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