nkeynes@359: /** nkeynes@359: * $Id: sh4x86.in,v 1.1 2007-08-23 12:33:27 nkeynes Exp $ 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@359: #include "sh4core.h" nkeynes@359: #include "sh4trans.h" nkeynes@359: #include "x86op.h" nkeynes@359: 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@359: OP(0x89); nkeynes@359: OP(0x45 + x86reg<<3); nkeynes@359: OP(REG_OFFSET(r[sh4reg])); nkeynes@359: } nkeynes@359: nkeynes@359: static inline void load_spreg( int x86reg, int regoffset ) nkeynes@359: { nkeynes@359: /* mov [bp+n], reg */ nkeynes@359: OP(0x89); nkeynes@359: OP(0x45 + x86reg<<3); nkeynes@359: OP(regoffset); nkeynes@359: } nkeynes@359: nkeynes@359: #define UNDEF() nkeynes@359: #define MEM_READ_BYTE( addr_reg, value_reg ) nkeynes@359: #define MEM_READ_WORD( addr_reg, value_reg ) nkeynes@359: #define MEM_READ_LONG( addr_reg, value_reg ) nkeynes@359: #define MEM_WRITE_BYTE( addr_reg, value_reg ) nkeynes@359: #define MEM_WRITE_WORD( addr_reg, value_reg ) nkeynes@359: #define MEM_WRITE_LONG( addr_reg, value_reg ) nkeynes@359: 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@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@359: OP(0x8B); nkeynes@359: OP(0x45 + x86reg<<3); nkeynes@359: OP(REG_OFFSET(r[sh4reg])); nkeynes@359: } nkeynes@359: void static inline store_spreg( int x86reg, int regoffset ) { nkeynes@359: /* mov reg, [bp+n] */ nkeynes@359: OP(0x8B); nkeynes@359: OP(0x45 + x86reg<<3); nkeynes@359: OP(regoffset); nkeynes@359: } nkeynes@359: nkeynes@359: nkeynes@359: /** nkeynes@359: * Emit the 'start of block' assembly. Sets up the stack frame and save nkeynes@359: * SI/DI as required nkeynes@359: */ nkeynes@359: void sh4_translate_begin_block() { nkeynes@359: /* push ebp */ nkeynes@359: *xlat_output++ = 0x50 + R_EBP; nkeynes@359: nkeynes@359: /* mov &sh4r, ebp */ nkeynes@359: load_imm32( R_EBP, (uint32_t)&sh4r ); nkeynes@359: nkeynes@359: /* load carry from SR */ nkeynes@359: } nkeynes@359: nkeynes@359: /** nkeynes@359: * Flush any open regs back to memory, restore SI/DI/, update PC, etc nkeynes@359: */ nkeynes@359: void sh4_translate_end_block( sh4addr_t pc ) { nkeynes@359: /* pop ebp */ nkeynes@359: *xlat_output++ = 0x58 + R_EBP; nkeynes@359: nkeynes@359: /* ret */ nkeynes@359: *xlat_output++ = 0xC3; nkeynes@359: } nkeynes@359: 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@359: * nkeynes@359: * @return true if the instruction marks the end of a basic block nkeynes@359: * (eg a branch or nkeynes@359: */ nkeynes@359: uint32_t sh4_x86_translate_instruction( uint32_t pc ) nkeynes@359: { nkeynes@359: uint16_t ir = 0; nkeynes@359: 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@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@359: :} nkeynes@359: ADDC Rm, Rn {: nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: LDC_t(); nkeynes@359: ADC_r32_r32( R_EAX, R_ECX ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: SETC_t(); 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@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@359: :} nkeynes@359: AND #imm, R0 {: nkeynes@359: // Note: x86 AND imm8 sign-extends, SH4 version zero-extends. So nkeynes@359: // need to use the imm32 version nkeynes@359: load_reg( R_EAX, 0 ); nkeynes@359: AND_imm32_r32(imm, R_EAX); nkeynes@359: store_reg( R_EAX, 0 ); 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@359: ADD_r32_r32( R_EAX, R_EBX ); nkeynes@359: MEM_READ_BYTE( R_ECX, R_EAX ); nkeynes@359: AND_imm32_r32(imm, R_ECX ); nkeynes@359: MEM_WRITE_BYTE( R_ECX, R_EAX ); 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@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@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@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@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@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@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@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@359: :} nkeynes@359: CMP/STR Rm, Rn {: :} nkeynes@359: DIV0S Rm, Rn {: :} nkeynes@359: DIV0U {: :} nkeynes@359: DIV1 Rm, Rn {: :} nkeynes@359: DMULS.L Rm, Rn {: :} nkeynes@359: DMULU.L Rm, Rn {: :} nkeynes@359: DT Rn {: nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: ADD_imm8s_r32( -1, Rn ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: SETE_t(); 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@359: EXTS.W Rm, Rn {: :} nkeynes@359: EXTU.B Rm, Rn {: :} nkeynes@359: EXTU.W Rm, Rn {: :} nkeynes@359: MAC.L @Rm+, @Rn+ {: :} nkeynes@359: MAC.W @Rm+, @Rn+ {: :} nkeynes@359: MOVT Rn {: nkeynes@359: load_spreg( R_EAX, R_T ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: MUL.L Rm, Rn {: :} nkeynes@359: MULS.W Rm, Rn {: :} nkeynes@359: MULU.W Rm, Rn {: :} 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@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@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@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@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@359: :} nkeynes@359: OR.B #imm, @(R0, GBR) {: :} nkeynes@359: ROTCL Rn {: nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: LDC_t(); nkeynes@359: RCL1_r32( R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: SETC_t(); nkeynes@359: :} nkeynes@359: ROTCR Rn {: nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: LDC_t(); nkeynes@359: RCR1_r32( R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: SETC_t(); 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@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@359: :} nkeynes@359: SHAD Rm, Rn {: nkeynes@359: /* Annoyingly enough, not directly convertible */ nkeynes@359: :} nkeynes@359: SHLD Rm, Rn {: nkeynes@359: :} nkeynes@359: SHAL Rn {: nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: SHL1_r32( R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: SHAR Rn {: nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: SAR1_r32( R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: SHLL Rn {: nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: SHL1_r32( R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); 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@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@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@359: :} nkeynes@359: SHLR Rn {: nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: SHR1_r32( R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); 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@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@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@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@359: :} nkeynes@359: SUBC Rm, Rn {: nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: LDC_t(); nkeynes@359: SBB_r32_r32( R_EAX, R_ECX ); nkeynes@359: store_reg( R_ECX, Rn ); 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@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@359: :} nkeynes@359: TAS.B @Rn {: :} nkeynes@359: TST Rm, Rn {: :} nkeynes@359: TST #imm, R0 {: :} nkeynes@359: TST.B #imm, @(R0, GBR) {: :} 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@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@359: :} nkeynes@359: XOR.B #imm, @(R0, GBR) {: nkeynes@359: load_reg( R_EAX, 0 ); nkeynes@359: load_spreg( R_ECX, R_GBR ); nkeynes@359: ADD_r32_r32( R_EAX, R_ECX ); nkeynes@359: MEM_READ_BYTE( R_ECX, R_EAX ); nkeynes@359: XOR_imm32_r32( imm, R_EAX ); nkeynes@359: MEM_WRITE_BYTE( R_ECX, R_EAX ); nkeynes@359: :} nkeynes@359: XTRCT Rm, Rn {: 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@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: MEM_WRITE_BYTE( R_ECX, R_EAX ); nkeynes@359: :} nkeynes@359: MOV.B Rm, @-Rn {: nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: ADD_imm8s_r32( -1, Rn ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: MEM_WRITE_BYTE( R_ECX, R_EAX ); nkeynes@359: :} nkeynes@359: MOV.B Rm, @(R0, Rn) {: nkeynes@359: load_reg( R_EAX, 0 ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: ADD_r32_r32( R_EAX, R_ECX ); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: MEM_WRITE_BYTE( R_ECX, R_EAX ); nkeynes@359: :} nkeynes@359: MOV.B R0, @(disp, GBR) {: nkeynes@359: load_reg( R_EAX, 0 ); nkeynes@359: load_spreg( R_ECX, R_GBR ); nkeynes@359: ADD_imm32_r32( disp, R_ECX ); nkeynes@359: MEM_WRITE_BYTE( R_ECX, R_EAX ); nkeynes@359: :} nkeynes@359: MOV.B R0, @(disp, Rn) {: nkeynes@359: load_reg( R_EAX, 0 ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: ADD_imm32_r32( disp, R_ECX ); nkeynes@359: MEM_WRITE_BYTE( R_ECX, R_EAX ); nkeynes@359: :} nkeynes@359: MOV.B @Rm, Rn {: nkeynes@359: load_reg( R_ECX, Rm ); nkeynes@359: MEM_READ_BYTE( R_ECX, R_EAX ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: :} nkeynes@359: MOV.B @Rm+, Rn {: nkeynes@359: load_reg( R_ECX, Rm ); nkeynes@359: MOV_r32_r32( R_ECX, R_EAX ); nkeynes@359: ADD_imm8s_r32( 1, R_EAX ); nkeynes@359: store_reg( R_EAX, Rm ); nkeynes@359: MEM_READ_BYTE( R_ECX, R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: MOV.B @(R0, Rm), Rn {: nkeynes@359: load_reg( R_EAX, 0 ); nkeynes@359: load_reg( R_ECX, Rm ); nkeynes@359: ADD_r32_r32( R_EAX, R_ECX ); nkeynes@359: MEM_READ_BYTE( R_ECX, R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: MOV.B @(disp, GBR), R0 {: nkeynes@359: load_spreg( R_ECX, R_GBR ); nkeynes@359: ADD_imm32_r32( disp, R_ECX ); nkeynes@359: MEM_READ_BYTE( R_ECX, R_EAX ); nkeynes@359: store_reg( R_EAX, 0 ); nkeynes@359: :} nkeynes@359: MOV.B @(disp, Rm), R0 {: nkeynes@359: load_reg( R_ECX, Rm ); nkeynes@359: ADD_imm32_r32( disp, R_ECX ); nkeynes@359: MEM_READ_BYTE( R_ECX, R_EAX ); nkeynes@359: store_reg( R_EAX, 0 ); nkeynes@359: :} nkeynes@359: MOV.L Rm, @Rn {: :} nkeynes@359: MOV.L Rm, @-Rn {: :} nkeynes@359: MOV.L Rm, @(R0, Rn) {: :} nkeynes@359: MOV.L R0, @(disp, GBR) {: :} nkeynes@359: MOV.L Rm, @(disp, Rn) {: :} nkeynes@359: MOV.L @Rm, Rn {: :} nkeynes@359: MOV.L @Rm+, Rn {: :} nkeynes@359: MOV.L @(R0, Rm), Rn {: :} nkeynes@359: MOV.L @(disp, GBR), R0 {: :} nkeynes@359: MOV.L @(disp, PC), Rn {: :} nkeynes@359: MOV.L @(disp, Rm), Rn {: :} nkeynes@359: MOV.W Rm, @Rn {: :} nkeynes@359: MOV.W Rm, @-Rn {: :} nkeynes@359: MOV.W Rm, @(R0, Rn) {: :} nkeynes@359: MOV.W R0, @(disp, GBR) {: :} nkeynes@359: MOV.W R0, @(disp, Rn) {: :} nkeynes@359: MOV.W @Rm, Rn {: :} nkeynes@359: MOV.W @Rm+, Rn {: :} nkeynes@359: MOV.W @(R0, Rm), Rn {: :} nkeynes@359: MOV.W @(disp, GBR), R0 {: :} nkeynes@359: MOV.W @(disp, PC), Rn {: :} nkeynes@359: MOV.W @(disp, Rm), R0 {: :} nkeynes@359: MOVA @(disp, PC), R0 {: :} nkeynes@359: MOVCA.L R0, @Rn {: :} nkeynes@359: nkeynes@359: /* Control transfer instructions */ nkeynes@359: BF disp {: :} nkeynes@359: BF/S disp {: :} nkeynes@359: BRA disp {: :} nkeynes@359: BRAF Rn {: :} nkeynes@359: BSR disp {: :} nkeynes@359: BSRF Rn {: :} nkeynes@359: BT disp {: /* If true, result PC += 4 + disp. else result PC = pc+2 */ nkeynes@359: return pc + 2; nkeynes@359: :} nkeynes@359: BT/S disp {: nkeynes@359: nkeynes@359: return pc + 4; nkeynes@359: :} nkeynes@359: JMP @Rn {: :} nkeynes@359: JSR @Rn {: :} nkeynes@359: RTE {: :} nkeynes@359: RTS {: :} nkeynes@359: TRAPA #imm {: :} nkeynes@359: UNDEF {: :} nkeynes@359: nkeynes@359: CLRMAC {: :} nkeynes@359: CLRS {: :} nkeynes@359: CLRT {: :} nkeynes@359: SETS {: :} nkeynes@359: SETT {: :} nkeynes@359: nkeynes@359: /* Floating point instructions */ nkeynes@359: FABS FRn {: :} nkeynes@359: FADD FRm, FRn {: :} nkeynes@359: FCMP/EQ FRm, FRn {: :} nkeynes@359: FCMP/GT FRm, FRn {: :} nkeynes@359: FCNVDS FRm, FPUL {: :} nkeynes@359: FCNVSD FPUL, FRn {: :} nkeynes@359: FDIV FRm, FRn {: :} nkeynes@359: FIPR FVm, FVn {: :} nkeynes@359: FLDS FRm, FPUL {: :} nkeynes@359: FLDI0 FRn {: :} nkeynes@359: FLDI1 FRn {: :} nkeynes@359: FLOAT FPUL, FRn {: :} nkeynes@359: FMAC FR0, FRm, FRn {: :} nkeynes@359: FMOV FRm, FRn {: :} nkeynes@359: FMOV FRm, @Rn {: :} nkeynes@359: FMOV FRm, @-Rn {: :} nkeynes@359: FMOV FRm, @(R0, Rn) {: :} nkeynes@359: FMOV @Rm, FRn {: :} nkeynes@359: FMOV @Rm+, FRn {: :} nkeynes@359: FMOV @(R0, Rm), FRn {: :} nkeynes@359: FMUL FRm, FRn {: :} nkeynes@359: FNEG FRn {: :} nkeynes@359: FRCHG {: :} nkeynes@359: FSCA FPUL, FRn {: :} nkeynes@359: FSCHG {: :} nkeynes@359: FSQRT FRn {: :} nkeynes@359: FSRRA FRn {: :} nkeynes@359: FSTS FPUL, FRn {: :} nkeynes@359: FSUB FRm, FRn {: :} nkeynes@359: FTRC FRm, FPUL {: :} nkeynes@359: FTRV XMTRX, FVn {: :} nkeynes@359: nkeynes@359: /* Processor control instructions */ nkeynes@359: LDC Rm, SR {: /* We need to be a little careful about SR */ :} 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@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_VBR ); nkeynes@359: :} nkeynes@359: LDC Rm, SSR {: nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_SSR ); nkeynes@359: :} nkeynes@359: LDC Rm, SGR {: nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_SGR ); nkeynes@359: :} nkeynes@359: LDC Rm, SPC {: nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_SPC ); nkeynes@359: :} nkeynes@359: LDC Rm, DBR {: nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_DBR ); nkeynes@359: :} nkeynes@359: LDC Rm, Rn_BANK {: :} nkeynes@359: LDC.L @Rm+, GBR {: nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@359: ADD_imm8s_r32( 4, R_EAX ); nkeynes@359: store_reg( R_EAX, Rm ); nkeynes@359: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_GBR ); nkeynes@359: :} nkeynes@359: LDC.L @Rm+, SR {: nkeynes@359: :} nkeynes@359: LDC.L @Rm+, VBR {: nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@359: ADD_imm8s_r32( 4, R_EAX ); nkeynes@359: store_reg( R_EAX, Rm ); nkeynes@359: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_VBR ); nkeynes@359: :} nkeynes@359: LDC.L @Rm+, SSR {: nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@359: ADD_imm8s_r32( 4, R_EAX ); nkeynes@359: store_reg( R_EAX, Rm ); nkeynes@359: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_SSR ); nkeynes@359: :} nkeynes@359: LDC.L @Rm+, SGR {: nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@359: ADD_imm8s_r32( 4, R_EAX ); nkeynes@359: store_reg( R_EAX, Rm ); nkeynes@359: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_SGR ); nkeynes@359: :} nkeynes@359: LDC.L @Rm+, SPC {: nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@359: ADD_imm8s_r32( 4, R_EAX ); nkeynes@359: store_reg( R_EAX, Rm ); nkeynes@359: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_SPC ); nkeynes@359: :} nkeynes@359: LDC.L @Rm+, DBR {: nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@359: ADD_imm8s_r32( 4, R_EAX ); nkeynes@359: store_reg( R_EAX, Rm ); nkeynes@359: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_DBR ); nkeynes@359: :} nkeynes@359: LDC.L @Rm+, Rn_BANK {: nkeynes@359: :} nkeynes@359: LDS Rm, FPSCR {: nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_FPSCR ); nkeynes@359: :} nkeynes@359: LDS.L @Rm+, FPSCR {: nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@359: ADD_imm8s_r32( 4, R_EAX ); nkeynes@359: store_reg( R_EAX, Rm ); nkeynes@359: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_FPSCR ); 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@359: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@359: ADD_imm8s_r32( 4, R_EAX ); nkeynes@359: store_reg( R_EAX, Rm ); nkeynes@359: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_FPUL ); 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@359: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@359: ADD_imm8s_r32( 4, R_EAX ); nkeynes@359: store_reg( R_EAX, Rm ); nkeynes@359: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_MACH ); 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@359: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@359: ADD_imm8s_r32( 4, R_EAX ); nkeynes@359: store_reg( R_EAX, Rm ); nkeynes@359: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_MACL ); 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@359: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@359: ADD_imm8s_r32( 4, R_EAX ); nkeynes@359: store_reg( R_EAX, Rm ); nkeynes@359: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_PR ); nkeynes@359: :} nkeynes@359: LDTLB {: :} nkeynes@359: OCBI @Rn {: :} nkeynes@359: OCBP @Rn {: :} nkeynes@359: OCBWB @Rn {: :} nkeynes@359: PREF @Rn {: :} nkeynes@359: SLEEP {: :} nkeynes@359: STC SR, Rn {: /* TODO */ 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@359: load_spreg( R_EAX, R_VBR ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: STC SSR, Rn {: nkeynes@359: load_spreg( R_EAX, R_SSR ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: STC SPC, Rn {: nkeynes@359: load_spreg( R_EAX, R_SPC ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: STC SGR, Rn {: nkeynes@359: load_spreg( R_EAX, R_SGR ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: STC DBR, Rn {: nkeynes@359: load_spreg( R_EAX, R_DBR ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: :} nkeynes@359: STC Rm_BANK, Rn {: /* TODO */ nkeynes@359: :} nkeynes@359: STC.L SR, @-Rn {: /* TODO */ nkeynes@359: :} nkeynes@359: STC.L VBR, @-Rn {: nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: ADD_imm8s_r32( -4, Rn ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: load_spreg( R_EAX, R_VBR ); nkeynes@359: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@359: :} nkeynes@359: STC.L SSR, @-Rn {: nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: ADD_imm8s_r32( -4, Rn ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: load_spreg( R_EAX, R_SSR ); nkeynes@359: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@359: :} nkeynes@359: STC.L SPC, @-Rn {: nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: ADD_imm8s_r32( -4, Rn ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: load_spreg( R_EAX, R_SPC ); nkeynes@359: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@359: :} nkeynes@359: STC.L SGR, @-Rn {: nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: ADD_imm8s_r32( -4, Rn ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: load_spreg( R_EAX, R_SGR ); nkeynes@359: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@359: :} nkeynes@359: STC.L DBR, @-Rn {: nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: ADD_imm8s_r32( -4, Rn ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: load_spreg( R_EAX, R_DBR ); nkeynes@359: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@359: :} nkeynes@359: STC.L Rm_BANK, @-Rn {: :} nkeynes@359: STC.L GBR, @-Rn {: nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: ADD_imm8s_r32( -4, Rn ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: load_spreg( R_EAX, R_GBR ); nkeynes@359: MEM_WRITE_LONG( R_ECX, R_EAX ); 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@359: load_reg( R_ECX, Rn ); nkeynes@359: ADD_imm8s_r32( -4, Rn ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: load_spreg( R_EAX, R_FPSCR ); nkeynes@359: MEM_WRITE_LONG( R_ECX, R_EAX ); 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@359: load_reg( R_ECX, Rn ); nkeynes@359: ADD_imm8s_r32( -4, Rn ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: load_spreg( R_EAX, R_FPUL ); nkeynes@359: MEM_WRITE_LONG( R_ECX, R_EAX ); 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@359: load_reg( R_ECX, Rn ); nkeynes@359: ADD_imm8s_r32( -4, Rn ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: load_spreg( R_EAX, R_MACH ); nkeynes@359: MEM_WRITE_LONG( R_ECX, R_EAX ); 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@359: load_reg( R_ECX, Rn ); nkeynes@359: ADD_imm8s_r32( -4, Rn ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: load_spreg( R_EAX, R_MACL ); nkeynes@359: MEM_WRITE_LONG( R_ECX, R_EAX ); 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@359: load_reg( R_ECX, Rn ); nkeynes@359: ADD_imm8s_r32( -4, Rn ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: load_spreg( R_EAX, R_PR ); nkeynes@359: MEM_WRITE_LONG( R_ECX, R_EAX ); 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@359: nkeynes@359: return 0; nkeynes@359: }