Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 119 additions & 1 deletion gui/qt/debugger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ void MainWindow::debugStep(int mode) {
} else {
disasm.base = static_cast<int32_t>(cpu.registers.PC);
disasmGet(true);

m_stepCtx.active = true;
m_stepCtx.seqNext = static_cast<uint32_t>(disasm.next);
debug_step(mode, static_cast<uint32_t>(disasm.next));
}
emu.resume();
Expand Down Expand Up @@ -392,6 +395,7 @@ void MainWindow::debugCommand(int reason, uint32_t data) {

if (reason == DBG_READY) {
guiReset = false;
navDisasmClear();
emu.resume();
return;
}
Expand Down Expand Up @@ -850,6 +854,17 @@ void MainWindow::debugPopulate() {
osUpdate();
stackUpdate();
disasmUpdateAddr(m_prevDisasmAddr = cpu.registers.PC, true);
// Track step navigation: append on control-flow (branch taken),
// replace on linear advance. Non-step stops do not modify history
if (m_stepCtx.active) {
bool tookBranch = (static_cast<uint32_t>(cpu.registers.PC) != m_stepCtx.seqNext);
if (tookBranch) {
navDisasmPush(m_prevDisasmAddr, true);
} else {
navDisasmReplace(m_prevDisasmAddr, true);
}
m_stepCtx.active = false;
}

memUpdate();

Expand Down Expand Up @@ -1964,6 +1979,98 @@ void MainWindow::disasmUpdateAddr(int base, bool pane) {
connect(m_disasm->verticalScrollBar(), &QScrollBar::valueChanged, this, &MainWindow::disasmScroll);
}

// ------------------------------------------------
// Disassembly navigation history helpers
// ------------------------------------------------

uint32_t MainWindow::currentDisasmAddress() const {
if (m_prevDisasmAddr) {
return m_prevDisasmAddr;
}
QString sel = m_disasm ? m_disasm->getSelectedAddr() : QString();
if (!sel.isEmpty()) {
return static_cast<uint32_t>(hex2int(sel));
}
return cpu.registers.PC;
}

void MainWindow::navDisasmEnsureSeeded() {
if (m_disasmNavIndex == -1) {
m_disasmNav.reserve(kMaxDisasmHistory);
// seed with the last PC location and current pane mode so that fully backing out returns to the same stop context
m_disasmNav.push_back({ currentDisasmAddress(), m_disasmPane });
m_disasmNavIndex = 0;
}
}

void MainWindow::navDisasmPush(uint32_t addr, bool pane) {
if (m_isApplyingDisasmNav) {
disasmUpdateAddr(static_cast<int>(addr), pane);
return;
}
if (m_disasmNavIndex >= 0 && m_disasmNavIndex < m_disasmNav.size()) {
const DisasmNavEntry &cur = m_disasmNav[m_disasmNavIndex];
if (cur.addr == addr && cur.pane == pane) {
disasmUpdateAddr(static_cast<int>(addr), pane);
return;
}
}
if (m_disasmNavIndex + 1 < m_disasmNav.size()) {
m_disasmNav.resize(m_disasmNavIndex + 1);
}
if (m_disasmNav.size() >= kMaxDisasmHistory) {
m_disasmNav.remove(0);
if (m_disasmNavIndex > 0) { --m_disasmNavIndex; }
}
m_disasmNav.push_back({addr, pane});
m_disasmNavIndex = m_disasmNav.size() - 1;
m_isApplyingDisasmNav = true;
disasmUpdateAddr(static_cast<int>(addr), pane);
m_isApplyingDisasmNav = false;
}

void MainWindow::navDisasmReplace(uint32_t addr, bool pane) {
if (m_isApplyingDisasmNav) {
return;
}
navDisasmEnsureSeeded();
if (m_disasmNavIndex < 0) {
m_disasmNav.push_back({addr, pane});
m_disasmNavIndex = m_disasmNav.size() - 1;
} else {
m_disasmNav[m_disasmNavIndex] = {addr, pane};
}
}

bool MainWindow::navDisasmBack() {
if (m_disasmNavIndex > 0) {
--m_disasmNavIndex;
const auto &e = m_disasmNav[m_disasmNavIndex];
m_isApplyingDisasmNav = true;
disasmUpdateAddr(static_cast<int>(e.addr), e.pane);
m_isApplyingDisasmNav = false;
return true;
}
return false;
}

bool MainWindow::navDisasmForward() {
if (m_disasmNavIndex >= 0 && m_disasmNavIndex + 1 < m_disasmNav.size()) {
++m_disasmNavIndex;
const auto &e = m_disasmNav[m_disasmNavIndex];
m_isApplyingDisasmNav = true;
disasmUpdateAddr(static_cast<int>(e.addr), e.pane);
m_isApplyingDisasmNav = false;
return true;
}
return false;
}

void MainWindow::navDisasmClear() {
m_disasmNav.clear();
m_disasmNavIndex = -1;
}

// ------------------------------------------------
// Misc
// ------------------------------------------------
Expand Down Expand Up @@ -1993,7 +2100,8 @@ void MainWindow::gotoPressed() {
}

void MainWindow::gotoDisasmAddr(uint32_t address) {
disasmUpdateAddr(address, false);
navDisasmEnsureSeeded();
navDisasmPush(address, false);
raiseContainingDock(ui->disasm);
ui->disasm->setFocus();
}
Expand Down Expand Up @@ -2111,6 +2219,16 @@ bool MainWindow::eventFilter(QObject *obj, QEvent *e) {
return QMainWindow::eventFilter(obj, e);
}

// Mouse back/forward in Disassembly view
if (obj == m_disasm && e->type() == QEvent::MouseButtonPress) {
auto *me = static_cast<QMouseEvent*>(e);
if (me->button() == Qt::BackButton) {
if (navDisasmBack()) { e->accept(); return true; }
} else if (me->button() == Qt::ForwardButton) {
if (navDisasmForward()) { e->accept(); return true; }
}
}

if (e->type() == QEvent::MouseButtonPress) {
QString name = obj->objectName();

Expand Down
17 changes: 16 additions & 1 deletion gui/qt/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@
m_breakpoints = ui->breakpoints;
m_ports = ui->ports;
m_disasm = ui->disasm;
m_disasm->installEventFilter(this);

ui->console->setMaximumBlockCount(1000);

Expand Down Expand Up @@ -158,9 +159,9 @@

// debug actions
connect(ui->buttonRun, &QPushButton::clicked, this, &MainWindow::debugToggle);
connect(ui->checkADLDisasm, &QCheckBox::stateChanged, this, &MainWindow::disasmUpdate);

Check warning on line 162 in gui/qt/mainwindow.cpp

View workflow job for this annotation

GitHub Actions / Build: ubuntu-22.04 - x64

‘void QCheckBox::stateChanged(int)’ is deprecated: Use checkStateChanged() instead [-Wdeprecated-declarations]

Check warning on line 162 in gui/qt/mainwindow.cpp

View workflow job for this annotation

GitHub Actions / Build: ubuntu-22.04 - x64-Dynamic

‘void QCheckBox::stateChanged(int)’ is deprecated: Use checkStateChanged() instead [-Wdeprecated-declarations]
connect(ui->checkADLStack, &QCheckBox::stateChanged, this, &MainWindow::stackUpdate);

Check warning on line 163 in gui/qt/mainwindow.cpp

View workflow job for this annotation

GitHub Actions / Build: ubuntu-22.04 - x64

‘void QCheckBox::stateChanged(int)’ is deprecated: Use checkStateChanged() instead [-Wdeprecated-declarations]

Check warning on line 163 in gui/qt/mainwindow.cpp

View workflow job for this annotation

GitHub Actions / Build: ubuntu-22.04 - x64-Dynamic

‘void QCheckBox::stateChanged(int)’ is deprecated: Use checkStateChanged() instead [-Wdeprecated-declarations]
connect(ui->checkADL, &QCheckBox::stateChanged, [this]{ disasmUpdate(); stackUpdate(); });

Check warning on line 164 in gui/qt/mainwindow.cpp

View workflow job for this annotation

GitHub Actions / Build: ubuntu-22.04 - x64

‘void QCheckBox::stateChanged(int)’ is deprecated: Use checkStateChanged() instead [-Wdeprecated-declarations]

Check warning on line 164 in gui/qt/mainwindow.cpp

View workflow job for this annotation

GitHub Actions / Build: ubuntu-22.04 - x64-Dynamic

‘void QCheckBox::stateChanged(int)’ is deprecated: Use checkStateChanged() instead [-Wdeprecated-declarations]
connect(ui->buttonAddPort, &QPushButton::clicked, this, &MainWindow::portAddSlot);
connect(ui->buttonAddBreakpoint, &QPushButton::clicked, this, &MainWindow::breakAddSlot);
connect(ui->buttonAddWatchpoint, &QPushButton::clicked, this, &MainWindow::watchAddSlot);
Expand Down Expand Up @@ -375,7 +376,7 @@
#ifdef PNG_WRITE_APNG_SUPPORTED
connect(ui->buttonRecordAnimated, &QPushButton::clicked, this, &MainWindow::recordAnimated);
connect(ui->apngSkip, &QSlider::valueChanged, this, &MainWindow::setFrameskip);
connect(ui->checkOptimizeRecording, &QCheckBox::stateChanged, this, &MainWindow::setOptimizeRecord);

Check warning on line 379 in gui/qt/mainwindow.cpp

View workflow job for this annotation

GitHub Actions / Build: ubuntu-22.04 - x64

‘void QCheckBox::stateChanged(int)’ is deprecated: Use checkStateChanged() instead [-Wdeprecated-declarations]

Check warning on line 379 in gui/qt/mainwindow.cpp

View workflow job for this annotation

GitHub Actions / Build: ubuntu-22.04 - x64-Dynamic

‘void QCheckBox::stateChanged(int)’ is deprecated: Use checkStateChanged() instead [-Wdeprecated-declarations]
#else
ui->actionRecordAnimated->setEnabled(false);
ui->buttonRecordAnimated->setEnabled(false);
Expand All @@ -390,13 +391,13 @@
connect(ui->actionReportBug, &QAction::triggered, []{ QDesktopServices::openUrl(QUrl("https://github.com/CE-Programming/CEmu/issues")); });

// other gui actions
connect(ui->checkAllowGroupDrag, &QCheckBox::stateChanged, this, &MainWindow::setDockGroupDrag);

Check warning on line 394 in gui/qt/mainwindow.cpp

View workflow job for this annotation

GitHub Actions / Build: ubuntu-22.04 - x64

‘void QCheckBox::stateChanged(int)’ is deprecated: Use checkStateChanged() instead [-Wdeprecated-declarations]

Check warning on line 394 in gui/qt/mainwindow.cpp

View workflow job for this annotation

GitHub Actions / Build: ubuntu-22.04 - x64-Dynamic

‘void QCheckBox::stateChanged(int)’ is deprecated: Use checkStateChanged() instead [-Wdeprecated-declarations]
connect(ui->buttonRunSetup, &QPushButton::clicked, this, &MainWindow::runSetup);
connect(ui->scaleLCD, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &MainWindow::setLcdScale);
connect(ui->upscaleLCD, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &MainWindow::setLcdUpscale);
connect(ui->fullscreenLCD, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &MainWindow::setLcdFullscreen);
connect(ui->guiSkip, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &MainWindow::setGuiSkip);
connect(ui->checkSkin, &QCheckBox::stateChanged, this, &MainWindow::setSkinToggle);

Check warning on line 400 in gui/qt/mainwindow.cpp

View workflow job for this annotation

GitHub Actions / Build: ubuntu-22.04 - x64

‘void QCheckBox::stateChanged(int)’ is deprecated: Use checkStateChanged() instead [-Wdeprecated-declarations]

Check warning on line 400 in gui/qt/mainwindow.cpp

View workflow job for this annotation

GitHub Actions / Build: ubuntu-22.04 - x64-Dynamic

‘void QCheckBox::stateChanged(int)’ is deprecated: Use checkStateChanged() instead [-Wdeprecated-declarations]
connect(ui->comboBoxAsicRev, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, &MainWindow::setAsicRevision);
connect(ui->checkPythonEdition, &QCheckBox::stateChanged, this, &MainWindow::setPythonEdition);
connect(ui->checkKeypadGhosting, &QCheckBox::stateChanged, this, &MainWindow::setKeypadGhosting);
Expand Down Expand Up @@ -518,6 +519,11 @@
m_shortcutStepOver = new QShortcut(QKeySequence(Qt::Key_F7), this);
m_shortcutStepNext = new QShortcut(QKeySequence(Qt::Key_F8), this);
m_shortcutStepOut = new QShortcut(QKeySequence(Qt::Key_F9), this);
m_shortcutNavBack = new QShortcut(QKeySequence(Qt::ALT | Qt::Key_Left), this);
m_shortcutNavForward = new QShortcut(QKeySequence(Qt::ALT | Qt::Key_Right), this);

connect(m_shortcutNavBack, &QShortcut::activated, this, [this]{ navDisasmBack(); });
connect(m_shortcutNavForward, &QShortcut::activated, this, [this]{ navDisasmForward(); });
m_shortcutDebug = new QShortcut(QKeySequence(Qt::Key_F10), this);
m_shortcutFullscreen = new QShortcut(QKeySequence(Qt::Key_F11), this);
m_shortcutAsm = new QShortcut(QKeySequence(Qt::Key_Pause), this);
Expand Down Expand Up @@ -2695,6 +2701,11 @@
uint32_t addr = static_cast<uint32_t>(hex2int(addrStr));

QMenu menu;
QAction *backAct = menu.addAction(tr("Back"));
QAction *fwdAct = menu.addAction(tr("Forward"));
backAct->setEnabled(m_disasmNavIndex > 0);
fwdAct->setEnabled(m_disasmNavIndex >= 0 && m_disasmNavIndex + 1 < m_disasmNav.size());
menu.addSeparator();
QAction *runUntil = menu.addAction(ACTION_RUN_UNTIL);
menu.addSeparator();
QAction *toggleBreak = menu.addAction(ACTION_TOGGLE_BREAK);
Expand All @@ -2706,7 +2717,11 @@
QAction *setPc = menu.addAction(tr("Set PC"));

QAction *item = menu.exec(globalPos);
if (item == setPc) {
if (item == backAct) {
navDisasmBack();
} else if (item == fwdAct) {
navDisasmForward();
} else if (item == setPc) {
ui->pcregView->setText(addrStr);
debug_set_pc(addr);
disasmUpdateAddr(static_cast<int>(cpu.registers.PC), true);
Expand Down
25 changes: 25 additions & 0 deletions gui/qt/mainwindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,8 @@ private slots:
QShortcut *m_shortcutStepOver;
QShortcut *m_shortcutStepNext;
QShortcut *m_shortcutStepOut;
QShortcut *m_shortcutNavBack;
QShortcut *m_shortcutNavForward;
QShortcut *m_shortcutDebug;
QShortcut *m_shortcutFullscreen;
QShortcut *m_shortcutAsm;
Expand Down Expand Up @@ -937,6 +939,29 @@ private slots:
QTableWidget *m_ports = nullptr;
DataWidget *m_disasm = nullptr;

struct DisasmNavEntry {
uint32_t addr;
bool pane;
};

QVector<DisasmNavEntry> m_disasmNav;
int m_disasmNavIndex = -1;
bool m_isApplyingDisasmNav = false;
static constexpr int kMaxDisasmHistory = 200;

[[nodiscard]] uint32_t currentDisasmAddress() const;
void navDisasmEnsureSeeded();
void navDisasmPush(uint32_t addr, bool pane);
void navDisasmReplace(uint32_t addr, bool pane);
bool navDisasmBack();
bool navDisasmForward();
void navDisasmClear();

struct StepNavCtx {
bool active = false;
uint32_t seqNext = 0; // sequential next PC at step start
} m_stepCtx;

#ifdef LIBUSB_SUPPORT
libusb_context *m_usbContext = nullptr;
libusb_hotplug_callback_handle m_usbHotplugCallbackHandle{};
Expand Down
Loading