filename | src/sh4/ia32abi.h |
changeset | 947:aa80962d6439 |
prev | 944:a4e31314bee1 |
author | nkeynes |
date | Tue Jan 06 02:03:36 2009 +0000 (15 years ago) |
branch | lxdream-mem |
permissions | -rw-r--r-- |
last change | Back out the CALL_ptr change (need to handle relocation from end-of-cache to front in overflow situations) |
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 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 MOV_r32_r32( addr_reg, R_ECX );
31 SHR_imm8_r32( 12, R_ECX );
32 MOV_r32disp32x4_r32( R_ECX, base, R_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(R_ECX, (uint32_t)ptr);
42 CALL_r32(R_ECX);
43 }
45 #ifdef HAVE_FASTCALL
46 static inline void call_func1( void *ptr, int arg1 )
47 {
48 if( arg1 != R_EAX ) {
49 MOV_r32_r32( arg1, R_EAX );
50 }
51 load_imm32(R_ECX, (uint32_t)ptr);
52 CALL_r32(R_ECX);
53 }
55 static inline void call_func1_r32( int addr_reg, int arg1 )
56 {
57 if( arg1 != R_EAX ) {
58 MOV_r32_r32( arg1, R_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 != R_EAX ) {
66 MOV_r32_r32( arg1, R_EAX );
67 }
68 CALL_r32disp8(preg, disp8);
69 }
71 static inline void call_func1_r32disp8_exc( int preg, uint32_t disp8, int arg1, int pc )
72 {
73 if( arg1 != R_EAX ) {
74 MOV_r32_r32( arg1, R_EAX );
75 }
76 load_exc_backpatch(R_EDX);
77 CALL_r32disp8(preg, disp8);
78 }
80 static inline void call_func2( void *ptr, int arg1, int arg2 )
81 {
82 if( arg2 != R_EDX ) {
83 MOV_r32_r32( arg2, R_EDX );
84 }
85 if( arg1 != R_EAX ) {
86 MOV_r32_r32( arg1, R_EAX );
87 }
88 load_imm32(R_ECX, (uint32_t)ptr);
89 CALL_r32(R_ECX);
90 }
92 static inline void call_func2_r32( int addr_reg, int arg1, int arg2 )
93 {
94 if( arg2 != R_EDX ) {
95 MOV_r32_r32( arg2, R_EDX );
96 }
97 if( arg1 != R_EAX ) {
98 MOV_r32_r32( arg1, R_EAX );
99 }
100 CALL_r32(addr_reg);
101 }
103 static inline void call_func2_r32disp8( int preg, uint32_t disp8, int arg1, int arg2 )
104 {
105 if( arg2 != R_EDX ) {
106 MOV_r32_r32( arg2, R_EDX );
107 }
108 if( arg1 != R_EAX ) {
109 MOV_r32_r32( arg1, R_EAX );
110 }
111 CALL_r32disp8(preg, disp8);
112 }
114 static inline void call_func2_r32disp8_exc( int preg, uint32_t disp8, int arg1, int arg2, int pc )
115 {
116 if( arg2 != R_EDX ) {
117 MOV_r32_r32( arg2, R_EDX );
118 }
119 if( arg1 != R_EAX ) {
120 MOV_r32_r32( arg1, R_EAX );
121 }
122 MOV_backpatch_esp8( 0 );
123 CALL_r32disp8(preg, disp8);
124 }
128 static inline void call_func1_exc( void *ptr, int arg1, int pc )
129 {
130 if( arg1 != R_EAX ) {
131 MOV_r32_r32( arg1, R_EAX );
132 }
133 load_exc_backpatch(R_EDX);
134 load_imm32(R_ECX, (uint32_t)ptr);
135 CALL_r32(R_ECX);
136 }
138 static inline void call_func2_exc( void *ptr, int arg1, int arg2, int pc )
139 {
140 if( arg2 != R_EDX ) {
141 MOV_r32_r32( arg2, R_EDX );
142 }
143 if( arg1 != R_EAX ) {
144 MOV_r32_r32( arg1, R_EAX );
145 }
146 MOV_backpatch_esp8(0);
147 load_imm32(R_ECX, (uint32_t)ptr);
148 CALL_r32(R_ECX);
149 }
151 #else
152 static inline void call_func1( void *ptr, int arg1 )
153 {
154 SUB_imm8s_r32( 12, R_ESP );
155 PUSH_r32(arg1);
156 load_imm32(R_ECX, (uint32_t)ptr);
157 CALL_r32(R_ECX);
158 ADD_imm8s_r32( 16, R_ESP );
159 }
161 static inline void call_func2( void *ptr, int arg1, int arg2 )
162 {
163 SUB_imm8s_r32( 8, R_ESP );
164 PUSH_r32(arg2);
165 PUSH_r32(arg1);
166 load_imm32(R_ECX, (uint32_t)ptr);
167 CALL_r32(R_ECX);
168 ADD_imm8s_r32( 16, R_ESP );
169 }
171 #endif
173 /**
174 * Emit the 'start of block' assembly. Sets up the stack frame and save
175 * SI/DI as required
176 * Allocates 8 bytes for local variables, which also has the convenient
177 * side-effect of aligning the stack.
178 */
179 void enter_block( )
180 {
181 PUSH_r32(R_EBP);
182 load_ptr( R_EBP, ((uint8_t *)&sh4r) + 128 );
183 SUB_imm8s_r32( 8, R_ESP );
184 }
186 static inline void exit_block( )
187 {
188 ADD_imm8s_r32( 8, R_ESP );
189 POP_r32(R_EBP);
190 RET();
191 }
193 /**
194 * Exit the block with sh4r.new_pc written with the target pc
195 */
196 void exit_block_pcset( sh4addr_t pc )
197 {
198 load_imm32( R_ECX, ((pc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
199 ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6
200 load_spreg( R_EAX, R_PC );
201 if( sh4_x86.tlb_on ) {
202 call_func1(xlat_get_code_by_vma,R_EAX);
203 } else {
204 call_func1(xlat_get_code,R_EAX);
205 }
206 exit_block();
207 }
209 /**
210 * Exit the block with sh4r.new_pc written with the target pc
211 */
212 void exit_block_newpcset( sh4addr_t pc )
213 {
214 load_imm32( R_ECX, ((pc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
215 ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6
216 load_spreg( R_EAX, R_NEW_PC );
217 store_spreg( R_EAX, R_PC );
218 if( sh4_x86.tlb_on ) {
219 call_func1(xlat_get_code_by_vma,R_EAX);
220 } else {
221 call_func1(xlat_get_code,R_EAX);
222 }
223 exit_block();
224 }
227 /**
228 * Exit the block to an absolute PC
229 */
230 void exit_block_abs( sh4addr_t pc, sh4addr_t endpc )
231 {
232 load_imm32( R_ECX, pc ); // 5
233 store_spreg( R_ECX, REG_OFFSET(pc) ); // 3
234 if( IS_IN_ICACHE(pc) ) {
235 MOV_moff32_EAX( xlat_get_lut_entry(GET_ICACHE_PHYS(pc)) ); // 5
236 AND_imm8s_r32( 0xFC, R_EAX ); // 3
237 } else if( sh4_x86.tlb_on ) {
238 call_func1(xlat_get_code_by_vma,R_ECX);
239 } else {
240 call_func1(xlat_get_code,R_ECX);
241 }
242 load_imm32( R_ECX, ((endpc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
243 ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6
244 exit_block();
245 }
247 /**
248 * Exit the block to a relative PC
249 */
250 void exit_block_rel( sh4addr_t pc, sh4addr_t endpc )
251 {
252 load_imm32( R_ECX, pc - sh4_x86.block_start_pc ); // 5
253 ADD_sh4r_r32( R_PC, R_ECX );
254 store_spreg( R_ECX, REG_OFFSET(pc) ); // 3
255 if( IS_IN_ICACHE(pc) ) {
256 MOV_moff32_EAX( xlat_get_lut_entry(GET_ICACHE_PHYS(pc)) ); // 5
257 AND_imm8s_r32( 0xFC, R_EAX ); // 3
258 } else if( sh4_x86.tlb_on ) {
259 call_func1(xlat_get_code_by_vma,R_ECX);
260 } else {
261 call_func1(xlat_get_code,R_ECX);
262 }
263 load_imm32( R_ECX, ((endpc - sh4_x86.block_start_pc)>>1)*sh4_cpu_period ); // 5
264 ADD_r32_sh4r( R_ECX, REG_OFFSET(slice_cycle) ); // 6
265 exit_block();
266 }
268 /**
269 * Write the block trailer (exception handling block)
270 */
271 void sh4_translate_end_block( sh4addr_t pc ) {
272 if( sh4_x86.branch_taken == FALSE ) {
273 // Didn't exit unconditionally already, so write the termination here
274 exit_block_rel( pc, pc );
275 }
276 if( sh4_x86.backpatch_posn != 0 ) {
277 unsigned int i;
278 // Raise exception
279 uint8_t *end_ptr = xlat_output;
280 MOV_r32_r32( R_EDX, R_ECX );
281 ADD_r32_r32( R_EDX, R_ECX );
282 ADD_r32_sh4r( R_ECX, R_PC );
283 MOV_moff32_EAX( &sh4_cpu_period );
284 MUL_r32( R_EDX );
285 ADD_r32_sh4r( R_EAX, REG_OFFSET(slice_cycle) );
287 POP_r32(R_EAX);
288 call_func1( sh4_raise_exception, R_EAX );
289 load_spreg( R_EAX, R_PC );
290 if( sh4_x86.tlb_on ) {
291 call_func1(xlat_get_code_by_vma,R_EAX);
292 } else {
293 call_func1(xlat_get_code,R_EAX);
294 }
295 exit_block();
297 // Exception already raised - just cleanup
298 uint8_t *preexc_ptr = xlat_output;
299 MOV_r32_r32( R_EDX, R_ECX );
300 ADD_r32_r32( R_EDX, R_ECX );
301 ADD_r32_sh4r( R_ECX, R_SPC );
302 MOV_moff32_EAX( &sh4_cpu_period );
303 MUL_r32( R_EDX );
304 ADD_r32_sh4r( R_EAX, REG_OFFSET(slice_cycle) );
305 load_spreg( R_EAX, R_PC );
306 if( sh4_x86.tlb_on ) {
307 call_func1(xlat_get_code_by_vma,R_EAX);
308 } else {
309 call_func1(xlat_get_code,R_EAX);
310 }
311 exit_block();
313 for( i=0; i< sh4_x86.backpatch_posn; i++ ) {
314 uint32_t *fixup_addr = (uint32_t *)&xlat_current_block->code[sh4_x86.backpatch_list[i].fixup_offset];
315 if( sh4_x86.backpatch_list[i].exc_code < 0 ) {
316 if( sh4_x86.backpatch_list[i].exc_code == -2 ) {
317 *fixup_addr = (uint32_t)xlat_output;
318 } else {
319 *fixup_addr += xlat_output - (uint8_t *)&xlat_current_block->code[sh4_x86.backpatch_list[i].fixup_offset] - 4;
320 }
321 load_imm32( R_EDX, sh4_x86.backpatch_list[i].fixup_icount );
322 int rel = preexc_ptr - xlat_output;
323 JMP_rel(rel);
324 } else {
325 *fixup_addr += xlat_output - (uint8_t *)&xlat_current_block->code[sh4_x86.backpatch_list[i].fixup_offset] - 4;
326 PUSH_imm32( sh4_x86.backpatch_list[i].exc_code );
327 load_imm32( R_EDX, sh4_x86.backpatch_list[i].fixup_icount );
328 int rel = end_ptr - xlat_output;
329 JMP_rel(rel);
330 }
331 }
332 }
333 }
336 /**
337 * The unwind methods only work if we compiled with DWARF2 frame information
338 * (ie -fexceptions), otherwise we have to use the direct frame scan.
339 */
340 #ifdef HAVE_EXCEPTIONS
341 #include <unwind.h>
343 struct UnwindInfo {
344 uintptr_t block_start;
345 uintptr_t block_end;
346 void *pc;
347 };
349 _Unwind_Reason_Code xlat_check_frame( struct _Unwind_Context *context, void *arg )
350 {
351 struct UnwindInfo *info = arg;
352 void *pc = (void *)_Unwind_GetIP(context);
353 if( ((uintptr_t)pc) >= info->block_start && ((uintptr_t)pc) < info->block_end ) {
354 info->pc = pc;
355 return _URC_NORMAL_STOP;
356 }
358 return _URC_NO_REASON;
359 }
361 void *xlat_get_native_pc( void *code, uint32_t code_size )
362 {
363 struct _Unwind_Exception exc;
364 struct UnwindInfo info;
366 info.pc = NULL;
367 info.block_start = (uintptr_t)code;
368 info.block_end = info.block_start + code_size;
369 void *result = NULL;
370 _Unwind_Backtrace( xlat_check_frame, &info );
371 return info.pc;
372 }
373 #else
374 void *xlat_get_native_pc( void *code, uint32_t code_size )
375 {
376 void *result = NULL;
377 asm(
378 "mov %%ebp, %%eax\n\t"
379 "mov $0x8, %%ecx\n\t"
380 "mov %1, %%edx\n"
381 "frame_loop: test %%eax, %%eax\n\t"
382 "je frame_not_found\n\t"
383 "cmp (%%eax), %%edx\n\t"
384 "je frame_found\n\t"
385 "sub $0x1, %%ecx\n\t"
386 "je frame_not_found\n\t"
387 "movl (%%eax), %%eax\n\t"
388 "jmp frame_loop\n"
389 "frame_found: movl 0x4(%%eax), %0\n"
390 "frame_not_found:"
391 : "=r" (result)
392 : "r" (((uint8_t *)&sh4r) + 128 )
393 : "eax", "ecx", "edx" );
394 return result;
395 }
396 #endif
398 #endif /* !lxdream_ia32mac.h */
.