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