Search
lxdream.org :: lxdream :: r590:4db6a084ca3c
lxdream 0.9.1
released Jun 29
Download Now
changeset590:4db6a084ca3c
parent589:045ba6eb6df1
child591:7b9612fd2395
authornkeynes
dateWed Jan 16 09:39:16 2008 +0000 (12 years ago)
Ensure PC correctness in presence of delay-slot exceptions
src/sh4/ia32abi.h
src/sh4/ia32mac.h
src/sh4/ia64abi.h
src/sh4/sh4x86.c
src/sh4/sh4x86.in
src/sh4/x86op.h
1.1 --- a/src/sh4/ia32abi.h Wed Jan 16 09:37:47 2008 +0000
1.2 +++ b/src/sh4/ia32abi.h Wed Jan 16 09:39:16 2008 +0000
1.3 @@ -116,13 +116,30 @@
1.4
1.5 /**
1.6 * Exit the block with sh4r.pc already written
1.7 - * Bytes: 15
1.8 */
1.9 void exit_block_pcset( sh4addr_t pc )
1.10 {
1.11 load_imm32( R_ECX, ((pc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
1.12 ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6
1.13 - load_spreg( R_EAX, REG_OFFSET(pc) );
1.14 + load_spreg( R_EAX, R_PC );
1.15 + if( sh4_x86.tlb_on ) {
1.16 + call_func1(xlat_get_code_by_vma,R_EAX);
1.17 + } else {
1.18 + call_func1(xlat_get_code,R_EAX);
1.19 + }
1.20 + POP_r32(R_EBP);
1.21 + RET();
1.22 +}
1.23 +
1.24 +/**
1.25 + * Exit the block with sh4r.new_pc written with the target pc
1.26 + */
1.27 +void exit_block_newpcset( sh4addr_t pc )
1.28 +{
1.29 + load_imm32( R_ECX, ((pc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
1.30 + ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6
1.31 + load_spreg( R_EAX, R_NEW_PC );
1.32 + store_spreg( R_EAX, R_PC );
1.33 if( sh4_x86.tlb_on ) {
1.34 call_func1(xlat_get_code_by_vma,R_EAX);
1.35 } else {
2.1 --- a/src/sh4/ia32mac.h Wed Jan 16 09:37:47 2008 +0000
2.2 +++ b/src/sh4/ia32mac.h Wed Jan 16 09:39:16 2008 +0000
2.3 @@ -138,14 +138,13 @@
2.4 }
2.5
2.6 /**
2.7 - * Exit the block with sh4r.pc already written
2.8 - * Bytes: 15
2.9 + * Exit the block with sh4r.new_pc written with the target pc
2.10 */
2.11 void exit_block_pcset( sh4addr_t pc )
2.12 {
2.13 load_imm32( R_ECX, ((pc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
2.14 ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6
2.15 - load_spreg( R_EAX, REG_OFFSET(pc) );
2.16 + load_spreg( R_EAX, R_PC );
2.17 if( sh4_x86.tlb_on ) {
2.18 call_func1(xlat_get_code_by_vma,R_EAX);
2.19 } else {
2.20 @@ -155,6 +154,25 @@
2.21 RET();
2.22 }
2.23
2.24 +/**
2.25 + * Exit the block with sh4r.new_pc written with the target pc
2.26 + */
2.27 +void exit_block_newpcset( sh4addr_t pc )
2.28 +{
2.29 + load_imm32( R_ECX, ((pc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
2.30 + ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6
2.31 + load_spreg( R_EAX, R_NEW_PC );
2.32 + store_spreg( R_EAX, R_PC );
2.33 + if( sh4_x86.tlb_on ) {
2.34 + call_func1(xlat_get_code_by_vma,R_EAX);
2.35 + } else {
2.36 + call_func1(xlat_get_code,R_EAX);
2.37 + }
2.38 + POP_r32(R_EBP);
2.39 + RET();
2.40 +}
2.41 +
2.42 +
2.43 #define EXIT_BLOCK_SIZE(pc) (24 + (IS_IN_ICACHE(pc)?5:CALL_FUNC1_SIZE))
2.44
2.45
3.1 --- a/src/sh4/ia64abi.h Wed Jan 16 09:37:47 2008 +0000
3.2 +++ b/src/sh4/ia64abi.h Wed Jan 16 09:39:16 2008 +0000
3.3 @@ -110,13 +110,30 @@
3.4
3.5 /**
3.6 * Exit the block with sh4r.pc already written
3.7 - * Bytes: 15
3.8 */
3.9 void exit_block_pcset( sh4addr_t pc )
3.10 {
3.11 load_imm32( R_ECX, ((pc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
3.12 ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6
3.13 - load_spreg( R_EAX, REG_OFFSET(pc) );
3.14 + load_spreg( R_EAX, R_PC );
3.15 + if( sh4_x86.tlb_on ) {
3.16 + call_func1(xlat_get_code_by_vma,R_EAX);
3.17 + } else {
3.18 + call_func1(xlat_get_code,R_EAX);
3.19 + }
3.20 + POP_r32(R_EBP);
3.21 + RET();
3.22 +}
3.23 +
3.24 +/**
3.25 + * Exit the block with sh4r.new_pc written with the target address
3.26 + */
3.27 +void exit_block_newpcset( sh4addr_t pc )
3.28 +{
3.29 + load_imm32( R_ECX, ((pc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
3.30 + ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6
3.31 + load_spreg( R_EAX, R_NEW_PC );
3.32 + store_spreg( R_EAX, R_PC );
3.33 if( sh4_x86.tlb_on ) {
3.34 call_func1(xlat_get_code_by_vma,R_EAX);
3.35 } else {
4.1 --- a/src/sh4/sh4x86.c Wed Jan 16 09:37:47 2008 +0000
4.2 +++ b/src/sh4/sh4x86.c Wed Jan 16 09:39:16 2008 +0000
4.3 @@ -42,13 +42,17 @@
4.4
4.5 #define MAX_RECOVERY_SIZE 2048
4.6
4.7 +#define DELAY_NONE 0
4.8 +#define DELAY_PC 1
4.9 +#define DELAY_PC_PR 2
4.10 +
4.11 /**
4.12 * Struct to manage internal translation state. This state is not saved -
4.13 * it is only valid between calls to sh4_translate_begin_block() and
4.14 * sh4_translate_end_block()
4.15 */
4.16 struct sh4_x86_state {
4.17 - gboolean in_delay_slot;
4.18 + int in_delay_slot;
4.19 gboolean priv_checked; /* true if we've already checked the cpu mode. */
4.20 gboolean fpuen_checked; /* true if we've already checked fpu enabled. */
4.21 gboolean branch_taken; /* true if we branched unconditionally */
4.22 @@ -342,7 +346,7 @@
4.23 #define MEM_WRITE_SIZE (CALL_FUNC2_SIZE)
4.24 #define MMU_TRANSLATE_SIZE (sh4_x86.tlb_on ? (CALL_FUNC1_SIZE + 12) : 0 )
4.25
4.26 -#define SLOTILLEGAL() JMP_exc(EXC_SLOT_ILLEGAL); sh4_x86.in_delay_slot = FALSE; return 1;
4.27 +#define SLOTILLEGAL() JMP_exc(EXC_SLOT_ILLEGAL); sh4_x86.in_delay_slot = DELAY_NONE; return 1;
4.28
4.29 /****** Import appropriate calling conventions ******/
4.30 #if SH4_TRANSLATOR == TARGET_X86_64
4.31 @@ -355,12 +359,41 @@
4.32 #endif
4.33 #endif
4.34
4.35 +/**
4.36 + * Embed a breakpoint into the generated code
4.37 + */
4.38 void sh4_translate_emit_breakpoint( sh4vma_t pc )
4.39 {
4.40 load_imm32( R_EAX, XLAT_EXIT_BREAKPOINT );
4.41 call_func1( sh4_translate_exit, R_EAX );
4.42 }
4.43 +
4.44 +/**
4.45 + * Embed a call to sh4_execute_instruction for situations that we
4.46 + * can't translate (mainly page-crossing delay slots at the moment).
4.47 + * Caller is responsible for setting new_pc.
4.48 + */
4.49 +void sh4_emulator_exit( sh4vma_t endpc )
4.50 +{
4.51 + load_imm32( R_ECX, endpc - sh4_x86.block_start_pc ); // 5
4.52 + ADD_r32_sh4r( R_ECX, R_PC );
4.53
4.54 + load_imm32( R_ECX, ((endpc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
4.55 + ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6
4.56 + load_imm32( R_ECX, sh4_x86.in_delay_slot ? 1 : 0 );
4.57 + store_spreg( R_ECX, REG_OFFSET(in_delay_slot) );
4.58 +
4.59 + call_func0( sh4_execute_instruction );
4.60 + load_imm32( R_EAX, R_PC );
4.61 + if( sh4_x86.tlb_on ) {
4.62 + call_func1(xlat_get_code_by_vma,R_EAX);
4.63 + } else {
4.64 + call_func1(xlat_get_code,R_EAX);
4.65 + }
4.66 + AND_imm8s_r32( 0xFC, R_EAX ); // 3
4.67 + POP_r32(R_EBP);
4.68 + RET();
4.69 +}
4.70
4.71 /**
4.72 * Translate a single instruction. Delayed branches are handled specially
4.73 @@ -371,7 +404,7 @@
4.74 * @return true if the instruction marks the end of a basic block
4.75 * (eg a branch or
4.76 */
4.77 -uint32_t sh4_translate_instruction( sh4addr_t pc )
4.78 +uint32_t sh4_translate_instruction( sh4vma_t pc )
4.79 {
4.80 uint32_t ir;
4.81 /* Read instruction from icache */
4.82 @@ -465,14 +498,15 @@
4.83 if( sh4_x86.in_delay_slot ) {
4.84 SLOTILLEGAL();
4.85 } else {
4.86 - load_imm32( R_ECX, pc + 4 );
4.87 - store_spreg( R_ECX, R_PR );
4.88 - ADD_sh4r_r32( REG_OFFSET(r[Rn]), R_ECX );
4.89 - store_spreg( R_ECX, REG_OFFSET(pc) );
4.90 - sh4_x86.in_delay_slot = TRUE;
4.91 + load_spreg( R_EAX, R_PC );
4.92 + ADD_imm32_r32( pc + 4 - sh4_x86.block_start_pc, R_EAX );
4.93 + store_spreg( R_EAX, R_PR );
4.94 + ADD_sh4r_r32( REG_OFFSET(r[Rn]), R_EAX );
4.95 + store_spreg( R_EAX, R_NEW_PC );
4.96 +
4.97 sh4_x86.tstate = TSTATE_NONE;
4.98 sh4_translate_instruction( pc + 2 );
4.99 - exit_block_pcset(pc+2);
4.100 + exit_block_newpcset(pc+2);
4.101 sh4_x86.branch_taken = TRUE;
4.102 return 4;
4.103 }
4.104 @@ -484,13 +518,14 @@
4.105 if( sh4_x86.in_delay_slot ) {
4.106 SLOTILLEGAL();
4.107 } else {
4.108 - load_reg( R_EAX, Rn );
4.109 - ADD_imm32_r32( pc + 4, R_EAX );
4.110 - store_spreg( R_EAX, REG_OFFSET(pc) );
4.111 - sh4_x86.in_delay_slot = TRUE;
4.112 + load_spreg( R_EAX, R_PC );
4.113 + ADD_imm32_r32( pc + 4 - sh4_x86.block_start_pc, R_EAX );
4.114 + ADD_sh4r_r32( REG_OFFSET(r[Rn]), R_EAX );
4.115 + store_spreg( R_EAX, R_NEW_PC );
4.116 + sh4_x86.in_delay_slot = DELAY_PC;
4.117 sh4_x86.tstate = TSTATE_NONE;
4.118 sh4_translate_instruction( pc + 2 );
4.119 - exit_block_pcset(pc+2);
4.120 + exit_block_newpcset(pc+2);
4.121 sh4_x86.branch_taken = TRUE;
4.122 return 4;
4.123 }
4.124 @@ -734,10 +769,10 @@
4.125 SLOTILLEGAL();
4.126 } else {
4.127 load_spreg( R_ECX, R_PR );
4.128 - store_spreg( R_ECX, REG_OFFSET(pc) );
4.129 - sh4_x86.in_delay_slot = TRUE;
4.130 + store_spreg( R_ECX, R_NEW_PC );
4.131 + sh4_x86.in_delay_slot = DELAY_PC;
4.132 sh4_translate_instruction(pc+2);
4.133 - exit_block_pcset(pc+2);
4.134 + exit_block_newpcset(pc+2);
4.135 sh4_x86.branch_taken = TRUE;
4.136 return 4;
4.137 }
4.138 @@ -748,7 +783,7 @@
4.139 check_priv();
4.140 call_func0( sh4_sleep );
4.141 sh4_x86.tstate = TSTATE_NONE;
4.142 - sh4_x86.in_delay_slot = FALSE;
4.143 + sh4_x86.in_delay_slot = DELAY_NONE;
4.144 return 2;
4.145 }
4.146 break;
4.147 @@ -759,15 +794,15 @@
4.148 } else {
4.149 check_priv();
4.150 load_spreg( R_ECX, R_SPC );
4.151 - store_spreg( R_ECX, REG_OFFSET(pc) );
4.152 + store_spreg( R_ECX, R_NEW_PC );
4.153 load_spreg( R_EAX, R_SSR );
4.154 call_func1( sh4_write_sr, R_EAX );
4.155 - sh4_x86.in_delay_slot = TRUE;
4.156 + sh4_x86.in_delay_slot = DELAY_PC;
4.157 sh4_x86.priv_checked = FALSE;
4.158 sh4_x86.fpuen_checked = FALSE;
4.159 sh4_x86.tstate = TSTATE_NONE;
4.160 sh4_translate_instruction(pc+2);
4.161 - exit_block_pcset(pc+2);
4.162 + exit_block_newpcset(pc+2);
4.163 sh4_x86.branch_taken = TRUE;
4.164 return 4;
4.165 }
4.166 @@ -1903,13 +1938,13 @@
4.167 if( sh4_x86.in_delay_slot ) {
4.168 SLOTILLEGAL();
4.169 } else {
4.170 - load_imm32( R_EAX, pc + 4 );
4.171 + load_spreg( R_EAX, R_PC );
4.172 + ADD_imm32_r32( pc + 4 - sh4_x86.block_start_pc, R_EAX );
4.173 store_spreg( R_EAX, R_PR );
4.174 load_reg( R_ECX, Rn );
4.175 - store_spreg( R_ECX, REG_OFFSET(pc) );
4.176 - sh4_x86.in_delay_slot = TRUE;
4.177 + store_spreg( R_ECX, R_NEW_PC );
4.178 sh4_translate_instruction(pc+2);
4.179 - exit_block_pcset(pc+2);
4.180 + exit_block_newpcset(pc+2);
4.181 sh4_x86.branch_taken = TRUE;
4.182 return 4;
4.183 }
4.184 @@ -1937,10 +1972,10 @@
4.185 SLOTILLEGAL();
4.186 } else {
4.187 load_reg( R_ECX, Rn );
4.188 - store_spreg( R_ECX, REG_OFFSET(pc) );
4.189 - sh4_x86.in_delay_slot = TRUE;
4.190 + store_spreg( R_ECX, R_NEW_PC );
4.191 + sh4_x86.in_delay_slot = DELAY_PC;
4.192 sh4_translate_instruction(pc+2);
4.193 - exit_block_pcset(pc+2);
4.194 + exit_block_newpcset(pc+2);
4.195 sh4_x86.branch_taken = TRUE;
4.196 return 4;
4.197 }
4.198 @@ -2408,7 +2443,7 @@
4.199 if( sh4_x86.in_delay_slot ) {
4.200 SLOTILLEGAL();
4.201 } else {
4.202 - sh4_x86.in_delay_slot = TRUE;
4.203 + sh4_x86.in_delay_slot = DELAY_PC;
4.204 if( sh4_x86.tstate == TSTATE_NONE ) {
4.205 CMP_imm8s_sh4r( 1, R_T );
4.206 sh4_x86.tstate = TSTATE_E;
4.207 @@ -2430,7 +2465,7 @@
4.208 SLOTILLEGAL();
4.209 } else {
4.210 sh4vma_t target = disp + pc + 4;
4.211 - sh4_x86.in_delay_slot = TRUE;
4.212 + sh4_x86.in_delay_slot = DELAY_PC;
4.213 if( sh4_x86.tstate == TSTATE_NONE ) {
4.214 CMP_imm8s_sh4r( 1, R_T );
4.215 sh4_x86.tstate = TSTATE_E;
4.216 @@ -2479,7 +2514,7 @@
4.217 if( sh4_x86.in_delay_slot ) {
4.218 SLOTILLEGAL();
4.219 } else {
4.220 - sh4_x86.in_delay_slot = TRUE;
4.221 + sh4_x86.in_delay_slot = DELAY_PC;
4.222 sh4_translate_instruction( pc + 2 );
4.223 exit_block_rel( disp + pc + 4, pc+4 );
4.224 sh4_x86.branch_taken = TRUE;
4.225 @@ -2493,9 +2528,10 @@
4.226 if( sh4_x86.in_delay_slot ) {
4.227 SLOTILLEGAL();
4.228 } else {
4.229 - load_imm32( R_EAX, pc + 4 );
4.230 + load_spreg( R_EAX, R_PC );
4.231 + ADD_imm32_r32( pc + 4 - sh4_x86.block_start_pc, R_EAX );
4.232 store_spreg( R_EAX, R_PR );
4.233 - sh4_x86.in_delay_slot = TRUE;
4.234 + sh4_x86.in_delay_slot = DELAY_PC;
4.235 sh4_translate_instruction( pc + 2 );
4.236 exit_block_rel( disp + pc + 4, pc+4 );
4.237 sh4_x86.branch_taken = TRUE;
4.238 @@ -2546,8 +2582,8 @@
4.239 if( sh4_x86.in_delay_slot ) {
4.240 SLOTILLEGAL();
4.241 } else {
4.242 - load_imm32( R_ECX, pc+2 );
4.243 - store_spreg( R_ECX, REG_OFFSET(pc) );
4.244 + load_imm32( R_ECX, pc+2 - sh4_x86.block_start_pc ); // 5
4.245 + ADD_r32_sh4r( R_ECX, R_PC );
4.246 load_imm32( R_EAX, imm );
4.247 call_func1( sh4_raise_trap, R_EAX );
4.248 sh4_x86.tstate = TSTATE_NONE;
4.249 @@ -3492,6 +3528,6 @@
4.250 break;
4.251 }
4.252
4.253 - sh4_x86.in_delay_slot = FALSE;
4.254 + sh4_x86.in_delay_slot = DELAY_NONE;
4.255 return 0;
4.256 }
5.1 --- a/src/sh4/sh4x86.in Wed Jan 16 09:37:47 2008 +0000
5.2 +++ b/src/sh4/sh4x86.in Wed Jan 16 09:39:16 2008 +0000
5.3 @@ -42,13 +42,17 @@
5.4
5.5 #define MAX_RECOVERY_SIZE 2048
5.6
5.7 +#define DELAY_NONE 0
5.8 +#define DELAY_PC 1
5.9 +#define DELAY_PC_PR 2
5.10 +
5.11 /**
5.12 * Struct to manage internal translation state. This state is not saved -
5.13 * it is only valid between calls to sh4_translate_begin_block() and
5.14 * sh4_translate_end_block()
5.15 */
5.16 struct sh4_x86_state {
5.17 - gboolean in_delay_slot;
5.18 + int in_delay_slot;
5.19 gboolean priv_checked; /* true if we've already checked the cpu mode. */
5.20 gboolean fpuen_checked; /* true if we've already checked fpu enabled. */
5.21 gboolean branch_taken; /* true if we branched unconditionally */
5.22 @@ -342,7 +346,7 @@
5.23 #define MEM_WRITE_SIZE (CALL_FUNC2_SIZE)
5.24 #define MMU_TRANSLATE_SIZE (sh4_x86.tlb_on ? (CALL_FUNC1_SIZE + 12) : 0 )
5.25
5.26 -#define SLOTILLEGAL() JMP_exc(EXC_SLOT_ILLEGAL); sh4_x86.in_delay_slot = FALSE; return 1;
5.27 +#define SLOTILLEGAL() JMP_exc(EXC_SLOT_ILLEGAL); sh4_x86.in_delay_slot = DELAY_NONE; return 1;
5.28
5.29 /****** Import appropriate calling conventions ******/
5.30 #if SH4_TRANSLATOR == TARGET_X86_64
5.31 @@ -355,12 +359,41 @@
5.32 #endif
5.33 #endif
5.34
5.35 +/**
5.36 + * Embed a breakpoint into the generated code
5.37 + */
5.38 void sh4_translate_emit_breakpoint( sh4vma_t pc )
5.39 {
5.40 load_imm32( R_EAX, XLAT_EXIT_BREAKPOINT );
5.41 call_func1( sh4_translate_exit, R_EAX );
5.42 }
5.43 +
5.44 +/**
5.45 + * Embed a call to sh4_execute_instruction for situations that we
5.46 + * can't translate (mainly page-crossing delay slots at the moment).
5.47 + * Caller is responsible for setting new_pc.
5.48 + */
5.49 +void sh4_emulator_exit( sh4vma_t endpc )
5.50 +{
5.51 + load_imm32( R_ECX, endpc - sh4_x86.block_start_pc ); // 5
5.52 + ADD_r32_sh4r( R_ECX, R_PC );
5.53
5.54 + load_imm32( R_ECX, ((endpc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
5.55 + ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6
5.56 + load_imm32( R_ECX, sh4_x86.in_delay_slot ? 1 : 0 );
5.57 + store_spreg( R_ECX, REG_OFFSET(in_delay_slot) );
5.58 +
5.59 + call_func0( sh4_execute_instruction );
5.60 + load_imm32( R_EAX, R_PC );
5.61 + if( sh4_x86.tlb_on ) {
5.62 + call_func1(xlat_get_code_by_vma,R_EAX);
5.63 + } else {
5.64 + call_func1(xlat_get_code,R_EAX);
5.65 + }
5.66 + AND_imm8s_r32( 0xFC, R_EAX ); // 3
5.67 + POP_r32(R_EBP);
5.68 + RET();
5.69 +}
5.70
5.71 /**
5.72 * Translate a single instruction. Delayed branches are handled specially
5.73 @@ -371,7 +404,7 @@
5.74 * @return true if the instruction marks the end of a basic block
5.75 * (eg a branch or
5.76 */
5.77 -uint32_t sh4_translate_instruction( sh4addr_t pc )
5.78 +uint32_t sh4_translate_instruction( sh4vma_t pc )
5.79 {
5.80 uint32_t ir;
5.81 /* Read instruction from icache */
5.82 @@ -1389,7 +1422,7 @@
5.83 SLOTILLEGAL();
5.84 } else {
5.85 sh4vma_t target = disp + pc + 4;
5.86 - sh4_x86.in_delay_slot = TRUE;
5.87 + sh4_x86.in_delay_slot = DELAY_PC;
5.88 if( sh4_x86.tstate == TSTATE_NONE ) {
5.89 CMP_imm8s_sh4r( 1, R_T );
5.90 sh4_x86.tstate = TSTATE_E;
5.91 @@ -1407,7 +1440,7 @@
5.92 if( sh4_x86.in_delay_slot ) {
5.93 SLOTILLEGAL();
5.94 } else {
5.95 - sh4_x86.in_delay_slot = TRUE;
5.96 + sh4_x86.in_delay_slot = DELAY_PC;
5.97 sh4_translate_instruction( pc + 2 );
5.98 exit_block_rel( disp + pc + 4, pc+4 );
5.99 sh4_x86.branch_taken = TRUE;
5.100 @@ -1418,13 +1451,14 @@
5.101 if( sh4_x86.in_delay_slot ) {
5.102 SLOTILLEGAL();
5.103 } else {
5.104 - load_reg( R_EAX, Rn );
5.105 - ADD_imm32_r32( pc + 4, R_EAX );
5.106 - store_spreg( R_EAX, REG_OFFSET(pc) );
5.107 - sh4_x86.in_delay_slot = TRUE;
5.108 + load_spreg( R_EAX, R_PC );
5.109 + ADD_imm32_r32( pc + 4 - sh4_x86.block_start_pc, R_EAX );
5.110 + ADD_sh4r_r32( REG_OFFSET(r[Rn]), R_EAX );
5.111 + store_spreg( R_EAX, R_NEW_PC );
5.112 + sh4_x86.in_delay_slot = DELAY_PC;
5.113 sh4_x86.tstate = TSTATE_NONE;
5.114 sh4_translate_instruction( pc + 2 );
5.115 - exit_block_pcset(pc+2);
5.116 + exit_block_newpcset(pc+2);
5.117 sh4_x86.branch_taken = TRUE;
5.118 return 4;
5.119 }
5.120 @@ -1433,9 +1467,10 @@
5.121 if( sh4_x86.in_delay_slot ) {
5.122 SLOTILLEGAL();
5.123 } else {
5.124 - load_imm32( R_EAX, pc + 4 );
5.125 + load_spreg( R_EAX, R_PC );
5.126 + ADD_imm32_r32( pc + 4 - sh4_x86.block_start_pc, R_EAX );
5.127 store_spreg( R_EAX, R_PR );
5.128 - sh4_x86.in_delay_slot = TRUE;
5.129 + sh4_x86.in_delay_slot = DELAY_PC;
5.130 sh4_translate_instruction( pc + 2 );
5.131 exit_block_rel( disp + pc + 4, pc+4 );
5.132 sh4_x86.branch_taken = TRUE;
5.133 @@ -1446,14 +1481,15 @@
5.134 if( sh4_x86.in_delay_slot ) {
5.135 SLOTILLEGAL();
5.136 } else {
5.137 - load_imm32( R_ECX, pc + 4 );
5.138 - store_spreg( R_ECX, R_PR );
5.139 - ADD_sh4r_r32( REG_OFFSET(r[Rn]), R_ECX );
5.140 - store_spreg( R_ECX, REG_OFFSET(pc) );
5.141 - sh4_x86.in_delay_slot = TRUE;
5.142 + load_spreg( R_EAX, R_PC );
5.143 + ADD_imm32_r32( pc + 4 - sh4_x86.block_start_pc, R_EAX );
5.144 + store_spreg( R_EAX, R_PR );
5.145 + ADD_sh4r_r32( REG_OFFSET(r[Rn]), R_EAX );
5.146 + store_spreg( R_EAX, R_NEW_PC );
5.147 +
5.148 sh4_x86.tstate = TSTATE_NONE;
5.149 sh4_translate_instruction( pc + 2 );
5.150 - exit_block_pcset(pc+2);
5.151 + exit_block_newpcset(pc+2);
5.152 sh4_x86.branch_taken = TRUE;
5.153 return 4;
5.154 }
5.155 @@ -1473,7 +1509,7 @@
5.156 if( sh4_x86.in_delay_slot ) {
5.157 SLOTILLEGAL();
5.158 } else {
5.159 - sh4_x86.in_delay_slot = TRUE;
5.160 + sh4_x86.in_delay_slot = DELAY_PC;
5.161 if( sh4_x86.tstate == TSTATE_NONE ) {
5.162 CMP_imm8s_sh4r( 1, R_T );
5.163 sh4_x86.tstate = TSTATE_E;
5.164 @@ -1492,10 +1528,10 @@
5.165 SLOTILLEGAL();
5.166 } else {
5.167 load_reg( R_ECX, Rn );
5.168 - store_spreg( R_ECX, REG_OFFSET(pc) );
5.169 - sh4_x86.in_delay_slot = TRUE;
5.170 + store_spreg( R_ECX, R_NEW_PC );
5.171 + sh4_x86.in_delay_slot = DELAY_PC;
5.172 sh4_translate_instruction(pc+2);
5.173 - exit_block_pcset(pc+2);
5.174 + exit_block_newpcset(pc+2);
5.175 sh4_x86.branch_taken = TRUE;
5.176 return 4;
5.177 }
5.178 @@ -1504,13 +1540,13 @@
5.179 if( sh4_x86.in_delay_slot ) {
5.180 SLOTILLEGAL();
5.181 } else {
5.182 - load_imm32( R_EAX, pc + 4 );
5.183 + load_spreg( R_EAX, R_PC );
5.184 + ADD_imm32_r32( pc + 4 - sh4_x86.block_start_pc, R_EAX );
5.185 store_spreg( R_EAX, R_PR );
5.186 load_reg( R_ECX, Rn );
5.187 - store_spreg( R_ECX, REG_OFFSET(pc) );
5.188 - sh4_x86.in_delay_slot = TRUE;
5.189 + store_spreg( R_ECX, R_NEW_PC );
5.190 sh4_translate_instruction(pc+2);
5.191 - exit_block_pcset(pc+2);
5.192 + exit_block_newpcset(pc+2);
5.193 sh4_x86.branch_taken = TRUE;
5.194 return 4;
5.195 }
5.196 @@ -1521,15 +1557,15 @@
5.197 } else {
5.198 check_priv();
5.199 load_spreg( R_ECX, R_SPC );
5.200 - store_spreg( R_ECX, REG_OFFSET(pc) );
5.201 + store_spreg( R_ECX, R_NEW_PC );
5.202 load_spreg( R_EAX, R_SSR );
5.203 call_func1( sh4_write_sr, R_EAX );
5.204 - sh4_x86.in_delay_slot = TRUE;
5.205 + sh4_x86.in_delay_slot = DELAY_PC;
5.206 sh4_x86.priv_checked = FALSE;
5.207 sh4_x86.fpuen_checked = FALSE;
5.208 sh4_x86.tstate = TSTATE_NONE;
5.209 sh4_translate_instruction(pc+2);
5.210 - exit_block_pcset(pc+2);
5.211 + exit_block_newpcset(pc+2);
5.212 sh4_x86.branch_taken = TRUE;
5.213 return 4;
5.214 }
5.215 @@ -1539,10 +1575,10 @@
5.216 SLOTILLEGAL();
5.217 } else {
5.218 load_spreg( R_ECX, R_PR );
5.219 - store_spreg( R_ECX, REG_OFFSET(pc) );
5.220 - sh4_x86.in_delay_slot = TRUE;
5.221 + store_spreg( R_ECX, R_NEW_PC );
5.222 + sh4_x86.in_delay_slot = DELAY_PC;
5.223 sh4_translate_instruction(pc+2);
5.224 - exit_block_pcset(pc+2);
5.225 + exit_block_newpcset(pc+2);
5.226 sh4_x86.branch_taken = TRUE;
5.227 return 4;
5.228 }
5.229 @@ -1551,8 +1587,8 @@
5.230 if( sh4_x86.in_delay_slot ) {
5.231 SLOTILLEGAL();
5.232 } else {
5.233 - load_imm32( R_ECX, pc+2 );
5.234 - store_spreg( R_ECX, REG_OFFSET(pc) );
5.235 + load_imm32( R_ECX, pc+2 - sh4_x86.block_start_pc ); // 5
5.236 + ADD_r32_sh4r( R_ECX, R_PC );
5.237 load_imm32( R_EAX, imm );
5.238 call_func1( sh4_raise_trap, R_EAX );
5.239 sh4_x86.tstate = TSTATE_NONE;
5.240 @@ -2451,7 +2487,7 @@
5.241 check_priv();
5.242 call_func0( sh4_sleep );
5.243 sh4_x86.tstate = TSTATE_NONE;
5.244 - sh4_x86.in_delay_slot = FALSE;
5.245 + sh4_x86.in_delay_slot = DELAY_NONE;
5.246 return 2;
5.247 :}
5.248 STC SR, Rn {:
5.249 @@ -2662,6 +2698,6 @@
5.250
5.251 NOP {: /* Do nothing. Well, we could emit an 0x90, but what would really be the point? */ :}
5.252 %%
5.253 - sh4_x86.in_delay_slot = FALSE;
5.254 + sh4_x86.in_delay_slot = DELAY_NONE;
5.255 return 0;
5.256 }
6.1 --- a/src/sh4/x86op.h Wed Jan 16 09:37:47 2008 +0000
6.2 +++ b/src/sh4/x86op.h Wed Jan 16 09:39:16 2008 +0000
6.3 @@ -100,6 +100,7 @@
6.4 #define R_MACH REG_OFFSET(mac)+4
6.5 #define R_MACL REG_OFFSET(mac)
6.6 #define R_PC REG_OFFSET(pc)
6.7 +#define R_NEW_PC REG_OFFSET(new_pc)
6.8 #define R_PR REG_OFFSET(pr)
6.9 #define R_SGR REG_OFFSET(sgr)
6.10 #define R_FPUL REG_OFFSET(fpul)
.