mqmc.cpp (8390B)
1 #include "mqmc.h" 2 3 #include <array> 4 #include <fstream> 5 6 #include "rom.h" 7 8 #include <cstring> // memcpy 9 10 #include "mqbuildconfig.h" 11 #include "mc68k/logging.h" 12 13 #define MC68K_CLASS mqLib::MqMc 14 #include "mc68k/musashiEntry.h" 15 16 namespace mqLib 17 { 18 constexpr uint32_t g_romAddress = 0x80000; 19 constexpr uint32_t g_pcInitial = 0x80130; 20 constexpr uint32_t g_memorySize = 0x40000; 21 22 static std::string logChar(char _val) 23 { 24 std::stringstream ss; 25 if(_val > 32 && _val < 127) 26 ss << _val; 27 else 28 ss << "[" << MCHEXN(static_cast<uint8_t>(_val), 2) << "]"; 29 return ss.str(); 30 } 31 32 MqMc::MqMc(const ROM& _rom) : m_rom(_rom) 33 { 34 if(!_rom.isValid()) 35 return; 36 m_romRuntimeData.resize(ROM::size()); 37 memcpy(m_romRuntimeData.data(), m_rom.getData().data(), ROM::size()); 38 39 m_flash.reset(new hwLib::Am29f(m_romRuntimeData.data(), m_romRuntimeData.size(), false, true)); 40 41 m_memory.resize(g_memorySize, 0); 42 43 reset(); 44 45 setPC(g_pcInitial); 46 47 getPortGP().setWriteTXCallback([this](const mc68k::Port&) 48 { 49 onPortGPWritten(); 50 }); 51 52 getPortE().setWriteTXCallback([this](const mc68k::Port&) 53 { 54 onPortEWritten(); 55 }); 56 57 getPortF().setWriteTXCallback([this](const mc68k::Port&) 58 { 59 onPortFWritten(); 60 }); 61 62 getPortQS().setDirectionChangeCallback([this](const mc68k::Port&) 63 { 64 onPortQSWritten(); 65 }); 66 67 getPortQS().setWriteTXCallback([this](const mc68k::Port&) 68 { 69 onPortQSWritten(); 70 }); 71 72 #if 0 73 dumpAssembly(g_romAddress, g_romSize); 74 #endif 75 } 76 77 MqMc::~MqMc() = default; 78 79 // uint64_t g_instructionCounter = 0; 80 // std::deque<uint32_t> g_lastPCs; 81 82 uint32_t MqMc::exec() 83 { 84 // if(g_instructionCounter >= 17300000) 85 // MCLOG("Exec @ " << MCHEX(getPC())); 86 /* 87 g_lastPCs.push_back(getPC()); 88 if(g_lastPCs.size() > 100) 89 g_lastPCs.pop_front(); 90 */ 91 // ++g_instructionCounter; 92 93 const uint32_t deltaCycles = Mc68k::exec(); 94 95 m_hdi08a.exec(deltaCycles); 96 97 if constexpr (g_useVoiceExpansion) 98 { 99 m_hdi08b.exec(deltaCycles); 100 m_hdi08c.exec(deltaCycles); 101 } 102 103 m_buttons.processButtons(getPortGP(), getPortE()); 104 105 return deltaCycles; 106 } 107 108 void MqMc::notifyDSPBooted() 109 { 110 if(!m_dspResetCompleted) 111 MCLOG("DSP has booted"); 112 m_dspResetCompleted = true; 113 } 114 115 uint16_t MqMc::readImm16(uint32_t addr) 116 { 117 if(addr < g_memorySize) 118 { 119 return mc68k::memoryOps::readU16(m_memory, addr); 120 } 121 122 if(addr >= g_romAddress && addr < g_romAddress + ROM::size()) 123 { 124 const auto r = mc68k::memoryOps::readU16(m_romRuntimeData, addr - g_romAddress); 125 // LOG("read16 from ROM addr=" << HEXN(addr, 8) << " val=" << HEXN(r, 4)); 126 return r; 127 } 128 // __debugbreak(); 129 return 0; 130 } 131 132 uint16_t MqMc::read16(uint32_t addr) 133 { 134 if(addr < g_memorySize) 135 { 136 return mc68k::memoryOps::readU16(m_memory, addr); 137 } 138 139 if(addr >= g_romAddress && addr < g_romAddress + ROM::size()) 140 { 141 const auto r = mc68k::memoryOps::readU16(m_romRuntimeData, addr - g_romAddress); 142 // LOG("read16 from ROM addr=" << HEXN(addr, 8) << " val=" << HEXN(r, 4)); 143 return r; 144 } 145 146 const auto pa = static_cast<mc68k::PeriphAddress>(addr & mc68k::g_peripheralMask); 147 148 if (m_hdi08a.isInRange(pa)) 149 return m_hdi08a.read16(pa); 150 151 if constexpr (g_useVoiceExpansion) 152 { 153 if (m_hdi08b.isInRange(pa)) 154 return m_hdi08b.read16(pa); 155 if (m_hdi08c.isInRange(pa)) 156 return m_hdi08c.read16(pa); 157 } 158 159 // LOG("read16 addr=" << HEXN(addr, 8) << ", pc=" << HEXN(getPC(), 8)); 160 161 return Mc68k::read16(addr); 162 } 163 164 uint8_t MqMc::read8(uint32_t addr) 165 { 166 if(addr < g_memorySize) 167 return m_memory[addr]; 168 169 if(addr >= g_romAddress && addr < g_romAddress + ROM::size()) 170 return m_romRuntimeData[addr - g_romAddress]; 171 172 const auto pa = static_cast<mc68k::PeriphAddress>(addr & mc68k::g_peripheralMask); 173 174 if (m_hdi08a.isInRange(pa)) 175 return m_hdi08a.read8(pa); 176 if constexpr (g_useVoiceExpansion) 177 { 178 if (m_hdi08b.isInRange(pa)) 179 return m_hdi08b.read8(pa); 180 if (m_hdi08c.isInRange(pa)) 181 return m_hdi08c.read8(pa); 182 } 183 184 // LOG("read8 addr=" << HEXN(addr, 8) << ", pc=" << HEXN(getPC(), 8)); 185 186 return Mc68k::read8(addr); 187 } 188 189 void MqMc::write16(uint32_t addr, uint16_t val) 190 { 191 // Dump memory if DSP test reaches error state 192 if(addr == 0x384A8) 193 { 194 if(val > 0 && val <= 0xff) 195 dumpMemory((std::string("DSPTest_Error_") + std::to_string(val)).c_str()); 196 } 197 198 if(addr < g_memorySize) 199 { 200 mc68k::memoryOps::writeU16(m_memory, addr, val); 201 return; 202 } 203 204 if(addr >= g_romAddress && addr < g_romAddress + ROM::size()) 205 { 206 MCLOG("write16 TO ROM addr=" << MCHEXN(addr, 8) << ", value=" << MCHEXN(val,4) << ", pc=" << MCHEXN(getPC(), 8)); 207 m_flash->write(addr - g_romAddress, val); 208 return; 209 } 210 211 const auto pa = static_cast<mc68k::PeriphAddress>(addr & mc68k::g_peripheralMask); 212 213 if (m_hdi08a.isInRange(pa)) 214 { 215 m_hdi08a.write16(pa, val); 216 return; 217 } 218 219 if constexpr (g_useVoiceExpansion) 220 { 221 if (m_hdi08b.isInRange(pa)) 222 { 223 m_hdi08b.write16(pa, val); 224 return; 225 } 226 if (m_hdi08c.isInRange(pa)) 227 { 228 m_hdi08c.write16(pa, val); 229 return; 230 } 231 } 232 233 Mc68k::write16(addr, val); 234 } 235 236 void MqMc::write8(uint32_t addr, uint8_t val) 237 { 238 // Dump memory if DSP test reaches error state 239 if(addr == 0x384A8) 240 { 241 if(val > 0) 242 dumpMemory((std::string("DSPTest_Error_") + std::to_string(val)).c_str()); 243 } 244 245 if(addr < g_memorySize) 246 { 247 m_memory[addr] = val; 248 return; 249 } 250 251 if(addr >= g_romAddress && addr < g_romAddress + ROM::size()) 252 { 253 MCLOG("write8 TO ROM addr=" << MCHEXN(addr, 8) << ", value=" << MCHEXN(val,2) << " char=" << logChar(val) << ", pc=" << MCHEXN(getPC(), 8)); 254 m_flash->write(addr - g_romAddress, val); 255 return; 256 } 257 258 // LOG("write8 addr=" << HEXN(addr, 8) << ", value=" << HEXN(val,2) << " char=" << logChar(val) << ", pc=" << HEXN(getPC(), 8)); 259 260 const auto pa = static_cast<mc68k::PeriphAddress>(addr & mc68k::g_peripheralMask); 261 if (m_hdi08a.isInRange(pa)) 262 { 263 m_hdi08a.write8(pa, val); 264 return; 265 } 266 267 if constexpr (g_useVoiceExpansion) 268 { 269 if (m_hdi08b.isInRange(pa)) 270 { 271 m_hdi08b.write8(pa, val); 272 return; 273 } 274 if (m_hdi08c.isInRange(pa)) 275 { 276 m_hdi08c.write8(pa, val); 277 return; 278 } 279 } 280 281 Mc68k::write8(addr, val); 282 } 283 284 void MqMc::dumpMemory(const char* _filename) const 285 { 286 FILE* hFile = fopen((std::string(_filename) + ".bin").c_str(), "wb"); 287 fwrite(m_memory.data(), 1, m_memory.size(), hFile); 288 fclose(hFile); 289 } 290 291 void MqMc::dumpROM(const char* _filename) const 292 { 293 FILE* hFile = fopen((std::string(_filename) + ".bin").c_str(), "wb"); 294 fwrite(m_romRuntimeData.data(), 1, ROM::size(), hFile); 295 fclose(hFile); 296 } 297 298 void MqMc::dumpAssembly(const uint32_t _first, const uint32_t _count) 299 { 300 std::stringstream ss; 301 ss << "mq_68k_" << _first << '-' << (_first + _count) << ".asm"; 302 303 std::ofstream f(ss.str(), std::ios::out); 304 305 for(uint32_t i=_first; i<_first + _count;) 306 { 307 char disasm[64]; 308 const auto opSize = disassemble(i, disasm); 309 f << MCHEXN(i,5) << ": " << disasm << std::endl; 310 if(!opSize) 311 ++i; 312 else 313 i += opSize; 314 } 315 f.close(); 316 } 317 318 void MqMc::onReset() 319 { 320 dumpMemory("dump_reset"); 321 } 322 323 uint32_t MqMc::onIllegalInstruction(uint32_t opcode) 324 { 325 std::stringstream ss; 326 ss << "illegalInstruction_" << MCHEXN(getPC(), 8) << "_op" << MCHEXN(opcode,8); 327 dumpMemory(ss.str().c_str()); 328 329 return Mc68k::onIllegalInstruction(opcode); 330 } 331 332 void MqMc::onPortEWritten() 333 { 334 processLCDandLEDs(); 335 } 336 337 void MqMc::onPortFWritten() 338 { 339 processLCDandLEDs(); 340 } 341 342 void MqMc::onPortGPWritten() 343 { 344 processLCDandLEDs(); 345 } 346 347 void MqMc::onPortQSWritten() 348 { 349 const bool resetIsOutput = getPortQS().getDirection() & (1<<3); 350 if(resetIsOutput) 351 { 352 if(!(getPortQS().read() & (1<<3))) 353 { 354 if(!m_dspResetRequest) 355 { 356 #ifdef _DEBUG 357 MCLOG("Request DSP RESET"); 358 #endif 359 m_dspResetRequest = true; 360 m_dspResetCompleted = false; 361 } 362 } 363 } 364 else 365 { 366 if(m_dspResetCompleted) 367 { 368 m_dspResetRequest = false; 369 getPortQS().writeRX(1<<3); 370 } 371 } 372 #if SUPPORT_NMI_INTERRUPT 373 if(getPortQS().getDirection() & (1<<6)) 374 { 375 m_dspInjectNmiRequest = (getPortQS().read() >> 6) & 1; 376 if(m_dspInjectNmiRequest) 377 int debug=0; 378 } 379 #endif 380 } 381 382 void MqMc::processLCDandLEDs() 383 { 384 if(m_lcd.exec(getPortGP(), getPortF())) 385 { 386 // const std::string s(&m_lcd.getDdRam().front()); 387 // if(s.find("SIG") != std::string::npos) 388 // dumpMemory("SIG"); 389 } 390 else 391 { 392 m_leds.exec(getPortF(), getPortGP(), getPortE()); 393 } 394 } 395 }