Set processor tab exec buttons' state in relation to runner state
MODIFY
src/defines.h
src/defines.h
@@ -64,7 +64,7 @@ enum cacheType { DM, SA, FA };
typedef std::unordered_map<uint32_t, uint8_t> memory;
-enum instrState { ERR_BFUNCT3, ERR_NULLLOAD, EXEC_ERR, SUCCESS, DONE, ERR_ECALL };
+enum runnerState { ERR_BFUNCT3, ERR_NULLLOAD, EXEC_ERR, SUCCESS, DONE, ERR_ECALL, BREAKPOINT };
const static QStringList ABInames = QStringList() << "zero"
<< "ra"

MODIFY
src/instructionmodel.cpp
src/instructionmodel.cpp
@@ -18,7 +18,7 @@ void InstructionModel::update() {
// Called when changes to the memory has been made
// assumes that only instructions are present in the memory when called!
beginResetModel();
- m_textSize = m_memory->size();
+ m_textSize = Runner::getRunner()->getTextSize();
endResetModel();
}

MODIFY
src/processortab.cpp
src/processortab.cpp
@@ -19,20 +19,32 @@ ProcessorTab::ProcessorTab(QWidget* parent) : QWidget(parent), m_ui(new Ui::Proc
m_ui->step->setEnabled(!state);
});
- // Setup speed slider
- m_timer.setInterval(1500 - 200 * m_ui->execSpeed->sliderPosition());
- connect(m_ui->execSpeed, &QSlider::valueChanged, [=](int pos) { m_timer.setInterval(1500 - 200 * pos); });
+ // Setup execution speed slider
+ m_ui->execSpeed->setSliderPosition(2);
+ m_timer.setInterval(1200 - 200 * m_ui->execSpeed->sliderPosition());
+ connect(m_ui->execSpeed, &QSlider::valueChanged, [=](int pos) { m_timer.setInterval(1200 - 200 * pos); });
connect(m_ui->reset, &QPushButton::clicked, [=] { m_ui->start->setChecked(false); });
// Setup stepping timer
connect(&m_timer, &QTimer::timeout, this, &ProcessorTab::on_step_clicked);
+
+ // Initially, no file is loaded, disable run, step and reset buttons
+ m_ui->reset->setEnabled(false);
+ m_ui->step->setEnabled(false);
+ m_ui->run->setEnabled(false);
+ m_ui->start->setEnabled(false);
}
void ProcessorTab::update() {
// Invoked when changes to binary simulation file has been made
m_instrModel->update();
m_ui->registerContainer->update();
+
+ m_ui->step->setEnabled(true);
+ m_ui->run->setEnabled(true);
+ m_ui->reset->setEnabled(true);
+ m_ui->start->setEnabled(true);
}
void ProcessorTab::initRegWidget() {
@@ -65,9 +77,17 @@ void ProcessorTab::on_displayValues_toggled(bool checked) {
}
void ProcessorTab::on_run_clicked() {
- Runner::getRunner()->exec();
+ auto runner = Runner::getRunner();
+ if (runner->isReady()) {
+ if (runner->exec() == DONE) {
+ m_instrModel->update();
m_ui->instructionView->update();
m_ui->registerContainer->update();
+ m_ui->step->setEnabled(false);
+ m_ui->start->setEnabled(false);
+ m_ui->run->setEnabled(false);
+ }
+ }
}
void ProcessorTab::on_reset_clicked() {
@@ -75,11 +95,21 @@ void ProcessorTab::on_reset_clicked() {
m_instrModel->update();
m_ui->instructionView->update();
m_ui->registerContainer->update();
+
+ m_ui->step->setEnabled(true);
+ m_ui->start->setEnabled(true);
+ m_ui->run->setEnabled(true);
}
void ProcessorTab::on_step_clicked() {
- Runner::getRunner()->step();
+ auto state = Runner::getRunner()->step();
m_instrModel->update();
m_ui->instructionView->update();
m_ui->registerContainer->update();
+
+ if (state == DONE) {
+ m_ui->step->setEnabled(false);
+ m_ui->start->setEnabled(false);
+ m_ui->run->setEnabled(false);
+ }
}

MODIFY
src/runner.cpp
src/runner.cpp
@@ -16,31 +16,39 @@ Runner::Runner(Parser* parser) {
Runner::~Runner() {}
-int Runner::exec() {
+runnerState Runner::exec() {
// Main simulator loop:
// Make parser parse an instruction based on the current program counter, and,
// if successfull, execute the read instruction. Loop until parser
// unsuccesfully parses an instruction.
- instrState err;
+ runnerState err;
while (getInstruction(m_pc)) {
+ setStageInstructions();
switch ((err = execInstruction(m_currentInstruction))) {
case SUCCESS:
break;
case DONE:
- return 0;
+ return DONE;
default:
handleError(err);
- return 1;
+ return err;
}
}
- return 0;
+ return EXEC_ERR;
}
-int Runner::step() {
+void Runner::setStageInstructions() {
m_stagePCS.IF = m_pc;
+ m_stagePCS.ID = m_pc - 4 >= 0 ? m_pc - 4 : m_stagePCS.ID;
+ m_stagePCS.EX = m_pc - 8 >= 0 ? m_pc - 8 : m_stagePCS.EX;
+ m_stagePCS.MEM = m_pc - 12 >= 0 ? m_pc - 12 : m_stagePCS.MEM;
+ m_stagePCS.WB = m_pc - 16 >= 0 ? m_pc - 16 : m_stagePCS.WB;
+}
+
+runnerState Runner::step() {
+ setStageInstructions();
getInstruction(m_pc);
- execInstruction(m_currentInstruction);
- return 0;
+ return execInstruction(m_currentInstruction);
}
bool Runner::getInstruction(int pc) {
@@ -52,7 +60,7 @@ bool Runner::getInstruction(int pc) {
return true;
}
-instrState Runner::execInstruction(Instruction instr) {
+runnerState Runner::execInstruction(Instruction instr) {
switch (instr.type) {
case LUI:
return execLuiInstr(instr);
@@ -75,12 +83,12 @@ instrState Runner::execInstruction(Instruction instr) {
case ECALL:
return execEcallInstr();
default:
- return instrState::EXEC_ERR;
+ return runnerState::EXEC_ERR;
break;
}
}
-instrState Runner::execLuiInstr(Instruction instr) {
+runnerState Runner::execLuiInstr(Instruction instr) {
/* "LUI places the U-immediate value in the top 20 bits of
* the destination m_register rd, filling in the lowest 12 bits with zeros"*/
std::vector<uint32_t> fields = m_parser->decodeUInstr(instr.word);
@@ -89,14 +97,14 @@ instrState Runner::execLuiInstr(Instruction instr) {
return SUCCESS;
}
-instrState Runner::execAuipcInstr(Instruction instr) {
+runnerState Runner::execAuipcInstr(Instruction instr) {
std::vector<uint32_t> fields = m_parser->decodeUInstr(instr.word);
m_reg[fields[1]] = (fields[0] << 12) + m_pc;
m_pc += 4;
return SUCCESS;
}
-instrState Runner::execJalInstr(Instruction instr) {
+runnerState Runner::execJalInstr(Instruction instr) {
std::vector<uint32_t> fields = m_parser->decodeJInstr(instr.word);
if (fields[4] != 0) { // rd = 0 equals unconditional jump
m_reg[fields[4]] = m_pc + 4;
@@ -110,7 +118,7 @@ instrState Runner::execJalInstr(Instruction instr) {
}
}
-instrState Runner::execJalrInstr(Instruction instr) {
+runnerState Runner::execJalrInstr(Instruction instr) {
std::vector<uint32_t> fields = m_parser->decodeIInstr(instr.word);
// Store initial register state of m_reg[fields[1]], in case
// fields[3]==fields[1]
@@ -129,7 +137,7 @@ instrState Runner::execJalrInstr(Instruction instr) {
}
}
-instrState Runner::execBranchInstr(Instruction instr) {
+runnerState Runner::execBranchInstr(Instruction instr) {
std::vector<uint32_t> fields = m_parser->decodeBInstr(instr.word);
// calculate target address using signed offset
@@ -160,7 +168,7 @@ instrState Runner::execBranchInstr(Instruction instr) {
return SUCCESS;
}
-instrState Runner::execLoadInstr(Instruction instr) {
+runnerState Runner::execLoadInstr(Instruction instr) {
std::vector<uint32_t> fields = m_parser->decodeIInstr(instr.word);
if (fields[3] == 0) {
return ERR_NULLLOAD;
@@ -208,7 +216,7 @@ uint32_t Runner::memRead(uint32_t address) {
return read;
}
-instrState Runner::execStoreInstr(Instruction instr) {
+runnerState Runner::execStoreInstr(Instruction instr) {
std::vector<uint32_t> fields = m_parser->decodeSInstr(instr.word);
auto target = signextend<int32_t, 12>((fields[0] << 5) | fields[4]) + m_reg[fields[2]];
@@ -229,7 +237,7 @@ instrState Runner::execStoreInstr(Instruction instr) {
return SUCCESS;
}
-instrState Runner::execOpImmInstr(Instruction instr) {
+runnerState Runner::execOpImmInstr(Instruction instr) {
std::vector<uint32_t> fields = m_parser->decodeIInstr(instr.word);
if (fields[3] == 0) {
return ERR_NULLLOAD;
@@ -272,7 +280,7 @@ instrState Runner::execOpImmInstr(Instruction instr) {
return SUCCESS;
}
-instrState Runner::execOpInstr(Instruction instr) {
+runnerState Runner::execOpInstr(Instruction instr) {
std::vector<uint32_t> fields = m_parser->decodeRInstr(instr.word);
switch (fields[3]) {
case 0b000:
@@ -410,7 +418,7 @@ instrState Runner::execOpInstr(Instruction instr) {
return SUCCESS;
}
-instrState Runner::execEcallInstr() {
+runnerState Runner::execEcallInstr() {
switch (m_reg[10]) // a0
{
case 10:
@@ -420,7 +428,7 @@ instrState Runner::execEcallInstr() {
}
}
-void Runner::handleError(instrState /*err*/) const {
+void Runner::handleError(runnerState /*err*/) const {
// handle error and print program counter + current instruction
throw "Error!";
}
@@ -430,6 +438,7 @@ void Runner::reset() {
restart();
m_memory.clear();
m_textSize = 0;
+ m_ready = false;
}
void Runner::restart() {
@@ -458,5 +467,6 @@ void Runner::restart() {
void Runner::update() {
// Must be called whenever external changes to the memory has been envoked
m_textSize = m_memory.size();
+ m_ready = true;
restart();
}

MODIFY
src/runner.h
src/runner.h
class Runner {
public:
- int exec();
- int step();
+ runnerState exec();
+ runnerState step();
static Runner* getRunner() {
static Runner runner(Parser::getParser());
return &runner;
@@ -25,6 +25,7 @@ public:
std::vector<uint32_t>* getRegPtr() { return &m_reg; }
int getTextSize() const { return m_textSize; }
const StagePCS& getStagePCS() const { return m_stagePCS; }
+ bool isReady() { return m_ready; }
void reset();
void restart();
@@ -33,8 +34,9 @@ public:
private:
Runner(Parser* parser);
~Runner();
- instrState execInstruction(Instruction instr);
- void handleError(instrState err) const;
+ runnerState execInstruction(Instruction instr);
+ void setStageInstructions();
+ void handleError(runnerState err) const;
int m_pc = 0; // program counter
@@ -59,22 +61,23 @@ private:
Parser* m_parser;
bool m_running = false; // flag for disabling UI update signals when running simulator
+ bool m_ready;
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);
- instrState execAuipcInstr(Instruction instr);
- instrState execJalInstr(Instruction instr);
- instrState execJalrInstr(Instruction instr);
- instrState execBranchInstr(Instruction instr);
- instrState execLoadInstr(Instruction instr);
- instrState execStoreInstr(Instruction instr);
- instrState execOpImmInstr(Instruction instr);
- instrState execOpInstr(Instruction instr);
- instrState execEcallInstr();
+ runnerState execLuiInstr(Instruction instr);
+ runnerState execAuipcInstr(Instruction instr);
+ runnerState execJalInstr(Instruction instr);
+ runnerState execJalrInstr(Instruction instr);
+ runnerState execBranchInstr(Instruction instr);
+ runnerState execLoadInstr(Instruction instr);
+ runnerState execStoreInstr(Instruction instr);
+ runnerState execOpImmInstr(Instruction instr);
+ runnerState execOpInstr(Instruction instr);
+ runnerState execEcallInstr();
// Cache
RunnerCache m_cache;

Set processor tab exec buttons' state in relation to runner state