Annotation of hatari/src/cpu/jit/compemu.h, revision 1.1.1.5

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.