nkeynes@359: /** nkeynes@408: * $Id: sh4x86.in,v 1.16 2007-09-28 07:27:20 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@368: #include nkeynes@388: #include nkeynes@368: nkeynes@380: #ifndef NDEBUG nkeynes@380: #define DEBUG_JUMPS 1 nkeynes@380: #endif nkeynes@380: 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@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@368: gboolean 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@408: uint32_t block_start_pc; nkeynes@368: nkeynes@368: /* Allocated memory for the (block-wide) back-patch list */ nkeynes@368: uint32_t **backpatch_list; nkeynes@368: uint32_t backpatch_posn; nkeynes@368: uint32_t backpatch_size; nkeynes@368: }; nkeynes@368: nkeynes@368: #define EXIT_DATA_ADDR_READ 0 nkeynes@368: #define EXIT_DATA_ADDR_WRITE 7 nkeynes@368: #define EXIT_ILLEGAL 14 nkeynes@368: #define EXIT_SLOT_ILLEGAL 21 nkeynes@368: #define EXIT_FPU_DISABLED 28 nkeynes@368: #define EXIT_SLOT_FPU_DISABLED 35 nkeynes@368: 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@368: sh4_x86.backpatch_size = DEFAULT_BACKPATCH_SIZE / sizeof(uint32_t *); nkeynes@368: } nkeynes@368: nkeynes@368: nkeynes@368: static void sh4_x86_add_backpatch( uint8_t *ptr ) nkeynes@368: { nkeynes@368: if( sh4_x86.backpatch_posn == sh4_x86.backpatch_size ) { nkeynes@368: sh4_x86.backpatch_size <<= 1; nkeynes@368: sh4_x86.backpatch_list = realloc( sh4_x86.backpatch_list, sh4_x86.backpatch_size * sizeof(uint32_t *) ); nkeynes@368: assert( sh4_x86.backpatch_list != NULL ); nkeynes@368: } nkeynes@368: sh4_x86.backpatch_list[sh4_x86.backpatch_posn++] = (uint32_t *)ptr; nkeynes@368: } nkeynes@368: nkeynes@368: static void sh4_x86_do_backpatch( uint8_t *reloc_base ) nkeynes@368: { nkeynes@368: unsigned int i; nkeynes@368: for( i=0; i>1)*sh4_cpu_period ); // 5 nkeynes@408: ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6 nkeynes@374: POP_r32(R_ESI); nkeynes@374: POP_r32(R_EBP); nkeynes@368: RET(); nkeynes@359: } nkeynes@359: nkeynes@359: /** nkeynes@408: * Exit the block with sh4r.pc already written nkeynes@408: * Bytes: 16 nkeynes@408: */ nkeynes@408: void exit_block_pcset( pc ) nkeynes@408: { nkeynes@408: XOR_r32_r32( R_EAX, R_EAX ); // 2 nkeynes@408: load_imm32( R_ECX, ((pc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5 nkeynes@408: ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6 nkeynes@408: POP_r32(R_ESI); nkeynes@408: POP_r32(R_EBP); nkeynes@408: RET(); nkeynes@408: } nkeynes@408: nkeynes@408: /** nkeynes@408: * Write the block trailer (exception handling block) nkeynes@359: */ nkeynes@359: void sh4_translate_end_block( sh4addr_t pc ) { nkeynes@388: if( sh4_x86.backpatch_posn != 0 ) { nkeynes@388: uint8_t *end_ptr = xlat_output; nkeynes@388: // Exception termination. Jump block for various exception codes: nkeynes@388: PUSH_imm32( EXC_DATA_ADDR_READ ); nkeynes@388: JMP_rel8( 33, target1 ); nkeynes@388: PUSH_imm32( EXC_DATA_ADDR_WRITE ); nkeynes@388: JMP_rel8( 26, target2 ); nkeynes@388: PUSH_imm32( EXC_ILLEGAL ); nkeynes@388: JMP_rel8( 19, target3 ); nkeynes@388: PUSH_imm32( EXC_SLOT_ILLEGAL ); nkeynes@388: JMP_rel8( 12, target4 ); nkeynes@388: PUSH_imm32( EXC_FPU_DISABLED ); nkeynes@388: JMP_rel8( 5, target5 ); nkeynes@388: PUSH_imm32( EXC_SLOT_FPU_DISABLED ); nkeynes@388: // target nkeynes@388: JMP_TARGET(target1); nkeynes@388: JMP_TARGET(target2); nkeynes@388: JMP_TARGET(target3); nkeynes@388: JMP_TARGET(target4); nkeynes@388: JMP_TARGET(target5); nkeynes@388: load_spreg( R_ECX, REG_OFFSET(pc) ); nkeynes@388: ADD_r32_r32( R_ESI, R_ECX ); nkeynes@388: ADD_r32_r32( R_ESI, R_ECX ); nkeynes@388: store_spreg( R_ECX, REG_OFFSET(pc) ); nkeynes@388: MOV_moff32_EAX( (uint32_t)&sh4_cpu_period ); nkeynes@388: load_spreg( R_ECX, REG_OFFSET(slice_cycle) ); nkeynes@388: MUL_r32( R_ESI ); nkeynes@388: ADD_r32_r32( R_EAX, R_ECX ); nkeynes@388: store_spreg( R_ECX, REG_OFFSET(slice_cycle) ); nkeynes@388: nkeynes@388: load_imm32( R_EAX, (uint32_t)sh4_raise_exception ); // 6 nkeynes@388: CALL_r32( R_EAX ); // 2 nkeynes@388: ADD_imm8s_r32( 4, R_ESP ); nkeynes@408: XOR_r32_r32( R_EAX, R_EAX ); nkeynes@388: POP_r32(R_ESI); nkeynes@388: POP_r32(R_EBP); nkeynes@388: RET(); nkeynes@368: nkeynes@388: sh4_x86_do_backpatch( end_ptr ); nkeynes@388: } nkeynes@368: nkeynes@359: } nkeynes@359: nkeynes@388: nkeynes@388: extern uint16_t *sh4_icache; nkeynes@388: extern uint32_t sh4_icache_addr; nkeynes@388: 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@408: uint32_t sh4_x86_translate_instruction( sh4addr_t pc ) nkeynes@359: { nkeynes@388: uint32_t ir; nkeynes@388: /* Read instruction */ nkeynes@388: uint32_t pageaddr = pc >> 12; nkeynes@388: if( sh4_icache != NULL && pageaddr == sh4_icache_addr ) { nkeynes@388: ir = sh4_icache[(pc&0xFFF)>>1]; nkeynes@388: } else { nkeynes@388: sh4_icache = (uint16_t *)mem_get_page(pc); nkeynes@388: if( ((uint32_t)sh4_icache) < MAX_IO_REGIONS ) { nkeynes@388: /* If someone's actually been so daft as to try to execute out of an IO nkeynes@388: * region, fallback on the full-blown memory read nkeynes@388: */ nkeynes@388: sh4_icache = NULL; nkeynes@388: ir = sh4_read_word(pc); nkeynes@388: } else { nkeynes@388: sh4_icache_addr = pageaddr; nkeynes@388: ir = sh4_icache[(pc&0xFFF)>>1]; nkeynes@388: } nkeynes@388: } 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@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: 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@374: ADD_r32_r32( R_EAX, R_ECX ); nkeynes@386: PUSH_r32(R_ECX); nkeynes@386: call_func0(sh4_read_byte); nkeynes@386: POP_r32(R_ECX); nkeynes@386: AND_imm32_r32(imm, R_EAX ); 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@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@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@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@361: :} nkeynes@386: DIV1 Rm, Rn {: nkeynes@386: load_spreg( R_ECX, R_M ); nkeynes@386: load_reg( R_EAX, Rn ); nkeynes@374: LDC_t(); 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@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@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@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@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@386: MAC.L @Rm+, @Rn+ {: nkeynes@386: load_reg( R_ECX, Rm ); nkeynes@386: check_ralign32( R_ECX ); nkeynes@386: load_reg( R_ECX, Rn ); nkeynes@386: check_ralign32( R_ECX ); nkeynes@386: ADD_imm8s_sh4r( 4, REG_OFFSET(r[Rn]) ); nkeynes@386: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@386: PUSH_r32( R_EAX ); nkeynes@386: load_reg( R_ECX, Rm ); nkeynes@386: ADD_imm8s_sh4r( 4, REG_OFFSET(r[Rm]) ); nkeynes@386: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@386: POP_r32( R_ECX ); 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@386: JE_rel8( 7, nosat ); nkeynes@386: call_func0( signsat48 ); nkeynes@386: JMP_TARGET( nosat ); nkeynes@386: :} nkeynes@386: MAC.W @Rm+, @Rn+ {: nkeynes@386: load_reg( R_ECX, Rm ); nkeynes@386: check_ralign16( R_ECX ); nkeynes@386: load_reg( R_ECX, Rn ); nkeynes@386: check_ralign16( R_ECX ); nkeynes@386: ADD_imm8s_sh4r( 2, REG_OFFSET(r[Rn]) ); nkeynes@386: MEM_READ_WORD( R_ECX, R_EAX ); nkeynes@386: PUSH_r32( R_EAX ); nkeynes@386: load_reg( R_ECX, Rm ); nkeynes@386: ADD_imm8s_sh4r( 2, REG_OFFSET(r[Rm]) ); nkeynes@386: MEM_READ_WORD( R_ECX, R_EAX ); nkeynes@386: POP_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@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@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@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@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@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@374: OR.B #imm, @(R0, GBR) {: nkeynes@374: load_reg( R_EAX, 0 ); nkeynes@374: load_spreg( R_ECX, R_GBR ); nkeynes@374: ADD_r32_r32( R_EAX, R_ECX ); nkeynes@386: PUSH_r32(R_ECX); nkeynes@386: call_func0(sh4_read_byte); nkeynes@386: POP_r32(R_ECX); nkeynes@386: OR_imm32_r32(imm, R_EAX ); nkeynes@374: MEM_WRITE_BYTE( R_ECX, R_EAX ); nkeynes@374: :} 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@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@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@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@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@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@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@397: SETC_t(); 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@394: SETC_t(); 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@361: TAS.B @Rn {: nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@361: MEM_READ_BYTE( R_ECX, R_EAX ); nkeynes@361: TEST_r8_r8( R_AL, R_AL ); nkeynes@361: SETE_t(); nkeynes@361: OR_imm8_r8( 0x80, R_AL ); nkeynes@386: load_reg( R_ECX, Rn ); nkeynes@361: MEM_WRITE_BYTE( R_ECX, R_EAX ); 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@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@368: :} nkeynes@368: TST.B #imm, @(R0, GBR) {: nkeynes@368: load_reg( R_EAX, 0); nkeynes@368: load_reg( R_ECX, R_GBR); nkeynes@368: ADD_r32_r32( R_EAX, R_ECX ); nkeynes@368: MEM_READ_BYTE( R_ECX, R_EAX ); nkeynes@394: TEST_imm8_r8( imm, R_AL ); nkeynes@368: SETE_t(); 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@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@386: PUSH_r32(R_ECX); nkeynes@386: call_func0(sh4_read_byte); nkeynes@386: POP_r32(R_ECX); nkeynes@359: XOR_imm32_r32( imm, R_EAX ); nkeynes@359: MEM_WRITE_BYTE( R_ECX, R_EAX ); 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@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@382: ADD_imm8s_r32( -1, R_ECX ); 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@386: store_reg( R_EAX, 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@374: MOV.L Rm, @Rn {: nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@374: check_walign32(R_ECX); nkeynes@361: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@361: :} nkeynes@361: MOV.L Rm, @-Rn {: nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@374: check_walign32( R_ECX ); nkeynes@361: ADD_imm8s_r32( -4, R_ECX ); nkeynes@361: store_reg( R_ECX, Rn ); nkeynes@361: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@361: :} nkeynes@361: MOV.L Rm, @(R0, Rn) {: nkeynes@361: load_reg( R_EAX, 0 ); nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@361: ADD_r32_r32( R_EAX, R_ECX ); nkeynes@374: check_walign32( R_ECX ); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@361: :} nkeynes@361: MOV.L R0, @(disp, GBR) {: nkeynes@361: load_spreg( R_ECX, R_GBR ); nkeynes@361: load_reg( R_EAX, 0 ); nkeynes@361: ADD_imm32_r32( disp, R_ECX ); nkeynes@374: check_walign32( R_ECX ); nkeynes@361: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@361: :} nkeynes@361: MOV.L Rm, @(disp, Rn) {: nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: ADD_imm32_r32( disp, R_ECX ); nkeynes@374: check_walign32( R_ECX ); nkeynes@361: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@361: :} nkeynes@361: MOV.L @Rm, Rn {: nkeynes@361: load_reg( R_ECX, Rm ); nkeynes@374: check_ralign32( R_ECX ); nkeynes@361: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); nkeynes@361: :} nkeynes@361: MOV.L @Rm+, Rn {: nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@382: check_ralign32( R_EAX ); nkeynes@361: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@361: ADD_imm8s_r32( 4, R_EAX ); nkeynes@361: store_reg( R_EAX, Rm ); nkeynes@361: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); nkeynes@361: :} nkeynes@361: MOV.L @(R0, Rm), Rn {: nkeynes@361: load_reg( R_EAX, 0 ); nkeynes@361: load_reg( R_ECX, Rm ); nkeynes@361: ADD_r32_r32( R_EAX, R_ECX ); nkeynes@374: check_ralign32( R_ECX ); nkeynes@361: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); nkeynes@361: :} nkeynes@361: MOV.L @(disp, GBR), R0 {: nkeynes@361: load_spreg( R_ECX, R_GBR ); nkeynes@361: ADD_imm32_r32( disp, R_ECX ); nkeynes@374: check_ralign32( R_ECX ); nkeynes@361: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@361: store_reg( R_EAX, 0 ); 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@388: char *ptr = mem_get_region(target); nkeynes@388: if( ptr != NULL ) { nkeynes@388: MOV_moff32_EAX( (uint32_t)ptr ); nkeynes@388: } else { nkeynes@388: load_imm32( R_ECX, target ); nkeynes@388: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@388: } nkeynes@382: store_reg( R_EAX, Rn ); nkeynes@374: } nkeynes@361: :} nkeynes@361: MOV.L @(disp, Rm), Rn {: nkeynes@361: load_reg( R_ECX, Rm ); nkeynes@361: ADD_imm8s_r32( disp, R_ECX ); nkeynes@374: check_ralign32( R_ECX ); nkeynes@361: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); nkeynes@361: :} nkeynes@361: MOV.W Rm, @Rn {: nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@374: check_walign16( R_ECX ); nkeynes@382: load_reg( R_EAX, Rm ); nkeynes@382: MEM_WRITE_WORD( R_ECX, R_EAX ); nkeynes@361: :} nkeynes@361: MOV.W Rm, @-Rn {: nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@374: check_walign16( R_ECX ); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: ADD_imm8s_r32( -2, R_ECX ); nkeynes@382: store_reg( R_ECX, Rn ); nkeynes@361: MEM_WRITE_WORD( R_ECX, R_EAX ); nkeynes@361: :} nkeynes@361: MOV.W Rm, @(R0, Rn) {: nkeynes@361: load_reg( R_EAX, 0 ); nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@361: ADD_r32_r32( R_EAX, R_ECX ); nkeynes@374: check_walign16( R_ECX ); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: MEM_WRITE_WORD( R_ECX, R_EAX ); nkeynes@361: :} nkeynes@361: MOV.W R0, @(disp, GBR) {: nkeynes@361: load_spreg( R_ECX, R_GBR ); nkeynes@361: load_reg( R_EAX, 0 ); nkeynes@361: ADD_imm32_r32( disp, R_ECX ); nkeynes@374: check_walign16( R_ECX ); nkeynes@361: MEM_WRITE_WORD( R_ECX, R_EAX ); nkeynes@361: :} nkeynes@361: MOV.W R0, @(disp, Rn) {: nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@361: load_reg( R_EAX, 0 ); nkeynes@361: ADD_imm32_r32( disp, R_ECX ); nkeynes@374: check_walign16( R_ECX ); nkeynes@361: MEM_WRITE_WORD( R_ECX, R_EAX ); nkeynes@361: :} nkeynes@361: MOV.W @Rm, Rn {: nkeynes@361: load_reg( R_ECX, Rm ); nkeynes@374: check_ralign16( R_ECX ); nkeynes@361: MEM_READ_WORD( R_ECX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); nkeynes@361: :} nkeynes@361: MOV.W @Rm+, Rn {: nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@374: check_ralign16( R_EAX ); nkeynes@361: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@361: ADD_imm8s_r32( 2, R_EAX ); nkeynes@361: store_reg( R_EAX, Rm ); nkeynes@361: MEM_READ_WORD( R_ECX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); nkeynes@361: :} nkeynes@361: MOV.W @(R0, Rm), Rn {: nkeynes@361: load_reg( R_EAX, 0 ); nkeynes@361: load_reg( R_ECX, Rm ); nkeynes@361: ADD_r32_r32( R_EAX, R_ECX ); nkeynes@374: check_ralign16( R_ECX ); nkeynes@361: MEM_READ_WORD( R_ECX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); nkeynes@361: :} nkeynes@361: MOV.W @(disp, GBR), R0 {: nkeynes@361: load_spreg( R_ECX, R_GBR ); nkeynes@361: ADD_imm32_r32( disp, R_ECX ); nkeynes@374: check_ralign16( R_ECX ); nkeynes@361: MEM_READ_WORD( R_ECX, R_EAX ); nkeynes@361: store_reg( R_EAX, 0 ); nkeynes@361: :} nkeynes@361: MOV.W @(disp, PC), Rn {: nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@374: load_imm32( R_ECX, pc + disp + 4 ); nkeynes@374: MEM_READ_WORD( R_ECX, R_EAX ); nkeynes@374: store_reg( R_EAX, Rn ); nkeynes@374: } nkeynes@361: :} nkeynes@361: MOV.W @(disp, Rm), R0 {: nkeynes@361: load_reg( R_ECX, Rm ); nkeynes@361: ADD_imm32_r32( disp, R_ECX ); nkeynes@374: check_ralign16( R_ECX ); nkeynes@361: MEM_READ_WORD( R_ECX, R_EAX ); nkeynes@361: store_reg( R_EAX, 0 ); nkeynes@361: :} nkeynes@361: MOVA @(disp, PC), R0 {: nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@374: load_imm32( R_ECX, (pc & 0xFFFFFFFC) + disp + 4 ); nkeynes@374: store_reg( R_ECX, 0 ); nkeynes@374: } nkeynes@361: :} nkeynes@361: MOVCA.L R0, @Rn {: nkeynes@361: load_reg( R_EAX, 0 ); nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@374: check_walign32( R_ECX ); nkeynes@361: MEM_WRITE_LONG( R_ECX, R_EAX ); 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@374: CMP_imm8s_sh4r( 0, R_T ); nkeynes@408: JNE_rel8( 30, nottaken ); nkeynes@408: exit_block( disp + pc + 4, pc+2 ); nkeynes@380: JMP_TARGET(nottaken); nkeynes@408: exit_block( pc + 2, pc + 2 ); 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@408: sh4_x86.in_delay_slot = TRUE; nkeynes@374: CMP_imm8s_sh4r( 0, R_T ); nkeynes@408: OP(0x0F); OP(0x85); uint32_t *patch = (uint32_t *)xlat_output; OP32(0); // JNE rel32 nkeynes@408: sh4_x86_translate_instruction(pc+2); nkeynes@408: exit_block( disp + pc + 4, pc+4 ); nkeynes@408: // not taken nkeynes@408: *patch = (xlat_output - ((uint8_t *)patch)) - 4; nkeynes@408: sh4_x86_translate_instruction(pc+2); nkeynes@408: exit_block( pc + 4, pc+4 ); 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@374: sh4_x86.in_delay_slot = TRUE; nkeynes@408: sh4_x86_translate_instruction( pc + 2 ); nkeynes@408: exit_block( disp + pc + 4, pc+4 ); 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@408: load_reg( R_EAX, Rn ); nkeynes@408: ADD_imm32_r32( pc + 4, R_EAX ); nkeynes@408: store_spreg( R_EAX, REG_OFFSET(pc) ); nkeynes@374: sh4_x86.in_delay_slot = TRUE; nkeynes@408: sh4_x86_translate_instruction( pc + 2 ); nkeynes@408: exit_block_pcset(pc+2); 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@374: load_imm32( R_EAX, pc + 4 ); nkeynes@374: store_spreg( R_EAX, R_PR ); nkeynes@374: sh4_x86.in_delay_slot = TRUE; nkeynes@408: sh4_x86_translate_instruction( pc + 2 ); nkeynes@408: exit_block( disp + pc + 4, pc+4 ); 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@408: load_imm32( R_ECX, pc + 4 ); nkeynes@408: store_spreg( R_ECX, R_PR ); nkeynes@408: ADD_sh4r_r32( REG_OFFSET(r[Rn]), R_ECX ); nkeynes@408: store_spreg( R_ECX, REG_OFFSET(pc) ); nkeynes@374: sh4_x86.in_delay_slot = TRUE; nkeynes@408: sh4_x86_translate_instruction( pc + 2 ); nkeynes@408: exit_block_pcset(pc+2); 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@374: CMP_imm8s_sh4r( 0, R_T ); nkeynes@408: JE_rel8( 30, nottaken ); nkeynes@408: exit_block( disp + pc + 4, pc+2 ); nkeynes@380: JMP_TARGET(nottaken); nkeynes@408: exit_block( pc + 2, pc+2 ); 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@408: sh4_x86.in_delay_slot = TRUE; nkeynes@374: CMP_imm8s_sh4r( 0, R_T ); nkeynes@408: OP(0x0F); OP(0x84); uint32_t *patch = (uint32_t *)xlat_output; OP32(0); // JE rel32 nkeynes@408: sh4_x86_translate_instruction(pc+2); nkeynes@408: exit_block( disp + pc + 4, pc+4 ); nkeynes@408: // not taken nkeynes@408: *patch = (xlat_output - ((uint8_t *)patch)) - 4; nkeynes@408: sh4_x86_translate_instruction(pc+2); nkeynes@408: exit_block( pc + 4, pc+4 ); 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@408: store_spreg( R_ECX, REG_OFFSET(pc) ); nkeynes@374: sh4_x86.in_delay_slot = TRUE; nkeynes@408: sh4_x86_translate_instruction(pc+2); nkeynes@408: exit_block_pcset(pc+2); 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@374: load_imm32( R_EAX, pc + 4 ); nkeynes@374: store_spreg( R_EAX, R_PR ); nkeynes@408: load_reg( R_ECX, Rn ); nkeynes@408: store_spreg( R_ECX, REG_OFFSET(pc) ); nkeynes@374: sh4_x86.in_delay_slot = TRUE; nkeynes@408: sh4_x86_translate_instruction(pc+2); nkeynes@408: exit_block_pcset(pc+2); 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@408: store_spreg( R_ECX, REG_OFFSET(pc) ); nkeynes@374: load_spreg( R_EAX, R_SSR ); nkeynes@374: call_func1( sh4_write_sr, R_EAX ); nkeynes@374: sh4_x86.in_delay_slot = TRUE; nkeynes@377: sh4_x86.priv_checked = FALSE; nkeynes@377: sh4_x86.fpuen_checked = FALSE; nkeynes@408: sh4_x86_translate_instruction(pc+2); nkeynes@408: exit_block_pcset(pc+2); 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@408: store_spreg( R_ECX, REG_OFFSET(pc) ); nkeynes@374: sh4_x86.in_delay_slot = TRUE; nkeynes@408: sh4_x86_translate_instruction(pc+2); nkeynes@408: exit_block_pcset(pc+2); 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@388: PUSH_imm32( imm ); nkeynes@388: call_func0( sh4_raise_trap ); nkeynes@388: ADD_imm8s_r32( 4, R_ESP ); nkeynes@408: exit_block_pcset(pc); 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@386: JMP_exit(EXIT_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@368: :} nkeynes@374: CLRS {: nkeynes@374: CLC(); nkeynes@374: SETC_sh4r(R_S); nkeynes@368: :} nkeynes@374: CLRT {: nkeynes@374: CLC(); nkeynes@374: SETC_t(); nkeynes@359: :} nkeynes@374: SETS {: nkeynes@374: STC(); nkeynes@374: SETC_sh4r(R_S); nkeynes@359: :} nkeynes@374: SETT {: nkeynes@374: STC(); nkeynes@374: SETC_t(); 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@375: :} nkeynes@375: FMOV FRm, @Rn {: nkeynes@377: check_fpuen(); nkeynes@375: load_reg( R_EDX, Rn ); nkeynes@375: check_walign32( R_EDX ); nkeynes@375: load_spreg( R_ECX, R_FPSCR ); nkeynes@375: TEST_imm32_r32( FPSCR_SZ, R_ECX ); nkeynes@380: JNE_rel8(20, doublesize); nkeynes@377: load_fr_bank( R_ECX ); nkeynes@375: load_fr( R_ECX, R_EAX, FRm ); nkeynes@375: MEM_WRITE_LONG( R_EDX, R_EAX ); // 12 nkeynes@375: if( FRm&1 ) { nkeynes@386: JMP_rel8( 48, end ); nkeynes@380: JMP_TARGET(doublesize); nkeynes@375: load_xf_bank( R_ECX ); nkeynes@380: load_fr( R_ECX, R_EAX, FRm&0x0E ); nkeynes@380: load_fr( R_ECX, R_ECX, FRm|0x01 ); nkeynes@380: MEM_WRITE_DOUBLE( R_EDX, R_EAX, R_ECX ); nkeynes@380: JMP_TARGET(end); nkeynes@375: } else { nkeynes@380: JMP_rel8( 39, end ); nkeynes@380: JMP_TARGET(doublesize); nkeynes@377: load_fr_bank( R_ECX ); nkeynes@380: load_fr( R_ECX, R_EAX, FRm&0x0E ); nkeynes@380: load_fr( R_ECX, R_ECX, FRm|0x01 ); nkeynes@380: MEM_WRITE_DOUBLE( R_EDX, R_EAX, R_ECX ); nkeynes@380: JMP_TARGET(end); nkeynes@375: } nkeynes@375: :} nkeynes@375: FMOV @Rm, FRn {: nkeynes@377: check_fpuen(); nkeynes@375: load_reg( R_EDX, Rm ); nkeynes@375: check_ralign32( R_EDX ); nkeynes@375: load_spreg( R_ECX, R_FPSCR ); nkeynes@375: TEST_imm32_r32( FPSCR_SZ, R_ECX ); nkeynes@380: JNE_rel8(19, doublesize); nkeynes@375: MEM_READ_LONG( R_EDX, R_EAX ); nkeynes@377: load_fr_bank( R_ECX ); nkeynes@375: store_fr( R_ECX, R_EAX, FRn ); nkeynes@375: if( FRn&1 ) { nkeynes@386: JMP_rel8(48, end); nkeynes@380: JMP_TARGET(doublesize); nkeynes@375: MEM_READ_DOUBLE( R_EDX, R_EAX, R_EDX ); nkeynes@375: load_spreg( R_ECX, R_FPSCR ); // assume read_long clobbered it nkeynes@375: load_xf_bank( R_ECX ); nkeynes@380: store_fr( R_ECX, R_EAX, FRn&0x0E ); nkeynes@380: store_fr( R_ECX, R_EDX, FRn|0x01 ); nkeynes@380: JMP_TARGET(end); nkeynes@375: } else { nkeynes@380: JMP_rel8(36, end); nkeynes@380: JMP_TARGET(doublesize); nkeynes@375: MEM_READ_DOUBLE( R_EDX, R_EAX, R_EDX ); nkeynes@377: load_fr_bank( R_ECX ); nkeynes@380: store_fr( R_ECX, R_EAX, FRn&0x0E ); nkeynes@380: store_fr( R_ECX, R_EDX, FRn|0x01 ); nkeynes@380: JMP_TARGET(end); nkeynes@375: } nkeynes@375: :} nkeynes@377: FMOV FRm, @-Rn {: nkeynes@377: check_fpuen(); nkeynes@377: load_reg( R_EDX, Rn ); nkeynes@377: check_walign32( R_EDX ); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_SZ, R_ECX ); nkeynes@382: JNE_rel8(26, doublesize); nkeynes@377: load_fr_bank( R_ECX ); nkeynes@377: load_fr( R_ECX, R_EAX, FRm ); nkeynes@377: ADD_imm8s_r32(-4,R_EDX); nkeynes@377: store_reg( R_EDX, Rn ); nkeynes@377: MEM_WRITE_LONG( R_EDX, R_EAX ); // 12 nkeynes@377: if( FRm&1 ) { nkeynes@386: JMP_rel8( 54, end ); nkeynes@380: JMP_TARGET(doublesize); nkeynes@377: load_xf_bank( R_ECX ); nkeynes@380: load_fr( R_ECX, R_EAX, FRm&0x0E ); nkeynes@380: load_fr( R_ECX, R_ECX, FRm|0x01 ); nkeynes@380: ADD_imm8s_r32(-8,R_EDX); nkeynes@380: store_reg( R_EDX, Rn ); nkeynes@380: MEM_WRITE_DOUBLE( R_EDX, R_EAX, R_ECX ); nkeynes@380: JMP_TARGET(end); nkeynes@377: } else { nkeynes@382: JMP_rel8( 45, end ); nkeynes@380: JMP_TARGET(doublesize); nkeynes@377: load_fr_bank( R_ECX ); nkeynes@380: load_fr( R_ECX, R_EAX, FRm&0x0E ); nkeynes@380: load_fr( R_ECX, R_ECX, FRm|0x01 ); nkeynes@380: ADD_imm8s_r32(-8,R_EDX); nkeynes@380: store_reg( R_EDX, Rn ); nkeynes@380: MEM_WRITE_DOUBLE( R_EDX, R_EAX, R_ECX ); nkeynes@380: JMP_TARGET(end); nkeynes@377: } nkeynes@377: :} nkeynes@377: FMOV @Rm+, FRn {: nkeynes@377: check_fpuen(); nkeynes@377: load_reg( R_EDX, Rm ); nkeynes@377: check_ralign32( R_EDX ); nkeynes@377: MOV_r32_r32( R_EDX, R_EAX ); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_SZ, R_ECX ); nkeynes@380: JNE_rel8(25, doublesize); nkeynes@377: ADD_imm8s_r32( 4, R_EAX ); nkeynes@377: store_reg( R_EAX, Rm ); nkeynes@377: MEM_READ_LONG( R_EDX, R_EAX ); nkeynes@377: load_fr_bank( R_ECX ); nkeynes@377: store_fr( R_ECX, R_EAX, FRn ); nkeynes@377: if( FRn&1 ) { nkeynes@386: JMP_rel8(54, end); nkeynes@380: JMP_TARGET(doublesize); nkeynes@377: ADD_imm8s_r32( 8, R_EAX ); nkeynes@377: store_reg(R_EAX, Rm); nkeynes@377: MEM_READ_DOUBLE( R_EDX, R_EAX, R_EDX ); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); // assume read_long clobbered it nkeynes@377: load_xf_bank( R_ECX ); nkeynes@380: store_fr( R_ECX, R_EAX, FRn&0x0E ); nkeynes@380: store_fr( R_ECX, R_EDX, FRn|0x01 ); nkeynes@380: JMP_TARGET(end); nkeynes@377: } else { nkeynes@380: JMP_rel8(42, end); nkeynes@377: ADD_imm8s_r32( 8, R_EAX ); nkeynes@377: store_reg(R_EAX, Rm); nkeynes@377: MEM_READ_DOUBLE( R_EDX, R_EAX, R_EDX ); nkeynes@377: load_fr_bank( R_ECX ); nkeynes@380: store_fr( R_ECX, R_EAX, FRn&0x0E ); nkeynes@380: store_fr( R_ECX, R_EDX, FRn|0x01 ); nkeynes@380: JMP_TARGET(end); nkeynes@377: } nkeynes@377: :} nkeynes@377: FMOV FRm, @(R0, Rn) {: nkeynes@377: check_fpuen(); nkeynes@377: load_reg( R_EDX, Rn ); nkeynes@377: ADD_sh4r_r32( REG_OFFSET(r[0]), R_EDX ); nkeynes@377: check_walign32( R_EDX ); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_SZ, R_ECX ); nkeynes@380: JNE_rel8(20, doublesize); nkeynes@377: load_fr_bank( R_ECX ); nkeynes@377: load_fr( R_ECX, R_EAX, FRm ); nkeynes@377: MEM_WRITE_LONG( R_EDX, R_EAX ); // 12 nkeynes@377: if( FRm&1 ) { nkeynes@386: JMP_rel8( 48, end ); nkeynes@380: JMP_TARGET(doublesize); nkeynes@377: load_xf_bank( R_ECX ); nkeynes@380: load_fr( R_ECX, R_EAX, FRm&0x0E ); nkeynes@380: load_fr( R_ECX, R_ECX, FRm|0x01 ); nkeynes@380: MEM_WRITE_DOUBLE( R_EDX, R_EAX, R_ECX ); nkeynes@380: JMP_TARGET(end); nkeynes@377: } else { nkeynes@380: JMP_rel8( 39, end ); nkeynes@380: JMP_TARGET(doublesize); nkeynes@377: load_fr_bank( R_ECX ); nkeynes@380: load_fr( R_ECX, R_EAX, FRm&0x0E ); nkeynes@380: load_fr( R_ECX, R_ECX, FRm|0x01 ); nkeynes@380: MEM_WRITE_DOUBLE( R_EDX, R_EAX, R_ECX ); nkeynes@380: JMP_TARGET(end); nkeynes@377: } nkeynes@377: :} nkeynes@377: FMOV @(R0, Rm), FRn {: nkeynes@377: check_fpuen(); nkeynes@377: load_reg( R_EDX, Rm ); nkeynes@377: ADD_sh4r_r32( REG_OFFSET(r[0]), R_EDX ); nkeynes@377: check_ralign32( R_EDX ); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_SZ, R_ECX ); nkeynes@380: JNE_rel8(19, doublesize); nkeynes@377: MEM_READ_LONG( R_EDX, R_EAX ); nkeynes@377: load_fr_bank( R_ECX ); nkeynes@377: store_fr( R_ECX, R_EAX, FRn ); nkeynes@377: if( FRn&1 ) { nkeynes@386: JMP_rel8(48, end); nkeynes@380: JMP_TARGET(doublesize); nkeynes@377: MEM_READ_DOUBLE( R_EDX, R_EAX, R_EDX ); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); // assume read_long clobbered it nkeynes@377: load_xf_bank( R_ECX ); nkeynes@380: store_fr( R_ECX, R_EAX, FRn&0x0E ); nkeynes@380: store_fr( R_ECX, R_EDX, FRn|0x01 ); nkeynes@380: JMP_TARGET(end); nkeynes@377: } else { nkeynes@380: JMP_rel8(36, end); nkeynes@380: JMP_TARGET(doublesize); nkeynes@377: MEM_READ_DOUBLE( R_EDX, R_EAX, R_EDX ); nkeynes@377: load_fr_bank( R_ECX ); nkeynes@380: store_fr( R_ECX, R_EAX, FRn&0x0E ); nkeynes@380: store_fr( R_ECX, R_EDX, FRn|0x01 ); nkeynes@380: JMP_TARGET(end); nkeynes@377: } 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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@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@388: JNE_rel8( 21, 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@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@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@388: JNE_rel8( 30, 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@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@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@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@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@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@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@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@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@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@374: :} nkeynes@359: LDC.L @Rm+, GBR {: nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@395: check_ralign32( R_EAX ); 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@368: LDC.L @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@395: check_ralign32( R_EAX ); nkeynes@386: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@386: ADD_imm8s_r32( 4, R_EAX ); nkeynes@386: store_reg( R_EAX, Rm ); nkeynes@386: MEM_READ_LONG( R_ECX, 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@386: } nkeynes@359: :} nkeynes@359: LDC.L @Rm+, VBR {: nkeynes@386: check_priv(); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@395: check_ralign32( R_EAX ); 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@386: check_priv(); 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@386: check_priv(); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@395: check_ralign32( R_EAX ); 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@386: check_priv(); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@395: check_ralign32( R_EAX ); 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@386: check_priv(); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@395: check_ralign32( R_EAX ); 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@386: check_priv(); nkeynes@374: load_reg( R_EAX, Rm ); nkeynes@395: check_ralign32( R_EAX ); nkeynes@374: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@374: ADD_imm8s_r32( 4, R_EAX ); nkeynes@374: store_reg( R_EAX, Rm ); nkeynes@374: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@374: store_spreg( R_EAX, REG_OFFSET(r_bank[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@386: update_fr_bank( R_EAX ); nkeynes@359: :} nkeynes@359: LDS.L @Rm+, FPSCR {: nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@395: check_ralign32( R_EAX ); 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@386: update_fr_bank( R_EAX ); 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@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@395: check_ralign32( R_EAX ); 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@395: check_ralign32( R_EAX ); 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@395: check_ralign32( R_EAX ); 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@374: PREF @Rn {: nkeynes@374: load_reg( R_EAX, Rn ); nkeynes@374: PUSH_r32( R_EAX ); nkeynes@374: AND_imm32_r32( 0xFC000000, R_EAX ); nkeynes@374: CMP_imm32_r32( 0xE0000000, R_EAX ); nkeynes@380: JNE_rel8(7, end); nkeynes@374: call_func0( sh4_flush_store_queue ); nkeynes@380: JMP_TARGET(end); nkeynes@377: ADD_imm8s_r32( 4, R_ESP ); nkeynes@374: :} nkeynes@388: SLEEP {: nkeynes@388: check_priv(); nkeynes@388: call_func0( sh4_sleep ); nkeynes@388: sh4_x86.in_delay_slot = FALSE; nkeynes@394: INC_r32(R_ESI); nkeynes@408: exit_block(pc+2, pc+2); 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@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@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@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@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@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@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@359: :} nkeynes@374: STC.L SR, @-Rn {: nkeynes@386: check_priv(); nkeynes@395: call_func0( sh4_read_sr ); nkeynes@368: load_reg( R_ECX, Rn ); nkeynes@395: check_walign32( R_ECX ); nkeynes@382: ADD_imm8s_r32( -4, R_ECX ); nkeynes@368: store_reg( R_ECX, Rn ); nkeynes@368: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@359: :} nkeynes@359: STC.L VBR, @-Rn {: nkeynes@386: check_priv(); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@395: check_walign32( R_ECX ); nkeynes@382: ADD_imm8s_r32( -4, R_ECX ); 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@386: check_priv(); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@395: check_walign32( R_ECX ); nkeynes@382: ADD_imm8s_r32( -4, R_ECX ); 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@386: check_priv(); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@395: check_walign32( R_ECX ); nkeynes@382: ADD_imm8s_r32( -4, R_ECX ); 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@386: check_priv(); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@395: check_walign32( R_ECX ); nkeynes@382: ADD_imm8s_r32( -4, R_ECX ); 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@386: check_priv(); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@395: check_walign32( R_ECX ); nkeynes@382: ADD_imm8s_r32( -4, R_ECX ); 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@374: STC.L Rm_BANK, @-Rn {: nkeynes@386: check_priv(); nkeynes@374: load_reg( R_ECX, Rn ); nkeynes@395: check_walign32( R_ECX ); nkeynes@382: ADD_imm8s_r32( -4, R_ECX ); nkeynes@374: store_reg( R_ECX, Rn ); nkeynes@374: load_spreg( R_EAX, REG_OFFSET(r_bank[Rm_BANK]) ); nkeynes@374: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@374: :} nkeynes@359: STC.L GBR, @-Rn {: nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@395: check_walign32( R_ECX ); nkeynes@382: ADD_imm8s_r32( -4, R_ECX ); 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@395: check_walign32( R_ECX ); nkeynes@382: ADD_imm8s_r32( -4, R_ECX ); 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@395: check_walign32( R_ECX ); nkeynes@382: ADD_imm8s_r32( -4, R_ECX ); 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@395: check_walign32( R_ECX ); nkeynes@382: ADD_imm8s_r32( -4, R_ECX ); 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@395: check_walign32( R_ECX ); nkeynes@382: ADD_imm8s_r32( -4, R_ECX ); 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@395: check_walign32( R_ECX ); nkeynes@382: ADD_imm8s_r32( -4, R_ECX ); 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@374: if( sh4_x86.in_delay_slot ) { nkeynes@386: ADD_imm8s_r32(2,R_ESI); nkeynes@374: sh4_x86.in_delay_slot = FALSE; nkeynes@386: } else { nkeynes@386: INC_r32(R_ESI); nkeynes@374: } nkeynes@359: return 0; nkeynes@359: }