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

File Contents

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