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