patch up some savestate issues
authornotaz <notasas@gmail.com>
Sun, 1 Oct 2023 21:02:39 +0000 (00:02 +0300)
committernotaz <notasas@gmail.com>
Sun, 1 Oct 2023 21:02:39 +0000 (00:02 +0300)
exposed by RetroArch's run-ahead/rewind functionality

14 files changed:
frontend/libretro.c
libpcsxcore/lightrec/plugin.c
libpcsxcore/mdec.c
libpcsxcore/misc.c
libpcsxcore/new_dynarec/events.h
libpcsxcore/psxbios.c
libpcsxcore/psxbios.h
libpcsxcore/psxcounters.c
plugins/dfsound/externals.h
plugins/dfsound/freeze.c
plugins/dfsound/spu.c
plugins/dfsound/spu.h
plugins/dfsound/spu_config.h
plugins/dfsound/xa.c

index a26d466..b8b1166 100644 (file)
@@ -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;
index 1fe04f6..d51fbc2 100644 (file)
@@ -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);
 }
index 167a1cf..612fe97 100644 (file)
@@ -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));
index d748ac0..8997c0b 100644 (file)
@@ -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:
index eeec289..5f57f37 100644 (file)
@@ -1,5 +1,7 @@
 #include "../psxcommon.h"
 
+extern int stop;
+
 union psxCP0Regs_;
 u32  schedule_timeslice(void);
 void gen_interupt(union psxCP0Regs_ *cp0);
index bad3457..73f277a 100644 (file)
@@ -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;
        }
 }
index c1368e6..c8c07ff 100644 (file)
@@ -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])();
index 9ff679e..ab8beee 100644 (file)
@@ -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();
     }
index f3fbc67..4407177 100644 (file)
@@ -218,7 +218,7 @@ typedef struct
  void (CALLBACK *cddavCallback)(short, short);\r
  void (CALLBACK *scheduleCallback)(unsigned int);\r
 \r
xa_decode_t   * xapGlobal;\r
const xa_decode_t * xapGlobal;\r
  unsigned int  * XAFeed;\r
  unsigned int  * XAPlay;\r
  unsigned int  * XAStart;\r
index 51e9fd7..d4898b4 100644 (file)
@@ -122,9 +122,10 @@ typedef struct
  unsigned short  decode_pos;\r
  uint32_t   pSpuIrq;\r
  uint32_t   spuAddr;\r
- uint32_t   dummy1;\r
- uint32_t   dummy2;\r
- uint32_t   dummy3;\r
+ uint32_t   rvb_cur;\r
+ uint16_t   xa_left;\r
+ uint16_t   cdda_left;\r
+ uint32_t   cycles_played;\r
 \r
  SPUCHAN_orig s_chan[MAXCHAN];   \r
 \r
@@ -132,8 +133,8 @@ typedef struct
 \r
 ////////////////////////////////////////////////////////////////////////\r
 \r
-void LoadStateV5(SPUFreeze_t * pF);                    // newest version\r
-void LoadStateUnknown(SPUFreeze_t * pF, uint32_t cycles); // unknown format\r
+static SPUOSSFreeze_t * LoadStateV5(SPUFreeze_t * pF, uint32_t cycles);\r
+static void LoadStateUnknown(SPUFreeze_t * pF, uint32_t cycles); // unknown format\r
 \r
 // we want to retain compatibility between versions,\r
 // so use original channel struct\r
