Add RegisterInitializationWidget
Register initializations will get written to the given register
each time the circuit is reset.
ADD
resources/icons/delete.svg
+<?xml version="1.0"?>
+<svg xmlns="http://www.w3.org/2000/svg" height="512px" viewBox="0 0 511.992 511.992" width="512px"><g><path d="m415.402344 495.421875-159.40625-159.410156-159.40625 159.410156c-22.097656 22.09375-57.921875 22.09375-80.019532 0-22.09375-22.097656-22.09375-57.921875 0-80.019531l159.410157-159.40625-159.410157-159.40625c-22.09375-22.097656-22.09375-57.921875 0-80.019532 22.097657-22.09375 57.921876-22.09375 80.019532 0l159.40625 159.410157 159.40625-159.410157c22.097656-22.09375 57.921875-22.09375 80.019531 0 22.09375 22.097657 22.09375 57.921876 0 80.019532l-159.410156 159.40625 159.410156 159.40625c22.09375 22.097656 22.09375 57.921875 0 80.019531-22.097656 22.09375-57.921875 22.09375-80.019531 0zm0 0" fill="#FF3B11" data-original="#E76E54" class="active-path" data-old_color="#e76e54"/></g> </svg>

MODIFY
resources/icons/icons.qrc
resources/icons/icons.qrc
<file>cancel.svg</file>
<file>saveas.svg</file>
<file>notepad.svg</file>
+ <file>plus.svg</file>
+ <file>delete.svg</file>
</qresource>
</RCC>

ADD
resources/icons/plus.svg
+<?xml version="1.0"?>
+<svg xmlns="http://www.w3.org/2000/svg" height="512px" viewBox="0 0 448 448" width="512px" class=""><g><path d="m408 184h-136c-4.417969 0-8-3.582031-8-8v-136c0-22.089844-17.910156-40-40-40s-40 17.910156-40 40v136c0 4.417969-3.582031 8-8 8h-136c-22.089844 0-40 17.910156-40 40s17.910156 40 40 40h136c4.417969 0 8 3.582031 8 8v136c0 22.089844 17.910156 40 40 40s40-17.910156 40-40v-136c0-4.417969 3.582031-8 8-8h136c22.089844 0 40-17.910156 40-40s-17.910156-40-40-40zm0 0" data-original="#000000" class="active-path" data-old_color="#000000" fill="#4BCB26"/></g> </svg>

