RV5S: Elaborate hazard handling
MODIFY
src/processors/RISC-V/rv5s/rv5s.h
src/processors/RISC-V/rv5s/rv5s.h
@@ -43,7 +43,7 @@ public:
4 >> pc_4->op2;
pc_src->out >> pc_reg->in;
0 >> pc_reg->clear;
- hzunit->hazardEnable >> pc_reg->enable;
+ hzunit->hazardFEEnable >> pc_reg->enable;
// Note: pc_src works uses the PcSrc enum, but is selected by the boolean signal
// from the controlflow OR gate. PcSrc enum values must adhere to the boolean
@@ -53,6 +53,9 @@ public:
controlflow_or->out >> *efsc_or->in[0];
ecallChecker->syscallExit >> *efsc_or->in[1];
+ efsc_or->out >> *efschz_or->in[0];
+ hzunit->hazardIDEXClear >> *efschz_or->in[1];
+
// -----------------------------------------------------------------------
// Instruction memory
pc_reg->out >> instr_mem->addr;
@@ -149,14 +152,14 @@ public:
pc_4->out >> ifid_reg->pc4_in;
pc_reg->out >> ifid_reg->pc_in;
instr_mem->data_out >> ifid_reg->instr_in;
- hzunit->hazardEnable >> ifid_reg->enable;
+ hzunit->hazardFEEnable >> ifid_reg->enable;
efsc_or->out >> ifid_reg->clear;
1 >> ifid_reg->valid_in; // Always valid unless register is cleared
// -----------------------------------------------------------------------
// ID/EX
- hzunit->hazardEnable >> idex_reg->enable;
- efsc_or->out >> idex_reg->clear;
+ hzunit->hazardIDEXEnable >> idex_reg->enable;
+ efschz_or->out >> idex_reg->clear;
// Data
ifid_reg->pc4_out >> idex_reg->pc4_in;
@@ -187,7 +190,7 @@ public:
// -----------------------------------------------------------------------
// EX/MEM
1 >> exmem_reg->enable;
- hzunit->hazardClear >> exmem_reg->clear;
+ hzunit->hazardEXMEMClear >> exmem_reg->clear;
// Data
idex_reg->pc_out >> exmem_reg->pc_in;
@@ -234,14 +237,16 @@ public:
// -----------------------------------------------------------------------
// Hazard detection unit
- idex_reg->rd_reg1_idx_out >> hzunit->id_reg1_idx;
- idex_reg->rd_reg2_idx_out >> hzunit->id_reg2_idx;
+ decode->r1_reg_idx >> hzunit->id_reg1_idx;
+ decode->r2_reg_idx >> hzunit->id_reg2_idx;
+
+ idex_reg->mem_do_read_out >> hzunit->ex_do_mem_read_en;
+ idex_reg->wr_reg_idx_out >> hzunit->ex_reg_wr_idx;
+
+ exmem_reg->reg_do_write_out >> hzunit->mem_do_reg_write;
- exmem_reg->wr_reg_idx_out >> hzunit->mem_reg_wr_idx;
- exmem_reg->mem_do_read_out >> hzunit->mem_do_read_en;
- exmem_reg->reg_do_write_out >> hzunit->mem_reg_do_write;
+ memwb_reg->reg_do_write_out >> hzunit->wb_do_reg_write;
- memwb_reg->reg_do_write_out >> hzunit->wb_reg_do_write;
idex_reg->opcode_out >> hzunit->opcode;
}
@@ -286,6 +291,8 @@ public:
SUBCOMPONENT(controlflow_or, TYPE(Or<1, 2>));
// True if controlflow action or performing syscall finishing
SUBCOMPONENT(efsc_or, TYPE(Or<1, 2>));
+ // True if above or stalling due to load-use hazard
+ SUBCOMPONENT(efschz_or, TYPE(Or<1, 2>));
// Address spaces
ADDRESSSPACE(m_memory);

