[WIP] Add MVC model for peripheral parameters
MODIFY
src/io/iobase.cpp
src/io/iobase.cpp
@@ -4,4 +4,10 @@ namespace Ripes {
std::map<std::type_index, int> IOBase::s_peripheralCount;
+bool IOBase::setParameter(unsigned ID, const QVariant& value) {
+ m_parameters.at(ID).value = value;
+ parameterChanged(ID);
+ return true;
+}
+
} // namespace Ripes

MODIFY
src/io/iobase.h
src/io/iobase.h
@@ -50,10 +50,9 @@ public:
/**
* @brief setParameter
- * Attempt to set the parameter @p ID to @p value. Returns the value that the parameter was set to (use this to
- * identify whether value was set successfully).
+ * Attempt to set the parameter @p ID to @p value. Returns true if the value was set successfully.
*/
- virtual const QVariant& setParameter(unsigned ID, const QVariant& value) = 0;
+ virtual bool setParameter(unsigned ID, const QVariant& value);
void setStartAddr(uint32_t addr) { m_startAddr = addr; }
uint32_t startAddr() const { return m_startAddr; }
@@ -70,7 +69,16 @@ public:
virtual uint32_t ioRead32(uint32_t offset) = 0;
virtual void ioWrite32(uint32_t offset, uint32_t value) = 0;
+signals:
+ /**
+ * @brief regMapChanged
+ * Should be emitted every time the register map of this peripheral changes.
+ */
+ void regMapChanged();
+
protected:
+ virtual void parameterChanged(unsigned ID) = 0;
+
::uint32_t m_startAddr;
std::map<unsigned, IOParam> m_parameters;

