RV5S(WOF): Implement hazard and stall reason info
MODIFY
external/VSRTL
external/VSRTL
-Subproject commit 53564df93035755909d9039e740b26c8ed16f5b2
+Subproject commit 59e3a1455647013ff053bb96d087a288176b5f9a

MODIFY
src/instructionmodel.cpp
src/instructionmodel.cpp
@@ -81,7 +81,7 @@ QVariant InstructionModel::PCData(uint32_t addr) const {
QVariant InstructionModel::stageData(uint32_t addr) const {
QStringList stagesForAddr;
for (const auto& si : m_stageInfos) {
- if ((si.second.pc == addr) && si.second.pc_valid) {
+ if ((si.second.pc == addr) && si.second.stage_valid) {
stagesForAddr << si.first;
}
}

MODIFY
src/processors/RISC-V/rv5s/rv5s.h
src/processors/RISC-V/rv5s/rv5s.h
#include "../rv_registerfile.h"
// Stage separating registers
-#include "../rv5swof/rv5swof_exmem.h"
#include "../rv5swof/rv5swof_ifid.h"
-#include "../rv5swof/rv5swof_memwb.h"
+#include "rv5s_exmem.h"
#include "rv5s_idex.h"
+#include "rv5s_memwb.h"
// Forwarding & Hazard detection unit
#include "rv5s_forwardingunit.h"
@@ -159,6 +159,7 @@ public:
// -----------------------------------------------------------------------
// ID/EX
hzunit->hazardIDEXEnable >> idex_reg->enable;
+ hzunit->hazardIDEXClear >> idex_reg->stalled_in;
efschz_or->out >> idex_reg->clear;
// Data
@@ -191,6 +192,9 @@ public:
// EX/MEM
1 >> exmem_reg->enable;
hzunit->hazardEXMEMClear >> exmem_reg->clear;
+ hzunit->hazardEXMEMClear >> *mem_stalled_or->in[0];
+ idex_reg->stalled_out >> *mem_stalled_or->in[1];
+ mem_stalled_or->out >> exmem_reg->stalled_in;
// Data
idex_reg->pc_out >> exmem_reg->pc_in;
@@ -211,6 +215,8 @@ public:
// -----------------------------------------------------------------------
// MEM/WB
+ exmem_reg->stalled_out >> memwb_reg->stalled_in;
+
// Data
exmem_reg->pc_out >> memwb_reg->pc_in;
exmem_reg->pc4_out >> memwb_reg->pc4_in;
@@ -265,8 +271,8 @@ public:
// Stage seperating registers
SUBCOMPONENT(ifid_reg, IFID);
SUBCOMPONENT(idex_reg, RV5S_IDEX);
- SUBCOMPONENT(exmem_reg, EXMEM);
- SUBCOMPONENT(memwb_reg, MEMWB);
+ SUBCOMPONENT(exmem_reg, RV5S_EXMEM);
+ SUBCOMPONENT(memwb_reg, RV5S_MEMWB);
// Multiplexers
SUBCOMPONENT(reg_wr_src, TYPE(EnumMultiplexer<RegWrSrc, RV_REG_WIDTH>));
@@ -294,6 +300,8 @@ public:
// True if above or stalling due to load-use hazard
SUBCOMPONENT(efschz_or, TYPE(Or<1, 2>));
+ SUBCOMPONENT(mem_stalled_or, TYPE(Or<1, 2>));
+
// Address spaces
ADDRESSSPACE(m_memory);
ADDRESSSPACE(m_regMem);
@@ -356,9 +364,45 @@ public:
if(stage < EX){
stageValid &= !ecallChecker->isSysCallExiting();
}
-
// clang-format on
- return StageInfo({getPcForStage(stage), stageValid});
+
+ // Gather stage state info
+ StageInfo::State state = StageInfo ::State::None;
+ switch (stage) {
+ case IF:
+ break;
+ case ID:
+ if (m_cycleCount > ID && ifid_reg->valid_out.uValue() == 0) {
+ state = StageInfo::State::Flushed;
+ }
+ break;
+ case EX: {
+ if (idex_reg->stalled_out.uValue() == 1) {
+ state = StageInfo::State::Stalled;
+ } else if (m_cycleCount > EX && idex_reg->valid_out.uValue() == 0) {
+ state = StageInfo::State::Flushed;
+ }
+ break;
+ }
+ case MEM: {
+ if (exmem_reg->stalled_out.uValue() == 1) {
+ state = StageInfo::State::Stalled;
+ } else if (m_cycleCount > MEM && exmem_reg->valid_out.uValue() == 0) {
+ state = StageInfo::State::Flushed;
+ }
+ break;
+ }
+ case WB: {
+ if (memwb_reg->stalled_out.uValue() == 1) {
+ state = StageInfo::State::Stalled;
+ } else if (m_cycleCount > WB && memwb_reg->valid_out.uValue() == 0) {
+ state = StageInfo::State::Flushed;
+ }
+ break;
+ }
+ }
+
+ return StageInfo({getPcForStage(stage), stageValid, state});
}
void setProgramCounter(uint32_t address) override {
@@ -382,7 +426,7 @@ public:
// The processor is finished when there are no more valid instructions in the pipeline
bool allStagesInvalid = true;
for (int stage = IF; stage < STAGECOUNT; stage++) {
- allStagesInvalid &= !stageInfo(stage).pc_valid;
+ allStagesInvalid &= !stageInfo(stage).stage_valid;
if (!allStagesInvalid)
break;
}

ADD
src/processors/RISC-V/rv5s/rv5s_exmem.h
+#pragma once
+
+#include "VSRTL/core/vsrtl_component.h"
+#include "VSRTL/core/vsrtl_register.h"
+
+#include "../riscv.h"
+
+#include "../rv5swof/rv5swof_exmem.h"
+
+namespace vsrtl {
+namespace core {
+using namespace Ripes;
+
+class RV5S_EXMEM : public EXMEM {
+public:
+ RV5S_EXMEM(std::string name, SimComponent* parent) : EXMEM(name, parent) {
+ // We want stalling info to persist through clearing of the register, so stalled register is always enabled and
+ // never cleared.
+ CONNECT_REGISTERED_CLEN_INPUT(stalled, 0, 1);
+ }
+
+ REGISTERED_CLEN_INPUT(stalled, 1);
+};
+
+} // namespace core
+} // namespace vsrtl

MODIFY
src/processors/RISC-V/rv5s/rv5s_idex.h
src/processors/RISC-V/rv5s/rv5s_idex.h
#pragma once
#include "VSRTL/core/vsrtl_component.h"
+#include "VSRTL/core/vsrtl_constant.h"
#include "VSRTL/core/vsrtl_register.h"
#include "../riscv.h"
@@ -22,11 +23,17 @@ public:
CONNECT_REGISTERED_CLEN_INPUT(rd_reg1_idx, clear, enable);
CONNECT_REGISTERED_CLEN_INPUT(rd_reg2_idx, clear, enable);
CONNECT_REGISTERED_CLEN_INPUT(opcode, clear, enable);
+
+ // We want stalling info to persist through clearing of the register, so stalled register is always enabled and
+ // never cleared.
+ CONNECT_REGISTERED_CLEN_INPUT(stalled, 0, 1);
}
REGISTERED_CLEN_INPUT(rd_reg1_idx, RV_REGS_BITS);
REGISTERED_CLEN_INPUT(rd_reg2_idx, RV_REGS_BITS);
REGISTERED_CLEN_INPUT(opcode, RVInstr::width());
+
+ REGISTERED_CLEN_INPUT(stalled, 1);
};
} // namespace core

