nkeynes@359: /** nkeynes@586: * $Id$ nkeynes@359: * nkeynes@359: * SH4 => x86 translation. This version does no real optimization, it just nkeynes@359: * outputs straight-line x86 code - it mainly exists to provide a baseline nkeynes@359: * to test the optimizing versions against. nkeynes@359: * nkeynes@359: * Copyright (c) 2007 Nathan Keynes. nkeynes@359: * nkeynes@359: * This program is free software; you can redistribute it and/or modify nkeynes@359: * it under the terms of the GNU General Public License as published by nkeynes@359: * the Free Software Foundation; either version 2 of the License, or nkeynes@359: * (at your option) any later version. nkeynes@359: * nkeynes@359: * This program is distributed in the hope that it will be useful, nkeynes@359: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@359: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@359: * GNU General Public License for more details. nkeynes@359: */ nkeynes@359: nkeynes@368: #include nkeynes@388: #include nkeynes@368: nkeynes@380: #ifndef NDEBUG nkeynes@380: #define DEBUG_JUMPS 1 nkeynes@380: #endif nkeynes@380: nkeynes@417: #include "sh4/xltcache.h" nkeynes@368: #include "sh4/sh4core.h" nkeynes@368: #include "sh4/sh4trans.h" nkeynes@671: #include "sh4/sh4stat.h" nkeynes@388: #include "sh4/sh4mmio.h" nkeynes@368: #include "sh4/x86op.h" nkeynes@368: #include "clock.h" nkeynes@368: nkeynes@368: #define DEFAULT_BACKPATCH_SIZE 4096 nkeynes@368: nkeynes@586: struct backpatch_record { nkeynes@604: uint32_t fixup_offset; nkeynes@586: uint32_t fixup_icount; nkeynes@596: int32_t exc_code; nkeynes@586: }; nkeynes@586: nkeynes@590: #define DELAY_NONE 0 nkeynes@590: #define DELAY_PC 1 nkeynes@590: #define DELAY_PC_PR 2 nkeynes@590: nkeynes@368: /** nkeynes@368: * Struct to manage internal translation state. This state is not saved - nkeynes@368: * it is only valid between calls to sh4_translate_begin_block() and nkeynes@368: * sh4_translate_end_block() nkeynes@368: */ nkeynes@368: struct sh4_x86_state { nkeynes@590: int in_delay_slot; nkeynes@368: gboolean priv_checked; /* true if we've already checked the cpu mode. */ nkeynes@368: gboolean fpuen_checked; /* true if we've already checked fpu enabled. */ nkeynes@409: gboolean branch_taken; /* true if we branched unconditionally */ nkeynes@408: uint32_t block_start_pc; nkeynes@547: uint32_t stack_posn; /* Trace stack height for alignment purposes */ nkeynes@417: int tstate; nkeynes@368: nkeynes@586: /* mode flags */ nkeynes@586: gboolean tlb_on; /* True if tlb translation is active */ nkeynes@586: nkeynes@368: /* Allocated memory for the (block-wide) back-patch list */ nkeynes@586: struct backpatch_record *backpatch_list; nkeynes@368: uint32_t backpatch_posn; nkeynes@368: uint32_t backpatch_size; nkeynes@368: }; nkeynes@368: nkeynes@417: #define TSTATE_NONE -1 nkeynes@417: #define TSTATE_O 0 nkeynes@417: #define TSTATE_C 2 nkeynes@417: #define TSTATE_E 4 nkeynes@417: #define TSTATE_NE 5 nkeynes@417: #define TSTATE_G 0xF nkeynes@417: #define TSTATE_GE 0xD nkeynes@417: #define TSTATE_A 7 nkeynes@417: #define TSTATE_AE 3 nkeynes@417: nkeynes@671: #ifdef ENABLE_SH4STATS nkeynes@671: #define COUNT_INST(id) load_imm32(R_EAX,id); call_func1(sh4_stats_add, R_EAX); sh4_x86.tstate = TSTATE_NONE nkeynes@671: #else nkeynes@671: #define COUNT_INST(id) nkeynes@671: #endif nkeynes@671: nkeynes@417: /** Branch if T is set (either in the current cflags, or in sh4r.t) */ nkeynes@669: #define JT_rel8(label) if( sh4_x86.tstate == TSTATE_NONE ) { \ nkeynes@417: CMP_imm8s_sh4r( 1, R_T ); sh4_x86.tstate = TSTATE_E; } \ nkeynes@669: OP(0x70+sh4_x86.tstate); MARK_JMP8(label); OP(-1) nkeynes@669: nkeynes@417: /** Branch if T is clear (either in the current cflags or in sh4r.t) */ nkeynes@669: #define JF_rel8(label) if( sh4_x86.tstate == TSTATE_NONE ) { \ nkeynes@417: CMP_imm8s_sh4r( 1, R_T ); sh4_x86.tstate = TSTATE_E; } \ nkeynes@669: OP(0x70+ (sh4_x86.tstate^1)); MARK_JMP8(label); OP(-1) nkeynes@417: nkeynes@368: static struct sh4_x86_state sh4_x86; nkeynes@368: nkeynes@388: static uint32_t max_int = 0x7FFFFFFF; nkeynes@388: static uint32_t min_int = 0x80000000; nkeynes@394: static uint32_t save_fcw; /* save value for fpu control word */ nkeynes@394: static uint32_t trunc_fcw = 0x0F7F; /* fcw value for truncation mode */ nkeynes@386: nkeynes@669: void sh4_translate_init(void) nkeynes@368: { nkeynes@368: sh4_x86.backpatch_list = malloc(DEFAULT_BACKPATCH_SIZE); nkeynes@586: sh4_x86.backpatch_size = DEFAULT_BACKPATCH_SIZE / sizeof(struct backpatch_record); nkeynes@368: } nkeynes@368: nkeynes@368: nkeynes@586: static void sh4_x86_add_backpatch( uint8_t *fixup_addr, uint32_t fixup_pc, uint32_t exc_code ) nkeynes@368: { nkeynes@368: if( sh4_x86.backpatch_posn == sh4_x86.backpatch_size ) { nkeynes@368: sh4_x86.backpatch_size <<= 1; nkeynes@586: sh4_x86.backpatch_list = realloc( sh4_x86.backpatch_list, nkeynes@586: sh4_x86.backpatch_size * sizeof(struct backpatch_record)); nkeynes@368: assert( sh4_x86.backpatch_list != NULL ); nkeynes@368: } nkeynes@586: if( sh4_x86.in_delay_slot ) { nkeynes@586: fixup_pc -= 2; nkeynes@586: } nkeynes@604: sh4_x86.backpatch_list[sh4_x86.backpatch_posn].fixup_offset = nkeynes@604: ((uint8_t *)fixup_addr) - ((uint8_t *)xlat_current_block->code); nkeynes@586: sh4_x86.backpatch_list[sh4_x86.backpatch_posn].fixup_icount = (fixup_pc - sh4_x86.block_start_pc)>>1; nkeynes@586: sh4_x86.backpatch_list[sh4_x86.backpatch_posn].exc_code = exc_code; nkeynes@586: sh4_x86.backpatch_posn++; nkeynes@368: } nkeynes@368: nkeynes@359: /** nkeynes@359: * Emit an instruction to load an SH4 reg into a real register nkeynes@359: */ nkeynes@359: static inline void load_reg( int x86reg, int sh4reg ) nkeynes@359: { nkeynes@359: /* mov [bp+n], reg */ nkeynes@361: OP(0x8B); nkeynes@361: OP(0x45 + (x86reg<<3)); nkeynes@359: OP(REG_OFFSET(r[sh4reg])); nkeynes@359: } nkeynes@359: nkeynes@374: static inline void load_reg16s( int x86reg, int sh4reg ) nkeynes@368: { nkeynes@374: OP(0x0F); nkeynes@374: OP(0xBF); nkeynes@374: MODRM_r32_sh4r(x86reg, REG_OFFSET(r[sh4reg])); nkeynes@368: } nkeynes@368: nkeynes@374: static inline void load_reg16u( int x86reg, int sh4reg ) nkeynes@368: { nkeynes@374: OP(0x0F); nkeynes@374: OP(0xB7); nkeynes@374: MODRM_r32_sh4r(x86reg, REG_OFFSET(r[sh4reg])); nkeynes@374: nkeynes@368: } nkeynes@368: nkeynes@380: #define load_spreg( x86reg, regoff ) MOV_sh4r_r32( regoff, x86reg ) nkeynes@380: #define store_spreg( x86reg, regoff ) MOV_r32_sh4r( x86reg, regoff ) nkeynes@359: /** nkeynes@359: * Emit an instruction to load an immediate value into a register nkeynes@359: */ nkeynes@359: static inline void load_imm32( int x86reg, uint32_t value ) { nkeynes@359: /* mov #value, reg */ nkeynes@359: OP(0xB8 + x86reg); nkeynes@359: OP32(value); nkeynes@359: } nkeynes@359: nkeynes@359: /** nkeynes@527: * Load an immediate 64-bit quantity (note: x86-64 only) nkeynes@527: */ nkeynes@800: static inline void load_imm64( int x86reg, uint64_t value ) { nkeynes@527: /* mov #value, reg */ nkeynes@527: REXW(); nkeynes@527: OP(0xB8 + x86reg); nkeynes@527: OP64(value); nkeynes@527: } nkeynes@527: nkeynes@527: /** nkeynes@359: * Emit an instruction to store an SH4 reg (RN) nkeynes@359: */ nkeynes@359: void static inline store_reg( int x86reg, int sh4reg ) { nkeynes@359: /* mov reg, [bp+n] */ nkeynes@361: OP(0x89); nkeynes@361: OP(0x45 + (x86reg<<3)); nkeynes@359: OP(REG_OFFSET(r[sh4reg])); nkeynes@359: } nkeynes@374: nkeynes@375: /** nkeynes@375: * Load an FR register (single-precision floating point) into an integer x86 nkeynes@375: * register (eg for register-to-register moves) nkeynes@375: */ nkeynes@669: #define load_fr(reg,frm) OP(0x8B); MODRM_r32_ebp32(reg, REG_OFFSET(fr[0][(frm)^1]) ) nkeynes@669: #define load_xf(reg,frm) OP(0x8B); MODRM_r32_ebp32(reg, REG_OFFSET(fr[1][(frm)^1]) ) nkeynes@375: nkeynes@375: /** nkeynes@669: * Load the low half of a DR register (DR or XD) into an integer x86 register nkeynes@669: */ nkeynes@669: #define load_dr0(reg,frm) OP(0x8B); MODRM_r32_ebp32(reg, REG_OFFSET(fr[frm&1][frm|0x01]) ) nkeynes@669: #define load_dr1(reg,frm) OP(0x8B); MODRM_r32_ebp32(reg, REG_OFFSET(fr[frm&1][frm&0x0E]) ) nkeynes@669: nkeynes@669: /** nkeynes@669: * Store an FR register (single-precision floating point) from an integer x86+ nkeynes@375: * register (eg for register-to-register moves) nkeynes@375: */ nkeynes@669: #define store_fr(reg,frm) OP(0x89); MODRM_r32_ebp32( reg, REG_OFFSET(fr[0][(frm)^1]) ) nkeynes@669: #define store_xf(reg,frm) OP(0x89); MODRM_r32_ebp32( reg, REG_OFFSET(fr[1][(frm)^1]) ) nkeynes@375: nkeynes@669: #define store_dr0(reg,frm) OP(0x89); MODRM_r32_ebp32( reg, REG_OFFSET(fr[frm&1][frm|0x01]) ) nkeynes@669: #define store_dr1(reg,frm) OP(0x89); MODRM_r32_ebp32( reg, REG_OFFSET(fr[frm&1][frm&0x0E]) ) nkeynes@375: nkeynes@374: nkeynes@669: #define push_fpul() FLDF_sh4r(R_FPUL) nkeynes@669: #define pop_fpul() FSTPF_sh4r(R_FPUL) nkeynes@669: #define push_fr(frm) FLDF_sh4r( REG_OFFSET(fr[0][(frm)^1]) ) nkeynes@669: #define pop_fr(frm) FSTPF_sh4r( REG_OFFSET(fr[0][(frm)^1]) ) nkeynes@669: #define push_xf(frm) FLDF_sh4r( REG_OFFSET(fr[1][(frm)^1]) ) nkeynes@669: #define pop_xf(frm) FSTPF_sh4r( REG_OFFSET(fr[1][(frm)^1]) ) nkeynes@669: #define push_dr(frm) FLDD_sh4r( REG_OFFSET(fr[0][(frm)&0x0E]) ) nkeynes@669: #define pop_dr(frm) FSTPD_sh4r( REG_OFFSET(fr[0][(frm)&0x0E]) ) nkeynes@669: #define push_xdr(frm) FLDD_sh4r( REG_OFFSET(fr[1][(frm)&0x0E]) ) nkeynes@669: #define pop_xdr(frm) FSTPD_sh4r( REG_OFFSET(fr[1][(frm)&0x0E]) ) nkeynes@377: nkeynes@377: nkeynes@374: nkeynes@368: /* Exception checks - Note that all exception checks will clobber EAX */ nkeynes@416: nkeynes@416: #define check_priv( ) \ nkeynes@416: if( !sh4_x86.priv_checked ) { \ nkeynes@416: sh4_x86.priv_checked = TRUE;\ nkeynes@416: load_spreg( R_EAX, R_SR );\ nkeynes@416: AND_imm32_r32( SR_MD, R_EAX );\ nkeynes@416: if( sh4_x86.in_delay_slot ) {\ nkeynes@586: JE_exc( EXC_SLOT_ILLEGAL );\ nkeynes@416: } else {\ nkeynes@586: JE_exc( EXC_ILLEGAL );\ nkeynes@416: }\ nkeynes@875: sh4_x86.tstate = TSTATE_NONE; \ nkeynes@416: }\ nkeynes@416: nkeynes@416: #define check_fpuen( ) \ nkeynes@416: if( !sh4_x86.fpuen_checked ) {\ nkeynes@416: sh4_x86.fpuen_checked = TRUE;\ nkeynes@416: load_spreg( R_EAX, R_SR );\ nkeynes@416: AND_imm32_r32( SR_FD, R_EAX );\ nkeynes@416: if( sh4_x86.in_delay_slot ) {\ nkeynes@586: JNE_exc(EXC_SLOT_FPU_DISABLED);\ nkeynes@416: } else {\ nkeynes@586: JNE_exc(EXC_FPU_DISABLED);\ nkeynes@416: }\ nkeynes@875: sh4_x86.tstate = TSTATE_NONE; \ nkeynes@416: } nkeynes@416: nkeynes@586: #define check_ralign16( x86reg ) \ nkeynes@586: TEST_imm32_r32( 0x00000001, x86reg ); \ nkeynes@586: JNE_exc(EXC_DATA_ADDR_READ) nkeynes@416: nkeynes@586: #define check_walign16( x86reg ) \ nkeynes@586: TEST_imm32_r32( 0x00000001, x86reg ); \ nkeynes@586: JNE_exc(EXC_DATA_ADDR_WRITE); nkeynes@368: nkeynes@586: #define check_ralign32( x86reg ) \ nkeynes@586: TEST_imm32_r32( 0x00000003, x86reg ); \ nkeynes@586: JNE_exc(EXC_DATA_ADDR_READ) nkeynes@368: nkeynes@586: #define check_walign32( x86reg ) \ nkeynes@586: TEST_imm32_r32( 0x00000003, x86reg ); \ nkeynes@586: JNE_exc(EXC_DATA_ADDR_WRITE); nkeynes@368: nkeynes@732: #define check_ralign64( x86reg ) \ nkeynes@732: TEST_imm32_r32( 0x00000007, x86reg ); \ nkeynes@732: JNE_exc(EXC_DATA_ADDR_READ) nkeynes@732: nkeynes@732: #define check_walign64( x86reg ) \ nkeynes@732: TEST_imm32_r32( 0x00000007, x86reg ); \ nkeynes@732: JNE_exc(EXC_DATA_ADDR_WRITE); nkeynes@732: nkeynes@824: #define UNDEF(ir) nkeynes@361: #define MEM_RESULT(value_reg) if(value_reg != R_EAX) { MOV_r32_r32(R_EAX,value_reg); } nkeynes@361: #define MEM_READ_BYTE( addr_reg, value_reg ) call_func1(sh4_read_byte, addr_reg ); MEM_RESULT(value_reg) nkeynes@361: #define MEM_READ_WORD( addr_reg, value_reg ) call_func1(sh4_read_word, addr_reg ); MEM_RESULT(value_reg) nkeynes@361: #define MEM_READ_LONG( addr_reg, value_reg ) call_func1(sh4_read_long, addr_reg ); MEM_RESULT(value_reg) nkeynes@361: #define MEM_WRITE_BYTE( addr_reg, value_reg ) call_func2(sh4_write_byte, addr_reg, value_reg) nkeynes@361: #define MEM_WRITE_WORD( addr_reg, value_reg ) call_func2(sh4_write_word, addr_reg, value_reg) nkeynes@361: #define MEM_WRITE_LONG( addr_reg, value_reg ) call_func2(sh4_write_long, addr_reg, value_reg) nkeynes@361: nkeynes@586: /** nkeynes@586: * Perform MMU translation on the address in addr_reg for a read operation, iff the TLB is turned nkeynes@586: * on, otherwise do nothing. Clobbers EAX, ECX and EDX. May raise a TLB exception or address error. nkeynes@586: */ nkeynes@586: #define MMU_TRANSLATE_READ( addr_reg ) if( sh4_x86.tlb_on ) { call_func1(mmu_vma_to_phys_read, addr_reg); CMP_imm32_r32(MMU_VMA_ERROR, R_EAX); JE_exc(-1); MEM_RESULT(addr_reg); } nkeynes@596: nkeynes@596: #define MMU_TRANSLATE_READ_EXC( addr_reg, exc_code ) if( sh4_x86.tlb_on ) { call_func1(mmu_vma_to_phys_read, addr_reg); CMP_imm32_r32(MMU_VMA_ERROR, R_EAX); JE_exc(exc_code); MEM_RESULT(addr_reg) } nkeynes@586: /** nkeynes@586: * Perform MMU translation on the address in addr_reg for a write operation, iff the TLB is turned nkeynes@586: * on, otherwise do nothing. Clobbers EAX, ECX and EDX. May raise a TLB exception or address error. nkeynes@586: */ nkeynes@586: #define MMU_TRANSLATE_WRITE( addr_reg ) if( sh4_x86.tlb_on ) { call_func1(mmu_vma_to_phys_write, addr_reg); CMP_imm32_r32(MMU_VMA_ERROR, R_EAX); JE_exc(-1); MEM_RESULT(addr_reg); } nkeynes@368: nkeynes@586: #define MEM_READ_SIZE (CALL_FUNC1_SIZE) nkeynes@586: #define MEM_WRITE_SIZE (CALL_FUNC2_SIZE) nkeynes@586: #define MMU_TRANSLATE_SIZE (sh4_x86.tlb_on ? (CALL_FUNC1_SIZE + 12) : 0 ) nkeynes@586: nkeynes@590: #define SLOTILLEGAL() JMP_exc(EXC_SLOT_ILLEGAL); sh4_x86.in_delay_slot = DELAY_NONE; return 1; nkeynes@388: nkeynes@539: /****** Import appropriate calling conventions ******/ nkeynes@675: #if SIZEOF_VOID_P == 8 nkeynes@539: #include "sh4/ia64abi.h" nkeynes@675: #else /* 32-bit system */ nkeynes@539: #ifdef APPLE_BUILD nkeynes@539: #include "sh4/ia32mac.h" nkeynes@539: #else nkeynes@539: #include "sh4/ia32abi.h" nkeynes@539: #endif nkeynes@539: #endif nkeynes@539: nkeynes@593: uint32_t sh4_translate_end_block_size() nkeynes@593: { nkeynes@596: if( sh4_x86.backpatch_posn <= 3 ) { nkeynes@596: return EPILOGUE_SIZE + (sh4_x86.backpatch_posn*12); nkeynes@596: } else { nkeynes@596: return EPILOGUE_SIZE + 48 + (sh4_x86.backpatch_posn-3)*15; nkeynes@596: } nkeynes@593: } nkeynes@593: nkeynes@593: nkeynes@590: /** nkeynes@590: * Embed a breakpoint into the generated code nkeynes@590: */ nkeynes@586: void sh4_translate_emit_breakpoint( sh4vma_t pc ) nkeynes@586: { nkeynes@591: load_imm32( R_EAX, pc ); nkeynes@591: call_func1( sh4_translate_breakpoint_hit, R_EAX ); nkeynes@875: sh4_x86.tstate = TSTATE_NONE; nkeynes@586: } nkeynes@590: nkeynes@601: nkeynes@601: #define UNTRANSLATABLE(pc) !IS_IN_ICACHE(pc) nkeynes@601: nkeynes@590: /** nkeynes@590: * Embed a call to sh4_execute_instruction for situations that we nkeynes@601: * can't translate (just page-crossing delay slots at the moment). nkeynes@601: * Caller is responsible for setting new_pc before calling this function. nkeynes@601: * nkeynes@601: * Performs: nkeynes@601: * Set PC = endpc nkeynes@601: * Set sh4r.in_delay_slot = sh4_x86.in_delay_slot nkeynes@601: * Update slice_cycle for endpc+2 (single step doesn't update slice_cycle) nkeynes@601: * Call sh4_execute_instruction nkeynes@601: * Call xlat_get_code_by_vma / xlat_get_code as for normal exit nkeynes@590: */ nkeynes@601: void exit_block_emu( sh4vma_t endpc ) nkeynes@590: { nkeynes@590: load_imm32( R_ECX, endpc - sh4_x86.block_start_pc ); // 5 nkeynes@590: ADD_r32_sh4r( R_ECX, R_PC ); nkeynes@586: nkeynes@601: load_imm32( R_ECX, (((endpc - sh4_x86.block_start_pc)>>1)+1)*sh4_cpu_period ); // 5 nkeynes@590: ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6 nkeynes@590: load_imm32( R_ECX, sh4_x86.in_delay_slot ? 1 : 0 ); nkeynes@590: store_spreg( R_ECX, REG_OFFSET(in_delay_slot) ); nkeynes@590: nkeynes@590: call_func0( sh4_execute_instruction ); nkeynes@601: load_spreg( R_EAX, R_PC ); nkeynes@590: if( sh4_x86.tlb_on ) { nkeynes@590: call_func1(xlat_get_code_by_vma,R_EAX); nkeynes@590: } else { nkeynes@590: call_func1(xlat_get_code,R_EAX); nkeynes@590: } nkeynes@601: AND_imm8s_rptr( 0xFC, R_EAX ); nkeynes@590: POP_r32(R_EBP); nkeynes@590: RET(); nkeynes@590: } nkeynes@539: nkeynes@359: /** nkeynes@359: * Translate a single instruction. Delayed branches are handled specially nkeynes@359: * by translating both branch and delayed instruction as a single unit (as nkeynes@359: * nkeynes@586: * The instruction MUST be in the icache (assert check) nkeynes@359: * nkeynes@359: * @return true if the instruction marks the end of a basic block nkeynes@359: * (eg a branch or nkeynes@359: */ nkeynes@590: uint32_t sh4_translate_instruction( sh4vma_t pc ) nkeynes@359: { nkeynes@388: uint32_t ir; nkeynes@586: /* Read instruction from icache */ nkeynes@586: assert( IS_IN_ICACHE(pc) ); nkeynes@586: ir = *(uint16_t *)GET_ICACHE_PTR(pc); nkeynes@586: nkeynes@586: /* PC is not in the current icache - this usually means we're running nkeynes@586: * with MMU on, and we've gone past the end of the page. And since nkeynes@586: * sh4_translate_block is pretty careful about this, it means we're nkeynes@586: * almost certainly in a delay slot. nkeynes@586: * nkeynes@586: * Since we can't assume the page is present (and we can't fault it in nkeynes@586: * at this point, inline a call to sh4_execute_instruction (with a few nkeynes@586: * small repairs to cope with the different environment). nkeynes@586: */ nkeynes@586: nkeynes@586: if( !sh4_x86.in_delay_slot ) { nkeynes@596: sh4_translate_add_recovery( (pc - sh4_x86.block_start_pc)>>1 ); nkeynes@388: } nkeynes@359: %% nkeynes@359: /* ALU operations */ nkeynes@359: ADD Rm, Rn {: nkeynes@671: COUNT_INST(I_ADD); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: ADD_r32_r32( R_EAX, R_ECX ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: ADD #imm, Rn {: nkeynes@671: COUNT_INST(I_ADDI); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: ADD_imm8s_r32( imm, R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: ADDC Rm, Rn {: nkeynes@671: COUNT_INST(I_ADDC); nkeynes@417: if( sh4_x86.tstate != TSTATE_C ) { nkeynes@417: LDC_t(); nkeynes@417: } nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: ADC_r32_r32( R_EAX, R_ECX ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: SETC_t(); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: :} nkeynes@359: ADDV Rm, Rn {: nkeynes@671: COUNT_INST(I_ADDV); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: ADD_r32_r32( R_EAX, R_ECX ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: SETO_t(); nkeynes@417: sh4_x86.tstate = TSTATE_O; nkeynes@359: :} nkeynes@359: AND Rm, Rn {: nkeynes@671: COUNT_INST(I_AND); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: AND_r32_r32( R_EAX, R_ECX ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: AND #imm, R0 {: nkeynes@671: COUNT_INST(I_ANDI); nkeynes@359: load_reg( R_EAX, 0 ); nkeynes@359: AND_imm32_r32(imm, R_EAX); nkeynes@359: store_reg( R_EAX, 0 ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: AND.B #imm, @(R0, GBR) {: nkeynes@671: COUNT_INST(I_ANDB); nkeynes@359: load_reg( R_EAX, 0 ); nkeynes@359: load_spreg( R_ECX, R_GBR ); nkeynes@586: ADD_r32_r32( R_ECX, R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: PUSH_realigned_r32(R_EAX); nkeynes@586: MEM_READ_BYTE( R_EAX, R_EAX ); nkeynes@547: POP_realigned_r32(R_ECX); nkeynes@386: AND_imm32_r32(imm, R_EAX ); nkeynes@359: MEM_WRITE_BYTE( R_ECX, R_EAX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: CMP/EQ Rm, Rn {: nkeynes@671: COUNT_INST(I_CMPEQ); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: CMP_r32_r32( R_EAX, R_ECX ); nkeynes@359: SETE_t(); nkeynes@417: sh4_x86.tstate = TSTATE_E; nkeynes@359: :} nkeynes@359: CMP/EQ #imm, R0 {: nkeynes@671: COUNT_INST(I_CMPEQI); nkeynes@359: load_reg( R_EAX, 0 ); nkeynes@359: CMP_imm8s_r32(imm, R_EAX); nkeynes@359: SETE_t(); nkeynes@417: sh4_x86.tstate = TSTATE_E; nkeynes@359: :} nkeynes@359: CMP/GE Rm, Rn {: nkeynes@671: COUNT_INST(I_CMPGE); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: CMP_r32_r32( R_EAX, R_ECX ); nkeynes@359: SETGE_t(); nkeynes@417: sh4_x86.tstate = TSTATE_GE; nkeynes@359: :} nkeynes@359: CMP/GT Rm, Rn {: nkeynes@671: COUNT_INST(I_CMPGT); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: CMP_r32_r32( R_EAX, R_ECX ); nkeynes@359: SETG_t(); nkeynes@417: sh4_x86.tstate = TSTATE_G; nkeynes@359: :} nkeynes@359: CMP/HI Rm, Rn {: nkeynes@671: COUNT_INST(I_CMPHI); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: CMP_r32_r32( R_EAX, R_ECX ); nkeynes@359: SETA_t(); nkeynes@417: sh4_x86.tstate = TSTATE_A; nkeynes@359: :} nkeynes@359: CMP/HS Rm, Rn {: nkeynes@671: COUNT_INST(I_CMPHS); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: CMP_r32_r32( R_EAX, R_ECX ); nkeynes@359: SETAE_t(); nkeynes@417: sh4_x86.tstate = TSTATE_AE; nkeynes@359: :} nkeynes@359: CMP/PL Rn {: nkeynes@671: COUNT_INST(I_CMPPL); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: CMP_imm8s_r32( 0, R_EAX ); nkeynes@359: SETG_t(); nkeynes@417: sh4_x86.tstate = TSTATE_G; nkeynes@359: :} nkeynes@359: CMP/PZ Rn {: nkeynes@671: COUNT_INST(I_CMPPZ); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: CMP_imm8s_r32( 0, R_EAX ); nkeynes@359: SETGE_t(); nkeynes@417: sh4_x86.tstate = TSTATE_GE; nkeynes@359: :} nkeynes@361: CMP/STR Rm, Rn {: nkeynes@671: COUNT_INST(I_CMPSTR); nkeynes@368: load_reg( R_EAX, Rm ); nkeynes@368: load_reg( R_ECX, Rn ); nkeynes@368: XOR_r32_r32( R_ECX, R_EAX ); nkeynes@368: TEST_r8_r8( R_AL, R_AL ); nkeynes@669: JE_rel8(target1); nkeynes@669: TEST_r8_r8( R_AH, R_AH ); nkeynes@669: JE_rel8(target2); nkeynes@669: SHR_imm8_r32( 16, R_EAX ); nkeynes@669: TEST_r8_r8( R_AL, R_AL ); nkeynes@669: JE_rel8(target3); nkeynes@669: TEST_r8_r8( R_AH, R_AH ); nkeynes@380: JMP_TARGET(target1); nkeynes@380: JMP_TARGET(target2); nkeynes@380: JMP_TARGET(target3); nkeynes@368: SETE_t(); nkeynes@417: sh4_x86.tstate = TSTATE_E; nkeynes@361: :} nkeynes@361: DIV0S Rm, Rn {: nkeynes@671: COUNT_INST(I_DIV0S); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@386: load_reg( R_ECX, Rn ); nkeynes@361: SHR_imm8_r32( 31, R_EAX ); nkeynes@361: SHR_imm8_r32( 31, R_ECX ); nkeynes@361: store_spreg( R_EAX, R_M ); nkeynes@361: store_spreg( R_ECX, R_Q ); nkeynes@361: CMP_r32_r32( R_EAX, R_ECX ); nkeynes@386: SETNE_t(); nkeynes@417: sh4_x86.tstate = TSTATE_NE; nkeynes@361: :} nkeynes@361: DIV0U {: nkeynes@671: COUNT_INST(I_DIV0U); nkeynes@361: XOR_r32_r32( R_EAX, R_EAX ); nkeynes@361: store_spreg( R_EAX, R_Q ); nkeynes@361: store_spreg( R_EAX, R_M ); nkeynes@361: store_spreg( R_EAX, R_T ); nkeynes@417: sh4_x86.tstate = TSTATE_C; // works for DIV1 nkeynes@361: :} nkeynes@386: DIV1 Rm, Rn {: nkeynes@671: COUNT_INST(I_DIV1); nkeynes@386: load_spreg( R_ECX, R_M ); nkeynes@386: load_reg( R_EAX, Rn ); nkeynes@417: if( sh4_x86.tstate != TSTATE_C ) { nkeynes@417: LDC_t(); nkeynes@417: } nkeynes@386: RCL1_r32( R_EAX ); nkeynes@386: SETC_r8( R_DL ); // Q' nkeynes@386: CMP_sh4r_r32( R_Q, R_ECX ); nkeynes@669: JE_rel8(mqequal); nkeynes@386: ADD_sh4r_r32( REG_OFFSET(r[Rm]), R_EAX ); nkeynes@669: JMP_rel8(end); nkeynes@380: JMP_TARGET(mqequal); nkeynes@386: SUB_sh4r_r32( REG_OFFSET(r[Rm]), R_EAX ); nkeynes@386: JMP_TARGET(end); nkeynes@386: store_reg( R_EAX, Rn ); // Done with Rn now nkeynes@386: SETC_r8(R_AL); // tmp1 nkeynes@386: XOR_r8_r8( R_DL, R_AL ); // Q' = Q ^ tmp1 nkeynes@386: XOR_r8_r8( R_AL, R_CL ); // Q'' = Q' ^ M nkeynes@386: store_spreg( R_ECX, R_Q ); nkeynes@386: XOR_imm8s_r32( 1, R_AL ); // T = !Q' nkeynes@386: MOVZX_r8_r32( R_AL, R_EAX ); nkeynes@386: store_spreg( R_EAX, R_T ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@374: :} nkeynes@361: DMULS.L Rm, Rn {: nkeynes@671: COUNT_INST(I_DMULS); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@361: IMUL_r32(R_ECX); nkeynes@361: store_spreg( R_EDX, R_MACH ); nkeynes@361: store_spreg( R_EAX, R_MACL ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@361: :} nkeynes@361: DMULU.L Rm, Rn {: nkeynes@671: COUNT_INST(I_DMULU); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@361: MUL_r32(R_ECX); nkeynes@361: store_spreg( R_EDX, R_MACH ); nkeynes@361: store_spreg( R_EAX, R_MACL ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@361: :} nkeynes@359: DT Rn {: nkeynes@671: COUNT_INST(I_DT); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@382: ADD_imm8s_r32( -1, R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: SETE_t(); nkeynes@417: sh4_x86.tstate = TSTATE_E; nkeynes@359: :} nkeynes@359: EXTS.B Rm, Rn {: nkeynes@671: COUNT_INST(I_EXTSB); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: MOVSX_r8_r32( R_EAX, R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@361: EXTS.W Rm, Rn {: nkeynes@671: COUNT_INST(I_EXTSW); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: MOVSX_r16_r32( R_EAX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); nkeynes@361: :} nkeynes@361: EXTU.B Rm, Rn {: nkeynes@671: COUNT_INST(I_EXTUB); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: MOVZX_r8_r32( R_EAX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); nkeynes@361: :} nkeynes@361: EXTU.W Rm, Rn {: nkeynes@671: COUNT_INST(I_EXTUW); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: MOVZX_r16_r32( R_EAX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); nkeynes@361: :} nkeynes@586: MAC.L @Rm+, @Rn+ {: nkeynes@671: COUNT_INST(I_MACL); nkeynes@586: if( Rm == Rn ) { nkeynes@586: load_reg( R_EAX, Rm ); nkeynes@586: check_ralign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: PUSH_realigned_r32( R_EAX ); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: ADD_imm8s_r32( 4, R_EAX ); nkeynes@596: MMU_TRANSLATE_READ_EXC( R_EAX, -5 ); nkeynes@586: ADD_imm8s_sh4r( 8, REG_OFFSET(r[Rn]) ); nkeynes@586: // Note translate twice in case of page boundaries. Maybe worth nkeynes@586: // adding a page-boundary check to skip the second translation nkeynes@586: } else { nkeynes@586: load_reg( R_EAX, Rm ); nkeynes@586: check_ralign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@596: load_reg( R_ECX, Rn ); nkeynes@596: check_ralign32( R_ECX ); nkeynes@586: PUSH_realigned_r32( R_EAX ); nkeynes@596: MMU_TRANSLATE_READ_EXC( R_ECX, -5 ); nkeynes@596: MOV_r32_r32( R_ECX, R_EAX ); nkeynes@586: ADD_imm8s_sh4r( 4, REG_OFFSET(r[Rn]) ); nkeynes@586: ADD_imm8s_sh4r( 4, REG_OFFSET(r[Rm]) ); nkeynes@586: } nkeynes@586: MEM_READ_LONG( R_EAX, R_EAX ); nkeynes@586: POP_r32( R_ECX ); nkeynes@586: PUSH_r32( R_EAX ); nkeynes@386: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@547: POP_realigned_r32( R_ECX ); nkeynes@586: nkeynes@386: IMUL_r32( R_ECX ); nkeynes@386: ADD_r32_sh4r( R_EAX, R_MACL ); nkeynes@386: ADC_r32_sh4r( R_EDX, R_MACH ); nkeynes@386: nkeynes@386: load_spreg( R_ECX, R_S ); nkeynes@386: TEST_r32_r32(R_ECX, R_ECX); nkeynes@669: JE_rel8( nosat ); nkeynes@386: call_func0( signsat48 ); nkeynes@386: JMP_TARGET( nosat ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@386: :} nkeynes@386: MAC.W @Rm+, @Rn+ {: nkeynes@671: COUNT_INST(I_MACW); nkeynes@586: if( Rm == Rn ) { nkeynes@586: load_reg( R_EAX, Rm ); nkeynes@586: check_ralign16( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: PUSH_realigned_r32( R_EAX ); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: ADD_imm8s_r32( 2, R_EAX ); nkeynes@596: MMU_TRANSLATE_READ_EXC( R_EAX, -5 ); nkeynes@586: ADD_imm8s_sh4r( 4, REG_OFFSET(r[Rn]) ); nkeynes@586: // Note translate twice in case of page boundaries. Maybe worth nkeynes@586: // adding a page-boundary check to skip the second translation nkeynes@586: } else { nkeynes@586: load_reg( R_EAX, Rm ); nkeynes@586: check_ralign16( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@596: load_reg( R_ECX, Rn ); nkeynes@596: check_ralign16( R_ECX ); nkeynes@586: PUSH_realigned_r32( R_EAX ); nkeynes@596: MMU_TRANSLATE_READ_EXC( R_ECX, -5 ); nkeynes@596: MOV_r32_r32( R_ECX, R_EAX ); nkeynes@586: ADD_imm8s_sh4r( 2, REG_OFFSET(r[Rn]) ); nkeynes@586: ADD_imm8s_sh4r( 2, REG_OFFSET(r[Rm]) ); nkeynes@586: } nkeynes@586: MEM_READ_WORD( R_EAX, R_EAX ); nkeynes@586: POP_r32( R_ECX ); nkeynes@586: PUSH_r32( R_EAX ); nkeynes@386: MEM_READ_WORD( R_ECX, R_EAX ); nkeynes@547: POP_realigned_r32( R_ECX ); nkeynes@386: IMUL_r32( R_ECX ); nkeynes@386: nkeynes@386: load_spreg( R_ECX, R_S ); nkeynes@386: TEST_r32_r32( R_ECX, R_ECX ); nkeynes@669: JE_rel8( nosat ); nkeynes@386: nkeynes@386: ADD_r32_sh4r( R_EAX, R_MACL ); // 6 nkeynes@669: JNO_rel8( end ); // 2 nkeynes@386: load_imm32( R_EDX, 1 ); // 5 nkeynes@386: store_spreg( R_EDX, R_MACH ); // 6 nkeynes@669: JS_rel8( positive ); // 2 nkeynes@386: load_imm32( R_EAX, 0x80000000 );// 5 nkeynes@386: store_spreg( R_EAX, R_MACL ); // 6 nkeynes@669: JMP_rel8(end2); // 2 nkeynes@386: nkeynes@386: JMP_TARGET(positive); nkeynes@386: load_imm32( R_EAX, 0x7FFFFFFF );// 5 nkeynes@386: store_spreg( R_EAX, R_MACL ); // 6 nkeynes@669: JMP_rel8(end3); // 2 nkeynes@386: nkeynes@386: JMP_TARGET(nosat); nkeynes@386: ADD_r32_sh4r( R_EAX, R_MACL ); // 6 nkeynes@386: ADC_r32_sh4r( R_EDX, R_MACH ); // 6 nkeynes@386: JMP_TARGET(end); nkeynes@386: JMP_TARGET(end2); nkeynes@386: JMP_TARGET(end3); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@386: :} nkeynes@359: MOVT Rn {: nkeynes@671: COUNT_INST(I_MOVT); nkeynes@359: load_spreg( R_EAX, R_T ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@361: MUL.L Rm, Rn {: nkeynes@671: COUNT_INST(I_MULL); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@361: MUL_r32( R_ECX ); nkeynes@361: store_spreg( R_EAX, R_MACL ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@361: :} nkeynes@374: MULS.W Rm, Rn {: nkeynes@671: COUNT_INST(I_MULSW); nkeynes@374: load_reg16s( R_EAX, Rm ); nkeynes@374: load_reg16s( R_ECX, Rn ); nkeynes@374: MUL_r32( R_ECX ); nkeynes@374: store_spreg( R_EAX, R_MACL ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@361: :} nkeynes@374: MULU.W Rm, Rn {: nkeynes@671: COUNT_INST(I_MULUW); nkeynes@374: load_reg16u( R_EAX, Rm ); nkeynes@374: load_reg16u( R_ECX, Rn ); nkeynes@374: MUL_r32( R_ECX ); nkeynes@374: store_spreg( R_EAX, R_MACL ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@374: :} nkeynes@359: NEG Rm, Rn {: nkeynes@671: COUNT_INST(I_NEG); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: NEG_r32( R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: NEGC Rm, Rn {: nkeynes@671: COUNT_INST(I_NEGC); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: XOR_r32_r32( R_ECX, R_ECX ); nkeynes@359: LDC_t(); nkeynes@359: SBB_r32_r32( R_EAX, R_ECX ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: SETC_t(); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: :} nkeynes@359: NOT Rm, Rn {: nkeynes@671: COUNT_INST(I_NOT); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: NOT_r32( R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: OR Rm, Rn {: nkeynes@671: COUNT_INST(I_OR); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: OR_r32_r32( R_EAX, R_ECX ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: OR #imm, R0 {: nkeynes@671: COUNT_INST(I_ORI); nkeynes@359: load_reg( R_EAX, 0 ); nkeynes@359: OR_imm32_r32(imm, R_EAX); nkeynes@359: store_reg( R_EAX, 0 ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@374: OR.B #imm, @(R0, GBR) {: nkeynes@671: COUNT_INST(I_ORB); nkeynes@374: load_reg( R_EAX, 0 ); nkeynes@374: load_spreg( R_ECX, R_GBR ); nkeynes@586: ADD_r32_r32( R_ECX, R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: PUSH_realigned_r32(R_EAX); nkeynes@586: MEM_READ_BYTE( R_EAX, R_EAX ); nkeynes@547: POP_realigned_r32(R_ECX); nkeynes@386: OR_imm32_r32(imm, R_EAX ); nkeynes@374: MEM_WRITE_BYTE( R_ECX, R_EAX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@374: :} nkeynes@359: ROTCL Rn {: nkeynes@671: COUNT_INST(I_ROTCL); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@417: if( sh4_x86.tstate != TSTATE_C ) { nkeynes@417: LDC_t(); nkeynes@417: } nkeynes@359: RCL1_r32( R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: SETC_t(); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: :} nkeynes@359: ROTCR Rn {: nkeynes@671: COUNT_INST(I_ROTCR); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@417: if( sh4_x86.tstate != TSTATE_C ) { nkeynes@417: LDC_t(); nkeynes@417: } nkeynes@359: RCR1_r32( R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: SETC_t(); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: :} nkeynes@359: ROTL Rn {: nkeynes@671: COUNT_INST(I_ROTL); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: ROL1_r32( R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: SETC_t(); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: :} nkeynes@359: ROTR Rn {: nkeynes@671: COUNT_INST(I_ROTR); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: ROR1_r32( R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: SETC_t(); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: :} nkeynes@359: SHAD Rm, Rn {: nkeynes@671: COUNT_INST(I_SHAD); nkeynes@359: /* Annoyingly enough, not directly convertible */ nkeynes@361: load_reg( R_EAX, Rn ); nkeynes@361: load_reg( R_ECX, Rm ); nkeynes@361: CMP_imm32_r32( 0, R_ECX ); nkeynes@669: JGE_rel8(doshl); nkeynes@361: nkeynes@361: NEG_r32( R_ECX ); // 2 nkeynes@361: AND_imm8_r8( 0x1F, R_CL ); // 3 nkeynes@669: JE_rel8(emptysar); // 2 nkeynes@361: SAR_r32_CL( R_EAX ); // 2 nkeynes@669: JMP_rel8(end); // 2 nkeynes@386: nkeynes@386: JMP_TARGET(emptysar); nkeynes@386: SAR_imm8_r32(31, R_EAX ); // 3 nkeynes@669: JMP_rel8(end2); nkeynes@382: nkeynes@380: JMP_TARGET(doshl); nkeynes@361: AND_imm8_r8( 0x1F, R_CL ); // 3 nkeynes@361: SHL_r32_CL( R_EAX ); // 2 nkeynes@380: JMP_TARGET(end); nkeynes@386: JMP_TARGET(end2); nkeynes@361: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: SHLD Rm, Rn {: nkeynes@671: COUNT_INST(I_SHLD); nkeynes@368: load_reg( R_EAX, Rn ); nkeynes@368: load_reg( R_ECX, Rm ); nkeynes@382: CMP_imm32_r32( 0, R_ECX ); nkeynes@669: JGE_rel8(doshl); nkeynes@368: nkeynes@382: NEG_r32( R_ECX ); // 2 nkeynes@382: AND_imm8_r8( 0x1F, R_CL ); // 3 nkeynes@669: JE_rel8(emptyshr ); nkeynes@382: SHR_r32_CL( R_EAX ); // 2 nkeynes@669: JMP_rel8(end); // 2 nkeynes@386: nkeynes@386: JMP_TARGET(emptyshr); nkeynes@386: XOR_r32_r32( R_EAX, R_EAX ); nkeynes@669: JMP_rel8(end2); nkeynes@382: nkeynes@382: JMP_TARGET(doshl); nkeynes@382: AND_imm8_r8( 0x1F, R_CL ); // 3 nkeynes@382: SHL_r32_CL( R_EAX ); // 2 nkeynes@382: JMP_TARGET(end); nkeynes@386: JMP_TARGET(end2); nkeynes@368: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: SHAL Rn {: nkeynes@671: COUNT_INST(I_SHAL); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: SHL1_r32( R_EAX ); nkeynes@397: SETC_t(); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: :} nkeynes@359: SHAR Rn {: nkeynes@671: COUNT_INST(I_SHAR); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: SAR1_r32( R_EAX ); nkeynes@397: SETC_t(); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: :} nkeynes@359: SHLL Rn {: nkeynes@671: COUNT_INST(I_SHLL); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: SHL1_r32( R_EAX ); nkeynes@397: SETC_t(); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: :} nkeynes@359: SHLL2 Rn {: nkeynes@671: COUNT_INST(I_SHLL); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: SHL_imm8_r32( 2, R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: SHLL8 Rn {: nkeynes@671: COUNT_INST(I_SHLL); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: SHL_imm8_r32( 8, R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: SHLL16 Rn {: nkeynes@671: COUNT_INST(I_SHLL); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: SHL_imm8_r32( 16, R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: SHLR Rn {: nkeynes@671: COUNT_INST(I_SHLR); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: SHR1_r32( R_EAX ); nkeynes@397: SETC_t(); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: :} nkeynes@359: SHLR2 Rn {: nkeynes@671: COUNT_INST(I_SHLR); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: SHR_imm8_r32( 2, R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: SHLR8 Rn {: nkeynes@671: COUNT_INST(I_SHLR); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: SHR_imm8_r32( 8, R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: SHLR16 Rn {: nkeynes@671: COUNT_INST(I_SHLR); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: SHR_imm8_r32( 16, R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: SUB Rm, Rn {: nkeynes@671: COUNT_INST(I_SUB); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: SUB_r32_r32( R_EAX, R_ECX ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: SUBC Rm, Rn {: nkeynes@671: COUNT_INST(I_SUBC); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@417: if( sh4_x86.tstate != TSTATE_C ) { nkeynes@417: LDC_t(); nkeynes@417: } nkeynes@359: SBB_r32_r32( R_EAX, R_ECX ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@394: SETC_t(); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: :} nkeynes@359: SUBV Rm, Rn {: nkeynes@671: COUNT_INST(I_SUBV); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: SUB_r32_r32( R_EAX, R_ECX ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: SETO_t(); nkeynes@417: sh4_x86.tstate = TSTATE_O; nkeynes@359: :} nkeynes@359: SWAP.B Rm, Rn {: nkeynes@671: COUNT_INST(I_SWAPB); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@601: XCHG_r8_r8( R_AL, R_AH ); // NB: does not touch EFLAGS nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: SWAP.W Rm, Rn {: nkeynes@671: COUNT_INST(I_SWAPB); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@359: SHL_imm8_r32( 16, R_ECX ); nkeynes@359: SHR_imm8_r32( 16, R_EAX ); nkeynes@359: OR_r32_r32( R_EAX, R_ECX ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@361: TAS.B @Rn {: nkeynes@671: COUNT_INST(I_TASB); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: PUSH_realigned_r32( R_EAX ); nkeynes@586: MEM_READ_BYTE( R_EAX, R_EAX ); nkeynes@361: TEST_r8_r8( R_AL, R_AL ); nkeynes@361: SETE_t(); nkeynes@361: OR_imm8_r8( 0x80, R_AL ); nkeynes@586: POP_realigned_r32( R_ECX ); nkeynes@361: MEM_WRITE_BYTE( R_ECX, R_EAX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@361: :} nkeynes@361: TST Rm, Rn {: nkeynes@671: COUNT_INST(I_TST); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@361: TEST_r32_r32( R_EAX, R_ECX ); nkeynes@361: SETE_t(); nkeynes@417: sh4_x86.tstate = TSTATE_E; nkeynes@361: :} nkeynes@368: TST #imm, R0 {: nkeynes@671: COUNT_INST(I_TSTI); nkeynes@368: load_reg( R_EAX, 0 ); nkeynes@368: TEST_imm32_r32( imm, R_EAX ); nkeynes@368: SETE_t(); nkeynes@417: sh4_x86.tstate = TSTATE_E; nkeynes@368: :} nkeynes@368: TST.B #imm, @(R0, GBR) {: nkeynes@671: COUNT_INST(I_TSTB); nkeynes@368: load_reg( R_EAX, 0); nkeynes@368: load_reg( R_ECX, R_GBR); nkeynes@586: ADD_r32_r32( R_ECX, R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: MEM_READ_BYTE( R_EAX, R_EAX ); nkeynes@394: TEST_imm8_r8( imm, R_AL ); nkeynes@368: SETE_t(); nkeynes@417: sh4_x86.tstate = TSTATE_E; nkeynes@368: :} nkeynes@359: XOR Rm, Rn {: nkeynes@671: COUNT_INST(I_XOR); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: XOR_r32_r32( R_EAX, R_ECX ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: XOR #imm, R0 {: nkeynes@671: COUNT_INST(I_XORI); nkeynes@359: load_reg( R_EAX, 0 ); nkeynes@359: XOR_imm32_r32( imm, R_EAX ); nkeynes@359: store_reg( R_EAX, 0 ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: XOR.B #imm, @(R0, GBR) {: nkeynes@671: COUNT_INST(I_XORB); nkeynes@359: load_reg( R_EAX, 0 ); nkeynes@359: load_spreg( R_ECX, R_GBR ); nkeynes@586: ADD_r32_r32( R_ECX, R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: PUSH_realigned_r32(R_EAX); nkeynes@586: MEM_READ_BYTE(R_EAX, R_EAX); nkeynes@547: POP_realigned_r32(R_ECX); nkeynes@359: XOR_imm32_r32( imm, R_EAX ); nkeynes@359: MEM_WRITE_BYTE( R_ECX, R_EAX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@361: XTRCT Rm, Rn {: nkeynes@671: COUNT_INST(I_XTRCT); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@394: load_reg( R_ECX, Rn ); nkeynes@394: SHL_imm8_r32( 16, R_EAX ); nkeynes@394: SHR_imm8_r32( 16, R_ECX ); nkeynes@361: OR_r32_r32( R_EAX, R_ECX ); nkeynes@361: store_reg( R_ECX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: nkeynes@359: /* Data move instructions */ nkeynes@359: MOV Rm, Rn {: nkeynes@671: COUNT_INST(I_MOV); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: MOV #imm, Rn {: nkeynes@671: COUNT_INST(I_MOVI); nkeynes@359: load_imm32( R_EAX, imm ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: MOV.B Rm, @Rn {: nkeynes@671: COUNT_INST(I_MOVB); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: load_reg( R_EDX, Rm ); nkeynes@586: MEM_WRITE_BYTE( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: MOV.B Rm, @-Rn {: nkeynes@671: COUNT_INST(I_MOVB); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: ADD_imm8s_r32( -1, R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: load_reg( R_EDX, Rm ); nkeynes@586: ADD_imm8s_sh4r( -1, REG_OFFSET(r[Rn]) ); nkeynes@586: MEM_WRITE_BYTE( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: MOV.B Rm, @(R0, Rn) {: nkeynes@671: COUNT_INST(I_MOVB); nkeynes@359: load_reg( R_EAX, 0 ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@586: ADD_r32_r32( R_ECX, R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: load_reg( R_EDX, Rm ); nkeynes@586: MEM_WRITE_BYTE( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: MOV.B R0, @(disp, GBR) {: nkeynes@671: COUNT_INST(I_MOVB); nkeynes@586: load_spreg( R_EAX, R_GBR ); nkeynes@586: ADD_imm32_r32( disp, R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: load_reg( R_EDX, 0 ); nkeynes@586: MEM_WRITE_BYTE( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: MOV.B R0, @(disp, Rn) {: nkeynes@671: COUNT_INST(I_MOVB); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: ADD_imm32_r32( disp, R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: load_reg( R_EDX, 0 ); nkeynes@586: MEM_WRITE_BYTE( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: MOV.B @Rm, Rn {: nkeynes@671: COUNT_INST(I_MOVB); nkeynes@586: load_reg( R_EAX, Rm ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: MEM_READ_BYTE( R_EAX, R_EAX ); nkeynes@386: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: MOV.B @Rm+, Rn {: nkeynes@671: COUNT_INST(I_MOVB); nkeynes@586: load_reg( R_EAX, Rm ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: ADD_imm8s_sh4r( 1, REG_OFFSET(r[Rm]) ); nkeynes@586: MEM_READ_BYTE( R_EAX, R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: MOV.B @(R0, Rm), Rn {: nkeynes@671: COUNT_INST(I_MOVB); nkeynes@359: load_reg( R_EAX, 0 ); nkeynes@359: load_reg( R_ECX, Rm ); nkeynes@586: ADD_r32_r32( R_ECX, R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ) nkeynes@586: MEM_READ_BYTE( R_EAX, R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: MOV.B @(disp, GBR), R0 {: nkeynes@671: COUNT_INST(I_MOVB); nkeynes@586: load_spreg( R_EAX, R_GBR ); nkeynes@586: ADD_imm32_r32( disp, R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: MEM_READ_BYTE( R_EAX, R_EAX ); nkeynes@359: store_reg( R_EAX, 0 ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: MOV.B @(disp, Rm), R0 {: nkeynes@671: COUNT_INST(I_MOVB); nkeynes@586: load_reg( R_EAX, Rm ); nkeynes@586: ADD_imm32_r32( disp, R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: MEM_READ_BYTE( R_EAX, R_EAX ); nkeynes@359: store_reg( R_EAX, 0 ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@374: MOV.L Rm, @Rn {: nkeynes@671: COUNT_INST(I_MOVL); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: check_walign32(R_EAX); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: load_reg( R_EDX, Rm ); nkeynes@586: MEM_WRITE_LONG( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@361: :} nkeynes@361: MOV.L Rm, @-Rn {: nkeynes@671: COUNT_INST(I_MOVL); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: ADD_imm8s_r32( -4, R_EAX ); nkeynes@586: check_walign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: load_reg( R_EDX, Rm ); nkeynes@586: ADD_imm8s_sh4r( -4, REG_OFFSET(r[Rn]) ); nkeynes@586: MEM_WRITE_LONG( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@361: :} nkeynes@361: MOV.L Rm, @(R0, Rn) {: nkeynes@671: COUNT_INST(I_MOVL); nkeynes@361: load_reg( R_EAX, 0 ); nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@586: ADD_r32_r32( R_ECX, R_EAX ); nkeynes@586: check_walign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: load_reg( R_EDX, Rm ); nkeynes@586: MEM_WRITE_LONG( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@361: :} nkeynes@361: MOV.L R0, @(disp, GBR) {: nkeynes@671: COUNT_INST(I_MOVL); nkeynes@586: load_spreg( R_EAX, R_GBR ); nkeynes@586: ADD_imm32_r32( disp, R_EAX ); nkeynes@586: check_walign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: load_reg( R_EDX, 0 ); nkeynes@586: MEM_WRITE_LONG( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@361: :} nkeynes@361: MOV.L Rm, @(disp, Rn) {: nkeynes@671: COUNT_INST(I_MOVL); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: ADD_imm32_r32( disp, R_EAX ); nkeynes@586: check_walign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: load_reg( R_EDX, Rm ); nkeynes@586: MEM_WRITE_LONG( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@361: :} nkeynes@361: MOV.L @Rm, Rn {: nkeynes@671: COUNT_INST(I_MOVL); nkeynes@586: load_reg( R_EAX, Rm ); nkeynes@586: check_ralign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: MEM_READ_LONG( R_EAX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@361: :} nkeynes@361: MOV.L @Rm+, Rn {: nkeynes@671: COUNT_INST(I_MOVL); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@382: check_ralign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: ADD_imm8s_sh4r( 4, REG_OFFSET(r[Rm]) ); nkeynes@586: MEM_READ_LONG( R_EAX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@361: :} nkeynes@361: MOV.L @(R0, Rm), Rn {: nkeynes@671: COUNT_INST(I_MOVL); nkeynes@361: load_reg( R_EAX, 0 ); nkeynes@361: load_reg( R_ECX, Rm ); nkeynes@586: ADD_r32_r32( R_ECX, R_EAX ); nkeynes@586: check_ralign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: MEM_READ_LONG( R_EAX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@361: :} nkeynes@361: MOV.L @(disp, GBR), R0 {: nkeynes@671: COUNT_INST(I_MOVL); nkeynes@586: load_spreg( R_EAX, R_GBR ); nkeynes@586: ADD_imm32_r32( disp, R_EAX ); nkeynes@586: check_ralign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: MEM_READ_LONG( R_EAX, R_EAX ); nkeynes@361: store_reg( R_EAX, 0 ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@361: :} nkeynes@361: MOV.L @(disp, PC), Rn {: nkeynes@671: COUNT_INST(I_MOVLPC); nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@388: uint32_t target = (pc & 0xFFFFFFFC) + disp + 4; nkeynes@586: if( IS_IN_ICACHE(target) ) { nkeynes@586: // If the target address is in the same page as the code, it's nkeynes@586: // pretty safe to just ref it directly and circumvent the whole nkeynes@586: // memory subsystem. (this is a big performance win) nkeynes@586: nkeynes@586: // FIXME: There's a corner-case that's not handled here when nkeynes@586: // the current code-page is in the ITLB but not in the UTLB. nkeynes@586: // (should generate a TLB miss although need to test SH4 nkeynes@586: // behaviour to confirm) Unlikely to be anyone depending on this nkeynes@586: // behaviour though. nkeynes@586: sh4ptr_t ptr = GET_ICACHE_PTR(target); nkeynes@527: MOV_moff32_EAX( ptr ); nkeynes@388: } else { nkeynes@586: // Note: we use sh4r.pc for the calc as we could be running at a nkeynes@586: // different virtual address than the translation was done with, nkeynes@586: // but we can safely assume that the low bits are the same. nkeynes@586: load_imm32( R_EAX, (pc-sh4_x86.block_start_pc) + disp + 4 - (pc&0x03) ); nkeynes@586: ADD_sh4r_r32( R_PC, R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: MEM_READ_LONG( R_EAX, R_EAX ); nkeynes@586: sh4_x86.tstate = TSTATE_NONE; nkeynes@388: } nkeynes@382: store_reg( R_EAX, Rn ); nkeynes@374: } nkeynes@361: :} nkeynes@361: MOV.L @(disp, Rm), Rn {: nkeynes@671: COUNT_INST(I_MOVL); nkeynes@586: load_reg( R_EAX, Rm ); nkeynes@586: ADD_imm8s_r32( disp, R_EAX ); nkeynes@586: check_ralign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: MEM_READ_LONG( R_EAX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@361: :} nkeynes@361: MOV.W Rm, @Rn {: nkeynes@671: COUNT_INST(I_MOVW); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: check_walign16( R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ) nkeynes@586: load_reg( R_EDX, Rm ); nkeynes@586: MEM_WRITE_WORD( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@361: :} nkeynes@361: MOV.W Rm, @-Rn {: nkeynes@671: COUNT_INST(I_MOVW); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: ADD_imm8s_r32( -2, R_EAX ); nkeynes@586: check_walign16( R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: load_reg( R_EDX, Rm ); nkeynes@586: ADD_imm8s_sh4r( -2, REG_OFFSET(r[Rn]) ); nkeynes@586: MEM_WRITE_WORD( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@361: :} nkeynes@361: MOV.W Rm, @(R0, Rn) {: nkeynes@671: COUNT_INST(I_MOVW); nkeynes@361: load_reg( R_EAX, 0 ); nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@586: ADD_r32_r32( R_ECX, R_EAX ); nkeynes@586: check_walign16( R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: load_reg( R_EDX, Rm ); nkeynes@586: MEM_WRITE_WORD( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@361: :} nkeynes@361: MOV.W R0, @(disp, GBR) {: nkeynes@671: COUNT_INST(I_MOVW); nkeynes@586: load_spreg( R_EAX, R_GBR ); nkeynes@586: ADD_imm32_r32( disp, R_EAX ); nkeynes@586: check_walign16( R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: load_reg( R_EDX, 0 ); nkeynes@586: MEM_WRITE_WORD( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@361: :} nkeynes@361: MOV.W R0, @(disp, Rn) {: nkeynes@671: COUNT_INST(I_MOVW); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: ADD_imm32_r32( disp, R_EAX ); nkeynes@586: check_walign16( R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: load_reg( R_EDX, 0 ); nkeynes@586: MEM_WRITE_WORD( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@361: :} nkeynes@361: MOV.W @Rm, Rn {: nkeynes@671: COUNT_INST(I_MOVW); nkeynes@586: load_reg( R_EAX, Rm ); nkeynes@586: check_ralign16( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: MEM_READ_WORD( R_EAX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@361: :} nkeynes@361: MOV.W @Rm+, Rn {: nkeynes@671: COUNT_INST(I_MOVW); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@374: check_ralign16( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: ADD_imm8s_sh4r( 2, REG_OFFSET(r[Rm]) ); nkeynes@586: MEM_READ_WORD( R_EAX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@361: :} nkeynes@361: MOV.W @(R0, Rm), Rn {: nkeynes@671: COUNT_INST(I_MOVW); nkeynes@361: load_reg( R_EAX, 0 ); nkeynes@361: load_reg( R_ECX, Rm ); nkeynes@586: ADD_r32_r32( R_ECX, R_EAX ); nkeynes@586: check_ralign16( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: MEM_READ_WORD( R_EAX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@361: :} nkeynes@361: MOV.W @(disp, GBR), R0 {: nkeynes@671: COUNT_INST(I_MOVW); nkeynes@586: load_spreg( R_EAX, R_GBR ); nkeynes@586: ADD_imm32_r32( disp, R_EAX ); nkeynes@586: check_ralign16( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: MEM_READ_WORD( R_EAX, R_EAX ); nkeynes@361: store_reg( R_EAX, 0 ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@361: :} nkeynes@361: MOV.W @(disp, PC), Rn {: nkeynes@671: COUNT_INST(I_MOVW); nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@586: // See comments for MOV.L @(disp, PC), Rn nkeynes@586: uint32_t target = pc + disp + 4; nkeynes@586: if( IS_IN_ICACHE(target) ) { nkeynes@586: sh4ptr_t ptr = GET_ICACHE_PTR(target); nkeynes@586: MOV_moff32_EAX( ptr ); nkeynes@586: MOVSX_r16_r32( R_EAX, R_EAX ); nkeynes@586: } else { nkeynes@586: load_imm32( R_EAX, (pc - sh4_x86.block_start_pc) + disp + 4 ); nkeynes@586: ADD_sh4r_r32( R_PC, R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: MEM_READ_WORD( R_EAX, R_EAX ); nkeynes@586: sh4_x86.tstate = TSTATE_NONE; nkeynes@586: } nkeynes@374: store_reg( R_EAX, Rn ); nkeynes@374: } nkeynes@361: :} nkeynes@361: MOV.W @(disp, Rm), R0 {: nkeynes@671: COUNT_INST(I_MOVW); nkeynes@586: load_reg( R_EAX, Rm ); nkeynes@586: ADD_imm32_r32( disp, R_EAX ); nkeynes@586: check_ralign16( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: MEM_READ_WORD( R_EAX, R_EAX ); nkeynes@361: store_reg( R_EAX, 0 ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@361: :} nkeynes@361: MOVA @(disp, PC), R0 {: nkeynes@671: COUNT_INST(I_MOVA); nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@586: load_imm32( R_ECX, (pc - sh4_x86.block_start_pc) + disp + 4 - (pc&0x03) ); nkeynes@586: ADD_sh4r_r32( R_PC, R_ECX ); nkeynes@374: store_reg( R_ECX, 0 ); nkeynes@586: sh4_x86.tstate = TSTATE_NONE; nkeynes@374: } nkeynes@361: :} nkeynes@361: MOVCA.L R0, @Rn {: nkeynes@671: COUNT_INST(I_MOVCA); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: check_walign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: load_reg( R_EDX, 0 ); nkeynes@586: MEM_WRITE_LONG( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@361: :} nkeynes@359: nkeynes@359: /* Control transfer instructions */ nkeynes@374: BF disp {: nkeynes@671: COUNT_INST(I_BF); nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@586: sh4vma_t target = disp + pc + 4; nkeynes@669: JT_rel8( nottaken ); nkeynes@586: exit_block_rel(target, pc+2 ); nkeynes@380: JMP_TARGET(nottaken); nkeynes@408: return 2; nkeynes@374: } nkeynes@374: :} nkeynes@374: BF/S disp {: nkeynes@671: COUNT_INST(I_BFS); nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@590: sh4_x86.in_delay_slot = DELAY_PC; nkeynes@601: if( UNTRANSLATABLE(pc+2) ) { nkeynes@601: load_imm32( R_EAX, pc + 4 - sh4_x86.block_start_pc ); nkeynes@669: JT_rel8(nottaken); nkeynes@601: ADD_imm32_r32( disp, R_EAX ); nkeynes@601: JMP_TARGET(nottaken); nkeynes@601: ADD_sh4r_r32( R_PC, R_EAX ); nkeynes@601: store_spreg( R_EAX, R_NEW_PC ); nkeynes@601: exit_block_emu(pc+2); nkeynes@601: sh4_x86.branch_taken = TRUE; nkeynes@601: return 2; nkeynes@601: } else { nkeynes@601: if( sh4_x86.tstate == TSTATE_NONE ) { nkeynes@601: CMP_imm8s_sh4r( 1, R_T ); nkeynes@601: sh4_x86.tstate = TSTATE_E; nkeynes@601: } nkeynes@601: sh4vma_t target = disp + pc + 4; nkeynes@601: OP(0x0F); OP(0x80+sh4_x86.tstate); uint32_t *patch = (uint32_t *)xlat_output; OP32(0); // JT rel32 nkeynes@879: int save_tstate = sh4_x86.tstate; nkeynes@601: sh4_translate_instruction(pc+2); nkeynes@601: exit_block_rel( target, pc+4 ); nkeynes@601: nkeynes@601: // not taken nkeynes@601: *patch = (xlat_output - ((uint8_t *)patch)) - 4; nkeynes@879: sh4_x86.tstate = save_tstate; nkeynes@601: sh4_translate_instruction(pc+2); nkeynes@601: return 4; nkeynes@417: } nkeynes@374: } nkeynes@374: :} nkeynes@374: BRA disp {: nkeynes@671: COUNT_INST(I_BRA); nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@590: sh4_x86.in_delay_slot = DELAY_PC; nkeynes@409: sh4_x86.branch_taken = TRUE; nkeynes@601: if( UNTRANSLATABLE(pc+2) ) { nkeynes@601: load_spreg( R_EAX, R_PC ); nkeynes@601: ADD_imm32_r32( pc + disp + 4 - sh4_x86.block_start_pc, R_EAX ); nkeynes@601: store_spreg( R_EAX, R_NEW_PC ); nkeynes@601: exit_block_emu(pc+2); nkeynes@601: return 2; nkeynes@601: } else { nkeynes@601: sh4_translate_instruction( pc + 2 ); nkeynes@601: exit_block_rel( disp + pc + 4, pc+4 ); nkeynes@601: return 4; nkeynes@601: } nkeynes@374: } nkeynes@374: :} nkeynes@374: BRAF Rn {: nkeynes@671: COUNT_INST(I_BRAF); nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@590: load_spreg( R_EAX, R_PC ); nkeynes@590: ADD_imm32_r32( pc + 4 - sh4_x86.block_start_pc, R_EAX ); nkeynes@590: ADD_sh4r_r32( REG_OFFSET(r[Rn]), R_EAX ); nkeynes@590: store_spreg( R_EAX, R_NEW_PC ); nkeynes@590: sh4_x86.in_delay_slot = DELAY_PC; nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@409: sh4_x86.branch_taken = TRUE; nkeynes@601: if( UNTRANSLATABLE(pc+2) ) { nkeynes@601: exit_block_emu(pc+2); nkeynes@601: return 2; nkeynes@601: } else { nkeynes@601: sh4_translate_instruction( pc + 2 ); nkeynes@601: exit_block_newpcset(pc+2); nkeynes@601: return 4; nkeynes@601: } nkeynes@374: } nkeynes@374: :} nkeynes@374: BSR disp {: nkeynes@671: COUNT_INST(I_BSR); nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@590: load_spreg( R_EAX, R_PC ); nkeynes@590: ADD_imm32_r32( pc + 4 - sh4_x86.block_start_pc, R_EAX ); nkeynes@374: store_spreg( R_EAX, R_PR ); nkeynes@590: sh4_x86.in_delay_slot = DELAY_PC; nkeynes@409: sh4_x86.branch_taken = TRUE; nkeynes@601: sh4_x86.tstate = TSTATE_NONE; nkeynes@601: if( UNTRANSLATABLE(pc+2) ) { nkeynes@601: ADD_imm32_r32( disp, R_EAX ); nkeynes@601: store_spreg( R_EAX, R_NEW_PC ); nkeynes@601: exit_block_emu(pc+2); nkeynes@601: return 2; nkeynes@601: } else { nkeynes@601: sh4_translate_instruction( pc + 2 ); nkeynes@601: exit_block_rel( disp + pc + 4, pc+4 ); nkeynes@601: return 4; nkeynes@601: } nkeynes@374: } nkeynes@374: :} nkeynes@374: BSRF Rn {: nkeynes@671: COUNT_INST(I_BSRF); nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@590: load_spreg( R_EAX, R_PC ); nkeynes@590: ADD_imm32_r32( pc + 4 - sh4_x86.block_start_pc, R_EAX ); nkeynes@590: store_spreg( R_EAX, R_PR ); nkeynes@590: ADD_sh4r_r32( REG_OFFSET(r[Rn]), R_EAX ); nkeynes@590: store_spreg( R_EAX, R_NEW_PC ); nkeynes@590: nkeynes@601: sh4_x86.in_delay_slot = DELAY_PC; nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@409: sh4_x86.branch_taken = TRUE; nkeynes@601: if( UNTRANSLATABLE(pc+2) ) { nkeynes@601: exit_block_emu(pc+2); nkeynes@601: return 2; nkeynes@601: } else { nkeynes@601: sh4_translate_instruction( pc + 2 ); nkeynes@601: exit_block_newpcset(pc+2); nkeynes@601: return 4; nkeynes@601: } nkeynes@374: } nkeynes@374: :} nkeynes@374: BT disp {: nkeynes@671: COUNT_INST(I_BT); nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@586: sh4vma_t target = disp + pc + 4; nkeynes@669: JF_rel8( nottaken ); nkeynes@586: exit_block_rel(target, pc+2 ); nkeynes@380: JMP_TARGET(nottaken); nkeynes@408: return 2; nkeynes@374: } nkeynes@374: :} nkeynes@374: BT/S disp {: nkeynes@671: COUNT_INST(I_BTS); nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@590: sh4_x86.in_delay_slot = DELAY_PC; nkeynes@601: if( UNTRANSLATABLE(pc+2) ) { nkeynes@601: load_imm32( R_EAX, pc + 4 - sh4_x86.block_start_pc ); nkeynes@669: JF_rel8(nottaken); nkeynes@601: ADD_imm32_r32( disp, R_EAX ); nkeynes@601: JMP_TARGET(nottaken); nkeynes@601: ADD_sh4r_r32( R_PC, R_EAX ); nkeynes@601: store_spreg( R_EAX, R_NEW_PC ); nkeynes@601: exit_block_emu(pc+2); nkeynes@601: sh4_x86.branch_taken = TRUE; nkeynes@601: return 2; nkeynes@601: } else { nkeynes@601: if( sh4_x86.tstate == TSTATE_NONE ) { nkeynes@601: CMP_imm8s_sh4r( 1, R_T ); nkeynes@601: sh4_x86.tstate = TSTATE_E; nkeynes@601: } nkeynes@601: OP(0x0F); OP(0x80+(sh4_x86.tstate^1)); uint32_t *patch = (uint32_t *)xlat_output; OP32(0); // JF rel32 nkeynes@879: int save_tstate = sh4_x86.tstate; nkeynes@601: sh4_translate_instruction(pc+2); nkeynes@601: exit_block_rel( disp + pc + 4, pc+4 ); nkeynes@601: // not taken nkeynes@601: *patch = (xlat_output - ((uint8_t *)patch)) - 4; nkeynes@879: sh4_x86.tstate = save_tstate; nkeynes@601: sh4_translate_instruction(pc+2); nkeynes@601: return 4; nkeynes@417: } nkeynes@374: } nkeynes@374: :} nkeynes@374: JMP @Rn {: nkeynes@671: COUNT_INST(I_JMP); nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@408: load_reg( R_ECX, Rn ); nkeynes@590: store_spreg( R_ECX, R_NEW_PC ); nkeynes@590: sh4_x86.in_delay_slot = DELAY_PC; nkeynes@409: sh4_x86.branch_taken = TRUE; nkeynes@601: if( UNTRANSLATABLE(pc+2) ) { nkeynes@601: exit_block_emu(pc+2); nkeynes@601: return 2; nkeynes@601: } else { nkeynes@601: sh4_translate_instruction(pc+2); nkeynes@601: exit_block_newpcset(pc+2); nkeynes@601: return 4; nkeynes@601: } nkeynes@374: } nkeynes@374: :} nkeynes@374: JSR @Rn {: nkeynes@671: COUNT_INST(I_JSR); nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@590: load_spreg( R_EAX, R_PC ); nkeynes@590: ADD_imm32_r32( pc + 4 - sh4_x86.block_start_pc, R_EAX ); nkeynes@374: store_spreg( R_EAX, R_PR ); nkeynes@408: load_reg( R_ECX, Rn ); nkeynes@590: store_spreg( R_ECX, R_NEW_PC ); nkeynes@601: sh4_x86.in_delay_slot = DELAY_PC; nkeynes@409: sh4_x86.branch_taken = TRUE; nkeynes@601: sh4_x86.tstate = TSTATE_NONE; nkeynes@601: if( UNTRANSLATABLE(pc+2) ) { nkeynes@601: exit_block_emu(pc+2); nkeynes@601: return 2; nkeynes@601: } else { nkeynes@601: sh4_translate_instruction(pc+2); nkeynes@601: exit_block_newpcset(pc+2); nkeynes@601: return 4; nkeynes@601: } nkeynes@374: } nkeynes@374: :} nkeynes@374: RTE {: nkeynes@671: COUNT_INST(I_RTE); nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@408: check_priv(); nkeynes@408: load_spreg( R_ECX, R_SPC ); nkeynes@590: store_spreg( R_ECX, R_NEW_PC ); nkeynes@374: load_spreg( R_EAX, R_SSR ); nkeynes@374: call_func1( sh4_write_sr, R_EAX ); nkeynes@590: sh4_x86.in_delay_slot = DELAY_PC; nkeynes@377: sh4_x86.priv_checked = FALSE; nkeynes@377: sh4_x86.fpuen_checked = FALSE; nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@409: sh4_x86.branch_taken = TRUE; nkeynes@601: if( UNTRANSLATABLE(pc+2) ) { nkeynes@601: exit_block_emu(pc+2); nkeynes@601: return 2; nkeynes@601: } else { nkeynes@601: sh4_translate_instruction(pc+2); nkeynes@601: exit_block_newpcset(pc+2); nkeynes@601: return 4; nkeynes@601: } nkeynes@374: } nkeynes@374: :} nkeynes@374: RTS {: nkeynes@671: COUNT_INST(I_RTS); nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@408: load_spreg( R_ECX, R_PR ); nkeynes@590: store_spreg( R_ECX, R_NEW_PC ); nkeynes@590: sh4_x86.in_delay_slot = DELAY_PC; nkeynes@409: sh4_x86.branch_taken = TRUE; nkeynes@601: if( UNTRANSLATABLE(pc+2) ) { nkeynes@601: exit_block_emu(pc+2); nkeynes@601: return 2; nkeynes@601: } else { nkeynes@601: sh4_translate_instruction(pc+2); nkeynes@601: exit_block_newpcset(pc+2); nkeynes@601: return 4; nkeynes@601: } nkeynes@374: } nkeynes@374: :} nkeynes@374: TRAPA #imm {: nkeynes@671: COUNT_INST(I_TRAPA); nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@590: load_imm32( R_ECX, pc+2 - sh4_x86.block_start_pc ); // 5 nkeynes@590: ADD_r32_sh4r( R_ECX, R_PC ); nkeynes@527: load_imm32( R_EAX, imm ); nkeynes@527: call_func1( sh4_raise_trap, R_EAX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@408: exit_block_pcset(pc); nkeynes@409: sh4_x86.branch_taken = TRUE; nkeynes@408: return 2; nkeynes@374: } nkeynes@374: :} nkeynes@374: UNDEF {: nkeynes@671: COUNT_INST(I_UNDEF); nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@382: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@586: JMP_exc(EXC_ILLEGAL); nkeynes@408: return 2; nkeynes@374: } nkeynes@368: :} nkeynes@374: nkeynes@374: CLRMAC {: nkeynes@671: COUNT_INST(I_CLRMAC); nkeynes@374: XOR_r32_r32(R_EAX, R_EAX); nkeynes@374: store_spreg( R_EAX, R_MACL ); nkeynes@374: store_spreg( R_EAX, R_MACH ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@368: :} nkeynes@374: CLRS {: nkeynes@671: COUNT_INST(I_CLRS); nkeynes@374: CLC(); nkeynes@374: SETC_sh4r(R_S); nkeynes@872: sh4_x86.tstate = TSTATE_NONE; nkeynes@368: :} nkeynes@374: CLRT {: nkeynes@671: COUNT_INST(I_CLRT); nkeynes@374: CLC(); nkeynes@374: SETC_t(); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: :} nkeynes@374: SETS {: nkeynes@671: COUNT_INST(I_SETS); nkeynes@374: STC(); nkeynes@374: SETC_sh4r(R_S); nkeynes@872: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@374: SETT {: nkeynes@671: COUNT_INST(I_SETT); nkeynes@374: STC(); nkeynes@374: SETC_t(); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@374: :} nkeynes@359: nkeynes@375: /* Floating point moves */ nkeynes@375: FMOV FRm, FRn {: nkeynes@671: COUNT_INST(I_FMOV1); nkeynes@377: check_fpuen(); nkeynes@375: load_spreg( R_ECX, R_FPSCR ); nkeynes@375: TEST_imm32_r32( FPSCR_SZ, R_ECX ); nkeynes@669: JNE_rel8(doublesize); nkeynes@673: load_fr( R_EAX, FRm ); // SZ=0 branch nkeynes@669: store_fr( R_EAX, FRn ); nkeynes@669: JMP_rel8(end); nkeynes@669: JMP_TARGET(doublesize); nkeynes@669: load_dr0( R_EAX, FRm ); nkeynes@669: load_dr1( R_ECX, FRm ); nkeynes@669: store_dr0( R_EAX, FRn ); nkeynes@669: store_dr1( R_ECX, FRn ); nkeynes@669: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@375: :} nkeynes@416: FMOV FRm, @Rn {: nkeynes@671: COUNT_INST(I_FMOV2); nkeynes@586: check_fpuen(); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@416: load_spreg( R_EDX, R_FPSCR ); nkeynes@416: TEST_imm32_r32( FPSCR_SZ, R_EDX ); nkeynes@669: JNE_rel8(doublesize); nkeynes@669: nkeynes@732: check_walign32( R_EAX ); nkeynes@732: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@669: load_fr( R_ECX, FRm ); nkeynes@586: MEM_WRITE_LONG( R_EAX, R_ECX ); // 12 nkeynes@669: JMP_rel8(end); nkeynes@669: nkeynes@669: JMP_TARGET(doublesize); nkeynes@732: check_walign64( R_EAX ); nkeynes@732: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@669: load_dr0( R_ECX, FRm ); nkeynes@669: load_dr1( R_EDX, FRm ); nkeynes@669: MEM_WRITE_DOUBLE( R_EAX, R_ECX, R_EDX ); nkeynes@669: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@375: :} nkeynes@375: FMOV @Rm, FRn {: nkeynes@671: COUNT_INST(I_FMOV5); nkeynes@586: check_fpuen(); nkeynes@586: load_reg( R_EAX, Rm ); nkeynes@416: load_spreg( R_EDX, R_FPSCR ); nkeynes@416: TEST_imm32_r32( FPSCR_SZ, R_EDX ); nkeynes@669: JNE_rel8(doublesize); nkeynes@669: nkeynes@732: check_ralign32( R_EAX ); nkeynes@732: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: MEM_READ_LONG( R_EAX, R_EAX ); nkeynes@669: store_fr( R_EAX, FRn ); nkeynes@669: JMP_rel8(end); nkeynes@669: nkeynes@669: JMP_TARGET(doublesize); nkeynes@732: check_ralign64( R_EAX ); nkeynes@732: MMU_TRANSLATE_READ( R_EAX ); nkeynes@669: MEM_READ_DOUBLE( R_EAX, R_ECX, R_EAX ); nkeynes@669: store_dr0( R_ECX, FRn ); nkeynes@669: store_dr1( R_EAX, FRn ); nkeynes@669: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@375: :} nkeynes@377: FMOV FRm, @-Rn {: nkeynes@671: COUNT_INST(I_FMOV3); nkeynes@586: check_fpuen(); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@416: load_spreg( R_EDX, R_FPSCR ); nkeynes@416: TEST_imm32_r32( FPSCR_SZ, R_EDX ); nkeynes@669: JNE_rel8(doublesize); nkeynes@669: nkeynes@732: check_walign32( R_EAX ); nkeynes@586: ADD_imm8s_r32( -4, R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@669: load_fr( R_ECX, FRm ); nkeynes@586: ADD_imm8s_sh4r(-4,REG_OFFSET(r[Rn])); nkeynes@669: MEM_WRITE_LONG( R_EAX, R_ECX ); nkeynes@669: JMP_rel8(end); nkeynes@669: nkeynes@669: JMP_TARGET(doublesize); nkeynes@732: check_walign64( R_EAX ); nkeynes@669: ADD_imm8s_r32(-8,R_EAX); nkeynes@669: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@669: load_dr0( R_ECX, FRm ); nkeynes@669: load_dr1( R_EDX, FRm ); nkeynes@669: ADD_imm8s_sh4r(-8,REG_OFFSET(r[Rn])); nkeynes@669: MEM_WRITE_DOUBLE( R_EAX, R_ECX, R_EDX ); nkeynes@669: JMP_TARGET(end); nkeynes@669: nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@416: FMOV @Rm+, FRn {: nkeynes@671: COUNT_INST(I_FMOV6); nkeynes@586: check_fpuen(); nkeynes@586: load_reg( R_EAX, Rm ); nkeynes@416: load_spreg( R_EDX, R_FPSCR ); nkeynes@416: TEST_imm32_r32( FPSCR_SZ, R_EDX ); nkeynes@669: JNE_rel8(doublesize); nkeynes@669: nkeynes@732: check_ralign32( R_EAX ); nkeynes@732: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: ADD_imm8s_sh4r( 4, REG_OFFSET(r[Rm]) ); nkeynes@586: MEM_READ_LONG( R_EAX, R_EAX ); nkeynes@669: store_fr( R_EAX, FRn ); nkeynes@669: JMP_rel8(end); nkeynes@669: nkeynes@669: JMP_TARGET(doublesize); nkeynes@732: check_ralign64( R_EAX ); nkeynes@732: MMU_TRANSLATE_READ( R_EAX ); nkeynes@669: ADD_imm8s_sh4r( 8, REG_OFFSET(r[Rm]) ); nkeynes@669: MEM_READ_DOUBLE( R_EAX, R_ECX, R_EAX ); nkeynes@669: store_dr0( R_ECX, FRn ); nkeynes@669: store_dr1( R_EAX, FRn ); nkeynes@669: JMP_TARGET(end); nkeynes@669: nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: FMOV FRm, @(R0, Rn) {: nkeynes@671: COUNT_INST(I_FMOV4); nkeynes@586: check_fpuen(); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: ADD_sh4r_r32( REG_OFFSET(r[0]), R_EAX ); nkeynes@416: load_spreg( R_EDX, R_FPSCR ); nkeynes@416: TEST_imm32_r32( FPSCR_SZ, R_EDX ); nkeynes@669: JNE_rel8(doublesize); nkeynes@669: nkeynes@732: check_walign32( R_EAX ); nkeynes@732: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@669: load_fr( R_ECX, FRm ); nkeynes@586: MEM_WRITE_LONG( R_EAX, R_ECX ); // 12 nkeynes@669: JMP_rel8(end); nkeynes@669: nkeynes@669: JMP_TARGET(doublesize); nkeynes@732: check_walign64( R_EAX ); nkeynes@732: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@669: load_dr0( R_ECX, FRm ); nkeynes@669: load_dr1( R_EDX, FRm ); nkeynes@669: MEM_WRITE_DOUBLE( R_EAX, R_ECX, R_EDX ); nkeynes@669: JMP_TARGET(end); nkeynes@669: nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: FMOV @(R0, Rm), FRn {: nkeynes@671: COUNT_INST(I_FMOV7); nkeynes@586: check_fpuen(); nkeynes@586: load_reg( R_EAX, Rm ); nkeynes@586: ADD_sh4r_r32( REG_OFFSET(r[0]), R_EAX ); nkeynes@416: load_spreg( R_EDX, R_FPSCR ); nkeynes@416: TEST_imm32_r32( FPSCR_SZ, R_EDX ); nkeynes@669: JNE_rel8(doublesize); nkeynes@669: nkeynes@732: check_ralign32( R_EAX ); nkeynes@732: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: MEM_READ_LONG( R_EAX, R_EAX ); nkeynes@669: store_fr( R_EAX, FRn ); nkeynes@669: JMP_rel8(end); nkeynes@669: nkeynes@669: JMP_TARGET(doublesize); nkeynes@732: check_ralign64( R_EAX ); nkeynes@732: MMU_TRANSLATE_READ( R_EAX ); nkeynes@669: MEM_READ_DOUBLE( R_EAX, R_ECX, R_EAX ); nkeynes@669: store_dr0( R_ECX, FRn ); nkeynes@669: store_dr1( R_EAX, FRn ); nkeynes@669: JMP_TARGET(end); nkeynes@669: nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: FLDI0 FRn {: /* IFF PR=0 */ nkeynes@671: COUNT_INST(I_FLDI0); nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@669: JNE_rel8(end); nkeynes@377: XOR_r32_r32( R_EAX, R_EAX ); nkeynes@669: store_fr( R_EAX, FRn ); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: FLDI1 FRn {: /* IFF PR=0 */ nkeynes@671: COUNT_INST(I_FLDI1); nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@669: JNE_rel8(end); nkeynes@377: load_imm32(R_EAX, 0x3F800000); nkeynes@669: store_fr( R_EAX, FRn ); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: nkeynes@377: FLOAT FPUL, FRn {: nkeynes@671: COUNT_INST(I_FLOAT); nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: FILD_sh4r(R_FPUL); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@669: JNE_rel8(doubleprec); nkeynes@669: pop_fr( FRn ); nkeynes@669: JMP_rel8(end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@669: pop_dr( FRn ); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: FTRC FRm, FPUL {: nkeynes@671: COUNT_INST(I_FTRC); nkeynes@377: check_fpuen(); nkeynes@388: load_spreg( R_ECX, R_FPSCR ); nkeynes@388: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@669: JNE_rel8(doubleprec); nkeynes@669: push_fr( FRm ); nkeynes@669: JMP_rel8(doop); nkeynes@388: JMP_TARGET(doubleprec); nkeynes@669: push_dr( FRm ); nkeynes@388: JMP_TARGET( doop ); nkeynes@789: load_ptr( R_ECX, &max_int ); nkeynes@388: FILD_r32ind( R_ECX ); nkeynes@388: FCOMIP_st(1); nkeynes@669: JNA_rel8( sat ); nkeynes@789: load_ptr( R_ECX, &min_int ); // 5 nkeynes@388: FILD_r32ind( R_ECX ); // 2 nkeynes@388: FCOMIP_st(1); // 2 nkeynes@669: JAE_rel8( sat2 ); // 2 nkeynes@789: load_ptr( R_EAX, &save_fcw ); nkeynes@394: FNSTCW_r32ind( R_EAX ); nkeynes@789: load_ptr( R_EDX, &trunc_fcw ); nkeynes@394: FLDCW_r32ind( R_EDX ); nkeynes@388: FISTP_sh4r(R_FPUL); // 3 nkeynes@394: FLDCW_r32ind( R_EAX ); nkeynes@669: JMP_rel8(end); // 2 nkeynes@388: nkeynes@388: JMP_TARGET(sat); nkeynes@388: JMP_TARGET(sat2); nkeynes@388: MOV_r32ind_r32( R_ECX, R_ECX ); // 2 nkeynes@388: store_spreg( R_ECX, R_FPUL ); nkeynes@388: FPOP_st(); nkeynes@388: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: FLDS FRm, FPUL {: nkeynes@671: COUNT_INST(I_FLDS); nkeynes@377: check_fpuen(); nkeynes@669: load_fr( R_EAX, FRm ); nkeynes@377: store_spreg( R_EAX, R_FPUL ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: FSTS FPUL, FRn {: nkeynes@671: COUNT_INST(I_FSTS); nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_EAX, R_FPUL ); nkeynes@669: store_fr( R_EAX, FRn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: FCNVDS FRm, FPUL {: nkeynes@671: COUNT_INST(I_FCNVDS); nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@669: JE_rel8(end); // only when PR=1 nkeynes@669: push_dr( FRm ); nkeynes@377: pop_fpul(); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: FCNVSD FPUL, FRn {: nkeynes@671: COUNT_INST(I_FCNVSD); nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@669: JE_rel8(end); // only when PR=1 nkeynes@377: push_fpul(); nkeynes@669: pop_dr( FRn ); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@375: nkeynes@359: /* Floating point instructions */ nkeynes@374: FABS FRn {: nkeynes@671: COUNT_INST(I_FABS); nkeynes@377: check_fpuen(); nkeynes@374: load_spreg( R_ECX, R_FPSCR ); nkeynes@374: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@669: JNE_rel8(doubleprec); nkeynes@669: push_fr(FRn); // 6 nkeynes@374: FABS_st0(); // 2 nkeynes@669: pop_fr(FRn); //6 nkeynes@669: JMP_rel8(end); // 2 nkeynes@380: JMP_TARGET(doubleprec); nkeynes@669: push_dr(FRn); nkeynes@374: FABS_st0(); nkeynes@669: pop_dr(FRn); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@374: :} nkeynes@377: FADD FRm, FRn {: nkeynes@671: COUNT_INST(I_FADD); nkeynes@377: check_fpuen(); nkeynes@375: load_spreg( R_ECX, R_FPSCR ); nkeynes@375: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@669: JNE_rel8(doubleprec); nkeynes@669: push_fr(FRm); nkeynes@669: push_fr(FRn); nkeynes@377: FADDP_st(1); nkeynes@669: pop_fr(FRn); nkeynes@669: JMP_rel8(end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@669: push_dr(FRm); nkeynes@669: push_dr(FRn); nkeynes@377: FADDP_st(1); nkeynes@669: pop_dr(FRn); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@375: :} nkeynes@377: FDIV FRm, FRn {: nkeynes@671: COUNT_INST(I_FDIV); nkeynes@377: check_fpuen(); nkeynes@375: load_spreg( R_ECX, R_FPSCR ); nkeynes@375: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@669: JNE_rel8(doubleprec); nkeynes@669: push_fr(FRn); nkeynes@669: push_fr(FRm); nkeynes@377: FDIVP_st(1); nkeynes@669: pop_fr(FRn); nkeynes@669: JMP_rel8(end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@669: push_dr(FRn); nkeynes@669: push_dr(FRm); nkeynes@377: FDIVP_st(1); nkeynes@669: pop_dr(FRn); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@375: :} nkeynes@375: FMAC FR0, FRm, FRn {: nkeynes@671: COUNT_INST(I_FMAC); nkeynes@377: check_fpuen(); nkeynes@375: load_spreg( R_ECX, R_FPSCR ); nkeynes@375: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@669: JNE_rel8(doubleprec); nkeynes@669: push_fr( 0 ); nkeynes@669: push_fr( FRm ); nkeynes@375: FMULP_st(1); nkeynes@669: push_fr( FRn ); nkeynes@375: FADDP_st(1); nkeynes@669: pop_fr( FRn ); nkeynes@669: JMP_rel8(end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@669: push_dr( 0 ); nkeynes@669: push_dr( FRm ); nkeynes@375: FMULP_st(1); nkeynes@669: push_dr( FRn ); nkeynes@375: FADDP_st(1); nkeynes@669: pop_dr( FRn ); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@375: :} nkeynes@375: nkeynes@377: FMUL FRm, FRn {: nkeynes@671: COUNT_INST(I_FMUL); nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@669: JNE_rel8(doubleprec); nkeynes@669: push_fr(FRm); nkeynes@669: push_fr(FRn); nkeynes@377: FMULP_st(1); nkeynes@669: pop_fr(FRn); nkeynes@669: JMP_rel8(end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@669: push_dr(FRm); nkeynes@669: push_dr(FRn); nkeynes@377: FMULP_st(1); nkeynes@669: pop_dr(FRn); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: FNEG FRn {: nkeynes@671: COUNT_INST(I_FNEG); nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@669: JNE_rel8(doubleprec); nkeynes@669: push_fr(FRn); nkeynes@377: FCHS_st0(); nkeynes@669: pop_fr(FRn); nkeynes@669: JMP_rel8(end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@669: push_dr(FRn); nkeynes@377: FCHS_st0(); nkeynes@669: pop_dr(FRn); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: FSRRA FRn {: nkeynes@671: COUNT_INST(I_FSRRA); nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@669: JNE_rel8(end); // PR=0 only nkeynes@377: FLD1_st0(); nkeynes@669: push_fr(FRn); nkeynes@377: FSQRT_st0(); nkeynes@377: FDIVP_st(1); nkeynes@669: pop_fr(FRn); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: FSQRT FRn {: nkeynes@671: COUNT_INST(I_FSQRT); nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@669: JNE_rel8(doubleprec); nkeynes@669: push_fr(FRn); nkeynes@377: FSQRT_st0(); nkeynes@669: pop_fr(FRn); nkeynes@669: JMP_rel8(end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@669: push_dr(FRn); nkeynes@377: FSQRT_st0(); nkeynes@669: pop_dr(FRn); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: FSUB FRm, FRn {: nkeynes@671: COUNT_INST(I_FSUB); nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@669: JNE_rel8(doubleprec); nkeynes@669: push_fr(FRn); nkeynes@669: push_fr(FRm); nkeynes@388: FSUBP_st(1); nkeynes@669: pop_fr(FRn); nkeynes@669: JMP_rel8(end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@669: push_dr(FRn); nkeynes@669: push_dr(FRm); nkeynes@388: FSUBP_st(1); nkeynes@669: pop_dr(FRn); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: nkeynes@377: FCMP/EQ FRm, FRn {: nkeynes@671: COUNT_INST(I_FCMPEQ); nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@669: JNE_rel8(doubleprec); nkeynes@669: push_fr(FRm); nkeynes@669: push_fr(FRn); nkeynes@669: JMP_rel8(end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@669: push_dr(FRm); nkeynes@669: push_dr(FRn); nkeynes@382: JMP_TARGET(end); nkeynes@377: FCOMIP_st(1); nkeynes@377: SETE_t(); nkeynes@377: FPOP_st(); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: FCMP/GT FRm, FRn {: nkeynes@671: COUNT_INST(I_FCMPGT); nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@669: JNE_rel8(doubleprec); nkeynes@669: push_fr(FRm); nkeynes@669: push_fr(FRn); nkeynes@669: JMP_rel8(end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@669: push_dr(FRm); nkeynes@669: push_dr(FRn); nkeynes@380: JMP_TARGET(end); nkeynes@377: FCOMIP_st(1); nkeynes@377: SETA_t(); nkeynes@377: FPOP_st(); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: nkeynes@377: FSCA FPUL, FRn {: nkeynes@671: COUNT_INST(I_FSCA); nkeynes@377: check_fpuen(); nkeynes@388: load_spreg( R_ECX, R_FPSCR ); nkeynes@388: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@669: JNE_rel8(doubleprec ); nkeynes@800: LEA_sh4r_rptr( REG_OFFSET(fr[0][FRn&0x0E]), R_ECX ); nkeynes@388: load_spreg( R_EDX, R_FPUL ); nkeynes@388: call_func2( sh4_fsca, R_EDX, R_ECX ); nkeynes@388: JMP_TARGET(doubleprec); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: FIPR FVm, FVn {: nkeynes@671: COUNT_INST(I_FIPR); nkeynes@377: check_fpuen(); nkeynes@388: load_spreg( R_ECX, R_FPSCR ); nkeynes@388: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@669: JNE_rel8( doubleprec); nkeynes@388: nkeynes@669: push_fr( FVm<<2 ); nkeynes@669: push_fr( FVn<<2 ); nkeynes@388: FMULP_st(1); nkeynes@669: push_fr( (FVm<<2)+1); nkeynes@669: push_fr( (FVn<<2)+1); nkeynes@388: FMULP_st(1); nkeynes@388: FADDP_st(1); nkeynes@669: push_fr( (FVm<<2)+2); nkeynes@669: push_fr( (FVn<<2)+2); nkeynes@388: FMULP_st(1); nkeynes@388: FADDP_st(1); nkeynes@669: push_fr( (FVm<<2)+3); nkeynes@669: push_fr( (FVn<<2)+3); nkeynes@388: FMULP_st(1); nkeynes@388: FADDP_st(1); nkeynes@669: pop_fr( (FVn<<2)+3); nkeynes@388: JMP_TARGET(doubleprec); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: FTRV XMTRX, FVn {: nkeynes@671: COUNT_INST(I_FTRV); nkeynes@377: check_fpuen(); nkeynes@388: load_spreg( R_ECX, R_FPSCR ); nkeynes@388: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@669: JNE_rel8( doubleprec ); nkeynes@800: LEA_sh4r_rptr( REG_OFFSET(fr[0][FVn<<2]), R_EDX ); nkeynes@669: call_func1( sh4_ftrv, R_EDX ); // 12 nkeynes@388: JMP_TARGET(doubleprec); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: nkeynes@377: FRCHG {: nkeynes@671: COUNT_INST(I_FRCHG); nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: XOR_imm32_r32( FPSCR_FR, R_ECX ); nkeynes@377: store_spreg( R_ECX, R_FPSCR ); nkeynes@669: call_func0( sh4_switch_fr_banks ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: FSCHG {: nkeynes@671: COUNT_INST(I_FSCHG); nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: XOR_imm32_r32( FPSCR_SZ, R_ECX ); nkeynes@377: store_spreg( R_ECX, R_FPSCR ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@359: nkeynes@359: /* Processor control instructions */ nkeynes@368: LDC Rm, SR {: nkeynes@671: COUNT_INST(I_LDCSR); nkeynes@386: if( sh4_x86.in_delay_slot ) { nkeynes@386: SLOTILLEGAL(); nkeynes@386: } else { nkeynes@386: check_priv(); nkeynes@386: load_reg( R_EAX, Rm ); nkeynes@386: call_func1( sh4_write_sr, R_EAX ); nkeynes@386: sh4_x86.priv_checked = FALSE; nkeynes@386: sh4_x86.fpuen_checked = FALSE; nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@386: } nkeynes@368: :} nkeynes@359: LDC Rm, GBR {: nkeynes@671: COUNT_INST(I_LDC); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_GBR ); nkeynes@359: :} nkeynes@359: LDC Rm, VBR {: nkeynes@671: COUNT_INST(I_LDC); nkeynes@386: check_priv(); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_VBR ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: LDC Rm, SSR {: nkeynes@671: COUNT_INST(I_LDC); nkeynes@386: check_priv(); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_SSR ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: LDC Rm, SGR {: nkeynes@671: COUNT_INST(I_LDC); nkeynes@386: check_priv(); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_SGR ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: LDC Rm, SPC {: nkeynes@671: COUNT_INST(I_LDC); nkeynes@386: check_priv(); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_SPC ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: LDC Rm, DBR {: nkeynes@671: COUNT_INST(I_LDC); nkeynes@386: check_priv(); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_DBR ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@374: LDC Rm, Rn_BANK {: nkeynes@671: COUNT_INST(I_LDC); nkeynes@386: check_priv(); nkeynes@374: load_reg( R_EAX, Rm ); nkeynes@374: store_spreg( R_EAX, REG_OFFSET(r_bank[Rn_BANK]) ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@374: :} nkeynes@359: LDC.L @Rm+, GBR {: nkeynes@671: COUNT_INST(I_LDCM); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@395: check_ralign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: ADD_imm8s_sh4r( 4, REG_OFFSET(r[Rm]) ); nkeynes@586: MEM_READ_LONG( R_EAX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_GBR ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@368: LDC.L @Rm+, SR {: nkeynes@671: COUNT_INST(I_LDCSRM); nkeynes@386: if( sh4_x86.in_delay_slot ) { nkeynes@386: SLOTILLEGAL(); nkeynes@386: } else { nkeynes@586: check_priv(); nkeynes@386: load_reg( R_EAX, Rm ); nkeynes@395: check_ralign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: ADD_imm8s_sh4r( 4, REG_OFFSET(r[Rm]) ); nkeynes@586: MEM_READ_LONG( R_EAX, R_EAX ); nkeynes@386: call_func1( sh4_write_sr, R_EAX ); nkeynes@386: sh4_x86.priv_checked = FALSE; nkeynes@386: sh4_x86.fpuen_checked = FALSE; nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@386: } nkeynes@359: :} nkeynes@359: LDC.L @Rm+, VBR {: nkeynes@671: COUNT_INST(I_LDCM); nkeynes@586: check_priv(); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@395: check_ralign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: ADD_imm8s_sh4r( 4, REG_OFFSET(r[Rm]) ); nkeynes@586: MEM_READ_LONG( R_EAX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_VBR ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: LDC.L @Rm+, SSR {: nkeynes@671: COUNT_INST(I_LDCM); nkeynes@586: check_priv(); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@416: check_ralign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: ADD_imm8s_sh4r( 4, REG_OFFSET(r[Rm]) ); nkeynes@586: MEM_READ_LONG( R_EAX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_SSR ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: LDC.L @Rm+, SGR {: nkeynes@671: COUNT_INST(I_LDCM); nkeynes@586: check_priv(); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@395: check_ralign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: ADD_imm8s_sh4r( 4, REG_OFFSET(r[Rm]) ); nkeynes@586: MEM_READ_LONG( R_EAX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_SGR ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: LDC.L @Rm+, SPC {: nkeynes@671: COUNT_INST(I_LDCM); nkeynes@586: check_priv(); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@395: check_ralign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: ADD_imm8s_sh4r( 4, REG_OFFSET(r[Rm]) ); nkeynes@586: MEM_READ_LONG( R_EAX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_SPC ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: LDC.L @Rm+, DBR {: nkeynes@671: COUNT_INST(I_LDCM); nkeynes@586: check_priv(); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@395: check_ralign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: ADD_imm8s_sh4r( 4, REG_OFFSET(r[Rm]) ); nkeynes@586: MEM_READ_LONG( R_EAX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_DBR ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: LDC.L @Rm+, Rn_BANK {: nkeynes@671: COUNT_INST(I_LDCM); nkeynes@586: check_priv(); nkeynes@374: load_reg( R_EAX, Rm ); nkeynes@395: check_ralign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: ADD_imm8s_sh4r( 4, REG_OFFSET(r[Rm]) ); nkeynes@586: MEM_READ_LONG( R_EAX, R_EAX ); nkeynes@374: store_spreg( R_EAX, REG_OFFSET(r_bank[Rn_BANK]) ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@626: LDS Rm, FPSCR {: nkeynes@673: COUNT_INST(I_LDSFPSCR); nkeynes@626: check_fpuen(); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@669: call_func1( sh4_write_fpscr, R_EAX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: LDS.L @Rm+, FPSCR {: nkeynes@673: COUNT_INST(I_LDSFPSCRM); nkeynes@626: check_fpuen(); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@395: check_ralign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: ADD_imm8s_sh4r( 4, REG_OFFSET(r[Rm]) ); nkeynes@586: MEM_READ_LONG( R_EAX, R_EAX ); nkeynes@669: call_func1( sh4_write_fpscr, R_EAX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: LDS Rm, FPUL {: nkeynes@671: COUNT_INST(I_LDS); nkeynes@626: check_fpuen(); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_FPUL ); nkeynes@359: :} nkeynes@359: LDS.L @Rm+, FPUL {: nkeynes@671: COUNT_INST(I_LDSM); nkeynes@626: check_fpuen(); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@395: check_ralign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: ADD_imm8s_sh4r( 4, REG_OFFSET(r[Rm]) ); nkeynes@586: MEM_READ_LONG( R_EAX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_FPUL ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: LDS Rm, MACH {: nkeynes@671: COUNT_INST(I_LDS); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_MACH ); nkeynes@359: :} nkeynes@359: LDS.L @Rm+, MACH {: nkeynes@671: COUNT_INST(I_LDSM); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@395: check_ralign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: ADD_imm8s_sh4r( 4, REG_OFFSET(r[Rm]) ); nkeynes@586: MEM_READ_LONG( R_EAX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_MACH ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: LDS Rm, MACL {: nkeynes@671: COUNT_INST(I_LDS); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_MACL ); nkeynes@359: :} nkeynes@359: LDS.L @Rm+, MACL {: nkeynes@671: COUNT_INST(I_LDSM); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@395: check_ralign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: ADD_imm8s_sh4r( 4, REG_OFFSET(r[Rm]) ); nkeynes@586: MEM_READ_LONG( R_EAX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_MACL ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: LDS Rm, PR {: nkeynes@671: COUNT_INST(I_LDS); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_PR ); nkeynes@359: :} nkeynes@359: LDS.L @Rm+, PR {: nkeynes@671: COUNT_INST(I_LDSM); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@395: check_ralign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@586: ADD_imm8s_sh4r( 4, REG_OFFSET(r[Rm]) ); nkeynes@586: MEM_READ_LONG( R_EAX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_PR ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@550: LDTLB {: nkeynes@671: COUNT_INST(I_LDTLB); nkeynes@553: call_func0( MMU_ldtlb ); nkeynes@875: sh4_x86.tstate = TSTATE_NONE; nkeynes@550: :} nkeynes@671: OCBI @Rn {: nkeynes@671: COUNT_INST(I_OCBI); nkeynes@671: :} nkeynes@671: OCBP @Rn {: nkeynes@671: COUNT_INST(I_OCBP); nkeynes@671: :} nkeynes@671: OCBWB @Rn {: nkeynes@671: COUNT_INST(I_OCBWB); nkeynes@671: :} nkeynes@374: PREF @Rn {: nkeynes@671: COUNT_INST(I_PREF); nkeynes@374: load_reg( R_EAX, Rn ); nkeynes@532: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@374: AND_imm32_r32( 0xFC000000, R_EAX ); nkeynes@374: CMP_imm32_r32( 0xE0000000, R_EAX ); nkeynes@669: JNE_rel8(end); nkeynes@532: call_func1( sh4_flush_store_queue, R_ECX ); nkeynes@586: TEST_r32_r32( R_EAX, R_EAX ); nkeynes@586: JE_exc(-1); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@374: :} nkeynes@388: SLEEP {: nkeynes@671: COUNT_INST(I_SLEEP); nkeynes@388: check_priv(); nkeynes@388: call_func0( sh4_sleep ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@590: sh4_x86.in_delay_slot = DELAY_NONE; nkeynes@408: return 2; nkeynes@388: :} nkeynes@386: STC SR, Rn {: nkeynes@671: COUNT_INST(I_STCSR); nkeynes@386: check_priv(); nkeynes@386: call_func0(sh4_read_sr); nkeynes@386: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: STC GBR, Rn {: nkeynes@671: COUNT_INST(I_STC); nkeynes@359: load_spreg( R_EAX, R_GBR ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: STC VBR, Rn {: nkeynes@671: COUNT_INST(I_STC); nkeynes@386: check_priv(); nkeynes@359: load_spreg( R_EAX, R_VBR ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: STC SSR, Rn {: nkeynes@671: COUNT_INST(I_STC); nkeynes@386: check_priv(); nkeynes@359: load_spreg( R_EAX, R_SSR ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: STC SPC, Rn {: nkeynes@671: COUNT_INST(I_STC); nkeynes@386: check_priv(); nkeynes@359: load_spreg( R_EAX, R_SPC ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: STC SGR, Rn {: nkeynes@671: COUNT_INST(I_STC); nkeynes@386: check_priv(); nkeynes@359: load_spreg( R_EAX, R_SGR ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: STC DBR, Rn {: nkeynes@671: COUNT_INST(I_STC); nkeynes@386: check_priv(); nkeynes@359: load_spreg( R_EAX, R_DBR ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@374: STC Rm_BANK, Rn {: nkeynes@671: COUNT_INST(I_STC); nkeynes@386: check_priv(); nkeynes@374: load_spreg( R_EAX, REG_OFFSET(r_bank[Rm_BANK]) ); nkeynes@374: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@374: STC.L SR, @-Rn {: nkeynes@671: COUNT_INST(I_STCSRM); nkeynes@586: check_priv(); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: check_walign32( R_EAX ); nkeynes@586: ADD_imm8s_r32( -4, R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: PUSH_realigned_r32( R_EAX ); nkeynes@395: call_func0( sh4_read_sr ); nkeynes@586: POP_realigned_r32( R_ECX ); nkeynes@586: ADD_imm8s_sh4r( -4, REG_OFFSET(r[Rn]) ); nkeynes@368: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: STC.L VBR, @-Rn {: nkeynes@671: COUNT_INST(I_STCM); nkeynes@586: check_priv(); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: check_walign32( R_EAX ); nkeynes@586: ADD_imm8s_r32( -4, R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: load_spreg( R_EDX, R_VBR ); nkeynes@586: ADD_imm8s_sh4r( -4, REG_OFFSET(r[Rn]) ); nkeynes@586: MEM_WRITE_LONG( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: STC.L SSR, @-Rn {: nkeynes@671: COUNT_INST(I_STCM); nkeynes@586: check_priv(); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: check_walign32( R_EAX ); nkeynes@586: ADD_imm8s_r32( -4, R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: load_spreg( R_EDX, R_SSR ); nkeynes@586: ADD_imm8s_sh4r( -4, REG_OFFSET(r[Rn]) ); nkeynes@586: MEM_WRITE_LONG( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@416: STC.L SPC, @-Rn {: nkeynes@671: COUNT_INST(I_STCM); nkeynes@586: check_priv(); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: check_walign32( R_EAX ); nkeynes@586: ADD_imm8s_r32( -4, R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: load_spreg( R_EDX, R_SPC ); nkeynes@586: ADD_imm8s_sh4r( -4, REG_OFFSET(r[Rn]) ); nkeynes@586: MEM_WRITE_LONG( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: STC.L SGR, @-Rn {: nkeynes@671: COUNT_INST(I_STCM); nkeynes@586: check_priv(); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: check_walign32( R_EAX ); nkeynes@586: ADD_imm8s_r32( -4, R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: load_spreg( R_EDX, R_SGR ); nkeynes@586: ADD_imm8s_sh4r( -4, REG_OFFSET(r[Rn]) ); nkeynes@586: MEM_WRITE_LONG( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: STC.L DBR, @-Rn {: nkeynes@671: COUNT_INST(I_STCM); nkeynes@586: check_priv(); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: check_walign32( R_EAX ); nkeynes@586: ADD_imm8s_r32( -4, R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: load_spreg( R_EDX, R_DBR ); nkeynes@586: ADD_imm8s_sh4r( -4, REG_OFFSET(r[Rn]) ); nkeynes@586: MEM_WRITE_LONG( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@374: STC.L Rm_BANK, @-Rn {: nkeynes@671: COUNT_INST(I_STCM); nkeynes@586: check_priv(); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: check_walign32( R_EAX ); nkeynes@586: ADD_imm8s_r32( -4, R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: load_spreg( R_EDX, REG_OFFSET(r_bank[Rm_BANK]) ); nkeynes@586: ADD_imm8s_sh4r( -4, REG_OFFSET(r[Rn]) ); nkeynes@586: MEM_WRITE_LONG( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@374: :} nkeynes@359: STC.L GBR, @-Rn {: nkeynes@671: COUNT_INST(I_STCM); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: check_walign32( R_EAX ); nkeynes@586: ADD_imm8s_r32( -4, R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: load_spreg( R_EDX, R_GBR ); nkeynes@586: ADD_imm8s_sh4r( -4, REG_OFFSET(r[Rn]) ); nkeynes@586: MEM_WRITE_LONG( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: STS FPSCR, Rn {: nkeynes@673: COUNT_INST(I_STSFPSCR); nkeynes@626: check_fpuen(); nkeynes@359: load_spreg( R_EAX, R_FPSCR ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: STS.L FPSCR, @-Rn {: nkeynes@673: COUNT_INST(I_STSFPSCRM); nkeynes@626: check_fpuen(); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: check_walign32( R_EAX ); nkeynes@586: ADD_imm8s_r32( -4, R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: load_spreg( R_EDX, R_FPSCR ); nkeynes@586: ADD_imm8s_sh4r( -4, REG_OFFSET(r[Rn]) ); nkeynes@586: MEM_WRITE_LONG( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: STS FPUL, Rn {: nkeynes@671: COUNT_INST(I_STS); nkeynes@626: check_fpuen(); nkeynes@359: load_spreg( R_EAX, R_FPUL ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: STS.L FPUL, @-Rn {: nkeynes@671: COUNT_INST(I_STSM); nkeynes@626: check_fpuen(); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: check_walign32( R_EAX ); nkeynes@586: ADD_imm8s_r32( -4, R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: load_spreg( R_EDX, R_FPUL ); nkeynes@586: ADD_imm8s_sh4r( -4, REG_OFFSET(r[Rn]) ); nkeynes@586: MEM_WRITE_LONG( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: STS MACH, Rn {: nkeynes@671: COUNT_INST(I_STS); nkeynes@359: load_spreg( R_EAX, R_MACH ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: STS.L MACH, @-Rn {: nkeynes@671: COUNT_INST(I_STSM); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: check_walign32( R_EAX ); nkeynes@586: ADD_imm8s_r32( -4, R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: load_spreg( R_EDX, R_MACH ); nkeynes@586: ADD_imm8s_sh4r( -4, REG_OFFSET(r[Rn]) ); nkeynes@586: MEM_WRITE_LONG( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: STS MACL, Rn {: nkeynes@671: COUNT_INST(I_STS); nkeynes@359: load_spreg( R_EAX, R_MACL ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: STS.L MACL, @-Rn {: nkeynes@671: COUNT_INST(I_STSM); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: check_walign32( R_EAX ); nkeynes@586: ADD_imm8s_r32( -4, R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: load_spreg( R_EDX, R_MACL ); nkeynes@586: ADD_imm8s_sh4r( -4, REG_OFFSET(r[Rn]) ); nkeynes@586: MEM_WRITE_LONG( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: STS PR, Rn {: nkeynes@671: COUNT_INST(I_STS); nkeynes@359: load_spreg( R_EAX, R_PR ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: STS.L PR, @-Rn {: nkeynes@671: COUNT_INST(I_STSM); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: check_walign32( R_EAX ); nkeynes@586: ADD_imm8s_r32( -4, R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@586: load_spreg( R_EDX, R_PR ); nkeynes@586: ADD_imm8s_sh4r( -4, REG_OFFSET(r[Rn]) ); nkeynes@586: MEM_WRITE_LONG( R_EAX, R_EDX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: nkeynes@671: NOP {: nkeynes@671: COUNT_INST(I_NOP); nkeynes@671: /* Do nothing. Well, we could emit an 0x90, but what would really be the point? */ nkeynes@671: :} nkeynes@359: %% nkeynes@590: sh4_x86.in_delay_slot = DELAY_NONE; nkeynes@359: return 0; nkeynes@359: }