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