Add ProcessorHandler, a single point-of-access for processor control
MODIFY
external/VSRTL
external/VSRTL
-Subproject commit a17828564504abbd7d7623734443ac757b38b4d8
+Subproject commit acedab39500616eb1fdbf08b968127f78cc10d72

MODIFY
src/assembler.cpp
src/assembler.cpp
@@ -753,7 +753,7 @@ inline QStringList splitColon(const QString& string) {
}
} // namespace
-const QByteArray& Assembler::assembleBinaryFile(const QTextDocument& doc) {
+const QByteArray& Assembler::assemble(const QTextDocument& doc) {
// Called by codeEditor when syntax has been accepted, and the document should be assembled into binary
// Because of the previously accepted syntax, !no! error handling will be done, to ensure a fast execution
int line = 0;

MODIFY
src/assembler.h
src/assembler.h
class Assembler {
public:
Assembler();
- const QByteArray& assembleBinaryFile(const QTextDocument& doc);
+ const QByteArray& assemble(const QTextDocument& doc);
bool hasError() { return m_error; }
bool hasData() { return m_hasData; }
const QByteArray& getTextSegment() { return m_textSegment; }

MODIFY
src/edittab.cpp
src/edittab.cpp
@@ -43,9 +43,7 @@ void EditTab::clear() {
void EditTab::assemble() {
if (m_ui->assemblyedit->syntaxAccepted()) {
- // No tooltips available => syntax is accepted
-
- const QByteArray& ret = m_assembler->assembleBinaryFile(*m_ui->assemblyedit->document());
+ const QByteArray& ret = m_assembler->assemble(*m_ui->assemblyedit->document());
if (!m_assembler->hasError()) {
assemblingComplete(ret, true, 0x0);
if (m_assembler->hasData()) {
@@ -53,7 +51,7 @@ void EditTab::assemble() {
}
} else {
QMessageBox err;
- err.setText("Error in assembling file.");
+ err.setText("Error during assembling of program");
err.exec();
}
}
@@ -83,14 +81,14 @@ void EditTab::setDisassemblerText() {
m_ui->binaryedit->updateBreakpoints();
}
-void EditTab::assemblingComplete(const QByteArray& arr, bool clear, uint32_t baseAddress) {
+void EditTab::assemblingComplete(const QByteArray& data, bool clear, uint32_t baseAddress) {
if (clear)
Parser::getParser()->clear();
// Pretty hacky way to discern between the text and data segments
if (baseAddress > 0) {
- Parser::getParser()->loadFromByteArrayIntoData(arr);
+ Parser::getParser()->loadFromByteArrayIntoData(data);
} else {
- Parser::getParser()->loadFromByteArray(arr, m_ui->disassembledViewButton->isChecked(), baseAddress);
+ Parser::getParser()->loadFromByteArray(data, m_ui->disassembledViewButton->isChecked(), baseAddress);
setDisassemblerText();
}
emit updateSimulator();

MODIFY
src/edittab.h
src/edittab.h
@@ -37,7 +37,7 @@ private slots:
void on_disassembledViewButton_toggled(bool checked);
private:
- void assemblingComplete(const QByteArray& binaryCode, bool clear = true, uint32_t baseAddress = 0x0);
+ void assemblingComplete(const QByteArray& data, bool clear = true, uint32_t baseAddress = 0x0);
Ui::EditTab* m_ui;
Assembler* m_assembler = nullptr;

MODIFY
src/mainwindow.cpp
src/mainwindow.cpp
#include "edittab.h"
#include "memorytab.h"
#include "parser.h"
+#include "processorhandler.h"
#include "processortab.h"
#include "registerwidget.h"
@@ -25,6 +26,9 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), m_ui(new Ui::Main
setWindowIcon(QIcon(":/icons/logo.svg"));
showMaximized();
+ // Setup processor handler
+ m_processorHandler = new ProcessorHandler();
+
// Create tabs
m_stackedTabs = new QStackedWidget(this);
m_ui->centrallayout->addWidget(m_stackedTabs);
@@ -36,7 +40,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), m_ui(new Ui::Main
tb = addToolBar("Processor");
tb->setVisible(false);
- m_processorTab = new ProcessorTab(tb, this);
+ m_processorTab = new ProcessorTab(*m_processorHandler, tb, this);
m_stackedTabs->insertWidget(1, m_processorTab);
tb = addToolBar("Processor");

MODIFY
src/mainwindow.h
src/mainwindow.h
@@ -12,6 +12,7 @@ QT_FORWARD_DECLARE_CLASS(QStackedWidget)
class EditTab;
class MemoryTab;
class ProcessorTab;
+class ProcessorHandler;
QT_FORWARD_DECLARE_CLASS(QActionGroup)
@@ -58,4 +59,5 @@ private:
ProcessorTab* m_processorTab = nullptr;
EditTab* m_editTab = nullptr;
MemoryTab* m_memoryTab = nullptr;
+ ProcessorHandler* m_processorHandler = nullptr;
};

ADD
src/processorhandler.cpp
+#include "processorhandler.h"
+
+#include "processorregistry.h"
+
+ProcessorHandler::ProcessorHandler() {
+ // Contruct the default processor
+ selectProcessor(m_currentProcessorID);
+}
+
+void ProcessorHandler::loadProgramData(const std::map<uint32_t, QByteArray&>& segments) {
+ auto& mem = m_currentProcessor->getMemory();
+
+ mem.clearInitializationMemories();
+ for (const auto& seg : segments) {
+ mem.addInitializationMemory(seg.first, seg.second.data(), sizeof(char));
+ }
+}
+
+void ProcessorHandler::selectProcessor(ProcessorID id) {
+ m_currentProcessorID = id;
+ m_currentProcessor = ProcessorRegistry::constructProcessor(m_currentProcessorID);
+}

ADD
src/processorhandler.h
+#pragma once
+
+#include "processorregistry.h"
+
+/**
+ * @brief The ProcessorHandler class
+ * Manages construction and destruction of a VSRTL processor design, when selecting between processors.
+ * Manages all interaction and control of the current processor.
+ */
+class ProcessorHandler {
+public:
+ ProcessorHandler();
+
+ Ripes::RipesProcessor* getProcessor() { return m_currentProcessor.get(); }
+ ProcessorID currentID() const { return m_currentProcessorID; }
+ void selectProcessor(ProcessorID id);
+ void loadProgramData(const std::map<uint32_t, QByteArray&>& segments);
+
+private:
+ static constexpr ProcessorID defaultProcessor = ProcessorID::RISCV_SS;
+ ProcessorID m_currentProcessorID = defaultProcessor;
+ std::unique_ptr<Ripes::RipesProcessor> m_currentProcessor;
+};

MODIFY
src/processorregistry.h
src/processorregistry.h
#include <QMetaType>
#include <map>
+#include <memory>
#include "processors/ripesprocessor.h"
@@ -21,39 +22,19 @@ Q_DECLARE_METATYPE(ProcessorID);
class ProcessorRegistry {
public:
- static constexpr ProcessorID defaultProcessor = ProcessorID::RISCV_SS;
-
using ProcessorMap = std::map<ProcessorID, ProcessorDescription>;
- static Ripes::RipesProcessor* getProcessor() { return instance().m_currentProcessor.get(); }
- static ProcessorID currentProcessorID() { return instance().m_currentProcessorID; }
static const ProcessorMap& getAvailableProcessors() { return instance().m_descriptions; }
-
- /**
- * @brief selectProcessor
- * @param id
- * @returns true if current processor changed
- */
- static bool selectProcessor(ProcessorID id) {
- if (id == instance().m_currentProcessorID) {
- return false;
- }
-
- // Create the new processor...
- instance().m_currentProcessorID = id;
- instance().createProcessor();
- return true;
- }
-
-private:
- void createProcessor() {
- switch (m_currentProcessorID) {
+ static std::unique_ptr<Ripes::RipesProcessor> constructProcessor(ProcessorID id) {
+ switch (id) {
case ProcessorID::RISCV_5S_WOF:
case ProcessorID::RISCV_5S_WF:
- case ProcessorID::RISCV_SS:
- m_currentProcessor = std::make_unique<vsrtl::RISCV::SingleCycleRISCV>();
+ case ProcessorID::RISCV_SS: {
+ return std::make_unique<vsrtl::RISCV::SingleCycleRISCV>();
+ }
}
}
+private:
ProcessorRegistry() {
// Initialize processors
@@ -68,20 +49,18 @@ private:
// RISC-V 5-Stage with forwarding
desc.id = ProcessorID::RISCV_5S_WF;
desc.ISA = "RV32IM";
- desc.name = "RISC-V 5-Stage with forwarding";
+ desc.name = "RISC-V 5-Stage w/ forwarding";
desc.description = "A 5-Stage in-order RISC-V processor with hazard detection and forwarding.";
m_descriptions[desc.id] = desc;
// RISC-V 5-stage without forwarding
desc.id = ProcessorID::RISCV_5S_WOF;
desc.ISA = "RV32IM";
- desc.name = "RISC-V 5-Stage without forwarding";
+ desc.name = "RISC-V 5-Stage wo/ forwarding";
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.";
m_descriptions[desc.id] = desc;
-
- createProcessor();
}
static ProcessorRegistry& instance() {
@@ -89,8 +68,5 @@ private:
return pr;
}
- ProcessorID m_currentProcessorID = defaultProcessor;
- std::unique_ptr<Ripes::RipesProcessor> m_currentProcessor;
-
ProcessorMap m_descriptions;
};

MODIFY
src/processors/ripesprocessor.h
src/processors/ripesprocessor.h
@@ -53,13 +53,13 @@ public:
virtual StageInfo stageInfo(unsigned int stageIndex) const = 0;
/**
- * @brief getMemoryPtr
+ * @brief getMemory
* @return pointer to the address space utilized by the implementing processor
*/
- virtual std::unordered_map<uint32_t, uint8_t>* getMemoryPtr() = 0;
+ virtual vsrtl::SparseArray& getMemory() = 0;
/**
- * @brief setEntryPoint
+ * @brief setProgramCounter
* Sets the program counter of the processor to @param address
*/
virtual void setProgramCounter(uint32_t address) = 0;

MODIFY
src/processors/ss/riscv_ss.h
src/processors/ss/riscv_ss.h
@@ -146,7 +146,7 @@ public:
pc_reg->forceValue(0, address);
propagateDesign();
}
- std::unordered_map<uint32_t, uint8_t>* getMemoryPtr() override { return &m_memory->data; }
+ SparseArray& getMemory() override { return *m_memory; }
};
} // namespace RISCV
} // namespace vsrtl

MODIFY
src/processorselectiondialog.cpp
src/processorselectiondialog.cpp
#include <QDialogButtonBox>
#include <QListWidget>
-#include "processorregistry.h"
-
-ProcessorSelectionDialog::ProcessorSelectionDialog(QWidget* parent)
- : QDialog(parent), ui(new Ui::ProcessorSelectionDialog) {
+ProcessorSelectionDialog::ProcessorSelectionDialog(const ProcessorHandler& handler, QWidget* parent)
+ : QDialog(parent), m_handler(handler), ui(new Ui::ProcessorSelectionDialog) {
ui->setupUi(this);
setWindowTitle("Select Processor");
@@ -15,7 +13,7 @@ ProcessorSelectionDialog::ProcessorSelectionDialog(QWidget* parent)
for (auto& desc : ProcessorRegistry::getAvailableProcessors()) {
QListWidgetItem* item = new QListWidgetItem(desc.second.name);
item->setData(Qt::UserRole, QVariant::fromValue(desc.second.id));
- if (desc.second.id == ProcessorRegistry::currentProcessorID()) {
+ if (desc.second.id == m_handler.currentID()) {
auto font = item->font();
font.setBold(true);
item->setFont(font);
@@ -35,7 +33,8 @@ ProcessorSelectionDialog::~ProcessorSelectionDialog() {
void ProcessorSelectionDialog::accept() {
const ProcessorID id = qvariant_cast<ProcessorID>(ui->processorList->currentItem()->data(Qt::UserRole));
- if (ProcessorRegistry::selectProcessor(id)) {
+ selectedID = id;
+ if (id != m_handler.currentID()) {
// New processor model was selected
return QDialog::accept();
} else {

MODIFY
src/processorselectiondialog.h
src/processorselectiondialog.h
#include <QDialog>
#include <QListWidget>
+#include "processorhandler.h"
+#include "processorregistry.h"
+
namespace Ui {
class ProcessorSelectionDialog;
}
@@ -11,9 +14,11 @@ class ProcessorSelectionDialog : public QDialog {
Q_OBJECT
public:
- explicit ProcessorSelectionDialog(QWidget* parent = nullptr);
+ explicit ProcessorSelectionDialog(const ProcessorHandler& handler, QWidget* parent = nullptr);
~ProcessorSelectionDialog();
+ ProcessorID selectedID;
+
public slots:
virtual void accept() override;
@@ -22,4 +27,6 @@ private slots:
private:
Ui::ProcessorSelectionDialog* ui;
+
+ const ProcessorHandler& m_handler;
};

MODIFY
src/processortab.cpp
src/processortab.cpp
#include "processors/ripesprocessor.h"
-ProcessorTab::ProcessorTab(QToolBar* toolbar, QWidget* parent) : RipesTab(toolbar, parent), m_ui(new Ui::ProcessorTab) {
+ProcessorTab::ProcessorTab(ProcessorHandler& handler, QToolBar* toolbar, QWidget* parent)
+ : RipesTab(toolbar, parent), m_handler(handler), m_ui(new Ui::ProcessorTab) {
m_ui->setupUi(this);
m_vsrtlWidget = m_ui->vsrtlWidget;
// Load the default processor
- m_vsrtlWidget->setDesign(ProcessorRegistry::getProcessor());
+ m_vsrtlWidget->setDesign(m_handler.getProcessor());
setupSimulatorActions();
@@ -133,10 +134,12 @@ void ProcessorTab::setupSimulatorActions() {
}
void ProcessorTab::processorSelection() {
- ProcessorSelectionDialog diag;
+ ProcessorSelectionDialog diag(m_handler);
if (diag.exec()) {
// New processor model was selected
- m_vsrtlWidget->setDesign(ProcessorRegistry::getProcessor());
+ m_vsrtlWidget->clearDesign();
+ m_handler.selectProcessor(diag.selectedID);
+ m_vsrtlWidget->setDesign(m_handler.getProcessor());
}
}

MODIFY
src/processortab.h
src/processortab.h
#include "pipeline.h"
#include "pipelinetable.h"
#include "pipelinetablemodel.h"
+#include "processorhandler.h"
#include "ripestab.h"
#include "graphics/pipelinewidget.h"
@@ -31,12 +32,16 @@ class ProcessorTab : public RipesTab {
Q_OBJECT
public:
- ProcessorTab(QToolBar* toolbar, QWidget* parent = nullptr);
+ ProcessorTab(ProcessorHandler& handler, QToolBar* toolbar, QWidget* parent = nullptr);
~ProcessorTab() override;
void initRegWidget();
void initInstructionView();
+signals:
+ void update();
+ void appendToLog(QString string);
+
public slots:
void restart();
void run();
@@ -52,10 +57,6 @@ private slots:
void showPipeliningTable();
void updateMetrics();
-signals:
- void update();
- void appendToLog(QString string);
-
private:
void setupSimulatorActions();
void updateActionState();
@@ -66,6 +67,7 @@ private:
InstructionModel* m_instrModel;
vsrtl::VSRTLWidget* m_vsrtlWidget = nullptr;
+ ProcessorHandler& m_handler;
// Actions
QAction* m_selectProcessorAction = nullptr;

Add ProcessorHandler, a single point-of-access for processor control