MODIFY
src/processorhandler.cpp
src/processorhandler.cpp
@@ -100,7 +100,7 @@ void ProcessorHandler::clearBreakpoints() {
m_breakpoints.clear();
}
-void ProcessorHandler::selectProcessor(const ProcessorID& id, RegisterSetup setup) {
+void ProcessorHandler::selectProcessor(const ProcessorID& id, RegisterInitialization setup) {
m_program = nullptr;
m_currentID = id;

MODIFY
src/processorhandler.h
src/processorhandler.h
@@ -42,7 +42,7 @@ public:
* Constructs the processor identified by @param id, and performs all necessary initialization through the
* RipesProcessor interface.
*/
- void selectProcessor(const ProcessorID& id, RegisterSetup setup = RegisterSetup());
+ void selectProcessor(const ProcessorID& id, RegisterInitialization setup = RegisterInitialization());
/**
* @brief checkValidExecutionRange

MODIFY
src/processorregistry.h
src/processorregistry.h
@@ -15,11 +15,11 @@ namespace Ripes {
enum class ProcessorID { RISCV_SS, RISCV_5S_WF, RISCV_5S_WOF };
// ============================================================================
-using RegisterSetup = std::map<unsigned, uint32_t>;
+using RegisterInitialization = std::map<unsigned, uint32_t>;
struct ProcessorDescription {
ProcessorID id;
- RegisterSetup defaultRegisterVals;
+ RegisterInitialization defaultRegisterVals;
const ISAInfoBase* isa;
QString name;
QString description;

MODIFY
src/processorselectiondialog.cpp
src/processorselectiondialog.cpp
@@ -26,16 +26,16 @@ ProcessorSelectionDialog::ProcessorSelectionDialog(QWidget* parent)
ui->processorList->addItem(item);
}
- QRegExpValidator* validator = new QRegExpValidator(this);
- validator->setRegExp(hexRegex32);
- ui->stackPtr->setValidator(validator);
- ui->dataPtr->setValidator(validator);
connect(ui->processorList, &QListWidget::currentItemChanged, this, &ProcessorSelectionDialog::selectionChanged);
connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
}
+RegisterInitialization ProcessorSelectionDialog::getRegisterInitialization() const {
+ return ui->regInitWidget->getInitialization();
+}
+
ProcessorSelectionDialog::~ProcessorSelectionDialog() {
delete ui;
}
@@ -43,13 +43,7 @@ ProcessorSelectionDialog::~ProcessorSelectionDialog() {
void ProcessorSelectionDialog::accept() {
const ProcessorID id = qvariant_cast<ProcessorID>(ui->processorList->currentItem()->data(Qt::UserRole));
selectedID = id;
-
- if (id != ProcessorHandler::get()->getID()) {
- // New processor model was selected
- return QDialog::accept();
- } else {
- return QDialog::reject();
- }
+ QDialog::accept();
}
void ProcessorSelectionDialog::selectionChanged(QListWidgetItem* current, QListWidgetItem* previous) {
@@ -59,14 +53,6 @@ void ProcessorSelectionDialog::selectionChanged(QListWidgetItem* current, QListW
ui->name->setText(desc.name);
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));
- */
+ ui->regInitWidget->processorSelectionChanged(id);
}
} // namespace Ripes

MODIFY
src/processorselectiondialog.h
src/processorselectiondialog.h
@@ -18,7 +18,8 @@ public:
explicit ProcessorSelectionDialog(QWidget* parent = nullptr);
~ProcessorSelectionDialog();
- ProcessorID selectedID;
+ ProcessorID getSelectedId() const { return selectedID; }
+ RegisterInitialization getRegisterInitialization() const;
public slots:
virtual void accept() override;
@@ -27,6 +28,7 @@ private slots:
void selectionChanged(QListWidgetItem* current, QListWidgetItem* previous);
private:
+ ProcessorID selectedID;
Ui::ProcessorSelectionDialog* ui;
};
} // namespace Ripes

MODIFY
src/processorselectiondialog.ui
src/processorselectiondialog.ui
<rect>
<x>0</x>
<y>0</y>
- <width>706</width>
- <height>315</height>
+ <width>636</width>
+ <height>327</height>
</rect>
</property>
<property name="windowTitle">
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
- <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1">
+ <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0">
<item>
<widget class="QListWidget" name="processorList">
<property name="sizePolicy">
</property>
</widget>
</item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout" stretch="0,2">
<item>
<layout class="QGridLayout" name="gridLayout">
- <item row="2" column="0">
- <widget class="QLabel" name="label_3">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
<property name="text">
- <string>Description:</string>
+ <string>Name:</string>
</property>
</widget>
</item>
- <item row="1" column="0">
- <widget class="QLabel" name="label_2">
- <property name="text">
- <string>ISA:</string>
+ <item row="2" column="1">
+ <widget class="QPlainTextEdit" name="description">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>100</height>
+ </size>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>16777215</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ <property name="baseSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
</property>
- </widget>
- </item>
- <item row="1" column="1">
- <widget class="QLineEdit" name="ISA">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
- <item row="3" column="0">
- <widget class="QLabel" name="stackPtrLabel">
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_3">
<property name="text">
- <string>Stack pointer:</string>
+ <string>Description:</string>
</property>
</widget>
</item>
- <item row="2" column="1">
- <widget class="QPlainTextEdit" name="description">
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="ISA">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
- <item row="0" column="0">
- <widget class="QLabel" name="label">
- <property name="text">
- <string>Name:</string>
- </property>
- </widget>
- </item>
<item row="0" column="1">
<widget class="QLineEdit" name="name">
<property name="readOnly">
</property>
</widget>
</item>
- <item row="4" column="0">
- <widget class="QLabel" name="dataPtrLabel">
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
<property name="text">
- <string>Data pointer:</string>
+ <string>ISA:</string>
</property>
</widget>
</item>
- <item row="3" column="1">
- <widget class="QLineEdit" name="stackPtr"/>
+ </layout>
</item>
- <item row="4" column="1">
- <widget class="QLineEdit" name="dataPtr"/>
+ <item>
+ <widget class="Ripes::RegisterInitializationWidget" name="regInitWidget" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>2</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>150</height>
+ </size>
+ </property>
+ </widget>
</item>
</layout>
</item>
</item>
</layout>
</widget>
+ <customwidgets>
+ <customwidget>
+ <class>Ripes::RegisterInitializationWidget</class>
+ <extends>QWidget</extends>
+ <header>registerinitializationwidget.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
<resources/>
<connections/>
</ui>

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

