commit 18c39a62ddf423a184b81e085a6a2f4f4d23a292
parent 937cfec4796bb566c42ca88b4b3bbe6bf0e66b3c
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date: Fri, 26 Jul 2024 23:29:09 +0200
syncronization work
Diffstat:
6 files changed, 139 insertions(+), 70 deletions(-)
diff --git a/source/hardwareLib/haltDSP.cpp b/source/hardwareLib/haltDSP.cpp
@@ -10,12 +10,26 @@ namespace hwLib
{
}
- void HaltDSP::haltDSP()
+ void HaltDSP::haltDSP(const bool _wait)
{
- if(m_halted)
- return;
if(++m_halted == 1)
+ {
+ ++m_irqRequestCount;
+
m_dsp.injectExternalInterrupt(m_irq);
+
+ if(_wait)
+ {
+ const auto expectedCount = m_irqRequestCount;
+ std::unique_lock lock(m_mutex);
+ m_cvHalted.wait(lock, [this, expectedCount]
+ {
+ if(expectedCount != m_irqServedCount)
+ return false;
+ return true;
+ });
+ }
+ }
}
bool HaltDSP::resumeDSP()
@@ -23,12 +37,56 @@ namespace hwLib
if(!m_halted)
return false;
if(--m_halted == 0)
- m_semaphore.notify();
+ m_blockSem.notify();
return true;
}
+ void HaltDSP::wakeUp(std::function<void()>&& _func)
+ {
+ if(!m_halted)
+ {
+ _func();
+ return;
+ }
+
+ {
+ std::unique_lock lock(m_mutex);
+ m_wakeUps.emplace(m_wakeUpId++, std::move(_func));
+ }
+ m_blockSem.notify();
+ }
+
void HaltDSP::onInterrupt()
{
- m_semaphore.wait();
+ // signal waiter that we reached halt state
+ {
+ std::unique_lock lock(m_mutex);
+ ++m_irqServedCount;
+ }
+ m_cvHalted.notify_one();
+
+ // halt and wait for resume or a wakeup call
+ m_blockSem.wait();
+
+ while(true)
+ {
+ std::function<void()> func;
+
+ // check if wakeup call
+ {
+ std::unique_lock lock(m_mutex);
+ const auto it = m_wakeUps.find(m_wakeUpCount);
+ if(it == m_wakeUps.end())
+ break;
+
+ func = std::move(it->second);
+ m_wakeUps.erase(it);
+ ++m_wakeUpCount;
+ }
+
+ // execute wakeup and go back to halt state
+ func();
+ m_blockSem.wait();
+ }
}
}
diff --git a/source/hardwareLib/haltDSP.h b/source/hardwareLib/haltDSP.h
@@ -1,6 +1,8 @@
#pragma once
#include <cstdint>
+#include <functional>
+#include <unordered_map>
#include "baseLib/semaphore.h"
@@ -16,9 +18,15 @@ namespace hwLib
public:
explicit HaltDSP(dsp56k::DSP& _dsp);
- void haltDSP();
+ void haltDSP(bool _wait = false);
bool resumeDSP();
+ bool halted() const {return m_halted > 0; }
+
+ dsp56k::DSP& getDSP() const { return m_dsp; }
+
+ void wakeUp(std::function<void()>&& _func);
+
private:
void onInterrupt();
@@ -26,7 +34,18 @@ namespace hwLib
uint32_t m_halted = 0;
uint32_t m_irq;
- baseLib::Semaphore m_semaphore;
+ baseLib::Semaphore m_blockSem;
+
+ std::mutex m_mutex;
+ std::condition_variable m_cvHalted;
+
+ uint32_t m_irqServedCount = 0;
+ uint32_t m_irqRequestCount = 0;
+
+ uint32_t m_wakeUpId = 0;
+ uint32_t m_wakeUpCount = 0;
+
+ std::unordered_map<uint32_t, std::function<void()>> m_wakeUps;
};
class ScopedResumeDSP
diff --git a/source/nord/n2x/n2xLib/n2xdsp.cpp b/source/nord/n2x/n2xLib/n2xdsp.cpp
@@ -64,6 +64,7 @@ namespace n2x
, m_name(_index ? "DSP B" : "DSP A")
, m_memory(g_memValidator, g_pMemSize, g_xyMemSize, g_externalMemAddr)
, m_dsp(m_memory, &m_periphX, &m_periphNop)
+ , m_haltDSP(m_dsp)
{
if(!_hw.isValid())
return;
@@ -177,7 +178,7 @@ namespace n2x
m_thread->setLogToStdout(false);
- m_vbaInterruptDone = dsp().registerInterruptFunc([this]
+ m_irqInterruptDone = dsp().registerInterruptFunc([this]
{
m_triggerInterruptDone.notify();
});
@@ -215,14 +216,33 @@ namespace n2x
void DSP::hdiSendIrqToDSP(const uint8_t _irq)
{
-// waitDspRxEmpty();
- dsp().injectExternalInterrupt(_irq);
-
- dsp().injectExternalInterrupt(m_vbaInterruptDone);
- m_hardware.resumeDSPsForFunc([&]
+ // If applicable, we wait for the halt on our DSP after resuming it
+ /*if(m_haltDSP.halted())
{
+ bool done = false;
+ std::mutex mutex;
+ std::condition_variable wait;
+ m_haltDSP.wakeUp([this, _irq, &mutex, &done, &wait]
+ {
+ dsp().execInterrupt(_irq);
+ {
+ std::unique_lock lock(mutex);
+ done = true;
+ }
+ wait.notify_one();
+ });
+ std::unique_lock lock(mutex);
+ wait.wait(lock, [&done]{return done;});
+ assert(done);
+ }
+ else*/
+ {
+ dsp().injectExternalInterrupt(_irq);
+ dsp().injectExternalInterrupt(m_irqInterruptDone);
+
+ hwLib::ScopedResumeDSP r(m_hardware.getDSPB().getHaltDSP());
m_triggerInterruptDone.wait();
- });
+ }
hdiTransferDSPtoUC();
}
@@ -265,14 +285,4 @@ namespace n2x
}
return false;
}
-
- void DSP::waitDspRxEmpty()
- {
- m_hardware.ucYieldLoop([&]()
- {
- return (hdi08().hasRXData() && hdi08().rxInterruptEnabled()) || dsp().hasPendingInterrupts();
- });
-// assert(!hdi08().hasRXData());
-// LOG("writeRX wait over");
- }
}
diff --git a/source/nord/n2x/n2xLib/n2xdsp.h b/source/nord/n2x/n2xLib/n2xdsp.h
@@ -7,6 +7,7 @@
#include "dsp56kEmu/dspthread.h"
#include "baseLib/semaphore.h"
+#include "hardwareLib/haltDSP.h"
namespace mc68k
{
@@ -44,7 +45,8 @@ namespace n2x
void advanceSamples(uint32_t _samples, uint32_t _latency);
- dsp56k::DSPThread& getDSPThread() const { return *m_thread.get(); }
+ dsp56k::DSPThread& getDSPThread() const { return *m_thread; }
+ auto& getHaltDSP() { return m_haltDSP; }
private:
void onUCRxEmpty(bool _needMoreData);
@@ -53,7 +55,6 @@ namespace n2x
uint8_t hdiUcReadIsr(uint8_t _isr);
void onEsaiCallback();
bool hdiTransferDSPtoUC();
- void waitDspRxEmpty();
Hardware& m_hardware;
mc68k::Hdi08& m_hdiUC;
@@ -81,6 +82,8 @@ namespace n2x
std::mutex m_haltDSPmutex;
baseLib::Semaphore m_triggerInterruptDone;
- uint32_t m_vbaInterruptDone = 0;
+ uint32_t m_irqInterruptDone = 0;
+
+ hwLib::HaltDSP m_haltDSP;
};
}
diff --git a/source/nord/n2x/n2xLib/n2xhardware.cpp b/source/nord/n2x/n2xLib/n2xhardware.cpp
@@ -40,9 +40,8 @@ namespace n2x
void Hardware::ucYieldLoop(const std::function<bool()>& _continue)
{
- const auto dspHalted = m_haltDSP;
-
- resumeDSP();
+ hwLib::ScopedResumeDSP rA(m_dspA.getHaltDSP());
+ hwLib::ScopedResumeDSP rB(m_dspB.getHaltDSP());
while(_continue())
{
@@ -60,9 +59,6 @@ namespace n2x
}
*/
}
-
- if(dspHalted)
- haltDSP();
}
void Hardware::processAudio(uint32_t _frames, const uint32_t _latency)
@@ -192,9 +188,6 @@ namespace n2x
{
m_requestedFramesAvailableMutex.unlock();
}
-
- std::unique_lock uLock(m_haltDSPmutex);
- m_haltDSPcv.wait(uLock, [&]{ return m_haltDSP == false; });
}
void Hardware::syncUCtoDSP()
@@ -208,7 +201,8 @@ namespace n2x
if(m_esaiFrameIndex == m_lastEsaiFrameIndex)
{
- resumeDSP();
+ m_dspHalted = false;
+ resumeDSPs();
std::unique_lock uLock(m_esaiFrameAddedMutex);
m_esaiFrameAddedCv.wait(uLock, [this]{return m_esaiFrameIndex > m_lastEsaiFrameIndex;});
}
@@ -233,34 +227,30 @@ namespace n2x
if(esaiDelta > g_syncHaltDspEsaiThreshold)
{
- haltDSP();
+ if(!m_dspHalted)
+ {
+ m_dspHalted = true;
+ haltDSPs();
+ }
}
- else
+ else if(m_dspHalted)
{
- resumeDSP();
+ m_dspHalted = false;
+ resumeDSPs();
}
m_lastEsaiFrameIndex = esaiFrameIndex;
}
- void Hardware::haltDSP()
+ void Hardware::haltDSPs()
{
- if(m_haltDSP)
- return;
-
- std::lock_guard uLockHalt(m_haltDSPmutex);
- m_haltDSP = true;
+// m_dspA.getHaltDSP().haltDSP();
+ m_dspB.getHaltDSP().haltDSP();
}
- void Hardware::resumeDSP()
+ void Hardware::resumeDSPs()
{
- if(!m_haltDSP)
- return;
-
- {
- std::lock_guard uLockHalt(m_haltDSPmutex);
- m_haltDSP = false;
- }
- m_haltDSPcv.notify_one();
+// m_dspA.getHaltDSP().resumeDSP();
+ m_dspB.getHaltDSP().resumeDSP();
}
}
diff --git a/source/nord/n2x/n2xLib/n2xhardware.h b/source/nord/n2x/n2xLib/n2xhardware.h
@@ -23,25 +23,16 @@ namespace n2x
void processAudio(uint32_t _frames, uint32_t _latency);
- void resumeDSPsForFunc(const std::function<void()>& _callback)
- {
- const auto halted = m_haltDSP;
- if(halted)
- resumeDSP();
- _callback();
- if(halted)
- haltDSP();
- }
-
auto& getDSPA() { return m_dspA; }
auto& getDSPB() { return m_dspB; }
+ void haltDSPs();
+ void resumeDSPs();
+
private:
void ensureBufferSize(uint32_t _frames);
void onEsaiCallback();
void syncUCtoDSP();
- void haltDSP();
- void resumeDSP();
Rom m_rom;
Microcontroller m_uc;
@@ -65,8 +56,6 @@ namespace n2x
std::mutex m_requestedFramesAvailableMutex;
std::condition_variable m_requestedFramesAvailableCv;
size_t m_requestedFrames = 0;
- bool m_haltDSP = false;
- std::condition_variable m_haltDSPcv;
- std::mutex m_haltDSPmutex;
+ bool m_dspHalted = false;
};
}