ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/uae_cpu/compiler/compemu_support.cpp
Revision: 1.17
Committed: 2003-03-19T16:28:23Z (21 years, 3 months ago) by gbeauche
Branch: MAIN
Changes since 1.16: +11 -2 lines
Log Message:
Add facility to filter out some opcodes from the compfunctbl[] et al.

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