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
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 flush(int save_regs);
172 extern void set_target(uae_u8* t);
173 extern uae_u8* get_target(void);
174 #ifdef UAE
175 extern void build_comp(void);
176 #endif
177 extern void set_cache_state(int enabled);
178 extern int get_cache_state(void);
179 extern uae_u32 get_jitted_size(void);
180 #ifdef JIT
181 #ifdef WINUAE_ARANYM
182 extern void (*flush_icache)(int n);
183 #else
184 extern void flush_icache(uaecptr ptr, int n);
185 extern void flush_icache_hard(uaecptr ptr, int n);
flush_icache(int n)186 static inline void flush_icache(int n)
187 {
188 flush_icache(0, n);
189 }
flush_icache_hard(int n)190 static inline void flush_icache_hard(int n)
191 {
192 flush_icache(0, n);
193 }
194 #endif
195 #endif
196 extern void alloc_cache(void);
197 extern int check_for_cache_miss(void);
198
199 /* JIT FPU compilation */
200 extern void comp_fpp_opp (uae_u32 opcode, uae_u16 extra);
201 extern void comp_fbcc_opp (uae_u32 opcode);
202 extern void comp_fscc_opp (uae_u32 opcode, uae_u16 extra);
203 void comp_fdbcc_opp (uae_u32 opcode, uae_u16 extra);
204 void comp_ftrapcc_opp (uae_u32 opcode, uaecptr oldpc);
205 void comp_fsave_opp (uae_u32 opcode);
206 void comp_frestore_opp (uae_u32 opcode);
207
208 extern uae_u32 needed_flags;
209 extern uae_u8* comp_pc_p;
210 extern void* pushall_call_handler;
211
212 #define VREGS 32
213 #define VFREGS 16
214
215 #define INMEM 1
216 #define CLEAN 2
217 #define DIRTY 3
218 #define UNDEF 4
219 #define ISCONST 5
220
221 typedef struct {
222 uae_u32* mem;
223 uae_u32 val;
224 uae_u8 is_swapped;
225 uae_u8 status;
226 uae_s8 realreg; /* gb-- realreg can hold -1 */
227 uae_u8 realind; /* The index in the holds[] array */
228 uae_u8 needflush;
229 uae_u8 validsize;
230 uae_u8 dirtysize;
231 uae_u8 dummy;
232 } reg_status;
233
234 typedef struct {
235 uae_u32* mem;
236 double val;
237 uae_u8 status;
238 uae_s8 realreg; /* gb-- realreg can hold -1 */
239 uae_u8 realind;
240 uae_u8 needflush;
241 } freg_status;
242
243 #define PC_P 16
244 #define FLAGX 17
245 #define FLAGTMP 18
246 #define NEXT_HANDLER 19
247 #define S1 20
248 #define S2 21
249 #define S3 22
250 #define S4 23
251 #define S5 24
252 #define S6 25
253 #define S7 26
254 #define S8 27
255 #define S9 28
256 #define S10 29
257 #define S11 30
258 #define S12 31
259
260 #define FP_RESULT 8
261 #define FS1 9
262 #define FS2 10
263 #define FS3 11
264
265 typedef struct {
266 uae_u32 touched;
267 uae_s8 holds[VREGS];
268 uae_u8 nholds;
269 uae_u8 canbyte;
270 uae_u8 canword;
271 uae_u8 locked;
272 } n_status;
273
274 typedef struct {
275 uae_u32 touched;
276 uae_s8 holds[VFREGS];
277 uae_u8 nholds;
278 uae_u8 locked;
279 } fn_status;
280
281 /* For flag handling */
282 #define NADA 1
283 #define TRASH 2
284 #define VALID 3
285
286 /* needflush values */
287 #define NF_SCRATCH 0
288 #define NF_TOMEM 1
289 #define NF_HANDLER 2
290
291 typedef struct {
292 /* Integer part */
293 reg_status state[VREGS];
294 n_status nat[N_REGS];
295 uae_u32 flags_on_stack;
296 uae_u32 flags_in_flags;
297 uae_u32 flags_are_important;
298 /* FPU part */
299 freg_status fate[VFREGS];
300 fn_status fat[N_FREGS];
301
302 /* x86 FPU part */
303 uae_s8 spos[N_FREGS];
304 uae_s8 onstack[6];
305 uae_s8 tos;
306 } bigstate;
307
308 typedef struct {
309 /* Integer part */
310 uae_s8 virt[VREGS];
311 uae_s8 nat[N_REGS];
312 } smallstate;
313
314 extern int touchcnt;
315
316 #define IMM uae_s32
317 #define RR1 uae_u32
318 #define RR2 uae_u32
319 #define RR4 uae_u32
320 /*
321 R1, R2, R4 collides with ARM registers defined in ucontext
322 #define R1 uae_u32
323 #define R2 uae_u32
324 #define R4 uae_u32
325 */
326 #define W1 uae_u32
327 #define W2 uae_u32
328 #define W4 uae_u32
329 #define RW1 uae_u32
330 #define RW2 uae_u32
331 #define RW4 uae_u32
332 #define MEMR uae_u32
333 #define MEMW uae_u32
334 #define MEMRW uae_u32
335
336 #define FW uae_u32
337 #define FR uae_u32
338 #define FRW uae_u32
339
340 #define MIDFUNC(nargs,func,args) void func args
341 #define MENDFUNC(nargs,func,args)
342 #define COMPCALL(func) func
343
344 #define LOWFUNC(flags,mem,nargs,func,args) static inline void func args
345 #define LENDFUNC(flags,mem,nargs,func,args)
346
347 /* What we expose to the outside */
348 #define DECLARE_MIDFUNC(func) extern void func
349
350 #if defined(CPU_arm)
351
352 #include "compemu_midfunc_arm.h"
353
354 #if defined(USE_JIT2)
355 #include "compemu_midfunc_arm2.h"
356 #endif
357 #endif
358
359 #if defined(CPU_i386) || defined(CPU_x86_64)
360 #include "compemu_midfunc_x86.h"
361 #endif
362
363 #undef DECLARE_MIDFUNC
364
365 extern int failure;
366 #define FAIL(x) do { failure|=x; } while (0)
367
368 /* Convenience functions exposed to gencomp */
369 extern uae_u32 m68k_pc_offset;
370 extern void readbyte(int address, int dest, int tmp);
371 extern void readword(int address, int dest, int tmp);
372 extern void readlong(int address, int dest, int tmp);
373 extern void writebyte(int address, int source, int tmp);
374 extern void writeword(int address, int source, int tmp);
375 extern void writelong(int address, int source, int tmp);
376 extern void writeword_clobber(int address, int source, int tmp);
377 extern void writelong_clobber(int address, int source, int tmp);
378 extern void get_n_addr(int address, int dest, int tmp);
379 extern void get_n_addr_jmp(int address, int dest, int tmp);
380 extern void calc_disp_ea_020(int base, uae_u32 dp, int target, int tmp);
381 /* Set native Z flag only if register is zero */
382 extern void set_zero(int r, int tmp);
383 extern int kill_rodent(int r);
384 #define SYNC_PC_OFFSET 100
385 extern void sync_m68k_pc(void);
386 extern uae_u32 get_const(int r);
387 extern int is_const(int r);
388 extern void register_branch(uae_u32 not_taken, uae_u32 taken, uae_u8 cond);
389
390 #define comp_get_ibyte(o) do_get_mem_byte((uae_u8 *)(comp_pc_p + (o) + 1))
391 #define comp_get_iword(o) do_get_mem_word((uae_u16 *)(comp_pc_p + (o)))
392 #define comp_get_ilong(o) do_get_mem_long((uae_u32 *)(comp_pc_p + (o)))
393
394 struct blockinfo_t;
395
396 typedef struct dep_t {
397 uae_u32* jmp_off;
398 struct blockinfo_t* target;
399 struct blockinfo_t* source;
400 struct dep_t** prev_p;
401 struct dep_t* next;
402 } dependency;
403
404 typedef struct checksum_info_t {
405 uae_u8 *start_p;
406 uae_u32 length;
407 struct checksum_info_t *next;
408 } checksum_info;
409
410 typedef struct blockinfo_t {
411 uae_s32 count;
412 cpuop_func* direct_handler_to_use;
413 cpuop_func* handler_to_use;
414 /* The direct handler does not check for the correct address */
415
416 cpuop_func* handler;
417 cpuop_func* direct_handler;
418
419 cpuop_func* direct_pen;
420 cpuop_func* direct_pcc;
421
422 #ifdef UAE
423 uae_u8* nexthandler;
424 #endif
425 uae_u8* pc_p;
426
427 uae_u32 c1;
428 uae_u32 c2;
429 #if USE_CHECKSUM_INFO
430 checksum_info *csi;
431 #else
432 uae_u32 len;
433 uae_u32 min_pcp;
434 #endif
435
436 struct blockinfo_t* next_same_cl;
437 struct blockinfo_t** prev_same_cl_p;
438 struct blockinfo_t* next;
439 struct blockinfo_t** prev_p;
440
441 uae_u8 optlevel;
442 uae_u8 needed_flags;
443 uae_u8 status;
444 uae_u8 havestate;
445
446 dependency dep[2]; /* Holds things we depend on */
447 dependency* deplist; /* List of things that depend on this */
448 smallstate env;
449
450 #ifdef JIT_DEBUG
451 /* (gb) size of the compiled block (direct handler) */
452 uae_u32 direct_handler_size;
453 #endif
454 } blockinfo;
455
456 #define BI_INVALID 0
457 #define BI_ACTIVE 1
458 #define BI_NEED_RECOMP 2
459 #define BI_NEED_CHECK 3
460 #define BI_CHECKING 4
461 #define BI_COMPILING 5
462 #define BI_FINALIZING 6
463
464 void execute_normal(void);
465 void exec_nostats(void);
466 void do_nothing(void);
467
468 #else
469
flush_icache(int)470 static inline void flush_icache(int) { }
471
472 #endif /* !USE_JIT */
473
474 #ifdef UAE
475
476 typedef struct {
477 uae_u8 type;
478 uae_u8 reg;
479 uae_u32 next;
480 } regacc;
481
482 #define JIT_EXCEPTION_HANDLER
483 // #define JIT_ALWAYS_DISTRUST
484
485 /* ARAnyM uses fpu_register name, used in scratch_t */
486 /* FIXME: check that no ARAnyM code assumes different floating point type */
487 typedef fptype fpu_register;
488
489 extern void compile_block(cpu_history* pc_hist, int blocklen, int totcyles);
490
491 #define MAXCYCLES (1000 * CYCLE_UNIT)
492 #define scaled_cycles(x) (currprefs.m68k_speed<0?(((x)/SCALE)?(((x)/SCALE<MAXCYCLES?((x)/SCALE):MAXCYCLES)):1):(x))
493
494 /* Flags for Bernie during development/debugging. Should go away eventually */
495 #define DISTRUST_CONSISTENT_MEM 0
496
497 typedef struct {
498 uae_u8 use_flags;
499 uae_u8 set_flags;
500 uae_u8 is_jump;
501 uae_u8 is_addx;
502 uae_u8 is_const_jump;
503 } op_properties;
504
505 extern op_properties prop[65536];
506
end_block(uae_u16 opcode)507 STATIC_INLINE int end_block(uae_u16 opcode)
508 {
509 return prop[opcode].is_jump ||
510 (prop[opcode].is_const_jump && !currprefs.comp_constjump);
511 }
512
513 #ifdef _WIN32
514 LONG WINAPI EvalException(LPEXCEPTION_POINTERS info);
515 #if defined(_MSC_VER) && !defined(NO_WIN32_EXCEPTION_HANDLER)
516 #ifdef _WIN64
517 /* Structured exception handling is table based for Windows x86-64, so
518 * Windows will not be able to find the exception handler. */
519 #else
520 #define USE_STRUCTURED_EXCEPTION_HANDLING
521 #endif
522 #endif
523 #endif
524
525 void jit_abort(const char *format,...);
526 #if SIZEOF_TCHAR != 1
527 void jit_abort(const TCHAR *format, ...);
528 #endif
529
530 #else
531
532 #ifdef WINUAE_ARANYM
533 #define jit_log(format, ...) D(bug(format, ##__VA_ARGS__))
534 #define jit_log2(format, ...) D2(bug(format, ##__VA_ARGS__))
535 void jit_abort(const char *format,...) __attribute__((format(printf, 1, 2))) __attribute__((__noreturn__));
536 #else
537 #define jit_abort(...) abort()
538 #define jit_log panicbug
539 #define jit_log2(...)
540 #endif
541
542 #endif /* UAE */
543
544 #ifdef CPU_64_BIT
check_uae_p32(uintptr address,const char * file,int line)545 static inline uae_u32 check_uae_p32(uintptr address, const char *file, int line)
546 {
547 if (address > (uintptr_t) 0xffffffff) {
548 jit_abort("JIT: 64-bit pointer (0x%llx) at %s:%d (fatal)",
549 (unsigned long long)address, file, line);
550 }
551 return (uae_u32) address;
552 }
553 #define uae_p32(x) (check_uae_p32((uintptr)(x), __FILE__, __LINE__))
554 #else
555 #define uae_p32(x) ((uae_u32)(x))
556 #endif
557
558 #endif /* COMPEMU_H */
559