Implement all instruction string generators
MODIFY
src/defines.h
src/defines.h
enum displayTypeN { Hex = 1, Binary = 2, Decimal = 3, Unsigned = 4, ASCII = 5 };
Q_DECLARE_METATYPE(displayTypeN)
+typedef struct {
+ int IF = 0;
+ int ID = 0;
+ int EX = 0;
+ int MEM = 0;
+ int WB = 0;
+} StagePCS;
+
enum Colors {
// Berkeley primary color palette
BerkeleyBlue = 0x003262,

MODIFY
src/instructionmodel.cpp
src/instructionmodel.cpp
#include <QHeaderView>
-InstructionModel::InstructionModel(Parser* parser, QObject* parent) : m_parserPtr(parser), QAbstractTableModel(parent) {
+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");
@@ -36,13 +37,26 @@ QVariant InstructionModel::data(const QModelIndex& index, int role) const {
if (!index.isValid() || role != Qt::DisplayRole) {
return QVariant();
}
+ int row = index.row();
switch (index.column()) {
case 0:
- return index.row() * 4;
- case 1:
- return "NaN";
+ return row * 4;
+ case 1: { // check if instruction is in any pipeline stage
+ if (row == m_pcsptr.EX)
+ return QString("EX");
+ else if (row == m_pcsptr.ID)
+ return QString("ID");
+ else if (row == m_pcsptr.IF)
+ return QString("IF");
+ else if (row == m_pcsptr.MEM)
+ return QString("MEM");
+ else if (row == m_pcsptr.WB)
+ return QString("WB");
+ else
+ return QVariant();
+ }
case 2:
- return m_parserPtr->genStringRepr(memRead(index.row() * 4));
+ return m_parserPtr->genStringRepr(memRead(row * 4));
default:
return QVariant();
}

MODIFY
src/instructionmodel.h
src/instructionmodel.h
@@ -9,7 +9,7 @@ class Parser;
class InstructionModel : public QAbstractTableModel {
Q_OBJECT
public:
- explicit InstructionModel(Parser* parser = nullptr, QObject* parent = nullptr);
+ InstructionModel(const StagePCS& pcsptr, Parser* parser = nullptr, QObject* parent = nullptr);
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
@@ -21,6 +21,7 @@ public:
void setTextSize(int textSize);
private:
+ const StagePCS& m_pcsptr;
memory* m_memory;
Parser* m_parserPtr;
int m_textSize = 0; // text segment, in bytes

MODIFY
src/mainwindow.cpp
src/mainwindow.cpp
@@ -44,7 +44,8 @@ MainWindow::MainWindow(Runner* runnerPtr, Parser* parserPtr, QWidget* parent)
m_ui->memorytab->setMemoryPtr(m_runnerPtr->getMemoryPtr());
m_ui->memorytab->setRegPtr(m_runnerPtr->getRegPtr());
m_ui->processortab->initRegWidget(m_runnerPtr->getRegPtr());
- m_ui->processortab->initInstructionView(m_runnerPtr->getMemoryPtr(), m_parserPtr, m_runnerPtr->getTextSize());
+ m_ui->processortab->initInstructionView(m_runnerPtr->getMemoryPtr(), m_runnerPtr->getStagePCS(), m_parserPtr,
+ m_runnerPtr->getTextSize());
m_ui->memorytab->init();

MODIFY
src/parser.cpp
src/parser.cpp
@@ -106,25 +106,134 @@ QString Parser::genStringRepr(uint32_t instr) const {
break;
}
}
-QString Parser::generateEcallString(uint32_t instr) const {
- return QString();
+QString Parser::generateEcallString(uint32_t) const {
+ return QString("ecall");
}
QString Parser::generateOpInstrString(uint32_t instr) const {
- return QString();
+ std::vector<uint32_t> fields = decodeRInstr(instr);
+ switch (fields[3]) {
+ case 0b000:
+ if (fields[0] == 0) {
+ return QString("add x%1 x%2 x%3").arg(fields[4]).arg(fields[2]).arg(fields[1]);
+ } else if (fields[0] == 0b0100000) {
+ return QString("sub x%1 x%2 x%3").arg(fields[4]).arg(fields[2]).arg(fields[1]);
+ break;
+ } else if (fields[0] == 0b0000001) {
+ return QString("mul x%1 x%2 x%3").arg(fields[4]).arg(fields[2]).arg(fields[1]);
+ }
+ case 0b001:
+ if (fields[0] == 0b0000001) {
+ return QString("mulh x%1 x%2 x%3").arg(fields[4]).arg(fields[2]).arg(fields[1]);
+ } else if (fields[0] == 0) {
+ return QString("sll x%1 x%2 x%3").arg(fields[4]).arg(fields[2]).arg(fields[1]);
+ }
+ case 0b010:
+ if (fields[0] == 0b0000001) {
+ return QString("mulhsu x%1 x%2 x%3").arg(fields[4]).arg(fields[2]).arg(fields[1]);
+ } else if (fields[0] == 0) {
+ return QString("slt x%1 x%2 x%3").arg(fields[4]).arg(fields[2]).arg(fields[1]);
+ }
+ case 0b011:
+ if (fields[0] == 0b0000001) {
+ return QString("mulhu x%1 x%2 x%3").arg(fields[4]).arg(fields[2]).arg(fields[1]);
+ } else {
+ return QString("sltu x%1 x%2 x%3").arg(fields[4]).arg(fields[2]).arg(fields[1]);
+ }
+ case 0b100:
+ if (fields[0] == 0b1) {
+ return QString("div x%1 x%2 x%3").arg(fields[4]).arg(fields[2]).arg(fields[1]);
+ } else {
+ return QString("xor x%1 x%2 x%3").arg(fields[4]).arg(fields[2]).arg(fields[1]);
+ }
+ case 0b101:
+ if (fields[0] == 0) {
+ return QString("srl x%1 x%2 x%3").arg(fields[4]).arg(fields[2]).arg(fields[1]);
+
+ } else if (fields[0] == 0b0100000) {
+ return QString("sra x%1 x%2 x%3").arg(fields[4]).arg(fields[2]).arg(fields[1]);
+
+ } else if (fields[0] == 0b1) {
+ return QString("divu x%1 x%2 x%3").arg(fields[4]).arg(fields[2]).arg(fields[1]);
+ }
+ case 0b110:
+ if (fields[0] == 0b1) {
+ return QString("rem x%1 x%2 x%3").arg(fields[4]).arg(fields[2]).arg(fields[1]);
+ } else {
+ return QString("or x%1 x%2 x%3").arg(fields[4]).arg(fields[2]).arg(fields[1]);
+ }
+ case 0b111:
+ if (fields[0] == 0b1) {
+ return QString("remu x%1 x%2 x%3").arg(fields[4]).arg(fields[2]).arg(fields[1]);
+ } else {
+ return QString("and x%1 x%2 x%3").arg(fields[4]).arg(fields[2]).arg(fields[1]);
+ }
+ }
}
QString Parser::generateOpImmString(uint32_t instr) const {
+ std::vector<uint32_t> fields = decodeIInstr(instr);
+ switch (fields[2]) {
+ case 0b000: // ADDI
+ return QString("addi x%1 x%2 %3").arg(fields[3]).arg(fields[1]).arg(signextend<int32_t, 12>(fields[0]));
+ case 0b001: // SLLI
+ return QString("slli x%1 x%2 %3").arg(fields[3]).arg(fields[1]).arg(fields[0] & 0b11111);
+ case 0b010: // SLTI
+ return QString("slti x%1 x%2 %3").arg(fields[3]).arg(fields[1]).arg(signextend<int32_t, 12>(fields[0]));
+ case 0b011: // SLTIU
+ return QString("sltiu x%1 x%2 %3").arg(fields[3]).arg(fields[1]).arg(fields[0]);
+ case 0b100: // XORI
+ return QString("xori x%1 x%2 %3").arg(fields[3]).arg(fields[1]).arg(fields[0]);
+ case 0b101:
+ if ((fields[0] >> 5) == 0) {
+ return QString("srli x%1 x%2 %3").arg(fields[3]).arg(fields[1]).arg(fields[0] & 0b11111);
+ } else { // SRAI
+ return QString("srai x%1 x%2 %3").arg(fields[3]).arg(fields[1]).arg(fields[0] & 0b11111);
+ }
+ case 0b110: // ORI
+ return QString("ori x%1 x%2 %3").arg(fields[3]).arg(fields[1]).arg(fields[0]);
+ case 0b111: // ANDI
+ return QString("andi x%1 x%2 %3").arg(fields[3]).arg(fields[1]).arg(fields[0]);
+ default:
return QString();
}
+}
QString Parser::generateStoreString(uint32_t instr) const {
+ std::vector<uint32_t> fields = decodeSInstr(instr);
+ auto offset = signextend<int32_t, 12>((fields[0] << 5) | fields[4]);
+ switch (fields[3]) {
+ case 0b000: // SB
+ return QString("sb x%1 %2(x%3)").arg(fields[1]).arg(offset).arg(fields[2]);
+ case 0b001: // SH
+ return QString("sh x%1 %2(x%3)").arg(fields[1]).arg(offset).arg(fields[2]);
+ case 0b010: // SW
+ return QString("sw x%1 %2(x%3)").arg(fields[1]).arg(offset).arg(fields[2]);
+ default:
return QString();
}
+}
QString Parser::generateLoadString(uint32_t instr) const {
+ std::vector<uint32_t> fields = decodeIInstr(instr);
+
+ // Handle different load types by pointer casting and subsequent
+ // dereferencing. This will handle whether to sign or zero extend.
+ switch (fields[2]) {
+ case 0b000: // LB - load sign extended byte
+ return QString("lb %1 %2(x%3)").arg(fields[3]).arg(fields[0]).arg(fields[1]);
+ case 0b001: // LH load sign extended halfword
+ return QString("lh %1 %2(x%3)").arg(fields[3]).arg(fields[0]).arg(fields[1]);
+ case 0b010: // LW load word
+ return QString("lw %1 %2(x%3)").arg(fields[3]).arg(fields[0]).arg(fields[1]);
+ case 0b100: // LBU load zero extended byte
+ return QString("lbu %1 %2(x%3)").arg(fields[3]).arg(fields[0]).arg(fields[1]);
+ case 0b101: // LHU load zero extended halfword
+ return QString("lhu %1 %2(x%3)").arg(fields[3]).arg(fields[0]).arg(fields[1]);
+ default:
return QString();
}
+}
QString Parser::generateBranchString(uint32_t instr) const {
std::vector<uint32_t> fields = decodeBInstr(instr);
@@ -148,17 +257,23 @@ QString Parser::generateBranchString(uint32_t instr) const {
}
QString Parser::generateJalrString(uint32_t instr) const {
- return QString();
+ std::vector<uint32_t> fields = decodeIInstr(instr);
+ return QString("jalr x%1 x%2 %3").arg(fields[3]).arg(fields[1]).arg(signextend<int32_t, 12>(fields[0]));
}
QString Parser::generateLuiString(uint32_t instr) const {
- return QString();
+ std::vector<uint32_t> fields = decodeUInstr(instr);
+ return QString("lui x%1 %2").arg(fields[1]).arg(fields[0]);
}
QString Parser::generateAuipcString(uint32_t instr) const {
- return QString();
+ std::vector<uint32_t> fields = decodeUInstr(instr);
+ return QString("auipc x%1 %2").arg(fields[1]).arg(fields[0]);
}
QString Parser::generateJalString(uint32_t instr) const {
- return QString();
+ std::vector<uint32_t> fields = decodeJInstr(instr);
+ int target = signextend<int32_t, 21>(fields[0] << 20 | fields[1] << 1 | fields[2] << 11 | fields[3] << 12);
+ // Check for misaligned four-byte boundary
+ return QString("jal x%1 %2").arg(fields[4]).arg(target);
}

MODIFY
src/processortab.cpp
src/processortab.cpp
@@ -26,9 +26,9 @@ void ProcessorTab::initRegWidget(std::vector<uint32_t>* regPtr) {
m_ui->registerContainer->init();
}
-void ProcessorTab::initInstructionView(memory* mem, Parser* parser, int textSize) {
+void ProcessorTab::initInstructionView(memory* mem, const StagePCS& pcsptr, Parser* parser, int textSize) {
// Setup instruction view
- m_instrModel = new InstructionModel(parser);
+ m_instrModel = new InstructionModel(pcsptr, parser);
m_ui->instructionView->setEditTriggers(QAbstractItemView::NoEditTriggers);
m_instrModel->setMemory(mem, textSize);
m_ui->instructionView->setModel(m_instrModel);

MODIFY
src/processortab.h
src/processortab.h
@@ -19,7 +19,7 @@ public:
~ProcessorTab();
void initRegWidget(std::vector<uint32_t>* regPtr);
- void initInstructionView(memory* mem, Parser* parser, int textSize);
+ void initInstructionView(memory* mem, const StagePCS& pcsptr, Parser* parser, int textSize);
private slots:
void on_expandView_clicked();

MODIFY
src/runner.h
src/runner.h
@@ -21,6 +21,7 @@ public:
memory* getMemoryPtr() { return &m_memory; }
std::vector<uint32_t>* getRegPtr() { return &m_reg; }
int getTextSize() const { return m_textSize; }
+ const StagePCS& getStagePCS() const { return m_stagePCS; }
private:
instrState execInstruction(Instruction instr);
@@ -52,6 +53,7 @@ private:
bool getInstruction(int pc);
Instruction m_currentInstruction;
+ StagePCS m_stagePCS; // container for which instruction is in each pipeline stage
// Instruction execution functions
instrState execLuiInstr(Instruction instr);

Implement all instruction string generators