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
28 * along with ARAnyM; if not, write to the Free Software Foundation,
29 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
30 */
31
32 #ifndef COMPEMU_H
33 #define COMPEMU_H
34
35 #include "sysconfig.h"
36 #include "newcpu.h"
37
38 #ifdef UAE
39 #ifdef CPU_64_BIT
40 typedef uae_u64 uintptr;
41 #else
42 typedef uae_u32 uintptr;
43 #endif
44 /* FIXME: cpummu.cpp also checks for USE_JIT, possibly others */
45 #define USE_JIT
46 #endif
47
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
59 #define TAGSIZE (TAGMASK+1)
60 #define MAXRUN 1024
61 #define cacheline(x) (((uintptr)x)&TAGMASK)
62
63 extern uae_u8* start_pc_p;
64 extern uae_u32 start_pc;
65
66 struct blockinfo_t;
67
68 struct cpu_history {
69 uae_u16* location;
70 #ifdef UAE
71 uae_u8 specmem;
72 #endif
73 };
74
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
85
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
102
103 /* Does flush_icache_range() only check for blocks falling in the requested range? */
104 #define LAZY_FLUSH_ICACHE_RANGE 0
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 ;-) */
119 #if defined(CPU_arm)
120 #define LONGEST_68K_INST 256 /* The number of bytes the longest possible
121 68k instruction takes */
122 #else
123 #define LONGEST_68K_INST 16 /* The number of bytes the longest possible
124 68k instruction takes */
125 #endif
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
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
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
145 #endif
146 #define FLAG_CZNV (FLAG_C | FLAG_Z | FLAG_N | FLAG_V)
147 #define FLAG_ALL (FLAG_C | FLAG_Z | FLAG_N | FLAG_V | FLAG_X)
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
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 */
158 #else
159 #define N_REGS 8 /* really only 7, but they are numbered 0,1,2,3,5,6,7 */
160 #endif
161 #endif
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 */
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
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);
175 extern uae_u8* get_target(void);
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
182 #ifdef WINUAE_ARANYM
183 extern void (*flush_icache)(int n);
184 #else
185 extern void flush_icache(int n);
186 extern void flush_icache_hard(int n);
187 #endif
188 #endif
189 extern void alloc_cache(void);
190 extern int check_for_cache_miss(void);
191
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);
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;
219 uae_s8 realreg; /* gb-- realreg can hold -1 */
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;
231 uae_s8 realreg; /* gb-- realreg can hold -1 */
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 {
302 /* Integer part */
303 uae_s8 virt[VREGS];
304 uae_s8 nat[N_REGS];
305 } smallstate;
306
307 extern int touchcnt;
308
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
315 #define R1 uae_u32
316 #define R2 uae_u32
317 #define R4 uae_u32
318 */
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
337 #define LOWFUNC(flags,mem,nargs,func,args) static inline void func args
338 #define LENDFUNC(flags,mem,nargs,func,args)
339
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
350 #endif
351
352 #if defined(CPU_i386) || defined(CPU_x86_64)
353 #include "compemu_midfunc_x86.h"
354 #endif
355
356 #undef DECLARE_MIDFUNC
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);
374 /* Set native Z flag only if register is zero */
375 extern void set_zero(int r, int tmp);
376 extern int kill_rodent(int r);
377 #define SYNC_PC_OFFSET 100
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;
392 struct blockinfo_t* source;
393 struct dep_t** prev_p;
394 struct dep_t* next;
395 } dependency;
396
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
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
415 #ifdef UAE
416 uae_u8* nexthandler;
417 #endif
418 uae_u8* pc_p;
419
420 uae_u32 c1;
421 uae_u32 c2;
422 #if USE_CHECKSUM_INFO
423 checksum_info *csi;
424 #else
425 uae_u32 len;
426 uae_u32 min_pcp;
427 #endif
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;
442
443 #ifdef JIT_DEBUG
444 /* (gb) size of the compiled block (direct handler) */
445 uae_u32 direct_handler_size;
446 #endif
447 } blockinfo;
448
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
flush_icache(int)463 static inline void flush_icache(int) { }
build_comp()464 static inline void build_comp() { }
465
466 #endif /* !USE_JIT */
467
468 #ifdef UAE
469
470 typedef struct {
471 uae_u8 type;
472 uae_u8 reg;
473 uae_u32 next;
474 } regacc;
475
476 #define JIT_EXCEPTION_HANDLER
477 // #define JIT_ALWAYS_DISTRUST
478
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
end_block(uae_u16 opcode)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
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
531 #define jit_abort(...) abort()
532 #define jit_log panicbug
533 #define jit_log2(...)
534 #endif
535
536 #endif /* UAE */
537
538 #ifdef CPU_64_BIT
check_uae_p32(uintptr address,const char * file,int line)539 static inline uae_u32 check_uae_p32(uintptr address, const char *file, int line)
540 {
541 if (address > (uintptr_t) 0xffffffff) {
542 jit_abort("JIT: 64-bit pointer (0x%llx) at %s:%d (fatal)",
543 (unsigned long long)address, file, line);
544 }
545 return (uae_u32) address;
546 }
547 #define uae_p32(x) (check_uae_p32((uintptr)(x), __FILE__, __LINE__))
548 #else
549 #define uae_p32(x) ((uae_u32)(x))
550 #endif
551
552 #endif /* COMPEMU_H */
553