xtDSP.cpp (4740B)
1 #include "xtDSP.h" 2 3 #include "xtHardware.h" 4 5 #if DSP56300_DEBUGGER 6 #include "dsp56kDebugger/debugger.h" 7 #endif 8 9 #include "mc68k/hdi08.h" 10 11 #include "dsp56kEmu/aar.h" 12 #include "dsp56kEmu/types.h" 13 14 namespace xt 15 { 16 static dsp56k::DefaultMemoryValidator g_memoryValidator; 17 18 DSP::DSP(Hardware& _hardware, mc68k::Hdi08& _hdiUC, const uint32_t _index) 19 : m_hardware(_hardware), m_hdiUC(_hdiUC) 20 , m_index(_index) 21 , m_name({static_cast<char>('A' + _index)}) 22 , m_periphX() 23 , m_memory(g_memoryValidator, g_pMemSize, g_xyMemSize, g_bridgedAddr, m_memoryBuffer) 24 , m_dsp(m_memory, &m_periphX, &m_periphNop) 25 , m_boot(m_dsp) 26 { 27 if(!_hardware.isValid()) 28 return; 29 30 m_periphX.getEssiClock().setExternalClockFrequency(10'240'000); // 10,24 MHz 31 m_periphX.getEssiClock().setSamplerate(40000); 32 m_periphX.getEssiClock().setClockSource(dsp56k::EsaiClock::ClockSource::Cycles); 33 34 auto config = m_dsp.getJit().getConfig(); 35 36 config.aguSupportBitreverse = true; 37 config.linkJitBlocks = true; 38 config.dynamicPeripheralAddressing = false; 39 #ifdef _DEBUG 40 config.debugDynamicPeripheralAddressing = true; 41 #endif 42 43 // allow dynamic peripheral addressing for code following clr b M_AAR3,r2 44 enableDynamicPeripheralAddressing(config, m_dsp, 0x62f41b, dsp56k::M_AAR3, 16); 45 46 m_dsp.getJit().setConfig(config); 47 48 // fill P memory with something that reminds us if we jump to garbage 49 for(dsp56k::TWord i=0; i<m_memory.sizeP(); ++i) 50 { 51 m_memory.set(dsp56k::MemArea_P, i, 0x000200); // debug instruction 52 m_dsp.getJit().notifyProgramMemWrite(i); 53 } 54 55 // getPeriph().disableTimers(true); 56 57 m_periphX.getEssi0().writeEmptyAudioIn(8); 58 59 hdi08().setRXRateLimit(0); 60 hdi08().setTransmitDataAlwaysEmpty(false); 61 62 m_hdiUC.setRxEmptyCallback([&](const bool needMoreData) 63 { 64 onUCRxEmpty(needMoreData); 65 }); 66 m_hdiUC.setWriteTxCallback([&](const uint32_t _word) 67 { 68 if(m_boot.hdiWriteTX(_word)) 69 onDspBooted(); 70 }); 71 m_hdiUC.setWriteIrqCallback([&](const uint8_t _irq) 72 { 73 hdiSendIrqToDSP(_irq); 74 }); 75 m_hdiUC.setReadIsrCallback([&](const uint8_t _isr) 76 { 77 return hdiUcReadIsr(_isr); 78 }); 79 } 80 81 void DSP::exec() 82 { 83 m_thread->join(); 84 m_thread.reset(); 85 86 m_hdiUC.setRxEmptyCallback({}); 87 m_dsp.exec(); 88 } 89 90 void DSP::dumpPMem(const std::string& _filename) 91 { 92 m_memory.saveAssembly((_filename + ".asm").c_str(), 0, g_pMemSize, true, false, &m_periphX); 93 } 94 95 void DSP::dumpXYMem(const std::string& _filename) const 96 { 97 m_memory.save((_filename + "_X.txt").c_str(), dsp56k::MemArea_X); 98 m_memory.save((_filename + "_Y.txt").c_str(), dsp56k::MemArea_Y); 99 } 100 101 void DSP::transferHostFlagsUc2Dsdp() 102 { 103 const uint32_t hf01 = m_hdiUC.icr() & 0x18; 104 105 if (hf01 != m_hdiHF01) 106 { 107 // LOG('[' << m_name << "] HDI HF01=" << HEXN((hf01>>3),1)); 108 waitDspRxEmpty(); 109 m_hdiHF01 = hf01; 110 hdi08().setPendingHostFlags01(hf01); 111 } 112 } 113 114 void DSP::onDspBooted() 115 { 116 m_hdiUC.setWriteTxCallback([&](const uint32_t _word) 117 { 118 hdiTransferUCtoDSP(_word); 119 }); 120 121 #if DSP56300_DEBUGGER 122 m_thread.reset(new dsp56k::DSPThread(dsp(), m_name.c_str(), std::make_shared<dsp56kDebugger::Debugger>(m_dsp))); 123 #else 124 m_thread.reset(new dsp56k::DSPThread(dsp(), m_name.c_str())); 125 #endif 126 127 m_thread->setLogToStdout(false); 128 } 129 130 void DSP::onUCRxEmpty(bool _needMoreData) 131 { 132 hdi08().injectTXInterrupt(); 133 134 if (_needMoreData) 135 { 136 m_hardware.ucYieldLoop([&]() 137 { 138 return dsp().hasPendingInterrupts() || (hdi08().txInterruptEnabled() && !hdi08().hasTX()); 139 }); 140 } 141 142 hdiTransferDSPtoUC(); 143 } 144 145 bool DSP::hdiTransferDSPtoUC() 146 { 147 if (m_hdiUC.canReceiveData() && hdi08().hasTX()) 148 { 149 const auto v = hdi08().readTX(); 150 // LOG('[' << m_name << "] HDI dsp2uc=" << HEX(v)); 151 m_hdiUC.writeRx(v); 152 return true; 153 } 154 return false; 155 } 156 157 void DSP::hdiTransferUCtoDSP(dsp56k::TWord _word) 158 { 159 m_haveSentTXtoDSP = true; 160 // LOG('[' << m_name << "] toDSP writeRX=" << HEX(_word)); 161 162 // this can happen during "Reorganising Memory", DSP must resume to process incoming data 163 if (hdi08().dataRXFull()) 164 m_hardware.resumeDSP(); 165 hdi08().writeRX(&_word, 1); 166 } 167 168 void DSP::hdiSendIrqToDSP(uint8_t _irq) 169 { 170 waitDspRxEmpty(); 171 172 // LOG('[' << m_name << "] Inject interrupt" << HEXN(_irq,2)); 173 174 dsp().injectExternalInterrupt(_irq); 175 176 m_hardware.ucYieldLoop([&]() 177 { 178 return dsp().hasPendingInterrupts(); 179 }); 180 181 hdiTransferDSPtoUC(); 182 } 183 184 uint8_t DSP::hdiUcReadIsr(uint8_t _isr) 185 { 186 // transfer DSP host flags HF2&3 to uc 187 const auto hf23 = hdi08().readControlRegister() & 0x18; 188 _isr &= ~0x18; 189 _isr |= hf23; 190 return _isr; 191 } 192 193 void DSP::waitDspRxEmpty() 194 { 195 m_hardware.ucYieldLoop([&]() 196 { 197 return (hdi08().hasRXData() && hdi08().rxInterruptEnabled()) || dsp().hasPendingInterrupts(); 198 }); 199 // LOG("writeRX wait over"); 200 } 201 202 }