@@ -228,14 +229,16 @@ static void load_register(unsigned long reg, unsigned int cycles)
 long CALLBACK SPUfreeze(uint32_t ulFreezeMode, SPUFreeze_t * pF,\r
  uint32_t cycles)\r
 {\r
- int i;SPUOSSFreeze_t * pFO;\r
+ SPUOSSFreeze_t * pFO = NULL;\r
+ int i;\r
 \r
  if(!pF) return 0;                                     // first check\r
 \r
- do_samples(cycles, 1);\r
-\r
  if(ulFreezeMode)                                      // info or save?\r
   {//--------------------------------------------------//\r
+   int xa_left = 0, cdda_left = 0;\r
+   do_samples(cycles, 1);\r
+\r
    if(ulFreezeMode==1)                                 \r
     memset(pF,0,sizeof(SPUFreeze_t)+sizeof(SPUOSSFreeze_t));\r
 \r
@@ -250,10 +253,31 @@ long CALLBACK SPUfreeze(uint32_t ulFreezeMode, SPUFreeze_t * pF,
 \r
    if(spu.xapGlobal && spu.XAPlay!=spu.XAFeed)         // some xa\r
     {\r
-     pF->xaS=*spu.xapGlobal;\r
+     xa_left = spu.XAFeed - spu.XAPlay;\r
+     if (xa_left < 0)\r
+      xa_left = spu.XAEnd - spu.XAPlay + spu.XAFeed - spu.XAStart;\r
+     pF->xaS = *spu.xapGlobal;\r
+    }\r
+   else if (spu.CDDAPlay != spu.CDDAFeed)\r
+    {\r
+     // abuse the xa struct to store leftover cdda samples\r
+     unsigned int *p = spu.CDDAPlay;\r
+     cdda_left = spu.CDDAFeed - spu.CDDAPlay;\r
+     if (cdda_left < 0)\r
+      cdda_left = spu.CDDAEnd - spu.CDDAPlay + spu.CDDAFeed - spu.CDDAStart;\r
+     if (cdda_left > sizeof(pF->xaS.pcm) / 4)\r
+      cdda_left = sizeof(pF->xaS.pcm) / 4;\r
+     if (p + cdda_left <= spu.CDDAEnd)\r
+      memcpy(pF->xaS.pcm, p, cdda_left * 4);\r
+     else {\r
+      memcpy(pF->xaS.pcm, p, (spu.CDDAEnd - p) * 4);\r
+      memcpy((char *)pF->xaS.pcm + (spu.CDDAEnd - p) * 4, spu.CDDAStart,\r
+             (cdda_left - (spu.CDDAEnd - p)) * 4);\r
+     }\r
+     pF->xaS.nsamples = 0;\r
     }\r
-   else \r
-   memset(&pF->xaS,0,sizeof(xa_decode_t));             // or clean xa\r
+   else\r
+    memset(&pF->xaS,0,sizeof(xa_decode_t));            // or clean xa\r
 \r
    pFO=(SPUOSSFreeze_t *)(pF+1);                       // store special stuff\r
 \r
@@ -263,6 +287,10 @@ long CALLBACK SPUfreeze(uint32_t ulFreezeMode, SPUFreeze_t * pF,
    pFO->spuAddr=spu.spuAddr;\r
    if(pFO->spuAddr==0) pFO->spuAddr=0xbaadf00d;\r
    pFO->decode_pos = spu.decode_pos;\r
+   pFO->rvb_cur = spu.rvb->CurrAddr;\r
+   pFO->xa_left = xa_left;\r
+   pFO->cdda_left = cdda_left;\r
+   pFO->cycles_played = spu.cycles_played;\r
 \r
    for(i=0;i<MAXCHAN;i++)\r
     {\r
@@ -283,15 +311,22 @@ long CALLBACK SPUfreeze(uint32_t ulFreezeMode, SPUFreeze_t * pF,
  memcpy(spu.regArea,pF->cSPUPort,0x200);\r
  spu.bMemDirty = 1;\r
 \r
- if(pF->xaS.nsamples<=4032)                            // start xa again\r
-  SPUplayADPCMchannel(&pF->xaS, spu.cycles_played, 0);\r
-\r
- spu.xapGlobal=0;\r
-\r
- if(!strcmp(pF->szSPUName,"PBOSS") && pF->ulFreezeVersion==5)\r
-   LoadStateV5(pF);\r
+ if (!strcmp(pF->szSPUName,"PBOSS") && pF->ulFreezeVersion==5)\r
+   pFO = LoadStateV5(pF, cycles);\r
  else LoadStateUnknown(pF, cycles);\r
 \r
+ spu.XAPlay = spu.XAFeed = spu.XAStart;\r
+ spu.CDDAPlay = spu.CDDAFeed = spu.CDDAStart;\r
+ if (pFO && pFO->xa_left && pF->xaS.nsamples) {        // start xa again\r
+  FeedXA(&pF->xaS);\r
+  spu.XAPlay = spu.XAFeed - pFO->xa_left;\r
+  if (spu.XAPlay < spu.XAStart)\r
+   spu.XAPlay = spu.XAStart;\r
+ }\r
+ else if (pFO && pFO->cdda_left) {                     // start cdda again\r
+  FeedCDDA((void *)pF->xaS.pcm, pFO->cdda_left * 4);\r
+ }\r
+\r
  // repair some globals\r
  for(i=0;i<=62;i+=2)\r
   load_register(H_Reverb+i, cycles);\r
@@ -308,7 +343,6 @@ long CALLBACK SPUfreeze(uint32_t ulFreezeMode, SPUFreeze_t * pF,
  for(i=0;i<MAXCHAN;i++) spu.SB[i * SB_SIZE + 28]=0;\r
 \r
  ClearWorkingState();\r
- spu.cycles_played = cycles;\r
 \r
  if (spu.spuCtrl & CTRL_IRQ)\r
   schedule_next_irq();\r
@@ -318,7 +352,7 @@ long CALLBACK SPUfreeze(uint32_t ulFreezeMode, SPUFreeze_t * pF,
 \r
 ////////////////////////////////////////////////////////////////////////\r
 \r
-void LoadStateV5(SPUFreeze_t * pF)\r
+static SPUOSSFreeze_t * LoadStateV5(SPUFreeze_t * pF, uint32_t cycles)\r
 {\r
  int i;SPUOSSFreeze_t * pFO;\r
 \r
@@ -332,6 +366,8 @@ void LoadStateV5(SPUFreeze_t * pF)
    else spu.spuAddr = pFO->spuAddr & 0x7fffe;\r
   }\r
  spu.decode_pos = pFO->decode_pos & 0x1ff;\r
+ spu.rvb->CurrAddr = pFO->rvb_cur;\r
+ spu.cycles_played = pFO->cycles_played ? pFO->cycles_played : cycles;\r
 \r
  spu.dwNewChannel=0;\r
  spu.dwChannelsAudible=0;\r
@@ -343,11 +379,12 @@ void LoadStateV5(SPUFreeze_t * pF)
    spu.s_chan[i].pCurr+=(uintptr_t)spu.spuMemC;\r
    spu.s_chan[i].pLoop+=(uintptr_t)spu.spuMemC;\r
   }\r
+ return pFO;\r
 }\r
 \r
 ////////////////////////////////////////////////////////////////////////\r
 \r
-void LoadStateUnknown(SPUFreeze_t * pF, uint32_t cycles)\r
+static void LoadStateUnknown(SPUFreeze_t * pF, uint32_t cycles)\r
 {\r
  int i;\r
 \r
@@ -360,6 +397,7 @@ void LoadStateUnknown(SPUFreeze_t * pF, uint32_t cycles)
  spu.dwChannelsAudible=0;\r
  spu.dwChannelDead=0;\r
  spu.pSpuIrq=spu.spuMemC;\r
+ spu.cycles_played = cycles;\r
 \r
  for(i=0;i<0xc0;i++)\r
   {\r
@@ -368,3 +406,4 @@ void LoadStateUnknown(SPUFreeze_t * pF, uint32_t cycles)
 }\r
 \r
 ////////////////////////////////////////////////////////////////////////\r
+// vim:shiftwidth=1:expandtab\r
index 283d598..9300a16 100644 (file)
@@ -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;
 
index 334c680..810ec07 100644 (file)
@@ -29,5 +29,7 @@
 void ClearWorkingState(void);\r
 void CALLBACK SPUplayADPCMchannel(xa_decode_t *xap, unsigned int cycle, int is_start);\r
 int  CALLBACK SPUplayCDDAchannel(short *pcm, int bytes, unsigned int cycle, int is_start);\r
+void FeedXA(const xa_decode_t *xap);\r
+void FeedCDDA(unsigned char *pcm, int nBytes);\r
 \r
 #endif /* __P_SPU_H__ */\r
index 95c8948..b830142 100644 (file)
@@ -11,7 +11,6 @@ typedef struct
  int        iUseInterpolation;
  int        iTempo;
  int        iUseThread;
- int        iUseFixedUpdates;  // output fixed number of samples/frame
 
  // status
  int        iThreadAvail;
index 23924d3..08afc00 100644 (file)
@@ -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(space<nBytes)
-  return 0x7761; // rearmed_wait
+  return;
 
  while(nBytes>0)
   {
@@ -431,8 +430,6 @@ INLINE int FeedCDDA(unsigned char *pcm, int nBytes)
    nBytes-=space;
    pcm+=space;
   }
-
- return 0x676f; // rearmed_go
 }
 
 #endif