MODIFY
src/io/ioledmatrix.cpp
src/io/ioledmatrix.cpp
@@ -33,10 +33,6 @@ QString IOLedMatrix::name() const {
return "LED Matrix"; // Todo: generate unique name
}
-const QVariant& IOLedMatrix::setParameter(unsigned ID, const QVariant& value) {
- return QVariant();
-}
-
uint32_t IOLedMatrix::ioRead8(uint32_t offset) {
return regRead(offset) & 0xFF;
}
@@ -61,10 +57,11 @@ inline QColor regToColor(uint32_t regVal) {
void IOLedMatrix::updateLEDRegs() {
const int width = m_parameters[WIDTH].value.toInt();
const int height = m_parameters[HEIGHT].value.toInt();
- m_ledRegs.resize(width * width);
+ const int nLEDs = width * height;
+ m_ledRegs.resize(nLEDs);
m_regDescs.clear();
- m_regDescs.resize(width * height);
+ m_regDescs.resize(nLEDs);
for (unsigned i = 0; i < m_regDescs.size(); i++) {
m_regDescs.at(i) = RegDesc{"LED_" + QString::number(i), RegDesc::RW::RW, 24, i * 4};
}
@@ -80,6 +77,10 @@ void IOLedMatrix::updateLEDRegs() {
m_ledRegs.at(idx) = r << 16 | g << 8 | b;
}
}
+
+ updateGeometry();
+ resize(minimumSize());
+ emit regMapChanged();
}
QSize IOLedMatrix::minimumSizeHint() const {

MODIFY
src/io/ioledmatrix.h
src/io/ioledmatrix.h
@@ -23,7 +23,6 @@ public:
virtual QString description() const override;
virtual QString name() const override;
- virtual const QVariant& setParameter(unsigned ID, const QVariant& value) override;
virtual const std::vector<RegDesc>& registers() const override { return m_regDescs; };
/**
@@ -37,6 +36,8 @@ public:
virtual void ioWrite32(uint32_t offset, uint32_t value) override;
protected:
+ virtual void parameterChanged(unsigned) override { updateLEDRegs(); };
+
/**
* QWidget drawing
*/

MODIFY
src/io/ioswitches.cpp
src/io/ioswitches.cpp
@@ -159,18 +159,10 @@ QString IOSwitches::name() const {
return "Switches"; // Todo: generate unique name
}
-const QVariant& IOSwitches::setParameter(unsigned ID, const QVariant& value) {
- switch (ID) {
- case SWITCHES: {
- }
- }
- return value;
-}
-
void IOSwitches::updateSwitches() {
const unsigned nSwitches = m_parameters.at(SWITCHES).value.toInt();
for (int i = 0; i < nSwitches; i++) {
- if (m_switches.size() <= i) {
+ if (m_switches.count(i) == 0) {
auto* sw = new ToggleButton(10, 8, true, this);
auto* label = new QLabel(QString::number(i), this);
m_switches[i] = {label, sw};
@@ -180,14 +172,25 @@ void IOSwitches::updateSwitches() {
}
// Remove extra switches if # of switches was reduced
- for (int i = nSwitches; i < m_switches.size(); i++) {
- m_switches.at(i).first->deleteLater();
- m_switches.at(i).second->deleteLater();
+ std::vector<int> idxToDelete;
+ for (const auto& it : m_switches) {
+ if (it.first >= nSwitches) {
+ idxToDelete.push_back(it.first);
+ }
+ }
- m_switches.erase(i);
+ for (int idx : idxToDelete) {
+ auto it = m_switches.find(idx);
+ Q_ASSERT(it != m_switches.end());
+ it->second.first->deleteLater();
+ it->second.second->deleteLater();
+ m_switches.erase(idx);
}
m_regDescs = {RegDesc{"Switches", RegDesc::RW::R, nSwitches, 0}};
+ updateGeometry();
+ resize(minimumSize());
+ emit regMapChanged();
}
uint32_t IOSwitches::ioRead8(uint32_t offset) {

MODIFY
src/io/ioswitches.h
src/io/ioswitches.h
@@ -69,7 +69,6 @@ public:
virtual QString description() const override;
virtual QString name() const override;
- virtual const QVariant& setParameter(unsigned ID, const QVariant& value) override;
virtual const std::vector<RegDesc>& registers() const override { return m_regDescs; };
/**
@@ -82,6 +81,9 @@ public:
virtual uint32_t ioRead32(uint32_t offset) override;
virtual void ioWrite32(uint32_t offset, uint32_t value) override;
+protected:
+ virtual void parameterChanged(unsigned) override { updateSwitches(); };
+
private:
void updateSwitches();

ADD
src/io/periphparammodel.cpp
+#include "periphparammodel.h"
+
+#include <QHeaderView>
+
+#include "iobase.h"
+#include "processorhandler.h"
+
+namespace Ripes {
+
+PeriphParamModel::PeriphParamModel(IOBase* peripheral, QObject* parent)
+ : QAbstractTableModel(parent), m_peripheral(peripheral) {}
+
+int PeriphParamModel::columnCount(const QModelIndex&) const {
+ return NColumns;
+}
+
+int PeriphParamModel::rowCount(const QModelIndex&) const {
+ return m_peripheral->parameters().size();
+}
+
+QVariant PeriphParamModel::headerData(int section, Qt::Orientation orientation, int role) const {
+ if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
+ switch (section) {
+ case Column::Name:
+ return "Name";
+ case Column::Value:
+ return "Value";
+ default:
+ return QVariant();
+ }
+ }
+ return QVariant();
+}
+
+bool PeriphParamModel::setData(const QModelIndex& index, const QVariant& value, int) {
+ const unsigned idx = index.row();
+ auto ret = m_peripheral->setParameter(idx, value);
+ return ret == value;
+}
+
+QVariant PeriphParamModel::data(const QModelIndex& index, int role) const {
+ if (!index.isValid()) {
+ return QVariant();
+ }
+
+ const unsigned idx = index.row();
+ switch (index.column()) {
+ case Column::Name: {
+ if (role == Qt::DisplayRole) {
+ return m_peripheral->parameters().at(idx).name;
+ }
+ break;
+ }
+ case Column::Value: {
+ switch (role) {
+ case Qt::DisplayRole:
+ return m_peripheral->parameters().at(idx).value;
+ case Qt::TextAlignmentRole:
+ return Qt::AlignCenter;
+ }
+ break;
+ }
+ default:
+ return QVariant();
+ }
+ return QVariant();
+}
+
+Qt::ItemFlags PeriphParamModel::flags(const QModelIndex& index) const {
+ const unsigned col = index.column();
+ Qt::ItemFlags flags = Qt::ItemIsEnabled;
+
+ if (col == Value) {
+ flags |= Qt::ItemIsEditable;
+ }
+
+ return flags;
+}
+} // namespace Ripes

ADD
src/io/periphparammodel.h
+#pragma once
+
+#include <QColor>
+#include <set>
+#include "defines.h"
+#include "mainmemory.h"
+
+#include "isa/isainfo.h"
+#include "radix.h"
+
+#include <QAbstractTableModel>
+
+namespace Ripes {
+class IOBase;
+
+class PeriphParamModel : public QAbstractTableModel {
+ Q_OBJECT
+public:
+ enum Column { Name, Value, NColumns };
+ PeriphParamModel(IOBase* peripheral, QObject* parent = nullptr);
+
+ int rowCount(const QModelIndex& parent = QModelIndex()) const override;
+ int columnCount(const QModelIndex& parent = QModelIndex()) const override;
+
+ QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
+ bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
+
+ Qt::ItemFlags flags(const QModelIndex& index) const override;
+
+private:
+ IOBase* m_peripheral = nullptr;
+};
+} // namespace Ripes

MODIFY
src/io/registermapmodel.cpp
src/io/registermapmodel.cpp
namespace Ripes {
RegisterMapModel::RegisterMapModel(IOBase* peripheral, QObject* parent)
- : QAbstractTableModel(parent), m_peripheral(peripheral) {}
+ : QAbstractTableModel(parent), m_peripheral(peripheral) {
+ connect(m_peripheral, &IOBase::regMapChanged, this, &RegisterMapModel::regMapChanged);
+}
+
+void RegisterMapModel::regMapChanged() {
+ // Let's assume that this is not a hot function, and just update the whole view.
+ emit dataChanged(index(0, 0), index(rowCount(), columnCount()));
+ emit layoutChanged();
+}
int RegisterMapModel::columnCount(const QModelIndex&) const {
return NColumns;

MODIFY
src/io/registermapmodel.h
src/io/registermapmodel.h
@@ -27,6 +27,9 @@ public:
Qt::ItemFlags flags(const QModelIndex& index) const override;
+public slots:
+ void regMapChanged();
+
private:
IOBase* m_peripheral = nullptr;
};

MODIFY
src/ioperipheraltab.cpp
src/ioperipheraltab.cpp
#include "ui_ioperipheraltab.h"
#include "io/iobase.h"
+#include "io/periphparammodel.h"
#include "io/registermapmodel.h"
namespace Ripes {
@@ -14,6 +15,10 @@ IOPeripheralTab::IOPeripheralTab(QWidget* parent, IOBase* peripheral)
m_ui->registerMapView->setModel(new RegisterMapModel(peripheral, this));
m_ui->registerMapView->horizontalHeader()->setStretchLastSection(true);
m_ui->registerMapView->resizeColumnsToContents();
+
+ m_ui->parameterView->setModel(new PeriphParamModel(peripheral, this));
+ m_ui->parameterView->horizontalHeader()->setStretchLastSection(true);
+ m_ui->parameterView->resizeColumnsToContents();
}
IOPeripheralTab::~IOPeripheralTab() {

[WIP] Add MVC model for peripheral parameters