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.19 by gbeauche, 2003-10-02T09:51:14Z

# 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-2002
7 + *    Gwenole Beauchesne
8 + *
9 + *  Basilisk II (C) 1997-2002 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   #define USE_MATCH 0
35  
36   /* kludge for Brian, so he can compile under MSVC++ */
# Line 40 | Line 69
69   #endif
70  
71   #ifndef WIN32
72 < #define PROFILE_COMPILE_TIME    1
72 > #define PROFILE_COMPILE_TIME            1
73 > #define PROFILE_UNTRANSLATED_INSNS      1
74   #endif
75  
76   #ifdef WIN32
# Line 65 | Line 95 | static clock_t emul_start_time = 0;
95   static clock_t emul_end_time    = 0;
96   #endif
97  
98 + #if PROFILE_UNTRANSLATED_INSNS
99 + const int untranslated_top_ten = 20;
100 + static uae_u32 raw_cputbl_count[65536] = { 0, };
101 + static uae_u16 opcode_nums[65536];
102 +
103 + static int untranslated_compfn(const void *e1, const void *e2)
104 + {
105 +        return raw_cputbl_count[*(const uae_u16 *)e1] < raw_cputbl_count[*(const uae_u16 *)e2];
106 + }
107 + #endif
108 +
109   compop_func *compfunctbl[65536];
110   compop_func *nfcompfunctbl[65536];
111   cpuop_func *nfcpufunctbl[65536];
112   uae_u8* comp_pc_p;
113  
114 + // From newcpu.cpp
115 + extern bool quit_program;
116 +
117   // gb-- Extra data for Basilisk II/JIT
118   #if JIT_DEBUG
119   static bool             JITDebug                        = false;        // Enable runtime disassemblers through mon?
# Line 84 | Line 128 | static bool            lazy_flush                      = true;         // Fl
128   static bool             avoid_fpu                       = true;         // Flag: compile FPU instructions ?
129   static bool             have_cmov                       = false;        // target has CMOV instructions ?
130   static bool             have_rat_stall          = true;         // target has partial register stalls ?
131 + const bool              tune_alignment          = true;         // Tune code alignments for running CPU ?
132 + const bool              tune_nop_fillers        = true;         // Tune no-op fillers for architecture
133 + static bool             setzflg_uses_bsf        = false;        // setzflg virtual instruction can use native BSF instruction correctly?
134 + static int              align_loops                     = 32;           // Align the start of loops
135 + static int              align_jumps                     = 32;           // Align the start of jumps
136   static int              zero_fd                         = -1;
137   static int              optcount[10]            = {
138          10,             // How often a block has to be executed before it is translated
# Line 100 | Line 149 | struct op_properties {
149   };
150   static op_properties prop[65536];
151  
103 // gb-- Control Flow Predicates
104
152   static inline int end_block(uae_u32 opcode)
153   {
154          return (prop[opcode].cflow & fl_end_block);
155   }
156  
157 + static inline bool is_const_jump(uae_u32 opcode)
158 + {
159 +        return (prop[opcode].cflow == fl_const_jump);
160 + }
161 +
162   static inline bool may_trap(uae_u32 opcode)
163   {
164          return (prop[opcode].cflow & fl_trap);
165   }
166  
167 + static inline unsigned int cft_map (unsigned int f)
168 + {
169 + #ifndef HAVE_GET_WORD_UNSWAPPED
170 +    return f;
171 + #else
172 +    return ((f >> 8) & 255) | ((f & 255) << 8);
173 + #endif
174 + }
175 +
176   uae_u8* start_pc_p;
177   uae_u32 start_pc;
178   uae_u32 current_block_pc_p;
# Line 139 | Line 200 | static void* popall_cache_miss=NULL;
200   static void* popall_recompile_block=NULL;
201   static void* popall_check_checksum=NULL;
202  
142 extern uae_u32 oink;
143 extern unsigned long foink3;
144 extern unsigned long foink;
145
203   /* The 68k only ever executes from even addresses. So right now, we
204   * waste half the entries in this array
205   * UPDATE: We now use those entries to store the start of the linked
# Line 487 | Line 544 | static void prepare_block(blockinfo* bi)
544     compiled. If the list of free blockinfos is empty, we allocate a new
545     pool of blockinfos and link the newly created blockinfos altogether
546     into the list of free blockinfos. Otherwise, we simply pop a structure
547 <   of the free list.
547 >   off the free list.
548  
549     Blockinfo are lazily deallocated, i.e. chained altogether in the
550     list of free blockinfos whenvever a translation cache flush (hard or
551     soft) request occurs.
552   */
553  
554 < #if USE_SEPARATE_BIA
555 < const int BLOCKINFO_POOL_SIZE = 128;
556 < struct blockinfo_pool {
557 <        blockinfo bi[BLOCKINFO_POOL_SIZE];
558 <        blockinfo_pool *next;
554 > template< class T >
555 > class LazyBlockAllocator
556 > {
557 >        enum {
558 >                kPoolSize = 1 + 4096 / sizeof(T)
559 >        };
560 >        struct Pool {
561 >                T chunk[kPoolSize];
562 >                Pool * next;
563 >        };
564 >        Pool * mPools;
565 >        T * mChunks;
566 > public:
567 >        LazyBlockAllocator() : mPools(0), mChunks(0) { }
568 >        ~LazyBlockAllocator();
569 >        T * acquire();
570 >        void release(T * const);
571   };
503 static blockinfo_pool * blockinfo_pools = 0;
504 static blockinfo *              free_blockinfos = 0;
505 #endif
572  
573 < static __inline__ blockinfo *alloc_blockinfo(void)
573 > template< class T >
574 > LazyBlockAllocator<T>::~LazyBlockAllocator()
575   {
576 < #if USE_SEPARATE_BIA
577 <        if (!free_blockinfos) {
578 <                // There is no blockinfo struct left, allocate a new
579 <                // pool and link the chunks into the free list
580 <                blockinfo_pool *bi_pool = (blockinfo_pool *)malloc(sizeof(blockinfo_pool));
581 <                for (blockinfo *bi = &bi_pool->bi[0]; bi < &bi_pool->bi[BLOCKINFO_POOL_SIZE]; bi++) {
582 <                        bi->next = free_blockinfos;
583 <                        free_blockinfos = bi;
576 >        Pool * currentPool = mPools;
577 >        while (currentPool) {
578 >                Pool * deadPool = currentPool;
579 >                currentPool = currentPool->next;
580 >                free(deadPool);
581 >        }
582 > }
583 >
584 > template< class T >
585 > T * LazyBlockAllocator<T>::acquire()
586 > {
587 >        if (!mChunks) {
588 >                // There is no chunk left, allocate a new pool and link the
589 >                // chunks into the free list
590 >                Pool * newPool = (Pool *)malloc(sizeof(Pool));
591 >                for (T * chunk = &newPool->chunk[0]; chunk < &newPool->chunk[kPoolSize]; chunk++) {
592 >                        chunk->next = mChunks;
593 >                        mChunks = chunk;
594                  }
595 <                bi_pool->next = blockinfo_pools;
596 <                blockinfo_pools = bi_pool;
595 >                newPool->next = mPools;
596 >                mPools = newPool;
597          }
598 <        blockinfo *bi = free_blockinfos;
599 <        free_blockinfos = bi->next;
600 < #else
524 <        blockinfo *bi = (blockinfo*)current_compile_p;
525 <        current_compile_p += sizeof(blockinfo);
526 < #endif
527 <        return bi;
598 >        T * chunk = mChunks;
599 >        mChunks = chunk->next;
600 >        return chunk;
601   }
602  
603 < static __inline__ void free_blockinfo(blockinfo *bi)
603 > template< class T >
604 > void LazyBlockAllocator<T>::release(T * const chunk)
605 > {
606 >        chunk->next = mChunks;
607 >        mChunks = chunk;
608 > }
609 >
610 > template< class T >
611 > class HardBlockAllocator
612   {
613 + public:
614 +        T * acquire() {
615 +                T * data = (T *)current_compile_p;
616 +                current_compile_p += sizeof(T);
617 +                return data;
618 +        }
619 +
620 +        void release(T * const chunk) {
621 +                // Deallocated on invalidation
622 +        }
623 + };
624 +
625   #if USE_SEPARATE_BIA
626 <        bi->next = free_blockinfos;
627 <        free_blockinfos = bi;
626 > static LazyBlockAllocator<blockinfo> BlockInfoAllocator;
627 > static LazyBlockAllocator<checksum_info> ChecksumInfoAllocator;
628 > #else
629 > static HardBlockAllocator<blockinfo> BlockInfoAllocator;
630 > static HardBlockAllocator<checksum_info> ChecksumInfoAllocator;
631   #endif
632 +
633 + static __inline__ checksum_info *alloc_checksum_info(void)
634 + {
635 +        checksum_info *csi = ChecksumInfoAllocator.acquire();
636 +        csi->next = NULL;
637 +        return csi;
638   }
639  
640 < static void free_blockinfo_pools(void)
640 > static __inline__ void free_checksum_info(checksum_info *csi)
641   {
642 < #if USE_SEPARATE_BIA
643 <        int blockinfo_pool_count = 0;
644 <        blockinfo_pool *curr_pool = blockinfo_pools;
645 <        while (curr_pool) {
646 <                blockinfo_pool_count++;
647 <                blockinfo_pool *dead_pool = curr_pool;
648 <                curr_pool = curr_pool->next;
649 <                free(dead_pool);
642 >        csi->next = NULL;
643 >        ChecksumInfoAllocator.release(csi);
644 > }
645 >
646 > static __inline__ void free_checksum_info_chain(checksum_info *csi)
647 > {
648 >        while (csi != NULL) {
649 >                checksum_info *csi2 = csi->next;
650 >                free_checksum_info(csi);
651 >                csi = csi2;
652          }
653 <        
654 <        uae_u32 blockinfo_pools_size = blockinfo_pool_count * BLOCKINFO_POOL_SIZE * sizeof(blockinfo);
655 <        write_log("### Blockinfo allocation statistics\n");
656 <        write_log("Number of blockinfo pools  : %d\n", blockinfo_pool_count);
657 <        write_log("Total number of blockinfos : %d (%d KB)\n",
658 <                          blockinfo_pool_count * BLOCKINFO_POOL_SIZE,
659 <                          blockinfo_pools_size / 1024);
660 <        write_log("\n");
653 > }
654 >
655 > static __inline__ blockinfo *alloc_blockinfo(void)
656 > {
657 >        blockinfo *bi = BlockInfoAllocator.acquire();
658 > #if USE_CHECKSUM_INFO
659 >        bi->csi = NULL;
660 > #endif
661 >        return bi;
662 > }
663 >
664 > static __inline__ void free_blockinfo(blockinfo *bi)
665 > {
666 > #if USE_CHECKSUM_INFO
667 >        free_checksum_info_chain(bi->csi);
668 >        bi->csi = NULL;
669   #endif
670 +        BlockInfoAllocator.release(bi);
671   }
672  
673   static __inline__ void alloc_blockinfos(void)
# Line 597 | Line 710 | static __inline__ void emit_long(uae_u32
710      target+=4;
711   }
712  
713 + static __inline__ void emit_block(const uae_u8 *block, uae_u32 blocklen)
714 + {
715 +        memcpy((uae_u8 *)target,block,blocklen);
716 +        target+=blocklen;
717 + }
718 +
719   static __inline__ uae_u32 reverse32(uae_u32 v)
720   {
721   #if 1
# Line 693 | Line 812 | static __inline__ void flush_flags(void)
812   int touchcnt;
813  
814   /********************************************************************
815 + * Partial register flushing for optimized calls                    *
816 + ********************************************************************/
817 +
818 + struct regusage {
819 +        uae_u16 rmask;
820 +        uae_u16 wmask;
821 + };
822 +
823 + static inline void ru_set(uae_u16 *mask, int reg)
824 + {
825 + #if USE_OPTIMIZED_CALLS
826 +        *mask |= 1 << reg;
827 + #endif
828 + }
829 +
830 + static inline bool ru_get(const uae_u16 *mask, int reg)
831 + {
832 + #if USE_OPTIMIZED_CALLS
833 +        return (*mask & (1 << reg));
834 + #else
835 +        /* Default: instruction reads & write to register */
836 +        return true;
837 + #endif
838 + }
839 +
840 + static inline void ru_set_read(regusage *ru, int reg)
841 + {
842 +        ru_set(&ru->rmask, reg);
843 + }
844 +
845 + static inline void ru_set_write(regusage *ru, int reg)
846 + {
847 +        ru_set(&ru->wmask, reg);
848 + }
849 +
850 + static inline bool ru_read_p(const regusage *ru, int reg)
851 + {
852 +        return ru_get(&ru->rmask, reg);
853 + }
854 +
855 + static inline bool ru_write_p(const regusage *ru, int reg)
856 + {
857 +        return ru_get(&ru->wmask, reg);
858 + }
859 +
860 + static void ru_fill_ea(regusage *ru, int reg, amodes mode,
861 +                                           wordsizes size, int write_mode)
862 + {
863 +        switch (mode) {
864 +        case Areg:
865 +                reg += 8;
866 +                /* fall through */
867 +        case Dreg:
868 +                ru_set(write_mode ? &ru->wmask : &ru->rmask, reg);
869 +                break;
870 +        case Ad16:
871 +                /* skip displacment */
872 +                m68k_pc_offset += 2;
873 +        case Aind:
874 +        case Aipi:
875 +        case Apdi:
876 +                ru_set_read(ru, reg+8);
877 +                break;
878 +        case Ad8r:
879 +                ru_set_read(ru, reg+8);
880 +                /* fall through */
881 +        case PC8r: {
882 +                uae_u16 dp = comp_get_iword((m68k_pc_offset+=2)-2);
883 +                reg = (dp >> 12) & 15;
884 +                ru_set_read(ru, reg);
885 +                if (dp & 0x100)
886 +                        m68k_pc_offset += (((dp & 0x30) >> 3) & 7) + ((dp & 3) * 2);
887 +                break;
888 +        }
889 +        case PC16:
890 +        case absw:
891 +        case imm0:
892 +        case imm1:
893 +                m68k_pc_offset += 2;
894 +                break;
895 +        case absl:
896 +        case imm2:
897 +                m68k_pc_offset += 4;
898 +                break;
899 +        case immi:
900 +                m68k_pc_offset += (size == sz_long) ? 4 : 2;
901 +                break;
902 +        }
903 + }
904 +
905 + /* TODO: split into a static initialization part and a dynamic one
906 +   (instructions depending on extension words) */
907 + static void ru_fill(regusage *ru, uae_u32 opcode)
908 + {
909 +        m68k_pc_offset += 2;
910 +
911 +        /* Default: no register is used or written to */
912 +        ru->rmask = 0;
913 +        ru->wmask = 0;
914 +
915 +        uae_u32 real_opcode = cft_map(opcode);
916 +        struct instr *dp = &table68k[real_opcode];
917 +
918 +        bool rw_dest = true;
919 +        bool handled = false;
920 +
921 +        /* Handle some instructions specifically */
922 +        uae_u16 reg, ext;
923 +        switch (dp->mnemo) {
924 +        case i_BFCHG:
925 +        case i_BFCLR:
926 +        case i_BFEXTS:
927 +        case i_BFEXTU:
928 +        case i_BFFFO:
929 +        case i_BFINS:
930 +        case i_BFSET:
931 +        case i_BFTST:
932 +                ext = comp_get_iword((m68k_pc_offset+=2)-2);
933 +                if (ext & 0x800) ru_set_read(ru, (ext >> 6) & 7);
934 +                if (ext & 0x020) ru_set_read(ru, ext & 7);
935 +                ru_fill_ea(ru, dp->dreg, (amodes)dp->dmode, (wordsizes)dp->size, 1);
936 +                if (dp->dmode == Dreg)
937 +                        ru_set_read(ru, dp->dreg);
938 +                switch (dp->mnemo) {
939 +                case i_BFEXTS:
940 +                case i_BFEXTU:
941 +                case i_BFFFO:
942 +                        ru_set_write(ru, (ext >> 12) & 7);
943 +                        break;
944 +                case i_BFINS:
945 +                        ru_set_read(ru, (ext >> 12) & 7);
946 +                        /* fall through */
947 +                case i_BFCHG:
948 +                case i_BFCLR:
949 +                case i_BSET:
950 +                        if (dp->dmode == Dreg)
951 +                                ru_set_write(ru, dp->dreg);
952 +                        break;
953 +                }
954 +                handled = true;
955 +                rw_dest = false;
956 +                break;
957 +
958 +        case i_BTST:
959 +                rw_dest = false;
960 +                break;
961 +
962 +        case i_CAS:
963 +        {
964 +                ext = comp_get_iword((m68k_pc_offset+=2)-2);
965 +                int Du = ext & 7;
966 +                ru_set_read(ru, Du);
967 +                int Dc = (ext >> 6) & 7;
968 +                ru_set_read(ru, Dc);
969 +                ru_set_write(ru, Dc);
970 +                break;
971 +        }
972 +        case i_CAS2:
973 +        {
974 +                int Dc1, Dc2, Du1, Du2, Rn1, Rn2;
975 +                ext = comp_get_iword((m68k_pc_offset+=2)-2);
976 +                Rn1 = (ext >> 12) & 15;
977 +                Du1 = (ext >> 6) & 7;
978 +                Dc1 = ext & 7;
979 +                ru_set_read(ru, Rn1);
980 +                ru_set_read(ru, Du1);
981 +                ru_set_read(ru, Dc1);
982 +                ru_set_write(ru, Dc1);
983 +                ext = comp_get_iword((m68k_pc_offset+=2)-2);
984 +                Rn2 = (ext >> 12) & 15;
985 +                Du2 = (ext >> 6) & 7;
986 +                Dc2 = ext & 7;
987 +                ru_set_read(ru, Rn2);
988 +                ru_set_read(ru, Du2);
989 +                ru_set_write(ru, Dc2);
990 +                break;
991 +        }
992 +        case i_DIVL: case i_MULL:
993 +                m68k_pc_offset += 2;
994 +                break;
995 +        case i_LEA:
996 +        case i_MOVE: case i_MOVEA: case i_MOVE16:
997 +                rw_dest = false;
998 +                break;
999 +        case i_PACK: case i_UNPK:
1000 +                rw_dest = false;
1001 +                m68k_pc_offset += 2;
1002 +                break;
1003 +        case i_TRAPcc:
1004 +                m68k_pc_offset += (dp->size == sz_long) ? 4 : 2;
1005 +                break;
1006 +        case i_RTR:
1007 +                /* do nothing, just for coverage debugging */
1008 +                break;
1009 +        /* TODO: handle EXG instruction */
1010 +        }
1011 +
1012 +        /* Handle A-Traps better */
1013 +        if ((real_opcode & 0xf000) == 0xa000) {
1014 +                handled = true;
1015 +        }
1016 +
1017 +        /* Handle EmulOps better */
1018 +        if ((real_opcode & 0xff00) == 0x7100) {
1019 +                handled = true;
1020 +                ru->rmask = 0xffff;
1021 +                ru->wmask = 0;
1022 +        }
1023 +
1024 +        if (dp->suse && !handled)
1025 +                ru_fill_ea(ru, dp->sreg, (amodes)dp->smode, (wordsizes)dp->size, 0);
1026 +
1027 +        if (dp->duse && !handled)
1028 +                ru_fill_ea(ru, dp->dreg, (amodes)dp->dmode, (wordsizes)dp->size, 1);
1029 +
1030 +        if (rw_dest)
1031 +                ru->rmask |= ru->wmask;
1032 +
1033 +        handled = handled || dp->suse || dp->duse;
1034 +
1035 +        /* Mark all registers as used/written if the instruction may trap */
1036 +        if (may_trap(opcode)) {
1037 +                handled = true;
1038 +                ru->rmask = 0xffff;
1039 +                ru->wmask = 0xffff;
1040 +        }
1041 +
1042 +        if (!handled) {
1043 +                write_log("ru_fill: %04x = { %04x, %04x }\n",
1044 +                                  real_opcode, ru->rmask, ru->wmask);
1045 +                abort();
1046 +        }
1047 + }
1048 +
1049 + /********************************************************************
1050   * register allocation per block logging                            *
1051   ********************************************************************/
1052  
# Line 1827 | Line 2181 | static void fflags_into_flags_internal(u
2181          else
2182      raw_fflags_into_flags(r);
2183      f_unlock(r);
2184 +    live_flags();
2185   }
2186  
2187  
# Line 2562 | Line 2917 | MIDFUNC(3,cmov_l_rm,(RW4 d, IMM s, IMM c
2917   }
2918   MENDFUNC(3,cmov_l_rm,(RW4 d, IMM s, IMM cc))
2919  
2920 < MIDFUNC(2,bsf_l_rr,(W4 d, R4 s))
2920 > MIDFUNC(1,setzflg_l,(RW4 r))
2921   {
2922 <    CLOBBER_BSF;
2923 <    s=readreg(s,4);
2924 <    d=writereg(d,4);
2925 <    raw_bsf_l_rr(d,s);
2926 <    unlock2(s);
2927 <    unlock2(d);
2922 >        if (setzflg_uses_bsf) {
2923 >                CLOBBER_BSF;
2924 >                r=rmw(r,4,4);
2925 >                raw_bsf_l_rr(r,r);
2926 >                unlock2(r);
2927 >        }
2928 >        else {
2929 >                Dif (live.flags_in_flags!=VALID) {
2930 >                        write_log("setzflg() wanted flags in native flags, they are %d\n",
2931 >                                          live.flags_in_flags);
2932 >                        abort();
2933 >                }
2934 >                r=readreg(r,4);
2935 >                int f=writereg(S11,4);
2936 >                int t=writereg(S12,4);
2937 >                raw_flags_set_zero(f,r,t);
2938 >                unlock2(f);
2939 >                unlock2(r);
2940 >                unlock2(t);
2941 >        }
2942   }
2943 < MENDFUNC(2,bsf_l_rr,(W4 d, R4 s))
2943 > MENDFUNC(1,setzflg_l,(RW4 r))
2944  
2945   MIDFUNC(2,imul_32_32,(RW4 d, R4 s))
2946   {
# Line 4509 | Line 4878 | static inline const char *str_on_off(boo
4878          return b ? "on" : "off";
4879   }
4880  
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
4881   void compiler_init(void)
4882   {
4883          static bool initialized = false;
# Line 4556 | Line 4916 | void compiler_init(void)
4916          
4917          // Initialize target CPU (check for features, e.g. CMOV, rat stalls)
4918          raw_init_cpu();
4919 +        setzflg_uses_bsf = target_check_bsf();
4920          write_log("<JIT compiler> : target processor has CMOV instructions : %s\n", have_cmov ? "yes" : "no");
4921          write_log("<JIT compiler> : target processor can suffer from partial register stalls : %s\n", have_rat_stall ? "yes" : "no");
4922 +        write_log("<JIT compiler> : alignment for loops, jumps are %d, %d\n", align_loops, align_jumps);
4923          
4924          // Translation cache flush mechanism
4925          lazy_flush = PrefsFindBool("jitlazyflush");
# Line 4568 | Line 4930 | void compiler_init(void)
4930          write_log("<JIT compiler> : register aliasing : %s\n", str_on_off(1));
4931          write_log("<JIT compiler> : FP register aliasing : %s\n", str_on_off(USE_F_ALIAS));
4932          write_log("<JIT compiler> : lazy constant offsetting : %s\n", str_on_off(USE_OFFSET));
4933 +        write_log("<JIT compiler> : block inlining : %s\n", str_on_off(USE_INLINING));
4934          write_log("<JIT compiler> : separate blockinfo allocation : %s\n", str_on_off(USE_SEPARATE_BIA));
4935          
4936          // Build compiler tables
# Line 4575 | Line 4938 | void compiler_init(void)
4938          
4939          initialized = true;
4940          
4941 + #if PROFILE_UNTRANSLATED_INSNS
4942 +        write_log("<JIT compiler> : gather statistics on untranslated insns count\n");
4943 + #endif
4944 +
4945   #if PROFILE_COMPILE_TIME
4946          write_log("<JIT compiler> : gather statistics on translation time\n");
4947          emul_start_time = clock();
# Line 4593 | Line 4960 | void compiler_exit(void)
4960                  compiled_code = 0;
4961          }
4962          
4596        // Deallocate blockinfo pools
4597        free_blockinfo_pools();
4598        
4963   #ifndef WIN32
4964          // Close /dev/zero
4965          if (zero_fd > 0)
# Line 4611 | Line 4975 | void compiler_exit(void)
4975                  100.0*double(compile_time)/double(emul_time));
4976          write_log("\n");
4977   #endif
4978 +
4979 + #if PROFILE_UNTRANSLATED_INSNS
4980 +        uae_u64 untranslated_count = 0;
4981 +        for (int i = 0; i < 65536; i++) {
4982 +                opcode_nums[i] = i;
4983 +                untranslated_count += raw_cputbl_count[i];
4984 +        }
4985 +        write_log("Sorting out untranslated instructions count...\n");
4986 +        qsort(opcode_nums, 65536, sizeof(uae_u16), untranslated_compfn);
4987 +        write_log("\nRank  Opc      Count Name\n");
4988 +        for (int i = 0; i < untranslated_top_ten; i++) {
4989 +                uae_u32 count = raw_cputbl_count[opcode_nums[i]];
4990 +                struct instr *dp;
4991 +                struct mnemolookup *lookup;
4992 +                if (!count)
4993 +                        break;
4994 +                dp = table68k + opcode_nums[i];
4995 +                for (lookup = lookuptab; lookup->mnemo != dp->mnemo; lookup++)
4996 +                        ;
4997 +                write_log("%03d: %04x %10lu %s\n", i, opcode_nums[i], count, lookup->name);
4998 +        }
4999 + #endif
5000   }
5001  
5002   bool compiler_use_jit(void)
# Line 4839 | Line 5225 | void freescratch(void)
5225  
5226   static void align_target(uae_u32 a)
5227   {
5228 <    /* Fill with NOPs --- makes debugging with gdb easier */
5229 <    while ((uae_u32)target&(a-1))
5230 <        *target++=0x90;
5228 >        if (!a)
5229 >                return;
5230 >
5231 >        if (tune_nop_fillers)
5232 >                raw_emit_nop_filler(a - (((uae_u32)target) & (a - 1)));
5233 >        else {
5234 >                /* Fill with NOPs --- makes debugging with gdb easier */
5235 >                while ((uae_u32)target&(a-1))
5236 >                        *target++=0x90;
5237 >        }
5238   }
5239  
5240   static __inline__ int isinrom(uintptr addr)
# Line 5166 | Line 5559 | void alloc_cache(void)
5559  
5560  
5561  
5562 < extern cpuop_rettype op_illg_1 (uae_u32 opcode) REGPARAM;
5562 > extern void op_illg_1 (uae_u32 opcode) REGPARAM;
5563  
5564   static void calc_checksum(blockinfo* bi, uae_u32* c1, uae_u32* c2)
5565   {
5566 <    uae_u32 k1=0;
5567 <    uae_u32 k2=0;
5175 <    uae_s32 len=bi->len;
5176 <    uae_u32 tmp=bi->min_pcp;
5177 <    uae_u32* pos;
5566 >    uae_u32 k1 = 0;
5567 >    uae_u32 k2 = 0;
5568  
5569 <    len+=(tmp&3);
5570 <    tmp&=(~3);
5571 <    pos=(uae_u32*)tmp;
5569 > #if USE_CHECKSUM_INFO
5570 >    checksum_info *csi = bi->csi;
5571 >        Dif(!csi) abort();
5572 >        while (csi) {
5573 >                uae_s32 len = csi->length;
5574 >                uae_u32 tmp = (uae_u32)csi->start_p;
5575 > #else
5576 >                uae_s32 len = bi->len;
5577 >                uae_u32 tmp = (uae_u32)bi->min_pcp;
5578 > #endif
5579 >                uae_u32*pos;
5580  
5581 <    if (len<0 || len>MAX_CHECKSUM_LEN) {
5582 <        *c1=0;
5583 <        *c2=0;
5584 <    }
5585 <    else {
5586 <        while (len>0) {
5587 <            k1+=*pos;
5588 <            k2^=*pos;
5589 <            pos++;
5590 <            len-=4;
5581 >                len += (tmp & 3);
5582 >                tmp &= ~3;
5583 >                pos = (uae_u32 *)tmp;
5584 >
5585 >                if (len >= 0 && len <= MAX_CHECKSUM_LEN) {
5586 >                        while (len > 0) {
5587 >                                k1 += *pos;
5588 >                                k2 ^= *pos;
5589 >                                pos++;
5590 >                                len -= 4;
5591 >                        }
5592 >                }
5593 >
5594 > #if USE_CHECKSUM_INFO
5595 >                csi = csi->next;
5596          }
5597 <        *c1=k1;
5598 <        *c2=k2;
5599 <    }
5597 > #endif
5598 >
5599 >        *c1 = k1;
5600 >        *c2 = k2;
5601   }
5602  
5603 < static void show_checksum(blockinfo* bi)
5603 > #if 0
5604 > static void show_checksum(CSI_TYPE* csi)
5605   {
5606      uae_u32 k1=0;
5607      uae_u32 k2=0;
5608 <    uae_s32 len=bi->len;
5609 <    uae_u32 tmp=(uae_u32)bi->pc_p;
5608 >    uae_s32 len=CSI_LENGTH(csi);
5609 >    uae_u32 tmp=(uae_u32)CSI_START_P(csi);
5610      uae_u32* pos;
5611  
5612      len+=(tmp&3);
# Line 5220 | Line 5625 | static void show_checksum(blockinfo* bi)
5625          write_log(" bla\n");
5626      }
5627   }
5628 + #endif
5629  
5630  
5631   int check_for_cache_miss(void)
# Line 5273 | Line 5679 | static int called_check_checksum(blockin
5679   static inline int block_check_checksum(blockinfo* bi)
5680   {
5681      uae_u32     c1,c2;
5682 <    int         isgood;
5682 >    bool        isgood;
5683      
5684      if (bi->status!=BI_NEED_CHECK)
5685          return 1;  /* This block is in a checked state */
5686      
5687      checksum_count++;
5688 +
5689      if (bi->c1 || bi->c2)
5690          calc_checksum(bi,&c1,&c2);
5691      else {
5692          c1=c2=1;  /* Make sure it doesn't match */
5693 <    }
5693 >        }
5694      
5695      isgood=(c1==bi->c1 && c2==bi->c2);
5696 +
5697      if (isgood) {
5698          /* This block is still OK. So we reactivate. Of course, that
5699             means we have to move it into the needs-to-be-flushed list */
# Line 5403 | Line 5811 | static __inline__ void create_popalls(vo
5811       registers before jumping back to the various get-out routines.
5812       This generates the code for it.
5813    */
5814 <  popall_do_nothing=current_compile_p;
5814 >  align_target(align_jumps);
5815 >  popall_do_nothing=get_target();
5816    for (i=0;i<N_REGS;i++) {
5817        if (need_to_preserve[i])
5818            raw_pop_l_r(i);
5819    }
5820    raw_jmp((uae_u32)do_nothing);
5412  align_target(32);
5821    
5822 +  align_target(align_jumps);
5823    popall_execute_normal=get_target();
5824    for (i=0;i<N_REGS;i++) {
5825        if (need_to_preserve[i])
5826            raw_pop_l_r(i);
5827    }
5828    raw_jmp((uae_u32)execute_normal);
5420  align_target(32);
5829  
5830 +  align_target(align_jumps);
5831    popall_cache_miss=get_target();
5832    for (i=0;i<N_REGS;i++) {
5833        if (need_to_preserve[i])
5834            raw_pop_l_r(i);
5835    }
5836    raw_jmp((uae_u32)cache_miss);
5428  align_target(32);
5837  
5838 +  align_target(align_jumps);
5839    popall_recompile_block=get_target();
5840    for (i=0;i<N_REGS;i++) {
5841        if (need_to_preserve[i])
5842            raw_pop_l_r(i);
5843    }
5844    raw_jmp((uae_u32)recompile_block);
5845 <  align_target(32);
5846 <  
5845 >
5846 >  align_target(align_jumps);
5847    popall_exec_nostats=get_target();
5848    for (i=0;i<N_REGS;i++) {
5849        if (need_to_preserve[i])
5850            raw_pop_l_r(i);
5851    }
5852    raw_jmp((uae_u32)exec_nostats);
5853 <  align_target(32);
5854 <  
5853 >
5854 >  align_target(align_jumps);
5855    popall_check_checksum=get_target();
5856    for (i=0;i<N_REGS;i++) {
5857        if (need_to_preserve[i])
5858            raw_pop_l_r(i);
5859    }
5860    raw_jmp((uae_u32)check_checksum);
5861 <  align_target(32);
5862 <  
5861 >
5862 >  align_target(align_jumps);
5863    current_compile_p=get_target();
5864   #else
5865    popall_exec_nostats=(void *)exec_nostats;
# Line 5459 | Line 5868 | static __inline__ void create_popalls(vo
5868    popall_recompile_block=(void *)recompile_block;
5869    popall_do_nothing=(void *)do_nothing;
5870    popall_check_checksum=(void *)check_checksum;
5462  pushall_call_handler=get_target();  
5871   #endif
5872  
5873    /* And now, the code to do the matching pushes and then jump
# Line 5475 | Line 5883 | static __inline__ void create_popalls(vo
5883    raw_mov_l_rm(r,(uae_u32)&regs.pc_p);
5884    raw_and_l_ri(r,TAGMASK);
5885    raw_jmp_m_indexed((uae_u32)cache_tags,r,4);
5886 +
5887 + #ifdef X86_ASSEMBLY
5888 +  align_target(align_jumps);
5889 +  m68k_compile_execute = (void (*)(void))get_target();
5890 +  for (i=N_REGS;i--;) {
5891 +          if (need_to_preserve[i])
5892 +                  raw_push_l_r(i);
5893 +  }
5894 +  align_target(align_loops);
5895 +  uae_u32 dispatch_loop = (uae_u32)get_target();
5896 +  r=REG_PC_TMP;
5897 +  raw_mov_l_rm(r,(uae_u32)&regs.pc_p);
5898 +  raw_and_l_ri(r,TAGMASK);
5899 +  raw_call_m_indexed((uae_u32)cache_tags,r,4);
5900 +  raw_cmp_l_mi((uae_u32)&regs.spcflags,0);
5901 +  raw_jcc_b_oponly(NATIVE_CC_EQ);
5902 +  emit_byte(dispatch_loop-((uae_u32)get_target()+1));
5903 +  raw_call((uae_u32)m68k_do_specialties);
5904 +  raw_test_l_rr(REG_RESULT,REG_RESULT);
5905 +  raw_jcc_b_oponly(NATIVE_CC_EQ);
5906 +  emit_byte(dispatch_loop-((uae_u32)get_target()+1));
5907 +  raw_cmp_b_mi((uae_u32)&quit_program,0);
5908 +  raw_jcc_b_oponly(NATIVE_CC_EQ);
5909 +  emit_byte(dispatch_loop-((uae_u32)get_target()+1));
5910 +  for (i=0;i<N_REGS;i++) {
5911 +          if (need_to_preserve[i])
5912 +                  raw_pop_l_r(i);
5913 +  }
5914 +  raw_ret();
5915 + #endif
5916   }
5917  
5918   static __inline__ void reset_lists(void)
# Line 5492 | Line 5930 | static void prepare_block(blockinfo* bi)
5930      int i;
5931  
5932      set_target(current_compile_p);
5933 <    align_target(32);
5933 >    align_target(align_jumps);
5934      bi->direct_pen=(cpuop_func *)get_target();
5935      raw_mov_l_rm(0,(uae_u32)&(bi->pc_p));
5936      raw_mov_l_mr((uae_u32)&regs.pc_p,0);
5937      raw_jmp((uae_u32)popall_execute_normal);
5938  
5939 <    align_target(32);
5939 >    align_target(align_jumps);
5940      bi->direct_pcc=(cpuop_func *)get_target();
5941      raw_mov_l_rm(0,(uae_u32)&(bi->pc_p));
5942      raw_mov_l_mr((uae_u32)&regs.pc_p,0);
5943      raw_jmp((uae_u32)popall_check_checksum);
5506
5507    align_target(32);
5944      current_compile_p=get_target();
5945  
5946      bi->deplist=NULL;
# Line 5518 | Line 5954 | static void prepare_block(blockinfo* bi)
5954      //bi->env=empty_ss;
5955   }
5956  
5957 + static bool avoid_opcode(uae_u32 opcode)
5958 + {
5959 + #if JIT_DEBUG
5960 +        struct instr *dp = &table68k[opcode];
5961 +        // filter opcodes per type, integral value, or whatever
5962 + #endif
5963 +        return false;
5964 + }
5965 +
5966   void build_comp(void)
5967   {
5968          int i;
# Line 5557 | Line 6002 | void build_comp(void)
6002          
6003          for (i = 0; tbl[i].opcode < 65536; i++) {
6004                  int cflow = table68k[tbl[i].opcode].cflow;
6005 +                if (USE_INLINING && ((cflow & fl_const_jump) != 0))
6006 +                        cflow = fl_const_jump;
6007 +                else
6008 +                        cflow &= ~fl_const_jump;
6009                  prop[cft_map(tbl[i].opcode)].cflow = cflow;
6010  
6011                  int uses_fpu = tbl[i].specific & 32;
6012 <                if (uses_fpu && avoid_fpu)
6012 >                if ((uses_fpu && avoid_fpu) || avoid_opcode(tbl[i].opcode))
6013                          compfunctbl[cft_map(tbl[i].opcode)] = NULL;
6014                  else
6015                          compfunctbl[cft_map(tbl[i].opcode)] = tbl[i].handler;
# Line 5568 | Line 6017 | void build_comp(void)
6017  
6018      for (i = 0; nftbl[i].opcode < 65536; i++) {
6019                  int uses_fpu = tbl[i].specific & 32;
6020 <                if (uses_fpu && avoid_fpu)
6020 >                if ((uses_fpu && avoid_fpu) || avoid_opcode(nftbl[i].opcode))
6021                          nfcompfunctbl[cft_map(nftbl[i].opcode)] = NULL;
6022                  else
6023                          nfcompfunctbl[cft_map(nftbl[i].opcode)] = nftbl[i].handler;
# Line 5850 | Line 6299 | static void compile_block(cpu_history* p
6299          int r;
6300          int was_comp=0;
6301          uae_u8 liveflags[MAXRUN+1];
6302 + #if USE_CHECKSUM_INFO
6303 +        bool trace_in_rom = isinrom((uintptr)pc_hist[0].location);
6304 +        uae_u32 max_pcp=(uae_u32)pc_hist[blocklen - 1].location;
6305 +        uae_u32 min_pcp=max_pcp;
6306 + #else
6307          uae_u32 max_pcp=(uae_u32)pc_hist[0].location;
6308          uae_u32 min_pcp=max_pcp;
6309 + #endif
6310          uae_u32 cl=cacheline(pc_hist[0].location);
6311          void* specflags=(void*)&regs.spcflags;
6312          blockinfo* bi=NULL;
# Line 5895 | Line 6350 | static void compile_block(cpu_history* p
6350          remove_deps(bi); /* We are about to create new code */
6351          bi->optlevel=optlev;
6352          bi->pc_p=(uae_u8*)pc_hist[0].location;
6353 + #if USE_CHECKSUM_INFO
6354 +        free_checksum_info_chain(bi->csi);
6355 +        bi->csi = NULL;
6356 + #endif
6357          
6358          liveflags[blocklen]=0x1f; /* All flags needed afterwards */
6359          i=blocklen;
# Line 5902 | Line 6361 | static void compile_block(cpu_history* p
6361              uae_u16* currpcp=pc_hist[i].location;
6362              uae_u32 op=DO_GET_OPCODE(currpcp);
6363  
6364 + #if USE_CHECKSUM_INFO
6365 +                trace_in_rom = trace_in_rom && isinrom((uintptr)currpcp);
6366 + #if USE_INLINING
6367 +                if (is_const_jump(op)) {
6368 +                        checksum_info *csi = alloc_checksum_info();
6369 +                        csi->start_p = (uae_u8 *)min_pcp;
6370 +                        csi->length = max_pcp - min_pcp + LONGEST_68K_INST;
6371 +                        csi->next = bi->csi;
6372 +                        bi->csi = csi;
6373 +                        max_pcp = (uae_u32)currpcp;
6374 +                }
6375 + #endif
6376 +                min_pcp = (uae_u32)currpcp;
6377 + #else
6378              if ((uae_u32)currpcp<min_pcp)
6379                  min_pcp=(uae_u32)currpcp;
6380              if ((uae_u32)currpcp>max_pcp)
6381                  max_pcp=(uae_u32)currpcp;
6382 + #endif
6383  
6384                  liveflags[i]=((liveflags[i+1]&
6385                                 (~prop[op].set_flags))|
# Line 5914 | Line 6388 | static void compile_block(cpu_history* p
6388                      liveflags[i]&= ~FLAG_Z;
6389          }
6390  
6391 + #if USE_CHECKSUM_INFO
6392 +        checksum_info *csi = alloc_checksum_info();
6393 +        csi->start_p = (uae_u8 *)min_pcp;
6394 +        csi->length = max_pcp - min_pcp + LONGEST_68K_INST;
6395 +        csi->next = bi->csi;
6396 +        bi->csi = csi;
6397 + #endif
6398 +
6399          bi->needed_flags=liveflags[0];
6400  
6401 <        align_target(32);
6401 >        align_target(align_loops);
6402          was_comp=0;
6403  
6404          bi->direct_handler=(cpuop_func *)get_target();
# Line 5975 | Line 6457 | static void compile_block(cpu_history* p
6457                          comp_pc_p=(uae_u8*)pc_hist[i].location;
6458                          init_comp();
6459                      }
6460 <                    was_comp++;
6460 >                    was_comp=1;
6461  
6462                      comptbl[opcode](opcode);
6463                      freescratch();
# Line 6003 | Line 6485 | static void compile_block(cpu_history* p
6485                      raw_mov_l_mi((uae_u32)&regs.pc_p,
6486                                   (uae_u32)pc_hist[i].location);
6487                      raw_call((uae_u32)cputbl[opcode]);
6488 <                    //raw_add_l_mi((uae_u32)&oink,1); // FIXME
6488 > #if PROFILE_UNTRANSLATED_INSNS
6489 >                        // raw_cputbl_count[] is indexed with plain opcode (in m68k order)
6490 >                        raw_add_l_mi((uae_u32)&raw_cputbl_count[cft_map(opcode)],1);
6491 > #endif
6492   #if USE_NORMAL_CALLING_CONVENTION
6493                      raw_inc_sp(4);
6494   #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                    }
6495                      
6496                      if (i < blocklen - 1) {
6497                          uae_s8* branchadd;
# Line 6091 | Line 6570 | static void compile_block(cpu_history* p
6570                  raw_jmp((uae_u32)popall_do_nothing);
6571                  create_jmpdep(bi,0,tba,t1);
6572  
6573 <                align_target(16);
6573 >                align_target(align_jumps);
6574                  /* not-predicted outcome */
6575                  *branchadd=(uae_u32)get_target()-((uae_u32)branchadd+4);
6576                  live=tmp; /* Ouch again */
# Line 6160 | Line 6639 | static void compile_block(cpu_history* p
6639          big_to_small_state(&live,&(bi->env));
6640   #endif
6641  
6642 + #if USE_CHECKSUM_INFO
6643 +        remove_from_list(bi);
6644 +        if (trace_in_rom) {
6645 +                // No need to checksum that block trace on cache invalidation
6646 +                free_checksum_info_chain(bi->csi);
6647 +                bi->csi = NULL;
6648 +                add_to_dormant(bi);
6649 +        }
6650 +        else {
6651 +            calc_checksum(bi,&(bi->c1),&(bi->c2));
6652 +                add_to_active(bi);
6653 +        }
6654 + #else
6655          if (next_pc_p+extra_len>=max_pcp &&
6656              next_pc_p+extra_len<max_pcp+LONGEST_68K_INST)
6657              max_pcp=next_pc_p+extra_len;  /* extra_len covers flags magic */
6658          else
6659              max_pcp+=LONGEST_68K_INST;
6660 +
6661          bi->len=max_pcp-min_pcp;
6662          bi->min_pcp=min_pcp;
6663 <                    
6663 >        
6664          remove_from_list(bi);
6665          if (isinrom(min_pcp) && isinrom(max_pcp)) {
6666              add_to_dormant(bi); /* No need to checksum it on cache flush.
# Line 6178 | Line 6671 | static void compile_block(cpu_history* p
6671              calc_checksum(bi,&(bi->c1),&(bi->c2));
6672              add_to_active(bi);
6673          }
6674 + #endif
6675          
6676          current_cache_size += get_target() - (uae_u8 *)current_compile_p;
6677          
# Line 6197 | Line 6691 | static void compile_block(cpu_history* p
6691   #endif
6692          
6693          log_dump();
6694 <        align_target(32);
6694 >        align_target(align_jumps);
6695  
6696          /* This is the non-direct handler */
6697          bi->handler=
# Line 6213 | Line 6707 | static void compile_block(cpu_history* p
6707  
6708          raw_jmp((uae_u32)bi->direct_handler);
6709  
6216        align_target(32);
6710          current_compile_p=get_target();
6218
6711          raise_in_cl_list(bi);
6712          
6713          /* We will flush soon, anyway, so let's do it now */
# Line 6241 | Line 6733 | void exec_nostats(void)
6733   {
6734          for (;;)  {
6735                  uae_u32 opcode = GET_OPCODE;
6244 #ifdef X86_ASSEMBLY__disable
6245                __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
6736                  (*cpufunctbl[opcode])(opcode);
6250 #endif
6737                  if (end_block(opcode) || SPCFLAGS_TEST(SPCFLAG_ALL)) {
6738                          return; /* We will deal with the spcflags in the caller */
6739                  }
# Line 6272 | Line 6758 | void execute_normal(void)
6758   #if FLIGHT_RECORDER
6759                          m68k_record_step(m68k_getpc());
6760   #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
6761                          (*cpufunctbl[opcode])(opcode);
6281 #endif
6762                          if (end_block(opcode) || SPCFLAGS_TEST(SPCFLAG_ALL) || blocklen>=MAXRUN) {
6763                                  compile_block(pc_hist, blocklen);
6764                                  return; /* We will deal with the spcflags in the caller */
# Line 6291 | Line 6771 | void execute_normal(void)
6771  
6772   typedef void (*compiled_handler)(void);
6773  
6774 + #ifdef X86_ASSEMBLY
6775 + void (*m68k_compile_execute)(void) = NULL;
6776 + #else
6777   void m68k_do_compile_execute(void)
6778   {
6779          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
6780                  ((compiled_handler)(pushall_call_handler))();
6303 #endif
6781                  /* Whenever we return from that, we should check spcflags */
6782                  if (SPCFLAGS_TEST(SPCFLAG_ALL)) {
6783                          if (m68k_do_specialties ())
# Line 6308 | Line 6785 | void m68k_do_compile_execute(void)
6785                  }
6786          }
6787   }
6788 + #endif

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines