diff --git a/sources/Debugger/CPUDebug.cpp b/sources/Debugger/CPUDebug.cpp index cb8392f..eb5bd12 100644 --- a/sources/Debugger/CPUDebug.cpp +++ b/sources/Debugger/CPUDebug.cpp @@ -38,6 +38,7 @@ namespace ComSquare::Debugger QMainWindow::connect(this->_ui.actionPause, &QAction::triggered, this, &CPUDebug::pause); QMainWindow::connect(this->_ui.actionStep, &QAction::triggered, this, &CPUDebug::step); + QMainWindow::connect(this->_ui.actionNext, &QAction::triggered, this, &CPUDebug::next); QMainWindow::connect(this->_ui.clear, &QPushButton::released, this, &CPUDebug::clearHistory); this->_window->show(); this->_updateRegistersPanel(); @@ -56,14 +57,30 @@ namespace ComSquare::Debugger unsigned CPUDebug::update() { try { + unsigned cycles = 0; + if (this->_isPaused) return 0xFF; if (this->_isStepping) { - unsigned ret = this->_executeInstruction(this->readPC()); + cycles = this->_executeInstruction(this->readPC()); this->_updateDisassembly(); - return ret; + return cycles; } - return CPU::update(); + + for (int i = 0; i < 0xFF; i++) { + auto breakpoint = std::find_if(this->breakpoints.begin(), this->breakpoints.end(), [this](Breakpoint &brk) { + return brk.address == this->_registers.pac; + }); + if (i != 0 && breakpoint != this->breakpoints.end()) { + if (breakpoint->oneTime) + this->breakpoints.erase(breakpoint); + this->_isPaused = false; + this->pause(); + return cycles; + } + cycles += this->_executeInstruction(this->readPC()); + } + return cycles; } catch (InvalidOpcode &e) { if (!this->_isPaused) this->pause(); @@ -105,6 +122,15 @@ namespace ComSquare::Debugger this->_isPaused = false; } + void CPUDebug::next() + { + auto next = std::find_if(this->disassembledInstructions.begin(), this->disassembledInstructions.end(), [this](DisassembledInstruction &i) { + return i.address > this->_registers.pac; + }); + this->breakpoints.push_back({next->address, true}); + this->_isPaused = false; + } + void CPUDebug::_updateRegistersPanel() { if (!this->_registers.p.m) @@ -378,10 +404,18 @@ RowPainter::RowPainter(ComSquare::Debugger::CPUDebug &cpu, QObject *parent) : QS void RowPainter::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { ComSquare::Debugger::DisassembledInstruction instruction = this->_cpu.disassembledInstructions[index.row()]; + bool isBreakpoint = false; + + auto breakpoint = std::find_if(this->_cpu.breakpoints.begin(), this->_cpu.breakpoints.end(), [instruction](ComSquare::Debugger::Breakpoint brk) { + return brk.address == instruction.address; + }); + if (breakpoint != this->_cpu.breakpoints.end()) + isBreakpoint = true; if (instruction.address == this->_cpu.getPC()) painter->fillRect(option.rect,QColor(Qt::darkGreen)); - // TODO display breakpoints with the Qt::darkRed color. + if (isBreakpoint && !breakpoint->oneTime) + painter->fillRect(option.rect,QColor(Qt::darkRed)); QStyledItemDelegate::paint(painter, option, index); } diff --git a/sources/Debugger/CPUDebug.hpp b/sources/Debugger/CPUDebug.hpp index 2ee125b..5cc42ee 100644 --- a/sources/Debugger/CPUDebug.hpp +++ b/sources/Debugger/CPUDebug.hpp @@ -95,6 +95,14 @@ namespace ComSquare::Debugger std::string toString(); }; + //! @brief Struct representing a breakpoint set by the user or by the app + struct Breakpoint { + //! @brief The address of the breakpoint + uint24_t address; + //! @brief If this is true, the breakpoint will be deleted on first hit and won't be shown on the disassembly view. + bool oneTime; + }; + //! @brief A custom CPU with a window that show it's registers and the disassembly. class CPUDebug : public CPU::CPU, public QObject { private: @@ -147,12 +155,16 @@ namespace ComSquare::Debugger void pause(); //! @brief Step - Execute a single instruction. void step(); + //! @brief Next - Continue running instructions until the next line is reached. + void next(); //! @brief Clear the history panel. void clearHistory(); //! @brief Called when the window is closed. Turn off the debugger and revert to a basic CPU. void disableDebugger(); //! @brief The list of disassembled instructions to show on the debugger. std::vector disassembledInstructions; + //! @brief The list of breakpoints the user has set. + std::vector breakpoints; //! @brief Return the current program counter of this CPU. uint24_t getPC(); //! @brief Update the UI when resetting the CPU.