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