ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/compiler/compemu_support.cpp
Revision: 1.11
Committed: 2002-10-03T16:13:46Z (21 years, 9 months ago) by gbeauche
Branch: MAIN
Changes since 1.10: +25 -0 lines
Log Message:
JIT add copyright notices just to notify people that's real derivative
work from GPL code (UAE-JIT). Additions and improvements are from B2
developers.

File Contents

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