ADD
src/registerinitializationwidget.cpp
+#include "registerinitializationwidget.h"
+#include "ui_registerinitializationwidget.h"
+
+#include "radix.h"
+
+#include <QComboBox>
+
+namespace Ripes {
+
+std::map<ProcessorID, RegisterInitialization> RegisterInitializationWidget::m_initializations;
+
+RegisterSelectionComboBox::RegisterSelectionComboBox(RegisterInitializationWidget* parent)
+ : QComboBox(parent), m_parent(parent) {
+ connect(this, QOverload<int>::of(&QComboBox::currentIndexChanged), [=] {
+ const int oldIdx = m_index;
+ m_index = currentData().toUInt();
+ emit regIndexChanged(oldIdx, m_index);
+ });
+}
+
+void RegisterSelectionComboBox::showPopup() {
+ if (count())
+ clear();
+
+ const auto& isa = ProcessorRegistry::getAvailableProcessors().at(m_parent->m_currentID).isa;
+ const auto& initializations = m_parent->m_initializations.at(m_parent->m_currentID);
+
+ std::set<unsigned> regOptions;
+ for (unsigned i = 0; i < isa->regCnt(); i++) {
+ if (!isa->regIsReadOnly(i)) {
+ regOptions.insert(i);
+ }
+ }
+
+ for (const auto& init : initializations) {
+ regOptions.erase(init.first);
+ }
+
+ for (const auto& i : regOptions) {
+ addItem(isa->regName(i) + " (" + isa->regAlias(i) + ")", i);
+ }
+ QComboBox::showPopup();
+}
+
+RegisterInitializationWidget::RegisterInitializationWidget(QWidget* parent)
+ : QWidget(parent), m_ui(new Ui::RegisterInitializationWidget) {
+ m_ui->setupUi(this);
+
+ m_hexValidator = new QRegExpValidator(this);
+ m_hexValidator->setRegExp(hexRegex32);
+
+ const QIcon addIcon = QIcon(":/icons/plus.svg");
+ m_ui->addInitButton->setIcon(addIcon);
+ connect(m_ui->addInitButton, &QPushButton::clicked,
+ [=] { this->addRegisterInitialization(getNonInitializedRegIdx()); });
+
+ // Initialize initializations for all available processors
+ for (const auto& desc : ProcessorRegistry::getAvailableProcessors()) {
+ // Set to initial value if this is the first time the dialog is loaded. Else, keep whatever changes has been
+ // stored in the static variable, made in previous invokations of the dialog.
+ if (!m_initializations.count(desc.second.id)) {
+ m_initializations[desc.second.id] = desc.second.defaultRegisterVals;
+ }
+ }
+}
+
+void RegisterInitializationWidget::processorSelectionChanged(ProcessorID id) {
+ // Clear current initialization widgets and recreate initialization widgets based on the currently selected
+ // processor
+ m_currentRegInitWidgets.clear();
+ m_currentID = id;
+
+ for (const auto& init : m_initializations.at(id)) {
+ addRegisterInitialization(init.first);
+ }
+
+ updateAddButtonState();
+}
+
+RegisterInitializationWidget::~RegisterInitializationWidget() {
+ delete m_ui;
+}
+
+void RegisterInitializationWidget::updateAddButtonState() {
+ const auto& desc = ProcessorRegistry::getAvailableProcessors().at(m_currentID);
+
+ // Disable add button if we have exhausted the number of registers to initialize for the given processor
+ if (getNonInitializedRegIdx() != -1) {
+ m_ui->addInitButton->setEnabled(true);
+ } else {
+ m_ui->addInitButton->setEnabled(false);
+ }
+}
+
+int RegisterInitializationWidget::getNonInitializedRegIdx() {
+ const auto& currentISA = ProcessorRegistry::getAvailableProcessors().at(m_currentID).isa;
+ const auto& currentInitForProc = m_initializations.at(m_currentID);
+ int id = 0;
+ while (currentInitForProc.count(id) || currentISA->regIsReadOnly(id)) {
+ id++;
+ }
+
+ return id < currentISA->regCnt() ? id : -1;
+}
+
+RegisterInitializationWidget::RegInitWidgets* RegisterInitializationWidget::addRegisterInitialization(unsigned regIdx) {
+ constexpr unsigned s_defaultval = 0;
+ if (!m_initializations.at(m_currentID).count(regIdx)) {
+ // No default value of the register initialization exists.
+ m_initializations.at(m_currentID)[regIdx] = s_defaultval;
+ }
+
+ const auto& regLayout = m_ui->regInitLayout;
+ const auto& isa = ProcessorRegistry::getAvailableProcessors().at(m_currentID).isa;
+
+ auto& w = m_currentRegInitWidgets.emplace_back(std::make_unique<RegInitWidgets>());
+ auto* w_ptr = w.get();
+
+ w->name = new RegisterSelectionComboBox(this);
+ w->value = new QLineEdit(this);
+ w->remove = new QPushButton(this);
+
+ w->name->addItem(isa->regName(regIdx) + " (" + isa->regAlias(regIdx) + ")", regIdx);
+
+ connect(w->name, &RegisterSelectionComboBox::regIndexChanged, [this, w_ptr](int oldIdx, int newIdx) {
+ m_initializations.at(m_currentID).erase(oldIdx);
+ m_initializations.at(m_currentID)[newIdx];
+ emit w_ptr->value->textChanged(w_ptr->value->text());
+ });
+
+ const QIcon removeIcon = QIcon(":/icons/delete.svg");
+ w->remove->setIcon(removeIcon);
+
+ w->value->setValidator(m_hexValidator);
+ w->value->setText("0x" + QString::number(m_initializations.at(m_currentID).at(regIdx), 16));
+ connect(w->value, &QLineEdit::textChanged, [this, w_ptr](const QString& text) {
+ this->m_initializations.at(this->m_currentID).at(w_ptr->name->currentData().toUInt()) =
+ text.toUInt(nullptr, 16);
+ });
+
+ const int nInitializations = regLayout->rowCount();
+ regLayout->addWidget(w->name, nInitializations, 0);
+ regLayout->addWidget(w->value, nInitializations, 1);
+ regLayout->addWidget(w->remove, nInitializations, 2);
+ connect(w->remove, &QPushButton::clicked, [this, w_ptr] { this->removeRegInitWidget(w_ptr); });
+
+ updateAddButtonState();
+ return w.get();
+}
+
+void RegisterInitializationWidget::removeRegInitWidget(RegisterInitializationWidget::RegInitWidgets* w) {
+ auto iter = std::find_if(m_currentRegInitWidgets.begin(), m_currentRegInitWidgets.end(),
+ [=](const auto& initWidget) { return initWidget.get() == w; });
+ assert(iter != m_currentRegInitWidgets.end());
+
+ // Current register index stored in the combobox of the regInitWidgets
+ const unsigned regIdx = w->name->itemData(0).toUInt();
+ m_initializations.at(m_currentID).erase(regIdx);
+
+ m_currentRegInitWidgets.erase(iter);
+ updateAddButtonState();
+}
+
+void RegisterInitializationWidget::RegInitWidgets::clear() {
+ delete name;
+ delete value;
+ delete remove;
+}
+
+RegisterInitialization RegisterInitializationWidget::getInitialization() const {
+ return m_initializations.at(m_currentID);
+}
+
+} // namespace Ripes

