Search
lxdream.org :: lxdream/src/sh4/sh4x86.in :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4x86.in
changeset 539:75f3e594d4a7
prev533:9764673fd4a5
next547:d6e00ffc4adc
author nkeynes
date Wed Nov 21 11:40:15 2007 +0000 (12 years ago)
permissions -rw-r--r--
last change Add support for the darwin ABI
file annotate diff log raw
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.3 @@ -45,6 +45,7 @@
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.8 int tstate;
1.9
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.13 }
1.14
1.15 -#if SH4_TRANSLATOR == TARGET_X86_64
1.16 -/* X86-64 has different calling conventions... */
1.17 -
1.18 -#define load_ptr( reg, ptr ) load_imm64( reg, (uint64_t)ptr );
1.19 -
1.20 -/**
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.23 - * Size: 12 bytes
1.24 - */
1.25 -#define CALL_FUNC0_SIZE 12
1.26 -static inline void call_func0( void *ptr )
1.27 -{
1.28 - load_imm64(R_EAX, (uint64_t)ptr);
1.29 - CALL_r32(R_EAX);
1.30 -}
1.31 -
1.32 -#define CALL_FUNC1_SIZE 14
1.33 -static inline void call_func1( void *ptr, int arg1 )
1.34 -{
1.35 - MOV_r32_r32(arg1, R_EDI);
1.36 - call_func0(ptr);
1.37 -}
1.38 -
1.39 -#define CALL_FUNC2_SIZE 16
1.40 -static inline void call_func2( void *ptr, int arg1, int arg2 )
1.41 -{
1.42 - MOV_r32_r32(arg1, R_EDI);
1.43 - MOV_r32_r32(arg2, R_ESI);
1.44 - call_func0(ptr);
1.45 -}
1.46 -
1.47 -#define MEM_WRITE_DOUBLE_SIZE 39
1.48 -/**
1.49 - * Write a double (64-bit) value into memory, with the first word in arg2a, and
1.50 - * the second in arg2b
1.51 - */
1.52 -static inline void MEM_WRITE_DOUBLE( int addr, int arg2a, int arg2b )
1.53 -{
1.54 -/*
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.61 -*/
1.62 - PUSH_r32(arg2b);
1.63 - PUSH_r32(addr);
1.64 - call_func2(sh4_write_long, addr, arg2a);
1.65 - POP_r32(addr);
1.66 - POP_r32(arg2b);
1.67 - ADD_imm8s_r32(4, addr);
1.68 - call_func2(sh4_write_long, addr, arg2b);
1.69 -}
1.70 -
1.71 -#define MEM_READ_DOUBLE_SIZE 35
1.72 -/**
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.75 - */
1.76 -static inline void MEM_READ_DOUBLE( int addr, int arg2a, int arg2b )
1.77 -{
1.78 -/*
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.84 -*/
1.85 - PUSH_r32(addr);
1.86 - call_func1(sh4_read_long, addr);
1.87 - POP_r32(R_EDI);
1.88 - PUSH_r32(R_EAX);
1.89 - ADD_imm8s_r32(4, R_EDI);
1.90 - call_func0(sh4_read_long);
1.91 - MOV_r32_r32(R_EAX, arg2b);
1.92 - POP_r32(arg2a);
1.93 -}
1.94 -
1.95 -#define EXIT_BLOCK_SIZE 35
1.96 -/**
1.97 - * Exit the block to an absolute PC
1.98 - */
1.99 -void exit_block( sh4addr_t pc, sh4addr_t endpc )
1.100 -{
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.107 - POP_r32(R_EBP);
1.108 - RET();
1.109 -}
1.110 -
1.111 -
1.112 -/**
1.113 - * Write the block trailer (exception handling block)
1.114 - */
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.119 - }
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.134 - // target
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.148 -
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.152 - POP_r32(R_EBP);
1.153 - RET();
1.154 -
1.155 - sh4_x86_do_backpatch( end_ptr );
1.156 - }
1.157 -}
1.158 -
1.159 -#else /* SH4_TRANSLATOR == TARGET_X86 */
1.160 -
1.161 -#define load_ptr( reg, ptr ) load_imm32( reg, (uint32_t)ptr );
1.162 -
1.163 -/**
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.166 - */
1.167 -#define CALL_FUNC0_SIZE 7
1.168 -static inline void call_func0( void *ptr )
1.169 -{
1.170 - load_imm32(R_EAX, (uint32_t)ptr);
1.171 - CALL_r32(R_EAX);
1.172 -}
1.173 -
1.174 -#define CALL_FUNC1_SIZE 11
1.175 -static inline void call_func1( void *ptr, int arg1 )
1.176 -{
1.177 - PUSH_r32(arg1);
1.178 - call_func0(ptr);
1.179 - ADD_imm8s_r32( 4, R_ESP );
1.180 -}
1.181 -
1.182 -#define CALL_FUNC2_SIZE 12
1.183 -static inline void call_func2( void *ptr, int arg1, int arg2 )
1.184 -{
1.185 - PUSH_r32(arg2);
1.186 - PUSH_r32(arg1);
1.187 - call_func0(ptr);
1.188 - ADD_imm8s_r32( 8, R_ESP );
1.189 -}
1.190 -
1.191 -/**
1.192 - * Write a double (64-bit) value into memory, with the first word in arg2a, and
1.193 - * the second in arg2b
1.194 - * NB: 30 bytes
1.195 - */
1.196 -#define MEM_WRITE_DOUBLE_SIZE 30
1.197 -static inline void MEM_WRITE_DOUBLE( int addr, int arg2a, int arg2b )
1.198 -{
1.199 - ADD_imm8s_r32( 4, addr );
1.200 - PUSH_r32(arg2b);
1.201 - PUSH_r32(addr);
1.202 - ADD_imm8s_r32( -4, addr );
1.203 - PUSH_r32(arg2a);
1.204 - PUSH_r32(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.209 -}
1.210 -
1.211 -/**
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.214 - * NB: 27 bytes
1.215 - */
1.216 -#define MEM_READ_DOUBLE_SIZE 27
1.217 -static inline void MEM_READ_DOUBLE( int addr, int arg2a, int arg2b )
1.218 -{
1.219 - PUSH_r32(addr);
1.220 - call_func0(sh4_read_long);
1.221 - POP_r32(addr);
1.222 - PUSH_r32(R_EAX);
1.223 - ADD_imm8s_r32( 4, addr );
1.224 - PUSH_r32(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.228 - POP_r32(arg2a);
1.229 -}
1.230 -
1.231 -#define EXIT_BLOCK_SIZE 29
1.232 -/**
1.233 - * Exit the block to an absolute PC
1.234 - */
1.235 -void exit_block( sh4addr_t pc, sh4addr_t endpc )
1.236 -{
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.243 - POP_r32(R_EBP);
1.244 - RET();
1.245 -}
1.246 -
1.247 -/**
1.248 - * Write the block trailer (exception handling block)
1.249 - */
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.254 - }
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.269 - // target
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.283 -
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.288 - POP_r32(R_EBP);
1.289 - RET();
1.290 -
1.291 - sh4_x86_do_backpatch( end_ptr );
1.292 - }
1.293 -}
1.294 -#endif
1.295 -
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.298
1.299 @@ -638,44 +358,21 @@
1.300
1.301 #define SLOTILLEGAL() precheck(); JMP_exit(EXIT_SLOT_ILLEGAL); sh4_x86.in_delay_slot = FALSE; return 1;
1.302
1.303 -
1.304 -
1.305 -/**
1.306 - * Emit the 'start of block' assembly. Sets up the stack frame and save
1.307 - * SI/DI as required
1.308 - */
1.309 -void sh4_translate_begin_block( sh4addr_t pc )
1.310 -{
1.311 - PUSH_r32(R_EBP);
1.312 - /* mov &sh4r, ebp */
1.313 - load_ptr( R_EBP, &sh4r );
1.314 -
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.322 -}
1.323 -
1.324 -/**
1.325 - * Exit the block with sh4r.pc already written
1.326 - * Bytes: 15
1.327 - */
1.328 -void exit_block_pcset( pc )
1.329 -{
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.334 - POP_r32(R_EBP);
1.335 - RET();
1.336 -}
1.337 -
1.338 extern uint16_t *sh4_icache;
1.339 extern uint32_t sh4_icache_addr;
1.340
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.347 +#else
1.348 +#include "sh4/ia32abi.h"
1.349 +#endif
1.350 +#endif
1.351 +
1.352 +
1.353 /**
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
.