1.1 --- a/src/sh4/sh4x86.in Tue Nov 20 08:31:34 2007 +0000
1.2 +++ b/src/sh4/sh4x86.in Wed Nov 21 11:40:15 2007 +0000
1.4 gboolean fpuen_checked; /* true if we've already checked fpu enabled. */
1.5 gboolean branch_taken; /* true if we branched unconditionally */
1.6 uint32_t block_start_pc;
1.7 + uint32_t stack_posn; /* Trace stack height for alignment purposes */
1.10 /* Allocated memory for the (block-wide) back-patch list */
1.11 @@ -264,287 +265,6 @@
1.12 OP(0xDD); OP(0x58 + bankreg); OP(frm<<2); // FST.D [bankreg + frm*4]
1.15 -#if SH4_TRANSLATOR == TARGET_X86_64
1.16 -/* X86-64 has different calling conventions... */
1.18 -#define load_ptr( reg, ptr ) load_imm64( reg, (uint64_t)ptr );
1.21 - * Note: clobbers EAX to make the indirect call - this isn't usually
1.22 - * a problem since the callee will usually clobber it anyway.
1.25 -#define CALL_FUNC0_SIZE 12
1.26 -static inline void call_func0( void *ptr )
1.28 - load_imm64(R_EAX, (uint64_t)ptr);
1.32 -#define CALL_FUNC1_SIZE 14
1.33 -static inline void call_func1( void *ptr, int arg1 )
1.35 - MOV_r32_r32(arg1, R_EDI);
1.39 -#define CALL_FUNC2_SIZE 16
1.40 -static inline void call_func2( void *ptr, int arg1, int arg2 )
1.42 - MOV_r32_r32(arg1, R_EDI);
1.43 - MOV_r32_r32(arg2, R_ESI);
1.47 -#define MEM_WRITE_DOUBLE_SIZE 39
1.49 - * Write a double (64-bit) value into memory, with the first word in arg2a, and
1.50 - * the second in arg2b
1.52 -static inline void MEM_WRITE_DOUBLE( int addr, int arg2a, int arg2b )
1.55 - MOV_r32_r32( addr, R_EDI );
1.56 - MOV_r32_r32( arg2b, R_ESI );
1.57 - REXW(); SHL_imm8_r32( 32, R_ESI );
1.58 - REXW(); MOVZX_r16_r32( arg2a, arg2a );
1.59 - REXW(); OR_r32_r32( arg2a, R_ESI );
1.60 - call_func0(sh4_write_quad);
1.64 - call_func2(sh4_write_long, addr, arg2a);
1.67 - ADD_imm8s_r32(4, addr);
1.68 - call_func2(sh4_write_long, addr, arg2b);
1.71 -#define MEM_READ_DOUBLE_SIZE 35
1.73 - * Read a double (64-bit) value from memory, writing the first word into arg2a
1.74 - * and the second into arg2b. The addr must not be in EAX
1.76 -static inline void MEM_READ_DOUBLE( int addr, int arg2a, int arg2b )
1.79 - MOV_r32_r32( addr, R_EDI );
1.80 - call_func0(sh4_read_quad);
1.81 - REXW(); MOV_r32_r32( R_EAX, arg2a );
1.82 - REXW(); MOV_r32_r32( R_EAX, arg2b );
1.83 - REXW(); SHR_imm8_r32( 32, arg2b );
1.86 - call_func1(sh4_read_long, addr);
1.89 - ADD_imm8s_r32(4, R_EDI);
1.90 - call_func0(sh4_read_long);
1.91 - MOV_r32_r32(R_EAX, arg2b);
1.95 -#define EXIT_BLOCK_SIZE 35
1.97 - * Exit the block to an absolute PC
1.99 -void exit_block( sh4addr_t pc, sh4addr_t endpc )
1.101 - load_imm32( R_ECX, pc ); // 5
1.102 - store_spreg( R_ECX, REG_OFFSET(pc) ); // 3
1.103 - REXW(); MOV_moff32_EAX( xlat_get_lut_entry(pc) );
1.104 - REXW(); AND_imm8s_r32( 0xFC, R_EAX ); // 3
1.105 - load_imm32( R_ECX, ((endpc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
1.106 - ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6
1.113 - * Write the block trailer (exception handling block)
1.115 -void sh4_translate_end_block( sh4addr_t pc ) {
1.116 - if( sh4_x86.branch_taken == FALSE ) {
1.117 - // Didn't exit unconditionally already, so write the termination here
1.118 - exit_block( pc, pc );
1.120 - if( sh4_x86.backpatch_posn != 0 ) {
1.121 - uint8_t *end_ptr = xlat_output;
1.122 - // Exception termination. Jump block for various exception codes:
1.123 - load_imm32( R_EDI, EXC_DATA_ADDR_READ );
1.124 - JMP_rel8( 33, target1 );
1.125 - load_imm32( R_EDI, EXC_DATA_ADDR_WRITE );
1.126 - JMP_rel8( 26, target2 );
1.127 - load_imm32( R_EDI, EXC_ILLEGAL );
1.128 - JMP_rel8( 19, target3 );
1.129 - load_imm32( R_EDI, EXC_SLOT_ILLEGAL );
1.130 - JMP_rel8( 12, target4 );
1.131 - load_imm32( R_EDI, EXC_FPU_DISABLED );
1.132 - JMP_rel8( 5, target5 );
1.133 - load_imm32( R_EDI, EXC_SLOT_FPU_DISABLED );
1.135 - JMP_TARGET(target1);
1.136 - JMP_TARGET(target2);
1.137 - JMP_TARGET(target3);
1.138 - JMP_TARGET(target4);
1.139 - JMP_TARGET(target5);
1.140 - // Raise exception
1.141 - load_spreg( R_ECX, REG_OFFSET(pc) );
1.142 - ADD_r32_r32( R_EDX, R_ECX );
1.143 - ADD_r32_r32( R_EDX, R_ECX );
1.144 - store_spreg( R_ECX, REG_OFFSET(pc) );
1.145 - MOV_moff32_EAX( &sh4_cpu_period );
1.146 - MUL_r32( R_EDX );
1.147 - ADD_r32_sh4r( R_EAX, REG_OFFSET(slice_cycle) );
1.149 - call_func0( sh4_raise_exception );
1.150 - load_spreg( R_EAX, REG_OFFSET(pc) );
1.151 - call_func1(xlat_get_code,R_EAX);
1.155 - sh4_x86_do_backpatch( end_ptr );
1.159 -#else /* SH4_TRANSLATOR == TARGET_X86 */
1.161 -#define load_ptr( reg, ptr ) load_imm32( reg, (uint32_t)ptr );
1.164 - * Note: clobbers EAX to make the indirect call - this isn't usually
1.165 - * a problem since the callee will usually clobber it anyway.
1.167 -#define CALL_FUNC0_SIZE 7
1.168 -static inline void call_func0( void *ptr )
1.170 - load_imm32(R_EAX, (uint32_t)ptr);
1.174 -#define CALL_FUNC1_SIZE 11
1.175 -static inline void call_func1( void *ptr, int arg1 )
1.179 - ADD_imm8s_r32( 4, R_ESP );
1.182 -#define CALL_FUNC2_SIZE 12
1.183 -static inline void call_func2( void *ptr, int arg1, int arg2 )
1.188 - ADD_imm8s_r32( 8, R_ESP );
1.192 - * Write a double (64-bit) value into memory, with the first word in arg2a, and
1.193 - * the second in arg2b
1.196 -#define MEM_WRITE_DOUBLE_SIZE 30
1.197 -static inline void MEM_WRITE_DOUBLE( int addr, int arg2a, int arg2b )
1.199 - ADD_imm8s_r32( 4, addr );
1.202 - ADD_imm8s_r32( -4, addr );
1.205 - call_func0(sh4_write_long);
1.206 - ADD_imm8s_r32( 8, R_ESP );
1.207 - call_func0(sh4_write_long);
1.208 - ADD_imm8s_r32( 8, R_ESP );
1.212 - * Read a double (64-bit) value from memory, writing the first word into arg2a
1.213 - * and the second into arg2b. The addr must not be in EAX
1.216 -#define MEM_READ_DOUBLE_SIZE 27
1.217 -static inline void MEM_READ_DOUBLE( int addr, int arg2a, int arg2b )
1.220 - call_func0(sh4_read_long);
1.223 - ADD_imm8s_r32( 4, addr );
1.225 - call_func0(sh4_read_long);
1.226 - ADD_imm8s_r32( 4, R_ESP );
1.227 - MOV_r32_r32( R_EAX, arg2b );
1.231 -#define EXIT_BLOCK_SIZE 29
1.233 - * Exit the block to an absolute PC
1.235 -void exit_block( sh4addr_t pc, sh4addr_t endpc )
1.237 - load_imm32( R_ECX, pc ); // 5
1.238 - store_spreg( R_ECX, REG_OFFSET(pc) ); // 3
1.239 - MOV_moff32_EAX( xlat_get_lut_entry(pc) ); // 5
1.240 - AND_imm8s_r32( 0xFC, R_EAX ); // 3
1.241 - load_imm32( R_ECX, ((endpc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
1.242 - ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6
1.248 - * Write the block trailer (exception handling block)
1.250 -void sh4_translate_end_block( sh4addr_t pc ) {
1.251 - if( sh4_x86.branch_taken == FALSE ) {
1.252 - // Didn't exit unconditionally already, so write the termination here
1.253 - exit_block( pc, pc );
1.255 - if( sh4_x86.backpatch_posn != 0 ) {
1.256 - uint8_t *end_ptr = xlat_output;
1.257 - // Exception termination. Jump block for various exception codes:
1.258 - PUSH_imm32( EXC_DATA_ADDR_READ );
1.259 - JMP_rel8( 33, target1 );
1.260 - PUSH_imm32( EXC_DATA_ADDR_WRITE );
1.261 - JMP_rel8( 26, target2 );
1.262 - PUSH_imm32( EXC_ILLEGAL );
1.263 - JMP_rel8( 19, target3 );
1.264 - PUSH_imm32( EXC_SLOT_ILLEGAL );
1.265 - JMP_rel8( 12, target4 );
1.266 - PUSH_imm32( EXC_FPU_DISABLED );
1.267 - JMP_rel8( 5, target5 );
1.268 - PUSH_imm32( EXC_SLOT_FPU_DISABLED );
1.270 - JMP_TARGET(target1);
1.271 - JMP_TARGET(target2);
1.272 - JMP_TARGET(target3);
1.273 - JMP_TARGET(target4);
1.274 - JMP_TARGET(target5);
1.275 - // Raise exception
1.276 - load_spreg( R_ECX, REG_OFFSET(pc) );
1.277 - ADD_r32_r32( R_EDX, R_ECX );
1.278 - ADD_r32_r32( R_EDX, R_ECX );
1.279 - store_spreg( R_ECX, REG_OFFSET(pc) );
1.280 - MOV_moff32_EAX( &sh4_cpu_period );
1.281 - MUL_r32( R_EDX );
1.282 - ADD_r32_sh4r( R_EAX, REG_OFFSET(slice_cycle) );
1.284 - call_func0( sh4_raise_exception );
1.285 - ADD_imm8s_r32( 4, R_ESP );
1.286 - load_spreg( R_EAX, REG_OFFSET(pc) );
1.287 - call_func1(xlat_get_code,R_EAX);
1.291 - sh4_x86_do_backpatch( end_ptr );
1.296 /* Exception checks - Note that all exception checks will clobber EAX */
1.297 #define precheck() load_imm32(R_EDX, (pc-sh4_x86.block_start_pc-(sh4_x86.in_delay_slot?2:0))>>1)
1.299 @@ -638,44 +358,21 @@
1.301 #define SLOTILLEGAL() precheck(); JMP_exit(EXIT_SLOT_ILLEGAL); sh4_x86.in_delay_slot = FALSE; return 1;
1.306 - * Emit the 'start of block' assembly. Sets up the stack frame and save
1.307 - * SI/DI as required
1.309 -void sh4_translate_begin_block( sh4addr_t pc )
1.312 - /* mov &sh4r, ebp */
1.313 - load_ptr( R_EBP, &sh4r );
1.315 - sh4_x86.in_delay_slot = FALSE;
1.316 - sh4_x86.priv_checked = FALSE;
1.317 - sh4_x86.fpuen_checked = FALSE;
1.318 - sh4_x86.branch_taken = FALSE;
1.319 - sh4_x86.backpatch_posn = 0;
1.320 - sh4_x86.block_start_pc = pc;
1.321 - sh4_x86.tstate = TSTATE_NONE;
1.325 - * Exit the block with sh4r.pc already written
1.328 -void exit_block_pcset( pc )
1.330 - load_imm32( R_ECX, ((pc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
1.331 - ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6
1.332 - load_spreg( R_EAX, REG_OFFSET(pc) );
1.333 - call_func1(xlat_get_code,R_EAX);
1.338 extern uint16_t *sh4_icache;
1.339 extern uint32_t sh4_icache_addr;
1.341 +/****** Import appropriate calling conventions ******/
1.342 +#if SH4_TRANSLATOR == TARGET_X86_64
1.343 +#include "sh4/ia64abi.h"
1.344 +#else /* SH4_TRANSLATOR == TARGET_X86 */
1.345 +#ifdef APPLE_BUILD
1.346 +#include "sh4/ia32mac.h"
1.348 +#include "sh4/ia32abi.h"
1.354 * Translate a single instruction. Delayed branches are handled specially
1.355 * by translating both branch and delayed instruction as a single unit (as