commit 937cfec4796bb566c42ca88b4b3bbe6bf0e66b3c
parent 4ff7f306532f62cfc61ae786587cc44bab59edae
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date: Thu, 25 Jul 2024 21:55:01 +0200
new synchronization attempt WIP
Diffstat:
7 files changed, 216 insertions(+), 0 deletions(-)
diff --git a/source/hardwareLib/CMakeLists.txt b/source/hardwareLib/CMakeLists.txt
@@ -5,9 +5,11 @@ add_library(hardwareLib STATIC)
set(SOURCES
am29f.cpp am29f.h
+ haltDSP.cpp haltDSP.h
i2c.cpp i2c.h
i2cFlash.cpp i2cFlash.h
sciMidi.cpp sciMidi.h
+ syncUCtoDSP.h
)
target_sources(hardwareLib PRIVATE ${SOURCES})
diff --git a/source/hardwareLib/haltDSP.cpp b/source/hardwareLib/haltDSP.cpp
@@ -0,0 +1,34 @@
+#include "haltDSP.h"
+
+#include "dsp56kEmu/dsp.h"
+
+namespace hwLib
+{
+ HaltDSP::HaltDSP(dsp56k::DSP& _dsp)
+ : m_dsp(_dsp)
+ , m_irq(_dsp.registerInterruptFunc([this] { onInterrupt(); }))
+ {
+ }
+
+ void HaltDSP::haltDSP()
+ {
+ if(m_halted)
+ return;
+ if(++m_halted == 1)
+ m_dsp.injectExternalInterrupt(m_irq);
+ }
+
+ bool HaltDSP::resumeDSP()
+ {
+ if(!m_halted)
+ return false;
+ if(--m_halted == 0)
+ m_semaphore.notify();
+ return true;
+ }
+
+ void HaltDSP::onInterrupt()
+ {
+ m_semaphore.wait();
+ }
+}
diff --git a/source/hardwareLib/haltDSP.h b/source/hardwareLib/haltDSP.h
@@ -0,0 +1,64 @@
+#pragma once
+
+#include <cstdint>
+
+#include "baseLib/semaphore.h"
+
+namespace dsp56k
+{
+ class DSP;
+}
+
+namespace hwLib
+{
+ class HaltDSP
+ {
+ public:
+ explicit HaltDSP(dsp56k::DSP& _dsp);
+
+ void haltDSP();
+ bool resumeDSP();
+
+ private:
+ void onInterrupt();
+
+ dsp56k::DSP& m_dsp;
+
+ uint32_t m_halted = 0;
+ uint32_t m_irq;
+ baseLib::Semaphore m_semaphore;
+ };
+
+ class ScopedResumeDSP
+ {
+ public:
+ explicit ScopedResumeDSP(HaltDSP& _haltDSP) : m_haltDSP(_haltDSP), m_resumed(_haltDSP.resumeDSP())
+ {
+ }
+
+ ~ScopedResumeDSP()
+ {
+ if(m_resumed)
+ m_haltDSP.haltDSP();
+ }
+ private:
+ HaltDSP& m_haltDSP;
+ bool m_resumed;
+ };
+
+ class ScopedHaltDSP
+ {
+ public:
+ explicit ScopedHaltDSP(HaltDSP& _haltDSP) : m_haltDSP(_haltDSP)
+ {
+ _haltDSP.haltDSP();
+ }
+
+ ~ScopedHaltDSP()
+ {
+ m_haltDSP.resumeDSP();
+ }
+ private:
+ HaltDSP& m_haltDSP;
+ };
+}
diff --git a/source/hardwareLib/syncUCtoDSP.h b/source/hardwareLib/syncUCtoDSP.h
@@ -0,0 +1,99 @@
+#pragma once
+
+#include <cstdint>
+
+#include "haltDSP.h"
+
+namespace hwLib
+{
+ template<uint32_t UcFreqHz, uint32_t Samplerate, uint32_t SamplesThreshold>
+ class SyncUCtoDSP
+ {
+ public:
+ static constexpr double SamplerateInv = 1.0 / static_cast<double>(Samplerate);
+ static constexpr double UcCyclesPerSample = static_cast<double>(UcFreqHz) / Samplerate;
+ static constexpr double UcCyclesThreshold = UcCyclesPerSample * SamplesThreshold;
+
+ explicit SyncUCtoDSP(dsp56k::DSP& _dsp) : m_haltDSP(_dsp)
+ {
+ }
+
+ virtual ~SyncUCtoDSP() = default;
+
+ void advanceDspSample()
+ {
+ m_targetUcCycles += UcCyclesPerSample;
+ ++m_totalSampleCount;
+
+ if((m_totalSampleCount & (SamplesThreshold-1)) == 0)
+ m_cvSampleAdded.notify_one();
+ }
+
+ void advanceUcCycles(const uint32_t _cycles)
+ {
+ m_totalUcCycles += static_cast<double>(_cycles);
+
+ evaluate();
+ }
+
+ auto& getHaltDSP() { return m_haltDSP; }
+
+ protected:
+ void evaluate()
+ {
+ if(!m_totalSampleCount)
+ return;
+
+ const auto diff = m_totalUcCycles - m_targetUcCycles;
+
+ if(diff > UcCyclesThreshold)
+ {
+ // UC is too fast, slow down
+ resumeDSP();
+ haltUC();
+ }
+ else if(diff < -UcCyclesThreshold)
+ {
+ haltDSP();
+ resumeUC();
+ }
+ else
+ {
+ resumeDSP();
+ resumeUC();
+ }
+ }
+
+ void haltUC()
+ {
+ const auto lastCount = m_totalSampleCount;
+ std::unique_lock lock(m_lockSampleAdded);
+ m_cvSampleAdded.wait(lock, [&]
+ {
+ return m_totalSampleCount > lastCount;
+ });
+ }
+
+ virtual void resumeUC()
+ {
+ }
+
+ void haltDSP()
+ {
+ m_haltDSP.haltDSP();
+ }
+
+ void resumeDSP()
+ {
+ m_haltDSP.resumeDSP();
+ }
+
+ private:
+ HaltDSP m_haltDSP;
+ double m_targetUcCycles = 0.0;
+ double m_totalUcCycles = 0.0;
+ uint32_t m_totalSampleCount = 0;
+ std::condition_variable m_cvSampleAdded;
+ std::mutex m_lockSampleAdded;
+ };
+}
diff --git a/source/nord/n2x/n2xLib/n2xsync.cpp b/source/nord/n2x/n2xLib/n2xsync.cpp
diff --git a/source/nord/n2x/n2xLib/n2xsync.h b/source/nord/n2x/n2xLib/n2xsync.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "n2xtypes.h"
+
+#include "hardwareLib/syncUCtoDSP.h"
+
+namespace n2x
+{
+ class Sync : public hwLib::SyncUCtoDSP<g_ucFreqHz, g_samplerate, 16>
+ {
+ public:
+ Sync(dsp56k::DSP& _dsp) : SyncUCtoDSP(_dsp)
+ {
+ }
+ };
+}
diff --git a/source/nord/n2x/n2xLib/n2xtypes.h b/source/nord/n2x/n2xLib/n2xtypes.h
@@ -40,6 +40,7 @@ namespace n2x
static constexpr uint32_t g_keyboardSize = 0x800;
static constexpr uint32_t g_samplerate = 98200;
+ static constexpr uint32_t g_ucFreqHz = 25165824; // Fext=32768Hz, SYNCR=$d700, W=1, X=1, Y=17
enum class ButtonType
{