ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/compiler/compemu_support.cpp
(Generate patch)

Comparing BasiliskII/src/uae_cpu/compiler/compemu_support.cpp (file contents):
Revision 1.3 by gbeauche, 2002-09-18T09:55:37Z vs.
Revision 1.34 by gbeauche, 2005-06-11T06:43:24Z

# Line 1 | Line 1
1 + /*
2 + *  compiler/compemu_support.cpp - Core dynamic translation engine
3 + *
4 + *  Original 68040 JIT compiler for UAE, copyright 2000-2002 Bernd Meyer
5 + *
6 + *  Adaptation for Basilisk II and improvements, copyright 2000-2005
7 + *    Gwenole Beauchesne
8 + *
9 + *  Basilisk II (C) 1997-2005 Christian Bauer
10 + *  
11 + *  This program is free software; you can redistribute it and/or modify
12 + *  it under the terms of the GNU General Public License as published by
13 + *  the Free Software Foundation; either version 2 of the License, or
14 + *  (at your option) any later version.
15 + *
16 + *  This program is distributed in the hope that it will be useful,
17 + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18 + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 + *  GNU General Public License for more details.
20 + *
21 + *  You should have received a copy of the GNU General Public License
22 + *  along with this program; if not, write to the Free Software
23 + *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24 + */
25 +
26   #if !REAL_ADDRESSING && !DIRECT_ADDRESSING
27   #error "Only Real or Direct Addressing is supported with the JIT Compiler"
28   #endif
29  
30 + #if X86_ASSEMBLY && !SAHF_SETO_PROFITABLE
31 + #error "Only [LS]AHF scheme to [gs]et flags is supported with the JIT Compiler"
32 + #endif
33 +
34 + /* NOTE: support for AMD64 assumes translation cache and other code
35 + * buffers are allocated into a 32-bit address space because (i) B2/JIT
36 + * code is not 64-bit clean and (ii) it's faster to resolve branches
37 + * that way.
38 + */
39 + #if !defined(__i386__) && !defined(__x86_64__)
40 + #error "Only IA-32 and X86-64 targets are supported with the JIT Compiler"
41 + #endif
42 +
43   #define USE_MATCH 0
44  
45   /* kludge for Brian, so he can compile under MSVC++ */
46   #define USE_NORMAL_CALLING_CONVENTION 0
47  
48   #ifndef WIN32
49 + #include <unistd.h>
50   #include <sys/types.h>
51   #include <sys/mman.h>
52   #endif
# Line 40 | Line 79
79   #endif
80  
81   #ifndef WIN32
82 < #define PROFILE_COMPILE_TIME    1
82 > #define PROFILE_COMPILE_TIME            1
83 > #define PROFILE_UNTRANSLATED_INSNS      1
84 > #endif
85 >
86 > #if defined(__x86_64__) && 0
87 > #define RECORD_REGISTER_USAGE           1
88   #endif
89  
90   #ifdef WIN32
# Line 57 | Line 101 | static void dummy_write_log(const char *
101   } while (0)
102   #endif
103  
104 + #if RECORD_REGISTER_USAGE
105 + static uint64 reg_count[16];
106 + static int reg_count_local[16];
107 +
108 + static int reg_count_compare(const void *ap, const void *bp)
109 + {
110 +    const int a = *((int *)ap);
111 +    const int b = *((int *)bp);
112 +    return reg_count[b] - reg_count[a];
113 + }
114 + #endif
115 +
116   #if PROFILE_COMPILE_TIME
117   #include <time.h>
118   static uae_u32 compile_count    = 0;
# Line 65 | Line 121 | static clock_t emul_start_time = 0;
121   static clock_t emul_end_time    = 0;
122   #endif
123  
124 < compop_func *compfunctbl[65536];
125 < compop_func *nfcompfunctbl[65536];
126 < cpuop_func *nfcpufunctbl[65536];
124 > #if PROFILE_UNTRANSLATED_INSNS
125 > const int untranslated_top_ten = 20;
126 > static uae_u32 raw_cputbl_count[65536] = { 0, };
127 > static uae_u16 opcode_nums[65536];
128 >
129 > static int untranslated_compfn(const void *e1, const void *e2)
130 > {
131 >        return raw_cputbl_count[*(const uae_u16 *)e1] < raw_cputbl_count[*(const uae_u16 *)e2];
132 > }
133 > #endif
134 >
135 > static compop_func *compfunctbl[65536];
136 > static compop_func *nfcompfunctbl[65536];
137 > static cpuop_func *nfcpufunctbl[65536];
138   uae_u8* comp_pc_p;
139  
140 + // From main_unix.cpp
141 + extern bool ThirtyThreeBitAddressing;
142 +
143 + // From newcpu.cpp
144 + extern bool quit_program;
145 +
146   // gb-- Extra data for Basilisk II/JIT
147   #if JIT_DEBUG
148   static bool             JITDebug                        = false;        // Enable runtime disassemblers through mon?
149   #else
150   const bool              JITDebug                        = false;        // Don't use JIT debug mode at all
151   #endif
152 + #if USE_INLINING
153 + static bool             follow_const_jumps      = true;         // Flag: translation through constant jumps    
154 + #else
155 + const bool              follow_const_jumps      = false;
156 + #endif
157  
158 < const uae_u32   MIN_CACHE_SIZE          = 2048;         // Minimal translation cache size (2048 KB)
158 > const uae_u32   MIN_CACHE_SIZE          = 1024;         // Minimal translation cache size (1 MB)
159   static uae_u32  cache_size                      = 0;            // Size of total cache allocated for compiled blocks
160   static uae_u32  current_cache_size      = 0;            // Cache grows upwards: how much has been consumed already
161   static bool             lazy_flush                      = true;         // Flag: lazy translation cache invalidation
162   static bool             avoid_fpu                       = true;         // Flag: compile FPU instructions ?
163   static bool             have_cmov                       = false;        // target has CMOV instructions ?
164 + static bool             have_lahf_lm            = true;         // target has LAHF supported in long mode ?
165   static bool             have_rat_stall          = true;         // target has partial register stalls ?
166 < static int              zero_fd                         = -1;
166 > const bool              tune_alignment          = true;         // Tune code alignments for running CPU ?
167 > const bool              tune_nop_fillers        = true;         // Tune no-op fillers for architecture
168 > static bool             setzflg_uses_bsf        = false;        // setzflg virtual instruction can use native BSF instruction correctly?
169 > static int              align_loops                     = 32;           // Align the start of loops
170 > static int              align_jumps                     = 32;           // Align the start of jumps
171   static int              optcount[10]            = {
172          10,             // How often a block has to be executed before it is translated
173          0,              // How often to use naive translation
# Line 100 | Line 183 | struct op_properties {
183   };
184   static op_properties prop[65536];
185  
103 // gb-- Control Flow Predicates
104
186   static inline int end_block(uae_u32 opcode)
187   {
188          return (prop[opcode].cflow & fl_end_block);
189   }
190  
191 + static inline bool is_const_jump(uae_u32 opcode)
192 + {
193 +        return (prop[opcode].cflow == fl_const_jump);
194 + }
195 +
196   static inline bool may_trap(uae_u32 opcode)
197   {
198          return (prop[opcode].cflow & fl_trap);
199   }
200  
201 + static inline unsigned int cft_map (unsigned int f)
202 + {
203 + #ifndef HAVE_GET_WORD_UNSWAPPED
204 +    return f;
205 + #else
206 +    return ((f >> 8) & 255) | ((f & 255) << 8);
207 + #endif
208 + }
209 +
210   uae_u8* start_pc_p;
211   uae_u32 start_pc;
212   uae_u32 current_block_pc_p;
213 < uae_u32 current_block_start_target;
213 > static uintptr current_block_start_target;
214   uae_u32 needed_flags;
215 < static uae_u32 next_pc_p;
216 < static uae_u32 taken_pc_p;
215 > static uintptr next_pc_p;
216 > static uintptr taken_pc_p;
217   static int branch_cc;
218   static int redo_current_block;
219  
# Line 130 | Line 225 | static uae_u8* current_compile_p=NULL;
225   static uae_u8* max_compile_start;
226   static uae_u8* compiled_code=NULL;
227   static uae_s32 reg_alloc_run;
228 + const int POPALLSPACE_SIZE = 1024; /* That should be enough space */
229 + static uae_u8* popallspace=NULL;
230  
231   void* pushall_call_handler=NULL;
232   static void* popall_do_nothing=NULL;
# Line 139 | Line 236 | static void* popall_cache_miss=NULL;
236   static void* popall_recompile_block=NULL;
237   static void* popall_check_checksum=NULL;
238  
142 extern uae_u32 oink;
143 extern unsigned long foink3;
144 extern unsigned long foink;
145
239   /* The 68k only ever executes from even addresses. So right now, we
240   * waste half the entries in this array
241   * UPDATE: We now use those entries to store the start of the linked
# Line 389 | Line 482 | static __inline__ void invalidate_block(
482  
483   static __inline__ void create_jmpdep(blockinfo* bi, int i, uae_u32* jmpaddr, uae_u32 target)
484   {
485 <    blockinfo*  tbi=get_blockinfo_addr((void*)target);
485 >    blockinfo*  tbi=get_blockinfo_addr((void*)(uintptr)target);
486      
487      Dif(!tbi) {
488          write_log("Could not create jmpdep!\n");
# Line 487 | Line 580 | static void prepare_block(blockinfo* bi)
580     compiled. If the list of free blockinfos is empty, we allocate a new
581     pool of blockinfos and link the newly created blockinfos altogether
582     into the list of free blockinfos. Otherwise, we simply pop a structure
583 <   of the free list.
583 >   off the free list.
584  
585     Blockinfo are lazily deallocated, i.e. chained altogether in the
586     list of free blockinfos whenvever a translation cache flush (hard or
587     soft) request occurs.
588   */
589  
590 < #if USE_SEPARATE_BIA
591 < const int BLOCKINFO_POOL_SIZE = 128;
592 < struct blockinfo_pool {
593 <        blockinfo bi[BLOCKINFO_POOL_SIZE];
594 <        blockinfo_pool *next;
590 > template< class T >
591 > class LazyBlockAllocator
592 > {
593 >        enum {
594 >                kPoolSize = 1 + 4096 / sizeof(T)
595 >        };
596 >        struct Pool {
597 >                T chunk[kPoolSize];
598 >                Pool * next;
599 >        };
600 >        Pool * mPools;
601 >        T * mChunks;
602 > public:
603 >        LazyBlockAllocator() : mPools(0), mChunks(0) { }
604 >        ~LazyBlockAllocator();
605 >        T * acquire();
606 >        void release(T * const);
607   };
503 static blockinfo_pool * blockinfo_pools = 0;
504 static blockinfo *              free_blockinfos = 0;
505 #endif
608  
609 < static __inline__ blockinfo *alloc_blockinfo(void)
609 > template< class T >
610 > LazyBlockAllocator<T>::~LazyBlockAllocator()
611   {
612 < #if USE_SEPARATE_BIA
613 <        if (!free_blockinfos) {
614 <                // There is no blockinfo struct left, allocate a new
615 <                // pool and link the chunks into the free list
616 <                blockinfo_pool *bi_pool = (blockinfo_pool *)malloc(sizeof(blockinfo_pool));
617 <                for (blockinfo *bi = &bi_pool->bi[0]; bi < &bi_pool->bi[BLOCKINFO_POOL_SIZE]; bi++) {
618 <                        bi->next = free_blockinfos;
619 <                        free_blockinfos = bi;
612 >        Pool * currentPool = mPools;
613 >        while (currentPool) {
614 >                Pool * deadPool = currentPool;
615 >                currentPool = currentPool->next;
616 >                free(deadPool);
617 >        }
618 > }
619 >
620 > template< class T >
621 > T * LazyBlockAllocator<T>::acquire()
622 > {
623 >        if (!mChunks) {
624 >                // There is no chunk left, allocate a new pool and link the
625 >                // chunks into the free list
626 >                Pool * newPool = (Pool *)malloc(sizeof(Pool));
627 >                for (T * chunk = &newPool->chunk[0]; chunk < &newPool->chunk[kPoolSize]; chunk++) {
628 >                        chunk->next = mChunks;
629 >                        mChunks = chunk;
630                  }
631 <                bi_pool->next = blockinfo_pools;
632 <                blockinfo_pools = bi_pool;
631 >                newPool->next = mPools;
632 >                mPools = newPool;
633          }
634 <        blockinfo *bi = free_blockinfos;
635 <        free_blockinfos = bi->next;
636 < #else
524 <        blockinfo *bi = (blockinfo*)current_compile_p;
525 <        current_compile_p += sizeof(blockinfo);
526 < #endif
527 <        return bi;
634 >        T * chunk = mChunks;
635 >        mChunks = chunk->next;
636 >        return chunk;
637   }
638  
639 < static __inline__ void free_blockinfo(blockinfo *bi)
639 > template< class T >
640 > void LazyBlockAllocator<T>::release(T * const chunk)
641 > {
642 >        chunk->next = mChunks;
643 >        mChunks = chunk;
644 > }
645 >
646 > template< class T >
647 > class HardBlockAllocator
648   {
649 + public:
650 +        T * acquire() {
651 +                T * data = (T *)current_compile_p;
652 +                current_compile_p += sizeof(T);
653 +                return data;
654 +        }
655 +
656 +        void release(T * const chunk) {
657 +                // Deallocated on invalidation
658 +        }
659 + };
660 +
661   #if USE_SEPARATE_BIA
662 <        bi->next = free_blockinfos;
663 <        free_blockinfos = bi;
662 > static LazyBlockAllocator<blockinfo> BlockInfoAllocator;
663 > static LazyBlockAllocator<checksum_info> ChecksumInfoAllocator;
664 > #else
665 > static HardBlockAllocator<blockinfo> BlockInfoAllocator;
666 > static HardBlockAllocator<checksum_info> ChecksumInfoAllocator;
667   #endif
668 +
669 + static __inline__ checksum_info *alloc_checksum_info(void)
670 + {
671 +        checksum_info *csi = ChecksumInfoAllocator.acquire();
672 +        csi->next = NULL;
673 +        return csi;
674   }
675  
676 < static void free_blockinfo_pools(void)
676 > static __inline__ void free_checksum_info(checksum_info *csi)
677   {
678 < #if USE_SEPARATE_BIA
679 <        int blockinfo_pool_count = 0;
680 <        blockinfo_pool *curr_pool = blockinfo_pools;
681 <        while (curr_pool) {
682 <                blockinfo_pool_count++;
683 <                blockinfo_pool *dead_pool = curr_pool;
684 <                curr_pool = curr_pool->next;
685 <                free(dead_pool);
678 >        csi->next = NULL;
679 >        ChecksumInfoAllocator.release(csi);
680 > }
681 >
682 > static __inline__ void free_checksum_info_chain(checksum_info *csi)
683 > {
684 >        while (csi != NULL) {
685 >                checksum_info *csi2 = csi->next;
686 >                free_checksum_info(csi);
687 >                csi = csi2;
688          }
689 <        
690 <        uae_u32 blockinfo_pools_size = blockinfo_pool_count * BLOCKINFO_POOL_SIZE * sizeof(blockinfo);
691 <        write_log("### Blockinfo allocation statistics\n");
692 <        write_log("Number of blockinfo pools  : %d\n", blockinfo_pool_count);
693 <        write_log("Total number of blockinfos : %d (%d KB)\n",
694 <                          blockinfo_pool_count * BLOCKINFO_POOL_SIZE,
695 <                          blockinfo_pools_size / 1024);
696 <        write_log("\n");
689 > }
690 >
691 > static __inline__ blockinfo *alloc_blockinfo(void)
692 > {
693 >        blockinfo *bi = BlockInfoAllocator.acquire();
694 > #if USE_CHECKSUM_INFO
695 >        bi->csi = NULL;
696 > #endif
697 >        return bi;
698 > }
699 >
700 > static __inline__ void free_blockinfo(blockinfo *bi)
701 > {
702 > #if USE_CHECKSUM_INFO
703 >        free_checksum_info_chain(bi->csi);
704 >        bi->csi = NULL;
705   #endif
706 +        BlockInfoAllocator.release(bi);
707   }
708  
709   static __inline__ void alloc_blockinfos(void)
# Line 597 | Line 746 | static __inline__ void emit_long(uae_u32
746      target+=4;
747   }
748  
749 + static __inline__ void emit_quad(uae_u64 x)
750 + {
751 +    *((uae_u64*)target)=x;
752 +    target+=8;
753 + }
754 +
755 + static __inline__ void emit_block(const uae_u8 *block, uae_u32 blocklen)
756 + {
757 +        memcpy((uae_u8 *)target,block,blocklen);
758 +        target+=blocklen;
759 + }
760 +
761   static __inline__ uae_u32 reverse32(uae_u32 v)
762   {
763   #if 1
# Line 693 | Line 854 | static __inline__ void flush_flags(void)
854   int touchcnt;
855  
856   /********************************************************************
857 + * Partial register flushing for optimized calls                    *
858 + ********************************************************************/
859 +
860 + struct regusage {
861 +        uae_u16 rmask;
862 +        uae_u16 wmask;
863 + };
864 +
865 + static inline void ru_set(uae_u16 *mask, int reg)
866 + {
867 + #if USE_OPTIMIZED_CALLS
868 +        *mask |= 1 << reg;
869 + #endif
870 + }
871 +
872 + static inline bool ru_get(const uae_u16 *mask, int reg)
873 + {
874 + #if USE_OPTIMIZED_CALLS
875 +        return (*mask & (1 << reg));
876 + #else
877 +        /* Default: instruction reads & write to register */
878 +        return true;
879 + #endif
880 + }
881 +
882 + static inline void ru_set_read(regusage *ru, int reg)
883 + {
884 +        ru_set(&ru->rmask, reg);
885 + }
886 +
887 + static inline void ru_set_write(regusage *ru, int reg)
888 + {
889 +        ru_set(&ru->wmask, reg);
890 + }
891 +
892 + static inline bool ru_read_p(const regusage *ru, int reg)
893 + {
894 +        return ru_get(&ru->rmask, reg);
895 + }
896 +
897 + static inline bool ru_write_p(const regusage *ru, int reg)
898 + {
899 +        return ru_get(&ru->wmask, reg);
900 + }
901 +
902 + static void ru_fill_ea(regusage *ru, int reg, amodes mode,
903 +                                           wordsizes size, int write_mode)
904 + {
905 +        switch (mode) {
906 +        case Areg:
907 +                reg += 8;
908 +                /* fall through */
909 +        case Dreg:
910 +                ru_set(write_mode ? &ru->wmask : &ru->rmask, reg);
911 +                break;
912 +        case Ad16:
913 +                /* skip displacment */
914 +                m68k_pc_offset += 2;
915 +        case Aind:
916 +        case Aipi:
917 +        case Apdi:
918 +                ru_set_read(ru, reg+8);
919 +                break;
920 +        case Ad8r:
921 +                ru_set_read(ru, reg+8);
922 +                /* fall through */
923 +        case PC8r: {
924 +                uae_u16 dp = comp_get_iword((m68k_pc_offset+=2)-2);
925 +                reg = (dp >> 12) & 15;
926 +                ru_set_read(ru, reg);
927 +                if (dp & 0x100)
928 +                        m68k_pc_offset += (((dp & 0x30) >> 3) & 7) + ((dp & 3) * 2);
929 +                break;
930 +        }
931 +        case PC16:
932 +        case absw:
933 +        case imm0:
934 +        case imm1:
935 +                m68k_pc_offset += 2;
936 +                break;
937 +        case absl:
938 +        case imm2:
939 +                m68k_pc_offset += 4;
940 +                break;
941 +        case immi:
942 +                m68k_pc_offset += (size == sz_long) ? 4 : 2;
943 +                break;
944 +        }
945 + }
946 +
947 + /* TODO: split into a static initialization part and a dynamic one
948 +   (instructions depending on extension words) */
949 + static void ru_fill(regusage *ru, uae_u32 opcode)
950 + {
951 +        m68k_pc_offset += 2;
952 +
953 +        /* Default: no register is used or written to */
954 +        ru->rmask = 0;
955 +        ru->wmask = 0;
956 +
957 +        uae_u32 real_opcode = cft_map(opcode);
958 +        struct instr *dp = &table68k[real_opcode];
959 +
960 +        bool rw_dest = true;
961 +        bool handled = false;
962 +
963 +        /* Handle some instructions specifically */
964 +        uae_u16 reg, ext;
965 +        switch (dp->mnemo) {
966 +        case i_BFCHG:
967 +        case i_BFCLR:
968 +        case i_BFEXTS:
969 +        case i_BFEXTU:
970 +        case i_BFFFO:
971 +        case i_BFINS:
972 +        case i_BFSET:
973 +        case i_BFTST:
974 +                ext = comp_get_iword((m68k_pc_offset+=2)-2);
975 +                if (ext & 0x800) ru_set_read(ru, (ext >> 6) & 7);
976 +                if (ext & 0x020) ru_set_read(ru, ext & 7);
977 +                ru_fill_ea(ru, dp->dreg, (amodes)dp->dmode, (wordsizes)dp->size, 1);
978 +                if (dp->dmode == Dreg)
979 +                        ru_set_read(ru, dp->dreg);
980 +                switch (dp->mnemo) {
981 +                case i_BFEXTS:
982 +                case i_BFEXTU:
983 +                case i_BFFFO:
984 +                        ru_set_write(ru, (ext >> 12) & 7);
985 +                        break;
986 +                case i_BFINS:
987 +                        ru_set_read(ru, (ext >> 12) & 7);
988 +                        /* fall through */
989 +                case i_BFCHG:
990 +                case i_BFCLR:
991 +                case i_BSET:
992 +                        if (dp->dmode == Dreg)
993 +                                ru_set_write(ru, dp->dreg);
994 +                        break;
995 +                }
996 +                handled = true;
997 +                rw_dest = false;
998 +                break;
999 +
1000 +        case i_BTST:
1001 +                rw_dest = false;
1002 +                break;
1003 +
1004 +        case i_CAS:
1005 +        {
1006 +                ext = comp_get_iword((m68k_pc_offset+=2)-2);
1007 +                int Du = ext & 7;
1008 +                ru_set_read(ru, Du);
1009 +                int Dc = (ext >> 6) & 7;
1010 +                ru_set_read(ru, Dc);
1011 +                ru_set_write(ru, Dc);
1012 +                break;
1013 +        }
1014 +        case i_CAS2:
1015 +        {
1016 +                int Dc1, Dc2, Du1, Du2, Rn1, Rn2;
1017 +                ext = comp_get_iword((m68k_pc_offset+=2)-2);
1018 +                Rn1 = (ext >> 12) & 15;
1019 +                Du1 = (ext >> 6) & 7;
1020 +                Dc1 = ext & 7;
1021 +                ru_set_read(ru, Rn1);
1022 +                ru_set_read(ru, Du1);
1023 +                ru_set_read(ru, Dc1);
1024 +                ru_set_write(ru, Dc1);
1025 +                ext = comp_get_iword((m68k_pc_offset+=2)-2);
1026 +                Rn2 = (ext >> 12) & 15;
1027 +                Du2 = (ext >> 6) & 7;
1028 +                Dc2 = ext & 7;
1029 +                ru_set_read(ru, Rn2);
1030 +                ru_set_read(ru, Du2);
1031 +                ru_set_write(ru, Dc2);
1032 +                break;
1033 +        }
1034 +        case i_DIVL: case i_MULL:
1035 +                m68k_pc_offset += 2;
1036 +                break;
1037 +        case i_LEA:
1038 +        case i_MOVE: case i_MOVEA: case i_MOVE16:
1039 +                rw_dest = false;
1040 +                break;
1041 +        case i_PACK: case i_UNPK:
1042 +                rw_dest = false;
1043 +                m68k_pc_offset += 2;
1044 +                break;
1045 +        case i_TRAPcc:
1046 +                m68k_pc_offset += (dp->size == sz_long) ? 4 : 2;
1047 +                break;
1048 +        case i_RTR:
1049 +                /* do nothing, just for coverage debugging */
1050 +                break;
1051 +        /* TODO: handle EXG instruction */
1052 +        }
1053 +
1054 +        /* Handle A-Traps better */
1055 +        if ((real_opcode & 0xf000) == 0xa000) {
1056 +                handled = true;
1057 +        }
1058 +
1059 +        /* Handle EmulOps better */
1060 +        if ((real_opcode & 0xff00) == 0x7100) {
1061 +                handled = true;
1062 +                ru->rmask = 0xffff;
1063 +                ru->wmask = 0;
1064 +        }
1065 +
1066 +        if (dp->suse && !handled)
1067 +                ru_fill_ea(ru, dp->sreg, (amodes)dp->smode, (wordsizes)dp->size, 0);
1068 +
1069 +        if (dp->duse && !handled)
1070 +                ru_fill_ea(ru, dp->dreg, (amodes)dp->dmode, (wordsizes)dp->size, 1);
1071 +
1072 +        if (rw_dest)
1073 +                ru->rmask |= ru->wmask;
1074 +
1075 +        handled = handled || dp->suse || dp->duse;
1076 +
1077 +        /* Mark all registers as used/written if the instruction may trap */
1078 +        if (may_trap(opcode)) {
1079 +                handled = true;
1080 +                ru->rmask = 0xffff;
1081 +                ru->wmask = 0xffff;
1082 +        }
1083 +
1084 +        if (!handled) {
1085 +                write_log("ru_fill: %04x = { %04x, %04x }\n",
1086 +                                  real_opcode, ru->rmask, ru->wmask);
1087 +                abort();
1088 +        }
1089 + }
1090 +
1091 + /********************************************************************
1092   * register allocation per block logging                            *
1093   ********************************************************************/
1094  
# Line 770 | Line 1166 | static __inline__ void do_load_reg(int n
1166    else if (r == FLAGX)
1167          raw_load_flagx(n, r);
1168    else
1169 <        raw_mov_l_rm(n, (uae_u32) live.state[r].mem);
1169 >        raw_mov_l_rm(n, (uintptr) live.state[r].mem);
1170   }
1171  
1172   static __inline__ void check_load_reg(int n, int r)
1173   {
1174 <  raw_mov_l_rm(n, (uae_u32) live.state[r].mem);
1174 >  raw_mov_l_rm(n, (uintptr) live.state[r].mem);
1175   }
1176  
1177   static __inline__ void log_vwrite(int r)
# Line 886 | Line 1282 | static  void tomem(int r)
1282  
1283      if (live.state[r].status==DIRTY) {
1284          switch (live.state[r].dirtysize) {
1285 <         case 1: raw_mov_b_mr((uae_u32)live.state[r].mem,rr); break;
1286 <         case 2: raw_mov_w_mr((uae_u32)live.state[r].mem,rr); break;
1287 <         case 4: raw_mov_l_mr((uae_u32)live.state[r].mem,rr); break;
1285 >         case 1: raw_mov_b_mr((uintptr)live.state[r].mem,rr); break;
1286 >         case 2: raw_mov_w_mr((uintptr)live.state[r].mem,rr); break;
1287 >         case 4: raw_mov_l_mr((uintptr)live.state[r].mem,rr); break;
1288           default: abort();
1289          }
1290          log_vwrite(r);
# Line 916 | Line 1312 | static __inline__ void writeback_const(i
1312          abort();
1313      }
1314  
1315 <    raw_mov_l_mi((uae_u32)live.state[r].mem,live.state[r].val);
1315 >    raw_mov_l_mi((uintptr)live.state[r].mem,live.state[r].val);
1316          log_vwrite(r);
1317      live.state[r].val=0;
1318      set_status(r,INMEM);
# Line 1049 | Line 1445 | static  int alloc_reg_hinted(int r, int
1445          if (size==4 && live.state[r].validsize==2) {
1446                  log_isused(bestreg);
1447                  log_visused(r);
1448 <            raw_mov_l_rm(bestreg,(uae_u32)live.state[r].mem);
1448 >            raw_mov_l_rm(bestreg,(uintptr)live.state[r].mem);
1449              raw_bswap_32(bestreg);
1450              raw_zero_extend_16_rr(rr,rr);
1451              raw_zero_extend_16_rr(bestreg,bestreg);
# Line 1293 | Line 1689 | static __inline__ void remove_all_offset
1689          remove_offset(i,-1);
1690   }
1691  
1692 + static inline void flush_reg_count(void)
1693 + {
1694 + #if RECORD_REGISTER_USAGE
1695 +    for (int r = 0; r < 16; r++)
1696 +        if (reg_count_local[r])
1697 +            ADDQim(reg_count_local[r], ((uintptr)reg_count) + (8 * r), X86_NOREG, X86_NOREG, 1);
1698 + #endif
1699 + }
1700 +
1701 + static inline void record_register(int r)
1702 + {
1703 + #if RECORD_REGISTER_USAGE
1704 +    if (r < 16)
1705 +        reg_count_local[r]++;
1706 + #endif
1707 + }
1708 +
1709   static __inline__ int readreg_general(int r, int size, int spec, int can_offset)
1710   {
1711      int n;
1712      int answer=-1;
1713      
1714 +    record_register(r);
1715          if (live.state[r].status==UNDEF) {
1716                  write_log("WARNING: Unexpected read of undefined register %d\n",r);
1717          }
# Line 1374 | Line 1788 | static __inline__ int writereg_general(i
1788      int n;
1789      int answer=-1;
1790  
1791 +    record_register(r);
1792      if (size<4) {
1793          remove_offset(r,spec);
1794      }
# Line 1455 | Line 1870 | static __inline__ int rmw_general(int r,
1870      int n;
1871      int answer=-1;
1872      
1873 +    record_register(r);
1874          if (live.state[r].status==UNDEF) {
1875                  write_log("WARNING: Unexpected read of undefined register %d\n",r);
1876          }
# Line 1546 | Line 1962 | static  void f_tomem(int r)
1962   {
1963      if (live.fate[r].status==DIRTY) {
1964   #if USE_LONG_DOUBLE
1965 <        raw_fmov_ext_mr((uae_u32)live.fate[r].mem,live.fate[r].realreg);
1965 >        raw_fmov_ext_mr((uintptr)live.fate[r].mem,live.fate[r].realreg);
1966   #else
1967 <        raw_fmov_mr((uae_u32)live.fate[r].mem,live.fate[r].realreg);
1967 >        raw_fmov_mr((uintptr)live.fate[r].mem,live.fate[r].realreg);
1968   #endif
1969          live.fate[r].status=CLEAN;
1970      }
# Line 1558 | Line 1974 | static  void f_tomem_drop(int r)
1974   {
1975      if (live.fate[r].status==DIRTY) {
1976   #if USE_LONG_DOUBLE
1977 <        raw_fmov_ext_mr_drop((uae_u32)live.fate[r].mem,live.fate[r].realreg);
1977 >        raw_fmov_ext_mr_drop((uintptr)live.fate[r].mem,live.fate[r].realreg);
1978   #else
1979 <        raw_fmov_mr_drop((uae_u32)live.fate[r].mem,live.fate[r].realreg);
1979 >        raw_fmov_mr_drop((uintptr)live.fate[r].mem,live.fate[r].realreg);
1980   #endif
1981          live.fate[r].status=INMEM;
1982      }
# Line 1668 | Line 2084 | static  int f_alloc_reg(int r, int willc
2084      if (!willclobber) {
2085          if (live.fate[r].status!=UNDEF) {
2086   #if USE_LONG_DOUBLE
2087 <            raw_fmov_ext_rm(bestreg,(uae_u32)live.fate[r].mem);
2087 >            raw_fmov_ext_rm(bestreg,(uintptr)live.fate[r].mem);
2088   #else
2089 <            raw_fmov_rm(bestreg,(uae_u32)live.fate[r].mem);
2089 >            raw_fmov_rm(bestreg,(uintptr)live.fate[r].mem);
2090   #endif
2091          }
2092          live.fate[r].status=CLEAN;
# Line 1827 | Line 2243 | static void fflags_into_flags_internal(u
2243          else
2244      raw_fflags_into_flags(r);
2245      f_unlock(r);
2246 +    live_flags();
2247   }
2248  
2249  
# Line 1875 | Line 2292 | MIDFUNC(0,duplicate_carry,(void))
2292   {
2293      evict(FLAGX);
2294      make_flags_live_internal();
2295 <    COMPCALL(setcc_m)((uae_u32)live.state[FLAGX].mem,2);
2295 >    COMPCALL(setcc_m)((uintptr)live.state[FLAGX].mem,2);
2296          log_vwrite(FLAGX);
2297   }
2298   MENDFUNC(0,duplicate_carry,(void))
# Line 2562 | Line 2979 | MIDFUNC(3,cmov_l_rm,(RW4 d, IMM s, IMM c
2979   }
2980   MENDFUNC(3,cmov_l_rm,(RW4 d, IMM s, IMM cc))
2981  
2982 < MIDFUNC(2,bsf_l_rr,(W4 d, R4 s))
2982 > MIDFUNC(2,bsf_l_rr,(W4 d, W4 s))
2983   {
2984      CLOBBER_BSF;
2985 <    s=readreg(s,4);
2986 <    d=writereg(d,4);
2987 <    raw_bsf_l_rr(d,s);
2985 >    s = readreg(s, 4);
2986 >    d = writereg(d, 4);
2987 >    raw_bsf_l_rr(d, s);
2988      unlock2(s);
2989      unlock2(d);
2990   }
2991 < MENDFUNC(2,bsf_l_rr,(W4 d, R4 s))
2991 > MENDFUNC(2,bsf_l_rr,(W4 d, W4 s))
2992 >
2993 > /* Set the Z flag depending on the value in s. Note that the
2994 >   value has to be 0 or -1 (or, more precisely, for non-zero
2995 >   values, bit 14 must be set)! */
2996 > MIDFUNC(2,simulate_bsf,(W4 tmp, RW4 s))
2997 > {
2998 >    CLOBBER_BSF;
2999 >    s=rmw_specific(s,4,4,FLAG_NREG3);
3000 >    tmp=writereg(tmp,4);
3001 >    raw_flags_set_zero(s, tmp);
3002 >    unlock2(tmp);
3003 >    unlock2(s);
3004 > }
3005 > MENDFUNC(2,simulate_bsf,(W4 tmp, RW4 s))
3006  
3007   MIDFUNC(2,imul_32_32,(RW4 d, R4 s))
3008   {
# Line 2617 | Line 3048 | MIDFUNC(2,mul_32_32,(RW4 d, R4 s))
3048   }
3049   MENDFUNC(2,mul_32_32,(RW4 d, R4 s))
3050  
3051 + #if SIZEOF_VOID_P == 8
3052 + MIDFUNC(2,sign_extend_32_rr,(W4 d, R2 s))
3053 + {
3054 +    int isrmw;
3055 +
3056 +    if (isconst(s)) {
3057 +        set_const(d,(uae_s32)live.state[s].val);
3058 +        return;
3059 +    }
3060 +
3061 +    CLOBBER_SE32;
3062 +    isrmw=(s==d);
3063 +    if (!isrmw) {
3064 +        s=readreg(s,4);
3065 +        d=writereg(d,4);
3066 +    }
3067 +    else {  /* If we try to lock this twice, with different sizes, we
3068 +               are int trouble! */
3069 +        s=d=rmw(s,4,4);
3070 +    }
3071 +    raw_sign_extend_32_rr(d,s);
3072 +    if (!isrmw) {
3073 +        unlock2(d);
3074 +        unlock2(s);
3075 +    }
3076 +    else {
3077 +        unlock2(s);
3078 +    }
3079 + }
3080 + MENDFUNC(2,sign_extend_32_rr,(W4 d, R2 s))
3081 + #endif
3082 +
3083   MIDFUNC(2,sign_extend_16_rr,(W4 d, R2 s))
3084   {
3085      int isrmw;
# Line 4461 | Line 4924 | MENDFUNC(2,fmul_rr,(FRW d, FR s))
4924   * Support functions exposed to gencomp. CREATE time                *
4925   ********************************************************************/
4926  
4927 + void set_zero(int r, int tmp)
4928 + {
4929 +    if (setzflg_uses_bsf)
4930 +        bsf_l_rr(r,r);
4931 +    else
4932 +        simulate_bsf(tmp,r);
4933 + }
4934 +
4935   int kill_rodent(int r)
4936   {
4937      return KILLTHERAT &&
# Line 4509 | Line 4980 | static inline const char *str_on_off(boo
4980          return b ? "on" : "off";
4981   }
4982  
4512 static __inline__ unsigned int cft_map (unsigned int f)
4513 {
4514 #ifndef HAVE_GET_WORD_UNSWAPPED
4515    return f;
4516 #else
4517    return ((f >> 8) & 255) | ((f & 255) << 8);
4518 #endif
4519 }
4520
4983   void compiler_init(void)
4984   {
4985          static bool initialized = false;
4986          if (initialized)
4987                  return;
4988 <        
4527 < #ifndef WIN32
4528 <        // Open /dev/zero
4529 <        zero_fd = open("/dev/zero", O_RDWR);
4530 <        if (zero_fd < 0) {
4531 <                char str[200];
4532 <                sprintf(str, GetString(STR_NO_DEV_ZERO_ERR), strerror(errno));
4533 <                ErrorAlert(str);
4534 <                QuitEmulator();
4535 <        }
4536 < #endif
4537 <        
4988 >
4989   #if JIT_DEBUG
4990          // JIT debug mode ?
4991          JITDebug = PrefsFindBool("jitdebug");
# Line 4556 | Line 5007 | void compiler_init(void)
5007          
5008          // Initialize target CPU (check for features, e.g. CMOV, rat stalls)
5009          raw_init_cpu();
5010 +        setzflg_uses_bsf = target_check_bsf();
5011          write_log("<JIT compiler> : target processor has CMOV instructions : %s\n", have_cmov ? "yes" : "no");
5012          write_log("<JIT compiler> : target processor can suffer from partial register stalls : %s\n", have_rat_stall ? "yes" : "no");
5013 +        write_log("<JIT compiler> : alignment for loops, jumps are %d, %d\n", align_loops, align_jumps);
5014          
5015          // Translation cache flush mechanism
5016          lazy_flush = PrefsFindBool("jitlazyflush");
# Line 4568 | Line 5021 | void compiler_init(void)
5021          write_log("<JIT compiler> : register aliasing : %s\n", str_on_off(1));
5022          write_log("<JIT compiler> : FP register aliasing : %s\n", str_on_off(USE_F_ALIAS));
5023          write_log("<JIT compiler> : lazy constant offsetting : %s\n", str_on_off(USE_OFFSET));
5024 + #if USE_INLINING
5025 +        follow_const_jumps = PrefsFindBool("jitinline");
5026 + #endif
5027 +        write_log("<JIT compiler> : translate through constant jumps : %s\n", str_on_off(follow_const_jumps));
5028          write_log("<JIT compiler> : separate blockinfo allocation : %s\n", str_on_off(USE_SEPARATE_BIA));
5029          
5030          // Build compiler tables
# Line 4575 | Line 5032 | void compiler_init(void)
5032          
5033          initialized = true;
5034          
5035 + #if PROFILE_UNTRANSLATED_INSNS
5036 +        write_log("<JIT compiler> : gather statistics on untranslated insns count\n");
5037 + #endif
5038 +
5039   #if PROFILE_COMPILE_TIME
5040          write_log("<JIT compiler> : gather statistics on translation time\n");
5041          emul_start_time = clock();
# Line 4592 | Line 5053 | void compiler_exit(void)
5053                  vm_release(compiled_code, cache_size * 1024);
5054                  compiled_code = 0;
5055          }
5056 <        
5057 <        // Deallocate blockinfo pools
5058 <        free_blockinfo_pools();
5059 <        
5060 < #ifndef WIN32
5061 <        // Close /dev/zero
4601 <        if (zero_fd > 0)
4602 <                close(zero_fd);
4603 < #endif
5056 >
5057 >        // Deallocate popallspace
5058 >        if (popallspace) {
5059 >                vm_release(popallspace, POPALLSPACE_SIZE);
5060 >                popallspace = 0;
5061 >        }
5062          
5063   #if PROFILE_COMPILE_TIME
5064          write_log("### Compile Block statistics\n");
# Line 4611 | Line 5069 | void compiler_exit(void)
5069                  100.0*double(compile_time)/double(emul_time));
5070          write_log("\n");
5071   #endif
5072 +
5073 + #if PROFILE_UNTRANSLATED_INSNS
5074 +        uae_u64 untranslated_count = 0;
5075 +        for (int i = 0; i < 65536; i++) {
5076 +                opcode_nums[i] = i;
5077 +                untranslated_count += raw_cputbl_count[i];
5078 +        }
5079 +        write_log("Sorting out untranslated instructions count...\n");
5080 +        qsort(opcode_nums, 65536, sizeof(uae_u16), untranslated_compfn);
5081 +        write_log("\nRank  Opc      Count Name\n");
5082 +        for (int i = 0; i < untranslated_top_ten; i++) {
5083 +                uae_u32 count = raw_cputbl_count[opcode_nums[i]];
5084 +                struct instr *dp;
5085 +                struct mnemolookup *lookup;
5086 +                if (!count)
5087 +                        break;
5088 +                dp = table68k + opcode_nums[i];
5089 +                for (lookup = lookuptab; lookup->mnemo != dp->mnemo; lookup++)
5090 +                        ;
5091 +                write_log("%03d: %04x %10lu %s\n", i, opcode_nums[i], count, lookup->name);
5092 +        }
5093 + #endif
5094 +
5095 + #if RECORD_REGISTER_USAGE
5096 +        int reg_count_ids[16];
5097 +        uint64 tot_reg_count = 0;
5098 +        for (int i = 0; i < 16; i++) {
5099 +            reg_count_ids[i] = i;
5100 +            tot_reg_count += reg_count[i];
5101 +        }
5102 +        qsort(reg_count_ids, 16, sizeof(int), reg_count_compare);
5103 +        uint64 cum_reg_count = 0;
5104 +        for (int i = 0; i < 16; i++) {
5105 +            int r = reg_count_ids[i];
5106 +            cum_reg_count += reg_count[r];
5107 +            printf("%c%d : %16ld %2.1f%% [%2.1f]\n", r < 8 ? 'D' : 'A', r % 8,
5108 +                   reg_count[r],
5109 +                   100.0*double(reg_count[r])/double(tot_reg_count),
5110 +                   100.0*double(cum_reg_count)/double(tot_reg_count));
5111 +        }
5112 + #endif
5113   }
5114  
5115   bool compiler_use_jit(void)
# Line 4641 | Line 5140 | void init_comp(void)
5140      uae_s8* cw=can_word;
5141      uae_s8* au=always_used;
5142  
5143 + #if RECORD_REGISTER_USAGE
5144 +    for (i=0;i<16;i++)
5145 +        reg_count_local[i] = 0;
5146 + #endif
5147 +
5148      for (i=0;i<VREGS;i++) {
5149          live.state[i].realreg=-1;
5150          live.state[i].needflush=NF_SCRATCH;
# Line 4665 | Line 5169 | void init_comp(void)
5169      }
5170      live.state[PC_P].mem=(uae_u32*)&(regs.pc_p);
5171      live.state[PC_P].needflush=NF_TOMEM;
5172 <    set_const(PC_P,(uae_u32)comp_pc_p);
5172 >    set_const(PC_P,(uintptr)comp_pc_p);
5173  
5174 <    live.state[FLAGX].mem=&(regflags.x);
5174 >    live.state[FLAGX].mem=(uae_u32*)&(regflags.x);
5175      live.state[FLAGX].needflush=NF_TOMEM;
5176      set_status(FLAGX,INMEM);
5177          
5178 <    live.state[FLAGTMP].mem=&(regflags.cznv);
5178 >    live.state[FLAGTMP].mem=(uae_u32*)&(regflags.cznv);
5179      live.state[FLAGTMP].needflush=NF_TOMEM;
5180      set_status(FLAGTMP,INMEM);
5181  
# Line 4690 | Line 5194 | void init_comp(void)
5194              live.fate[i].status=INMEM;
5195          }
5196          else
5197 <            live.fate[i].mem=(uae_u32*)(scratch.fregs+i);
5197 >            live.fate[i].mem=(uae_u32*)(&scratch.fregs[i]);
5198      }
5199  
5200  
# Line 4745 | Line 5249 | void flush(int save_regs)
5249                  switch(live.state[i].status) {
5250                   case INMEM:  
5251                      if (live.state[i].val) {
5252 <                        raw_add_l_mi((uae_u32)live.state[i].mem,live.state[i].val);
5252 >                        raw_add_l_mi((uintptr)live.state[i].mem,live.state[i].val);
5253                          log_vwrite(i);
5254                          live.state[i].val=0;
5255                      }
# Line 4839 | Line 5343 | void freescratch(void)
5343  
5344   static void align_target(uae_u32 a)
5345   {
5346 <    /* Fill with NOPs --- makes debugging with gdb easier */
5347 <    while ((uae_u32)target&(a-1))
5348 <        *target++=0x90;
5346 >        if (!a)
5347 >                return;
5348 >
5349 >        if (tune_nop_fillers)
5350 >                raw_emit_nop_filler(a - (((uintptr)target) & (a - 1)));
5351 >        else {
5352 >                /* Fill with NOPs --- makes debugging with gdb easier */
5353 >                while ((uintptr)target&(a-1))
5354 >                        *target++=0x90;
5355 >        }
5356   }
5357  
5358   static __inline__ int isinrom(uintptr addr)
# Line 4907 | Line 5418 | void register_branch(uae_u32 not_taken,
5418   static uae_u32 get_handler_address(uae_u32 addr)
5419   {
5420      uae_u32 cl=cacheline(addr);
5421 <    blockinfo* bi=get_blockinfo_addr_new((void*)addr,0);
5422 <    return (uae_u32)&(bi->direct_handler_to_use);
5421 >    blockinfo* bi=get_blockinfo_addr_new((void*)(uintptr)addr,0);
5422 >    return (uintptr)&(bi->direct_handler_to_use);
5423   }
5424  
5425   static uae_u32 get_handler(uae_u32 addr)
5426   {
5427      uae_u32 cl=cacheline(addr);
5428 <    blockinfo* bi=get_blockinfo_addr_new((void*)addr,0);
5429 <    return (uae_u32)bi->direct_handler_to_use;
5428 >    blockinfo* bi=get_blockinfo_addr_new((void*)(uintptr)addr,0);
5429 >    return (uintptr)bi->direct_handler_to_use;
5430   }
5431  
5432   static void load_handler(int reg, uae_u32 addr)
# Line 4927 | Line 5438 | static void load_handler(int reg, uae_u3
5438   *  if that assumption is wrong! No branches, no second chances, just
5439   *  straight go-for-it attitude */
5440  
5441 < static void writemem_real(int address, int source, int offset, int size, int tmp, int clobber)
5441 > static void writemem_real(int address, int source, int size, int tmp, int clobber)
5442   {
5443      int f=tmp;
5444  
5445          if (clobber)
5446              f=source;
5447 +
5448 + #if SIZEOF_VOID_P == 8
5449 +        if (!ThirtyThreeBitAddressing)
5450 +                sign_extend_32_rr(address, address);
5451 + #endif
5452 +
5453          switch(size) {
5454           case 1: mov_b_bRr(address,source,MEMBaseDiff); break;
5455           case 2: mov_w_rr(f,source); bswap_16(f); mov_w_bRr(address,f,MEMBaseDiff); break;
# Line 4944 | Line 5461 | static void writemem_real(int address, i
5461  
5462   void writebyte(int address, int source, int tmp)
5463   {
5464 <        writemem_real(address,source,20,1,tmp,0);
5464 >        writemem_real(address,source,1,tmp,0);
5465   }
5466  
5467   static __inline__ void writeword_general(int address, int source, int tmp,
5468                                           int clobber)
5469   {
5470 <        writemem_real(address,source,16,2,tmp,clobber);
5470 >        writemem_real(address,source,2,tmp,clobber);
5471   }
5472  
5473   void writeword_clobber(int address, int source, int tmp)
# Line 4966 | Line 5483 | void writeword(int address, int source,
5483   static __inline__ void writelong_general(int address, int source, int tmp,
5484                                           int clobber)
5485   {
5486 <        writemem_real(address,source,12,4,tmp,clobber);
5486 >        writemem_real(address,source,4,tmp,clobber);
5487   }
5488  
5489   void writelong_clobber(int address, int source, int tmp)
# Line 4985 | Line 5502 | void writelong(int address, int source,
5502   *  if that assumption is wrong! No branches, no second chances, just
5503   *  straight go-for-it attitude */
5504  
5505 < static void readmem_real(int address, int dest, int offset, int size, int tmp)
5505 > static void readmem_real(int address, int dest, int size, int tmp)
5506   {
5507      int f=tmp;
5508  
5509      if (size==4 && address!=dest)
5510          f=dest;
5511  
5512 + #if SIZEOF_VOID_P == 8
5513 +        if (!ThirtyThreeBitAddressing)
5514 +                sign_extend_32_rr(address, address);
5515 + #endif
5516 +
5517          switch(size) {
5518           case 1: mov_b_brR(dest,address,MEMBaseDiff); break;
5519           case 2: mov_w_brR(dest,address,MEMBaseDiff); bswap_16(dest); break;
# Line 5002 | Line 5524 | static void readmem_real(int address, in
5524  
5525   void readbyte(int address, int dest, int tmp)
5526   {
5527 <        readmem_real(address,dest,8,1,tmp);
5527 >        readmem_real(address,dest,1,tmp);
5528   }
5529  
5530   void readword(int address, int dest, int tmp)
5531   {
5532 <        readmem_real(address,dest,4,2,tmp);
5532 >        readmem_real(address,dest,2,tmp);
5533   }
5534  
5535   void readlong(int address, int dest, int tmp)
5536   {
5537 <        readmem_real(address,dest,0,4,tmp);
5537 >        readmem_real(address,dest,4,tmp);
5538   }
5539  
5540   void get_n_addr(int address, int dest, int tmp)
# Line 5137 | Line 5659 | uae_u32 get_jitted_size(void)
5659      return 0;
5660   }
5661  
5662 + const int CODE_ALLOC_MAX_ATTEMPTS = 10;
5663 + const int CODE_ALLOC_BOUNDARIES   = 128 * 1024; // 128 KB
5664 +
5665 + static uint8 *do_alloc_code(uint32 size, int depth)
5666 + {
5667 + #if defined(__linux__) && 0
5668 +        /*
5669 +          This is a really awful hack that is known to work on Linux at
5670 +          least.
5671 +          
5672 +          The trick here is to make sure the allocated cache is nearby
5673 +          code segment, and more precisely in the positive half of a
5674 +          32-bit address space. i.e. addr < 0x80000000. Actually, it
5675 +          turned out that a 32-bit binary run on AMD64 yields a cache
5676 +          allocated around 0xa0000000, thus causing some troubles when
5677 +          translating addresses from m68k to x86.
5678 +        */
5679 +        static uint8 * code_base = NULL;
5680 +        if (code_base == NULL) {
5681 +                uintptr page_size = getpagesize();
5682 +                uintptr boundaries = CODE_ALLOC_BOUNDARIES;
5683 +                if (boundaries < page_size)
5684 +                        boundaries = page_size;
5685 +                code_base = (uint8 *)sbrk(0);
5686 +                for (int attempts = 0; attempts < CODE_ALLOC_MAX_ATTEMPTS; attempts++) {
5687 +                        if (vm_acquire_fixed(code_base, size) == 0) {
5688 +                                uint8 *code = code_base;
5689 +                                code_base += size;
5690 +                                return code;
5691 +                        }
5692 +                        code_base += boundaries;
5693 +                }
5694 +                return NULL;
5695 +        }
5696 +
5697 +        if (vm_acquire_fixed(code_base, size) == 0) {
5698 +                uint8 *code = code_base;
5699 +                code_base += size;
5700 +                return code;
5701 +        }
5702 +
5703 +        if (depth >= CODE_ALLOC_MAX_ATTEMPTS)
5704 +                return NULL;
5705 +
5706 +        return do_alloc_code(size, depth + 1);
5707 + #else
5708 +        uint8 *code = (uint8 *)vm_acquire(size);
5709 +        return code == VM_MAP_FAILED ? NULL : code;
5710 + #endif
5711 + }
5712 +
5713 + static inline uint8 *alloc_code(uint32 size)
5714 + {
5715 +        uint8 *ptr = do_alloc_code(size, 0);
5716 +        /* allocated code must fit in 32-bit boundaries */
5717 +        assert((uintptr)ptr <= 0xffffffff);
5718 +        return ptr;
5719 + }
5720 +
5721   void alloc_cache(void)
5722   {
5723          if (compiled_code) {
# Line 5149 | Line 5730 | void alloc_cache(void)
5730                  return;
5731          
5732          while (!compiled_code && cache_size) {
5733 <                if ((compiled_code = (uae_u8 *)vm_acquire(cache_size * 1024)) == VM_MAP_FAILED) {
5733 >                if ((compiled_code = alloc_code(cache_size * 1024)) == NULL) {
5734                          compiled_code = 0;
5735                          cache_size /= 2;
5736                  }
5737          }
5738 <        vm_protect(compiled_code, cache_size, VM_PAGE_READ | VM_PAGE_WRITE | VM_PAGE_EXECUTE);
5738 >        vm_protect(compiled_code, cache_size * 1024, VM_PAGE_READ | VM_PAGE_WRITE | VM_PAGE_EXECUTE);
5739          
5740          if (compiled_code) {
5741                  write_log("<JIT compiler> : actual translation cache size : %d KB at 0x%08X\n", cache_size, compiled_code);
# Line 5166 | Line 5747 | void alloc_cache(void)
5747  
5748  
5749  
5750 < extern cpuop_rettype op_illg_1 (uae_u32 opcode) REGPARAM;
5750 > extern void op_illg_1 (uae_u32 opcode) REGPARAM;
5751  
5752   static void calc_checksum(blockinfo* bi, uae_u32* c1, uae_u32* c2)
5753   {
5754 <    uae_u32 k1=0;
5755 <    uae_u32 k2=0;
5175 <    uae_s32 len=bi->len;
5176 <    uae_u32 tmp=bi->min_pcp;
5177 <    uae_u32* pos;
5754 >    uae_u32 k1 = 0;
5755 >    uae_u32 k2 = 0;
5756  
5757 <    len+=(tmp&3);
5758 <    tmp&=(~3);
5759 <    pos=(uae_u32*)tmp;
5757 > #if USE_CHECKSUM_INFO
5758 >    checksum_info *csi = bi->csi;
5759 >        Dif(!csi) abort();
5760 >        while (csi) {
5761 >                uae_s32 len = csi->length;
5762 >                uintptr tmp = (uintptr)csi->start_p;
5763 > #else
5764 >                uae_s32 len = bi->len;
5765 >                uintptr tmp = (uintptr)bi->min_pcp;
5766 > #endif
5767 >                uae_u32*pos;
5768  
5769 <    if (len<0 || len>MAX_CHECKSUM_LEN) {
5770 <        *c1=0;
5771 <        *c2=0;
5772 <    }
5773 <    else {
5774 <        while (len>0) {
5775 <            k1+=*pos;
5776 <            k2^=*pos;
5777 <            pos++;
5778 <            len-=4;
5769 >                len += (tmp & 3);
5770 >                tmp &= ~((uintptr)3);
5771 >                pos = (uae_u32 *)tmp;
5772 >
5773 >                if (len >= 0 && len <= MAX_CHECKSUM_LEN) {
5774 >                        while (len > 0) {
5775 >                                k1 += *pos;
5776 >                                k2 ^= *pos;
5777 >                                pos++;
5778 >                                len -= 4;
5779 >                        }
5780 >                }
5781 >
5782 > #if USE_CHECKSUM_INFO
5783 >                csi = csi->next;
5784          }
5785 <        *c1=k1;
5786 <        *c2=k2;
5787 <    }
5785 > #endif
5786 >
5787 >        *c1 = k1;
5788 >        *c2 = k2;
5789   }
5790  
5791 < static void show_checksum(blockinfo* bi)
5791 > #if 0
5792 > static void show_checksum(CSI_TYPE* csi)
5793   {
5794      uae_u32 k1=0;
5795      uae_u32 k2=0;
5796 <    uae_s32 len=bi->len;
5797 <    uae_u32 tmp=(uae_u32)bi->pc_p;
5796 >    uae_s32 len=CSI_LENGTH(csi);
5797 >    uae_u32 tmp=(uintptr)CSI_START_P(csi);
5798      uae_u32* pos;
5799  
5800      len+=(tmp&3);
# Line 5220 | Line 5813 | static void show_checksum(blockinfo* bi)
5813          write_log(" bla\n");
5814      }
5815   }
5816 + #endif
5817  
5818  
5819   int check_for_cache_miss(void)
# Line 5273 | Line 5867 | static int called_check_checksum(blockin
5867   static inline int block_check_checksum(blockinfo* bi)
5868   {
5869      uae_u32     c1,c2;
5870 <    int         isgood;
5870 >    bool        isgood;
5871      
5872      if (bi->status!=BI_NEED_CHECK)
5873          return 1;  /* This block is in a checked state */
5874      
5875      checksum_count++;
5876 +
5877      if (bi->c1 || bi->c2)
5878          calc_checksum(bi,&c1,&c2);
5879      else {
5880          c1=c2=1;  /* Make sure it doesn't match */
5881 <    }
5881 >        }
5882      
5883      isgood=(c1==bi->c1 && c2==bi->c2);
5884 +
5885      if (isgood) {
5886          /* This block is still OK. So we reactivate. Of course, that
5887             means we have to move it into the needs-to-be-flushed list */
# Line 5390 | Line 5986 | static __inline__ void match_states(bloc
5986      }
5987   }
5988  
5393 static uae_u8 popallspace[1024]; /* That should be enough space */
5394
5989   static __inline__ void create_popalls(void)
5990   {
5991    int i,r;
5992  
5993 +  if ((popallspace = alloc_code(POPALLSPACE_SIZE)) == NULL) {
5994 +          write_log("FATAL: Could not allocate popallspace!\n");
5995 +          abort();
5996 +  }
5997 +  vm_protect(popallspace, POPALLSPACE_SIZE, VM_PAGE_READ | VM_PAGE_WRITE);
5998 +
5999    current_compile_p=popallspace;
6000    set_target(current_compile_p);
6001   #if USE_PUSH_POP
# Line 5403 | Line 6003 | static __inline__ void create_popalls(vo
6003       registers before jumping back to the various get-out routines.
6004       This generates the code for it.
6005    */
6006 <  popall_do_nothing=current_compile_p;
6006 >  align_target(align_jumps);
6007 >  popall_do_nothing=get_target();
6008    for (i=0;i<N_REGS;i++) {
6009        if (need_to_preserve[i])
6010            raw_pop_l_r(i);
6011    }
6012 <  raw_jmp((uae_u32)do_nothing);
5412 <  align_target(32);
6012 >  raw_jmp((uintptr)do_nothing);
6013    
6014 +  align_target(align_jumps);
6015    popall_execute_normal=get_target();
6016    for (i=0;i<N_REGS;i++) {
6017        if (need_to_preserve[i])
6018            raw_pop_l_r(i);
6019    }
6020 <  raw_jmp((uae_u32)execute_normal);
5420 <  align_target(32);
6020 >  raw_jmp((uintptr)execute_normal);
6021  
6022 +  align_target(align_jumps);
6023    popall_cache_miss=get_target();
6024    for (i=0;i<N_REGS;i++) {
6025        if (need_to_preserve[i])
6026            raw_pop_l_r(i);
6027    }
6028 <  raw_jmp((uae_u32)cache_miss);
5428 <  align_target(32);
6028 >  raw_jmp((uintptr)cache_miss);
6029  
6030 +  align_target(align_jumps);
6031    popall_recompile_block=get_target();
6032    for (i=0;i<N_REGS;i++) {
6033        if (need_to_preserve[i])
6034            raw_pop_l_r(i);
6035    }
6036 <  raw_jmp((uae_u32)recompile_block);
6037 <  align_target(32);
6038 <  
6036 >  raw_jmp((uintptr)recompile_block);
6037 >
6038 >  align_target(align_jumps);
6039    popall_exec_nostats=get_target();
6040    for (i=0;i<N_REGS;i++) {
6041        if (need_to_preserve[i])
6042            raw_pop_l_r(i);
6043    }
6044 <  raw_jmp((uae_u32)exec_nostats);
6045 <  align_target(32);
6046 <  
6044 >  raw_jmp((uintptr)exec_nostats);
6045 >
6046 >  align_target(align_jumps);
6047    popall_check_checksum=get_target();
6048    for (i=0;i<N_REGS;i++) {
6049        if (need_to_preserve[i])
6050            raw_pop_l_r(i);
6051    }
6052 <  raw_jmp((uae_u32)check_checksum);
6053 <  align_target(32);
6054 <  
6052 >  raw_jmp((uintptr)check_checksum);
6053 >
6054 >  align_target(align_jumps);
6055    current_compile_p=get_target();
6056   #else
6057    popall_exec_nostats=(void *)exec_nostats;
# Line 5459 | Line 6060 | static __inline__ void create_popalls(vo
6060    popall_recompile_block=(void *)recompile_block;
6061    popall_do_nothing=(void *)do_nothing;
6062    popall_check_checksum=(void *)check_checksum;
5462  pushall_call_handler=get_target();  
6063   #endif
6064  
6065    /* And now, the code to do the matching pushes and then jump
# Line 5472 | Line 6072 | static __inline__ void create_popalls(vo
6072    }
6073   #endif
6074    r=REG_PC_TMP;
6075 <  raw_mov_l_rm(r,(uae_u32)&regs.pc_p);
6075 >  raw_mov_l_rm(r,(uintptr)&regs.pc_p);
6076    raw_and_l_ri(r,TAGMASK);
6077 <  raw_jmp_m_indexed((uae_u32)cache_tags,r,4);
6077 >  raw_jmp_m_indexed((uintptr)cache_tags,r,SIZEOF_VOID_P);
6078 >
6079 > #if defined(X86_ASSEMBLY) || defined(X86_64_ASSEMBLY)
6080 >  align_target(align_jumps);
6081 >  m68k_compile_execute = (void (*)(void))get_target();
6082 >  for (i=N_REGS;i--;) {
6083 >          if (need_to_preserve[i])
6084 >                  raw_push_l_r(i);
6085 >  }
6086 >  align_target(align_loops);
6087 >  uae_u32 dispatch_loop = (uintptr)get_target();
6088 >  r=REG_PC_TMP;
6089 >  raw_mov_l_rm(r,(uintptr)&regs.pc_p);
6090 >  raw_and_l_ri(r,TAGMASK);
6091 >  raw_call_m_indexed((uintptr)cache_tags,r,SIZEOF_VOID_P);
6092 >  raw_cmp_l_mi((uintptr)&regs.spcflags,0);
6093 >  raw_jcc_b_oponly(NATIVE_CC_EQ);
6094 >  emit_byte(dispatch_loop-((uintptr)get_target()+1));
6095 >  raw_call((uintptr)m68k_do_specialties);
6096 >  raw_test_l_rr(REG_RESULT,REG_RESULT);
6097 >  raw_jcc_b_oponly(NATIVE_CC_EQ);
6098 >  emit_byte(dispatch_loop-((uintptr)get_target()+1));
6099 >  raw_cmp_b_mi((uintptr)&quit_program,0);
6100 >  raw_jcc_b_oponly(NATIVE_CC_EQ);
6101 >  emit_byte(dispatch_loop-((uintptr)get_target()+1));
6102 >  for (i=0;i<N_REGS;i++) {
6103 >          if (need_to_preserve[i])
6104 >                  raw_pop_l_r(i);
6105 >  }
6106 >  raw_ret();
6107 > #endif
6108 >
6109 >  // no need to further write into popallspace
6110 >  vm_protect(popallspace, POPALLSPACE_SIZE, VM_PAGE_READ | VM_PAGE_EXECUTE);
6111   }
6112  
6113   static __inline__ void reset_lists(void)
# Line 5492 | Line 6125 | static void prepare_block(blockinfo* bi)
6125      int i;
6126  
6127      set_target(current_compile_p);
6128 <    align_target(32);
6128 >    align_target(align_jumps);
6129      bi->direct_pen=(cpuop_func *)get_target();
6130 <    raw_mov_l_rm(0,(uae_u32)&(bi->pc_p));
6131 <    raw_mov_l_mr((uae_u32)&regs.pc_p,0);
6132 <    raw_jmp((uae_u32)popall_execute_normal);
6130 >    raw_mov_l_rm(0,(uintptr)&(bi->pc_p));
6131 >    raw_mov_l_mr((uintptr)&regs.pc_p,0);
6132 >    raw_jmp((uintptr)popall_execute_normal);
6133  
6134 <    align_target(32);
6134 >    align_target(align_jumps);
6135      bi->direct_pcc=(cpuop_func *)get_target();
6136 <    raw_mov_l_rm(0,(uae_u32)&(bi->pc_p));
6137 <    raw_mov_l_mr((uae_u32)&regs.pc_p,0);
6138 <    raw_jmp((uae_u32)popall_check_checksum);
5506 <
5507 <    align_target(32);
6136 >    raw_mov_l_rm(0,(uintptr)&(bi->pc_p));
6137 >    raw_mov_l_mr((uintptr)&regs.pc_p,0);
6138 >    raw_jmp((uintptr)popall_check_checksum);
6139      current_compile_p=get_target();
6140  
6141      bi->deplist=NULL;
# Line 5518 | Line 6149 | static void prepare_block(blockinfo* bi)
6149      //bi->env=empty_ss;
6150   }
6151  
6152 + // OPCODE is in big endian format, use cft_map() beforehand, if needed.
6153 + static inline void reset_compop(int opcode)
6154 + {
6155 +        compfunctbl[opcode] = NULL;
6156 +        nfcompfunctbl[opcode] = NULL;
6157 + }
6158 +
6159 + static int read_opcode(const char *p)
6160 + {
6161 +        int opcode = 0;
6162 +        for (int i = 0; i < 4; i++) {
6163 +                int op = p[i];
6164 +                switch (op) {
6165 +                case '0': case '1': case '2': case '3': case '4':
6166 +                case '5': case '6': case '7': case '8': case '9':
6167 +                        opcode = (opcode << 4) | (op - '0');
6168 +                        break;
6169 +                case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
6170 +                        opcode = (opcode << 4) | ((op - 'a') + 10);
6171 +                        break;
6172 +                case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
6173 +                        opcode = (opcode << 4) | ((op - 'A') + 10);
6174 +                        break;
6175 +                default:
6176 +                        return -1;
6177 +                }
6178 +        }
6179 +        return opcode;
6180 + }
6181 +
6182 + static bool merge_blacklist()
6183 + {
6184 +        const char *blacklist = PrefsFindString("jitblacklist");
6185 +        if (blacklist) {
6186 +                const char *p = blacklist;
6187 +                for (;;) {
6188 +                        if (*p == 0)
6189 +                                return true;
6190 +
6191 +                        int opcode1 = read_opcode(p);
6192 +                        if (opcode1 < 0)
6193 +                                return false;
6194 +                        p += 4;
6195 +
6196 +                        int opcode2 = opcode1;
6197 +                        if (*p == '-') {
6198 +                                p++;
6199 +                                opcode2 = read_opcode(p);
6200 +                                if (opcode2 < 0)
6201 +                                        return false;
6202 +                                p += 4;
6203 +                        }
6204 +
6205 +                        if (*p == 0 || *p == ';') {
6206 +                                write_log("<JIT compiler> : blacklist opcodes : %04x-%04x\n", opcode1, opcode2);
6207 +                                for (int opcode = opcode1; opcode <= opcode2; opcode++)
6208 +                                        reset_compop(cft_map(opcode));
6209 +
6210 +                                if (*p++ == ';')
6211 +                                        continue;
6212 +
6213 +                                return true;
6214 +                        }
6215 +
6216 +                        return false;
6217 +                }
6218 +        }
6219 +        return true;
6220 + }
6221 +
6222   void build_comp(void)
6223   {
6224          int i;
# Line 5547 | Line 6248 | void build_comp(void)
6248      write_log ("<JIT compiler> : building compiler function tables\n");
6249          
6250          for (opcode = 0; opcode < 65536; opcode++) {
6251 +                reset_compop(opcode);
6252                  nfcpufunctbl[opcode] = op_illg_1;
5551                compfunctbl[opcode] = NULL;
5552                nfcompfunctbl[opcode] = NULL;
6253                  prop[opcode].use_flags = 0x1f;
6254                  prop[opcode].set_flags = 0x1f;
6255                  prop[opcode].cflow = fl_trap; // ILLEGAL instructions do trap
# Line 5557 | Line 6257 | void build_comp(void)
6257          
6258          for (i = 0; tbl[i].opcode < 65536; i++) {
6259                  int cflow = table68k[tbl[i].opcode].cflow;
6260 +                if (follow_const_jumps && (tbl[i].specific & 16))
6261 +                        cflow = fl_const_jump;
6262 +                else
6263 +                        cflow &= ~fl_const_jump;
6264                  prop[cft_map(tbl[i].opcode)].cflow = cflow;
6265  
6266                  int uses_fpu = tbl[i].specific & 32;
# Line 5605 | Line 6309 | void build_comp(void)
6309                  }
6310                  prop[cft_map(opcode)].set_flags = table68k[opcode].flagdead;
6311                  prop[cft_map(opcode)].use_flags = table68k[opcode].flaglive;
6312 +                /* Unconditional jumps don't evaluate condition codes, so they
6313 +                 * don't actually use any flags themselves */
6314 +                if (prop[cft_map(opcode)].cflow & fl_const_jump)
6315 +                        prop[cft_map(opcode)].use_flags = 0;
6316      }
6317          for (i = 0; nfctbl[i].handler != NULL; i++) {
6318                  if (nfctbl[i].specific)
6319                          nfcpufunctbl[cft_map(tbl[i].opcode)] = nfctbl[i].handler;
6320          }
6321  
6322 +        /* Merge in blacklist */
6323 +        if (!merge_blacklist())
6324 +                write_log("<JIT compiler> : blacklist merge failure!\n");
6325 +
6326      count=0;
6327      for (opcode = 0; opcode < 65536; opcode++) {
6328          if (compfunctbl[cft_map(opcode)])
# Line 5729 | Line 6441 | static inline void flush_icache_lazy(int
6441          active=NULL;
6442   }
6443  
6444 + void flush_icache_range(uae_u32 start, uae_u32 length)
6445 + {
6446 +        if (!active)
6447 +                return;
6448 +
6449 + #if LAZY_FLUSH_ICACHE_RANGE
6450 +        uae_u8 *start_p = get_real_address(start);
6451 +        blockinfo *bi = active;
6452 +        while (bi) {
6453 + #if USE_CHECKSUM_INFO
6454 +                bool invalidate = false;
6455 +                for (checksum_info *csi = bi->csi; csi && !invalidate; csi = csi->next)
6456 +                        invalidate = (((start_p - csi->start_p) < csi->length) ||
6457 +                                                  ((csi->start_p - start_p) < length));
6458 + #else
6459 +                // Assume system is consistent and would invalidate the right range
6460 +                const bool invalidate = (bi->pc_p - start_p) < length;
6461 + #endif
6462 +                if (invalidate) {
6463 +                        uae_u32 cl = cacheline(bi->pc_p);
6464 +                        if (bi == cache_tags[cl + 1].bi)
6465 +                                        cache_tags[cl].handler = (cpuop_func *)popall_execute_normal;
6466 +                        bi->handler_to_use = (cpuop_func *)popall_execute_normal;
6467 +                        set_dhtu(bi, bi->direct_pen);
6468 +                        bi->status = BI_NEED_RECOMP;
6469 +                }
6470 +                bi = bi->next;
6471 +        }
6472 +        return;
6473 + #endif
6474 +        flush_icache(-1);
6475 + }
6476 +
6477   static void catastrophe(void)
6478   {
6479      abort();
# Line 5739 | Line 6484 | int failure;
6484   #define TARGET_M68K             0
6485   #define TARGET_POWERPC  1
6486   #define TARGET_X86              2
6487 + #define TARGET_X86_64   3
6488   #if defined(i386) || defined(__i386__)
6489   #define TARGET_NATIVE   TARGET_X86
6490   #endif
6491   #if defined(powerpc) || defined(__powerpc__)
6492   #define TARGET_NATIVE   TARGET_POWERPC
6493   #endif
6494 + #if defined(x86_64) || defined(__x86_64__)
6495 + #define TARGET_NATIVE   TARGET_X86_64
6496 + #endif
6497  
6498   #ifdef ENABLE_MON
6499 < static uae_u32 mon_read_byte_jit(uae_u32 addr)
6499 > static uae_u32 mon_read_byte_jit(uintptr addr)
6500   {
6501          uae_u8 *m = (uae_u8 *)addr;
6502 <        return (uae_u32)(*m);
6502 >        return (uintptr)(*m);
6503   }
6504  
6505 < static void mon_write_byte_jit(uae_u32 addr, uae_u32 b)
6505 > static void mon_write_byte_jit(uintptr addr, uae_u32 b)
6506   {
6507          uae_u8 *m = (uae_u8 *)addr;
6508          *m = b;
# Line 5770 | Line 6519 | void disasm_block(int target, uint8 * st
6519          sprintf(disasm_str, "%s $%x $%x",
6520                          target == TARGET_M68K ? "d68" :
6521                          target == TARGET_X86 ? "d86" :
6522 +                        target == TARGET_X86_64 ? "d8664" :
6523                          target == TARGET_POWERPC ? "d" : "x",
6524                          start, start + length - 1);
6525          
6526 <        uae_u32 (*old_mon_read_byte)(uae_u32) = mon_read_byte;
6527 <        void (*old_mon_write_byte)(uae_u32, uae_u32) = mon_write_byte;
6526 >        uae_u32 (*old_mon_read_byte)(uintptr) = mon_read_byte;
6527 >        void (*old_mon_write_byte)(uintptr, uae_u32) = mon_write_byte;
6528          
6529          mon_read_byte = mon_read_byte_jit;
6530          mon_write_byte = mon_write_byte_jit;
# Line 5787 | Line 6537 | void disasm_block(int target, uint8 * st
6537   #endif
6538   }
6539  
6540 < static inline void disasm_native_block(uint8 *start, size_t length)
6540 > static void disasm_native_block(uint8 *start, size_t length)
6541   {
6542          disasm_block(TARGET_NATIVE, start, length);
6543   }
6544  
6545 < static inline void disasm_m68k_block(uint8 *start, size_t length)
6545 > static void disasm_m68k_block(uint8 *start, size_t length)
6546   {
6547          disasm_block(TARGET_M68K, start, length);
6548   }
# Line 5826 | Line 6576 | void compiler_dumpstate(void)
6576          
6577          write_log("### Block in Mac address space\n");
6578          write_log("M68K block   : %p\n",
6579 <                          (void *)get_virtual_address(last_regs_pc_p));
6579 >                          (void *)(uintptr)get_virtual_address(last_regs_pc_p));
6580          write_log("Native block : %p (%d bytes)\n",
6581 <                          (void *)get_virtual_address(last_compiled_block_addr),
6581 >                          (void *)(uintptr)get_virtual_address(last_compiled_block_addr),
6582                            get_blockinfo_addr(last_regs_pc_p)->direct_handler_size);
6583          write_log("\n");
6584   }
# Line 5850 | Line 6600 | static void compile_block(cpu_history* p
6600          int r;
6601          int was_comp=0;
6602          uae_u8 liveflags[MAXRUN+1];
6603 <        uae_u32 max_pcp=(uae_u32)pc_hist[0].location;
6604 <        uae_u32 min_pcp=max_pcp;
6603 > #if USE_CHECKSUM_INFO
6604 >        bool trace_in_rom = isinrom((uintptr)pc_hist[0].location);
6605 >        uintptr max_pcp=(uintptr)pc_hist[blocklen - 1].location;
6606 >        uintptr min_pcp=max_pcp;
6607 > #else
6608 >        uintptr max_pcp=(uintptr)pc_hist[0].location;
6609 >        uintptr min_pcp=max_pcp;
6610 > #endif
6611          uae_u32 cl=cacheline(pc_hist[0].location);
6612          void* specflags=(void*)&regs.spcflags;
6613          blockinfo* bi=NULL;
# Line 5890 | Line 6646 | static void compile_block(cpu_history* p
6646                  optlev++;
6647              bi->count=optcount[optlev]-1;
6648          }
6649 <        current_block_pc_p=(uae_u32)pc_hist[0].location;
6649 >        current_block_pc_p=(uintptr)pc_hist[0].location;
6650          
6651          remove_deps(bi); /* We are about to create new code */
6652          bi->optlevel=optlev;
6653          bi->pc_p=(uae_u8*)pc_hist[0].location;
6654 + #if USE_CHECKSUM_INFO
6655 +        free_checksum_info_chain(bi->csi);
6656 +        bi->csi = NULL;
6657 + #endif
6658          
6659          liveflags[blocklen]=0x1f; /* All flags needed afterwards */
6660          i=blocklen;
# Line 5902 | Line 6662 | static void compile_block(cpu_history* p
6662              uae_u16* currpcp=pc_hist[i].location;
6663              uae_u32 op=DO_GET_OPCODE(currpcp);
6664  
6665 <            if ((uae_u32)currpcp<min_pcp)
6666 <                min_pcp=(uae_u32)currpcp;
6667 <            if ((uae_u32)currpcp>max_pcp)
6668 <                max_pcp=(uae_u32)currpcp;
6665 > #if USE_CHECKSUM_INFO
6666 >                trace_in_rom = trace_in_rom && isinrom((uintptr)currpcp);
6667 >                if (follow_const_jumps && is_const_jump(op)) {
6668 >                        checksum_info *csi = alloc_checksum_info();
6669 >                        csi->start_p = (uae_u8 *)min_pcp;
6670 >                        csi->length = max_pcp - min_pcp + LONGEST_68K_INST;
6671 >                        csi->next = bi->csi;
6672 >                        bi->csi = csi;
6673 >                        max_pcp = (uintptr)currpcp;
6674 >                }
6675 >                min_pcp = (uintptr)currpcp;
6676 > #else
6677 >            if ((uintptr)currpcp<min_pcp)
6678 >                min_pcp=(uintptr)currpcp;
6679 >            if ((uintptr)currpcp>max_pcp)
6680 >                max_pcp=(uintptr)currpcp;
6681 > #endif
6682  
6683                  liveflags[i]=((liveflags[i+1]&
6684                                 (~prop[op].set_flags))|
# Line 5914 | Line 6687 | static void compile_block(cpu_history* p
6687                      liveflags[i]&= ~FLAG_Z;
6688          }
6689  
6690 + #if USE_CHECKSUM_INFO
6691 +        checksum_info *csi = alloc_checksum_info();
6692 +        csi->start_p = (uae_u8 *)min_pcp;
6693 +        csi->length = max_pcp - min_pcp + LONGEST_68K_INST;
6694 +        csi->next = bi->csi;
6695 +        bi->csi = csi;
6696 + #endif
6697 +
6698          bi->needed_flags=liveflags[0];
6699  
6700 <        align_target(32);
6700 >        align_target(align_loops);
6701          was_comp=0;
6702  
6703          bi->direct_handler=(cpuop_func *)get_target();
6704          set_dhtu(bi,bi->direct_handler);
6705          bi->status=BI_COMPILING;
6706 <        current_block_start_target=(uae_u32)get_target();
6706 >        current_block_start_target=(uintptr)get_target();
6707          
6708          log_startblock();
6709          
6710          if (bi->count>=0) { /* Need to generate countdown code */
6711 <            raw_mov_l_mi((uae_u32)&regs.pc_p,(uae_u32)pc_hist[0].location);
6712 <            raw_sub_l_mi((uae_u32)&(bi->count),1);
6713 <            raw_jl((uae_u32)popall_recompile_block);
6711 >            raw_mov_l_mi((uintptr)&regs.pc_p,(uintptr)pc_hist[0].location);
6712 >            raw_sub_l_mi((uintptr)&(bi->count),1);
6713 >            raw_jl((uintptr)popall_recompile_block);
6714          }
6715          if (optlev==0) { /* No need to actually translate */
6716              /* Execute normally without keeping stats */
6717 <            raw_mov_l_mi((uae_u32)&regs.pc_p,(uae_u32)pc_hist[0].location);
6718 <            raw_jmp((uae_u32)popall_exec_nostats);
6717 >            raw_mov_l_mi((uintptr)&regs.pc_p,(uintptr)pc_hist[0].location);
6718 >            raw_jmp((uintptr)popall_exec_nostats);
6719          }
6720          else {
6721              reg_alloc_run=0;
# Line 5946 | Line 6727 | static void compile_block(cpu_history* p
6727              init_comp();
6728              was_comp=1;
6729  
6730 + #ifdef USE_CPU_EMUL_SERVICES
6731 +            raw_sub_l_mi((uintptr)&emulated_ticks,blocklen);
6732 +            raw_jcc_b_oponly(NATIVE_CC_GT);
6733 +            uae_s8 *branchadd=(uae_s8*)get_target();
6734 +            emit_byte(0);
6735 +            raw_call((uintptr)cpu_do_check_ticks);
6736 +            *branchadd=(uintptr)get_target()-((uintptr)branchadd+1);
6737 + #endif
6738 +
6739   #if JIT_DEBUG
6740                  if (JITDebug) {
6741 <                        raw_mov_l_mi((uae_u32)&last_regs_pc_p,(uae_u32)pc_hist[0].location);
6742 <                        raw_mov_l_mi((uae_u32)&last_compiled_block_addr,(uae_u32)current_block_start_target);
6741 >                        raw_mov_l_mi((uintptr)&last_regs_pc_p,(uintptr)pc_hist[0].location);
6742 >                        raw_mov_l_mi((uintptr)&last_compiled_block_addr,current_block_start_target);
6743                  }
6744   #endif
6745                  
# Line 5967 | Line 6757 | static void compile_block(cpu_history* p
6757                      cputbl=cpufunctbl;
6758                      comptbl=compfunctbl;
6759                  }
6760 +
6761 + #if FLIGHT_RECORDER
6762 +                {
6763 +                    mov_l_ri(S1, get_virtual_address((uae_u8 *)(pc_hist[i].location)) | 1);
6764 +                    clobber_flags();
6765 +                    remove_all_offsets();
6766 +                    int arg = readreg_specific(S1,4,REG_PAR1);
6767 +                    prepare_for_call_1();
6768 +                    unlock2(arg);
6769 +                    prepare_for_call_2();
6770 +                    raw_call((uintptr)m68k_record_step);
6771 +                }
6772 + #endif
6773                  
6774                  failure = 1; // gb-- defaults to failure state
6775                  if (comptbl[opcode] && optlev>1) {
# Line 5975 | Line 6778 | static void compile_block(cpu_history* p
6778                          comp_pc_p=(uae_u8*)pc_hist[i].location;
6779                          init_comp();
6780                      }
6781 <                    was_comp++;
6781 >                    was_comp=1;
6782  
6783                      comptbl[opcode](opcode);
6784                      freescratch();
# Line 6000 | Line 6803 | static void compile_block(cpu_history* p
6803   #if USE_NORMAL_CALLING_CONVENTION
6804                      raw_push_l_r(REG_PAR1);
6805   #endif
6806 <                    raw_mov_l_mi((uae_u32)&regs.pc_p,
6807 <                                 (uae_u32)pc_hist[i].location);
6808 <                    raw_call((uae_u32)cputbl[opcode]);
6809 <                    //raw_add_l_mi((uae_u32)&oink,1); // FIXME
6806 >                    raw_mov_l_mi((uintptr)&regs.pc_p,
6807 >                                 (uintptr)pc_hist[i].location);
6808 >                    raw_call((uintptr)cputbl[opcode]);
6809 > #if PROFILE_UNTRANSLATED_INSNS
6810 >                        // raw_cputbl_count[] is indexed with plain opcode (in m68k order)
6811 >                        raw_add_l_mi((uintptr)&raw_cputbl_count[cft_map(opcode)],1);
6812 > #endif
6813   #if USE_NORMAL_CALLING_CONVENTION
6814                      raw_inc_sp(4);
6815   #endif
6010                    if (needed_flags) {
6011                        //raw_mov_l_mi((uae_u32)&foink3,(uae_u32)opcode+65536);
6012                    }
6013                    else {
6014                        //raw_mov_l_mi((uae_u32)&foink3,(uae_u32)opcode);
6015                    }
6816                      
6817                      if (i < blocklen - 1) {
6818                          uae_s8* branchadd;
6819                          
6820 <                        raw_mov_l_rm(0,(uae_u32)specflags);
6820 >                        raw_mov_l_rm(0,(uintptr)specflags);
6821                          raw_test_l_rr(0,0);
6822                          raw_jz_b_oponly();
6823                          branchadd=(uae_s8 *)get_target();
6824                          emit_byte(0);
6825 <                        raw_jmp((uae_u32)popall_do_nothing);
6826 <                        *branchadd=(uae_u32)get_target()-(uae_u32)branchadd-1;
6825 >                        raw_jmp((uintptr)popall_do_nothing);
6826 >                        *branchadd=(uintptr)get_target()-(uintptr)branchadd-1;
6827                      }
6828                  }
6829              }
# Line 6057 | Line 6857 | static void compile_block(cpu_history* p
6857                  log_flush();
6858  
6859              if (next_pc_p) { /* A branch was registered */
6860 <                uae_u32 t1=next_pc_p;
6861 <                uae_u32 t2=taken_pc_p;
6860 >                uintptr t1=next_pc_p;
6861 >                uintptr t2=taken_pc_p;
6862                  int     cc=branch_cc;
6863                  
6864                  uae_u32* branchadd;
# Line 6083 | Line 6883 | static void compile_block(cpu_history* p
6883                  /* predicted outcome */
6884                  tbi=get_blockinfo_addr_new((void*)t1,1);
6885                  match_states(tbi);
6886 <                raw_cmp_l_mi((uae_u32)specflags,0);
6886 >                raw_cmp_l_mi((uintptr)specflags,0);
6887                  raw_jcc_l_oponly(4);
6888                  tba=(uae_u32*)get_target();
6889 <                emit_long(get_handler(t1)-((uae_u32)tba+4));
6890 <                raw_mov_l_mi((uae_u32)&regs.pc_p,t1);
6891 <                raw_jmp((uae_u32)popall_do_nothing);
6889 >                emit_long(get_handler(t1)-((uintptr)tba+4));
6890 >                raw_mov_l_mi((uintptr)&regs.pc_p,t1);
6891 >                flush_reg_count();
6892 >                raw_jmp((uintptr)popall_do_nothing);
6893                  create_jmpdep(bi,0,tba,t1);
6894  
6895 <                align_target(16);
6895 >                align_target(align_jumps);
6896                  /* not-predicted outcome */
6897 <                *branchadd=(uae_u32)get_target()-((uae_u32)branchadd+4);
6897 >                *branchadd=(uintptr)get_target()-((uintptr)branchadd+4);
6898                  live=tmp; /* Ouch again */
6899                  tbi=get_blockinfo_addr_new((void*)t2,1);
6900                  match_states(tbi);
6901  
6902                  //flush(1); /* Can only get here if was_comp==1 */
6903 <                raw_cmp_l_mi((uae_u32)specflags,0);
6903 >                raw_cmp_l_mi((uintptr)specflags,0);
6904                  raw_jcc_l_oponly(4);
6905                  tba=(uae_u32*)get_target();
6906 <                emit_long(get_handler(t2)-((uae_u32)tba+4));
6907 <                raw_mov_l_mi((uae_u32)&regs.pc_p,t2);
6908 <                raw_jmp((uae_u32)popall_do_nothing);
6906 >                emit_long(get_handler(t2)-((uintptr)tba+4));
6907 >                raw_mov_l_mi((uintptr)&regs.pc_p,t2);
6908 >                flush_reg_count();
6909 >                raw_jmp((uintptr)popall_do_nothing);
6910                  create_jmpdep(bi,1,tba,t2);
6911              }          
6912              else
# Line 6112 | Line 6914 | static void compile_block(cpu_history* p
6914                  if (was_comp) {
6915                      flush(1);
6916                  }
6917 +                flush_reg_count();
6918                  
6919                  /* Let's find out where next_handler is... */
6920                  if (was_comp && isinreg(PC_P)) {
6921                      r=live.state[PC_P].realreg;
6922                          raw_and_l_ri(r,TAGMASK);
6923                          int r2 = (r==0) ? 1 : 0;
6924 <                        raw_mov_l_ri(r2,(uae_u32)popall_do_nothing);
6925 <                        raw_cmp_l_mi((uae_u32)specflags,0);
6926 <                        raw_cmov_l_rm_indexed(r2,(uae_u32)cache_tags,r,4,4);
6924 >                        raw_mov_l_ri(r2,(uintptr)popall_do_nothing);
6925 >                        raw_cmp_l_mi((uintptr)specflags,0);
6926 >                        raw_cmov_l_rm_indexed(r2,(uintptr)cache_tags,r,SIZEOF_VOID_P,NATIVE_CC_EQ);
6927                          raw_jmp_r(r2);
6928                  }
6929                  else if (was_comp && isconst(PC_P)) {
# Line 6128 | Line 6931 | static void compile_block(cpu_history* p
6931                      uae_u32* tba;
6932                      blockinfo* tbi;
6933  
6934 <                    tbi=get_blockinfo_addr_new((void*)v,1);
6934 >                    tbi=get_blockinfo_addr_new((void*)(uintptr)v,1);
6935                      match_states(tbi);
6936  
6937 <                        raw_cmp_l_mi((uae_u32)specflags,0);
6937 >                        raw_cmp_l_mi((uintptr)specflags,0);
6938                          raw_jcc_l_oponly(4);
6939                      tba=(uae_u32*)get_target();
6940 <                    emit_long(get_handler(v)-((uae_u32)tba+4));
6941 <                    raw_mov_l_mi((uae_u32)&regs.pc_p,v);
6942 <                    raw_jmp((uae_u32)popall_do_nothing);
6940 >                    emit_long(get_handler(v)-((uintptr)tba+4));
6941 >                    raw_mov_l_mi((uintptr)&regs.pc_p,v);
6942 >                    raw_jmp((uintptr)popall_do_nothing);
6943                      create_jmpdep(bi,0,tba,v);
6944                  }
6945                  else {
6946                      r=REG_PC_TMP;
6947 <                    raw_mov_l_rm(r,(uae_u32)&regs.pc_p);
6947 >                    raw_mov_l_rm(r,(uintptr)&regs.pc_p);
6948                          raw_and_l_ri(r,TAGMASK);
6949                          int r2 = (r==0) ? 1 : 0;
6950 <                        raw_mov_l_ri(r2,(uae_u32)popall_do_nothing);
6951 <                        raw_cmp_l_mi((uae_u32)specflags,0);
6952 <                        raw_cmov_l_rm_indexed(r2,(uae_u32)cache_tags,r,4,4);
6950 >                        raw_mov_l_ri(r2,(uintptr)popall_do_nothing);
6951 >                        raw_cmp_l_mi((uintptr)specflags,0);
6952 >                        raw_cmov_l_rm_indexed(r2,(uintptr)cache_tags,r,SIZEOF_VOID_P,NATIVE_CC_EQ);
6953                          raw_jmp_r(r2);
6954                  }
6955              }
# Line 6160 | Line 6963 | static void compile_block(cpu_history* p
6963          big_to_small_state(&live,&(bi->env));
6964   #endif
6965  
6966 + #if USE_CHECKSUM_INFO
6967 +        remove_from_list(bi);
6968 +        if (trace_in_rom) {
6969 +                // No need to checksum that block trace on cache invalidation
6970 +                free_checksum_info_chain(bi->csi);
6971 +                bi->csi = NULL;
6972 +                add_to_dormant(bi);
6973 +        }
6974 +        else {
6975 +            calc_checksum(bi,&(bi->c1),&(bi->c2));
6976 +                add_to_active(bi);
6977 +        }
6978 + #else
6979          if (next_pc_p+extra_len>=max_pcp &&
6980              next_pc_p+extra_len<max_pcp+LONGEST_68K_INST)
6981              max_pcp=next_pc_p+extra_len;  /* extra_len covers flags magic */
6982          else
6983              max_pcp+=LONGEST_68K_INST;
6984 +
6985          bi->len=max_pcp-min_pcp;
6986          bi->min_pcp=min_pcp;
6987 <                    
6987 >        
6988          remove_from_list(bi);
6989          if (isinrom(min_pcp) && isinrom(max_pcp)) {
6990              add_to_dormant(bi); /* No need to checksum it on cache flush.
# Line 6178 | Line 6995 | static void compile_block(cpu_history* p
6995              calc_checksum(bi,&(bi->c1),&(bi->c2));
6996              add_to_active(bi);
6997          }
6998 + #endif
6999          
7000          current_cache_size += get_target() - (uae_u8 *)current_compile_p;
7001          
# Line 6197 | Line 7015 | static void compile_block(cpu_history* p
7015   #endif
7016          
7017          log_dump();
7018 <        align_target(32);
7018 >        align_target(align_jumps);
7019  
7020          /* This is the non-direct handler */
7021          bi->handler=
7022              bi->handler_to_use=(cpuop_func *)get_target();
7023 <        raw_cmp_l_mi((uae_u32)&regs.pc_p,(uae_u32)pc_hist[0].location);
7024 <        raw_jnz((uae_u32)popall_cache_miss);
7023 >        raw_cmp_l_mi((uintptr)&regs.pc_p,(uintptr)pc_hist[0].location);
7024 >        raw_jnz((uintptr)popall_cache_miss);
7025          comp_pc_p=(uae_u8*)pc_hist[0].location;
7026  
7027          bi->status=BI_FINALIZING;
# Line 6211 | Line 7029 | static void compile_block(cpu_history* p
7029          match_states(bi);
7030          flush(1);
7031  
7032 <        raw_jmp((uae_u32)bi->direct_handler);
7032 >        raw_jmp((uintptr)bi->direct_handler);
7033  
6216        align_target(32);
7034          current_compile_p=get_target();
6218
7035          raise_in_cl_list(bi);
7036          
7037          /* We will flush soon, anyway, so let's do it now */
# Line 6230 | Line 7046 | static void compile_block(cpu_history* p
7046          compile_time += (clock() - start_time);
7047   #endif
7048      }
7049 +
7050 +    /* Account for compilation time */
7051 +    cpu_do_check_ticks();
7052   }
7053  
7054   void do_nothing(void)
# Line 6241 | Line 7060 | void exec_nostats(void)
7060   {
7061          for (;;)  {
7062                  uae_u32 opcode = GET_OPCODE;
7063 < #ifdef X86_ASSEMBLY__disable
7064 <                __asm__ __volatile__("\tpushl %%ebp\n\tcall *%%ebx\n\tpopl %%ebp" /* FIXME */
6246 <                                                         : : "b" (cpufunctbl[opcode]), "a" (opcode)
6247 <                                                         : "%edx", "%ecx", "%esi", "%edi",  "%ebp", "memory", "cc");
6248 < #else
6249 <                (*cpufunctbl[opcode])(opcode);
7063 > #if FLIGHT_RECORDER
7064 >                m68k_record_step(m68k_getpc());
7065   #endif
7066 +                (*cpufunctbl[opcode])(opcode);
7067 +                cpu_check_ticks();
7068                  if (end_block(opcode) || SPCFLAGS_TEST(SPCFLAG_ALL)) {
7069                          return; /* We will deal with the spcflags in the caller */
7070                  }
# Line 6272 | Line 7089 | void execute_normal(void)
7089   #if FLIGHT_RECORDER
7090                          m68k_record_step(m68k_getpc());
7091   #endif
6275 #ifdef X86_ASSEMBLY__disable
6276                        __asm__ __volatile__("\tpushl %%ebp\n\tcall *%%ebx\n\tpopl %%ebp" /* FIXME */
6277                                                                 : : "b" (cpufunctbl[opcode]), "a" (opcode)
6278                                                                 : "%edx", "%ecx", "%esi", "%edi", "%ebp", "memory", "cc");
6279 #else
7092                          (*cpufunctbl[opcode])(opcode);
7093 < #endif
7093 >                        cpu_check_ticks();
7094                          if (end_block(opcode) || SPCFLAGS_TEST(SPCFLAG_ALL) || blocklen>=MAXRUN) {
7095                                  compile_block(pc_hist, blocklen);
7096                                  return; /* We will deal with the spcflags in the caller */
# Line 6291 | Line 7103 | void execute_normal(void)
7103  
7104   typedef void (*compiled_handler)(void);
7105  
7106 + #if defined(X86_ASSEMBLY) || defined(X86_64_ASSEMBLY)
7107 + void (*m68k_compile_execute)(void) = NULL;
7108 + #else
7109   void m68k_do_compile_execute(void)
7110   {
7111          for (;;) {
6297 #ifdef X86_ASSEMBLY
6298                __asm__ __volatile__("\tpushl %%ebp\n\tcall *%%ebx\n\tpopl %%ebp" /* FIXME */
6299                                                         : : "b" (cache_tags[cacheline(regs.pc_p)].handler)
6300                                                         : "%edx", "%ecx", "%eax", "%esi", "%edi", "%ebp", "memory", "cc");
6301 #else
7112                  ((compiled_handler)(pushall_call_handler))();
6303 #endif
7113                  /* Whenever we return from that, we should check spcflags */
7114                  if (SPCFLAGS_TEST(SPCFLAG_ALL)) {
7115                          if (m68k_do_specialties ())
# Line 6308 | Line 7117 | void m68k_do_compile_execute(void)
7117                  }
7118          }
7119   }
7120 + #endif

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines