ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/compiler/compemu_support.cpp
Revision: 1.8
Committed: 2002-10-02T15:55:10Z (21 years, 9 months ago) by gbeauche
Branch: MAIN
Changes since 1.7: +122 -54 lines
Log Message:
- Remove dead code in readcpu.cpp concerning CONST_JUMP control flow.
- Replace unused fl_compiled with fl_const_jump
- Implement block inlining enabled with USE_INLINING && USE_CHECKSUM_INFO.
  However, this is currently disabled as it doesn't give much and exhibits
  even more a cache/code generation problem with FPU JIT compiled code.
- Actual checksum values are now integral part of a blockinfo regardless
  of USE_CHECKSUM_INFO is set or not. Reduce number of elements in that
  structure and speeds up a little calculation of checksum of chained blocks.
- Don't care about show_checksum() for now.

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