mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-07-11 17:58:29 +12:00
Initial DSP debugger work
This commit is contained in:
parent
f4e6a082bb
commit
415bf7b0a4
9 changed files with 309 additions and 5 deletions
|
@ -314,7 +314,7 @@ else()
|
||||||
message(FATAL_ERROR "Currently unsupported CPU architecture")
|
message(FATAL_ERROR "Currently unsupported CPU architecture")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_subdirectory(third_party/teakra EXCLUDE_FROM_ALL)
|
add_subdirectory(third_party/teakra)
|
||||||
add_subdirectory(third_party/fdk-aac)
|
add_subdirectory(third_party/fdk-aac)
|
||||||
|
|
||||||
set(CAPSTONE_ARCHITECTURE_DEFAULT OFF)
|
set(CAPSTONE_ARCHITECTURE_DEFAULT OFF)
|
||||||
|
@ -686,8 +686,8 @@ set(ALL_SOURCES ${SOURCE_FILES} ${FS_SOURCE_FILES} ${CRYPTO_SOURCE_FILES} ${KERN
|
||||||
${AUDIO_SOURCE_FILES} ${HEADER_FILES} ${FRONTEND_HEADER_FILES})
|
${AUDIO_SOURCE_FILES} ${HEADER_FILES} ${FRONTEND_HEADER_FILES})
|
||||||
target_sources(AlberCore PRIVATE ${ALL_SOURCES})
|
target_sources(AlberCore PRIVATE ${ALL_SOURCES})
|
||||||
|
|
||||||
target_link_libraries(AlberCore PRIVATE dynarmic glad resources_console_fonts teakra fdk-aac)
|
target_link_libraries(AlberCore PRIVATE dynarmic glad resources_console_fonts fdk-aac)
|
||||||
target_link_libraries(AlberCore PUBLIC glad capstone fmt::fmt)
|
target_link_libraries(AlberCore PUBLIC glad capstone fmt::fmt teakra)
|
||||||
|
|
||||||
if(ENABLE_DISCORD_RPC AND NOT ANDROID)
|
if(ENABLE_DISCORD_RPC AND NOT ANDROID)
|
||||||
target_compile_definitions(AlberCore PUBLIC "PANDA3DS_ENABLE_DISCORD_RPC=1")
|
target_compile_definitions(AlberCore PUBLIC "PANDA3DS_ENABLE_DISCORD_RPC=1")
|
||||||
|
@ -733,12 +733,13 @@ if(NOT BUILD_HYDRA_CORE AND NOT BUILD_LIBRETRO_CORE)
|
||||||
set(FRONTEND_SOURCE_FILES src/panda_qt/main.cpp src/panda_qt/screen.cpp src/panda_qt/main_window.cpp src/panda_qt/about_window.cpp
|
set(FRONTEND_SOURCE_FILES src/panda_qt/main.cpp src/panda_qt/screen.cpp src/panda_qt/main_window.cpp src/panda_qt/about_window.cpp
|
||||||
src/panda_qt/config_window.cpp src/panda_qt/zep.cpp src/panda_qt/text_editor.cpp src/panda_qt/cheats_window.cpp src/panda_qt/mappings.cpp
|
src/panda_qt/config_window.cpp src/panda_qt/zep.cpp src/panda_qt/text_editor.cpp src/panda_qt/cheats_window.cpp src/panda_qt/mappings.cpp
|
||||||
src/panda_qt/patch_window.cpp src/panda_qt/elided_label.cpp src/panda_qt/shader_editor.cpp src/panda_qt/translations.cpp
|
src/panda_qt/patch_window.cpp src/panda_qt/elided_label.cpp src/panda_qt/shader_editor.cpp src/panda_qt/translations.cpp
|
||||||
src/panda_qt/thread_debugger.cpp src/panda_qt/cpu_debugger.cpp
|
src/panda_qt/thread_debugger.cpp src/panda_qt/cpu_debugger.cpp src/panda_qt/dsp_debugger.cpp
|
||||||
)
|
)
|
||||||
set(FRONTEND_HEADER_FILES include/panda_qt/screen.hpp include/panda_qt/main_window.hpp include/panda_qt/about_window.hpp
|
set(FRONTEND_HEADER_FILES include/panda_qt/screen.hpp include/panda_qt/main_window.hpp include/panda_qt/about_window.hpp
|
||||||
include/panda_qt/config_window.hpp include/panda_qt/text_editor.hpp include/panda_qt/cheats_window.hpp
|
include/panda_qt/config_window.hpp include/panda_qt/text_editor.hpp include/panda_qt/cheats_window.hpp
|
||||||
include/panda_qt/patch_window.hpp include/panda_qt/elided_label.hpp include/panda_qt/shader_editor.hpp
|
include/panda_qt/patch_window.hpp include/panda_qt/elided_label.hpp include/panda_qt/shader_editor.hpp
|
||||||
include/panda_qt/thread_debugger.hpp include/panda_qt/cpu_debugger.hpp include/panda_qt/disabled_widget_overlay.hpp
|
include/panda_qt/thread_debugger.hpp include/panda_qt/cpu_debugger.hpp include/panda_qt/dsp_debugger.hpp
|
||||||
|
include/panda_qt/disabled_widget_overlay.hpp
|
||||||
)
|
)
|
||||||
|
|
||||||
source_group("Source Files\\Qt" FILES ${FRONTEND_SOURCE_FILES})
|
source_group("Source Files\\Qt" FILES ${FRONTEND_SOURCE_FILES})
|
||||||
|
|
|
@ -63,6 +63,8 @@ namespace Audio {
|
||||||
|
|
||||||
Samples& getSamples() { return sampleBuffer; }
|
Samples& getSamples() { return sampleBuffer; }
|
||||||
virtual void setAudioEnabled(bool enable) { audioEnabled = enable; }
|
virtual void setAudioEnabled(bool enable) { audioEnabled = enable; }
|
||||||
|
|
||||||
|
virtual u32 getPC() { return 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<DSPCore> makeDSPCore(EmulatorConfig& config, Memory& mem, Scheduler& scheduler, DSPService& dspService);
|
std::unique_ptr<DSPCore> makeDSPCore(EmulatorConfig& config, Memory& mem, Scheduler& scheduler, DSPService& dspService);
|
||||||
|
|
|
@ -90,6 +90,7 @@ namespace Audio {
|
||||||
|
|
||||||
void setAudioEnabled(bool enable) override;
|
void setAudioEnabled(bool enable) override;
|
||||||
u8* getDspMemory() override { return teakra.GetDspMemory().data(); }
|
u8* getDspMemory() override { return teakra.GetDspMemory().data(); }
|
||||||
|
u32 getPC() override;
|
||||||
|
|
||||||
u16 recvData(u32 regId) override { return teakra.RecvData(regId); }
|
u16 recvData(u32 regId) override { return teakra.RecvData(regId); }
|
||||||
bool recvDataIsReady(u32 regId) override { return teakra.RecvDataIsReady(regId); }
|
bool recvDataIsReady(u32 regId) override { return teakra.RecvDataIsReady(regId); }
|
||||||
|
|
|
@ -126,6 +126,7 @@ class Emulator {
|
||||||
Memory& getMemory() { return memory; }
|
Memory& getMemory() { return memory; }
|
||||||
Kernel& getKernel() { return kernel; }
|
Kernel& getKernel() { return kernel; }
|
||||||
Scheduler& getScheduler() { return scheduler; }
|
Scheduler& getScheduler() { return scheduler; }
|
||||||
|
Audio::DSPCore* getDSP() { return dsp.get(); }
|
||||||
|
|
||||||
EmulatorConfig& getConfig() { return config; }
|
EmulatorConfig& getConfig() { return config; }
|
||||||
Cheats& getCheats() { return cheats; }
|
Cheats& getCheats() { return cheats; }
|
||||||
|
|
45
include/panda_qt/dsp_debugger.hpp
Normal file
45
include/panda_qt/dsp_debugger.hpp
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#pragma once
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QListWidget>
|
||||||
|
#include <QPlainTextEdit>
|
||||||
|
#include <QScrollBar>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
#include "capstone.hpp"
|
||||||
|
#include "emulator.hpp"
|
||||||
|
#include "panda_qt/disabled_widget_overlay.hpp"
|
||||||
|
|
||||||
|
class DSPDebugger : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
Emulator* emu;
|
||||||
|
|
||||||
|
QListWidget* disasmListWidget;
|
||||||
|
QScrollBar* verticalScrollBar;
|
||||||
|
QPlainTextEdit* registerTextEdit;
|
||||||
|
QTimer* updateTimer;
|
||||||
|
QLineEdit* addressInput;
|
||||||
|
|
||||||
|
DisabledWidgetOverlay* disabledOverlay;
|
||||||
|
|
||||||
|
bool enabled = false;
|
||||||
|
bool followPC = false;
|
||||||
|
Common::CapstoneDisassembler disassembler;
|
||||||
|
|
||||||
|
public:
|
||||||
|
DSPDebugger(Emulator* emulator, QWidget* parent = nullptr);
|
||||||
|
void enable();
|
||||||
|
void disable();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Update the state of the disassembler. Qt events should always call update, not updateDisasm/updateRegister
|
||||||
|
// As update properly handles thread safety
|
||||||
|
void update();
|
||||||
|
void updateDisasm();
|
||||||
|
void updateRegisters();
|
||||||
|
void scrollToPC();
|
||||||
|
|
||||||
|
bool eventFilter(QObject* obj, QEvent* event) override;
|
||||||
|
void showEvent(QShowEvent* event) override;
|
||||||
|
void resizeEvent(QResizeEvent* event) override;
|
||||||
|
void keyPressEvent(QKeyEvent* event) override;
|
||||||
|
};
|
|
@ -18,6 +18,7 @@
|
||||||
#include "panda_qt/cheats_window.hpp"
|
#include "panda_qt/cheats_window.hpp"
|
||||||
#include "panda_qt/config_window.hpp"
|
#include "panda_qt/config_window.hpp"
|
||||||
#include "panda_qt/cpu_debugger.hpp"
|
#include "panda_qt/cpu_debugger.hpp"
|
||||||
|
#include "panda_qt/dsp_debugger.hpp"
|
||||||
#include "panda_qt/patch_window.hpp"
|
#include "panda_qt/patch_window.hpp"
|
||||||
#include "panda_qt/screen.hpp"
|
#include "panda_qt/screen.hpp"
|
||||||
#include "panda_qt/shader_editor.hpp"
|
#include "panda_qt/shader_editor.hpp"
|
||||||
|
@ -112,6 +113,7 @@ class MainWindow : public QMainWindow {
|
||||||
PatchWindow* patchWindow;
|
PatchWindow* patchWindow;
|
||||||
ShaderEditorWindow* shaderEditor;
|
ShaderEditorWindow* shaderEditor;
|
||||||
CPUDebugger* cpuDebugger;
|
CPUDebugger* cpuDebugger;
|
||||||
|
DSPDebugger* dspDebugger;
|
||||||
ThreadDebugger* threadDebugger;
|
ThreadDebugger* threadDebugger;
|
||||||
|
|
||||||
// We use SDL's game controller API since it's the sanest API that supports as many controllers as possible
|
// We use SDL's game controller API since it's the sanest API that supports as many controllers as possible
|
||||||
|
|
|
@ -7,6 +7,10 @@
|
||||||
|
|
||||||
#include "services/dsp.hpp"
|
#include "services/dsp.hpp"
|
||||||
|
|
||||||
|
#undef Assert
|
||||||
|
#undef UNREACHABLE
|
||||||
|
#include "teakra/impl/register.h"
|
||||||
|
|
||||||
using namespace Audio;
|
using namespace Audio;
|
||||||
|
|
||||||
struct Dsp1 {
|
struct Dsp1 {
|
||||||
|
@ -343,3 +347,5 @@ void TeakraDSP::unloadComponent() {
|
||||||
teakra.RecvData(2);
|
teakra.RecvData(2);
|
||||||
running = false;
|
running = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 TeakraDSP::getPC() { return teakra.GetRegisterState().pc; }
|
242
src/panda_qt/dsp_debugger.cpp
Normal file
242
src/panda_qt/dsp_debugger.cpp
Normal file
|
@ -0,0 +1,242 @@
|
||||||
|
#include "panda_qt/dsp_debugger.hpp"
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QGridLayout>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QListWidget>
|
||||||
|
#include <QPlainTextEdit>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <limits>
|
||||||
|
#include <span>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "teakra/disassembler.h"
|
||||||
|
|
||||||
|
// TODO: Make this actually thread-safe by having it only work when paused
|
||||||
|
static int getLinesInViewport(QListWidget* listWidget) {
|
||||||
|
auto viewportHeight = listWidget->viewport()->height();
|
||||||
|
QFontMetrics fm = QFontMetrics(listWidget->font());
|
||||||
|
auto lineHeight = fm.height();
|
||||||
|
|
||||||
|
return int(viewportHeight / lineHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::pair<int, int> getVisibleLineRange(QListWidget* listWidget, QScrollBar* scrollBar) {
|
||||||
|
int firstLine = scrollBar->value();
|
||||||
|
int lineCount = getLinesInViewport(listWidget);
|
||||||
|
|
||||||
|
return {firstLine, lineCount};
|
||||||
|
}
|
||||||
|
|
||||||
|
DSPDebugger::DSPDebugger(Emulator* emulator, QWidget* parent) : emu(emulator), disassembler(CS_ARCH_ARM, CS_MODE_ARM), QWidget(parent, Qt::Window) {
|
||||||
|
setWindowTitle(tr("DSP debugger"));
|
||||||
|
resize(1000, 600);
|
||||||
|
|
||||||
|
QGridLayout* gridLayout = new QGridLayout(this);
|
||||||
|
QHBoxLayout* horizontalLayout = new QHBoxLayout();
|
||||||
|
|
||||||
|
// Set up the top line widgets
|
||||||
|
QPushButton* goToAddressButton = new QPushButton(tr("Go to address"), this);
|
||||||
|
QPushButton* goToPCButton = new QPushButton(tr("Go to PC"), this);
|
||||||
|
QCheckBox* followPCCheckBox = new QCheckBox(tr("Follow PC"), this);
|
||||||
|
addressInput = new QLineEdit(this);
|
||||||
|
|
||||||
|
horizontalLayout->addWidget(goToAddressButton);
|
||||||
|
horizontalLayout->addWidget(goToPCButton);
|
||||||
|
horizontalLayout->addWidget(followPCCheckBox);
|
||||||
|
horizontalLayout->addWidget(addressInput);
|
||||||
|
|
||||||
|
followPCCheckBox->setChecked(followPC);
|
||||||
|
connect(followPCCheckBox, &QCheckBox::toggled, this, [&](bool checked) { followPC = checked; });
|
||||||
|
|
||||||
|
addressInput->setPlaceholderText(tr("Address to jump to"));
|
||||||
|
addressInput->setMaximumWidth(150);
|
||||||
|
|
||||||
|
gridLayout->addLayout(horizontalLayout, 0, 0);
|
||||||
|
|
||||||
|
// Disassembly list on the left, scrollbar in the middle, register view on the right
|
||||||
|
disasmListWidget = new QListWidget(this);
|
||||||
|
gridLayout->addWidget(disasmListWidget, 1, 0);
|
||||||
|
|
||||||
|
verticalScrollBar = new QScrollBar(Qt::Vertical, this);
|
||||||
|
gridLayout->addWidget(verticalScrollBar, 1, 1);
|
||||||
|
|
||||||
|
registerTextEdit = new QPlainTextEdit(this);
|
||||||
|
registerTextEdit->setEnabled(true);
|
||||||
|
registerTextEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
registerTextEdit->setMaximumWidth(800);
|
||||||
|
gridLayout->addWidget(registerTextEdit, 1, 2);
|
||||||
|
|
||||||
|
// Setup overlay for when the widget is disabled
|
||||||
|
disabledOverlay = new DisabledWidgetOverlay(this, tr("Pause the emulator to use the DSP Debugger"));
|
||||||
|
disabledOverlay->resize(size()); // Fill the whole screen
|
||||||
|
disabledOverlay->raise();
|
||||||
|
disabledOverlay->hide();
|
||||||
|
|
||||||
|
// Use a monospace font for the disassembly to align it
|
||||||
|
QFont mono_font = QFont("Courier New");
|
||||||
|
mono_font.setStyleHint(QFont::Monospace);
|
||||||
|
disasmListWidget->setFont(mono_font);
|
||||||
|
registerTextEdit->setFont(mono_font);
|
||||||
|
|
||||||
|
// Forward scrolling from the list widget to our scrollbar
|
||||||
|
disasmListWidget->installEventFilter(this);
|
||||||
|
|
||||||
|
// Annoyingly, due to a Qt limitation we can't set it to U32_MAX
|
||||||
|
verticalScrollBar->setRange(0, std::numeric_limits<s32>::max());
|
||||||
|
verticalScrollBar->setSingleStep(8);
|
||||||
|
verticalScrollBar->setPageStep(getLinesInViewport(disasmListWidget));
|
||||||
|
verticalScrollBar->show();
|
||||||
|
connect(verticalScrollBar, &QScrollBar::valueChanged, this, &DSPDebugger::updateDisasm);
|
||||||
|
registerTextEdit->setReadOnly(true);
|
||||||
|
|
||||||
|
connect(goToPCButton, &QPushButton::clicked, this, [&]() { scrollToPC(); });
|
||||||
|
|
||||||
|
// We have a QTimer that triggers every 500ms to update our widget when it's active
|
||||||
|
updateTimer = new QTimer(this);
|
||||||
|
connect(updateTimer, &QTimer::timeout, this, &DSPDebugger::update);
|
||||||
|
|
||||||
|
// Go to address when the "Go to address" button is pressed, or when we press enter inside the address input box
|
||||||
|
connect(goToAddressButton, &QPushButton::clicked, this, [&]() {
|
||||||
|
QString text = addressInput->text().trimmed();
|
||||||
|
|
||||||
|
bool validAddr = false;
|
||||||
|
u32 addr = text.toUInt(&validAddr, 16); // Parse address as hex
|
||||||
|
if (validAddr) {
|
||||||
|
verticalScrollBar->setValue(addr);
|
||||||
|
} else {
|
||||||
|
addressInput->setText(tr("Invalid hexadecimal address"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
connect(addressInput, &QLineEdit::returnPressed, goToAddressButton, &QPushButton::click);
|
||||||
|
|
||||||
|
disable();
|
||||||
|
hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPDebugger::enable() {
|
||||||
|
enabled = true;
|
||||||
|
|
||||||
|
disabledOverlay->hide();
|
||||||
|
scrollToPC();
|
||||||
|
|
||||||
|
// Update the widget every 500ms
|
||||||
|
updateTimer->start(500);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPDebugger::disable() {
|
||||||
|
enabled = false;
|
||||||
|
|
||||||
|
updateTimer->stop();
|
||||||
|
disabledOverlay->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPDebugger::update() {
|
||||||
|
if (enabled) {
|
||||||
|
if (followPC) {
|
||||||
|
scrollToPC();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDisasm();
|
||||||
|
updateRegisters();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPDebugger::updateDisasm() {
|
||||||
|
int currentRow = disasmListWidget->currentRow();
|
||||||
|
disasmListWidget->clear();
|
||||||
|
|
||||||
|
auto [firstLine, lineCount] = getVisibleLineRange(disasmListWidget, verticalScrollBar);
|
||||||
|
const u32 startPC = (firstLine + 1) & ~1; // Align PC to 2 bytes
|
||||||
|
|
||||||
|
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& mem = emu->getMemory();
|
||||||
|
u32 pc = DSP->getPC();
|
||||||
|
|
||||||
|
std::string disassembly;
|
||||||
|
|
||||||
|
for (u32 addr = startPC, instructionCount = 0; instructionCount < lineCount; instructionCount++) {
|
||||||
|
const u16 instruction = readWord(addr);
|
||||||
|
const bool needExpansion = Teakra::Disassembler::NeedExpansion(instruction);
|
||||||
|
|
||||||
|
const u16 expansion = needExpansion ? readWord(addr + 2) : u16(0);
|
||||||
|
addr += needExpansion ? sizeof(u32) : sizeof(u16);
|
||||||
|
|
||||||
|
std::string disassembly = Teakra::Disassembler::Do(instruction, expansion);
|
||||||
|
disassembly = fmt::format("{:08X} | {}", addr, disassembly);
|
||||||
|
|
||||||
|
QListWidgetItem* item = new QListWidgetItem(QString::fromStdString(disassembly));
|
||||||
|
if (addr == pc) {
|
||||||
|
item->setBackground(Qt::darkGreen);
|
||||||
|
}
|
||||||
|
disasmListWidget->addItem(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
disasmListWidget->setCurrentRow(currentRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPDebugger::scrollToPC() {
|
||||||
|
u32 pc = emu->getDSP()->getPC();
|
||||||
|
verticalScrollBar->setValue(pc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPDebugger::updateRegisters() { registerTextEdit->setPlainText(QString::fromStdString("")); }
|
||||||
|
|
||||||
|
bool DSPDebugger::eventFilter(QObject* obj, QEvent* event) {
|
||||||
|
// Forward scroll events from the list widget to the scrollbar
|
||||||
|
if (obj == disasmListWidget && event->type() == QEvent::Wheel) {
|
||||||
|
QWheelEvent* wheelEvent = (QWheelEvent*)event;
|
||||||
|
|
||||||
|
int wheelSteps = wheelEvent->angleDelta().y() / 60;
|
||||||
|
int newScrollValue = verticalScrollBar->value() - wheelSteps;
|
||||||
|
newScrollValue = qBound(verticalScrollBar->minimum(), newScrollValue, verticalScrollBar->maximum());
|
||||||
|
verticalScrollBar->setValue(newScrollValue);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QWidget::eventFilter(obj, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPDebugger::showEvent(QShowEvent* event) {
|
||||||
|
QWidget::showEvent(event);
|
||||||
|
|
||||||
|
enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scroll 1 instruction up or down when the arrow keys are pressed and we're at the edge of the disassembly list
|
||||||
|
void DSPDebugger::keyPressEvent(QKeyEvent* event) {
|
||||||
|
constexpr usize instructionSize = sizeof(u16);
|
||||||
|
|
||||||
|
if (event->key() == Qt::Key_Up) {
|
||||||
|
verticalScrollBar->setValue(verticalScrollBar->value() - instructionSize);
|
||||||
|
} else if (event->key() == Qt::Key_Down) {
|
||||||
|
verticalScrollBar->setValue(verticalScrollBar->value() + instructionSize);
|
||||||
|
} else {
|
||||||
|
QWidget::keyPressEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DSPDebugger::resizeEvent(QResizeEvent* event) {
|
||||||
|
QWidget::resizeEvent(event);
|
||||||
|
disabledOverlay->resize(event->size());
|
||||||
|
verticalScrollBar->setPageStep(getLinesInViewport(disasmListWidget));
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "cheats.hpp"
|
#include "cheats.hpp"
|
||||||
#include "input_mappings.hpp"
|
#include "input_mappings.hpp"
|
||||||
|
#include "panda_qt/dsp_debugger.hpp"
|
||||||
#include "sdl_sensors.hpp"
|
#include "sdl_sensors.hpp"
|
||||||
#include "services/dsp.hpp"
|
#include "services/dsp.hpp"
|
||||||
#include "version.hpp"
|
#include "version.hpp"
|
||||||
|
@ -67,6 +68,7 @@ MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent)
|
||||||
auto patchWindowAction = toolsMenu->addAction(tr("Open Patch Window"));
|
auto patchWindowAction = toolsMenu->addAction(tr("Open Patch Window"));
|
||||||
auto shaderEditorAction = toolsMenu->addAction(tr("Open Shader Editor"));
|
auto shaderEditorAction = toolsMenu->addAction(tr("Open Shader Editor"));
|
||||||
auto cpuDebuggerAction = toolsMenu->addAction(tr("Open CPU Debugger"));
|
auto cpuDebuggerAction = toolsMenu->addAction(tr("Open CPU Debugger"));
|
||||||
|
auto dspDebuggerAction = toolsMenu->addAction(tr("Open DSP Debugger"));
|
||||||
auto threadDebuggerAction = toolsMenu->addAction(tr("Open Thread Debugger"));
|
auto threadDebuggerAction = toolsMenu->addAction(tr("Open Thread Debugger"));
|
||||||
auto dumpDspFirmware = toolsMenu->addAction(tr("Dump loaded DSP firmware"));
|
auto dumpDspFirmware = toolsMenu->addAction(tr("Dump loaded DSP firmware"));
|
||||||
|
|
||||||
|
@ -76,6 +78,7 @@ MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent)
|
||||||
connect(cheatsEditorAction, &QAction::triggered, this, [this]() { cheatsEditor->show(); });
|
connect(cheatsEditorAction, &QAction::triggered, this, [this]() { cheatsEditor->show(); });
|
||||||
connect(patchWindowAction, &QAction::triggered, this, [this]() { patchWindow->show(); });
|
connect(patchWindowAction, &QAction::triggered, this, [this]() { patchWindow->show(); });
|
||||||
connect(cpuDebuggerAction, &QAction::triggered, this, [this]() { cpuDebugger->show(); });
|
connect(cpuDebuggerAction, &QAction::triggered, this, [this]() { cpuDebugger->show(); });
|
||||||
|
connect(dspDebuggerAction, &QAction::triggered, this, [this]() { dspDebugger->show(); });
|
||||||
connect(threadDebuggerAction, &QAction::triggered, this, [this]() { threadDebugger->show(); });
|
connect(threadDebuggerAction, &QAction::triggered, this, [this]() { threadDebugger->show(); });
|
||||||
connect(dumpDspFirmware, &QAction::triggered, this, &MainWindow::dumpDspFirmware);
|
connect(dumpDspFirmware, &QAction::triggered, this, &MainWindow::dumpDspFirmware);
|
||||||
|
|
||||||
|
@ -97,6 +100,7 @@ MainWindow::MainWindow(QApplication* app, QWidget* parent) : QMainWindow(parent)
|
||||||
shaderEditor = new ShaderEditorWindow(this, "shader.glsl", "");
|
shaderEditor = new ShaderEditorWindow(this, "shader.glsl", "");
|
||||||
threadDebugger = new ThreadDebugger(emu, this);
|
threadDebugger = new ThreadDebugger(emu, this);
|
||||||
cpuDebugger = new CPUDebugger(emu, this);
|
cpuDebugger = new CPUDebugger(emu, this);
|
||||||
|
dspDebugger = new DSPDebugger(emu, this);
|
||||||
|
|
||||||
shaderEditor->setEnable(emu->getRenderer()->supportsShaderReload());
|
shaderEditor->setEnable(emu->getRenderer()->supportsShaderReload());
|
||||||
if (shaderEditor->supported) {
|
if (shaderEditor->supported) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue