[WIP] Add stage validation and statistics counting to RV5SWOF
MODIFY
external/VSRTL
external/VSRTL
-Subproject commit 4f09918df10ba4dcb66faf6bf60faefb542b7558
+Subproject commit 53564df93035755909d9039e740b26c8ed16f5b2

MODIFY
src/processorregistry.h
src/processorregistry.h
@@ -82,7 +82,7 @@ private:
desc.description =
"A 5-Stage in-order RISC-V processor with no hazard detection and forwarding. \n\nThe user is expected to "
"resolve all data hazard through insertions of NOP instructions to correctly schedule the code.";
- desc.layouts.push_back({"Extended", ":/layouts/5s/rv_5s_wof_extended_layout.json", true});
+ desc.layouts.push_back({}); //"Extended", ":/layouts/5s/rv_5s_wof_extended_layout.json", true});
desc.defaultRegisterVals = {{2, 0x7ffffff0}, {3, 0x10000000}};
m_descriptions[desc.id] = desc;
}

MODIFY
src/processors/5s/5s_exmem.h
src/processors/5s/5s_exmem.h
@@ -22,6 +22,8 @@ public:
CONNECT_REGISTERED_INPUT(reg_do_write);
CONNECT_REGISTERED_INPUT(mem_do_write);
CONNECT_REGISTERED_INPUT(mem_op);
+
+ CONNECT_REGISTERED_INPUT(valid);
}
// Data
@@ -36,6 +38,10 @@ public:
REGISTERED_INPUT(reg_do_write, 1);
REGISTERED_INPUT(mem_do_write, 1);
REGISTERED_INPUT(mem_op, MemOp::width());
+
+ // Valid signal. False when the register bank has been cleared. May be used by UI to determine whether the NOP in
+ // the stage is a user-inserted nop or the result of some pipeline action.
+ REGISTERED_INPUT(valid, 1);
};
} // namespace core

MODIFY
src/processors/5s/5s_idex.h
src/processors/5s/5s_idex.h
@@ -29,6 +29,8 @@ public:
CONNECT_REGISTERED_CLEN_INPUT(br_op, clear, enable);
CONNECT_REGISTERED_CLEN_INPUT(do_br, clear, enable);
CONNECT_REGISTERED_CLEN_INPUT(do_jmp, clear, enable);
+
+ CONNECT_REGISTERED_CLEN_INPUT(valid, clear, enable);
}
// Data
@@ -54,6 +56,10 @@ public:
// Register bank controls
INPUTPORT(enable, 1);
INPUTPORT(clear, 1);
+
+ // Valid signal. False when the register bank has been cleared. May be used by UI to determine whether the NOP in
+ // the stage is a user-inserted nop or the result of some pipeline action.
+ REGISTERED_CLEN_INPUT(valid, 1);
};
} // namespace core

MODIFY
src/processors/5s/5s_ifid.h
src/processors/5s/5s_ifid.h
@@ -15,6 +15,8 @@ public:
CONNECT_REGISTERED_CLEN_INPUT(pc4, clear, enable);
CONNECT_REGISTERED_CLEN_INPUT(pc, clear, enable);
CONNECT_REGISTERED_CLEN_INPUT(instr, clear, enable);
+
+ CONNECT_REGISTERED_CLEN_INPUT(valid, clear, enable);
}
REGISTERED_CLEN_INPUT(pc4, RV_REG_WIDTH);
@@ -24,6 +26,10 @@ public:
// Register controls
INPUTPORT(enable, 1);
INPUTPORT(clear, 1);
+
+ // Valid signal. False when the register bank has been cleared. May be used by UI to determine whether the NOP in
+ // the stage is a user-inserted nop or the result of some pipeline action.
+ REGISTERED_CLEN_INPUT(valid, 1);
};
} // namespace core

MODIFY
src/processors/5s/5s_memwb.h
src/processors/5s/5s_memwb.h
@@ -20,6 +20,8 @@ public:
CONNECT_REGISTERED_INPUT(reg_wr_src_ctrl);
CONNECT_REGISTERED_INPUT(wr_reg_idx);
CONNECT_REGISTERED_INPUT(reg_do_write);
+
+ CONNECT_REGISTERED_INPUT(valid);
}
// Data
@@ -32,6 +34,10 @@ public:
REGISTERED_INPUT(reg_wr_src_ctrl, RegWrSrc::width());
REGISTERED_INPUT(wr_reg_idx, RV_REGS_BITS);
REGISTERED_INPUT(reg_do_write, 1);
+
+ // Valid signal. False when the register bank has been cleared. May be used by UI to determine whether the NOP in
+ // the stage is a user-inserted nop or the result of some pipeline action.
+ REGISTERED_INPUT(valid, 1);
};
} // namespace core

