ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/compiler.cpp
Revision: 1.1
Committed: 1999-11-03T10:56:34Z (25 years ago) by cebix
Branch: MAIN
CVS Tags: snapshot-17022001, release-0_8-1, snapshot-13072000, snapshot-22121999
Log Message:
- imported UAE CPU 0.8.10 changes
- new utility functions Mac_memset, Mac2Host_memcpy, Host2Mac_memcpu and
  Mac2Mac_memcpy
- extfs.cpp: fixed bug in fs_rename() and fs_cat_move() (auxiliary IOParam
  block was not in Mac address space)
- some provisions for using UAE CPU compiler (doesn't work yet)

File Contents

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