ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/compiler/compemu_support.cpp
Revision: 1.10
Committed: 2002-10-03T15:05:01Z (21 years, 11 months ago) by gbeauche
Branch: MAIN
Changes since 1.9: +5 -11 lines
Log Message:
- Turn on runtime detection of loop and jump alignment as Aranym people
  reported they got some improvement with it and larger loops. Small
  loops are an issue for now until unrolling is implemented for DBcc.
- Const jumps are identified in readcpu. I don't want to duplicate code
  uselessly. Rather, it's the JIT job to know whether we are doing block
  inlining and un-marking those instructions as end-of-block.

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.10 static bool tune_alignment = true; // Tune code alignments for running CPU ?
107 gbeauche 1.5 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     for (i = 0; tbl[i].opcode < 65536; i++) {
5703     int cflow = table68k[tbl[i].opcode].cflow;
5704 gbeauche 1.10 if (USE_INLINING && ((cflow & fl_const_jump) != 0))
5705     cflow = fl_const_jump;
5706 gbeauche 1.8 else
5707 gbeauche 1.10 cflow &= ~fl_const_jump;
5708     prop[cft_map(tbl[i].opcode)].cflow = cflow;
5709 gbeauche 1.1
5710     int uses_fpu = tbl[i].specific & 32;
5711     if (uses_fpu && avoid_fpu)
5712     compfunctbl[cft_map(tbl[i].opcode)] = NULL;
5713     else
5714     compfunctbl[cft_map(tbl[i].opcode)] = tbl[i].handler;
5715     }
5716 gbeauche 1.8
5717 gbeauche 1.1 for (i = 0; nftbl[i].opcode < 65536; i++) {
5718     int uses_fpu = tbl[i].specific & 32;
5719     if (uses_fpu && avoid_fpu)
5720     nfcompfunctbl[cft_map(nftbl[i].opcode)] = NULL;
5721     else
5722     nfcompfunctbl[cft_map(nftbl[i].opcode)] = nftbl[i].handler;
5723    
5724     nfcpufunctbl[cft_map(nftbl[i].opcode)] = nfctbl[i].handler;
5725     }
5726    
5727     for (i = 0; nfctbl[i].handler; i++) {
5728     nfcpufunctbl[cft_map(nfctbl[i].opcode)] = nfctbl[i].handler;
5729     }
5730    
5731     for (opcode = 0; opcode < 65536; opcode++) {
5732     compop_func *f;
5733     compop_func *nff;
5734     cpuop_func *nfcf;
5735     int isaddx,cflow;
5736    
5737     if (table68k[opcode].mnemo == i_ILLG || table68k[opcode].clev > cpu_level)
5738     continue;
5739    
5740     if (table68k[opcode].handler != -1) {
5741     f = compfunctbl[cft_map(table68k[opcode].handler)];
5742     nff = nfcompfunctbl[cft_map(table68k[opcode].handler)];
5743     nfcf = nfcpufunctbl[cft_map(table68k[opcode].handler)];
5744     cflow = prop[cft_map(table68k[opcode].handler)].cflow;
5745     isaddx = prop[cft_map(table68k[opcode].handler)].is_addx;
5746     prop[cft_map(opcode)].cflow = cflow;
5747     prop[cft_map(opcode)].is_addx = isaddx;
5748     compfunctbl[cft_map(opcode)] = f;
5749     nfcompfunctbl[cft_map(opcode)] = nff;
5750     Dif (nfcf == op_illg_1)
5751     abort();
5752     nfcpufunctbl[cft_map(opcode)] = nfcf;
5753     }
5754     prop[cft_map(opcode)].set_flags = table68k[opcode].flagdead;
5755     prop[cft_map(opcode)].use_flags = table68k[opcode].flaglive;
5756     }
5757     for (i = 0; nfctbl[i].handler != NULL; i++) {
5758     if (nfctbl[i].specific)
5759     nfcpufunctbl[cft_map(tbl[i].opcode)] = nfctbl[i].handler;
5760     }
5761    
5762     count=0;
5763     for (opcode = 0; opcode < 65536; opcode++) {
5764     if (compfunctbl[cft_map(opcode)])
5765     count++;
5766     }
5767     write_log("<JIT compiler> : supposedly %d compileable opcodes!\n",count);
5768    
5769     /* Initialise state */
5770     create_popalls();
5771     alloc_cache();
5772     reset_lists();
5773    
5774     for (i=0;i<TAGSIZE;i+=2) {
5775     cache_tags[i].handler=(cpuop_func *)popall_execute_normal;
5776     cache_tags[i+1].bi=NULL;
5777     }
5778    
5779     #if 0
5780     for (i=0;i<N_REGS;i++) {
5781     empty_ss.nat[i].holds=-1;
5782     empty_ss.nat[i].validsize=0;
5783     empty_ss.nat[i].dirtysize=0;
5784     }
5785     #endif
5786     for (i=0;i<VREGS;i++) {
5787     empty_ss.virt[i]=L_NEEDED;
5788     }
5789     for (i=0;i<N_REGS;i++) {
5790     empty_ss.nat[i]=L_UNKNOWN;
5791     }
5792     default_ss=empty_ss;
5793     }
5794    
5795    
5796     static void flush_icache_none(int n)
5797     {
5798     /* Nothing to do. */
5799     }
5800    
5801     static void flush_icache_hard(int n)
5802     {
5803     uae_u32 i;
5804     blockinfo* bi, *dbi;
5805    
5806     hard_flush_count++;
5807     #if 0
5808     write_log("Flush Icache_hard(%d/%x/%p), %u KB\n",
5809     n,regs.pc,regs.pc_p,current_cache_size/1024);
5810     current_cache_size = 0;
5811     #endif
5812     bi=active;
5813     while(bi) {
5814     cache_tags[cacheline(bi->pc_p)].handler=(cpuop_func *)popall_execute_normal;
5815     cache_tags[cacheline(bi->pc_p)+1].bi=NULL;
5816     dbi=bi; bi=bi->next;
5817     free_blockinfo(dbi);
5818     }
5819     bi=dormant;
5820     while(bi) {
5821     cache_tags[cacheline(bi->pc_p)].handler=(cpuop_func *)popall_execute_normal;
5822     cache_tags[cacheline(bi->pc_p)+1].bi=NULL;
5823     dbi=bi; bi=bi->next;
5824     free_blockinfo(dbi);
5825     }
5826    
5827     reset_lists();
5828     if (!compiled_code)
5829     return;
5830     current_compile_p=compiled_code;
5831     SPCFLAGS_SET( SPCFLAG_JIT_EXEC_RETURN ); /* To get out of compiled code */
5832     }
5833    
5834    
5835     /* "Soft flushing" --- instead of actually throwing everything away,
5836     we simply mark everything as "needs to be checked".
5837     */
5838    
5839     static inline void flush_icache_lazy(int n)
5840     {
5841     uae_u32 i;
5842     blockinfo* bi;
5843     blockinfo* bi2;
5844    
5845     soft_flush_count++;
5846     if (!active)
5847     return;
5848    
5849     bi=active;
5850     while (bi) {
5851     uae_u32 cl=cacheline(bi->pc_p);
5852     if (bi->status==BI_INVALID ||
5853     bi->status==BI_NEED_RECOMP) {
5854     if (bi==cache_tags[cl+1].bi)
5855     cache_tags[cl].handler=(cpuop_func *)popall_execute_normal;
5856     bi->handler_to_use=(cpuop_func *)popall_execute_normal;
5857     set_dhtu(bi,bi->direct_pen);
5858     bi->status=BI_INVALID;
5859     }
5860     else {
5861     if (bi==cache_tags[cl+1].bi)
5862     cache_tags[cl].handler=(cpuop_func *)popall_check_checksum;
5863     bi->handler_to_use=(cpuop_func *)popall_check_checksum;
5864     set_dhtu(bi,bi->direct_pcc);
5865     bi->status=BI_NEED_CHECK;
5866     }
5867     bi2=bi;
5868     bi=bi->next;
5869     }
5870     /* bi2 is now the last entry in the active list */
5871     bi2->next=dormant;
5872     if (dormant)
5873     dormant->prev_p=&(bi2->next);
5874    
5875     dormant=active;
5876     active->prev_p=&dormant;
5877     active=NULL;
5878     }
5879    
5880     static void catastrophe(void)
5881     {
5882     abort();
5883     }
5884    
5885     int failure;
5886    
5887     #define TARGET_M68K 0
5888     #define TARGET_POWERPC 1
5889     #define TARGET_X86 2
5890     #if defined(i386) || defined(__i386__)
5891     #define TARGET_NATIVE TARGET_X86
5892     #endif
5893     #if defined(powerpc) || defined(__powerpc__)
5894     #define TARGET_NATIVE TARGET_POWERPC
5895     #endif
5896    
5897     #ifdef ENABLE_MON
5898     static uae_u32 mon_read_byte_jit(uae_u32 addr)
5899     {
5900     uae_u8 *m = (uae_u8 *)addr;
5901     return (uae_u32)(*m);
5902     }
5903    
5904     static void mon_write_byte_jit(uae_u32 addr, uae_u32 b)
5905     {
5906     uae_u8 *m = (uae_u8 *)addr;
5907     *m = b;
5908     }
5909     #endif
5910    
5911     void disasm_block(int target, uint8 * start, size_t length)
5912     {
5913     if (!JITDebug)
5914     return;
5915    
5916     #if defined(JIT_DEBUG) && defined(ENABLE_MON)
5917     char disasm_str[200];
5918     sprintf(disasm_str, "%s $%x $%x",
5919     target == TARGET_M68K ? "d68" :
5920     target == TARGET_X86 ? "d86" :
5921     target == TARGET_POWERPC ? "d" : "x",
5922     start, start + length - 1);
5923    
5924     uae_u32 (*old_mon_read_byte)(uae_u32) = mon_read_byte;
5925     void (*old_mon_write_byte)(uae_u32, uae_u32) = mon_write_byte;
5926    
5927     mon_read_byte = mon_read_byte_jit;
5928     mon_write_byte = mon_write_byte_jit;
5929    
5930     char *arg[5] = {"mon", "-m", "-r", disasm_str, NULL};
5931     mon(4, arg);
5932    
5933     mon_read_byte = old_mon_read_byte;
5934     mon_write_byte = old_mon_write_byte;
5935     #endif
5936     }
5937    
5938     static inline void disasm_native_block(uint8 *start, size_t length)
5939     {
5940     disasm_block(TARGET_NATIVE, start, length);
5941     }
5942    
5943     static inline void disasm_m68k_block(uint8 *start, size_t length)
5944     {
5945     disasm_block(TARGET_M68K, start, length);
5946     }
5947    
5948     #ifdef HAVE_GET_WORD_UNSWAPPED
5949     # define DO_GET_OPCODE(a) (do_get_mem_word_unswapped((uae_u16 *)(a)))
5950     #else
5951     # define DO_GET_OPCODE(a) (do_get_mem_word((uae_u16 *)(a)))
5952     #endif
5953    
5954     #if JIT_DEBUG
5955     static uae_u8 *last_regs_pc_p = 0;
5956     static uae_u8 *last_compiled_block_addr = 0;
5957    
5958     void compiler_dumpstate(void)
5959     {
5960     if (!JITDebug)
5961     return;
5962    
5963     write_log("### Host addresses\n");
5964     write_log("MEM_BASE : %x\n", MEMBaseDiff);
5965     write_log("PC_P : %p\n", &regs.pc_p);
5966     write_log("SPCFLAGS : %p\n", &regs.spcflags);
5967     write_log("D0-D7 : %p-%p\n", &regs.regs[0], &regs.regs[7]);
5968     write_log("A0-A7 : %p-%p\n", &regs.regs[8], &regs.regs[15]);
5969     write_log("\n");
5970    
5971     write_log("### M68k processor state\n");
5972     m68k_dumpstate(0);
5973     write_log("\n");
5974    
5975     write_log("### Block in Mac address space\n");
5976     write_log("M68K block : %p\n",
5977     (void *)get_virtual_address(last_regs_pc_p));
5978     write_log("Native block : %p (%d bytes)\n",
5979     (void *)get_virtual_address(last_compiled_block_addr),
5980     get_blockinfo_addr(last_regs_pc_p)->direct_handler_size);
5981     write_log("\n");
5982     }
5983     #endif
5984    
5985     static void compile_block(cpu_history* pc_hist, int blocklen)
5986     {
5987     if (letit && compiled_code) {
5988     #if PROFILE_COMPILE_TIME
5989     compile_count++;
5990     clock_t start_time = clock();
5991     #endif
5992     #if JIT_DEBUG
5993     bool disasm_block = false;
5994     #endif
5995    
5996     /* OK, here we need to 'compile' a block */
5997     int i;
5998     int r;
5999     int was_comp=0;
6000     uae_u8 liveflags[MAXRUN+1];
6001 gbeauche 1.8 #if USE_CHECKSUM_INFO
6002     bool trace_in_rom = isinrom((uintptr)pc_hist[0].location);
6003     uae_u32 max_pcp=(uae_u32)pc_hist[blocklen - 1].location;
6004     uae_u32 min_pcp=max_pcp;
6005     #else
6006 gbeauche 1.1 uae_u32 max_pcp=(uae_u32)pc_hist[0].location;
6007     uae_u32 min_pcp=max_pcp;
6008 gbeauche 1.8 #endif
6009 gbeauche 1.1 uae_u32 cl=cacheline(pc_hist[0].location);
6010     void* specflags=(void*)&regs.spcflags;
6011     blockinfo* bi=NULL;
6012     blockinfo* bi2;
6013     int extra_len=0;
6014    
6015     redo_current_block=0;
6016     if (current_compile_p>=max_compile_start)
6017     flush_icache_hard(7);
6018    
6019     alloc_blockinfos();
6020    
6021     bi=get_blockinfo_addr_new(pc_hist[0].location,0);
6022     bi2=get_blockinfo(cl);
6023    
6024     optlev=bi->optlevel;
6025     if (bi->status!=BI_INVALID) {
6026     Dif (bi!=bi2) {
6027     /* I don't think it can happen anymore. Shouldn't, in
6028     any case. So let's make sure... */
6029     write_log("WOOOWOO count=%d, ol=%d %p %p\n",
6030     bi->count,bi->optlevel,bi->handler_to_use,
6031     cache_tags[cl].handler);
6032     abort();
6033     }
6034    
6035     Dif (bi->count!=-1 && bi->status!=BI_NEED_RECOMP) {
6036     write_log("bi->count=%d, bi->status=%d\n",bi->count,bi->status);
6037     /* What the heck? We are not supposed to be here! */
6038     abort();
6039     }
6040     }
6041     if (bi->count==-1) {
6042     optlev++;
6043     while (!optcount[optlev])
6044     optlev++;
6045     bi->count=optcount[optlev]-1;
6046     }
6047     current_block_pc_p=(uae_u32)pc_hist[0].location;
6048    
6049     remove_deps(bi); /* We are about to create new code */
6050     bi->optlevel=optlev;
6051     bi->pc_p=(uae_u8*)pc_hist[0].location;
6052 gbeauche 1.8 #if USE_CHECKSUM_INFO
6053     free_checksum_info_chain(bi->csi);
6054     bi->csi = NULL;
6055     #endif
6056 gbeauche 1.1
6057     liveflags[blocklen]=0x1f; /* All flags needed afterwards */
6058     i=blocklen;
6059     while (i--) {
6060     uae_u16* currpcp=pc_hist[i].location;
6061     uae_u32 op=DO_GET_OPCODE(currpcp);
6062    
6063 gbeauche 1.8 #if USE_CHECKSUM_INFO
6064     trace_in_rom = trace_in_rom && isinrom((uintptr)currpcp);
6065     #if USE_INLINING
6066     if (is_const_jump(op)) {
6067     checksum_info *csi = alloc_checksum_info();
6068     csi->start_p = (uae_u8 *)min_pcp;
6069     csi->length = max_pcp - min_pcp + LONGEST_68K_INST;
6070     csi->next = bi->csi;
6071     bi->csi = csi;
6072     max_pcp = (uae_u32)currpcp;
6073     }
6074     #endif
6075     min_pcp = (uae_u32)currpcp;
6076     #else
6077 gbeauche 1.1 if ((uae_u32)currpcp<min_pcp)
6078     min_pcp=(uae_u32)currpcp;
6079     if ((uae_u32)currpcp>max_pcp)
6080     max_pcp=(uae_u32)currpcp;
6081 gbeauche 1.8 #endif
6082 gbeauche 1.1
6083     liveflags[i]=((liveflags[i+1]&
6084     (~prop[op].set_flags))|
6085     prop[op].use_flags);
6086     if (prop[op].is_addx && (liveflags[i+1]&FLAG_Z)==0)
6087     liveflags[i]&= ~FLAG_Z;
6088     }
6089    
6090 gbeauche 1.8 #if USE_CHECKSUM_INFO
6091     checksum_info *csi = alloc_checksum_info();
6092     csi->start_p = (uae_u8 *)min_pcp;
6093     csi->length = max_pcp - min_pcp + LONGEST_68K_INST;
6094     csi->next = bi->csi;
6095     bi->csi = csi;
6096     #endif
6097    
6098 gbeauche 1.1 bi->needed_flags=liveflags[0];
6099    
6100 gbeauche 1.5 align_target(align_loops);
6101 gbeauche 1.1 was_comp=0;
6102    
6103     bi->direct_handler=(cpuop_func *)get_target();
6104     set_dhtu(bi,bi->direct_handler);
6105     bi->status=BI_COMPILING;
6106     current_block_start_target=(uae_u32)get_target();
6107    
6108     log_startblock();
6109    
6110     if (bi->count>=0) { /* Need to generate countdown code */
6111     raw_mov_l_mi((uae_u32)&regs.pc_p,(uae_u32)pc_hist[0].location);
6112     raw_sub_l_mi((uae_u32)&(bi->count),1);
6113     raw_jl((uae_u32)popall_recompile_block);
6114     }
6115     if (optlev==0) { /* No need to actually translate */
6116     /* Execute normally without keeping stats */
6117     raw_mov_l_mi((uae_u32)&regs.pc_p,(uae_u32)pc_hist[0].location);
6118     raw_jmp((uae_u32)popall_exec_nostats);
6119     }
6120     else {
6121     reg_alloc_run=0;
6122     next_pc_p=0;
6123     taken_pc_p=0;
6124     branch_cc=0;
6125    
6126     comp_pc_p=(uae_u8*)pc_hist[0].location;
6127     init_comp();
6128     was_comp=1;
6129    
6130     #if JIT_DEBUG
6131     if (JITDebug) {
6132     raw_mov_l_mi((uae_u32)&last_regs_pc_p,(uae_u32)pc_hist[0].location);
6133     raw_mov_l_mi((uae_u32)&last_compiled_block_addr,(uae_u32)current_block_start_target);
6134     }
6135     #endif
6136    
6137     for (i=0;i<blocklen &&
6138     get_target_noopt()<max_compile_start;i++) {
6139     cpuop_func **cputbl;
6140     compop_func **comptbl;
6141     uae_u32 opcode=DO_GET_OPCODE(pc_hist[i].location);
6142     needed_flags=(liveflags[i+1] & prop[opcode].set_flags);
6143     if (!needed_flags) {
6144     cputbl=nfcpufunctbl;
6145     comptbl=nfcompfunctbl;
6146     }
6147     else {
6148     cputbl=cpufunctbl;
6149     comptbl=compfunctbl;
6150     }
6151    
6152     failure = 1; // gb-- defaults to failure state
6153     if (comptbl[opcode] && optlev>1) {
6154     failure=0;
6155     if (!was_comp) {
6156     comp_pc_p=(uae_u8*)pc_hist[i].location;
6157     init_comp();
6158     }
6159     was_comp++;
6160    
6161     comptbl[opcode](opcode);
6162     freescratch();
6163     if (!(liveflags[i+1] & FLAG_CZNV)) {
6164     /* We can forget about flags */
6165     dont_care_flags();
6166     }
6167     #if INDIVIDUAL_INST
6168     flush(1);
6169     nop();
6170     flush(1);
6171     was_comp=0;
6172     #endif
6173     }
6174    
6175     if (failure) {
6176     if (was_comp) {
6177     flush(1);
6178     was_comp=0;
6179     }
6180     raw_mov_l_ri(REG_PAR1,(uae_u32)opcode);
6181     #if USE_NORMAL_CALLING_CONVENTION
6182     raw_push_l_r(REG_PAR1);
6183     #endif
6184     raw_mov_l_mi((uae_u32)&regs.pc_p,
6185     (uae_u32)pc_hist[i].location);
6186     raw_call((uae_u32)cputbl[opcode]);
6187 gbeauche 1.9 #if PROFILE_UNTRANSLATED_INSNS
6188     // raw_cputbl_count[] is indexed with plain opcode (in m68k order)
6189     raw_add_l_mi((uae_u32)&raw_cputbl_count[cft_map(opcode)],1);
6190     #endif
6191 gbeauche 1.1 //raw_add_l_mi((uae_u32)&oink,1); // FIXME
6192     #if USE_NORMAL_CALLING_CONVENTION
6193     raw_inc_sp(4);
6194     #endif
6195     if (needed_flags) {
6196     //raw_mov_l_mi((uae_u32)&foink3,(uae_u32)opcode+65536);
6197     }
6198     else {
6199     //raw_mov_l_mi((uae_u32)&foink3,(uae_u32)opcode);
6200     }
6201    
6202     if (i < blocklen - 1) {
6203     uae_s8* branchadd;
6204    
6205     raw_mov_l_rm(0,(uae_u32)specflags);
6206     raw_test_l_rr(0,0);
6207     raw_jz_b_oponly();
6208     branchadd=(uae_s8 *)get_target();
6209     emit_byte(0);
6210     raw_jmp((uae_u32)popall_do_nothing);
6211     *branchadd=(uae_u32)get_target()-(uae_u32)branchadd-1;
6212     }
6213     }
6214     }
6215     #if 1 /* This isn't completely kosher yet; It really needs to be
6216     be integrated into a general inter-block-dependency scheme */
6217     if (next_pc_p && taken_pc_p &&
6218     was_comp && taken_pc_p==current_block_pc_p) {
6219     blockinfo* bi1=get_blockinfo_addr_new((void*)next_pc_p,0);
6220     blockinfo* bi2=get_blockinfo_addr_new((void*)taken_pc_p,0);
6221     uae_u8 x=bi1->needed_flags;
6222    
6223     if (x==0xff || 1) { /* To be on the safe side */
6224     uae_u16* next=(uae_u16*)next_pc_p;
6225     uae_u32 op=DO_GET_OPCODE(next);
6226    
6227     x=0x1f;
6228     x&=(~prop[op].set_flags);
6229     x|=prop[op].use_flags;
6230     }
6231    
6232     x|=bi2->needed_flags;
6233     if (!(x & FLAG_CZNV)) {
6234     /* We can forget about flags */
6235     dont_care_flags();
6236     extra_len+=2; /* The next instruction now is part of this
6237     block */
6238     }
6239    
6240     }
6241     #endif
6242     log_flush();
6243    
6244     if (next_pc_p) { /* A branch was registered */
6245     uae_u32 t1=next_pc_p;
6246     uae_u32 t2=taken_pc_p;
6247     int cc=branch_cc;
6248    
6249     uae_u32* branchadd;
6250     uae_u32* tba;
6251     bigstate tmp;
6252     blockinfo* tbi;
6253    
6254     if (taken_pc_p<next_pc_p) {
6255     /* backward branch. Optimize for the "taken" case ---
6256     which means the raw_jcc should fall through when
6257     the 68k branch is taken. */
6258     t1=taken_pc_p;
6259     t2=next_pc_p;
6260     cc=branch_cc^1;
6261     }
6262    
6263     tmp=live; /* ouch! This is big... */
6264     raw_jcc_l_oponly(cc);
6265     branchadd=(uae_u32*)get_target();
6266     emit_long(0);
6267    
6268     /* predicted outcome */
6269     tbi=get_blockinfo_addr_new((void*)t1,1);
6270     match_states(tbi);
6271     raw_cmp_l_mi((uae_u32)specflags,0);
6272     raw_jcc_l_oponly(4);
6273     tba=(uae_u32*)get_target();
6274     emit_long(get_handler(t1)-((uae_u32)tba+4));
6275     raw_mov_l_mi((uae_u32)&regs.pc_p,t1);
6276     raw_jmp((uae_u32)popall_do_nothing);
6277     create_jmpdep(bi,0,tba,t1);
6278    
6279 gbeauche 1.5 align_target(align_jumps);
6280 gbeauche 1.1 /* not-predicted outcome */
6281     *branchadd=(uae_u32)get_target()-((uae_u32)branchadd+4);
6282     live=tmp; /* Ouch again */
6283     tbi=get_blockinfo_addr_new((void*)t2,1);
6284     match_states(tbi);
6285    
6286     //flush(1); /* Can only get here if was_comp==1 */
6287     raw_cmp_l_mi((uae_u32)specflags,0);
6288     raw_jcc_l_oponly(4);
6289     tba=(uae_u32*)get_target();
6290     emit_long(get_handler(t2)-((uae_u32)tba+4));
6291     raw_mov_l_mi((uae_u32)&regs.pc_p,t2);
6292     raw_jmp((uae_u32)popall_do_nothing);
6293     create_jmpdep(bi,1,tba,t2);
6294     }
6295     else
6296     {
6297     if (was_comp) {
6298     flush(1);
6299     }
6300    
6301     /* Let's find out where next_handler is... */
6302     if (was_comp && isinreg(PC_P)) {
6303     r=live.state[PC_P].realreg;
6304     raw_and_l_ri(r,TAGMASK);
6305     int r2 = (r==0) ? 1 : 0;
6306     raw_mov_l_ri(r2,(uae_u32)popall_do_nothing);
6307     raw_cmp_l_mi((uae_u32)specflags,0);
6308     raw_cmov_l_rm_indexed(r2,(uae_u32)cache_tags,r,4,4);
6309     raw_jmp_r(r2);
6310     }
6311     else if (was_comp && isconst(PC_P)) {
6312     uae_u32 v=live.state[PC_P].val;
6313     uae_u32* tba;
6314     blockinfo* tbi;
6315    
6316     tbi=get_blockinfo_addr_new((void*)v,1);
6317     match_states(tbi);
6318    
6319     raw_cmp_l_mi((uae_u32)specflags,0);
6320     raw_jcc_l_oponly(4);
6321     tba=(uae_u32*)get_target();
6322     emit_long(get_handler(v)-((uae_u32)tba+4));
6323     raw_mov_l_mi((uae_u32)&regs.pc_p,v);
6324     raw_jmp((uae_u32)popall_do_nothing);
6325     create_jmpdep(bi,0,tba,v);
6326     }
6327     else {
6328     r=REG_PC_TMP;
6329     raw_mov_l_rm(r,(uae_u32)&regs.pc_p);
6330     raw_and_l_ri(r,TAGMASK);
6331     int r2 = (r==0) ? 1 : 0;
6332     raw_mov_l_ri(r2,(uae_u32)popall_do_nothing);
6333     raw_cmp_l_mi((uae_u32)specflags,0);
6334     raw_cmov_l_rm_indexed(r2,(uae_u32)cache_tags,r,4,4);
6335     raw_jmp_r(r2);
6336     }
6337     }
6338     }
6339    
6340     #if USE_MATCH
6341     if (callers_need_recompile(&live,&(bi->env))) {
6342     mark_callers_recompile(bi);
6343     }
6344    
6345     big_to_small_state(&live,&(bi->env));
6346     #endif
6347    
6348 gbeauche 1.8 #if USE_CHECKSUM_INFO
6349     remove_from_list(bi);
6350     if (trace_in_rom) {
6351     // No need to checksum that block trace on cache invalidation
6352     free_checksum_info_chain(bi->csi);
6353     bi->csi = NULL;
6354     add_to_dormant(bi);
6355     }
6356     else {
6357     calc_checksum(bi,&(bi->c1),&(bi->c2));
6358     add_to_active(bi);
6359     }
6360     #else
6361 gbeauche 1.1 if (next_pc_p+extra_len>=max_pcp &&
6362     next_pc_p+extra_len<max_pcp+LONGEST_68K_INST)
6363     max_pcp=next_pc_p+extra_len; /* extra_len covers flags magic */
6364     else
6365     max_pcp+=LONGEST_68K_INST;
6366 gbeauche 1.7
6367 gbeauche 1.1 bi->len=max_pcp-min_pcp;
6368     bi->min_pcp=min_pcp;
6369 gbeauche 1.7
6370 gbeauche 1.1 remove_from_list(bi);
6371     if (isinrom(min_pcp) && isinrom(max_pcp)) {
6372     add_to_dormant(bi); /* No need to checksum it on cache flush.
6373     Please don't start changing ROMs in
6374     flight! */
6375     }
6376     else {
6377     calc_checksum(bi,&(bi->c1),&(bi->c2));
6378     add_to_active(bi);
6379     }
6380 gbeauche 1.8 #endif
6381 gbeauche 1.1
6382     current_cache_size += get_target() - (uae_u8 *)current_compile_p;
6383    
6384     #if JIT_DEBUG
6385     if (JITDebug)
6386     bi->direct_handler_size = get_target() - (uae_u8 *)current_block_start_target;
6387    
6388     if (JITDebug && disasm_block) {
6389     uaecptr block_addr = start_pc + ((char *)pc_hist[0].location - (char *)start_pc_p);
6390     D(bug("M68K block @ 0x%08x (%d insns)\n", block_addr, blocklen));
6391     uae_u32 block_size = ((uae_u8 *)pc_hist[blocklen - 1].location - (uae_u8 *)pc_hist[0].location) + 1;
6392     disasm_m68k_block((uae_u8 *)pc_hist[0].location, block_size);
6393     D(bug("Compiled block @ 0x%08x\n", pc_hist[0].location));
6394     disasm_native_block((uae_u8 *)current_block_start_target, bi->direct_handler_size);
6395     getchar();
6396     }
6397     #endif
6398    
6399     log_dump();
6400 gbeauche 1.5 align_target(align_jumps);
6401 gbeauche 1.1
6402     /* This is the non-direct handler */
6403     bi->handler=
6404     bi->handler_to_use=(cpuop_func *)get_target();
6405     raw_cmp_l_mi((uae_u32)&regs.pc_p,(uae_u32)pc_hist[0].location);
6406     raw_jnz((uae_u32)popall_cache_miss);
6407     comp_pc_p=(uae_u8*)pc_hist[0].location;
6408    
6409     bi->status=BI_FINALIZING;
6410     init_comp();
6411     match_states(bi);
6412     flush(1);
6413    
6414     raw_jmp((uae_u32)bi->direct_handler);
6415    
6416     current_compile_p=get_target();
6417     raise_in_cl_list(bi);
6418    
6419     /* We will flush soon, anyway, so let's do it now */
6420     if (current_compile_p>=max_compile_start)
6421     flush_icache_hard(7);
6422    
6423     bi->status=BI_ACTIVE;
6424     if (redo_current_block)
6425     block_need_recompile(bi);
6426    
6427     #if PROFILE_COMPILE_TIME
6428     compile_time += (clock() - start_time);
6429     #endif
6430     }
6431     }
6432    
6433     void do_nothing(void)
6434     {
6435     /* What did you expect this to do? */
6436     }
6437    
6438     void exec_nostats(void)
6439     {
6440     for (;;) {
6441     uae_u32 opcode = GET_OPCODE;
6442     (*cpufunctbl[opcode])(opcode);
6443     if (end_block(opcode) || SPCFLAGS_TEST(SPCFLAG_ALL)) {
6444     return; /* We will deal with the spcflags in the caller */
6445     }
6446     }
6447     }
6448    
6449     void execute_normal(void)
6450     {
6451     if (!check_for_cache_miss()) {
6452     cpu_history pc_hist[MAXRUN];
6453     int blocklen = 0;
6454     #if REAL_ADDRESSING || DIRECT_ADDRESSING
6455     start_pc_p = regs.pc_p;
6456     start_pc = get_virtual_address(regs.pc_p);
6457     #else
6458     start_pc_p = regs.pc_oldp;
6459     start_pc = regs.pc;
6460     #endif
6461     for (;;) { /* Take note: This is the do-it-normal loop */
6462     pc_hist[blocklen++].location = (uae_u16 *)regs.pc_p;
6463     uae_u32 opcode = GET_OPCODE;
6464     #if FLIGHT_RECORDER
6465     m68k_record_step(m68k_getpc());
6466     #endif
6467     (*cpufunctbl[opcode])(opcode);
6468     if (end_block(opcode) || SPCFLAGS_TEST(SPCFLAG_ALL) || blocklen>=MAXRUN) {
6469     compile_block(pc_hist, blocklen);
6470     return; /* We will deal with the spcflags in the caller */
6471     }
6472     /* No need to check regs.spcflags, because if they were set,
6473     we'd have ended up inside that "if" */
6474     }
6475     }
6476     }
6477    
6478     typedef void (*compiled_handler)(void);
6479    
6480 gbeauche 1.6 #ifdef X86_ASSEMBLY
6481     void (*m68k_compile_execute)(void) = NULL;
6482     #else
6483 gbeauche 1.1 void m68k_do_compile_execute(void)
6484     {
6485     for (;;) {
6486     ((compiled_handler)(pushall_call_handler))();
6487     /* Whenever we return from that, we should check spcflags */
6488     if (SPCFLAGS_TEST(SPCFLAG_ALL)) {
6489     if (m68k_do_specialties ())
6490     return;
6491     }
6492     }
6493     }
6494 gbeauche 1.6 #endif