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

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