diff --git a/SIDFactoryII/drivers/sf2driver11_05.prg b/SIDFactoryII/drivers/sf2driver11_05.prg index b50a9eb6..2d36d772 100644 Binary files a/SIDFactoryII/drivers/sf2driver11_05.prg and b/SIDFactoryII/drivers/sf2driver11_05.prg differ diff --git a/SIDFactoryII/source/runtime/editor/driver/driver_info.cpp b/SIDFactoryII/source/runtime/editor/driver/driver_info.cpp index f5f8bb78..bf59be90 100644 --- a/SIDFactoryII/source/runtime/editor/driver/driver_info.cpp +++ b/SIDFactoryII/source/runtime/editor/driver/driver_info.cpp @@ -339,8 +339,8 @@ namespace Editor m_DriverCommon.m_TempoCounterAddress = inReader.ReadWord(); m_DriverCommon.m_TriggerSyncAddress = inReader.ReadWord(); m_DriverCommon.m_NoteEventTriggerSyncValue = inReader.ReadByte(); - m_DriverCommon.m_ReservedByte = inReader.ReadByte(); - m_DriverCommon.m_ReservedWord = inReader.ReadWord(); + m_DriverCommon.m_UpdatesPerFrameAddress = inReader.ReadWord(); + m_DriverCommon.m_MaxUpdatesPerFrame = inReader.ReadByte(); } diff --git a/SIDFactoryII/source/runtime/editor/driver/driver_info.h b/SIDFactoryII/source/runtime/editor/driver/driver_info.h index cc8f93e9..6123bc4a 100644 --- a/SIDFactoryII/source/runtime/editor/driver/driver_info.h +++ b/SIDFactoryII/source/runtime/editor/driver/driver_info.h @@ -89,8 +89,8 @@ namespace Editor unsigned short m_TempoCounterAddress; unsigned short m_TriggerSyncAddress; unsigned char m_NoteEventTriggerSyncValue; - unsigned char m_ReservedByte; - unsigned short m_ReservedWord; + unsigned short m_UpdatesPerFrameAddress; + unsigned char m_MaxUpdatesPerFrame; }; diff --git a/SIDFactoryII/source/runtime/editor/screens/screen_edit.cpp b/SIDFactoryII/source/runtime/editor/screens/screen_edit.cpp index 19f4f79c..86856ffd 100644 --- a/SIDFactoryII/source/runtime/editor/screens/screen_edit.cpp +++ b/SIDFactoryII/source/runtime/editor/screens/screen_edit.cpp @@ -390,6 +390,24 @@ namespace Editor if (m_EditState.IsFollowPlayMode() && m_PlaybackCurrentEventPos >= 0) m_TracksComponent->SetEventPosition(m_PlaybackCurrentEventPos, true); } + + // Constantly refresh update per frame + unsigned char update_per_frame = [&]() + { + unsigned short updates_per_frame_vector = m_DriverInfo->GetDriverCommon().m_UpdatesPerFrameAddress; + if (updates_per_frame_vector != 0) + { + m_CPUMemory->Lock(); + unsigned char value = m_CPUMemory->GetByte(updates_per_frame_vector) + 1; + m_CPUMemory->Unlock(); + + return value; + } + + return (unsigned char)(0); + }(); + + m_ExecutionHandler->SetUpdatesPerFrame(update_per_frame < 1 ? 1 : update_per_frame); } diff --git a/SIDFactoryII/source/runtime/emulation/cpuframecapture.cpp b/SIDFactoryII/source/runtime/emulation/cpuframecapture.cpp index 3da99075..79e203eb 100644 --- a/SIDFactoryII/source/runtime/emulation/cpuframecapture.cpp +++ b/SIDFactoryII/source/runtime/emulation/cpuframecapture.cpp @@ -30,16 +30,36 @@ namespace Emulation void CPUFrameCapture::Capture(unsigned short inStartAddress, unsigned char inAccumulatorValue) { - // Set program counter - m_CPU->SetPC(inStartAddress); - m_CPU->SetAccumulator(inAccumulatorValue); + Capture(inStartAddress, inAccumulatorValue, 1); + } + + void CPUFrameCapture::Capture(unsigned short inStartAddress, unsigned char inAccumulatorValue, int inEventlySpreadRepetitions) + { + FOUNDATION_ASSERT(inEventlySpreadRepetitions > 0); - // Set the CPU to be not suspended - m_CPU->SetSuspended(false); + const int cyclesPerRepetition = m_uiMaxCycles / inEventlySpreadRepetitions; // Execute instructions until suspending! - while (!m_CPU->IsSuspended() && static_cast(m_CPU->CycleCounterGetCurrent()) < m_uiMaxCycles) - m_CPU->ExecuteInstruction(); + for(int i=0; i< inEventlySpreadRepetitions; ++i) + { + // Set program counter + m_CPU->SetPC(inStartAddress); + m_CPU->SetAccumulator(inAccumulatorValue); + + // Set the CPU to be not suspended + m_CPU->SetSuspended(false); + + if(i > 0) + { + const int startCycle = cyclesPerRepetition * i; + FOUNDATION_ASSERT(m_CPU->CycleCounterGetCurrent() <= startCycle); + + m_CPU->CycleCounterSetCurrent(startCycle); + } + + while (!m_CPU->IsSuspended() && static_cast(m_CPU->CycleCounterGetCurrent()) < m_uiMaxCycles) + m_CPU->ExecuteInstruction(); + } // Record the number of cycles spend on the executing code before the CPU was suspended! m_uiCyclesSpend = static_cast(m_CPU->CycleCounterGetCurrent()); @@ -48,6 +68,7 @@ namespace Emulation m_ReachedMaxCycleCount = m_uiCyclesSpend >= m_uiMaxCycles; } + void CPUFrameCapture::Write(unsigned short usAddress, unsigned char ucVal, int iCycle) { if (usAddress >= m_usCaptureRangeBegin && usAddress <= m_usCaptureRangeEnd) diff --git a/SIDFactoryII/source/runtime/emulation/cpuframecapture.h b/SIDFactoryII/source/runtime/emulation/cpuframecapture.h index d2f8ce50..2485ae18 100644 --- a/SIDFactoryII/source/runtime/emulation/cpuframecapture.h +++ b/SIDFactoryII/source/runtime/emulation/cpuframecapture.h @@ -38,6 +38,7 @@ namespace Emulation ~CPUFrameCapture(); void Capture(unsigned short inStartAddress, unsigned char inAccumulatorValue); + void Capture(unsigned short inStartAddress, unsigned char inAccumulatorValue, int inEventlySpreadRepetitions); virtual void Write(unsigned short usAddress, unsigned char ucVal, int iCycle); diff --git a/SIDFactoryII/source/runtime/execution/executionhandler.cpp b/SIDFactoryII/source/runtime/execution/executionhandler.cpp index a28c2957..b3ae0f7c 100644 --- a/SIDFactoryII/source/runtime/execution/executionhandler.cpp +++ b/SIDFactoryII/source/runtime/execution/executionhandler.cpp @@ -44,6 +44,7 @@ namespace Emulation , m_SampleBufferReadCursor(0) , m_SampleBufferWriteCursor(0) , m_CPUFrameCounter(0) + , m_UpdatesPerFrame(1) , m_UpdateEnabled(false) , m_ErrorState(false) { @@ -316,6 +317,14 @@ namespace Emulation Unlock(); } + void ExecutionHandler::SetUpdatesPerFrame(unsigned char inUpdatesPerFrame) + { + Lock(); + m_UpdatesPerFrame = inUpdatesPerFrame; + Unlock(); + } + + void ExecutionHandler::StartWriteOutputToFile(const std::string& inFilename) { FOUNDATION_ASSERT(m_SIDProxy != nullptr); @@ -429,7 +438,7 @@ namespace Emulation break; case ActionType::Update: if (!m_ErrorState) - frameCapture.Capture(GetAddressFromActionType(action.m_ActionType), action.m_ActionArgument); + frameCapture.Capture(GetAddressFromActionType(action.m_ActionType), action.m_ActionArgument, static_cast(m_UpdatesPerFrame)); default: break; } @@ -447,7 +456,7 @@ namespace Emulation if (!error) { - frameCapture.Capture(GetAddressFromActionType(ActionType::Update), 0); + frameCapture.Capture(GetAddressFromActionType(ActionType::Update), 0, static_cast(m_UpdatesPerFrame)); error = frameCapture.IsMaxCycleCountReached(); if (m_PostUpdateCallback) @@ -462,7 +471,7 @@ namespace Emulation if (m_CyclesPerFrame - frameCapture.GetCyclesSpend() < m_CyclesPerFrame >> 2) break; - frameCapture.Capture(GetAddressFromActionType(ActionType::Update), 0); + frameCapture.Capture(GetAddressFromActionType(ActionType::Update), 0, static_cast(m_UpdatesPerFrame)); if (m_PostUpdateCallback) m_PostUpdateCallback(m_Memory); diff --git a/SIDFactoryII/source/runtime/execution/executionhandler.h b/SIDFactoryII/source/runtime/execution/executionhandler.h index bcf26e78..6e869a47 100644 --- a/SIDFactoryII/source/runtime/execution/executionhandler.h +++ b/SIDFactoryII/source/runtime/execution/executionhandler.h @@ -79,6 +79,7 @@ namespace Emulation void SetStopVector(unsigned short inVector); void SetUpdateVector(unsigned short inVector); void SetPostUpdateCallback(const std::function& inPostUpdateCallback); + void SetUpdatesPerFrame(unsigned char inUpdatesPerFrame); // Cycles unsigned int GetCPUCyclesSpendLastFrame() const { return m_CPUCyclesSpend; } @@ -147,6 +148,7 @@ namespace Emulation bool m_UpdateEnabled; unsigned int m_FastForwardUpdateCount; std::function m_PostUpdateCallback; + unsigned char m_UpdatesPerFrame; // Driver vectors unsigned short m_InitVector;