Display instructions above each stage in PipelineWidget
MODIFY
src/defines.h
src/defines.h
#define STACKSTART 0x7ffffff0
#define DATASTART 0x10000000
+enum class Stage { IF, ID, EX, MEM, WB };
+
enum displayTypeN { Hex, Binary, Decimal, Unsigned, ASCII };
Q_DECLARE_METATYPE(displayTypeN)

MODIFY
src/graphics/backgrounditems.cpp
src/graphics/backgrounditems.cpp
@@ -41,18 +41,18 @@ Text::Text(QPointF pos) {
QRectF Text::boundingRect() const {
QFontMetrics obj(m_font);
- auto rect = obj.boundingRect(*m_text);
+ auto rect = obj.boundingRect(m_text);
rect.moveTo(m_pos.toPoint());
return rect;
}
void Text::paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*) {
QFontMetrics obj(m_font);
- QRectF rect = obj.boundingRect(*m_text);
+ QRectF rect = obj.boundingRect(m_text);
rect.moveTo(m_pos.toPoint());
rect.translate(-rect.width() / 2, -rect.height() / 2);
painter->setFont(m_font);
- painter->drawText(rect, Qt::AlignCenter, *m_text);
+ painter->drawText(rect, Qt::AlignCenter, m_text);
}
} // namespace Graphics

MODIFY
src/graphics/backgrounditems.h
src/graphics/backgrounditems.h
@@ -21,12 +21,12 @@ private:
class Text : public QGraphicsItem {
public:
Text(QPointF pos);
- void setTextPtr(QString* text) { m_text = text; }
+ void setText(const QString& text) { m_text = text; }
QRectF boundingRect() const;
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget);
private:
- QString* m_text;
+ QString m_text;
QFont m_font;
QPointF m_pos;
};

