Generate symbol header file for peripheral memory-mapped registers
MODIFY
src/io/iobase.cpp
src/io/iobase.cpp
@@ -11,8 +11,8 @@ IOBase::IOBase(unsigned IOType, QWidget* parent) : QWidget(parent), m_type(IOTyp
connect(this, &IOBase::scheduleUpdate, this, QOverload<>::of(&QWidget::update));
}
-QString IOBase::cName() const {
- QString cname = name();
+QString cName(const QString& name) {
+ QString cname = name;
for (const auto& ch : {' ', '-'}) {
cname.replace(ch, "_");
}

MODIFY
src/io/iobase.h
src/io/iobase.h
namespace Ripes {
+/**
+ * @brief cName
+ * @returns a string escaped to be suitable as a source constant definition
+ */
+QString cName(const QString& name);
+
struct IOParam {
IOParam(unsigned _id, QString _name, QVariant _defValue, bool _hasRange, QVariant _min = QVariant(),
QVariant _max = QVariant())
@@ -30,6 +36,11 @@ struct RegDesc {
RW rw;
unsigned bitWidth;
uint32_t address;
+ /**
+ * @brief exported
+ * if true, a constant symbol is generated that may be referenced in the assembler, which targets this register.
+ */
+ bool exported = false;
};
class IOBase : public QWidget {
@@ -45,12 +56,6 @@ public:
const std::map<unsigned, IOParam>& parameters() const { return m_parameters; }
virtual QString description() const = 0;
- /**
- * @brief cName
- * @returns unique name for this component, escaped to be suitable as a source constant definition
- */
- QString cName() const;
-
/**
* @brief name
* @returns unique name for this specific component

MODIFY
src/io/iodpad.cpp
src/io/iodpad.cpp
@@ -35,7 +35,7 @@ IODPad::IODPad(QWidget* parent) : IOBase(IOType::DPAD, parent) {
m_buttons[static_cast<IdxToDir>(i)] = button;
button->setArrowType(arrow);
- m_regDescs.push_back(RegDesc{name, RegDesc::RW::R, 1, i * 4});
+ m_regDescs.push_back(RegDesc{name, RegDesc::RW::R, 1, i * 4, true});
}
auto* gridLayout = new QGridLayout();

MODIFY
src/io/ioledmatrix.cpp
src/io/ioledmatrix.cpp
@@ -65,7 +65,13 @@ void IOLedMatrix::updateLEDRegs() {
m_regDescs.clear();
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};
+ RegDesc regdesc;
+ regdesc.name = "LED_" + QString::number(i);
+ regdesc.rw = RegDesc::RW::RW;
+ regdesc.bitWidth = 24;
+ regdesc.address = i * 4;
+ regdesc.exported = false;
+ m_regDescs.at(i) = regdesc;
}
updateGeometry();

MODIFY
src/io/iomanager.cpp
src/io/iomanager.cpp
#include "processorhandler.h"
#include "ripessettings.h"
+#include <memory>
+
#include "VSRTL/core/vsrtl_sparsearray.h"
namespace Ripes {
@@ -15,6 +17,14 @@ IOManager::IOManager() : QObject(nullptr) {
refreshMemoryMap();
}
+QString IOManager::cSymbolsHeaderpath() const {
+ if (m_symbolsHeaderFile) {
+ return m_symbolsHeaderFile->fileName();
+ } else {
+ return QString();
+ }
+}
+
uint32_t IOManager::nextPeripheralAddress() const {
uint32_t base = 0;
if (m_peripherals.empty()) {
@@ -102,6 +112,61 @@ void IOManager::refreshMemoryMap() {
}
emit memoryMapChanged();
+ updateSymbols();
+}
+
+std::map<QString, uint32_t> IOManager::assemblerSymbolsForPeriph(IOBase* peripheral) const {
+ const QString& periphName = cName(peripheral->name());
+ std::map<QString, uint32_t> symbols;
+ const auto& periphInfo = m_peripherals.at(peripheral);
+ symbols[periphName + "_BASE"] = periphInfo.startAddr;
+ symbols[periphName + "_SIZE"] = periphInfo.size;
+
+ for (const auto& reg : peripheral->registers()) {
+ if (reg.exported) {
+ symbols[periphName + "_" + cName(reg.name)] = reg.address + periphInfo.startAddr;
+ }
+ }
+
+ return symbols;
+}
+
+void IOManager::updateSymbols() {
+ m_assemblerSymbols.clear();
+
+ // Generate symbol mapping + header file
+ QStringList headerfile;
+ for (const auto& p : m_peripherals) {
+ const QString& periphName = cName(p.first->name());
+ headerfile << "// *****************************************************************************";
+ headerfile << "// * " + periphName;
+ headerfile << "// *****************************************************************************";
+
+ auto symbols = assemblerSymbolsForPeriph(p.first);
+ m_assemblerSymbols.insert(symbols.begin(), symbols.end());
+
+ for (const auto& symbol : assemblerSymbolsForPeriph(p.first)) {
+ headerfile << "#define " + symbol.first + "\t" + "(0x" + QString::number(symbol.second, 16) + ")";
+ }
+
+ headerfile << "\n";
+ }
+
+ // Store header file at a temporary location
+ if (!(m_symbolsHeaderFile && (QFile::exists(m_symbolsHeaderFile->fileName())))) {
+ const auto tempFileTemplate =
+ QString(QDir::tempPath() + QDir::separator() + QCoreApplication::applicationName() + ".XXXXXX.h");
+ QTemporaryFile tmpHdrFile = QTemporaryFile(tempFileTemplate);
+ tmpHdrFile.setAutoRemove(false);
+ if (tmpHdrFile.open()) {
+ m_symbolsHeaderFile = std::make_unique<QFile>(tmpHdrFile.fileName());
+ }
+ }
+
+ if (m_symbolsHeaderFile->open(QIODevice::ReadWrite | QIODevice::Truncate)) {
+ m_symbolsHeaderFile->write(headerfile.join('\n').toUtf8());
+ m_symbolsHeaderFile->close();
+ }
}
} // namespace Ripes

MODIFY
src/io/iomanager.h
src/io/iomanager.h
#include "iobase.h"
#include "ioregistry.h"
+#include <QFile>
+
namespace Ripes {
struct MemoryMapEntry {
@@ -23,11 +25,33 @@ public:
void removePeripheral(IOBase* peripheral, std::atomic<bool>& ok);
const MemoryMap& memoryMap() const { return m_memoryMap; }
+ /**
+ * @brief cSymbolsHeaderpath
+ * @returns the path of a header file of #define's containing the current peripherals base addresses + memory mapped
+ * registers
+ */
+ QString cSymbolsHeaderpath() const;
+
+ /**
+ * @brief assemblerSymbols
+ * @returns as cSymbols, but as a map which can be directly loaded into the assembler.
+ */
+ std::map<QString, uint32_t> assemblerSymbols() const { return m_assemblerSymbols; }
+
signals:
void memoryMapChanged();
void peripheralRemoved(QObject* peripheral);
private:
+ std::map<QString, uint32_t> assemblerSymbolsForPeriph(IOBase* peripheral) const;
+
+ /**
+ * @brief updateSymbols
+ * Updates the set of exported memory-mapped symbols for the currently instantiated peripherals, as well as the
+ * generated header file.
+ */
+ void updateSymbols();
+
void refreshMemoryMap();
void peripheralSizeChanged(IOBase* peripheral);
@@ -54,6 +78,8 @@ private:
MemoryMap m_memoryMap;
std::map<IOBase*, MemoryMapEntry> m_peripherals;
+ std::map<QString, uint32_t> m_assemblerSymbols;
+ std::unique_ptr<QFile> m_symbolsHeaderFile;
};
} // namespace Ripes

MODIFY
src/io/ioswitches.cpp
src/io/ioswitches.cpp
@@ -184,7 +184,9 @@ void IOSwitches::updateSwitches() {
m_switches.erase(idx);
}
- m_regDescs = {RegDesc{"Switches", RegDesc::RW::R, nSwitches, 0}};
+ // No reason to export the register, since the base pointer already points to it, and it is the only register of
+ // this component.
+ m_regDescs = {RegDesc{"Switches", RegDesc::RW::R, nSwitches, 0, false}};
updateGeometry();
resize(minimumSize());
emit regMapChanged();

Generate symbol header file for peripheral memory-mapped registers