|
|
1.1.1.3 root 1: /*
2: * compiler/compemu.h - Public interface and definitions
3: *
4: * Copyright (c) 2001-2004 Milan Jurik of ARAnyM dev team (see AUTHORS)
5: *
6: * Inspired by Christian Bauer's Basilisk II
7: *
8: * This file is part of the ARAnyM project which builds a new and powerful
9: * TOS/FreeMiNT compatible virtual machine running on almost any hardware.
10: *
11: * JIT compiler m68k -> IA-32 and AMD64
12: *
13: * Original 68040 JIT compiler for UAE, copyright 2000-2002 Bernd Meyer
14: * Adaptation for Basilisk II and improvements, copyright 2000-2004 Gwenole Beauchesne
15: * Portions related to CPU detection come from linux/arch/i386/kernel/setup.c
16: *
17: * ARAnyM is free software; you can redistribute it and/or modify
18: * it under the terms of the GNU General Public License as published by
19: * the Free Software Foundation; either version 2 of the License, or
20: * (at your option) any later version.
21: *
22: * ARAnyM is distributed in the hope that it will be useful,
23: * but WITHOUT ANY WARRANTY; without even the implied warranty of
24: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25: * GNU General Public License for more details.
26: *
27: * You should have received a copy of the GNU General Public License
1.1.1.4 ! root 28: * along with ARAnyM; if not, write to the Free Software Foundation,
! 29: * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
1.1.1.3 root 30: */
1.1 root 31:
1.1.1.3 root 32: #ifndef COMPEMU_H
33: #define COMPEMU_H
1.1 root 34:
1.1.1.3 root 35: #include "newcpu.h"
36:
37: #ifdef UAE
1.1 root 38: #ifdef CPU_64_BIT
39: typedef uae_u64 uintptr;
40: #else
41: typedef uae_u32 uintptr;
42: #endif
1.1.1.3 root 43: /* FIXME: cpummu.cpp also checks for USE_JIT, possibly others */
44: #define USE_JIT
45: #endif
1.1 root 46:
1.1.1.3 root 47: #ifdef USE_JIT
48:
49: #ifdef JIT_DEBUG
50: /* dump some information (m68k block, x86 block addresses) about the compiler state */
51: extern void compiler_dumpstate(void);
52: #endif
53:
54: /* Now that we do block chaining, and also have linked lists on each tag,
55: TAGMASK can be much smaller and still do its job. Saves several megs
56: of memory! */
57: #define TAGMASK 0x0000ffff
1.1 root 58: #define TAGSIZE (TAGMASK+1)
59: #define MAXRUN 1024
1.1.1.3 root 60: #define cacheline(x) (((uintptr)x)&TAGMASK)
1.1 root 61:
62: extern uae_u8* start_pc_p;
63: extern uae_u32 start_pc;
64:
1.1.1.3 root 65: struct blockinfo_t;
1.1 root 66:
1.1.1.3 root 67: struct cpu_history {
1.1 root 68: uae_u16* location;
69: uae_u8 specmem;
1.1.1.3 root 70: };
1.1 root 71:
1.1.1.3 root 72: union cacheline {
73: cpuop_func* handler;
74: blockinfo_t * bi;
75: };
76:
77: /* Use new spill/reload strategy when calling external functions */
78: #define USE_OPTIMIZED_CALLS 0
79: #if USE_OPTIMIZED_CALLS
80: #error implementation in progress
81: #endif
1.1 root 82:
1.1.1.3 root 83: /* (gb) When on, this option can save save up to 30% compilation time
84: * when many lazy flushes occur (e.g. apps in MacOS 8.x).
85: */
86: #define USE_SEPARATE_BIA 1
87:
88: /* Use chain of checksum_info_t to compute the block checksum */
89: #define USE_CHECKSUM_INFO 1
90:
91: /* Use code inlining, aka follow-up of constant jumps */
92: #define USE_INLINING 1
93:
94: /* Inlining requires the chained checksuming information */
95: #if USE_INLINING
96: #undef USE_CHECKSUM_INFO
97: #define USE_CHECKSUM_INFO 1
98: #endif
1.1 root 99:
1.1.1.3 root 100: /* Does flush_icache_range() only check for blocks falling in the requested range? */
101: #define LAZY_FLUSH_ICACHE_RANGE 0
1.1 root 102:
103: #define USE_F_ALIAS 1
104: #define USE_OFFSET 1
105: #define COMP_DEBUG 1
106:
107: #if COMP_DEBUG
108: #define Dif(x) if (x)
109: #else
110: #define Dif(x) if (0)
111: #endif
112:
113: #define SCALE 2
114:
115: #define BYTES_PER_INST 10240 /* paranoid ;-) */
1.1.1.3 root 116: #if defined(CPU_arm)
117: #define LONGEST_68K_INST 256 /* The number of bytes the longest possible
118: 68k instruction takes */
119: #else
1.1 root 120: #define LONGEST_68K_INST 16 /* The number of bytes the longest possible
121: 68k instruction takes */
1.1.1.3 root 122: #endif
1.1 root 123: #define MAX_CHECKSUM_LEN 2048 /* The maximum size we calculate checksums
124: for. Anything larger will be flushed
125: unconditionally even with SOFT_FLUSH */
126: #define MAX_HOLD_BI 3 /* One for the current block, and up to two
127: for jump targets */
128:
129: #define INDIVIDUAL_INST 0
130: #define FLAG_C 0x0010
131: #define FLAG_V 0x0008
132: #define FLAG_Z 0x0004
133: #define FLAG_N 0x0002
134: #define FLAG_X 0x0001
135: #define FLAG_CZNV (FLAG_C | FLAG_Z | FLAG_N | FLAG_V)
136: #define FLAG_ZNV (FLAG_Z | FLAG_N | FLAG_V)
137:
138: #define KILLTHERAT 1 /* Set to 1 to avoid some partial_rat_stalls */
139:
1.1.1.3 root 140: #if defined(CPU_arm)
141: #define USE_DATA_BUFFER
142: #define N_REGS 13 /* really 16, but 13 to 15 are SP, LR, PC */
143: #else
144: #if defined(CPU_x86_64)
145: #define N_REGS 16 /* really only 15, but they are numbered 0-3,5-15 */
1.1 root 146: #else
147: #define N_REGS 8 /* really only 7, but they are numbered 0,1,2,3,5,6,7 */
1.1.1.3 root 148: #endif
149: #endif
1.1 root 150: #define N_FREGS 6 /* That leaves us two positions on the stack to play with */
151:
152: /* Functions exposed to newcpu, or to what was moved from newcpu.c to
153: * compemu_support.c */
154: extern void init_comp(void);
155: extern void flush(int save_regs);
156: extern void small_flush(int save_regs);
157: extern void set_target(uae_u8* t);
1.1.1.3 root 158: extern uae_u8* get_target(void);
1.1 root 159: extern void freescratch(void);
160: extern void build_comp(void);
161: extern void set_cache_state(int enabled);
162: extern int get_cache_state(void);
163: extern uae_u32 get_jitted_size(void);
164: #ifdef JIT
1.1.1.4 ! root 165: extern void flush_icache(int n);
! 166: extern void flush_icache_hard(int n);
1.1 root 167: #endif
168: extern void alloc_cache(void);
169: extern int check_for_cache_miss(void);
170:
1.1.1.3 root 171: /* JIT FPU compilation */
172: extern void comp_fpp_opp (uae_u32 opcode, uae_u16 extra);
173: extern void comp_fbcc_opp (uae_u32 opcode);
174: extern void comp_fscc_opp (uae_u32 opcode, uae_u16 extra);
175: void comp_fdbcc_opp (uae_u32 opcode, uae_u16 extra);
176: void comp_ftrapcc_opp (uae_u32 opcode, uaecptr oldpc);
177: void comp_fsave_opp (uae_u32 opcode);
178: void comp_frestore_opp (uae_u32 opcode);
1.1 root 179:
180: extern uae_u32 needed_flags;
181: extern uae_u8* comp_pc_p;
182: extern void* pushall_call_handler;
183:
184: #define VREGS 32
185: #define VFREGS 16
186:
187: #define INMEM 1
188: #define CLEAN 2
189: #define DIRTY 3
190: #define UNDEF 4
191: #define ISCONST 5
192:
193: typedef struct {
194: uae_u32* mem;
195: uae_u32 val;
196: uae_u8 is_swapped;
197: uae_u8 status;
1.1.1.3 root 198: uae_s8 realreg; /* gb-- realreg can hold -1 */
1.1 root 199: uae_u8 realind; /* The index in the holds[] array */
200: uae_u8 needflush;
201: uae_u8 validsize;
202: uae_u8 dirtysize;
203: uae_u8 dummy;
204: } reg_status;
205:
206: typedef struct {
207: uae_u32* mem;
208: double val;
209: uae_u8 status;
1.1.1.3 root 210: uae_s8 realreg; /* gb-- realreg can hold -1 */
1.1 root 211: uae_u8 realind;
212: uae_u8 needflush;
213: } freg_status;
214:
215: #define PC_P 16
216: #define FLAGX 17
217: #define FLAGTMP 18
218: #define NEXT_HANDLER 19
219: #define S1 20
220: #define S2 21
221: #define S3 22
222: #define S4 23
223: #define S5 24
224: #define S6 25
225: #define S7 26
226: #define S8 27
227: #define S9 28
228: #define S10 29
229: #define S11 30
230: #define S12 31
231:
232: #define FP_RESULT 8
233: #define FS1 9
234: #define FS2 10
235: #define FS3 11
236:
237: typedef struct {
238: uae_u32 touched;
239: uae_s8 holds[VREGS];
240: uae_u8 nholds;
241: uae_u8 canbyte;
242: uae_u8 canword;
243: uae_u8 locked;
244: } n_status;
245:
246: typedef struct {
247: uae_u32 touched;
248: uae_s8 holds[VFREGS];
249: uae_u8 nholds;
250: uae_u8 locked;
251: } fn_status;
252:
253: /* For flag handling */
254: #define NADA 1
255: #define TRASH 2
256: #define VALID 3
257:
258: /* needflush values */
259: #define NF_SCRATCH 0
260: #define NF_TOMEM 1
261: #define NF_HANDLER 2
262:
263: typedef struct {
264: /* Integer part */
265: reg_status state[VREGS];
266: n_status nat[N_REGS];
267: uae_u32 flags_on_stack;
268: uae_u32 flags_in_flags;
269: uae_u32 flags_are_important;
270: /* FPU part */
271: freg_status fate[VFREGS];
272: fn_status fat[N_FREGS];
273:
274: /* x86 FPU part */
275: uae_s8 spos[N_FREGS];
276: uae_s8 onstack[6];
277: uae_s8 tos;
278: } bigstate;
279:
280: typedef struct {
1.1.1.3 root 281: /* Integer part */
282: uae_s8 virt[VREGS];
283: uae_s8 nat[N_REGS];
1.1 root 284: } smallstate;
285:
286: extern int touchcnt;
287:
1.1.1.3 root 288: #define IMM uae_s32
289: #define RR1 uae_u32
290: #define RR2 uae_u32
291: #define RR4 uae_u32
292: /*
293: R1, R2, R4 collides with ARM registers defined in ucontext
1.1 root 294: #define R1 uae_u32
295: #define R2 uae_u32
296: #define R4 uae_u32
1.1.1.3 root 297: */
1.1 root 298: #define W1 uae_u32
299: #define W2 uae_u32
300: #define W4 uae_u32
301: #define RW1 uae_u32
302: #define RW2 uae_u32
303: #define RW4 uae_u32
304: #define MEMR uae_u32
305: #define MEMW uae_u32
306: #define MEMRW uae_u32
307:
308: #define FW uae_u32
309: #define FR uae_u32
310: #define FRW uae_u32
311:
312: #define MIDFUNC(nargs,func,args) void func args
313: #define MENDFUNC(nargs,func,args)
314: #define COMPCALL(func) func
315:
1.1.1.3 root 316: #define LOWFUNC(flags,mem,nargs,func,args) static inline void func args
1.1 root 317: #define LENDFUNC(flags,mem,nargs,func,args)
318:
1.1.1.3 root 319: /* What we expose to the outside */
320: #define DECLARE_MIDFUNC(func) extern void func
321:
322: #if defined(CPU_arm)
323:
324: #include "compemu_midfunc_arm.h"
325:
326: #if defined(USE_JIT2)
327: #include "compemu_midfunc_arm2.h"
328: #endif
1.1 root 329: #endif
330:
1.1.1.3 root 331: #if defined(CPU_i386) || defined(CPU_x86_64)
332: #include "compemu_midfunc_x86.h"
333: #endif
1.1 root 334:
1.1.1.3 root 335: #undef DECLARE_MIDFUNC
1.1 root 336:
337: extern int failure;
338: #define FAIL(x) do { failure|=x; } while (0)
339:
340: /* Convenience functions exposed to gencomp */
341: extern uae_u32 m68k_pc_offset;
342: extern void readbyte(int address, int dest, int tmp);
343: extern void readword(int address, int dest, int tmp);
344: extern void readlong(int address, int dest, int tmp);
345: extern void writebyte(int address, int source, int tmp);
346: extern void writeword(int address, int source, int tmp);
347: extern void writelong(int address, int source, int tmp);
348: extern void writeword_clobber(int address, int source, int tmp);
349: extern void writelong_clobber(int address, int source, int tmp);
350: extern void get_n_addr(int address, int dest, int tmp);
351: extern void get_n_addr_jmp(int address, int dest, int tmp);
352: extern void calc_disp_ea_020(int base, uae_u32 dp, int target, int tmp);
1.1.1.3 root 353: /* Set native Z flag only if register is zero */
354: extern void set_zero(int r, int tmp);
1.1 root 355: extern int kill_rodent(int r);
1.1.1.3 root 356: #define SYNC_PC_OFFSET 100
1.1 root 357: extern void sync_m68k_pc(void);
358: extern uae_u32 get_const(int r);
359: extern int is_const(int r);
360: extern void register_branch(uae_u32 not_taken, uae_u32 taken, uae_u8 cond);
361:
362: #define comp_get_ibyte(o) do_get_mem_byte((uae_u8 *)(comp_pc_p + (o) + 1))
363: #define comp_get_iword(o) do_get_mem_word((uae_u16 *)(comp_pc_p + (o)))
364: #define comp_get_ilong(o) do_get_mem_long((uae_u32 *)(comp_pc_p + (o)))
365:
366: struct blockinfo_t;
367:
368: typedef struct dep_t {
369: uae_u32* jmp_off;
370: struct blockinfo_t* target;
1.1.1.3 root 371: struct blockinfo_t* source;
1.1 root 372: struct dep_t** prev_p;
373: struct dep_t* next;
374: } dependency;
375:
1.1.1.3 root 376: typedef struct checksum_info_t {
377: uae_u8 *start_p;
378: uae_u32 length;
379: struct checksum_info_t *next;
380: } checksum_info;
381:
1.1 root 382: typedef struct blockinfo_t {
383: uae_s32 count;
384: cpuop_func* direct_handler_to_use;
385: cpuop_func* handler_to_use;
386: /* The direct handler does not check for the correct address */
387:
388: cpuop_func* handler;
389: cpuop_func* direct_handler;
390:
391: cpuop_func* direct_pen;
392: cpuop_func* direct_pcc;
393:
394: uae_u8* nexthandler;
395: uae_u8* pc_p;
396:
397: uae_u32 c1;
398: uae_u32 c2;
1.1.1.3 root 399: #if USE_CHECKSUM_INFO
400: checksum_info *csi;
401: #else
1.1 root 402: uae_u32 len;
1.1.1.3 root 403: uae_u32 min_pcp;
404: #endif
1.1 root 405:
406: struct blockinfo_t* next_same_cl;
407: struct blockinfo_t** prev_same_cl_p;
408: struct blockinfo_t* next;
409: struct blockinfo_t** prev_p;
410:
411: uae_u8 optlevel;
412: uae_u8 needed_flags;
413: uae_u8 status;
414: uae_u8 havestate;
415:
416: dependency dep[2]; /* Holds things we depend on */
417: dependency* deplist; /* List of things that depend on this */
418: smallstate env;
1.1.1.3 root 419:
420: #ifdef JIT_DEBUG
421: /* (gb) size of the compiled block (direct handler) */
422: uae_u32 direct_handler_size;
423: #endif
1.1 root 424: } blockinfo;
425:
1.1.1.3 root 426: #define BI_INVALID 0
427: #define BI_ACTIVE 1
428: #define BI_NEED_RECOMP 2
429: #define BI_NEED_CHECK 3
430: #define BI_CHECKING 4
431: #define BI_COMPILING 5
432: #define BI_FINALIZING 6
433:
434: void execute_normal(void);
435: void exec_nostats(void);
436: void do_nothing(void);
437:
438: #else
439:
440: static inline void flush_icache(int) { }
441: static inline void build_comp() { }
442:
443: #endif /* !USE_JIT */
444:
445: #ifdef UAE
1.1 root 446:
447: typedef struct {
448: uae_u8 type;
449: uae_u8 reg;
450: uae_u32 next;
451: } regacc;
452:
1.1.1.3 root 453: #define JIT_EXCEPTION_HANDLER
454: // #define JIT_ALWAYS_DISTRUST
1.1 root 455:
1.1.1.3 root 456: /* ARAnyM uses fpu_register name, used in scratch_t */
457: /* FIXME: check that no ARAnyM code assumes different floating point type */
458: typedef fptype fpu_register;
459:
460: extern void compile_block(cpu_history* pc_hist, int blocklen, int totcyles);
461:
462: #define MAXCYCLES (1000 * CYCLE_UNIT)
463: #define scaled_cycles(x) (currprefs.m68k_speed<0?(((x)/SCALE)?(((x)/SCALE<MAXCYCLES?((x)/SCALE):MAXCYCLES)):1):(x))
464:
465: /* Flags for Bernie during development/debugging. Should go away eventually */
466: #define DISTRUST_CONSISTENT_MEM 0
467:
468: typedef struct {
469: uae_u8 use_flags;
470: uae_u8 set_flags;
471: uae_u8 is_jump;
472: uae_u8 is_addx;
473: uae_u8 is_const_jump;
474: } op_properties;
475:
476: extern op_properties prop[65536];
477:
478: STATIC_INLINE int end_block(uae_u16 opcode)
479: {
480: return prop[opcode].is_jump ||
481: (prop[opcode].is_const_jump && !currprefs.comp_constjump);
482: }
483:
484: #ifdef _WIN32
485: LONG WINAPI EvalException(LPEXCEPTION_POINTERS info);
486: #if defined(_MSC_VER) && !defined(NO_WIN32_EXCEPTION_HANDLER)
487: #ifdef _WIN64
488: /* Structured exception handling is table based for Windows x86-64, so
489: * Windows will not be able to find the exception handler. */
490: #else
491: #define USE_STRUCTURED_EXCEPTION_HANDLING
492: #endif
493: #endif
494: #endif
495:
496: void jit_abort(const char *format,...);
497: #if SIZEOF_TCHAR != 1
498: void jit_abort(const TCHAR *format, ...);
499: #endif
500:
501: #else
502:
503: #define jit_abort(...) abort()
504: #define jit_log panicbug
505: #define jit_log2(...)
506:
507: #endif
508:
509: #ifdef CPU_64_BIT
510: static inline uae_u32 check_uae_p32(uae_u64 address, const char *file, int line)
511: {
512: if (address > (uintptr_t) 0xffffffff) {
513: jit_abort("JIT: 64-bit pointer (0x%llx) at %s:%d (fatal)",
514: address, file, line);
515: }
516: return (uae_u32) address;
517: }
518: #define uae_p32(x) (check_uae_p32((uae_u64)(x), __FILE__, __LINE__))
519: #else
520: #define uae_p32(x) ((uae_u32)(x))
521: #endif
522:
523: #endif /* COMPEMU_H */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.