Enable breakpoints for the VSRTL processor
MODIFY
src/codeeditor.cpp
src/codeeditor.cpp
#include "codeeditor.h"
#include "defines.h"
-#include "pipeline.h"
#include <QAction>
#include <QApplication>
@@ -108,18 +107,7 @@ void CodeEditor::updateTooltip(int line, QString tip) {
}
void CodeEditor::clearBreakpoints() {
- auto breakpoints = Pipeline::getPipeline()->getBreakpoints();
- breakpoints->clear();
-}
-
-void CodeEditor::updateBreakpoints() {
- // called after disassembler text has been set
-
- auto breakpoints = Pipeline::getPipeline()->getBreakpoints();
- // Remove breakpoints if a breakpoint line has been removed
- while (!breakpoints->empty() && *(breakpoints->rbegin()) > ((blockCount() - 1) * 4)) { // byte indexed
- breakpoints->erase(std::prev(breakpoints->end()));
- }
+ m_handler->clearBreakpoints();
}
bool CodeEditor::event(QEvent* event) {
@@ -229,15 +217,13 @@ void CodeEditor::breakpointAreaPaintEvent(QPaintEvent* event) {
if (m_breakpointAreaEnabled) {
QTextBlock block = firstVisibleBlock();
- int blockNumber = block.blockNumber() * 4; // byte indexed
+ uint32_t address = block.blockNumber() * m_handler->getProcessor()->implementsISA().bytes();
int top = (int)blockBoundingGeometry(block).translated(contentOffset()).top();
int bottom = top + (int)blockBoundingRect(block).height();
- auto breakpoints = Pipeline::getPipeline()->getBreakpoints();
-
while (block.isValid() && top <= event->rect().bottom()) {
if (block.isVisible() && bottom >= event->rect().top()) {
- if (breakpoints->find(blockNumber) != breakpoints->end()) {
+ if (m_handler->hasBreakpoint(address)) {
painter.drawPixmap(m_breakpointArea->padding, top, m_breakpointArea->imageWidth,
m_breakpointArea->imageHeight, m_breakpointArea->m_breakpoint);
}
@@ -246,7 +232,7 @@ void CodeEditor::breakpointAreaPaintEvent(QPaintEvent* event) {
block = block.next();
top = bottom;
bottom = top + (int)blockBoundingRect(block).height();
- blockNumber += 4;
+ address += m_handler->getProcessor()->implementsISA().bytes();
}
}
}
@@ -268,6 +254,7 @@ void CodeEditor::breakpointClick(QMouseEvent* event, int forceState) {
if (m_breakpointAreaEnabled) {
// Get line height
QTextBlock block = firstVisibleBlock();
+
auto height = blockBoundingRect(block).height();
// Find block index in the codeeditor
@@ -282,29 +269,15 @@ void CodeEditor::breakpointClick(QMouseEvent* event, int forceState) {
block = block.next();
index--;
}
- // Set or unset breakpoint
- // Since we want the simulator as fast as possible, the breakpoints are byte-indexed
- auto breakpoints = Pipeline::getPipeline()->getBreakpoints();
- int blockNumber = block.blockNumber() * 4;
- if (block.isValid()) {
- auto brkptIter = breakpoints->find(blockNumber);
- // Set/unset breakpoint
- if (forceState == 1) {
- breakpoints->insert(blockNumber);
- } else if (forceState == 2) {
- if (brkptIter != breakpoints->end())
- breakpoints->erase(breakpoints->find(blockNumber));
- } else {
- if (brkptIter != breakpoints->end()) {
- breakpoints->erase(brkptIter);
- } else {
- breakpoints->insert(blockNumber);
- }
- }
+ if (!block.isValid())
+ return;
+
+ // Toggle breakpoint
+ const uint32_t address = block.blockNumber() * m_handler->getProcessor()->implementsISA().bytes();
+ m_handler->toggleBreakpoint(address);
repaint();
}
}
-}
// -------------- breakpoint area ----------------------------------

MODIFY
src/codeeditor.h
src/codeeditor.h
#include <QTimer>
#include "assembler.h"
+#include "processorhandler.h"
#include "syntaxhighlighter.h"
#include <set>
@@ -21,12 +22,12 @@ class CodeEditor : public QPlainTextEdit {
Q_OBJECT
public:
CodeEditor(QWidget* parent = nullptr);
+ void setHandler(ProcessorHandler* handler) { m_handler = handler; }
void lineNumberAreaPaintEvent(QPaintEvent* event);
void breakpointAreaPaintEvent(QPaintEvent* event);
void breakpointClick(QMouseEvent* event, int forceState = 0);
void clearBreakpoints();
- void updateBreakpoints();
int lineNumberAreaWidth();
void setupSyntaxHighlighter();
void setupChangedTimer();
@@ -65,6 +66,8 @@ private:
QFont m_font = font();
+ ProcessorHandler* m_handler = nullptr;
+
// A timer is needed for only catching one of the multiple wheel events that
// occur on a regular mouse scroll
QTimer m_fontTimer;

MODIFY
src/edittab.cpp
src/edittab.cpp
#include "parser.h"
#include "pipeline.h"
-EditTab::EditTab(QToolBar* toolbar, QWidget* parent) : RipesTab(toolbar, parent), m_ui(new Ui::EditTab) {
+EditTab::EditTab(ProcessorHandler& handler, QToolBar* toolbar, QWidget* parent)
+ : RipesTab(toolbar, parent), m_ui(new Ui::EditTab), m_handler(handler) {
m_ui->setupUi(this);
+ m_ui->binaryedit->setHandler(&m_handler);
// Only add syntax highlighter for code edit view - not for translated code. This is assumed to be correct after a
// translation is complete
@@ -84,7 +86,6 @@ void EditTab::setDisassemblerText() {
const QString& text = m_ui->disassembledViewButton->isChecked() ? Parser::getParser()->getDisassembledRepr()
: Parser::getParser()->getBinaryRepr();
m_ui->binaryedit->setPlainText(text);
- m_ui->binaryedit->updateBreakpoints();
}
void EditTab::assemblingComplete(const QByteArray& data, bool clear, uint32_t baseAddress) {

MODIFY
src/edittab.h
src/edittab.h
#include <map>
#include "assembler.h"
+#include "processorhandler.h"
#include "program.h"
#include "ripestab.h"
@@ -18,7 +19,7 @@ class EditTab : public RipesTab {
Q_OBJECT
public:
- EditTab(QToolBar* toolbar, QWidget* parent = nullptr);
+ EditTab(ProcessorHandler& handler, QToolBar* toolbar, QWidget* parent = nullptr);
~EditTab() override;
void setAssemblyText(const QString& text);
@@ -48,4 +49,5 @@ private:
Ui::EditTab* m_ui;
Assembler* m_assembler = nullptr;
+ ProcessorHandler& m_handler;
};

MODIFY
src/mainwindow.cpp
src/mainwindow.cpp
@@ -35,7 +35,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), m_ui(new Ui::Main
auto* tb = addToolBar("Edit");
tb->setVisible(false);
- m_editTab = new EditTab(tb, this);
+ m_editTab = new EditTab(*m_processorHandler, tb, this);
m_stackedTabs->insertWidget(0, m_editTab);
tb = addToolBar("Processor");

MODIFY
src/processorhandler.cpp
src/processorhandler.cpp
@@ -24,6 +24,17 @@ void ProcessorHandler::loadProgram(const Program& p) {
// Set the valid execution range to be contained within the .text segment.
m_validExecutionRange = {p.text.first, p.text.first + p.text.second->length()};
+ // Update breakpoints to stay within the loaded program range
+ std::vector<uint32_t> bpsToRemove;
+ for (const auto& bp : m_breakpoints) {
+ if (bp < m_validExecutionRange.first | bp >= m_validExecutionRange.second) {
+ bpsToRemove.push_back(bp);
+ }
+ }
+ for (const auto& bp : bpsToRemove) {
+ m_breakpoints.erase(bp);
+ }
+
emit reqProcessorReset();
}
@@ -39,6 +50,21 @@ bool ProcessorHandler::hasBreakpoint(const uint32_t address) const {
return m_breakpoints.count(address);
}
+void ProcessorHandler::checkBreakpoint() {
+ const auto pc = m_currentProcessor->pcForStage(0);
+ if (m_breakpoints.count(pc)) {
+ emit hitBreakpoint(pc);
+ }
+}
+
+void ProcessorHandler::toggleBreakpoint(const uint32_t address) {
+ setBreakpoint(address, !hasBreakpoint(address));
+}
+
+void ProcessorHandler::clearBreakpoints() {
+ m_breakpoints.clear();
+}
+
void ProcessorHandler::selectProcessor(const ProcessorID id) {
m_currentProcessorID = id;
m_currentProcessor = ProcessorRegistry::constructProcessor(m_currentProcessorID);

MODIFY
src/processorhandler.h
src/processorhandler.h
@@ -59,8 +59,11 @@ public:
*/
uint32_t getRegisterValue(const unsigned idx) const;
+ void checkBreakpoint();
void setBreakpoint(const uint32_t address, bool enabled);
+ void toggleBreakpoint(const uint32_t address);
bool hasBreakpoint(const uint32_t address) const;
+ void clearBreakpoints();
signals:
/**
@@ -89,6 +92,12 @@ signals:
*/
void exit();
+ /**
+ * @brief hitBreakpoint
+ * Emitted whenever the instruction at breakpoint @param address is fetched into the processor
+ */
+ void hitBreakpoint(uint32_t address);
+
public slots:
void loadProgram(const Program& p);

MODIFY
src/processortab.cpp
src/processortab.cpp
@@ -30,6 +30,8 @@ ProcessorTab::ProcessorTab(ProcessorHandler& handler, QToolBar* toolbar, QWidget
m_ui->registerWidget->updateModel();
connect(this, &ProcessorTab::update, m_ui->registerWidget, &RegisterWidget::updateView);
+ connect(&m_handler, &ProcessorHandler::hitBreakpoint, this, &ProcessorTab::pause);
+
setupSimulatorActions();
// Create temporary pipeline widget to reduce changeset during VSRTL integration
@@ -144,6 +146,10 @@ void ProcessorTab::setupSimulatorActions() {
m_toolbar->addAction(m_pipelineTableAction);
}
+void ProcessorTab::pause() {
+ m_autoClockAction->setChecked(false);
+}
+
void ProcessorTab::processorSelection() {
ProcessorSelectionDialog diag(m_handler);
if (diag.exec()) {
@@ -267,6 +273,7 @@ void ProcessorTab::rewind() {
void ProcessorTab::clock() {
m_vsrtlWidget->clock();
m_handler.checkValidExecutionRange();
+ m_handler.checkBreakpoint();
auto pipeline = Pipeline::getPipeline();
auto state = pipeline->step();
@@ -277,13 +284,6 @@ void ProcessorTab::clock() {
}
emit update();
-
- // Pipeline has finished executing
- /*
- if (pipeline->isFinished() || (state == 1 && ecallVal.first == Pipeline::ECALL::exit)) {
- enableSimulatorControls();
- }
- */
}
bool ProcessorTab::handleEcall(const std::pair<Pipeline::ECALL, int32_t>& ecall_val) {

MODIFY
src/processortab.h
src/processortab.h
@@ -42,6 +42,7 @@ signals:
void appendToLog(QString string);
public slots:
+ void pause();
void restart();
void reset();
void rewind();

Enable breakpoints for the VSRTL processor