Decouple VSRTL::Design from RipesProcessor interface [WIP 2]
MODIFY
src/processorhandler.cpp
src/processorhandler.cpp
#include "processorregistry.h"
#include "processors/ripesprocessor.h"
+#include "processors/ripesvsrtlprocessor.h"
#include "ripessettings.h"
#include "statusmanager.h"
@@ -45,9 +46,9 @@ ProcessorHandler::ProcessorHandler() {
// Connect relevant settings changes to VSRTL
connect(RipesSettings::getObserver(RIPES_SETTING_REWINDSTACKSIZE), &SettingObserver::modified,
- [=](const auto& size) { m_currentProcessor->setReverseStackSize(size.toUInt()); });
+ [=](const auto& size) { m_currentProcessor->setMaxReverseCycles(size.toUInt()); });
// Update VSRTL reverse stack size to reflect current settings
- m_currentProcessor->setReverseStackSize(RipesSettings::value(RIPES_SETTING_REWINDSTACKSIZE).toUInt());
+ m_currentProcessor->setMaxReverseCycles(RipesSettings::value(RIPES_SETTING_REWINDSTACKSIZE).toUInt());
m_syscallManager = std::make_unique<RISCVSyscallManager>();
}
@@ -156,7 +157,11 @@ void ProcessorHandler::_setBreakpoint(const uint32_t address, bool enabled) {
void ProcessorHandler::_loadProcessorToWidget(vsrtl::VSRTLWidget* widget) {
m_vsrtlWidget = widget;
- widget->setDesign(m_currentProcessor.get());
+
+ // Currently, only VSRTL processors can be visualized
+ if (auto* vsrtlProcessor = dynamic_cast<RipesVSRTLProcessor*>(m_currentProcessor.get())) {
+ widget->setDesign(vsrtlProcessor);
+ }
}
bool ProcessorHandler::_hasBreakpoint(const uint32_t address) const {
@@ -225,7 +230,7 @@ void ProcessorHandler::_selectProcessor(const ProcessorID& id, const QStringList
ptrValueBytes.data(), m_currentProcessor->implementsISA()->bytes());
}
- m_currentProcessor->verifyAndInitialize();
+ m_currentProcessor->postConstruct();
createAssemblerForCurrentISA();
if (keepProgram && m_program) {
@@ -235,9 +240,9 @@ void ProcessorHandler::_selectProcessor(const ProcessorID& id, const QStringList
}
// Reconnect the wrappers for processor signal emission
- m_currentProcessor->designWasClocked.Connect(this, &ProcessorHandler::processorWasClockedWrapper);
- m_currentProcessor->designWasReset.Connect(this, &ProcessorHandler::processorResetWrapper);
- m_currentProcessor->designWasReversed.Connect(this, &ProcessorHandler::processorReversedWrapper);
+ m_currentProcessor->processorWasClocked.Connect(this, &ProcessorHandler::processorWasClockedWrapper);
+ m_currentProcessor->processorWasReset.Connect(this, &ProcessorHandler::processorResetWrapper);
+ m_currentProcessor->processorWasReversed.Connect(this, &ProcessorHandler::processorReversedWrapper);
emit processorChanged();
}

MODIFY
src/processorhandler.h
src/processorhandler.h
@@ -29,8 +29,8 @@ public:
return handler;
}
- static vsrtl::core::RipesVSRTLProcessor* getProcessorNonConst() { return get()->_getProcessorNonConst(); }
- static const vsrtl::core::RipesVSRTLProcessor* getProcessor() { return get()->_getProcessor(); }
+ static RipesProcessor* getProcessorNonConst() { return get()->_getProcessorNonConst(); }
+ static const RipesProcessor* getProcessor() { return get()->_getProcessor(); }
static const std::shared_ptr<Assembler::AssemblerBase> getAssembler() { return get()->_getAssembler(); }
static const ProcessorID& getID() { return get()->_getID(); }
static std::shared_ptr<const Program> getProgram() { return get()->_getProgram(); }
@@ -193,8 +193,8 @@ private slots:
void asyncTrap();
private:
- vsrtl::core::RipesVSRTLProcessor* _getProcessorNonConst() { return m_currentProcessor.get(); }
- const vsrtl::core::RipesVSRTLProcessor* _getProcessor() { return m_currentProcessor.get(); }
+ RipesProcessor* _getProcessorNonConst() { return m_currentProcessor.get(); }
+ const RipesProcessor* _getProcessor() { return m_currentProcessor.get(); }
const std::shared_ptr<Assembler::AssemblerBase> _getAssembler() { return m_currentAssembler; }
const ProcessorID& _getID() const { return m_currentID; }
std::shared_ptr<const Program> _getProgram() const { return m_program; }
@@ -239,7 +239,7 @@ private:
ProcessorHandler();
ProcessorID m_currentID;
- std::unique_ptr<vsrtl::core::RipesVSRTLProcessor> m_currentProcessor;
+ std::unique_ptr<RipesProcessor> m_currentProcessor;
std::unique_ptr<SyscallManager> m_syscallManager;
std::shared_ptr<Assembler::AssemblerBase> m_currentAssembler;

