filename | src/sh4/ia32abi.h |
changeset | 991:60c7fab9c880 |
prev | 968:6fb1481859a4 |
author | nkeynes |
date | Wed Mar 04 23:12:21 2009 +0000 (15 years ago) |
permissions | -rw-r--r-- |
last change | Move xltcache to xlat/ src directory Commit new and improved x86 opcode file - cleaned up and added support for amd64 extended registers |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
3 *
4 * Provides the implementation for the ia32 ABI variant
5 * (eg prologue, epilogue, and calling conventions). Stack frame is
6 * aligned on 16-byte boundaries for the benefit of OS X (which
7 * requires it).
8 *
9 * Copyright (c) 2007 Nathan Keynes.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 */
22 #ifndef lxdream_ia32mac_H
23 #define lxdream_ia32mac_H 1
25 #define load_ptr( reg, ptr ) load_imm32( reg, (uint32_t)ptr );
27 static inline void decode_address( int addr_reg )
28 {
29 uintptr_t base = (sh4r.xlat_sh4_mode&SR_MD) ? (uintptr_t)sh4_address_space : (uintptr_t)sh4_user_address_space;
30 MOVL_r32_r32( addr_reg, REG_ECX );
31 SHRL_imm_r32( 12, REG_ECX );
32 MOVP_sib_rptr( 2, REG_ECX, -1, base, REG_ECX );
33 }
35 /**
36 * Note: clobbers EAX to make the indirect call - this isn't usually
37 * a problem since the callee will usually clobber it anyway.
38 */
39 static inline void call_func0( void *ptr )
40 {
41 load_imm32(REG_ECX, (uint32_t)ptr);
42 CALL_r32(REG_ECX);
43 }
45 #ifdef HAVE_FASTCALL
46 static inline void call_func1( void *ptr, int arg1 )
47 {
48 if( arg1 != REG_EAX ) {
49 MOVL_r32_r32( arg1, REG_EAX );
50 }
51 MOVP_immptr_rptr((uintptr_t)ptr, REG_ECX);
52 CALL_r32(REG_ECX);
53 }
55 static inline void call_func1_r32( int addr_reg, int arg1 )
56 {
57 if( arg1 != REG_EAX ) {
58 MOVL_r32_r32( arg1, REG_EAX );
59 }
60 CALL_r32(addr_reg);
61 }
63 static inline void call_func1_r32disp8( int preg, uint32_t disp8, int arg1 )
64 {
65 if( arg1 != REG_EAX ) {
66 MOVL_r32_r32( arg1, REG_EAX );
67 }
68 CALL_r32disp(preg, disp8);
69 }
71 static inline void call_func1_r32disp8_exc( int preg, uint32_t disp8, int arg1, int pc )
72 {
73 if( arg1 != REG_EAX ) {
74 MOVL_r32_r32( arg1, REG_EAX );
75 }
76 MOVP_immptr_rptr(0,REG_EDX);
77 sh4_x86_add_backpatch(xlat_output, pc, -2);
78 CALL_r32disp(preg, disp8);
79 }
81 static inline void call_func2( void *ptr, int arg1, int arg2 )
82 {
83 if( arg2 != REG_EDX ) {
84 MOVL_r32_r32( arg2, REG_EDX );
85 }
86 if( arg1 != REG_EAX ) {
87 MOVL_r32_r32( arg1, REG_EAX );
88 }
89 MOVP_immptr_rptr((uint32_t)ptr, REG_ECX);
90 CALL_r32(REG_ECX);
91 }
93 static inline void call_func2_r32( int addr_reg, int arg1, int arg2 )
94 {
95 if( arg2 != REG_EDX ) {
96 MOVL_r32_r32( arg2, REG_EDX );
97 }
98 if( arg1 != REG_EAX ) {
99 MOVL_r32_r32( arg1, REG_EAX );
100 }
101 CALL_r32(addr_reg);
102 }
104 static inline void call_func2_r32disp8( int preg, uint32_t disp8, int arg1, int arg2 )
105 {
106 if( arg2 != REG_EDX ) {
107 MOVL_r32_r32( arg2, REG_EDX );
108 }
109 if( arg1 != REG_EAX ) {
110 MOVL_r32_r32( arg1, REG_EAX );
111 }
112 CALL_r32disp(preg, disp8);
113 }
115 static inline void call_func2_r32disp8_exc( int preg, uint32_t disp8, int arg1, int arg2, int pc )
116 {
117 if( arg2 != REG_EDX ) {
118 MOVL_r32_r32( arg2, REG_EDX );
119 }
120 if( arg1 != REG_EAX ) {
121 MOVL_r32_r32( arg1, REG_EAX );
122 }
123 MOVL_imm32_rspdisp(0,0);
124 sh4_x86_add_backpatch(xlat_output, pc, -2);
125 CALL_r32disp(preg, disp8);
126 }
130 static inline void call_func1_exc( void *ptr, int arg1, int pc )
131 {
132 if( arg1 != REG_EAX ) {
133 MOVL_r32_r32( arg1, REG_EAX );
134 }
135 MOVP_immptr_rptr(0,REG_EDX);
136 sh4_x86_add_backpatch(xlat_output, pc, -2);
137 MOVP_immptr_rptr((uint32_t)ptr, REG_ECX);
138 CALL_r32(REG_ECX);
139 }
141 static inline void call_func2_exc( void *ptr, int arg1, int arg2, int pc )
142 {
143 if( arg2 != REG_EDX ) {
144 MOVL_r32_r32( arg2, REG_EDX );
145 }
146 if( arg1 != REG_EAX ) {
147 MOVL_r32_r32( arg1, REG_EAX );
148 }
149 MOVL_imm32_rspdisp(0,0);
150 sh4_x86_add_backpatch(xlat_output, pc, -2);
151 MOVP_immptr_rptr((uint32_t)ptr, REG_ECX);
152 CALL_r32(REG_ECX);
153 }
155 #else
156 static inline void call_func1( void *ptr, int arg1 )
157 {
158 SUBL_imms_r32( 12, REG_ESP );
159 PUSH_r32(arg1);
160 MOVP_immptr_rptr((uint32_t)ptr, REG_ECX);
161 CALL_r32(REG_ECX);
162 ADDL_imms_r32( 16, REG_ESP );
163 }
165 static inline void call_func2( void *ptr, int arg1, int arg2 )
166 {
167 SUBL_imms_r32( 8, REG_ESP );
168 PUSH_r32(arg2);
169 PUSH_r32(arg1);
170 MOVP_immptr_rptr((uint32_t)ptr, REG_ECX);
171 CALL_r32(REG_ECX);
172 ADDL_imms_r32( 16, REG_ESP );
173 }
175 #endif
177 /**
178 * Emit the 'start of block' assembly. Sets up the stack frame and save
179 * SI/DI as required
180 * Allocates 8 bytes for local variables, which also has the convenient
181 * side-effect of aligning the stack.
182 */
183 void enter_block( )
184 {
185 PUSH_r32(REG_EBP);
186 load_ptr( REG_EBP, ((uint8_t *)&sh4r) + 128 );
187 SUBL_imms_r32( 8, REG_ESP );
188 }
190 static inline void exit_block( )
191 {
192 ADDL_imms_r32( 8, REG_ESP );
193 POP_r32(REG_EBP);
194 RET();
195 }
197 /**
198 * Exit the block with sh4r.new_pc written with the target pc
199 */
200 void exit_block_pcset( sh4addr_t pc )
201 {
202 load_imm32( REG_ECX, ((pc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
203 ADDL_r32_rbpdisp( REG_ECX, REG_OFFSET(slice_cycle) ); // 6
204 load_spreg( REG_EAX, R_PC );
205 if( sh4_x86.tlb_on ) {
206 call_func1(xlat_get_code_by_vma,REG_EAX);
207 } else {
208 call_func1(xlat_get_code,REG_EAX);
209 }
210 exit_block();
211 }
213 /**
214 * Exit the block with sh4r.new_pc written with the target pc
215 */
216 void exit_block_newpcset( sh4addr_t pc )
217 {
218 load_imm32( REG_ECX, ((pc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
219 ADDL_r32_rbpdisp( REG_ECX, REG_OFFSET(slice_cycle) ); // 6
220 load_spreg( REG_EAX, R_NEW_PC );
221 store_spreg( REG_EAX, R_PC );
222 if( sh4_x86.tlb_on ) {
223 call_func1(xlat_get_code_by_vma,REG_EAX);
224 } else {
225 call_func1(xlat_get_code,REG_EAX);
226 }
227 exit_block();
228 }
231 /**
232 * Exit the block to an absolute PC
233 */
234 void exit_block_abs( sh4addr_t pc, sh4addr_t endpc )
235 {
236 load_imm32( REG_ECX, pc ); // 5
237 store_spreg( REG_ECX, REG_OFFSET(pc) ); // 3
238 if( IS_IN_ICACHE(pc) ) {
239 MOVP_moffptr_rax( xlat_get_lut_entry(GET_ICACHE_PHYS(pc)) ); // 5
240 ANDL_imms_r32( 0xFFFFFFFC, REG_EAX ); // 3
241 } else if( sh4_x86.tlb_on ) {
242 call_func1(xlat_get_code_by_vma,REG_ECX);
243 } else {
244 call_func1(xlat_get_code,REG_ECX);
245 }
246 load_imm32( REG_ECX, ((endpc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
247 ADDL_r32_rbpdisp( REG_ECX, REG_OFFSET(slice_cycle) ); // 6
248 exit_block();
249 }
251 /**
252 * Exit the block to a relative PC
253 */
254 void exit_block_rel( sh4addr_t pc, sh4addr_t endpc )
255 {
256 load_imm32( REG_ECX, pc - sh4_x86.block_start_pc ); // 5
257 ADDL_rbpdisp_r32( R_PC, REG_ECX );
258 store_spreg( REG_ECX, R_PC ); // 3
259 if( IS_IN_ICACHE(pc) ) {
260 MOVP_moffptr_rax( xlat_get_lut_entry(GET_ICACHE_PHYS(pc)) ); // 5
261 ANDL_imms_r32( 0xFFFFFFFC, REG_EAX ); // 3
262 } else if( sh4_x86.tlb_on ) {
263 call_func1(xlat_get_code_by_vma,REG_ECX);
264 } else {
265 call_func1(xlat_get_code,REG_ECX);
266 }
267 load_imm32( REG_ECX, ((endpc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
268 ADDL_r32_rbpdisp( REG_ECX, REG_OFFSET(slice_cycle) ); // 6
269 exit_block();
270 }
272 /**
273 * Exit unconditionally with a general exception
274 */
275 void exit_block_exc( int code, sh4addr_t pc )
276 {
277 load_imm32( REG_ECX, pc - sh4_x86.block_start_pc ); // 5
278 ADDL_r32_rbpdisp( REG_ECX, R_PC );
279 load_imm32( REG_ECX, ((pc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
280 ADDL_r32_rbpdisp( REG_ECX, REG_OFFSET(slice_cycle) ); // 6
281 load_imm32( REG_EAX, code );
282 call_func1( sh4_raise_exception, REG_EAX );
284 load_spreg( REG_EAX, R_PC );
285 if( sh4_x86.tlb_on ) {
286 call_func1(xlat_get_code_by_vma,REG_EAX);
287 } else {
288 call_func1(xlat_get_code,REG_EAX);
289 }
291 exit_block();
292 }
294 /**
295 * Write the block trailer (exception handling block)
296 */
297 void sh4_translate_end_block( sh4addr_t pc ) {
298 if( sh4_x86.branch_taken == FALSE ) {
299 // Didn't exit unconditionally already, so write the termination here
300 exit_block_rel( pc, pc );
301 }
302 if( sh4_x86.backpatch_posn != 0 ) {
303 unsigned int i;
304 // Raise exception
305 uint8_t *end_ptr = xlat_output;
306 MOVL_r32_r32( REG_EDX, REG_ECX );
307 ADDL_r32_r32( REG_EDX, REG_ECX );
308 ADDL_r32_rbpdisp( REG_ECX, R_PC );
309 MOVL_moffptr_eax( &sh4_cpu_period );
310 MULL_r32( REG_EDX );
311 ADDL_r32_rbpdisp( REG_EAX, REG_OFFSET(slice_cycle) );
313 POP_r32(REG_EAX);
314 call_func1( sh4_raise_exception, REG_EAX );
315 load_spreg( REG_EAX, R_PC );
316 if( sh4_x86.tlb_on ) {
317 call_func1(xlat_get_code_by_vma,REG_EAX);
318 } else {
319 call_func1(xlat_get_code,REG_EAX);
320 }
321 exit_block();
323 // Exception already raised - just cleanup
324 uint8_t *preexc_ptr = xlat_output;
325 MOVL_r32_r32( REG_EDX, REG_ECX );
326 ADDL_r32_r32( REG_EDX, REG_ECX );
327 ADDL_r32_rbpdisp( REG_ECX, R_SPC );
328 MOVL_moffptr_eax( &sh4_cpu_period );
329 MULL_r32( REG_EDX );
330 ADDL_r32_rbpdisp( REG_EAX, REG_OFFSET(slice_cycle) );
331 load_spreg( REG_EAX, R_PC );
332 if( sh4_x86.tlb_on ) {
333 call_func1(xlat_get_code_by_vma,REG_EAX);
334 } else {
335 call_func1(xlat_get_code,REG_EAX);
336 }
337 exit_block();
339 for( i=0; i< sh4_x86.backpatch_posn; i++ ) {
340 uint32_t *fixup_addr = (uint32_t *)&xlat_current_block->code[sh4_x86.backpatch_list[i].fixup_offset];
341 if( sh4_x86.backpatch_list[i].exc_code < 0 ) {
342 if( sh4_x86.backpatch_list[i].exc_code == -2 ) {
343 *fixup_addr = (uint32_t)xlat_output;
344 } else {
345 *fixup_addr += xlat_output - (uint8_t *)&xlat_current_block->code[sh4_x86.backpatch_list[i].fixup_offset] - 4;
346 }
347 load_imm32( REG_EDX, sh4_x86.backpatch_list[i].fixup_icount );
348 int rel = preexc_ptr - xlat_output;
349 JMP_prerel(rel);
350 } else {
351 *fixup_addr += xlat_output - (uint8_t *)&xlat_current_block->code[sh4_x86.backpatch_list[i].fixup_offset] - 4;
352 PUSH_imm32( sh4_x86.backpatch_list[i].exc_code );
353 load_imm32( REG_EDX, sh4_x86.backpatch_list[i].fixup_icount );
354 int rel = end_ptr - xlat_output;
355 JMP_prerel(rel);
356 }
357 }
358 }
359 }
362 /**
363 * The unwind methods only work if we compiled with DWARF2 frame information
364 * (ie -fexceptions), otherwise we have to use the direct frame scan.
365 */
366 #ifdef HAVE_EXCEPTIONS
367 #include <unwind.h>
369 struct UnwindInfo {
370 uintptr_t block_start;
371 uintptr_t block_end;
372 void *pc;
373 };
375 _Unwind_Reason_Code xlat_check_frame( struct _Unwind_Context *context, void *arg )
376 {
377 struct UnwindInfo *info = arg;
378 void *pc = (void *)_Unwind_GetIP(context);
379 if( ((uintptr_t)pc) >= info->block_start && ((uintptr_t)pc) < info->block_end ) {
380 info->pc = pc;
381 return _URC_NORMAL_STOP;
382 }
384 return _URC_NO_REASON;
385 }
387 void *xlat_get_native_pc( void *code, uint32_t code_size )
388 {
389 struct _Unwind_Exception exc;
390 struct UnwindInfo info;
392 info.pc = NULL;
393 info.block_start = (uintptr_t)code;
394 info.block_end = info.block_start + code_size;
395 void *result = NULL;
396 _Unwind_Backtrace( xlat_check_frame, &info );
397 return info.pc;
398 }
399 #else
400 void *xlat_get_native_pc( void *code, uint32_t code_size )
401 {
402 void *result = NULL;
403 asm(
404 "mov %%ebp, %%eax\n\t"
405 "mov $0x8, %%ecx\n\t"
406 "mov %1, %%edx\n"
407 "frame_loop: test %%eax, %%eax\n\t"
408 "je frame_not_found\n\t"
409 "cmp (%%eax), %%edx\n\t"
410 "je frame_found\n\t"
411 "sub $0x1, %%ecx\n\t"
412 "je frame_not_found\n\t"
413 "movl (%%eax), %%eax\n\t"
414 "jmp frame_loop\n"
415 "frame_found: movl 0x4(%%eax), %0\n"
416 "frame_not_found:"
417 : "=r" (result)
418 : "r" (((uint8_t *)&sh4r) + 128 )
419 : "eax", "ecx", "edx" );
420 return result;
421 }
422 #endif
424 #endif /* !lxdream_ia32mac.h */
.