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