diff --git a/include/audio/dsp_core.hpp b/include/audio/dsp_core.hpp index 27a660d3..b15a64da 100644 --- a/include/audio/dsp_core.hpp +++ b/include/audio/dsp_core.hpp @@ -66,6 +66,21 @@ namespace Audio { virtual Type getType() = 0; virtual void* getRegisters() { return nullptr; } + + // Read a word from program memory. By default, just perform a regular DSP RAM read for the HLE cores + // The LLE cores translate the address, accounting for the way Teak memory is mapped + virtual u16 readProgramWord(u32 address) { + u8* dspRam = getDspMemory(); + + auto readByte = [&](u32 addr) { + if (addr >= 256_KB) return u8(0); + return dspRam[addr]; + }; + + u16 lsb = u16(readByte(address)); + u16 msb = u16(readByte(address + 1)); + return u16(lsb | (msb << 8)); + } }; std::unique_ptr makeDSPCore(EmulatorConfig& config, Memory& mem, Scheduler& scheduler, DSPService& dspService); diff --git a/include/audio/teakra_core.hpp b/include/audio/teakra_core.hpp index 9fd6a02c..46cf7c00 100644 --- a/include/audio/teakra_core.hpp +++ b/include/audio/teakra_core.hpp @@ -92,6 +92,7 @@ namespace Audio { u8* getDspMemory() override { return teakra.GetDspMemory().data(); } void* getRegisters() override; DSPCore::Type getType() override { return DSPCore::Type::Teakra; } + u16 readProgramWord(u32 address) override { return teakra.ProgramRead(address); } u16 recvData(u32 regId) override { return teakra.RecvData(regId); } bool recvDataIsReady(u32 regId) override { return teakra.RecvDataIsReady(regId); } diff --git a/include/panda_qt/dsp_debugger.hpp b/include/panda_qt/dsp_debugger.hpp index 72b4f884..e0067690 100644 --- a/include/panda_qt/dsp_debugger.hpp +++ b/include/panda_qt/dsp_debugger.hpp @@ -5,7 +5,6 @@ #include #include -#include "capstone.hpp" #include "emulator.hpp" #include "panda_qt/disabled_widget_overlay.hpp" @@ -20,10 +19,10 @@ class DSPDebugger : public QWidget { QLineEdit* addressInput; DisabledWidgetOverlay* disabledOverlay; + DisabledWidgetOverlay* disabledRegisterEditOverlay; bool enabled = false; bool followPC = false; - Common::CapstoneDisassembler disassembler; public: DSPDebugger(Emulator* emulator, QWidget* parent = nullptr); diff --git a/src/panda_qt/cpu_debugger.cpp b/src/panda_qt/cpu_debugger.cpp index 6a2aebab..61730c53 100644 --- a/src/panda_qt/cpu_debugger.cpp +++ b/src/panda_qt/cpu_debugger.cpp @@ -69,7 +69,7 @@ CPUDebugger::CPUDebugger(Emulator* emulator, QWidget* parent) : emu(emulator), d // Setup overlay for when the widget is disabled disabledOverlay = new DisabledWidgetOverlay(this, tr("Pause the emulator to use the CPU Debugger")); - disabledOverlay->resize(size()); // Fill the whole screen + disabledOverlay->resize(size()); // Fill the whole widget disabledOverlay->raise(); disabledOverlay->hide(); diff --git a/src/panda_qt/dsp_debugger.cpp b/src/panda_qt/dsp_debugger.cpp index 7d44cc1c..3cb1c0fa 100644 --- a/src/panda_qt/dsp_debugger.cpp +++ b/src/panda_qt/dsp_debugger.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include "audio/dsp_core.hpp" @@ -35,7 +34,7 @@ static std::pair getVisibleLineRange(QListWidget* listWidget, QScrollB return {firstLine, lineCount}; } -DSPDebugger::DSPDebugger(Emulator* emulator, QWidget* parent) : emu(emulator), disassembler(CS_ARCH_ARM, CS_MODE_ARM), QWidget(parent, Qt::Window) { +DSPDebugger::DSPDebugger(Emulator* emulator, QWidget* parent) : emu(emulator), QWidget(parent, Qt::Window) { setWindowTitle(tr("DSP debugger")); resize(1000, 600); @@ -74,12 +73,18 @@ DSPDebugger::DSPDebugger(Emulator* emulator, QWidget* parent) : emu(emulator), d registerTextEdit->setMaximumWidth(800); gridLayout->addWidget(registerTextEdit, 1, 2); - // Setup overlay for when the widget is disabled + // Setup overlay for when the debugger is disabled disabledOverlay = new DisabledWidgetOverlay(this, tr("Pause the emulator to use the DSP Debugger")); - disabledOverlay->resize(size()); // Fill the whole screen + disabledOverlay->resize(size()); // Fill the whole widget disabledOverlay->raise(); disabledOverlay->hide(); + // Setup overlay for when the register widget is disabled + disabledRegisterEditOverlay = new DisabledWidgetOverlay(registerTextEdit, tr("Register view is only supported\nwith LLE DSP")); + disabledRegisterEditOverlay->resize(registerTextEdit->size()); + disabledRegisterEditOverlay->raise(); + disabledRegisterEditOverlay->hide(); + // Use a monospace font for the disassembly to align it QFont mono_font = QFont("Courier New"); mono_font.setStyleHint(QFont::Monospace); @@ -155,21 +160,10 @@ void DSPDebugger::updateDisasm() { disasmListWidget->clear(); auto [firstLine, lineCount] = getVisibleLineRange(disasmListWidget, verticalScrollBar); - const u32 startPC = (firstLine + 1) & ~1; // Align PC to 2 bytes + const u32 startPC = firstLine; - auto DSP = emu->getDSP(); - auto dspRam = DSP->getDspMemory(); - auto readByte = [&](u32 addr) { - if (addr >= 256_KB) return u8(0); - - return dspRam[addr]; - }; - - auto readWord = [&](u32 addr) { - u16 lsb = u16(readByte(addr)); - u16 msb = u16(readByte(addr + 1)); - return u16(lsb | (msb << 8)); - }; + auto dsp = emu->getDSP(); + auto dspRam = dsp->getDspMemory(); auto& mem = emu->getMemory(); u32 pc = getPC(); @@ -177,10 +171,10 @@ void DSPDebugger::updateDisasm() { std::string disassembly; for (u32 addr = startPC, instructionCount = 0; instructionCount < lineCount; instructionCount++) { - const u16 instruction = readWord(addr); + const u16 instruction = dsp->readProgramWord(addr); const bool needExpansion = Teakra::Disassembler::NeedExpansion(instruction); - const u16 expansion = needExpansion ? readWord(addr + 2) : u16(0); + const u16 expansion = needExpansion ? dsp->readProgramWord(addr + 2) : u16(0); std::string disassembly = Teakra::Disassembler::Do(instruction, expansion); disassembly = fmt::format("{:08X} | {}", addr, disassembly); @@ -199,11 +193,11 @@ void DSPDebugger::updateDisasm() { // This is only supported on the Teakra core, as other cores don't actually have a register contexts u32 DSPDebugger::getPC() { - auto DSP = emu->getDSP(); - auto dspType = DSP->getType(); + auto dsp = emu->getDSP(); + auto dspType = dsp->getType(); if (dspType == Audio::DSPCore::Type::Teakra) { - auto regs = (Teakra::RegisterState*)DSP->getRegisters(); + auto regs = (Teakra::RegisterState*)dsp->getRegisters(); return regs->pc | (u32(regs->prpage) << 18); } else { return 0; @@ -215,7 +209,52 @@ void DSPDebugger::scrollToPC() { verticalScrollBar->setValue(pc); } -void DSPDebugger::updateRegisters() { registerTextEdit->setPlainText(QString::fromStdString("")); } +void DSPDebugger::updateRegisters() { + auto dsp = emu->getDSP(); + auto dspType = dsp->getType(); + + if (dspType == Audio::DSPCore::Type::Teakra) { + std::string text = ""; + text.reserve(4096); + + auto regs = (Teakra::RegisterState*)dsp->getRegisters(); + text += fmt::format( + "PC: 0x{:05X}\nProgram Page: 0x{:01X}\nStack Pointer: 0x{:04X}\n", regs->pc & 0x3FFFF, regs->prpage & 0xF, regs->sp + ); + + text += "\nGeneral Purpose Registers\n"; + for (int i = 0; i < 8; i++) { + text += fmt::format("r{:01d}: 0x{:08X}\n", i, regs->r[i]); + } + + text += "\nAccumulators (40-bit)\n"; + text += fmt::format("a0: 0x{:010X}\n", regs->a[0] & 0xFFFFFFFFFFull); + text += fmt::format("a1: 0x{:010X}\n", regs->a[1] & 0xFFFFFFFFFFull); + text += fmt::format("b0: 0x{:010X}\n", regs->b[0] & 0xFFFFFFFFFFull); + text += fmt::format("b1: 0x{:010X}\n", regs->b[1] & 0xFFFFFFFFFFull); + text += fmt::format("a1s: 0x{:010X}\n", regs->a1s & 0xFFFFFFFFFFull); + text += fmt::format("b1s: 0x{:010X}\n", regs->b1s & 0xFFFFFFFFFFull); + + text += "\nMultiplication Unit\n"; + text += fmt::format("x0: 0x{:04X}\n", regs->x[0]); + text += fmt::format("x1: 0x{:04X}\n", regs->x[1]); + text += fmt::format("y0: 0x{:04X}\n", regs->y[0]); + text += fmt::format("y1: 0x{:04X}\n", regs->y[1]); + text += fmt::format("p0: 0x{:08X}\n", regs->p[0]); + text += fmt::format("p1: 0x{:08X}\n", regs->p[1]); + + text += "\nOther Registers\n"; + text += fmt::format("mixp: 0x{:04X}\n", regs->mixp); + text += fmt::format("sv: 0x{:04X}\n", regs->sv); + text += fmt::format("Shift mode: {}\n", regs->s ? "Logic" : "Arithmetic"); + + registerTextEdit->setPlainText(QString::fromStdString(text)); + disabledRegisterEditOverlay->hide(); + } else { + registerTextEdit->setPlainText(QString::fromStdString("")); + disabledRegisterEditOverlay->show(); + } +} bool DSPDebugger::eventFilter(QObject* obj, QEvent* event) { // Forward scroll events from the list widget to the scrollbar @@ -255,7 +294,8 @@ void DSPDebugger::keyPressEvent(QKeyEvent* event) { void DSPDebugger::resizeEvent(QResizeEvent* event) { QWidget::resizeEvent(event); disabledOverlay->resize(event->size()); - verticalScrollBar->setPageStep(getLinesInViewport(disasmListWidget)); + disabledRegisterEditOverlay->resize(registerTextEdit->size()); + verticalScrollBar->setPageStep(getLinesInViewport(disasmListWidget)); update(); } \ No newline at end of file diff --git a/third_party/teakra b/third_party/teakra index 01db7cdd..e34a8679 160000 --- a/third_party/teakra +++ b/third_party/teakra @@ -1 +1 @@ -Subproject commit 01db7cdd00aabcce559a8dddce8798dabb71949b +Subproject commit e34a86799efd65e3c44b915a4d65b3514d34df4f