X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=libpcsxcore%2Fnew_dynarec%2Fnew_dynarec.c;h=f9046bda9ee270aa6603c5231400dbb45964afc1;hb=5a18ce2e9a7dac901f6cfb5d0b42c58f23c53b29;hp=e937b762e33d8f8e01df106e350ae3375644a788;hpb=9c67c98f2350736b964e616743daf7aa10d022ec;p=pcsx_rearmed.git diff --git a/libpcsxcore/new_dynarec/new_dynarec.c b/libpcsxcore/new_dynarec/new_dynarec.c index e937b762..f9046bda 100644 --- a/libpcsxcore/new_dynarec/new_dynarec.c +++ b/libpcsxcore/new_dynarec/new_dynarec.c @@ -49,6 +49,7 @@ //#define DISASM //#define ASSEM_PRINT +//#define REG_ALLOC_PRINT #ifdef ASSEM_PRINT #define assem_debug printf @@ -75,9 +76,17 @@ #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)]; @@ -110,9 +119,14 @@ 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; @@ -198,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() @@ -224,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; @@ -289,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 @@ -320,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(); @@ -586,10 +604,9 @@ 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[]) { - int hr; - for (hr=0;hrregmap, 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_) @@ -5591,7 +5618,7 @@ static void sjump_assemble(int i, const struct regstat *i_regs) int cc; int match; match=match_bt(branch_regs[i].regmap,branch_regs[i].dirty,ba[i]); - assem_debug("smatch=%d\n",match); + assem_debug("smatch=%d ooo=%d\n", match, dops[i].ooo); int s1l; int unconditional=0,nevertaken=0; int invert=0; @@ -5828,7 +5855,9 @@ static void sjump_assemble(int i, const struct regstat *i_regs) wb_invalidate(regs[i].regmap,branch_regs[i].regmap,regs[i].dirty,ds_unneeded); load_regs(regs[i].regmap,branch_regs[i].regmap,dops[i+1].rs1,dops[i+1].rs2); address_generation(i+1,&branch_regs[i],0); - load_regs(regs[i].regmap,branch_regs[i].regmap,CCREG,CCREG); + if (ram_offset) + load_regs(regs[i].regmap,branch_regs[i].regmap,ROREG,ROREG); + load_regs(regs[i].regmap,branch_regs[i].regmap,CCREG,INVCP); ds_assemble(i+1,&branch_regs[i]); cc=get_reg(branch_regs[i].regmap,CCREG); if (cc == -1) { @@ -6117,8 +6146,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; @@ -6688,6 +6730,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) { @@ -6773,6 +6833,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) {} @@ -6831,6 +6901,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); @@ -6843,7 +6914,7 @@ 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(); @@ -6851,11 +6922,11 @@ void new_dynarec_init(void) #ifdef BASE_ADDR_DYNAMIC #ifdef VITA sceBlock = getVMBlock(); //sceKernelAllocMemBlockForVM("code", sizeof(*ndrc)); - if (sceBlock < 0) - SysPrintf("sceKernelAllocMemBlockForVM failed\n"); + 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) @@ -6903,6 +6974,7 @@ void new_dynarec_cleanup(void) int n; #ifdef BASE_ADDR_DYNAMIC #ifdef VITA + // sceBlock is managed by retroarch's bootstrap code //sceKernelFreeMemBlock(sceBlock); //sceBlock = -1; #else @@ -7046,11 +7118,11 @@ void new_dynarec_load_blocks(const void *save, int size) memcpy(&psxRegs.GPR, regs_save, sizeof(regs_save)); } -static void apply_hacks(void) +static int apply_hacks(void) { int i; if (HACK_ENABLED(NDHACK_NO_COMPAT_HACKS)) - return; + return 0; /* special hack(s) */ for (i = 0; i < slen - 4; i++) { @@ -7075,11 +7147,12 @@ static void apply_hacks(void) 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; + 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) @@ -7117,9 +7190,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); @@ -7135,7 +7210,6 @@ 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; } @@ -7188,7 +7262,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; @@ -7634,9 +7708,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--) { @@ -7663,7 +7737,7 @@ int new_recompile_block(u_int addr) } assert(slen>0); - apply_hacks(); + int clear_hack_addr = apply_hacks(); /* Pass 2 - Register dependencies and branch targets */ @@ -7672,14 +7746,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; @@ -7710,6 +7786,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 %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]) { @@ -8633,7 +8713,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]) { @@ -8912,7 +8991,10 @@ int new_recompile_block(u_int addr) 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) { @@ -9009,7 +9091,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)