Annotation of hatari/src/cpu/jit/compemu_support.c, revision 1.1.1.5

1.1.1.3   root        1: /*
                      2:  * compiler/compemu_support.cpp - Core dynamic translation engine
                      3:  *
                      4:  * Copyright (c) 2001-2009 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 / ARM
                     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:  */
                     31: 
                     32: #ifdef UAE
1.1       root       33: 
                     34: #define writemem_special writemem
                     35: #define readmem_special  readmem
                     36: 
1.1.1.3   root       37: #else
                     38: #if !FIXED_ADDRESSING
                     39: #error "Only Fixed Addressing is supported with the JIT Compiler"
                     40: #endif
                     41: 
                     42: #if defined(X86_ASSEMBLY) && !SAHF_SETO_PROFITABLE
                     43: #error "Only [LS]AHF scheme to [gs]et flags is supported with the JIT Compiler"
                     44: #endif
                     45: 
                     46: /* NOTE: support for AMD64 assumes translation cache and other code
                     47:  * buffers are allocated into a 32-bit address space because (i) B2/JIT
                     48:  * code is not 64-bit clean and (ii) it's faster to resolve branches
                     49:  * that way.
                     50:  */
                     51: #if !defined(CPU_i386) && !defined(CPU_x86_64) && !defined(CPU_arm)
                     52: #error "Only IA-32, X86-64 and ARM v6 targets are supported with the JIT Compiler"
                     53: #endif
                     54: #endif
                     55: 
                     56: #define USE_MATCH 0
                     57: 
                     58: /* kludge for Brian, so he can compile under MSVC++ */
                     59: #define USE_NORMAL_CALLING_CONVENTION 0
                     60: 
1.1       root       61: #include "sysconfig.h"
                     62: #include "sysdeps.h"
                     63: 
1.1.1.3   root       64: #ifdef JIT
1.1       root       65: 
1.1.1.3   root       66: #ifdef UAE
1.1       root       67: #include "options.h"
                     68: #include "events.h"
1.1.1.3   root       69: #include "memory.h"
1.1       root       70: #include "custom.h"
1.1.1.3   root       71: #else
                     72: #include "cpu_emulation.h"
                     73: #include "main.h"
                     74: #include "vm_alloc.h"
                     75: 
                     76: #include "m68k.h"
                     77: #include "memory-uae.h"
                     78: #include "readcpu.h"
                     79: #endif
1.1       root       80: #include "newcpu.h"
                     81: #include "comptbl.h"
1.1.1.3   root       82: #ifdef UAE
1.1       root       83: #include "compemu.h"
1.1.1.3   root       84: #else
                     85: #include "compiler/compemu.h"
                     86: #include "fpu/fpu.h"
                     87: #include "fpu/flags.h"
                     88: #include "parameters.h"
                     89: #endif
                     90: 
                     91: #ifdef UAE
                     92: #include "uae/log.h"
                     93: 
                     94: #include "uae/vm.h"
                     95: #define VM_PAGE_READ UAE_VM_READ
                     96: #define VM_PAGE_WRITE UAE_VM_WRITE
                     97: #define VM_PAGE_EXECUTE UAE_VM_EXECUTE
                     98: #define VM_MAP_FAILED UAE_VM_ALLOC_FAILED
                     99: #define VM_MAP_DEFAULT 1
                    100: #define VM_MAP_32BIT 1
                    101: #define vm_protect(address, size, protect) uae_vm_protect(address, size, protect)
                    102: #define vm_release(address, size) uae_vm_free(address, size)
                    103: 
                    104: static inline void *vm_acquire(size_t size, int options = VM_MAP_DEFAULT)
                    105: {
                    106:        assert(options == (VM_MAP_DEFAULT | VM_MAP_32BIT));
                    107:        return uae_vm_alloc(size, UAE_VM_32BIT, UAE_VM_READ_WRITE);
                    108: }
                    109: 
                    110: #define UNUSED(x)
                    111: #include "uae.h"
                    112: #include "uae/log.h"
                    113: #define jit_log(format, ...) \
                    114:        uae_log("JIT: " format "\n", ##__VA_ARGS__);
                    115: #define jit_log2(format, ...)
1.1       root      116: 
1.1.1.3   root      117: #define MEMBaseDiff uae_p32(NATMEM_OFFSET)
1.1       root      118: 
1.1.1.3   root      119: #ifdef NATMEM_OFFSET
                    120: #define FIXED_ADDRESSING 1
                    121: #endif
                    122: 
                    123: #define SAHF_SETO_PROFITABLE
1.1       root      124: 
                    125: // %%% BRIAN KING WAS HERE %%%
                    126: extern bool canbang;
1.1.1.3   root      127: 
                    128: #include "compemu_prefs.cpp"
                    129: 
                    130: #define uint32 uae_u32
                    131: #define uint8 uae_u8
                    132: 
                    133: static inline int distrust_check(int value)
                    134: {
                    135: #ifdef JIT_ALWAYS_DISTRUST
                    136:        return 1;
                    137: #else
                    138:        int distrust = value;
                    139:        return distrust;
                    140: #endif
                    141: }
                    142: 
                    143: static inline int distrust_byte(void)
                    144: {
                    145:        return distrust_check(currprefs.comptrustbyte);
                    146: }
                    147: 
                    148: static inline int distrust_word(void)
                    149: {
                    150:        return distrust_check(currprefs.comptrustword);
                    151: }
                    152: 
                    153: static inline int distrust_long(void)
                    154: {
                    155:        return distrust_check(currprefs.comptrustlong);
                    156: }
                    157: 
                    158: static inline int distrust_addr(void)
                    159: {
                    160:        return distrust_check(currprefs.comptrustnaddr);
                    161: }
                    162: 
                    163: #else
                    164: #define DEBUG 0
                    165: #include "debug.h"
                    166: 
1.1.1.5 ! root      167: #define NATMEM_OFFSET MEMBaseDiff
        !           168: #define canbang 1
        !           169: #define op_illg op_illg_1
        !           170: 
        !           171: #ifdef WINUAE_ARANYM
        !           172: void jit_abort(const char *format, ...)
        !           173: {
        !           174:        va_list args;
        !           175:        va_start(args, format);
        !           176:        ndebug::pdbvprintf(format, args);
        !           177:        va_end(args);
        !           178:        abort();
        !           179: }
        !           180: #endif
        !           181: 
1.1.1.3   root      182: #if DEBUG
                    183: #define PROFILE_COMPILE_TIME           1
                    184: #define PROFILE_UNTRANSLATED_INSNS     1
                    185: #endif
                    186: #endif
                    187: 
                    188: # include <csignal>
                    189: # include <cstdlib>
                    190: # include <cerrno>
                    191: # include <cassert>
                    192: 
                    193: #if defined(CPU_x86_64) && 0
                    194: #define RECORD_REGISTER_USAGE          1
                    195: #endif
                    196: 
                    197: #ifdef JIT_DEBUG
                    198: #undef abort
                    199: #define abort() do { \
                    200:        fprintf(stderr, "Abort in file %s at line %d\n", __FILE__, __LINE__); \
                    201:        compiler_dumpstate(); \
                    202:        exit(EXIT_FAILURE); \
                    203: } while (0)
                    204: #endif
                    205: 
                    206: #ifdef RECORD_REGISTER_USAGE
                    207: static uint64 reg_count[16];
                    208: static int reg_count_local[16];
                    209: 
                    210: static int reg_count_compare(const void *ap, const void *bp)
                    211: {
                    212:     const int a = *((int *)ap);
                    213:     const int b = *((int *)bp);
                    214:     return reg_count[b] - reg_count[a];
                    215: }
                    216: #endif
                    217: 
                    218: #ifdef PROFILE_COMPILE_TIME
                    219: #include <time.h>
                    220: static uae_u32 compile_count   = 0;
                    221: static clock_t compile_time            = 0;
                    222: static clock_t emul_start_time = 0;
                    223: static clock_t emul_end_time   = 0;
                    224: #endif
                    225: 
                    226: #ifdef PROFILE_UNTRANSLATED_INSNS
1.1.1.5 ! root      227: static const int untranslated_top_ten = 50;
1.1.1.3   root      228: static uae_u32 raw_cputbl_count[65536] = { 0, };
                    229: static uae_u16 opcode_nums[65536];
                    230: 
                    231: 
                    232: static int untranslated_compfn(const void *e1, const void *e2)
                    233: {
                    234:        return raw_cputbl_count[*(const uae_u16 *)e1] < raw_cputbl_count[*(const uae_u16 *)e2];
                    235: }
                    236: #endif
                    237: 
                    238: static compop_func *compfunctbl[65536];
                    239: static compop_func *nfcompfunctbl[65536];
1.1       root      240: #ifdef NOFLAGS_SUPPORT
1.1.1.3   root      241: static cpuop_func *nfcpufunctbl[65536];
1.1       root      242: #endif
                    243: uae_u8* comp_pc_p;
                    244: 
1.1.1.3   root      245: #ifdef UAE
                    246: /* defined in uae.h */
                    247: #else
                    248: // External variables
                    249: // newcpu.cpp
                    250: extern int quit_program;
                    251: #endif
                    252: 
                    253: // gb-- Extra data for Basilisk II/JIT
                    254: #ifdef JIT_DEBUG
                    255: static bool            JITDebug                        = false;        // Enable runtime disassemblers through mon?
                    256: #else
                    257: const bool             JITDebug                        = false;        // Don't use JIT debug mode at all
                    258: #endif
                    259: #if USE_INLINING
                    260: #ifdef UAE
                    261: #define follow_const_jumps (currprefs.comp_constjump != 0)
                    262: #else
                    263: static bool follow_const_jumps = true; // Flag: translation through constant jumps
                    264: #endif
                    265: #else
                    266: const bool follow_const_jumps = false;
                    267: #endif
                    268: 
                    269: const uae_u32 MIN_CACHE_SIZE = 1024; // Minimal translation cache size (1 MB)
                    270: static uae_u32 cache_size = 0; // Size of total cache allocated for compiled blocks
                    271: static uae_u32         current_cache_size      = 0;            // Cache grows upwards: how much has been consumed already
                    272: static bool            lazy_flush              = true; // Flag: lazy translation cache invalidation
                    273: #ifdef UAE
                    274: #ifdef USE_JIT_FPU
                    275: #define avoid_fpu (!currprefs.compfpu)
                    276: #else
                    277: #define avoid_fpu (true)
                    278: #endif
                    279: #else
                    280: static bool avoid_fpu = true; // Flag: compile FPU instructions ?
                    281: #endif
                    282: static bool            have_cmov               = false;        // target has CMOV instructions ?
                    283: static bool            have_rat_stall          = true; // target has partial register stalls ?
                    284: const bool             tune_alignment          = true; // Tune code alignments for running CPU ?
                    285: const bool             tune_nop_fillers        = true; // Tune no-op fillers for architecture
                    286: static bool            setzflg_uses_bsf        = false;        // setzflg virtual instruction can use native BSF instruction correctly?
                    287: static int             align_loops             = 32;   // Align the start of loops
                    288: static int             align_jumps             = 32;   // Align the start of jumps
                    289: static int             optcount[10]            = {
                    290: #ifdef UAE
                    291:        4,              // How often a block has to be executed before it is translated
                    292: #else
                    293:        10,             // How often a block has to be executed before it is translated
                    294: #endif
                    295:        0,              // How often to use naive translation
                    296:        0, 0, 0, 0,
                    297:        -1, -1, -1, -1
                    298: };
                    299: 
                    300: #ifdef UAE
                    301: /* FIXME: op_properties is currently in compemu.h */
                    302: 
                    303: op_properties prop[65536];
                    304: 
                    305: static inline bool is_const_jump(uae_u32 opcode)
                    306: {
                    307:        return prop[opcode].is_const_jump != 0;
                    308: }
                    309: #else
                    310: struct op_properties {
                    311:        uae_u8 use_flags;
                    312:        uae_u8 set_flags;
                    313:        uae_u8 is_addx;
                    314:        uae_u8 cflow;
                    315: };
                    316: static op_properties prop[65536];
                    317: 
                    318: static inline int end_block(uae_u32 opcode)
                    319: {
                    320:        return (prop[opcode].cflow & fl_end_block);
                    321: }
                    322: 
                    323: static inline bool is_const_jump(uae_u32 opcode)
                    324: {
                    325:        return (prop[opcode].cflow == fl_const_jump);
                    326: }
                    327: 
1.1.1.5 ! root      328: #if 0
1.1.1.3   root      329: static inline bool may_trap(uae_u32 opcode)
                    330: {
                    331:        return (prop[opcode].cflow & fl_trap);
                    332: }
1.1.1.5 ! root      333: #endif
1.1.1.3   root      334: 
                    335: #endif
                    336: 
                    337: static inline unsigned int cft_map (unsigned int f)
                    338: {
                    339: #ifdef UAE
                    340:        return f;
                    341: #else
                    342: #if !defined(HAVE_GET_WORD_UNSWAPPED) || defined(FULLMMU)
                    343:        return f;
                    344: #else
                    345:        return ((f >> 8) & 255) | ((f & 255) << 8);
                    346: #endif
                    347: #endif
                    348: }
                    349: 
1.1       root      350: uae_u8* start_pc_p;
                    351: uae_u32 start_pc;
                    352: uae_u32 current_block_pc_p;
1.1.1.3   root      353: static uintptr current_block_start_target;
1.1       root      354: uae_u32 needed_flags;
1.1.1.3   root      355: static uintptr next_pc_p;
                    356: static uintptr taken_pc_p;
1.1       root      357: static int     branch_cc;
1.1.1.3   root      358: static int redo_current_block;
                    359: 
1.1       root      360: static uae_u8* current_compile_p=NULL;
                    361: static uae_u8* max_compile_start;
1.1.1.3   root      362: static uae_u8* compiled_code=NULL;
1.1       root      363: static uae_s32 reg_alloc_run;
1.1.1.3   root      364: const int POPALLSPACE_SIZE = 2048; /* That should be enough space */
                    365: static uae_u8 *popallspace=NULL;
1.1       root      366: 
                    367: void* pushall_call_handler=NULL;
                    368: static void* popall_do_nothing=NULL;
                    369: static void* popall_exec_nostats=NULL;
                    370: static void* popall_execute_normal=NULL;
                    371: static void* popall_cache_miss=NULL;
                    372: static void* popall_recompile_block=NULL;
                    373: static void* popall_check_checksum=NULL;
                    374: 
                    375: /* The 68k only ever executes from even addresses. So right now, we
1.1.1.3   root      376:  * waste half the entries in this array
                    377:  * UPDATE: We now use those entries to store the start of the linked
                    378:  * lists that we maintain for each hash result.
                    379:  */
1.1.1.5 ! root      380: static cacheline cache_tags[TAGSIZE];
        !           381: static int cache_enabled=0;
        !           382: static blockinfo* hold_bi[MAX_HOLD_BI];
        !           383: static blockinfo* active;
        !           384: static blockinfo* dormant;
1.1       root      385: 
                    386: #ifdef NOFLAGS_SUPPORT
                    387: /* 68040 */
1.1.1.3   root      388: extern const struct cputbl op_smalltbl_0_nf[];
1.1       root      389: #endif
                    390: extern const struct comptbl op_smalltbl_0_comp_nf[];
                    391: extern const struct comptbl op_smalltbl_0_comp_ff[];
1.1.1.3   root      392: 
1.1       root      393: #ifdef NOFLAGS_SUPPORT
                    394: /* 68020 + 68881 */
                    395: extern const struct cputbl op_smalltbl_1_nf[];
                    396: /* 68020 */
                    397: extern const struct cputbl op_smalltbl_2_nf[];
                    398: /* 68010 */
                    399: extern const struct cputbl op_smalltbl_3_nf[];
                    400: /* 68000 */
                    401: extern const struct cputbl op_smalltbl_4_nf[];
                    402: /* 68000 slow but compatible.  */
                    403: extern const struct cputbl op_smalltbl_5_nf[];
                    404: #endif
                    405: 
1.1.1.5 ! root      406: #ifdef WINUAE_ARANYM
        !           407: static void flush_icache_hard(int n);
        !           408: static void flush_icache_lazy(int n);
        !           409: static void flush_icache_none(int n);
        !           410: void (*flush_icache)(int n) = flush_icache_none;
        !           411: #endif
        !           412: 
        !           413: static bigstate live;
        !           414: static smallstate empty_ss;
        !           415: static smallstate default_ss;
1.1       root      416: static int optlev;
                    417: 
                    418: static int writereg(int r, int size);
1.1.1.3   root      419: static void unlock2(int r);
1.1       root      420: static void setlock(int r);
                    421: static int readreg_specific(int r, int size, int spec);
                    422: static int writereg_specific(int r, int size, int spec);
                    423: static void prepare_for_call_1(void);
                    424: static void prepare_for_call_2(void);
                    425: static void align_target(uae_u32 a);
                    426: 
1.1.1.3   root      427: static void inline flush_cpu_icache(void *from, void *to);
                    428: static void inline write_jmp_target(uae_u32 *jmpaddr, cpuop_func* a);
                    429: static void inline emit_jmp_target(uae_u32 a);
1.1       root      430: 
                    431: uae_u32 m68k_pc_offset;
                    432: 
                    433: /* Some arithmetic operations can be optimized away if the operands
1.1.1.3   root      434:  * are known to be constant. But that's only a good idea when the
                    435:  * side effects they would have on the flags are not important. This
                    436:  * variable indicates whether we need the side effects or not
                    437:  */
1.1.1.5 ! root      438: static uae_u32 needflags=0;
1.1       root      439: 
                    440: /* Flag handling is complicated.
1.1.1.3   root      441:  *
                    442:  * x86 instructions create flags, which quite often are exactly what we
                    443:  * want. So at times, the "68k" flags are actually in the x86 flags.
                    444:  *
                    445:  * Then again, sometimes we do x86 instructions that clobber the x86
                    446:  * flags, but don't represent a corresponding m68k instruction. In that
                    447:  * case, we have to save them.
                    448:  *
                    449:  * We used to save them to the stack, but now store them back directly
                    450:  * into the regflags.cznv of the traditional emulation. Thus some odd
                    451:  * names.
                    452:  *
                    453:  * So flags can be in either of two places (used to be three; boy were
                    454:  * things complicated back then!); And either place can contain either
                    455:  * valid flags or invalid trash (and on the stack, there was also the
                    456:  * option of "nothing at all", now gone). A couple of variables keep
                    457:  * track of the respective states.
                    458:  *
                    459:  * To make things worse, we might or might not be interested in the flags.
                    460:  * by default, we are, but a call to dont_care_flags can change that
                    461:  * until the next call to live_flags. If we are not, pretty much whatever
                    462:  * is in the register and/or the native flags is seen as valid.
                    463:  */
1.1       root      464: 
1.1.1.3   root      465: static inline blockinfo* get_blockinfo(uae_u32 cl)
1.1       root      466: {
                    467:        return cache_tags[cl+1].bi;
                    468: }
                    469: 
1.1.1.3   root      470: static inline blockinfo* get_blockinfo_addr(void* addr)
1.1       root      471: {
                    472:        blockinfo*  bi=get_blockinfo(cacheline(addr));
                    473: 
                    474:        while (bi) {
                    475:                if (bi->pc_p==addr)
                    476:                        return bi;
                    477:                bi=bi->next_same_cl;
                    478:        }
                    479:        return NULL;
                    480: }
                    481: 
1.1.1.5 ! root      482: #ifdef WINUAE_ARANYM
        !           483: /*******************************************************************
        !           484:  * Disassembler support                                            *
        !           485:  *******************************************************************/
        !           486: 
        !           487: #define TARGET_M68K            0
        !           488: #define TARGET_POWERPC 1
        !           489: #define TARGET_X86             2
        !           490: #define TARGET_X86_64  3
        !           491: #define TARGET_ARM             4
        !           492: #if defined(CPU_i386)
        !           493: #define TARGET_NATIVE  TARGET_X86
        !           494: #endif
        !           495: #if defined(CPU_powerpc)
        !           496: #define TARGET_NATIVE  TARGET_POWERPC
        !           497: #endif
        !           498: #if defined(CPU_x86_64)
        !           499: #define TARGET_NATIVE  TARGET_X86_64
        !           500: #endif
        !           501: #if defined(CPU_arm)
        !           502: #define TARGET_NATIVE  TARGET_ARM
        !           503: #endif
        !           504: #include "disasm-glue.h"
        !           505: 
        !           506: #ifdef JIT_DEBUG
        !           507: static void disasm_block(int disasm_target, const uint8 *start, size_t length)
        !           508: {
        !           509:        UNUSED(start);
        !           510:        UNUSED(length);
        !           511:        switch (disasm_target)
        !           512:        {
        !           513:        case TARGET_M68K:
        !           514: #if defined(HAVE_DISASM_M68K)
        !           515:                {
        !           516:                        char buf[256];
        !           517: 
        !           518:                        disasm_info.memory_vma = ((memptr)((uintptr_t)(start) - MEMBaseDiff));
        !           519:                        while (length > 0)
        !           520:                        {
        !           521:                                int isize = m68k_disasm_to_buf(&disasm_info, buf);
        !           522:                                bug("%s", buf);
        !           523:                                if (isize < 0)
        !           524:                                        break;
        !           525:                                if ((uintptr)isize > length)
        !           526:                                        break;
        !           527:                                length -= isize;
        !           528:                        }
        !           529:                }
        !           530: #endif
        !           531:                break;
        !           532:        case TARGET_X86:
        !           533:        case TARGET_X86_64:
        !           534: #if defined(HAVE_DISASM_X86)
        !           535:                {
        !           536:                        const uint8 *end = start + length;
        !           537:                        char buf[256];
        !           538: 
        !           539:                        while (start < end)
        !           540:                        {
        !           541:                                start = x86_disasm(start, buf);
        !           542:                                bug("%s", buf);
        !           543:                        }
        !           544:                }
        !           545: #endif
        !           546:                break;
        !           547:        case TARGET_ARM:
        !           548: #if defined(HAVE_DISASM_ARM)
        !           549:                {
        !           550:                        const uint8 *end = start + length;
        !           551:                        char buf[256];
        !           552: 
        !           553:                        while (start < end)
        !           554:                        {
        !           555:                                start = arm_disasm(start, buf);
        !           556:                                bug("%s", buf);
        !           557:                        }
        !           558:                }
        !           559: #endif
        !           560:                break;
        !           561:        }
        !           562: }
        !           563: 
        !           564: static inline void disasm_native_block(const uint8 *start, size_t length)
        !           565: {
        !           566:        disasm_block(TARGET_NATIVE, start, length);
        !           567: }
        !           568: 
        !           569: static inline void disasm_m68k_block(const uint8 *start, size_t length)
        !           570: {
        !           571:        disasm_block(TARGET_M68K, start, length);
        !           572: }
        !           573: #endif
        !           574: #endif
        !           575: 
1.1       root      576: 
                    577: /*******************************************************************
1.1.1.3   root      578:  * All sorts of list related functions for all of the lists        *
                    579:  *******************************************************************/
1.1       root      580: 
1.1.1.3   root      581: static inline void remove_from_cl_list(blockinfo* bi)
1.1       root      582: {
                    583:        uae_u32 cl=cacheline(bi->pc_p);
                    584: 
                    585:        if (bi->prev_same_cl_p)
                    586:                *(bi->prev_same_cl_p)=bi->next_same_cl;
                    587:        if (bi->next_same_cl)
                    588:                bi->next_same_cl->prev_same_cl_p=bi->prev_same_cl_p;
                    589:        if (cache_tags[cl+1].bi)
                    590:                cache_tags[cl].handler=cache_tags[cl+1].bi->handler_to_use;
                    591:        else
                    592:                cache_tags[cl].handler=(cpuop_func*)popall_execute_normal;
                    593: }
                    594: 
1.1.1.3   root      595: static inline void remove_from_list(blockinfo* bi)
1.1       root      596: {
                    597:        if (bi->prev_p)
                    598:                *(bi->prev_p)=bi->next;
                    599:        if (bi->next)
                    600:                bi->next->prev_p=bi->prev_p;
                    601: }
                    602: 
1.1.1.5 ! root      603: #if 0
1.1.1.3   root      604: static inline void remove_from_lists(blockinfo* bi)
1.1       root      605: {
                    606:        remove_from_list(bi);
                    607:        remove_from_cl_list(bi);
                    608: }
1.1.1.5 ! root      609: #endif
1.1       root      610: 
1.1.1.3   root      611: static inline void add_to_cl_list(blockinfo* bi)
1.1       root      612: {
                    613:        uae_u32 cl=cacheline(bi->pc_p);
                    614: 
                    615:        if (cache_tags[cl+1].bi)
                    616:                cache_tags[cl+1].bi->prev_same_cl_p=&(bi->next_same_cl);
                    617:        bi->next_same_cl=cache_tags[cl+1].bi;
                    618: 
                    619:        cache_tags[cl+1].bi=bi;
                    620:        bi->prev_same_cl_p=&(cache_tags[cl+1].bi);
                    621: 
                    622:        cache_tags[cl].handler=bi->handler_to_use;
                    623: }
                    624: 
1.1.1.3   root      625: static inline void raise_in_cl_list(blockinfo* bi)
1.1       root      626: {
                    627:        remove_from_cl_list(bi);
                    628:        add_to_cl_list(bi);
                    629: }
                    630: 
1.1.1.3   root      631: static inline void add_to_active(blockinfo* bi)
1.1       root      632: {
                    633:        if (active)
                    634:                active->prev_p=&(bi->next);
                    635:        bi->next=active;
                    636: 
                    637:        active=bi;
                    638:        bi->prev_p=&active;
                    639: }
                    640: 
1.1.1.3   root      641: static inline void add_to_dormant(blockinfo* bi)
1.1       root      642: {
                    643:        if (dormant)
                    644:                dormant->prev_p=&(bi->next);
                    645:        bi->next=dormant;
                    646: 
                    647:        dormant=bi;
                    648:        bi->prev_p=&dormant;
                    649: }
                    650: 
1.1.1.3   root      651: static inline void remove_dep(dependency* d)
1.1       root      652: {
                    653:        if (d->prev_p)
                    654:                *(d->prev_p)=d->next;
                    655:        if (d->next)
                    656:                d->next->prev_p=d->prev_p;
                    657:        d->prev_p=NULL;
                    658:        d->next=NULL;
                    659: }
                    660: 
                    661: /* This block's code is about to be thrown away, so it no longer
1.1.1.3   root      662:    depends on anything else */
                    663: static inline void remove_deps(blockinfo* bi)
1.1       root      664: {
                    665:        remove_dep(&(bi->dep[0]));
                    666:        remove_dep(&(bi->dep[1]));
                    667: }
                    668: 
1.1.1.3   root      669: static inline void adjust_jmpdep(dependency* d, cpuop_func* a)
1.1       root      670: {
1.1.1.3   root      671:        write_jmp_target(d->jmp_off, a);
1.1       root      672: }
                    673: 
                    674: /********************************************************************
1.1.1.3   root      675:  * Soft flush handling support functions                            *
                    676:  ********************************************************************/
1.1       root      677: 
1.1.1.3   root      678: static inline void set_dhtu(blockinfo* bi, cpuop_func *dh)
1.1       root      679: {
1.1.1.3   root      680:        jit_log2("bi is %p",bi);
1.1       root      681:        if (dh!=bi->direct_handler_to_use) {
                    682:                dependency* x=bi->deplist;
1.1.1.3   root      683:                jit_log2("bi->deplist=%p",bi->deplist);
1.1       root      684:                while (x) {
1.1.1.3   root      685:                        jit_log2("x is %p",x);
                    686:                        jit_log2("x->next is %p",x->next);
                    687:                        jit_log2("x->prev_p is %p",x->prev_p);
1.1       root      688: 
                    689:                        if (x->jmp_off) {
                    690:                                adjust_jmpdep(x,dh);
                    691:                        }
                    692:                        x=x->next;
                    693:                }
1.1.1.3   root      694:                bi->direct_handler_to_use=dh;
1.1       root      695:        }
                    696: }
                    697: 
1.1.1.3   root      698: static inline void invalidate_block(blockinfo* bi)
1.1       root      699: {
                    700:        int i;
                    701: 
                    702:        bi->optlevel=0;
1.1.1.3   root      703:        bi->count=optcount[0]-1;
1.1       root      704:        bi->handler=NULL;
                    705:        bi->handler_to_use=(cpuop_func*)popall_execute_normal;
                    706:        bi->direct_handler=NULL;
                    707:        set_dhtu(bi,bi->direct_pen);
                    708:        bi->needed_flags=0xff;
1.1.1.3   root      709:        bi->status=BI_INVALID;
1.1       root      710:        for (i=0;i<2;i++) {
                    711:                bi->dep[i].jmp_off=NULL;
                    712:                bi->dep[i].target=NULL;
                    713:        }
                    714:        remove_deps(bi);
                    715: }
                    716: 
1.1.1.3   root      717: static inline void create_jmpdep(blockinfo* bi, int i, uae_u32* jmpaddr, uae_u32 target)
1.1       root      718: {
1.1.1.3   root      719:        blockinfo*  tbi=get_blockinfo_addr((void*)(uintptr)target);
1.1       root      720: 
                    721:        Dif(!tbi) {
1.1.1.3   root      722:                jit_abort("Could not create jmpdep!");
1.1       root      723:        }
                    724:        bi->dep[i].jmp_off=jmpaddr;
1.1.1.3   root      725:        bi->dep[i].source=bi;
1.1       root      726:        bi->dep[i].target=tbi;
                    727:        bi->dep[i].next=tbi->deplist;
                    728:        if (bi->dep[i].next)
                    729:                bi->dep[i].next->prev_p=&(bi->dep[i].next);
                    730:        bi->dep[i].prev_p=&(tbi->deplist);
                    731:        tbi->deplist=&(bi->dep[i]);
                    732: }
                    733: 