MODIFY
src/graphics/pipelinewidget.cpp
src/graphics/pipelinewidget.cpp
#include "pipelinewidget.h"
#include "backgrounditems.h"
#include "connection.h"
-#include "defines.h"
#include "shape.h"
#include <QDebug>
@@ -250,27 +249,21 @@ PipelineWidget::PipelineWidget(QWidget* parent) : QGraphicsView(parent) {
scene->addItem(dash4);
int textPad = 20;
- Graphics::Text* if_instr = new Graphics::Text(QPointF(
+ if_instr = new Graphics::Text(QPointF(
-dash1->sceneBoundingRect().left() + dash1->sceneBoundingRect().width() / 2 + -spaceBetweenStateRegs / 2,
dash1->sceneBoundingRect().top() + textPad));
- Graphics::Text* id_instr = new Graphics::Text(
+ id_instr = new Graphics::Text(
QPointF(dash1->sceneBoundingRect().left() + dash1->sceneBoundingRect().width() / 2 + spaceBetweenStateRegs / 2,
dash1->sceneBoundingRect().top() + textPad));
- Graphics::Text* ex_instr = new Graphics::Text(
+ ex_instr = new Graphics::Text(
QPointF(dash2->sceneBoundingRect().left() + dash2->sceneBoundingRect().width() / 2 + spaceBetweenStateRegs / 2,
dash2->sceneBoundingRect().top() + textPad));
- Graphics::Text* mem_instr = new Graphics::Text(
+ mem_instr = new Graphics::Text(
QPointF(dash3->sceneBoundingRect().left() + dash3->sceneBoundingRect().width() / 2 + spaceBetweenStateRegs / 2,
dash3->sceneBoundingRect().top() + textPad));
- Graphics::Text* wb_instr = new Graphics::Text(QPointF(dash4->sceneBoundingRect().left() + spaceBetweenStateRegs / 3,
+ wb_instr = new Graphics::Text(QPointF(dash4->sceneBoundingRect().left() + spaceBetweenStateRegs / 3,
dash4->sceneBoundingRect().top() + textPad));
- if_instr->setTextPtr(new QString("and x12, x2, x5"));
- id_instr->setTextPtr(new QString("beq x1, x3, 16"));
- ex_instr->setTextPtr(new QString("sub x10, x4, x8"));
- mem_instr->setTextPtr(new QString("nop"));
- wb_instr->setTextPtr(new QString("rd x10 24 x2"));
-
scene->addItem(if_instr);
scene->addItem(id_instr);
scene->addItem(ex_instr);
@@ -278,6 +271,31 @@ PipelineWidget::PipelineWidget(QWidget* parent) : QGraphicsView(parent) {
scene->addItem(wb_instr);
}
+void PipelineWidget::update() {
+ QWidget::update();
+}
+
+void PipelineWidget::stageTextChanged(Stage stage, const QString& text) {
+ switch (stage) {
+ case Stage::IF:
+ if_instr->setText(text);
+ break;
+ case Stage::ID:
+ id_instr->setText(text);
+ break;
+ case Stage::EX:
+ ex_instr->setText(text);
+ break;
+ case Stage::MEM:
+ mem_instr->setText(text);
+ break;
+ case Stage::WB:
+ wb_instr->setText(text);
+ break;
+ }
+ scene()->update();
+}
+
void PipelineWidget::moveToIO(Graphics::Shape* source, Graphics::Shape* dest, QPointF* sourcePoint, QPointF* destPoint,
int connectionLength) {
// Moves the source shape such that its sourcePoint is aligned with the

MODIFY
src/graphics/pipelinewidget.h
src/graphics/pipelinewidget.h
#include <QGraphicsView>
#include <QPair>
+#include "defines.h"
+
namespace Graphics {
class Connection;
+class Text;
class Shape;
-}
+} // namespace Graphics
typedef QPair<Graphics::Shape*, int> ShapePair;
@@ -21,6 +24,10 @@ public:
void expandToView() { fitInView(scene()->sceneRect().adjusted(-30, 0, 10, 0), Qt::KeepAspectRatio); }
void displayAllValues(bool state);
+public slots:
+ void update();
+ void stageTextChanged(Stage stage, const QString& text);
+
signals:
void displayAllValuesSig(bool state);
@@ -50,6 +57,13 @@ private:
Graphics::Shape* idex;
Graphics::Shape* exmem;
Graphics::Shape* memwb;
+
+ // Text pointers
+ Graphics::Text* if_instr;
+ Graphics::Text* id_instr;
+ Graphics::Text* ex_instr;
+ Graphics::Text* mem_instr;
+ Graphics::Text* wb_instr;
};
#endif // PIPELINEWIDGET_H

MODIFY
src/instructionmodel.cpp
src/instructionmodel.cpp
#include <QHeaderView>
-InstructionModel::InstructionModel(const StagePCS& pcsptr, Parser* parser, QObject* parent)
- : m_pcsptr(pcsptr), m_parserPtr(parser), QAbstractTableModel(parent) {
- /*
- setHeaderData(0, Qt::Horizontal, "PC");
- setHeaderData(1, Qt::Horizontal, "Stage");
- setHeaderData(2, Qt::Horizontal, "Instruction");
- */
- m_memory = Pipeline::getPipeline()->getMemoryPtr();
+InstructionModel::InstructionModel(const StagePCS& pcsptr, const StagePCS& pcsptrPre, Parser* parser, QObject* parent)
+ : m_pcsptr(pcsptr), m_pcsptrPre(pcsptrPre), m_parserPtr(parser), QAbstractTableModel(parent) {
+ m_pipelinePtr = Pipeline::getPipeline();
+ m_memory = m_pipelinePtr->getMemoryPtr();
}
void InstructionModel::update() {
@@ -30,6 +26,13 @@ int InstructionModel::columnCount(const QModelIndex&) const {
return 3;
}
+namespace {
+#define VALIDATE(stage) \
+ if (!m_pcsptr.stage.second) { \
+ emit textChanged(Stage::stage, ""); \
+ }
+}
+
QVariant InstructionModel::data(const QModelIndex& index, int role) const {
if (!index.isValid() || role != Qt::DisplayRole) {
return QVariant();
@@ -39,21 +42,47 @@ QVariant InstructionModel::data(const QModelIndex& index, int role) const {
case 0:
return row * 4;
case 1: { // check if instruction is in any pipeline stage, and whether the given PC for the pipeline stage is
- // valid
+ // valid. For the pipelinewidget, determine if an instruction in a given stage is equal to the text
+ // size, if so, clear previous instruction texts in the pipeline widget
uint32_t byteIndex = row * 4;
- if (byteIndex == m_pcsptr.EX.first && m_pcsptr.EX.second)
+ uint32_t maxInstr = m_textSize - 4;
+ if (byteIndex == m_pcsptr.EX.first && m_pcsptr.EX.second) {
+ emit textChanged(Stage::EX, m_parserPtr->genStringRepr(memRead(row * 4)));
+ if (byteIndex == maxInstr) {
+ emit textChanged(Stage::ID, "");
+ }
return QString("EX");
- else if (byteIndex == m_pcsptr.ID.first && m_pcsptr.ID.second)
+ } else if (byteIndex == m_pcsptr.ID.first && m_pcsptr.ID.second) {
+ emit textChanged(Stage::ID, m_parserPtr->genStringRepr(memRead(row * 4)));
+ if (byteIndex == maxInstr) {
+ emit textChanged(Stage::IF, "");
+ }
return QString("ID");
- else if (byteIndex == m_pcsptr.IF.first && m_pcsptr.IF.second)
+ } else if (byteIndex == m_pcsptr.IF.first && m_pcsptr.IF.second) {
+ emit textChanged(Stage::IF, m_parserPtr->genStringRepr(memRead(row * 4)));
return QString("IF");
- else if (byteIndex == m_pcsptr.MEM.first && m_pcsptr.MEM.second)
+ } else if (byteIndex == m_pcsptr.MEM.first && m_pcsptr.MEM.second) {
+ emit textChanged(Stage::MEM, m_parserPtr->genStringRepr(memRead(row * 4)));
+ if (byteIndex == maxInstr) {
+ emit textChanged(Stage::EX, "");
+ }
return QString("MEM");
- else if (byteIndex == m_pcsptr.WB.first && m_pcsptr.WB.second)
+ } else if (byteIndex == m_pcsptr.WB.first && m_pcsptr.WB.second) {
+ emit textChanged(Stage::WB, m_parserPtr->genStringRepr(memRead(row * 4)));
+ if (byteIndex == maxInstr) {
+ emit textChanged(Stage::MEM, "");
+ }
return QString("WB");
- else
+ } else {
+ // Clear invalid PC values for each stage (used when resetting the simlation)
+ VALIDATE(IF);
+ VALIDATE(ID);
+ VALIDATE(EX);
+ VALIDATE(MEM);
+ VALIDATE(WB);
return QVariant();
}
+ }
case 2:
return m_parserPtr->genStringRepr(memRead(row * 4));
default:

MODIFY
src/instructionmodel.h
src/instructionmodel.h
#include <QAbstractTableModel>
class Parser;
+class Pipeline;
class InstructionModel : public QAbstractTableModel {
Q_OBJECT
public:
- InstructionModel(const StagePCS& pcsptr, Parser* parser = nullptr, QObject* parent = nullptr);
+ InstructionModel(const StagePCS& pcsptr, const StagePCS& pcsptrPre, Parser* parser = nullptr,
+ QObject* parent = nullptr);
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
@@ -22,13 +24,16 @@ public:
private:
const StagePCS& m_pcsptr;
+ const StagePCS& m_pcsptrPre;
MainMemory* m_memory;
+ Pipeline* m_pipelinePtr;
Parser* m_parserPtr;
int m_textSize = 0; // text segment, in bytes
uint32_t memRead(uint32_t address) const;
signals:
+ void textChanged(Stage stage, QString text) const;
public slots:
};

MODIFY
src/mainwindow.cpp
src/mainwindow.cpp
@@ -55,7 +55,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), m_ui(new Ui::Main
m_ui->consoles->hide();
};
});
- connect(this, &MainWindow::update, m_ui->processortab, &ProcessorTab::update);
+ connect(this, &MainWindow::update, m_ui->processortab, &ProcessorTab::restart);
}
MainWindow::~MainWindow() {

MODIFY
src/pipeline.cpp
src/pipeline.cpp
@@ -391,6 +391,7 @@ int Pipeline::step() {
// Execution is finished if nops are in all stages except WB
if (m_pcs.WB.first == m_textSize) {
+ m_finished = true;
return 1;
} else {
return 0;
@@ -402,6 +403,7 @@ void Pipeline::setStagePCS() {
// To validate a PC value (whether there is actually an instruction in the stage, or if the pipeline has
// been reset), the previous stage PC is used to determine the current state of a stage To facilitate this,
// the PCS are set in reverse order
+ m_pcsPre = m_pcs;
m_pcs.WB = m_pcs.MEM.second ? PCVAL(r_PC_MEMWB) : m_pcs.WB;
m_pcs.MEM = m_pcs.EX.second ? PCVAL(r_PC_EXMEM) : m_pcs.MEM;
m_pcs.EX = m_pcs.ID.second ? PCVAL(r_PC_IDEX) : m_pcs.EX;
@@ -436,6 +438,8 @@ void Pipeline::restart() {
m_memory.reset(m_textSize);
m_reg.init();
m_pcs.reset();
+ m_pcsPre.reset();
+ m_finished = false;
// Reset all registers to 0 and propagate signals through combinational logic
RegBase::resetAll();

MODIFY
src/pipeline.h
src/pipeline.h
@@ -18,8 +18,10 @@ public:
MainMemory* getMemoryPtr() { return &m_memory; }
std::vector<uint32_t>* getRegPtr() { return m_reg.getRegPtr(); }
const StagePCS& getStagePCS() const { return m_pcs; }
+ const StagePCS& getStagePCSPre() const { return m_pcsPre; }
int getTextSize() const { return m_textSize; }
bool isReady() const { return m_ready; }
+ bool isFinished() const { return m_finished; }
static Pipeline* getPipeline() {
static Pipeline pipeline;
@@ -38,6 +40,7 @@ private:
// Program counters for each stage
void setStagePCS();
StagePCS m_pcs;
+ StagePCS m_pcsPre;
bool m_finished = false;
// Memory

MODIFY
src/processortab.cpp
src/processortab.cpp
#include "processortab.h"
#include "instructionmodel.h"
+#include "pipelinewidget.h"
#include "ui_processortab.h"
#include "parser.h"
@@ -30,6 +31,10 @@ ProcessorTab::ProcessorTab(QWidget* parent) : QWidget(parent), m_ui(new Ui::Proc
// Setup stepping timer
connect(&m_timer, &QTimer::timeout, this, &ProcessorTab::on_step_clicked);
+ // Setup updating signals
+ connect(this, &ProcessorTab::update, m_ui->registerContainer, &RegisterContainerWidget::update);
+ connect(this, &ProcessorTab::update, m_ui->pipelineWidget, &PipelineWidget::update);
+
// Initially, no file is loaded, disable run, step and reset buttons
m_ui->reset->setEnabled(false);
m_ui->step->setEnabled(false);
@@ -37,10 +42,9 @@ ProcessorTab::ProcessorTab(QWidget* parent) : QWidget(parent), m_ui(new Ui::Proc
m_ui->start->setEnabled(false);
}
-void ProcessorTab::update() {
+void ProcessorTab::restart() {
// Invoked when changes to binary simulation file has been made
- m_instrModel->update();
- m_ui->registerContainer->update();
+ emit update();
m_ui->step->setEnabled(true);
m_ui->run->setEnabled(true);
@@ -56,13 +60,19 @@ void ProcessorTab::initRegWidget() {
void ProcessorTab::initInstructionView() {
// Setup instruction view
- m_instrModel = new InstructionModel(Pipeline::getPipeline()->getStagePCS(), Parser::getParser());
+ m_instrModel = new InstructionModel(Pipeline::getPipeline()->getStagePCS(),
+ Pipeline::getPipeline()->getStagePCSPre(), Parser::getParser());
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(1, QHeaderView::ResizeToContents);
m_ui->instructionView->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Stretch);
- m_instrModel->update();
+ connect(this, &ProcessorTab::update, m_ui->instructionView, QOverload<>::of(&QWidget::update));
+ connect(this, &ProcessorTab::update, m_instrModel, &InstructionModel::update);
+
+ // Connect instruction model text changes to the pipeline widget (changing instruction names displayed above each
+ // stage)
+ connect(m_instrModel, &InstructionModel::textChanged, m_ui->pipelineWidget, &PipelineWidget::stageTextChanged);
}
ProcessorTab::~ProcessorTab() {
@@ -81,9 +91,7 @@ void ProcessorTab::on_run_clicked() {
auto pipeline = Pipeline::getPipeline();
if (pipeline->isReady()) {
if (pipeline->run()) {
- m_instrModel->update();
- m_ui->instructionView->update();
- m_ui->registerContainer->update();
+ emit update();
m_ui->step->setEnabled(false);
m_ui->start->setEnabled(false);
m_ui->run->setEnabled(false);
@@ -93,9 +101,7 @@ void ProcessorTab::on_run_clicked() {
void ProcessorTab::on_reset_clicked() {
Pipeline::getPipeline()->restart();
- m_instrModel->update();
- m_ui->instructionView->update();
- m_ui->registerContainer->update();
+ emit update();
m_ui->step->setEnabled(true);
m_ui->start->setEnabled(true);
@@ -104,9 +110,7 @@ void ProcessorTab::on_reset_clicked() {
void ProcessorTab::on_step_clicked() {
auto state = Pipeline::getPipeline()->step();
- m_instrModel->update();
- m_ui->instructionView->update();
- m_ui->registerContainer->update();
+ emit update();
if (state) {
m_ui->step->setEnabled(false);

MODIFY
src/processortab.h
src/processortab.h
@@ -24,7 +24,7 @@ public:
void initInstructionView();
public slots:
- void update();
+ void restart();
private slots:
@@ -43,6 +43,9 @@ private:
InstructionModel* m_instrModel;
QTimer m_timer;
+
+signals:
+ void update();
};
#endif // PROCESSORTAB_H

Display instructions above each stage in PipelineWidget