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