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