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.35 by gbeauche, 2006-01-15T22:42:51Z

# 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 > #if ! USE_PUSH_POP
136 > static void (*m68k_do_compile_execute)(void) = NULL;
137 > #endif
138 >
139 > static compop_func *compfunctbl[65536];
140 > static compop_func *nfcompfunctbl[65536];
141 > static cpuop_func *nfcpufunctbl[65536];
142   uae_u8* comp_pc_p;
143  
144 + // From main_unix.cpp
145 + extern bool ThirtyThreeBitAddressing;
146 +
147 + // From newcpu.cpp
148 + extern bool quit_program;
149 +
150   // gb-- Extra data for Basilisk II/JIT
151   #if JIT_DEBUG
152   static bool             JITDebug                        = false;        // Enable runtime disassemblers through mon?
153   #else
154   const bool              JITDebug                        = false;        // Don't use JIT debug mode at all
155   #endif
156 + #if USE_INLINING
157 + static bool             follow_const_jumps      = true;         // Flag: translation through constant jumps    
158 + #else
159 + const bool              follow_const_jumps      = false;
160 + #endif
161  
162 < const uae_u32   MIN_CACHE_SIZE          = 2048;         // Minimal translation cache size (2048 KB)
162 > const uae_u32   MIN_CACHE_SIZE          = 1024;         // Minimal translation cache size (1 MB)
163   static uae_u32  cache_size                      = 0;            // Size of total cache allocated for compiled blocks
164   static uae_u32  current_cache_size      = 0;            // Cache grows upwards: how much has been consumed already
165   static bool             lazy_flush                      = true;         // Flag: lazy translation cache invalidation
166   static bool             avoid_fpu                       = true;         // Flag: compile FPU instructions ?
167   static bool             have_cmov                       = false;        // target has CMOV instructions ?
168 + static bool             have_lahf_lm            = true;         // target has LAHF supported in long mode ?
169   static bool             have_rat_stall          = true;         // target has partial register stalls ?
170 < static int              zero_fd                         = -1;
170 > const bool              tune_alignment          = true;         // Tune code alignments for running CPU ?
171 > const bool              tune_nop_fillers        = true;         // Tune no-op fillers for architecture
172 > static bool             setzflg_uses_bsf        = false;        // setzflg virtual instruction can use native BSF instruction correctly?
173 > static int              align_loops                     = 32;           // Align the start of loops
174 > static int              align_jumps                     = 32;           // Align the start of jumps
175   static int              optcount[10]            = {
176          10,             // How often a block has to be executed before it is translated
177          0,              // How often to use naive translation
# Line 100 | Line 187 | struct op_properties {
187   };
188   static op_properties prop[65536];
189  
103 // gb-- Control Flow Predicates
104
190   static inline int end_block(uae_u32 opcode)
191   {
192          return (prop[opcode].cflow & fl_end_block);
193   }
194  
195 + static inline bool is_const_jump(uae_u32 opcode)
196 + {
197 +        return (prop[opcode].cflow == fl_const_jump);
198 + }
199 +
200   static inline bool may_trap(uae_u32 opcode)
201   {
202          return (prop[opcode].cflow & fl_trap);
203   }
204  
205 + static inline unsigned int cft_map (unsigned int f)
206 + {
207 + #ifndef HAVE_GET_WORD_UNSWAPPED
208 +    return f;
209 + #else
210 +    return ((f >> 8) & 255) | ((f & 255) << 8);
211 + #endif
212 + }
213 +
214   uae_u8* start_pc_p;
215   uae_u32 start_pc;
216   uae_u32 current_block_pc_p;
217 < uae_u32 current_block_start_target;
217 > static uintptr current_block_start_target;
218   uae_u32 needed_flags;
219 < static uae_u32 next_pc_p;
220 < static uae_u32 taken_pc_p;
219 > static uintptr next_pc_p;
220 > static uintptr taken_pc_p;
221   static int branch_cc;
222   static int redo_current_block;
223  
# Line 130 | Line 229 | static uae_u8* current_compile_p=NULL;
229   static uae_u8* max_compile_start;
230   static uae_u8* compiled_code=NULL;
231   static uae_s32 reg_alloc_run;
232 + const int POPALLSPACE_SIZE = 1024; /* That should be enough space */
233 + static uae_u8* popallspace=NULL;
234  
235   void* pushall_call_handler=NULL;
236   static void* popall_do_nothing=NULL;
# Line 139 | Line 240 | static void* popall_cache_miss=NULL;
240   static void* popall_recompile_block=NULL;
241   static void* popall_check_checksum=NULL;
242  
142 extern uae_u32 oink;
143 extern unsigned long foink3;
144 extern unsigned long foink;
145
243   /* The 68k only ever executes from even addresses. So right now, we
244   * waste half the entries in this array
245   * UPDATE: We now use those entries to store the start of the linked
# Line 389 | Line 486 | static __inline__ void invalidate_block(
486  
487   static __inline__ void create_jmpdep(blockinfo* bi, int i, uae_u32* jmpaddr, uae_u32 target)
488   {
489 <    blockinfo*  tbi=get_blockinfo_addr((void*)target);
489 >    blockinfo*  tbi=get_blockinfo_addr((void*)(uintptr)target);
490      
491      Dif(!tbi) {
492          write_log("Could not create jmpdep!\n");
# Line 487 | Line 584 | static void prepare_block(blockinfo* bi)
584     compiled. If the list of free blockinfos is empty, we allocate a new
585     pool of blockinfos and link the newly created blockinfos altogether
586     into the list of free blockinfos. Otherwise, we simply pop a structure
587 <   of the free list.
587 >   off the free list.
588  
589     Blockinfo are lazily deallocated, i.e. chained altogether in the
590     list of free blockinfos whenvever a translation cache flush (hard or
591     soft) request occurs.
592   */
593  
594 < #if USE_SEPARATE_BIA
595 < const int BLOCKINFO_POOL_SIZE = 128;
596 < struct blockinfo_pool {
597 <        blockinfo bi[BLOCKINFO_POOL_SIZE];
598 <        blockinfo_pool *next;
594 > template< class T >
595 > class LazyBlockAllocator
596 > {
597 >        enum {
598 >                kPoolSize = 1 + 4096 / sizeof(T)
599 >        };
600 >        struct Pool {
601 >                T chunk[kPoolSize];
602 >                Pool * next;
603 >        };
604 >        Pool * mPools;
605 >        T * mChunks;
606 > public:
607 >        LazyBlockAllocator() : mPools(0), mChunks(0) { }
608 >        ~LazyBlockAllocator();
609 >        T * acquire();
610 >        void release(T * const);
611   };
503 static blockinfo_pool * blockinfo_pools = 0;
504 static blockinfo *              free_blockinfos = 0;
505 #endif
612  
613 < static __inline__ blockinfo *alloc_blockinfo(void)
613 > template< class T >
614 > LazyBlockAllocator<T>::~LazyBlockAllocator()
615   {
616 < #if USE_SEPARATE_BIA
617 <        if (!free_blockinfos) {
618 <                // There is no blockinfo struct left, allocate a new
619 <                // pool and link the chunks into the free list
620 <                blockinfo_pool *bi_pool = (blockinfo_pool *)malloc(sizeof(blockinfo_pool));
621 <                for (blockinfo *bi = &bi_pool->bi[0]; bi < &bi_pool->bi[BLOCKINFO_POOL_SIZE]; bi++) {
622 <                        bi->next = free_blockinfos;
623 <                        free_blockinfos = bi;
616 >        Pool * currentPool = mPools;
617 >        while (currentPool) {
618 >                Pool * deadPool = currentPool;
619 >                currentPool = currentPool->next;
620 >                free(deadPool);
621 >        }
622 > }
623 >
624 > template< class T >
625 > T * LazyBlockAllocator<T>::acquire()
626 > {
627 >        if (!mChunks) {
628 >                // There is no chunk left, allocate a new pool and link the
629 >                // chunks into the free list
630 >                Pool * newPool = (Pool *)malloc(sizeof(Pool));
631 >                for (T * chunk = &newPool->chunk[0]; chunk < &newPool->chunk[kPoolSize]; chunk++) {
632 >                        chunk->next = mChunks;
633 >                        mChunks = chunk;
634                  }
635 <                bi_pool->next = blockinfo_pools;
636 <                blockinfo_pools = bi_pool;
635 >                newPool->next = mPools;
636 >                mPools = newPool;
637          }
638 <        blockinfo *bi = free_blockinfos;
639 <        free_blockinfos = bi->next;
640 < #else
524 <        blockinfo *bi = (blockinfo*)current_compile_p;
525 <        current_compile_p += sizeof(blockinfo);
526 < #endif
527 <        return bi;
638 >        T * chunk = mChunks;
639 >        mChunks = chunk->next;
640 >        return chunk;
641   }
642  
643 < static __inline__ void free_blockinfo(blockinfo *bi)
643 > template< class T >
644 > void LazyBlockAllocator<T>::release(T * const chunk)
645 > {
646 >        chunk->next = mChunks;
647 >        mChunks = chunk;
648 > }
649 >
650 > template< class T >
651 > class HardBlockAllocator
652   {
653 + public:
654 +        T * acquire() {
655 +                T * data = (T *)current_compile_p;
656 +                current_compile_p += sizeof(T);
657 +                return data;
658 +        }
659 +
660 +        void release(T * const chunk) {
661 +                // Deallocated on invalidation
662 +        }
663 + };
664 +
665   #if USE_SEPARATE_BIA
666 <        bi->next = free_blockinfos;
667 <        free_blockinfos = bi;
666 > static LazyBlockAllocator<blockinfo> BlockInfoAllocator;
667 > static LazyBlockAllocator<checksum_info> ChecksumInfoAllocator;
668 > #else
669 > static HardBlockAllocator<blockinfo> BlockInfoAllocator;
670 > static HardBlockAllocator<checksum_info> ChecksumInfoAllocator;
671   #endif
672 +
673 + static __inline__ checksum_info *alloc_checksum_info(void)
674 + {
675 +        checksum_info *csi = ChecksumInfoAllocator.acquire();
676 +        csi->next = NULL;
677 +        return csi;
678   }
679  
680 < static void free_blockinfo_pools(void)
680 > static __inline__ void free_checksum_info(checksum_info *csi)
681   {
682 < #if USE_SEPARATE_BIA
683 <        int blockinfo_pool_count = 0;
684 <        blockinfo_pool *curr_pool = blockinfo_pools;
685 <        while (curr_pool) {
686 <                blockinfo_pool_count++;
687 <                blockinfo_pool *dead_pool = curr_pool;
688 <                curr_pool = curr_pool->next;
689 <                free(dead_pool);
682 >        csi->next = NULL;
683 >        ChecksumInfoAllocator.release(csi);
684 > }
685 >
686 > static __inline__ void free_checksum_info_chain(checksum_info *csi)
687 > {
688 >        while (csi != NULL) {
689 >                checksum_info *csi2 = csi->next;
690 >                free_checksum_info(csi);
691 >                csi = csi2;
692          }
693 <        
694 <        uae_u32 blockinfo_pools_size = blockinfo_pool_count * BLOCKINFO_POOL_SIZE * sizeof(blockinfo);
695 <        write_log("### Blockinfo allocation statistics\n");
696 <        write_log("Number of blockinfo pools  : %d\n", blockinfo_pool_count);
697 <        write_log("Total number of blockinfos : %d (%d KB)\n",
698 <                          blockinfo_pool_count * BLOCKINFO_POOL_SIZE,
699 <                          blockinfo_pools_size / 1024);
700 <        write_log("\n");
693 > }
694 >
695 > static __inline__ blockinfo *alloc_blockinfo(void)
696 > {
697 >        blockinfo *bi = BlockInfoAllocator.acquire();
698 > #if USE_CHECKSUM_INFO
699 >        bi->csi = NULL;
700 > #endif
701 >        return bi;
702 > }
703 >
704 > static __inline__ void free_blockinfo(blockinfo *bi)
705 > {
706 > #if USE_CHECKSUM_INFO
707 >        free_checksum_info_chain(bi->csi);
708 >        bi->csi = NULL;
709   #endif
710 +        BlockInfoAllocator.release(bi);
711   }
712  
713   static __inline__ void alloc_blockinfos(void)
# Line 597 | Line 750 | static __inline__ void emit_long(uae_u32
750      target+=4;
751   }
752  
753 + static __inline__ void emit_quad(uae_u64 x)
754 + {
755 +    *((uae_u64*)target)=x;
756 +    target+=8;
757 + }
758 +
759 + static __inline__ void emit_block(const uae_u8 *block, uae_u32 blocklen)
760 + {
761 +        memcpy((uae_u8 *)target,block,blocklen);
762 +        target+=blocklen;
763 + }
764 +
765   static __inline__ uae_u32 reverse32(uae_u32 v)
766   {
767   #if 1
# Line 693 | Line 858 | static __inline__ void flush_flags(void)
858   int touchcnt;
859  
860   /********************************************************************
861 + * Partial register flushing for optimized calls                    *
862 + ********************************************************************/
863 +
864 + struct regusage {
865 +        uae_u16 rmask;
866 +        uae_u16 wmask;
867 + };
868 +
869 + static inline void ru_set(uae_u16 *mask, int reg)
870 + {
871 + #if USE_OPTIMIZED_CALLS
872 +        *mask |= 1 << reg;
873 + #endif
874 + }
875 +
876 + static inline bool ru_get(const uae_u16 *mask, int reg)
877 + {
878 + #if USE_OPTIMIZED_CALLS
879 +        return (*mask & (1 << reg));
880 + #else
881 +        /* Default: instruction reads & write to register */
882 +        return true;
883 + #endif
884 + }
885 +
886 + static inline void ru_set_read(regusage *ru, int reg)
887 + {
888 +        ru_set(&ru->rmask, reg);
889 + }
890 +
891 + static inline void ru_set_write(regusage *ru, int reg)
892 + {
893 +        ru_set(&ru->wmask, reg);
894 + }
895 +
896 + static inline bool ru_read_p(const regusage *ru, int reg)
897 + {
898 +        return ru_get(&ru->rmask, reg);
899 + }
900 +
901 + static inline bool ru_write_p(const regusage *ru, int reg)
902 + {
903 +        return ru_get(&ru->wmask, reg);
904 + }
905 +
906 + static void ru_fill_ea(regusage *ru, int reg, amodes mode,
907 +                                           wordsizes size, int write_mode)
908 + {
909 +        switch (mode) {
910 +        case Areg:
911 +                reg += 8;
912 +                /* fall through */
913 +        case Dreg:
914 +                ru_set(write_mode ? &ru->wmask : &ru->rmask, reg);
915 +                break;
916 +        case Ad16:
917 +                /* skip displacment */
918 +                m68k_pc_offset += 2;
919 +        case Aind:
920 +        case Aipi:
921 +        case Apdi:
922 +                ru_set_read(ru, reg+8);
923 +                break;
924 +        case Ad8r:
925 +                ru_set_read(ru, reg+8);
926 +                /* fall through */
927 +        case PC8r: {
928 +                uae_u16 dp = comp_get_iword((m68k_pc_offset+=2)-2);
929 +                reg = (dp >> 12) & 15;
930 +                ru_set_read(ru, reg);
931 +                if (dp & 0x100)
932 +                        m68k_pc_offset += (((dp & 0x30) >> 3) & 7) + ((dp & 3) * 2);
933 +                break;
934 +        }
935 +        case PC16:
936 +        case absw:
937 +        case imm0:
938 +        case imm1:
939 +                m68k_pc_offset += 2;
940 +                break;
941 +        case absl:
942 +        case imm2:
943 +                m68k_pc_offset += 4;
944 +                break;
945 +        case immi:
946 +                m68k_pc_offset += (size == sz_long) ? 4 : 2;
947 +                break;
948 +        }
949 + }
950 +
951 + /* TODO: split into a static initialization part and a dynamic one
952 +   (instructions depending on extension words) */
953 + static void ru_fill(regusage *ru, uae_u32 opcode)
954 + {
955 +        m68k_pc_offset += 2;
956 +
957 +        /* Default: no register is used or written to */
958 +        ru->rmask = 0;
959 +        ru->wmask = 0;
960 +
961 +        uae_u32 real_opcode = cft_map(opcode);
962 +        struct instr *dp = &table68k[real_opcode];
963 +
964 +        bool rw_dest = true;
965 +        bool handled = false;
966 +
967 +        /* Handle some instructions specifically */
968 +        uae_u16 reg, ext;
969 +        switch (dp->mnemo) {
970 +        case i_BFCHG:
971 +        case i_BFCLR:
972 +        case i_BFEXTS:
973 +        case i_BFEXTU:
974 +        case i_BFFFO:
975 +        case i_BFINS:
976 +        case i_BFSET:
977 +        case i_BFTST:
978 +                ext = comp_get_iword((m68k_pc_offset+=2)-2);
979 +                if (ext & 0x800) ru_set_read(ru, (ext >> 6) & 7);
980 +                if (ext & 0x020) ru_set_read(ru, ext & 7);
981 +                ru_fill_ea(ru, dp->dreg, (amodes)dp->dmode, (wordsizes)dp->size, 1);
982 +                if (dp->dmode == Dreg)
983 +                        ru_set_read(ru, dp->dreg);
984 +                switch (dp->mnemo) {
985 +                case i_BFEXTS:
986 +                case i_BFEXTU:
987 +                case i_BFFFO:
988 +                        ru_set_write(ru, (ext >> 12) & 7);
989 +                        break;
990 +                case i_BFINS:
991 +                        ru_set_read(ru, (ext >> 12) & 7);
992 +                        /* fall through */
993 +                case i_BFCHG:
994 +                case i_BFCLR:
995 +                case i_BSET:
996 +                        if (dp->dmode == Dreg)
997 +                                ru_set_write(ru, dp->dreg);
998 +                        break;
999 +                }
1000 +                handled = true;
1001 +                rw_dest = false;
1002 +                break;
1003 +
1004 +        case i_BTST:
1005 +                rw_dest = false;
1006 +                break;
1007 +
1008 +        case i_CAS:
1009 +        {
1010 +                ext = comp_get_iword((m68k_pc_offset+=2)-2);
1011 +                int Du = ext & 7;
1012 +                ru_set_read(ru, Du);
1013 +                int Dc = (ext >> 6) & 7;
1014 +                ru_set_read(ru, Dc);
1015 +                ru_set_write(ru, Dc);
1016 +                break;
1017 +        }
1018 +        case i_CAS2:
1019 +        {
1020 +                int Dc1, Dc2, Du1, Du2, Rn1, Rn2;
1021 +                ext = comp_get_iword((m68k_pc_offset+=2)-2);
1022 +                Rn1 = (ext >> 12) & 15;
1023 +                Du1 = (ext >> 6) & 7;
1024 +                Dc1 = ext & 7;
1025 +                ru_set_read(ru, Rn1);
1026 +                ru_set_read(ru, Du1);
1027 +                ru_set_read(ru, Dc1);
1028 +                ru_set_write(ru, Dc1);
1029 +                ext = comp_get_iword((m68k_pc_offset+=2)-2);
1030 +                Rn2 = (ext >> 12) & 15;
1031 +                Du2 = (ext >> 6) & 7;
1032 +                Dc2 = ext & 7;
1033 +                ru_set_read(ru, Rn2);
1034 +                ru_set_read(ru, Du2);
1035 +                ru_set_write(ru, Dc2);
1036 +                break;
1037 +        }
1038 +        case i_DIVL: case i_MULL:
1039 +                m68k_pc_offset += 2;
1040 +                break;
1041 +        case i_LEA:
1042 +        case i_MOVE: case i_MOVEA: case i_MOVE16:
1043 +                rw_dest = false;
1044 +                break;
1045 +        case i_PACK: case i_UNPK:
1046 +                rw_dest = false;
1047 +                m68k_pc_offset += 2;
1048 +                break;
1049 +        case i_TRAPcc:
1050 +                m68k_pc_offset += (dp->size == sz_long) ? 4 : 2;
1051 +                break;
1052 +        case i_RTR:
1053 +                /* do nothing, just for coverage debugging */
1054 +                break;
1055 +        /* TODO: handle EXG instruction */
1056 +        }
1057 +
1058 +        /* Handle A-Traps better */
1059 +        if ((real_opcode & 0xf000) == 0xa000) {
1060 +                handled = true;
1061 +        }
1062 +
1063 +        /* Handle EmulOps better */
1064 +        if ((real_opcode & 0xff00) == 0x7100) {
1065 +                handled = true;
1066 +                ru->rmask = 0xffff;
1067 +                ru->wmask = 0;
1068 +        }
1069 +
1070 +        if (dp->suse && !handled)
1071 +                ru_fill_ea(ru, dp->sreg, (amodes)dp->smode, (wordsizes)dp->size, 0);
1072 +
1073 +        if (dp->duse && !handled)
1074 +                ru_fill_ea(ru, dp->dreg, (amodes)dp->dmode, (wordsizes)dp->size, 1);
1075 +
1076 +        if (rw_dest)
1077 +                ru->rmask |= ru->wmask;
1078 +
1079 +        handled = handled || dp->suse || dp->duse;
1080 +
1081 +        /* Mark all registers as used/written if the instruction may trap */
1082 +        if (may_trap(opcode)) {
1083 +                handled = true;
1084 +                ru->rmask = 0xffff;
1085 +                ru->wmask = 0xffff;
1086 +        }
1087 +
1088 +        if (!handled) {
1089 +                write_log("ru_fill: %04x = { %04x, %04x }\n",
1090 +                                  real_opcode, ru->rmask, ru->wmask);
1091 +                abort();
1092 +        }
1093 + }
1094 +
1095 + /********************************************************************
1096   * register allocation per block logging                            *
1097   ********************************************************************/
1098  
# Line 770 | Line 1170 | static __inline__ void do_load_reg(int n
1170    else if (r == FLAGX)
1171          raw_load_flagx(n, r);
1172    else
1173 <        raw_mov_l_rm(n, (uae_u32) live.state[r].mem);
1173 >        raw_mov_l_rm(n, (uintptr) live.state[r].mem);
1174   }
1175  
1176   static __inline__ void check_load_reg(int n, int r)
1177   {
1178 <  raw_mov_l_rm(n, (uae_u32) live.state[r].mem);
1178 >  raw_mov_l_rm(n, (uintptr) live.state[r].mem);
1179   }
1180  
1181   static __inline__ void log_vwrite(int r)
# Line 886 | Line 1286 | static  void tomem(int r)
1286  
1287      if (live.state[r].status==DIRTY) {
1288          switch (live.state[r].dirtysize) {
1289 <         case 1: raw_mov_b_mr((uae_u32)live.state[r].mem,rr); break;
1290 <         case 2: raw_mov_w_mr((uae_u32)live.state[r].mem,rr); break;
1291 <         case 4: raw_mov_l_mr((uae_u32)live.state[r].mem,rr); break;
1289 >         case 1: raw_mov_b_mr((uintptr)live.state[r].mem,rr); break;
1290 >         case 2: raw_mov_w_mr((uintptr)live.state[r].mem,rr); break;
1291 >         case 4: raw_mov_l_mr((uintptr)live.state[r].mem,rr); break;
1292           default: abort();
1293          }
1294          log_vwrite(r);
# Line 916 | Line 1316 | static __inline__ void writeback_const(i
1316          abort();
1317      }
1318  
1319 <    raw_mov_l_mi((uae_u32)live.state[r].mem,live.state[r].val);
1319 >    raw_mov_l_mi((uintptr)live.state[r].mem,live.state[r].val);
1320          log_vwrite(r);
1321      live.state[r].val=0;
1322      set_status(r,INMEM);
# Line 1049 | Line 1449 | static  int alloc_reg_hinted(int r, int
1449          if (size==4 && live.state[r].validsize==2) {
1450                  log_isused(bestreg);
1451                  log_visused(r);
1452 <            raw_mov_l_rm(bestreg,(uae_u32)live.state[r].mem);
1452 >            raw_mov_l_rm(bestreg,(uintptr)live.state[r].mem);
1453              raw_bswap_32(bestreg);
1454              raw_zero_extend_16_rr(rr,rr);
1455              raw_zero_extend_16_rr(bestreg,bestreg);
# Line 1293 | Line 1693 | static __inline__ void remove_all_offset
1693          remove_offset(i,-1);
1694   }
1695  
1696 + static inline void flush_reg_count(void)
1697 + {
1698 + #if RECORD_REGISTER_USAGE
1699 +    for (int r = 0; r < 16; r++)
1700 +        if (reg_count_local[r])
1701 +            ADDQim(reg_count_local[r], ((uintptr)reg_count) + (8 * r), X86_NOREG, X86_NOREG, 1);
1702 + #endif
1703 + }
1704 +
1705 + static inline void record_register(int r)
1706 + {
1707 + #if RECORD_REGISTER_USAGE
1708 +    if (r < 16)
1709 +        reg_count_local[r]++;
1710 + #endif
1711 + }
1712 +
1713   static __inline__ int readreg_general(int r, int size, int spec, int can_offset)
1714   {
1715      int n;
1716      int answer=-1;
1717      
1718 +    record_register(r);
1719          if (live.state[r].status==UNDEF) {
1720                  write_log("WARNING: Unexpected read of undefined register %d\n",r);
1721          }
# Line 1374 | Line 1792 | static __inline__ int writereg_general(i
1792      int n;
1793      int answer=-1;
1794  
1795 +    record_register(r);
1796      if (size<4) {
1797          remove_offset(r,spec);
1798      }
# Line 1455 | Line 1874 | static __inline__ int rmw_general(int r,
1874      int n;
1875      int answer=-1;
1876      
1877 +    record_register(r);
1878          if (live.state[r].status==UNDEF) {
1879                  write_log("WARNING: Unexpected read of undefined register %d\n",r);
1880          }
# Line 1546 | Line 1966 | static  void f_tomem(int r)
1966   {
1967      if (live.fate[r].status==DIRTY) {
1968   #if USE_LONG_DOUBLE
1969 <        raw_fmov_ext_mr((uae_u32)live.fate[r].mem,live.fate[r].realreg);
1969 >        raw_fmov_ext_mr((uintptr)live.fate[r].mem,live.fate[r].realreg);
1970   #else
1971 <        raw_fmov_mr((uae_u32)live.fate[r].mem,live.fate[r].realreg);
1971 >        raw_fmov_mr((uintptr)live.fate[r].mem,live.fate[r].realreg);
1972   #endif
1973          live.fate[r].status=CLEAN;
1974      }
# Line 1558 | Line 1978 | static  void f_tomem_drop(int r)
1978   {
1979      if (live.fate[r].status==DIRTY) {
1980   #if USE_LONG_DOUBLE
1981 <        raw_fmov_ext_mr_drop((uae_u32)live.fate[r].mem,live.fate[r].realreg);
1981 >        raw_fmov_ext_mr_drop((uintptr)live.fate[r].mem,live.fate[r].realreg);
1982   #else
1983 <        raw_fmov_mr_drop((uae_u32)live.fate[r].mem,live.fate[r].realreg);
1983 >        raw_fmov_mr_drop((uintptr)live.fate[r].mem,live.fate[r].realreg);
1984   #endif
1985          live.fate[r].status=INMEM;
1986      }
# Line 1668 | Line 2088 | static  int f_alloc_reg(int r, int willc
2088      if (!willclobber) {
2089          if (live.fate[r].status!=UNDEF) {
2090   #if USE_LONG_DOUBLE
2091 <            raw_fmov_ext_rm(bestreg,(uae_u32)live.fate[r].mem);
2091 >            raw_fmov_ext_rm(bestreg,(uintptr)live.fate[r].mem);
2092   #else
2093 <            raw_fmov_rm(bestreg,(uae_u32)live.fate[r].mem);
2093 >            raw_fmov_rm(bestreg,(uintptr)live.fate[r].mem);
2094   #endif
2095          }
2096          live.fate[r].status=CLEAN;
# Line 1827 | Line 2247 | static void fflags_into_flags_internal(u
2247          else
2248      raw_fflags_into_flags(r);
2249      f_unlock(r);
2250 +    live_flags();
2251   }
2252  
2253  
# Line 1875 | Line 2296 | MIDFUNC(0,duplicate_carry,(void))
2296   {
2297      evict(FLAGX);
2298      make_flags_live_internal();
2299 <    COMPCALL(setcc_m)((uae_u32)live.state[FLAGX].mem,2);
2299 >    COMPCALL(setcc_m)((uintptr)live.state[FLAGX].mem,2);
2300          log_vwrite(FLAGX);
2301   }
2302   MENDFUNC(0,duplicate_carry,(void))
# Line 2562 | Line 2983 | MIDFUNC(3,cmov_l_rm,(RW4 d, IMM s, IMM c
2983   }
2984   MENDFUNC(3,cmov_l_rm,(RW4 d, IMM s, IMM cc))
2985  
2986 < MIDFUNC(2,bsf_l_rr,(W4 d, R4 s))
2986 > MIDFUNC(2,bsf_l_rr,(W4 d, W4 s))
2987   {
2988      CLOBBER_BSF;
2989 <    s=readreg(s,4);
2990 <    d=writereg(d,4);
2991 <    raw_bsf_l_rr(d,s);
2989 >    s = readreg(s, 4);
2990 >    d = writereg(d, 4);
2991 >    raw_bsf_l_rr(d, s);
2992      unlock2(s);
2993      unlock2(d);
2994   }
2995 < MENDFUNC(2,bsf_l_rr,(W4 d, R4 s))
2995 > MENDFUNC(2,bsf_l_rr,(W4 d, W4 s))
2996 >
2997 > /* Set the Z flag depending on the value in s. Note that the
2998 >   value has to be 0 or -1 (or, more precisely, for non-zero
2999 >   values, bit 14 must be set)! */
3000 > MIDFUNC(2,simulate_bsf,(W4 tmp, RW4 s))
3001 > {
3002 >    CLOBBER_BSF;
3003 >    s=rmw_specific(s,4,4,FLAG_NREG3);
3004 >    tmp=writereg(tmp,4);
3005 >    raw_flags_set_zero(s, tmp);
3006 >    unlock2(tmp);
3007 >    unlock2(s);
3008 > }
3009 > MENDFUNC(2,simulate_bsf,(W4 tmp, RW4 s))
3010  
3011   MIDFUNC(2,imul_32_32,(RW4 d, R4 s))
3012   {
# Line 2617 | Line 3052 | MIDFUNC(2,mul_32_32,(RW4 d, R4 s))
3052   }
3053   MENDFUNC(2,mul_32_32,(RW4 d, R4 s))
3054  
3055 + #if SIZEOF_VOID_P == 8
3056 + MIDFUNC(2,sign_extend_32_rr,(W4 d, R2 s))
3057 + {
3058 +    int isrmw;
3059 +
3060 +    if (isconst(s)) {
3061 +        set_const(d,(uae_s32)live.state[s].val);
3062 +        return;
3063 +    }
3064 +
3065 +    CLOBBER_SE32;
3066 +    isrmw=(s==d);
3067 +    if (!isrmw) {
3068 +        s=readreg(s,4);
3069 +        d=writereg(d,4);
3070 +    }
3071 +    else {  /* If we try to lock this twice, with different sizes, we
3072 +               are int trouble! */
3073 +        s=d=rmw(s,4,4);
3074 +    }
3075 +    raw_sign_extend_32_rr(d,s);
3076 +    if (!isrmw) {
3077 +        unlock2(d);
3078 +        unlock2(s);
3079 +    }
3080 +    else {
3081 +        unlock2(s);
3082 +    }
3083 + }
3084 + MENDFUNC(2,sign_extend_32_rr,(W4 d, R2 s))
3085 + #endif
3086 +
3087   MIDFUNC(2,sign_extend_16_rr,(W4 d, R2 s))
3088   {
3089      int isrmw;
# Line 4461 | Line 4928 | MENDFUNC(2,fmul_rr,(FRW d, FR s))
4928   * Support functions exposed to gencomp. CREATE time                *
4929   ********************************************************************/
4930  
4931 + void set_zero(int r, int tmp)
4932 + {
4933 +    if (setzflg_uses_bsf)
4934 +        bsf_l_rr(r,r);
4935 +    else
4936 +        simulate_bsf(tmp,r);
4937 + }
4938 +
4939   int kill_rodent(int r)
4940   {
4941      return KILLTHERAT &&
# Line 4509 | Line 4984 | static inline const char *str_on_off(boo
4984          return b ? "on" : "off";
4985   }
4986  
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
4987   void compiler_init(void)
4988   {
4989          static bool initialized = false;
4990          if (initialized)
4991                  return;
4992 <        
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 <        
4992 >
4993   #if JIT_DEBUG
4994          // JIT debug mode ?
4995          JITDebug = PrefsFindBool("jitdebug");
# Line 4556 | Line 5011 | void compiler_init(void)
5011          
5012          // Initialize target CPU (check for features, e.g. CMOV, rat stalls)
5013          raw_init_cpu();
5014 +        setzflg_uses_bsf = target_check_bsf();
5015          write_log("<JIT compiler> : target processor has CMOV instructions : %s\n", have_cmov ? "yes" : "no");
5016          write_log("<JIT compiler> : target processor can suffer from partial register stalls : %s\n", have_rat_stall ? "yes" : "no");
5017 +        write_log("<JIT compiler> : alignment for loops, jumps are %d, %d\n", align_loops, align_jumps);
5018          
5019          // Translation cache flush mechanism
5020          lazy_flush = PrefsFindBool("jitlazyflush");
# Line 4568 | Line 5025 | void compiler_init(void)
5025          write_log("<JIT compiler> : register aliasing : %s\n", str_on_off(1));
5026          write_log("<JIT compiler> : FP register aliasing : %s\n", str_on_off(USE_F_ALIAS));
5027          write_log("<JIT compiler> : lazy constant offsetting : %s\n", str_on_off(USE_OFFSET));
5028 + #if USE_INLINING
5029 +        follow_const_jumps = PrefsFindBool("jitinline");
5030 + #endif
5031 +        write_log("<JIT compiler> : translate through constant jumps : %s\n", str_on_off(follow_const_jumps));
5032          write_log("<JIT compiler> : separate blockinfo allocation : %s\n", str_on_off(USE_SEPARATE_BIA));
5033          
5034          // Build compiler tables
# Line 4575 | Line 5036 | void compiler_init(void)
5036          
5037          initialized = true;
5038          
5039 + #if PROFILE_UNTRANSLATED_INSNS
5040 +        write_log("<JIT compiler> : gather statistics on untranslated insns count\n");
5041 + #endif
5042 +
5043   #if PROFILE_COMPILE_TIME
5044          write_log("<JIT compiler> : gather statistics on translation time\n");
5045          emul_start_time = clock();
# Line 4592 | Line 5057 | void compiler_exit(void)
5057                  vm_release(compiled_code, cache_size * 1024);
5058                  compiled_code = 0;
5059          }
5060 <        
5061 <        // Deallocate blockinfo pools
5062 <        free_blockinfo_pools();
5063 <        
5064 < #ifndef WIN32
5065 <        // Close /dev/zero
4601 <        if (zero_fd > 0)
4602 <                close(zero_fd);
4603 < #endif
5060 >
5061 >        // Deallocate popallspace
5062 >        if (popallspace) {
5063 >                vm_release(popallspace, POPALLSPACE_SIZE);
5064 >                popallspace = 0;
5065 >        }
5066          
5067   #if PROFILE_COMPILE_TIME
5068          write_log("### Compile Block statistics\n");
# Line 4611 | Line 5073 | void compiler_exit(void)
5073                  100.0*double(compile_time)/double(emul_time));
5074          write_log("\n");
5075   #endif
5076 +
5077 + #if PROFILE_UNTRANSLATED_INSNS
5078 +        uae_u64 untranslated_count = 0;
5079 +        for (int i = 0; i < 65536; i++) {
5080 +                opcode_nums[i] = i;
5081 +                untranslated_count += raw_cputbl_count[i];
5082 +        }
5083 +        write_log("Sorting out untranslated instructions count...\n");
5084 +        qsort(opcode_nums, 65536, sizeof(uae_u16), untranslated_compfn);
5085 +        write_log("\nRank  Opc      Count Name\n");
5086 +        for (int i = 0; i < untranslated_top_ten; i++) {
5087 +                uae_u32 count = raw_cputbl_count[opcode_nums[i]];
5088 +                struct instr *dp;
5089 +                struct mnemolookup *lookup;
5090 +                if (!count)
5091 +                        break;
5092 +                dp = table68k + opcode_nums[i];
5093 +                for (lookup = lookuptab; lookup->mnemo != dp->mnemo; lookup++)
5094 +                        ;
5095 +                write_log("%03d: %04x %10lu %s\n", i, opcode_nums[i], count, lookup->name);
5096 +        }
5097 + #endif
5098 +
5099 + #if RECORD_REGISTER_USAGE
5100 +        int reg_count_ids[16];
5101 +        uint64 tot_reg_count = 0;
5102 +        for (int i = 0; i < 16; i++) {
5103 +            reg_count_ids[i] = i;
5104 +            tot_reg_count += reg_count[i];
5105 +        }
5106 +        qsort(reg_count_ids, 16, sizeof(int), reg_count_compare);
5107 +        uint64 cum_reg_count = 0;
5108 +        for (int i = 0; i < 16; i++) {
5109 +            int r = reg_count_ids[i];
5110 +            cum_reg_count += reg_count[r];
5111 +            printf("%c%d : %16ld %2.1f%% [%2.1f]\n", r < 8 ? 'D' : 'A', r % 8,
5112 +                   reg_count[r],
5113 +                   100.0*double(reg_count[r])/double(tot_reg_count),
5114 +                   100.0*double(cum_reg_count)/double(tot_reg_count));
5115 +        }
5116 + #endif
5117   }
5118  
5119   bool compiler_use_jit(void)
# Line 4641 | Line 5144 | void init_comp(void)
5144      uae_s8* cw=can_word;
5145      uae_s8* au=always_used;
5146  
5147 + #if RECORD_REGISTER_USAGE
5148 +    for (i=0;i<16;i++)
5149 +        reg_count_local[i] = 0;
5150 + #endif
5151 +
5152      for (i=0;i<VREGS;i++) {
5153          live.state[i].realreg=-1;
5154          live.state[i].needflush=NF_SCRATCH;
# Line 4665 | Line 5173 | void init_comp(void)
5173      }
5174      live.state[PC_P].mem=(uae_u32*)&(regs.pc_p);
5175      live.state[PC_P].needflush=NF_TOMEM;
5176 <    set_const(PC_P,(uae_u32)comp_pc_p);
5176 >    set_const(PC_P,(uintptr)comp_pc_p);
5177  
5178 <    live.state[FLAGX].mem=&(regflags.x);
5178 >    live.state[FLAGX].mem=(uae_u32*)&(regflags.x);
5179      live.state[FLAGX].needflush=NF_TOMEM;
5180      set_status(FLAGX,INMEM);
5181          
5182 <    live.state[FLAGTMP].mem=&(regflags.cznv);
5182 >    live.state[FLAGTMP].mem=(uae_u32*)&(regflags.cznv);
5183      live.state[FLAGTMP].needflush=NF_TOMEM;
5184      set_status(FLAGTMP,INMEM);
5185  
# Line 4690 | Line 5198 | void init_comp(void)
5198              live.fate[i].status=INMEM;
5199          }
5200          else
5201 <            live.fate[i].mem=(uae_u32*)(scratch.fregs+i);
5201 >            live.fate[i].mem=(uae_u32*)(&scratch.fregs[i]);
5202      }
5203  
5204  
# Line 4745 | Line 5253 | void flush(int save_regs)
5253                  switch(live.state[i].status) {
5254                   case INMEM:  
5255                      if (live.state[i].val) {
5256 <                        raw_add_l_mi((uae_u32)live.state[i].mem,live.state[i].val);
5256 >                        raw_add_l_mi((uintptr)live.state[i].mem,live.state[i].val);
5257                          log_vwrite(i);
5258                          live.state[i].val=0;
5259                      }
# Line 4839 | Line 5347 | void freescratch(void)
5347  
5348   static void align_target(uae_u32 a)
5349   {
5350 <    /* Fill with NOPs --- makes debugging with gdb easier */
5351 <    while ((uae_u32)target&(a-1))
5352 <        *target++=0x90;
5350 >        if (!a)
5351 >                return;
5352 >
5353 >        if (tune_nop_fillers)
5354 >                raw_emit_nop_filler(a - (((uintptr)target) & (a - 1)));
5355 >        else {
5356 >                /* Fill with NOPs --- makes debugging with gdb easier */
5357 >                while ((uintptr)target&(a-1))
5358 >                        *target++=0x90;
5359 >        }
5360   }
5361  
5362   static __inline__ int isinrom(uintptr addr)
# Line 4907 | Line 5422 | void register_branch(uae_u32 not_taken,
5422   static uae_u32 get_handler_address(uae_u32 addr)
5423   {
5424      uae_u32 cl=cacheline(addr);
5425 <    blockinfo* bi=get_blockinfo_addr_new((void*)addr,0);
5426 <    return (uae_u32)&(bi->direct_handler_to_use);
5425 >    blockinfo* bi=get_blockinfo_addr_new((void*)(uintptr)addr,0);
5426 >    return (uintptr)&(bi->direct_handler_to_use);
5427   }
5428  
5429   static uae_u32 get_handler(uae_u32 addr)
5430   {
5431      uae_u32 cl=cacheline(addr);
5432 <    blockinfo* bi=get_blockinfo_addr_new((void*)addr,0);
5433 <    return (uae_u32)bi->direct_handler_to_use;
5432 >    blockinfo* bi=get_blockinfo_addr_new((void*)(uintptr)addr,0);
5433 >    return (uintptr)bi->direct_handler_to_use;
5434   }
5435  
5436   static void load_handler(int reg, uae_u32 addr)
# Line 4927 | Line 5442 | static void load_handler(int reg, uae_u3
5442   *  if that assumption is wrong! No branches, no second chances, just
5443   *  straight go-for-it attitude */
5444  
5445 < static void writemem_real(int address, int source, int offset, int size, int tmp, int clobber)
5445 > static void writemem_real(int address, int source, int size, int tmp, int clobber)
5446   {
5447      int f=tmp;
5448  
5449          if (clobber)
5450              f=source;
5451 +
5452 + #if SIZEOF_VOID_P == 8
5453 +        if (!ThirtyThreeBitAddressing)
5454 +                sign_extend_32_rr(address, address);
5455 + #endif
5456 +
5457          switch(size) {
5458           case 1: mov_b_bRr(address,source,MEMBaseDiff); break;
5459           case 2: mov_w_rr(f,source); bswap_16(f); mov_w_bRr(address,f,MEMBaseDiff); break;
# Line 4944 | Line 5465 | static void writemem_real(int address, i
5465  
5466   void writebyte(int address, int source, int tmp)
5467   {
5468 <        writemem_real(address,source,20,1,tmp,0);
5468 >        writemem_real(address,source,1,tmp,0);
5469   }
5470  
5471   static __inline__ void writeword_general(int address, int source, int tmp,
5472                                           int clobber)
5473   {
5474 <        writemem_real(address,source,16,2,tmp,clobber);
5474 >        writemem_real(address,source,2,tmp,clobber);
5475   }
5476  
5477   void writeword_clobber(int address, int source, int tmp)
# Line 4966 | Line 5487 | void writeword(int address, int source,
5487   static __inline__ void writelong_general(int address, int source, int tmp,
5488                                           int clobber)
5489   {
5490 <        writemem_real(address,source,12,4,tmp,clobber);
5490 >        writemem_real(address,source,4,tmp,clobber);
5491   }
5492  
5493   void writelong_clobber(int address, int source, int tmp)
# Line 4985 | Line 5506 | void writelong(int address, int source,
5506   *  if that assumption is wrong! No branches, no second chances, just
5507   *  straight go-for-it attitude */
5508  
5509 < static void readmem_real(int address, int dest, int offset, int size, int tmp)
5509 > static void readmem_real(int address, int dest, int size, int tmp)
5510   {
5511      int f=tmp;
5512  
5513      if (size==4 && address!=dest)
5514          f=dest;
5515  
5516 + #if SIZEOF_VOID_P == 8
5517 +        if (!ThirtyThreeBitAddressing)
5518 +                sign_extend_32_rr(address, address);
5519 + #endif
5520 +
5521          switch(size) {
5522           case 1: mov_b_brR(dest,address,MEMBaseDiff); break;
5523           case 2: mov_w_brR(dest,address,MEMBaseDiff); bswap_16(dest); break;
# Line 5002 | Line 5528 | static void readmem_real(int address, in
5528  
5529   void readbyte(int address, int dest, int tmp)
5530   {
5531 <        readmem_real(address,dest,8,1,tmp);
5531 >        readmem_real(address,dest,1,tmp);
5532   }
5533  
5534   void readword(int address, int dest, int tmp)
5535   {
5536 <        readmem_real(address,dest,4,2,tmp);
5536 >        readmem_real(address,dest,2,tmp);
5537   }
5538  
5539   void readlong(int address, int dest, int tmp)
5540   {
5541 <        readmem_real(address,dest,0,4,tmp);
5541 >        readmem_real(address,dest,4,tmp);
5542   }
5543  
5544   void get_n_addr(int address, int dest, int tmp)
# Line 5137 | Line 5663 | uae_u32 get_jitted_size(void)
5663      return 0;
5664   }
5665  
5666 + const int CODE_ALLOC_MAX_ATTEMPTS = 10;
5667 + const int CODE_ALLOC_BOUNDARIES   = 128 * 1024; // 128 KB
5668 +
5669 + static uint8 *do_alloc_code(uint32 size, int depth)
5670 + {
5671 + #if defined(__linux__) && 0
5672 +        /*
5673 +          This is a really awful hack that is known to work on Linux at
5674 +          least.
5675 +          
5676 +          The trick here is to make sure the allocated cache is nearby
5677 +          code segment, and more precisely in the positive half of a
5678 +          32-bit address space. i.e. addr < 0x80000000. Actually, it
5679 +          turned out that a 32-bit binary run on AMD64 yields a cache
5680 +          allocated around 0xa0000000, thus causing some troubles when
5681 +          translating addresses from m68k to x86.
5682 +        */
5683 +        static uint8 * code_base = NULL;
5684 +        if (code_base == NULL) {
5685 +                uintptr page_size = getpagesize();
5686 +                uintptr boundaries = CODE_ALLOC_BOUNDARIES;
5687 +                if (boundaries < page_size)
5688 +                        boundaries = page_size;
5689 +                code_base = (uint8 *)sbrk(0);
5690 +                for (int attempts = 0; attempts < CODE_ALLOC_MAX_ATTEMPTS; attempts++) {
5691 +                        if (vm_acquire_fixed(code_base, size) == 0) {
5692 +                                uint8 *code = code_base;
5693 +                                code_base += size;
5694 +                                return code;
5695 +                        }
5696 +                        code_base += boundaries;
5697 +                }
5698 +                return NULL;
5699 +        }
5700 +
5701 +        if (vm_acquire_fixed(code_base, size) == 0) {
5702 +                uint8 *code = code_base;
5703 +                code_base += size;
5704 +                return code;
5705 +        }
5706 +
5707 +        if (depth >= CODE_ALLOC_MAX_ATTEMPTS)
5708 +                return NULL;
5709 +
5710 +        return do_alloc_code(size, depth + 1);
5711 + #else
5712 +        uint8 *code = (uint8 *)vm_acquire(size);
5713 +        return code == VM_MAP_FAILED ? NULL : code;
5714 + #endif
5715 + }
5716 +
5717 + static inline uint8 *alloc_code(uint32 size)
5718 + {
5719 +        uint8 *ptr = do_alloc_code(size, 0);
5720 +        /* allocated code must fit in 32-bit boundaries */
5721 +        assert((uintptr)ptr <= 0xffffffff);
5722 +        return ptr;
5723 + }
5724 +
5725   void alloc_cache(void)
5726   {
5727          if (compiled_code) {
# Line 5149 | Line 5734 | void alloc_cache(void)
5734                  return;
5735          
5736          while (!compiled_code && cache_size) {
5737 <                if ((compiled_code = (uae_u8 *)vm_acquire(cache_size * 1024)) == VM_MAP_FAILED) {
5737 >                if ((compiled_code = alloc_code(cache_size * 1024)) == NULL) {
5738                          compiled_code = 0;
5739                          cache_size /= 2;
5740                  }
5741          }
5742 <        vm_protect(compiled_code, cache_size, VM_PAGE_READ | VM_PAGE_WRITE | VM_PAGE_EXECUTE);
5742 >        vm_protect(compiled_code, cache_size * 1024, VM_PAGE_READ | VM_PAGE_WRITE | VM_PAGE_EXECUTE);
5743          
5744          if (compiled_code) {
5745                  write_log("<JIT compiler> : actual translation cache size : %d KB at 0x%08X\n", cache_size, compiled_code);
# Line 5166 | Line 5751 | void alloc_cache(void)
5751  
5752  
5753  
5754 < extern cpuop_rettype op_illg_1 (uae_u32 opcode) REGPARAM;
5754 > extern void op_illg_1 (uae_u32 opcode) REGPARAM;
5755  
5756   static void calc_checksum(blockinfo* bi, uae_u32* c1, uae_u32* c2)
5757   {
5758 <    uae_u32 k1=0;
5759 <    uae_u32 k2=0;
5175 <    uae_s32 len=bi->len;
5176 <    uae_u32 tmp=bi->min_pcp;
5177 <    uae_u32* pos;
5758 >    uae_u32 k1 = 0;
5759 >    uae_u32 k2 = 0;
5760  
5761 <    len+=(tmp&3);
5762 <    tmp&=(~3);
5763 <    pos=(uae_u32*)tmp;
5761 > #if USE_CHECKSUM_INFO
5762 >    checksum_info *csi = bi->csi;
5763 >        Dif(!csi) abort();
5764 >        while (csi) {
5765 >                uae_s32 len = csi->length;
5766 >                uintptr tmp = (uintptr)csi->start_p;
5767 > #else
5768 >                uae_s32 len = bi->len;
5769 >                uintptr tmp = (uintptr)bi->min_pcp;
5770 > #endif
5771 >                uae_u32*pos;
5772  
5773 <    if (len<0 || len>MAX_CHECKSUM_LEN) {
5774 <        *c1=0;
5775 <        *c2=0;
5776 <    }
5777 <    else {
5778 <        while (len>0) {
5779 <            k1+=*pos;
5780 <            k2^=*pos;
5781 <            pos++;
5782 <            len-=4;
5773 >                len += (tmp & 3);
5774 >                tmp &= ~((uintptr)3);
5775 >                pos = (uae_u32 *)tmp;
5776 >
5777 >                if (len >= 0 && len <= MAX_CHECKSUM_LEN) {
5778 >                        while (len > 0) {
5779 >                                k1 += *pos;
5780 >                                k2 ^= *pos;
5781 >                                pos++;
5782 >                                len -= 4;
5783 >                        }
5784 >                }
5785 >
5786 > #if USE_CHECKSUM_INFO
5787 >                csi = csi->next;
5788          }
5789 <        *c1=k1;
5790 <        *c2=k2;
5791 <    }
5789 > #endif
5790 >
5791 >        *c1 = k1;
5792 >        *c2 = k2;
5793   }
5794  
5795 < static void show_checksum(blockinfo* bi)
5795 > #if 0
5796 > static void show_checksum(CSI_TYPE* csi)
5797   {
5798      uae_u32 k1=0;
5799      uae_u32 k2=0;
5800 <    uae_s32 len=bi->len;
5801 <    uae_u32 tmp=(uae_u32)bi->pc_p;
5800 >    uae_s32 len=CSI_LENGTH(csi);
5801 >    uae_u32 tmp=(uintptr)CSI_START_P(csi);
5802      uae_u32* pos;
5803  
5804      len+=(tmp&3);
# Line 5220 | Line 5817 | static void show_checksum(blockinfo* bi)
5817          write_log(" bla\n");
5818      }
5819   }
5820 + #endif
5821  
5822  
5823   int check_for_cache_miss(void)
# Line 5273 | Line 5871 | static int called_check_checksum(blockin
5871   static inline int block_check_checksum(blockinfo* bi)
5872   {
5873      uae_u32     c1,c2;
5874 <    int         isgood;
5874 >    bool        isgood;
5875      
5876      if (bi->status!=BI_NEED_CHECK)
5877          return 1;  /* This block is in a checked state */
5878      
5879      checksum_count++;
5880 +
5881      if (bi->c1 || bi->c2)
5882          calc_checksum(bi,&c1,&c2);
5883      else {
5884          c1=c2=1;  /* Make sure it doesn't match */
5885 <    }
5885 >        }
5886      
5887      isgood=(c1==bi->c1 && c2==bi->c2);
5888 +
5889      if (isgood) {
5890          /* This block is still OK. So we reactivate. Of course, that
5891             means we have to move it into the needs-to-be-flushed list */
# Line 5390 | Line 5990 | static __inline__ void match_states(bloc
5990      }
5991   }
5992  
5393 static uae_u8 popallspace[1024]; /* That should be enough space */
5394
5993   static __inline__ void create_popalls(void)
5994   {
5995    int i,r;
5996  
5997 +  if ((popallspace = alloc_code(POPALLSPACE_SIZE)) == NULL) {
5998 +          write_log("FATAL: Could not allocate popallspace!\n");
5999 +          abort();
6000 +  }
6001 +  vm_protect(popallspace, POPALLSPACE_SIZE, VM_PAGE_READ | VM_PAGE_WRITE);
6002 +
6003 +  int stack_space = STACK_OFFSET;
6004 +  for (i=0;i<N_REGS;i++) {
6005 +          if (need_to_preserve[i])
6006 +                  stack_space += sizeof(void *);
6007 +  }
6008 +  stack_space %= STACK_ALIGN;
6009 +  if (stack_space)
6010 +          stack_space = STACK_ALIGN - stack_space;
6011 +
6012    current_compile_p=popallspace;
6013    set_target(current_compile_p);
6014   #if USE_PUSH_POP
# Line 5403 | Line 6016 | static __inline__ void create_popalls(vo
6016       registers before jumping back to the various get-out routines.
6017       This generates the code for it.
6018    */
6019 <  popall_do_nothing=current_compile_p;
6019 >  align_target(align_jumps);
6020 >  popall_do_nothing=get_target();
6021 >  raw_inc_sp(stack_space);
6022    for (i=0;i<N_REGS;i++) {
6023        if (need_to_preserve[i])
6024            raw_pop_l_r(i);
6025    }
6026 <  raw_jmp((uae_u32)do_nothing);
5412 <  align_target(32);
6026 >  raw_jmp((uintptr)do_nothing);
6027    
6028 +  align_target(align_jumps);
6029    popall_execute_normal=get_target();
6030 +  raw_inc_sp(stack_space);
6031    for (i=0;i<N_REGS;i++) {
6032        if (need_to_preserve[i])
6033            raw_pop_l_r(i);
6034    }
6035 <  raw_jmp((uae_u32)execute_normal);
5420 <  align_target(32);
6035 >  raw_jmp((uintptr)execute_normal);
6036  
6037 +  align_target(align_jumps);
6038    popall_cache_miss=get_target();
6039 +  raw_inc_sp(stack_space);
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)cache_miss);
5428 <  align_target(32);
6044 >  raw_jmp((uintptr)cache_miss);
6045  
6046 +  align_target(align_jumps);
6047    popall_recompile_block=get_target();
6048 +  raw_inc_sp(stack_space);
6049    for (i=0;i<N_REGS;i++) {
6050        if (need_to_preserve[i])
6051            raw_pop_l_r(i);
6052    }
6053 <  raw_jmp((uae_u32)recompile_block);
6054 <  align_target(32);
6055 <  
6053 >  raw_jmp((uintptr)recompile_block);
6054 >
6055 >  align_target(align_jumps);
6056    popall_exec_nostats=get_target();
6057 +  raw_inc_sp(stack_space);
6058    for (i=0;i<N_REGS;i++) {
6059        if (need_to_preserve[i])
6060            raw_pop_l_r(i);
6061    }
6062 <  raw_jmp((uae_u32)exec_nostats);
6063 <  align_target(32);
6064 <  
6062 >  raw_jmp((uintptr)exec_nostats);
6063 >
6064 >  align_target(align_jumps);
6065    popall_check_checksum=get_target();
6066 +  raw_inc_sp(stack_space);
6067    for (i=0;i<N_REGS;i++) {
6068        if (need_to_preserve[i])
6069            raw_pop_l_r(i);
6070    }
6071 <  raw_jmp((uae_u32)check_checksum);
6072 <  align_target(32);
6073 <  
6071 >  raw_jmp((uintptr)check_checksum);
6072 >
6073 >  align_target(align_jumps);
6074    current_compile_p=get_target();
6075   #else
6076    popall_exec_nostats=(void *)exec_nostats;
# Line 5459 | Line 6079 | static __inline__ void create_popalls(vo
6079    popall_recompile_block=(void *)recompile_block;
6080    popall_do_nothing=(void *)do_nothing;
6081    popall_check_checksum=(void *)check_checksum;
5462  pushall_call_handler=get_target();  
6082   #endif
6083  
6084    /* And now, the code to do the matching pushes and then jump
# Line 5471 | Line 6090 | static __inline__ void create_popalls(vo
6090            raw_push_l_r(i);
6091    }
6092   #endif
6093 +  raw_dec_sp(stack_space);
6094 +  r=REG_PC_TMP;
6095 +  raw_mov_l_rm(r,(uintptr)&regs.pc_p);
6096 +  raw_and_l_ri(r,TAGMASK);
6097 +  raw_jmp_m_indexed((uintptr)cache_tags,r,SIZEOF_VOID_P);
6098 +
6099 + #if ! USE_PUSH_POP
6100 +  align_target(align_jumps);
6101 +  m68k_do_compile_execute = (void (*)(void))get_target();
6102 +  for (i=N_REGS;i--;) {
6103 +          if (need_to_preserve[i])
6104 +                  raw_push_l_r(i);
6105 +  }
6106 +  raw_dec_sp(stack_space);
6107 +  align_target(align_loops);
6108 +  uae_u32 dispatch_loop = (uintptr)get_target();
6109    r=REG_PC_TMP;
6110 <  raw_mov_l_rm(r,(uae_u32)&regs.pc_p);
6110 >  raw_mov_l_rm(r,(uintptr)&regs.pc_p);
6111    raw_and_l_ri(r,TAGMASK);
6112 <  raw_jmp_m_indexed((uae_u32)cache_tags,r,4);
6112 >  raw_call_m_indexed((uintptr)cache_tags,r,SIZEOF_VOID_P);
6113 >  raw_cmp_l_mi((uintptr)&regs.spcflags,0);
6114 >  raw_jcc_b_oponly(NATIVE_CC_EQ);
6115 >  emit_byte(dispatch_loop-((uintptr)get_target()+1));
6116 >  raw_call((uintptr)m68k_do_specialties);
6117 >  raw_test_l_rr(REG_RESULT,REG_RESULT);
6118 >  raw_jcc_b_oponly(NATIVE_CC_EQ);
6119 >  emit_byte(dispatch_loop-((uintptr)get_target()+1));
6120 >  raw_cmp_b_mi((uintptr)&quit_program,0);
6121 >  raw_jcc_b_oponly(NATIVE_CC_EQ);
6122 >  emit_byte(dispatch_loop-((uintptr)get_target()+1));
6123 >  raw_inc_sp(stack_space);
6124 >  for (i=0;i<N_REGS;i++) {
6125 >          if (need_to_preserve[i])
6126 >                  raw_pop_l_r(i);
6127 >  }
6128 >  raw_ret();
6129 > #endif
6130 >
6131 >  // no need to further write into popallspace
6132 >  vm_protect(popallspace, POPALLSPACE_SIZE, VM_PAGE_READ | VM_PAGE_EXECUTE);
6133   }
6134  
6135   static __inline__ void reset_lists(void)
# Line 5492 | Line 6147 | static void prepare_block(blockinfo* bi)
6147      int i;
6148  
6149      set_target(current_compile_p);
6150 <    align_target(32);
6150 >    align_target(align_jumps);
6151      bi->direct_pen=(cpuop_func *)get_target();
6152 <    raw_mov_l_rm(0,(uae_u32)&(bi->pc_p));
6153 <    raw_mov_l_mr((uae_u32)&regs.pc_p,0);
6154 <    raw_jmp((uae_u32)popall_execute_normal);
6152 >    raw_mov_l_rm(0,(uintptr)&(bi->pc_p));
6153 >    raw_mov_l_mr((uintptr)&regs.pc_p,0);
6154 >    raw_jmp((uintptr)popall_execute_normal);
6155  
6156 <    align_target(32);
6156 >    align_target(align_jumps);
6157      bi->direct_pcc=(cpuop_func *)get_target();
6158 <    raw_mov_l_rm(0,(uae_u32)&(bi->pc_p));
6159 <    raw_mov_l_mr((uae_u32)&regs.pc_p,0);
6160 <    raw_jmp((uae_u32)popall_check_checksum);
5506 <
5507 <    align_target(32);
6158 >    raw_mov_l_rm(0,(uintptr)&(bi->pc_p));
6159 >    raw_mov_l_mr((uintptr)&regs.pc_p,0);
6160 >    raw_jmp((uintptr)popall_check_checksum);
6161      current_compile_p=get_target();
6162  
6163      bi->deplist=NULL;
# Line 5518 | Line 6171 | static void prepare_block(blockinfo* bi)
6171      //bi->env=empty_ss;
6172   }
6173  
6174 + // OPCODE is in big endian format, use cft_map() beforehand, if needed.
6175 + static inline void reset_compop(int opcode)
6176 + {
6177 +        compfunctbl[opcode] = NULL;
6178 +        nfcompfunctbl[opcode] = NULL;
6179 + }
6180 +
6181 + static int read_opcode(const char *p)
6182 + {
6183 +        int opcode = 0;
6184 +        for (int i = 0; i < 4; i++) {
6185 +                int op = p[i];
6186 +                switch (op) {
6187 +                case '0': case '1': case '2': case '3': case '4':
6188 +                case '5': case '6': case '7': case '8': case '9':
6189 +                        opcode = (opcode << 4) | (op - '0');
6190 +                        break;
6191 +                case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
6192 +                        opcode = (opcode << 4) | ((op - 'a') + 10);
6193 +                        break;
6194 +                case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
6195 +                        opcode = (opcode << 4) | ((op - 'A') + 10);
6196 +                        break;
6197 +                default:
6198 +                        return -1;
6199 +                }
6200 +        }
6201 +        return opcode;
6202 + }
6203 +
6204 + static bool merge_blacklist()
6205 + {
6206 +        const char *blacklist = PrefsFindString("jitblacklist");
6207 +        if (blacklist) {
6208 +                const char *p = blacklist;
6209 +                for (;;) {
6210 +                        if (*p == 0)
6211 +                                return true;
6212 +
6213 +                        int opcode1 = read_opcode(p);
6214 +                        if (opcode1 < 0)
6215 +                                return false;
6216 +                        p += 4;
6217 +
6218 +                        int opcode2 = opcode1;
6219 +                        if (*p == '-') {
6220 +                                p++;
6221 +                                opcode2 = read_opcode(p);
6222 +                                if (opcode2 < 0)
6223 +                                        return false;
6224 +                                p += 4;
6225 +                        }
6226 +
6227 +                        if (*p == 0 || *p == ';') {
6228 +                                write_log("<JIT compiler> : blacklist opcodes : %04x-%04x\n", opcode1, opcode2);
6229 +                                for (int opcode = opcode1; opcode <= opcode2; opcode++)
6230 +                                        reset_compop(cft_map(opcode));
6231 +
6232 +                                if (*p++ == ';')
6233 +                                        continue;
6234 +
6235 +                                return true;
6236 +                        }
6237 +
6238 +                        return false;
6239 +                }
6240 +        }
6241 +        return true;
6242 + }
6243 +
6244   void build_comp(void)
6245   {
6246          int i;
# Line 5547 | Line 6270 | void build_comp(void)
6270      write_log ("<JIT compiler> : building compiler function tables\n");
6271          
6272          for (opcode = 0; opcode < 65536; opcode++) {
6273 +                reset_compop(opcode);
6274                  nfcpufunctbl[opcode] = op_illg_1;
5551                compfunctbl[opcode] = NULL;
5552                nfcompfunctbl[opcode] = NULL;
6275                  prop[opcode].use_flags = 0x1f;
6276                  prop[opcode].set_flags = 0x1f;
6277                  prop[opcode].cflow = fl_trap; // ILLEGAL instructions do trap
# Line 5557 | Line 6279 | void build_comp(void)
6279          
6280          for (i = 0; tbl[i].opcode < 65536; i++) {
6281                  int cflow = table68k[tbl[i].opcode].cflow;
6282 +                if (follow_const_jumps && (tbl[i].specific & 16))
6283 +                        cflow = fl_const_jump;
6284 +                else
6285 +                        cflow &= ~fl_const_jump;
6286                  prop[cft_map(tbl[i].opcode)].cflow = cflow;
6287  
6288                  int uses_fpu = tbl[i].specific & 32;
# Line 5605 | Line 6331 | void build_comp(void)
6331                  }
6332                  prop[cft_map(opcode)].set_flags = table68k[opcode].flagdead;
6333                  prop[cft_map(opcode)].use_flags = table68k[opcode].flaglive;
6334 +                /* Unconditional jumps don't evaluate condition codes, so they
6335 +                 * don't actually use any flags themselves */
6336 +                if (prop[cft_map(opcode)].cflow & fl_const_jump)
6337 +                        prop[cft_map(opcode)].use_flags = 0;
6338      }
6339          for (i = 0; nfctbl[i].handler != NULL; i++) {
6340                  if (nfctbl[i].specific)
6341                          nfcpufunctbl[cft_map(tbl[i].opcode)] = nfctbl[i].handler;
6342          }
6343  
6344 +        /* Merge in blacklist */
6345 +        if (!merge_blacklist())
6346 +                write_log("<JIT compiler> : blacklist merge failure!\n");
6347 +
6348      count=0;
6349      for (opcode = 0; opcode < 65536; opcode++) {
6350          if (compfunctbl[cft_map(opcode)])
# Line 5729 | Line 6463 | static inline void flush_icache_lazy(int
6463          active=NULL;
6464   }
6465  
6466 + void flush_icache_range(uae_u32 start, uae_u32 length)
6467 + {
6468 +        if (!active)
6469 +                return;
6470 +
6471 + #if LAZY_FLUSH_ICACHE_RANGE
6472 +        uae_u8 *start_p = get_real_address(start);
6473 +        blockinfo *bi = active;
6474 +        while (bi) {
6475 + #if USE_CHECKSUM_INFO
6476 +                bool invalidate = false;
6477 +                for (checksum_info *csi = bi->csi; csi && !invalidate; csi = csi->next)
6478 +                        invalidate = (((start_p - csi->start_p) < csi->length) ||
6479 +                                                  ((csi->start_p - start_p) < length));
6480 + #else
6481 +                // Assume system is consistent and would invalidate the right range
6482 +                const bool invalidate = (bi->pc_p - start_p) < length;
6483 + #endif
6484 +                if (invalidate) {
6485 +                        uae_u32 cl = cacheline(bi->pc_p);
6486 +                        if (bi == cache_tags[cl + 1].bi)
6487 +                                        cache_tags[cl].handler = (cpuop_func *)popall_execute_normal;
6488 +                        bi->handler_to_use = (cpuop_func *)popall_execute_normal;
6489 +                        set_dhtu(bi, bi->direct_pen);
6490 +                        bi->status = BI_NEED_RECOMP;
6491 +                }
6492 +                bi = bi->next;
6493 +        }
6494 +        return;
6495 + #endif
6496 +        flush_icache(-1);
6497 + }
6498 +
6499   static void catastrophe(void)
6500   {
6501      abort();
# Line 5739 | Line 6506 | int failure;
6506   #define TARGET_M68K             0
6507   #define TARGET_POWERPC  1
6508   #define TARGET_X86              2
6509 + #define TARGET_X86_64   3
6510   #if defined(i386) || defined(__i386__)
6511   #define TARGET_NATIVE   TARGET_X86
6512   #endif
6513   #if defined(powerpc) || defined(__powerpc__)
6514   #define TARGET_NATIVE   TARGET_POWERPC
6515   #endif
6516 + #if defined(x86_64) || defined(__x86_64__)
6517 + #define TARGET_NATIVE   TARGET_X86_64
6518 + #endif
6519  
6520   #ifdef ENABLE_MON
6521 < static uae_u32 mon_read_byte_jit(uae_u32 addr)
6521 > static uae_u32 mon_read_byte_jit(uintptr addr)
6522   {
6523          uae_u8 *m = (uae_u8 *)addr;
6524 <        return (uae_u32)(*m);
6524 >        return (uintptr)(*m);
6525   }
6526  
6527 < static void mon_write_byte_jit(uae_u32 addr, uae_u32 b)
6527 > static void mon_write_byte_jit(uintptr addr, uae_u32 b)
6528   {
6529          uae_u8 *m = (uae_u8 *)addr;
6530          *m = b;
# Line 5770 | Line 6541 | void disasm_block(int target, uint8 * st
6541          sprintf(disasm_str, "%s $%x $%x",
6542                          target == TARGET_M68K ? "d68" :
6543                          target == TARGET_X86 ? "d86" :
6544 +                        target == TARGET_X86_64 ? "d8664" :
6545                          target == TARGET_POWERPC ? "d" : "x",
6546                          start, start + length - 1);
6547          
6548 <        uae_u32 (*old_mon_read_byte)(uae_u32) = mon_read_byte;
6549 <        void (*old_mon_write_byte)(uae_u32, uae_u32) = mon_write_byte;
6548 >        uae_u32 (*old_mon_read_byte)(uintptr) = mon_read_byte;
6549 >        void (*old_mon_write_byte)(uintptr, uae_u32) = mon_write_byte;
6550          
6551          mon_read_byte = mon_read_byte_jit;
6552          mon_write_byte = mon_write_byte_jit;
# Line 5787 | Line 6559 | void disasm_block(int target, uint8 * st
6559   #endif
6560   }
6561  
6562 < static inline void disasm_native_block(uint8 *start, size_t length)
6562 > static void disasm_native_block(uint8 *start, size_t length)
6563   {
6564          disasm_block(TARGET_NATIVE, start, length);
6565   }
6566  
6567 < static inline void disasm_m68k_block(uint8 *start, size_t length)
6567 > static void disasm_m68k_block(uint8 *start, size_t length)
6568   {
6569          disasm_block(TARGET_M68K, start, length);
6570   }
# Line 5826 | Line 6598 | void compiler_dumpstate(void)
6598          
6599          write_log("### Block in Mac address space\n");
6600          write_log("M68K block   : %p\n",
6601 <                          (void *)get_virtual_address(last_regs_pc_p));
6601 >                          (void *)(uintptr)get_virtual_address(last_regs_pc_p));
6602          write_log("Native block : %p (%d bytes)\n",
6603 <                          (void *)get_virtual_address(last_compiled_block_addr),
6603 >                          (void *)(uintptr)get_virtual_address(last_compiled_block_addr),
6604                            get_blockinfo_addr(last_regs_pc_p)->direct_handler_size);
6605          write_log("\n");
6606   }
# Line 5850 | Line 6622 | static void compile_block(cpu_history* p
6622          int r;
6623          int was_comp=0;
6624          uae_u8 liveflags[MAXRUN+1];
6625 <        uae_u32 max_pcp=(uae_u32)pc_hist[0].location;
6626 <        uae_u32 min_pcp=max_pcp;
6625 > #if USE_CHECKSUM_INFO
6626 >        bool trace_in_rom = isinrom((uintptr)pc_hist[0].location);
6627 >        uintptr max_pcp=(uintptr)pc_hist[blocklen - 1].location;
6628 >        uintptr min_pcp=max_pcp;
6629 > #else
6630 >        uintptr max_pcp=(uintptr)pc_hist[0].location;
6631 >        uintptr min_pcp=max_pcp;
6632 > #endif
6633          uae_u32 cl=cacheline(pc_hist[0].location);
6634          void* specflags=(void*)&regs.spcflags;
6635          blockinfo* bi=NULL;
# Line 5890 | Line 6668 | static void compile_block(cpu_history* p
6668                  optlev++;
6669              bi->count=optcount[optlev]-1;
6670          }
6671 <        current_block_pc_p=(uae_u32)pc_hist[0].location;
6671 >        current_block_pc_p=(uintptr)pc_hist[0].location;
6672          
6673          remove_deps(bi); /* We are about to create new code */
6674          bi->optlevel=optlev;
6675          bi->pc_p=(uae_u8*)pc_hist[0].location;
6676 + #if USE_CHECKSUM_INFO
6677 +        free_checksum_info_chain(bi->csi);
6678 +        bi->csi = NULL;
6679 + #endif
6680          
6681          liveflags[blocklen]=0x1f; /* All flags needed afterwards */
6682          i=blocklen;
# Line 5902 | Line 6684 | static void compile_block(cpu_history* p
6684              uae_u16* currpcp=pc_hist[i].location;
6685              uae_u32 op=DO_GET_OPCODE(currpcp);
6686  
6687 <            if ((uae_u32)currpcp<min_pcp)
6688 <                min_pcp=(uae_u32)currpcp;
6689 <            if ((uae_u32)currpcp>max_pcp)
6690 <                max_pcp=(uae_u32)currpcp;
6687 > #if USE_CHECKSUM_INFO
6688 >                trace_in_rom = trace_in_rom && isinrom((uintptr)currpcp);
6689 >                if (follow_const_jumps && is_const_jump(op)) {
6690 >                        checksum_info *csi = alloc_checksum_info();
6691 >                        csi->start_p = (uae_u8 *)min_pcp;
6692 >                        csi->length = max_pcp - min_pcp + LONGEST_68K_INST;
6693 >                        csi->next = bi->csi;
6694 >                        bi->csi = csi;
6695 >                        max_pcp = (uintptr)currpcp;
6696 >                }
6697 >                min_pcp = (uintptr)currpcp;
6698 > #else
6699 >            if ((uintptr)currpcp<min_pcp)
6700 >                min_pcp=(uintptr)currpcp;
6701 >            if ((uintptr)currpcp>max_pcp)
6702 >                max_pcp=(uintptr)currpcp;
6703 > #endif
6704  
6705                  liveflags[i]=((liveflags[i+1]&
6706                                 (~prop[op].set_flags))|
# Line 5914 | Line 6709 | static void compile_block(cpu_history* p
6709                      liveflags[i]&= ~FLAG_Z;
6710          }
6711  
6712 + #if USE_CHECKSUM_INFO
6713 +        checksum_info *csi = alloc_checksum_info();
6714 +        csi->start_p = (uae_u8 *)min_pcp;
6715 +        csi->length = max_pcp - min_pcp + LONGEST_68K_INST;
6716 +        csi->next = bi->csi;
6717 +        bi->csi = csi;
6718 + #endif
6719 +
6720          bi->needed_flags=liveflags[0];
6721  
6722 <        align_target(32);
6722 >        align_target(align_loops);
6723          was_comp=0;
6724  
6725          bi->direct_handler=(cpuop_func *)get_target();
6726          set_dhtu(bi,bi->direct_handler);
6727          bi->status=BI_COMPILING;
6728 <        current_block_start_target=(uae_u32)get_target();
6728 >        current_block_start_target=(uintptr)get_target();
6729          
6730          log_startblock();
6731          
6732          if (bi->count>=0) { /* Need to generate countdown code */
6733 <            raw_mov_l_mi((uae_u32)&regs.pc_p,(uae_u32)pc_hist[0].location);
6734 <            raw_sub_l_mi((uae_u32)&(bi->count),1);
6735 <            raw_jl((uae_u32)popall_recompile_block);
6733 >            raw_mov_l_mi((uintptr)&regs.pc_p,(uintptr)pc_hist[0].location);
6734 >            raw_sub_l_mi((uintptr)&(bi->count),1);
6735 >            raw_jl((uintptr)popall_recompile_block);
6736          }
6737          if (optlev==0) { /* No need to actually translate */
6738              /* Execute normally without keeping stats */
6739 <            raw_mov_l_mi((uae_u32)&regs.pc_p,(uae_u32)pc_hist[0].location);
6740 <            raw_jmp((uae_u32)popall_exec_nostats);
6739 >            raw_mov_l_mi((uintptr)&regs.pc_p,(uintptr)pc_hist[0].location);
6740 >            raw_jmp((uintptr)popall_exec_nostats);
6741          }
6742          else {
6743              reg_alloc_run=0;
# Line 5946 | Line 6749 | static void compile_block(cpu_history* p
6749              init_comp();
6750              was_comp=1;
6751  
6752 + #ifdef USE_CPU_EMUL_SERVICES
6753 +            raw_sub_l_mi((uintptr)&emulated_ticks,blocklen);
6754 +            raw_jcc_b_oponly(NATIVE_CC_GT);
6755 +            uae_s8 *branchadd=(uae_s8*)get_target();
6756 +            emit_byte(0);
6757 +            raw_call((uintptr)cpu_do_check_ticks);
6758 +            *branchadd=(uintptr)get_target()-((uintptr)branchadd+1);
6759 + #endif
6760 +
6761   #if JIT_DEBUG
6762                  if (JITDebug) {
6763 <                        raw_mov_l_mi((uae_u32)&last_regs_pc_p,(uae_u32)pc_hist[0].location);
6764 <                        raw_mov_l_mi((uae_u32)&last_compiled_block_addr,(uae_u32)current_block_start_target);
6763 >                        raw_mov_l_mi((uintptr)&last_regs_pc_p,(uintptr)pc_hist[0].location);
6764 >                        raw_mov_l_mi((uintptr)&last_compiled_block_addr,current_block_start_target);
6765                  }
6766   #endif
6767                  
# Line 5967 | Line 6779 | static void compile_block(cpu_history* p
6779                      cputbl=cpufunctbl;
6780                      comptbl=compfunctbl;
6781                  }
6782 +
6783 + #if FLIGHT_RECORDER
6784 +                {
6785 +                    mov_l_ri(S1, get_virtual_address((uae_u8 *)(pc_hist[i].location)) | 1);
6786 +                    clobber_flags();
6787 +                    remove_all_offsets();
6788 +                    int arg = readreg_specific(S1,4,REG_PAR1);
6789 +                    prepare_for_call_1();
6790 +                    unlock2(arg);
6791 +                    prepare_for_call_2();
6792 +                    raw_call((uintptr)m68k_record_step);
6793 +                }
6794 + #endif
6795                  
6796                  failure = 1; // gb-- defaults to failure state
6797                  if (comptbl[opcode] && optlev>1) {
# Line 5975 | Line 6800 | static void compile_block(cpu_history* p
6800                          comp_pc_p=(uae_u8*)pc_hist[i].location;
6801                          init_comp();
6802                      }
6803 <                    was_comp++;
6803 >                    was_comp=1;
6804  
6805                      comptbl[opcode](opcode);
6806                      freescratch();
# Line 6000 | Line 6825 | static void compile_block(cpu_history* p
6825   #if USE_NORMAL_CALLING_CONVENTION
6826                      raw_push_l_r(REG_PAR1);
6827   #endif
6828 <                    raw_mov_l_mi((uae_u32)&regs.pc_p,
6829 <                                 (uae_u32)pc_hist[i].location);
6830 <                    raw_call((uae_u32)cputbl[opcode]);
6831 <                    //raw_add_l_mi((uae_u32)&oink,1); // FIXME
6828 >                    raw_mov_l_mi((uintptr)&regs.pc_p,
6829 >                                 (uintptr)pc_hist[i].location);
6830 >                    raw_call((uintptr)cputbl[opcode]);
6831 > #if PROFILE_UNTRANSLATED_INSNS
6832 >                        // raw_cputbl_count[] is indexed with plain opcode (in m68k order)
6833 >                        raw_add_l_mi((uintptr)&raw_cputbl_count[cft_map(opcode)],1);
6834 > #endif
6835   #if USE_NORMAL_CALLING_CONVENTION
6836                      raw_inc_sp(4);
6837   #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                    }
6838                      
6839                      if (i < blocklen - 1) {
6840                          uae_s8* branchadd;
6841                          
6842 <                        raw_mov_l_rm(0,(uae_u32)specflags);
6842 >                        raw_mov_l_rm(0,(uintptr)specflags);
6843                          raw_test_l_rr(0,0);
6844                          raw_jz_b_oponly();
6845                          branchadd=(uae_s8 *)get_target();
6846                          emit_byte(0);
6847 <                        raw_jmp((uae_u32)popall_do_nothing);
6848 <                        *branchadd=(uae_u32)get_target()-(uae_u32)branchadd-1;
6847 >                        raw_jmp((uintptr)popall_do_nothing);
6848 >                        *branchadd=(uintptr)get_target()-(uintptr)branchadd-1;
6849                      }
6850                  }
6851              }
# Line 6057 | Line 6879 | static void compile_block(cpu_history* p
6879                  log_flush();
6880  
6881              if (next_pc_p) { /* A branch was registered */
6882 <                uae_u32 t1=next_pc_p;
6883 <                uae_u32 t2=taken_pc_p;
6882 >                uintptr t1=next_pc_p;
6883 >                uintptr t2=taken_pc_p;
6884                  int     cc=branch_cc;
6885                  
6886                  uae_u32* branchadd;
# Line 6083 | Line 6905 | static void compile_block(cpu_history* p
6905                  /* predicted outcome */
6906                  tbi=get_blockinfo_addr_new((void*)t1,1);
6907                  match_states(tbi);
6908 <                raw_cmp_l_mi((uae_u32)specflags,0);
6908 >                raw_cmp_l_mi((uintptr)specflags,0);
6909                  raw_jcc_l_oponly(4);
6910                  tba=(uae_u32*)get_target();
6911 <                emit_long(get_handler(t1)-((uae_u32)tba+4));
6912 <                raw_mov_l_mi((uae_u32)&regs.pc_p,t1);
6913 <                raw_jmp((uae_u32)popall_do_nothing);
6911 >                emit_long(get_handler(t1)-((uintptr)tba+4));
6912 >                raw_mov_l_mi((uintptr)&regs.pc_p,t1);
6913 >                flush_reg_count();
6914 >                raw_jmp((uintptr)popall_do_nothing);
6915                  create_jmpdep(bi,0,tba,t1);
6916  
6917 <                align_target(16);
6917 >                align_target(align_jumps);
6918                  /* not-predicted outcome */
6919 <                *branchadd=(uae_u32)get_target()-((uae_u32)branchadd+4);
6919 >                *branchadd=(uintptr)get_target()-((uintptr)branchadd+4);
6920                  live=tmp; /* Ouch again */
6921                  tbi=get_blockinfo_addr_new((void*)t2,1);
6922                  match_states(tbi);
6923  
6924                  //flush(1); /* Can only get here if was_comp==1 */
6925 <                raw_cmp_l_mi((uae_u32)specflags,0);
6925 >                raw_cmp_l_mi((uintptr)specflags,0);
6926                  raw_jcc_l_oponly(4);
6927                  tba=(uae_u32*)get_target();
6928 <                emit_long(get_handler(t2)-((uae_u32)tba+4));
6929 <                raw_mov_l_mi((uae_u32)&regs.pc_p,t2);
6930 <                raw_jmp((uae_u32)popall_do_nothing);
6928 >                emit_long(get_handler(t2)-((uintptr)tba+4));
6929 >                raw_mov_l_mi((uintptr)&regs.pc_p,t2);
6930 >                flush_reg_count();
6931 >                raw_jmp((uintptr)popall_do_nothing);
6932                  create_jmpdep(bi,1,tba,t2);
6933              }          
6934              else
# Line 6112 | Line 6936 | static void compile_block(cpu_history* p
6936                  if (was_comp) {
6937                      flush(1);
6938                  }
6939 +                flush_reg_count();
6940                  
6941                  /* Let's find out where next_handler is... */
6942                  if (was_comp && isinreg(PC_P)) {
6943                      r=live.state[PC_P].realreg;
6944                          raw_and_l_ri(r,TAGMASK);
6945                          int r2 = (r==0) ? 1 : 0;
6946 <                        raw_mov_l_ri(r2,(uae_u32)popall_do_nothing);
6947 <                        raw_cmp_l_mi((uae_u32)specflags,0);
6948 <                        raw_cmov_l_rm_indexed(r2,(uae_u32)cache_tags,r,4,4);
6946 >                        raw_mov_l_ri(r2,(uintptr)popall_do_nothing);
6947 >                        raw_cmp_l_mi((uintptr)specflags,0);
6948 >                        raw_cmov_l_rm_indexed(r2,(uintptr)cache_tags,r,SIZEOF_VOID_P,NATIVE_CC_EQ);
6949                          raw_jmp_r(r2);
6950                  }
6951                  else if (was_comp && isconst(PC_P)) {
# Line 6128 | Line 6953 | static void compile_block(cpu_history* p
6953                      uae_u32* tba;
6954                      blockinfo* tbi;
6955  
6956 <                    tbi=get_blockinfo_addr_new((void*)v,1);
6956 >                    tbi=get_blockinfo_addr_new((void*)(uintptr)v,1);
6957                      match_states(tbi);
6958  
6959 <                        raw_cmp_l_mi((uae_u32)specflags,0);
6959 >                        raw_cmp_l_mi((uintptr)specflags,0);
6960                          raw_jcc_l_oponly(4);
6961                      tba=(uae_u32*)get_target();
6962 <                    emit_long(get_handler(v)-((uae_u32)tba+4));
6963 <                    raw_mov_l_mi((uae_u32)&regs.pc_p,v);
6964 <                    raw_jmp((uae_u32)popall_do_nothing);
6962 >                    emit_long(get_handler(v)-((uintptr)tba+4));
6963 >                    raw_mov_l_mi((uintptr)&regs.pc_p,v);
6964 >                    raw_jmp((uintptr)popall_do_nothing);
6965                      create_jmpdep(bi,0,tba,v);
6966                  }
6967                  else {
6968                      r=REG_PC_TMP;
6969 <                    raw_mov_l_rm(r,(uae_u32)&regs.pc_p);
6969 >                    raw_mov_l_rm(r,(uintptr)&regs.pc_p);
6970                          raw_and_l_ri(r,TAGMASK);
6971                          int r2 = (r==0) ? 1 : 0;
6972 <                        raw_mov_l_ri(r2,(uae_u32)popall_do_nothing);
6973 <                        raw_cmp_l_mi((uae_u32)specflags,0);
6974 <                        raw_cmov_l_rm_indexed(r2,(uae_u32)cache_tags,r,4,4);
6972 >                        raw_mov_l_ri(r2,(uintptr)popall_do_nothing);
6973 >                        raw_cmp_l_mi((uintptr)specflags,0);
6974 >                        raw_cmov_l_rm_indexed(r2,(uintptr)cache_tags,r,SIZEOF_VOID_P,NATIVE_CC_EQ);
6975                          raw_jmp_r(r2);
6976                  }
6977              }
# Line 6160 | Line 6985 | static void compile_block(cpu_history* p
6985          big_to_small_state(&live,&(bi->env));
6986   #endif
6987  
6988 + #if USE_CHECKSUM_INFO
6989 +        remove_from_list(bi);
6990 +        if (trace_in_rom) {
6991 +                // No need to checksum that block trace on cache invalidation
6992 +                free_checksum_info_chain(bi->csi);
6993 +                bi->csi = NULL;
6994 +                add_to_dormant(bi);
6995 +        }
6996 +        else {
6997 +            calc_checksum(bi,&(bi->c1),&(bi->c2));
6998 +                add_to_active(bi);
6999 +        }
7000 + #else
7001          if (next_pc_p+extra_len>=max_pcp &&
7002              next_pc_p+extra_len<max_pcp+LONGEST_68K_INST)
7003              max_pcp=next_pc_p+extra_len;  /* extra_len covers flags magic */
7004          else
7005              max_pcp+=LONGEST_68K_INST;
7006 +
7007          bi->len=max_pcp-min_pcp;
7008          bi->min_pcp=min_pcp;
7009 <                    
7009 >        
7010          remove_from_list(bi);
7011          if (isinrom(min_pcp) && isinrom(max_pcp)) {
7012              add_to_dormant(bi); /* No need to checksum it on cache flush.
# Line 6178 | Line 7017 | static void compile_block(cpu_history* p
7017              calc_checksum(bi,&(bi->c1),&(bi->c2));
7018              add_to_active(bi);
7019          }
7020 + #endif
7021          
7022          current_cache_size += get_target() - (uae_u8 *)current_compile_p;
7023          
# Line 6197 | Line 7037 | static void compile_block(cpu_history* p
7037   #endif
7038          
7039          log_dump();
7040 <        align_target(32);
7040 >        align_target(align_jumps);
7041  
7042          /* This is the non-direct handler */
7043          bi->handler=
7044              bi->handler_to_use=(cpuop_func *)get_target();
7045 <        raw_cmp_l_mi((uae_u32)&regs.pc_p,(uae_u32)pc_hist[0].location);
7046 <        raw_jnz((uae_u32)popall_cache_miss);
7045 >        raw_cmp_l_mi((uintptr)&regs.pc_p,(uintptr)pc_hist[0].location);
7046 >        raw_jnz((uintptr)popall_cache_miss);
7047          comp_pc_p=(uae_u8*)pc_hist[0].location;
7048  
7049          bi->status=BI_FINALIZING;
# Line 6211 | Line 7051 | static void compile_block(cpu_history* p
7051          match_states(bi);
7052          flush(1);
7053  
7054 <        raw_jmp((uae_u32)bi->direct_handler);
7054 >        raw_jmp((uintptr)bi->direct_handler);
7055  
6216        align_target(32);
7056          current_compile_p=get_target();
6218
7057          raise_in_cl_list(bi);
7058          
7059          /* We will flush soon, anyway, so let's do it now */
# Line 6230 | Line 7068 | static void compile_block(cpu_history* p
7068          compile_time += (clock() - start_time);
7069   #endif
7070      }
7071 +
7072 +    /* Account for compilation time */
7073 +    cpu_do_check_ticks();
7074   }
7075  
7076   void do_nothing(void)
# Line 6241 | Line 7082 | void exec_nostats(void)
7082   {
7083          for (;;)  {
7084                  uae_u32 opcode = GET_OPCODE;
7085 < #ifdef X86_ASSEMBLY__disable
7086 <                __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);
7085 > #if FLIGHT_RECORDER
7086 >                m68k_record_step(m68k_getpc());
7087   #endif
7088 +                (*cpufunctbl[opcode])(opcode);
7089 +                cpu_check_ticks();
7090                  if (end_block(opcode) || SPCFLAGS_TEST(SPCFLAG_ALL)) {
7091                          return; /* We will deal with the spcflags in the caller */
7092                  }
# Line 6272 | Line 7111 | void execute_normal(void)
7111   #if FLIGHT_RECORDER
7112                          m68k_record_step(m68k_getpc());
7113   #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
7114                          (*cpufunctbl[opcode])(opcode);
7115 < #endif
7115 >                        cpu_check_ticks();
7116                          if (end_block(opcode) || SPCFLAGS_TEST(SPCFLAG_ALL) || blocklen>=MAXRUN) {
7117                                  compile_block(pc_hist, blocklen);
7118                                  return; /* We will deal with the spcflags in the caller */
# Line 6291 | Line 7125 | void execute_normal(void)
7125  
7126   typedef void (*compiled_handler)(void);
7127  
7128 + #if USE_PUSH_POP
7129   void m68k_do_compile_execute(void)
7130   {
7131          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
7132                  ((compiled_handler)(pushall_call_handler))();
6303 #endif
7133                  /* Whenever we return from that, we should check spcflags */
7134                  if (SPCFLAGS_TEST(SPCFLAG_ALL)) {
7135                          if (m68k_do_specialties ())
# Line 6308 | Line 7137 | void m68k_do_compile_execute(void)
7137                  }
7138          }
7139   }
7140 + #endif
7141 +
7142 + void m68k_compile_execute (void)
7143 + {
7144 +    for (;;) {
7145 +          if (quit_program)
7146 +                break;
7147 +          m68k_do_compile_execute();
7148 +    }
7149 + }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines