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