MODIFY
src/processors/5s/riscv_5s.h
src/processors/5s/riscv_5s.h
@@ -165,6 +165,7 @@ public:
instr_mem->data_out >> ifid_reg->instr_in;
1 >> ifid_reg->enable;
controlflow_or->out >> ifid_reg->clear;
+ 1 >> ifid_reg->valid_in; // Always valid unless register is cleared
// -----------------------------------------------------------------------
// ID/EX
@@ -191,6 +192,8 @@ public:
control->do_branch >> idex_reg->do_br_in;
control->do_jump >> idex_reg->do_jmp_in;
+ ifid_reg->valid_out >> idex_reg->valid_in;
+
// -----------------------------------------------------------------------
// EX/MEM
@@ -207,6 +210,8 @@ public:
idex_reg->mem_do_write_out >> exmem_reg->mem_do_write_in;
idex_reg->mem_op_out >> exmem_reg->mem_op_in;
+ idex_reg->valid_out >> exmem_reg->valid_in;
+
// -----------------------------------------------------------------------
// MEM/WB
@@ -220,6 +225,8 @@ public:
exmem_reg->reg_wr_src_ctrl_out >> memwb_reg->reg_wr_src_ctrl_in;
exmem_reg->wr_reg_idx_out >> memwb_reg->wr_reg_idx_in;
exmem_reg->reg_do_write_out >> memwb_reg->reg_do_write_in;
+
+ exmem_reg->valid_out >> memwb_reg->valid_in;
}
// Design subcomponents
@@ -296,7 +303,34 @@ public:
return "N/A";
}
}
- StageInfo stageInfo(unsigned int idx) const override { return StageInfo({getPcForStage(idx), true}); }
+ StageInfo stageInfo(unsigned int idx) const override {
+ bool stageValid = true;
+ // Has the pipeline stage been filled?
+ stageValid &= idx <= m_cycleCount;
+
+ // clang-format off
+ // Has the stage been cleared?
+ switch(idx){
+ case 1: stageValid &= ifid_reg->valid_out.uValue(); break;
+ case 2: stageValid &= idex_reg->valid_out.uValue(); break;
+ case 3: stageValid &= exmem_reg->valid_out.uValue(); break;
+ case 4: stageValid &= memwb_reg->valid_out.uValue(); break;
+ default: case 0: break;
+ }
+
+ // Is the stage carrying a valid (executable) PC?
+ switch(idx){
+ case 1: stageValid &= isExecutableAddress(ifid_reg->pc_out.uValue()); break;
+ case 2: stageValid &= isExecutableAddress(idex_reg->pc_out.uValue()); break;
+ case 3: stageValid &= isExecutableAddress(exmem_reg->pc_out.uValue()); break;
+ case 4: stageValid &= isExecutableAddress(memwb_reg->pc_out.uValue()); break;
+ default: case 0: stageValid &= isExecutableAddress(pc_reg->out.uValue()); break;
+ }
+
+ // clang-format on
+ return StageInfo({getPcForStage(idx), stageValid});
+ }
+
void setProgramCounter(uint32_t address) override {
pc_reg->forceValue(0, address);
propagateDesign();
@@ -317,16 +351,22 @@ public:
void setRegister(unsigned i, uint32_t v) override { setSynchronousValue(registerFile->_wr_mem, i, v); }
void clock() override {
- // @todo fix for staged pipeline
+ // An instruction has been retired if the instruction in the WB stage is valid and the PC is within the
+ // executable range of the program
+ if (memwb_reg->valid_out.uValue() != 0 && isExecutableAddress(memwb_reg->pc_out.uValue())) {
m_instructionsRetired++;
+ }
RipesProcessor::clock();
m_fcntr++;
}
void reverse() override {
- m_instructionsRetired--;
RipesProcessor::reverse();
+ if (memwb_reg->valid_out.uValue() != 0 && isExecutableAddress(memwb_reg->pc_out.uValue())) {
+ m_instructionsRetired--;
+ }
+
m_fcntr--;
}

[WIP] Add stage validation and statistics counting to RV5SWOF