MODIFY
src/processorregistry.h
src/processorregistry.h
@@ -75,8 +75,7 @@ public:
}
return desc->second;
}
- static std::unique_ptr<vsrtl::core::RipesVSRTLProcessor> constructProcessor(ProcessorID id,
- const QStringList& extensions) {
+ static std::unique_ptr<RipesProcessor> constructProcessor(ProcessorID id, const QStringList& extensions) {
switch (id) {
case ProcessorID::RV32_5S_NO_FW_HZ:
return std::make_unique<vsrtl::core::RV5S_NO_FW_HZ<32>>(extensions);

MODIFY
src/processors/RISC-V/rv5s/rv5s.h
src/processors/RISC-V/rv5s/rv5s.h
@@ -455,7 +455,7 @@ public:
m_instructionsRetired++;
}
- RipesVSRTLProcessor::clock();
+ Design::clock();
}
void reverse() override {
@@ -465,7 +465,7 @@ public:
ecallChecker->setSysCallExiting(false);
m_syscallExitCycle = -1;
}
- RipesVSRTLProcessor::reverse();
+ Design::reverse();
if (memwb_reg->valid_out.uValue() != 0 && isExecutableAddress(memwb_reg->pc_out.uValue())) {
m_instructionsRetired--;
}
@@ -473,7 +473,7 @@ public:
void reset() override {
ecallChecker->setSysCallExiting(false);
- RipesVSRTLProcessor::reset();
+ Design::reset();
m_syscallExitCycle = -1;
}

MODIFY
src/processors/RISC-V/rv5s_no_fw/rv5s_no_fw.h
src/processors/RISC-V/rv5s_no_fw/rv5s_no_fw.h
@@ -430,7 +430,7 @@ public:
m_instructionsRetired++;
}
- RipesVSRTLProcessor::clock();
+ Design::clock();
}
void reverse() override {
@@ -440,7 +440,7 @@ public:
ecallChecker->setSysCallExiting(false);
m_syscallExitCycle = -1;
}
- RipesVSRTLProcessor::reverse();
+ Design::reverse();
if (memwb_reg->valid_out.uValue() != 0 && isExecutableAddress(memwb_reg->pc_out.uValue())) {
m_instructionsRetired--;
}
@@ -448,7 +448,7 @@ public:
void reset() override {
ecallChecker->setSysCallExiting(false);
- RipesVSRTLProcessor::reset();
+ Design::reset();
m_syscallExitCycle = -1;
}

MODIFY
src/processors/RISC-V/rv5s_no_fw_hz/rv5s_no_fw_hz.h
src/processors/RISC-V/rv5s_no_fw_hz/rv5s_no_fw_hz.h
@@ -381,7 +381,7 @@ public:
m_instructionsRetired++;
}
- RipesVSRTLProcessor::clock();
+ Design::clock();
}
void reverse() override {
@@ -391,14 +391,14 @@ public:
ecallChecker->setSysCallExiting(false);
m_syscallExitCycle = -1;
}
- RipesVSRTLProcessor::reverse();
+ Design::reverse();
if (memwb_reg->valid_out.uValue() != 0 && isExecutableAddress(memwb_reg->pc_out.uValue())) {
m_instructionsRetired--;
}
}
void reset() override {
- RipesVSRTLProcessor::reset();
+ Design::reset();
ecallChecker->setSysCallExiting(false);
m_syscallExitCycle = -1;
}

