ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/compiler/compemu_support.cpp
Revision: 1.15
Committed: 2003-03-13T15:57:01Z (21 years, 6 months ago) by gbeauche
Branch: MAIN
Changes since 1.14: +21 -10 lines
Log Message:
Workaround change in flags handling for BSF instruction on Pentium 4.
i.e. currently disable translation of ADDX/SUBX/B<CHG,CLR,SET,TST> instructions
in that case. That is to say, better (much?) slower than inaccurate. :-(

File Contents

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