ADD
src/processors/RISC-V/rv5s/rv5s_memwb.h
+#pragma once
+
+#include "VSRTL/core/vsrtl_component.h"
+#include "VSRTL/core/vsrtl_register.h"
+
+#include "../riscv.h"
+
+#include "../rv5swof/rv5swof_memwb.h"
+
+namespace vsrtl {
+namespace core {
+using namespace Ripes;
+
+class RV5S_MEMWB : public MEMWB {
+public:
+ RV5S_MEMWB(std::string name, SimComponent* parent) : MEMWB(name, parent) { CONNECT_REGISTERED_INPUT(stalled); }
+
+ REGISTERED_INPUT(stalled, 1);
+};
+
+} // namespace core
+} // namespace vsrtl

MODIFY
src/processors/RISC-V/rv5swof/rv5swof.h
src/processors/RISC-V/rv5swof/rv5swof.h
@@ -296,9 +296,39 @@ public:
if(stage < EX){
stageValid &= !ecallChecker->isSysCallExiting();
}
-
// clang-format on
- return StageInfo({getPcForStage(stage), stageValid});
+
+ // Gather stage state info
+ StageInfo::State state = StageInfo ::State::None;
+ switch (stage) {
+ case IF:
+ break;
+ case ID:
+ if (m_cycleCount > ID && ifid_reg->valid_out.uValue() == 0) {
+ state = StageInfo::State::Flushed;
+ }
+ break;
+ case EX: {
+ if (m_cycleCount > EX && idex_reg->valid_out.uValue() == 0) {
+ state = StageInfo::State::Flushed;
+ }
+ break;
+ }
+ case MEM: {
+ if (m_cycleCount > MEM && exmem_reg->valid_out.uValue() == 0) {
+ state = StageInfo::State::Flushed;
+ }
+ break;
+ }
+ case WB: {
+ if (m_cycleCount > WB && memwb_reg->valid_out.uValue() == 0) {
+ state = StageInfo::State::Flushed;
+ }
+ break;
+ }
+ }
+
+ return StageInfo({getPcForStage(stage), stageValid, state});
}
void setProgramCounter(uint32_t address) override {
@@ -322,7 +352,7 @@ public:
// The processor is finished when there are no more valid instructions in the pipeline
bool allStagesInvalid = true;
for (int stage = IF; stage < STAGECOUNT; stage++) {
- allStagesInvalid &= !stageInfo(stage).pc_valid;
+ allStagesInvalid &= !stageInfo(stage).stage_valid;
if (!allStagesInvalid)
break;
}

MODIFY
src/processors/ripesprocessor.h
src/processors/ripesprocessor.h
@@ -28,8 +28,10 @@ enum SysCall {
* additional information which the processor may communicate to the GUI regarding the given stage.
*/
struct StageInfo {
+ enum class State { None, Stalled, Flushed };
unsigned int pc = 0;
- bool pc_valid = false;
+ bool stage_valid = false;
+ State state;
};
/**

MODIFY
src/processortab.cpp
src/processortab.cpp
@@ -276,11 +276,16 @@ void ProcessorTab::updateInstructionLabels() {
if (!m_stageInstructionLabels.count(i))
continue;
const auto stageInfo = proc->stageInfo(i);
+ auto* instrLabel = m_stageInstructionLabels.at(i);
QString instrString;
- if (stageInfo.pc_valid) {
+ if (stageInfo.state != StageInfo::State::None) {
+ instrString = stageInfo.state == StageInfo::State::Flushed ? "nop (flush)" : "nop (stall)";
+ instrLabel->setColor(Qt::red);
+ } else if (stageInfo.stage_valid) {
instrString = ProcessorHandler::get()->parseInstrAt(stageInfo.pc);
+ instrLabel->setColor(QColor());
}
- m_stageInstructionLabels.at(i)->setText(instrString);
+ instrLabel->setText(instrString);
}
}

MODIFY
src/stagetablemodel.cpp
src/stagetablemodel.cpp
@@ -72,7 +72,7 @@ QVariant StageTableModel::data(const QModelIndex& index, int role) const {
const auto& stageInfo = m_cycleStageInfos.at(index.column());
QStringList stagesForAddr;
for (const auto& si : stageInfo) {
- if (si.second.pc == addr && si.second.pc_valid) {
+ if (si.second.pc == addr && si.second.stage_valid) {
stagesForAddr << si.first;
}
}

RV5S(WOF): Implement hazard and stall reason info