--- uae/src/compiler.c 2018/04/24 16:38:39 1.1.1.1 +++ uae/src/compiler.c 2018/04/24 16:48:51 1.1.1.6 @@ -1,9 +1,9 @@ - /* + /* * UAE - The Un*x Amiga Emulator - * + * * m68k emulation * - * (c) 1995 Bernd Schmidt + * Copyright 1996 Bernd Schmidt */ #include "sysconfig.h" @@ -15,16 +15,14 @@ #include "gui.h" #include "memory.h" #include "custom.h" +#include "readcpu.h" #include "newcpu.h" #include "ersatz.h" -#include "readcpu.h" #include "blitter.h" #include "debug.h" #include "autoconf.h" #include "compiler.h" -#define RELY_ON_LOADSEG_DETECTION - #ifdef USE_COMPILER #include @@ -32,7 +30,7 @@ char *address_space, *good_address_map; code_execfunc exec_me; -UBYTE nr_bbs_to_run = 1; +uae_u8 nr_bbs_to_run = 1; int nr_bbs_start = 40; static int compile_failure; @@ -40,11 +38,11 @@ static int quiet_compile = 1; int i_want_to_die = 1; static int n_compiled = 0; static int n_max_comp = 99999999; -static CPTR call_only_me = 0; +static uaecptr call_only_me = 0; int patched_syscalls = 0; -static int count_bits(UWORD v) +static int count_bits(uae_u16 v) { int bits = 0; while (v != 0) { @@ -55,12 +53,12 @@ static int count_bits(UWORD v) return bits; } -static UWORD bitswap(UWORD v) +static uae_u16 bitswap(uae_u16 v) { - UWORD newv = 0; - UWORD m1 = 1, m2 = 0x8000; + uae_u16 newv = 0; + uae_u16 m1 = 1, m2 = 0x8000; int i; - + for (i = 0; i < 16; i++) { if (v & m1) newv |= m2; @@ -72,9 +70,6 @@ static UWORD bitswap(UWORD v) static long long compiled_hits = 0; -/* @@@ FIXME: a defragmenter would be nice for this, but since we flush - * the cache all the time anyway to deal with LoadSegs() */ - /* 16K areas with 512 byte blocks */ #define SUBUNIT_ORDER 9 #define PAGE_SUBUNIT (1 << SUBUNIT_ORDER) @@ -87,8 +82,8 @@ static struct code_page *first_code_page static struct code_page *new_code_page(void) { struct code_page *ncp; - - ncp = (struct code_page *)mmap(NULL, PAGE_ALLOC_UNIT, + + ncp = (struct code_page *)mmap(NULL, PAGE_ALLOC_UNIT, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE, zerofd, zeroff); zeroff += PAGE_ALLOC_UNIT; @@ -100,19 +95,25 @@ static struct code_page *new_code_page(v return ncp; } -#define NUM_HASH 1024 -#define NUM_FUNCTIONS 8192 +#define NUM_HASH 32768 /* larger values cause some paging on my 16MB machine */ #define HASH_MASK (NUM_HASH-1) +#define MAX_UNUSED_HASH 512 -static int SCAN_MARK = 5; /* Number of calls after which to scan a function */ -static int COMPILE_MARK = 50; /* Number of calls after which to compile a function */ +static int SCAN_MARK = 1; /* Number of calls after which to scan a function */ +static int COMPILE_MARK = 5; /* Number of calls after which to compile a function */ +/* The main address -> function lookup hashtable. We use the lower bits of + * the address as hash function. */ static struct hash_entry cpu_hash[NUM_HASH]; +/* These aren't really LRU lists... They used to be, but keeping them in that + * order is costly. The hash LRU list is now a two-part list: Functions that have + * no code allocated for them are placed at the beginning. Such entries can be + * recycled when we need a new hash entry. */ static struct hash_block lru_first_block; static struct hash_entry lru_first_hash; static struct hash_entry *freelist_hash; static struct hash_block *freelist_block; -static struct hash_entry hash_entries[NUM_FUNCTIONS]; +static int num_unused_hash; static int m68k_scan_func(struct hash_entry *); static int m68k_compile_block(struct hash_block *); @@ -121,7 +122,7 @@ static char *alloc_code(struct hash_bloc { struct code_page *cp; long int allocsize = (ninsns * 32 + PAGE_SUBUNIT-1) & ~(PAGE_SUBUNIT-1); - ULONG allocmask; + uae_u32 allocmask; int allocbits; int j; int last_bit; @@ -130,9 +131,9 @@ static char *alloc_code(struct hash_bloc return NULL; allocbits = (allocsize >> SUBUNIT_ORDER); allocmask = (1 << allocbits) - 1; - + for (cp = first_code_page; cp != NULL; cp = cp->next) { - ULONG thispage_alloc = cp->allocmask; + uae_u32 thispage_alloc = cp->allocmask; for (j = 1; j < (33 - allocbits); j++) { if ((cp->allocmask & (allocmask << j)) == 0) { goto found_page; @@ -145,7 +146,7 @@ static char *alloc_code(struct hash_bloc if (cp == NULL) return NULL; j = 1; - + found_page: /* See whether there is in fact more space for us. If so, allocate all of * it. compile_block() will free everything it didn't need. */ @@ -166,23 +167,41 @@ found_page: return hb->compile_start; } -static int remove_hash_from_lists(struct hash_entry *h) +static void remove_hash_from_lists(struct hash_entry *h) { - if (h->locked || h->cacheflush) - return 0; - h->lru_next->lru_prev = h->lru_prev; h->lru_prev->lru_next = h->lru_next; - + h->next->prev = h->prev; h->prev->next = h->next; - return 1; +} + +static void lru_touch(struct hash_entry *h) +{ + h->lru_next->lru_prev = h->lru_prev; + h->lru_prev->lru_next = h->lru_next; + + h->lru_next = &lru_first_hash; + h->lru_prev = lru_first_hash.lru_prev; + h->lru_prev->lru_next = h; + lru_first_hash.lru_prev = h; +} + +static void lru_untouch(struct hash_entry *h) +{ + h->lru_next->lru_prev = h->lru_prev; + h->lru_prev->lru_next = h->lru_next; + + h->lru_prev = &lru_first_hash; + h->lru_next = lru_first_hash.lru_next; + h->lru_next->lru_prev = h; + lru_first_hash.lru_next = h; } static void forget_block(struct hash_block *hb) { struct hash_entry *h = hb->he_first; - + hb->lru_next->lru_prev = hb->lru_prev; hb->lru_prev->lru_next = hb->lru_next; @@ -198,56 +217,31 @@ static void forget_block(struct hash_blo h->execute = NULL; h->next_same_block = NULL; h = next; + num_unused_hash++; + lru_untouch(h); } while (h != hb->he_first); -} - -static void kill_lru_block(void) -{ - struct hash_block *hb = lru_first_block.lru_next; - struct hash_entry *h = hb->he_first; - - hb->lru_next->lru_prev = hb->lru_prev; - hb->lru_prev->lru_next = hb->lru_next; - - hb->lru_next = freelist_block; - freelist_block = hb; - - if (hb->cpage != NULL) { - hb->cpage->allocmask &= ~hb->page_allocmask; - } - do { - struct hash_entry *next = h->next_same_block; - if (remove_hash_from_lists(h)) { - h->next_same_block = freelist_hash; - freelist_hash = h; - } else { - h->block = NULL; - h->next_same_block = NULL; - h->execute = NULL; - } - h = next; - } while (h != hb->he_first); + compiler_flush_jsr_stack(); } static void lru_touch_block(struct hash_block *h) { h->lru_next->lru_prev = h->lru_prev; h->lru_prev->lru_next = h->lru_next; - + h->lru_next = &lru_first_block; h->lru_prev = lru_first_block.lru_prev; h->lru_prev->lru_next = h; - lru_first_block.lru_prev = h; + lru_first_block.lru_prev = h; } -static int check_block(struct hash_block *hb) +STATIC_INLINE int check_block(struct hash_block *hb) { #ifndef RELY_ON_LOADSEG_DETECTION struct hash_entry *h = hb->he_first; - + do { struct hash_entry *next = h->next_same_block; - if (h->matchword != *(ULONG *)get_real_address(h->addr)) + if (h->matchword != *(uae_u32 *)get_real_address(h->addr)) return 0; h = next; } while (h != hb->he_first); @@ -255,10 +249,10 @@ static int check_block(struct hash_block return 1; } -ULONG flush_icache(void) +uae_u32 flush_icache(void) { struct hash_block *hb = lru_first_block.lru_next; - + while (hb != &lru_first_block) { struct hash_block *next = hb->lru_next; if (hb->cpage != NULL) { @@ -271,7 +265,7 @@ ULONG flush_icache(void) } hb = next; } - return regs.d[0]; + return m68k_dreg(regs, 0); } void possible_loadseg(void) @@ -283,7 +277,7 @@ void possible_loadseg(void) static struct hash_block *new_block(void) { struct hash_block *b = freelist_block; - + if (b != NULL) { freelist_block = b->lru_next; } else @@ -304,14 +298,21 @@ static struct hash_entry *get_free_hash( if (h != NULL) { freelist_hash = h->next_same_block; break; - } + } h = lru_first_hash.lru_next; - if (h->block == NULL) { + if (num_unused_hash >= MAX_UNUSED_HASH && h->block == NULL + && !h->locked) + { remove_hash_from_lists(h); + num_unused_hash--; break; } - kill_lru_block(); + h = (struct hash_entry *)malloc(sizeof(struct hash_entry)); + h->next_same_block = NULL; + h->addr = -1; + break; } + num_unused_hash++; h->block = NULL; h->ncalls = 0; h->locked = h->cacheflush = 0; @@ -319,10 +320,10 @@ static struct hash_entry *get_free_hash( return h; } -static struct hash_entry *new_hash(CPTR addr) +static struct hash_entry *new_hash(uaecptr addr) { struct hash_entry *h = get_free_hash(); - + h->addr = addr; /* Chain the new node */ @@ -334,35 +335,23 @@ static struct hash_entry *new_hash(CPTR h->lru_prev = lru_first_hash.lru_prev; h->lru_prev->lru_next = h; lru_first_hash.lru_prev = h; - + h->next_same_block = NULL; return h; } - -static void lru_touch(struct hash_entry *h) -{ - if (0) { - h->lru_next->lru_prev = h->lru_prev; - h->lru_prev->lru_next = h->lru_next; - - h->lru_next = &lru_first_hash; - h->lru_prev = lru_first_hash.lru_prev; - h->lru_prev->lru_next = h; - lru_first_hash.lru_prev = h; - } -} - -static struct hash_entry *find_hash(CPTR addr) +static struct hash_entry *find_hash(uaecptr addr) { struct hash_entry *h; struct hash_entry *h1 = cpu_hash + ((addr >> 1) & HASH_MASK); if (h1->next->addr == addr) return h1->next; - + for (h = h1->next; h != h1; h = h->next) { if (h->addr == addr) { + /* Put it at the head of the list so that the above shortcut + * works the next time we come here */ h->next->prev = h->prev; h->prev->next = h->next; h->prev = h1; h->next = h1->next; @@ -373,19 +362,23 @@ static struct hash_entry *find_hash(CPTR return NULL; } -static struct hash_entry *get_hash_for_func(CPTR addr) +static struct hash_entry *get_hash_for_func(uaecptr addr, int mark_locked) { struct hash_entry *h = find_hash(addr); if (h == NULL) h = new_hash (addr); +#if 0 /* Too expensive */ else lru_touch(h); +#endif + if (mark_locked) + h->locked = 1; return h; } -static struct hash_entry *get_hash(CPTR addr) +static struct hash_entry *get_hash(uaecptr addr) { - struct hash_entry *h = get_hash_for_func(addr); + struct hash_entry *h = get_hash_for_func(addr, 0); if (h->block == NULL) { if (++h->ncalls == SCAN_MARK) { @@ -396,24 +389,24 @@ static struct hash_entry *get_hash(CPTR lru_touch_block(h->block); if (m68k_compile_block(h->block)) { h->block->untranslatable = 1; - } else + } else { h->block->translated = 1; + } } - return h; } -void special_flush_hash(CPTR addr) +void special_flush_hash(uaecptr addr) { - struct hash_entry *h = get_hash_for_func(addr); - + struct hash_entry *h = get_hash_for_func(addr, 0); + h->cacheflush = 1; } -static __inline__ void m68k_setpc_hash(CPTR newpc) +STATIC_INLINE void m68k_setpc_hash(uaecptr newpc) { struct hash_entry *h = get_hash(newpc); - + if (h->cacheflush) flush_icache(); @@ -425,14 +418,14 @@ static __inline__ void m68k_setpc_hash(C nr_bbs_to_run = nr_bbs_start; regs.spcflags |= SPCFLAG_EXEC; } - } else + } else flush_icache(); } regs.pc = newpc; regs.pc_p = regs.pc_oldp = get_real_address(newpc); } -static __inline__ void m68k_setpc_nohash(CPTR newpc) +STATIC_INLINE void m68k_setpc_nohash(uaecptr newpc) { #if 0 /* This is probably not too good for efficiency... FIXME */ @@ -445,22 +438,22 @@ static __inline__ void m68k_setpc_nohash regs.pc_p = regs.pc_oldp = get_real_address(newpc); } -void m68k_setpc(CPTR newpc) +void m68k_setpc(uaecptr newpc) { - m68k_setpc_hash(newpc); + m68k_setpc_hash(newpc); } -void m68k_setpc_fast(CPTR newpc) +void m68k_setpc_fast(uaecptr newpc) { - m68k_setpc_nohash(newpc); + m68k_setpc_nohash(newpc); } -void m68k_setpc_rte(CPTR newpc) +void m68k_setpc_rte(uaecptr newpc) { m68k_setpc_nohash(newpc); } -void m68k_setpc_bcc(CPTR newpc) +void m68k_setpc_bcc(uaecptr newpc) { m68k_setpc_hash(newpc); } @@ -469,7 +462,10 @@ static void hash_init(void) { int i; struct hash_entry **hepp; - + + freelist_block = NULL; + freelist_hash = NULL; + for(i = 0; i < NUM_HASH; i++) { cpu_hash[i].next = cpu_hash[i].prev = cpu_hash + i; cpu_hash[i].lru_next = cpu_hash[i].lru_prev = NULL; @@ -477,17 +473,11 @@ static void hash_init(void) cpu_hash[i].locked = 0; cpu_hash[i].cacheflush = 0; cpu_hash[i].addr = -1; } - hepp = &freelist_hash; - for(i = 0; i < NUM_FUNCTIONS; i++) { - *hepp = hash_entries + i; - hash_entries[i].next_same_block = NULL; - hash_entries[i].addr = -1; - hepp = &hash_entries[i].next_same_block; - } + lru_first_hash.lru_next = lru_first_hash.lru_prev = &lru_first_hash; lru_first_block.lru_next = lru_first_block.lru_prev = &lru_first_block; - - freelist_block = NULL; + + num_unused_hash = 0; } static void code_init(void) @@ -497,39 +487,37 @@ static void code_init(void) zeroff = 0; } -void compiler_init(void) -{ - int i; - code_init(); - hash_init(); -} +#define CC68K_C 16 +#define CC68K_V 8 +#define CC68K_Z 4 +#define CC68K_N 2 +#define CC68K_X 1 -/* Help function for the scan routine */ -static __inline__ int cc_flagmask(const int cc) +STATIC_INLINE int cc_flagmask_68k(const int cc) { switch(cc){ case 0: return 0; /* T */ case 1: return 0; /* F */ - case 2: return 5; /* HI */ - case 3: return 5; /* LS */ - case 4: return 1; /* CC */ - case 5: return 1; /* CS */ - case 6: return 4; /* NE */ - case 7: return 4; /* EQ */ - case 8: return 2; /* VC */ - case 9: return 2; /* VS */ - case 10:return 8; /* PL */ - case 11:return 8; /* MI */ - case 12:return 10; /* GE */ - case 13:return 10; /* LT */ - case 14:return 14; /* GT */ - case 15:return 14; /* LE */ + case 2: return CC68K_C|CC68K_Z; /* HI */ + case 3: return CC68K_C|CC68K_Z; /* LS */ + case 4: return CC68K_C; /* CC */ + case 5: return CC68K_C; /* CS */ + case 6: return CC68K_Z; /* NE */ + case 7: return CC68K_Z; /* EQ */ + case 8: return CC68K_V; /* VC */ + case 9: return CC68K_V; /* VS */ + case 10:return CC68K_N; /* PL */ + case 11:return CC68K_N; /* MI */ + case 12:return CC68K_N|CC68K_V; /* GE */ + case 13:return CC68K_N|CC68K_V; /* LT */ + case 14:return CC68K_N|CC68K_V|CC68K_Z; /* GT */ + case 15:return CC68K_N|CC68K_V|CC68K_Z; /* LE */ } abort(); return 0; } -static __inline__ void translate_step_over_ea(UBYTE **pcpp, amodes m, +STATIC_INLINE void translate_step_over_ea(uae_u8 **pcpp, amodes m, wordsizes size) { switch (m) { @@ -555,7 +543,7 @@ static __inline__ void translate_step_ov case Ad8r: case PC8r: { - UWORD extra = *(*pcpp)++; + uae_u16 extra = *(*pcpp)++; extra <<= 8; extra |= *(*pcpp)++; /* @@@ handle 68020 stuff here */ @@ -569,14 +557,14 @@ static __inline__ void translate_step_ov } } -static struct instr *translate_getnextinsn(UBYTE **pcpp) +static struct instr *translate_getnextinsn(uae_u8 **pcpp) { - UWORD opcode; + uae_u16 opcode; struct instr *dp; - + opcode = *(*pcpp)++ << 8; opcode |= *(*pcpp)++; - + if (cpufunctbl[opcode] == op_illg) { opcode = 0x4AFC; } @@ -593,12 +581,12 @@ static struct instr *translate_getnextin #define CB_STACKSIZE 200 #define BB_STACKSIZE 200 -static ULONG condbranch_stack[CB_STACKSIZE]; +static uae_u32 condbranch_stack[CB_STACKSIZE]; static int condbranch_src_stack[CB_STACKSIZE]; struct bb_info { struct hash_entry *h; - CPTR stopaddr; + uaecptr stopaddr; int can_compile_last; struct bb_info *bb_next1, *bb_next2; int flags_live_at_end; @@ -608,12 +596,12 @@ struct bb_info { static int top_bb; -static CPTR bcc_target_stack[BB_STACKSIZE]; +static uaecptr bcc_target_stack[BB_STACKSIZE]; -static int new_bcc_target(CPTR addr) +static int new_bcc_target(uaecptr addr) { int i; - + for (i = 0; i < top_bb; i++) if (bcc_target_stack[i] == addr) return 1; @@ -626,11 +614,11 @@ static int new_bcc_target(CPTR addr) static int bcc_compfn(const void *a, const void *b) { - CPTR *a1 = (CPTR *)a, *b1 = (CPTR *)b; - + uaecptr *a1 = (uaecptr *)a, *b1 = (uaecptr *)b; + if (*a1 == *b1) printf("BUG!!\n"); - + if (*a1 < *b1) return 1; return -1; @@ -639,10 +627,10 @@ static int bcc_compfn(const void *a, con static int bb_compfn(const void *a, const void *b) { struct bb_info *a1 = (struct bb_info *)a, *b1 = (struct bb_info *)b; - + if (a1->h->addr == b1->h->addr) printf("BUG!!\n"); - + if (a1->h->addr < b1->h->addr) return -1; return 1; @@ -657,24 +645,24 @@ static int find_basic_blocks(struct hash new_bcc_target(h->addr); while (top_bb > current_bb) { - CPTR addr = bcc_target_stack[current_bb]; + uaecptr addr = bcc_target_stack[current_bb]; int ninsns = 0; - UBYTE *realpc = get_real_address(addr); - UBYTE *rpc_start = realpc; - + uae_u8 *realpc = get_real_address(addr); + uae_u8 *rpc_start = realpc; + for(;;) { - CPTR thisinsn_addr = (realpc - rpc_start) + addr; - UBYTE *rpc_save = realpc; + uaecptr thisinsn_addr = (realpc - rpc_start) + addr; + uae_u8 *rpc_save = realpc; struct instr *dp = translate_getnextinsn(&realpc); - CPTR nextinsn_addr = (realpc - rpc_start) + addr; + uaecptr nextinsn_addr = (realpc - rpc_start) + addr; - if (dp->mnemo == i_RTS || dp->mnemo == i_RTE + if (dp->mnemo == i_RTS || dp->mnemo == i_RTE || dp->mnemo == i_RTR || dp->mnemo == i_RTD - || dp->mnemo == i_JMP || dp->mnemo == i_ILLG) + || dp->mnemo == i_JMP || dp->mnemo == i_ILLG) { break; } - + if (dp->mnemo == i_BSR || dp->mnemo == i_JSR) { if (!new_bcc_target(nextinsn_addr)) return 0; @@ -682,21 +670,21 @@ static int find_basic_blocks(struct hash } if (dp->mnemo == i_DBcc) { - CPTR newaddr = thisinsn_addr + 2 + (WORD)((*(rpc_save+2) << 8) | *(rpc_save+3)); + uaecptr newaddr = thisinsn_addr + 2 + (uae_s16)((*(rpc_save+2) << 8) | *(rpc_save+3)); if (!new_bcc_target(nextinsn_addr)) return 0; if (!new_bcc_target(newaddr)) return 0; break; } - + if (dp->mnemo == i_Bcc) { - CPTR newaddr; + uaecptr newaddr; if (dp->smode == imm1) - newaddr = thisinsn_addr + 2 + (WORD)((*(rpc_save+2) << 8) | *(rpc_save+3)); + newaddr = thisinsn_addr + 2 + (uae_s16)((*(rpc_save+2) << 8) | *(rpc_save+3)); else - newaddr = thisinsn_addr + 2 + (BYTE)dp->sreg; - + newaddr = thisinsn_addr + 2 + (uae_s8)dp->sreg; + if (dp->cc != 0) if (!new_bcc_target(nextinsn_addr)) return 0; @@ -708,7 +696,7 @@ static int find_basic_blocks(struct hash current_bb++; } - qsort(bcc_target_stack, top_bb, sizeof (CPTR), bcc_compfn); + qsort(bcc_target_stack, top_bb, sizeof (uaecptr), bcc_compfn); return 1; } @@ -718,16 +706,25 @@ static int m68k_scan_func(struct hash_en int i; struct hash_block *found_block; struct hash_entry **hepp; - + if (!find_basic_blocks(h)) return 0; found_block = NULL; - + + /* First, lock the hash entries we already have to prevent grief */ for (i = 0; i < top_bb; i++) { - struct hash_entry *h = get_hash_for_func(bcc_target_stack[i]); + struct hash_entry *h = find_hash(bcc_target_stack[i]); + if (h != NULL) + h->locked = 1; + } + + /* Allocate new ones */ + for (i = 0; i < top_bb; i++) { + struct hash_entry *h = get_hash_for_func(bcc_target_stack[i], 1); bb_stack[i].h = h; - /* if (h->block != NULL && h->block != found_block) { +#if 0 /* This doesn't work in all cases */ + if (h->block != NULL && h->block != found_block) { if (found_block == NULL) { if (h->block->cpage != NULL) fprintf(stderr, "Found compiled code\n"); @@ -743,7 +740,8 @@ static int m68k_scan_func(struct hash_en } else fprintf(stderr, "Bad case.\n"); } - }*/ + } +#endif } if (found_block == NULL) { found_block = new_block(); @@ -760,6 +758,8 @@ static int m68k_scan_func(struct hash_en struct bb_info *bb = bb_stack + i; if (bb->h->block == NULL) { + num_unused_hash--; + lru_touch(bb->h); bb->h->block = found_block; *hepp = bb->h; hepp = &bb->h->next_same_block; @@ -774,12 +774,12 @@ struct ea_reg_info { int regs_set:16; int regs_used:16; int nr_scratch; - ULONG temp1, temp2; + uae_u32 temp1, temp2; }; #define MAX_TRANSLATE 2048 struct insn_info_struct { - CPTR address; + uaecptr address; struct instr *dp; int flags_set; int flags_used; @@ -790,22 +790,24 @@ struct insn_info_struct { char *compiled_fillin; /* Address where to put offset if this is a Bcc */ int regs_set:16; int regs_used:16; - int stop_translation:1; + int stop_translation:2; int sync_cache:1; int sync_flags:1; int ccuser_follows:1; } insn_info [MAX_TRANSLATE]; +#define EA_NONE 0 #define EA_LOAD 1 #define EA_STORE 2 -#define EA_IN_REG 4 /* Not quite sure yet what this flag will mean... :) */ +#define EA_MODIFY 4 + #if 0 static void analyze_ea_for_insn(amodes mode, int reg, wordsizes size, struct ea_reg_info *eai, - UBYTE **pcpp, CPTR pca, + uae_u8 **pcpp, uaecptr pca, int ea_purpose) { - UBYTE *p = *pcpp; + uae_u8 *p = *pcpp; switch(mode) { case Dreg: @@ -817,7 +819,7 @@ static void analyze_ea_for_insn(amodes m if (ea_purpose & EA_STORE) eai->regs_set |= 1 << reg; break; - + case Areg: eai->ea_type = eat_reg; if (size != sz_long && (ea_purpose & EA_STORE)) @@ -827,7 +829,7 @@ static void analyze_ea_for_insn(amodes m if (ea_purpose & EA_STORE) eai->regs_set |= 1 << (8+reg); break; - + case Ad16: case Aind: case Apdi: @@ -840,10 +842,10 @@ static void analyze_ea_for_insn(amodes m eai->ea_type = eat_imem; pii->regs_used |= 1 << (8+reg); - eai->temp = (UWORD)((*p << 8) | *(p+1)); + eai->temp = (uae_u16)((*p << 8) | *(p+1)); r = (eai->temp & 0x7000) >> 12; - (*pcpp) += 2; p += 2; - + (*pcpp) += 2; p += 2; + if (eai->temp1 & 0x8000) pii->regs_used |= 1 << (8+r); else @@ -852,8 +854,8 @@ static void analyze_ea_for_insn(amodes m case PC8r: eai->ea_type = eat_imem; - eai->temp1 = (UWORD)((*p << 8) | *(p+1)); - eai->temp2 = pca + (BYTE)eai->temp1; + eai->temp1 = (uae_u16)do_get_mem_word((uae_u16 *)p); + eai->temp2 = pca + (uae_s8)eai->temp1; (*pcpp) += 2; p += 2; r = (eai->temp1 & 0x7000) >> 12; @@ -862,23 +864,22 @@ static void analyze_ea_for_insn(amodes m else pii->regs_used |= 1 << r; break; - - case PC16: + + case PC16: eai->ea_type = eat_amem; - eai->temp1 = pca + (WORD)((*p << 8) | *(p+1)); + eai->temp1 = pca + (uae_s16)do_get_mem_word((uae_u16 *)p); (*pcpp) += 2; break; - + case absw: eai->ea_type = eat_amem; - eai->temp1 = (WORD)((*p << 8) | *(p+1)); + eai->temp1 = (uae_s16)do_get_mem_word((uae_u16 *)p); (*pcpp) += 2; break; case absl: eai->ea_type = eat_amem; - eai->temp1 = (LONG)((*p << 24) | (*(p+1) << 16) - | (*(p+2) << 8) | *(p+3)); + eai->temp1 = (uae_s32)do_get_mem_long((uae_u32 *)p); (*pcpp) += 4; break; @@ -887,31 +888,31 @@ static void analyze_ea_for_insn(amodes m goto imm2_const; if (size == sz_word) goto imm1_const; - + /* fall through */ case imm0: eai->ea_type = eat_imm; - eai->temp1 = (BYTE)*(p+1); + eai->temp1 = (uae_s8)*(p+1); (*pcpp) += 2; break; case imm1: imm1_const: eai->ea_type = eat_imm; - eai->temp1 = (WORD)((*p << 8) | *(p+1)); + eai->temp1 = (uae_s16)do_get_mem_word((uae_u16 *)p); (*pcpp) += 2; break; case imm2: imm2_const: eai->ea_type = eat_imm; - eai->temp1 = (LONG)((*p << 24) | (*(p+1) << 16) | (*(p+2) << 8) | *(p+3)); + eai->temp1 = (uae_s32)do_get_mem_long((uae_u32 *)p); (*pcpp) += 4; break; case immi: eai->ea_type = eat_imm; - eai->temp1 = (BYTE)reg; + eai->temp1 = (uae_s8)reg; break; default: @@ -922,7 +923,10 @@ static void analyze_ea_for_insn(amodes m static struct bb_info *find_bb(struct hash_entry *h) { int i; - + + if (h == NULL) + printf("Bug...\n"); + for (i = 0; i < top_bb; i++) if (bb_stack[i].h == h) return bb_stack + i; @@ -935,9 +939,10 @@ static int m68k_scan_block(struct hash_b { struct hash_entry *h = hb->he_first; int i, iip, last_iip; - + int changed, round; + top_bb = 0; - + do { struct bb_info *bb = bb_stack + top_bb; bb->h = h; @@ -946,7 +951,7 @@ static int m68k_scan_block(struct hash_b h = h->next_same_block; top_bb++; } while (h != hb->he_first); - + qsort(bb_stack, top_bb, sizeof (struct bb_info), bb_compfn); *movem_count = 0; @@ -954,9 +959,9 @@ static int m68k_scan_block(struct hash_b iip = 0; for (i = 0; i < top_bb; i++) { struct bb_info *bb = bb_stack + i; - UBYTE *realpc = get_real_address(bb->h->addr); - UBYTE *rpc_start = realpc; - CPTR stop_addr = 0; + uae_u8 *realpc = get_real_address(bb->h->addr); + uae_u8 *rpc_start = realpc; + uaecptr stop_addr = 0; int live_at_start = 31, may_clear_las = 31; struct insn_info_struct *prev_ii = NULL; @@ -966,28 +971,28 @@ static int m68k_scan_block(struct hash_b for (;;) { struct insn_info_struct *thisii = insn_info + iip; - CPTR thisinsn_addr = (realpc - rpc_start) + bb->h->addr; - UBYTE *rpc_save = realpc; + uaecptr thisinsn_addr = (realpc - rpc_start) + bb->h->addr; + uae_u8 *rpc_save = realpc; struct instr *dp = translate_getnextinsn(&realpc); - CPTR nextinsn_addr = (realpc - rpc_start) + bb->h->addr; - + uaecptr nextinsn_addr = (realpc - rpc_start) + bb->h->addr; + int fset = dp->flagdead == -1 ? 31 : dp->flagdead; int fuse = dp->flaglive == -1 ? 31 : dp->flaglive; - + if (thisinsn_addr == stop_addr) { bb->bb_next1 = find_bb (find_hash (thisinsn_addr)); break; } - + if (dp->mnemo == i_Scc || dp->mnemo == i_Bcc || dp->mnemo == i_DBcc) { - fset = 0, fuse = cc_flagmask(dp->cc); + fset = 0, fuse = cc_flagmask_68k(dp->cc); if (prev_ii && dp->mnemo != i_Scc) /* Don't use Scc here: ea can cause an exit */ prev_ii->ccuser_follows = 1; } may_clear_las &= ~fuse; live_at_start &= ~(fset & may_clear_las); - + thisii->dp = dp; thisii->address = thisinsn_addr; thisii->stop_translation = 0; @@ -1003,42 +1008,51 @@ static int m68k_scan_block(struct hash_b if (iip == MAX_TRANSLATE) return 0; - if (dp->mnemo == i_RTS || dp->mnemo == i_RTE + if (dp->mnemo == i_RTS || dp->mnemo == i_RTE || dp->mnemo == i_RTR || dp->mnemo == i_RTD - || dp->mnemo == i_JMP || dp->mnemo == i_ILLG - || dp->mnemo == i_BSR || dp->mnemo == i_JSR) + || dp->mnemo == i_JMP || dp->mnemo == i_ILLG) { thisii->flags_used = 31; thisii->regs_used = 65535; - thisii->stop_translation = 1; + thisii->stop_translation = dp->mnemo == i_RTS || dp->mnemo == i_JMP ? 2 : 1; break; } - + if (dp->mnemo == i_BSR || dp->mnemo == i_JSR) + { + thisii->flags_used = 31; + thisii->regs_used = 65535; + bb->can_compile_last = 1; + bb->bb_next1 = find_bb (get_hash_for_func (nextinsn_addr, 1)); + if (bb->bb_next1 == NULL) + thisii->stop_translation = 1; + break; + } + if (dp->mnemo == i_DBcc) { - CPTR newaddr = thisinsn_addr + 2 + (WORD)((*(rpc_save+2) << 8) | *(rpc_save+3)); + uaecptr newaddr = thisinsn_addr + 2 + (uae_s16)((*(rpc_save+2) << 8) | *(rpc_save+3)); bb->can_compile_last = 1; - bb->bb_next1 = find_bb (find_hash (newaddr)); + bb->bb_next1 = find_bb (get_hash_for_func (newaddr, 1)); if (bb->bb_next1 == NULL) thisii->stop_translation = 1; - bb->bb_next2 = find_bb (find_hash (nextinsn_addr)); + bb->bb_next2 = find_bb (get_hash_for_func (nextinsn_addr, 1)); if (bb->bb_next2 == NULL) thisii->stop_translation = 1; thisii->regs_used = 65535; break; } - + if (dp->mnemo == i_Bcc) { - CPTR newaddr; + uaecptr newaddr; if (dp->smode == imm1) - newaddr = thisinsn_addr + 2 + (WORD)((*(rpc_save+2) << 8) | *(rpc_save+3)); + newaddr = thisinsn_addr + 2 + (uae_s16)((*(rpc_save+2) << 8) | *(rpc_save+3)); else - newaddr = thisinsn_addr + 2 + (BYTE)dp->sreg; + newaddr = thisinsn_addr + 2 + (uae_s8)dp->sreg; bb->can_compile_last = 1; - bb->bb_next1 = find_bb(get_hash_for_func(newaddr)); + bb->bb_next1 = find_bb(get_hash_for_func(newaddr, 1)); if (bb->bb_next1 == NULL) thisii->stop_translation = 1; if (dp->cc != 0) { - bb->bb_next2 = find_bb(get_hash_for_func(nextinsn_addr)); + bb->bb_next2 = find_bb(get_hash_for_func(nextinsn_addr, 1)); if (bb->bb_next2 == NULL) thisii->stop_translation = 1; } @@ -1047,7 +1061,7 @@ static int m68k_scan_block(struct hash_b } if (dp->mnemo == i_MVMLE || dp->mnemo == i_MVMEL) { - UWORD regmask = (*(rpc_save + 2) << 8) | (*(rpc_save + 3)); + uae_u16 regmask = (*(rpc_save + 2) << 8) | (*(rpc_save + 3)); *movem_count += count_bits(regmask); if (dp->dmode == Apdi) regmask = bitswap(regmask); @@ -1063,60 +1077,117 @@ static int m68k_scan_block(struct hash_b bb->flags_live_at_start = live_at_start; } last_iip = iip; + round = 0; + do { + changed = 0; + for (i = 0; i < top_bb; i++) { + struct bb_info *bb = bb_stack + i; + int mnemo; + int current_live; + struct instr *dp; + + iip = bb->last_iip; + mnemo = insn_info[iip].dp->mnemo; + + /* Fix up branches */ + if (round == 0 && (mnemo == i_DBcc || mnemo == i_Bcc)) { + if (bb->bb_next1 != NULL) { + insn_info[bb->last_iip].jumps_to = bb->bb_next1->first_iip; + insn_info[bb->bb_next1->first_iip].jump_target = 1; + } + } - for (i = 0; i < top_bb; i++) { - struct bb_info *bb = bb_stack + i; - int mnemo; - int current_live; - struct instr *dp; - - iip = bb->last_iip; - mnemo = insn_info[iip].dp->mnemo; - - /* Fix up branches */ - if (mnemo == i_DBcc || mnemo == i_Bcc) { - if (bb->bb_next1 != NULL) { - insn_info[bb->last_iip].jumps_to = bb->bb_next1->first_iip; - insn_info[bb->bb_next1->first_iip].jump_target = 1; - } - } - /* And take care of flag life information */ - dp = insn_info[iip].dp; - if (insn_info[iip].stop_translation) - current_live = 31; - else if (dp->mnemo == i_DBcc || dp->mnemo == i_Bcc) { - current_live = 0; - if (bb->bb_next1 != NULL) - current_live |= bb->bb_next1->flags_live_at_start; - if (bb->bb_next2 != NULL) - current_live |= bb->bb_next2->flags_live_at_start; - } else { - if (bb->bb_next1 == NULL && bb->bb_next2 == NULL) - fprintf(stderr, "Can't happen\n"); - current_live = 0; - if (bb->bb_next1 != NULL) - current_live |= bb->bb_next1->flags_live_at_start; - if (bb->bb_next2 != NULL) - current_live |= bb->bb_next2->flags_live_at_start; + /* And take care of flag life information */ + dp = insn_info[iip].dp; + if (insn_info[iip].stop_translation) + current_live = 31; + else if (dp->mnemo == i_DBcc || dp->mnemo == i_Bcc) { + current_live = 0; + if (bb->bb_next1 != NULL) + current_live |= bb->bb_next1->flags_live_at_start; + if (bb->bb_next2 != NULL) + current_live |= bb->bb_next2->flags_live_at_start; + } else { + if (bb->bb_next1 == NULL && bb->bb_next2 == NULL) + fprintf(stderr, "Can't happen\n"); + current_live = 0; + if (bb->bb_next1 != NULL) + current_live |= bb->bb_next1->flags_live_at_start; + if (bb->bb_next2 != NULL) + current_live |= bb->bb_next2->flags_live_at_start; + } + + do { + insn_info[iip].flags_live_at_end = current_live; + current_live &= ~insn_info[iip].flags_set; + current_live |= insn_info[iip].flags_used; + } while (iip-- != bb->first_iip); + + if (bb->flags_live_at_start != current_live && !quiet_compile) + fprintf(stderr, "Fascinating %d!\n", round), changed = 1; + bb->flags_live_at_start = current_live; } + round++; + } while (changed); + return last_iip; +} - do { - insn_info[iip].flags_live_at_end = current_live; - current_live &= ~insn_info[iip].flags_set; - current_live |= insn_info[iip].flags_used; - } while (iip-- != bb->first_iip); - - if (bb->flags_live_at_start != current_live && !quiet_compile) - fprintf(stderr, "Fascinating!\n"); - bb->flags_live_at_start = current_live; +#define MAX_JSRS 4096 /* must be a power of two */ + +static uaecptr jsr_rets[MAX_JSRS]; +static struct hash_entry *jsr_hash[MAX_JSRS]; +static int jsr_num; +static struct hash_entry dummy_hash; /* This is for safety purposes only */ + + +static void jsr_stack_init(void) +{ + jsr_num = 0; + dummy_hash.execute = NULL; +} + +void compiler_flush_jsr_stack(void) +{ + jsr_num = 0; +} + +void m68k_do_rts(void) +{ + m68k_setpc(get_long(m68k_areg(regs, 7))); + m68k_areg(regs, 7) += 4; + if (jsr_num > 0) + jsr_num--; +} + +__inline__ void m68k_do_jsr(uaecptr oldpc, uaecptr dest) +{ + struct hash_entry *h = find_hash(oldpc); + + if (jsr_num == MAX_JSRS) + compiler_flush_jsr_stack(); + if (h == NULL) { + jsr_hash[jsr_num] = &dummy_hash; + jsr_rets[jsr_num++] = 0xC0DEDBAD; + } else { + jsr_hash[jsr_num] = h; + jsr_rets[jsr_num++] = oldpc; } - return last_iip; + m68k_areg(regs, 7) -= 4; + put_long(m68k_areg(regs, 7), oldpc); + m68k_setpc(dest); } +void m68k_do_bsr(uaecptr oldpc, uae_s32 offset) +{ + m68k_do_jsr(oldpc, m68k_getpc() + offset); +} + +/* Here starts the actual compiling part */ + static char *compile_current_addr; static char *compile_last_addr; -static __inline__ void assemble(UBYTE a) +STATIC_INLINE void assemble(uae_u8 a) { if (compile_current_addr < compile_last_addr) { *compile_current_addr++ = a; @@ -1125,7 +1196,7 @@ static __inline__ void assemble(UBYTE a) } } -static __inline__ void assemble_ulong(ULONG a) +STATIC_INLINE void assemble_ulong(uae_u32 a) { assemble(a); assemble(a >> 8); @@ -1133,23 +1204,31 @@ static __inline__ void assemble_ulong(UL assemble(a >> 24); } -static __inline__ void assemble_uword(UWORD a) +STATIC_INLINE void assemble_ulong_68k(uae_u32 a) +{ + assemble(a >> 24); + assemble(a >> 16); + assemble(a >> 8); + assemble(a); +} + +STATIC_INLINE void assemble_uword(uae_u16 a) { assemble(a); assemble(a >> 8); } -static __inline__ void assemble_long(void *a) +STATIC_INLINE void assemble_long(void *a) { - assemble_ulong((ULONG)a); + assemble_ulong((uae_u32)a); } -static __inline__ void compile_org(char *addr) +STATIC_INLINE void compile_org(char *addr) { compile_current_addr = addr; } -static __inline__ char *compile_here(void) +STATIC_INLINE char *compile_here(void) { return compile_current_addr; } @@ -1183,6 +1262,7 @@ struct register_mapping { int x86_cache_reg[8]; /* Regs used for the 68000 register cache */ int x86_cr_type[8]; /* Caching data or address register? */ int x86_locked[8]; /* Regs used for some purpose */ + int x86_users[8]; int x86_byteorder[8]; int x86_verified[8]; }; @@ -1191,13 +1271,13 @@ struct register_mapping { * First, code to compile some primitive x86 instructions */ -static void compile_lea_reg_with_offset(int dstreg, int srcreg, ULONG srcoffs) +static void compile_lea_reg_with_offset(int dstreg, int srcreg, uae_u32 srcoffs) { assemble(0x8D); if (srcreg == -2) { assemble(0x05 + 8*dstreg); assemble_ulong(srcoffs); - } else if ((LONG)srcoffs >= -128 && (LONG)srcoffs <= 127) { + } else if ((uae_s32)srcoffs >= -128 && (uae_s32)srcoffs <= 127) { assemble(0x40 + 8*dstreg + srcreg); assemble(srcoffs); } else { @@ -1224,7 +1304,7 @@ static void compile_move_reg_reg(int dst } static void compile_move_between_reg_mem_regoffs(int dstreg, int srcreg, - ULONG srcoffs, wordsizes size, + uae_u32 srcoffs, wordsizes size, int code) { if (size == sz_byte && (dstreg & 0x80) != 0) @@ -1241,11 +1321,11 @@ static void compile_move_between_reg_mem assemble(code); else assemble(code + 1); - + if (srcreg == -2) { assemble(0x05 + 8*dstreg); assemble_ulong(srcoffs); - } else if ((LONG)srcoffs >= -128 && (LONG)srcoffs <= 127) { + } else if ((uae_s32)srcoffs >= -128 && (uae_s32)srcoffs <= 127) { assemble(0x40 + 8*dstreg + srcreg); assemble(srcoffs); } else { @@ -1254,13 +1334,13 @@ static void compile_move_between_reg_mem } } -static void compile_move_reg_from_mem_regoffs(int dstreg, int srcreg, - ULONG srcoffs, wordsizes size) +static void compile_move_reg_from_mem_regoffs(int dstreg, int srcreg, + uae_u32 srcoffs, wordsizes size) { compile_move_between_reg_mem_regoffs(dstreg, srcreg, srcoffs, size, 0x8A); } -static void compile_move_reg_to_mem_regoffs(int dstreg, ULONG dstoffs, +static void compile_move_reg_to_mem_regoffs(int dstreg, uae_u32 dstoffs, int srcreg, wordsizes size) { compile_move_between_reg_mem_regoffs(srcreg, dstreg, dstoffs, size, 0x88); @@ -1291,14 +1371,14 @@ static void compile_byteswap(int x86r, w static void compile_force_byteorder(struct register_mapping *map, int x86r, int desired_bo, int save_flags) { - if (x86r == -2 || map->x86_byteorder[x86r] == desired_bo) + if (x86r < 0 || map->x86_byteorder[x86r] == desired_bo) return; - + if (map->x86_byteorder[x86r] == BO_SWAPPED_LONG) compile_byteswap(x86r, sz_long, save_flags); else if (map->x86_byteorder[x86r] == BO_SWAPPED_WORD) compile_byteswap(x86r, sz_word, save_flags); - + if (desired_bo == BO_SWAPPED_LONG) compile_byteswap(x86r, sz_long, save_flags); else if (desired_bo == BO_SWAPPED_WORD) @@ -1309,11 +1389,11 @@ static void compile_force_byteorder(stru /* Add a constant offset to a x86 register. If it's in the cache, make sure * we update the const_offset value. The flags are unaffected by this */ -static void compile_offset_reg(struct register_mapping *map, int x86r, - ULONG offset) +static void compile_offset_reg(struct register_mapping *map, int x86r, + uae_u32 offset) { int cached_68k; - + if (offset == 0 || x86r == -1 || x86r == -2) return; @@ -1332,9 +1412,9 @@ static int get_unused_x86_register(struc for (x86r = 0; x86r < 24; x86r++) { if (map->x86_cache_reg[x86r] != -1) continue; - if (map->x86_locked[x86r] > 0) + if (map->x86_users[x86r] > 0) continue; - + map->x86_verified[x86r] = 0; map->x86_byteorder[x86r] = BO_NORMAL; return x86r; @@ -1347,34 +1427,34 @@ static int get_unused_x86_register(struc * If may_clobber is 1 and the reg had an offset, the reg will be offsetted * by this function */ -static void sync_reg(struct register_mapping *map, int x86r, void *m68kr, - ULONG offset, int dirty, int may_clobber) +static void sync_reg(struct register_mapping *map, int x86r, void *m68kr, + uae_u32 offset, int dirty, int may_clobber) { - compile_force_byteorder(map, x86r, BO_NORMAL, 1); + if (dirty || offset != 0) + compile_force_byteorder(map, x86r, BO_NORMAL, 1); if (offset != 0) { if (may_clobber) { compile_lea_reg_with_offset(x86r, x86r, offset); dirty = 1; } else { int tmpr = get_unused_x86_register(map); - if (tmpr != -1) { + if (tmpr != -1) { compile_lea_reg_with_offset(tmpr, x86r, offset); x86r = tmpr; dirty = 1; } else { compile_lea_reg_with_offset(x86r, x86r, offset); assemble(0x89); /* movl x86r,m68kr */ - assemble(0x05 + (x86r << 3)); + assemble(0x05 + (x86r << 3)); assemble_long(m68kr); compile_lea_reg_with_offset(x86r, x86r, -offset); return; } } } - if (dirty) { assemble(0x89); /* movl x86r,m68kr */ - assemble(0x05 + (x86r << 3)); + assemble(0x05 + (x86r << 3)); assemble_long(m68kr); } } @@ -1387,11 +1467,11 @@ static void sync_reg_cache(struct regist int cr68k = map->x86_cache_reg[i]; if (cr68k != -1) { if (map->x86_cr_type[i] == 1) { - sync_reg(map, i, regs.d + cr68k, map->x86_const_offset[i], map->x86_dirty[i], 1); + sync_reg(map, i, regs.regs + cr68k, map->x86_const_offset[i], map->x86_dirty[i], 1); if (flush) map->dreg_map[cr68k] = -1; } else { - sync_reg(map, i, regs.a + cr68k, map->x86_const_offset[i], map->x86_dirty[i], 1); + sync_reg(map, i, regs.regs + 8 + cr68k, map->x86_const_offset[i], map->x86_dirty[i], 1); if (flush) map->areg_map[cr68k] = -1; } @@ -1403,27 +1483,28 @@ static void sync_reg_cache(struct regist memset(map->x86_dirty, 0, sizeof map->x86_dirty); } -static void remove_x86r_from_cache(struct register_mapping *map, int x86r, +static void remove_x86r_from_cache(struct register_mapping *map, int x86r, int may_clobber) { int j; int reg_68k; - + if (x86r == -1) return; reg_68k = map->x86_cache_reg[x86r]; - - if (reg_68k != -1) { - if (map->x86_cr_type[x86r] == 1) { - map->dreg_map[reg_68k] = -1; - sync_reg(map, x86r, regs.d + reg_68k, map->x86_const_offset[x86r], - map->x86_dirty[x86r], may_clobber); - } else { - map->areg_map[reg_68k] = -1; - sync_reg(map, x86r, regs.a + reg_68k, map->x86_const_offset[x86r], - map->x86_dirty[x86r], may_clobber); - } + + if (reg_68k == -1) + return; + + if (map->x86_cr_type[x86r] == 1) { + map->dreg_map[reg_68k] = -1; + sync_reg(map, x86r, regs.regs + reg_68k, map->x86_const_offset[x86r], + map->x86_dirty[x86r], may_clobber); + } else { + map->areg_map[reg_68k] = -1; + sync_reg(map, x86r, regs.regs + 8 + reg_68k, map->x86_const_offset[x86r], + map->x86_dirty[x86r], may_clobber); } map->x86_dirty[x86r] = 0; map->x86_cache_reg[x86r] = -1; @@ -1445,10 +1526,15 @@ static int get_free_x86_register(struct if (cnt < 8 && map->x86_cache_reg[x86r] != -1) continue; /* Never use locked registers */ - if (map->x86_locked[x86r] > 0) + if (map->x86_users[x86r] > 0) continue; remove_x86r_from_cache(map, x86r, 1); + map->x86_dirty[x86r] = 0; + map->x86_cache_reg[x86r] = -1; + map->x86_const_offset[x86r] = 0; + map->x86_verified[x86r] = 0; + map->x86_byteorder[x86r] = BO_NORMAL; return x86r; } printf("Out of registers!\n"); @@ -1468,10 +1554,15 @@ static int get_typed_x86_register(struct if (cnt < 8 && map->x86_cache_reg[x86r] != -1) continue; /* Never use locked registers */ - if (map->x86_locked[x86r] > 0) + if (map->x86_users[x86r] > 0) continue; remove_x86r_from_cache(map, x86r, 1); + map->x86_dirty[x86r] = 0; + map->x86_cache_reg[x86r] = -1; + map->x86_const_offset[x86r] = 0; + map->x86_verified[x86r] = 0; + map->x86_byteorder[x86r] = BO_NORMAL; return x86r; } printf("Out of type registers!\n"); @@ -1481,25 +1572,57 @@ static int get_typed_x86_register(struct static void compile_unlock_reg(struct register_mapping *map, int reg) { if (reg >= 0) { - map->x86_locked[reg]--; + if (--map->x86_users[reg] == 0) + map->x86_locked[reg] = 0; + + } +} + +static void lock_reg(struct register_mapping *map, int x86r, int lock_type) +{ +#if 1 + switch (map->x86_locked[x86r]) { + case 0: + if (map->x86_users[x86r] != 0) + printf("Users for an unlocked reg!\n"); + break; + case 1: + if (lock_type == 2) + printf("Locking shared reg for exclusive use!\n"); + break; + case 2: + printf("Locking exclusive reg!\n"); + break; + default: + printf("Unknown lock?\n"); + break; } +#endif + map->x86_locked[x86r] = lock_type; + map->x86_users[x86r]++; } static int get_and_lock_68k_reg(struct register_mapping *map, int reg, int is_dreg, - int preferred, int no_offset) + int preferred, int no_offset, int lock_type) { int x86r; int *regmap; - ULONG *reghome; - + uae_u32 *reghome; + uae_u32 const_off = 0; + + if (reg < 0 || reg > 7) { + printf("Mad compiler disease\n"); + return 0; + } + if (is_dreg) - regmap = map->dreg_map, reghome = regs.d; + regmap = map->dreg_map, reghome = regs.regs; else - regmap = map->areg_map, reghome = regs.a; - + regmap = map->areg_map, reghome = regs.regs + 8; + if (preferred == 0) preferred = ALL_X86_REGS; - + x86r = regmap[reg]; if (x86r == -1) { x86r = get_free_x86_register(map, preferred); @@ -1512,56 +1635,65 @@ static int get_and_lock_68k_reg(struct r map->x86_verified[x86r] = 0; map->x86_byteorder[x86r] = BO_NORMAL; regmap[reg] = x86r; - } else if (map->x86_locked[x86r] > 0) { - /* Register was in cache, and was locked. Need to make a copy */ - int newr = get_free_x86_register(map, preferred); - int old_dirty = 0; - int old_verified; - int old_bo; - - if (map->x86_const_offset[x86r] == 0) { - compile_move_reg_reg(newr, x86r, sz_long); - } else { - compile_force_byteorder(map, x86r, BO_NORMAL, 1); - compile_lea_reg_with_offset(newr, x86r, map->x86_const_offset[x86r]); - old_dirty = 1; + } else { + const_off = map->x86_const_offset[x86r]; + + if (map->x86_locked[x86r] == 2 + || (map->x86_locked[x86r] == 1 && (lock_type == 2 || (const_off != 0 && no_offset)))) + { + int newr; + int old_dirty = 0; + int old_verified; + int old_bo; + + newr = get_free_x86_register(map, preferred); + if (const_off == 0) { + compile_move_reg_reg(newr, x86r, sz_long); + } else { + compile_force_byteorder(map, x86r, BO_NORMAL, 1); + compile_lea_reg_with_offset(newr, x86r, const_off); + old_dirty = 1; + const_off = 0; + } + /* Remove old reg from cache... */ + map->x86_cache_reg[x86r] = -1; + map->x86_cr_type[x86r] = is_dreg; + map->x86_const_offset[x86r] = 0; + old_dirty |= map->x86_dirty[x86r]; + old_verified = map->x86_verified[x86r]; + old_bo = map->x86_byteorder[x86r]; + map->x86_verified[x86r] = 0; + map->x86_dirty[x86r] = 0; + x86r = newr; + /* ... and make the new one the cache register */ + map->x86_cache_reg[x86r] = reg; + map->x86_cr_type[x86r] = is_dreg; + map->x86_const_offset[x86r] = 0; + map->x86_dirty[x86r] = old_dirty; + map->x86_verified[x86r] = old_verified; + map->x86_byteorder[x86r] = old_bo; + regmap[reg] = x86r; } - /* Remove old reg from cache... */ - map->x86_cache_reg[x86r] = -1; - map->x86_cr_type[x86r] = is_dreg; - map->x86_const_offset[x86r] = 0; - old_dirty |= map->x86_dirty[x86r]; - old_verified = map->x86_verified[x86r]; - old_bo = map->x86_byteorder[x86r]; - map->x86_verified[x86r] = 0; - map->x86_dirty[x86r] = 0; - x86r = newr; - /* ... and make the new one the cache register */ - map->x86_cache_reg[x86r] = reg; - map->x86_cr_type[x86r] = is_dreg; - map->x86_const_offset[x86r] = 0; - map->x86_dirty[x86r] = old_dirty; - map->x86_verified[x86r] = old_verified; - map->x86_byteorder[x86r] = old_bo; - regmap[reg] = x86r; } - map->x86_locked[x86r]++; - if (no_offset && map->x86_const_offset[x86r] != 0) { + if (no_offset && const_off != 0) { + if (map->x86_locked[x86r] != 0) + printf("modifying locked reg\n"); compile_force_byteorder(map, x86r, BO_NORMAL, 1); compile_lea_reg_with_offset(x86r, x86r, map->x86_const_offset[x86r]); map->x86_const_offset[x86r] = 0; map->x86_dirty[x86r] = 1; } + lock_reg(map, x86r, lock_type); return x86r; } /* - * Move a constant to a register. Don't anything if we already have a + * Move a constant to a register. Don't do anything if we already have a * register, even if it is offset by a constant */ static int compile_force_const_reg(struct register_mapping *map, int x86r, - ULONG *offs, int desired) + uae_u32 *offs, int desired) { int newr = x86r; @@ -1575,41 +1707,21 @@ static int compile_force_const_reg(struc assemble_ulong(*offs); *offs = 0; } - map->x86_locked[newr]++; + map->x86_users[newr]++; return newr; } -static int compile_extend_long(struct register_mapping *map, int x86r, - ULONG *srcoffs, wordsizes size) +static void compile_extend_long(struct register_mapping *map, int x86r, + wordsizes size) { + if (x86r < 0) { + printf("Bad reg in extend_long\n"); + return; + } + compile_force_byteorder(map, x86r, BO_NORMAL, 1); + if (size != sz_long) { - if (x86r == -2) { - ULONG offs = *srcoffs; - if (size == sz_byte) - offs = (LONG)(BYTE)offs; - else if (size == sz_word) - offs = (LONG)(WORD)offs; - *srcoffs = offs; - return x86r; - } else if (*srcoffs != 0) { - int newr = get_free_x86_register(map, ALL_X86_REGS); - compile_lea_reg_with_offset(newr, x86r, *srcoffs); - *srcoffs = 0; - x86r = newr; - } else if (map->x86_locked[x86r] != 0) { - int newr = get_free_x86_register(map, ALL_X86_REGS); - assemble(0x0F); - if (size == sz_byte) { - assemble(0xBE); - } else { - assemble(0xBF); - } - assemble(0xC0 + newr*8 + x86r); - x86r = newr; - goto extended; - } - if (x86r == r_EAX && size == sz_word) { assemble(0x98); /* cwtl */ } else { @@ -1622,52 +1734,35 @@ static int compile_extend_long(struct re assemble(0xC0 + x86r*9); } } - extended: - if (x86r >= 0) - map->x86_locked[x86r]++; - return x86r; } -/* - * Either move a constant into a register, or get rid of a constant offset - * for a register - */ +struct ea_info { + int reg; + amodes mode; + wordsizes size; + int address_reg; /* The x86 reg holding the address, or -1 if ea doesn't refer to memory + * -2 if it refers to memory, but only with a constant address */ + uae_u32 addr_const_off; /* Constant offset to the address */ + int data_reg; /* The x86 reg that holds the data. -1 if data is not present yet. + * -2 if data is constant */ + uae_u32 data_const_off; + int flags; /* Extra info. Contains the dp field of d8r modes */ + int purpose; +}; -static int compile_move_const_reg(struct register_mapping *map, int x86r, - ULONG *offs, int desired) +static void init_eainfo(struct ea_info *eai) { - int newr = x86r; - if (newr == -2) { - if (desired == 0) - newr = get_free_x86_register(map, ALL_X86_REGS); - else - newr = get_typed_x86_register(map, desired); - assemble(0xB8 + newr); - assemble_ulong(*offs); - } else { - compile_offset_reg(map, x86r, *offs); - } - *offs = 0; - map->x86_locked[newr]++; - return newr; + eai->address_reg = -1; + eai->addr_const_off = 0; + eai->data_reg = -1; + eai->data_const_off = 0; } -static int compile_move_to_modereg(struct register_mapping *map, int x86r, - wordsizes size) -{ - int newr = x86r; - - if (size == sz_byte && ((1 << x86r) & DATA_X86_REGS) == 0) { - newr = get_typed_x86_register(map, DATA_X86_REGS); - compile_force_byteorder(map, x86r, BO_NORMAL, 1); - if (((1 << newr) & DATA_X86_REGS) == 0) - printf("Can't get data register for byte value\n"); - assemble(0x89); - assemble(0xC0 + newr*8 + x86r); - } - map->x86_locked[newr]++; - return newr; -} +struct insn_reg_needs { + int checkpoint_no; + int dreg_needed[8], areg_needed[8]; + int dreg_mask[8], areg_mask[8]; +}; /* * This structure holds information about predec/postinc addressing modes. @@ -1678,10 +1773,10 @@ struct pid_undo { int x86r[2]; int m68kr[2]; int dirty[2]; - ULONG offs[2]; + int offs[2]; }; -static void add_undo(struct pid_undo *pud, int x86r, int m68kr, ULONG offs, +static void add_undo(struct pid_undo *pud, int x86r, int m68kr, int offs, int dirty) { int i; @@ -1695,29 +1790,39 @@ static void add_undo(struct pid_undo *pu pud->used++; } -struct ea_info { - int reg; - amodes mode; - wordsizes size; - int regs_locked; /* The regs locked for this ea by compile_prepareea() */ - int locked_regs[3]; - int address_reg; /* The x86 reg holding the address, or -1 if ea doesn't refer to memory - * -2 if it refers to memory, but only with a constant address */ - ULONG addr_const_off; /* Constant offset to the address */ - int flags; /* Extra info. Contains the dp field of d8r modes */ - int purpose; - int data_reg; /* The x86 reg that holds the data. -1 if data is not present yet. - * -2 if data is constant */ - ULONG data_const_off; -}; +/* + * Lock previous contents of address registers used in predec/postinc modes + * for generate_possible_exit(). + */ -static void init_eainfo(struct ea_info *eai) +static void compile_prepare_undo(struct register_mapping *map, amodes mode, + int reg, struct pid_undo *pud) { - eai->regs_locked = 0; - eai->address_reg = -1; - eai->addr_const_off = 0; - eai->data_reg = -1; - eai->data_const_off = 0; + int x86r; + + switch(mode){ + default: + break; + + case Apdi: + x86r = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0, 1); + /* This saves recording the byteorder in the pud structure, and we'll + * need it in normal byteorder anyway */ + compile_force_byteorder(map, x86r, BO_NORMAL, 0); + /* + * Add this reg with its current offset to the undo buffer. + * Since we have locked it, we are certain that it will not be + * modified. + */ + add_undo(pud, x86r, reg, map->x86_const_offset[x86r], map->x86_dirty[x86r]); + break; + + case Aipi: + x86r = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0, 1); + compile_force_byteorder(map, x86r, BO_NORMAL, 0); + add_undo(pud, x86r, reg, map->x86_const_offset[x86r], map->x86_dirty[x86r]); + break; + } } /* @@ -1727,203 +1832,138 @@ static void init_eainfo(struct ea_info * */ static void compile_prepareea(struct register_mapping *map, amodes mode, - int reg, wordsizes size, UBYTE **pcpp, CPTR pca, - struct ea_info *eai, int ea_purpose, - struct pid_undo *pud, int pidmult) + int reg, wordsizes size, uae_u8 **pcpp, uaecptr pca, + struct ea_info *eainf, int eaino, int ea_purpose, + int pidmult) { + struct ea_info *eai = eainf + eaino; int pdival = size == sz_byte && reg != 7 ? 1 : size == sz_long ? 4 : 2; - UBYTE *p = *pcpp; - UWORD dp; + uae_u8 *p = *pcpp; + uae_u16 dp; int r; int x86r, tmpr; pdival *= pidmult; - + init_eainfo(eai); eai->mode = mode; eai->size = size; eai->reg = reg; - + switch(mode){ case Dreg: - if (size != sz_long && (ea_purpose & EA_STORE)) - ea_purpose |= EA_LOAD; - /* Is the register in the cache, or do we need it there? If so, lock it. - * This will make sure we are the only ones who have it locked, so we - * can mess with it without expecting surprises. - * Get it without a constant offset. */ - x86r = map->dreg_map[reg]; - if (x86r != -1 || (ea_purpose & EA_LOAD)) { - eai->regs_locked = 1; - x86r = eai->locked_regs[0] = get_and_lock_68k_reg(map, reg, 1, 0, 1); - } - /* And if we need to manipulate it with byte sizes, we ought to get it - * into an appropriate register */ - if (size == sz_byte && x86r != -1 && (ea_purpose & (EA_LOAD|EA_STORE)) - && ((1 << x86r) & DATA_X86_REGS) == 0) - { - int newr = get_typed_x86_register(map, DATA_X86_REGS); - compile_force_byteorder(map, x86r, BO_NORMAL, 0); - compile_move_reg_reg(newr, x86r, sz_long); - map->x86_locked[newr]++; - compile_unlock_reg(map, x86r); - eai->locked_regs[0] = newr; - - /* We need to update the register cache, otherwise storeea - * will mark the new one dirty, but that is never checked. */ - map->x86_const_offset[newr] = map->x86_const_offset[x86r]; - map->x86_dirty[newr] = map->x86_dirty[x86r]; - map->x86_cache_reg[x86r] = -1; - map->x86_cache_reg[newr] = reg; - map->x86_cr_type[newr] = 1; - map->dreg_map[reg] = newr; - } - if (eai->regs_locked == 1) { - eai->data_reg = eai->locked_regs[0]; - eai->data_const_off = map->x86_const_offset[eai->data_reg]; - } - break; - case Areg: - if (size != sz_long && (ea_purpose & EA_STORE)) - printf("Areg != long\n"); - x86r = map->areg_map[reg]; - if (x86r != -1 || (ea_purpose & EA_LOAD)) { - eai->regs_locked = 1; - x86r = eai->locked_regs[0] = get_and_lock_68k_reg(map, reg, 0, 0, 1); - } - /* And if we need to get the byte part, we ought to get it - * into an appropriate register */ - if (size == sz_byte && x86r != -1 && (ea_purpose & EA_LOAD) - && ((1 << x86r) & DATA_X86_REGS) == 0) - { - int newr = get_typed_x86_register(map, DATA_X86_REGS); - compile_force_byteorder(map, x86r, BO_NORMAL, 0); - compile_move_reg_reg(newr, x86r, sz_long); - map->x86_locked[newr]++; - compile_unlock_reg(map, x86r); - eai->locked_regs[0] = newr; - } - if (eai->regs_locked == 1) { - eai->data_reg = eai->locked_regs[0]; - eai->data_const_off = map->x86_const_offset[eai->data_reg]; - } break; - + case Ad16: - eai->addr_const_off = (WORD)((*p << 8) | *(p+1)); + eai->addr_const_off = (uae_s16)do_get_mem_word((uae_u16 *)p); (*pcpp) += 2; p += 2; - x86r = eai->locked_regs[0] = eai->address_reg = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0); + x86r = eai->address_reg = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0, 1); compile_force_byteorder(map, x86r, BO_NORMAL, 0); eai->addr_const_off += map->x86_const_offset[x86r]; - eai->regs_locked = 1; break; case Aind: - x86r = eai->locked_regs[0] = eai->address_reg = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0); + x86r = eai->address_reg = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0, 1); compile_force_byteorder(map, x86r, BO_NORMAL, 0); eai->addr_const_off = map->x86_const_offset[x86r]; - eai->regs_locked = 1; break; - + case Apdi: - x86r = eai->locked_regs[0] = eai->address_reg = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0); + x86r = eai->address_reg = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0, 1); compile_force_byteorder(map, x86r, BO_NORMAL, 0); - /* - * Add this reg with its current offset to the undo buffer. - * Since we have locked it, we are certain that it will not be - * modified at least before generate_possible_exits() has done its - * job. - */ - add_undo(pud, x86r, reg, map->x86_const_offset[x86r], map->x86_dirty[x86r]); map->x86_const_offset[x86r] -= pdival; eai->addr_const_off = map->x86_const_offset[x86r]; - eai->regs_locked = 1; break; - + case Aipi: - x86r = eai->locked_regs[0] = eai->address_reg = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0); + x86r = eai->address_reg = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0, 1); compile_force_byteorder(map, x86r, BO_NORMAL, 0); - add_undo(pud, x86r, reg, map->x86_const_offset[x86r], map->x86_dirty[x86r]); eai->addr_const_off = map->x86_const_offset[x86r]; map->x86_const_offset[x86r] += pdival; - eai->regs_locked = 1; break; case Ad8r: - dp = (WORD)((*p << 8) | *(p+1)); + dp = (uae_s16)do_get_mem_word((uae_u16 *)p); r = (dp & 0x7000) >> 12; - (*pcpp) += 2; p += 2; - - tmpr = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0); - x86r = get_and_lock_68k_reg(map, r, dp & 0x8000 ? 0 : 1, 0, 1); - compile_force_byteorder(map, x86r, BO_NORMAL, 0); + (*pcpp) += 2; p += 2; + + tmpr = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0, 1); compile_force_byteorder(map, tmpr, BO_NORMAL, 0); - eai->locked_regs[0] = eai->address_reg = get_free_x86_register(map, ADDRESS_X86_REGS); - map->x86_locked[eai->address_reg]++; - - eai->addr_const_off = map->x86_const_offset[tmpr] + (BYTE)dp; + eai->addr_const_off = map->x86_const_offset[tmpr] + (uae_s8)dp; + + if (dp & 0x800) { + x86r = get_and_lock_68k_reg(map, r, dp & 0x8000 ? 0 : 1, ADDRESS_X86_REGS, 0, 2); + remove_x86r_from_cache(map, x86r, 0); + compile_force_byteorder(map, x86r, BO_NORMAL, 0); + eai->addr_const_off += map->x86_const_offset[x86r]; + } else { + x86r = get_and_lock_68k_reg(map, r, dp & 0x8000 ? 0 : 1, ADDRESS_X86_REGS, 1, 2); + remove_x86r_from_cache(map, x86r, 0); + compile_force_byteorder(map, x86r, BO_NORMAL, 0); + } + eai->address_reg = x86r; + r = (dp & 0x7000) >> 12; if (dp & 0x800) { - if ((LONG)eai->addr_const_off >= -128 && (LONG)eai->addr_const_off <= 127) { - assemble(0x8D); - assemble(0x44 + eai->address_reg*8); /* leal disp8(dispreg,basereg),addrreg */ + if (eai->addr_const_off == 0) { + assemble(0x03); assemble(0xC0 + tmpr + x86r*8); /* addl basereg,addrreg */ + } else if ((uae_s32)eai->addr_const_off >= -128 && (uae_s32)eai->addr_const_off <= 127) { + assemble(0x8D); + assemble(0x44 + x86r*8); /* leal disp8(dispreg,basereg),dispreg */ assemble(x86r*8 + tmpr); assemble(eai->addr_const_off); } else { assemble(0x8D); - assemble(0x84 + eai->address_reg*8); /* leal disp32(dispreg,basereg),addrreg */ + assemble(0x84 + x86r*8); /* leal disp32(dispreg,basereg),dispreg */ assemble(x86r*8 + tmpr); assemble_ulong(eai->addr_const_off); } eai->addr_const_off = 0; } else { assemble(0x0F); assemble(0xBF); - assemble(0xC0 + x86r + eai->address_reg*8); /* movswl dispreg,addrreg */ - assemble(0x03); assemble(0xC0 + tmpr + eai->address_reg*8); /* addl basereg,addrreg */ + assemble(0xC0 + x86r*9); /* movswl dispreg,addrreg */ + assemble(0x03); assemble(0xC0 + tmpr + x86r*8); /* addl basereg,addrreg */ } - compile_unlock_reg(map, x86r); compile_unlock_reg(map, tmpr); - eai->regs_locked = 1; break; case PC8r: - dp = (WORD)((*p << 8) | *(p+1)); + dp = (uae_s16)do_get_mem_word((uae_u16 *)p); (*pcpp) += 2; p += 2; r = (dp & 0x7000) >> 12; - eai->addr_const_off = pca + (BYTE)dp; + eai->addr_const_off = pca + (uae_s8)dp; if (dp & 0x800) { - eai->locked_regs[0] = eai->address_reg = get_and_lock_68k_reg(map, r, dp & 0x8000 ? 0 : 1, 0, 1); + x86r = get_and_lock_68k_reg(map, r, dp & 0x8000 ? 0 : 1, ADDRESS_X86_REGS, 0, 1); + remove_x86r_from_cache(map, x86r, 0); + compile_force_byteorder(map, x86r, BO_NORMAL, 0); + eai->addr_const_off += map->x86_const_offset[x86r]; } else { - eai->regs_locked = 2; - tmpr = get_and_lock_68k_reg(map, r, dp & 0x8000 ? 0 : 1, 0, 1); - compile_force_byteorder(map, tmpr, BO_NORMAL, 0); - eai->locked_regs[0] = eai->address_reg = get_free_x86_register(map, ADDRESS_X86_REGS); - map->x86_locked[eai->address_reg]++; + x86r = get_and_lock_68k_reg(map, r, dp & 0x8000 ? 0 : 1, ADDRESS_X86_REGS, 1, 2); + remove_x86r_from_cache(map, x86r, 0); + compile_force_byteorder(map, x86r, BO_NORMAL, 0); assemble(0x0F); assemble(0xBF); - assemble(0xC0 + tmpr + eai->address_reg*8); /* movswl dispreg,addrreg */ - compile_unlock_reg(map, tmpr); + assemble(0xC0 + x86r*9); /* movswl dispreg,addrreg */ } - eai->regs_locked = 1; + eai->address_reg = x86r; break; - + case PC16: - eai->addr_const_off = pca + (WORD)((*p << 8) | *(p+1)); + eai->addr_const_off = pca + (uae_s16)do_get_mem_word((uae_u16 *)p); eai->address_reg = -2; (*pcpp) += 2; p += 2; break; - + case absw: - eai->addr_const_off = (WORD)((*p << 8) | *(p+1)); + eai->addr_const_off = (uae_s16)do_get_mem_word((uae_u16 *)p); eai->address_reg = -2; (*pcpp) += 2; p += 2; break; case absl: - eai->addr_const_off = (LONG)((*p << 24) | (*(p+1) << 16) - | (*(p+2) << 8) | *(p+3)); + eai->addr_const_off = (uae_s32)do_get_mem_long((uae_u32 *)p); eai->address_reg = -2; (*pcpp) += 4; p += 4; break; @@ -1933,31 +1973,30 @@ static void compile_prepareea(struct reg goto imm2_const; if (size == sz_word) goto imm1_const; - + /* fall through */ case imm0: - eai->data_const_off = (BYTE)*(p+1); + eai->data_const_off = (uae_s8)*(p+1); eai->data_reg = -2; (*pcpp) += 2; p += 2; break; case imm1: imm1_const: - eai->data_const_off = (WORD)((*p << 8) | *(p+1)); + eai->data_const_off = (uae_s16)do_get_mem_word((uae_u16 *)p); eai->data_reg = -2; (*pcpp) += 2; p += 2; break; case imm2: imm2_const: - eai->data_const_off = (LONG)((*p << 24) | (*(p+1) << 16) - | (*(p+2) << 8) | *(p+3)); + eai->data_const_off = (uae_s32)do_get_mem_long((uae_u32 *)p); eai->data_reg = -2; (*pcpp) += 4; p += 4; break; case immi: - eai->data_const_off = (BYTE)reg; + eai->data_const_off = (uae_s8)reg; eai->data_reg = -2; break; @@ -1967,184 +2006,763 @@ static void compile_prepareea(struct reg eai->purpose = ea_purpose; } -static int compile_fetchea(struct register_mapping *map, struct ea_info *eai, - ULONG *reg_offset) +static void compile_get_excl_lock(struct register_mapping *map, struct ea_info *eai) { - int x86r; - ULONG constant; - - if (eai->data_reg != -1) { - *reg_offset = eai->data_const_off; - return eai->data_reg; - } - - if (eai->mode == Dreg || eai->mode == Areg || eai->mode == immi || eai->mode == imm - || eai->mode == imm0 || eai->mode == imm1 || eai->mode == imm2 - || eai->address_reg == -1) - printf("BUG\n"); + int x86r = eai->data_reg; + + if (x86r >= 0 && map->x86_locked[x86r] == 1) { + int newr; + if (eai->size == sz_byte) + newr = get_typed_x86_register(map, DATA_X86_REGS); + else + newr = get_free_x86_register(map, ALL_X86_REGS); + + compile_move_reg_reg(newr, x86r, sz_long); + eai->data_reg = newr; + lock_reg(map, eai->data_reg, 2); + } +} + +/* + * Some functions to assemble some 386 opcodes which have a similar + * structure (ADD, AND, OR, etc.). These take source and destination + * addressing modes, check their validity and assemble a complete + * 386 instruction. + */ + +STATIC_INLINE int rmop_long(struct ea_info *eai) +{ + if (eai->data_reg == -2) + printf("rmop for const\n"); + else if (eai->data_reg == -1) { + if (eai->address_reg == -2) + return 5; + if (eai->address_reg == -1) { + /* This must be a 68k register in its home location */ + return 5; + } +#if 0 /* We need to add address_space... */ + if (eai->addr_const_off == 0 && eai->address_reg != r_EBP) { + return eai->address_reg; + } + else if ((uae_s32)eai->addr_const_off >= -128 && (uae_s32)eai->addr_const_off <= 127) { + return eai->address_reg | 0x40; + } +#endif + return eai->address_reg | 0x80; + } else { + if (eai->size == sz_byte && ((1 << eai->data_reg) & DATA_X86_REGS) == 0) + printf("wrong type reg in rmop\n"); + if (eai->data_const_off != 0) + printf("data_const_off in rmop\n"); + return 0xC0 + eai->data_reg; + } + return 0; +} + +STATIC_INLINE int rmop_short(struct ea_info *eai) +{ + if (eai->data_reg == -2) + printf("rmop_short for const\n"); + else if (eai->data_reg == -1) { + printf("rmop_short for mem\n"); + } else { + if (eai->size == sz_byte && ((1 << eai->data_reg) & DATA_X86_REGS) == 0) + printf("wrong type reg in rmop_short\n"); + if (eai->data_const_off != 0) + printf("data_const_off in rmop_short\n"); + return eai->data_reg*8; + } + return 0; +} + +STATIC_INLINE void rmop_finalize(struct ea_info *eai) +{ + if (eai->data_reg == -2) + assemble_ulong(eai->data_const_off); + else if (eai->data_reg == -1) { + if (eai->address_reg == -2) + /* Constant address */ + assemble_long(address_space + (uae_s32)eai->addr_const_off); + else if (eai->address_reg == -1) { + /* Register in its home location */ + if (eai->mode == Areg) + assemble_long(regs.regs + 8 + eai->reg); + else + assemble_long(regs.regs + eai->reg); + } else { +#if 0 + /* Indirect address with offset */ + if ((uae_s32)eai->addr_const_off >= -128 && (uae_s32)eai->addr_const_off <= 127) { + } +#endif + assemble_long(address_space + (uae_s32)eai->addr_const_off); + } + } +} + +static void compile_eas(struct register_mapping *map, struct ea_info *eainf, int eaino_s, int eaino_d, + int optype) +{ + struct ea_info *eais = eainf + eaino_s; + struct ea_info *eaid = eainf + eaino_d; + int szflag = eais->size == sz_byte ? 0 : 1; + int swapflag = 0; + int opcode; - *reg_offset = 0; + if (eais->data_reg == -1) { + compile_force_byteorder(map, eais->address_reg, BO_NORMAL, 0); + eais = eainf + eaino_d; + eaid = eainf + eaino_s; + swapflag = 1; + } + if (eais->data_reg == -1) { + compile_force_byteorder(map, eais->address_reg, BO_NORMAL, 0); + } + + if (eais->size == sz_word) + assemble(0x66); + + if (eais->data_reg == -2) { + assemble(0x80+szflag); + assemble(8*optype | rmop_long(eaid)); + rmop_finalize(eaid); + switch(eais->size) { + case sz_byte: assemble(eais->data_const_off); break; + case sz_word: assemble_uword(eais->data_const_off); break; + case sz_long: assemble_ulong(eais->data_const_off); break; + } + } else { + assemble(8*optype | szflag | 2*swapflag); + assemble(rmop_long(eaid) | rmop_short(eais)); + rmop_finalize(eaid); + } +} + +static void compile_fetchmem(struct register_mapping *map, struct ea_info *eai) +{ + int x86r; if (eai->size == sz_byte) x86r = get_typed_x86_register(map, DATA_X86_REGS); else x86r = get_free_x86_register(map, ALL_X86_REGS); - map->x86_locked[x86r]++; + lock_reg(map, x86r, 2); compile_force_byteorder(map, eai->address_reg, BO_NORMAL, 0); - compile_move_reg_from_mem_regoffs(x86r, eai->address_reg, - (ULONG)(eai->addr_const_off + address_space), + compile_move_reg_from_mem_regoffs(x86r, eai->address_reg, + (uae_u32)(eai->addr_const_off + address_space), eai->size); - + map->x86_verified[x86r] = 0; switch (eai->size) { case sz_byte: map->x86_byteorder[x86r] = BO_NORMAL; break; case sz_word: map->x86_byteorder[x86r] = BO_SWAPPED_WORD; break; case sz_long: map->x86_byteorder[x86r] = BO_SWAPPED_LONG; break; } - return x86r; + eai->data_reg = x86r; + eai->data_const_off = 0; } -static void compile_storeea(struct register_mapping *map, struct ea_info *eai, - int valuereg, ULONG valueoffset) +static void compile_fetchimm(struct register_mapping *map, struct ea_info *eai, int byteorder) { - ULONG constant; - int newr, cacher; - - if (eai->mode == Dreg) { - /* Easy case first: just put the reg in the register cache */ - if (eai->size == sz_long) { - newr = compile_move_const_reg(map, valuereg, &valueoffset, 0); - compile_unlock_reg(map, valuereg); - if (valueoffset != 0) - printf("Hoppla?\n"); - /* - * Two checks whether registers are already in the cache. + int x86r; + if (eai->size == sz_byte) + x86r = get_typed_x86_register(map, DATA_X86_REGS); + else + x86r = get_free_x86_register(map, ALL_X86_REGS); + + switch (byteorder) { + case BO_SWAPPED_LONG: + eai->data_const_off = (((eai->data_const_off & 0xFF000000) >> 24) + | ((eai->data_const_off & 0xFF0000) >> 8) + | ((eai->data_const_off & 0xFF00) << 8) + | ((eai->data_const_off & 0xFF) << 24)); + break; + case BO_SWAPPED_WORD: + eai->data_const_off = (((eai->data_const_off & 0xFF00) >> 8) + | ((eai->data_const_off & 0xFF) << 8) + | (eai->data_const_off & 0xFFFF0000)); + break; + case BO_NORMAL: + break; + } + lock_reg(map, x86r, 2); + map->x86_byteorder[x86r] = byteorder; map->x86_verified[x86r] = 0; + + switch (eai->size) { + case sz_byte: assemble(0xC6); assemble(0xC0 + x86r); assemble(eai->data_const_off); break; + case sz_word: assemble(0x66); assemble(0xC7); assemble(0xC0 + x86r); assemble_uword(eai->data_const_off); break; + case sz_long: assemble(0xC7); assemble(0xC0 + x86r); assemble_ulong(eai->data_const_off); break; + } + eai->data_reg = x86r; + eai->data_const_off = 0; +} + +/* + * 1: reg + * 2: mem + * 4: imm + */ + +static int binop_alternatives[] = { + 7, 1, + 5, 3, + 0, 0 +}; + +static int binop_worda_alternatives[] = { + 1, 3, + 0, 0 +}; + +static int regonly_alternatives[] = { + 1, 1, + 0, 0 +}; + +static void compile_loadeas(struct register_mapping *map, struct ea_info *eainf, + int eaino_s, int eaino_d, int *alternatives, + int scramble_poss, int load_dest) +{ + struct ea_info *eais = eainf + eaino_s; + struct ea_info *eaid = eainf + eaino_d; + int scrambled_bo = eaid->size == sz_long ? BO_SWAPPED_LONG : eaid->size == sz_word ? BO_SWAPPED_WORD : BO_NORMAL; + int i, scrambled = 0; + int best = 0; + int bestcost = -1; + int *ap; + uae_u32 *sregp = NULL, *dregp = NULL; + int screg = -1, dcreg = -1; + int stype = -1, dtype = -1; + int asrc, adst; + int regprefs = eais->size == sz_byte ? DATA_X86_REGS : 0; + + if (eais->mode == Dreg) { + stype = 0; + screg = map->dreg_map[eais->reg]; + if (screg == -1) + sregp = regs.regs + eais->reg; + } else if (eais->mode == Areg) { + stype = 0; + screg = map->areg_map[eais->reg]; + if (screg == -1) + sregp = regs.regs + 8 + eais->reg; + } else if (eais->data_reg == -2) { + stype = -2; + } + + if (eaid->mode == Dreg) { + dtype = 0; + dcreg = map->dreg_map[eaid->reg]; + if (dcreg == -1) + dregp = regs.regs + eaid->reg; + } else if (eaid->mode == Areg) { + dtype = 0; + dcreg = map->areg_map[eaid->reg]; + if (dcreg == -1) + dregp = regs.regs + 8 + eaid->reg; + } else if (eaid->data_reg == -2) { + dtype = -2; + } + + ap = alternatives; + + for (i = 0;; i++) { + int cost = 0; + + asrc = *ap++; + if (asrc == 0) + break; + adst = *ap++; + + if (stype == -2 && (asrc & 4) == 0) + cost++; + else if (stype == -1 && ((asrc & 2) == 0 || (eais->size != sz_byte && !scramble_poss))) + cost++; + else if (stype == 0 && screg == -1 && (asrc & 2) == 0) + cost++; + + if (dtype == -1 && ((adst & 2) == 0 || (eaid->size != sz_byte && !scramble_poss))) + /* The !load_dest case isn't handled by the current code, + * and it isn't desirable anyway. Use a different alternative */ - if (map->x86_cache_reg[newr] != -1 - && (map->x86_cache_reg[newr] != eai->reg - || map->x86_cr_type[newr] != 1)) - { - remove_x86r_from_cache(map, newr, 0); + cost += load_dest ? 1 : 100; + else if (dtype == 0 && dcreg == -1 && (adst & 2) == 0) + cost++; + + if (bestcost == -1 || cost < bestcost) { + bestcost = cost; + best = i; + } + } + + asrc = alternatives[2*best]; + adst = alternatives[2*best+1]; + + if (dtype == -1) { + if (load_dest) { + if ((adst & 2) == 0 || (eaid->size != sz_byte && !scramble_poss)) + compile_fetchmem(map, eaid); + } else { + if ((adst & 2) == 0) { + printf("Not loading memory operand. Prepare to die.\n"); + if (eaid->size == sz_byte) + eaid->data_reg = get_typed_x86_register(map, DATA_X86_REGS); + else + eaid->data_reg = get_free_x86_register(map, ALL_X86_REGS); } - if (map->dreg_map[eai->reg] != -1 - && map->dreg_map[eai->reg] != newr) - { - /* No need to write back */ - map->x86_cache_reg[map->dreg_map[eai->reg]] = -1; + } + /* Scrambled in both mem and reg cases */ + if (eaid->size != sz_byte && scramble_poss) + scrambled = 1; + } else { + if (dcreg == -1 && !load_dest && (adst & 2) == 0 && eaid->size == sz_long) { + /* We need a register, but we don't need to fetch the old data. + * See storeea for some more code handling this case. This first + * if statement could be eliminated, we would generate some + * superfluous moves. This is an optimization. If it were not + * done, the mem-mem-move warning could be commented in in + * storeea. */ + if (eaid->size == sz_byte) + eaid->data_reg = get_typed_x86_register(map, DATA_X86_REGS); + else + eaid->data_reg = get_free_x86_register(map, ALL_X86_REGS); + eaid->data_const_off = 0; + } else if ((dcreg == -1 && (adst & 2) == 0) || dcreg != -1) { + int reg_bo; + eaid->data_reg = get_and_lock_68k_reg(map, eaid->reg, eaid->mode == Dreg, regprefs, 1, 2); + eaid->data_const_off = 0; + + reg_bo = map->x86_byteorder[eaid->data_reg]; + + if (reg_bo != BO_NORMAL) { + if (reg_bo != scrambled_bo) + compile_force_byteorder(map, eaid->data_reg, BO_NORMAL, 0); + else if (scramble_poss) + scrambled = 1; } - map->x86_cache_reg[newr] = eai->reg; - map->x86_cr_type[newr] = 1; - map->x86_const_offset[newr] = valueoffset; - map->x86_dirty[newr] = 1; - map->dreg_map[eai->reg] = newr; - map->x86_verified[newr] = 0; - return; } - - if (eai->data_reg < 0) - printf("Don't have a data reg to move to!\n"); - - compile_force_byteorder(map, eai->data_reg, BO_NORMAL, 1); - compile_force_byteorder(map, valuereg, BO_NORMAL, 1); - map->x86_verified[eai->data_reg] = 0; - if (valuereg == -2) { - if (eai->size == sz_byte) { - if (((1 << eai->data_reg) & DATA_X86_REGS) == 0) - printf("Uhoh - not moving to proper type reg\n"); - assemble(0xB0 + eai->data_reg); - assemble(valueoffset); - } else { - assemble(0x66); assemble(0xB8 + eai->data_reg); - assemble_uword(valueoffset); + } + + if (stype == -2) { + /* @@@ may need to scramble imm, this is a workaround */ + if ((asrc & 4) == 0 || scrambled) + compile_fetchimm(map, eais, scrambled ? scrambled_bo : BO_NORMAL); + } else if (stype == -1) { + if ((asrc & 2) == 0 || (eais->size != sz_byte && !scrambled)) + compile_fetchmem(map, eais); + } else { + if ((screg == -1 && (asrc & 2) == 0) || screg != -1) { + eais->data_reg = get_and_lock_68k_reg(map, eais->reg, eais->mode == Dreg, regprefs, 1, 2); + eais->data_const_off = 0; + } + } + + /* Optimization */ + if (scrambled && eais->data_reg >= 0 && !load_dest + && map->x86_byteorder[eais->data_reg] == BO_NORMAL + && eaid->size == sz_long && dtype == 0) + scrambled = 0; + + if (regprefs != 0 && eais->data_reg >= 0 && ((1 << eais->data_reg) & regprefs) == 0) { + int tmpr = get_typed_x86_register(map, regprefs); + compile_move_reg_reg(tmpr, eais->data_reg, sz_long); + eais->data_reg = tmpr; + } + + if (regprefs != 0 && eaid->data_reg >= 0 && ((1 << eaid->data_reg) & regprefs) == 0) { + int tmpr = get_typed_x86_register(map, regprefs); + compile_move_reg_reg(tmpr, eaid->data_reg, sz_long); + eaid->data_reg = tmpr; + } + + /* Now set the byteorder once and for all (should already be correct for + * most cases) */ + if (scrambled) { + if (eaid->data_reg >= 0) + compile_force_byteorder(map, eaid->data_reg, scrambled_bo, 0); + if (eais->data_reg >= 0) + compile_force_byteorder(map, eais->data_reg, scrambled_bo, 0); + } else { + if (eaid->data_reg >= 0) + compile_force_byteorder(map, eaid->data_reg, BO_NORMAL, 0); + if (eais->data_reg >= 0) + compile_force_byteorder(map, eais->data_reg, BO_NORMAL, 0); + } +} + +static void compile_fetchea(struct register_mapping *map, struct ea_info *eainf, + int eaino, int asrc) +{ + struct ea_info *eais = eainf + eaino; + int scrambled_bo = eais->size == sz_long ? BO_SWAPPED_LONG : eais->size == sz_word ? BO_SWAPPED_WORD : BO_NORMAL; + int i, scrambled = 0; + int best = 0; + int bestcost = -1; + int *ap; + uae_u32 *sregp = NULL; + int screg = -1, stype = -1; + int regprefs = eais->size == sz_byte ? DATA_X86_REGS : 0; + + if (eais->mode == Dreg) { + stype = 0; + screg = map->dreg_map[eais->reg]; + if (screg == -1) + sregp = regs.regs + eais->reg; + } else if (eais->mode == Areg) { + stype = 0; + screg = map->areg_map[eais->reg]; + if (screg == -1) + sregp = regs.regs + 8 + eais->reg; + } else if (eais->data_reg == -2) { + stype = -2; + } + + if (stype == -2) { + if ((asrc & 4) == 0) + compile_fetchimm(map, eais, scrambled ? scrambled_bo : BO_NORMAL); + } else if (stype == -1) { + if ((asrc & 2) == 0 || eais->size != sz_byte) + compile_fetchmem(map, eais); + } else { + if ((screg == -1 && (asrc & 2) == 0) || screg != -1) { + eais->data_reg = get_and_lock_68k_reg(map, eais->reg, eais->mode == Dreg, regprefs, 1, 2); + eais->data_const_off = 0; + } + } + + if (eais->data_reg >= 0) + compile_force_byteorder(map, eais->data_reg, BO_NORMAL, 0); +} + +/* + * compile_note_modify() should be called on destination EAs obtained from + * compile_loadeas(), if their value was modified (e.g. by the compile_eas() + * function) + */ + +static void compile_note_modify(struct register_mapping *map, struct ea_info *eainf, + int eaino) +{ + struct ea_info *eai = eainf + eaino; + int newr; + int szflag = eai->size == sz_byte ? 0 : 1; + + if (eai->mode == Dreg) { + /* We only need to do something if we have the value in a register, + * otherwise, the home location was modified already */ + if (eai->data_reg >= 0) { + if (eai->data_reg != map->dreg_map[eai->reg]) { + remove_x86r_from_cache(map, eai->data_reg, 0); + if (map->dreg_map[eai->reg] >= 0) + remove_x86r_from_cache(map, map->dreg_map[eai->reg], 0); + map->x86_cache_reg[eai->data_reg] = eai->reg; + map->x86_cr_type[eai->data_reg] = 1; + map->dreg_map[eai->reg] = eai->data_reg; } - } else { - /* Move the subword into the right place */ -/* This shouldn't be necessary */ -#if 0 - newr = compile_force_const_reg(map, valuereg, &valueoffset); -#else - newr = valuereg; -#endif - compile_unlock_reg(map, valuereg); - compile_move_reg_reg(eai->data_reg, newr, eai->size); + map->x86_verified[eai->data_reg] = 0; + map->x86_const_offset[eai->data_reg] = eai->data_const_off; + map->x86_dirty[eai->data_reg] = 1; } - map->x86_dirty[eai->data_reg] = 1; return; } else if (eai->mode == Areg) { if (eai->size != sz_long) printf("Areg put != long\n"); - newr = compile_force_const_reg(map, valuereg, &valueoffset, 0); - compile_unlock_reg(map, valuereg); + /* We only need to do something if we have the value in a register, + * otherwise, the home location was modified already */ + if (eai->data_reg >= 0) { + if (eai->data_reg != map->areg_map[eai->reg]) { + remove_x86r_from_cache(map, eai->data_reg, 0); + if (map->areg_map[eai->reg] >= 0) + remove_x86r_from_cache(map, map->areg_map[eai->reg], 0); + map->x86_cache_reg[eai->data_reg] = eai->reg; + map->x86_cr_type[eai->data_reg] = 0; + map->areg_map[eai->reg] = eai->data_reg; + } + map->x86_verified[eai->data_reg] = 0; + map->x86_const_offset[eai->data_reg] = eai->data_const_off; + map->x86_dirty[eai->data_reg] = 1; + } + return; + } else { + /* Storing to memory from reg? */ + if (eai->data_reg >= 0) { + compile_offset_reg(map, eai->data_reg, eai->data_const_off); + + switch (eai->size) { + case sz_byte: compile_force_byteorder(map, eai->data_reg, BO_NORMAL, 1); break; + case sz_word: compile_force_byteorder(map, eai->data_reg, BO_SWAPPED_WORD, 1); break; + case sz_long: compile_force_byteorder(map, eai->data_reg, BO_SWAPPED_LONG, 1); break; + } + compile_force_byteorder(map, eai->address_reg, BO_NORMAL, 0); + compile_move_reg_to_mem_regoffs(eai->address_reg, + (uae_u32)(eai->addr_const_off + address_space), + eai->data_reg, eai->size); + } + } +} - if (map->x86_cache_reg[newr] != -1 - && (map->x86_cache_reg[newr] != eai->reg - || map->x86_cr_type[newr] != 0)) - { - remove_x86r_from_cache(map, newr, 0); +static void compile_storeea(struct register_mapping *map, struct ea_info *eainf, + int eaino_s, int eaino_d) +{ + struct ea_info *eais = eainf + eaino_s; + struct ea_info *eaid = eainf + eaino_d; + int newr, cacher; + int szflag = eaid->size == sz_byte ? 0 : 1; + + if (eaid->mode == Dreg) { + /* Is the reg to move from already the register cache reg for the + * destination? */ + if (eais->data_reg >= 0 && eais->data_reg == map->dreg_map[eaid->reg]) { + map->x86_dirty[eais->data_reg] = 1; map->x86_verified[eais->data_reg] = 0; + map->x86_const_offset[eais->data_reg] = eais->data_const_off; + return; } - if (map->areg_map[eai->reg] != -1 - && map->areg_map[eai->reg] != newr) - { - /* No need to write back */ - map->x86_cache_reg[map->areg_map[eai->reg]] = -1; + /* Is the destination register in its home location? */ + if (map->dreg_map[eaid->reg] < 0) { + if (eais->data_reg == -2) { + /* Move immediate to regs.regs */ + if (eaid->size == sz_word) assemble(0x66); + assemble(0xC6 + szflag); assemble(0x05); assemble_long(regs.regs + eaid->reg); + switch (eaid->size) { + case sz_byte: assemble(eais->data_const_off); break; + case sz_word: assemble_uword(eais->data_const_off); break; + case sz_long: assemble_ulong(eais->data_const_off); break; + } + } else if (eais->data_reg == -1) { +#if 0 + printf("Shouldn't happen (mem-mem-move)\n"); +#endif + /* This _can_ happen: move.l $4,d0, if d0 isn't in the + * cache, will come here. But a reg will be allocated for + * dest. We use this. This _really_ shouldn't happen if + * the size isn't long. */ + if (eaid->size != sz_long) + printf("_Really_ shouldn't happen (Dreg case)\n"); + map->x86_cache_reg[eaid->data_reg] = eaid->reg; + map->x86_cr_type[eaid->data_reg] = 1; + map->x86_const_offset[eaid->data_reg] = eaid->data_const_off; + map->dreg_map[eaid->reg] = eaid->data_reg; + map->x86_verified[eaid->data_reg] = 0; + goto have_cache_reg_d; + } else { + if (eais->size == sz_long) { + /* Make this the new register cache reg */ + remove_x86r_from_cache(map, eais->data_reg, 0); + map->x86_cache_reg[eais->data_reg] = eaid->reg; + map->x86_cr_type[eais->data_reg] = 1; + map->x86_const_offset[eais->data_reg] = eais->data_const_off; + map->dreg_map[eaid->reg] = eais->data_reg; + map->x86_verified[eais->data_reg] = 0; + } else { + /* Move from reg to regs.regs */ + compile_force_byteorder(map, eais->data_reg, BO_NORMAL, 1); + compile_offset_reg (map, eais->data_reg, eais->data_const_off); + if (eaid->size == sz_word) assemble(0x66); + assemble(0x88 + szflag); assemble(0x05 + 8*eais->data_reg); + assemble_long(regs.regs + eaid->reg); + } + } + } else { + int destr; + + have_cache_reg_d: + + destr = map->dreg_map[eaid->reg]; + if (eaid->size != sz_long) + compile_force_byteorder(map, destr, BO_NORMAL, 1); + + if (eais->data_reg == -2) { + /* Move immediate to reg */ + if (eaid->size == sz_word) assemble(0x66); + assemble(0xC6 + szflag); assemble(0xC0 + destr); + switch (eaid->size) { + case sz_byte: assemble(eais->data_const_off); break; + case sz_word: assemble_uword(eais->data_const_off); break; + case sz_long: assemble_ulong(eais->data_const_off); break; + } + /* normal byteorder comes either from force above or from long + * const move */ + map->x86_byteorder[destr] = BO_NORMAL; + } else if (eais->data_reg == -1) { + if (eais->mode == Dreg) { + compile_move_reg_from_mem_regoffs(destr, -2, (uae_u32)(regs.regs + eais->reg), + eais->size); + map->x86_byteorder[destr] = BO_NORMAL; + } else if (eais->mode == Areg) { + compile_move_reg_from_mem_regoffs(destr, -2, (uae_u32)(regs.regs + 8 + eais->reg), + eais->size); + map->x86_byteorder[destr] = BO_NORMAL; + } else { + /* Move mem to reg */ + compile_force_byteorder(map, eais->address_reg, BO_NORMAL, 0); + compile_move_reg_from_mem_regoffs(destr, eais->address_reg, + (uae_u32)(eais->addr_const_off + address_space), + eais->size); + + switch (eais->size) { + case sz_byte: map->x86_byteorder[destr] = BO_NORMAL; break; + case sz_word: map->x86_byteorder[destr] = BO_SWAPPED_WORD; break; + case sz_long: map->x86_byteorder[destr] = BO_SWAPPED_LONG; break; + } + } + } else { + if (eais->size == sz_long) { + /* Make this the new register cache reg */ + remove_x86r_from_cache(map, eais->data_reg, 0); + remove_x86r_from_cache(map, destr, 0); + map->x86_cache_reg[eais->data_reg] = eaid->reg; + map->x86_cr_type[eais->data_reg] = 1; + map->x86_const_offset[eais->data_reg] = eais->data_const_off; + map->dreg_map[eaid->reg] = eais->data_reg; + map->x86_verified[eais->data_reg] = 0; + } else { + /* Move from reg to reg */ + compile_force_byteorder(map, eais->data_reg, BO_NORMAL, 1); + compile_offset_reg (map, eais->data_reg, eais->data_const_off); + if (eaid->size == sz_word) assemble(0x66); + assemble(0x88 + szflag); assemble(0xC0 + destr + 8*eais->data_reg); + } + } } - map->x86_verified[newr] = 0; - map->x86_cache_reg[newr] = eai->reg; - map->x86_cr_type[newr] = 0; - map->x86_const_offset[newr] = valueoffset; - map->x86_dirty[newr] = 1; - map->areg_map[eai->reg] = newr; + + if (map->dreg_map[eaid->reg] >= 0) + map->x86_dirty[map->dreg_map[eaid->reg]] = 1; + return; + } else if (eaid->mode == Areg) { + if (eaid->size != sz_long) + printf("Areg put != long\n"); + + /* Is the reg to move from already the register cache reg for the + * destination? */ + if (eais->data_reg >= 0 && eais->data_reg == map->areg_map[eaid->reg]) { + map->x86_dirty[eais->data_reg] = 1; map->x86_verified[eais->data_reg] = 0; + map->x86_const_offset[eais->data_reg] = eais->data_const_off; + return; + } + /* Is the destination register in its home location? */ + if (map->areg_map[eaid->reg] < 0) { + if (eais->data_reg == -2) { + /* Move immediate to regs.regs */ + assemble(0xC7); assemble(0x05); assemble_long(regs.regs + 8 + eaid->reg); + assemble_ulong(eais->data_const_off); + } else if (eais->data_reg == -1) { +#if 0 /* see above... */ + printf("Shouldn't happen (mem-mem-move)\n"); +#endif + map->x86_cache_reg[eaid->data_reg] = eaid->reg; + map->x86_cr_type[eaid->data_reg] = 0; + map->x86_const_offset[eaid->data_reg] = eaid->data_const_off; + map->areg_map[eaid->reg] = eaid->data_reg; + map->x86_verified[eaid->data_reg] = 0; + goto have_cache_reg_a; + } else { + /* Make this the new register cache reg */ + remove_x86r_from_cache(map, eais->data_reg, 0); + map->x86_cache_reg[eais->data_reg] = eaid->reg; + map->x86_cr_type[eais->data_reg] = 0; + map->x86_const_offset[eais->data_reg] = eais->data_const_off; + map->areg_map[eaid->reg] = eais->data_reg; + map->x86_verified[eais->data_reg] = 0; + } + } else { + int destr; + + have_cache_reg_a: + + destr = map->areg_map[eaid->reg]; + if (eaid->size != sz_long) + compile_force_byteorder(map, destr, BO_NORMAL, 1); + + if (eais->data_reg == -2) { + /* Move immediate to reg */ + assemble(0xC7); assemble(0xC0 + destr); + assemble_ulong(eais->data_const_off); + + /* normal byteorder comes either from force above or from long + * const move */ + map->x86_byteorder[destr] = BO_NORMAL; + } else if (eais->data_reg == -1) { + if (eais->mode == Dreg) { + compile_move_reg_from_mem_regoffs(destr, -2, (uae_u32)(regs.regs + eais->reg), + eais->size); + map->x86_byteorder[destr] = BO_NORMAL; + } else if (eais->mode == Areg) { + compile_move_reg_from_mem_regoffs(destr, -2, (uae_u32)(regs.regs + 8 + eais->reg), + eais->size); + map->x86_byteorder[destr] = BO_NORMAL; + } else { + /* Move mem to reg */ + compile_force_byteorder(map, eais->address_reg, BO_NORMAL, 0); + compile_move_reg_from_mem_regoffs(destr, eais->address_reg, + (uae_u32)(eais->addr_const_off + address_space), + eais->size); + + map->x86_byteorder[destr] = BO_SWAPPED_LONG; + } + } else { + /* Make this the new register cache reg */ + remove_x86r_from_cache(map, eais->data_reg, 0); + remove_x86r_from_cache(map, destr, 0); + map->x86_cache_reg[eais->data_reg] = eaid->reg; + map->x86_cr_type[eais->data_reg] = 0; + map->x86_const_offset[eais->data_reg] = eais->data_const_off; + map->areg_map[eaid->reg] = eais->data_reg; + map->x86_verified[eais->data_reg] = 0; + } + } + + if (map->areg_map[eaid->reg] >= 0) + map->x86_dirty[map->areg_map[eaid->reg]] = 1; return; } - compile_offset_reg(map, valuereg, valueoffset); + if (eais->data_reg == -1) + printf("Storing to mem, but not from reg\n"); /* Correct the byteorder */ - if (valuereg != -2) { - switch (eai->size) { - case sz_byte: compile_force_byteorder(map, valuereg, BO_NORMAL, 1); break; - case sz_word: compile_force_byteorder(map, valuereg, BO_SWAPPED_WORD, 1); break; - case sz_long: compile_force_byteorder(map, valuereg, BO_SWAPPED_LONG, 1); break; - } + if (eais->data_reg != -2) { + compile_offset_reg(map, eais->data_reg, eais->data_const_off); + + switch (eaid->size) { + case sz_byte: compile_force_byteorder(map, eais->data_reg, BO_NORMAL, 1); break; + case sz_word: compile_force_byteorder(map, eais->data_reg, BO_SWAPPED_WORD, 1); break; + case sz_long: compile_force_byteorder(map, eais->data_reg, BO_SWAPPED_LONG, 1); break; + } + compile_force_byteorder(map, eaid->address_reg, BO_NORMAL, 0); + compile_move_reg_to_mem_regoffs(eaid->address_reg, + (uae_u32)(eaid->addr_const_off + address_space), + eais->data_reg, eaid->size); } else { - switch (eai->size) { + switch (eaid->size) { case sz_long: - valueoffset = (((valueoffset & 0xFF000000) >> 24) - | ((valueoffset & 0xFF0000) >> 8) - | ((valueoffset & 0xFF00) << 8) - | ((valueoffset & 0xFF) << 24)); + eais->data_const_off = (((eais->data_const_off & 0xFF000000) >> 24) + | ((eais->data_const_off & 0xFF0000) >> 8) + | ((eais->data_const_off & 0xFF00) << 8) + | ((eais->data_const_off & 0xFF) << 24)); break; case sz_word: - valueoffset = (((valueoffset & 0xFF00) >> 8) - | ((valueoffset & 0xFF) << 8)); + eais->data_const_off = (((eais->data_const_off & 0xFF00) >> 8) + | ((eais->data_const_off & 0xFF) << 8)); break; } - } - - /* We may have the value either in valuereg or in valueoffset by now, - * not in both (see call to compile_offset_reg() above) */ - - if (valuereg != -2) { - compile_move_reg_to_mem_regoffs(eai->address_reg, - (ULONG)(eai->addr_const_off + address_space), - valuereg, eai->size); - } else { + compile_force_byteorder(map, eaid->address_reg, BO_NORMAL, 0); /* generate code to move valueoffset,eaoffset(eareg) */ - switch(eai->size) { + switch(eaid->size) { case sz_byte: assemble(0xC6); break; case sz_word: assemble(0x66); /* fall through */ case sz_long: assemble(0xC7); break; } - if (eai->address_reg == -2) { /* absolute or PC-relative */ + if (eaid->address_reg == -2) { /* absolute or PC-relative */ assemble(0x05); - assemble_long(eai->addr_const_off + address_space); + assemble_long(eaid->addr_const_off + address_space); } else { - assemble(0x80 + eai->address_reg); - assemble_long(eai->addr_const_off + address_space); + assemble(0x80 + eaid->address_reg); + assemble_long(eaid->addr_const_off + address_space); } - switch(eai->size) { - case sz_byte: assemble(valueoffset); break; - case sz_word: assemble_uword(valueoffset); break; - case sz_long: assemble_ulong(valueoffset); break; + switch(eaid->size) { + case sz_byte: assemble(eais->data_const_off); break; + case sz_word: assemble_uword(eais->data_const_off); break; + case sz_long: assemble_ulong(eais->data_const_off); break; } } } @@ -2154,7 +2772,7 @@ static void compile_storeea(struct regis static struct { struct register_mapping map; char *jmpoffs; - ULONG address; + uae_u32 address; int noflush:1; } compile_exit_stack[CE_STACK_SIZE]; @@ -2165,7 +2783,7 @@ static struct register_mapping current_e static void generate_exit(struct register_mapping *map, int address) { int i; - + if (map != NULL) sync_reg_cache (map, 1); assemble(0xB8); /* movl $new_pc,%eax */ @@ -2173,7 +2791,7 @@ static void generate_exit(struct registe assemble(0xC3); /* RET */ } -static void copy_map_with_undo(struct register_mapping *dst, +static void copy_map_with_undo(struct register_mapping *dst, struct register_mapping *src, struct pid_undo *pud) { @@ -2194,11 +2812,28 @@ static void copy_map_with_undo(struct re } } +static void unlock_pud(struct register_mapping *map, struct pid_undo *pud) +{ + int i; + for (i = 0; i < pud->used; i++) { + compile_unlock_reg(map, pud->x86r[i]); + } +} + +static int exits_necessary; + static void generate_possible_exit(struct register_mapping *map, struct ea_info *eai, int iip, struct pid_undo *pud) { struct register_mapping exit_regmap; + + if (!exits_necessary) { + unlock_pud(map, pud); + return; + } + + compile_force_byteorder(map, eai->address_reg, BO_NORMAL, 0); switch (eai->address_reg) { case -1: /* EA doesn't refer to memory */ @@ -2232,6 +2867,7 @@ static void generate_possible_exit(struc cesp++; break; } + unlock_pud(map, pud); } static void finish_exits(void) @@ -2269,7 +2905,7 @@ static void finish_condjumps(int lastiip #define CC_X_FROM_86C 1 #define CC_C_FROM_86C 2 #define CC_Z_FROM_86Z 4 -#define CC_V_FROM_86V 8 +#define CC_V_FROM_86V 8 #define CC_N_FROM_86N 16 #define CC_TEST_REG 32 #define CC_Z_FROM_86C 64 @@ -2278,15 +2914,9 @@ static void finish_condjumps(int lastiip #define CC_AFTER_RO 512 #define CC_AFTER_ROX 1024 -#define CC68K_C 16 -#define CC68K_V 8 -#define CC68K_Z 4 -#define CC68K_N 2 -#define CC68K_X 1 - static unsigned int cc_status; static int cc_reg; -static ULONG cc_offset; +static uae_u32 cc_offset; static wordsizes cc_size; static void compile_do_cc_test_reg(struct register_mapping *map) @@ -2303,7 +2933,7 @@ static void compile_do_cc_test_reg(struc assemble(0xC0 + 9*cc_reg); } -static int compile_flush_cc_cache(struct register_mapping *map, int status, +static int compile_flush_cc_cache(struct register_mapping *map, int status, int live_at_end, int user_follows, int user_live_at_end, int user_ccval) { @@ -2311,7 +2941,7 @@ static int compile_flush_cc_cache(struct if (user_follows) { int need_for_user = 0; - int user_flagmask = cc_flagmask(user_ccval); + int user_flagmask = cc_flagmask_68k(user_ccval); if (user_flagmask & CC68K_C) need_for_user |= CC_C_FROM_86C; @@ -2338,7 +2968,7 @@ static int compile_flush_cc_cache(struct /* We fake some information here... */ if (user_flagmask == CC68K_C && (user_live_at_end & ~CC68K_C) == 0) status = status_for_user = CC_C_FROM_86C; - else if (((user_flagmask | user_live_at_end) & CC68K_C) == 0) { + else if (((user_flagmask | user_live_at_end) & (CC68K_C|CC68K_V)) == 0) { status = CC_TEST_REG; user_live_at_end = CC68K_Z|CC68K_N|CC68K_V; status_for_user = (CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V); } else @@ -2346,7 +2976,7 @@ static int compile_flush_cc_cache(struct } else if (status == CC_AFTER_ROX) { if (user_flagmask == CC68K_C && (user_live_at_end & ~(CC68K_C|CC68K_X)) == 0) status = status_for_user = CC_C_FROM_86C; - else if (((user_flagmask | user_live_at_end) & (CC68K_C|CC68K_X)) == 0) { + else if (((user_flagmask | user_live_at_end) & (CC68K_C|CC68K_X|CC68K_V)) == 0) { status = CC_TEST_REG; user_live_at_end = CC68K_Z|CC68K_N|CC68K_V; status_for_user = (CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V); } else @@ -2360,15 +2990,15 @@ static int compile_flush_cc_cache(struct } /* - * Now store the flags which are live at the end of this insn and set by - * us into their home locations + * Now store the flags which are live at the end of this insn and set by + * us into their home locations */ if (status == CC_TEST_REG) { if ((live_at_end & (CC68K_C|CC68K_V|CC68K_Z|CC68K_N)) == 0) goto all_ok; if (cc_reg == -2) { - UBYTE f = 0; + uae_u8 f = 0; if (cc_size == sz_byte) { f |= (cc_offset & 0x80) ? 0x80 : 0; f |= (cc_offset & 0xFF) == 0 ? 0x40 : 0; @@ -2379,7 +3009,7 @@ static int compile_flush_cc_cache(struct f |= (cc_offset & 0x80000000) ? 0x80 : 0; f |= (cc_offset & 0xFFFFFFFF) == 0 ? 0x40 : 0; } - assemble(0x66); assemble(0xC7); assemble(0x05); + assemble(0xC7); assemble(0x05); assemble_long((char*)®flags); assemble_uword(f); } else { @@ -2388,7 +3018,7 @@ static int compile_flush_cc_cache(struct /* pushfl; popl tmpr; movl tempr, regflags */ assemble(0x9C); assemble(0x58+tmpr); - compile_move_reg_to_mem_regoffs(-2, (ULONG)®flags, tmpr, sz_word); + compile_move_reg_to_mem_regoffs(-2, (uae_u32)®flags, tmpr, sz_long); } } else if (status == CC_Z_FROM_86C) { if ((live_at_end & CC68K_Z) != 0) { @@ -2397,7 +3027,7 @@ static int compile_flush_cc_cache(struct /* setnc tmpr; shl $6, tmpr; andb $~0x40, regflags; orb tmpr, regflags */ assemble(0x0F); assemble(0x93); assemble(0xC0 + tmpr); assemble(0xC0); assemble(4*8 + 0xC0 + tmpr); assemble(6); - assemble(0x80); assemble(0x05+0x20); assemble_long(®flags); assemble((UBYTE)~0x40); + assemble(0x80); assemble(0x05+0x20); assemble_long(®flags); assemble((uae_u8)~0x40); assemble(0x08); assemble(0x05+ tmpr*8); assemble_long(®flags); assemble(0x9D); } @@ -2405,37 +3035,44 @@ static int compile_flush_cc_cache(struct int tmpr = get_typed_x86_register(map, DATA_X86_REGS); assemble(0x9C); compile_do_cc_test_reg(map); - /* pushfl; popl tmpr; movl tempr, regflags */ - assemble(0x9C); assemble(0x58+tmpr); + /* pushfl; popl tmpr; andl $0xff,tmpr (mask out V flag which is cleared after rotates) */ + assemble(0x9C); assemble(0x58 + tmpr); + assemble(0x81); assemble(0xC0 + tmpr + 8*4); assemble_ulong(0xFF); assemble(0x9D); /* adc $0, tmpr */ assemble(0x80); assemble(0xC0 + tmpr + 8*2); assemble(0); - compile_move_reg_to_mem_regoffs(-2, (ULONG)®flags, tmpr, sz_word); + compile_move_reg_to_mem_regoffs(-2, (uae_u32)®flags, tmpr, sz_long); if (status == CC_AFTER_ROX) - compile_move_reg_to_mem_regoffs(-2, 2 + (ULONG)®flags, tmpr, sz_word); + compile_move_reg_to_mem_regoffs(-2, 4 + (uae_u32)®flags, tmpr, sz_long); } else if (status != 0) { assert((status & CC_TEST_REG) == 0); assert (status == (CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_X_FROM_86C | CC_V_FROM_86V) || status == (CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V) || status == CC_C_FROM_86C); - + if ((status & CC_X_FROM_86C) == 0) live_at_end &= ~CC68K_X; - - if (status == CC_C_FROM_86C && (live_at_end & CC68K_C) != 0) + + if (status == CC_C_FROM_86C && (live_at_end & CC68K_C) != 0) fprintf(stderr, "Shouldn't be needing C here!\n"); else if (live_at_end) { if ((live_at_end & CC68K_X) == 0) status &= ~CC_X_FROM_86C; if (live_at_end) { - int tmpr = get_free_x86_register(map, ALL_X86_REGS); - /* pushfl; popl tmpr; movl tempr, regflags */ - assemble(0x9C); assemble(0x58+tmpr); - compile_move_reg_to_mem_regoffs(-2, (ULONG)®flags, tmpr, sz_word); - - if (status & CC_X_FROM_86C) { - compile_move_reg_to_mem_regoffs(-2, 2 + (ULONG)®flags, tmpr, sz_word); + if ((status & CC_X_FROM_86C) != 0 && live_at_end == CC68K_X) { + /* SETC regflags + 4 */ + assemble(0x0F); assemble(0x92); + assemble(0x05); assemble_long(4 + (uae_u32)®flags); + } else { + int tmpr = get_free_x86_register(map, ALL_X86_REGS); + /* pushfl; popl tmpr; movl tempr, regflags */ + assemble(0x9C); assemble(0x58+tmpr); + compile_move_reg_to_mem_regoffs(-2, (uae_u32)®flags, tmpr, sz_long); + + if (status & CC_X_FROM_86C) { + compile_move_reg_to_mem_regoffs(-2, 4 + (uae_u32)®flags, tmpr, sz_word); + } } } } @@ -2444,12 +3081,12 @@ static int compile_flush_cc_cache(struct all_ok: return status_for_user; } - + static char *compile_condbranch(struct register_mapping *map, int iip, int new_cc_status) { int cc = insn_info[iip].dp->cc; - int flagsused = cc_flagmask(cc); + int flagsused = cc_flagmask_68k(cc); int flagsneeded = 0; char *undo_pointer = compile_here(); @@ -2462,17 +3099,19 @@ static char *compile_condbranch(struct r if (flagsused & CC68K_V) flagsneeded |= CC_V_FROM_86V; - if (new_cc_status == CC_SAHF) { + if (flagsneeded == 0) + /* Fine */; + else if (new_cc_status == CC_SAHF) { int tmpr = get_free_x86_register(map, ALL_X86_REGS); - compile_move_reg_from_mem_regoffs(tmpr, -2, (ULONG)®flags, sz_long); + compile_move_reg_from_mem_regoffs(tmpr, -2, (uae_u32)®flags, sz_long); assemble(0x66); assemble(0x50+tmpr); assemble(0x66); assemble(0x9D); new_cc_status = CC_C_FROM_86C|CC_Z_FROM_86Z|CC_N_FROM_86N|CC_V_FROM_86V; } else if (new_cc_status == CC_TEST_CONST) { int n,z; switch(cc_size) { - case sz_byte: n = ((BYTE)cc_offset) < 0; z = ((BYTE)cc_offset) == 0; break; - case sz_word: n = ((WORD)cc_offset) < 0; z = ((WORD)cc_offset) == 0; break; - case sz_long: n = ((LONG)cc_offset) < 0; z = ((LONG)cc_offset) == 0; break; + case sz_byte: n = ((uae_s8)cc_offset) < 0; z = ((uae_s8)cc_offset) == 0; break; + case sz_word: n = ((uae_s16)cc_offset) < 0; z = ((uae_s16)cc_offset) == 0; break; + case sz_long: n = ((uae_s32)cc_offset) < 0; z = ((uae_s32)cc_offset) == 0; break; } #define Bcc_TRUE 0 #define Bcc_FALSE 1 @@ -2502,10 +3141,10 @@ static char *compile_condbranch(struct r } else if (cc != 0 && cc != 1) printf("Groan!\n"); } - + if (cc == 1) return NULL; - + if ((flagsneeded & new_cc_status) == flagsneeded) { char *result; /* We can generate a simple branch */ @@ -2537,24 +3176,20 @@ static char *compile_condbranch(struct r return NULL; } -static void compile_handle_bcc(struct register_mapping *map, int iip, +static void compile_handle_bcc(struct register_mapping *map, int iip, int new_cc_status) { insn_info[iip].compiled_fillin = compile_condbranch(map, iip, new_cc_status); } -static void compile_handle_dbcc(struct register_mapping *map, int iip, +static void compile_handle_dbcc(struct register_mapping *map, int iip, int new_cc_status, int dreg) { - int cc = insn_info[iip].dp->cc; - int flagsused = cc_flagmask(cc); - int flagsneeded = 0; - char *undo_pointer = compile_here(); char *fillin1 = compile_condbranch(map, iip, new_cc_status); - + /* subw $1,dreg; jnc ... */ assemble(0x66); assemble(0x83); assemble(0x05 + 5*8); - assemble_long(regs.d + dreg); + assemble_long(regs.regs + dreg); assemble(1); assemble(0x0F); assemble(0x83); insn_info[iip].compiled_fillin = compile_here(); @@ -2567,95 +3202,81 @@ static void compile_handle_dbcc(struct r } } -static void handle_bit_insns(struct register_mapping *map, struct ea_info *srcea, - struct ea_info *dstea, instrmnem optype) +static void handle_bit_insns(struct register_mapping *map, struct ea_info *eainf, + int eaino_s, int eaino_d, instrmnem optype) { - int srcreg, dstreg, dstreg2; - ULONG srcoffs, dstoffs; + struct ea_info *srcea = eainf + eaino_s, *dstea = eainf + eaino_d; int code = (optype == i_BTST ? 0 : optype == i_BSET ? 1 : optype == i_BCLR ? 2 : /* optype == i_BCHG */ 3); - srcreg = compile_fetchea(map, srcea, &srcoffs); - if (srcreg >= 0) { - compile_offset_reg(map, srcreg, srcoffs); - srcoffs = 0; - } - /* Fake some EA info... */ - if (dstea->data_reg == -2) { - dstreg2 = compile_fetchea(map, dstea, &dstoffs); - dstreg = compile_move_const_reg(map, dstreg2, &dstoffs, 0); - compile_unlock_reg(map, dstreg2); - dstea->data_const_off = 0; - dstea->data_reg = dstreg; - } else if (dstea->data_reg >= 0) { - compile_offset_reg(map, dstea->data_reg, dstea->data_const_off); - dstea->data_const_off = 0; - } - compile_force_byteorder(map, srcreg, BO_NORMAL, 0); - if (srcreg != -2) { - remove_x86r_from_cache(map, srcreg, 0); + compile_fetchea(map, eainf, eaino_s, 5); + compile_fetchea(map, eainf, eaino_d, 3); + + if (srcea->data_reg != -2) { + compile_force_byteorder(map, srcea->data_reg, BO_NORMAL, 0); + remove_x86r_from_cache(map, srcea->data_reg, 0); /* andl $something,srcreg */ - assemble(0x83); assemble(0xC0 + 4*8 + srcreg); + assemble(0x83); assemble(0xC0 + 4*8 + srcea->data_reg); if (dstea->size == sz_byte) assemble(7); else assemble(31); } else if (dstea->size == sz_byte) - srcoffs &= 7; + srcea->data_const_off &= 7; else - srcoffs &= 31; + srcea->data_const_off &= 31; /* Areg isn't possible here */ if (dstea->mode == Dreg && dstea->data_reg == -1) { - if (srcreg == -2) { + if (srcea->data_reg == -2) { assemble(0x0F); assemble(0xBA); assemble(5 + 8*(4 + code)); - assemble_long(regs.d + dstea->reg); - assemble(srcoffs); + assemble_long(regs.regs + dstea->reg); + assemble(srcea->data_const_off); } else { assemble(0x0F); assemble(0xA3 + 8*code); - assemble(5 + srcreg*8); - assemble_long(regs.d + dstea->reg); + assemble(5 + srcea->data_reg*8); + assemble_long(regs.regs + dstea->reg); } } else if (dstea->data_reg >= 0) { compile_force_byteorder(map, dstea->data_reg, BO_NORMAL, 0); - if (srcreg == -2) { + if (srcea->data_reg == -2) { assemble(0x0F); assemble(0xBA); assemble(0xC0 + dstea->data_reg + 8*(4 + code)); - assemble(srcoffs); + assemble(srcea->data_const_off); } else { assemble(0x0F); assemble(0xA3 + 8*code); - assemble(0xC0 + dstea->data_reg + srcreg*8); + assemble(0xC0 + dstea->data_reg + srcea->data_reg*8); } if (optype != i_BTST) map->x86_dirty[dstea->data_reg] = 1; } else { int addr_code = dstea->address_reg == -2 ? 5 : dstea->address_reg + 0x80; + compile_force_byteorder(map, dstea->address_reg, BO_NORMAL, 0); /* We have an address in memory */ if (dstea->data_reg != -1) printf("Things don't look good in handle_bit_insns\n"); - if (srcreg == -2) { - assemble(0x0F); assemble(0xBA); + if (srcea->data_reg == -2) { + assemble(0x0F); assemble(0xBA); assemble(addr_code + 8*(4 + code)); assemble_long(address_space + dstea->addr_const_off); - assemble(srcoffs); + assemble(srcea->data_const_off); } else { assemble(0x0F); assemble(0xA3 + 8*code); - assemble(addr_code + srcreg*8); + assemble(addr_code + srcea->data_reg*8); assemble_long(address_space + dstea->addr_const_off); } - + } cc_status = CC_Z_FROM_86C; } static int do_rotshi = 1; -static void handle_rotshi(struct register_mapping *map, int iip, - UBYTE *realpc, CPTR current_addr) +static void handle_rotshi(struct register_mapping *map, int iip, + uae_u8 *realpc, uaecptr current_addr, struct pid_undo *pud) { - struct pid_undo pub; struct ea_info eai; int amode_reg = insn_info[iip].dp->sreg; int amode_mode = insn_info[iip].dp->smode; @@ -2663,10 +3284,8 @@ static void handle_rotshi(struct registe int shiftcount; int mnemo = insn_info[iip].dp->mnemo; int shiftcode; + int locked_eax_for_sahf = 0; - int srcreg, srcreg2; - ULONG srcoffs; - switch(mnemo) { case i_ASLW: shiftcount = 1; mnemo = i_ASL; break; case i_ASRW: shiftcount = 1; mnemo = i_ASR; break; @@ -2677,43 +3296,37 @@ static void handle_rotshi(struct registe case i_ROXLW:shiftcount = 1; mnemo = i_ROXL;break; case i_ROXRW:shiftcount = 1; mnemo = i_ROXR;break; default: - if (insn_info[iip].dp->smode != immi) { - generate_exit(map, insn_info[iip].address); - return; - } amode_reg = insn_info[iip].dp->dreg; amode_mode = insn_info[iip].dp->dmode; shiftcount = insn_info[iip].dp->sreg; break; } - if ((mnemo == i_LSL || mnemo == i_LSR || mnemo == i_ASR || mnemo == i_ASL) - && (insn_info[iip].flags_live_at_end & CC68K_V) != 0) { - generate_exit(map, insn_info[iip].address); - return; - } - if (mnemo == i_ROR || mnemo == i_ROL || mnemo == i_ROXR || mnemo == i_ROXL) { - if ((insn_info[iip].flags_live_at_end & CC68K_V) != 0) { + if ((insn_info[iip].flags_live_at_end & CC68K_V) != 0) { + if (mnemo == i_ASL) { generate_exit(map, insn_info[iip].address); + printf("Can't handle this shift\n"); return; + } else if (mnemo == i_ASR || mnemo == i_LSR || mnemo == i_LSL) { + remove_x86r_from_cache(map, r_EAX, 1); + locked_eax_for_sahf = 1; + lock_reg(map, r_EAX, 2); } + } if (mnemo == i_ROXR || mnemo == i_ROXL) { remove_x86r_from_cache(map, r_EAX, 1); - map->x86_locked[r_EAX]++; - compile_move_reg_from_mem_regoffs(r_AH, -2, 2 + (ULONG)®flags, - sz_byte); + lock_reg(map, r_EAX, 2); + compile_move_reg_from_mem_regoffs(r_AH, -2, 4 + (uae_u32)®flags, sz_byte); } + compile_prepare_undo(map, amode_mode, amode_reg, pud); compile_prepareea(map, amode_mode, amode_reg, size, &realpc, current_addr, - &eai, EA_LOAD|EA_STORE, &pub, 1); - - generate_possible_exit(map, &eai, iip, &pub); - - srcreg = compile_fetchea(map, &eai, &srcoffs); - srcreg2 = compile_move_const_reg(map, srcreg, &srcoffs, insn_info[iip].dp->size == sz_byte ? DATA_X86_REGS : 0); - compile_unlock_reg(map, srcreg); + &eai, 0, EA_LOAD|EA_STORE|EA_MODIFY, 1); + + generate_possible_exit(map, &eai, iip, pud); - compile_force_byteorder(map, srcreg2, BO_NORMAL, 0); + compile_fetchea(map, &eai, 0, 1); + compile_force_byteorder(map, eai.data_reg, BO_NORMAL, 0); switch (mnemo) { case i_ASL: @@ -2721,7 +3334,7 @@ static void handle_rotshi(struct registe break; case i_LSL: shiftcode = 4; cc_status = CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V | CC_X_FROM_86C; - break; + break; case i_LSR: shiftcode = 5; cc_status = CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V | CC_X_FROM_86C; break; @@ -2735,24 +3348,129 @@ static void handle_rotshi(struct registe shiftcode = 0; cc_status = CC_AFTER_RO; break; case i_ROXL: - shiftcode = 2; assemble(0x9E); /* SAHF */ cc_status = CC_AFTER_ROX; + shiftcode = 2; assemble(0x9E); /* SAHF */ cc_status = CC_AFTER_ROX; compile_unlock_reg(map, r_EAX); break; case i_ROXR: - shiftcode = 3; assemble(0x9E); /* SAHF */ cc_status = CC_AFTER_ROX; + shiftcode = 3; assemble(0x9E); /* SAHF */ cc_status = CC_AFTER_ROX; compile_unlock_reg(map, r_EAX); break; } if (size == sz_word) assemble(0x66); assemble((shiftcount == 1 ? 0xD0 : 0xC0) + (size == sz_byte ? 0 : 1)); - assemble(shiftcode*8+0xC0 + srcreg); + assemble(shiftcode*8+0xC0 + eai.data_reg); if (shiftcount != 1) assemble(shiftcount); - cc_offset = 0; cc_size = size; cc_reg = srcreg; - - compile_storeea(map, &eai, srcreg, 0); + cc_offset = 0; cc_size = size; cc_reg = eai.data_reg; + + if (locked_eax_for_sahf) { + /* The trick here is that the overflow flag isn't put into AH in SAHF */ + assemble(0x9E); + assemble(0x0B); assemble(9*1 + 0xC0); + assemble(0x9F); + compile_unlock_reg(map, r_EAX); + } + compile_note_modify(map, &eai, 0); } -static ULONG testmask = 0xF80000, testval = 0xF80000; +static void handle_rotshi_variable(struct register_mapping *map, int iip, + uae_u8 *realpc, uaecptr current_addr, + struct pid_undo *pud) +{ + struct ea_info eais, eaid; + int mnemo = insn_info[iip].dp->mnemo; + int shiftcode; + char *tmp1, *tmp2; + int locked_eax_for_sahf = 0; + + remove_x86r_from_cache(map, r_ECX, 1); + lock_reg(map, r_ECX, 2); + + if ((insn_info[iip].flags_live_at_end & CC68K_V) != 0) { + if (mnemo == i_ASL) { + generate_exit(map, insn_info[iip].address); + printf("Can't handle this shift (var)\n"); + return; + } else if (mnemo == i_ASR || mnemo == i_LSR || mnemo == i_LSL) { + remove_x86r_from_cache(map, r_EAX, 1); + locked_eax_for_sahf = 1; + lock_reg(map, r_EAX, 2); + } + + } + if (mnemo == i_ROXR || mnemo == i_ROXL) { + remove_x86r_from_cache(map, r_EAX, 1); + lock_reg(map, r_EAX, 2); + compile_move_reg_from_mem_regoffs(r_AH, -2, 4 + (uae_u32)®flags, + sz_byte); + } + /* Both src and dest are Dreg modes */ + compile_prepareea(map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, + sz_long, &realpc, current_addr, + &eais, 0, EA_LOAD, 1); + compile_prepareea(map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, + insn_info[iip].dp->size, &realpc, current_addr, + &eaid, 0, EA_LOAD|EA_STORE|EA_MODIFY, 1); + + compile_fetchea(map, &eais, 0, 1); + compile_fetchea(map, &eaid, 1, 1); + compile_force_byteorder(map, eais.data_reg, BO_NORMAL, 0); + compile_force_byteorder(map, eaid.data_reg, BO_NORMAL, 0); + compile_move_reg_reg(r_ECX, eais.data_reg, sz_long); + /* Test against zero, and test bit 6. If 1 <= count <= 31, we can do the + * operation, otherwise, we have to exit */ + assemble(0xF6); assemble(0xC0 + r_ECX); assemble(0x1F); + assemble(0x74); assemble(9); + assemble(0xF6); assemble(0xC0 + r_ECX); assemble(0x20); + + assemble(0x0F); assemble(0x85); tmp1 = compile_here(); assemble_ulong(0); + generate_exit(map, insn_info[iip].address); + tmp2 = compile_here(); compile_org (tmp1); assemble_ulong((tmp2-tmp1) + 4); compile_org(tmp2); + + switch (mnemo) { + case i_ASL: + shiftcode = 4; cc_status = CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V | CC_X_FROM_86C; + break; + case i_LSL: + shiftcode = 4; cc_status = CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V | CC_X_FROM_86C; + break; + case i_LSR: + shiftcode = 5; cc_status = CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V | CC_X_FROM_86C; + break; + case i_ASR: + shiftcode = 7; cc_status = CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V | CC_X_FROM_86C; + break; + case i_ROR: + shiftcode = 1; cc_status = CC_AFTER_RO; + break; + case i_ROL: + shiftcode = 0; cc_status = CC_AFTER_RO; + break; + case i_ROXL: + shiftcode = 2; assemble(0x9E); /* SAHF */ cc_status = CC_AFTER_ROX; compile_unlock_reg(map, r_EAX); + break; + case i_ROXR: + shiftcode = 3; assemble(0x9E); /* SAHF */ cc_status = CC_AFTER_ROX; compile_unlock_reg(map, r_EAX); + break; + } + + if (insn_info[iip].dp->size == sz_word) + assemble(0x66); + assemble(0xD2 + (insn_info[iip].dp->size == sz_byte ? 0 : 1)); + assemble(shiftcode*8+0xC0 + eaid.data_reg); + cc_offset = 0; cc_size = insn_info[iip].dp->size; cc_reg = eaid.data_reg; + + if (locked_eax_for_sahf) { + /* The trick here is that the overflow flag isn't put into AH in SAHF */ + assemble(0x9E); + assemble(0x0B); assemble(9*1 + 0xC0); + assemble(0x9F); + compile_unlock_reg(map, r_EAX); + } + compile_note_modify(map, &eaid, 0); + compile_unlock_reg(map, r_ECX); +} + +static uae_u32 testmask = 0xF80000, testval = 0xF80000; static int m68k_compile_block(struct hash_block *hb) { @@ -2760,10 +3478,11 @@ static int m68k_compile_block(struct has int last_iip = m68k_scan_block(hb, &movem_extra); struct register_mapping map; int i, iip, szflag; - UBYTE *realpc_start = NULL; + uae_u8 *realpc_start = NULL; struct bb_info *current_bb; int cc_status_for_bcc = CC_SAHF; - + struct insn_reg_needs reg_needs_init; + cesp = 0; if (n_compiled > n_max_comp) @@ -2778,16 +3497,18 @@ static int m68k_compile_block(struct has && 0 && !patched_syscalls) return 1; + exits_necessary = ((hb->he_first->addr & 0xF80000) == 0xF80000 || !USER_PROGRAMS_BEHAVE); + if (alloc_code (hb, last_iip + movem_extra) == NULL) { hb->allocfailed = 1; return 0; } compile_org(hb->compile_start); compile_last_addr = (char *)hb->compile_start + hb->alloclen; - + /* m68k_scan_block() will leave this all set up */ current_bb = bb_stack; - + for (i = 0; i < 8; i++) { map.dreg_map[i] = map.areg_map[i] = -1; map.x86_dirty[i] = 0; @@ -2797,19 +3518,26 @@ static int m68k_compile_block(struct has map.x86_verified[i] = 0; map.x86_byteorder[i] = BO_NORMAL; } - + + reg_needs_init.checkpoint_no = 0; + for (i = 0; i < 8; i++) { + reg_needs_init.dreg_needed[i] = reg_needs_init.areg_needed[i] = -1; + reg_needs_init.dreg_mask[i] = reg_needs_init.areg_mask[i] = ALL_X86_REGS; + } + for (iip = 0; iip < last_iip && !compile_failure; iip++) { - UBYTE *realpc; - int srcreg, dstreg, srcreg2, dstreg2; - ULONG srcoffs, dstoffs; - struct ea_info eainfo[4]; - CPTR current_addr; + uae_u8 *realpc; + struct ea_info eainfo[8]; + uaecptr current_addr; struct pid_undo pub; - + struct insn_reg_needs this_reg_needs = reg_needs_init; + /* Set up locks for a new insn. We don't bother to clear this * properly after compiling one insn. */ - for (i = 0; i < 8; i++) - map.x86_locked[i] = i == r_ESP ? 1 : 0; + for (i = 0; i < 8; i++) { + map.x86_users[i] = i == r_ESP ? 1 : 0; + map.x86_locked[i] = i == r_ESP ? 2 : 0; + } pub.used = 0; current_addr = insn_info[iip].address + 2; @@ -2818,17 +3546,18 @@ static int m68k_compile_block(struct has sync_reg_cache(&map, 1); if (!quiet_compile) printf("Compiling %08lx\n", current_bb->h->addr); + realpc_start = get_real_address(current_bb->h->addr); current_bb->h->execute = (code_execfunc)compile_here(); - current_bb->h->matchword = *(ULONG *)realpc_start; + current_bb->h->matchword = *(uae_u32 *)realpc_start; cc_status_for_bcc = CC_SAHF; } - realpc = realpc_start + (current_addr - current_bb->h->addr); + realpc = realpc_start + (current_addr - current_bb->h->addr); - insn_info[iip].compiled_jumpaddr = compile_here(); + insn_info[iip].compiled_jumpaddr = compile_here(); insn_info[iip].compiled_fillin = NULL; - + if (insn_info[iip].jump_target) { if (cesp == CE_STACK_SIZE) { generate_exit(NULL, insn_info[iip].address); @@ -2845,11 +3574,186 @@ static int m68k_compile_block(struct has } /* * This will sort out all insns we can't compile, including - * conditional branches and jumps out of this block */ + * jumps out of this block */ if (insn_info[iip].stop_translation == 1) { generate_exit(&map, insn_info[iip].address); cc_status = 0; } else switch (insn_info[iip].dp->mnemo) { + case i_NOP: + cc_status = 0; + if (!quiet_compile) + printf("Compiling a NOP\n"); + break; + + case i_RTS: + sync_reg_cache(&map, 1); + lock_reg(&map, r_ECX, 2); + lock_reg(&map, r_EBX, 2); + { + char *tmp1, *tmp2, *tmp3; + + /* fetch (A7) */ + assemble(0x8B); assemble(0x5 + r_EBX*8); assemble_long(regs.regs + 15); + assemble(0x8B); assemble(0x80 + 9*r_EBX); assemble_long(address_space); + assemble(0x0F); /* bswapl x86r */ + assemble(0xC8 + r_EBX); + /* fetch jsr_num */ + assemble(0x8B); assemble(0x5 + r_ECX*8); assemble_long(&jsr_num); + assemble(0x09); assemble(0xC0 + 9*r_ECX); + assemble(0x0F); assemble(0x84); tmp1 = compile_here(); assemble_ulong(0); + assemble(0xFF); assemble(1*8 + 0xC0 + r_ECX); + /* cmpl %ebx,disp32(,%ecx,4) */ + assemble(0x39); assemble(0x04 + 8*r_EBX); assemble(0x8d); + assemble_long(jsr_rets); + assemble(0x0F); assemble(0x85); tmp2 = compile_here(); assemble_ulong(0); + /* movl disp32(,%ecx,4),%ebx */ + assemble(0x8B); assemble(0x04 + 8*r_EBX); assemble(0x8d); + assemble_long(jsr_hash); + /* movl execute(%ebx), %ebx */ + assemble(0x8B); assemble(0x040 + 9*r_EBX); assemble((int)&((struct hash_entry *)0)->execute); + assemble(0x09); assemble(0xC0 + 9*r_EBX); + assemble(0x0F); assemble(0x85); tmp3 = compile_here(); assemble_ulong(0); + compile_org(tmp1); assemble_ulong(tmp3 - tmp1); + compile_org(tmp2); assemble_ulong(tmp3 - tmp2); + compile_org(tmp3 + 4); + generate_exit(&map, insn_info[iip].address); + tmp1 = compile_here(); + compile_org(tmp3); assemble_ulong((tmp1-tmp3)-4); + compile_org(tmp1); + assemble(0x89); assemble(0x5 + r_ECX*8); assemble_long(&jsr_num); + assemble(0x83); assemble(0x05 + 5*8); assemble_long(regs.regs + 15); assemble(-4); + /* Off we go */ + assemble(0xFF); assemble(4*8 + 0xC0 + r_EBX); + } + break; + + case i_JMP: + sync_reg_cache(&map, 1); + compile_prepareea(&map, insn_info[iip].dp->smode, + insn_info[iip].dp->sreg, + insn_info[iip].dp->size, &realpc, current_addr, + eainfo, 0, EA_LOAD, 1); + { + char *tmp1, *tmp2, *tmp3; + + struct hash_entry *tmph; + if (eainfo[0].address_reg != -2 || (tmph = get_hash_for_func(eainfo[0].addr_const_off, 1)) == 0) { + if (eainfo[0].address_reg != -2 && !quiet_compile) + printf("Can't compile indirect JMP\n"); + generate_exit(&map, insn_info[iip].address); + break; + } + /* check whether the destination has compiled code */ + assemble(0x8B); assemble(r_EBX*8 + 0x05); assemble_long(&(tmph->execute)); + assemble(0x09); assemble(0xC0 + 9*r_EBX); + assemble(0x0F); assemble(0x85); tmp1 = compile_here(); assemble_ulong(0); + generate_exit(&map, insn_info[iip].address); + tmp2 = compile_here(); compile_org(tmp1); + assemble_ulong((tmp2 - tmp1) - 4); + compile_org(tmp2); + /* Off we go */ + assemble(0xFF); assemble(4*8 + 0xC0 + r_EBX); + } + cc_status = 0; + break; + + case i_JSR: + sync_reg_cache(&map, 1); + lock_reg(&map, r_ECX, 2); + lock_reg(&map, r_EBX, 2); + compile_prepareea(&map, insn_info[iip].dp->smode, + insn_info[iip].dp->sreg, + insn_info[iip].dp->size, &realpc, current_addr, + eainfo, 0, EA_LOAD, 1); + { + char *tmp1, *tmp2, *tmp3; + + struct hash_entry *tmph; + if (eainfo[0].address_reg != -2 || (tmph = get_hash_for_func(eainfo[0].addr_const_off, 1)) == 0) { + if (eainfo[0].address_reg != -2 && !quiet_compile) + printf("Can't compile indirect JSR\n"); + generate_exit(&map, insn_info[iip].address); + break; + } + assert(iip + 1 < last_iip); + assert(iip == current_bb->last_iip); + /* check whether the destination has compiled code */ + assemble(0x8B); assemble(r_EBX*8 + 0x05); assemble_long(&(tmph->execute)); + assemble(0x09); assemble(0xC0 + 9*r_EBX); + assemble(0x0F); assemble(0x84); tmp3 = compile_here(); assemble_ulong(0); + /* check for stack overflow */ + assemble(0x8B); assemble(r_ECX*8 + 0x05); assemble_long(&jsr_num); + assemble(0xF7); assemble(0xC0+r_ECX); assemble_ulong(MAX_JSRS); + assemble(0x0F); assemble(0x84); tmp1 = compile_here(); assemble_ulong(0); + generate_exit(&map, insn_info[iip].address); + tmp2 = compile_here(); compile_org(tmp1); assemble_ulong((tmp2 - tmp1) - 4); + compile_org(tmp3); assemble_ulong(tmp1-tmp3); + compile_org(tmp2); + /* movl $something,disp32(,%ecx,4) */ + assemble(0xC7); assemble(0x04); assemble(0x8d); + assemble_long(jsr_rets); assemble_ulong(insn_info[iip+1].address); + assemble(0xC7); assemble(0x04); assemble(0x8d); + assemble_long(jsr_hash); assemble_long((current_bb + 1)->h); + /* incl jsr_num */ + assemble(0xFF); assemble(0x05); assemble_long(&jsr_num); + /* Put things on the 68k stack */ + assemble(0x83); assemble(0x05 + 5*8); assemble_long(regs.regs + 15); assemble(4); + assemble(0x8B); assemble(r_ECX*8+ 0x05); assemble_long(regs.regs + 15); + assemble(0xC7); assemble(0x80 + r_ECX); assemble_long(address_space); + assemble_ulong_68k(insn_info[iip+1].address); + /* Off we go */ + assemble(0xFF); assemble(4*8 + 0xC0 + r_EBX); + } + break; + + case i_BSR: + sync_reg_cache(&map, 1); + lock_reg(&map, r_ECX, 2); + lock_reg(&map, r_EBX, 2); + compile_prepareea(&map, insn_info[iip].dp->smode, + insn_info[iip].dp->sreg, + insn_info[iip].dp->size, &realpc, current_addr, + eainfo, 0, EA_LOAD, 1); + { + char *tmp1, *tmp2, *tmp3; + uaecptr dest = insn_info[iip].address + 2 + (uae_s32)eainfo[0].data_const_off; + struct hash_entry *tmph; + if ((tmph = get_hash_for_func(dest, 1)) == 0) { + generate_exit(&map, insn_info[iip].address); + break; + } + assert(iip + 1 < last_iip); + assert(iip == current_bb->last_iip); + + /* check whether the destination has compiled code */ + assemble(0x8B); assemble(r_EBX*8 + 0x05); assemble_long(&(tmph->execute)); + assemble(0x09); assemble(0xC0 + 9*r_EBX); + assemble(0x0F); assemble(0x84); tmp3 = compile_here(); assemble_ulong(0); + /* check for stack overflow */ + assemble(0x8B); assemble(r_ECX*8 + 0x05); assemble_long(&jsr_num); + assemble(0xF7); assemble(0xC0+r_ECX); assemble_ulong(MAX_JSRS); + assemble(0x0F); assemble(0x84); tmp1 = compile_here(); assemble_ulong(0); + generate_exit(&map, insn_info[iip].address); + tmp2 = compile_here(); compile_org(tmp1); assemble_ulong((tmp2 - tmp1) - 4); + compile_org(tmp3); assemble_ulong(tmp1-tmp3); + compile_org(tmp2); + /* movl $something,disp32(,%ecx,4) */ + assemble(0xC7); assemble(0x04); assemble(0x8d); + assemble_long(jsr_rets); assemble_ulong(insn_info[iip+1].address); + assemble(0xC7); assemble(0x04); assemble(0x8d); + assemble_long(jsr_hash); assemble_long((current_bb + 1)->h); + /* incl jsr_num */ + assemble(0xFF); assemble(0x05); assemble_long(&jsr_num); + /* Put things on the 68k stack */ + assemble(0x83); assemble(0x05 + 5*8); assemble_long(regs.regs + 15); assemble(4); + assemble(0x8B); assemble(r_ECX*8+ 0x05); assemble_long(regs.regs + 15); + assemble(0xC7); assemble(0x80 + r_ECX); assemble_long(address_space); + assemble_ulong_68k(insn_info[iip+1].address); + /* Off we go */ + assemble(0xFF); assemble(4*8 + 0xC0 + r_EBX); + } + break; + case i_Bcc: sync_reg_cache(&map, 0); compile_handle_bcc(&map, iip, cc_status_for_bcc); @@ -2865,14 +3769,15 @@ static int m68k_compile_block(struct has break; #if 0 case i_Scc: + compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub); compile_prepareea(&map, insn_info[iip].dp->smode, - insn_info[iip].dp->sreg, + insn_info[iip].dp->sreg, insn_info[iip].dp->size, &realpc, current_addr, - eainfo, EA_STORE, &pub, 1); + eainfo, 0, EA_STORE, 1); generate_possible_exit(&map, eainfo, iip, &pub); srcreg2 = get_; - compile_storeea(&map, eainfo + 0, -2, 0); + compile_note_modify(&map, eainfo, 0); cc_status = 0; break; @@ -2881,96 +3786,73 @@ static int m68k_compile_block(struct has case i_SUB: case i_CMP: case i_CMPM: + compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub); + compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub); compile_prepareea(&map, insn_info[iip].dp->smode, - insn_info[iip].dp->sreg, + insn_info[iip].dp->sreg, insn_info[iip].dp->size, &realpc, current_addr, - eainfo, EA_LOAD, &pub, 1); + eainfo, 0, EA_LOAD, 1); compile_prepareea(&map, insn_info[iip].dp->dmode, - insn_info[iip].dp->dreg, + insn_info[iip].dp->dreg, insn_info[iip].dp->size, &realpc, current_addr, - eainfo + 1, EA_IN_REG | EA_LOAD | EA_STORE, - &pub, 1); + eainfo, 1, + (insn_info[iip].dp->mnemo == i_ADD || insn_info[iip].dp->mnemo == i_SUB + ? EA_MODIFY | EA_LOAD | EA_STORE + : EA_LOAD | EA_STORE), 1); generate_possible_exit(&map, eainfo, iip, &pub); generate_possible_exit(&map, eainfo+1, iip, &pub); - - szflag = insn_info[iip].dp->size == sz_byte ? 0 : 1; - srcreg = compile_fetchea(&map, eainfo + 0, &srcoffs); - dstreg = compile_fetchea(&map, eainfo + 1, &dstoffs); - - srcreg2 = compile_move_const_reg(&map, srcreg, &srcoffs, insn_info[iip].dp->size == sz_byte ? DATA_X86_REGS : 0); - compile_unlock_reg(&map, srcreg); - compile_offset_reg(&map, dstreg, dstoffs); - compile_force_byteorder(&map, srcreg2, BO_NORMAL, 0); - compile_force_byteorder(&map, dstreg, BO_NORMAL, 0); + compile_loadeas(&map, eainfo, 0, 1, binop_alternatives, 0, 1); - if (insn_info[iip].dp->size == sz_word) - assemble(0x66); switch (insn_info[iip].dp->mnemo) { - case i_ADD: assemble(0x00+szflag); break; - case i_SUB: assemble(0x28+szflag); break; - case i_AND: assemble(0x20+szflag); break; - case i_EOR: assemble(0x30+szflag); break; - case i_CMP: case i_CMPM: assemble(0x38+szflag); break; - case i_OR: assemble(0x08+szflag); break; - } - assemble(0xC0 + srcreg2*8 + dstreg); - if ((insn_info[iip].dp->mnemo != i_CMP) - && (insn_info[iip].dp->mnemo != i_CMPM)) - compile_storeea(&map, eainfo + 1, dstreg, 0); + case i_ADD: compile_eas(&map, eainfo, 0, 1, 0); break; + case i_SUB: compile_eas(&map, eainfo, 0, 1, 5); break; + case i_CMP: case i_CMPM: compile_eas(&map, eainfo, 0, 1, 7); break; + } + + if (insn_info[iip].dp->mnemo != i_CMP && insn_info[iip].dp->mnemo != i_CMPM) + compile_note_modify(&map, eainfo, 1); switch (insn_info[iip].dp->mnemo) { case i_ADD: case i_SUB: - cc_status = CC_X_FROM_86C | CC_Z_FROM_86Z |CC_C_FROM_86C |CC_V_FROM_86V |CC_N_FROM_86N; + cc_status = CC_X_FROM_86C | CC_Z_FROM_86Z | CC_C_FROM_86C | CC_V_FROM_86V | CC_N_FROM_86N; break; - case i_AND: - case i_EOR: - case i_OR: case i_CMP: case i_CMPM: - cc_status = CC_Z_FROM_86Z |CC_C_FROM_86C |CC_V_FROM_86V |CC_N_FROM_86N; + cc_status = CC_Z_FROM_86Z | CC_C_FROM_86C | CC_V_FROM_86V | CC_N_FROM_86N; break; } break; case i_ADDX: case i_SUBX: + compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub); + compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub); compile_prepareea(&map, insn_info[iip].dp->smode, - insn_info[iip].dp->sreg, + insn_info[iip].dp->sreg, insn_info[iip].dp->size, &realpc, current_addr, - eainfo, EA_LOAD, &pub, 1); + eainfo, 0, EA_LOAD, 1); compile_prepareea(&map, insn_info[iip].dp->dmode, - insn_info[iip].dp->dreg, + insn_info[iip].dp->dreg, insn_info[iip].dp->size, &realpc, current_addr, - eainfo + 1, EA_IN_REG | EA_LOAD | EA_STORE, - &pub, 1); + eainfo, 1, EA_MODIFY | EA_LOAD | EA_STORE, 1); generate_possible_exit(&map, eainfo, iip, &pub); generate_possible_exit(&map, eainfo+1, iip, &pub); - - szflag = insn_info[iip].dp->size == sz_byte ? 0 : 1; - srcreg = compile_fetchea(&map, eainfo + 0, &srcoffs); - dstreg = compile_fetchea(&map, eainfo + 1, &dstoffs); - - srcreg2 = compile_move_const_reg(&map, srcreg, &srcoffs, insn_info[iip].dp->size == sz_byte ? DATA_X86_REGS : 0); - compile_unlock_reg(&map, srcreg); - compile_offset_reg(&map, dstreg, dstoffs); - - compile_force_byteorder(&map, srcreg2, BO_NORMAL, 0); - compile_force_byteorder(&map, dstreg, BO_NORMAL, 0); - - /* bt $16, regflags ; get carry */ - assemble(0x0F); assemble(0xBA); assemble(0x5+4*8); - assemble_long(®flags); assemble(0x10); - if (insn_info[iip].dp->size == sz_word) - assemble(0x66); + + compile_loadeas(&map, eainfo, 0, 1, binop_alternatives, 0, 1); + + /* bt $0, regflags+4 ; get carry */ + assemble(0x0F); assemble(0xBA); assemble(0x5+4*8); + assemble_ulong(4 + (uae_u32)®flags); assemble(0); + switch (insn_info[iip].dp->mnemo) { - case i_ADDX: assemble(0x10+szflag); break; - case i_SUBX: assemble(0x18+szflag); break; + case i_ADDX: compile_eas(&map, eainfo, 0, 1, 2); break; + case i_SUBX: compile_eas(&map, eainfo, 0, 1, 3); break; } - assemble(0xC0 + srcreg2*8 + dstreg); - compile_storeea(&map, eainfo + 1, dstreg, 0); + compile_note_modify(&map, eainfo, 1); + if (insn_info[iip].flags_live_at_end & CC68K_Z) { /* Darn. */ int tmpr = get_free_x86_register(&map, ALL_X86_REGS); @@ -2981,7 +3863,7 @@ static int m68k_compile_block(struct has assemble(0x21); assemble(0x05 + 8*tmpr); assemble_long(®flags); assemble(0x81); assemble(0xC0 + 8*4 + tmpr); assemble_ulong(~0x40); assemble(0x09); assemble(0x05 + 8*tmpr); assemble_long(®flags); - compile_move_reg_to_mem_regoffs(-2, 2 + (ULONG)®flags, tmpr, sz_word); + compile_move_reg_to_mem_regoffs(-2, 4 + (uae_u32)®flags, tmpr, sz_long); cc_status = 0; } else { /* Lies! */ @@ -2991,46 +3873,39 @@ static int m68k_compile_block(struct has case i_MULU: case i_MULS: + compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub); + compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub); compile_prepareea(&map, insn_info[iip].dp->smode, - insn_info[iip].dp->sreg, + insn_info[iip].dp->sreg, insn_info[iip].dp->size, &realpc, current_addr, - eainfo, EA_LOAD, &pub, 1); + eainfo, 0, EA_LOAD, 1); compile_prepareea(&map, insn_info[iip].dp->dmode, - insn_info[iip].dp->dreg, + insn_info[iip].dp->dreg, insn_info[iip].dp->size, &realpc, current_addr, - eainfo + 1, EA_IN_REG | EA_LOAD | EA_STORE, - &pub, 1); + eainfo, 1, EA_MODIFY | EA_LOAD | EA_STORE, 1); generate_possible_exit(&map, eainfo, iip, &pub); generate_possible_exit(&map, eainfo+1, iip, &pub); - - srcreg = compile_fetchea(&map, eainfo + 0, &srcoffs); - dstreg = compile_fetchea(&map, eainfo + 1, &dstoffs); - - srcreg2 = compile_move_const_reg(&map, srcreg, &srcoffs, insn_info[iip].dp->size == sz_byte ? DATA_X86_REGS : 0); - compile_unlock_reg(&map, srcreg); - compile_offset_reg(&map, dstreg, dstoffs); - compile_force_byteorder(&map, srcreg2, BO_NORMAL, 0); - compile_force_byteorder(&map, dstreg, BO_NORMAL, 0); + compile_loadeas(&map, eainfo, 0, 1, regonly_alternatives, 0, 1); /* Extend the regs properly */ - remove_x86r_from_cache(&map, srcreg2, 0); + remove_x86r_from_cache(&map, eainfo[0].data_reg, 0); switch (insn_info[iip].dp->mnemo) { case i_MULU: - assemble(0x81); assemble(0xC0+4*8+srcreg2); assemble_ulong(0xFFFF); - assemble(0x81); assemble(0xC0+4*8+dstreg); assemble_ulong(0xFFFF); + assemble(0x81); assemble(0xC0+4*8 + eainfo[0].data_reg); assemble_ulong(0xFFFF); + assemble(0x81); assemble(0xC0+4*8 + eainfo[1].data_reg); assemble_ulong(0xFFFF); break; case i_MULS: - assemble(0x0F); assemble(0xBF); assemble(0xC0 + 9*srcreg2); - assemble(0x0F); assemble(0xBF); assemble(0xC0 + 9*dstreg); + assemble(0x0F); assemble(0xBF); assemble(0xC0 + 9*eainfo[0].data_reg); + assemble(0x0F); assemble(0xBF); assemble(0xC0 + 9*eainfo[1].data_reg); break; } /* and multiply */ - assemble(0x0F); assemble(0xAF); assemble(0xC0 + 8*dstreg + srcreg2); - compile_storeea(&map, eainfo + 1, dstreg, 0); + assemble(0x0F); assemble(0xAF); assemble(0xC0 + 8*eainfo[1].data_reg + eainfo[0].data_reg); + compile_note_modify(&map, eainfo, 1); cc_status = CC_TEST_REG; - cc_reg = dstreg; + cc_reg = eainfo[1].data_reg; cc_offset = 0; cc_size = sz_long; break; @@ -3038,234 +3913,254 @@ static int m68k_compile_block(struct has case i_ADDA: case i_SUBA: case i_CMPA: + compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub); + compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub); compile_prepareea(&map, insn_info[iip].dp->smode, - insn_info[iip].dp->sreg, + insn_info[iip].dp->sreg, insn_info[iip].dp->size, &realpc, current_addr, - eainfo, EA_LOAD, &pub, 1); + eainfo, 0, EA_LOAD, 1); compile_prepareea(&map, insn_info[iip].dp->dmode, - insn_info[iip].dp->dreg, + insn_info[iip].dp->dreg, sz_long, &realpc, current_addr, - eainfo + 1, EA_IN_REG | EA_LOAD | EA_STORE, - &pub, 1); + eainfo, 1, + (insn_info[iip].dp->mnemo == i_ADDA || insn_info[iip].dp->mnemo == i_SUBA + ? EA_MODIFY | EA_LOAD | EA_STORE + : EA_LOAD | EA_STORE), + 1); generate_possible_exit(&map, eainfo, iip, &pub); - srcreg2 = compile_fetchea(&map, eainfo + 0, &srcoffs); - dstreg = compile_fetchea(&map, eainfo + 1, &dstoffs); - srcreg = compile_move_const_reg(&map, srcreg2, &srcoffs, 0); - compile_unlock_reg(&map, srcreg2); - srcreg2 = compile_extend_long(&map, srcreg, &srcoffs, eainfo[0].size); - compile_unlock_reg(&map, srcreg); - compile_offset_reg(&map, dstreg, dstoffs); - - compile_force_byteorder(&map, srcreg2, BO_NORMAL, 0); - compile_force_byteorder(&map, dstreg, BO_NORMAL, 0); + compile_loadeas(&map, eainfo, 0, 1, + insn_info[iip].dp->size == sz_word ? binop_worda_alternatives : binop_alternatives, + 0, 1); + + if (insn_info[iip].dp->size == sz_word) { + remove_x86r_from_cache(&map, eainfo[0].data_reg, 0); + compile_extend_long(&map, eainfo[0].data_reg, sz_word); + } + eainfo[0].size = sz_long; switch (insn_info[iip].dp->mnemo) { - case i_ADDA: assemble(0x01); break; - case i_SUBA: assemble(0x29); break; - case i_CMPA: assemble(0x39); break; + case i_ADDA: compile_eas(&map, eainfo, 0, 1, 0); break; + case i_SUBA: compile_eas(&map, eainfo, 0, 1, 5); break; + case i_CMPA: compile_eas(&map, eainfo, 0, 1, 7); break; } - assemble(0xC0 + srcreg2*8 + dstreg); if (insn_info[iip].dp->mnemo == i_CMPA) { cc_status = CC_Z_FROM_86Z |CC_C_FROM_86C |CC_V_FROM_86V |CC_N_FROM_86N; } else { - compile_storeea(&map, eainfo + 1, dstreg, 0); + compile_note_modify(&map, eainfo, 1); cc_status = 0; } break; case i_MOVE: + compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub); + compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub); compile_prepareea(&map, insn_info[iip].dp->smode, - insn_info[iip].dp->sreg, + insn_info[iip].dp->sreg, insn_info[iip].dp->size, &realpc, current_addr, - eainfo, EA_LOAD, &pub, 1); + eainfo, 0, EA_LOAD, 1); compile_prepareea(&map, insn_info[iip].dp->dmode, - insn_info[iip].dp->dreg, + insn_info[iip].dp->dreg, insn_info[iip].dp->size, &realpc, current_addr, - eainfo + 1, EA_STORE, &pub, 1); + eainfo, 1, EA_STORE, 1); generate_possible_exit(&map, eainfo, iip, &pub); generate_possible_exit(&map, eainfo + 1, iip, &pub); - - srcreg = compile_fetchea(&map, eainfo + 0, &srcoffs); - compile_storeea(&map, eainfo + 1, srcreg, srcoffs); - cc_status = CC_TEST_REG; - cc_reg = srcreg; - cc_offset = srcoffs; + + compile_loadeas(&map, eainfo, 0, 1, binop_alternatives, 1, 0); + compile_storeea(&map, eainfo, 0, 1); + + if (eainfo[0].data_reg == -2) { + cc_status = CC_TEST_REG; + cc_reg = -2; + cc_offset = eainfo[0].data_const_off; + } else if (eainfo[0].data_reg == -1) { + if (eainfo[1].data_reg == -1) + printf("Don't know where to get flags from\n"); + cc_status = CC_TEST_REG; + cc_offset = 0; + cc_reg = eainfo[1].data_reg; + } else { + cc_status = CC_TEST_REG; + cc_reg = eainfo[0].data_reg; + cc_offset = 0; + } cc_size = eainfo[0].size; - + break; case i_MOVEA: + compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub); + compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub); compile_prepareea(&map, insn_info[iip].dp->smode, - insn_info[iip].dp->sreg, + insn_info[iip].dp->sreg, insn_info[iip].dp->size, &realpc, current_addr, - eainfo, EA_LOAD, &pub, 1); + eainfo, 0, EA_LOAD, 1); compile_prepareea(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, sz_long, &realpc, current_addr, - eainfo + 1, EA_STORE, &pub, 1); + eainfo, 1, EA_STORE, 1); generate_possible_exit(&map, eainfo, iip, &pub); - - srcreg = compile_fetchea(&map, eainfo, &srcoffs); - srcreg2 = compile_extend_long(&map, srcreg, &srcoffs, eainfo[0].size); - compile_unlock_reg(&map, srcreg); - compile_storeea(&map, eainfo + 1, srcreg2, srcoffs); + + compile_loadeas(&map, eainfo, 0, 1, + insn_info[iip].dp->size == sz_word ? binop_worda_alternatives : binop_alternatives, + 0, 0); + + if (insn_info[iip].dp->size == sz_word) { + remove_x86r_from_cache(&map, eainfo[0].data_reg, 0); + compile_extend_long(&map, eainfo[0].data_reg, sz_word); + } + eainfo[0].size = sz_long; + + compile_storeea(&map, eainfo, 0, 1); cc_status = 0; break; case i_EXG: - compile_prepareea(&map, insn_info[iip].dp->smode, - insn_info[iip].dp->sreg, - sz_long, &realpc, current_addr, - eainfo, EA_LOAD|EA_STORE, &pub, 1); - compile_prepareea(&map, insn_info[iip].dp->dmode, - insn_info[iip].dp->dreg, - sz_long, &realpc, current_addr, - eainfo + 1, EA_LOAD|EA_STORE, &pub, 1); + if (insn_info[iip].dp->smode != insn_info[iip].dp->dmode + || insn_info[iip].dp->sreg != insn_info[iip].dp->dreg) + { + compile_prepareea(&map, insn_info[iip].dp->smode, + insn_info[iip].dp->sreg, + sz_long, &realpc, current_addr, + eainfo, 0, EA_LOAD|EA_STORE, 1); + compile_prepareea(&map, insn_info[iip].dp->dmode, + insn_info[iip].dp->dreg, + sz_long, &realpc, current_addr, + eainfo, 1, EA_LOAD|EA_STORE, 1); - srcreg = compile_fetchea(&map, eainfo, &srcoffs); - dstreg = compile_fetchea(&map, eainfo+1, &dstoffs); - compile_unlock_reg(&map, srcreg); - compile_storeea(&map, eainfo + 1, srcreg, srcoffs); - compile_storeea(&map, eainfo, dstreg, dstoffs); + compile_loadeas(&map, eainfo, 0, 1, regonly_alternatives, 0, 1); + compile_storeea(&map, eainfo, 1, 0); + compile_storeea(&map, eainfo, 0, 1); + } cc_status = 0; break; - + case i_LINK: + compile_prepare_undo(&map, Apdi, 7, &pub); compile_prepareea(&map, insn_info[iip].dp->smode, - insn_info[iip].dp->sreg, + insn_info[iip].dp->sreg, sz_long, &realpc, current_addr, - eainfo, EA_LOAD|EA_STORE, &pub, 1); + eainfo, 0, EA_LOAD|EA_STORE, 1); compile_prepareea(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, sz_long, &realpc, current_addr, - eainfo + 1, EA_LOAD, &pub, 1); + eainfo, 1, EA_LOAD, 1); compile_prepareea(&map, Apdi, 7, sz_long, &realpc, current_addr, - eainfo + 2, EA_STORE, &pub, 1); + eainfo, 2, EA_STORE, 1); generate_possible_exit(&map, eainfo+2, iip, &pub); - srcreg = compile_fetchea(&map, eainfo + 0, &srcoffs); - dstreg = compile_fetchea(&map, eainfo + 1, &dstoffs); - compile_storeea(&map, eainfo + 2, srcreg, srcoffs); + compile_fetchea(&map, eainfo, 0, 1); + /* we know this is a constant - no need to fetch it*/ + /* compile_fetchea(&map, eainfo, 1); */ + compile_storeea(&map, eainfo, 0, 2); /* An -> -(A7) */ compile_prepareea(&map, Areg, 7, sz_long, &realpc, current_addr, - eainfo + 3, EA_STORE, &pub, 1); - srcreg = compile_fetchea(&map, eainfo + 3, &srcoffs); - compile_storeea(&map, eainfo + 0, srcreg, srcoffs); + eainfo, 3, EA_STORE, 1); + compile_fetchea(&map, eainfo, 3, 1); + compile_storeea(&map, eainfo, 3, 0); /* A7 -> An */ + /* @@@ 020 */ - compile_storeea(&map, eainfo + 3, srcreg, srcoffs+(WORD)dstoffs); + compile_prepareea(&map, Areg, 7, sz_long, &realpc, current_addr, + eainfo, 4, EA_LOAD, 1); + compile_prepareea(&map, Areg, 7, sz_long, &realpc, current_addr, + eainfo, 5, EA_STORE, 1); + compile_fetchea(&map, eainfo, 4, 1); + eainfo[4].data_const_off += (uae_s16)eainfo[1].data_const_off; + compile_storeea(&map, eainfo, 4, 5); /* A7+off -> A7 */ cc_status = 0; break; - + case i_UNLK: - compile_prepareea(&map, insn_info[iip].dp->smode, - insn_info[iip].dp->sreg, - sz_long, &realpc, current_addr, - eainfo, EA_LOAD|EA_STORE, &pub, 1); - compile_prepareea(&map, Aind, - insn_info[iip].dp->sreg, + compile_prepareea(&map, Areg, + insn_info[iip].dp->sreg, sz_long, &realpc, current_addr, - eainfo + 1, EA_LOAD, &pub, 1); + eainfo, 0, EA_LOAD, 1); + compile_prepareea(&map, Areg, 7, sz_long, &realpc, current_addr, + eainfo, 1, EA_STORE, 1); - generate_possible_exit(&map, eainfo+1, iip, &pub); + generate_possible_exit(&map, eainfo + 0, iip, &pub); - compile_prepareea(&map, Areg, 7, sz_long, &realpc, current_addr, - eainfo + 3, EA_STORE, &pub, 1); - srcreg = compile_fetchea(&map, eainfo + 1, &srcoffs); - dstreg = compile_fetchea(&map, eainfo + 0, &dstoffs); - compile_storeea(&map, eainfo + 0, srcreg, srcoffs); - compile_storeea(&map, eainfo + 3, dstreg, dstoffs+4); - cc_status = 0; + compile_fetchea(&map, eainfo, 0, 1); + compile_storeea(&map, eainfo, 0, 1); + + /* The Apdi could of course point to a non-memory area, but undos + * are difficult here, and anyway: which program does evil hacks + * with UNLK? */ + compile_prepareea(&map, Aipi, 7, sz_long, &realpc, current_addr, + eainfo, 2, EA_LOAD, 1); + compile_prepareea(&map, insn_info[iip].dp->smode, + insn_info[iip].dp->sreg, + sz_long, &realpc, current_addr, + eainfo, 3, EA_STORE, 1); + compile_fetchea(&map, eainfo, 2, 1); + compile_storeea(&map, eainfo, 2, 3); + + cc_status = 0; break; case i_OR: case i_AND: case i_EOR: + compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub); + compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub); compile_prepareea(&map, insn_info[iip].dp->smode, - insn_info[iip].dp->sreg, + insn_info[iip].dp->sreg, insn_info[iip].dp->size, &realpc, current_addr, - eainfo, EA_LOAD, &pub, 1); + eainfo, 0, EA_LOAD, 1); compile_prepareea(&map, insn_info[iip].dp->dmode, - insn_info[iip].dp->dreg, + insn_info[iip].dp->dreg, insn_info[iip].dp->size, &realpc, current_addr, - eainfo + 1, EA_IN_REG | EA_LOAD | EA_STORE, &pub, 1); + eainfo, 1, EA_MODIFY | EA_LOAD | EA_STORE, 1); generate_possible_exit(&map, eainfo, iip, &pub); generate_possible_exit(&map, eainfo + 1, iip, &pub); - - szflag = insn_info[iip].dp->size == sz_byte ? 0 : 1; - srcreg = compile_fetchea(&map, eainfo + 0, &srcoffs); - dstreg = compile_fetchea(&map, eainfo + 1, &dstoffs); - - srcreg2 = compile_move_const_reg(&map, srcreg, &srcoffs, insn_info[iip].dp->size == sz_byte ? DATA_X86_REGS : 0); - compile_unlock_reg(&map, srcreg); - compile_offset_reg(&map, dstreg, dstoffs); - compile_force_byteorder(&map, srcreg2, BO_NORMAL, 0); - compile_force_byteorder(&map, dstreg, BO_NORMAL, 0); + compile_loadeas(&map, eainfo, 0, 1, binop_alternatives, 0, 1); - if (insn_info[iip].dp->size == sz_word) - assemble(0x66); switch (insn_info[iip].dp->mnemo) { - case i_AND: assemble(0x20+szflag); break; - case i_EOR: assemble(0x30+szflag); break; - case i_OR: assemble(0x08+szflag); break; - } - assemble(0xC0 + srcreg2*8 + dstreg); - compile_storeea(&map, eainfo + 1, dstreg, 0); - cc_status = CC_Z_FROM_86Z |CC_C_FROM_86C |CC_V_FROM_86V |CC_N_FROM_86N; - break; - - case i_BTST: - case i_BSET: - case i_BCLR: - case i_BCHG: - compile_prepareea(&map, insn_info[iip].dp->smode, - insn_info[iip].dp->sreg, - insn_info[iip].dp->size, &realpc, current_addr, - eainfo, EA_LOAD, &pub, 1); - compile_prepareea(&map, insn_info[iip].dp->dmode, - insn_info[iip].dp->dreg, - insn_info[iip].dp->size, &realpc, current_addr, - eainfo + 1, 0, &pub, 1); - - generate_possible_exit(&map, eainfo, iip, &pub); - generate_possible_exit(&map, eainfo + 1, iip, &pub); + case i_AND: compile_eas(&map, eainfo, 0, 1, 4); break; + case i_EOR: compile_eas(&map, eainfo, 0, 1, 6); break; + case i_OR: compile_eas(&map, eainfo, 0, 1, 1); break; + } - handle_bit_insns(&map, eainfo, eainfo + 1, insn_info[iip].dp->mnemo); + compile_note_modify(&map, eainfo, 1); + cc_status = CC_Z_FROM_86Z | CC_C_FROM_86C | CC_V_FROM_86V | CC_N_FROM_86N; break; - + case i_TST: + compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub); compile_prepareea(&map, insn_info[iip].dp->smode, - insn_info[iip].dp->sreg, + insn_info[iip].dp->sreg, insn_info[iip].dp->size, &realpc, current_addr, - eainfo, EA_LOAD, &pub, 1); + eainfo, 0, EA_LOAD, 1); generate_possible_exit(&map, eainfo, iip, &pub); - - srcreg = compile_fetchea(&map, eainfo + 0, &srcoffs); + + compile_fetchea(&map, eainfo, 0, 1); cc_status = CC_TEST_REG; - cc_reg = srcreg; - cc_offset = srcoffs; + cc_reg = eainfo[0].data_reg; + cc_offset = 0; cc_size = eainfo[0].size; break; - + case i_CLR: + compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub); compile_prepareea(&map, insn_info[iip].dp->smode, - insn_info[iip].dp->sreg, + insn_info[iip].dp->sreg, insn_info[iip].dp->size, &realpc, current_addr, - eainfo, EA_STORE, &pub, 1); - - generate_possible_exit(&map, eainfo, iip, &pub); - - compile_storeea(&map, eainfo + 0, -2, 0); + eainfo, 0, EA_STORE, 1); + compile_prepareea(&map, immi, 0, sz_long, &realpc, current_addr, + eainfo, 1, EA_LOAD, 1); + generate_possible_exit(&map, eainfo + 0, iip, &pub); + compile_loadeas(&map, eainfo, 1, 0, binop_alternatives, 1, 0); + compile_storeea(&map, eainfo, 1, 0); cc_status = CC_TEST_REG; cc_reg = -2; @@ -3274,16 +4169,15 @@ static int m68k_compile_block(struct has break; case i_EXT: + /* No exits, no undo - this is always a Dreg; fetchea will get it in a reg + * without offset */ compile_prepareea(&map, insn_info[iip].dp->smode, - insn_info[iip].dp->sreg, + insn_info[iip].dp->sreg, insn_info[iip].dp->size == sz_long ? sz_word : sz_byte, &realpc, current_addr, - eainfo, EA_LOAD|EA_STORE, &pub, 1); - /* No exits - this is always a Dreg; fetchea will get it in a reg - * without offset */ - srcreg = compile_fetchea(&map, eainfo + 0, &srcoffs); - - compile_force_byteorder(&map, srcreg, BO_NORMAL, 0); + eainfo, 0, EA_LOAD|EA_STORE, 1); + compile_fetchea(&map, eainfo, 0, 1); + compile_force_byteorder(&map, eainfo[0].data_reg, BO_NORMAL, 0); if (insn_info[iip].dp->size == sz_word) assemble(0x66); @@ -3292,149 +4186,161 @@ static int m68k_compile_block(struct has assemble(0xBF); else assemble(0xBE); - - assemble(0xC0 + 9*srcreg); - map.x86_dirty[srcreg] = 1; + + assemble(0xC0 + 9*eainfo[0].data_reg); + map.x86_dirty[eainfo[0].data_reg] = 1; cc_status = CC_TEST_REG; - cc_reg = srcreg; - cc_offset = srcoffs; - cc_size = eainfo[0].size; + cc_reg = eainfo[0].data_reg; + cc_offset = 0; + cc_size = eainfo[0].size; break; case i_NOT: case i_NEG: szflag = insn_info[iip].dp->size == sz_byte ? 0 : 1; + compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub); compile_prepareea(&map, insn_info[iip].dp->smode, - insn_info[iip].dp->sreg, + insn_info[iip].dp->sreg, insn_info[iip].dp->size, &realpc, current_addr, - eainfo, EA_LOAD|EA_STORE, &pub, 1); + eainfo, 0, EA_LOAD|EA_STORE, 1); generate_possible_exit(&map, eainfo, iip, &pub); - - srcreg = compile_fetchea(&map, eainfo + 0, &srcoffs); - srcreg2 = compile_move_const_reg(&map, srcreg, &srcoffs, insn_info[iip].dp->size == sz_byte ? DATA_X86_REGS : 0); - compile_unlock_reg(&map, srcreg); - compile_force_byteorder(&map, srcreg2, BO_NORMAL, 0); + compile_fetchea(&map, eainfo, 0, 1); + compile_force_byteorder(&map, eainfo[0].data_reg, BO_NORMAL, 0); if (insn_info[iip].dp->size == sz_word) assemble(0x66); assemble(0xF6 + szflag); - - assemble(0xC0 + srcreg2 + 8*(insn_info[iip].dp->mnemo == i_NOT ? 2 : 3)); - compile_storeea(&map, eainfo, srcreg, 0); - cc_status = CC_TEST_REG; - cc_reg = srcreg; - cc_offset = 0; - cc_size = eainfo[0].size; + assemble(0xC0 + eainfo[0].data_reg + 8*(insn_info[iip].dp->mnemo == i_NOT ? 2 : 3)); + compile_note_modify(&map, eainfo, 0); + + if (insn_info[iip].dp->mnemo == i_NEG) + cc_status = CC_Z_FROM_86Z | CC_C_FROM_86C | CC_V_FROM_86V | CC_N_FROM_86N | CC_X_FROM_86C; + else { + cc_status = CC_TEST_REG; + cc_reg = eainfo[0].data_reg; + cc_offset = 0; + cc_size = eainfo[0].size; + } break; case i_SWAP: + /* No exits, no undo - this is always a Dreg; fetchea will get it in a reg + * without offset */ compile_prepareea(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, sz_long, &realpc, current_addr, - eainfo, EA_LOAD|EA_STORE, &pub, 1); - /* No exits - this is always a Dreg; fetchea will get it in a reg - * without offset */ - srcreg = compile_fetchea(&map, eainfo + 0, &srcoffs); + eainfo, 0, EA_LOAD|EA_STORE, 1); + + compile_fetchea(&map, eainfo, 0, 1); + compile_force_byteorder(&map, eainfo[0].data_reg, BO_NORMAL, 0); - compile_force_byteorder(&map, srcreg, BO_NORMAL, 0); /* roll $16, srcreg */ - assemble(0xC1); assemble(0xC0 + srcreg); assemble(16); + assemble(0xC1); assemble(0xC0 + eainfo[0].data_reg); assemble(16); - map.x86_dirty[srcreg] = 1; + /* @@@ un-shortcut */ + map.x86_dirty[eainfo[0].data_reg] = 1; cc_status = CC_TEST_REG; - cc_reg = srcreg; - cc_offset = srcoffs; - cc_size = eainfo[0].size; + cc_reg = eainfo[0].data_reg; + cc_offset = 0; + cc_size = eainfo[0].size; break; - + case i_LEA: + /* No exits necessary here: never touches memory */ compile_prepareea(&map, insn_info[iip].dp->smode, - insn_info[iip].dp->sreg, + insn_info[iip].dp->sreg, insn_info[iip].dp->size, &realpc, current_addr, - eainfo, 0, &pub, 1); + eainfo, 0, 0, 1); + eainfo[0].data_reg = eainfo[0].address_reg; + eainfo[0].data_const_off = eainfo[0].addr_const_off; + eainfo[0].address_reg = -1; + compile_get_excl_lock(&map, eainfo + 0); compile_prepareea(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, sz_long, &realpc, current_addr, - eainfo + 1, EA_STORE, &pub, 1); - compile_storeea(&map, eainfo + 1, eainfo[0].address_reg, - eainfo[0].addr_const_off); + eainfo, 1, EA_STORE, 1); + compile_storeea(&map, eainfo, 0, 1); cc_status = 0; break; case i_PEA: + compile_prepare_undo(&map, Apdi, 7, &pub); compile_prepareea(&map, insn_info[iip].dp->smode, - insn_info[iip].dp->sreg, + insn_info[iip].dp->sreg, insn_info[iip].dp->size, &realpc, current_addr, - eainfo, 0, &pub, 1); + eainfo, 0, 0, 1); + eainfo[0].data_reg = eainfo[0].address_reg; + eainfo[0].data_const_off = eainfo[0].addr_const_off; + eainfo[0].address_reg = -1; + compile_get_excl_lock(&map, eainfo + 0); compile_prepareea(&map, Apdi, 7, sz_long, &realpc, current_addr, - eainfo + 1, EA_STORE, &pub, 1); + eainfo, 1, EA_STORE, 1); generate_possible_exit(&map, eainfo+1, iip, &pub); + compile_storeea(&map, eainfo, 0, 1); - compile_storeea(&map, eainfo + 1, eainfo[0].address_reg, - eainfo[0].addr_const_off); cc_status = 0; break; case i_MVMEL: compile_prepareea(&map, insn_info[iip].dp->smode, - insn_info[iip].dp->sreg, + insn_info[iip].dp->sreg, sz_word, &realpc, current_addr, - eainfo, EA_LOAD, &pub, 1); + eainfo, 0, EA_LOAD, 1); sync_reg_cache(&map, 0); { /* Scratch 0 holds the registers while they are being moved * from/to memory. Scratch 1 points at regs.d. Scratch 2 * points at the base addr in memory where to fetch data - * from + * from. */ int scratch0, scratch1, scratch2; - UWORD mask = eainfo[0].data_const_off; + uae_u16 mask = eainfo[0].data_const_off; int bits = count_bits(mask); int size = insn_info[iip].dp->size == sz_long ? 4 : 2; int i; - UBYTE x86amode; - ULONG current_offs = 0; - + uae_u8 x86amode; + uae_u32 current_offs = 0; + + compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub); /* !!! Note current_addr + 2 here! */ compile_prepareea(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, insn_info[iip].dp->size, &realpc, current_addr + 2, - eainfo + 1, EA_LOAD, &pub, bits); - + eainfo, 1, EA_LOAD, bits); + generate_possible_exit(&map, eainfo + 1, iip, &pub); scratch0 = get_free_x86_register(&map, ADDRESS_X86_REGS); - map.x86_locked[scratch0]++; + lock_reg(&map, scratch0, 2); scratch1 = get_free_x86_register(&map, ADDRESS_X86_REGS); - map.x86_locked[scratch1]++; + lock_reg(&map, scratch1, 2); scratch2 = get_free_x86_register(&map, ADDRESS_X86_REGS); - map.x86_locked[scratch2]++; + lock_reg(&map, scratch2, 2); compile_force_byteorder(&map, eainfo[1].address_reg, BO_NORMAL, 0); - - compile_lea_reg_with_offset(scratch1, -2, (ULONG)regs.d); + + compile_lea_reg_with_offset(scratch1, -2, (uae_u32)regs.regs); compile_lea_reg_with_offset(scratch2, eainfo[1].address_reg, - (ULONG)(address_space + eainfo[1].addr_const_off)); + (uae_u32)(address_space + eainfo[1].addr_const_off)); for (i = 0; i < 16; i++) { - int r68k = i & 7; - ULONG *regp = i < 8 ? regs.d : regs.a; + int r68k = i; int *cache68k = i < 8 ? map.dreg_map : map.areg_map; - if (mask & 1 - && (i < 8 + if (mask & 1 + && (i < 8 || insn_info[iip].dp->dmode != Aipi - || r68k != insn_info[iip].dp->dreg)) { - int tmpr = cache68k[r68k]; - + || (r68k & 7) != insn_info[iip].dp->dreg)) { + int tmpr = cache68k[r68k & 7]; + if (tmpr != -1) { - cache68k[r68k] = -1; + cache68k[r68k & 7] = -1; map.x86_cache_reg[tmpr] = -1; } compile_move_reg_from_mem_regoffs(scratch0, scratch2, @@ -3450,7 +4356,7 @@ static int m68k_compile_block(struct has assemble(0x0F); /* bswapl scratch0 */ assemble(0xC8 + scratch0); } - compile_move_reg_to_mem_regoffs(scratch1, (char *)(regp + r68k) - (char *)regs.d, + compile_move_reg_to_mem_regoffs(scratch1, (char *)(regs.regs + r68k) - (char *)regs.regs, scratch0, sz_long); } if (mask & 1) @@ -3463,52 +4369,58 @@ static int m68k_compile_block(struct has case i_MVMLE: compile_prepareea(&map, insn_info[iip].dp->smode, - insn_info[iip].dp->sreg, + insn_info[iip].dp->sreg, sz_word, &realpc, current_addr, - eainfo, EA_LOAD, &pub, 1); + eainfo, 0, EA_LOAD, 1); sync_reg_cache(&map, 0); { int scratch0,scratch1,scratch2; - UWORD mask = eainfo[0].data_const_off; + uae_u16 mask = eainfo[0].data_const_off; int bits = count_bits(mask); int size = insn_info[iip].dp->size == sz_long ? 4 : 2; int i; - UBYTE x86amode; - ULONG current_offs = 0; - int addrareg = get_and_lock_68k_reg(&map, insn_info[iip].dp->dreg, - 0, 0, 1); - compile_force_byteorder(&map, addrareg, BO_NORMAL, 0); + uae_u8 x86amode; + uae_u32 current_offs = 0; + int addrareg = -1; + if (insn_info[iip].dp->dmode == Aind + || insn_info[iip].dp->dmode == Apdi + || insn_info[iip].dp->dmode == Aipi + || insn_info[iip].dp->dmode == Ad16 + || insn_info[iip].dp->dmode == Ad8r) + { + addrareg = get_and_lock_68k_reg(&map, insn_info[iip].dp->dreg, 0, ADDRESS_X86_REGS, 1, 2); + compile_force_byteorder(&map, addrareg, BO_NORMAL, 0); + } if (insn_info[iip].dp->dmode == Apdi) mask = bitswap(mask); /* !!! Note current_addr + 2 here! */ + compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub); compile_prepareea(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, insn_info[iip].dp->size, &realpc, current_addr + 2, - eainfo + 1, EA_STORE, &pub, bits); - + eainfo, 1, EA_STORE, bits); + generate_possible_exit(&map, eainfo + 1, iip, &pub); scratch0 = get_free_x86_register(&map, ADDRESS_X86_REGS); - map.x86_locked[scratch0]++; + lock_reg(&map, scratch0, 2); scratch1 = get_free_x86_register(&map, ADDRESS_X86_REGS); - map.x86_locked[scratch1]++; + lock_reg(&map, scratch1, 2); scratch2 = get_free_x86_register(&map, ADDRESS_X86_REGS); - map.x86_locked[scratch2]++; + lock_reg(&map, scratch2, 2); compile_force_byteorder(&map, eainfo[1].address_reg, BO_NORMAL, 0); - compile_lea_reg_with_offset(scratch1, -2, (ULONG)regs.d); + compile_lea_reg_with_offset(scratch1, -2, (uae_u32)regs.regs); compile_lea_reg_with_offset(scratch2, eainfo[1].address_reg, - (ULONG)(address_space + eainfo[1].addr_const_off)); + (uae_u32)(address_space + eainfo[1].addr_const_off)); for (i = 0; i < 16; i++) { - int r68k = i & 7; - ULONG *regp = i < 8 ? regs.d : regs.a; - int *cache68k = i < 8 ? map.dreg_map : map.areg_map; + int r68k = i; if (mask & 1) { /* move from 68k reg */ - if (i < 8 || r68k != insn_info[iip].dp->dreg) { - compile_move_reg_from_mem_regoffs(scratch0, scratch1, (char *)(regp + r68k) - (char *)regs.d, + if (i < 8 || (i & 7) != insn_info[iip].dp->dreg || addrareg == -1) { + compile_move_reg_from_mem_regoffs(scratch0, scratch1, (char *)(regs.regs + r68k) - (char *)regs.regs, sz_long); } else { assemble(0x8B); assemble(0xC0 + 8*scratch0 + addrareg); @@ -3532,27 +4444,53 @@ static int m68k_compile_block(struct has } cc_status = 0; break; +#if 1 + case i_BTST: + case i_BSET: + case i_BCLR: + case i_BCHG: + compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub); + compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub); + compile_prepareea(&map, insn_info[iip].dp->smode, + insn_info[iip].dp->sreg, + insn_info[iip].dp->size, &realpc, current_addr, + eainfo, 0, EA_LOAD, 1); + compile_prepareea(&map, insn_info[iip].dp->dmode, + insn_info[iip].dp->dreg, + insn_info[iip].dp->size, &realpc, current_addr, + eainfo, 1, 0, 1); + + generate_possible_exit(&map, eainfo, iip, &pub); + generate_possible_exit(&map, eainfo + 1, iip, &pub); + + handle_bit_insns(&map, eainfo, 0, 1, insn_info[iip].dp->mnemo); + break; - case i_ASL: case i_ASR: case i_LSL: case i_LSR: + case i_ASL: case i_ASR: case i_LSL: case i_LSR: case i_ROL: case i_ROR: case i_ROXL:case i_ROXR: - case i_ASLW: case i_ASRW: case i_LSLW: case i_LSRW: + if (insn_info[iip].dp->smode == Dreg && do_rotshi) { + handle_rotshi_variable(&map, iip, realpc, current_addr, &pub); + break; + } + /* fall through */ + case i_ASLW: case i_ASRW: case i_LSLW: case i_LSRW: case i_ROLW: case i_RORW: case i_ROXLW:case i_ROXRW: if (do_rotshi) { - handle_rotshi(&map, iip, realpc, current_addr); + handle_rotshi(&map, iip, realpc, current_addr, &pub); break; } - +#endif default: generate_exit(&map, insn_info[iip].address); cc_status = 0; break; } if (insn_info[iip].ccuser_follows) - cc_status_for_bcc = compile_flush_cc_cache(&map, cc_status, + cc_status_for_bcc = compile_flush_cc_cache(&map, cc_status, insn_info[iip].flags_live_at_end, 1, insn_info[iip+1].flags_live_at_end, insn_info[iip+1].dp->cc); else - cc_status_for_bcc = compile_flush_cc_cache(&map, cc_status, + cc_status_for_bcc = compile_flush_cc_cache(&map, cc_status, insn_info[iip].flags_live_at_end, 0, 0, 0); @@ -3571,9 +4509,9 @@ static int m68k_compile_block(struct has { int needed_len = compile_here() - hb->compile_start; int allocsize = (needed_len + PAGE_SUBUNIT - 1) & ~(PAGE_SUBUNIT-1); - ULONG allocmask; + uae_u32 allocmask; int allocbits; - + allocbits = (allocsize >> SUBUNIT_ORDER); allocmask = (1 << allocbits) - 1; while ((allocmask & hb->page_allocmask) != allocmask) @@ -3585,7 +4523,7 @@ static int m68k_compile_block(struct has hb->cpage->allocmask |= allocmask; } return 0; - + oops: if (1 || !quiet_compile) fprintf(stderr, "Compile failed!\n"); @@ -3594,7 +4532,7 @@ static int m68k_compile_block(struct has hb->untranslatable = 1; { struct hash_entry *h = hb->he_first; - + do { h->execute = NULL; h = h->next_same_block; @@ -3603,6 +4541,13 @@ static int m68k_compile_block(struct has return 1; } +void compiler_init(void) +{ + code_init(); + hash_init(); + jsr_stack_init(); +} + /* * Why do compilers always have to be so complicated? And I thought GCC was * a mess...