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@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@586: uint32_t *fixup_addr; nkeynes@586: uint32_t fixup_icount; nkeynes@596: int32_t exc_code; nkeynes@586: }; nkeynes@586: nkeynes@586: #define MAX_RECOVERY_SIZE 2048 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@417: /** Branch if T is set (either in the current cflags, or in sh4r.t) */ nkeynes@417: #define JT_rel8(rel8,label) if( sh4_x86.tstate == TSTATE_NONE ) { \ nkeynes@417: CMP_imm8s_sh4r( 1, R_T ); sh4_x86.tstate = TSTATE_E; } \ nkeynes@417: OP(0x70+sh4_x86.tstate); OP(rel8); \ nkeynes@417: MARK_JMP(rel8,label) nkeynes@417: /** Branch if T is clear (either in the current cflags or in sh4r.t) */ nkeynes@417: #define JF_rel8(rel8,label) if( sh4_x86.tstate == TSTATE_NONE ) { \ nkeynes@417: CMP_imm8s_sh4r( 1, R_T ); sh4_x86.tstate = TSTATE_E; } \ nkeynes@417: OP(0x70+ (sh4_x86.tstate^1)); OP(rel8); \ nkeynes@417: MARK_JMP(rel8, label) 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@368: void sh4_x86_init() 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@586: sh4_x86.backpatch_list[sh4_x86.backpatch_posn].fixup_addr = (uint32_t *)fixup_addr; 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@527: static inline void load_imm64( int x86reg, uint32_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@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@374: #define load_fr_bank(bankreg) load_spreg( bankreg, REG_OFFSET(fr_bank)) 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@375: void static inline load_fr( int bankreg, int x86reg, int frm ) nkeynes@375: { nkeynes@375: OP(0x8B); OP(0x40+bankreg+(x86reg<<3)); OP((frm^1)<<2); nkeynes@375: } nkeynes@375: nkeynes@375: /** nkeynes@375: * Store an FR register (single-precision floating point) into an integer x86 nkeynes@375: * register (eg for register-to-register moves) nkeynes@375: */ nkeynes@375: void static inline store_fr( int bankreg, int x86reg, int frn ) nkeynes@375: { nkeynes@375: OP(0x89); OP(0x40+bankreg+(x86reg<<3)); OP((frn^1)<<2); nkeynes@375: } nkeynes@375: nkeynes@375: nkeynes@375: /** nkeynes@375: * Load a pointer to the back fp back into the specified x86 register. The nkeynes@375: * bankreg must have been previously loaded with FPSCR. nkeynes@388: * NB: 12 bytes nkeynes@375: */ nkeynes@374: static inline void load_xf_bank( int bankreg ) nkeynes@374: { nkeynes@386: NOT_r32( bankreg ); nkeynes@374: SHR_imm8_r32( (21 - 6), bankreg ); // Extract bit 21 then *64 for bank size nkeynes@374: AND_imm8s_r32( 0x40, bankreg ); // Complete extraction nkeynes@374: OP(0x8D); OP(0x44+(bankreg<<3)); OP(0x28+bankreg); OP(REG_OFFSET(fr)); // LEA [ebp+bankreg+disp], bankreg nkeynes@374: } nkeynes@374: nkeynes@375: /** nkeynes@386: * Update the fr_bank pointer based on the current fpscr value. nkeynes@386: */ nkeynes@386: static inline void update_fr_bank( int fpscrreg ) nkeynes@386: { nkeynes@386: SHR_imm8_r32( (21 - 6), fpscrreg ); // Extract bit 21 then *64 for bank size nkeynes@386: AND_imm8s_r32( 0x40, fpscrreg ); // Complete extraction nkeynes@386: OP(0x8D); OP(0x44+(fpscrreg<<3)); OP(0x28+fpscrreg); OP(REG_OFFSET(fr)); // LEA [ebp+fpscrreg+disp], fpscrreg nkeynes@386: store_spreg( fpscrreg, REG_OFFSET(fr_bank) ); nkeynes@386: } nkeynes@386: /** nkeynes@377: * Push FPUL (as a 32-bit float) onto the FPU stack nkeynes@377: */ nkeynes@377: static inline void push_fpul( ) nkeynes@377: { nkeynes@377: OP(0xD9); OP(0x45); OP(R_FPUL); nkeynes@377: } nkeynes@377: nkeynes@377: /** nkeynes@377: * Pop FPUL (as a 32-bit float) from the FPU stack nkeynes@377: */ nkeynes@377: static inline void pop_fpul( ) nkeynes@377: { nkeynes@377: OP(0xD9); OP(0x5D); OP(R_FPUL); nkeynes@377: } nkeynes@377: nkeynes@377: /** nkeynes@375: * Push a 32-bit float onto the FPU stack, with bankreg previously loaded nkeynes@375: * with the location of the current fp bank. nkeynes@375: */ nkeynes@374: static inline void push_fr( int bankreg, int frm ) nkeynes@374: { nkeynes@374: OP(0xD9); OP(0x40 + bankreg); OP((frm^1)<<2); // FLD.S [bankreg + frm^1*4] nkeynes@374: } nkeynes@374: nkeynes@375: /** nkeynes@375: * Pop a 32-bit float from the FPU stack and store it back into the fp bank, nkeynes@375: * with bankreg previously loaded with the location of the current fp bank. nkeynes@375: */ nkeynes@374: static inline void pop_fr( int bankreg, int frm ) nkeynes@374: { nkeynes@374: OP(0xD9); OP(0x58 + bankreg); OP((frm^1)<<2); // FST.S [bankreg + frm^1*4] nkeynes@374: } nkeynes@374: nkeynes@375: /** nkeynes@375: * Push a 64-bit double onto the FPU stack, with bankreg previously loaded nkeynes@375: * with the location of the current fp bank. nkeynes@375: */ nkeynes@374: static inline void push_dr( int bankreg, int frm ) nkeynes@374: { nkeynes@375: OP(0xDD); OP(0x40 + bankreg); OP(frm<<2); // FLD.D [bankreg + frm*4] nkeynes@374: } nkeynes@374: nkeynes@374: static inline void pop_dr( int bankreg, int frm ) nkeynes@374: { nkeynes@375: OP(0xDD); OP(0x58 + bankreg); OP(frm<<2); // FST.D [bankreg + frm*4] nkeynes@374: } 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@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@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@361: #define UNDEF() 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@539: #if SH4_TRANSLATOR == TARGET_X86_64 nkeynes@539: #include "sh4/ia64abi.h" nkeynes@539: #else /* SH4_TRANSLATOR == TARGET_X86 */ 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@586: } nkeynes@590: nkeynes@590: /** nkeynes@590: * Embed a call to sh4_execute_instruction for situations that we nkeynes@590: * can't translate (mainly page-crossing delay slots at the moment). nkeynes@590: * Caller is responsible for setting new_pc. nkeynes@590: */ nkeynes@590: void sh4_emulator_exit( 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@590: load_imm32( R_ECX, ((endpc - sh4_x86.block_start_pc)>>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@590: load_imm32( 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@590: AND_imm8s_r32( 0xFC, R_EAX ); // 3 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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@380: JE_rel8(13, target1); nkeynes@368: TEST_r8_r8( R_AH, R_AH ); // 2 nkeynes@380: JE_rel8(9, target2); nkeynes@368: SHR_imm8_r32( 16, R_EAX ); // 3 nkeynes@368: TEST_r8_r8( R_AL, R_AL ); // 2 nkeynes@380: JE_rel8(2, target3); nkeynes@368: TEST_r8_r8( R_AH, R_AH ); // 2 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@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@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@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@386: JE_rel8(5, mqequal); nkeynes@386: ADD_sh4r_r32( REG_OFFSET(r[Rm]), R_EAX ); nkeynes@386: JMP_rel8(3, 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@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@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@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@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@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@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@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@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@527: JE_rel8( CALL_FUNC0_SIZE, 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@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@386: JE_rel8( 47, nosat ); nkeynes@386: nkeynes@386: ADD_r32_sh4r( R_EAX, R_MACL ); // 6 nkeynes@386: JNO_rel8( 51, end ); // 2 nkeynes@386: load_imm32( R_EDX, 1 ); // 5 nkeynes@386: store_spreg( R_EDX, R_MACH ); // 6 nkeynes@386: JS_rel8( 13, positive ); // 2 nkeynes@386: load_imm32( R_EAX, 0x80000000 );// 5 nkeynes@386: store_spreg( R_EAX, R_MACL ); // 6 nkeynes@386: JMP_rel8( 25, 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@386: JMP_rel8( 12, 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@359: load_spreg( R_EAX, R_T ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@361: MUL.L Rm, Rn {: 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@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@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@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@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@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@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@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@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@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@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@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@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@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@386: JGE_rel8(16, doshl); nkeynes@361: nkeynes@361: NEG_r32( R_ECX ); // 2 nkeynes@361: AND_imm8_r8( 0x1F, R_CL ); // 3 nkeynes@386: JE_rel8( 4, emptysar); // 2 nkeynes@361: SAR_r32_CL( R_EAX ); // 2 nkeynes@386: JMP_rel8(10, end); // 2 nkeynes@386: nkeynes@386: JMP_TARGET(emptysar); nkeynes@386: SAR_imm8_r32(31, R_EAX ); // 3 nkeynes@386: JMP_rel8(5, 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@368: load_reg( R_EAX, Rn ); nkeynes@368: load_reg( R_ECX, Rm ); nkeynes@382: CMP_imm32_r32( 0, R_ECX ); nkeynes@386: JGE_rel8(15, doshl); nkeynes@368: nkeynes@382: NEG_r32( R_ECX ); // 2 nkeynes@382: AND_imm8_r8( 0x1F, R_CL ); // 3 nkeynes@386: JE_rel8( 4, emptyshr ); nkeynes@382: SHR_r32_CL( R_EAX ); // 2 nkeynes@386: JMP_rel8(9, end); // 2 nkeynes@386: nkeynes@386: JMP_TARGET(emptyshr); nkeynes@386: XOR_r32_r32( R_EAX, R_EAX ); nkeynes@386: JMP_rel8(5, 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@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@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@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@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@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@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@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@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@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@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@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@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@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@359: load_reg( R_EAX, Rm ); nkeynes@359: XCHG_r8_r8( R_AL, R_AH ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: SWAP.W Rm, Rn {: 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@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@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@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@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@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@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@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@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@359: load_reg( R_EAX, Rm ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: MOV #imm, Rn {: nkeynes@359: load_imm32( R_EAX, imm ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: MOV.B Rm, @Rn {: 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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@586: sh4vma_t target = disp + pc + 4; nkeynes@586: JT_rel8( EXIT_BLOCK_REL_SIZE(target), 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@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@586: sh4vma_t target = disp + pc + 4; nkeynes@590: sh4_x86.in_delay_slot = DELAY_PC; nkeynes@417: if( sh4_x86.tstate == TSTATE_NONE ) { nkeynes@417: CMP_imm8s_sh4r( 1, R_T ); nkeynes@417: sh4_x86.tstate = TSTATE_E; nkeynes@417: } nkeynes@417: OP(0x0F); OP(0x80+sh4_x86.tstate); uint32_t *patch = (uint32_t *)xlat_output; OP32(0); // JNE rel32 nkeynes@526: sh4_translate_instruction(pc+2); nkeynes@586: exit_block_rel( target, pc+4 ); nkeynes@408: // not taken nkeynes@408: *patch = (xlat_output - ((uint8_t *)patch)) - 4; nkeynes@526: sh4_translate_instruction(pc+2); nkeynes@408: return 4; nkeynes@374: } nkeynes@374: :} nkeynes@374: BRA disp {: nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@590: sh4_x86.in_delay_slot = DELAY_PC; nkeynes@526: sh4_translate_instruction( pc + 2 ); nkeynes@586: exit_block_rel( disp + pc + 4, pc+4 ); nkeynes@409: sh4_x86.branch_taken = TRUE; nkeynes@408: return 4; nkeynes@374: } nkeynes@374: :} nkeynes@374: BRAF Rn {: 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@526: sh4_translate_instruction( pc + 2 ); nkeynes@590: exit_block_newpcset(pc+2); nkeynes@409: sh4_x86.branch_taken = TRUE; nkeynes@408: return 4; nkeynes@374: } nkeynes@374: :} nkeynes@374: BSR disp {: 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@526: sh4_translate_instruction( pc + 2 ); nkeynes@586: exit_block_rel( disp + pc + 4, pc+4 ); nkeynes@409: sh4_x86.branch_taken = TRUE; nkeynes@408: return 4; nkeynes@374: } nkeynes@374: :} nkeynes@374: BSRF Rn {: 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@526: sh4_translate_instruction( pc + 2 ); nkeynes@590: exit_block_newpcset(pc+2); nkeynes@409: sh4_x86.branch_taken = TRUE; nkeynes@408: return 4; nkeynes@374: } nkeynes@374: :} nkeynes@374: BT disp {: nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@586: sh4vma_t target = disp + pc + 4; nkeynes@586: JF_rel8( EXIT_BLOCK_REL_SIZE(target), 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@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@590: sh4_x86.in_delay_slot = DELAY_PC; nkeynes@417: if( sh4_x86.tstate == TSTATE_NONE ) { nkeynes@417: CMP_imm8s_sh4r( 1, R_T ); nkeynes@417: sh4_x86.tstate = TSTATE_E; nkeynes@417: } nkeynes@417: OP(0x0F); OP(0x80+(sh4_x86.tstate^1)); uint32_t *patch = (uint32_t *)xlat_output; OP32(0); // JE rel32 nkeynes@526: sh4_translate_instruction(pc+2); nkeynes@586: exit_block_rel( disp + pc + 4, pc+4 ); nkeynes@408: // not taken nkeynes@408: *patch = (xlat_output - ((uint8_t *)patch)) - 4; nkeynes@526: sh4_translate_instruction(pc+2); nkeynes@408: return 4; nkeynes@374: } nkeynes@374: :} nkeynes@374: JMP @Rn {: 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@526: sh4_translate_instruction(pc+2); nkeynes@590: exit_block_newpcset(pc+2); nkeynes@409: sh4_x86.branch_taken = TRUE; nkeynes@408: return 4; nkeynes@374: } nkeynes@374: :} nkeynes@374: JSR @Rn {: 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@526: sh4_translate_instruction(pc+2); nkeynes@590: exit_block_newpcset(pc+2); nkeynes@409: sh4_x86.branch_taken = TRUE; nkeynes@408: return 4; nkeynes@374: } nkeynes@374: :} nkeynes@374: 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@526: sh4_translate_instruction(pc+2); nkeynes@590: exit_block_newpcset(pc+2); nkeynes@409: sh4_x86.branch_taken = TRUE; nkeynes@408: return 4; nkeynes@374: } nkeynes@374: :} nkeynes@374: 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@526: sh4_translate_instruction(pc+2); nkeynes@590: exit_block_newpcset(pc+2); nkeynes@409: sh4_x86.branch_taken = TRUE; nkeynes@408: return 4; nkeynes@374: } nkeynes@374: :} nkeynes@374: TRAPA #imm {: 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@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@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@374: CLC(); nkeynes@374: SETC_sh4r(R_S); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@368: :} nkeynes@374: CLRT {: nkeynes@374: CLC(); nkeynes@374: SETC_t(); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: :} nkeynes@374: SETS {: nkeynes@374: STC(); nkeynes@374: SETC_sh4r(R_S); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: :} nkeynes@374: 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@375: /* As horrible as this looks, it's actually covering 5 separate cases: nkeynes@375: * 1. 32-bit fr-to-fr (PR=0) nkeynes@375: * 2. 64-bit dr-to-dr (PR=1, FRm&1 == 0, FRn&1 == 0 ) nkeynes@375: * 3. 64-bit dr-to-xd (PR=1, FRm&1 == 0, FRn&1 == 1 ) nkeynes@375: * 4. 64-bit xd-to-dr (PR=1, FRm&1 == 1, FRn&1 == 0 ) nkeynes@375: * 5. 64-bit xd-to-xd (PR=1, FRm&1 == 1, FRn&1 == 1 ) nkeynes@375: */ nkeynes@377: check_fpuen(); nkeynes@375: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: load_fr_bank( R_EDX ); nkeynes@375: TEST_imm32_r32( FPSCR_SZ, R_ECX ); nkeynes@380: JNE_rel8(8, doublesize); nkeynes@375: load_fr( R_EDX, R_EAX, FRm ); // PR=0 branch nkeynes@375: store_fr( R_EDX, R_EAX, FRn ); nkeynes@375: if( FRm&1 ) { nkeynes@386: JMP_rel8(24, end); nkeynes@380: JMP_TARGET(doublesize); nkeynes@375: load_xf_bank( R_ECX ); nkeynes@375: load_fr( R_ECX, R_EAX, FRm-1 ); nkeynes@375: if( FRn&1 ) { nkeynes@375: load_fr( R_ECX, R_EDX, FRm ); nkeynes@375: store_fr( R_ECX, R_EAX, FRn-1 ); nkeynes@375: store_fr( R_ECX, R_EDX, FRn ); nkeynes@375: } else /* FRn&1 == 0 */ { nkeynes@375: load_fr( R_ECX, R_ECX, FRm ); nkeynes@388: store_fr( R_EDX, R_EAX, FRn ); nkeynes@388: store_fr( R_EDX, R_ECX, FRn+1 ); nkeynes@375: } nkeynes@380: JMP_TARGET(end); nkeynes@375: } else /* FRm&1 == 0 */ { nkeynes@375: if( FRn&1 ) { nkeynes@386: JMP_rel8(24, end); nkeynes@375: load_xf_bank( R_ECX ); nkeynes@375: load_fr( R_EDX, R_EAX, FRm ); nkeynes@375: load_fr( R_EDX, R_EDX, FRm+1 ); nkeynes@375: store_fr( R_ECX, R_EAX, FRn-1 ); nkeynes@375: store_fr( R_ECX, R_EDX, FRn ); nkeynes@380: JMP_TARGET(end); nkeynes@375: } else /* FRn&1 == 0 */ { nkeynes@380: JMP_rel8(12, end); nkeynes@375: load_fr( R_EDX, R_EAX, FRm ); nkeynes@375: load_fr( R_EDX, R_ECX, FRm+1 ); nkeynes@375: store_fr( R_EDX, R_EAX, FRn ); nkeynes@375: store_fr( R_EDX, R_ECX, FRn+1 ); nkeynes@380: JMP_TARGET(end); nkeynes@375: } nkeynes@375: } nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@375: :} nkeynes@416: FMOV FRm, @Rn {: nkeynes@586: check_fpuen(); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: check_walign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@416: load_spreg( R_EDX, R_FPSCR ); nkeynes@416: TEST_imm32_r32( FPSCR_SZ, R_EDX ); nkeynes@586: JNE_rel8(8 + MEM_WRITE_SIZE, doublesize); nkeynes@416: load_fr_bank( R_EDX ); nkeynes@586: load_fr( R_EDX, R_ECX, FRm ); nkeynes@586: MEM_WRITE_LONG( R_EAX, R_ECX ); // 12 nkeynes@375: if( FRm&1 ) { nkeynes@527: JMP_rel8( 18 + MEM_WRITE_DOUBLE_SIZE, end ); nkeynes@380: JMP_TARGET(doublesize); nkeynes@416: load_xf_bank( R_EDX ); nkeynes@586: load_fr( R_EDX, R_ECX, FRm&0x0E ); nkeynes@416: load_fr( R_EDX, R_EDX, FRm|0x01 ); nkeynes@586: MEM_WRITE_DOUBLE( R_EAX, R_ECX, R_EDX ); nkeynes@380: JMP_TARGET(end); nkeynes@375: } else { nkeynes@527: JMP_rel8( 9 + MEM_WRITE_DOUBLE_SIZE, end ); nkeynes@380: JMP_TARGET(doublesize); nkeynes@416: load_fr_bank( R_EDX ); nkeynes@586: load_fr( R_EDX, R_ECX, FRm&0x0E ); nkeynes@416: load_fr( R_EDX, R_EDX, FRm|0x01 ); nkeynes@586: MEM_WRITE_DOUBLE( R_EAX, R_ECX, R_EDX ); nkeynes@380: JMP_TARGET(end); nkeynes@375: } nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@375: :} nkeynes@375: FMOV @Rm, FRn {: nkeynes@586: check_fpuen(); nkeynes@586: load_reg( R_EAX, Rm ); nkeynes@586: check_ralign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@416: load_spreg( R_EDX, R_FPSCR ); nkeynes@416: TEST_imm32_r32( FPSCR_SZ, R_EDX ); nkeynes@586: JNE_rel8(8 + MEM_READ_SIZE, doublesize); nkeynes@586: MEM_READ_LONG( R_EAX, R_EAX ); nkeynes@416: load_fr_bank( R_EDX ); nkeynes@416: store_fr( R_EDX, R_EAX, FRn ); nkeynes@375: if( FRn&1 ) { nkeynes@527: JMP_rel8(21 + MEM_READ_DOUBLE_SIZE, end); nkeynes@380: JMP_TARGET(doublesize); nkeynes@586: MEM_READ_DOUBLE( R_EAX, R_ECX, R_EAX ); nkeynes@416: load_spreg( R_EDX, R_FPSCR ); // assume read_long clobbered it nkeynes@416: load_xf_bank( R_EDX ); nkeynes@586: store_fr( R_EDX, R_ECX, FRn&0x0E ); nkeynes@586: store_fr( R_EDX, R_EAX, FRn|0x01 ); nkeynes@380: JMP_TARGET(end); nkeynes@375: } else { nkeynes@527: JMP_rel8(9 + MEM_READ_DOUBLE_SIZE, end); nkeynes@380: JMP_TARGET(doublesize); nkeynes@586: MEM_READ_DOUBLE( R_EAX, R_ECX, R_EAX ); nkeynes@416: load_fr_bank( R_EDX ); nkeynes@586: store_fr( R_EDX, R_ECX, FRn&0x0E ); nkeynes@586: store_fr( R_EDX, R_EAX, FRn|0x01 ); nkeynes@380: JMP_TARGET(end); nkeynes@375: } nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@375: :} nkeynes@377: FMOV FRm, @-Rn {: nkeynes@586: check_fpuen(); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: check_walign32( R_EAX ); nkeynes@416: load_spreg( R_EDX, R_FPSCR ); nkeynes@416: TEST_imm32_r32( FPSCR_SZ, R_EDX ); nkeynes@586: JNE_rel8(15 + MEM_WRITE_SIZE + MMU_TRANSLATE_SIZE, doublesize); nkeynes@586: ADD_imm8s_r32( -4, R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@416: load_fr_bank( R_EDX ); nkeynes@586: load_fr( R_EDX, R_ECX, FRm ); nkeynes@586: ADD_imm8s_sh4r(-4,REG_OFFSET(r[Rn])); nkeynes@586: MEM_WRITE_LONG( R_EAX, R_ECX ); // 12 nkeynes@377: if( FRm&1 ) { nkeynes@586: JMP_rel8( 25 + MEM_WRITE_DOUBLE_SIZE + MMU_TRANSLATE_SIZE, end ); nkeynes@380: JMP_TARGET(doublesize); nkeynes@586: ADD_imm8s_r32(-8,R_EAX); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@416: load_xf_bank( R_EDX ); nkeynes@586: load_fr( R_EDX, R_ECX, FRm&0x0E ); nkeynes@416: load_fr( R_EDX, R_EDX, FRm|0x01 ); nkeynes@586: ADD_imm8s_sh4r(-8,REG_OFFSET(r[Rn])); nkeynes@586: MEM_WRITE_DOUBLE( R_EAX, R_ECX, R_EDX ); nkeynes@380: JMP_TARGET(end); nkeynes@377: } else { nkeynes@586: JMP_rel8( 16 + MEM_WRITE_DOUBLE_SIZE + MMU_TRANSLATE_SIZE, end ); nkeynes@380: JMP_TARGET(doublesize); nkeynes@586: ADD_imm8s_r32(-8,R_EAX); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@416: load_fr_bank( R_EDX ); nkeynes@586: load_fr( R_EDX, R_ECX, FRm&0x0E ); nkeynes@416: load_fr( R_EDX, R_EDX, FRm|0x01 ); nkeynes@586: ADD_imm8s_sh4r(-8,REG_OFFSET(r[Rn])); nkeynes@586: MEM_WRITE_DOUBLE( R_EAX, R_ECX, R_EDX ); nkeynes@380: JMP_TARGET(end); nkeynes@377: } nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@416: FMOV @Rm+, FRn {: nkeynes@586: check_fpuen(); nkeynes@586: load_reg( R_EAX, Rm ); nkeynes@586: check_ralign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@416: load_spreg( R_EDX, R_FPSCR ); nkeynes@416: TEST_imm32_r32( FPSCR_SZ, R_EDX ); nkeynes@586: JNE_rel8(12 + MEM_READ_SIZE, doublesize); nkeynes@586: ADD_imm8s_sh4r( 4, REG_OFFSET(r[Rm]) ); nkeynes@586: MEM_READ_LONG( R_EAX, R_EAX ); nkeynes@416: load_fr_bank( R_EDX ); nkeynes@416: store_fr( R_EDX, R_EAX, FRn ); nkeynes@377: if( FRn&1 ) { nkeynes@586: JMP_rel8(25 + MEM_READ_DOUBLE_SIZE, end); nkeynes@380: JMP_TARGET(doublesize); nkeynes@586: ADD_imm8s_sh4r( 8, REG_OFFSET(r[Rm]) ); nkeynes@586: MEM_READ_DOUBLE( R_EAX, R_ECX, R_EAX ); nkeynes@416: load_spreg( R_EDX, R_FPSCR ); // assume read_long clobbered it nkeynes@416: load_xf_bank( R_EDX ); nkeynes@586: store_fr( R_EDX, R_ECX, FRn&0x0E ); nkeynes@586: store_fr( R_EDX, R_EAX, FRn|0x01 ); nkeynes@380: JMP_TARGET(end); nkeynes@377: } else { nkeynes@586: JMP_rel8(13 + MEM_READ_DOUBLE_SIZE, end); nkeynes@586: ADD_imm8s_sh4r( 8, REG_OFFSET(r[Rm]) ); nkeynes@586: MEM_READ_DOUBLE( R_EAX, R_ECX, R_EAX ); nkeynes@416: load_fr_bank( R_EDX ); nkeynes@586: store_fr( R_EDX, R_ECX, FRn&0x0E ); nkeynes@586: store_fr( R_EDX, R_EAX, FRn|0x01 ); nkeynes@380: JMP_TARGET(end); nkeynes@377: } nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: FMOV FRm, @(R0, Rn) {: nkeynes@586: check_fpuen(); nkeynes@586: load_reg( R_EAX, Rn ); nkeynes@586: ADD_sh4r_r32( REG_OFFSET(r[0]), R_EAX ); nkeynes@586: check_walign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_WRITE( R_EAX ); nkeynes@416: load_spreg( R_EDX, R_FPSCR ); nkeynes@416: TEST_imm32_r32( FPSCR_SZ, R_EDX ); nkeynes@586: JNE_rel8(8 + MEM_WRITE_SIZE, doublesize); nkeynes@416: load_fr_bank( R_EDX ); nkeynes@586: load_fr( R_EDX, R_ECX, FRm ); nkeynes@586: MEM_WRITE_LONG( R_EAX, R_ECX ); // 12 nkeynes@377: if( FRm&1 ) { nkeynes@527: JMP_rel8( 18 + MEM_WRITE_DOUBLE_SIZE, end ); nkeynes@380: JMP_TARGET(doublesize); nkeynes@416: load_xf_bank( R_EDX ); nkeynes@586: load_fr( R_EDX, R_ECX, FRm&0x0E ); nkeynes@416: load_fr( R_EDX, R_EDX, FRm|0x01 ); nkeynes@586: MEM_WRITE_DOUBLE( R_EAX, R_ECX, R_EDX ); nkeynes@380: JMP_TARGET(end); nkeynes@377: } else { nkeynes@527: JMP_rel8( 9 + MEM_WRITE_DOUBLE_SIZE, end ); nkeynes@380: JMP_TARGET(doublesize); nkeynes@416: load_fr_bank( R_EDX ); nkeynes@586: load_fr( R_EDX, R_ECX, FRm&0x0E ); nkeynes@416: load_fr( R_EDX, R_EDX, FRm|0x01 ); nkeynes@586: MEM_WRITE_DOUBLE( R_EAX, R_ECX, R_EDX ); nkeynes@380: JMP_TARGET(end); nkeynes@377: } nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: FMOV @(R0, Rm), FRn {: nkeynes@586: check_fpuen(); nkeynes@586: load_reg( R_EAX, Rm ); nkeynes@586: ADD_sh4r_r32( REG_OFFSET(r[0]), R_EAX ); nkeynes@586: check_ralign32( R_EAX ); nkeynes@586: MMU_TRANSLATE_READ( R_EAX ); nkeynes@416: load_spreg( R_EDX, R_FPSCR ); nkeynes@416: TEST_imm32_r32( FPSCR_SZ, R_EDX ); nkeynes@586: JNE_rel8(8 + MEM_READ_SIZE, doublesize); nkeynes@586: MEM_READ_LONG( R_EAX, R_EAX ); nkeynes@416: load_fr_bank( R_EDX ); nkeynes@416: store_fr( R_EDX, R_EAX, FRn ); nkeynes@377: if( FRn&1 ) { nkeynes@527: JMP_rel8(21 + MEM_READ_DOUBLE_SIZE, end); nkeynes@380: JMP_TARGET(doublesize); nkeynes@586: MEM_READ_DOUBLE( R_EAX, R_ECX, R_EAX ); nkeynes@416: load_spreg( R_EDX, R_FPSCR ); // assume read_long clobbered it nkeynes@416: load_xf_bank( R_EDX ); nkeynes@586: store_fr( R_EDX, R_ECX, FRn&0x0E ); nkeynes@586: store_fr( R_EDX, R_EAX, FRn|0x01 ); nkeynes@380: JMP_TARGET(end); nkeynes@377: } else { nkeynes@527: JMP_rel8(9 + MEM_READ_DOUBLE_SIZE, end); nkeynes@380: JMP_TARGET(doublesize); nkeynes@586: MEM_READ_DOUBLE( R_EAX, R_ECX, R_EAX ); nkeynes@416: load_fr_bank( R_EDX ); nkeynes@586: store_fr( R_EDX, R_ECX, FRn&0x0E ); nkeynes@586: store_fr( R_EDX, R_EAX, FRn|0x01 ); nkeynes@380: JMP_TARGET(end); nkeynes@377: } nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: FLDI0 FRn {: /* IFF PR=0 */ nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@380: JNE_rel8(8, end); nkeynes@377: XOR_r32_r32( R_EAX, R_EAX ); nkeynes@377: load_spreg( R_ECX, REG_OFFSET(fr_bank) ); nkeynes@377: store_fr( R_ECX, 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@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@380: JNE_rel8(11, end); nkeynes@377: load_imm32(R_EAX, 0x3F800000); nkeynes@377: load_spreg( R_ECX, REG_OFFSET(fr_bank) ); nkeynes@377: store_fr( R_ECX, 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@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: load_spreg(R_EDX, REG_OFFSET(fr_bank)); nkeynes@377: FILD_sh4r(R_FPUL); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@380: JNE_rel8(5, doubleprec); nkeynes@377: pop_fr( R_EDX, FRn ); nkeynes@380: JMP_rel8(3, end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@377: pop_dr( R_EDX, FRn ); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: FTRC FRm, FPUL {: nkeynes@377: check_fpuen(); nkeynes@388: load_spreg( R_ECX, R_FPSCR ); nkeynes@388: load_fr_bank( R_EDX ); nkeynes@388: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@388: JNE_rel8(5, doubleprec); nkeynes@388: push_fr( R_EDX, FRm ); nkeynes@388: JMP_rel8(3, doop); nkeynes@388: JMP_TARGET(doubleprec); nkeynes@388: push_dr( R_EDX, FRm ); nkeynes@388: JMP_TARGET( doop ); nkeynes@388: load_imm32( R_ECX, (uint32_t)&max_int ); nkeynes@388: FILD_r32ind( R_ECX ); nkeynes@388: FCOMIP_st(1); nkeynes@394: JNA_rel8( 32, sat ); nkeynes@388: load_imm32( R_ECX, (uint32_t)&min_int ); // 5 nkeynes@388: FILD_r32ind( R_ECX ); // 2 nkeynes@388: FCOMIP_st(1); // 2 nkeynes@394: JAE_rel8( 21, sat2 ); // 2 nkeynes@394: load_imm32( R_EAX, (uint32_t)&save_fcw ); nkeynes@394: FNSTCW_r32ind( R_EAX ); nkeynes@394: load_imm32( R_EDX, (uint32_t)&trunc_fcw ); nkeynes@394: FLDCW_r32ind( R_EDX ); nkeynes@388: FISTP_sh4r(R_FPUL); // 3 nkeynes@394: FLDCW_r32ind( R_EAX ); nkeynes@388: JMP_rel8( 9, 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@377: check_fpuen(); nkeynes@377: load_fr_bank( R_ECX ); nkeynes@377: load_fr( R_ECX, 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@377: check_fpuen(); nkeynes@377: load_fr_bank( R_ECX ); nkeynes@377: load_spreg( R_EAX, R_FPUL ); nkeynes@377: store_fr( R_ECX, R_EAX, FRn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: FCNVDS FRm, FPUL {: nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@380: JE_rel8(9, end); // only when PR=1 nkeynes@377: load_fr_bank( R_ECX ); nkeynes@377: push_dr( R_ECX, 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@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@380: JE_rel8(9, end); // only when PR=1 nkeynes@377: load_fr_bank( R_ECX ); nkeynes@377: push_fpul(); nkeynes@377: pop_dr( R_ECX, 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@377: check_fpuen(); nkeynes@374: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: load_fr_bank( R_EDX ); nkeynes@374: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@380: JNE_rel8(10, doubleprec); nkeynes@374: push_fr(R_EDX, FRn); // 3 nkeynes@374: FABS_st0(); // 2 nkeynes@374: pop_fr( R_EDX, FRn); //3 nkeynes@380: JMP_rel8(8,end); // 2 nkeynes@380: JMP_TARGET(doubleprec); nkeynes@374: push_dr(R_EDX, FRn); nkeynes@374: FABS_st0(); nkeynes@374: pop_dr(R_EDX, FRn); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@374: :} nkeynes@377: FADD FRm, FRn {: nkeynes@377: check_fpuen(); nkeynes@375: load_spreg( R_ECX, R_FPSCR ); nkeynes@375: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@377: load_fr_bank( R_EDX ); nkeynes@380: JNE_rel8(13,doubleprec); nkeynes@377: push_fr(R_EDX, FRm); nkeynes@377: push_fr(R_EDX, FRn); nkeynes@377: FADDP_st(1); nkeynes@377: pop_fr(R_EDX, FRn); nkeynes@380: JMP_rel8(11,end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@377: push_dr(R_EDX, FRm); nkeynes@377: push_dr(R_EDX, FRn); nkeynes@377: FADDP_st(1); nkeynes@377: pop_dr(R_EDX, FRn); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@375: :} nkeynes@377: FDIV FRm, FRn {: nkeynes@377: check_fpuen(); nkeynes@375: load_spreg( R_ECX, R_FPSCR ); nkeynes@375: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@377: load_fr_bank( R_EDX ); nkeynes@380: JNE_rel8(13, doubleprec); nkeynes@377: push_fr(R_EDX, FRn); nkeynes@377: push_fr(R_EDX, FRm); nkeynes@377: FDIVP_st(1); nkeynes@377: pop_fr(R_EDX, FRn); nkeynes@380: JMP_rel8(11, end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@377: push_dr(R_EDX, FRn); nkeynes@377: push_dr(R_EDX, FRm); nkeynes@377: FDIVP_st(1); nkeynes@377: pop_dr(R_EDX, FRn); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@375: :} nkeynes@375: FMAC FR0, FRm, FRn {: nkeynes@377: check_fpuen(); nkeynes@375: load_spreg( R_ECX, R_FPSCR ); nkeynes@375: load_spreg( R_EDX, REG_OFFSET(fr_bank)); nkeynes@375: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@380: JNE_rel8(18, doubleprec); nkeynes@375: push_fr( R_EDX, 0 ); nkeynes@375: push_fr( R_EDX, FRm ); nkeynes@375: FMULP_st(1); nkeynes@375: push_fr( R_EDX, FRn ); nkeynes@375: FADDP_st(1); nkeynes@375: pop_fr( R_EDX, FRn ); nkeynes@380: JMP_rel8(16, end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@375: push_dr( R_EDX, 0 ); nkeynes@375: push_dr( R_EDX, FRm ); nkeynes@375: FMULP_st(1); nkeynes@375: push_dr( R_EDX, FRn ); nkeynes@375: FADDP_st(1); nkeynes@375: pop_dr( R_EDX, FRn ); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@375: :} nkeynes@375: nkeynes@377: FMUL FRm, FRn {: nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@377: load_fr_bank( R_EDX ); nkeynes@380: JNE_rel8(13, doubleprec); nkeynes@377: push_fr(R_EDX, FRm); nkeynes@377: push_fr(R_EDX, FRn); nkeynes@377: FMULP_st(1); nkeynes@377: pop_fr(R_EDX, FRn); nkeynes@380: JMP_rel8(11, end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@377: push_dr(R_EDX, FRm); nkeynes@377: push_dr(R_EDX, FRn); nkeynes@377: FMULP_st(1); nkeynes@377: pop_dr(R_EDX, FRn); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: FNEG FRn {: nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@377: load_fr_bank( R_EDX ); nkeynes@380: JNE_rel8(10, doubleprec); nkeynes@377: push_fr(R_EDX, FRn); nkeynes@377: FCHS_st0(); nkeynes@377: pop_fr(R_EDX, FRn); nkeynes@380: JMP_rel8(8, end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@377: push_dr(R_EDX, FRn); nkeynes@377: FCHS_st0(); nkeynes@377: pop_dr(R_EDX, FRn); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: FSRRA FRn {: nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@377: load_fr_bank( R_EDX ); nkeynes@380: JNE_rel8(12, end); // PR=0 only nkeynes@377: FLD1_st0(); nkeynes@377: push_fr(R_EDX, FRn); nkeynes@377: FSQRT_st0(); nkeynes@377: FDIVP_st(1); nkeynes@377: pop_fr(R_EDX, FRn); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: FSQRT FRn {: nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@377: load_fr_bank( R_EDX ); nkeynes@380: JNE_rel8(10, doubleprec); nkeynes@377: push_fr(R_EDX, FRn); nkeynes@377: FSQRT_st0(); nkeynes@377: pop_fr(R_EDX, FRn); nkeynes@380: JMP_rel8(8, end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@377: push_dr(R_EDX, FRn); nkeynes@377: FSQRT_st0(); nkeynes@377: pop_dr(R_EDX, FRn); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: FSUB FRm, FRn {: nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@377: load_fr_bank( R_EDX ); nkeynes@380: JNE_rel8(13, doubleprec); nkeynes@377: push_fr(R_EDX, FRn); nkeynes@377: push_fr(R_EDX, FRm); nkeynes@388: FSUBP_st(1); nkeynes@377: pop_fr(R_EDX, FRn); nkeynes@380: JMP_rel8(11, end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@377: push_dr(R_EDX, FRn); nkeynes@377: push_dr(R_EDX, FRm); nkeynes@388: FSUBP_st(1); nkeynes@377: pop_dr(R_EDX, FRn); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: nkeynes@377: FCMP/EQ FRm, FRn {: nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@377: load_fr_bank( R_EDX ); nkeynes@380: JNE_rel8(8, doubleprec); nkeynes@377: push_fr(R_EDX, FRm); nkeynes@377: push_fr(R_EDX, FRn); nkeynes@380: JMP_rel8(6, end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@377: push_dr(R_EDX, FRm); nkeynes@377: push_dr(R_EDX, 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@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@377: load_fr_bank( R_EDX ); nkeynes@380: JNE_rel8(8, doubleprec); nkeynes@377: push_fr(R_EDX, FRm); nkeynes@377: push_fr(R_EDX, FRn); nkeynes@380: JMP_rel8(6, end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@377: push_dr(R_EDX, FRm); nkeynes@377: push_dr(R_EDX, 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@377: check_fpuen(); nkeynes@388: load_spreg( R_ECX, R_FPSCR ); nkeynes@388: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@527: JNE_rel8( CALL_FUNC2_SIZE + 9, doubleprec ); nkeynes@388: load_fr_bank( R_ECX ); nkeynes@388: ADD_imm8s_r32( (FRn&0x0E)<<2, 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@377: check_fpuen(); nkeynes@388: load_spreg( R_ECX, R_FPSCR ); nkeynes@388: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@388: JNE_rel8(44, doubleprec); nkeynes@388: nkeynes@388: load_fr_bank( R_ECX ); nkeynes@388: push_fr( R_ECX, FVm<<2 ); nkeynes@388: push_fr( R_ECX, FVn<<2 ); nkeynes@388: FMULP_st(1); nkeynes@388: push_fr( R_ECX, (FVm<<2)+1); nkeynes@388: push_fr( R_ECX, (FVn<<2)+1); nkeynes@388: FMULP_st(1); nkeynes@388: FADDP_st(1); nkeynes@388: push_fr( R_ECX, (FVm<<2)+2); nkeynes@388: push_fr( R_ECX, (FVn<<2)+2); nkeynes@388: FMULP_st(1); nkeynes@388: FADDP_st(1); nkeynes@388: push_fr( R_ECX, (FVm<<2)+3); nkeynes@388: push_fr( R_ECX, (FVn<<2)+3); nkeynes@388: FMULP_st(1); nkeynes@388: FADDP_st(1); nkeynes@388: pop_fr( R_ECX, (FVn<<2)+3); nkeynes@388: JMP_TARGET(doubleprec); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: FTRV XMTRX, FVn {: nkeynes@377: check_fpuen(); nkeynes@388: load_spreg( R_ECX, R_FPSCR ); nkeynes@388: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@527: JNE_rel8( 18 + CALL_FUNC2_SIZE, doubleprec ); nkeynes@388: load_fr_bank( R_EDX ); // 3 nkeynes@388: ADD_imm8s_r32( FVn<<4, R_EDX ); // 3 nkeynes@388: load_xf_bank( R_ECX ); // 12 nkeynes@388: call_func2( sh4_ftrv, R_EDX, R_ECX ); // 12 nkeynes@388: JMP_TARGET(doubleprec); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: nkeynes@377: 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@386: update_fr_bank( R_ECX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: :} nkeynes@377: 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@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@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_GBR ); nkeynes@359: :} nkeynes@359: LDC Rm, VBR {: 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@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@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@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@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@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@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@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@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@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@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@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@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@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@359: LDS Rm, FPSCR {: nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_FPSCR ); nkeynes@386: update_fr_bank( R_EAX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: LDS.L @Rm+, FPSCR {: 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_FPSCR ); nkeynes@386: update_fr_bank( R_EAX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: :} nkeynes@359: LDS Rm, FPUL {: nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_FPUL ); nkeynes@359: :} nkeynes@359: LDS.L @Rm+, FPUL {: 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@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_MACH ); nkeynes@359: :} nkeynes@359: LDS.L @Rm+, MACH {: 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@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_MACL ); nkeynes@359: :} nkeynes@359: LDS.L @Rm+, MACL {: 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@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_PR ); nkeynes@359: :} nkeynes@359: LDS.L @Rm+, PR {: 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@553: call_func0( MMU_ldtlb ); nkeynes@550: :} nkeynes@359: OCBI @Rn {: :} nkeynes@359: OCBP @Rn {: :} nkeynes@359: OCBWB @Rn {: :} nkeynes@374: PREF @Rn {: 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@586: JNE_rel8(8+CALL_FUNC1_SIZE, 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@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@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@359: load_spreg( R_EAX, R_GBR ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: STC VBR, Rn {: 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@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@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@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@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@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@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@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@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@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@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@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@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@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@359: load_spreg( R_EAX, R_FPSCR ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: STS.L FPSCR, @-Rn {: 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@359: load_spreg( R_EAX, R_FPUL ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: STS.L FPUL, @-Rn {: 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@359: load_spreg( R_EAX, R_MACH ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: STS.L MACH, @-Rn {: 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@359: load_spreg( R_EAX, R_MACL ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: STS.L MACL, @-Rn {: 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@359: load_spreg( R_EAX, R_PR ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: STS.L PR, @-Rn {: 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@359: NOP {: /* Do nothing. Well, we could emit an 0x90, but what would really be the point? */ :} nkeynes@359: %% nkeynes@590: sh4_x86.in_delay_slot = DELAY_NONE; nkeynes@359: return 0; nkeynes@359: }