44 |
|
#endif |
45 |
|
|
46 |
|
#ifndef WIN32 |
47 |
< |
#define PROFILE_COMPILE_TIME 1 |
47 |
> |
#define PROFILE_COMPILE_TIME 1 |
48 |
> |
#define PROFILE_UNTRANSLATED_INSNS 1 |
49 |
|
#endif |
50 |
|
|
51 |
|
#ifdef WIN32 |
70 |
|
static clock_t emul_end_time = 0; |
71 |
|
#endif |
72 |
|
|
73 |
+ |
#if PROFILE_UNTRANSLATED_INSNS |
74 |
+ |
const int untranslated_top_ten = 20; |
75 |
+ |
static uae_u32 raw_cputbl_count[65536] = { 0, }; |
76 |
+ |
static uae_u16 opcode_nums[65536]; |
77 |
+ |
|
78 |
+ |
static int untranslated_compfn(const void *e1, const void *e2) |
79 |
+ |
{ |
80 |
+ |
return raw_cputbl_count[*(const uae_u16 *)e1] < raw_cputbl_count[*(const uae_u16 *)e2]; |
81 |
+ |
} |
82 |
+ |
#endif |
83 |
+ |
|
84 |
|
compop_func *compfunctbl[65536]; |
85 |
|
compop_func *nfcompfunctbl[65536]; |
86 |
|
cpuop_func *nfcpufunctbl[65536]; |
87 |
|
uae_u8* comp_pc_p; |
88 |
|
|
89 |
+ |
// From newcpu.cpp |
90 |
+ |
extern bool quit_program; |
91 |
+ |
|
92 |
|
// gb-- Extra data for Basilisk II/JIT |
93 |
|
#if JIT_DEBUG |
94 |
|
static bool JITDebug = false; // Enable runtime disassemblers through mon? |
103 |
|
static bool avoid_fpu = true; // Flag: compile FPU instructions ? |
104 |
|
static bool have_cmov = false; // target has CMOV instructions ? |
105 |
|
static bool have_rat_stall = true; // target has partial register stalls ? |
106 |
+ |
static bool tune_alignment = false; // Tune code alignments for running CPU ? |
107 |
+ |
static int align_loops = 32; // Align the start of loops |
108 |
+ |
static int align_jumps = 32; // Align the start of jumps |
109 |
|
static int zero_fd = -1; |
110 |
|
static int optcount[10] = { |
111 |
|
10, // How often a block has to be executed before it is translated |
122 |
|
}; |
123 |
|
static op_properties prop[65536]; |
124 |
|
|
107 |
– |
// gb-- Control Flow Predicates |
108 |
– |
|
125 |
|
static inline int end_block(uae_u32 opcode) |
126 |
|
{ |
127 |
|
return (prop[opcode].cflow & fl_end_block); |
128 |
|
} |
129 |
|
|
130 |
< |
static inline bool may_trap(uae_u32 opcode) |
130 |
> |
static inline bool is_const_jump(uae_u32 opcode) |
131 |
|
{ |
132 |
< |
return (prop[opcode].cflow & fl_trap); |
132 |
> |
return (prop[opcode].cflow == fl_const_jump); |
133 |
|
} |
134 |
|
|
135 |
|
uae_u8* start_pc_p; |
507 |
|
compiled. If the list of free blockinfos is empty, we allocate a new |
508 |
|
pool of blockinfos and link the newly created blockinfos altogether |
509 |
|
into the list of free blockinfos. Otherwise, we simply pop a structure |
510 |
< |
of the free list. |
510 |
> |
off the free list. |
511 |
|
|
512 |
|
Blockinfo are lazily deallocated, i.e. chained altogether in the |
513 |
|
list of free blockinfos whenvever a translation cache flush (hard or |
514 |
|
soft) request occurs. |
515 |
|
*/ |
516 |
|
|
517 |
< |
#if USE_SEPARATE_BIA |
518 |
< |
const int BLOCKINFO_POOL_SIZE = 128; |
519 |
< |
struct blockinfo_pool { |
520 |
< |
blockinfo bi[BLOCKINFO_POOL_SIZE]; |
521 |
< |
blockinfo_pool *next; |
517 |
> |
template< class T > |
518 |
> |
class LazyBlockAllocator |
519 |
> |
{ |
520 |
> |
enum { |
521 |
> |
kPoolSize = 1 + 4096 / sizeof(T) |
522 |
> |
}; |
523 |
> |
struct Pool { |
524 |
> |
T chunk[kPoolSize]; |
525 |
> |
Pool * next; |
526 |
> |
}; |
527 |
> |
Pool * mPools; |
528 |
> |
T * mChunks; |
529 |
> |
public: |
530 |
> |
LazyBlockAllocator() : mPools(0), mChunks(0) { } |
531 |
> |
~LazyBlockAllocator(); |
532 |
> |
T * acquire(); |
533 |
> |
void release(T * const); |
534 |
|
}; |
507 |
– |
static blockinfo_pool * blockinfo_pools = 0; |
508 |
– |
static blockinfo * free_blockinfos = 0; |
509 |
– |
#endif |
535 |
|
|
536 |
< |
static __inline__ blockinfo *alloc_blockinfo(void) |
536 |
> |
template< class T > |
537 |
> |
LazyBlockAllocator<T>::~LazyBlockAllocator() |
538 |
|
{ |
539 |
< |
#if USE_SEPARATE_BIA |
540 |
< |
if (!free_blockinfos) { |
541 |
< |
// There is no blockinfo struct left, allocate a new |
542 |
< |
// pool and link the chunks into the free list |
543 |
< |
blockinfo_pool *bi_pool = (blockinfo_pool *)malloc(sizeof(blockinfo_pool)); |
544 |
< |
for (blockinfo *bi = &bi_pool->bi[0]; bi < &bi_pool->bi[BLOCKINFO_POOL_SIZE]; bi++) { |
545 |
< |
bi->next = free_blockinfos; |
546 |
< |
free_blockinfos = bi; |
539 |
> |
Pool * currentPool = mPools; |
540 |
> |
while (currentPool) { |
541 |
> |
Pool * deadPool = currentPool; |
542 |
> |
currentPool = currentPool->next; |
543 |
> |
free(deadPool); |
544 |
> |
} |
545 |
> |
} |
546 |
> |
|
547 |
> |
template< class T > |
548 |
> |
T * LazyBlockAllocator<T>::acquire() |
549 |
> |
{ |
550 |
> |
if (!mChunks) { |
551 |
> |
// There is no chunk left, allocate a new pool and link the |
552 |
> |
// chunks into the free list |
553 |
> |
Pool * newPool = (Pool *)malloc(sizeof(Pool)); |
554 |
> |
for (T * chunk = &newPool->chunk[0]; chunk < &newPool->chunk[kPoolSize]; chunk++) { |
555 |
> |
chunk->next = mChunks; |
556 |
> |
mChunks = chunk; |
557 |
|
} |
558 |
< |
bi_pool->next = blockinfo_pools; |
559 |
< |
blockinfo_pools = bi_pool; |
558 |
> |
newPool->next = mPools; |
559 |
> |
mPools = newPool; |
560 |
|
} |
561 |
< |
blockinfo *bi = free_blockinfos; |
562 |
< |
free_blockinfos = bi->next; |
563 |
< |
#else |
528 |
< |
blockinfo *bi = (blockinfo*)current_compile_p; |
529 |
< |
current_compile_p += sizeof(blockinfo); |
530 |
< |
#endif |
531 |
< |
return bi; |
561 |
> |
T * chunk = mChunks; |
562 |
> |
mChunks = chunk->next; |
563 |
> |
return chunk; |
564 |
|
} |
565 |
|
|
566 |
< |
static __inline__ void free_blockinfo(blockinfo *bi) |
566 |
> |
template< class T > |
567 |
> |
void LazyBlockAllocator<T>::release(T * const chunk) |
568 |
> |
{ |
569 |
> |
chunk->next = mChunks; |
570 |
> |
mChunks = chunk; |
571 |
> |
} |
572 |
> |
|
573 |
> |
template< class T > |
574 |
> |
class HardBlockAllocator |
575 |
|
{ |
576 |
+ |
public: |
577 |
+ |
T * acquire() { |
578 |
+ |
T * data = (T *)current_compile_p; |
579 |
+ |
current_compile_p += sizeof(T); |
580 |
+ |
return data; |
581 |
+ |
} |
582 |
+ |
|
583 |
+ |
void release(T * const chunk) { |
584 |
+ |
// Deallocated on invalidation |
585 |
+ |
} |
586 |
+ |
}; |
587 |
+ |
|
588 |
|
#if USE_SEPARATE_BIA |
589 |
< |
bi->next = free_blockinfos; |
590 |
< |
free_blockinfos = bi; |
589 |
> |
static LazyBlockAllocator<blockinfo> BlockInfoAllocator; |
590 |
> |
static LazyBlockAllocator<checksum_info> ChecksumInfoAllocator; |
591 |
> |
#else |
592 |
> |
static HardBlockAllocator<blockinfo> BlockInfoAllocator; |
593 |
> |
static HardBlockAllocator<checksum_info> ChecksumInfoAllocator; |
594 |
|
#endif |
595 |
+ |
|
596 |
+ |
static __inline__ checksum_info *alloc_checksum_info(void) |
597 |
+ |
{ |
598 |
+ |
checksum_info *csi = ChecksumInfoAllocator.acquire(); |
599 |
+ |
csi->next = NULL; |
600 |
+ |
return csi; |
601 |
|
} |
602 |
|
|
603 |
< |
static void free_blockinfo_pools(void) |
603 |
> |
static __inline__ void free_checksum_info(checksum_info *csi) |
604 |
|
{ |
605 |
< |
#if USE_SEPARATE_BIA |
606 |
< |
int blockinfo_pool_count = 0; |
607 |
< |
blockinfo_pool *curr_pool = blockinfo_pools; |
608 |
< |
while (curr_pool) { |
609 |
< |
blockinfo_pool_count++; |
610 |
< |
blockinfo_pool *dead_pool = curr_pool; |
611 |
< |
curr_pool = curr_pool->next; |
612 |
< |
free(dead_pool); |
605 |
> |
csi->next = NULL; |
606 |
> |
ChecksumInfoAllocator.release(csi); |
607 |
> |
} |
608 |
> |
|
609 |
> |
static __inline__ void free_checksum_info_chain(checksum_info *csi) |
610 |
> |
{ |
611 |
> |
while (csi != NULL) { |
612 |
> |
checksum_info *csi2 = csi->next; |
613 |
> |
free_checksum_info(csi); |
614 |
> |
csi = csi2; |
615 |
|
} |
616 |
< |
|
617 |
< |
uae_u32 blockinfo_pools_size = blockinfo_pool_count * BLOCKINFO_POOL_SIZE * sizeof(blockinfo); |
618 |
< |
write_log("### Blockinfo allocation statistics\n"); |
619 |
< |
write_log("Number of blockinfo pools : %d\n", blockinfo_pool_count); |
620 |
< |
write_log("Total number of blockinfos : %d (%d KB)\n", |
621 |
< |
blockinfo_pool_count * BLOCKINFO_POOL_SIZE, |
622 |
< |
blockinfo_pools_size / 1024); |
623 |
< |
write_log("\n"); |
616 |
> |
} |
617 |
> |
|
618 |
> |
static __inline__ blockinfo *alloc_blockinfo(void) |
619 |
> |
{ |
620 |
> |
blockinfo *bi = BlockInfoAllocator.acquire(); |
621 |
> |
#if USE_CHECKSUM_INFO |
622 |
> |
bi->csi = NULL; |
623 |
> |
#endif |
624 |
> |
return bi; |
625 |
> |
} |
626 |
> |
|
627 |
> |
static __inline__ void free_blockinfo(blockinfo *bi) |
628 |
> |
{ |
629 |
> |
#if USE_CHECKSUM_INFO |
630 |
> |
free_checksum_info_chain(bi->csi); |
631 |
> |
bi->csi = NULL; |
632 |
|
#endif |
633 |
+ |
BlockInfoAllocator.release(bi); |
634 |
|
} |
635 |
|
|
636 |
|
static __inline__ void alloc_blockinfos(void) |
4634 |
|
raw_init_cpu(); |
4635 |
|
write_log("<JIT compiler> : target processor has CMOV instructions : %s\n", have_cmov ? "yes" : "no"); |
4636 |
|
write_log("<JIT compiler> : target processor can suffer from partial register stalls : %s\n", have_rat_stall ? "yes" : "no"); |
4637 |
+ |
write_log("<JIT compiler> : alignment for loops, jumps are %d, %d\n", align_loops, align_jumps); |
4638 |
|
|
4639 |
|
// Translation cache flush mechanism |
4640 |
|
lazy_flush = PrefsFindBool("jitlazyflush"); |
4645 |
|
write_log("<JIT compiler> : register aliasing : %s\n", str_on_off(1)); |
4646 |
|
write_log("<JIT compiler> : FP register aliasing : %s\n", str_on_off(USE_F_ALIAS)); |
4647 |
|
write_log("<JIT compiler> : lazy constant offsetting : %s\n", str_on_off(USE_OFFSET)); |
4648 |
+ |
write_log("<JIT compiler> : block inlining : %s\n", str_on_off(USE_INLINING)); |
4649 |
|
write_log("<JIT compiler> : separate blockinfo allocation : %s\n", str_on_off(USE_SEPARATE_BIA)); |
4650 |
|
|
4651 |
|
// Build compiler tables |
4653 |
|
|
4654 |
|
initialized = true; |
4655 |
|
|
4656 |
+ |
#if PROFILE_UNTRANSLATED_INSNS |
4657 |
+ |
write_log("<JIT compiler> : gather statistics on untranslated insns count\n"); |
4658 |
+ |
#endif |
4659 |
+ |
|
4660 |
|
#if PROFILE_COMPILE_TIME |
4661 |
|
write_log("<JIT compiler> : gather statistics on translation time\n"); |
4662 |
|
emul_start_time = clock(); |
4675 |
|
compiled_code = 0; |
4676 |
|
} |
4677 |
|
|
4600 |
– |
// Deallocate blockinfo pools |
4601 |
– |
free_blockinfo_pools(); |
4602 |
– |
|
4678 |
|
#ifndef WIN32 |
4679 |
|
// Close /dev/zero |
4680 |
|
if (zero_fd > 0) |
4690 |
|
100.0*double(compile_time)/double(emul_time)); |
4691 |
|
write_log("\n"); |
4692 |
|
#endif |
4693 |
+ |
|
4694 |
+ |
#if PROFILE_UNTRANSLATED_INSNS |
4695 |
+ |
uae_u64 untranslated_count = 0; |
4696 |
+ |
for (int i = 0; i < 65536; i++) { |
4697 |
+ |
opcode_nums[i] = i; |
4698 |
+ |
untranslated_count += raw_cputbl_count[i]; |
4699 |
+ |
} |
4700 |
+ |
write_log("Sorting out untranslated instructions count...\n"); |
4701 |
+ |
qsort(opcode_nums, 65536, sizeof(uae_u16), untranslated_compfn); |
4702 |
+ |
write_log("\nRank Opc Count Name\n"); |
4703 |
+ |
for (int i = 0; i < untranslated_top_ten; i++) { |
4704 |
+ |
uae_u32 count = raw_cputbl_count[opcode_nums[i]]; |
4705 |
+ |
struct instr *dp; |
4706 |
+ |
struct mnemolookup *lookup; |
4707 |
+ |
if (!count) |
4708 |
+ |
break; |
4709 |
+ |
dp = table68k + opcode_nums[i]; |
4710 |
+ |
for (lookup = lookuptab; lookup->mnemo != dp->mnemo; lookup++) |
4711 |
+ |
; |
4712 |
+ |
write_log("%03d: %04x %10lu %s\n", i, opcode_nums[i], count, lookup->name); |
4713 |
+ |
} |
4714 |
+ |
#endif |
4715 |
|
} |
4716 |
|
|
4717 |
|
bool compiler_use_jit(void) |
5271 |
|
|
5272 |
|
static void calc_checksum(blockinfo* bi, uae_u32* c1, uae_u32* c2) |
5273 |
|
{ |
5274 |
< |
uae_u32 k1=0; |
5275 |
< |
uae_u32 k2=0; |
5179 |
< |
uae_s32 len=bi->len; |
5180 |
< |
uae_u32 tmp=bi->min_pcp; |
5181 |
< |
uae_u32* pos; |
5274 |
> |
uae_u32 k1 = 0; |
5275 |
> |
uae_u32 k2 = 0; |
5276 |
|
|
5277 |
< |
len+=(tmp&3); |
5278 |
< |
tmp&=(~3); |
5279 |
< |
pos=(uae_u32*)tmp; |
5277 |
> |
#if USE_CHECKSUM_INFO |
5278 |
> |
checksum_info *csi = bi->csi; |
5279 |
> |
Dif(!csi) abort(); |
5280 |
> |
while (csi) { |
5281 |
> |
uae_s32 len = csi->length; |
5282 |
> |
uae_u32 tmp = (uae_u32)csi->start_p; |
5283 |
> |
#else |
5284 |
> |
uae_s32 len = bi->len; |
5285 |
> |
uae_u32 tmp = (uae_u32)bi->min_pcp; |
5286 |
> |
#endif |
5287 |
> |
uae_u32*pos; |
5288 |
|
|
5289 |
< |
if (len<0 || len>MAX_CHECKSUM_LEN) { |
5290 |
< |
*c1=0; |
5291 |
< |
*c2=0; |
5292 |
< |
} |
5293 |
< |
else { |
5294 |
< |
while (len>0) { |
5295 |
< |
k1+=*pos; |
5296 |
< |
k2^=*pos; |
5297 |
< |
pos++; |
5298 |
< |
len-=4; |
5289 |
> |
len += (tmp & 3); |
5290 |
> |
tmp &= ~3; |
5291 |
> |
pos = (uae_u32 *)tmp; |
5292 |
> |
|
5293 |
> |
if (len >= 0 && len <= MAX_CHECKSUM_LEN) { |
5294 |
> |
while (len > 0) { |
5295 |
> |
k1 += *pos; |
5296 |
> |
k2 ^= *pos; |
5297 |
> |
pos++; |
5298 |
> |
len -= 4; |
5299 |
> |
} |
5300 |
> |
} |
5301 |
> |
|
5302 |
> |
#if USE_CHECKSUM_INFO |
5303 |
> |
csi = csi->next; |
5304 |
|
} |
5305 |
< |
*c1=k1; |
5306 |
< |
*c2=k2; |
5307 |
< |
} |
5305 |
> |
#endif |
5306 |
> |
|
5307 |
> |
*c1 = k1; |
5308 |
> |
*c2 = k2; |
5309 |
|
} |
5310 |
|
|
5311 |
< |
static void show_checksum(blockinfo* bi) |
5311 |
> |
#if 0 |
5312 |
> |
static void show_checksum(CSI_TYPE* csi) |
5313 |
|
{ |
5314 |
|
uae_u32 k1=0; |
5315 |
|
uae_u32 k2=0; |
5316 |
< |
uae_s32 len=bi->len; |
5317 |
< |
uae_u32 tmp=(uae_u32)bi->pc_p; |
5316 |
> |
uae_s32 len=CSI_LENGTH(csi); |
5317 |
> |
uae_u32 tmp=(uae_u32)CSI_START_P(csi); |
5318 |
|
uae_u32* pos; |
5319 |
|
|
5320 |
|
len+=(tmp&3); |
5333 |
|
write_log(" bla\n"); |
5334 |
|
} |
5335 |
|
} |
5336 |
+ |
#endif |
5337 |
|
|
5338 |
|
|
5339 |
|
int check_for_cache_miss(void) |
5387 |
|
static inline int block_check_checksum(blockinfo* bi) |
5388 |
|
{ |
5389 |
|
uae_u32 c1,c2; |
5390 |
< |
int isgood; |
5390 |
> |
bool isgood; |
5391 |
|
|
5392 |
|
if (bi->status!=BI_NEED_CHECK) |
5393 |
|
return 1; /* This block is in a checked state */ |
5394 |
|
|
5395 |
|
checksum_count++; |
5396 |
+ |
|
5397 |
|
if (bi->c1 || bi->c2) |
5398 |
|
calc_checksum(bi,&c1,&c2); |
5399 |
|
else { |
5400 |
|
c1=c2=1; /* Make sure it doesn't match */ |
5401 |
< |
} |
5401 |
> |
} |
5402 |
|
|
5403 |
|
isgood=(c1==bi->c1 && c2==bi->c2); |
5404 |
+ |
|
5405 |
|
if (isgood) { |
5406 |
|
/* This block is still OK. So we reactivate. Of course, that |
5407 |
|
means we have to move it into the needs-to-be-flushed list */ |
5519 |
|
registers before jumping back to the various get-out routines. |
5520 |
|
This generates the code for it. |
5521 |
|
*/ |
5522 |
< |
popall_do_nothing=current_compile_p; |
5522 |
> |
align_target(align_jumps); |
5523 |
> |
popall_do_nothing=get_target(); |
5524 |
|
for (i=0;i<N_REGS;i++) { |
5525 |
|
if (need_to_preserve[i]) |
5526 |
|
raw_pop_l_r(i); |
5527 |
|
} |
5528 |
|
raw_jmp((uae_u32)do_nothing); |
5416 |
– |
align_target(32); |
5529 |
|
|
5530 |
+ |
align_target(align_jumps); |
5531 |
|
popall_execute_normal=get_target(); |
5532 |
|
for (i=0;i<N_REGS;i++) { |
5533 |
|
if (need_to_preserve[i]) |
5534 |
|
raw_pop_l_r(i); |
5535 |
|
} |
5536 |
|
raw_jmp((uae_u32)execute_normal); |
5424 |
– |
align_target(32); |
5537 |
|
|
5538 |
+ |
align_target(align_jumps); |
5539 |
|
popall_cache_miss=get_target(); |
5540 |
|
for (i=0;i<N_REGS;i++) { |
5541 |
|
if (need_to_preserve[i]) |
5542 |
|
raw_pop_l_r(i); |
5543 |
|
} |
5544 |
|
raw_jmp((uae_u32)cache_miss); |
5432 |
– |
align_target(32); |
5545 |
|
|
5546 |
+ |
align_target(align_jumps); |
5547 |
|
popall_recompile_block=get_target(); |
5548 |
|
for (i=0;i<N_REGS;i++) { |
5549 |
|
if (need_to_preserve[i]) |
5550 |
|
raw_pop_l_r(i); |
5551 |
|
} |
5552 |
|
raw_jmp((uae_u32)recompile_block); |
5553 |
< |
align_target(32); |
5554 |
< |
|
5553 |
> |
|
5554 |
> |
align_target(align_jumps); |
5555 |
|
popall_exec_nostats=get_target(); |
5556 |
|
for (i=0;i<N_REGS;i++) { |
5557 |
|
if (need_to_preserve[i]) |
5558 |
|
raw_pop_l_r(i); |
5559 |
|
} |
5560 |
|
raw_jmp((uae_u32)exec_nostats); |
5561 |
< |
align_target(32); |
5562 |
< |
|
5561 |
> |
|
5562 |
> |
align_target(align_jumps); |
5563 |
|
popall_check_checksum=get_target(); |
5564 |
|
for (i=0;i<N_REGS;i++) { |
5565 |
|
if (need_to_preserve[i]) |
5566 |
|
raw_pop_l_r(i); |
5567 |
|
} |
5568 |
|
raw_jmp((uae_u32)check_checksum); |
5569 |
< |
align_target(32); |
5570 |
< |
|
5569 |
> |
|
5570 |
> |
align_target(align_jumps); |
5571 |
|
current_compile_p=get_target(); |
5572 |
|
#else |
5573 |
|
popall_exec_nostats=(void *)exec_nostats; |
5576 |
|
popall_recompile_block=(void *)recompile_block; |
5577 |
|
popall_do_nothing=(void *)do_nothing; |
5578 |
|
popall_check_checksum=(void *)check_checksum; |
5466 |
– |
pushall_call_handler=get_target(); |
5579 |
|
#endif |
5580 |
|
|
5581 |
|
/* And now, the code to do the matching pushes and then jump |
5591 |
|
raw_mov_l_rm(r,(uae_u32)®s.pc_p); |
5592 |
|
raw_and_l_ri(r,TAGMASK); |
5593 |
|
raw_jmp_m_indexed((uae_u32)cache_tags,r,4); |
5594 |
+ |
|
5595 |
+ |
#ifdef X86_ASSEMBLY |
5596 |
+ |
align_target(align_jumps); |
5597 |
+ |
m68k_compile_execute = (void (*)(void))get_target(); |
5598 |
+ |
for (i=N_REGS;i--;) { |
5599 |
+ |
if (need_to_preserve[i]) |
5600 |
+ |
raw_push_l_r(i); |
5601 |
+ |
} |
5602 |
+ |
align_target(align_loops); |
5603 |
+ |
uae_u32 dispatch_loop = (uae_u32)get_target(); |
5604 |
+ |
r=REG_PC_TMP; |
5605 |
+ |
raw_mov_l_rm(r,(uae_u32)®s.pc_p); |
5606 |
+ |
raw_and_l_ri(r,TAGMASK); |
5607 |
+ |
raw_call_m_indexed((uae_u32)cache_tags,r,4); |
5608 |
+ |
raw_cmp_l_mi((uae_u32)®s.spcflags,0); |
5609 |
+ |
raw_jcc_b_oponly(NATIVE_CC_EQ); |
5610 |
+ |
emit_byte(dispatch_loop-((uae_u32)get_target()+1)); |
5611 |
+ |
raw_call((uae_u32)m68k_do_specialties); |
5612 |
+ |
raw_test_l_rr(REG_RESULT,REG_RESULT); |
5613 |
+ |
raw_jcc_b_oponly(NATIVE_CC_EQ); |
5614 |
+ |
emit_byte(dispatch_loop-((uae_u32)get_target()+1)); |
5615 |
+ |
raw_cmp_b_mi((uae_u32)&quit_program,0); |
5616 |
+ |
raw_jcc_b_oponly(NATIVE_CC_EQ); |
5617 |
+ |
emit_byte(dispatch_loop-((uae_u32)get_target()+1)); |
5618 |
+ |
for (i=0;i<N_REGS;i++) { |
5619 |
+ |
if (need_to_preserve[i]) |
5620 |
+ |
raw_pop_l_r(i); |
5621 |
+ |
} |
5622 |
+ |
raw_ret(); |
5623 |
+ |
#endif |
5624 |
|
} |
5625 |
|
|
5626 |
|
static __inline__ void reset_lists(void) |
5638 |
|
int i; |
5639 |
|
|
5640 |
|
set_target(current_compile_p); |
5641 |
< |
align_target(32); |
5641 |
> |
align_target(align_jumps); |
5642 |
|
bi->direct_pen=(cpuop_func *)get_target(); |
5643 |
|
raw_mov_l_rm(0,(uae_u32)&(bi->pc_p)); |
5644 |
|
raw_mov_l_mr((uae_u32)®s.pc_p,0); |
5645 |
|
raw_jmp((uae_u32)popall_execute_normal); |
5646 |
|
|
5647 |
< |
align_target(32); |
5647 |
> |
align_target(align_jumps); |
5648 |
|
bi->direct_pcc=(cpuop_func *)get_target(); |
5649 |
|
raw_mov_l_rm(0,(uae_u32)&(bi->pc_p)); |
5650 |
|
raw_mov_l_mr((uae_u32)®s.pc_p,0); |
5651 |
|
raw_jmp((uae_u32)popall_check_checksum); |
5510 |
– |
|
5511 |
– |
align_target(32); |
5652 |
|
current_compile_p=get_target(); |
5653 |
|
|
5654 |
|
bi->deplist=NULL; |
5699 |
|
prop[opcode].cflow = fl_trap; // ILLEGAL instructions do trap |
5700 |
|
} |
5701 |
|
|
5702 |
+ |
#define IS_CONST_JUMP(opc) \ |
5703 |
+ |
( ((table68k[opc].mnemo == i_Bcc) && (table68k[opc].cc < 2)) \ |
5704 |
+ |
|| (table68k[opc].mnemo == i_BSR) \ |
5705 |
+ |
) |
5706 |
+ |
|
5707 |
|
for (i = 0; tbl[i].opcode < 65536; i++) { |
5708 |
|
int cflow = table68k[tbl[i].opcode].cflow; |
5709 |
< |
prop[cft_map(tbl[i].opcode)].cflow = cflow; |
5709 |
> |
if (USE_INLINING && IS_CONST_JUMP(tbl[i].opcode)) |
5710 |
> |
prop[cft_map(tbl[i].opcode)].cflow = fl_const_jump; |
5711 |
> |
else |
5712 |
> |
prop[cft_map(tbl[i].opcode)].cflow = cflow; |
5713 |
|
|
5714 |
|
int uses_fpu = tbl[i].specific & 32; |
5715 |
|
if (uses_fpu && avoid_fpu) |
5718 |
|
compfunctbl[cft_map(tbl[i].opcode)] = tbl[i].handler; |
5719 |
|
} |
5720 |
|
|
5721 |
+ |
#undef IS_CONST_JUMP |
5722 |
+ |
|
5723 |
|
for (i = 0; nftbl[i].opcode < 65536; i++) { |
5724 |
|
int uses_fpu = tbl[i].specific & 32; |
5725 |
|
if (uses_fpu && avoid_fpu) |
6004 |
|
int r; |
6005 |
|
int was_comp=0; |
6006 |
|
uae_u8 liveflags[MAXRUN+1]; |
6007 |
+ |
#if USE_CHECKSUM_INFO |
6008 |
+ |
bool trace_in_rom = isinrom((uintptr)pc_hist[0].location); |
6009 |
+ |
uae_u32 max_pcp=(uae_u32)pc_hist[blocklen - 1].location; |
6010 |
+ |
uae_u32 min_pcp=max_pcp; |
6011 |
+ |
#else |
6012 |
|
uae_u32 max_pcp=(uae_u32)pc_hist[0].location; |
6013 |
|
uae_u32 min_pcp=max_pcp; |
6014 |
+ |
#endif |
6015 |
|
uae_u32 cl=cacheline(pc_hist[0].location); |
6016 |
|
void* specflags=(void*)®s.spcflags; |
6017 |
|
blockinfo* bi=NULL; |
6055 |
|
remove_deps(bi); /* We are about to create new code */ |
6056 |
|
bi->optlevel=optlev; |
6057 |
|
bi->pc_p=(uae_u8*)pc_hist[0].location; |
6058 |
+ |
#if USE_CHECKSUM_INFO |
6059 |
+ |
free_checksum_info_chain(bi->csi); |
6060 |
+ |
bi->csi = NULL; |
6061 |
+ |
#endif |
6062 |
|
|
6063 |
|
liveflags[blocklen]=0x1f; /* All flags needed afterwards */ |
6064 |
|
i=blocklen; |
6066 |
|
uae_u16* currpcp=pc_hist[i].location; |
6067 |
|
uae_u32 op=DO_GET_OPCODE(currpcp); |
6068 |
|
|
6069 |
+ |
#if USE_CHECKSUM_INFO |
6070 |
+ |
trace_in_rom = trace_in_rom && isinrom((uintptr)currpcp); |
6071 |
+ |
#if USE_INLINING |
6072 |
+ |
if (is_const_jump(op)) { |
6073 |
+ |
checksum_info *csi = alloc_checksum_info(); |
6074 |
+ |
csi->start_p = (uae_u8 *)min_pcp; |
6075 |
+ |
csi->length = max_pcp - min_pcp + LONGEST_68K_INST; |
6076 |
+ |
csi->next = bi->csi; |
6077 |
+ |
bi->csi = csi; |
6078 |
+ |
max_pcp = (uae_u32)currpcp; |
6079 |
+ |
} |
6080 |
+ |
#endif |
6081 |
+ |
min_pcp = (uae_u32)currpcp; |
6082 |
+ |
#else |
6083 |
|
if ((uae_u32)currpcp<min_pcp) |
6084 |
|
min_pcp=(uae_u32)currpcp; |
6085 |
|
if ((uae_u32)currpcp>max_pcp) |
6086 |
|
max_pcp=(uae_u32)currpcp; |
6087 |
+ |
#endif |
6088 |
|
|
6089 |
|
liveflags[i]=((liveflags[i+1]& |
6090 |
|
(~prop[op].set_flags))| |
6093 |
|
liveflags[i]&= ~FLAG_Z; |
6094 |
|
} |
6095 |
|
|
6096 |
+ |
#if USE_CHECKSUM_INFO |
6097 |
+ |
checksum_info *csi = alloc_checksum_info(); |
6098 |
+ |
csi->start_p = (uae_u8 *)min_pcp; |
6099 |
+ |
csi->length = max_pcp - min_pcp + LONGEST_68K_INST; |
6100 |
+ |
csi->next = bi->csi; |
6101 |
+ |
bi->csi = csi; |
6102 |
+ |
#endif |
6103 |
+ |
|
6104 |
|
bi->needed_flags=liveflags[0]; |
6105 |
|
|
6106 |
< |
align_target(32); |
6106 |
> |
align_target(align_loops); |
6107 |
|
was_comp=0; |
6108 |
|
|
6109 |
|
bi->direct_handler=(cpuop_func *)get_target(); |
6190 |
|
raw_mov_l_mi((uae_u32)®s.pc_p, |
6191 |
|
(uae_u32)pc_hist[i].location); |
6192 |
|
raw_call((uae_u32)cputbl[opcode]); |
6193 |
+ |
#if PROFILE_UNTRANSLATED_INSNS |
6194 |
+ |
// raw_cputbl_count[] is indexed with plain opcode (in m68k order) |
6195 |
+ |
raw_add_l_mi((uae_u32)&raw_cputbl_count[cft_map(opcode)],1); |
6196 |
+ |
#endif |
6197 |
|
//raw_add_l_mi((uae_u32)&oink,1); // FIXME |
6198 |
|
#if USE_NORMAL_CALLING_CONVENTION |
6199 |
|
raw_inc_sp(4); |
6282 |
|
raw_jmp((uae_u32)popall_do_nothing); |
6283 |
|
create_jmpdep(bi,0,tba,t1); |
6284 |
|
|
6285 |
< |
align_target(16); |
6285 |
> |
align_target(align_jumps); |
6286 |
|
/* not-predicted outcome */ |
6287 |
|
*branchadd=(uae_u32)get_target()-((uae_u32)branchadd+4); |
6288 |
|
live=tmp; /* Ouch again */ |
6351 |
|
big_to_small_state(&live,&(bi->env)); |
6352 |
|
#endif |
6353 |
|
|
6354 |
+ |
#if USE_CHECKSUM_INFO |
6355 |
+ |
remove_from_list(bi); |
6356 |
+ |
if (trace_in_rom) { |
6357 |
+ |
// No need to checksum that block trace on cache invalidation |
6358 |
+ |
free_checksum_info_chain(bi->csi); |
6359 |
+ |
bi->csi = NULL; |
6360 |
+ |
add_to_dormant(bi); |
6361 |
+ |
} |
6362 |
+ |
else { |
6363 |
+ |
calc_checksum(bi,&(bi->c1),&(bi->c2)); |
6364 |
+ |
add_to_active(bi); |
6365 |
+ |
} |
6366 |
+ |
#else |
6367 |
|
if (next_pc_p+extra_len>=max_pcp && |
6368 |
|
next_pc_p+extra_len<max_pcp+LONGEST_68K_INST) |
6369 |
|
max_pcp=next_pc_p+extra_len; /* extra_len covers flags magic */ |
6370 |
|
else |
6371 |
|
max_pcp+=LONGEST_68K_INST; |
6372 |
+ |
|
6373 |
|
bi->len=max_pcp-min_pcp; |
6374 |
|
bi->min_pcp=min_pcp; |
6375 |
< |
|
6375 |
> |
|
6376 |
|
remove_from_list(bi); |
6377 |
|
if (isinrom(min_pcp) && isinrom(max_pcp)) { |
6378 |
|
add_to_dormant(bi); /* No need to checksum it on cache flush. |
6383 |
|
calc_checksum(bi,&(bi->c1),&(bi->c2)); |
6384 |
|
add_to_active(bi); |
6385 |
|
} |
6386 |
+ |
#endif |
6387 |
|
|
6388 |
|
current_cache_size += get_target() - (uae_u8 *)current_compile_p; |
6389 |
|
|
6403 |
|
#endif |
6404 |
|
|
6405 |
|
log_dump(); |
6406 |
< |
align_target(32); |
6406 |
> |
align_target(align_jumps); |
6407 |
|
|
6408 |
|
/* This is the non-direct handler */ |
6409 |
|
bi->handler= |
6419 |
|
|
6420 |
|
raw_jmp((uae_u32)bi->direct_handler); |
6421 |
|
|
6220 |
– |
align_target(32); |
6422 |
|
current_compile_p=get_target(); |
6222 |
– |
|
6423 |
|
raise_in_cl_list(bi); |
6424 |
|
|
6425 |
|
/* We will flush soon, anyway, so let's do it now */ |
6445 |
|
{ |
6446 |
|
for (;;) { |
6447 |
|
uae_u32 opcode = GET_OPCODE; |
6248 |
– |
#ifdef X86_ASSEMBLY__disable |
6249 |
– |
__asm__ __volatile__("\tpushl %%ebp\n\tcall *%%ebx\n\tpopl %%ebp" /* FIXME */ |
6250 |
– |
: : "b" (cpufunctbl[opcode]), "a" (opcode) |
6251 |
– |
: "%edx", "%ecx", "%esi", "%edi", "%ebp", "memory", "cc"); |
6252 |
– |
#else |
6448 |
|
(*cpufunctbl[opcode])(opcode); |
6254 |
– |
#endif |
6449 |
|
if (end_block(opcode) || SPCFLAGS_TEST(SPCFLAG_ALL)) { |
6450 |
|
return; /* We will deal with the spcflags in the caller */ |
6451 |
|
} |
6470 |
|
#if FLIGHT_RECORDER |
6471 |
|
m68k_record_step(m68k_getpc()); |
6472 |
|
#endif |
6279 |
– |
#ifdef X86_ASSEMBLY__disable |
6280 |
– |
__asm__ __volatile__("\tpushl %%ebp\n\tcall *%%ebx\n\tpopl %%ebp" /* FIXME */ |
6281 |
– |
: : "b" (cpufunctbl[opcode]), "a" (opcode) |
6282 |
– |
: "%edx", "%ecx", "%esi", "%edi", "%ebp", "memory", "cc"); |
6283 |
– |
#else |
6473 |
|
(*cpufunctbl[opcode])(opcode); |
6285 |
– |
#endif |
6474 |
|
if (end_block(opcode) || SPCFLAGS_TEST(SPCFLAG_ALL) || blocklen>=MAXRUN) { |
6475 |
|
compile_block(pc_hist, blocklen); |
6476 |
|
return; /* We will deal with the spcflags in the caller */ |
6483 |
|
|
6484 |
|
typedef void (*compiled_handler)(void); |
6485 |
|
|
6486 |
+ |
#ifdef X86_ASSEMBLY |
6487 |
+ |
void (*m68k_compile_execute)(void) = NULL; |
6488 |
+ |
#else |
6489 |
|
void m68k_do_compile_execute(void) |
6490 |
|
{ |
6491 |
|
for (;;) { |
6301 |
– |
#ifdef X86_ASSEMBLY |
6302 |
– |
__asm__ __volatile__("\tpushl %%ebp\n\tcall *%%ebx\n\tpopl %%ebp" /* FIXME */ |
6303 |
– |
: : "b" (cache_tags[cacheline(regs.pc_p)].handler) |
6304 |
– |
: "%edx", "%ecx", "%eax", "%esi", "%edi", "%ebp", "memory", "cc"); |
6305 |
– |
#else |
6492 |
|
((compiled_handler)(pushall_call_handler))(); |
6307 |
– |
#endif |
6493 |
|
/* Whenever we return from that, we should check spcflags */ |
6494 |
|
if (SPCFLAGS_TEST(SPCFLAG_ALL)) { |
6495 |
|
if (m68k_do_specialties ()) |
6497 |
|
} |
6498 |
|
} |
6499 |
|
} |
6500 |
+ |
#endif |