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