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