MODIFY
src/processors/RISC-V/rv5s_no_hz/rv5s_no_hz.h
src/processors/RISC-V/rv5s_no_hz/rv5s_no_hz.h
@@ -414,7 +414,7 @@ public:
m_instructionsRetired++;
}
- RipesVSRTLProcessor::clock();
+ Design::clock();
}
void reverse() override {
@@ -424,14 +424,14 @@ public:
ecallChecker->setSysCallExiting(false);
m_syscallExitCycle = -1;
}
- RipesVSRTLProcessor::reverse();
+ Design::reverse();
if (memwb_reg->valid_out.uValue() != 0 && isExecutableAddress(memwb_reg->pc_out.uValue())) {
m_instructionsRetired--;
}
}
void reset() override {
- RipesVSRTLProcessor::reset();
+ Design::reset();
ecallChecker->setSysCallExiting(false);
m_syscallExitCycle = -1;
}

MODIFY
src/processors/RISC-V/rv6s_dual/rv6s_dual.h
src/processors/RISC-V/rv6s_dual/rv6s_dual.h
@@ -774,7 +774,7 @@ public:
// executable range of the program
m_instructionsRetired += instructionsRetired();
- RipesVSRTLProcessor::clock();
+ Design::clock();
}
void reverse() override {
@@ -784,13 +784,13 @@ public:
ecallChecker->setSysCallExiting(false);
m_syscallExitCycle = -1;
}
- RipesVSRTLProcessor::reverse();
+ Design::reverse();
m_instructionsRetired -= instructionsRetired();
}
void reset() override {
ecallChecker->setSysCallExiting(false);
- RipesVSRTLProcessor::reset();
+ Design::reset();
m_syscallExitCycle = -1;
}

MODIFY
src/processors/RISC-V/rvss/rvss.h
src/processors/RISC-V/rvss/rvss.h
@@ -189,7 +189,7 @@ public:
// m_finishInNextCycle may be set during Design::clock(). Store the value before clocking the processor, and
// emit finished if this was the final clock cycle.
const bool finishInThisCycle = m_finishInNextCycle;
- RipesVSRTLProcessor::clock();
+ Design::clock();
if (finishInThisCycle) {
m_finished = true;
}
@@ -197,14 +197,14 @@ public:
void reverse() override {
m_instructionsRetired--;
- RipesVSRTLProcessor::reverse();
+ Design::reverse();
// Ensure that reverses performed when we expected to finish in the following cycle, clears this expectation.
m_finishInNextCycle = false;
m_finished = false;
}
void reset() override {
- RipesVSRTLProcessor::reset();
+ Design::reset();
m_finishInNextCycle = false;
m_finished = false;
}

MODIFY
src/processors/ripesprocessor.h
src/processors/ripesprocessor.h
@@ -47,6 +47,24 @@ struct FinalizeReason {
class RipesProcessor {
public:
RipesProcessor() {}
+ virtual ~RipesProcessor(){};
+
+ /**
+ * @brief postConstruct
+ * Called after the processor has been constructed. Implementing processors can use this to start any initialization
+ * which must be performed after class construction.
+ */
+ virtual void postConstruct(){};
+
+ /**
+ * @brief The Features struct
+ * The set of optional features implemented by this processor
+ */
+ struct Features {
+ bool isReversible = false;
+ };
+
+ const Features& features() const { return m_features; }
/**
* @brief registerFiles
@@ -157,7 +175,36 @@ public:
* @brief reset
* Resets the processor
*/
- virtual void reset() = 0;
+ virtual void resetProcessor() = 0;
+
+ /**
+ * @brief clock
+ * Clocks the processor
+ */
+ virtual void clockProcessor() = 0;
+
+ /**
+ * @brief clocked, reversed & reset signals
+ * These signals must be emitted whenever the processor has finished the given operation.
+ * Signals should only be emitted if m_emitsSignals is set.
+ */
+ Gallant::Signal0<> processorWasClocked;
+ Gallant::Signal0<> processorWasReversed;
+ Gallant::Signal0<> processorWasReset;
+
+ /** FEATURE: Reversible=============================================*/
+ /**
+ * @brief reverse
+ * Reverses the processor, undoing the latest clock cycle
+ */
+ virtual void reverse(){};
+ /**
+ * @brief setMaxReverseCycles
+ * @p cycles denotes the maximum number of cycles that the processor is expected to be able to reverse.
+ */
+ virtual void setMaxReverseCycles(unsigned cycles) { Q_UNUSED(cycles); };
+
+ /** ================================================================*/
/**
* @brief isExecutableAddress
@@ -196,6 +243,16 @@ public:
* @returns the number of instructions which has retired (ie. executed and no longer in the pipeline).
*/
virtual long long getInstructionsRetired() const = 0;
+ /**
+ * @brief getCycleCount
+ * @returns the number of cycles which has been executed.
+ */
+ virtual long long getCycleCount() const = 0;
+
+protected:
+ // m_features should be adjusted accordingly during processor construction
+ Features m_features;
+ bool m_emitsSignals = true;
};
} // namespace Ripes

