Rework/clean-up tracking of currently enabled ISA
ISA can be accessed by either:
Requesting the currently loaded processor
or, statically asking a (non-instantiated) processor
This commit mainly ensures that the current ISA is used when
instantiating the assembler.
MODIFY
src/editor/codeeditor.cpp
src/editor/codeeditor.cpp
@@ -108,8 +108,10 @@ bool CodeEditor::eventFilter(QObject* /*observed*/, QEvent* event) {
}
void CodeEditor::rehighlight() {
+ if (m_highlighter) {
m_highlighter->rehighlight();
}
+}
bool CodeEditor::event(QEvent* event) {
// Override event handler for receiving tool tips
@@ -156,7 +158,7 @@ void CodeEditor::setSourceType(SourceType type, const std::set<QString>& support
switch (m_sourceType) {
case SourceType::Assembly: {
auto* isa = ProcessorHandler::get()->currentISA();
- if (isa->isaID() == ISA::RV32IM) {
+ if (isa->isaID() == ISA::RV32I) {
m_highlighter = std::make_unique<RVSyntaxHighlighter>(document(), m_errors, supportedOpcodes);
} else {
Q_ASSERT(false && "Unknown ISA selected");

MODIFY
src/edittab.cpp
src/edittab.cpp
@@ -57,8 +57,6 @@ EditTab::EditTab(QToolBar* toolbar, QWidget* parent) : RipesTab(toolbar, parent)
m_ui->programViewer->setReadOnly(true);
- m_assembler = std::make_unique<AssemblerTmp::RV32I_Assembler>();
-
connect(m_ui->setAssemblyInput, &QRadioButton::toggled, this, &EditTab::sourceTypeChanged);
connect(m_ui->setCInput, &QRadioButton::toggled, this, &EditTab::sourceTypeChanged);
connect(m_ui->setCInput, &QRadioButton::toggled, m_buildAction, &QAction::setEnabled);
@@ -75,8 +73,9 @@ EditTab::EditTab(QToolBar* toolbar, QWidget* parent) : RipesTab(toolbar, parent)
connect(ProcessorHandler::get(), &ProcessorHandler::runFinished,
[=] { m_buildAction->setEnabled(m_ui->setCInput->isChecked()); });
- enableEditor();
+ onProcessorChanged();
sourceTypeChanged();
+ enableEditor();
}
void EditTab::showSymbolNavigator() {
@@ -190,6 +189,21 @@ void EditTab::sourceTypeChanged() {
m_ui->codeEditor->setSourceType(m_currentSourceType, m_assembler->getOpcodes());
}
+void EditTab::createAssemblerForCurrentISA() {
+ const auto& ISA = ProcessorHandler::get()->currentISA();
+
+ if (auto* rvisa = dynamic_cast<const ISAInfo<ISA::RV32I>*>(ISA)) {
+ m_assembler = std::make_unique<AssemblerTmp::RV32I_Assembler>(rvisa);
+ } else {
+ Q_UNREACHABLE();
+ }
+}
+
+void EditTab::onProcessorChanged() {
+ createAssemblerForCurrentISA();
+ assemble();
+}
+
void EditTab::emitProgramChanged() {
emit programChanged(m_activeProgram);
updateProgramViewer();

MODIFY
src/edittab.h
src/edittab.h
@@ -47,8 +47,8 @@ signals:
void editorStateChanged(bool enabled);
public slots:
+ void onProcessorChanged();
void updateProgramViewerHighlighting();
-
void emitProgramChanged();
/**
@@ -72,6 +72,7 @@ private:
void assemble();
void compile();
+ void createAssemblerForCurrentISA();
void updateProgramViewer();
bool loadFlatBinaryFile(Program& program, QFile& file, unsigned long entryPoint, unsigned long loadAt);
bool loadSourceFile(Program& program, QFile& file);

MODIFY
src/isainfo.h
src/isainfo.h
#include <QMap>
#include <QString>
+#include <set>
#include "elfio/elf_types.hpp"
namespace Ripes {
/// Currently supported ISAs
-enum class ISA { RV32IM };
-const static std::map<ISA, QString> ISANames = {{ISA::RV32IM, "RISC-V"}};
+enum class ISA { RV32I };
+const static std::map<ISA, QString> ISAFamilyNames = {{ISA::RV32I, "RISC-V"}};
class ISAInfoBase {
public:
@@ -42,18 +43,15 @@ public:
*/
virtual QString elfSupportsFlags(unsigned flags) const = 0;
+ virtual const QStringList& supportedExtensions() const = 0;
+ virtual const QStringList& enabledExtensions() const = 0;
+
protected:
ISAInfoBase() {}
};
template <ISA isa>
-class ISAInfo : public ISAInfoBase {
-public:
- static const ISAInfo<isa>* instance();
-
-private:
- ISAInfo<isa>() {}
-};
+class ISAInfo : public ISAInfoBase {};
// ==================================== RISCV ====================================
namespace {
@@ -119,8 +117,19 @@ const static std::map<RVElfFlags, QString> RVELFFlagStrings {{RVC, "RVC"}, {Floa
} // namespace
template <>
-class ISAInfo<ISA::RV32IM> : public ISAInfoBase {
+class ISAInfo<ISA::RV32I> : public ISAInfoBase {
public:
+ ISAInfo<ISA::RV32I>(const QStringList extensions) {
+ // Validate extensions
+ for (const auto& ext : extensions) {
+ if (m_supportedExtensions.contains(ext)) {
+ m_enabledExtensions << ext;
+ } else {
+ assert(false && "Invalid extension specified for ISA");
+ }
+ }
+ }
+
enum SysCall {
None = 0,
PrintInt = 1,
@@ -143,13 +152,9 @@ public:
brk = 214,
Open = 1024
};
- static const ISAInfo<ISA::RV32IM>* instance() {
- static ISAInfo<ISA::RV32IM> pr;
- return &pr;
- }
- QString name() const override { return "RV32IM"; }
- ISA isaID() const override { return ISA::RV32IM; }
+ QString name() const override { return "RV32I" + enabledExtensions().join(""); }
+ ISA isaID() const override { return ISA::RV32I; }
unsigned int regCnt() const override { return 32; }
QString regName(unsigned i) const override {
@@ -197,6 +202,13 @@ public:
}
return err;
}
+
+ const QStringList& supportedExtensions() const override { return m_supportedExtensions; }
+ const QStringList& enabledExtensions() const override { return m_enabledExtensions; }
+
+private:
+ QStringList m_enabledExtensions;
+ QStringList m_supportedExtensions = {"M"};
};
} // namespace Ripes

MODIFY
src/mainwindow.cpp
src/mainwindow.cpp
@@ -98,7 +98,7 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), m_ui(new Ui::Main
// Reset and program reload signals
connect(m_memoryTab, &MemoryTab::reqProcessorReset, m_processorTab, &ProcessorTab::reset);
connect(ProcessorHandler::get(), &ProcessorHandler::reqProcessorReset, m_processorTab, &ProcessorTab::reset);
- connect(ProcessorHandler::get(), &ProcessorHandler::reqReloadProgram, m_editTab, &EditTab::emitProgramChanged);
+ connect(ProcessorHandler::get(), &ProcessorHandler::processorChanged, m_editTab, &EditTab::onProcessorChanged);
connect(ProcessorHandler::get(), &ProcessorHandler::stopping, m_processorTab, &ProcessorTab::pause);
connect(m_processorTab, &ProcessorTab::processorWasReset, [=] { SystemIO::reset(); });

MODIFY
src/processorhandler.cpp
src/processorhandler.cpp
@@ -175,8 +175,7 @@ void ProcessorHandler::selectProcessor(const ProcessorID& id, RegisterInitializa
m_currentProcessor->verifyAndInitialize();
- // Processor loaded. Request for the currently assembled program to be loaded into the processor
- emit reqReloadProgram();
+ emit processorChanged();
}
int ProcessorHandler::getCurrentProgramSize() const {

MODIFY
src/processorhandler.h
src/processorhandler.h
#include <QFutureWatcher>
#include <QObject>
-#include "processorregistry.h"
#include "assembler/program.h"
+#include "processorregistry.h"
#include "syscall/ripes_syscall.h"
#include "vsrtl_widget.h"
@@ -34,6 +34,7 @@ public:
std::weak_ptr<const Program> getProgram() const { return m_program; }
const ISAInfoBase* currentISA() const { return m_currentProcessor->implementsISA(); }
const SyscallManager& getSyscallManager() const { return *m_syscallManager; }
+
/**
* @brief loadProcessorToWidget
* Loads the current processor to the @param VSRTLWidget. Required given that ProcessorHandler::getProcessor returns
@@ -130,6 +131,13 @@ public:
void stopRun();
signals:
+
+ /**
+ * @brief processorChanged
+ * Emitted when a new processor has been chosen.
+ */
+ void processorChanged();
+
/**
* @brief reqProcessorReset
* Emitted whenever changes to the internal state of the processor has been made, and a reset of any depending
@@ -137,13 +145,6 @@ signals:
*/
void reqProcessorReset();
- /**
- * @brief reqReloadProgram
- * Emitted whenever the processor has been changed, and we require the currently assembled program to be inserted
- * into the newly loaded processors memory
- */
- void reqReloadProgram();
-
/**
* @brief exit
* end the current simulation, disallowing further clocking of the processor unless the processor is reset.

MODIFY
src/processorregistry.h
src/processorregistry.h
@@ -72,7 +72,7 @@ private:
// RISC-V single cycle
ProcessorDescription desc;
desc.id = ProcessorID::RVSS;
- desc.isa = ISAInfo<ISA::RV32IM>::instance();
+ desc.isa = vsrtl::core::RVSS::ISA();
desc.name = "Single Cycle Processor";
desc.description = "A single cycle processor";
desc.layouts = {{"Standard", ":/layouts/RISC-V/rvss/rv_ss_standard_layout.json", {0.5}},
@@ -83,7 +83,7 @@ private:
// RISC-V 5-Stage
desc = ProcessorDescription();
desc.id = ProcessorID::RV5S;
- desc.isa = ISAInfo<ISA::RV32IM>::instance();
+ desc.isa = vsrtl::core::RV5S::ISA();
desc.name = "5-Stage Processor";
desc.description = "A 5-Stage in-order processor with hazard detection/elimination and forwarding.";
desc.layouts = {{"Standard", ":/layouts/RISC-V/rv5s/rv5s_standard_layout.json", {0.08, 0.29, 0.55, 0.75, 0.87}},
@@ -94,7 +94,7 @@ private:
// RISC-V 5-stage without hazard detection
desc = ProcessorDescription();
desc.id = ProcessorID::RV5S_NO_HZ;
- desc.isa = ISAInfo<ISA::RV32IM>::instance();
+ desc.isa = vsrtl::core::RV5S_NO_HZ::ISA();
desc.name = "5-Stage Processor w/o hazard detection";
desc.description = "A 5-Stage in-order processor with forwarding but no hazard detection/elimination.";
desc.layouts = {
@@ -106,7 +106,7 @@ private:
// RISC-V 5-stage without forwarding or hazard detection
desc = ProcessorDescription();
desc.id = ProcessorID::RV5S_NO_FW_HZ;
- desc.isa = ISAInfo<ISA::RV32IM>::instance();
+ desc.isa = vsrtl::core::RV5S_NO_FW_HZ::ISA();
desc.name = "5-Stage Processor w/o forwarding or hazard detection";
desc.description = "A 5-Stage in-order processor with no forwarding or hazard detection/elimination.";
desc.layouts = {{"Standard",

MODIFY
src/processorselectiondialog.cpp
src/processorselectiondialog.cpp
@@ -17,7 +17,7 @@ ProcessorSelectionDialog::ProcessorSelectionDialog(QWidget* parent)
// Initialize top level ISA items
m_ui->processors->setHeaderHidden(true);
std::map<ISA, QTreeWidgetItem*> isaItems;
- for (const auto& isa : ISANames) {
+ for (const auto& isa : ISAFamilyNames) {
auto* isaItem = new QTreeWidgetItem({isa.second});
isaItems[isa.first] = isaItem;
isaItem->setFlags(isaItem->flags() & ~(Qt::ItemIsSelectable));

MODIFY
src/syscall/riscv_syscall.h
src/syscall/riscv_syscall.h
@@ -38,31 +38,31 @@ class RISCVSyscallManager : public SyscallManagerT<RISCVSyscall> {
public:
RISCVSyscallManager() {
// Print syscalls
- emplace<PrintIntSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32IM>::PrintInt);
- emplace<PrintFloatSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32IM>::PrintFloat);
- emplace<PrintStrSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32IM>::PrintStr);
- emplace<PrintCharSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32IM>::PrintChar);
- emplace<PrintHexSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32IM>::PrintIntHex);
- emplace<PrintBinarySyscall<RISCVSyscall>>(ISAInfo<ISA::RV32IM>::PrintIntBinary);
- emplace<PrintUnsignedSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32IM>::PrintIntUnsigned);
+ emplace<PrintIntSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32I>::PrintInt);
+ emplace<PrintFloatSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32I>::PrintFloat);
+ emplace<PrintStrSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32I>::PrintStr);
+ emplace<PrintCharSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32I>::PrintChar);
+ emplace<PrintHexSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32I>::PrintIntHex);
+ emplace<PrintBinarySyscall<RISCVSyscall>>(ISAInfo<ISA::RV32I>::PrintIntBinary);
+ emplace<PrintUnsignedSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32I>::PrintIntUnsigned);
// Control syscalls
- emplace<ExitSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32IM>::Exit);
- emplace<Exit2Syscall<RISCVSyscall>>(ISAInfo<ISA::RV32IM>::Exit2);
- emplace<BrkSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32IM>::brk);
+ emplace<ExitSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32I>::Exit);
+ emplace<Exit2Syscall<RISCVSyscall>>(ISAInfo<ISA::RV32I>::Exit2);
+ emplace<BrkSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32I>::brk);
// File syscalls
- emplace<CloseSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32IM>::Close);
- emplace<LSeekSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32IM>::LSeek);
- emplace<ReadSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32IM>::Read);
- emplace<OpenSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32IM>::Open);
- emplace<WriteSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32IM>::Write);
- emplace<GetCWDSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32IM>::GetCWD);
- emplace<FStatSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32IM>::FStat);
+ emplace<CloseSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32I>::Close);
+ emplace<LSeekSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32I>::LSeek);
+ emplace<ReadSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32I>::Read);
+ emplace<OpenSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32I>::Open);
+ emplace<WriteSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32I>::Write);
+ emplace<GetCWDSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32I>::GetCWD);
+ emplace<FStatSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32I>::FStat);
// Time syscalls
- emplace<CyclesSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32IM>::Cycles);
- emplace<TimeMsSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32IM>::TimeMs);
+ emplace<CyclesSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32I>::Cycles);
+ emplace<TimeMsSyscall<RISCVSyscall>>(ISAInfo<ISA::RV32I>::TimeMs);
}
};

Rework/clean-up tracking of currently enabled ISA

ISA can be accessed by either:
- Requesting the currently loaded processor
- or, statically asking a (non-instantiated) processor
This commit mainly ensures that the current ISA is used when
instantiating the assembler.