Annotation of uae/src/compiler.c, revision 1.1

1.1     ! root        1:  /* 
        !             2:   * UAE - The Un*x Amiga Emulator
        !             3:   * 
        !             4:   * m68k emulation
        !             5:   *
        !             6:   * (c) 1995 Bernd Schmidt
        !             7:   */
        !             8: 
        !             9: #include "sysconfig.h"
        !            10: #include "sysdeps.h"
        !            11: 
        !            12: #include "config.h"
        !            13: #include "options.h"
        !            14: #include "events.h"
        !            15: #include "gui.h"
        !            16: #include "memory.h"
        !            17: #include "custom.h"
        !            18: #include "newcpu.h"
        !            19: #include "ersatz.h"
        !            20: #include "readcpu.h"
        !            21: #include "blitter.h"
        !            22: #include "debug.h"
        !            23: #include "autoconf.h"
        !            24: #include "compiler.h"
        !            25: 
        !            26: #define RELY_ON_LOADSEG_DETECTION
        !            27: 
        !            28: #ifdef USE_COMPILER
        !            29: 
        !            30: #include <sys/mman.h>
        !            31: 
        !            32: char *address_space, *good_address_map;
        !            33: 
        !            34: code_execfunc exec_me;
        !            35: UBYTE nr_bbs_to_run = 1;
        !            36: int nr_bbs_start = 40;
        !            37: 
        !            38: static int compile_failure;
        !            39: static int quiet_compile = 1;
        !            40: int i_want_to_die = 1;
        !            41: static int n_compiled = 0;
        !            42: static int n_max_comp = 99999999;
        !            43: static CPTR call_only_me = 0;
        !            44: 
        !            45: int patched_syscalls = 0;
        !            46: 
        !            47: static int count_bits(UWORD v)
        !            48: {
        !            49:     int bits = 0;
        !            50:     while (v != 0) {
        !            51:        if (v & 1)
        !            52:            bits++;
        !            53:        v >>= 1;
        !            54:     }
        !            55:     return bits;
        !            56: }
        !            57: 
        !            58: static UWORD bitswap(UWORD v)
        !            59: {
        !            60:     UWORD newv = 0;
        !            61:     UWORD m1 = 1, m2 = 0x8000;
        !            62:     int i;
        !            63:     
        !            64:     for (i = 0; i < 16; i++) {
        !            65:        if (v & m1)
        !            66:            newv |= m2;
        !            67:        m2 >>= 1;
        !            68:        m1 <<= 1;
        !            69:     }
        !            70:     return newv;
        !            71: }
        !            72: 
        !            73: static long long compiled_hits = 0;
        !            74: 
        !            75: /* @@@ FIXME: a defragmenter would be nice for this, but since we flush
        !            76:  * the cache all the time anyway to deal with LoadSegs() */
        !            77: 
        !            78: /* 16K areas with 512 byte blocks */
        !            79: #define SUBUNIT_ORDER 9
        !            80: #define PAGE_SUBUNIT (1 << SUBUNIT_ORDER)
        !            81: #define PAGE_ALLOC_UNIT (PAGE_SUBUNIT * 32)
        !            82: 
        !            83: static int zerofd;
        !            84: static int zeroff;
        !            85: static struct code_page *first_code_page;
        !            86: 
        !            87: static struct code_page *new_code_page(void)
        !            88: {
        !            89:     struct code_page *ncp;
        !            90:     
        !            91:     ncp = (struct code_page *)mmap(NULL, PAGE_ALLOC_UNIT, 
        !            92:                                   PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE,
        !            93:                                   zerofd, zeroff);
        !            94:     zeroff += PAGE_ALLOC_UNIT;
        !            95:     if (ncp) {
        !            96:        ncp->next = first_code_page;
        !            97:        first_code_page = ncp;
        !            98:        ncp->allocmask = 1; /* what a waste */
        !            99:     }
        !           100:     return ncp;
        !           101: }
        !           102: 
        !           103: #define NUM_HASH 1024
        !           104: #define NUM_FUNCTIONS 8192
        !           105: #define HASH_MASK (NUM_HASH-1)
        !           106: 
        !           107: static int SCAN_MARK = 5; /* Number of calls after which to scan a function */
        !           108: static int COMPILE_MARK = 50; /* Number of calls after which to compile a function */
        !           109: 
        !           110: static struct hash_entry cpu_hash[NUM_HASH];
        !           111: static struct hash_block lru_first_block;
        !           112: static struct hash_entry lru_first_hash;
        !           113: static struct hash_entry *freelist_hash;
        !           114: static struct hash_block *freelist_block;
        !           115: static struct hash_entry hash_entries[NUM_FUNCTIONS];
        !           116: 
        !           117: static int m68k_scan_func(struct hash_entry *);
        !           118: static int m68k_compile_block(struct hash_block *);
        !           119: 
        !           120: static char *alloc_code(struct hash_block *hb, int ninsns)
        !           121: {
        !           122:     struct code_page *cp;
        !           123:     long int allocsize = (ninsns * 32 + PAGE_SUBUNIT-1) & ~(PAGE_SUBUNIT-1);
        !           124:     ULONG allocmask;
        !           125:     int allocbits;
        !           126:     int j;
        !           127:     int last_bit;
        !           128: 
        !           129:     if (allocsize >= (PAGE_ALLOC_UNIT - (1 << SUBUNIT_ORDER)))
        !           130:        return NULL;
        !           131:     allocbits = (allocsize >> SUBUNIT_ORDER);
        !           132:     allocmask = (1 << allocbits) - 1;
        !           133:     
        !           134:     for (cp = first_code_page; cp != NULL; cp = cp->next) {
        !           135:        ULONG thispage_alloc = cp->allocmask;
        !           136:        for (j = 1; j < (33 - allocbits); j++) {
        !           137:            if ((cp->allocmask & (allocmask << j)) == 0) {
        !           138:                goto found_page;
        !           139:            }
        !           140:        }
        !           141:     }
        !           142: 
        !           143:     /* Nothing large enough free: make a new page */
        !           144:     cp = new_code_page();
        !           145:     if (cp == NULL)
        !           146:        return NULL;
        !           147:     j = 1;
        !           148:     
        !           149: found_page:
        !           150:     /* See whether there is in fact more space for us. If so, allocate all of
        !           151:      * it. compile_block() will free everything it didn't need. */
        !           152: 
        !           153:     allocmask <<= j;
        !           154:     last_bit = allocbits + j;
        !           155:     while (last_bit < 32 && (cp->allocmask & (1 << last_bit)) == 0) {
        !           156:        allocmask |= 1 << last_bit;
        !           157:        allocsize += PAGE_SUBUNIT;
        !           158:        last_bit++;
        !           159:     }
        !           160: 
        !           161:     hb->page_allocmask = allocmask;
        !           162:     hb->cpage = cp;
        !           163:     cp->allocmask |= allocmask;
        !           164:     hb->compile_start = ((char *)cp + (j << SUBUNIT_ORDER));
        !           165:     hb->alloclen = allocsize;
        !           166:     return hb->compile_start;
        !           167: }
        !           168: 
        !           169: static int remove_hash_from_lists(struct hash_entry *h)
        !           170: {
        !           171:     if (h->locked || h->cacheflush)
        !           172:        return 0;
        !           173: 
        !           174:     h->lru_next->lru_prev = h->lru_prev;
        !           175:     h->lru_prev->lru_next = h->lru_next;
        !           176:     
        !           177:     h->next->prev = h->prev;
        !           178:     h->prev->next = h->next;
        !           179:     return 1;
        !           180: }
        !           181: 
        !           182: static void forget_block(struct hash_block *hb)
        !           183: {
        !           184:     struct hash_entry *h = hb->he_first;
        !           185:     
        !           186:     hb->lru_next->lru_prev = hb->lru_prev;
        !           187:     hb->lru_prev->lru_next = hb->lru_next;
        !           188: 
        !           189:     hb->lru_next = freelist_block;
        !           190:     freelist_block = hb;
        !           191: 
        !           192:     if (hb->cpage != NULL)
        !           193:        fprintf(stderr, "Discarding block with code. Tsk.\n");
        !           194: 
        !           195:     do {
        !           196:        struct hash_entry *next = h->next_same_block;
        !           197:        h->block = NULL;
        !           198:        h->execute = NULL;
        !           199:        h->next_same_block = NULL;
        !           200:        h = next;
        !           201:     } while (h != hb->he_first);
        !           202: }
        !           203: 
        !           204: static void kill_lru_block(void)
        !           205: {
        !           206:     struct hash_block *hb = lru_first_block.lru_next;
        !           207:     struct hash_entry *h = hb->he_first;
        !           208:     
        !           209:     hb->lru_next->lru_prev = hb->lru_prev;
        !           210:     hb->lru_prev->lru_next = hb->lru_next;
        !           211: 
        !           212:     hb->lru_next = freelist_block;
        !           213:     freelist_block = hb;
        !           214:     
        !           215:     if (hb->cpage != NULL) {
        !           216:        hb->cpage->allocmask &= ~hb->page_allocmask;
        !           217:     }
        !           218:     do {
        !           219:        struct hash_entry *next = h->next_same_block;
        !           220:        if (remove_hash_from_lists(h)) {
        !           221:            h->next_same_block = freelist_hash;
        !           222:            freelist_hash = h;
        !           223:        } else {
        !           224:            h->block = NULL;
        !           225:            h->next_same_block = NULL;
        !           226:            h->execute = NULL;
        !           227:        }
        !           228:        h = next;
        !           229:     } while (h != hb->he_first);
        !           230: }
        !           231: 
        !           232: static void lru_touch_block(struct hash_block *h)
        !           233: {
        !           234:     h->lru_next->lru_prev = h->lru_prev;
        !           235:     h->lru_prev->lru_next = h->lru_next;
        !           236:     
        !           237:     h->lru_next = &lru_first_block;
        !           238:     h->lru_prev = lru_first_block.lru_prev;
        !           239:     h->lru_prev->lru_next = h;
        !           240:     lru_first_block.lru_prev = h;    
        !           241: }
        !           242: 
        !           243: static int check_block(struct hash_block *hb)
        !           244: {
        !           245: #ifndef RELY_ON_LOADSEG_DETECTION
        !           246:     struct hash_entry *h = hb->he_first;
        !           247:     
        !           248:     do {
        !           249:        struct hash_entry *next = h->next_same_block;
        !           250:        if (h->matchword != *(ULONG *)get_real_address(h->addr))
        !           251:            return 0;
        !           252:        h = next;
        !           253:     } while (h != hb->he_first);
        !           254: #endif
        !           255:     return 1;
        !           256: }
        !           257: 
        !           258: ULONG flush_icache(void)
        !           259: {
        !           260:     struct hash_block *hb = lru_first_block.lru_next;
        !           261:     
        !           262:     while (hb != &lru_first_block) {
        !           263:        struct hash_block *next = hb->lru_next;
        !           264:        if (hb->cpage != NULL) {
        !           265:            /* Address in chipmem? Then forget about block*/
        !           266:            if ((hb->he_first->addr & ~0xF80000) != 0xF80000) {
        !           267:                hb->cpage->allocmask &= ~hb->page_allocmask;
        !           268:                hb->cpage = NULL;
        !           269:                forget_block(hb);
        !           270:            }
        !           271:        }
        !           272:        hb = next;
        !           273:     }
        !           274:     return regs.d[0];
        !           275: }
        !           276: 
        !           277: void possible_loadseg(void)
        !           278: {
        !           279:     fprintf(stderr, "Possible LoadSeg() detected\n");
        !           280:     flush_icache();
        !           281: }
        !           282: 
        !           283: static struct hash_block *new_block(void)
        !           284: {
        !           285:     struct hash_block *b = freelist_block;
        !           286:     
        !           287:     if (b != NULL) {
        !           288:        freelist_block = b->lru_next;
        !           289:     } else
        !           290:        b = (struct hash_block *)malloc(sizeof *b);
        !           291:     b->nrefs = 0;
        !           292:     b->cpage = NULL;
        !           293:     b->he_first = NULL;
        !           294:     b->translated = b->untranslatable = b->allocfailed = 0;
        !           295:     return b;
        !           296: }
        !           297: 
        !           298: static struct hash_entry *get_free_hash(void)
        !           299: {
        !           300:     struct hash_entry *h;
        !           301: 
        !           302:     for (;;) {
        !           303:        h = freelist_hash;
        !           304:        if (h != NULL) {
        !           305:            freelist_hash = h->next_same_block;
        !           306:            break;
        !           307:        } 
        !           308:        h = lru_first_hash.lru_next;
        !           309:        if (h->block == NULL) {
        !           310:            remove_hash_from_lists(h);
        !           311:            break;
        !           312:        }
        !           313:        kill_lru_block();
        !           314:     }
        !           315:     h->block = NULL;
        !           316:     h->ncalls = 0;
        !           317:     h->locked = h->cacheflush = 0;
        !           318:     h->execute = NULL;
        !           319:     return h;
        !           320: }
        !           321: 
        !           322: static struct hash_entry *new_hash(CPTR addr)
        !           323: {
        !           324:     struct hash_entry *h = get_free_hash();
        !           325:     
        !           326:     h->addr = addr;
        !           327: 
        !           328:     /* Chain the new node */
        !           329:     h->prev = cpu_hash + ((addr >> 1) & HASH_MASK);
        !           330:     h->next = h->prev->next;
        !           331:     h->next->prev = h->prev->next = h;
        !           332: 
        !           333:     h->lru_next = &lru_first_hash;
        !           334:     h->lru_prev = lru_first_hash.lru_prev;
        !           335:     h->lru_prev->lru_next = h;
        !           336:     lru_first_hash.lru_prev = h;
        !           337:     
        !           338:     h->next_same_block = NULL;
        !           339: 
        !           340:     return h;
        !           341: }
        !           342: 
        !           343: static void lru_touch(struct hash_entry *h)
        !           344: {
        !           345:     if (0) {
        !           346:     h->lru_next->lru_prev = h->lru_prev;
        !           347:     h->lru_prev->lru_next = h->lru_next;
        !           348:     
        !           349:     h->lru_next = &lru_first_hash;
        !           350:     h->lru_prev = lru_first_hash.lru_prev;
        !           351:     h->lru_prev->lru_next = h;
        !           352:     lru_first_hash.lru_prev = h;
        !           353:     }
        !           354: }
        !           355: 
        !           356: static struct hash_entry *find_hash(CPTR addr)
        !           357: {
        !           358:     struct hash_entry *h;
        !           359:     struct hash_entry *h1 = cpu_hash + ((addr >> 1) & HASH_MASK);
        !           360: 
        !           361:     if (h1->next->addr == addr)
        !           362:        return h1->next;
        !           363:     
        !           364:     for (h = h1->next; h != h1; h = h->next) {
        !           365:        if (h->addr == addr) {
        !           366:            h->next->prev = h->prev; h->prev->next = h->next;
        !           367:            h->prev = h1;
        !           368:            h->next = h1->next;
        !           369:            h->next->prev = h->prev->next = h;
        !           370:            return h;
        !           371:        }
        !           372:     }
        !           373:     return NULL;
        !           374: }
        !           375: 
        !           376: static struct hash_entry *get_hash_for_func(CPTR addr)
        !           377: {
        !           378:     struct hash_entry *h = find_hash(addr);
        !           379:     if (h == NULL)
        !           380:        h = new_hash (addr);
        !           381:     else
        !           382:        lru_touch(h);
        !           383:     return h;
        !           384: }
        !           385: 
        !           386: static struct hash_entry *get_hash(CPTR addr)
        !           387: {
        !           388:     struct hash_entry *h = get_hash_for_func(addr);
        !           389: 
        !           390:     if (h->block == NULL) {
        !           391:        if (++h->ncalls == SCAN_MARK) {
        !           392:            m68k_scan_func(h);
        !           393:        }
        !           394:     } else
        !           395:        if (!h->block->untranslatable && h->block->nrefs++ == COMPILE_MARK) {
        !           396:            lru_touch_block(h->block);
        !           397:            if (m68k_compile_block(h->block)) {
        !           398:                h->block->untranslatable = 1;
        !           399:            } else
        !           400:                h->block->translated = 1;
        !           401:        }
        !           402: 
        !           403:     return h;
        !           404: }
        !           405: 
        !           406: void special_flush_hash(CPTR addr)
        !           407: {
        !           408:     struct hash_entry *h = get_hash_for_func(addr);
        !           409:     
        !           410:     h->cacheflush = 1;
        !           411: }
        !           412: 
        !           413: static __inline__ void m68k_setpc_hash(CPTR newpc)
        !           414: {
        !           415:     struct hash_entry *h = get_hash(newpc);
        !           416:     
        !           417:     if (h->cacheflush)
        !           418:        flush_icache();
        !           419: 
        !           420:     if (h->execute != NULL) {
        !           421:        if ((h->addr & 0xF80000) == 0xF80000 || check_block(h->block)) {
        !           422:            compiled_hits++;
        !           423:            if (i_want_to_die && (call_only_me == 0 || call_only_me == newpc)) {
        !           424:                exec_me = h->execute;
        !           425:                nr_bbs_to_run = nr_bbs_start;
        !           426:                regs.spcflags |= SPCFLAG_EXEC;
        !           427:            }
        !           428:        } else 
        !           429:            flush_icache();
        !           430:     }
        !           431:     regs.pc = newpc;
        !           432:     regs.pc_p = regs.pc_oldp = get_real_address(newpc);
        !           433: }
        !           434: 
        !           435: static __inline__ void m68k_setpc_nohash(CPTR newpc)
        !           436: {
        !           437: #if 0
        !           438:     /* This is probably not too good for efficiency... FIXME */
        !           439:     struct hash_entry *h = find_hash(newpc);
        !           440: 
        !           441:     if (h != NULL && h->cacheflush)
        !           442:        flush_icache();
        !           443: #endif
        !           444:     regs.pc = newpc;
        !           445:     regs.pc_p = regs.pc_oldp = get_real_address(newpc);
        !           446: }
        !           447: 
        !           448: void m68k_setpc(CPTR newpc)
        !           449: {
        !           450:     m68k_setpc_hash(newpc);    
        !           451: }
        !           452: 
        !           453: void m68k_setpc_fast(CPTR newpc)
        !           454: {
        !           455:     m68k_setpc_nohash(newpc);    
        !           456: }
        !           457: 
        !           458: void m68k_setpc_rte(CPTR newpc)
        !           459: {
        !           460:     m68k_setpc_nohash(newpc);
        !           461: }
        !           462: 
        !           463: void m68k_setpc_bcc(CPTR newpc)
        !           464: {
        !           465:     m68k_setpc_hash(newpc);
        !           466: }
        !           467: 
        !           468: static void hash_init(void)
        !           469: {
        !           470:     int i;
        !           471:     struct hash_entry **hepp;
        !           472:     
        !           473:     for(i = 0; i < NUM_HASH; i++) {
        !           474:        cpu_hash[i].next = cpu_hash[i].prev = cpu_hash + i;
        !           475:        cpu_hash[i].lru_next = cpu_hash[i].lru_prev = NULL;
        !           476:        cpu_hash[i].block = NULL;
        !           477:        cpu_hash[i].locked = 0; cpu_hash[i].cacheflush = 0;
        !           478:        cpu_hash[i].addr = -1;
        !           479:     }
        !           480:     hepp = &freelist_hash;
        !           481:     for(i = 0; i < NUM_FUNCTIONS; i++) {
        !           482:        *hepp = hash_entries + i;
        !           483:        hash_entries[i].next_same_block = NULL;
        !           484:        hash_entries[i].addr = -1;
        !           485:        hepp = &hash_entries[i].next_same_block;
        !           486:     }
        !           487:     lru_first_hash.lru_next = lru_first_hash.lru_prev = &lru_first_hash;
        !           488:     lru_first_block.lru_next = lru_first_block.lru_prev = &lru_first_block;
        !           489:     
        !           490:     freelist_block = NULL;
        !           491: }
        !           492: 
        !           493: static void code_init(void)
        !           494: {
        !           495:     first_code_page = NULL;
        !           496:     zerofd = open("/dev/zero", O_RDWR);
        !           497:     zeroff = 0;
        !           498: }
        !           499: 
        !           500: void compiler_init(void)
        !           501: {
        !           502:     int i;
        !           503:     code_init();
        !           504:     hash_init();
        !           505: }
        !           506: 
        !           507: /* Help function for the scan routine */
        !           508: static __inline__ int cc_flagmask(const int cc)
        !           509: {
        !           510:     switch(cc){
        !           511:      case 0: return 0;                       /* T */
        !           512:      case 1: return 0;                       /* F */
        !           513:      case 2: return 5;                       /* HI */
        !           514:      case 3: return 5;                       /* LS */
        !           515:      case 4: return 1;                       /* CC */
        !           516:      case 5: return 1;                       /* CS */
        !           517:      case 6: return 4;                       /* NE */
        !           518:      case 7: return 4;                       /* EQ */
        !           519:      case 8: return 2;                       /* VC */
        !           520:      case 9: return 2;                       /* VS */
        !           521:      case 10:return 8;                       /* PL */
        !           522:      case 11:return 8;                       /* MI */
        !           523:      case 12:return 10;                      /* GE */
        !           524:      case 13:return 10;                      /* LT */
        !           525:      case 14:return 14;                      /* GT */
        !           526:      case 15:return 14;                      /* LE */
        !           527:     }
        !           528:     abort();
        !           529:     return 0;
        !           530: }
        !           531: 
        !           532: static __inline__ void translate_step_over_ea(UBYTE **pcpp, amodes m, 
        !           533:                                              wordsizes size)
        !           534: {
        !           535:     switch (m) {
        !           536:      case Areg:
        !           537:      case Dreg:
        !           538:      case Aind:
        !           539:      case Aipi:
        !           540:      case Apdi:
        !           541:      case immi:
        !           542:        break;
        !           543: 
        !           544:      case imm:
        !           545:        if (size == sz_long)
        !           546:            goto is_long;
        !           547:        /* fall through */
        !           548:      case Ad16:
        !           549:      case PC16:
        !           550:      case imm0:
        !           551:      case imm1:
        !           552:      case absw:
        !           553:        (*pcpp)+=2;
        !           554:        break;
        !           555:      case Ad8r:
        !           556:      case PC8r:
        !           557:        {
        !           558:            UWORD extra = *(*pcpp)++;
        !           559:            extra <<= 8;
        !           560:            extra |= *(*pcpp)++;
        !           561:            /* @@@ handle 68020 stuff here */
        !           562:        }
        !           563:        break;
        !           564:      case absl:
        !           565:      case imm2:
        !           566:        is_long:
        !           567:        (*pcpp) += 4;
        !           568:        break;
        !           569:     }
        !           570: }
        !           571: 
        !           572: static struct instr *translate_getnextinsn(UBYTE **pcpp)
        !           573: {
        !           574:     UWORD opcode;
        !           575:     struct instr *dp;
        !           576:     
        !           577:     opcode = *(*pcpp)++ << 8;
        !           578:     opcode |= *(*pcpp)++;
        !           579:     
        !           580:     if (cpufunctbl[opcode] == op_illg) {
        !           581:        opcode = 0x4AFC;
        !           582:     }
        !           583:     dp = table68k + opcode;
        !           584:     if (dp->suse) {
        !           585:        translate_step_over_ea(pcpp, dp->smode, dp->size);
        !           586:     }
        !           587:     if (dp->duse) {
        !           588:        translate_step_over_ea(pcpp, dp->dmode, dp->size);
        !           589:     }
        !           590:     return dp;
        !           591: }
        !           592: 
        !           593: #define CB_STACKSIZE 200
        !           594: #define BB_STACKSIZE 200
        !           595: 
        !           596: static ULONG condbranch_stack[CB_STACKSIZE];
        !           597: static int condbranch_src_stack[CB_STACKSIZE];
        !           598: 
        !           599: struct bb_info {
        !           600:     struct hash_entry *h;
        !           601:     CPTR stopaddr;
        !           602:     int can_compile_last;
        !           603:     struct bb_info *bb_next1, *bb_next2;
        !           604:     int flags_live_at_end;
        !           605:     int flags_live_at_start;
        !           606:     int first_iip, last_iip;
        !           607: } bb_stack[BB_STACKSIZE];
        !           608: 
        !           609: static int top_bb;
        !           610: 
        !           611: static CPTR bcc_target_stack[BB_STACKSIZE];
        !           612: 
        !           613: static int new_bcc_target(CPTR addr)
        !           614: {
        !           615:     int i;
        !           616:     
        !           617:     for (i = 0; i < top_bb; i++)
        !           618:        if (bcc_target_stack[i] == addr)
        !           619:            return 1;
        !           620: 
        !           621:     if (top_bb == BB_STACKSIZE)
        !           622:        return 0;
        !           623:     bcc_target_stack[top_bb++] = addr;
        !           624:     return 1;
        !           625: }
        !           626: 
        !           627: static int bcc_compfn(const void *a, const void *b)
        !           628: {
        !           629:     CPTR *a1 = (CPTR *)a, *b1 = (CPTR *)b;
        !           630:     
        !           631:     if (*a1 == *b1)
        !           632:        printf("BUG!!\n");
        !           633:     
        !           634:     if (*a1 < *b1)
        !           635:        return 1;
        !           636:     return -1;
        !           637: }
        !           638: 
        !           639: static int bb_compfn(const void *a, const void *b)
        !           640: {
        !           641:     struct bb_info *a1 = (struct bb_info *)a, *b1 = (struct bb_info *)b;
        !           642:     
        !           643:     if (a1->h->addr == b1->h->addr)
        !           644:        printf("BUG!!\n");
        !           645:     
        !           646:     if (a1->h->addr < b1->h->addr)
        !           647:        return -1;
        !           648:     return 1;
        !           649: }
        !           650: 
        !           651: static int find_basic_blocks(struct hash_entry *h)
        !           652: {
        !           653:     int current_bb = 0;
        !           654: 
        !           655:     top_bb = 0;
        !           656:     bcc_target_stack[0] = h->addr;
        !           657:     new_bcc_target(h->addr);
        !           658: 
        !           659:     while (top_bb > current_bb) {
        !           660:        CPTR addr = bcc_target_stack[current_bb];
        !           661:        int ninsns = 0;
        !           662:        UBYTE *realpc = get_real_address(addr);
        !           663:        UBYTE *rpc_start = realpc;
        !           664:        
        !           665:        for(;;) {
        !           666:            CPTR thisinsn_addr = (realpc - rpc_start) + addr;
        !           667:            UBYTE *rpc_save = realpc;
        !           668:            struct instr *dp = translate_getnextinsn(&realpc);
        !           669:            CPTR nextinsn_addr = (realpc - rpc_start) + addr;
        !           670: 
        !           671:            if (dp->mnemo == i_RTS || dp->mnemo == i_RTE 
        !           672:                || dp->mnemo == i_RTR || dp->mnemo == i_RTD
        !           673:                || dp->mnemo == i_JMP || dp->mnemo == i_ILLG) 
        !           674:            {
        !           675:                break;
        !           676:            }
        !           677:            
        !           678:            if (dp->mnemo == i_BSR || dp->mnemo == i_JSR) {
        !           679:                if (!new_bcc_target(nextinsn_addr))
        !           680:                    return 0;
        !           681:                break;
        !           682:            }
        !           683: 
        !           684:            if (dp->mnemo == i_DBcc) {
        !           685:                CPTR newaddr = thisinsn_addr + 2 + (WORD)((*(rpc_save+2) << 8) | *(rpc_save+3));
        !           686:                if (!new_bcc_target(nextinsn_addr))
        !           687:                    return 0;
        !           688:                if (!new_bcc_target(newaddr))
        !           689:                    return 0;
        !           690:                break;
        !           691:            }
        !           692:            
        !           693:            if (dp->mnemo == i_Bcc) {
        !           694:                CPTR newaddr;
        !           695:                if (dp->smode == imm1)
        !           696:                    newaddr = thisinsn_addr + 2 + (WORD)((*(rpc_save+2) << 8) | *(rpc_save+3));
        !           697:                else
        !           698:                    newaddr = thisinsn_addr + 2 + (BYTE)dp->sreg;
        !           699:                
        !           700:                if (dp->cc != 0)
        !           701:                    if (!new_bcc_target(nextinsn_addr))
        !           702:                        return 0;
        !           703:                if (!new_bcc_target(newaddr))
        !           704:                    return 0;
        !           705:                break;
        !           706:            }
        !           707:        }
        !           708:        current_bb++;
        !           709:     }
        !           710: 
        !           711:     qsort(bcc_target_stack, top_bb, sizeof (CPTR), bcc_compfn);
        !           712: 
        !           713:     return 1;
        !           714: }
        !           715: 
        !           716: static int m68k_scan_func(struct hash_entry *h)
        !           717: {
        !           718:     int i;
        !           719:     struct hash_block *found_block;
        !           720:     struct hash_entry **hepp;
        !           721:     
        !           722:     if (!find_basic_blocks(h))
        !           723:        return 0;
        !           724: 
        !           725:     found_block = NULL;
        !           726:     
        !           727:     for (i = 0; i < top_bb; i++) {
        !           728:        struct hash_entry *h = get_hash_for_func(bcc_target_stack[i]);
        !           729:        bb_stack[i].h = h;
        !           730:        /* if (h->block != NULL && h->block != found_block) {
        !           731:            if (found_block == NULL) {
        !           732:                if (h->block->cpage != NULL)
        !           733:                    fprintf(stderr, "Found compiled code\n");
        !           734:                else
        !           735:                    found_block = h->block;
        !           736:            } else {
        !           737:                fprintf(stderr, "Multiple blocks found.\n");
        !           738:                if (h->block->cpage == NULL)
        !           739:                    forget_block(h->block);
        !           740:                else if (found_block->cpage == NULL) {
        !           741:                    forget_block(found_block);
        !           742:                    found_block = h->block;
        !           743:                } else
        !           744:                    fprintf(stderr, "Bad case.\n");
        !           745:            }
        !           746:        }*/
        !           747:     }
        !           748:     if (found_block == NULL) {
        !           749:        found_block = new_block();
        !           750: 
        !           751:        found_block->lru_next = &lru_first_block;
        !           752:        found_block->lru_prev = lru_first_block.lru_prev;
        !           753:        found_block->lru_prev->lru_next = found_block;
        !           754:        lru_first_block.lru_prev = found_block;
        !           755:     }
        !           756: 
        !           757:     hepp = &found_block->he_first;
        !           758:     found_block->he_first = NULL;
        !           759:     for (i = 0; i < top_bb; i++) {
        !           760:        struct bb_info *bb = bb_stack + i;
        !           761: 
        !           762:        if (bb->h->block == NULL) {
        !           763:            bb->h->block = found_block;
        !           764:            *hepp = bb->h;
        !           765:            hepp = &bb->h->next_same_block;
        !           766:        }
        !           767:     }
        !           768:     *hepp = found_block->he_first;
        !           769:     return 1;
        !           770: }
        !           771: 
        !           772: struct ea_reg_info {
        !           773:     enum { eat_reg, eat_imem, eat_amem, eat_const } ea_type;
        !           774:     int regs_set:16;
        !           775:     int regs_used:16;
        !           776:     int nr_scratch;
        !           777:     ULONG temp1, temp2;
        !           778: };
        !           779: 
        !           780: #define MAX_TRANSLATE 2048
        !           781: struct insn_info_struct {
        !           782:     CPTR address;
        !           783:     struct instr *dp;
        !           784:     int flags_set;
        !           785:     int flags_used;
        !           786:     int flags_live_at_end;
        !           787:     int jump_target;
        !           788:     int jumps_to;
        !           789:     char *compiled_jumpaddr; /* Address to use for jumps to this insn */
        !           790:     char *compiled_fillin;   /* Address where to put offset if this is a Bcc */
        !           791:     int regs_set:16;
        !           792:     int regs_used:16;
        !           793:     int stop_translation:1;
        !           794:     int sync_cache:1;
        !           795:     int sync_flags:1;
        !           796:     int ccuser_follows:1;
        !           797: } insn_info [MAX_TRANSLATE];
        !           798: 
        !           799: #define EA_LOAD 1
        !           800: #define EA_STORE 2
        !           801: #define EA_IN_REG 4 /* Not quite sure yet what this flag will mean... :) */
        !           802: #if 0
        !           803: static void analyze_ea_for_insn(amodes mode, int reg, wordsizes size,
        !           804:                                struct ea_reg_info *eai,
        !           805:                                UBYTE **pcpp, CPTR pca,
        !           806:                                int ea_purpose)
        !           807: {
        !           808:     UBYTE *p = *pcpp;
        !           809: 
        !           810:     switch(mode) {
        !           811:      case Dreg:
        !           812:        eai->ea_type = eat_reg;
        !           813:        if (size != sz_long && (ea_purpose & EA_STORE))
        !           814:            ea_purpose |= EA_LOAD;
        !           815:        if (ea_purpose & EA_LOAD)
        !           816:            eai->regs_used |= 1 << reg;
        !           817:        if (ea_purpose & EA_STORE)
        !           818:            eai->regs_set |= 1 << reg;
        !           819:        break;
        !           820:        
        !           821:      case Areg:
        !           822:        eai->ea_type = eat_reg;
        !           823:        if (size != sz_long && (ea_purpose & EA_STORE))
        !           824:            printf("Areg != long\n");
        !           825:        if (ea_purpose & EA_LOAD)
        !           826:            eai->regs_used |= 1 << (8+reg);
        !           827:        if (ea_purpose & EA_STORE)
        !           828:            eai->regs_set |= 1 << (8+reg);
        !           829:        break;
        !           830:        
        !           831:      case Ad16:
        !           832:      case Aind:
        !           833:      case Apdi:
        !           834:      case Aipi:
        !           835:        eai->ea_type = eat_imem;
        !           836:        eai->regs_used |= 1 << (8+reg);
        !           837:        break;
        !           838: 
        !           839:      case Ad8r:
        !           840:        eai->ea_type = eat_imem;
        !           841:        pii->regs_used |= 1 << (8+reg);
        !           842: 
        !           843:        eai->temp = (UWORD)((*p << 8) | *(p+1));
        !           844:        r = (eai->temp & 0x7000) >> 12;
        !           845:        (*pcpp) += 2; p += 2;   
        !           846:        
        !           847:        if (eai->temp1 & 0x8000)
        !           848:            pii->regs_used |= 1 << (8+r);
        !           849:        else
        !           850:            pii->regs_used |= 1 << r;
        !           851:        break;
        !           852: 
        !           853:      case PC8r:
        !           854:        eai->ea_type = eat_imem;
        !           855:        eai->temp1 = (UWORD)((*p << 8) | *(p+1));
        !           856:        eai->temp2 = pca + (BYTE)eai->temp1;
        !           857:        (*pcpp) += 2; p += 2;
        !           858:        r = (eai->temp1 & 0x7000) >> 12;
        !           859: 
        !           860:        if (eai->temp1 & 0x8000)
        !           861:            pii->regs_used |= 1 << (8+r);
        !           862:        else
        !           863:            pii->regs_used |= 1 << r;
        !           864:        break;
        !           865:        
        !           866:      case PC16:        
        !           867:        eai->ea_type = eat_amem;
        !           868:        eai->temp1 = pca + (WORD)((*p << 8) | *(p+1));
        !           869:        (*pcpp) += 2;
        !           870:        break;
        !           871:        
        !           872:      case absw:
        !           873:        eai->ea_type = eat_amem;
        !           874:        eai->temp1 = (WORD)((*p << 8) | *(p+1));
        !           875:        (*pcpp) += 2;
        !           876:        break;
        !           877: 
        !           878:      case absl:
        !           879:        eai->ea_type = eat_amem;
        !           880:        eai->temp1 = (LONG)((*p << 24) | (*(p+1) << 16)
        !           881:                                   | (*(p+2) << 8) | *(p+3));
        !           882:        (*pcpp) += 4;
        !           883:        break;
        !           884: 
        !           885:      case imm:
        !           886:        if (size == sz_long)
        !           887:            goto imm2_const;
        !           888:        if (size == sz_word)
        !           889:            goto imm1_const;
        !           890:        
        !           891:        /* fall through */
        !           892:      case imm0:
        !           893:        eai->ea_type = eat_imm;
        !           894:        eai->temp1 = (BYTE)*(p+1);
        !           895:        (*pcpp) += 2;
        !           896:        break;
        !           897: 
        !           898:      case imm1:
        !           899:        imm1_const:
        !           900:        eai->ea_type = eat_imm;
        !           901:        eai->temp1 = (WORD)((*p << 8) | *(p+1));
        !           902:        (*pcpp) += 2;
        !           903:        break;
        !           904: 
        !           905:      case imm2:
        !           906:        imm2_const:
        !           907:        eai->ea_type = eat_imm;
        !           908:        eai->temp1 = (LONG)((*p << 24) | (*(p+1) << 16) | (*(p+2) << 8) | *(p+3));
        !           909:        (*pcpp) += 4;
        !           910:        break;
        !           911: 
        !           912:      case immi:
        !           913:        eai->ea_type = eat_imm;
        !           914:        eai->temp1 = (BYTE)reg;
        !           915:        break;
        !           916: 
        !           917:      default:
        !           918:        break;
        !           919:     }
        !           920: }
        !           921: #endif
        !           922: static struct bb_info *find_bb(struct hash_entry *h)
        !           923: {
        !           924:     int i;
        !           925:     
        !           926:     for (i = 0; i < top_bb; i++)
        !           927:        if (bb_stack[i].h == h)
        !           928:            return bb_stack + i;
        !           929:     if (!quiet_compile)
        !           930:        fprintf(stderr, "BB not found!\n");
        !           931:     return NULL;
        !           932: }
        !           933: 
        !           934: static int m68k_scan_block(struct hash_block *hb, int *movem_count)
        !           935: {
        !           936:     struct hash_entry *h = hb->he_first;
        !           937:     int i, iip, last_iip;
        !           938:     
        !           939:     top_bb = 0;
        !           940:     
        !           941:     do {
        !           942:        struct bb_info *bb = bb_stack + top_bb;
        !           943:        bb->h = h;
        !           944:        bb->bb_next1 = NULL;
        !           945:        bb->bb_next2 = NULL;
        !           946:        h = h->next_same_block;
        !           947:        top_bb++;
        !           948:     } while (h != hb->he_first);
        !           949:     
        !           950:     qsort(bb_stack, top_bb, sizeof (struct bb_info), bb_compfn);
        !           951: 
        !           952:     *movem_count = 0;
        !           953: 
        !           954:     iip = 0;
        !           955:     for (i = 0; i < top_bb; i++) {
        !           956:        struct bb_info *bb = bb_stack + i;
        !           957:        UBYTE *realpc = get_real_address(bb->h->addr);
        !           958:        UBYTE *rpc_start = realpc;
        !           959:        CPTR stop_addr = 0;
        !           960:        int live_at_start = 31, may_clear_las = 31;
        !           961:        struct insn_info_struct *prev_ii = NULL;
        !           962: 
        !           963:        if (i < top_bb - 1)
        !           964:            stop_addr = (bb+1)->h->addr;
        !           965:        bb->first_iip = iip;
        !           966: 
        !           967:        for (;;) {
        !           968:            struct insn_info_struct *thisii = insn_info + iip;
        !           969:            CPTR thisinsn_addr = (realpc - rpc_start) + bb->h->addr;
        !           970:            UBYTE *rpc_save = realpc;
        !           971:            struct instr *dp = translate_getnextinsn(&realpc);
        !           972:            CPTR nextinsn_addr = (realpc - rpc_start) + bb->h->addr;
        !           973:            
        !           974:            int fset = dp->flagdead == -1 ? 31 : dp->flagdead;
        !           975:            int fuse = dp->flaglive == -1 ? 31 : dp->flaglive;
        !           976:            
        !           977:            if (thisinsn_addr == stop_addr) {
        !           978:                bb->bb_next1 = find_bb (find_hash (thisinsn_addr));
        !           979:                break;
        !           980:            }
        !           981:            
        !           982:            if (dp->mnemo == i_Scc || dp->mnemo == i_Bcc || dp->mnemo == i_DBcc) {
        !           983:                fset = 0, fuse = cc_flagmask(dp->cc);
        !           984:                if (prev_ii && dp->mnemo != i_Scc) /* Don't use Scc here: ea can cause an exit */
        !           985:                    prev_ii->ccuser_follows = 1;
        !           986:            }
        !           987: 
        !           988:            may_clear_las &= ~fuse;
        !           989:            live_at_start &= ~(fset & may_clear_las);
        !           990:            
        !           991:            thisii->dp = dp;
        !           992:            thisii->address = thisinsn_addr;
        !           993:            thisii->stop_translation = 0;
        !           994:            thisii->ccuser_follows = 0;
        !           995: /*         thisii->have_reginfo = 0;*/
        !           996:            thisii->jump_target = 0;
        !           997:            thisii->sync_cache = thisii->sync_flags = 0;
        !           998:            thisii->flags_set = fset;
        !           999:            thisii->flags_used = fuse;
        !          1000:            thisii->regs_set = 0;
        !          1001:            thisii->regs_used = 0;
        !          1002:            iip++;
        !          1003:            if (iip == MAX_TRANSLATE)
        !          1004:                return 0;
        !          1005: 
        !          1006:            if (dp->mnemo == i_RTS || dp->mnemo == i_RTE 
        !          1007:                || dp->mnemo == i_RTR || dp->mnemo == i_RTD
        !          1008:                || dp->mnemo == i_JMP || dp->mnemo == i_ILLG
        !          1009:                || dp->mnemo == i_BSR || dp->mnemo == i_JSR)
        !          1010:            {
        !          1011:                thisii->flags_used = 31;
        !          1012:                thisii->regs_used = 65535;
        !          1013:                thisii->stop_translation = 1;
        !          1014:                break;
        !          1015:            }
        !          1016:            
        !          1017:            if (dp->mnemo == i_DBcc) {
        !          1018:                CPTR newaddr = thisinsn_addr + 2 + (WORD)((*(rpc_save+2) << 8) | *(rpc_save+3));
        !          1019:                bb->can_compile_last = 1;
        !          1020:                bb->bb_next1 = find_bb (find_hash (newaddr));
        !          1021:                if (bb->bb_next1 == NULL)
        !          1022:                    thisii->stop_translation = 1;
        !          1023:                bb->bb_next2 = find_bb (find_hash (nextinsn_addr));
        !          1024:                if (bb->bb_next2 == NULL)
        !          1025:                    thisii->stop_translation = 1;
        !          1026:                thisii->regs_used = 65535;
        !          1027:                break;
        !          1028:            }
        !          1029:            
        !          1030:            if (dp->mnemo == i_Bcc) {
        !          1031:                CPTR newaddr;
        !          1032:                if (dp->smode == imm1)
        !          1033:                    newaddr = thisinsn_addr + 2 + (WORD)((*(rpc_save+2) << 8) | *(rpc_save+3));
        !          1034:                else
        !          1035:                    newaddr = thisinsn_addr + 2 + (BYTE)dp->sreg;
        !          1036:                bb->can_compile_last = 1;
        !          1037:                bb->bb_next1 = find_bb(get_hash_for_func(newaddr));
        !          1038:                if (bb->bb_next1 == NULL)
        !          1039:                    thisii->stop_translation = 1;
        !          1040:                if (dp->cc != 0) {
        !          1041:                    bb->bb_next2 = find_bb(get_hash_for_func(nextinsn_addr));
        !          1042:                    if (bb->bb_next2 == NULL)
        !          1043:                        thisii->stop_translation = 1;
        !          1044:                }
        !          1045:                thisii->regs_used = 65535;
        !          1046:                break;
        !          1047:            }
        !          1048: 
        !          1049:            if (dp->mnemo == i_MVMLE || dp->mnemo == i_MVMEL) {
        !          1050:                UWORD regmask = (*(rpc_save + 2) << 8) | (*(rpc_save + 3));
        !          1051:                *movem_count += count_bits(regmask);
        !          1052:                if (dp->dmode == Apdi)
        !          1053:                    regmask = bitswap(regmask);
        !          1054:                if (dp->mnemo == i_MVMLE)
        !          1055:                    thisii->regs_used = regmask;
        !          1056:                else
        !          1057:                    thisii->regs_set = regmask;
        !          1058:            }
        !          1059: 
        !          1060:            prev_ii = thisii;
        !          1061:        }
        !          1062:        bb->last_iip = iip - 1;
        !          1063:        bb->flags_live_at_start = live_at_start;
        !          1064:     }
        !          1065:     last_iip = iip;
        !          1066: 
        !          1067:     for (i = 0; i < top_bb; i++) {
        !          1068:        struct bb_info *bb = bb_stack + i;
        !          1069:        int mnemo;
        !          1070:        int current_live;
        !          1071:        struct instr *dp;
        !          1072:        
        !          1073:        iip = bb->last_iip;
        !          1074:        mnemo = insn_info[iip].dp->mnemo;
        !          1075: 
        !          1076:        /* Fix up branches */
        !          1077:        if (mnemo == i_DBcc || mnemo == i_Bcc) {
        !          1078:            if (bb->bb_next1 != NULL) {
        !          1079:                insn_info[bb->last_iip].jumps_to = bb->bb_next1->first_iip;
        !          1080:                insn_info[bb->bb_next1->first_iip].jump_target = 1;
        !          1081:            }
        !          1082:        }
        !          1083:        /* And take care of flag life information */
        !          1084:        dp = insn_info[iip].dp;
        !          1085:        if (insn_info[iip].stop_translation)
        !          1086:            current_live = 31;
        !          1087:        else if (dp->mnemo == i_DBcc || dp->mnemo == i_Bcc) {
        !          1088:            current_live = 0;
        !          1089:            if (bb->bb_next1 != NULL)
        !          1090:                current_live |= bb->bb_next1->flags_live_at_start;
        !          1091:            if (bb->bb_next2 != NULL)
        !          1092:                current_live |= bb->bb_next2->flags_live_at_start;
        !          1093:        } else {
        !          1094:            if (bb->bb_next1 == NULL && bb->bb_next2 == NULL)
        !          1095:                fprintf(stderr, "Can't happen\n");
        !          1096:            current_live = 0;
        !          1097:            if (bb->bb_next1 != NULL)
        !          1098:                current_live |= bb->bb_next1->flags_live_at_start;
        !          1099:            if (bb->bb_next2 != NULL)
        !          1100:                current_live |= bb->bb_next2->flags_live_at_start;
        !          1101:        }
        !          1102: 
        !          1103:        do {
        !          1104:            insn_info[iip].flags_live_at_end = current_live;
        !          1105:            current_live &= ~insn_info[iip].flags_set;
        !          1106:            current_live |= insn_info[iip].flags_used;
        !          1107:        } while (iip-- != bb->first_iip);
        !          1108: 
        !          1109:        if (bb->flags_live_at_start != current_live && !quiet_compile)
        !          1110:            fprintf(stderr, "Fascinating!\n");
        !          1111:        bb->flags_live_at_start = current_live;
        !          1112:     }
        !          1113:     return last_iip;
        !          1114: }
        !          1115: 
        !          1116: static char *compile_current_addr;
        !          1117: static char *compile_last_addr;
        !          1118: 
        !          1119: static __inline__ void assemble(UBYTE a)
        !          1120: {
        !          1121:     if (compile_current_addr < compile_last_addr) {
        !          1122:        *compile_current_addr++ = a;
        !          1123:     } else {
        !          1124:        compile_failure = 1;
        !          1125:     }
        !          1126: }
        !          1127: 
        !          1128: static __inline__ void assemble_ulong(ULONG a)
        !          1129: {
        !          1130:     assemble(a);
        !          1131:     assemble(a >> 8);
        !          1132:     assemble(a >> 16);
        !          1133:     assemble(a >> 24);
        !          1134: }
        !          1135: 
        !          1136: static __inline__ void assemble_uword(UWORD a)
        !          1137: {
        !          1138:     assemble(a);
        !          1139:     assemble(a >> 8);
        !          1140: }
        !          1141: 
        !          1142: static __inline__ void assemble_long(void *a)
        !          1143: {
        !          1144:     assemble_ulong((ULONG)a);
        !          1145: }
        !          1146: 
        !          1147: static __inline__ void compile_org(char *addr)
        !          1148: {
        !          1149:     compile_current_addr = addr;
        !          1150: }
        !          1151: 
        !          1152: static __inline__ char *compile_here(void)
        !          1153: {
        !          1154:     return compile_current_addr;
        !          1155: }
        !          1156: 
        !          1157: #define r_EAX 0
        !          1158: #define r_ECX 1
        !          1159: #define r_EDX 2
        !          1160: #define r_EBX 3
        !          1161: #define r_ESP 4
        !          1162: #define r_EBP 5
        !          1163: #define r_ESI 6
        !          1164: #define r_EDI 7
        !          1165: 
        !          1166: #define r_AH 0x84
        !          1167: #define r_CH 0x85
        !          1168: #define r_DH 0x86
        !          1169: #define r_BH 0x87
        !          1170: 
        !          1171: #define ALL_X86_REGS 255
        !          1172: #define ADDRESS_X86_REGS ((1 << r_EBP) | (1 << r_ESI) | (1 << r_EDI))
        !          1173: #define DATA_X86_REGS ((1 << r_EAX) | (1 << r_EDX) | (1 << r_EBX) | (1 << r_ECX))
        !          1174: 
        !          1175: #define BO_NORMAL 0
        !          1176: #define BO_SWAPPED_LONG 1
        !          1177: #define BO_SWAPPED_WORD 2
        !          1178: 
        !          1179: struct register_mapping {
        !          1180:     int dreg_map[8], areg_map[8]; /* 68000 register cache */
        !          1181:     int x86_const_offset[8];
        !          1182:     int x86_dirty[8];
        !          1183:     int x86_cache_reg[8]; /* Regs used for the 68000 register cache */
        !          1184:     int x86_cr_type[8]; /* Caching data or address register? */
        !          1185:     int x86_locked[8]; /* Regs used for some purpose */
        !          1186:     int x86_byteorder[8];
        !          1187:     int x86_verified[8];
        !          1188: };
        !          1189: 
        !          1190: /*
        !          1191:  * First, code to compile some primitive x86 instructions
        !          1192:  */
        !          1193: 
        !          1194: static void compile_lea_reg_with_offset(int dstreg, int srcreg, ULONG srcoffs)
        !          1195: {
        !          1196:     assemble(0x8D);
        !          1197:     if (srcreg == -2) {
        !          1198:        assemble(0x05 + 8*dstreg);
        !          1199:        assemble_ulong(srcoffs);
        !          1200:     } else if ((LONG)srcoffs >= -128 && (LONG)srcoffs <= 127) {
        !          1201:        assemble(0x40 + 8*dstreg + srcreg);
        !          1202:        assemble(srcoffs);
        !          1203:     } else {
        !          1204:        assemble(0x80 + 8*dstreg + srcreg);
        !          1205:        assemble_ulong(srcoffs);
        !          1206:     }
        !          1207: }
        !          1208: 
        !          1209: static void compile_move_reg_reg(int dstreg, int srcreg, wordsizes size)
        !          1210: {
        !          1211:     if (size == sz_byte
        !          1212:        && (((1 << dstreg) & DATA_X86_REGS) == 0
        !          1213:            || ((1 << srcreg) & DATA_X86_REGS) == 0))
        !          1214:     {
        !          1215:        fprintf(stderr, "Moving wrong register types!\n");
        !          1216:     }
        !          1217:     if (size == sz_word)
        !          1218:        assemble(0x66);
        !          1219:     if (size == sz_byte)
        !          1220:        assemble(0x88);
        !          1221:     else
        !          1222:        assemble(0x89);
        !          1223:     assemble(0xC0 + dstreg + 8*srcreg);
        !          1224: }
        !          1225: 
        !          1226: static void compile_move_between_reg_mem_regoffs(int dstreg, int srcreg,
        !          1227:                                                 ULONG srcoffs, wordsizes size,
        !          1228:                                                 int code)
        !          1229: {
        !          1230:     if (size == sz_byte && (dstreg & 0x80) != 0)
        !          1231:        dstreg &= ~0x80;
        !          1232:     else if ((size == sz_byte
        !          1233:              && ((1 << dstreg) & DATA_X86_REGS) == 0)
        !          1234:             || (size != sz_byte && (dstreg & 0x80) != 0))
        !          1235:     {
        !          1236:        fprintf(stderr, "Moving wrong register types!\n");
        !          1237:     }
        !          1238:     if (size == sz_word)
        !          1239:        assemble(0x66);
        !          1240:     if (size == sz_byte)
        !          1241:        assemble(code);
        !          1242:     else
        !          1243:        assemble(code + 1);
        !          1244:     
        !          1245:     if (srcreg == -2) {
        !          1246:        assemble(0x05 + 8*dstreg);
        !          1247:        assemble_ulong(srcoffs);
        !          1248:     } else if ((LONG)srcoffs >= -128 && (LONG)srcoffs <= 127) {
        !          1249:        assemble(0x40 + 8*dstreg + srcreg);
        !          1250:        assemble(srcoffs);
        !          1251:     } else {
        !          1252:        assemble(0x80 + 8*dstreg + srcreg);
        !          1253:        assemble_ulong(srcoffs);
        !          1254:     }
        !          1255: }
        !          1256: 
        !          1257: static void compile_move_reg_from_mem_regoffs(int dstreg, int srcreg, 
        !          1258:                                              ULONG srcoffs, wordsizes size)
        !          1259: {
        !          1260:     compile_move_between_reg_mem_regoffs(dstreg, srcreg, srcoffs, size, 0x8A);
        !          1261: }
        !          1262: 
        !          1263: static void compile_move_reg_to_mem_regoffs(int dstreg, ULONG dstoffs, 
        !          1264:                                            int srcreg, wordsizes size)
        !          1265: {
        !          1266:     compile_move_between_reg_mem_regoffs(srcreg, dstreg, dstoffs, size, 0x88);
        !          1267: }
        !          1268: 
        !          1269: static void compile_byteswap(int x86r, wordsizes size, int save_flags)
        !          1270: {
        !          1271:     switch(size) {
        !          1272:      case sz_word:
        !          1273:        if (save_flags)
        !          1274:            assemble(0x9C);
        !          1275:        assemble(0x66); /* rolw $8,x86r */
        !          1276:        assemble(0xC1);
        !          1277:        assemble(0xC0 + x86r);
        !          1278:        assemble(8);
        !          1279:        if (save_flags)
        !          1280:            assemble(0x9D);
        !          1281:        break;
        !          1282:      case sz_long:
        !          1283:        assemble(0x0F); /* bswapl x86r */
        !          1284:        assemble(0xC8+x86r);
        !          1285:        break;
        !          1286:      default:
        !          1287:        break;
        !          1288:     }
        !          1289: }
        !          1290: 
        !          1291: static void compile_force_byteorder(struct register_mapping *map, int x86r,
        !          1292:                                    int desired_bo, int save_flags)
        !          1293: {
        !          1294:     if (x86r == -2 || map->x86_byteorder[x86r] == desired_bo)
        !          1295:        return;
        !          1296:     
        !          1297:     if (map->x86_byteorder[x86r] == BO_SWAPPED_LONG)
        !          1298:        compile_byteswap(x86r, sz_long, save_flags);
        !          1299:     else if (map->x86_byteorder[x86r] == BO_SWAPPED_WORD)
        !          1300:        compile_byteswap(x86r, sz_word, save_flags);
        !          1301:     
        !          1302:     if (desired_bo == BO_SWAPPED_LONG)
        !          1303:        compile_byteswap(x86r, sz_long, save_flags);
        !          1304:     else if (desired_bo == BO_SWAPPED_WORD)
        !          1305:        compile_byteswap(x86r, sz_word, save_flags);
        !          1306:     map->x86_byteorder[x86r] = desired_bo;
        !          1307: }
        !          1308: 
        !          1309: /* Add a constant offset to a x86 register. If it's in the cache, make sure
        !          1310:  * we update the const_offset value. The flags are unaffected by this */
        !          1311: 
        !          1312: static void compile_offset_reg(struct register_mapping *map, int x86r, 
        !          1313:                               ULONG offset)
        !          1314: {
        !          1315:     int cached_68k;
        !          1316:     
        !          1317:     if (offset == 0 || x86r == -1 || x86r == -2)
        !          1318:        return;
        !          1319: 
        !          1320:     compile_force_byteorder(map, x86r, BO_NORMAL, 1);
        !          1321:     cached_68k = map->x86_cache_reg[x86r];
        !          1322:     if (cached_68k != -1) {
        !          1323:        map->x86_const_offset[x86r] -= offset;
        !          1324:        map->x86_dirty[x86r] = 1;
        !          1325:     }
        !          1326:     compile_lea_reg_with_offset(x86r, x86r, offset);
        !          1327: }
        !          1328: 
        !          1329: static int get_unused_x86_register(struct register_mapping *map)
        !          1330: {
        !          1331:     int x86r;
        !          1332:     for (x86r = 0; x86r < 24; x86r++) {
        !          1333:        if (map->x86_cache_reg[x86r] != -1)
        !          1334:            continue;
        !          1335:        if (map->x86_locked[x86r] > 0)
        !          1336:            continue;
        !          1337:        
        !          1338:        map->x86_verified[x86r] = 0;
        !          1339:        map->x86_byteorder[x86r] = BO_NORMAL;
        !          1340:        return x86r;
        !          1341:     }
        !          1342:     return -1;
        !          1343: }
        !          1344: 
        !          1345: /*
        !          1346:  * sync_reg() may not touch the flags
        !          1347:  * If may_clobber is 1 and the reg had an offset, the reg will be offsetted
        !          1348:  * by this function
        !          1349:  */
        !          1350: static void sync_reg(struct register_mapping *map, int x86r, void *m68kr, 
        !          1351:                     ULONG offset, int dirty, int may_clobber)
        !          1352: {
        !          1353:     compile_force_byteorder(map, x86r, BO_NORMAL, 1);
        !          1354:     if (offset != 0) {
        !          1355:        if (may_clobber) {
        !          1356:            compile_lea_reg_with_offset(x86r, x86r, offset);
        !          1357:            dirty = 1;
        !          1358:        } else {
        !          1359:            int tmpr = get_unused_x86_register(map);
        !          1360:            if (tmpr != -1) { 
        !          1361:                compile_lea_reg_with_offset(tmpr, x86r, offset);
        !          1362:                x86r = tmpr;
        !          1363:                dirty = 1;
        !          1364:            } else {
        !          1365:                compile_lea_reg_with_offset(x86r, x86r, offset);
        !          1366:                assemble(0x89);          /* movl x86r,m68kr */
        !          1367:                assemble(0x05 + (x86r << 3)); 
        !          1368:                assemble_long(m68kr);
        !          1369:                compile_lea_reg_with_offset(x86r, x86r, -offset);
        !          1370:                return;
        !          1371:            }
        !          1372:        }
        !          1373:     }
        !          1374: 
        !          1375:     if (dirty) {
        !          1376:        assemble(0x89);          /* movl x86r,m68kr */
        !          1377:        assemble(0x05 + (x86r << 3)); 
        !          1378:        assemble_long(m68kr);
        !          1379:     }
        !          1380: }
        !          1381: 
        !          1382: static void sync_reg_cache(struct register_mapping *map, int flush)
        !          1383: {
        !          1384:     int i;
        !          1385: 
        !          1386:     for (i = 0; i < 8; i++) {
        !          1387:        int cr68k = map->x86_cache_reg[i];
        !          1388:        if (cr68k != -1) {
        !          1389:            if (map->x86_cr_type[i] == 1) {
        !          1390:                sync_reg(map, i, regs.d + cr68k, map->x86_const_offset[i], map->x86_dirty[i], 1);
        !          1391:                if (flush)
        !          1392:                    map->dreg_map[cr68k] = -1;
        !          1393:            } else {
        !          1394:                sync_reg(map, i, regs.a + cr68k, map->x86_const_offset[i], map->x86_dirty[i], 1);
        !          1395:                if (flush)
        !          1396:                    map->areg_map[cr68k] = -1;
        !          1397:            }
        !          1398:            if (flush)
        !          1399:                map->x86_cache_reg[i] = -1;
        !          1400:            map->x86_const_offset[i] = 0;
        !          1401:        }
        !          1402:     }
        !          1403:     memset(map->x86_dirty, 0, sizeof map->x86_dirty);
        !          1404: }
        !          1405: 
        !          1406: static void remove_x86r_from_cache(struct register_mapping *map, int x86r, 
        !          1407:                                   int may_clobber)
        !          1408: {
        !          1409:     int j;
        !          1410:     int reg_68k;
        !          1411:     
        !          1412:     if (x86r == -1)
        !          1413:        return;
        !          1414: 
        !          1415:     reg_68k = map->x86_cache_reg[x86r];
        !          1416:     
        !          1417:     if (reg_68k != -1) {
        !          1418:        if (map->x86_cr_type[x86r] == 1) {
        !          1419:            map->dreg_map[reg_68k] = -1;
        !          1420:            sync_reg(map, x86r, regs.d + reg_68k, map->x86_const_offset[x86r],
        !          1421:                     map->x86_dirty[x86r], may_clobber);
        !          1422:        } else {
        !          1423:            map->areg_map[reg_68k] = -1;
        !          1424:            sync_reg(map, x86r, regs.a + reg_68k,  map->x86_const_offset[x86r],
        !          1425:                     map->x86_dirty[x86r], may_clobber);
        !          1426:        }
        !          1427:     }
        !          1428:     map->x86_dirty[x86r] = 0;
        !          1429:     map->x86_cache_reg[x86r] = -1;
        !          1430:     map->x86_const_offset[x86r] = 0;
        !          1431:     map->x86_verified[x86r] = 0;
        !          1432:     map->x86_byteorder[x86r] = BO_NORMAL;
        !          1433: }
        !          1434: 
        !          1435: static int get_free_x86_register(struct register_mapping *map,
        !          1436:                                 int preferred_mask)
        !          1437: {
        !          1438:     int cnt;
        !          1439:     for (cnt = 0; cnt < 24; cnt++) {
        !          1440:        int x86r = cnt & 7;
        !          1441:        /* In the first two passes, try to get one of the preferred regs */
        !          1442:        if (cnt < 16 && ((1 << x86r) & preferred_mask) == 0)
        !          1443:            continue;
        !          1444:        /* In the first pass, don't discard any registers from the cache */
        !          1445:        if (cnt < 8 && map->x86_cache_reg[x86r] != -1)
        !          1446:            continue;
        !          1447:        /* Never use locked registers */
        !          1448:        if (map->x86_locked[x86r] > 0)
        !          1449:            continue;
        !          1450: 
        !          1451:        remove_x86r_from_cache(map, x86r, 1);
        !          1452:        return x86r;
        !          1453:     }
        !          1454:     printf("Out of registers!\n");
        !          1455:     return -1;
        !          1456: }
        !          1457: 
        !          1458: static int get_typed_x86_register(struct register_mapping *map,
        !          1459:                                  int preferred_mask)
        !          1460: {
        !          1461:     int cnt;
        !          1462:     for (cnt = 0; cnt < 16; cnt++) {
        !          1463:        int x86r = cnt & 7;
        !          1464:        /* Get one of the preferred regs */
        !          1465:        if (((1 << x86r) & preferred_mask) == 0)
        !          1466:            continue;
        !          1467:        /* In the first pass, don't discard any registers from the cache */
        !          1468:        if (cnt < 8 && map->x86_cache_reg[x86r] != -1)
        !          1469:            continue;
        !          1470:        /* Never use locked registers */
        !          1471:        if (map->x86_locked[x86r] > 0)
        !          1472:            continue;
        !          1473: 
        !          1474:        remove_x86r_from_cache(map, x86r, 1);
        !          1475:        return x86r;
        !          1476:     }
        !          1477:     printf("Out of type registers!\n");
        !          1478:     return -1;
        !          1479: }
        !          1480: 
        !          1481: static void compile_unlock_reg(struct register_mapping *map, int reg)
        !          1482: {
        !          1483:     if (reg >= 0) {
        !          1484:        map->x86_locked[reg]--;
        !          1485:     }
        !          1486: }
        !          1487: 
        !          1488: static int get_and_lock_68k_reg(struct register_mapping *map, int reg, int is_dreg,
        !          1489:                                int preferred, int no_offset)
        !          1490: {
        !          1491:     int x86r;
        !          1492:     int *regmap;
        !          1493:     ULONG *reghome;
        !          1494:     
        !          1495:     if (is_dreg)
        !          1496:        regmap = map->dreg_map, reghome = regs.d;
        !          1497:     else
        !          1498:        regmap = map->areg_map, reghome = regs.a;
        !          1499:     
        !          1500:     if (preferred == 0)
        !          1501:        preferred = ALL_X86_REGS;
        !          1502:     
        !          1503:     x86r = regmap[reg];
        !          1504:     if (x86r == -1) {
        !          1505:        x86r = get_free_x86_register(map, preferred);
        !          1506:        assemble(0x8B); assemble(0x05 + (x86r << 3)); /* movl regs.d[reg],x86r */
        !          1507:        assemble_long(reghome + reg);
        !          1508:        map->x86_cache_reg[x86r] = reg;
        !          1509:        map->x86_cr_type[x86r] = is_dreg;
        !          1510:        map->x86_const_offset[x86r] = 0;
        !          1511:        map->x86_dirty[x86r] = 0;
        !          1512:        map->x86_verified[x86r] = 0;
        !          1513:        map->x86_byteorder[x86r] = BO_NORMAL;
        !          1514:        regmap[reg] = x86r;
        !          1515:     } else if (map->x86_locked[x86r] > 0) {
        !          1516:        /* Register was in cache, and was locked. Need to make a copy */
        !          1517:        int newr = get_free_x86_register(map, preferred);
        !          1518:        int old_dirty = 0;
        !          1519:        int old_verified;
        !          1520:        int old_bo;
        !          1521:        
        !          1522:        if (map->x86_const_offset[x86r] == 0) {
        !          1523:            compile_move_reg_reg(newr, x86r, sz_long);
        !          1524:        } else {
        !          1525:            compile_force_byteorder(map, x86r, BO_NORMAL, 1);
        !          1526:            compile_lea_reg_with_offset(newr, x86r, map->x86_const_offset[x86r]);
        !          1527:            old_dirty = 1;
        !          1528:        }
        !          1529:        /* Remove old reg from cache... */
        !          1530:        map->x86_cache_reg[x86r] = -1;
        !          1531:        map->x86_cr_type[x86r] = is_dreg;
        !          1532:        map->x86_const_offset[x86r] = 0;
        !          1533:        old_dirty |= map->x86_dirty[x86r];
        !          1534:        old_verified = map->x86_verified[x86r];
        !          1535:        old_bo = map->x86_byteorder[x86r];
        !          1536:        map->x86_verified[x86r] = 0;
        !          1537:        map->x86_dirty[x86r] = 0;
        !          1538:        x86r = newr;
        !          1539:        /* ... and make the new one the cache register */
        !          1540:        map->x86_cache_reg[x86r] = reg;
        !          1541:        map->x86_cr_type[x86r] = is_dreg;
        !          1542:        map->x86_const_offset[x86r] = 0;
        !          1543:        map->x86_dirty[x86r] = old_dirty;
        !          1544:        map->x86_verified[x86r] = old_verified;
        !          1545:        map->x86_byteorder[x86r] = old_bo;
        !          1546:        regmap[reg] = x86r;
        !          1547:     }
        !          1548:     map->x86_locked[x86r]++;
        !          1549:     if (no_offset && map->x86_const_offset[x86r] != 0) {
        !          1550:        compile_force_byteorder(map, x86r, BO_NORMAL, 1);
        !          1551:        compile_lea_reg_with_offset(x86r, x86r, map->x86_const_offset[x86r]);
        !          1552:        map->x86_const_offset[x86r] = 0;
        !          1553:        map->x86_dirty[x86r] = 1;
        !          1554:     }
        !          1555:     return x86r;
        !          1556: }
        !          1557: 
        !          1558: /*
        !          1559:  * Move a constant to a register. Don't anything if we already have a
        !          1560:  * register, even if it is offset by a constant
        !          1561:  */
        !          1562: 
        !          1563: static int compile_force_const_reg(struct register_mapping *map, int x86r,
        !          1564:                                   ULONG *offs, int desired)
        !          1565: {
        !          1566:     int newr = x86r;
        !          1567: 
        !          1568:     if (newr == -2) {
        !          1569:        if (desired == 0)
        !          1570:            newr = get_free_x86_register(map, ALL_X86_REGS);
        !          1571:        else
        !          1572:            newr = get_typed_x86_register(map, desired);
        !          1573: 
        !          1574:        assemble(0xB8 + newr);
        !          1575:        assemble_ulong(*offs);
        !          1576:        *offs = 0;
        !          1577:     }
        !          1578:     map->x86_locked[newr]++;
        !          1579:     return newr;
        !          1580: }
        !          1581: 
        !          1582: static int compile_extend_long(struct register_mapping *map, int x86r,
        !          1583:                               ULONG *srcoffs, wordsizes size)
        !          1584: {
        !          1585:     compile_force_byteorder(map, x86r, BO_NORMAL, 1);
        !          1586:     if (size != sz_long) {
        !          1587:        if (x86r == -2) {
        !          1588:            ULONG offs = *srcoffs;
        !          1589:            if (size == sz_byte)
        !          1590:                offs = (LONG)(BYTE)offs;
        !          1591:            else if (size == sz_word)
        !          1592:                offs = (LONG)(WORD)offs;
        !          1593:            *srcoffs = offs;
        !          1594:            return x86r;
        !          1595:        } else if (*srcoffs != 0) {
        !          1596:            int newr = get_free_x86_register(map, ALL_X86_REGS);
        !          1597:            compile_lea_reg_with_offset(newr, x86r, *srcoffs);
        !          1598:            *srcoffs = 0;
        !          1599:            x86r = newr;
        !          1600:        } else if (map->x86_locked[x86r] != 0) {
        !          1601:            int newr = get_free_x86_register(map, ALL_X86_REGS);
        !          1602:            assemble(0x0F);
        !          1603:            if (size == sz_byte) {
        !          1604:                assemble(0xBE);
        !          1605:            } else {
        !          1606:                assemble(0xBF);
        !          1607:            }
        !          1608:            assemble(0xC0 + newr*8 + x86r);
        !          1609:            x86r = newr;
        !          1610:            goto extended;
        !          1611:        }
        !          1612:        
        !          1613:        if (x86r == r_EAX && size == sz_word) {
        !          1614:            assemble(0x98); /* cwtl */
        !          1615:        } else {
        !          1616:            assemble(0x0F);
        !          1617:            if (size == sz_byte) {
        !          1618:                assemble(0xBE);
        !          1619:            } else {
        !          1620:                assemble(0xBF);
        !          1621:            }
        !          1622:            assemble(0xC0 + x86r*9);
        !          1623:        }
        !          1624:     }
        !          1625:     extended:
        !          1626:     if (x86r >= 0)
        !          1627:        map->x86_locked[x86r]++;
        !          1628:     return x86r;
        !          1629: }
        !          1630: 
        !          1631: /*
        !          1632:  * Either move a constant into a register, or get rid of a constant offset
        !          1633:  * for a register
        !          1634:  */
        !          1635: 
        !          1636: static int compile_move_const_reg(struct register_mapping *map, int x86r,
        !          1637:                                  ULONG *offs, int desired)
        !          1638: {
        !          1639:     int newr = x86r;
        !          1640:     if (newr == -2) {
        !          1641:        if (desired == 0)
        !          1642:            newr = get_free_x86_register(map, ALL_X86_REGS);
        !          1643:        else
        !          1644:            newr = get_typed_x86_register(map, desired);
        !          1645:        assemble(0xB8 + newr);
        !          1646:        assemble_ulong(*offs);
        !          1647:     } else {
        !          1648:        compile_offset_reg(map, x86r, *offs);
        !          1649:     }
        !          1650:     *offs = 0;
        !          1651:     map->x86_locked[newr]++;
        !          1652:     return newr;
        !          1653: }
        !          1654: 
        !          1655: static int compile_move_to_modereg(struct register_mapping *map, int x86r, 
        !          1656:                                   wordsizes size)
        !          1657: {
        !          1658:     int newr = x86r;
        !          1659:     
        !          1660:     if (size == sz_byte && ((1 << x86r) & DATA_X86_REGS) == 0) {
        !          1661:        newr = get_typed_x86_register(map, DATA_X86_REGS);
        !          1662:        compile_force_byteorder(map, x86r, BO_NORMAL, 1);
        !          1663:        if (((1 << newr) & DATA_X86_REGS) == 0)
        !          1664:            printf("Can't get data register for byte value\n");
        !          1665:        assemble(0x89);
        !          1666:        assemble(0xC0 + newr*8 + x86r);
        !          1667:     }
        !          1668:     map->x86_locked[newr]++;
        !          1669:     return newr;
        !          1670: }
        !          1671: 
        !          1672: /*
        !          1673:  * This structure holds information about predec/postinc addressing modes.
        !          1674:  */
        !          1675: 
        !          1676: struct pid_undo {
        !          1677:     int used;
        !          1678:     int x86r[2];
        !          1679:     int m68kr[2];
        !          1680:     int dirty[2];
        !          1681:     ULONG offs[2];
        !          1682: };
        !          1683: 
        !          1684: static void add_undo(struct pid_undo *pud, int x86r, int m68kr, ULONG offs,
        !          1685:                     int dirty)
        !          1686: {
        !          1687:     int i;
        !          1688:     for (i = 0; i < pud->used; i++)
        !          1689:        if (pud->m68kr[i] == m68kr)
        !          1690:            return;
        !          1691:     pud->m68kr[i] = m68kr;
        !          1692:     pud->x86r[i] = x86r;
        !          1693:     pud->offs[i] = offs;
        !          1694:     pud->dirty[i] = dirty;
        !          1695:     pud->used++;
        !          1696: }
        !          1697: 
        !          1698: struct ea_info {
        !          1699:     int reg;
        !          1700:     amodes mode;
        !          1701:     wordsizes size;
        !          1702:     int regs_locked;    /* The regs locked for this ea by compile_prepareea() */
        !          1703:     int locked_regs[3];
        !          1704:     int address_reg;    /* The x86 reg holding the address, or -1 if ea doesn't refer to memory
        !          1705:                         * -2 if it refers to memory, but only with a constant address */
        !          1706:     ULONG addr_const_off; /* Constant offset to the address */
        !          1707:     int flags;            /* Extra info. Contains the dp field of d8r modes */
        !          1708:     int purpose;
        !          1709:     int data_reg;         /* The x86 reg that holds the data. -1 if data is not present yet. 
        !          1710:                           * -2 if data is constant */
        !          1711:     ULONG data_const_off;
        !          1712: };
        !          1713: 
        !          1714: static void init_eainfo(struct ea_info *eai)
        !          1715: {
        !          1716:     eai->regs_locked = 0;
        !          1717:     eai->address_reg = -1;
        !          1718:     eai->addr_const_off = 0;
        !          1719:     eai->data_reg = -1;
        !          1720:     eai->data_const_off = 0;
        !          1721: }
        !          1722: 
        !          1723: /*
        !          1724:  * Load all the registers absolutely needed to calculate and verify thea
        !          1725:  * address. Load other registers if convenient.
        !          1726:  * This contains a fair amount of magic to get the register cache working right.
        !          1727:  */
        !          1728: 
        !          1729: static void compile_prepareea(struct register_mapping *map, amodes mode,
        !          1730:                              int reg, wordsizes size, UBYTE **pcpp, CPTR pca,
        !          1731:                              struct ea_info *eai, int ea_purpose,
        !          1732:                              struct pid_undo *pud, int pidmult)
        !          1733: {
        !          1734:     int pdival = size == sz_byte && reg != 7 ? 1 : size == sz_long ? 4 : 2;
        !          1735:     UBYTE *p = *pcpp;
        !          1736:     UWORD dp;
        !          1737:     int r;
        !          1738:     int x86r, tmpr;
        !          1739: 
        !          1740:     pdival *= pidmult;
        !          1741:     
        !          1742:     init_eainfo(eai);
        !          1743:     eai->mode = mode;
        !          1744:     eai->size = size;
        !          1745:     eai->reg = reg;
        !          1746:     
        !          1747:     switch(mode){
        !          1748:      case Dreg:
        !          1749:        if (size != sz_long && (ea_purpose & EA_STORE))
        !          1750:            ea_purpose |= EA_LOAD;
        !          1751:        /* Is the register in the cache, or do we need it there? If so, lock it.
        !          1752:         * This will make sure we are the only ones who have it locked, so we
        !          1753:         * can mess with it without expecting surprises. 
        !          1754:         * Get it without a constant offset. */
        !          1755:        x86r = map->dreg_map[reg];
        !          1756:        if (x86r != -1 || (ea_purpose & EA_LOAD)) {
        !          1757:            eai->regs_locked = 1;
        !          1758:            x86r = eai->locked_regs[0] = get_and_lock_68k_reg(map, reg, 1, 0, 1);
        !          1759:        }
        !          1760:        /* And if we need to manipulate it with byte sizes, we ought to get it
        !          1761:         * into an appropriate register */
        !          1762:        if (size == sz_byte && x86r != -1 && (ea_purpose & (EA_LOAD|EA_STORE))
        !          1763:            && ((1 << x86r) & DATA_X86_REGS) == 0) 
        !          1764:        {
        !          1765:            int newr = get_typed_x86_register(map, DATA_X86_REGS);
        !          1766:            compile_force_byteorder(map, x86r, BO_NORMAL, 0);
        !          1767:            compile_move_reg_reg(newr, x86r, sz_long);
        !          1768:            map->x86_locked[newr]++;
        !          1769:            compile_unlock_reg(map, x86r);
        !          1770:            eai->locked_regs[0] = newr;
        !          1771:            
        !          1772:            /* We need to update the register cache, otherwise storeea
        !          1773:             * will mark the new one dirty, but that is never checked. */
        !          1774:            map->x86_const_offset[newr] = map->x86_const_offset[x86r];
        !          1775:            map->x86_dirty[newr] = map->x86_dirty[x86r];
        !          1776:            map->x86_cache_reg[x86r] = -1;
        !          1777:            map->x86_cache_reg[newr] = reg;
        !          1778:            map->x86_cr_type[newr] = 1;
        !          1779:            map->dreg_map[reg] = newr;
        !          1780:        }
        !          1781:        if (eai->regs_locked == 1) {
        !          1782:            eai->data_reg = eai->locked_regs[0];
        !          1783:            eai->data_const_off = map->x86_const_offset[eai->data_reg];
        !          1784:        }
        !          1785:        break;
        !          1786:        
        !          1787:      case Areg:
        !          1788:        if (size != sz_long && (ea_purpose & EA_STORE))
        !          1789:            printf("Areg != long\n");
        !          1790:        x86r = map->areg_map[reg];
        !          1791:        if (x86r != -1 || (ea_purpose & EA_LOAD)) {
        !          1792:            eai->regs_locked = 1;
        !          1793:            x86r = eai->locked_regs[0] = get_and_lock_68k_reg(map, reg, 0, 0, 1);
        !          1794:        }
        !          1795:        /* And if we need to get the byte part, we ought to get it
        !          1796:         * into an appropriate register */
        !          1797:        if (size == sz_byte && x86r != -1 && (ea_purpose & EA_LOAD)
        !          1798:            && ((1 << x86r) & DATA_X86_REGS) == 0)
        !          1799:        {
        !          1800:            int newr = get_typed_x86_register(map, DATA_X86_REGS);
        !          1801:            compile_force_byteorder(map, x86r, BO_NORMAL, 0);
        !          1802:            compile_move_reg_reg(newr, x86r, sz_long);
        !          1803:            map->x86_locked[newr]++;
        !          1804:            compile_unlock_reg(map, x86r);
        !          1805:            eai->locked_regs[0] = newr;
        !          1806:        }
        !          1807:        if (eai->regs_locked == 1) {
        !          1808:            eai->data_reg = eai->locked_regs[0];
        !          1809:            eai->data_const_off = map->x86_const_offset[eai->data_reg];
        !          1810:        }
        !          1811:        break;
        !          1812:        
        !          1813:      case Ad16:
        !          1814:        eai->addr_const_off = (WORD)((*p << 8) | *(p+1));
        !          1815:        (*pcpp) += 2; p += 2;
        !          1816:        x86r = eai->locked_regs[0] = eai->address_reg = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0);
        !          1817:        compile_force_byteorder(map, x86r, BO_NORMAL, 0);
        !          1818:        eai->addr_const_off += map->x86_const_offset[x86r];
        !          1819:        eai->regs_locked = 1;
        !          1820:        break;
        !          1821: 
        !          1822:      case Aind:
        !          1823:        x86r = eai->locked_regs[0] = eai->address_reg = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0);
        !          1824:        compile_force_byteorder(map, x86r, BO_NORMAL, 0);
        !          1825:        eai->addr_const_off = map->x86_const_offset[x86r];
        !          1826:        eai->regs_locked = 1;
        !          1827:        break;
        !          1828:        
        !          1829:      case Apdi:
        !          1830:        x86r = eai->locked_regs[0] = eai->address_reg = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0);
        !          1831:        compile_force_byteorder(map, x86r, BO_NORMAL, 0);
        !          1832:        /* 
        !          1833:         * Add this reg with its current offset to the undo buffer.
        !          1834:         * Since we have locked it, we are certain that it will not be
        !          1835:         * modified at least before generate_possible_exits() has done its
        !          1836:         * job.
        !          1837:         */
        !          1838:        add_undo(pud, x86r, reg, map->x86_const_offset[x86r], map->x86_dirty[x86r]);
        !          1839:        map->x86_const_offset[x86r] -= pdival;
        !          1840:        eai->addr_const_off = map->x86_const_offset[x86r];
        !          1841:        eai->regs_locked = 1;
        !          1842:        break;
        !          1843:        
        !          1844:      case Aipi:
        !          1845:        x86r = eai->locked_regs[0] = eai->address_reg = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0);
        !          1846:        compile_force_byteorder(map, x86r, BO_NORMAL, 0);
        !          1847:        add_undo(pud, x86r, reg, map->x86_const_offset[x86r], map->x86_dirty[x86r]);
        !          1848:        eai->addr_const_off = map->x86_const_offset[x86r];
        !          1849:        map->x86_const_offset[x86r] += pdival;
        !          1850:        eai->regs_locked = 1;
        !          1851:        break;
        !          1852: 
        !          1853:      case Ad8r:
        !          1854:        dp = (WORD)((*p << 8) | *(p+1));
        !          1855:        r = (dp & 0x7000) >> 12;
        !          1856:        (*pcpp) += 2; p += 2;   
        !          1857:        
        !          1858:        tmpr = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0);
        !          1859:        x86r = get_and_lock_68k_reg(map, r, dp & 0x8000 ? 0 : 1, 0, 1);
        !          1860:        compile_force_byteorder(map, x86r, BO_NORMAL, 0);
        !          1861:        compile_force_byteorder(map, tmpr, BO_NORMAL, 0);
        !          1862:        eai->locked_regs[0] = eai->address_reg = get_free_x86_register(map, ADDRESS_X86_REGS);
        !          1863:        map->x86_locked[eai->address_reg]++;
        !          1864:        
        !          1865:        eai->addr_const_off = map->x86_const_offset[tmpr] + (BYTE)dp;
        !          1866:        r = (dp & 0x7000) >> 12;
        !          1867: 
        !          1868:        if (dp & 0x800) {
        !          1869:            if ((LONG)eai->addr_const_off >= -128 && (LONG)eai->addr_const_off <= 127) {
        !          1870:                assemble(0x8D); 
        !          1871:                assemble(0x44 + eai->address_reg*8); /* leal disp8(dispreg,basereg),addrreg */
        !          1872:                assemble(x86r*8 + tmpr);
        !          1873:                assemble(eai->addr_const_off);
        !          1874:            } else {
        !          1875:                assemble(0x8D);
        !          1876:                assemble(0x84 + eai->address_reg*8); /* leal disp32(dispreg,basereg),addrreg */
        !          1877:                assemble(x86r*8 + tmpr);
        !          1878:                assemble_ulong(eai->addr_const_off);
        !          1879:            }
        !          1880:            eai->addr_const_off = 0;
        !          1881:        } else {
        !          1882:            assemble(0x0F); assemble(0xBF);
        !          1883:            assemble(0xC0 + x86r + eai->address_reg*8); /* movswl dispreg,addrreg */
        !          1884:            assemble(0x03); assemble(0xC0 + tmpr + eai->address_reg*8); /* addl basereg,addrreg */
        !          1885:        }
        !          1886:        compile_unlock_reg(map, x86r);
        !          1887:        compile_unlock_reg(map, tmpr);
        !          1888:        eai->regs_locked = 1;
        !          1889:        break;
        !          1890: 
        !          1891:      case PC8r:
        !          1892:        dp = (WORD)((*p << 8) | *(p+1));
        !          1893:        (*pcpp) += 2; p += 2;
        !          1894:        r = (dp & 0x7000) >> 12;
        !          1895:        eai->addr_const_off = pca + (BYTE)dp;
        !          1896:        if (dp & 0x800) {
        !          1897:            eai->locked_regs[0] = eai->address_reg = get_and_lock_68k_reg(map, r, dp & 0x8000 ? 0 : 1, 0, 1);
        !          1898:        } else {
        !          1899:            eai->regs_locked = 2;
        !          1900:            tmpr = get_and_lock_68k_reg(map, r, dp & 0x8000 ? 0 : 1, 0, 1);
        !          1901:            compile_force_byteorder(map, tmpr, BO_NORMAL, 0);
        !          1902:            eai->locked_regs[0] = eai->address_reg = get_free_x86_register(map, ADDRESS_X86_REGS);
        !          1903:            map->x86_locked[eai->address_reg]++;
        !          1904: 
        !          1905:            assemble(0x0F); assemble(0xBF);
        !          1906:            assemble(0xC0 + tmpr + eai->address_reg*8); /* movswl dispreg,addrreg */
        !          1907:            compile_unlock_reg(map, tmpr);
        !          1908:        }
        !          1909:        eai->regs_locked = 1;
        !          1910:        break;
        !          1911:        
        !          1912:      case PC16:
        !          1913:        eai->addr_const_off = pca + (WORD)((*p << 8) | *(p+1));
        !          1914:        eai->address_reg = -2;
        !          1915:        (*pcpp) += 2; p += 2;
        !          1916:        break;
        !          1917:        
        !          1918:      case absw:
        !          1919:        eai->addr_const_off = (WORD)((*p << 8) | *(p+1));
        !          1920:        eai->address_reg = -2;
        !          1921:        (*pcpp) += 2; p += 2;
        !          1922:        break;
        !          1923: 
        !          1924:      case absl:
        !          1925:        eai->addr_const_off = (LONG)((*p << 24) | (*(p+1) << 16)
        !          1926:                                   | (*(p+2) << 8) | *(p+3));
        !          1927:        eai->address_reg = -2;
        !          1928:        (*pcpp) += 4; p += 4;
        !          1929:        break;
        !          1930: 
        !          1931:      case imm:
        !          1932:        if (size == sz_long)
        !          1933:            goto imm2_const;
        !          1934:        if (size == sz_word)
        !          1935:            goto imm1_const;
        !          1936:        
        !          1937:        /* fall through */
        !          1938:      case imm0:
        !          1939:        eai->data_const_off = (BYTE)*(p+1);
        !          1940:        eai->data_reg = -2;
        !          1941:        (*pcpp) += 2; p += 2;
        !          1942:        break;
        !          1943: 
        !          1944:      case imm1:
        !          1945:        imm1_const:
        !          1946:        eai->data_const_off = (WORD)((*p << 8) | *(p+1));
        !          1947:        eai->data_reg = -2;
        !          1948:        (*pcpp) += 2; p += 2;
        !          1949:        break;
        !          1950: 
        !          1951:      case imm2:
        !          1952:        imm2_const:
        !          1953:        eai->data_const_off = (LONG)((*p << 24) | (*(p+1) << 16)
        !          1954:                                   | (*(p+2) << 8) | *(p+3));
        !          1955:        eai->data_reg = -2;
        !          1956:        (*pcpp) += 4; p += 4;
        !          1957:        break;
        !          1958: 
        !          1959:      case immi:
        !          1960:        eai->data_const_off = (BYTE)reg;
        !          1961:        eai->data_reg = -2;
        !          1962:        break;
        !          1963: 
        !          1964:      default:
        !          1965:        break;
        !          1966:     }
        !          1967:     eai->purpose = ea_purpose;
        !          1968: }
        !          1969: 
        !          1970: static int compile_fetchea(struct register_mapping *map, struct ea_info *eai,
        !          1971:                           ULONG *reg_offset)
        !          1972: {
        !          1973:     int x86r;
        !          1974:     ULONG constant;
        !          1975:     
        !          1976:     if (eai->data_reg != -1) {
        !          1977:        *reg_offset = eai->data_const_off;
        !          1978:        return eai->data_reg;
        !          1979:     }
        !          1980:     
        !          1981:     if (eai->mode == Dreg || eai->mode == Areg || eai->mode == immi || eai->mode == imm
        !          1982:        || eai->mode == imm0 || eai->mode == imm1 || eai->mode == imm2
        !          1983:        || eai->address_reg == -1)
        !          1984:        printf("BUG\n");
        !          1985: 
        !          1986:     *reg_offset = 0;
        !          1987:     if (eai->size == sz_byte)
        !          1988:        x86r = get_typed_x86_register(map, DATA_X86_REGS);
        !          1989:     else
        !          1990:        x86r = get_free_x86_register(map, ALL_X86_REGS);
        !          1991:     map->x86_locked[x86r]++;
        !          1992: 
        !          1993:     compile_force_byteorder(map, eai->address_reg, BO_NORMAL, 0);
        !          1994:     compile_move_reg_from_mem_regoffs(x86r, eai->address_reg, 
        !          1995:                                      (ULONG)(eai->addr_const_off + address_space),
        !          1996:                                      eai->size);
        !          1997:     
        !          1998:     switch (eai->size) {
        !          1999:      case sz_byte: map->x86_byteorder[x86r] = BO_NORMAL; break;
        !          2000:      case sz_word: map->x86_byteorder[x86r] = BO_SWAPPED_WORD; break;
        !          2001:      case sz_long: map->x86_byteorder[x86r] = BO_SWAPPED_LONG; break;
        !          2002:     }
        !          2003:     return x86r;
        !          2004: }
        !          2005: 
        !          2006: static void compile_storeea(struct register_mapping *map, struct ea_info *eai,
        !          2007:                             int valuereg, ULONG valueoffset)
        !          2008: {
        !          2009:     ULONG constant;
        !          2010:     int newr, cacher;
        !          2011:     
        !          2012:     if (eai->mode == Dreg) {
        !          2013:        /* Easy case first: just put the reg in the register cache */
        !          2014:        if (eai->size == sz_long) {
        !          2015:            newr = compile_move_const_reg(map, valuereg, &valueoffset, 0);
        !          2016:            compile_unlock_reg(map, valuereg);
        !          2017:            if (valueoffset != 0)
        !          2018:                printf("Hoppla?\n");
        !          2019:            /*
        !          2020:             * Two checks whether registers are already in the cache.
        !          2021:             */
        !          2022:            if (map->x86_cache_reg[newr] != -1 
        !          2023:                && (map->x86_cache_reg[newr] != eai->reg
        !          2024:                    || map->x86_cr_type[newr] != 1))
        !          2025:            {
        !          2026:                remove_x86r_from_cache(map, newr, 0);
        !          2027:            }
        !          2028:            if (map->dreg_map[eai->reg] != -1
        !          2029:                && map->dreg_map[eai->reg] != newr) 
        !          2030:            {
        !          2031:                /* No need to write back */
        !          2032:                map->x86_cache_reg[map->dreg_map[eai->reg]] = -1;
        !          2033:            }
        !          2034:            map->x86_cache_reg[newr] = eai->reg;
        !          2035:            map->x86_cr_type[newr] = 1;
        !          2036:            map->x86_const_offset[newr] = valueoffset;
        !          2037:            map->x86_dirty[newr] = 1;
        !          2038:            map->dreg_map[eai->reg] = newr;
        !          2039:            map->x86_verified[newr] = 0;
        !          2040:            return;
        !          2041:        }
        !          2042:        
        !          2043:        if (eai->data_reg < 0)
        !          2044:            printf("Don't have a data reg to move to!\n");
        !          2045: 
        !          2046:        compile_force_byteorder(map, eai->data_reg, BO_NORMAL, 1);
        !          2047:        compile_force_byteorder(map, valuereg, BO_NORMAL, 1);
        !          2048:        map->x86_verified[eai->data_reg] = 0;
        !          2049:        if (valuereg == -2) {
        !          2050:            if (eai->size == sz_byte) {
        !          2051:                if (((1 << eai->data_reg) & DATA_X86_REGS) == 0)
        !          2052:                    printf("Uhoh - not moving to proper type reg\n");
        !          2053:                assemble(0xB0 + eai->data_reg);
        !          2054:                assemble(valueoffset);
        !          2055:            } else {
        !          2056:                assemble(0x66); assemble(0xB8 + eai->data_reg);
        !          2057:                assemble_uword(valueoffset);
        !          2058:            }
        !          2059:        } else {
        !          2060:            /* Move the subword into the right place */
        !          2061: /* This shouldn't be necessary */
        !          2062: #if 0
        !          2063:            newr = compile_force_const_reg(map, valuereg, &valueoffset);
        !          2064: #else
        !          2065:            newr = valuereg;
        !          2066: #endif
        !          2067:            compile_unlock_reg(map, valuereg);
        !          2068:            compile_move_reg_reg(eai->data_reg, newr, eai->size);
        !          2069:        }
        !          2070:        map->x86_dirty[eai->data_reg] = 1;
        !          2071:        return;
        !          2072:     } else if (eai->mode == Areg) {
        !          2073:        if (eai->size != sz_long)
        !          2074:            printf("Areg put != long\n");
        !          2075: 
        !          2076:        newr = compile_force_const_reg(map, valuereg, &valueoffset, 0);
        !          2077:        compile_unlock_reg(map, valuereg);
        !          2078: 
        !          2079:        if (map->x86_cache_reg[newr] != -1 
        !          2080:            && (map->x86_cache_reg[newr] != eai->reg
        !          2081:                || map->x86_cr_type[newr] != 0))
        !          2082:        {
        !          2083:            remove_x86r_from_cache(map, newr, 0);
        !          2084:        }
        !          2085:        if (map->areg_map[eai->reg] != -1
        !          2086:            && map->areg_map[eai->reg] != newr)
        !          2087:        {
        !          2088:            /* No need to write back */
        !          2089:            map->x86_cache_reg[map->areg_map[eai->reg]] = -1;
        !          2090:        }
        !          2091:        map->x86_verified[newr] = 0;
        !          2092:        map->x86_cache_reg[newr] = eai->reg;
        !          2093:        map->x86_cr_type[newr] = 0;
        !          2094:        map->x86_const_offset[newr] = valueoffset;
        !          2095:        map->x86_dirty[newr] = 1;
        !          2096:        map->areg_map[eai->reg] = newr;
        !          2097:        return;
        !          2098:     }
        !          2099: 
        !          2100:     compile_offset_reg(map, valuereg, valueoffset);
        !          2101:     /* Correct the byteorder */
        !          2102:     if (valuereg != -2) {
        !          2103:        switch (eai->size) {
        !          2104:         case sz_byte: compile_force_byteorder(map, valuereg, BO_NORMAL, 1); break;
        !          2105:         case sz_word: compile_force_byteorder(map, valuereg, BO_SWAPPED_WORD, 1); break;
        !          2106:         case sz_long: compile_force_byteorder(map, valuereg, BO_SWAPPED_LONG, 1); break;
        !          2107:        }
        !          2108:     } else {
        !          2109:        switch (eai->size) {
        !          2110:         case sz_long:
        !          2111:            valueoffset = (((valueoffset & 0xFF000000) >> 24)
        !          2112:                           | ((valueoffset & 0xFF0000) >> 8)
        !          2113:                           | ((valueoffset & 0xFF00) << 8)
        !          2114:                           | ((valueoffset & 0xFF) << 24));
        !          2115:            break;
        !          2116:         case sz_word:
        !          2117:            valueoffset = (((valueoffset & 0xFF00) >> 8)
        !          2118:                           | ((valueoffset & 0xFF) << 8));
        !          2119:            break;
        !          2120:        }
        !          2121:     }
        !          2122:     
        !          2123:     /* We may have the value either in valuereg or in valueoffset by now,
        !          2124:      * not in both (see call to compile_offset_reg() above) */
        !          2125:     
        !          2126:     if (valuereg != -2) {
        !          2127:        compile_move_reg_to_mem_regoffs(eai->address_reg,
        !          2128:                                        (ULONG)(eai->addr_const_off + address_space),
        !          2129:                                        valuereg, eai->size);
        !          2130:     } else {
        !          2131:        /* generate code to move valueoffset,eaoffset(eareg) */
        !          2132:        switch(eai->size) {                   
        !          2133:         case sz_byte: assemble(0xC6); break;
        !          2134:         case sz_word: assemble(0x66); /* fall through */
        !          2135:         case sz_long: assemble(0xC7); break;
        !          2136:        }
        !          2137:        if (eai->address_reg == -2) { /* absolute or PC-relative */
        !          2138:            assemble(0x05);
        !          2139:            assemble_long(eai->addr_const_off + address_space);
        !          2140:        } else {
        !          2141:            assemble(0x80 + eai->address_reg);
        !          2142:            assemble_long(eai->addr_const_off + address_space);
        !          2143:        }
        !          2144:        switch(eai->size) {
        !          2145:         case sz_byte: assemble(valueoffset); break;
        !          2146:         case sz_word: assemble_uword(valueoffset); break;
        !          2147:         case sz_long: assemble_ulong(valueoffset); break;
        !          2148:        }
        !          2149:     }
        !          2150: }
        !          2151: 
        !          2152: #define CE_STACK_SIZE 1000
        !          2153: 
        !          2154: static struct {
        !          2155:     struct register_mapping map;
        !          2156:     char *jmpoffs;
        !          2157:     ULONG address;
        !          2158:     int noflush:1;
        !          2159: } compile_exit_stack[CE_STACK_SIZE];
        !          2160: 
        !          2161: static int cesp;
        !          2162: 
        !          2163: static struct register_mapping current_exit_regmap;
        !          2164: 
        !          2165: static void generate_exit(struct register_mapping *map, int address)
        !          2166: {
        !          2167:     int i;
        !          2168:     
        !          2169:     if (map != NULL)
        !          2170:        sync_reg_cache (map, 1);
        !          2171:     assemble(0xB8); /* movl $new_pc,%eax */
        !          2172:     assemble_ulong(address);
        !          2173:     assemble(0xC3); /* RET */
        !          2174: }
        !          2175: 
        !          2176: static void copy_map_with_undo(struct register_mapping *dst, 
        !          2177:                               struct register_mapping *src,
        !          2178:                               struct pid_undo *pud)
        !          2179: {
        !          2180:     int i;
        !          2181:     *dst = *src;
        !          2182:     for (i = 0; i < pud->used; i++) {
        !          2183:        int m68kr = pud->m68kr[i];
        !          2184:        int x86r = pud->x86r[i];
        !          2185:        int old_cr = dst->areg_map[m68kr];
        !          2186:        if (old_cr != -1) {
        !          2187:            dst->x86_cache_reg[old_cr] = -1;
        !          2188:        }
        !          2189:        dst->x86_cache_reg[x86r] = m68kr;
        !          2190:        dst->areg_map[m68kr] = x86r;
        !          2191:        dst->x86_cr_type[x86r] = 0;
        !          2192:        dst->x86_const_offset[x86r] = pud->offs[i];
        !          2193:        dst->x86_dirty[x86r] = pud->dirty[i];
        !          2194:     }
        !          2195: }
        !          2196: 
        !          2197: static void generate_possible_exit(struct register_mapping *map,
        !          2198:                                   struct ea_info *eai, int iip,
        !          2199:                                   struct pid_undo *pud)
        !          2200: {
        !          2201:     struct register_mapping exit_regmap;
        !          2202:     switch (eai->address_reg) {
        !          2203:      case -1:
        !          2204:        /* EA doesn't refer to memory */
        !          2205:        break;
        !          2206:      case -2:
        !          2207:        /* Only a constant offset */
        !          2208:        eai->addr_const_off &= (1<<24)-1;
        !          2209:        if (!good_address_map[eai->addr_const_off]) {
        !          2210:            copy_map_with_undo(&exit_regmap, map, pud);
        !          2211:            generate_exit(&exit_regmap, insn_info[iip].address);
        !          2212:        }
        !          2213:        break;
        !          2214:      default:
        !          2215:        if (map->x86_verified[eai->address_reg])
        !          2216:            break;
        !          2217:        map->x86_verified[eai->address_reg] = 1;
        !          2218:        if (cesp == CE_STACK_SIZE) {
        !          2219:            copy_map_with_undo(&exit_regmap, map, pud);
        !          2220:            generate_exit(&exit_regmap, insn_info[iip].address);
        !          2221:            break;
        !          2222:        }
        !          2223:        copy_map_with_undo(&compile_exit_stack[cesp].map, map, pud);
        !          2224:        compile_exit_stack[cesp].address = insn_info[iip].address;
        !          2225:        assemble(0x80); assemble(0xB8 + eai->address_reg); /* cmpb $0, good_address_map(x86r) */
        !          2226:        assemble_long(good_address_map + eai->addr_const_off);
        !          2227:        assemble(0);
        !          2228:        assemble(0x0F); assemble(0x84); /* JE finish */
        !          2229:        compile_exit_stack[cesp].jmpoffs = compile_here();
        !          2230:        compile_exit_stack[cesp].noflush = 0;
        !          2231:        assemble_ulong(0);
        !          2232:        cesp++;
        !          2233:        break;
        !          2234:     }
        !          2235: }
        !          2236: 
        !          2237: static void finish_exits(void)
        !          2238: {
        !          2239:     int i;
        !          2240:     for (i = 0; i < cesp; i++) {
        !          2241:        char *exitpoint = compile_here();
        !          2242:        char *nextpoint;
        !          2243: 
        !          2244:        if (compile_exit_stack[i].noflush)
        !          2245:            generate_exit(NULL, compile_exit_stack[i].address);
        !          2246:        else
        !          2247:            generate_exit(&compile_exit_stack[i].map, compile_exit_stack[i].address);
        !          2248:        nextpoint = compile_here();
        !          2249:        compile_org(compile_exit_stack[i].jmpoffs);
        !          2250:        assemble_ulong(exitpoint - (compile_exit_stack[i].jmpoffs + 4));
        !          2251:        compile_org(nextpoint);
        !          2252:     }
        !          2253: }
        !          2254: 
        !          2255: static void finish_condjumps(int lastiip)
        !          2256: {
        !          2257:     int iip;
        !          2258:     char *lastptr = compile_here();
        !          2259:     for (iip = 0; iip < lastiip; iip++) {
        !          2260:        char *fillin = insn_info[iip].compiled_fillin;
        !          2261:        if (fillin != NULL) {
        !          2262:            compile_org(insn_info[iip].compiled_fillin);
        !          2263:            assemble_ulong(insn_info[insn_info[iip].jumps_to].compiled_jumpaddr - (fillin + 4));
        !          2264:        }
        !          2265:     }
        !          2266:     compile_org(lastptr);
        !          2267: }
        !          2268: 
        !          2269: #define CC_X_FROM_86C 1
        !          2270: #define CC_C_FROM_86C 2
        !          2271: #define CC_Z_FROM_86Z 4
        !          2272: #define CC_V_FROM_86V 8 
        !          2273: #define CC_N_FROM_86N 16
        !          2274: #define CC_TEST_REG   32
        !          2275: #define CC_Z_FROM_86C 64
        !          2276: #define CC_SAHF       128
        !          2277: #define CC_TEST_CONST 256
        !          2278: #define CC_AFTER_RO   512
        !          2279: #define CC_AFTER_ROX  1024
        !          2280: 
        !          2281: #define CC68K_C 16
        !          2282: #define CC68K_V 8
        !          2283: #define CC68K_Z 4
        !          2284: #define CC68K_N 2
        !          2285: #define CC68K_X 1
        !          2286: 
        !          2287: static unsigned int cc_status;
        !          2288: static int cc_reg;
        !          2289: static ULONG cc_offset;
        !          2290: static wordsizes cc_size;
        !          2291: 
        !          2292: static void compile_do_cc_test_reg(struct register_mapping *map)
        !          2293: {
        !          2294:     compile_force_byteorder(map, cc_reg, BO_NORMAL, 1);
        !          2295:     if (cc_offset != 0)
        !          2296:        printf("Pull my finger\n");
        !          2297:     if (cc_size == sz_word) /* test ccreg */
        !          2298:        assemble(0x66);
        !          2299:     if (cc_size == sz_byte)
        !          2300:        assemble(0x84);
        !          2301:     else
        !          2302:        assemble(0x85);
        !          2303:     assemble(0xC0 + 9*cc_reg);
        !          2304: }
        !          2305: 
        !          2306: static int compile_flush_cc_cache(struct register_mapping *map, int status, 
        !          2307:                                  int live_at_end, int user_follows,
        !          2308:                                  int user_live_at_end, int user_ccval)
        !          2309: {
        !          2310:     int status_for_user = 0;
        !          2311: 
        !          2312:     if (user_follows) {
        !          2313:        int need_for_user = 0;
        !          2314:        int user_flagmask = cc_flagmask(user_ccval);
        !          2315: 
        !          2316:        if (user_flagmask & CC68K_C)
        !          2317:            need_for_user |= CC_C_FROM_86C;
        !          2318:        if (user_flagmask & CC68K_Z)
        !          2319:            need_for_user |= CC_Z_FROM_86Z;
        !          2320:        if (user_flagmask & CC68K_N)
        !          2321:            need_for_user |= CC_N_FROM_86N;
        !          2322:        if (user_flagmask & CC68K_V)
        !          2323:            need_for_user |= CC_V_FROM_86V;
        !          2324: 
        !          2325:        /* Check whether we can satisfy the user's needs in a simple way. */
        !          2326:        if ((need_for_user & status) == need_for_user)
        !          2327:            status_for_user = status;
        !          2328:        else if (user_flagmask == CC68K_Z && status == CC_Z_FROM_86C)
        !          2329:            status_for_user = status;
        !          2330:        else if (status == CC_TEST_REG && (user_flagmask & (CC68K_C|CC68K_V|CC68K_Z|CC68K_N)) != 0) {
        !          2331:            if (cc_reg == -2) {
        !          2332:                status_for_user = CC_TEST_CONST;
        !          2333:            } else {
        !          2334:                compile_do_cc_test_reg(map);
        !          2335:                status_for_user = status = (CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V);
        !          2336:            }
        !          2337:        } else if (status == CC_AFTER_RO) {
        !          2338:            /* We fake some information here... */
        !          2339:            if (user_flagmask == CC68K_C && (user_live_at_end & ~CC68K_C) == 0)
        !          2340:                status = status_for_user = CC_C_FROM_86C;
        !          2341:            else if (((user_flagmask | user_live_at_end) & CC68K_C) == 0) {
        !          2342:                status = CC_TEST_REG; user_live_at_end = CC68K_Z|CC68K_N|CC68K_V;
        !          2343:                status_for_user = (CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V);
        !          2344:            } else
        !          2345:                status_for_user = CC_SAHF;
        !          2346:        } else if (status == CC_AFTER_ROX) {
        !          2347:            if (user_flagmask == CC68K_C && (user_live_at_end & ~(CC68K_C|CC68K_X)) == 0)
        !          2348:                status = status_for_user = CC_C_FROM_86C;
        !          2349:            else if (((user_flagmask | user_live_at_end) & (CC68K_C|CC68K_X)) == 0) {
        !          2350:                status = CC_TEST_REG; user_live_at_end = CC68K_Z|CC68K_N|CC68K_V;
        !          2351:                status_for_user = (CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V);
        !          2352:            } else
        !          2353:                status_for_user = CC_SAHF;
        !          2354:        } else if (need_for_user != 0) {
        !          2355:            /* No way to handle it easily */
        !          2356:            status_for_user = CC_SAHF;
        !          2357:        }
        !          2358:        if (status_for_user != CC_SAHF)
        !          2359:            live_at_end = user_live_at_end;
        !          2360:     }
        !          2361: 
        !          2362:     /*
        !          2363:      * Now store the flags which are live at the end of this insn and set by 
        !          2364:      * us into their home locations 
        !          2365:      */
        !          2366:     if (status == CC_TEST_REG) {
        !          2367:        if ((live_at_end & (CC68K_C|CC68K_V|CC68K_Z|CC68K_N)) == 0)
        !          2368:            goto all_ok;
        !          2369: 
        !          2370:        if (cc_reg == -2) {
        !          2371:            UBYTE f = 0;
        !          2372:            if (cc_size == sz_byte) {
        !          2373:                f |= (cc_offset & 0x80) ? 0x80 : 0;
        !          2374:                f |= (cc_offset & 0xFF) == 0 ? 0x40 : 0;
        !          2375:            } else if (cc_size == sz_byte) {
        !          2376:                f |= (cc_offset & 0x8000) ? 0x80 : 0;
        !          2377:                f |= (cc_offset & 0xFFFF) == 0 ? 0x40 : 0;
        !          2378:            } else {
        !          2379:                f |= (cc_offset & 0x80000000) ? 0x80 : 0;
        !          2380:                f |= (cc_offset & 0xFFFFFFFF) == 0 ? 0x40 : 0;
        !          2381:            }
        !          2382:            assemble(0x66); assemble(0xC7); assemble(0x05); 
        !          2383:            assemble_long((char*)&regflags);
        !          2384:            assemble_uword(f);
        !          2385:        } else {
        !          2386:            int tmpr = get_free_x86_register(map, ALL_X86_REGS);
        !          2387:            compile_do_cc_test_reg(map);
        !          2388: 
        !          2389:            /* pushfl; popl tmpr; movl tempr, regflags */
        !          2390:            assemble(0x9C); assemble(0x58+tmpr);
        !          2391:            compile_move_reg_to_mem_regoffs(-2, (ULONG)&regflags, tmpr, sz_word);
        !          2392:        }
        !          2393:     } else if (status == CC_Z_FROM_86C) {
        !          2394:        if ((live_at_end & CC68K_Z) != 0) {
        !          2395:            int tmpr = get_typed_x86_register(map, DATA_X86_REGS);
        !          2396:            assemble(0x9C);
        !          2397:            /* setnc tmpr; shl $6, tmpr; andb $~0x40, regflags; orb tmpr, regflags */
        !          2398:            assemble(0x0F); assemble(0x93); assemble(0xC0 + tmpr);
        !          2399:            assemble(0xC0); assemble(4*8 + 0xC0 + tmpr); assemble(6);
        !          2400:            assemble(0x80); assemble(0x05+0x20); assemble_long(&regflags); assemble((UBYTE)~0x40);
        !          2401:            assemble(0x08); assemble(0x05+ tmpr*8); assemble_long(&regflags);
        !          2402:            assemble(0x9D);
        !          2403:        }
        !          2404:     } else if (status == CC_AFTER_RO || status == CC_AFTER_ROX) {
        !          2405:        int tmpr = get_typed_x86_register(map, DATA_X86_REGS);
        !          2406:        assemble(0x9C);
        !          2407:        compile_do_cc_test_reg(map);
        !          2408:        /* pushfl; popl tmpr; movl tempr, regflags */
        !          2409:        assemble(0x9C); assemble(0x58+tmpr);
        !          2410:        assemble(0x9D);
        !          2411:        /* adc $0, tmpr */
        !          2412:        assemble(0x80); assemble(0xC0 + tmpr + 8*2); assemble(0);
        !          2413:        compile_move_reg_to_mem_regoffs(-2, (ULONG)&regflags, tmpr, sz_word);
        !          2414:        if (status == CC_AFTER_ROX)
        !          2415:            compile_move_reg_to_mem_regoffs(-2, 2 + (ULONG)&regflags, tmpr, sz_word);
        !          2416:     } else if (status != 0) {
        !          2417:        assert((status & CC_TEST_REG) == 0);
        !          2418:        assert (status == (CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_X_FROM_86C | CC_V_FROM_86V)
        !          2419:                || status == (CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V)
        !          2420:                || status == CC_C_FROM_86C);
        !          2421:            
        !          2422:        if ((status & CC_X_FROM_86C) == 0)
        !          2423:            live_at_end &= ~CC68K_X;
        !          2424:        
        !          2425:        if (status == CC_C_FROM_86C && (live_at_end & CC68K_C) != 0) 
        !          2426:            fprintf(stderr, "Shouldn't be needing C here!\n");
        !          2427:        else if (live_at_end) {
        !          2428:            if ((live_at_end & CC68K_X) == 0)
        !          2429:                status &= ~CC_X_FROM_86C;
        !          2430: 
        !          2431:            if (live_at_end) {
        !          2432:                int tmpr = get_free_x86_register(map, ALL_X86_REGS);
        !          2433:                /* pushfl; popl tmpr; movl tempr, regflags */
        !          2434:                assemble(0x9C); assemble(0x58+tmpr);
        !          2435:                compile_move_reg_to_mem_regoffs(-2, (ULONG)&regflags, tmpr, sz_word);
        !          2436:                
        !          2437:                if (status & CC_X_FROM_86C) {
        !          2438:                    compile_move_reg_to_mem_regoffs(-2, 2 + (ULONG)&regflags, tmpr, sz_word);
        !          2439:                }
        !          2440:            }
        !          2441:        }
        !          2442:     }
        !          2443: 
        !          2444:     all_ok:
        !          2445:     return status_for_user;
        !          2446: }
        !          2447:     
        !          2448: static char *compile_condbranch(struct register_mapping *map, int iip,
        !          2449:                                int new_cc_status)
        !          2450: {
        !          2451:     int cc = insn_info[iip].dp->cc;
        !          2452:     int flagsused = cc_flagmask(cc);
        !          2453:     int flagsneeded = 0;
        !          2454:     char *undo_pointer = compile_here();
        !          2455: 
        !          2456:     if (flagsused & CC68K_C)
        !          2457:        flagsneeded |= CC_C_FROM_86C;
        !          2458:     if (flagsused & CC68K_Z)
        !          2459:        flagsneeded |= CC_Z_FROM_86Z;
        !          2460:     if (flagsused & CC68K_N)
        !          2461:        flagsneeded |= CC_N_FROM_86N;
        !          2462:     if (flagsused & CC68K_V)
        !          2463:        flagsneeded |= CC_V_FROM_86V;
        !          2464: 
        !          2465:     if (new_cc_status == CC_SAHF) {
        !          2466:        int tmpr = get_free_x86_register(map, ALL_X86_REGS);
        !          2467:        compile_move_reg_from_mem_regoffs(tmpr, -2, (ULONG)&regflags, sz_long);
        !          2468:        assemble(0x66); assemble(0x50+tmpr); assemble(0x66); assemble(0x9D);
        !          2469:        new_cc_status = CC_C_FROM_86C|CC_Z_FROM_86Z|CC_N_FROM_86N|CC_V_FROM_86V;
        !          2470:     } else if (new_cc_status == CC_TEST_CONST) {
        !          2471:        int n,z;
        !          2472:        switch(cc_size) {
        !          2473:         case sz_byte: n = ((BYTE)cc_offset) < 0; z = ((BYTE)cc_offset) == 0; break;
        !          2474:         case sz_word: n = ((WORD)cc_offset) < 0; z = ((WORD)cc_offset) == 0; break;
        !          2475:         case sz_long: n = ((LONG)cc_offset) < 0; z = ((LONG)cc_offset) == 0; break;
        !          2476:        }
        !          2477: #define Bcc_TRUE 0
        !          2478: #define Bcc_FALSE 1
        !          2479:        flagsneeded = 0;
        !          2480:        new_cc_status = 0;
        !          2481:        switch (cc) {
        !          2482:         case 2: cc = !z ? Bcc_TRUE : Bcc_FALSE; break; /* !CFLG && !ZFLG */
        !          2483:         case 3: cc = z ? Bcc_TRUE : Bcc_FALSE; break; /* CFLG || ZFLG */
        !          2484:         case 4: cc = Bcc_TRUE; break; /* !CFLG */
        !          2485:         case 5: cc = Bcc_FALSE; break; /* CFLG */
        !          2486:         case 6: cc = !z ? Bcc_TRUE : Bcc_FALSE; break; /* !ZFLG */
        !          2487:         case 7: cc = z ? Bcc_TRUE : Bcc_FALSE; break; /* ZFLG */
        !          2488:         case 8: cc = Bcc_TRUE; break; /* !VFLG */
        !          2489:         case 9: cc = Bcc_FALSE; break; /* VFLG */
        !          2490:         case 10:cc = !n ? Bcc_TRUE : Bcc_FALSE; break; /* !NFLG */
        !          2491:         case 11:cc = n ? Bcc_TRUE : Bcc_FALSE; break; /* NFLG */
        !          2492:         case 12:cc = !n ? Bcc_TRUE : Bcc_FALSE; break; /* NFLG == VFLG */
        !          2493:         case 13:cc = n ? Bcc_TRUE : Bcc_FALSE; break; /* NFLG != VFLG */
        !          2494:         case 14:cc = !n && !z ? Bcc_TRUE : Bcc_FALSE; break; /* !ZFLG && (NFLG == VFLG) */
        !          2495:         case 15:cc = n || z ? Bcc_TRUE : Bcc_FALSE; break; /* ZFLG || (NFLG != VFLG) */
        !          2496:        }
        !          2497:     } else if (new_cc_status == CC_Z_FROM_86C) {
        !          2498:        if (cc == 6 || cc == 7) {
        !          2499:            cc = (cc - 2) ^ 1;
        !          2500:            /* Fake... */
        !          2501:            flagsneeded = new_cc_status = CC_C_FROM_86C;
        !          2502:        } else if (cc != 0 && cc != 1)
        !          2503:            printf("Groan!\n");
        !          2504:     }
        !          2505:     
        !          2506:     if (cc == 1)
        !          2507:        return NULL;
        !          2508:     
        !          2509:     if ((flagsneeded & new_cc_status) == flagsneeded) {
        !          2510:        char *result;
        !          2511:        /* We can generate a simple branch */
        !          2512:        if (cc == 0)
        !          2513:            assemble(0xE9);
        !          2514:        else
        !          2515:            assemble(0x0F);
        !          2516:        switch(cc) {
        !          2517:         case 2: assemble(0x87); break;          /* HI */
        !          2518:         case 3: assemble(0x86); break;          /* LS */
        !          2519:         case 4: assemble(0x83); break;          /* CC */
        !          2520:         case 5: assemble(0x82); break;          /* CS */
        !          2521:         case 6: assemble(0x85); break;          /* NE */
        !          2522:         case 7: assemble(0x84); break;          /* EQ */
        !          2523:         case 8: assemble(0x81); break;          /* VC */
        !          2524:         case 9: assemble(0x80); break;          /* VS */
        !          2525:         case 10:assemble(0x89); break;          /* PL */
        !          2526:         case 11:assemble(0x88); break;          /* MI */
        !          2527:         case 12:assemble(0x8D); break;          /* GE */
        !          2528:         case 13:assemble(0x8C); break;          /* LT */
        !          2529:         case 14:assemble(0x8F); break;          /* GT */
        !          2530:         case 15:assemble(0x8E); break;          /* LE */
        !          2531:        }
        !          2532:        result = compile_here();
        !          2533:        assemble_ulong(0);
        !          2534:        return result;
        !          2535:     }
        !          2536:     printf("Uhhuh.\n");
        !          2537:     return NULL;
        !          2538: }
        !          2539: 
        !          2540: static void compile_handle_bcc(struct register_mapping *map, int iip, 
        !          2541:                               int new_cc_status)
        !          2542: {
        !          2543:     insn_info[iip].compiled_fillin = compile_condbranch(map, iip, new_cc_status);
        !          2544: }
        !          2545: 
        !          2546: static void compile_handle_dbcc(struct register_mapping *map, int iip, 
        !          2547:                                int new_cc_status, int dreg)
        !          2548: {
        !          2549:     int cc = insn_info[iip].dp->cc;
        !          2550:     int flagsused = cc_flagmask(cc);
        !          2551:     int flagsneeded = 0;
        !          2552:     char *undo_pointer = compile_here();
        !          2553:     char *fillin1 = compile_condbranch(map, iip, new_cc_status);
        !          2554:     
        !          2555:     /* subw $1,dreg; jnc ... */
        !          2556:     assemble(0x66); assemble(0x83); assemble(0x05 + 5*8);
        !          2557:     assemble_long(regs.d + dreg);
        !          2558:     assemble(1);
        !          2559:     assemble(0x0F); assemble(0x83);
        !          2560:     insn_info[iip].compiled_fillin = compile_here();
        !          2561:     assemble_ulong(0);
        !          2562:     if (fillin1 != NULL) {
        !          2563:        char *oldp = compile_here();
        !          2564:        compile_org(fillin1);
        !          2565:        assemble_ulong(oldp - (fillin1+4));
        !          2566:        compile_org(oldp);
        !          2567:     }
        !          2568: }
        !          2569: 
        !          2570: static void handle_bit_insns(struct register_mapping *map, struct ea_info *srcea,
        !          2571:                             struct ea_info *dstea, instrmnem optype)
        !          2572: {
        !          2573:     int srcreg, dstreg, dstreg2;
        !          2574:     ULONG srcoffs, dstoffs;
        !          2575:     int code = (optype == i_BTST ? 0
        !          2576:                : optype == i_BSET ? 1
        !          2577:                : optype == i_BCLR ? 2
        !          2578:                : /* optype == i_BCHG */ 3);
        !          2579: 
        !          2580:     srcreg = compile_fetchea(map, srcea, &srcoffs);
        !          2581:     if (srcreg >= 0) {
        !          2582:        compile_offset_reg(map, srcreg, srcoffs);
        !          2583:        srcoffs = 0;
        !          2584:     }
        !          2585:     /* Fake some EA info... */
        !          2586:     if (dstea->data_reg == -2) {
        !          2587:        dstreg2 = compile_fetchea(map, dstea, &dstoffs);
        !          2588:        dstreg = compile_move_const_reg(map, dstreg2, &dstoffs, 0);
        !          2589:        compile_unlock_reg(map, dstreg2);
        !          2590:        dstea->data_const_off = 0;
        !          2591:        dstea->data_reg = dstreg;
        !          2592:     } else if (dstea->data_reg >= 0) {
        !          2593:        compile_offset_reg(map, dstea->data_reg, dstea->data_const_off);
        !          2594:        dstea->data_const_off = 0;
        !          2595:     }
        !          2596:     compile_force_byteorder(map, srcreg, BO_NORMAL, 0);
        !          2597:     if (srcreg != -2) {
        !          2598:        remove_x86r_from_cache(map, srcreg, 0);
        !          2599:        /* andl $something,srcreg */
        !          2600:        assemble(0x83); assemble(0xC0 + 4*8 + srcreg);
        !          2601:        if (dstea->size == sz_byte)
        !          2602:            assemble(7);
        !          2603:        else
        !          2604:            assemble(31);
        !          2605:     } else
        !          2606:        if (dstea->size == sz_byte)
        !          2607:            srcoffs &= 7;
        !          2608:        else
        !          2609:            srcoffs &= 31;
        !          2610: 
        !          2611:     /* Areg isn't possible here */
        !          2612:     if (dstea->mode == Dreg && dstea->data_reg == -1) {
        !          2613:        if (srcreg == -2) {
        !          2614:            assemble(0x0F); assemble(0xBA); assemble(5 + 8*(4 + code));
        !          2615:            assemble_long(regs.d + dstea->reg);
        !          2616:            assemble(srcoffs);
        !          2617:        } else {
        !          2618:            assemble(0x0F); assemble(0xA3 + 8*code);
        !          2619:            assemble(5 + srcreg*8);
        !          2620:            assemble_long(regs.d + dstea->reg);
        !          2621:        }
        !          2622:     } else if (dstea->data_reg >= 0) {
        !          2623:        compile_force_byteorder(map, dstea->data_reg, BO_NORMAL, 0);
        !          2624:        if (srcreg == -2) {
        !          2625:            assemble(0x0F); assemble(0xBA); assemble(0xC0 + dstea->data_reg + 8*(4 + code));
        !          2626:            assemble(srcoffs);
        !          2627:        } else {
        !          2628:            assemble(0x0F); assemble(0xA3 + 8*code);
        !          2629:            assemble(0xC0 + dstea->data_reg + srcreg*8);
        !          2630:        }
        !          2631:        if (optype != i_BTST)
        !          2632:            map->x86_dirty[dstea->data_reg] = 1;
        !          2633:     } else {
        !          2634:        int addr_code = dstea->address_reg == -2 ? 5 : dstea->address_reg + 0x80;
        !          2635:        /* We have an address in memory */
        !          2636:        if (dstea->data_reg != -1)
        !          2637:            printf("Things don't look good in handle_bit_insns\n");
        !          2638:        if (srcreg == -2) {
        !          2639:            assemble(0x0F); assemble(0xBA); 
        !          2640:            assemble(addr_code + 8*(4 + code));
        !          2641:            assemble_long(address_space + dstea->addr_const_off);
        !          2642:            assemble(srcoffs);
        !          2643:        } else {
        !          2644:            assemble(0x0F); assemble(0xA3 + 8*code);
        !          2645:            assemble(addr_code + srcreg*8);
        !          2646:            assemble_long(address_space + dstea->addr_const_off);
        !          2647:        }
        !          2648:        
        !          2649:     }
        !          2650:     cc_status = CC_Z_FROM_86C;
        !          2651: }
        !          2652: 
        !          2653: static int do_rotshi = 1;
        !          2654: 
        !          2655: static void handle_rotshi(struct register_mapping *map, int iip, 
        !          2656:                          UBYTE *realpc, CPTR current_addr)
        !          2657: {
        !          2658:     struct pid_undo pub;
        !          2659:     struct ea_info eai;
        !          2660:     int amode_reg = insn_info[iip].dp->sreg;
        !          2661:     int amode_mode = insn_info[iip].dp->smode;
        !          2662:     wordsizes size = insn_info[iip].dp->size;
        !          2663:     int shiftcount;
        !          2664:     int mnemo = insn_info[iip].dp->mnemo;
        !          2665:     int shiftcode;
        !          2666: 
        !          2667:     int srcreg, srcreg2;
        !          2668:     ULONG srcoffs;
        !          2669:     
        !          2670:     switch(mnemo) {
        !          2671:      case i_ASLW: shiftcount = 1; mnemo = i_ASL; break;
        !          2672:      case i_ASRW: shiftcount = 1; mnemo = i_ASR; break;
        !          2673:      case i_LSLW: shiftcount = 1; mnemo = i_LSL; break;
        !          2674:      case i_LSRW: shiftcount = 1; mnemo = i_LSR; break;
        !          2675:      case i_ROLW: shiftcount = 1; mnemo = i_ROL; break;
        !          2676:      case i_RORW: shiftcount = 1; mnemo = i_ROR; break;
        !          2677:      case i_ROXLW:shiftcount = 1; mnemo = i_ROXL;break;
        !          2678:      case i_ROXRW:shiftcount = 1; mnemo = i_ROXR;break;
        !          2679:      default:
        !          2680:        if (insn_info[iip].dp->smode != immi) {
        !          2681:            generate_exit(map, insn_info[iip].address);
        !          2682:            return;
        !          2683:        }
        !          2684:        amode_reg = insn_info[iip].dp->dreg;
        !          2685:        amode_mode = insn_info[iip].dp->dmode;
        !          2686:        shiftcount = insn_info[iip].dp->sreg;
        !          2687:        break;
        !          2688:     }
        !          2689:     if ((mnemo == i_LSL || mnemo == i_LSR || mnemo == i_ASR || mnemo == i_ASL)
        !          2690:        && (insn_info[iip].flags_live_at_end & CC68K_V) != 0) {
        !          2691:        generate_exit(map, insn_info[iip].address);
        !          2692:        return;
        !          2693:     }
        !          2694:     if (mnemo == i_ROR || mnemo == i_ROL || mnemo == i_ROXR || mnemo == i_ROXL) {
        !          2695:        if ((insn_info[iip].flags_live_at_end & CC68K_V) != 0) {
        !          2696:            generate_exit(map, insn_info[iip].address);
        !          2697:            return;
        !          2698:        }
        !          2699:     }
        !          2700:     if (mnemo == i_ROXR || mnemo == i_ROXL) {
        !          2701:        remove_x86r_from_cache(map, r_EAX, 1);
        !          2702:        map->x86_locked[r_EAX]++;
        !          2703:        compile_move_reg_from_mem_regoffs(r_AH, -2, 2 + (ULONG)&regflags,
        !          2704:                                          sz_byte);
        !          2705:     }
        !          2706:     compile_prepareea(map, amode_mode, amode_reg, size,
        !          2707:                      &realpc, current_addr,
        !          2708:                      &eai, EA_LOAD|EA_STORE, &pub, 1);
        !          2709:     
        !          2710:     generate_possible_exit(map, &eai, iip, &pub);
        !          2711:     
        !          2712:     srcreg = compile_fetchea(map, &eai, &srcoffs);
        !          2713:     srcreg2 = compile_move_const_reg(map, srcreg, &srcoffs, insn_info[iip].dp->size == sz_byte ? DATA_X86_REGS : 0);
        !          2714:     compile_unlock_reg(map, srcreg);
        !          2715: 
        !          2716:     compile_force_byteorder(map, srcreg2, BO_NORMAL, 0);
        !          2717: 
        !          2718:     switch (mnemo) {
        !          2719:      case i_ASL:
        !          2720:        shiftcode = 4; cc_status = CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V | CC_X_FROM_86C;
        !          2721:        break;
        !          2722:      case i_LSL:
        !          2723:        shiftcode = 4; cc_status = CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V | CC_X_FROM_86C;
        !          2724:        break;  
        !          2725:      case i_LSR:
        !          2726:        shiftcode = 5; cc_status = CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V | CC_X_FROM_86C;
        !          2727:        break;
        !          2728:      case i_ASR:
        !          2729:        shiftcode = 7; cc_status = CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V | CC_X_FROM_86C;
        !          2730:        break;
        !          2731:      case i_ROR:
        !          2732:        shiftcode = 1; cc_status = CC_AFTER_RO;
        !          2733:        break;
        !          2734:      case i_ROL:
        !          2735:        shiftcode = 0; cc_status = CC_AFTER_RO;
        !          2736:        break;
        !          2737:      case i_ROXL:
        !          2738:        shiftcode = 2; assemble(0x9E); /* SAHF */ cc_status = CC_AFTER_ROX;
        !          2739:        break;
        !          2740:      case i_ROXR:
        !          2741:        shiftcode = 3; assemble(0x9E); /* SAHF */ cc_status = CC_AFTER_ROX;
        !          2742:        break;
        !          2743:     }
        !          2744: 
        !          2745:     if (size == sz_word)
        !          2746:        assemble(0x66);
        !          2747:     assemble((shiftcount == 1 ? 0xD0 : 0xC0) + (size == sz_byte ? 0 : 1));
        !          2748:     assemble(shiftcode*8+0xC0 + srcreg);
        !          2749:     if (shiftcount != 1) assemble(shiftcount);
        !          2750:     cc_offset = 0; cc_size = size; cc_reg = srcreg;
        !          2751:     
        !          2752:     compile_storeea(map, &eai, srcreg, 0);
        !          2753: }
        !          2754: 
        !          2755: static ULONG testmask = 0xF80000, testval = 0xF80000;
        !          2756: 
        !          2757: static int m68k_compile_block(struct hash_block *hb)
        !          2758: {
        !          2759:     int movem_extra = 0;
        !          2760:     int last_iip = m68k_scan_block(hb, &movem_extra);
        !          2761:     struct register_mapping map;
        !          2762:     int i, iip, szflag;
        !          2763:     UBYTE *realpc_start = NULL;
        !          2764:     struct bb_info *current_bb;
        !          2765:     int cc_status_for_bcc = CC_SAHF;
        !          2766:     
        !          2767:     cesp = 0;
        !          2768: 
        !          2769:     if (n_compiled > n_max_comp)
        !          2770:        return 1;
        !          2771:     else if (n_compiled++ == n_max_comp)
        !          2772:        printf("X\n");
        !          2773: 
        !          2774:     cc_status = 0; compile_failure = 0;
        !          2775: 
        !          2776:     /* Kickstart ROM address? */
        !          2777:     if ((hb->he_first->addr & 0xF80000) != 0xF80000
        !          2778:        && 0 && !patched_syscalls)
        !          2779:        return 1;
        !          2780: 
        !          2781:     if (alloc_code (hb, last_iip + movem_extra) == NULL) {
        !          2782:        hb->allocfailed = 1;
        !          2783:        return 0;
        !          2784:     }
        !          2785:     compile_org(hb->compile_start);
        !          2786:     compile_last_addr = (char *)hb->compile_start + hb->alloclen;
        !          2787:     
        !          2788:     /* m68k_scan_block() will leave this all set up */
        !          2789:     current_bb = bb_stack;
        !          2790:     
        !          2791:     for (i = 0; i < 8; i++) {
        !          2792:        map.dreg_map[i] = map.areg_map[i] = -1;
        !          2793:        map.x86_dirty[i] = 0;
        !          2794:        map.x86_cache_reg[i] = -1;
        !          2795:        map.x86_cr_type[i] = 0;
        !          2796:        map.x86_const_offset[i] = 0;
        !          2797:        map.x86_verified[i] = 0;
        !          2798:        map.x86_byteorder[i] = BO_NORMAL;
        !          2799:     }
        !          2800:     
        !          2801:     for (iip = 0; iip < last_iip && !compile_failure; iip++) {
        !          2802:        UBYTE *realpc;
        !          2803:        int srcreg, dstreg, srcreg2, dstreg2;
        !          2804:        ULONG srcoffs, dstoffs;
        !          2805:        struct ea_info eainfo[4];
        !          2806:        CPTR current_addr;
        !          2807:        struct pid_undo pub;
        !          2808:        
        !          2809:        /* Set up locks for a new insn. We don't bother to clear this
        !          2810:         * properly after compiling one insn. */
        !          2811:        for (i = 0; i < 8; i++)
        !          2812:            map.x86_locked[i] = i == r_ESP ? 1 : 0;
        !          2813: 
        !          2814:        pub.used = 0;
        !          2815:        current_addr = insn_info[iip].address + 2;
        !          2816: 
        !          2817:        if (iip == current_bb->first_iip) {
        !          2818:            sync_reg_cache(&map, 1);
        !          2819:            if (!quiet_compile)
        !          2820:                printf("Compiling %08lx\n", current_bb->h->addr);
        !          2821:            realpc_start = get_real_address(current_bb->h->addr);
        !          2822:            current_bb->h->execute = (code_execfunc)compile_here();
        !          2823:            current_bb->h->matchword = *(ULONG *)realpc_start;
        !          2824:            cc_status_for_bcc = CC_SAHF;
        !          2825:        }
        !          2826: 
        !          2827:        realpc = realpc_start + (current_addr - current_bb->h->addr);   
        !          2828: 
        !          2829:        insn_info[iip].compiled_jumpaddr = compile_here();          
        !          2830:        insn_info[iip].compiled_fillin = NULL;
        !          2831:        
        !          2832:        if (insn_info[iip].jump_target) {
        !          2833:            if (cesp == CE_STACK_SIZE) {
        !          2834:                generate_exit(NULL, insn_info[iip].address);
        !          2835:                compile_failure = 1;
        !          2836:            } else {
        !          2837:                assemble(0xFE); assemble(0x05 + 8*1); assemble_long(&nr_bbs_to_run);
        !          2838:                assemble(0x0F); assemble(0x84); /* JE finish */
        !          2839:                compile_exit_stack[cesp].noflush = 1;
        !          2840:                compile_exit_stack[cesp].address = current_bb->h;
        !          2841:                compile_exit_stack[cesp].jmpoffs = compile_here();
        !          2842:                assemble_ulong(0);
        !          2843:                cesp++;
        !          2844:            }
        !          2845:        }
        !          2846:        /*
        !          2847:         * This will sort out all insns we can't compile, including
        !          2848:         * conditional branches and jumps out of this block */
        !          2849:        if (insn_info[iip].stop_translation == 1) {
        !          2850:            generate_exit(&map, insn_info[iip].address);
        !          2851:            cc_status = 0;
        !          2852:        } else switch (insn_info[iip].dp->mnemo) {
        !          2853:         case i_Bcc:
        !          2854:            sync_reg_cache(&map, 0);
        !          2855:            compile_handle_bcc(&map, iip, cc_status_for_bcc);
        !          2856:            cc_status = 0;
        !          2857:            break;
        !          2858: 
        !          2859:         case i_DBcc:
        !          2860:            sync_reg_cache(&map, 0);
        !          2861:            remove_x86r_from_cache(&map, map.dreg_map[insn_info[iip].dp->sreg], 1);
        !          2862:            compile_handle_dbcc(&map, iip, cc_status_for_bcc,
        !          2863:                                insn_info[iip].dp->sreg);
        !          2864:            cc_status = 0;
        !          2865:            break;
        !          2866: #if 0
        !          2867:         case i_Scc:
        !          2868:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          2869:                              insn_info[iip].dp->sreg, 
        !          2870:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          2871:                              eainfo, EA_STORE, &pub, 1);
        !          2872: 
        !          2873:            generate_possible_exit(&map, eainfo, iip, &pub);
        !          2874:            srcreg2 = get_;
        !          2875:            compile_storeea(&map, eainfo + 0, -2, 0);
        !          2876: 
        !          2877:            cc_status = 0;
        !          2878:            break;
        !          2879: #endif
        !          2880:         case i_ADD:
        !          2881:         case i_SUB:
        !          2882:         case i_CMP:
        !          2883:         case i_CMPM:
        !          2884:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          2885:                              insn_info[iip].dp->sreg, 
        !          2886:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          2887:                              eainfo, EA_LOAD, &pub, 1);
        !          2888:            compile_prepareea(&map, insn_info[iip].dp->dmode,
        !          2889:                              insn_info[iip].dp->dreg, 
        !          2890:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          2891:                              eainfo + 1, EA_IN_REG | EA_LOAD | EA_STORE, 
        !          2892:                              &pub, 1);
        !          2893: 
        !          2894:            generate_possible_exit(&map, eainfo, iip, &pub);
        !          2895:            generate_possible_exit(&map, eainfo+1, iip, &pub);
        !          2896:            
        !          2897:            szflag = insn_info[iip].dp->size == sz_byte ? 0 : 1;
        !          2898:            srcreg = compile_fetchea(&map, eainfo + 0, &srcoffs);
        !          2899:            dstreg = compile_fetchea(&map, eainfo + 1, &dstoffs);
        !          2900:            
        !          2901:            srcreg2 = compile_move_const_reg(&map, srcreg, &srcoffs, insn_info[iip].dp->size == sz_byte ? DATA_X86_REGS : 0);
        !          2902:            compile_unlock_reg(&map, srcreg);
        !          2903:            compile_offset_reg(&map, dstreg, dstoffs);
        !          2904: 
        !          2905:            compile_force_byteorder(&map, srcreg2, BO_NORMAL, 0);
        !          2906:            compile_force_byteorder(&map, dstreg, BO_NORMAL, 0);
        !          2907: 
        !          2908:            if (insn_info[iip].dp->size == sz_word)
        !          2909:                assemble(0x66);
        !          2910:            switch (insn_info[iip].dp->mnemo) {
        !          2911:             case i_ADD: assemble(0x00+szflag); break;
        !          2912:             case i_SUB: assemble(0x28+szflag); break;
        !          2913:             case i_AND: assemble(0x20+szflag); break;
        !          2914:             case i_EOR: assemble(0x30+szflag); break;
        !          2915:             case i_CMP: case i_CMPM: assemble(0x38+szflag); break;
        !          2916:             case i_OR: assemble(0x08+szflag); break;
        !          2917:            }
        !          2918:            assemble(0xC0 + srcreg2*8 + dstreg);
        !          2919:            if ((insn_info[iip].dp->mnemo != i_CMP)
        !          2920:                && (insn_info[iip].dp->mnemo != i_CMPM))
        !          2921:                compile_storeea(&map, eainfo + 1, dstreg, 0);
        !          2922:            switch (insn_info[iip].dp->mnemo) {
        !          2923:             case i_ADD:
        !          2924:             case i_SUB:
        !          2925:                cc_status = CC_X_FROM_86C | CC_Z_FROM_86Z |CC_C_FROM_86C |CC_V_FROM_86V |CC_N_FROM_86N;
        !          2926:                break;
        !          2927:             case i_AND:
        !          2928:             case i_EOR:
        !          2929:             case i_OR:
        !          2930:             case i_CMP:
        !          2931:             case i_CMPM:
        !          2932:                cc_status = CC_Z_FROM_86Z |CC_C_FROM_86C |CC_V_FROM_86V |CC_N_FROM_86N;
        !          2933:                break;
        !          2934:            }
        !          2935:            break;
        !          2936: 
        !          2937:         case i_ADDX:
        !          2938:         case i_SUBX:
        !          2939:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          2940:                              insn_info[iip].dp->sreg, 
        !          2941:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          2942:                              eainfo, EA_LOAD, &pub, 1);
        !          2943:            compile_prepareea(&map, insn_info[iip].dp->dmode,
        !          2944:                              insn_info[iip].dp->dreg, 
        !          2945:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          2946:                              eainfo + 1, EA_IN_REG | EA_LOAD | EA_STORE, 
        !          2947:                              &pub, 1);
        !          2948: 
        !          2949:            generate_possible_exit(&map, eainfo, iip, &pub);
        !          2950:            generate_possible_exit(&map, eainfo+1, iip, &pub);
        !          2951:            
        !          2952:            szflag = insn_info[iip].dp->size == sz_byte ? 0 : 1;
        !          2953:            srcreg = compile_fetchea(&map, eainfo + 0, &srcoffs);
        !          2954:            dstreg = compile_fetchea(&map, eainfo + 1, &dstoffs);
        !          2955:            
        !          2956:            srcreg2 = compile_move_const_reg(&map, srcreg, &srcoffs, insn_info[iip].dp->size == sz_byte ? DATA_X86_REGS : 0);
        !          2957:            compile_unlock_reg(&map, srcreg);
        !          2958:            compile_offset_reg(&map, dstreg, dstoffs);
        !          2959: 
        !          2960:            compile_force_byteorder(&map, srcreg2, BO_NORMAL, 0);
        !          2961:            compile_force_byteorder(&map, dstreg, BO_NORMAL, 0);
        !          2962: 
        !          2963:            /* bt $16, regflags ; get carry */
        !          2964:            assemble(0x0F); assemble(0xBA); assemble(0x5+4*8); 
        !          2965:            assemble_long(&regflags); assemble(0x10);
        !          2966:            if (insn_info[iip].dp->size == sz_word)
        !          2967:                assemble(0x66);
        !          2968:            switch (insn_info[iip].dp->mnemo) {
        !          2969:             case i_ADDX: assemble(0x10+szflag); break;
        !          2970:             case i_SUBX: assemble(0x18+szflag); break;
        !          2971:            }
        !          2972:            assemble(0xC0 + srcreg2*8 + dstreg);
        !          2973:            compile_storeea(&map, eainfo + 1, dstreg, 0);
        !          2974:            if (insn_info[iip].flags_live_at_end & CC68K_Z) {
        !          2975:                /* Darn. */
        !          2976:                int tmpr = get_free_x86_register(&map, ALL_X86_REGS);
        !          2977:                /* pushfl; popl tmpr */
        !          2978:                assemble(0x9C); assemble(0x58+tmpr);
        !          2979:                /* Magic! */
        !          2980:                /* andl tmpr, regflags; andl $~0x40,tmpr; orl tmpr, regflags */
        !          2981:                assemble(0x21); assemble(0x05 + 8*tmpr); assemble_long(&regflags);
        !          2982:                assemble(0x81); assemble(0xC0 + 8*4 + tmpr); assemble_ulong(~0x40);
        !          2983:                assemble(0x09); assemble(0x05 + 8*tmpr); assemble_long(&regflags);
        !          2984:                compile_move_reg_to_mem_regoffs(-2, 2 + (ULONG)&regflags, tmpr, sz_word);
        !          2985:                cc_status = 0;
        !          2986:            } else {
        !          2987:                /* Lies! */
        !          2988:                cc_status = CC_X_FROM_86C | CC_Z_FROM_86Z |CC_C_FROM_86C |CC_V_FROM_86V |CC_N_FROM_86N;
        !          2989:            }
        !          2990:            break;
        !          2991: 
        !          2992:         case i_MULU:
        !          2993:         case i_MULS:
        !          2994:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          2995:                              insn_info[iip].dp->sreg, 
        !          2996:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          2997:                              eainfo, EA_LOAD, &pub, 1);
        !          2998:            compile_prepareea(&map, insn_info[iip].dp->dmode,
        !          2999:                              insn_info[iip].dp->dreg, 
        !          3000:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          3001:                              eainfo + 1, EA_IN_REG | EA_LOAD | EA_STORE, 
        !          3002:                              &pub, 1);
        !          3003: 
        !          3004:            generate_possible_exit(&map, eainfo, iip, &pub);
        !          3005:            generate_possible_exit(&map, eainfo+1, iip, &pub);
        !          3006:            
        !          3007:            srcreg = compile_fetchea(&map, eainfo + 0, &srcoffs);
        !          3008:            dstreg = compile_fetchea(&map, eainfo + 1, &dstoffs);
        !          3009:            
        !          3010:            srcreg2 = compile_move_const_reg(&map, srcreg, &srcoffs, insn_info[iip].dp->size == sz_byte ? DATA_X86_REGS : 0);
        !          3011:            compile_unlock_reg(&map, srcreg);
        !          3012:            compile_offset_reg(&map, dstreg, dstoffs);
        !          3013: 
        !          3014:            compile_force_byteorder(&map, srcreg2, BO_NORMAL, 0);
        !          3015:            compile_force_byteorder(&map, dstreg, BO_NORMAL, 0);
        !          3016: 
        !          3017:            /* Extend the regs properly */
        !          3018:            remove_x86r_from_cache(&map, srcreg2, 0);
        !          3019:            switch (insn_info[iip].dp->mnemo) {
        !          3020:             case i_MULU:
        !          3021:                assemble(0x81); assemble(0xC0+4*8+srcreg2); assemble_ulong(0xFFFF);
        !          3022:                assemble(0x81); assemble(0xC0+4*8+dstreg); assemble_ulong(0xFFFF);
        !          3023:                break;
        !          3024:             case i_MULS:
        !          3025:                assemble(0x0F); assemble(0xBF); assemble(0xC0 + 9*srcreg2);
        !          3026:                assemble(0x0F); assemble(0xBF); assemble(0xC0 + 9*dstreg);
        !          3027:                break;
        !          3028:            }
        !          3029:            /* and multiply */
        !          3030:            assemble(0x0F); assemble(0xAF); assemble(0xC0 + 8*dstreg + srcreg2);
        !          3031:            compile_storeea(&map, eainfo + 1, dstreg, 0);
        !          3032:            cc_status = CC_TEST_REG;
        !          3033:            cc_reg = dstreg;
        !          3034:            cc_offset = 0;
        !          3035:            cc_size = sz_long;
        !          3036:            break;
        !          3037: 
        !          3038:         case i_ADDA:
        !          3039:         case i_SUBA:
        !          3040:         case i_CMPA:
        !          3041:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          3042:                              insn_info[iip].dp->sreg, 
        !          3043:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          3044:                              eainfo, EA_LOAD, &pub, 1);
        !          3045:            compile_prepareea(&map, insn_info[iip].dp->dmode,
        !          3046:                              insn_info[iip].dp->dreg, 
        !          3047:                              sz_long, &realpc, current_addr,
        !          3048:                              eainfo + 1, EA_IN_REG | EA_LOAD | EA_STORE, 
        !          3049:                              &pub, 1);
        !          3050: 
        !          3051:            generate_possible_exit(&map, eainfo, iip, &pub);
        !          3052: 
        !          3053:            srcreg2 = compile_fetchea(&map, eainfo + 0, &srcoffs);
        !          3054:            dstreg = compile_fetchea(&map, eainfo + 1, &dstoffs);
        !          3055:            srcreg = compile_move_const_reg(&map, srcreg2, &srcoffs, 0);
        !          3056:            compile_unlock_reg(&map, srcreg2);
        !          3057:            srcreg2 = compile_extend_long(&map, srcreg, &srcoffs, eainfo[0].size);
        !          3058:            compile_unlock_reg(&map, srcreg);
        !          3059:            compile_offset_reg(&map, dstreg, dstoffs);
        !          3060: 
        !          3061:            compile_force_byteorder(&map, srcreg2, BO_NORMAL, 0);
        !          3062:            compile_force_byteorder(&map, dstreg, BO_NORMAL, 0);
        !          3063: 
        !          3064:            switch (insn_info[iip].dp->mnemo) {
        !          3065:             case i_ADDA: assemble(0x01); break;
        !          3066:             case i_SUBA: assemble(0x29); break;
        !          3067:             case i_CMPA: assemble(0x39); break;
        !          3068:            }
        !          3069:            assemble(0xC0 + srcreg2*8 + dstreg);
        !          3070: 
        !          3071:            if (insn_info[iip].dp->mnemo == i_CMPA) {
        !          3072:                cc_status = CC_Z_FROM_86Z |CC_C_FROM_86C |CC_V_FROM_86V |CC_N_FROM_86N;
        !          3073:            } else {
        !          3074:                compile_storeea(&map, eainfo + 1, dstreg, 0);
        !          3075:                cc_status = 0;
        !          3076:            }
        !          3077:            break;
        !          3078: 
        !          3079:         case i_MOVE:
        !          3080:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          3081:                              insn_info[iip].dp->sreg, 
        !          3082:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          3083:                              eainfo, EA_LOAD, &pub, 1);
        !          3084:            compile_prepareea(&map, insn_info[iip].dp->dmode,
        !          3085:                              insn_info[iip].dp->dreg, 
        !          3086:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          3087:                              eainfo + 1, EA_STORE, &pub, 1);
        !          3088: 
        !          3089:            generate_possible_exit(&map, eainfo, iip, &pub);
        !          3090:            generate_possible_exit(&map, eainfo + 1, iip, &pub);
        !          3091:            
        !          3092:            srcreg = compile_fetchea(&map, eainfo + 0, &srcoffs);
        !          3093:            compile_storeea(&map, eainfo + 1, srcreg, srcoffs);
        !          3094:            cc_status = CC_TEST_REG;
        !          3095:            cc_reg = srcreg;
        !          3096:            cc_offset = srcoffs;
        !          3097:            cc_size = eainfo[0].size;
        !          3098:            
        !          3099:            break;
        !          3100: 
        !          3101:         case i_MOVEA:
        !          3102:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          3103:                              insn_info[iip].dp->sreg, 
        !          3104:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          3105:                              eainfo, EA_LOAD, &pub, 1);
        !          3106:            compile_prepareea(&map, insn_info[iip].dp->dmode,
        !          3107:                              insn_info[iip].dp->dreg,
        !          3108:                              sz_long, &realpc, current_addr,
        !          3109:                              eainfo + 1, EA_STORE, &pub, 1);
        !          3110: 
        !          3111:            generate_possible_exit(&map, eainfo, iip, &pub);
        !          3112:            
        !          3113:            srcreg = compile_fetchea(&map, eainfo, &srcoffs);
        !          3114:            srcreg2 = compile_extend_long(&map, srcreg, &srcoffs, eainfo[0].size);
        !          3115:            compile_unlock_reg(&map, srcreg);
        !          3116:            compile_storeea(&map, eainfo + 1, srcreg2, srcoffs);
        !          3117: 
        !          3118:            cc_status = 0;
        !          3119:            break;
        !          3120: 
        !          3121:         case i_EXG:
        !          3122:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          3123:                              insn_info[iip].dp->sreg,
        !          3124:                              sz_long, &realpc, current_addr,
        !          3125:                              eainfo, EA_LOAD|EA_STORE, &pub, 1);
        !          3126:            compile_prepareea(&map, insn_info[iip].dp->dmode,
        !          3127:                              insn_info[iip].dp->dreg,
        !          3128:                              sz_long, &realpc, current_addr,
        !          3129:                              eainfo + 1, EA_LOAD|EA_STORE, &pub, 1);
        !          3130: 
        !          3131:            srcreg = compile_fetchea(&map, eainfo, &srcoffs);
        !          3132:            dstreg = compile_fetchea(&map, eainfo+1, &dstoffs);
        !          3133:            compile_unlock_reg(&map, srcreg);
        !          3134:            compile_storeea(&map, eainfo + 1, srcreg, srcoffs);
        !          3135:            compile_storeea(&map, eainfo, dstreg, dstoffs);
        !          3136: 
        !          3137:            cc_status = 0;
        !          3138:            break;
        !          3139:            
        !          3140:         case i_LINK:
        !          3141:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          3142:                              insn_info[iip].dp->sreg, 
        !          3143:                              sz_long, &realpc, current_addr,
        !          3144:                              eainfo, EA_LOAD|EA_STORE, &pub, 1);
        !          3145:            compile_prepareea(&map, insn_info[iip].dp->dmode,
        !          3146:                              insn_info[iip].dp->dreg,
        !          3147:                              sz_long, &realpc, current_addr,
        !          3148:                              eainfo + 1, EA_LOAD, &pub, 1);
        !          3149:            compile_prepareea(&map, Apdi, 7, sz_long, &realpc, current_addr,
        !          3150:                              eainfo + 2, EA_STORE, &pub, 1);
        !          3151: 
        !          3152:            generate_possible_exit(&map, eainfo+2, iip, &pub);
        !          3153: 
        !          3154:            srcreg = compile_fetchea(&map, eainfo + 0, &srcoffs);
        !          3155:            dstreg = compile_fetchea(&map, eainfo + 1, &dstoffs);
        !          3156:            compile_storeea(&map, eainfo + 2, srcreg, srcoffs);
        !          3157: 
        !          3158:            compile_prepareea(&map, Areg, 7, sz_long, &realpc, current_addr,
        !          3159:                              eainfo + 3, EA_STORE, &pub, 1);
        !          3160:            srcreg = compile_fetchea(&map, eainfo + 3, &srcoffs);
        !          3161:            compile_storeea(&map, eainfo + 0, srcreg, srcoffs);
        !          3162:            /* @@@ 020 */
        !          3163:            compile_storeea(&map, eainfo + 3, srcreg, srcoffs+(WORD)dstoffs); 
        !          3164:            cc_status = 0;
        !          3165:            break;
        !          3166:                    
        !          3167:         case i_UNLK:
        !          3168:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          3169:                              insn_info[iip].dp->sreg, 
        !          3170:                              sz_long, &realpc, current_addr,
        !          3171:                              eainfo, EA_LOAD|EA_STORE, &pub, 1);
        !          3172:            compile_prepareea(&map, Aind,
        !          3173:                              insn_info[iip].dp->sreg, 
        !          3174:                              sz_long, &realpc, current_addr,
        !          3175:                              eainfo + 1, EA_LOAD, &pub, 1);
        !          3176: 
        !          3177:            generate_possible_exit(&map, eainfo+1, iip, &pub);
        !          3178: 
        !          3179:            compile_prepareea(&map, Areg, 7, sz_long, &realpc, current_addr,
        !          3180:                              eainfo + 3, EA_STORE, &pub, 1);
        !          3181:            srcreg = compile_fetchea(&map, eainfo + 1, &srcoffs);
        !          3182:            dstreg = compile_fetchea(&map, eainfo + 0, &dstoffs);
        !          3183:            compile_storeea(&map, eainfo + 0, srcreg, srcoffs);
        !          3184:            compile_storeea(&map, eainfo + 3, dstreg, dstoffs+4);
        !          3185:            cc_status = 0;          
        !          3186:            break;
        !          3187: 
        !          3188:         case i_OR:
        !          3189:         case i_AND:
        !          3190:         case i_EOR:
        !          3191:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          3192:                              insn_info[iip].dp->sreg, 
        !          3193:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          3194:                              eainfo, EA_LOAD, &pub, 1);
        !          3195:            compile_prepareea(&map, insn_info[iip].dp->dmode,
        !          3196:                              insn_info[iip].dp->dreg, 
        !          3197:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          3198:                              eainfo + 1, EA_IN_REG | EA_LOAD | EA_STORE, &pub, 1);
        !          3199: 
        !          3200:            generate_possible_exit(&map, eainfo, iip, &pub);
        !          3201:            generate_possible_exit(&map, eainfo + 1, iip, &pub);
        !          3202:            
        !          3203:            szflag = insn_info[iip].dp->size == sz_byte ? 0 : 1;
        !          3204:            srcreg = compile_fetchea(&map, eainfo + 0, &srcoffs);
        !          3205:            dstreg = compile_fetchea(&map, eainfo + 1, &dstoffs);
        !          3206:            
        !          3207:            srcreg2 = compile_move_const_reg(&map, srcreg, &srcoffs, insn_info[iip].dp->size == sz_byte ? DATA_X86_REGS : 0);
        !          3208:            compile_unlock_reg(&map, srcreg);
        !          3209:            compile_offset_reg(&map, dstreg, dstoffs);
        !          3210: 
        !          3211:            compile_force_byteorder(&map, srcreg2, BO_NORMAL, 0);
        !          3212:            compile_force_byteorder(&map, dstreg, BO_NORMAL, 0);
        !          3213: 
        !          3214:            if (insn_info[iip].dp->size == sz_word)
        !          3215:                assemble(0x66);
        !          3216:            switch (insn_info[iip].dp->mnemo) {
        !          3217:             case i_AND: assemble(0x20+szflag); break;
        !          3218:             case i_EOR: assemble(0x30+szflag); break;
        !          3219:             case i_OR: assemble(0x08+szflag); break;
        !          3220:            }
        !          3221:            assemble(0xC0 + srcreg2*8 + dstreg);
        !          3222:            compile_storeea(&map, eainfo + 1, dstreg, 0);
        !          3223:            cc_status = CC_Z_FROM_86Z |CC_C_FROM_86C |CC_V_FROM_86V |CC_N_FROM_86N;
        !          3224:            break;
        !          3225:            
        !          3226:         case i_BTST:
        !          3227:         case i_BSET:
        !          3228:         case i_BCLR:
        !          3229:         case i_BCHG:
        !          3230:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          3231:                              insn_info[iip].dp->sreg, 
        !          3232:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          3233:                              eainfo, EA_LOAD, &pub, 1);
        !          3234:            compile_prepareea(&map, insn_info[iip].dp->dmode,
        !          3235:                              insn_info[iip].dp->dreg, 
        !          3236:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          3237:                              eainfo + 1, 0, &pub, 1);
        !          3238: 
        !          3239:            generate_possible_exit(&map, eainfo, iip, &pub);
        !          3240:            generate_possible_exit(&map, eainfo + 1, iip, &pub);
        !          3241: 
        !          3242:            handle_bit_insns(&map, eainfo, eainfo + 1, insn_info[iip].dp->mnemo);
        !          3243:            break;
        !          3244:            
        !          3245:         case i_TST:
        !          3246:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          3247:                              insn_info[iip].dp->sreg, 
        !          3248:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          3249:                              eainfo, EA_LOAD, &pub, 1);
        !          3250: 
        !          3251:            generate_possible_exit(&map, eainfo, iip, &pub);
        !          3252:            
        !          3253:            srcreg = compile_fetchea(&map, eainfo + 0, &srcoffs);
        !          3254:            cc_status = CC_TEST_REG;
        !          3255:            cc_reg = srcreg;
        !          3256:            cc_offset = srcoffs;
        !          3257:            cc_size = eainfo[0].size;
        !          3258:            break;
        !          3259:            
        !          3260:         case i_CLR:
        !          3261:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          3262:                              insn_info[iip].dp->sreg, 
        !          3263:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          3264:                              eainfo, EA_STORE, &pub, 1);
        !          3265: 
        !          3266:            generate_possible_exit(&map, eainfo, iip, &pub);
        !          3267:            
        !          3268:            compile_storeea(&map, eainfo + 0, -2, 0);
        !          3269: 
        !          3270:            cc_status = CC_TEST_REG;
        !          3271:            cc_reg = -2;
        !          3272:            cc_offset = 0;
        !          3273:            cc_size = eainfo[0].size;
        !          3274:            break;
        !          3275: 
        !          3276:         case i_EXT:
        !          3277:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          3278:                              insn_info[iip].dp->sreg, 
        !          3279:                              insn_info[iip].dp->size == sz_long ? sz_word : sz_byte,
        !          3280:                              &realpc, current_addr,
        !          3281:                              eainfo, EA_LOAD|EA_STORE, &pub, 1);
        !          3282:            /* No exits - this is always a Dreg; fetchea will get it in a reg
        !          3283:             * without offset */
        !          3284:            srcreg = compile_fetchea(&map, eainfo + 0, &srcoffs);
        !          3285: 
        !          3286:            compile_force_byteorder(&map, srcreg, BO_NORMAL, 0);
        !          3287: 
        !          3288:            if (insn_info[iip].dp->size == sz_word)
        !          3289:                assemble(0x66);
        !          3290:            assemble(0x0F);
        !          3291:            if (insn_info[iip].dp->size == sz_long)
        !          3292:                assemble(0xBF);
        !          3293:            else
        !          3294:                assemble(0xBE);
        !          3295:            
        !          3296:            assemble(0xC0 + 9*srcreg);
        !          3297:            map.x86_dirty[srcreg] = 1;
        !          3298: 
        !          3299:            cc_status = CC_TEST_REG;
        !          3300:            cc_reg = srcreg;
        !          3301:            cc_offset = srcoffs;
        !          3302:            cc_size = eainfo[0].size;       
        !          3303:            break;
        !          3304: 
        !          3305:         case i_NOT:
        !          3306:         case i_NEG:
        !          3307:            szflag = insn_info[iip].dp->size == sz_byte ? 0 : 1;
        !          3308: 
        !          3309:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          3310:                              insn_info[iip].dp->sreg, 
        !          3311:                              insn_info[iip].dp->size,
        !          3312:                              &realpc, current_addr,
        !          3313:                              eainfo, EA_LOAD|EA_STORE, &pub, 1);
        !          3314: 
        !          3315:            generate_possible_exit(&map, eainfo, iip, &pub);
        !          3316:            
        !          3317:            srcreg = compile_fetchea(&map, eainfo + 0, &srcoffs);           
        !          3318:            srcreg2 = compile_move_const_reg(&map, srcreg, &srcoffs, insn_info[iip].dp->size == sz_byte ? DATA_X86_REGS : 0);
        !          3319:            compile_unlock_reg(&map, srcreg);
        !          3320: 
        !          3321:            compile_force_byteorder(&map, srcreg2, BO_NORMAL, 0);
        !          3322: 
        !          3323:            if (insn_info[iip].dp->size == sz_word)
        !          3324:                assemble(0x66);
        !          3325:            assemble(0xF6 + szflag);
        !          3326:            
        !          3327:            assemble(0xC0 + srcreg2 + 8*(insn_info[iip].dp->mnemo == i_NOT ? 2 : 3));
        !          3328:            compile_storeea(&map, eainfo, srcreg, 0);
        !          3329: 
        !          3330:            cc_status = CC_TEST_REG;
        !          3331:            cc_reg = srcreg;
        !          3332:            cc_offset = 0;
        !          3333:            cc_size = eainfo[0].size;       
        !          3334:            break;
        !          3335: 
        !          3336:         case i_SWAP:
        !          3337:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          3338:                              insn_info[iip].dp->sreg, sz_long,
        !          3339:                              &realpc, current_addr,
        !          3340:                              eainfo, EA_LOAD|EA_STORE, &pub, 1);
        !          3341:            /* No exits - this is always a Dreg; fetchea will get it in a reg
        !          3342:             * without offset */
        !          3343:            srcreg = compile_fetchea(&map, eainfo + 0, &srcoffs);
        !          3344: 
        !          3345:            compile_force_byteorder(&map, srcreg, BO_NORMAL, 0);
        !          3346:            /* roll $16, srcreg */
        !          3347:            assemble(0xC1); assemble(0xC0 + srcreg); assemble(16);
        !          3348: 
        !          3349:            map.x86_dirty[srcreg] = 1;
        !          3350: 
        !          3351:            cc_status = CC_TEST_REG;
        !          3352:            cc_reg = srcreg;
        !          3353:            cc_offset = srcoffs;
        !          3354:            cc_size = eainfo[0].size;       
        !          3355:            break;
        !          3356:            
        !          3357:         case i_LEA:
        !          3358:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          3359:                              insn_info[iip].dp->sreg, 
        !          3360:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          3361:                              eainfo, 0, &pub, 1);
        !          3362:            compile_prepareea(&map, insn_info[iip].dp->dmode,
        !          3363:                              insn_info[iip].dp->dreg,
        !          3364:                              sz_long, &realpc, current_addr,
        !          3365:                              eainfo + 1, EA_STORE, &pub, 1);
        !          3366:            compile_storeea(&map, eainfo + 1, eainfo[0].address_reg, 
        !          3367:                            eainfo[0].addr_const_off);
        !          3368:            cc_status = 0;
        !          3369:            break;
        !          3370: 
        !          3371:         case i_PEA:
        !          3372:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          3373:                              insn_info[iip].dp->sreg, 
        !          3374:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          3375:                              eainfo, 0, &pub, 1);
        !          3376:            compile_prepareea(&map, Apdi, 7, sz_long, &realpc, current_addr,
        !          3377:                              eainfo + 1, EA_STORE, &pub, 1);
        !          3378: 
        !          3379:            generate_possible_exit(&map, eainfo+1, iip, &pub);
        !          3380: 
        !          3381:            compile_storeea(&map, eainfo + 1, eainfo[0].address_reg, 
        !          3382:                            eainfo[0].addr_const_off);
        !          3383:            cc_status = 0;
        !          3384:            break;
        !          3385: 
        !          3386:         case i_MVMEL:
        !          3387:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          3388:                              insn_info[iip].dp->sreg, 
        !          3389:                              sz_word, &realpc, current_addr,
        !          3390:                              eainfo, EA_LOAD, &pub, 1);
        !          3391:            sync_reg_cache(&map, 0);
        !          3392:            {
        !          3393:                /* Scratch 0 holds the registers while they are being moved
        !          3394:                 * from/to memory. Scratch 1 points at regs.d. Scratch 2
        !          3395:                 * points at the base addr in memory where to fetch data
        !          3396:                 * from
        !          3397:                 */
        !          3398:                int scratch0, scratch1, scratch2;
        !          3399:                UWORD mask = eainfo[0].data_const_off;
        !          3400:                int bits = count_bits(mask);
        !          3401:                int size = insn_info[iip].dp->size == sz_long ? 4 : 2;
        !          3402:                int i;
        !          3403:                UBYTE x86amode;
        !          3404:                ULONG current_offs = 0;
        !          3405:                
        !          3406:                /* !!! Note current_addr + 2 here! */
        !          3407:                compile_prepareea(&map, insn_info[iip].dp->dmode,
        !          3408:                                  insn_info[iip].dp->dreg,
        !          3409:                                  insn_info[iip].dp->size, &realpc, current_addr + 2,
        !          3410:                                  eainfo + 1, EA_LOAD, &pub, bits);
        !          3411:                
        !          3412:                generate_possible_exit(&map, eainfo + 1, iip, &pub);
        !          3413: 
        !          3414:                scratch0 = get_free_x86_register(&map, ADDRESS_X86_REGS);
        !          3415:                map.x86_locked[scratch0]++;
        !          3416:                scratch1 = get_free_x86_register(&map, ADDRESS_X86_REGS);
        !          3417:                map.x86_locked[scratch1]++;
        !          3418:                scratch2 = get_free_x86_register(&map, ADDRESS_X86_REGS);
        !          3419:                map.x86_locked[scratch2]++;
        !          3420:                compile_force_byteorder(&map, eainfo[1].address_reg, BO_NORMAL, 0);
        !          3421:                
        !          3422:                compile_lea_reg_with_offset(scratch1, -2, (ULONG)regs.d);
        !          3423:                compile_lea_reg_with_offset(scratch2, eainfo[1].address_reg,
        !          3424:                                            (ULONG)(address_space + eainfo[1].addr_const_off));
        !          3425: 
        !          3426:                for (i = 0; i < 16; i++) {
        !          3427:                    int r68k = i & 7;
        !          3428:                    ULONG *regp = i < 8 ? regs.d : regs.a;
        !          3429:                    int *cache68k = i < 8 ? map.dreg_map : map.areg_map;
        !          3430:                    if (mask & 1 
        !          3431:                        && (i < 8 
        !          3432:                            || insn_info[iip].dp->dmode != Aipi
        !          3433:                            || r68k != insn_info[iip].dp->dreg)) {
        !          3434:                        int tmpr = cache68k[r68k];
        !          3435:                        
        !          3436:                        if (tmpr != -1) {
        !          3437:                            cache68k[r68k] = -1;
        !          3438:                            map.x86_cache_reg[tmpr] = -1;
        !          3439:                        }
        !          3440:                        compile_move_reg_from_mem_regoffs(scratch0, scratch2,
        !          3441:                                                          current_offs, insn_info[iip].dp->size);
        !          3442:                        if (size == 2) {
        !          3443:                            assemble(0x66); /* rolw $8,scratch0 */
        !          3444:                            assemble(0xC1);
        !          3445:                            assemble(0xC0 + scratch0);
        !          3446:                            assemble(8);
        !          3447:                            assemble(0x0F); assemble(0xBF); /* extend */
        !          3448:                            assemble(0xC0 + 9*scratch0);
        !          3449:                        } else {
        !          3450:                            assemble(0x0F); /* bswapl scratch0 */
        !          3451:                            assemble(0xC8 + scratch0);
        !          3452:                        }
        !          3453:                        compile_move_reg_to_mem_regoffs(scratch1, (char *)(regp + r68k) - (char *)regs.d,
        !          3454:                                                        scratch0, sz_long);
        !          3455:                    }
        !          3456:                    if (mask & 1)
        !          3457:                        current_offs += size;
        !          3458:                    mask >>= 1;
        !          3459:                }
        !          3460:            }
        !          3461:            cc_status = 0;
        !          3462:            break;
        !          3463: 
        !          3464:         case i_MVMLE:
        !          3465:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          3466:                              insn_info[iip].dp->sreg, 
        !          3467:                              sz_word, &realpc, current_addr,
        !          3468:                              eainfo, EA_LOAD, &pub, 1);
        !          3469:            sync_reg_cache(&map, 0);
        !          3470:            {
        !          3471:                int scratch0,scratch1,scratch2;
        !          3472:                UWORD mask = eainfo[0].data_const_off;
        !          3473:                int bits = count_bits(mask);
        !          3474:                int size = insn_info[iip].dp->size == sz_long ? 4 : 2;
        !          3475:                int i;
        !          3476:                UBYTE x86amode;
        !          3477:                ULONG current_offs = 0;
        !          3478:                int addrareg = get_and_lock_68k_reg(&map, insn_info[iip].dp->dreg, 
        !          3479:                                                    0, 0, 1);
        !          3480:                compile_force_byteorder(&map, addrareg, BO_NORMAL, 0);
        !          3481:                if (insn_info[iip].dp->dmode == Apdi)
        !          3482:                    mask = bitswap(mask);
        !          3483:                /* !!! Note current_addr + 2 here! */
        !          3484:                compile_prepareea(&map, insn_info[iip].dp->dmode,
        !          3485:                                  insn_info[iip].dp->dreg,
        !          3486:                                  insn_info[iip].dp->size, &realpc, current_addr + 2,
        !          3487:                                  eainfo + 1, EA_STORE, &pub, bits);
        !          3488:                
        !          3489:                generate_possible_exit(&map, eainfo + 1, iip, &pub);
        !          3490: 
        !          3491:                scratch0 = get_free_x86_register(&map, ADDRESS_X86_REGS);
        !          3492:                map.x86_locked[scratch0]++;
        !          3493:                scratch1 = get_free_x86_register(&map, ADDRESS_X86_REGS);
        !          3494:                map.x86_locked[scratch1]++;
        !          3495:                scratch2 = get_free_x86_register(&map, ADDRESS_X86_REGS);
        !          3496:                map.x86_locked[scratch2]++;
        !          3497: 
        !          3498:                compile_force_byteorder(&map, eainfo[1].address_reg, BO_NORMAL, 0);
        !          3499: 
        !          3500:                compile_lea_reg_with_offset(scratch1, -2, (ULONG)regs.d);
        !          3501:                compile_lea_reg_with_offset(scratch2, eainfo[1].address_reg,
        !          3502:                                            (ULONG)(address_space + eainfo[1].addr_const_off));
        !          3503: 
        !          3504:                for (i = 0; i < 16; i++) {
        !          3505:                    int r68k = i & 7;
        !          3506:                    ULONG *regp = i < 8 ? regs.d : regs.a;
        !          3507:                    int *cache68k = i < 8 ? map.dreg_map : map.areg_map;
        !          3508:                    if (mask & 1) {
        !          3509:                        /* move from 68k reg */
        !          3510:                        if (i < 8 || r68k != insn_info[iip].dp->dreg) {
        !          3511:                            compile_move_reg_from_mem_regoffs(scratch0, scratch1, (char *)(regp + r68k) - (char *)regs.d,
        !          3512:                                                              sz_long);
        !          3513:                        } else {
        !          3514:                            assemble(0x8B); assemble(0xC0 + 8*scratch0 + addrareg);
        !          3515:                        }
        !          3516: 
        !          3517:                        if (size == 2) {
        !          3518:                            assemble(0x66); /* rolw $8,scratch0 */
        !          3519:                            assemble(0xC1);
        !          3520:                            assemble(0xC0 + scratch0); assemble(8);
        !          3521:                        } else {
        !          3522:                            assemble(0x0F); /* bswapl scratch0 */
        !          3523:                            assemble(0xC8 + scratch0);
        !          3524:                        }
        !          3525:                        compile_move_reg_to_mem_regoffs(scratch2, current_offs,
        !          3526:                                                        scratch0, insn_info[iip].dp->size);
        !          3527:                    }
        !          3528:                    if (mask & 1)
        !          3529:                        current_offs += size;
        !          3530:                    mask >>= 1;
        !          3531:                }
        !          3532:            }
        !          3533:            cc_status = 0;
        !          3534:            break;
        !          3535: 
        !          3536:         case i_ASL: case i_ASR: case i_LSL: case i_LSR: 
        !          3537:         case i_ROL: case i_ROR: case i_ROXL:case i_ROXR:
        !          3538:         case i_ASLW: case i_ASRW: case i_LSLW: case i_LSRW: 
        !          3539:         case i_ROLW: case i_RORW: case i_ROXLW:case i_ROXRW:
        !          3540:            if (do_rotshi) {
        !          3541:                handle_rotshi(&map, iip, realpc, current_addr);
        !          3542:                break;
        !          3543:            }
        !          3544: 
        !          3545:         default:
        !          3546:            generate_exit(&map, insn_info[iip].address); cc_status = 0;
        !          3547:            break;
        !          3548:        }
        !          3549:        if (insn_info[iip].ccuser_follows)
        !          3550:            cc_status_for_bcc = compile_flush_cc_cache(&map, cc_status, 
        !          3551:                                   insn_info[iip].flags_live_at_end,
        !          3552:                                   1, insn_info[iip+1].flags_live_at_end,
        !          3553:                                   insn_info[iip+1].dp->cc);
        !          3554:        else
        !          3555:            cc_status_for_bcc = compile_flush_cc_cache(&map, cc_status, 
        !          3556:                                   insn_info[iip].flags_live_at_end,
        !          3557:                                   0, 0, 0);
        !          3558: 
        !          3559:        if (iip == current_bb->last_iip) {
        !          3560:            current_bb++;
        !          3561:        }
        !          3562:     }
        !          3563:     if (compile_failure)
        !          3564:        goto oops;
        !          3565: 
        !          3566:     /* Compile all exits that we prepared earlier */
        !          3567:     finish_exits();
        !          3568:     if (compile_failure)
        !          3569:        goto oops;
        !          3570:     finish_condjumps(last_iip);
        !          3571:     {
        !          3572:        int needed_len = compile_here() - hb->compile_start;
        !          3573:        int allocsize = (needed_len + PAGE_SUBUNIT - 1) & ~(PAGE_SUBUNIT-1);
        !          3574:        ULONG allocmask;
        !          3575:        int allocbits;
        !          3576:        
        !          3577:        allocbits = (allocsize >> SUBUNIT_ORDER);
        !          3578:        allocmask = (1 << allocbits) - 1;
        !          3579:        while ((allocmask & hb->page_allocmask) != allocmask)
        !          3580:            allocmask <<= 1;
        !          3581:        if ((hb->page_allocmask & ~allocmask) != 0 && !quiet_compile)
        !          3582:            fprintf(stderr, "Gaining some bits: %08lx\n", hb->page_allocmask & ~allocmask);
        !          3583:        hb->cpage->allocmask &= ~hb->page_allocmask;
        !          3584:        hb->page_allocmask = allocmask;
        !          3585:        hb->cpage->allocmask |= allocmask;
        !          3586:     }
        !          3587:     return 0;
        !          3588:     
        !          3589:     oops:
        !          3590:     if (1 || !quiet_compile)
        !          3591:        fprintf(stderr, "Compile failed!\n");
        !          3592:     hb->cpage->allocmask &= ~hb->page_allocmask;
        !          3593:     hb->cpage = NULL;
        !          3594:     hb->untranslatable = 1;
        !          3595:     {
        !          3596:        struct hash_entry *h = hb->he_first;
        !          3597:        
        !          3598:        do {
        !          3599:            h->execute = NULL;
        !          3600:            h = h->next_same_block;
        !          3601:        } while (h != hb->he_first);
        !          3602:     }
        !          3603:     return 1;
        !          3604: }
        !          3605: 
        !          3606: /*
        !          3607:  * Why do compilers always have to be so complicated? And I thought GCC was
        !          3608:  * a mess...
        !          3609:  */
        !          3610: 
        !          3611: #endif /* USE_COMPILER */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.