Add breakpoint support through InstructionView
MODIFY
src/instructionmodel.cpp
src/instructionmodel.cpp
@@ -23,7 +23,7 @@ int InstructionModel::rowCount(const QModelIndex&) const {
}
int InstructionModel::columnCount(const QModelIndex&) const {
- return 3;
+ return 4;
}
namespace {
@@ -36,18 +36,32 @@ namespace {
}
QVariant InstructionModel::data(const QModelIndex& index, int role) const {
- if (!index.isValid() || role != Qt::DisplayRole) {
+ if (!index.isValid()) {
return QVariant();
}
int row = index.row();
switch (index.column()) {
- case 0:
- return row * 4;
+ case 0: {
+ // Breakpoints. Return true if breakpoint is found
+ if (role == Qt::CheckStateRole) {
+ if (m_pipelinePtr->m_breakpoints.find(row * 4) != m_pipelinePtr->m_breakpoints.end()) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+ break;
+ }
case 1: {
- // check if instruction is in any pipeline stage, and whether the given PC for the pipeline stage is
- // valid.
- // Furthermore, because of branching, an instruction can be in multiple stages at once - therefore, we build
- // up a return string by checking all stage program counters
+ if (role == Qt::DisplayRole)
+ return row * 4;
+ break;
+ }
+ case 2: {
+ if (role == Qt::DisplayRole) {
+ // check if instruction is in any pipeline stage, and whether the given PC for the pipeline
+ // stage is valid. Furthermore, because of branching, an instruction can be in multiple stages
+ // at once - therefore, we build up a return string by checking all stage program counters
QStringList retStrings;
uint32_t byteIndex = row * 4;
uint32_t maxInstr = m_textSize - 4;
@@ -96,21 +110,51 @@ QVariant InstructionModel::data(const QModelIndex& index, int role) const {
return retStrings.join("/");
}
}
- case 2:
+ break;
+ }
+ case 3:
+ if (role == Qt::DisplayRole) {
return m_parserPtr->genStringRepr(memRead(row * 4));
+ }
default:
return QVariant();
}
+ return QVariant();
+}
+
+bool InstructionModel::setData(const QModelIndex& index, const QVariant& value, int role) {
+ if (index.column() == 0 && role == Qt::CheckStateRole) {
+ if ((Qt::CheckState)value.toInt() == Qt::Checked) {
+ if (m_pipelinePtr->m_breakpoints.find(index.row() * 4) != m_pipelinePtr->m_breakpoints.end()) {
+ // Breakpoint is already set - remove breakpoint
+ m_pipelinePtr->m_breakpoints.erase(index.row() * 4);
+ } else {
+ // Set breakpoint
+ m_pipelinePtr->m_breakpoints.insert(index.row() * 4);
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+Qt::ItemFlags InstructionModel::flags(const QModelIndex& index) const {
+ auto def = Qt::ItemIsEnabled;
+ if (index.column() == 0)
+ return Qt::ItemIsUserCheckable | def;
+ return def;
}
QVariant InstructionModel::headerData(int section, Qt::Orientation orientation, int role) const {
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
switch (section) {
case 0:
- return "PC";
+ return "BP";
case 1:
- return "Stage";
+ return "PC";
case 2:
+ return "Stage";
+ case 3:
return "Instruction";
default:
return QVariant();

MODIFY
src/instructionmodel.h
src/instructionmodel.h
#ifndef INSTRUCTIONMODEL_H
#define INSTRUCTIONMODEL_H
+#include <set>
#include "defines.h"
#include "mainmemory.h"
@@ -20,6 +21,9 @@ public:
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
+ bool setData(const QModelIndex& index, const QVariant& value, int role) override;
+ Qt::ItemFlags flags(const QModelIndex& index) const override;
+
void update();
private:

MODIFY
src/pipeline.cpp
src/pipeline.cpp
@@ -644,13 +644,15 @@ int Pipeline::step() {
// Set stage program counters
setStagePCS();
- // Execution is finished if nops are in all stages except WB
+ // Check for finished execution and breakpoints
if (m_pcs.WB.pc > m_textSize) {
m_finished = true;
return 1;
- } else {
- return 0;
+ } else if (m_breakpoints.find((uint32_t)r_PC_IF) != m_breakpoints.end()) {
+ // Breakpoint set at current r_PC_IF value
+ return 1;
}
+ { return 0; }
}
#define PCVAL(pc, reg) \
@@ -679,6 +681,7 @@ void Pipeline::reset() {
// Called when resetting the simulator (loading a new program)
restart();
m_memory.clear();
+ m_breakpoints.clear();
m_textSize = 0;
m_ready = false;
}

MODIFY
src/pipeline.h
src/pipeline.h
#include "mainmemory.h"
#include "pipelineobjects.h"
+#include <set>
+
class Pipeline {
public:
Pipeline();
@@ -28,6 +30,8 @@ public:
return &pipeline;
}
+ std::set<uint32_t> m_breakpoints;
+
private:
// Simulator functions
void propagateCombinational();

MODIFY
src/processortab.cpp
src/processortab.cpp
@@ -10,19 +10,7 @@ ProcessorTab::ProcessorTab(QWidget* parent) : QWidget(parent), m_ui(new Ui::Proc
m_ui->setupUi(this);
// Setup buttons
- connect(m_ui->start, &QPushButton::toggled, [=](bool state) {
- if (state) {
- m_ui->start->setText("Pause simulation (F5)");
- m_ui->start->setShortcut(
- Qt::Key_F5); // The shortcut is for some reason cleared when editing the button text
- m_timer.start();
- } else {
- m_ui->start->setText("Start simulation (F5)");
- m_ui->start->setShortcut(Qt::Key_F5);
- m_timer.stop();
- };
- m_ui->step->setEnabled(!state);
- });
+ connect(m_ui->start, &QPushButton::toggled, this, &ProcessorTab::toggleTimer);
// Setup execution speed slider
connect(m_ui->execSpeed, &QSlider::valueChanged, [=](int pos) {
@@ -48,6 +36,22 @@ ProcessorTab::ProcessorTab(QWidget* parent) : QWidget(parent), m_ui(new Ui::Proc
m_ui->start->setEnabled(false);
}
+void ProcessorTab::toggleTimer(bool state) {
+ const static QString pauseText = QLatin1String("Stop autostepping (F5)");
+ const static QString startText = QLatin1String("Start autostepping (F5)");
+ if (state) {
+ m_ui->start->setText(pauseText);
+ m_ui->start->setShortcut(Qt::Key_F5); // The shortcut is for some reason cleared when editing the button text
+ m_timer.start();
+ } else {
+ m_ui->start->setText(startText);
+ m_ui->start->setShortcut(Qt::Key_F5);
+ m_ui->start->setChecked(false);
+ m_timer.stop();
+ };
+ m_ui->step->setEnabled(!state);
+}
+
void ProcessorTab::restart() {
// Invoked when changes to binary simulation file has been made
emit update();
@@ -71,7 +75,9 @@ void ProcessorTab::initInstructionView() {
m_ui->instructionView->setEditTriggers(QAbstractItemView::NoEditTriggers);
m_ui->instructionView->setModel(m_instrModel);
m_ui->instructionView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
- m_ui->instructionView->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Stretch);
+ m_ui->instructionView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
+ m_ui->instructionView->horizontalHeader()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
+ m_ui->instructionView->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Stretch);
connect(this, &ProcessorTab::update, m_ui->instructionView, QOverload<>::of(&QWidget::update));
connect(this, &ProcessorTab::update, m_instrModel, &InstructionModel::update);
@@ -95,11 +101,13 @@ void ProcessorTab::on_displayValues_toggled(bool checked) {
void ProcessorTab::on_run_clicked() {
auto pipeline = Pipeline::getPipeline();
if (pipeline->isReady()) {
- if (pipeline->run()) {
+ if (pipeline->run() && pipeline->isFinished()) {
emit update();
m_ui->step->setEnabled(false);
m_ui->start->setEnabled(false);
m_ui->run->setEnabled(false);
+ } else {
+ emit update();
}
}
}
@@ -114,12 +122,16 @@ void ProcessorTab::on_reset_clicked() {
}
void ProcessorTab::on_step_clicked() {
- auto state = Pipeline::getPipeline()->step();
+ auto pipeline = Pipeline::getPipeline();
+ auto state = pipeline->step();
emit update();
- if (state) {
+ if (pipeline->isFinished()) {
m_ui->step->setEnabled(false);
m_ui->start->setEnabled(false);
m_ui->run->setEnabled(false);
+ } else if (state == 1) {
+ // Breakpoint encountered, stop autostepping
+ toggleTimer(false);
}
}

MODIFY
src/processortab.h
src/processortab.h
@@ -38,6 +38,8 @@ private slots:
void on_step_clicked();
+ void toggleTimer(bool state);
+
private:
Ui::ProcessorTab* m_ui;
InstructionModel* m_instrModel;

MODIFY
src/processortab.ui
src/processortab.ui
<string>Start simulation, stepping through the program</string>
</property>
<property name="text">
- <string>Start simulation (F5)</string>
+ <string>Start autostepping (F5)</string>
</property>
<property name="shortcut">
<string>F5</string>

Add breakpoint support through InstructionView