Annotation of hatari/src/uae-cpu/compiler.c, revision 1.1

1.1     ! root        1:  /*
        !             2:   * UAE - The Un*x Amiga Emulator
        !             3:   *
        !             4:   * m68k emulation
        !             5:   *
        !             6:   * Copyright 1996 Bernd Schmidt
        !             7:   */
        !             8: 
        !             9: #include <sys/types.h>
        !            10: #include <sys/stat.h>
        !            11: #include <fcntl.h>
        !            12: 
        !            13: #include "sysdeps.h"
        !            14: #include "hatari-glue.h"
        !            15: #include "memory.h"
        !            16: #include "newcpu.h"
        !            17: #include "compiler.h"
        !            18: /*
        !            19: #include "sysconfig.h"
        !            20: #include "config.h"
        !            21: #include "options.h"
        !            22: #include "events.h"
        !            23: #include "gui.h"
        !            24: #include "custom.h"
        !            25: #include "ersatz.h"
        !            26: #include "blitter.h"
        !            27: #include "debug.h"
        !            28: #include "autoconf.h"
        !            29: */
        !            30: 
        !            31: #ifdef USE_COMPILER
        !            32: 
        !            33: #include <sys/mman.h>
        !            34: 
        !            35: char *address_space, *good_address_map;
        !            36: 
        !            37: code_execfunc exec_me;
        !            38: uae_u8 nr_bbs_to_run = 1;
        !            39: int nr_bbs_start = 40;
        !            40: 
        !            41: static int compile_failure;
        !            42: static int quiet_compile = 1;
        !            43: int i_want_to_die = 1;
        !            44: static int n_compiled = 0;
        !            45: static int n_max_comp = 99999999;
        !            46: static uaecptr call_only_me = 0;
        !            47: 
        !            48: int patched_syscalls = 0;
        !            49: 
        !            50: static int count_bits(uae_u16 v)
        !            51: {
        !            52:     int bits = 0;
        !            53:     while (v != 0) {
        !            54:        if (v & 1)
        !            55:            bits++;
        !            56:        v >>= 1;
        !            57:     }
        !            58:     return bits;
        !            59: }
        !            60: 
        !            61: static uae_u16 bitswap(uae_u16 v)
        !            62: {
        !            63:     uae_u16 newv = 0;
        !            64:     uae_u16 m1 = 1, m2 = 0x8000;
        !            65:     int i;
        !            66: 
        !            67:     for (i = 0; i < 16; i++) {
        !            68:        if (v & m1)
        !            69:            newv |= m2;
        !            70:        m2 >>= 1;
        !            71:        m1 <<= 1;
        !            72:     }
        !            73:     return newv;
        !            74: }
        !            75: 
        !            76: static long long compiled_hits = 0;
        !            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 32768 /* larger values cause some paging on my 16MB machine */
        !           104: #define HASH_MASK (NUM_HASH-1)
        !           105: #define MAX_UNUSED_HASH 512
        !           106: 
        !           107: static int SCAN_MARK = 1; /* Number of calls after which to scan a function */
        !           108: static int COMPILE_MARK = 5; /* Number of calls after which to compile a function */
        !           109: 
        !           110: /* The main address -> function lookup hashtable. We use the lower bits of
        !           111:  * the address as hash function. */
        !           112: static struct hash_entry cpu_hash[NUM_HASH];
        !           113: /* These aren't really LRU lists... They used to be, but keeping them in that
        !           114:  * order is costly. The hash LRU list is now a two-part list: Functions that have
        !           115:  * no code allocated for them are placed at the beginning. Such entries can be
        !           116:  * recycled when we need a new hash entry. */
        !           117: static struct hash_block lru_first_block;
        !           118: static struct hash_entry lru_first_hash;
        !           119: static struct hash_entry *freelist_hash;
        !           120: static struct hash_block *freelist_block;
        !           121: static int num_unused_hash;
        !           122: 
        !           123: static int m68k_scan_func(struct hash_entry *);
        !           124: static int m68k_compile_block(struct hash_block *);
        !           125: 
        !           126: static char *alloc_code(struct hash_block *hb, int ninsns)
        !           127: {
        !           128:     struct code_page *cp;
        !           129:     long int allocsize = (ninsns * 32 + PAGE_SUBUNIT-1) & ~(PAGE_SUBUNIT-1);
        !           130:     uae_u32 allocmask;
        !           131:     int allocbits;
        !           132:     int j;
        !           133:     int last_bit;
        !           134: 
        !           135:     if (allocsize >= (PAGE_ALLOC_UNIT - (1 << SUBUNIT_ORDER)))
        !           136:        return NULL;
        !           137:     allocbits = (allocsize >> SUBUNIT_ORDER);
        !           138:     allocmask = (1 << allocbits) - 1;
        !           139: 
        !           140:     for (cp = first_code_page; cp != NULL; cp = cp->next) {
        !           141:        uae_u32 thispage_alloc = cp->allocmask;
        !           142:        for (j = 1; j < (33 - allocbits); j++) {
        !           143:            if ((cp->allocmask & (allocmask << j)) == 0) {
        !           144:                goto found_page;
        !           145:            }
        !           146:        }
        !           147:     }
        !           148: 
        !           149:     /* Nothing large enough free: make a new page */
        !           150:     cp = new_code_page();
        !           151:     if (cp == NULL)
        !           152:        return NULL;
        !           153:     j = 1;
        !           154: 
        !           155: found_page:
        !           156:     /* See whether there is in fact more space for us. If so, allocate all of
        !           157:      * it. compile_block() will free everything it didn't need. */
        !           158: 
        !           159:     allocmask <<= j;
        !           160:     last_bit = allocbits + j;
        !           161:     while (last_bit < 32 && (cp->allocmask & (1 << last_bit)) == 0) {
        !           162:        allocmask |= 1 << last_bit;
        !           163:        allocsize += PAGE_SUBUNIT;
        !           164:        last_bit++;
        !           165:     }
        !           166: 
        !           167:     hb->page_allocmask = allocmask;
        !           168:     hb->cpage = cp;
        !           169:     cp->allocmask |= allocmask;
        !           170:     hb->compile_start = ((char *)cp + (j << SUBUNIT_ORDER));
        !           171:     hb->alloclen = allocsize;
        !           172:     return hb->compile_start;
        !           173: }
        !           174: 
        !           175: static void remove_hash_from_lists(struct hash_entry *h)
        !           176: {
        !           177:     h->lru_next->lru_prev = h->lru_prev;
        !           178:     h->lru_prev->lru_next = h->lru_next;
        !           179: 
        !           180:     h->next->prev = h->prev;
        !           181:     h->prev->next = h->next;
        !           182: }
        !           183: 
        !           184: static void lru_touch(struct hash_entry *h)
        !           185: {
        !           186:     h->lru_next->lru_prev = h->lru_prev;
        !           187:     h->lru_prev->lru_next = h->lru_next;
        !           188: 
        !           189:     h->lru_next = &lru_first_hash;
        !           190:     h->lru_prev = lru_first_hash.lru_prev;
        !           191:     h->lru_prev->lru_next = h;
        !           192:     lru_first_hash.lru_prev = h;
        !           193: }
        !           194: 
        !           195: static void lru_untouch(struct hash_entry *h)
        !           196: {
        !           197:     h->lru_next->lru_prev = h->lru_prev;
        !           198:     h->lru_prev->lru_next = h->lru_next;
        !           199: 
        !           200:     h->lru_prev = &lru_first_hash;
        !           201:     h->lru_next = lru_first_hash.lru_next;
        !           202:     h->lru_next->lru_prev = h;
        !           203:     lru_first_hash.lru_next = h;
        !           204: }
        !           205: 
        !           206: static void forget_block(struct hash_block *hb)
        !           207: {
        !           208:     struct hash_entry *h = hb->he_first;
        !           209: 
        !           210:     hb->lru_next->lru_prev = hb->lru_prev;
        !           211:     hb->lru_prev->lru_next = hb->lru_next;
        !           212: 
        !           213:     hb->lru_next = freelist_block;
        !           214:     freelist_block = hb;
        !           215: 
        !           216:     if (hb->cpage != NULL)
        !           217:        fprintf(stderr, "Discarding block with code. Tsk.\n");
        !           218: 
        !           219:     do {
        !           220:        struct hash_entry *next = h->next_same_block;
        !           221:        h->block = NULL;
        !           222:        h->execute = NULL;
        !           223:        h->next_same_block = NULL;
        !           224:        h = next;
        !           225:        num_unused_hash++;
        !           226:        lru_untouch(h);
        !           227:     } while (h != hb->he_first);
        !           228:     compiler_flush_jsr_stack();
        !           229: }
        !           230: 
        !           231: static void lru_touch_block(struct hash_block *h)
        !           232: {
        !           233:     h->lru_next->lru_prev = h->lru_prev;
        !           234:     h->lru_prev->lru_next = h->lru_next;
        !           235: 
        !           236:     h->lru_next = &lru_first_block;
        !           237:     h->lru_prev = lru_first_block.lru_prev;
        !           238:     h->lru_prev->lru_next = h;
        !           239:     lru_first_block.lru_prev = h;
        !           240: }
        !           241: 
        !           242: STATIC_INLINE int check_block(struct hash_block *hb)
        !           243: {
        !           244: #ifndef RELY_ON_LOADSEG_DETECTION
        !           245:     struct hash_entry *h = hb->he_first;
        !           246: 
        !           247:     do {
        !           248:        struct hash_entry *next = h->next_same_block;
        !           249:        if (h->matchword != *(uae_u32 *)get_real_address(h->addr))
        !           250:            return 0;
        !           251:        h = next;
        !           252:     } while (h != hb->he_first);
        !           253: #endif
        !           254:     return 1;
        !           255: }
        !           256: 
        !           257: uae_u32 flush_icache(void)
        !           258: {
        !           259:     struct hash_block *hb = lru_first_block.lru_next;
        !           260: 
        !           261:     while (hb != &lru_first_block) {
        !           262:        struct hash_block *next = hb->lru_next;
        !           263:        if (hb->cpage != NULL) {
        !           264:            /* Address in chipmem? Then forget about block*/
        !           265:            if ((hb->he_first->addr & ~0xF80000) != 0xF80000) {
        !           266:                hb->cpage->allocmask &= ~hb->page_allocmask;
        !           267:                hb->cpage = NULL;
        !           268:                forget_block(hb);
        !           269:            }
        !           270:        }
        !           271:        hb = next;
        !           272:     }
        !           273:     return m68k_dreg(regs, 0);
        !           274: }
        !           275: 
        !           276: void possible_loadseg(void)
        !           277: {
        !           278:     fprintf(stderr, "Possible LoadSeg() detected\n");
        !           279:     flush_icache();
        !           280: }
        !           281: 
        !           282: static struct hash_block *new_block(void)
        !           283: {
        !           284:     struct hash_block *b = freelist_block;
        !           285: 
        !           286:     if (b != NULL) {
        !           287:        freelist_block = b->lru_next;
        !           288:     } else
        !           289:        b = (struct hash_block *)malloc(sizeof *b);
        !           290:     b->nrefs = 0;
        !           291:     b->cpage = NULL;
        !           292:     b->he_first = NULL;
        !           293:     b->translated = b->untranslatable = b->allocfailed = 0;
        !           294:     return b;
        !           295: }
        !           296: 
        !           297: static struct hash_entry *get_free_hash(void)
        !           298: {
        !           299:     struct hash_entry *h;
        !           300: 
        !           301:     for (;;) {
        !           302:        h = freelist_hash;
        !           303:        if (h != NULL) {
        !           304:            freelist_hash = h->next_same_block;
        !           305:            break;
        !           306:        }
        !           307:        h = lru_first_hash.lru_next;
        !           308:        if (num_unused_hash >= MAX_UNUSED_HASH && h->block == NULL
        !           309:            && !h->locked)
        !           310:        {
        !           311:            remove_hash_from_lists(h);
        !           312:            num_unused_hash--;
        !           313:            break;
        !           314:        }
        !           315:        h = (struct hash_entry *)malloc(sizeof(struct hash_entry));
        !           316:        h->next_same_block = NULL;
        !           317:        h->addr = -1;
        !           318:        break;
        !           319:     }
        !           320:     num_unused_hash++;
        !           321:     h->block = NULL;
        !           322:     h->ncalls = 0;
        !           323:     h->locked = h->cacheflush = 0;
        !           324:     h->execute = NULL;
        !           325:     return h;
        !           326: }
        !           327: 
        !           328: static struct hash_entry *new_hash(uaecptr addr)
        !           329: {
        !           330:     struct hash_entry *h = get_free_hash();
        !           331: 
        !           332:     h->addr = addr;
        !           333: 
        !           334:     /* Chain the new node */
        !           335:     h->prev = cpu_hash + ((addr >> 1) & HASH_MASK);
        !           336:     h->next = h->prev->next;
        !           337:     h->next->prev = h->prev->next = h;
        !           338: 
        !           339:     h->lru_next = &lru_first_hash;
        !           340:     h->lru_prev = lru_first_hash.lru_prev;
        !           341:     h->lru_prev->lru_next = h;
        !           342:     lru_first_hash.lru_prev = h;
        !           343: 
        !           344:     h->next_same_block = NULL;
        !           345: 
        !           346:     return h;
        !           347: }
        !           348: static struct hash_entry *find_hash(uaecptr addr)
        !           349: {
        !           350:     struct hash_entry *h;
        !           351:     struct hash_entry *h1 = cpu_hash + ((addr >> 1) & HASH_MASK);
        !           352: 
        !           353:     if (h1->next->addr == addr)
        !           354:        return h1->next;
        !           355: 
        !           356:     for (h = h1->next; h != h1; h = h->next) {
        !           357:        if (h->addr == addr) {
        !           358:            /* Put it at the head of the list so that the above shortcut
        !           359:             * works the next time we come here */
        !           360:            h->next->prev = h->prev; h->prev->next = h->next;
        !           361:            h->prev = h1;
        !           362:            h->next = h1->next;
        !           363:            h->next->prev = h->prev->next = h;
        !           364:            return h;
        !           365:        }
        !           366:     }
        !           367:     return NULL;
        !           368: }
        !           369: 
        !           370: static struct hash_entry *get_hash_for_func(uaecptr addr, int mark_locked)
        !           371: {
        !           372:     struct hash_entry *h = find_hash(addr);
        !           373:     if (h == NULL)
        !           374:        h = new_hash (addr);
        !           375: #if 0 /* Too expensive */
        !           376:     else
        !           377:        lru_touch(h);
        !           378: #endif
        !           379:     if (mark_locked)
        !           380:        h->locked = 1;
        !           381:     return h;
        !           382: }
        !           383: 
        !           384: static struct hash_entry *get_hash(uaecptr addr)
        !           385: {
        !           386:     struct hash_entry *h = get_hash_for_func(addr, 0);
        !           387: 
        !           388:     if (h->block == NULL) {
        !           389:        if (++h->ncalls == SCAN_MARK) {
        !           390:            m68k_scan_func(h);
        !           391:        }
        !           392:     } else
        !           393:        if (!h->block->untranslatable && h->block->nrefs++ == COMPILE_MARK) {
        !           394:            lru_touch_block(h->block);
        !           395:            if (m68k_compile_block(h->block)) {
        !           396:                h->block->untranslatable = 1;
        !           397:            } else {
        !           398:                h->block->translated = 1;
        !           399:            }
        !           400:        }
        !           401:     return h;
        !           402: }
        !           403: 
        !           404: void special_flush_hash(uaecptr addr)
        !           405: {
        !           406:     struct hash_entry *h = get_hash_for_func(addr, 0);
        !           407: 
        !           408:     h->cacheflush = 1;
        !           409: }
        !           410: 
        !           411: STATIC_INLINE void m68k_setpc_hash(uaecptr newpc)
        !           412: {
        !           413:     struct hash_entry *h = get_hash(newpc);
        !           414: 
        !           415:     if (h->cacheflush)
        !           416:        flush_icache();
        !           417: 
        !           418:     if (h->execute != NULL) {
        !           419:        if ((h->addr & 0xF80000) == 0xF80000 || check_block(h->block)) {
        !           420:            compiled_hits++;
        !           421:            if (i_want_to_die && (call_only_me == 0 || call_only_me == newpc)) {
        !           422:                exec_me = h->execute;
        !           423:                nr_bbs_to_run = nr_bbs_start;
        !           424:                regs.spcflags |= SPCFLAG_EXEC;
        !           425:            }
        !           426:        } else
        !           427:            flush_icache();
        !           428:     }
        !           429:     regs.pc = newpc;
        !           430:     regs.pc_p = regs.pc_oldp = get_real_address(newpc);
        !           431: }
        !           432: 
        !           433: STATIC_INLINE void m68k_setpc_nohash(uaecptr newpc)
        !           434: {
        !           435: #if 0
        !           436:     /* This is probably not too good for efficiency... FIXME */
        !           437:     struct hash_entry *h = find_hash(newpc);
        !           438: 
        !           439:     if (h != NULL && h->cacheflush)
        !           440:        flush_icache();
        !           441: #endif
        !           442:     regs.pc = newpc;
        !           443:     regs.pc_p = regs.pc_oldp = get_real_address(newpc);
        !           444: }
        !           445: 
        !           446: void m68k_setpc(uaecptr newpc)
        !           447: {
        !           448:     m68k_setpc_hash(newpc);
        !           449: }
        !           450: 
        !           451: void m68k_setpc_fast(uaecptr newpc)
        !           452: {
        !           453:     m68k_setpc_nohash(newpc);
        !           454: }
        !           455: 
        !           456: void m68k_setpc_rte(uaecptr newpc)
        !           457: {
        !           458:     m68k_setpc_nohash(newpc);
        !           459: }
        !           460: 
        !           461: void m68k_setpc_bcc(uaecptr newpc)
        !           462: {
        !           463:     m68k_setpc_hash(newpc);
        !           464: }
        !           465: 
        !           466: static void hash_init(void)
        !           467: {
        !           468:     int i;
        !           469:     struct hash_entry **hepp;
        !           470: 
        !           471:     freelist_block = NULL;
        !           472:     freelist_hash = NULL;
        !           473: 
        !           474:     for(i = 0; i < NUM_HASH; i++) {
        !           475:        cpu_hash[i].next = cpu_hash[i].prev = cpu_hash + i;
        !           476:        cpu_hash[i].lru_next = cpu_hash[i].lru_prev = NULL;
        !           477:        cpu_hash[i].block = NULL;
        !           478:        cpu_hash[i].locked = 0; cpu_hash[i].cacheflush = 0;
        !           479:        cpu_hash[i].addr = -1;
        !           480:     }
        !           481: 
        !           482:     lru_first_hash.lru_next = lru_first_hash.lru_prev = &lru_first_hash;
        !           483:     lru_first_block.lru_next = lru_first_block.lru_prev = &lru_first_block;
        !           484: 
        !           485:     num_unused_hash = 0;
        !           486: }
        !           487: 
        !           488: static void code_init(void)
        !           489: {
        !           490:     first_code_page = NULL;
        !           491:     zerofd = open("/dev/zero", O_RDWR);
        !           492:     zeroff = 0;
        !           493: }
        !           494: 
        !           495: #define CC68K_C 16
        !           496: #define CC68K_V 8
        !           497: #define CC68K_Z 4
        !           498: #define CC68K_N 2
        !           499: #define CC68K_X 1
        !           500: 
        !           501: STATIC_INLINE int cc_flagmask_68k(const int cc)
        !           502: {
        !           503:     switch(cc){
        !           504:      case 0: return 0;                       /* T */
        !           505:      case 1: return 0;                       /* F */
        !           506:      case 2: return CC68K_C|CC68K_Z;         /* HI */
        !           507:      case 3: return CC68K_C|CC68K_Z;         /* LS */
        !           508:      case 4: return CC68K_C;                 /* CC */
        !           509:      case 5: return CC68K_C;                 /* CS */
        !           510:      case 6: return CC68K_Z;                 /* NE */
        !           511:      case 7: return CC68K_Z;                 /* EQ */
        !           512:      case 8: return CC68K_V;                 /* VC */
        !           513:      case 9: return CC68K_V;                 /* VS */
        !           514:      case 10:return CC68K_N;                 /* PL */
        !           515:      case 11:return CC68K_N;                 /* MI */
        !           516:      case 12:return CC68K_N|CC68K_V;         /* GE */
        !           517:      case 13:return CC68K_N|CC68K_V;         /* LT */
        !           518:      case 14:return CC68K_N|CC68K_V|CC68K_Z; /* GT */
        !           519:      case 15:return CC68K_N|CC68K_V|CC68K_Z; /* LE */
        !           520:     }
        !           521:     abort();
        !           522:     return 0;
        !           523: }
        !           524: 
        !           525: STATIC_INLINE void translate_step_over_ea(uae_u8 **pcpp, amodes m,
        !           526:                                              wordsizes size)
        !           527: {
        !           528:     switch (m) {
        !           529:      case Areg:
        !           530:      case Dreg:
        !           531:      case Aind:
        !           532:      case Aipi:
        !           533:      case Apdi:
        !           534:      case immi:
        !           535:        break;
        !           536: 
        !           537:      case imm:
        !           538:        if (size == sz_long)
        !           539:            goto is_long;
        !           540:        /* fall through */
        !           541:      case Ad16:
        !           542:      case PC16:
        !           543:      case imm0:
        !           544:      case imm1:
        !           545:      case absw:
        !           546:        (*pcpp)+=2;
        !           547:        break;
        !           548:      case Ad8r:
        !           549:      case PC8r:
        !           550:        {
        !           551:            uae_u16 extra = *(*pcpp)++;
        !           552:            extra <<= 8;
        !           553:            extra |= *(*pcpp)++;
        !           554:            /* @@@ handle 68020 stuff here */
        !           555:        }
        !           556:        break;
        !           557:      case absl:
        !           558:      case imm2:
        !           559:        is_long:
        !           560:        (*pcpp) += 4;
        !           561:        break;
        !           562:     }
        !           563: }
        !           564: 
        !           565: static struct instr *translate_getnextinsn(uae_u8 **pcpp)
        !           566: {
        !           567:     uae_u16 opcode;
        !           568:     struct instr *dp;
        !           569: 
        !           570:     opcode = *(*pcpp)++ << 8;
        !           571:     opcode |= *(*pcpp)++;
        !           572: 
        !           573:     if (cpufunctbl[opcode] == op_illg) {
        !           574:        opcode = 0x4AFC;
        !           575:     }
        !           576:     dp = table68k + opcode;
        !           577:     if (dp->suse) {
        !           578:        translate_step_over_ea(pcpp, dp->smode, dp->size);
        !           579:     }
        !           580:     if (dp->duse) {
        !           581:        translate_step_over_ea(pcpp, dp->dmode, dp->size);
        !           582:     }
        !           583:     return dp;
        !           584: }
        !           585: 
        !           586: #define CB_STACKSIZE 200
        !           587: #define BB_STACKSIZE 200
        !           588: 
        !           589: static uae_u32 condbranch_stack[CB_STACKSIZE];
        !           590: static int condbranch_src_stack[CB_STACKSIZE];
        !           591: 
        !           592: struct bb_info {
        !           593:     struct hash_entry *h;
        !           594:     uaecptr stopaddr;
        !           595:     int can_compile_last;
        !           596:     struct bb_info *bb_next1, *bb_next2;
        !           597:     int flags_live_at_end;
        !           598:     int flags_live_at_start;
        !           599:     int first_iip, last_iip;
        !           600: } bb_stack[BB_STACKSIZE];
        !           601: 
        !           602: static int top_bb;
        !           603: 
        !           604: static uaecptr bcc_target_stack[BB_STACKSIZE];
        !           605: 
        !           606: static int new_bcc_target(uaecptr addr)
        !           607: {
        !           608:     int i;
        !           609: 
        !           610:     for (i = 0; i < top_bb; i++)
        !           611:        if (bcc_target_stack[i] == addr)
        !           612:            return 1;
        !           613: 
        !           614:     if (top_bb == BB_STACKSIZE)
        !           615:        return 0;
        !           616:     bcc_target_stack[top_bb++] = addr;
        !           617:     return 1;
        !           618: }
        !           619: 
        !           620: static int bcc_compfn(const void *a, const void *b)
        !           621: {
        !           622:     uaecptr *a1 = (uaecptr *)a, *b1 = (uaecptr *)b;
        !           623: 
        !           624:     if (*a1 == *b1)
        !           625:        printf("BUG!!\n");
        !           626: 
        !           627:     if (*a1 < *b1)
        !           628:        return 1;
        !           629:     return -1;
        !           630: }
        !           631: 
        !           632: static int bb_compfn(const void *a, const void *b)
        !           633: {
        !           634:     struct bb_info *a1 = (struct bb_info *)a, *b1 = (struct bb_info *)b;
        !           635: 
        !           636:     if (a1->h->addr == b1->h->addr)
        !           637:        printf("BUG!!\n");
        !           638: 
        !           639:     if (a1->h->addr < b1->h->addr)
        !           640:        return -1;
        !           641:     return 1;
        !           642: }
        !           643: 
        !           644: static int find_basic_blocks(struct hash_entry *h)
        !           645: {
        !           646:     int current_bb = 0;
        !           647: 
        !           648:     top_bb = 0;
        !           649:     bcc_target_stack[0] = h->addr;
        !           650:     new_bcc_target(h->addr);
        !           651: 
        !           652:     while (top_bb > current_bb) {
        !           653:        uaecptr addr = bcc_target_stack[current_bb];
        !           654:        int ninsns = 0;
        !           655:        uae_u8 *realpc = get_real_address(addr);
        !           656:        uae_u8 *rpc_start = realpc;
        !           657: 
        !           658:        for(;;) {
        !           659:            uaecptr thisinsn_addr = (realpc - rpc_start) + addr;
        !           660:            uae_u8 *rpc_save = realpc;
        !           661:            struct instr *dp = translate_getnextinsn(&realpc);
        !           662:            uaecptr nextinsn_addr = (realpc - rpc_start) + addr;
        !           663: 
        !           664:            if (dp->mnemo == i_RTS || dp->mnemo == i_RTE
        !           665:                || dp->mnemo == i_RTR || dp->mnemo == i_RTD
        !           666:                || dp->mnemo == i_JMP || dp->mnemo == i_ILLG)
        !           667:            {
        !           668:                break;
        !           669:            }
        !           670: 
        !           671:            if (dp->mnemo == i_BSR || dp->mnemo == i_JSR) {
        !           672:                if (!new_bcc_target(nextinsn_addr))
        !           673:                    return 0;
        !           674:                break;
        !           675:            }
        !           676: 
        !           677:            if (dp->mnemo == i_DBcc) {
        !           678:                uaecptr newaddr = thisinsn_addr + 2 + (uae_s16)((*(rpc_save+2) << 8) | *(rpc_save+3));
        !           679:                if (!new_bcc_target(nextinsn_addr))
        !           680:                    return 0;
        !           681:                if (!new_bcc_target(newaddr))
        !           682:                    return 0;
        !           683:                break;
        !           684:            }
        !           685: 
        !           686:            if (dp->mnemo == i_Bcc) {
        !           687:                uaecptr newaddr;
        !           688:                if (dp->smode == imm1)
        !           689:                    newaddr = thisinsn_addr + 2 + (uae_s16)((*(rpc_save+2) << 8) | *(rpc_save+3));
        !           690:                else
        !           691:                    newaddr = thisinsn_addr + 2 + (uae_s8)dp->sreg;
        !           692: 
        !           693:                if (dp->cc != 0)
        !           694:                    if (!new_bcc_target(nextinsn_addr))
        !           695:                        return 0;
        !           696:                if (!new_bcc_target(newaddr))
        !           697:                    return 0;
        !           698:                break;
        !           699:            }
        !           700:        }
        !           701:        current_bb++;
        !           702:     }
        !           703: 
        !           704:     qsort(bcc_target_stack, top_bb, sizeof (uaecptr), bcc_compfn);
        !           705: 
        !           706:     return 1;
        !           707: }
        !           708: 
        !           709: static int m68k_scan_func(struct hash_entry *h)
        !           710: {
        !           711:     int i;
        !           712:     struct hash_block *found_block;
        !           713:     struct hash_entry **hepp;
        !           714: 
        !           715:     if (!find_basic_blocks(h))
        !           716:        return 0;
        !           717: 
        !           718:     found_block = NULL;
        !           719: 
        !           720:     /* First, lock the hash entries we already have to prevent grief */
        !           721:     for (i = 0; i < top_bb; i++) {
        !           722:        struct hash_entry *h = find_hash(bcc_target_stack[i]);
        !           723:        if (h != NULL)
        !           724:            h->locked = 1;
        !           725:     }
        !           726: 
        !           727:     /* Allocate new ones */
        !           728:     for (i = 0; i < top_bb; i++) {
        !           729:        struct hash_entry *h = get_hash_for_func(bcc_target_stack[i], 1);
        !           730:        bb_stack[i].h = h;
        !           731: #if 0 /* This doesn't work in all cases */
        !           732:        if (h->block != NULL && h->block != found_block) {
        !           733:            if (found_block == NULL) {
        !           734:                if (h->block->cpage != NULL)
        !           735:                    fprintf(stderr, "Found compiled code\n");
        !           736:                else
        !           737:                    found_block = h->block;
        !           738:            } else {
        !           739:                fprintf(stderr, "Multiple blocks found.\n");
        !           740:                if (h->block->cpage == NULL)
        !           741:                    forget_block(h->block);
        !           742:                else if (found_block->cpage == NULL) {
        !           743:                    forget_block(found_block);
        !           744:                    found_block = h->block;
        !           745:                } else
        !           746:                    fprintf(stderr, "Bad case.\n");
        !           747:            }
        !           748:        }
        !           749: #endif
        !           750:     }
        !           751:     if (found_block == NULL) {
        !           752:        found_block = new_block();
        !           753: 
        !           754:        found_block->lru_next = &lru_first_block;
        !           755:        found_block->lru_prev = lru_first_block.lru_prev;
        !           756:        found_block->lru_prev->lru_next = found_block;
        !           757:        lru_first_block.lru_prev = found_block;
        !           758:     }
        !           759: 
        !           760:     hepp = &found_block->he_first;
        !           761:     found_block->he_first = NULL;
        !           762:     for (i = 0; i < top_bb; i++) {
        !           763:        struct bb_info *bb = bb_stack + i;
        !           764: 
        !           765:        if (bb->h->block == NULL) {
        !           766:            num_unused_hash--;
        !           767:            lru_touch(bb->h);
        !           768:            bb->h->block = found_block;
        !           769:            *hepp = bb->h;
        !           770:            hepp = &bb->h->next_same_block;
        !           771:        }
        !           772:     }
        !           773:     *hepp = found_block->he_first;
        !           774:     return 1;
        !           775: }
        !           776: 
        !           777: struct ea_reg_info {
        !           778:     enum { eat_reg, eat_imem, eat_amem, eat_const } ea_type;
        !           779:     int regs_set:16;
        !           780:     int regs_used:16;
        !           781:     int nr_scratch;
        !           782:     uae_u32 temp1, temp2;
        !           783: };
        !           784: 
        !           785: #define MAX_TRANSLATE 2048
        !           786: struct insn_info_struct {
        !           787:     uaecptr address;
        !           788:     struct instr *dp;
        !           789:     int flags_set;
        !           790:     int flags_used;
        !           791:     int flags_live_at_end;
        !           792:     int jump_target;
        !           793:     int jumps_to;
        !           794:     char *compiled_jumpaddr; /* Address to use for jumps to this insn */
        !           795:     char *compiled_fillin;   /* Address where to put offset if this is a Bcc */
        !           796:     int regs_set:16;
        !           797:     int regs_used:16;
        !           798:     int stop_translation:2;
        !           799:     int sync_cache:1;
        !           800:     int sync_flags:1;
        !           801:     int ccuser_follows:1;
        !           802: } insn_info [MAX_TRANSLATE];
        !           803: 
        !           804: #define EA_NONE 0
        !           805: #define EA_LOAD 1
        !           806: #define EA_STORE 2
        !           807: #define EA_MODIFY 4
        !           808: 
        !           809: #if 0
        !           810: static void analyze_ea_for_insn(amodes mode, int reg, wordsizes size,
        !           811:                                struct ea_reg_info *eai,
        !           812:                                uae_u8 **pcpp, uaecptr pca,
        !           813:                                int ea_purpose)
        !           814: {
        !           815:     uae_u8 *p = *pcpp;
        !           816: 
        !           817:     switch(mode) {
        !           818:      case Dreg:
        !           819:        eai->ea_type = eat_reg;
        !           820:        if (size != sz_long && (ea_purpose & EA_STORE))
        !           821:            ea_purpose |= EA_LOAD;
        !           822:        if (ea_purpose & EA_LOAD)
        !           823:            eai->regs_used |= 1 << reg;
        !           824:        if (ea_purpose & EA_STORE)
        !           825:            eai->regs_set |= 1 << reg;
        !           826:        break;
        !           827: 
        !           828:      case Areg:
        !           829:        eai->ea_type = eat_reg;
        !           830:        if (size != sz_long && (ea_purpose & EA_STORE))
        !           831:            printf("Areg != long\n");
        !           832:        if (ea_purpose & EA_LOAD)
        !           833:            eai->regs_used |= 1 << (8+reg);
        !           834:        if (ea_purpose & EA_STORE)
        !           835:            eai->regs_set |= 1 << (8+reg);
        !           836:        break;
        !           837: 
        !           838:      case Ad16:
        !           839:      case Aind:
        !           840:      case Apdi:
        !           841:      case Aipi:
        !           842:        eai->ea_type = eat_imem;
        !           843:        eai->regs_used |= 1 << (8+reg);
        !           844:        break;
        !           845: 
        !           846:      case Ad8r:
        !           847:        eai->ea_type = eat_imem;
        !           848:        pii->regs_used |= 1 << (8+reg);
        !           849: 
        !           850:        eai->temp = (uae_u16)((*p << 8) | *(p+1));
        !           851:        r = (eai->temp & 0x7000) >> 12;
        !           852:        (*pcpp) += 2; p += 2;
        !           853: 
        !           854:        if (eai->temp1 & 0x8000)
        !           855:            pii->regs_used |= 1 << (8+r);
        !           856:        else
        !           857:            pii->regs_used |= 1 << r;
        !           858:        break;
        !           859: 
        !           860:      case PC8r:
        !           861:        eai->ea_type = eat_imem;
        !           862:        eai->temp1 = (uae_u16)do_get_mem_word((uae_u16 *)p);
        !           863:        eai->temp2 = pca + (uae_s8)eai->temp1;
        !           864:        (*pcpp) += 2; p += 2;
        !           865:        r = (eai->temp1 & 0x7000) >> 12;
        !           866: 
        !           867:        if (eai->temp1 & 0x8000)
        !           868:            pii->regs_used |= 1 << (8+r);
        !           869:        else
        !           870:            pii->regs_used |= 1 << r;
        !           871:        break;
        !           872: 
        !           873:      case PC16:
        !           874:        eai->ea_type = eat_amem;
        !           875:        eai->temp1 = pca + (uae_s16)do_get_mem_word((uae_u16 *)p);
        !           876:        (*pcpp) += 2;
        !           877:        break;
        !           878: 
        !           879:      case absw:
        !           880:        eai->ea_type = eat_amem;
        !           881:        eai->temp1 = (uae_s16)do_get_mem_word((uae_u16 *)p);
        !           882:        (*pcpp) += 2;
        !           883:        break;
        !           884: 
        !           885:      case absl:
        !           886:        eai->ea_type = eat_amem;
        !           887:        eai->temp1 = (uae_s32)do_get_mem_long((uae_u32 *)p);
        !           888:        (*pcpp) += 4;
        !           889:        break;
        !           890: 
        !           891:      case imm:
        !           892:        if (size == sz_long)
        !           893:            goto imm2_const;
        !           894:        if (size == sz_word)
        !           895:            goto imm1_const;
        !           896: 
        !           897:        /* fall through */
        !           898:      case imm0:
        !           899:        eai->ea_type = eat_imm;
        !           900:        eai->temp1 = (uae_s8)*(p+1);
        !           901:        (*pcpp) += 2;
        !           902:        break;
        !           903: 
        !           904:      case imm1:
        !           905:        imm1_const:
        !           906:        eai->ea_type = eat_imm;
        !           907:        eai->temp1 = (uae_s16)do_get_mem_word((uae_u16 *)p);
        !           908:        (*pcpp) += 2;
        !           909:        break;
        !           910: 
        !           911:      case imm2:
        !           912:        imm2_const:
        !           913:        eai->ea_type = eat_imm;
        !           914:        eai->temp1 = (uae_s32)do_get_mem_long((uae_u32 *)p);
        !           915:        (*pcpp) += 4;
        !           916:        break;
        !           917: 
        !           918:      case immi:
        !           919:        eai->ea_type = eat_imm;
        !           920:        eai->temp1 = (uae_s8)reg;
        !           921:        break;
        !           922: 
        !           923:      default:
        !           924:        break;
        !           925:     }
        !           926: }
        !           927: #endif
        !           928: static struct bb_info *find_bb(struct hash_entry *h)
        !           929: {
        !           930:     int i;
        !           931: 
        !           932:     if (h == NULL)
        !           933:        printf("Bug...\n");
        !           934: 
        !           935:     for (i = 0; i < top_bb; i++)
        !           936:        if (bb_stack[i].h == h)
        !           937:            return bb_stack + i;
        !           938:     if (!quiet_compile)
        !           939:        fprintf(stderr, "BB not found!\n");
        !           940:     return NULL;
        !           941: }
        !           942: 
        !           943: static int m68k_scan_block(struct hash_block *hb, int *movem_count)
        !           944: {
        !           945:     struct hash_entry *h = hb->he_first;
        !           946:     int i, iip, last_iip;
        !           947:     int changed, round;
        !           948: 
        !           949:     top_bb = 0;
        !           950: 
        !           951:     do {
        !           952:        struct bb_info *bb = bb_stack + top_bb;
        !           953:        bb->h = h;
        !           954:        bb->bb_next1 = NULL;
        !           955:        bb->bb_next2 = NULL;
        !           956:        h = h->next_same_block;
        !           957:        top_bb++;
        !           958:     } while (h != hb->he_first);
        !           959: 
        !           960:     qsort(bb_stack, top_bb, sizeof (struct bb_info), bb_compfn);
        !           961: 
        !           962:     *movem_count = 0;
        !           963: 
        !           964:     iip = 0;
        !           965:     for (i = 0; i < top_bb; i++) {
        !           966:        struct bb_info *bb = bb_stack + i;
        !           967:        uae_u8 *realpc = get_real_address(bb->h->addr);
        !           968:        uae_u8 *rpc_start = realpc;
        !           969:        uaecptr stop_addr = 0;
        !           970:        int live_at_start = 31, may_clear_las = 31;
        !           971:        struct insn_info_struct *prev_ii = NULL;
        !           972: 
        !           973:        if (i < top_bb - 1)
        !           974:            stop_addr = (bb+1)->h->addr;
        !           975:        bb->first_iip = iip;
        !           976: 
        !           977:        for (;;) {
        !           978:            struct insn_info_struct *thisii = insn_info + iip;
        !           979:            uaecptr thisinsn_addr = (realpc - rpc_start) + bb->h->addr;
        !           980:            uae_u8 *rpc_save = realpc;
        !           981:            struct instr *dp = translate_getnextinsn(&realpc);
        !           982:            uaecptr nextinsn_addr = (realpc - rpc_start) + bb->h->addr;
        !           983: 
        !           984:            int fset = dp->flagdead == -1 ? 31 : dp->flagdead;
        !           985:            int fuse = dp->flaglive == -1 ? 31 : dp->flaglive;
        !           986: 
        !           987:            if (thisinsn_addr == stop_addr) {
        !           988:                bb->bb_next1 = find_bb (find_hash (thisinsn_addr));
        !           989:                break;
        !           990:            }
        !           991: 
        !           992:            if (dp->mnemo == i_Scc || dp->mnemo == i_Bcc || dp->mnemo == i_DBcc) {
        !           993:                fset = 0, fuse = cc_flagmask_68k(dp->cc);
        !           994:                if (prev_ii && dp->mnemo != i_Scc) /* Don't use Scc here: ea can cause an exit */
        !           995:                    prev_ii->ccuser_follows = 1;
        !           996:            }
        !           997: 
        !           998:            may_clear_las &= ~fuse;
        !           999:            live_at_start &= ~(fset & may_clear_las);
        !          1000: 
        !          1001:            thisii->dp = dp;
        !          1002:            thisii->address = thisinsn_addr;
        !          1003:            thisii->stop_translation = 0;
        !          1004:            thisii->ccuser_follows = 0;
        !          1005: /*         thisii->have_reginfo = 0;*/
        !          1006:            thisii->jump_target = 0;
        !          1007:            thisii->sync_cache = thisii->sync_flags = 0;
        !          1008:            thisii->flags_set = fset;
        !          1009:            thisii->flags_used = fuse;
        !          1010:            thisii->regs_set = 0;
        !          1011:            thisii->regs_used = 0;
        !          1012:            iip++;
        !          1013:            if (iip == MAX_TRANSLATE)
        !          1014:                return 0;
        !          1015: 
        !          1016:            if (dp->mnemo == i_RTS || dp->mnemo == i_RTE
        !          1017:                || dp->mnemo == i_RTR || dp->mnemo == i_RTD
        !          1018:                || dp->mnemo == i_JMP || dp->mnemo == i_ILLG)
        !          1019:            {
        !          1020:                thisii->flags_used = 31;
        !          1021:                thisii->regs_used = 65535;
        !          1022:                thisii->stop_translation = dp->mnemo == i_RTS || dp->mnemo == i_JMP ? 2 : 1;
        !          1023:                break;
        !          1024:            }
        !          1025:            if (dp->mnemo == i_BSR || dp->mnemo == i_JSR)
        !          1026:            {
        !          1027:                thisii->flags_used = 31;
        !          1028:                thisii->regs_used = 65535;
        !          1029:                bb->can_compile_last = 1;
        !          1030:                bb->bb_next1 = find_bb (get_hash_for_func (nextinsn_addr, 1));
        !          1031:                if (bb->bb_next1 == NULL)
        !          1032:                    thisii->stop_translation = 1;
        !          1033:                break;
        !          1034:            }
        !          1035: 
        !          1036:            if (dp->mnemo == i_DBcc) {
        !          1037:                uaecptr newaddr = thisinsn_addr + 2 + (uae_s16)((*(rpc_save+2) << 8) | *(rpc_save+3));
        !          1038:                bb->can_compile_last = 1;
        !          1039:                bb->bb_next1 = find_bb (get_hash_for_func (newaddr, 1));
        !          1040:                if (bb->bb_next1 == NULL)
        !          1041:                    thisii->stop_translation = 1;
        !          1042:                bb->bb_next2 = find_bb (get_hash_for_func (nextinsn_addr, 1));
        !          1043:                if (bb->bb_next2 == NULL)
        !          1044:                    thisii->stop_translation = 1;
        !          1045:                thisii->regs_used = 65535;
        !          1046:                break;
        !          1047:            }
        !          1048: 
        !          1049:            if (dp->mnemo == i_Bcc) {
        !          1050:                uaecptr newaddr;
        !          1051:                if (dp->smode == imm1)
        !          1052:                    newaddr = thisinsn_addr + 2 + (uae_s16)((*(rpc_save+2) << 8) | *(rpc_save+3));
        !          1053:                else
        !          1054:                    newaddr = thisinsn_addr + 2 + (uae_s8)dp->sreg;
        !          1055:                bb->can_compile_last = 1;
        !          1056:                bb->bb_next1 = find_bb(get_hash_for_func(newaddr, 1));
        !          1057:                if (bb->bb_next1 == NULL)
        !          1058:                    thisii->stop_translation = 1;
        !          1059:                if (dp->cc != 0) {
        !          1060:                    bb->bb_next2 = find_bb(get_hash_for_func(nextinsn_addr, 1));
        !          1061:                    if (bb->bb_next2 == NULL)
        !          1062:                        thisii->stop_translation = 1;
        !          1063:                }
        !          1064:                thisii->regs_used = 65535;
        !          1065:                break;
        !          1066:            }
        !          1067: 
        !          1068:            if (dp->mnemo == i_MVMLE || dp->mnemo == i_MVMEL) {
        !          1069:                uae_u16 regmask = (*(rpc_save + 2) << 8) | (*(rpc_save + 3));
        !          1070:                *movem_count += count_bits(regmask);
        !          1071:                if (dp->dmode == Apdi)
        !          1072:                    regmask = bitswap(regmask);
        !          1073:                if (dp->mnemo == i_MVMLE)
        !          1074:                    thisii->regs_used = regmask;
        !          1075:                else
        !          1076:                    thisii->regs_set = regmask;
        !          1077:            }
        !          1078: 
        !          1079:            prev_ii = thisii;
        !          1080:        }
        !          1081:        bb->last_iip = iip - 1;
        !          1082:        bb->flags_live_at_start = live_at_start;
        !          1083:     }
        !          1084:     last_iip = iip;
        !          1085:     round = 0;
        !          1086:     do {
        !          1087:        changed = 0;
        !          1088:        for (i = 0; i < top_bb; i++) {
        !          1089:            struct bb_info *bb = bb_stack + i;
        !          1090:            int mnemo;
        !          1091:            int current_live;
        !          1092:            struct instr *dp;
        !          1093: 
        !          1094:            iip = bb->last_iip;
        !          1095:            mnemo = insn_info[iip].dp->mnemo;
        !          1096: 
        !          1097:            /* Fix up branches */
        !          1098:            if (round == 0 && (mnemo == i_DBcc || mnemo == i_Bcc)) {
        !          1099:                if (bb->bb_next1 != NULL) {
        !          1100:                    insn_info[bb->last_iip].jumps_to = bb->bb_next1->first_iip;
        !          1101:                    insn_info[bb->bb_next1->first_iip].jump_target = 1;
        !          1102:                }
        !          1103:            }
        !          1104: 
        !          1105:            /* And take care of flag life information */
        !          1106:            dp = insn_info[iip].dp;
        !          1107:            if (insn_info[iip].stop_translation)
        !          1108:                current_live = 31;
        !          1109:            else if (dp->mnemo == i_DBcc || dp->mnemo == i_Bcc) {
        !          1110:                current_live = 0;
        !          1111:                if (bb->bb_next1 != NULL)
        !          1112:                    current_live |= bb->bb_next1->flags_live_at_start;
        !          1113:                if (bb->bb_next2 != NULL)
        !          1114:                    current_live |= bb->bb_next2->flags_live_at_start;
        !          1115:            } else {
        !          1116:                if (bb->bb_next1 == NULL && bb->bb_next2 == NULL)
        !          1117:                    fprintf(stderr, "Can't happen\n");
        !          1118:                current_live = 0;
        !          1119:                if (bb->bb_next1 != NULL)
        !          1120:                    current_live |= bb->bb_next1->flags_live_at_start;
        !          1121:                if (bb->bb_next2 != NULL)
        !          1122:                    current_live |= bb->bb_next2->flags_live_at_start;
        !          1123:            }
        !          1124: 
        !          1125:            do {
        !          1126:                insn_info[iip].flags_live_at_end = current_live;
        !          1127:                current_live &= ~insn_info[iip].flags_set;
        !          1128:                current_live |= insn_info[iip].flags_used;
        !          1129:            } while (iip-- != bb->first_iip);
        !          1130: 
        !          1131:            if (bb->flags_live_at_start != current_live && !quiet_compile)
        !          1132:                fprintf(stderr, "Fascinating %d!\n", round), changed = 1;
        !          1133:            bb->flags_live_at_start = current_live;
        !          1134:        }
        !          1135:        round++;
        !          1136:     } while (changed);
        !          1137:     return last_iip;
        !          1138: }
        !          1139: 
        !          1140: #define MAX_JSRS 4096 /* must be a power of two */
        !          1141: 
        !          1142: static uaecptr jsr_rets[MAX_JSRS];
        !          1143: static struct hash_entry *jsr_hash[MAX_JSRS];
        !          1144: static int jsr_num;
        !          1145: static struct hash_entry dummy_hash; /* This is for safety purposes only */
        !          1146: 
        !          1147: 
        !          1148: static void jsr_stack_init(void)
        !          1149: {
        !          1150:     jsr_num = 0;
        !          1151:     dummy_hash.execute = NULL;
        !          1152: }
        !          1153: 
        !          1154: void compiler_flush_jsr_stack(void)
        !          1155: {
        !          1156:     jsr_num = 0;
        !          1157: }
        !          1158: 
        !          1159: void m68k_do_rts(void)
        !          1160: {
        !          1161:     m68k_setpc(get_long(m68k_areg(regs, 7)));
        !          1162:     m68k_areg(regs, 7) += 4;
        !          1163:     if (jsr_num > 0)
        !          1164:        jsr_num--;
        !          1165: }
        !          1166: 
        !          1167: __inline__ void m68k_do_jsr(uaecptr oldpc, uaecptr dest)
        !          1168: {
        !          1169:     struct hash_entry *h = find_hash(oldpc);
        !          1170: 
        !          1171:     if (jsr_num == MAX_JSRS)
        !          1172:        compiler_flush_jsr_stack();
        !          1173:     if (h == NULL) {
        !          1174:        jsr_hash[jsr_num] = &dummy_hash;
        !          1175:        jsr_rets[jsr_num++] = 0xC0DEDBAD;
        !          1176:     } else {
        !          1177:        jsr_hash[jsr_num] = h;
        !          1178:        jsr_rets[jsr_num++] = oldpc;
        !          1179:     }
        !          1180:     m68k_areg(regs, 7) -= 4;
        !          1181:     put_long(m68k_areg(regs, 7), oldpc);
        !          1182:     m68k_setpc(dest);
        !          1183: }
        !          1184: 
        !          1185: void m68k_do_bsr(uaecptr oldpc, uae_s32 offset)
        !          1186: {
        !          1187:     m68k_do_jsr(oldpc, m68k_getpc() + offset);
        !          1188: }
        !          1189: 
        !          1190: /* Here starts the actual compiling part */
        !          1191: 
        !          1192: static char *compile_current_addr;
        !          1193: static char *compile_last_addr;
        !          1194: 
        !          1195: STATIC_INLINE void assemble(uae_u8 a)
        !          1196: {
        !          1197:     if (compile_current_addr < compile_last_addr) {
        !          1198:        *compile_current_addr++ = a;
        !          1199:     } else {
        !          1200:        compile_failure = 1;
        !          1201:     }
        !          1202: }
        !          1203: 
        !          1204: STATIC_INLINE void assemble_ulong(uae_u32 a)
        !          1205: {
        !          1206:     assemble(a);
        !          1207:     assemble(a >> 8);
        !          1208:     assemble(a >> 16);
        !          1209:     assemble(a >> 24);
        !          1210: }
        !          1211: 
        !          1212: STATIC_INLINE void assemble_ulong_68k(uae_u32 a)
        !          1213: {
        !          1214:     assemble(a >> 24);
        !          1215:     assemble(a >> 16);
        !          1216:     assemble(a >> 8);
        !          1217:     assemble(a);
        !          1218: }
        !          1219: 
        !          1220: STATIC_INLINE void assemble_uword(uae_u16 a)
        !          1221: {
        !          1222:     assemble(a);
        !          1223:     assemble(a >> 8);
        !          1224: }
        !          1225: 
        !          1226: STATIC_INLINE void assemble_long(void *a)
        !          1227: {
        !          1228:     assemble_ulong((uae_u32)a);
        !          1229: }
        !          1230: 
        !          1231: STATIC_INLINE void compile_org(char *addr)
        !          1232: {
        !          1233:     compile_current_addr = addr;
        !          1234: }
        !          1235: 
        !          1236: STATIC_INLINE char *compile_here(void)
        !          1237: {
        !          1238:     return compile_current_addr;
        !          1239: }
        !          1240: 
        !          1241: #define r_EAX 0
        !          1242: #define r_ECX 1
        !          1243: #define r_EDX 2
        !          1244: #define r_EBX 3
        !          1245: #define r_ESP 4
        !          1246: #define r_EBP 5
        !          1247: #define r_ESI 6
        !          1248: #define r_EDI 7
        !          1249: 
        !          1250: #define r_AH 0x84
        !          1251: #define r_CH 0x85
        !          1252: #define r_DH 0x86
        !          1253: #define r_BH 0x87
        !          1254: 
        !          1255: #define ALL_X86_REGS 255
        !          1256: #define ADDRESS_X86_REGS ((1 << r_EBP) | (1 << r_ESI) | (1 << r_EDI))
        !          1257: #define DATA_X86_REGS ((1 << r_EAX) | (1 << r_EDX) | (1 << r_EBX) | (1 << r_ECX))
        !          1258: 
        !          1259: #define BO_NORMAL 0
        !          1260: #define BO_SWAPPED_LONG 1
        !          1261: #define BO_SWAPPED_WORD 2
        !          1262: 
        !          1263: struct register_mapping {
        !          1264:     int dreg_map[8], areg_map[8]; /* 68000 register cache */
        !          1265:     int x86_const_offset[8];
        !          1266:     int x86_dirty[8];
        !          1267:     int x86_cache_reg[8]; /* Regs used for the 68000 register cache */
        !          1268:     int x86_cr_type[8]; /* Caching data or address register? */
        !          1269:     int x86_locked[8]; /* Regs used for some purpose */
        !          1270:     int x86_users[8];
        !          1271:     int x86_byteorder[8];
        !          1272:     int x86_verified[8];
        !          1273: };
        !          1274: 
        !          1275: /*
        !          1276:  * First, code to compile some primitive x86 instructions
        !          1277:  */
        !          1278: 
        !          1279: static void compile_lea_reg_with_offset(int dstreg, int srcreg, uae_u32 srcoffs)
        !          1280: {
        !          1281:     assemble(0x8D);
        !          1282:     if (srcreg == -2) {
        !          1283:        assemble(0x05 + 8*dstreg);
        !          1284:        assemble_ulong(srcoffs);
        !          1285:     } else if ((uae_s32)srcoffs >= -128 && (uae_s32)srcoffs <= 127) {
        !          1286:        assemble(0x40 + 8*dstreg + srcreg);
        !          1287:        assemble(srcoffs);
        !          1288:     } else {
        !          1289:        assemble(0x80 + 8*dstreg + srcreg);
        !          1290:        assemble_ulong(srcoffs);
        !          1291:     }
        !          1292: }
        !          1293: 
        !          1294: static void compile_move_reg_reg(int dstreg, int srcreg, wordsizes size)
        !          1295: {
        !          1296:     if (size == sz_byte
        !          1297:        && (((1 << dstreg) & DATA_X86_REGS) == 0
        !          1298:            || ((1 << srcreg) & DATA_X86_REGS) == 0))
        !          1299:     {
        !          1300:        fprintf(stderr, "Moving wrong register types!\n");
        !          1301:     }
        !          1302:     if (size == sz_word)
        !          1303:        assemble(0x66);
        !          1304:     if (size == sz_byte)
        !          1305:        assemble(0x88);
        !          1306:     else
        !          1307:        assemble(0x89);
        !          1308:     assemble(0xC0 + dstreg + 8*srcreg);
        !          1309: }
        !          1310: 
        !          1311: static void compile_move_between_reg_mem_regoffs(int dstreg, int srcreg,
        !          1312:                                                 uae_u32 srcoffs, wordsizes size,
        !          1313:                                                 int code)
        !          1314: {
        !          1315:     if (size == sz_byte && (dstreg & 0x80) != 0)
        !          1316:        dstreg &= ~0x80;
        !          1317:     else if ((size == sz_byte
        !          1318:              && ((1 << dstreg) & DATA_X86_REGS) == 0)
        !          1319:             || (size != sz_byte && (dstreg & 0x80) != 0))
        !          1320:     {
        !          1321:        fprintf(stderr, "Moving wrong register types!\n");
        !          1322:     }
        !          1323:     if (size == sz_word)
        !          1324:        assemble(0x66);
        !          1325:     if (size == sz_byte)
        !          1326:        assemble(code);
        !          1327:     else
        !          1328:        assemble(code + 1);
        !          1329: 
        !          1330:     if (srcreg == -2) {
        !          1331:        assemble(0x05 + 8*dstreg);
        !          1332:        assemble_ulong(srcoffs);
        !          1333:     } else if ((uae_s32)srcoffs >= -128 && (uae_s32)srcoffs <= 127) {
        !          1334:        assemble(0x40 + 8*dstreg + srcreg);
        !          1335:        assemble(srcoffs);
        !          1336:     } else {
        !          1337:        assemble(0x80 + 8*dstreg + srcreg);
        !          1338:        assemble_ulong(srcoffs);
        !          1339:     }
        !          1340: }
        !          1341: 
        !          1342: static void compile_move_reg_from_mem_regoffs(int dstreg, int srcreg,
        !          1343:                                              uae_u32 srcoffs, wordsizes size)
        !          1344: {
        !          1345:     compile_move_between_reg_mem_regoffs(dstreg, srcreg, srcoffs, size, 0x8A);
        !          1346: }
        !          1347: 
        !          1348: static void compile_move_reg_to_mem_regoffs(int dstreg, uae_u32 dstoffs,
        !          1349:                                            int srcreg, wordsizes size)
        !          1350: {
        !          1351:     compile_move_between_reg_mem_regoffs(srcreg, dstreg, dstoffs, size, 0x88);
        !          1352: }
        !          1353: 
        !          1354: static void compile_byteswap(int x86r, wordsizes size, int save_flags)
        !          1355: {
        !          1356:     switch(size) {
        !          1357:      case sz_word:
        !          1358:        if (save_flags)
        !          1359:            assemble(0x9C);
        !          1360:        assemble(0x66); /* rolw $8,x86r */
        !          1361:        assemble(0xC1);
        !          1362:        assemble(0xC0 + x86r);
        !          1363:        assemble(8);
        !          1364:        if (save_flags)
        !          1365:            assemble(0x9D);
        !          1366:        break;
        !          1367:      case sz_long:
        !          1368:        assemble(0x0F); /* bswapl x86r */
        !          1369:        assemble(0xC8+x86r);
        !          1370:        break;
        !          1371:      default:
        !          1372:        break;
        !          1373:     }
        !          1374: }
        !          1375: 
        !          1376: static void compile_force_byteorder(struct register_mapping *map, int x86r,
        !          1377:                                    int desired_bo, int save_flags)
        !          1378: {
        !          1379:     if (x86r < 0 || map->x86_byteorder[x86r] == desired_bo)
        !          1380:        return;
        !          1381: 
        !          1382:     if (map->x86_byteorder[x86r] == BO_SWAPPED_LONG)
        !          1383:        compile_byteswap(x86r, sz_long, save_flags);
        !          1384:     else if (map->x86_byteorder[x86r] == BO_SWAPPED_WORD)
        !          1385:        compile_byteswap(x86r, sz_word, save_flags);
        !          1386: 
        !          1387:     if (desired_bo == BO_SWAPPED_LONG)
        !          1388:        compile_byteswap(x86r, sz_long, save_flags);
        !          1389:     else if (desired_bo == BO_SWAPPED_WORD)
        !          1390:        compile_byteswap(x86r, sz_word, save_flags);
        !          1391:     map->x86_byteorder[x86r] = desired_bo;
        !          1392: }
        !          1393: 
        !          1394: /* Add a constant offset to a x86 register. If it's in the cache, make sure
        !          1395:  * we update the const_offset value. The flags are unaffected by this */
        !          1396: 
        !          1397: static void compile_offset_reg(struct register_mapping *map, int x86r,
        !          1398:                               uae_u32 offset)
        !          1399: {
        !          1400:     int cached_68k;
        !          1401: 
        !          1402:     if (offset == 0 || x86r == -1 || x86r == -2)
        !          1403:        return;
        !          1404: 
        !          1405:     compile_force_byteorder(map, x86r, BO_NORMAL, 1);
        !          1406:     cached_68k = map->x86_cache_reg[x86r];
        !          1407:     if (cached_68k != -1) {
        !          1408:        map->x86_const_offset[x86r] -= offset;
        !          1409:        map->x86_dirty[x86r] = 1;
        !          1410:     }
        !          1411:     compile_lea_reg_with_offset(x86r, x86r, offset);
        !          1412: }
        !          1413: 
        !          1414: static int get_unused_x86_register(struct register_mapping *map)
        !          1415: {
        !          1416:     int x86r;
        !          1417:     for (x86r = 0; x86r < 24; x86r++) {
        !          1418:        if (map->x86_cache_reg[x86r] != -1)
        !          1419:            continue;
        !          1420:        if (map->x86_users[x86r] > 0)
        !          1421:            continue;
        !          1422: 
        !          1423:        map->x86_verified[x86r] = 0;
        !          1424:        map->x86_byteorder[x86r] = BO_NORMAL;
        !          1425:        return x86r;
        !          1426:     }
        !          1427:     return -1;
        !          1428: }
        !          1429: 
        !          1430: /*
        !          1431:  * sync_reg() may not touch the flags
        !          1432:  * If may_clobber is 1 and the reg had an offset, the reg will be offsetted
        !          1433:  * by this function
        !          1434:  */
        !          1435: static void sync_reg(struct register_mapping *map, int x86r, void *m68kr,
        !          1436:                     uae_u32 offset, int dirty, int may_clobber)
        !          1437: {
        !          1438:     if (dirty || offset != 0)
        !          1439:        compile_force_byteorder(map, x86r, BO_NORMAL, 1);
        !          1440:     if (offset != 0) {
        !          1441:        if (may_clobber) {
        !          1442:            compile_lea_reg_with_offset(x86r, x86r, offset);
        !          1443:            dirty = 1;
        !          1444:        } else {
        !          1445:            int tmpr = get_unused_x86_register(map);
        !          1446:            if (tmpr != -1) {
        !          1447:                compile_lea_reg_with_offset(tmpr, x86r, offset);
        !          1448:                x86r = tmpr;
        !          1449:                dirty = 1;
        !          1450:            } else {
        !          1451:                compile_lea_reg_with_offset(x86r, x86r, offset);
        !          1452:                assemble(0x89);          /* movl x86r,m68kr */
        !          1453:                assemble(0x05 + (x86r << 3));
        !          1454:                assemble_long(m68kr);
        !          1455:                compile_lea_reg_with_offset(x86r, x86r, -offset);
        !          1456:                return;
        !          1457:            }
        !          1458:        }
        !          1459:     }
        !          1460:     if (dirty) {
        !          1461:        assemble(0x89);          /* movl x86r,m68kr */
        !          1462:        assemble(0x05 + (x86r << 3));
        !          1463:        assemble_long(m68kr);
        !          1464:     }
        !          1465: }
        !          1466: 
        !          1467: static void sync_reg_cache(struct register_mapping *map, int flush)
        !          1468: {
        !          1469:     int i;
        !          1470: 
        !          1471:     for (i = 0; i < 8; i++) {
        !          1472:        int cr68k = map->x86_cache_reg[i];
        !          1473:        if (cr68k != -1) {
        !          1474:            if (map->x86_cr_type[i] == 1) {
        !          1475:                sync_reg(map, i, regs.regs + cr68k, map->x86_const_offset[i], map->x86_dirty[i], 1);
        !          1476:                if (flush)
        !          1477:                    map->dreg_map[cr68k] = -1;
        !          1478:            } else {
        !          1479:                sync_reg(map, i, regs.regs + 8 + cr68k, map->x86_const_offset[i], map->x86_dirty[i], 1);
        !          1480:                if (flush)
        !          1481:                    map->areg_map[cr68k] = -1;
        !          1482:            }
        !          1483:            if (flush)
        !          1484:                map->x86_cache_reg[i] = -1;
        !          1485:            map->x86_const_offset[i] = 0;
        !          1486:        }
        !          1487:     }
        !          1488:     memset(map->x86_dirty, 0, sizeof map->x86_dirty);
        !          1489: }
        !          1490: 
        !          1491: static void remove_x86r_from_cache(struct register_mapping *map, int x86r,
        !          1492:                                   int may_clobber)
        !          1493: {
        !          1494:     int j;
        !          1495:     int reg_68k;
        !          1496: 
        !          1497:     if (x86r == -1)
        !          1498:        return;
        !          1499: 
        !          1500:     reg_68k = map->x86_cache_reg[x86r];
        !          1501: 
        !          1502:     if (reg_68k == -1)
        !          1503:        return;
        !          1504: 
        !          1505:     if (map->x86_cr_type[x86r] == 1) {
        !          1506:        map->dreg_map[reg_68k] = -1;
        !          1507:        sync_reg(map, x86r, regs.regs + reg_68k, map->x86_const_offset[x86r],
        !          1508:                 map->x86_dirty[x86r], may_clobber);
        !          1509:     } else {
        !          1510:        map->areg_map[reg_68k] = -1;
        !          1511:        sync_reg(map, x86r, regs.regs + 8 + reg_68k,  map->x86_const_offset[x86r],
        !          1512:                 map->x86_dirty[x86r], may_clobber);
        !          1513:     }
        !          1514:     map->x86_dirty[x86r] = 0;
        !          1515:     map->x86_cache_reg[x86r] = -1;
        !          1516:     map->x86_const_offset[x86r] = 0;
        !          1517:     map->x86_verified[x86r] = 0;
        !          1518:     map->x86_byteorder[x86r] = BO_NORMAL;
        !          1519: }
        !          1520: 
        !          1521: static int get_free_x86_register(struct register_mapping *map,
        !          1522:                                 int preferred_mask)
        !          1523: {
        !          1524:     int cnt;
        !          1525:     for (cnt = 0; cnt < 24; cnt++) {
        !          1526:        int x86r = cnt & 7;
        !          1527:        /* In the first two passes, try to get one of the preferred regs */
        !          1528:        if (cnt < 16 && ((1 << x86r) & preferred_mask) == 0)
        !          1529:            continue;
        !          1530:        /* In the first pass, don't discard any registers from the cache */
        !          1531:        if (cnt < 8 && map->x86_cache_reg[x86r] != -1)
        !          1532:            continue;
        !          1533:        /* Never use locked registers */
        !          1534:        if (map->x86_users[x86r] > 0)
        !          1535:            continue;
        !          1536: 
        !          1537:        remove_x86r_from_cache(map, x86r, 1);
        !          1538:        map->x86_dirty[x86r] = 0;
        !          1539:        map->x86_cache_reg[x86r] = -1;
        !          1540:        map->x86_const_offset[x86r] = 0;
        !          1541:        map->x86_verified[x86r] = 0;
        !          1542:        map->x86_byteorder[x86r] = BO_NORMAL;
        !          1543:        return x86r;
        !          1544:     }
        !          1545:     printf("Out of registers!\n");
        !          1546:     return -1;
        !          1547: }
        !          1548: 
        !          1549: static int get_typed_x86_register(struct register_mapping *map,
        !          1550:                                  int preferred_mask)
        !          1551: {
        !          1552:     int cnt;
        !          1553:     for (cnt = 0; cnt < 16; cnt++) {
        !          1554:        int x86r = cnt & 7;
        !          1555:        /* Get one of the preferred regs */
        !          1556:        if (((1 << x86r) & preferred_mask) == 0)
        !          1557:            continue;
        !          1558:        /* In the first pass, don't discard any registers from the cache */
        !          1559:        if (cnt < 8 && map->x86_cache_reg[x86r] != -1)
        !          1560:            continue;
        !          1561:        /* Never use locked registers */
        !          1562:        if (map->x86_users[x86r] > 0)
        !          1563:            continue;
        !          1564: 
        !          1565:        remove_x86r_from_cache(map, x86r, 1);
        !          1566:        map->x86_dirty[x86r] = 0;
        !          1567:        map->x86_cache_reg[x86r] = -1;
        !          1568:        map->x86_const_offset[x86r] = 0;
        !          1569:        map->x86_verified[x86r] = 0;
        !          1570:        map->x86_byteorder[x86r] = BO_NORMAL;
        !          1571:        return x86r;
        !          1572:     }
        !          1573:     printf("Out of type registers!\n");
        !          1574:     return -1;
        !          1575: }
        !          1576: 
        !          1577: static void compile_unlock_reg(struct register_mapping *map, int reg)
        !          1578: {
        !          1579:     if (reg >= 0) {
        !          1580:        if (--map->x86_users[reg] == 0)
        !          1581:            map->x86_locked[reg] = 0;
        !          1582: 
        !          1583:     }
        !          1584: }
        !          1585: 
        !          1586: static void lock_reg(struct register_mapping *map, int x86r, int lock_type)
        !          1587: {
        !          1588: #if 1
        !          1589:     switch (map->x86_locked[x86r]) {
        !          1590:      case 0:
        !          1591:        if (map->x86_users[x86r] != 0)
        !          1592:            printf("Users for an unlocked reg!\n");
        !          1593:        break;
        !          1594:      case 1:
        !          1595:        if (lock_type == 2)
        !          1596:            printf("Locking shared reg for exclusive use!\n");
        !          1597:        break;
        !          1598:      case 2:
        !          1599:        printf("Locking exclusive reg!\n");
        !          1600:        break;
        !          1601:      default:
        !          1602:        printf("Unknown lock?\n");
        !          1603:        break;
        !          1604:     }
        !          1605: #endif
        !          1606:     map->x86_locked[x86r] = lock_type;
        !          1607:     map->x86_users[x86r]++;
        !          1608: }
        !          1609: 
        !          1610: static int get_and_lock_68k_reg(struct register_mapping *map, int reg, int is_dreg,
        !          1611:                                int preferred, int no_offset, int lock_type)
        !          1612: {
        !          1613:     int x86r;
        !          1614:     int *regmap;
        !          1615:     uae_u32 *reghome;
        !          1616:     uae_u32 const_off = 0;
        !          1617: 
        !          1618:     if (reg < 0 || reg > 7) {
        !          1619:        printf("Mad compiler disease\n");
        !          1620:        return 0;
        !          1621:     }
        !          1622: 
        !          1623:     if (is_dreg)
        !          1624:        regmap = map->dreg_map, reghome = regs.regs;
        !          1625:     else
        !          1626:        regmap = map->areg_map, reghome = regs.regs + 8;
        !          1627: 
        !          1628:     if (preferred == 0)
        !          1629:        preferred = ALL_X86_REGS;
        !          1630: 
        !          1631:     x86r = regmap[reg];
        !          1632:     if (x86r == -1) {
        !          1633:        x86r = get_free_x86_register(map, preferred);
        !          1634:        assemble(0x8B); assemble(0x05 + (x86r << 3)); /* movl regs.d[reg],x86r */
        !          1635:        assemble_long(reghome + reg);
        !          1636:        map->x86_cache_reg[x86r] = reg;
        !          1637:        map->x86_cr_type[x86r] = is_dreg;
        !          1638:        map->x86_const_offset[x86r] = 0;
        !          1639:        map->x86_dirty[x86r] = 0;
        !          1640:        map->x86_verified[x86r] = 0;
        !          1641:        map->x86_byteorder[x86r] = BO_NORMAL;
        !          1642:        regmap[reg] = x86r;
        !          1643:     } else {
        !          1644:        const_off = map->x86_const_offset[x86r];
        !          1645: 
        !          1646:        if (map->x86_locked[x86r] == 2
        !          1647:            || (map->x86_locked[x86r] == 1 && (lock_type == 2 || (const_off != 0 && no_offset))))
        !          1648:        {
        !          1649:            int newr;
        !          1650:            int old_dirty = 0;
        !          1651:            int old_verified;
        !          1652:            int old_bo;
        !          1653: 
        !          1654:            newr = get_free_x86_register(map, preferred);
        !          1655:            if (const_off == 0) {
        !          1656:                compile_move_reg_reg(newr, x86r, sz_long);
        !          1657:            } else {
        !          1658:                compile_force_byteorder(map, x86r, BO_NORMAL, 1);
        !          1659:                compile_lea_reg_with_offset(newr, x86r, const_off);
        !          1660:                old_dirty = 1;
        !          1661:                const_off = 0;
        !          1662:            }
        !          1663:            /* Remove old reg from cache... */
        !          1664:            map->x86_cache_reg[x86r] = -1;
        !          1665:            map->x86_cr_type[x86r] = is_dreg;
        !          1666:            map->x86_const_offset[x86r] = 0;
        !          1667:            old_dirty |= map->x86_dirty[x86r];
        !          1668:            old_verified = map->x86_verified[x86r];
        !          1669:            old_bo = map->x86_byteorder[x86r];
        !          1670:            map->x86_verified[x86r] = 0;
        !          1671:            map->x86_dirty[x86r] = 0;
        !          1672:            x86r = newr;
        !          1673:            /* ... and make the new one the cache register */
        !          1674:            map->x86_cache_reg[x86r] = reg;
        !          1675:            map->x86_cr_type[x86r] = is_dreg;
        !          1676:            map->x86_const_offset[x86r] = 0;
        !          1677:            map->x86_dirty[x86r] = old_dirty;
        !          1678:            map->x86_verified[x86r] = old_verified;
        !          1679:            map->x86_byteorder[x86r] = old_bo;
        !          1680:            regmap[reg] = x86r;
        !          1681:        }
        !          1682:     }
        !          1683:     if (no_offset && const_off != 0) {
        !          1684:        if (map->x86_locked[x86r] != 0)
        !          1685:            printf("modifying locked reg\n");
        !          1686:        compile_force_byteorder(map, x86r, BO_NORMAL, 1);
        !          1687:        compile_lea_reg_with_offset(x86r, x86r, map->x86_const_offset[x86r]);
        !          1688:        map->x86_const_offset[x86r] = 0;
        !          1689:        map->x86_dirty[x86r] = 1;
        !          1690:     }
        !          1691:     lock_reg(map, x86r, lock_type);
        !          1692:     return x86r;
        !          1693: }
        !          1694: 
        !          1695: /*
        !          1696:  * Move a constant to a register. Don't do anything if we already have a
        !          1697:  * register, even if it is offset by a constant
        !          1698:  */
        !          1699: 
        !          1700: static int compile_force_const_reg(struct register_mapping *map, int x86r,
        !          1701:                                   uae_u32 *offs, int desired)
        !          1702: {
        !          1703:     int newr = x86r;
        !          1704: 
        !          1705:     if (newr == -2) {
        !          1706:        if (desired == 0)
        !          1707:            newr = get_free_x86_register(map, ALL_X86_REGS);
        !          1708:        else
        !          1709:            newr = get_typed_x86_register(map, desired);
        !          1710: 
        !          1711:        assemble(0xB8 + newr);
        !          1712:        assemble_ulong(*offs);
        !          1713:        *offs = 0;
        !          1714:     }
        !          1715:     map->x86_users[newr]++;
        !          1716:     return newr;
        !          1717: }
        !          1718: 
        !          1719: static void compile_extend_long(struct register_mapping *map, int x86r,
        !          1720:                                wordsizes size)
        !          1721: {
        !          1722:     if (x86r < 0) {
        !          1723:        printf("Bad reg in extend_long\n");
        !          1724:        return;
        !          1725:     }
        !          1726: 
        !          1727:     compile_force_byteorder(map, x86r, BO_NORMAL, 1);
        !          1728: 
        !          1729:     if (size != sz_long) {
        !          1730:        if (x86r == r_EAX && size == sz_word) {
        !          1731:            assemble(0x98); /* cwtl */
        !          1732:        } else {
        !          1733:            assemble(0x0F);
        !          1734:            if (size == sz_byte) {
        !          1735:                assemble(0xBE);
        !          1736:            } else {
        !          1737:                assemble(0xBF);
        !          1738:            }
        !          1739:            assemble(0xC0 + x86r*9);
        !          1740:        }
        !          1741:     }
        !          1742: }
        !          1743: 
        !          1744: struct ea_info {
        !          1745:     int reg;
        !          1746:     amodes mode;
        !          1747:     wordsizes size;
        !          1748:     int address_reg;    /* The x86 reg holding the address, or -1 if ea doesn't refer to memory
        !          1749:                         * -2 if it refers to memory, but only with a constant address */
        !          1750:     uae_u32 addr_const_off; /* Constant offset to the address */
        !          1751:     int data_reg;         /* The x86 reg that holds the data. -1 if data is not present yet.
        !          1752:                           * -2 if data is constant */
        !          1753:     uae_u32 data_const_off;
        !          1754:     int flags;            /* Extra info. Contains the dp field of d8r modes */
        !          1755:     int purpose;
        !          1756: };
        !          1757: 
        !          1758: static void init_eainfo(struct ea_info *eai)
        !          1759: {
        !          1760:     eai->address_reg = -1;
        !          1761:     eai->addr_const_off = 0;
        !          1762:     eai->data_reg = -1;
        !          1763:     eai->data_const_off = 0;
        !          1764: }
        !          1765: 
        !          1766: struct insn_reg_needs {
        !          1767:     int checkpoint_no;
        !          1768:     int dreg_needed[8], areg_needed[8];
        !          1769:     int dreg_mask[8], areg_mask[8];
        !          1770: };
        !          1771: 
        !          1772: /*
        !          1773:  * This structure holds information about predec/postinc addressing modes.
        !          1774:  */
        !          1775: 
        !          1776: struct pid_undo {
        !          1777:     int used;
        !          1778:     int x86r[2];
        !          1779:     int m68kr[2];
        !          1780:     int dirty[2];
        !          1781:     int offs[2];
        !          1782: };
        !          1783: 
        !          1784: static void add_undo(struct pid_undo *pud, int x86r, int m68kr, int offs,
        !          1785:                     int dirty)
        !          1786: {
        !          1787:     int i;
        !          1788:     for (i = 0; i < pud->used; i++)
        !          1789:        if (pud->m68kr[i] == m68kr)
        !          1790:            return;
        !          1791:     pud->m68kr[i] = m68kr;
        !          1792:     pud->x86r[i] = x86r;
        !          1793:     pud->offs[i] = offs;
        !          1794:     pud->dirty[i] = dirty;
        !          1795:     pud->used++;
        !          1796: }
        !          1797: 
        !          1798: /*
        !          1799:  * Lock previous contents of address registers used in predec/postinc modes
        !          1800:  * for generate_possible_exit().
        !          1801:  */
        !          1802: 
        !          1803: static void compile_prepare_undo(struct register_mapping *map, amodes mode,
        !          1804:                              int reg, struct pid_undo *pud)
        !          1805: {
        !          1806:     int x86r;
        !          1807: 
        !          1808:     switch(mode){
        !          1809:      default:
        !          1810:        break;
        !          1811: 
        !          1812:      case Apdi:
        !          1813:        x86r = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0, 1);
        !          1814:        /* This saves recording the byteorder in the pud structure, and we'll
        !          1815:         * need it in normal byteorder anyway */
        !          1816:        compile_force_byteorder(map, x86r, BO_NORMAL, 0);
        !          1817:        /*
        !          1818:         * Add this reg with its current offset to the undo buffer.
        !          1819:         * Since we have locked it, we are certain that it will not be
        !          1820:         * modified.
        !          1821:         */
        !          1822:        add_undo(pud, x86r, reg, map->x86_const_offset[x86r], map->x86_dirty[x86r]);
        !          1823:        break;
        !          1824: 
        !          1825:      case Aipi:
        !          1826:        x86r = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0, 1);
        !          1827:        compile_force_byteorder(map, x86r, BO_NORMAL, 0);
        !          1828:        add_undo(pud, x86r, reg, map->x86_const_offset[x86r], map->x86_dirty[x86r]);
        !          1829:        break;
        !          1830:     }
        !          1831: }
        !          1832: 
        !          1833: /*
        !          1834:  * Load all the registers absolutely needed to calculate and verify thea
        !          1835:  * address. Load other registers if convenient.
        !          1836:  * This contains a fair amount of magic to get the register cache working right.
        !          1837:  */
        !          1838: 
        !          1839: static void compile_prepareea(struct register_mapping *map, amodes mode,
        !          1840:                              int reg, wordsizes size, uae_u8 **pcpp, uaecptr pca,
        !          1841:                              struct ea_info *eainf, int eaino, int ea_purpose,
        !          1842:                              int pidmult)
        !          1843: {
        !          1844:     struct ea_info *eai = eainf + eaino;
        !          1845:     int pdival = size == sz_byte && reg != 7 ? 1 : size == sz_long ? 4 : 2;
        !          1846:     uae_u8 *p = *pcpp;
        !          1847:     uae_u16 dp;
        !          1848:     int r;
        !          1849:     int x86r, tmpr;
        !          1850: 
        !          1851:     pdival *= pidmult;
        !          1852: 
        !          1853:     init_eainfo(eai);
        !          1854:     eai->mode = mode;
        !          1855:     eai->size = size;
        !          1856:     eai->reg = reg;
        !          1857: 
        !          1858:     switch(mode){
        !          1859:      case Dreg:
        !          1860:      case Areg:
        !          1861:        break;
        !          1862: 
        !          1863:      case Ad16:
        !          1864:        eai->addr_const_off = (uae_s16)do_get_mem_word((uae_u16 *)p);
        !          1865:        (*pcpp) += 2; p += 2;
        !          1866:        x86r = eai->address_reg = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0, 1);
        !          1867:        compile_force_byteorder(map, x86r, BO_NORMAL, 0);
        !          1868:        eai->addr_const_off += map->x86_const_offset[x86r];
        !          1869:        break;
        !          1870: 
        !          1871:      case Aind:
        !          1872:        x86r = eai->address_reg = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0, 1);
        !          1873:        compile_force_byteorder(map, x86r, BO_NORMAL, 0);
        !          1874:        eai->addr_const_off = map->x86_const_offset[x86r];
        !          1875:        break;
        !          1876: 
        !          1877:      case Apdi:
        !          1878:        x86r = eai->address_reg = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0, 1);
        !          1879:        compile_force_byteorder(map, x86r, BO_NORMAL, 0);
        !          1880:        map->x86_const_offset[x86r] -= pdival;
        !          1881:        eai->addr_const_off = map->x86_const_offset[x86r];
        !          1882:        break;
        !          1883: 
        !          1884:      case Aipi:
        !          1885:        x86r = eai->address_reg = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0, 1);
        !          1886:        compile_force_byteorder(map, x86r, BO_NORMAL, 0);
        !          1887:        eai->addr_const_off = map->x86_const_offset[x86r];
        !          1888:        map->x86_const_offset[x86r] += pdival;
        !          1889:        break;
        !          1890: 
        !          1891:      case Ad8r:
        !          1892:        dp = (uae_s16)do_get_mem_word((uae_u16 *)p);
        !          1893:        r = (dp & 0x7000) >> 12;
        !          1894:        (*pcpp) += 2; p += 2;
        !          1895: 
        !          1896:        tmpr = get_and_lock_68k_reg(map, reg, 0, ADDRESS_X86_REGS, 0, 1);
        !          1897:        compile_force_byteorder(map, tmpr, BO_NORMAL, 0);
        !          1898:        eai->addr_const_off = map->x86_const_offset[tmpr] + (uae_s8)dp;
        !          1899: 
        !          1900:        if (dp & 0x800) {
        !          1901:            x86r = get_and_lock_68k_reg(map, r, dp & 0x8000 ? 0 : 1, ADDRESS_X86_REGS, 0, 2);
        !          1902:            remove_x86r_from_cache(map, x86r, 0);
        !          1903:            compile_force_byteorder(map, x86r, BO_NORMAL, 0);
        !          1904:            eai->addr_const_off += map->x86_const_offset[x86r];
        !          1905:        } else {
        !          1906:            x86r = get_and_lock_68k_reg(map, r, dp & 0x8000 ? 0 : 1, ADDRESS_X86_REGS, 1, 2);
        !          1907:            remove_x86r_from_cache(map, x86r, 0);
        !          1908:            compile_force_byteorder(map, x86r, BO_NORMAL, 0);
        !          1909:        }
        !          1910:        eai->address_reg = x86r;
        !          1911: 
        !          1912:        r = (dp & 0x7000) >> 12;
        !          1913: 
        !          1914:        if (dp & 0x800) {
        !          1915:            if (eai->addr_const_off == 0) {
        !          1916:                assemble(0x03); assemble(0xC0 + tmpr + x86r*8); /* addl basereg,addrreg */
        !          1917:            } else if ((uae_s32)eai->addr_const_off >= -128 && (uae_s32)eai->addr_const_off <= 127) {
        !          1918:                assemble(0x8D);
        !          1919:                assemble(0x44 + x86r*8); /* leal disp8(dispreg,basereg),dispreg */
        !          1920:                assemble(x86r*8 + tmpr);
        !          1921:                assemble(eai->addr_const_off);
        !          1922:            } else {
        !          1923:                assemble(0x8D);
        !          1924:                assemble(0x84 + x86r*8); /* leal disp32(dispreg,basereg),dispreg */
        !          1925:                assemble(x86r*8 + tmpr);
        !          1926:                assemble_ulong(eai->addr_const_off);
        !          1927:            }
        !          1928:            eai->addr_const_off = 0;
        !          1929:        } else {
        !          1930:            assemble(0x0F); assemble(0xBF);
        !          1931:            assemble(0xC0 + x86r*9); /* movswl dispreg,addrreg */
        !          1932:            assemble(0x03); assemble(0xC0 + tmpr + x86r*8); /* addl basereg,addrreg */
        !          1933:        }
        !          1934:        compile_unlock_reg(map, tmpr);
        !          1935:        break;
        !          1936: 
        !          1937:      case PC8r:
        !          1938:        dp = (uae_s16)do_get_mem_word((uae_u16 *)p);
        !          1939:        (*pcpp) += 2; p += 2;
        !          1940:        r = (dp & 0x7000) >> 12;
        !          1941:        eai->addr_const_off = pca + (uae_s8)dp;
        !          1942:        if (dp & 0x800) {
        !          1943:            x86r = get_and_lock_68k_reg(map, r, dp & 0x8000 ? 0 : 1, ADDRESS_X86_REGS, 0, 1);
        !          1944:            remove_x86r_from_cache(map, x86r, 0);
        !          1945:            compile_force_byteorder(map, x86r, BO_NORMAL, 0);
        !          1946:            eai->addr_const_off += map->x86_const_offset[x86r];
        !          1947:        } else {
        !          1948:            x86r = get_and_lock_68k_reg(map, r, dp & 0x8000 ? 0 : 1, ADDRESS_X86_REGS, 1, 2);
        !          1949:            remove_x86r_from_cache(map, x86r, 0);
        !          1950:            compile_force_byteorder(map, x86r, BO_NORMAL, 0);
        !          1951: 
        !          1952:            assemble(0x0F); assemble(0xBF);
        !          1953:            assemble(0xC0 + x86r*9); /* movswl dispreg,addrreg */
        !          1954:        }
        !          1955:        eai->address_reg = x86r;
        !          1956:        break;
        !          1957: 
        !          1958:      case PC16:
        !          1959:        eai->addr_const_off = pca + (uae_s16)do_get_mem_word((uae_u16 *)p);
        !          1960:        eai->address_reg = -2;
        !          1961:        (*pcpp) += 2; p += 2;
        !          1962:        break;
        !          1963: 
        !          1964:      case absw:
        !          1965:        eai->addr_const_off = (uae_s16)do_get_mem_word((uae_u16 *)p);
        !          1966:        eai->address_reg = -2;
        !          1967:        (*pcpp) += 2; p += 2;
        !          1968:        break;
        !          1969: 
        !          1970:      case absl:
        !          1971:        eai->addr_const_off = (uae_s32)do_get_mem_long((uae_u32 *)p);
        !          1972:        eai->address_reg = -2;
        !          1973:        (*pcpp) += 4; p += 4;
        !          1974:        break;
        !          1975: 
        !          1976:      case imm:
        !          1977:        if (size == sz_long)
        !          1978:            goto imm2_const;
        !          1979:        if (size == sz_word)
        !          1980:            goto imm1_const;
        !          1981: 
        !          1982:        /* fall through */
        !          1983:      case imm0:
        !          1984:        eai->data_const_off = (uae_s8)*(p+1);
        !          1985:        eai->data_reg = -2;
        !          1986:        (*pcpp) += 2; p += 2;
        !          1987:        break;
        !          1988: 
        !          1989:      case imm1:
        !          1990:        imm1_const:
        !          1991:        eai->data_const_off = (uae_s16)do_get_mem_word((uae_u16 *)p);
        !          1992:        eai->data_reg = -2;
        !          1993:        (*pcpp) += 2; p += 2;
        !          1994:        break;
        !          1995: 
        !          1996:      case imm2:
        !          1997:        imm2_const:
        !          1998:        eai->data_const_off = (uae_s32)do_get_mem_long((uae_u32 *)p);
        !          1999:        eai->data_reg = -2;
        !          2000:        (*pcpp) += 4; p += 4;
        !          2001:        break;
        !          2002: 
        !          2003:      case immi:
        !          2004:        eai->data_const_off = (uae_s8)reg;
        !          2005:        eai->data_reg = -2;
        !          2006:        break;
        !          2007: 
        !          2008:      default:
        !          2009:        break;
        !          2010:     }
        !          2011:     eai->purpose = ea_purpose;
        !          2012: }
        !          2013: 
        !          2014: static void compile_get_excl_lock(struct register_mapping *map, struct ea_info *eai)
        !          2015: {
        !          2016:     int x86r = eai->data_reg;
        !          2017: 
        !          2018:     if (x86r >= 0 && map->x86_locked[x86r] == 1) {
        !          2019:        int newr;
        !          2020:        if (eai->size == sz_byte)
        !          2021:            newr = get_typed_x86_register(map, DATA_X86_REGS);
        !          2022:        else
        !          2023:            newr = get_free_x86_register(map, ALL_X86_REGS);
        !          2024: 
        !          2025:        compile_move_reg_reg(newr, x86r, sz_long);
        !          2026:        eai->data_reg = newr;
        !          2027:        lock_reg(map, eai->data_reg, 2);
        !          2028:     }
        !          2029: }
        !          2030: 
        !          2031: /*
        !          2032:  * Some functions to assemble some 386 opcodes which have a similar
        !          2033:  * structure (ADD, AND, OR, etc.). These take source and destination
        !          2034:  * addressing modes, check their validity and assemble a complete
        !          2035:  * 386 instruction.
        !          2036:  */
        !          2037: 
        !          2038: STATIC_INLINE int rmop_long(struct ea_info *eai)
        !          2039: {
        !          2040:     if (eai->data_reg == -2)
        !          2041:        printf("rmop for const\n");
        !          2042:     else if (eai->data_reg == -1) {
        !          2043:        if (eai->address_reg == -2)
        !          2044:            return 5;
        !          2045:        if (eai->address_reg == -1) {
        !          2046:            /* This must be a 68k register in its home location */
        !          2047:            return 5;
        !          2048:        }
        !          2049: #if 0 /* We need to add address_space... */
        !          2050:        if (eai->addr_const_off == 0 && eai->address_reg != r_EBP) {
        !          2051:            return eai->address_reg;
        !          2052:        }
        !          2053:        else if ((uae_s32)eai->addr_const_off >= -128 && (uae_s32)eai->addr_const_off <= 127) {
        !          2054:            return eai->address_reg | 0x40;
        !          2055:        }
        !          2056: #endif
        !          2057:        return eai->address_reg | 0x80;
        !          2058:     } else {
        !          2059:        if (eai->size == sz_byte && ((1 << eai->data_reg) & DATA_X86_REGS) == 0)
        !          2060:            printf("wrong type reg in rmop\n");
        !          2061:        if (eai->data_const_off != 0)
        !          2062:            printf("data_const_off in rmop\n");
        !          2063:        return 0xC0 + eai->data_reg;
        !          2064:     }
        !          2065:     return 0;
        !          2066: }
        !          2067: 
        !          2068: STATIC_INLINE int rmop_short(struct ea_info *eai)
        !          2069: {
        !          2070:     if (eai->data_reg == -2)
        !          2071:        printf("rmop_short for const\n");
        !          2072:     else if (eai->data_reg == -1) {
        !          2073:        printf("rmop_short for mem\n");
        !          2074:     } else {
        !          2075:        if (eai->size == sz_byte && ((1 << eai->data_reg) & DATA_X86_REGS) == 0)
        !          2076:            printf("wrong type reg in rmop_short\n");
        !          2077:        if (eai->data_const_off != 0)
        !          2078:            printf("data_const_off in rmop_short\n");
        !          2079:        return eai->data_reg*8;
        !          2080:     }
        !          2081:     return 0;
        !          2082: }
        !          2083: 
        !          2084: STATIC_INLINE void rmop_finalize(struct ea_info *eai)
        !          2085: {
        !          2086:     if (eai->data_reg == -2)
        !          2087:        assemble_ulong(eai->data_const_off);
        !          2088:     else if (eai->data_reg == -1) {
        !          2089:        if (eai->address_reg == -2)
        !          2090:            /* Constant address */
        !          2091:            assemble_long(address_space + (uae_s32)eai->addr_const_off);
        !          2092:        else if (eai->address_reg == -1) {
        !          2093:            /* Register in its home location */
        !          2094:            if (eai->mode == Areg)
        !          2095:                assemble_long(regs.regs + 8  + eai->reg);
        !          2096:            else
        !          2097:                assemble_long(regs.regs + eai->reg);
        !          2098:        } else {
        !          2099: #if 0
        !          2100:            /* Indirect address with offset */
        !          2101:            if ((uae_s32)eai->addr_const_off >= -128 && (uae_s32)eai->addr_const_off <= 127) {
        !          2102:            }
        !          2103: #endif
        !          2104:            assemble_long(address_space + (uae_s32)eai->addr_const_off);
        !          2105:        }
        !          2106:     }
        !          2107: }
        !          2108: 
        !          2109: static void compile_eas(struct register_mapping *map, struct ea_info *eainf, int eaino_s, int eaino_d,
        !          2110:                        int optype)
        !          2111: {
        !          2112:     struct ea_info *eais = eainf + eaino_s;
        !          2113:     struct ea_info *eaid = eainf + eaino_d;
        !          2114:     int szflag = eais->size == sz_byte ? 0 : 1;
        !          2115:     int swapflag = 0;
        !          2116:     int opcode;
        !          2117: 
        !          2118:     if (eais->data_reg == -1) {
        !          2119:        compile_force_byteorder(map, eais->address_reg, BO_NORMAL, 0);
        !          2120:        eais = eainf + eaino_d;
        !          2121:        eaid = eainf + eaino_s;
        !          2122:        swapflag = 1;
        !          2123:     }
        !          2124:     if (eais->data_reg == -1) {
        !          2125:        compile_force_byteorder(map, eais->address_reg, BO_NORMAL, 0);
        !          2126:     }
        !          2127: 
        !          2128:     if (eais->size == sz_word)
        !          2129:        assemble(0x66);
        !          2130: 
        !          2131:     if (eais->data_reg == -2) {
        !          2132:        assemble(0x80+szflag);
        !          2133:        assemble(8*optype | rmop_long(eaid));
        !          2134:        rmop_finalize(eaid);
        !          2135:        switch(eais->size) {
        !          2136:         case sz_byte: assemble(eais->data_const_off); break;
        !          2137:         case sz_word: assemble_uword(eais->data_const_off); break;
        !          2138:         case sz_long: assemble_ulong(eais->data_const_off); break;
        !          2139:        }
        !          2140:     } else {
        !          2141:        assemble(8*optype | szflag | 2*swapflag);
        !          2142:        assemble(rmop_long(eaid) | rmop_short(eais));
        !          2143:        rmop_finalize(eaid);
        !          2144:     }
        !          2145: }
        !          2146: 
        !          2147: static void compile_fetchmem(struct register_mapping *map, struct ea_info *eai)
        !          2148: {
        !          2149:     int x86r;
        !          2150:     if (eai->size == sz_byte)
        !          2151:        x86r = get_typed_x86_register(map, DATA_X86_REGS);
        !          2152:     else
        !          2153:        x86r = get_free_x86_register(map, ALL_X86_REGS);
        !          2154: 
        !          2155:     lock_reg(map, x86r, 2);
        !          2156:     compile_force_byteorder(map, eai->address_reg, BO_NORMAL, 0);
        !          2157:     compile_move_reg_from_mem_regoffs(x86r, eai->address_reg,
        !          2158:                                      (uae_u32)(eai->addr_const_off + address_space),
        !          2159:                                      eai->size);
        !          2160:     map->x86_verified[x86r] = 0;
        !          2161:     switch (eai->size) {
        !          2162:      case sz_byte: map->x86_byteorder[x86r] = BO_NORMAL; break;
        !          2163:      case sz_word: map->x86_byteorder[x86r] = BO_SWAPPED_WORD; break;
        !          2164:      case sz_long: map->x86_byteorder[x86r] = BO_SWAPPED_LONG; break;
        !          2165:     }
        !          2166:     eai->data_reg = x86r;
        !          2167:     eai->data_const_off = 0;
        !          2168: }
        !          2169: 
        !          2170: static void compile_fetchimm(struct register_mapping *map, struct ea_info *eai, int byteorder)
        !          2171: {
        !          2172:     int x86r;
        !          2173:     if (eai->size == sz_byte)
        !          2174:        x86r = get_typed_x86_register(map, DATA_X86_REGS);
        !          2175:     else
        !          2176:        x86r = get_free_x86_register(map, ALL_X86_REGS);
        !          2177: 
        !          2178:     switch (byteorder) {
        !          2179:      case BO_SWAPPED_LONG:
        !          2180:        eai->data_const_off = (((eai->data_const_off & 0xFF000000) >> 24)
        !          2181:                               | ((eai->data_const_off & 0xFF0000) >> 8)
        !          2182:                               | ((eai->data_const_off & 0xFF00) << 8)
        !          2183:                               | ((eai->data_const_off & 0xFF) << 24));
        !          2184:        break;
        !          2185:      case BO_SWAPPED_WORD:
        !          2186:        eai->data_const_off = (((eai->data_const_off & 0xFF00) >> 8)
        !          2187:                               | ((eai->data_const_off & 0xFF) << 8)
        !          2188:                               | (eai->data_const_off & 0xFFFF0000));
        !          2189:        break;
        !          2190:      case BO_NORMAL:
        !          2191:        break;
        !          2192:     }
        !          2193:     lock_reg(map, x86r, 2);
        !          2194:     map->x86_byteorder[x86r] = byteorder; map->x86_verified[x86r] = 0;
        !          2195: 
        !          2196:     switch (eai->size) {
        !          2197:      case sz_byte: assemble(0xC6); assemble(0xC0 + x86r); assemble(eai->data_const_off); break;
        !          2198:      case sz_word: assemble(0x66); assemble(0xC7); assemble(0xC0 + x86r); assemble_uword(eai->data_const_off); break;
        !          2199:      case sz_long: assemble(0xC7); assemble(0xC0 + x86r); assemble_ulong(eai->data_const_off); break;
        !          2200:     }
        !          2201:     eai->data_reg = x86r;
        !          2202:     eai->data_const_off = 0;
        !          2203: }
        !          2204: 
        !          2205: /*
        !          2206:  * 1: reg
        !          2207:  * 2: mem
        !          2208:  * 4: imm
        !          2209:  */
        !          2210: 
        !          2211: static int binop_alternatives[] = {
        !          2212:     7, 1,
        !          2213:     5, 3,
        !          2214:     0, 0
        !          2215: };
        !          2216: 
        !          2217: static int binop_worda_alternatives[] = {
        !          2218:     1, 3,
        !          2219:     0, 0
        !          2220: };
        !          2221: 
        !          2222: static int regonly_alternatives[] = {
        !          2223:     1, 1,
        !          2224:     0, 0
        !          2225: };
        !          2226: 
        !          2227: static void compile_loadeas(struct register_mapping *map, struct ea_info *eainf,
        !          2228:                           int eaino_s, int eaino_d, int *alternatives,
        !          2229:                           int scramble_poss, int load_dest)
        !          2230: {
        !          2231:     struct ea_info *eais = eainf + eaino_s;
        !          2232:     struct ea_info *eaid = eainf + eaino_d;
        !          2233:     int scrambled_bo = eaid->size == sz_long ? BO_SWAPPED_LONG : eaid->size == sz_word ? BO_SWAPPED_WORD : BO_NORMAL;
        !          2234:     int i, scrambled = 0;
        !          2235:     int best = 0;
        !          2236:     int bestcost = -1;
        !          2237:     int *ap;
        !          2238:     uae_u32 *sregp = NULL, *dregp = NULL;
        !          2239:     int screg = -1, dcreg = -1;
        !          2240:     int stype = -1, dtype = -1;
        !          2241:     int asrc, adst;
        !          2242:     int regprefs = eais->size == sz_byte ? DATA_X86_REGS : 0;
        !          2243: 
        !          2244:     if (eais->mode == Dreg) {
        !          2245:        stype = 0;
        !          2246:        screg = map->dreg_map[eais->reg];
        !          2247:        if (screg == -1)
        !          2248:            sregp = regs.regs + eais->reg;
        !          2249:     } else if (eais->mode == Areg) {
        !          2250:        stype = 0;
        !          2251:        screg = map->areg_map[eais->reg];
        !          2252:        if (screg == -1)
        !          2253:            sregp = regs.regs + 8 + eais->reg;
        !          2254:     } else if (eais->data_reg == -2) {
        !          2255:        stype = -2;
        !          2256:     }
        !          2257: 
        !          2258:     if (eaid->mode == Dreg) {
        !          2259:        dtype = 0;
        !          2260:        dcreg = map->dreg_map[eaid->reg];
        !          2261:        if (dcreg == -1)
        !          2262:            dregp = regs.regs + eaid->reg;
        !          2263:     } else if (eaid->mode == Areg) {
        !          2264:        dtype = 0;
        !          2265:        dcreg = map->areg_map[eaid->reg];
        !          2266:        if (dcreg == -1)
        !          2267:            dregp = regs.regs + 8 + eaid->reg;
        !          2268:     } else if (eaid->data_reg == -2) {
        !          2269:        dtype = -2;
        !          2270:     }
        !          2271: 
        !          2272:     ap = alternatives;
        !          2273: 
        !          2274:     for (i = 0;; i++) {
        !          2275:        int cost = 0;
        !          2276: 
        !          2277:        asrc = *ap++;
        !          2278:        if (asrc == 0)
        !          2279:            break;
        !          2280:        adst = *ap++;
        !          2281: 
        !          2282:        if (stype == -2 && (asrc & 4) == 0)
        !          2283:            cost++;
        !          2284:        else if (stype == -1 && ((asrc & 2) == 0 || (eais->size != sz_byte && !scramble_poss)))
        !          2285:            cost++;
        !          2286:        else if (stype == 0 && screg == -1 && (asrc & 2) == 0)
        !          2287:            cost++;
        !          2288: 
        !          2289:        if (dtype == -1 && ((adst & 2) == 0 || (eaid->size != sz_byte && !scramble_poss)))
        !          2290:            /* The !load_dest case isn't handled by the current code,
        !          2291:             * and it isn't desirable anyway. Use a different alternative
        !          2292:             */
        !          2293:            cost += load_dest ? 1 : 100;
        !          2294:        else if (dtype == 0 && dcreg == -1 && (adst & 2) == 0)
        !          2295:            cost++;
        !          2296: 
        !          2297:        if (bestcost == -1 || cost < bestcost) {
        !          2298:            bestcost = cost;
        !          2299:            best = i;
        !          2300:        }
        !          2301:     }
        !          2302: 
        !          2303:     asrc = alternatives[2*best];
        !          2304:     adst = alternatives[2*best+1];
        !          2305: 
        !          2306:     if (dtype == -1) {
        !          2307:        if (load_dest) {
        !          2308:            if ((adst & 2) == 0 || (eaid->size != sz_byte && !scramble_poss))
        !          2309:                compile_fetchmem(map, eaid);
        !          2310:        } else {
        !          2311:            if ((adst & 2) == 0) {
        !          2312:                printf("Not loading memory operand. Prepare to die.\n");
        !          2313:                if (eaid->size == sz_byte)
        !          2314:                    eaid->data_reg = get_typed_x86_register(map, DATA_X86_REGS);
        !          2315:                else
        !          2316:                    eaid->data_reg = get_free_x86_register(map, ALL_X86_REGS);
        !          2317:            }
        !          2318:        }
        !          2319:        /* Scrambled in both mem and reg cases */
        !          2320:        if (eaid->size != sz_byte && scramble_poss)
        !          2321:            scrambled = 1;
        !          2322:     } else {
        !          2323:        if (dcreg == -1 && !load_dest && (adst & 2) == 0 && eaid->size == sz_long) {
        !          2324:            /* We need a register, but we don't need to fetch the old data.
        !          2325:             * See storeea for some more code handling this case. This first
        !          2326:             * if statement could be eliminated, we would generate some
        !          2327:             * superfluous moves. This is an optimization. If it were not
        !          2328:             * done, the mem-mem-move warning could be commented in in
        !          2329:             * storeea. */
        !          2330:            if (eaid->size == sz_byte)
        !          2331:                eaid->data_reg = get_typed_x86_register(map, DATA_X86_REGS);
        !          2332:            else
        !          2333:                eaid->data_reg = get_free_x86_register(map, ALL_X86_REGS);
        !          2334:            eaid->data_const_off = 0;
        !          2335:        } else if ((dcreg == -1 && (adst & 2) == 0) || dcreg != -1) {
        !          2336:            int reg_bo;
        !          2337:            eaid->data_reg = get_and_lock_68k_reg(map, eaid->reg, eaid->mode == Dreg, regprefs, 1, 2);
        !          2338:            eaid->data_const_off = 0;
        !          2339: 
        !          2340:            reg_bo = map->x86_byteorder[eaid->data_reg];
        !          2341: 
        !          2342:            if (reg_bo != BO_NORMAL) {
        !          2343:                if (reg_bo != scrambled_bo)
        !          2344:                    compile_force_byteorder(map, eaid->data_reg, BO_NORMAL, 0);
        !          2345:                else if (scramble_poss)
        !          2346:                    scrambled = 1;
        !          2347:            }
        !          2348:        }
        !          2349:     }
        !          2350: 
        !          2351:     if (stype == -2) {
        !          2352:        /* @@@ may need to scramble imm, this is a workaround */
        !          2353:        if ((asrc & 4) == 0 || scrambled)
        !          2354:            compile_fetchimm(map, eais, scrambled ? scrambled_bo : BO_NORMAL);
        !          2355:     } else if (stype == -1) {
        !          2356:        if ((asrc & 2) == 0 || (eais->size != sz_byte && !scrambled))
        !          2357:            compile_fetchmem(map, eais);
        !          2358:     } else {
        !          2359:        if ((screg == -1 && (asrc & 2) == 0) || screg != -1) {
        !          2360:            eais->data_reg = get_and_lock_68k_reg(map, eais->reg, eais->mode == Dreg, regprefs, 1, 2);
        !          2361:            eais->data_const_off = 0;
        !          2362:        }
        !          2363:     }
        !          2364: 
        !          2365:     /* Optimization */
        !          2366:     if (scrambled && eais->data_reg >= 0 && !load_dest
        !          2367:        && map->x86_byteorder[eais->data_reg] == BO_NORMAL
        !          2368:        && eaid->size == sz_long && dtype == 0)
        !          2369:        scrambled = 0;
        !          2370: 
        !          2371:     if (regprefs != 0 && eais->data_reg >= 0 && ((1 << eais->data_reg) & regprefs) == 0) {
        !          2372:        int tmpr = get_typed_x86_register(map, regprefs);
        !          2373:        compile_move_reg_reg(tmpr, eais->data_reg, sz_long);
        !          2374:        eais->data_reg = tmpr;
        !          2375:     }
        !          2376: 
        !          2377:     if (regprefs != 0 && eaid->data_reg >= 0 && ((1 << eaid->data_reg) & regprefs) == 0) {
        !          2378:        int tmpr = get_typed_x86_register(map, regprefs);
        !          2379:        compile_move_reg_reg(tmpr, eaid->data_reg, sz_long);
        !          2380:        eaid->data_reg = tmpr;
        !          2381:     }
        !          2382: 
        !          2383:     /* Now set the byteorder once and for all (should already be correct for
        !          2384:      * most cases) */
        !          2385:     if (scrambled) {
        !          2386:        if (eaid->data_reg >= 0)
        !          2387:            compile_force_byteorder(map, eaid->data_reg, scrambled_bo, 0);
        !          2388:        if (eais->data_reg >= 0)
        !          2389:            compile_force_byteorder(map, eais->data_reg, scrambled_bo, 0);
        !          2390:     } else {
        !          2391:        if (eaid->data_reg >= 0)
        !          2392:            compile_force_byteorder(map, eaid->data_reg, BO_NORMAL, 0);
        !          2393:        if (eais->data_reg >= 0)
        !          2394:            compile_force_byteorder(map, eais->data_reg, BO_NORMAL, 0);
        !          2395:     }
        !          2396: }
        !          2397: 
        !          2398: static void compile_fetchea(struct register_mapping *map, struct ea_info *eainf,
        !          2399:                            int eaino, int asrc)
        !          2400: {
        !          2401:     struct ea_info *eais = eainf + eaino;
        !          2402:     int scrambled_bo = eais->size == sz_long ? BO_SWAPPED_LONG : eais->size == sz_word ? BO_SWAPPED_WORD : BO_NORMAL;
        !          2403:     int i, scrambled = 0;
        !          2404:     int best = 0;
        !          2405:     int bestcost = -1;
        !          2406:     int *ap;
        !          2407:     uae_u32 *sregp = NULL;
        !          2408:     int screg = -1, stype = -1;
        !          2409:     int regprefs = eais->size == sz_byte ? DATA_X86_REGS : 0;
        !          2410: 
        !          2411:     if (eais->mode == Dreg) {
        !          2412:        stype = 0;
        !          2413:        screg = map->dreg_map[eais->reg];
        !          2414:        if (screg == -1)
        !          2415:            sregp = regs.regs + eais->reg;
        !          2416:     } else if (eais->mode == Areg) {
        !          2417:        stype = 0;
        !          2418:        screg = map->areg_map[eais->reg];
        !          2419:        if (screg == -1)
        !          2420:            sregp = regs.regs + 8 + eais->reg;
        !          2421:     } else if (eais->data_reg == -2) {
        !          2422:        stype = -2;
        !          2423:     }
        !          2424: 
        !          2425:     if (stype == -2) {
        !          2426:        if ((asrc & 4) == 0)
        !          2427:            compile_fetchimm(map, eais, scrambled ? scrambled_bo : BO_NORMAL);
        !          2428:     } else if (stype == -1) {
        !          2429:        if ((asrc & 2) == 0 || eais->size != sz_byte)
        !          2430:            compile_fetchmem(map, eais);
        !          2431:     } else {
        !          2432:        if ((screg == -1 && (asrc & 2) == 0) || screg != -1) {
        !          2433:            eais->data_reg = get_and_lock_68k_reg(map, eais->reg, eais->mode == Dreg, regprefs, 1, 2);
        !          2434:            eais->data_const_off = 0;
        !          2435:        }
        !          2436:     }
        !          2437: 
        !          2438:     if (eais->data_reg >= 0)
        !          2439:        compile_force_byteorder(map, eais->data_reg, BO_NORMAL, 0);
        !          2440: }
        !          2441: 
        !          2442: /*
        !          2443:  * compile_note_modify() should be called on destination EAs obtained from
        !          2444:  * compile_loadeas(), if their value was modified (e.g. by the compile_eas()
        !          2445:  * function)
        !          2446:  */
        !          2447: 
        !          2448: static void compile_note_modify(struct register_mapping *map, struct ea_info *eainf,
        !          2449:                                int eaino)
        !          2450: {
        !          2451:     struct ea_info *eai = eainf + eaino;
        !          2452:     int newr;
        !          2453:     int szflag = eai->size == sz_byte ? 0 : 1;
        !          2454: 
        !          2455:     if (eai->mode == Dreg) {
        !          2456:        /* We only need to do something if we have the value in a register,
        !          2457:         * otherwise, the home location was modified already */
        !          2458:        if (eai->data_reg >= 0) {
        !          2459:            if (eai->data_reg != map->dreg_map[eai->reg]) {
        !          2460:                remove_x86r_from_cache(map, eai->data_reg, 0);
        !          2461:                if (map->dreg_map[eai->reg] >= 0)
        !          2462:                    remove_x86r_from_cache(map, map->dreg_map[eai->reg], 0);
        !          2463:                map->x86_cache_reg[eai->data_reg] = eai->reg;
        !          2464:                map->x86_cr_type[eai->data_reg] = 1;
        !          2465:                map->dreg_map[eai->reg] = eai->data_reg;
        !          2466:            }
        !          2467:            map->x86_verified[eai->data_reg] = 0;
        !          2468:            map->x86_const_offset[eai->data_reg] = eai->data_const_off;
        !          2469:            map->x86_dirty[eai->data_reg] = 1;
        !          2470:        }
        !          2471:        return;
        !          2472:     } else if (eai->mode == Areg) {
        !          2473:        if (eai->size != sz_long)
        !          2474:            printf("Areg put != long\n");
        !          2475: 
        !          2476:        /* We only need to do something if we have the value in a register,
        !          2477:         * otherwise, the home location was modified already */
        !          2478:        if (eai->data_reg >= 0) {
        !          2479:            if (eai->data_reg != map->areg_map[eai->reg]) {
        !          2480:                remove_x86r_from_cache(map, eai->data_reg, 0);
        !          2481:                if (map->areg_map[eai->reg] >= 0)
        !          2482:                    remove_x86r_from_cache(map, map->areg_map[eai->reg], 0);
        !          2483:                map->x86_cache_reg[eai->data_reg] = eai->reg;
        !          2484:                map->x86_cr_type[eai->data_reg] = 0;
        !          2485:                map->areg_map[eai->reg] = eai->data_reg;
        !          2486:            }
        !          2487:            map->x86_verified[eai->data_reg] = 0;
        !          2488:            map->x86_const_offset[eai->data_reg] = eai->data_const_off;
        !          2489:            map->x86_dirty[eai->data_reg] = 1;
        !          2490:        }
        !          2491:        return;
        !          2492:     } else {
        !          2493:        /* Storing to memory from reg? */
        !          2494:        if (eai->data_reg >= 0) {
        !          2495:            compile_offset_reg(map, eai->data_reg, eai->data_const_off);
        !          2496: 
        !          2497:            switch (eai->size) {
        !          2498:             case sz_byte: compile_force_byteorder(map, eai->data_reg, BO_NORMAL, 1); break;
        !          2499:             case sz_word: compile_force_byteorder(map, eai->data_reg, BO_SWAPPED_WORD, 1); break;
        !          2500:             case sz_long: compile_force_byteorder(map, eai->data_reg, BO_SWAPPED_LONG, 1); break;
        !          2501:            }
        !          2502:            compile_force_byteorder(map, eai->address_reg, BO_NORMAL, 0);
        !          2503:            compile_move_reg_to_mem_regoffs(eai->address_reg,
        !          2504:                                            (uae_u32)(eai->addr_const_off + address_space),
        !          2505:                                            eai->data_reg, eai->size);
        !          2506:        }
        !          2507:     }
        !          2508: }
        !          2509: 
        !          2510: static void compile_storeea(struct register_mapping *map, struct ea_info *eainf,
        !          2511:                            int eaino_s, int eaino_d)
        !          2512: {
        !          2513:     struct ea_info *eais = eainf + eaino_s;
        !          2514:     struct ea_info *eaid = eainf + eaino_d;
        !          2515:     int newr, cacher;
        !          2516:     int szflag = eaid->size == sz_byte ? 0 : 1;
        !          2517: 
        !          2518:     if (eaid->mode == Dreg) {
        !          2519:        /* Is the reg to move from already the register cache reg for the
        !          2520:         * destination? */
        !          2521:        if (eais->data_reg >= 0 && eais->data_reg == map->dreg_map[eaid->reg]) {
        !          2522:            map->x86_dirty[eais->data_reg] = 1; map->x86_verified[eais->data_reg] = 0;
        !          2523:            map->x86_const_offset[eais->data_reg] = eais->data_const_off;
        !          2524:            return;
        !          2525:        }
        !          2526:        /* Is the destination register in its home location? */
        !          2527:        if (map->dreg_map[eaid->reg] < 0) {
        !          2528:            if (eais->data_reg == -2) {
        !          2529:                /* Move immediate to regs.regs */
        !          2530:                if (eaid->size == sz_word) assemble(0x66);
        !          2531:                assemble(0xC6 + szflag); assemble(0x05); assemble_long(regs.regs + eaid->reg);
        !          2532:                switch (eaid->size) {
        !          2533:                 case sz_byte: assemble(eais->data_const_off); break;
        !          2534:                 case sz_word: assemble_uword(eais->data_const_off); break;
        !          2535:                 case sz_long: assemble_ulong(eais->data_const_off); break;
        !          2536:                }
        !          2537:            } else if (eais->data_reg == -1) {
        !          2538: #if 0
        !          2539:                printf("Shouldn't happen (mem-mem-move)\n");
        !          2540: #endif
        !          2541:                /* This _can_ happen: move.l $4,d0, if d0 isn't in the
        !          2542:                 * cache, will come here. But a reg will be allocated for
        !          2543:                 * dest. We use this. This _really_ shouldn't happen if
        !          2544:                 * the size isn't long. */
        !          2545:                if (eaid->size != sz_long)
        !          2546:                    printf("_Really_ shouldn't happen (Dreg case)\n");
        !          2547:                map->x86_cache_reg[eaid->data_reg] = eaid->reg;
        !          2548:                map->x86_cr_type[eaid->data_reg] = 1;
        !          2549:                map->x86_const_offset[eaid->data_reg] = eaid->data_const_off;
        !          2550:                map->dreg_map[eaid->reg] = eaid->data_reg;
        !          2551:                map->x86_verified[eaid->data_reg] = 0;
        !          2552:                goto have_cache_reg_d;
        !          2553:            } else {
        !          2554:                if (eais->size == sz_long) {
        !          2555:                    /* Make this the new register cache reg */
        !          2556:                    remove_x86r_from_cache(map, eais->data_reg, 0);
        !          2557:                    map->x86_cache_reg[eais->data_reg] = eaid->reg;
        !          2558:                    map->x86_cr_type[eais->data_reg] = 1;
        !          2559:                    map->x86_const_offset[eais->data_reg] = eais->data_const_off;
        !          2560:                    map->dreg_map[eaid->reg] = eais->data_reg;
        !          2561:                    map->x86_verified[eais->data_reg] = 0;
        !          2562:                } else {
        !          2563:                    /* Move from reg to regs.regs */
        !          2564:                    compile_force_byteorder(map, eais->data_reg, BO_NORMAL, 1);
        !          2565:                    compile_offset_reg (map, eais->data_reg, eais->data_const_off);
        !          2566:                    if (eaid->size == sz_word) assemble(0x66);
        !          2567:                    assemble(0x88 + szflag); assemble(0x05 + 8*eais->data_reg);
        !          2568:                    assemble_long(regs.regs + eaid->reg);
        !          2569:                }
        !          2570:            }
        !          2571:        } else {
        !          2572:            int destr;
        !          2573: 
        !          2574:            have_cache_reg_d:
        !          2575: 
        !          2576:            destr = map->dreg_map[eaid->reg];
        !          2577:            if (eaid->size != sz_long)
        !          2578:                compile_force_byteorder(map, destr, BO_NORMAL, 1);
        !          2579: 
        !          2580:            if (eais->data_reg == -2) {
        !          2581:                /* Move immediate to reg */
        !          2582:                if (eaid->size == sz_word) assemble(0x66);
        !          2583:                assemble(0xC6 + szflag); assemble(0xC0 + destr);
        !          2584:                switch (eaid->size) {
        !          2585:                 case sz_byte: assemble(eais->data_const_off); break;
        !          2586:                 case sz_word: assemble_uword(eais->data_const_off); break;
        !          2587:                 case sz_long: assemble_ulong(eais->data_const_off); break;
        !          2588:                }
        !          2589:                /* normal byteorder comes either from force above or from long
        !          2590:                 * const move */
        !          2591:                map->x86_byteorder[destr] = BO_NORMAL;
        !          2592:            } else if (eais->data_reg == -1) {
        !          2593:                if (eais->mode == Dreg) {
        !          2594:                    compile_move_reg_from_mem_regoffs(destr, -2, (uae_u32)(regs.regs + eais->reg),
        !          2595:                                                      eais->size);
        !          2596:                    map->x86_byteorder[destr] = BO_NORMAL;
        !          2597:                } else if (eais->mode == Areg) {
        !          2598:                    compile_move_reg_from_mem_regoffs(destr, -2, (uae_u32)(regs.regs + 8 + eais->reg),
        !          2599:                                                      eais->size);
        !          2600:                    map->x86_byteorder[destr] = BO_NORMAL;
        !          2601:                } else {
        !          2602:                    /* Move mem to reg */
        !          2603:                    compile_force_byteorder(map, eais->address_reg, BO_NORMAL, 0);
        !          2604:                    compile_move_reg_from_mem_regoffs(destr, eais->address_reg,
        !          2605:                                                      (uae_u32)(eais->addr_const_off + address_space),
        !          2606:                                                      eais->size);
        !          2607: 
        !          2608:                    switch (eais->size) {
        !          2609:                     case sz_byte: map->x86_byteorder[destr] = BO_NORMAL; break;
        !          2610:                     case sz_word: map->x86_byteorder[destr] = BO_SWAPPED_WORD; break;
        !          2611:                     case sz_long: map->x86_byteorder[destr] = BO_SWAPPED_LONG; break;
        !          2612:                    }
        !          2613:                }
        !          2614:            } else {
        !          2615:                if (eais->size == sz_long) {
        !          2616:                    /* Make this the new register cache reg */
        !          2617:                    remove_x86r_from_cache(map, eais->data_reg, 0);
        !          2618:                    remove_x86r_from_cache(map, destr, 0);
        !          2619:                    map->x86_cache_reg[eais->data_reg] = eaid->reg;
        !          2620:                    map->x86_cr_type[eais->data_reg] = 1;
        !          2621:                    map->x86_const_offset[eais->data_reg] = eais->data_const_off;
        !          2622:                    map->dreg_map[eaid->reg] = eais->data_reg;
        !          2623:                    map->x86_verified[eais->data_reg] = 0;
        !          2624:                } else {
        !          2625:                    /* Move from reg to reg */
        !          2626:                    compile_force_byteorder(map, eais->data_reg, BO_NORMAL, 1);
        !          2627:                    compile_offset_reg (map, eais->data_reg, eais->data_const_off);
        !          2628:                    if (eaid->size == sz_word) assemble(0x66);
        !          2629:                    assemble(0x88 + szflag); assemble(0xC0 + destr + 8*eais->data_reg);
        !          2630:                }
        !          2631:            }
        !          2632:        }
        !          2633: 
        !          2634:        if (map->dreg_map[eaid->reg] >= 0)
        !          2635:            map->x86_dirty[map->dreg_map[eaid->reg]] = 1;
        !          2636:        return;
        !          2637:     } else if (eaid->mode == Areg) {
        !          2638:        if (eaid->size != sz_long)
        !          2639:            printf("Areg put != long\n");
        !          2640: 
        !          2641:        /* Is the reg to move from already the register cache reg for the
        !          2642:         * destination? */
        !          2643:        if (eais->data_reg >= 0 && eais->data_reg == map->areg_map[eaid->reg]) {
        !          2644:            map->x86_dirty[eais->data_reg] = 1; map->x86_verified[eais->data_reg] = 0;
        !          2645:            map->x86_const_offset[eais->data_reg] = eais->data_const_off;
        !          2646:            return;
        !          2647:        }
        !          2648:        /* Is the destination register in its home location? */
        !          2649:        if (map->areg_map[eaid->reg] < 0) {
        !          2650:            if (eais->data_reg == -2) {
        !          2651:                /* Move immediate to regs.regs */
        !          2652:                assemble(0xC7); assemble(0x05); assemble_long(regs.regs + 8 + eaid->reg);
        !          2653:                assemble_ulong(eais->data_const_off);
        !          2654:            } else if (eais->data_reg == -1) {
        !          2655: #if 0 /* see above... */
        !          2656:                printf("Shouldn't happen (mem-mem-move)\n");
        !          2657: #endif
        !          2658:                map->x86_cache_reg[eaid->data_reg] = eaid->reg;
        !          2659:                map->x86_cr_type[eaid->data_reg] = 0;
        !          2660:                map->x86_const_offset[eaid->data_reg] = eaid->data_const_off;
        !          2661:                map->areg_map[eaid->reg] = eaid->data_reg;
        !          2662:                map->x86_verified[eaid->data_reg] = 0;
        !          2663:                goto have_cache_reg_a;
        !          2664:            } else {
        !          2665:                /* Make this the new register cache reg */
        !          2666:                remove_x86r_from_cache(map, eais->data_reg, 0);
        !          2667:                map->x86_cache_reg[eais->data_reg] = eaid->reg;
        !          2668:                map->x86_cr_type[eais->data_reg] = 0;
        !          2669:                map->x86_const_offset[eais->data_reg] = eais->data_const_off;
        !          2670:                map->areg_map[eaid->reg] = eais->data_reg;
        !          2671:                map->x86_verified[eais->data_reg] = 0;
        !          2672:            }
        !          2673:        } else {
        !          2674:            int destr;
        !          2675: 
        !          2676:            have_cache_reg_a:
        !          2677: 
        !          2678:            destr = map->areg_map[eaid->reg];
        !          2679:            if (eaid->size != sz_long)
        !          2680:                compile_force_byteorder(map, destr, BO_NORMAL, 1);
        !          2681: 
        !          2682:            if (eais->data_reg == -2) {
        !          2683:                /* Move immediate to reg */
        !          2684:                assemble(0xC7); assemble(0xC0 + destr);
        !          2685:                assemble_ulong(eais->data_const_off);
        !          2686: 
        !          2687:                /* normal byteorder comes either from force above or from long
        !          2688:                 * const move */
        !          2689:                map->x86_byteorder[destr] = BO_NORMAL;
        !          2690:            } else if (eais->data_reg == -1) {
        !          2691:                if (eais->mode == Dreg) {
        !          2692:                    compile_move_reg_from_mem_regoffs(destr, -2, (uae_u32)(regs.regs + eais->reg),
        !          2693:                                                      eais->size);
        !          2694:                    map->x86_byteorder[destr] = BO_NORMAL;
        !          2695:                } else if (eais->mode == Areg) {
        !          2696:                    compile_move_reg_from_mem_regoffs(destr, -2, (uae_u32)(regs.regs + 8 + eais->reg),
        !          2697:                                                      eais->size);
        !          2698:                    map->x86_byteorder[destr] = BO_NORMAL;
        !          2699:                } else {
        !          2700:                    /* Move mem to reg */
        !          2701:                    compile_force_byteorder(map, eais->address_reg, BO_NORMAL, 0);
        !          2702:                    compile_move_reg_from_mem_regoffs(destr, eais->address_reg,
        !          2703:                                                      (uae_u32)(eais->addr_const_off + address_space),
        !          2704:                                                      eais->size);
        !          2705: 
        !          2706:                    map->x86_byteorder[destr] = BO_SWAPPED_LONG;
        !          2707:                }
        !          2708:            } else {
        !          2709:                /* Make this the new register cache reg */
        !          2710:                remove_x86r_from_cache(map, eais->data_reg, 0);
        !          2711:                remove_x86r_from_cache(map, destr, 0);
        !          2712:                map->x86_cache_reg[eais->data_reg] = eaid->reg;
        !          2713:                map->x86_cr_type[eais->data_reg] = 0;
        !          2714:                map->x86_const_offset[eais->data_reg] = eais->data_const_off;
        !          2715:                map->areg_map[eaid->reg] = eais->data_reg;
        !          2716:                map->x86_verified[eais->data_reg] = 0;
        !          2717:            }
        !          2718:        }
        !          2719: 
        !          2720:        if (map->areg_map[eaid->reg] >= 0)
        !          2721:            map->x86_dirty[map->areg_map[eaid->reg]] = 1;
        !          2722:        return;
        !          2723:     }
        !          2724: 
        !          2725:     if (eais->data_reg == -1)
        !          2726:        printf("Storing to mem, but not from reg\n");
        !          2727:     /* Correct the byteorder */
        !          2728:     if (eais->data_reg != -2) {
        !          2729:        compile_offset_reg(map, eais->data_reg, eais->data_const_off);
        !          2730: 
        !          2731:        switch (eaid->size) {
        !          2732:         case sz_byte: compile_force_byteorder(map, eais->data_reg, BO_NORMAL, 1); break;
        !          2733:         case sz_word: compile_force_byteorder(map, eais->data_reg, BO_SWAPPED_WORD, 1); break;
        !          2734:         case sz_long: compile_force_byteorder(map, eais->data_reg, BO_SWAPPED_LONG, 1); break;
        !          2735:        }
        !          2736:        compile_force_byteorder(map, eaid->address_reg, BO_NORMAL, 0);
        !          2737:        compile_move_reg_to_mem_regoffs(eaid->address_reg,
        !          2738:                                        (uae_u32)(eaid->addr_const_off + address_space),
        !          2739:                                        eais->data_reg, eaid->size);
        !          2740:     } else {
        !          2741:        switch (eaid->size) {
        !          2742:         case sz_long:
        !          2743:            eais->data_const_off = (((eais->data_const_off & 0xFF000000) >> 24)
        !          2744:                                 | ((eais->data_const_off & 0xFF0000) >> 8)
        !          2745:                                 | ((eais->data_const_off & 0xFF00) << 8)
        !          2746:                                 | ((eais->data_const_off & 0xFF) << 24));
        !          2747:            break;
        !          2748:         case sz_word:
        !          2749:            eais->data_const_off = (((eais->data_const_off & 0xFF00) >> 8)
        !          2750:                                 | ((eais->data_const_off & 0xFF) << 8));
        !          2751:            break;
        !          2752:        }
        !          2753:        compile_force_byteorder(map, eaid->address_reg, BO_NORMAL, 0);
        !          2754:        /* generate code to move valueoffset,eaoffset(eareg) */
        !          2755:        switch(eaid->size) {
        !          2756:         case sz_byte: assemble(0xC6); break;
        !          2757:         case sz_word: assemble(0x66); /* fall through */
        !          2758:         case sz_long: assemble(0xC7); break;
        !          2759:        }
        !          2760:        if (eaid->address_reg == -2) { /* absolute or PC-relative */
        !          2761:            assemble(0x05);
        !          2762:            assemble_long(eaid->addr_const_off + address_space);
        !          2763:        } else {
        !          2764:            assemble(0x80 + eaid->address_reg);
        !          2765:            assemble_long(eaid->addr_const_off + address_space);
        !          2766:        }
        !          2767:        switch(eaid->size) {
        !          2768:         case sz_byte: assemble(eais->data_const_off); break;
        !          2769:         case sz_word: assemble_uword(eais->data_const_off); break;
        !          2770:         case sz_long: assemble_ulong(eais->data_const_off); break;
        !          2771:        }
        !          2772:     }
        !          2773: }
        !          2774: 
        !          2775: #define CE_STACK_SIZE 1000
        !          2776: 
        !          2777: static struct {
        !          2778:     struct register_mapping map;
        !          2779:     char *jmpoffs;
        !          2780:     uae_u32 address;
        !          2781:     int noflush:1;
        !          2782: } compile_exit_stack[CE_STACK_SIZE];
        !          2783: 
        !          2784: static int cesp;
        !          2785: 
        !          2786: static struct register_mapping current_exit_regmap;
        !          2787: 
        !          2788: static void generate_exit(struct register_mapping *map, int address)
        !          2789: {
        !          2790:     int i;
        !          2791: 
        !          2792:     if (map != NULL)
        !          2793:        sync_reg_cache (map, 1);
        !          2794:     assemble(0xB8); /* movl $new_pc,%eax */
        !          2795:     assemble_ulong(address);
        !          2796:     assemble(0xC3); /* RET */
        !          2797: }
        !          2798: 
        !          2799: static void copy_map_with_undo(struct register_mapping *dst,
        !          2800:                               struct register_mapping *src,
        !          2801:                               struct pid_undo *pud)
        !          2802: {
        !          2803:     int i;
        !          2804:     *dst = *src;
        !          2805:     for (i = 0; i < pud->used; i++) {
        !          2806:        int m68kr = pud->m68kr[i];
        !          2807:        int x86r = pud->x86r[i];
        !          2808:        int old_cr = dst->areg_map[m68kr];
        !          2809:        if (old_cr != -1) {
        !          2810:            dst->x86_cache_reg[old_cr] = -1;
        !          2811:        }
        !          2812:        dst->x86_cache_reg[x86r] = m68kr;
        !          2813:        dst->areg_map[m68kr] = x86r;
        !          2814:        dst->x86_cr_type[x86r] = 0;
        !          2815:        dst->x86_const_offset[x86r] = pud->offs[i];
        !          2816:        dst->x86_dirty[x86r] = pud->dirty[i];
        !          2817:     }
        !          2818: }
        !          2819: 
        !          2820: static void unlock_pud(struct register_mapping *map, struct pid_undo *pud)
        !          2821: {
        !          2822:     int i;
        !          2823:     for (i = 0; i < pud->used; i++) {
        !          2824:        compile_unlock_reg(map, pud->x86r[i]);
        !          2825:     }
        !          2826: }
        !          2827: 
        !          2828: static int exits_necessary;
        !          2829: 
        !          2830: static void generate_possible_exit(struct register_mapping *map,
        !          2831:                                   struct ea_info *eai, int iip,
        !          2832:                                   struct pid_undo *pud)
        !          2833: {
        !          2834:     struct register_mapping exit_regmap;
        !          2835: 
        !          2836:     if (!exits_necessary) {
        !          2837:        unlock_pud(map, pud);
        !          2838:        return;
        !          2839:     }
        !          2840: 
        !          2841:     compile_force_byteorder(map, eai->address_reg, BO_NORMAL, 0);
        !          2842:     switch (eai->address_reg) {
        !          2843:      case -1:
        !          2844:        /* EA doesn't refer to memory */
        !          2845:        break;
        !          2846:      case -2:
        !          2847:        /* Only a constant offset */
        !          2848:        eai->addr_const_off &= (1<<24)-1;
        !          2849:        if (!good_address_map[eai->addr_const_off]) {
        !          2850:            copy_map_with_undo(&exit_regmap, map, pud);
        !          2851:            generate_exit(&exit_regmap, insn_info[iip].address);
        !          2852:        }
        !          2853:        break;
        !          2854:      default:
        !          2855:        if (map->x86_verified[eai->address_reg])
        !          2856:            break;
        !          2857:        map->x86_verified[eai->address_reg] = 1;
        !          2858:        if (cesp == CE_STACK_SIZE) {
        !          2859:            copy_map_with_undo(&exit_regmap, map, pud);
        !          2860:            generate_exit(&exit_regmap, insn_info[iip].address);
        !          2861:            break;
        !          2862:        }
        !          2863:        copy_map_with_undo(&compile_exit_stack[cesp].map, map, pud);
        !          2864:        compile_exit_stack[cesp].address = insn_info[iip].address;
        !          2865:        assemble(0x80); assemble(0xB8 + eai->address_reg); /* cmpb $0, good_address_map(x86r) */
        !          2866:        assemble_long(good_address_map + eai->addr_const_off);
        !          2867:        assemble(0);
        !          2868:        assemble(0x0F); assemble(0x84); /* JE finish */
        !          2869:        compile_exit_stack[cesp].jmpoffs = compile_here();
        !          2870:        compile_exit_stack[cesp].noflush = 0;
        !          2871:        assemble_ulong(0);
        !          2872:        cesp++;
        !          2873:        break;
        !          2874:     }
        !          2875:     unlock_pud(map, pud);
        !          2876: }
        !          2877: 
        !          2878: static void finish_exits(void)
        !          2879: {
        !          2880:     int i;
        !          2881:     for (i = 0; i < cesp; i++) {
        !          2882:        char *exitpoint = compile_here();
        !          2883:        char *nextpoint;
        !          2884: 
        !          2885:        if (compile_exit_stack[i].noflush)
        !          2886:            generate_exit(NULL, compile_exit_stack[i].address);
        !          2887:        else
        !          2888:            generate_exit(&compile_exit_stack[i].map, compile_exit_stack[i].address);
        !          2889:        nextpoint = compile_here();
        !          2890:        compile_org(compile_exit_stack[i].jmpoffs);
        !          2891:        assemble_ulong(exitpoint - (compile_exit_stack[i].jmpoffs + 4));
        !          2892:        compile_org(nextpoint);
        !          2893:     }
        !          2894: }
        !          2895: 
        !          2896: static void finish_condjumps(int lastiip)
        !          2897: {
        !          2898:     int iip;
        !          2899:     char *lastptr = compile_here();
        !          2900:     for (iip = 0; iip < lastiip; iip++) {
        !          2901:        char *fillin = insn_info[iip].compiled_fillin;
        !          2902:        if (fillin != NULL) {
        !          2903:            compile_org(insn_info[iip].compiled_fillin);
        !          2904:            assemble_ulong(insn_info[insn_info[iip].jumps_to].compiled_jumpaddr - (fillin + 4));
        !          2905:        }
        !          2906:     }
        !          2907:     compile_org(lastptr);
        !          2908: }
        !          2909: 
        !          2910: #define CC_X_FROM_86C 1
        !          2911: #define CC_C_FROM_86C 2
        !          2912: #define CC_Z_FROM_86Z 4
        !          2913: #define CC_V_FROM_86V 8
        !          2914: #define CC_N_FROM_86N 16
        !          2915: #define CC_TEST_REG   32
        !          2916: #define CC_Z_FROM_86C 64
        !          2917: #define CC_SAHF       128
        !          2918: #define CC_TEST_CONST 256
        !          2919: #define CC_AFTER_RO   512
        !          2920: #define CC_AFTER_ROX  1024
        !          2921: 
        !          2922: static unsigned int cc_status;
        !          2923: static int cc_reg;
        !          2924: static uae_u32 cc_offset;
        !          2925: static wordsizes cc_size;
        !          2926: 
        !          2927: static void compile_do_cc_test_reg(struct register_mapping *map)
        !          2928: {
        !          2929:     compile_force_byteorder(map, cc_reg, BO_NORMAL, 1);
        !          2930:     if (cc_offset != 0)
        !          2931:        printf("Pull my finger\n");
        !          2932:     if (cc_size == sz_word) /* test ccreg */
        !          2933:        assemble(0x66);
        !          2934:     if (cc_size == sz_byte)
        !          2935:        assemble(0x84);
        !          2936:     else
        !          2937:        assemble(0x85);
        !          2938:     assemble(0xC0 + 9*cc_reg);
        !          2939: }
        !          2940: 
        !          2941: static int compile_flush_cc_cache(struct register_mapping *map, int status,
        !          2942:                                  int live_at_end, int user_follows,
        !          2943:                                  int user_live_at_end, int user_ccval)
        !          2944: {
        !          2945:     int status_for_user = 0;
        !          2946: 
        !          2947:     if (user_follows) {
        !          2948:        int need_for_user = 0;
        !          2949:        int user_flagmask = cc_flagmask_68k(user_ccval);
        !          2950: 
        !          2951:        if (user_flagmask & CC68K_C)
        !          2952:            need_for_user |= CC_C_FROM_86C;
        !          2953:        if (user_flagmask & CC68K_Z)
        !          2954:            need_for_user |= CC_Z_FROM_86Z;
        !          2955:        if (user_flagmask & CC68K_N)
        !          2956:            need_for_user |= CC_N_FROM_86N;
        !          2957:        if (user_flagmask & CC68K_V)
        !          2958:            need_for_user |= CC_V_FROM_86V;
        !          2959: 
        !          2960:        /* Check whether we can satisfy the user's needs in a simple way. */
        !          2961:        if ((need_for_user & status) == need_for_user)
        !          2962:            status_for_user = status;
        !          2963:        else if (user_flagmask == CC68K_Z && status == CC_Z_FROM_86C)
        !          2964:            status_for_user = status;
        !          2965:        else if (status == CC_TEST_REG && (user_flagmask & (CC68K_C|CC68K_V|CC68K_Z|CC68K_N)) != 0) {
        !          2966:            if (cc_reg == -2) {
        !          2967:                status_for_user = CC_TEST_CONST;
        !          2968:            } else {
        !          2969:                compile_do_cc_test_reg(map);
        !          2970:                status_for_user = status = (CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V);
        !          2971:            }
        !          2972:        } else if (status == CC_AFTER_RO) {
        !          2973:            /* We fake some information here... */
        !          2974:            if (user_flagmask == CC68K_C && (user_live_at_end & ~CC68K_C) == 0)
        !          2975:                status = status_for_user = CC_C_FROM_86C;
        !          2976:            else if (((user_flagmask | user_live_at_end) & (CC68K_C|CC68K_V)) == 0) {
        !          2977:                status = CC_TEST_REG; user_live_at_end = CC68K_Z|CC68K_N|CC68K_V;
        !          2978:                status_for_user = (CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V);
        !          2979:            } else
        !          2980:                status_for_user = CC_SAHF;
        !          2981:        } else if (status == CC_AFTER_ROX) {
        !          2982:            if (user_flagmask == CC68K_C && (user_live_at_end & ~(CC68K_C|CC68K_X)) == 0)
        !          2983:                status = status_for_user = CC_C_FROM_86C;
        !          2984:            else if (((user_flagmask | user_live_at_end) & (CC68K_C|CC68K_X|CC68K_V)) == 0) {
        !          2985:                status = CC_TEST_REG; user_live_at_end = CC68K_Z|CC68K_N|CC68K_V;
        !          2986:                status_for_user = (CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V);
        !          2987:            } else
        !          2988:                status_for_user = CC_SAHF;
        !          2989:        } else if (need_for_user != 0) {
        !          2990:            /* No way to handle it easily */
        !          2991:            status_for_user = CC_SAHF;
        !          2992:        }
        !          2993:        if (status_for_user != CC_SAHF)
        !          2994:            live_at_end = user_live_at_end;
        !          2995:     }
        !          2996: 
        !          2997:     /*
        !          2998:      * Now store the flags which are live at the end of this insn and set by
        !          2999:      * us into their home locations
        !          3000:      */
        !          3001:     if (status == CC_TEST_REG) {
        !          3002:        if ((live_at_end & (CC68K_C|CC68K_V|CC68K_Z|CC68K_N)) == 0)
        !          3003:            goto all_ok;
        !          3004: 
        !          3005:        if (cc_reg == -2) {
        !          3006:            uae_u8 f = 0;
        !          3007:            if (cc_size == sz_byte) {
        !          3008:                f |= (cc_offset & 0x80) ? 0x80 : 0;
        !          3009:                f |= (cc_offset & 0xFF) == 0 ? 0x40 : 0;
        !          3010:            } else if (cc_size == sz_byte) {
        !          3011:                f |= (cc_offset & 0x8000) ? 0x80 : 0;
        !          3012:                f |= (cc_offset & 0xFFFF) == 0 ? 0x40 : 0;
        !          3013:            } else {
        !          3014:                f |= (cc_offset & 0x80000000) ? 0x80 : 0;
        !          3015:                f |= (cc_offset & 0xFFFFFFFF) == 0 ? 0x40 : 0;
        !          3016:            }
        !          3017:            assemble(0xC7); assemble(0x05);
        !          3018:            assemble_long((char*)&regflags);
        !          3019:            assemble_uword(f);
        !          3020:        } else {
        !          3021:            int tmpr = get_free_x86_register(map, ALL_X86_REGS);
        !          3022:            compile_do_cc_test_reg(map);
        !          3023: 
        !          3024:            /* pushfl; popl tmpr; movl tempr, regflags */
        !          3025:            assemble(0x9C); assemble(0x58+tmpr);
        !          3026:            compile_move_reg_to_mem_regoffs(-2, (uae_u32)&regflags, tmpr, sz_long);
        !          3027:        }
        !          3028:     } else if (status == CC_Z_FROM_86C) {
        !          3029:        if ((live_at_end & CC68K_Z) != 0) {
        !          3030:            int tmpr = get_typed_x86_register(map, DATA_X86_REGS);
        !          3031:            assemble(0x9C);
        !          3032:            /* setnc tmpr; shl $6, tmpr; andb $~0x40, regflags; orb tmpr, regflags */
        !          3033:            assemble(0x0F); assemble(0x93); assemble(0xC0 + tmpr);
        !          3034:            assemble(0xC0); assemble(4*8 + 0xC0 + tmpr); assemble(6);
        !          3035:            assemble(0x80); assemble(0x05+0x20); assemble_long(&regflags); assemble((uae_u8)~0x40);
        !          3036:            assemble(0x08); assemble(0x05+ tmpr*8); assemble_long(&regflags);
        !          3037:            assemble(0x9D);
        !          3038:        }
        !          3039:     } else if (status == CC_AFTER_RO || status == CC_AFTER_ROX) {
        !          3040:        int tmpr = get_typed_x86_register(map, DATA_X86_REGS);
        !          3041:        assemble(0x9C);
        !          3042:        compile_do_cc_test_reg(map);
        !          3043:        /* pushfl; popl tmpr; andl $0xff,tmpr (mask out V flag which is cleared after rotates) */
        !          3044:        assemble(0x9C); assemble(0x58 + tmpr);
        !          3045:        assemble(0x81); assemble(0xC0 + tmpr + 8*4); assemble_ulong(0xFF);
        !          3046:        assemble(0x9D);
        !          3047:        /* adc $0, tmpr */
        !          3048:        assemble(0x80); assemble(0xC0 + tmpr + 8*2); assemble(0);
        !          3049:        compile_move_reg_to_mem_regoffs(-2, (uae_u32)&regflags, tmpr, sz_long);
        !          3050:        if (status == CC_AFTER_ROX)
        !          3051:            compile_move_reg_to_mem_regoffs(-2, 4 + (uae_u32)&regflags, tmpr, sz_long);
        !          3052:     } else if (status != 0) {
        !          3053:        assert((status & CC_TEST_REG) == 0);
        !          3054:        assert (status == (CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_X_FROM_86C | CC_V_FROM_86V)
        !          3055:                || status == (CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V)
        !          3056:                || status == CC_C_FROM_86C);
        !          3057: 
        !          3058:        if ((status & CC_X_FROM_86C) == 0)
        !          3059:            live_at_end &= ~CC68K_X;
        !          3060: 
        !          3061:        if (status == CC_C_FROM_86C && (live_at_end & CC68K_C) != 0)
        !          3062:            fprintf(stderr, "Shouldn't be needing C here!\n");
        !          3063:        else if (live_at_end) {
        !          3064:            if ((live_at_end & CC68K_X) == 0)
        !          3065:                status &= ~CC_X_FROM_86C;
        !          3066: 
        !          3067:            if (live_at_end) {
        !          3068:                if ((status & CC_X_FROM_86C) != 0 && live_at_end == CC68K_X) {
        !          3069:                    /* SETC regflags + 4 */
        !          3070:                    assemble(0x0F); assemble(0x92);
        !          3071:                    assemble(0x05); assemble_long(4 + (uae_u32)&regflags);
        !          3072:                } else {
        !          3073:                    int tmpr = get_free_x86_register(map, ALL_X86_REGS);
        !          3074:                    /* pushfl; popl tmpr; movl tempr, regflags */
        !          3075:                    assemble(0x9C); assemble(0x58+tmpr);
        !          3076:                    compile_move_reg_to_mem_regoffs(-2, (uae_u32)&regflags, tmpr, sz_long);
        !          3077: 
        !          3078:                    if (status & CC_X_FROM_86C) {
        !          3079:                        compile_move_reg_to_mem_regoffs(-2, 4 + (uae_u32)&regflags, tmpr, sz_word);
        !          3080:                    }
        !          3081:                }
        !          3082:            }
        !          3083:        }
        !          3084:     }
        !          3085: 
        !          3086:     all_ok:
        !          3087:     return status_for_user;
        !          3088: }
        !          3089: 
        !          3090: static char *compile_condbranch(struct register_mapping *map, int iip,
        !          3091:                                int new_cc_status)
        !          3092: {
        !          3093:     int cc = insn_info[iip].dp->cc;
        !          3094:     int flagsused = cc_flagmask_68k(cc);
        !          3095:     int flagsneeded = 0;
        !          3096:     char *undo_pointer = compile_here();
        !          3097: 
        !          3098:     if (flagsused & CC68K_C)
        !          3099:        flagsneeded |= CC_C_FROM_86C;
        !          3100:     if (flagsused & CC68K_Z)
        !          3101:        flagsneeded |= CC_Z_FROM_86Z;
        !          3102:     if (flagsused & CC68K_N)
        !          3103:        flagsneeded |= CC_N_FROM_86N;
        !          3104:     if (flagsused & CC68K_V)
        !          3105:        flagsneeded |= CC_V_FROM_86V;
        !          3106: 
        !          3107:     if (flagsneeded == 0)
        !          3108:        /* Fine */;
        !          3109:     else if (new_cc_status == CC_SAHF) {
        !          3110:        int tmpr = get_free_x86_register(map, ALL_X86_REGS);
        !          3111:        compile_move_reg_from_mem_regoffs(tmpr, -2, (uae_u32)&regflags, sz_long);
        !          3112:        assemble(0x66); assemble(0x50+tmpr); assemble(0x66); assemble(0x9D);
        !          3113:        new_cc_status = CC_C_FROM_86C|CC_Z_FROM_86Z|CC_N_FROM_86N|CC_V_FROM_86V;
        !          3114:     } else if (new_cc_status == CC_TEST_CONST) {
        !          3115:        int n,z;
        !          3116:        switch(cc_size) {
        !          3117:         case sz_byte: n = ((uae_s8)cc_offset) < 0; z = ((uae_s8)cc_offset) == 0; break;
        !          3118:         case sz_word: n = ((uae_s16)cc_offset) < 0; z = ((uae_s16)cc_offset) == 0; break;
        !          3119:         case sz_long: n = ((uae_s32)cc_offset) < 0; z = ((uae_s32)cc_offset) == 0; break;
        !          3120:        }
        !          3121: #define Bcc_TRUE 0
        !          3122: #define Bcc_FALSE 1
        !          3123:        flagsneeded = 0;
        !          3124:        new_cc_status = 0;
        !          3125:        switch (cc) {
        !          3126:         case 2: cc = !z ? Bcc_TRUE : Bcc_FALSE; break; /* !CFLG && !ZFLG */
        !          3127:         case 3: cc = z ? Bcc_TRUE : Bcc_FALSE; break; /* CFLG || ZFLG */
        !          3128:         case 4: cc = Bcc_TRUE; break; /* !CFLG */
        !          3129:         case 5: cc = Bcc_FALSE; break; /* CFLG */
        !          3130:         case 6: cc = !z ? Bcc_TRUE : Bcc_FALSE; break; /* !ZFLG */
        !          3131:         case 7: cc = z ? Bcc_TRUE : Bcc_FALSE; break; /* ZFLG */
        !          3132:         case 8: cc = Bcc_TRUE; break; /* !VFLG */
        !          3133:         case 9: cc = Bcc_FALSE; break; /* VFLG */
        !          3134:         case 10:cc = !n ? Bcc_TRUE : Bcc_FALSE; break; /* !NFLG */
        !          3135:         case 11:cc = n ? Bcc_TRUE : Bcc_FALSE; break; /* NFLG */
        !          3136:         case 12:cc = !n ? Bcc_TRUE : Bcc_FALSE; break; /* NFLG == VFLG */
        !          3137:         case 13:cc = n ? Bcc_TRUE : Bcc_FALSE; break; /* NFLG != VFLG */
        !          3138:         case 14:cc = !n && !z ? Bcc_TRUE : Bcc_FALSE; break; /* !ZFLG && (NFLG == VFLG) */
        !          3139:         case 15:cc = n || z ? Bcc_TRUE : Bcc_FALSE; break; /* ZFLG || (NFLG != VFLG) */
        !          3140:        }
        !          3141:     } else if (new_cc_status == CC_Z_FROM_86C) {
        !          3142:        if (cc == 6 || cc == 7) {
        !          3143:            cc = (cc - 2) ^ 1;
        !          3144:            /* Fake... */
        !          3145:            flagsneeded = new_cc_status = CC_C_FROM_86C;
        !          3146:        } else if (cc != 0 && cc != 1)
        !          3147:            printf("Groan!\n");
        !          3148:     }
        !          3149: 
        !          3150:     if (cc == 1)
        !          3151:        return NULL;
        !          3152: 
        !          3153:     if ((flagsneeded & new_cc_status) == flagsneeded) {
        !          3154:        char *result;
        !          3155:        /* We can generate a simple branch */
        !          3156:        if (cc == 0)
        !          3157:            assemble(0xE9);
        !          3158:        else
        !          3159:            assemble(0x0F);
        !          3160:        switch(cc) {
        !          3161:         case 2: assemble(0x87); break;          /* HI */
        !          3162:         case 3: assemble(0x86); break;          /* LS */
        !          3163:         case 4: assemble(0x83); break;          /* CC */
        !          3164:         case 5: assemble(0x82); break;          /* CS */
        !          3165:         case 6: assemble(0x85); break;          /* NE */
        !          3166:         case 7: assemble(0x84); break;          /* EQ */
        !          3167:         case 8: assemble(0x81); break;          /* VC */
        !          3168:         case 9: assemble(0x80); break;          /* VS */
        !          3169:         case 10:assemble(0x89); break;          /* PL */
        !          3170:         case 11:assemble(0x88); break;          /* MI */
        !          3171:         case 12:assemble(0x8D); break;          /* GE */
        !          3172:         case 13:assemble(0x8C); break;          /* LT */
        !          3173:         case 14:assemble(0x8F); break;          /* GT */
        !          3174:         case 15:assemble(0x8E); break;          /* LE */
        !          3175:        }
        !          3176:        result = compile_here();
        !          3177:        assemble_ulong(0);
        !          3178:        return result;
        !          3179:     }
        !          3180:     printf("Uhhuh.\n");
        !          3181:     return NULL;
        !          3182: }
        !          3183: 
        !          3184: static void compile_handle_bcc(struct register_mapping *map, int iip,
        !          3185:                               int new_cc_status)
        !          3186: {
        !          3187:     insn_info[iip].compiled_fillin = compile_condbranch(map, iip, new_cc_status);
        !          3188: }
        !          3189: 
        !          3190: static void compile_handle_dbcc(struct register_mapping *map, int iip,
        !          3191:                                int new_cc_status, int dreg)
        !          3192: {
        !          3193:     char *fillin1 = compile_condbranch(map, iip, new_cc_status);
        !          3194: 
        !          3195:     /* subw $1,dreg; jnc ... */
        !          3196:     assemble(0x66); assemble(0x83); assemble(0x05 + 5*8);
        !          3197:     assemble_long(regs.regs + dreg);
        !          3198:     assemble(1);
        !          3199:     assemble(0x0F); assemble(0x83);
        !          3200:     insn_info[iip].compiled_fillin = compile_here();
        !          3201:     assemble_ulong(0);
        !          3202:     if (fillin1 != NULL) {
        !          3203:        char *oldp = compile_here();
        !          3204:        compile_org(fillin1);
        !          3205:        assemble_ulong(oldp - (fillin1+4));
        !          3206:        compile_org(oldp);
        !          3207:     }
        !          3208: }
        !          3209: 
        !          3210: static void handle_bit_insns(struct register_mapping *map, struct ea_info *eainf,
        !          3211:                             int eaino_s, int eaino_d, instrmnem optype)
        !          3212: {
        !          3213:     struct ea_info *srcea = eainf + eaino_s, *dstea = eainf + eaino_d;
        !          3214:     int code = (optype == i_BTST ? 0
        !          3215:                : optype == i_BSET ? 1
        !          3216:                : optype == i_BCLR ? 2
        !          3217:                : /* optype == i_BCHG */ 3);
        !          3218: 
        !          3219:     compile_fetchea(map, eainf, eaino_s, 5);
        !          3220:     compile_fetchea(map, eainf, eaino_d, 3);
        !          3221: 
        !          3222:     if (srcea->data_reg != -2) {
        !          3223:        compile_force_byteorder(map, srcea->data_reg, BO_NORMAL, 0);
        !          3224:        remove_x86r_from_cache(map, srcea->data_reg, 0);
        !          3225:        /* andl $something,srcreg */
        !          3226:        assemble(0x83); assemble(0xC0 + 4*8 + srcea->data_reg);
        !          3227:        if (dstea->size == sz_byte)
        !          3228:            assemble(7);
        !          3229:        else
        !          3230:            assemble(31);
        !          3231:     } else
        !          3232:        if (dstea->size == sz_byte)
        !          3233:            srcea->data_const_off &= 7;
        !          3234:        else
        !          3235:            srcea->data_const_off &= 31;
        !          3236: 
        !          3237:     /* Areg isn't possible here */
        !          3238:     if (dstea->mode == Dreg && dstea->data_reg == -1) {
        !          3239:        if (srcea->data_reg == -2) {
        !          3240:            assemble(0x0F); assemble(0xBA); assemble(5 + 8*(4 + code));
        !          3241:            assemble_long(regs.regs + dstea->reg);
        !          3242:            assemble(srcea->data_const_off);
        !          3243:        } else {
        !          3244:            assemble(0x0F); assemble(0xA3 + 8*code);
        !          3245:            assemble(5 + srcea->data_reg*8);
        !          3246:            assemble_long(regs.regs + dstea->reg);
        !          3247:        }
        !          3248:     } else if (dstea->data_reg >= 0) {
        !          3249:        compile_force_byteorder(map, dstea->data_reg, BO_NORMAL, 0);
        !          3250:        if (srcea->data_reg == -2) {
        !          3251:            assemble(0x0F); assemble(0xBA); assemble(0xC0 + dstea->data_reg + 8*(4 + code));
        !          3252:            assemble(srcea->data_const_off);
        !          3253:        } else {
        !          3254:            assemble(0x0F); assemble(0xA3 + 8*code);
        !          3255:            assemble(0xC0 + dstea->data_reg + srcea->data_reg*8);
        !          3256:        }
        !          3257:        if (optype != i_BTST)
        !          3258:            map->x86_dirty[dstea->data_reg] = 1;
        !          3259:     } else {
        !          3260:        int addr_code = dstea->address_reg == -2 ? 5 : dstea->address_reg + 0x80;
        !          3261:        compile_force_byteorder(map, dstea->address_reg, BO_NORMAL, 0);
        !          3262:        /* We have an address in memory */
        !          3263:        if (dstea->data_reg != -1)
        !          3264:            printf("Things don't look good in handle_bit_insns\n");
        !          3265:        if (srcea->data_reg == -2) {
        !          3266:            assemble(0x0F); assemble(0xBA);
        !          3267:            assemble(addr_code + 8*(4 + code));
        !          3268:            assemble_long(address_space + dstea->addr_const_off);
        !          3269:            assemble(srcea->data_const_off);
        !          3270:        } else {
        !          3271:            assemble(0x0F); assemble(0xA3 + 8*code);
        !          3272:            assemble(addr_code + srcea->data_reg*8);
        !          3273:            assemble_long(address_space + dstea->addr_const_off);
        !          3274:        }
        !          3275: 
        !          3276:     }
        !          3277:     cc_status = CC_Z_FROM_86C;
        !          3278: }
        !          3279: 
        !          3280: static int do_rotshi = 1;
        !          3281: 
        !          3282: static void handle_rotshi(struct register_mapping *map, int iip,
        !          3283:                          uae_u8 *realpc, uaecptr current_addr, struct pid_undo *pud)
        !          3284: {
        !          3285:     struct ea_info eai;
        !          3286:     int amode_reg = insn_info[iip].dp->sreg;
        !          3287:     int amode_mode = insn_info[iip].dp->smode;
        !          3288:     wordsizes size = insn_info[iip].dp->size;
        !          3289:     int shiftcount;
        !          3290:     int mnemo = insn_info[iip].dp->mnemo;
        !          3291:     int shiftcode;
        !          3292:     int locked_eax_for_sahf = 0;
        !          3293: 
        !          3294:     switch(mnemo) {
        !          3295:      case i_ASLW: shiftcount = 1; mnemo = i_ASL; break;
        !          3296:      case i_ASRW: shiftcount = 1; mnemo = i_ASR; break;
        !          3297:      case i_LSLW: shiftcount = 1; mnemo = i_LSL; break;
        !          3298:      case i_LSRW: shiftcount = 1; mnemo = i_LSR; break;
        !          3299:      case i_ROLW: shiftcount = 1; mnemo = i_ROL; break;
        !          3300:      case i_RORW: shiftcount = 1; mnemo = i_ROR; break;
        !          3301:      case i_ROXLW:shiftcount = 1; mnemo = i_ROXL;break;
        !          3302:      case i_ROXRW:shiftcount = 1; mnemo = i_ROXR;break;
        !          3303:      default:
        !          3304:        amode_reg = insn_info[iip].dp->dreg;
        !          3305:        amode_mode = insn_info[iip].dp->dmode;
        !          3306:        shiftcount = insn_info[iip].dp->sreg;
        !          3307:        break;
        !          3308:     }
        !          3309:     if ((insn_info[iip].flags_live_at_end & CC68K_V) != 0) {
        !          3310:        if (mnemo == i_ASL) {
        !          3311:            generate_exit(map, insn_info[iip].address);
        !          3312:            printf("Can't handle this shift\n");
        !          3313:            return;
        !          3314:        } else if (mnemo == i_ASR || mnemo == i_LSR || mnemo == i_LSL) {
        !          3315:            remove_x86r_from_cache(map, r_EAX, 1);
        !          3316:            locked_eax_for_sahf = 1;
        !          3317:            lock_reg(map, r_EAX, 2);
        !          3318:        }
        !          3319: 
        !          3320:     }
        !          3321:     if (mnemo == i_ROXR || mnemo == i_ROXL) {
        !          3322:        remove_x86r_from_cache(map, r_EAX, 1);
        !          3323:        lock_reg(map, r_EAX, 2);
        !          3324:        compile_move_reg_from_mem_regoffs(r_AH, -2, 4 + (uae_u32)&regflags, sz_byte);
        !          3325:     }
        !          3326:     compile_prepare_undo(map, amode_mode, amode_reg, pud);
        !          3327:     compile_prepareea(map, amode_mode, amode_reg, size,
        !          3328:                      &realpc, current_addr,
        !          3329:                      &eai, 0, EA_LOAD|EA_STORE|EA_MODIFY, 1);
        !          3330: 
        !          3331:     generate_possible_exit(map, &eai, iip, pud);
        !          3332: 
        !          3333:     compile_fetchea(map, &eai, 0, 1);
        !          3334:     compile_force_byteorder(map, eai.data_reg, BO_NORMAL, 0);
        !          3335: 
        !          3336:     switch (mnemo) {
        !          3337:      case i_ASL:
        !          3338:        shiftcode = 4; cc_status = CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V | CC_X_FROM_86C;
        !          3339:        break;
        !          3340:      case i_LSL:
        !          3341:        shiftcode = 4; cc_status = CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V | CC_X_FROM_86C;
        !          3342:        break;
        !          3343:      case i_LSR:
        !          3344:        shiftcode = 5; cc_status = CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V | CC_X_FROM_86C;
        !          3345:        break;
        !          3346:      case i_ASR:
        !          3347:        shiftcode = 7; cc_status = CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V | CC_X_FROM_86C;
        !          3348:        break;
        !          3349:      case i_ROR:
        !          3350:        shiftcode = 1; cc_status = CC_AFTER_RO;
        !          3351:        break;
        !          3352:      case i_ROL:
        !          3353:        shiftcode = 0; cc_status = CC_AFTER_RO;
        !          3354:        break;
        !          3355:      case i_ROXL:
        !          3356:        shiftcode = 2; assemble(0x9E); /* SAHF */ cc_status = CC_AFTER_ROX; compile_unlock_reg(map, r_EAX);
        !          3357:        break;
        !          3358:      case i_ROXR:
        !          3359:        shiftcode = 3; assemble(0x9E); /* SAHF */ cc_status = CC_AFTER_ROX; compile_unlock_reg(map, r_EAX);
        !          3360:        break;
        !          3361:     }
        !          3362: 
        !          3363:     if (size == sz_word)
        !          3364:        assemble(0x66);
        !          3365:     assemble((shiftcount == 1 ? 0xD0 : 0xC0) + (size == sz_byte ? 0 : 1));
        !          3366:     assemble(shiftcode*8+0xC0 + eai.data_reg);
        !          3367:     if (shiftcount != 1) assemble(shiftcount);
        !          3368:     cc_offset = 0; cc_size = size; cc_reg = eai.data_reg;
        !          3369: 
        !          3370:     if (locked_eax_for_sahf) {
        !          3371:        /* The trick here is that the overflow flag isn't put into AH in SAHF */
        !          3372:        assemble(0x9E);
        !          3373:        assemble(0x0B); assemble(9*1 + 0xC0);
        !          3374:        assemble(0x9F);
        !          3375:        compile_unlock_reg(map, r_EAX);
        !          3376:     }
        !          3377:     compile_note_modify(map, &eai, 0);
        !          3378: }
        !          3379: 
        !          3380: static void handle_rotshi_variable(struct register_mapping *map, int iip,
        !          3381:                                   uae_u8 *realpc, uaecptr current_addr,
        !          3382:                                   struct pid_undo *pud)
        !          3383: {
        !          3384:     struct ea_info eais, eaid;
        !          3385:     int mnemo = insn_info[iip].dp->mnemo;
        !          3386:     int shiftcode;
        !          3387:     char *tmp1, *tmp2;
        !          3388:     int locked_eax_for_sahf = 0;
        !          3389: 
        !          3390:     remove_x86r_from_cache(map, r_ECX, 1);
        !          3391:     lock_reg(map, r_ECX, 2);
        !          3392: 
        !          3393:     if ((insn_info[iip].flags_live_at_end & CC68K_V) != 0) {
        !          3394:        if (mnemo == i_ASL) {
        !          3395:            generate_exit(map, insn_info[iip].address);
        !          3396:            printf("Can't handle this shift (var)\n");
        !          3397:            return;
        !          3398:        } else if (mnemo == i_ASR || mnemo == i_LSR || mnemo == i_LSL) {
        !          3399:            remove_x86r_from_cache(map, r_EAX, 1);
        !          3400:            locked_eax_for_sahf = 1;
        !          3401:            lock_reg(map, r_EAX, 2);
        !          3402:        }
        !          3403: 
        !          3404:     }
        !          3405:     if (mnemo == i_ROXR || mnemo == i_ROXL) {
        !          3406:        remove_x86r_from_cache(map, r_EAX, 1);
        !          3407:        lock_reg(map, r_EAX, 2);
        !          3408:        compile_move_reg_from_mem_regoffs(r_AH, -2, 4 + (uae_u32)&regflags,
        !          3409:                                          sz_byte);
        !          3410:     }
        !          3411:     /* Both src and dest are Dreg modes */
        !          3412:     compile_prepareea(map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg,
        !          3413:                      sz_long, &realpc, current_addr,
        !          3414:                      &eais, 0, EA_LOAD, 1);
        !          3415:     compile_prepareea(map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg,
        !          3416:                      insn_info[iip].dp->size, &realpc, current_addr,
        !          3417:                      &eaid, 0, EA_LOAD|EA_STORE|EA_MODIFY, 1);
        !          3418: 
        !          3419:     compile_fetchea(map, &eais, 0, 1);
        !          3420:     compile_fetchea(map, &eaid, 1, 1);
        !          3421:     compile_force_byteorder(map, eais.data_reg, BO_NORMAL, 0);
        !          3422:     compile_force_byteorder(map, eaid.data_reg, BO_NORMAL, 0);
        !          3423:     compile_move_reg_reg(r_ECX, eais.data_reg, sz_long);
        !          3424:     /* Test against zero, and test bit 6. If 1 <= count <= 31, we can do the
        !          3425:      * operation, otherwise, we have to exit */
        !          3426:     assemble(0xF6); assemble(0xC0 + r_ECX); assemble(0x1F);
        !          3427:     assemble(0x74); assemble(9);
        !          3428:     assemble(0xF6); assemble(0xC0 + r_ECX); assemble(0x20);
        !          3429: 
        !          3430:     assemble(0x0F); assemble(0x85); tmp1 = compile_here(); assemble_ulong(0);
        !          3431:     generate_exit(map, insn_info[iip].address);
        !          3432:     tmp2 = compile_here(); compile_org (tmp1); assemble_ulong((tmp2-tmp1) + 4); compile_org(tmp2);
        !          3433: 
        !          3434:     switch (mnemo) {
        !          3435:      case i_ASL:
        !          3436:        shiftcode = 4; cc_status = CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V | CC_X_FROM_86C;
        !          3437:        break;
        !          3438:      case i_LSL:
        !          3439:        shiftcode = 4; cc_status = CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V | CC_X_FROM_86C;
        !          3440:        break;
        !          3441:      case i_LSR:
        !          3442:        shiftcode = 5; cc_status = CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V | CC_X_FROM_86C;
        !          3443:        break;
        !          3444:      case i_ASR:
        !          3445:        shiftcode = 7; cc_status = CC_C_FROM_86C | CC_Z_FROM_86Z | CC_N_FROM_86N | CC_V_FROM_86V | CC_X_FROM_86C;
        !          3446:        break;
        !          3447:      case i_ROR:
        !          3448:        shiftcode = 1; cc_status = CC_AFTER_RO;
        !          3449:        break;
        !          3450:      case i_ROL:
        !          3451:        shiftcode = 0; cc_status = CC_AFTER_RO;
        !          3452:        break;
        !          3453:      case i_ROXL:
        !          3454:        shiftcode = 2; assemble(0x9E); /* SAHF */ cc_status = CC_AFTER_ROX; compile_unlock_reg(map, r_EAX);
        !          3455:        break;
        !          3456:      case i_ROXR:
        !          3457:        shiftcode = 3; assemble(0x9E); /* SAHF */ cc_status = CC_AFTER_ROX; compile_unlock_reg(map, r_EAX);
        !          3458:        break;
        !          3459:     }
        !          3460: 
        !          3461:     if (insn_info[iip].dp->size == sz_word)
        !          3462:        assemble(0x66);
        !          3463:     assemble(0xD2 + (insn_info[iip].dp->size == sz_byte ? 0 : 1));
        !          3464:     assemble(shiftcode*8+0xC0 + eaid.data_reg);
        !          3465:     cc_offset = 0; cc_size = insn_info[iip].dp->size; cc_reg = eaid.data_reg;
        !          3466: 
        !          3467:     if (locked_eax_for_sahf) {
        !          3468:        /* The trick here is that the overflow flag isn't put into AH in SAHF */
        !          3469:        assemble(0x9E);
        !          3470:        assemble(0x0B); assemble(9*1 + 0xC0);
        !          3471:        assemble(0x9F);
        !          3472:        compile_unlock_reg(map, r_EAX);
        !          3473:     }
        !          3474:     compile_note_modify(map, &eaid, 0);
        !          3475:     compile_unlock_reg(map, r_ECX);
        !          3476: }
        !          3477: 
        !          3478: static uae_u32 testmask = 0xFC0000, testval = 0xFC0000;
        !          3479: 
        !          3480: #ifndef USER_PROGRAMS_BEHAVE
        !          3481: #define USER_PROGRAMS_BEHAVE 0
        !          3482: #endif
        !          3483: 
        !          3484: static int m68k_compile_block(struct hash_block *hb)
        !          3485: {
        !          3486:     int movem_extra = 0;
        !          3487:     int last_iip = m68k_scan_block(hb, &movem_extra);
        !          3488:     struct register_mapping map;
        !          3489:     int i, iip, szflag;
        !          3490:     uae_u8 *realpc_start = NULL;
        !          3491:     struct bb_info *current_bb;
        !          3492:     int cc_status_for_bcc = CC_SAHF;
        !          3493:     struct insn_reg_needs reg_needs_init;
        !          3494: 
        !          3495:     cesp = 0;
        !          3496: 
        !          3497:     if (n_compiled > n_max_comp)
        !          3498:        return 1;
        !          3499:     else if (n_compiled++ == n_max_comp)
        !          3500:        printf("X\n");
        !          3501: 
        !          3502:     cc_status = 0; compile_failure = 0;
        !          3503: 
        !          3504:     /* Kickstart ROM address? */
        !          3505:     if ((hb->he_first->addr & 0xFC0000) != 0xFC0000
        !          3506:        && 0 && !patched_syscalls)
        !          3507:        return 1;
        !          3508: 
        !          3509:     exits_necessary = ((hb->he_first->addr & 0xFC0000) == 0xFC0000 || !USER_PROGRAMS_BEHAVE);
        !          3510: 
        !          3511:     if (alloc_code (hb, last_iip + movem_extra) == NULL) {
        !          3512:        hb->allocfailed = 1;
        !          3513:        return 0;
        !          3514:     }
        !          3515:     compile_org(hb->compile_start);
        !          3516:     compile_last_addr = (char *)hb->compile_start + hb->alloclen;
        !          3517: 
        !          3518:     /* m68k_scan_block() will leave this all set up */
        !          3519:     current_bb = bb_stack;
        !          3520: 
        !          3521:     for (i = 0; i < 8; i++) {
        !          3522:        map.dreg_map[i] = map.areg_map[i] = -1;
        !          3523:        map.x86_dirty[i] = 0;
        !          3524:        map.x86_cache_reg[i] = -1;
        !          3525:        map.x86_cr_type[i] = 0;
        !          3526:        map.x86_const_offset[i] = 0;
        !          3527:        map.x86_verified[i] = 0;
        !          3528:        map.x86_byteorder[i] = BO_NORMAL;
        !          3529:     }
        !          3530: 
        !          3531:     reg_needs_init.checkpoint_no = 0;
        !          3532:     for (i = 0; i < 8; i++) {
        !          3533:        reg_needs_init.dreg_needed[i] = reg_needs_init.areg_needed[i] = -1;
        !          3534:        reg_needs_init.dreg_mask[i] = reg_needs_init.areg_mask[i] = ALL_X86_REGS;
        !          3535:     }
        !          3536: 
        !          3537:     for (iip = 0; iip < last_iip && !compile_failure; iip++) {
        !          3538:        uae_u8 *realpc;
        !          3539:        struct ea_info eainfo[8];
        !          3540:        uaecptr current_addr;
        !          3541:        struct pid_undo pub;
        !          3542:        struct insn_reg_needs this_reg_needs = reg_needs_init;
        !          3543: 
        !          3544:        /* Set up locks for a new insn. We don't bother to clear this
        !          3545:         * properly after compiling one insn. */
        !          3546:        for (i = 0; i < 8; i++) {
        !          3547:            map.x86_users[i] = i == r_ESP ? 1 : 0;
        !          3548:            map.x86_locked[i] = i == r_ESP ? 2 : 0;
        !          3549:        }
        !          3550: 
        !          3551:        pub.used = 0;
        !          3552:        current_addr = insn_info[iip].address + 2;
        !          3553: 
        !          3554:        if (iip == current_bb->first_iip) {
        !          3555:            sync_reg_cache(&map, 1);
        !          3556:            if (!quiet_compile)
        !          3557:                printf("Compiling %08lx\n", current_bb->h->addr);
        !          3558: 
        !          3559:            realpc_start = get_real_address(current_bb->h->addr);
        !          3560:            current_bb->h->execute = (code_execfunc)compile_here();
        !          3561:            current_bb->h->matchword = *(uae_u32 *)realpc_start;
        !          3562:            cc_status_for_bcc = CC_SAHF;
        !          3563:        }
        !          3564: 
        !          3565:        realpc = realpc_start + (current_addr - current_bb->h->addr);
        !          3566: 
        !          3567:        insn_info[iip].compiled_jumpaddr = compile_here();
        !          3568:        insn_info[iip].compiled_fillin = NULL;
        !          3569: 
        !          3570:        if (insn_info[iip].jump_target) {
        !          3571:            if (cesp == CE_STACK_SIZE) {
        !          3572:                generate_exit(NULL, insn_info[iip].address);
        !          3573:                compile_failure = 1;
        !          3574:            } else {
        !          3575:                assemble(0xFE); assemble(0x05 + 8*1); assemble_long(&nr_bbs_to_run);
        !          3576:                assemble(0x0F); assemble(0x84); /* JE finish */
        !          3577:                compile_exit_stack[cesp].noflush = 1;
        !          3578:                compile_exit_stack[cesp].address = current_bb->h;
        !          3579:                compile_exit_stack[cesp].jmpoffs = compile_here();
        !          3580:                assemble_ulong(0);
        !          3581:                cesp++;
        !          3582:            }
        !          3583:        }
        !          3584:        /*
        !          3585:         * This will sort out all insns we can't compile, including
        !          3586:         * jumps out of this block */
        !          3587:        if (insn_info[iip].stop_translation == 1) {
        !          3588:            generate_exit(&map, insn_info[iip].address);
        !          3589:            cc_status = 0;
        !          3590:        } else switch (insn_info[iip].dp->mnemo) {
        !          3591:         case i_NOP:
        !          3592:            cc_status = 0;
        !          3593:            if (!quiet_compile)
        !          3594:                printf("Compiling a NOP\n");
        !          3595:            break;
        !          3596: 
        !          3597:         case i_RTS:
        !          3598:            sync_reg_cache(&map, 1);
        !          3599:            lock_reg(&map, r_ECX, 2);
        !          3600:            lock_reg(&map, r_EBX, 2);
        !          3601:            {
        !          3602:                char *tmp1, *tmp2, *tmp3;
        !          3603: 
        !          3604:                /* fetch (A7) */
        !          3605:                assemble(0x8B); assemble(0x5 + r_EBX*8); assemble_long(regs.regs + 15);
        !          3606:                assemble(0x8B); assemble(0x80 + 9*r_EBX); assemble_long(address_space);
        !          3607:                assemble(0x0F); /* bswapl x86r */
        !          3608:                assemble(0xC8 + r_EBX);
        !          3609:                /* fetch jsr_num */
        !          3610:                assemble(0x8B); assemble(0x5 + r_ECX*8); assemble_long(&jsr_num);
        !          3611:                assemble(0x09); assemble(0xC0 + 9*r_ECX);
        !          3612:                assemble(0x0F); assemble(0x84); tmp1 = compile_here(); assemble_ulong(0);
        !          3613:                assemble(0xFF); assemble(1*8 + 0xC0 + r_ECX);
        !          3614:                /* cmpl %ebx,disp32(,%ecx,4) */
        !          3615:                assemble(0x39); assemble(0x04 + 8*r_EBX); assemble(0x8d);
        !          3616:                assemble_long(jsr_rets);
        !          3617:                assemble(0x0F); assemble(0x85); tmp2 = compile_here(); assemble_ulong(0);
        !          3618:                /* movl disp32(,%ecx,4),%ebx */
        !          3619:                assemble(0x8B); assemble(0x04 + 8*r_EBX); assemble(0x8d);
        !          3620:                assemble_long(jsr_hash);
        !          3621:                /* movl execute(%ebx), %ebx */
        !          3622:                assemble(0x8B); assemble(0x040 + 9*r_EBX); assemble((int)&((struct hash_entry *)0)->execute);
        !          3623:                assemble(0x09); assemble(0xC0 + 9*r_EBX);
        !          3624:                assemble(0x0F); assemble(0x85); tmp3 = compile_here(); assemble_ulong(0);
        !          3625:                compile_org(tmp1); assemble_ulong(tmp3 - tmp1);
        !          3626:                compile_org(tmp2); assemble_ulong(tmp3 - tmp2);
        !          3627:                compile_org(tmp3 + 4);
        !          3628:                generate_exit(&map, insn_info[iip].address);
        !          3629:                tmp1 = compile_here();
        !          3630:                compile_org(tmp3); assemble_ulong((tmp1-tmp3)-4);
        !          3631:                compile_org(tmp1);
        !          3632:                assemble(0x89); assemble(0x5 + r_ECX*8); assemble_long(&jsr_num);
        !          3633:                assemble(0x83); assemble(0x05 + 5*8); assemble_long(regs.regs + 15); assemble(-4);
        !          3634:                /* Off we go */
        !          3635:                assemble(0xFF); assemble(4*8 + 0xC0 + r_EBX);
        !          3636:            }
        !          3637:            break;
        !          3638: 
        !          3639:         case i_JMP:
        !          3640:            sync_reg_cache(&map, 1);
        !          3641:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          3642:                              insn_info[iip].dp->sreg,
        !          3643:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          3644:                              eainfo, 0, EA_LOAD, 1);
        !          3645:            {
        !          3646:                char *tmp1, *tmp2, *tmp3;
        !          3647: 
        !          3648:                struct hash_entry *tmph;
        !          3649:                if (eainfo[0].address_reg != -2 || (tmph = get_hash_for_func(eainfo[0].addr_const_off, 1)) == 0) {
        !          3650:                    if (eainfo[0].address_reg != -2 && !quiet_compile)
        !          3651:                        printf("Can't compile indirect JMP\n");
        !          3652:                    generate_exit(&map, insn_info[iip].address);
        !          3653:                    break;
        !          3654:                }
        !          3655:                /* check whether the destination has compiled code */
        !          3656:                assemble(0x8B); assemble(r_EBX*8 + 0x05); assemble_long(&(tmph->execute));
        !          3657:                assemble(0x09); assemble(0xC0 + 9*r_EBX);
        !          3658:                assemble(0x0F); assemble(0x85); tmp1 = compile_here(); assemble_ulong(0);
        !          3659:                generate_exit(&map, insn_info[iip].address);
        !          3660:                tmp2 = compile_here(); compile_org(tmp1);
        !          3661:                assemble_ulong((tmp2 - tmp1) - 4);
        !          3662:                compile_org(tmp2);
        !          3663:                /* Off we go */
        !          3664:                assemble(0xFF); assemble(4*8 + 0xC0 + r_EBX);
        !          3665:            }
        !          3666:            cc_status = 0;
        !          3667:            break;
        !          3668: 
        !          3669:         case i_JSR:
        !          3670:            sync_reg_cache(&map, 1);
        !          3671:            lock_reg(&map, r_ECX, 2);
        !          3672:            lock_reg(&map, r_EBX, 2);
        !          3673:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          3674:                              insn_info[iip].dp->sreg,
        !          3675:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          3676:                              eainfo, 0, EA_LOAD, 1);
        !          3677:            {
        !          3678:                char *tmp1, *tmp2, *tmp3;
        !          3679: 
        !          3680:                struct hash_entry *tmph;
        !          3681:                if (eainfo[0].address_reg != -2 || (tmph = get_hash_for_func(eainfo[0].addr_const_off, 1)) == 0) {
        !          3682:                    if (eainfo[0].address_reg != -2 && !quiet_compile)
        !          3683:                        printf("Can't compile indirect JSR\n");
        !          3684:                    generate_exit(&map, insn_info[iip].address);
        !          3685:                    break;
        !          3686:                }
        !          3687:                assert(iip + 1 < last_iip);
        !          3688:                assert(iip == current_bb->last_iip);
        !          3689:                /* check whether the destination has compiled code */
        !          3690:                assemble(0x8B); assemble(r_EBX*8 + 0x05); assemble_long(&(tmph->execute));
        !          3691:                assemble(0x09); assemble(0xC0 + 9*r_EBX);
        !          3692:                assemble(0x0F); assemble(0x84); tmp3 = compile_here(); assemble_ulong(0);
        !          3693:                /* check for stack overflow */
        !          3694:                assemble(0x8B); assemble(r_ECX*8 + 0x05); assemble_long(&jsr_num);
        !          3695:                assemble(0xF7); assemble(0xC0+r_ECX); assemble_ulong(MAX_JSRS);
        !          3696:                assemble(0x0F); assemble(0x84); tmp1 = compile_here(); assemble_ulong(0);
        !          3697:                generate_exit(&map, insn_info[iip].address);
        !          3698:                tmp2 = compile_here(); compile_org(tmp1); assemble_ulong((tmp2 - tmp1) - 4);
        !          3699:                compile_org(tmp3); assemble_ulong(tmp1-tmp3);
        !          3700:                compile_org(tmp2);
        !          3701:                /* movl $something,disp32(,%ecx,4) */
        !          3702:                assemble(0xC7); assemble(0x04); assemble(0x8d);
        !          3703:                assemble_long(jsr_rets); assemble_ulong(insn_info[iip+1].address);
        !          3704:                assemble(0xC7); assemble(0x04); assemble(0x8d);
        !          3705:                assemble_long(jsr_hash); assemble_long((current_bb + 1)->h);
        !          3706:                /* incl jsr_num */
        !          3707:                assemble(0xFF); assemble(0x05); assemble_long(&jsr_num);
        !          3708:                /* Put things on the 68k stack */
        !          3709:                assemble(0x83); assemble(0x05 + 5*8); assemble_long(regs.regs + 15); assemble(4);
        !          3710:                assemble(0x8B); assemble(r_ECX*8+ 0x05); assemble_long(regs.regs + 15);
        !          3711:                assemble(0xC7); assemble(0x80 + r_ECX); assemble_long(address_space);
        !          3712:                assemble_ulong_68k(insn_info[iip+1].address);
        !          3713:                /* Off we go */
        !          3714:                assemble(0xFF); assemble(4*8 + 0xC0 + r_EBX);
        !          3715:            }
        !          3716:            break;
        !          3717: 
        !          3718:         case i_BSR:
        !          3719:            sync_reg_cache(&map, 1);
        !          3720:            lock_reg(&map, r_ECX, 2);
        !          3721:            lock_reg(&map, r_EBX, 2);
        !          3722:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          3723:                              insn_info[iip].dp->sreg,
        !          3724:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          3725:                              eainfo, 0, EA_LOAD, 1);
        !          3726:            {
        !          3727:                char *tmp1, *tmp2, *tmp3;
        !          3728:                uaecptr dest = insn_info[iip].address + 2 + (uae_s32)eainfo[0].data_const_off;
        !          3729:                struct hash_entry *tmph;
        !          3730:                if ((tmph = get_hash_for_func(dest, 1)) == 0) {
        !          3731:                    generate_exit(&map, insn_info[iip].address);
        !          3732:                    break;
        !          3733:                }
        !          3734:                assert(iip + 1 < last_iip);
        !          3735:                assert(iip == current_bb->last_iip);
        !          3736: 
        !          3737:                /* check whether the destination has compiled code */
        !          3738:                assemble(0x8B); assemble(r_EBX*8 + 0x05); assemble_long(&(tmph->execute));
        !          3739:                assemble(0x09); assemble(0xC0 + 9*r_EBX);
        !          3740:                assemble(0x0F); assemble(0x84); tmp3 = compile_here(); assemble_ulong(0);
        !          3741:                /* check for stack overflow */
        !          3742:                assemble(0x8B); assemble(r_ECX*8 + 0x05); assemble_long(&jsr_num);
        !          3743:                assemble(0xF7); assemble(0xC0+r_ECX); assemble_ulong(MAX_JSRS);
        !          3744:                assemble(0x0F); assemble(0x84); tmp1 = compile_here(); assemble_ulong(0);
        !          3745:                generate_exit(&map, insn_info[iip].address);
        !          3746:                tmp2 = compile_here(); compile_org(tmp1); assemble_ulong((tmp2 - tmp1) - 4);
        !          3747:                compile_org(tmp3); assemble_ulong(tmp1-tmp3);
        !          3748:                compile_org(tmp2);
        !          3749:                /* movl $something,disp32(,%ecx,4) */
        !          3750:                assemble(0xC7); assemble(0x04); assemble(0x8d);
        !          3751:                assemble_long(jsr_rets); assemble_ulong(insn_info[iip+1].address);
        !          3752:                assemble(0xC7); assemble(0x04); assemble(0x8d);
        !          3753:                assemble_long(jsr_hash); assemble_long((current_bb + 1)->h);
        !          3754:                /* incl jsr_num */
        !          3755:                assemble(0xFF); assemble(0x05); assemble_long(&jsr_num);
        !          3756:                /* Put things on the 68k stack */
        !          3757:                assemble(0x83); assemble(0x05 + 5*8); assemble_long(regs.regs + 15); assemble(4);
        !          3758:                assemble(0x8B); assemble(r_ECX*8+ 0x05); assemble_long(regs.regs + 15);
        !          3759:                assemble(0xC7); assemble(0x80 + r_ECX); assemble_long(address_space);
        !          3760:                assemble_ulong_68k(insn_info[iip+1].address);
        !          3761:                /* Off we go */
        !          3762:                assemble(0xFF); assemble(4*8 + 0xC0 + r_EBX);
        !          3763:            }
        !          3764:            break;
        !          3765: 
        !          3766:         case i_Bcc:
        !          3767:            sync_reg_cache(&map, 0);
        !          3768:            compile_handle_bcc(&map, iip, cc_status_for_bcc);
        !          3769:            cc_status = 0;
        !          3770:            break;
        !          3771: 
        !          3772:         case i_DBcc:
        !          3773:            sync_reg_cache(&map, 0);
        !          3774:            remove_x86r_from_cache(&map, map.dreg_map[insn_info[iip].dp->sreg], 1);
        !          3775:            compile_handle_dbcc(&map, iip, cc_status_for_bcc,
        !          3776:                                insn_info[iip].dp->sreg);
        !          3777:            cc_status = 0;
        !          3778:            break;
        !          3779: #if 0
        !          3780:         case i_Scc:
        !          3781:            compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub);
        !          3782:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          3783:                              insn_info[iip].dp->sreg,
        !          3784:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          3785:                              eainfo, 0, EA_STORE, 1);
        !          3786: 
        !          3787:            generate_possible_exit(&map, eainfo, iip, &pub);
        !          3788:            srcreg2 = get_;
        !          3789:            compile_note_modify(&map, eainfo, 0);
        !          3790: 
        !          3791:            cc_status = 0;
        !          3792:            break;
        !          3793: #endif
        !          3794:         case i_ADD:
        !          3795:         case i_SUB:
        !          3796:         case i_CMP:
        !          3797:         case i_CMPM:
        !          3798:            compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub);
        !          3799:            compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub);
        !          3800:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          3801:                              insn_info[iip].dp->sreg,
        !          3802:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          3803:                              eainfo, 0, EA_LOAD, 1);
        !          3804:            compile_prepareea(&map, insn_info[iip].dp->dmode,
        !          3805:                              insn_info[iip].dp->dreg,
        !          3806:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          3807:                              eainfo, 1,
        !          3808:                              (insn_info[iip].dp->mnemo == i_ADD || insn_info[iip].dp->mnemo == i_SUB
        !          3809:                               ? EA_MODIFY | EA_LOAD | EA_STORE
        !          3810:                               : EA_LOAD | EA_STORE), 1);
        !          3811: 
        !          3812:            generate_possible_exit(&map, eainfo, iip, &pub);
        !          3813:            generate_possible_exit(&map, eainfo+1, iip, &pub);
        !          3814: 
        !          3815:            compile_loadeas(&map, eainfo, 0, 1, binop_alternatives, 0, 1);
        !          3816: 
        !          3817:            switch (insn_info[iip].dp->mnemo) {
        !          3818:             case i_ADD: compile_eas(&map, eainfo, 0, 1, 0); break;
        !          3819:             case i_SUB: compile_eas(&map, eainfo, 0, 1, 5); break;
        !          3820:             case i_CMP: case i_CMPM: compile_eas(&map, eainfo, 0, 1, 7); break;
        !          3821:            }
        !          3822: 
        !          3823:            if (insn_info[iip].dp->mnemo != i_CMP && insn_info[iip].dp->mnemo != i_CMPM)
        !          3824:                compile_note_modify(&map, eainfo, 1);
        !          3825:            switch (insn_info[iip].dp->mnemo) {
        !          3826:             case i_ADD:
        !          3827:             case i_SUB:
        !          3828:                cc_status = CC_X_FROM_86C | CC_Z_FROM_86Z | CC_C_FROM_86C | CC_V_FROM_86V | CC_N_FROM_86N;
        !          3829:                break;
        !          3830:             case i_CMP:
        !          3831:             case i_CMPM:
        !          3832:                cc_status = CC_Z_FROM_86Z | CC_C_FROM_86C | CC_V_FROM_86V | CC_N_FROM_86N;
        !          3833:                break;
        !          3834:            }
        !          3835:            break;
        !          3836: 
        !          3837:         case i_ADDX:
        !          3838:         case i_SUBX:
        !          3839:            compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub);
        !          3840:            compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub);
        !          3841:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          3842:                              insn_info[iip].dp->sreg,
        !          3843:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          3844:                              eainfo, 0, EA_LOAD, 1);
        !          3845:            compile_prepareea(&map, insn_info[iip].dp->dmode,
        !          3846:                              insn_info[iip].dp->dreg,
        !          3847:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          3848:                              eainfo, 1, EA_MODIFY | EA_LOAD | EA_STORE, 1);
        !          3849: 
        !          3850:            generate_possible_exit(&map, eainfo, iip, &pub);
        !          3851:            generate_possible_exit(&map, eainfo+1, iip, &pub);
        !          3852: 
        !          3853:            compile_loadeas(&map, eainfo, 0, 1, binop_alternatives, 0, 1);
        !          3854: 
        !          3855:            /* bt $0, regflags+4 ; get carry */
        !          3856:            assemble(0x0F); assemble(0xBA); assemble(0x5+4*8);
        !          3857:            assemble_ulong(4 + (uae_u32)&regflags); assemble(0);
        !          3858: 
        !          3859:            switch (insn_info[iip].dp->mnemo) {
        !          3860:             case i_ADDX: compile_eas(&map, eainfo, 0, 1, 2); break;
        !          3861:             case i_SUBX: compile_eas(&map, eainfo, 0, 1, 3); break;
        !          3862:            }
        !          3863:            compile_note_modify(&map, eainfo, 1);
        !          3864: 
        !          3865:            if (insn_info[iip].flags_live_at_end & CC68K_Z) {
        !          3866:                /* Darn. */
        !          3867:                int tmpr = get_free_x86_register(&map, ALL_X86_REGS);
        !          3868:                /* pushfl; popl tmpr */
        !          3869:                assemble(0x9C); assemble(0x58+tmpr);
        !          3870:                /* Magic! */
        !          3871:                /* andl tmpr, regflags; andl $~0x40,tmpr; orl tmpr, regflags */
        !          3872:                assemble(0x21); assemble(0x05 + 8*tmpr); assemble_long(&regflags);
        !          3873:                assemble(0x81); assemble(0xC0 + 8*4 + tmpr); assemble_ulong(~0x40);
        !          3874:                assemble(0x09); assemble(0x05 + 8*tmpr); assemble_long(&regflags);
        !          3875:                compile_move_reg_to_mem_regoffs(-2, 4 + (uae_u32)&regflags, tmpr, sz_long);
        !          3876:                cc_status = 0;
        !          3877:            } else {
        !          3878:                /* Lies! */
        !          3879:                cc_status = CC_X_FROM_86C | CC_Z_FROM_86Z |CC_C_FROM_86C |CC_V_FROM_86V |CC_N_FROM_86N;
        !          3880:            }
        !          3881:            break;
        !          3882: 
        !          3883:         case i_MULU:
        !          3884:         case i_MULS:
        !          3885:            compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub);
        !          3886:            compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub);
        !          3887:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          3888:                              insn_info[iip].dp->sreg,
        !          3889:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          3890:                              eainfo, 0, EA_LOAD, 1);
        !          3891:            compile_prepareea(&map, insn_info[iip].dp->dmode,
        !          3892:                              insn_info[iip].dp->dreg,
        !          3893:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          3894:                              eainfo, 1, EA_MODIFY | EA_LOAD | EA_STORE, 1);
        !          3895: 
        !          3896:            generate_possible_exit(&map, eainfo, iip, &pub);
        !          3897:            generate_possible_exit(&map, eainfo+1, iip, &pub);
        !          3898: 
        !          3899:            compile_loadeas(&map, eainfo, 0, 1, regonly_alternatives, 0, 1);
        !          3900: 
        !          3901:            /* Extend the regs properly */
        !          3902:            remove_x86r_from_cache(&map, eainfo[0].data_reg, 0);
        !          3903:            switch (insn_info[iip].dp->mnemo) {
        !          3904:             case i_MULU:
        !          3905:                assemble(0x81); assemble(0xC0+4*8 + eainfo[0].data_reg); assemble_ulong(0xFFFF);
        !          3906:                assemble(0x81); assemble(0xC0+4*8 + eainfo[1].data_reg); assemble_ulong(0xFFFF);
        !          3907:                break;
        !          3908:             case i_MULS:
        !          3909:                assemble(0x0F); assemble(0xBF); assemble(0xC0 + 9*eainfo[0].data_reg);
        !          3910:                assemble(0x0F); assemble(0xBF); assemble(0xC0 + 9*eainfo[1].data_reg);
        !          3911:                break;
        !          3912:            }
        !          3913:            /* and multiply */
        !          3914:            assemble(0x0F); assemble(0xAF); assemble(0xC0 + 8*eainfo[1].data_reg + eainfo[0].data_reg);
        !          3915:            compile_note_modify(&map, eainfo, 1);
        !          3916:            cc_status = CC_TEST_REG;
        !          3917:            cc_reg = eainfo[1].data_reg;
        !          3918:            cc_offset = 0;
        !          3919:            cc_size = sz_long;
        !          3920:            break;
        !          3921: 
        !          3922:         case i_ADDA:
        !          3923:         case i_SUBA:
        !          3924:         case i_CMPA:
        !          3925:            compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub);
        !          3926:            compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub);
        !          3927:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          3928:                              insn_info[iip].dp->sreg,
        !          3929:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          3930:                              eainfo, 0, EA_LOAD, 1);
        !          3931:            compile_prepareea(&map, insn_info[iip].dp->dmode,
        !          3932:                              insn_info[iip].dp->dreg,
        !          3933:                              sz_long, &realpc, current_addr,
        !          3934:                              eainfo, 1,
        !          3935:                              (insn_info[iip].dp->mnemo == i_ADDA || insn_info[iip].dp->mnemo == i_SUBA
        !          3936:                               ? EA_MODIFY | EA_LOAD | EA_STORE
        !          3937:                               : EA_LOAD | EA_STORE),
        !          3938:                              1);
        !          3939: 
        !          3940:            generate_possible_exit(&map, eainfo, iip, &pub);
        !          3941: 
        !          3942:            compile_loadeas(&map, eainfo, 0, 1,
        !          3943:                            insn_info[iip].dp->size == sz_word ? binop_worda_alternatives : binop_alternatives,
        !          3944:                            0, 1);
        !          3945: 
        !          3946:            if (insn_info[iip].dp->size == sz_word) {
        !          3947:                remove_x86r_from_cache(&map, eainfo[0].data_reg, 0);
        !          3948:                compile_extend_long(&map, eainfo[0].data_reg, sz_word);
        !          3949:            }
        !          3950:            eainfo[0].size = sz_long;
        !          3951: 
        !          3952:            switch (insn_info[iip].dp->mnemo) {
        !          3953:             case i_ADDA: compile_eas(&map, eainfo, 0, 1, 0); break;
        !          3954:             case i_SUBA: compile_eas(&map, eainfo, 0, 1, 5); break;
        !          3955:             case i_CMPA: compile_eas(&map, eainfo, 0, 1, 7); break;
        !          3956:            }
        !          3957: 
        !          3958:            if (insn_info[iip].dp->mnemo == i_CMPA) {
        !          3959:                cc_status = CC_Z_FROM_86Z |CC_C_FROM_86C |CC_V_FROM_86V |CC_N_FROM_86N;
        !          3960:            } else {
        !          3961:                compile_note_modify(&map, eainfo, 1);
        !          3962:                cc_status = 0;
        !          3963:            }
        !          3964:            break;
        !          3965: 
        !          3966:         case i_MOVE:
        !          3967:            compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub);
        !          3968:            compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub);
        !          3969:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          3970:                              insn_info[iip].dp->sreg,
        !          3971:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          3972:                              eainfo, 0, EA_LOAD, 1);
        !          3973:            compile_prepareea(&map, insn_info[iip].dp->dmode,
        !          3974:                              insn_info[iip].dp->dreg,
        !          3975:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          3976:                              eainfo, 1, EA_STORE, 1);
        !          3977: 
        !          3978:            generate_possible_exit(&map, eainfo, iip, &pub);
        !          3979:            generate_possible_exit(&map, eainfo + 1, iip, &pub);
        !          3980: 
        !          3981:            compile_loadeas(&map, eainfo, 0, 1, binop_alternatives, 1, 0);
        !          3982:            compile_storeea(&map, eainfo, 0, 1);
        !          3983: 
        !          3984:            if (eainfo[0].data_reg == -2) {
        !          3985:                cc_status = CC_TEST_REG;
        !          3986:                cc_reg = -2;
        !          3987:                cc_offset = eainfo[0].data_const_off;
        !          3988:            } else if (eainfo[0].data_reg == -1) {
        !          3989:                if (eainfo[1].data_reg == -1)
        !          3990:                    printf("Don't know where to get flags from\n");
        !          3991:                cc_status = CC_TEST_REG;
        !          3992:                cc_offset = 0;
        !          3993:                cc_reg = eainfo[1].data_reg;
        !          3994:            } else {
        !          3995:                cc_status = CC_TEST_REG;
        !          3996:                cc_reg = eainfo[0].data_reg;
        !          3997:                cc_offset = 0;
        !          3998:            }
        !          3999:            cc_size = eainfo[0].size;
        !          4000: 
        !          4001:            break;
        !          4002: 
        !          4003:         case i_MOVEA:
        !          4004:            compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub);
        !          4005:            compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub);
        !          4006:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          4007:                              insn_info[iip].dp->sreg,
        !          4008:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          4009:                              eainfo, 0, EA_LOAD, 1);
        !          4010:            compile_prepareea(&map, insn_info[iip].dp->dmode,
        !          4011:                              insn_info[iip].dp->dreg,
        !          4012:                              sz_long, &realpc, current_addr,
        !          4013:                              eainfo, 1, EA_STORE, 1);
        !          4014: 
        !          4015:            generate_possible_exit(&map, eainfo, iip, &pub);
        !          4016: 
        !          4017:            compile_loadeas(&map, eainfo, 0, 1,
        !          4018:                            insn_info[iip].dp->size == sz_word ? binop_worda_alternatives : binop_alternatives,
        !          4019:                            0, 0);
        !          4020: 
        !          4021:            if (insn_info[iip].dp->size == sz_word) {
        !          4022:                remove_x86r_from_cache(&map, eainfo[0].data_reg, 0);
        !          4023:                compile_extend_long(&map, eainfo[0].data_reg, sz_word);
        !          4024:            }
        !          4025:            eainfo[0].size = sz_long;
        !          4026: 
        !          4027:            compile_storeea(&map, eainfo, 0, 1);
        !          4028: 
        !          4029:            cc_status = 0;
        !          4030:            break;
        !          4031: 
        !          4032:         case i_EXG:
        !          4033:            if (insn_info[iip].dp->smode != insn_info[iip].dp->dmode
        !          4034:                || insn_info[iip].dp->sreg != insn_info[iip].dp->dreg)
        !          4035:            {
        !          4036:                compile_prepareea(&map, insn_info[iip].dp->smode,
        !          4037:                                  insn_info[iip].dp->sreg,
        !          4038:                                  sz_long, &realpc, current_addr,
        !          4039:                                  eainfo, 0, EA_LOAD|EA_STORE, 1);
        !          4040:                compile_prepareea(&map, insn_info[iip].dp->dmode,
        !          4041:                                  insn_info[iip].dp->dreg,
        !          4042:                                  sz_long, &realpc, current_addr,
        !          4043:                                  eainfo, 1, EA_LOAD|EA_STORE, 1);
        !          4044: 
        !          4045:                compile_loadeas(&map, eainfo, 0, 1, regonly_alternatives, 0, 1);
        !          4046:                compile_storeea(&map, eainfo, 1, 0);
        !          4047:                compile_storeea(&map, eainfo, 0, 1);
        !          4048:            }
        !          4049: 
        !          4050:            cc_status = 0;
        !          4051:            break;
        !          4052: 
        !          4053:         case i_LINK:
        !          4054:            compile_prepare_undo(&map, Apdi, 7, &pub);
        !          4055:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          4056:                              insn_info[iip].dp->sreg,
        !          4057:                              sz_long, &realpc, current_addr,
        !          4058:                              eainfo, 0, EA_LOAD|EA_STORE, 1);
        !          4059:            compile_prepareea(&map, insn_info[iip].dp->dmode,
        !          4060:                              insn_info[iip].dp->dreg,
        !          4061:                              sz_long, &realpc, current_addr,
        !          4062:                              eainfo, 1, EA_LOAD, 1);
        !          4063:            compile_prepareea(&map, Apdi, 7, sz_long, &realpc, current_addr,
        !          4064:                              eainfo, 2, EA_STORE, 1);
        !          4065: 
        !          4066:            generate_possible_exit(&map, eainfo+2, iip, &pub);
        !          4067: 
        !          4068:            compile_fetchea(&map, eainfo, 0, 1);
        !          4069:            /* we know this is a constant - no need to fetch it*/
        !          4070:            /* compile_fetchea(&map, eainfo, 1); */
        !          4071:            compile_storeea(&map, eainfo, 0, 2); /* An -> -(A7) */
        !          4072: 
        !          4073:            compile_prepareea(&map, Areg, 7, sz_long, &realpc, current_addr,
        !          4074:                              eainfo, 3, EA_STORE, 1);
        !          4075:            compile_fetchea(&map, eainfo, 3, 1);
        !          4076:            compile_storeea(&map, eainfo, 3, 0); /* A7 -> An */
        !          4077: 
        !          4078:            /* @@@ 020 */
        !          4079:            compile_prepareea(&map, Areg, 7, sz_long, &realpc, current_addr,
        !          4080:                              eainfo, 4, EA_LOAD, 1);
        !          4081:            compile_prepareea(&map, Areg, 7, sz_long, &realpc, current_addr,
        !          4082:                              eainfo, 5, EA_STORE, 1);
        !          4083:            compile_fetchea(&map, eainfo, 4, 1);
        !          4084:            eainfo[4].data_const_off += (uae_s16)eainfo[1].data_const_off;
        !          4085:            compile_storeea(&map, eainfo, 4, 5); /* A7+off -> A7 */
        !          4086:            cc_status = 0;
        !          4087:            break;
        !          4088: 
        !          4089:         case i_UNLK:
        !          4090:            compile_prepareea(&map, Areg,
        !          4091:                              insn_info[iip].dp->sreg,
        !          4092:                              sz_long, &realpc, current_addr,
        !          4093:                              eainfo, 0, EA_LOAD, 1);
        !          4094:            compile_prepareea(&map, Areg, 7, sz_long, &realpc, current_addr,
        !          4095:                              eainfo, 1, EA_STORE, 1);
        !          4096: 
        !          4097:            generate_possible_exit(&map, eainfo + 0, iip, &pub);
        !          4098: 
        !          4099:            compile_fetchea(&map, eainfo, 0, 1);
        !          4100:            compile_storeea(&map, eainfo, 0, 1);
        !          4101: 
        !          4102:            /* The Apdi could of course point to a non-memory area, but undos
        !          4103:             * are difficult here, and anyway: which program does evil hacks
        !          4104:             * with UNLK? */
        !          4105:            compile_prepareea(&map, Aipi, 7, sz_long, &realpc, current_addr,
        !          4106:                              eainfo, 2, EA_LOAD, 1);
        !          4107:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          4108:                              insn_info[iip].dp->sreg,
        !          4109:                              sz_long, &realpc, current_addr,
        !          4110:                              eainfo, 3, EA_STORE, 1);
        !          4111:            compile_fetchea(&map, eainfo, 2, 1);
        !          4112:            compile_storeea(&map, eainfo, 2, 3);
        !          4113: 
        !          4114:            cc_status = 0;
        !          4115:            break;
        !          4116: 
        !          4117:         case i_OR:
        !          4118:         case i_AND:
        !          4119:         case i_EOR:
        !          4120:            compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub);
        !          4121:            compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub);
        !          4122:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          4123:                              insn_info[iip].dp->sreg,
        !          4124:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          4125:                              eainfo, 0, EA_LOAD, 1);
        !          4126:            compile_prepareea(&map, insn_info[iip].dp->dmode,
        !          4127:                              insn_info[iip].dp->dreg,
        !          4128:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          4129:                              eainfo, 1, EA_MODIFY | EA_LOAD | EA_STORE, 1);
        !          4130: 
        !          4131:            generate_possible_exit(&map, eainfo, iip, &pub);
        !          4132:            generate_possible_exit(&map, eainfo + 1, iip, &pub);
        !          4133: 
        !          4134:            compile_loadeas(&map, eainfo, 0, 1, binop_alternatives, 0, 1);
        !          4135: 
        !          4136:            switch (insn_info[iip].dp->mnemo) {
        !          4137:             case i_AND: compile_eas(&map, eainfo, 0, 1, 4); break;
        !          4138:             case i_EOR: compile_eas(&map, eainfo, 0, 1, 6); break;
        !          4139:             case i_OR:  compile_eas(&map, eainfo, 0, 1, 1); break;
        !          4140:            }
        !          4141: 
        !          4142:            compile_note_modify(&map, eainfo, 1);
        !          4143:            cc_status = CC_Z_FROM_86Z | CC_C_FROM_86C | CC_V_FROM_86V | CC_N_FROM_86N;
        !          4144:            break;
        !          4145: 
        !          4146:         case i_TST:
        !          4147:            compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub);
        !          4148:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          4149:                              insn_info[iip].dp->sreg,
        !          4150:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          4151:                              eainfo, 0, EA_LOAD, 1);
        !          4152: 
        !          4153:            generate_possible_exit(&map, eainfo, iip, &pub);
        !          4154: 
        !          4155:            compile_fetchea(&map, eainfo, 0, 1);
        !          4156:            cc_status = CC_TEST_REG;
        !          4157:            cc_reg = eainfo[0].data_reg;
        !          4158:            cc_offset = 0;
        !          4159:            cc_size = eainfo[0].size;
        !          4160:            break;
        !          4161: 
        !          4162:         case i_CLR:
        !          4163:            compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub);
        !          4164:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          4165:                              insn_info[iip].dp->sreg,
        !          4166:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          4167:                              eainfo, 0, EA_STORE, 1);
        !          4168:            compile_prepareea(&map, immi, 0, sz_long, &realpc, current_addr,
        !          4169:                              eainfo, 1, EA_LOAD, 1);
        !          4170:            generate_possible_exit(&map, eainfo + 0, iip, &pub);
        !          4171:            compile_loadeas(&map, eainfo, 1, 0, binop_alternatives, 1, 0);
        !          4172:            compile_storeea(&map, eainfo, 1, 0);
        !          4173: 
        !          4174:            cc_status = CC_TEST_REG;
        !          4175:            cc_reg = -2;
        !          4176:            cc_offset = 0;
        !          4177:            cc_size = eainfo[0].size;
        !          4178:            break;
        !          4179: 
        !          4180:         case i_EXT:
        !          4181:            /* No exits, no undo - this is always a Dreg; fetchea will get it in a reg
        !          4182:             * without offset */
        !          4183:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          4184:                              insn_info[iip].dp->sreg,
        !          4185:                              insn_info[iip].dp->size == sz_long ? sz_word : sz_byte,
        !          4186:                              &realpc, current_addr,
        !          4187:                              eainfo, 0, EA_LOAD|EA_STORE, 1);
        !          4188:            compile_fetchea(&map, eainfo, 0, 1);
        !          4189:            compile_force_byteorder(&map, eainfo[0].data_reg, BO_NORMAL, 0);
        !          4190: 
        !          4191:            if (insn_info[iip].dp->size == sz_word)
        !          4192:                assemble(0x66);
        !          4193:            assemble(0x0F);
        !          4194:            if (insn_info[iip].dp->size == sz_long)
        !          4195:                assemble(0xBF);
        !          4196:            else
        !          4197:                assemble(0xBE);
        !          4198: 
        !          4199:            assemble(0xC0 + 9*eainfo[0].data_reg);
        !          4200:            map.x86_dirty[eainfo[0].data_reg] = 1;
        !          4201: 
        !          4202:            cc_status = CC_TEST_REG;
        !          4203:            cc_reg = eainfo[0].data_reg;
        !          4204:            cc_offset = 0;
        !          4205:            cc_size = eainfo[0].size;
        !          4206:            break;
        !          4207: 
        !          4208:         case i_NOT:
        !          4209:         case i_NEG:
        !          4210:            szflag = insn_info[iip].dp->size == sz_byte ? 0 : 1;
        !          4211: 
        !          4212:            compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub);
        !          4213:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          4214:                              insn_info[iip].dp->sreg,
        !          4215:                              insn_info[iip].dp->size,
        !          4216:                              &realpc, current_addr,
        !          4217:                              eainfo, 0, EA_LOAD|EA_STORE, 1);
        !          4218: 
        !          4219:            generate_possible_exit(&map, eainfo, iip, &pub);
        !          4220: 
        !          4221:            compile_fetchea(&map, eainfo, 0, 1);
        !          4222:            compile_force_byteorder(&map, eainfo[0].data_reg, BO_NORMAL, 0);
        !          4223: 
        !          4224:            if (insn_info[iip].dp->size == sz_word)
        !          4225:                assemble(0x66);
        !          4226:            assemble(0xF6 + szflag);
        !          4227: 
        !          4228:            assemble(0xC0 + eainfo[0].data_reg + 8*(insn_info[iip].dp->mnemo == i_NOT ? 2 : 3));
        !          4229:            compile_note_modify(&map, eainfo, 0);
        !          4230: 
        !          4231:            if (insn_info[iip].dp->mnemo == i_NEG)
        !          4232:                cc_status = CC_Z_FROM_86Z | CC_C_FROM_86C | CC_V_FROM_86V | CC_N_FROM_86N | CC_X_FROM_86C;
        !          4233:            else {
        !          4234:                cc_status = CC_TEST_REG;
        !          4235:                cc_reg = eainfo[0].data_reg;
        !          4236:                cc_offset = 0;
        !          4237:                cc_size = eainfo[0].size;
        !          4238:            }
        !          4239:            break;
        !          4240: 
        !          4241:         case i_SWAP:
        !          4242:            /* No exits, no undo - this is always a Dreg; fetchea will get it in a reg
        !          4243:             * without offset */
        !          4244:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          4245:                              insn_info[iip].dp->sreg, sz_long,
        !          4246:                              &realpc, current_addr,
        !          4247:                              eainfo, 0, EA_LOAD|EA_STORE, 1);
        !          4248: 
        !          4249:            compile_fetchea(&map, eainfo, 0, 1);
        !          4250:            compile_force_byteorder(&map, eainfo[0].data_reg, BO_NORMAL, 0);
        !          4251: 
        !          4252:            /* roll $16, srcreg */
        !          4253:            assemble(0xC1); assemble(0xC0 + eainfo[0].data_reg); assemble(16);
        !          4254: 
        !          4255:            /* @@@ un-shortcut */
        !          4256:            map.x86_dirty[eainfo[0].data_reg] = 1;
        !          4257: 
        !          4258:            cc_status = CC_TEST_REG;
        !          4259:            cc_reg = eainfo[0].data_reg;
        !          4260:            cc_offset = 0;
        !          4261:            cc_size = eainfo[0].size;
        !          4262:            break;
        !          4263: 
        !          4264:         case i_LEA:
        !          4265:            /* No exits necessary here: never touches memory */
        !          4266:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          4267:                              insn_info[iip].dp->sreg,
        !          4268:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          4269:                              eainfo, 0, 0, 1);
        !          4270:            eainfo[0].data_reg = eainfo[0].address_reg;
        !          4271:            eainfo[0].data_const_off = eainfo[0].addr_const_off;
        !          4272:            eainfo[0].address_reg = -1;
        !          4273:            compile_get_excl_lock(&map, eainfo + 0);
        !          4274:            compile_prepareea(&map, insn_info[iip].dp->dmode,
        !          4275:                              insn_info[iip].dp->dreg,
        !          4276:                              sz_long, &realpc, current_addr,
        !          4277:                              eainfo, 1, EA_STORE, 1);
        !          4278:            compile_storeea(&map, eainfo, 0, 1);
        !          4279:            cc_status = 0;
        !          4280:            break;
        !          4281: 
        !          4282:         case i_PEA:
        !          4283:            compile_prepare_undo(&map, Apdi, 7, &pub);
        !          4284:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          4285:                              insn_info[iip].dp->sreg,
        !          4286:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          4287:                              eainfo, 0, 0, 1);
        !          4288:            eainfo[0].data_reg = eainfo[0].address_reg;
        !          4289:            eainfo[0].data_const_off = eainfo[0].addr_const_off;
        !          4290:            eainfo[0].address_reg = -1;
        !          4291:            compile_get_excl_lock(&map, eainfo + 0);
        !          4292:            compile_prepareea(&map, Apdi, 7, sz_long, &realpc, current_addr,
        !          4293:                              eainfo, 1, EA_STORE, 1);
        !          4294: 
        !          4295:            generate_possible_exit(&map, eainfo+1, iip, &pub);
        !          4296:            compile_storeea(&map, eainfo, 0, 1);
        !          4297: 
        !          4298:            cc_status = 0;
        !          4299:            break;
        !          4300: 
        !          4301:         case i_MVMEL:
        !          4302:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          4303:                              insn_info[iip].dp->sreg,
        !          4304:                              sz_word, &realpc, current_addr,
        !          4305:                              eainfo, 0, EA_LOAD, 1);
        !          4306:            sync_reg_cache(&map, 0);
        !          4307:            {
        !          4308:                /* Scratch 0 holds the registers while they are being moved
        !          4309:                 * from/to memory. Scratch 1 points at regs.d. Scratch 2
        !          4310:                 * points at the base addr in memory where to fetch data
        !          4311:                 * from.
        !          4312:                 */
        !          4313:                int scratch0, scratch1, scratch2;
        !          4314:                uae_u16 mask = eainfo[0].data_const_off;
        !          4315:                int bits = count_bits(mask);
        !          4316:                int size = insn_info[iip].dp->size == sz_long ? 4 : 2;
        !          4317:                int i;
        !          4318:                uae_u8 x86amode;
        !          4319:                uae_u32 current_offs = 0;
        !          4320: 
        !          4321:                compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub);
        !          4322:                /* !!! Note current_addr + 2 here! */
        !          4323:                compile_prepareea(&map, insn_info[iip].dp->dmode,
        !          4324:                                  insn_info[iip].dp->dreg,
        !          4325:                                  insn_info[iip].dp->size, &realpc, current_addr + 2,
        !          4326:                                  eainfo, 1, EA_LOAD, bits);
        !          4327: 
        !          4328:                generate_possible_exit(&map, eainfo + 1, iip, &pub);
        !          4329: 
        !          4330:                scratch0 = get_free_x86_register(&map, ADDRESS_X86_REGS);
        !          4331:                lock_reg(&map, scratch0, 2);
        !          4332:                scratch1 = get_free_x86_register(&map, ADDRESS_X86_REGS);
        !          4333:                lock_reg(&map, scratch1, 2);
        !          4334:                scratch2 = get_free_x86_register(&map, ADDRESS_X86_REGS);
        !          4335:                lock_reg(&map, scratch2, 2);
        !          4336:                compile_force_byteorder(&map, eainfo[1].address_reg, BO_NORMAL, 0);
        !          4337: 
        !          4338:                compile_lea_reg_with_offset(scratch1, -2, (uae_u32)regs.regs);
        !          4339:                compile_lea_reg_with_offset(scratch2, eainfo[1].address_reg,
        !          4340:                                            (uae_u32)(address_space + eainfo[1].addr_const_off));
        !          4341: 
        !          4342:                for (i = 0; i < 16; i++) {
        !          4343:                    int r68k = i;
        !          4344:                    int *cache68k = i < 8 ? map.dreg_map : map.areg_map;
        !          4345:                    if (mask & 1
        !          4346:                        && (i < 8
        !          4347:                            || insn_info[iip].dp->dmode != Aipi
        !          4348:                            || (r68k & 7) != insn_info[iip].dp->dreg)) {
        !          4349:                        int tmpr = cache68k[r68k & 7];
        !          4350: 
        !          4351:                        if (tmpr != -1) {
        !          4352:                            cache68k[r68k & 7] = -1;
        !          4353:                            map.x86_cache_reg[tmpr] = -1;
        !          4354:                        }
        !          4355:                        compile_move_reg_from_mem_regoffs(scratch0, scratch2,
        !          4356:                                                          current_offs, insn_info[iip].dp->size);
        !          4357:                        if (size == 2) {
        !          4358:                            assemble(0x66); /* rolw $8,scratch0 */
        !          4359:                            assemble(0xC1);
        !          4360:                            assemble(0xC0 + scratch0);
        !          4361:                            assemble(8);
        !          4362:                            assemble(0x0F); assemble(0xBF); /* extend */
        !          4363:                            assemble(0xC0 + 9*scratch0);
        !          4364:                        } else {
        !          4365:                            assemble(0x0F); /* bswapl scratch0 */
        !          4366:                            assemble(0xC8 + scratch0);
        !          4367:                        }
        !          4368:                        compile_move_reg_to_mem_regoffs(scratch1, (char *)(regs.regs + r68k) - (char *)regs.regs,
        !          4369:                                                        scratch0, sz_long);
        !          4370:                    }
        !          4371:                    if (mask & 1)
        !          4372:                        current_offs += size;
        !          4373:                    mask >>= 1;
        !          4374:                }
        !          4375:            }
        !          4376:            cc_status = 0;
        !          4377:            break;
        !          4378: 
        !          4379:         case i_MVMLE:
        !          4380:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          4381:                              insn_info[iip].dp->sreg,
        !          4382:                              sz_word, &realpc, current_addr,
        !          4383:                              eainfo, 0, EA_LOAD, 1);
        !          4384:            sync_reg_cache(&map, 0);
        !          4385:            {
        !          4386:                int scratch0,scratch1,scratch2;
        !          4387:                uae_u16 mask = eainfo[0].data_const_off;
        !          4388:                int bits = count_bits(mask);
        !          4389:                int size = insn_info[iip].dp->size == sz_long ? 4 : 2;
        !          4390:                int i;
        !          4391:                uae_u8 x86amode;
        !          4392:                uae_u32 current_offs = 0;
        !          4393:                int addrareg = -1;
        !          4394:                if (insn_info[iip].dp->dmode == Aind
        !          4395:                    || insn_info[iip].dp->dmode == Apdi
        !          4396:                    || insn_info[iip].dp->dmode == Aipi
        !          4397:                    || insn_info[iip].dp->dmode == Ad16
        !          4398:                    || insn_info[iip].dp->dmode == Ad8r)
        !          4399:                {
        !          4400:                    addrareg = get_and_lock_68k_reg(&map, insn_info[iip].dp->dreg, 0, ADDRESS_X86_REGS, 1, 2);
        !          4401:                    compile_force_byteorder(&map, addrareg, BO_NORMAL, 0);
        !          4402:                }
        !          4403:                if (insn_info[iip].dp->dmode == Apdi)
        !          4404:                    mask = bitswap(mask);
        !          4405:                /* !!! Note current_addr + 2 here! */
        !          4406:                compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub);
        !          4407:                compile_prepareea(&map, insn_info[iip].dp->dmode,
        !          4408:                                  insn_info[iip].dp->dreg,
        !          4409:                                  insn_info[iip].dp->size, &realpc, current_addr + 2,
        !          4410:                                  eainfo, 1, EA_STORE, bits);
        !          4411: 
        !          4412:                generate_possible_exit(&map, eainfo + 1, iip, &pub);
        !          4413: 
        !          4414:                scratch0 = get_free_x86_register(&map, ADDRESS_X86_REGS);
        !          4415:                lock_reg(&map, scratch0, 2);
        !          4416:                scratch1 = get_free_x86_register(&map, ADDRESS_X86_REGS);
        !          4417:                lock_reg(&map, scratch1, 2);
        !          4418:                scratch2 = get_free_x86_register(&map, ADDRESS_X86_REGS);
        !          4419:                lock_reg(&map, scratch2, 2);
        !          4420: 
        !          4421:                compile_force_byteorder(&map, eainfo[1].address_reg, BO_NORMAL, 0);
        !          4422: 
        !          4423:                compile_lea_reg_with_offset(scratch1, -2, (uae_u32)regs.regs);
        !          4424:                compile_lea_reg_with_offset(scratch2, eainfo[1].address_reg,
        !          4425:                                            (uae_u32)(address_space + eainfo[1].addr_const_off));
        !          4426: 
        !          4427:                for (i = 0; i < 16; i++) {
        !          4428:                    int r68k = i;
        !          4429:                    if (mask & 1) {
        !          4430:                        /* move from 68k reg */
        !          4431:                        if (i < 8 || (i & 7) != insn_info[iip].dp->dreg || addrareg == -1) {
        !          4432:                            compile_move_reg_from_mem_regoffs(scratch0, scratch1, (char *)(regs.regs + r68k) - (char *)regs.regs,
        !          4433:                                                              sz_long);
        !          4434:                        } else {
        !          4435:                            assemble(0x8B); assemble(0xC0 + 8*scratch0 + addrareg);
        !          4436:                        }
        !          4437: 
        !          4438:                        if (size == 2) {
        !          4439:                            assemble(0x66); /* rolw $8,scratch0 */
        !          4440:                            assemble(0xC1);
        !          4441:                            assemble(0xC0 + scratch0); assemble(8);
        !          4442:                        } else {
        !          4443:                            assemble(0x0F); /* bswapl scratch0 */
        !          4444:                            assemble(0xC8 + scratch0);
        !          4445:                        }
        !          4446:                        compile_move_reg_to_mem_regoffs(scratch2, current_offs,
        !          4447:                                                        scratch0, insn_info[iip].dp->size);
        !          4448:                    }
        !          4449:                    if (mask & 1)
        !          4450:                        current_offs += size;
        !          4451:                    mask >>= 1;
        !          4452:                }
        !          4453:            }
        !          4454:            cc_status = 0;
        !          4455:            break;
        !          4456: #if 1
        !          4457:         case i_BTST:
        !          4458:         case i_BSET:
        !          4459:         case i_BCLR:
        !          4460:         case i_BCHG:
        !          4461:            compile_prepare_undo(&map, insn_info[iip].dp->smode, insn_info[iip].dp->sreg, &pub);
        !          4462:            compile_prepare_undo(&map, insn_info[iip].dp->dmode, insn_info[iip].dp->dreg, &pub);
        !          4463:            compile_prepareea(&map, insn_info[iip].dp->smode,
        !          4464:                              insn_info[iip].dp->sreg,
        !          4465:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          4466:                              eainfo, 0, EA_LOAD, 1);
        !          4467:            compile_prepareea(&map, insn_info[iip].dp->dmode,
        !          4468:                              insn_info[iip].dp->dreg,
        !          4469:                              insn_info[iip].dp->size, &realpc, current_addr,
        !          4470:                              eainfo, 1, 0, 1);
        !          4471: 
        !          4472:            generate_possible_exit(&map, eainfo, iip, &pub);
        !          4473:            generate_possible_exit(&map, eainfo + 1, iip, &pub);
        !          4474: 
        !          4475:            handle_bit_insns(&map, eainfo, 0, 1, insn_info[iip].dp->mnemo);
        !          4476:            break;
        !          4477: 
        !          4478:         case i_ASL: case i_ASR: case i_LSL: case i_LSR:
        !          4479:         case i_ROL: case i_ROR: case i_ROXL:case i_ROXR:
        !          4480:            if (insn_info[iip].dp->smode == Dreg && do_rotshi) {
        !          4481:                handle_rotshi_variable(&map, iip, realpc, current_addr, &pub);
        !          4482:                break;
        !          4483:            }
        !          4484:            /* fall through */
        !          4485:         case i_ASLW: case i_ASRW: case i_LSLW: case i_LSRW:
        !          4486:         case i_ROLW: case i_RORW: case i_ROXLW:case i_ROXRW:
        !          4487:            if (do_rotshi) {
        !          4488:                handle_rotshi(&map, iip, realpc, current_addr, &pub);
        !          4489:                break;
        !          4490:            }
        !          4491: #endif
        !          4492:         default:
        !          4493:            generate_exit(&map, insn_info[iip].address); cc_status = 0;
        !          4494:            break;
        !          4495:        }
        !          4496:        if (insn_info[iip].ccuser_follows)
        !          4497:            cc_status_for_bcc = compile_flush_cc_cache(&map, cc_status,
        !          4498:                                   insn_info[iip].flags_live_at_end,
        !          4499:                                   1, insn_info[iip+1].flags_live_at_end,
        !          4500:                                   insn_info[iip+1].dp->cc);
        !          4501:        else
        !          4502:            cc_status_for_bcc = compile_flush_cc_cache(&map, cc_status,
        !          4503:                                   insn_info[iip].flags_live_at_end,
        !          4504:                                   0, 0, 0);
        !          4505: 
        !          4506:        if (iip == current_bb->last_iip) {
        !          4507:            current_bb++;
        !          4508:        }
        !          4509:     }
        !          4510:     if (compile_failure)
        !          4511:        goto oops;
        !          4512: 
        !          4513:     /* Compile all exits that we prepared earlier */
        !          4514:     finish_exits();
        !          4515:     if (compile_failure)
        !          4516:        goto oops;
        !          4517:     finish_condjumps(last_iip);
        !          4518:     {
        !          4519:        int needed_len = compile_here() - hb->compile_start;
        !          4520:        int allocsize = (needed_len + PAGE_SUBUNIT - 1) & ~(PAGE_SUBUNIT-1);
        !          4521:        uae_u32 allocmask;
        !          4522:        int allocbits;
        !          4523: 
        !          4524:        allocbits = (allocsize >> SUBUNIT_ORDER);
        !          4525:        allocmask = (1 << allocbits) - 1;
        !          4526:        while ((allocmask & hb->page_allocmask) != allocmask)
        !          4527:            allocmask <<= 1;
        !          4528:        if ((hb->page_allocmask & ~allocmask) != 0 && !quiet_compile)
        !          4529:            fprintf(stderr, "Gaining some bits: %08lx\n", hb->page_allocmask & ~allocmask);
        !          4530:        hb->cpage->allocmask &= ~hb->page_allocmask;
        !          4531:        hb->page_allocmask = allocmask;
        !          4532:        hb->cpage->allocmask |= allocmask;
        !          4533:     }
        !          4534:     return 0;
        !          4535: 
        !          4536:     oops:
        !          4537:     if (1 || !quiet_compile)
        !          4538:        fprintf(stderr, "Compile failed!\n");
        !          4539:     hb->cpage->allocmask &= ~hb->page_allocmask;
        !          4540:     hb->cpage = NULL;
        !          4541:     hb->untranslatable = 1;
        !          4542:     {
        !          4543:        struct hash_entry *h = hb->he_first;
        !          4544: 
        !          4545:        do {
        !          4546:            h->execute = NULL;
        !          4547:            h = h->next_same_block;
        !          4548:        } while (h != hb->he_first);
        !          4549:     }
        !          4550:     return 1;
        !          4551: }
        !          4552: 
        !          4553: void compiler_init(void)
        !          4554: {
        !          4555:     code_init();
        !          4556:     hash_init();
        !          4557:     jsr_stack_init();
        !          4558: }
        !          4559: 
        !          4560: /*
        !          4561:  * Why do compilers always have to be so complicated? And I thought GCC was
        !          4562:  * a mess...
        !          4563:  */
        !          4564: 
        !          4565: #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.