1.1.1.3   root      734: static inline void block_need_recompile(blockinfo * bi)
1.1       root      735: {
1.1.1.3   root      736:        uae_u32 cl = cacheline(bi->pc_p);
1.1       root      737: 
1.1.1.3   root      738:        set_dhtu(bi, bi->direct_pen);
                    739:        bi->direct_handler = bi->direct_pen;
1.1       root      740: 
1.1.1.3   root      741:        bi->handler_to_use = (cpuop_func *)popall_execute_normal;
                    742:        bi->handler = (cpuop_func *)popall_execute_normal;
                    743:        if (bi == cache_tags[cl + 1].bi)
                    744:                cache_tags[cl].handler = (cpuop_func *)popall_execute_normal;
                    745:        bi->status = BI_NEED_RECOMP;
                    746: }
                    747: 
1.1.1.5 ! root      748: #if USE_MATCH
1.1.1.3   root      749: static inline void mark_callers_recompile(blockinfo * bi)
                    750: {
                    751:   dependency *x = bi->deplist;
                    752: 
1.1.1.5 ! root      753:   while (x) {
1.1.1.3   root      754:        dependency *next = x->next;     /* This disappears when we mark for
                    755:                                                                 * recompilation and thus remove the
                    756:                                                                 * blocks from the lists */
                    757:        if (x->jmp_off) {
                    758:          blockinfo *cbi = x->source;
                    759: 
                    760:          Dif(cbi->status == BI_INVALID) {
                    761:                jit_log("invalid block in dependency list"); // FIXME?
                    762:                // abort();
                    763:          }
                    764:          if (cbi->status == BI_ACTIVE || cbi->status == BI_NEED_CHECK) {
                    765:                block_need_recompile(cbi);
                    766:                mark_callers_recompile(cbi);
                    767:          }
                    768:          else if (cbi->status == BI_COMPILING) {
                    769:                redo_current_block = 1;
                    770:          }
                    771:          else if (cbi->status == BI_NEED_RECOMP) {
                    772:                /* nothing */
                    773:          }
                    774:          else {
                    775:                jit_log2("Status %d in mark_callers",cbi->status); // FIXME?
                    776:          }
                    777:        }
                    778:        x = next;
                    779:   }
1.1       root      780: }
1.1.1.5 ! root      781: #endif
1.1       root      782: 
1.1.1.3   root      783: static inline blockinfo* get_blockinfo_addr_new(void* addr, int /* setstate */)
1.1       root      784: {
                    785:        blockinfo*  bi=get_blockinfo_addr(addr);
                    786:        int i;
                    787: 
                    788:        if (!bi) {
                    789:                for (i=0;i<MAX_HOLD_BI && !bi;i++) {
                    790:                        if (hold_bi[i]) {
1.1.1.3   root      791:                                (void)cacheline(addr);
1.1       root      792: 
                    793:                                bi=hold_bi[i];
                    794:                                hold_bi[i]=NULL;
                    795:                                bi->pc_p=(uae_u8*)addr;
                    796:                                invalidate_block(bi);
                    797:                                add_to_active(bi);
                    798:                                add_to_cl_list(bi);
                    799: 
                    800:                        }
                    801:                }
                    802:        }
                    803:        if (!bi) {
1.1.1.3   root      804:                jit_abort("Looking for blockinfo, can't find free one");
                    805:        }
                    806:        return bi;
                    807: }
                    808: 
                    809: static void prepare_block(blockinfo* bi);
                    810: 
1.1.1.4   root      811: /* Management of blockinfos.
1.1.1.3   root      812: 
                    813:    A blockinfo struct is allocated whenever a new block has to be
                    814:    compiled. If the list of free blockinfos is empty, we allocate a new
                    815:    pool of blockinfos and link the newly created blockinfos altogether
                    816:    into the list of free blockinfos. Otherwise, we simply pop a structure
                    817:    of the free list.
                    818: 
                    819:    Blockinfo are lazily deallocated, i.e. chained altogether in the
                    820:    list of free blockinfos whenvever a translation cache flush (hard or
                    821:    soft) request occurs.
                    822: */
                    823: 
                    824: template< class T >
                    825: class LazyBlockAllocator
                    826: {
                    827:        enum {
                    828:                kPoolSize = 1 + (16384 - sizeof(T) - sizeof(void *)) / sizeof(T)
                    829:        };
                    830:        struct Pool {
                    831:                T chunk[kPoolSize];
                    832:                Pool * next;
                    833:        };
                    834:        Pool * mPools;
                    835:        T * mChunks;
                    836: public:
                    837:        LazyBlockAllocator() : mPools(0), mChunks(0) { }
                    838: #ifdef UAE
                    839: #else
                    840:        ~LazyBlockAllocator();
                    841: #endif
                    842:        T * acquire();
                    843:        void release(T * const);
                    844: };
                    845: 
                    846: #ifdef UAE
                    847: /* uae_vm_release may do logging, which isn't safe to do when the application
                    848:  * is shutting down. Better to release memory manually with a function call
                    849:  * to a release_all method on shutdown, or even simpler, just let the OS
                    850:  * handle it (we're shutting down anyway). */
                    851: #else
                    852: template< class T >
                    853: LazyBlockAllocator<T>::~LazyBlockAllocator()
                    854: {
                    855:        Pool * currentPool = mPools;
                    856:        while (currentPool) {
                    857:                Pool * deadPool = currentPool;
                    858:                currentPool = currentPool->next;
                    859:                vm_release(deadPool, sizeof(Pool));
                    860:        }
                    861: }
                    862: #endif
                    863: 
                    864: template< class T >
                    865: T * LazyBlockAllocator<T>::acquire()
                    866: {
                    867:        if (!mChunks) {
                    868:                // There is no chunk left, allocate a new pool and link the
                    869:                // chunks into the free list
                    870:                Pool * newPool = (Pool *)vm_acquire(sizeof(Pool), VM_MAP_DEFAULT | VM_MAP_32BIT);
                    871:                if (newPool == VM_MAP_FAILED) {
                    872:                        jit_abort("Could not allocate block pool!");
                    873:                }
                    874:                for (T * chunk = &newPool->chunk[0]; chunk < &newPool->chunk[kPoolSize]; chunk++) {
                    875:                        chunk->next = mChunks;
                    876:                        mChunks = chunk;
                    877:                }
                    878:                newPool->next = mPools;
                    879:                mPools = newPool;
                    880:        }
                    881:        T * chunk = mChunks;
                    882:        mChunks = chunk->next;
                    883:        return chunk;
                    884: }
                    885: 
                    886: template< class T >
                    887: void LazyBlockAllocator<T>::release(T * const chunk)
                    888: {
                    889:        chunk->next = mChunks;
                    890:        mChunks = chunk;
                    891: }
                    892: 
                    893: template< class T >
                    894: class HardBlockAllocator
                    895: {
                    896: public:
                    897:        T * acquire() {
                    898:                T * data = (T *)current_compile_p;
                    899:                current_compile_p += sizeof(T);
                    900:                return data;
                    901:        }
                    902: 
1.1.1.5 ! root      903:        void release(T * const ) {
1.1.1.3   root      904:                // Deallocated on invalidation
1.1       root      905:        }
1.1.1.3   root      906: };
                    907: 
                    908: #if USE_SEPARATE_BIA
                    909: static LazyBlockAllocator<blockinfo> BlockInfoAllocator;
                    910: static LazyBlockAllocator<checksum_info> ChecksumInfoAllocator;
                    911: #else
                    912: static HardBlockAllocator<blockinfo> BlockInfoAllocator;
                    913: static HardBlockAllocator<checksum_info> ChecksumInfoAllocator;
                    914: #endif
                    915: 
                    916: static inline checksum_info *alloc_checksum_info(void)
                    917: {
                    918:        checksum_info *csi = ChecksumInfoAllocator.acquire();
                    919:        csi->next = NULL;
                    920:        return csi;
                    921: }
                    922: 
                    923: static inline void free_checksum_info(checksum_info *csi)
                    924: {
                    925:        csi->next = NULL;
                    926:        ChecksumInfoAllocator.release(csi);
                    927: }
1.1       root      928: 
1.1.1.3   root      929: static inline void free_checksum_info_chain(checksum_info *csi)
                    930: {
                    931:        while (csi != NULL) {
                    932:                checksum_info *csi2 = csi->next;
                    933:                free_checksum_info(csi);
                    934:                csi = csi2;
1.1       root      935:        }
1.1.1.3   root      936: }
                    937: 
                    938: static inline blockinfo *alloc_blockinfo(void)
                    939: {
                    940:        blockinfo *bi = BlockInfoAllocator.acquire();
                    941: #if USE_CHECKSUM_INFO
                    942:        bi->csi = NULL;
1.1       root      943: #endif
                    944:        return bi;
                    945: }
                    946: 
1.1.1.3   root      947: static inline void free_blockinfo(blockinfo *bi)
                    948: {
                    949: #if USE_CHECKSUM_INFO
                    950:        free_checksum_info_chain(bi->csi);
                    951:        bi->csi = NULL;
                    952: #endif
                    953:        BlockInfoAllocator.release(bi);
                    954: }
1.1       root      955: 
1.1.1.3   root      956: static inline void alloc_blockinfos(void)
1.1       root      957: {
                    958:        int i;
                    959:        blockinfo* bi;
                    960: 
                    961:        for (i=0;i<MAX_HOLD_BI;i++) {
                    962:                if (hold_bi[i])
                    963:                        return;
1.1.1.3   root      964:                bi=hold_bi[i]=alloc_blockinfo();
1.1       root      965:                prepare_block(bi);
                    966:        }
                    967: }
                    968: 
                    969: /********************************************************************
1.1.1.3   root      970:  * Functions to emit data into memory, and other general support    *
                    971:  ********************************************************************/
1.1       root      972: 
1.1.1.3   root      973: static uae_u8* target;
                    974: 
                    975: static inline void emit_byte(uae_u8 x)
                    976: {
                    977:        *target++=x;
1.1       root      978: }
                    979: 
1.1.1.3   root      980: static inline void skip_n_bytes(int n) {
                    981:        target += n;
                    982: }
1.1       root      983: 
1.1.1.3   root      984: static inline void skip_byte()
                    985: {
1.1.1.5 ! root      986:        skip_n_bytes(1);
1.1.1.3   root      987: }
1.1       root      988: 
1.1.1.3   root      989: static inline void skip_word()
1.1       root      990: {
1.1.1.5 ! root      991:        skip_n_bytes(2);
1.1       root      992: }
                    993: 
1.1.1.3   root      994: static inline void skip_long()
1.1       root      995: {
1.1.1.5 ! root      996:        skip_n_bytes(4);
1.1       root      997: }
                    998: 
1.1.1.3   root      999: static inline void skip_quad()
1.1       root     1000: {
1.1.1.5 ! root     1001:        skip_n_bytes(8);
1.1       root     1002: }
                   1003: 
1.1.1.5 ! root     1004: static inline void emit_word(uae_u16 x)
        !          1005: {
        !          1006:        *((uae_u16*)target)=x;
        !          1007:        skip_word();
        !          1008: }
        !          1009: 
        !          1010: static inline void emit_long(uae_u32 x)
        !          1011: {
        !          1012:        *((uae_u32*)target)=x;
        !          1013:        skip_long();
        !          1014: }
        !          1015: 
        !          1016: static inline void emit_quad(uae_u64 x)
1.1       root     1017: {
1.1.1.3   root     1018:        *((uae_u64*) target) = x;
1.1.1.5 ! root     1019:        skip_quad();
1.1       root     1020: }
                   1021: 
1.1.1.3   root     1022: static inline void emit_block(const uae_u8 *block, uae_u32 blocklen)
1.1       root     1023: {
1.1.1.3   root     1024:        memcpy((uae_u8 *)target,block,blocklen);
                   1025:        target+=blocklen;
1.1       root     1026: }
                   1027: 
1.1.1.3   root     1028: #define MAX_COMPILE_PTR                max_compile_start
                   1029: 
                   1030: static inline uae_u32 reverse32(uae_u32 v)
                   1031: {
1.1.1.5 ! root     1032: #ifdef WINUAE_ARANYM
1.1.1.3   root     1033:        // gb-- We have specialized byteswapping functions, just use them
                   1034:        return do_byteswap_32(v);
1.1.1.5 ! root     1035: #elif _MSC_VER
        !          1036:        return _byteswap_ulong(v);
1.1.1.3   root     1037: #else
                   1038:        return ((v>>24)&0xff) | ((v>>8)&0xff00) | ((v<<8)&0xff0000) | ((v<<24)&0xff000000);
                   1039: #endif
                   1040: }
1.1       root     1041: 
                   1042: void set_target(uae_u8* t)
                   1043: {
                   1044:        target=t;
                   1045: }
                   1046: 
1.1.1.3   root     1047: static inline uae_u8* get_target_noopt(void)
1.1       root     1048: {
                   1049:        return target;
                   1050: }
                   1051: 
1.1.1.3   root     1052: inline uae_u8* get_target(void)
1.1       root     1053: {
                   1054:        return get_target_noopt();
                   1055: }
                   1056: 
1.1.1.3   root     1057: /********************************************************************
                   1058:  * New version of data buffer: interleave data and code             *
                   1059:  ********************************************************************/
                   1060: #if defined(USE_DATA_BUFFER)
                   1061: 
                   1062: #define DATA_BUFFER_SIZE 1024    // Enlarge POPALLSPACE_SIZE if this value is greater than 768
                   1063: #define DATA_BUFFER_MAXOFFSET 4096 - 32 // max range between emit of data and use of data
                   1064: static uae_u8* data_writepos = 0;
                   1065: static uae_u8* data_endpos = 0;
                   1066: #if DEBUG
                   1067: static long data_wasted = 0;
                   1068: #endif
                   1069: 
                   1070: static inline void compemu_raw_branch(IMM d);
                   1071: 
                   1072: static inline void data_check_end(long n, long codesize)
                   1073: {
                   1074:        if(data_writepos + n > data_endpos || get_target_noopt() + codesize - data_writepos > DATA_BUFFER_MAXOFFSET)
                   1075:        {
                   1076:                // Start new buffer
                   1077: #if DEBUG
                   1078:                if(data_writepos < data_endpos)
                   1079:                        data_wasted += data_endpos - data_writepos;
                   1080: #endif
                   1081:                compemu_raw_branch(DATA_BUFFER_SIZE);
                   1082:                data_writepos = get_target_noopt();
                   1083:                data_endpos = data_writepos + DATA_BUFFER_SIZE;
                   1084:                set_target(get_target_noopt() + DATA_BUFFER_SIZE);
                   1085:        }
                   1086: }
                   1087: 
                   1088: static inline long data_word_offs(uae_u16 x)
                   1089: {
                   1090:        data_check_end(4, 4);
                   1091: #ifdef WORDS_BIGENDIAN
                   1092:        *((uae_u16*)data_writepos)=x;
                   1093:        data_writepos += 2;
                   1094:        *((uae_u16*)data_writepos)=0;
                   1095:        data_writepos += 2;
                   1096: #else
                   1097:        *((uae_u32*)data_writepos)=x;
                   1098:        data_writepos += 4;
                   1099: #endif
                   1100:        return (long)data_writepos - (long)get_target_noopt() - 12;
                   1101: }
                   1102: 
                   1103: static inline long data_long(uae_u32 x, long codesize)
                   1104: {
                   1105:        data_check_end(4, codesize);
                   1106:        *((uae_u32*)data_writepos)=x;
                   1107:        data_writepos += 4;
                   1108:        return (long)data_writepos - 4;
                   1109: }
                   1110: 
                   1111: static inline long data_long_offs(uae_u32 x)
                   1112: {
                   1113:        data_check_end(4, 4);
                   1114:        *((uae_u32*)data_writepos)=x;
                   1115:        data_writepos += 4;
                   1116:        return (long)data_writepos - (long)get_target_noopt() - 12;
                   1117: }
                   1118: 
                   1119: static inline long get_data_offset(long t)
                   1120: {
                   1121:        return t - (long)get_target_noopt() - 8;
                   1122: }
                   1123: 
                   1124: static inline void reset_data_buffer(void)
                   1125: {
                   1126:        data_writepos = 0;
                   1127:        data_endpos = 0;
                   1128: }
1.1       root     1129: 
1.1.1.3   root     1130: #endif
1.1       root     1131: /********************************************************************
1.1.1.3   root     1132:  * Getting the information about the target CPU                     *
                   1133:  ********************************************************************/
1.1       root     1134: 
1.1.1.3   root     1135: #if defined(CPU_arm)
                   1136: #include "codegen_arm.cpp"
                   1137: #endif
                   1138: #if defined(CPU_i386) || defined(CPU_x86_64)
                   1139: #include "codegen_x86.cpp"
                   1140: #endif
1.1       root     1141: 
                   1142: 
                   1143: /********************************************************************
1.1.1.3   root     1144:  * Flags status handling. EMIT TIME!                                *
                   1145:  ********************************************************************/
1.1       root     1146: 
1.1.1.3   root     1147: static void bt_l_ri_noclobber(RR4 r, IMM i);
1.1       root     1148: 
                   1149: static void make_flags_live_internal(void)
                   1150: {
                   1151:        if (live.flags_in_flags==VALID)
                   1152:                return;
                   1153:        Dif (live.flags_on_stack==TRASH) {
1.1.1.3   root     1154:                jit_abort("Want flags, got something on stack, but it is TRASH");
1.1       root     1155:        }
                   1156:        if (live.flags_on_stack==VALID) {
                   1157:                int tmp;
                   1158:                tmp=readreg_specific(FLAGTMP,4,FLAG_NREG2);
                   1159:                raw_reg_to_flags(tmp);
1.1.1.3   root     1160:                unlock2(tmp);
1.1       root     1161: 
                   1162:                live.flags_in_flags=VALID;
                   1163:                return;
                   1164:        }
1.1.1.3   root     1165:        jit_abort("Huh? live.flags_in_flags=%d, live.flags_on_stack=%d, but need to make live",
1.1       root     1166:                live.flags_in_flags,live.flags_on_stack);
                   1167: }
                   1168: 
                   1169: static void flags_to_stack(void)
                   1170: {
                   1171:        if (live.flags_on_stack==VALID)
                   1172:                return;
                   1173:        if (!live.flags_are_important) {
                   1174:                live.flags_on_stack=VALID;
                   1175:                return;
                   1176:        }
                   1177:        Dif (live.flags_in_flags!=VALID)
1.1.1.3   root     1178:                jit_abort("flags_to_stack != VALID");
1.1       root     1179:        else  {
                   1180:                int tmp;
                   1181:                tmp=writereg_specific(FLAGTMP,4,FLAG_NREG1);
                   1182:                raw_flags_to_reg(tmp);
1.1.1.3   root     1183:                unlock2(tmp);
1.1       root     1184:        }
                   1185:        live.flags_on_stack=VALID;
                   1186: }
                   1187: 
1.1.1.3   root     1188: static inline void clobber_flags(void)
1.1       root     1189: {
                   1190:        if (live.flags_in_flags==VALID && live.flags_on_stack!=VALID)
                   1191:                flags_to_stack();
                   1192:        live.flags_in_flags=TRASH;
                   1193: }
                   1194: 
                   1195: /* Prepare for leaving the compiled stuff */
1.1.1.3   root     1196: static inline void flush_flags(void)
1.1       root     1197: {
                   1198:        flags_to_stack();
                   1199:        return;
                   1200: }
                   1201: 
                   1202: int touchcnt;
                   1203: 
                   1204: /********************************************************************
1.1.1.3   root     1205:  * Partial register flushing for optimized calls                    *
                   1206:  ********************************************************************/
1.1       root     1207: 
1.1.1.3   root     1208: struct regusage {
                   1209:        uae_u16 rmask;
                   1210:        uae_u16 wmask;
                   1211: };
1.1       root     1212: 
1.1.1.5 ! root     1213: #if 0
1.1.1.3   root     1214: static inline void ru_set(uae_u16 *mask, int reg)
                   1215: {
                   1216: #if USE_OPTIMIZED_CALLS
                   1217:        *mask |= 1 << reg;
                   1218: #else
                   1219:        UNUSED(mask);
                   1220:        UNUSED(reg);
                   1221: #endif
                   1222: }
1.1       root     1223: 
1.1.1.3   root     1224: static inline bool ru_get(const uae_u16 *mask, int reg)
1.1       root     1225: {
1.1.1.3   root     1226: #if USE_OPTIMIZED_CALLS
                   1227:        return (*mask & (1 << reg));
                   1228: #else
                   1229:        UNUSED(mask);
                   1230:        UNUSED(reg);
                   1231:        /* Default: instruction reads & write to register */
                   1232:        return true;
                   1233: #endif
                   1234: }
                   1235: 
                   1236: static inline void ru_set_read(regusage *ru, int reg)
                   1237: {
                   1238:        ru_set(&ru->rmask, reg);
                   1239: }
                   1240: 
                   1241: static inline void ru_set_write(regusage *ru, int reg)
                   1242: {
                   1243:        ru_set(&ru->wmask, reg);
                   1244: }
                   1245: 
                   1246: static inline bool ru_read_p(const regusage *ru, int reg)
                   1247: {
                   1248:        return ru_get(&ru->rmask, reg);
                   1249: }
                   1250: 
                   1251: static inline bool ru_write_p(const regusage *ru, int reg)
                   1252: {
                   1253:        return ru_get(&ru->wmask, reg);
                   1254: }
                   1255: 
                   1256: static void ru_fill_ea(regusage *ru, int reg, amodes mode,
                   1257:                                           wordsizes size, int write_mode)
                   1258: {
                   1259:        switch (mode) {
                   1260:        case Areg:
                   1261:                reg += 8;
                   1262:                /* fall through */
                   1263:        case Dreg:
                   1264:                ru_set(write_mode ? &ru->wmask : &ru->rmask, reg);
                   1265:                break;
                   1266:        case Ad16:
                   1267:                /* skip displacment */
                   1268:                m68k_pc_offset += 2;
                   1269:        case Aind:
                   1270:        case Aipi:
                   1271:        case Apdi:
                   1272:                ru_set_read(ru, reg+8);
                   1273:                break;
                   1274:        case Ad8r:
                   1275:                ru_set_read(ru, reg+8);
                   1276:                /* fall through */
                   1277:        case PC8r: {
                   1278:                uae_u16 dp = comp_get_iword((m68k_pc_offset+=2)-2);
                   1279:                reg = (dp >> 12) & 15;
                   1280:                ru_set_read(ru, reg);
                   1281:                if (dp & 0x100)
                   1282:                        m68k_pc_offset += (((dp & 0x30) >> 3) & 7) + ((dp & 3) * 2);
                   1283:                break;
                   1284:        }
                   1285:        case PC16:
                   1286:        case absw:
                   1287:        case imm0:
                   1288:        case imm1:
                   1289:                m68k_pc_offset += 2;
                   1290:                break;
                   1291:        case absl:
                   1292:        case imm2:
                   1293:                m68k_pc_offset += 4;
                   1294:                break;
                   1295:        case immi:
                   1296:                m68k_pc_offset += (size == sz_long) ? 4 : 2;
                   1297:                break;
                   1298:        }
                   1299: }
                   1300: 
                   1301: /* TODO: split into a static initialization part and a dynamic one
                   1302:    (instructions depending on extension words) */
                   1303: 
                   1304: static void ru_fill(regusage *ru, uae_u32 opcode)
                   1305: {
                   1306:        m68k_pc_offset += 2;
                   1307: 
                   1308:        /* Default: no register is used or written to */
                   1309:        ru->rmask = 0;
                   1310:        ru->wmask = 0;
                   1311: 
                   1312:        uae_u32 real_opcode = cft_map(opcode);
                   1313:        struct instr *dp = &table68k[real_opcode];
                   1314: 
                   1315:        bool rw_dest = true;
                   1316:        bool handled = false;
                   1317: 
                   1318:        /* Handle some instructions specifically */
                   1319:        uae_u16 ext;
                   1320:        switch (dp->mnemo) {
                   1321:        case i_BFCHG:
                   1322:        case i_BFCLR:
                   1323:        case i_BFEXTS:
                   1324:        case i_BFEXTU:
                   1325:        case i_BFFFO:
                   1326:        case i_BFINS:
                   1327:        case i_BFSET:
                   1328:        case i_BFTST:
                   1329:                ext = comp_get_iword((m68k_pc_offset+=2)-2);
                   1330:                if (ext & 0x800) ru_set_read(ru, (ext >> 6) & 7);
                   1331:                if (ext & 0x020) ru_set_read(ru, ext & 7);
                   1332:                ru_fill_ea(ru, dp->dreg, (amodes)dp->dmode, (wordsizes)dp->size, 1);
                   1333:                if (dp->dmode == Dreg)
                   1334:                        ru_set_read(ru, dp->dreg);
                   1335:                switch (dp->mnemo) {
                   1336:                case i_BFEXTS:
                   1337:                case i_BFEXTU:
                   1338:                case i_BFFFO:
                   1339:                        ru_set_write(ru, (ext >> 12) & 7);
                   1340:                        break;
                   1341:                case i_BFINS:
                   1342:                        ru_set_read(ru, (ext >> 12) & 7);
                   1343:                        /* fall through */
                   1344:                case i_BFCHG:
                   1345:                case i_BFCLR:
                   1346:                case i_BSET:
                   1347:                        if (dp->dmode == Dreg)
                   1348:                                ru_set_write(ru, dp->dreg);
                   1349:                        break;
                   1350:                }
                   1351:                handled = true;
                   1352:                rw_dest = false;
                   1353:                break;
                   1354: 
                   1355:        case i_BTST:
                   1356:                rw_dest = false;
                   1357:                break;
                   1358: 
                   1359:        case i_CAS:
                   1360:        {
                   1361:                ext = comp_get_iword((m68k_pc_offset+=2)-2);
                   1362:                int Du = ext & 7;
                   1363:                ru_set_read(ru, Du);
                   1364:                int Dc = (ext >> 6) & 7;
                   1365:                ru_set_read(ru, Dc);
                   1366:                ru_set_write(ru, Dc);
                   1367:                break;
                   1368:        }
                   1369:        case i_CAS2:
                   1370:        {
                   1371:                int Dc1, Dc2, Du1, Du2, Rn1, Rn2;
                   1372:                ext = comp_get_iword((m68k_pc_offset+=2)-2);
                   1373:                Rn1 = (ext >> 12) & 15;
                   1374:                Du1 = (ext >> 6) & 7;
                   1375:                Dc1 = ext & 7;
                   1376:                ru_set_read(ru, Rn1);
                   1377:                ru_set_read(ru, Du1);
                   1378:                ru_set_read(ru, Dc1);
                   1379:                ru_set_write(ru, Dc1);
                   1380:                ext = comp_get_iword((m68k_pc_offset+=2)-2);
                   1381:                Rn2 = (ext >> 12) & 15;
                   1382:                Du2 = (ext >> 6) & 7;
                   1383:                Dc2 = ext & 7;
                   1384:                ru_set_read(ru, Rn2);
                   1385:                ru_set_read(ru, Du2);
                   1386:                ru_set_write(ru, Dc2);
                   1387:                break;
                   1388:        }
                   1389:        case i_DIVL: case i_MULL:
                   1390:                m68k_pc_offset += 2;
                   1391:                break;
                   1392:        case i_LEA:
                   1393:        case i_MOVE: case i_MOVEA: case i_MOVE16:
                   1394:                rw_dest = false;
                   1395:                break;
                   1396:        case i_PACK: case i_UNPK:
                   1397:                rw_dest = false;
                   1398:                m68k_pc_offset += 2;
                   1399:                break;
                   1400:        case i_TRAPcc:
                   1401:                m68k_pc_offset += (dp->size == sz_long) ? 4 : 2;
                   1402:                break;
                   1403:        case i_RTR:
                   1404:                /* do nothing, just for coverage debugging */
                   1405:                break;
                   1406:        /* TODO: handle EXG instruction */
                   1407:        }
                   1408: 
                   1409:        /* Handle A-Traps better */
                   1410:        if ((real_opcode & 0xf000) == 0xa000) {
                   1411:                handled = true;
                   1412:        }
                   1413: 
                   1414:        /* Handle EmulOps better */
                   1415:        if ((real_opcode & 0xff00) == 0x7100) {
                   1416:                handled = true;
                   1417:                ru->rmask = 0xffff;
                   1418:                ru->wmask = 0;
                   1419:        }
                   1420: 
                   1421:        if (dp->suse && !handled)
                   1422:                ru_fill_ea(ru, dp->sreg, (amodes)dp->smode, (wordsizes)dp->size, 0);
                   1423: 
                   1424:        if (dp->duse && !handled)
                   1425:                ru_fill_ea(ru, dp->dreg, (amodes)dp->dmode, (wordsizes)dp->size, 1);
                   1426: 
                   1427:        if (rw_dest)
                   1428:                ru->rmask |= ru->wmask;
                   1429: 
                   1430:        handled = handled || dp->suse || dp->duse;
                   1431: 
                   1432:        /* Mark all registers as used/written if the instruction may trap */
                   1433:        if (may_trap(opcode)) {
                   1434:                handled = true;
                   1435:                ru->rmask = 0xffff;
                   1436:                ru->wmask = 0xffff;
                   1437:        }
                   1438: 
                   1439:        if (!handled) {
                   1440:                jit_abort("ru_fill: %04x = { %04x, %04x }",
                   1441:                                  real_opcode, ru->rmask, ru->wmask);
                   1442:        }
                   1443: }
                   1444: #endif
                   1445: 
                   1446: /********************************************************************
                   1447:  * register allocation per block logging                            *
                   1448:  ********************************************************************/
                   1449: 
                   1450: static uae_s8 vstate[VREGS];
                   1451: static uae_s8 vwritten[VREGS];
                   1452: static uae_s8 nstate[N_REGS];
                   1453: 
                   1454: #define L_UNKNOWN -127
                   1455: #define L_UNAVAIL -1
                   1456: #define L_NEEDED -2
                   1457: #define L_UNNEEDED -3
                   1458: 
1.1.1.5 ! root     1459: #if USE_MATCH
1.1.1.3   root     1460: static inline void big_to_small_state(bigstate * /* b */, smallstate * s)
                   1461: {
                   1462:   int i;
                   1463:        
                   1464:   for (i = 0; i < VREGS; i++)
                   1465:        s->virt[i] = vstate[i];
                   1466:   for (i = 0; i < N_REGS; i++)
                   1467:        s->nat[i] = nstate[i];
                   1468: }
                   1469: 
                   1470: static inline int callers_need_recompile(bigstate * /* b */, smallstate * s)
                   1471: {
                   1472:   int i;
                   1473:   int reverse = 0;
                   1474: 
                   1475:   for (i = 0; i < VREGS; i++) {
                   1476:        if (vstate[i] != L_UNNEEDED && s->virt[i] == L_UNNEEDED)
                   1477:          return 1;
                   1478:        if (vstate[i] == L_UNNEEDED && s->virt[i] != L_UNNEEDED)
                   1479:          reverse++;
                   1480:   }
                   1481:   for (i = 0; i < N_REGS; i++) {
                   1482:        if (nstate[i] >= 0 && nstate[i] != s->nat[i])
                   1483:          return 1;
                   1484:        if (nstate[i] < 0 && s->nat[i] >= 0)
                   1485:          reverse++;
                   1486:   }
                   1487:   if (reverse >= 2 && USE_MATCH)
                   1488:        return 1;       /* In this case, it might be worth recompiling the
                   1489:                                 * callers */
                   1490:   return 0;
                   1491: }
1.1.1.5 ! root     1492: #endif
1.1.1.3   root     1493: 
                   1494: static inline void log_startblock(void)
                   1495: {
                   1496:        int i;
                   1497: 
                   1498:        for (i = 0; i < VREGS; i++) {
1.1.1.5 ! root     1499:                vstate[i] = L_UNKNOWN;
        !          1500:                vwritten[i] = 0;
1.1.1.3   root     1501:        }
1.1.1.5 ! root     1502:        for (i = 0; i < N_REGS; i++)
        !          1503:                nstate[i] = L_UNKNOWN;
1.1       root     1504: }
                   1505: 
1.1.1.3   root     1506: /* Using an n-reg for a temp variable */
                   1507: static inline void log_isused(int n)
1.1       root     1508: {
1.1.1.5 ! root     1509:        if (nstate[n] == L_UNKNOWN)
        !          1510:                nstate[n] = L_UNAVAIL;
1.1       root     1511: }
                   1512: 
1.1.1.3   root     1513: static inline void log_visused(int r)
1.1       root     1514: {
1.1.1.3   root     1515:        if (vstate[r] == L_UNKNOWN)
                   1516:                vstate[r] = L_NEEDED;
                   1517: }
                   1518: 
                   1519: static inline void do_load_reg(int n, int r)
                   1520: {
                   1521:        if (r == FLAGTMP)
                   1522:                raw_load_flagreg(n, r);
                   1523:        else if (r == FLAGX)
                   1524:                raw_load_flagx(n, r);
                   1525:        else
                   1526:                compemu_raw_mov_l_rm(n, (uintptr) live.state[r].mem);
                   1527: }
                   1528: 
1.1.1.5 ! root     1529: #if 0
1.1.1.3   root     1530: static inline void check_load_reg(int n, int r)
                   1531: {
                   1532:        compemu_raw_mov_l_rm(n, (uintptr) live.state[r].mem);
                   1533: }
1.1.1.5 ! root     1534: #endif
1.1.1.3   root     1535: 
                   1536: static inline void log_vwrite(int r)
                   1537: {
                   1538:        vwritten[r] = 1;
                   1539: }
                   1540: 
                   1541: /* Using an n-reg to hold a v-reg */
                   1542: static inline void log_isreg(int n, int r)
                   1543: {
                   1544:        if (nstate[n] == L_UNKNOWN && r < 16 && !vwritten[r] && USE_MATCH)
1.1.1.5 ! root     1545:                nstate[n] = r;
1.1.1.3   root     1546:        else {
                   1547:                do_load_reg(n, r);
                   1548:                if (nstate[n] == L_UNKNOWN)
                   1549:                        nstate[n] = L_UNAVAIL;
                   1550:        }
1.1.1.5 ! root     1551:        if (vstate[r] == L_UNKNOWN)
        !          1552:                vstate[r] = L_NEEDED;
1.1       root     1553: }
                   1554: 
1.1.1.3   root     1555: static inline void log_clobberreg(int r)
1.1       root     1556: {
1.1.1.5 ! root     1557:        if (vstate[r] == L_UNKNOWN)
        !          1558:                vstate[r] = L_UNNEEDED;
1.1       root     1559: }
                   1560: 
                   1561: /* This ends all possibility of clever register allocation */
                   1562: 
1.1.1.3   root     1563: static inline void log_flush(void)
1.1       root     1564: {
                   1565:        int i;
1.1.1.5 ! root     1566: 
        !          1567:        for (i = 0; i < VREGS; i++)
        !          1568:                if (vstate[i] == L_UNKNOWN)
        !          1569:                        vstate[i] = L_NEEDED;
        !          1570:        for (i = 0; i < N_REGS; i++)
        !          1571:                if (nstate[i] == L_UNKNOWN)
        !          1572:                        nstate[i] = L_UNAVAIL;
1.1       root     1573: }
                   1574: 
1.1.1.3   root     1575: static inline void log_dump(void)
1.1       root     1576: {
                   1577:        int i;
                   1578: 
                   1579:        return;
                   1580: 
1.1.1.3   root     1581:        jit_log("----------------------");
1.1.1.5 ! root     1582:        for (i = 0; i < N_REGS; i++) {
        !          1583:                switch (nstate[i]) {
1.1.1.3   root     1584:                case L_UNKNOWN:
1.1.1.5 ! root     1585:                        jit_log("Nat %d : UNKNOWN", i);
1.1.1.3   root     1586:                        break;
                   1587:                case L_UNAVAIL:
1.1.1.5 ! root     1588:                        jit_log("Nat %d : UNAVAIL", i);
1.1.1.3   root     1589:                        break;
                   1590:                default:
1.1.1.5 ! root     1591:                        jit_log("Nat %d : %d", i, nstate[i]);
1.1.1.3   root     1592:                        break;
1.1       root     1593:                }
                   1594:        }
1.1.1.5 ! root     1595:        for (i = 0; i < VREGS; i++) {
1.1.1.3   root     1596:                if (vstate[i] == L_UNNEEDED) {
1.1.1.5 ! root     1597:                        jit_log("Virt %d: UNNEEDED", i);
1.1.1.3   root     1598:                }
1.1       root     1599:        }
                   1600: }
                   1601: 
                   1602: /********************************************************************
1.1.1.3   root     1603:  * register status handling. EMIT TIME!                             *
                   1604:  ********************************************************************/
1.1       root     1605: 
1.1.1.3   root     1606: static inline void set_status(int r, int status)
1.1       root     1607: {
1.1.1.5 ! root     1608:        if (status == ISCONST)
1.1       root     1609:                log_clobberreg(r);
                   1610:        live.state[r].status=status;
                   1611: }
                   1612: 
1.1.1.3   root     1613: static inline int isinreg(int r)
1.1       root     1614: {
                   1615:        return live.state[r].status==CLEAN || live.state[r].status==DIRTY;
                   1616: }
                   1617: 
1.1.1.3   root     1618: static inline void adjust_nreg(int r, uae_u32 val)
1.1       root     1619: {
                   1620:        if (!val)
                   1621:                return;
1.1.1.3   root     1622:        compemu_raw_lea_l_brr(r,r,val);
1.1       root     1623: }
                   1624: 
1.1.1.5 ! root     1625: static void tomem(int r)
1.1       root     1626: {
                   1627:        int rr=live.state[r].realreg;
                   1628: 
                   1629:        if (isinreg(r)) {
1.1.1.3   root     1630:                if (live.state[r].val && live.nat[rr].nholds==1
                   1631:                        && !live.nat[rr].locked) {
1.1.1.5 ! root     1632:                        jit_log2("RemovingA offset %x from reg %d (%d) at %p", live.state[r].val,r,rr,target);
        !          1633:                        adjust_nreg(rr,live.state[r].val);
        !          1634:                        live.state[r].val=0;
        !          1635:                        live.state[r].dirtysize=4;
        !          1636:                        set_status(r,DIRTY);
1.1       root     1637:                }
                   1638:        }
                   1639: 
                   1640:        if (live.state[r].status==DIRTY) {
                   1641:                switch (live.state[r].dirtysize) {
1.1.1.3   root     1642:                case 1: compemu_raw_mov_b_mr((uintptr)live.state[r].mem,rr); break;
                   1643:                case 2: compemu_raw_mov_w_mr((uintptr)live.state[r].mem,rr); break;
                   1644:                case 4: compemu_raw_mov_l_mr((uintptr)live.state[r].mem,rr); break;
1.1       root     1645:                default: abort();
                   1646:                }
1.1.1.3   root     1647:                log_vwrite(r);
1.1       root     1648:                set_status(r,CLEAN);
                   1649:                live.state[r].dirtysize=0;
                   1650:        }
                   1651: }
                   1652: 
1.1.1.3   root     1653: static inline int isconst(int r)
1.1       root     1654: {
                   1655:        return live.state[r].status==ISCONST;
                   1656: }
                   1657: 
                   1658: int is_const(int r)
                   1659: {
                   1660:        return isconst(r);
                   1661: }
                   1662: 
1.1.1.3   root     1663: static inline void writeback_const(int r)
1.1       root     1664: {
                   1665:        if (!isconst(r))
                   1666:                return;
                   1667:        Dif (live.state[r].needflush==NF_HANDLER) {
1.1.1.3   root     1668:                jit_abort("Trying to write back constant NF_HANDLER!");
1.1       root     1669:        }
                   1670: 
1.1.1.3   root     1671:        compemu_raw_mov_l_mi((uintptr)live.state[r].mem,live.state[r].val);
                   1672:        log_vwrite(r);
1.1       root     1673:        live.state[r].val=0;
                   1674:        set_status(r,INMEM);
                   1675: }
                   1676: 
1.1.1.3   root     1677: static inline void tomem_c(int r)
1.1       root     1678: {
                   1679:        if (isconst(r)) {
                   1680:                writeback_const(r);
                   1681:        }
                   1682:        else
                   1683:                tomem(r);
                   1684: }
                   1685: 
1.1.1.5 ! root     1686: static void evict(int r)
1.1       root     1687: {
                   1688:        int rr;
                   1689: 
                   1690:        if (!isinreg(r))
                   1691:                return;
                   1692:        tomem(r);
                   1693:        rr=live.state[r].realreg;
                   1694: 
                   1695:        Dif (live.nat[rr].locked &&
                   1696:                live.nat[rr].nholds==1) {
1.1.1.5 ! root     1697:                jit_abort("register %d in nreg %d is locked!",r,live.state[r].realreg);
1.1       root     1698:        }
                   1699: 
                   1700:        live.nat[rr].nholds--;
                   1701:        if (live.nat[rr].nholds!=live.state[r].realind) { /* Was not last */
                   1702:                int topreg=live.nat[rr].holds[live.nat[rr].nholds];
                   1703:                int thisind=live.state[r].realind;
1.1.1.5 ! root     1704: 
1.1       root     1705:                live.nat[rr].holds[thisind]=topreg;
                   1706:                live.state[topreg].realind=thisind;
                   1707:        }
                   1708:        live.state[r].realreg=-1;
                   1709:        set_status(r,INMEM);
                   1710: }
                   1711: 
1.1.1.3   root     1712: static inline void free_nreg(int r)
1.1       root     1713: {
                   1714:        int i=live.nat[r].nholds;
                   1715: 
                   1716:        while (i) {
                   1717:                int vr;
                   1718: 
                   1719:                --i;
                   1720:                vr=live.nat[r].holds[i];
                   1721:                evict(vr);
                   1722:        }
                   1723:        Dif (live.nat[r].nholds!=0) {
1.1.1.3   root     1724:                jit_abort("Failed to free nreg %d, nholds is %d",r,live.nat[r].nholds);
1.1       root     1725:        }
                   1726: }
                   1727: 
                   1728: /* Use with care! */
1.1.1.3   root     1729: static inline void isclean(int r)
1.1       root     1730: {
                   1731:        if (!isinreg(r))
                   1732:                return;
                   1733:        live.state[r].validsize=4;
                   1734:        live.state[r].dirtysize=0;
                   1735:        live.state[r].val=0;
                   1736:        set_status(r,CLEAN);
                   1737: }
                   1738: 
1.1.1.3   root     1739: static inline void disassociate(int r)
1.1       root     1740: {
                   1741:        isclean(r);
                   1742:        evict(r);
                   1743: }
                   1744: 
1.1.1.3   root     1745: static inline void set_const(int r, uae_u32 val)
1.1       root     1746: {
                   1747:        disassociate(r);
                   1748:        live.state[r].val=val;
                   1749:        set_status(r,ISCONST);
                   1750: }
                   1751: 
1.1.1.3   root     1752: static inline uae_u32 get_offset(int r)
1.1       root     1753: {
                   1754:        return live.state[r].val;
                   1755: }
                   1756: 
1.1.1.5 ! root     1757: static int alloc_reg_hinted(int r, int size, int willclobber, int hint)
1.1       root     1758: {
                   1759:        int bestreg;
                   1760:        uae_s32 when;
                   1761:        int i;
                   1762:        uae_s32 badness=0; /* to shut up gcc */
                   1763:        bestreg=-1;
                   1764:        when=2000000000;
                   1765: 
1.1.1.3   root     1766:        /* XXX use a regalloc_order table? */
                   1767:        for (i=0;i<N_REGS;i++) {
1.1       root     1768:                badness=live.nat[i].touched;
                   1769:                if (live.nat[i].nholds==0)
                   1770:                        badness=0;
                   1771:                if (i==hint)
                   1772:                        badness-=200000000;
                   1773:                if (!live.nat[i].locked && badness<when) {
                   1774:                        if ((size==1 && live.nat[i].canbyte) ||
                   1775:                                (size==2 && live.nat[i].canword) ||
                   1776:                                (size==4)) {
1.1.1.5 ! root     1777:                                bestreg=i;
        !          1778:                                when=badness;
        !          1779:                                if (live.nat[i].nholds==0 && hint<0)
        !          1780:                                        break;
        !          1781:                                if (i==hint)
        !          1782:                                        break;
1.1       root     1783:                        }
                   1784:                }
                   1785:        }
                   1786:        Dif (bestreg==-1)
1.1.1.3   root     1787:                jit_abort("alloc_reg_hinted bestreg=-1");
1.1       root     1788: 
                   1789:        if (live.nat[bestreg].nholds>0) {
                   1790:                free_nreg(bestreg);
                   1791:        }
                   1792:        if (isinreg(r)) {
                   1793:                int rr=live.state[r].realreg;
                   1794:                /* This will happen if we read a partially dirty register at a
1.1.1.5 ! root     1795:                   bigger size */
1.1       root     1796:                Dif (willclobber || live.state[r].validsize>=size)
1.1.1.3   root     1797:                        jit_abort("willclobber || live.state[r].validsize>=size");
1.1       root     1798:                Dif (live.nat[rr].nholds!=1)
1.1.1.3   root     1799:                        jit_abort("live.nat[rr].nholds!=1");
1.1       root     1800:                if (size==4 && live.state[r].validsize==2) {
                   1801:                        log_isused(bestreg);
1.1.1.3   root     1802:                        log_visused(r);
                   1803:                        compemu_raw_mov_l_rm(bestreg,(uintptr)live.state[r].mem);
                   1804:                        compemu_raw_bswap_32(bestreg);
                   1805:                        compemu_raw_zero_extend_16_rr(rr,rr);
                   1806:                        compemu_raw_zero_extend_16_rr(bestreg,bestreg);
                   1807:                        compemu_raw_bswap_32(bestreg);
                   1808:                        compemu_raw_lea_l_rr_indexed(rr, rr, bestreg, 1);
1.1       root     1809:                        live.state[r].validsize=4;
                   1810:                        live.nat[rr].touched=touchcnt++;
                   1811:                        return rr;
                   1812:                }
                   1813:                if (live.state[r].validsize==1) {
                   1814:                        /* Nothing yet */
                   1815:                }
                   1816:                evict(r);
                   1817:        }
                   1818: 
                   1819:        if (!willclobber) {
                   1820:                if (live.state[r].status!=UNDEF) {
                   1821:                        if (isconst(r)) {
1.1.1.3   root     1822:                                compemu_raw_mov_l_ri(bestreg,live.state[r].val);
1.1       root     1823:                                live.state[r].val=0;
                   1824:                                live.state[r].dirtysize=4;
                   1825:                                set_status(r,DIRTY);
                   1826:                                log_isused(bestreg);
                   1827:                        }
                   1828:                        else {
1.1.1.3   root     1829:                                log_isreg(bestreg, r);  /* This will also load it! */
1.1       root     1830:                                live.state[r].dirtysize=0;
                   1831:                                set_status(r,CLEAN);
                   1832:                        }
                   1833:                }
                   1834:                else {
                   1835:                        live.state[r].val=0;
                   1836:                        live.state[r].dirtysize=0;
                   1837:                        set_status(r,CLEAN);
                   1838:                        log_isused(bestreg);
                   1839:                }
                   1840:                live.state[r].validsize=4;
                   1841:        }
                   1842:        else { /* this is the easiest way, but not optimal. FIXME! */
                   1843:                /* Now it's trickier, but hopefully still OK */
                   1844:                if (!isconst(r) || size==4) {
                   1845:                        live.state[r].validsize=size;
                   1846:                        live.state[r].dirtysize=size;
                   1847:                        live.state[r].val=0;
                   1848:                        set_status(r,DIRTY);
1.1.1.3   root     1849:                        if (size == 4) {
                   1850:                                log_clobberreg(r);
1.1       root     1851:                                log_isused(bestreg);
1.1.1.5 ! root     1852:                        }
1.1.1.3   root     1853:                        else {
                   1854:                                log_visused(r);
                   1855:                                log_isused(bestreg);
                   1856:                        }
1.1       root     1857:                }
                   1858:                else {
                   1859:                        if (live.state[r].status!=UNDEF)
1.1.1.3   root     1860:                                compemu_raw_mov_l_ri(bestreg,live.state[r].val);
1.1       root     1861:                        live.state[r].val=0;
                   1862:                        live.state[r].validsize=4;
                   1863:                        live.state[r].dirtysize=4;
                   1864:                        set_status(r,DIRTY);
                   1865:                        log_isused(bestreg);
                   1866:                }
                   1867:        }
                   1868:        live.state[r].realreg=bestreg;
                   1869:        live.state[r].realind=live.nat[bestreg].nholds;
                   1870:        live.nat[bestreg].touched=touchcnt++;
                   1871:        live.nat[bestreg].holds[live.nat[bestreg].nholds]=r;
                   1872:        live.nat[bestreg].nholds++;
                   1873: 
                   1874:        return bestreg;
                   1875: }
                   1876: 
1.1.1.3   root     1877: /*
1.1.1.5 ! root     1878: static int alloc_reg(int r, int size, int willclobber)
1.1       root     1879: {
                   1880:        return alloc_reg_hinted(r,size,willclobber,-1);
                   1881: }
1.1.1.3   root     1882: */
1.1       root     1883: 
1.1.1.3   root     1884: static void unlock2(int r)
1.1       root     1885: {
                   1886:        Dif (!live.nat[r].locked)
1.1.1.3   root     1887:                jit_abort("unlock2 %d not locked", r);
1.1       root     1888:        live.nat[r].locked--;
                   1889: }
                   1890: 
1.1.1.5 ! root     1891: static void setlock(int r)
1.1       root     1892: {
                   1893:        live.nat[r].locked++;
                   1894: }
                   1895: 
                   1896: 
                   1897: static void mov_nregs(int d, int s)
                   1898: {
                   1899:        int nd=live.nat[d].nholds;
                   1900:        int i;
                   1901: 
                   1902:        if (s==d)
                   1903:                return;
                   1904: 
                   1905:        if (nd>0)
                   1906:                free_nreg(d);
                   1907: 
                   1908:        log_isused(d);
1.1.1.3   root     1909:        compemu_raw_mov_l_rr(d,s);
1.1       root     1910: 
                   1911:        for (i=0;i<live.nat[s].nholds;i++) {
                   1912:                int vs=live.nat[s].holds[i];
                   1913: 
                   1914:                live.state[vs].realreg=d;
                   1915:                live.state[vs].realind=i;
                   1916:                live.nat[d].holds[i]=vs;
                   1917:        }
                   1918:        live.nat[d].nholds=live.nat[s].nholds;
                   1919: 
                   1920:        live.nat[s].nholds=0;
                   1921: }
                   1922: 
                   1923: 
1.1.1.3   root     1924: static inline void make_exclusive(int r, int size, int spec)
1.1       root     1925: {
                   1926:        reg_status oldstate;
                   1927:        int rr=live.state[r].realreg;
                   1928:        int nr;
                   1929:        int nind;
                   1930:        int ndirt=0;
                   1931:        int i;
                   1932: 
                   1933:        if (!isinreg(r))
                   1934:                return;
                   1935:        if (live.nat[rr].nholds==1)
                   1936:                return;
                   1937:        for (i=0;i<live.nat[rr].nholds;i++) {
                   1938:                int vr=live.nat[rr].holds[i];
                   1939:                if (vr!=r &&
                   1940:                        (live.state[vr].status==DIRTY || live.state[vr].val))
                   1941:                        ndirt++;
                   1942:        }
                   1943:        if (!ndirt && size<live.state[r].validsize && !live.nat[rr].locked) {
                   1944:                /* Everything else is clean, so let's keep this register */
                   1945:                for (i=0;i<live.nat[rr].nholds;i++) {
                   1946:                        int vr=live.nat[rr].holds[i];
                   1947:                        if (vr!=r) {
                   1948:                                evict(vr);
                   1949:                                i--; /* Try that index again! */
                   1950:                        }
                   1951:                }
                   1952:                Dif (live.nat[rr].nholds!=1) {
1.1.1.3   root     1953:                        jit_abort("natreg %d holds %d vregs, %d not exclusive",
1.1       root     1954:                                rr,live.nat[rr].nholds,r);
                   1955:                }
                   1956:                return;
                   1957:        }
                   1958: 
                   1959:        /* We have to split the register */
                   1960:        oldstate=live.state[r];
                   1961: 
                   1962:        setlock(rr); /* Make sure this doesn't go away */
                   1963:        /* Forget about r being in the register rr */
                   1964:        disassociate(r);
                   1965:        /* Get a new register, that we will clobber completely */
                   1966:        if (oldstate.status==DIRTY) {
                   1967:                /* If dirtysize is <4, we need a register that can handle the
1.1.1.5 ! root     1968:                   eventual smaller memory store! Thanks to Quake68k for exposing
        !          1969:                   this detail ;-) */
1.1       root     1970:                nr=alloc_reg_hinted(r,oldstate.dirtysize,1,spec);
                   1971:        }
                   1972:        else {
                   1973:                nr=alloc_reg_hinted(r,4,1,spec);
                   1974:        }
                   1975:        nind=live.state[r].realind;
                   1976:        live.state[r]=oldstate;   /* Keep all the old state info */
                   1977:        live.state[r].realreg=nr;
                   1978:        live.state[r].realind=nind;
                   1979: 
                   1980:        if (size<live.state[r].validsize) {
                   1981:                if (live.state[r].val) {
                   1982:                        /* Might as well compensate for the offset now */
1.1.1.3   root     1983:                        compemu_raw_lea_l_brr(nr,rr,oldstate.val);
1.1       root     1984:                        live.state[r].val=0;
                   1985:                        live.state[r].dirtysize=4;
                   1986:                        set_status(r,DIRTY);
                   1987:                }
                   1988:                else
1.1.1.3   root     1989:                        compemu_raw_mov_l_rr(nr,rr);  /* Make another copy */
1.1       root     1990:        }
1.1.1.3   root     1991:        unlock2(rr);
1.1       root     1992: }
                   1993: 
1.1.1.3   root     1994: static inline void add_offset(int r, uae_u32 off)
1.1       root     1995: {
                   1996:        live.state[r].val+=off;
                   1997: }
                   1998: 
1.1.1.3   root     1999: static inline void remove_offset(int r, int spec)
1.1       root     2000: {
                   2001:        int rr;
                   2002: 
                   2003:        if (isconst(r))
                   2004:                return;
                   2005:        if (live.state[r].val==0)
                   2006:                return;
                   2007:        if (isinreg(r) && live.state[r].validsize<4)
                   2008:                evict(r);
                   2009: 
                   2010:        if (!isinreg(r))
                   2011:                alloc_reg_hinted(r,4,0,spec);
                   2012: 
                   2013:        Dif (live.state[r].validsize!=4) {
1.1.1.3   root     2014:                jit_abort("Validsize=%d in remove_offset",live.state[r].validsize);
1.1       root     2015:        }
                   2016:        make_exclusive(r,0,-1);
                   2017:        /* make_exclusive might have done the job already */
                   2018:        if (live.state[r].val==0)
                   2019:                return;
                   2020: 
                   2021:        rr=live.state[r].realreg;
                   2022: 
                   2023:        if (live.nat[rr].nholds==1) {
1.1.1.3   root     2024:                jit_log2("RemovingB offset %x from reg %d (%d) at %p", live.state[r].val,r,rr,target);
1.1       root     2025:                adjust_nreg(rr,live.state[r].val);
                   2026:                live.state[r].dirtysize=4;
                   2027:                live.state[r].val=0;
                   2028:                set_status(r,DIRTY);
                   2029:                return;
                   2030:        }
1.1.1.3   root     2031:        jit_abort("Failed in remove_offset");
1.1       root     2032: }
                   2033: 
1.1.1.3   root     2034: static inline void remove_all_offsets(void)
1.1       root     2035: {
                   2036:        int i;
                   2037: 
                   2038:        for (i=0;i<VREGS;i++)
                   2039:                remove_offset(i,-1);
                   2040: }
                   2041: 
1.1.1.3   root     2042: static inline void flush_reg_count(void)
                   2043: {
                   2044: #ifdef RECORD_REGISTER_USAGE
1.1.1.5 ! root     2045:        for (int r = 0; r < 16; r++)
        !          2046:                if (reg_count_local[r])
        !          2047:                        ADDQim(reg_count_local[r], ((uintptr)reg_count) + (8 * r), X86_NOREG, X86_NOREG, 1);
1.1.1.3   root     2048: #endif
                   2049: }
                   2050: 
                   2051: static inline void record_register(int r)
                   2052: {
                   2053: #ifdef RECORD_REGISTER_USAGE
1.1.1.5 ! root     2054:        if (r < 16)
        !          2055:                reg_count_local[r]++;
1.1.1.3   root     2056: #else
                   2057:        UNUSED(r);
                   2058: #endif
                   2059: }
                   2060: 
                   2061: static inline int readreg_general(int r, int size, int spec, int can_offset)
1.1       root     2062: {
                   2063:        int n;
                   2064:        int answer=-1;
                   2065: 
1.1.1.3   root     2066:        record_register(r);
1.1       root     2067:        if (live.state[r].status==UNDEF) {
1.1.1.3   root     2068:                jit_log("WARNING: Unexpected read of undefined register %d",r);
1.1       root     2069:        }
                   2070:        if (!can_offset)
                   2071:                remove_offset(r,spec);
                   2072: 
                   2073:        if (isinreg(r) && live.state[r].validsize>=size) {
                   2074:                n=live.state[r].realreg;
                   2075:                switch(size) {
                   2076:                case 1:
                   2077:                        if (live.nat[n].canbyte || spec>=0) {
                   2078:                                answer=n;
                   2079:                        }
                   2080:                        break;
                   2081:                case 2:
                   2082:                        if (live.nat[n].canword || spec>=0) {
                   2083:                                answer=n;
                   2084:                        }
                   2085:                        break;
                   2086:                case 4:
                   2087:                        answer=n;
                   2088:                        break;
                   2089:                default: abort();
                   2090:                }
                   2091:                if (answer<0)
                   2092:                        evict(r);
                   2093:        }
                   2094:        /* either the value was in memory to start with, or it was evicted and
1.1.1.5 ! root     2095:           is in memory now */
1.1       root     2096:        if (answer<0) {
                   2097:                answer=alloc_reg_hinted(r,spec>=0?4:size,0,spec);
                   2098:        }
                   2099: 
                   2100:        if (spec>=0 && spec!=answer) {
                   2101:                /* Too bad */
                   2102:                mov_nregs(spec,answer);
                   2103:                answer=spec;
                   2104:        }
                   2105:        live.nat[answer].locked++;
                   2106:        live.nat[answer].touched=touchcnt++;
                   2107:        return answer;
                   2108: }
                   2109: 
                   2110: 
                   2111: 
                   2112: static int readreg(int r, int size)
                   2113: {
                   2114:        return readreg_general(r,size,-1,0);
                   2115: }
                   2116: 
                   2117: static int readreg_specific(int r, int size, int spec)
                   2118: {
                   2119:        return readreg_general(r,size,spec,0);
                   2120: }
                   2121: 
                   2122: static int readreg_offset(int r, int size)
                   2123: {
                   2124:        return readreg_general(r,size,-1,1);
                   2125: }
                   2126: 
1.1.1.3   root     2127: /* writereg_general(r, size, spec)
                   2128:  *
                   2129:  * INPUT
                   2130:  * - r    : mid-layer register
                   2131:  * - size : requested size (1/2/4)
                   2132:  * - spec : -1 if find or make a register free, otherwise specifies
                   2133:  *          the physical register to use in any case
                   2134:  *
                   2135:  * OUTPUT
                   2136:  * - hard (physical, x86 here) register allocated to virtual register r
                   2137:  */
                   2138: static inline int writereg_general(int r, int size, int spec)
1.1       root     2139: {
                   2140:        int n;
                   2141:        int answer=-1;
                   2142: 
1.1.1.3   root     2143:        record_register(r);
1.1       root     2144:        if (size<4) {
                   2145:                remove_offset(r,spec);
                   2146:        }
                   2147: 
                   2148:        make_exclusive(r,size,spec);
                   2149:        if (isinreg(r)) {
                   2150:                int nvsize=size>live.state[r].validsize?size:live.state[r].validsize;
                   2151:                int ndsize=size>live.state[r].dirtysize?size:live.state[r].dirtysize;
                   2152:                n=live.state[r].realreg;
                   2153: 
                   2154:                Dif (live.nat[n].nholds!=1)
1.1.1.3   root     2155:                        jit_abort("live.nat[%d].nholds!=1", n);
1.1       root     2156:                switch(size) {
                   2157:                case 1:
                   2158:                        if (live.nat[n].canbyte || spec>=0) {
                   2159:                                live.state[r].dirtysize=ndsize;
                   2160:                                live.state[r].validsize=nvsize;
                   2161:                                answer=n;
                   2162:                        }
                   2163:                        break;
                   2164:                case 2:
                   2165:                        if (live.nat[n].canword || spec>=0) {
                   2166:                                live.state[r].dirtysize=ndsize;
                   2167:                                live.state[r].validsize=nvsize;
                   2168:                                answer=n;
                   2169:                        }
                   2170:                        break;
                   2171:                case 4:
                   2172:                        live.state[r].dirtysize=ndsize;
                   2173:                        live.state[r].validsize=nvsize;
                   2174:                        answer=n;
                   2175:                        break;
                   2176:                default: abort();
                   2177:                }
                   2178:                if (answer<0)
                   2179:                        evict(r);
                   2180:        }
                   2181:        /* either the value was in memory to start with, or it was evicted and
1.1.1.5 ! root     2182:           is in memory now */
1.1       root     2183:        if (answer<0) {
                   2184:                answer=alloc_reg_hinted(r,size,1,spec);
                   2185:        }
                   2186:        if (spec>=0 && spec!=answer) {
                   2187:                mov_nregs(spec,answer);
                   2188:                answer=spec;
                   2189:        }
                   2190:        if (live.state[r].status==UNDEF)
                   2191:                live.state[r].validsize=4;
                   2192:        live.state[r].dirtysize=size>live.state[r].dirtysize?size:live.state[r].dirtysize;
                   2193:        live.state[r].validsize=size>live.state[r].validsize?size:live.state[r].validsize;
                   2194: 
                   2195:        live.nat[answer].locked++;
                   2196:        live.nat[answer].touched=touchcnt++;
                   2197:        if (size==4) {
                   2198:                live.state[r].val=0;
                   2199:        }
                   2200:        else {
                   2201:                Dif (live.state[r].val) {
1.1.1.3   root     2202:                        jit_abort("Problem with val");
1.1       root     2203:                }
                   2204:        }
                   2205:        set_status(r,DIRTY);
                   2206:        return answer;
                   2207: }
                   2208: 
                   2209: static int writereg(int r, int size)
                   2210: {
                   2211:        return writereg_general(r,size,-1);
                   2212: }
                   2213: 
                   2214: static int writereg_specific(int r, int size, int spec)
                   2215: {
                   2216:        return writereg_general(r,size,spec);
                   2217: }
                   2218: 
1.1.1.3   root     2219: static inline int rmw_general(int r, int wsize, int rsize, int spec)
1.1       root     2220: {
                   2221:        int n;
                   2222:        int answer=-1;
                   2223: 
1.1.1.3   root     2224:        record_register(r);
1.1       root     2225:        if (live.state[r].status==UNDEF) {
1.1.1.3   root     2226:                jit_log("WARNING: Unexpected read of undefined register %d",r);
1.1       root     2227:        }
                   2228:        remove_offset(r,spec);
                   2229:        make_exclusive(r,0,spec);
                   2230: 
                   2231:        Dif (wsize<rsize) {
1.1.1.3   root     2232:                jit_abort("Cannot handle wsize<rsize in rmw_general()");
1.1       root     2233:        }
                   2234:        if (isinreg(r) && live.state[r].validsize>=rsize) {
                   2235:                n=live.state[r].realreg;
                   2236:                Dif (live.nat[n].nholds!=1)
1.1.1.5 ! root     2237:                        jit_abort("live.nat[%d].nholds!=1", n);
1.1       root     2238: 
                   2239:                switch(rsize) {
                   2240:                case 1:
                   2241:                        if (live.nat[n].canbyte || spec>=0) {
                   2242:                                answer=n;
                   2243:                        }
                   2244:                        break;
                   2245:                case 2:
                   2246:                        if (live.nat[n].canword || spec>=0) {
                   2247:                                answer=n;
                   2248:                        }
                   2249:                        break;
                   2250:                case 4:
                   2251:                        answer=n;
                   2252:                        break;
                   2253:                default: abort();
                   2254:                }
                   2255:                if (answer<0)
                   2256:                        evict(r);
                   2257:        }
                   2258:        /* either the value was in memory to start with, or it was evicted and
1.1.1.5 ! root     2259:           is in memory now */
1.1       root     2260:        if (answer<0) {
                   2261:                answer=alloc_reg_hinted(r,spec>=0?4:rsize,0,spec);
                   2262:        }
                   2263: 
                   2264:        if (spec>=0 && spec!=answer) {
                   2265:                /* Too bad */
                   2266:                mov_nregs(spec,answer);
                   2267:                answer=spec;
                   2268:        }
                   2269:        if (wsize>live.state[r].dirtysize)
                   2270:                live.state[r].dirtysize=wsize;
                   2271:        if (wsize>live.state[r].validsize)
                   2272:                live.state[r].validsize=wsize;
                   2273:        set_status(r,DIRTY);
                   2274: 
                   2275:        live.nat[answer].locked++;
                   2276:        live.nat[answer].touched=touchcnt++;
                   2277: 
                   2278:        Dif (live.state[r].val) {
1.1.1.3   root     2279:                jit_abort("Problem with val(rmw)");
1.1       root     2280:        }
                   2281:        return answer;
                   2282: }
                   2283: 
                   2284: static int rmw(int r, int wsize, int rsize)
                   2285: {
                   2286:        return rmw_general(r,wsize,rsize,-1);
                   2287: }
                   2288: 
                   2289: static int rmw_specific(int r, int wsize, int rsize, int spec)
                   2290: {
                   2291:        return rmw_general(r,wsize,rsize,spec);
                   2292: }
                   2293: 
                   2294: 
                   2295: /* needed for restoring the carry flag on non-P6 cores */
1.1.1.3   root     2296: static void bt_l_ri_noclobber(RR4 r, IMM i)
1.1       root     2297: {
                   2298:        int size=4;
                   2299:        if (i<16)
                   2300:                size=2;
                   2301:        r=readreg(r,size);
1.1.1.3   root     2302:        compemu_raw_bt_l_ri(r,i);
                   2303:        unlock2(r);
1.1       root     2304: }
                   2305: 
                   2306: /********************************************************************
1.1.1.3   root     2307:  * FPU register status handling. EMIT TIME!                         *
                   2308:  ********************************************************************/
1.1       root     2309: 
1.1.1.5 ! root     2310: static void f_tomem(int r)
1.1       root     2311: {
                   2312:        if (live.fate[r].status==DIRTY) {
1.1.1.5 ! root     2313:                if (use_long_double) {
        !          2314:                        raw_fmov_ext_mr((uintptr)live.fate[r].mem, live.fate[r].realreg);
        !          2315:                } else {
        !          2316:                        raw_fmov_mr((uintptr)live.fate[r].mem, live.fate[r].realreg);
        !          2317:                }
1.1       root     2318:                live.fate[r].status=CLEAN;
                   2319:        }
                   2320: }
                   2321: 
1.1.1.5 ! root     2322: static void f_tomem_drop(int r)
1.1       root     2323: {
                   2324:        if (live.fate[r].status==DIRTY) {
1.1.1.5 ! root     2325:                if (use_long_double) {
        !          2326:                        raw_fmov_ext_mr_drop((uintptr)live.fate[r].mem, live.fate[r].realreg);
        !          2327:                } else {
        !          2328:                        raw_fmov_mr_drop((uintptr)live.fate[r].mem, live.fate[r].realreg);
        !          2329:                }
1.1       root     2330:                live.fate[r].status=INMEM;
                   2331:        }
                   2332: }
                   2333: 
                   2334: 
1.1.1.3   root     2335: static inline int f_isinreg(int r)
1.1       root     2336: {
                   2337:        return live.fate[r].status==CLEAN || live.fate[r].status==DIRTY;
                   2338: }
                   2339: 
                   2340: static void f_evict(int r)
                   2341: {
                   2342:        int rr;
                   2343: 
                   2344:        if (!f_isinreg(r))
                   2345:                return;
                   2346:        rr=live.fate[r].realreg;
                   2347:        if (live.fat[rr].nholds==1)
                   2348:                f_tomem_drop(r);
                   2349:        else
                   2350:                f_tomem(r);
                   2351: 
                   2352:        Dif (live.fat[rr].locked &&
                   2353:                live.fat[rr].nholds==1) {
1.1.1.5 ! root     2354:                jit_abort("FPU register %d in nreg %d is locked!",r,live.fate[r].realreg);
1.1       root     2355:        }
                   2356: 
                   2357:        live.fat[rr].nholds--;
                   2358:        if (live.fat[rr].nholds!=live.fate[r].realind) { /* Was not last */
                   2359:                int topreg=live.fat[rr].holds[live.fat[rr].nholds];
                   2360:                int thisind=live.fate[r].realind;
                   2361:                live.fat[rr].holds[thisind]=topreg;
                   2362:                live.fate[topreg].realind=thisind;
                   2363:        }
                   2364:        live.fate[r].status=INMEM;
                   2365:        live.fate[r].realreg=-1;
                   2366: }
                   2367: 
1.1.1.3   root     2368: static inline void f_free_nreg(int r)
1.1       root     2369: {
                   2370:        int i=live.fat[r].nholds;
                   2371: 
                   2372:        while (i) {
                   2373:                int vr;
                   2374: 
                   2375:                --i;
                   2376:                vr=live.fat[r].holds[i];
                   2377:                f_evict(vr);
                   2378:        }
                   2379:        Dif (live.fat[r].nholds!=0) {
1.1.1.3   root     2380:                jit_abort("Failed to free nreg %d, nholds is %d",r,live.fat[r].nholds);
1.1       root     2381:        }
                   2382: }
                   2383: 
                   2384: 
                   2385: /* Use with care! */
1.1.1.3   root     2386: static inline void f_isclean(int r)
1.1       root     2387: {
                   2388:        if (!f_isinreg(r))
                   2389:                return;
                   2390:        live.fate[r].status=CLEAN;
                   2391: }
                   2392: 
1.1.1.3   root     2393: static inline void f_disassociate(int r)
1.1       root     2394: {
                   2395:        f_isclean(r);
                   2396:        f_evict(r);
                   2397: }
                   2398: 
                   2399: 
                   2400: 
1.1.1.5 ! root     2401: static int f_alloc_reg(int r, int willclobber)
1.1       root     2402: {
                   2403:        int bestreg;
                   2404:        uae_s32 when;
                   2405:        int i;
                   2406:        uae_s32 badness;
                   2407:        bestreg=-1;
                   2408:        when=2000000000;
                   2409:        for (i=N_FREGS;i--;) {
                   2410:                badness=live.fat[i].touched;
                   2411:                if (live.fat[i].nholds==0)
                   2412:                        badness=0;
                   2413: 
                   2414:                if (!live.fat[i].locked && badness<when) {
                   2415:                        bestreg=i;
                   2416:                        when=badness;
                   2417:                        if (live.fat[i].nholds==0)
                   2418:                                break;
                   2419:                }
                   2420:        }
                   2421:        Dif (bestreg==-1)
1.1.1.5 ! root     2422:                jit_abort("bestreg==-1");
1.1       root     2423: 
                   2424:        if (live.fat[bestreg].nholds>0) {
                   2425:                f_free_nreg(bestreg);
                   2426:        }
                   2427:        if (f_isinreg(r)) {
                   2428:                f_evict(r);
                   2429:        }
                   2430: 
                   2431:        if (!willclobber) {
                   2432:                if (live.fate[r].status!=UNDEF) {
1.1.1.5 ! root     2433:                        if (use_long_double) {
        !          2434:                                raw_fmov_ext_rm(bestreg, (uintptr)live.fate[r].mem);
        !          2435:                        } else {
        !          2436:                                raw_fmov_rm(bestreg, (uintptr)live.fate[r].mem);
        !          2437:                        }
1.1       root     2438:                }
                   2439:                live.fate[r].status=CLEAN;
                   2440:        }
                   2441:        else {
                   2442:                live.fate[r].status=DIRTY;
                   2443:        }
                   2444:        live.fate[r].realreg=bestreg;
                   2445:        live.fate[r].realind=live.fat[bestreg].nholds;
                   2446:        live.fat[bestreg].touched=touchcnt++;
                   2447:        live.fat[bestreg].holds[live.fat[bestreg].nholds]=r;
                   2448:        live.fat[bestreg].nholds++;
                   2449: 
                   2450:        return bestreg;
                   2451: }
                   2452: 
1.1.1.5 ! root     2453: static void f_unlock(int r)
1.1       root     2454: {
                   2455:        Dif (!live.fat[r].locked)
1.1.1.5 ! root     2456:                jit_abort ("unlock %d", r);
1.1       root     2457:        live.fat[r].locked--;
                   2458: }
                   2459: 
1.1.1.5 ! root     2460: static void f_setlock(int r)
1.1       root     2461: {
                   2462:        live.fat[r].locked++;
                   2463: }
                   2464: 
1.1.1.3   root     2465: static inline int f_readreg(int r)
1.1       root     2466: {
                   2467:        int n;
                   2468:        int answer=-1;
                   2469: 
                   2470:        if (f_isinreg(r)) {
                   2471:                n=live.fate[r].realreg;
                   2472:                answer=n;
                   2473:        }
                   2474:        /* either the value was in memory to start with, or it was evicted and
1.1.1.5 ! root     2475:           is in memory now */
1.1       root     2476:        if (answer<0)
                   2477:                answer=f_alloc_reg(r,0);
                   2478: 
                   2479:        live.fat[answer].locked++;
                   2480:        live.fat[answer].touched=touchcnt++;
                   2481:        return answer;
                   2482: }
                   2483: 
1.1.1.3   root     2484: static inline void f_make_exclusive(int r, int clobber)
1.1       root     2485: {
                   2486:        freg_status oldstate;
                   2487:        int rr=live.fate[r].realreg;
                   2488:        int nr;
                   2489:        int nind;
                   2490:        int ndirt=0;
                   2491:        int i;
                   2492: 
                   2493:        if (!f_isinreg(r))
                   2494:                return;
                   2495:        if (live.fat[rr].nholds==1)
                   2496:                return;
                   2497:        for (i=0;i<live.fat[rr].nholds;i++) {
                   2498:                int vr=live.fat[rr].holds[i];
                   2499:                if (vr!=r && live.fate[vr].status==DIRTY)
                   2500:                        ndirt++;
                   2501:        }
                   2502:        if (!ndirt && !live.fat[rr].locked) {
                   2503:                /* Everything else is clean, so let's keep this register */
                   2504:                for (i=0;i<live.fat[rr].nholds;i++) {
                   2505:                        int vr=live.fat[rr].holds[i];
                   2506:                        if (vr!=r) {
                   2507:                                f_evict(vr);
                   2508:                                i--; /* Try that index again! */
                   2509:                        }
                   2510:                }
                   2511:                Dif (live.fat[rr].nholds!=1) {
1.1.1.3   root     2512:                        jit_log("realreg %d holds %d (",rr,live.fat[rr].nholds);
1.1       root     2513:                        for (i=0;i<live.fat[rr].nholds;i++) {
1.1.1.3   root     2514:                                jit_log(" %d(%d,%d)",live.fat[rr].holds[i],
1.1       root     2515:                                        live.fate[live.fat[rr].holds[i]].realreg,
                   2516:                                        live.fate[live.fat[rr].holds[i]].realind);
                   2517:                        }
1.1.1.3   root     2518:                        jit_log("");
                   2519:                        jit_abort("x");
1.1       root     2520:                }
                   2521:                return;
                   2522:        }
                   2523: 
                   2524:        /* We have to split the register */
                   2525:        oldstate=live.fate[r];
                   2526: 
                   2527:        f_setlock(rr); /* Make sure this doesn't go away */
                   2528:        /* Forget about r being in the register rr */
                   2529:        f_disassociate(r);
                   2530:        /* Get a new register, that we will clobber completely */
                   2531:        nr=f_alloc_reg(r,1);
                   2532:        nind=live.fate[r].realind;
                   2533:        if (!clobber)
                   2534:                raw_fmov_rr(nr,rr);  /* Make another copy */
                   2535:        live.fate[r]=oldstate;   /* Keep all the old state info */
                   2536:        live.fate[r].realreg=nr;
                   2537:        live.fate[r].realind=nind;
                   2538:        f_unlock(rr);
                   2539: }
                   2540: 
                   2541: 
1.1.1.3   root     2542: static inline int f_writereg(int r)
1.1       root     2543: {
                   2544:        int n;
                   2545:        int answer=-1;
                   2546: 
                   2547:        f_make_exclusive(r,1);
                   2548:        if (f_isinreg(r)) {
                   2549:                n=live.fate[r].realreg;
                   2550:                answer=n;
                   2551:        }
                   2552:        if (answer<0) {
                   2553:                answer=f_alloc_reg(r,1);
                   2554:        }
                   2555:        live.fate[r].status=DIRTY;
                   2556:        live.fat[answer].locked++;
                   2557:        live.fat[answer].touched=touchcnt++;
                   2558:        return answer;
                   2559: }
                   2560: 
1.1.1.3   root     2561: #if defined(CPU_arm)
                   2562: #include "compemu_midfunc_arm.cpp"
1.1       root     2563: 
1.1.1.3   root     2564: #if defined(USE_JIT2)
                   2565: #include "compemu_midfunc_arm2.cpp"
                   2566: #endif
                   2567: #endif
1.1       root     2568: 
1.1.1.3   root     2569: #if defined(CPU_i386) || defined(CPU_x86_64)
                   2570: #include "compemu_midfunc_x86.cpp"
                   2571: #endif
1.1       root     2572: 
                   2573: 
1.1.1.3   root     2574: /********************************************************************
                   2575:  * Support functions exposed to gencomp. CREATE time                *
                   2576:  ********************************************************************/
1.1       root     2577: 
1.1.1.3   root     2578: void set_zero(int r, int tmp)
1.1       root     2579: {
1.1.1.5 ! root     2580:        if (setzflg_uses_bsf)
        !          2581:                bsf_l_rr(r,r);
        !          2582:        else
        !          2583:                simulate_bsf(tmp,r);
1.1       root     2584: }
                   2585: 
1.1.1.3   root     2586: int kill_rodent(int r)
1.1       root     2587: {
1.1.1.3   root     2588:        return KILLTHERAT &&
                   2589:                have_rat_stall &&
                   2590:                (live.state[r].status==INMEM ||
1.1.1.5 ! root     2591:                 live.state[r].status==CLEAN ||
        !          2592:                 live.state[r].status==ISCONST ||
        !          2593:                 live.state[r].dirtysize==4);
1.1       root     2594: }
                   2595: 
1.1.1.3   root     2596: uae_u32 get_const(int r)
1.1       root     2597: {
1.1.1.5 ! root     2598:        Dif (!isconst(r)) {
        !          2599:                jit_abort("Register %d should be constant, but isn't",r);
1.1       root     2600:        }
1.1.1.3   root     2601:        return live.state[r].val;
1.1       root     2602: }
                   2603: 
1.1.1.3   root     2604: void sync_m68k_pc(void)
1.1       root     2605: {
1.1.1.3   root     2606:        if (m68k_pc_offset) {
                   2607:                add_l_ri(PC_P,m68k_pc_offset);
                   2608:                comp_pc_p+=m68k_pc_offset;
                   2609:                m68k_pc_offset=0;
                   2610:        }
1.1       root     2611: }
                   2612: 
1.1.1.3   root     2613: /********************************************************************
                   2614:  * Scratch registers management                                     *
                   2615:  ********************************************************************/
1.1       root     2616: 
1.1.1.3   root     2617: struct scratch_t {
                   2618:        uae_u32         regs[VREGS];
                   2619:        fpu_register    fregs[VFREGS];
                   2620: };
1.1       root     2621: 
1.1.1.3   root     2622: static scratch_t scratch;
1.1       root     2623: 
1.1.1.3   root     2624: /********************************************************************
                   2625:  * Support functions exposed to newcpu                              *
                   2626:  ********************************************************************/
1.1       root     2627: 
1.1.1.3   root     2628: static inline const char *str_on_off(bool b)
1.1       root     2629: {
1.1.1.3   root     2630:        return b ? "on" : "off";
1.1       root     2631: }
                   2632: 
1.1.1.3   root     2633: #ifdef UAE
                   2634: static
                   2635: #endif
                   2636: void compiler_init(void)
1.1       root     2637: {
1.1.1.3   root     2638:        static bool initialized = false;
                   2639:        if (initialized)
                   2640:                return;
1.1       root     2641: 
1.1.1.3   root     2642: #ifdef UAE
                   2643: #else
                   2644: #ifdef JIT_DEBUG
                   2645:        // JIT debug mode ?
1.1.1.5 ! root     2646:        JITDebug = bx_options.jit.jitdebug;
1.1.1.3   root     2647: #endif
                   2648:        jit_log("<JIT compiler> : enable runtime disassemblers : %s", JITDebug ? "yes" : "no");
                   2649: 
                   2650: #ifdef USE_JIT_FPU
                   2651:        // Use JIT compiler for FPU instructions ?
                   2652:        avoid_fpu = !bx_options.jit.jitfpu;
                   2653: #else
                   2654:        // JIT FPU is always disabled
                   2655:        avoid_fpu = true;
                   2656: #endif
                   2657:        jit_log("<JIT compiler> : compile FPU instructions : %s", !avoid_fpu ? "yes" : "no");
1.1       root     2658: 
1.1.1.3   root     2659:        // Get size of the translation cache (in KB)
                   2660:        cache_size = bx_options.jit.jitcachesize;
                   2661:        jit_log("<JIT compiler> : requested translation cache size : %d KB", cache_size);
1.1       root     2662: 
1.1.1.3   root     2663:        setzflg_uses_bsf = target_check_bsf();
                   2664:        jit_log("<JIT compiler> : target processor has CMOV instructions : %s", have_cmov ? "yes" : "no");
                   2665:        jit_log("<JIT compiler> : target processor can suffer from partial register stalls : %s", have_rat_stall ? "yes" : "no");
                   2666:        jit_log("<JIT compiler> : alignment for loops, jumps are %d, %d", align_loops, align_jumps);
                   2667: #if defined(CPU_i386) || defined(CPU_x86_64)
                   2668:        jit_log("<JIT compiler> : target processor has SSE2 instructions : %s", cpuinfo.x86_has_xmm2 ? "yes" : "no");
                   2669:        jit_log("<JIT compiler> : cache linesize is %lu", (unsigned long)cpuinfo.x86_clflush_size);
                   2670: #endif
1.1       root     2671: 
1.1.1.3   root     2672:        // Translation cache flush mechanism
                   2673:        lazy_flush = (bx_options.jit.jitlazyflush == 0) ? false : true;
                   2674:        jit_log("<JIT compiler> : lazy translation cache invalidation : %s", str_on_off(lazy_flush));
                   2675:        flush_icache = lazy_flush ? flush_icache_lazy : flush_icache_hard;
1.1       root     2676: 
1.1.1.3   root     2677:        // Compiler features
                   2678:        jit_log("<JIT compiler> : register aliasing : %s", str_on_off(1));
                   2679:        jit_log("<JIT compiler> : FP register aliasing : %s", str_on_off(USE_F_ALIAS));
                   2680:        jit_log("<JIT compiler> : lazy constant offsetting : %s", str_on_off(USE_OFFSET));
                   2681: #if USE_INLINING
                   2682:        follow_const_jumps = bx_options.jit.jitinline;
                   2683: #endif
                   2684:        jit_log("<JIT compiler> : block inlining : %s", str_on_off(follow_const_jumps));
                   2685:        jit_log("<JIT compiler> : separate blockinfo allocation : %s", str_on_off(USE_SEPARATE_BIA));
1.1       root     2686: 
1.1.1.3   root     2687:        // Build compiler tables
                   2688:        build_comp();
                   2689: #endif
1.1       root     2690: 
1.1.1.3   root     2691:        initialized = true;
1.1       root     2692: 
1.1.1.3   root     2693: #ifdef PROFILE_UNTRANSLATED_INSNS
                   2694:        jit_log("<JIT compiler> : gather statistics on untranslated insns count");
                   2695: #endif
1.1       root     2696: 
1.1.1.3   root     2697: #ifdef PROFILE_COMPILE_TIME
                   2698:        jit_log("<JIT compiler> : gather statistics on translation time");
                   2699:        emul_start_time = clock();
                   2700: #endif
1.1       root     2701: }
                   2702: 
1.1.1.3   root     2703: #ifdef UAE
                   2704: static
                   2705: #endif
                   2706: void compiler_exit(void)
1.1       root     2707: {
1.1.1.3   root     2708: #ifdef PROFILE_COMPILE_TIME
                   2709:        emul_end_time = clock();
                   2710: #endif
1.1       root     2711: 
1.1.1.3   root     2712: #ifdef UAE
                   2713: #else
                   2714: #if DEBUG
                   2715: #if defined(USE_DATA_BUFFER)
1.1.1.5 ! root     2716:        jit_log("data_wasted = %d bytes", data_wasted);
1.1.1.3   root     2717: #endif
                   2718: #endif
1.1.1.5 ! root     2719: 
1.1.1.3   root     2720:        // Deallocate translation cache
                   2721:        if (compiled_code) {
                   2722:                vm_release(compiled_code, cache_size * 1024);
                   2723:                compiled_code = 0;
1.1       root     2724:        }
                   2725: 
1.1.1.3   root     2726:        // Deallocate popallspace
                   2727:        if (popallspace) {
                   2728:                vm_release(popallspace, POPALLSPACE_SIZE);
                   2729:                popallspace = 0;
1.1       root     2730:        }
1.1.1.3   root     2731: #endif
1.1       root     2732: 
1.1.1.3   root     2733: #ifdef PROFILE_COMPILE_TIME
                   2734:        jit_log("### Compile Block statistics");
                   2735:        jit_log("Number of calls to compile_block : %d", compile_count);
                   2736:        uae_u32 emul_time = emul_end_time - emul_start_time;
                   2737:        jit_log("Total emulation time   : %.1f sec", double(emul_time)/double(CLOCKS_PER_SEC));
                   2738:        jit_log("Total compilation time : %.1f sec (%.1f%%)", double(compile_time)/double(CLOCKS_PER_SEC), 100.0*double(compile_time)/double(emul_time));
                   2739: #endif
                   2740: 
                   2741: #ifdef PROFILE_UNTRANSLATED_INSNS
                   2742:        uae_u64 untranslated_count = 0;
                   2743:        for (int i = 0; i < 65536; i++) {
                   2744:                opcode_nums[i] = i;
                   2745:                untranslated_count += raw_cputbl_count[i];
                   2746:        }
1.1.1.5 ! root     2747:        bug("Sorting out untranslated instructions count...");
1.1.1.3   root     2748:        qsort(opcode_nums, 65536, sizeof(uae_u16), untranslated_compfn);
                   2749:        jit_log("Rank  Opc      Count Name");
                   2750:        for (int i = 0; i < untranslated_top_ten; i++) {
                   2751:                uae_u32 count = raw_cputbl_count[opcode_nums[i]];
                   2752:                struct instr *dp;
                   2753:                struct mnemolookup *lookup;
                   2754:                if (!count)
                   2755:                        break;
                   2756:                dp = table68k + opcode_nums[i];
                   2757:                for (lookup = lookuptab; lookup->mnemo != (instrmnem)dp->mnemo; lookup++)
                   2758:                        ;
1.1.1.5 ! root     2759:                bug("%03d: %04x %10u %s", i, opcode_nums[i], count, lookup->name);
1.1       root     2760:        }
1.1.1.3   root     2761: #endif
1.1       root     2762: 
1.1.1.3   root     2763: #ifdef RECORD_REGISTER_USAGE
                   2764:        int reg_count_ids[16];
                   2765:        uint64 tot_reg_count = 0;
                   2766:        for (int i = 0; i < 16; i++) {
1.1.1.5 ! root     2767:                reg_count_ids[i] = i;
        !          2768:                tot_reg_count += reg_count[i];
1.1.1.3   root     2769:        }
                   2770:        qsort(reg_count_ids, 16, sizeof(int), reg_count_compare);
                   2771:        uint64 cum_reg_count = 0;
                   2772:        for (int i = 0; i < 16; i++) {
1.1.1.5 ! root     2773:                int r = reg_count_ids[i];
        !          2774:                cum_reg_count += reg_count[r];
        !          2775:                jit_log("%c%d : %16ld %2.1f%% [%2.1f]", r < 8 ? 'D' : 'A', r % 8,
1.1.1.3   root     2776:                   reg_count[r],
                   2777:                   100.0*double(reg_count[r])/double(tot_reg_count),
                   2778:                   100.0*double(cum_reg_count)/double(tot_reg_count));
1.1       root     2779:        }
1.1.1.3   root     2780: #endif
1.1       root     2781: }
                   2782: 
1.1.1.3   root     2783: #ifdef UAE
                   2784: #else
                   2785: bool compiler_use_jit(void)
1.1       root     2786: {
1.1.1.3   root     2787:        // Check for the "jit" prefs item
                   2788:        if (!bx_options.jit.jit)
                   2789:                return false;
                   2790:        
                   2791:        // Don't use JIT if translation cache size is less then MIN_CACHE_SIZE KB
                   2792:        if (bx_options.jit.jitcachesize < MIN_CACHE_SIZE) {
                   2793:                panicbug("<JIT compiler> : translation cache size is less than %d KB. Disabling JIT.\n", MIN_CACHE_SIZE);
                   2794:                return false;
1.1       root     2795:        }
1.1.1.3   root     2796:        
                   2797:        return true;
1.1       root     2798: }
1.1.1.3   root     2799: #endif
1.1       root     2800: 
1.1.1.3   root     2801: void init_comp(void)
                   2802: {
                   2803:        int i;
                   2804:        uae_s8* cb=can_byte;
                   2805:        uae_s8* cw=can_word;
                   2806:        uae_s8* au=always_used;
                   2807: 
                   2808: #ifdef RECORD_REGISTER_USAGE
                   2809:        for (i=0;i<16;i++)
                   2810:                reg_count_local[i] = 0;
                   2811: #endif
1.1       root     2812: 
1.1.1.3   root     2813:        for (i=0;i<VREGS;i++) {
                   2814:                live.state[i].realreg=-1;
                   2815:                live.state[i].needflush=NF_SCRATCH;
                   2816:                live.state[i].val=0;
                   2817:                set_status(i,UNDEF);
1.1       root     2818:        }
                   2819: 
1.1.1.3   root     2820:        for (i=0;i<VFREGS;i++) {
                   2821:                live.fate[i].status=UNDEF;
                   2822:                live.fate[i].realreg=-1;
                   2823:                live.fate[i].needflush=NF_SCRATCH;
1.1       root     2824:        }
                   2825: 
1.1.1.3   root     2826:        for (i=0;i<VREGS;i++) {
                   2827:                if (i<16) { /* First 16 registers map to 68k registers */
                   2828:                        live.state[i].mem=&regs.regs[i];
                   2829:                        live.state[i].needflush=NF_TOMEM;
                   2830:                        set_status(i,INMEM);
                   2831:                }
                   2832:                else
                   2833:                        live.state[i].mem=scratch.regs+i;
1.1       root     2834:        }
1.1.1.3   root     2835:        live.state[PC_P].mem=(uae_u32*)&(regs.pc_p);
                   2836:        live.state[PC_P].needflush=NF_TOMEM;
                   2837:        set_const(PC_P,(uintptr)comp_pc_p);
1.1       root     2838: 
1.1.1.3   root     2839:        live.state[FLAGX].mem=(uae_u32*)&(regflags.x);
                   2840:        live.state[FLAGX].needflush=NF_TOMEM;
                   2841:        set_status(FLAGX,INMEM);
1.1       root     2842: 
1.1.1.3   root     2843: #if defined(CPU_arm)
                   2844:        live.state[FLAGTMP].mem=(uae_u32*)&(regflags.nzcv);
                   2845: #else
                   2846:        live.state[FLAGTMP].mem=(uae_u32*)&(regflags.cznv);
                   2847: #endif
                   2848:        live.state[FLAGTMP].needflush=NF_TOMEM;
                   2849:        set_status(FLAGTMP,INMEM);
1.1       root     2850: 
                   2851:        live.state[NEXT_HANDLER].needflush=NF_HANDLER;
                   2852:        set_status(NEXT_HANDLER,UNDEF);
                   2853: 
                   2854:        for (i=0;i<VFREGS;i++) {
                   2855:                if (i<8) { /* First 8 registers map to 68k FPU registers */
1.1.1.3   root     2856: #ifdef UAE
1.1.1.2   root     2857:                        live.fate[i].mem=(uae_u32*)(&regs.fp[i].fp);
1.1.1.3   root     2858: #else
                   2859:                        live.fate[i].mem=(uae_u32*)fpu_register_address(i);
                   2860: #endif
1.1       root     2861:                        live.fate[i].needflush=NF_TOMEM;
                   2862:                        live.fate[i].status=INMEM;
                   2863:                }
                   2864:                else if (i==FP_RESULT) {
1.1.1.3   root     2865: #ifdef UAE
1.1.1.4   root     2866:                        live.fate[i].mem=(uae_u32*)(&regs.fp_result.fp);
1.1.1.3   root     2867: #else
                   2868:                        live.fate[i].mem=(uae_u32*)(&fpu.result);
                   2869: #endif
1.1       root     2870:                        live.fate[i].needflush=NF_TOMEM;
1.1.1.3   root     2871:                        live.fate[i].status=INMEM;
                   2872:                }
                   2873:                else
                   2874:                        live.fate[i].mem=(uae_u32*)(&scratch.fregs[i]);
1.1       root     2875:        }
                   2876: 
                   2877: 
1.1.1.3   root     2878:        for (i=0;i<N_REGS;i++) {
                   2879:                live.nat[i].touched=0;
                   2880:                live.nat[i].nholds=0;
                   2881:                live.nat[i].locked=0;
                   2882:                if (*cb==i) {
                   2883:                        live.nat[i].canbyte=1; cb++;
                   2884:                } else live.nat[i].canbyte=0;
                   2885:                if (*cw==i) {
                   2886:                        live.nat[i].canword=1; cw++;
                   2887:                } else live.nat[i].canword=0;
                   2888:                if (*au==i) {
                   2889:                        live.nat[i].locked=1; au++;
1.1       root     2890:                }
                   2891:        }
                   2892: 
1.1.1.3   root     2893:        for (i=0;i<N_FREGS;i++) {
                   2894:                live.fat[i].touched=0;
                   2895:                live.fat[i].nholds=0;
                   2896:                live.fat[i].locked=0;
1.1       root     2897:        }
1.1.1.3   root     2898: 
                   2899:        touchcnt=1;
                   2900:        m68k_pc_offset=0;
                   2901:        live.flags_in_flags=TRASH;
                   2902:        live.flags_on_stack=VALID;
                   2903:        live.flags_are_important=1;
                   2904: 
                   2905:        raw_fp_init();
1.1       root     2906: }
                   2907: 
                   2908: /* Only do this if you really mean it! The next call should be to init!*/
                   2909: void flush(int save_regs)
                   2910: {
                   2911:        int i;
                   2912: 
                   2913:        log_flush();
                   2914:        flush_flags(); /* low level */
                   2915:        sync_m68k_pc(); /* mid level */
                   2916: 
                   2917:        if (save_regs) {
                   2918:                for (i=0;i<VFREGS;i++) {
                   2919:                        if (live.fate[i].needflush==NF_SCRATCH ||
                   2920:                                live.fate[i].status==CLEAN) {
1.1.1.5 ! root     2921:                                f_disassociate(i);
1.1       root     2922:                        }
                   2923:                }
                   2924:                for (i=0;i<VREGS;i++) {
                   2925:                        if (live.state[i].needflush==NF_TOMEM) {
                   2926:                                switch(live.state[i].status) {
                   2927:                                case INMEM:
                   2928:                                        if (live.state[i].val) {
1.1.1.3   root     2929:                                                compemu_raw_add_l_mi((uintptr)live.state[i].mem,live.state[i].val);
                   2930:                                                log_vwrite(i);
1.1       root     2931:                                                live.state[i].val=0;
                   2932:                                        }
                   2933:                                        break;
                   2934:                                case CLEAN:
                   2935:                                case DIRTY:
1.1.1.5 ! root     2936:                                        remove_offset(i,-1);
        !          2937:                                        tomem(i);
        !          2938:                                        break;
1.1       root     2939:                                case ISCONST:
                   2940:                                        if (i!=PC_P)
                   2941:                                                writeback_const(i);
                   2942:                                        break;
                   2943:                                default: break;
                   2944:                                }
                   2945:                                Dif (live.state[i].val && i!=PC_P) {
1.1.1.3   root     2946:                                        jit_log("Register %d still has val %x", i,live.state[i].val);
1.1       root     2947:                                }
                   2948:                        }
                   2949:                }
                   2950:                for (i=0;i<VFREGS;i++) {
                   2951:                        if (live.fate[i].needflush==NF_TOMEM &&
                   2952:                                live.fate[i].status==DIRTY) {
1.1.1.5 ! root     2953:                                f_evict(i);
1.1       root     2954:                        }
                   2955:                }
                   2956:                raw_fp_cleanup_drop();
                   2957:        }
                   2958:        if (needflags) {
1.1.1.3   root     2959:                jit_log("Warning! flush with needflags=1!");
1.1       root     2960:        }
                   2961: }
                   2962: 
1.1.1.3   root     2963: #if 0
1.1       root     2964: static void flush_keepflags(void)
                   2965: {
                   2966:        int i;
                   2967: 
                   2968:        for (i=0;i<VFREGS;i++) {
                   2969:                if (live.fate[i].needflush==NF_SCRATCH ||
                   2970:                        live.fate[i].status==CLEAN) {
1.1.1.5 ! root     2971:                        f_disassociate(i);
1.1       root     2972:                }
                   2973:        }
                   2974:        for (i=0;i<VREGS;i++) {
                   2975:                if (live.state[i].needflush==NF_TOMEM) {
                   2976:                        switch(live.state[i].status) {
                   2977:                        case INMEM:
                   2978:                                /* Can't adjust the offset here --- that needs "add" */
                   2979:                                break;
                   2980:                        case CLEAN:
                   2981:                        case DIRTY:
1.1.1.5 ! root     2982:                                remove_offset(i,-1);
        !          2983:                                tomem(i);
        !          2984:                                break;
1.1       root     2985:                        case ISCONST:
                   2986:                                if (i!=PC_P)
                   2987:                                        writeback_const(i);
                   2988:                                break;
                   2989:                        default: break;
                   2990:                        }
                   2991:                }
                   2992:        }
                   2993:        for (i=0;i<VFREGS;i++) {
                   2994:                if (live.fate[i].needflush==NF_TOMEM &&
                   2995:                        live.fate[i].status==DIRTY) {
1.1.1.5 ! root     2996:                        f_evict(i);
1.1       root     2997:                }
                   2998:        }
                   2999:        raw_fp_cleanup_drop();
                   3000: }
1.1.1.3   root     3001: #endif
1.1       root     3002: 
                   3003: void freescratch(void)
                   3004: {
                   3005:        int i;
                   3006:        for (i=0;i<N_REGS;i++)
1.1.1.5 ! root     3007: #if defined(CPU_arm)
        !          3008:                if (live.nat[i].locked && i != REG_WORK1 && i != REG_WORK2)
        !          3009: #else
        !          3010:                if (live.nat[i].locked && i != ESP_INDEX
        !          3011: #if defined(UAE) && defined(CPU_x86_64)
        !          3012:                        && i != R12_INDEX
        !          3013: #endif
        !          3014:                        )
        !          3015: #endif
        !          3016:                {
1.1.1.3   root     3017:                        jit_log("Warning! %d is locked",i);
1.1.1.5 ! root     3018:                }
1.1       root     3019: 
                   3020:        for (i=0;i<VREGS;i++)
                   3021:                if (live.state[i].needflush==NF_SCRATCH) {
                   3022:                        forget_about(i);
                   3023:                }
                   3024: 
1.1.1.5 ! root     3025:        for (i=0;i<VFREGS;i++)
        !          3026:                if (live.fate[i].needflush==NF_SCRATCH) {
        !          3027:                        f_forget_about(i);
        !          3028:                }
1.1       root     3029: }
                   3030: 
                   3031: /********************************************************************
1.1.1.3   root     3032:  * Support functions, internal                                      *
                   3033:  ********************************************************************/
1.1       root     3034: 
                   3035: 
                   3036: static void align_target(uae_u32 a)
                   3037: {
1.1.1.3   root     3038:        if (!a)
                   3039:                return;
                   3040: 
                   3041:        if (tune_nop_fillers)
                   3042:                raw_emit_nop_filler(a - (((uintptr)target) & (a - 1)));
                   3043:        else {
                   3044:                /* Fill with NOPs --- makes debugging with gdb easier */
                   3045:                while ((uintptr)target&(a-1))
1.1.1.5 ! root     3046:                        emit_byte(0x90); // Attention x86 specific code
1.1.1.3   root     3047:        }
1.1       root     3048: }
                   3049: 
1.1.1.3   root     3050: static inline int isinrom(uintptr addr)
1.1       root     3051: {
1.1.1.3   root     3052: #ifdef UAE
                   3053:        return (addr >= uae_p32(kickmem_bank.baseaddr) &&
                   3054:                        addr < uae_p32(kickmem_bank.baseaddr + 8 * 65536));
                   3055: #else
                   3056:        return ((addr >= (uintptr)ROMBaseHost) && (addr < (uintptr)ROMBaseHost + ROMSize));
                   3057: #endif
1.1       root     3058: }
                   3059: 
                   3060: static void flush_all(void)
                   3061: {
                   3062:        int i;
                   3063: 
                   3064:        log_flush();
                   3065:        for (i=0;i<VREGS;i++)
                   3066:                if (live.state[i].status==DIRTY) {
                   3067:                        if (!call_saved[live.state[i].realreg]) {
                   3068:                                tomem(i);
                   3069:                        }
                   3070:                }
1.1.1.5 ! root     3071:        for (i=0;i<VFREGS;i++)
        !          3072:                if (f_isinreg(i))
        !          3073:                        f_evict(i);
        !          3074:        raw_fp_cleanup_drop();
1.1       root     3075: }
                   3076: 
                   3077: /* Make sure all registers that will get clobbered by a call are
1.1.1.3   root     3078:    save and sound in memory */
1.1       root     3079: static void prepare_for_call_1(void)
                   3080: {
                   3081:        flush_all();  /* If there are registers that don't get clobbered,
1.1.1.5 ! root     3082:                           * we should be a bit more selective here */
1.1       root     3083: }
                   3084: 
                   3085: /* We will call a C routine in a moment. That will clobber all registers,
1.1.1.3   root     3086:    so we need to disassociate everything */
1.1       root     3087: static void prepare_for_call_2(void)
                   3088: {
                   3089:        int i;
                   3090:        for (i=0;i<N_REGS;i++)
                   3091:                if (!call_saved[i] && live.nat[i].nholds>0)
                   3092:                        free_nreg(i);
                   3093: 
                   3094:        for (i=0;i<N_FREGS;i++)
                   3095:                if (live.fat[i].nholds>0)
                   3096:                        f_free_nreg(i);
                   3097: 
                   3098:        live.flags_in_flags=TRASH;  /* Note: We assume we already rescued the
1.1.1.5 ! root     3099:                                                                   flags at the very start of the call_r
        !          3100:                                                                   functions! */
1.1       root     3101: }
                   3102: 
                   3103: /********************************************************************
1.1.1.3   root     3104:  * Memory access and related functions, CREATE time                 *
                   3105:  ********************************************************************/
1.1       root     3106: 
                   3107: void register_branch(uae_u32 not_taken, uae_u32 taken, uae_u8 cond)
                   3108: {
                   3109:        next_pc_p=not_taken;
                   3110:        taken_pc_p=taken;
                   3111:        branch_cc=cond;
                   3112: }
                   3113: 
1.1.1.3   root     3114: /* Note: get_handler may fail in 64 Bit environments, if direct_handler_to_use is
1.1.1.5 ! root     3115:  * outside 32 bit
1.1.1.3   root     3116:  */
                   3117: static uintptr get_handler(uintptr addr)
1.1       root     3118: {
1.1.1.3   root     3119:        blockinfo* bi=get_blockinfo_addr_new((void*)(uintptr)addr,0);
                   3120:        return (uintptr)bi->direct_handler_to_use;
1.1       root     3121: }
                   3122: 
                   3123: /* This version assumes that it is writing *real* memory, and *will* fail
1.1.1.5 ! root     3124:  * if that assumption is wrong! No branches, no second chances, just
        !          3125:  * straight go-for-it attitude */
1.1       root     3126: 
1.1.1.3   root     3127: static void writemem_real(int address, int source, int size, int tmp, int clobber)
1.1       root     3128: {
                   3129:        int f=tmp;
                   3130: 
                   3131: #ifdef NATMEM_OFFSET
                   3132:        if (canbang) {  /* Woohoo! go directly at the memory! */
                   3133:                if (clobber)
                   3134:                        f=source;
1.1.1.3   root     3135: 
1.1       root     3136:                switch(size) {
1.1.1.5 ! root     3137:                        case 1: mov_b_bRr(address,source,MEMBaseDiff); break;
        !          3138:                        case 2: mov_w_rr(f,source); mid_bswap_16(f); mov_w_bRr(address,f,MEMBaseDiff); break;
        !          3139:                        case 4: mov_l_rr(f,source); mid_bswap_32(f); mov_l_bRr(address,f,MEMBaseDiff); break;
1.1       root     3140:                }
                   3141:                forget_about(tmp);
                   3142:                forget_about(f);
                   3143:                return;
                   3144:        }
                   3145: #endif
                   3146: 
1.1.1.5 ! root     3147: #ifdef UAE
1.1       root     3148:        mov_l_rr(f,address);
                   3149:        shrl_l_ri(f,16);  /* The index into the baseaddr table */
1.1.1.3   root     3150:        mov_l_rm_indexed(f,uae_p32(baseaddr),f,SIZEOF_VOID_P); /* FIXME: is SIZEOF_VOID_P correct? */
1.1       root     3151: 
                   3152:        if (address==source) { /* IBrowse does this! */
                   3153:                if (size > 1) {
                   3154:                        add_l(f,address); /* f now holds the final address */
                   3155:                        switch (size) {
1.1.1.3   root     3156:                        case 2: mid_bswap_16(source); mov_w_Rr(f,source,0);
                   3157:                                mid_bswap_16(source); return;
                   3158:                        case 4: mid_bswap_32(source); mov_l_Rr(f,source,0);
                   3159:                                mid_bswap_32(source); return;
1.1       root     3160:                        }
                   3161:                }
                   3162:        }
                   3163:        switch (size) { /* f now holds the offset */
1.1.1.3   root     3164:        case 1: mov_b_mrr_indexed(address,f,1,source); break;
                   3165:        case 2: mid_bswap_16(source); mov_w_mrr_indexed(address,f,1,source);
                   3166:                mid_bswap_16(source); break;       /* base, index, source */
                   3167:        case 4: mid_bswap_32(source); mov_l_mrr_indexed(address,f,1,source);
                   3168:                mid_bswap_32(source); break;
1.1       root     3169:        }
1.1.1.5 ! root     3170: #endif
1.1       root     3171: }
                   3172: 
1.1.1.5 ! root     3173: #ifdef UAE
1.1.1.3   root     3174: static inline void writemem(int address, int source, int offset, int size, int tmp)
1.1       root     3175: {
                   3176:        int f=tmp;
                   3177: 
                   3178:        mov_l_rr(f,address);
                   3179:        shrl_l_ri(f,16);   /* The index into the mem bank table */
1.1.1.3   root     3180:        mov_l_rm_indexed(f,uae_p32(mem_banks),f,SIZEOF_VOID_P); /* FIXME: is SIZEOF_VOID_P correct? */
1.1       root     3181:        /* Now f holds a pointer to the actual membank */
                   3182:        mov_l_rR(f,f,offset);
                   3183:        /* Now f holds the address of the b/w/lput function */
                   3184:        call_r_02(f,address,source,4,size);
                   3185:        forget_about(tmp);
                   3186: }
1.1.1.5 ! root     3187: #endif
1.1       root     3188: 
                   3189: void writebyte(int address, int source, int tmp)
                   3190: {
1.1.1.5 ! root     3191: #ifdef UAE
1.1.1.3   root     3192:        if ((special_mem & S_WRITE) || distrust_byte())
                   3193:                writemem_special(address, source, 5 * SIZEOF_VOID_P, 1, tmp);
1.1       root     3194:        else
1.1.1.5 ! root     3195: #endif
1.1.1.3   root     3196:                writemem_real(address,source,1,tmp,0);
1.1       root     3197: }
                   3198: 
1.1.1.3   root     3199: static inline void writeword_general(int address, int source, int tmp,
1.1       root     3200:        int clobber)
                   3201: {
1.1.1.5 ! root     3202: #ifdef UAE
1.1.1.3   root     3203:        if ((special_mem & S_WRITE) || distrust_word())
                   3204:                writemem_special(address, source, 4 * SIZEOF_VOID_P, 2, tmp);
1.1       root     3205:        else
1.1.1.5 ! root     3206: #endif
1.1.1.3   root     3207:                writemem_real(address,source,2,tmp,clobber);
1.1       root     3208: }
                   3209: 
                   3210: void writeword_clobber(int address, int source, int tmp)
                   3211: {
                   3212:        writeword_general(address,source,tmp,1);
                   3213: }
                   3214: 
                   3215: void writeword(int address, int source, int tmp)
                   3216: {
                   3217:        writeword_general(address,source,tmp,0);
                   3218: }
                   3219: 
1.1.1.3   root     3220: static inline void writelong_general(int address, int source, int tmp,
1.1       root     3221:        int clobber)
                   3222: {
1.1.1.5 ! root     3223: #ifdef UAE
1.1.1.3   root     3224:        if ((special_mem & S_WRITE) || distrust_long())
                   3225:                writemem_special(address, source, 3 * SIZEOF_VOID_P, 4, tmp);
1.1       root     3226:        else
1.1.1.5 ! root     3227: #endif
1.1.1.3   root     3228:                writemem_real(address,source,4,tmp,clobber);
1.1       root     3229: }
                   3230: 
                   3231: void writelong_clobber(int address, int source, int tmp)
                   3232: {
                   3233:        writelong_general(address,source,tmp,1);
                   3234: }
                   3235: 
                   3236: void writelong(int address, int source, int tmp)
                   3237: {
                   3238:        writelong_general(address,source,tmp,0);
                   3239: }
                   3240: 
                   3241: 
                   3242: 
                   3243: /* This version assumes that it is reading *real* memory, and *will* fail
1.1.1.5 ! root     3244:  * if that assumption is wrong! No branches, no second chances, just
        !          3245:  * straight go-for-it attitude */
1.1       root     3246: 
1.1.1.3   root     3247: static void readmem_real(int address, int dest, int size, int tmp)
1.1       root     3248: {
                   3249:        int f=tmp;
                   3250: 
                   3251:        if (size==4 && address!=dest)
                   3252:                f=dest;
                   3253: 
                   3254: #ifdef NATMEM_OFFSET
                   3255:        if (canbang) {  /* Woohoo! go directly at the memory! */
                   3256:                switch(size) {
1.1.1.5 ! root     3257:                        case 1: mov_b_brR(dest,address,MEMBaseDiff); break;
        !          3258:                        case 2: mov_w_brR(dest,address,MEMBaseDiff); mid_bswap_16(dest); break;
        !          3259:                        case 4: mov_l_brR(dest,address,MEMBaseDiff); mid_bswap_32(dest); break;
1.1       root     3260:                }
                   3261:                forget_about(tmp);
1.1.1.3   root     3262:                (void) f;
1.1       root     3263:                return;
                   3264:        }
                   3265: #endif
                   3266: 
1.1.1.5 ! root     3267: #ifdef UAE
1.1       root     3268:        mov_l_rr(f,address);
                   3269:        shrl_l_ri(f,16);   /* The index into the baseaddr table */
1.1.1.3   root     3270:        mov_l_rm_indexed(f,uae_p32(baseaddr),f,SIZEOF_VOID_P); /* FIXME: is SIZEOF_VOID_P correct? */
1.1       root     3271:        /* f now holds the offset */
                   3272: 
                   3273:        switch(size) {
1.1.1.3   root     3274:        case 1: mov_b_rrm_indexed(dest,address,f,1); break;
                   3275:        case 2: mov_w_rrm_indexed(dest,address,f,1); mid_bswap_16(dest); break;
                   3276:        case 4: mov_l_rrm_indexed(dest,address,f,1); mid_bswap_32(dest); break;
1.1       root     3277:        }
                   3278:        forget_about(tmp);
1.1.1.5 ! root     3279: #endif
1.1       root     3280: }
                   3281: 
                   3282: 
                   3283: 
1.1.1.5 ! root     3284: #ifdef UAE
1.1.1.3   root     3285: static inline void readmem(int address, int dest, int offset, int size, int tmp)
1.1       root     3286: {
                   3287:        int f=tmp;
                   3288: 
                   3289:        mov_l_rr(f,address);
                   3290:        shrl_l_ri(f,16);   /* The index into the mem bank table */
1.1.1.3   root     3291:        mov_l_rm_indexed(f,uae_p32(mem_banks),f,SIZEOF_VOID_P); /* FIXME: is SIZEOF_VOID_P correct? */
1.1       root     3292:        /* Now f holds a pointer to the actual membank */
                   3293:        mov_l_rR(f,f,offset);
                   3294:        /* Now f holds the address of the b/w/lget function */
                   3295:        call_r_11(dest,f,address,size,4);
                   3296:        forget_about(tmp);
                   3297: }
1.1.1.5 ! root     3298: #endif
1.1       root     3299: 
                   3300: void readbyte(int address, int dest, int tmp)
                   3301: {
1.1.1.5 ! root     3302: #ifdef UAE
1.1.1.3   root     3303:        if ((special_mem & S_READ) || distrust_byte())
                   3304:                readmem_special(address, dest, 2 * SIZEOF_VOID_P, 1, tmp);
1.1       root     3305:        else
1.1.1.5 ! root     3306: #endif
1.1.1.3   root     3307:                readmem_real(address,dest,1,tmp);
1.1       root     3308: }
                   3309: 
                   3310: void readword(int address, int dest, int tmp)
                   3311: {
1.1.1.5 ! root     3312: #ifdef UAE
1.1.1.3   root     3313:        if ((special_mem & S_READ) || distrust_word())
                   3314:                readmem_special(address, dest, 1 * SIZEOF_VOID_P, 2, tmp);
1.1       root     3315:        else
1.1.1.5 ! root     3316: #endif
1.1.1.3   root     3317:                readmem_real(address,dest,2,tmp);
1.1       root     3318: }
                   3319: 
                   3320: void readlong(int address, int dest, int tmp)
                   3321: {
1.1.1.5 ! root     3322: #ifdef UAE
1.1.1.3   root     3323:        if ((special_mem & S_READ) || distrust_long())
                   3324:                readmem_special(address, dest, 0 * SIZEOF_VOID_P, 4, tmp);
1.1       root     3325:        else
1.1.1.5 ! root     3326: #endif
1.1.1.3   root     3327:                readmem_real(address,dest,4,tmp);
1.1       root     3328: }
                   3329: 
1.1.1.3   root     3330: void get_n_addr(int address, int dest, int tmp)
1.1       root     3331: {
1.1.1.5 ! root     3332: #ifdef UAE
1.1.1.3   root     3333:        if (special_mem || distrust_addr()) {
                   3334:                /* This one might appear a bit odd... */
                   3335:                readmem(address, dest, 6 * SIZEOF_VOID_P, 4, tmp);
                   3336:                return;
                   3337:        }
1.1.1.5 ! root     3338: #endif
1.1       root     3339: 
1.1.1.3   root     3340:        // a is the register containing the virtual address
                   3341:        // after the offset had been fetched
                   3342:        int a=tmp;
                   3343: 
                   3344:        // f is the register that will contain the offset
1.1       root     3345:        int f=tmp;
1.1.1.3   root     3346: 
                   3347:        // a == f == tmp if (address == dest)
                   3348:        if (address!=dest) {
                   3349:                a=address;
1.1       root     3350:                f=dest;
1.1.1.3   root     3351:        }
1.1       root     3352: 
                   3353: #ifdef NATMEM_OFFSET
                   3354:        if (canbang) {
1.1.1.3   root     3355: #if FIXED_ADDRESSING
                   3356:                lea_l_brr(dest,address,MEMBaseDiff);
                   3357: #else
1.1.1.4   root     3358: # error "Only fixed addressing mode supported"
1.1.1.3   root     3359: #endif
1.1       root     3360:                forget_about(tmp);
1.1.1.3   root     3361:                (void) f;
                   3362:                (void) a;
1.1       root     3363:                return;
                   3364:        }
                   3365: #endif
1.1.1.5 ! root     3366: 
        !          3367: #ifdef UAE
1.1       root     3368:        mov_l_rr(f,address);
                   3369:        mov_l_rr(dest,address); // gb-- nop if dest==address
                   3370:        shrl_l_ri(f,16);
1.1.1.3   root     3371:        mov_l_rm_indexed(f,uae_p32(baseaddr),f,SIZEOF_VOID_P); /* FIXME: is SIZEOF_VOID_P correct? */
1.1       root     3372:        add_l(dest,f);
                   3373:        forget_about(tmp);
1.1.1.5 ! root     3374: #endif
1.1       root     3375: }
                   3376: 
                   3377: void get_n_addr_jmp(int address, int dest, int tmp)
                   3378: {
1.1.1.5 ! root     3379: #ifdef WINUAE_ARANYM
1.1.1.3   root     3380:        /* For this, we need to get the same address as the rest of UAE
                   3381:         would --- otherwise we end up translating everything twice */
1.1       root     3382:        get_n_addr(address,dest,tmp);
                   3383: #else
                   3384:        int f=tmp;
                   3385:        if (address!=dest)
                   3386:                f=dest;
                   3387:        mov_l_rr(f,address);
                   3388:        shrl_l_ri(f,16);   /* The index into the baseaddr bank table */
1.1.1.3   root     3389:        mov_l_rm_indexed(dest,uae_p32(baseaddr),f,SIZEOF_VOID_P); /* FIXME: is SIZEOF_VOID_P correct? */
1.1       root     3390:        add_l(dest,address);
                   3391:        and_l_ri (dest, ~1);
                   3392:        forget_about(tmp);
                   3393: #endif
                   3394: }
                   3395: 
