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 aa062e07de6159fcbcffcc141a6c35967221afca
parent 62c887ef33ee4efb936a4c4b0eda8818b2011721
Author: dsp56300 <dsp56300@users.noreply.github.com>
Date:   Sun,  7 Jul 2024 19:23:14 +0200

rework DSP boot to no longer rely on the speed of a thread that feeds the HDI08 port, do it via callback now

Diffstat:
Msource/virusLib/device.cpp | 2+-
Msource/virusLib/dspSingle.cpp | 41+++++++++++++++++++++++++++++++++++++++++
Msource/virusLib/dspSingle.h | 7+++++++
Msource/virusLib/romfile.cpp | 53+++++++++++++----------------------------------------
Msource/virusLib/romfile.h | 8+++++---
Mtemp/cmake_win64/gearmulator.sln.DotSettings | 1+
6 files changed, 68 insertions(+), 44 deletions(-)

diff --git a/source/virusLib/device.cpp b/source/virusLib/device.cpp @@ -564,7 +564,7 @@ namespace virusLib std::thread Device::bootDSP(DspSingle& _dsp, const ROMFile& _rom, const bool _createDebugger) { - auto res = _rom.bootDSP(_dsp.getDSP(), _dsp.getHDI08()); + auto res = _rom.bootDSP(_dsp); _dsp.startDSPThread(_createDebugger); return res; } diff --git a/source/virusLib/dspSingle.cpp b/source/virusLib/dspSingle.cpp @@ -130,4 +130,45 @@ namespace virusLib while(!outs.empty()) outs.pop_front(); } + + std::thread DspSingle::boot(const ROMFile::BootRom& _bootRom, const std::vector<dsp56k::TWord>& _commandStream) + { + // Copy BootROM to DSP memory + for (uint32_t i=0; i<_bootRom.data.size(); i++) + { + const auto p = _bootRom.offset + i; + getMemory().set(dsp56k::MemArea_P, p, _bootRom.data[i]); + getJIT().notifyProgramMemWrite(p); + } + +// dsp.memory().saveAssembly((m_file + "_BootROM.asm").c_str(), bootRom.offset, bootRom.size, false, false, &periph); + + // Write command stream to HDI08 RX + m_commandStream = _commandStream; + m_commandStreamReadIndex = 0; + + while(!getHDI08().dataRXFull() && m_commandStreamReadIndex < m_commandStream.size()) + getHDI08().writeRX(&m_commandStream[m_commandStreamReadIndex++], 1); + + getHDI08().setReadRxCallback([this] + { + if(m_commandStreamReadIndex >= m_commandStream.size()) + { + getHDI08().setReadRxCallback(nullptr); + return; + } + + getHDI08().writeRX(&m_commandStream[m_commandStreamReadIndex++], 1); + }); + + std::thread waitForCommandStreamWrite([this]() + { + while(m_commandStreamReadIndex < m_commandStream.size()) + std::this_thread::yield(); + }); + + // Initialize the DSP + getDSP().setPC(_bootRom.offset); + return waitForCommandStreamWrite; + } } diff --git a/source/virusLib/dspSingle.h b/source/virusLib/dspSingle.h @@ -1,5 +1,7 @@ #pragma once +#include "romfile.h" + #include "dsp56kEmu/dspthread.h" #include "dsp56kEmu/memory.h" #include "dsp56kEmu/peripherals.h" @@ -39,6 +41,8 @@ namespace virusLib void disableESSI1(); void drainESSI1(); + std::thread boot(const ROMFile::BootRom& _bootRom, const std::vector<dsp56k::TWord>& _commandStream); + template<typename T> static void ensureSize(std::vector<T>& _buf, size_t _size) { if(_buf.size() >= _size) @@ -72,5 +76,8 @@ namespace virusLib dsp56k::Jit* m_jit = nullptr; std::unique_ptr<dsp56k::DSPThread> m_dspThread; + + std::vector<dsp56k::TWord> m_commandStream; + uint32_t m_commandStreamReadIndex = 0; }; } diff --git a/source/virusLib/romfile.cpp b/source/virusLib/romfile.cpp @@ -14,8 +14,7 @@ #include <cstring> // memcpy #include "demoplaybackTI.h" -#include "dsp56kEmu/memory.h" -#include "dsp56kEmu/threadtools.h" +#include "dspSingle.h" namespace virusLib { @@ -25,7 +24,7 @@ ROMFile::ROMFile(std::vector<uint8_t> _data, std::string _name, const DeviceMode if(initialize()) return; m_romFileData.clear(); - bootRom.size = 0; + m_bootRom.size = 0; } ROMFile ROMFile::invalid() @@ -59,15 +58,15 @@ bool ROMFile::initialize() if (chunks.empty()) return false; - bootRom.size = chunks[0].items[0]; - bootRom.offset = chunks[0].items[1]; - bootRom.data = std::vector<uint32_t>(bootRom.size); + m_bootRom.size = chunks[0].items[0]; + m_bootRom.offset = chunks[0].items[1]; + m_bootRom.data = std::vector<uint32_t>(m_bootRom.size); // The first chunk contains the bootrom uint32_t i = 2; - for (; i < bootRom.size + 2; i++) + for (; i < m_bootRom.size + 2; i++) { - bootRom.data[i-2] = chunks[0].items[i]; + m_bootRom.data[i-2] = chunks[0].items[i]; } // The rest of the chunks is made up of the command stream @@ -78,8 +77,8 @@ bool ROMFile::initialize() i = 0; } - printf("Program BootROM size = 0x%x\n", bootRom.size); - printf("Program BootROM offset = 0x%x\n", bootRom.offset); + printf("Program BootROM size = 0x%x\n", m_bootRom.size); + printf("Program BootROM offset = 0x%x\n", m_bootRom.offset); printf("Program CommandStream size = 0x%x\n", static_cast<uint32_t>(m_commandStream.size())); #if VIRUS_SUPPORT_TI @@ -127,7 +126,7 @@ bool ROMFile::initialize() if(j == searchSize-1) { TPreset preset; - memcpy(&preset[0], &fw.DSP[i - 4], std::size(preset)); + memcpy(preset.data(), &fw.DSP[i - 4], std::size(preset)); // validate that we found the correct data by checking part volumes. It might just be a string somewhere in the data for(size_t k=0; k<16; ++k) @@ -137,7 +136,7 @@ bool ROMFile::initialize() if(k == 15) { - for(size_t k=0; k<getPresetsPerBank(); ++k) + for(size_t p=0; p<getPresetsPerBank(); ++p) m_multis.push_back(preset); } } @@ -331,35 +330,9 @@ bool ROMFile::loadPresetFile(std::istream& _file, DeviceModel _model) return true; } -std::thread ROMFile::bootDSP(dsp56k::DSP& dsp, dsp56k::HDI08& _hdi08) const +std::thread ROMFile::bootDSP(DspSingle& _dsp) const { - // Load BootROM in DSP memory - for (uint32_t i=0; i<bootRom.data.size(); i++) - { - const auto p = bootRom.offset + i; - dsp.memory().set(dsp56k::MemArea_P, p, bootRom.data[i]); - dsp.getJit().notifyProgramMemWrite(p); - } - -// dsp.memory().saveAssembly((m_file + "_BootROM.asm").c_str(), bootRom.offset, bootRom.size, false, false, &periph); - - // Attach command stream - size_t i=0; - while(!_hdi08.dataRXFull() && i < m_commandStream.size()) - _hdi08.writeRX(&m_commandStream[i++], 1); - - std::thread feedCommandStream([&_hdi08, this, i]() - { - if(i >= m_commandStream.size()) - return; - - dsp56k::ThreadTools::setCurrentThreadPriority(dsp56k::ThreadPriority::Highest); - _hdi08.writeRX(&m_commandStream[i], m_commandStream.size() - i); - }); - - // Initialize the DSP - dsp.setPC(bootRom.offset); - return feedCommandStream; + return _dsp.boot(m_bootRom, m_commandStream); } std::string ROMFile::getModelName() const diff --git a/source/virusLib/romfile.h b/source/virusLib/romfile.h @@ -18,6 +18,8 @@ namespace dsp56k namespace virusLib { +class DspSingle; + class ROMFile { public: @@ -50,9 +52,9 @@ public: static std::string getMultiName(const TPreset& _preset); static std::string getPresetName(const TPreset& _preset, uint32_t _first, uint32_t _last); - std::thread bootDSP(dsp56k::DSP& dsp, dsp56k::HDI08& _hdi08) const; + std::thread bootDSP(DspSingle& _dsp) const; - bool isValid() const { return bootRom.size > 0; } + bool isValid() const { return m_bootRom.size > 0; } DeviceModel getModel() const { return m_model; } @@ -124,7 +126,7 @@ private: bool initialize(); - BootRom bootRom; + BootRom m_bootRom; std::vector<uint32_t> m_commandStream; DeviceModel m_model = DeviceModel::Invalid; diff --git a/temp/cmake_win64/gearmulator.sln.DotSettings b/temp/cmake_win64/gearmulator.sln.DotSettings @@ -23,6 +23,7 @@ <s:String x:Key="/Default/CodeStyle/Naming/CppNaming/Abbreviations/=SSH/@EntryIndexedValue">SSH</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CppNaming/Abbreviations/=SSL/@EntryIndexedValue">SSL</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CppNaming/Abbreviations/=TI/@EntryIndexedValue">TI</s:String> + <s:String x:Key="/Default/CodeStyle/Naming/CppNaming/Abbreviations/=TX/@EntryIndexedValue">TX</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CppNaming/Abbreviations/=XY/@EntryIndexedValue">XY</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CppNaming/Rules/=Classes_0020and_0020structs/@EntryIndexedValue">&lt;NamingElement Priority="1"&gt;&lt;Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"&gt;&lt;type Name="__interface" /&gt;&lt;type Name="class" /&gt;&lt;type Name="struct" /&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;&lt;/NamingElement&gt;</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CppNaming/Rules/=Class_0020and_0020struct_0020fields/@EntryIndexedValue">&lt;NamingElement Priority="11"&gt;&lt;Descriptor Static="Indeterminate" Constexpr="Indeterminate" Const="Indeterminate" Volatile="Indeterminate" Accessibility="NOT_APPLICABLE"&gt;&lt;type Name="class field" /&gt;&lt;type Name="struct field" /&gt;&lt;/Descriptor&gt;&lt;Policy Inspect="True" Prefix="m_" Suffix="" Style="aaBb" /&gt;&lt;/NamingElement&gt;</s:String>