nkeynes@359: /** nkeynes@374: * $Id: sh4x86.c,v 1.4 2007-09-11 02:14:46 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@368: nkeynes@368: #include "sh4/sh4core.h" nkeynes@368: #include "sh4/sh4trans.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@368: nkeynes@368: /* Allocated memory for the (block-wide) back-patch list */ nkeynes@368: uint32_t **backpatch_list; nkeynes@368: uint32_t backpatch_posn; nkeynes@368: uint32_t backpatch_size; nkeynes@368: }; nkeynes@368: nkeynes@368: #define EXIT_DATA_ADDR_READ 0 nkeynes@368: #define EXIT_DATA_ADDR_WRITE 7 nkeynes@368: #define EXIT_ILLEGAL 14 nkeynes@368: #define EXIT_SLOT_ILLEGAL 21 nkeynes@368: #define EXIT_FPU_DISABLED 28 nkeynes@368: #define EXIT_SLOT_FPU_DISABLED 35 nkeynes@368: nkeynes@368: static struct sh4_x86_state sh4_x86; nkeynes@368: nkeynes@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> 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@374: call_func0(sh4_read_sr); nkeynes@368: store_reg( R_EAX, Rn ); 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@359: load_spreg( R_EAX, R_VBR ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* STC SSR, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_spreg( R_EAX, R_SSR ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x4: nkeynes@359: { /* STC SPC, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_spreg( R_EAX, R_SPC ); 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 0x1: nkeynes@359: { /* STC Rm_BANK, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm_BANK = ((ir>>4)&0x7); nkeynes@374: load_spreg( R_EAX, REG_OFFSET(r_bank[Rm_BANK]) ); nkeynes@374: store_reg( R_EAX, Rn ); 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@374: load_imm32( R_EAX, pc + 4 ); nkeynes@374: store_spreg( R_EAX, R_PR ); nkeynes@374: load_reg( R_EDI, Rn ); nkeynes@374: ADD_r32_r32( R_EAX, R_EDI ); nkeynes@374: sh4_x86.in_delay_slot = TRUE; nkeynes@374: INC_r32(R_ESI); nkeynes@374: return 0; 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@374: load_reg( R_EDI, Rn ); nkeynes@374: sh4_x86.in_delay_slot = TRUE; nkeynes@374: INC_r32(R_ESI); nkeynes@374: return 0; 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@374: JNE_rel8(8); nkeynes@374: call_func0( sh4_flush_store_queue ); nkeynes@374: ADD_imm8s_r32( -4, R_ESP ); 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@374: check_walign32( R_ECX ); nkeynes@361: MEM_WRITE_LONG( R_ECX, R_EAX ); 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@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@374: check_walign16( R_ECX ); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: MEM_WRITE_WORD( R_ECX, R_EAX ); 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@374: check_walign32( R_ECX ); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: MEM_WRITE_LONG( R_ECX, R_EAX ); 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@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@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* SETT */ nkeynes@374: STC(); nkeynes@374: SETC_t(); 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@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@359: } nkeynes@359: break; nkeynes@359: case 0x5: nkeynes@359: { /* SETS */ nkeynes@374: STC(); nkeynes@374: SETC_sh4r(R_S); 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@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@359: load_spreg( R_EAX, R_SGR ); nkeynes@359: store_reg( R_EAX, Rn ); 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@359: load_spreg( R_EAX, R_DBR ); 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 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@374: load_spreg( R_EDI, R_PR ); nkeynes@374: sh4_x86.in_delay_slot = TRUE; nkeynes@374: INC_r32(R_ESI); nkeynes@374: return 0; nkeynes@374: } nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* SLEEP */ nkeynes@374: /* TODO */ nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* RTE */ nkeynes@374: check_priv(); nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: SLOTILLEGAL(); nkeynes@374: } else { nkeynes@374: load_spreg( R_EDI, R_PR ); 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@374: INC_r32(R_ESI); nkeynes@374: return 0; 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@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@374: check_ralign16( R_ECX ); nkeynes@361: MEM_READ_WORD( R_ECX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); 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@374: check_ralign32( R_ECX ); nkeynes@361: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); 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@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@374: check_walign32( R_ECX ); nkeynes@361: MEM_WRITE_LONG( R_ECX, R_EAX ); 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@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@374: check_walign16( R_ECX ); nkeynes@361: MEM_READ_WORD( R_ECX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); 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@374: check_walign32(R_ECX); nkeynes@361: MEM_WRITE_LONG( R_ECX, R_EAX ); 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@359: ADD_imm8s_r32( -1, Rn ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: MEM_WRITE_BYTE( R_ECX, R_EAX ); nkeynes@359: } nkeynes@359: 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@374: check_walign16( R_ECX ); nkeynes@361: load_reg( R_EAX, Rm ); nkeynes@361: ADD_imm8s_r32( -2, R_ECX ); nkeynes@361: MEM_WRITE_WORD( R_ECX, R_EAX ); 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@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@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@361: load_reg( R_ECX, Rm ); 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@361: SETE_t(); 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@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@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@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@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@368: JE_rel8(13); nkeynes@368: TEST_r8_r8( R_AH, R_AH ); // 2 nkeynes@368: JE_rel8(9); nkeynes@368: SHR_imm8_r32( 16, R_EAX ); // 3 nkeynes@368: TEST_r8_r8( R_AL, R_AL ); // 2 nkeynes@368: JE_rel8(2); nkeynes@368: TEST_r8_r8( R_AH, R_AH ); // 2 nkeynes@368: SETE_t(); 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@361: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@361: SHR_imm8_r32( 16, R_EAX ); nkeynes@361: SHL_imm8_r32( 16, R_ECX ); nkeynes@361: OR_r32_r32( R_EAX, R_ECX ); nkeynes@361: store_reg( R_ECX, Rn ); nkeynes@359: } nkeynes@359: 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@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@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@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@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@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@374: load_reg( R_ECX, Rn ); nkeynes@374: LDC_t(); nkeynes@374: RCL1_r32( R_ECX ); // OP2 nkeynes@374: SETC_r32( R_EDX ); // Q nkeynes@374: load_spreg( R_EAX, R_Q ); nkeynes@374: CMP_sh4r_r32( R_M, R_EAX ); nkeynes@374: JE_rel8(8); nkeynes@374: ADD_sh4r_r32( REG_OFFSET(r[Rm]), R_ECX ); nkeynes@374: JMP_rel8(3); nkeynes@374: SUB_sh4r_r32( REG_OFFSET(r[Rm]), R_ECX ); nkeynes@374: // TODO 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@361: store_spreg( R_EAX, R_MACL ); 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@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@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@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@359: LDC_t(); nkeynes@359: SBB_r32_r32( R_EAX, R_ECX ); nkeynes@359: store_reg( R_ECX, Rn ); 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@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@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@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@359: load_reg( R_EAX, Rm ); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: LDC_t(); nkeynes@359: ADC_r32_r32( R_EAX, R_ECX ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: SETC_t(); nkeynes@359: } nkeynes@359: 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@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@359: store_reg( R_EAX, Rn ); 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@359: ADD_imm8s_r32( -1, Rn ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: SETE_t(); 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@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 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@359: store_reg( R_EAX, Rn ); 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@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@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 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@359: ADD_imm8s_r32( -4, Rn ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: load_spreg( R_EAX, R_MACH ); nkeynes@359: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@359: } nkeynes@359: 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@359: ADD_imm8s_r32( -4, Rn ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: load_spreg( R_EAX, R_MACL ); nkeynes@359: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@359: } nkeynes@359: 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@359: ADD_imm8s_r32( -4, Rn ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: load_spreg( R_EAX, R_PR ); nkeynes@359: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* STC.L SGR, @-Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: ADD_imm8s_r32( -4, Rn ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: load_spreg( R_EAX, R_SGR ); nkeynes@359: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@359: } nkeynes@359: 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@359: ADD_imm8s_r32( -4, Rn ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: load_spreg( R_EAX, R_FPUL ); nkeynes@359: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@359: } nkeynes@359: 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@359: ADD_imm8s_r32( -4, Rn ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: load_spreg( R_EAX, R_FPSCR ); nkeynes@359: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xF: nkeynes@359: { /* STC.L DBR, @-Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: ADD_imm8s_r32( -4, Rn ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: load_spreg( R_EAX, R_DBR ); nkeynes@359: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@359: } nkeynes@359: 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@374: load_reg( R_ECX, Rn ); nkeynes@374: ADD_imm8s_r32( -4, Rn ); nkeynes@374: store_reg( R_ECX, Rn ); nkeynes@374: call_func0( sh4_read_sr ); nkeynes@374: MEM_WRITE_LONG( R_ECX, R_EAX ); 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@359: ADD_imm8s_r32( -4, Rn ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: load_spreg( R_EAX, R_GBR ); nkeynes@359: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* STC.L VBR, @-Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: ADD_imm8s_r32( -4, Rn ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: load_spreg( R_EAX, R_VBR ); nkeynes@359: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* STC.L SSR, @-Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: ADD_imm8s_r32( -4, Rn ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: load_spreg( R_EAX, R_SSR ); nkeynes@359: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x4: nkeynes@359: { /* STC.L SPC, @-Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: load_reg( R_ECX, Rn ); nkeynes@359: ADD_imm8s_r32( -4, Rn ); nkeynes@359: store_reg( R_ECX, Rn ); nkeynes@359: load_spreg( R_EAX, R_SPC ); nkeynes@359: MEM_WRITE_LONG( R_ECX, R_EAX ); nkeynes@359: } nkeynes@359: 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@374: load_reg( R_ECX, Rn ); nkeynes@374: ADD_imm8s_r32( -4, Rn ); 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@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@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@359: LDC_t(); nkeynes@359: RCL1_r32( R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: SETC_t(); 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@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@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@359: LDC_t(); nkeynes@359: RCR1_r32( R_EAX ); nkeynes@359: store_reg( R_EAX, Rn ); nkeynes@359: SETC_t(); 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@359: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@359: ADD_imm8s_r32( 4, R_EAX ); nkeynes@359: store_reg( R_EAX, Rm ); nkeynes@359: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_MACH ); nkeynes@359: } nkeynes@359: 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@359: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@359: ADD_imm8s_r32( 4, R_EAX ); nkeynes@359: store_reg( R_EAX, Rm ); nkeynes@359: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_MACL ); nkeynes@359: } nkeynes@359: 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@359: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@359: ADD_imm8s_r32( 4, R_EAX ); nkeynes@359: store_reg( R_EAX, Rm ); nkeynes@359: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_PR ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* LDC.L @Rm+, SGR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@359: ADD_imm8s_r32( 4, R_EAX ); nkeynes@359: store_reg( R_EAX, Rm ); nkeynes@359: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_SGR ); nkeynes@359: } nkeynes@359: 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@359: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@359: ADD_imm8s_r32( 4, R_EAX ); nkeynes@359: store_reg( R_EAX, Rm ); nkeynes@359: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_FPUL ); nkeynes@359: } nkeynes@359: 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@359: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@359: ADD_imm8s_r32( 4, R_EAX ); nkeynes@359: store_reg( R_EAX, Rm ); nkeynes@359: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_FPSCR ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xF: nkeynes@359: { /* LDC.L @Rm+, DBR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@359: ADD_imm8s_r32( 4, R_EAX ); nkeynes@359: store_reg( R_EAX, Rm ); nkeynes@359: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_DBR ); nkeynes@359: } nkeynes@359: 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@368: load_reg( R_EAX, Rm ); nkeynes@368: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@368: ADD_imm8s_r32( 4, R_EAX ); nkeynes@368: store_reg( R_EAX, Rm ); nkeynes@368: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@374: call_func1( sh4_write_sr, R_EAX ); 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@359: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@359: ADD_imm8s_r32( 4, R_EAX ); nkeynes@359: store_reg( R_EAX, Rm ); nkeynes@359: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_GBR ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* LDC.L @Rm+, VBR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@359: ADD_imm8s_r32( 4, R_EAX ); nkeynes@359: store_reg( R_EAX, Rm ); nkeynes@359: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_VBR ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* LDC.L @Rm+, SSR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@359: ADD_imm8s_r32( 4, R_EAX ); nkeynes@359: store_reg( R_EAX, Rm ); nkeynes@359: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_SSR ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x4: nkeynes@359: { /* LDC.L @Rm+, SPC */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@359: ADD_imm8s_r32( 4, R_EAX ); nkeynes@359: store_reg( R_EAX, Rm ); nkeynes@359: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@359: store_spreg( R_EAX, R_SPC ); nkeynes@359: } nkeynes@359: 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@374: load_reg( R_EAX, Rm ); nkeynes@374: MOV_r32_r32( R_EAX, R_ECX ); nkeynes@374: ADD_imm8s_r32( 4, R_EAX ); nkeynes@374: store_reg( R_EAX, Rm ); nkeynes@374: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@374: store_spreg( R_EAX, REG_OFFSET(r_bank[Rn_BANK]) ); nkeynes@359: } nkeynes@359: 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@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@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@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@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@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@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@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_SGR ); 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@359: } nkeynes@359: break; nkeynes@359: case 0xF: nkeynes@359: { /* LDC Rm, DBR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_DBR ); 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@374: load_reg( R_EDI, Rn ); nkeynes@374: sh4_x86.in_delay_slot = TRUE; nkeynes@374: INC_r32(R_ESI); nkeynes@374: return 0; 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@361: MEM_WRITE_BYTE( R_ECX, R_EAX ); 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@374: load_reg( R_EDI, Rn ); nkeynes@374: sh4_x86.in_delay_slot = TRUE; nkeynes@374: INC_r32(R_ESI); nkeynes@374: return 0; 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@361: JAE_rel8(9); nkeynes@361: nkeynes@361: NEG_r32( R_ECX ); // 2 nkeynes@361: AND_imm8_r8( 0x1F, R_CL ); // 3 nkeynes@361: SAR_r32_CL( R_EAX ); // 2 nkeynes@361: JMP_rel8(5); // 2 nkeynes@361: nkeynes@361: AND_imm8_r8( 0x1F, R_CL ); // 3 nkeynes@361: SHL_r32_CL( R_EAX ); // 2 nkeynes@361: nkeynes@361: store_reg( R_EAX, Rn ); 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@368: nkeynes@368: MOV_r32_r32( R_EAX, R_EDX ); nkeynes@368: SHL_r32_CL( R_EAX ); nkeynes@368: NEG_r32( R_ECX ); nkeynes@368: SHR_r32_CL( R_EDX ); nkeynes@368: CMP_imm8s_r32( 0, R_ECX ); nkeynes@368: CMOVAE_r32_r32( R_EDX, R_EAX ); nkeynes@368: store_reg( R_EAX, Rn ); 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@368: load_reg( R_EAX, Rm ); nkeynes@374: call_func1( sh4_write_sr, R_EAX ); 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@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_VBR ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* LDC Rm, SSR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_SSR ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x4: nkeynes@359: { /* LDC Rm, SPC */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: load_reg( R_EAX, Rm ); nkeynes@359: store_spreg( R_EAX, R_SPC ); 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@374: load_reg( R_EAX, Rm ); nkeynes@374: store_spreg( R_EAX, REG_OFFSET(r_bank[Rn_BANK]) ); 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@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@374: check_ralign32( R_ECX ); nkeynes@361: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); 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@359: store_reg( R_ECX, Rn ); 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@374: check_ralign16( R_ECX ); nkeynes@361: MEM_READ_WORD( R_ECX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); 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@374: check_ralign32( R_ECX ); nkeynes@361: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@361: store_reg( R_EAX, Rn ); 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@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@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@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@374: check_ralign32( R_ECX ); 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@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@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@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@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@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@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@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@374: check_walign16( R_ECX ); nkeynes@361: MEM_WRITE_WORD( R_ECX, R_EAX ); 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@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@374: check_ralign16( R_ECX ); nkeynes@361: MEM_READ_WORD( R_ECX, R_EAX ); nkeynes@361: store_reg( R_EAX, 0 ); 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@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@374: load_imm32( R_EDI, pc + 2 ); nkeynes@374: CMP_imm8s_sh4r( 0, R_T ); nkeynes@374: JE_rel8( 5 ); nkeynes@374: load_imm32( R_EDI, disp + pc + 4 ); nkeynes@374: INC_r32(R_ESI); nkeynes@374: return 1; 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@374: load_imm32( R_EDI, pc + 2 ); nkeynes@374: CMP_imm8s_sh4r( 0, R_T ); nkeynes@374: JNE_rel8( 5 ); nkeynes@374: load_imm32( R_EDI, disp + pc + 4 ); nkeynes@374: INC_r32(R_ESI); nkeynes@374: return 1; 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@374: load_imm32( R_EDI, pc + 2 ); nkeynes@374: CMP_imm8s_sh4r( 0, R_T ); nkeynes@374: JE_rel8( 5 ); nkeynes@374: load_imm32( R_EDI, disp + pc + 4 ); nkeynes@374: sh4_x86.in_delay_slot = TRUE; nkeynes@374: INC_r32(R_ESI); nkeynes@374: return 0; 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@374: load_imm32( R_EDI, pc + 2 ); nkeynes@374: CMP_imm8s_sh4r( 0, R_T ); nkeynes@374: JNE_rel8( 5 ); nkeynes@374: load_imm32( R_EDI, disp + pc + 4 ); nkeynes@374: sh4_x86.in_delay_slot = TRUE; nkeynes@374: INC_r32(R_ESI); nkeynes@374: return 0; 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@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: load_imm32( R_EDI, disp + pc + 4 ); nkeynes@374: sh4_x86.in_delay_slot = TRUE; nkeynes@374: INC_r32(R_ESI); nkeynes@374: return 0; 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: load_imm32( R_EDI, disp + pc + 4 ); nkeynes@374: sh4_x86.in_delay_slot = TRUE; nkeynes@374: INC_r32(R_ESI); nkeynes@374: return 0; 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@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@374: check_walign16( R_ECX ); nkeynes@361: MEM_WRITE_WORD( R_ECX, R_EAX ); 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@374: check_walign32( R_ECX ); nkeynes@361: MEM_WRITE_LONG( R_ECX, R_EAX ); 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@374: // TODO: Write TRA nkeynes@374: RAISE_EXCEPTION(EXC_TRAP); 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@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@374: check_ralign16( R_ECX ); nkeynes@361: MEM_READ_WORD( R_ECX, R_EAX ); nkeynes@361: store_reg( R_EAX, 0 ); 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@374: check_ralign32( R_ECX ); nkeynes@361: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@361: store_reg( R_EAX, 0 ); 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@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@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@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@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@368: TEST_imm8_r8( imm, R_EAX ); nkeynes@368: SETE_t(); 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@359: MEM_READ_BYTE( R_ECX, R_EAX ); nkeynes@359: AND_imm32_r32(imm, R_ECX ); nkeynes@359: MEM_WRITE_BYTE( R_ECX, R_EAX ); nkeynes@359: } nkeynes@359: 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@359: MEM_READ_BYTE( R_ECX, R_EAX ); nkeynes@359: XOR_imm32_r32( imm, R_EAX ); nkeynes@359: MEM_WRITE_BYTE( R_ECX, R_EAX ); nkeynes@359: } nkeynes@359: 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@374: MEM_READ_BYTE( R_ECX, R_EAX ); nkeynes@374: OR_imm32_r32(imm, R_ECX ); nkeynes@374: MEM_WRITE_BYTE( R_ECX, R_EAX ); 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@374: load_imm32( R_ECX, (pc & 0xFFFFFFFC) + disp + 4 ); nkeynes@374: MEM_READ_LONG( R_ECX, R_EAX ); nkeynes@374: store_reg( R_EAX, 0 ); 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@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@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@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@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@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@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@359: } nkeynes@359: break; nkeynes@359: case 0x7: nkeynes@359: { /* FMOV FRm, @(R0, Rn) */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t FRm = ((ir>>4)&0xF); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x8: nkeynes@359: { /* FMOV @Rm, FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); 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@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@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@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@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@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* FLDS FRm, FPUL */ nkeynes@359: uint32_t FRm = ((ir>>8)&0xF); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* FLOAT FPUL, FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* FTRC FRm, FPUL */ nkeynes@359: uint32_t FRm = ((ir>>8)&0xF); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x4: nkeynes@359: { /* FNEG FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x5: nkeynes@359: { /* FABS FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); nkeynes@374: load_spreg( R_ECX, R_FPSCR ); nkeynes@374: load_spreg( R_EDX, REG_OFFSET(fr_bank) ); nkeynes@374: TEST_imm32_r32( FPSCR_PR, R_ECX ); nkeynes@374: JNE_rel8(10); nkeynes@374: push_fr(R_EDX, FRn); // 3 nkeynes@374: FABS_st0(); // 2 nkeynes@374: pop_fr( R_EDX, FRn); //3 nkeynes@374: JMP_rel8(8); // 2 nkeynes@374: push_dr(R_EDX, FRn); nkeynes@374: FABS_st0(); nkeynes@374: pop_dr(R_EDX, FRn); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x6: nkeynes@359: { /* FSQRT FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x7: nkeynes@359: { /* FSRRA FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x8: nkeynes@359: { /* FLDI0 FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x9: nkeynes@359: { /* FLDI1 FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xA: nkeynes@359: { /* FCNVSD FPUL, FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xB: nkeynes@359: { /* FCNVDS FRm, FPUL */ nkeynes@359: uint32_t FRm = ((ir>>8)&0xF); 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@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@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@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: switch( (ir&0xC00) >> 10 ) { nkeynes@359: case 0x0: nkeynes@359: { /* FSCHG */ nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* FRCHG */ nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* UNDEF */ nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: RAISE_EXCEPTION(EXC_SLOT_ILLEGAL); nkeynes@374: } else { nkeynes@374: RAISE_EXCEPTION(EXC_ILLEGAL); nkeynes@374: } nkeynes@374: return 1; 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@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: } nkeynes@359: nkeynes@368: INC_r32(R_ESI); nkeynes@374: if( sh4_x86.in_delay_slot ) { nkeynes@374: sh4_x86.in_delay_slot = FALSE; nkeynes@374: return 1; nkeynes@374: } nkeynes@359: return 0; nkeynes@359: }