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