Search
lxdream.org :: lxdream/src/sh4/sh4x86.c :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4x86.c
changeset 590:4db6a084ca3c
prev586:2a3ba82cf243
next591:7b9612fd2395
author nkeynes
date Wed Jan 16 09:39:16 2008 +0000 (13 years ago)
permissions -rw-r--r--
last change Ensure PC correctness in presence of delay-slot exceptions
file annotate diff log raw
1.1 --- a/src/sh4/sh4x86.c Tue Jan 15 20:50:23 2008 +0000
1.2 +++ b/src/sh4/sh4x86.c Wed Jan 16 09:39:16 2008 +0000
1.3 @@ -42,13 +42,17 @@
1.4
1.5 #define MAX_RECOVERY_SIZE 2048
1.6
1.7 +#define DELAY_NONE 0
1.8 +#define DELAY_PC 1
1.9 +#define DELAY_PC_PR 2
1.10 +
1.11 /**
1.12 * Struct to manage internal translation state. This state is not saved -
1.13 * it is only valid between calls to sh4_translate_begin_block() and
1.14 * sh4_translate_end_block()
1.15 */
1.16 struct sh4_x86_state {
1.17 - gboolean in_delay_slot;
1.18 + int in_delay_slot;
1.19 gboolean priv_checked; /* true if we've already checked the cpu mode. */
1.20 gboolean fpuen_checked; /* true if we've already checked fpu enabled. */
1.21 gboolean branch_taken; /* true if we branched unconditionally */
1.22 @@ -342,7 +346,7 @@
1.23 #define MEM_WRITE_SIZE (CALL_FUNC2_SIZE)
1.24 #define MMU_TRANSLATE_SIZE (sh4_x86.tlb_on ? (CALL_FUNC1_SIZE + 12) : 0 )
1.25
1.26 -#define SLOTILLEGAL() JMP_exc(EXC_SLOT_ILLEGAL); sh4_x86.in_delay_slot = FALSE; return 1;
1.27 +#define SLOTILLEGAL() JMP_exc(EXC_SLOT_ILLEGAL); sh4_x86.in_delay_slot = DELAY_NONE; return 1;
1.28
1.29 /****** Import appropriate calling conventions ******/
1.30 #if SH4_TRANSLATOR == TARGET_X86_64
1.31 @@ -355,12 +359,41 @@
1.32 #endif
1.33 #endif
1.34
1.35 +/**
1.36 + * Embed a breakpoint into the generated code
1.37 + */
1.38 void sh4_translate_emit_breakpoint( sh4vma_t pc )
1.39 {
1.40 load_imm32( R_EAX, XLAT_EXIT_BREAKPOINT );
1.41 call_func1( sh4_translate_exit, R_EAX );
1.42 }
1.43 +
1.44 +/**
1.45 + * Embed a call to sh4_execute_instruction for situations that we
1.46 + * can't translate (mainly page-crossing delay slots at the moment).
1.47 + * Caller is responsible for setting new_pc.
1.48 + */
1.49 +void sh4_emulator_exit( sh4vma_t endpc )
1.50 +{
1.51 + load_imm32( R_ECX, endpc - sh4_x86.block_start_pc ); // 5
1.52 + ADD_r32_sh4r( R_ECX, R_PC );
1.53
1.54 + load_imm32( R_ECX, ((endpc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
1.55 + ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6
1.56 + load_imm32( R_ECX, sh4_x86.in_delay_slot ? 1 : 0 );
1.57 + store_spreg( R_ECX, REG_OFFSET(in_delay_slot) );
1.58 +
1.59 + call_func0( sh4_execute_instruction );
1.60 + load_imm32( R_EAX, R_PC );
1.61 + if( sh4_x86.tlb_on ) {
1.62 + call_func1(xlat_get_code_by_vma,R_EAX);
1.63 + } else {
1.64 + call_func1(xlat_get_code,R_EAX);
1.65 + }
1.66 + AND_imm8s_r32( 0xFC, R_EAX ); // 3
1.67 + POP_r32(R_EBP);
1.68 + RET();
1.69 +}
1.70
1.71 /**
1.72 * Translate a single instruction. Delayed branches are handled specially
1.73 @@ -371,7 +404,7 @@
1.74 * @return true if the instruction marks the end of a basic block
1.75 * (eg a branch or
1.76 */
1.77 -uint32_t sh4_translate_instruction( sh4addr_t pc )
1.78 +uint32_t sh4_translate_instruction( sh4vma_t pc )
1.79 {
1.80 uint32_t ir;
1.81 /* Read instruction from icache */
1.82 @@ -465,14 +498,15 @@
1.83 if( sh4_x86.in_delay_slot ) {
1.84 SLOTILLEGAL();
1.85 } else {
1.86 - load_imm32( R_ECX, pc + 4 );
1.87 - store_spreg( R_ECX, R_PR );
1.88 - ADD_sh4r_r32( REG_OFFSET(r[Rn]), R_ECX );
1.89 - store_spreg( R_ECX, REG_OFFSET(pc) );
1.90 - sh4_x86.in_delay_slot = TRUE;
1.91 + load_spreg( R_EAX, R_PC );
1.92 + ADD_imm32_r32( pc + 4 - sh4_x86.block_start_pc, R_EAX );
1.93 + store_spreg( R_EAX, R_PR );
1.94 + ADD_sh4r_r32( REG_OFFSET(r[Rn]), R_EAX );
1.95 + store_spreg( R_EAX, R_NEW_PC );
1.96 +
1.97 sh4_x86.tstate = TSTATE_NONE;
1.98 sh4_translate_instruction( pc + 2 );
1.99 - exit_block_pcset(pc+2);
1.100 + exit_block_newpcset(pc+2);
1.101 sh4_x86.branch_taken = TRUE;
1.102 return 4;
1.103 }
1.104 @@ -484,13 +518,14 @@
1.105 if( sh4_x86.in_delay_slot ) {
1.106 SLOTILLEGAL();
1.107 } else {
1.108 - load_reg( R_EAX, Rn );
1.109 - ADD_imm32_r32( pc + 4, R_EAX );
1.110 - store_spreg( R_EAX, REG_OFFSET(pc) );
1.111 - sh4_x86.in_delay_slot = TRUE;
1.112 + load_spreg( R_EAX, R_PC );
1.113 + ADD_imm32_r32( pc + 4 - sh4_x86.block_start_pc, R_EAX );
1.114 + ADD_sh4r_r32( REG_OFFSET(r[Rn]), R_EAX );
1.115 + store_spreg( R_EAX, R_NEW_PC );
1.116 + sh4_x86.in_delay_slot = DELAY_PC;
1.117 sh4_x86.tstate = TSTATE_NONE;
1.118 sh4_translate_instruction( pc + 2 );
1.119 - exit_block_pcset(pc+2);
1.120 + exit_block_newpcset(pc+2);
1.121 sh4_x86.branch_taken = TRUE;
1.122 return 4;
1.123 }
1.124 @@ -734,10 +769,10 @@
1.125 SLOTILLEGAL();
1.126 } else {
1.127 load_spreg( R_ECX, R_PR );
1.128 - store_spreg( R_ECX, REG_OFFSET(pc) );
1.129 - sh4_x86.in_delay_slot = TRUE;
1.130 + store_spreg( R_ECX, R_NEW_PC );
1.131 + sh4_x86.in_delay_slot = DELAY_PC;
1.132 sh4_translate_instruction(pc+2);
1.133 - exit_block_pcset(pc+2);
1.134 + exit_block_newpcset(pc+2);
1.135 sh4_x86.branch_taken = TRUE;
1.136 return 4;
1.137 }
1.138 @@ -748,7 +783,7 @@
1.139 check_priv();
1.140 call_func0( sh4_sleep );
1.141 sh4_x86.tstate = TSTATE_NONE;
1.142 - sh4_x86.in_delay_slot = FALSE;
1.143 + sh4_x86.in_delay_slot = DELAY_NONE;
1.144 return 2;
1.145 }
1.146 break;
1.147 @@ -759,15 +794,15 @@
1.148 } else {
1.149 check_priv();
1.150 load_spreg( R_ECX, R_SPC );
1.151 - store_spreg( R_ECX, REG_OFFSET(pc) );
1.152 + store_spreg( R_ECX, R_NEW_PC );
1.153 load_spreg( R_EAX, R_SSR );
1.154 call_func1( sh4_write_sr, R_EAX );
1.155 - sh4_x86.in_delay_slot = TRUE;
1.156 + sh4_x86.in_delay_slot = DELAY_PC;
1.157 sh4_x86.priv_checked = FALSE;
1.158 sh4_x86.fpuen_checked = FALSE;
1.159 sh4_x86.tstate = TSTATE_NONE;
1.160 sh4_translate_instruction(pc+2);
1.161 - exit_block_pcset(pc+2);
1.162 + exit_block_newpcset(pc+2);
1.163 sh4_x86.branch_taken = TRUE;
1.164 return 4;
1.165 }
1.166 @@ -1903,13 +1938,13 @@
1.167 if( sh4_x86.in_delay_slot ) {
1.168 SLOTILLEGAL();
1.169 } else {
1.170 - load_imm32( R_EAX, pc + 4 );
1.171 + load_spreg( R_EAX, R_PC );
1.172 + ADD_imm32_r32( pc + 4 - sh4_x86.block_start_pc, R_EAX );
1.173 store_spreg( R_EAX, R_PR );
1.174 load_reg( R_ECX, Rn );
1.175 - store_spreg( R_ECX, REG_OFFSET(pc) );
1.176 - sh4_x86.in_delay_slot = TRUE;
1.177 + store_spreg( R_ECX, R_NEW_PC );
1.178 sh4_translate_instruction(pc+2);
1.179 - exit_block_pcset(pc+2);
1.180 + exit_block_newpcset(pc+2);
1.181 sh4_x86.branch_taken = TRUE;
1.182 return 4;
1.183 }
1.184 @@ -1937,10 +1972,10 @@
1.185 SLOTILLEGAL();
1.186 } else {
1.187 load_reg( R_ECX, Rn );
1.188 - store_spreg( R_ECX, REG_OFFSET(pc) );
1.189 - sh4_x86.in_delay_slot = TRUE;
1.190 + store_spreg( R_ECX, R_NEW_PC );
1.191 + sh4_x86.in_delay_slot = DELAY_PC;
1.192 sh4_translate_instruction(pc+2);
1.193 - exit_block_pcset(pc+2);
1.194 + exit_block_newpcset(pc+2);
1.195 sh4_x86.branch_taken = TRUE;
1.196 return 4;
1.197 }
1.198 @@ -2408,7 +2443,7 @@
1.199 if( sh4_x86.in_delay_slot ) {
1.200 SLOTILLEGAL();
1.201 } else {
1.202 - sh4_x86.in_delay_slot = TRUE;
1.203 + sh4_x86.in_delay_slot = DELAY_PC;
1.204 if( sh4_x86.tstate == TSTATE_NONE ) {
1.205 CMP_imm8s_sh4r( 1, R_T );
1.206 sh4_x86.tstate = TSTATE_E;
1.207 @@ -2430,7 +2465,7 @@
1.208 SLOTILLEGAL();
1.209 } else {
1.210 sh4vma_t target = disp + pc + 4;
1.211 - sh4_x86.in_delay_slot = TRUE;
1.212 + sh4_x86.in_delay_slot = DELAY_PC;
1.213 if( sh4_x86.tstate == TSTATE_NONE ) {
1.214 CMP_imm8s_sh4r( 1, R_T );
1.215 sh4_x86.tstate = TSTATE_E;
1.216 @@ -2479,7 +2514,7 @@
1.217 if( sh4_x86.in_delay_slot ) {
1.218 SLOTILLEGAL();
1.219 } else {
1.220 - sh4_x86.in_delay_slot = TRUE;
1.221 + sh4_x86.in_delay_slot = DELAY_PC;
1.222 sh4_translate_instruction( pc + 2 );
1.223 exit_block_rel( disp + pc + 4, pc+4 );
1.224 sh4_x86.branch_taken = TRUE;
1.225 @@ -2493,9 +2528,10 @@
1.226 if( sh4_x86.in_delay_slot ) {
1.227 SLOTILLEGAL();
1.228 } else {
1.229 - load_imm32( R_EAX, pc + 4 );
1.230 + load_spreg( R_EAX, R_PC );
1.231 + ADD_imm32_r32( pc + 4 - sh4_x86.block_start_pc, R_EAX );
1.232 store_spreg( R_EAX, R_PR );
1.233 - sh4_x86.in_delay_slot = TRUE;
1.234 + sh4_x86.in_delay_slot = DELAY_PC;
1.235 sh4_translate_instruction( pc + 2 );
1.236 exit_block_rel( disp + pc + 4, pc+4 );
1.237 sh4_x86.branch_taken = TRUE;
1.238 @@ -2546,8 +2582,8 @@
1.239 if( sh4_x86.in_delay_slot ) {
1.240 SLOTILLEGAL();
1.241 } else {
1.242 - load_imm32( R_ECX, pc+2 );
1.243 - store_spreg( R_ECX, REG_OFFSET(pc) );
1.244 + load_imm32( R_ECX, pc+2 - sh4_x86.block_start_pc ); // 5
1.245 + ADD_r32_sh4r( R_ECX, R_PC );
1.246 load_imm32( R_EAX, imm );
1.247 call_func1( sh4_raise_trap, R_EAX );
1.248 sh4_x86.tstate = TSTATE_NONE;
1.249 @@ -3492,6 +3528,6 @@
1.250 break;
1.251 }
1.252
1.253 - sh4_x86.in_delay_slot = FALSE;
1.254 + sh4_x86.in_delay_slot = DELAY_NONE;
1.255 return 0;
1.256 }
.