From 403a6290ffad888ab6e3ca05ce4736f052e4147f Mon Sep 17 00:00:00 2001 From: notaz Date: Mon, 2 Oct 2023 00:02:39 +0300 Subject: [PATCH] patch up some savestate issues exposed by RetroArch's run-ahead/rewind functionality --- frontend/libretro.c | 1 - libpcsxcore/lightrec/plugin.c | 5 +- libpcsxcore/mdec.c | 13 +++-- libpcsxcore/misc.c | 4 +- libpcsxcore/new_dynarec/events.h | 2 + libpcsxcore/psxbios.c | 5 +- libpcsxcore/psxbios.h | 2 +- libpcsxcore/psxcounters.c | 8 +--- plugins/dfsound/externals.h | 2 +- plugins/dfsound/freeze.c | 81 +++++++++++++++++++++++--------- plugins/dfsound/spu.c | 8 ++-- plugins/dfsound/spu.h | 2 + plugins/dfsound/spu_config.h | 1 - plugins/dfsound/xa.c | 9 ++-- 14 files changed, 89 insertions(+), 54 deletions(-) diff --git a/frontend/libretro.c b/frontend/libretro.c index a26d4662..b8b11665 100644 --- a/frontend/libretro.c +++ b/frontend/libretro.c @@ -3120,7 +3120,6 @@ void retro_init(void) #endif pl_rearmed_cbs.gpu_peops.iUseDither = 1; pl_rearmed_cbs.gpu_peops.dwActFixes = GPU_PEOPS_OLD_FRAME_SKIP; - spu_config.iUseFixedUpdates = 1; SaveFuncs.open = save_open; SaveFuncs.read = save_read; diff --git a/libpcsxcore/lightrec/plugin.c b/libpcsxcore/lightrec/plugin.c index 1fe04f65..d51fbc24 100644 --- a/libpcsxcore/lightrec/plugin.c +++ b/libpcsxcore/lightrec/plugin.c @@ -492,6 +492,9 @@ static void lightrec_plugin_execute_internal(bool block_only) regs = lightrec_get_registers(lightrec_state); gen_interupt((psxCP0Regs *)regs->cp0); + if (!block_only && stop) + return; + cycles_pcsx = next_interupt - psxRegs.cycle; assert((s32)cycles_pcsx > 0); @@ -549,8 +552,6 @@ static void lightrec_plugin_execute_internal(bool block_only) static void lightrec_plugin_execute(void) { - extern int stop; - while (!stop) lightrec_plugin_execute_internal(false); } diff --git a/libpcsxcore/mdec.c b/libpcsxcore/mdec.c index 167a1cff..612fe974 100644 --- a/libpcsxcore/mdec.c +++ b/libpcsxcore/mdec.c @@ -674,27 +674,26 @@ void mdec1Interrupt() { } int mdecFreeze(void *f, int Mode) { - u8 *base = (u8 *)&psxM[0x100000]; + u8 *base = (u8 *)psxM; u32 v; gzfreeze(&mdec.reg0, sizeof(mdec.reg0)); gzfreeze(&mdec.reg1, sizeof(mdec.reg1)); - // old code used to save raw pointers.. v = (u8 *)mdec.rl - base; gzfreeze(&v, sizeof(v)); - mdec.rl = (u16 *)(base + (v & 0xffffe)); + mdec.rl = (u16 *)(base + (v & 0x1ffffe)); v = (u8 *)mdec.rl_end - base; gzfreeze(&v, sizeof(v)); - mdec.rl_end = (u16 *)(base + (v & 0xffffe)); + mdec.rl_end = (u16 *)(base + (v & 0x1ffffe)); v = 0; if (mdec.block_buffer_pos) - v = mdec.block_buffer_pos - base; + v = mdec.block_buffer_pos - mdec.block_buffer; gzfreeze(&v, sizeof(v)); mdec.block_buffer_pos = 0; - if (v) - mdec.block_buffer_pos = base + (v & 0xfffff); + if (v && v < sizeof(mdec.block_buffer)) + mdec.block_buffer_pos = mdec.block_buffer; gzfreeze(&mdec.block_buffer, sizeof(mdec.block_buffer)); gzfreeze(&mdec.pending_dma1, sizeof(mdec.pending_dma1)); diff --git a/libpcsxcore/misc.c b/libpcsxcore/misc.c index d748ac07..8997c0b5 100644 --- a/libpcsxcore/misc.c +++ b/libpcsxcore/misc.c @@ -288,7 +288,7 @@ int LoadCdrom() { //psxCpu->Reset(); if (Config.HLE) - psxBiosCheckExe(tmpHead.h.t_addr, tmpHead.h.t_size); + psxBiosCheckExe(tmpHead.h.t_addr, tmpHead.h.t_size, 0); return 0; } @@ -770,7 +770,7 @@ int LoadState(const char *file) { padFreeze(f, 0); if (Config.HLE) - psxBiosCheckExe(biosBranchCheckOld, 0x60); + psxBiosCheckExe(biosBranchCheckOld, 0x60, 1); result = 0; cleanup: diff --git a/libpcsxcore/new_dynarec/events.h b/libpcsxcore/new_dynarec/events.h index eeec289d..5f57f374 100644 --- a/libpcsxcore/new_dynarec/events.h +++ b/libpcsxcore/new_dynarec/events.h @@ -1,5 +1,7 @@ #include "../psxcommon.h" +extern int stop; + union psxCP0Regs_; u32 schedule_timeslice(void); void gen_interupt(union psxCP0Regs_ *cp0); diff --git a/libpcsxcore/psxbios.c b/libpcsxcore/psxbios.c index bad34578..73f277a0 100644 --- a/libpcsxcore/psxbios.c +++ b/libpcsxcore/psxbios.c @@ -4175,7 +4175,7 @@ void (* const psxHLEt[24])() = { hleExcPadCard1, hleExcPadCard2, }; -void psxBiosCheckExe(u32 t_addr, u32 t_size) +void psxBiosCheckExe(u32 t_addr, u32 t_size, int loading_state) { // lw $v0, 0x10($sp) // nop @@ -4213,7 +4213,8 @@ void psxBiosCheckExe(u32 t_addr, u32 t_size) if ((SWAP32(r32[i + j]) >> 16) != 0x3c04) // lui continue; - SysPrintf("HLE vsync @%08x\n", start + i * 4); + if (!loading_state) + SysPrintf("HLE vsync @%08x\n", start + i * 4); psxRegs.biosBranchCheck = (t_addr & 0xa01ffffc) + i * 4; } } diff --git a/libpcsxcore/psxbios.h b/libpcsxcore/psxbios.h index c1368e67..c8c07ff7 100644 --- a/libpcsxcore/psxbios.h +++ b/libpcsxcore/psxbios.h @@ -40,7 +40,7 @@ void psxBiosException(); void psxBiosFreeze(int Mode); void psxBiosCnfLoaded(u32 tcb_cnt, u32 evcb_cnt, u32 sp); void psxBiosSetupBootState(void); -void psxBiosCheckExe(u32 t_addr, u32 t_size); +void psxBiosCheckExe(u32 t_addr, u32 t_size, int loading_state); void psxBiosCheckBranch(void); extern void (*biosA0[256])(); diff --git a/libpcsxcore/psxcounters.c b/libpcsxcore/psxcounters.c index 9ff679e2..ab8beeea 100644 --- a/libpcsxcore/psxcounters.c +++ b/libpcsxcore/psxcounters.c @@ -561,7 +561,6 @@ void psxRcntInit() s32 psxRcntFreeze( void *f, s32 Mode ) { u32 spuSyncCount = 0; - u32 count; s32 i; gzfreeze( &rcnts, sizeof(Rcnt) * CounterQuantity ); @@ -572,14 +571,9 @@ s32 psxRcntFreeze( void *f, s32 Mode ) if (Mode == 0) { - // don't trust things from a savestate rcnts[3].rate = 1; - for( i = 0; i < CounterQuantity; ++i ) - { + for( i = 0; i < CounterQuantity - 1; ++i ) _psxRcntWmode( i, rcnts[i].mode ); - count = (psxRegs.cycle - rcnts[i].cycleStart) / rcnts[i].rate; - _psxRcntWcount( i, count ); - } scheduleRcntBase(); psxRcntSet(); } diff --git a/plugins/dfsound/externals.h b/plugins/dfsound/externals.h index f3fbc678..4407177a 100644 --- a/plugins/dfsound/externals.h +++ b/plugins/dfsound/externals.h @@ -218,7 +218,7 @@ typedef struct void (CALLBACK *cddavCallback)(short, short); void (CALLBACK *scheduleCallback)(unsigned int); - xa_decode_t * xapGlobal; + const xa_decode_t * xapGlobal; unsigned int * XAFeed; unsigned int * XAPlay; unsigned int * XAStart; diff --git a/plugins/dfsound/freeze.c b/plugins/dfsound/freeze.c index 51e9fd77..d4898b46 100644 --- a/plugins/dfsound/freeze.c +++ b/plugins/dfsound/freeze.c @@ -122,9 +122,10 @@ typedef struct unsigned short decode_pos; uint32_t pSpuIrq; uint32_t spuAddr; - uint32_t dummy1; - uint32_t dummy2; - uint32_t dummy3; + uint32_t rvb_cur; + uint16_t xa_left; + uint16_t cdda_left; + uint32_t cycles_played; SPUCHAN_orig s_chan[MAXCHAN]; @@ -132,8 +133,8 @@ typedef struct //////////////////////////////////////////////////////////////////////// -void LoadStateV5(SPUFreeze_t * pF); // newest version -void LoadStateUnknown(SPUFreeze_t * pF, uint32_t cycles); // unknown format +static SPUOSSFreeze_t * LoadStateV5(SPUFreeze_t * pF, uint32_t cycles); +static void LoadStateUnknown(SPUFreeze_t * pF, uint32_t cycles); // unknown format // we want to retain compatibility between versions, // so use original channel struct @@ -228,14 +229,16 @@ static void load_register(unsigned long reg, unsigned int cycles) long CALLBACK SPUfreeze(uint32_t ulFreezeMode, SPUFreeze_t * pF, uint32_t cycles) { - int i;SPUOSSFreeze_t * pFO; + SPUOSSFreeze_t * pFO = NULL; + int i; if(!pF) return 0; // first check - do_samples(cycles, 1); - if(ulFreezeMode) // info or save? {//--------------------------------------------------// + int xa_left = 0, cdda_left = 0; + do_samples(cycles, 1); + if(ulFreezeMode==1) memset(pF,0,sizeof(SPUFreeze_t)+sizeof(SPUOSSFreeze_t)); @@ -250,10 +253,31 @@ long CALLBACK SPUfreeze(uint32_t ulFreezeMode, SPUFreeze_t * pF, if(spu.xapGlobal && spu.XAPlay!=spu.XAFeed) // some xa { - pF->xaS=*spu.xapGlobal; + xa_left = spu.XAFeed - spu.XAPlay; + if (xa_left < 0) + xa_left = spu.XAEnd - spu.XAPlay + spu.XAFeed - spu.XAStart; + pF->xaS = *spu.xapGlobal; + } + else if (spu.CDDAPlay != spu.CDDAFeed) + { + // abuse the xa struct to store leftover cdda samples + unsigned int *p = spu.CDDAPlay; + cdda_left = spu.CDDAFeed - spu.CDDAPlay; + if (cdda_left < 0) + cdda_left = spu.CDDAEnd - spu.CDDAPlay + spu.CDDAFeed - spu.CDDAStart; + if (cdda_left > sizeof(pF->xaS.pcm) / 4) + cdda_left = sizeof(pF->xaS.pcm) / 4; + if (p + cdda_left <= spu.CDDAEnd) + memcpy(pF->xaS.pcm, p, cdda_left * 4); + else { + memcpy(pF->xaS.pcm, p, (spu.CDDAEnd - p) * 4); + memcpy((char *)pF->xaS.pcm + (spu.CDDAEnd - p) * 4, spu.CDDAStart, + (cdda_left - (spu.CDDAEnd - p)) * 4); + } + pF->xaS.nsamples = 0; } - else - memset(&pF->xaS,0,sizeof(xa_decode_t)); // or clean xa + else + memset(&pF->xaS,0,sizeof(xa_decode_t)); // or clean xa pFO=(SPUOSSFreeze_t *)(pF+1); // store special stuff @@ -263,6 +287,10 @@ long CALLBACK SPUfreeze(uint32_t ulFreezeMode, SPUFreeze_t * pF, pFO->spuAddr=spu.spuAddr; if(pFO->spuAddr==0) pFO->spuAddr=0xbaadf00d; pFO->decode_pos = spu.decode_pos; + pFO->rvb_cur = spu.rvb->CurrAddr; + pFO->xa_left = xa_left; + pFO->cdda_left = cdda_left; + pFO->cycles_played = spu.cycles_played; for(i=0;icSPUPort,0x200); spu.bMemDirty = 1; - if(pF->xaS.nsamples<=4032) // start xa again - SPUplayADPCMchannel(&pF->xaS, spu.cycles_played, 0); - - spu.xapGlobal=0; - - if(!strcmp(pF->szSPUName,"PBOSS") && pF->ulFreezeVersion==5) - LoadStateV5(pF); + if (!strcmp(pF->szSPUName,"PBOSS") && pF->ulFreezeVersion==5) + pFO = LoadStateV5(pF, cycles); else LoadStateUnknown(pF, cycles); + spu.XAPlay = spu.XAFeed = spu.XAStart; + spu.CDDAPlay = spu.CDDAFeed = spu.CDDAStart; + if (pFO && pFO->xa_left && pF->xaS.nsamples) { // start xa again + FeedXA(&pF->xaS); + spu.XAPlay = spu.XAFeed - pFO->xa_left; + if (spu.XAPlay < spu.XAStart) + spu.XAPlay = spu.XAStart; + } + else if (pFO && pFO->cdda_left) { // start cdda again + FeedCDDA((void *)pF->xaS.pcm, pFO->cdda_left * 4); + } + // repair some globals for(i=0;i<=62;i+=2) load_register(H_Reverb+i, cycles); @@ -308,7 +343,6 @@ long CALLBACK SPUfreeze(uint32_t ulFreezeMode, SPUFreeze_t * pF, for(i=0;ispuAddr & 0x7fffe; } spu.decode_pos = pFO->decode_pos & 0x1ff; + spu.rvb->CurrAddr = pFO->rvb_cur; + spu.cycles_played = pFO->cycles_played ? pFO->cycles_played : cycles; spu.dwNewChannel=0; spu.dwChannelsAudible=0; @@ -343,11 +379,12 @@ void LoadStateV5(SPUFreeze_t * pF) spu.s_chan[i].pCurr+=(uintptr_t)spu.spuMemC; spu.s_chan[i].pLoop+=(uintptr_t)spu.spuMemC; } + return pFO; } //////////////////////////////////////////////////////////////////////// -void LoadStateUnknown(SPUFreeze_t * pF, uint32_t cycles) +static void LoadStateUnknown(SPUFreeze_t * pF, uint32_t cycles) { int i; @@ -360,6 +397,7 @@ void LoadStateUnknown(SPUFreeze_t * pF, uint32_t cycles) spu.dwChannelsAudible=0; spu.dwChannelDead=0; spu.pSpuIrq=spu.spuMemC; + spu.cycles_played = cycles; for(i=0;i<0xc0;i++) { @@ -368,3 +406,4 @@ void LoadStateUnknown(SPUFreeze_t * pF, uint32_t cycles) } //////////////////////////////////////////////////////////////////////// +// vim:shiftwidth=1:expandtab diff --git a/plugins/dfsound/spu.c b/plugins/dfsound/spu.c index 283d5988..9300a16c 100644 --- a/plugins/dfsound/spu.c +++ b/plugins/dfsound/spu.c @@ -1286,7 +1286,7 @@ void schedule_next_irq(void) void CALLBACK SPUasync(unsigned int cycle, unsigned int flags) { - do_samples(cycle, spu_config.iUseFixedUpdates); + do_samples(cycle, 0); if (spu.spuCtrl & CTRL_IRQ) schedule_next_irq(); @@ -1328,6 +1328,7 @@ void CALLBACK SPUplayADPCMchannel(xa_decode_t *xap, unsigned int cycle, int is_s do_samples(cycle, 1); // catch up to prevent source underflows later FeedXA(xap); // call main XA feeder + spu.xapGlobal = xap; // store info for save states } // CDDA AUDIO @@ -1339,7 +1340,8 @@ int CALLBACK SPUplayCDDAchannel(short *pcm, int nbytes, unsigned int cycle, int if (is_start) do_samples(cycle, 1); // catch up to prevent source underflows later - return FeedCDDA((unsigned char *)pcm, nbytes); + FeedCDDA((unsigned char *)pcm, nbytes); + return 0; } // to be called after state load @@ -1361,7 +1363,7 @@ static void SetupStreams(void) spu.XAFeed = spu.XAStart; spu.CDDAStart = malloc(CDDA_BUFFER_SIZE); // alloc cdda buffer - spu.CDDAEnd = spu.CDDAStart + 16384; + spu.CDDAEnd = spu.CDDAStart + CDDA_BUFFER_SIZE / sizeof(uint32_t); spu.CDDAPlay = spu.CDDAStart; spu.CDDAFeed = spu.CDDAStart; diff --git a/plugins/dfsound/spu.h b/plugins/dfsound/spu.h index 334c6809..810ec07d 100644 --- a/plugins/dfsound/spu.h +++ b/plugins/dfsound/spu.h @@ -29,5 +29,7 @@ void ClearWorkingState(void); void CALLBACK SPUplayADPCMchannel(xa_decode_t *xap, unsigned int cycle, int is_start); int CALLBACK SPUplayCDDAchannel(short *pcm, int bytes, unsigned int cycle, int is_start); +void FeedXA(const xa_decode_t *xap); +void FeedCDDA(unsigned char *pcm, int nBytes); #endif /* __P_SPU_H__ */ diff --git a/plugins/dfsound/spu_config.h b/plugins/dfsound/spu_config.h index 95c89486..b830142e 100644 --- a/plugins/dfsound/spu_config.h +++ b/plugins/dfsound/spu_config.h @@ -11,7 +11,6 @@ typedef struct int iUseInterpolation; int iTempo; int iUseThread; - int iUseFixedUpdates; // output fixed number of samples/frame // status int iThreadAvail; diff --git a/plugins/dfsound/xa.c b/plugins/dfsound/xa.c index 23924d3b..08afc009 100644 --- a/plugins/dfsound/xa.c +++ b/plugins/dfsound/xa.c @@ -130,13 +130,12 @@ static unsigned long timeGetTime_spu() // FEED XA //////////////////////////////////////////////////////////////////////// -INLINE void FeedXA(xa_decode_t *xap) +void FeedXA(const xa_decode_t *xap) { int sinc,spos,i,iSize,iPlace,vl,vr; if(!spu.bSPUIsOpen) return; - spu.xapGlobal = xap; // store info for save states spu.XARepeat = 3; // set up repeat #if 0//def XA_HACK @@ -410,12 +409,12 @@ INLINE void FeedXA(xa_decode_t *xap) // FEED CDDA //////////////////////////////////////////////////////////////////////// -INLINE int FeedCDDA(unsigned char *pcm, int nBytes) +void FeedCDDA(unsigned char *pcm, int nBytes) { int space; space=(spu.CDDAPlay-spu.CDDAFeed-1)*4 & (CDDA_BUFFER_SIZE - 1); if(space0) { @@ -431,8 +430,6 @@ INLINE int FeedCDDA(unsigned char *pcm, int nBytes) nBytes-=space; pcm+=space; } - - return 0x676f; // rearmed_go } #endif -- 2.39.5