Implement processor finalizing when fetching out-of-.text instructions
This commit ensures that the processor is set to start finalizing once it has
been detected that it will start to fetch instructions from outside of the .text
segment of the currently loaded program.
MODIFY
src/assembler.cpp
src/assembler.cpp
@@ -807,9 +807,9 @@ const QByteArray& Assembler::assemble(const QTextDocument& doc) {
return m_textSegment;
}
-const std::map<uint32_t, QByteArray*> Assembler::getSegments() {
- std::map<uint32_t, QByteArray*> segs;
- segs[0] = &m_textSegment;
- segs[DATASTART] = &m_dataSegment;
- return segs;
+const Program Assembler::getProgram() {
+ Program p;
+ p.text = {0, &m_textSegment};
+ p.others.push_back({DATASTART, &m_dataSegment});
+ return p;
}

MODIFY
src/assembler.h
src/assembler.h
#include <QByteArray>
#include <QTextDocument>
+#include "program.h"
+
class Assembler {
public:
Assembler();
@@ -14,7 +16,7 @@ public:
const QByteArray& getDataSegment() { return m_dataSegment; }
void clear() { m_textSegment.clear(); }
- const std::map<uint32_t, QByteArray*> getSegments();
+ const Program getProgram();
private:
uint32_t getRegisterNumber(const QString& reg);

MODIFY
src/edittab.cpp
src/edittab.cpp
@@ -42,7 +42,7 @@ void EditTab::clear() {
}
void EditTab::emitProgramChanged() {
- emit programChanged(m_assembler->getSegments());
+ emit programChanged(m_assembler->getProgram());
}
void EditTab::assemble() {
@@ -53,7 +53,7 @@ void EditTab::assemble() {
if (m_assembler->hasData()) {
assemblingComplete(m_assembler->getDataSegment(), false, DATASTART);
}
- emit programChanged(m_assembler->getSegments());
+ emitProgramChanged();
} else {
QMessageBox err;
err.setText("Error during assembling of program");

MODIFY
src/edittab.h
src/edittab.h
#include <map>
#include "assembler.h"
+#include "program.h"
#include "ripestab.h"
namespace Ui {
@@ -32,7 +33,7 @@ public:
signals:
void updateSimulator(); // Emitted when a file has been successfully loaded or assembled, and binary info must be
// sent to the processor
- void programChanged(const std::map<uint32_t, QByteArray*> program);
+ void programChanged(const Program& program);
public slots:
void emitProgramChanged();

MODIFY
src/processorhandler.cpp
src/processorhandler.cpp
#include "processorhandler.h"
#include "processorregistry.h"
+#include "program.h"
#include <QMessageBox>
@@ -9,14 +10,18 @@ ProcessorHandler::ProcessorHandler() {
selectProcessor(m_currentProcessorID);
}
-void ProcessorHandler::loadProgram(const std::map<uint32_t, QByteArray*>& segments) {
+void ProcessorHandler::loadProgram(const Program& p) {
auto& mem = m_currentProcessor->getMemory();
mem.clearInitializationMemories();
- for (const auto& seg : segments) {
+ mem.addInitializationMemory(p.text.first, p.text.second->data(), p.text.second->length());
+ for (const auto& seg : p.others) {
mem.addInitializationMemory(seg.first, seg.second->data(), seg.second->length());
}
+ // Set the valid execution range to be contained within the .text segment.
+ m_validExecutionRange = {p.text.first, p.text.first + p.text.second->length()};
+
emit reqProcessorReset();
}
@@ -69,6 +74,9 @@ void ProcessorHandler::processorFinished() {
emit exit();
}
-void ProcessorHandler::canClockProcessor() const {
- const auto pc = m_currentProcessor->pcForStage(0);
+void ProcessorHandler::checkValidExecutionRange() const {
+ const auto pc = m_currentProcessor->nextPcForStage(0);
+ if (!(m_validExecutionRange.first <= pc && pc < m_validExecutionRange.second)) {
+ m_currentProcessor->finalize();
+ }
}

MODIFY
src/processorhandler.h
src/processorhandler.h
#include <QObject>
#include "processorregistry.h"
+#include "program.h"
/**
* @brief The ProcessorHandler class
@@ -25,11 +26,12 @@ public:
void selectProcessor(ProcessorID id);
/**
- * @brief canClockProcessor
- * Checks whether it is valid to further clock the processor. A check will be performed to see whether the current
- * program counter is at the end of the current .text segment
+ * @brief checkValidExecutionRange
+ * Checks whether the processor, given continued clocking, that it will execute within the currently validated
+ * execution range. If the processor in the next cycle will start to fetch instructions outside of the validated
+ * range, the processor is instead requested to start finalizing.
*/
- void canClockProcessor() const;
+ void checkValidExecutionRange() const;
signals:
/**
@@ -59,7 +61,7 @@ signals:
void exit();
public slots:
- void loadProgram(const std::map<uint32_t, QByteArray*>& segments);
+ void loadProgram(const Program& p);
private slots:
void handleSysCall();
@@ -69,4 +71,12 @@ private:
static constexpr ProcessorID defaultProcessor = ProcessorID::RISCV_SS;
ProcessorID m_currentProcessorID = defaultProcessor;
std::unique_ptr<Ripes::RipesProcessor> m_currentProcessor;
+
+ /**
+ * @brief m_validExecutionRange
+ * Address range which the processor is allowed to fetch instructions from. Currently, only a single range is
+ * supported which shall encapsulate the .text segment. If, for instance JIT compilation and execution is required
+ * in the future, this range should be expanded to also include the .data or other relevant program sections.
+ */
+ std::pair<uint32_t, uint32_t> m_validExecutionRange;
};

MODIFY
src/processors/ripesprocessor.h
src/processors/ripesprocessor.h
@@ -48,6 +48,13 @@ public:
*/
virtual unsigned int pcForStage(unsigned int stageIndex) const = 0;
+ /**
+ * @brief nextPcForStage
+ * @param stageIndex
+ * @return Next-state program counter for stage @param stageIndex
+ */
+ virtual unsigned int nextPcForStage(unsigned int stageIndex) const = 0;
+
/**
* @brief stageInfo
* @param stageIndex

MODIFY
src/processors/ss/riscv_ss.h
src/processors/ss/riscv_ss.h
@@ -149,6 +149,7 @@ public:
unsigned int stageCount() const override { return 1; }
unsigned int breakpointBreaksStage() const override { return 0; }
unsigned int pcForStage(unsigned int) const override { return pc_reg->out.uValue(); }
+ unsigned int nextPcForStage(unsigned int) const override { return pc_src->out.uValue(); }
Ripes::StageInfo stageInfo(unsigned int stageIndex) const override { return {}; }
void setProgramCounter(uint32_t address) override {
pc_reg->forceValue(0, address);
@@ -171,8 +172,13 @@ public:
}
}
+ void reset() override {
+ Design::reset();
+ m_finishInNextCycle = false;
+ }
+
private:
bool m_finishInNextCycle = false;
-};
+}; // namespace RISCV
} // namespace RISCV
} // namespace vsrtl

MODIFY
src/processortab.cpp
src/processortab.cpp
@@ -248,6 +248,7 @@ void ProcessorTab::setCurrentInstruction(int row) {
void ProcessorTab::clock() {
m_vsrtlWidget->clock();
+ m_handler.checkValidExecutionRange();
auto pipeline = Pipeline::getPipeline();
auto state = pipeline->step();

ADD
src/program.h
+#pragma once
+
+#include <QByteArray>
+#include <vector>
+
+/**
+ * @brief The Program struct
+ * Wrapper around a program to be loaded into simulator memory. Text section shall contain the instructions of the
+ * program. Others section may contain all other program sections (.bss, .data, ...)
+ */
+struct Program {
+ using Section = std::pair<uint32_t, QByteArray*>;
+ Section text;
+ std::vector<Section> others;
+};

Implement processor finalizing when fetching out-of-.text instructions

This commit ensures that the processor is set to start finalizing once it has
been detected that it will start to fetch instructions from outside of the .text
segment of the currently loaded program.