nkeynes@359: /** nkeynes@586: * $Id$ nkeynes@359: * nkeynes@359: * SH4 emulation core, and parent module for all the SH4 peripheral nkeynes@359: * modules. nkeynes@359: * nkeynes@359: * Copyright (c) 2005 Nathan Keynes. nkeynes@359: * nkeynes@359: * This program is free software; you can redistribute it and/or modify nkeynes@359: * it under the terms of the GNU General Public License as published by nkeynes@359: * the Free Software Foundation; either version 2 of the License, or nkeynes@359: * (at your option) any later version. nkeynes@359: * nkeynes@359: * This program is distributed in the hope that it will be useful, nkeynes@359: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@359: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@359: * GNU General Public License for more details. nkeynes@359: */ nkeynes@359: nkeynes@359: #define MODULE sh4_module nkeynes@586: #include nkeynes@359: #include nkeynes@359: #include "dream.h" nkeynes@430: #include "dreamcast.h" nkeynes@430: #include "eventq.h" nkeynes@430: #include "mem.h" nkeynes@430: #include "clock.h" nkeynes@430: #include "syscall.h" nkeynes@359: #include "sh4/sh4core.h" nkeynes@359: #include "sh4/sh4mmio.h" nkeynes@671: #include "sh4/sh4stat.h" nkeynes@359: #include "sh4/intc.h" nkeynes@359: nkeynes@359: #define SH4_CALLTRACE 1 nkeynes@359: nkeynes@359: #define MAX_INT 0x7FFFFFFF nkeynes@359: #define MIN_INT 0x80000000 nkeynes@359: #define MAX_INTF 2147483647.0 nkeynes@359: #define MIN_INTF -2147483648.0 nkeynes@359: nkeynes@359: /********************** SH4 Module Definition ****************************/ nkeynes@359: nkeynes@359: uint32_t sh4_run_slice( uint32_t nanosecs ) nkeynes@359: { nkeynes@359: int i; nkeynes@359: sh4r.slice_cycle = 0; nkeynes@359: nkeynes@359: if( sh4r.sh4_state != SH4_STATE_RUNNING ) { nkeynes@617: sh4_sleep_run_slice(nanosecs); nkeynes@359: } nkeynes@359: nkeynes@359: if( sh4_breakpoint_count == 0 ) { nkeynes@359: for( ; sh4r.slice_cycle < nanosecs; sh4r.slice_cycle += sh4_cpu_period ) { nkeynes@359: if( SH4_EVENT_PENDING() ) { nkeynes@359: if( sh4r.event_types & PENDING_EVENT ) { nkeynes@359: event_execute(); nkeynes@359: } nkeynes@359: /* Eventq execute may (quite likely) deliver an immediate IRQ */ nkeynes@359: if( sh4r.event_types & PENDING_IRQ ) { nkeynes@359: sh4_accept_interrupt(); nkeynes@359: } nkeynes@359: } nkeynes@359: if( !sh4_execute_instruction() ) { nkeynes@359: break; nkeynes@359: } nkeynes@359: } nkeynes@359: } else { nkeynes@359: for( ;sh4r.slice_cycle < nanosecs; sh4r.slice_cycle += sh4_cpu_period ) { nkeynes@359: if( SH4_EVENT_PENDING() ) { nkeynes@359: if( sh4r.event_types & PENDING_EVENT ) { nkeynes@359: event_execute(); nkeynes@359: } nkeynes@359: /* Eventq execute may (quite likely) deliver an immediate IRQ */ nkeynes@359: if( sh4r.event_types & PENDING_IRQ ) { nkeynes@359: sh4_accept_interrupt(); nkeynes@359: } nkeynes@359: } nkeynes@359: nkeynes@359: if( !sh4_execute_instruction() ) nkeynes@359: break; nkeynes@359: #ifdef ENABLE_DEBUG_MODE nkeynes@359: for( i=0; i 0 ) { nkeynes@359: call_stack_depth--; nkeynes@359: } nkeynes@359: } nkeynes@359: nkeynes@359: void fprint_stack_trace( FILE *f ) nkeynes@359: { nkeynes@359: int i = call_stack_depth -1; nkeynes@359: if( i >= MAX_CALLSTACK ) nkeynes@359: i = MAX_CALLSTACK - 1; nkeynes@359: for( ; i >= 0; i-- ) { nkeynes@359: fprintf( f, "%d. Call from %08X => %08X, SP=%08X\n", nkeynes@359: (call_stack_depth - i), call_stack[i].call_addr, nkeynes@359: call_stack[i].target_addr, call_stack[i].stack_pointer ); nkeynes@359: } nkeynes@359: } nkeynes@359: nkeynes@359: #define TRACE_CALL( source, dest ) trace_call(source, dest) nkeynes@359: #define TRACE_RETURN( source, dest ) trace_return(source, dest) nkeynes@359: #else nkeynes@359: #define TRACE_CALL( dest, rts ) nkeynes@359: #define TRACE_RETURN( source, dest ) nkeynes@359: #endif nkeynes@359: nkeynes@732: #define CHECKPRIV() if( !IS_SH4_PRIVMODE() ) return sh4_raise_slot_exception( EXC_ILLEGAL, EXC_SLOT_ILLEGAL ) nkeynes@732: #define CHECKRALIGN16(addr) if( (addr)&0x01 ) return sh4_raise_exception( EXC_DATA_ADDR_READ ) nkeynes@732: #define CHECKRALIGN32(addr) if( (addr)&0x03 ) return sh4_raise_exception( EXC_DATA_ADDR_READ ) nkeynes@732: #define CHECKRALIGN64(addr) if( (addr)&0x07 ) return sh4_raise_exception( EXC_DATA_ADDR_READ ) nkeynes@732: #define CHECKWALIGN16(addr) if( (addr)&0x01 ) return sh4_raise_exception( EXC_DATA_ADDR_WRITE ) nkeynes@732: #define CHECKWALIGN32(addr) if( (addr)&0x03 ) return sh4_raise_exception( EXC_DATA_ADDR_WRITE ) nkeynes@732: #define CHECKWALIGN64(addr) if( (addr)&0x07 ) return sh4_raise_exception( EXC_DATA_ADDR_WRITE ) nkeynes@732: nkeynes@732: #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@732: #define CHECKDEST(p) if( (p) == 0 ) { ERROR( "%08X: Branch/jump to NULL, CPU halted", sh4r.pc ); dreamcast_stop(); return FALSE; } nkeynes@732: #define CHECKSLOTILLEGAL() if(sh4r.in_delay_slot) return sh4_raise_exception(EXC_SLOT_ILLEGAL) nkeynes@732: nkeynes@586: #define MEM_READ_BYTE( addr, val ) memtmp = mmu_vma_to_phys_read(addr); if( memtmp == MMU_VMA_ERROR ) { return TRUE; } else { val = sh4_read_byte(memtmp); } nkeynes@586: #define MEM_READ_WORD( addr, val ) memtmp = mmu_vma_to_phys_read(addr); if( memtmp == MMU_VMA_ERROR ) { return TRUE; } else { val = sh4_read_word(memtmp); } nkeynes@586: #define MEM_READ_LONG( addr, val ) memtmp = mmu_vma_to_phys_read(addr); if( memtmp == MMU_VMA_ERROR ) { return TRUE; } else { val = sh4_read_long(memtmp); } nkeynes@586: #define MEM_WRITE_BYTE( addr, val ) memtmp = mmu_vma_to_phys_write(addr); if( memtmp == MMU_VMA_ERROR ) { return TRUE; } else { sh4_write_byte(memtmp, val); } nkeynes@586: #define MEM_WRITE_WORD( addr, val ) memtmp = mmu_vma_to_phys_write(addr); if( memtmp == MMU_VMA_ERROR ) { return TRUE; } else { sh4_write_word(memtmp, val); } nkeynes@586: #define MEM_WRITE_LONG( addr, val ) memtmp = mmu_vma_to_phys_write(addr); if( memtmp == MMU_VMA_ERROR ) { return TRUE; } else { sh4_write_long(memtmp, val); } nkeynes@359: nkeynes@359: #define FP_WIDTH (IS_FPU_DOUBLESIZE() ? 8 : 4) nkeynes@359: nkeynes@732: #define MEM_FP_READ( addr, reg ) \ nkeynes@732: if( IS_FPU_DOUBLESIZE() ) { \ nkeynes@732: CHECKRALIGN64(addr); \ nkeynes@732: memtmp = mmu_vma_to_phys_read(addr); \ nkeynes@732: if( memtmp == MMU_VMA_ERROR ) { \ nkeynes@732: return TRUE; \ nkeynes@732: } else { \ nkeynes@732: if( reg & 1 ) { \ nkeynes@732: *((uint32_t *)&XF((reg) & 0x0E)) = sh4_read_long(memtmp); \ nkeynes@732: *((uint32_t *)&XF(reg)) = sh4_read_long(memtmp+4); \ nkeynes@732: } else { \ nkeynes@732: *((uint32_t *)&FR(reg)) = sh4_read_long(memtmp); \ nkeynes@732: *((uint32_t *)&FR((reg) | 0x01)) = sh4_read_long(memtmp+4); \ nkeynes@732: } \ nkeynes@732: } \ nkeynes@732: } else { \ nkeynes@732: CHECKRALIGN32(addr); \ nkeynes@732: memtmp = mmu_vma_to_phys_read(addr); \ nkeynes@732: if( memtmp == MMU_VMA_ERROR ) { \ nkeynes@732: return TRUE; \ nkeynes@732: } else { \ nkeynes@732: *((uint32_t *)&FR(reg)) = sh4_read_long(memtmp); \ nkeynes@732: } \ nkeynes@359: } nkeynes@732: #define MEM_FP_WRITE( addr, reg ) \ nkeynes@732: if( IS_FPU_DOUBLESIZE() ) { \ nkeynes@732: CHECKWALIGN64(addr); \ nkeynes@732: memtmp = mmu_vma_to_phys_write(addr); \ nkeynes@732: if( memtmp == MMU_VMA_ERROR ) { \ nkeynes@732: return TRUE; \ nkeynes@732: } else { \ nkeynes@732: if( reg & 1 ) { \ nkeynes@732: sh4_write_long( memtmp, *((uint32_t *)&XF((reg)&0x0E)) ); \ nkeynes@732: sh4_write_long( memtmp+4, *((uint32_t *)&XF(reg)) ); \ nkeynes@732: } else { \ nkeynes@736: sh4_write_long( memtmp, *((uint32_t *)&FR(reg)) ); \ nkeynes@732: sh4_write_long( memtmp+4, *((uint32_t *)&FR((reg)|0x01)) ); \ nkeynes@732: } \ nkeynes@732: } \ nkeynes@732: } else { \ nkeynes@732: CHECKWALIGN32(addr); \ nkeynes@732: memtmp = mmu_vma_to_phys_write(addr); \ nkeynes@732: if( memtmp == MMU_VMA_ERROR ) { \ nkeynes@732: return TRUE; \ nkeynes@732: } else { \ nkeynes@732: sh4_write_long( memtmp, *((uint32_t *)&FR((reg))) ); \ nkeynes@732: } \ nkeynes@359: } nkeynes@359: nkeynes@359: gboolean sh4_execute_instruction( void ) nkeynes@359: { nkeynes@359: uint32_t pc; nkeynes@359: unsigned short ir; nkeynes@359: uint32_t tmp; nkeynes@359: float ftmp; nkeynes@359: double dtmp; nkeynes@586: int64_t memtmp; // temporary holder for memory reads nkeynes@359: nkeynes@359: #define R0 sh4r.r[0] nkeynes@359: pc = sh4r.pc; nkeynes@359: if( pc > 0xFFFFFF00 ) { nkeynes@359: /* SYSCALL Magic */ nkeynes@359: syscall_invoke( pc ); nkeynes@359: sh4r.in_delay_slot = 0; nkeynes@359: pc = sh4r.pc = sh4r.pr; nkeynes@359: sh4r.new_pc = sh4r.pc + 2; nkeynes@671: return TRUE; nkeynes@359: } nkeynes@359: CHECKRALIGN16(pc); nkeynes@359: nkeynes@671: #ifdef ENABLE_SH4STATS nkeynes@671: sh4_stats_add_by_pc(sh4r.pc); nkeynes@671: #endif nkeynes@671: nkeynes@359: /* Read instruction */ nkeynes@586: if( !IS_IN_ICACHE(pc) ) { nkeynes@586: if( !mmu_update_icache(pc) ) { nkeynes@586: // Fault - look for the fault handler nkeynes@586: if( !mmu_update_icache(sh4r.pc) ) { nkeynes@586: // double fault - halt nkeynes@586: ERROR( "Double fault - halting" ); nkeynes@586: dreamcast_stop(); nkeynes@586: return FALSE; nkeynes@586: } nkeynes@359: } nkeynes@586: pc = sh4r.pc; nkeynes@359: } nkeynes@586: assert( IS_IN_ICACHE(pc) ); nkeynes@586: ir = *(uint16_t *)GET_ICACHE_PTR(sh4r.pc); nkeynes@359: %% nkeynes@359: AND Rm, Rn {: sh4r.r[Rn] &= sh4r.r[Rm]; :} nkeynes@359: AND #imm, R0 {: R0 &= imm; :} nkeynes@586: AND.B #imm, @(R0, GBR) {: MEM_READ_BYTE(R0+sh4r.gbr, tmp); MEM_WRITE_BYTE( R0 + sh4r.gbr, imm & tmp ); :} nkeynes@359: NOT Rm, Rn {: sh4r.r[Rn] = ~sh4r.r[Rm]; :} nkeynes@359: OR Rm, Rn {: sh4r.r[Rn] |= sh4r.r[Rm]; :} nkeynes@359: OR #imm, R0 {: R0 |= imm; :} nkeynes@586: OR.B #imm, @(R0, GBR) {: MEM_READ_BYTE(R0+sh4r.gbr, tmp); MEM_WRITE_BYTE( R0 + sh4r.gbr, imm | tmp ); :} nkeynes@359: TAS.B @Rn {: nkeynes@586: MEM_READ_BYTE( sh4r.r[Rn], tmp ); nkeynes@359: sh4r.t = ( tmp == 0 ? 1 : 0 ); nkeynes@359: MEM_WRITE_BYTE( sh4r.r[Rn], tmp | 0x80 ); nkeynes@359: :} nkeynes@359: TST Rm, Rn {: sh4r.t = (sh4r.r[Rn]&sh4r.r[Rm] ? 0 : 1); :} nkeynes@359: TST #imm, R0 {: sh4r.t = (R0 & imm ? 0 : 1); :} nkeynes@586: TST.B #imm, @(R0, GBR) {: MEM_READ_BYTE(R0+sh4r.gbr, tmp); sh4r.t = ( tmp & imm ? 0 : 1 ); :} nkeynes@359: XOR Rm, Rn {: sh4r.r[Rn] ^= sh4r.r[Rm]; :} nkeynes@359: XOR #imm, R0 {: R0 ^= imm; :} nkeynes@586: XOR.B #imm, @(R0, GBR) {: MEM_READ_BYTE(R0+sh4r.gbr, tmp); MEM_WRITE_BYTE( R0 + sh4r.gbr, imm ^ tmp ); :} nkeynes@359: XTRCT Rm, Rn {: sh4r.r[Rn] = (sh4r.r[Rn]>>16) | (sh4r.r[Rm]<<16); :} nkeynes@359: nkeynes@359: ROTL Rn {: 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: ROTR Rn {: 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: ROTCL Rn {: 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: ROTCR Rn {: 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: SHAD Rm, Rn {: 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: SHLD Rm, Rn {: 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: SHAL Rn {: nkeynes@359: sh4r.t = sh4r.r[Rn] >> 31; nkeynes@359: sh4r.r[Rn] <<= 1; nkeynes@359: :} nkeynes@359: SHAR Rn {: nkeynes@359: sh4r.t = sh4r.r[Rn] & 0x00000001; nkeynes@359: sh4r.r[Rn] = ((int32_t)sh4r.r[Rn]) >> 1; nkeynes@359: :} nkeynes@359: SHLL Rn {: sh4r.t = sh4r.r[Rn] >> 31; sh4r.r[Rn] <<= 1; :} nkeynes@359: SHLR Rn {: sh4r.t = sh4r.r[Rn] & 0x00000001; sh4r.r[Rn] >>= 1; :} nkeynes@359: SHLL2 Rn {: sh4r.r[Rn] <<= 2; :} nkeynes@359: SHLR2 Rn {: sh4r.r[Rn] >>= 2; :} nkeynes@359: SHLL8 Rn {: sh4r.r[Rn] <<= 8; :} nkeynes@359: SHLR8 Rn {: sh4r.r[Rn] >>= 8; :} nkeynes@359: SHLL16 Rn {: sh4r.r[Rn] <<= 16; :} nkeynes@359: SHLR16 Rn {: sh4r.r[Rn] >>= 16; :} nkeynes@359: nkeynes@359: EXTU.B Rm, Rn {: sh4r.r[Rn] = sh4r.r[Rm]&0x000000FF; :} nkeynes@359: EXTU.W Rm, Rn {: sh4r.r[Rn] = sh4r.r[Rm]&0x0000FFFF; :} nkeynes@359: EXTS.B Rm, Rn {: sh4r.r[Rn] = SIGNEXT8( sh4r.r[Rm]&0x000000FF ); :} nkeynes@359: EXTS.W Rm, Rn {: sh4r.r[Rn] = SIGNEXT16( sh4r.r[Rm]&0x0000FFFF ); :} nkeynes@359: SWAP.B Rm, Rn {: sh4r.r[Rn] = (sh4r.r[Rm]&0xFFFF0000) | ((sh4r.r[Rm]&0x0000FF00)>>8) | ((sh4r.r[Rm]&0x000000FF)<<8); :} nkeynes@359: SWAP.W Rm, Rn {: sh4r.r[Rn] = (sh4r.r[Rm]>>16) | (sh4r.r[Rm]<<16); :} nkeynes@359: nkeynes@359: CLRT {: sh4r.t = 0; :} nkeynes@359: SETT {: sh4r.t = 1; :} nkeynes@359: CLRMAC {: sh4r.mac = 0; :} nkeynes@550: LDTLB {: MMU_ldtlb(); :} nkeynes@359: CLRS {: sh4r.s = 0; :} nkeynes@359: SETS {: sh4r.s = 1; :} nkeynes@359: MOVT Rn {: sh4r.r[Rn] = sh4r.t; :} nkeynes@359: NOP {: /* NOP */ :} nkeynes@359: nkeynes@359: PREF @Rn {: 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: OCBI @Rn {: :} nkeynes@359: OCBP @Rn {: :} nkeynes@359: OCBWB @Rn {: :} nkeynes@359: MOVCA.L R0, @Rn {: nkeynes@359: tmp = sh4r.r[Rn]; nkeynes@359: CHECKWALIGN32(tmp); nkeynes@359: MEM_WRITE_LONG( tmp, R0 ); nkeynes@359: :} nkeynes@359: MOV.B Rm, @(R0, Rn) {: MEM_WRITE_BYTE( R0 + sh4r.r[Rn], sh4r.r[Rm] ); :} nkeynes@359: MOV.W Rm, @(R0, Rn) {: nkeynes@359: CHECKWALIGN16( R0 + sh4r.r[Rn] ); nkeynes@359: MEM_WRITE_WORD( R0 + sh4r.r[Rn], sh4r.r[Rm] ); nkeynes@359: :} nkeynes@359: MOV.L Rm, @(R0, Rn) {: nkeynes@359: CHECKWALIGN32( R0 + sh4r.r[Rn] ); nkeynes@359: MEM_WRITE_LONG( R0 + sh4r.r[Rn], sh4r.r[Rm] ); nkeynes@359: :} nkeynes@586: MOV.B @(R0, Rm), Rn {: MEM_READ_BYTE( R0 + sh4r.r[Rm], sh4r.r[Rn] ); :} nkeynes@359: MOV.W @(R0, Rm), Rn {: CHECKRALIGN16( R0 + sh4r.r[Rm] ); nkeynes@586: MEM_READ_WORD( R0 + sh4r.r[Rm], sh4r.r[Rn] ); nkeynes@359: :} nkeynes@359: MOV.L @(R0, Rm), Rn {: CHECKRALIGN32( R0 + sh4r.r[Rm] ); nkeynes@586: MEM_READ_LONG( R0 + sh4r.r[Rm], sh4r.r[Rn] ); nkeynes@359: :} nkeynes@359: MOV.L Rm, @(disp, Rn) {: nkeynes@359: tmp = sh4r.r[Rn] + disp; nkeynes@359: CHECKWALIGN32( tmp ); nkeynes@359: MEM_WRITE_LONG( tmp, sh4r.r[Rm] ); nkeynes@359: :} nkeynes@359: MOV.B Rm, @Rn {: MEM_WRITE_BYTE( sh4r.r[Rn], sh4r.r[Rm] ); :} nkeynes@359: MOV.W Rm, @Rn {: CHECKWALIGN16( sh4r.r[Rn] ); MEM_WRITE_WORD( sh4r.r[Rn], sh4r.r[Rm] ); :} nkeynes@359: MOV.L Rm, @Rn {: CHECKWALIGN32( sh4r.r[Rn] ); MEM_WRITE_LONG( sh4r.r[Rn], sh4r.r[Rm] ); :} nkeynes@587: MOV.B Rm, @-Rn {: MEM_WRITE_BYTE( sh4r.r[Rn]-1, sh4r.r[Rm] ); sh4r.r[Rn]--; :} nkeynes@587: MOV.W Rm, @-Rn {: CHECKWALIGN16( sh4r.r[Rn] ); MEM_WRITE_WORD( sh4r.r[Rn]-2, sh4r.r[Rm] ); sh4r.r[Rn] -= 2; :} nkeynes@587: MOV.L Rm, @-Rn {: CHECKWALIGN32( sh4r.r[Rn] ); MEM_WRITE_LONG( sh4r.r[Rn]-4, sh4r.r[Rm] ); sh4r.r[Rn] -= 4; :} nkeynes@359: MOV.L @(disp, Rm), Rn {: nkeynes@359: tmp = sh4r.r[Rm] + disp; nkeynes@359: CHECKRALIGN32( tmp ); nkeynes@586: MEM_READ_LONG( tmp, sh4r.r[Rn] ); nkeynes@359: :} nkeynes@586: MOV.B @Rm, Rn {: MEM_READ_BYTE( sh4r.r[Rm], sh4r.r[Rn] ); :} nkeynes@586: MOV.W @Rm, Rn {: CHECKRALIGN16( sh4r.r[Rm] ); MEM_READ_WORD( sh4r.r[Rm], sh4r.r[Rn] ); :} nkeynes@586: MOV.L @Rm, Rn {: CHECKRALIGN32( sh4r.r[Rm] ); MEM_READ_LONG( sh4r.r[Rm], sh4r.r[Rn] ); :} nkeynes@359: MOV Rm, Rn {: sh4r.r[Rn] = sh4r.r[Rm]; :} nkeynes@586: MOV.B @Rm+, Rn {: MEM_READ_BYTE( sh4r.r[Rm], sh4r.r[Rn] ); sh4r.r[Rm] ++; :} nkeynes@586: MOV.W @Rm+, Rn {: CHECKRALIGN16( sh4r.r[Rm] ); MEM_READ_WORD( sh4r.r[Rm], sh4r.r[Rn] ); sh4r.r[Rm] += 2; :} nkeynes@586: MOV.L @Rm+, Rn {: CHECKRALIGN32( sh4r.r[Rm] ); MEM_READ_LONG( sh4r.r[Rm], sh4r.r[Rn] ); sh4r.r[Rm] += 4; :} nkeynes@359: MOV.L @(disp, PC), Rn {: nkeynes@359: CHECKSLOTILLEGAL(); nkeynes@359: tmp = (pc&0xFFFFFFFC) + disp + 4; nkeynes@586: MEM_READ_LONG( tmp, sh4r.r[Rn] ); nkeynes@359: :} nkeynes@359: MOV.B R0, @(disp, GBR) {: MEM_WRITE_BYTE( sh4r.gbr + disp, R0 ); :} nkeynes@359: MOV.W R0, @(disp, GBR) {: nkeynes@359: tmp = sh4r.gbr + disp; nkeynes@359: CHECKWALIGN16( tmp ); nkeynes@359: MEM_WRITE_WORD( tmp, R0 ); nkeynes@359: :} nkeynes@359: MOV.L R0, @(disp, GBR) {: nkeynes@359: tmp = sh4r.gbr + disp; nkeynes@359: CHECKWALIGN32( tmp ); nkeynes@359: MEM_WRITE_LONG( tmp, R0 ); nkeynes@359: :} nkeynes@586: MOV.B @(disp, GBR), R0 {: MEM_READ_BYTE( sh4r.gbr + disp, R0 ); :} nkeynes@359: MOV.W @(disp, GBR), R0 {: nkeynes@359: tmp = sh4r.gbr + disp; nkeynes@359: CHECKRALIGN16( tmp ); nkeynes@586: MEM_READ_WORD( tmp, R0 ); nkeynes@359: :} nkeynes@359: MOV.L @(disp, GBR), R0 {: nkeynes@359: tmp = sh4r.gbr + disp; nkeynes@359: CHECKRALIGN32( tmp ); nkeynes@586: MEM_READ_LONG( tmp, R0 ); nkeynes@359: :} nkeynes@359: MOV.B R0, @(disp, Rn) {: MEM_WRITE_BYTE( sh4r.r[Rn] + disp, R0 ); :} nkeynes@359: MOV.W R0, @(disp, Rn) {: nkeynes@359: tmp = sh4r.r[Rn] + disp; nkeynes@359: CHECKWALIGN16( tmp ); nkeynes@359: MEM_WRITE_WORD( tmp, R0 ); nkeynes@359: :} nkeynes@586: MOV.B @(disp, Rm), R0 {: MEM_READ_BYTE( sh4r.r[Rm] + disp, R0 ); :} nkeynes@359: MOV.W @(disp, Rm), R0 {: nkeynes@359: tmp = sh4r.r[Rm] + disp; nkeynes@359: CHECKRALIGN16( tmp ); nkeynes@586: MEM_READ_WORD( tmp, R0 ); nkeynes@359: :} nkeynes@359: MOV.W @(disp, PC), Rn {: nkeynes@359: CHECKSLOTILLEGAL(); nkeynes@359: tmp = pc + 4 + disp; nkeynes@586: MEM_READ_WORD( tmp, sh4r.r[Rn] ); nkeynes@359: :} nkeynes@359: MOVA @(disp, PC), R0 {: nkeynes@359: CHECKSLOTILLEGAL(); nkeynes@359: R0 = (pc&0xFFFFFFFC) + disp + 4; nkeynes@359: :} nkeynes@359: MOV #imm, Rn {: sh4r.r[Rn] = imm; :} nkeynes@359: nkeynes@732: FMOV @(R0, Rm), FRn {: MEM_FP_READ( sh4r.r[Rm] + R0, FRn ); :} nkeynes@732: FMOV FRm, @(R0, Rn) {: MEM_FP_WRITE( sh4r.r[Rn] + R0, FRm ); :} nkeynes@732: FMOV @Rm, FRn {: MEM_FP_READ( sh4r.r[Rm], FRn ); :} nkeynes@732: FMOV @Rm+, FRn {: MEM_FP_READ( sh4r.r[Rm], FRn ); sh4r.r[Rm] += FP_WIDTH; :} nkeynes@732: FMOV FRm, @Rn {: MEM_FP_WRITE( sh4r.r[Rn], FRm ); :} nkeynes@732: FMOV FRm, @-Rn {: MEM_FP_WRITE( sh4r.r[Rn] - FP_WIDTH, FRm ); sh4r.r[Rn] -= FP_WIDTH; :} nkeynes@732: FMOV FRm, FRn {: nkeynes@732: if( IS_FPU_DOUBLESIZE() ) nkeynes@732: DR(FRn) = DR(FRm); nkeynes@732: else nkeynes@732: FR(FRn) = FR(FRm); nkeynes@732: :} nkeynes@732: nkeynes@359: CMP/EQ #imm, R0 {: sh4r.t = ( R0 == imm ? 1 : 0 ); :} nkeynes@359: CMP/EQ Rm, Rn {: sh4r.t = ( sh4r.r[Rm] == sh4r.r[Rn] ? 1 : 0 ); :} nkeynes@359: CMP/GE Rm, Rn {: sh4r.t = ( ((int32_t)sh4r.r[Rn]) >= ((int32_t)sh4r.r[Rm]) ? 1 : 0 ); :} nkeynes@359: CMP/GT Rm, Rn {: sh4r.t = ( ((int32_t)sh4r.r[Rn]) > ((int32_t)sh4r.r[Rm]) ? 1 : 0 ); :} nkeynes@359: CMP/HI Rm, Rn {: sh4r.t = ( sh4r.r[Rn] > sh4r.r[Rm] ? 1 : 0 ); :} nkeynes@359: CMP/HS Rm, Rn {: sh4r.t = ( sh4r.r[Rn] >= sh4r.r[Rm] ? 1 : 0 ); :} nkeynes@359: CMP/PL Rn {: sh4r.t = ( ((int32_t)sh4r.r[Rn]) > 0 ? 1 : 0 ); :} nkeynes@359: CMP/PZ Rn {: sh4r.t = ( ((int32_t)sh4r.r[Rn]) >= 0 ? 1 : 0 ); :} nkeynes@359: CMP/STR Rm, Rn {: 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: nkeynes@359: ADD Rm, Rn {: sh4r.r[Rn] += sh4r.r[Rm]; :} nkeynes@359: ADD #imm, Rn {: sh4r.r[Rn] += imm; :} nkeynes@359: ADDC Rm, Rn {: 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: ADDV Rm, Rn {: 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: DIV0U {: sh4r.m = sh4r.q = sh4r.t = 0; :} nkeynes@359: DIV0S Rm, Rn {: 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: DIV1 Rm, Rn {: 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: DMULS.L Rm, Rn {: sh4r.mac = SIGNEXT32(sh4r.r[Rm]) * SIGNEXT32(sh4r.r[Rn]); :} nkeynes@359: DMULU.L Rm, Rn {: sh4r.mac = ((uint64_t)sh4r.r[Rm]) * ((uint64_t)sh4r.r[Rn]); :} nkeynes@359: DT Rn {: nkeynes@359: sh4r.r[Rn] --; nkeynes@359: sh4r.t = ( sh4r.r[Rn] == 0 ? 1 : 0 ); nkeynes@359: :} nkeynes@359: MAC.W @Rm+, @Rn+ {: nkeynes@587: int32_t stmp; nkeynes@587: if( Rm == Rn ) { nkeynes@587: CHECKRALIGN16(sh4r.r[Rn]); nkeynes@587: MEM_READ_WORD( sh4r.r[Rn], tmp ); nkeynes@587: stmp = SIGNEXT16(tmp); nkeynes@587: MEM_READ_WORD( sh4r.r[Rn]+2, tmp ); nkeynes@587: stmp *= SIGNEXT16(tmp); nkeynes@587: sh4r.r[Rn] += 4; nkeynes@587: } else { nkeynes@587: CHECKRALIGN16( sh4r.r[Rn] ); nkeynes@587: CHECKRALIGN16( sh4r.r[Rm] ); nkeynes@587: MEM_READ_WORD(sh4r.r[Rn], tmp); nkeynes@587: stmp = SIGNEXT16(tmp); nkeynes@587: MEM_READ_WORD(sh4r.r[Rm], tmp); nkeynes@587: stmp = stmp * SIGNEXT16(tmp); nkeynes@587: sh4r.r[Rn] += 2; nkeynes@587: sh4r.r[Rm] += 2; nkeynes@587: } 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: MAC.L @Rm+, @Rn+ {: nkeynes@587: int64_t tmpl; nkeynes@587: if( Rm == Rn ) { nkeynes@587: CHECKRALIGN32( sh4r.r[Rn] ); nkeynes@587: MEM_READ_LONG(sh4r.r[Rn], tmp); nkeynes@587: tmpl = SIGNEXT32(tmp); nkeynes@587: MEM_READ_LONG(sh4r.r[Rn]+4, tmp); nkeynes@587: tmpl = tmpl * SIGNEXT32(tmp) + sh4r.mac; nkeynes@587: sh4r.r[Rn] += 8; nkeynes@587: } else { nkeynes@587: CHECKRALIGN32( sh4r.r[Rm] ); nkeynes@587: CHECKRALIGN32( sh4r.r[Rn] ); nkeynes@587: MEM_READ_LONG(sh4r.r[Rn], tmp); nkeynes@587: tmpl = SIGNEXT32(tmp); nkeynes@587: MEM_READ_LONG(sh4r.r[Rm], tmp); nkeynes@587: tmpl = tmpl * SIGNEXT32(tmp) + sh4r.mac; nkeynes@587: sh4r.r[Rn] += 4; nkeynes@587: sh4r.r[Rm] += 4; nkeynes@587: } 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: MUL.L Rm, Rn {: sh4r.mac = (sh4r.mac&0xFFFFFFFF00000000LL) | nkeynes@359: (sh4r.r[Rm] * sh4r.r[Rn]); :} nkeynes@359: MULU.W Rm, Rn {: nkeynes@359: sh4r.mac = (sh4r.mac&0xFFFFFFFF00000000LL) | nkeynes@359: (uint32_t)((sh4r.r[Rm]&0xFFFF) * (sh4r.r[Rn]&0xFFFF)); nkeynes@359: :} nkeynes@359: MULS.W Rm, Rn {: 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: NEGC Rm, Rn {: nkeynes@359: tmp = 0 - sh4r.r[Rm]; nkeynes@359: sh4r.r[Rn] = tmp - sh4r.t; nkeynes@359: sh4r.t = ( 0 tmp || (sh4r.r[Rn] == tmp && sh4r.t == 1)); nkeynes@359: :} nkeynes@359: nkeynes@359: BRAF Rn {: 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: BSRF Rn {: 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: BT disp {: 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: BF disp {: 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: BT/S disp {: nkeynes@359: CHECKSLOTILLEGAL(); nkeynes@359: if( sh4r.t ) { 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 + disp + 4; nkeynes@359: sh4r.in_delay_slot = 1; nkeynes@359: return TRUE; nkeynes@359: } nkeynes@359: :} nkeynes@359: BF/S disp {: nkeynes@359: CHECKSLOTILLEGAL(); nkeynes@359: if( !sh4r.t ) { 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 + disp + 4; nkeynes@359: return TRUE; nkeynes@359: } nkeynes@359: :} nkeynes@359: BRA disp {: 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: BSR disp {: 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: TRAPA #imm {: nkeynes@359: CHECKSLOTILLEGAL(); nkeynes@359: sh4r.pc += 2; nkeynes@586: sh4_raise_trap( imm ); nkeynes@586: return TRUE; nkeynes@359: :} 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: 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: 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: JMP @Rn {: 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: JSR @Rn {: 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: STS MACH, Rn {: sh4r.r[Rn] = (sh4r.mac>>32); :} nkeynes@359: STS.L MACH, @-Rn {: nkeynes@587: CHECKWALIGN32( sh4r.r[Rn] ); nkeynes@587: MEM_WRITE_LONG( sh4r.r[Rn]-4, (sh4r.mac>>32) ); nkeynes@359: sh4r.r[Rn] -= 4; nkeynes@359: :} nkeynes@359: STC.L SR, @-Rn {: nkeynes@359: CHECKPRIV(); nkeynes@587: CHECKWALIGN32( sh4r.r[Rn] ); nkeynes@587: MEM_WRITE_LONG( sh4r.r[Rn]-4, sh4_read_sr() ); nkeynes@359: sh4r.r[Rn] -= 4; nkeynes@359: :} nkeynes@359: LDS.L @Rm+, MACH {: nkeynes@359: CHECKRALIGN32( sh4r.r[Rm] ); nkeynes@586: MEM_READ_LONG(sh4r.r[Rm], tmp); nkeynes@359: sh4r.mac = (sh4r.mac & 0x00000000FFFFFFFF) | nkeynes@586: (((uint64_t)tmp)<<32); nkeynes@359: sh4r.r[Rm] += 4; nkeynes@359: :} nkeynes@359: LDC.L @Rm+, SR {: nkeynes@359: CHECKSLOTILLEGAL(); nkeynes@359: CHECKPRIV(); nkeynes@359: CHECKWALIGN32( sh4r.r[Rm] ); nkeynes@586: MEM_READ_LONG(sh4r.r[Rm], tmp); nkeynes@586: sh4_write_sr( tmp ); nkeynes@359: sh4r.r[Rm] +=4; nkeynes@359: :} nkeynes@359: LDS Rm, MACH {: nkeynes@359: sh4r.mac = (sh4r.mac & 0x00000000FFFFFFFF) | nkeynes@359: (((uint64_t)sh4r.r[Rm])<<32); nkeynes@359: :} nkeynes@359: LDC Rm, SR {: nkeynes@359: CHECKSLOTILLEGAL(); nkeynes@359: CHECKPRIV(); nkeynes@374: sh4_write_sr( sh4r.r[Rm] ); nkeynes@359: :} nkeynes@359: LDC Rm, SGR {: nkeynes@359: CHECKPRIV(); nkeynes@359: sh4r.sgr = sh4r.r[Rm]; nkeynes@359: :} nkeynes@359: LDC.L @Rm+, SGR {: nkeynes@359: CHECKPRIV(); nkeynes@359: CHECKRALIGN32( sh4r.r[Rm] ); nkeynes@586: MEM_READ_LONG(sh4r.r[Rm], sh4r.sgr); nkeynes@359: sh4r.r[Rm] +=4; nkeynes@359: :} nkeynes@359: STS MACL, Rn {: sh4r.r[Rn] = (uint32_t)sh4r.mac; :} nkeynes@359: STS.L MACL, @-Rn {: nkeynes@587: CHECKWALIGN32( sh4r.r[Rn] ); nkeynes@587: MEM_WRITE_LONG( sh4r.r[Rn]-4, (uint32_t)sh4r.mac ); nkeynes@359: sh4r.r[Rn] -= 4; nkeynes@359: :} nkeynes@359: STC.L GBR, @-Rn {: nkeynes@587: CHECKWALIGN32( sh4r.r[Rn] ); nkeynes@587: MEM_WRITE_LONG( sh4r.r[Rn]-4, sh4r.gbr ); nkeynes@359: sh4r.r[Rn] -= 4; nkeynes@359: :} nkeynes@359: LDS.L @Rm+, MACL {: nkeynes@359: CHECKRALIGN32( sh4r.r[Rm] ); nkeynes@586: MEM_READ_LONG(sh4r.r[Rm], tmp); nkeynes@359: sh4r.mac = (sh4r.mac & 0xFFFFFFFF00000000LL) | nkeynes@586: (uint64_t)((uint32_t)tmp); nkeynes@359: sh4r.r[Rm] += 4; nkeynes@359: :} nkeynes@359: LDC.L @Rm+, GBR {: nkeynes@359: CHECKRALIGN32( sh4r.r[Rm] ); nkeynes@586: MEM_READ_LONG(sh4r.r[Rm], sh4r.gbr); nkeynes@359: sh4r.r[Rm] +=4; nkeynes@359: :} nkeynes@359: LDS Rm, MACL {: nkeynes@359: sh4r.mac = (sh4r.mac & 0xFFFFFFFF00000000LL) | nkeynes@359: (uint64_t)((uint32_t)(sh4r.r[Rm])); nkeynes@359: :} nkeynes@359: LDC Rm, GBR {: sh4r.gbr = sh4r.r[Rm]; :} nkeynes@359: STS PR, Rn {: sh4r.r[Rn] = sh4r.pr; :} nkeynes@359: STS.L PR, @-Rn {: nkeynes@587: CHECKWALIGN32( sh4r.r[Rn] ); nkeynes@587: MEM_WRITE_LONG( sh4r.r[Rn]-4, sh4r.pr ); nkeynes@359: sh4r.r[Rn] -= 4; nkeynes@359: :} nkeynes@359: STC.L VBR, @-Rn {: nkeynes@359: CHECKPRIV(); nkeynes@587: CHECKWALIGN32( sh4r.r[Rn] ); nkeynes@587: MEM_WRITE_LONG( sh4r.r[Rn]-4, sh4r.vbr ); nkeynes@359: sh4r.r[Rn] -= 4; nkeynes@359: :} nkeynes@359: LDS.L @Rm+, PR {: nkeynes@359: CHECKRALIGN32( sh4r.r[Rm] ); nkeynes@586: MEM_READ_LONG( sh4r.r[Rm], sh4r.pr ); nkeynes@359: sh4r.r[Rm] += 4; nkeynes@359: :} nkeynes@359: LDC.L @Rm+, VBR {: nkeynes@359: CHECKPRIV(); nkeynes@359: CHECKRALIGN32( sh4r.r[Rm] ); nkeynes@586: MEM_READ_LONG(sh4r.r[Rm], sh4r.vbr); nkeynes@359: sh4r.r[Rm] +=4; nkeynes@359: :} nkeynes@359: LDS Rm, PR {: sh4r.pr = sh4r.r[Rm]; :} nkeynes@359: LDC Rm, VBR {: nkeynes@359: CHECKPRIV(); nkeynes@359: sh4r.vbr = sh4r.r[Rm]; nkeynes@359: :} nkeynes@359: STC SGR, Rn {: nkeynes@359: CHECKPRIV(); nkeynes@359: sh4r.r[Rn] = sh4r.sgr; nkeynes@359: :} nkeynes@359: STC.L SGR, @-Rn {: nkeynes@359: CHECKPRIV(); nkeynes@587: CHECKWALIGN32( sh4r.r[Rn] ); nkeynes@587: MEM_WRITE_LONG( sh4r.r[Rn]-4, sh4r.sgr ); nkeynes@359: sh4r.r[Rn] -= 4; nkeynes@359: :} nkeynes@359: STC.L SSR, @-Rn {: nkeynes@359: CHECKPRIV(); nkeynes@587: CHECKWALIGN32( sh4r.r[Rn] ); nkeynes@587: MEM_WRITE_LONG( sh4r.r[Rn]-4, sh4r.ssr ); nkeynes@359: sh4r.r[Rn] -= 4; nkeynes@359: :} nkeynes@359: LDC.L @Rm+, SSR {: nkeynes@359: CHECKPRIV(); nkeynes@359: CHECKRALIGN32( sh4r.r[Rm] ); nkeynes@586: MEM_READ_LONG(sh4r.r[Rm], sh4r.ssr); nkeynes@359: sh4r.r[Rm] +=4; nkeynes@359: :} nkeynes@359: LDC Rm, SSR {: nkeynes@359: CHECKPRIV(); nkeynes@359: sh4r.ssr = sh4r.r[Rm]; nkeynes@359: :} nkeynes@359: STC.L SPC, @-Rn {: nkeynes@359: CHECKPRIV(); nkeynes@587: CHECKWALIGN32( sh4r.r[Rn] ); nkeynes@587: MEM_WRITE_LONG( sh4r.r[Rn]-4, sh4r.spc ); nkeynes@359: sh4r.r[Rn] -= 4; nkeynes@359: :} nkeynes@359: LDC.L @Rm+, SPC {: nkeynes@359: CHECKPRIV(); nkeynes@359: CHECKRALIGN32( sh4r.r[Rm] ); nkeynes@586: MEM_READ_LONG(sh4r.r[Rm], sh4r.spc); nkeynes@359: sh4r.r[Rm] +=4; nkeynes@359: :} nkeynes@359: LDC Rm, SPC {: nkeynes@359: CHECKPRIV(); nkeynes@359: sh4r.spc = sh4r.r[Rm]; nkeynes@359: :} nkeynes@626: STS FPUL, Rn {: nkeynes@626: CHECKFPUEN(); nkeynes@669: sh4r.r[Rn] = FPULi; nkeynes@626: :} nkeynes@359: STS.L FPUL, @-Rn {: nkeynes@626: CHECKFPUEN(); nkeynes@587: CHECKWALIGN32( sh4r.r[Rn] ); nkeynes@669: MEM_WRITE_LONG( sh4r.r[Rn]-4, FPULi ); nkeynes@359: sh4r.r[Rn] -= 4; nkeynes@359: :} nkeynes@359: LDS.L @Rm+, FPUL {: nkeynes@626: CHECKFPUEN(); nkeynes@359: CHECKRALIGN32( sh4r.r[Rm] ); nkeynes@669: MEM_READ_LONG(sh4r.r[Rm], FPULi); nkeynes@359: sh4r.r[Rm] +=4; nkeynes@359: :} nkeynes@626: LDS Rm, FPUL {: nkeynes@626: CHECKFPUEN(); nkeynes@669: FPULi = sh4r.r[Rm]; nkeynes@626: :} nkeynes@626: STS FPSCR, Rn {: nkeynes@626: CHECKFPUEN(); nkeynes@626: sh4r.r[Rn] = sh4r.fpscr; nkeynes@626: :} nkeynes@359: STS.L FPSCR, @-Rn {: nkeynes@626: CHECKFPUEN(); nkeynes@587: CHECKWALIGN32( sh4r.r[Rn] ); nkeynes@587: MEM_WRITE_LONG( sh4r.r[Rn]-4, sh4r.fpscr ); nkeynes@359: sh4r.r[Rn] -= 4; nkeynes@359: :} nkeynes@359: LDS.L @Rm+, FPSCR {: nkeynes@626: CHECKFPUEN(); nkeynes@359: CHECKRALIGN32( sh4r.r[Rm] ); nkeynes@669: MEM_READ_LONG(sh4r.r[Rm], tmp); nkeynes@359: sh4r.r[Rm] +=4; nkeynes@669: sh4_write_fpscr( tmp ); nkeynes@359: :} nkeynes@374: LDS Rm, FPSCR {: nkeynes@626: CHECKFPUEN(); nkeynes@669: sh4_write_fpscr( sh4r.r[Rm] ); nkeynes@374: :} nkeynes@359: STC DBR, Rn {: CHECKPRIV(); sh4r.r[Rn] = sh4r.dbr; :} nkeynes@359: STC.L DBR, @-Rn {: nkeynes@359: CHECKPRIV(); nkeynes@587: CHECKWALIGN32( sh4r.r[Rn] ); nkeynes@587: MEM_WRITE_LONG( sh4r.r[Rn]-4, sh4r.dbr ); nkeynes@359: sh4r.r[Rn] -= 4; nkeynes@359: :} nkeynes@359: LDC.L @Rm+, DBR {: nkeynes@359: CHECKPRIV(); nkeynes@359: CHECKRALIGN32( sh4r.r[Rm] ); nkeynes@586: MEM_READ_LONG(sh4r.r[Rm], sh4r.dbr); nkeynes@359: sh4r.r[Rm] +=4; nkeynes@359: :} nkeynes@359: LDC Rm, DBR {: nkeynes@359: CHECKPRIV(); nkeynes@359: sh4r.dbr = sh4r.r[Rm]; nkeynes@359: :} nkeynes@359: STC.L Rm_BANK, @-Rn {: nkeynes@359: CHECKPRIV(); nkeynes@587: CHECKWALIGN32( sh4r.r[Rn] ); nkeynes@587: MEM_WRITE_LONG( sh4r.r[Rn]-4, sh4r.r_bank[Rm_BANK] ); nkeynes@359: sh4r.r[Rn] -= 4; nkeynes@359: :} nkeynes@359: LDC.L @Rm+, Rn_BANK {: nkeynes@359: CHECKPRIV(); nkeynes@359: CHECKRALIGN32( sh4r.r[Rm] ); nkeynes@586: MEM_READ_LONG( sh4r.r[Rm], sh4r.r_bank[Rn_BANK] ); nkeynes@359: sh4r.r[Rm] += 4; nkeynes@359: :} nkeynes@359: LDC Rm, Rn_BANK {: nkeynes@359: CHECKPRIV(); nkeynes@359: sh4r.r_bank[Rn_BANK] = sh4r.r[Rm]; nkeynes@359: :} nkeynes@359: STC SR, Rn {: nkeynes@359: CHECKPRIV(); nkeynes@359: sh4r.r[Rn] = sh4_read_sr(); nkeynes@359: :} nkeynes@359: STC GBR, Rn {: nkeynes@359: sh4r.r[Rn] = sh4r.gbr; nkeynes@359: :} nkeynes@359: STC VBR, Rn {: nkeynes@359: CHECKPRIV(); nkeynes@359: sh4r.r[Rn] = sh4r.vbr; nkeynes@359: :} nkeynes@359: STC SSR, Rn {: nkeynes@359: CHECKPRIV(); nkeynes@359: sh4r.r[Rn] = sh4r.ssr; nkeynes@359: :} nkeynes@359: STC SPC, Rn {: nkeynes@359: CHECKPRIV(); nkeynes@359: sh4r.r[Rn] = sh4r.spc; nkeynes@359: :} nkeynes@359: STC Rm_BANK, Rn {: nkeynes@359: CHECKPRIV(); nkeynes@359: sh4r.r[Rn] = sh4r.r_bank[Rm_BANK]; nkeynes@359: :} nkeynes@359: nkeynes@359: FADD FRm, FRn {: 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: FSUB FRm, FRn {: 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: nkeynes@359: FMUL FRm, FRn {: 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: nkeynes@359: FDIV FRm, FRn {: 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: nkeynes@359: FCMP/EQ FRm, FRn {: 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: nkeynes@359: FCMP/GT FRm, FRn {: 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: nkeynes@359: FSTS FPUL, FRn {: CHECKFPUEN(); FR(FRn) = FPULf; :} nkeynes@359: FLDS FRm, FPUL {: CHECKFPUEN(); FPULf = FR(FRm); :} nkeynes@359: FLOAT FPUL, FRn {: 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@374: } nkeynes@359: :} nkeynes@359: FTRC FRm, FPUL {: 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: FNEG FRn {: 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: FABS FRn {: 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: FSQRT FRn {: 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: FLDI0 FRn {: 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: FLDI1 FRn {: 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: FMAC FR0, FRm, FRn {: 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@374: FRCHG {: nkeynes@374: CHECKFPUEN(); nkeynes@374: sh4r.fpscr ^= FPSCR_FR; nkeynes@669: sh4_switch_fr_banks(); nkeynes@374: :} nkeynes@359: FSCHG {: CHECKFPUEN(); sh4r.fpscr ^= FPSCR_SZ; :} nkeynes@359: FCNVSD FPUL, FRn {: nkeynes@359: CHECKFPUEN(); nkeynes@359: if( IS_FPU_DOUBLEPREC() && !IS_FPU_DOUBLESIZE() ) { nkeynes@359: DR(FRn) = (double)FPULf; nkeynes@359: } nkeynes@359: :} nkeynes@359: FCNVDS FRm, FPUL {: nkeynes@359: CHECKFPUEN(); nkeynes@359: if( IS_FPU_DOUBLEPREC() && !IS_FPU_DOUBLESIZE() ) { nkeynes@359: FPULf = (float)DR(FRm); nkeynes@359: } nkeynes@359: :} nkeynes@359: nkeynes@359: FSRRA FRn {: nkeynes@359: CHECKFPUEN(); nkeynes@359: if( !IS_FPU_DOUBLEPREC() ) { nkeynes@359: FR(FRn) = 1.0/sqrtf(FR(FRn)); nkeynes@359: } nkeynes@359: :} nkeynes@359: FIPR FVm, FVn {: 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: FSCA FPUL, FRn {: 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: FTRV XMTRX, FVn {: nkeynes@359: CHECKFPUEN(); nkeynes@359: if( !IS_FPU_DOUBLEPREC() ) { nkeynes@669: sh4_ftrv(&(DRF(FVn<<1)) ); nkeynes@359: } nkeynes@359: :} nkeynes@359: UNDEF {: nkeynes@359: UNDEF(ir); nkeynes@359: :} nkeynes@359: %% nkeynes@359: sh4r.pc = sh4r.new_pc; nkeynes@359: sh4r.new_pc += 2; nkeynes@359: sh4r.in_delay_slot = 0; nkeynes@359: return TRUE; nkeynes@359: }