gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

commit 4b51e97a5b4dad1b5692fea66fdea72369d28bf7
parent d086bfd5b25d9697734e7a923817f78e4fa29c99
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date:   Sun, 11 Aug 2024 03:44:02 +0200

rework sync code for more accurate UC timing on slower CPUs

Diffstat:
Msource/hardwareLib/haltDSP.cpp | 4++++
Msource/hardwareLib/haltDSP.h | 5++++-
Msource/nord/n2x/n2xLib/n2xdsp.cpp | 19+++++++++++++++++++
Msource/nord/n2x/n2xLib/n2xhardware.cpp | 4++++
Msource/nord/n2x/n2xLib/n2xhardware.h | 1+
5 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/source/hardwareLib/haltDSP.cpp b/source/hardwareLib/haltDSP.cpp @@ -65,6 +65,8 @@ namespace hwLib } m_cvHalted.notify_one(); + m_halting = true; + // halt and wait for resume or a wakeup call m_blockSem.wait(); @@ -88,5 +90,7 @@ namespace hwLib func(); m_blockSem.wait(); } + + m_halting = false; } } diff --git a/source/hardwareLib/haltDSP.h b/source/hardwareLib/haltDSP.h @@ -21,7 +21,8 @@ namespace hwLib void haltDSP(bool _wait = false); bool resumeDSP(); - bool halted() const {return m_halted > 0; } + // only returns true if the last halt request has been serviced + bool isHalting() const { return m_halting && m_irqRequestCount == m_irqServedCount; } dsp56k::DSP& getDSP() const { return m_dsp; } @@ -46,6 +47,8 @@ namespace hwLib uint32_t m_wakeUpCount = 0; std::unordered_map<uint32_t, std::function<void()>> m_wakeUps; + + bool m_halting = false; }; class ScopedResumeDSP diff --git a/source/nord/n2x/n2xLib/n2xdsp.cpp b/source/nord/n2x/n2xLib/n2xdsp.cpp @@ -150,6 +150,7 @@ namespace n2x { if(_needMoreData) { + hwLib::ScopedResumeDSP rA(m_hardware.getDSPA().getHaltDSP()); hwLib::ScopedResumeDSP rB(m_hardware.getDSPB().getHaltDSP()); while(dsp().hasPendingInterrupts()) @@ -166,10 +167,28 @@ namespace n2x void DSP::hdiSendIrqToDSP(const uint8_t _irq) { + if(m_hardware.requestingHaltDSPs() && getHaltDSP().isHalting()) + { + // this is a very hacky way to execute a DSP interrupt even though the DSP is halted. This case happens if the DSPs run too fast + // and are halted by the sync code, but the UC wants to inject an interrupt, which needs to be executed immediately. + // In this case, we execute the interrupt without altering the DSP state + + const auto numOps = dsp().getInstructionCounter(); + const auto numCycles = dsp().getCycles(); + + const auto pc = dsp().getPC(); + dsp().getJit().exec(_irq); + dsp().setPC(pc); + + const_cast<uint32_t&>(dsp().getInstructionCounter()) = numOps; + const_cast<uint32_t&>(dsp().getCycles()) = numCycles; + } + else { dsp().injectExternalInterrupt(_irq); dsp().injectExternalInterrupt(m_irqInterruptDone); + hwLib::ScopedResumeDSP rA(m_hardware.getDSPA().getHaltDSP()); hwLib::ScopedResumeDSP rB(m_hardware.getDSPB().getHaltDSP()); m_triggerInterruptDone.wait(); } diff --git a/source/nord/n2x/n2xLib/n2xhardware.cpp b/source/nord/n2x/n2xLib/n2xhardware.cpp @@ -319,6 +319,8 @@ namespace n2x if(m_dspHalted) return; m_dspHalted = true; +// LOG("Halt"); + m_dspA.getHaltDSP().haltDSP(); m_dspB.getHaltDSP().haltDSP(); } @@ -327,6 +329,8 @@ namespace n2x if(!m_dspHalted) return; m_dspHalted = false; +// LOG("Resume"); + m_dspA.getHaltDSP().resumeDSP(); m_dspB.getHaltDSP().resumeDSP(); } diff --git a/source/nord/n2x/n2xLib/n2xhardware.h b/source/nord/n2x/n2xLib/n2xhardware.h @@ -33,6 +33,7 @@ namespace n2x void haltDSPs(); void resumeDSPs(); + bool requestingHaltDSPs() const { return m_dspHalted; } bool getButtonState(ButtonType _type) const; void setButtonState(ButtonType _type, bool _pressed);