|
|
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*)®flags); ! 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)®flags, 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(®flags); assemble((UBYTE)~0x40); ! 2401: assemble(0x08); assemble(0x05+ tmpr*8); assemble_long(®flags); ! 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)®flags, tmpr, sz_word); ! 2414: if (status == CC_AFTER_ROX) ! 2415: compile_move_reg_to_mem_regoffs(-2, 2 + (ULONG)®flags, 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)®flags, tmpr, sz_word); ! 2436: ! 2437: if (status & CC_X_FROM_86C) { ! 2438: compile_move_reg_to_mem_regoffs(-2, 2 + (ULONG)®flags, 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)®flags, 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)®flags, ! 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(®flags); 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(®flags); ! 2982: assemble(0x81); assemble(0xC0 + 8*4 + tmpr); assemble_ulong(~0x40); ! 2983: assemble(0x09); assemble(0x05 + 8*tmpr); assemble_long(®flags); ! 2984: compile_move_reg_to_mem_regoffs(-2, 2 + (ULONG)®flags, 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 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.