ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/compiler/compemu_support.cpp
Revision: 1.9
Committed: 2002-10-02T16:22:51Z (21 years, 11 months ago) by gbeauche
Branch: MAIN
Changes since 1.8: +43 -1 lines
Log Message:
Add PROFILE_UNTRANSLATED_INSNS information. Interestingly, the following
are the bottleneck now: DIVS, BSR.L (why isn't it translated yet?),
bit-field instructions (I need to self-motivate enough for that), and
A-Traps.

File Contents

# User Rev Content
1 gbeauche 1.1 #if !REAL_ADDRESSING && !DIRECT_ADDRESSING
2     #error "Only Real or Direct Addressing is supported with the JIT Compiler"
3     #endif
4    
5 gbeauche 1.4 #if X86_ASSEMBLY && !SAHF_SETO_PROFITABLE
6     #error "Only [LS]AHF scheme to [gs]et flags is supported with the JIT Compiler"
7     #endif
8    
9 gbeauche 1.1 #define USE_MATCH 0
10    
11     /* kludge for Brian, so he can compile under MSVC++ */
12     #define USE_NORMAL_CALLING_CONVENTION 0
13    
14     #ifndef WIN32
15     #include <sys/types.h>
16     #include <sys/mman.h>
17     #endif
18    
19     #include <stdlib.h>
20     #include <fcntl.h>
21     #include <errno.h>
22    
23     #include "sysdeps.h"
24     #include "cpu_emulation.h"
25     #include "main.h"
26     #include "prefs.h"
27     #include "user_strings.h"
28 gbeauche 1.2 #include "vm_alloc.h"
29 gbeauche 1.1
30     #include "m68k.h"
31     #include "memory.h"
32     #include "readcpu.h"
33     #include "newcpu.h"
34     #include "comptbl.h"
35     #include "compiler/compemu.h"
36     #include "fpu/fpu.h"
37     #include "fpu/flags.h"
38    
39     #define DEBUG 1
40     #include "debug.h"
41    
42     #ifdef ENABLE_MON
43     #include "mon.h"
44     #endif
45    
46     #ifndef WIN32
47 gbeauche 1.9 #define PROFILE_COMPILE_TIME 1
48     #define PROFILE_UNTRANSLATED_INSNS 1
49 gbeauche 1.1 #endif
50    
51     #ifdef WIN32
52     #undef write_log
53     #define write_log dummy_write_log
54     static void dummy_write_log(const char *, ...) { }
55     #endif
56    
57     #if JIT_DEBUG
58     #undef abort
59     #define abort() do { \
60     fprintf(stderr, "Abort in file %s at line %d\n", __FILE__, __LINE__); \
61     exit(EXIT_FAILURE); \
62     } while (0)
63     #endif
64    
65     #if PROFILE_COMPILE_TIME
66     #include <time.h>
67     static uae_u32 compile_count = 0;
68     static clock_t compile_time = 0;
69     static clock_t emul_start_time = 0;
70     static clock_t emul_end_time = 0;
71     #endif
72    
73 gbeauche 1.9 #if PROFILE_UNTRANSLATED_INSNS
74     const int untranslated_top_ten = 20;
75     static uae_u32 raw_cputbl_count[65536] = { 0, };
76     static uae_u16 opcode_nums[65536];
77    
78     static int untranslated_compfn(const void *e1, const void *e2)
79     {
80     return raw_cputbl_count[*(const uae_u16 *)e1] < raw_cputbl_count[*(const uae_u16 *)e2];
81     }
82     #endif
83    
84 gbeauche 1.1 compop_func *compfunctbl[65536];
85     compop_func *nfcompfunctbl[65536];
86     cpuop_func *nfcpufunctbl[65536];
87     uae_u8* comp_pc_p;
88    
89 gbeauche 1.6 // From newcpu.cpp
90     extern bool quit_program;
91    
92 gbeauche 1.1 // gb-- Extra data for Basilisk II/JIT
93     #if JIT_DEBUG
94     static bool JITDebug = false; // Enable runtime disassemblers through mon?
95     #else
96     const bool JITDebug = false; // Don't use JIT debug mode at all
97     #endif
98    
99     const uae_u32 MIN_CACHE_SIZE = 2048; // Minimal translation cache size (2048 KB)
100     static uae_u32 cache_size = 0; // Size of total cache allocated for compiled blocks
101 gbeauche 1.3 static uae_u32 current_cache_size = 0; // Cache grows upwards: how much has been consumed already
102 gbeauche 1.1 static bool lazy_flush = true; // Flag: lazy translation cache invalidation
103     static bool avoid_fpu = true; // Flag: compile FPU instructions ?
104     static bool have_cmov = false; // target has CMOV instructions ?
105     static bool have_rat_stall = true; // target has partial register stalls ?
106 gbeauche 1.5 static bool tune_alignment = false; // Tune code alignments for running CPU ?
107     static int align_loops = 32; // Align the start of loops
108     static int align_jumps = 32; // Align the start of jumps
109 gbeauche 1.1 static int zero_fd = -1;
110     static int optcount[10] = {
111     10, // How often a block has to be executed before it is translated
112     0, // How often to use naive translation
113     0, 0, 0, 0,
114     -1, -1, -1, -1
115     };
116    
117     struct op_properties {
118     uae_u8 use_flags;
119     uae_u8 set_flags;
120     uae_u8 is_addx;
121     uae_u8 cflow;
122     };
123     static op_properties prop[65536];
124    
125     static inline int end_block(uae_u32 opcode)
126     {
127     return (prop[opcode].cflow & fl_end_block);
128     }
129    
130 gbeauche 1.8 static inline bool is_const_jump(uae_u32 opcode)
131     {
132     return (prop[opcode].cflow == fl_const_jump);
133     }
134    
135 gbeauche 1.1 uae_u8* start_pc_p;
136     uae_u32 start_pc;
137     uae_u32 current_block_pc_p;
138     uae_u32 current_block_start_target;
139     uae_u32 needed_flags;
140     static uae_u32 next_pc_p;
141     static uae_u32 taken_pc_p;
142     static int branch_cc;
143     static int redo_current_block;
144    
145     int segvcount=0;
146     int soft_flush_count=0;
147     int hard_flush_count=0;
148     int checksum_count=0;
149     static uae_u8* current_compile_p=NULL;
150     static uae_u8* max_compile_start;
151     static uae_u8* compiled_code=NULL;
152     static uae_s32 reg_alloc_run;
153    
154     void* pushall_call_handler=NULL;
155     static void* popall_do_nothing=NULL;
156     static void* popall_exec_nostats=NULL;
157     static void* popall_execute_normal=NULL;
158     static void* popall_cache_miss=NULL;
159     static void* popall_recompile_block=NULL;
160     static void* popall_check_checksum=NULL;
161    
162     extern uae_u32 oink;
163     extern unsigned long foink3;
164     extern unsigned long foink;
165    
166     /* The 68k only ever executes from even addresses. So right now, we
167     * waste half the entries in this array
168     * UPDATE: We now use those entries to store the start of the linked
169     * lists that we maintain for each hash result.
170     */
171     cacheline cache_tags[TAGSIZE];
172     int letit=0;
173     blockinfo* hold_bi[MAX_HOLD_BI];
174     blockinfo* active;
175     blockinfo* dormant;
176    
177     /* 68040 */
178     extern struct cputbl op_smalltbl_0_nf[];
179     extern struct comptbl op_smalltbl_0_comp_nf[];
180     extern struct comptbl op_smalltbl_0_comp_ff[];
181    
182     /* 68020 + 68881 */
183     extern struct cputbl op_smalltbl_1_nf[];
184    
185     /* 68020 */
186     extern struct cputbl op_smalltbl_2_nf[];
187    
188     /* 68010 */
189     extern struct cputbl op_smalltbl_3_nf[];
190    
191     /* 68000 */
192     extern struct cputbl op_smalltbl_4_nf[];
193    
194     /* 68000 slow but compatible. */
195     extern struct cputbl op_smalltbl_5_nf[];
196    
197     static void flush_icache_hard(int n);
198     static void flush_icache_lazy(int n);
199     static void flush_icache_none(int n);
200     void (*flush_icache)(int n) = flush_icache_none;
201    
202    
203    
204     bigstate live;
205     smallstate empty_ss;
206     smallstate default_ss;
207     static int optlev;
208    
209     static int writereg(int r, int size);
210     static void unlock2(int r);
211     static void setlock(int r);
212     static int readreg_specific(int r, int size, int spec);
213     static int writereg_specific(int r, int size, int spec);
214     static void prepare_for_call_1(void);
215     static void prepare_for_call_2(void);
216     static void align_target(uae_u32 a);
217    
218     static uae_s32 nextused[VREGS];
219    
220     uae_u32 m68k_pc_offset;
221    
222     /* Some arithmetic ooperations can be optimized away if the operands
223     * are known to be constant. But that's only a good idea when the
224     * side effects they would have on the flags are not important. This
225     * variable indicates whether we need the side effects or not
226     */
227     uae_u32 needflags=0;
228    
229     /* Flag handling is complicated.
230     *
231     * x86 instructions create flags, which quite often are exactly what we
232     * want. So at times, the "68k" flags are actually in the x86 flags.
233     *
234     * Then again, sometimes we do x86 instructions that clobber the x86
235     * flags, but don't represent a corresponding m68k instruction. In that
236     * case, we have to save them.
237     *
238     * We used to save them to the stack, but now store them back directly
239     * into the regflags.cznv of the traditional emulation. Thus some odd
240     * names.
241     *
242     * So flags can be in either of two places (used to be three; boy were
243     * things complicated back then!); And either place can contain either
244     * valid flags or invalid trash (and on the stack, there was also the
245     * option of "nothing at all", now gone). A couple of variables keep
246     * track of the respective states.
247     *
248     * To make things worse, we might or might not be interested in the flags.
249     * by default, we are, but a call to dont_care_flags can change that
250     * until the next call to live_flags. If we are not, pretty much whatever
251     * is in the register and/or the native flags is seen as valid.
252     */
253    
254     static __inline__ blockinfo* get_blockinfo(uae_u32 cl)
255     {
256     return cache_tags[cl+1].bi;
257     }
258    
259     static __inline__ blockinfo* get_blockinfo_addr(void* addr)
260     {
261     blockinfo* bi=get_blockinfo(cacheline(addr));
262    
263     while (bi) {
264     if (bi->pc_p==addr)
265     return bi;
266     bi=bi->next_same_cl;
267     }
268     return NULL;
269     }
270    
271    
272     /*******************************************************************
273     * All sorts of list related functions for all of the lists *
274     *******************************************************************/
275    
276     static __inline__ void remove_from_cl_list(blockinfo* bi)
277     {
278     uae_u32 cl=cacheline(bi->pc_p);
279    
280     if (bi->prev_same_cl_p)
281     *(bi->prev_same_cl_p)=bi->next_same_cl;
282     if (bi->next_same_cl)
283     bi->next_same_cl->prev_same_cl_p=bi->prev_same_cl_p;
284     if (cache_tags[cl+1].bi)
285     cache_tags[cl].handler=cache_tags[cl+1].bi->handler_to_use;
286     else
287     cache_tags[cl].handler=(cpuop_func *)popall_execute_normal;
288     }
289    
290     static __inline__ void remove_from_list(blockinfo* bi)
291     {
292     if (bi->prev_p)
293     *(bi->prev_p)=bi->next;
294     if (bi->next)
295     bi->next->prev_p=bi->prev_p;
296     }
297    
298     static __inline__ void remove_from_lists(blockinfo* bi)
299     {
300     remove_from_list(bi);
301     remove_from_cl_list(bi);
302     }
303    
304     static __inline__ void add_to_cl_list(blockinfo* bi)
305     {
306     uae_u32 cl=cacheline(bi->pc_p);
307    
308     if (cache_tags[cl+1].bi)
309     cache_tags[cl+1].bi->prev_same_cl_p=&(bi->next_same_cl);
310     bi->next_same_cl=cache_tags[cl+1].bi;
311    
312     cache_tags[cl+1].bi=bi;
313     bi->prev_same_cl_p=&(cache_tags[cl+1].bi);
314    
315     cache_tags[cl].handler=bi->handler_to_use;
316     }
317    
318     static __inline__ void raise_in_cl_list(blockinfo* bi)
319     {
320     remove_from_cl_list(bi);
321     add_to_cl_list(bi);
322     }
323    
324     static __inline__ void add_to_active(blockinfo* bi)
325     {
326     if (active)
327     active->prev_p=&(bi->next);
328     bi->next=active;
329    
330     active=bi;
331     bi->prev_p=&active;
332     }
333    
334     static __inline__ void add_to_dormant(blockinfo* bi)
335     {
336     if (dormant)
337     dormant->prev_p=&(bi->next);
338     bi->next=dormant;
339    
340     dormant=bi;
341     bi->prev_p=&dormant;
342     }
343    
344     static __inline__ void remove_dep(dependency* d)
345     {
346     if (d->prev_p)
347     *(d->prev_p)=d->next;
348     if (d->next)
349     d->next->prev_p=d->prev_p;
350     d->prev_p=NULL;
351     d->next=NULL;
352     }
353    
354     /* This block's code is about to be thrown away, so it no longer
355     depends on anything else */
356     static __inline__ void remove_deps(blockinfo* bi)
357     {
358     remove_dep(&(bi->dep[0]));
359     remove_dep(&(bi->dep[1]));
360     }
361    
362     static __inline__ void adjust_jmpdep(dependency* d, cpuop_func* a)
363     {
364     *(d->jmp_off)=(uintptr)a-((uintptr)d->jmp_off+4);
365     }
366    
367     /********************************************************************
368     * Soft flush handling support functions *
369     ********************************************************************/
370    
371     static __inline__ void set_dhtu(blockinfo* bi, cpuop_func* dh)
372     {
373     //write_log("bi is %p\n",bi);
374     if (dh!=bi->direct_handler_to_use) {
375     dependency* x=bi->deplist;
376     //write_log("bi->deplist=%p\n",bi->deplist);
377     while (x) {
378     //write_log("x is %p\n",x);
379     //write_log("x->next is %p\n",x->next);
380     //write_log("x->prev_p is %p\n",x->prev_p);
381    
382     if (x->jmp_off) {
383     adjust_jmpdep(x,dh);
384     }
385     x=x->next;
386     }
387     bi->direct_handler_to_use=dh;
388     }
389     }
390    
391     static __inline__ void invalidate_block(blockinfo* bi)
392     {
393     int i;
394    
395     bi->optlevel=0;
396     bi->count=optcount[0]-1;
397     bi->handler=NULL;
398     bi->handler_to_use=(cpuop_func *)popall_execute_normal;
399     bi->direct_handler=NULL;
400     set_dhtu(bi,bi->direct_pen);
401     bi->needed_flags=0xff;
402     bi->status=BI_INVALID;
403     for (i=0;i<2;i++) {
404     bi->dep[i].jmp_off=NULL;
405     bi->dep[i].target=NULL;
406     }
407     remove_deps(bi);
408     }
409    
410     static __inline__ void create_jmpdep(blockinfo* bi, int i, uae_u32* jmpaddr, uae_u32 target)
411     {
412     blockinfo* tbi=get_blockinfo_addr((void*)target);
413    
414     Dif(!tbi) {
415     write_log("Could not create jmpdep!\n");
416     abort();
417     }
418     bi->dep[i].jmp_off=jmpaddr;
419     bi->dep[i].source=bi;
420     bi->dep[i].target=tbi;
421     bi->dep[i].next=tbi->deplist;
422     if (bi->dep[i].next)
423     bi->dep[i].next->prev_p=&(bi->dep[i].next);
424     bi->dep[i].prev_p=&(tbi->deplist);
425     tbi->deplist=&(bi->dep[i]);
426     }
427    
428     static __inline__ void block_need_recompile(blockinfo * bi)
429     {
430     uae_u32 cl = cacheline(bi->pc_p);
431    
432     set_dhtu(bi, bi->direct_pen);
433     bi->direct_handler = bi->direct_pen;
434    
435     bi->handler_to_use = (cpuop_func *)popall_execute_normal;
436     bi->handler = (cpuop_func *)popall_execute_normal;
437     if (bi == cache_tags[cl + 1].bi)
438     cache_tags[cl].handler = (cpuop_func *)popall_execute_normal;
439     bi->status = BI_NEED_RECOMP;
440     }
441    
442     static __inline__ void mark_callers_recompile(blockinfo * bi)
443     {
444     dependency *x = bi->deplist;
445    
446     while (x) {
447     dependency *next = x->next; /* This disappears when we mark for
448     * recompilation and thus remove the
449     * blocks from the lists */
450     if (x->jmp_off) {
451     blockinfo *cbi = x->source;
452    
453     Dif(cbi->status == BI_INVALID) {
454     // write_log("invalid block in dependency list\n"); // FIXME?
455     // abort();
456     }
457     if (cbi->status == BI_ACTIVE || cbi->status == BI_NEED_CHECK) {
458     block_need_recompile(cbi);
459     mark_callers_recompile(cbi);
460     }
461     else if (cbi->status == BI_COMPILING) {
462     redo_current_block = 1;
463     }
464     else if (cbi->status == BI_NEED_RECOMP) {
465     /* nothing */
466     }
467     else {
468     //write_log("Status %d in mark_callers\n",cbi->status); // FIXME?
469     }
470     }
471     x = next;
472     }
473     }
474    
475     static __inline__ blockinfo* get_blockinfo_addr_new(void* addr, int setstate)
476     {
477     blockinfo* bi=get_blockinfo_addr(addr);
478     int i;
479    
480     if (!bi) {
481     for (i=0;i<MAX_HOLD_BI && !bi;i++) {
482     if (hold_bi[i]) {
483     uae_u32 cl=cacheline(addr);
484    
485     bi=hold_bi[i];
486     hold_bi[i]=NULL;
487     bi->pc_p=(uae_u8 *)addr;
488     invalidate_block(bi);
489     add_to_active(bi);
490     add_to_cl_list(bi);
491    
492     }
493     }
494     }
495     if (!bi) {
496     write_log("Looking for blockinfo, can't find free one\n");
497     abort();
498     }
499     return bi;
500     }
501    
502     static void prepare_block(blockinfo* bi);
503    
504     /* Managment of blockinfos.
505    
506     A blockinfo struct is allocated whenever a new block has to be
507     compiled. If the list of free blockinfos is empty, we allocate a new
508     pool of blockinfos and link the newly created blockinfos altogether
509     into the list of free blockinfos. Otherwise, we simply pop a structure
510 gbeauche 1.7 off the free list.
511 gbeauche 1.1
512     Blockinfo are lazily deallocated, i.e. chained altogether in the
513     list of free blockinfos whenvever a translation cache flush (hard or
514     soft) request occurs.
515     */
516    
517 gbeauche 1.7 template< class T >
518     class LazyBlockAllocator
519     {
520     enum {
521     kPoolSize = 1 + 4096 / sizeof(T)
522     };
523     struct Pool {
524     T chunk[kPoolSize];
525     Pool * next;
526     };
527     Pool * mPools;
528     T * mChunks;
529     public:
530     LazyBlockAllocator() : mPools(0), mChunks(0) { }
531     ~LazyBlockAllocator();
532     T * acquire();
533     void release(T * const);
534 gbeauche 1.1 };
535    
536 gbeauche 1.7 template< class T >
537     LazyBlockAllocator<T>::~LazyBlockAllocator()
538 gbeauche 1.1 {
539 gbeauche 1.7 Pool * currentPool = mPools;
540     while (currentPool) {
541     Pool * deadPool = currentPool;
542     currentPool = currentPool->next;
543     free(deadPool);
544     }
545     }
546    
547     template< class T >
548     T * LazyBlockAllocator<T>::acquire()
549     {
550     if (!mChunks) {
551     // There is no chunk left, allocate a new pool and link the
552     // chunks into the free list
553     Pool * newPool = (Pool *)malloc(sizeof(Pool));
554     for (T * chunk = &newPool->chunk[0]; chunk < &newPool->chunk[kPoolSize]; chunk++) {
555     chunk->next = mChunks;
556     mChunks = chunk;
557 gbeauche 1.1 }
558 gbeauche 1.7 newPool->next = mPools;
559     mPools = newPool;
560     }
561     T * chunk = mChunks;
562     mChunks = chunk->next;
563     return chunk;
564     }
565    
566     template< class T >
567     void LazyBlockAllocator<T>::release(T * const chunk)
568     {
569     chunk->next = mChunks;
570     mChunks = chunk;
571     }
572    
573     template< class T >
574     class HardBlockAllocator
575     {
576     public:
577     T * acquire() {
578     T * data = (T *)current_compile_p;
579     current_compile_p += sizeof(T);
580     return data;
581 gbeauche 1.1 }
582 gbeauche 1.7
583     void release(T * const chunk) {
584     // Deallocated on invalidation
585     }
586     };
587    
588     #if USE_SEPARATE_BIA
589     static LazyBlockAllocator<blockinfo> BlockInfoAllocator;
590     static LazyBlockAllocator<checksum_info> ChecksumInfoAllocator;
591 gbeauche 1.1 #else
592 gbeauche 1.7 static HardBlockAllocator<blockinfo> BlockInfoAllocator;
593     static HardBlockAllocator<checksum_info> ChecksumInfoAllocator;
594 gbeauche 1.1 #endif
595    
596 gbeauche 1.8 static __inline__ checksum_info *alloc_checksum_info(void)
597     {
598     checksum_info *csi = ChecksumInfoAllocator.acquire();
599     csi->next = NULL;
600     return csi;
601     }
602    
603     static __inline__ void free_checksum_info(checksum_info *csi)
604     {
605     csi->next = NULL;
606     ChecksumInfoAllocator.release(csi);
607     }
608    
609     static __inline__ void free_checksum_info_chain(checksum_info *csi)
610     {
611     while (csi != NULL) {
612     checksum_info *csi2 = csi->next;
613     free_checksum_info(csi);
614     csi = csi2;
615     }
616     }
617 gbeauche 1.7
618     static __inline__ blockinfo *alloc_blockinfo(void)
619 gbeauche 1.1 {
620 gbeauche 1.7 blockinfo *bi = BlockInfoAllocator.acquire();
621     #if USE_CHECKSUM_INFO
622     bi->csi = NULL;
623 gbeauche 1.1 #endif
624 gbeauche 1.7 return bi;
625 gbeauche 1.1 }
626    
627 gbeauche 1.7 static __inline__ void free_blockinfo(blockinfo *bi)
628 gbeauche 1.1 {
629 gbeauche 1.7 #if USE_CHECKSUM_INFO
630 gbeauche 1.8 free_checksum_info_chain(bi->csi);
631     bi->csi = NULL;
632 gbeauche 1.1 #endif
633 gbeauche 1.7 BlockInfoAllocator.release(bi);
634 gbeauche 1.1 }
635    
636     static __inline__ void alloc_blockinfos(void)
637     {
638     int i;
639     blockinfo* bi;
640    
641     for (i=0;i<MAX_HOLD_BI;i++) {
642     if (hold_bi[i])
643     return;
644     bi=hold_bi[i]=alloc_blockinfo();
645     prepare_block(bi);
646     }
647     }
648    
649     /********************************************************************
650     * Functions to emit data into memory, and other general support *
651     ********************************************************************/
652    
653     static uae_u8* target;
654    
655     static void emit_init(void)
656     {
657     }
658    
659     static __inline__ void emit_byte(uae_u8 x)
660     {
661     *target++=x;
662     }
663    
664     static __inline__ void emit_word(uae_u16 x)
665     {
666     *((uae_u16*)target)=x;
667     target+=2;
668     }
669    
670     static __inline__ void emit_long(uae_u32 x)
671     {
672     *((uae_u32*)target)=x;
673     target+=4;
674     }
675    
676     static __inline__ uae_u32 reverse32(uae_u32 v)
677     {
678     #if 1
679     // gb-- We have specialized byteswapping functions, just use them
680     return do_byteswap_32(v);
681     #else
682     return ((v>>24)&0xff) | ((v>>8)&0xff00) | ((v<<8)&0xff0000) | ((v<<24)&0xff000000);
683     #endif
684     }
685    
686     /********************************************************************
687     * Getting the information about the target CPU *
688     ********************************************************************/
689    
690     #include "codegen_x86.cpp"
691    
692     void set_target(uae_u8* t)
693     {
694     target=t;
695     }
696    
697     static __inline__ uae_u8* get_target_noopt(void)
698     {
699     return target;
700     }
701    
702     __inline__ uae_u8* get_target(void)
703     {
704     return get_target_noopt();
705     }
706    
707    
708     /********************************************************************
709     * Flags status handling. EMIT TIME! *
710     ********************************************************************/
711    
712     static void bt_l_ri_noclobber(R4 r, IMM i);
713    
714     static void make_flags_live_internal(void)
715     {
716     if (live.flags_in_flags==VALID)
717     return;
718     Dif (live.flags_on_stack==TRASH) {
719     write_log("Want flags, got something on stack, but it is TRASH\n");
720     abort();
721     }
722     if (live.flags_on_stack==VALID) {
723     int tmp;
724     tmp=readreg_specific(FLAGTMP,4,FLAG_NREG2);
725     raw_reg_to_flags(tmp);
726     unlock2(tmp);
727    
728     live.flags_in_flags=VALID;
729     return;
730     }
731     write_log("Huh? live.flags_in_flags=%d, live.flags_on_stack=%d, but need to make live\n",
732     live.flags_in_flags,live.flags_on_stack);
733     abort();
734     }
735    
736     static void flags_to_stack(void)
737     {
738     if (live.flags_on_stack==VALID)
739     return;
740     if (!live.flags_are_important) {
741     live.flags_on_stack=VALID;
742     return;
743     }
744     Dif (live.flags_in_flags!=VALID)
745     abort();
746     else {
747     int tmp;
748     tmp=writereg_specific(FLAGTMP,4,FLAG_NREG1);
749     raw_flags_to_reg(tmp);
750     unlock2(tmp);
751     }
752     live.flags_on_stack=VALID;
753     }
754    
755     static __inline__ void clobber_flags(void)
756     {
757     if (live.flags_in_flags==VALID && live.flags_on_stack!=VALID)
758     flags_to_stack();
759     live.flags_in_flags=TRASH;
760     }
761    
762     /* Prepare for leaving the compiled stuff */
763     static __inline__ void flush_flags(void)
764     {
765     flags_to_stack();
766     return;
767     }
768    
769     int touchcnt;
770    
771     /********************************************************************
772     * register allocation per block logging *
773     ********************************************************************/
774    
775     static uae_s8 vstate[VREGS];
776     static uae_s8 vwritten[VREGS];
777     static uae_s8 nstate[N_REGS];
778    
779     #define L_UNKNOWN -127
780     #define L_UNAVAIL -1
781     #define L_NEEDED -2
782     #define L_UNNEEDED -3
783    
784     static __inline__ void big_to_small_state(bigstate * b, smallstate * s)
785     {
786     int i;
787    
788     for (i = 0; i < VREGS; i++)
789     s->virt[i] = vstate[i];
790     for (i = 0; i < N_REGS; i++)
791     s->nat[i] = nstate[i];
792     }
793    
794     static __inline__ int callers_need_recompile(bigstate * b, smallstate * s)
795     {
796     int i;
797     int reverse = 0;
798    
799     for (i = 0; i < VREGS; i++) {
800     if (vstate[i] != L_UNNEEDED && s->virt[i] == L_UNNEEDED)
801     return 1;
802     if (vstate[i] == L_UNNEEDED && s->virt[i] != L_UNNEEDED)
803     reverse++;
804     }
805     for (i = 0; i < N_REGS; i++) {
806     if (nstate[i] >= 0 && nstate[i] != s->nat[i])
807     return 1;
808     if (nstate[i] < 0 && s->nat[i] >= 0)
809     reverse++;
810     }
811     if (reverse >= 2 && USE_MATCH)
812     return 1; /* In this case, it might be worth recompiling the
813     * callers */
814     return 0;
815     }
816    
817     static __inline__ void log_startblock(void)
818     {
819     int i;
820    
821     for (i = 0; i < VREGS; i++) {
822     vstate[i] = L_UNKNOWN;
823     vwritten[i] = 0;
824     }
825     for (i = 0; i < N_REGS; i++)
826     nstate[i] = L_UNKNOWN;
827     }
828    
829     /* Using an n-reg for a temp variable */
830     static __inline__ void log_isused(int n)
831     {
832     if (nstate[n] == L_UNKNOWN)
833     nstate[n] = L_UNAVAIL;
834     }
835    
836     static __inline__ void log_visused(int r)
837     {
838     if (vstate[r] == L_UNKNOWN)
839     vstate[r] = L_NEEDED;
840     }
841    
842     static __inline__ void do_load_reg(int n, int r)
843     {
844     if (r == FLAGTMP)
845     raw_load_flagreg(n, r);
846     else if (r == FLAGX)
847     raw_load_flagx(n, r);
848     else
849     raw_mov_l_rm(n, (uae_u32) live.state[r].mem);
850     }
851    
852     static __inline__ void check_load_reg(int n, int r)
853     {
854     raw_mov_l_rm(n, (uae_u32) live.state[r].mem);
855     }
856    
857     static __inline__ void log_vwrite(int r)
858     {
859     vwritten[r] = 1;
860     }
861    
862     /* Using an n-reg to hold a v-reg */
863     static __inline__ void log_isreg(int n, int r)
864     {
865     static int count = 0;
866    
867     if (nstate[n] == L_UNKNOWN && r < 16 && !vwritten[r] && USE_MATCH)
868     nstate[n] = r;
869     else {
870     do_load_reg(n, r);
871     if (nstate[n] == L_UNKNOWN)
872     nstate[n] = L_UNAVAIL;
873     }
874     if (vstate[r] == L_UNKNOWN)
875     vstate[r] = L_NEEDED;
876     }
877    
878     static __inline__ void log_clobberreg(int r)
879     {
880     if (vstate[r] == L_UNKNOWN)
881     vstate[r] = L_UNNEEDED;
882     }
883    
884     /* This ends all possibility of clever register allocation */
885    
886     static __inline__ void log_flush(void)
887     {
888     int i;
889    
890     for (i = 0; i < VREGS; i++)
891     if (vstate[i] == L_UNKNOWN)
892     vstate[i] = L_NEEDED;
893     for (i = 0; i < N_REGS; i++)
894     if (nstate[i] == L_UNKNOWN)
895     nstate[i] = L_UNAVAIL;
896     }
897    
898     static __inline__ void log_dump(void)
899     {
900     int i;
901    
902     return;
903    
904     write_log("----------------------\n");
905     for (i = 0; i < N_REGS; i++) {
906     switch (nstate[i]) {
907     case L_UNKNOWN:
908     write_log("Nat %d : UNKNOWN\n", i);
909     break;
910     case L_UNAVAIL:
911     write_log("Nat %d : UNAVAIL\n", i);
912     break;
913     default:
914     write_log("Nat %d : %d\n", i, nstate[i]);
915     break;
916     }
917     }
918     for (i = 0; i < VREGS; i++) {
919     if (vstate[i] == L_UNNEEDED)
920     write_log("Virt %d: UNNEEDED\n", i);
921     }
922     }
923    
924     /********************************************************************
925     * register status handling. EMIT TIME! *
926     ********************************************************************/
927    
928     static __inline__ void set_status(int r, int status)
929     {
930     if (status == ISCONST)
931     log_clobberreg(r);
932     live.state[r].status=status;
933     }
934    
935     static __inline__ int isinreg(int r)
936     {
937     return live.state[r].status==CLEAN || live.state[r].status==DIRTY;
938     }
939    
940     static __inline__ void adjust_nreg(int r, uae_u32 val)
941     {
942     if (!val)
943     return;
944     raw_lea_l_brr(r,r,val);
945     }
946    
947     static void tomem(int r)
948     {
949     int rr=live.state[r].realreg;
950    
951     if (isinreg(r)) {
952     if (live.state[r].val && live.nat[rr].nholds==1
953     && !live.nat[rr].locked) {
954     // write_log("RemovingA offset %x from reg %d (%d) at %p\n",
955     // live.state[r].val,r,rr,target);
956     adjust_nreg(rr,live.state[r].val);
957     live.state[r].val=0;
958     live.state[r].dirtysize=4;
959     set_status(r,DIRTY);
960     }
961     }
962    
963     if (live.state[r].status==DIRTY) {
964     switch (live.state[r].dirtysize) {
965     case 1: raw_mov_b_mr((uae_u32)live.state[r].mem,rr); break;
966     case 2: raw_mov_w_mr((uae_u32)live.state[r].mem,rr); break;
967     case 4: raw_mov_l_mr((uae_u32)live.state[r].mem,rr); break;
968     default: abort();
969     }
970     log_vwrite(r);
971     set_status(r,CLEAN);
972     live.state[r].dirtysize=0;
973     }
974     }
975    
976     static __inline__ int isconst(int r)
977     {
978     return live.state[r].status==ISCONST;
979     }
980    
981     int is_const(int r)
982     {
983     return isconst(r);
984     }
985    
986     static __inline__ void writeback_const(int r)
987     {
988     if (!isconst(r))
989     return;
990     Dif (live.state[r].needflush==NF_HANDLER) {
991     write_log("Trying to write back constant NF_HANDLER!\n");
992     abort();
993     }
994    
995     raw_mov_l_mi((uae_u32)live.state[r].mem,live.state[r].val);
996     log_vwrite(r);
997     live.state[r].val=0;
998     set_status(r,INMEM);
999     }
1000    
1001     static __inline__ void tomem_c(int r)
1002     {
1003     if (isconst(r)) {
1004     writeback_const(r);
1005     }
1006     else
1007     tomem(r);
1008     }
1009    
1010     static void evict(int r)
1011     {
1012     int rr;
1013    
1014     if (!isinreg(r))
1015     return;
1016     tomem(r);
1017     rr=live.state[r].realreg;
1018    
1019     Dif (live.nat[rr].locked &&
1020     live.nat[rr].nholds==1) {
1021     write_log("register %d in nreg %d is locked!\n",r,live.state[r].realreg);
1022     abort();
1023     }
1024    
1025     live.nat[rr].nholds--;
1026     if (live.nat[rr].nholds!=live.state[r].realind) { /* Was not last */
1027     int topreg=live.nat[rr].holds[live.nat[rr].nholds];
1028     int thisind=live.state[r].realind;
1029    
1030     live.nat[rr].holds[thisind]=topreg;
1031     live.state[topreg].realind=thisind;
1032     }
1033     live.state[r].realreg=-1;
1034     set_status(r,INMEM);
1035     }
1036    
1037     static __inline__ void free_nreg(int r)
1038     {
1039     int i=live.nat[r].nholds;
1040    
1041     while (i) {
1042     int vr;
1043    
1044     --i;
1045     vr=live.nat[r].holds[i];
1046     evict(vr);
1047     }
1048     Dif (live.nat[r].nholds!=0) {
1049     write_log("Failed to free nreg %d, nholds is %d\n",r,live.nat[r].nholds);
1050     abort();
1051     }
1052     }
1053    
1054     /* Use with care! */
1055     static __inline__ void isclean(int r)
1056     {
1057     if (!isinreg(r))
1058     return;
1059     live.state[r].validsize=4;
1060     live.state[r].dirtysize=0;
1061     live.state[r].val=0;
1062     set_status(r,CLEAN);
1063     }
1064    
1065     static __inline__ void disassociate(int r)
1066     {
1067     isclean(r);
1068     evict(r);
1069     }
1070    
1071     static __inline__ void set_const(int r, uae_u32 val)
1072     {
1073     disassociate(r);
1074     live.state[r].val=val;
1075     set_status(r,ISCONST);
1076     }
1077    
1078     static __inline__ uae_u32 get_offset(int r)
1079     {
1080     return live.state[r].val;
1081     }
1082    
1083     static int alloc_reg_hinted(int r, int size, int willclobber, int hint)
1084     {
1085     int bestreg;
1086     uae_s32 when;
1087     int i;
1088     uae_s32 badness=0; /* to shut up gcc */
1089     bestreg=-1;
1090     when=2000000000;
1091    
1092     for (i=N_REGS;i--;) {
1093     badness=live.nat[i].touched;
1094     if (live.nat[i].nholds==0)
1095     badness=0;
1096     if (i==hint)
1097     badness-=200000000;
1098     if (!live.nat[i].locked && badness<when) {
1099     if ((size==1 && live.nat[i].canbyte) ||
1100     (size==2 && live.nat[i].canword) ||
1101     (size==4)) {
1102     bestreg=i;
1103     when=badness;
1104     if (live.nat[i].nholds==0 && hint<0)
1105     break;
1106     if (i==hint)
1107     break;
1108     }
1109     }
1110     }
1111     Dif (bestreg==-1)
1112     abort();
1113    
1114     if (live.nat[bestreg].nholds>0) {
1115     free_nreg(bestreg);
1116     }
1117     if (isinreg(r)) {
1118     int rr=live.state[r].realreg;
1119     /* This will happen if we read a partially dirty register at a
1120     bigger size */
1121     Dif (willclobber || live.state[r].validsize>=size)
1122     abort();
1123     Dif (live.nat[rr].nholds!=1)
1124     abort();
1125     if (size==4 && live.state[r].validsize==2) {
1126     log_isused(bestreg);
1127     log_visused(r);
1128     raw_mov_l_rm(bestreg,(uae_u32)live.state[r].mem);
1129     raw_bswap_32(bestreg);
1130     raw_zero_extend_16_rr(rr,rr);
1131     raw_zero_extend_16_rr(bestreg,bestreg);
1132     raw_bswap_32(bestreg);
1133     raw_lea_l_brr_indexed(rr,rr,bestreg,1,0);
1134     live.state[r].validsize=4;
1135     live.nat[rr].touched=touchcnt++;
1136     return rr;
1137     }
1138     if (live.state[r].validsize==1) {
1139     /* Nothing yet */
1140     }
1141     evict(r);
1142     }
1143    
1144     if (!willclobber) {
1145     if (live.state[r].status!=UNDEF) {
1146     if (isconst(r)) {
1147     raw_mov_l_ri(bestreg,live.state[r].val);
1148     live.state[r].val=0;
1149     live.state[r].dirtysize=4;
1150     set_status(r,DIRTY);
1151     log_isused(bestreg);
1152     }
1153     else {
1154     log_isreg(bestreg, r); /* This will also load it! */
1155     live.state[r].dirtysize=0;
1156     set_status(r,CLEAN);
1157     }
1158     }
1159     else {
1160     live.state[r].val=0;
1161     live.state[r].dirtysize=0;
1162     set_status(r,CLEAN);
1163     log_isused(bestreg);
1164     }
1165     live.state[r].validsize=4;
1166     }
1167     else { /* this is the easiest way, but not optimal. FIXME! */
1168     /* Now it's trickier, but hopefully still OK */
1169     if (!isconst(r) || size==4) {
1170     live.state[r].validsize=size;
1171     live.state[r].dirtysize=size;
1172     live.state[r].val=0;
1173     set_status(r,DIRTY);
1174     if (size == 4) {
1175     log_clobberreg(r);
1176     log_isused(bestreg);
1177     }
1178     else {
1179     log_visused(r);
1180     log_isused(bestreg);
1181     }
1182     }
1183     else {
1184     if (live.state[r].status!=UNDEF)
1185     raw_mov_l_ri(bestreg,live.state[r].val);
1186     live.state[r].val=0;
1187     live.state[r].validsize=4;
1188     live.state[r].dirtysize=4;
1189     set_status(r,DIRTY);
1190     log_isused(bestreg);
1191     }
1192     }
1193     live.state[r].realreg=bestreg;
1194     live.state[r].realind=live.nat[bestreg].nholds;
1195     live.nat[bestreg].touched=touchcnt++;
1196     live.nat[bestreg].holds[live.nat[bestreg].nholds]=r;
1197     live.nat[bestreg].nholds++;
1198    
1199     return bestreg;
1200     }
1201    
1202     static int alloc_reg(int r, int size, int willclobber)
1203     {
1204     return alloc_reg_hinted(r,size,willclobber,-1);
1205     }
1206    
1207     static void unlock2(int r)
1208     {
1209     Dif (!live.nat[r].locked)
1210     abort();
1211     live.nat[r].locked--;
1212     }
1213    
1214     static void setlock(int r)
1215     {
1216     live.nat[r].locked++;
1217     }
1218    
1219    
1220     static void mov_nregs(int d, int s)
1221     {
1222     int ns=live.nat[s].nholds;
1223     int nd=live.nat[d].nholds;
1224     int i;
1225    
1226     if (s==d)
1227     return;
1228    
1229     if (nd>0)
1230     free_nreg(d);
1231    
1232     log_isused(d);
1233     raw_mov_l_rr(d,s);
1234    
1235     for (i=0;i<live.nat[s].nholds;i++) {
1236     int vs=live.nat[s].holds[i];
1237    
1238     live.state[vs].realreg=d;
1239     live.state[vs].realind=i;
1240     live.nat[d].holds[i]=vs;
1241     }
1242     live.nat[d].nholds=live.nat[s].nholds;
1243    
1244     live.nat[s].nholds=0;
1245     }
1246    
1247    
1248     static __inline__ void make_exclusive(int r, int size, int spec)
1249     {
1250     int clobber;
1251     reg_status oldstate;
1252     int rr=live.state[r].realreg;
1253     int nr;
1254     int nind;
1255     int ndirt=0;
1256     int i;
1257    
1258     if (!isinreg(r))
1259     return;
1260     if (live.nat[rr].nholds==1)
1261     return;
1262     for (i=0;i<live.nat[rr].nholds;i++) {
1263     int vr=live.nat[rr].holds[i];
1264     if (vr!=r &&
1265     (live.state[vr].status==DIRTY || live.state[vr].val))
1266     ndirt++;
1267     }
1268     if (!ndirt && size<live.state[r].validsize && !live.nat[rr].locked) {
1269     /* Everything else is clean, so let's keep this register */
1270     for (i=0;i<live.nat[rr].nholds;i++) {
1271     int vr=live.nat[rr].holds[i];
1272     if (vr!=r) {
1273     evict(vr);
1274     i--; /* Try that index again! */
1275     }
1276     }
1277     Dif (live.nat[rr].nholds!=1) {
1278     write_log("natreg %d holds %d vregs, %d not exclusive\n",
1279     rr,live.nat[rr].nholds,r);
1280     abort();
1281     }
1282     return;
1283     }
1284    
1285     /* We have to split the register */
1286     oldstate=live.state[r];
1287    
1288     setlock(rr); /* Make sure this doesn't go away */
1289     /* Forget about r being in the register rr */
1290     disassociate(r);
1291     /* Get a new register, that we will clobber completely */
1292     if (oldstate.status==DIRTY) {
1293     /* If dirtysize is <4, we need a register that can handle the
1294     eventual smaller memory store! Thanks to Quake68k for exposing
1295     this detail ;-) */
1296     nr=alloc_reg_hinted(r,oldstate.dirtysize,1,spec);
1297     }
1298     else {
1299     nr=alloc_reg_hinted(r,4,1,spec);
1300     }
1301     nind=live.state[r].realind;
1302     live.state[r]=oldstate; /* Keep all the old state info */
1303     live.state[r].realreg=nr;
1304     live.state[r].realind=nind;
1305    
1306     if (size<live.state[r].validsize) {
1307     if (live.state[r].val) {
1308     /* Might as well compensate for the offset now */
1309     raw_lea_l_brr(nr,rr,oldstate.val);
1310     live.state[r].val=0;
1311     live.state[r].dirtysize=4;
1312     set_status(r,DIRTY);
1313     }
1314     else
1315     raw_mov_l_rr(nr,rr); /* Make another copy */
1316     }
1317     unlock2(rr);
1318     }
1319    
1320     static __inline__ void add_offset(int r, uae_u32 off)
1321     {
1322     live.state[r].val+=off;
1323     }
1324    
1325     static __inline__ void remove_offset(int r, int spec)
1326     {
1327     reg_status oldstate;
1328     int rr;
1329    
1330     if (isconst(r))
1331     return;
1332     if (live.state[r].val==0)
1333     return;
1334     if (isinreg(r) && live.state[r].validsize<4)
1335     evict(r);
1336    
1337     if (!isinreg(r))
1338     alloc_reg_hinted(r,4,0,spec);
1339    
1340     Dif (live.state[r].validsize!=4) {
1341     write_log("Validsize=%d in remove_offset\n",live.state[r].validsize);
1342     abort();
1343     }
1344     make_exclusive(r,0,-1);
1345     /* make_exclusive might have done the job already */
1346     if (live.state[r].val==0)
1347     return;
1348    
1349     rr=live.state[r].realreg;
1350    
1351     if (live.nat[rr].nholds==1) {
1352     //write_log("RemovingB offset %x from reg %d (%d) at %p\n",
1353     // live.state[r].val,r,rr,target);
1354     adjust_nreg(rr,live.state[r].val);
1355     live.state[r].dirtysize=4;
1356     live.state[r].val=0;
1357     set_status(r,DIRTY);
1358     return;
1359     }
1360     write_log("Failed in remove_offset\n");
1361     abort();
1362     }
1363    
1364     static __inline__ void remove_all_offsets(void)
1365     {
1366     int i;
1367    
1368     for (i=0;i<VREGS;i++)
1369     remove_offset(i,-1);
1370     }
1371    
1372     static __inline__ int readreg_general(int r, int size, int spec, int can_offset)
1373     {
1374     int n;
1375     int answer=-1;
1376    
1377     if (live.state[r].status==UNDEF) {
1378     write_log("WARNING: Unexpected read of undefined register %d\n",r);
1379     }
1380     if (!can_offset)
1381     remove_offset(r,spec);
1382    
1383     if (isinreg(r) && live.state[r].validsize>=size) {
1384     n=live.state[r].realreg;
1385     switch(size) {
1386     case 1:
1387     if (live.nat[n].canbyte || spec>=0) {
1388     answer=n;
1389     }
1390     break;
1391     case 2:
1392     if (live.nat[n].canword || spec>=0) {
1393     answer=n;
1394     }
1395     break;
1396     case 4:
1397     answer=n;
1398     break;
1399     default: abort();
1400     }
1401     if (answer<0)
1402     evict(r);
1403     }
1404     /* either the value was in memory to start with, or it was evicted and
1405     is in memory now */
1406     if (answer<0) {
1407     answer=alloc_reg_hinted(r,spec>=0?4:size,0,spec);
1408     }
1409    
1410     if (spec>=0 && spec!=answer) {
1411     /* Too bad */
1412     mov_nregs(spec,answer);
1413     answer=spec;
1414     }
1415     live.nat[answer].locked++;
1416     live.nat[answer].touched=touchcnt++;
1417     return answer;
1418     }
1419    
1420    
1421    
1422     static int readreg(int r, int size)
1423     {
1424     return readreg_general(r,size,-1,0);
1425     }
1426    
1427     static int readreg_specific(int r, int size, int spec)
1428     {
1429     return readreg_general(r,size,spec,0);
1430     }
1431    
1432     static int readreg_offset(int r, int size)
1433     {
1434     return readreg_general(r,size,-1,1);
1435     }
1436    
1437     /* writereg_general(r, size, spec)
1438     *
1439     * INPUT
1440     * - r : mid-layer register
1441     * - size : requested size (1/2/4)
1442     * - spec : -1 if find or make a register free, otherwise specifies
1443     * the physical register to use in any case
1444     *
1445     * OUTPUT
1446     * - hard (physical, x86 here) register allocated to virtual register r
1447     */
1448     static __inline__ int writereg_general(int r, int size, int spec)
1449     {
1450     int n;
1451     int answer=-1;
1452    
1453     if (size<4) {
1454     remove_offset(r,spec);
1455     }
1456    
1457     make_exclusive(r,size,spec);
1458     if (isinreg(r)) {
1459     int nvsize=size>live.state[r].validsize?size:live.state[r].validsize;
1460     int ndsize=size>live.state[r].dirtysize?size:live.state[r].dirtysize;
1461     n=live.state[r].realreg;
1462    
1463     Dif (live.nat[n].nholds!=1)
1464     abort();
1465     switch(size) {
1466     case 1:
1467     if (live.nat[n].canbyte || spec>=0) {
1468     live.state[r].dirtysize=ndsize;
1469     live.state[r].validsize=nvsize;
1470     answer=n;
1471     }
1472     break;
1473     case 2:
1474     if (live.nat[n].canword || spec>=0) {
1475     live.state[r].dirtysize=ndsize;
1476     live.state[r].validsize=nvsize;
1477     answer=n;
1478     }
1479     break;
1480     case 4:
1481     live.state[r].dirtysize=ndsize;
1482     live.state[r].validsize=nvsize;
1483     answer=n;
1484     break;
1485     default: abort();
1486     }
1487     if (answer<0)
1488     evict(r);
1489     }
1490     /* either the value was in memory to start with, or it was evicted and
1491     is in memory now */
1492     if (answer<0) {
1493     answer=alloc_reg_hinted(r,size,1,spec);
1494     }
1495     if (spec>=0 && spec!=answer) {
1496     mov_nregs(spec,answer);
1497     answer=spec;
1498     }
1499     if (live.state[r].status==UNDEF)
1500     live.state[r].validsize=4;
1501     live.state[r].dirtysize=size>live.state[r].dirtysize?size:live.state[r].dirtysize;
1502     live.state[r].validsize=size>live.state[r].validsize?size:live.state[r].validsize;
1503    
1504     live.nat[answer].locked++;
1505     live.nat[answer].touched=touchcnt++;
1506     if (size==4) {
1507     live.state[r].val=0;
1508     }
1509     else {
1510     Dif (live.state[r].val) {
1511     write_log("Problem with val\n");
1512     abort();
1513     }
1514     }
1515     set_status(r,DIRTY);
1516     return answer;
1517     }
1518    
1519     static int writereg(int r, int size)
1520     {
1521     return writereg_general(r,size,-1);
1522     }
1523    
1524     static int writereg_specific(int r, int size, int spec)
1525     {
1526     return writereg_general(r,size,spec);
1527     }
1528    
1529     static __inline__ int rmw_general(int r, int wsize, int rsize, int spec)
1530     {
1531     int n;
1532     int answer=-1;
1533    
1534     if (live.state[r].status==UNDEF) {
1535     write_log("WARNING: Unexpected read of undefined register %d\n",r);
1536     }
1537     remove_offset(r,spec);
1538     make_exclusive(r,0,spec);
1539    
1540     Dif (wsize<rsize) {
1541     write_log("Cannot handle wsize<rsize in rmw_general()\n");
1542     abort();
1543     }
1544     if (isinreg(r) && live.state[r].validsize>=rsize) {
1545     n=live.state[r].realreg;
1546     Dif (live.nat[n].nholds!=1)
1547     abort();
1548    
1549     switch(rsize) {
1550     case 1:
1551     if (live.nat[n].canbyte || spec>=0) {
1552     answer=n;
1553     }
1554     break;
1555     case 2:
1556     if (live.nat[n].canword || spec>=0) {
1557     answer=n;
1558     }
1559     break;
1560     case 4:
1561     answer=n;
1562     break;
1563     default: abort();
1564     }
1565     if (answer<0)
1566     evict(r);
1567     }
1568     /* either the value was in memory to start with, or it was evicted and
1569     is in memory now */
1570     if (answer<0) {
1571     answer=alloc_reg_hinted(r,spec>=0?4:rsize,0,spec);
1572     }
1573    
1574     if (spec>=0 && spec!=answer) {
1575     /* Too bad */
1576     mov_nregs(spec,answer);
1577     answer=spec;
1578     }
1579     if (wsize>live.state[r].dirtysize)
1580     live.state[r].dirtysize=wsize;
1581     if (wsize>live.state[r].validsize)
1582     live.state[r].validsize=wsize;
1583     set_status(r,DIRTY);
1584    
1585     live.nat[answer].locked++;
1586     live.nat[answer].touched=touchcnt++;
1587    
1588     Dif (live.state[r].val) {
1589     write_log("Problem with val(rmw)\n");
1590     abort();
1591     }
1592     return answer;
1593     }
1594    
1595     static int rmw(int r, int wsize, int rsize)
1596     {
1597     return rmw_general(r,wsize,rsize,-1);
1598     }
1599    
1600     static int rmw_specific(int r, int wsize, int rsize, int spec)
1601     {
1602     return rmw_general(r,wsize,rsize,spec);
1603     }
1604    
1605    
1606     /* needed for restoring the carry flag on non-P6 cores */
1607     static void bt_l_ri_noclobber(R4 r, IMM i)
1608     {
1609     int size=4;
1610     if (i<16)
1611     size=2;
1612     r=readreg(r,size);
1613     raw_bt_l_ri(r,i);
1614     unlock2(r);
1615     }
1616    
1617     /********************************************************************
1618     * FPU register status handling. EMIT TIME! *
1619     ********************************************************************/
1620    
1621     static void f_tomem(int r)
1622     {
1623     if (live.fate[r].status==DIRTY) {
1624     #if USE_LONG_DOUBLE
1625     raw_fmov_ext_mr((uae_u32)live.fate[r].mem,live.fate[r].realreg);
1626     #else
1627     raw_fmov_mr((uae_u32)live.fate[r].mem,live.fate[r].realreg);
1628     #endif
1629     live.fate[r].status=CLEAN;
1630     }
1631     }
1632    
1633     static void f_tomem_drop(int r)
1634     {
1635     if (live.fate[r].status==DIRTY) {
1636     #if USE_LONG_DOUBLE
1637     raw_fmov_ext_mr_drop((uae_u32)live.fate[r].mem,live.fate[r].realreg);
1638     #else
1639     raw_fmov_mr_drop((uae_u32)live.fate[r].mem,live.fate[r].realreg);
1640     #endif
1641     live.fate[r].status=INMEM;
1642     }
1643     }
1644    
1645    
1646     static __inline__ int f_isinreg(int r)
1647     {
1648     return live.fate[r].status==CLEAN || live.fate[r].status==DIRTY;
1649     }
1650    
1651     static void f_evict(int r)
1652     {
1653     int rr;
1654    
1655     if (!f_isinreg(r))
1656     return;
1657     rr=live.fate[r].realreg;
1658     if (live.fat[rr].nholds==1)
1659     f_tomem_drop(r);
1660     else
1661     f_tomem(r);
1662    
1663     Dif (live.fat[rr].locked &&
1664     live.fat[rr].nholds==1) {
1665     write_log("FPU register %d in nreg %d is locked!\n",r,live.fate[r].realreg);
1666     abort();
1667     }
1668    
1669     live.fat[rr].nholds--;
1670     if (live.fat[rr].nholds!=live.fate[r].realind) { /* Was not last */
1671     int topreg=live.fat[rr].holds[live.fat[rr].nholds];
1672     int thisind=live.fate[r].realind;
1673     live.fat[rr].holds[thisind]=topreg;
1674     live.fate[topreg].realind=thisind;
1675     }
1676     live.fate[r].status=INMEM;
1677     live.fate[r].realreg=-1;
1678     }
1679    
1680     static __inline__ void f_free_nreg(int r)
1681     {
1682     int i=live.fat[r].nholds;
1683    
1684     while (i) {
1685     int vr;
1686    
1687     --i;
1688     vr=live.fat[r].holds[i];
1689     f_evict(vr);
1690     }
1691     Dif (live.fat[r].nholds!=0) {
1692     write_log("Failed to free nreg %d, nholds is %d\n",r,live.fat[r].nholds);
1693     abort();
1694     }
1695     }
1696    
1697    
1698     /* Use with care! */
1699     static __inline__ void f_isclean(int r)
1700     {
1701     if (!f_isinreg(r))
1702     return;
1703     live.fate[r].status=CLEAN;
1704     }
1705    
1706     static __inline__ void f_disassociate(int r)
1707     {
1708     f_isclean(r);
1709     f_evict(r);
1710     }
1711    
1712    
1713    
1714     static int f_alloc_reg(int r, int willclobber)
1715     {
1716     int bestreg;
1717     uae_s32 when;
1718     int i;
1719     uae_s32 badness;
1720     bestreg=-1;
1721     when=2000000000;
1722     for (i=N_FREGS;i--;) {
1723     badness=live.fat[i].touched;
1724     if (live.fat[i].nholds==0)
1725     badness=0;
1726    
1727     if (!live.fat[i].locked && badness<when) {
1728     bestreg=i;
1729     when=badness;
1730     if (live.fat[i].nholds==0)
1731     break;
1732     }
1733     }
1734     Dif (bestreg==-1)
1735     abort();
1736    
1737     if (live.fat[bestreg].nholds>0) {
1738     f_free_nreg(bestreg);
1739     }
1740     if (f_isinreg(r)) {
1741     f_evict(r);
1742     }
1743    
1744     if (!willclobber) {
1745     if (live.fate[r].status!=UNDEF) {
1746     #if USE_LONG_DOUBLE
1747     raw_fmov_ext_rm(bestreg,(uae_u32)live.fate[r].mem);
1748     #else
1749     raw_fmov_rm(bestreg,(uae_u32)live.fate[r].mem);
1750     #endif
1751     }
1752     live.fate[r].status=CLEAN;
1753     }
1754     else {
1755     live.fate[r].status=DIRTY;
1756     }
1757     live.fate[r].realreg=bestreg;
1758     live.fate[r].realind=live.fat[bestreg].nholds;
1759     live.fat[bestreg].touched=touchcnt++;
1760     live.fat[bestreg].holds[live.fat[bestreg].nholds]=r;
1761     live.fat[bestreg].nholds++;
1762    
1763     return bestreg;
1764     }
1765    
1766     static void f_unlock(int r)
1767     {
1768     Dif (!live.fat[r].locked)
1769     abort();
1770     live.fat[r].locked--;
1771     }
1772    
1773     static void f_setlock(int r)
1774     {
1775     live.fat[r].locked++;
1776     }
1777    
1778     static __inline__ int f_readreg(int r)
1779     {
1780     int n;
1781     int answer=-1;
1782    
1783     if (f_isinreg(r)) {
1784     n=live.fate[r].realreg;
1785     answer=n;
1786     }
1787     /* either the value was in memory to start with, or it was evicted and
1788     is in memory now */
1789     if (answer<0)
1790     answer=f_alloc_reg(r,0);
1791    
1792     live.fat[answer].locked++;
1793     live.fat[answer].touched=touchcnt++;
1794     return answer;
1795     }
1796    
1797     static __inline__ void f_make_exclusive(int r, int clobber)
1798     {
1799     freg_status oldstate;
1800     int rr=live.fate[r].realreg;
1801     int nr;
1802     int nind;
1803     int ndirt=0;
1804     int i;
1805    
1806     if (!f_isinreg(r))
1807     return;
1808     if (live.fat[rr].nholds==1)
1809     return;
1810     for (i=0;i<live.fat[rr].nholds;i++) {
1811     int vr=live.fat[rr].holds[i];
1812     if (vr!=r && live.fate[vr].status==DIRTY)
1813     ndirt++;
1814     }
1815     if (!ndirt && !live.fat[rr].locked) {
1816     /* Everything else is clean, so let's keep this register */
1817     for (i=0;i<live.fat[rr].nholds;i++) {
1818     int vr=live.fat[rr].holds[i];
1819     if (vr!=r) {
1820     f_evict(vr);
1821     i--; /* Try that index again! */
1822     }
1823     }
1824     Dif (live.fat[rr].nholds!=1) {
1825     write_log("realreg %d holds %d (",rr,live.fat[rr].nholds);
1826     for (i=0;i<live.fat[rr].nholds;i++) {
1827     write_log(" %d(%d,%d)",live.fat[rr].holds[i],
1828     live.fate[live.fat[rr].holds[i]].realreg,
1829     live.fate[live.fat[rr].holds[i]].realind);
1830     }
1831     write_log("\n");
1832     abort();
1833     }
1834     return;
1835     }
1836    
1837     /* We have to split the register */
1838     oldstate=live.fate[r];
1839    
1840     f_setlock(rr); /* Make sure this doesn't go away */
1841     /* Forget about r being in the register rr */
1842     f_disassociate(r);
1843     /* Get a new register, that we will clobber completely */
1844     nr=f_alloc_reg(r,1);
1845     nind=live.fate[r].realind;
1846     if (!clobber)
1847     raw_fmov_rr(nr,rr); /* Make another copy */
1848     live.fate[r]=oldstate; /* Keep all the old state info */
1849     live.fate[r].realreg=nr;
1850     live.fate[r].realind=nind;
1851     f_unlock(rr);
1852     }
1853    
1854    
1855     static __inline__ int f_writereg(int r)
1856     {
1857     int n;
1858     int answer=-1;
1859    
1860     f_make_exclusive(r,1);
1861     if (f_isinreg(r)) {
1862     n=live.fate[r].realreg;
1863     answer=n;
1864     }
1865     if (answer<0) {
1866     answer=f_alloc_reg(r,1);
1867     }
1868     live.fate[r].status=DIRTY;
1869     live.fat[answer].locked++;
1870     live.fat[answer].touched=touchcnt++;
1871     return answer;
1872     }
1873    
1874     static int f_rmw(int r)
1875     {
1876     int n;
1877    
1878     f_make_exclusive(r,0);
1879     if (f_isinreg(r)) {
1880     n=live.fate[r].realreg;
1881     }
1882     else
1883     n=f_alloc_reg(r,0);
1884     live.fate[r].status=DIRTY;
1885     live.fat[n].locked++;
1886     live.fat[n].touched=touchcnt++;
1887     return n;
1888     }
1889    
1890     static void fflags_into_flags_internal(uae_u32 tmp)
1891     {
1892     int r;
1893    
1894     clobber_flags();
1895     r=f_readreg(FP_RESULT);
1896     if (FFLAG_NREG_CLOBBER_CONDITION) {
1897     int tmp2=tmp;
1898     tmp=writereg_specific(tmp,4,FFLAG_NREG);
1899     raw_fflags_into_flags(r);
1900     unlock2(tmp);
1901     forget_about(tmp2);
1902     }
1903     else
1904     raw_fflags_into_flags(r);
1905     f_unlock(r);
1906     }
1907    
1908    
1909    
1910    
1911     /********************************************************************
1912     * CPU functions exposed to gencomp. Both CREATE and EMIT time *
1913     ********************************************************************/
1914    
1915     /*
1916     * RULES FOR HANDLING REGISTERS:
1917     *
1918     * * In the function headers, order the parameters
1919     * - 1st registers written to
1920     * - 2nd read/modify/write registers
1921     * - 3rd registers read from
1922     * * Before calling raw_*, you must call readreg, writereg or rmw for
1923     * each register
1924     * * The order for this is
1925     * - 1st call remove_offset for all registers written to with size<4
1926     * - 2nd call readreg for all registers read without offset
1927     * - 3rd call rmw for all rmw registers
1928     * - 4th call readreg_offset for all registers that can handle offsets
1929     * - 5th call get_offset for all the registers from the previous step
1930     * - 6th call writereg for all written-to registers
1931     * - 7th call raw_*
1932     * - 8th unlock2 all registers that were locked
1933     */
1934    
1935     MIDFUNC(0,live_flags,(void))
1936     {
1937     live.flags_on_stack=TRASH;
1938     live.flags_in_flags=VALID;
1939     live.flags_are_important=1;
1940     }
1941     MENDFUNC(0,live_flags,(void))
1942    
1943     MIDFUNC(0,dont_care_flags,(void))
1944     {
1945     live.flags_are_important=0;
1946     }
1947     MENDFUNC(0,dont_care_flags,(void))
1948    
1949    
1950     MIDFUNC(0,duplicate_carry,(void))
1951     {
1952     evict(FLAGX);
1953     make_flags_live_internal();
1954     COMPCALL(setcc_m)((uae_u32)live.state[FLAGX].mem,2);
1955     log_vwrite(FLAGX);
1956     }
1957     MENDFUNC(0,duplicate_carry,(void))
1958    
1959     MIDFUNC(0,restore_carry,(void))
1960     {
1961     if (!have_rat_stall) { /* Not a P6 core, i.e. no partial stalls */
1962     bt_l_ri_noclobber(FLAGX,0);
1963     }
1964     else { /* Avoid the stall the above creates.
1965     This is slow on non-P6, though.
1966     */
1967     COMPCALL(rol_b_ri(FLAGX,8));
1968     isclean(FLAGX);
1969     }
1970     }
1971     MENDFUNC(0,restore_carry,(void))
1972    
1973     MIDFUNC(0,start_needflags,(void))
1974     {
1975     needflags=1;
1976     }
1977     MENDFUNC(0,start_needflags,(void))
1978    
1979     MIDFUNC(0,end_needflags,(void))
1980     {
1981     needflags=0;
1982     }
1983     MENDFUNC(0,end_needflags,(void))
1984    
1985     MIDFUNC(0,make_flags_live,(void))
1986     {
1987     make_flags_live_internal();
1988     }
1989     MENDFUNC(0,make_flags_live,(void))
1990    
1991     MIDFUNC(1,fflags_into_flags,(W2 tmp))
1992     {
1993     clobber_flags();
1994     fflags_into_flags_internal(tmp);
1995     }
1996     MENDFUNC(1,fflags_into_flags,(W2 tmp))
1997    
1998    
1999     MIDFUNC(2,bt_l_ri,(R4 r, IMM i)) /* This is defined as only affecting C */
2000     {
2001     int size=4;
2002     if (i<16)
2003     size=2;
2004     CLOBBER_BT;
2005     r=readreg(r,size);
2006     raw_bt_l_ri(r,i);
2007     unlock2(r);
2008     }
2009     MENDFUNC(2,bt_l_ri,(R4 r, IMM i)) /* This is defined as only affecting C */
2010    
2011     MIDFUNC(2,bt_l_rr,(R4 r, R4 b)) /* This is defined as only affecting C */
2012     {
2013     CLOBBER_BT;
2014     r=readreg(r,4);
2015     b=readreg(b,4);
2016     raw_bt_l_rr(r,b);
2017     unlock2(r);
2018     unlock2(b);
2019     }
2020     MENDFUNC(2,bt_l_rr,(R4 r, R4 b)) /* This is defined as only affecting C */
2021    
2022     MIDFUNC(2,btc_l_ri,(RW4 r, IMM i))
2023     {
2024     int size=4;
2025     if (i<16)
2026     size=2;
2027     CLOBBER_BT;
2028     r=rmw(r,size,size);
2029     raw_btc_l_ri(r,i);
2030     unlock2(r);
2031     }
2032     MENDFUNC(2,btc_l_ri,(RW4 r, IMM i))
2033    
2034     MIDFUNC(2,btc_l_rr,(RW4 r, R4 b))
2035     {
2036     CLOBBER_BT;
2037     b=readreg(b,4);
2038     r=rmw(r,4,4);
2039     raw_btc_l_rr(r,b);
2040     unlock2(r);
2041     unlock2(b);
2042     }
2043     MENDFUNC(2,btc_l_rr,(RW4 r, R4 b))
2044    
2045    
2046     MIDFUNC(2,btr_l_ri,(RW4 r, IMM i))
2047     {
2048     int size=4;
2049     if (i<16)
2050     size=2;
2051     CLOBBER_BT;
2052     r=rmw(r,size,size);
2053     raw_btr_l_ri(r,i);
2054     unlock2(r);
2055     }
2056     MENDFUNC(2,btr_l_ri,(RW4 r, IMM i))
2057    
2058     MIDFUNC(2,btr_l_rr,(RW4 r, R4 b))
2059     {
2060     CLOBBER_BT;
2061     b=readreg(b,4);
2062     r=rmw(r,4,4);
2063     raw_btr_l_rr(r,b);
2064     unlock2(r);
2065     unlock2(b);
2066     }
2067     MENDFUNC(2,btr_l_rr,(RW4 r, R4 b))
2068    
2069    
2070     MIDFUNC(2,bts_l_ri,(RW4 r, IMM i))
2071     {
2072     int size=4;
2073     if (i<16)
2074     size=2;
2075     CLOBBER_BT;
2076     r=rmw(r,size,size);
2077     raw_bts_l_ri(r,i);
2078     unlock2(r);
2079     }
2080     MENDFUNC(2,bts_l_ri,(RW4 r, IMM i))
2081    
2082     MIDFUNC(2,bts_l_rr,(RW4 r, R4 b))
2083     {
2084     CLOBBER_BT;
2085     b=readreg(b,4);
2086     r=rmw(r,4,4);
2087     raw_bts_l_rr(r,b);
2088     unlock2(r);
2089     unlock2(b);
2090     }
2091     MENDFUNC(2,bts_l_rr,(RW4 r, R4 b))
2092    
2093     MIDFUNC(2,mov_l_rm,(W4 d, IMM s))
2094     {
2095     CLOBBER_MOV;
2096     d=writereg(d,4);
2097     raw_mov_l_rm(d,s);
2098     unlock2(d);
2099     }
2100     MENDFUNC(2,mov_l_rm,(W4 d, IMM s))
2101    
2102    
2103     MIDFUNC(1,call_r,(R4 r)) /* Clobbering is implicit */
2104     {
2105     r=readreg(r,4);
2106     raw_call_r(r);
2107     unlock2(r);
2108     }
2109     MENDFUNC(1,call_r,(R4 r)) /* Clobbering is implicit */
2110    
2111     MIDFUNC(2,sub_l_mi,(IMM d, IMM s))
2112     {
2113     CLOBBER_SUB;
2114     raw_sub_l_mi(d,s) ;
2115     }
2116     MENDFUNC(2,sub_l_mi,(IMM d, IMM s))
2117    
2118     MIDFUNC(2,mov_l_mi,(IMM d, IMM s))
2119     {
2120     CLOBBER_MOV;
2121     raw_mov_l_mi(d,s) ;
2122     }
2123     MENDFUNC(2,mov_l_mi,(IMM d, IMM s))
2124    
2125     MIDFUNC(2,mov_w_mi,(IMM d, IMM s))
2126     {
2127     CLOBBER_MOV;
2128     raw_mov_w_mi(d,s) ;
2129     }
2130     MENDFUNC(2,mov_w_mi,(IMM d, IMM s))
2131    
2132     MIDFUNC(2,mov_b_mi,(IMM d, IMM s))
2133     {
2134     CLOBBER_MOV;
2135     raw_mov_b_mi(d,s) ;
2136     }
2137     MENDFUNC(2,mov_b_mi,(IMM d, IMM s))
2138    
2139     MIDFUNC(2,rol_b_ri,(RW1 r, IMM i))
2140     {
2141     if (!i && !needflags)
2142     return;
2143     CLOBBER_ROL;
2144     r=rmw(r,1,1);
2145     raw_rol_b_ri(r,i);
2146     unlock2(r);
2147     }
2148     MENDFUNC(2,rol_b_ri,(RW1 r, IMM i))
2149    
2150     MIDFUNC(2,rol_w_ri,(RW2 r, IMM i))
2151     {
2152     if (!i && !needflags)
2153     return;
2154     CLOBBER_ROL;
2155     r=rmw(r,2,2);
2156     raw_rol_w_ri(r,i);
2157     unlock2(r);
2158     }
2159     MENDFUNC(2,rol_w_ri,(RW2 r, IMM i))
2160    
2161     MIDFUNC(2,rol_l_ri,(RW4 r, IMM i))
2162     {
2163     if (!i && !needflags)
2164     return;
2165     CLOBBER_ROL;
2166     r=rmw(r,4,4);
2167     raw_rol_l_ri(r,i);
2168     unlock2(r);
2169     }
2170     MENDFUNC(2,rol_l_ri,(RW4 r, IMM i))
2171    
2172     MIDFUNC(2,rol_l_rr,(RW4 d, R1 r))
2173     {
2174     if (isconst(r)) {
2175     COMPCALL(rol_l_ri)(d,(uae_u8)live.state[r].val);
2176     return;
2177     }
2178     CLOBBER_ROL;
2179     r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2180     d=rmw(d,4,4);
2181     Dif (r!=1) {
2182     write_log("Illegal register %d in raw_rol_b\n",r);
2183     abort();
2184     }
2185     raw_rol_l_rr(d,r) ;
2186     unlock2(r);
2187     unlock2(d);
2188     }
2189     MENDFUNC(2,rol_l_rr,(RW4 d, R1 r))
2190    
2191     MIDFUNC(2,rol_w_rr,(RW2 d, R1 r))
2192     { /* Can only do this with r==1, i.e. cl */
2193    
2194     if (isconst(r)) {
2195     COMPCALL(rol_w_ri)(d,(uae_u8)live.state[r].val);
2196     return;
2197     }
2198     CLOBBER_ROL;
2199     r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2200     d=rmw(d,2,2);
2201     Dif (r!=1) {
2202     write_log("Illegal register %d in raw_rol_b\n",r);
2203     abort();
2204     }
2205     raw_rol_w_rr(d,r) ;
2206     unlock2(r);
2207     unlock2(d);
2208     }
2209     MENDFUNC(2,rol_w_rr,(RW2 d, R1 r))
2210    
2211     MIDFUNC(2,rol_b_rr,(RW1 d, R1 r))
2212     { /* Can only do this with r==1, i.e. cl */
2213    
2214     if (isconst(r)) {
2215     COMPCALL(rol_b_ri)(d,(uae_u8)live.state[r].val);
2216     return;
2217     }
2218    
2219     CLOBBER_ROL;
2220     r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2221     d=rmw(d,1,1);
2222     Dif (r!=1) {
2223     write_log("Illegal register %d in raw_rol_b\n",r);
2224     abort();
2225     }
2226     raw_rol_b_rr(d,r) ;
2227     unlock2(r);
2228     unlock2(d);
2229     }
2230     MENDFUNC(2,rol_b_rr,(RW1 d, R1 r))
2231    
2232    
2233     MIDFUNC(2,shll_l_rr,(RW4 d, R1 r))
2234     {
2235     if (isconst(r)) {
2236     COMPCALL(shll_l_ri)(d,(uae_u8)live.state[r].val);
2237     return;
2238     }
2239     CLOBBER_SHLL;
2240     r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2241     d=rmw(d,4,4);
2242     Dif (r!=1) {
2243     write_log("Illegal register %d in raw_rol_b\n",r);
2244     abort();
2245     }
2246     raw_shll_l_rr(d,r) ;
2247     unlock2(r);
2248     unlock2(d);
2249     }
2250     MENDFUNC(2,shll_l_rr,(RW4 d, R1 r))
2251    
2252     MIDFUNC(2,shll_w_rr,(RW2 d, R1 r))
2253     { /* Can only do this with r==1, i.e. cl */
2254    
2255     if (isconst(r)) {
2256     COMPCALL(shll_w_ri)(d,(uae_u8)live.state[r].val);
2257     return;
2258     }
2259     CLOBBER_SHLL;
2260     r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2261     d=rmw(d,2,2);
2262     Dif (r!=1) {
2263     write_log("Illegal register %d in raw_shll_b\n",r);
2264     abort();
2265     }
2266     raw_shll_w_rr(d,r) ;
2267     unlock2(r);
2268     unlock2(d);
2269     }
2270     MENDFUNC(2,shll_w_rr,(RW2 d, R1 r))
2271    
2272     MIDFUNC(2,shll_b_rr,(RW1 d, R1 r))
2273     { /* Can only do this with r==1, i.e. cl */
2274    
2275     if (isconst(r)) {
2276     COMPCALL(shll_b_ri)(d,(uae_u8)live.state[r].val);
2277     return;
2278     }
2279    
2280     CLOBBER_SHLL;
2281     r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2282     d=rmw(d,1,1);
2283     Dif (r!=1) {
2284     write_log("Illegal register %d in raw_shll_b\n",r);
2285     abort();
2286     }
2287     raw_shll_b_rr(d,r) ;
2288     unlock2(r);
2289     unlock2(d);
2290     }
2291     MENDFUNC(2,shll_b_rr,(RW1 d, R1 r))
2292    
2293    
2294     MIDFUNC(2,ror_b_ri,(R1 r, IMM i))
2295     {
2296     if (!i && !needflags)
2297     return;
2298     CLOBBER_ROR;
2299     r=rmw(r,1,1);
2300     raw_ror_b_ri(r,i);
2301     unlock2(r);
2302     }
2303     MENDFUNC(2,ror_b_ri,(R1 r, IMM i))
2304    
2305     MIDFUNC(2,ror_w_ri,(R2 r, IMM i))
2306     {
2307     if (!i && !needflags)
2308     return;
2309     CLOBBER_ROR;
2310     r=rmw(r,2,2);
2311     raw_ror_w_ri(r,i);
2312     unlock2(r);
2313     }
2314     MENDFUNC(2,ror_w_ri,(R2 r, IMM i))
2315    
2316     MIDFUNC(2,ror_l_ri,(R4 r, IMM i))
2317     {
2318     if (!i && !needflags)
2319     return;
2320     CLOBBER_ROR;
2321     r=rmw(r,4,4);
2322     raw_ror_l_ri(r,i);
2323     unlock2(r);
2324     }
2325     MENDFUNC(2,ror_l_ri,(R4 r, IMM i))
2326    
2327     MIDFUNC(2,ror_l_rr,(R4 d, R1 r))
2328     {
2329     if (isconst(r)) {
2330     COMPCALL(ror_l_ri)(d,(uae_u8)live.state[r].val);
2331     return;
2332     }
2333     CLOBBER_ROR;
2334     r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2335     d=rmw(d,4,4);
2336     raw_ror_l_rr(d,r) ;
2337     unlock2(r);
2338     unlock2(d);
2339     }
2340     MENDFUNC(2,ror_l_rr,(R4 d, R1 r))
2341    
2342     MIDFUNC(2,ror_w_rr,(R2 d, R1 r))
2343     {
2344     if (isconst(r)) {
2345     COMPCALL(ror_w_ri)(d,(uae_u8)live.state[r].val);
2346     return;
2347     }
2348     CLOBBER_ROR;
2349     r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2350     d=rmw(d,2,2);
2351     raw_ror_w_rr(d,r) ;
2352     unlock2(r);
2353     unlock2(d);
2354     }
2355     MENDFUNC(2,ror_w_rr,(R2 d, R1 r))
2356    
2357     MIDFUNC(2,ror_b_rr,(R1 d, R1 r))
2358     {
2359     if (isconst(r)) {
2360     COMPCALL(ror_b_ri)(d,(uae_u8)live.state[r].val);
2361     return;
2362     }
2363    
2364     CLOBBER_ROR;
2365     r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2366     d=rmw(d,1,1);
2367     raw_ror_b_rr(d,r) ;
2368     unlock2(r);
2369     unlock2(d);
2370     }
2371     MENDFUNC(2,ror_b_rr,(R1 d, R1 r))
2372    
2373     MIDFUNC(2,shrl_l_rr,(RW4 d, R1 r))
2374     {
2375     if (isconst(r)) {
2376     COMPCALL(shrl_l_ri)(d,(uae_u8)live.state[r].val);
2377     return;
2378     }
2379     CLOBBER_SHRL;
2380     r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2381     d=rmw(d,4,4);
2382     Dif (r!=1) {
2383     write_log("Illegal register %d in raw_rol_b\n",r);
2384     abort();
2385     }
2386     raw_shrl_l_rr(d,r) ;
2387     unlock2(r);
2388     unlock2(d);
2389     }
2390     MENDFUNC(2,shrl_l_rr,(RW4 d, R1 r))
2391    
2392     MIDFUNC(2,shrl_w_rr,(RW2 d, R1 r))
2393     { /* Can only do this with r==1, i.e. cl */
2394    
2395     if (isconst(r)) {
2396     COMPCALL(shrl_w_ri)(d,(uae_u8)live.state[r].val);
2397     return;
2398     }
2399     CLOBBER_SHRL;
2400     r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2401     d=rmw(d,2,2);
2402     Dif (r!=1) {
2403     write_log("Illegal register %d in raw_shrl_b\n",r);
2404     abort();
2405     }
2406     raw_shrl_w_rr(d,r) ;
2407     unlock2(r);
2408     unlock2(d);
2409     }
2410     MENDFUNC(2,shrl_w_rr,(RW2 d, R1 r))
2411    
2412     MIDFUNC(2,shrl_b_rr,(RW1 d, R1 r))
2413     { /* Can only do this with r==1, i.e. cl */
2414    
2415     if (isconst(r)) {
2416     COMPCALL(shrl_b_ri)(d,(uae_u8)live.state[r].val);
2417     return;
2418     }
2419    
2420     CLOBBER_SHRL;
2421     r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2422     d=rmw(d,1,1);
2423     Dif (r!=1) {
2424     write_log("Illegal register %d in raw_shrl_b\n",r);
2425     abort();
2426     }
2427     raw_shrl_b_rr(d,r) ;
2428     unlock2(r);
2429     unlock2(d);
2430     }
2431     MENDFUNC(2,shrl_b_rr,(RW1 d, R1 r))
2432    
2433    
2434    
2435     MIDFUNC(2,shll_l_ri,(RW4 r, IMM i))
2436     {
2437     if (!i && !needflags)
2438     return;
2439     if (isconst(r) && !needflags) {
2440     live.state[r].val<<=i;
2441     return;
2442     }
2443     CLOBBER_SHLL;
2444     r=rmw(r,4,4);
2445     raw_shll_l_ri(r,i);
2446     unlock2(r);
2447     }
2448     MENDFUNC(2,shll_l_ri,(RW4 r, IMM i))
2449    
2450     MIDFUNC(2,shll_w_ri,(RW2 r, IMM i))
2451     {
2452     if (!i && !needflags)
2453     return;
2454     CLOBBER_SHLL;
2455     r=rmw(r,2,2);
2456     raw_shll_w_ri(r,i);
2457     unlock2(r);
2458     }
2459     MENDFUNC(2,shll_w_ri,(RW2 r, IMM i))
2460    
2461     MIDFUNC(2,shll_b_ri,(RW1 r, IMM i))
2462     {
2463     if (!i && !needflags)
2464     return;
2465     CLOBBER_SHLL;
2466     r=rmw(r,1,1);
2467     raw_shll_b_ri(r,i);
2468     unlock2(r);
2469     }
2470     MENDFUNC(2,shll_b_ri,(RW1 r, IMM i))
2471    
2472     MIDFUNC(2,shrl_l_ri,(RW4 r, IMM i))
2473     {
2474     if (!i && !needflags)
2475     return;
2476     if (isconst(r) && !needflags) {
2477     live.state[r].val>>=i;
2478     return;
2479     }
2480     CLOBBER_SHRL;
2481     r=rmw(r,4,4);
2482     raw_shrl_l_ri(r,i);
2483     unlock2(r);
2484     }
2485     MENDFUNC(2,shrl_l_ri,(RW4 r, IMM i))
2486    
2487     MIDFUNC(2,shrl_w_ri,(RW2 r, IMM i))
2488     {
2489     if (!i && !needflags)
2490     return;
2491     CLOBBER_SHRL;
2492     r=rmw(r,2,2);
2493     raw_shrl_w_ri(r,i);
2494     unlock2(r);
2495     }
2496     MENDFUNC(2,shrl_w_ri,(RW2 r, IMM i))
2497    
2498     MIDFUNC(2,shrl_b_ri,(RW1 r, IMM i))
2499     {
2500     if (!i && !needflags)
2501     return;
2502     CLOBBER_SHRL;
2503     r=rmw(r,1,1);
2504     raw_shrl_b_ri(r,i);
2505     unlock2(r);
2506     }
2507     MENDFUNC(2,shrl_b_ri,(RW1 r, IMM i))
2508    
2509     MIDFUNC(2,shra_l_ri,(RW4 r, IMM i))
2510     {
2511     if (!i && !needflags)
2512     return;
2513     CLOBBER_SHRA;
2514     r=rmw(r,4,4);
2515     raw_shra_l_ri(r,i);
2516     unlock2(r);
2517     }
2518     MENDFUNC(2,shra_l_ri,(RW4 r, IMM i))
2519    
2520     MIDFUNC(2,shra_w_ri,(RW2 r, IMM i))
2521     {
2522     if (!i && !needflags)
2523     return;
2524     CLOBBER_SHRA;
2525     r=rmw(r,2,2);
2526     raw_shra_w_ri(r,i);
2527     unlock2(r);
2528     }
2529     MENDFUNC(2,shra_w_ri,(RW2 r, IMM i))
2530    
2531     MIDFUNC(2,shra_b_ri,(RW1 r, IMM i))
2532     {
2533     if (!i && !needflags)
2534     return;
2535     CLOBBER_SHRA;
2536     r=rmw(r,1,1);
2537     raw_shra_b_ri(r,i);
2538     unlock2(r);
2539     }
2540     MENDFUNC(2,shra_b_ri,(RW1 r, IMM i))
2541    
2542     MIDFUNC(2,shra_l_rr,(RW4 d, R1 r))
2543     {
2544     if (isconst(r)) {
2545     COMPCALL(shra_l_ri)(d,(uae_u8)live.state[r].val);
2546     return;
2547     }
2548     CLOBBER_SHRA;
2549     r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2550     d=rmw(d,4,4);
2551     Dif (r!=1) {
2552     write_log("Illegal register %d in raw_rol_b\n",r);
2553     abort();
2554     }
2555     raw_shra_l_rr(d,r) ;
2556     unlock2(r);
2557     unlock2(d);
2558     }
2559     MENDFUNC(2,shra_l_rr,(RW4 d, R1 r))
2560    
2561     MIDFUNC(2,shra_w_rr,(RW2 d, R1 r))
2562     { /* Can only do this with r==1, i.e. cl */
2563    
2564     if (isconst(r)) {
2565     COMPCALL(shra_w_ri)(d,(uae_u8)live.state[r].val);
2566     return;
2567     }
2568     CLOBBER_SHRA;
2569     r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2570     d=rmw(d,2,2);
2571     Dif (r!=1) {
2572     write_log("Illegal register %d in raw_shra_b\n",r);
2573     abort();
2574     }
2575     raw_shra_w_rr(d,r) ;
2576     unlock2(r);
2577     unlock2(d);
2578     }
2579     MENDFUNC(2,shra_w_rr,(RW2 d, R1 r))
2580    
2581     MIDFUNC(2,shra_b_rr,(RW1 d, R1 r))
2582     { /* Can only do this with r==1, i.e. cl */
2583    
2584     if (isconst(r)) {
2585     COMPCALL(shra_b_ri)(d,(uae_u8)live.state[r].val);
2586     return;
2587     }
2588    
2589     CLOBBER_SHRA;
2590     r=readreg_specific(r,1,SHIFTCOUNT_NREG);
2591     d=rmw(d,1,1);
2592     Dif (r!=1) {
2593     write_log("Illegal register %d in raw_shra_b\n",r);
2594     abort();
2595     }
2596     raw_shra_b_rr(d,r) ;
2597     unlock2(r);
2598     unlock2(d);
2599     }
2600     MENDFUNC(2,shra_b_rr,(RW1 d, R1 r))
2601    
2602    
2603     MIDFUNC(2,setcc,(W1 d, IMM cc))
2604     {
2605     CLOBBER_SETCC;
2606     d=writereg(d,1);
2607     raw_setcc(d,cc);
2608     unlock2(d);
2609     }
2610     MENDFUNC(2,setcc,(W1 d, IMM cc))
2611    
2612     MIDFUNC(2,setcc_m,(IMM d, IMM cc))
2613     {
2614     CLOBBER_SETCC;
2615     raw_setcc_m(d,cc);
2616     }
2617     MENDFUNC(2,setcc_m,(IMM d, IMM cc))
2618    
2619     MIDFUNC(3,cmov_l_rr,(RW4 d, R4 s, IMM cc))
2620     {
2621     if (d==s)
2622     return;
2623     CLOBBER_CMOV;
2624     s=readreg(s,4);
2625     d=rmw(d,4,4);
2626     raw_cmov_l_rr(d,s,cc);
2627     unlock2(s);
2628     unlock2(d);
2629     }
2630     MENDFUNC(3,cmov_l_rr,(RW4 d, R4 s, IMM cc))
2631    
2632     MIDFUNC(3,cmov_l_rm,(RW4 d, IMM s, IMM cc))
2633     {
2634     CLOBBER_CMOV;
2635     d=rmw(d,4,4);
2636     raw_cmov_l_rm(d,s,cc);
2637     unlock2(d);
2638     }
2639     MENDFUNC(3,cmov_l_rm,(RW4 d, IMM s, IMM cc))
2640    
2641     MIDFUNC(2,bsf_l_rr,(W4 d, R4 s))
2642     {
2643     CLOBBER_BSF;
2644     s=readreg(s,4);
2645     d=writereg(d,4);
2646     raw_bsf_l_rr(d,s);
2647     unlock2(s);
2648     unlock2(d);
2649     }
2650     MENDFUNC(2,bsf_l_rr,(W4 d, R4 s))
2651    
2652     MIDFUNC(2,imul_32_32,(RW4 d, R4 s))
2653     {
2654     CLOBBER_MUL;
2655     s=readreg(s,4);
2656     d=rmw(d,4,4);
2657     raw_imul_32_32(d,s);
2658     unlock2(s);
2659     unlock2(d);
2660     }
2661     MENDFUNC(2,imul_32_32,(RW4 d, R4 s))
2662    
2663     MIDFUNC(2,imul_64_32,(RW4 d, RW4 s))
2664     {
2665     CLOBBER_MUL;
2666     s=rmw_specific(s,4,4,MUL_NREG2);
2667     d=rmw_specific(d,4,4,MUL_NREG1);
2668     raw_imul_64_32(d,s);
2669     unlock2(s);
2670     unlock2(d);
2671     }
2672     MENDFUNC(2,imul_64_32,(RW4 d, RW4 s))
2673    
2674     MIDFUNC(2,mul_64_32,(RW4 d, RW4 s))
2675     {
2676     CLOBBER_MUL;
2677     s=rmw_specific(s,4,4,MUL_NREG2);
2678     d=rmw_specific(d,4,4,MUL_NREG1);
2679     raw_mul_64_32(d,s);
2680     unlock2(s);
2681     unlock2(d);
2682     }
2683     MENDFUNC(2,mul_64_32,(RW4 d, RW4 s))
2684    
2685     MIDFUNC(2,mul_32_32,(RW4 d, R4 s))
2686     {
2687     CLOBBER_MUL;
2688     s=readreg(s,4);
2689     d=rmw(d,4,4);
2690     raw_mul_32_32(d,s);
2691     unlock2(s);
2692     unlock2(d);
2693     }
2694     MENDFUNC(2,mul_32_32,(RW4 d, R4 s))
2695    
2696     MIDFUNC(2,sign_extend_16_rr,(W4 d, R2 s))
2697     {
2698     int isrmw;
2699    
2700     if (isconst(s)) {
2701     set_const(d,(uae_s32)(uae_s16)live.state[s].val);
2702     return;
2703     }
2704    
2705     CLOBBER_SE16;
2706     isrmw=(s==d);
2707     if (!isrmw) {
2708     s=readreg(s,2);
2709     d=writereg(d,4);
2710     }
2711     else { /* If we try to lock this twice, with different sizes, we
2712     are int trouble! */
2713     s=d=rmw(s,4,2);
2714     }
2715     raw_sign_extend_16_rr(d,s);
2716     if (!isrmw) {
2717     unlock2(d);
2718     unlock2(s);
2719     }
2720     else {
2721     unlock2(s);
2722     }
2723     }
2724     MENDFUNC(2,sign_extend_16_rr,(W4 d, R2 s))
2725    
2726     MIDFUNC(2,sign_extend_8_rr,(W4 d, R1 s))
2727     {
2728     int isrmw;
2729    
2730     if (isconst(s)) {
2731     set_const(d,(uae_s32)(uae_s8)live.state[s].val);
2732     return;
2733     }
2734    
2735     isrmw=(s==d);
2736     CLOBBER_SE8;
2737     if (!isrmw) {
2738     s=readreg(s,1);
2739     d=writereg(d,4);
2740     }
2741     else { /* If we try to lock this twice, with different sizes, we
2742     are int trouble! */
2743     s=d=rmw(s,4,1);
2744     }
2745    
2746     raw_sign_extend_8_rr(d,s);
2747    
2748     if (!isrmw) {
2749     unlock2(d);
2750     unlock2(s);
2751     }
2752     else {
2753     unlock2(s);
2754     }
2755     }
2756     MENDFUNC(2,sign_extend_8_rr,(W4 d, R1 s))
2757    
2758    
2759     MIDFUNC(2,zero_extend_16_rr,(W4 d, R2 s))
2760     {
2761     int isrmw;
2762    
2763     if (isconst(s)) {
2764     set_const(d,(uae_u32)(uae_u16)live.state[s].val);
2765     return;
2766     }
2767    
2768     isrmw=(s==d);
2769     CLOBBER_ZE16;
2770     if (!isrmw) {
2771     s=readreg(s,2);
2772     d=writereg(d,4);
2773     }
2774     else { /* If we try to lock this twice, with different sizes, we
2775     are int trouble! */
2776     s=d=rmw(s,4,2);
2777     }
2778     raw_zero_extend_16_rr(d,s);
2779     if (!isrmw) {
2780     unlock2(d);
2781     unlock2(s);
2782     }
2783     else {
2784     unlock2(s);
2785     }
2786     }
2787     MENDFUNC(2,zero_extend_16_rr,(W4 d, R2 s))
2788    
2789     MIDFUNC(2,zero_extend_8_rr,(W4 d, R1 s))
2790     {
2791     int isrmw;
2792     if (isconst(s)) {
2793     set_const(d,(uae_u32)(uae_u8)live.state[s].val);
2794     return;
2795     }
2796    
2797     isrmw=(s==d);
2798     CLOBBER_ZE8;
2799     if (!isrmw) {
2800     s=readreg(s,1);
2801     d=writereg(d,4);
2802     }
2803     else { /* If we try to lock this twice, with different sizes, we
2804     are int trouble! */
2805     s=d=rmw(s,4,1);
2806     }
2807    
2808     raw_zero_extend_8_rr(d,s);
2809    
2810     if (!isrmw) {
2811     unlock2(d);
2812     unlock2(s);
2813     }
2814     else {
2815     unlock2(s);
2816     }
2817     }
2818     MENDFUNC(2,zero_extend_8_rr,(W4 d, R1 s))
2819    
2820     MIDFUNC(2,mov_b_rr,(W1 d, R1 s))
2821     {
2822     if (d==s)
2823     return;
2824     if (isconst(s)) {
2825     COMPCALL(mov_b_ri)(d,(uae_u8)live.state[s].val);
2826     return;
2827     }
2828    
2829     CLOBBER_MOV;
2830     s=readreg(s,1);
2831     d=writereg(d,1);
2832     raw_mov_b_rr(d,s);
2833     unlock2(d);
2834     unlock2(s);
2835     }
2836     MENDFUNC(2,mov_b_rr,(W1 d, R1 s))
2837    
2838     MIDFUNC(2,mov_w_rr,(W2 d, R2 s))
2839     {
2840     if (d==s)
2841     return;
2842     if (isconst(s)) {
2843     COMPCALL(mov_w_ri)(d,(uae_u16)live.state[s].val);
2844     return;
2845     }
2846    
2847     CLOBBER_MOV;
2848     s=readreg(s,2);
2849     d=writereg(d,2);
2850     raw_mov_w_rr(d,s);
2851     unlock2(d);
2852     unlock2(s);
2853     }
2854     MENDFUNC(2,mov_w_rr,(W2 d, R2 s))
2855    
2856    
2857     MIDFUNC(4,mov_l_rrm_indexed,(W4 d,R4 baser, R4 index, IMM factor))
2858     {
2859     CLOBBER_MOV;
2860     baser=readreg(baser,4);
2861     index=readreg(index,4);
2862     d=writereg(d,4);
2863    
2864     raw_mov_l_rrm_indexed(d,baser,index,factor);
2865     unlock2(d);
2866     unlock2(baser);
2867     unlock2(index);
2868     }
2869     MENDFUNC(4,mov_l_rrm_indexed,(W4 d,R4 baser, R4 index, IMM factor))
2870    
2871     MIDFUNC(4,mov_w_rrm_indexed,(W2 d, R4 baser, R4 index, IMM factor))
2872     {
2873     CLOBBER_MOV;
2874     baser=readreg(baser,4);
2875     index=readreg(index,4);
2876     d=writereg(d,2);
2877    
2878     raw_mov_w_rrm_indexed(d,baser,index,factor);
2879     unlock2(d);
2880     unlock2(baser);
2881     unlock2(index);
2882     }
2883     MENDFUNC(4,mov_w_rrm_indexed,(W2 d, R4 baser, R4 index, IMM factor))
2884    
2885     MIDFUNC(4,mov_b_rrm_indexed,(W1 d, R4 baser, R4 index, IMM factor))
2886     {
2887     CLOBBER_MOV;
2888     baser=readreg(baser,4);
2889     index=readreg(index,4);
2890     d=writereg(d,1);
2891    
2892     raw_mov_b_rrm_indexed(d,baser,index,factor);
2893    
2894     unlock2(d);
2895     unlock2(baser);
2896     unlock2(index);
2897     }
2898     MENDFUNC(4,mov_b_rrm_indexed,(W1 d, R4 baser, R4 index, IMM factor))
2899    
2900    
2901     MIDFUNC(4,mov_l_mrr_indexed,(R4 baser, R4 index, IMM factor, R4 s))
2902     {
2903     CLOBBER_MOV;
2904     baser=readreg(baser,4);
2905     index=readreg(index,4);
2906     s=readreg(s,4);
2907    
2908     Dif (baser==s || index==s)
2909     abort();
2910    
2911    
2912     raw_mov_l_mrr_indexed(baser,index,factor,s);
2913     unlock2(s);
2914     unlock2(baser);
2915     unlock2(index);
2916     }
2917     MENDFUNC(4,mov_l_mrr_indexed,(R4 baser, R4 index, IMM factor, R4 s))
2918    
2919     MIDFUNC(4,mov_w_mrr_indexed,(R4 baser, R4 index, IMM factor, R2 s))
2920     {
2921     CLOBBER_MOV;
2922     baser=readreg(baser,4);
2923     index=readreg(index,4);
2924     s=readreg(s,2);
2925    
2926     raw_mov_w_mrr_indexed(baser,index,factor,s);
2927     unlock2(s);
2928     unlock2(baser);
2929     unlock2(index);
2930     }
2931     MENDFUNC(4,mov_w_mrr_indexed,(R4 baser, R4 index, IMM factor, R2 s))
2932    
2933     MIDFUNC(4,mov_b_mrr_indexed,(R4 baser, R4 index, IMM factor, R1 s))
2934     {
2935     CLOBBER_MOV;
2936     s=readreg(s,1);
2937     baser=readreg(baser,4);
2938     index=readreg(index,4);
2939    
2940     raw_mov_b_mrr_indexed(baser,index,factor,s);
2941     unlock2(s);
2942     unlock2(baser);
2943     unlock2(index);
2944     }
2945     MENDFUNC(4,mov_b_mrr_indexed,(R4 baser, R4 index, IMM factor, R1 s))
2946    
2947    
2948     MIDFUNC(5,mov_l_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R4 s))
2949     {
2950     int basereg=baser;
2951     int indexreg=index;
2952    
2953     CLOBBER_MOV;
2954     s=readreg(s,4);
2955     baser=readreg_offset(baser,4);
2956     index=readreg_offset(index,4);
2957    
2958     base+=get_offset(basereg);
2959     base+=factor*get_offset(indexreg);
2960    
2961     raw_mov_l_bmrr_indexed(base,baser,index,factor,s);
2962     unlock2(s);
2963     unlock2(baser);
2964     unlock2(index);
2965     }
2966     MENDFUNC(5,mov_l_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R4 s))
2967    
2968     MIDFUNC(5,mov_w_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R2 s))
2969     {
2970     int basereg=baser;
2971     int indexreg=index;
2972    
2973     CLOBBER_MOV;
2974     s=readreg(s,2);
2975     baser=readreg_offset(baser,4);
2976     index=readreg_offset(index,4);
2977    
2978     base+=get_offset(basereg);
2979     base+=factor*get_offset(indexreg);
2980    
2981     raw_mov_w_bmrr_indexed(base,baser,index,factor,s);
2982     unlock2(s);
2983     unlock2(baser);
2984     unlock2(index);
2985     }
2986     MENDFUNC(5,mov_w_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R2 s))
2987    
2988     MIDFUNC(5,mov_b_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R1 s))
2989     {
2990     int basereg=baser;
2991     int indexreg=index;
2992    
2993     CLOBBER_MOV;
2994     s=readreg(s,1);
2995     baser=readreg_offset(baser,4);
2996     index=readreg_offset(index,4);
2997    
2998     base+=get_offset(basereg);
2999     base+=factor*get_offset(indexreg);
3000    
3001     raw_mov_b_bmrr_indexed(base,baser,index,factor,s);
3002     unlock2(s);
3003     unlock2(baser);
3004     unlock2(index);
3005     }
3006     MENDFUNC(5,mov_b_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R1 s))
3007    
3008    
3009    
3010     /* Read a long from base+baser+factor*index */
3011     MIDFUNC(5,mov_l_brrm_indexed,(W4 d, IMM base, R4 baser, R4 index, IMM factor))
3012     {
3013     int basereg=baser;
3014     int indexreg=index;
3015    
3016     CLOBBER_MOV;
3017     baser=readreg_offset(baser,4);
3018     index=readreg_offset(index,4);
3019     base+=get_offset(basereg);
3020     base+=factor*get_offset(indexreg);
3021     d=writereg(d,4);
3022     raw_mov_l_brrm_indexed(d,base,baser,index,factor);
3023     unlock2(d);
3024     unlock2(baser);
3025     unlock2(index);
3026     }
3027     MENDFUNC(5,mov_l_brrm_indexed,(W4 d, IMM base, R4 baser, R4 index, IMM factor))
3028    
3029    
3030     MIDFUNC(5,mov_w_brrm_indexed,(W2 d, IMM base, R4 baser, R4 index, IMM factor))
3031     {
3032     int basereg=baser;
3033     int indexreg=index;
3034    
3035     CLOBBER_MOV;
3036     remove_offset(d,-1);
3037     baser=readreg_offset(baser,4);
3038     index=readreg_offset(index,4);
3039     base+=get_offset(basereg);
3040     base+=factor*get_offset(indexreg);
3041     d=writereg(d,2);
3042     raw_mov_w_brrm_indexed(d,base,baser,index,factor);
3043     unlock2(d);
3044     unlock2(baser);
3045     unlock2(index);
3046     }
3047     MENDFUNC(5,mov_w_brrm_indexed,(W2 d, IMM base, R4 baser, R4 index, IMM factor))
3048    
3049    
3050     MIDFUNC(5,mov_b_brrm_indexed,(W1 d, IMM base, R4 baser, R4 index, IMM factor))
3051     {
3052     int basereg=baser;
3053     int indexreg=index;
3054    
3055     CLOBBER_MOV;
3056     remove_offset(d,-1);
3057     baser=readreg_offset(baser,4);
3058     index=readreg_offset(index,4);
3059     base+=get_offset(basereg);
3060     base+=factor*get_offset(indexreg);
3061     d=writereg(d,1);
3062     raw_mov_b_brrm_indexed(d,base,baser,index,factor);
3063     unlock2(d);
3064     unlock2(baser);
3065     unlock2(index);
3066     }
3067     MENDFUNC(5,mov_b_brrm_indexed,(W1 d, IMM base, R4 baser, R4 index, IMM factor))
3068    
3069     /* Read a long from base+factor*index */
3070     MIDFUNC(4,mov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor))
3071     {
3072     int indexreg=index;
3073    
3074     if (isconst(index)) {
3075     COMPCALL(mov_l_rm)(d,base+factor*live.state[index].val);
3076     return;
3077     }
3078    
3079     CLOBBER_MOV;
3080     index=readreg_offset(index,4);
3081     base+=get_offset(indexreg)*factor;
3082     d=writereg(d,4);
3083    
3084     raw_mov_l_rm_indexed(d,base,index,factor);
3085     unlock2(index);
3086     unlock2(d);
3087     }
3088     MENDFUNC(4,mov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor))
3089    
3090    
3091     /* read the long at the address contained in s+offset and store in d */
3092     MIDFUNC(3,mov_l_rR,(W4 d, R4 s, IMM offset))
3093     {
3094     if (isconst(s)) {
3095     COMPCALL(mov_l_rm)(d,live.state[s].val+offset);
3096     return;
3097     }
3098     CLOBBER_MOV;
3099     s=readreg(s,4);
3100     d=writereg(d,4);
3101    
3102     raw_mov_l_rR(d,s,offset);
3103     unlock2(d);
3104     unlock2(s);
3105     }
3106     MENDFUNC(3,mov_l_rR,(W4 d, R4 s, IMM offset))
3107    
3108     /* read the word at the address contained in s+offset and store in d */
3109     MIDFUNC(3,mov_w_rR,(W2 d, R4 s, IMM offset))
3110     {
3111     if (isconst(s)) {
3112     COMPCALL(mov_w_rm)(d,live.state[s].val+offset);
3113     return;
3114     }
3115     CLOBBER_MOV;
3116     s=readreg(s,4);
3117     d=writereg(d,2);
3118    
3119     raw_mov_w_rR(d,s,offset);
3120     unlock2(d);
3121     unlock2(s);
3122     }
3123     MENDFUNC(3,mov_w_rR,(W2 d, R4 s, IMM offset))
3124    
3125     /* read the word at the address contained in s+offset and store in d */
3126     MIDFUNC(3,mov_b_rR,(W1 d, R4 s, IMM offset))
3127     {
3128     if (isconst(s)) {
3129     COMPCALL(mov_b_rm)(d,live.state[s].val+offset);
3130     return;
3131     }
3132     CLOBBER_MOV;
3133     s=readreg(s,4);
3134     d=writereg(d,1);
3135    
3136     raw_mov_b_rR(d,s,offset);
3137     unlock2(d);
3138     unlock2(s);
3139     }
3140     MENDFUNC(3,mov_b_rR,(W1 d, R4 s, IMM offset))
3141    
3142     /* read the long at the address contained in s+offset and store in d */
3143     MIDFUNC(3,mov_l_brR,(W4 d, R4 s, IMM offset))
3144     {
3145     int sreg=s;
3146     if (isconst(s)) {
3147     COMPCALL(mov_l_rm)(d,live.state[s].val+offset);
3148     return;
3149     }
3150     CLOBBER_MOV;
3151     s=readreg_offset(s,4);
3152     offset+=get_offset(sreg);
3153     d=writereg(d,4);
3154    
3155     raw_mov_l_brR(d,s,offset);
3156     unlock2(d);
3157     unlock2(s);
3158     }
3159     MENDFUNC(3,mov_l_brR,(W4 d, R4 s, IMM offset))
3160    
3161     /* read the word at the address contained in s+offset and store in d */
3162     MIDFUNC(3,mov_w_brR,(W2 d, R4 s, IMM offset))
3163     {
3164     int sreg=s;
3165     if (isconst(s)) {
3166     COMPCALL(mov_w_rm)(d,live.state[s].val+offset);
3167     return;
3168     }
3169     CLOBBER_MOV;
3170     remove_offset(d,-1);
3171     s=readreg_offset(s,4);
3172     offset+=get_offset(sreg);
3173     d=writereg(d,2);
3174    
3175     raw_mov_w_brR(d,s,offset);
3176     unlock2(d);
3177     unlock2(s);
3178     }
3179     MENDFUNC(3,mov_w_brR,(W2 d, R4 s, IMM offset))
3180    
3181     /* read the word at the address contained in s+offset and store in d */
3182     MIDFUNC(3,mov_b_brR,(W1 d, R4 s, IMM offset))
3183     {
3184     int sreg=s;
3185     if (isconst(s)) {
3186     COMPCALL(mov_b_rm)(d,live.state[s].val+offset);
3187     return;
3188     }
3189     CLOBBER_MOV;
3190     remove_offset(d,-1);
3191     s=readreg_offset(s,4);
3192     offset+=get_offset(sreg);
3193     d=writereg(d,1);
3194    
3195     raw_mov_b_brR(d,s,offset);
3196     unlock2(d);
3197     unlock2(s);
3198     }
3199     MENDFUNC(3,mov_b_brR,(W1 d, R4 s, IMM offset))
3200    
3201     MIDFUNC(3,mov_l_Ri,(R4 d, IMM i, IMM offset))
3202     {
3203     int dreg=d;
3204     if (isconst(d)) {
3205     COMPCALL(mov_l_mi)(live.state[d].val+offset,i);
3206     return;
3207     }
3208    
3209     CLOBBER_MOV;
3210     d=readreg_offset(d,4);
3211     offset+=get_offset(dreg);
3212     raw_mov_l_Ri(d,i,offset);
3213     unlock2(d);
3214     }
3215     MENDFUNC(3,mov_l_Ri,(R4 d, IMM i, IMM offset))
3216    
3217     MIDFUNC(3,mov_w_Ri,(R4 d, IMM i, IMM offset))
3218     {
3219     int dreg=d;
3220     if (isconst(d)) {
3221     COMPCALL(mov_w_mi)(live.state[d].val+offset,i);
3222     return;
3223     }
3224    
3225     CLOBBER_MOV;
3226     d=readreg_offset(d,4);
3227     offset+=get_offset(dreg);
3228     raw_mov_w_Ri(d,i,offset);
3229     unlock2(d);
3230     }
3231     MENDFUNC(3,mov_w_Ri,(R4 d, IMM i, IMM offset))
3232    
3233     MIDFUNC(3,mov_b_Ri,(R4 d, IMM i, IMM offset))
3234     {
3235     int dreg=d;
3236     if (isconst(d)) {
3237     COMPCALL(mov_b_mi)(live.state[d].val+offset,i);
3238     return;
3239     }
3240    
3241     CLOBBER_MOV;
3242     d=readreg_offset(d,4);
3243     offset+=get_offset(dreg);
3244     raw_mov_b_Ri(d,i,offset);
3245     unlock2(d);
3246     }
3247     MENDFUNC(3,mov_b_Ri,(R4 d, IMM i, IMM offset))
3248    
3249     /* Warning! OFFSET is byte sized only! */
3250     MIDFUNC(3,mov_l_Rr,(R4 d, R4 s, IMM offset))
3251     {
3252     if (isconst(d)) {
3253     COMPCALL(mov_l_mr)(live.state[d].val+offset,s);
3254     return;
3255     }
3256     if (isconst(s)) {
3257     COMPCALL(mov_l_Ri)(d,live.state[s].val,offset);
3258     return;
3259     }
3260    
3261     CLOBBER_MOV;
3262     s=readreg(s,4);
3263     d=readreg(d,4);
3264    
3265     raw_mov_l_Rr(d,s,offset);
3266     unlock2(d);
3267     unlock2(s);
3268     }
3269     MENDFUNC(3,mov_l_Rr,(R4 d, R4 s, IMM offset))
3270    
3271     MIDFUNC(3,mov_w_Rr,(R4 d, R2 s, IMM offset))
3272     {
3273     if (isconst(d)) {
3274     COMPCALL(mov_w_mr)(live.state[d].val+offset,s);
3275     return;
3276     }
3277     if (isconst(s)) {
3278     COMPCALL(mov_w_Ri)(d,(uae_u16)live.state[s].val,offset);
3279     return;
3280     }
3281    
3282     CLOBBER_MOV;
3283     s=readreg(s,2);
3284     d=readreg(d,4);
3285     raw_mov_w_Rr(d,s,offset);
3286     unlock2(d);
3287     unlock2(s);
3288     }
3289     MENDFUNC(3,mov_w_Rr,(R4 d, R2 s, IMM offset))
3290    
3291     MIDFUNC(3,mov_b_Rr,(R4 d, R1 s, IMM offset))
3292     {
3293     if (isconst(d)) {
3294     COMPCALL(mov_b_mr)(live.state[d].val+offset,s);
3295     return;
3296     }
3297     if (isconst(s)) {
3298     COMPCALL(mov_b_Ri)(d,(uae_u8)live.state[s].val,offset);
3299     return;
3300     }
3301    
3302     CLOBBER_MOV;
3303     s=readreg(s,1);
3304     d=readreg(d,4);
3305     raw_mov_b_Rr(d,s,offset);
3306     unlock2(d);
3307     unlock2(s);
3308     }
3309     MENDFUNC(3,mov_b_Rr,(R4 d, R1 s, IMM offset))
3310    
3311     MIDFUNC(3,lea_l_brr,(W4 d, R4 s, IMM offset))
3312     {
3313     if (isconst(s)) {
3314     COMPCALL(mov_l_ri)(d,live.state[s].val+offset);
3315     return;
3316     }
3317     #if USE_OFFSET
3318     if (d==s) {
3319     add_offset(d,offset);
3320     return;
3321     }
3322     #endif
3323     CLOBBER_LEA;
3324     s=readreg(s,4);
3325     d=writereg(d,4);
3326     raw_lea_l_brr(d,s,offset);
3327     unlock2(d);
3328     unlock2(s);
3329     }
3330     MENDFUNC(3,lea_l_brr,(W4 d, R4 s, IMM offset))
3331    
3332     MIDFUNC(5,lea_l_brr_indexed,(W4 d, R4 s, R4 index, IMM factor, IMM offset))
3333     {
3334     if (!offset) {
3335     COMPCALL(lea_l_rr_indexed)(d,s,index,factor);
3336     return;
3337     }
3338     CLOBBER_LEA;
3339     s=readreg(s,4);
3340     index=readreg(index,4);
3341     d=writereg(d,4);
3342    
3343     raw_lea_l_brr_indexed(d,s,index,factor,offset);
3344     unlock2(d);
3345     unlock2(index);
3346     unlock2(s);
3347     }
3348     MENDFUNC(5,lea_l_brr_indexed,(W4 d, R4 s, R4 index, IMM factor, IMM offset))
3349    
3350     MIDFUNC(4,lea_l_rr_indexed,(W4 d, R4 s, R4 index, IMM factor))
3351     {
3352     CLOBBER_LEA;
3353     s=readreg(s,4);
3354     index=readreg(index,4);
3355     d=writereg(d,4);
3356    
3357     raw_lea_l_rr_indexed(d,s,index,factor);
3358     unlock2(d);
3359     unlock2(index);
3360     unlock2(s);
3361     }
3362     MENDFUNC(4,lea_l_rr_indexed,(W4 d, R4 s, R4 index, IMM factor))
3363    
3364     /* write d to the long at the address contained in s+offset */
3365     MIDFUNC(3,mov_l_bRr,(R4 d, R4 s, IMM offset))
3366     {
3367     int dreg=d;
3368     if (isconst(d)) {
3369     COMPCALL(mov_l_mr)(live.state[d].val+offset,s);
3370     return;
3371     }
3372    
3373     CLOBBER_MOV;
3374     s=readreg(s,4);
3375     d=readreg_offset(d,4);
3376     offset+=get_offset(dreg);
3377    
3378     raw_mov_l_bRr(d,s,offset);
3379     unlock2(d);
3380     unlock2(s);
3381     }
3382     MENDFUNC(3,mov_l_bRr,(R4 d, R4 s, IMM offset))
3383    
3384     /* write the word at the address contained in s+offset and store in d */
3385     MIDFUNC(3,mov_w_bRr,(R4 d, R2 s, IMM offset))
3386     {
3387     int dreg=d;
3388    
3389     if (isconst(d)) {
3390     COMPCALL(mov_w_mr)(live.state[d].val+offset,s);
3391     return;
3392     }
3393    
3394     CLOBBER_MOV;
3395     s=readreg(s,2);
3396     d=readreg_offset(d,4);
3397     offset+=get_offset(dreg);
3398     raw_mov_w_bRr(d,s,offset);
3399     unlock2(d);
3400     unlock2(s);
3401     }
3402     MENDFUNC(3,mov_w_bRr,(R4 d, R2 s, IMM offset))
3403    
3404     MIDFUNC(3,mov_b_bRr,(R4 d, R1 s, IMM offset))
3405     {
3406     int dreg=d;
3407     if (isconst(d)) {
3408     COMPCALL(mov_b_mr)(live.state[d].val+offset,s);
3409     return;
3410     }
3411    
3412     CLOBBER_MOV;
3413     s=readreg(s,1);
3414     d=readreg_offset(d,4);
3415     offset+=get_offset(dreg);
3416     raw_mov_b_bRr(d,s,offset);
3417     unlock2(d);
3418     unlock2(s);
3419     }
3420     MENDFUNC(3,mov_b_bRr,(R4 d, R1 s, IMM offset))
3421    
3422     MIDFUNC(1,bswap_32,(RW4 r))
3423     {
3424     int reg=r;
3425    
3426     if (isconst(r)) {
3427     uae_u32 oldv=live.state[r].val;
3428     live.state[r].val=reverse32(oldv);
3429     return;
3430     }
3431    
3432     CLOBBER_SW32;
3433     r=rmw(r,4,4);
3434     raw_bswap_32(r);
3435     unlock2(r);
3436     }
3437     MENDFUNC(1,bswap_32,(RW4 r))
3438    
3439     MIDFUNC(1,bswap_16,(RW2 r))
3440     {
3441     if (isconst(r)) {
3442     uae_u32 oldv=live.state[r].val;
3443     live.state[r].val=((oldv>>8)&0xff) | ((oldv<<8)&0xff00) |
3444     (oldv&0xffff0000);
3445     return;
3446     }
3447    
3448     CLOBBER_SW16;
3449     r=rmw(r,2,2);
3450    
3451     raw_bswap_16(r);
3452     unlock2(r);
3453     }
3454     MENDFUNC(1,bswap_16,(RW2 r))
3455    
3456    
3457    
3458     MIDFUNC(2,mov_l_rr,(W4 d, R4 s))
3459     {
3460     int olds;
3461    
3462     if (d==s) { /* How pointless! */
3463     return;
3464     }
3465     if (isconst(s)) {
3466     COMPCALL(mov_l_ri)(d,live.state[s].val);
3467     return;
3468     }
3469     olds=s;
3470     disassociate(d);
3471     s=readreg_offset(s,4);
3472     live.state[d].realreg=s;
3473     live.state[d].realind=live.nat[s].nholds;
3474     live.state[d].val=live.state[olds].val;
3475     live.state[d].validsize=4;
3476     live.state[d].dirtysize=4;
3477     set_status(d,DIRTY);
3478    
3479     live.nat[s].holds[live.nat[s].nholds]=d;
3480     live.nat[s].nholds++;
3481     log_clobberreg(d);
3482     /* write_log("Added %d to nreg %d(%d), now holds %d regs\n",
3483     d,s,live.state[d].realind,live.nat[s].nholds); */
3484     unlock2(s);
3485     }
3486     MENDFUNC(2,mov_l_rr,(W4 d, R4 s))
3487    
3488     MIDFUNC(2,mov_l_mr,(IMM d, R4 s))
3489     {
3490     if (isconst(s)) {
3491     COMPCALL(mov_l_mi)(d,live.state[s].val);
3492     return;
3493     }
3494     CLOBBER_MOV;
3495     s=readreg(s,4);
3496    
3497     raw_mov_l_mr(d,s);
3498     unlock2(s);
3499     }
3500     MENDFUNC(2,mov_l_mr,(IMM d, R4 s))
3501    
3502    
3503     MIDFUNC(2,mov_w_mr,(IMM d, R2 s))
3504     {
3505     if (isconst(s)) {
3506     COMPCALL(mov_w_mi)(d,(uae_u16)live.state[s].val);
3507     return;
3508     }
3509     CLOBBER_MOV;
3510     s=readreg(s,2);
3511    
3512     raw_mov_w_mr(d,s);
3513     unlock2(s);
3514     }
3515     MENDFUNC(2,mov_w_mr,(IMM d, R2 s))
3516    
3517     MIDFUNC(2,mov_w_rm,(W2 d, IMM s))
3518     {
3519     CLOBBER_MOV;
3520     d=writereg(d,2);
3521    
3522     raw_mov_w_rm(d,s);
3523     unlock2(d);
3524     }
3525     MENDFUNC(2,mov_w_rm,(W2 d, IMM s))
3526    
3527     MIDFUNC(2,mov_b_mr,(IMM d, R1 s))
3528     {
3529     if (isconst(s)) {
3530     COMPCALL(mov_b_mi)(d,(uae_u8)live.state[s].val);
3531     return;
3532     }
3533    
3534     CLOBBER_MOV;
3535     s=readreg(s,1);
3536    
3537     raw_mov_b_mr(d,s);
3538     unlock2(s);
3539     }
3540     MENDFUNC(2,mov_b_mr,(IMM d, R1 s))
3541    
3542     MIDFUNC(2,mov_b_rm,(W1 d, IMM s))
3543     {
3544     CLOBBER_MOV;
3545     d=writereg(d,1);
3546    
3547     raw_mov_b_rm(d,s);
3548     unlock2(d);
3549     }
3550     MENDFUNC(2,mov_b_rm,(W1 d, IMM s))
3551    
3552     MIDFUNC(2,mov_l_ri,(W4 d, IMM s))
3553     {
3554     set_const(d,s);
3555     return;
3556     }
3557     MENDFUNC(2,mov_l_ri,(W4 d, IMM s))
3558    
3559     MIDFUNC(2,mov_w_ri,(W2 d, IMM s))
3560     {
3561     CLOBBER_MOV;
3562     d=writereg(d,2);
3563    
3564     raw_mov_w_ri(d,s);
3565     unlock2(d);
3566     }
3567     MENDFUNC(2,mov_w_ri,(W2 d, IMM s))
3568    
3569     MIDFUNC(2,mov_b_ri,(W1 d, IMM s))
3570     {
3571     CLOBBER_MOV;
3572     d=writereg(d,1);
3573    
3574     raw_mov_b_ri(d,s);
3575     unlock2(d);
3576     }
3577     MENDFUNC(2,mov_b_ri,(W1 d, IMM s))
3578    
3579    
3580     MIDFUNC(2,add_l_mi,(IMM d, IMM s))
3581     {
3582     CLOBBER_ADD;
3583     raw_add_l_mi(d,s) ;
3584     }
3585     MENDFUNC(2,add_l_mi,(IMM d, IMM s))
3586    
3587     MIDFUNC(2,add_w_mi,(IMM d, IMM s))
3588     {
3589     CLOBBER_ADD;
3590     raw_add_w_mi(d,s) ;
3591     }
3592     MENDFUNC(2,add_w_mi,(IMM d, IMM s))
3593    
3594     MIDFUNC(2,add_b_mi,(IMM d, IMM s))
3595     {
3596     CLOBBER_ADD;
3597     raw_add_b_mi(d,s) ;
3598     }
3599     MENDFUNC(2,add_b_mi,(IMM d, IMM s))
3600    
3601    
3602     MIDFUNC(2,test_l_ri,(R4 d, IMM i))
3603     {
3604     CLOBBER_TEST;
3605     d=readreg(d,4);
3606    
3607     raw_test_l_ri(d,i);
3608     unlock2(d);
3609     }
3610     MENDFUNC(2,test_l_ri,(R4 d, IMM i))
3611    
3612     MIDFUNC(2,test_l_rr,(R4 d, R4 s))
3613     {
3614     CLOBBER_TEST;
3615     d=readreg(d,4);
3616     s=readreg(s,4);
3617    
3618     raw_test_l_rr(d,s);;
3619     unlock2(d);
3620     unlock2(s);
3621     }
3622     MENDFUNC(2,test_l_rr,(R4 d, R4 s))
3623    
3624     MIDFUNC(2,test_w_rr,(R2 d, R2 s))
3625     {
3626     CLOBBER_TEST;
3627     d=readreg(d,2);
3628     s=readreg(s,2);
3629    
3630     raw_test_w_rr(d,s);
3631     unlock2(d);
3632     unlock2(s);
3633     }
3634     MENDFUNC(2,test_w_rr,(R2 d, R2 s))
3635    
3636     MIDFUNC(2,test_b_rr,(R1 d, R1 s))
3637     {
3638     CLOBBER_TEST;
3639     d=readreg(d,1);
3640     s=readreg(s,1);
3641    
3642     raw_test_b_rr(d,s);
3643     unlock2(d);
3644     unlock2(s);
3645     }
3646     MENDFUNC(2,test_b_rr,(R1 d, R1 s))
3647    
3648    
3649     MIDFUNC(2,and_l_ri,(RW4 d, IMM i))
3650     {
3651     if (isconst(d) && !needflags) {
3652     live.state[d].val &= i;
3653     return;
3654     }
3655    
3656     CLOBBER_AND;
3657     d=rmw(d,4,4);
3658    
3659     raw_and_l_ri(d,i);
3660     unlock2(d);
3661     }
3662     MENDFUNC(2,and_l_ri,(RW4 d, IMM i))
3663    
3664     MIDFUNC(2,and_l,(RW4 d, R4 s))
3665     {
3666     CLOBBER_AND;
3667     s=readreg(s,4);
3668     d=rmw(d,4,4);
3669    
3670     raw_and_l(d,s);
3671     unlock2(d);
3672     unlock2(s);
3673     }
3674     MENDFUNC(2,and_l,(RW4 d, R4 s))
3675    
3676     MIDFUNC(2,and_w,(RW2 d, R2 s))
3677     {
3678     CLOBBER_AND;
3679     s=readreg(s,2);
3680     d=rmw(d,2,2);
3681    
3682     raw_and_w(d,s);
3683     unlock2(d);
3684     unlock2(s);
3685     }
3686     MENDFUNC(2,and_w,(RW2 d, R2 s))
3687    
3688     MIDFUNC(2,and_b,(RW1 d, R1 s))
3689     {
3690     CLOBBER_AND;
3691     s=readreg(s,1);
3692     d=rmw(d,1,1);
3693    
3694     raw_and_b(d,s);
3695     unlock2(d);
3696     unlock2(s);
3697     }
3698     MENDFUNC(2,and_b,(RW1 d, R1 s))
3699    
3700     // gb-- used for making an fpcr value in compemu_fpp.cpp
3701     MIDFUNC(2,or_l_rm,(RW4 d, IMM s))
3702     {
3703     CLOBBER_OR;
3704     d=rmw(d,4,4);
3705    
3706     raw_or_l_rm(d,s);
3707     unlock2(d);
3708     }
3709     MENDFUNC(2,or_l_rm,(RW4 d, IMM s))
3710    
3711     MIDFUNC(2,or_l_ri,(RW4 d, IMM i))
3712     {
3713     if (isconst(d) && !needflags) {
3714     live.state[d].val|=i;
3715     return;
3716     }
3717     CLOBBER_OR;
3718     d=rmw(d,4,4);
3719    
3720     raw_or_l_ri(d,i);
3721     unlock2(d);
3722     }
3723     MENDFUNC(2,or_l_ri,(RW4 d, IMM i))
3724    
3725     MIDFUNC(2,or_l,(RW4 d, R4 s))
3726     {
3727     if (isconst(d) && isconst(s) && !needflags) {
3728     live.state[d].val|=live.state[s].val;
3729     return;
3730     }
3731     CLOBBER_OR;
3732     s=readreg(s,4);
3733     d=rmw(d,4,4);
3734    
3735     raw_or_l(d,s);
3736     unlock2(d);
3737     unlock2(s);
3738     }
3739     MENDFUNC(2,or_l,(RW4 d, R4 s))
3740    
3741     MIDFUNC(2,or_w,(RW2 d, R2 s))
3742     {
3743     CLOBBER_OR;
3744     s=readreg(s,2);
3745     d=rmw(d,2,2);
3746    
3747     raw_or_w(d,s);
3748     unlock2(d);
3749     unlock2(s);
3750     }
3751     MENDFUNC(2,or_w,(RW2 d, R2 s))
3752    
3753     MIDFUNC(2,or_b,(RW1 d, R1 s))
3754     {
3755     CLOBBER_OR;
3756     s=readreg(s,1);
3757     d=rmw(d,1,1);
3758    
3759     raw_or_b(d,s);
3760     unlock2(d);
3761     unlock2(s);
3762     }
3763     MENDFUNC(2,or_b,(RW1 d, R1 s))
3764    
3765     MIDFUNC(2,adc_l,(RW4 d, R4 s))
3766     {
3767     CLOBBER_ADC;
3768     s=readreg(s,4);
3769     d=rmw(d,4,4);
3770    
3771     raw_adc_l(d,s);
3772    
3773     unlock2(d);
3774     unlock2(s);
3775     }
3776     MENDFUNC(2,adc_l,(RW4 d, R4 s))
3777    
3778     MIDFUNC(2,adc_w,(RW2 d, R2 s))
3779     {
3780     CLOBBER_ADC;
3781     s=readreg(s,2);
3782     d=rmw(d,2,2);
3783    
3784     raw_adc_w(d,s);
3785     unlock2(d);
3786     unlock2(s);
3787     }
3788     MENDFUNC(2,adc_w,(RW2 d, R2 s))
3789    
3790     MIDFUNC(2,adc_b,(RW1 d, R1 s))
3791     {
3792     CLOBBER_ADC;
3793     s=readreg(s,1);
3794     d=rmw(d,1,1);
3795    
3796     raw_adc_b(d,s);
3797     unlock2(d);
3798     unlock2(s);
3799     }
3800     MENDFUNC(2,adc_b,(RW1 d, R1 s))
3801    
3802     MIDFUNC(2,add_l,(RW4 d, R4 s))
3803     {
3804     if (isconst(s)) {
3805     COMPCALL(add_l_ri)(d,live.state[s].val);
3806     return;
3807     }
3808    
3809     CLOBBER_ADD;
3810     s=readreg(s,4);
3811     d=rmw(d,4,4);
3812    
3813     raw_add_l(d,s);
3814    
3815     unlock2(d);
3816     unlock2(s);
3817     }
3818     MENDFUNC(2,add_l,(RW4 d, R4 s))
3819    
3820     MIDFUNC(2,add_w,(RW2 d, R2 s))
3821     {
3822     if (isconst(s)) {
3823     COMPCALL(add_w_ri)(d,(uae_u16)live.state[s].val);
3824     return;
3825     }
3826    
3827     CLOBBER_ADD;
3828     s=readreg(s,2);
3829     d=rmw(d,2,2);
3830    
3831     raw_add_w(d,s);
3832     unlock2(d);
3833     unlock2(s);
3834     }
3835     MENDFUNC(2,add_w,(RW2 d, R2 s))
3836    
3837     MIDFUNC(2,add_b,(RW1 d, R1 s))
3838     {
3839     if (isconst(s)) {
3840     COMPCALL(add_b_ri)(d,(uae_u8)live.state[s].val);
3841     return;
3842     }
3843    
3844     CLOBBER_ADD;
3845     s=readreg(s,1);
3846     d=rmw(d,1,1);
3847    
3848     raw_add_b(d,s);
3849     unlock2(d);
3850     unlock2(s);
3851     }
3852     MENDFUNC(2,add_b,(RW1 d, R1 s))
3853    
3854     MIDFUNC(2,sub_l_ri,(RW4 d, IMM i))
3855     {
3856     if (!i && !needflags)
3857     return;
3858     if (isconst(d) && !needflags) {
3859     live.state[d].val-=i;
3860     return;
3861     }
3862     #if USE_OFFSET
3863     if (!needflags) {
3864     add_offset(d,-i);
3865     return;
3866     }
3867     #endif
3868    
3869     CLOBBER_SUB;
3870     d=rmw(d,4,4);
3871    
3872     raw_sub_l_ri(d,i);
3873     unlock2(d);
3874     }
3875     MENDFUNC(2,sub_l_ri,(RW4 d, IMM i))
3876    
3877     MIDFUNC(2,sub_w_ri,(RW2 d, IMM i))
3878     {
3879     if (!i && !needflags)
3880     return;
3881    
3882     CLOBBER_SUB;
3883     d=rmw(d,2,2);
3884    
3885     raw_sub_w_ri(d,i);
3886     unlock2(d);
3887     }
3888     MENDFUNC(2,sub_w_ri,(RW2 d, IMM i))
3889    
3890     MIDFUNC(2,sub_b_ri,(RW1 d, IMM i))
3891     {
3892     if (!i && !needflags)
3893     return;
3894    
3895     CLOBBER_SUB;
3896     d=rmw(d,1,1);
3897    
3898     raw_sub_b_ri(d,i);
3899    
3900     unlock2(d);
3901     }
3902     MENDFUNC(2,sub_b_ri,(RW1 d, IMM i))
3903    
3904     MIDFUNC(2,add_l_ri,(RW4 d, IMM i))
3905     {
3906     if (!i && !needflags)
3907     return;
3908     if (isconst(d) && !needflags) {
3909     live.state[d].val+=i;
3910     return;
3911     }
3912     #if USE_OFFSET
3913     if (!needflags) {
3914     add_offset(d,i);
3915     return;
3916     }
3917     #endif
3918     CLOBBER_ADD;
3919     d=rmw(d,4,4);
3920     raw_add_l_ri(d,i);
3921     unlock2(d);
3922     }
3923     MENDFUNC(2,add_l_ri,(RW4 d, IMM i))
3924    
3925     MIDFUNC(2,add_w_ri,(RW2 d, IMM i))
3926     {
3927     if (!i && !needflags)
3928     return;
3929    
3930     CLOBBER_ADD;
3931     d=rmw(d,2,2);
3932    
3933     raw_add_w_ri(d,i);
3934     unlock2(d);
3935     }
3936     MENDFUNC(2,add_w_ri,(RW2 d, IMM i))
3937    
3938     MIDFUNC(2,add_b_ri,(RW1 d, IMM i))
3939     {
3940     if (!i && !needflags)
3941     return;
3942    
3943     CLOBBER_ADD;
3944     d=rmw(d,1,1);
3945    
3946     raw_add_b_ri(d,i);
3947    
3948     unlock2(d);
3949     }
3950     MENDFUNC(2,add_b_ri,(RW1 d, IMM i))
3951    
3952     MIDFUNC(2,sbb_l,(RW4 d, R4 s))
3953     {
3954     CLOBBER_SBB;
3955     s=readreg(s,4);
3956     d=rmw(d,4,4);
3957    
3958     raw_sbb_l(d,s);
3959     unlock2(d);
3960     unlock2(s);
3961     }
3962     MENDFUNC(2,sbb_l,(RW4 d, R4 s))
3963    
3964     MIDFUNC(2,sbb_w,(RW2 d, R2 s))
3965     {
3966     CLOBBER_SBB;
3967     s=readreg(s,2);
3968     d=rmw(d,2,2);
3969    
3970     raw_sbb_w(d,s);
3971     unlock2(d);
3972     unlock2(s);
3973     }
3974     MENDFUNC(2,sbb_w,(RW2 d, R2 s))
3975    
3976     MIDFUNC(2,sbb_b,(RW1 d, R1 s))
3977     {
3978     CLOBBER_SBB;
3979     s=readreg(s,1);
3980     d=rmw(d,1,1);
3981    
3982     raw_sbb_b(d,s);
3983     unlock2(d);
3984     unlock2(s);
3985     }
3986     MENDFUNC(2,sbb_b,(RW1 d, R1 s))
3987    
3988     MIDFUNC(2,sub_l,(RW4 d, R4 s))
3989     {
3990     if (isconst(s)) {
3991     COMPCALL(sub_l_ri)(d,live.state[s].val);
3992     return;
3993     }
3994    
3995     CLOBBER_SUB;
3996     s=readreg(s,4);
3997     d=rmw(d,4,4);
3998    
3999     raw_sub_l(d,s);
4000     unlock2(d);
4001     unlock2(s);
4002     }
4003     MENDFUNC(2,sub_l,(RW4 d, R4 s))
4004    
4005     MIDFUNC(2,sub_w,(RW2 d, R2 s))
4006     {
4007     if (isconst(s)) {
4008     COMPCALL(sub_w_ri)(d,(uae_u16)live.state[s].val);
4009     return;
4010     }
4011    
4012     CLOBBER_SUB;
4013     s=readreg(s,2);
4014     d=rmw(d,2,2);
4015    
4016     raw_sub_w(d,s);
4017     unlock2(d);
4018     unlock2(s);
4019     }
4020     MENDFUNC(2,sub_w,(RW2 d, R2 s))
4021    
4022     MIDFUNC(2,sub_b,(RW1 d, R1 s))
4023     {
4024     if (isconst(s)) {
4025     COMPCALL(sub_b_ri)(d,(uae_u8)live.state[s].val);
4026     return;
4027     }
4028    
4029     CLOBBER_SUB;
4030     s=readreg(s,1);
4031     d=rmw(d,1,1);
4032    
4033     raw_sub_b(d,s);
4034     unlock2(d);
4035     unlock2(s);
4036     }
4037     MENDFUNC(2,sub_b,(RW1 d, R1 s))
4038    
4039     MIDFUNC(2,cmp_l,(R4 d, R4 s))
4040     {
4041     CLOBBER_CMP;
4042     s=readreg(s,4);
4043     d=readreg(d,4);
4044    
4045     raw_cmp_l(d,s);
4046     unlock2(d);
4047     unlock2(s);
4048     }
4049     MENDFUNC(2,cmp_l,(R4 d, R4 s))
4050    
4051     MIDFUNC(2,cmp_l_ri,(R4 r, IMM i))
4052     {
4053     CLOBBER_CMP;
4054     r=readreg(r,4);
4055    
4056     raw_cmp_l_ri(r,i);
4057     unlock2(r);
4058     }
4059     MENDFUNC(2,cmp_l_ri,(R4 r, IMM i))
4060    
4061     MIDFUNC(2,cmp_w,(R2 d, R2 s))
4062     {
4063     CLOBBER_CMP;
4064     s=readreg(s,2);
4065     d=readreg(d,2);
4066    
4067     raw_cmp_w(d,s);
4068     unlock2(d);
4069     unlock2(s);
4070     }
4071     MENDFUNC(2,cmp_w,(R2 d, R2 s))
4072    
4073     MIDFUNC(2,cmp_b,(R1 d, R1 s))
4074     {
4075     CLOBBER_CMP;
4076     s=readreg(s,1);
4077     d=readreg(d,1);
4078    
4079     raw_cmp_b(d,s);
4080     unlock2(d);
4081     unlock2(s);
4082     }
4083     MENDFUNC(2,cmp_b,(R1 d, R1 s))
4084    
4085    
4086     MIDFUNC(2,xor_l,(RW4 d, R4 s))
4087     {
4088     CLOBBER_XOR;
4089     s=readreg(s,4);
4090     d=rmw(d,4,4);
4091    
4092     raw_xor_l(d,s);
4093     unlock2(d);
4094     unlock2(s);
4095     }
4096     MENDFUNC(2,xor_l,(RW4 d, R4 s))
4097    
4098     MIDFUNC(2,xor_w,(RW2 d, R2 s))
4099     {
4100     CLOBBER_XOR;
4101     s=readreg(s,2);
4102     d=rmw(d,2,2);
4103    
4104     raw_xor_w(d,s);
4105     unlock2(d);
4106     unlock2(s);
4107     }
4108     MENDFUNC(2,xor_w,(RW2 d, R2 s))
4109    
4110     MIDFUNC(2,xor_b,(RW1 d, R1 s))
4111     {
4112     CLOBBER_XOR;
4113     s=readreg(s,1);
4114     d=rmw(d,1,1);
4115    
4116     raw_xor_b(d,s);
4117     unlock2(d);
4118     unlock2(s);
4119     }
4120     MENDFUNC(2,xor_b,(RW1 d, R1 s))
4121    
4122     MIDFUNC(5,call_r_11,(W4 out1, R4 r, R4 in1, IMM osize, IMM isize))
4123     {
4124     clobber_flags();
4125     remove_all_offsets();
4126     if (osize==4) {
4127     if (out1!=in1 && out1!=r) {
4128     COMPCALL(forget_about)(out1);
4129     }
4130     }
4131     else {
4132     tomem_c(out1);
4133     }
4134    
4135     in1=readreg_specific(in1,isize,REG_PAR1);
4136     r=readreg(r,4);
4137     prepare_for_call_1(); /* This should ensure that there won't be
4138     any need for swapping nregs in prepare_for_call_2
4139     */
4140     #if USE_NORMAL_CALLING_CONVENTION
4141     raw_push_l_r(in1);
4142     #endif
4143     unlock2(in1);
4144     unlock2(r);
4145    
4146     prepare_for_call_2();
4147     raw_call_r(r);
4148    
4149     #if USE_NORMAL_CALLING_CONVENTION
4150     raw_inc_sp(4);
4151     #endif
4152    
4153    
4154     live.nat[REG_RESULT].holds[0]=out1;
4155     live.nat[REG_RESULT].nholds=1;
4156     live.nat[REG_RESULT].touched=touchcnt++;
4157    
4158     live.state[out1].realreg=REG_RESULT;
4159     live.state[out1].realind=0;
4160     live.state[out1].val=0;
4161     live.state[out1].validsize=osize;
4162     live.state[out1].dirtysize=osize;
4163     set_status(out1,DIRTY);
4164     }
4165     MENDFUNC(5,call_r_11,(W4 out1, R4 r, R4 in1, IMM osize, IMM isize))
4166    
4167     MIDFUNC(5,call_r_02,(R4 r, R4 in1, R4 in2, IMM isize1, IMM isize2))
4168     {
4169     clobber_flags();
4170     remove_all_offsets();
4171     in1=readreg_specific(in1,isize1,REG_PAR1);
4172     in2=readreg_specific(in2,isize2,REG_PAR2);
4173     r=readreg(r,4);
4174     prepare_for_call_1(); /* This should ensure that there won't be
4175     any need for swapping nregs in prepare_for_call_2
4176     */
4177     #if USE_NORMAL_CALLING_CONVENTION
4178     raw_push_l_r(in2);
4179     raw_push_l_r(in1);
4180     #endif
4181     unlock2(r);
4182     unlock2(in1);
4183     unlock2(in2);
4184     prepare_for_call_2();
4185     raw_call_r(r);
4186     #if USE_NORMAL_CALLING_CONVENTION
4187     raw_inc_sp(8);
4188     #endif
4189     }
4190     MENDFUNC(5,call_r_02,(R4 r, R4 in1, R4 in2, IMM isize1, IMM isize2))
4191    
4192     /* forget_about() takes a mid-layer register */
4193     MIDFUNC(1,forget_about,(W4 r))
4194     {
4195     if (isinreg(r))
4196     disassociate(r);
4197     live.state[r].val=0;
4198     set_status(r,UNDEF);
4199     }
4200     MENDFUNC(1,forget_about,(W4 r))
4201    
4202     MIDFUNC(0,nop,(void))
4203     {
4204     raw_nop();
4205     }
4206     MENDFUNC(0,nop,(void))
4207    
4208    
4209     MIDFUNC(1,f_forget_about,(FW r))
4210     {
4211     if (f_isinreg(r))
4212     f_disassociate(r);
4213     live.fate[r].status=UNDEF;
4214     }
4215     MENDFUNC(1,f_forget_about,(FW r))
4216    
4217     MIDFUNC(1,fmov_pi,(FW r))
4218     {
4219     r=f_writereg(r);
4220     raw_fmov_pi(r);
4221     f_unlock(r);
4222     }
4223     MENDFUNC(1,fmov_pi,(FW r))
4224    
4225     MIDFUNC(1,fmov_log10_2,(FW r))
4226     {
4227     r=f_writereg(r);
4228     raw_fmov_log10_2(r);
4229     f_unlock(r);
4230     }
4231     MENDFUNC(1,fmov_log10_2,(FW r))
4232    
4233     MIDFUNC(1,fmov_log2_e,(FW r))
4234     {
4235     r=f_writereg(r);
4236     raw_fmov_log2_e(r);
4237     f_unlock(r);
4238     }
4239     MENDFUNC(1,fmov_log2_e,(FW r))
4240    
4241     MIDFUNC(1,fmov_loge_2,(FW r))
4242     {
4243     r=f_writereg(r);
4244     raw_fmov_loge_2(r);
4245     f_unlock(r);
4246     }
4247     MENDFUNC(1,fmov_loge_2,(FW r))
4248    
4249     MIDFUNC(1,fmov_1,(FW r))
4250     {
4251     r=f_writereg(r);
4252     raw_fmov_1(r);
4253     f_unlock(r);
4254     }
4255     MENDFUNC(1,fmov_1,(FW r))
4256    
4257     MIDFUNC(1,fmov_0,(FW r))
4258     {
4259     r=f_writereg(r);
4260     raw_fmov_0(r);
4261     f_unlock(r);
4262     }
4263     MENDFUNC(1,fmov_0,(FW r))
4264    
4265     MIDFUNC(2,fmov_rm,(FW r, MEMR m))
4266     {
4267     r=f_writereg(r);
4268     raw_fmov_rm(r,m);
4269     f_unlock(r);
4270     }
4271     MENDFUNC(2,fmov_rm,(FW r, MEMR m))
4272    
4273     MIDFUNC(2,fmovi_rm,(FW r, MEMR m))
4274     {
4275     r=f_writereg(r);
4276     raw_fmovi_rm(r,m);
4277     f_unlock(r);
4278     }
4279     MENDFUNC(2,fmovi_rm,(FW r, MEMR m))
4280    
4281     MIDFUNC(2,fmovi_mr,(MEMW m, FR r))
4282     {
4283     r=f_readreg(r);
4284     raw_fmovi_mr(m,r);
4285     f_unlock(r);
4286     }
4287     MENDFUNC(2,fmovi_mr,(MEMW m, FR r))
4288    
4289     MIDFUNC(2,fmovs_rm,(FW r, MEMR m))
4290     {
4291     r=f_writereg(r);
4292     raw_fmovs_rm(r,m);
4293     f_unlock(r);
4294     }
4295     MENDFUNC(2,fmovs_rm,(FW r, MEMR m))
4296    
4297     MIDFUNC(2,fmovs_mr,(MEMW m, FR r))
4298     {
4299     r=f_readreg(r);
4300     raw_fmovs_mr(m,r);
4301     f_unlock(r);
4302     }
4303     MENDFUNC(2,fmovs_mr,(MEMW m, FR r))
4304    
4305     MIDFUNC(2,fmov_ext_mr,(MEMW m, FR r))
4306     {
4307     r=f_readreg(r);
4308     raw_fmov_ext_mr(m,r);
4309     f_unlock(r);
4310     }
4311     MENDFUNC(2,fmov_ext_mr,(MEMW m, FR r))
4312    
4313     MIDFUNC(2,fmov_mr,(MEMW m, FR r))
4314     {
4315     r=f_readreg(r);
4316     raw_fmov_mr(m,r);
4317     f_unlock(r);
4318     }
4319     MENDFUNC(2,fmov_mr,(MEMW m, FR r))
4320    
4321     MIDFUNC(2,fmov_ext_rm,(FW r, MEMR m))
4322     {
4323     r=f_writereg(r);
4324     raw_fmov_ext_rm(r,m);
4325     f_unlock(r);
4326     }
4327     MENDFUNC(2,fmov_ext_rm,(FW r, MEMR m))
4328    
4329     MIDFUNC(2,fmov_rr,(FW d, FR s))
4330     {
4331     if (d==s) { /* How pointless! */
4332     return;
4333     }
4334     #if USE_F_ALIAS
4335     f_disassociate(d);
4336     s=f_readreg(s);
4337     live.fate[d].realreg=s;
4338     live.fate[d].realind=live.fat[s].nholds;
4339     live.fate[d].status=DIRTY;
4340     live.fat[s].holds[live.fat[s].nholds]=d;
4341     live.fat[s].nholds++;
4342     f_unlock(s);
4343     #else
4344     s=f_readreg(s);
4345     d=f_writereg(d);
4346     raw_fmov_rr(d,s);
4347     f_unlock(s);
4348     f_unlock(d);
4349     #endif
4350     }
4351     MENDFUNC(2,fmov_rr,(FW d, FR s))
4352    
4353     MIDFUNC(2,fldcw_m_indexed,(R4 index, IMM base))
4354     {
4355     index=readreg(index,4);
4356    
4357     raw_fldcw_m_indexed(index,base);
4358     unlock2(index);
4359     }
4360     MENDFUNC(2,fldcw_m_indexed,(R4 index, IMM base))
4361    
4362     MIDFUNC(1,ftst_r,(FR r))
4363     {
4364     r=f_readreg(r);
4365     raw_ftst_r(r);
4366     f_unlock(r);
4367     }
4368     MENDFUNC(1,ftst_r,(FR r))
4369    
4370     MIDFUNC(0,dont_care_fflags,(void))
4371     {
4372     f_disassociate(FP_RESULT);
4373     }
4374     MENDFUNC(0,dont_care_fflags,(void))
4375    
4376     MIDFUNC(2,fsqrt_rr,(FW d, FR s))
4377     {
4378     s=f_readreg(s);
4379     d=f_writereg(d);
4380     raw_fsqrt_rr(d,s);
4381     f_unlock(s);
4382     f_unlock(d);
4383     }
4384     MENDFUNC(2,fsqrt_rr,(FW d, FR s))
4385    
4386     MIDFUNC(2,fabs_rr,(FW d, FR s))
4387     {
4388     s=f_readreg(s);
4389     d=f_writereg(d);
4390     raw_fabs_rr(d,s);
4391     f_unlock(s);
4392     f_unlock(d);
4393     }
4394     MENDFUNC(2,fabs_rr,(FW d, FR s))
4395    
4396     MIDFUNC(2,fsin_rr,(FW d, FR s))
4397     {
4398     s=f_readreg(s);
4399     d=f_writereg(d);
4400     raw_fsin_rr(d,s);
4401     f_unlock(s);
4402     f_unlock(d);
4403     }
4404     MENDFUNC(2,fsin_rr,(FW d, FR s))
4405    
4406     MIDFUNC(2,fcos_rr,(FW d, FR s))
4407     {
4408     s=f_readreg(s);
4409     d=f_writereg(d);
4410     raw_fcos_rr(d,s);
4411     f_unlock(s);
4412     f_unlock(d);
4413     }
4414     MENDFUNC(2,fcos_rr,(FW d, FR s))
4415    
4416     MIDFUNC(2,ftwotox_rr,(FW d, FR s))
4417     {
4418     s=f_readreg(s);
4419     d=f_writereg(d);
4420     raw_ftwotox_rr(d,s);
4421     f_unlock(s);
4422     f_unlock(d);
4423     }
4424     MENDFUNC(2,ftwotox_rr,(FW d, FR s))
4425    
4426     MIDFUNC(2,fetox_rr,(FW d, FR s))
4427     {
4428     s=f_readreg(s);
4429     d=f_writereg(d);
4430     raw_fetox_rr(d,s);
4431     f_unlock(s);
4432     f_unlock(d);
4433     }
4434     MENDFUNC(2,fetox_rr,(FW d, FR s))
4435    
4436     MIDFUNC(2,frndint_rr,(FW d, FR s))
4437     {
4438     s=f_readreg(s);
4439     d=f_writereg(d);
4440     raw_frndint_rr(d,s);
4441     f_unlock(s);
4442     f_unlock(d);
4443     }
4444     MENDFUNC(2,frndint_rr,(FW d, FR s))
4445    
4446     MIDFUNC(2,flog2_rr,(FW d, FR s))
4447     {
4448     s=f_readreg(s);
4449     d=f_writereg(d);
4450     raw_flog2_rr(d,s);
4451     f_unlock(s);
4452     f_unlock(d);
4453     }
4454     MENDFUNC(2,flog2_rr,(FW d, FR s))
4455    
4456     MIDFUNC(2,fneg_rr,(FW d, FR s))
4457     {
4458     s=f_readreg(s);
4459     d=f_writereg(d);
4460     raw_fneg_rr(d,s);
4461     f_unlock(s);
4462     f_unlock(d);
4463     }
4464     MENDFUNC(2,fneg_rr,(FW d, FR s))
4465    
4466     MIDFUNC(2,fadd_rr,(FRW d, FR s))
4467     {
4468     s=f_readreg(s);
4469     d=f_rmw(d);
4470     raw_fadd_rr(d,s);
4471     f_unlock(s);
4472     f_unlock(d);
4473     }
4474     MENDFUNC(2,fadd_rr,(FRW d, FR s))
4475    
4476     MIDFUNC(2,fsub_rr,(FRW d, FR s))
4477     {
4478     s=f_readreg(s);
4479     d=f_rmw(d);
4480     raw_fsub_rr(d,s);
4481     f_unlock(s);
4482     f_unlock(d);
4483     }
4484     MENDFUNC(2,fsub_rr,(FRW d, FR s))
4485    
4486     MIDFUNC(2,fcmp_rr,(FR d, FR s))
4487     {
4488     d=f_readreg(d);
4489     s=f_readreg(s);
4490     raw_fcmp_rr(d,s);
4491     f_unlock(s);
4492     f_unlock(d);
4493     }
4494     MENDFUNC(2,fcmp_rr,(FR d, FR s))
4495    
4496     MIDFUNC(2,fdiv_rr,(FRW d, FR s))
4497     {
4498     s=f_readreg(s);
4499     d=f_rmw(d);
4500     raw_fdiv_rr(d,s);
4501     f_unlock(s);
4502     f_unlock(d);
4503     }
4504     MENDFUNC(2,fdiv_rr,(FRW d, FR s))
4505    
4506     MIDFUNC(2,frem_rr,(FRW d, FR s))
4507     {
4508     s=f_readreg(s);
4509     d=f_rmw(d);
4510     raw_frem_rr(d,s);
4511     f_unlock(s);
4512     f_unlock(d);
4513     }
4514     MENDFUNC(2,frem_rr,(FRW d, FR s))
4515    
4516     MIDFUNC(2,frem1_rr,(FRW d, FR s))
4517     {
4518     s=f_readreg(s);
4519     d=f_rmw(d);
4520     raw_frem1_rr(d,s);
4521     f_unlock(s);
4522     f_unlock(d);
4523     }
4524     MENDFUNC(2,frem1_rr,(FRW d, FR s))
4525    
4526     MIDFUNC(2,fmul_rr,(FRW d, FR s))
4527     {
4528     s=f_readreg(s);
4529     d=f_rmw(d);
4530     raw_fmul_rr(d,s);
4531     f_unlock(s);
4532     f_unlock(d);
4533     }
4534     MENDFUNC(2,fmul_rr,(FRW d, FR s))
4535    
4536     /********************************************************************
4537     * Support functions exposed to gencomp. CREATE time *
4538     ********************************************************************/
4539    
4540     int kill_rodent(int r)
4541     {
4542     return KILLTHERAT &&
4543     have_rat_stall &&
4544     (live.state[r].status==INMEM ||
4545     live.state[r].status==CLEAN ||
4546     live.state[r].status==ISCONST ||
4547     live.state[r].dirtysize==4);
4548     }
4549    
4550     uae_u32 get_const(int r)
4551     {
4552     Dif (!isconst(r)) {
4553     write_log("Register %d should be constant, but isn't\n",r);
4554     abort();
4555     }
4556     return live.state[r].val;
4557     }
4558    
4559     void sync_m68k_pc(void)
4560     {
4561     if (m68k_pc_offset) {
4562     add_l_ri(PC_P,m68k_pc_offset);
4563     comp_pc_p+=m68k_pc_offset;
4564     m68k_pc_offset=0;
4565     }
4566     }
4567    
4568     /********************************************************************
4569     * Scratch registers management *
4570     ********************************************************************/
4571    
4572     struct scratch_t {
4573     uae_u32 regs[VREGS];
4574     fpu_register fregs[VFREGS];
4575     };
4576    
4577     static scratch_t scratch;
4578    
4579     /********************************************************************
4580     * Support functions exposed to newcpu *
4581     ********************************************************************/
4582    
4583     static inline const char *str_on_off(bool b)
4584     {
4585     return b ? "on" : "off";
4586     }
4587    
4588     static __inline__ unsigned int cft_map (unsigned int f)
4589     {
4590     #ifndef HAVE_GET_WORD_UNSWAPPED
4591     return f;
4592     #else
4593     return ((f >> 8) & 255) | ((f & 255) << 8);
4594     #endif
4595     }
4596    
4597     void compiler_init(void)
4598     {
4599     static bool initialized = false;
4600     if (initialized)
4601     return;
4602    
4603     #ifndef WIN32
4604     // Open /dev/zero
4605     zero_fd = open("/dev/zero", O_RDWR);
4606     if (zero_fd < 0) {
4607     char str[200];
4608     sprintf(str, GetString(STR_NO_DEV_ZERO_ERR), strerror(errno));
4609     ErrorAlert(str);
4610     QuitEmulator();
4611     }
4612     #endif
4613    
4614     #if JIT_DEBUG
4615     // JIT debug mode ?
4616     JITDebug = PrefsFindBool("jitdebug");
4617     #endif
4618     write_log("<JIT compiler> : enable runtime disassemblers : %s\n", JITDebug ? "yes" : "no");
4619    
4620     #ifdef USE_JIT_FPU
4621     // Use JIT compiler for FPU instructions ?
4622     avoid_fpu = !PrefsFindBool("jitfpu");
4623     #else
4624     // JIT FPU is always disabled
4625     avoid_fpu = true;
4626     #endif
4627     write_log("<JIT compiler> : compile FPU instructions : %s\n", !avoid_fpu ? "yes" : "no");
4628    
4629     // Get size of the translation cache (in KB)
4630     cache_size = PrefsFindInt32("jitcachesize");
4631     write_log("<JIT compiler> : requested translation cache size : %d KB\n", cache_size);
4632    
4633     // Initialize target CPU (check for features, e.g. CMOV, rat stalls)
4634     raw_init_cpu();
4635     write_log("<JIT compiler> : target processor has CMOV instructions : %s\n", have_cmov ? "yes" : "no");
4636     write_log("<JIT compiler> : target processor can suffer from partial register stalls : %s\n", have_rat_stall ? "yes" : "no");
4637 gbeauche 1.5 write_log("<JIT compiler> : alignment for loops, jumps are %d, %d\n", align_loops, align_jumps);
4638 gbeauche 1.1
4639     // Translation cache flush mechanism
4640     lazy_flush = PrefsFindBool("jitlazyflush");
4641     write_log("<JIT compiler> : lazy translation cache invalidation : %s\n", str_on_off(lazy_flush));
4642     flush_icache = lazy_flush ? flush_icache_lazy : flush_icache_hard;
4643    
4644     // Compiler features
4645     write_log("<JIT compiler> : register aliasing : %s\n", str_on_off(1));
4646     write_log("<JIT compiler> : FP register aliasing : %s\n", str_on_off(USE_F_ALIAS));
4647     write_log("<JIT compiler> : lazy constant offsetting : %s\n", str_on_off(USE_OFFSET));
4648 gbeauche 1.8 write_log("<JIT compiler> : block inlining : %s\n", str_on_off(USE_INLINING));
4649 gbeauche 1.1 write_log("<JIT compiler> : separate blockinfo allocation : %s\n", str_on_off(USE_SEPARATE_BIA));
4650    
4651     // Build compiler tables
4652     build_comp();
4653    
4654     initialized = true;
4655    
4656 gbeauche 1.9 #if PROFILE_UNTRANSLATED_INSNS
4657     write_log("<JIT compiler> : gather statistics on untranslated insns count\n");
4658     #endif
4659    
4660 gbeauche 1.1 #if PROFILE_COMPILE_TIME
4661     write_log("<JIT compiler> : gather statistics on translation time\n");
4662     emul_start_time = clock();
4663     #endif
4664     }
4665    
4666     void compiler_exit(void)
4667     {
4668     #if PROFILE_COMPILE_TIME
4669     emul_end_time = clock();
4670     #endif
4671    
4672     // Deallocate translation cache
4673     if (compiled_code) {
4674 gbeauche 1.3 vm_release(compiled_code, cache_size * 1024);
4675 gbeauche 1.1 compiled_code = 0;
4676     }
4677    
4678     #ifndef WIN32
4679     // Close /dev/zero
4680     if (zero_fd > 0)
4681     close(zero_fd);
4682     #endif
4683    
4684     #if PROFILE_COMPILE_TIME
4685     write_log("### Compile Block statistics\n");
4686     write_log("Number of calls to compile_block : %d\n", compile_count);
4687     uae_u32 emul_time = emul_end_time - emul_start_time;
4688     write_log("Total emulation time : %.1f sec\n", double(emul_time)/double(CLOCKS_PER_SEC));
4689     write_log("Total compilation time : %.1f sec (%.1f%%)\n", double(compile_time)/double(CLOCKS_PER_SEC),
4690     100.0*double(compile_time)/double(emul_time));
4691     write_log("\n");
4692     #endif
4693 gbeauche 1.9
4694     #if PROFILE_UNTRANSLATED_INSNS
4695     uae_u64 untranslated_count = 0;
4696     for (int i = 0; i < 65536; i++) {
4697     opcode_nums[i] = i;
4698     untranslated_count += raw_cputbl_count[i];
4699     }
4700     write_log("Sorting out untranslated instructions count...\n");
4701     qsort(opcode_nums, 65536, sizeof(uae_u16), untranslated_compfn);
4702     write_log("\nRank Opc Count Name\n");
4703     for (int i = 0; i < untranslated_top_ten; i++) {
4704     uae_u32 count = raw_cputbl_count[opcode_nums[i]];
4705     struct instr *dp;
4706     struct mnemolookup *lookup;
4707     if (!count)
4708     break;
4709     dp = table68k + opcode_nums[i];
4710     for (lookup = lookuptab; lookup->mnemo != dp->mnemo; lookup++)
4711     ;
4712     write_log("%03d: %04x %10lu %s\n", i, opcode_nums[i], count, lookup->name);
4713     }
4714     #endif
4715 gbeauche 1.1 }
4716    
4717     bool compiler_use_jit(void)
4718     {
4719     // Check for the "jit" prefs item
4720     if (!PrefsFindBool("jit"))
4721     return false;
4722    
4723     // Don't use JIT if translation cache size is less then MIN_CACHE_SIZE KB
4724     if (PrefsFindInt32("jitcachesize") < MIN_CACHE_SIZE) {
4725     write_log("<JIT compiler> : translation cache size is less than %d KB. Disabling JIT.\n", MIN_CACHE_SIZE);
4726     return false;
4727     }
4728    
4729     // FIXME: there are currently problems with JIT compilation and anything below a 68040
4730     if (CPUType < 4) {
4731     write_log("<JIT compiler> : 68040 emulation is required instead of 680%d0. Disabling JIT.\n", CPUType);
4732     return false;
4733     }
4734    
4735     return true;
4736     }
4737    
4738     void init_comp(void)
4739     {
4740     int i;
4741     uae_s8* cb=can_byte;
4742     uae_s8* cw=can_word;
4743     uae_s8* au=always_used;
4744    
4745     for (i=0;i<VREGS;i++) {
4746     live.state[i].realreg=-1;
4747     live.state[i].needflush=NF_SCRATCH;
4748     live.state[i].val=0;
4749     set_status(i,UNDEF);
4750     }
4751    
4752     for (i=0;i<VFREGS;i++) {
4753     live.fate[i].status=UNDEF;
4754     live.fate[i].realreg=-1;
4755     live.fate[i].needflush=NF_SCRATCH;
4756     }
4757    
4758     for (i=0;i<VREGS;i++) {
4759     if (i<16) { /* First 16 registers map to 68k registers */
4760     live.state[i].mem=((uae_u32*)&regs)+i;
4761     live.state[i].needflush=NF_TOMEM;
4762     set_status(i,INMEM);
4763     }
4764     else
4765     live.state[i].mem=scratch.regs+i;
4766     }
4767     live.state[PC_P].mem=(uae_u32*)&(regs.pc_p);
4768     live.state[PC_P].needflush=NF_TOMEM;
4769     set_const(PC_P,(uae_u32)comp_pc_p);
4770    
4771     live.state[FLAGX].mem=&(regflags.x);
4772     live.state[FLAGX].needflush=NF_TOMEM;
4773     set_status(FLAGX,INMEM);
4774    
4775     live.state[FLAGTMP].mem=&(regflags.cznv);
4776     live.state[FLAGTMP].needflush=NF_TOMEM;
4777     set_status(FLAGTMP,INMEM);
4778    
4779     live.state[NEXT_HANDLER].needflush=NF_HANDLER;
4780     set_status(NEXT_HANDLER,UNDEF);
4781    
4782     for (i=0;i<VFREGS;i++) {
4783     if (i<8) { /* First 8 registers map to 68k FPU registers */
4784     live.fate[i].mem=(uae_u32*)fpu_register_address(i);
4785     live.fate[i].needflush=NF_TOMEM;
4786     live.fate[i].status=INMEM;
4787     }
4788     else if (i==FP_RESULT) {
4789     live.fate[i].mem=(uae_u32*)(&fpu.result);
4790     live.fate[i].needflush=NF_TOMEM;
4791     live.fate[i].status=INMEM;
4792     }
4793     else
4794     live.fate[i].mem=(uae_u32*)(scratch.fregs+i);
4795     }
4796    
4797    
4798     for (i=0;i<N_REGS;i++) {
4799     live.nat[i].touched=0;
4800     live.nat[i].nholds=0;
4801     live.nat[i].locked=0;
4802     if (*cb==i) {
4803     live.nat[i].canbyte=1; cb++;
4804     } else live.nat[i].canbyte=0;
4805     if (*cw==i) {
4806     live.nat[i].canword=1; cw++;
4807     } else live.nat[i].canword=0;
4808     if (*au==i) {
4809     live.nat[i].locked=1; au++;
4810     }
4811     }
4812    
4813     for (i=0;i<N_FREGS;i++) {
4814     live.fat[i].touched=0;
4815     live.fat[i].nholds=0;
4816     live.fat[i].locked=0;
4817     }
4818    
4819     touchcnt=1;
4820     m68k_pc_offset=0;
4821     live.flags_in_flags=TRASH;
4822     live.flags_on_stack=VALID;
4823     live.flags_are_important=1;
4824    
4825     raw_fp_init();
4826     }
4827    
4828     /* Only do this if you really mean it! The next call should be to init!*/
4829     void flush(int save_regs)
4830     {
4831     int fi,i;
4832    
4833     log_flush();
4834     flush_flags(); /* low level */
4835     sync_m68k_pc(); /* mid level */
4836    
4837     if (save_regs) {
4838     for (i=0;i<VFREGS;i++) {
4839     if (live.fate[i].needflush==NF_SCRATCH ||
4840     live.fate[i].status==CLEAN) {
4841     f_disassociate(i);
4842     }
4843     }
4844     for (i=0;i<VREGS;i++) {
4845     if (live.state[i].needflush==NF_TOMEM) {
4846     switch(live.state[i].status) {
4847     case INMEM:
4848     if (live.state[i].val) {
4849     raw_add_l_mi((uae_u32)live.state[i].mem,live.state[i].val);
4850     log_vwrite(i);
4851     live.state[i].val=0;
4852     }
4853     break;
4854     case CLEAN:
4855     case DIRTY:
4856     remove_offset(i,-1); tomem(i); break;
4857     case ISCONST:
4858     if (i!=PC_P)
4859     writeback_const(i);
4860     break;
4861     default: break;
4862     }
4863     Dif (live.state[i].val && i!=PC_P) {
4864     write_log("Register %d still has val %x\n",
4865     i,live.state[i].val);
4866     }
4867     }
4868     }
4869     for (i=0;i<VFREGS;i++) {
4870     if (live.fate[i].needflush==NF_TOMEM &&
4871     live.fate[i].status==DIRTY) {
4872     f_evict(i);
4873     }
4874     }
4875     raw_fp_cleanup_drop();
4876     }
4877     if (needflags) {
4878     write_log("Warning! flush with needflags=1!\n");
4879     }
4880     }
4881    
4882     static void flush_keepflags(void)
4883     {
4884     int fi,i;
4885    
4886     for (i=0;i<VFREGS;i++) {
4887     if (live.fate[i].needflush==NF_SCRATCH ||
4888     live.fate[i].status==CLEAN) {
4889     f_disassociate(i);
4890     }
4891     }
4892     for (i=0;i<VREGS;i++) {
4893     if (live.state[i].needflush==NF_TOMEM) {
4894     switch(live.state[i].status) {
4895     case INMEM:
4896     /* Can't adjust the offset here --- that needs "add" */
4897     break;
4898     case CLEAN:
4899     case DIRTY:
4900     remove_offset(i,-1); tomem(i); break;
4901     case ISCONST:
4902     if (i!=PC_P)
4903     writeback_const(i);
4904     break;
4905     default: break;
4906     }
4907     }
4908     }
4909     for (i=0;i<VFREGS;i++) {
4910     if (live.fate[i].needflush==NF_TOMEM &&
4911     live.fate[i].status==DIRTY) {
4912     f_evict(i);
4913     }
4914     }
4915     raw_fp_cleanup_drop();
4916     }
4917    
4918     void freescratch(void)
4919     {
4920     int i;
4921     for (i=0;i<N_REGS;i++)
4922     if (live.nat[i].locked && i!=4)
4923     write_log("Warning! %d is locked\n",i);
4924    
4925     for (i=0;i<VREGS;i++)
4926     if (live.state[i].needflush==NF_SCRATCH) {
4927     forget_about(i);
4928     }
4929    
4930     for (i=0;i<VFREGS;i++)
4931     if (live.fate[i].needflush==NF_SCRATCH) {
4932     f_forget_about(i);
4933     }
4934     }
4935    
4936     /********************************************************************
4937     * Support functions, internal *
4938     ********************************************************************/
4939    
4940    
4941     static void align_target(uae_u32 a)
4942     {
4943     /* Fill with NOPs --- makes debugging with gdb easier */
4944     while ((uae_u32)target&(a-1))
4945     *target++=0x90;
4946     }
4947    
4948     static __inline__ int isinrom(uintptr addr)
4949     {
4950     return ((addr >= (uintptr)ROMBaseHost) && (addr < (uintptr)ROMBaseHost + ROMSize));
4951     }
4952    
4953     static void flush_all(void)
4954     {
4955     int i;
4956    
4957     log_flush();
4958     for (i=0;i<VREGS;i++)
4959     if (live.state[i].status==DIRTY) {
4960     if (!call_saved[live.state[i].realreg]) {
4961     tomem(i);
4962     }
4963     }
4964     for (i=0;i<VFREGS;i++)
4965     if (f_isinreg(i))
4966     f_evict(i);
4967     raw_fp_cleanup_drop();
4968     }
4969    
4970     /* Make sure all registers that will get clobbered by a call are
4971     save and sound in memory */
4972     static void prepare_for_call_1(void)
4973     {
4974     flush_all(); /* If there are registers that don't get clobbered,
4975     * we should be a bit more selective here */
4976     }
4977    
4978     /* We will call a C routine in a moment. That will clobber all registers,
4979     so we need to disassociate everything */
4980     static void prepare_for_call_2(void)
4981     {
4982     int i;
4983     for (i=0;i<N_REGS;i++)
4984     if (!call_saved[i] && live.nat[i].nholds>0)
4985     free_nreg(i);
4986    
4987     for (i=0;i<N_FREGS;i++)
4988     if (live.fat[i].nholds>0)
4989     f_free_nreg(i);
4990    
4991     live.flags_in_flags=TRASH; /* Note: We assume we already rescued the
4992     flags at the very start of the call_r
4993     functions! */
4994     }
4995    
4996     /********************************************************************
4997     * Memory access and related functions, CREATE time *
4998     ********************************************************************/
4999    
5000     void register_branch(uae_u32 not_taken, uae_u32 taken, uae_u8 cond)
5001     {
5002     next_pc_p=not_taken;
5003     taken_pc_p=taken;
5004     branch_cc=cond;
5005     }
5006    
5007    
5008     static uae_u32 get_handler_address(uae_u32 addr)
5009     {
5010     uae_u32 cl=cacheline(addr);
5011     blockinfo* bi=get_blockinfo_addr_new((void*)addr,0);
5012     return (uae_u32)&(bi->direct_handler_to_use);
5013     }
5014    
5015     static uae_u32 get_handler(uae_u32 addr)
5016     {
5017     uae_u32 cl=cacheline(addr);
5018     blockinfo* bi=get_blockinfo_addr_new((void*)addr,0);
5019     return (uae_u32)bi->direct_handler_to_use;
5020     }
5021    
5022     static void load_handler(int reg, uae_u32 addr)
5023     {
5024     mov_l_rm(reg,get_handler_address(addr));
5025     }
5026    
5027     /* This version assumes that it is writing *real* memory, and *will* fail
5028     * if that assumption is wrong! No branches, no second chances, just
5029     * straight go-for-it attitude */
5030    
5031     static void writemem_real(int address, int source, int offset, int size, int tmp, int clobber)
5032     {
5033     int f=tmp;
5034    
5035     if (clobber)
5036     f=source;
5037     switch(size) {
5038     case 1: mov_b_bRr(address,source,MEMBaseDiff); break;
5039     case 2: mov_w_rr(f,source); bswap_16(f); mov_w_bRr(address,f,MEMBaseDiff); break;
5040     case 4: mov_l_rr(f,source); bswap_32(f); mov_l_bRr(address,f,MEMBaseDiff); break;
5041     }
5042     forget_about(tmp);
5043     forget_about(f);
5044     }
5045    
5046     void writebyte(int address, int source, int tmp)
5047     {
5048     writemem_real(address,source,20,1,tmp,0);
5049     }
5050    
5051     static __inline__ void writeword_general(int address, int source, int tmp,
5052     int clobber)
5053     {
5054     writemem_real(address,source,16,2,tmp,clobber);
5055     }
5056    
5057     void writeword_clobber(int address, int source, int tmp)
5058     {
5059     writeword_general(address,source,tmp,1);
5060     }
5061    
5062     void writeword(int address, int source, int tmp)
5063     {
5064     writeword_general(address,source,tmp,0);
5065     }
5066    
5067     static __inline__ void writelong_general(int address, int source, int tmp,
5068     int clobber)
5069     {
5070     writemem_real(address,source,12,4,tmp,clobber);
5071     }
5072    
5073     void writelong_clobber(int address, int source, int tmp)
5074     {
5075     writelong_general(address,source,tmp,1);
5076     }
5077    
5078     void writelong(int address, int source, int tmp)
5079     {
5080     writelong_general(address,source,tmp,0);
5081     }
5082    
5083    
5084    
5085     /* This version assumes that it is reading *real* memory, and *will* fail
5086     * if that assumption is wrong! No branches, no second chances, just
5087     * straight go-for-it attitude */
5088    
5089     static void readmem_real(int address, int dest, int offset, int size, int tmp)
5090     {
5091     int f=tmp;
5092    
5093     if (size==4 && address!=dest)
5094     f=dest;
5095    
5096     switch(size) {
5097     case 1: mov_b_brR(dest,address,MEMBaseDiff); break;
5098     case 2: mov_w_brR(dest,address,MEMBaseDiff); bswap_16(dest); break;
5099     case 4: mov_l_brR(dest,address,MEMBaseDiff); bswap_32(dest); break;
5100     }
5101     forget_about(tmp);
5102     }
5103    
5104     void readbyte(int address, int dest, int tmp)
5105     {
5106     readmem_real(address,dest,8,1,tmp);
5107     }
5108    
5109     void readword(int address, int dest, int tmp)
5110     {
5111     readmem_real(address,dest,4,2,tmp);
5112     }
5113    
5114     void readlong(int address, int dest, int tmp)
5115     {
5116     readmem_real(address,dest,0,4,tmp);
5117     }
5118    
5119     void get_n_addr(int address, int dest, int tmp)
5120     {
5121     // a is the register containing the virtual address
5122     // after the offset had been fetched
5123     int a=tmp;
5124    
5125     // f is the register that will contain the offset
5126     int f=tmp;
5127    
5128     // a == f == tmp if (address == dest)
5129     if (address!=dest) {
5130     a=address;
5131     f=dest;
5132     }
5133    
5134     #if REAL_ADDRESSING
5135     mov_l_rr(dest, address);
5136     #elif DIRECT_ADDRESSING
5137     lea_l_brr(dest,address,MEMBaseDiff);
5138     #endif
5139     forget_about(tmp);
5140     }
5141    
5142     void get_n_addr_jmp(int address, int dest, int tmp)
5143     {
5144     /* For this, we need to get the same address as the rest of UAE
5145     would --- otherwise we end up translating everything twice */
5146     get_n_addr(address,dest,tmp);
5147     }
5148    
5149    
5150     /* base is a register, but dp is an actual value.
5151     target is a register, as is tmp */
5152     void calc_disp_ea_020(int base, uae_u32 dp, int target, int tmp)
5153     {
5154     int reg = (dp >> 12) & 15;
5155     int regd_shift=(dp >> 9) & 3;
5156    
5157     if (dp & 0x100) {
5158     int ignorebase=(dp&0x80);
5159     int ignorereg=(dp&0x40);
5160     int addbase=0;
5161     int outer=0;
5162    
5163     if ((dp & 0x30) == 0x20) addbase = (uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
5164     if ((dp & 0x30) == 0x30) addbase = comp_get_ilong((m68k_pc_offset+=4)-4);
5165    
5166     if ((dp & 0x3) == 0x2) outer = (uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2);
5167     if ((dp & 0x3) == 0x3) outer = comp_get_ilong((m68k_pc_offset+=4)-4);
5168    
5169     if ((dp & 0x4) == 0) { /* add regd *before* the get_long */
5170     if (!ignorereg) {
5171     if ((dp & 0x800) == 0)
5172     sign_extend_16_rr(target,reg);
5173     else
5174     mov_l_rr(target,reg);
5175     shll_l_ri(target,regd_shift);
5176     }
5177     else
5178     mov_l_ri(target,0);
5179    
5180     /* target is now regd */
5181     if (!ignorebase)
5182     add_l(target,base);
5183     add_l_ri(target,addbase);
5184     if (dp&0x03) readlong(target,target,tmp);
5185     } else { /* do the getlong first, then add regd */
5186     if (!ignorebase) {
5187     mov_l_rr(target,base);
5188     add_l_ri(target,addbase);
5189     }
5190     else
5191     mov_l_ri(target,addbase);
5192     if (dp&0x03) readlong(target,target,tmp);
5193    
5194     if (!ignorereg) {
5195     if ((dp & 0x800) == 0)
5196     sign_extend_16_rr(tmp,reg);
5197     else
5198     mov_l_rr(tmp,reg);
5199     shll_l_ri(tmp,regd_shift);
5200     /* tmp is now regd */
5201     add_l(target,tmp);
5202     }
5203     }
5204     add_l_ri(target,outer);
5205     }
5206     else { /* 68000 version */
5207     if ((dp & 0x800) == 0) { /* Sign extend */
5208     sign_extend_16_rr(target,reg);
5209     lea_l_brr_indexed(target,base,target,1<<regd_shift,(uae_s32)((uae_s8)dp));
5210     }
5211     else {
5212     lea_l_brr_indexed(target,base,reg,1<<regd_shift,(uae_s32)((uae_s8)dp));
5213     }
5214     }
5215     forget_about(tmp);
5216     }
5217    
5218    
5219    
5220    
5221    
5222     void set_cache_state(int enabled)
5223     {
5224     if (enabled!=letit)
5225     flush_icache_hard(77);
5226     letit=enabled;
5227     }
5228    
5229     int get_cache_state(void)
5230     {
5231     return letit;
5232     }
5233    
5234     uae_u32 get_jitted_size(void)
5235     {
5236     if (compiled_code)
5237     return current_compile_p-compiled_code;
5238     return 0;
5239     }
5240    
5241     void alloc_cache(void)
5242     {
5243     if (compiled_code) {
5244     flush_icache_hard(6);
5245 gbeauche 1.3 vm_release(compiled_code, cache_size * 1024);
5246 gbeauche 1.1 compiled_code = 0;
5247     }
5248    
5249     if (cache_size == 0)
5250     return;
5251    
5252     while (!compiled_code && cache_size) {
5253 gbeauche 1.2 if ((compiled_code = (uae_u8 *)vm_acquire(cache_size * 1024)) == VM_MAP_FAILED) {
5254 gbeauche 1.1 compiled_code = 0;
5255     cache_size /= 2;
5256     }
5257     }
5258 gbeauche 1.2 vm_protect(compiled_code, cache_size, VM_PAGE_READ | VM_PAGE_WRITE | VM_PAGE_EXECUTE);
5259 gbeauche 1.1
5260     if (compiled_code) {
5261     write_log("<JIT compiler> : actual translation cache size : %d KB at 0x%08X\n", cache_size, compiled_code);
5262     max_compile_start = compiled_code + cache_size*1024 - BYTES_PER_INST;
5263     current_compile_p = compiled_code;
5264     current_cache_size = 0;
5265     }
5266     }
5267    
5268    
5269    
5270     extern cpuop_rettype op_illg_1 (uae_u32 opcode) REGPARAM;
5271    
5272 gbeauche 1.8 static void calc_checksum(blockinfo* bi, uae_u32* c1, uae_u32* c2)
5273 gbeauche 1.1 {
5274 gbeauche 1.8 uae_u32 k1 = 0;
5275     uae_u32 k2 = 0;
5276    
5277     #if USE_CHECKSUM_INFO
5278     checksum_info *csi = bi->csi;
5279     Dif(!csi) abort();
5280     while (csi) {
5281     uae_s32 len = csi->length;
5282     uae_u32 tmp = (uae_u32)csi->start_p;
5283     #else
5284     uae_s32 len = bi->len;
5285     uae_u32 tmp = (uae_u32)bi->min_pcp;
5286     #endif
5287     uae_u32*pos;
5288 gbeauche 1.1
5289 gbeauche 1.8 len += (tmp & 3);
5290     tmp &= ~3;
5291     pos = (uae_u32 *)tmp;
5292    
5293     if (len >= 0 && len <= MAX_CHECKSUM_LEN) {
5294     while (len > 0) {
5295     k1 += *pos;
5296     k2 ^= *pos;
5297     pos++;
5298     len -= 4;
5299     }
5300     }
5301 gbeauche 1.1
5302 gbeauche 1.8 #if USE_CHECKSUM_INFO
5303     csi = csi->next;
5304 gbeauche 1.1 }
5305 gbeauche 1.8 #endif
5306    
5307     *c1 = k1;
5308     *c2 = k2;
5309 gbeauche 1.1 }
5310    
5311 gbeauche 1.8 #if 0
5312 gbeauche 1.7 static void show_checksum(CSI_TYPE* csi)
5313 gbeauche 1.1 {
5314     uae_u32 k1=0;
5315     uae_u32 k2=0;
5316 gbeauche 1.7 uae_s32 len=CSI_LENGTH(csi);
5317     uae_u32 tmp=(uae_u32)CSI_START_P(csi);
5318 gbeauche 1.1 uae_u32* pos;
5319    
5320     len+=(tmp&3);
5321     tmp&=(~3);
5322     pos=(uae_u32*)tmp;
5323    
5324     if (len<0 || len>MAX_CHECKSUM_LEN) {
5325     return;
5326     }
5327     else {
5328     while (len>0) {
5329     write_log("%08x ",*pos);
5330     pos++;
5331     len-=4;
5332     }
5333     write_log(" bla\n");
5334     }
5335     }
5336 gbeauche 1.8 #endif
5337 gbeauche 1.1
5338    
5339     int check_for_cache_miss(void)
5340     {
5341     blockinfo* bi=get_blockinfo_addr(regs.pc_p);
5342    
5343     if (bi) {
5344     int cl=cacheline(regs.pc_p);
5345     if (bi!=cache_tags[cl+1].bi) {
5346     raise_in_cl_list(bi);
5347     return 1;
5348     }
5349     }
5350     return 0;
5351     }
5352    
5353    
5354     static void recompile_block(void)
5355     {
5356     /* An existing block's countdown code has expired. We need to make
5357     sure that execute_normal doesn't refuse to recompile due to a
5358     perceived cache miss... */
5359     blockinfo* bi=get_blockinfo_addr(regs.pc_p);
5360    
5361     Dif (!bi)
5362     abort();
5363     raise_in_cl_list(bi);
5364     execute_normal();
5365     return;
5366     }
5367     static void cache_miss(void)
5368     {
5369     blockinfo* bi=get_blockinfo_addr(regs.pc_p);
5370     uae_u32 cl=cacheline(regs.pc_p);
5371     blockinfo* bi2=get_blockinfo(cl);
5372    
5373     if (!bi) {
5374     execute_normal(); /* Compile this block now */
5375     return;
5376     }
5377     Dif (!bi2 || bi==bi2) {
5378     write_log("Unexplained cache miss %p %p\n",bi,bi2);
5379     abort();
5380     }
5381     raise_in_cl_list(bi);
5382     return;
5383     }
5384    
5385     static int called_check_checksum(blockinfo* bi);
5386    
5387     static inline int block_check_checksum(blockinfo* bi)
5388     {
5389     uae_u32 c1,c2;
5390 gbeauche 1.7 bool isgood;
5391 gbeauche 1.1
5392     if (bi->status!=BI_NEED_CHECK)
5393     return 1; /* This block is in a checked state */
5394    
5395     checksum_count++;
5396 gbeauche 1.7
5397 gbeauche 1.1 if (bi->c1 || bi->c2)
5398     calc_checksum(bi,&c1,&c2);
5399     else {
5400     c1=c2=1; /* Make sure it doesn't match */
5401 gbeauche 1.7 }
5402 gbeauche 1.1
5403     isgood=(c1==bi->c1 && c2==bi->c2);
5404 gbeauche 1.7
5405 gbeauche 1.1 if (isgood) {
5406     /* This block is still OK. So we reactivate. Of course, that
5407     means we have to move it into the needs-to-be-flushed list */
5408     bi->handler_to_use=bi->handler;
5409     set_dhtu(bi,bi->direct_handler);
5410     bi->status=BI_CHECKING;
5411     isgood=called_check_checksum(bi);
5412     }
5413     if (isgood) {
5414     /* write_log("reactivate %p/%p (%x %x/%x %x)\n",bi,bi->pc_p,
5415     c1,c2,bi->c1,bi->c2);*/
5416     remove_from_list(bi);
5417     add_to_active(bi);
5418     raise_in_cl_list(bi);
5419     bi->status=BI_ACTIVE;
5420     }
5421     else {
5422     /* This block actually changed. We need to invalidate it,
5423     and set it up to be recompiled */
5424     /* write_log("discard %p/%p (%x %x/%x %x)\n",bi,bi->pc_p,
5425     c1,c2,bi->c1,bi->c2); */
5426     invalidate_block(bi);
5427     raise_in_cl_list(bi);
5428     }
5429     return isgood;
5430     }
5431    
5432     static int called_check_checksum(blockinfo* bi)
5433     {
5434     dependency* x=bi->deplist;
5435     int isgood=1;
5436     int i;
5437    
5438     for (i=0;i<2 && isgood;i++) {
5439     if (bi->dep[i].jmp_off) {
5440     isgood=block_check_checksum(bi->dep[i].target);
5441     }
5442     }
5443     return isgood;
5444     }
5445    
5446     static void check_checksum(void)
5447     {
5448     blockinfo* bi=get_blockinfo_addr(regs.pc_p);
5449     uae_u32 cl=cacheline(regs.pc_p);
5450     blockinfo* bi2=get_blockinfo(cl);
5451    
5452     /* These are not the droids you are looking for... */
5453     if (!bi) {
5454     /* Whoever is the primary target is in a dormant state, but
5455     calling it was accidental, and we should just compile this
5456     new block */
5457     execute_normal();
5458     return;
5459     }
5460     if (bi!=bi2) {
5461     /* The block was hit accidentally, but it does exist. Cache miss */
5462     cache_miss();
5463     return;
5464     }
5465    
5466     if (!block_check_checksum(bi))
5467     execute_normal();
5468     }
5469    
5470     static __inline__ void match_states(blockinfo* bi)
5471     {
5472     int i;
5473     smallstate* s=&(bi->env);
5474    
5475     if (bi->status==BI_NEED_CHECK) {
5476     block_check_checksum(bi);
5477     }
5478     if (bi->status==BI_ACTIVE ||
5479     bi->status==BI_FINALIZING) { /* Deal with the *promises* the
5480     block makes (about not using
5481     certain vregs) */
5482     for (i=0;i<16;i++) {
5483     if (s->virt[i]==L_UNNEEDED) {
5484     // write_log("unneeded reg %d at %p\n",i,target);
5485     COMPCALL(forget_about)(i); // FIXME
5486     }
5487     }
5488     }
5489     flush(1);
5490    
5491     /* And now deal with the *demands* the block makes */
5492     for (i=0;i<N_REGS;i++) {
5493     int v=s->nat[i];
5494     if (v>=0) {
5495     // printf("Loading reg %d into %d at %p\n",v,i,target);
5496     readreg_specific(v,4,i);
5497     // do_load_reg(i,v);
5498     // setlock(i);
5499     }
5500     }
5501     for (i=0;i<N_REGS;i++) {
5502     int v=s->nat[i];
5503     if (v>=0) {
5504     unlock2(i);
5505     }
5506     }
5507     }
5508    
5509     static uae_u8 popallspace[1024]; /* That should be enough space */
5510    
5511     static __inline__ void create_popalls(void)
5512     {
5513     int i,r;
5514    
5515     current_compile_p=popallspace;
5516     set_target(current_compile_p);
5517     #if USE_PUSH_POP
5518     /* If we can't use gcc inline assembly, we need to pop some
5519     registers before jumping back to the various get-out routines.
5520     This generates the code for it.
5521     */
5522 gbeauche 1.5 align_target(align_jumps);
5523     popall_do_nothing=get_target();
5524 gbeauche 1.1 for (i=0;i<N_REGS;i++) {
5525     if (need_to_preserve[i])
5526     raw_pop_l_r(i);
5527     }
5528     raw_jmp((uae_u32)do_nothing);
5529    
5530 gbeauche 1.5 align_target(align_jumps);
5531 gbeauche 1.1 popall_execute_normal=get_target();
5532     for (i=0;i<N_REGS;i++) {
5533     if (need_to_preserve[i])
5534     raw_pop_l_r(i);
5535     }
5536     raw_jmp((uae_u32)execute_normal);
5537    
5538 gbeauche 1.5 align_target(align_jumps);
5539 gbeauche 1.1 popall_cache_miss=get_target();
5540     for (i=0;i<N_REGS;i++) {
5541     if (need_to_preserve[i])
5542     raw_pop_l_r(i);
5543     }
5544     raw_jmp((uae_u32)cache_miss);
5545    
5546 gbeauche 1.5 align_target(align_jumps);
5547 gbeauche 1.1 popall_recompile_block=get_target();
5548     for (i=0;i<N_REGS;i++) {
5549     if (need_to_preserve[i])
5550     raw_pop_l_r(i);
5551     }
5552     raw_jmp((uae_u32)recompile_block);
5553 gbeauche 1.5
5554     align_target(align_jumps);
5555 gbeauche 1.1 popall_exec_nostats=get_target();
5556     for (i=0;i<N_REGS;i++) {
5557     if (need_to_preserve[i])
5558     raw_pop_l_r(i);
5559     }
5560     raw_jmp((uae_u32)exec_nostats);
5561 gbeauche 1.5
5562     align_target(align_jumps);
5563 gbeauche 1.1 popall_check_checksum=get_target();
5564     for (i=0;i<N_REGS;i++) {
5565     if (need_to_preserve[i])
5566     raw_pop_l_r(i);
5567     }
5568     raw_jmp((uae_u32)check_checksum);
5569 gbeauche 1.5
5570     align_target(align_jumps);
5571 gbeauche 1.1 current_compile_p=get_target();
5572     #else
5573     popall_exec_nostats=(void *)exec_nostats;
5574     popall_execute_normal=(void *)execute_normal;
5575     popall_cache_miss=(void *)cache_miss;
5576     popall_recompile_block=(void *)recompile_block;
5577     popall_do_nothing=(void *)do_nothing;
5578     popall_check_checksum=(void *)check_checksum;
5579     #endif
5580    
5581     /* And now, the code to do the matching pushes and then jump
5582     into a handler routine */
5583     pushall_call_handler=get_target();
5584     #if USE_PUSH_POP
5585     for (i=N_REGS;i--;) {
5586     if (need_to_preserve[i])
5587     raw_push_l_r(i);
5588     }
5589     #endif
5590     r=REG_PC_TMP;
5591     raw_mov_l_rm(r,(uae_u32)&regs.pc_p);
5592     raw_and_l_ri(r,TAGMASK);
5593     raw_jmp_m_indexed((uae_u32)cache_tags,r,4);
5594 gbeauche 1.6
5595     #ifdef X86_ASSEMBLY
5596     align_target(align_jumps);
5597     m68k_compile_execute = (void (*)(void))get_target();
5598     for (i=N_REGS;i--;) {
5599     if (need_to_preserve[i])
5600     raw_push_l_r(i);
5601     }
5602     align_target(align_loops);
5603     uae_u32 dispatch_loop = (uae_u32)get_target();
5604     r=REG_PC_TMP;
5605     raw_mov_l_rm(r,(uae_u32)&regs.pc_p);
5606     raw_and_l_ri(r,TAGMASK);
5607     raw_call_m_indexed((uae_u32)cache_tags,r,4);
5608     raw_cmp_l_mi((uae_u32)&regs.spcflags,0);
5609     raw_jcc_b_oponly(NATIVE_CC_EQ);
5610     emit_byte(dispatch_loop-((uae_u32)get_target()+1));
5611     raw_call((uae_u32)m68k_do_specialties);
5612     raw_test_l_rr(REG_RESULT,REG_RESULT);
5613     raw_jcc_b_oponly(NATIVE_CC_EQ);
5614     emit_byte(dispatch_loop-((uae_u32)get_target()+1));
5615     raw_cmp_b_mi((uae_u32)&quit_program,0);
5616     raw_jcc_b_oponly(NATIVE_CC_EQ);
5617     emit_byte(dispatch_loop-((uae_u32)get_target()+1));
5618     for (i=0;i<N_REGS;i++) {
5619     if (need_to_preserve[i])
5620     raw_pop_l_r(i);
5621     }
5622     raw_ret();
5623     #endif
5624 gbeauche 1.1 }
5625    
5626     static __inline__ void reset_lists(void)
5627     {
5628     int i;
5629    
5630     for (i=0;i<MAX_HOLD_BI;i++)
5631     hold_bi[i]=NULL;
5632     active=NULL;
5633     dormant=NULL;
5634     }
5635    
5636     static void prepare_block(blockinfo* bi)
5637     {
5638     int i;
5639    
5640     set_target(current_compile_p);
5641 gbeauche 1.5 align_target(align_jumps);
5642 gbeauche 1.1 bi->direct_pen=(cpuop_func *)get_target();
5643     raw_mov_l_rm(0,(uae_u32)&(bi->pc_p));
5644     raw_mov_l_mr((uae_u32)&regs.pc_p,0);
5645     raw_jmp((uae_u32)popall_execute_normal);
5646    
5647 gbeauche 1.5 align_target(align_jumps);
5648 gbeauche 1.1 bi->direct_pcc=(cpuop_func *)get_target();
5649     raw_mov_l_rm(0,(uae_u32)&(bi->pc_p));
5650     raw_mov_l_mr((uae_u32)&regs.pc_p,0);
5651     raw_jmp((uae_u32)popall_check_checksum);
5652     current_compile_p=get_target();
5653    
5654     bi->deplist=NULL;
5655     for (i=0;i<2;i++) {
5656     bi->dep[i].prev_p=NULL;
5657     bi->dep[i].next=NULL;
5658     }
5659     bi->env=default_ss;
5660     bi->status=BI_INVALID;
5661     bi->havestate=0;
5662     //bi->env=empty_ss;
5663     }
5664    
5665     void build_comp(void)
5666     {
5667     int i;
5668     int jumpcount=0;
5669     unsigned long opcode;
5670     struct comptbl* tbl=op_smalltbl_0_comp_ff;
5671     struct comptbl* nftbl=op_smalltbl_0_comp_nf;
5672     int count;
5673     int cpu_level = 0; // 68000 (default)
5674     if (CPUType == 4)
5675     cpu_level = 4; // 68040 with FPU
5676     else {
5677     if (FPUType)
5678     cpu_level = 3; // 68020 with FPU
5679     else if (CPUType >= 2)
5680     cpu_level = 2; // 68020
5681     else if (CPUType == 1)
5682     cpu_level = 1;
5683     }
5684     struct cputbl *nfctbl = (
5685     cpu_level == 4 ? op_smalltbl_0_nf
5686     : cpu_level == 3 ? op_smalltbl_1_nf
5687     : cpu_level == 2 ? op_smalltbl_2_nf
5688     : cpu_level == 1 ? op_smalltbl_3_nf
5689     : op_smalltbl_4_nf);
5690    
5691     write_log ("<JIT compiler> : building compiler function tables\n");
5692    
5693     for (opcode = 0; opcode < 65536; opcode++) {
5694     nfcpufunctbl[opcode] = op_illg_1;
5695     compfunctbl[opcode] = NULL;
5696     nfcompfunctbl[opcode] = NULL;
5697     prop[opcode].use_flags = 0x1f;
5698     prop[opcode].set_flags = 0x1f;
5699     prop[opcode].cflow = fl_trap; // ILLEGAL instructions do trap
5700     }
5701    
5702 gbeauche 1.8 #define IS_CONST_JUMP(opc) \
5703     ( ((table68k[opc].mnemo == i_Bcc) && (table68k[opc].cc < 2)) \
5704     || (table68k[opc].mnemo == i_BSR) \
5705     )
5706    
5707 gbeauche 1.1 for (i = 0; tbl[i].opcode < 65536; i++) {
5708     int cflow = table68k[tbl[i].opcode].cflow;
5709 gbeauche 1.8 if (USE_INLINING && IS_CONST_JUMP(tbl[i].opcode))
5710     prop[cft_map(tbl[i].opcode)].cflow = fl_const_jump;
5711     else
5712     prop[cft_map(tbl[i].opcode)].cflow = cflow;
5713 gbeauche 1.1
5714     int uses_fpu = tbl[i].specific & 32;
5715     if (uses_fpu && avoid_fpu)
5716     compfunctbl[cft_map(tbl[i].opcode)] = NULL;
5717     else
5718     compfunctbl[cft_map(tbl[i].opcode)] = tbl[i].handler;
5719     }
5720    
5721 gbeauche 1.8 #undef IS_CONST_JUMP
5722    
5723 gbeauche 1.1 for (i = 0; nftbl[i].opcode < 65536; i++) {
5724     int uses_fpu = tbl[i].specific & 32;
5725     if (uses_fpu && avoid_fpu)
5726     nfcompfunctbl[cft_map(nftbl[i].opcode)] = NULL;
5727     else
5728     nfcompfunctbl[cft_map(nftbl[i].opcode)] = nftbl[i].handler;
5729    
5730     nfcpufunctbl[cft_map(nftbl[i].opcode)] = nfctbl[i].handler;
5731     }
5732    
5733     for (i = 0; nfctbl[i].handler; i++) {
5734     nfcpufunctbl[cft_map(nfctbl[i].opcode)] = nfctbl[i].handler;
5735     }
5736    
5737     for (opcode = 0; opcode < 65536; opcode++) {
5738     compop_func *f;
5739     compop_func *nff;
5740     cpuop_func *nfcf;
5741     int isaddx,cflow;
5742    
5743     if (table68k[opcode].mnemo == i_ILLG || table68k[opcode].clev > cpu_level)
5744     continue;
5745    
5746     if (table68k[opcode].handler != -1) {
5747     f = compfunctbl[cft_map(table68k[opcode].handler)];
5748     nff = nfcompfunctbl[cft_map(table68k[opcode].handler)];
5749     nfcf = nfcpufunctbl[cft_map(table68k[opcode].handler)];
5750     cflow = prop[cft_map(table68k[opcode].handler)].cflow;
5751     isaddx = prop[cft_map(table68k[opcode].handler)].is_addx;
5752     prop[cft_map(opcode)].cflow = cflow;
5753     prop[cft_map(opcode)].is_addx = isaddx;
5754     compfunctbl[cft_map(opcode)] = f;
5755     nfcompfunctbl[cft_map(opcode)] = nff;
5756     Dif (nfcf == op_illg_1)
5757     abort();
5758     nfcpufunctbl[cft_map(opcode)] = nfcf;
5759     }
5760     prop[cft_map(opcode)].set_flags = table68k[opcode].flagdead;
5761     prop[cft_map(opcode)].use_flags = table68k[opcode].flaglive;
5762     }
5763     for (i = 0; nfctbl[i].handler != NULL; i++) {
5764     if (nfctbl[i].specific)
5765     nfcpufunctbl[cft_map(tbl[i].opcode)] = nfctbl[i].handler;
5766     }
5767    
5768     count=0;
5769     for (opcode = 0; opcode < 65536; opcode++) {
5770     if (compfunctbl[cft_map(opcode)])
5771     count++;
5772     }
5773     write_log("<JIT compiler> : supposedly %d compileable opcodes!\n",count);
5774    
5775     /* Initialise state */
5776     create_popalls();
5777     alloc_cache();
5778     reset_lists();
5779    
5780     for (i=0;i<TAGSIZE;i+=2) {
5781     cache_tags[i].handler=(cpuop_func *)popall_execute_normal;
5782     cache_tags[i+1].bi=NULL;
5783     }
5784    
5785     #if 0
5786     for (i=0;i<N_REGS;i++) {
5787     empty_ss.nat[i].holds=-1;
5788     empty_ss.nat[i].validsize=0;
5789     empty_ss.nat[i].dirtysize=0;
5790     }
5791     #endif
5792     for (i=0;i<VREGS;i++) {
5793     empty_ss.virt[i]=L_NEEDED;
5794     }
5795     for (i=0;i<N_REGS;i++) {
5796     empty_ss.nat[i]=L_UNKNOWN;
5797     }
5798     default_ss=empty_ss;
5799     }
5800    
5801    
5802     static void flush_icache_none(int n)
5803     {
5804     /* Nothing to do. */
5805     }
5806    
5807     static void flush_icache_hard(int n)
5808     {
5809     uae_u32 i;
5810     blockinfo* bi, *dbi;
5811    
5812     hard_flush_count++;
5813     #if 0
5814     write_log("Flush Icache_hard(%d/%x/%p), %u KB\n",
5815     n,regs.pc,regs.pc_p,current_cache_size/1024);
5816     current_cache_size = 0;
5817     #endif
5818     bi=active;
5819     while(bi) {
5820     cache_tags[cacheline(bi->pc_p)].handler=(cpuop_func *)popall_execute_normal;
5821     cache_tags[cacheline(bi->pc_p)+1].bi=NULL;
5822     dbi=bi; bi=bi->next;
5823     free_blockinfo(dbi);
5824     }
5825     bi=dormant;
5826     while(bi) {
5827     cache_tags[cacheline(bi->pc_p)].handler=(cpuop_func *)popall_execute_normal;
5828     cache_tags[cacheline(bi->pc_p)+1].bi=NULL;
5829     dbi=bi; bi=bi->next;
5830     free_blockinfo(dbi);
5831     }
5832    
5833     reset_lists();
5834     if (!compiled_code)
5835     return;
5836     current_compile_p=compiled_code;
5837     SPCFLAGS_SET( SPCFLAG_JIT_EXEC_RETURN ); /* To get out of compiled code */
5838     }
5839    
5840    
5841     /* "Soft flushing" --- instead of actually throwing everything away,
5842     we simply mark everything as "needs to be checked".
5843     */
5844    
5845     static inline void flush_icache_lazy(int n)
5846     {
5847     uae_u32 i;
5848     blockinfo* bi;
5849     blockinfo* bi2;
5850    
5851     soft_flush_count++;
5852     if (!active)
5853     return;
5854    
5855     bi=active;
5856     while (bi) {
5857     uae_u32 cl=cacheline(bi->pc_p);
5858     if (bi->status==BI_INVALID ||
5859     bi->status==BI_NEED_RECOMP) {
5860     if (bi==cache_tags[cl+1].bi)
5861     cache_tags[cl].handler=(cpuop_func *)popall_execute_normal;
5862     bi->handler_to_use=(cpuop_func *)popall_execute_normal;
5863     set_dhtu(bi,bi->direct_pen);
5864     bi->status=BI_INVALID;
5865     }
5866     else {
5867     if (bi==cache_tags[cl+1].bi)
5868     cache_tags[cl].handler=(cpuop_func *)popall_check_checksum;
5869     bi->handler_to_use=(cpuop_func *)popall_check_checksum;
5870     set_dhtu(bi,bi->direct_pcc);
5871     bi->status=BI_NEED_CHECK;
5872     }
5873     bi2=bi;
5874     bi=bi->next;
5875     }
5876     /* bi2 is now the last entry in the active list */
5877     bi2->next=dormant;
5878     if (dormant)
5879     dormant->prev_p=&(bi2->next);
5880    
5881     dormant=active;
5882     active->prev_p=&dormant;
5883     active=NULL;
5884     }
5885    
5886     static void catastrophe(void)
5887     {
5888     abort();
5889     }
5890    
5891     int failure;
5892    
5893     #define TARGET_M68K 0
5894     #define TARGET_POWERPC 1
5895     #define TARGET_X86 2
5896     #if defined(i386) || defined(__i386__)
5897     #define TARGET_NATIVE TARGET_X86
5898     #endif
5899     #if defined(powerpc) || defined(__powerpc__)
5900     #define TARGET_NATIVE TARGET_POWERPC
5901     #endif
5902    
5903     #ifdef ENABLE_MON
5904     static uae_u32 mon_read_byte_jit(uae_u32 addr)
5905     {
5906     uae_u8 *m = (uae_u8 *)addr;
5907     return (uae_u32)(*m);
5908     }
5909    
5910     static void mon_write_byte_jit(uae_u32 addr, uae_u32 b)
5911     {
5912     uae_u8 *m = (uae_u8 *)addr;
5913     *m = b;
5914     }
5915     #endif
5916    
5917     void disasm_block(int target, uint8 * start, size_t length)
5918     {
5919     if (!JITDebug)
5920     return;
5921    
5922     #if defined(JIT_DEBUG) && defined(ENABLE_MON)
5923     char disasm_str[200];
5924     sprintf(disasm_str, "%s $%x $%x",
5925     target == TARGET_M68K ? "d68" :
5926     target == TARGET_X86 ? "d86" :
5927     target == TARGET_POWERPC ? "d" : "x",
5928     start, start + length - 1);
5929    
5930     uae_u32 (*old_mon_read_byte)(uae_u32) = mon_read_byte;
5931     void (*old_mon_write_byte)(uae_u32, uae_u32) = mon_write_byte;
5932    
5933     mon_read_byte = mon_read_byte_jit;
5934     mon_write_byte = mon_write_byte_jit;
5935    
5936     char *arg[5] = {"mon", "-m", "-r", disasm_str, NULL};
5937     mon(4, arg);
5938    
5939     mon_read_byte = old_mon_read_byte;
5940     mon_write_byte = old_mon_write_byte;
5941     #endif
5942     }
5943    
5944     static inline void disasm_native_block(uint8 *start, size_t length)
5945     {
5946     disasm_block(TARGET_NATIVE, start, length);
5947     }
5948    
5949     static inline void disasm_m68k_block(uint8 *start, size_t length)
5950     {
5951     disasm_block(TARGET_M68K, start, length);
5952     }
5953    
5954     #ifdef HAVE_GET_WORD_UNSWAPPED
5955     # define DO_GET_OPCODE(a) (do_get_mem_word_unswapped((uae_u16 *)(a)))
5956     #else
5957     # define DO_GET_OPCODE(a) (do_get_mem_word((uae_u16 *)(a)))
5958     #endif
5959    
5960     #if JIT_DEBUG
5961     static uae_u8 *last_regs_pc_p = 0;
5962     static uae_u8 *last_compiled_block_addr = 0;
5963    
5964     void compiler_dumpstate(void)
5965     {
5966     if (!JITDebug)
5967     return;
5968    
5969     write_log("### Host addresses\n");
5970     write_log("MEM_BASE : %x\n", MEMBaseDiff);
5971     write_log("PC_P : %p\n", &regs.pc_p);
5972     write_log("SPCFLAGS : %p\n", &regs.spcflags);
5973     write_log("D0-D7 : %p-%p\n", &regs.regs[0], &regs.regs[7]);
5974     write_log("A0-A7 : %p-%p\n", &regs.regs[8], &regs.regs[15]);
5975     write_log("\n");
5976    
5977     write_log("### M68k processor state\n");
5978     m68k_dumpstate(0);
5979     write_log("\n");
5980    
5981     write_log("### Block in Mac address space\n");
5982     write_log("M68K block : %p\n",
5983     (void *)get_virtual_address(last_regs_pc_p));
5984     write_log("Native block : %p (%d bytes)\n",
5985     (void *)get_virtual_address(last_compiled_block_addr),
5986     get_blockinfo_addr(last_regs_pc_p)->direct_handler_size);
5987     write_log("\n");
5988     }
5989     #endif
5990    
5991     static void compile_block(cpu_history* pc_hist, int blocklen)
5992     {
5993     if (letit && compiled_code) {
5994     #if PROFILE_COMPILE_TIME
5995     compile_count++;
5996     clock_t start_time = clock();
5997     #endif
5998     #if JIT_DEBUG
5999     bool disasm_block = false;
6000     #endif
6001    
6002     /* OK, here we need to 'compile' a block */
6003     int i;
6004     int r;
6005     int was_comp=0;
6006     uae_u8 liveflags[MAXRUN+1];
6007 gbeauche 1.8 #if USE_CHECKSUM_INFO
6008     bool trace_in_rom = isinrom((uintptr)pc_hist[0].location);
6009     uae_u32 max_pcp=(uae_u32)pc_hist[blocklen - 1].location;
6010     uae_u32 min_pcp=max_pcp;
6011     #else
6012 gbeauche 1.1 uae_u32 max_pcp=(uae_u32)pc_hist[0].location;
6013     uae_u32 min_pcp=max_pcp;
6014 gbeauche 1.8 #endif
6015 gbeauche 1.1 uae_u32 cl=cacheline(pc_hist[0].location);
6016     void* specflags=(void*)&regs.spcflags;
6017     blockinfo* bi=NULL;
6018     blockinfo* bi2;
6019     int extra_len=0;
6020    
6021     redo_current_block=0;
6022     if (current_compile_p>=max_compile_start)
6023     flush_icache_hard(7);
6024    
6025     alloc_blockinfos();
6026    
6027     bi=get_blockinfo_addr_new(pc_hist[0].location,0);
6028     bi2=get_blockinfo(cl);
6029    
6030     optlev=bi->optlevel;
6031     if (bi->status!=BI_INVALID) {
6032     Dif (bi!=bi2) {
6033     /* I don't think it can happen anymore. Shouldn't, in
6034     any case. So let's make sure... */
6035     write_log("WOOOWOO count=%d, ol=%d %p %p\n",
6036     bi->count,bi->optlevel,bi->handler_to_use,
6037     cache_tags[cl].handler);
6038     abort();
6039     }
6040    
6041     Dif (bi->count!=-1 && bi->status!=BI_NEED_RECOMP) {
6042     write_log("bi->count=%d, bi->status=%d\n",bi->count,bi->status);
6043     /* What the heck? We are not supposed to be here! */
6044     abort();
6045     }
6046     }
6047     if (bi->count==-1) {
6048     optlev++;
6049     while (!optcount[optlev])
6050     optlev++;
6051     bi->count=optcount[optlev]-1;
6052     }
6053     current_block_pc_p=(uae_u32)pc_hist[0].location;
6054    
6055     remove_deps(bi); /* We are about to create new code */
6056     bi->optlevel=optlev;
6057     bi->pc_p=(uae_u8*)pc_hist[0].location;
6058 gbeauche 1.8 #if USE_CHECKSUM_INFO
6059     free_checksum_info_chain(bi->csi);
6060     bi->csi = NULL;
6061     #endif
6062 gbeauche 1.1
6063     liveflags[blocklen]=0x1f; /* All flags needed afterwards */
6064     i=blocklen;
6065     while (i--) {
6066     uae_u16* currpcp=pc_hist[i].location;
6067     uae_u32 op=DO_GET_OPCODE(currpcp);
6068    
6069 gbeauche 1.8 #if USE_CHECKSUM_INFO
6070     trace_in_rom = trace_in_rom && isinrom((uintptr)currpcp);
6071     #if USE_INLINING
6072     if (is_const_jump(op)) {
6073     checksum_info *csi = alloc_checksum_info();
6074     csi->start_p = (uae_u8 *)min_pcp;
6075     csi->length = max_pcp - min_pcp + LONGEST_68K_INST;
6076     csi->next = bi->csi;
6077     bi->csi = csi;
6078     max_pcp = (uae_u32)currpcp;
6079     }
6080     #endif
6081     min_pcp = (uae_u32)currpcp;
6082     #else
6083 gbeauche 1.1 if ((uae_u32)currpcp<min_pcp)
6084     min_pcp=(uae_u32)currpcp;
6085     if ((uae_u32)currpcp>max_pcp)
6086     max_pcp=(uae_u32)currpcp;
6087 gbeauche 1.8 #endif
6088 gbeauche 1.1
6089     liveflags[i]=((liveflags[i+1]&
6090     (~prop[op].set_flags))|
6091     prop[op].use_flags);
6092     if (prop[op].is_addx && (liveflags[i+1]&FLAG_Z)==0)
6093     liveflags[i]&= ~FLAG_Z;
6094     }
6095    
6096 gbeauche 1.8 #if USE_CHECKSUM_INFO
6097     checksum_info *csi = alloc_checksum_info();
6098     csi->start_p = (uae_u8 *)min_pcp;
6099     csi->length = max_pcp - min_pcp + LONGEST_68K_INST;
6100     csi->next = bi->csi;
6101     bi->csi = csi;
6102     #endif
6103    
6104 gbeauche 1.1 bi->needed_flags=liveflags[0];
6105    
6106 gbeauche 1.5 align_target(align_loops);
6107 gbeauche 1.1 was_comp=0;
6108    
6109     bi->direct_handler=(cpuop_func *)get_target();
6110     set_dhtu(bi,bi->direct_handler);
6111     bi->status=BI_COMPILING;
6112     current_block_start_target=(uae_u32)get_target();
6113    
6114     log_startblock();
6115    
6116     if (bi->count>=0) { /* Need to generate countdown code */
6117     raw_mov_l_mi((uae_u32)&regs.pc_p,(uae_u32)pc_hist[0].location);
6118     raw_sub_l_mi((uae_u32)&(bi->count),1);
6119     raw_jl((uae_u32)popall_recompile_block);
6120     }
6121     if (optlev==0) { /* No need to actually translate */
6122     /* Execute normally without keeping stats */
6123     raw_mov_l_mi((uae_u32)&regs.pc_p,(uae_u32)pc_hist[0].location);
6124     raw_jmp((uae_u32)popall_exec_nostats);
6125     }
6126     else {
6127     reg_alloc_run=0;
6128     next_pc_p=0;
6129     taken_pc_p=0;
6130     branch_cc=0;
6131    
6132     comp_pc_p=(uae_u8*)pc_hist[0].location;
6133     init_comp();
6134     was_comp=1;
6135    
6136     #if JIT_DEBUG
6137     if (JITDebug) {
6138     raw_mov_l_mi((uae_u32)&last_regs_pc_p,(uae_u32)pc_hist[0].location);
6139     raw_mov_l_mi((uae_u32)&last_compiled_block_addr,(uae_u32)current_block_start_target);
6140     }
6141     #endif
6142    
6143     for (i=0;i<blocklen &&
6144     get_target_noopt()<max_compile_start;i++) {
6145     cpuop_func **cputbl;
6146     compop_func **comptbl;
6147     uae_u32 opcode=DO_GET_OPCODE(pc_hist[i].location);
6148     needed_flags=(liveflags[i+1] & prop[opcode].set_flags);
6149     if (!needed_flags) {
6150     cputbl=nfcpufunctbl;
6151     comptbl=nfcompfunctbl;
6152     }
6153     else {
6154     cputbl=cpufunctbl;
6155     comptbl=compfunctbl;
6156     }
6157    
6158     failure = 1; // gb-- defaults to failure state
6159     if (comptbl[opcode] && optlev>1) {
6160     failure=0;
6161     if (!was_comp) {
6162     comp_pc_p=(uae_u8*)pc_hist[i].location;
6163     init_comp();
6164     }
6165     was_comp++;
6166    
6167     comptbl[opcode](opcode);
6168     freescratch();
6169     if (!(liveflags[i+1] & FLAG_CZNV)) {
6170     /* We can forget about flags */
6171     dont_care_flags();
6172     }
6173     #if INDIVIDUAL_INST
6174     flush(1);
6175     nop();
6176     flush(1);
6177     was_comp=0;
6178     #endif
6179     }
6180    
6181     if (failure) {
6182     if (was_comp) {
6183     flush(1);
6184     was_comp=0;
6185     }
6186     raw_mov_l_ri(REG_PAR1,(uae_u32)opcode);
6187     #if USE_NORMAL_CALLING_CONVENTION
6188     raw_push_l_r(REG_PAR1);
6189     #endif
6190     raw_mov_l_mi((uae_u32)&regs.pc_p,
6191     (uae_u32)pc_hist[i].location);
6192     raw_call((uae_u32)cputbl[opcode]);
6193 gbeauche 1.9 #if PROFILE_UNTRANSLATED_INSNS
6194     // raw_cputbl_count[] is indexed with plain opcode (in m68k order)
6195     raw_add_l_mi((uae_u32)&raw_cputbl_count[cft_map(opcode)],1);
6196     #endif
6197 gbeauche 1.1 //raw_add_l_mi((uae_u32)&oink,1); // FIXME
6198     #if USE_NORMAL_CALLING_CONVENTION
6199     raw_inc_sp(4);
6200     #endif
6201     if (needed_flags) {
6202     //raw_mov_l_mi((uae_u32)&foink3,(uae_u32)opcode+65536);
6203     }
6204     else {
6205     //raw_mov_l_mi((uae_u32)&foink3,(uae_u32)opcode);
6206     }
6207    
6208     if (i < blocklen - 1) {
6209     uae_s8* branchadd;
6210    
6211     raw_mov_l_rm(0,(uae_u32)specflags);
6212     raw_test_l_rr(0,0);
6213     raw_jz_b_oponly();
6214     branchadd=(uae_s8 *)get_target();
6215     emit_byte(0);
6216     raw_jmp((uae_u32)popall_do_nothing);
6217     *branchadd=(uae_u32)get_target()-(uae_u32)branchadd-1;
6218     }
6219     }
6220     }
6221     #if 1 /* This isn't completely kosher yet; It really needs to be
6222     be integrated into a general inter-block-dependency scheme */
6223     if (next_pc_p && taken_pc_p &&
6224     was_comp && taken_pc_p==current_block_pc_p) {
6225     blockinfo* bi1=get_blockinfo_addr_new((void*)next_pc_p,0);
6226     blockinfo* bi2=get_blockinfo_addr_new((void*)taken_pc_p,0);
6227     uae_u8 x=bi1->needed_flags;
6228    
6229     if (x==0xff || 1) { /* To be on the safe side */
6230     uae_u16* next=(uae_u16*)next_pc_p;
6231     uae_u32 op=DO_GET_OPCODE(next);
6232    
6233     x=0x1f;
6234     x&=(~prop[op].set_flags);
6235     x|=prop[op].use_flags;
6236     }
6237    
6238     x|=bi2->needed_flags;
6239     if (!(x & FLAG_CZNV)) {
6240     /* We can forget about flags */
6241     dont_care_flags();
6242     extra_len+=2; /* The next instruction now is part of this
6243     block */
6244     }
6245    
6246     }
6247     #endif
6248     log_flush();
6249    
6250     if (next_pc_p) { /* A branch was registered */
6251     uae_u32 t1=next_pc_p;
6252     uae_u32 t2=taken_pc_p;
6253     int cc=branch_cc;
6254    
6255     uae_u32* branchadd;
6256     uae_u32* tba;
6257     bigstate tmp;
6258     blockinfo* tbi;
6259    
6260     if (taken_pc_p<next_pc_p) {
6261     /* backward branch. Optimize for the "taken" case ---
6262     which means the raw_jcc should fall through when
6263     the 68k branch is taken. */
6264     t1=taken_pc_p;
6265     t2=next_pc_p;
6266     cc=branch_cc^1;
6267     }
6268    
6269     tmp=live; /* ouch! This is big... */
6270     raw_jcc_l_oponly(cc);
6271     branchadd=(uae_u32*)get_target();
6272     emit_long(0);
6273    
6274     /* predicted outcome */
6275     tbi=get_blockinfo_addr_new((void*)t1,1);
6276     match_states(tbi);
6277     raw_cmp_l_mi((uae_u32)specflags,0);
6278     raw_jcc_l_oponly(4);
6279     tba=(uae_u32*)get_target();
6280     emit_long(get_handler(t1)-((uae_u32)tba+4));
6281     raw_mov_l_mi((uae_u32)&regs.pc_p,t1);
6282     raw_jmp((uae_u32)popall_do_nothing);
6283     create_jmpdep(bi,0,tba,t1);
6284    
6285 gbeauche 1.5 align_target(align_jumps);
6286 gbeauche 1.1 /* not-predicted outcome */
6287     *branchadd=(uae_u32)get_target()-((uae_u32)branchadd+4);
6288     live=tmp; /* Ouch again */
6289     tbi=get_blockinfo_addr_new((void*)t2,1);
6290     match_states(tbi);
6291    
6292     //flush(1); /* Can only get here if was_comp==1 */
6293     raw_cmp_l_mi((uae_u32)specflags,0);
6294     raw_jcc_l_oponly(4);
6295     tba=(uae_u32*)get_target();
6296     emit_long(get_handler(t2)-((uae_u32)tba+4));
6297     raw_mov_l_mi((uae_u32)&regs.pc_p,t2);
6298     raw_jmp((uae_u32)popall_do_nothing);
6299     create_jmpdep(bi,1,tba,t2);
6300     }
6301     else
6302     {
6303     if (was_comp) {
6304     flush(1);
6305     }
6306    
6307     /* Let's find out where next_handler is... */
6308     if (was_comp && isinreg(PC_P)) {
6309     r=live.state[PC_P].realreg;
6310     raw_and_l_ri(r,TAGMASK);
6311     int r2 = (r==0) ? 1 : 0;
6312     raw_mov_l_ri(r2,(uae_u32)popall_do_nothing);
6313     raw_cmp_l_mi((uae_u32)specflags,0);
6314     raw_cmov_l_rm_indexed(r2,(uae_u32)cache_tags,r,4,4);
6315     raw_jmp_r(r2);
6316     }
6317     else if (was_comp && isconst(PC_P)) {
6318     uae_u32 v=live.state[PC_P].val;
6319     uae_u32* tba;
6320     blockinfo* tbi;
6321    
6322     tbi=get_blockinfo_addr_new((void*)v,1);
6323     match_states(tbi);
6324    
6325     raw_cmp_l_mi((uae_u32)specflags,0);
6326     raw_jcc_l_oponly(4);
6327     tba=(uae_u32*)get_target();
6328     emit_long(get_handler(v)-((uae_u32)tba+4));
6329     raw_mov_l_mi((uae_u32)&regs.pc_p,v);
6330     raw_jmp((uae_u32)popall_do_nothing);
6331     create_jmpdep(bi,0,tba,v);
6332     }
6333     else {
6334     r=REG_PC_TMP;
6335     raw_mov_l_rm(r,(uae_u32)&regs.pc_p);
6336     raw_and_l_ri(r,TAGMASK);
6337     int r2 = (r==0) ? 1 : 0;
6338     raw_mov_l_ri(r2,(uae_u32)popall_do_nothing);
6339     raw_cmp_l_mi((uae_u32)specflags,0);
6340     raw_cmov_l_rm_indexed(r2,(uae_u32)cache_tags,r,4,4);
6341     raw_jmp_r(r2);
6342     }
6343     }
6344     }
6345    
6346     #if USE_MATCH
6347     if (callers_need_recompile(&live,&(bi->env))) {
6348     mark_callers_recompile(bi);
6349     }
6350    
6351     big_to_small_state(&live,&(bi->env));
6352     #endif
6353    
6354 gbeauche 1.8 #if USE_CHECKSUM_INFO
6355     remove_from_list(bi);
6356     if (trace_in_rom) {
6357     // No need to checksum that block trace on cache invalidation
6358     free_checksum_info_chain(bi->csi);
6359     bi->csi = NULL;
6360     add_to_dormant(bi);
6361     }
6362     else {
6363     calc_checksum(bi,&(bi->c1),&(bi->c2));
6364     add_to_active(bi);
6365     }
6366     #else
6367 gbeauche 1.1 if (next_pc_p+extra_len>=max_pcp &&
6368     next_pc_p+extra_len<max_pcp+LONGEST_68K_INST)
6369     max_pcp=next_pc_p+extra_len; /* extra_len covers flags magic */
6370     else
6371     max_pcp+=LONGEST_68K_INST;
6372 gbeauche 1.7
6373 gbeauche 1.1 bi->len=max_pcp-min_pcp;
6374     bi->min_pcp=min_pcp;
6375 gbeauche 1.7
6376 gbeauche 1.1 remove_from_list(bi);
6377     if (isinrom(min_pcp) && isinrom(max_pcp)) {
6378     add_to_dormant(bi); /* No need to checksum it on cache flush.
6379     Please don't start changing ROMs in
6380     flight! */
6381     }
6382     else {
6383     calc_checksum(bi,&(bi->c1),&(bi->c2));
6384     add_to_active(bi);
6385     }
6386 gbeauche 1.8 #endif
6387 gbeauche 1.1
6388     current_cache_size += get_target() - (uae_u8 *)current_compile_p;
6389    
6390     #if JIT_DEBUG
6391     if (JITDebug)
6392     bi->direct_handler_size = get_target() - (uae_u8 *)current_block_start_target;
6393    
6394     if (JITDebug && disasm_block) {
6395     uaecptr block_addr = start_pc + ((char *)pc_hist[0].location - (char *)start_pc_p);
6396     D(bug("M68K block @ 0x%08x (%d insns)\n", block_addr, blocklen));
6397     uae_u32 block_size = ((uae_u8 *)pc_hist[blocklen - 1].location - (uae_u8 *)pc_hist[0].location) + 1;
6398     disasm_m68k_block((uae_u8 *)pc_hist[0].location, block_size);
6399     D(bug("Compiled block @ 0x%08x\n", pc_hist[0].location));
6400     disasm_native_block((uae_u8 *)current_block_start_target, bi->direct_handler_size);
6401     getchar();
6402     }
6403     #endif
6404    
6405     log_dump();
6406 gbeauche 1.5 align_target(align_jumps);
6407 gbeauche 1.1
6408     /* This is the non-direct handler */
6409     bi->handler=
6410     bi->handler_to_use=(cpuop_func *)get_target();
6411     raw_cmp_l_mi((uae_u32)&regs.pc_p,(uae_u32)pc_hist[0].location);
6412     raw_jnz((uae_u32)popall_cache_miss);
6413     comp_pc_p=(uae_u8*)pc_hist[0].location;
6414    
6415     bi->status=BI_FINALIZING;
6416     init_comp();
6417     match_states(bi);
6418     flush(1);
6419    
6420     raw_jmp((uae_u32)bi->direct_handler);
6421    
6422     current_compile_p=get_target();
6423     raise_in_cl_list(bi);
6424    
6425     /* We will flush soon, anyway, so let's do it now */
6426     if (current_compile_p>=max_compile_start)
6427     flush_icache_hard(7);
6428    
6429     bi->status=BI_ACTIVE;
6430     if (redo_current_block)
6431     block_need_recompile(bi);
6432    
6433     #if PROFILE_COMPILE_TIME
6434     compile_time += (clock() - start_time);
6435     #endif
6436     }
6437     }
6438    
6439     void do_nothing(void)
6440     {
6441     /* What did you expect this to do? */
6442     }
6443    
6444     void exec_nostats(void)
6445     {
6446     for (;;) {
6447     uae_u32 opcode = GET_OPCODE;
6448     (*cpufunctbl[opcode])(opcode);
6449     if (end_block(opcode) || SPCFLAGS_TEST(SPCFLAG_ALL)) {
6450     return; /* We will deal with the spcflags in the caller */
6451     }
6452     }
6453     }
6454    
6455     void execute_normal(void)
6456     {
6457     if (!check_for_cache_miss()) {
6458     cpu_history pc_hist[MAXRUN];
6459     int blocklen = 0;
6460     #if REAL_ADDRESSING || DIRECT_ADDRESSING
6461     start_pc_p = regs.pc_p;
6462     start_pc = get_virtual_address(regs.pc_p);
6463     #else
6464     start_pc_p = regs.pc_oldp;
6465     start_pc = regs.pc;
6466     #endif
6467     for (;;) { /* Take note: This is the do-it-normal loop */
6468     pc_hist[blocklen++].location = (uae_u16 *)regs.pc_p;
6469     uae_u32 opcode = GET_OPCODE;
6470     #if FLIGHT_RECORDER
6471     m68k_record_step(m68k_getpc());
6472     #endif
6473     (*cpufunctbl[opcode])(opcode);
6474     if (end_block(opcode) || SPCFLAGS_TEST(SPCFLAG_ALL) || blocklen>=MAXRUN) {
6475     compile_block(pc_hist, blocklen);
6476     return; /* We will deal with the spcflags in the caller */
6477     }
6478     /* No need to check regs.spcflags, because if they were set,
6479     we'd have ended up inside that "if" */
6480     }
6481     }
6482     }
6483    
6484     typedef void (*compiled_handler)(void);
6485    
6486 gbeauche 1.6 #ifdef X86_ASSEMBLY
6487     void (*m68k_compile_execute)(void) = NULL;
6488     #else
6489 gbeauche 1.1 void m68k_do_compile_execute(void)
6490     {
6491     for (;;) {
6492     ((compiled_handler)(pushall_call_handler))();
6493     /* Whenever we return from that, we should check spcflags */
6494     if (SPCFLAGS_TEST(SPCFLAG_ALL)) {
6495     if (m68k_do_specialties ())
6496     return;
6497     }
6498     }
6499     }
6500 gbeauche 1.6 #endif