Search
lxdream.org :: lxdream/src/sh4/sh4core.in :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4core.in
changeset 953:f4a156508ad1
prev927:17b6b9e245d8
next970:44d62d0850c8
author nkeynes
date Tue Jan 13 11:56:28 2009 +0000 (11 years ago)
permissions -rw-r--r--
last change Merge lxdream-mem branch back to trunk
file annotate diff log raw
1.1 --- a/src/sh4/sh4core.in Mon Dec 15 10:44:56 2008 +0000
1.2 +++ b/src/sh4/sh4core.in Tue Jan 13 11:56:28 2009 +0000
1.3 @@ -29,7 +29,7 @@
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.9
1.10 #define SH4_CALLTRACE 1
1.11
1.12 @@ -102,9 +102,6 @@
1.13
1.14 /********************** SH4 emulation core ****************************/
1.15
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.18 -
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.24 #endif
1.25
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.36 + } else {
1.37 + sh4_raise_exception(normal_code);
1.38 + }
1.39 + return TRUE;
1.40 +}
1.41 +
1.42 +
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.50
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.55 +
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.58
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.71 #else
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.82 #endif
1.83 -
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.90 -
1.91
1.92 #define FP_WIDTH (IS_FPU_DOUBLESIZE() ? 8 : 4)
1.93
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.98 if( reg & 1 ) { \
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.103 } else { \
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.108 } \
1.109 } else { \
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.114 }
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.119 if( reg & 1 ) { \
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.124 } else { \
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.129 } \
1.130 } else { \
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.135 }
1.136
1.137 +#define UNDEF(ir)
1.138 +#define UNIMP(ir)
1.139 +
1.140 +/**
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.144 + */
1.145 +void sh4_finalize_instruction( void )
1.146 +{
1.147 + unsigned short ir;
1.148 + uint32_t tmp;
1.149 +
1.150 + assert( IS_IN_ICACHE(sh4r.pc) );
1.151 + ir = *(uint16_t *)GET_ICACHE_PTR(sh4r.pc);
1.152 +
1.153 + /**
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.157 + *
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.160 + */
1.161 +
1.162 +%%
1.163 +BRA disp {:
1.164 + sh4r.pc += 2;
1.165 + sh4_finalize_instruction();
1.166 + sh4r.pc += disp;
1.167 + sh4r.slice_cycle += sh4_cpu_period;
1.168 +:}
1.169 +BRAF Rn {:
1.170 + sh4r.pc += 2;
1.171 + tmp = sh4r.r[Rn];
1.172 + sh4_finalize_instruction();
1.173 + sh4r.pc += tmp;
1.174 + sh4r.slice_cycle += sh4_cpu_period;
1.175 +:}
1.176 +BSR disp {:
1.177 + /* Note: PR is already set */
1.178 + sh4r.pc += 2;
1.179 + sh4_finalize_instruction();
1.180 + sh4r.pc += disp;
1.181 + sh4r.slice_cycle += sh4_cpu_period;
1.182 +:}
1.183 +BSRF Rn {:
1.184 + /* Note: PR is already set */
1.185 + sh4r.pc += 2;
1.186 + tmp = sh4r.r[Rn];
1.187 + sh4_finalize_instruction();
1.188 + sh4r.pc += tmp;
1.189 + sh4r.slice_cycle += sh4_cpu_period;
1.190 +:}
1.191 +BF/S disp {:
1.192 + sh4r.pc += 2;
1.193 + sh4_finalize_instruction();
1.194 + if( !sh4r.t ) {
1.195 + sh4r.pc += disp;
1.196 + }
1.197 + sh4r.slice_cycle += sh4_cpu_period;
1.198 +:}
1.199 +BT/S disp {:
1.200 + sh4r.pc += 2;
1.201 + sh4_finalize_instruction();
1.202 + if( sh4r.t ) {
1.203 + sh4r.pc += disp;
1.204 + }
1.205 + sh4r.slice_cycle += sh4_cpu_period;
1.206 +:}
1.207 +JMP @Rn {:
1.208 + sh4r.pc += 2;
1.209 + tmp = sh4r.r[Rn];
1.210 + sh4_finalize_instruction();
1.211 + sh4r.pc = tmp;
1.212 + sh4r.new_pc = tmp + 2;
1.213 + sh4r.slice_cycle += 2*sh4_cpu_period;
1.214 + return;
1.215 +:}
1.216 +JSR @Rn {:
1.217 + /* Note: PR is already set */
1.218 + sh4r.pc += 2;
1.219 + tmp = sh4r.r[Rn];
1.220 + sh4_finalize_instruction();
1.221 + sh4r.pc = tmp;
1.222 + sh4r.new_pc = tmp + 2;
1.223 + sh4r.slice_cycle += 2*sh4_cpu_period;
1.224 + return;
1.225 +:}
1.226 +RTS {:
1.227 + sh4r.pc += 2;
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.232 + return;
1.233 +:}
1.234 +RTE {:
1.235 + /* SR is already set */
1.236 + sh4r.pc += 2;
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.241 + return;
1.242 +:}
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.249 +%%
1.250 + sh4r.pc += 2;
1.251 + sh4r.new_pc = sh4r.pc+2;
1.252 + sh4r.slice_cycle += sh4_cpu_period;
1.253 +}
1.254 +
1.255 +#undef UNDEF(ir)
1.256 +#undef UNIMP(ir)
1.257 +
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.260 +
1.261 +
1.262 gboolean sh4_execute_instruction( void )
1.263 {
1.264 uint32_t pc;
1.265 @@ -260,6 +393,14 @@
1.266 }
1.267 assert( IS_IN_ICACHE(pc) );
1.268 ir = *(uint16_t *)GET_ICACHE_PTR(sh4r.pc);
1.269 +
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.272 + * correctness)
1.273 + */
1.274 + if( sh4r.in_delay_slot ) {
1.275 + sh4r.pc -= 2;
1.276 + }
1.277 %%
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.282
1.283 PREF @Rn {:
1.284 - tmp = sh4r.r[Rn];
1.285 - if( (tmp & 0xFC000000) == 0xE0000000 ) {
1.286 - sh4_flush_store_queue(tmp);
1.287 - }
1.288 + MEM_PREFETCH(sh4r.r[Rn]);
1.289 :}
1.290 OCBI @Rn {: :}
1.291 OCBP @Rn {: :}
.