ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/compiler/compemu_support.cpp
Revision: 1.4
Committed: 2002-09-18T11:41:56Z (22 years ago) by gbeauche
Branch: MAIN
Changes since 1.3: +4 -0 lines
Log Message:
Move -DSAHF_SETO_PROFITABLE down in x86 & gas specific block. Also ensure
SAHF_SETO_PROFITABLE is defined when compiling the JIT. Aka I don't want
to support obsolete and probably bogus code nowadays.

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