MODIFY
src/processors/ripesvsrtlprocessor.h
src/processors/ripesvsrtlprocessor.h
@@ -11,17 +11,37 @@ namespace Ripes {
class RipesVSRTLProcessor : public RipesProcessor, public vsrtl::core::Design {
public:
- RipesVSRTLProcessor(std::string name) : Design(name) {}
+ RipesVSRTLProcessor(std::string name) : Design(name) {
+ // VSRTL provides reversible simulation
+ m_features.isReversible = true;
+
+ // Shim signal emissions from VSRTL to RipesProcessor
+ designWasClocked.Connect(&processorWasClocked, &Gallant::Signal0<>::Emit);
+ designWasReversed.Connect(&processorWasReversed, &Gallant::Signal0<>::Emit);
+ designWasReset.Connect(&processorWasReset, &Gallant::Signal0<>::Emit);
+ }
- virtual void reset() override {
+ virtual void resetProcessor() override {
m_instructionsRetired = 0;
Design::reset();
}
+ virtual void clockProcessor() override { Design::clock(); }
+
long long getInstructionsRetired() const override { return m_instructionsRetired; }
+ long long getCycleCount() const override { return m_cycleCount; }
+ void setMaxReverseCycles(unsigned cycles) override { setReverseStackSize(cycles); }
+
+ void postConstruct() override {
+ /**
+ * VSRTL designs must call verifyAndInitialize after being constructed.
+ */
+ verifyAndInitialize();
+ }
protected:
- // Statistics
+ // m_instructionsRetired should be modified by the processor when it retires (or "un-retires", while reversing) an
+ // instruction
long long m_instructionsRetired = 0;
};

MODIFY
test/tst_cosimulate.cpp
test/tst_cosimulate.cpp
@@ -185,7 +185,7 @@ void tst_Cosimulate::executeSimulator(Trace& trace, const Trace* refTrace) {
Registers preRegs = dumpRegs();
do {
- ProcessorHandler::get()->getProcessorNonConst()->clock();
+ ProcessorHandler::get()->getProcessorNonConst()->clockProcessor();
cycles++;
Registers regs = dumpRegs();
@@ -256,7 +256,7 @@ const Trace& tst_Cosimulate::generateReferenceTrace(const QStringList& extension
void tst_Cosimulate::cosimulate(const ProcessorID& id, const QStringList& extensions) {
// Connect the global reset request signal to directly resetting the processor
connect(RipesSettings::getObserver(RIPES_GLOBALSIGNAL_REQRESET), &SettingObserver::modified,
- [=] { ProcessorHandler::get()->getProcessorNonConst()->reset(); });
+ [=] { ProcessorHandler::get()->getProcessorNonConst()->resetProcessor(); });
m_loader = new EditTab(new QToolBar(), nullptr);
connect(m_loader, &EditTab::programChanged, ProcessorHandler::get(), &ProcessorHandler::loadProgram);

MODIFY
test/tst_riscv.cpp
test/tst_riscv.cpp
@@ -115,7 +115,7 @@ QString tst_RISCV::executeSimulator() {
bool maxCyclesReached = false;
unsigned cycles = 0;
do {
- ProcessorHandler::getProcessorNonConst()->clock();
+ ProcessorHandler::getProcessorNonConst()->clockProcessor();
cycles++;
@@ -136,7 +136,7 @@ QString tst_RISCV::executeSimulator() {
void tst_RISCV::runTests(const ProcessorID& id, const QString& testdir) {
// Connect the global reset request signal to directly resetting the processor
connect(RipesSettings::getObserver(RIPES_GLOBALSIGNAL_REQRESET), &SettingObserver::modified,
- [=] { ProcessorHandler::get()->getProcessorNonConst()->reset(); });
+ [=] { ProcessorHandler::get()->getProcessorNonConst()->resetProcessor(); });
const auto dir = QDir(testdir);
const auto testFiles = dir.entryList({"*.s"});

Decouple VSRTL::Design from RipesProcessor interface [WIP 2]