Make section information be a property of Programs
MODIFY
src/assembler.cpp
src/assembler.cpp
#include <QRegularExpression>
#include <QTextBlock>
+#define DATA_START 0x10000000
+
namespace Ripes {
namespace {
@@ -697,7 +699,7 @@ void Assembler::unpackOp(const QStringList& _fields, int& pos) {
if (m_inDataSegment) {
m_labelPosMap[string] =
// Offset label by data segment position and length of the data segment
- m_dataSegment.length() + ProcessorHandler::get()->getSetup().segmentPtrs.at(ProgramSegment::Data);
+ m_dataSegment.length() + DATA_START;
} else {
// The label is in the text segment. Label is defined without an offset
m_labelPosMap[string] = pos * 4;
@@ -812,8 +814,9 @@ const QByteArray& Assembler::assemble(const QTextDocument& doc) {
const Program Assembler::getProgram() {
Program p;
- p.text = {ProcessorHandler::get()->getSetup().segmentPtrs.at(ProgramSegment::Text), m_textSegment};
- p.others.push_back({ProcessorHandler::get()->getSetup().segmentPtrs.at(ProgramSegment::Data), m_dataSegment});
+ p.sections.push_back({TEXT_SECTION_NAME, 0, m_textSegment});
+ p.sections.push_back({".data", DATA_START, m_dataSegment});
return p;
}
+
} // namespace Ripes

MODIFY
src/edittab.cpp
src/edittab.cpp
@@ -123,9 +123,12 @@ void EditTab::enableAssemblyInput() {
}
void EditTab::setDisassemblerText() {
- auto text = m_ui->disassembledViewButton->isChecked()
- ? Parser::getParser()->disassemble(m_activeProgram.text.second)
- : Parser::getParser()->binarize(m_activeProgram.text.second);
+ const auto* textSection = m_activeProgram.getSection(TEXT_SECTION_NAME);
+ if (!textSection)
+ return;
+
+ auto text = m_ui->disassembledViewButton->isChecked() ? Parser::getParser()->disassemble(textSection->data)
+ : Parser::getParser()->binarize(textSection->data);
m_ui->binaryedit->setPlainText(text);
}
@@ -146,11 +149,12 @@ void EditTab::on_disassembledViewButton_toggled() {
}
bool EditTab::loadFlatBinaryFile(Program& program, QFile& file, uint32_t entryPoint, uint32_t loadAt) {
- QByteArray text;
- text = file.readAll();
+ ProgramSection section;
+ section.name = TEXT_SECTION_NAME;
+ section.address = loadAt;
+ section.data = file.readAll();
- program.text.first = loadAt;
- program.text.second = text;
+ program.sections.push_back(section);
program.entryPoint = entryPoint;
m_ui->curInputSrcLabel->setText("Flat binary");
@@ -159,7 +163,7 @@ bool EditTab::loadFlatBinaryFile(Program& program, QFile& file, uint32_t entryPo
return true;
}
-bool EditTab::loadAssemblyFile(Program& program, QFile& file) {
+bool EditTab::loadAssemblyFile(Program&, QFile& file) {
enableEditor();
setAssemblyText(file.readAll());
return true;

MODIFY
src/gotocombobox.cpp
src/gotocombobox.cpp
@@ -22,16 +22,19 @@ void GoToComboBox::showPopup() {
addItem("Select", QVariant::fromValue<GoToFunction>(GoToFunction::Select));
addItem("Address...", QVariant::fromValue<GoToFunction>(GoToFunction::Address));
- for (const auto& seg : ProcessorHandler::get()->getSetup().segmentPtrs) {
- addItem(s_programSegmentName.at(seg.first), QVariant::fromValue<ProgramSegment>(seg.first));
+
+ if (ProcessorHandler::get()->getProgram()) {
+ for (const auto& section : ProcessorHandler::get()->getProgram()->sections) {
+ addItem(section.name, QVariant::fromValue<GoToFunction>(GoToFunction::Section));
+ }
}
+
QComboBox::showPopup();
}
void GoToComboBox::signalFilter(int index) {
const auto& value = itemData(index);
- if (value.userType() == QVariant::fromValue(GoToFunction::Select).userType()) {
const GoToFunction f = qvariant_cast<GoToFunction>(value);
switch (f) {
case GoToFunction::Select:
@@ -44,14 +47,13 @@ void GoToComboBox::signalFilter(int index) {
}
break;
}
+ case GoToFunction::Section: {
+ const QString& sectionName = itemText(index);
+ emit jumpToAddress(ProcessorHandler::get()->getProgram()->getSection(sectionName)->address);
+ break;
}
}
- if (value.userType() == QVariant::fromValue(ProgramSegment::Data).userType()) {
- const ProgramSegment seg = qvariant_cast<ProgramSegment>(value);
- emit jumpToAddress(ProcessorHandler::get()->getSetup().segmentPtrs.at(seg));
- }
-
clear();
}
} // namespace Ripes

MODIFY
src/gotocombobox.h
src/gotocombobox.h
namespace Ripes {
-enum class GoToFunction { Select, Address };
+enum class GoToFunction { Select, Address, Section };
class GoToComboBox : public QComboBox {
Q_OBJECT

MODIFY
src/instructionmodel.cpp
src/instructionmodel.cpp
@@ -7,7 +7,7 @@ namespace Ripes {
namespace {
uint32_t indexToAddress(const QModelIndex& index) {
- return index.row() * 4;
+ return (index.row() * 4) + ProcessorHandler::get()->getProgram()->getSection(TEXT_SECTION_NAME)->address;
}
} // namespace

MODIFY
src/processorhandler.cpp
src/processorhandler.cpp
@@ -10,24 +10,27 @@ namespace Ripes {
ProcessorHandler::ProcessorHandler() {
// Contruct the default processor
- selectProcessor(m_currentSetup);
+ selectProcessor(m_currentID);
}
void ProcessorHandler::loadProgram(const Program* p) {
+ auto* textSection = p->getSection(TEXT_SECTION_NAME);
+ if (!textSection)
+ return;
+
auto& mem = m_currentProcessor->getMemory();
m_program = p;
// Memory initializations
mem.clearInitializationMemories();
- 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());
+ for (const auto& seg : p->sections) {
+ mem.addInitializationMemory(seg.address, seg.data.data(), seg.data.length());
}
m_currentProcessor->setPCInitialValue(p->entryPoint);
// Set the valid execution range to be contained within the .text segment.
- m_validExecutionRange = {p->text.first, p->text.first + p->text.second.length()};
+ m_validExecutionRange = {textSection->address, textSection->address + textSection->data.length()};
// Update breakpoints to stay within the loaded program range
std::vector<uint32_t> bpsToRemove;
@@ -82,58 +85,41 @@ void ProcessorHandler::clearBreakpoints() {
m_breakpoints.clear();
}
-void ProcessorHandler::selectProcessor(const ProcessorSetup& setup) {
- m_currentSetup = setup;
+void ProcessorHandler::selectProcessor(const ProcessorID& id, RegisterSetup setup) {
+ m_currentID = id;
// Processor initializations
- m_currentProcessor = ProcessorRegistry::constructProcessor(m_currentSetup.id);
+ m_currentProcessor = ProcessorRegistry::constructProcessor(m_currentID);
m_currentProcessor->handleSysCall.Connect(this, &ProcessorHandler::handleSysCall);
m_currentProcessor->finished.Connect(this, &ProcessorHandler::processorFinished);
// Register initializations
auto& regs = m_currentProcessor->getRegisters();
regs.clearInitializationMemories();
- for (const auto& seg : m_currentSetup.segmentPtrs) {
+ for (const auto& kv : setup) {
// Memories are initialized through pointers to byte arrays, so we have to transform the intitial pointer
// address to the compatible format.
QByteArray ptrValueBytes;
- auto ptrValue = seg.second;
+ auto ptrValue = kv.second;
for (int i = 0; i < m_currentProcessor->implementsISA()->bytes(); i++) {
ptrValueBytes.push_back(static_cast<char>(ptrValue & 0xFF));
ptrValue >>= CHAR_BIT;
}
- switch (seg.first) {
- case ProgramSegment::Stack: {
- const int sp_idx = m_currentProcessor->implementsISA()->spReg();
- if (sp_idx >= 0) {
- regs.addInitializationMemory(sp_idx << ceillog2(m_currentProcessor->implementsISA()->bytes()),
- ptrValueBytes.data(), m_currentProcessor->implementsISA()->bytes());
- }
- break;
- }
- case ProgramSegment::Data: {
- const int gp_idx = m_currentProcessor->implementsISA()->gpReg();
- if (gp_idx >= 0) {
- regs.addInitializationMemory(gp_idx << ceillog2(m_currentProcessor->implementsISA()->bytes()),
+ regs.addInitializationMemory(kv.first << ceillog2(m_currentProcessor->implementsISA()->bytes()),
ptrValueBytes.data(), m_currentProcessor->implementsISA()->bytes());
}
- break;
- }
- default:
- break;
- }
-
- if (seg.first == ProgramSegment::Stack) {
- }
- }
// Processor loaded. Request for the currently assembled program to be loaded into the processor
emit reqReloadProgram();
}
int ProcessorHandler::getCurrentProgramSize() const {
- if (m_program)
- return m_program->text.second.size();
+ if (m_program) {
+ const auto* textSection = m_program->getSection(TEXT_SECTION_NAME);
+ assert(textSection);
+ return textSection->data.length();
+ }
+
return 0;
}

MODIFY
src/processorhandler.h
src/processorhandler.h
@@ -24,7 +24,8 @@ public:
}
const vsrtl::core::RipesProcessor* getProcessor() { return m_currentProcessor.get(); }
- const ProcessorSetup& getSetup() const { return m_currentSetup; }
+ const ProcessorID& getID() const { return m_currentID; }
+ const Program* getProgram() const { return m_program; }
const ISAInfoBase* currentISA() const { return m_currentProcessor->implementsISA(); }
/**
@@ -39,7 +40,7 @@ public:
* Constructs the processor identified by @param id, and performs all necessary initialization through the
* RipesProcessor interface.
*/
- void selectProcessor(const ProcessorSetup& id);
+ void selectProcessor(const ProcessorID& id, RegisterSetup setup = RegisterSetup());
/**
* @brief checkValidExecutionRange
@@ -129,7 +130,7 @@ private slots:
private:
ProcessorHandler();
- ProcessorSetup m_currentSetup = ProcessorRegistry::getDescription(ProcessorID::RISCV_SS).defaultSetup;
+ ProcessorID m_currentID = ProcessorID::RISCV_SS;
std::unique_ptr<vsrtl::core::RipesProcessor> m_currentProcessor;
/**

MODIFY
src/processorregistry.h
src/processorregistry.h
@@ -15,17 +15,11 @@ namespace Ripes {
enum class ProcessorID { RISCV_SS, RISCV_5S_WF, RISCV_5S_WOF };
// ============================================================================
-enum class ProgramSegment { Text, Data, Stack };
-const static std::map<ProgramSegment, QString> s_programSegmentName = {{ProgramSegment::Text, "Text"},
- {ProgramSegment::Data, "Data"},
- {ProgramSegment::Stack, "Stack"}};
-struct ProcessorSetup {
- ProcessorID id;
- std::map<ProgramSegment, uint32_t> segmentPtrs;
-};
+using RegisterSetup = std::map<unsigned, uint32_t>;
struct ProcessorDescription {
- ProcessorSetup defaultSetup;
+ ProcessorID id;
+ RegisterSetup defaultRegisterVals;
const ISAInfoBase* isa;
QString name;
QString description;
@@ -52,37 +46,30 @@ private:
// RISC-V single cycle
ProcessorDescription desc;
- desc.defaultSetup.id = ProcessorID::RISCV_SS;
- desc.defaultSetup.segmentPtrs[ProgramSegment::Text] = 0;
- desc.defaultSetup.segmentPtrs[ProgramSegment::Data] = 0x10000000;
- desc.defaultSetup.segmentPtrs[ProgramSegment::Stack] = 0x7ffffff0;
-
+ desc.id = ProcessorID::RISCV_SS;
desc.isa = ISAInfo<ISA::RV32IM>::instance();
desc.name = "RISC-V Single Cycle";
desc.description = "A single cycle RISC-V processor";
- m_descriptions[desc.defaultSetup.id] = desc;
+ desc.defaultRegisterVals = {{2, 0x7ffffff0}, {3, 0x10000000}};
+ m_descriptions[desc.id] = desc;
// RISC-V 5-Stage with forwarding
- desc.defaultSetup.id = ProcessorID::RISCV_5S_WF;
- desc.defaultSetup.segmentPtrs[ProgramSegment::Text] = 0;
- desc.defaultSetup.segmentPtrs[ProgramSegment::Data] = 0x10000000;
- desc.defaultSetup.segmentPtrs[ProgramSegment::Stack] = 0x7ffffff0;
+ desc.id = ProcessorID::RISCV_5S_WF;
desc.isa = ISAInfo<ISA::RV32IM>::instance();
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.defaultSetup.id] = desc;
+ desc.defaultRegisterVals = {{2, 0x7ffffff0}, {3, 0x10000000}};
+ m_descriptions[desc.id] = desc;
// RISC-V 5-stage without forwarding
- desc.defaultSetup.id = ProcessorID::RISCV_5S_WOF;
- desc.defaultSetup.segmentPtrs[ProgramSegment::Text] = 0;
- desc.defaultSetup.segmentPtrs[ProgramSegment::Data] = 0x10000000;
- desc.defaultSetup.segmentPtrs[ProgramSegment::Stack] = 0x7ffffff0;
+ desc.id = ProcessorID::RISCV_5S_WOF;
desc.isa = ISAInfo<ISA::RV32IM>::instance();
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.defaultSetup.id] = desc;
+ desc.defaultRegisterVals = {{2, 0x7ffffff0}, {3, 0x10000000}};
+ m_descriptions[desc.id] = desc;
}
static ProcessorRegistry& instance() {
@@ -95,4 +82,3 @@ private:
} // namespace Ripes
Q_DECLARE_METATYPE(Ripes::ProcessorID);
-Q_DECLARE_METATYPE(Ripes::ProgramSegment);

MODIFY
src/processorselectiondialog.cpp
src/processorselectiondialog.cpp
@@ -17,8 +17,8 @@ ProcessorSelectionDialog::ProcessorSelectionDialog(QWidget* parent)
// Initialize processor list
for (auto& desc : ProcessorRegistry::getAvailableProcessors()) {
QListWidgetItem* item = new QListWidgetItem(desc.second.name);
- item->setData(Qt::UserRole, QVariant::fromValue(desc.second.defaultSetup.id));
- if (desc.second.defaultSetup.id == ProcessorHandler::get()->getSetup().id) {
+ item->setData(Qt::UserRole, QVariant::fromValue(desc.second.id));
+ if (desc.second.id == ProcessorHandler::get()->getID()) {
auto font = item->font();
font.setBold(true);
item->setFont(font);
@@ -42,12 +42,9 @@ ProcessorSelectionDialog::~ProcessorSelectionDialog() {
void ProcessorSelectionDialog::accept() {
const ProcessorID id = qvariant_cast<ProcessorID>(ui->processorList->currentItem()->data(Qt::UserRole));
- selectedSetup = ProcessorRegistry::getDescription(id).defaultSetup;
+ selectedID = id;
- selectedSetup.segmentPtrs[ProgramSegment::Data] = ui->dataPtr->text().toUInt(nullptr, 16);
- selectedSetup.segmentPtrs[ProgramSegment::Stack] = ui->stackPtr->text().toUInt(nullptr, 16);
-
- if (id != ProcessorHandler::get()->getSetup().id) {
+ if (id != ProcessorHandler::get()->getID()) {
// New processor model was selected
return QDialog::accept();
} else {
@@ -63,11 +60,13 @@ void ProcessorSelectionDialog::selectionChanged(QListWidgetItem* current, QListW
ui->ISA->setText(desc.isa->name());
ui->description->setPlainText(desc.description);
+ /*
ui->stackPtr->setText(
"0x" +
QString::number(ProcessorRegistry::getDescription(id).defaultSetup.segmentPtrs.at(ProgramSegment::Stack), 16));
ui->dataPtr->setText(
"0x" +
QString::number(ProcessorRegistry::getDescription(id).defaultSetup.segmentPtrs.at(ProgramSegment::Data), 16));
+ */
}
} // namespace Ripes

MODIFY
src/processorselectiondialog.h
src/processorselectiondialog.h
@@ -18,7 +18,7 @@ public:
explicit ProcessorSelectionDialog(QWidget* parent = nullptr);
~ProcessorSelectionDialog();
- ProcessorSetup selectedSetup;
+ ProcessorID selectedID;
public slots:
virtual void accept() override;

MODIFY
src/processortab.cpp
src/processortab.cpp
@@ -152,7 +152,8 @@ void ProcessorTab::processorSelection() {
if (diag.exec()) {
// New processor model was selected
m_vsrtlWidget->clearDesign();
- ProcessorHandler::get()->selectProcessor(diag.selectedSetup);
+ ProcessorHandler::get()->selectProcessor(
+ diag.selectedID, ProcessorRegistry::getDescription(diag.selectedID).defaultRegisterVals);
ProcessorHandler::get()->loadProcessorToWidget(m_vsrtlWidget);
updateInstructionModel();
m_ui->registerWidget->updateModel();

MODIFY
src/program.h
src/program.h
#pragma once
#include <QByteArray>
+#include <QMap>
#include <QString>
#include <vector>
@@ -8,6 +9,8 @@ namespace Ripes {
enum class FileType { Assembly, FlatBinary, Executable };
+#define TEXT_SECTION_NAME ".text"
+
struct LoadFileParams {
QString filepath;
FileType type;
@@ -15,15 +18,30 @@ struct LoadFileParams {
uint32_t binaryLoadAt;
};
+struct ProgramSection {
+ QString name;
+ uint32_t address;
+ QByteArray data;
+};
+
/**
* @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;
uint32_t entryPoint = 0;
- std::vector<Section> others;
+ std::vector<ProgramSection> sections;
+
+ const ProgramSection* getSection(const QString& name) const {
+ const auto secIter =
+ std::find_if(sections.begin(), sections.end(), [=](const auto& section) { return section.name == name; });
+
+ if (secIter == sections.end()) {
+ return nullptr;
+ }
+
+ return &*secIter;
+ }
};
} // namespace Ripes

Make section information be a property of Programs