From 03f55e6b49eb81d099f33b67ee6b5fa4620a54bc Mon Sep 17 00:00:00 2001 From: notaz Date: Mon, 22 Dec 2014 04:10:25 +0200 Subject: [PATCH] drc: implement block addr list saving should give better experience after savestate load --- frontend/libretro.c | 5 +- libpcsxcore/misc.c | 5 +- libpcsxcore/new_dynarec/emu_if.c | 50 ++++++- libpcsxcore/new_dynarec/new_dynarec.c | 205 +++++++++++++++++--------- libpcsxcore/new_dynarec/new_dynarec.h | 2 + libpcsxcore/r3000a.h | 4 +- 6 files changed, 196 insertions(+), 75 deletions(-) diff --git a/frontend/libretro.c b/frontend/libretro.c index fa544fd5..34e3b4ef 100644 --- a/frontend/libretro.c +++ b/frontend/libretro.c @@ -303,8 +303,9 @@ void retro_get_system_av_info(struct retro_system_av_info *info) /* savestates */ size_t retro_serialize_size(void) { - // it's currently 4380651 bytes, but have some reserved for future - return 0x430000; + // it's currently 4380651-4397047 bytes, + // but have some reserved for future + return 0x440000; } struct save_fp { diff --git a/libpcsxcore/misc.c b/libpcsxcore/misc.c index 3ee9876d..58170cf0 100644 --- a/libpcsxcore/misc.c +++ b/libpcsxcore/misc.c @@ -573,7 +573,7 @@ int SaveState(const char *file) { f = SaveFuncs.open(file, "wb"); if (f == NULL) return -1; - new_dyna_save(); + new_dyna_before_save(); SaveFuncs.write(f, (void *)PcsxHeader, 32); SaveFuncs.write(f, (void *)&SaveVersion, sizeof(u32)); @@ -615,6 +615,7 @@ int SaveState(const char *file) { psxHwFreeze(f, 1); psxRcntFreeze(f, 1); mdecFreeze(f, 1); + new_dyna_freeze(f, 1); SaveFuncs.close(f); @@ -679,9 +680,9 @@ int LoadState(const char *file) { psxHwFreeze(f, 0); psxRcntFreeze(f, 0); mdecFreeze(f, 0); + new_dyna_freeze(f, 0); SaveFuncs.close(f); - new_dyna_restore(); return 0; } diff --git a/libpcsxcore/new_dynarec/emu_if.c b/libpcsxcore/new_dynarec/emu_if.c index 89e2bd6f..b7a24890 100644 --- a/libpcsxcore/new_dynarec/emu_if.c +++ b/libpcsxcore/new_dynarec/emu_if.c @@ -122,7 +122,7 @@ void pcsx_mtc0_ds(u32 reg, u32 val) MTC0(reg, val); } -void new_dyna_save(void) +void new_dyna_before_save(void) { psxRegs.interrupt &= ~(1 << PSXINT_RCNT); // old savestate compat @@ -134,7 +134,7 @@ void new_dyna_after_save(void) psxRegs.interrupt |= 1 << PSXINT_RCNT; } -void new_dyna_restore(void) +static void new_dyna_restore(void) { int i; for (i = 0; i < PSXINT_COUNT; i++) @@ -147,6 +147,50 @@ void new_dyna_restore(void) new_dyna_pcsx_mem_load_state(); } +void new_dyna_freeze(void *f, int mode) +{ + const char header_save[8] = "ariblks"; + uint32_t addrs[1024 * 4]; + int32_t size = 0; + int bytes; + char header[8]; + + if (mode != 0) { // save + size = new_dynarec_save_blocks(addrs, sizeof(addrs)); + if (size == 0) + return; + + SaveFuncs.write(f, header_save, sizeof(header_save)); + SaveFuncs.write(f, &size, sizeof(size)); + SaveFuncs.write(f, addrs, size); + } + else { + new_dyna_restore(); + + bytes = SaveFuncs.read(f, header, sizeof(header)); + if (bytes != sizeof(header) || strcmp(header, header_save)) { + if (bytes > 0) + SaveFuncs.seek(f, -bytes, SEEK_CUR); + return; + } + SaveFuncs.read(f, &size, sizeof(size)); + if (size <= 0) + return; + if (size > sizeof(addrs)) { + bytes = size - sizeof(addrs); + SaveFuncs.seek(f, bytes, SEEK_CUR); + size = sizeof(addrs); + } + bytes = SaveFuncs.read(f, addrs, size); + if (bytes != size) + return; + + new_dynarec_load_blocks(addrs, size); + } + + //printf("drc: %d block info entries %s\n", size/8, mode ? "saved" : "loaded"); +} + /* GTE stuff */ void *gte_handlers[64]; @@ -407,6 +451,8 @@ void new_dyna_pcsx_mem_init(void) {} void new_dyna_pcsx_mem_reset(void) {} void new_dyna_pcsx_mem_load_state(void) {} void new_dyna_pcsx_mem_shutdown(void) {} +int new_dynarec_save_blocks(void *save, int size) { return 0; } +void new_dynarec_load_blocks(const void *save, int size) {} #endif #ifdef DRC_DBG diff --git a/libpcsxcore/new_dynarec/new_dynarec.c b/libpcsxcore/new_dynarec/new_dynarec.c index 82b7445a..8d1e53ac 100644 --- a/libpcsxcore/new_dynarec/new_dynarec.c +++ b/libpcsxcore/new_dynarec/new_dynarec.c @@ -85,7 +85,6 @@ struct ll_entry u_int start; u_int *source; - u_int pagelimit; char insn[MAXBLOCK][10]; u_char itype[MAXBLOCK]; u_char opcode[MAXBLOCK]; @@ -8059,17 +8058,132 @@ void new_dynarec_cleanup() #endif } -int new_recompile_block(int addr) +static u_int *get_source_start(u_int addr, u_int *limit) { -/* - if(addr==0x800cd050) { - int block; - for(block=0x80000;block<0x80800;block++) invalidate_block(block); - int n; - for(n=0;n<=2048;n++) ll_clear(jump_dirty+n); + if (addr < 0x00200000 || + (0xa0000000 <= addr && addr < 0xa0200000)) { + // used for BIOS calls mostly? + *limit = (addr&0xa0000000)|0x00200000; + return (u_int *)((u_int)rdram + (addr&0x1fffff)); + } + else if (!Config.HLE && ( + /* (0x9fc00000 <= addr && addr < 0x9fc80000) ||*/ + (0xbfc00000 <= addr && addr < 0xbfc80000))) { + // BIOS + *limit = (addr & 0xfff00000) | 0x80000; + return (u_int *)((u_int)psxR + (addr&0x7ffff)); + } + else if (addr >= 0x80000000 && addr < 0x80000000+RAM_SIZE) { + *limit = (addr & 0x80600000) + 0x00200000; + return (u_int *)((u_int)rdram + (addr&0x1fffff)); + } +} + +static u_int scan_for_ret(u_int addr) +{ + u_int limit = 0; + u_int *mem; + + mem = get_source_start(addr, &limit); + if (mem == NULL) + return addr; + + if (limit > addr + 0x1000) + limit = addr + 0x1000; + for (; addr < limit; addr += 4, mem++) { + if (*mem == 0x03e00008) // jr $ra + return addr + 8; } -*/ - //if(Count==365117028) tracedebug=1; +} + +struct savestate_block { + uint32_t addr; + uint32_t regflags; +}; + +static int addr_cmp(const void *p1_, const void *p2_) +{ + const struct savestate_block *p1 = p1_, *p2 = p2_; + return p1->addr - p2->addr; +} + +int new_dynarec_save_blocks(void *save, int size) +{ + struct savestate_block *blocks = save; + int maxcount = size / sizeof(blocks[0]); + struct savestate_block tmp_blocks[1024]; + struct ll_entry *head; + int p, s, d, o, bcnt; + u_int addr; + + o = 0; + for (p = 0; p < sizeof(jump_in) / sizeof(jump_in[0]); p++) { + bcnt = 0; + for (head = jump_in[p]; head != NULL; head = head->next) { + tmp_blocks[bcnt].addr = head->vaddr; + tmp_blocks[bcnt].regflags = head->reg_sv_flags; + bcnt++; + } + if (bcnt < 1) + continue; + qsort(tmp_blocks, bcnt, sizeof(tmp_blocks[0]), addr_cmp); + + addr = tmp_blocks[0].addr; + for (s = d = 0; s < bcnt; s++) { + if (tmp_blocks[s].addr < addr) + continue; + if (d == 0 || tmp_blocks[d-1].addr != tmp_blocks[s].addr) + tmp_blocks[d++] = tmp_blocks[s]; + addr = scan_for_ret(tmp_blocks[s].addr); + } + + if (o + d > maxcount) + d = maxcount - o; + memcpy(&blocks[o], tmp_blocks, d * sizeof(blocks[0])); + o += d; + } + + return o * sizeof(blocks[0]); +} + +void new_dynarec_load_blocks(const void *save, int size) +{ + const struct savestate_block *blocks = save; + int count = size / sizeof(blocks[0]); + u_int regs_save[32]; + uint32_t f; + int i, b; + + get_addr(psxRegs.pc); + + // change GPRs for speculation to at least partially work.. + memcpy(regs_save, &psxRegs.GPR, sizeof(regs_save)); + for (i = 1; i < 32; i++) + psxRegs.GPR.r[i] = 0x80000000; + + for (b = 0; b < count; b++) { + for (f = blocks[b].regflags, i = 0; f; f >>= 1, i++) { + if (f & 1) + psxRegs.GPR.r[i] = 0x1f800000; + } + + get_addr(blocks[b].addr); + + for (f = blocks[b].regflags, i = 0; f; f >>= 1, i++) { + if (f & 1) + psxRegs.GPR.r[i] = 0x80000000; + } + } + + memcpy(&psxRegs.GPR, regs_save, sizeof(regs_save)); +} + +int new_recompile_block(int addr) +{ + u_int pagelimit = 0; + u_int state_rflags = 0; + int i; + assem_debug("NOTCOMPILED: addr = %x -> %x\n", (int)addr, (int)out); //printf("NOTCOMPILED: addr = %x -> %x\n", (int)addr, (int)out); //printf("TRACE: count=%d next=%d (compile %x)\n",Count,next_interupt,addr); @@ -8080,10 +8194,16 @@ int new_recompile_block(int addr) rlist(); }*/ //rlist(); + + // this is just for speculation + for (i = 1; i < 32; i++) { + if ((psxRegs.GPR.r[i] & 0xffff0000) == 0x1f800000) + state_rflags |= 1 << i; + } + start = (u_int)addr&~3; //assert(((u_int)addr&1)==0); new_dynarec_did_compile=1; -#ifdef PCSX if (Config.HLE && start == 0x80001000) // hlecall { // XXX: is this enough? Maybe check hleSoftCall? @@ -8097,62 +8217,13 @@ int new_recompile_block(int addr) #ifdef __arm__ __clear_cache((void *)beginning,out); #endif - ll_add(jump_in+page,start,(void *)beginning); + ll_add_flags(jump_in+page,start,state_rflags,(void *)beginning); return 0; } - else if ((u_int)addr < 0x00200000 || - (0xa0000000 <= addr && addr < 0xa0200000)) { - // used for BIOS calls mostly? - source = (u_int *)((u_int)rdram+(start&0x1fffff)); - pagelimit = (addr&0xa0000000)|0x00200000; - } - else if (!Config.HLE && ( -/* (0x9fc00000 <= addr && addr < 0x9fc80000) ||*/ - (0xbfc00000 <= addr && addr < 0xbfc80000))) { - // BIOS - source = (u_int *)((u_int)psxR+(start&0x7ffff)); - pagelimit = (addr&0xfff00000)|0x80000; - } - else -#endif -#ifdef MUPEN64 - if ((int)addr >= 0xa4000000 && (int)addr < 0xa4001000) { - source = (u_int *)((u_int)SP_DMEM+start-0xa4000000); - pagelimit = 0xa4001000; - } - else -#endif - if ((int)addr >= 0x80000000 && (int)addr < 0x80000000+RAM_SIZE) { - source = (u_int *)((u_int)rdram+start-0x80000000); - pagelimit = 0x80000000+RAM_SIZE; - } -#ifndef DISABLE_TLB - else if ((signed int)addr >= (signed int)0xC0000000) { - //printf("addr=%x mm=%x\n",(u_int)addr,(memory_map[start>>12]<<2)); - //if(tlb_LUT_r[start>>12]) - //source = (u_int *)(((int)rdram)+(tlb_LUT_r[start>>12]&0xFFFFF000)+(((int)addr)&0xFFF)-0x80000000); - if((signed int)memory_map[start>>12]>=0) { - source = (u_int *)((u_int)(start+(memory_map[start>>12]<<2))); - pagelimit=(start+4096)&0xFFFFF000; - int map=memory_map[start>>12]; - int i; - for(i=0;i<5;i++) { - //printf("start: %x next: %x\n",map,memory_map[pagelimit>>12]); - if((map&0xBFFFFFFF)==(memory_map[pagelimit>>12]&0xBFFFFFFF)) pagelimit+=4096; - } - assem_debug("pagelimit=%x\n",pagelimit); - assem_debug("mapping=%x (%x)\n",memory_map[start>>12],(memory_map[start>>12]<<2)+start); - } - else { - assem_debug("Compile at unmapped memory address: %x \n", (int)addr); - //assem_debug("start: %x next: %x\n",memory_map[start>>12],memory_map[(start+4096)>>12]); - return -1; // Caller will invoke exception handler - } - //printf("source= %x\n",(int)source); - } -#endif - else { - SysPrintf("Compile at bogus memory address: %x \n", (int)addr); + + source = get_source_start(start, &pagelimit); + if (source == NULL) { + SysPrintf("Compile at bogus memory address: %08x\n", addr); exit(1); } @@ -8167,7 +8238,7 @@ int new_recompile_block(int addr) /* Pass 9: linker */ /* Pass 10: garbage collection / free memory */ - int i,j; + int j; int done=0; unsigned int type,op,op2; @@ -11482,7 +11553,7 @@ int new_recompile_block(int addr) assem_debug("jump_in: %x\n",start+i*4); ll_add(jump_dirty+vpage,vaddr,(void *)out); int entry_point=do_dirty_stub(i); - ll_add(jump_in+page,vaddr,(void *)entry_point); + ll_add_flags(jump_in+page,vaddr,state_rflags,(void *)entry_point); // If there was an existing entry in the hash table, // replace it with the new address. // Don't add new entries. We'll insert the diff --git a/libpcsxcore/new_dynarec/new_dynarec.h b/libpcsxcore/new_dynarec/new_dynarec.h index 1396ef88..ddc84a5a 100644 --- a/libpcsxcore/new_dynarec/new_dynarec.h +++ b/libpcsxcore/new_dynarec/new_dynarec.h @@ -15,6 +15,8 @@ void new_dynarec_init(); void new_dynarec_cleanup(); void new_dynarec_clear_full(); void new_dyna_start(); +int new_dynarec_save_blocks(void *save, int size); +void new_dynarec_load_blocks(const void *save, int size); void invalidate_all_pages(); void invalidate_block(unsigned int block); diff --git a/libpcsxcore/r3000a.h b/libpcsxcore/r3000a.h index a6a6254e..31aa3f8e 100644 --- a/libpcsxcore/r3000a.h +++ b/libpcsxcore/r3000a.h @@ -192,9 +192,9 @@ extern psxRegisters psxRegs; extern u32 event_cycles[PSXINT_COUNT]; extern u32 next_interupt; -void new_dyna_save(void); +void new_dyna_before_save(void); void new_dyna_after_save(void); -void new_dyna_restore(void); +void new_dyna_freeze(void *f, int mode); #define new_dyna_set_event(e, c) { \ s32 c_ = c; \ -- 2.39.2