nkeynes@23: /** nkeynes@401: * $Id: sh4core.c,v 1.48 2007-09-20 08:37:19 nkeynes Exp $ nkeynes@23: * nkeynes@23: * SH4 emulation core, and parent module for all the SH4 peripheral nkeynes@23: * modules. nkeynes@23: * nkeynes@23: * Copyright (c) 2005 Nathan Keynes. nkeynes@23: * nkeynes@23: * This program is free software; you can redistribute it and/or modify nkeynes@23: * it under the terms of the GNU General Public License as published by nkeynes@23: * the Free Software Foundation; either version 2 of the License, or nkeynes@23: * (at your option) any later version. nkeynes@23: * nkeynes@23: * This program is distributed in the hope that it will be useful, nkeynes@23: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@23: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@23: * GNU General Public License for more details. nkeynes@23: */ nkeynes@23: nkeynes@35: #define MODULE sh4_module nkeynes@1: #include nkeynes@1: #include "dream.h" nkeynes@84: #include "sh4/sh4core.h" nkeynes@84: #include "sh4/sh4mmio.h" nkeynes@84: #include "sh4/intc.h" nkeynes@1: #include "mem.h" nkeynes@23: #include "clock.h" nkeynes@102: #include "syscall.h" nkeynes@1: nkeynes@157: #define SH4_CALLTRACE 1 nkeynes@157: nkeynes@123: #define MAX_INT 0x7FFFFFFF nkeynes@123: #define MIN_INT 0x80000000 nkeynes@123: #define MAX_INTF 2147483647.0 nkeynes@123: #define MIN_INTF -2147483648.0 nkeynes@123: nkeynes@23: /********************** SH4 Module Definition ****************************/ nkeynes@23: nkeynes@391: uint16_t *sh4_icache = NULL; nkeynes@391: uint32_t sh4_icache_addr = 0; nkeynes@43: nkeynes@30: uint32_t sh4_run_slice( uint32_t nanosecs ) nkeynes@1: { nkeynes@23: int i; nkeynes@265: sh4r.slice_cycle = 0; nkeynes@23: nkeynes@27: if( sh4r.sh4_state != SH4_STATE_RUNNING ) { nkeynes@265: if( sh4r.event_pending < nanosecs ) { nkeynes@265: sh4r.sh4_state = SH4_STATE_RUNNING; nkeynes@265: sh4r.slice_cycle = sh4r.event_pending; nkeynes@265: } nkeynes@23: } nkeynes@27: nkeynes@235: if( sh4_breakpoint_count == 0 ) { nkeynes@265: for( ; sh4r.slice_cycle < nanosecs; sh4r.slice_cycle += sh4_cpu_period ) { nkeynes@265: if( SH4_EVENT_PENDING() ) { nkeynes@265: if( sh4r.event_types & PENDING_EVENT ) { nkeynes@265: event_execute(); nkeynes@265: } nkeynes@265: /* Eventq execute may (quite likely) deliver an immediate IRQ */ nkeynes@265: if( sh4r.event_types & PENDING_IRQ ) { nkeynes@265: sh4_accept_interrupt(); nkeynes@265: } nkeynes@265: } nkeynes@235: if( !sh4_execute_instruction() ) { nkeynes@43: break; nkeynes@43: } nkeynes@43: } nkeynes@235: } else { nkeynes@265: for( ;sh4r.slice_cycle < nanosecs; sh4r.slice_cycle += sh4_cpu_period ) { nkeynes@265: if( SH4_EVENT_PENDING() ) { nkeynes@265: if( sh4r.event_types & PENDING_EVENT ) { nkeynes@265: event_execute(); nkeynes@265: } nkeynes@265: /* Eventq execute may (quite likely) deliver an immediate IRQ */ nkeynes@265: if( sh4r.event_types & PENDING_IRQ ) { nkeynes@265: sh4_accept_interrupt(); nkeynes@265: } nkeynes@265: } nkeynes@265: nkeynes@235: if( !sh4_execute_instruction() ) nkeynes@235: break; nkeynes@235: #ifdef ENABLE_DEBUG_MODE nkeynes@235: for( i=0; i 0 ) { nkeynes@157: call_stack_depth--; nkeynes@157: } nkeynes@157: } nkeynes@157: nkeynes@157: void fprint_stack_trace( FILE *f ) nkeynes@157: { nkeynes@157: int i = call_stack_depth -1; nkeynes@157: if( i >= MAX_CALLSTACK ) nkeynes@157: i = MAX_CALLSTACK - 1; nkeynes@157: for( ; i >= 0; i-- ) { nkeynes@157: fprintf( f, "%d. Call from %08X => %08X, SP=%08X\n", nkeynes@157: (call_stack_depth - i), call_stack[i].call_addr, nkeynes@157: call_stack[i].target_addr, call_stack[i].stack_pointer ); nkeynes@157: } nkeynes@157: } nkeynes@157: nkeynes@157: #define TRACE_CALL( source, dest ) trace_call(source, dest) nkeynes@157: #define TRACE_RETURN( source, dest ) trace_return(source, dest) nkeynes@157: #else nkeynes@157: #define TRACE_CALL( dest, rts ) nkeynes@157: #define TRACE_RETURN( source, dest ) nkeynes@157: #endif nkeynes@157: nkeynes@10: #define MEM_READ_BYTE( addr ) sh4_read_byte(addr) nkeynes@10: #define MEM_READ_WORD( addr ) sh4_read_word(addr) nkeynes@10: #define MEM_READ_LONG( addr ) sh4_read_long(addr) nkeynes@10: #define MEM_WRITE_BYTE( addr, val ) sh4_write_byte(addr, val) nkeynes@10: #define MEM_WRITE_WORD( addr, val ) sh4_write_word(addr, val) nkeynes@10: #define MEM_WRITE_LONG( addr, val ) sh4_write_long(addr, val) nkeynes@1: nkeynes@1: #define FP_WIDTH (IS_FPU_DOUBLESIZE() ? 8 : 4) nkeynes@1: nkeynes@124: #define MEM_FP_READ( addr, reg ) sh4_read_float( addr, reg ); nkeynes@124: #define MEM_FP_WRITE( addr, reg ) sh4_write_float( addr, reg ); nkeynes@84: nkeynes@246: #define CHECKPRIV() if( !IS_SH4_PRIVMODE() ) return sh4_raise_slot_exception( EXC_ILLEGAL, EXC_SLOT_ILLEGAL ) nkeynes@367: #define CHECKRALIGN16(addr) if( (addr)&0x01 ) return sh4_raise_exception( EXC_DATA_ADDR_READ ) nkeynes@367: #define CHECKRALIGN32(addr) if( (addr)&0x03 ) return sh4_raise_exception( EXC_DATA_ADDR_READ ) nkeynes@367: #define CHECKWALIGN16(addr) if( (addr)&0x01 ) return sh4_raise_exception( EXC_DATA_ADDR_WRITE ) nkeynes@367: #define CHECKWALIGN32(addr) if( (addr)&0x03 ) return sh4_raise_exception( EXC_DATA_ADDR_WRITE ) nkeynes@208: nkeynes@367: #define CHECKFPUEN() if( !IS_FPU_ENABLED() ) { if( ir == 0xFFFD ) { UNDEF(ir); } else { return sh4_raise_slot_exception( EXC_FPU_DISABLED, EXC_SLOT_FPU_DISABLED ); } } nkeynes@84: #define CHECKDEST(p) if( (p) == 0 ) { ERROR( "%08X: Branch/jump to NULL, CPU halted", sh4r.pc ); dreamcast_stop(); return FALSE; } nkeynes@246: #define CHECKSLOTILLEGAL() if(sh4r.in_delay_slot) return sh4_raise_exception(EXC_SLOT_ILLEGAL) nkeynes@1: nkeynes@124: static void sh4_write_float( uint32_t addr, int reg ) nkeynes@124: { nkeynes@124: if( IS_FPU_DOUBLESIZE() ) { nkeynes@124: if( reg & 1 ) { nkeynes@124: sh4_write_long( addr, *((uint32_t *)&XF((reg)&0x0E)) ); nkeynes@124: sh4_write_long( addr+4, *((uint32_t *)&XF(reg)) ); nkeynes@124: } else { nkeynes@124: sh4_write_long( addr, *((uint32_t *)&FR(reg)) ); nkeynes@124: sh4_write_long( addr+4, *((uint32_t *)&FR((reg)|0x01)) ); nkeynes@124: } nkeynes@124: } else { nkeynes@124: sh4_write_long( addr, *((uint32_t *)&FR((reg))) ); nkeynes@124: } nkeynes@124: } nkeynes@124: nkeynes@124: static void sh4_read_float( uint32_t addr, int reg ) nkeynes@124: { nkeynes@124: if( IS_FPU_DOUBLESIZE() ) { nkeynes@124: if( reg & 1 ) { nkeynes@124: *((uint32_t *)&XF((reg) & 0x0E)) = sh4_read_long(addr); nkeynes@124: *((uint32_t *)&XF(reg)) = sh4_read_long(addr+4); nkeynes@124: } else { nkeynes@124: *((uint32_t *)&FR(reg)) = sh4_read_long(addr); nkeynes@124: *((uint32_t *)&FR((reg) | 0x01)) = sh4_read_long(addr+4); nkeynes@124: } nkeynes@124: } else { nkeynes@124: *((uint32_t *)&FR(reg)) = sh4_read_long(addr); nkeynes@124: } nkeynes@124: } nkeynes@124: nkeynes@27: gboolean sh4_execute_instruction( void ) nkeynes@1: { nkeynes@84: uint32_t pc; nkeynes@2: unsigned short ir; nkeynes@1: uint32_t tmp; nkeynes@123: float ftmp; nkeynes@123: double dtmp; nkeynes@1: nkeynes@1: #define R0 sh4r.r[0] nkeynes@2: pc = sh4r.pc; nkeynes@84: if( pc > 0xFFFFFF00 ) { nkeynes@84: /* SYSCALL Magic */ nkeynes@102: syscall_invoke( pc ); nkeynes@104: sh4r.in_delay_slot = 0; nkeynes@84: pc = sh4r.pc = sh4r.pr; nkeynes@84: sh4r.new_pc = sh4r.pc + 2; nkeynes@84: } nkeynes@208: CHECKRALIGN16(pc); nkeynes@235: nkeynes@235: /* Read instruction */ nkeynes@235: uint32_t pageaddr = pc >> 12; nkeynes@235: if( sh4_icache != NULL && pageaddr == sh4_icache_addr ) { nkeynes@235: ir = sh4_icache[(pc&0xFFF)>>1]; nkeynes@235: } else { nkeynes@235: sh4_icache = (uint16_t *)mem_get_page(pc); nkeynes@235: if( ((uint32_t)sh4_icache) < MAX_IO_REGIONS ) { nkeynes@235: /* If someone's actually been so daft as to try to execute out of an IO nkeynes@235: * region, fallback on the full-blown memory read nkeynes@235: */ nkeynes@235: sh4_icache = NULL; nkeynes@235: ir = MEM_READ_WORD(pc); nkeynes@235: } else { nkeynes@235: sh4_icache_addr = pageaddr; nkeynes@235: ir = sh4_icache[(pc&0xFFF)>>1]; nkeynes@235: } nkeynes@235: } 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@359: CHECKPRIV(); nkeynes@359: sh4r.r[Rn] = sh4_read_sr(); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* STC GBR, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: CHECKPRIV(); nkeynes@359: sh4r.r[Rn] = sh4r.gbr; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* STC VBR, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: CHECKPRIV(); nkeynes@359: sh4r.r[Rn] = sh4r.vbr; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* STC SSR, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: CHECKPRIV(); nkeynes@359: sh4r.r[Rn] = sh4r.ssr; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x4: nkeynes@359: { /* STC SPC, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: CHECKPRIV(); nkeynes@359: sh4r.r[Rn] = sh4r.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: { /* STC Rm_BANK, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm_BANK = ((ir>>4)&0x7); nkeynes@359: CHECKPRIV(); nkeynes@359: sh4r.r[Rn] = sh4r.r_bank[Rm_BANK]; 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@359: CHECKSLOTILLEGAL(); nkeynes@359: CHECKDEST( pc + 4 + sh4r.r[Rn] ); nkeynes@359: sh4r.in_delay_slot = 1; nkeynes@359: sh4r.pr = sh4r.pc + 4; nkeynes@359: sh4r.pc = sh4r.new_pc; nkeynes@359: sh4r.new_pc = pc + 4 + sh4r.r[Rn]; nkeynes@359: TRACE_CALL( pc, sh4r.new_pc ); nkeynes@359: return TRUE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* BRAF Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: CHECKSLOTILLEGAL(); nkeynes@359: CHECKDEST( pc + 4 + sh4r.r[Rn] ); nkeynes@359: sh4r.in_delay_slot = 1; nkeynes@359: sh4r.pc = sh4r.new_pc; nkeynes@359: sh4r.new_pc = pc + 4 + sh4r.r[Rn]; nkeynes@359: return TRUE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x8: nkeynes@359: { /* PREF @Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: tmp = sh4r.r[Rn]; nkeynes@359: if( (tmp & 0xFC000000) == 0xE0000000 ) { nkeynes@369: sh4_flush_store_queue(tmp); nkeynes@359: } 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@359: tmp = sh4r.r[Rn]; nkeynes@359: CHECKWALIGN32(tmp); nkeynes@359: MEM_WRITE_LONG( tmp, R0 ); 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: MEM_WRITE_BYTE( R0 + sh4r.r[Rn], sh4r.r[Rm] ); 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@359: CHECKWALIGN16( R0 + sh4r.r[Rn] ); nkeynes@359: MEM_WRITE_WORD( R0 + sh4r.r[Rn], sh4r.r[Rm] ); 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@359: CHECKWALIGN32( R0 + sh4r.r[Rn] ); nkeynes@359: MEM_WRITE_LONG( R0 + sh4r.r[Rn], sh4r.r[Rm] ); 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@359: sh4r.mac = (sh4r.mac&0xFFFFFFFF00000000LL) | nkeynes@359: (sh4r.r[Rm] * sh4r.r[Rn]); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x8: nkeynes@359: switch( (ir&0xFF0) >> 4 ) { nkeynes@359: case 0x0: nkeynes@359: { /* CLRT */ nkeynes@359: sh4r.t = 0; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* SETT */ nkeynes@359: sh4r.t = 1; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* CLRMAC */ nkeynes@359: sh4r.mac = 0; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* LDTLB */ nkeynes@359: /* TODO */ nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x4: nkeynes@359: { /* CLRS */ nkeynes@359: sh4r.s = 0; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x5: nkeynes@359: { /* SETS */ nkeynes@359: sh4r.s = 1; 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: /* NOP */ nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* DIV0U */ nkeynes@359: sh4r.m = sh4r.q = sh4r.t = 0; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* MOVT Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: sh4r.r[Rn] = sh4r.t; 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: sh4r.r[Rn] = (sh4r.mac>>32); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* STS MACL, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: sh4r.r[Rn] = (uint32_t)sh4r.mac; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* STS PR, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: sh4r.r[Rn] = sh4r.pr; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* STC SGR, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: CHECKPRIV(); nkeynes@359: sh4r.r[Rn] = sh4r.sgr; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x5: nkeynes@359: { /* STS FPUL, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: sh4r.r[Rn] = sh4r.fpul; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x6: nkeynes@359: { /* STS FPSCR, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: sh4r.r[Rn] = sh4r.fpscr; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xF: nkeynes@359: { /* STC DBR, Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: CHECKPRIV(); sh4r.r[Rn] = sh4r.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&0xFF0) >> 4 ) { nkeynes@359: case 0x0: nkeynes@359: { /* RTS */ nkeynes@359: CHECKSLOTILLEGAL(); nkeynes@359: CHECKDEST( sh4r.pr ); nkeynes@359: sh4r.in_delay_slot = 1; nkeynes@359: sh4r.pc = sh4r.new_pc; nkeynes@359: sh4r.new_pc = sh4r.pr; nkeynes@359: TRACE_RETURN( pc, sh4r.new_pc ); nkeynes@359: return TRUE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* SLEEP */ nkeynes@359: if( MMIO_READ( CPG, STBCR ) & 0x80 ) { nkeynes@359: sh4r.sh4_state = SH4_STATE_STANDBY; nkeynes@359: } else { nkeynes@359: sh4r.sh4_state = SH4_STATE_SLEEP; nkeynes@359: } nkeynes@359: return FALSE; /* Halt CPU */ nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* RTE */ nkeynes@359: CHECKPRIV(); nkeynes@359: CHECKDEST( sh4r.spc ); nkeynes@359: CHECKSLOTILLEGAL(); nkeynes@359: sh4r.in_delay_slot = 1; nkeynes@359: sh4r.pc = sh4r.new_pc; nkeynes@359: sh4r.new_pc = sh4r.spc; nkeynes@374: sh4_write_sr( sh4r.ssr ); nkeynes@359: return TRUE; 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: sh4r.r[Rn] = MEM_READ_BYTE( R0 + sh4r.r[Rm] ); 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@359: CHECKRALIGN16( R0 + sh4r.r[Rm] ); nkeynes@359: sh4r.r[Rn] = MEM_READ_WORD( R0 + sh4r.r[Rm] ); 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@359: CHECKRALIGN32( R0 + sh4r.r[Rm] ); nkeynes@359: sh4r.r[Rn] = MEM_READ_LONG( R0 + sh4r.r[Rm] ); 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: CHECKRALIGN32( sh4r.r[Rm] ); nkeynes@359: CHECKRALIGN32( sh4r.r[Rn] ); nkeynes@359: int64_t tmpl = SIGNEXT32(MEM_READ_LONG(sh4r.r[Rn])); nkeynes@359: sh4r.r[Rn] += 4; nkeynes@359: tmpl = tmpl * SIGNEXT32(MEM_READ_LONG(sh4r.r[Rm])) + sh4r.mac; nkeynes@359: sh4r.r[Rm] += 4; nkeynes@359: if( sh4r.s ) { nkeynes@359: /* 48-bit Saturation. Yuch */ nkeynes@359: if( tmpl < (int64_t)0xFFFF800000000000LL ) nkeynes@359: tmpl = 0xFFFF800000000000LL; nkeynes@359: else if( tmpl > (int64_t)0x00007FFFFFFFFFFFLL ) nkeynes@359: tmpl = 0x00007FFFFFFFFFFFLL; nkeynes@359: } nkeynes@359: sh4r.mac = tmpl; 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@359: tmp = sh4r.r[Rn] + disp; nkeynes@359: CHECKWALIGN32( tmp ); nkeynes@359: MEM_WRITE_LONG( tmp, sh4r.r[Rm] ); 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: MEM_WRITE_BYTE( sh4r.r[Rn], sh4r.r[Rm] ); 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@359: CHECKWALIGN16( sh4r.r[Rn] ); MEM_WRITE_WORD( sh4r.r[Rn], sh4r.r[Rm] ); 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@359: CHECKWALIGN32( sh4r.r[Rn] ); MEM_WRITE_LONG( sh4r.r[Rn], sh4r.r[Rm] ); 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: sh4r.r[Rn] --; MEM_WRITE_BYTE( sh4r.r[Rn], sh4r.r[Rm] ); 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@359: sh4r.r[Rn] -= 2; CHECKWALIGN16( sh4r.r[Rn] ); MEM_WRITE_WORD( sh4r.r[Rn], sh4r.r[Rm] ); 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@359: sh4r.r[Rn] -= 4; CHECKWALIGN32( sh4r.r[Rn] ); MEM_WRITE_LONG( sh4r.r[Rn], sh4r.r[Rm] ); 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@359: sh4r.q = sh4r.r[Rn]>>31; nkeynes@359: sh4r.m = sh4r.r[Rm]>>31; nkeynes@359: sh4r.t = sh4r.q ^ sh4r.m; 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@359: sh4r.t = (sh4r.r[Rn]&sh4r.r[Rm] ? 0 : 1); 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: sh4r.r[Rn] &= sh4r.r[Rm]; 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: sh4r.r[Rn] ^= sh4r.r[Rm]; 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: sh4r.r[Rn] |= sh4r.r[Rm]; 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@359: /* set T = 1 if any byte in RM & RN is the same */ nkeynes@359: tmp = sh4r.r[Rm] ^ sh4r.r[Rn]; nkeynes@359: sh4r.t = ((tmp&0x000000FF)==0 || (tmp&0x0000FF00)==0 || nkeynes@359: (tmp&0x00FF0000)==0 || (tmp&0xFF000000)==0)?1:0; 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@359: sh4r.r[Rn] = (sh4r.r[Rn]>>16) | (sh4r.r[Rm]<<16); 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@359: sh4r.mac = (sh4r.mac&0xFFFFFFFF00000000LL) | nkeynes@359: (uint32_t)((sh4r.r[Rm]&0xFFFF) * (sh4r.r[Rn]&0xFFFF)); 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@359: sh4r.mac = (sh4r.mac&0xFFFFFFFF00000000LL) | nkeynes@359: (uint32_t)(SIGNEXT32(sh4r.r[Rm]&0xFFFF) * SIGNEXT32(sh4r.r[Rn]&0xFFFF)); 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: sh4r.t = ( sh4r.r[Rm] == sh4r.r[Rn] ? 1 : 0 ); 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: sh4r.t = ( sh4r.r[Rn] >= sh4r.r[Rm] ? 1 : 0 ); 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: sh4r.t = ( ((int32_t)sh4r.r[Rn]) >= ((int32_t)sh4r.r[Rm]) ? 1 : 0 ); 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@384: /* This is derived from the sh4 manual with some simplifications */ nkeynes@359: uint32_t tmp0, tmp1, tmp2, dir; nkeynes@359: nkeynes@359: dir = sh4r.q ^ sh4r.m; nkeynes@359: sh4r.q = (sh4r.r[Rn] >> 31); nkeynes@359: tmp2 = sh4r.r[Rm]; nkeynes@359: sh4r.r[Rn] = (sh4r.r[Rn] << 1) | sh4r.t; nkeynes@359: tmp0 = sh4r.r[Rn]; nkeynes@359: if( dir ) { nkeynes@359: sh4r.r[Rn] += tmp2; nkeynes@359: tmp1 = (sh4r.r[Rn]tmp0 ? 1 : 0 ); nkeynes@359: } nkeynes@359: sh4r.q ^= sh4r.m ^ tmp1; nkeynes@359: sh4r.t = ( sh4r.q == sh4r.m ? 1 : 0 ); 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@359: sh4r.mac = ((uint64_t)sh4r.r[Rm]) * ((uint64_t)sh4r.r[Rn]); 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: sh4r.t = ( sh4r.r[Rn] > sh4r.r[Rm] ? 1 : 0 ); 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: sh4r.t = ( ((int32_t)sh4r.r[Rn]) > ((int32_t)sh4r.r[Rm]) ? 1 : 0 ); 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: sh4r.r[Rn] -= sh4r.r[Rm]; 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: tmp = sh4r.r[Rn]; nkeynes@359: sh4r.r[Rn] = sh4r.r[Rn] - sh4r.r[Rm] - sh4r.t; nkeynes@359: sh4r.t = (sh4r.r[Rn] > tmp || (sh4r.r[Rn] == tmp && sh4r.t == 1)); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xB: nkeynes@359: UNIMP(ir); /* SUBV Rm, Rn */ 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: sh4r.r[Rn] += sh4r.r[Rm]; 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@359: sh4r.mac = SIGNEXT32(sh4r.r[Rm]) * SIGNEXT32(sh4r.r[Rn]); 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: tmp = sh4r.r[Rn]; nkeynes@359: sh4r.r[Rn] += sh4r.r[Rm] + sh4r.t; nkeynes@359: sh4r.t = ( sh4r.r[Rn] < tmp || (sh4r.r[Rn] == tmp && sh4r.t != 0) ? 1 : 0 ); 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: tmp = sh4r.r[Rn] + sh4r.r[Rm]; nkeynes@359: sh4r.t = ( (sh4r.r[Rn]>>31) == (sh4r.r[Rm]>>31) && ((sh4r.r[Rn]>>31) != (tmp>>31)) ); nkeynes@359: sh4r.r[Rn] = tmp; 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: sh4r.t = sh4r.r[Rn] >> 31; sh4r.r[Rn] <<= 1; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* DT Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: sh4r.r[Rn] --; nkeynes@359: sh4r.t = ( sh4r.r[Rn] == 0 ? 1 : 0 ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* SHAL Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: sh4r.t = sh4r.r[Rn] >> 31; nkeynes@359: sh4r.r[Rn] <<= 1; 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: sh4r.t = sh4r.r[Rn] & 0x00000001; sh4r.r[Rn] >>= 1; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* CMP/PZ Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: sh4r.t = ( ((int32_t)sh4r.r[Rn]) >= 0 ? 1 : 0 ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* SHAR Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: sh4r.t = sh4r.r[Rn] & 0x00000001; nkeynes@359: sh4r.r[Rn] = ((int32_t)sh4r.r[Rn]) >> 1; 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: sh4r.r[Rn] -= 4; nkeynes@359: CHECKWALIGN32( sh4r.r[Rn] ); nkeynes@359: MEM_WRITE_LONG( sh4r.r[Rn], (sh4r.mac>>32) ); 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: sh4r.r[Rn] -= 4; nkeynes@359: CHECKWALIGN32( sh4r.r[Rn] ); nkeynes@359: MEM_WRITE_LONG( sh4r.r[Rn], (uint32_t)sh4r.mac ); 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: sh4r.r[Rn] -= 4; nkeynes@359: CHECKWALIGN32( sh4r.r[Rn] ); nkeynes@359: MEM_WRITE_LONG( sh4r.r[Rn], sh4r.pr ); 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: CHECKPRIV(); nkeynes@359: sh4r.r[Rn] -= 4; nkeynes@359: CHECKWALIGN32( sh4r.r[Rn] ); nkeynes@359: MEM_WRITE_LONG( sh4r.r[Rn], sh4r.sgr ); 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: sh4r.r[Rn] -= 4; nkeynes@359: CHECKWALIGN32( sh4r.r[Rn] ); nkeynes@359: MEM_WRITE_LONG( sh4r.r[Rn], sh4r.fpul ); 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: sh4r.r[Rn] -= 4; nkeynes@359: CHECKWALIGN32( sh4r.r[Rn] ); nkeynes@359: MEM_WRITE_LONG( sh4r.r[Rn], sh4r.fpscr ); 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: CHECKPRIV(); nkeynes@359: sh4r.r[Rn] -= 4; nkeynes@359: CHECKWALIGN32( sh4r.r[Rn] ); nkeynes@359: MEM_WRITE_LONG( sh4r.r[Rn], sh4r.dbr ); 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@359: CHECKPRIV(); nkeynes@359: sh4r.r[Rn] -= 4; nkeynes@359: CHECKWALIGN32( sh4r.r[Rn] ); nkeynes@359: MEM_WRITE_LONG( sh4r.r[Rn], sh4_read_sr() ); 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: sh4r.r[Rn] -= 4; nkeynes@359: CHECKWALIGN32( sh4r.r[Rn] ); nkeynes@359: MEM_WRITE_LONG( sh4r.r[Rn], sh4r.gbr ); 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: CHECKPRIV(); nkeynes@359: sh4r.r[Rn] -= 4; nkeynes@359: CHECKWALIGN32( sh4r.r[Rn] ); nkeynes@359: MEM_WRITE_LONG( sh4r.r[Rn], sh4r.vbr ); 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: CHECKPRIV(); nkeynes@359: sh4r.r[Rn] -= 4; nkeynes@359: CHECKWALIGN32( sh4r.r[Rn] ); nkeynes@359: MEM_WRITE_LONG( sh4r.r[Rn], sh4r.ssr ); 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: CHECKPRIV(); nkeynes@359: sh4r.r[Rn] -= 4; nkeynes@359: CHECKWALIGN32( sh4r.r[Rn] ); nkeynes@359: MEM_WRITE_LONG( sh4r.r[Rn], sh4r.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: { /* STC.L Rm_BANK, @-Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); uint32_t Rm_BANK = ((ir>>4)&0x7); nkeynes@359: CHECKPRIV(); nkeynes@359: sh4r.r[Rn] -= 4; nkeynes@359: CHECKWALIGN32( sh4r.r[Rn] ); nkeynes@359: MEM_WRITE_LONG( sh4r.r[Rn], sh4r.r_bank[Rm_BANK] ); 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: sh4r.t = sh4r.r[Rn] >> 31; nkeynes@359: sh4r.r[Rn] <<= 1; nkeynes@359: sh4r.r[Rn] |= sh4r.t; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* ROTCL Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: tmp = sh4r.r[Rn] >> 31; nkeynes@359: sh4r.r[Rn] <<= 1; nkeynes@359: sh4r.r[Rn] |= sh4r.t; nkeynes@359: sh4r.t = tmp; 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: sh4r.t = sh4r.r[Rn] & 0x00000001; nkeynes@359: sh4r.r[Rn] >>= 1; nkeynes@359: sh4r.r[Rn] |= (sh4r.t << 31); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* CMP/PL Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: sh4r.t = ( ((int32_t)sh4r.r[Rn]) > 0 ? 1 : 0 ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* ROTCR Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: tmp = sh4r.r[Rn] & 0x00000001; nkeynes@359: sh4r.r[Rn] >>= 1; nkeynes@359: sh4r.r[Rn] |= (sh4r.t << 31 ); nkeynes@359: sh4r.t = tmp; 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: CHECKRALIGN32( sh4r.r[Rm] ); nkeynes@359: sh4r.mac = (sh4r.mac & 0x00000000FFFFFFFF) | nkeynes@359: (((uint64_t)MEM_READ_LONG(sh4r.r[Rm]))<<32); nkeynes@359: sh4r.r[Rm] += 4; 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: CHECKRALIGN32( sh4r.r[Rm] ); nkeynes@359: sh4r.mac = (sh4r.mac & 0xFFFFFFFF00000000LL) | nkeynes@359: (uint64_t)((uint32_t)MEM_READ_LONG(sh4r.r[Rm])); nkeynes@359: sh4r.r[Rm] += 4; 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: CHECKRALIGN32( sh4r.r[Rm] ); nkeynes@359: sh4r.pr = MEM_READ_LONG( sh4r.r[Rm] ); nkeynes@359: sh4r.r[Rm] += 4; 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: CHECKPRIV(); nkeynes@359: CHECKRALIGN32( sh4r.r[Rm] ); nkeynes@359: sh4r.sgr = MEM_READ_LONG(sh4r.r[Rm]); nkeynes@359: sh4r.r[Rm] +=4; 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: CHECKRALIGN32( sh4r.r[Rm] ); nkeynes@359: sh4r.fpul = MEM_READ_LONG(sh4r.r[Rm]); nkeynes@359: sh4r.r[Rm] +=4; 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: CHECKRALIGN32( sh4r.r[Rm] ); nkeynes@359: sh4r.fpscr = MEM_READ_LONG(sh4r.r[Rm]); nkeynes@359: sh4r.r[Rm] +=4; nkeynes@374: sh4r.fr_bank = &sh4r.fr[(sh4r.fpscr&FPSCR_FR)>>21][0]; 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: CHECKPRIV(); nkeynes@359: CHECKRALIGN32( sh4r.r[Rm] ); nkeynes@359: sh4r.dbr = MEM_READ_LONG(sh4r.r[Rm]); nkeynes@359: sh4r.r[Rm] +=4; 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@359: CHECKSLOTILLEGAL(); nkeynes@359: CHECKPRIV(); nkeynes@359: CHECKWALIGN32( sh4r.r[Rm] ); nkeynes@374: sh4_write_sr( MEM_READ_LONG(sh4r.r[Rm]) ); nkeynes@359: sh4r.r[Rm] +=4; 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: CHECKRALIGN32( sh4r.r[Rm] ); nkeynes@359: sh4r.gbr = MEM_READ_LONG(sh4r.r[Rm]); nkeynes@359: sh4r.r[Rm] +=4; 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: CHECKPRIV(); nkeynes@359: CHECKRALIGN32( sh4r.r[Rm] ); nkeynes@359: sh4r.vbr = MEM_READ_LONG(sh4r.r[Rm]); nkeynes@359: sh4r.r[Rm] +=4; 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: CHECKPRIV(); nkeynes@359: CHECKRALIGN32( sh4r.r[Rm] ); nkeynes@359: sh4r.ssr = MEM_READ_LONG(sh4r.r[Rm]); nkeynes@359: sh4r.r[Rm] +=4; 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: CHECKPRIV(); nkeynes@359: CHECKRALIGN32( sh4r.r[Rm] ); nkeynes@359: sh4r.spc = MEM_READ_LONG(sh4r.r[Rm]); nkeynes@359: sh4r.r[Rm] +=4; 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@359: CHECKPRIV(); nkeynes@359: CHECKRALIGN32( sh4r.r[Rm] ); nkeynes@359: sh4r.r_bank[Rn_BANK] = MEM_READ_LONG( sh4r.r[Rm] ); nkeynes@359: sh4r.r[Rm] += 4; 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: sh4r.r[Rn] <<= 2; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* SHLL8 Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: sh4r.r[Rn] <<= 8; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* SHLL16 Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: sh4r.r[Rn] <<= 16; 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: sh4r.r[Rn] >>= 2; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* SHLR8 Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: sh4r.r[Rn] >>= 8; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* SHLR16 Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: sh4r.r[Rn] >>= 16; 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: sh4r.mac = (sh4r.mac & 0x00000000FFFFFFFF) | nkeynes@359: (((uint64_t)sh4r.r[Rm])<<32); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* LDS Rm, MACL */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: sh4r.mac = (sh4r.mac & 0xFFFFFFFF00000000LL) | nkeynes@359: (uint64_t)((uint32_t)(sh4r.r[Rm])); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* LDS Rm, PR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: sh4r.pr = sh4r.r[Rm]; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* LDC Rm, SGR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: CHECKPRIV(); nkeynes@359: sh4r.sgr = sh4r.r[Rm]; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x5: nkeynes@359: { /* LDS Rm, FPUL */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: sh4r.fpul = sh4r.r[Rm]; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x6: nkeynes@359: { /* LDS Rm, FPSCR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@374: sh4r.fpscr = sh4r.r[Rm]; nkeynes@374: sh4r.fr_bank = &sh4r.fr[(sh4r.fpscr&FPSCR_FR)>>21][0]; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xF: nkeynes@359: { /* LDC Rm, DBR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: CHECKPRIV(); nkeynes@359: sh4r.dbr = sh4r.r[Rm]; 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@359: CHECKDEST( sh4r.r[Rn] ); nkeynes@359: CHECKSLOTILLEGAL(); nkeynes@359: sh4r.in_delay_slot = 1; nkeynes@359: sh4r.pc = sh4r.new_pc; nkeynes@359: sh4r.new_pc = sh4r.r[Rn]; nkeynes@359: sh4r.pr = pc + 4; nkeynes@359: TRACE_CALL( pc, sh4r.new_pc ); nkeynes@359: return TRUE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* TAS.B @Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: tmp = MEM_READ_BYTE( sh4r.r[Rn] ); nkeynes@359: sh4r.t = ( tmp == 0 ? 1 : 0 ); nkeynes@359: MEM_WRITE_BYTE( sh4r.r[Rn], tmp | 0x80 ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* JMP @Rn */ nkeynes@359: uint32_t Rn = ((ir>>8)&0xF); nkeynes@359: CHECKDEST( sh4r.r[Rn] ); nkeynes@359: CHECKSLOTILLEGAL(); nkeynes@359: sh4r.in_delay_slot = 1; nkeynes@359: sh4r.pc = sh4r.new_pc; nkeynes@359: sh4r.new_pc = sh4r.r[Rn]; nkeynes@359: return TRUE; 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: tmp = sh4r.r[Rm]; nkeynes@359: if( (tmp & 0x80000000) == 0 ) sh4r.r[Rn] <<= (tmp&0x1f); nkeynes@359: else if( (tmp & 0x1F) == 0 ) nkeynes@359: sh4r.r[Rn] = ((int32_t)sh4r.r[Rn]) >> 31; nkeynes@359: else nkeynes@359: sh4r.r[Rn] = ((int32_t)sh4r.r[Rn]) >> (((~sh4r.r[Rm]) & 0x1F)+1); 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@359: tmp = sh4r.r[Rm]; nkeynes@359: if( (tmp & 0x80000000) == 0 ) sh4r.r[Rn] <<= (tmp&0x1f); nkeynes@359: else if( (tmp & 0x1F) == 0 ) sh4r.r[Rn] = 0; nkeynes@359: else sh4r.r[Rn] >>= (((~tmp) & 0x1F)+1); 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@359: CHECKSLOTILLEGAL(); nkeynes@359: CHECKPRIV(); nkeynes@374: sh4_write_sr( sh4r.r[Rm] ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* LDC Rm, GBR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: sh4r.gbr = sh4r.r[Rm]; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* LDC Rm, VBR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: CHECKPRIV(); nkeynes@359: sh4r.vbr = sh4r.r[Rm]; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* LDC Rm, SSR */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: CHECKPRIV(); nkeynes@359: sh4r.ssr = sh4r.r[Rm]; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x4: nkeynes@359: { /* LDC Rm, SPC */ nkeynes@359: uint32_t Rm = ((ir>>8)&0xF); nkeynes@359: CHECKPRIV(); nkeynes@359: sh4r.spc = sh4r.r[Rm]; 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@359: CHECKPRIV(); nkeynes@359: sh4r.r_bank[Rn_BANK] = sh4r.r[Rm]; 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: CHECKRALIGN16( sh4r.r[Rn] ); nkeynes@359: CHECKRALIGN16( sh4r.r[Rm] ); nkeynes@359: int32_t stmp = SIGNEXT16(MEM_READ_WORD(sh4r.r[Rn])); nkeynes@359: sh4r.r[Rn] += 2; nkeynes@359: stmp = stmp * SIGNEXT16(MEM_READ_WORD(sh4r.r[Rm])); nkeynes@359: sh4r.r[Rm] += 2; nkeynes@359: if( sh4r.s ) { nkeynes@359: int64_t tmpl = (int64_t)((int32_t)sh4r.mac) + (int64_t)stmp; nkeynes@359: if( tmpl > (int64_t)0x000000007FFFFFFFLL ) { nkeynes@359: sh4r.mac = 0x000000017FFFFFFFLL; nkeynes@359: } else if( tmpl < (int64_t)0xFFFFFFFF80000000LL ) { nkeynes@359: sh4r.mac = 0x0000000180000000LL; nkeynes@359: } else { nkeynes@359: sh4r.mac = (sh4r.mac & 0xFFFFFFFF00000000LL) | nkeynes@359: ((uint32_t)(sh4r.mac + stmp)); nkeynes@359: } nkeynes@359: } else { nkeynes@359: sh4r.mac += SIGNEXT32(stmp); nkeynes@359: } 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@359: tmp = sh4r.r[Rm] + disp; nkeynes@359: CHECKRALIGN32( tmp ); nkeynes@359: sh4r.r[Rn] = MEM_READ_LONG( tmp ); 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: sh4r.r[Rn] = MEM_READ_BYTE( sh4r.r[Rm] ); 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@359: CHECKRALIGN16( sh4r.r[Rm] ); sh4r.r[Rn] = MEM_READ_WORD( sh4r.r[Rm] ); 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@359: CHECKRALIGN32( sh4r.r[Rm] ); sh4r.r[Rn] = MEM_READ_LONG( sh4r.r[Rm] ); 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: sh4r.r[Rn] = sh4r.r[Rm]; 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: sh4r.r[Rn] = MEM_READ_BYTE( sh4r.r[Rm] ); sh4r.r[Rm] ++; 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@359: CHECKRALIGN16( sh4r.r[Rm] ); sh4r.r[Rn] = MEM_READ_WORD( sh4r.r[Rm] ); sh4r.r[Rm] += 2; 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@359: CHECKRALIGN32( sh4r.r[Rm] ); sh4r.r[Rn] = MEM_READ_LONG( sh4r.r[Rm] ); sh4r.r[Rm] += 4; 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: sh4r.r[Rn] = ~sh4r.r[Rm]; 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: sh4r.r[Rn] = (sh4r.r[Rm]&0xFFFF0000) | ((sh4r.r[Rm]&0x0000FF00)>>8) | ((sh4r.r[Rm]&0x000000FF)<<8); 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: sh4r.r[Rn] = (sh4r.r[Rm]>>16) | (sh4r.r[Rm]<<16); 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: tmp = 0 - sh4r.r[Rm]; nkeynes@359: sh4r.r[Rn] = tmp - sh4r.t; nkeynes@359: sh4r.t = ( 0>8)&0xF); uint32_t Rm = ((ir>>4)&0xF); nkeynes@359: sh4r.r[Rn] = 0 - sh4r.r[Rm]; 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@359: sh4r.r[Rn] = sh4r.r[Rm]&0x000000FF; 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@359: sh4r.r[Rn] = sh4r.r[Rm]&0x0000FFFF; 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: sh4r.r[Rn] = SIGNEXT8( sh4r.r[Rm]&0x000000FF ); 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@359: sh4r.r[Rn] = SIGNEXT16( sh4r.r[Rm]&0x0000FFFF ); 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: sh4r.r[Rn] += imm; 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: MEM_WRITE_BYTE( sh4r.r[Rn] + disp, R0 ); 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@359: tmp = sh4r.r[Rn] + disp; nkeynes@359: CHECKWALIGN16( tmp ); nkeynes@359: MEM_WRITE_WORD( tmp, R0 ); 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: R0 = MEM_READ_BYTE( sh4r.r[Rm] + disp ); 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@359: tmp = sh4r.r[Rm] + disp; nkeynes@359: CHECKRALIGN16( tmp ); nkeynes@359: R0 = MEM_READ_WORD( tmp ); 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: sh4r.t = ( R0 == imm ? 1 : 0 ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x9: nkeynes@359: { /* BT disp */ nkeynes@359: int32_t disp = SIGNEXT8(ir&0xFF)<<1; nkeynes@359: CHECKSLOTILLEGAL(); nkeynes@359: if( sh4r.t ) { nkeynes@359: CHECKDEST( sh4r.pc + disp + 4 ) nkeynes@359: sh4r.pc += disp + 4; nkeynes@359: sh4r.new_pc = sh4r.pc + 2; nkeynes@27: return TRUE; nkeynes@359: } nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xB: nkeynes@359: { /* BF disp */ nkeynes@359: int32_t disp = SIGNEXT8(ir&0xFF)<<1; nkeynes@359: CHECKSLOTILLEGAL(); nkeynes@359: if( !sh4r.t ) { nkeynes@359: CHECKDEST( sh4r.pc + disp + 4 ) nkeynes@359: sh4r.pc += disp + 4; nkeynes@359: sh4r.new_pc = sh4r.pc + 2; nkeynes@359: return TRUE; nkeynes@359: } nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xD: nkeynes@359: { /* BT/S disp */ nkeynes@359: int32_t disp = SIGNEXT8(ir&0xFF)<<1; nkeynes@359: CHECKSLOTILLEGAL(); nkeynes@359: if( sh4r.t ) { nkeynes@359: CHECKDEST( sh4r.pc + disp + 4 ) nkeynes@2: sh4r.in_delay_slot = 1; nkeynes@1: sh4r.pc = sh4r.new_pc; nkeynes@359: sh4r.new_pc = pc + disp + 4; nkeynes@359: sh4r.in_delay_slot = 1; nkeynes@27: return TRUE; nkeynes@359: } nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xF: nkeynes@359: { /* BF/S disp */ nkeynes@359: int32_t disp = SIGNEXT8(ir&0xFF)<<1; nkeynes@359: CHECKSLOTILLEGAL(); nkeynes@359: if( !sh4r.t ) { nkeynes@359: CHECKDEST( sh4r.pc + disp + 4 ) nkeynes@2: sh4r.in_delay_slot = 1; nkeynes@1: sh4r.pc = sh4r.new_pc; nkeynes@359: sh4r.new_pc = pc + disp + 4; nkeynes@27: return TRUE; nkeynes@359: } 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@359: CHECKSLOTILLEGAL(); nkeynes@359: tmp = pc + 4 + disp; nkeynes@359: sh4r.r[Rn] = MEM_READ_WORD( tmp ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xA: nkeynes@359: { /* BRA disp */ nkeynes@359: int32_t disp = SIGNEXT12(ir&0xFFF)<<1; nkeynes@359: CHECKSLOTILLEGAL(); nkeynes@359: CHECKDEST( sh4r.pc + disp + 4 ); nkeynes@359: sh4r.in_delay_slot = 1; nkeynes@359: sh4r.pc = sh4r.new_pc; nkeynes@359: sh4r.new_pc = pc + 4 + disp; nkeynes@359: return TRUE; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xB: nkeynes@359: { /* BSR disp */ nkeynes@359: int32_t disp = SIGNEXT12(ir&0xFFF)<<1; nkeynes@359: CHECKDEST( sh4r.pc + disp + 4 ); nkeynes@359: CHECKSLOTILLEGAL(); nkeynes@359: sh4r.in_delay_slot = 1; nkeynes@359: sh4r.pr = pc + 4; nkeynes@359: sh4r.pc = sh4r.new_pc; nkeynes@359: sh4r.new_pc = pc + 4 + disp; nkeynes@359: TRACE_CALL( pc, sh4r.new_pc ); nkeynes@359: return TRUE; 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: MEM_WRITE_BYTE( sh4r.gbr + disp, R0 ); 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@359: tmp = sh4r.gbr + disp; nkeynes@359: CHECKWALIGN16( tmp ); nkeynes@359: MEM_WRITE_WORD( tmp, R0 ); 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@359: tmp = sh4r.gbr + disp; nkeynes@359: CHECKWALIGN32( tmp ); nkeynes@359: MEM_WRITE_LONG( tmp, R0 ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* TRAPA #imm */ nkeynes@359: uint32_t imm = (ir&0xFF); nkeynes@359: CHECKSLOTILLEGAL(); nkeynes@359: MMIO_WRITE( MMU, TRA, imm<<2 ); nkeynes@359: sh4r.pc += 2; nkeynes@359: sh4_raise_exception( EXC_TRAP ); 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: R0 = MEM_READ_BYTE( sh4r.gbr + disp ); 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@359: tmp = sh4r.gbr + disp; nkeynes@359: CHECKRALIGN16( tmp ); nkeynes@359: R0 = MEM_READ_WORD( tmp ); 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@359: tmp = sh4r.gbr + disp; nkeynes@359: CHECKRALIGN32( tmp ); nkeynes@359: R0 = MEM_READ_LONG( tmp ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x7: nkeynes@359: { /* MOVA @(disp, PC), R0 */ nkeynes@359: uint32_t disp = (ir&0xFF)<<2; nkeynes@359: CHECKSLOTILLEGAL(); nkeynes@359: R0 = (pc&0xFFFFFFFC) + disp + 4; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x8: nkeynes@359: { /* TST #imm, R0 */ nkeynes@359: uint32_t imm = (ir&0xFF); nkeynes@359: sh4r.t = (R0 & imm ? 0 : 1); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x9: nkeynes@359: { /* AND #imm, R0 */ nkeynes@359: uint32_t imm = (ir&0xFF); nkeynes@359: R0 &= imm; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xA: nkeynes@359: { /* XOR #imm, R0 */ nkeynes@359: uint32_t imm = (ir&0xFF); nkeynes@359: R0 ^= imm; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xB: nkeynes@359: { /* OR #imm, R0 */ nkeynes@359: uint32_t imm = (ir&0xFF); nkeynes@359: R0 |= imm; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xC: nkeynes@359: { /* TST.B #imm, @(R0, GBR) */ nkeynes@359: uint32_t imm = (ir&0xFF); nkeynes@359: sh4r.t = ( MEM_READ_BYTE(R0 + sh4r.gbr) & imm ? 0 : 1 ); 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: MEM_WRITE_BYTE( R0 + sh4r.gbr, imm & MEM_READ_BYTE(R0 + sh4r.gbr) ); 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: MEM_WRITE_BYTE( R0 + sh4r.gbr, imm ^ MEM_READ_BYTE(R0 + sh4r.gbr) ); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xF: nkeynes@359: { /* OR.B #imm, @(R0, GBR) */ nkeynes@359: uint32_t imm = (ir&0xFF); nkeynes@359: MEM_WRITE_BYTE( R0 + sh4r.gbr, imm | MEM_READ_BYTE(R0 + sh4r.gbr) ); 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@359: CHECKSLOTILLEGAL(); nkeynes@359: tmp = (pc&0xFFFFFFFC) + disp + 4; nkeynes@359: sh4r.r[Rn] = MEM_READ_LONG( tmp ); 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: sh4r.r[Rn] = imm; 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: CHECKFPUEN(); nkeynes@359: if( IS_FPU_DOUBLEPREC() ) { nkeynes@359: DR(FRn) += DR(FRm); nkeynes@359: } else { nkeynes@359: FR(FRn) += FR(FRm); nkeynes@359: } 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: CHECKFPUEN(); nkeynes@359: if( IS_FPU_DOUBLEPREC() ) { nkeynes@359: DR(FRn) -= DR(FRm); nkeynes@359: } else { nkeynes@359: FR(FRn) -= FR(FRm); nkeynes@359: } 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: CHECKFPUEN(); nkeynes@359: if( IS_FPU_DOUBLEPREC() ) { nkeynes@359: DR(FRn) *= DR(FRm); nkeynes@359: } else { nkeynes@359: FR(FRn) *= FR(FRm); nkeynes@359: } 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: CHECKFPUEN(); nkeynes@359: if( IS_FPU_DOUBLEPREC() ) { nkeynes@359: DR(FRn) /= DR(FRm); nkeynes@359: } else { nkeynes@359: FR(FRn) /= FR(FRm); nkeynes@359: } 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: CHECKFPUEN(); nkeynes@359: if( IS_FPU_DOUBLEPREC() ) { nkeynes@359: sh4r.t = ( DR(FRn) == DR(FRm) ? 1 : 0 ); nkeynes@359: } else { nkeynes@359: sh4r.t = ( FR(FRn) == FR(FRm) ? 1 : 0 ); nkeynes@359: } 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: CHECKFPUEN(); nkeynes@359: if( IS_FPU_DOUBLEPREC() ) { nkeynes@359: sh4r.t = ( DR(FRn) > DR(FRm) ? 1 : 0 ); nkeynes@359: } else { nkeynes@359: sh4r.t = ( FR(FRn) > FR(FRm) ? 1 : 0 ); nkeynes@359: } 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: MEM_FP_READ( sh4r.r[Rm] + R0, FRn ); 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: MEM_FP_WRITE( sh4r.r[Rn] + R0, FRm ); 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: MEM_FP_READ( sh4r.r[Rm], FRn ); 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: MEM_FP_READ( sh4r.r[Rm], FRn ); sh4r.r[Rm] += FP_WIDTH; 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: MEM_FP_WRITE( sh4r.r[Rn], FRm ); 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: sh4r.r[Rn] -= FP_WIDTH; MEM_FP_WRITE( sh4r.r[Rn], FRm ); 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: if( IS_FPU_DOUBLESIZE() ) nkeynes@359: DR(FRn) = DR(FRm); nkeynes@359: else nkeynes@359: FR(FRn) = FR(FRm); 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: CHECKFPUEN(); FR(FRn) = FPULf; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: { /* FLDS FRm, FPUL */ nkeynes@359: uint32_t FRm = ((ir>>8)&0xF); nkeynes@359: CHECKFPUEN(); FPULf = FR(FRm); nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* FLOAT FPUL, FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); nkeynes@359: CHECKFPUEN(); nkeynes@374: if( IS_FPU_DOUBLEPREC() ) { nkeynes@374: if( FRn&1 ) { // No, really... nkeynes@374: dtmp = (double)FPULi; nkeynes@374: FR(FRn) = *(((float *)&dtmp)+1); nkeynes@374: } else { nkeynes@374: DRF(FRn>>1) = (double)FPULi; nkeynes@374: } nkeynes@374: } else { nkeynes@359: FR(FRn) = (float)FPULi; nkeynes@359: } nkeynes@374: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* FTRC FRm, FPUL */ nkeynes@359: uint32_t FRm = ((ir>>8)&0xF); nkeynes@359: CHECKFPUEN(); nkeynes@359: if( IS_FPU_DOUBLEPREC() ) { nkeynes@374: if( FRm&1 ) { nkeynes@374: dtmp = 0; nkeynes@374: *(((float *)&dtmp)+1) = FR(FRm); nkeynes@374: } else { nkeynes@374: dtmp = DRF(FRm>>1); nkeynes@374: } nkeynes@359: if( dtmp >= MAX_INTF ) nkeynes@359: FPULi = MAX_INT; nkeynes@359: else if( dtmp <= MIN_INTF ) nkeynes@359: FPULi = MIN_INT; nkeynes@359: else nkeynes@359: FPULi = (int32_t)dtmp; nkeynes@359: } else { nkeynes@359: ftmp = FR(FRm); nkeynes@359: if( ftmp >= MAX_INTF ) nkeynes@359: FPULi = MAX_INT; nkeynes@359: else if( ftmp <= MIN_INTF ) nkeynes@359: FPULi = MIN_INT; nkeynes@359: else nkeynes@359: FPULi = (int32_t)ftmp; nkeynes@359: } nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x4: nkeynes@359: { /* FNEG FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); nkeynes@359: CHECKFPUEN(); nkeynes@359: if( IS_FPU_DOUBLEPREC() ) { nkeynes@359: DR(FRn) = -DR(FRn); nkeynes@359: } else { nkeynes@359: FR(FRn) = -FR(FRn); nkeynes@359: } nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x5: nkeynes@359: { /* FABS FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); nkeynes@359: CHECKFPUEN(); nkeynes@359: if( IS_FPU_DOUBLEPREC() ) { nkeynes@359: DR(FRn) = fabs(DR(FRn)); nkeynes@359: } else { nkeynes@359: FR(FRn) = fabsf(FR(FRn)); nkeynes@359: } nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x6: nkeynes@359: { /* FSQRT FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); nkeynes@359: CHECKFPUEN(); nkeynes@359: if( IS_FPU_DOUBLEPREC() ) { nkeynes@359: DR(FRn) = sqrt(DR(FRn)); nkeynes@359: } else { nkeynes@359: FR(FRn) = sqrtf(FR(FRn)); nkeynes@359: } nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x7: nkeynes@359: { /* FSRRA FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); nkeynes@359: CHECKFPUEN(); nkeynes@359: if( !IS_FPU_DOUBLEPREC() ) { nkeynes@359: FR(FRn) = 1.0/sqrtf(FR(FRn)); nkeynes@359: } nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x8: nkeynes@359: { /* FLDI0 FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); nkeynes@359: CHECKFPUEN(); nkeynes@359: if( IS_FPU_DOUBLEPREC() ) { nkeynes@359: DR(FRn) = 0.0; nkeynes@359: } else { nkeynes@359: FR(FRn) = 0.0; nkeynes@359: } nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x9: nkeynes@359: { /* FLDI1 FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); nkeynes@359: CHECKFPUEN(); nkeynes@359: if( IS_FPU_DOUBLEPREC() ) { nkeynes@359: DR(FRn) = 1.0; nkeynes@359: } else { nkeynes@359: FR(FRn) = 1.0; nkeynes@359: } nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xA: nkeynes@359: { /* FCNVSD FPUL, FRn */ nkeynes@359: uint32_t FRn = ((ir>>8)&0xF); nkeynes@359: CHECKFPUEN(); nkeynes@359: if( IS_FPU_DOUBLEPREC() && !IS_FPU_DOUBLESIZE() ) { nkeynes@359: DR(FRn) = (double)FPULf; nkeynes@359: } nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0xB: nkeynes@359: { /* FCNVDS FRm, FPUL */ nkeynes@359: uint32_t FRm = ((ir>>8)&0xF); nkeynes@359: CHECKFPUEN(); nkeynes@359: if( IS_FPU_DOUBLEPREC() && !IS_FPU_DOUBLESIZE() ) { nkeynes@359: FPULf = (float)DR(FRm); nkeynes@359: } 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: CHECKFPUEN(); nkeynes@359: if( !IS_FPU_DOUBLEPREC() ) { nkeynes@359: int tmp2 = FVn<<2; nkeynes@359: tmp = FVm<<2; nkeynes@359: FR(tmp2+3) = FR(tmp)*FR(tmp2) + nkeynes@359: FR(tmp+1)*FR(tmp2+1) + nkeynes@359: FR(tmp+2)*FR(tmp2+2) + nkeynes@359: FR(tmp+3)*FR(tmp2+3); nkeynes@359: } 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: CHECKFPUEN(); nkeynes@359: if( !IS_FPU_DOUBLEPREC() ) { nkeynes@391: sh4_fsca( FPULi, &(DRF(FRn>>1)) ); nkeynes@391: /* nkeynes@359: float angle = (((float)(FPULi&0xFFFF))/65536.0) * 2 * M_PI; nkeynes@359: FR(FRn) = sinf(angle); nkeynes@359: FR((FRn)+1) = cosf(angle); nkeynes@391: */ nkeynes@359: } 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: CHECKFPUEN(); nkeynes@359: if( !IS_FPU_DOUBLEPREC() ) { nkeynes@391: sh4_ftrv(&(DRF(FVn<<1)), &sh4r.fr[((~sh4r.fpscr)&FPSCR_FR)>>21][0]); nkeynes@391: /* nkeynes@359: tmp = FVn<<2; nkeynes@374: float *xf = &sh4r.fr[((~sh4r.fpscr)&FPSCR_FR)>>21][0]; nkeynes@359: float fv[4] = { FR(tmp), FR(tmp+1), FR(tmp+2), FR(tmp+3) }; nkeynes@374: FR(tmp) = xf[1] * fv[0] + xf[5]*fv[1] + nkeynes@374: xf[9]*fv[2] + xf[13]*fv[3]; nkeynes@374: FR(tmp+1) = xf[0] * fv[0] + xf[4]*fv[1] + nkeynes@374: xf[8]*fv[2] + xf[12]*fv[3]; nkeynes@374: FR(tmp+2) = xf[3] * fv[0] + xf[7]*fv[1] + nkeynes@374: xf[11]*fv[2] + xf[15]*fv[3]; nkeynes@374: FR(tmp+3) = xf[2] * fv[0] + xf[6]*fv[1] + nkeynes@374: xf[10]*fv[2] + xf[14]*fv[3]; nkeynes@391: */ nkeynes@359: } nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x1: nkeynes@359: switch( (ir&0xC00) >> 10 ) { nkeynes@359: case 0x0: nkeynes@359: { /* FSCHG */ nkeynes@359: CHECKFPUEN(); sh4r.fpscr ^= FPSCR_SZ; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x2: nkeynes@359: { /* FRCHG */ nkeynes@374: CHECKFPUEN(); nkeynes@374: sh4r.fpscr ^= FPSCR_FR; nkeynes@374: sh4r.fr_bank = &sh4r.fr[(sh4r.fpscr&FPSCR_FR)>>21][0]; nkeynes@359: } nkeynes@359: break; nkeynes@359: case 0x3: nkeynes@359: { /* UNDEF */ nkeynes@359: UNDEF(ir); 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: CHECKFPUEN(); nkeynes@359: if( IS_FPU_DOUBLEPREC() ) { nkeynes@359: DR(FRn) += DR(FRm)*DR(0); nkeynes@359: } else { nkeynes@359: FR(FRn) += FR(FRm)*FR(0); nkeynes@359: } nkeynes@359: } nkeynes@359: break; nkeynes@359: default: nkeynes@359: UNDEF(); nkeynes@359: break; nkeynes@359: } nkeynes@359: break; nkeynes@359: } nkeynes@1: nkeynes@1: sh4r.pc = sh4r.new_pc; nkeynes@1: sh4r.new_pc += 2; nkeynes@2: sh4r.in_delay_slot = 0; nkeynes@273: return TRUE; nkeynes@1: }