From c6dfcd1900725a366c9e646c5698a28326061b1c Mon Sep 17 00:00:00 2001 From: Sour Date: Sat, 29 Feb 2020 11:34:23 -0500 Subject: [PATCH] States: Prevent lockup when loading older save states taken when SPC sample rate was set to 32khz --- Core/Spc.cpp | 21 ++++++++++++++++++--- Core/Spc.h | 2 ++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Core/Spc.cpp b/Core/Spc.cpp index fd08764..bc5da1c 100644 --- a/Core/Spc.cpp +++ b/Core/Spc.cpp @@ -48,7 +48,7 @@ Spc::Spc(Console* console) _operandB = 0; _enabled = true; - _clockRatio = (double)(Spc::SpcSampleRate * 64) / _console->GetMasterClockRate(); + UpdateClockRatio(); } #ifndef DUMMYSPC @@ -96,7 +96,7 @@ void Spc::SetSpcState(bool enabled) if(_enabled != enabled) { if(enabled) { //When re-enabling, adjust the cycle counter to prevent running extra cycles - _state.Cycle = (uint64_t)(_memoryManager->GetMasterClock() * _clockRatio); + UpdateClockRatio(); } else { //Catch up SPC before disabling it Run(); @@ -105,6 +105,19 @@ void Spc::SetSpcState(bool enabled) } } +void Spc::UpdateClockRatio() +{ + _clockRatio = (double)(Spc::SpcSampleRate * 64) / _console->GetMasterClockRate(); + + //If the target cycle is off by more than 10 cycles, reset the counter to match what was expected + //This can happen due to overclocking (which disables the SPC for some scanlines) or if the SPC's + //internal sample rate is changed between versions (e.g 32000hz -> 32040hz) + uint64_t targetCycle = (uint64_t)(_memoryManager->GetMasterClock() * _clockRatio); + if(std::abs((int64_t)targetCycle - (int64_t)_state.Cycle) > 10) { + _state.Cycle = targetCycle; + } +} + void Spc::Idle() { IncCycleCount(-1); @@ -359,7 +372,7 @@ void Spc::ProcessEndFrame() { Run(); - _clockRatio = (double)(Spc::SpcSampleRate * 64) / _console->GetMasterClockRate(); + UpdateClockRatio(); int sampleCount = _dsp->sample_count(); if(sampleCount != 0) { @@ -446,6 +459,8 @@ void Spc::Serialize(Serializer &s) } else { s.StreamArray(dspState, SPC_DSP::state_size); + UpdateClockRatio(); + uint8_t *in = dspState; _dsp->copy_state(&in, [](uint8_t** input, void* output, size_t size) { memcpy(output, *input, size); diff --git a/Core/Spc.h b/Core/Spc.h index 8dff29e..8d65bcd 100644 --- a/Core/Spc.h +++ b/Core/Spc.h @@ -280,6 +280,8 @@ private: void EndAddr(); void ProcessCycle(); void Exec(); + + void UpdateClockRatio(); public: Spc(Console* console);