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 9442722906683f6e800dfbaa8016c216c7717f57
parent 0c51c32af1525a0a1ca975240c9999d946fd9cb0
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date:   Thu, 18 Jul 2024 18:59:10 +0200

continuing attempts to boot n2x

Diffstat:
Msource/nord/n2x/n2xLib/n2xdsp.cpp | 87++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Msource/nord/n2x/n2xLib/n2xdsp.h | 5+++++
Msource/nord/n2x/n2xLib/n2xhardware.cpp | 8++++++++
Msource/nord/n2x/n2xLib/n2xhardware.h | 3+++
Msource/nord/n2x/n2xLib/n2xmc.cpp | 44+++++++++++++++++++++++++++++++++++++++++---
Msource/nord/n2x/n2xLib/n2xtypes.h | 17++++++++++++-----
6 files changed, 146 insertions(+), 18 deletions(-)

diff --git a/source/nord/n2x/n2xLib/n2xdsp.cpp b/source/nord/n2x/n2xLib/n2xdsp.cpp @@ -1,7 +1,9 @@ #include "n2xdsp.h" #include "n2xhardware.h" +#include "dsp56kDebugger/debugger.h" #include "dsp56kEmu/dspthread.h" +#include "mc68k/hdi08.h" namespace n2x { @@ -74,12 +76,13 @@ namespace n2x config.aguSupportBitreverse = true; config.linkJitBlocks = true; - config.dynamicPeripheralAddressing = false; + config.dynamicPeripheralAddressing = true; #ifdef _DEBUG config.debugDynamicPeripheralAddressing = true; #endif config.maxInstructionsPerBlock = 0; config.support16BitSCMode = true; + config.dynamicFastInterrupts = true; m_dsp.getJit().setConfig(config); @@ -106,6 +109,9 @@ namespace n2x // set OMR pins so that bootcode wants program data via HDI08 RX m_dsp.setPC(g_bootCodeBase); m_dsp.regs().omr.var |= OMR_MA | OMR_MB | OMR_MC | OMR_MD; + + hdi08().setRXRateLimit(0); + hdi08().setTransmitDataAlwaysEmpty(false); m_hdiUC.setRxEmptyCallback([&](const bool _needMoreData) { @@ -123,51 +129,112 @@ namespace n2x { return hdiUcReadIsr(_isr); }); + m_hdiUC.setInitHdi08Callback([&] + { + // clear init flag again immediately, code is waiting for it to happen + m_hdiUC.icr(m_hdiUC.icr() & 0x7f); + m_hdiUC.isr(m_hdiUC.isr() | mc68k::Hdi08::IsrBits::Txde | mc68k::Hdi08::IsrBits::Trdy); + }); #if DSP56300_DEBUGGER - m_thread.reset(new dsp56k::DSPThread(dsp(), m_name.c_str(), std::make_shared<dsp56kDebugger::Debugger>(m_dsp.dsp()))); -#else - m_thread.reset(new dsp56k::DSPThread(dsp(), m_name.c_str())); + if(!m_index) + m_thread.reset(new dsp56k::DSPThread(dsp(), m_name.c_str(), std::make_shared<dsp56kDebugger::Debugger>(m_dsp))); + else #endif + m_thread.reset(new dsp56k::DSPThread(dsp(), m_name.c_str())); m_thread->setLogToStdout(false); } void DSP::onUCRxEmpty(bool _needMoreData) { + hdiTransferDSPtoUC(); } void DSP::hdiTransferUCtoDSP(const uint32_t _word) { - LOG('[' << m_name << "] toDSP writeRX=" << HEX(_word)); + LOG('[' << m_name << "] toDSP writeRX=" << HEX(_word) << ", ucPC=" << HEX(m_hardware.getUC().getPC())); hdi08().writeRX(&_word, 1); + m_hdiUC.isr(m_hdiUC.isr() & ~(mc68k::Hdi08::IsrBits::Txde | mc68k::Hdi08::IsrBits::Trdy)); } - void DSP::hdiSendIrqToDSP(uint8_t _irq) + void DSP::hdiSendIrqToDSP(const uint8_t _irq) { - dsp().injectExternalInterrupt(_irq); + LOG('[' << m_name << "] sendIRQtoDSP " << HEXN(_irq, 2)); + + waitDspRxEmpty(); + const auto& rxData = hdi08().rxData(); + auto& rxHack = const_cast<std::decay_t<decltype(rxData)>&>(rxData); - while(dsp().hasPendingInterrupts()) + if(hdi08().rxData().size() > 1) { - std::this_thread::yield(); + dsp56k::TWord v; + while(!hdi08().rxData().empty()) + { + v = rxHack.pop_front(); + LOG("Discarding UC2DSP HDI word " << HEX(v)); + } + LOG("Re-sending word " << HEX(v)); + hdi08().writeRX(&v,1); } + + dsp().injectExternalInterrupt(_irq); + + m_hardware.ucYieldLoop([&] + { + return dsp().hasPendingInterrupts(); + }); + + hdiTransferDSPtoUC(); } uint8_t DSP::hdiUcReadIsr(uint8_t _isr) { + // transfer DSP host flags HF2&3 to uc + const auto hf23 = hdi08().readControlRegister() & 0x18; + _isr &= ~0x18; + _isr |= hf23; + if(hdi08().hasRXData()) + _isr &= ~mc68k::Hdi08::IsrBits::Txde; + else if(_isr & mc68k::Hdi08::IsrBits::Txde) + _isr |= mc68k::Hdi08::IsrBits::Trdy; return _isr; } + void DSP::transferHostFlagsUc2Dsdp() + { + const uint32_t hf01 = m_hdiUC.icr() & 0x18; + + if (hf01 != m_hdiHF01) + { +// LOG('[' << m_name << "] HDI HF01=" << HEXN((hf01>>3),1)); + + waitDspRxEmpty(); + + m_hdiHF01 = hf01; + hdi08().setPendingHostFlags01(hf01); + } + } + bool DSP::hdiTransferDSPtoUC() { if (m_hdiUC.canReceiveData() && hdi08().hasTX()) { const auto v = hdi08().readTX(); - LOG('[' << m_name << "] HDI dsp2uc=" << HEX(v)); + LOG('[' << m_name << "] HDI dsp2UC=" << HEX(v)); m_hdiUC.writeRx(v); return true; } 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 @@ -40,7 +40,11 @@ namespace n2x void hdiTransferUCtoDSP(uint32_t _word); void hdiSendIrqToDSP(uint8_t _irq); uint8_t hdiUcReadIsr(uint8_t _isr); + public: + void transferHostFlagsUc2Dsdp(); + private: bool hdiTransferDSPtoUC(); + void waitDspRxEmpty(); Hardware& m_hardware; mc68k::Hdi08& m_hdiUC; @@ -56,5 +60,6 @@ namespace n2x std::unique_ptr<dsp56k::DSPThread> m_thread; bool m_receivedMagicEsaiPacket = false; + uint32_t m_hdiHF01 = 0; }; } diff --git a/source/nord/n2x/n2xLib/n2xhardware.cpp b/source/nord/n2x/n2xLib/n2xhardware.cpp @@ -19,5 +19,13 @@ namespace n2x void Hardware::process() { m_uc.exec(); + m_dspA.transferHostFlagsUc2Dsdp(); + m_dspB.transferHostFlagsUc2Dsdp(); + } + + void Hardware::ucYieldLoop(const std::function<bool()>& _continue) + { + while(_continue()) + std::this_thread::yield(); } } diff --git a/source/nord/n2x/n2xLib/n2xhardware.h b/source/nord/n2x/n2xLib/n2xhardware.h @@ -14,6 +14,9 @@ namespace n2x void process(); + Microcontroller& getUC() {return m_uc; } + void ucYieldLoop(const std::function<bool()>& _continue); + private: Rom m_rom; Microcontroller m_uc; diff --git a/source/nord/n2x/n2xLib/n2xmc.cpp b/source/nord/n2x/n2xLib/n2xmc.cpp @@ -2,6 +2,7 @@ #include <cassert> +#include "n2xdsp.h" #include "n2xrom.h" namespace n2x @@ -14,7 +15,7 @@ namespace n2x m_rom = _rom.data(); m_ram.fill(0); - dumpAssembly("n2x_68k.asm", g_romAddress, g_romSize); +// dumpAssembly("n2x_68k.asm", g_romAddress, g_romSize); reset(); @@ -49,6 +50,24 @@ namespace n2x if(m_hdi08A.isInRange(pa)) return m_hdi08A.read16(pa); if(m_hdi08B.isInRange(pa)) return m_hdi08B.read16(pa); + if(_addr >= g_frontPanelAddressA && _addr < g_frontPanelAddressA + g_frontPanelSize) + { + LOG("Read Frontpanel A " << HEX(_addr)); + return 0; + } + + if(_addr >= g_frontPanelAddressB && _addr < g_frontPanelAddressB + g_frontPanelSize) + { + LOG("Read Frontpanel B " << HEX(_addr)); + return 0; + } + + if(_addr >= g_keyboardAddress && _addr < g_keyboardAddress + g_keyboardSize) + { + LOG("Read Keyboard A " << HEX(_addr)); + return 0; + } + return Mc68k::read16(_addr); } @@ -61,6 +80,24 @@ namespace n2x if(m_hdi08A.isInRange(pa)) return m_hdi08A.read8(pa); if(m_hdi08B.isInRange(pa)) return m_hdi08B.read8(pa); + + if(_addr >= g_frontPanelAddressA && _addr < g_frontPanelAddressA + g_frontPanelSize) + { + LOG("Read Frontpanel A " << HEX(_addr)); + return 0xff; + } + + if(_addr >= g_frontPanelAddressB && _addr < g_frontPanelAddressB + g_frontPanelSize) + { + LOG("Read Frontpanel B " << HEX(_addr)); + return 0xff; + } + + if(_addr >= g_keyboardAddress && _addr < g_keyboardAddress + g_keyboardSize) + { + LOG("Read Keyboard A " << HEX(_addr)); + return 0xff; + } return Mc68k::read8(_addr); } @@ -130,10 +167,11 @@ namespace n2x uint32_t Microcontroller::exec() { const auto pc = getPC(); +// LOG("uc PC=" << HEX(pc)); if(pc >= g_ramAddress) { - if(pc == 0x1000c8) - dumpAssembly("nl2x_68k_ram.asm", g_ramAddress, g_ramSize); +// if(pc == 0x1000c8) +// dumpAssembly("nl2x_68k_ram.asm", g_ramAddress, g_ramSize); } const auto cycles = Mc68k::exec(); diff --git a/source/nord/n2x/n2xLib/n2xtypes.h b/source/nord/n2x/n2xLib/n2xtypes.h @@ -22,11 +22,18 @@ namespace n2x static constexpr uint32_t g_romSize = 1024 * 512; static constexpr uint32_t g_ramSize = 1024 * 256; - static constexpr uint32_t g_pcInitial = 0xc2; + static constexpr uint32_t g_pcInitial = 0xc2; - static constexpr uint32_t g_romAddress = 0; - static constexpr uint32_t g_ramAddress = 0x100000; + static constexpr uint32_t g_romAddress = 0; + static constexpr uint32_t g_ramAddress = 0x100000; - static constexpr uint32_t g_dspAAddress = 0x200008; - static constexpr uint32_t g_dspBAddress = 0x200010; + static constexpr uint32_t g_dspAAddress = 0x200008; + static constexpr uint32_t g_dspBAddress = 0x200010; + + static constexpr uint32_t g_frontPanelAddressA = 0x202800; + static constexpr uint32_t g_frontPanelAddressB = 0x202000; + static constexpr uint32_t g_keyboardAddress = 0x203000; + + static constexpr uint32_t g_frontPanelSize = 0x800; + static constexpr uint32_t g_keyboardSize = 0x800; }