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-2004 |
7 |
+ |
* Gwenole Beauchesne |
8 |
+ |
* |
9 |
+ |
* Basilisk II (C) 1997-2004 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 |
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 |
|
#ifdef WIN32 |
105 |
|
static clock_t emul_end_time = 0; |
106 |
|
#endif |
107 |
|
|
108 |
< |
compop_func *compfunctbl[65536]; |
109 |
< |
compop_func *nfcompfunctbl[65536]; |
110 |
< |
cpuop_func *nfcpufunctbl[65536]; |
108 |
> |
#if PROFILE_UNTRANSLATED_INSNS |
109 |
> |
const int untranslated_top_ten = 20; |
110 |
> |
static uae_u32 raw_cputbl_count[65536] = { 0, }; |
111 |
> |
static uae_u16 opcode_nums[65536]; |
112 |
> |
|
113 |
> |
static int untranslated_compfn(const void *e1, const void *e2) |
114 |
> |
{ |
115 |
> |
return raw_cputbl_count[*(const uae_u16 *)e1] < raw_cputbl_count[*(const uae_u16 *)e2]; |
116 |
> |
} |
117 |
> |
#endif |
118 |
> |
|
119 |
> |
static compop_func *compfunctbl[65536]; |
120 |
> |
static compop_func *nfcompfunctbl[65536]; |
121 |
> |
static cpuop_func *nfcpufunctbl[65536]; |
122 |
|
uae_u8* comp_pc_p; |
123 |
|
|
124 |
+ |
// From main_unix.cpp |
125 |
+ |
extern bool ThirtyThreeBitAddressing; |
126 |
+ |
|
127 |
+ |
// From newcpu.cpp |
128 |
+ |
extern bool quit_program; |
129 |
+ |
|
130 |
|
// gb-- Extra data for Basilisk II/JIT |
131 |
|
#if JIT_DEBUG |
132 |
|
static bool JITDebug = false; // Enable runtime disassemblers through mon? |
134 |
|
const bool JITDebug = false; // Don't use JIT debug mode at all |
135 |
|
#endif |
136 |
|
|
137 |
< |
const uae_u32 MIN_CACHE_SIZE = 2048; // Minimal translation cache size (2048 KB) |
137 |
> |
const uae_u32 MIN_CACHE_SIZE = 1024; // Minimal translation cache size (1 MB) |
138 |
|
static uae_u32 cache_size = 0; // Size of total cache allocated for compiled blocks |
139 |
|
static uae_u32 current_cache_size = 0; // Cache grows upwards: how much has been consumed already |
140 |
|
static bool lazy_flush = true; // Flag: lazy translation cache invalidation |
141 |
|
static bool avoid_fpu = true; // Flag: compile FPU instructions ? |
142 |
|
static bool have_cmov = false; // target has CMOV instructions ? |
143 |
|
static bool have_rat_stall = true; // target has partial register stalls ? |
144 |
< |
static int zero_fd = -1; |
144 |
> |
const bool tune_alignment = true; // Tune code alignments for running CPU ? |
145 |
> |
const bool tune_nop_fillers = true; // Tune no-op fillers for architecture |
146 |
> |
static bool setzflg_uses_bsf = false; // setzflg virtual instruction can use native BSF instruction correctly? |
147 |
> |
static int align_loops = 32; // Align the start of loops |
148 |
> |
static int align_jumps = 32; // Align the start of jumps |
149 |
|
static int optcount[10] = { |
150 |
|
10, // How often a block has to be executed before it is translated |
151 |
|
0, // How often to use naive translation |
161 |
|
}; |
162 |
|
static op_properties prop[65536]; |
163 |
|
|
103 |
– |
// gb-- Control Flow Predicates |
104 |
– |
|
164 |
|
static inline int end_block(uae_u32 opcode) |
165 |
|
{ |
166 |
|
return (prop[opcode].cflow & fl_end_block); |
167 |
|
} |
168 |
|
|
169 |
+ |
static inline bool is_const_jump(uae_u32 opcode) |
170 |
+ |
{ |
171 |
+ |
return (prop[opcode].cflow == fl_const_jump); |
172 |
+ |
} |
173 |
+ |
|
174 |
|
static inline bool may_trap(uae_u32 opcode) |
175 |
|
{ |
176 |
|
return (prop[opcode].cflow & fl_trap); |
177 |
|
} |
178 |
|
|
179 |
+ |
static inline unsigned int cft_map (unsigned int f) |
180 |
+ |
{ |
181 |
+ |
#ifndef HAVE_GET_WORD_UNSWAPPED |
182 |
+ |
return f; |
183 |
+ |
#else |
184 |
+ |
return ((f >> 8) & 255) | ((f & 255) << 8); |
185 |
+ |
#endif |
186 |
+ |
} |
187 |
+ |
|
188 |
|
uae_u8* start_pc_p; |
189 |
|
uae_u32 start_pc; |
190 |
|
uae_u32 current_block_pc_p; |
191 |
< |
uae_u32 current_block_start_target; |
191 |
> |
static uintptr current_block_start_target; |
192 |
|
uae_u32 needed_flags; |
193 |
< |
static uae_u32 next_pc_p; |
194 |
< |
static uae_u32 taken_pc_p; |
193 |
> |
static uintptr next_pc_p; |
194 |
> |
static uintptr taken_pc_p; |
195 |
|
static int branch_cc; |
196 |
|
static int redo_current_block; |
197 |
|
|
203 |
|
static uae_u8* max_compile_start; |
204 |
|
static uae_u8* compiled_code=NULL; |
205 |
|
static uae_s32 reg_alloc_run; |
206 |
+ |
const int POPALLSPACE_SIZE = 1024; /* That should be enough space */ |
207 |
+ |
static uae_u8* popallspace=NULL; |
208 |
|
|
209 |
|
void* pushall_call_handler=NULL; |
210 |
|
static void* popall_do_nothing=NULL; |
214 |
|
static void* popall_recompile_block=NULL; |
215 |
|
static void* popall_check_checksum=NULL; |
216 |
|
|
142 |
– |
extern uae_u32 oink; |
143 |
– |
extern unsigned long foink3; |
144 |
– |
extern unsigned long foink; |
145 |
– |
|
217 |
|
/* The 68k only ever executes from even addresses. So right now, we |
218 |
|
* waste half the entries in this array |
219 |
|
* UPDATE: We now use those entries to store the start of the linked |
460 |
|
|
461 |
|
static __inline__ void create_jmpdep(blockinfo* bi, int i, uae_u32* jmpaddr, uae_u32 target) |
462 |
|
{ |
463 |
< |
blockinfo* tbi=get_blockinfo_addr((void*)target); |
463 |
> |
blockinfo* tbi=get_blockinfo_addr((void*)(uintptr)target); |
464 |
|
|
465 |
|
Dif(!tbi) { |
466 |
|
write_log("Could not create jmpdep!\n"); |
558 |
|
compiled. If the list of free blockinfos is empty, we allocate a new |
559 |
|
pool of blockinfos and link the newly created blockinfos altogether |
560 |
|
into the list of free blockinfos. Otherwise, we simply pop a structure |
561 |
< |
of the free list. |
561 |
> |
off the free list. |
562 |
|
|
563 |
|
Blockinfo are lazily deallocated, i.e. chained altogether in the |
564 |
|
list of free blockinfos whenvever a translation cache flush (hard or |
565 |
|
soft) request occurs. |
566 |
|
*/ |
567 |
|
|
568 |
< |
#if USE_SEPARATE_BIA |
569 |
< |
const int BLOCKINFO_POOL_SIZE = 128; |
570 |
< |
struct blockinfo_pool { |
571 |
< |
blockinfo bi[BLOCKINFO_POOL_SIZE]; |
572 |
< |
blockinfo_pool *next; |
568 |
> |
template< class T > |
569 |
> |
class LazyBlockAllocator |
570 |
> |
{ |
571 |
> |
enum { |
572 |
> |
kPoolSize = 1 + 4096 / sizeof(T) |
573 |
> |
}; |
574 |
> |
struct Pool { |
575 |
> |
T chunk[kPoolSize]; |
576 |
> |
Pool * next; |
577 |
> |
}; |
578 |
> |
Pool * mPools; |
579 |
> |
T * mChunks; |
580 |
> |
public: |
581 |
> |
LazyBlockAllocator() : mPools(0), mChunks(0) { } |
582 |
> |
~LazyBlockAllocator(); |
583 |
> |
T * acquire(); |
584 |
> |
void release(T * const); |
585 |
|
}; |
503 |
– |
static blockinfo_pool * blockinfo_pools = 0; |
504 |
– |
static blockinfo * free_blockinfos = 0; |
505 |
– |
#endif |
586 |
|
|
587 |
< |
static __inline__ blockinfo *alloc_blockinfo(void) |
587 |
> |
template< class T > |
588 |
> |
LazyBlockAllocator<T>::~LazyBlockAllocator() |
589 |
|
{ |
590 |
< |
#if USE_SEPARATE_BIA |
591 |
< |
if (!free_blockinfos) { |
592 |
< |
// There is no blockinfo struct left, allocate a new |
593 |
< |
// pool and link the chunks into the free list |
594 |
< |
blockinfo_pool *bi_pool = (blockinfo_pool *)malloc(sizeof(blockinfo_pool)); |
595 |
< |
for (blockinfo *bi = &bi_pool->bi[0]; bi < &bi_pool->bi[BLOCKINFO_POOL_SIZE]; bi++) { |
596 |
< |
bi->next = free_blockinfos; |
597 |
< |
free_blockinfos = bi; |
590 |
> |
Pool * currentPool = mPools; |
591 |
> |
while (currentPool) { |
592 |
> |
Pool * deadPool = currentPool; |
593 |
> |
currentPool = currentPool->next; |
594 |
> |
free(deadPool); |
595 |
> |
} |
596 |
> |
} |
597 |
> |
|
598 |
> |
template< class T > |
599 |
> |
T * LazyBlockAllocator<T>::acquire() |
600 |
> |
{ |
601 |
> |
if (!mChunks) { |
602 |
> |
// There is no chunk left, allocate a new pool and link the |
603 |
> |
// chunks into the free list |
604 |
> |
Pool * newPool = (Pool *)malloc(sizeof(Pool)); |
605 |
> |
for (T * chunk = &newPool->chunk[0]; chunk < &newPool->chunk[kPoolSize]; chunk++) { |
606 |
> |
chunk->next = mChunks; |
607 |
> |
mChunks = chunk; |
608 |
|
} |
609 |
< |
bi_pool->next = blockinfo_pools; |
610 |
< |
blockinfo_pools = bi_pool; |
609 |
> |
newPool->next = mPools; |
610 |
> |
mPools = newPool; |
611 |
|
} |
612 |
< |
blockinfo *bi = free_blockinfos; |
613 |
< |
free_blockinfos = bi->next; |
614 |
< |
#else |
524 |
< |
blockinfo *bi = (blockinfo*)current_compile_p; |
525 |
< |
current_compile_p += sizeof(blockinfo); |
526 |
< |
#endif |
527 |
< |
return bi; |
612 |
> |
T * chunk = mChunks; |
613 |
> |
mChunks = chunk->next; |
614 |
> |
return chunk; |
615 |
|
} |
616 |
|
|
617 |
< |
static __inline__ void free_blockinfo(blockinfo *bi) |
617 |
> |
template< class T > |
618 |
> |
void LazyBlockAllocator<T>::release(T * const chunk) |
619 |
> |
{ |
620 |
> |
chunk->next = mChunks; |
621 |
> |
mChunks = chunk; |
622 |
> |
} |
623 |
> |
|
624 |
> |
template< class T > |
625 |
> |
class HardBlockAllocator |
626 |
|
{ |
627 |
+ |
public: |
628 |
+ |
T * acquire() { |
629 |
+ |
T * data = (T *)current_compile_p; |
630 |
+ |
current_compile_p += sizeof(T); |
631 |
+ |
return data; |
632 |
+ |
} |
633 |
+ |
|
634 |
+ |
void release(T * const chunk) { |
635 |
+ |
// Deallocated on invalidation |
636 |
+ |
} |
637 |
+ |
}; |
638 |
+ |
|
639 |
|
#if USE_SEPARATE_BIA |
640 |
< |
bi->next = free_blockinfos; |
641 |
< |
free_blockinfos = bi; |
640 |
> |
static LazyBlockAllocator<blockinfo> BlockInfoAllocator; |
641 |
> |
static LazyBlockAllocator<checksum_info> ChecksumInfoAllocator; |
642 |
> |
#else |
643 |
> |
static HardBlockAllocator<blockinfo> BlockInfoAllocator; |
644 |
> |
static HardBlockAllocator<checksum_info> ChecksumInfoAllocator; |
645 |
|
#endif |
646 |
+ |
|
647 |
+ |
static __inline__ checksum_info *alloc_checksum_info(void) |
648 |
+ |
{ |
649 |
+ |
checksum_info *csi = ChecksumInfoAllocator.acquire(); |
650 |
+ |
csi->next = NULL; |
651 |
+ |
return csi; |
652 |
|
} |
653 |
|
|
654 |
< |
static void free_blockinfo_pools(void) |
654 |
> |
static __inline__ void free_checksum_info(checksum_info *csi) |
655 |
|
{ |
656 |
< |
#if USE_SEPARATE_BIA |
657 |
< |
int blockinfo_pool_count = 0; |
658 |
< |
blockinfo_pool *curr_pool = blockinfo_pools; |
659 |
< |
while (curr_pool) { |
660 |
< |
blockinfo_pool_count++; |
661 |
< |
blockinfo_pool *dead_pool = curr_pool; |
662 |
< |
curr_pool = curr_pool->next; |
663 |
< |
free(dead_pool); |
656 |
> |
csi->next = NULL; |
657 |
> |
ChecksumInfoAllocator.release(csi); |
658 |
> |
} |
659 |
> |
|
660 |
> |
static __inline__ void free_checksum_info_chain(checksum_info *csi) |
661 |
> |
{ |
662 |
> |
while (csi != NULL) { |
663 |
> |
checksum_info *csi2 = csi->next; |
664 |
> |
free_checksum_info(csi); |
665 |
> |
csi = csi2; |
666 |
|
} |
667 |
< |
|
668 |
< |
uae_u32 blockinfo_pools_size = blockinfo_pool_count * BLOCKINFO_POOL_SIZE * sizeof(blockinfo); |
669 |
< |
write_log("### Blockinfo allocation statistics\n"); |
670 |
< |
write_log("Number of blockinfo pools : %d\n", blockinfo_pool_count); |
671 |
< |
write_log("Total number of blockinfos : %d (%d KB)\n", |
672 |
< |
blockinfo_pool_count * BLOCKINFO_POOL_SIZE, |
673 |
< |
blockinfo_pools_size / 1024); |
556 |
< |
write_log("\n"); |
667 |
> |
} |
668 |
> |
|
669 |
> |
static __inline__ blockinfo *alloc_blockinfo(void) |
670 |
> |
{ |
671 |
> |
blockinfo *bi = BlockInfoAllocator.acquire(); |
672 |
> |
#if USE_CHECKSUM_INFO |
673 |
> |
bi->csi = NULL; |
674 |
|
#endif |
675 |
+ |
return bi; |
676 |
+ |
} |
677 |
+ |
|
678 |
+ |
static __inline__ void free_blockinfo(blockinfo *bi) |
679 |
+ |
{ |
680 |
+ |
#if USE_CHECKSUM_INFO |
681 |
+ |
free_checksum_info_chain(bi->csi); |
682 |
+ |
bi->csi = NULL; |
683 |
+ |
#endif |
684 |
+ |
BlockInfoAllocator.release(bi); |
685 |
|
} |
686 |
|
|
687 |
|
static __inline__ void alloc_blockinfos(void) |
724 |
|
target+=4; |
725 |
|
} |
726 |
|
|
727 |
+ |
static __inline__ void emit_quad(uae_u64 x) |
728 |
+ |
{ |
729 |
+ |
*((uae_u64*)target)=x; |
730 |
+ |
target+=8; |
731 |
+ |
} |
732 |
+ |
|
733 |
+ |
static __inline__ void emit_block(const uae_u8 *block, uae_u32 blocklen) |
734 |
+ |
{ |
735 |
+ |
memcpy((uae_u8 *)target,block,blocklen); |
736 |
+ |
target+=blocklen; |
737 |
+ |
} |
738 |
+ |
|
739 |
|
static __inline__ uae_u32 reverse32(uae_u32 v) |
740 |
|
{ |
741 |
|
#if 1 |
832 |
|
int touchcnt; |
833 |
|
|
834 |
|
/******************************************************************** |
835 |
+ |
* Partial register flushing for optimized calls * |
836 |
+ |
********************************************************************/ |
837 |
+ |
|
838 |
+ |
struct regusage { |
839 |
+ |
uae_u16 rmask; |
840 |
+ |
uae_u16 wmask; |
841 |
+ |
}; |
842 |
+ |
|
843 |
+ |
static inline void ru_set(uae_u16 *mask, int reg) |
844 |
+ |
{ |
845 |
+ |
#if USE_OPTIMIZED_CALLS |
846 |
+ |
*mask |= 1 << reg; |
847 |
+ |
#endif |
848 |
+ |
} |
849 |
+ |
|
850 |
+ |
static inline bool ru_get(const uae_u16 *mask, int reg) |
851 |
+ |
{ |
852 |
+ |
#if USE_OPTIMIZED_CALLS |
853 |
+ |
return (*mask & (1 << reg)); |
854 |
+ |
#else |
855 |
+ |
/* Default: instruction reads & write to register */ |
856 |
+ |
return true; |
857 |
+ |
#endif |
858 |
+ |
} |
859 |
+ |
|
860 |
+ |
static inline void ru_set_read(regusage *ru, int reg) |
861 |
+ |
{ |
862 |
+ |
ru_set(&ru->rmask, reg); |
863 |
+ |
} |
864 |
+ |
|
865 |
+ |
static inline void ru_set_write(regusage *ru, int reg) |
866 |
+ |
{ |
867 |
+ |
ru_set(&ru->wmask, reg); |
868 |
+ |
} |
869 |
+ |
|
870 |
+ |
static inline bool ru_read_p(const regusage *ru, int reg) |
871 |
+ |
{ |
872 |
+ |
return ru_get(&ru->rmask, reg); |
873 |
+ |
} |
874 |
+ |
|
875 |
+ |
static inline bool ru_write_p(const regusage *ru, int reg) |
876 |
+ |
{ |
877 |
+ |
return ru_get(&ru->wmask, reg); |
878 |
+ |
} |
879 |
+ |
|
880 |
+ |
static void ru_fill_ea(regusage *ru, int reg, amodes mode, |
881 |
+ |
wordsizes size, int write_mode) |
882 |
+ |
{ |
883 |
+ |
switch (mode) { |
884 |
+ |
case Areg: |
885 |
+ |
reg += 8; |
886 |
+ |
/* fall through */ |
887 |
+ |
case Dreg: |
888 |
+ |
ru_set(write_mode ? &ru->wmask : &ru->rmask, reg); |
889 |
+ |
break; |
890 |
+ |
case Ad16: |
891 |
+ |
/* skip displacment */ |
892 |
+ |
m68k_pc_offset += 2; |
893 |
+ |
case Aind: |
894 |
+ |
case Aipi: |
895 |
+ |
case Apdi: |
896 |
+ |
ru_set_read(ru, reg+8); |
897 |
+ |
break; |
898 |
+ |
case Ad8r: |
899 |
+ |
ru_set_read(ru, reg+8); |
900 |
+ |
/* fall through */ |
901 |
+ |
case PC8r: { |
902 |
+ |
uae_u16 dp = comp_get_iword((m68k_pc_offset+=2)-2); |
903 |
+ |
reg = (dp >> 12) & 15; |
904 |
+ |
ru_set_read(ru, reg); |
905 |
+ |
if (dp & 0x100) |
906 |
+ |
m68k_pc_offset += (((dp & 0x30) >> 3) & 7) + ((dp & 3) * 2); |
907 |
+ |
break; |
908 |
+ |
} |
909 |
+ |
case PC16: |
910 |
+ |
case absw: |
911 |
+ |
case imm0: |
912 |
+ |
case imm1: |
913 |
+ |
m68k_pc_offset += 2; |
914 |
+ |
break; |
915 |
+ |
case absl: |
916 |
+ |
case imm2: |
917 |
+ |
m68k_pc_offset += 4; |
918 |
+ |
break; |
919 |
+ |
case immi: |
920 |
+ |
m68k_pc_offset += (size == sz_long) ? 4 : 2; |
921 |
+ |
break; |
922 |
+ |
} |
923 |
+ |
} |
924 |
+ |
|
925 |
+ |
/* TODO: split into a static initialization part and a dynamic one |
926 |
+ |
(instructions depending on extension words) */ |
927 |
+ |
static void ru_fill(regusage *ru, uae_u32 opcode) |
928 |
+ |
{ |
929 |
+ |
m68k_pc_offset += 2; |
930 |
+ |
|
931 |
+ |
/* Default: no register is used or written to */ |
932 |
+ |
ru->rmask = 0; |
933 |
+ |
ru->wmask = 0; |
934 |
+ |
|
935 |
+ |
uae_u32 real_opcode = cft_map(opcode); |
936 |
+ |
struct instr *dp = &table68k[real_opcode]; |
937 |
+ |
|
938 |
+ |
bool rw_dest = true; |
939 |
+ |
bool handled = false; |
940 |
+ |
|
941 |
+ |
/* Handle some instructions specifically */ |
942 |
+ |
uae_u16 reg, ext; |
943 |
+ |
switch (dp->mnemo) { |
944 |
+ |
case i_BFCHG: |
945 |
+ |
case i_BFCLR: |
946 |
+ |
case i_BFEXTS: |
947 |
+ |
case i_BFEXTU: |
948 |
+ |
case i_BFFFO: |
949 |
+ |
case i_BFINS: |
950 |
+ |
case i_BFSET: |
951 |
+ |
case i_BFTST: |
952 |
+ |
ext = comp_get_iword((m68k_pc_offset+=2)-2); |
953 |
+ |
if (ext & 0x800) ru_set_read(ru, (ext >> 6) & 7); |
954 |
+ |
if (ext & 0x020) ru_set_read(ru, ext & 7); |
955 |
+ |
ru_fill_ea(ru, dp->dreg, (amodes)dp->dmode, (wordsizes)dp->size, 1); |
956 |
+ |
if (dp->dmode == Dreg) |
957 |
+ |
ru_set_read(ru, dp->dreg); |
958 |
+ |
switch (dp->mnemo) { |
959 |
+ |
case i_BFEXTS: |
960 |
+ |
case i_BFEXTU: |
961 |
+ |
case i_BFFFO: |
962 |
+ |
ru_set_write(ru, (ext >> 12) & 7); |
963 |
+ |
break; |
964 |
+ |
case i_BFINS: |
965 |
+ |
ru_set_read(ru, (ext >> 12) & 7); |
966 |
+ |
/* fall through */ |
967 |
+ |
case i_BFCHG: |
968 |
+ |
case i_BFCLR: |
969 |
+ |
case i_BSET: |
970 |
+ |
if (dp->dmode == Dreg) |
971 |
+ |
ru_set_write(ru, dp->dreg); |
972 |
+ |
break; |
973 |
+ |
} |
974 |
+ |
handled = true; |
975 |
+ |
rw_dest = false; |
976 |
+ |
break; |
977 |
+ |
|
978 |
+ |
case i_BTST: |
979 |
+ |
rw_dest = false; |
980 |
+ |
break; |
981 |
+ |
|
982 |
+ |
case i_CAS: |
983 |
+ |
{ |
984 |
+ |
ext = comp_get_iword((m68k_pc_offset+=2)-2); |
985 |
+ |
int Du = ext & 7; |
986 |
+ |
ru_set_read(ru, Du); |
987 |
+ |
int Dc = (ext >> 6) & 7; |
988 |
+ |
ru_set_read(ru, Dc); |
989 |
+ |
ru_set_write(ru, Dc); |
990 |
+ |
break; |
991 |
+ |
} |
992 |
+ |
case i_CAS2: |
993 |
+ |
{ |
994 |
+ |
int Dc1, Dc2, Du1, Du2, Rn1, Rn2; |
995 |
+ |
ext = comp_get_iword((m68k_pc_offset+=2)-2); |
996 |
+ |
Rn1 = (ext >> 12) & 15; |
997 |
+ |
Du1 = (ext >> 6) & 7; |
998 |
+ |
Dc1 = ext & 7; |
999 |
+ |
ru_set_read(ru, Rn1); |
1000 |
+ |
ru_set_read(ru, Du1); |
1001 |
+ |
ru_set_read(ru, Dc1); |
1002 |
+ |
ru_set_write(ru, Dc1); |
1003 |
+ |
ext = comp_get_iword((m68k_pc_offset+=2)-2); |
1004 |
+ |
Rn2 = (ext >> 12) & 15; |
1005 |
+ |
Du2 = (ext >> 6) & 7; |
1006 |
+ |
Dc2 = ext & 7; |
1007 |
+ |
ru_set_read(ru, Rn2); |
1008 |
+ |
ru_set_read(ru, Du2); |
1009 |
+ |
ru_set_write(ru, Dc2); |
1010 |
+ |
break; |
1011 |
+ |
} |
1012 |
+ |
case i_DIVL: case i_MULL: |
1013 |
+ |
m68k_pc_offset += 2; |
1014 |
+ |
break; |
1015 |
+ |
case i_LEA: |
1016 |
+ |
case i_MOVE: case i_MOVEA: case i_MOVE16: |
1017 |
+ |
rw_dest = false; |
1018 |
+ |
break; |
1019 |
+ |
case i_PACK: case i_UNPK: |
1020 |
+ |
rw_dest = false; |
1021 |
+ |
m68k_pc_offset += 2; |
1022 |
+ |
break; |
1023 |
+ |
case i_TRAPcc: |
1024 |
+ |
m68k_pc_offset += (dp->size == sz_long) ? 4 : 2; |
1025 |
+ |
break; |
1026 |
+ |
case i_RTR: |
1027 |
+ |
/* do nothing, just for coverage debugging */ |
1028 |
+ |
break; |
1029 |
+ |
/* TODO: handle EXG instruction */ |
1030 |
+ |
} |
1031 |
+ |
|
1032 |
+ |
/* Handle A-Traps better */ |
1033 |
+ |
if ((real_opcode & 0xf000) == 0xa000) { |
1034 |
+ |
handled = true; |
1035 |
+ |
} |
1036 |
+ |
|
1037 |
+ |
/* Handle EmulOps better */ |
1038 |
+ |
if ((real_opcode & 0xff00) == 0x7100) { |
1039 |
+ |
handled = true; |
1040 |
+ |
ru->rmask = 0xffff; |
1041 |
+ |
ru->wmask = 0; |
1042 |
+ |
} |
1043 |
+ |
|
1044 |
+ |
if (dp->suse && !handled) |
1045 |
+ |
ru_fill_ea(ru, dp->sreg, (amodes)dp->smode, (wordsizes)dp->size, 0); |
1046 |
+ |
|
1047 |
+ |
if (dp->duse && !handled) |
1048 |
+ |
ru_fill_ea(ru, dp->dreg, (amodes)dp->dmode, (wordsizes)dp->size, 1); |
1049 |
+ |
|
1050 |
+ |
if (rw_dest) |
1051 |
+ |
ru->rmask |= ru->wmask; |
1052 |
+ |
|
1053 |
+ |
handled = handled || dp->suse || dp->duse; |
1054 |
+ |
|
1055 |
+ |
/* Mark all registers as used/written if the instruction may trap */ |
1056 |
+ |
if (may_trap(opcode)) { |
1057 |
+ |
handled = true; |
1058 |
+ |
ru->rmask = 0xffff; |
1059 |
+ |
ru->wmask = 0xffff; |
1060 |
+ |
} |
1061 |
+ |
|
1062 |
+ |
if (!handled) { |
1063 |
+ |
write_log("ru_fill: %04x = { %04x, %04x }\n", |
1064 |
+ |
real_opcode, ru->rmask, ru->wmask); |
1065 |
+ |
abort(); |
1066 |
+ |
} |
1067 |
+ |
} |
1068 |
+ |
|
1069 |
+ |
/******************************************************************** |
1070 |
|
* register allocation per block logging * |
1071 |
|
********************************************************************/ |
1072 |
|
|
1144 |
|
else if (r == FLAGX) |
1145 |
|
raw_load_flagx(n, r); |
1146 |
|
else |
1147 |
< |
raw_mov_l_rm(n, (uae_u32) live.state[r].mem); |
1147 |
> |
raw_mov_l_rm(n, (uintptr) live.state[r].mem); |
1148 |
|
} |
1149 |
|
|
1150 |
|
static __inline__ void check_load_reg(int n, int r) |
1151 |
|
{ |
1152 |
< |
raw_mov_l_rm(n, (uae_u32) live.state[r].mem); |
1152 |
> |
raw_mov_l_rm(n, (uintptr) live.state[r].mem); |
1153 |
|
} |
1154 |
|
|
1155 |
|
static __inline__ void log_vwrite(int r) |
1260 |
|
|
1261 |
|
if (live.state[r].status==DIRTY) { |
1262 |
|
switch (live.state[r].dirtysize) { |
1263 |
< |
case 1: raw_mov_b_mr((uae_u32)live.state[r].mem,rr); break; |
1264 |
< |
case 2: raw_mov_w_mr((uae_u32)live.state[r].mem,rr); break; |
1265 |
< |
case 4: raw_mov_l_mr((uae_u32)live.state[r].mem,rr); break; |
1263 |
> |
case 1: raw_mov_b_mr((uintptr)live.state[r].mem,rr); break; |
1264 |
> |
case 2: raw_mov_w_mr((uintptr)live.state[r].mem,rr); break; |
1265 |
> |
case 4: raw_mov_l_mr((uintptr)live.state[r].mem,rr); break; |
1266 |
|
default: abort(); |
1267 |
|
} |
1268 |
|
log_vwrite(r); |
1290 |
|
abort(); |
1291 |
|
} |
1292 |
|
|
1293 |
< |
raw_mov_l_mi((uae_u32)live.state[r].mem,live.state[r].val); |
1293 |
> |
raw_mov_l_mi((uintptr)live.state[r].mem,live.state[r].val); |
1294 |
|
log_vwrite(r); |
1295 |
|
live.state[r].val=0; |
1296 |
|
set_status(r,INMEM); |
1423 |
|
if (size==4 && live.state[r].validsize==2) { |
1424 |
|
log_isused(bestreg); |
1425 |
|
log_visused(r); |
1426 |
< |
raw_mov_l_rm(bestreg,(uae_u32)live.state[r].mem); |
1426 |
> |
raw_mov_l_rm(bestreg,(uintptr)live.state[r].mem); |
1427 |
|
raw_bswap_32(bestreg); |
1428 |
|
raw_zero_extend_16_rr(rr,rr); |
1429 |
|
raw_zero_extend_16_rr(bestreg,bestreg); |
1920 |
|
{ |
1921 |
|
if (live.fate[r].status==DIRTY) { |
1922 |
|
#if USE_LONG_DOUBLE |
1923 |
< |
raw_fmov_ext_mr((uae_u32)live.fate[r].mem,live.fate[r].realreg); |
1923 |
> |
raw_fmov_ext_mr((uintptr)live.fate[r].mem,live.fate[r].realreg); |
1924 |
|
#else |
1925 |
< |
raw_fmov_mr((uae_u32)live.fate[r].mem,live.fate[r].realreg); |
1925 |
> |
raw_fmov_mr((uintptr)live.fate[r].mem,live.fate[r].realreg); |
1926 |
|
#endif |
1927 |
|
live.fate[r].status=CLEAN; |
1928 |
|
} |
1932 |
|
{ |
1933 |
|
if (live.fate[r].status==DIRTY) { |
1934 |
|
#if USE_LONG_DOUBLE |
1935 |
< |
raw_fmov_ext_mr_drop((uae_u32)live.fate[r].mem,live.fate[r].realreg); |
1935 |
> |
raw_fmov_ext_mr_drop((uintptr)live.fate[r].mem,live.fate[r].realreg); |
1936 |
|
#else |
1937 |
< |
raw_fmov_mr_drop((uae_u32)live.fate[r].mem,live.fate[r].realreg); |
1937 |
> |
raw_fmov_mr_drop((uintptr)live.fate[r].mem,live.fate[r].realreg); |
1938 |
|
#endif |
1939 |
|
live.fate[r].status=INMEM; |
1940 |
|
} |
2042 |
|
if (!willclobber) { |
2043 |
|
if (live.fate[r].status!=UNDEF) { |
2044 |
|
#if USE_LONG_DOUBLE |
2045 |
< |
raw_fmov_ext_rm(bestreg,(uae_u32)live.fate[r].mem); |
2045 |
> |
raw_fmov_ext_rm(bestreg,(uintptr)live.fate[r].mem); |
2046 |
|
#else |
2047 |
< |
raw_fmov_rm(bestreg,(uae_u32)live.fate[r].mem); |
2047 |
> |
raw_fmov_rm(bestreg,(uintptr)live.fate[r].mem); |
2048 |
|
#endif |
2049 |
|
} |
2050 |
|
live.fate[r].status=CLEAN; |
2201 |
|
else |
2202 |
|
raw_fflags_into_flags(r); |
2203 |
|
f_unlock(r); |
2204 |
+ |
live_flags(); |
2205 |
|
} |
2206 |
|
|
2207 |
|
|
2250 |
|
{ |
2251 |
|
evict(FLAGX); |
2252 |
|
make_flags_live_internal(); |
2253 |
< |
COMPCALL(setcc_m)((uae_u32)live.state[FLAGX].mem,2); |
2253 |
> |
COMPCALL(setcc_m)((uintptr)live.state[FLAGX].mem,2); |
2254 |
|
log_vwrite(FLAGX); |
2255 |
|
} |
2256 |
|
MENDFUNC(0,duplicate_carry,(void)) |
2937 |
|
} |
2938 |
|
MENDFUNC(3,cmov_l_rm,(RW4 d, IMM s, IMM cc)) |
2939 |
|
|
2940 |
< |
MIDFUNC(2,bsf_l_rr,(W4 d, R4 s)) |
2940 |
> |
MIDFUNC(2,bsf_l_rr,(W4 d, W4 s)) |
2941 |
|
{ |
2942 |
|
CLOBBER_BSF; |
2943 |
< |
s=readreg(s,4); |
2944 |
< |
d=writereg(d,4); |
2945 |
< |
raw_bsf_l_rr(d,s); |
2943 |
> |
s = readreg(s, 4); |
2944 |
> |
d = writereg(d, 4); |
2945 |
> |
raw_bsf_l_rr(d, s); |
2946 |
|
unlock2(s); |
2947 |
|
unlock2(d); |
2948 |
|
} |
2949 |
< |
MENDFUNC(2,bsf_l_rr,(W4 d, R4 s)) |
2949 |
> |
MENDFUNC(2,bsf_l_rr,(W4 d, W4 s)) |
2950 |
> |
|
2951 |
> |
/* Set the Z flag depending on the value in s. Note that the |
2952 |
> |
value has to be 0 or -1 (or, more precisely, for non-zero |
2953 |
> |
values, bit 14 must be set)! */ |
2954 |
> |
MIDFUNC(2,simulate_bsf,(W4 tmp, RW4 s)) |
2955 |
> |
{ |
2956 |
> |
CLOBBER_BSF; |
2957 |
> |
s=rmw_specific(s,4,4,FLAG_NREG3); |
2958 |
> |
tmp=writereg(tmp,4); |
2959 |
> |
raw_flags_set_zero(s, tmp); |
2960 |
> |
unlock2(tmp); |
2961 |
> |
unlock2(s); |
2962 |
> |
} |
2963 |
> |
MENDFUNC(2,simulate_bsf,(W4 tmp, RW4 s)) |
2964 |
|
|
2965 |
|
MIDFUNC(2,imul_32_32,(RW4 d, R4 s)) |
2966 |
|
{ |
3006 |
|
} |
3007 |
|
MENDFUNC(2,mul_32_32,(RW4 d, R4 s)) |
3008 |
|
|
3009 |
+ |
#if SIZEOF_VOID_P == 8 |
3010 |
+ |
MIDFUNC(2,sign_extend_32_rr,(W4 d, R2 s)) |
3011 |
+ |
{ |
3012 |
+ |
int isrmw; |
3013 |
+ |
|
3014 |
+ |
if (isconst(s)) { |
3015 |
+ |
set_const(d,(uae_s32)live.state[s].val); |
3016 |
+ |
return; |
3017 |
+ |
} |
3018 |
+ |
|
3019 |
+ |
CLOBBER_SE32; |
3020 |
+ |
isrmw=(s==d); |
3021 |
+ |
if (!isrmw) { |
3022 |
+ |
s=readreg(s,4); |
3023 |
+ |
d=writereg(d,4); |
3024 |
+ |
} |
3025 |
+ |
else { /* If we try to lock this twice, with different sizes, we |
3026 |
+ |
are int trouble! */ |
3027 |
+ |
s=d=rmw(s,4,4); |
3028 |
+ |
} |
3029 |
+ |
raw_sign_extend_32_rr(d,s); |
3030 |
+ |
if (!isrmw) { |
3031 |
+ |
unlock2(d); |
3032 |
+ |
unlock2(s); |
3033 |
+ |
} |
3034 |
+ |
else { |
3035 |
+ |
unlock2(s); |
3036 |
+ |
} |
3037 |
+ |
} |
3038 |
+ |
MENDFUNC(2,sign_extend_32_rr,(W4 d, R2 s)) |
3039 |
+ |
#endif |
3040 |
+ |
|
3041 |
|
MIDFUNC(2,sign_extend_16_rr,(W4 d, R2 s)) |
3042 |
|
{ |
3043 |
|
int isrmw; |
4882 |
|
* Support functions exposed to gencomp. CREATE time * |
4883 |
|
********************************************************************/ |
4884 |
|
|
4885 |
+ |
void set_zero(int r, int tmp) |
4886 |
+ |
{ |
4887 |
+ |
if (setzflg_uses_bsf) |
4888 |
+ |
bsf_l_rr(r,r); |
4889 |
+ |
else |
4890 |
+ |
simulate_bsf(tmp,r); |
4891 |
+ |
} |
4892 |
+ |
|
4893 |
|
int kill_rodent(int r) |
4894 |
|
{ |
4895 |
|
return KILLTHERAT && |
4938 |
|
return b ? "on" : "off"; |
4939 |
|
} |
4940 |
|
|
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 |
– |
|
4941 |
|
void compiler_init(void) |
4942 |
|
{ |
4943 |
|
static bool initialized = false; |
4944 |
|
if (initialized) |
4945 |
|
return; |
4946 |
< |
|
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 |
< |
|
4946 |
> |
|
4947 |
|
#if JIT_DEBUG |
4948 |
|
// JIT debug mode ? |
4949 |
|
JITDebug = PrefsFindBool("jitdebug"); |
4965 |
|
|
4966 |
|
// Initialize target CPU (check for features, e.g. CMOV, rat stalls) |
4967 |
|
raw_init_cpu(); |
4968 |
+ |
setzflg_uses_bsf = target_check_bsf(); |
4969 |
|
write_log("<JIT compiler> : target processor has CMOV instructions : %s\n", have_cmov ? "yes" : "no"); |
4970 |
|
write_log("<JIT compiler> : target processor can suffer from partial register stalls : %s\n", have_rat_stall ? "yes" : "no"); |
4971 |
+ |
write_log("<JIT compiler> : alignment for loops, jumps are %d, %d\n", align_loops, align_jumps); |
4972 |
|
|
4973 |
|
// Translation cache flush mechanism |
4974 |
|
lazy_flush = PrefsFindBool("jitlazyflush"); |
4979 |
|
write_log("<JIT compiler> : register aliasing : %s\n", str_on_off(1)); |
4980 |
|
write_log("<JIT compiler> : FP register aliasing : %s\n", str_on_off(USE_F_ALIAS)); |
4981 |
|
write_log("<JIT compiler> : lazy constant offsetting : %s\n", str_on_off(USE_OFFSET)); |
4982 |
+ |
write_log("<JIT compiler> : block inlining : %s\n", str_on_off(USE_INLINING)); |
4983 |
|
write_log("<JIT compiler> : separate blockinfo allocation : %s\n", str_on_off(USE_SEPARATE_BIA)); |
4984 |
|
|
4985 |
|
// Build compiler tables |
4987 |
|
|
4988 |
|
initialized = true; |
4989 |
|
|
4990 |
+ |
#if PROFILE_UNTRANSLATED_INSNS |
4991 |
+ |
write_log("<JIT compiler> : gather statistics on untranslated insns count\n"); |
4992 |
+ |
#endif |
4993 |
+ |
|
4994 |
|
#if PROFILE_COMPILE_TIME |
4995 |
|
write_log("<JIT compiler> : gather statistics on translation time\n"); |
4996 |
|
emul_start_time = clock(); |
5008 |
|
vm_release(compiled_code, cache_size * 1024); |
5009 |
|
compiled_code = 0; |
5010 |
|
} |
5011 |
< |
|
5012 |
< |
// Deallocate blockinfo pools |
5013 |
< |
free_blockinfo_pools(); |
5014 |
< |
|
5015 |
< |
#ifndef WIN32 |
5016 |
< |
// Close /dev/zero |
4601 |
< |
if (zero_fd > 0) |
4602 |
< |
close(zero_fd); |
4603 |
< |
#endif |
5011 |
> |
|
5012 |
> |
// Deallocate popallspace |
5013 |
> |
if (popallspace) { |
5014 |
> |
vm_release(popallspace, POPALLSPACE_SIZE); |
5015 |
> |
popallspace = 0; |
5016 |
> |
} |
5017 |
|
|
5018 |
|
#if PROFILE_COMPILE_TIME |
5019 |
|
write_log("### Compile Block statistics\n"); |
5024 |
|
100.0*double(compile_time)/double(emul_time)); |
5025 |
|
write_log("\n"); |
5026 |
|
#endif |
5027 |
+ |
|
5028 |
+ |
#if PROFILE_UNTRANSLATED_INSNS |
5029 |
+ |
uae_u64 untranslated_count = 0; |
5030 |
+ |
for (int i = 0; i < 65536; i++) { |
5031 |
+ |
opcode_nums[i] = i; |
5032 |
+ |
untranslated_count += raw_cputbl_count[i]; |
5033 |
+ |
} |
5034 |
+ |
write_log("Sorting out untranslated instructions count...\n"); |
5035 |
+ |
qsort(opcode_nums, 65536, sizeof(uae_u16), untranslated_compfn); |
5036 |
+ |
write_log("\nRank Opc Count Name\n"); |
5037 |
+ |
for (int i = 0; i < untranslated_top_ten; i++) { |
5038 |
+ |
uae_u32 count = raw_cputbl_count[opcode_nums[i]]; |
5039 |
+ |
struct instr *dp; |
5040 |
+ |
struct mnemolookup *lookup; |
5041 |
+ |
if (!count) |
5042 |
+ |
break; |
5043 |
+ |
dp = table68k + opcode_nums[i]; |
5044 |
+ |
for (lookup = lookuptab; lookup->mnemo != dp->mnemo; lookup++) |
5045 |
+ |
; |
5046 |
+ |
write_log("%03d: %04x %10lu %s\n", i, opcode_nums[i], count, lookup->name); |
5047 |
+ |
} |
5048 |
+ |
#endif |
5049 |
|
} |
5050 |
|
|
5051 |
|
bool compiler_use_jit(void) |
5100 |
|
} |
5101 |
|
live.state[PC_P].mem=(uae_u32*)&(regs.pc_p); |
5102 |
|
live.state[PC_P].needflush=NF_TOMEM; |
5103 |
< |
set_const(PC_P,(uae_u32)comp_pc_p); |
5103 |
> |
set_const(PC_P,(uintptr)comp_pc_p); |
5104 |
|
|
5105 |
< |
live.state[FLAGX].mem=&(regflags.x); |
5105 |
> |
live.state[FLAGX].mem=(uae_u32*)&(regflags.x); |
5106 |
|
live.state[FLAGX].needflush=NF_TOMEM; |
5107 |
|
set_status(FLAGX,INMEM); |
5108 |
|
|
5109 |
< |
live.state[FLAGTMP].mem=&(regflags.cznv); |
5109 |
> |
live.state[FLAGTMP].mem=(uae_u32*)&(regflags.cznv); |
5110 |
|
live.state[FLAGTMP].needflush=NF_TOMEM; |
5111 |
|
set_status(FLAGTMP,INMEM); |
5112 |
|
|
5125 |
|
live.fate[i].status=INMEM; |
5126 |
|
} |
5127 |
|
else |
5128 |
< |
live.fate[i].mem=(uae_u32*)(scratch.fregs+i); |
5128 |
> |
live.fate[i].mem=(uae_u32*)(&scratch.fregs[i]); |
5129 |
|
} |
5130 |
|
|
5131 |
|
|
5180 |
|
switch(live.state[i].status) { |
5181 |
|
case INMEM: |
5182 |
|
if (live.state[i].val) { |
5183 |
< |
raw_add_l_mi((uae_u32)live.state[i].mem,live.state[i].val); |
5183 |
> |
raw_add_l_mi((uintptr)live.state[i].mem,live.state[i].val); |
5184 |
|
log_vwrite(i); |
5185 |
|
live.state[i].val=0; |
5186 |
|
} |
5274 |
|
|
5275 |
|
static void align_target(uae_u32 a) |
5276 |
|
{ |
5277 |
< |
/* Fill with NOPs --- makes debugging with gdb easier */ |
5278 |
< |
while ((uae_u32)target&(a-1)) |
5279 |
< |
*target++=0x90; |
5277 |
> |
if (!a) |
5278 |
> |
return; |
5279 |
> |
|
5280 |
> |
if (tune_nop_fillers) |
5281 |
> |
raw_emit_nop_filler(a - (((uintptr)target) & (a - 1))); |
5282 |
> |
else { |
5283 |
> |
/* Fill with NOPs --- makes debugging with gdb easier */ |
5284 |
> |
while ((uintptr)target&(a-1)) |
5285 |
> |
*target++=0x90; |
5286 |
> |
} |
5287 |
|
} |
5288 |
|
|
5289 |
|
static __inline__ int isinrom(uintptr addr) |
5349 |
|
static uae_u32 get_handler_address(uae_u32 addr) |
5350 |
|
{ |
5351 |
|
uae_u32 cl=cacheline(addr); |
5352 |
< |
blockinfo* bi=get_blockinfo_addr_new((void*)addr,0); |
5353 |
< |
return (uae_u32)&(bi->direct_handler_to_use); |
5352 |
> |
blockinfo* bi=get_blockinfo_addr_new((void*)(uintptr)addr,0); |
5353 |
> |
return (uintptr)&(bi->direct_handler_to_use); |
5354 |
|
} |
5355 |
|
|
5356 |
|
static uae_u32 get_handler(uae_u32 addr) |
5357 |
|
{ |
5358 |
|
uae_u32 cl=cacheline(addr); |
5359 |
< |
blockinfo* bi=get_blockinfo_addr_new((void*)addr,0); |
5360 |
< |
return (uae_u32)bi->direct_handler_to_use; |
5359 |
> |
blockinfo* bi=get_blockinfo_addr_new((void*)(uintptr)addr,0); |
5360 |
> |
return (uintptr)bi->direct_handler_to_use; |
5361 |
|
} |
5362 |
|
|
5363 |
|
static void load_handler(int reg, uae_u32 addr) |
5369 |
|
* if that assumption is wrong! No branches, no second chances, just |
5370 |
|
* straight go-for-it attitude */ |
5371 |
|
|
5372 |
< |
static void writemem_real(int address, int source, int offset, int size, int tmp, int clobber) |
5372 |
> |
static void writemem_real(int address, int source, int size, int tmp, int clobber) |
5373 |
|
{ |
5374 |
|
int f=tmp; |
5375 |
|
|
5376 |
|
if (clobber) |
5377 |
|
f=source; |
5378 |
+ |
|
5379 |
+ |
#if SIZEOF_VOID_P == 8 |
5380 |
+ |
if (!ThirtyThreeBitAddressing) |
5381 |
+ |
sign_extend_32_rr(address, address); |
5382 |
+ |
#endif |
5383 |
+ |
|
5384 |
|
switch(size) { |
5385 |
|
case 1: mov_b_bRr(address,source,MEMBaseDiff); break; |
5386 |
|
case 2: mov_w_rr(f,source); bswap_16(f); mov_w_bRr(address,f,MEMBaseDiff); break; |
5392 |
|
|
5393 |
|
void writebyte(int address, int source, int tmp) |
5394 |
|
{ |
5395 |
< |
writemem_real(address,source,20,1,tmp,0); |
5395 |
> |
writemem_real(address,source,1,tmp,0); |
5396 |
|
} |
5397 |
|
|
5398 |
|
static __inline__ void writeword_general(int address, int source, int tmp, |
5399 |
|
int clobber) |
5400 |
|
{ |
5401 |
< |
writemem_real(address,source,16,2,tmp,clobber); |
5401 |
> |
writemem_real(address,source,2,tmp,clobber); |
5402 |
|
} |
5403 |
|
|
5404 |
|
void writeword_clobber(int address, int source, int tmp) |
5414 |
|
static __inline__ void writelong_general(int address, int source, int tmp, |
5415 |
|
int clobber) |
5416 |
|
{ |
5417 |
< |
writemem_real(address,source,12,4,tmp,clobber); |
5417 |
> |
writemem_real(address,source,4,tmp,clobber); |
5418 |
|
} |
5419 |
|
|
5420 |
|
void writelong_clobber(int address, int source, int tmp) |
5433 |
|
* if that assumption is wrong! No branches, no second chances, just |
5434 |
|
* straight go-for-it attitude */ |
5435 |
|
|
5436 |
< |
static void readmem_real(int address, int dest, int offset, int size, int tmp) |
5436 |
> |
static void readmem_real(int address, int dest, int size, int tmp) |
5437 |
|
{ |
5438 |
|
int f=tmp; |
5439 |
|
|
5440 |
|
if (size==4 && address!=dest) |
5441 |
|
f=dest; |
5442 |
|
|
5443 |
+ |
#if SIZEOF_VOID_P == 8 |
5444 |
+ |
if (!ThirtyThreeBitAddressing) |
5445 |
+ |
sign_extend_32_rr(address, address); |
5446 |
+ |
#endif |
5447 |
+ |
|
5448 |
|
switch(size) { |
5449 |
|
case 1: mov_b_brR(dest,address,MEMBaseDiff); break; |
5450 |
|
case 2: mov_w_brR(dest,address,MEMBaseDiff); bswap_16(dest); break; |
5455 |
|
|
5456 |
|
void readbyte(int address, int dest, int tmp) |
5457 |
|
{ |
5458 |
< |
readmem_real(address,dest,8,1,tmp); |
5458 |
> |
readmem_real(address,dest,1,tmp); |
5459 |
|
} |
5460 |
|
|
5461 |
|
void readword(int address, int dest, int tmp) |
5462 |
|
{ |
5463 |
< |
readmem_real(address,dest,4,2,tmp); |
5463 |
> |
readmem_real(address,dest,2,tmp); |
5464 |
|
} |
5465 |
|
|
5466 |
|
void readlong(int address, int dest, int tmp) |
5467 |
|
{ |
5468 |
< |
readmem_real(address,dest,0,4,tmp); |
5468 |
> |
readmem_real(address,dest,4,tmp); |
5469 |
|
} |
5470 |
|
|
5471 |
|
void get_n_addr(int address, int dest, int tmp) |
5590 |
|
return 0; |
5591 |
|
} |
5592 |
|
|
5593 |
+ |
const int CODE_ALLOC_MAX_ATTEMPTS = 10; |
5594 |
+ |
const int CODE_ALLOC_BOUNDARIES = 128 * 1024; // 128 KB |
5595 |
+ |
|
5596 |
+ |
static uint8 *do_alloc_code(uint32 size, int depth) |
5597 |
+ |
{ |
5598 |
+ |
#if defined(__linux__) && 0 |
5599 |
+ |
/* |
5600 |
+ |
This is a really awful hack that is known to work on Linux at |
5601 |
+ |
least. |
5602 |
+ |
|
5603 |
+ |
The trick here is to make sure the allocated cache is nearby |
5604 |
+ |
code segment, and more precisely in the positive half of a |
5605 |
+ |
32-bit address space. i.e. addr < 0x80000000. Actually, it |
5606 |
+ |
turned out that a 32-bit binary run on AMD64 yields a cache |
5607 |
+ |
allocated around 0xa0000000, thus causing some troubles when |
5608 |
+ |
translating addresses from m68k to x86. |
5609 |
+ |
*/ |
5610 |
+ |
static uint8 * code_base = NULL; |
5611 |
+ |
if (code_base == NULL) { |
5612 |
+ |
uintptr page_size = getpagesize(); |
5613 |
+ |
uintptr boundaries = CODE_ALLOC_BOUNDARIES; |
5614 |
+ |
if (boundaries < page_size) |
5615 |
+ |
boundaries = page_size; |
5616 |
+ |
code_base = (uint8 *)sbrk(0); |
5617 |
+ |
for (int attempts = 0; attempts < CODE_ALLOC_MAX_ATTEMPTS; attempts++) { |
5618 |
+ |
if (vm_acquire_fixed(code_base, size) == 0) { |
5619 |
+ |
uint8 *code = code_base; |
5620 |
+ |
code_base += size; |
5621 |
+ |
return code; |
5622 |
+ |
} |
5623 |
+ |
code_base += boundaries; |
5624 |
+ |
} |
5625 |
+ |
return NULL; |
5626 |
+ |
} |
5627 |
+ |
|
5628 |
+ |
if (vm_acquire_fixed(code_base, size) == 0) { |
5629 |
+ |
uint8 *code = code_base; |
5630 |
+ |
code_base += size; |
5631 |
+ |
return code; |
5632 |
+ |
} |
5633 |
+ |
|
5634 |
+ |
if (depth >= CODE_ALLOC_MAX_ATTEMPTS) |
5635 |
+ |
return NULL; |
5636 |
+ |
|
5637 |
+ |
return do_alloc_code(size, depth + 1); |
5638 |
+ |
#else |
5639 |
+ |
uint8 *code = (uint8 *)vm_acquire(size); |
5640 |
+ |
return code == VM_MAP_FAILED ? NULL : code; |
5641 |
+ |
#endif |
5642 |
+ |
} |
5643 |
+ |
|
5644 |
+ |
static inline uint8 *alloc_code(uint32 size) |
5645 |
+ |
{ |
5646 |
+ |
return do_alloc_code(size, 0); |
5647 |
+ |
} |
5648 |
+ |
|
5649 |
|
void alloc_cache(void) |
5650 |
|
{ |
5651 |
|
if (compiled_code) { |
5658 |
|
return; |
5659 |
|
|
5660 |
|
while (!compiled_code && cache_size) { |
5661 |
< |
if ((compiled_code = (uae_u8 *)vm_acquire(cache_size * 1024)) == VM_MAP_FAILED) { |
5661 |
> |
if ((compiled_code = alloc_code(cache_size * 1024)) == NULL) { |
5662 |
|
compiled_code = 0; |
5663 |
|
cache_size /= 2; |
5664 |
|
} |
5665 |
|
} |
5666 |
< |
vm_protect(compiled_code, cache_size, VM_PAGE_READ | VM_PAGE_WRITE | VM_PAGE_EXECUTE); |
5666 |
> |
vm_protect(compiled_code, cache_size * 1024, VM_PAGE_READ | VM_PAGE_WRITE | VM_PAGE_EXECUTE); |
5667 |
|
|
5668 |
|
if (compiled_code) { |
5669 |
|
write_log("<JIT compiler> : actual translation cache size : %d KB at 0x%08X\n", cache_size, compiled_code); |
5675 |
|
|
5676 |
|
|
5677 |
|
|
5678 |
< |
extern cpuop_rettype op_illg_1 (uae_u32 opcode) REGPARAM; |
5678 |
> |
extern void op_illg_1 (uae_u32 opcode) REGPARAM; |
5679 |
|
|
5680 |
|
static void calc_checksum(blockinfo* bi, uae_u32* c1, uae_u32* c2) |
5681 |
|
{ |
5682 |
< |
uae_u32 k1=0; |
5683 |
< |
uae_u32 k2=0; |
5175 |
< |
uae_s32 len=bi->len; |
5176 |
< |
uae_u32 tmp=bi->min_pcp; |
5177 |
< |
uae_u32* pos; |
5682 |
> |
uae_u32 k1 = 0; |
5683 |
> |
uae_u32 k2 = 0; |
5684 |
|
|
5685 |
< |
len+=(tmp&3); |
5686 |
< |
tmp&=(~3); |
5687 |
< |
pos=(uae_u32*)tmp; |
5685 |
> |
#if USE_CHECKSUM_INFO |
5686 |
> |
checksum_info *csi = bi->csi; |
5687 |
> |
Dif(!csi) abort(); |
5688 |
> |
while (csi) { |
5689 |
> |
uae_s32 len = csi->length; |
5690 |
> |
uintptr tmp = (uintptr)csi->start_p; |
5691 |
> |
#else |
5692 |
> |
uae_s32 len = bi->len; |
5693 |
> |
uintptr tmp = (uintptr)bi->min_pcp; |
5694 |
> |
#endif |
5695 |
> |
uae_u32*pos; |
5696 |
|
|
5697 |
< |
if (len<0 || len>MAX_CHECKSUM_LEN) { |
5698 |
< |
*c1=0; |
5699 |
< |
*c2=0; |
5700 |
< |
} |
5701 |
< |
else { |
5702 |
< |
while (len>0) { |
5703 |
< |
k1+=*pos; |
5704 |
< |
k2^=*pos; |
5705 |
< |
pos++; |
5706 |
< |
len-=4; |
5697 |
> |
len += (tmp & 3); |
5698 |
> |
tmp &= ~((uintptr)3); |
5699 |
> |
pos = (uae_u32 *)tmp; |
5700 |
> |
|
5701 |
> |
if (len >= 0 && len <= MAX_CHECKSUM_LEN) { |
5702 |
> |
while (len > 0) { |
5703 |
> |
k1 += *pos; |
5704 |
> |
k2 ^= *pos; |
5705 |
> |
pos++; |
5706 |
> |
len -= 4; |
5707 |
> |
} |
5708 |
> |
} |
5709 |
> |
|
5710 |
> |
#if USE_CHECKSUM_INFO |
5711 |
> |
csi = csi->next; |
5712 |
|
} |
5713 |
< |
*c1=k1; |
5714 |
< |
*c2=k2; |
5715 |
< |
} |
5713 |
> |
#endif |
5714 |
> |
|
5715 |
> |
*c1 = k1; |
5716 |
> |
*c2 = k2; |
5717 |
|
} |
5718 |
|
|
5719 |
< |
static void show_checksum(blockinfo* bi) |
5719 |
> |
#if 0 |
5720 |
> |
static void show_checksum(CSI_TYPE* csi) |
5721 |
|
{ |
5722 |
|
uae_u32 k1=0; |
5723 |
|
uae_u32 k2=0; |
5724 |
< |
uae_s32 len=bi->len; |
5725 |
< |
uae_u32 tmp=(uae_u32)bi->pc_p; |
5724 |
> |
uae_s32 len=CSI_LENGTH(csi); |
5725 |
> |
uae_u32 tmp=(uintptr)CSI_START_P(csi); |
5726 |
|
uae_u32* pos; |
5727 |
|
|
5728 |
|
len+=(tmp&3); |
5741 |
|
write_log(" bla\n"); |
5742 |
|
} |
5743 |
|
} |
5744 |
+ |
#endif |
5745 |
|
|
5746 |
|
|
5747 |
|
int check_for_cache_miss(void) |
5795 |
|
static inline int block_check_checksum(blockinfo* bi) |
5796 |
|
{ |
5797 |
|
uae_u32 c1,c2; |
5798 |
< |
int isgood; |
5798 |
> |
bool isgood; |
5799 |
|
|
5800 |
|
if (bi->status!=BI_NEED_CHECK) |
5801 |
|
return 1; /* This block is in a checked state */ |
5802 |
|
|
5803 |
|
checksum_count++; |
5804 |
+ |
|
5805 |
|
if (bi->c1 || bi->c2) |
5806 |
|
calc_checksum(bi,&c1,&c2); |
5807 |
|
else { |
5808 |
|
c1=c2=1; /* Make sure it doesn't match */ |
5809 |
< |
} |
5809 |
> |
} |
5810 |
|
|
5811 |
|
isgood=(c1==bi->c1 && c2==bi->c2); |
5812 |
+ |
|
5813 |
|
if (isgood) { |
5814 |
|
/* This block is still OK. So we reactivate. Of course, that |
5815 |
|
means we have to move it into the needs-to-be-flushed list */ |
5914 |
|
} |
5915 |
|
} |
5916 |
|
|
5393 |
– |
static uae_u8 popallspace[1024]; /* That should be enough space */ |
5394 |
– |
|
5917 |
|
static __inline__ void create_popalls(void) |
5918 |
|
{ |
5919 |
|
int i,r; |
5920 |
|
|
5921 |
+ |
if ((popallspace = alloc_code(POPALLSPACE_SIZE)) == NULL) { |
5922 |
+ |
write_log("FATAL: Could not allocate popallspace!\n"); |
5923 |
+ |
abort(); |
5924 |
+ |
} |
5925 |
+ |
vm_protect(popallspace, POPALLSPACE_SIZE, VM_PAGE_READ | VM_PAGE_WRITE); |
5926 |
+ |
|
5927 |
|
current_compile_p=popallspace; |
5928 |
|
set_target(current_compile_p); |
5929 |
|
#if USE_PUSH_POP |
5931 |
|
registers before jumping back to the various get-out routines. |
5932 |
|
This generates the code for it. |
5933 |
|
*/ |
5934 |
< |
popall_do_nothing=current_compile_p; |
5934 |
> |
align_target(align_jumps); |
5935 |
> |
popall_do_nothing=get_target(); |
5936 |
|
for (i=0;i<N_REGS;i++) { |
5937 |
|
if (need_to_preserve[i]) |
5938 |
|
raw_pop_l_r(i); |
5939 |
|
} |
5940 |
< |
raw_jmp((uae_u32)do_nothing); |
5412 |
< |
align_target(32); |
5940 |
> |
raw_jmp((uintptr)do_nothing); |
5941 |
|
|
5942 |
+ |
align_target(align_jumps); |
5943 |
|
popall_execute_normal=get_target(); |
5944 |
|
for (i=0;i<N_REGS;i++) { |
5945 |
|
if (need_to_preserve[i]) |
5946 |
|
raw_pop_l_r(i); |
5947 |
|
} |
5948 |
< |
raw_jmp((uae_u32)execute_normal); |
5420 |
< |
align_target(32); |
5948 |
> |
raw_jmp((uintptr)execute_normal); |
5949 |
|
|
5950 |
+ |
align_target(align_jumps); |
5951 |
|
popall_cache_miss=get_target(); |
5952 |
|
for (i=0;i<N_REGS;i++) { |
5953 |
|
if (need_to_preserve[i]) |
5954 |
|
raw_pop_l_r(i); |
5955 |
|
} |
5956 |
< |
raw_jmp((uae_u32)cache_miss); |
5428 |
< |
align_target(32); |
5956 |
> |
raw_jmp((uintptr)cache_miss); |
5957 |
|
|
5958 |
+ |
align_target(align_jumps); |
5959 |
|
popall_recompile_block=get_target(); |
5960 |
|
for (i=0;i<N_REGS;i++) { |
5961 |
|
if (need_to_preserve[i]) |
5962 |
|
raw_pop_l_r(i); |
5963 |
|
} |
5964 |
< |
raw_jmp((uae_u32)recompile_block); |
5965 |
< |
align_target(32); |
5966 |
< |
|
5964 |
> |
raw_jmp((uintptr)recompile_block); |
5965 |
> |
|
5966 |
> |
align_target(align_jumps); |
5967 |
|
popall_exec_nostats=get_target(); |
5968 |
|
for (i=0;i<N_REGS;i++) { |
5969 |
|
if (need_to_preserve[i]) |
5970 |
|
raw_pop_l_r(i); |
5971 |
|
} |
5972 |
< |
raw_jmp((uae_u32)exec_nostats); |
5973 |
< |
align_target(32); |
5974 |
< |
|
5972 |
> |
raw_jmp((uintptr)exec_nostats); |
5973 |
> |
|
5974 |
> |
align_target(align_jumps); |
5975 |
|
popall_check_checksum=get_target(); |
5976 |
|
for (i=0;i<N_REGS;i++) { |
5977 |
|
if (need_to_preserve[i]) |
5978 |
|
raw_pop_l_r(i); |
5979 |
|
} |
5980 |
< |
raw_jmp((uae_u32)check_checksum); |
5981 |
< |
align_target(32); |
5982 |
< |
|
5980 |
> |
raw_jmp((uintptr)check_checksum); |
5981 |
> |
|
5982 |
> |
align_target(align_jumps); |
5983 |
|
current_compile_p=get_target(); |
5984 |
|
#else |
5985 |
|
popall_exec_nostats=(void *)exec_nostats; |
5988 |
|
popall_recompile_block=(void *)recompile_block; |
5989 |
|
popall_do_nothing=(void *)do_nothing; |
5990 |
|
popall_check_checksum=(void *)check_checksum; |
5462 |
– |
pushall_call_handler=get_target(); |
5991 |
|
#endif |
5992 |
|
|
5993 |
|
/* And now, the code to do the matching pushes and then jump |
6000 |
|
} |
6001 |
|
#endif |
6002 |
|
r=REG_PC_TMP; |
6003 |
< |
raw_mov_l_rm(r,(uae_u32)®s.pc_p); |
6003 |
> |
raw_mov_l_rm(r,(uintptr)®s.pc_p); |
6004 |
> |
raw_and_l_ri(r,TAGMASK); |
6005 |
> |
raw_jmp_m_indexed((uintptr)cache_tags,r,SIZEOF_VOID_P); |
6006 |
> |
|
6007 |
> |
#if defined(X86_ASSEMBLY) || defined(X86_64_ASSEMBLY) |
6008 |
> |
align_target(align_jumps); |
6009 |
> |
m68k_compile_execute = (void (*)(void))get_target(); |
6010 |
> |
for (i=N_REGS;i--;) { |
6011 |
> |
if (need_to_preserve[i]) |
6012 |
> |
raw_push_l_r(i); |
6013 |
> |
} |
6014 |
> |
align_target(align_loops); |
6015 |
> |
uae_u32 dispatch_loop = (uintptr)get_target(); |
6016 |
> |
r=REG_PC_TMP; |
6017 |
> |
raw_mov_l_rm(r,(uintptr)®s.pc_p); |
6018 |
|
raw_and_l_ri(r,TAGMASK); |
6019 |
< |
raw_jmp_m_indexed((uae_u32)cache_tags,r,4); |
6019 |
> |
raw_call_m_indexed((uintptr)cache_tags,r,SIZEOF_VOID_P); |
6020 |
> |
raw_cmp_l_mi((uintptr)®s.spcflags,0); |
6021 |
> |
raw_jcc_b_oponly(NATIVE_CC_EQ); |
6022 |
> |
emit_byte(dispatch_loop-((uintptr)get_target()+1)); |
6023 |
> |
raw_call((uintptr)m68k_do_specialties); |
6024 |
> |
raw_test_l_rr(REG_RESULT,REG_RESULT); |
6025 |
> |
raw_jcc_b_oponly(NATIVE_CC_EQ); |
6026 |
> |
emit_byte(dispatch_loop-((uintptr)get_target()+1)); |
6027 |
> |
raw_cmp_b_mi((uintptr)&quit_program,0); |
6028 |
> |
raw_jcc_b_oponly(NATIVE_CC_EQ); |
6029 |
> |
emit_byte(dispatch_loop-((uintptr)get_target()+1)); |
6030 |
> |
for (i=0;i<N_REGS;i++) { |
6031 |
> |
if (need_to_preserve[i]) |
6032 |
> |
raw_pop_l_r(i); |
6033 |
> |
} |
6034 |
> |
raw_ret(); |
6035 |
> |
#endif |
6036 |
> |
|
6037 |
> |
// no need to further write into popallspace |
6038 |
> |
vm_protect(popallspace, POPALLSPACE_SIZE, VM_PAGE_READ | VM_PAGE_EXECUTE); |
6039 |
|
} |
6040 |
|
|
6041 |
|
static __inline__ void reset_lists(void) |
6053 |
|
int i; |
6054 |
|
|
6055 |
|
set_target(current_compile_p); |
6056 |
< |
align_target(32); |
6056 |
> |
align_target(align_jumps); |
6057 |
|
bi->direct_pen=(cpuop_func *)get_target(); |
6058 |
< |
raw_mov_l_rm(0,(uae_u32)&(bi->pc_p)); |
6059 |
< |
raw_mov_l_mr((uae_u32)®s.pc_p,0); |
6060 |
< |
raw_jmp((uae_u32)popall_execute_normal); |
6058 |
> |
raw_mov_l_rm(0,(uintptr)&(bi->pc_p)); |
6059 |
> |
raw_mov_l_mr((uintptr)®s.pc_p,0); |
6060 |
> |
raw_jmp((uintptr)popall_execute_normal); |
6061 |
|
|
6062 |
< |
align_target(32); |
6062 |
> |
align_target(align_jumps); |
6063 |
|
bi->direct_pcc=(cpuop_func *)get_target(); |
6064 |
< |
raw_mov_l_rm(0,(uae_u32)&(bi->pc_p)); |
6065 |
< |
raw_mov_l_mr((uae_u32)®s.pc_p,0); |
6066 |
< |
raw_jmp((uae_u32)popall_check_checksum); |
5506 |
< |
|
5507 |
< |
align_target(32); |
6064 |
> |
raw_mov_l_rm(0,(uintptr)&(bi->pc_p)); |
6065 |
> |
raw_mov_l_mr((uintptr)®s.pc_p,0); |
6066 |
> |
raw_jmp((uintptr)popall_check_checksum); |
6067 |
|
current_compile_p=get_target(); |
6068 |
|
|
6069 |
|
bi->deplist=NULL; |
6077 |
|
//bi->env=empty_ss; |
6078 |
|
} |
6079 |
|
|
6080 |
+ |
// OPCODE is in big endian format, use cft_map() beforehand, if needed. |
6081 |
+ |
static inline void reset_compop(int opcode) |
6082 |
+ |
{ |
6083 |
+ |
compfunctbl[opcode] = NULL; |
6084 |
+ |
nfcompfunctbl[opcode] = NULL; |
6085 |
+ |
} |
6086 |
+ |
|
6087 |
+ |
static int read_opcode(const char *p) |
6088 |
+ |
{ |
6089 |
+ |
int opcode = 0; |
6090 |
+ |
for (int i = 0; i < 4; i++) { |
6091 |
+ |
int op = p[i]; |
6092 |
+ |
switch (op) { |
6093 |
+ |
case '0': case '1': case '2': case '3': case '4': |
6094 |
+ |
case '5': case '6': case '7': case '8': case '9': |
6095 |
+ |
opcode = (opcode << 4) | (op - '0'); |
6096 |
+ |
break; |
6097 |
+ |
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': |
6098 |
+ |
opcode = (opcode << 4) | ((op - 'a') + 10); |
6099 |
+ |
break; |
6100 |
+ |
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': |
6101 |
+ |
opcode = (opcode << 4) | ((op - 'A') + 10); |
6102 |
+ |
break; |
6103 |
+ |
default: |
6104 |
+ |
return -1; |
6105 |
+ |
} |
6106 |
+ |
} |
6107 |
+ |
return opcode; |
6108 |
+ |
} |
6109 |
+ |
|
6110 |
+ |
static bool merge_blacklist() |
6111 |
+ |
{ |
6112 |
+ |
const char *blacklist = PrefsFindString("jitblacklist"); |
6113 |
+ |
if (blacklist) { |
6114 |
+ |
const char *p = blacklist; |
6115 |
+ |
for (;;) { |
6116 |
+ |
if (*p == 0) |
6117 |
+ |
return true; |
6118 |
+ |
|
6119 |
+ |
int opcode1 = read_opcode(p); |
6120 |
+ |
if (opcode1 < 0) |
6121 |
+ |
return false; |
6122 |
+ |
p += 4; |
6123 |
+ |
|
6124 |
+ |
int opcode2 = opcode1; |
6125 |
+ |
if (*p == '-') { |
6126 |
+ |
p++; |
6127 |
+ |
opcode2 = read_opcode(p); |
6128 |
+ |
if (opcode2 < 0) |
6129 |
+ |
return false; |
6130 |
+ |
p += 4; |
6131 |
+ |
} |
6132 |
+ |
|
6133 |
+ |
if (*p == 0 || *p == ';') { |
6134 |
+ |
write_log("<JIT compiler> : blacklist opcodes : %04x-%04x\n", opcode1, opcode2); |
6135 |
+ |
for (int opcode = opcode1; opcode <= opcode2; opcode++) |
6136 |
+ |
reset_compop(cft_map(opcode)); |
6137 |
+ |
|
6138 |
+ |
if (*p++ == ';') |
6139 |
+ |
continue; |
6140 |
+ |
|
6141 |
+ |
return true; |
6142 |
+ |
} |
6143 |
+ |
|
6144 |
+ |
return false; |
6145 |
+ |
} |
6146 |
+ |
} |
6147 |
+ |
return true; |
6148 |
+ |
} |
6149 |
+ |
|
6150 |
|
void build_comp(void) |
6151 |
|
{ |
6152 |
|
int i; |
6176 |
|
write_log ("<JIT compiler> : building compiler function tables\n"); |
6177 |
|
|
6178 |
|
for (opcode = 0; opcode < 65536; opcode++) { |
6179 |
+ |
reset_compop(opcode); |
6180 |
|
nfcpufunctbl[opcode] = op_illg_1; |
5551 |
– |
compfunctbl[opcode] = NULL; |
5552 |
– |
nfcompfunctbl[opcode] = NULL; |
6181 |
|
prop[opcode].use_flags = 0x1f; |
6182 |
|
prop[opcode].set_flags = 0x1f; |
6183 |
|
prop[opcode].cflow = fl_trap; // ILLEGAL instructions do trap |
6185 |
|
|
6186 |
|
for (i = 0; tbl[i].opcode < 65536; i++) { |
6187 |
|
int cflow = table68k[tbl[i].opcode].cflow; |
6188 |
+ |
if (USE_INLINING && ((cflow & fl_const_jump) != 0)) |
6189 |
+ |
cflow = fl_const_jump; |
6190 |
+ |
else |
6191 |
+ |
cflow &= ~fl_const_jump; |
6192 |
|
prop[cft_map(tbl[i].opcode)].cflow = cflow; |
6193 |
|
|
6194 |
|
int uses_fpu = tbl[i].specific & 32; |
6243 |
|
nfcpufunctbl[cft_map(tbl[i].opcode)] = nfctbl[i].handler; |
6244 |
|
} |
6245 |
|
|
6246 |
+ |
/* Merge in blacklist */ |
6247 |
+ |
if (!merge_blacklist()) |
6248 |
+ |
write_log("<JIT compiler> : blacklist merge failure!\n"); |
6249 |
+ |
|
6250 |
|
count=0; |
6251 |
|
for (opcode = 0; opcode < 65536; opcode++) { |
6252 |
|
if (compfunctbl[cft_map(opcode)]) |
6365 |
|
active=NULL; |
6366 |
|
} |
6367 |
|
|
6368 |
+ |
void flush_icache_range(uae_u32 start, uae_u32 length) |
6369 |
+ |
{ |
6370 |
+ |
if (!active) |
6371 |
+ |
return; |
6372 |
+ |
|
6373 |
+ |
#if LAZY_FLUSH_ICACHE_RANGE |
6374 |
+ |
uae_u8 *start_p = get_real_address(start); |
6375 |
+ |
blockinfo *bi = active; |
6376 |
+ |
while (bi) { |
6377 |
+ |
#if USE_CHECKSUM_INFO |
6378 |
+ |
bool invalidate = false; |
6379 |
+ |
for (checksum_info *csi = bi->csi; csi && !invalidate; csi = csi->next) |
6380 |
+ |
invalidate = (((start_p - csi->start_p) < csi->length) || |
6381 |
+ |
((csi->start_p - start_p) < length)); |
6382 |
+ |
#else |
6383 |
+ |
// Assume system is consistent and would invalidate the right range |
6384 |
+ |
const bool invalidate = (bi->pc_p - start_p) < length; |
6385 |
+ |
#endif |
6386 |
+ |
if (invalidate) { |
6387 |
+ |
uae_u32 cl = cacheline(bi->pc_p); |
6388 |
+ |
if (bi == cache_tags[cl + 1].bi) |
6389 |
+ |
cache_tags[cl].handler = (cpuop_func *)popall_execute_normal; |
6390 |
+ |
bi->handler_to_use = (cpuop_func *)popall_execute_normal; |
6391 |
+ |
set_dhtu(bi, bi->direct_pen); |
6392 |
+ |
bi->status = BI_NEED_RECOMP; |
6393 |
+ |
} |
6394 |
+ |
bi = bi->next; |
6395 |
+ |
} |
6396 |
+ |
return; |
6397 |
+ |
#endif |
6398 |
+ |
flush_icache(-1); |
6399 |
+ |
} |
6400 |
+ |
|
6401 |
|
static void catastrophe(void) |
6402 |
|
{ |
6403 |
|
abort(); |
6408 |
|
#define TARGET_M68K 0 |
6409 |
|
#define TARGET_POWERPC 1 |
6410 |
|
#define TARGET_X86 2 |
6411 |
+ |
#define TARGET_X86_64 3 |
6412 |
|
#if defined(i386) || defined(__i386__) |
6413 |
|
#define TARGET_NATIVE TARGET_X86 |
6414 |
|
#endif |
6415 |
|
#if defined(powerpc) || defined(__powerpc__) |
6416 |
|
#define TARGET_NATIVE TARGET_POWERPC |
6417 |
|
#endif |
6418 |
+ |
#if defined(x86_64) || defined(__x86_64__) |
6419 |
+ |
#define TARGET_NATIVE TARGET_X86_64 |
6420 |
+ |
#endif |
6421 |
|
|
6422 |
|
#ifdef ENABLE_MON |
6423 |
< |
static uae_u32 mon_read_byte_jit(uae_u32 addr) |
6423 |
> |
static uae_u32 mon_read_byte_jit(uintptr addr) |
6424 |
|
{ |
6425 |
|
uae_u8 *m = (uae_u8 *)addr; |
6426 |
< |
return (uae_u32)(*m); |
6426 |
> |
return (uintptr)(*m); |
6427 |
|
} |
6428 |
|
|
6429 |
< |
static void mon_write_byte_jit(uae_u32 addr, uae_u32 b) |
6429 |
> |
static void mon_write_byte_jit(uintptr addr, uae_u32 b) |
6430 |
|
{ |
6431 |
|
uae_u8 *m = (uae_u8 *)addr; |
6432 |
|
*m = b; |
6443 |
|
sprintf(disasm_str, "%s $%x $%x", |
6444 |
|
target == TARGET_M68K ? "d68" : |
6445 |
|
target == TARGET_X86 ? "d86" : |
6446 |
+ |
target == TARGET_X86_64 ? "d8664" : |
6447 |
|
target == TARGET_POWERPC ? "d" : "x", |
6448 |
|
start, start + length - 1); |
6449 |
|
|
6450 |
< |
uae_u32 (*old_mon_read_byte)(uae_u32) = mon_read_byte; |
6451 |
< |
void (*old_mon_write_byte)(uae_u32, uae_u32) = mon_write_byte; |
6450 |
> |
uae_u32 (*old_mon_read_byte)(uintptr) = mon_read_byte; |
6451 |
> |
void (*old_mon_write_byte)(uintptr, uae_u32) = mon_write_byte; |
6452 |
|
|
6453 |
|
mon_read_byte = mon_read_byte_jit; |
6454 |
|
mon_write_byte = mon_write_byte_jit; |
6461 |
|
#endif |
6462 |
|
} |
6463 |
|
|
6464 |
< |
static inline void disasm_native_block(uint8 *start, size_t length) |
6464 |
> |
static void disasm_native_block(uint8 *start, size_t length) |
6465 |
|
{ |
6466 |
|
disasm_block(TARGET_NATIVE, start, length); |
6467 |
|
} |
6468 |
|
|
6469 |
< |
static inline void disasm_m68k_block(uint8 *start, size_t length) |
6469 |
> |
static void disasm_m68k_block(uint8 *start, size_t length) |
6470 |
|
{ |
6471 |
|
disasm_block(TARGET_M68K, start, length); |
6472 |
|
} |
6500 |
|
|
6501 |
|
write_log("### Block in Mac address space\n"); |
6502 |
|
write_log("M68K block : %p\n", |
6503 |
< |
(void *)get_virtual_address(last_regs_pc_p)); |
6503 |
> |
(void *)(uintptr)get_virtual_address(last_regs_pc_p)); |
6504 |
|
write_log("Native block : %p (%d bytes)\n", |
6505 |
< |
(void *)get_virtual_address(last_compiled_block_addr), |
6505 |
> |
(void *)(uintptr)get_virtual_address(last_compiled_block_addr), |
6506 |
|
get_blockinfo_addr(last_regs_pc_p)->direct_handler_size); |
6507 |
|
write_log("\n"); |
6508 |
|
} |
6524 |
|
int r; |
6525 |
|
int was_comp=0; |
6526 |
|
uae_u8 liveflags[MAXRUN+1]; |
6527 |
< |
uae_u32 max_pcp=(uae_u32)pc_hist[0].location; |
6528 |
< |
uae_u32 min_pcp=max_pcp; |
6527 |
> |
#if USE_CHECKSUM_INFO |
6528 |
> |
bool trace_in_rom = isinrom((uintptr)pc_hist[0].location); |
6529 |
> |
uintptr max_pcp=(uintptr)pc_hist[blocklen - 1].location; |
6530 |
> |
uintptr min_pcp=max_pcp; |
6531 |
> |
#else |
6532 |
> |
uintptr max_pcp=(uintptr)pc_hist[0].location; |
6533 |
> |
uintptr min_pcp=max_pcp; |
6534 |
> |
#endif |
6535 |
|
uae_u32 cl=cacheline(pc_hist[0].location); |
6536 |
|
void* specflags=(void*)®s.spcflags; |
6537 |
|
blockinfo* bi=NULL; |
6570 |
|
optlev++; |
6571 |
|
bi->count=optcount[optlev]-1; |
6572 |
|
} |
6573 |
< |
current_block_pc_p=(uae_u32)pc_hist[0].location; |
6573 |
> |
current_block_pc_p=(uintptr)pc_hist[0].location; |
6574 |
|
|
6575 |
|
remove_deps(bi); /* We are about to create new code */ |
6576 |
|
bi->optlevel=optlev; |
6577 |
|
bi->pc_p=(uae_u8*)pc_hist[0].location; |
6578 |
+ |
#if USE_CHECKSUM_INFO |
6579 |
+ |
free_checksum_info_chain(bi->csi); |
6580 |
+ |
bi->csi = NULL; |
6581 |
+ |
#endif |
6582 |
|
|
6583 |
|
liveflags[blocklen]=0x1f; /* All flags needed afterwards */ |
6584 |
|
i=blocklen; |
6586 |
|
uae_u16* currpcp=pc_hist[i].location; |
6587 |
|
uae_u32 op=DO_GET_OPCODE(currpcp); |
6588 |
|
|
6589 |
< |
if ((uae_u32)currpcp<min_pcp) |
6590 |
< |
min_pcp=(uae_u32)currpcp; |
6591 |
< |
if ((uae_u32)currpcp>max_pcp) |
6592 |
< |
max_pcp=(uae_u32)currpcp; |
6589 |
> |
#if USE_CHECKSUM_INFO |
6590 |
> |
trace_in_rom = trace_in_rom && isinrom((uintptr)currpcp); |
6591 |
> |
#if USE_INLINING |
6592 |
> |
if (is_const_jump(op)) { |
6593 |
> |
checksum_info *csi = alloc_checksum_info(); |
6594 |
> |
csi->start_p = (uae_u8 *)min_pcp; |
6595 |
> |
csi->length = max_pcp - min_pcp + LONGEST_68K_INST; |
6596 |
> |
csi->next = bi->csi; |
6597 |
> |
bi->csi = csi; |
6598 |
> |
max_pcp = (uintptr)currpcp; |
6599 |
> |
} |
6600 |
> |
#endif |
6601 |
> |
min_pcp = (uintptr)currpcp; |
6602 |
> |
#else |
6603 |
> |
if ((uintptr)currpcp<min_pcp) |
6604 |
> |
min_pcp=(uintptr)currpcp; |
6605 |
> |
if ((uintptr)currpcp>max_pcp) |
6606 |
> |
max_pcp=(uintptr)currpcp; |
6607 |
> |
#endif |
6608 |
|
|
6609 |
|
liveflags[i]=((liveflags[i+1]& |
6610 |
|
(~prop[op].set_flags))| |
6613 |
|
liveflags[i]&= ~FLAG_Z; |
6614 |
|
} |
6615 |
|
|
6616 |
+ |
#if USE_CHECKSUM_INFO |
6617 |
+ |
checksum_info *csi = alloc_checksum_info(); |
6618 |
+ |
csi->start_p = (uae_u8 *)min_pcp; |
6619 |
+ |
csi->length = max_pcp - min_pcp + LONGEST_68K_INST; |
6620 |
+ |
csi->next = bi->csi; |
6621 |
+ |
bi->csi = csi; |
6622 |
+ |
#endif |
6623 |
+ |
|
6624 |
|
bi->needed_flags=liveflags[0]; |
6625 |
|
|
6626 |
< |
align_target(32); |
6626 |
> |
align_target(align_loops); |
6627 |
|
was_comp=0; |
6628 |
|
|
6629 |
|
bi->direct_handler=(cpuop_func *)get_target(); |
6630 |
|
set_dhtu(bi,bi->direct_handler); |
6631 |
|
bi->status=BI_COMPILING; |
6632 |
< |
current_block_start_target=(uae_u32)get_target(); |
6632 |
> |
current_block_start_target=(uintptr)get_target(); |
6633 |
|
|
6634 |
|
log_startblock(); |
6635 |
|
|
6636 |
|
if (bi->count>=0) { /* Need to generate countdown code */ |
6637 |
< |
raw_mov_l_mi((uae_u32)®s.pc_p,(uae_u32)pc_hist[0].location); |
6638 |
< |
raw_sub_l_mi((uae_u32)&(bi->count),1); |
6639 |
< |
raw_jl((uae_u32)popall_recompile_block); |
6637 |
> |
raw_mov_l_mi((uintptr)®s.pc_p,(uintptr)pc_hist[0].location); |
6638 |
> |
raw_sub_l_mi((uintptr)&(bi->count),1); |
6639 |
> |
raw_jl((uintptr)popall_recompile_block); |
6640 |
|
} |
6641 |
|
if (optlev==0) { /* No need to actually translate */ |
6642 |
|
/* Execute normally without keeping stats */ |
6643 |
< |
raw_mov_l_mi((uae_u32)®s.pc_p,(uae_u32)pc_hist[0].location); |
6644 |
< |
raw_jmp((uae_u32)popall_exec_nostats); |
6643 |
> |
raw_mov_l_mi((uintptr)®s.pc_p,(uintptr)pc_hist[0].location); |
6644 |
> |
raw_jmp((uintptr)popall_exec_nostats); |
6645 |
|
} |
6646 |
|
else { |
6647 |
|
reg_alloc_run=0; |
6655 |
|
|
6656 |
|
#if JIT_DEBUG |
6657 |
|
if (JITDebug) { |
6658 |
< |
raw_mov_l_mi((uae_u32)&last_regs_pc_p,(uae_u32)pc_hist[0].location); |
6659 |
< |
raw_mov_l_mi((uae_u32)&last_compiled_block_addr,(uae_u32)current_block_start_target); |
6658 |
> |
raw_mov_l_mi((uintptr)&last_regs_pc_p,(uintptr)pc_hist[0].location); |
6659 |
> |
raw_mov_l_mi((uintptr)&last_compiled_block_addr,current_block_start_target); |
6660 |
|
} |
6661 |
|
#endif |
6662 |
|
|
6682 |
|
comp_pc_p=(uae_u8*)pc_hist[i].location; |
6683 |
|
init_comp(); |
6684 |
|
} |
6685 |
< |
was_comp++; |
6685 |
> |
was_comp=1; |
6686 |
|
|
6687 |
|
comptbl[opcode](opcode); |
6688 |
|
freescratch(); |
6707 |
|
#if USE_NORMAL_CALLING_CONVENTION |
6708 |
|
raw_push_l_r(REG_PAR1); |
6709 |
|
#endif |
6710 |
< |
raw_mov_l_mi((uae_u32)®s.pc_p, |
6711 |
< |
(uae_u32)pc_hist[i].location); |
6712 |
< |
raw_call((uae_u32)cputbl[opcode]); |
6713 |
< |
//raw_add_l_mi((uae_u32)&oink,1); // FIXME |
6710 |
> |
raw_mov_l_mi((uintptr)®s.pc_p, |
6711 |
> |
(uintptr)pc_hist[i].location); |
6712 |
> |
raw_call((uintptr)cputbl[opcode]); |
6713 |
> |
#if PROFILE_UNTRANSLATED_INSNS |
6714 |
> |
// raw_cputbl_count[] is indexed with plain opcode (in m68k order) |
6715 |
> |
raw_add_l_mi((uintptr)&raw_cputbl_count[cft_map(opcode)],1); |
6716 |
> |
#endif |
6717 |
|
#if USE_NORMAL_CALLING_CONVENTION |
6718 |
|
raw_inc_sp(4); |
6719 |
|
#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 |
– |
} |
6720 |
|
|
6721 |
|
if (i < blocklen - 1) { |
6722 |
|
uae_s8* branchadd; |
6723 |
|
|
6724 |
< |
raw_mov_l_rm(0,(uae_u32)specflags); |
6724 |
> |
raw_mov_l_rm(0,(uintptr)specflags); |
6725 |
|
raw_test_l_rr(0,0); |
6726 |
|
raw_jz_b_oponly(); |
6727 |
|
branchadd=(uae_s8 *)get_target(); |
6728 |
|
emit_byte(0); |
6729 |
< |
raw_jmp((uae_u32)popall_do_nothing); |
6730 |
< |
*branchadd=(uae_u32)get_target()-(uae_u32)branchadd-1; |
6729 |
> |
raw_jmp((uintptr)popall_do_nothing); |
6730 |
> |
*branchadd=(uintptr)get_target()-(uintptr)branchadd-1; |
6731 |
|
} |
6732 |
|
} |
6733 |
|
} |
6761 |
|
log_flush(); |
6762 |
|
|
6763 |
|
if (next_pc_p) { /* A branch was registered */ |
6764 |
< |
uae_u32 t1=next_pc_p; |
6765 |
< |
uae_u32 t2=taken_pc_p; |
6764 |
> |
uintptr t1=next_pc_p; |
6765 |
> |
uintptr t2=taken_pc_p; |
6766 |
|
int cc=branch_cc; |
6767 |
|
|
6768 |
|
uae_u32* branchadd; |
6787 |
|
/* predicted outcome */ |
6788 |
|
tbi=get_blockinfo_addr_new((void*)t1,1); |
6789 |
|
match_states(tbi); |
6790 |
< |
raw_cmp_l_mi((uae_u32)specflags,0); |
6790 |
> |
raw_cmp_l_mi((uintptr)specflags,0); |
6791 |
|
raw_jcc_l_oponly(4); |
6792 |
|
tba=(uae_u32*)get_target(); |
6793 |
< |
emit_long(get_handler(t1)-((uae_u32)tba+4)); |
6794 |
< |
raw_mov_l_mi((uae_u32)®s.pc_p,t1); |
6795 |
< |
raw_jmp((uae_u32)popall_do_nothing); |
6793 |
> |
emit_long(get_handler(t1)-((uintptr)tba+4)); |
6794 |
> |
raw_mov_l_mi((uintptr)®s.pc_p,t1); |
6795 |
> |
raw_jmp((uintptr)popall_do_nothing); |
6796 |
|
create_jmpdep(bi,0,tba,t1); |
6797 |
|
|
6798 |
< |
align_target(16); |
6798 |
> |
align_target(align_jumps); |
6799 |
|
/* not-predicted outcome */ |
6800 |
< |
*branchadd=(uae_u32)get_target()-((uae_u32)branchadd+4); |
6800 |
> |
*branchadd=(uintptr)get_target()-((uintptr)branchadd+4); |
6801 |
|
live=tmp; /* Ouch again */ |
6802 |
|
tbi=get_blockinfo_addr_new((void*)t2,1); |
6803 |
|
match_states(tbi); |
6804 |
|
|
6805 |
|
//flush(1); /* Can only get here if was_comp==1 */ |
6806 |
< |
raw_cmp_l_mi((uae_u32)specflags,0); |
6806 |
> |
raw_cmp_l_mi((uintptr)specflags,0); |
6807 |
|
raw_jcc_l_oponly(4); |
6808 |
|
tba=(uae_u32*)get_target(); |
6809 |
< |
emit_long(get_handler(t2)-((uae_u32)tba+4)); |
6810 |
< |
raw_mov_l_mi((uae_u32)®s.pc_p,t2); |
6811 |
< |
raw_jmp((uae_u32)popall_do_nothing); |
6809 |
> |
emit_long(get_handler(t2)-((uintptr)tba+4)); |
6810 |
> |
raw_mov_l_mi((uintptr)®s.pc_p,t2); |
6811 |
> |
raw_jmp((uintptr)popall_do_nothing); |
6812 |
|
create_jmpdep(bi,1,tba,t2); |
6813 |
|
} |
6814 |
|
else |
6822 |
|
r=live.state[PC_P].realreg; |
6823 |
|
raw_and_l_ri(r,TAGMASK); |
6824 |
|
int r2 = (r==0) ? 1 : 0; |
6825 |
< |
raw_mov_l_ri(r2,(uae_u32)popall_do_nothing); |
6826 |
< |
raw_cmp_l_mi((uae_u32)specflags,0); |
6827 |
< |
raw_cmov_l_rm_indexed(r2,(uae_u32)cache_tags,r,4,4); |
6825 |
> |
raw_mov_l_ri(r2,(uintptr)popall_do_nothing); |
6826 |
> |
raw_cmp_l_mi((uintptr)specflags,0); |
6827 |
> |
raw_cmov_l_rm_indexed(r2,(uintptr)cache_tags,r,SIZEOF_VOID_P,NATIVE_CC_EQ); |
6828 |
|
raw_jmp_r(r2); |
6829 |
|
} |
6830 |
|
else if (was_comp && isconst(PC_P)) { |
6832 |
|
uae_u32* tba; |
6833 |
|
blockinfo* tbi; |
6834 |
|
|
6835 |
< |
tbi=get_blockinfo_addr_new((void*)v,1); |
6835 |
> |
tbi=get_blockinfo_addr_new((void*)(uintptr)v,1); |
6836 |
|
match_states(tbi); |
6837 |
|
|
6838 |
< |
raw_cmp_l_mi((uae_u32)specflags,0); |
6838 |
> |
raw_cmp_l_mi((uintptr)specflags,0); |
6839 |
|
raw_jcc_l_oponly(4); |
6840 |
|
tba=(uae_u32*)get_target(); |
6841 |
< |
emit_long(get_handler(v)-((uae_u32)tba+4)); |
6842 |
< |
raw_mov_l_mi((uae_u32)®s.pc_p,v); |
6843 |
< |
raw_jmp((uae_u32)popall_do_nothing); |
6841 |
> |
emit_long(get_handler(v)-((uintptr)tba+4)); |
6842 |
> |
raw_mov_l_mi((uintptr)®s.pc_p,v); |
6843 |
> |
raw_jmp((uintptr)popall_do_nothing); |
6844 |
|
create_jmpdep(bi,0,tba,v); |
6845 |
|
} |
6846 |
|
else { |
6847 |
|
r=REG_PC_TMP; |
6848 |
< |
raw_mov_l_rm(r,(uae_u32)®s.pc_p); |
6848 |
> |
raw_mov_l_rm(r,(uintptr)®s.pc_p); |
6849 |
|
raw_and_l_ri(r,TAGMASK); |
6850 |
|
int r2 = (r==0) ? 1 : 0; |
6851 |
< |
raw_mov_l_ri(r2,(uae_u32)popall_do_nothing); |
6852 |
< |
raw_cmp_l_mi((uae_u32)specflags,0); |
6853 |
< |
raw_cmov_l_rm_indexed(r2,(uae_u32)cache_tags,r,4,4); |
6851 |
> |
raw_mov_l_ri(r2,(uintptr)popall_do_nothing); |
6852 |
> |
raw_cmp_l_mi((uintptr)specflags,0); |
6853 |
> |
raw_cmov_l_rm_indexed(r2,(uintptr)cache_tags,r,SIZEOF_VOID_P,NATIVE_CC_EQ); |
6854 |
|
raw_jmp_r(r2); |
6855 |
|
} |
6856 |
|
} |
6864 |
|
big_to_small_state(&live,&(bi->env)); |
6865 |
|
#endif |
6866 |
|
|
6867 |
+ |
#if USE_CHECKSUM_INFO |
6868 |
+ |
remove_from_list(bi); |
6869 |
+ |
if (trace_in_rom) { |
6870 |
+ |
// No need to checksum that block trace on cache invalidation |
6871 |
+ |
free_checksum_info_chain(bi->csi); |
6872 |
+ |
bi->csi = NULL; |
6873 |
+ |
add_to_dormant(bi); |
6874 |
+ |
} |
6875 |
+ |
else { |
6876 |
+ |
calc_checksum(bi,&(bi->c1),&(bi->c2)); |
6877 |
+ |
add_to_active(bi); |
6878 |
+ |
} |
6879 |
+ |
#else |
6880 |
|
if (next_pc_p+extra_len>=max_pcp && |
6881 |
|
next_pc_p+extra_len<max_pcp+LONGEST_68K_INST) |
6882 |
|
max_pcp=next_pc_p+extra_len; /* extra_len covers flags magic */ |
6883 |
|
else |
6884 |
|
max_pcp+=LONGEST_68K_INST; |
6885 |
+ |
|
6886 |
|
bi->len=max_pcp-min_pcp; |
6887 |
|
bi->min_pcp=min_pcp; |
6888 |
< |
|
6888 |
> |
|
6889 |
|
remove_from_list(bi); |
6890 |
|
if (isinrom(min_pcp) && isinrom(max_pcp)) { |
6891 |
|
add_to_dormant(bi); /* No need to checksum it on cache flush. |
6896 |
|
calc_checksum(bi,&(bi->c1),&(bi->c2)); |
6897 |
|
add_to_active(bi); |
6898 |
|
} |
6899 |
+ |
#endif |
6900 |
|
|
6901 |
|
current_cache_size += get_target() - (uae_u8 *)current_compile_p; |
6902 |
|
|
6916 |
|
#endif |
6917 |
|
|
6918 |
|
log_dump(); |
6919 |
< |
align_target(32); |
6919 |
> |
align_target(align_jumps); |
6920 |
|
|
6921 |
|
/* This is the non-direct handler */ |
6922 |
|
bi->handler= |
6923 |
|
bi->handler_to_use=(cpuop_func *)get_target(); |
6924 |
< |
raw_cmp_l_mi((uae_u32)®s.pc_p,(uae_u32)pc_hist[0].location); |
6925 |
< |
raw_jnz((uae_u32)popall_cache_miss); |
6924 |
> |
raw_cmp_l_mi((uintptr)®s.pc_p,(uintptr)pc_hist[0].location); |
6925 |
> |
raw_jnz((uintptr)popall_cache_miss); |
6926 |
|
comp_pc_p=(uae_u8*)pc_hist[0].location; |
6927 |
|
|
6928 |
|
bi->status=BI_FINALIZING; |
6930 |
|
match_states(bi); |
6931 |
|
flush(1); |
6932 |
|
|
6933 |
< |
raw_jmp((uae_u32)bi->direct_handler); |
6933 |
> |
raw_jmp((uintptr)bi->direct_handler); |
6934 |
|
|
6216 |
– |
align_target(32); |
6935 |
|
current_compile_p=get_target(); |
6218 |
– |
|
6936 |
|
raise_in_cl_list(bi); |
6937 |
|
|
6938 |
|
/* We will flush soon, anyway, so let's do it now */ |
6958 |
|
{ |
6959 |
|
for (;;) { |
6960 |
|
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 |
6961 |
|
(*cpufunctbl[opcode])(opcode); |
6250 |
– |
#endif |
6962 |
|
if (end_block(opcode) || SPCFLAGS_TEST(SPCFLAG_ALL)) { |
6963 |
|
return; /* We will deal with the spcflags in the caller */ |
6964 |
|
} |
6983 |
|
#if FLIGHT_RECORDER |
6984 |
|
m68k_record_step(m68k_getpc()); |
6985 |
|
#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 |
6986 |
|
(*cpufunctbl[opcode])(opcode); |
6281 |
– |
#endif |
6987 |
|
if (end_block(opcode) || SPCFLAGS_TEST(SPCFLAG_ALL) || blocklen>=MAXRUN) { |
6988 |
|
compile_block(pc_hist, blocklen); |
6989 |
|
return; /* We will deal with the spcflags in the caller */ |
6996 |
|
|
6997 |
|
typedef void (*compiled_handler)(void); |
6998 |
|
|
6999 |
+ |
#if defined(X86_ASSEMBLY) || defined(X86_64_ASSEMBLY) |
7000 |
+ |
void (*m68k_compile_execute)(void) = NULL; |
7001 |
+ |
#else |
7002 |
|
void m68k_do_compile_execute(void) |
7003 |
|
{ |
7004 |
|
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 |
7005 |
|
((compiled_handler)(pushall_call_handler))(); |
6303 |
– |
#endif |
7006 |
|
/* Whenever we return from that, we should check spcflags */ |
7007 |
|
if (SPCFLAGS_TEST(SPCFLAG_ALL)) { |
7008 |
|
if (m68k_do_specialties ()) |
7010 |
|
} |
7011 |
|
} |
7012 |
|
} |
7013 |
+ |
#endif |