1.1.1.3   root     3396: 
                   3397: /* base is a register, but dp is an actual value. 
                   3398:    target is a register, as is tmp */
1.1       root     3399: void calc_disp_ea_020(int base, uae_u32 dp, int target, int tmp)
                   3400: {
                   3401:        int reg = (dp >> 12) & 15;
                   3402:        int regd_shift=(dp >> 9) & 3;
                   3403: 
                   3404:        if (dp & 0x100) {
                   3405:                int ignorebase=(dp&0x80);
                   3406:                int ignorereg=(dp&0x40);
                   3407:                int addbase=0;
                   3408:                int outer=0;
                   3409: 
                   3410:                if ((dp & 0x30) == 0x20) addbase = (uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
                   3411:                if ((dp & 0x30) == 0x30) addbase = comp_get_ilong((m68k_pc_offset+=4)-4);
                   3412: 
                   3413:                if ((dp & 0x3) == 0x2) outer = (uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
                   3414:                if ((dp & 0x3) == 0x3) outer = comp_get_ilong((m68k_pc_offset+=4)-4);
                   3415: 
                   3416:                if ((dp & 0x4) == 0) {  /* add regd *before* the get_long */
                   3417:                        if (!ignorereg) {
                   3418:                                if ((dp & 0x800) == 0)
                   3419:                                        sign_extend_16_rr(target,reg);
                   3420:                                else
                   3421:                                        mov_l_rr(target,reg);
                   3422:                                shll_l_ri(target,regd_shift);
                   3423:                        }
                   3424:                        else
                   3425:                                mov_l_ri(target,0);
                   3426: 
                   3427:                        /* target is now regd */
                   3428:                        if (!ignorebase)
                   3429:                                add_l(target,base);
                   3430:                        add_l_ri(target,addbase);
                   3431:                        if (dp&0x03) readlong(target,target,tmp);
                   3432:                } else { /* do the getlong first, then add regd */
                   3433:                        if (!ignorebase) {
                   3434:                                mov_l_rr(target,base);
                   3435:                                add_l_ri(target,addbase);
                   3436:                        }
                   3437:                        else
                   3438:                                mov_l_ri(target,addbase);
                   3439:                        if (dp&0x03) readlong(target,target,tmp);
                   3440: 
                   3441:                        if (!ignorereg) {
                   3442:                                if ((dp & 0x800) == 0)
                   3443:                                        sign_extend_16_rr(tmp,reg);
                   3444:                                else
                   3445:                                        mov_l_rr(tmp,reg);
                   3446:                                shll_l_ri(tmp,regd_shift);
                   3447:                                /* tmp is now regd */
                   3448:                                add_l(target,tmp);
                   3449:                        }
                   3450:                }
                   3451:                add_l_ri(target,outer);
                   3452:        }
                   3453:        else { /* 68000 version */
                   3454:                if ((dp & 0x800) == 0) { /* Sign extend */
                   3455:                        sign_extend_16_rr(target,reg);
1.1.1.3   root     3456:                        lea_l_brr_indexed(target,base,target,1<<regd_shift,(uae_s32)((uae_s8)dp));
1.1       root     3457:                }
                   3458:                else {
1.1.1.3   root     3459:                        lea_l_brr_indexed(target,base,reg,1<<regd_shift,(uae_s32)((uae_s8)dp));
1.1       root     3460:                }
                   3461:        }
                   3462:        forget_about(tmp);
                   3463: }
                   3464: 
1.1.1.3   root     3465: 
                   3466: 
                   3467: 
1.1       root     3468: 
                   3469: void set_cache_state(int enabled)
                   3470: {
1.1.1.5 ! root     3471:        if (enabled!=cache_enabled)
        !          3472:                flush_icache_hard(77);
        !          3473:        cache_enabled=enabled;
1.1       root     3474: }
                   3475: 
                   3476: int get_cache_state(void)
                   3477: {
1.1.1.5 ! root     3478:        return cache_enabled;
1.1       root     3479: }
                   3480: 
                   3481: uae_u32 get_jitted_size(void)
                   3482: {
                   3483:        if (compiled_code)
                   3484:                return current_compile_p-compiled_code;
                   3485:        return 0;
                   3486: }
                   3487: 
1.1.1.3   root     3488: static uint8 *do_alloc_code(uint32 size, int depth)
                   3489: {
                   3490:        UNUSED(depth);
                   3491:        uint8 *code = (uint8 *)vm_acquire(size, VM_MAP_DEFAULT | VM_MAP_32BIT);
                   3492:        return code == VM_MAP_FAILED ? NULL : code;
                   3493: }
                   3494: 
                   3495: static inline uint8 *alloc_code(uint32 size)
                   3496: {
                   3497:        uint8 *ptr = do_alloc_code(size, 0);
                   3498:        /* allocated code must fit in 32-bit boundaries */
                   3499:        assert((uintptr)ptr <= 0xffffffff);
                   3500:        return ptr;
                   3501: }
                   3502: 
1.1       root     3503: void alloc_cache(void)
                   3504: {
                   3505:        if (compiled_code) {
1.1.1.5 ! root     3506:                flush_icache_hard(6);
1.1.1.3   root     3507:                vm_release(compiled_code, cache_size * 1024);
                   3508:                compiled_code = 0;
1.1       root     3509:        }
1.1.1.3   root     3510: 
                   3511: #ifdef UAE
                   3512:        cache_size = currprefs.cachesize;
                   3513: #endif
                   3514:        if (cache_size == 0)
1.1       root     3515:                return;
                   3516: 
1.1.1.3   root     3517:        while (!compiled_code && cache_size) {
                   3518:                if ((compiled_code = alloc_code(cache_size * 1024)) == NULL) {
                   3519:                        compiled_code = 0;
                   3520:                        cache_size /= 2;
                   3521:                }
1.1       root     3522:        }
1.1.1.3   root     3523:        vm_protect(compiled_code, cache_size * 1024, VM_PAGE_READ | VM_PAGE_WRITE | VM_PAGE_EXECUTE);
                   3524:        
1.1       root     3525:        if (compiled_code) {
1.1.1.5 ! root     3526:                jit_log("<JIT compiler> : actual translation cache size : %d KB at %p-%p", cache_size, compiled_code, compiled_code + cache_size*1024);
1.1.1.3   root     3527: #ifdef USE_DATA_BUFFER
                   3528:                max_compile_start = compiled_code + cache_size*1024 - BYTES_PER_INST - DATA_BUFFER_SIZE;
                   3529: #else
                   3530:                max_compile_start = compiled_code + cache_size*1024 - BYTES_PER_INST;
                   3531: #endif
1.1.1.5 ! root     3532:                current_compile_p = compiled_code;
1.1.1.3   root     3533:                current_cache_size = 0;
                   3534: #if defined(USE_DATA_BUFFER)
                   3535:                reset_data_buffer();
                   3536: #endif
1.1       root     3537:        }
                   3538: }
                   3539: 
                   3540: static void calc_checksum(blockinfo* bi, uae_u32* c1, uae_u32* c2)
                   3541: {
1.1.1.5 ! root     3542:        uae_u32 k1 = 0;
        !          3543:        uae_u32 k2 = 0;
1.1       root     3544: 
1.1.1.3   root     3545: #if USE_CHECKSUM_INFO
                   3546:        checksum_info *csi = bi->csi;
                   3547:        Dif(!csi) abort();
                   3548:        while (csi) {
                   3549:                uae_s32 len = csi->length;
                   3550:                uintptr tmp = (uintptr)csi->start_p;
                   3551: #else
1.1.1.5 ! root     3552:                uae_s32 len = bi->len;
1.1.1.3   root     3553:                uintptr tmp = (uintptr)bi->min_pcp;
                   3554: #endif
                   3555:                uae_u32* pos;
1.1       root     3556: 
1.1.1.5 ! root     3557:                len += (tmp & 3);
1.1.1.3   root     3558:                tmp &= ~((uintptr)3);
1.1.1.5 ! root     3559:                pos = (uae_u32 *)tmp;
1.1.1.3   root     3560: 
                   3561:                if (len >= 0 && len <= MAX_CHECKSUM_LEN) {
1.1.1.5 ! root     3562:                        while (len > 0) {
        !          3563:                                k1 += *pos;
        !          3564:                                k2 ^= *pos;
1.1.1.3   root     3565:                                pos++;
1.1.1.5 ! root     3566:                                len -= 4;
1.1.1.3   root     3567:                        }
1.1       root     3568:                }
1.1.1.3   root     3569: 
                   3570: #if USE_CHECKSUM_INFO
                   3571:                csi = csi->next;
1.1       root     3572:        }
1.1.1.3   root     3573: #endif
                   3574: 
                   3575:        *c1 = k1;
                   3576:        *c2 = k2;
1.1       root     3577: }
                   3578: 
1.1.1.3   root     3579: #if 0
                   3580: static void show_checksum(CSI_TYPE* csi)
1.1       root     3581: {
                   3582:        uae_u32 k1=0;
                   3583:        uae_u32 k2=0;
1.1.1.3   root     3584:        uae_s32 len=CSI_LENGTH(csi);
                   3585:        uae_u32 tmp=(uintptr)CSI_START_P(csi);
1.1       root     3586:        uae_u32* pos;
                   3587: 
                   3588:        len+=(tmp&3);
                   3589:        tmp&=(~3);
                   3590:        pos=(uae_u32*)tmp;
                   3591: 
                   3592:        if (len<0 || len>MAX_CHECKSUM_LEN) {
                   3593:                return;
                   3594:        }
                   3595:        else {
                   3596:                while (len>0) {
1.1.1.3   root     3597:                        jit_log("%08x ",*pos);
1.1       root     3598:                        pos++;
                   3599:                        len-=4;
                   3600:                }
1.1.1.3   root     3601:                jit_log(" bla");
1.1       root     3602:        }
                   3603: }
1.1.1.3   root     3604: #endif
1.1       root     3605: 
                   3606: 
                   3607: int check_for_cache_miss(void)
                   3608: {
                   3609:        blockinfo* bi=get_blockinfo_addr(regs.pc_p);
                   3610: 
                   3611:        if (bi) {
                   3612:                int cl=cacheline(regs.pc_p);
                   3613:                if (bi!=cache_tags[cl+1].bi) {
                   3614:                        raise_in_cl_list(bi);
                   3615:                        return 1;
                   3616:                }
                   3617:        }
                   3618:        return 0;
                   3619: }
                   3620: 
                   3621: 
                   3622: static void recompile_block(void)
                   3623: {
                   3624:        /* An existing block's countdown code has expired. We need to make
1.1.1.5 ! root     3625:           sure that execute_normal doesn't refuse to recompile due to a
        !          3626:           perceived cache miss... */
1.1       root     3627:        blockinfo*  bi=get_blockinfo_addr(regs.pc_p);
                   3628: 
                   3629:        Dif (!bi)
1.1.1.3   root     3630:                jit_abort("recompile_block");
1.1       root     3631:        raise_in_cl_list(bi);
                   3632:        execute_normal();
                   3633:        return;
                   3634: }
                   3635: static void cache_miss(void)
                   3636: {
                   3637:        blockinfo*  bi=get_blockinfo_addr(regs.pc_p);
1.1.1.5 ! root     3638: #if COMP_DEBUG
1.1       root     3639:        uae_u32     cl=cacheline(regs.pc_p);
                   3640:        blockinfo*  bi2=get_blockinfo(cl);
1.1.1.5 ! root     3641: #endif
1.1       root     3642: 
                   3643:        if (!bi) {
                   3644:                execute_normal(); /* Compile this block now */
                   3645:                return;
                   3646:        }
                   3647:        Dif (!bi2 || bi==bi2) {
1.1.1.3   root     3648:                jit_abort("Unexplained cache miss %p %p",bi,bi2);
1.1       root     3649:        }
                   3650:        raise_in_cl_list(bi);
                   3651:        return;
                   3652: }
                   3653: 
1.1.1.3   root     3654: static int called_check_checksum(blockinfo* bi);
1.1       root     3655: 
1.1.1.3   root     3656: static inline int block_check_checksum(blockinfo* bi)
                   3657: {
1.1       root     3658:        uae_u32     c1,c2;
1.1.1.3   root     3659:        bool        isgood;
1.1.1.5 ! root     3660: 
1.1.1.3   root     3661:        if (bi->status!=BI_NEED_CHECK)
                   3662:                return 1;  /* This block is in a checked state */
1.1       root     3663: 
                   3664:        if (bi->c1 || bi->c2)
                   3665:                calc_checksum(bi,&c1,&c2);
                   3666:        else {
                   3667:                c1=c2=1;  /* Make sure it doesn't match */
                   3668:        }
1.1.1.3   root     3669: 
                   3670:        isgood=(c1==bi->c1 && c2==bi->c2);
                   3671: 
                   3672:        if (isgood) {
1.1       root     3673:                /* This block is still OK. So we reactivate. Of course, that
1.1.1.5 ! root     3674:                   means we have to move it into the needs-to-be-flushed list */
1.1       root     3675:                bi->handler_to_use=bi->handler;
                   3676:                set_dhtu(bi,bi->direct_handler);
1.1.1.3   root     3677:                bi->status=BI_CHECKING;
                   3678:                isgood=called_check_checksum(bi) != 0;
                   3679:        }
                   3680:        if (isgood) {
                   3681:                jit_log2("reactivate %p/%p (%x %x/%x %x)",bi,bi->pc_p, c1,c2,bi->c1,bi->c2);
1.1       root     3682:                remove_from_list(bi);
                   3683:                add_to_active(bi);
                   3684:                raise_in_cl_list(bi);
1.1.1.3   root     3685:                bi->status=BI_ACTIVE;
1.1       root     3686:        }
                   3687:        else {
                   3688:                /* This block actually changed. We need to invalidate it,
1.1.1.5 ! root     3689:                   and set it up to be recompiled */
1.1.1.3   root     3690:                jit_log2("discard %p/%p (%x %x/%x %x)",bi,bi->pc_p, c1,c2,bi->c1,bi->c2);
1.1       root     3691:                invalidate_block(bi);
                   3692:                raise_in_cl_list(bi);
1.1.1.3   root     3693:        }
                   3694:        return isgood;
                   3695: }
                   3696: 
                   3697: static int called_check_checksum(blockinfo* bi)
                   3698: {
                   3699:        int isgood=1;
                   3700:        int i;
                   3701: 
                   3702:        for (i=0;i<2 && isgood;i++) {
                   3703:                if (bi->dep[i].jmp_off) {
1.1.1.5 ! root     3704:                        isgood=block_check_checksum(bi->dep[i].target);
1.1.1.3   root     3705:                }
                   3706:        }
                   3707:        return isgood;
                   3708: }
                   3709: 
                   3710: static void check_checksum(void)
                   3711: {
                   3712:        blockinfo*  bi=get_blockinfo_addr(regs.pc_p);
                   3713:        uae_u32     cl=cacheline(regs.pc_p);
                   3714:        blockinfo*  bi2=get_blockinfo(cl);
                   3715: 
1.1.1.5 ! root     3716:        /* These are not the droids you are looking for... */
1.1.1.3   root     3717:        if (!bi) {
                   3718:                /* Whoever is the primary target is in a dormant state, but
1.1.1.5 ! root     3719:                   calling it was accidental, and we should just compile this
        !          3720:                   new block */
1.1       root     3721:                execute_normal();
1.1.1.3   root     3722:                return;
                   3723:        }
                   3724:        if (bi!=bi2) {
                   3725:                /* The block was hit accidentally, but it does exist. Cache miss */
                   3726:                cache_miss();
                   3727:                return;
1.1       root     3728:        }
1.1.1.3   root     3729: 
                   3730:        if (!block_check_checksum(bi))
                   3731:                execute_normal();
1.1       root     3732: }
                   3733: 
1.1.1.3   root     3734: static inline void match_states(blockinfo* bi)
                   3735: {
                   3736:        int i;
                   3737:        smallstate* s=&(bi->env);
                   3738: 
                   3739:        if (bi->status==BI_NEED_CHECK) {
                   3740:                block_check_checksum(bi);
                   3741:        }
                   3742:        if (bi->status==BI_ACTIVE ||
                   3743:                bi->status==BI_FINALIZING) {  /* Deal with the *promises* the
                   3744:                                                 block makes (about not using
                   3745:                                                 certain vregs) */
                   3746:                for (i=0;i<16;i++) {
                   3747:                        if (s->virt[i]==L_UNNEEDED) {
                   3748:                                jit_log2("unneeded reg %d at %p",i,target);
                   3749:                                COMPCALL(forget_about)(i); // FIXME
                   3750:                        }
                   3751:                }
                   3752:        }
                   3753:        flush(1);
                   3754: 
                   3755:        /* And now deal with the *demands* the block makes */
                   3756:        for (i=0;i<N_REGS;i++) {
                   3757:                int v=s->nat[i];
                   3758:                if (v>=0) {
                   3759:                        // printf("Loading reg %d into %d at %p\n",v,i,target);
                   3760:                        readreg_specific(v,4,i);
                   3761:                        // do_load_reg(i,v);
                   3762:                        // setlock(i);
                   3763:                }
                   3764:        }
                   3765:        for (i=0;i<N_REGS;i++) {
                   3766:                int v=s->nat[i];
                   3767:                if (v>=0) {
                   3768:                        unlock2(i);
                   3769:                }
                   3770:        }
                   3771: }
1.1       root     3772: 
1.1.1.3   root     3773: static inline void create_popalls(void)
1.1       root     3774: {
                   3775:        int i,r;
                   3776: 
1.1.1.3   root     3777:        if (popallspace == NULL) {
                   3778:                if ((popallspace = alloc_code(POPALLSPACE_SIZE)) == NULL) {
                   3779:                        jit_log("WARNING: Could not allocate popallspace!");
1.1.1.5 ! root     3780: #ifdef UAE
        !          3781:                        if (currprefs.cachesize > 0)
1.1.1.3   root     3782: #endif
1.1.1.5 ! root     3783:                        {
1.1.1.3   root     3784:                                jit_abort("Could not allocate popallspace!");
                   3785:                        }
1.1.1.5 ! root     3786: #ifdef UAE
1.1.1.3   root     3787:                        /* This is not fatal if JIT is not used. If JIT is
                   3788:                         * turned on, it will crash, but it would have crashed
                   3789:                         * anyway. */
                   3790:                        return;
1.1.1.5 ! root     3791: #endif
1.1.1.3   root     3792:                }
                   3793:        }
                   3794:        vm_protect(popallspace, POPALLSPACE_SIZE, VM_PAGE_READ | VM_PAGE_WRITE);
                   3795: 
                   3796:        int stack_space = STACK_OFFSET;
1.1       root     3797:        for (i=0;i<N_REGS;i++) {
                   3798:                if (need_to_preserve[i])
1.1.1.3   root     3799:                        stack_space += sizeof(void *);
1.1       root     3800:        }
1.1.1.3   root     3801:        stack_space %= STACK_ALIGN;
                   3802:        if (stack_space)
                   3803:                stack_space = STACK_ALIGN - stack_space;
                   3804: 
                   3805:        current_compile_p=popallspace;
                   3806:        set_target(current_compile_p);
                   3807: 
                   3808: #if defined(USE_DATA_BUFFER)
                   3809:        reset_data_buffer();
                   3810: #endif
1.1       root     3811: 
1.1.1.3   root     3812:        /* We need to guarantee 16-byte stack alignment on x86 at any point
                   3813:           within the JIT generated code. We have multiple exit points
                   3814:           possible but a single entry. A "jmp" is used so that we don't
                   3815:           have to generate stack alignment in generated code that has to
                   3816:           call external functions (e.g. a generic instruction handler).
                   3817: 
                   3818:           In summary, JIT generated code is not leaf so we have to deal
                   3819:           with it here to maintain correct stack alignment. */
                   3820:        align_target(align_jumps);
                   3821:        current_compile_p=get_target();
                   3822:        pushall_call_handler=get_target();
                   3823:        raw_push_regs_to_preserve();
                   3824:        raw_dec_sp(stack_space);
                   3825:        r=REG_PC_TMP;
                   3826:        compemu_raw_mov_l_rm(r, uae_p32(&regs.pc_p));
                   3827:        compemu_raw_and_l_ri(r,TAGMASK);
1.1.1.5 ! root     3828:        compemu_raw_jmp_m_indexed(uae_p32(cache_tags), r, sizeof(void *));
1.1.1.3   root     3829: 
                   3830:        /* now the exit points */
                   3831:        align_target(align_jumps);
                   3832:        popall_do_nothing=get_target();
                   3833:        raw_inc_sp(stack_space);
                   3834:        raw_pop_preserved_regs();
                   3835:        compemu_raw_jmp(uae_p32(do_nothing));
                   3836: 
                   3837:        align_target(align_jumps);
1.1       root     3838:        popall_execute_normal=get_target();
1.1.1.3   root     3839:        raw_inc_sp(stack_space);
                   3840:        raw_pop_preserved_regs();
                   3841:        compemu_raw_jmp(uae_p32(execute_normal));
1.1       root     3842: 
1.1.1.3   root     3843:        align_target(align_jumps);
1.1       root     3844:        popall_cache_miss=get_target();
1.1.1.3   root     3845:        raw_inc_sp(stack_space);
                   3846:        raw_pop_preserved_regs();
                   3847:        compemu_raw_jmp(uae_p32(cache_miss));
1.1       root     3848: 
1.1.1.3   root     3849:        align_target(align_jumps);
1.1       root     3850:        popall_recompile_block=get_target();
1.1.1.3   root     3851:        raw_inc_sp(stack_space);
                   3852:        raw_pop_preserved_regs();
                   3853:        compemu_raw_jmp(uae_p32(recompile_block));
1.1       root     3854: 
1.1.1.3   root     3855:        align_target(align_jumps);
1.1       root     3856:        popall_exec_nostats=get_target();
1.1.1.3   root     3857:        raw_inc_sp(stack_space);
                   3858:        raw_pop_preserved_regs();
                   3859:        compemu_raw_jmp(uae_p32(exec_nostats));
1.1       root     3860: 
1.1.1.3   root     3861:        align_target(align_jumps);
1.1       root     3862:        popall_check_checksum=get_target();
1.1.1.3   root     3863:        raw_inc_sp(stack_space);
                   3864:        raw_pop_preserved_regs();
                   3865:        compemu_raw_jmp(uae_p32(check_checksum));
1.1       root     3866: 
1.1.1.3   root     3867: #if defined(USE_DATA_BUFFER)
                   3868:        reset_data_buffer();
1.1       root     3869: #endif
                   3870: 
1.1.1.3   root     3871: #ifdef UAE
                   3872: #ifdef USE_UDIS86
                   3873:        UDISFN(pushall_call_handler, get_target());
1.1       root     3874: #endif
1.1.1.3   root     3875: #endif
                   3876:        // no need to further write into popallspace
                   3877:        vm_protect(popallspace, POPALLSPACE_SIZE, VM_PAGE_READ | VM_PAGE_EXECUTE);
                   3878:        // No need to flush. Initialized and not modified
                   3879:        // flush_cpu_icache((void *)popallspace, (void *)target);
1.1       root     3880: }
                   3881: 
1.1.1.3   root     3882: static inline void reset_lists(void)
1.1       root     3883: {
                   3884:        int i;
                   3885: 
                   3886:        for (i=0;i<MAX_HOLD_BI;i++)
                   3887:                hold_bi[i]=NULL;
                   3888:        active=NULL;
                   3889:        dormant=NULL;
                   3890: }
                   3891: 
                   3892: static void prepare_block(blockinfo* bi)
                   3893: {
                   3894:        int i;
                   3895: 
                   3896:        set_target(current_compile_p);
1.1.1.3   root     3897:        align_target(align_jumps);
1.1       root     3898:        bi->direct_pen=(cpuop_func*)get_target();
1.1.1.3   root     3899:        compemu_raw_mov_l_rm(0,(uintptr)&(bi->pc_p));
                   3900:        compemu_raw_mov_l_mr((uintptr)&regs.pc_p,0);
                   3901:        compemu_raw_jmp((uintptr)popall_execute_normal);
1.1       root     3902: 
1.1.1.3   root     3903:        align_target(align_jumps);
1.1       root     3904:        bi->direct_pcc=(cpuop_func*)get_target();
1.1.1.3   root     3905:        compemu_raw_mov_l_rm(0,(uintptr)&(bi->pc_p));
                   3906:        compemu_raw_mov_l_mr((uintptr)&regs.pc_p,0);
                   3907:        compemu_raw_jmp((uintptr)popall_check_checksum);
                   3908:        flush_cpu_icache((void *)current_compile_p, (void *)target);
1.1       root     3909:        current_compile_p=get_target();
                   3910: 
                   3911:        bi->deplist=NULL;
                   3912:        for (i=0;i<2;i++) {
                   3913:                bi->dep[i].prev_p=NULL;
                   3914:                bi->dep[i].next=NULL;
                   3915:        }
                   3916:        bi->env=default_ss;
1.1.1.3   root     3917:        bi->status=BI_INVALID;
1.1       root     3918:        bi->havestate=0;
                   3919:        //bi->env=empty_ss;
                   3920: }
                   3921: 
1.1.1.5 ! root     3922: #ifdef UAE
1.1       root     3923: void compemu_reset(void)
                   3924: {
                   3925:        set_cache_state(0);
                   3926: }
1.1.1.5 ! root     3927: #endif
1.1       root     3928: 
1.1.1.3   root     3929: #ifdef UAE
                   3930: #else
                   3931: // OPCODE is in big endian format, use cft_map() beforehand, if needed.
                   3932: #endif
                   3933: static inline void reset_compop(int opcode)
                   3934: {
                   3935:        compfunctbl[opcode] = NULL;
                   3936:        nfcompfunctbl[opcode] = NULL;
                   3937: }
                   3938: 
                   3939: static int read_opcode(const char *p)
                   3940: {
                   3941:        int opcode = 0;
                   3942:        for (int i = 0; i < 4; i++) {
                   3943:                int op = p[i];
                   3944:                switch (op) {
                   3945:                case '0': case '1': case '2': case '3': case '4':
                   3946:                case '5': case '6': case '7': case '8': case '9':
                   3947:                        opcode = (opcode << 4) | (op - '0');
                   3948:                        break;
                   3949:                case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
                   3950:                        opcode = (opcode << 4) | ((op - 'a') + 10);
                   3951:                        break;
                   3952:                case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
                   3953:                        opcode = (opcode << 4) | ((op - 'A') + 10);
                   3954:                        break;
                   3955:                default:
                   3956:                        return -1;
                   3957:                }
                   3958:        }
                   3959:        return opcode;
                   3960: }
                   3961: 
                   3962: static bool merge_blacklist()
                   3963: {
                   3964: #ifdef UAE
                   3965:        const char *blacklist = "";
                   3966: #else
                   3967:        const char *blacklist = bx_options.jit.jitblacklist;
                   3968: #endif
                   3969:        if (blacklist[0] != '\0') {
                   3970:                const char *p = blacklist;
                   3971:                for (;;) {
                   3972:                        if (*p == 0)
                   3973:                                return true;
                   3974: 
                   3975:                        int opcode1 = read_opcode(p);
                   3976:                        if (opcode1 < 0)
                   3977:                                return false;
                   3978:                        p += 4;
                   3979: 
                   3980:                        int opcode2 = opcode1;
                   3981:                        if (*p == '-') {
                   3982:                                p++;
                   3983:                                opcode2 = read_opcode(p);
                   3984:                                if (opcode2 < 0)
                   3985:                                        return false;
                   3986:                                p += 4;
                   3987:                        }
                   3988: 
                   3989:                        if (*p == 0 || *p == ',') {
1.1.1.5 ! root     3990:                                jit_log("<JIT compiler> : blacklist opcodes : %04x-%04x", opcode1, opcode2);
1.1.1.3   root     3991:                                for (int opcode = opcode1; opcode <= opcode2; opcode++)
                   3992:                                        reset_compop(cft_map(opcode));
                   3993: 
                   3994:                                if (*(p++) == ',')
                   3995:                                        continue;
                   3996: 
                   3997:                                return true;
                   3998:                        }
                   3999: 
                   4000:                        return false;
                   4001:                }
                   4002:        }
                   4003:        return true;
                   4004: }
                   4005: 
1.1       root     4006: void build_comp(void)
                   4007: {
                   4008:        int i;
                   4009:        unsigned long opcode;
                   4010:        const struct comptbl* tbl=op_smalltbl_0_comp_ff;
                   4011:        const struct comptbl* nftbl=op_smalltbl_0_comp_nf;
                   4012:        int count;
1.1.1.5 ! root     4013: #ifdef WINUAE_ARANYM
        !          4014:        unsigned int cpu_level = 4;             // 68040
        !          4015:        const struct cputbl *nfctbl = op_smalltbl_0_nf;
        !          4016: #else
1.1       root     4017: #ifdef NOFLAGS_SUPPORT
                   4018:        struct comptbl *nfctbl = (currprefs.cpu_level >= 5 ? op_smalltbl_0_nf
                   4019:                : currprefs.cpu_level == 4 ? op_smalltbl_1_nf
                   4020:                : (currprefs.cpu_level == 2 || currprefs.cpu_level == 3) ? op_smalltbl_2_nf
                   4021:                : currprefs.cpu_level == 1 ? op_smalltbl_3_nf
                   4022:                : ! currprefs.cpu_compatible ? op_smalltbl_4_nf
                   4023:                : op_smalltbl_5_nf);
                   4024: #endif
1.1.1.5 ! root     4025: #endif
        !          4026:        // Initialize target CPU (check for features, e.g. CMOV, rat stalls)
1.1       root     4027:        raw_init_cpu();
1.1.1.3   root     4028: 
1.1       root     4029: #ifdef NATMEM_OFFSET
1.1.1.3   root     4030: #ifdef UAE
                   4031: #ifdef JIT_EXCEPTION_HANDLER
                   4032:        install_exception_handler();
                   4033: #endif
1.1       root     4034: #endif
                   4035: #endif
1.1.1.3   root     4036: 
1.1.1.5 ! root     4037:        jit_log("<JIT compiler> : building compiler function tables");
1.1.1.3   root     4038:        
1.1       root     4039:        for (opcode = 0; opcode < 65536; opcode++) {
1.1.1.3   root     4040:                reset_compop(opcode);
1.1       root     4041: #ifdef NOFLAGS_SUPPORT
                   4042:                nfcpufunctbl[opcode] = op_illg;
                   4043: #endif
1.1.1.5 ! root     4044:                prop[opcode].use_flags = FLAG_ALL;
        !          4045:                prop[opcode].set_flags = FLAG_ALL;
        !          4046: #ifdef UAE
1.1       root     4047:                prop[opcode].is_jump=1;
1.1.1.5 ! root     4048: #else
        !          4049:                prop[opcode].cflow = fl_trap; // ILLEGAL instructions do trap
        !          4050: #endif
1.1       root     4051:        }
                   4052: 
                   4053:        for (i = 0; tbl[i].opcode < 65536; i++) {
1.1.1.5 ! root     4054: #ifdef UAE
1.1.1.3   root     4055:                int isjmp = (tbl[i].specific & COMP_OPCODE_ISJUMP);
                   4056:                int isaddx = (tbl[i].specific & COMP_OPCODE_ISADDX);
                   4057:                int iscjmp = (tbl[i].specific & COMP_OPCODE_ISCJUMP);
                   4058: 
                   4059:                prop[cft_map(tbl[i].opcode)].is_jump = isjmp;
                   4060:                prop[cft_map(tbl[i].opcode)].is_const_jump = iscjmp;
                   4061:                prop[cft_map(tbl[i].opcode)].is_addx = isaddx;
1.1.1.5 ! root     4062: #else
        !          4063:                int cflow = table68k[tbl[i].opcode].cflow;
        !          4064:                if (follow_const_jumps && (tbl[i].specific & COMP_OPCODE_ISCJUMP))
        !          4065:                        cflow = fl_const_jump;
        !          4066:                else
        !          4067:                        cflow &= ~fl_const_jump;
        !          4068:                prop[cft_map(tbl[i].opcode)].cflow = cflow;
        !          4069: #endif
1.1.1.3   root     4070: 
                   4071:                bool uses_fpu = (tbl[i].specific & COMP_OPCODE_USES_FPU) != 0;
                   4072:                if (uses_fpu && avoid_fpu)
                   4073:                        compfunctbl[cft_map(tbl[i].opcode)] = NULL;
                   4074:                else
                   4075:                        compfunctbl[cft_map(tbl[i].opcode)] = tbl[i].handler;
1.1       root     4076:        }
1.1.1.3   root     4077: 
1.1       root     4078:        for (i = 0; nftbl[i].opcode < 65536; i++) {
1.1.1.5 ! root     4079:                bool uses_fpu = (tbl[i].specific & COMP_OPCODE_USES_FPU) != 0;
        !          4080:                if (uses_fpu && avoid_fpu)
        !          4081:                        nfcompfunctbl[cft_map(nftbl[i].opcode)] = NULL;
        !          4082:                else
        !          4083:                        nfcompfunctbl[cft_map(nftbl[i].opcode)] = nftbl[i].handler;
1.1       root     4084: #ifdef NOFLAGS_SUPPORT
1.1.1.3   root     4085:                nfcpufunctbl[cft_map(nftbl[i].opcode)] = nfctbl[i].handler;
1.1       root     4086: #endif
                   4087:        }
                   4088: 
                   4089: #ifdef NOFLAGS_SUPPORT
                   4090:        for (i = 0; nfctbl[i].handler; i++) {
1.1.1.3   root     4091:                nfcpufunctbl[cft_map(nfctbl[i].opcode)] = nfctbl[i].handler;
1.1       root     4092:        }
                   4093: #endif
                   4094: 
                   4095:        for (opcode = 0; opcode < 65536; opcode++) {
                   4096:                compop_func *f;
                   4097:                compop_func *nff;
                   4098: #ifdef NOFLAGS_SUPPORT
1.1.1.3   root     4099:                cpuop_func *nfcf;
1.1       root     4100: #endif
1.1.1.5 ! root     4101:                int isaddx;
        !          4102: #ifdef UAE
        !          4103:                int isjmp,iscjmp;
        !          4104: #else
        !          4105:                int cflow;
        !          4106: #endif
1.1       root     4107: 
1.1.1.5 ! root     4108: #ifdef UAE
1.1.1.3   root     4109:                int cpu_level = (currprefs.cpu_model - 68000) / 10;
                   4110:                if (cpu_level > 4)
                   4111:                        cpu_level--;
1.1.1.5 ! root     4112: #endif
1.1.1.3   root     4113:                if ((instrmnem)table68k[opcode].mnemo == i_ILLG || table68k[opcode].clev > cpu_level)
1.1       root     4114:                        continue;
                   4115: 
                   4116:                if (table68k[opcode].handler != -1) {
1.1.1.3   root     4117:                        f = compfunctbl[cft_map(table68k[opcode].handler)];
                   4118:                        nff = nfcompfunctbl[cft_map(table68k[opcode].handler)];
1.1       root     4119: #ifdef NOFLAGS_SUPPORT
1.1.1.3   root     4120:                        nfcf = nfcpufunctbl[cft_map(table68k[opcode].handler)];
1.1       root     4121: #endif
1.1.1.5 ! root     4122:                        isaddx = prop[cft_map(table68k[opcode].handler)].is_addx;
        !          4123:                        prop[cft_map(opcode)].is_addx = isaddx;
        !          4124: #ifdef UAE
1.1.1.3   root     4125:                        isjmp = prop[cft_map(table68k[opcode].handler)].is_jump;
                   4126:                        iscjmp = prop[cft_map(table68k[opcode].handler)].is_const_jump;
                   4127:                        prop[cft_map(opcode)].is_jump = isjmp;
                   4128:                        prop[cft_map(opcode)].is_const_jump = iscjmp;
1.1.1.5 ! root     4129: #else
        !          4130:                        cflow = prop[cft_map(table68k[opcode].handler)].cflow;
        !          4131:                        prop[cft_map(opcode)].cflow = cflow;
        !          4132: #endif
1.1.1.3   root     4133:                        compfunctbl[cft_map(opcode)] = f;
                   4134:                        nfcompfunctbl[cft_map(opcode)] = nff;
1.1       root     4135: #ifdef NOFLAGS_SUPPORT
                   4136:                        Dif (nfcf == op_illg)
                   4137:                                abort();
1.1.1.3   root     4138:                        nfcpufunctbl[cft_map(opcode)] = nfcf;
1.1       root     4139: #endif
                   4140:                }
1.1.1.3   root     4141:                prop[cft_map(opcode)].set_flags = table68k[opcode].flagdead;
                   4142:                prop[cft_map(opcode)].use_flags = table68k[opcode].flaglive;
1.1       root     4143:                /* Unconditional jumps don't evaluate condition codes, so they
1.1.1.3   root     4144:                 * don't actually use any flags themselves */
1.1.1.5 ! root     4145: #ifdef UAE
1.1.1.3   root     4146:                if (prop[cft_map(opcode)].is_const_jump)
1.1.1.5 ! root     4147: #else
        !          4148:                if (prop[cft_map(opcode)].cflow & fl_const_jump)
        !          4149: #endif
1.1.1.3   root     4150:                        prop[cft_map(opcode)].use_flags = 0;
1.1       root     4151:        }
                   4152: #ifdef NOFLAGS_SUPPORT
                   4153:        for (i = 0; nfctbl[i].handler != NULL; i++) {
                   4154:                if (nfctbl[i].specific)
1.1.1.3   root     4155:                        nfcpufunctbl[cft_map(tbl[i].opcode)] = nfctbl[i].handler;
1.1       root     4156:        }
                   4157: #endif
                   4158: 
1.1.1.3   root     4159:        /* Merge in blacklist */
                   4160:        if (!merge_blacklist())
1.1.1.5 ! root     4161:        {
        !          4162:                jit_log("<JIT compiler> : blacklist merge failure!");
        !          4163:        }
        !          4164:        
1.1       root     4165:        count=0;
                   4166:        for (opcode = 0; opcode < 65536; opcode++) {
1.1.1.3   root     4167:                if (compfunctbl[cft_map(opcode)])
1.1       root     4168:                        count++;
                   4169:        }
1.1.1.5 ! root     4170:        jit_log("<JIT compiler> : supposedly %d compileable opcodes!",count);
1.1       root     4171: 
                   4172:        /* Initialise state */
                   4173:        create_popalls();
1.1.1.3   root     4174:        alloc_cache();
1.1       root     4175:        reset_lists();
                   4176: 
                   4177:        for (i=0;i<TAGSIZE;i+=2) {
                   4178:                cache_tags[i].handler=(cpuop_func*)popall_execute_normal;
                   4179:                cache_tags[i+1].bi=NULL;
                   4180:        }
1.1.1.5 ! root     4181: #ifdef UAE
1.1       root     4182:        compemu_reset();
1.1.1.5 ! root     4183: #endif
1.1       root     4184: 
1.1.1.3   root     4185: #if 0
1.1       root     4186:        for (i=0;i<N_REGS;i++) {
                   4187:                empty_ss.nat[i].holds=-1;
                   4188:                empty_ss.nat[i].validsize=0;
                   4189:                empty_ss.nat[i].dirtysize=0;
                   4190:        }
                   4191: #endif
1.1.1.3   root     4192:        for (i=0;i<VREGS;i++) {
                   4193:                empty_ss.virt[i]=L_NEEDED;
                   4194:        }
                   4195:        for (i=0;i<N_REGS;i++) {
                   4196:                empty_ss.nat[i]=L_UNKNOWN;
                   4197:        }
                   4198:        default_ss=empty_ss;
1.1       root     4199: }
                   4200: 
                   4201: 
1.1.1.3   root     4202: static void flush_icache_none(int)
1.1       root     4203: {
1.1.1.3   root     4204:        /* Nothing to do.  */
                   4205: }
                   4206: 
1.1.1.4   root     4207: void flush_icache_hard(int n)
1.1.1.3   root     4208: {
                   4209:        blockinfo* bi, *dbi;
1.1       root     4210: 
1.1.1.5 ! root     4211: #ifndef UAE
        !          4212:        jit_log("JIT: Flush Icache_hard(%d/%x/%p), %u KB",
        !          4213:                n,regs.pc,regs.pc_p,current_cache_size/1024);
1.1       root     4214: #endif
1.1.1.5 ! root     4215:        UNUSED(n);
1.1       root     4216:        bi=active;
                   4217:        while(bi) {
                   4218:                cache_tags[cacheline(bi->pc_p)].handler=(cpuop_func*)popall_execute_normal;
                   4219:                cache_tags[cacheline(bi->pc_p)+1].bi=NULL;
1.1.1.3   root     4220:                dbi=bi; bi=bi->next;
                   4221:                free_blockinfo(dbi);
1.1       root     4222:        }
                   4223:        bi=dormant;
                   4224:        while(bi) {
                   4225:                cache_tags[cacheline(bi->pc_p)].handler=(cpuop_func*)popall_execute_normal;
                   4226:                cache_tags[cacheline(bi->pc_p)+1].bi=NULL;
1.1.1.3   root     4227:                dbi=bi; bi=bi->next;
                   4228:                free_blockinfo(dbi);
1.1       root     4229:        }
                   4230: 
                   4231:        reset_lists();
                   4232:        if (!compiled_code)
                   4233:                return;
1.1.1.5 ! root     4234: 
        !          4235: #if defined(USE_DATA_BUFFER)
        !          4236:        reset_data_buffer();
        !          4237: #endif
        !          4238: 
1.1       root     4239:        current_compile_p=compiled_code;
1.1.1.5 ! root     4240: #ifdef UAE
1.1       root     4241:        set_special(0); /* To get out of compiled code */
1.1.1.5 ! root     4242: #else
        !          4243:        SPCFLAGS_SET( SPCFLAG_JIT_EXEC_RETURN ); /* To get out of compiled code */
        !          4244: #endif
1.1       root     4245: }
                   4246: 
                   4247: 
                   4248: /* "Soft flushing" --- instead of actually throwing everything away,
1.1.1.3   root     4249:    we simply mark everything as "needs to be checked".
1.1       root     4250: */
                   4251: 
1.1.1.5 ! root     4252: #ifdef WINUAE_ARANYM
        !          4253: static inline void flush_icache_lazy(int)
        !          4254: #else
1.1.1.4   root     4255: void flush_icache(int n)
1.1.1.5 ! root     4256: #endif
1.1       root     4257: {
                   4258:        blockinfo* bi;
                   4259:        blockinfo* bi2;
                   4260: 
1.1.1.5 ! root     4261: #ifdef UAE
1.1       root     4262:        if (currprefs.comp_hardflush) {
1.1.1.4   root     4263:                flush_icache_hard(n);
1.1       root     4264:                return;
                   4265:        }
1.1.1.5 ! root     4266: #endif
1.1       root     4267:        if (!active)
                   4268:                return;
                   4269: 
                   4270:        bi=active;
                   4271:        while (bi) {
                   4272:                uae_u32 cl=cacheline(bi->pc_p);
1.1.1.3   root     4273:                if (bi->status==BI_INVALID ||
                   4274:                        bi->status==BI_NEED_RECOMP) { 
1.1       root     4275:                        if (bi==cache_tags[cl+1].bi)
                   4276:                                cache_tags[cl].handler=(cpuop_func*)popall_execute_normal;
                   4277:                        bi->handler_to_use=(cpuop_func*)popall_execute_normal;
                   4278:                        set_dhtu(bi,bi->direct_pen);
1.1.1.3   root     4279:                        bi->status=BI_INVALID;
                   4280:                }
                   4281:                else {
1.1       root     4282:                        if (bi==cache_tags[cl+1].bi)
                   4283:                                cache_tags[cl].handler=(cpuop_func*)popall_check_checksum;
                   4284:                        bi->handler_to_use=(cpuop_func*)popall_check_checksum;
                   4285:                        set_dhtu(bi,bi->direct_pcc);
1.1.1.3   root     4286:                        bi->status=BI_NEED_CHECK;
1.1       root     4287:                }
                   4288:                bi2=bi;
                   4289:                bi=bi->next;
                   4290:        }
                   4291:        /* bi2 is now the last entry in the active list */
                   4292:        bi2->next=dormant;
                   4293:        if (dormant)
                   4294:                dormant->prev_p=&(bi2->next);
                   4295: 
                   4296:        dormant=active;
                   4297:        active->prev_p=&dormant;
                   4298:        active=NULL;
                   4299: }
                   4300: 
1.1.1.3   root     4301: #ifdef UAE
                   4302: static
                   4303: #endif
                   4304: void flush_icache_range(uae_u32 start, uae_u32 length)
                   4305: {
                   4306:        if (!active)
                   4307:                return;
                   4308: 
                   4309: #if LAZY_FLUSH_ICACHE_RANGE
                   4310:        uae_u8 *start_p = get_real_address(start);
                   4311:        blockinfo *bi = active;
                   4312:        while (bi) {
                   4313: #if USE_CHECKSUM_INFO
                   4314:                bool invalidate = false;
                   4315:                for (checksum_info *csi = bi->csi; csi && !invalidate; csi = csi->next)
                   4316:                        invalidate = (((start_p - csi->start_p) < csi->length) ||
                   4317:                                                  ((csi->start_p - start_p) < length));
                   4318: #else
                   4319:                // Assume system is consistent and would invalidate the right range
                   4320:                const bool invalidate = (bi->pc_p - start_p) < length;
                   4321: #endif
                   4322:                if (invalidate) {
                   4323:                        uae_u32 cl = cacheline(bi->pc_p);
                   4324:                        if (bi == cache_tags[cl + 1].bi)
                   4325:                                        cache_tags[cl].handler = (cpuop_func *)popall_execute_normal;
                   4326:                        bi->handler_to_use = (cpuop_func *)popall_execute_normal;
                   4327:                        set_dhtu(bi, bi->direct_pen);
                   4328:                        bi->status = BI_NEED_RECOMP;
                   4329:                }
                   4330:                bi = bi->next;
                   4331:        }
                   4332:        return;
                   4333: #else
                   4334:                UNUSED(start);
                   4335:                UNUSED(length);
                   4336: #endif
                   4337:        flush_icache(-1);
                   4338: }
1.1       root     4339: 
1.1.1.3   root     4340: /*
1.1       root     4341: static void catastrophe(void)
                   4342: {
1.1.1.3   root     4343:        jit_abort("catastprophe");
1.1       root     4344: }
1.1.1.3   root     4345: */
1.1       root     4346: 
                   4347: int failure;
                   4348: 
1.1.1.3   root     4349: #ifdef UAE
                   4350: static inline unsigned int get_opcode_cft_map(unsigned int f)
                   4351: {
                   4352:        return ((f >> 8) & 255) | ((f & 255) << 8);
                   4353: }
                   4354: #define DO_GET_OPCODE(a) (get_opcode_cft_map((uae_u16)*(a)))
                   4355: #else
                   4356: #if defined(HAVE_GET_WORD_UNSWAPPED) && !defined(FULLMMU)
                   4357: # define DO_GET_OPCODE(a) (do_get_mem_word_unswapped((uae_u16 *)(a)))
                   4358: #else
                   4359: # define DO_GET_OPCODE(a) (do_get_mem_word((uae_u16 *)(a)))
                   4360: #endif
                   4361: #endif
                   4362: 
                   4363: #ifdef JIT_DEBUG
                   4364: static uae_u8 *last_regs_pc_p = 0;
                   4365: static uae_u8 *last_compiled_block_addr = 0;
                   4366: 
                   4367: void compiler_dumpstate(void)
                   4368: {
                   4369:        if (!JITDebug)
                   4370:                return;
                   4371:        
1.1.1.5 ! root     4372:        jit_log("### Host addresses");
        !          4373:        jit_log("MEM_BASE    : %lx", (unsigned long)MEMBaseDiff);
        !          4374:        jit_log("PC_P        : %p", &regs.pc_p);
        !          4375:        jit_log("SPCFLAGS    : %p", &regs.spcflags);
        !          4376:        jit_log("D0-D7       : %p-%p", &regs.regs[0], &regs.regs[7]);
        !          4377:        jit_log("A0-A7       : %p-%p", &regs.regs[8], &regs.regs[15]);
        !          4378:        jit_log(" ");
1.1.1.3   root     4379:        
1.1.1.5 ! root     4380:        jit_log("### M68k processor state");
        !          4381: #ifdef UAE
        !          4382:        m68k_dumpstate(NULL);
        !          4383: #else
1.1.1.3   root     4384:        m68k_dumpstate(stderr, 0);
1.1.1.5 ! root     4385: #endif
        !          4386:        jit_log(" ");
1.1.1.3   root     4387:        
1.1.1.5 ! root     4388:        jit_log("### Block in Atari address space");
        !          4389:        jit_log("M68K block   : %p",
1.1.1.3   root     4390:                          (void *)(uintptr)last_regs_pc_p);
                   4391:        if (last_regs_pc_p != 0) {
1.1.1.5 ! root     4392:                jit_log("Native block : %p (%d bytes)",
1.1.1.3   root     4393:                          (void *)last_compiled_block_addr,
                   4394:                          get_blockinfo_addr(last_regs_pc_p)->direct_handler_size);
                   4395:        }
1.1.1.5 ! root     4396:        jit_log(" ");
1.1.1.3   root     4397: }
                   4398: #endif
1.1       root     4399: 
1.1.1.3   root     4400: #ifdef UAE
                   4401: void compile_block(cpu_history *pc_hist, int blocklen, int totcycles)
                   4402: {
1.1.1.5 ! root     4403:        if (cache_enabled && compiled_code && currprefs.cpu_model >= 68020) {
1.1.1.3   root     4404: #else
                   4405: static void compile_block(cpu_history* pc_hist, int blocklen)
1.1       root     4406: {
1.1.1.5 ! root     4407:        if (cache_enabled && compiled_code) {
1.1.1.3   root     4408: #endif
                   4409: #ifdef PROFILE_COMPILE_TIME
                   4410:                compile_count++;
                   4411:                clock_t start_time = clock();
                   4412: #endif
                   4413: #ifdef JIT_DEBUG
                   4414:                bool disasm_block = false;
                   4415: #endif
1.1       root     4416: 
                   4417:                /* OK, here we need to 'compile' a block */
                   4418:                int i;
                   4419:                int r;
                   4420:                int was_comp=0;
                   4421:                uae_u8 liveflags[MAXRUN+1];
1.1.1.3   root     4422: #if USE_CHECKSUM_INFO
                   4423:                bool trace_in_rom = isinrom((uintptr)pc_hist[0].location) != 0;
                   4424:                uintptr max_pcp=(uintptr)pc_hist[blocklen - 1].location;
                   4425:                uintptr min_pcp=max_pcp;
                   4426: #else
                   4427:                uintptr max_pcp=(uintptr)pc_hist[0].location;
                   4428:                uintptr min_pcp=max_pcp;
                   4429: #endif
1.1       root     4430:                uae_u32 cl=cacheline(pc_hist[0].location);
                   4431:                void* specflags=(void*)&regs.spcflags;
                   4432:                blockinfo* bi=NULL;
                   4433:                blockinfo* bi2;
                   4434:                int extra_len=0;
                   4435: 
1.1.1.3   root     4436:                redo_current_block=0;
                   4437:                if (current_compile_p >= MAX_COMPILE_PTR)
1.1.1.5 ! root     4438:                        flush_icache_hard(7);
1.1       root     4439: 
                   4440:                alloc_blockinfos();
                   4441: 
                   4442:                bi=get_blockinfo_addr_new(pc_hist[0].location,0);
                   4443:                bi2=get_blockinfo(cl);
                   4444: 
                   4445:                optlev=bi->optlevel;
1.1.1.3   root     4446:                if (bi->status!=BI_INVALID) {
1.1       root     4447:                        Dif (bi!=bi2) {
                   4448:                                /* I don't think it can happen anymore. Shouldn't, in
1.1.1.5 ! root     4449:                                   any case. So let's make sure... */
1.1.1.3   root     4450:                                jit_abort("WOOOWOO count=%d, ol=%d %p %p", bi->count,bi->optlevel,bi->handler_to_use, cache_tags[cl].handler);
1.1       root     4451:                        }
                   4452: 
1.1.1.3   root     4453:                        Dif (bi->count!=-1 && bi->status!=BI_NEED_RECOMP) {
                   4454:                                jit_abort("bi->count=%d, bi->status=%d,bi->optlevel=%d",bi->count,bi->status,bi->optlevel);
1.1       root     4455:                                /* What the heck? We are not supposed to be here! */
                   4456:                        }
                   4457:                }
                   4458:                if (bi->count==-1) {
                   4459:                        optlev++;
1.1.1.3   root     4460:                        while (!optcount[optlev])
1.1       root     4461:                                optlev++;
1.1.1.3   root     4462:                        bi->count=optcount[optlev]-1;
1.1       root     4463:                }
1.1.1.3   root     4464:                current_block_pc_p=(uintptr)pc_hist[0].location;
1.1       root     4465: 
                   4466:                remove_deps(bi); /* We are about to create new code */
                   4467:                bi->optlevel=optlev;
                   4468:                bi->pc_p=(uae_u8*)pc_hist[0].location;
1.1.1.3   root     4469: #if USE_CHECKSUM_INFO
                   4470:                free_checksum_info_chain(bi->csi);
                   4471:                bi->csi = NULL;
                   4472: #endif
1.1       root     4473: 
1.1.1.5 ! root     4474:                liveflags[blocklen]=FLAG_ALL; /* All flags needed afterwards */
1.1       root     4475:                i=blocklen;
                   4476:                while (i--) {
                   4477:                        uae_u16* currpcp=pc_hist[i].location;
1.1.1.3   root     4478:                        uae_u32 op=DO_GET_OPCODE(currpcp);
1.1       root     4479: 
1.1.1.3   root     4480: #if USE_CHECKSUM_INFO
                   4481:                        trace_in_rom = trace_in_rom && isinrom((uintptr)currpcp);
                   4482:                        if (follow_const_jumps && is_const_jump(op)) {
                   4483:                                checksum_info *csi = alloc_checksum_info();
                   4484:                                csi->start_p = (uae_u8 *)min_pcp;
                   4485:                                csi->length = max_pcp - min_pcp + LONGEST_68K_INST;
                   4486:                                csi->next = bi->csi;
                   4487:                                bi->csi = csi;
                   4488:                                max_pcp = (uintptr)currpcp;
                   4489:                        }
                   4490:                        min_pcp = (uintptr)currpcp;
                   4491: #else
                   4492:                        if ((uintptr)currpcp<min_pcp)
                   4493:                                min_pcp=(uintptr)currpcp;
                   4494:                        if ((uintptr)currpcp>max_pcp)
                   4495:                                max_pcp=(uintptr)currpcp;
                   4496: #endif
1.1       root     4497: 
1.1.1.3   root     4498: #ifdef UAE
1.1.1.5 ! root     4499:                        if (!currprefs.compnf) {
        !          4500:                                liveflags[i]=FLAG_ALL;
        !          4501:                        }
        !          4502:                        else
1.1.1.3   root     4503: #endif
1.1.1.5 ! root     4504:                        {
        !          4505:                                liveflags[i] = ((liveflags[i+1] & (~prop[op].set_flags))|prop[op].use_flags);
1.1       root     4506:                                if (prop[op].is_addx && (liveflags[i+1]&FLAG_Z)==0)
                   4507:                                        liveflags[i]&= ~FLAG_Z;
                   4508:                        }
                   4509:                }
                   4510: 
1.1.1.3   root     4511: #if USE_CHECKSUM_INFO
                   4512:                checksum_info *csi = alloc_checksum_info();
                   4513:                csi->start_p = (uae_u8 *)min_pcp;
                   4514:                csi->length = max_pcp - min_pcp + LONGEST_68K_INST;
                   4515:                csi->next = bi->csi;
                   4516:                bi->csi = csi;
                   4517: #endif
1.1       root     4518: 
1.1.1.3   root     4519:                bi->needed_flags=liveflags[0];
1.1       root     4520: 
1.1.1.3   root     4521:                align_target(align_loops);
1.1       root     4522:                was_comp=0;
                   4523: 
                   4524:                bi->direct_handler=(cpuop_func*)get_target();
                   4525:                set_dhtu(bi,bi->direct_handler);
1.1.1.3   root     4526:                bi->status=BI_COMPILING;
                   4527:                current_block_start_target=(uintptr)get_target();
                   4528:        
                   4529:                log_startblock();
1.1       root     4530: 
                   4531:                if (bi->count>=0) { /* Need to generate countdown code */
1.1.1.3   root     4532:                        compemu_raw_mov_l_mi((uintptr)&regs.pc_p,(uintptr)pc_hist[0].location);
                   4533:                        compemu_raw_sub_l_mi((uintptr)&(bi->count),1);
                   4534:                        compemu_raw_jl((uintptr)popall_recompile_block);
1.1       root     4535:                }
                   4536:                if (optlev==0) { /* No need to actually translate */
                   4537:                        /* Execute normally without keeping stats */
1.1.1.3   root     4538:                        compemu_raw_mov_l_mi((uintptr)&regs.pc_p,(uintptr)pc_hist[0].location);
                   4539:                        compemu_raw_jmp((uintptr)popall_exec_nostats);
1.1       root     4540:                }
                   4541:                else {
                   4542:                        reg_alloc_run=0;
                   4543:                        next_pc_p=0;
                   4544:                        taken_pc_p=0;
1.1.1.3   root     4545:                        branch_cc=0; // Only to be initialized. Will be set together with next_pc_p
1.1       root     4546: 
1.1.1.3   root     4547:                        comp_pc_p=(uae_u8*)pc_hist[0].location;
                   4548:                        init_comp();
                   4549:                        was_comp=1;
                   4550: 
                   4551: #ifdef USE_CPU_EMUL_SERVICES
                   4552:                        compemu_raw_sub_l_mi((uintptr)&emulated_ticks,blocklen);
                   4553:                        compemu_raw_jcc_b_oponly(NATIVE_CC_GT);
                   4554:                        uae_s8 *branchadd=(uae_s8*)get_target();
                   4555:                        skip_byte();
                   4556:                        raw_dec_sp(STACK_SHADOW_SPACE);
                   4557:                        compemu_raw_call((uintptr)cpu_do_check_ticks);
                   4558:                        raw_inc_sp(STACK_SHADOW_SPACE);
                   4559:                        *branchadd=(uintptr)get_target()-((uintptr)branchadd+1);
                   4560: #endif
                   4561: 
                   4562: #ifdef JIT_DEBUG
                   4563:                        if (JITDebug) {
                   4564:                                compemu_raw_mov_l_mi((uintptr)&last_regs_pc_p,(uintptr)pc_hist[0].location);
                   4565:                                compemu_raw_mov_l_mi((uintptr)&last_compiled_block_addr,current_block_start_target);
                   4566:                        }
                   4567: #endif
1.1.1.5 ! root     4568: 
        !          4569:                        for (i=0;i<blocklen && get_target_noopt() < MAX_COMPILE_PTR;i++) {
        !          4570:                                cpuop_func **cputbl;
        !          4571:                                compop_func **comptbl;
        !          4572:                                uae_u32 opcode=DO_GET_OPCODE(pc_hist[i].location);
        !          4573:                                needed_flags=(liveflags[i+1] & prop[opcode].set_flags);
1.1.1.3   root     4574: #ifdef UAE
1.1.1.5 ! root     4575:                                special_mem=pc_hist[i].specmem;
        !          4576:                                if (!needed_flags && currprefs.compnf)
1.1.1.3   root     4577: #else
1.1.1.5 ! root     4578:                                if (!needed_flags)
1.1.1.3   root     4579: #endif
1.1.1.5 ! root     4580:                                {
1.1       root     4581: #ifdef NOFLAGS_SUPPORT
1.1.1.5 ! root     4582:                                        cputbl=nfcpufunctbl;
1.1       root     4583: #else
1.1.1.5 ! root     4584:                                        cputbl=cpufunctbl;
1.1       root     4585: #endif
1.1.1.5 ! root     4586:                                        comptbl=nfcompfunctbl;
        !          4587:                                }
        !          4588:                                else {
        !          4589:                                        cputbl=cpufunctbl;
        !          4590:                                        comptbl=compfunctbl;
        !          4591:                                }
1.1       root     4592: 
1.1.1.3   root     4593: #ifdef FLIGHT_RECORDER
1.1.1.5 ! root     4594:                                {
        !          4595:                                        /* store also opcode to second register */
        !          4596:                                        clobber_flags();
        !          4597:                                        remove_all_offsets();
        !          4598:                                        prepare_for_call_1();
        !          4599:                                        prepare_for_call_2();
        !          4600:                                        raw_mov_l_ri(REG_PAR1, ((uintptr)(pc_hist[i].location)) - MEMBaseDiff);
        !          4601:                                        raw_mov_w_ri(REG_PAR2, opcode);
        !          4602:                                        raw_dec_sp(STACK_SHADOW_SPACE);
        !          4603:                                        compemu_raw_call((uintptr)m68k_record_step);
        !          4604:                                        raw_inc_sp(STACK_SHADOW_SPACE);
        !          4605:                                }
        !          4606: #endif
        !          4607: 
        !          4608:                                failure = 1; // gb-- defaults to failure state
        !          4609:                                if (comptbl[opcode] && optlev>1) {
        !          4610:                                        failure=0;
        !          4611:                                        if (!was_comp) {
        !          4612:                                                comp_pc_p=(uae_u8*)pc_hist[i].location;
        !          4613:                                                init_comp();
1.1.1.3   root     4614:                                        }
1.1.1.5 ! root     4615:                                        was_comp=1;
        !          4616:                                        
        !          4617: #ifdef WINUAE_ARANYM
        !          4618:                                        bool isnop = do_get_mem_word(pc_hist[i].location) == 0x4e71 ||
        !          4619:                                                ((i + 1) < blocklen && do_get_mem_word(pc_hist[i+1].location) == 0x4e71);
        !          4620:                                        
        !          4621:                                        if (isnop)
        !          4622:                                                compemu_raw_mov_l_mi((uintptr)&regs.fault_pc, ((uintptr)(pc_hist[i].location)) - MEMBaseDiff);
1.1.1.3   root     4623: #endif
                   4624: 
1.1.1.5 ! root     4625:                                        comptbl[opcode](opcode);
        !          4626:                                        freescratch();
        !          4627:                                        if (!(liveflags[i+1] & FLAG_CZNV)) {
        !          4628:                                                /* We can forget about flags */
        !          4629:                                                dont_care_flags();
        !          4630:                                        }
1.1       root     4631: #if INDIVIDUAL_INST
1.1.1.5 ! root     4632:                                        flush(1);
        !          4633:                                        nop();
        !          4634:                                        flush(1);
        !          4635:                                        was_comp=0;
        !          4636: #endif
        !          4637: 
        !          4638: #ifdef WINUAE_ARANYM
        !          4639:                                        /*
        !          4640:                                         * workaround for buserror handling: on a "nop", write registers back
        !          4641:                                         */
        !          4642:                                        if (isnop)
        !          4643:                                        {
1.1       root     4644:                                                flush(1);
                   4645:                                                nop();
                   4646:                                                was_comp=0;
                   4647:                                        }
1.1.1.5 ! root     4648: #endif
        !          4649:                                }
1.1.1.3   root     4650: 
1.1.1.5 ! root     4651:                                if (failure) {
        !          4652:                                        if (was_comp) {
        !          4653:                                                flush(1);
        !          4654:                                                was_comp=0;
        !          4655:                                        }
        !          4656:                                        compemu_raw_mov_l_ri(REG_PAR1,(uae_u32)opcode);
1.1       root     4657: #if USE_NORMAL_CALLING_CONVENTION
1.1.1.5 ! root     4658:                                        raw_push_l_r(REG_PAR1);
1.1       root     4659: #endif
1.1.1.5 ! root     4660:                                        compemu_raw_mov_l_mi((uintptr)&regs.pc_p,
        !          4661:                                                (uintptr)pc_hist[i].location);
        !          4662:                                        raw_dec_sp(STACK_SHADOW_SPACE);
        !          4663:                                        compemu_raw_call((uintptr)cputbl[opcode]);
        !          4664:                                        raw_inc_sp(STACK_SHADOW_SPACE);
1.1.1.3   root     4665: #ifdef PROFILE_UNTRANSLATED_INSNS
1.1.1.5 ! root     4666:                                        // raw_cputbl_count[] is indexed with plain opcode (in m68k order)
        !          4667:                                        compemu_raw_add_l_mi((uintptr)&raw_cputbl_count[cft_map(opcode)],1);
1.1.1.3   root     4668: #endif
1.1       root     4669: #if USE_NORMAL_CALLING_CONVENTION
1.1.1.5 ! root     4670:                                        raw_inc_sp(4);
1.1       root     4671: #endif
                   4672: 
1.1.1.5 ! root     4673:                                        if (i < blocklen - 1) {
        !          4674:                                                uae_s8* branchadd;
1.1       root     4675: 
1.1.1.5 ! root     4676:                                                /* if (SPCFLAGS_TEST(SPCFLAG_STOP)) popall_do_nothing() */
        !          4677:                                                compemu_raw_mov_l_rm(0,(uintptr)specflags);
        !          4678:                                                compemu_raw_test_l_rr(0,0);
1.1.1.3   root     4679: #if defined(USE_DATA_BUFFER)
1.1.1.5 ! root     4680:                                                data_check_end(8, 64);  // just a pessimistic guess...
1.1.1.3   root     4681: #endif
1.1.1.5 ! root     4682:                                                compemu_raw_jz_b_oponly();
        !          4683:                                                branchadd=(uae_s8*)get_target();
        !          4684:                                                skip_byte();
1.1.1.3   root     4685: #ifdef UAE
1.1.1.5 ! root     4686:                                                raw_sub_l_mi(uae_p32(&countdown),scaled_cycles(totcycles));
1.1.1.3   root     4687: #endif
1.1.1.5 ! root     4688:                                                compemu_raw_jmp((uintptr)popall_do_nothing);
        !          4689:                                                *branchadd=(uintptr)get_target()-(uintptr)branchadd-1;
1.1       root     4690:                                        }
1.1.1.5 ! root     4691:                                }
1.1       root     4692:                        }
1.1.1.3   root     4693: #if 1 /* This isn't completely kosher yet; It really needs to be
1.1.1.5 ! root     4694:                 be integrated into a general inter-block-dependency scheme */
1.1       root     4695:                        if (next_pc_p && taken_pc_p &&
1.1.1.5 ! root     4696:                                was_comp && taken_pc_p==current_block_pc_p)
        !          4697:                        {
        !          4698:                                blockinfo* bi1=get_blockinfo_addr_new((void*)next_pc_p,0);
        !          4699:                                blockinfo* bi2=get_blockinfo_addr_new((void*)taken_pc_p,0);
        !          4700:                                uae_u8 x=bi1->needed_flags;
        !          4701: 
        !          4702:                                if (x==0xff || 1) {  /* To be on the safe side */
        !          4703:                                        uae_u16* next=(uae_u16*)next_pc_p;
        !          4704:                                        uae_u32 op=DO_GET_OPCODE(next);
        !          4705: 
        !          4706:                                        x=FLAG_ALL;
        !          4707:                                        x&=(~prop[op].set_flags);
        !          4708:                                        x|=prop[op].use_flags;
        !          4709:                                }
1.1       root     4710: 
1.1.1.5 ! root     4711:                                x|=bi2->needed_flags;
        !          4712:                                if (!(x & FLAG_CZNV)) {
        !          4713:                                        /* We can forget about flags */
        !          4714:                                        dont_care_flags();
        !          4715:                                        extra_len+=2; /* The next instruction now is part of this block */
        !          4716:                                }
1.1       root     4717:                        }
                   4718: #endif
1.1.1.3   root     4719:                        log_flush();
1.1       root     4720: 
                   4721:                        if (next_pc_p) { /* A branch was registered */
1.1.1.3   root     4722:                                uintptr t1=next_pc_p;
                   4723:                                uintptr t2=taken_pc_p;
1.1       root     4724:                                int     cc=branch_cc;
                   4725: 
                   4726:                                uae_u32* branchadd;
                   4727:                                uae_u32* tba;
                   4728:                                bigstate tmp;
                   4729:                                blockinfo* tbi;
                   4730: 
                   4731:                                if (taken_pc_p<next_pc_p) {
                   4732:                                        /* backward branch. Optimize for the "taken" case ---
1.1.1.5 ! root     4733:                                           which means the raw_jcc should fall through when
        !          4734:                                           the 68k branch is taken. */
1.1       root     4735:                                        t1=taken_pc_p;
                   4736:                                        t2=next_pc_p;
                   4737:                                        cc=branch_cc^1;
                   4738:                                }
                   4739: 
                   4740:                                tmp=live; /* ouch! This is big... */
1.1.1.3   root     4741: #if defined(USE_DATA_BUFFER)
                   4742:                                data_check_end(32, 128); // just a pessimistic guess...
                   4743: #endif
                   4744:                                compemu_raw_jcc_l_oponly(cc);
1.1       root     4745:                                branchadd=(uae_u32*)get_target();
1.1.1.3   root     4746:                                skip_long();
1.1.1.5 ! root     4747: 
1.1       root     4748:                                /* predicted outcome */
                   4749:                                tbi=get_blockinfo_addr_new((void*)t1,1);
1.1.1.3   root     4750:                                match_states(tbi);
                   4751: #ifdef UAE
                   4752:                                raw_sub_l_mi(uae_p32(&countdown),scaled_cycles(totcycles));
1.1.1.5 ! root     4753:                                raw_jcc_l_oponly(NATIVE_CC_PL);
1.1.1.3   root     4754: #else
                   4755:                                compemu_raw_cmp_l_mi8((uintptr)specflags,0);
                   4756:                                compemu_raw_jcc_l_oponly(NATIVE_CC_EQ);
                   4757: #endif
1.1       root     4758:                                tba=(uae_u32*)get_target();
1.1.1.3   root     4759:                                emit_jmp_target(get_handler(t1));
                   4760:                                compemu_raw_mov_l_mi((uintptr)&regs.pc_p,t1);
                   4761:                                flush_reg_count();
                   4762:                                compemu_raw_jmp((uintptr)popall_do_nothing);
1.1       root     4763:                                create_jmpdep(bi,0,tba,t1);
                   4764: 
1.1.1.3   root     4765:                                align_target(align_jumps);
1.1       root     4766:                                /* not-predicted outcome */
1.1.1.3   root     4767:                                write_jmp_target(branchadd, (cpuop_func *)get_target());
1.1       root     4768:                                live=tmp; /* Ouch again */
                   4769:                                tbi=get_blockinfo_addr_new((void*)t2,1);
1.1.1.3   root     4770:                                match_states(tbi);
1.1       root     4771: 
                   4772:                                //flush(1); /* Can only get here if was_comp==1 */
1.1.1.3   root     4773: #ifdef UAE
                   4774:                                raw_sub_l_mi(uae_p32(&countdown),scaled_cycles(totcycles));
1.1.1.5 ! root     4775:                                raw_jcc_l_oponly(NATIVE_CC_PL);
1.1.1.3   root     4776: #else
                   4777:                                compemu_raw_cmp_l_mi8((uintptr)specflags,0);
                   4778:                                compemu_raw_jcc_l_oponly(NATIVE_CC_EQ);
                   4779: #endif
1.1       root     4780:                                tba=(uae_u32*)get_target();
1.1.1.3   root     4781:                                emit_jmp_target(get_handler(t2));
                   4782:                                compemu_raw_mov_l_mi((uintptr)&regs.pc_p,t2);
                   4783:                                flush_reg_count();
                   4784:                                compemu_raw_jmp((uintptr)popall_do_nothing);
1.1       root     4785:                                create_jmpdep(bi,1,tba,t2);
                   4786:                        }
                   4787:                        else
                   4788:                        {
                   4789:                                if (was_comp) {
                   4790:                                        flush(1);
                   4791:                                }
1.1.1.3   root     4792:                                flush_reg_count();
1.1       root     4793: 
                   4794:                                /* Let's find out where next_handler is... */
                   4795:                                if (was_comp && isinreg(PC_P)) {
                   4796:                                        r=live.state[PC_P].realreg;
1.1.1.3   root     4797:                                        compemu_raw_and_l_ri(r,TAGMASK);
                   4798:                                        int r2 = (r==0) ? 1 : 0;
                   4799:                                        compemu_raw_mov_l_ri(r2,(uintptr)popall_do_nothing);
                   4800: #ifdef UAE
                   4801:                                        raw_sub_l_mi(uae_p32(&countdown),scaled_cycles(totcycles));
1.1.1.5 ! root     4802:                                        raw_cmov_l_rm_indexed(r2,(uintptr)cache_tags,r,sizeof(void *),NATIVE_CC_PL);
1.1.1.3   root     4803: #else
                   4804:                                        compemu_raw_cmp_l_mi8((uintptr)specflags,0);
1.1.1.5 ! root     4805:                                        compemu_raw_cmov_l_rm_indexed(r2,(uintptr)cache_tags,r,sizeof(void *),NATIVE_CC_EQ);
1.1.1.3   root     4806: #endif
                   4807:                                        compemu_raw_jmp_r(r2);
1.1       root     4808:                                }
                   4809:                                else if (was_comp && isconst(PC_P)) {
1.1.1.3   root     4810:                                        uintptr v = live.state[PC_P].val;
1.1       root     4811:                                        uae_u32* tba;
                   4812:                                        blockinfo* tbi;
                   4813: 
1.1.1.3   root     4814:                                        tbi = get_blockinfo_addr_new((void*) v, 1);
                   4815:                                        match_states(tbi);
1.1       root     4816: 
1.1.1.3   root     4817: #ifdef UAE
                   4818:                                        raw_sub_l_mi(uae_p32(&countdown),scaled_cycles(totcycles));
1.1.1.5 ! root     4819:                                        raw_jcc_l_oponly(NATIVE_CC_PL);
1.1.1.3   root     4820: #else
                   4821:                                        compemu_raw_cmp_l_mi8((uintptr)specflags,0);
                   4822:                                        compemu_raw_jcc_l_oponly(NATIVE_CC_EQ);
                   4823: #endif
1.1       root     4824:                                        tba=(uae_u32*)get_target();
1.1.1.3   root     4825:                                        emit_jmp_target(get_handler(v));
                   4826:                                        compemu_raw_mov_l_mi((uintptr)&regs.pc_p,v);
                   4827:                                        compemu_raw_jmp((uintptr)popall_do_nothing);
1.1       root     4828:                                        create_jmpdep(bi,0,tba,v);
                   4829:                                }
                   4830:                                else {
                   4831:                                        r=REG_PC_TMP;
1.1.1.3   root     4832:                                        compemu_raw_mov_l_rm(r,(uintptr)&regs.pc_p);
                   4833:                                        compemu_raw_and_l_ri(r,TAGMASK);
                   4834:                                        int r2 = (r==0) ? 1 : 0;
                   4835:                                        compemu_raw_mov_l_ri(r2,(uintptr)popall_do_nothing);
                   4836: #ifdef UAE
                   4837:                                        raw_sub_l_mi(uae_p32(&countdown),scaled_cycles(totcycles));
1.1.1.5 ! root     4838:                                        raw_cmov_l_rm_indexed(r2,(uintptr)cache_tags,r,sizeof(void *),NATIVE_CC_PL);
1.1.1.3   root     4839: #else
                   4840:                                        compemu_raw_cmp_l_mi8((uintptr)specflags,0);
1.1.1.5 ! root     4841:                                        compemu_raw_cmov_l_rm_indexed(r2,(uintptr)cache_tags,r,sizeof(void *),NATIVE_CC_EQ);
1.1.1.3   root     4842: #endif
                   4843:                                        compemu_raw_jmp_r(r2);
1.1       root     4844:                                }
                   4845:                        }
                   4846:                }
                   4847: 
1.1.1.3   root     4848: #if USE_MATCH
1.1.1.5 ! root     4849:                if (callers_need_recompile(&live,&(bi->env))) {
        !          4850:                        mark_callers_recompile(bi);
        !          4851:                }
1.1.1.3   root     4852: 
1.1.1.5 ! root     4853:                big_to_small_state(&live,&(bi->env));
1.1.1.3   root     4854: #endif
                   4855: 
                   4856: #if USE_CHECKSUM_INFO
                   4857:                remove_from_list(bi);
                   4858:                if (trace_in_rom) {
                   4859:                        // No need to checksum that block trace on cache invalidation
                   4860:                        free_checksum_info_chain(bi->csi);
                   4861:                        bi->csi = NULL;
                   4862:                        add_to_dormant(bi);
                   4863:                }
                   4864:                else {
                   4865:                        calc_checksum(bi,&(bi->c1),&(bi->c2));
                   4866:                        add_to_active(bi);
                   4867:                }
                   4868: #else
1.1       root     4869:                if (next_pc_p+extra_len>=max_pcp &&
                   4870:                        next_pc_p+extra_len<max_pcp+LONGEST_68K_INST)
                   4871:                        max_pcp=next_pc_p+extra_len;  /* extra_len covers flags magic */
                   4872:                else
                   4873:                        max_pcp+=LONGEST_68K_INST;
1.1.1.3   root     4874: 
1.1       root     4875:                bi->len=max_pcp-min_pcp;
                   4876:                bi->min_pcp=min_pcp;
                   4877: 
                   4878:                remove_from_list(bi);
1.1.1.3   root     4879:                if (isinrom(min_pcp) && isinrom(max_pcp)) {
1.1       root     4880:                        add_to_dormant(bi); /* No need to checksum it on cache flush.
1.1.1.5 ! root     4881:                                                                   Please don't start changing ROMs in
        !          4882:                                                                   flight! */
1.1.1.3   root     4883:                }
1.1       root     4884:                else {
                   4885:                        calc_checksum(bi,&(bi->c1),&(bi->c2));
                   4886:                        add_to_active(bi);
                   4887:                }
1.1.1.3   root     4888: #endif
                   4889: 
                   4890:                current_cache_size += get_target() - (uae_u8 *)current_compile_p;
                   4891: 
                   4892: #ifdef JIT_DEBUG
1.1.1.5 ! root     4893:                bi->direct_handler_size = get_target() - (uae_u8 *)current_block_start_target;
1.1.1.3   root     4894: 
                   4895:                if (JITDebug && disasm_block) {
                   4896:                        uaecptr block_addr = start_pc + ((char *)pc_hist[0].location - (char *)start_pc_p);
1.1.1.5 ! root     4897:                        jit_log("M68K block @ 0x%08x (%d insns)", block_addr, blocklen);
1.1.1.3   root     4898:                        uae_u32 block_size = ((uae_u8 *)pc_hist[blocklen - 1].location - (uae_u8 *)pc_hist[0].location) + 1;
1.1.1.5 ! root     4899: #ifdef WINUAE_ARANYM
        !          4900:                        disasm_m68k_block((const uae_u8 *)pc_hist[0].location, block_size);
        !          4901: #endif
        !          4902:                        jit_log("Compiled block @ %p", pc_hist[0].location);
        !          4903: #ifdef WINUAE_ARANYM
        !          4904:                        disasm_native_block((const uae_u8 *)current_block_start_target, bi->direct_handler_size);
        !          4905: #endif
        !          4906:                        UNUSED(block_addr);
1.1.1.3   root     4907:                }
                   4908: #endif
1.1       root     4909: 
                   4910:                log_dump();
1.1.1.3   root     4911:                align_target(align_jumps);
                   4912: 
                   4913: #ifdef UAE
                   4914: #ifdef USE_UDIS86
                   4915:                UDISFN(current_block_start_target, target)
                   4916: #endif
                   4917: #endif
                   4918: 
                   4919:                /* This is the non-direct handler */
                   4920:                bi->handler=
                   4921:                        bi->handler_to_use=(cpuop_func *)get_target();
                   4922:                compemu_raw_cmp_l_mi((uintptr)&regs.pc_p,(uintptr)pc_hist[0].location);
                   4923:                compemu_raw_jnz((uintptr)popall_cache_miss);
                   4924:                comp_pc_p=(uae_u8*)pc_hist[0].location;
                   4925: 
                   4926:                bi->status=BI_FINALIZING;
                   4927:                init_comp();
                   4928:                match_states(bi);
                   4929:                flush(1);
1.1       root     4930: 
1.1.1.3   root     4931:                compemu_raw_jmp((uintptr)bi->direct_handler);
                   4932: 
                   4933:                flush_cpu_icache((void *)current_block_start_target, (void *)target);
                   4934:                current_compile_p=get_target();
1.1       root     4935:                raise_in_cl_list(bi);
1.1.1.5 ! root     4936: #ifdef UAE
1.1       root     4937:                bi->nexthandler=current_compile_p;
1.1.1.5 ! root     4938: #endif
1.1       root     4939: 
                   4940:                /* We will flush soon, anyway, so let's do it now */
1.1.1.3   root     4941:                if (current_compile_p >= MAX_COMPILE_PTR)
1.1.1.5 ! root     4942:                        flush_icache_hard(7);
1.1       root     4943: 
1.1.1.3   root     4944:                bi->status=BI_ACTIVE;
                   4945:                if (redo_current_block)
                   4946:                        block_need_recompile(bi);
                   4947: 
                   4948: #ifdef PROFILE_COMPILE_TIME
                   4949:                compile_time += (clock() - start_time);
                   4950: #endif
                   4951: #ifdef UAE
                   4952:                /* Account for compilation time */
                   4953:                do_extra_cycles(totcycles);
                   4954: #endif
1.1.1.5 ! root     4955:        }
1.1.1.3   root     4956: }
                   4957: 
                   4958: #ifdef UAE
                   4959:     /* Slightly different function defined in newcpu.cpp */
                   4960: #else
                   4961: void do_nothing(void)
                   4962: {
1.1.1.5 ! root     4963:        /* What did you expect this to do? */
1.1.1.3   root     4964: }
                   4965: #endif
                   4966: 
                   4967: #ifdef UAE
                   4968:     /* Different implementation in newcpu.cpp */
                   4969: #else
                   4970: void exec_nostats(void)
                   4971: {
                   4972:        for (;;)  { 
                   4973:                uae_u32 opcode = GET_OPCODE;
                   4974: #ifdef FLIGHT_RECORDER
                   4975:                m68k_record_step(m68k_getpc(), opcode);
                   4976: #endif
                   4977:                (*cpufunctbl[opcode])(opcode);
                   4978:                cpu_check_ticks();
                   4979:                if (end_block(opcode) || SPCFLAGS_TEST(SPCFLAG_ALL)) {
                   4980:                        return; /* We will deal with the spcflags in the caller */
                   4981:                }
                   4982:        }
                   4983: }
                   4984: #endif
                   4985: 
                   4986: #ifdef UAE
                   4987: /* FIXME: check differences against UAE execute_normal (newcpu.cpp) */
                   4988: #else
                   4989: void execute_normal(void)
                   4990: {
                   4991:        if (!check_for_cache_miss()) {
                   4992:                cpu_history pc_hist[MAXRUN];
                   4993:                int blocklen = 0;
                   4994: #if 0 && FIXED_ADDRESSING
                   4995:                start_pc_p = regs.pc_p;
                   4996:                start_pc = get_virtual_address(regs.pc_p);
                   4997: #else
1.1.1.5 ! root     4998:                start_pc_p = regs.pc_oldp;
1.1.1.3   root     4999:                start_pc = regs.pc; 
                   5000: #endif
                   5001:                for (;;)  { /* Take note: This is the do-it-normal loop */
                   5002:                        pc_hist[blocklen++].location = (uae_u16 *)regs.pc_p;
                   5003:                        uae_u32 opcode = GET_OPCODE;
                   5004: #ifdef FLIGHT_RECORDER
                   5005:                        m68k_record_step(m68k_getpc(), opcode);
                   5006: #endif
                   5007:                        (*cpufunctbl[opcode])(opcode);
                   5008:                        cpu_check_ticks();
                   5009:                        if (end_block(opcode) || SPCFLAGS_TEST(SPCFLAG_ALL) || blocklen>=MAXRUN) {
                   5010:                                compile_block(pc_hist, blocklen);
                   5011:                                return; /* We will deal with the spcflags in the caller */
                   5012:                        }
                   5013:                        /* No need to check regs.spcflags, because if they were set,
                   5014:                        we'd have ended up inside that "if" */
                   5015:                }
                   5016:        }
                   5017: }
                   5018: #endif
                   5019: 
                   5020: typedef void (*compiled_handler)(void);
                   5021: 
                   5022: #ifdef UAE
                   5023: /* FIXME: check differences against UAE m68k_do_compile_execute */
                   5024: #else
                   5025: void m68k_do_compile_execute(void)
                   5026: {
                   5027:        for (;;) {
                   5028:                ((compiled_handler)(pushall_call_handler))();
                   5029:                /* Whenever we return from that, we should check spcflags */
                   5030:                if (SPCFLAGS_TEST(SPCFLAG_ALL)) {
                   5031:                        if (m68k_do_specialties ())
                   5032:                                return;
                   5033:                }
1.1       root     5034:        }
                   5035: }
1.1.1.3   root     5036: #endif
1.1       root     5037: 
1.1.1.3   root     5038: #ifdef UAE
                   5039: /* FIXME: check differences against UAE m68k_compile_execute */
                   5040: #else
                   5041: void m68k_compile_execute (void)
                   5042: {
                   5043: setjmpagain:
                   5044:        TRY(prb) {
                   5045:                for (;;) {
                   5046:                        if (quit_program > 0) {
                   5047:                                if (quit_program == 1) {
                   5048: #ifdef FLIGHT_RECORDER
                   5049:                                        dump_flight_recorder();
                   5050: #endif
                   5051:                                        break;
                   5052:                                }
                   5053:                                quit_program = 0;
                   5054:                                m68k_reset ();
                   5055:                        }
                   5056:                        m68k_do_compile_execute();
                   5057:                }
                   5058:        }
                   5059:        CATCH(prb) {
1.1.1.5 ! root     5060:                jit_log("m68k_compile_execute: exception %d pc=%08x (%08x+%p-%p) fault_pc=%08x addr=%08x -> %08x sp=%08x",
        !          5061:                        int(prb),
        !          5062:                        m68k_getpc(),
        !          5063:                        regs.pc, regs.pc_p, regs.pc_oldp,
        !          5064:                        regs.fault_pc,
        !          5065:                        regs.mmu_fault_addr, get_long (regs.vbr + 4*prb),
        !          5066:                        regs.regs[15]);
1.1.1.3   root     5067:                flush_icache(0);
                   5068:                Exception(prb, 0);
                   5069:                goto setjmpagain;
                   5070:        }
                   5071: }
1.1       root     5072: #endif
1.1.1.3   root     5073: 
                   5074: #endif /* JIT */

unix.superglobalmegacorp.com

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