ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/compiler.cpp
Revision: 1.2
Committed: 2001-03-20T17:35:45Z (23 years, 8 months ago) by gbeauche
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +0 -0 lines
State: FILE REMOVED
Log Message:
- removed old JIT compiler, its related support functions and files
  (compiler.{h,cpp})

File Contents

# User Rev Content
1 cebix 1.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 */