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