dspSingle.cpp (6018B)
1 #include "dspSingle.h" 2 3 #include "dsp56kEmu/dsp.h" 4 5 #if DSP56300_DEBUGGER 6 #include "dsp56kDebugger/debugger.h" 7 #endif 8 9 namespace virusLib 10 { 11 constexpr dsp56k::TWord g_externalMemStart = 0x020000; 12 13 DspSingle::DspSingle(uint32_t _memorySize, bool _use56367Peripherals/* = false*/, const char* _name/* = nullptr*/, bool _use56303Peripherals/* = false*/) 14 : m_name(_name ? _name : std::string()) 15 , m_periphX362(_use56367Peripherals ? &m_periphY367 : nullptr) 16 , m_hdi08(_use56303Peripherals ? m_periphX303.getHI08() : m_periphX362.getHDI08()) 17 , m_audio(_use56303Peripherals ? static_cast<dsp56k::Audio&>(m_periphX303.getEssi0()) : static_cast<dsp56k::Audio&>(m_periphX362.getEsai())) 18 , m_esxiClock(_use56303Peripherals ? static_cast<dsp56k::EsxiClock&>(m_periphX303.getEssiClock()) : static_cast<dsp56k::EsxiClock&>(m_periphX362.getEsaiClock())) 19 { 20 const size_t requiredMemSize = 21 dsp56k::alignedSize<dsp56k::DSP>() + 22 dsp56k::alignedSize<dsp56k::Memory>() + 23 dsp56k::Memory::calcMemSize(_memorySize, g_externalMemStart) * sizeof(uint32_t); 24 25 m_buffer.resize(dsp56k::alignedSize(requiredMemSize)); 26 27 auto* buf = m_buffer.data(); 28 buf = dsp56k::alignedAddress(buf); 29 30 auto* bufDSPClass = buf; 31 auto* bufMemClass = bufDSPClass + dsp56k::alignedSize<dsp56k::DSP>(); 32 auto* bufMemSpace = bufMemClass + dsp56k::alignedSize<dsp56k::Memory>(); 33 34 m_memory = new (bufMemClass)dsp56k::Memory(m_memoryValidator, _memorySize, _memorySize, g_externalMemStart, reinterpret_cast<dsp56k::TWord*>(bufMemSpace)); 35 36 dsp56k::IPeripherals* periphX = &m_periphX362; 37 dsp56k::IPeripherals* periphY = &m_periphNop; 38 39 if(_use56303Peripherals) 40 { 41 periphX = &m_periphX303; 42 m_periphX303.getEssiClock().setExternalClockFrequency(4'000'000); // 4 Mhz 43 m_periphX303.getEssiClock().setSamplerate(12000000/256); 44 drainESSI1(); 45 } 46 47 if (_use56367Peripherals) 48 periphY = &m_periphY367; 49 50 m_dsp = new (buf)dsp56k::DSP(*m_memory, periphX, periphY); 51 52 m_jit = &m_dsp->getJit(); 53 } 54 55 DspSingle::~DspSingle() 56 { 57 m_dspThread.reset(); 58 59 if(m_dsp) 60 { 61 m_dsp->~DSP(); 62 m_memory->~Memory(); 63 64 m_dsp = nullptr; 65 m_memory = nullptr; 66 } 67 } 68 69 void DspSingle::startDSPThread(const bool _createDebugger) 70 { 71 #if DSP56300_DEBUGGER 72 const auto debugger = _createDebugger ? std::make_shared<dsp56kDebugger::Debugger>(*m_dsp) : std::shared_ptr<dsp56kDebugger::Debugger>(); 73 #else 74 const auto debugger = std::shared_ptr<dsp56k::DebuggerInterface>(); 75 #endif 76 77 m_dspThread.reset(new dsp56k::DSPThread(*m_dsp, m_name.empty() ? nullptr : m_name.c_str(), debugger)); 78 79 #ifdef ZYNTHIAN 80 m_dspThread->setLogToDebug(false); 81 m_dspThread->setLogToStdout(false); 82 #endif 83 } 84 85 template<typename T> void processAudio(DspSingle& _dsp, const synthLib::TAudioInputsT<T>& _inputs, const synthLib::TAudioOutputsT<T>& _outputs, const size_t _samples, uint32_t _latency, std::vector<T>& _dummyIn, std::vector<T>& _dummyOut) 86 { 87 DspSingle::ensureSize(_dummyIn, _samples<<1); 88 DspSingle::ensureSize(_dummyOut, _samples<<1); 89 90 const T* dIn = _dummyIn.data(); 91 T* dOut = _dummyOut.data(); 92 93 const T* inputs[] = {_inputs[0] ? _inputs[0] : dIn, _inputs[1] ? _inputs[1] : dIn, dIn, dIn, dIn, dIn, dIn, dIn}; 94 T* outputs[] = 95 { _outputs[0] ? _outputs[0] : dOut 96 , _outputs[1] ? _outputs[1] : dOut 97 , _outputs[2] ? _outputs[2] : dOut 98 , _outputs[3] ? _outputs[3] : dOut 99 , _outputs[4] ? _outputs[4] : dOut 100 , _outputs[5] ? _outputs[5] : dOut 101 , dOut, dOut, dOut, dOut, dOut, dOut}; 102 103 _dsp.getAudio().processAudioInterleaved(inputs, outputs, static_cast<uint32_t>(_samples), _latency); 104 } 105 void DspSingle::processAudio(const synthLib::TAudioInputs& _inputs, const synthLib::TAudioOutputs& _outputs, const size_t _samples, const uint32_t _latency) 106 { 107 virusLib::processAudio(*this, _inputs, _outputs, _samples, _latency, m_dummyBufferInF, m_dummyBufferOutF); 108 } 109 110 void DspSingle::processAudio(const synthLib::TAudioInputsInt& _inputs, const synthLib::TAudioOutputsInt& _outputs, const size_t _samples, const uint32_t _latency) 111 { 112 virusLib::processAudio(*this, _inputs, _outputs, _samples, _latency, m_dummyBufferInI, m_dummyBufferOutI); 113 } 114 115 void DspSingle::disableESSI1() 116 { 117 // Model A uses ESSI1 to send some initialization data to something. 118 // Disable it once it has done doing that because otherwise it keeps running 119 // and causes a performance hit that we can prevent by disabling it 120 auto& essi = m_periphX303.getEssi1(); 121 auto crb = essi.readCRB(); 122 crb &= ~((1<<dsp56k::Essi::CRB_RE) | dsp56k::Essi::CRB_TE); 123 essi.writeCRB(crb); 124 } 125 126 void DspSingle::drainESSI1() 127 { 128 auto& essi = m_periphX303.getEssi1(); 129 auto& ins = essi.getAudioInputs(); 130 auto& outs = essi.getAudioOutputs(); 131 132 while(!ins.full()) 133 ins.push_back({}); 134 135 while(!outs.empty()) 136 outs.pop_front(); 137 } 138 139 std::thread DspSingle::boot(const ROMFile::BootRom& _bootRom, const std::vector<dsp56k::TWord>& _commandStream) 140 { 141 // Copy BootROM to DSP memory 142 for (uint32_t i=0; i<_bootRom.data.size(); i++) 143 { 144 const auto p = _bootRom.offset + i; 145 getMemory().set(dsp56k::MemArea_P, p, _bootRom.data[i]); 146 getJIT().notifyProgramMemWrite(p); 147 } 148 149 // dsp.memory().saveAssembly((m_file + "_BootROM.asm").c_str(), bootRom.offset, bootRom.size, false, false, &periph); 150 151 // Write command stream to HDI08 RX 152 m_commandStream = _commandStream; 153 m_commandStreamReadIndex = 0; 154 155 while(!getHDI08().dataRXFull() && m_commandStreamReadIndex < m_commandStream.size()) 156 getHDI08().writeRX(&m_commandStream[m_commandStreamReadIndex++], 1); 157 158 getHDI08().setReadRxCallback([this] 159 { 160 if(m_commandStreamReadIndex >= m_commandStream.size()) 161 { 162 getHDI08().setReadRxCallback(nullptr); 163 return; 164 } 165 166 getHDI08().writeRX(&m_commandStream[m_commandStreamReadIndex++], 1); 167 }); 168 169 std::thread waitForCommandStreamWrite([this]() 170 { 171 while(m_commandStreamReadIndex < m_commandStream.size()) 172 std::this_thread::yield(); 173 }); 174 175 // Initialize the DSP 176 getDSP().setPC(_bootRom.offset); 177 return waitForCommandStreamWrite; 178 } 179 }