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

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

unix.superglobalmegacorp.com

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