diff options
Diffstat (limited to 'src/emu/cpu/mips/mdrcold.c')
-rw-r--r-- | src/emu/cpu/mips/mdrcold.c | 4883 |
1 files changed, 4883 insertions, 0 deletions
diff --git a/src/emu/cpu/mips/mdrcold.c b/src/emu/cpu/mips/mdrcold.c new file mode 100644 index 00000000000..d960eae06c0 --- /dev/null +++ b/src/emu/cpu/mips/mdrcold.c @@ -0,0 +1,4883 @@ + + +/*************************************************************************** + CONFIGURATION +***************************************************************************/ + +#define STRIP_NOPS 1 /* 1 is faster */ +#define USE_SSE 0 /* can't tell any speed difference here */ + + + +/*************************************************************************** + CONSTANTS +***************************************************************************/ + +#define MAX_INSTRUCTIONS ((512 + 128) / 4) + +/* recompiler flags */ +#define RECOMPILE_UNIMPLEMENTED 0x0000 +#define RECOMPILE_SUCCESSFUL 0x0001 +#define RECOMPILE_SUCCESSFUL_CP(c,p) (RECOMPILE_SUCCESSFUL | (((c) & 0xfff) << 8) | (((p) & 0xfff) << 20)) +#define RECOMPILE_MAY_CAUSE_EXCEPTION 0x0002 +#define RECOMPILE_END_OF_STRING 0x0004 +#define RECOMPILE_CHECK_INTERRUPTS 0x0008 +#define RECOMPILE_CHECK_SW_INTERRUPTS 0x0010 +#define RECOMPILE_ADD_DISPATCH 0x0020 + +/* append_readwrite flags */ +#define ARW_READ 0x0000 +#define ARW_WRITE 0x0001 +#define ARW_UNSIGNED 0x0000 +#define ARW_SIGNED 0x0002 +#define ARW_MASKED 0x0004 + + + +/*************************************************************************** + MACROS +***************************************************************************/ + +#define REGDISP(reg) (offsetof(mips3_state, r[reg]) - offsetof(mips3_state, r[17])) +#define REGADDR(reg) MBD(REG_ESI, REGDISP(reg)) +#define REGADDRLO(reg) MBD(REG_ESI, REGDISP(reg)) +#define REGADDRHI(reg) MBD(REG_ESI, REGDISP(reg)+4) + +#define HIADDR REGADDR(REG_HI) +#define HIADDRLO REGADDRLO(REG_HI) +#define HIADDRHI REGADDRHI(REG_HI) + +#define LOADDR REGADDR(REG_LO) +#define LOADDRLO REGADDRLO(REG_LO) +#define LOADDRHI REGADDRHI(REG_LO) + +#define CPR0ADDR(reg) MABS((UINT8 *)&mips3.core->cpr[0][reg]) +#define CPR0ADDRLO(reg) MABS((UINT8 *)&mips3.core->cpr[0][reg]) +#define CPR0ADDRHI(reg) MABS((UINT8 *)&mips3.core->cpr[0][reg] + 4) + +#define CCR0ADDR(reg) MABS((UINT8 *)&mips3.core->ccr[0][reg]) +#define CCR0ADDRLO(reg) MABS((UINT8 *)&mips3.core->ccr[0][reg]) +#define CCR0ADDRHI(reg) MABS((UINT8 *)&mips3.core->ccr[0][reg] + 4) + +#define CPR1ADDR(reg) MABS((UINT8 *)&mips3.core->cpr[1][reg]) +#define CPR1ADDRLO(reg) MABS((UINT8 *)&mips3.core->cpr[1][reg]) +#define CPR1ADDRHI(reg) MABS((UINT8 *)&mips3.core->cpr[1][reg] + 4) + +#define CCR1ADDR(reg) MABS((UINT8 *)&mips3.core->ccr[1][reg]) +#define CCR1ADDRLO(reg) MABS((UINT8 *)&mips3.core->ccr[1][reg]) +#define CCR1ADDRHI(reg) MABS((UINT8 *)&mips3.core->ccr[1][reg] + 4) + +#define CPR2ADDR(reg) MABS((UINT8 *)&mips3.core->cpr[2][reg]) +#define CPR2ADDRLO(reg) MABS((UINT8 *)&mips3.core->cpr[2][reg]) +#define CPR2ADDRHI(reg) MABS((UINT8 *)&mips3.core->cpr[2][reg] + 4) + +#define CCR2ADDR(reg) MABS((UINT8 *)&mips3.core->ccr[2][reg]) +#define CCR2ADDRLO(reg) MABS((UINT8 *)&mips3.core->ccr[2][reg]) +#define CCR2ADDRHI(reg) MABS((UINT8 *)&mips3.core->ccr[2][reg] + 4) + +#define FPR32(reg) (IS_FR0 ? &((float *)&mips3.core->cpr[1][0])[reg] : (float *)&mips3.core->cpr[1][reg]) +#define FPR32ADDR(reg) MABS(FPR32(reg)) +#define FPR32ADDRLO(reg) MABS(FPR32(reg)) +#define FPR32ADDRHI(reg) MABS((UINT8 *)FPR32(reg) + 4) + +#define FPR64(reg) (IS_FR0 ? (double *)&mips3.core->cpr[1][(reg)/2] : (double *)&mips3.core->cpr[1][reg]) +#define FPR64ADDR(reg) MABS(FPR64(reg)) +#define FPR64ADDR(reg) MABS(FPR64(reg)) +#define FPR64ADDRLO(reg) MABS(FPR64(reg)) +#define FPR64ADDRHI(reg) MABS((UINT8 *)FPR64(reg) + 4) + +#define CF1ADDR(which) MABS(&mips3.core->cf[1][(mips3.core->flavor < MIPS3_TYPE_MIPS_IV) ? 0 : (which)]) + +#define ICOUNTADDR MABS(&mips3.core->icount) + + +/*************************************************************************** + USEFUL PRIMITIVES +***************************************************************************/ + +INLINE void emit_mov_r64_m64(x86code **emitptr, UINT8 reghi, UINT8 reglo, DECLARE_MEMPARAMS) +{ + emit_mov_r32_m32(emitptr, reglo, MEMPARAMS); + emit_mov_r32_m32(emitptr, reghi, base, index, scale, disp+4); +} + +INLINE void emit_mov_m64_r64(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 reghi, UINT8 reglo) +{ + emit_mov_m32_r32(emitptr, MEMPARAMS, reglo); + emit_mov_m32_r32(emitptr, base, index, scale, disp+4, reghi); +} + +INLINE void emit_mov_m64_imm32(x86code **emitptr, DECLARE_MEMPARAMS, INT32 imm) +{ + emit_mov_m32_imm(emitptr, MEMPARAMS, imm); + emit_mov_m32_imm(emitptr, base, index, scale, disp+4, (INT32)imm >> 31); +} + +INLINE void emit_zero_m64(x86code **emitptr, DECLARE_MEMPARAMS) +{ + if (USE_SSE) + { + emit_xorpd_r128_r128(emitptr, REG_XMM0, REG_XMM0); + emit_movsd_m64_r128(emitptr, MEMPARAMS, REG_XMM0); + } + else + emit_mov_m64_imm32(emitptr, MEMPARAMS, 0); +} + +INLINE void emit_mov_m64_m64(x86code **emitptr, DECLARE_MEMPARAMS, UINT8 base2, UINT8 index2, UINT8 scale2, INT32 disp2) +{ + if (USE_SSE) + { + emit_movsd_r128_m64(emitptr, REG_XMM0, base2, index2, scale2, disp2); + emit_movsd_m64_r128(emitptr, MEMPARAMS, REG_XMM0); + } + else + { + emit_mov_r64_m64(emitptr, REG_EDX, REG_EAX, base2, index2, scale2, disp2); + emit_mov_m64_r64(emitptr, MEMPARAMS, REG_EDX, REG_EAX); + } +} + +#define emit_save_pc_before_call(e) \ +do { \ + if (mips3.drcoptions & MIPS3DRC_FLUSH_PC) \ + emit_mov_m32_r32(e, MABS(drc->pcptr), REG_EDI); \ +} while (0) + + + + +/*************************************************************************** + TYPEDEFS +***************************************************************************/ + +struct _mips3drc_data +{ + x86code * generate_interrupt_exception; + x86code * generate_cop_exception; + x86code * generate_overflow_exception; + x86code * generate_invalidop_exception; + x86code * generate_syscall_exception; + x86code * generate_break_exception; + x86code * generate_trap_exception; + x86code * generate_tlbload_exception; + x86code * generate_tlbstore_exception; + x86code * handle_pc_tlb_mismatch; + x86code * read_and_translate_byte_signed; + x86code * read_and_translate_byte_unsigned; + x86code * read_and_translate_half_signed; + x86code * read_and_translate_half_unsigned; + x86code * read_and_translate_word; + x86code * read_and_translate_word_masked; + x86code * read_and_translate_double; + x86code * read_and_translate_double_masked; + x86code * write_and_translate_byte; + x86code * write_and_translate_half; + x86code * write_and_translate_word; + x86code * write_and_translate_word_masked; + x86code * write_and_translate_double; + x86code * write_and_translate_double_masked; +}; + + + +/*************************************************************************** + FUNCTION PROTOTYPES +***************************************************************************/ + +static void drc_reset_callback(drc_core *drc); +static void drc_recompile_callback(drc_core *drc); +static void drc_entrygen_callback(drc_core *drc); + +static UINT32 compile_one(drc_core *drc, UINT32 pc, UINT32 physpc); + +static void append_generate_exception(drc_core *drc, UINT8 exception); +static void append_readwrite_and_translate(drc_core *drc, int size, UINT8 flags); +static void append_tlb_verify(drc_core *drc, UINT32 pc, void *target); +static void append_update_cycle_counting(drc_core *drc); +static void append_check_interrupts(drc_core *drc, int inline_generate); +static void append_check_sw_interrupts(drc_core *drc, int inline_generate); + +static UINT32 recompile_instruction(drc_core *drc, UINT32 pc, UINT32 physpc); +static UINT32 recompile_special(drc_core *drc, UINT32 pc, UINT32 op); +static UINT32 recompile_regimm(drc_core *drc, UINT32 pc, UINT32 op); + +static UINT32 recompile_cop0(drc_core *drc, UINT32 pc, UINT32 op); +static UINT32 recompile_cop1(drc_core *drc, UINT32 pc, UINT32 op); +static UINT32 recompile_cop1x(drc_core *drc, UINT32 pc, UINT32 op); + + + +/*************************************************************************** + PRIVATE GLOBAL VARIABLES +***************************************************************************/ + +static UINT64 dmult_temp1; +static UINT64 dmult_temp2; +static UINT32 jr_temp; + +static UINT8 in_delay_slot = 0; + + + +/*************************************************************************** + CORE RECOMPILER SYSTEMS +***************************************************************************/ + +/*------------------------------------------------- + mips3drc_init - initialize the drc-specific + state +-------------------------------------------------*/ + +static void mips3drc_init(void) +{ + drc_config drconfig; + + /* fill in the config */ + memset(&drconfig, 0, sizeof(drconfig)); + drconfig.cache_base = mips3.cache; + drconfig.cache_size = CACHE_SIZE; + drconfig.max_instructions = MAX_INSTRUCTIONS; + drconfig.address_bits = 32; + drconfig.lsbs_to_ignore = 2; + drconfig.uses_fp = 1; + drconfig.uses_sse = USE_SSE; + drconfig.pc_in_memory = 0; + drconfig.icount_in_memory = 0; + drconfig.pcptr = (UINT32 *)&mips3.core->pc; + drconfig.icountptr = (UINT32 *)&mips3.core->icount; + drconfig.esiptr = NULL; + drconfig.cb_reset = drc_reset_callback; + drconfig.cb_recompile = drc_recompile_callback; + drconfig.cb_entrygen = drc_entrygen_callback; + + /* initialize the compiler */ + mips3.drc = drc_init(cpu_getactivecpu(), &drconfig); + mips3.drcoptions = MIPS3DRC_FASTEST_OPTIONS; + + /* allocate our data out of the cache */ + mips3.drcdata = drc_alloc(mips3.drc, sizeof(*mips3.drcdata)); + memset(mips3.drcdata, 0, sizeof(*mips3.drcdata)); +} + + +/*------------------------------------------------- + mips3drc_exit - clean up the drc-specific + state +-------------------------------------------------*/ + +static void mips3drc_exit(void) +{ +} + + + +/*************************************************************************** + RECOMPILER CALLBACKS +***************************************************************************/ + +/*------------------------------------------------------------------ + drc_reset_callback +------------------------------------------------------------------*/ + +static void drc_reset_callback(drc_core *drc) +{ + if (LOG_CODE) + { + x86log_disasm_code_range(mips3.log, "entry_point:", (x86code *)drc->entry_point, drc->out_of_cycles); + x86log_disasm_code_range(mips3.log, "out_of_cycles:", drc->out_of_cycles, drc->recompile); + x86log_disasm_code_range(mips3.log, "recompile:", drc->recompile, drc->dispatch); + x86log_disasm_code_range(mips3.log, "dispatch:", drc->dispatch, drc->flush); + x86log_disasm_code_range(mips3.log, "flush:", drc->flush, drc->cache_top); + } + + mips3.drcdata->generate_interrupt_exception = drc->cache_top; + append_generate_exception(drc, EXCEPTION_INTERRUPT); + if (LOG_CODE) + x86log_disasm_code_range(mips3.log, "generate_interrupt_exception:", mips3.drcdata->generate_interrupt_exception, drc->cache_top); + + mips3.drcdata->generate_cop_exception = drc->cache_top; + append_generate_exception(drc, EXCEPTION_BADCOP); + if (LOG_CODE) + x86log_disasm_code_range(mips3.log, "generate_cop_exception:", mips3.drcdata->generate_cop_exception, drc->cache_top); + + mips3.drcdata->generate_overflow_exception = drc->cache_top; + append_generate_exception(drc, EXCEPTION_OVERFLOW); + if (LOG_CODE) + x86log_disasm_code_range(mips3.log, "generate_overflow_exception:", mips3.drcdata->generate_overflow_exception, drc->cache_top); + + mips3.drcdata->generate_invalidop_exception = drc->cache_top; + append_generate_exception(drc, EXCEPTION_INVALIDOP); + if (LOG_CODE) + x86log_disasm_code_range(mips3.log, "generate_invalidop_exception:", mips3.drcdata->generate_invalidop_exception, drc->cache_top); + + mips3.drcdata->generate_syscall_exception = drc->cache_top; + append_generate_exception(drc, EXCEPTION_SYSCALL); + if (LOG_CODE) + x86log_disasm_code_range(mips3.log, "generate_syscall_exception:", mips3.drcdata->generate_syscall_exception, drc->cache_top); + + mips3.drcdata->generate_break_exception = drc->cache_top; + append_generate_exception(drc, EXCEPTION_BREAK); + if (LOG_CODE) + x86log_disasm_code_range(mips3.log, "generate_break_exception:", mips3.drcdata->generate_break_exception, drc->cache_top); + + mips3.drcdata->generate_trap_exception = drc->cache_top; + append_generate_exception(drc, EXCEPTION_TRAP); + if (LOG_CODE) + x86log_disasm_code_range(mips3.log, "generate_trap_exception:", mips3.drcdata->generate_trap_exception, drc->cache_top); + + mips3.drcdata->generate_tlbload_exception = drc->cache_top; + append_generate_exception(drc, EXCEPTION_TLBLOAD); + if (LOG_CODE) + x86log_disasm_code_range(mips3.log, "generate_tlbload_exception:", mips3.drcdata->generate_tlbload_exception, drc->cache_top); + + mips3.drcdata->generate_tlbstore_exception = drc->cache_top; + append_generate_exception(drc, EXCEPTION_TLBSTORE); + if (LOG_CODE) + x86log_disasm_code_range(mips3.log, "generate_tlbstore_exception:", mips3.drcdata->generate_tlbstore_exception, drc->cache_top); + + mips3.drcdata->handle_pc_tlb_mismatch = drc->cache_top; + emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EDI); // mov eax,edi + emit_shr_r32_imm(DRCTOP, REG_EAX, 12); // shr eax,12 + emit_mov_r32_m32(DRCTOP, REG_EBX, MISD(REG_EAX, 4, mips3.core->tlb_table)); // mov ebx,tlb_table[eax*4] + emit_test_r32_imm(DRCTOP, REG_EBX, 2); // test ebx,2 + emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EDI); // mov eax,edi + emit_jcc(DRCTOP, COND_NZ, mips3.drcdata->generate_tlbload_exception); // jnz generate_tlbload_exception + emit_mov_m32_r32(DRCTOP, MABS(drc->pcptr), REG_EDI); // mov [pcptr],edi + emit_jmp(DRCTOP, drc->recompile); // jmp recompile + if (LOG_CODE) + x86log_disasm_code_range(mips3.log, "handle_pc_tlb_mismatch:", mips3.drcdata->handle_pc_tlb_mismatch, drc->cache_top); + + mips3.drcdata->read_and_translate_byte_signed = drc->cache_top; + append_readwrite_and_translate(drc, 1, ARW_READ | ARW_SIGNED); + if (LOG_CODE) + x86log_disasm_code_range(mips3.log, "read_and_translate_byte_signed:", mips3.drcdata->read_and_translate_byte_signed, drc->cache_top); + + mips3.drcdata->read_and_translate_byte_unsigned = drc->cache_top; + append_readwrite_and_translate(drc, 1, ARW_READ | ARW_UNSIGNED); + if (LOG_CODE) + x86log_disasm_code_range(mips3.log, "read_and_translate_byte_unsigned:", mips3.drcdata->read_and_translate_byte_unsigned, drc->cache_top); + + mips3.drcdata->read_and_translate_half_signed = drc->cache_top; + append_readwrite_and_translate(drc, 2, ARW_READ | ARW_SIGNED); + if (LOG_CODE) + x86log_disasm_code_range(mips3.log, "read_and_translate_half_signed:", mips3.drcdata->read_and_translate_half_signed, drc->cache_top); + + mips3.drcdata->read_and_translate_half_unsigned = drc->cache_top; + append_readwrite_and_translate(drc, 2, ARW_READ | ARW_UNSIGNED); + if (LOG_CODE) + x86log_disasm_code_range(mips3.log, "read_and_translate_half_unsigned:", mips3.drcdata->read_and_translate_half_unsigned, drc->cache_top); + + mips3.drcdata->read_and_translate_word = drc->cache_top; + append_readwrite_and_translate(drc, 4, ARW_READ); + if (LOG_CODE) + x86log_disasm_code_range(mips3.log, "read_and_translate_word:", mips3.drcdata->read_and_translate_word, drc->cache_top); + + mips3.drcdata->read_and_translate_word_masked = drc->cache_top; + append_readwrite_and_translate(drc, 4, ARW_READ | ARW_MASKED); + if (LOG_CODE) + x86log_disasm_code_range(mips3.log, "read_and_translate_word_masked:", mips3.drcdata->read_and_translate_word_masked, drc->cache_top); + + mips3.drcdata->read_and_translate_double = drc->cache_top; + append_readwrite_and_translate(drc, 8, ARW_READ); + if (LOG_CODE) + x86log_disasm_code_range(mips3.log, "read_and_translate_double:", mips3.drcdata->read_and_translate_double, drc->cache_top); + + mips3.drcdata->read_and_translate_double_masked = drc->cache_top; + append_readwrite_and_translate(drc, 8, ARW_READ | ARW_MASKED); + if (LOG_CODE) + x86log_disasm_code_range(mips3.log, "read_and_translate_double_masked:", mips3.drcdata->read_and_translate_double_masked, drc->cache_top); + + mips3.drcdata->write_and_translate_byte = drc->cache_top; + append_readwrite_and_translate(drc, 1, ARW_WRITE); + if (LOG_CODE) + x86log_disasm_code_range(mips3.log, "write_and_translate_byte:", mips3.drcdata->write_and_translate_byte, drc->cache_top); + + mips3.drcdata->write_and_translate_half = drc->cache_top; + append_readwrite_and_translate(drc, 2, ARW_WRITE); + if (LOG_CODE) + x86log_disasm_code_range(mips3.log, "write_and_translate_half:", mips3.drcdata->write_and_translate_half, drc->cache_top); + + mips3.drcdata->write_and_translate_word = drc->cache_top; + append_readwrite_and_translate(drc, 4, ARW_WRITE); + if (LOG_CODE) + x86log_disasm_code_range(mips3.log, "write_and_translate_word:", mips3.drcdata->write_and_translate_word, drc->cache_top); + + mips3.drcdata->write_and_translate_word_masked = drc->cache_top; + append_readwrite_and_translate(drc, 4, ARW_WRITE | ARW_MASKED); + if (LOG_CODE) + x86log_disasm_code_range(mips3.log, "write_and_translate_word_masked:", mips3.drcdata->write_and_translate_word_masked, drc->cache_top); + + mips3.drcdata->write_and_translate_double = drc->cache_top; + append_readwrite_and_translate(drc, 8, ARW_WRITE); + if (LOG_CODE) + x86log_disasm_code_range(mips3.log, "write_and_translate_double:", mips3.drcdata->write_and_translate_double, drc->cache_top); + + mips3.drcdata->write_and_translate_double_masked = drc->cache_top; + append_readwrite_and_translate(drc, 8, ARW_WRITE | ARW_MASKED); + if (LOG_CODE) + x86log_disasm_code_range(mips3.log, "write_and_translate_double_masked:", mips3.drcdata->write_and_translate_double_masked, drc->cache_top); +} + + +/*------------------------------------------------------------------ + drc_recompile_callback +------------------------------------------------------------------*/ + +static void drc_recompile_callback(drc_core *drc) +{ + int remaining = MAX_INSTRUCTIONS; + x86code *start = drc->cache_top; + UINT32 pc = mips3.core->pc; + UINT32 lastpc = pc; + UINT32 physpc; + + (void)start; + + /* begin the sequence */ + drc_begin_sequence(drc, pc); + + /* make sure our FR flag matches the last time */ + emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_FR); // test [COP0_Status],SR_FR + emit_jcc(DRCTOP, IS_FR0 ? COND_NZ : COND_Z, drc->recompile); // jnz/z recompile + + /* ensure that we are still mapped */ + append_tlb_verify(drc, pc, mips3.drcdata->handle_pc_tlb_mismatch); + physpc = pc; + if (!mips3com_translate_address(mips3.core, ADDRESS_SPACE_PROGRAM, &physpc)) + { + emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EDI); // mov eax,edi + emit_jmp(DRCTOP, mips3.drcdata->generate_tlbload_exception); // jmp tlbload_exception + goto exit; + } + change_pc(physpc); + + /* loose verification case: one verification here only */ + if (!(mips3.drcoptions & MIPS3DRC_STRICT_VERIFY)) + drc_append_verify_code(drc, cpu_opptr(physpc), 4); + + /* loop until we hit an unconditional branch */ + while (--remaining != 0) + { + UINT32 result; + + /* if we crossed a page boundary, check the mapping */ + if ((pc ^ lastpc) & 0xfffff000) + { + physpc = pc; + if (!mips3com_translate_address(mips3.core, ADDRESS_SPACE_PROGRAM, &physpc)) + break; + append_tlb_verify(drc, pc, drc->dispatch); + change_pc(physpc); + } + + /* compile one instruction */ + physpc = (physpc & 0xfffff000) | (pc & 0xfff); + result = compile_one(drc, pc, physpc); + lastpc = pc; + pc += (INT32)result >> 20; + if (result & RECOMPILE_END_OF_STRING) + break; + } + + /* add dispatcher just in case */ + if (remaining == 0) + drc_append_dispatcher(drc); + +exit: + /* end the sequence */ + drc_end_sequence(drc); + + /* log the generated code */ + if (LOG_CODE) + { + char label[60]; + physpc = mips3.core->pc; + mips3com_translate_address(mips3.core, ADDRESS_SPACE_PROGRAM, &physpc); + sprintf(label, "Code @ %08X (%08X physical)", mips3.core->pc, physpc); + x86log_disasm_code_range(mips3.log, label, start, drc->cache_top); + } +} + + +/*------------------------------------------------------------------ + drc_entrygen_callback +------------------------------------------------------------------*/ + +static void drc_entrygen_callback(drc_core *drc) +{ + emit_mov_r32_imm(DRCTOP, REG_ESI, (FPTR)&mips3.core->r[17]); + append_check_interrupts(drc, 1); +} + + + +/*************************************************************************** + RECOMPILER CORE +***************************************************************************/ + +/*------------------------------------------------------------------ + compile_one +------------------------------------------------------------------*/ + +static UINT32 compile_one(drc_core *drc, UINT32 pc, UINT32 physpc) +{ + int pcdelta, cycles, hotnum; + UINT32 *opptr; + UINT32 result; + + /* register this instruction */ + drc_register_code_at_cache_top(drc, pc); + + /* get a pointer to the current instruction */ + change_pc(physpc); + opptr = cpu_opptr(physpc); + + /* emit debugging and self-modifying code checks */ + drc_append_call_debugger(drc); + if (mips3.drcoptions & MIPS3DRC_STRICT_VERIFY) + drc_append_verify_code(drc, opptr, 4); + + /* is this a hotspot? */ + for (hotnum = 0; hotnum < MIPS3_MAX_HOTSPOTS; hotnum++) + if (pc == mips3.hotspot[hotnum].pc && *(UINT32 *)opptr == mips3.hotspot[hotnum].opcode) + break; + + /* compile the instruction */ + result = recompile_instruction(drc, pc, physpc); + + /* handle the results */ + if (!(result & RECOMPILE_SUCCESSFUL)) + fatalerror("Unimplemented op %08X (%02X,%02X)", *opptr, *opptr >> 26, *opptr & 0x3f); + + pcdelta = (INT32)result >> 20; + cycles = (result >> 8) & 0xfff; + + /* absorb any NOPs following */ + if (STRIP_NOPS && !Machine->debug_mode) + { + if (!(result & (RECOMPILE_END_OF_STRING | RECOMPILE_CHECK_INTERRUPTS | RECOMPILE_CHECK_SW_INTERRUPTS))) + while ((((pc + pcdelta) ^ pc) & 0xfffff000) == 0 && pcdelta < 120 && opptr[pcdelta/4] == 0) + { + pcdelta += 4; + cycles += 1; + } + } + + /* epilogue */ + if (hotnum != MIPS3_MAX_HOTSPOTS) + cycles += mips3.hotspot[hotnum].cycles; + drc_append_standard_epilogue(drc, cycles, pcdelta, 1); + + /* check interrupts */ + if (result & RECOMPILE_CHECK_INTERRUPTS) + append_check_interrupts(drc, 0); + if (result & RECOMPILE_CHECK_SW_INTERRUPTS) + append_check_sw_interrupts(drc, 0); + if (result & RECOMPILE_ADD_DISPATCH) + drc_append_dispatcher(drc); + + return (result & 0xff) | ((cycles & 0xfff) << 8) | ((pcdelta & 0xfff) << 20); +} + + + +/*************************************************************************** + COMMON ROUTINES +***************************************************************************/ + +/*------------------------------------------------------------------ + append_generate_exception +------------------------------------------------------------------*/ + +static void append_generate_exception(drc_core *drc, UINT8 exception) +{ + UINT32 offset = (exception >= EXCEPTION_TLBMOD && exception <= EXCEPTION_TLBSTORE) ? 0x00 : 0x180; + emit_link link1, link2; + + /* assumes address is in EAX */ + if (exception == EXCEPTION_TLBLOAD || exception == EXCEPTION_TLBSTORE) + { + emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_BadVAddr), REG_EAX); // mov [BadVAddr],eax + emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_EntryHi), 0x000000ff); // and [EntryHi],0x000000ff + emit_and_r32_imm(DRCTOP, REG_EAX, 0xffffe000); // and eax,0xffffe000 + emit_or_m32_r32(DRCTOP, CPR0ADDR(COP0_EntryHi), REG_EAX); // or [EntryHi],eax + emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_Context), 0xff800000); // and [Context],0xff800000 + emit_shr_r32_imm(DRCTOP, REG_EAX, 9); // shr eax,9 + emit_or_m32_r32(DRCTOP, CPR0ADDR(COP0_Context), REG_EAX); // or [Context],eax + } + + emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_EPC), REG_EDI); // mov [COP0_EPC],edi + emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Cause)); // mov eax,[COP0_Cause] + emit_and_r32_imm(DRCTOP, REG_EAX, ~0x800000ff); // and eax,~0x800000ff + if (exception) + emit_or_r32_imm(DRCTOP, REG_EAX, exception << 2); // or eax,exception << 2 + emit_cmp_m32_imm(DRCTOP, MABS(&mips3.nextpc), ~0); // cmp [mips3.nextpc],~0 + emit_jcc_short_link(DRCTOP, COND_E, &link1); // je skip + emit_mov_m32_imm(DRCTOP, MABS(&mips3.nextpc), ~0); // mov [mips3.nextpc],~0 + emit_sub_m32_imm(DRCTOP, CPR0ADDR(COP0_EPC), 4); // sub [COP0_EPC],4 + emit_or_r32_imm(DRCTOP, REG_EAX, 0x80000000); // or eax,0x80000000 + resolve_link(DRCTOP, &link1); // skip: + emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Cause), REG_EAX); // mov [COP0_Cause],eax + emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Status)); // mov eax,[COP0_Status] + emit_or_r32_imm(DRCTOP, REG_EAX, SR_EXL); // or eax,SR_EXL + emit_test_r32_imm(DRCTOP, REG_EAX, SR_BEV); // test eax,SR_BEV + emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Status), REG_EAX); // mov [COP0_Status],eax + emit_mov_r32_imm(DRCTOP, REG_EDI, 0xbfc00200 + offset); // mov edi,0xbfc00200+offset + emit_jcc_short_link(DRCTOP, COND_NZ, &link2); // jnz skip2 + emit_mov_r32_imm(DRCTOP, REG_EDI, 0x80000000 + offset); // mov edi,0x80000000+offset + resolve_link(DRCTOP, &link2); // skip2: + drc_append_dispatcher(drc); // dispatch +} + + +/*------------------------------------------------------------------ + append_readwrite_and_translate +------------------------------------------------------------------*/ + +static void append_readwrite_and_translate(drc_core *drc, int size, UINT8 flags) +{ + emit_link link1 = { 0 }, link2 = { 0 }, link3 = { 0 }; + int ramnum; + + emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 4)); // mov eax,[esp+4] + emit_mov_r32_r32(DRCTOP, REG_EBX, REG_EAX); // mov ebx,eax + emit_shr_r32_imm(DRCTOP, REG_EBX, 12); // shr ebx,12 + emit_mov_r32_m32(DRCTOP, REG_EBX, MISD(REG_EBX, 4, mips3.core->tlb_table)); // mov ebx,tlb_table[ebx*4] + emit_and_r32_imm(DRCTOP, REG_EAX, 0xfff); // and eax,0xfff + emit_shr_r32_imm(DRCTOP, REG_EBX, ((flags & ARW_WRITE) ? 1 : 2)); // shr ebx,2/1 (read/write) + emit_lea_r32_m32(DRCTOP, REG_EBX, MBISD(REG_EAX, REG_EBX, ((flags & ARW_WRITE) ? 2 : 4), 0)); + // lea ebx,[eax+ebx*4/2] (read/write) + emit_jcc_near_link(DRCTOP, COND_C, &link1); // jc error + for (ramnum = 0; ramnum < MIPS3_MAX_FASTRAM; ramnum++) + if (!Machine->debug_mode && mips3.fastram[ramnum].base && (!(flags & ARW_WRITE) || !mips3.fastram[ramnum].readonly)) + { + UINT32 fastbase = (UINT32)((UINT8 *)mips3.fastram[ramnum].base - mips3.fastram[ramnum].start); + if (mips3.fastram[ramnum].end != 0xffffffff) + { + emit_cmp_r32_imm(DRCTOP, REG_EBX, mips3.fastram[ramnum].end); // cmp ebx,fastram_end + emit_jcc_short_link(DRCTOP, COND_A, &link2); // ja notram + } + if (mips3.fastram[ramnum].start != 0x00000000) + { + emit_cmp_r32_imm(DRCTOP, REG_EBX, mips3.fastram[ramnum].start); // cmp ebx,fastram_start + emit_jcc_short_link(DRCTOP, COND_B, &link3); // jb notram + } + + if (!(flags & ARW_WRITE)) + { + if (size == 1) + { + if (mips3.core->bigendian) + emit_xor_r32_imm(DRCTOP, REG_EBX, 3); // xor ebx,3 + if (flags & ARW_SIGNED) + emit_movsx_r32_m8(DRCTOP, REG_EAX, MBD(REG_EBX, fastbase)); // movsx eax,byte ptr [ebx+fastbase] + else + emit_movzx_r32_m8(DRCTOP, REG_EAX, MBD(REG_EBX, fastbase)); // movzx eax,byte ptr [ebx+fastbase] + } + else if (size == 2) + { + if (mips3.core->bigendian) + emit_xor_r32_imm(DRCTOP, REG_EBX, 2); // xor ebx,2 + if (flags & ARW_SIGNED) + emit_movsx_r32_m16(DRCTOP, REG_EAX, MBD(REG_EBX, fastbase)); // movsx eax,word ptr [ebx+fastbase] + else + emit_movzx_r32_m16(DRCTOP, REG_EAX, MBD(REG_EBX, fastbase)); // movzx eax,word ptr [ebx+fastbase] + } + else if (size == 4) + emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_EBX, fastbase)); // mov eax,[ebx+fastbase] + else if (size == 8) + { + if (mips3.core->bigendian) + emit_mov_r64_m64(DRCTOP, REG_EAX, REG_EDX, MBD(REG_EBX, (FPTR)fastbase)); + // mov eax:edx,[ebx+fastbase] + else + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, MBD(REG_EBX, (FPTR)fastbase)); + // mov edx:eax,[ebx+fastbase] + } + emit_ret(DRCTOP); // ret + } + else + { + if (size == 1) + { + emit_mov_r8_m8(DRCTOP, REG_AL, MBD(REG_ESP, 8)); // mov al,[esp+8] + if (mips3.core->bigendian) + emit_xor_r32_imm(DRCTOP, REG_EBX, 3); // xor ebx,3 + emit_mov_m8_r8(DRCTOP, MBD(REG_EBX, fastbase), REG_AL); // mov [ebx+fastbase],al + } + else if (size == 2) + { + emit_mov_r16_m16(DRCTOP, REG_AX, MBD(REG_ESP, 8)); // mov ax,[esp+8] + if (mips3.core->bigendian) + emit_xor_r32_imm(DRCTOP, REG_EBX, 2); // xor ebx,2 + emit_mov_m16_r16(DRCTOP, MBD(REG_EBX, fastbase), REG_AX); // mov [ebx+fastbase],ax + } + else if (size == 4) + { + if (!(flags & ARW_MASKED)) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 8)); // mov eax,[esp+8] + emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase), REG_EAX); // mov [ebx+fastbase],eax + } + else + { + emit_mov_r32_m32(DRCTOP, REG_ECX, MBD(REG_ESP, 12)); // mov ecx,[esp+12] + emit_mov_r32_r32(DRCTOP, REG_EAX, REG_ECX); // mov eax,ecx + emit_and_r32_m32(DRCTOP, REG_ECX, MBD(REG_EBX, fastbase)); // and ecx,[ebx+fastbase] + emit_not_r32(DRCTOP, REG_EAX); // not eax + emit_and_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 8)); // and eax,[esp+8] + emit_or_r32_r32(DRCTOP, REG_EAX, REG_ECX); // or eax,ecx + emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase), REG_EAX); // mov [ebx+fastbase],eax + } + } + else if (size == 8) + { + if (!(flags & ARW_MASKED)) + { + if (mips3.core->bigendian) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 8)); // mov eax,[esp+8] + emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase+4), REG_EAX); // mov [ebx+fastbase+4],eax + emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 12)); // mov eax,[esp+12] + emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase), REG_EAX); // mov [ebx+fastbase],eax + } + else + { + emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 8)); // mov eax,[esp+8] + emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase), REG_EAX); // mov [ebx+fastbase],eax + emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 12)); // mov eax,[esp+12] + emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase+4), REG_EAX); // mov [ebx+fastbase+4],eax + } + } + else + { + if (mips3.core->bigendian) + { + emit_mov_r32_m32(DRCTOP, REG_ECX, MBD(REG_ESP, 16)); // mov ecx,[esp+16] + emit_mov_r32_r32(DRCTOP, REG_EAX, REG_ECX); // mov eax,ecx + emit_and_r32_m32(DRCTOP, REG_ECX, MBD(REG_EBX, fastbase+4)); // and ecx,[ebx+fastbase+4] + emit_not_r32(DRCTOP, REG_EAX); // not eax + emit_and_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 8)); // and eax,[esp+8] + emit_or_r32_r32(DRCTOP, REG_EAX, REG_ECX); // or eax,ecx + emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase+4), REG_EAX); // mov [ebx+fastbase+4],eax + emit_mov_r32_m32(DRCTOP, REG_ECX, MBD(REG_ESP, 20)); // mov ecx,[esp+20] + emit_mov_r32_r32(DRCTOP, REG_EAX, REG_ECX); // mov eax,ecx + emit_and_r32_m32(DRCTOP, REG_ECX, MBD(REG_EBX, fastbase)); // and ecx,[ebx+fastbase] + emit_not_r32(DRCTOP, REG_EAX); // not eax + emit_and_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 12)); // and eax,[esp+12] + emit_or_r32_r32(DRCTOP, REG_EAX, REG_ECX); // or eax,ecx + emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase), REG_EAX); // mov [ebx+fastbase],eax + } + else + { + emit_mov_r32_m32(DRCTOP, REG_ECX, MBD(REG_ESP, 16)); // mov ecx,[esp+16] + emit_mov_r32_r32(DRCTOP, REG_EAX, REG_ECX); // mov eax,ecx + emit_and_r32_m32(DRCTOP, REG_ECX, MBD(REG_EBX, fastbase)); // and ecx,[ebx+fastbase] + emit_not_r32(DRCTOP, REG_EAX); // not eax + emit_and_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 8)); // and eax,[esp+8] + emit_or_r32_r32(DRCTOP, REG_EAX, REG_ECX); // or eax,ecx + emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase), REG_EAX); // mov [ebx+fastbase],eax + emit_mov_r32_m32(DRCTOP, REG_ECX, MBD(REG_ESP, 20)); // mov ecx,[esp+20] + emit_mov_r32_r32(DRCTOP, REG_EAX, REG_ECX); // mov eax,ecx + emit_and_r32_m32(DRCTOP, REG_ECX, MBD(REG_EBX, fastbase+4)); // and ecx,[ebx+fastbase+4] + emit_not_r32(DRCTOP, REG_EAX); // not eax + emit_and_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 12)); // and eax,[esp+12] + emit_or_r32_r32(DRCTOP, REG_EAX, REG_ECX); // or eax,ecx + emit_mov_m32_r32(DRCTOP, MBD(REG_EBX, fastbase+4), REG_EAX); // mov [ebx+fastbase+4],eax + } + } + } + emit_ret(DRCTOP); // ret + } + + if (mips3.fastram[ramnum].end != 0xffffffff) // notram: + resolve_link(DRCTOP, &link2); + if (mips3.fastram[ramnum].start != 0x00000000) + resolve_link(DRCTOP, &link3); + } + + if (flags & ARW_WRITE) + { + emit_mov_m32_r32(DRCTOP, MBD(REG_ESP, 4), REG_EBX); // mov [esp+4],ebx + if (size == 1) + emit_jmp(DRCTOP, (x86code *)mips3.core->memory.writebyte); // jmp writebyte + else if (size == 2) + emit_jmp(DRCTOP, (x86code *)mips3.core->memory.writehalf); // jmp writehalf + else if (size == 4) + { + if (!(flags & ARW_MASKED)) + emit_jmp(DRCTOP, (x86code *)mips3.core->memory.writeword); // jmp writeword + else + emit_jmp(DRCTOP, (x86code *)mips3.core->memory.writeword_masked); // jmp writeword_masked + } + else + { + if (!(flags & ARW_MASKED)) + emit_jmp(DRCTOP, (x86code *)mips3.core->memory.writedouble); // jmp writedouble + else + emit_jmp(DRCTOP, (x86code *)mips3.core->memory.writedouble_masked); // jmp writedouble_masked + } + } + else + { + if (size == 1) + { + emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 + emit_push_r32(DRCTOP, REG_EBX); // push ebx + emit_call(DRCTOP, (x86code *)mips3.core->memory.readbyte); // call readbyte + if (flags & ARW_SIGNED) + emit_movsx_r32_r8(DRCTOP, REG_EAX, REG_AL); // movsx eax,al + else + emit_movzx_r32_r8(DRCTOP, REG_EAX, REG_AL); // movzx eax,al + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + emit_ret(DRCTOP); // ret + } + else if (size == 2) + { + emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 + emit_push_r32(DRCTOP, REG_EBX); // push ebx + emit_call(DRCTOP, (x86code *)mips3.core->memory.readhalf); // call readhalf + if (flags & ARW_SIGNED) + emit_movsx_r32_r16(DRCTOP, REG_EAX, REG_AX); // movsx eax,ax + else + emit_movzx_r32_r16(DRCTOP, REG_EAX, REG_AX); // movzx eax,ax + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + emit_ret(DRCTOP); // ret + } + else if (size == 4) + { + emit_mov_m32_r32(DRCTOP, MBD(REG_ESP, 4), REG_EBX); // mov [esp+4],ebx + if (!(flags & ARW_MASKED)) + emit_jmp(DRCTOP, (x86code *)mips3.core->memory.readword); // jmp readword + else + emit_jmp(DRCTOP, (x86code *)mips3.core->memory.readword_masked); // jmp readword_masked + } + else + { + emit_mov_m32_r32(DRCTOP, MBD(REG_ESP, 4), REG_EBX); // mov [esp+4],ebx + if (!(flags & ARW_MASKED)) + emit_jmp(DRCTOP, (x86code *)mips3.core->memory.readdouble); // jmp readdouble + else + emit_jmp(DRCTOP, (x86code *)mips3.core->memory.readdouble_masked); // jmp readdouble_masked + } + } + { + int valuebytes = (size == 8) ? 8 : 4; + int stackbytes = 4 + ((flags & ARW_WRITE) ? 4 + valuebytes : 4) + ((flags & ARW_MASKED) ? valuebytes : 0); + resolve_link(DRCTOP, &link1); // error: + emit_mov_r32_m32(DRCTOP, REG_EAX, MBD(REG_ESP, 4)); // mov eax,[esp+4] + emit_add_r32_imm(DRCTOP, REG_ESP, stackbytes); // add esp,stack_bytes + emit_jmp(DRCTOP, (flags & ARW_WRITE) ? (x86code *)mips3.drcdata->generate_tlbstore_exception : (x86code *)mips3.drcdata->generate_tlbload_exception); + // jmp generate_exception + } +} + + +/*------------------------------------------------------------------ + append_tlb_verify +------------------------------------------------------------------*/ + +static void append_tlb_verify(drc_core *drc, UINT32 pc, void *target) +{ + /* addresses 0x80000000-0xbfffffff are direct-mapped; no checking needed */ + if (pc < 0x80000000 || pc >= 0xc0000000) + { + emit_cmp_m32_imm(DRCTOP, MABS(&mips3.core->tlb_table[pc >> 12]), mips3.core->tlb_table[pc >> 12]); + // cmp tlbtable[pc >> 12],physpc & 0xfffff000 + emit_jcc(DRCTOP, COND_NE, target); // jne handle_pc_tlb_mismatch + } +} + + +/*------------------------------------------------------------------ + append_update_cycle_counting +------------------------------------------------------------------*/ + +static void append_update_cycle_counting(drc_core *drc) +{ + emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_push_imm(DRCTOP, (FPTR)mips3.core); // push mips3.core + emit_call(DRCTOP, (x86code *)mips3com_update_cycle_counting); // call update_cycle_counting + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] +} + + +/*------------------------------------------------------------------ + append_check_interrupts +------------------------------------------------------------------*/ + +static void append_check_interrupts(drc_core *drc, int inline_generate) +{ + emit_link link1, link2, link3; + emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Cause)); // mov eax,[COP0_Cause] + emit_and_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Status)); // and eax,[COP0_Status] + emit_and_r32_imm(DRCTOP, REG_EAX, 0xfc00); // and eax,0xfc00 + if (!inline_generate) + emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip + else + emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz skip + emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_IE); // test [COP0_Status,SR_IE + if (!inline_generate) + emit_jcc_short_link(DRCTOP, COND_Z, &link2); // jz skip + else + emit_jcc_near_link(DRCTOP, COND_Z, &link2); // jz skip + emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_EXL | SR_ERL); // test [COP0_Status,SR_EXL | SR_ERL + if (!inline_generate) + emit_jcc(DRCTOP, COND_Z, mips3.drcdata->generate_interrupt_exception); // jz generate_interrupt_exception + else + { + emit_jcc_near_link(DRCTOP, COND_NZ, &link3); // jnz skip + append_generate_exception(drc, EXCEPTION_INTERRUPT); // <generate exception> + resolve_link(DRCTOP, &link3); // skip: + } + resolve_link(DRCTOP, &link1); // skip: + resolve_link(DRCTOP, &link2); +} + + +/*------------------------------------------------------------------ + append_check_sw_interrupts +------------------------------------------------------------------*/ + +static void append_check_sw_interrupts(drc_core *drc, int inline_generate) +{ + emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Cause), 0x300); // test [COP0_Cause],0x300 + emit_jcc(DRCTOP, COND_NZ, mips3.drcdata->generate_interrupt_exception); // jnz generate_interrupt_exception +} + + +/*------------------------------------------------------------------ + append_branch_or_dispatch +------------------------------------------------------------------*/ + +static void append_branch_or_dispatch(drc_core *drc, UINT32 newpc, int cycles) +{ + void *code = drc_get_code_at_pc(drc, newpc); + emit_mov_r32_imm(DRCTOP, REG_EDI, newpc); // mov edi,newpc + drc_append_standard_epilogue(drc, cycles, 0, 1); // <epilogue> + + if (code) + emit_jmp(DRCTOP, code); // jmp code + else + drc_append_tentative_fixed_dispatcher(drc, newpc); // <dispatch> +} + + + +/*************************************************************************** + CORE RECOMPILATION +***************************************************************************/ + +static void ddiv(INT64 *rs, INT64 *rt) +{ + if (*rt) + { + mips3.core->r[REG_LO] = *rs / *rt; + mips3.core->r[REG_HI] = *rs % *rt; + } +} + +static void ddivu(UINT64 *rs, UINT64 *rt) +{ + if (*rt) + { + mips3.core->r[REG_LO] = *rs / *rt; + mips3.core->r[REG_HI] = *rs % *rt; + } +} + + +/*------------------------------------------------------------------ + recompile_delay_slot +------------------------------------------------------------------*/ + +static int recompile_delay_slot(drc_core *drc, UINT32 pc) +{ + UINT8 *saved_top; + UINT32 result; + UINT32 physpc; + +#ifdef MAME_DEBUG + if (Machine->debug_mode) + { + /* emit debugging */ + emit_mov_r32_imm(DRCTOP, REG_EDI, pc); + drc_append_call_debugger(drc); + } +#endif + + saved_top = drc->cache_top; + + /* recompile the instruction as-is */ + in_delay_slot = 1; + physpc = pc; + mips3com_translate_address(mips3.core, ADDRESS_SPACE_PROGRAM, &physpc); + result = recompile_instruction(drc, pc, physpc); // <next instruction> + in_delay_slot = 0; + + /* if the instruction can cause an exception, recompile setting nextpc */ + if (result & RECOMPILE_MAY_CAUSE_EXCEPTION) + { + drc->cache_top = saved_top; + emit_mov_m32_imm(DRCTOP, MABS(&mips3.nextpc), 0); // bogus nextpc for exceptions + result = recompile_instruction(drc, pc, physpc); // <next instruction> + emit_mov_m32_imm(DRCTOP, MABS(&mips3.nextpc), ~0); // reset nextpc + } + + return (result >> 8) & 0xfff; +} + + +/*------------------------------------------------------------------ + recompile_instruction +------------------------------------------------------------------*/ + +static UINT32 recompile_instruction(drc_core *drc, UINT32 pc, UINT32 physpc) +{ + emit_link link1, link2 = { 0 }, link3; + UINT32 op = cpu_readop32(physpc); + int cycles; + + if (LOG_CODE) + log_add_disasm_comment(mips3.log, drc->cache_top, pc, op); + + switch (op >> 26) + { + case 0x00: /* SPECIAL */ + return recompile_special(drc, pc, op); + + case 0x01: /* REGIMM */ + return recompile_regimm(drc, pc, op); + + case 0x02: /* J */ + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, (pc & 0xf0000000) | (LIMMVAL << 2), 1+cycles); // <branch or dispatch> + return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING; + + case 0x03: /* JAL */ + emit_mov_m64_imm32(DRCTOP, REGADDR(31), pc + 8); // mov [31],pc + 8 + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, (pc & 0xf0000000) | (LIMMVAL << 2), 1+cycles); // <branch or dispatch> + return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING; + + case 0x04: /* BEQ */ + if (RSREG == RTREG) + { + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING; + } + else if (RSREG == 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo + emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi + emit_jcc_near_link(DRCTOP, COND_NZ, &link1); // jnz skip + } + else if (RTREG == 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // or eax,[rsreg].hi + emit_jcc_near_link(DRCTOP, COND_NZ, &link1); // jnz skip + } + else + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo + emit_jcc_near_link(DRCTOP, COND_NE, &link1); // jne skip + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi + emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi + emit_jcc_near_link(DRCTOP, COND_NE, &link2); // jne skip + } + + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + resolve_link(DRCTOP, &link1); // skip: + if (RSREG != 0 && RTREG != 0) + resolve_link(DRCTOP, &link2); // skip: + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x05: /* BNE */ + if (RSREG == 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo + emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi + emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz skip + } + else if (RTREG == 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // or eax,[rsreg].hi + emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz skip + } + else + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo + emit_jcc_short_link(DRCTOP, COND_NE, &link2); // jne takeit + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi + emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi + emit_jcc_near_link(DRCTOP, COND_E, &link1); // je skip + resolve_link(DRCTOP, &link2); // takeit: + } + + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + resolve_link(DRCTOP, &link1); // skip: + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x06: /* BLEZ */ + if (RSREG == 0) + { + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING; + } + else + { + emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0 + emit_jcc_near_link(DRCTOP, COND_G, &link1); // jg skip + emit_jcc_short_link(DRCTOP, COND_L, &link2); // jl takeit + emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), 0); // cmp [rsreg].lo,0 + emit_jcc_near_link(DRCTOP, COND_NE, &link3); // jne skip + resolve_link(DRCTOP, &link2); // takeit: + } + + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + resolve_link(DRCTOP, &link1); // skip: + resolve_link(DRCTOP, &link3); // skip: + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x07: /* BGTZ */ + if (RSREG == 0) + return RECOMPILE_SUCCESSFUL_CP(1,4); + else + { + emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0 + emit_jcc_near_link(DRCTOP, COND_L, &link1); // jl skip + emit_jcc_short_link(DRCTOP, COND_G, &link2); // jg takeit + emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), 0); // cmp [rsreg].lo,0 + emit_jcc_near_link(DRCTOP, COND_E, &link3); // je skip + resolve_link(DRCTOP, &link2); // takeit: + } + + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + resolve_link(DRCTOP, &link1); // skip: + resolve_link(DRCTOP, &link3); // skip: + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x08: /* ADDI */ + if (RSREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_jcc(DRCTOP, COND_O, mips3.drcdata->generate_overflow_exception); // jo generate_overflow_exception + if (RTREG != 0) + { + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax + } + } + else if (RTREG != 0) + emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), SIMMVAL); // mov [rtreg],const + return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; + + case 0x09: /* ADDIU */ + if (RTREG != 0) + { + if (RSREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax + } + else + emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), SIMMVAL); // mov [rtreg],const + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x0a: /* SLTI */ + if (RTREG != 0) + { + if (RSREG != 0) + { + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] + emit_sub_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // sub eax,[rtreg].lo + emit_sbb_r32_imm(DRCTOP, REG_EDX, ((INT32)SIMMVAL >> 31)); // sbb edx,[rtreg].lo + emit_shr_r32_imm(DRCTOP, REG_EDX, 31); // shr edx,31 + emit_mov_m32_r32(DRCTOP, REGADDRLO(RTREG), REG_EDX); // mov [rdreg].lo,edx + emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rdreg].hi,0 + } + else + { + emit_mov_m32_imm(DRCTOP, REGADDRLO(RTREG), (0 < SIMMVAL)); // mov [rtreg].lo,const + emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,sign-extend(const) + } + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x0b: /* SLTIU */ + if (RTREG != 0) + { + if (RSREG != 0) + { + emit_xor_r32_r32(DRCTOP, REG_ECX, REG_ECX); // xor ecx,ecx + emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), ((INT32)SIMMVAL >> 31)); // cmp [rsreg].hi,upper + emit_jcc_short_link(DRCTOP, COND_B, &link1); // jb takeit + emit_jcc_short_link(DRCTOP, COND_A, &link2); // ja skip + emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), SIMMVAL); // cmp [rsreg].lo,lower + emit_jcc_short_link(DRCTOP, COND_AE, &link3); // jae skip + resolve_link(DRCTOP, &link1); // takeit: + emit_add_r32_imm(DRCTOP, REG_ECX, 1); // add ecx,1 + resolve_link(DRCTOP, &link2); // skip: + resolve_link(DRCTOP, &link3); // skip: + emit_mov_m32_r32(DRCTOP, REGADDRLO(RTREG), REG_ECX); // mov [rtreg].lo,ecx + emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,sign-extend(const) + } + else + { + emit_mov_m32_imm(DRCTOP, REGADDRLO(RTREG), (0 < SIMMVAL)); // mov [rtreg].lo,const + emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,sign-extend(const) + } + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x0c: /* ANDI */ + if (RTREG != 0) + { + if (RSREG == RTREG) + { + emit_and_m32_imm(DRCTOP, REGADDRLO(RTREG), UIMMVAL); // and [rtreg],UIMMVAL + emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,0 + } + else if (RSREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_and_r32_imm(DRCTOP, REG_EAX, UIMMVAL); // and eax,UIMMVAL + emit_mov_m32_r32(DRCTOP, REGADDRLO(RTREG), REG_EAX); // mov [rtreg].lo,eax + emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,0 + } + else + emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), 0); // mov [rtreg],0 + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x0d: /* ORI */ + if (RTREG != 0) + { + if (RSREG == RTREG) + emit_or_m32_imm(DRCTOP, REGADDRLO(RTREG), UIMMVAL); // or [rtreg].lo,UIMMVAL + else if (RSREG != 0) + { + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] + emit_or_r32_imm(DRCTOP, REG_EAX, UIMMVAL); // or eax,UIMMVAL + emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax + } + else + emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), UIMMVAL); // mov [rtreg],const + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x0e: /* XORI */ + if (RTREG != 0) + { + if (RSREG == RTREG) + emit_xor_m32_imm(DRCTOP, REGADDRLO(RTREG), UIMMVAL); // xor [rtreg].lo,UIMMVAL + else if (RSREG != 0) + { + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] + emit_xor_r32_imm(DRCTOP, REG_EAX, UIMMVAL); // xor eax,UIMMVAL + emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax + } + else + emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), UIMMVAL); // mov [rtreg],const + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x0f: /* LUI */ + if (RTREG != 0) + emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), UIMMVAL << 16); // mov [rtreg],const << 16 + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x10: /* COP0 */ + return recompile_cop0(drc, pc, op) | RECOMPILE_MAY_CAUSE_EXCEPTION; + + case 0x11: /* COP1 */ + return recompile_cop1(drc, pc, op) | RECOMPILE_MAY_CAUSE_EXCEPTION; + + case 0x12: /* COP2 */ + emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception + return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING; + + case 0x13: /* COP1X - R5000 */ + if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV) + { + emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception + return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING; + } + return recompile_cop1x(drc, pc, op) | RECOMPILE_MAY_CAUSE_EXCEPTION; + + case 0x14: /* BEQL */ + if (RSREG == RTREG) + { + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING; + } + else if (RSREG == 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo + emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi + emit_jcc_near_link(DRCTOP, COND_NZ, &link1); // jnz skip + } + else if (RTREG == 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // or eax,[rsreg].hi + emit_jcc_near_link(DRCTOP, COND_NZ, &link1); // jnz skip + } + else + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo + emit_jcc_near_link(DRCTOP, COND_NE, &link1); // jne skip + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi + emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi + emit_jcc_near_link(DRCTOP, COND_NE, &link2); // jne skip + } + + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + resolve_link(DRCTOP, &link1); // skip: + if (RSREG != 0 && RTREG != 0) + resolve_link(DRCTOP, &link2); // skip: + return RECOMPILE_SUCCESSFUL_CP(1,8); + + case 0x15: /* BNEL */ + if (RSREG == 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo + emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi + emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz skip + } + else if (RTREG == 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // or eax,[rsreg].hi + emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz skip + } + else + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo + emit_jcc_short_link(DRCTOP, COND_NE, &link2); // jne takeit + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi + emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi + emit_jcc_near_link(DRCTOP, COND_E, &link1); // je skip + resolve_link(DRCTOP, &link2); // takeit: + } + + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + resolve_link(DRCTOP, &link1); // skip: + return RECOMPILE_SUCCESSFUL_CP(1,8); + + case 0x16: /* BLEZL */ + if (RSREG == 0) + { + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING; + } + else + { + emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0 + emit_jcc_near_link(DRCTOP, COND_G, &link1); // jg skip + emit_jcc_short_link(DRCTOP, COND_L, &link2); // jl takeit + emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), 0); // cmp [rsreg].lo,0 + emit_jcc_near_link(DRCTOP, COND_NE, &link3); // jne skip + resolve_link(DRCTOP, &link2); // takeit: + } + + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + resolve_link(DRCTOP, &link1); // skip: + resolve_link(DRCTOP, &link3); // skip: + return RECOMPILE_SUCCESSFUL_CP(1,8); + + case 0x17: /* BGTZL */ + if (RSREG == 0) + return RECOMPILE_SUCCESSFUL_CP(1,8); + else + { + emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0 + emit_jcc_near_link(DRCTOP, COND_L, &link1); // jl skip + emit_jcc_short_link(DRCTOP, COND_G, &link2); // jg takeit + emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), 0); // cmp [rsreg].lo,0 + emit_jcc_near_link(DRCTOP, COND_E, &link3); // je skip + resolve_link(DRCTOP, &link2); // takeit: + } + + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + resolve_link(DRCTOP, &link1); // skip: + resolve_link(DRCTOP, &link3); // skip: + return RECOMPILE_SUCCESSFUL_CP(1,8); + + case 0x18: /* DADDI */ + if (RSREG != 0) + { + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_adc_r32_imm(DRCTOP, REG_EDX, (SIMMVAL < 0) ? -1 : 0); // adc edx,signext(SIMMVAL) + emit_jcc(DRCTOP, COND_O, mips3.drcdata->generate_overflow_exception); // jo generate_overflow_exception + if (RTREG != 0) + emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax + } + else if (RTREG != 0) + emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), SIMMVAL); // mov [rtreg],const + return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; + + case 0x19: /* DADDIU */ + if (RTREG != 0) + { + if (RSREG != 0) + { + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_adc_r32_imm(DRCTOP, REG_EDX, (SIMMVAL < 0) ? -1 : 0); // adc edx,signext(SIMMVAL) + emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax + } + else + emit_mov_m64_imm32(DRCTOP, REGADDR(RTREG), SIMMVAL); // mov [rtreg],const + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x1a: /* LDL */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + if (SIMMVAL) + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 4, 0)); // lea ecx,[eax*4] + emit_and_r32_imm(DRCTOP, REG_EAX, ~7); // and eax,~7 + emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1 + emit_mov_r32_imm(DRCTOP, REG_EBP, -1); // mov ebp,-1 + if (!mips3.core->bigendian) + emit_xor_r32_imm(DRCTOP, REG_ECX, 0x1c); // xor ecx,0x1c + emit_shr_r32_cl(DRCTOP, REG_EBP); // shr ebp,cl + emit_shrd_r32_r32_cl(DRCTOP, REG_EBX, REG_EBP); // shrd ebx,ebp,cl + emit_shr_r32_cl(DRCTOP, REG_EBP); // shr ebp,cl + emit_not_r32(DRCTOP, REG_EBX); // not ebx + emit_not_r32(DRCTOP, REG_EBP); // not ebp + emit_push_r32(DRCTOP, REG_ECX); // push ecx + emit_push_r32(DRCTOP, REG_EBP); // push ebp + emit_push_r32(DRCTOP, REG_EBX); // push ebx + emit_push_r32(DRCTOP, REG_EAX); // push eax + emit_call(DRCTOP, mips3.drcdata->read_and_translate_double_masked); // call read_and_translate_double_masked + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + emit_pop_r32(DRCTOP, REG_ECX); // pop ecx + + if (RTREG != 0) + { + emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1 + emit_mov_r32_imm(DRCTOP, REG_EBP, -1); // mov ebp,-1 + emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl + emit_shld_r32_r32_cl(DRCTOP, REG_EBP, REG_EBX); // shld ebp,ebx,cl + emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl + emit_not_r32(DRCTOP, REG_EBX); // not ebx + emit_not_r32(DRCTOP, REG_EBP); // not ebp + emit_shld_r32_r32_cl(DRCTOP, REG_EDX, REG_EAX); // shld edx,eax,cl + emit_shl_r32_cl(DRCTOP, REG_EAX); // shl eax,cl + emit_shld_r32_r32_cl(DRCTOP, REG_EDX, REG_EAX); // shld edx,eax,cl + emit_shl_r32_cl(DRCTOP, REG_EAX); // shl eax,cl + emit_and_r32_m32(DRCTOP, REG_EBX, REGADDRLO(RTREG)); // and ebx,[rtreg].lo + emit_and_r32_m32(DRCTOP, REG_EBP, REGADDRHI(RTREG)); // and ebp,[rtreg].hi + emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx + emit_or_r32_r32(DRCTOP, REG_EDX, REG_EBP); // or edx,ebp + emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax + } + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x1b: /* LDR */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + if (SIMMVAL) + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 4, 0)); // lea ecx,[eax*4] + emit_and_r32_imm(DRCTOP, REG_EAX, ~7); // and eax,~7 + emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1 + emit_mov_r32_imm(DRCTOP, REG_EBP, -1); // mov ebp,-1 + if (mips3.core->bigendian) + emit_xor_r32_imm(DRCTOP, REG_ECX, 0x1c); // xor ecx,0x1c + emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl + emit_shld_r32_r32_cl(DRCTOP, REG_EBP, REG_EBX); // shld ebp,ebx,cl + emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl + emit_not_r32(DRCTOP, REG_EBX); // not ebx + emit_not_r32(DRCTOP, REG_EBP); // not ebp + emit_push_r32(DRCTOP, REG_ECX); // push ecx + emit_push_r32(DRCTOP, REG_EBP); // push ebp + emit_push_r32(DRCTOP, REG_EBX); // push ebx + emit_push_r32(DRCTOP, REG_EAX); // push eax + emit_call(DRCTOP, mips3.drcdata->read_and_translate_double_masked); // call read_and_translate_double_masked + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + emit_pop_r32(DRCTOP, REG_ECX); // pop ecx + + if (RTREG != 0) + { + emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1 + emit_mov_r32_imm(DRCTOP, REG_EBP, -1); // mov ebp,-1 + emit_shr_r32_cl(DRCTOP, REG_EBP); // shr ebp,cl + emit_shrd_r32_r32_cl(DRCTOP, REG_EBX, REG_EBP); // shrd ebx,ebp,cl + emit_shr_r32_cl(DRCTOP, REG_EBP); // shr ebp,cl + emit_not_r32(DRCTOP, REG_EBX); // not ebx + emit_not_r32(DRCTOP, REG_EBP); // not ebp + emit_shrd_r32_r32_cl(DRCTOP, REG_EAX, REG_EDX); // shld eax,edx,cl + emit_shr_r32_cl(DRCTOP, REG_EDX); // shl edx,cl + emit_shrd_r32_r32_cl(DRCTOP, REG_EAX, REG_EDX); // shld eax,edx,cl + emit_shr_r32_cl(DRCTOP, REG_EDX); // shl edx,cl + emit_and_r32_m32(DRCTOP, REG_EBX, REGADDRLO(RTREG)); // and ebx,[rtreg].lo + emit_and_r32_m32(DRCTOP, REG_EBP, REGADDRHI(RTREG)); // and ebp,[rtreg].hi + emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx + emit_or_r32_r32(DRCTOP, REG_EDX, REG_EBP); // or edx,ebp + emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax + } + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x1c: /* IDT-specific opcodes: mad/madu/mul on R4640/4650, msub on RC32364 */ + switch (op & 0x1f) + { + case 0: /* MAD */ + if (RSREG != 0 && RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg] + emit_mov_r32_m32(DRCTOP, REG_EDX, REGADDRLO(RTREG)); // mov edx,[rtreg] + emit_imul_r32(DRCTOP, REG_EDX); // imul edx + emit_add_r32_m32(DRCTOP, REG_EAX, LOADDRLO); // add eax,[lo] + emit_adc_r32_m32(DRCTOP, REG_EDX, HIADDRLO); // adc edx,[hi] + emit_mov_r32_r32(DRCTOP, REG_EBX, REG_EDX); // mov ebx,edx + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax + emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EBX); // mov eax,ebx + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax + } + return RECOMPILE_SUCCESSFUL_CP(3,4); + + case 1: /* MADU */ + if (RSREG != 0 && RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg] + emit_mov_r32_m32(DRCTOP, REG_EDX, REGADDRLO(RTREG)); // mov edx,[rtreg] + emit_mul_r32(DRCTOP, REG_EDX); // mul edx + emit_add_r32_m32(DRCTOP, REG_EAX, LOADDRLO); // add eax,[lo] + emit_adc_r32_m32(DRCTOP, REG_EDX, HIADDRLO); // adc edx,[hi] + emit_mov_r32_r32(DRCTOP, REG_EBX, REG_EDX); // mov ebx,edx + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax + emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EBX); // mov eax,ebx + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax + } + return RECOMPILE_SUCCESSFUL_CP(3,4); + + case 2: /* MUL */ + if (RDREG != 0) + { + if (RSREG != 0 && RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_imul_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // imul eax,[rtreg].lo + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else + emit_zero_m64(DRCTOP, REGADDR(RDREG)); // mov [rdreg],0 + } + return RECOMPILE_SUCCESSFUL_CP(3,4); + } + break; + + case 0x20: /* LB */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 + if (RSREG != 0 && SIMMVAL != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_push_r32(DRCTOP, REG_EAX); // push eax + } + else if (RSREG != 0) + emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo + else + emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL + emit_call(DRCTOP, mips3.drcdata->read_and_translate_byte_signed); // call read_and_translate_byte_signed + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + if (RTREG != 0) + { + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax + } + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x21: /* LH */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 + if (RSREG != 0 && SIMMVAL != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_push_r32(DRCTOP, REG_EAX); // push eax + } + else if (RSREG != 0) + emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo + else + emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL + emit_call(DRCTOP, mips3.drcdata->read_and_translate_half_signed); // call read_and_translate_half_signed + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + if (RTREG != 0) + { + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax + } + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x22: /* LWL */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4 + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + if (SIMMVAL) + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 8, 0)); // lea ecx,[eax*8] + emit_and_r32_imm(DRCTOP, REG_EAX, ~3); // and eax,~3 + emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1 + if (!mips3.core->bigendian) + emit_xor_r32_imm(DRCTOP, REG_ECX, 0x18); // xor ecx,0x18 + emit_shr_r32_cl(DRCTOP, REG_EBX); // shr ebx,cl + emit_not_r32(DRCTOP, REG_EBX); // not ebx + emit_push_r32(DRCTOP, REG_ECX); // push ecx + emit_push_r32(DRCTOP, REG_EBX); // push ebx + emit_push_r32(DRCTOP, REG_EAX); // push eax + emit_call(DRCTOP, mips3.drcdata->read_and_translate_word_masked); // call read_and_translate_word_masked + emit_add_r32_imm(DRCTOP, REG_ESP, 8); // add esp,8 + emit_pop_r32(DRCTOP, REG_ECX); // pop ecx + + if (RTREG != 0) + { + emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1 + emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl + emit_not_r32(DRCTOP, REG_EBX); // not ebx + emit_shl_r32_cl(DRCTOP, REG_EAX); // shl eax,cl + emit_and_r32_m32(DRCTOP, REG_EBX, REGADDRLO(RTREG)); // and ebx,[rtreg].lo + emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax + } + emit_add_r32_imm(DRCTOP, REG_ESP, 4); // add esp,4 + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x23: /* LW */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 + if (RSREG != 0 && SIMMVAL != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_push_r32(DRCTOP, REG_EAX); // push eax + } + else if (RSREG != 0) + emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo + else + emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL + emit_call(DRCTOP, mips3.drcdata->read_and_translate_word); // call read_and_translate_word + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + if (RTREG != 0) + { + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax + } + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x24: /* LBU */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 + if (RSREG != 0 && SIMMVAL != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_push_r32(DRCTOP, REG_EAX); // push eax + } + else if (RSREG != 0) + emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo + else + emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL + emit_call(DRCTOP, mips3.drcdata->read_and_translate_byte_unsigned); // call read_and_translate_byte_unsigned + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + if (RTREG != 0) + { + emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,0 + emit_mov_m32_r32(DRCTOP, REGADDRLO(RTREG), REG_EAX); // mov [rtreg].lo,eax + } + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x25: /* LHU */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 + if (RSREG != 0 && SIMMVAL != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_push_r32(DRCTOP, REG_EAX); // push eax + } + else if (RSREG != 0) + emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo + else + emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL + emit_call(DRCTOP, mips3.drcdata->read_and_translate_half_unsigned); // call read_and_translate_half_unsigned + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + if (RTREG != 0) + { + emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,0 + emit_mov_m32_r32(DRCTOP, REGADDRLO(RTREG), REG_EAX); // mov [rtreg].lo,eax + } + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x26: /* LWR */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4 + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + if (SIMMVAL) + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 8, 0)); // lea ecx,[eax*8] + emit_and_r32_imm(DRCTOP, REG_EAX, ~3); // and eax,~3 + emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1 + if (mips3.core->bigendian) + emit_xor_r32_imm(DRCTOP, REG_ECX, 0x18); // xor ecx,0x18 + emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl + emit_not_r32(DRCTOP, REG_EBX); // not ebx + emit_push_r32(DRCTOP, REG_ECX); // push ecx + emit_push_r32(DRCTOP, REG_EBX); // push ebx + emit_push_r32(DRCTOP, REG_EAX); // push eax + emit_call(DRCTOP, mips3.drcdata->read_and_translate_word_masked); // call read_and_translate_word_masked + emit_add_r32_imm(DRCTOP, REG_ESP, 8); // add esp,8 + emit_pop_r32(DRCTOP, REG_ECX); // pop ecx + + if (RTREG != 0) + { + emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1 + emit_shr_r32_cl(DRCTOP, REG_EBX); // shr ebx,cl + emit_not_r32(DRCTOP, REG_EBX); // not ebx + emit_shr_r32_cl(DRCTOP, REG_EAX); // shr eax,cl + emit_and_r32_m32(DRCTOP, REG_EBX, REGADDRLO(RTREG)); // and ebx,[rtreg].lo + emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax + } + emit_add_r32_imm(DRCTOP, REG_ESP, 4); // add esp,4 + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x27: /* LWU */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 + if (RSREG != 0 && SIMMVAL != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_push_r32(DRCTOP, REG_EAX); // push eax + } + else if (RSREG != 0) + emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo + else + emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL + emit_call(DRCTOP, mips3.drcdata->read_and_translate_word); // call read_and_translate_word + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + if (RTREG != 0) + { + emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,0 + emit_mov_m32_r32(DRCTOP, REGADDRLO(RTREG), REG_EAX); // mov [rtreg].lo,eax + } + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x28: /* SB */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4 + if (RTREG != 0) + emit_push_m32(DRCTOP, REGADDRLO(RTREG)); // push dword [rtreg].lo + else + emit_push_imm(DRCTOP, 0); // push 0 + if (RSREG != 0 && SIMMVAL != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_push_r32(DRCTOP, REG_EAX); // push eax + } + else if (RSREG != 0) + emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo + else + emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL + emit_call(DRCTOP, mips3.drcdata->write_and_translate_byte); // call writebyte + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x29: /* SH */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4 + if (RTREG != 0) + emit_push_m32(DRCTOP, REGADDRLO(RTREG)); // push dword [rtreg].lo + else + emit_push_imm(DRCTOP, 0); // push 0 + if (RSREG != 0 && SIMMVAL != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_push_r32(DRCTOP, REG_EAX); // push eax + } + else if (RSREG != 0) + emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo + else + emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL + emit_call(DRCTOP, mips3.drcdata->write_and_translate_half); // call writehalf + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x2a: /* SWL */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4 + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + if (SIMMVAL) + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 8, 0)); // lea ecx,[eax*8] + emit_and_r32_imm(DRCTOP, REG_EAX, ~3); // and eax,~3 + emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1 + if (!mips3.core->bigendian) + emit_xor_r32_imm(DRCTOP, REG_ECX, 0x18); // xor ecx,0x18 + emit_shr_r32_cl(DRCTOP, REG_EBX); // shr ebx,cl + emit_not_r32(DRCTOP, REG_EBX); // not ebx + emit_push_r32(DRCTOP, REG_EBX); // push ebx + if (RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EDX, REGADDRLO(RTREG)); // mov edx,[rtreg].lo + emit_shr_r32_cl(DRCTOP, REG_EDX); // shr edx,cl + emit_push_r32(DRCTOP, REG_EDX); // push edx + } + else + emit_push_imm(DRCTOP, 0); // push 0 + emit_push_r32(DRCTOP, REG_EAX); // push eax + emit_call(DRCTOP, mips3.drcdata->write_and_translate_word_masked); // call write_and_translate_word_masked + emit_add_r32_imm(DRCTOP, REG_ESP, 16); // add esp,16 + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x2b: /* SW */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4 + if (RTREG != 0) + emit_push_m32(DRCTOP, REGADDRLO(RTREG)); // push dword [rtreg].lo + else + emit_push_imm(DRCTOP, 0); // push 0 + if (RSREG != 0 && SIMMVAL != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_push_r32(DRCTOP, REG_EAX); // push eax + } + else if (RSREG != 0) + emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo + else + emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL + emit_call(DRCTOP, mips3.drcdata->write_and_translate_word); // call write_and_translate_word + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x2c: /* SDL */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_sub_r32_imm(DRCTOP, REG_ESP, 12); // sub esp,12 + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + if (SIMMVAL) + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 4, 0)); // lea ecx,[eax*4] + emit_and_r32_imm(DRCTOP, REG_EAX, ~7); // and eax,~7 + emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1 + emit_mov_r32_imm(DRCTOP, REG_EBP, -1); // mov ebp,-1 + if (!mips3.core->bigendian) + emit_xor_r32_imm(DRCTOP, REG_ECX, 0x1c); // xor ecx,0x1c + emit_shr_r32_cl(DRCTOP, REG_EBP); // shr ebp,cl + emit_shrd_r32_r32_cl(DRCTOP, REG_EBX, REG_EBP); // shrd ebx,ebp,cl + emit_shr_r32_cl(DRCTOP, REG_EBP); // shr ebp,cl + emit_not_r32(DRCTOP, REG_EBP); // not ebp + emit_not_r32(DRCTOP, REG_EBX); // not ebx + emit_push_r32(DRCTOP, REG_EBP); // push ebp + emit_push_r32(DRCTOP, REG_EBX); // push ebx + if (RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EBX, REGADDRLO(RTREG)); // mov ebx,[rtreg].lo + emit_mov_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // mov edx,[rtreg].hi + emit_shrd_r32_r32_cl(DRCTOP, REG_EBX, REG_EDX); // shrd ebx,edx,cl + emit_shr_r32_cl(DRCTOP, REG_EDX); // shr edx,cl + emit_shrd_r32_r32_cl(DRCTOP, REG_EBX, REG_EDX); // shrd ebx,edx,cl + emit_shr_r32_cl(DRCTOP, REG_EDX); // shr edx,cl + emit_push_r32(DRCTOP, REG_EDX); // push edx + emit_push_r32(DRCTOP, REG_EBX); // push ebx + } + else + { + emit_push_imm(DRCTOP, 0); // push 0 + emit_push_imm(DRCTOP, 0); // push 0 + } + emit_push_r32(DRCTOP, REG_EAX); // push eax + emit_call(DRCTOP, mips3.drcdata->write_and_translate_double_masked); // call write_and_translate_double_masked + emit_add_r32_imm(DRCTOP, REG_ESP, 32); // add esp,32 + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x2d: /* SDR */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_sub_r32_imm(DRCTOP, REG_ESP, 12); // sub esp,12 + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + if (SIMMVAL) + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 4, 0)); // lea ecx,[eax*4] + emit_and_r32_imm(DRCTOP, REG_EAX, ~7); // and eax,~7 + emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1 + emit_mov_r32_imm(DRCTOP, REG_EBP, -1); // mov ebp,-1 + if (mips3.core->bigendian) + emit_xor_r32_imm(DRCTOP, REG_ECX, 0x1c); // xor ecx,0x1c + emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl + emit_shld_r32_r32_cl(DRCTOP, REG_EBP, REG_EBX); // shld ebp,ebx,cl + emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl + emit_not_r32(DRCTOP, REG_EBP); // not ebp + emit_not_r32(DRCTOP, REG_EBX); // not ebx + emit_push_r32(DRCTOP, REG_EBP); // push ebp + emit_push_r32(DRCTOP, REG_EBX); // push ebx + if (RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EBX, REGADDRLO(RTREG)); // mov ebx,[rtreg].lo + emit_mov_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // mov edx,[rtreg].hi + emit_shld_r32_r32_cl(DRCTOP, REG_EDX, REG_EBX); // shld edx,ebx,cl + emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl + emit_shld_r32_r32_cl(DRCTOP, REG_EDX, REG_EBX); // shld edx,ebx,cl + emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl + emit_push_r32(DRCTOP, REG_EDX); // push edx + emit_push_r32(DRCTOP, REG_EBX); // push ebx + } + else + { + emit_push_imm(DRCTOP, 0); // push 0 + emit_push_imm(DRCTOP, 0); // push 0 + } + emit_push_r32(DRCTOP, REG_EAX); // push eax + emit_call(DRCTOP, mips3.drcdata->write_and_translate_double_masked); // call write_and_translate_double_masked + emit_add_r32_imm(DRCTOP, REG_ESP, 32); // add esp,32 + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x2e: /* SWR */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4 + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + if (SIMMVAL) + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_lea_r32_m32(DRCTOP, REG_ECX, MISD(REG_EAX, 8, 0)); // lea ecx,[eax*8] + emit_and_r32_imm(DRCTOP, REG_EAX, ~3); // and eax,~3 + emit_mov_r32_imm(DRCTOP, REG_EBX, -1); // mov ebx,-1 + if (mips3.core->bigendian) + emit_xor_r32_imm(DRCTOP, REG_ECX, 0x18); // xor ecx,0x18 + emit_shl_r32_cl(DRCTOP, REG_EBX); // shl ebx,cl + emit_not_r32(DRCTOP, REG_EBX); // not ebx + emit_push_r32(DRCTOP, REG_EBX); // push ebx + if (RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EDX, REGADDRLO(RTREG)); // mov edx,[rtreg].lo + emit_shl_r32_cl(DRCTOP, REG_EDX); // shl edx,cl + emit_push_r32(DRCTOP, REG_EDX); // push edx + } + else + emit_push_imm(DRCTOP, 0); // push 0 + emit_push_r32(DRCTOP, REG_EAX); // push eax + emit_call(DRCTOP, mips3.drcdata->write_and_translate_word_masked); // call write_and_translate_word_masked + emit_add_r32_imm(DRCTOP, REG_ESP, 16); // add esp,16 + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x2f: /* CACHE */ + return RECOMPILE_SUCCESSFUL_CP(1,4); + +// case 0x30: /* LL */ logerror("mips3 Unhandled op: LL\n"); break; + + case 0x31: /* LWC1 */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 + if (RSREG != 0 && SIMMVAL != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].los + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_push_r32(DRCTOP, REG_EAX); // push eax + } + else if (RSREG != 0) + emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo + else + emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL + emit_call(DRCTOP, mips3.drcdata->read_and_translate_word); // call read_and_translate_word + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + emit_mov_m32_r32(DRCTOP, FPR32ADDR(RTREG), REG_EAX); // mov [rtreg],eax + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x32: /* LWC2 */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 + if (RSREG != 0 && SIMMVAL != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_push_r32(DRCTOP, REG_EAX); // push eax + } + else if (RSREG != 0) + emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo + else + emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL + emit_call(DRCTOP, mips3.drcdata->read_and_translate_word); // call read_and_translate_word + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + emit_mov_m32_r32(DRCTOP, CPR2ADDR(RTREG), REG_EAX); // mov [rtreg],eax + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x33: /* PREF */ + if (mips3.core->flavor >= MIPS3_TYPE_MIPS_IV) + return RECOMPILE_SUCCESSFUL_CP(1,4); + else + { + emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception + return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING; + } + +// case 0x34: /* LLD */ logerror("mips3 Unhandled op: LLD\n"); break; + + case 0x35: /* LDC1 */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 + if (RSREG != 0 && SIMMVAL != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_push_r32(DRCTOP, REG_EAX); // push eax + } + else if (RSREG != 0) + emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo + else + emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL + emit_call(DRCTOP, mips3.drcdata->read_and_translate_double); // call read_and_translate_double + emit_mov_m64_r64(DRCTOP, FPR64ADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x36: /* LDC2 */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 + if (RSREG != 0 && SIMMVAL != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_push_r32(DRCTOP, REG_EAX); // push eax + } + else if (RSREG != 0) + emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo + else + emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL + emit_call(DRCTOP, mips3.drcdata->read_and_translate_double); // call read_and_translate_word + emit_mov_m64_r64(DRCTOP, CPR2ADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x37: /* LD */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 + if (RSREG != 0 && SIMMVAL != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_push_r32(DRCTOP, REG_EAX); // push eax + } + else if (RSREG != 0) + emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo + else + emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL + emit_call(DRCTOP, mips3.drcdata->read_and_translate_double); // call read_and_translate_double + if (RTREG != 0) + emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + +// case 0x38: /* SC */ logerror("mips3 Unhandled op: SC\n"); break; + + case 0x39: /* SWC1 */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4 + emit_push_m32(DRCTOP, FPR32ADDR(RTREG)); // push dword [rtreg] + if (RSREG != 0 && SIMMVAL != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_push_r32(DRCTOP, REG_EAX); // push eax + } + else if (RSREG != 0) + emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo + else + emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL + emit_call(DRCTOP, mips3.drcdata->write_and_translate_word); // call write_and_translate_word + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x3a: /* SWC2 */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4 + emit_push_m32(DRCTOP, CPR2ADDR(RTREG)); // push dword [rtreg] + if (RSREG != 0 && SIMMVAL != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_push_r32(DRCTOP, REG_EAX); // push eax + } + else if (RSREG != 0) + emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo + else + emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL + emit_call(DRCTOP, mips3.drcdata->write_and_translate_word); // call write_and_translate_word + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + +// case 0x3b: /* SWC3 */ invalid_instruction(op); break; +// case 0x3c: /* SCD */ logerror("mips3 Unhandled op: SCD\n"); break; + + case 0x3d: /* SDC1 */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_push_m32(DRCTOP, FPR64ADDRHI(RTREG)); // push dword [rtreg].hi + emit_push_m32(DRCTOP, FPR64ADDRLO(RTREG)); // push dword [rtreg].lo + if (RSREG != 0 && SIMMVAL != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_push_r32(DRCTOP, REG_EAX); // push eax + } + else if (RSREG != 0) + emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo + else + emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL + emit_call(DRCTOP, mips3.drcdata->write_and_translate_double); // call write_and_translate_double + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x3e: /* SDC2 */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_push_m32(DRCTOP, CPR2ADDRHI(RTREG)); // push dword [rtreg].hi + emit_push_m32(DRCTOP, CPR2ADDRLO(RTREG)); // push dword [rtreg].lo + if (RSREG != 0 && SIMMVAL != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_push_r32(DRCTOP, REG_EAX); // push eax + } + else if (RSREG != 0) + emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo + else + emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL + emit_call(DRCTOP, mips3.drcdata->write_and_translate_double); // call write_and_translate_double + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x3f: /* SD */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + if (RTREG != 0) + { + emit_push_m32(DRCTOP, REGADDRHI(RTREG)); // push dword [rtreg].hi + emit_push_m32(DRCTOP, REGADDRLO(RTREG)); // push dword [rtreg].lo + } + else + { + emit_push_imm(DRCTOP, 0); // push 0 + emit_push_imm(DRCTOP, 0); // push 0 + } + if (RSREG != 0 && SIMMVAL != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_add_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // add eax,SIMMVAL + emit_push_r32(DRCTOP, REG_EAX); // push eax + } + else if (RSREG != 0) + emit_push_m32(DRCTOP, REGADDRLO(RSREG)); // push [rsreg].lo + else + emit_push_imm(DRCTOP, SIMMVAL); // push SIMMVAL + emit_call(DRCTOP, mips3.drcdata->write_and_translate_double); // call write_and_translate_double + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + +// default: /* ??? */ invalid_instruction(op); break; + } + return RECOMPILE_UNIMPLEMENTED; +} + + +/*------------------------------------------------------------------ + recompile_special +------------------------------------------------------------------*/ + +static UINT32 recompile_special1(drc_core *drc, UINT32 pc, UINT32 op) +{ + emit_link link1, link2, link3; + int cycles; + + switch (op & 63) + { + case 0x00: /* SLL */ + if (RDREG != 0) + { + if (RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo + if (SHIFT != 0) + emit_shl_r32_imm(DRCTOP, REG_EAX, SHIFT); // shl eax,SHIFT + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else + emit_zero_m64(DRCTOP, REGADDR(RDREG)); + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x01: /* MOVF - R5000*/ + if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV) + { + emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception + return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING; + } + emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp [cf[x]],0 + emit_jcc_short_link(DRCTOP, ((op >> 16) & 1) ? COND_Z : COND_NZ, &link1); // jz/nz skip + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + resolve_link(DRCTOP, &link1); // skip: + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x02: /* SRL */ + if (RDREG != 0) + { + if (RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo + if (SHIFT != 0) + emit_shr_r32_imm(DRCTOP, REG_EAX, SHIFT); // shr eax,SHIFT + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else + emit_zero_m64(DRCTOP, REGADDR(RDREG)); + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x03: /* SRA */ + if (RDREG != 0) + { + if (RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo + if (SHIFT != 0) + emit_sar_r32_imm(DRCTOP, REG_EAX, SHIFT); // sar eax,SHIFT + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else + emit_zero_m64(DRCTOP, REGADDR(RDREG)); + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x04: /* SLLV */ + if (RDREG != 0) + { + if (RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo + if (RSREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RSREG)); // mov ecx,[rsreg].lo + emit_shl_r32_cl(DRCTOP, REG_EAX); // shl eax,cl + } + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else + emit_zero_m64(DRCTOP, REGADDR(RDREG)); + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x06: /* SRLV */ + if (RDREG != 0) + { + if (RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo + if (RSREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RSREG)); // mov ecx,[rsreg].lo + emit_shr_r32_cl(DRCTOP, REG_EAX); // shr eax,cl + } + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else + emit_zero_m64(DRCTOP, REGADDR(RDREG)); + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x07: /* SRAV */ + if (RDREG != 0) + { + if (RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo + if (RSREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RSREG)); // mov ecx,[rsreg].lo + emit_sar_r32_cl(DRCTOP, REG_EAX); // sar eax,cl + } + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else + emit_zero_m64(DRCTOP, REGADDR(RDREG)); + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x08: /* JR */ + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_mov_m32_r32(DRCTOP, MABS(&jr_temp), REG_EAX); // mov jr_temp,eax + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + emit_mov_r32_m32(DRCTOP, REG_EDI, MABS(&jr_temp)); // mov edi,jr_temp + return RECOMPILE_SUCCESSFUL_CP(1+cycles,0) | RECOMPILE_END_OF_STRING | RECOMPILE_ADD_DISPATCH; + + case 0x09: /* JALR */ + if (RDREG != 0) + emit_mov_m64_imm32(DRCTOP, REGADDR(RDREG), pc + 8); // mov [rdreg],pc + 8 + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + emit_mov_r32_m32(DRCTOP, REG_EDI, REGADDRLO(RSREG)); // mov edi,[rsreg].lo + return RECOMPILE_SUCCESSFUL_CP(1+cycles,0) | RECOMPILE_END_OF_STRING | RECOMPILE_ADD_DISPATCH; + + case 0x0a: /* MOVZ - R5000 */ + if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV) + { + emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception + return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING; + } + if (RDREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo + emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi + emit_jcc_short_link(DRCTOP, COND_NZ, &link1); // jnz skip + emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG)); + // mov [rdreg],[rsreg] + resolve_link(DRCTOP, &link1); // skip: + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x0b: /* MOVN - R5000 */ + if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV) + { + emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception + return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING; + } + if (RDREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo + emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi + emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip + emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG)); + // mov [rdreg],[rsreg] + resolve_link(DRCTOP, &link1); // skip: + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x0c: /* SYSCALL */ + emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_syscall_exception); // jmp generate_syscall_exception + return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING; + + case 0x0d: /* BREAK */ + emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_break_exception); // jmp generate_break_exception + return RECOMPILE_SUCCESSFUL | RECOMPILE_MAY_CAUSE_EXCEPTION | RECOMPILE_END_OF_STRING; + + case 0x0f: /* SYNC */ + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x10: /* MFHI */ + if (RDREG != 0) + emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), HIADDR); // mov [rdreg],[hi] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x11: /* MTHI */ + emit_mov_m64_m64(DRCTOP, HIADDR, REGADDR(RSREG)); // mov [hi],[rsreg] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x12: /* MFLO */ + if (RDREG != 0) + emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), LOADDR); // mov [rdreg],[lo] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x13: /* MTLO */ + emit_mov_m64_m64(DRCTOP, LOADDR, REGADDR(RSREG)); // mov [lo],[rsreg] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x14: /* DSLLV */ + if (RDREG != 0) + { + if (RTREG != 0) + { + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg] + if (RSREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RSREG)); // mov ecx,[rsreg].lo + emit_test_r32_imm(DRCTOP, REG_ECX, 0x20); // test ecx,0x20 + emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip + emit_mov_r32_r32(DRCTOP, REG_EDX, REG_EAX); // mov edx,eax + emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax + resolve_link(DRCTOP, &link1); // skip: + emit_shld_r32_r32_cl(DRCTOP, REG_EDX, REG_EAX); // shld edx,eax,cl + emit_shl_r32_cl(DRCTOP, REG_EAX); // shl eax,cl + } + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else + emit_zero_m64(DRCTOP, REGADDR(RDREG)); + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x16: /* DSRLV */ + if (RDREG != 0) + { + if (RTREG != 0) + { + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg] + if (RSREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RSREG)); // mov ecx,[rsreg].lo + emit_test_r32_imm(DRCTOP, REG_ECX, 0x20); // test ecx,0x20 + emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip + emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EDX); // mov eax,edx + emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx + resolve_link(DRCTOP, &link1); // skip: + emit_shrd_r32_r32_cl(DRCTOP, REG_EAX, REG_EDX); // shrd eax,edx,cl + emit_shr_r32_cl(DRCTOP, REG_EDX); // shr edx,cl + } + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else + emit_zero_m64(DRCTOP, REGADDR(RDREG)); + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x17: /* DSRAV */ + if (RDREG != 0) + { + if (RTREG != 0) + { + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg] + if (RSREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RSREG)); // mov ecx,[rsreg].lo + emit_test_r32_imm(DRCTOP, REG_ECX, 0x20); // test ecx,0x20 + emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip + emit_mov_r32_r32(DRCTOP, REG_EAX, REG_EDX); // mov eax,edx + emit_cdq(DRCTOP); // cdq + resolve_link(DRCTOP, &link1); // skip: + emit_shrd_r32_r32_cl(DRCTOP, REG_EAX, REG_EDX); // shrd eax,edx,cl + emit_sar_r32_cl(DRCTOP, REG_EDX); // sar edx,cl + } + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else + emit_zero_m64(DRCTOP, REGADDR(RDREG)); + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x18: /* MULT */ + emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RTREG)); // mov ecx,[rtreg].lo + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_imul_r32(DRCTOP, REG_ECX); // imul ecx + emit_push_r32(DRCTOP, REG_EDX); // push edx + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax + emit_pop_r32(DRCTOP, REG_EAX); // pop eax + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax + return RECOMPILE_SUCCESSFUL_CP(4,4); + + case 0x19: /* MULTU */ + emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RTREG)); // mov ecx,[rtreg].lo + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_mul_r32(DRCTOP, REG_ECX); // mul ecx + emit_push_r32(DRCTOP, REG_EDX); // push edx + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax + emit_pop_r32(DRCTOP, REG_EAX); // pop eax + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax + return RECOMPILE_SUCCESSFUL_CP(4,4); + + case 0x1a: /* DIV */ + if (RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RTREG)); // mov ecx,[rtreg].lo + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_cdq(DRCTOP); // cdq + emit_cmp_r32_imm(DRCTOP, REG_ECX, 0); // cmp ecx,0 + emit_jcc_short_link(DRCTOP, COND_E, &link1); // je skip + emit_idiv_r32(DRCTOP, REG_ECX); // idiv ecx + emit_push_r32(DRCTOP, REG_EDX); // push edx + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax + emit_pop_r32(DRCTOP, REG_EAX); // pop eax + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax + resolve_link(DRCTOP, &link1); // skip: + } + return RECOMPILE_SUCCESSFUL_CP(36,4); + + case 0x1b: /* DIVU */ + if (RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_ECX, REGADDRLO(RTREG)); // mov ecx,[rtreg].lo + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx + emit_cmp_r32_imm(DRCTOP, REG_ECX, 0); // cmp ecx,0 + emit_jcc_short_link(DRCTOP, COND_E, &link1); // je skip + emit_div_r32(DRCTOP, REG_ECX); // div ecx + emit_push_r32(DRCTOP, REG_EDX); // push edx + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, LOADDR, REG_EDX, REG_EAX); // mov [lo],edx:eax + emit_pop_r32(DRCTOP, REG_EAX); // pop eax + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_EAX); // mov [hi],edx:eax + resolve_link(DRCTOP, &link1); // skip: + } + return RECOMPILE_SUCCESSFUL_CP(36,4); + + case 0x1c: /* DMULT */ + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] + emit_cmp_r32_imm(DRCTOP, REG_EDX, 0); // cmp edx,0 + emit_jcc_short_link(DRCTOP, COND_GE, &link1); // jge skip1 + emit_mov_r32_r32(DRCTOP, REG_ECX, REG_EDX); // mov ecx,edx + emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx + emit_neg_r32(DRCTOP, REG_EAX); // neg eax + emit_sbb_r32_r32(DRCTOP, REG_EDX, REG_ECX); // sbb edx,ecx + resolve_link(DRCTOP, &link1); // skip1: + emit_mov_m64_r64(DRCTOP, MABS(&dmult_temp1), REG_EDX, REG_EAX); // mov [dmult_temp1],edx:eax + + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg] + emit_cmp_r32_imm(DRCTOP, REG_EDX, 0); // cmp edx,0 + emit_jcc_short_link(DRCTOP, COND_GE, &link2); // jge skip2 + emit_mov_r32_r32(DRCTOP, REG_ECX, REG_EDX); // mov ecx,edx + emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx + emit_neg_r32(DRCTOP, REG_EAX); // neg eax + emit_sbb_r32_r32(DRCTOP, REG_EDX, REG_ECX); // sbb edx,ecx + resolve_link(DRCTOP, &link2); // skip2: + emit_mov_m64_r64(DRCTOP, MABS(&dmult_temp2), REG_EDX, REG_EAX); // mov [dmult_temp2],edx:eax + + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(LO(&dmult_temp1))); // mov eax,[dmult_temp1].lo + emit_mul_m32(DRCTOP, MABS(LO(&dmult_temp2))); // mul [dmult_temp2].lo + emit_mov_r32_r32(DRCTOP, REG_ECX, REG_EDX); // mov ecx,edx + emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX); // xor ebx,ebx + emit_mov_m32_r32(DRCTOP, LOADDRLO, REG_EAX); // mov [lo].lo,eax + + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(HI(&dmult_temp1))); // mov eax,[dmult_temp1].hi + emit_mul_m32(DRCTOP, MABS(LO(&dmult_temp2))); // mul [dmult_temp2].lo + emit_add_r32_r32(DRCTOP, REG_ECX, REG_EAX); // add ecx,eax + emit_adc_r32_r32(DRCTOP, REG_EBX, REG_EDX); // adc ebx,edx + + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(LO(&dmult_temp1))); // mov eax,[dmult_temp1].lo + emit_mul_m32(DRCTOP, MABS(HI(&dmult_temp2))); // mul [dmult_temp2].hi + emit_add_r32_r32(DRCTOP, REG_ECX, REG_EAX); // add ecx,eax + emit_adc_r32_r32(DRCTOP, REG_EBX, REG_EDX); // adc ebx,edx + emit_mov_m32_r32(DRCTOP, LOADDRHI, REG_ECX); // mov [lo].hi,ecx + + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(HI(&dmult_temp1))); // mov eax,[dmult_temp1].hi + emit_mul_m32(DRCTOP, MABS(HI(&dmult_temp2))); // mul [dmult_temp2].hi + emit_add_r32_r32(DRCTOP, REG_EBX, REG_EAX); // add ebx,eax + emit_adc_r32_imm(DRCTOP, REG_EDX, 0); // adc edx,0 + emit_mov_m32_r32(DRCTOP, HIADDRLO, REG_EBX); // mov [hi].lo,ebx + emit_mov_m32_r32(DRCTOP, HIADDRHI, REG_EDX); // mov [hi].hi,edx + + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi + emit_xor_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // xor eax,[rtreg].hi + emit_jcc_short_link(DRCTOP, COND_NS, &link3); // jns noflip + emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax + emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX); // xor ebx,ebx + emit_xor_r32_r32(DRCTOP, REG_ECX, REG_ECX); // xor ecx,ecx + emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx + emit_sub_r32_m32(DRCTOP, REG_EAX, LOADDRLO); // sub eax,[lo].lo + emit_sbb_r32_m32(DRCTOP, REG_EBX, LOADDRHI); // sbb ebx,[lo].hi + emit_sbb_r32_m32(DRCTOP, REG_ECX, HIADDRLO); // sbb ecx,[hi].lo + emit_sbb_r32_m32(DRCTOP, REG_EDX, HIADDRHI); // sbb edx,[hi].hi + emit_mov_m64_r64(DRCTOP, LOADDR, REG_EBX, REG_EAX); // mov [lo],ebx:eax + emit_mov_m64_r64(DRCTOP, HIADDR, REG_EDX, REG_ECX); // mov [hi],edx:ecx + resolve_link(DRCTOP, &link3); // noflip: + return RECOMPILE_SUCCESSFUL_CP(8,4); + + case 0x1d: /* DMULTU */ + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_mul_m32(DRCTOP, REGADDRLO(RTREG)); // mul [rtreg].lo + emit_mov_r32_r32(DRCTOP, REG_ECX, REG_EDX); // mov ecx,edx + emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX); // xor ebx,ebx + emit_mov_m32_r32(DRCTOP, LOADDRLO, REG_EAX); // mov [lo].lo,eax + + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi + emit_mul_m32(DRCTOP, REGADDRLO(RTREG)); // mul [rtreg].lo + emit_add_r32_r32(DRCTOP, REG_ECX, REG_EAX); // add ecx,eax + emit_adc_r32_r32(DRCTOP, REG_EBX, REG_EDX); // adc ebx,edx + + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_mul_m32(DRCTOP, REGADDRHI(RTREG)); // mul [rtreg].hi + emit_add_r32_r32(DRCTOP, REG_ECX, REG_EAX); // add ecx,eax + emit_adc_r32_r32(DRCTOP, REG_EBX, REG_EDX); // adc ebx,edx + emit_mov_m32_r32(DRCTOP, LOADDRHI, REG_ECX); // mov [lo].hi,ecx + + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi + emit_mul_m32(DRCTOP, REGADDRHI(RTREG)); // mul [rtreg].hi + emit_add_r32_r32(DRCTOP, REG_EBX, REG_EAX); // add ebx,eax + emit_adc_r32_imm(DRCTOP, REG_EDX, 0); // adc edx,0 + emit_mov_m32_r32(DRCTOP, HIADDRLO, REG_EBX); // mov [hi].lo,ebx + emit_mov_m32_r32(DRCTOP, HIADDRHI, REG_EDX); // mov [hi].hi,edx + return RECOMPILE_SUCCESSFUL_CP(8,4); + + case 0x1e: /* DDIV */ + emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4 + emit_push_imm(DRCTOP, (FPTR)&mips3.core->r[RTREG]); // push [rtreg] + emit_push_imm(DRCTOP, (FPTR)&mips3.core->r[RSREG]); // push [rsreg] + emit_call(DRCTOP, (x86code *)ddiv); // call ddiv + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + return RECOMPILE_SUCCESSFUL_CP(68,4); + + case 0x1f: /* DDIVU */ + emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4 + emit_push_imm(DRCTOP, (FPTR)&mips3.core->r[RTREG]); // push [rtreg] + emit_push_imm(DRCTOP, (FPTR)&mips3.core->r[RSREG]); // push [rsreg] + emit_call(DRCTOP, (x86code *)ddivu); // call ddivu + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + return RECOMPILE_SUCCESSFUL_CP(68,4); + } + + emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception + return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; +} + +static UINT32 recompile_special2(drc_core *drc, UINT32 pc, UINT32 op) +{ + emit_link link1, link2, link3; + + switch (op & 63) + { + case 0x20: /* ADD */ + if (RSREG != 0 && RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg].lo + emit_jcc(DRCTOP, COND_O, mips3.drcdata->generate_overflow_exception); // jo generate_overflow_exception + if (RDREG != 0) + { + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + } + else if (RDREG != 0) + { + if (RSREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else if (RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else + emit_zero_m64(DRCTOP, REGADDR(RDREG)); + } + return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; + + case 0x21: /* ADDU */ + if (RDREG != 0) + { + if (RSREG != 0 && RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg].lo + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else if (RSREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else if (RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else + emit_zero_m64(DRCTOP, REGADDR(RDREG)); + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x22: /* SUB */ + if (RSREG != 0 && RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo + emit_jcc(DRCTOP, COND_O, mips3.drcdata->generate_overflow_exception); // jo generate_overflow_exception + if (RDREG != 0) + { + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + } + else if (RDREG != 0) + { + if (RSREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else if (RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo + emit_neg_r32(DRCTOP, REG_EAX); // neg eax + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else + emit_zero_m64(DRCTOP, REGADDR(RDREG)); + } + return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; + + case 0x23: /* SUBU */ + if (RDREG != 0) + { + if (RSREG != 0 && RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else if (RSREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else if (RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo + emit_neg_r32(DRCTOP, REG_EAX); // neg eax + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else + emit_zero_m64(DRCTOP, REGADDR(RDREG)); + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x24: /* AND */ + if (RDREG != 0) + { + if (RSREG != 0 && RTREG != 0) + { + if (USE_SSE) + { + emit_movsd_r128_m64(DRCTOP, REG_XMM0, REGADDR(RSREG)); // movsd xmm0,[rsreg] + emit_movsd_r128_m64(DRCTOP, REG_XMM1, REGADDR(RTREG)); // movsd xmm1,[rtreg] + emit_andpd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1); // andpd xmm0,xmm1 + emit_movsd_m64_r128(DRCTOP, REGADDR(RDREG), REG_XMM0); // mov [rdreg],xmm0 + } + else + { + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); + // mov edx:eax,[rsreg] + emit_and_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // and eax,[rtreg].lo + emit_and_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // and edx,[rtreg].hi + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + } + else + emit_zero_m64(DRCTOP, REGADDR(RDREG)); + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x25: /* OR */ + if (RDREG != 0) + { + if (RSREG != 0 && RTREG != 0) + { + if (USE_SSE) + { + emit_movsd_r128_m64(DRCTOP, REG_XMM0, REGADDR(RSREG)); // movsd xmm0,[rsreg] + emit_movsd_r128_m64(DRCTOP, REG_XMM1, REGADDR(RTREG)); // movsd xmm1,[rtreg] + emit_orpd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1); // orpd xmm0,xmm1 + emit_movsd_m64_r128(DRCTOP, REGADDR(RDREG), REG_XMM0); // mov [rdreg],xmm0 + } + else + { + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); + // mov edx:eax,[rsreg] + emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // or eax,[rtreg].lo + emit_or_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // or edx,[rtreg].hi + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + } + else if (RSREG != 0) + emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG)); // mov [rdreg],[rsreg] + else if (RTREG != 0) + emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RTREG)); // mov [rdreg],[rtreg] + else + emit_zero_m64(DRCTOP, REGADDR(RDREG)); + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x26: /* XOR */ + if (RDREG != 0) + { + if (RSREG != 0 && RTREG != 0) + { + if (USE_SSE) + { + emit_movsd_r128_m64(DRCTOP, REG_XMM0, REGADDR(RSREG)); // movsd xmm0,[rsreg] + emit_movsd_r128_m64(DRCTOP, REG_XMM1, REGADDR(RTREG)); // movsd xmm1,[rtreg] + emit_xorpd_r128_r128(DRCTOP, REG_XMM0, REG_XMM1); // xorpd xmm0,xmm1 + emit_movsd_m64_r128(DRCTOP, REGADDR(RDREG), REG_XMM0); // mov [rdreg],xmm0 + } + else + { + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); + // mov edx:eax,[rsreg] + emit_xor_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // xor eax,[rtreg].lo + emit_xor_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // xor edx,[rtreg].hi + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + } + else if (RSREG != 0) + emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG)); // mov [rdreg],[rsreg] + else if (RTREG != 0) + emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RTREG)); // mov [rdreg],[rtreg] + else + emit_zero_m64(DRCTOP, REGADDR(RDREG)); + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x27: /* NOR */ + if (RDREG != 0) + { + if (RSREG != 0 && RTREG != 0) + { + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] + emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // or eax,[rtreg].lo + emit_or_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // or edx,[rtreg].hi + emit_not_r32(DRCTOP, REG_EDX); // not edx + emit_not_r32(DRCTOP, REG_EAX); // not eax + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else if (RSREG != 0) + { + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] + emit_not_r32(DRCTOP, REG_EDX); // not edx + emit_not_r32(DRCTOP, REG_EAX); // not eax + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else if (RTREG != 0) + { + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg] + emit_not_r32(DRCTOP, REG_EDX); // not edx + emit_not_r32(DRCTOP, REG_EAX); // not eax + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else + { + emit_mov_m32_imm(DRCTOP, REGADDRLO(RDREG), ~0); // mov [rtreg].lo,~0 + emit_mov_m32_imm(DRCTOP, REGADDRHI(RDREG), ~0); // mov [rtreg].hi,~0 + } + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x2a: /* SLT */ + if (RDREG != 0) + { + if (RSREG != 0) + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] + else + { + emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx + emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax + } + if (RTREG != 0) + { + emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo + emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].lo + } + emit_shr_r32_imm(DRCTOP, REG_EDX, 31); // shr edx,31 + emit_mov_m32_r32(DRCTOP, REGADDRLO(RDREG), REG_EDX); // mov [rdreg].lo,edx + emit_mov_m32_imm(DRCTOP, REGADDRHI(RDREG), 0); // mov [rdreg].hi,0 + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x2b: /* SLTU */ + if (RDREG != 0) + { + emit_xor_r32_r32(DRCTOP, REG_ECX, REG_ECX); // xor ecx,ecx + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi + emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi + emit_jcc_short_link(DRCTOP, COND_B, &link1); // jb setit + emit_jcc_short_link(DRCTOP, COND_A, &link2); // ja skipit + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo + emit_jcc_short_link(DRCTOP, COND_AE, &link3); // jae skipit + resolve_link(DRCTOP, &link1); // setit: + emit_add_r32_imm(DRCTOP, REG_ECX, 1); // add ecx,1 + resolve_link(DRCTOP, &link2); // skipit: + resolve_link(DRCTOP, &link3); // skipit: + emit_mov_m32_r32(DRCTOP, REGADDRLO(RDREG), REG_ECX); // mov [rdreg].lo,ecx + emit_mov_m32_imm(DRCTOP, REGADDRHI(RDREG), 0); // mov [rdreg].hi,0 + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x2c: /* DADD */ + if (RSREG != 0 && RTREG != 0) + { + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] + emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg].lo + emit_adc_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // adc edx,[rtreg].hi + emit_jcc(DRCTOP, COND_O, mips3.drcdata->generate_overflow_exception); // jo generate_overflow_exception + if (RDREG != 0) + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else if (RDREG != 0) + { + if (RSREG != 0) + emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG)); // mov [rdreg],[rsreg] + else if (RTREG != 0) + emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RTREG)); // mov [rdreg],[rtreg] + else + emit_zero_m64(DRCTOP, REGADDR(RDREG)); + } + return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; + + case 0x2d: /* DADDU */ + if (RDREG != 0) + { + if (RSREG != 0 && RTREG != 0) + { + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] + emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg].lo + emit_adc_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // adc edx,[rtreg].hi + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else if (RSREG != 0) + emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG)); + // mov [rdreg],[rsreg] + else if (RTREG != 0) + emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RTREG)); + // mov [rdreg],[rtreg] + else + emit_zero_m64(DRCTOP, REGADDR(RDREG)); + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x2e: /* DSUB */ + if (RSREG != 0 && RTREG != 0) + { + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] + emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo + emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].hi + emit_jcc(DRCTOP, COND_O, mips3.drcdata->generate_overflow_exception); // jo generate_overflow_exception + if (RDREG != 0) + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else if (RDREG != 0) + { + if (RSREG != 0) + emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG)); // mov [rdreg],[rsreg] + else if (RTREG != 0) + { + emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax + emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx + emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo + emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].hi + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else + emit_zero_m64(DRCTOP, REGADDR(RDREG)); + } + return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; + + case 0x2f: /* DSUBU */ + if (RDREG != 0) + { + if (RSREG != 0 && RTREG != 0) + { + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] + emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo + emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].hi + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else if (RSREG != 0) + emit_mov_m64_m64(DRCTOP, REGADDR(RDREG), REGADDR(RSREG)); // mov [rdreg],[rsreg] + else if (RTREG != 0) + { + emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax + emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx + emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo + emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].hi + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else + emit_zero_m64(DRCTOP, REGADDR(RDREG)); + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x30: /* TGE */ + if (RSREG != 0) + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] + else + { + emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx + emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax + } + if (RTREG != 0) + { + emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo + emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].hi + } + else + emit_cmp_r32_imm(DRCTOP, REG_EDX, 0); // cmp edx,0 + emit_jcc(DRCTOP, COND_GE, mips3.drcdata->generate_trap_exception); // jge generate_trap_exception + return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; + + case 0x31: /* TGEU */ + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi + emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi + emit_jcc(DRCTOP, COND_A, mips3.drcdata->generate_trap_exception); // ja generate_trap_exception + emit_jcc_short_link(DRCTOP, COND_B, &link1); // jb skipit + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo + emit_jcc(DRCTOP, COND_AE, mips3.drcdata->generate_trap_exception); // jae generate_trap_exception + resolve_link(DRCTOP, &link1); // skipit: + return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; + + case 0x32: /* TLT */ + if (RSREG != 0) + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] + else + { + emit_xor_r32_r32(DRCTOP, REG_EDX, REG_EDX); // xor edx,edx + emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax + } + if (RTREG != 0) + { + emit_sub_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // sub eax,[rtreg].lo + emit_sbb_r32_m32(DRCTOP, REG_EDX, REGADDRHI(RTREG)); // sbb edx,[rtreg].hi + } + else + emit_cmp_r32_imm(DRCTOP, REG_EDX, 0); // cmp edx,0 + emit_jcc(DRCTOP, COND_L, mips3.drcdata->generate_trap_exception); // jl generate_trap_exception + return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; + + case 0x33: /* TLTU */ + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi + emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi + emit_jcc(DRCTOP, COND_B, mips3.drcdata->generate_trap_exception); // jb generate_trap_exception + emit_jcc_short_link(DRCTOP, COND_A, &link1); // ja skipit + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo + emit_jcc(DRCTOP, COND_B, mips3.drcdata->generate_trap_exception); // jb generate_trap_exception + resolve_link(DRCTOP, &link1); // skipit: + return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; + + case 0x34: /* TEQ */ + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi + emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi + emit_jcc_short_link(DRCTOP, COND_NE, &link1); // jne skipit + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo + emit_jcc(DRCTOP, COND_E, mips3.drcdata->generate_trap_exception); // je generate_trap_exception + resolve_link(DRCTOP, &link1); // skipit: + return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; + + case 0x36: /* TNE */ + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RSREG)); // mov eax,[rsreg].hi + emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // cmp eax,[rtreg].hi + emit_jcc_short_link(DRCTOP, COND_E, &link1); // je skipit + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg].lo + emit_cmp_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // cmp eax,[rtreg].lo + emit_jcc(DRCTOP, COND_NE, mips3.drcdata->generate_trap_exception); // jne generate_trap_exception + resolve_link(DRCTOP, &link1); // skipit: + return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; + + case 0x38: /* DSLL */ + if (RDREG != 0) + { + if (RTREG != 0) + { + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg] + if (SHIFT != 0) + { + emit_shld_r32_r32_imm(DRCTOP, REG_EDX, REG_EAX, SHIFT); // shld edx,eax,SHIFT + emit_shl_r32_imm(DRCTOP, REG_EAX, SHIFT); // shl eax,SHIFT + } + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else + emit_zero_m64(DRCTOP, REGADDR(RDREG)); + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x3a: /* DSRL */ + if (RDREG != 0) + { + if (RTREG != 0) + { + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg] + if (SHIFT != 0) + { + emit_shrd_r32_r32_imm(DRCTOP, REG_EAX, REG_EDX, SHIFT); // shrd eax,edx,SHIFT + emit_shr_r32_imm(DRCTOP, REG_EDX, SHIFT); // shr edx,SHIFT + } + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else + emit_zero_m64(DRCTOP, REGADDR(RDREG)); + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x3b: /* DSRA */ + if (RDREG != 0) + { + if (RTREG != 0) + { + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RTREG)); // mov edx:eax,[rtreg] + if (SHIFT != 0) + { + emit_shrd_r32_r32_imm(DRCTOP, REG_EAX, REG_EDX, SHIFT); // shrd eax,edx,SHIFT + emit_sar_r32_imm(DRCTOP, REG_EDX, SHIFT); // sar edx,SHIFT + } + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else + emit_zero_m64(DRCTOP, REGADDR(RDREG)); + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x3c: /* DSLL32 */ + if (RDREG != 0) + { + if (RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo + if (SHIFT != 0) + emit_shl_r32_imm(DRCTOP, REG_EAX, SHIFT); // shl eax,SHIFT + emit_mov_m32_imm(DRCTOP, REGADDRLO(RDREG), 0); // mov [rdreg].lo,0 + emit_mov_m32_r32(DRCTOP, REGADDRHI(RDREG), REG_EAX); // mov [rdreg].hi,eax + } + else + emit_zero_m64(DRCTOP, REGADDR(RDREG)); + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x3e: /* DSRL32 */ + if (RDREG != 0) + { + if (RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // mov eax,[rtreg].hi + if (SHIFT != 0) + emit_shr_r32_imm(DRCTOP, REG_EAX, SHIFT); // shr eax,SHIFT + emit_mov_m32_imm(DRCTOP, REGADDRHI(RDREG), 0); // mov [rdreg].hi,0 + emit_mov_m32_r32(DRCTOP, REGADDRLO(RDREG), REG_EAX); // mov [rdreg].lo,eax + } + else + emit_zero_m64(DRCTOP, REGADDR(RDREG)); + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x3f: /* DSRA32 */ + if (RDREG != 0) + { + if (RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // mov eax,[rtreg].hi + emit_cdq(DRCTOP); // cdq + if (SHIFT != 0) + emit_sar_r32_imm(DRCTOP, REG_EAX, SHIFT); // sar eax,SHIFT + emit_mov_m64_r64(DRCTOP, REGADDR(RDREG), REG_EDX, REG_EAX); // mov [rdreg],edx:eax + } + else + emit_zero_m64(DRCTOP, REGADDR(RDREG)); + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + } + + emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception + return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; +} + + +static UINT32 recompile_special(drc_core *drc, UINT32 pc, UINT32 op) +{ + if (!(op & 32)) + return recompile_special1(drc, pc, op); + else + return recompile_special2(drc, pc, op); +} + + +/*------------------------------------------------------------------ + recompile_regimm +------------------------------------------------------------------*/ + +static UINT32 recompile_regimm(drc_core *drc, UINT32 pc, UINT32 op) +{ + emit_link link1; + int cycles; + + switch (RTREG) + { + case 0x00: /* BLTZ */ + if (RSREG == 0) + return RECOMPILE_SUCCESSFUL_CP(1,4); + else + { + emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0 + emit_jcc_near_link(DRCTOP, COND_GE, &link1); // jge skip + } + + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + resolve_link(DRCTOP, &link1); // skip: + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x01: /* BGEZ */ + if (RSREG == 0) + { + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING; + } + else + { + emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0 + emit_jcc_near_link(DRCTOP, COND_L, &link1); // jl skip + } + + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + resolve_link(DRCTOP, &link1); // skip: + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x02: /* BLTZL */ + if (RSREG == 0) + return RECOMPILE_SUCCESSFUL_CP(1,4); + else + { + emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0 + emit_jcc_near_link(DRCTOP, COND_GE, &link1); // jge skip + } + + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + resolve_link(DRCTOP, &link1); // skip: + return RECOMPILE_SUCCESSFUL_CP(1,8); + + case 0x03: /* BGEZL */ + if (RSREG == 0) + { + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING; + } + else + { + emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0 + emit_jcc_near_link(DRCTOP, COND_L, &link1); // jl skip + } + + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + resolve_link(DRCTOP, &link1); // skip: + return RECOMPILE_SUCCESSFUL_CP(1,8); + + case 0x08: /* TGEI */ + if (RSREG != 0) + { + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] + emit_sub_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // sub eax,[rtreg].lo + emit_sbb_r32_imm(DRCTOP, REG_EDX, ((INT32)SIMMVAL >> 31)); // sbb edx,[rtreg].lo + emit_jcc(DRCTOP, COND_GE, mips3.drcdata->generate_trap_exception); // jge generate_trap_exception + } + else + { + if (0 >= SIMMVAL) + emit_jmp(DRCTOP, mips3.drcdata->generate_trap_exception); // jmp generate_trap_exception + } + return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; + + case 0x09: /* TGEIU */ + if (RSREG != 0) + { + emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), ((INT32)SIMMVAL >> 31)); + // cmp [rsreg].hi,upper + emit_jcc(DRCTOP, COND_A, mips3.drcdata->generate_trap_exception); // ja generate_trap_exception + emit_jcc_short_link(DRCTOP, COND_B, &link1); // jb skip + emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), SIMMVAL); // cmp [rsreg].lo,lower + emit_jcc(DRCTOP, COND_AE, mips3.drcdata->generate_trap_exception); // jae generate_trap_exception + resolve_link(DRCTOP, &link1); // skip: + } + else + { + if (0 >= SIMMVAL) + emit_jmp(DRCTOP, mips3.drcdata->generate_trap_exception); // jmp generate_trap_exception + } + return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; + + case 0x0a: /* TLTI */ + if (RSREG != 0) + { + emit_mov_r64_m64(DRCTOP, REG_EDX, REG_EAX, REGADDR(RSREG)); // mov edx:eax,[rsreg] + emit_sub_r32_imm(DRCTOP, REG_EAX, SIMMVAL); // sub eax,[rtreg].lo + emit_sbb_r32_imm(DRCTOP, REG_EDX, ((INT32)SIMMVAL >> 31)); // sbb edx,[rtreg].lo + emit_jcc(DRCTOP, COND_L, mips3.drcdata->generate_trap_exception); // jl generate_trap_exception + } + else + { + if (0 < SIMMVAL) + emit_jmp(DRCTOP, mips3.drcdata->generate_trap_exception); // jmp generate_trap_exception + } + return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; + + case 0x0b: /* TLTIU */ + if (RSREG != 0) + { + emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), ((INT32)SIMMVAL >> 31)); + // cmp [rsreg].hi,upper + emit_jcc(DRCTOP, COND_B, mips3.drcdata->generate_trap_exception); // jb generate_trap_exception + emit_jcc_short_link(DRCTOP, COND_A, &link1); // ja skip + emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), SIMMVAL); // cmp [rsreg].lo,lower + emit_jcc(DRCTOP, COND_B, mips3.drcdata->generate_trap_exception); // jb generate_trap_exception + resolve_link(DRCTOP, &link1); // skip: + } + else + { + emit_mov_m32_imm(DRCTOP, REGADDRLO(RTREG), (0 < SIMMVAL)); // mov [rtreg].lo,const + emit_mov_m32_imm(DRCTOP, REGADDRHI(RTREG), 0); // mov [rtreg].hi,sign-extend(const) + } + return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; + + case 0x0c: /* TEQI */ + if (RSREG != 0) + { + emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), ((INT32)SIMMVAL >> 31)); + // cmp [rsreg].hi,upper + emit_jcc_short_link(DRCTOP, COND_NE, &link1); // jne skip + emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), SIMMVAL); // cmp [rsreg].lo,lower + emit_jcc(DRCTOP, COND_E, mips3.drcdata->generate_trap_exception); // je generate_trap_exception + resolve_link(DRCTOP, &link1); // skip: + } + else + { + if (0 == SIMMVAL) + emit_jmp(DRCTOP, mips3.drcdata->generate_trap_exception); // jmp generate_trap_exception + } + return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; + + case 0x0e: /* TNEI */ + if (RSREG != 0) + { + emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), ((INT32)SIMMVAL >> 31)); + // cmp [rsreg].hi,upper + emit_jcc_short_link(DRCTOP, COND_E, &link1); // je skip + emit_cmp_m32_imm(DRCTOP, REGADDRLO(RSREG), SIMMVAL); // cmp [rsreg].lo,lower + emit_jcc(DRCTOP, COND_NE, mips3.drcdata->generate_trap_exception); // jne generate_trap_exception + resolve_link(DRCTOP, &link1); // skip: + } + else + { + if (0 != SIMMVAL) + emit_jmp(DRCTOP, mips3.drcdata->generate_trap_exception); // jmp generate_trap_exception + } + return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_MAY_CAUSE_EXCEPTION; + + case 0x10: /* BLTZAL */ + if (RSREG == 0) + return RECOMPILE_SUCCESSFUL_CP(1,4); + else + { + emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0 + emit_jcc_near_link(DRCTOP, COND_GE, &link1); // jge skip + } + emit_mov_m64_imm32(DRCTOP, MABS(&mips3.core->r[31]), pc + 8); // mov [31],pc + 8 + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + resolve_link(DRCTOP, &link1); // skip: + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x11: /* BGEZAL */ + if (RSREG == 0) + { + emit_mov_m64_imm32(DRCTOP, MABS(&mips3.core->r[31]), pc + 8); // mov [31],pc + 8 + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING; + } + else + { + emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0 + emit_jcc_near_link(DRCTOP, COND_L, &link1); // jl skip + } + + emit_mov_m64_imm32(DRCTOP, MABS(&mips3.core->r[31]), pc + 8); // mov [31],pc + 8 + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + resolve_link(DRCTOP, &link1); // skip: + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x12: /* BLTZALL */ + if (RSREG == 0) + return RECOMPILE_SUCCESSFUL_CP(1,4); + else + { + emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0 + emit_jcc_near_link(DRCTOP, COND_GE, &link1); // jge skip + } + + emit_mov_m64_imm32(DRCTOP, MABS(&mips3.core->r[31]), pc + 8); // mov [31],pc + 8 + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + resolve_link(DRCTOP, &link1); // skip: + return RECOMPILE_SUCCESSFUL_CP(1,8); + + case 0x13: /* BGEZALL */ + if (RSREG == 0) + { + emit_mov_m64_imm32(DRCTOP, MABS(&mips3.core->r[31]), pc + 8); // mov [31],pc + 8 + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + return RECOMPILE_SUCCESSFUL_CP(0,0) | RECOMPILE_END_OF_STRING; + } + else + { + emit_cmp_m32_imm(DRCTOP, REGADDRHI(RSREG), 0); // cmp [rsreg].hi,0 + emit_jcc_near_link(DRCTOP, COND_L, &link1); // jl skip + } + + emit_mov_m64_imm32(DRCTOP, MABS(&mips3.core->r[31]), pc + 8); // mov [31],pc + 8 + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + resolve_link(DRCTOP, &link1); // skip: + return RECOMPILE_SUCCESSFUL_CP(1,8); + } + + emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception + return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; +} + + + +/*************************************************************************** + COP0 RECOMPILATION +***************************************************************************/ + +/*------------------------------------------------------------------ + recompile_set_cop0_reg +------------------------------------------------------------------*/ + +static UINT32 recompile_set_cop0_reg(drc_core *drc, UINT8 reg) +{ + emit_link link1; + + switch (reg) + { + case COP0_Cause: + emit_mov_r32_m32(DRCTOP, REG_EBX, CPR0ADDR(COP0_Cause)); // mov ebx,[COP0_Cause] + emit_and_r32_imm(DRCTOP, REG_EAX, ~0xfc00); // and eax,~0xfc00 + emit_and_r32_imm(DRCTOP, REG_EBX, 0xfc00); // and ebx,0xfc00 + emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx + emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Cause), REG_EAX); // mov [COP0_Cause],eax + emit_and_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(COP0_Status)); // and eax,[COP0_Status] + return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_CHECK_SW_INTERRUPTS; + + case COP0_Status: + emit_mov_r32_m32(DRCTOP, REG_EBX, CPR0ADDR(COP0_Status)); // mov ebx,[COP0_Status] + emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Status), REG_EAX); // mov [COP0_Status],eax + emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EAX); // xor ebx,eax +/* +#ifdef MAME_DEBUG + _test_r32_imm(REG_EAX, 0xe0); // test eax,0xe0 + _jcc_short_link(COND_Z, &link1); // jz skip + _sub_r32_imm(REG_ESP, 4); // sub esp,4 + _push_r32(REG_EAX); // push eax + _push_imm("System set 64-bit addressing mode, SR=%08X"); // push <string> + _call(mame_printf_debug); // call mame_printf_debug + _call(mame_debug_break); // call mame_debug_break + _add_r32_imm(REG_ESP, 12); // add esp,12 + _resolve_link(&link1); // skip: +#endif +*/ + emit_test_r32_imm(DRCTOP, REG_EBX, 0x8000); // test ebx,0x8000 + emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip + append_update_cycle_counting(drc); // update cycle counting + resolve_link(DRCTOP, &link1); // skip: + return RECOMPILE_SUCCESSFUL_CP(1,4) | RECOMPILE_CHECK_INTERRUPTS | RECOMPILE_END_OF_STRING | RECOMPILE_ADD_DISPATCH; + + case COP0_Count: + emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Count), REG_EAX); // mov [COP0_Count],eax + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 + emit_push_r32(DRCTOP, REG_EAX); // push eax + emit_call(DRCTOP, (x86code *)activecpu_gettotalcycles64); // call activecpu_gettotalcycles64 + emit_pop_r32(DRCTOP, REG_EBX); // pop ebx + emit_add_r32_imm(DRCTOP, REG_ESP, 8); // add esp,8 + emit_sub_r32_r32(DRCTOP, REG_EAX, REG_EBX); // sub eax,ebx + emit_sbb_r32_imm(DRCTOP, REG_EDX, 0); // sbb edx,0 + emit_sub_r32_r32(DRCTOP, REG_EAX, REG_EBX); // sub eax,ebx + emit_sbb_r32_imm(DRCTOP, REG_EDX, 0); // sbb edx,0 + emit_mov_m64_r64(DRCTOP, MABS(&mips3.core->count_zero_time), REG_EDX, REG_EAX); // mov [mips3.core->count_zero_time],edx:eax + append_update_cycle_counting(drc); // update cycle counting + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case COP0_Compare: + emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Compare), REG_EAX); // mov [COP0_Compare],eax + emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_Cause), ~0x8000); // and [COP0_Cause],~0x8000 + append_update_cycle_counting(drc); // update cycle counting + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case COP0_PRId: + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case COP0_Config: + emit_mov_r32_m32(DRCTOP, REG_EBX, CPR0ADDR(COP0_Config)); // mov ebx,[COP0_Cause] + emit_and_r32_imm(DRCTOP, REG_EAX, 0x0007); // and eax,0x0007 + emit_and_r32_imm(DRCTOP, REG_EBX, ~0x0007); // and ebx,~0x0007 + emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx + emit_mov_m32_r32(DRCTOP, CPR0ADDR(COP0_Config), REG_EAX); // mov [COP0_Cause],eax + return RECOMPILE_SUCCESSFUL_CP(1,4); + + default: + emit_mov_m32_r32(DRCTOP, CPR0ADDR(reg), REG_EAX); // mov [reg],eax + return RECOMPILE_SUCCESSFUL_CP(1,4); + } + return RECOMPILE_UNIMPLEMENTED; +} + + +/*------------------------------------------------------------------ + recompile_get_cop0_reg +------------------------------------------------------------------*/ + +static UINT32 recompile_get_cop0_reg(drc_core *drc, UINT8 reg) +{ + emit_link link1; + + switch (reg) + { + case COP0_Count: + emit_sub_r32_imm(DRCTOP, REG_EBP, 250); // sub ebp,24 + emit_jcc_short_link(DRCTOP, COND_NS, &link1); // jns notneg + emit_xor_r32_r32(DRCTOP, REG_EBP, REG_EBP); // xor ebp,ebp + resolve_link(DRCTOP, &link1); // notneg: + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_sub_r32_imm(DRCTOP, REG_ESP, 12); // sub esp,12 + emit_call(DRCTOP, (x86code *)activecpu_gettotalcycles64); // call activecpu_gettotalcycles64 + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + emit_sub_r32_m32(DRCTOP, REG_EAX, MABS(LO(&mips3.core->count_zero_time))); // sub eax,[mips3.core->count_zero_time+0] + emit_sbb_r32_m32(DRCTOP, REG_EDX, MABS(HI(&mips3.core->count_zero_time))); // sbb edx,[mips3.core->count_zero_time+4] + emit_shrd_r32_r32_imm(DRCTOP, REG_EAX, REG_EDX, 1); // shrd eax,edx,1 + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case COP0_Cause: + emit_sub_r32_imm(DRCTOP, REG_EBP, 250); // sub ebp,24 + emit_jcc_short_link(DRCTOP, COND_NS, &link1); // jns notneg + emit_xor_r32_r32(DRCTOP, REG_EBP, REG_EBP); // xor ebp,ebp + resolve_link(DRCTOP, &link1); // notneg: + emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(reg)); // mov eax,[reg] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + default: + emit_mov_r32_m32(DRCTOP, REG_EAX, CPR0ADDR(reg)); // mov eax,[reg] + return RECOMPILE_SUCCESSFUL_CP(1,4); + } + return RECOMPILE_UNIMPLEMENTED; +} + + +/*------------------------------------------------------------------ + recompile_cop0 +------------------------------------------------------------------*/ + +static UINT32 recompile_cop0(drc_core *drc, UINT32 pc, UINT32 op) +{ + emit_link checklink; + UINT32 result; + + if (mips3.drcoptions & MIPS3DRC_STRICT_COP0) + { + emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_KSU_MASK); // test [COP0_Status],SR_KSU_MASK + emit_jcc_short_link(DRCTOP, COND_Z, &checklink); // jz okay + emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_COP0); // test [COP0_Status],SR_COP0 + emit_jcc(DRCTOP, COND_Z, mips3.drcdata->generate_cop_exception); // jz generate_cop_exception + resolve_link(DRCTOP, &checklink); // okay: + } + + switch (RSREG) + { + case 0x00: /* MFCz */ + result = RECOMPILE_SUCCESSFUL_CP(1,4); + if (RTREG != 0) + { + result = recompile_get_cop0_reg(drc, RDREG); // read cop0 reg + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax + } + return result; + + case 0x01: /* DMFCz */ + result = RECOMPILE_SUCCESSFUL_CP(1,4); + if (RTREG != 0) + { + result = recompile_get_cop0_reg(drc, RDREG); // read cop0 reg + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax + } + return result; + + case 0x02: /* CFCz */ + if (RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, CCR0ADDR(RDREG)); // mov eax,[mips3.core->ccr[0][rdreg]] + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [rtreg],edx:eax + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x04: /* MTCz */ + if (RTREG != 0) + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[mips3.core->r[RTREG]] + else + emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax + result = recompile_set_cop0_reg(drc, RDREG); // write cop0 reg + return result; + + case 0x05: /* DMTCz */ + if (RTREG != 0) + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[mips3.core->r[RTREG]] + else + emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax + result = recompile_set_cop0_reg(drc, RDREG); // write cop0 reg + return result; + + case 0x06: /* CTCz */ + if (RTREG != 0) + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[mips3.core->r[RTREG]] + else + emit_xor_r32_r32(DRCTOP, REG_EAX, REG_EAX); // xor eax,eax + emit_mov_m32_r32(DRCTOP, CCR0ADDR(RDREG), REG_EAX); // mov [mips3.core->ccr[0][RDREG]],eax + return RECOMPILE_SUCCESSFUL_CP(1,4); + +// case 0x08: /* BC */ +// switch (RTREG) +// { +// case 0x00: /* BCzF */ if (!mips3.core->cf[0][0]) ADDPC(SIMMVAL); break; +// case 0x01: /* BCzF */ if (mips3.core->cf[0][0]) ADDPC(SIMMVAL); break; +// case 0x02: /* BCzFL */ invalid_instruction(op); break; +// case 0x03: /* BCzTL */ invalid_instruction(op); break; +// default: invalid_instruction(op); break; +// } +// break; + + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: /* COP */ + switch (op & 0x01ffffff) + { + case 0x01: /* TLBR */ + emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 + emit_push_imm(DRCTOP, (FPTR)mips3.core); // push mips3.core + drc_append_save_call_restore(drc, (x86code *)mips3com_tlbr, 12); // call tlbr + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x02: /* TLBWI */ + emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 + emit_push_imm(DRCTOP, (FPTR)mips3.core); // push mips3.core + drc_append_save_call_restore(drc, (x86code *)mips3com_tlbwi, 12); // call tlbwi + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x06: /* TLBWR */ + emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 + emit_push_imm(DRCTOP, (FPTR)mips3.core); // push mips3.core + drc_append_save_call_restore(drc, (x86code *)mips3com_tlbwr, 12); // call tlbwr + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x08: /* TLBP */ + emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 + emit_push_imm(DRCTOP, (FPTR)mips3.core); // push mips3.core + drc_append_save_call_restore(drc, (x86code *)mips3com_tlbp, 12); // call tlbp + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x10: /* RFE */ + emit_jmp(DRCTOP, mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception + return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; + + case 0x18: /* ERET */ + emit_mov_r32_m32(DRCTOP, REG_EDI, CPR0ADDR(COP0_EPC)); // mov edi,[COP0_EPC] + emit_and_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), ~SR_EXL); // and [COP0_Status],~SR_EXL + return RECOMPILE_SUCCESSFUL_CP(1,0) | RECOMPILE_CHECK_INTERRUPTS | RECOMPILE_END_OF_STRING | RECOMPILE_ADD_DISPATCH; + + default: + emit_jmp(DRCTOP, mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception + return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; + } + break; + +// default: +// _jmp(mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception +// return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; + } + return RECOMPILE_UNIMPLEMENTED; +} + + + +/*************************************************************************** + COP1 RECOMPILATION +***************************************************************************/ + +/*------------------------------------------------------------------ + recompile_cop1 +------------------------------------------------------------------*/ + +static UINT32 recompile_cop1(drc_core *drc, UINT32 pc, UINT32 op) +{ + emit_link link1; + int cycles, i; + + if (mips3.drcoptions & MIPS3DRC_STRICT_COP1) + { + emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_COP1); // test [COP0_Status],SR_COP1 + emit_jcc(DRCTOP, COND_Z, mips3.drcdata->generate_cop_exception); // jz generate_cop_exception + } + + switch (RSREG) + { + case 0x00: /* MFCz */ + if (RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(RDREG)); // mov eax,[RDREG] + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [RTREG],edx:eax + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x01: /* DMFCz */ + if (RTREG != 0) + emit_mov_m64_m64(DRCTOP, REGADDR(RTREG), FPR64ADDR(RDREG)); + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x02: /* CFCz */ + if (RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, CCR1ADDR(RDREG)); // mov eax,[mips3.core->ccr[1][RDREG]] + if (RDREG == 31) + { + emit_and_r32_imm(DRCTOP, REG_EAX, ~0xfe800000); // and eax,~0xfe800000 + emit_xor_r32_r32(DRCTOP, REG_EBX, REG_EBX); // xor ebx,ebx + emit_cmp_m8_imm(DRCTOP, MABS(&mips3.core->cf[1][0]), 0); // cmp [cf[0]],0 + emit_setcc_r8(DRCTOP, COND_NZ, REG_BL); // setnz bl + emit_shl_r32_imm(DRCTOP, REG_EBX, 23); // shl ebx,23 + emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx + if (mips3.core->flavor >= MIPS3_TYPE_MIPS_IV) + for (i = 1; i <= 7; i++) + { + emit_cmp_m8_imm(DRCTOP, MABS(&mips3.core->cf[1][i]), 0); // cmp [cf[i]],0 + emit_setcc_r8(DRCTOP, COND_NZ, REG_BL); // setnz bl + emit_shl_r32_imm(DRCTOP, REG_EBX, 24+i); // shl ebx,24+i + emit_or_r32_r32(DRCTOP, REG_EAX, REG_EBX); // or eax,ebx + } + } + emit_cdq(DRCTOP); // cdq + emit_mov_m64_r64(DRCTOP, REGADDR(RTREG), REG_EDX, REG_EAX); // mov [mips3.core->r[RTREG]],edx:eax + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x04: /* MTCz */ + if (RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[mips3.core->r[RTREG]] + emit_mov_m32_r32(DRCTOP, FPR32ADDR(RDREG), REG_EAX); // mov [mips3.core->cpr[1][RDREG]],eax + } + else + emit_mov_m32_imm(DRCTOP, FPR32ADDR(RDREG), 0); // mov [mips3.core->cpr[1][RDREG]],0 + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x05: /* DMTCz */ + if (RTREG != 0) + emit_mov_m64_m64(DRCTOP, FPR64ADDR(RDREG), REGADDR(RTREG)); + else + emit_zero_m64(DRCTOP, FPR64ADDR(RDREG)); // mov [mips3.core->cpr[1][RDREG]],0 + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x06: /* CTCz */ + if (RTREG != 0) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[mips3.core->r[RTREG]] + emit_mov_m32_r32(DRCTOP, CCR1ADDR(RDREG), REG_EAX); // mov [mips3.core->ccr[1][RDREG]],eax + } + else + emit_mov_m32_imm(DRCTOP, CCR1ADDR(RDREG), 0); // mov [mips3.core->ccr[1][RDREG]],0 + if (RDREG == 31) + { + emit_mov_r32_m32(DRCTOP, REG_EAX, MABS(LO(&mips3.core->ccr[1][RDREG]))); // mov eax,[mips3.core->ccr[1][RDREG]] + emit_test_r32_imm(DRCTOP, REG_EAX, 1 << 23); // test eax,1<<23 + emit_setcc_m8(DRCTOP, COND_NZ, MABS(&mips3.core->cf[1][0])); // setnz [cf[0]] + if (mips3.core->flavor >= MIPS3_TYPE_MIPS_IV) + for (i = 1; i <= 7; i++) + { + emit_test_r32_imm(DRCTOP, REG_EAX, 1 << (24+i)); // test eax,1<<(24+i) + emit_setcc_m8(DRCTOP, COND_NZ, MABS(&mips3.core->cf[1][i])); // setnz [cf[i]] + } + emit_and_r32_imm(DRCTOP, REG_EAX, 3); // and eax,3 + emit_test_r32_imm(DRCTOP, REG_EAX, 1); // test eax,1 + emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz skip + emit_xor_r32_imm(DRCTOP, REG_EAX, 2); // xor eax,2 + resolve_link(DRCTOP, &link1); // skip: + drc_append_set_fp_rounding(drc, REG_EAX); // set_rounding(EAX) + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x08: /* BC */ + switch ((op >> 16) & 3) + { + case 0x00: /* BCzF */ + emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp [cf[x]],0 + emit_jcc_near_link(DRCTOP, COND_NZ, &link1); // jnz link1 + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + resolve_link(DRCTOP, &link1); // skip: + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x01: /* BCzT */ + emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp [cf[x]],0 + emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz link1 + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + resolve_link(DRCTOP, &link1); // skip: + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x02: /* BCzFL */ + emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp [cf[x]],0 + emit_jcc_near_link(DRCTOP, COND_NZ, &link1); // jnz link1 + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + resolve_link(DRCTOP, &link1); // skip: + return RECOMPILE_SUCCESSFUL_CP(1,8); + + case 0x03: /* BCzTL */ + emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp [cf[x]],0 + emit_jcc_near_link(DRCTOP, COND_Z, &link1); // jz link1 + cycles = recompile_delay_slot(drc, pc + 4); // <next instruction> + append_branch_or_dispatch(drc, pc + 4 + (SIMMVAL << 2), 1+cycles); // <branch or dispatch> + resolve_link(DRCTOP, &link1); // skip: + return RECOMPILE_SUCCESSFUL_CP(1,8); + } + break; + + default: + switch (op & 0x3f) + { + case 0x00: + if (IS_SINGLE(op)) /* ADD.S */ + { + if (USE_SSE) + { + emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] + emit_addss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // addss xmm0,[ftreg] + emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 + } + else + { + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] + emit_faddp(DRCTOP); // faddp + emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] + } + } + else /* ADD.D */ + { + if (USE_SSE) + { + emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] + emit_addsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // addsd xmm0,[ftreg] + emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 + } + else + { + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] + emit_faddp(DRCTOP); // faddp + emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] + } + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x01: + if (IS_SINGLE(op)) /* SUB.S */ + { + if (USE_SSE) + { + emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] + emit_subss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // subss xmm0,[ftreg] + emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 + } + else + { + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] + emit_fsubp(DRCTOP); // fsubp + emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] + } + } + else /* SUB.D */ + { + if (USE_SSE) + { + emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] + emit_subsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // subsd xmm0,[ftreg] + emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 + } + else + { + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] + emit_fsubp(DRCTOP); // fsubp + emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] + } + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x02: + if (IS_SINGLE(op)) /* MUL.S */ + { + if (USE_SSE) + { + emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] + emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg] + emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 + } + else + { + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] + emit_fmulp(DRCTOP); // fmulp + emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] + } + } + else /* MUL.D */ + { + if (USE_SSE) + { + emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] + emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg] + emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 + } + else + { + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] + emit_fmulp(DRCTOP); // fmulp + emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] + } + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x03: + if (IS_SINGLE(op)) /* DIV.S */ + { + if (USE_SSE) + { + emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] + emit_divss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // divss xmm0,[ftreg] + emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 + } + else + { + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] + emit_fdivp(DRCTOP); // fdivp + emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] + } + } + else /* DIV.D */ + { + if (USE_SSE) + { + emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] + emit_divsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // divsd xmm0,[ftreg] + emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 + } + else + { + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] + emit_fdivp(DRCTOP); // fdivp + emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] + } + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x04: + if (IS_SINGLE(op)) /* SQRT.S */ + { + if (USE_SSE) + { + emit_sqrtss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // sqrtss xmm0,[fsreg] + emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 + } + else + { + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + emit_fsqrt(DRCTOP); // fsqrt + emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] + } + } + else /* SQRT.D */ + { + if (USE_SSE) + { + emit_sqrtsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // sqrtsd xmm0,[fsreg] + emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 + } + else + { + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + emit_fsqrt(DRCTOP); // fsqrt + emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] + } + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x05: + if (IS_SINGLE(op)) /* ABS.S */ + { + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + emit_fabs(DRCTOP); // fabs + emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] + } + else /* ABS.D */ + { + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + emit_fabs(DRCTOP); // fabs + emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x06: + if (IS_SINGLE(op)) /* MOV.S */ + { + emit_mov_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // mov eax,[fsreg] + emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax + } + else /* MOV.D */ + emit_mov_m64_m64(DRCTOP, FPR64ADDR(FDREG), FPR64ADDR(FSREG)); + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x07: + if (IS_SINGLE(op)) /* NEG.S */ + { + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + emit_fchs(DRCTOP); // fchs + emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] + } + else /* NEG.D */ + { + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + emit_fchs(DRCTOP); // fchs + emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x08: + drc_append_set_temp_fp_rounding(drc, FPRND_NEAR); + if (IS_SINGLE(op)) /* ROUND.L.S */ + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + else /* ROUND.L.D */ + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + emit_fistp_m64(DRCTOP, FPR64ADDR(FDREG)); // fistp [fdreg] + drc_append_restore_fp_rounding(drc); + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x09: + drc_append_set_temp_fp_rounding(drc, FPRND_CHOP); + if (IS_SINGLE(op)) /* TRUNC.L.S */ + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + else /* TRUNC.L.D */ + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + emit_fistp_m64(DRCTOP, FPR64ADDR(FDREG)); // fistp [fdreg] + drc_append_restore_fp_rounding(drc); + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x0a: + drc_append_set_temp_fp_rounding(drc, FPRND_UP); + if (IS_SINGLE(op)) /* CEIL.L.S */ + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + else /* CEIL.L.D */ + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + emit_fistp_m64(DRCTOP, FPR64ADDR(FDREG)); // fistp [fdreg] + drc_append_restore_fp_rounding(drc); + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x0b: + drc_append_set_temp_fp_rounding(drc, FPRND_DOWN); + if (IS_SINGLE(op)) /* FLOOR.L.S */ + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + else /* FLOOR.L.D */ + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + emit_fistp_m64(DRCTOP, FPR64ADDR(FDREG)); // fistp [fdreg] + drc_append_restore_fp_rounding(drc); + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x0c: + drc_append_set_temp_fp_rounding(drc, FPRND_NEAR); + if (IS_SINGLE(op)) /* ROUND.W.S */ + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + else /* ROUND.W.D */ + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + emit_fistp_m32(DRCTOP, FPR32ADDR(FDREG)); // fistp [fdreg] + drc_append_restore_fp_rounding(drc); + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x0d: + drc_append_set_temp_fp_rounding(drc, FPRND_CHOP); + if (IS_SINGLE(op)) /* TRUNC.W.S */ + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + else /* TRUNC.W.D */ + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + emit_fistp_m32(DRCTOP, FPR32ADDR(FDREG)); // fistp [fdreg] + drc_append_restore_fp_rounding(drc); + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x0e: + drc_append_set_temp_fp_rounding(drc, FPRND_UP); + if (IS_SINGLE(op)) /* CEIL.W.S */ + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + else /* CEIL.W.D */ + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + emit_fistp_m32(DRCTOP, FPR32ADDR(FDREG)); // fistp [fdreg] + drc_append_restore_fp_rounding(drc); + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x0f: + drc_append_set_temp_fp_rounding(drc, FPRND_DOWN); + if (IS_SINGLE(op)) /* FLOOR.W.S */ + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + else /* FLOOR.W.D */ + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + emit_fistp_m32(DRCTOP, FPR32ADDR(FDREG)); // fistp [fdreg] + drc_append_restore_fp_rounding(drc); + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x11: /* R5000 */ + if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV) + { + emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); + // jmp generate_invalidop_exception + return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; + } + emit_cmp_m8_imm(DRCTOP, CF1ADDR((op >> 18) & 7), 0); // cmp [cf[x]],0 + emit_jcc_short_link(DRCTOP, ((op >> 16) & 1) ? COND_Z : COND_NZ, &link1); + // jz/nz skip + if (IS_SINGLE(op)) /* MOVT/F.S */ + { + emit_mov_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // mov eax,[fsreg] + emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax + } + else /* MOVT/F.D */ + emit_mov_m64_m64(DRCTOP, FPR64ADDR(FDREG), FPR64ADDR(FSREG)); + resolve_link(DRCTOP, &link1); // skip: + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x12: /* R5000 */ + if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV) + { + emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); + // jmp generate_invalidop_exception + return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; + } + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo + emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi + emit_jcc_short_link(DRCTOP, COND_NZ, &link1); // jnz skip + if (IS_SINGLE(op)) /* MOVZ.S */ + { + emit_mov_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // mov eax,[fsreg] + emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax + } + else /* MOVZ.D */ + emit_mov_m64_m64(DRCTOP, FPR64ADDR(FDREG), FPR64ADDR(FSREG)); + resolve_link(DRCTOP, &link1); // skip: + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x13: /* R5000 */ + if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV) + { + emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); + // jmp generate_invalidop_exception + return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; + } + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // mov eax,[rtreg].lo + emit_or_r32_m32(DRCTOP, REG_EAX, REGADDRHI(RTREG)); // or eax,[rtreg].hi + emit_jcc_short_link(DRCTOP, COND_Z, &link1); // jz skip + if (IS_SINGLE(op)) /* MOVN.S */ + { + emit_mov_r32_m32(DRCTOP, REG_EAX, FPR32ADDR(FSREG)); // mov eax,[fsreg] + emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax + } + else /* MOVN.D */ + emit_mov_m64_m64(DRCTOP, FPR64ADDR(FDREG), FPR64ADDR(FSREG)); + resolve_link(DRCTOP, &link1); // skip: + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x15: /* R5000 */ + if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV) + { + emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); + // jmp generate_invalidop_exception + return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; + } + emit_fld1(DRCTOP); // fld1 + if (IS_SINGLE(op)) /* RECIP.S */ + { + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + emit_fdivp(DRCTOP); // fdivp + emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] + } + else /* RECIP.D */ + { + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + emit_fdivp(DRCTOP); // fdivp + emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x16: /* R5000 */ + if (mips3.core->flavor < MIPS3_TYPE_MIPS_IV) + { + emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); + // jmp generate_invalidop_exception + return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; + } + emit_fld1(DRCTOP); // fld1 + if (IS_SINGLE(op)) /* RSQRT.S */ + { + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + emit_fsqrt(DRCTOP); // fsqrt + emit_fdivp(DRCTOP); // fdivp + emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] + } + else /* RSQRT.D */ + { + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + emit_fsqrt(DRCTOP); // fsqrt + emit_fdivp(DRCTOP); // fdivp + emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x20: + if (IS_INTEGRAL(op)) + { + if (IS_SINGLE(op)) /* CVT.S.W */ + emit_fild_m32(DRCTOP, FPR32ADDR(FSREG)); // fild [fsreg] + else /* CVT.S.L */ + emit_fild_m64(DRCTOP, FPR64ADDR(FSREG)); // fild [fsreg] + } + else /* CVT.S.D */ + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x21: + if (IS_INTEGRAL(op)) + { + if (IS_SINGLE(op)) /* CVT.D.W */ + emit_fild_m32(DRCTOP, FPR32ADDR(FSREG)); // fild [fsreg] + else /* CVT.D.L */ + emit_fild_m64(DRCTOP, FPR64ADDR(FSREG)); // fild [fsreg] + } + else /* CVT.D.S */ + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x24: + if (IS_SINGLE(op)) /* CVT.W.S */ + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + else /* CVT.W.D */ + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + emit_fistp_m32(DRCTOP, FPR32ADDR(FDREG)); // fistp [fdreg] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x25: + if (IS_SINGLE(op)) /* CVT.L.S */ + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + else /* CVT.L.D */ + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + emit_fistp_m64(DRCTOP, FPR64ADDR(FDREG)); // fistp [fdreg] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x30: + case 0x38: + emit_mov_m8_imm(DRCTOP, CF1ADDR((op >> 8) & 7), 0); /* C.F.S/D */ + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x31: + case 0x39: + emit_mov_m8_imm(DRCTOP, CF1ADDR((op >> 8) & 7), 0); /* C.UN.S/D */ + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x32: + case 0x3a: + if (USE_SSE) + { + if (IS_SINGLE(op)) /* C.EQ.S */ + { + emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] + emit_comiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // comiss xmm0,[ftreg] + } + else + { + emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] + emit_comisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // comisd xmm0,[ftreg] + } + emit_setcc_m8(DRCTOP, COND_E, CF1ADDR((op >> 8) & 7)); // sete [cf[x]] + } + else + { + if (IS_SINGLE(op)) /* C.EQ.S */ + { + emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + } + else + { + emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + } + emit_fcompp(DRCTOP); // fcompp + emit_fstsw_ax(DRCTOP); // fnstsw ax + emit_sahf(DRCTOP); // sahf + emit_setcc_m8(DRCTOP, COND_E, CF1ADDR((op >> 8) & 7)); // sete [cf[x]] + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x33: + case 0x3b: + if (USE_SSE) + { + if (IS_SINGLE(op)) /* C.UEQ.S */ + { + emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] + emit_ucomiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // ucomiss xmm0,[ftreg] + } + else + { + emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] + emit_ucomisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // ucomisd xmm0,[ftreg] + } + emit_setcc_m8(DRCTOP, COND_E, CF1ADDR((op >> 8) & 7)); // sete [cf[x]] + } + else + { + if (IS_SINGLE(op)) /* C.UEQ.S */ + { + emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + } + else + { + emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + } + emit_fucompp(DRCTOP); // fucompp + emit_fstsw_ax(DRCTOP); // fnstsw ax + emit_sahf(DRCTOP); // sahf + emit_setcc_m8(DRCTOP, COND_E, CF1ADDR((op >> 8) & 7)); // sete [cf[x]] + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x34: + case 0x3c: + if (USE_SSE) + { + if (IS_SINGLE(op)) /* C.OLT.S */ + { + emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] + emit_comiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // comiss xmm0,[ftreg] + } + else + { + emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] + emit_comisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // comisd xmm0,[ftreg] + } + emit_setcc_m8(DRCTOP, COND_B, CF1ADDR((op >> 8) & 7)); // setb [cf[x]] + } + else + { + if (IS_SINGLE(op)) /* C.OLT.S */ + { + emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + } + else + { + emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + } + emit_fcompp(DRCTOP); // fcompp + emit_fstsw_ax(DRCTOP); // fnstsw ax + emit_sahf(DRCTOP); // sahf + emit_setcc_m8(DRCTOP, COND_B, CF1ADDR((op >> 8) & 7)); // setb [cf[x]] + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x35: + case 0x3d: + if (USE_SSE) + { + if (IS_SINGLE(op)) /* C.ULT.S */ + { + emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] + emit_ucomiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // ucomiss xmm0,[ftreg] + } + else + { + emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] + emit_ucomisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // ucomisd xmm0,[ftreg] + } + emit_setcc_m8(DRCTOP, COND_B, CF1ADDR((op >> 8) & 7)); // setb [cf[x]] + } + else + { + if (IS_SINGLE(op)) /* C.ULT.S */ + { + emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + } + else + { + emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + } + emit_fucompp(DRCTOP); // fucompp + emit_fstsw_ax(DRCTOP); // fnstsw ax + emit_sahf(DRCTOP); // sahf + emit_setcc_m8(DRCTOP, COND_B, CF1ADDR((op >> 8) & 7)); // setb [cf[x]] + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x36: + case 0x3e: + if (USE_SSE) + { + if (IS_SINGLE(op)) /* C.OLE.S */ + { + emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] + emit_comiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // comiss xmm0,[ftreg] + } + else + { + emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] + emit_comisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // comisd xmm0,[ftreg] + } + emit_setcc_m8(DRCTOP, COND_BE, CF1ADDR((op >> 8) & 7)); // setle [cf[x]] + } + else + { + if (IS_SINGLE(op)) /* C.OLE.S */ + { + emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + } + else + { + emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + } + emit_fcompp(DRCTOP); // fcompp + emit_fstsw_ax(DRCTOP); // fnstsw ax + emit_sahf(DRCTOP); // sahf + emit_setcc_m8(DRCTOP, COND_BE, CF1ADDR((op >> 8) & 7)); // setbe [cf[x]] + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x37: + case 0x3f: + if (USE_SSE) + { + if (IS_SINGLE(op)) /* C.ULE.S */ + { + emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] + emit_ucomiss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // ucomiss xmm0,[ftreg] + } + else + { + emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] + emit_ucomisd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // ucomisd xmm0,[ftreg] + } + emit_setcc_m8(DRCTOP, COND_BE, CF1ADDR((op >> 8) & 7)); // setl [cf[x]] + } + else + { + if (IS_SINGLE(op)) /* C.ULE.S */ + { + emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + } + else + { + emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + } + emit_fucompp(DRCTOP); // fucompp + emit_fstsw_ax(DRCTOP); // fnstsw ax + emit_sahf(DRCTOP); // sahf + emit_setcc_m8(DRCTOP, COND_BE, CF1ADDR((op >> 8) & 7)); // setbe [cf[x]] + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + } + break; + } + emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception + return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; +} + + + +/*************************************************************************** + COP1X RECOMPILATION +***************************************************************************/ + +/*------------------------------------------------------------------ + recompile_cop1x +------------------------------------------------------------------*/ + +static UINT32 recompile_cop1x(drc_core *drc, UINT32 pc, UINT32 op) +{ + if (mips3.drcoptions & MIPS3DRC_STRICT_COP1) + { + emit_test_m32_imm(DRCTOP, CPR0ADDR(COP0_Status), SR_COP1); // test [COP0_Status],SR_COP1 + emit_jcc(DRCTOP, COND_Z, mips3.drcdata->generate_cop_exception); // jz generate_cop_exception + } + + switch (op & 0x3f) + { + case 0x00: /* LWXC1 */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg] + emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg] + emit_push_r32(DRCTOP, REG_EAX); // push eax + emit_call(DRCTOP, mips3.drcdata->read_and_translate_word); // call read_and_translate_word + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + emit_mov_m32_r32(DRCTOP, FPR32ADDR(FDREG), REG_EAX); // mov [fdreg],eax + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x01: /* LDXC1 */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_sub_r32_imm(DRCTOP, REG_ESP, 8); // sub esp,8 + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg] + emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg] + emit_push_r32(DRCTOP, REG_EAX); // push eax + emit_call(DRCTOP, mips3.drcdata->read_and_translate_double); // call read_and_translate_double + emit_mov_m32_r32(DRCTOP, FPR64ADDRLO(FDREG), REG_EAX); // mov [fdreg].lo,eax + emit_mov_m32_r32(DRCTOP, FPR64ADDRHI(FDREG), REG_EDX); // mov [fdreg].hi,edx + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x08: /* SWXC1 */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_sub_r32_imm(DRCTOP, REG_ESP, 4); // sub esp,4 + emit_push_m32(DRCTOP, FPR32ADDR(FSREG)); // push [fsreg] + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg] + emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg] + emit_push_r32(DRCTOP, REG_EAX); // push eax + emit_call(DRCTOP, mips3.drcdata->write_and_translate_word); // call write_and_translate_word + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,8 + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x09: /* SDXC1 */ + emit_mov_m32_r32(DRCTOP, ICOUNTADDR, REG_EBP); // mov [icount],ebp + emit_save_pc_before_call(DRCTOP); // save pc + emit_push_m32(DRCTOP, FPR64ADDRHI(FSREG)); // push [fsreg].hi + emit_push_m32(DRCTOP, FPR64ADDRLO(FSREG)); // push [fsreg].lo + emit_mov_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RSREG)); // mov eax,[rsreg] + emit_add_r32_m32(DRCTOP, REG_EAX, REGADDRLO(RTREG)); // add eax,[rtreg] + emit_push_r32(DRCTOP, REG_EAX); // push eax + emit_call(DRCTOP, mips3.drcdata->write_and_translate_double); // call write_and_translate_double + emit_add_r32_imm(DRCTOP, REG_ESP, 12); // add esp,12 + emit_mov_r32_m32(DRCTOP, REG_EBP, ICOUNTADDR); // mov ebp,[icount] + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x0f: /* PREFX */ + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x20: /* MADD.S */ + if (USE_SSE) + { + emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] + emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg] + emit_addss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FRREG)); // addss xmm0,[frreg] + emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 + } + else + { + emit_fld_m32(DRCTOP, FPR32ADDR(FRREG)); // fld [frreg] + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] + emit_fmulp(DRCTOP); // fmulp + emit_faddp(DRCTOP); // faddp + emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x21: /* MADD.D */ + if (USE_SSE) + { + emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] + emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg] + emit_addsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FRREG)); // addsd xmm0,[frreg] + emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 + } + else + { + emit_fld_m64(DRCTOP, FPR64ADDR(FRREG)); // fld [frreg] + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] + emit_fmulp(DRCTOP); // fmulp + emit_faddp(DRCTOP); // faddp + emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x28: /* MSUB.S */ + if (USE_SSE) + { + emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] + emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg] + emit_subss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FRREG)); // subss xmm0,[frreg] + emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM0); // movss [fdreg],xmm0 + } + else + { + emit_fld_m32(DRCTOP, FPR32ADDR(FRREG)); // fld [frreg] + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] + emit_fmulp(DRCTOP); // fmulp + emit_fsubrp(DRCTOP); // fsubrp + emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x29: /* MSUB.D */ + if (USE_SSE) + { + emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] + emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg] + emit_subsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FRREG)); // subsd xmm0,[frreg] + emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM0); // movsd [fdreg],xmm0 + } + else + { + emit_fld_m64(DRCTOP, FPR64ADDR(FRREG)); // fld [frreg] + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] + emit_fmulp(DRCTOP); // fmulp + emit_fsubrp(DRCTOP); // fsubrp + emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x30: /* NMADD.S */ + if (USE_SSE) + { + emit_xorps_r128_r128(DRCTOP, REG_XMM1, REG_XMM1); // xorps xmm1,xmm1 + emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] + emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg] + emit_addss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FRREG)); // addss xmm0,[frreg] + emit_subss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subss xmm1,xmm0 + emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM1); // movss [fdreg],xmm1 + } + else + { + emit_fld_m32(DRCTOP, FPR32ADDR(FRREG)); // fld [frreg] + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] + emit_fmulp(DRCTOP); // fmulp + emit_faddp(DRCTOP); // faddp + emit_fchs(DRCTOP); // fchs + emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x31: /* NMADD.D */ + if (USE_SSE) + { + emit_xorps_r128_r128(DRCTOP, REG_XMM1, REG_XMM1); // xorps xmm1,xmm1 + emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] + emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg] + emit_addsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FRREG)); // addsd xmm0,[frreg] + emit_subss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subss xmm1,xmm0 + emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM1); // movsd [fdreg],xmm1 + } + else + { + emit_fld_m64(DRCTOP, FPR64ADDR(FRREG)); // fld [frreg] + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] + emit_fmulp(DRCTOP); // fmulp + emit_faddp(DRCTOP); // faddp + emit_fchs(DRCTOP); // fchs + emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x38: /* NMSUB.S */ + if (USE_SSE) + { + emit_movss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FSREG)); // movss xmm0,[fsreg] + emit_mulss_r128_m32(DRCTOP, REG_XMM0, FPR32ADDR(FTREG)); // mulss xmm0,[ftreg] + emit_movss_r128_m32(DRCTOP, REG_XMM1, FPR32ADDR(FRREG)); // movss xmm1,[frreg] + emit_subss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subss xmm1,xmm0 + emit_movss_m32_r128(DRCTOP, FPR32ADDR(FDREG), REG_XMM1); // movss [fdreg],xmm1 + } + else + { + emit_fld_m32(DRCTOP, FPR32ADDR(FRREG)); // fld [frreg] + emit_fld_m32(DRCTOP, FPR32ADDR(FSREG)); // fld [fsreg] + emit_fld_m32(DRCTOP, FPR32ADDR(FTREG)); // fld [ftreg] + emit_fmulp(DRCTOP); // fmulp + emit_fsubp(DRCTOP); // fsubp + emit_fstp_m32(DRCTOP, FPR32ADDR(FDREG)); // fstp [fdreg] + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x39: /* NMSUB.D */ + if (USE_SSE) + { + emit_movsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FSREG)); // movsd xmm0,[fsreg] + emit_mulsd_r128_m64(DRCTOP, REG_XMM0, FPR64ADDR(FTREG)); // mulsd xmm0,[ftreg] + emit_movsd_r128_m64(DRCTOP, REG_XMM1, FPR64ADDR(FRREG)); // movsd xmm1,[frreg] + emit_subss_r128_r128(DRCTOP, REG_XMM1, REG_XMM0); // subss xmm1,xmm0 + emit_movsd_m64_r128(DRCTOP, FPR64ADDR(FDREG), REG_XMM1); // movsd [fdreg],xmm1 + } + else + { + emit_fld_m64(DRCTOP, FPR64ADDR(FRREG)); // fld [frreg] + emit_fld_m64(DRCTOP, FPR64ADDR(FSREG)); // fld [fsreg] + emit_fld_m64(DRCTOP, FPR64ADDR(FTREG)); // fld [ftreg] + emit_fmulp(DRCTOP); // fmulp + emit_fsubp(DRCTOP); // fsubrp + emit_fstp_m64(DRCTOP, FPR64ADDR(FDREG)); // fstp [fdreg] + } + return RECOMPILE_SUCCESSFUL_CP(1,4); + + case 0x24: /* MADD.W */ + case 0x25: /* MADD.L */ + case 0x2c: /* MSUB.W */ + case 0x2d: /* MSUB.L */ + case 0x34: /* NMADD.W */ + case 0x35: /* NMADD.L */ + case 0x3c: /* NMSUB.W */ + case 0x3d: /* NMSUB.L */ + default: + fprintf(stderr, "cop1x %X\n", op); + break; + } + emit_jmp(DRCTOP, (void *)mips3.drcdata->generate_invalidop_exception); // jmp generate_invalidop_exception + return RECOMPILE_SUCCESSFUL | RECOMPILE_END_OF_STRING; +} |