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

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

unix.superglobalmegacorp.com

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