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