ADD
src/registerinitializationwidget.h
+#pragma once
+
+#include <QComboBox>
+#include <QLabel>
+#include <QLineEdit>
+#include <QPushButton>
+#include <QRegExpValidator>
+#include <QWidget>
+
+#include "processorregistry.h"
+
+namespace Ripes {
+class RegisterInitializationWidget;
+class RegisterSelectionComboBox;
+
+namespace Ui {
+class RegisterInitializationWidget;
+}
+
+class RegisterInitializationWidget : public QWidget {
+ Q_OBJECT
+ friend class RegisterSelectionComboBox;
+
+ struct RegInitWidgets {
+ RegisterSelectionComboBox* name = nullptr;
+ QLineEdit* value = nullptr;
+ QPushButton* remove = nullptr;
+
+ ~RegInitWidgets() { clear(); }
+ void clear();
+ };
+
+public:
+ explicit RegisterInitializationWidget(QWidget* parent = nullptr);
+ ~RegisterInitializationWidget();
+
+ RegisterInitialization getInitialization() const;
+
+ void processorSelectionChanged(ProcessorID id);
+
+private slots:
+ RegInitWidgets* addRegisterInitialization(unsigned regIdx);
+
+private:
+ void updateAddButtonState();
+ int getNonInitializedRegIdx();
+ void removeRegInitWidget(RegInitWidgets* w);
+
+ Ui::RegisterInitializationWidget* m_ui;
+
+ static std::map<ProcessorID, RegisterInitialization> m_initializations;
+ ProcessorID m_currentID;
+ QRegExpValidator* m_hexValidator;
+
+ std::vector<std::unique_ptr<RegInitWidgets>> m_currentRegInitWidgets;
+};
+
+class RegisterSelectionComboBox : public QComboBox {
+ Q_OBJECT
+public:
+ RegisterSelectionComboBox(RegisterInitializationWidget* parent = nullptr);
+ void showPopup() override;
+
+signals:
+ void regIndexChanged(int oldIdx, int newIdx);
+
+private:
+ int m_index = -1;
+ RegisterInitializationWidget* m_parent = nullptr;
+};
+
+} // namespace Ripes

ADD
src/registerinitializationwidget.ui
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Ripes::RegisterInitializationWidget</class>
+ <widget class="QWidget" name="Ripes::RegisterInitializationWidget">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item row="0" column="0">
+ <layout class="QVBoxLayout" name="layout">
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="toolTip">
+ <string>A register initialization value will be written to a register once the circuit is reset.</string>
+ </property>
+ <property name="text">
+ <string>Register initialization</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QScrollArea" name="scrollArea">
+ <property name="widgetResizable">
+ <bool>true</bool>
+ </property>
+ <widget class="QWidget" name="scrollAreaWidgetContents">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>396</width>
+ <height>231</height>
+ </rect>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0">
+ <layout class="QGridLayout" name="regInitLayout"/>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="addLayout">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="addInitButton">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>

Add RegisterInitializationWidget

Register initializations will get written to the given register
each time the circuit is reset.