MODIFY
src/processors/RISC-V/rv5s/rv5s_hazardunit.h
src/processors/RISC-V/rv5s/rv5s_hazardunit.h
@@ -11,26 +11,37 @@ using namespace Ripes;
class HazardUnit : public Component {
public:
HazardUnit(std::string name, SimComponent* parent) : Component(name, parent) {
- hazardEnable << [=] { return !hasHazard(); };
- hazardClear << [=] { return hasHazard(); };
+ hazardFEEnable << [=] { return !hasHazard(); };
+ hazardIDEXEnable << [=] { return !hasEcallHazard(); };
+ hazardEXMEMClear << [=] { return hasEcallHazard(); };
+ hazardIDEXClear << [=] { return hasLoadUseHazard(); };
stallEcallHandling << [=] { return hasEcallHazard(); };
}
INPUTPORT(id_reg1_idx, RV_REGS_BITS);
INPUTPORT(id_reg2_idx, RV_REGS_BITS);
- INPUTPORT(mem_reg_wr_idx, RV_REGS_BITS);
- INPUTPORT(mem_do_read_en, 1);
- INPUTPORT(mem_reg_do_write, 1);
+ INPUTPORT(ex_reg_wr_idx, RV_REGS_BITS);
+ INPUTPORT(ex_do_mem_read_en, 1);
- INPUTPORT(wb_reg_do_write, 1);
+ INPUTPORT(mem_do_reg_write, 1);
+
+ INPUTPORT(wb_do_reg_write, 1);
INPUTPORT_ENUM(opcode, RVInstr);
- // Hazard Enable: Low when stalling (shall be connected to a register 'enable' input port
- OUTPUTPORT(hazardEnable, 1);
- // Hazard clear: High when stalling (shall be connected to a register 'clear' input port.
- OUTPUTPORT(hazardClear, 1);
+ // Hazard Front End enable: Low when stalling the front end (shall be connected to a register 'enable' input port).
+ // The
+ OUTPUTPORT(hazardFEEnable, 1);
+
+ // Hazard IDEX enable: Low when stalling due to an ECALL hazard
+ OUTPUTPORT(hazardIDEXEnable, 1);
+
+ // EXMEM clear: High when an ECALL hazard is detected
+ OUTPUTPORT(hazardEXMEMClear, 1);
+ // IDEX clear: High when a load-use hazard is detected
+ OUTPUTPORT(hazardIDEXClear, 1);
+
// Stall Ecall Handling: High whenever we are about to handle an ecall, but have outstanding writes in the pipeline
// which must be comitted to the register file before handling the ecall.
OUTPUTPORT(stallEcallHandling, 1);
@@ -39,12 +50,12 @@ private:
bool hasHazard() { return hasLoadUseHazard() || hasEcallHazard(); }
bool hasLoadUseHazard() const {
- const unsigned midx = mem_reg_wr_idx.uValue();
+ const unsigned exidx = ex_reg_wr_idx.uValue();
const unsigned idx1 = id_reg1_idx.uValue();
const unsigned idx2 = id_reg2_idx.uValue();
- const bool mrd = mem_do_read_en.uValue();
+ const bool mrd = ex_do_mem_read_en.uValue();
- return (midx == idx1 || midx == idx2) && mrd;
+ return (exidx == idx1 || exidx == idx2) && mrd;
}
bool hasEcallHazard() const {
@@ -53,7 +64,7 @@ private:
// front-end of the pipeline shall be stalled until the remainder of the pipeline has been cleared and there are
// no more outstanding writes.
const bool isEcall = opcode.uValue() == RVInstr::ECALL;
- return isEcall && (mem_reg_do_write.uValue() || wb_reg_do_write.uValue());
+ return isEcall && (mem_do_reg_write.uValue() || wb_do_reg_write.uValue());
}
};
} // namespace core

RV5S: Elaborate hazard handling