1.1 --- a/src/sh4/sh4core.in Mon Dec 15 10:44:56 2008 +0000
1.2 +++ b/src/sh4/sh4core.in Wed Jan 14 00:16:44 2009 +0000
1.4 #include "sh4/sh4core.h"
1.5 #include "sh4/sh4mmio.h"
1.6 #include "sh4/sh4stat.h"
1.7 -#include "sh4/intc.h"
1.8 +#include "sh4/mmu.h"
1.10 #define SH4_CALLTRACE 1
1.14 /********************** SH4 emulation core ****************************/
1.16 -#define UNDEF(ir) return sh4_raise_slot_exception(EXC_ILLEGAL, EXC_SLOT_ILLEGAL)
1.17 -#define UNIMP(ir) do{ ERROR( "Halted on unimplemented instruction at %08x, opcode = %04x", sh4r.pc, ir ); sh4_core_exit(CORE_EXIT_HALT); return FALSE; }while(0)
1.19 #if(SH4_CALLTRACE == 1)
1.20 #define MAX_CALLSTACK 32
1.21 static struct call_stack {
1.22 @@ -152,72 +149,208 @@
1.23 #define TRACE_RETURN( source, dest )
1.26 -#define CHECKPRIV() if( !IS_SH4_PRIVMODE() ) return sh4_raise_slot_exception( EXC_ILLEGAL, EXC_SLOT_ILLEGAL )
1.27 -#define CHECKRALIGN16(addr) if( (addr)&0x01 ) return sh4_raise_exception( EXC_DATA_ADDR_READ )
1.28 -#define CHECKRALIGN32(addr) if( (addr)&0x03 ) return sh4_raise_exception( EXC_DATA_ADDR_READ )
1.29 -#define CHECKRALIGN64(addr) if( (addr)&0x07 ) return sh4_raise_exception( EXC_DATA_ADDR_READ )
1.30 -#define CHECKWALIGN16(addr) if( (addr)&0x01 ) return sh4_raise_exception( EXC_DATA_ADDR_WRITE )
1.31 -#define CHECKWALIGN32(addr) if( (addr)&0x03 ) return sh4_raise_exception( EXC_DATA_ADDR_WRITE )
1.32 -#define CHECKWALIGN64(addr) if( (addr)&0x07 ) return sh4_raise_exception( EXC_DATA_ADDR_WRITE )
1.33 +static gboolean FASTCALL sh4_raise_slot_exception( int normal_code, int slot_code ) {
1.34 + if( sh4r.in_delay_slot ) {
1.35 + sh4_raise_exception(slot_code);
1.37 + sh4_raise_exception(normal_code);
1.43 +#define CHECKPRIV() if( !IS_SH4_PRIVMODE() ) { return sh4_raise_slot_exception( EXC_ILLEGAL, EXC_SLOT_ILLEGAL ); }
1.44 +#define CHECKRALIGN16(addr) if( (addr)&0x01 ) { sh4_raise_exception( EXC_DATA_ADDR_READ ); return TRUE; }
1.45 +#define CHECKRALIGN32(addr) if( (addr)&0x03 ) { sh4_raise_exception( EXC_DATA_ADDR_READ ); return TRUE; }
1.46 +#define CHECKRALIGN64(addr) if( (addr)&0x07 ) { sh4_raise_exception( EXC_DATA_ADDR_READ ); return TRUE; }
1.47 +#define CHECKWALIGN16(addr) if( (addr)&0x01 ) { sh4_raise_exception( EXC_DATA_ADDR_WRITE ); return TRUE; }
1.48 +#define CHECKWALIGN32(addr) if( (addr)&0x03 ) { sh4_raise_exception( EXC_DATA_ADDR_WRITE ); return TRUE; }
1.49 +#define CHECKWALIGN64(addr) if( (addr)&0x07 ) { sh4_raise_exception( EXC_DATA_ADDR_WRITE ); return TRUE; }
1.51 #define CHECKFPUEN() if( !IS_FPU_ENABLED() ) { if( ir == 0xFFFD ) { UNDEF(ir); } else { return sh4_raise_slot_exception( EXC_FPU_DISABLED, EXC_SLOT_FPU_DISABLED ); } }
1.52 #define CHECKDEST(p) if( (p) == 0 ) { ERROR( "%08X: Branch/jump to NULL, CPU halted", sh4r.pc ); sh4_core_exit(CORE_EXIT_HALT); return FALSE; }
1.53 -#define CHECKSLOTILLEGAL() if(sh4r.in_delay_slot) return sh4_raise_exception(EXC_SLOT_ILLEGAL)
1.54 +#define CHECKSLOTILLEGAL() if(sh4r.in_delay_slot) { sh4_raise_exception(EXC_SLOT_ILLEGAL); return TRUE; }
1.56 +#define ADDRSPACE (IS_SH4_PRIVMODE() ? sh4_address_space : sh4_user_address_space)
1.57 +#define SQADDRSPACE (IS_SH4_PRIVMODE() ? storequeue_address_space : storequeue_user_address_space)
1.59 #ifdef HAVE_FRAME_ADDRESS
1.60 static FASTCALL __attribute__((noinline)) void *__first_arg(void *a, void *b) { return a; }
1.61 #define INIT_EXCEPTIONS(label) goto *__first_arg(&&fnstart,&&label); fnstart:
1.62 -#define MMU_TRANSLATE_READ( addr ) memtmp = mmu_vma_to_phys_read(addr, &&except )
1.63 -#define MMU_TRANSLATE_WRITE( addr ) memtmp = mmu_vma_to_phys_write(addr, &&except )
1.64 +#define MEM_READ_BYTE( addr, val ) val = ((mem_read_exc_fn_t)ADDRSPACE[(addr)>>12]->read_byte)((addr), &&except)
1.65 +#define MEM_READ_WORD( addr, val ) val = ((mem_read_exc_fn_t)ADDRSPACE[(addr)>>12]->read_word)((addr), &&except)
1.66 +#define MEM_READ_LONG( addr, val ) val = ((mem_read_exc_fn_t)ADDRSPACE[(addr)>>12]->read_long)((addr), &&except)
1.67 +#define MEM_WRITE_BYTE( addr, val ) ((mem_write_exc_fn_t)ADDRSPACE[(addr)>>12]->write_byte)((addr), (val), &&except)
1.68 +#define MEM_WRITE_WORD( addr, val ) ((mem_write_exc_fn_t)ADDRSPACE[(addr)>>12]->write_word)((addr), (val), &&except)
1.69 +#define MEM_WRITE_LONG( addr, val ) ((mem_write_exc_fn_t)ADDRSPACE[(addr)>>12]->write_long)((addr), (val), &&except)
1.70 +#define MEM_PREFETCH( addr ) ((mem_prefetch_exc_fn_t)ADDRSPACE[(addr)>>12]->prefetch)((addr), &&except)
1.72 #define INIT_EXCEPTIONS(label)
1.73 -#define MMU_TRANSLATE_READ( addr ) if( (memtmp = mmu_vma_to_phys_read(addr)) == MMU_VMA_ERROR ) { return TRUE; }
1.74 -#define MMU_TRANSLATE_WRITE( addr ) if( (memtmp = mmu_vma_to_phys_write(addr)) == MMU_VMA_ERROR ) { return TRUE; }
1.75 +#define MEM_READ_BYTE( addr, val ) val = ADDRSPACE[(addr)>>12]->read_byte(addr)
1.76 +#define MEM_READ_WORD( addr, val ) val = ADDRSPACE[(addr)>>12]->read_word(addr)
1.77 +#define MEM_READ_LONG( addr, val ) val = ADDRSPACE[(addr)>>12]->read_long(addr)
1.78 +#define MEM_WRITE_BYTE( addr, val ) ADDRSPACE[(addr)>>12]->write_byte(addr, val)
1.79 +#define MEM_WRITE_WORD( addr, val ) ADDRSPACE[(addr)>>12]->write_word(addr, val)
1.80 +#define MEM_WRITE_LONG( addr, val ) ADDRSPACE[(addr)>>12]->write_long(addr, val)
1.81 +#define MEM_PREFETCH( addr ) ADDRSPACE[(addr)>>12]->prefetch(addr)
1.84 -#define MEM_READ_BYTE( addr, val ) MMU_TRANSLATE_READ(addr); val = sh4_read_byte(memtmp)
1.85 -#define MEM_READ_WORD( addr, val ) MMU_TRANSLATE_READ(addr); val = sh4_read_word(memtmp)
1.86 -#define MEM_READ_LONG( addr, val ) MMU_TRANSLATE_READ(addr); val = sh4_read_long(memtmp)
1.87 -#define MEM_WRITE_BYTE( addr, val ) MMU_TRANSLATE_WRITE(addr); sh4_write_byte(memtmp, val)
1.88 -#define MEM_WRITE_WORD( addr, val ) MMU_TRANSLATE_WRITE(addr); sh4_write_word(memtmp, val)
1.89 -#define MEM_WRITE_LONG( addr, val ) MMU_TRANSLATE_WRITE(addr); sh4_write_long(memtmp, val)
1.92 #define FP_WIDTH (IS_FPU_DOUBLESIZE() ? 8 : 4)
1.94 #define MEM_FP_READ( addr, reg ) \
1.95 if( IS_FPU_DOUBLESIZE() ) { \
1.96 CHECKRALIGN64(addr); \
1.97 - MMU_TRANSLATE_READ(addr); \
1.99 - *((uint32_t *)&XF((reg) & 0x0E)) = sh4_read_long(memtmp); \
1.100 - *((uint32_t *)&XF(reg)) = sh4_read_long(memtmp+4); \
1.101 + MEM_READ_LONG( addr, *((uint32_t *)&XF((reg) & 0x0E)) ); \
1.102 + MEM_READ_LONG( addr+4, *((uint32_t *)&XF(reg)) ); \
1.104 - *((uint32_t *)&FR(reg)) = sh4_read_long(memtmp); \
1.105 - *((uint32_t *)&FR((reg) | 0x01)) = sh4_read_long(memtmp+4); \
1.106 + MEM_READ_LONG( addr, *((uint32_t *)&FR(reg)) ); \
1.107 + MEM_READ_LONG( addr+4, *((uint32_t *)&FR((reg)|0x01)) ); \
1.110 CHECKRALIGN32(addr); \
1.111 - MMU_TRANSLATE_READ(addr); \
1.112 - *((uint32_t *)&FR(reg)) = sh4_read_long(memtmp); \
1.113 + MEM_READ_LONG( addr, *((uint32_t *)&FR(reg)) ); \
1.115 #define MEM_FP_WRITE( addr, reg ) \
1.116 if( IS_FPU_DOUBLESIZE() ) { \
1.117 CHECKWALIGN64(addr); \
1.118 - MMU_TRANSLATE_WRITE(addr); \
1.120 - sh4_write_long( memtmp, *((uint32_t *)&XF((reg)&0x0E)) ); \
1.121 - sh4_write_long( memtmp+4, *((uint32_t *)&XF(reg)) ); \
1.122 + MEM_WRITE_LONG( addr, *((uint32_t *)&XF((reg)&0x0E)) ); \
1.123 + MEM_WRITE_LONG( addr+4, *((uint32_t *)&XF(reg)) ); \
1.125 - sh4_write_long( memtmp, *((uint32_t *)&FR(reg)) ); \
1.126 - sh4_write_long( memtmp+4, *((uint32_t *)&FR((reg)|0x01)) ); \
1.127 + MEM_WRITE_LONG( addr, *((uint32_t *)&FR(reg)) ); \
1.128 + MEM_WRITE_LONG( addr+4, *((uint32_t *)&FR((reg)|0x01)) ); \
1.131 CHECKWALIGN32(addr); \
1.132 - MMU_TRANSLATE_WRITE(addr); \
1.133 - sh4_write_long( memtmp, *((uint32_t *)&FR((reg))) ); \
1.134 + MEM_WRITE_LONG(addr, *((uint32_t *)&FR((reg))) ); \
1.141 + * Perform instruction-completion following core exit of a partially completed
1.142 + * instruction. NOTE: This is only allowed on memory writes, operation is not
1.143 + * guaranteed in any other case.
1.145 +void sh4_finalize_instruction( void )
1.147 + unsigned short ir;
1.150 + assert( IS_IN_ICACHE(sh4r.pc) );
1.151 + ir = *(uint16_t *)GET_ICACHE_PTR(sh4r.pc);
1.154 + * Note - we can't take an exit on a control transfer instruction itself,
1.155 + * which means the exit must have happened in the delay slot. So for these
1.156 + * cases, finalize the delay slot instruction, and re-execute the control transfer.
1.158 + * For delay slots which modify the argument used in the branch instruction,
1.159 + * we pretty much just assume that that can't have already happened in an exit case.
1.165 + sh4_finalize_instruction();
1.167 + sh4r.slice_cycle += sh4_cpu_period;
1.171 + tmp = sh4r.r[Rn];
1.172 + sh4_finalize_instruction();
1.174 + sh4r.slice_cycle += sh4_cpu_period;
1.177 + /* Note: PR is already set */
1.179 + sh4_finalize_instruction();
1.181 + sh4r.slice_cycle += sh4_cpu_period;
1.184 + /* Note: PR is already set */
1.186 + tmp = sh4r.r[Rn];
1.187 + sh4_finalize_instruction();
1.189 + sh4r.slice_cycle += sh4_cpu_period;
1.193 + sh4_finalize_instruction();
1.197 + sh4r.slice_cycle += sh4_cpu_period;
1.201 + sh4_finalize_instruction();
1.205 + sh4r.slice_cycle += sh4_cpu_period;
1.209 + tmp = sh4r.r[Rn];
1.210 + sh4_finalize_instruction();
1.212 + sh4r.new_pc = tmp + 2;
1.213 + sh4r.slice_cycle += 2*sh4_cpu_period;
1.217 + /* Note: PR is already set */
1.219 + tmp = sh4r.r[Rn];
1.220 + sh4_finalize_instruction();
1.222 + sh4r.new_pc = tmp + 2;
1.223 + sh4r.slice_cycle += 2*sh4_cpu_period;
1.228 + sh4_finalize_instruction();
1.229 + sh4r.pc = sh4r.pr;
1.230 + sh4r.new_pc = sh4r.pr + 2;
1.231 + sh4r.slice_cycle += 2*sh4_cpu_period;
1.235 + /* SR is already set */
1.237 + sh4_finalize_instruction();
1.238 + sh4r.pc = sh4r.spc;
1.239 + sh4r.new_pc = sh4r.pr + 2;
1.240 + sh4r.slice_cycle += 2*sh4_cpu_period;
1.243 +MOV.B Rm, @-Rn {: sh4r.r[Rn]--; :}
1.244 +MOV.W Rm, @-Rn {: sh4r.r[Rn] -= 2; :}
1.245 +MOV.L Rm, @-Rn {: sh4r.r[Rn] -= 4; :}
1.246 +MOV.B @Rm+, Rn {: sh4r.r[Rm] ++; :}
1.247 +MOV.W @Rm+, Rn {: sh4r.r[Rm] += 2; :}
1.248 +MOV.L @Rm+, Rn {: sh4r.r[Rm] += 4; :}
1.251 + sh4r.new_pc = sh4r.pc+2;
1.252 + sh4r.slice_cycle += sh4_cpu_period;
1.258 +#define UNDEF(ir) return sh4_raise_slot_exception(EXC_ILLEGAL, EXC_SLOT_ILLEGAL)
1.259 +#define UNIMP(ir) do{ ERROR( "Halted on unimplemented instruction at %08x, opcode = %04x", sh4r.pc, ir ); sh4_core_exit(CORE_EXIT_HALT); return FALSE; }while(0)
1.262 gboolean sh4_execute_instruction( void )
1.265 @@ -260,6 +393,14 @@
1.267 assert( IS_IN_ICACHE(pc) );
1.268 ir = *(uint16_t *)GET_ICACHE_PTR(sh4r.pc);
1.270 + /* FIXME: This is a bit of a hack, but the PC of the delay slot should not
1.271 + * be visible until after the instruction has executed (for exception
1.274 + if( sh4r.in_delay_slot ) {
1.278 AND Rm, Rn {: sh4r.r[Rn] &= sh4r.r[Rm]; :}
1.279 AND #imm, R0 {: R0 &= imm; :}
1.280 @@ -351,10 +492,7 @@
1.281 NOP {: /* NOP */ :}
1.284 - tmp = sh4r.r[Rn];
1.285 - if( (tmp & 0xFC000000) == 0xE0000000 ) {
1.286 - sh4_flush_store_queue(tmp);
1.288 + MEM_PREFETCH(sh4r.r[Rn]);