#define writemem_special writemem #define readmem_special readmem #define USE_MATCHSTATE 0 #define setzflg_uses_bsf 0 #include "sysconfig.h" #include "sysdeps.h" #include "options.h" #include "events.h" #include "include/memory.h" #include "custom.h" #include "newcpu.h" #include "comptbl.h" #include "compemu.h" #include "uae_endian.h" // %%% BRIAN KING WAS HERE %%% extern int canbang; compop_func *compfunctbl[65536]; compop_func *nfcompfunctbl[65536]; #ifdef NOFLAGS_SUPPORT cpuop_func *nfcpufunctbl[65536]; #endif uae_u8* comp_pc_p; uae_u8* start_pc_p; uae_u32 start_pc; uae_u32 current_block_pc_p; uae_u32 current_block_start_target; uae_u32 needed_flags; static uae_u32 next_pc_p; static uae_u32 taken_pc_p; static int branch_cc; int segvcount=0; int soft_flush_count=0; int hard_flush_count=0; int compile_count=0; int checksum_count=0; static uae_u8* current_compile_p=NULL; static uae_u8* max_compile_start; uae_u8* compiled_code=NULL; static uae_s32 reg_alloc_run; static int align_loops = 32;// Align the start of loops static int align_jumps = 32;// Align the start of jumps void *pushall_call_handler; static void *popall_do_nothing; static void *popall_exec_nostats; static void *popall_execute_normal; static void *popall_cache_miss; static void *popall_recompile_block; static void *popall_check_checksum; static uae_u8 *popallspace; /* The 68k only ever executes from even addresses. So right now, we waste half the entries in this array UPDATE: We now use those entries to store the start of the linked lists that we maintain for each hash result. */ cacheline cache_tags[TAGSIZE]; static int letit; blockinfo* hold_bi[MAX_HOLD_BI]; blockinfo* active; blockinfo* dormant; op_properties prop[65536]; #ifdef NOFLAGS_SUPPORT /* 68040 */ extern const struct cputbl op_smalltbl_0_nf[]; #endif extern const struct comptbl op_smalltbl_0_comp_nf[]; extern const struct comptbl op_smalltbl_0_comp_ff[]; #ifdef NOFLAGS_SUPPORT /* 68020 + 68881 */ extern const struct cputbl op_smalltbl_1_nf[]; /* 68020 */ extern const struct cputbl op_smalltbl_2_nf[]; /* 68010 */ extern const struct cputbl op_smalltbl_3_nf[]; /* 68000 */ extern const struct cputbl op_smalltbl_4_nf[]; #ifdef CPUEMU_5 /* 68000 slow but compatible. */ extern const struct cputbl op_smalltbl_5_nf[]; #endif #endif static void flush_icache_hard(int n); bigstate live; smallstate empty_ss; smallstate default_ss; static int optlev; static int writereg(int r, int size); static void unlock(int r); static void setlock(int r); static int readreg_specific(int r, int size, int spec); static int writereg_specific(int r, int size, int spec); static void prepare_for_call_1(void); static void prepare_for_call_2(void); static void align_target(uae_u32 a); #ifdef NATMEM_OFFSET # ifndef WIN32 struct sigaction *saved_handler; # endif #endif uae_u32 m68k_pc_offset; /* Some arithmetic ooperations can be optimized away if the operands are known to be constant. But that's only a good idea when the side effects they would have on the flags are not important. This variable indicates whether we need the side effects or not */ uae_u32 needflags=0; /* Flag handling is complicated. x86 instructions create flags, which quite often are exactly what we want. So at times, the "68k" flags are actually in the x86 flags. Then again, sometimes we do x86 instructions that clobber the x86 flags, but don't represent a corresponding m68k instruction. In that case, we have to save them. We used to save them to the stack, but now store them back directly into the regflags.cznv of the traditional emulation. Thus some odd names. So flags can be in either of two places (used to be three; boy were things complicated back then!); And either place can contain either valid flags or invalid trash (and on the stack, there was also the option of "nothing at all", now gone). A couple of variables keep track of the respective states. To make things worse, we might or might not be interested in the flags. by default, we are, but a call to dont_care_flags can change that until the next call to live_flags. If we are not, pretty much whatever is in the register and/or the native flags is seen as valid. */ STATIC_INLINE blockinfo* get_blockinfo(uae_u32 cl) { return cache_tags[cl+1].bi; } STATIC_INLINE blockinfo* get_blockinfo_addr(void* addr) { blockinfo* bi=get_blockinfo(cacheline(addr)); while (bi) { if (bi->pc_p==addr) return bi; bi=bi->next_same_cl; } return NULL; } /******************************************************************* * All sorts of list related functions for all of the lists * *******************************************************************/ STATIC_INLINE void remove_from_cl_list(blockinfo* bi) { uae_u32 cl=cacheline(bi->pc_p); if (bi->prev_same_cl_p) *(bi->prev_same_cl_p)=bi->next_same_cl; if (bi->next_same_cl) bi->next_same_cl->prev_same_cl_p=bi->prev_same_cl_p; if (cache_tags[cl+1].bi) cache_tags[cl].handler=cache_tags[cl+1].bi->handler_to_use; else cache_tags[cl].handler=popall_execute_normal; } STATIC_INLINE void remove_from_list(blockinfo* bi) { if (bi->prev_p) *(bi->prev_p)=bi->next; if (bi->next) bi->next->prev_p=bi->prev_p; } STATIC_INLINE void remove_from_lists(blockinfo* bi) { remove_from_list(bi); remove_from_cl_list(bi); } STATIC_INLINE void add_to_cl_list(blockinfo* bi) { uae_u32 cl=cacheline(bi->pc_p); if (cache_tags[cl+1].bi) cache_tags[cl+1].bi->prev_same_cl_p=&(bi->next_same_cl); bi->next_same_cl=cache_tags[cl+1].bi; cache_tags[cl+1].bi=bi; bi->prev_same_cl_p=&(cache_tags[cl+1].bi); cache_tags[cl].handler=bi->handler_to_use; } STATIC_INLINE void raise_in_cl_list(blockinfo* bi) { remove_from_cl_list(bi); add_to_cl_list(bi); } STATIC_INLINE void add_to_active(blockinfo* bi) { if (active) active->prev_p=&(bi->next); bi->next=active; active=bi; bi->prev_p=&active; } STATIC_INLINE void add_to_dormant(blockinfo* bi) { if (dormant) dormant->prev_p=&(bi->next); bi->next=dormant; dormant=bi; bi->prev_p=&dormant; } STATIC_INLINE void remove_dep(dependency* d) { if (d->prev_p) *(d->prev_p)=d->next; if (d->next) d->next->prev_p=d->prev_p; d->prev_p=NULL; d->next=NULL; } /* This block's code is about to be thrown away, so it no longer depends on anything else */ STATIC_INLINE void remove_deps(blockinfo* bi) { remove_dep(&(bi->dep[0])); remove_dep(&(bi->dep[1])); } STATIC_INLINE void adjust_jmpdep(dependency* d, void* a) { *(d->jmp_off) = (uae_uintptr)a - ((uae_uintptr)d->jmp_off+4); } /******************************************************************** * Soft flush handling support functions * ********************************************************************/ STATIC_INLINE void set_dhtu(blockinfo* bi, void* dh) { //printf("bi is %p\n",bi); if (dh!=bi->direct_handler_to_use) { dependency* x=bi->deplist; //printf("bi->deplist=%p\n",bi->deplist); while (x) { //printf("x is %p\n",x); //printf("x->next is %p\n",x->next); //printf("x->prev_p is %p\n",x->prev_p); if (x->jmp_off) { adjust_jmpdep(x,dh); } x=x->next; } bi->direct_handler_to_use=dh; } } STATIC_INLINE void invalidate_block(blockinfo* bi) { int i; bi->optlevel=0; bi->count=currprefs.optcount[0]-1; bi->handler=NULL; bi->handler_to_use=popall_execute_normal; bi->direct_handler=NULL; set_dhtu(bi,bi->direct_pen); bi->needed_flags=0xff; for (i=0;i<2;i++) { bi->dep[i].jmp_off=NULL; bi->dep[i].target=NULL; } remove_deps(bi); } STATIC_INLINE void create_jmpdep(blockinfo* bi, int i, uae_u32* jmpaddr, uae_uintptr target) { blockinfo* tbi=get_blockinfo_addr((void*)target); Dif(!tbi) { write_log ("JIT: Could not create jmpdep!\n"); abort(); } bi->dep[i].jmp_off=jmpaddr; bi->dep[i].target=tbi; bi->dep[i].next=tbi->deplist; if (bi->dep[i].next) bi->dep[i].next->prev_p=&(bi->dep[i].next); bi->dep[i].prev_p=&(tbi->deplist); tbi->deplist=&(bi->dep[i]); } STATIC_INLINE void big_to_small_state(bigstate* b, smallstate* s) { int i; int count=0; for (i=0;inat[i].validsize=0; s->nat[i].dirtysize=0; if (b->nat[i].nholds) { int index=b->nat[i].nholds-1; int r=b->nat[i].holds[index]; s->nat[i].holds=r; s->nat[i].validsize=b->state[r].validsize; s->nat[i].dirtysize=b->state[r].dirtysize; count++; } } write_log ("JIT: count=%d\n", count); for (i=0;inat[i].dirtysize=0; } } STATIC_INLINE void attached_state(blockinfo* bi) { bi->havestate=1; if (bi->direct_handler_to_use==bi->direct_handler) set_dhtu(bi,bi->direct_pen); bi->direct_handler=bi->direct_pen; bi->status=BI_TARGETTED; } STATIC_INLINE blockinfo* get_blockinfo_addr_new(void* addr, int setstate) { blockinfo* bi=get_blockinfo_addr(addr); int i; if (!bi) { for (i=0;ipc_p=addr; invalidate_block(bi); add_to_active(bi); add_to_cl_list(bi); } } } if (!bi) { write_log ("JIT: Looking for blockinfo, can't find free one\n"); abort(); } #if USE_MATCHSTATE if (setstate && !bi->havestate) { big_to_small_state(&live,&(bi->env)); attached_state(bi); } #endif return bi; } static void prepare_block(blockinfo* bi); STATIC_INLINE void alloc_blockinfos(void) { int i; blockinfo* bi; for (i=0;i0) { free_nreg(bestreg); } if (isinreg(r)) { int rr=live.state[r].realreg; /* This will happen if we read a partially dirty register at a bigger size */ Dif (willclobber || live.state[r].validsize>=size) abort(); Dif (live.nat[rr].nholds!=1) abort(); if (size==4 && live.state[r].validsize==2) { log_isused(bestreg); raw_mov_l_rm(bestreg,(uae_uintptr)live.state[r].mem); raw_bswap_32(bestreg); raw_zero_extend_16_rr(rr,rr); raw_zero_extend_16_rr(bestreg,bestreg); raw_bswap_32(bestreg); raw_lea_l_brr_indexed(rr,rr,bestreg,1,0); live.state[r].validsize=4; live.nat[rr].touched=touchcnt++; return rr; } if (live.state[r].validsize==1) { /* Nothing yet */ } evict(r); } if (!willclobber) { if (live.state[r].status!=UNDEF) { if (isconst(r)) { raw_mov_l_ri(bestreg,live.state[r].val); live.state[r].val=0; live.state[r].dirtysize=4; set_status(r,DIRTY); log_isused(bestreg); } else { if (r==FLAGTMP) raw_load_flagreg(bestreg,r); else if (r==FLAGX) raw_load_flagx(bestreg,r); else { raw_mov_l_rm(bestreg,(uae_uintptr)live.state[r].mem); } live.state[r].dirtysize=0; set_status(r,CLEAN); log_isreg(bestreg,r); } } else { live.state[r].val=0; live.state[r].dirtysize=0; set_status(r,CLEAN); log_isused(bestreg); } live.state[r].validsize=4; } else { /* this is the easiest way, but not optimal. FIXME! */ /* Now it's trickier, but hopefully still OK */ if (!isconst(r) || size==4) { live.state[r].validsize=size; live.state[r].dirtysize=size; live.state[r].val=0; set_status(r,DIRTY); if (size==4) log_isused(bestreg); else log_isreg(bestreg,r); } else { if (live.state[r].status!=UNDEF) raw_mov_l_ri(bestreg,live.state[r].val); live.state[r].val=0; live.state[r].validsize=4; live.state[r].dirtysize=4; set_status(r,DIRTY); log_isused(bestreg); } } live.state[r].realreg=bestreg; live.state[r].realind=live.nat[bestreg].nholds; live.nat[bestreg].touched=touchcnt++; live.nat[bestreg].holds[live.nat[bestreg].nholds]=r; live.nat[bestreg].nholds++; return bestreg; } static int alloc_reg(int r, int size, int willclobber) { return alloc_reg_hinted(r,size,willclobber,-1); } static void unlock(int r) { Dif (!live.nat[r].locked) abort(); live.nat[r].locked--; } static void setlock(int r) { live.nat[r].locked++; } static void mov_nregs(int d, int s) { int nd=live.nat[d].nholds; int i; if (s==d) return; if (nd>0) free_nreg(d); raw_mov_l_rr(d,s); log_isused(d); for (i=0;i=size) { n=live.state[r].realreg; switch(size) { case 1: if (live.nat[n].canbyte || spec>=0) { answer=n; } break; case 2: if (live.nat[n].canword || spec>=0) { answer=n; } break; case 4: answer=n; break; default: abort(); } if (answer<0) evict(r); } /* either the value was in memory to start with, or it was evicted and is in memory now */ if (answer<0) { answer=alloc_reg_hinted(r,spec>=0?4:size,0,spec); } if (spec>=0 && spec!=answer) { /* Too bad */ mov_nregs(spec,answer); answer=spec; } live.nat[answer].locked++; live.nat[answer].touched=touchcnt++; return answer; } static int readreg(int r, int size) { return readreg_general(r,size,-1,0); } static int readreg_specific(int r, int size, int spec) { return readreg_general(r,size,spec,0); } static int readreg_offset(int r, int size) { return readreg_general(r,size,-1,1); } STATIC_INLINE int writereg_general(int r, int size, int spec) { int n; int answer=-1; if (size<4) { remove_offset(r,spec); } make_exclusive(r,size,spec); if (isinreg(r)) { int nvsize=size>live.state[r].validsize?size:live.state[r].validsize; int ndsize=size>live.state[r].dirtysize?size:live.state[r].dirtysize; n=live.state[r].realreg; Dif (live.nat[n].nholds!=1) abort(); switch(size) { case 1: if (live.nat[n].canbyte || spec>=0) { live.state[r].dirtysize=ndsize; live.state[r].validsize=nvsize; answer=n; } break; case 2: if (live.nat[n].canword || spec>=0) { live.state[r].dirtysize=ndsize; live.state[r].validsize=nvsize; answer=n; } break; case 4: live.state[r].dirtysize=ndsize; live.state[r].validsize=nvsize; answer=n; break; default: abort(); } if (answer<0) evict(r); } /* either the value was in memory to start with, or it was evicted and is in memory now */ if (answer<0) { answer=alloc_reg_hinted(r,size,1,spec); } if (spec>=0 && spec!=answer) { mov_nregs(spec,answer); answer=spec; } if (live.state[r].status==UNDEF) live.state[r].validsize=4; live.state[r].dirtysize=size>live.state[r].dirtysize?size:live.state[r].dirtysize; live.state[r].validsize=size>live.state[r].validsize?size:live.state[r].validsize; live.nat[answer].locked++; live.nat[answer].touched=touchcnt++; if (size==4) { live.state[r].val=0; } else { Dif (live.state[r].val) { write_log ("JIT: Problem with val\n"); abort(); } } set_status(r,DIRTY); return answer; } static int writereg(int r, int size) { return writereg_general(r,size,-1); } static int writereg_specific(int r, int size, int spec) { return writereg_general(r,size,spec); } STATIC_INLINE int rmw_general(int r, int wsize, int rsize, int spec) { int n; int answer=-1; if (live.state[r].status==UNDEF) { write_log ("JIT: WARNING: Unexpected read of undefined register %d\n", r); } remove_offset(r,spec); make_exclusive(r,0,spec); Dif (wsize=rsize) { n=live.state[r].realreg; Dif (live.nat[n].nholds!=1) abort(); switch(rsize) { case 1: if (live.nat[n].canbyte || spec>=0) { answer=n; } break; case 2: if (live.nat[n].canword || spec>=0) { answer=n; } break; case 4: answer=n; break; default: abort(); } if (answer<0) evict(r); } /* either the value was in memory to start with, or it was evicted and is in memory now */ if (answer<0) { answer=alloc_reg_hinted(r,spec>=0?4:rsize,0,spec); } if (spec>=0 && spec!=answer) { /* Too bad */ mov_nregs(spec,answer); answer=spec; } if (wsize>live.state[r].dirtysize) live.state[r].dirtysize=wsize; if (wsize>live.state[r].validsize) live.state[r].validsize=wsize; set_status(r,DIRTY); live.nat[answer].locked++; live.nat[answer].touched=touchcnt++; Dif (live.state[r].val) { write_log ("JIT: Problem with val(rmw)\n"); abort(); } return answer; } static int rmw(int r, int wsize, int rsize) { return rmw_general(r,wsize,rsize,-1); } static int rmw_specific(int r, int wsize, int rsize, int spec) { return rmw_general(r,wsize,rsize,spec); } /* needed for restoring the carry flag on non-P6 cores */ static void bt_l_ri_noclobber(R4 r, IMM i) { int size=4; if (i<16) size=2; r=readreg(r,size); raw_bt_l_ri(r,i); unlock(r); } /******************************************************************** * FPU register status handling. EMIT TIME! * ********************************************************************/ static void f_tomem(int r) { if (live.fate[r].status==DIRTY) { #if USE_LONG_DOUBLE raw_fmov_ext_mr((uae_uintptr)live.fate[r].mem,live.fate[r].realreg); #else raw_fmov_mr((uae_uintptr)live.fate[r].mem,live.fate[r].realreg); #endif live.fate[r].status=CLEAN; } } static void f_tomem_drop(int r) { if (live.fate[r].status==DIRTY) { #if USE_LONG_DOUBLE raw_fmov_ext_mr_drop((uae_uintptr)live.fate[r].mem,live.fate[r].realreg); #else raw_fmov_mr_drop((uae_uintptr)live.fate[r].mem,live.fate[r].realreg); #endif live.fate[r].status=INMEM; } } STATIC_INLINE int f_isinreg(int r) { return live.fate[r].status==CLEAN || live.fate[r].status==DIRTY; } static void f_evict(int r) { int rr; if (!f_isinreg(r)) return; rr=live.fate[r].realreg; if (live.fat[rr].nholds==1) f_tomem_drop(r); else f_tomem(r); Dif (live.fat[rr].locked && live.fat[rr].nholds==1) { write_log ("JIT: FPU register %d in nreg %d is locked!\n", r, live.fate[r].realreg); abort(); } live.fat[rr].nholds--; if (live.fat[rr].nholds!=live.fate[r].realind) { /* Was not last */ int topreg=live.fat[rr].holds[live.fat[rr].nholds]; int thisind=live.fate[r].realind; live.fat[rr].holds[thisind]=topreg; live.fate[topreg].realind=thisind; } live.fate[r].status=INMEM; live.fate[r].realreg=-1; } STATIC_INLINE void f_free_nreg(int r) { int i=live.fat[r].nholds; while (i) { int vr; --i; vr=live.fat[r].holds[i]; f_evict(vr); } Dif (live.fat[r].nholds!=0) { write_log ("JIT: Failed to free nreg %d, nholds is %d\n", r, live.fat[r].nholds); abort(); } } /* Use with care! */ STATIC_INLINE void f_isclean(int r) { if (!f_isinreg(r)) return; live.fate[r].status=CLEAN; } STATIC_INLINE void f_disassociate(int r) { f_isclean(r); f_evict(r); } static int f_alloc_reg(int r, int willclobber) { int bestreg; uae_s32 when; int i; uae_s32 badness; bestreg=-1; when=2000000000; for (i=N_FREGS;i--;) { badness=live.fat[i].touched; if (live.fat[i].nholds==0) badness=0; if (!live.fat[i].locked && badness0) { f_free_nreg(bestreg); } if (f_isinreg(r)) { f_evict(r); } if (!willclobber) { if (live.fate[r].status!=UNDEF) { #if USE_LONG_DOUBLE raw_fmov_ext_rm(bestreg,(uae_uintptr)live.fate[r].mem); #else raw_fmov_rm(bestreg,(uae_uintptr)live.fate[r].mem); #endif } live.fate[r].status=CLEAN; } else { live.fate[r].status=DIRTY; } live.fate[r].realreg=bestreg; live.fate[r].realind=live.fat[bestreg].nholds; live.fat[bestreg].touched=touchcnt++; live.fat[bestreg].holds[live.fat[bestreg].nholds]=r; live.fat[bestreg].nholds++; return bestreg; } static void f_unlock(int r) { Dif (!live.fat[r].locked) abort(); live.fat[r].locked--; } static void f_setlock(int r) { live.fat[r].locked++; } static __inline__ int f_readreg(int r) { int n; int answer=-1; if (f_isinreg(r)) { n=live.fate[r].realreg; answer=n; } /* either the value was in memory to start with, or it was evicted and is in memory now */ if (answer<0) answer=f_alloc_reg(r,0); live.fat[answer].locked++; live.fat[answer].touched=touchcnt++; return answer; } static __inline__ void f_make_exclusive(int r, int clobber) { freg_status oldstate; int rr=live.fate[r].realreg; int nr; int nind; int ndirt=0; int i; if (!f_isinreg(r)) return; if (live.fat[rr].nholds==1) return; for (i=0;i>=i; return; } CLOBBER_SHRL; r=rmw(r,4,4); raw_shrl_l_ri(r,i); unlock(r); } MENDFUNC(2,shrl_l_ri,(RW4 r, IMM i)) MIDFUNC(2,shrl_w_ri,(RW2 r, IMM i)) { if (!i && !needflags) return; CLOBBER_SHRL; r=rmw(r,2,2); raw_shrl_w_ri(r,i); unlock(r); } MENDFUNC(2,shrl_w_ri,(RW2 r, IMM i)) MIDFUNC(2,shrl_b_ri,(RW1 r, IMM i)) { if (!i && !needflags) return; CLOBBER_SHRL; r=rmw(r,1,1); raw_shrl_b_ri(r,i); unlock(r); } MENDFUNC(2,shrl_b_ri,(RW1 r, IMM i)) MIDFUNC(2,shra_l_ri,(RW4 r, IMM i)) { if (!i && !needflags) return; CLOBBER_SHRA; r=rmw(r,4,4); raw_shra_l_ri(r,i); unlock(r); } MENDFUNC(2,shra_l_ri,(RW4 r, IMM i)) MIDFUNC(2,shra_w_ri,(RW2 r, IMM i)) { if (!i && !needflags) return; CLOBBER_SHRA; r=rmw(r,2,2); raw_shra_w_ri(r,i); unlock(r); } MENDFUNC(2,shra_w_ri,(RW2 r, IMM i)) MIDFUNC(2,shra_b_ri,(RW1 r, IMM i)) { if (!i && !needflags) return; CLOBBER_SHRA; r=rmw(r,1,1); raw_shra_b_ri(r,i); unlock(r); } MENDFUNC(2,shra_b_ri,(RW1 r, IMM i)) MIDFUNC(2,shra_l_rr,(RW4 d, R1 r)) { if (isconst(r)) { COMPCALL(shra_l_ri)(d,(uae_u8)live.state[r].val); return; } CLOBBER_SHRA; r=readreg_specific(r,1,SHIFTCOUNT_NREG); d=rmw(d,4,4); Dif (r!=1) { write_log ("JIT: Illegal register %d in raw_rol_b\n", r); abort(); } raw_shra_l_rr(d,r) ; unlock(r); unlock(d); } MENDFUNC(2,shra_l_rr,(RW4 d, R1 r)) MIDFUNC(2,shra_w_rr,(RW2 d, R1 r)) { /* Can only do this with r==1, i.e. cl */ if (isconst(r)) { COMPCALL(shra_w_ri)(d,(uae_u8)live.state[r].val); return; } CLOBBER_SHRA; r=readreg_specific(r,1,SHIFTCOUNT_NREG); d=rmw(d,2,2); Dif (r!=1) { write_log ("JIT: Illegal register %d in raw_shra_b\n", r); abort(); } raw_shra_w_rr(d,r) ; unlock(r); unlock(d); } MENDFUNC(2,shra_w_rr,(RW2 d, R1 r)) MIDFUNC(2,shra_b_rr,(RW1 d, R1 r)) { /* Can only do this with r==1, i.e. cl */ if (isconst(r)) { COMPCALL(shra_b_ri)(d,(uae_u8)live.state[r].val); return; } CLOBBER_SHRA; r=readreg_specific(r,1,SHIFTCOUNT_NREG); d=rmw(d,1,1); Dif (r!=1) { write_log ("JIT: Illegal register %d in raw_shra_b\n", r); abort(); } raw_shra_b_rr(d,r) ; unlock(r); unlock(d); } MENDFUNC(2,shra_b_rr,(RW1 d, R1 r)) MIDFUNC(2,setcc,(W1 d, IMM cc)) { CLOBBER_SETCC; d=writereg(d,1); raw_setcc(d,cc); unlock(d); } MENDFUNC(2,setcc,(W1 d, IMM cc)) MIDFUNC(2,setcc_m,(IMM d, IMM cc)) { CLOBBER_SETCC; raw_setcc_m(d,cc); } MENDFUNC(2,setcc_m,(IMM d, IMM cc)) MIDFUNC(3,cmov_l_rr,(RW4 d, R4 s, IMM cc)) { if (d==s) return; CLOBBER_CMOV; s=readreg(s,4); d=rmw(d,4,4); raw_cmov_l_rr(d,s,cc); unlock(s); unlock(d); } MENDFUNC(3,cmov_l_rr,(RW4 d, R4 s, IMM cc)) MIDFUNC(1,setzflg_l,(RW4 r)) { if (setzflg_uses_bsf) { CLOBBER_BSF; r=rmw(r,4,4); raw_bsf_l_rr(r,r); unlock(r); } else { Dif (live.flags_in_flags!=VALID) { write_log ("JIT: setzflg() wanted flags in native flags, they are %d\n", live.flags_in_flags); abort(); } r=readreg(r,4); { int f=writereg(S11,4); int t=writereg(S12,4); raw_flags_set_zero(f,r,t); unlock(f); unlock(r); unlock(t); } } } MENDFUNC(1,setzflg_l,(RW4 r)) MIDFUNC(3,cmov_l_rm,(RW4 d, IMM s, IMM cc)) { CLOBBER_CMOV; d=rmw(d,4,4); raw_cmov_l_rm(d,s,cc); unlock(d); } MENDFUNC(3,cmov_l_rm,(RW4 d, IMM s, IMM cc)) MIDFUNC(2,bsf_l_rr,(W4 d, R4 s)) { CLOBBER_BSF; s=readreg(s,4); d=writereg(d,4); raw_bsf_l_rr(d,s); unlock(s); unlock(d); } MENDFUNC(2,bsf_l_rr,(W4 d, R4 s)) MIDFUNC(2,imul_32_32,(RW4 d, R4 s)) { CLOBBER_MUL; s=readreg(s,4); d=rmw(d,4,4); raw_imul_32_32(d,s); unlock(s); unlock(d); } MENDFUNC(2,imul_32_32,(RW4 d, R4 s)) MIDFUNC(2,imul_64_32,(RW4 d, RW4 s)) { CLOBBER_MUL; s=rmw_specific(s,4,4,MUL_NREG2); d=rmw_specific(d,4,4,MUL_NREG1); raw_imul_64_32(d,s); unlock(s); unlock(d); } MENDFUNC(2,imul_64_32,(RW4 d, RW4 s)) MIDFUNC(2,mul_64_32,(RW4 d, RW4 s)) { CLOBBER_MUL; s=rmw_specific(s,4,4,MUL_NREG2); d=rmw_specific(d,4,4,MUL_NREG1); raw_mul_64_32(d,s); unlock(s); unlock(d); } MENDFUNC(2,mul_64_32,(RW4 d, RW4 s)) MIDFUNC(2,mul_32_32,(RW4 d, R4 s)) { CLOBBER_MUL; s=readreg(s,4); d=rmw(d,4,4); raw_mul_32_32(d,s); unlock(s); unlock(d); } MENDFUNC(2,mul_32_32,(RW4 d, R4 s)) MIDFUNC(2,sign_extend_16_rr,(W4 d, R2 s)) { int isrmw; if (isconst(s)) { set_const(d,(uae_s32)(uae_s16)live.state[s].val); return; } CLOBBER_SE16; isrmw=(s==d); if (!isrmw) { s=readreg(s,2); d=writereg(d,4); } else { /* If we try to lock this twice, with different sizes, we are int trouble! */ s=d=rmw(s,4,2); } raw_sign_extend_16_rr(d,s); if (!isrmw) { unlock(d); unlock(s); } else { unlock(s); } } MENDFUNC(2,sign_extend_16_rr,(W4 d, R2 s)) MIDFUNC(2,sign_extend_8_rr,(W4 d, R1 s)) { int isrmw; if (isconst(s)) { set_const(d,(uae_s32)(uae_s8)live.state[s].val); return; } isrmw=(s==d); CLOBBER_SE8; if (!isrmw) { s=readreg(s,1); d=writereg(d,4); } else { /* If we try to lock this twice, with different sizes, we are int trouble! */ s=d=rmw(s,4,1); } raw_sign_extend_8_rr(d,s); if (!isrmw) { unlock(d); unlock(s); } else { unlock(s); } } MENDFUNC(2,sign_extend_8_rr,(W4 d, R1 s)) MIDFUNC(2,zero_extend_16_rr,(W4 d, R2 s)) { int isrmw; if (isconst(s)) { set_const(d,(uae_u32)(uae_u16)live.state[s].val); return; } isrmw=(s==d); CLOBBER_ZE16; if (!isrmw) { s=readreg(s,2); d=writereg(d,4); } else { /* If we try to lock this twice, with different sizes, we are int trouble! */ s=d=rmw(s,4,2); } raw_zero_extend_16_rr(d,s); if (!isrmw) { unlock(d); unlock(s); } else { unlock(s); } } MENDFUNC(2,zero_extend_16_rr,(W4 d, R2 s)) MIDFUNC(2,zero_extend_8_rr,(W4 d, R1 s)) { int isrmw; if (isconst(s)) { set_const(d,(uae_u32)(uae_u8)live.state[s].val); return; } isrmw=(s==d); CLOBBER_ZE8; if (!isrmw) { s=readreg(s,1); d=writereg(d,4); } else { /* If we try to lock this twice, with different sizes, we are int trouble! */ s=d=rmw(s,4,1); } raw_zero_extend_8_rr(d,s); if (!isrmw) { unlock(d); unlock(s); } else { unlock(s); } } MENDFUNC(2,zero_extend_8_rr,(W4 d, R1 s)) MIDFUNC(2,mov_b_rr,(W1 d, R1 s)) { if (d==s) return; if (isconst(s)) { COMPCALL(mov_b_ri)(d,(uae_u8)live.state[s].val); return; } CLOBBER_MOV; s=readreg(s,1); d=writereg(d,1); raw_mov_b_rr(d,s); unlock(d); unlock(s); } MENDFUNC(2,mov_b_rr,(W1 d, R1 s)) MIDFUNC(2,mov_w_rr,(W2 d, R2 s)) { if (d==s) return; if (isconst(s)) { COMPCALL(mov_w_ri)(d,(uae_u16)live.state[s].val); return; } CLOBBER_MOV; s=readreg(s,2); d=writereg(d,2); raw_mov_w_rr(d,s); unlock(d); unlock(s); } MENDFUNC(2,mov_w_rr,(W2 d, R2 s)) MIDFUNC(4,mov_l_rrm_indexed,(W4 d,R4 baser, R4 index, IMM factor)) { CLOBBER_MOV; baser=readreg(baser,4); index=readreg(index,4); d=writereg(d,4); raw_mov_l_rrm_indexed(d,baser,index,factor); unlock(d); unlock(baser); unlock(index); } MENDFUNC(4,mov_l_rrm_indexed,(W4 d,R4 baser, R4 index, IMM factor)) MIDFUNC(4,mov_w_rrm_indexed,(W2 d, R4 baser, R4 index, IMM factor)) { CLOBBER_MOV; baser=readreg(baser,4); index=readreg(index,4); d=writereg(d,2); raw_mov_w_rrm_indexed(d,baser,index,factor); unlock(d); unlock(baser); unlock(index); } MENDFUNC(4,mov_w_rrm_indexed,(W2 d, R4 baser, R4 index, IMM factor)) MIDFUNC(4,mov_b_rrm_indexed,(W1 d, R4 baser, R4 index, IMM factor)) { CLOBBER_MOV; baser=readreg(baser,4); index=readreg(index,4); d=writereg(d,1); raw_mov_b_rrm_indexed(d,baser,index,factor); unlock(d); unlock(baser); unlock(index); } MENDFUNC(4,mov_b_rrm_indexed,(W1 d, R4 baser, R4 index, IMM factor)) MIDFUNC(4,mov_l_mrr_indexed,(R4 baser, R4 index, IMM factor, R4 s)) { CLOBBER_MOV; baser=readreg(baser,4); index=readreg(index,4); s=readreg(s,4); Dif (baser==s || index==s) abort(); raw_mov_l_mrr_indexed(baser,index,factor,s); unlock(s); unlock(baser); unlock(index); } MENDFUNC(4,mov_l_mrr_indexed,(R4 baser, R4 index, IMM factor, R4 s)) MIDFUNC(4,mov_w_mrr_indexed,(R4 baser, R4 index, IMM factor, R2 s)) { CLOBBER_MOV; baser=readreg(baser,4); index=readreg(index,4); s=readreg(s,2); raw_mov_w_mrr_indexed(baser,index,factor,s); unlock(s); unlock(baser); unlock(index); } MENDFUNC(4,mov_w_mrr_indexed,(R4 baser, R4 index, IMM factor, R2 s)) MIDFUNC(4,mov_b_mrr_indexed,(R4 baser, R4 index, IMM factor, R1 s)) { CLOBBER_MOV; s=readreg(s,1); baser=readreg(baser,4); index=readreg(index,4); raw_mov_b_mrr_indexed(baser,index,factor,s); unlock(s); unlock(baser); unlock(index); } MENDFUNC(4,mov_b_mrr_indexed,(R4 baser, R4 index, IMM factor, R1 s)) MIDFUNC(5,mov_l_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R4 s)) { int basereg=baser; int indexreg=index; CLOBBER_MOV; s=readreg(s,4); baser=readreg_offset(baser,4); index=readreg_offset(index,4); base+=get_offset(basereg); base+=factor*get_offset(indexreg); raw_mov_l_bmrr_indexed(base,baser,index,factor,s); unlock(s); unlock(baser); unlock(index); } MENDFUNC(5,mov_l_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R4 s)) MIDFUNC(5,mov_w_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R2 s)) { int basereg=baser; int indexreg=index; CLOBBER_MOV; s=readreg(s,2); baser=readreg_offset(baser,4); index=readreg_offset(index,4); base+=get_offset(basereg); base+=factor*get_offset(indexreg); raw_mov_w_bmrr_indexed(base,baser,index,factor,s); unlock(s); unlock(baser); unlock(index); } MENDFUNC(5,mov_w_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R2 s)) MIDFUNC(5,mov_b_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R1 s)) { int basereg=baser; int indexreg=index; CLOBBER_MOV; s=readreg(s,1); baser=readreg_offset(baser,4); index=readreg_offset(index,4); base+=get_offset(basereg); base+=factor*get_offset(indexreg); raw_mov_b_bmrr_indexed(base,baser,index,factor,s); unlock(s); unlock(baser); unlock(index); } MENDFUNC(5,mov_b_bmrr_indexed,(IMM base, R4 baser, R4 index, IMM factor, R1 s)) /* Read a long from base+baser+factor*index */ MIDFUNC(5,mov_l_brrm_indexed,(W4 d, IMM base, R4 baser, R4 index, IMM factor)) { int basereg=baser; int indexreg=index; CLOBBER_MOV; baser=readreg_offset(baser,4); index=readreg_offset(index,4); base+=get_offset(basereg); base+=factor*get_offset(indexreg); d=writereg(d,4); raw_mov_l_brrm_indexed(d,base,baser,index,factor); unlock(d); unlock(baser); unlock(index); } MENDFUNC(5,mov_l_brrm_indexed,(W4 d, IMM base, R4 baser, R4 index, IMM factor)) MIDFUNC(5,mov_w_brrm_indexed,(W2 d, IMM base, R4 baser, R4 index, IMM factor)) { int basereg=baser; int indexreg=index; CLOBBER_MOV; remove_offset(d,-1); baser=readreg_offset(baser,4); index=readreg_offset(index,4); base+=get_offset(basereg); base+=factor*get_offset(indexreg); d=writereg(d,2); raw_mov_w_brrm_indexed(d,base,baser,index,factor); unlock(d); unlock(baser); unlock(index); } MENDFUNC(5,mov_w_brrm_indexed,(W2 d, IMM base, R4 baser, R4 index, IMM factor)) MIDFUNC(5,mov_b_brrm_indexed,(W1 d, IMM base, R4 baser, R4 index, IMM factor)) { int basereg=baser; int indexreg=index; CLOBBER_MOV; remove_offset(d,-1); baser=readreg_offset(baser,4); index=readreg_offset(index,4); base+=get_offset(basereg); base+=factor*get_offset(indexreg); d=writereg(d,1); raw_mov_b_brrm_indexed(d,base,baser,index,factor); unlock(d); unlock(baser); unlock(index); } MENDFUNC(5,mov_b_brrm_indexed,(W1 d, IMM base, R4 baser, R4 index, IMM factor)) /* Read a long from base+factor*index */ MIDFUNC(4,mov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor)) { int indexreg=index; if (isconst(index)) { COMPCALL(mov_l_rm)(d,base+factor*live.state[index].val); return; } CLOBBER_MOV; index=readreg_offset(index,4); base+=get_offset(indexreg)*factor; d=writereg(d,4); raw_mov_l_rm_indexed(d,base,index,factor); unlock(index); unlock(d); } MENDFUNC(4,mov_l_rm_indexed,(W4 d, IMM base, R4 index, IMM factor)) /* read the long at the address contained in s+offset and store in d */ MIDFUNC(3,mov_l_rR,(W4 d, R4 s, IMM offset)) { if (isconst(s)) { COMPCALL(mov_l_rm)(d,live.state[s].val+offset); return; } CLOBBER_MOV; s=readreg(s,4); d=writereg(d,4); raw_mov_l_rR(d,s,offset); unlock(d); unlock(s); } MENDFUNC(3,mov_l_rR,(W4 d, R4 s, IMM offset)) /* read the word at the address contained in s+offset and store in d */ MIDFUNC(3,mov_w_rR,(W2 d, R4 s, IMM offset)) { if (isconst(s)) { COMPCALL(mov_w_rm)(d,live.state[s].val+offset); return; } CLOBBER_MOV; s=readreg(s,4); d=writereg(d,2); raw_mov_w_rR(d,s,offset); unlock(d); unlock(s); } MENDFUNC(3,mov_w_rR,(W2 d, R4 s, IMM offset)) /* read the word at the address contained in s+offset and store in d */ MIDFUNC(3,mov_b_rR,(W1 d, R4 s, IMM offset)) { if (isconst(s)) { COMPCALL(mov_b_rm)(d,live.state[s].val+offset); return; } CLOBBER_MOV; s=readreg(s,4); d=writereg(d,1); raw_mov_b_rR(d,s,offset); unlock(d); unlock(s); } MENDFUNC(3,mov_b_rR,(W1 d, R4 s, IMM offset)) /* read the long at the address contained in s+offset and store in d */ MIDFUNC(3,mov_l_brR,(W4 d, R4 s, IMM offset)) { int sreg=s; if (isconst(s)) { COMPCALL(mov_l_rm)(d,live.state[s].val+offset); return; } CLOBBER_MOV; s=readreg_offset(s,4); offset+=get_offset(sreg); d=writereg(d,4); raw_mov_l_brR(d,s,offset); unlock(d); unlock(s); } MENDFUNC(3,mov_l_brR,(W4 d, R4 s, IMM offset)) /* read the word at the address contained in s+offset and store in d */ MIDFUNC(3,mov_w_brR,(W2 d, R4 s, IMM offset)) { int sreg=s; if (isconst(s)) { COMPCALL(mov_w_rm)(d,live.state[s].val+offset); return; } CLOBBER_MOV; remove_offset(d,-1); s=readreg_offset(s,4); offset+=get_offset(sreg); d=writereg(d,2); raw_mov_w_brR(d,s,offset); unlock(d); unlock(s); } MENDFUNC(3,mov_w_brR,(W2 d, R4 s, IMM offset)) /* read the word at the address contained in s+offset and store in d */ MIDFUNC(3,mov_b_brR,(W1 d, R4 s, IMM offset)) { int sreg=s; if (isconst(s)) { COMPCALL(mov_b_rm)(d,live.state[s].val+offset); return; } CLOBBER_MOV; remove_offset(d,-1); s=readreg_offset(s,4); offset+=get_offset(sreg); d=writereg(d,1); raw_mov_b_brR(d,s,offset); unlock(d); unlock(s); } MENDFUNC(3,mov_b_brR,(W1 d, R4 s, IMM offset)) MIDFUNC(3,mov_l_Ri,(R4 d, IMM i, IMM offset)) { int dreg=d; if (isconst(d)) { COMPCALL(mov_l_mi)(live.state[d].val+offset,i); return; } CLOBBER_MOV; d=readreg_offset(d,4); offset+=get_offset(dreg); raw_mov_l_Ri(d,i,offset); unlock(d); } MENDFUNC(3,mov_l_Ri,(R4 d, IMM i, IMM offset)) MIDFUNC(3,mov_w_Ri,(R4 d, IMM i, IMM offset)) { int dreg=d; if (isconst(d)) { COMPCALL(mov_w_mi)(live.state[d].val+offset,i); return; } CLOBBER_MOV; d=readreg_offset(d,4); offset+=get_offset(dreg); raw_mov_w_Ri(d,i,offset); unlock(d); } MENDFUNC(3,mov_w_Ri,(R4 d, IMM i, IMM offset)) MIDFUNC(3,mov_b_Ri,(R4 d, IMM i, IMM offset)) { int dreg=d; if (isconst(d)) { COMPCALL(mov_b_mi)(live.state[d].val+offset,i); return; } CLOBBER_MOV; d=readreg_offset(d,4); offset+=get_offset(dreg); raw_mov_b_Ri(d,i,offset); unlock(d); } MENDFUNC(3,mov_b_Ri,(R4 d, IMM i, IMM offset)) /* Warning! OFFSET is byte sized only! */ MIDFUNC(3,mov_l_Rr,(R4 d, R4 s, IMM offset)) { if (isconst(d)) { COMPCALL(mov_l_mr)(live.state[d].val+offset,s); return; } if (isconst(s)) { COMPCALL(mov_l_Ri)(d,live.state[s].val,offset); return; } CLOBBER_MOV; s=readreg(s,4); d=readreg(d,4); raw_mov_l_Rr(d,s,offset); unlock(d); unlock(s); } MENDFUNC(3,mov_l_Rr,(R4 d, R4 s, IMM offset)) MIDFUNC(3,mov_w_Rr,(R4 d, R2 s, IMM offset)) { if (isconst(d)) { COMPCALL(mov_w_mr)(live.state[d].val+offset,s); return; } if (isconst(s)) { COMPCALL(mov_w_Ri)(d,(uae_u16)live.state[s].val,offset); return; } CLOBBER_MOV; s=readreg(s,2); d=readreg(d,4); raw_mov_w_Rr(d,s,offset); unlock(d); unlock(s); } MENDFUNC(3,mov_w_Rr,(R4 d, R2 s, IMM offset)) MIDFUNC(3,mov_b_Rr,(R4 d, R1 s, IMM offset)) { if (isconst(d)) { COMPCALL(mov_b_mr)(live.state[d].val+offset,s); return; } if (isconst(s)) { COMPCALL(mov_b_Ri)(d,(uae_u8)live.state[s].val,offset); return; } CLOBBER_MOV; s=readreg(s,1); d=readreg(d,4); raw_mov_b_Rr(d,s,offset); unlock(d); unlock(s); } MENDFUNC(3,mov_b_Rr,(R4 d, R1 s, IMM offset)) MIDFUNC(3,lea_l_brr,(W4 d, R4 s, IMM offset)) { if (isconst(s)) { COMPCALL(mov_l_ri)(d,live.state[s].val+offset); return; } #if USE_OFFSET if (d==s) { add_offset(d,offset); return; } #endif CLOBBER_LEA; s=readreg(s,4); d=writereg(d,4); raw_lea_l_brr(d,s,offset); unlock(d); unlock(s); } MENDFUNC(3,lea_l_brr,(W4 d, R4 s, IMM offset)) MIDFUNC(5,lea_l_brr_indexed,(W4 d, R4 s, R4 index, IMM factor, IMM offset)) { if (!offset) { COMPCALL(lea_l_rr_indexed)(d,s,index,factor); return; } CLOBBER_LEA; s=readreg(s,4); index=readreg(index,4); d=writereg(d,4); raw_lea_l_brr_indexed(d,s,index,factor,offset); unlock(d); unlock(index); unlock(s); } MENDFUNC(5,lea_l_brr_indexed,(W4 d, R4 s, R4 index, IMM factor, IMM offset)) MIDFUNC(4,lea_l_rr_indexed,(W4 d, R4 s, R4 index, IMM factor)) { CLOBBER_LEA; s=readreg(s,4); index=readreg(index,4); d=writereg(d,4); raw_lea_l_rr_indexed(d,s,index,factor); unlock(d); unlock(index); unlock(s); } MENDFUNC(4,lea_l_rr_indexed,(W4 d, R4 s, R4 index, IMM factor)) /* write d to the long at the address contained in s+offset */ MIDFUNC(3,mov_l_bRr,(R4 d, R4 s, IMM offset)) { int dreg=d; if (isconst(d)) { COMPCALL(mov_l_mr)(live.state[d].val+offset,s); return; } CLOBBER_MOV; s=readreg(s,4); d=readreg_offset(d,4); offset+=get_offset(dreg); raw_mov_l_bRr(d,s,offset); unlock(d); unlock(s); } MENDFUNC(3,mov_l_bRr,(R4 d, R4 s, IMM offset)) /* write the word at the address contained in s+offset and store in d */ MIDFUNC(3,mov_w_bRr,(R4 d, R2 s, IMM offset)) { int dreg=d; if (isconst(d)) { COMPCALL(mov_w_mr)(live.state[d].val+offset,s); return; } CLOBBER_MOV; s=readreg(s,2); d=readreg_offset(d,4); offset+=get_offset(dreg); raw_mov_w_bRr(d,s,offset); unlock(d); unlock(s); } MENDFUNC(3,mov_w_bRr,(R4 d, R2 s, IMM offset)) MIDFUNC(3,mov_b_bRr,(R4 d, R1 s, IMM offset)) { int dreg=d; if (isconst(d)) { COMPCALL(mov_b_mr)(live.state[d].val+offset,s); return; } CLOBBER_MOV; s=readreg(s,1); d=readreg_offset(d,4); offset+=get_offset(dreg); raw_mov_b_bRr(d,s,offset); unlock(d); unlock(s); } MENDFUNC(3,mov_b_bRr,(R4 d, R1 s, IMM offset)) MIDFUNC(1,gen_bswap_32,(RW4 r)) { if (isconst(r)) { uae_u32 oldv=live.state[r].val; live.state[r].val=reverse32(oldv); return; } CLOBBER_SW32; r=rmw(r,4,4); raw_bswap_32(r); unlock(r); } MENDFUNC(1,gen_bswap_32,(RW4 r)) MIDFUNC(1,gen_bswap_16,(RW2 r)) { if (isconst(r)) { uae_u32 oldv=live.state[r].val; live.state[r].val=((oldv>>8)&0xff) | ((oldv<<8)&0xff00) | (oldv&0xffff0000); return; } CLOBBER_SW16; r=rmw(r,2,2); raw_bswap_16(r); unlock(r); } MENDFUNC(1,gen_bswap_16,(RW2 r)) MIDFUNC(2,mov_l_rr,(W4 d, R4 s)) { int olds; if (d==s) { /* How pointless! */ return; } if (isconst(s)) { COMPCALL(mov_l_ri)(d,live.state[s].val); return; } #if USE_ALIAS olds=s; disassociate(d); s=readreg_offset(s,4); live.state[d].realreg=s; live.state[d].realind=live.nat[s].nholds; live.state[d].val=live.state[olds].val; live.state[d].validsize=4; live.state[d].dirtysize=4; set_status(d,DIRTY); live.nat[s].holds[live.nat[s].nholds]=d; live.nat[s].nholds++; log_clobberreg(d); /* printf("Added %d to nreg %d(%d), now holds %d regs\n", d,s,live.state[d].realind,live.nat[s].nholds); */ unlock(s); #else CLOBBER_MOV; s=readreg(s,4); d=writereg(d,4); raw_mov_l_rr(d,s); unlock(d); unlock(s); #endif } MENDFUNC(2,mov_l_rr,(W4 d, R4 s)) MIDFUNC(2,mov_l_mr,(IMM d, R4 s)) { if (isconst(s)) { COMPCALL(mov_l_mi)(d,live.state[s].val); return; } CLOBBER_MOV; s=readreg(s,4); raw_mov_l_mr(d,s); unlock(s); } MENDFUNC(2,mov_l_mr,(IMM d, R4 s)) MIDFUNC(2,mov_w_mr,(IMM d, R2 s)) { if (isconst(s)) { COMPCALL(mov_w_mi)(d,(uae_u16)live.state[s].val); return; } CLOBBER_MOV; s=readreg(s,2); raw_mov_w_mr(d,s); unlock(s); } MENDFUNC(2,mov_w_mr,(IMM d, R2 s)) MIDFUNC(2,mov_w_rm,(W2 d, IMM s)) { CLOBBER_MOV; d=writereg(d,2); raw_mov_w_rm(d,s); unlock(d); } MENDFUNC(2,mov_w_rm,(W2 d, IMM s)) MIDFUNC(2,mov_b_mr,(IMM d, R1 s)) { if (isconst(s)) { COMPCALL(mov_b_mi)(d,(uae_u8)live.state[s].val); return; } CLOBBER_MOV; s=readreg(s,1); raw_mov_b_mr(d,s); unlock(s); } MENDFUNC(2,mov_b_mr,(IMM d, R1 s)) MIDFUNC(2,mov_b_rm,(W1 d, IMM s)) { CLOBBER_MOV; d=writereg(d,1); raw_mov_b_rm(d,s); unlock(d); } MENDFUNC(2,mov_b_rm,(W1 d, IMM s)) MIDFUNC(2,mov_l_ri,(W4 d, IMM s)) { set_const(d,s); return; } MENDFUNC(2,mov_l_ri,(W4 d, IMM s)) MIDFUNC(2,mov_w_ri,(W2 d, IMM s)) { CLOBBER_MOV; d=writereg(d,2); raw_mov_w_ri(d,s); unlock(d); } MENDFUNC(2,mov_w_ri,(W2 d, IMM s)) MIDFUNC(2,mov_b_ri,(W1 d, IMM s)) { CLOBBER_MOV; d=writereg(d,1); raw_mov_b_ri(d,s); unlock(d); } MENDFUNC(2,mov_b_ri,(W1 d, IMM s)) MIDFUNC(2,add_l_mi,(IMM d, IMM s)) { CLOBBER_ADD; raw_add_l_mi(d,s) ; } MENDFUNC(2,add_l_mi,(IMM d, IMM s)) MIDFUNC(2,add_w_mi,(IMM d, IMM s)) { CLOBBER_ADD; raw_add_w_mi(d,s) ; } MENDFUNC(2,add_w_mi,(IMM d, IMM s)) MIDFUNC(2,add_b_mi,(IMM d, IMM s)) { CLOBBER_ADD; raw_add_b_mi(d,s) ; } MENDFUNC(2,add_b_mi,(IMM d, IMM s)) MIDFUNC(2,test_l_ri,(R4 d, IMM i)) { CLOBBER_TEST; d=readreg(d,4); raw_test_l_ri(d,i); unlock(d); } MENDFUNC(2,test_l_ri,(R4 d, IMM i)) MIDFUNC(2,test_l_rr,(R4 d, R4 s)) { CLOBBER_TEST; d=readreg(d,4); s=readreg(s,4); raw_test_l_rr(d,s);; unlock(d); unlock(s); } MENDFUNC(2,test_l_rr,(R4 d, R4 s)) MIDFUNC(2,test_w_rr,(R2 d, R2 s)) { CLOBBER_TEST; d=readreg(d,2); s=readreg(s,2); raw_test_w_rr(d,s); unlock(d); unlock(s); } MENDFUNC(2,test_w_rr,(R2 d, R2 s)) MIDFUNC(2,test_b_rr,(R1 d, R1 s)) { CLOBBER_TEST; d=readreg(d,1); s=readreg(s,1); raw_test_b_rr(d,s); unlock(d); unlock(s); } MENDFUNC(2,test_b_rr,(R1 d, R1 s)) MIDFUNC(2,and_l_ri,(RW4 d, IMM i)) { if (isconst (d) && ! needflags) { live.state[d].val &= i; return; } CLOBBER_AND; d=rmw(d,4,4); raw_and_l_ri(d,i); unlock(d); } MENDFUNC(2,and_l_ri,(RW4 d, IMM i)) MIDFUNC(2,and_l,(RW4 d, R4 s)) { CLOBBER_AND; s=readreg(s,4); d=rmw(d,4,4); raw_and_l(d,s); unlock(d); unlock(s); } MENDFUNC(2,and_l,(RW4 d, R4 s)) MIDFUNC(2,and_w,(RW2 d, R2 s)) { CLOBBER_AND; s=readreg(s,2); d=rmw(d,2,2); raw_and_w(d,s); unlock(d); unlock(s); } MENDFUNC(2,and_w,(RW2 d, R2 s)) MIDFUNC(2,and_b,(RW1 d, R1 s)) { CLOBBER_AND; s=readreg(s,1); d=rmw(d,1,1); raw_and_b(d,s); unlock(d); unlock(s); } MENDFUNC(2,and_b,(RW1 d, R1 s)) MIDFUNC(2,or_l_ri,(RW4 d, IMM i)) { if (isconst(d) && !needflags) { live.state[d].val|=i; return; } CLOBBER_OR; d=rmw(d,4,4); raw_or_l_ri(d,i); unlock(d); } MENDFUNC(2,or_l_ri,(RW4 d, IMM i)) MIDFUNC(2,or_l,(RW4 d, R4 s)) { if (isconst(d) && isconst(s) && !needflags) { live.state[d].val|=live.state[s].val; return; } CLOBBER_OR; s=readreg(s,4); d=rmw(d,4,4); raw_or_l(d,s); unlock(d); unlock(s); } MENDFUNC(2,or_l,(RW4 d, R4 s)) MIDFUNC(2,or_w,(RW2 d, R2 s)) { CLOBBER_OR; s=readreg(s,2); d=rmw(d,2,2); raw_or_w(d,s); unlock(d); unlock(s); } MENDFUNC(2,or_w,(RW2 d, R2 s)) MIDFUNC(2,or_b,(RW1 d, R1 s)) { CLOBBER_OR; s=readreg(s,1); d=rmw(d,1,1); raw_or_b(d,s); unlock(d); unlock(s); } MENDFUNC(2,or_b,(RW1 d, R1 s)) MIDFUNC(2,adc_l,(RW4 d, R4 s)) { CLOBBER_ADC; s=readreg(s,4); d=rmw(d,4,4); raw_adc_l(d,s); unlock(d); unlock(s); } MENDFUNC(2,adc_l,(RW4 d, R4 s)) MIDFUNC(2,adc_w,(RW2 d, R2 s)) { CLOBBER_ADC; s=readreg(s,2); d=rmw(d,2,2); raw_adc_w(d,s); unlock(d); unlock(s); } MENDFUNC(2,adc_w,(RW2 d, R2 s)) MIDFUNC(2,adc_b,(RW1 d, R1 s)) { CLOBBER_ADC; s=readreg(s,1); d=rmw(d,1,1); raw_adc_b(d,s); unlock(d); unlock(s); } MENDFUNC(2,adc_b,(RW1 d, R1 s)) MIDFUNC(2,add_l,(RW4 d, R4 s)) { if (isconst(s)) { COMPCALL(add_l_ri)(d,live.state[s].val); return; } CLOBBER_ADD; s=readreg(s,4); d=rmw(d,4,4); raw_add_l(d,s); unlock(d); unlock(s); } MENDFUNC(2,add_l,(RW4 d, R4 s)) MIDFUNC(2,add_w,(RW2 d, R2 s)) { if (isconst(s)) { COMPCALL(add_w_ri)(d,(uae_u16)live.state[s].val); return; } CLOBBER_ADD; s=readreg(s,2); d=rmw(d,2,2); raw_add_w(d,s); unlock(d); unlock(s); } MENDFUNC(2,add_w,(RW2 d, R2 s)) MIDFUNC(2,add_b,(RW1 d, R1 s)) { if (isconst(s)) { COMPCALL(add_b_ri)(d,(uae_u8)live.state[s].val); return; } CLOBBER_ADD; s=readreg(s,1); d=rmw(d,1,1); raw_add_b(d,s); unlock(d); unlock(s); } MENDFUNC(2,add_b,(RW1 d, R1 s)) MIDFUNC(2,sub_l_ri,(RW4 d, IMM i)) { if (!i && !needflags) return; if (isconst(d) && !needflags) { live.state[d].val-=i; return; } #if USE_OFFSET if (!needflags) { add_offset(d,-(signed)i); return; } #endif CLOBBER_SUB; d=rmw(d,4,4); raw_sub_l_ri(d,i); unlock(d); } MENDFUNC(2,sub_l_ri,(RW4 d, IMM i)) MIDFUNC(2,sub_w_ri,(RW2 d, IMM i)) { if (!i && !needflags) return; CLOBBER_SUB; d=rmw(d,2,2); raw_sub_w_ri(d,i); unlock(d); } MENDFUNC(2,sub_w_ri,(RW2 d, IMM i)) MIDFUNC(2,sub_b_ri,(RW1 d, IMM i)) { if (!i && !needflags) return; CLOBBER_SUB; d=rmw(d,1,1); raw_sub_b_ri(d,i); unlock(d); } MENDFUNC(2,sub_b_ri,(RW1 d, IMM i)) MIDFUNC(2,add_l_ri,(RW4 d, IMM i)) { if (!i && !needflags) return; if (isconst(d) && !needflags) { live.state[d].val+=i; return; } #if USE_OFFSET if (!needflags) { add_offset(d,i); return; } #endif CLOBBER_ADD; d=rmw(d,4,4); raw_add_l_ri(d,i); unlock(d); } MENDFUNC(2,add_l_ri,(RW4 d, IMM i)) MIDFUNC(2,add_w_ri,(RW2 d, IMM i)) { if (!i && !needflags) return; CLOBBER_ADD; d=rmw(d,2,2); raw_add_w_ri(d,i); unlock(d); } MENDFUNC(2,add_w_ri,(RW2 d, IMM i)) MIDFUNC(2,add_b_ri,(RW1 d, IMM i)) { if (!i && !needflags) return; CLOBBER_ADD; d=rmw(d,1,1); raw_add_b_ri(d,i); unlock(d); } MENDFUNC(2,add_b_ri,(RW1 d, IMM i)) MIDFUNC(2,sbb_l,(RW4 d, R4 s)) { CLOBBER_SBB; s=readreg(s,4); d=rmw(d,4,4); raw_sbb_l(d,s); unlock(d); unlock(s); } MENDFUNC(2,sbb_l,(RW4 d, R4 s)) MIDFUNC(2,sbb_w,(RW2 d, R2 s)) { CLOBBER_SBB; s=readreg(s,2); d=rmw(d,2,2); raw_sbb_w(d,s); unlock(d); unlock(s); } MENDFUNC(2,sbb_w,(RW2 d, R2 s)) MIDFUNC(2,sbb_b,(RW1 d, R1 s)) { CLOBBER_SBB; s=readreg(s,1); d=rmw(d,1,1); raw_sbb_b(d,s); unlock(d); unlock(s); } MENDFUNC(2,sbb_b,(RW1 d, R1 s)) MIDFUNC(2,sub_l,(RW4 d, R4 s)) { if (isconst(s)) { COMPCALL(sub_l_ri)(d,live.state[s].val); return; } CLOBBER_SUB; s=readreg(s,4); d=rmw(d,4,4); raw_sub_l(d,s); unlock(d); unlock(s); } MENDFUNC(2,sub_l,(RW4 d, R4 s)) MIDFUNC(2,sub_w,(RW2 d, R2 s)) { if (isconst(s)) { COMPCALL(sub_w_ri)(d,(uae_u16)live.state[s].val); return; } CLOBBER_SUB; s=readreg(s,2); d=rmw(d,2,2); raw_sub_w(d,s); unlock(d); unlock(s); } MENDFUNC(2,sub_w,(RW2 d, R2 s)) MIDFUNC(2,sub_b,(RW1 d, R1 s)) { if (isconst(s)) { COMPCALL(sub_b_ri)(d,(uae_u8)live.state[s].val); return; } CLOBBER_SUB; s=readreg(s,1); d=rmw(d,1,1); raw_sub_b(d,s); unlock(d); unlock(s); } MENDFUNC(2,sub_b,(RW1 d, R1 s)) MIDFUNC(2,cmp_l,(R4 d, R4 s)) { CLOBBER_CMP; s=readreg(s,4); d=readreg(d,4); raw_cmp_l(d,s); unlock(d); unlock(s); } MENDFUNC(2,cmp_l,(R4 d, R4 s)) MIDFUNC(2,cmp_l_ri,(R4 r, IMM i)) { CLOBBER_CMP; r=readreg(r,4); raw_cmp_l_ri(r,i); unlock(r); } MENDFUNC(2,cmp_l_ri,(R4 r, IMM i)) MIDFUNC(2,cmp_w,(R2 d, R2 s)) { CLOBBER_CMP; s=readreg(s,2); d=readreg(d,2); raw_cmp_w(d,s); unlock(d); unlock(s); } MENDFUNC(2,cmp_w,(R2 d, R2 s)) MIDFUNC(2,cmp_b,(R1 d, R1 s)) { CLOBBER_CMP; s=readreg(s,1); d=readreg(d,1); raw_cmp_b(d,s); unlock(d); unlock(s); } MENDFUNC(2,cmp_b,(R1 d, R1 s)) MIDFUNC(2,xor_l,(RW4 d, R4 s)) { CLOBBER_XOR; s=readreg(s,4); d=rmw(d,4,4); raw_xor_l(d,s); unlock(d); unlock(s); } MENDFUNC(2,xor_l,(RW4 d, R4 s)) MIDFUNC(2,xor_w,(RW2 d, R2 s)) { CLOBBER_XOR; s=readreg(s,2); d=rmw(d,2,2); raw_xor_w(d,s); unlock(d); unlock(s); } MENDFUNC(2,xor_w,(RW2 d, R2 s)) MIDFUNC(2,xor_b,(RW1 d, R1 s)) { CLOBBER_XOR; s=readreg(s,1); d=rmw(d,1,1); raw_xor_b(d,s); unlock(d); unlock(s); } MENDFUNC(2,xor_b,(RW1 d, R1 s)) MIDFUNC(5,call_r_11,(W4 out1, R4 r, R4 in1, IMM osize, IMM isize)) { clobber_flags(); remove_all_offsets(); if (osize==4) { if (out1!=in1 && out1!=r) { COMPCALL(forget_about)(out1); } } else { tomem_c(out1); } in1=readreg_specific(in1,isize,REG_PAR1); r=readreg(r,4); prepare_for_call_1(); /* This should ensure that there won't be any need for swapping nregs in prepare_for_call_2 */ #if USE_NORMAL_CALLING_CONVENTION raw_push_l_r(in1); #endif unlock(in1); unlock(r); prepare_for_call_2(); raw_call_r(r); #if USE_NORMAL_CALLING_CONVENTION raw_inc_sp(4); #endif live.nat[REG_RESULT].holds[0]=out1; live.nat[REG_RESULT].nholds=1; live.nat[REG_RESULT].touched=touchcnt++; live.state[out1].realreg=REG_RESULT; live.state[out1].realind=0; live.state[out1].val=0; live.state[out1].validsize=osize; live.state[out1].dirtysize=osize; set_status(out1,DIRTY); } MENDFUNC(5,call_r_11,(W4 out1, R4 r, R4 in1, IMM osize, IMM isize)) MIDFUNC(5,call_r_02,(R4 r, R4 in1, R4 in2, IMM isize1, IMM isize2)) { clobber_flags(); remove_all_offsets(); in1=readreg_specific(in1,isize1,REG_PAR1); in2=readreg_specific(in2,isize2,REG_PAR2); r=readreg(r,4); prepare_for_call_1(); /* This should ensure that there won't be any need for swapping nregs in prepare_for_call_2 */ #if USE_NORMAL_CALLING_CONVENTION raw_push_l_r(in2); raw_push_l_r(in1); #endif unlock(r); unlock(in1); unlock(in2); prepare_for_call_2(); raw_call_r(r); #if USE_NORMAL_CALLING_CONVENTION raw_inc_sp(8); #endif } MENDFUNC(5,call_r_02,(R4 r, R4 in1, R4 in2, IMM isize1, IMM isize2)) MIDFUNC(1,forget_about,(W4 r)) { if (isinreg(r)) disassociate(r); live.state[r].val=0; set_status(r,UNDEF); } MENDFUNC(1,forget_about,(W4 r)) MIDFUNC(0,nop,(void)) { raw_nop(); } MENDFUNC(0,nop,(void)) MIDFUNC(1,f_forget_about,(FW r)) { if (f_isinreg(r)) f_disassociate(r); live.fate[r].status=UNDEF; } MENDFUNC(1,f_forget_about,(FW r)) MIDFUNC(1,fmov_pi,(FW r)) { r=f_writereg(r); raw_fmov_pi(r); f_unlock(r); } MENDFUNC(1,fmov_pi,(FW r)) MIDFUNC(1,fmov_log10_2,(FW r)) { r=f_writereg(r); raw_fmov_log10_2(r); f_unlock(r); } MENDFUNC(1,fmov_log10_2,(FW r)) MIDFUNC(1,fmov_log2_e,(FW r)) { r=f_writereg(r); raw_fmov_log2_e(r); f_unlock(r); } MENDFUNC(1,fmov_log2_e,(FW r)) MIDFUNC(1,fmov_loge_2,(FW r)) { r=f_writereg(r); raw_fmov_loge_2(r); f_unlock(r); } MENDFUNC(1,fmov_loge_2,(FW r)) MIDFUNC(1,fmov_1,(FW r)) { r=f_writereg(r); raw_fmov_1(r); f_unlock(r); } MENDFUNC(1,fmov_1,(FW r)) MIDFUNC(1,fmov_0,(FW r)) { r=f_writereg(r); raw_fmov_0(r); f_unlock(r); } MENDFUNC(1,fmov_0,(FW r)) MIDFUNC(2,fmov_rm,(FW r, MEMR m)) { r=f_writereg(r); raw_fmov_rm(r,m); f_unlock(r); } MENDFUNC(2,fmov_rm,(FW r, MEMR m)) MIDFUNC(2,fmovi_rm,(FW r, MEMR m)) { r=f_writereg(r); raw_fmovi_rm(r,m); f_unlock(r); } MENDFUNC(2,fmovi_rm,(FW r, MEMR m)) MIDFUNC(2,fmovi_mr,(MEMW m, FR r)) { r=f_readreg(r); raw_fmovi_mr(m,r); f_unlock(r); } MENDFUNC(2,fmovi_mr,(MEMW m, FR r)) MIDFUNC(2,fmovs_rm,(FW r, MEMR m)) { r=f_writereg(r); raw_fmovs_rm(r,m); f_unlock(r); } MENDFUNC(2,fmovs_rm,(FW r, MEMR m)) MIDFUNC(2,fmovs_mr,(MEMW m, FR r)) { r=f_readreg(r); raw_fmovs_mr(m,r); f_unlock(r); } MENDFUNC(2,fmovs_mr,(MEMW m, FR r)) MIDFUNC(2,fmov_ext_mr,(MEMW m, FR r)) { r=f_readreg(r); raw_fmov_ext_mr(m,r); f_unlock(r); } MENDFUNC(2,fmov_ext_mr,(MEMW m, FR r)) MIDFUNC(2,fmov_mr,(MEMW m, FR r)) { r=f_readreg(r); raw_fmov_mr(m,r); f_unlock(r); } MENDFUNC(2,fmov_mr,(MEMW m, FR r)) MIDFUNC(2,fmov_ext_rm,(FW r, MEMR m)) { r=f_writereg(r); raw_fmov_ext_rm(r,m); f_unlock(r); } MENDFUNC(2,fmov_ext_rm,(FW r, MEMR m)) MIDFUNC(2,fmov_rr,(FW d, FR s)) { if (d==s) { /* How pointless! */ return; } #if USE_F_ALIAS f_disassociate(d); s=f_readreg(s); live.fate[d].realreg=s; live.fate[d].realind=live.fat[s].nholds; live.fate[d].status=DIRTY; live.fat[s].holds[live.fat[s].nholds]=d; live.fat[s].nholds++; f_unlock(s); #else s=f_readreg(s); d=f_writereg(d); raw_fmov_rr(d,s); f_unlock(s); f_unlock(d); #endif } MENDFUNC(2,fmov_rr,(FW d, FR s)) MIDFUNC(2,fldcw_m_indexed,(R4 index, IMM base)) { index=readreg(index,4); raw_fldcw_m_indexed(index,base); unlock(index); } MENDFUNC(2,fldcw_m_indexed,(R4 index, IMM base)) MIDFUNC(1,ftst_r,(FR r)) { r=f_readreg(r); raw_ftst_r(r); f_unlock(r); } MENDFUNC(1,ftst_r,(FR r)) MIDFUNC(0,dont_care_fflags,(void)) { f_disassociate(FP_RESULT); } MENDFUNC(0,dont_care_fflags,(void)) MIDFUNC(2,fsqrt_rr,(FW d, FR s)) { s=f_readreg(s); d=f_writereg(d); raw_fsqrt_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,fsqrt_rr,(FW d, FR s)) MIDFUNC(2,fabs_rr,(FW d, FR s)) { s=f_readreg(s); d=f_writereg(d); raw_fabs_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,fabs_rr,(FW d, FR s)) MIDFUNC(2,fsin_rr,(FW d, FR s)) { s=f_readreg(s); d=f_writereg(d); raw_fsin_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,fsin_rr,(FW d, FR s)) MIDFUNC(2,fcos_rr,(FW d, FR s)) { s=f_readreg(s); d=f_writereg(d); raw_fcos_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,fcos_rr,(FW d, FR s)) MIDFUNC(2,ftwotox_rr,(FW d, FR s)) { s=f_readreg(s); d=f_writereg(d); raw_ftwotox_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,ftwotox_rr,(FW d, FR s)) MIDFUNC(2,fetox_rr,(FW d, FR s)) { s=f_readreg(s); d=f_writereg(d); raw_fetox_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,fetox_rr,(FW d, FR s)) MIDFUNC(2,frndint_rr,(FW d, FR s)) { s=f_readreg(s); d=f_writereg(d); raw_frndint_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,frndint_rr,(FW d, FR s)) MIDFUNC(2,flog2_rr,(FW d, FR s)) { s=f_readreg(s); d=f_writereg(d); raw_flog2_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,flog2_rr,(FW d, FR s)) MIDFUNC(2,fneg_rr,(FW d, FR s)) { s=f_readreg(s); d=f_writereg(d); raw_fneg_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,fneg_rr,(FW d, FR s)) MIDFUNC(2,fadd_rr,(FRW d, FR s)) { s=f_readreg(s); d=f_rmw(d); raw_fadd_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,fadd_rr,(FRW d, FR s)) MIDFUNC(2,fsub_rr,(FRW d, FR s)) { s=f_readreg(s); d=f_rmw(d); raw_fsub_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,fsub_rr,(FRW d, FR s)) MIDFUNC(2,fcmp_rr,(FR d, FR s)) { d=f_readreg(d); s=f_readreg(s); raw_fcmp_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,fcmp_rr,(FR d, FR s)) MIDFUNC(2,fdiv_rr,(FRW d, FR s)) { s=f_readreg(s); d=f_rmw(d); raw_fdiv_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,fdiv_rr,(FRW d, FR s)) MIDFUNC(2,frem_rr,(FRW d, FR s)) { s=f_readreg(s); d=f_rmw(d); raw_frem_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,frem_rr,(FRW d, FR s)) MIDFUNC(2,frem1_rr,(FRW d, FR s)) { s=f_readreg(s); d=f_rmw(d); raw_frem1_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,frem1_rr,(FRW d, FR s)) MIDFUNC(2,fmul_rr,(FRW d, FR s)) { s=f_readreg(s); d=f_rmw(d); raw_fmul_rr(d,s); f_unlock(s); f_unlock(d); } MENDFUNC(2,fmul_rr,(FRW d, FR s)) /******************************************************************** * Support functions exposed to gencomp. CREATE time * ********************************************************************/ int kill_rodent(int r) { return KILLTHERAT && have_rat_stall && (live.state[r].status==INMEM || live.state[r].status==CLEAN || live.state[r].status==ISCONST || live.state[r].dirtysize==4); } uae_u32 get_const(int r) { Dif (!isconst(r)) { write_log ("JIT: Register %d should be constant, but isn't\n", r); abort(); } return live.state[r].val; } void sync_m68k_pc(void) { if (m68k_pc_offset) { add_l_ri(PC_P,m68k_pc_offset); comp_pc_p+=m68k_pc_offset; m68k_pc_offset=0; } } /******************************************************************** * Support functions exposed to newcpu * ********************************************************************/ uae_u32 scratch[VREGS]; #ifdef FPUEMU fptype fscratch[VFREGS]; #endif void init_comp(void) { int i; uae_u8* cb = (uae_u8 *)can_byte; uae_u8* cw = (uae_u8 *)can_word; uae_u8* au = (uae_u8 *)always_used; for (i=0;i1) abort(); if (live.nat[n].nholds && depthnat[i].validsize) vton[s->nat[i].holds]=i; flush_flags(); /* low level */ sync_m68k_pc(); /* mid level */ /* We don't do FREGS yet, so this is raw flush() code */ for (i=0;is->nat[vton[i]].dirtysize) tomem(i); /* Fall-through! */ case CLEAN: if (vton[i]==-1 || live.state[i].validsizenat[vton[i]].validsize) evict(i); else make_exclusive(i,0,-1); break; case INMEM: break; case UNDEF: break; default: write_log ("JIT: Weird status: %d\n", live.state[i].status); abort(); } } /* Quick consistency check */ for (i=0;is->nat[n].dirtysize) abort; if (live.state[i].validsizenat[n].validsize) abort; live.state[i].dirtysize=s->nat[n].dirtysize; live.state[i].validsize=s->nat[n].validsize; if (live.state[i].dirtysize) set_status(i,DIRTY); break; case UNDEF: break; } if (n!=-1) live.nat[n].touched=touchcnt++; } } #else static __inline__ void match_states(smallstate* s) { flush(1); } #endif /* Only do this if you really mean it! The next call should be to init!*/ void flush(int save_regs) { int i; log_flush(); flush_flags(); /* low level */ sync_m68k_pc(); /* mid level */ if (save_regs) { for (i=0;i= (uae_uintptr) kickmemory && addr < (uae_uintptr) kickmemory + 8 * 65536); } static void flush_all(void) { int i; log_flush(); for (i=0;i0) free_nreg(i); for (i=0;i0) f_free_nreg(i); live.flags_in_flags=TRASH; /* Note: We assume we already rescued the flags at the very start of the call_r functions! */ } /******************************************************************** * Memory access and related functions, CREATE time * ********************************************************************/ void register_branch (uae_u32 not_taken, uae_u32 taken, uae_u8 cond) { next_pc_p = not_taken; taken_pc_p = taken; branch_cc = cond; } static uae_uintptr get_handler_address (uae_uintptr addr) { blockinfo *bi = get_blockinfo_addr_new ((void *) addr, 0); return (uae_uintptr) &(bi->direct_handler_to_use); } static uae_uintptr get_handler (uae_uintptr addr) { blockinfo *bi = get_blockinfo_addr_new ((void *) addr, 0); return (uae_uintptr) bi->direct_handler_to_use; } static void load_handler (int reg, uae_uintptr addr) { mov_l_rm (reg, get_handler_address (addr)); } /* This version assumes that it is writing *real* memory, and *will* fail * if that assumption is wrong! No branches, no second chances, just * straight go-for-it attitude */ STATIC_INLINE void writemem_real (int address, int source, int offset, int size, int tmp, int clobber) { int f = tmp; #ifdef NATMEM_OFFSET if (canbang) { /* Woohoo! go directly at the memory! */ if (clobber) f = source; switch (size) { case 1: mov_b_bRr (address, source, NATMEM_OFFSET); break; case 2: mov_w_rr (f, source); gen_bswap_16 (f); mov_w_bRr (address, f, NATMEM_OFFSET); break; case 4: mov_l_rr (f, source); gen_bswap_32 (f); mov_l_bRr (address, f, NATMEM_OFFSET); break; } forget_about (tmp); forget_about (f); return; } #endif mov_l_rr (f, address); shrl_l_ri (f, 16); /* The index into the baseaddr table */ mov_l_rm_indexed (f, (uae_uintptr) baseaddr, f, 4); if (address == source && size > 1) { /* IBrowse does this! */ add_l (f, address); /* f now has the final address */ switch (size) { case 2: gen_bswap_16 (source); mov_w_Rr (f, source, 0); gen_bswap_16 (source); break; case 4: gen_bswap_32 (source); mov_l_Rr (f, source, 0); gen_bswap_32 (source); break; } } else { /* f now holds the offset */ switch (size) { case 1: mov_b_mrr_indexed (address,f,1,source); break; case 2: gen_bswap_16 (source); mov_w_mrr_indexed (address, f, 1, source); gen_bswap_16 (source); break; case 4: gen_bswap_32 (source); mov_l_mrr_indexed (address, f, 1, source); gen_bswap_32 (source); break; } } } STATIC_INLINE void writemem (int address, int source, int offset, int size, int tmp) { int f = tmp; mov_l_rr (f, address); shrl_l_ri (f, 16); /* The index into the mem bank table */ mov_l_rm_indexed (f, (uae_uintptr) mem_banks, f, 4); /* Now f holds a pointer to the actual membank */ mov_l_rR (f, f, offset); /* Now f holds the address of the b/w/lput function */ call_r_02 (f, address, source, 4, size); forget_about (tmp); } void writebyte (int address, int source, int tmp) { int distrust; switch (currprefs.comptrustbyte) { default: case 0: distrust = 0; break; case 1: distrust = 1; break; case 2: distrust = ((start_pc & 0xF80000) == 0xF80000); break; case 3: distrust = !have_done_picasso; break; } if ((special_mem & SPECIAL_MEM_WRITE) || distrust) writemem_special (address, source, 20, 1, tmp); else writemem_real (address, source, 20, 1, tmp, 0); } void writeword_general (int address, int source, int tmp, int clobber) { int distrust; switch (currprefs.comptrustword) { default: case 0: distrust = 0; break; case 1: distrust = 1; break; case 2: distrust = ((start_pc & 0xF80000) == 0xF80000); break; case 3: distrust = !have_done_picasso; break; } if ((special_mem & SPECIAL_MEM_WRITE) || distrust) writemem_special (address, source, 16, 2, tmp); else writemem_real (address, source, 16, 2, tmp, clobber); } void writelong_general (int address, int source, int tmp, int clobber) { int distrust; switch (currprefs.comptrustlong) { default: case 0: distrust = 0; break; case 1: distrust = 1; break; case 2: distrust = ((start_pc & 0xF80000) == 0xF80000); break; case 3: distrust = !have_done_picasso; break; } if ((special_mem & SPECIAL_MEM_WRITE) || distrust) writemem_special (address, source, 12, 4, tmp); else writemem_real (address, source, 12, 4, tmp, clobber); } /* This version assumes that it is reading *real* memory, and *will* fail * if that assumption is wrong! No branches, no second chances, just * straight go-for-it attitude */ STATIC_INLINE void readmem_real (int address, int dest, int offset, int size, int tmp) { int f = tmp; if (size == 4 && address != dest) f = dest; #ifdef NATMEM_OFFSET if (canbang) { /* Woohoo! go directly at the memory! */ switch (size) { case 1: mov_b_brR (dest, address, NATMEM_OFFSET); break; case 2: mov_w_brR (dest, address, NATMEM_OFFSET); gen_bswap_16 (dest); break; case 4: mov_l_brR (dest, address, NATMEM_OFFSET); gen_bswap_32 (dest); break; } forget_about (tmp); return; } #endif mov_l_rr (f, address); shrl_l_ri (f, 16); /* The index into the baseaddr table */ mov_l_rm_indexed (f, (uae_uintptr) baseaddr, f, 4); /* f now holds the offset */ switch(size) { case 1: mov_b_rrm_indexed (dest, address, f, 1); break; case 2: mov_w_rrm_indexed (dest, address, f, 1); gen_bswap_16 (dest); break; case 4: mov_l_rrm_indexed (dest, address, f, 1); gen_bswap_32 (dest); break; } forget_about (tmp); } STATIC_INLINE void readmem (int address, int dest, int offset, int size, int tmp) { int f = tmp; mov_l_rr (f,address); shrl_l_ri (f,16); /* The index into the mem bank table */ mov_l_rm_indexed (f, (uae_uintptr) mem_banks, f, 4); /* Now f holds a pointer to the actual membank */ mov_l_rR (f, f, offset); /* Now f holds the address of the b/w/lget function */ call_r_11 (dest, f, address, size, 4); forget_about (tmp); } void readbyte (int address, int dest, int tmp) { int distrust; switch (currprefs.comptrustbyte) { default: case 0: distrust = 0; break; case 1: distrust = 1; break; case 2: distrust = ((start_pc & 0xF80000) == 0xF80000); break; case 3: distrust = !have_done_picasso; break; } if ((special_mem & SPECIAL_MEM_READ) || distrust) readmem_special (address, dest, 8, 1,tmp); else readmem_real (address, dest, 8, 1, tmp); } void readword (int address, int dest, int tmp) { int distrust; switch (currprefs.comptrustword) { default: case 0: distrust = 0; break; case 1: distrust = 1; break; case 2: distrust = ((start_pc & 0xF80000) == 0xF80000); break; case 3: distrust = !have_done_picasso; break; } if ((special_mem & SPECIAL_MEM_READ) || distrust) readmem_special (address, dest, 4, 2, tmp); else readmem_real (address, dest, 4, 2, tmp); } void readlong (int address, int dest, int tmp) { int distrust; switch (currprefs.comptrustlong) { default: case 0: distrust = 0; break; case 1: distrust = 1; break; case 2: distrust = ((start_pc & 0xF80000) == 0xF80000); break; case 3: distrust = !have_done_picasso; break; } if ((special_mem & SPECIAL_MEM_READ) || distrust) readmem_special (address, dest, 0, 4,tmp); else readmem_real (address, dest, 0, 4, tmp); } /* This one might appear a bit odd... */ STATIC_INLINE void get_n_addr_old (int address, int dest, int tmp) { readmem (address, dest, 24, 4, tmp); } STATIC_INLINE void get_n_addr_real (int address, int dest, int tmp) { int f = tmp; if (address != dest) f = dest; #ifdef NATMEM_OFFSET if (canbang) { lea_l_brr (dest, address, NATMEM_OFFSET); forget_about (tmp); return; } #endif mov_l_rr (f, address); mov_l_rr (dest, address); // gb-- nop if dest==address shrl_l_ri (f, 16); mov_l_rm_indexed (f, (uae_uintptr) baseaddr, f, 4); add_l (dest,f); forget_about (tmp); } void get_n_addr (int address, int dest, int tmp) { int distrust; switch (currprefs.comptrustnaddr) { default: case 0: distrust = 0; break; case 1: distrust = 1; break; case 2: distrust = ((start_pc & 0xF80000) == 0xF80000); break; case 3: distrust = !have_done_picasso; break; } if (special_mem || distrust) get_n_addr_old (address,dest,tmp); else get_n_addr_real (address,dest,tmp); } void get_n_addr_jmp (int address, int dest, int tmp) { #if 0 /* For this, we need to get the same address as the rest of UAE would --- otherwise we end up translating everything twice */ get_n_addr (address, dest, tmp); #else int f = tmp; if (address != dest) f = dest; mov_l_rr (f, address); shrl_l_ri (f, 16); /* The index into the baseaddr bank table */ mov_l_rm_indexed (dest, (uae_uintptr) baseaddr, f, 4); add_l (dest, address); and_l_ri (dest, ~1); forget_about (tmp); #endif } /* base is a register, but dp is an actual value. target is a register, as is tmp */ void calc_disp_ea_020(int base, uae_u32 dp, int target, int tmp) { int reg = (dp >> 12) & 15; int regd_shift=(dp >> 9) & 3; if (dp & 0x100) { int ignorebase=(dp&0x80); int ignorereg=(dp&0x40); int addbase=0; int outer=0; if ((dp & 0x30) == 0x20) addbase = (uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2); if ((dp & 0x30) == 0x30) addbase = comp_get_ilong((m68k_pc_offset+=4)-4); if ((dp & 0x3) == 0x2) outer = (uae_s32)(uae_s16)comp_get_iword((m68k_pc_offset+=2)-2); if ((dp & 0x3) == 0x3) outer = comp_get_ilong((m68k_pc_offset+=4)-4); if ((dp & 0x4) == 0) { /* add regd *before* the get_long */ if (!ignorereg) { if ((dp & 0x800) == 0) sign_extend_16_rr(target,reg); else mov_l_rr(target,reg); shll_l_ri(target,regd_shift); } else mov_l_ri(target,0); /* target is now regd */ if (!ignorebase) add_l(target,base); add_l_ri(target,addbase); if (dp&0x03) readlong(target,target,tmp); } else { /* do the getlong first, then add regd */ if (!ignorebase) { mov_l_rr(target,base); add_l_ri(target,addbase); } else mov_l_ri(target,addbase); if (dp&0x03) readlong(target,target,tmp); if (!ignorereg) { if ((dp & 0x800) == 0) sign_extend_16_rr(tmp,reg); else mov_l_rr(tmp,reg); shll_l_ri(tmp,regd_shift); /* tmp is now regd */ add_l(target,tmp); } } add_l_ri(target,outer); } else { /* 68000 version */ if ((dp & 0x800) == 0) { /* Sign extend */ sign_extend_16_rr(target,reg); lea_l_brr_indexed(target,base,target,1<> 8) & 255) | ((f & 255) << 8); } extern unsigned long op_illg (uae_u32 opcode, struct regstruct *regs) REGPARAM; static void calc_checksum(blockinfo* bi, uae_u32* c1, uae_u32* c2) { uae_u32 k1=0; uae_u32 k2=0; uae_s32 len=bi->len; uae_uintptr tmp=bi->min_pcp; uae_u32* pos; len+=(tmp&3); tmp&=(~3); pos=(uae_u32*)tmp; if (len<0 || len>MAX_CHECKSUM_LEN) { *c1=0; *c2=0; } else { while (len>0) { k1+=*pos; k2^=*pos; pos++; len-=4; } *c1=k1; *c2=k2; } } int check_for_cache_miss(void) { blockinfo* bi=get_blockinfo_addr(regs.pc_p); if (bi) { int cl=cacheline(regs.pc_p); if (bi!=cache_tags[cl+1].bi) { raise_in_cl_list(bi); return 1; } } return 0; } static void recompile_block(void) { /* An existing block's countdown code has expired. We need to make sure that execute_normal doesn't refuse to recompile due to a perceived cache miss... */ blockinfo* bi=get_blockinfo_addr(regs.pc_p); Dif (!bi) abort(); raise_in_cl_list(bi); execute_normal(); return; } static void cache_miss(void) { blockinfo* bi=get_blockinfo_addr(regs.pc_p); uae_u32 cl=cacheline(regs.pc_p); blockinfo* bi2=get_blockinfo(cl); if (!bi) { execute_normal(); /* Compile this block now */ return; } Dif (!bi2 || bi==bi2) { write_log ("JIT: Unexplained cache miss %p %p\n", bi, bi2); abort(); } raise_in_cl_list(bi); return; } static void check_checksum(void) { blockinfo* bi=get_blockinfo_addr(regs.pc_p); uae_u32 cl=cacheline(regs.pc_p); blockinfo* bi2=get_blockinfo(cl); uae_u32 c1,c2; checksum_count++; /* These are not the droids you are looking for... */ if (!bi) { /* Whoever is the primary target is in a dormant state, but calling it was accidental, and we should just compile this new block */ execute_normal(); return; } if (bi!=bi2) { /* The block was hit accidentally, but it does exist. Cache miss */ cache_miss(); return; } if (bi->c1 || bi->c2) calc_checksum(bi,&c1,&c2); else { c1=c2=1; /* Make sure it doesn't match */ } if (c1==bi->c1 && c2==bi->c2) { /* This block is still OK. So we reactivate. Of course, that means we have to move it into the needs-to-be-flushed list */ bi->handler_to_use=bi->handler; set_dhtu(bi,bi->direct_handler); /* printf("reactivate %p/%p (%x %x/%x %x)\n",bi,bi->pc_p, c1,c2,bi->c1,bi->c2);*/ remove_from_list(bi); add_to_active(bi); raise_in_cl_list(bi); } else { /* This block actually changed. We need to invalidate it, and set it up to be recompiled */ /* printf("discard %p/%p (%x %x/%x %x)\n",bi,bi->pc_p, c1,c2,bi->c1,bi->c2); */ invalidate_block(bi); raise_in_cl_list(bi); execute_normal(); } } static void free_popalls (void) { if (popallspace) { cache_free (popallspace); popallspace = 0; } popall_exec_nostats = 0; popall_execute_normal = 0; popall_cache_miss = 0; popall_recompile_block = 0; popall_do_nothing = 0; popall_check_checksum = 0; pushall_call_handler = 0; } static void create_popalls (void) { popallspace = cache_alloc (1024); if (popallspace) { int i, r; current_compile_p = popallspace; set_target (current_compile_p); #if USE_PUSH_POP /* If we can't use gcc inline assembly, we need to pop some * registers before jumping back to the various get-out routines. * This generates the code for it. */ popall_do_nothing = current_compile_p; for (i = 0; i < N_REGS; i++) { if (need_to_preserve[i]) raw_pop_l_r (i); } raw_jmp ((uae_uintptr) do_nothing); align_target (align_jumps); popall_execute_normal = get_target (); for (i = 0; i < N_REGS; i++) { if (need_to_preserve[i]) raw_pop_l_r (i); } raw_jmp ((uae_uintptr) execute_normal); align_target (align_jumps); popall_cache_miss = get_target (); for (i = 0; i < N_REGS; i++) { if (need_to_preserve[i]) raw_pop_l_r (i); } raw_jmp ((uae_uintptr) cache_miss); align_target (align_jumps); popall_recompile_block = get_target (); for (i = 0; i < N_REGS; i++) { if (need_to_preserve[i]) raw_pop_l_r (i); } raw_jmp ((uae_uintptr) recompile_block); align_target (align_jumps); popall_exec_nostats = get_target (); for (i = 0; i < N_REGS; i++) { if (need_to_preserve[i]) raw_pop_l_r (i); } raw_jmp ((uae_uintptr) exec_nostats); align_target (align_jumps); popall_check_checksum = get_target (); for (i = 0; i < N_REGS; i++) { if (need_to_preserve[i]) raw_pop_l_r (i); } raw_jmp ((uae_uintptr) check_checksum); align_target (align_jumps); current_compile_p=get_target(); #else popall_exec_nostats = exec_nostats; popall_execute_normal = execute_normal; popall_cache_miss = cache_miss; popall_recompile_block = recompile_block; popall_do_nothing = do_nothing; popall_check_checksum = check_checksum; #endif /* And now, the code to do the matching pushes and then jump * into a handler routine. */ pushall_call_handler = get_target (); #if USE_PUSH_POP for (i = N_REGS; i--;) { if (need_to_preserve[i]) raw_push_l_r (i); } #endif r = REG_PC_TMP; raw_mov_l_rm (r, (uae_uintptr) ®s.pc_p); raw_and_l_ri (r, TAGMASK); raw_jmp_m_indexed ((uae_uintptr) cache_tags, r, 4); } } STATIC_INLINE void reset_lists (void) { int i; for (i = 0; i < MAX_HOLD_BI; i++) hold_bi[i] = NULL; active = NULL; dormant = NULL; } static void prepare_block(blockinfo* bi) { int i; set_target(current_compile_p); align_target (align_jumps); bi->direct_pen=(void*)get_target(); raw_mov_l_rm(0,(uae_uintptr)&(bi->pc_p)); raw_mov_l_mr((uae_uintptr)®s.pc_p, 0); raw_jmp((uae_uintptr)popall_execute_normal); align_target (align_jumps); bi->direct_pcc=(void*)get_target(); raw_mov_l_rm(0,(uae_uintptr)&(bi->pc_p)); raw_mov_l_mr((uae_uintptr)®s.pc_p, 0); raw_jmp((uae_uintptr)popall_check_checksum); current_compile_p=get_target(); bi->deplist=NULL; for (i=0;i<2;i++) { bi->dep[i].prev_p=NULL; bi->dep[i].next=NULL; } bi->env=default_ss; bi->status=BI_NEW; bi->havestate=0; //bi->env=empty_ss; } void compemu_reset(void) { set_cache_state(0); } void build_comp (void) { int i; unsigned long opcode; const struct comptbl *tbl = op_smalltbl_0_comp_ff; const struct comptbl *nftbl = op_smalltbl_0_comp_nf; int count; #ifdef NOFLAGS_SUPPORT struct cputbl *nfctbl = (currprefs.cpu_level >= 4 ? op_smalltbl_0_nf : currprefs.cpu_level == 3 ? op_smalltbl_1_nf : currprefs.cpu_level == 2 ? op_smalltbl_2_nf : currprefs.cpu_level == 1 ? op_smalltbl_3_nf # ifdef CPUEMU_5 : currprefs.cpu_compatible ? op_smalltbl_5_nf # endif : op_smalltbl_4_nf); #endif raw_init_cpu (); write_log ("JIT: Building compiler function table.\n"); for (opcode = 0; opcode < 65536; opcode++) { #ifdef NOFLAGS_SUPPORT nfcpufunctbl[opcode] = op_illg; #endif compfunctbl[opcode] = NULL; nfcompfunctbl[opcode] = NULL; prop[opcode].use_flags = 0x1f; prop[opcode].set_flags = 0x1f; prop[opcode].is_jump=1; } for (i = 0; tbl[i].opcode < 65536; i++) { int isjmp=(tbl[i].specific&1); int isaddx=(tbl[i].specific&8); int iscjmp=(tbl[i].specific&16); prop[tbl[i].opcode].is_jump=isjmp; prop[tbl[i].opcode].is_const_jump=iscjmp; prop[tbl[i].opcode].is_addx=isaddx; compfunctbl[tbl[i].opcode] = tbl[i].handler; } for (i = 0; nftbl[i].opcode < 65536; i++) { nfcompfunctbl[nftbl[i].opcode] = nftbl[i].handler; #ifdef NOFLAGS_SUPPORT nfcpufunctbl[nftbl[i].opcode] = nfctbl[i].handler; #endif } #ifdef NOFLAGS_SUPPORT for (i = 0; nfctbl[i].handler; i++) { nfcpufunctbl[nfctbl[i].opcode] = nfctbl[i].handler; } #endif for (opcode = 0; opcode < 65536; opcode++) { compop_func *f; compop_func *nff; #ifdef NOFLAGS_SUPPORT cpuop_func *nfcf; #endif int isjmp,isaddx,iscjmp; if (table68k[opcode].mnemo == i_ILLG || table68k[opcode].clev > currprefs.cpu_level) continue; if (table68k[opcode].handler != -1) { f = compfunctbl[table68k[opcode].handler]; nff = nfcompfunctbl[table68k[opcode].handler]; #ifdef NOFLAGS_SUPPORT nfcf = nfcpufunctbl[table68k[opcode].handler]; #endif isjmp=prop[table68k[opcode].handler].is_jump; iscjmp=prop[table68k[opcode].handler].is_const_jump; isaddx=prop[table68k[opcode].handler].is_addx; prop[opcode].is_jump=isjmp; prop[opcode].is_const_jump=iscjmp; prop[opcode].is_addx=isaddx; compfunctbl[opcode] = f; nfcompfunctbl[opcode] = nff; #ifdef NOFLAGS_SUPPORT Dif (nfcf == op_illg) abort(); nfcpufunctbl[opcode] = nfcf; #endif } prop[opcode].set_flags =table68k[opcode].flagdead; prop[opcode].use_flags =table68k[opcode].flaglive; /* Unconditional jumps don't evaluate condition codes, so they don't actually use any flags themselves */ if (prop[opcode].is_const_jump) prop[opcode].use_flags=0; } #ifdef NOFLAGS_SUPPORT for (i = 0; nfctbl[i].handler != NULL; i++) { if (nfctbl[i].specific) nfcpufunctbl[tbl[i].opcode] = nfctbl[i].handler; } #endif count=0; for (opcode = 0; opcode < 65536; opcode++) { if (compfunctbl[opcode]) count++; } write_log ("JIT: Supposedly %d compileable opcodes.\n", count); #ifdef NATMEM_OFFSET if (canbang) { # ifndef _WIN32 /* Set up signal handler to catch illegal natmem accesses */ struct sigaction act; act.sa_sigaction = vec; sigemptyset (&act.sa_mask); act.sa_flags = SA_SIGINFO; sigaction (SIGSEGV, &act, NULL); # endif /* Cache for generating illegal natmem access handler. */ veccode = cache_alloc (256); if (!veccode) { canbang = 0; sigaction (SIGSEGV, saved_handler, 0); } else write_log ("JIT: Enabled direct memory access.\n"); } #endif /* Initialise state */ alloc_cache (); create_popalls (); reset_lists (); for (i=0;ipc_p)].handler=(void*)popall_execute_normal; cache_tags[cacheline(bi->pc_p)+1].bi=NULL; bi=bi->next; } bi=dormant; while(bi) { cache_tags[cacheline(bi->pc_p)].handler=(void*)popall_execute_normal; cache_tags[cacheline(bi->pc_p)+1].bi=NULL; bi=bi->next; } reset_lists(); if (!compiled_code) return; current_compile_p=compiled_code; set_special (®s,0); /* To get out of compiled code */ } /* "Soft flushing" --- instead of actually throwing everything away, we simply mark everything as "needs to be checked". */ void flush_icache(int n) { uae_u32 i; blockinfo* bi; blockinfo* bi2; if (currprefs.comp_hardflush) { flush_icache_hard(n); return; } soft_flush_count++; if (!active) return; bi=active; while (bi) { uae_u32 cl=cacheline(bi->pc_p); if (!bi->handler) { /* invalidated block */ if (bi==cache_tags[cl+1].bi) cache_tags[cl].handler=popall_execute_normal; bi->handler_to_use=popall_execute_normal; set_dhtu(bi,bi->direct_pen); } else { if (bi==cache_tags[cl+1].bi) cache_tags[cl].handler=popall_check_checksum; bi->handler_to_use=popall_check_checksum; set_dhtu(bi,bi->direct_pcc); } bi2=bi; bi=bi->next; } /* bi2 is now the last entry in the active list */ bi2->next=dormant; if (dormant) dormant->prev_p=&(bi2->next); dormant=active; active->prev_p=&dormant; active=NULL; } int failure; void compile_block (const cpu_history *pc_hist, int blocklen, int totcycles) { if (letit && compiled_code && currprefs.cpu_level>=2) { /* OK, here we need to 'compile' a block */ int i; int r; int was_comp=0; uae_u8 liveflags[MAXRUN+1]; uae_uintptr max_pcp=(uae_uintptr)pc_hist[0].location; uae_uintptr min_pcp=max_pcp; uae_u32 cl=cacheline(pc_hist[0].location); void* specflags=(void*)®s.spcflags; blockinfo* bi=NULL; blockinfo* bi2; int extra_len=0; compile_count++; if (current_compile_p>=max_compile_start) flush_icache_hard(7); alloc_blockinfos(); bi=get_blockinfo_addr_new(pc_hist[0].location,0); bi2=get_blockinfo(cl); optlev=bi->optlevel; if (bi->handler) { Dif (bi!=bi2) { /* I don't think it can happen anymore. Shouldn't, in any case. So let's make sure... */ write_log ("WOOOWOO count=%d, ol=%d %p %p\n", bi->count, bi->optlevel, bi->handler_to_use, cache_tags[cl].handler); abort(); } Dif (bi->count!=-1 && bi->status!=BI_TARGETTED) { /* What the heck? We are not supposed to be here! */ abort(); } } if (bi->count==-1) { optlev++; while (!currprefs.optcount[optlev]) optlev++; bi->count=currprefs.optcount[optlev]-1; } current_block_pc_p=(uae_uintptr)pc_hist[0].location; remove_deps(bi); /* We are about to create new code */ bi->optlevel=optlev; bi->pc_p=(uae_u8*)pc_hist[0].location; liveflags[blocklen]=0x1f; /* All flags needed afterwards */ i=blocklen; while (i--) { uae_u16* currpcp=pc_hist[i].location; int op=cft_map(*currpcp); if ((uae_uintptr) currpcp < min_pcp) min_pcp = (uae_uintptr) currpcp; if ((uae_uintptr) currpcp > max_pcp) max_pcp = (uae_uintptr) currpcp; if (currprefs.compnf) { liveflags[i]=((liveflags[i+1]& (~prop[op].set_flags))| prop[op].use_flags); if (prop[op].is_addx && (liveflags[i+1]&FLAG_Z)==0) liveflags[i]&= ~FLAG_Z; } else { liveflags[i]=0x1f; } } bi->needed_flags=liveflags[0]; #if 1 /* This is the non-direct handler */ align_target(32); set_target(get_target()+1); align_target(16); /* Now aligned at n*32+16 */ #else align_target (align_loops); #endif bi->handler= bi->handler_to_use=(void*)get_target(); raw_cmp_l_mi((uae_uintptr)®s.pc_p,(uae_uintptr)pc_hist[0].location); raw_jnz((uae_uintptr)popall_cache_miss); /* This was 16 bytes on the x86, so now aligned on (n+1)*32 */ was_comp=0; #if USE_MATCHSTATE comp_pc_p=(uae_u8*)pc_hist[0].location; init_comp(); match_states(&(bi->env)); was_comp=1; #endif bi->direct_handler=(void*)get_target(); set_dhtu(bi,bi->direct_handler); current_block_start_target=(uae_uintptr)get_target(); if (bi->count>=0) { /* Need to generate countdown code */ raw_mov_l_mi((uae_uintptr)®s.pc_p,(uae_uintptr)pc_hist[0].location); raw_sub_l_mi((uae_uintptr)&(bi->count),1); raw_jl((uae_uintptr)popall_recompile_block); } if (optlev==0) { /* No need to actually translate */ /* Execute normally without keeping stats */ raw_mov_l_mi((uae_uintptr)®s.pc_p,(uae_uintptr)pc_hist[0].location); raw_jmp((uae_uintptr)popall_exec_nostats); } else { reg_alloc_run=0; next_pc_p=0; taken_pc_p=0; branch_cc=0; log_startblock(); for (i=0;i1) { failure=0; if (!was_comp) { comp_pc_p=(uae_u8*)pc_hist[i].location; init_comp(); } was_comp++; comptbl[opcode](opcode); freescratch(); if (!(liveflags[i+1] & FLAG_CZNV)) { /* We can forget about flags */ dont_care_flags(); } #if INDIVIDUAL_INST flush(1); nop(); flush(1); was_comp=0; #endif } else failure=1; if (failure) { if (was_comp) { flush(1); was_comp=0; } raw_mov_l_ri(REG_PAR1,(uae_u32)opcode); raw_mov_l_ri(REG_PAR2,(uae_uintptr)®s); #if USE_NORMAL_CALLING_CONVENTION raw_push_l_r(REG_PAR2); raw_push_l_r(REG_PAR1); #endif raw_mov_l_mi((uae_uintptr)®s.pc_p, (uae_uintptr)pc_hist[i].location); raw_call((uae_uintptr)cputbl[opcode]); #if USE_NORMAL_CALLING_CONVENTION raw_inc_sp(8); #endif if (ineeded_flags; if (x==0xff || 1) { /* To be on the safe side */ uae_u16* next=(uae_u16*)next_pc_p; uae_u16 op=cft_map(*next); x=0x1f; x&=(~prop[op].set_flags); x|=prop[op].use_flags; } x|=bi2->needed_flags; if (!(x & FLAG_CZNV)) { /* We can forget about flags */ dont_care_flags(); extra_len+=2; /* The next instruction now is part of this block */ } } #endif if (next_pc_p) { /* A branch was registered */ uae_uintptr t1=next_pc_p; uae_uintptr t2=taken_pc_p; int cc=branch_cc; uae_u32* branchadd; uae_u32* tba; bigstate tmp; blockinfo* tbi; if (taken_pc_penv)); //flush(1); /* Can only get here if was_comp==1 */ raw_sub_l_mi((uae_uintptr)&countdown,scaled_cycles(totcycles)); raw_jcc_l_oponly(9); tba=(uae_u32*)get_target(); emit_long(get_handler(t1)-((uae_uintptr)tba+4)); raw_mov_l_mi((uae_uintptr)®s.pc_p,t1); raw_jmp((uae_uintptr)popall_do_nothing); create_jmpdep(bi,0,tba,t1); align_target (align_jumps); /* not-predicted outcome */ *branchadd=(uae_uintptr)get_target()-((uae_uintptr)branchadd+4); live=tmp; /* Ouch again */ tbi=get_blockinfo_addr_new((void*)t2,1); match_states(&(tbi->env)); //flush(1); /* Can only get here if was_comp==1 */ raw_sub_l_mi((uae_uintptr)&countdown,scaled_cycles(totcycles)); raw_jcc_l_oponly(9); tba=(uae_u32*)get_target(); emit_long(get_handler(t2)-((uae_uintptr)tba+4)); raw_mov_l_mi((uae_uintptr)®s.pc_p,t2); raw_jmp((uae_uintptr)popall_do_nothing); create_jmpdep(bi,1,tba,t2); } else { if (was_comp) { flush(1); } /* Let's find out where next_handler is... */ if (was_comp && isinreg(PC_P)) { int r2; r=live.state[PC_P].realreg; if (r==0) r2=1; else r2=0; raw_and_l_ri(r,TAGMASK); raw_mov_l_ri(r2,(uae_uintptr)popall_do_nothing); raw_sub_l_mi((uae_uintptr)&countdown,scaled_cycles(totcycles)); raw_cmov_l_rm_indexed(r2,(uae_uintptr)cache_tags,r,4,9); raw_jmp_r(r2); } else if (was_comp && isconst(PC_P)) { uae_u32 v=live.state[PC_P].val; uae_u32* tba; blockinfo* tbi; tbi=get_blockinfo_addr_new((void*)(uae_uintptr)v,1); match_states(&(tbi->env)); raw_sub_l_mi((uae_uintptr)&countdown,scaled_cycles(totcycles)); raw_jcc_l_oponly(9); tba=(uae_u32*)get_target(); emit_long(get_handler(v)-((uae_uintptr)tba+4)); raw_mov_l_mi((uae_uintptr)®s.pc_p,v); raw_jmp((uae_uintptr)popall_do_nothing); create_jmpdep(bi,0,tba,v); } else { int r2; r=REG_PC_TMP; raw_mov_l_rm(r,(uae_uintptr)®s.pc_p); if (r==0) r2=1; else r2=0; raw_and_l_ri(r,TAGMASK); raw_mov_l_ri(r2,(uae_uintptr)popall_do_nothing); raw_sub_l_mi((uae_uintptr)&countdown,scaled_cycles(totcycles)); raw_cmov_l_rm_indexed(r2,(uae_uintptr)cache_tags,r,4,9); raw_jmp_r(r2); } } } if (next_pc_p+extra_len>=max_pcp && next_pc_p+extra_lenlen=max_pcp-min_pcp; bi->min_pcp=min_pcp; remove_from_list(bi); if (isinrom(min_pcp) && isinrom(max_pcp)) add_to_dormant(bi); /* No need to checksum it on cache flush. Please don't start changing ROMs in flight! */ else { calc_checksum(bi,&(bi->c1),&(bi->c2)); add_to_active(bi); } log_dump(); align_target (align_jumps); current_compile_p=get_target(); raise_in_cl_list(bi); bi->nexthandler=current_compile_p; /* We will flush soon, anyway, so let's do it now */ if (current_compile_p>=max_compile_start) flush_icache_hard(7); do_extra_cycles(totcycles); /* for the compilation time */ } }