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