X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=libpcsxcore%2Fnew_dynarec%2Fnew_dynarec.c;h=abb0d07611dc5098a71ded4749ae0ffcfa1b7295;hb=9de8a0c3587effdbd19584cbca3baf566d1d21bd;hp=f1005db85b9c52319478cb16034e717b3563a1e2;hpb=9a3ccfeb31dad024ab5c249c870866570414b2ba;p=pcsx_rearmed.git diff --git a/libpcsxcore/new_dynarec/new_dynarec.c b/libpcsxcore/new_dynarec/new_dynarec.c index f1005db8..abb0d076 100644 --- a/libpcsxcore/new_dynarec/new_dynarec.c +++ b/libpcsxcore/new_dynarec/new_dynarec.c @@ -29,10 +29,6 @@ #ifdef _3DS #include <3ds_utils.h> #endif -#ifdef VITA -#include -static int sceBlock; -#endif #include "new_dynarec_config.h" #include "../psxhle.h" @@ -53,6 +49,7 @@ static int sceBlock; //#define DISASM //#define ASSEM_PRINT +//#define REG_ALLOC_PRINT #ifdef ASSEM_PRINT #define assem_debug printf @@ -79,9 +76,17 @@ static int sceBlock; #define MAXBLOCK 4096 #define MAX_OUTPUT_BLOCK_SIZE 262144 +#ifdef VITA +// apparently Vita has a 16MB limit, so either we cut tc in half, +// or use this hack (it's a hack because tc size was designed to be power-of-2) +#define TC_REDUCE_BYTES 4096 +#else +#define TC_REDUCE_BYTES 0 +#endif + struct ndrc_mem { - u_char translation_cache[1 << TARGET_SIZE_2]; + u_char translation_cache[(1 << TARGET_SIZE_2) - TC_REDUCE_BYTES]; struct { struct tramp_insns ops[2048 / sizeof(struct tramp_insns)]; @@ -114,15 +119,20 @@ enum stub_type { INVCODE_STUB = 14, }; +// regmap_pre[i] - regs before [i] insn starts; dirty things here that +// don't match .regmap will be written back +// [i].regmap_entry - regs that must be set up if someone jumps here +// [i].regmap - regs [i] insn will read/(over)write +// branch_regs[i].* - same as above but for branches, takes delay slot into account struct regstat { - signed char regmap_entry[HOST_REGS]; // pre-insn + loop preloaded regs? + signed char regmap_entry[HOST_REGS]; signed char regmap[HOST_REGS]; uint64_t wasdirty; uint64_t dirty; uint64_t u; - u_int wasconst; - u_int isconst; + u_int wasconst; // before; for example 'lw r2, (r2)' wasconst is true + u_int isconst; // ... but isconst is false when r2 is known u_int loadedconst; // host regs that have constants loaded u_int waswritten; // MIPS regs that were used as store base before }; @@ -202,7 +212,7 @@ static struct decoded_insn static u_int ba[MAXBLOCK]; static uint64_t unneeded_reg[MAXBLOCK]; static uint64_t branch_unneeded_reg[MAXBLOCK]; - // pre-instruction [i], excluding loop-preload regs? + // see 'struct regstat' for a description static signed char regmap_pre[MAXBLOCK][HOST_REGS]; // contains 'real' consts at [i] insn, but may differ from what's actually // loaded in host reg as 'final' value is always loaded, see get_final_value() @@ -228,7 +238,7 @@ static struct decoded_insn static void *copy; static int expirep; static u_int stop_after_jal; - static u_int f1_hack; // 0 - off, ~0 - capture address, else addr + static u_int f1_hack; int new_dynarec_hacks; int new_dynarec_hacks_pergame; @@ -293,7 +303,7 @@ static struct decoded_insn //#define FLOAT 19 // Floating point unit //#define FCONV 20 // Convert integer to float //#define FCOMP 21 // Floating point compare (sets FSREG) -#define SYSCALL 22// SYSCALL +#define SYSCALL 22// SYSCALL,BREAK #define OTHER 23 // Other #define SPAN 24 // Branch/delay slot spans 2 pages #define NI 25 // Not implemented @@ -324,6 +334,10 @@ void verify_code_ds(); void cc_interrupt(); void fp_exception(); void fp_exception_ds(); +void jump_syscall (u_int u0, u_int u1, u_int pc); +void jump_syscall_ds(u_int u0, u_int u1, u_int pc); +void jump_break (u_int u0, u_int u1, u_int pc); +void jump_break_ds(u_int u0, u_int u1, u_int pc); void jump_to_new_pc(); void call_gteStall(); void new_dyna_leave(); @@ -354,6 +368,14 @@ static void pass_args(int a0, int a1); static void emit_far_jump(const void *f); static void emit_far_call(const void *f); +#ifdef VITA +#include +static int sceBlock; +// note: this interacts with RetroArch's Vita bootstrap code: bootstrap/vita/sbrk.c +extern int getVMBlock(); +int _newlib_vm_size_user = sizeof(*ndrc); +#endif + static void mprotect_w_x(void *start, void *end, int is_x) { #ifdef NO_WRITE_EXEC @@ -468,12 +490,12 @@ static void do_clear_cache(void) int cycle_multiplier = CYCLE_MULT_DEFAULT; // 100 for 1.0 int cycle_multiplier_override; int cycle_multiplier_old; +static int cycle_multiplier_active; static int CLOCK_ADJUST(int x) { - int m = cycle_multiplier_override && cycle_multiplier == CYCLE_MULT_DEFAULT - ? cycle_multiplier_override : cycle_multiplier; - int s=(x>>31)|1; + int m = cycle_multiplier_active; + int s = (x >> 31) | 1; return (x * m + s * 50) / 100; } @@ -563,14 +585,12 @@ void noinline *get_addr(u_int vaddr) //printf("TRACE: count=%d next=%d (get_addr no-match %x)\n",Count,next_interupt,vaddr); int r=new_recompile_block(vaddr); if(r==0) return get_addr(vaddr); - // Execute in unmapped page, generate pagefault execption + // generate an address error Status|=2; - Cause=(vaddr<<31)|0x8; + Cause=(vaddr<<31)|(4<<2); EPC=(vaddr&1)?vaddr-5:vaddr; BadVAddr=(vaddr&~1); - Context=(Context&0xFF80000F)|((BadVAddr>>9)&0x007FFFF0); - EntryHi=BadVAddr&0xFFFFE000; - return get_addr_ht(0x80000000); + return get_addr_ht(0x80000080); } // Look up address in hash table first void *get_addr_ht(u_int vaddr) @@ -582,16 +602,32 @@ void *get_addr_ht(u_int vaddr) return get_addr(vaddr); } -void clear_all_regs(signed char regmap[]) +static void clear_all_regs(signed char regmap[]) +{ + memset(regmap, -1, sizeof(regmap[0]) * HOST_REGS); +} + +static signed char get_reg(const signed char regmap[], signed char r) { int hr; - for (hr=0;hrregmap[hr]&63)==reg) { - cur->dirty|=1<regmap, reg); + if (hr >= 0) + cur->dirty |= 1<regmap[hr]==reg) { - cur->isconst|=1<regmap, reg); + if (hr >= 0) { + cur->isconst |= 1<regmap[hr]&63)==reg) { - cur->isconst&=~(1<regmap, reg); + if (hr >= 0) + cur->isconst &= ~(1<regmap[hr]&63)==reg) { - return (cur->isconst>>hr)&1; - } - } + if (reg < 0) return 0; + if (!reg) return 1; + hr = get_reg(cur->regmap, reg); + if (hr >= 0) + return (cur->isconst>>hr)&1; return 0; } -static uint32_t get_const(struct regstat *cur, signed char reg) +static uint32_t get_const(const struct regstat *cur, signed char reg) { int hr; - if(!reg) return 0; - for (hr=0;hrregmap[hr]==reg) { - return current_constmap[hr]; - } - } - SysPrintf("Unknown constant in r%d\n",reg); + if (!reg) return 0; + hr = get_reg(cur->regmap, reg); + if (hr >= 0) + return current_constmap[hr]; + + SysPrintf("Unknown constant in r%d\n", reg); abort(); } @@ -860,14 +888,14 @@ void alloc_all(struct regstat *cur,int i) for(hr=0;hrregmap[hr]&63)!=dops[i].rs1)&&((cur->regmap[hr]&63)!=dops[i].rs2)&& - ((cur->regmap[hr]&63)!=dops[i].rt1)&&((cur->regmap[hr]&63)!=dops[i].rt2)) + if((cur->regmap[hr]!=dops[i].rs1)&&(cur->regmap[hr]!=dops[i].rs2)&& + (cur->regmap[hr]!=dops[i].rt1)&&(cur->regmap[hr]!=dops[i].rt2)) { cur->regmap[hr]=-1; cur->dirty&=~(1<regmap[hr]&63)==0) + if(cur->regmap[hr]==0) { cur->regmap[hr]=-1; cur->dirty&=~(1<regmap[preferred_reg]&63]==j) { for(hr=0;hrregmap[hr]&63)==r) { + if(cur->regmap[hr]==r) { cur->regmap[hr]=-1; cur->dirty&=~(1<isconst&=~(1<>hr)&1) { assert(regmap[hr]<64); emit_storereg(r,hr); @@ -2125,7 +2157,7 @@ static void wb_valid(signed char pre[],signed char entry[],u_int dirty_pre,u_int for(hr=0;hr>(reg&63))&1) { + if(((~u)>>reg)&1) { if(reg>0) { if(((dirty_pre&~dirty)>>hr)&1) { if(reg>0&®<34) { @@ -2783,12 +2815,12 @@ static void load_assemble(int i, const struct regstat *i_regs, int ccadj_) // could be FIFO, must perform the read // ||dummy read assem_debug("(forced read)\n"); - tl=get_reg(i_regs->regmap,-1); + tl=get_reg_temp(i_regs->regmap); assert(tl>=0); } if(offset||s<0||c) addr=tl; else addr=s; - //if(tl<0) tl=get_reg(i_regs->regmap,-1); + //if(tl<0) tl=get_reg_temp(i_regs->regmap); if(tl>=0) { //printf("load_assemble: c=%d\n",c); //if(c) printf("load_assemble: const=%lx\n",(long)constmap[i][s]+offset); @@ -2919,7 +2951,7 @@ static void loadlr_assemble(int i, const struct regstat *i_regs, int ccadj_) u_int reglist=get_host_reglist(i_regs->regmap); tl=get_reg(i_regs->regmap,dops[i].rt1); s=get_reg(i_regs->regmap,dops[i].rs1); - temp=get_reg(i_regs->regmap,-1); + temp=get_reg_temp(i_regs->regmap); temp2=get_reg(i_regs->regmap,FTEMP); addr=get_reg(i_regs->regmap,AGEN1+(i&1)); assert(addr<0); @@ -3005,7 +3037,7 @@ static void store_assemble(int i, const struct regstat *i_regs, int ccadj_) tl=get_reg(i_regs->regmap,dops[i].rs2); s=get_reg(i_regs->regmap,dops[i].rs1); temp=get_reg(i_regs->regmap,agr); - if(temp<0) temp=get_reg(i_regs->regmap,-1); + if(temp<0) temp=get_reg_temp(i_regs->regmap); offset=imm[i]; if(s>=0) { c=(i_regs->wasconst>>s)&1; @@ -3130,7 +3162,7 @@ static void storelr_assemble(int i, const struct regstat *i_regs, int ccadj_) tl=get_reg(i_regs->regmap,dops[i].rs2); s=get_reg(i_regs->regmap,dops[i].rs1); temp=get_reg(i_regs->regmap,agr); - if(temp<0) temp=get_reg(i_regs->regmap,-1); + if(temp<0) temp=get_reg_temp(i_regs->regmap); offset=imm[i]; if(s>=0) { c=(i_regs->isconst>>s)&1; @@ -3559,7 +3591,7 @@ static void multdiv_do_stall(int i, const struct regstat *i_regs) { int j, known_cycles = 0; u_int reglist = get_host_reglist(i_regs->regmap); - int rtmp = get_reg(i_regs->regmap, -1); + int rtmp = get_reg_temp(i_regs->regmap); if (rtmp < 0) rtmp = reglist_find_free(reglist); if (HACK_ENABLED(NDHACK_NO_STALLS)) @@ -3708,7 +3740,7 @@ static void c2ls_assemble(int i, const struct regstat *i_regs, int ccadj_) // get the address if (dops[i].opcode==0x3a) { // SWC2 ar=get_reg(i_regs->regmap,agr); - if(ar<0) ar=get_reg(i_regs->regmap,-1); + if(ar<0) ar=get_reg_temp(i_regs->regmap); reglist|=1<>11) & 0x1f; - signed char temp = get_reg(i_regs->regmap, -1); + signed char temp = get_reg_temp(i_regs->regmap); if (!HACK_ENABLED(NDHACK_NO_STALLS)) { u_int reglist = reglist_exclude(get_host_reglist(i_regs->regmap), temp, -1); @@ -3923,9 +3955,15 @@ static void call_c_cpu_handler(int i, const struct regstat *i_regs, int ccadj_, static void syscall_assemble(int i, const struct regstat *i_regs, int ccadj_) { - emit_movimm(0x20,0); // cause code - emit_movimm(0,1); // not in delay slot - call_c_cpu_handler(i, i_regs, ccadj_, start+i*4, psxException); + // 'break' tends to be littered around to catch things like + // division by 0 and is almost never executed, so don't emit much code here + void *func = (dops[i].opcode2 == 0x0C) + ? (is_delayslot ? jump_syscall_ds : jump_syscall) + : (is_delayslot ? jump_break_ds : jump_break); + assert(get_reg(i_regs->regmap, CCREG) == HOST_CCREG); + emit_movimm(start + i*4, 2); // pc + emit_addimm(HOST_CCREG, ccadj_ + CLOCK_ADJUST(1), HOST_CCREG); + emit_far_jump(func); } static void hlecall_assemble(int i, const struct regstat *i_regs, int ccadj_) @@ -4122,6 +4160,7 @@ static int assemble(int i, const struct regstat *i_regs, int ccadj_) case SPAN: pagespan_assemble(i, i_regs); break; + case NOP: case OTHER: case NI: // not handled, just skip @@ -4186,7 +4225,7 @@ static void wb_invalidate(signed char pre[],signed char entry[],uint64_t dirty,u for(hr=0;hr=0&&(pre[hr]&63)=0&&pre[hr]=0) { emit_mov(hr,nr); @@ -4261,7 +4300,7 @@ void address_generation(int i, const struct regstat *i_regs, signed char entry[] int agr=AGEN1+(i&1); if(dops[i].itype==LOAD) { ra=get_reg(i_regs->regmap,dops[i].rt1); - if(ra<0) ra=get_reg(i_regs->regmap,-1); + if(ra<0) ra=get_reg_temp(i_regs->regmap); assert(ra>=0); } if(dops[i].itype==LOADLR) { @@ -4269,14 +4308,14 @@ void address_generation(int i, const struct regstat *i_regs, signed char entry[] } if(dops[i].itype==STORE||dops[i].itype==STORELR) { ra=get_reg(i_regs->regmap,agr); - if(ra<0) ra=get_reg(i_regs->regmap,-1); + if(ra<0) ra=get_reg_temp(i_regs->regmap); } if(dops[i].itype==C2LS) { if ((dops[i].opcode&0x3b)==0x31||(dops[i].opcode&0x3b)==0x32) // LWC1/LDC1/LWC2/LDC2 ra=get_reg(i_regs->regmap,FTEMP); else { // SWC1/SDC1/SWC2/SDC2 ra=get_reg(i_regs->regmap,agr); - if(ra<0) ra=get_reg(i_regs->regmap,-1); + if(ra<0) ra=get_reg_temp(i_regs->regmap); } } int rs=get_reg(i_regs->regmap,dops[i].rs1); @@ -4523,7 +4562,7 @@ static void load_all_regs(const signed char i_regmap[]) emit_zeroreg(hr); } else - if(i_regmap[hr]>0 && (i_regmap[hr]&63)0 && i_regmap[hr]0 && (i_regmap[hr]&63)0 && i_regmap[hr]regmap[hr]&63)!=dops[i].rs1 && - (i_regs->regmap[hr]&63)!=dops[i].rs2 ) + i_regs->regmap[hr]!=dops[i].rs1 && + i_regs->regmap[hr]!=dops[i].rs2 ) { addr=hr++;break; } @@ -5881,8 +5922,8 @@ static void pagespan_assemble(int i, const struct regstat *i_regs) while(hrregmap[hr]&63)!=dops[i].rs1 && - (i_regs->regmap[hr]&63)!=dops[i].rs2 ) + i_regs->regmap[hr]!=dops[i].rs1 && + i_regs->regmap[hr]!=dops[i].rs2 ) { alt=hr++;break; } @@ -5893,8 +5934,8 @@ static void pagespan_assemble(int i, const struct regstat *i_regs) while(hrregmap[hr]&63)!=dops[i].rs1 && - (i_regs->regmap[hr]&63)!=dops[i].rs2 ) + i_regs->regmap[hr]!=dops[i].rs1 && + i_regs->regmap[hr]!=dops[i].rs2 ) { ntaddr=hr;break; } @@ -6090,7 +6131,7 @@ static void pagespan_ds() } int btaddr=get_reg(regs[0].regmap,BTREG); if(btaddr<0) { - btaddr=get_reg(regs[0].regmap,-1); + btaddr=get_reg_temp(regs[0].regmap); emit_readword(&branch_target,btaddr); } assert(btaddr!=HOST_CCREG); @@ -6112,8 +6153,21 @@ static void pagespan_ds() load_regs_bt(regs[0].regmap,regs[0].dirty,start+4); } +static void check_regmap(signed char *regmap) +{ +#ifndef NDEBUG + int i,j; + for (i = 0; i < HOST_REGS; i++) { + if (regmap[i] < 0) + continue; + for (j = i + 1; j < HOST_REGS; j++) + assert(regmap[i] != regmap[j]); + } +#endif +} + // Basic liveness analysis for MIPS registers -void unneeded_registers(int istart,int iend,int r) +static void unneeded_registers(int istart,int iend,int r) { int i; uint64_t u,gte_u,b,gte_b; @@ -6283,6 +6337,7 @@ void clean_registers(int istart,int iend,int wr) } for (i=iend;i>=istart;i--) { + __builtin_prefetch(regs[i-1].regmap); if(dops[i].is_jump) { if(ba[i]=(start+slen*4)) @@ -6296,18 +6351,18 @@ void clean_registers(int istart,int iend,int wr) // Merge in delay slot (will dirty) for(r=0;r33) will_dirty_i&=~(1<33) will_dirty_i&=~(1<33) will_dirty_i&=~(1<33) will_dirty_i&=~(1<33) will_dirty_i&=~(1<33) will_dirty_i&=~(1<33) will_dirty_i&=~(1<33) will_dirty_i&=~(1<33) temp_will_dirty&=~(1<33) temp_will_dirty&=~(1<33) temp_will_dirty&=~(1<33) temp_will_dirty&=~(1<33) temp_will_dirty&=~(1<33) temp_will_dirty&=~(1<33) temp_will_dirty&=~(1<33) temp_will_dirty&=~(1<0 && (regmap_pre[i][r]&63)<34) { - temp_will_dirty|=((unneeded_reg[i]>>(regmap_pre[i][r]&63))&1)<>(regmap_pre[i][r]&63))&1)<0 && regmap_pre[i][r]<34) { + temp_will_dirty|=((unneeded_reg[i]>>regmap_pre[i][r])&1)<>regmap_pre[i][r])&1)<>2]&(1<=0) { - will_dirty_i|=((unneeded_reg[(ba[i]-start)>>2]>>(branch_regs[i].regmap[r]&63))&1)<>2]>>(branch_regs[i].regmap[r]&63))&1)<>2]>>branch_regs[i].regmap[r])&1)<>2]>>branch_regs[i].regmap[r])&1)<33) will_dirty_i&=~(1<33) will_dirty_i&=~(1<33) will_dirty_i&=~(1<33) will_dirty_i&=~(1<start+i*4) { // Disable recursion (for debugging) + //if(ba[i]>start+i*4) // Disable recursion (for debugging) for(r=0;r>2]&(1<=0) { - will_dirty_i&=((unneeded_reg[(ba[i]-start)>>2]>>(target_reg&63))&1)<>2]>>(target_reg&63))&1)<>2]>>target_reg)&1)<>2]>>target_reg)&1)<33) will_dirty_i&=~(1<33) will_dirty_i&=~(1<33) will_dirty_i&=~(1<33) will_dirty_i&=~(1<33) will_dirty_i&=~(1<33) will_dirty_i&=~(1<istart) { if (!dops[i].is_jump) { // Don't store a register immediately after writing it, // may prevent dual-issue. - if((regs[i].regmap[r]&63)==dops[i-1].rt1) wont_dirty_i|=1<0 && (regmap_pre[i][r]&63)<34) { - will_dirty_i|=((unneeded_reg[i]>>(regmap_pre[i][r]&63))&1)<>(regmap_pre[i][r]&63))&1)<0 && regmap_pre[i][r]<34) { + will_dirty_i|=((unneeded_reg[i]>>regmap_pre[i][r])&1)<>regmap_pre[i][r])&1)<>r)&1));*/ @@ -6683,6 +6736,24 @@ void clean_registers(int istart,int iend,int wr) } #ifdef DISASM +#include +void print_regmap(const char *name, const signed char *regmap) +{ + char buf[5]; + int i, l; + fputs(name, stdout); + for (i = 0; i < HOST_REGS; i++) { + l = 0; + if (regmap[i] >= 0) + l = snprintf(buf, sizeof(buf), "$%d", regmap[i]); + for (; l < 3; l++) + buf[l] = ' '; + buf[l] = 0; + printf(" r%d=%s", i, buf); + } + fputs("\n", stdout); +} + /* disassembly */ void disassemble_inst(int i) { @@ -6768,6 +6839,16 @@ void disassemble_inst(int i) //printf (" %s %8x\n",insn[i],source[i]); printf (" %x: %s\n",start+i*4,insn[i]); } + return; + printf("D: %"PRIu64" WD: %"PRIu64" U: %"PRIu64"\n", + regs[i].dirty, regs[i].wasdirty, unneeded_reg[i]); + print_regmap("pre: ", regmap_pre[i]); + print_regmap("entry: ", regs[i].regmap_entry); + print_regmap("map: ", regs[i].regmap); + if (dops[i].is_jump) { + print_regmap("bentry:", branch_regs[i].regmap_entry); + print_regmap("bmap: ", branch_regs[i].regmap); + } } #else static void disassemble_inst(int i) {} @@ -6788,7 +6869,7 @@ static void new_dynarec_test(void) SysPrintf("linkage_arm* miscompilation/breakage detected.\n"); } - SysPrintf("testing if we can run recompiled code...\n"); + SysPrintf("testing if we can run recompiled code @%p...\n", out); ((volatile u_int *)out)[0]++; // make cache dirty for (i = 0; i < ARRAY_SIZE(ret); i++) { @@ -6826,6 +6907,7 @@ void new_dynarec_clear_full(void) literalcount=0; stop_after_jal=0; inv_code_start=inv_code_end=~0; + hack_addr=0; f1_hack=0; // TLB for(n=0;n<4096;n++) ll_clear(jump_in+n); @@ -6838,16 +6920,24 @@ void new_dynarec_clear_full(void) void new_dynarec_init(void) { - SysPrintf("Init new dynarec\n"); + SysPrintf("Init new dynarec, ndrc size %x\n", (int)sizeof(*ndrc)); +#ifdef _3DS + check_rosalina(); +#endif #ifdef BASE_ADDR_DYNAMIC #ifdef VITA - sceBlock = sceKernelAllocMemBlockForVM("code", 1 << TARGET_SIZE_2); - if (sceBlock < 0) - SysPrintf("sceKernelAllocMemBlockForVM failed\n"); + sceBlock = getVMBlock(); //sceKernelAllocMemBlockForVM("code", sizeof(*ndrc)); + if (sceBlock <= 0) + SysPrintf("sceKernelAllocMemBlockForVM failed: %x\n", sceBlock); int ret = sceKernelGetMemBlockBase(sceBlock, (void **)&ndrc); if (ret < 0) - SysPrintf("sceKernelGetMemBlockBase failed\n"); + SysPrintf("sceKernelGetMemBlockBase failed: %x\n", ret); + sceKernelOpenVMDomain(); + sceClibPrintf("translation_cache = 0x%08lx\n ", (long)ndrc->translation_cache); + #elif defined(_MSC_VER) + ndrc = VirtualAlloc(NULL, sizeof(*ndrc), MEM_COMMIT | MEM_RESERVE, + PAGE_EXECUTE_READWRITE); #else uintptr_t desired_addr = 0; #ifdef __ELF__ @@ -6865,7 +6955,8 @@ void new_dynarec_init(void) #else #ifndef NO_WRITE_EXEC // not all systems allow execute in data segment by default - if (mprotect(ndrc, sizeof(ndrc->translation_cache) + sizeof(ndrc->tramp.ops), + // size must be 4K aligned for 3DS? + if (mprotect(ndrc, sizeof(*ndrc), PROT_READ | PROT_WRITE | PROT_EXEC) != 0) SysPrintf("mprotect() failed: %s\n", strerror(errno)); #endif @@ -6889,8 +6980,9 @@ void new_dynarec_cleanup(void) int n; #ifdef BASE_ADDR_DYNAMIC #ifdef VITA - sceKernelFreeMemBlock(sceBlock); - sceBlock = -1; + // sceBlock is managed by retroarch's bootstrap code + //sceKernelFreeMemBlock(sceBlock); + //sceBlock = -1; #else if (munmap(ndrc, sizeof(*ndrc)) < 0) SysPrintf("munmap() failed\n"); @@ -6906,9 +6998,6 @@ void new_dynarec_cleanup(void) static u_int *get_source_start(u_int addr, u_int *limit) { - if (!HACK_ENABLED(NDHACK_OVERRIDE_CYCLE_M)) - cycle_multiplier_override = 0; - if (addr < 0x00200000 || (0xa0000000 <= addr && addr < 0xa0200000)) { @@ -6923,7 +7012,7 @@ static u_int *get_source_start(u_int addr, u_int *limit) // BIOS. The multiplier should be much higher as it's uncached 8bit mem, // but timings in PCSX are too tied to the interpreter's BIAS if (!HACK_ENABLED(NDHACK_OVERRIDE_CYCLE_M)) - cycle_multiplier_override = 200; + cycle_multiplier_active = 200; *limit = (addr & 0xfff00000) | 0x80000; return (u_int *)((u_char *)psxR + (addr&0x7ffff)); @@ -7035,6 +7124,43 @@ void new_dynarec_load_blocks(const void *save, int size) memcpy(&psxRegs.GPR, regs_save, sizeof(regs_save)); } +static int apply_hacks(void) +{ + int i; + if (HACK_ENABLED(NDHACK_NO_COMPAT_HACKS)) + return 0; + /* special hack(s) */ + for (i = 0; i < slen - 4; i++) + { + // lui a4, 0xf200; jal ; addu a0, 2; slti v0, 28224 + if (source[i] == 0x3c04f200 && dops[i+1].itype == UJUMP + && source[i+2] == 0x34840002 && dops[i+3].opcode == 0x0a + && imm[i+3] == 0x6e40 && dops[i+3].rs1 == 2) + { + SysPrintf("PE2 hack @%08x\n", start + (i+3)*4); + dops[i + 3].itype = NOP; + } + } + i = slen; + if (i > 10 && source[i-1] == 0 && source[i-2] == 0x03e00008 + && source[i-4] == 0x8fbf0018 && source[i-6] == 0x00c0f809 + && dops[i-7].itype == STORE) + { + i = i-8; + if (dops[i].itype == IMM16) + i--; + // swl r2, 15(r6); swr r2, 12(r6); sw r6, *; jalr r6 + if (dops[i].itype == STORELR && dops[i].rs1 == 6 + && dops[i-1].itype == STORELR && dops[i-1].rs1 == 6) + { + SysPrintf("F1 hack from %08x, old dst %08x\n", start, hack_addr); + f1_hack = 1; + return 1; + } + } + return 0; +} + int new_recompile_block(u_int addr) { u_int pagelimit = 0; @@ -7070,9 +7196,11 @@ int new_recompile_block(u_int addr) ll_add_flags(jump_in+page,start,state_rflags,(void *)beginning); return 0; } - else if (f1_hack == ~0u || (f1_hack != 0 && start == f1_hack)) { + else if (f1_hack && hack_addr == 0) { void *beginning = start_block(); u_int page = get_page(start); + emit_movimm(start, 0); + emit_writeword(0, &hack_addr); emit_readword(&psxRegs.GPR.n.sp, 0); emit_readptr(&mem_rtab, 1); emit_shrimm(0, 12, 2); @@ -7088,14 +7216,20 @@ int new_recompile_block(u_int addr) ll_add_flags(jump_in + page, start, state_rflags, beginning); SysPrintf("F1 hack to %08x\n", start); - f1_hack = start; return 0; } + cycle_multiplier_active = cycle_multiplier_override && cycle_multiplier == CYCLE_MULT_DEFAULT + ? cycle_multiplier_override : cycle_multiplier; + source = get_source_start(start, &pagelimit); if (source == NULL) { - SysPrintf("Compile at bogus memory address: %08x\n", addr); - abort(); + if (addr != hack_addr) { + SysPrintf("Compile at bogus memory address: %08x\n", addr); + hack_addr = addr; + } + //abort(); + return -1; } /* Pass 1: disassemble */ @@ -7110,16 +7244,16 @@ int new_recompile_block(u_int addr) /* Pass 10: garbage collection / free memory */ int j; - int done=0; + int done = 0, ni_count = 0; unsigned int type,op,op2; //printf("addr = %x source = %x %x\n", addr,source,source[0]); /* Pass 1 disassembly */ - for(i=0;!done;i++) { - dops[i].bt=0; - dops[i].ooo=0; + for (i = 0; !done; i++) + { + memset(&dops[i], 0, sizeof(dops[i])); op2=0; minimum_free_regs[i]=0; dops[i].opcode=op=source[i]>>26; @@ -7138,7 +7272,7 @@ int new_recompile_block(u_int addr) case 0x08: strcpy(insn[i],"JR"); type=RJUMP; break; case 0x09: strcpy(insn[i],"JALR"); type=RJUMP; break; case 0x0C: strcpy(insn[i],"SYSCALL"); type=SYSCALL; break; - case 0x0D: strcpy(insn[i],"BREAK"); type=OTHER; break; + case 0x0D: strcpy(insn[i],"BREAK"); type=SYSCALL; break; case 0x0F: strcpy(insn[i],"SYNC"); type=OTHER; break; case 0x10: strcpy(insn[i],"MFHI"); type=MOV; break; case 0x11: strcpy(insn[i],"MTHI"); type=MOV; break; @@ -7559,12 +7693,12 @@ int new_recompile_block(u_int addr) do_in_intrp=1; } } - if(do_in_intrp) { - dops[i-1].rs1=CCREG; - dops[i-1].rs2=dops[i-1].rt1=dops[i-1].rt2=0; - ba[i-1]=-1; - dops[i-1].itype=INTCALL; - done=2; + if (do_in_intrp) { + memset(&dops[i-1], 0, sizeof(dops[i-1])); + dops[i-1].itype = INTCALL; + dops[i-1].rs1 = CCREG; + ba[i-1] = -1; + done = 2; i--; // don't compile the DS } } @@ -7584,9 +7718,9 @@ int new_recompile_block(u_int addr) // Don't get too close to the limit if(i>MAXBLOCK/2) done=1; } - if(dops[i].itype==SYSCALL&&stop_after_jal) done=1; - if(dops[i].itype==HLECALL||dops[i].itype==INTCALL) done=2; - if(done==2) { + if (dops[i].itype == SYSCALL || dops[i].itype == HLECALL || dops[i].itype == INTCALL) + done = stop_after_jal ? 1 : 2; + if (done == 2) { // Does the block continue due to a branch? for(j=i-1;j>=0;j--) { @@ -7600,7 +7734,7 @@ int new_recompile_block(u_int addr) assert(start+i*4 8 || dops[i].opcode == 0x11)) { done=stop_after_jal=1; SysPrintf("Disabled speculative precompilation\n"); } @@ -7613,23 +7747,7 @@ int new_recompile_block(u_int addr) } assert(slen>0); - /* spacial hack(s) */ - if (i > 10 && source[i-1] == 0 && source[i-2] == 0x03e00008 - && source[i-4] == 0x8fbf0018 && source[i-6] == 0x00c0f809 - && dops[i-7].itype == STORE) - { - i = i-8; - if (dops[i].itype == IMM16) - i--; - // swl r2, 15(r6); swr r2, 12(r6); sw r6, *; jalr r6 - if (dops[i].itype == STORELR && dops[i].rs1 == 6 - && dops[i-1].itype == STORELR && dops[i-1].rs1 == 6) - { - SysPrintf("F1 hack from %08x\n", start); - if (f1_hack == 0) - f1_hack = ~0u; - } - } + int clear_hack_addr = apply_hacks(); /* Pass 2 - Register dependencies and branch targets */ @@ -7638,14 +7756,16 @@ int new_recompile_block(u_int addr) /* Pass 3 - Register allocation */ struct regstat current; // Current register allocations/status - current.dirty=0; - current.u=unneeded_reg[0]; + clear_all_regs(current.regmap_entry); clear_all_regs(current.regmap); - alloc_reg(¤t,0,CCREG); - dirty_reg(¤t,CCREG); - current.isconst=0; - current.wasconst=0; - current.waswritten=0; + current.wasdirty = current.dirty = 0; + current.u = unneeded_reg[0]; + alloc_reg(¤t, 0, CCREG); + dirty_reg(¤t, CCREG); + current.wasconst = 0; + current.isconst = 0; + current.loadedconst = 0; + current.waswritten = 0; int ds=0; int cc=0; int hr=-1; @@ -7676,6 +7796,9 @@ int new_recompile_block(u_int addr) memcpy(regmap_pre[i],current.regmap,sizeof(current.regmap)); regs[i].wasconst=current.isconst; regs[i].wasdirty=current.dirty; + regs[i].dirty=0; + regs[i].u=0; + regs[i].isconst=0; regs[i].loadedconst=0; if (!dops[i].is_jump) { if(i+1=TEMPREG){ + if(or<0||r>=TEMPREG){ regs[i].regmap_entry[hr]=-1; } else @@ -7995,7 +8121,7 @@ int new_recompile_block(u_int addr) // Just move it to a different register regs[i].regmap_entry[hr]=r; // If it was dirty before, it's still dirty - if((regs[i].wasdirty>>or)&1) dirty_reg(¤t,r&63); + if((regs[i].wasdirty>>or)&1) dirty_reg(¤t,r); } } else @@ -8331,8 +8457,8 @@ int new_recompile_block(u_int addr) // Merge in delay slot for(hr=0;hr0&&!dops[i].bt&&((regs[i].wasdirty>>hr)&1)) { if((regmap_pre[i][hr]>0&&!((unneeded_reg[i]>>regmap_pre[i][hr])&1))) { - if(dops[i-1].rt1==(regmap_pre[i][hr]&63)) nr|=1<0&&!((unneeded_reg[i]>>regs[i].regmap_entry[hr])&1))) { - if(dops[i-1].rt1==(regs[i].regmap_entry[hr]&63)) nr|=1< %x, %x %d/%d\n",start+i*4,ba[i],start+j*4,hr,r); if(r<34&&((unneeded_reg[j]>>r)&1)) break; assert(r < 64); - if(regs[j].regmap[hr]==f_regmap[hr]&&(f_regmap[hr]&63) %x, %x %d/%d\n",start+i*4,ba[i],start+j*4,hr,r); int k; if(regs[i].regmap[hr]==-1&&branch_regs[i].regmap[hr]==-1) { + if(get_reg(regs[i].regmap,f_regmap[hr])>=0) break; if(get_reg(regs[i+2].regmap,f_regmap[hr])>=0) break; - if(r>63) { - if(get_reg(regs[i].regmap,r&63)<0) break; - if(get_reg(branch_regs[i].regmap,r&63)<0) break; - } k=i; while(k>1&®s[k-1].regmap[hr]==-1) { if(count_free_regs(regs[k-1].regmap)<=minimum_free_regs[k-1]) { @@ -8596,7 +8723,6 @@ int new_recompile_block(u_int addr) if(k>2&&(dops[k-3].itype==UJUMP||dops[k-3].itype==RJUMP)&&dops[k-3].rt1==31) { break; } - assert(r < 64); k--; } if(regs[k-1].regmap[hr]==f_regmap[hr]&®map_pre[k][hr]==f_regmap[hr]) { @@ -8874,8 +9000,11 @@ int new_recompile_block(u_int addr) ||(dops[i+1].opcode&0x3b)==0x39||(dops[i+1].opcode&0x3b)==0x3a) { // SB/SH/SW/SD/SWC1/SDC1/SWC2/SDC2 if(get_reg(regs[i+1].regmap,dops[i+1].rs1)<0) { hr=get_reg2(regs[i].regmap,regs[i+1].regmap,-1); - if(hr<0) hr=get_reg(regs[i+1].regmap,-1); - else {regs[i+1].regmap[hr]=AGEN1+((i+1)&1);regs[i+1].isconst&=~(1<=0); if(regs[i].regmap[hr]<0&®s[i+1].regmap_entry[hr]<0) { @@ -8932,7 +9061,7 @@ int new_recompile_block(u_int addr) hr=get_reg(regs[i+1].regmap,FTEMP); if(dops[i+1].itype==STORE||dops[i+1].itype==STORELR||(dops[i+1].opcode&0x3b)==0x39||(dops[i+1].opcode&0x3b)==0x3a) { // SWC1/SDC1/SWC2/SDC2 hr=get_reg(regs[i+1].regmap,AGEN1+((i+1)&1)); - if(hr<0) hr=get_reg(regs[i+1].regmap,-1); + if(hr<0) hr=get_reg_temp(regs[i+1].regmap); } if(hr>=0&®s[i].regmap[hr]<0) { int rs=get_reg(regs[i+1].regmap,dops[i+1].rs1); @@ -8972,7 +9101,7 @@ int new_recompile_block(u_int addr) dops[slen-1].bt=1; // Mark as a branch target so instruction can restart after exception } -#ifdef DISASM +#ifdef REG_ALLOC_PRINT /* Debug/disassembly */ for(i=0;i\n"); drc_dbg_emit_do_cmp(i, ccadj[i]); + if (clear_hack_addr) { + emit_movimm(0, 0); + emit_writeword(0, &hack_addr); + clear_hack_addr = 0; + } // load regs if(regs[i].regmap_entry[HOST_CCREG]==CCREG&®s[i].regmap[HOST_CCREG]!=CCREG)