nkeynes@359: /** nkeynes@502: * $Id: sh4x86.c,v 1.19 2007-11-08 11:54:16 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@417: #include "sh4/xltcache.h" nkeynes@368: #include "sh4/sh4core.h" nkeynes@368: #include "sh4/sh4trans.h" nkeynes@388: #include "sh4/sh4mmio.h" nkeynes@368: #include "sh4/x86op.h" nkeynes@368: #include "clock.h" nkeynes@368: nkeynes@368: #define DEFAULT_BACKPATCH_SIZE 4096 nkeynes@368: nkeynes@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@409: gboolean branch_taken; /* true if we branched unconditionally */ nkeynes@408: uint32_t block_start_pc; nkeynes@417: int tstate; 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@417: #define TSTATE_NONE -1 nkeynes@417: #define TSTATE_O 0 nkeynes@417: #define TSTATE_C 2 nkeynes@417: #define TSTATE_E 4 nkeynes@417: #define TSTATE_NE 5 nkeynes@417: #define TSTATE_G 0xF nkeynes@417: #define TSTATE_GE 0xD nkeynes@417: #define TSTATE_A 7 nkeynes@417: #define TSTATE_AE 3 nkeynes@417: nkeynes@417: /** Branch if T is set (either in the current cflags, or in sh4r.t) */ nkeynes@417: #define JT_rel8(rel8,label) if( sh4_x86.tstate == TSTATE_NONE ) { \ nkeynes@417: CMP_imm8s_sh4r( 1, R_T ); sh4_x86.tstate = TSTATE_E; } \ nkeynes@417: OP(0x70+sh4_x86.tstate); OP(rel8); \ nkeynes@417: MARK_JMP(rel8,label) nkeynes@417: /** Branch if T is clear (either in the current cflags or in sh4r.t) */ nkeynes@417: #define JF_rel8(rel8,label) if( sh4_x86.tstate == TSTATE_NONE ) { \ nkeynes@417: CMP_imm8s_sh4r( 1, R_T ); sh4_x86.tstate = TSTATE_E; } \ nkeynes@417: OP(0x70+ (sh4_x86.tstate^1)); OP(rel8); \ nkeynes@417: MARK_JMP(rel8, label) nkeynes@417: nkeynes@417: 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) nkeynes@416: nkeynes@416: #define check_priv( ) \ nkeynes@416: if( !sh4_x86.priv_checked ) { \ nkeynes@416: sh4_x86.priv_checked = TRUE;\ nkeynes@416: precheck();\ nkeynes@416: load_spreg( R_EAX, R_SR );\ nkeynes@416: AND_imm32_r32( SR_MD, R_EAX );\ nkeynes@416: if( sh4_x86.in_delay_slot ) {\ nkeynes@416: JE_exit( EXIT_SLOT_ILLEGAL );\ nkeynes@416: } else {\ nkeynes@416: JE_exit( EXIT_ILLEGAL );\ nkeynes@416: }\ nkeynes@416: }\ nkeynes@416: nkeynes@416: nkeynes@416: static void check_priv_no_precheck() nkeynes@368: { nkeynes@368: if( !sh4_x86.priv_checked ) { nkeynes@368: sh4_x86.priv_checked = TRUE; nkeynes@368: load_spreg( R_EAX, R_SR ); nkeynes@368: AND_imm32_r32( SR_MD, R_EAX ); nkeynes@368: if( sh4_x86.in_delay_slot ) { nkeynes@368: JE_exit( EXIT_SLOT_ILLEGAL ); nkeynes@368: } else { nkeynes@368: JE_exit( EXIT_ILLEGAL ); nkeynes@368: } nkeynes@368: } nkeynes@368: } nkeynes@368: nkeynes@416: #define check_fpuen( ) \ nkeynes@416: if( !sh4_x86.fpuen_checked ) {\ nkeynes@416: sh4_x86.fpuen_checked = TRUE;\ nkeynes@416: precheck();\ nkeynes@416: load_spreg( R_EAX, R_SR );\ nkeynes@416: AND_imm32_r32( SR_FD, R_EAX );\ nkeynes@416: if( sh4_x86.in_delay_slot ) {\ nkeynes@416: JNE_exit(EXIT_SLOT_FPU_DISABLED);\ nkeynes@416: } else {\ nkeynes@416: JNE_exit(EXIT_FPU_DISABLED);\ nkeynes@416: }\ nkeynes@416: } nkeynes@416: nkeynes@416: static void check_fpuen_no_precheck() nkeynes@368: { nkeynes@368: if( !sh4_x86.fpuen_checked ) { nkeynes@368: sh4_x86.fpuen_checked = TRUE; nkeynes@368: load_spreg( R_EAX, R_SR ); nkeynes@368: AND_imm32_r32( SR_FD, R_EAX ); nkeynes@368: if( sh4_x86.in_delay_slot ) { nkeynes@368: JNE_exit(EXIT_SLOT_FPU_DISABLED); nkeynes@368: } else { nkeynes@368: JNE_exit(EXIT_FPU_DISABLED); nkeynes@368: } nkeynes@368: } nkeynes@416: nkeynes@368: } nkeynes@368: nkeynes@368: static void check_ralign16( int x86reg ) nkeynes@368: { nkeynes@368: TEST_imm32_r32( 0x00000001, x86reg ); nkeynes@368: JNE_exit(EXIT_DATA_ADDR_READ); nkeynes@368: } nkeynes@368: nkeynes@368: static void check_walign16( int x86reg ) nkeynes@368: { nkeynes@368: TEST_imm32_r32( 0x00000001, x86reg ); nkeynes@368: JNE_exit(EXIT_DATA_ADDR_WRITE); nkeynes@368: } nkeynes@368: nkeynes@368: static void check_ralign32( int x86reg ) nkeynes@368: { nkeynes@368: TEST_imm32_r32( 0x00000003, x86reg ); nkeynes@368: JNE_exit(EXIT_DATA_ADDR_READ); nkeynes@368: } nkeynes@368: static void check_walign32( int x86reg ) nkeynes@368: { nkeynes@368: TEST_imm32_r32( 0x00000003, x86reg ); nkeynes@368: JNE_exit(EXIT_DATA_ADDR_WRITE); nkeynes@368: } nkeynes@368: nkeynes@361: #define UNDEF() nkeynes@361: #define MEM_RESULT(value_reg) if(value_reg != R_EAX) { MOV_r32_r32(R_EAX,value_reg); } nkeynes@361: #define MEM_READ_BYTE( addr_reg, value_reg ) call_func1(sh4_read_byte, addr_reg ); MEM_RESULT(value_reg) nkeynes@361: #define MEM_READ_WORD( addr_reg, value_reg ) call_func1(sh4_read_word, addr_reg ); MEM_RESULT(value_reg) nkeynes@361: #define MEM_READ_LONG( addr_reg, value_reg ) call_func1(sh4_read_long, addr_reg ); MEM_RESULT(value_reg) nkeynes@361: #define MEM_WRITE_BYTE( addr_reg, value_reg ) call_func2(sh4_write_byte, addr_reg, value_reg) nkeynes@361: #define MEM_WRITE_WORD( addr_reg, value_reg ) call_func2(sh4_write_word, addr_reg, value_reg) nkeynes@361: #define MEM_WRITE_LONG( addr_reg, value_reg ) call_func2(sh4_write_long, addr_reg, value_reg) nkeynes@361: nkeynes@416: #define SLOTILLEGAL() precheck(); JMP_exit(EXIT_SLOT_ILLEGAL); sh4_x86.in_delay_slot = FALSE; return 1; nkeynes@368: nkeynes@368: 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@408: void sh4_translate_begin_block( sh4addr_t pc ) nkeynes@368: { nkeynes@368: PUSH_r32(R_EBP); nkeynes@359: /* mov &sh4r, ebp */ nkeynes@359: load_imm32( R_EBP, (uint32_t)&sh4r ); nkeynes@368: nkeynes@368: sh4_x86.in_delay_slot = FALSE; nkeynes@368: sh4_x86.priv_checked = FALSE; nkeynes@368: sh4_x86.fpuen_checked = FALSE; nkeynes@409: sh4_x86.branch_taken = FALSE; nkeynes@368: sh4_x86.backpatch_posn = 0; nkeynes@408: sh4_x86.block_start_pc = pc; nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@368: } nkeynes@359: nkeynes@368: /** nkeynes@408: * Exit the block to an absolute PC nkeynes@416: * Bytes: 29 nkeynes@368: */ nkeynes@408: void exit_block( sh4addr_t pc, sh4addr_t endpc ) nkeynes@368: { nkeynes@408: load_imm32( R_ECX, pc ); // 5 nkeynes@408: store_spreg( R_ECX, REG_OFFSET(pc) ); // 3 nkeynes@408: MOV_moff32_EAX( (uint32_t)xlat_get_lut_entry(pc) ); // 5 nkeynes@408: AND_imm8s_r32( 0xFC, R_EAX ); // 3 nkeynes@408: load_imm32( R_ECX, ((endpc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5 nkeynes@408: ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6 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@416: * Bytes: 15 nkeynes@408: */ nkeynes@408: void exit_block_pcset( pc ) nkeynes@408: { 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@417: load_spreg( R_EAX, REG_OFFSET(pc) ); nkeynes@417: call_func1(xlat_get_code,R_EAX); 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@409: if( sh4_x86.branch_taken == FALSE ) { nkeynes@409: // Didn't exit unconditionally already, so write the termination here nkeynes@409: exit_block( pc, pc ); nkeynes@409: } 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@417: // Raise exception nkeynes@388: load_spreg( R_ECX, REG_OFFSET(pc) ); nkeynes@416: ADD_r32_r32( R_EDX, R_ECX ); nkeynes@416: ADD_r32_r32( R_EDX, R_ECX ); nkeynes@388: store_spreg( R_ECX, REG_OFFSET(pc) ); nkeynes@388: MOV_moff32_EAX( (uint32_t)&sh4_cpu_period ); nkeynes@416: MUL_r32( R_EDX ); nkeynes@417: ADD_r32_sh4r( R_EAX, 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@417: load_spreg( R_EAX, REG_OFFSET(pc) ); nkeynes@417: call_func1(xlat_get_code,R_EAX); 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: switch( (ir&0xF000) >> 12 ) { nkeynes@359: case 0x0: nkeynes@359: switch( ir&0xF ) { nkeynes@359: case 0x2: nkeynes@359: switch( (ir&0x80) >> 7 ) { nkeynes@359: case 0x0: nkeynes@359: switch( (ir&0x70) >> 4 ) { nkeynes@359: case 0x0: nkeynes@359: { /* STC SR, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@386: check_priv(); nkeynes@374: call_func0(sh4_read_sr); nkeynes@368: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* STC GBR, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_spreg( R_EAX, R_GBR ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* STC VBR, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@386: check_priv(); nkeynes@359: load_spreg( R_EAX, R_VBR ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* STC SSR, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@386: check_priv(); nkeynes@359: load_spreg( R_EAX, R_SSR ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x4: nkeynes@359: { /* STC SPC, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@386: check_priv(); nkeynes@359: load_spreg( R_EAX, R_SPC ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* STC Rm_BANK, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm_BANK = ((ir>>4)&0x7); nkeynes@386: check_priv(); nkeynes@374: load_spreg( R_EAX, REG_OFFSET(r_bank[Rm_BANK]) ); nkeynes@374: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: switch( (ir&0xF0) >> 4 ) { nkeynes@359: case 0x0: nkeynes@359: { /* BSRF Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@408: sh4_x86_translate_instruction( pc + 2 ); nkeynes@408: exit_block_pcset(pc+2); nkeynes@409: sh4_x86.branch_taken = TRUE; nkeynes@408: return 4; nkeynes@374: } nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* BRAF Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@408: sh4_x86_translate_instruction( pc + 2 ); nkeynes@408: exit_block_pcset(pc+2); nkeynes@409: sh4_x86.branch_taken = TRUE; nkeynes@408: return 4; nkeynes@374: } nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x8: nkeynes@359: { /* PREF @Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x9: nkeynes@359: { /* OCBI @Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xA: nkeynes@359: { /* OCBP @Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xB: nkeynes@359: { /* OCBWB @Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xC: nkeynes@359: { /* MOVCA.L R0, @Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@361: load_reg( R_EAX, 0 ); nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@416: precheck(); nkeynes@374: check_walign32( R_ECX ); nkeynes@361: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x4: nkeynes@359: { /* MOV.B Rm, @(R0, Rn) */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x5: nkeynes@359: { /* MOV.W Rm, @(R0, Rn) */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@361: load_reg( R_EAX, 0 ); nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@361: ADD_r32_r32( R_EAX, R_ECX ); nkeynes@416: precheck(); nkeynes@374: check_walign16( R_ECX ); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: MEM_WRITE_WORD( R_ECX, R_EAX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x6: nkeynes@359: { /* MOV.L Rm, @(R0, Rn) */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@361: load_reg( R_EAX, 0 ); nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@361: ADD_r32_r32( R_EAX, R_ECX ); nkeynes@416: precheck(); nkeynes@374: check_walign32( R_ECX ); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x7: nkeynes@359: { /* MUL.L Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@361: MUL_r32( R_ECX ); nkeynes@361: store_spreg( R_EAX, R_MACL ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x8: nkeynes@359: switch( (ir&0xFF0) >> 4 ) { nkeynes@359: case 0x0: nkeynes@359: { /* CLRT */ nkeynes@374: CLC(); nkeynes@374: SETC_t(); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* SETT */ nkeynes@374: STC(); nkeynes@374: SETC_t(); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* CLRMAC */ nkeynes@374: XOR_r32_r32(R_EAX, R_EAX); nkeynes@374: store_spreg( R_EAX, R_MACL ); nkeynes@374: store_spreg( R_EAX, R_MACH ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* LDTLB */ nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x4: nkeynes@359: { /* CLRS */ nkeynes@374: CLC(); nkeynes@374: SETC_sh4r(R_S); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x5: nkeynes@359: { /* SETS */ nkeynes@374: STC(); nkeynes@374: SETC_sh4r(R_S); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x9: nkeynes@359: switch( (ir&0xF0) >> 4 ) { nkeynes@359: case 0x0: nkeynes@359: { /* NOP */ nkeynes@359: /* Do nothing. Well, we could emit an 0x90, but what would really be the point? */ nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* DIV0U */ nkeynes@361: XOR_r32_r32( R_EAX, R_EAX ); nkeynes@361: store_spreg( R_EAX, R_Q ); nkeynes@361: store_spreg( R_EAX, R_M ); nkeynes@361: store_spreg( R_EAX, R_T ); nkeynes@417: sh4_x86.tstate = TSTATE_C; // works for DIV1 nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* MOVT Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_spreg( R_EAX, R_T ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xA: nkeynes@359: switch( (ir&0xF0) >> 4 ) { nkeynes@359: case 0x0: nkeynes@359: { /* STS MACH, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_spreg( R_EAX, R_MACH ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* STS MACL, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_spreg( R_EAX, R_MACL ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* STS PR, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_spreg( R_EAX, R_PR ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* STC SGR, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@386: check_priv(); nkeynes@359: load_spreg( R_EAX, R_SGR ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x5: nkeynes@359: { /* STS FPUL, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_spreg( R_EAX, R_FPUL ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x6: nkeynes@359: { /* STS FPSCR, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_spreg( R_EAX, R_FPSCR ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xF: nkeynes@359: { /* STC DBR, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@386: check_priv(); nkeynes@359: load_spreg( R_EAX, R_DBR ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xB: nkeynes@359: switch( (ir&0xFF0) >> 4 ) { nkeynes@359: case 0x0: nkeynes@359: { /* 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@409: sh4_x86.branch_taken = TRUE; nkeynes@408: return 4; nkeynes@374: } nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* SLEEP */ nkeynes@388: check_priv(); nkeynes@388: call_func0( sh4_sleep ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@388: sh4_x86.in_delay_slot = FALSE; nkeynes@408: return 2; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@408: sh4_x86_translate_instruction(pc+2); nkeynes@408: exit_block_pcset(pc+2); nkeynes@409: sh4_x86.branch_taken = TRUE; nkeynes@408: return 4; nkeynes@374: } nkeynes@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xC: nkeynes@359: { /* MOV.B @(R0, Rm), Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xD: nkeynes@359: { /* MOV.W @(R0, Rm), Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@361: load_reg( R_EAX, 0 ); nkeynes@361: load_reg( R_ECX, Rm ); nkeynes@361: ADD_r32_r32( R_EAX, R_ECX ); nkeynes@416: precheck(); nkeynes@374: check_ralign16( R_ECX ); nkeynes@361: MEM_READ_WORD( R_ECX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xE: nkeynes@359: { /* MOV.L @(R0, Rm), Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@361: load_reg( R_EAX, 0 ); nkeynes@361: load_reg( R_ECX, Rm ); nkeynes@361: ADD_r32_r32( R_EAX, R_ECX ); nkeynes@416: precheck(); nkeynes@374: check_ralign32( R_ECX ); nkeynes@361: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xF: nkeynes@359: { /* MAC.L @Rm+, @Rn+ */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@386: load_reg( R_ECX, Rm ); nkeynes@416: precheck(); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* MOV.L Rm, @(disp, Rn) */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); uint32_t disp = (ir&0xF)<<2; nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: ADD_imm32_r32( disp, R_ECX ); nkeynes@416: precheck(); nkeynes@374: check_walign32( R_ECX ); nkeynes@361: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: switch( ir&0xF ) { nkeynes@359: case 0x0: nkeynes@359: { /* MOV.B Rm, @Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: MEM_WRITE_BYTE( R_ECX, R_EAX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* MOV.W Rm, @Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@416: precheck(); nkeynes@374: check_walign16( R_ECX ); nkeynes@386: load_reg( R_EAX, Rm ); nkeynes@386: MEM_WRITE_WORD( R_ECX, R_EAX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* MOV.L Rm, @Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@416: precheck(); nkeynes@374: check_walign32(R_ECX); nkeynes@361: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x4: nkeynes@359: { /* MOV.B Rm, @-Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@386: ADD_imm8s_r32( -1, R_ECX ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: MEM_WRITE_BYTE( R_ECX, R_EAX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x5: nkeynes@359: { /* MOV.W Rm, @-Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@416: precheck(); nkeynes@374: check_walign16( R_ECX ); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: ADD_imm8s_r32( -2, R_ECX ); nkeynes@386: store_reg( R_ECX, Rn ); nkeynes@361: MEM_WRITE_WORD( R_ECX, R_EAX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x6: nkeynes@359: { /* MOV.L Rm, @-Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@416: precheck(); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x7: nkeynes@359: { /* DIV0S Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@386: load_reg( R_ECX, Rn ); nkeynes@361: SHR_imm8_r32( 31, R_EAX ); nkeynes@361: SHR_imm8_r32( 31, R_ECX ); nkeynes@361: store_spreg( R_EAX, R_M ); nkeynes@361: store_spreg( R_ECX, R_Q ); nkeynes@361: CMP_r32_r32( R_EAX, R_ECX ); nkeynes@386: SETNE_t(); nkeynes@417: sh4_x86.tstate = TSTATE_NE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x8: nkeynes@359: { /* TST Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@361: TEST_r32_r32( R_EAX, R_ECX ); nkeynes@361: SETE_t(); nkeynes@417: sh4_x86.tstate = TSTATE_E; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x9: nkeynes@359: { /* AND Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: AND_r32_r32( R_EAX, R_ECX ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xA: nkeynes@359: { /* XOR Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: XOR_r32_r32( R_EAX, R_ECX ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xB: nkeynes@359: { /* OR Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: OR_r32_r32( R_EAX, R_ECX ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xC: nkeynes@359: { /* CMP/STR Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@368: load_reg( R_EAX, Rm ); nkeynes@368: load_reg( R_ECX, Rn ); nkeynes@368: XOR_r32_r32( R_ECX, R_EAX ); nkeynes@368: TEST_r8_r8( R_AL, R_AL ); nkeynes@380: JE_rel8(13, target1); nkeynes@368: TEST_r8_r8( R_AH, R_AH ); // 2 nkeynes@380: JE_rel8(9, target2); nkeynes@368: SHR_imm8_r32( 16, R_EAX ); // 3 nkeynes@368: TEST_r8_r8( R_AL, R_AL ); // 2 nkeynes@380: JE_rel8(2, target3); nkeynes@368: TEST_r8_r8( R_AH, R_AH ); // 2 nkeynes@380: JMP_TARGET(target1); nkeynes@380: JMP_TARGET(target2); nkeynes@380: JMP_TARGET(target3); nkeynes@368: SETE_t(); nkeynes@417: sh4_x86.tstate = TSTATE_E; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xD: nkeynes@359: { /* XTRCT Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@394: load_reg( R_ECX, Rn ); nkeynes@394: SHL_imm8_r32( 16, R_EAX ); nkeynes@394: SHR_imm8_r32( 16, R_ECX ); nkeynes@361: OR_r32_r32( R_EAX, R_ECX ); nkeynes@361: store_reg( R_ECX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xE: nkeynes@359: { /* MULU.W Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@374: load_reg16u( R_EAX, Rm ); nkeynes@374: load_reg16u( R_ECX, Rn ); nkeynes@374: MUL_r32( R_ECX ); nkeynes@374: store_spreg( R_EAX, R_MACL ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xF: nkeynes@359: { /* MULS.W Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@374: load_reg16s( R_EAX, Rm ); nkeynes@374: load_reg16s( R_ECX, Rn ); nkeynes@374: MUL_r32( R_ECX ); nkeynes@374: store_spreg( R_EAX, R_MACL ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: switch( ir&0xF ) { nkeynes@359: case 0x0: nkeynes@359: { /* CMP/EQ Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: CMP_r32_r32( R_EAX, R_ECX ); nkeynes@359: SETE_t(); nkeynes@417: sh4_x86.tstate = TSTATE_E; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* CMP/HS Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: CMP_r32_r32( R_EAX, R_ECX ); nkeynes@359: SETAE_t(); nkeynes@417: sh4_x86.tstate = TSTATE_AE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* CMP/GE Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: CMP_r32_r32( R_EAX, R_ECX ); nkeynes@359: SETGE_t(); nkeynes@417: sh4_x86.tstate = TSTATE_GE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x4: nkeynes@359: { /* DIV1 Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@386: load_spreg( R_ECX, R_M ); nkeynes@386: load_reg( R_EAX, Rn ); nkeynes@417: if( sh4_x86.tstate != TSTATE_C ) { nkeynes@417: LDC_t(); nkeynes@417: } nkeynes@386: RCL1_r32( R_EAX ); nkeynes@386: SETC_r8( R_DL ); // Q' nkeynes@386: CMP_sh4r_r32( R_Q, R_ECX ); nkeynes@386: JE_rel8(5, mqequal); nkeynes@386: ADD_sh4r_r32( REG_OFFSET(r[Rm]), R_EAX ); nkeynes@386: JMP_rel8(3, end); nkeynes@380: JMP_TARGET(mqequal); nkeynes@386: SUB_sh4r_r32( REG_OFFSET(r[Rm]), R_EAX ); nkeynes@386: JMP_TARGET(end); nkeynes@386: store_reg( R_EAX, Rn ); // Done with Rn now nkeynes@386: SETC_r8(R_AL); // tmp1 nkeynes@386: XOR_r8_r8( R_DL, R_AL ); // Q' = Q ^ tmp1 nkeynes@386: XOR_r8_r8( R_AL, R_CL ); // Q'' = Q' ^ M nkeynes@386: store_spreg( R_ECX, R_Q ); nkeynes@386: XOR_imm8s_r32( 1, R_AL ); // T = !Q' nkeynes@386: MOVZX_r8_r32( R_AL, R_EAX ); nkeynes@386: store_spreg( R_EAX, R_T ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x5: nkeynes@359: { /* DMULU.L Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); 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@417: store_spreg( R_EAX, R_MACL ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x6: nkeynes@359: { /* CMP/HI Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: CMP_r32_r32( R_EAX, R_ECX ); nkeynes@359: SETA_t(); nkeynes@417: sh4_x86.tstate = TSTATE_A; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x7: nkeynes@359: { /* CMP/GT Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: CMP_r32_r32( R_EAX, R_ECX ); nkeynes@359: SETG_t(); nkeynes@417: sh4_x86.tstate = TSTATE_G; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x8: nkeynes@359: { /* SUB Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: SUB_r32_r32( R_EAX, R_ECX ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xA: nkeynes@359: { /* SUBC Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@417: if( sh4_x86.tstate != TSTATE_C ) { nkeynes@417: LDC_t(); nkeynes@417: } nkeynes@359: SBB_r32_r32( R_EAX, R_ECX ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@394: SETC_t(); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xB: nkeynes@359: { /* SUBV Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: SUB_r32_r32( R_EAX, R_ECX ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: SETO_t(); nkeynes@417: sh4_x86.tstate = TSTATE_O; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xC: nkeynes@359: { /* ADD Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: ADD_r32_r32( R_EAX, R_ECX ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xD: nkeynes@359: { /* DMULS.L Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@361: IMUL_r32(R_ECX); nkeynes@361: store_spreg( R_EDX, R_MACH ); nkeynes@361: store_spreg( R_EAX, R_MACL ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xE: nkeynes@359: { /* ADDC Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@417: if( sh4_x86.tstate != TSTATE_C ) { nkeynes@417: LDC_t(); nkeynes@417: } nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: ADC_r32_r32( R_EAX, R_ECX ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: SETC_t(); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xF: nkeynes@359: { /* ADDV Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: ADD_r32_r32( R_EAX, R_ECX ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: SETO_t(); nkeynes@417: sh4_x86.tstate = TSTATE_O; nkeynes@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x4: nkeynes@359: switch( ir&0xF ) { nkeynes@359: case 0x0: nkeynes@359: switch( (ir&0xF0) >> 4 ) { nkeynes@359: case 0x0: nkeynes@359: { /* SHLL Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: SHL1_r32( R_EAX ); nkeynes@397: SETC_t(); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* DT Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@386: ADD_imm8s_r32( -1, R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: SETE_t(); nkeynes@417: sh4_x86.tstate = TSTATE_E; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* SHAL Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: SHL1_r32( R_EAX ); nkeynes@397: SETC_t(); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: switch( (ir&0xF0) >> 4 ) { nkeynes@359: case 0x0: nkeynes@359: { /* SHLR Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: SHR1_r32( R_EAX ); nkeynes@397: SETC_t(); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* CMP/PZ Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: CMP_imm8s_r32( 0, R_EAX ); nkeynes@359: SETGE_t(); nkeynes@417: sh4_x86.tstate = TSTATE_GE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* SHAR Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: SAR1_r32( R_EAX ); nkeynes@397: SETC_t(); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: switch( (ir&0xF0) >> 4 ) { nkeynes@359: case 0x0: nkeynes@359: { /* STS.L MACH, @-Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@416: precheck(); nkeynes@395: check_walign32( R_ECX ); nkeynes@386: 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* STS.L MACL, @-Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@416: precheck(); nkeynes@395: check_walign32( R_ECX ); nkeynes@386: 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* STS.L PR, @-Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@416: precheck(); nkeynes@395: check_walign32( R_ECX ); nkeynes@386: 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* STC.L SGR, @-Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@416: precheck(); nkeynes@416: check_priv_no_precheck(); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@395: check_walign32( R_ECX ); nkeynes@386: 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x5: nkeynes@359: { /* STS.L FPUL, @-Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@416: precheck(); nkeynes@395: check_walign32( R_ECX ); nkeynes@386: 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x6: nkeynes@359: { /* STS.L FPSCR, @-Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@416: precheck(); nkeynes@395: check_walign32( R_ECX ); nkeynes@386: 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xF: nkeynes@359: { /* STC.L DBR, @-Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@416: precheck(); nkeynes@416: check_priv_no_precheck(); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@395: check_walign32( R_ECX ); nkeynes@386: 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: switch( (ir&0x80) >> 7 ) { nkeynes@359: case 0x0: nkeynes@359: switch( (ir&0x70) >> 4 ) { nkeynes@359: case 0x0: nkeynes@359: { /* STC.L SR, @-Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@416: precheck(); nkeynes@416: check_priv_no_precheck(); nkeynes@395: call_func0( sh4_read_sr ); nkeynes@374: load_reg( R_ECX, Rn ); nkeynes@395: check_walign32( R_ECX ); nkeynes@386: ADD_imm8s_r32( -4, R_ECX ); nkeynes@374: store_reg( R_ECX, Rn ); nkeynes@374: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* STC.L GBR, @-Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@416: precheck(); nkeynes@395: check_walign32( R_ECX ); nkeynes@386: 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* STC.L VBR, @-Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@416: precheck(); nkeynes@416: check_priv_no_precheck(); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@395: check_walign32( R_ECX ); nkeynes@386: 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* STC.L SSR, @-Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@416: precheck(); nkeynes@416: check_priv_no_precheck(); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@395: check_walign32( R_ECX ); nkeynes@386: 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x4: nkeynes@359: { /* STC.L SPC, @-Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@416: precheck(); nkeynes@416: check_priv_no_precheck(); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@395: check_walign32( R_ECX ); nkeynes@386: 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* STC.L Rm_BANK, @-Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm_BANK = ((ir>>4)&0x7); nkeynes@416: precheck(); nkeynes@416: check_priv_no_precheck(); nkeynes@374: load_reg( R_ECX, Rn ); nkeynes@395: check_walign32( R_ECX ); nkeynes@386: 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x4: nkeynes@359: switch( (ir&0xF0) >> 4 ) { nkeynes@359: case 0x0: nkeynes@359: { /* ROTL Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: ROL1_r32( R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: SETC_t(); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* ROTCL Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@417: if( sh4_x86.tstate != TSTATE_C ) { nkeynes@417: LDC_t(); nkeynes@417: } nkeynes@359: RCL1_r32( R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: SETC_t(); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x5: nkeynes@359: switch( (ir&0xF0) >> 4 ) { nkeynes@359: case 0x0: nkeynes@359: { /* ROTR Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: ROR1_r32( R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: SETC_t(); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* CMP/PL Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: CMP_imm8s_r32( 0, R_EAX ); nkeynes@359: SETG_t(); nkeynes@417: sh4_x86.tstate = TSTATE_G; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* ROTCR Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@417: if( sh4_x86.tstate != TSTATE_C ) { nkeynes@417: LDC_t(); nkeynes@417: } nkeynes@359: RCR1_r32( R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: SETC_t(); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x6: nkeynes@359: switch( (ir&0xF0) >> 4 ) { nkeynes@359: case 0x0: nkeynes@359: { /* LDS.L @Rm+, MACH */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@416: precheck(); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* LDS.L @Rm+, MACL */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@416: precheck(); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* LDS.L @Rm+, PR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@416: precheck(); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* LDC.L @Rm+, SGR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@416: precheck(); nkeynes@416: check_priv_no_precheck(); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x5: nkeynes@359: { /* LDS.L @Rm+, FPUL */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@416: precheck(); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x6: nkeynes@359: { /* LDS.L @Rm+, FPSCR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@416: precheck(); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xF: nkeynes@359: { /* LDC.L @Rm+, DBR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@416: precheck(); nkeynes@416: check_priv_no_precheck(); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x7: nkeynes@359: switch( (ir&0x80) >> 7 ) { nkeynes@359: case 0x0: nkeynes@359: switch( (ir&0x70) >> 4 ) { nkeynes@359: case 0x0: nkeynes@359: { /* LDC.L @Rm+, SR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@386: if( sh4_x86.in_delay_slot ) { nkeynes@386: SLOTILLEGAL(); nkeynes@386: } else { nkeynes@416: precheck(); nkeynes@416: check_priv_no_precheck(); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@386: } nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* LDC.L @Rm+, GBR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@416: precheck(); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* LDC.L @Rm+, VBR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@416: precheck(); nkeynes@416: check_priv_no_precheck(); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* LDC.L @Rm+, SSR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@416: precheck(); nkeynes@416: check_priv_no_precheck(); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@416: 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_SSR ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x4: nkeynes@359: { /* LDC.L @Rm+, SPC */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@416: precheck(); nkeynes@416: check_priv_no_precheck(); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* LDC.L @Rm+, Rn_BANK */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); uint32_t Rn_BANK = ((ir>>4)&0x7); nkeynes@416: precheck(); nkeynes@416: check_priv_no_precheck(); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x8: nkeynes@359: switch( (ir&0xF0) >> 4 ) { nkeynes@359: case 0x0: nkeynes@359: { /* SHLL2 Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: SHL_imm8_r32( 2, R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* SHLL8 Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: SHL_imm8_r32( 8, R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* SHLL16 Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: SHL_imm8_r32( 16, R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x9: nkeynes@359: switch( (ir&0xF0) >> 4 ) { nkeynes@359: case 0x0: nkeynes@359: { /* SHLR2 Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: SHR_imm8_r32( 2, R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* SHLR8 Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: SHR_imm8_r32( 8, R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* SHLR16 Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: SHR_imm8_r32( 16, R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xA: nkeynes@359: switch( (ir&0xF0) >> 4 ) { nkeynes@359: case 0x0: nkeynes@359: { /* LDS Rm, MACH */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_MACH ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* LDS Rm, MACL */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_MACL ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* LDS Rm, PR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_PR ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* LDC Rm, SGR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@386: check_priv(); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_SGR ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x5: nkeynes@359: { /* LDS Rm, FPUL */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_FPUL ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x6: nkeynes@359: { /* LDS Rm, FPSCR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_FPSCR ); nkeynes@386: update_fr_bank( R_EAX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xF: nkeynes@359: { /* LDC Rm, DBR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@386: check_priv(); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_DBR ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xB: nkeynes@359: switch( (ir&0xF0) >> 4 ) { nkeynes@359: case 0x0: nkeynes@359: { /* JSR @Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); 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@409: sh4_x86.branch_taken = TRUE; nkeynes@408: return 4; nkeynes@374: } nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* TAS.B @Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* JMP @Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); 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@409: sh4_x86.branch_taken = TRUE; nkeynes@408: return 4; nkeynes@374: } nkeynes@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xC: nkeynes@359: { /* SHAD Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); 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@386: nkeynes@380: JMP_TARGET(doshl); nkeynes@361: AND_imm8_r8( 0x1F, R_CL ); // 3 nkeynes@361: SHL_r32_CL( R_EAX ); // 2 nkeynes@380: JMP_TARGET(end); nkeynes@386: JMP_TARGET(end2); nkeynes@361: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xD: nkeynes@359: { /* SHLD Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@368: load_reg( R_EAX, Rn ); nkeynes@368: load_reg( R_ECX, Rm ); nkeynes@386: CMP_imm32_r32( 0, R_ECX ); nkeynes@386: JGE_rel8(15, doshl); nkeynes@368: nkeynes@386: NEG_r32( R_ECX ); // 2 nkeynes@386: AND_imm8_r8( 0x1F, R_CL ); // 3 nkeynes@386: JE_rel8( 4, emptyshr ); nkeynes@386: 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@386: nkeynes@386: JMP_TARGET(doshl); nkeynes@386: AND_imm8_r8( 0x1F, R_CL ); // 3 nkeynes@386: SHL_r32_CL( R_EAX ); // 2 nkeynes@386: JMP_TARGET(end); nkeynes@386: JMP_TARGET(end2); nkeynes@368: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xE: nkeynes@359: switch( (ir&0x80) >> 7 ) { nkeynes@359: case 0x0: nkeynes@359: switch( (ir&0x70) >> 4 ) { nkeynes@359: case 0x0: nkeynes@359: { /* LDC Rm, SR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@386: if( sh4_x86.in_delay_slot ) { nkeynes@386: SLOTILLEGAL(); nkeynes@386: } else { nkeynes@386: check_priv(); nkeynes@386: load_reg( R_EAX, Rm ); nkeynes@386: call_func1( sh4_write_sr, R_EAX ); nkeynes@386: sh4_x86.priv_checked = FALSE; nkeynes@386: sh4_x86.fpuen_checked = FALSE; nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@386: } nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* LDC Rm, GBR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_GBR ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* LDC Rm, VBR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@386: check_priv(); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_VBR ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* LDC Rm, SSR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@386: check_priv(); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_SSR ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x4: nkeynes@359: { /* LDC Rm, SPC */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@386: check_priv(); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_SPC ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* LDC Rm, Rn_BANK */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); uint32_t Rn_BANK = ((ir>>4)&0x7); nkeynes@386: check_priv(); nkeynes@374: load_reg( R_EAX, Rm ); nkeynes@374: store_spreg( R_EAX, REG_OFFSET(r_bank[Rn_BANK]) ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xF: nkeynes@359: { /* MAC.W @Rm+, @Rn+ */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@386: load_reg( R_ECX, Rm ); nkeynes@416: precheck(); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x5: nkeynes@359: { /* MOV.L @(disp, Rm), Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); uint32_t disp = (ir&0xF)<<2; nkeynes@361: load_reg( R_ECX, Rm ); nkeynes@361: ADD_imm8s_r32( disp, R_ECX ); nkeynes@416: precheck(); nkeynes@374: check_ralign32( R_ECX ); nkeynes@361: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x6: nkeynes@359: switch( ir&0xF ) { nkeynes@359: case 0x0: nkeynes@359: { /* MOV.B @Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@359: load_reg( R_ECX, Rm ); nkeynes@359: MEM_READ_BYTE( R_ECX, R_EAX ); nkeynes@386: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* MOV.W @Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@361: load_reg( R_ECX, Rm ); nkeynes@416: precheck(); nkeynes@374: check_ralign16( R_ECX ); nkeynes@361: MEM_READ_WORD( R_ECX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* MOV.L @Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@361: load_reg( R_ECX, Rm ); nkeynes@416: precheck(); nkeynes@374: check_ralign32( R_ECX ); nkeynes@361: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* MOV Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x4: nkeynes@359: { /* MOV.B @Rm+, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x5: nkeynes@359: { /* MOV.W @Rm+, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@416: precheck(); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x6: nkeynes@359: { /* MOV.L @Rm+, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@416: precheck(); nkeynes@386: 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x7: nkeynes@359: { /* NOT Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: NOT_r32( R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x8: nkeynes@359: { /* SWAP.B Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); 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: break; nkeynes@359: case 0x9: nkeynes@359: { /* SWAP.W Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@359: SHL_imm8_r32( 16, R_ECX ); nkeynes@359: SHR_imm8_r32( 16, R_EAX ); nkeynes@359: OR_r32_r32( R_EAX, R_ECX ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xA: nkeynes@359: { /* NEGC Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: XOR_r32_r32( R_ECX, R_ECX ); nkeynes@359: LDC_t(); nkeynes@359: SBB_r32_r32( R_EAX, R_ECX ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: SETC_t(); nkeynes@417: sh4_x86.tstate = TSTATE_C; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xB: nkeynes@359: { /* NEG Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: NEG_r32( R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xC: nkeynes@359: { /* EXTU.B Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: MOVZX_r8_r32( R_EAX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xD: nkeynes@359: { /* EXTU.W Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: MOVZX_r16_r32( R_EAX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xE: nkeynes@359: { /* EXTS.B Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); 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: break; nkeynes@359: case 0xF: nkeynes@359: { /* EXTS.W Rm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: MOVSX_r16_r32( R_EAX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); nkeynes@359: } nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x7: nkeynes@359: { /* ADD #imm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); int32_t imm = SIGNEXT8(ir&0xFF); nkeynes@359: load_reg( R_EAX, Rn ); nkeynes@359: ADD_imm8s_r32( imm, R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x8: nkeynes@359: switch( (ir&0xF00) >> 8 ) { nkeynes@359: case 0x0: nkeynes@359: { /* MOV.B R0, @(disp, Rn) */ nkeynes@359: uint32_t Rn = ((ir>>4)&0xF); uint32_t disp = (ir&0xF); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* MOV.W R0, @(disp, Rn) */ nkeynes@359: uint32_t Rn = ((ir>>4)&0xF); uint32_t disp = (ir&0xF)<<1; nkeynes@361: load_reg( R_ECX, Rn ); nkeynes@361: load_reg( R_EAX, 0 ); nkeynes@361: ADD_imm32_r32( disp, R_ECX ); nkeynes@416: precheck(); nkeynes@374: check_walign16( R_ECX ); nkeynes@361: MEM_WRITE_WORD( R_ECX, R_EAX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x4: nkeynes@359: { /* MOV.B @(disp, Rm), R0 */ nkeynes@359: uint32_t Rm = ((ir>>4)&0xF); uint32_t disp = (ir&0xF); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x5: nkeynes@359: { /* MOV.W @(disp, Rm), R0 */ nkeynes@359: uint32_t Rm = ((ir>>4)&0xF); uint32_t disp = (ir&0xF)<<1; nkeynes@361: load_reg( R_ECX, Rm ); nkeynes@361: ADD_imm32_r32( disp, R_ECX ); nkeynes@416: precheck(); nkeynes@374: check_ralign16( R_ECX ); nkeynes@361: MEM_READ_WORD( R_ECX, R_EAX ); nkeynes@361: store_reg( R_EAX, 0 ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x8: nkeynes@359: { /* CMP/EQ #imm, R0 */ nkeynes@359: int32_t imm = SIGNEXT8(ir&0xFF); nkeynes@359: load_reg( R_EAX, 0 ); nkeynes@359: CMP_imm8s_r32(imm, R_EAX); nkeynes@359: SETE_t(); nkeynes@417: sh4_x86.tstate = TSTATE_E; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x9: nkeynes@359: { /* BT disp */ nkeynes@359: int32_t disp = SIGNEXT8(ir&0xFF)<<1; nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@417: JF_rel8( 29, nottaken ); nkeynes@408: exit_block( disp + pc + 4, pc+2 ); nkeynes@380: JMP_TARGET(nottaken); nkeynes@408: return 2; nkeynes@374: } nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xB: nkeynes@359: { /* BF disp */ nkeynes@359: int32_t disp = SIGNEXT8(ir&0xFF)<<1; nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@417: JT_rel8( 29, nottaken ); nkeynes@408: exit_block( disp + pc + 4, pc+2 ); nkeynes@380: JMP_TARGET(nottaken); nkeynes@408: return 2; nkeynes@374: } nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xD: nkeynes@359: { /* BT/S disp */ nkeynes@359: int32_t disp = SIGNEXT8(ir&0xFF)<<1; nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@408: sh4_x86.in_delay_slot = TRUE; nkeynes@417: if( sh4_x86.tstate == TSTATE_NONE ) { nkeynes@417: CMP_imm8s_sh4r( 1, R_T ); nkeynes@417: sh4_x86.tstate = TSTATE_E; nkeynes@417: } nkeynes@417: OP(0x0F); OP(0x80+(sh4_x86.tstate^1)); uint32_t *patch = (uint32_t *)xlat_output; OP32(0); // JE rel32 nkeynes@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: return 4; nkeynes@374: } nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xF: nkeynes@359: { /* BF/S disp */ nkeynes@359: int32_t disp = SIGNEXT8(ir&0xFF)<<1; nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@408: sh4_x86.in_delay_slot = TRUE; nkeynes@417: if( sh4_x86.tstate == TSTATE_NONE ) { nkeynes@417: CMP_imm8s_sh4r( 1, R_T ); nkeynes@417: sh4_x86.tstate = TSTATE_E; nkeynes@417: } nkeynes@417: OP(0x0F); OP(0x80+sh4_x86.tstate); uint32_t *patch = (uint32_t *)xlat_output; OP32(0); // JNE rel32 nkeynes@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: return 4; nkeynes@374: } nkeynes@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x9: nkeynes@359: { /* MOV.W @(disp, PC), Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t disp = (ir&0xFF)<<1; 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@374: } nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xA: nkeynes@359: { /* BRA disp */ nkeynes@359: int32_t disp = SIGNEXT12(ir&0xFFF)<<1; 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@409: sh4_x86.branch_taken = TRUE; nkeynes@408: return 4; nkeynes@374: } nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xB: nkeynes@359: { /* BSR disp */ nkeynes@359: int32_t disp = SIGNEXT12(ir&0xFFF)<<1; 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@409: sh4_x86.branch_taken = TRUE; nkeynes@408: return 4; nkeynes@374: } nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xC: nkeynes@359: switch( (ir&0xF00) >> 8 ) { nkeynes@359: case 0x0: nkeynes@359: { /* MOV.B R0, @(disp, GBR) */ nkeynes@359: uint32_t disp = (ir&0xFF); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* MOV.W R0, @(disp, GBR) */ nkeynes@359: uint32_t disp = (ir&0xFF)<<1; nkeynes@361: load_spreg( R_ECX, R_GBR ); nkeynes@361: load_reg( R_EAX, 0 ); nkeynes@361: ADD_imm32_r32( disp, R_ECX ); nkeynes@416: precheck(); nkeynes@374: check_walign16( R_ECX ); nkeynes@361: MEM_WRITE_WORD( R_ECX, R_EAX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* MOV.L R0, @(disp, GBR) */ nkeynes@359: uint32_t disp = (ir&0xFF)<<2; nkeynes@361: load_spreg( R_ECX, R_GBR ); nkeynes@361: load_reg( R_EAX, 0 ); nkeynes@361: ADD_imm32_r32( disp, R_ECX ); nkeynes@416: precheck(); nkeynes@374: check_walign32( R_ECX ); nkeynes@361: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* TRAPA #imm */ nkeynes@359: uint32_t imm = (ir&0xFF); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@408: exit_block_pcset(pc); nkeynes@409: sh4_x86.branch_taken = TRUE; nkeynes@408: return 2; nkeynes@374: } nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x4: nkeynes@359: { /* MOV.B @(disp, GBR), R0 */ nkeynes@359: uint32_t disp = (ir&0xFF); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x5: nkeynes@359: { /* MOV.W @(disp, GBR), R0 */ nkeynes@359: uint32_t disp = (ir&0xFF)<<1; nkeynes@361: load_spreg( R_ECX, R_GBR ); nkeynes@361: ADD_imm32_r32( disp, R_ECX ); nkeynes@416: precheck(); nkeynes@374: check_ralign16( R_ECX ); nkeynes@361: MEM_READ_WORD( R_ECX, R_EAX ); nkeynes@361: store_reg( R_EAX, 0 ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x6: nkeynes@359: { /* MOV.L @(disp, GBR), R0 */ nkeynes@359: uint32_t disp = (ir&0xFF)<<2; nkeynes@361: load_spreg( R_ECX, R_GBR ); nkeynes@361: ADD_imm32_r32( disp, R_ECX ); nkeynes@416: precheck(); nkeynes@374: check_ralign32( R_ECX ); nkeynes@361: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@361: store_reg( R_EAX, 0 ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x7: nkeynes@359: { /* MOVA @(disp, PC), R0 */ nkeynes@359: uint32_t disp = (ir&0xFF)<<2; 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@359: } nkeynes@359: break; nkeynes@359: case 0x8: nkeynes@359: { /* TST #imm, R0 */ nkeynes@359: uint32_t imm = (ir&0xFF); nkeynes@368: load_reg( R_EAX, 0 ); nkeynes@368: TEST_imm32_r32( imm, R_EAX ); nkeynes@368: SETE_t(); nkeynes@417: sh4_x86.tstate = TSTATE_E; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x9: nkeynes@359: { /* AND #imm, R0 */ nkeynes@359: uint32_t imm = (ir&0xFF); nkeynes@359: load_reg( R_EAX, 0 ); nkeynes@359: AND_imm32_r32(imm, R_EAX); nkeynes@359: store_reg( R_EAX, 0 ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xA: nkeynes@359: { /* XOR #imm, R0 */ nkeynes@359: uint32_t imm = (ir&0xFF); nkeynes@359: load_reg( R_EAX, 0 ); nkeynes@359: XOR_imm32_r32( imm, R_EAX ); nkeynes@359: store_reg( R_EAX, 0 ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xB: nkeynes@359: { /* OR #imm, R0 */ nkeynes@359: uint32_t imm = (ir&0xFF); nkeynes@359: load_reg( R_EAX, 0 ); nkeynes@359: OR_imm32_r32(imm, R_EAX); nkeynes@359: store_reg( R_EAX, 0 ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xC: nkeynes@359: { /* TST.B #imm, @(R0, GBR) */ nkeynes@359: uint32_t imm = (ir&0xFF); 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@417: sh4_x86.tstate = TSTATE_E; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xD: nkeynes@359: { /* AND.B #imm, @(R0, GBR) */ nkeynes@359: uint32_t imm = (ir&0xFF); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xE: nkeynes@359: { /* XOR.B #imm, @(R0, GBR) */ nkeynes@359: uint32_t imm = (ir&0xFF); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xF: nkeynes@359: { /* OR.B #imm, @(R0, GBR) */ nkeynes@359: uint32_t imm = (ir&0xFF); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xD: nkeynes@359: { /* MOV.L @(disp, PC), Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t disp = (ir&0xFF)<<2; nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@388: uint32_t target = (pc & 0xFFFFFFFC) + disp + 4; nkeynes@502: sh4ptr_t 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@386: store_reg( R_EAX, Rn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@374: } nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xE: nkeynes@359: { /* MOV #imm, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); int32_t imm = SIGNEXT8(ir&0xFF); nkeynes@359: load_imm32( R_EAX, imm ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xF: nkeynes@359: switch( ir&0xF ) { nkeynes@359: case 0x0: nkeynes@359: { /* FADD FRm, FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); uint32_t FRm = ((ir>>4)&0xF); 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: FADDP_st(1); nkeynes@377: pop_fr(R_EDX, FRn); nkeynes@380: JMP_rel8(11,end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@377: push_dr(R_EDX, FRm); nkeynes@377: push_dr(R_EDX, FRn); nkeynes@377: FADDP_st(1); nkeynes@377: pop_dr(R_EDX, FRn); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* FSUB FRm, FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); uint32_t FRm = ((ir>>4)&0xF); nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@377: load_fr_bank( R_EDX ); nkeynes@380: JNE_rel8(13, doubleprec); nkeynes@377: push_fr(R_EDX, FRn); nkeynes@377: push_fr(R_EDX, FRm); nkeynes@388: FSUBP_st(1); nkeynes@377: pop_fr(R_EDX, FRn); nkeynes@380: JMP_rel8(11, end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@377: push_dr(R_EDX, FRn); nkeynes@377: push_dr(R_EDX, FRm); nkeynes@388: FSUBP_st(1); nkeynes@377: pop_dr(R_EDX, FRn); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* FMUL FRm, FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); uint32_t FRm = ((ir>>4)&0xF); nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@377: load_fr_bank( R_EDX ); nkeynes@380: JNE_rel8(13, doubleprec); nkeynes@377: push_fr(R_EDX, FRm); nkeynes@377: push_fr(R_EDX, FRn); nkeynes@377: FMULP_st(1); nkeynes@377: pop_fr(R_EDX, FRn); nkeynes@380: JMP_rel8(11, end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@377: push_dr(R_EDX, FRm); nkeynes@377: push_dr(R_EDX, FRn); nkeynes@377: FMULP_st(1); nkeynes@377: pop_dr(R_EDX, FRn); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* FDIV FRm, FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); uint32_t FRm = ((ir>>4)&0xF); 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@377: FDIVP_st(1); nkeynes@377: pop_fr(R_EDX, FRn); nkeynes@380: JMP_rel8(11, end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@377: push_dr(R_EDX, FRn); nkeynes@377: push_dr(R_EDX, FRm); nkeynes@377: FDIVP_st(1); nkeynes@377: pop_dr(R_EDX, FRn); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x4: nkeynes@359: { /* FCMP/EQ FRm, FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); uint32_t FRm = ((ir>>4)&0xF); 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@386: JMP_TARGET(end); nkeynes@377: FCOMIP_st(1); nkeynes@377: SETE_t(); nkeynes@377: FPOP_st(); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x5: nkeynes@359: { /* FCMP/GT FRm, FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); uint32_t FRm = ((ir>>4)&0xF); nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@377: load_fr_bank( R_EDX ); nkeynes@380: JNE_rel8(8, doubleprec); nkeynes@377: push_fr(R_EDX, FRm); nkeynes@377: push_fr(R_EDX, FRn); nkeynes@380: JMP_rel8(6, end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@377: push_dr(R_EDX, FRm); nkeynes@377: push_dr(R_EDX, FRn); nkeynes@380: JMP_TARGET(end); nkeynes@377: FCOMIP_st(1); nkeynes@377: SETA_t(); nkeynes@377: FPOP_st(); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x6: nkeynes@359: { /* FMOV @(R0, Rm), FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@416: precheck(); nkeynes@416: check_fpuen_no_precheck(); nkeynes@416: load_reg( R_ECX, Rm ); nkeynes@416: ADD_sh4r_r32( REG_OFFSET(r[0]), R_ECX ); nkeynes@416: check_ralign32( R_ECX ); nkeynes@416: load_spreg( R_EDX, R_FPSCR ); nkeynes@416: TEST_imm32_r32( FPSCR_SZ, R_EDX ); nkeynes@380: JNE_rel8(19, doublesize); nkeynes@416: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@416: load_fr_bank( R_EDX ); nkeynes@416: store_fr( R_EDX, R_EAX, FRn ); nkeynes@375: if( FRn&1 ) { nkeynes@386: JMP_rel8(48, end); nkeynes@380: JMP_TARGET(doublesize); nkeynes@416: MEM_READ_DOUBLE( R_ECX, R_EAX, R_ECX ); nkeynes@416: load_spreg( R_EDX, R_FPSCR ); // assume read_long clobbered it nkeynes@416: load_xf_bank( R_EDX ); nkeynes@416: store_fr( R_EDX, R_EAX, FRn&0x0E ); nkeynes@416: store_fr( R_EDX, R_ECX, FRn|0x01 ); nkeynes@380: JMP_TARGET(end); nkeynes@375: } else { nkeynes@380: JMP_rel8(36, end); nkeynes@380: JMP_TARGET(doublesize); nkeynes@416: MEM_READ_DOUBLE( R_ECX, R_EAX, R_ECX ); nkeynes@416: load_fr_bank( R_EDX ); nkeynes@416: store_fr( R_EDX, R_EAX, FRn&0x0E ); nkeynes@416: store_fr( R_EDX, R_ECX, FRn|0x01 ); nkeynes@380: JMP_TARGET(end); nkeynes@377: } nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: } nkeynes@377: break; nkeynes@377: case 0x7: nkeynes@377: { /* FMOV FRm, @(R0, Rn) */ nkeynes@377: uint32_t Rn = ((ir>>8)&0xF); uint32_t FRm = ((ir>>4)&0xF); nkeynes@416: precheck(); nkeynes@416: check_fpuen_no_precheck(); nkeynes@416: load_reg( R_ECX, Rn ); nkeynes@416: ADD_sh4r_r32( REG_OFFSET(r[0]), R_ECX ); nkeynes@416: check_walign32( R_ECX ); nkeynes@416: load_spreg( R_EDX, R_FPSCR ); nkeynes@416: TEST_imm32_r32( FPSCR_SZ, R_EDX ); nkeynes@380: JNE_rel8(20, doublesize); nkeynes@416: load_fr_bank( R_EDX ); nkeynes@416: load_fr( R_EDX, R_EAX, FRm ); nkeynes@416: MEM_WRITE_LONG( R_ECX, R_EAX ); // 12 nkeynes@377: if( FRm&1 ) { nkeynes@386: JMP_rel8( 48, end ); nkeynes@380: JMP_TARGET(doublesize); nkeynes@416: load_xf_bank( R_EDX ); nkeynes@416: load_fr( R_EDX, R_EAX, FRm&0x0E ); nkeynes@416: load_fr( R_EDX, R_EDX, FRm|0x01 ); nkeynes@416: MEM_WRITE_DOUBLE( R_ECX, R_EAX, R_EDX ); nkeynes@380: JMP_TARGET(end); nkeynes@377: } else { nkeynes@380: JMP_rel8( 39, end ); nkeynes@380: JMP_TARGET(doublesize); nkeynes@416: load_fr_bank( R_EDX ); nkeynes@416: load_fr( R_EDX, R_EAX, FRm&0x0E ); nkeynes@416: load_fr( R_EDX, R_EDX, FRm|0x01 ); nkeynes@416: MEM_WRITE_DOUBLE( R_ECX, R_EAX, R_EDX ); nkeynes@380: JMP_TARGET(end); nkeynes@377: } nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@377: } nkeynes@377: break; nkeynes@377: case 0x8: nkeynes@377: { /* FMOV @Rm, FRn */ nkeynes@377: uint32_t FRn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@416: precheck(); nkeynes@416: check_fpuen_no_precheck(); nkeynes@416: load_reg( R_ECX, Rm ); nkeynes@416: check_ralign32( R_ECX ); nkeynes@416: load_spreg( R_EDX, R_FPSCR ); nkeynes@416: TEST_imm32_r32( FPSCR_SZ, R_EDX ); nkeynes@380: JNE_rel8(19, doublesize); nkeynes@416: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@416: load_fr_bank( R_EDX ); nkeynes@416: store_fr( R_EDX, R_EAX, FRn ); nkeynes@377: if( FRn&1 ) { nkeynes@386: JMP_rel8(48, end); nkeynes@380: JMP_TARGET(doublesize); nkeynes@416: MEM_READ_DOUBLE( R_ECX, R_EAX, R_ECX ); nkeynes@416: load_spreg( R_EDX, R_FPSCR ); // assume read_long clobbered it nkeynes@416: load_xf_bank( R_EDX ); nkeynes@416: store_fr( R_EDX, R_EAX, FRn&0x0E ); nkeynes@416: store_fr( R_EDX, R_ECX, FRn|0x01 ); nkeynes@380: JMP_TARGET(end); nkeynes@377: } else { nkeynes@380: JMP_rel8(36, end); nkeynes@380: JMP_TARGET(doublesize); nkeynes@416: MEM_READ_DOUBLE( R_ECX, R_EAX, R_ECX ); nkeynes@416: load_fr_bank( R_EDX ); nkeynes@416: store_fr( R_EDX, R_EAX, FRn&0x0E ); nkeynes@416: store_fr( R_EDX, R_ECX, FRn|0x01 ); nkeynes@380: JMP_TARGET(end); nkeynes@375: } nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x9: nkeynes@359: { /* FMOV @Rm+, FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@416: precheck(); nkeynes@416: check_fpuen_no_precheck(); nkeynes@416: load_reg( R_ECX, Rm ); nkeynes@416: check_ralign32( R_ECX ); nkeynes@416: MOV_r32_r32( R_ECX, R_EAX ); nkeynes@416: load_spreg( R_EDX, R_FPSCR ); nkeynes@416: TEST_imm32_r32( FPSCR_SZ, R_EDX ); nkeynes@380: JNE_rel8(25, doublesize); nkeynes@377: ADD_imm8s_r32( 4, R_EAX ); nkeynes@377: store_reg( R_EAX, Rm ); nkeynes@416: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@416: load_fr_bank( R_EDX ); nkeynes@416: store_fr( R_EDX, 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@416: MEM_READ_DOUBLE( R_ECX, R_EAX, R_ECX ); nkeynes@416: load_spreg( R_EDX, R_FPSCR ); // assume read_long clobbered it nkeynes@416: load_xf_bank( R_EDX ); nkeynes@416: store_fr( R_EDX, R_EAX, FRn&0x0E ); nkeynes@416: store_fr( R_EDX, R_ECX, 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@416: MEM_READ_DOUBLE( R_ECX, R_EAX, R_ECX ); nkeynes@416: load_fr_bank( R_EDX ); nkeynes@416: store_fr( R_EDX, R_EAX, FRn&0x0E ); nkeynes@416: store_fr( R_EDX, R_ECX, FRn|0x01 ); nkeynes@380: JMP_TARGET(end); nkeynes@377: } nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xA: nkeynes@359: { /* FMOV FRm, @Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t FRm = ((ir>>4)&0xF); nkeynes@416: precheck(); nkeynes@416: check_fpuen_no_precheck(); nkeynes@416: load_reg( R_ECX, Rn ); nkeynes@416: check_walign32( R_ECX ); nkeynes@416: load_spreg( R_EDX, R_FPSCR ); nkeynes@416: TEST_imm32_r32( FPSCR_SZ, R_EDX ); nkeynes@380: JNE_rel8(20, doublesize); nkeynes@416: load_fr_bank( R_EDX ); nkeynes@416: load_fr( R_EDX, R_EAX, FRm ); nkeynes@416: MEM_WRITE_LONG( R_ECX, R_EAX ); // 12 nkeynes@375: if( FRm&1 ) { nkeynes@386: JMP_rel8( 48, end ); nkeynes@380: JMP_TARGET(doublesize); nkeynes@416: load_xf_bank( R_EDX ); nkeynes@416: load_fr( R_EDX, R_EAX, FRm&0x0E ); nkeynes@416: load_fr( R_EDX, R_EDX, FRm|0x01 ); nkeynes@416: MEM_WRITE_DOUBLE( R_ECX, R_EAX, R_EDX ); nkeynes@380: JMP_TARGET(end); nkeynes@375: } else { nkeynes@380: JMP_rel8( 39, end ); nkeynes@380: JMP_TARGET(doublesize); nkeynes@416: load_fr_bank( R_EDX ); nkeynes@416: load_fr( R_EDX, R_EAX, FRm&0x0E ); nkeynes@416: load_fr( R_EDX, R_EDX, FRm|0x01 ); nkeynes@416: MEM_WRITE_DOUBLE( R_ECX, R_EAX, R_EDX ); nkeynes@380: JMP_TARGET(end); nkeynes@375: } nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xB: nkeynes@359: { /* FMOV FRm, @-Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t FRm = ((ir>>4)&0xF); nkeynes@416: precheck(); nkeynes@416: check_fpuen_no_precheck(); nkeynes@416: load_reg( R_ECX, Rn ); nkeynes@416: check_walign32( R_ECX ); nkeynes@416: load_spreg( R_EDX, R_FPSCR ); nkeynes@416: TEST_imm32_r32( FPSCR_SZ, R_EDX ); nkeynes@386: JNE_rel8(26, doublesize); nkeynes@416: load_fr_bank( R_EDX ); nkeynes@416: load_fr( R_EDX, R_EAX, FRm ); nkeynes@416: ADD_imm8s_r32(-4,R_ECX); nkeynes@416: store_reg( R_ECX, Rn ); nkeynes@416: MEM_WRITE_LONG( R_ECX, R_EAX ); // 12 nkeynes@377: if( FRm&1 ) { nkeynes@386: JMP_rel8( 54, end ); nkeynes@380: JMP_TARGET(doublesize); nkeynes@416: load_xf_bank( R_EDX ); nkeynes@416: load_fr( R_EDX, R_EAX, FRm&0x0E ); nkeynes@416: load_fr( R_EDX, R_EDX, FRm|0x01 ); nkeynes@416: ADD_imm8s_r32(-8,R_ECX); nkeynes@416: store_reg( R_ECX, Rn ); nkeynes@416: MEM_WRITE_DOUBLE( R_ECX, R_EAX, R_EDX ); nkeynes@380: JMP_TARGET(end); nkeynes@377: } else { nkeynes@386: JMP_rel8( 45, end ); nkeynes@380: JMP_TARGET(doublesize); nkeynes@416: load_fr_bank( R_EDX ); nkeynes@416: load_fr( R_EDX, R_EAX, FRm&0x0E ); nkeynes@416: load_fr( R_EDX, R_EDX, FRm|0x01 ); nkeynes@416: ADD_imm8s_r32(-8,R_ECX); nkeynes@416: store_reg( R_ECX, Rn ); nkeynes@416: MEM_WRITE_DOUBLE( R_ECX, R_EAX, R_EDX ); nkeynes@380: JMP_TARGET(end); nkeynes@377: } nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xC: nkeynes@359: { /* FMOV FRm, FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); uint32_t FRm = ((ir>>4)&0xF); nkeynes@375: /* As horrible as this looks, it's actually covering 5 separate cases: nkeynes@375: * 1. 32-bit fr-to-fr (PR=0) nkeynes@375: * 2. 64-bit dr-to-dr (PR=1, FRm&1 == 0, FRn&1 == 0 ) nkeynes@375: * 3. 64-bit dr-to-xd (PR=1, FRm&1 == 0, FRn&1 == 1 ) nkeynes@375: * 4. 64-bit xd-to-dr (PR=1, FRm&1 == 1, FRn&1 == 0 ) nkeynes@375: * 5. 64-bit xd-to-xd (PR=1, FRm&1 == 1, FRn&1 == 1 ) nkeynes@375: */ nkeynes@377: check_fpuen(); nkeynes@375: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: load_fr_bank( R_EDX ); nkeynes@375: TEST_imm32_r32( FPSCR_SZ, R_ECX ); nkeynes@380: JNE_rel8(8, doublesize); nkeynes@375: load_fr( R_EDX, R_EAX, FRm ); // PR=0 branch nkeynes@375: store_fr( R_EDX, R_EAX, FRn ); nkeynes@375: if( FRm&1 ) { nkeynes@386: JMP_rel8(24, end); nkeynes@380: JMP_TARGET(doublesize); nkeynes@375: load_xf_bank( R_ECX ); nkeynes@375: load_fr( R_ECX, R_EAX, FRm-1 ); nkeynes@375: if( FRn&1 ) { nkeynes@375: load_fr( R_ECX, R_EDX, FRm ); nkeynes@375: store_fr( R_ECX, R_EAX, FRn-1 ); nkeynes@375: store_fr( R_ECX, R_EDX, FRn ); nkeynes@375: } else /* FRn&1 == 0 */ { nkeynes@375: load_fr( R_ECX, R_ECX, FRm ); nkeynes@388: store_fr( R_EDX, R_EAX, FRn ); nkeynes@388: store_fr( R_EDX, R_ECX, FRn+1 ); nkeynes@375: } nkeynes@380: JMP_TARGET(end); nkeynes@375: } else /* FRm&1 == 0 */ { nkeynes@375: if( FRn&1 ) { nkeynes@386: JMP_rel8(24, end); nkeynes@375: load_xf_bank( R_ECX ); nkeynes@375: load_fr( R_EDX, R_EAX, FRm ); nkeynes@375: load_fr( R_EDX, R_EDX, FRm+1 ); nkeynes@375: store_fr( R_ECX, R_EAX, FRn-1 ); nkeynes@375: store_fr( R_ECX, R_EDX, FRn ); nkeynes@380: JMP_TARGET(end); nkeynes@375: } else /* FRn&1 == 0 */ { nkeynes@380: JMP_rel8(12, end); nkeynes@375: load_fr( R_EDX, R_EAX, FRm ); nkeynes@375: load_fr( R_EDX, R_ECX, FRm+1 ); nkeynes@375: store_fr( R_EDX, R_EAX, FRn ); nkeynes@375: store_fr( R_EDX, R_ECX, FRn+1 ); nkeynes@380: JMP_TARGET(end); nkeynes@375: } nkeynes@375: } nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xD: nkeynes@359: switch( (ir&0xF0) >> 4 ) { nkeynes@359: case 0x0: nkeynes@359: { /* FSTS FPUL, FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); nkeynes@377: check_fpuen(); nkeynes@377: load_fr_bank( R_ECX ); nkeynes@377: load_spreg( R_EAX, R_FPUL ); nkeynes@377: store_fr( R_ECX, R_EAX, FRn ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* FLDS FRm, FPUL */ nkeynes@359: uint32_t FRm = ((ir>>8)&0xF); nkeynes@377: check_fpuen(); nkeynes@377: load_fr_bank( R_ECX ); nkeynes@377: load_fr( R_ECX, R_EAX, FRm ); nkeynes@377: store_spreg( R_EAX, R_FPUL ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* FLOAT FPUL, FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: load_spreg(R_EDX, REG_OFFSET(fr_bank)); nkeynes@377: FILD_sh4r(R_FPUL); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@380: JNE_rel8(5, doubleprec); nkeynes@377: pop_fr( R_EDX, FRn ); nkeynes@380: JMP_rel8(3, end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@377: pop_dr( R_EDX, FRn ); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* FTRC FRm, FPUL */ nkeynes@359: uint32_t FRm = ((ir>>8)&0xF); nkeynes@377: check_fpuen(); nkeynes@388: load_spreg( R_ECX, R_FPSCR ); nkeynes@388: load_fr_bank( R_EDX ); nkeynes@388: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@388: JNE_rel8(5, doubleprec); nkeynes@388: push_fr( R_EDX, FRm ); nkeynes@388: JMP_rel8(3, doop); nkeynes@388: JMP_TARGET(doubleprec); nkeynes@388: push_dr( R_EDX, FRm ); nkeynes@388: JMP_TARGET( doop ); nkeynes@388: load_imm32( R_ECX, (uint32_t)&max_int ); nkeynes@388: FILD_r32ind( R_ECX ); nkeynes@388: FCOMIP_st(1); nkeynes@394: JNA_rel8( 32, sat ); nkeynes@388: load_imm32( R_ECX, (uint32_t)&min_int ); // 5 nkeynes@388: FILD_r32ind( R_ECX ); // 2 nkeynes@388: FCOMIP_st(1); // 2 nkeynes@394: JAE_rel8( 21, sat2 ); // 2 nkeynes@394: load_imm32( R_EAX, (uint32_t)&save_fcw ); nkeynes@394: FNSTCW_r32ind( R_EAX ); nkeynes@394: load_imm32( R_EDX, (uint32_t)&trunc_fcw ); nkeynes@394: FLDCW_r32ind( R_EDX ); nkeynes@388: FISTP_sh4r(R_FPUL); // 3 nkeynes@394: FLDCW_r32ind( R_EAX ); nkeynes@388: JMP_rel8( 9, end ); // 2 nkeynes@388: nkeynes@388: JMP_TARGET(sat); nkeynes@388: JMP_TARGET(sat2); nkeynes@388: MOV_r32ind_r32( R_ECX, R_ECX ); // 2 nkeynes@388: store_spreg( R_ECX, R_FPUL ); nkeynes@388: FPOP_st(); nkeynes@388: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x4: nkeynes@359: { /* FNEG FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@377: load_fr_bank( R_EDX ); nkeynes@380: JNE_rel8(10, doubleprec); nkeynes@377: push_fr(R_EDX, FRn); nkeynes@377: FCHS_st0(); nkeynes@377: pop_fr(R_EDX, FRn); nkeynes@380: JMP_rel8(8, end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@377: push_dr(R_EDX, FRn); nkeynes@377: FCHS_st0(); nkeynes@377: pop_dr(R_EDX, FRn); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x5: nkeynes@359: { /* FABS FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); nkeynes@377: check_fpuen(); nkeynes@374: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: load_fr_bank( R_EDX ); nkeynes@374: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@380: JNE_rel8(10, doubleprec); nkeynes@374: push_fr(R_EDX, FRn); // 3 nkeynes@374: FABS_st0(); // 2 nkeynes@374: pop_fr( R_EDX, FRn); //3 nkeynes@380: JMP_rel8(8,end); // 2 nkeynes@380: JMP_TARGET(doubleprec); nkeynes@374: push_dr(R_EDX, FRn); nkeynes@374: FABS_st0(); nkeynes@374: pop_dr(R_EDX, FRn); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x6: nkeynes@359: { /* FSQRT FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@377: load_fr_bank( R_EDX ); nkeynes@380: JNE_rel8(10, doubleprec); nkeynes@377: push_fr(R_EDX, FRn); nkeynes@377: FSQRT_st0(); nkeynes@377: pop_fr(R_EDX, FRn); nkeynes@380: JMP_rel8(8, end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@377: push_dr(R_EDX, FRn); nkeynes@377: FSQRT_st0(); nkeynes@377: pop_dr(R_EDX, FRn); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x7: nkeynes@359: { /* FSRRA FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@377: load_fr_bank( R_EDX ); nkeynes@380: JNE_rel8(12, end); // PR=0 only nkeynes@377: FLD1_st0(); nkeynes@377: push_fr(R_EDX, FRn); nkeynes@377: FSQRT_st0(); nkeynes@377: FDIVP_st(1); nkeynes@377: pop_fr(R_EDX, FRn); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x8: nkeynes@359: { /* FLDI0 FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); nkeynes@377: /* IFF PR=0 */ nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@380: JNE_rel8(8, end); nkeynes@377: XOR_r32_r32( R_EAX, R_EAX ); nkeynes@377: load_spreg( R_ECX, REG_OFFSET(fr_bank) ); nkeynes@377: store_fr( R_ECX, R_EAX, FRn ); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x9: nkeynes@359: { /* FLDI1 FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); nkeynes@377: /* IFF PR=0 */ nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@380: JNE_rel8(11, end); nkeynes@377: load_imm32(R_EAX, 0x3F800000); nkeynes@377: load_spreg( R_ECX, REG_OFFSET(fr_bank) ); nkeynes@377: store_fr( R_ECX, R_EAX, FRn ); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xA: nkeynes@359: { /* FCNVSD FPUL, FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@380: JE_rel8(9, end); // only when PR=1 nkeynes@377: load_fr_bank( R_ECX ); nkeynes@377: push_fpul(); nkeynes@377: pop_dr( R_ECX, FRn ); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xB: nkeynes@359: { /* FCNVDS FRm, FPUL */ nkeynes@359: uint32_t FRm = ((ir>>8)&0xF); nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@380: JE_rel8(9, end); // only when PR=1 nkeynes@377: load_fr_bank( R_ECX ); nkeynes@377: push_dr( R_ECX, FRm ); nkeynes@377: pop_fpul(); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xE: nkeynes@359: { /* FIPR FVm, FVn */ nkeynes@359: uint32_t FVn = ((ir>>10)&0x3); uint32_t FVm = ((ir>>8)&0x3); nkeynes@377: check_fpuen(); nkeynes@388: load_spreg( R_ECX, R_FPSCR ); nkeynes@388: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@388: JNE_rel8(44, doubleprec); nkeynes@388: nkeynes@388: load_fr_bank( R_ECX ); nkeynes@388: push_fr( R_ECX, FVm<<2 ); nkeynes@388: push_fr( R_ECX, FVn<<2 ); nkeynes@388: FMULP_st(1); nkeynes@388: push_fr( R_ECX, (FVm<<2)+1); nkeynes@388: push_fr( R_ECX, (FVn<<2)+1); nkeynes@388: FMULP_st(1); nkeynes@388: FADDP_st(1); nkeynes@388: push_fr( R_ECX, (FVm<<2)+2); nkeynes@388: push_fr( R_ECX, (FVn<<2)+2); nkeynes@388: FMULP_st(1); nkeynes@388: FADDP_st(1); nkeynes@388: push_fr( R_ECX, (FVm<<2)+3); nkeynes@388: push_fr( R_ECX, (FVn<<2)+3); nkeynes@388: FMULP_st(1); nkeynes@388: FADDP_st(1); nkeynes@388: pop_fr( R_ECX, (FVn<<2)+3); nkeynes@388: JMP_TARGET(doubleprec); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xF: nkeynes@359: switch( (ir&0x100) >> 8 ) { nkeynes@359: case 0x0: nkeynes@359: { /* FSCA FPUL, FRn */ nkeynes@359: uint32_t FRn = ((ir>>9)&0x7)<<1; 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: switch( (ir&0x200) >> 9 ) { nkeynes@359: case 0x0: nkeynes@359: { /* FTRV XMTRX, FVn */ nkeynes@359: uint32_t FVn = ((ir>>10)&0x3); 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@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: switch( (ir&0xC00) >> 10 ) { nkeynes@359: case 0x0: nkeynes@359: { /* FSCHG */ nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: XOR_imm32_r32( FPSCR_SZ, R_ECX ); nkeynes@377: store_spreg( R_ECX, R_FPSCR ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* FRCHG */ nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: XOR_imm32_r32( FPSCR_FR, R_ECX ); nkeynes@377: store_spreg( R_ECX, R_FPSCR ); nkeynes@386: update_fr_bank( R_ECX ); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* UNDEF */ nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@386: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@416: precheck(); nkeynes@386: JMP_exit(EXIT_ILLEGAL); nkeynes@408: return 2; nkeynes@374: } nkeynes@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xE: nkeynes@359: { /* FMAC FR0, FRm, FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); uint32_t FRm = ((ir>>4)&0xF); nkeynes@377: check_fpuen(); nkeynes@377: load_spreg( R_ECX, R_FPSCR ); nkeynes@377: load_spreg( R_EDX, REG_OFFSET(fr_bank)); nkeynes@377: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@380: JNE_rel8(18, doubleprec); nkeynes@377: push_fr( R_EDX, 0 ); nkeynes@377: push_fr( R_EDX, FRm ); nkeynes@377: FMULP_st(1); nkeynes@377: push_fr( R_EDX, FRn ); nkeynes@377: FADDP_st(1); nkeynes@377: pop_fr( R_EDX, FRn ); nkeynes@380: JMP_rel8(16, end); nkeynes@380: JMP_TARGET(doubleprec); nkeynes@377: push_dr( R_EDX, 0 ); nkeynes@377: push_dr( R_EDX, FRm ); nkeynes@377: FMULP_st(1); nkeynes@377: push_dr( R_EDX, FRn ); nkeynes@377: FADDP_st(1); nkeynes@377: pop_dr( R_EDX, FRn ); nkeynes@380: JMP_TARGET(end); nkeynes@417: sh4_x86.tstate = TSTATE_NONE; nkeynes@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: } nkeynes@359: nkeynes@416: sh4_x86.in_delay_slot = FALSE; nkeynes@359: return 0; nkeynes@359: }