aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--funreg.hpp6
-rw-r--r--svd2funreg/Makefile2
-rw-r--r--svd2funreg/main.cpp147
3 files changed, 120 insertions, 35 deletions
diff --git a/funreg.hpp b/funreg.hpp
index 9dc5449..db0bb37 100644
--- a/funreg.hpp
+++ b/funreg.hpp
@@ -192,9 +192,9 @@ struct Register {
// bit-mask created by merging all provided bit-masks.
// If no masks are given, a mask selecting all bits is used.
template<typename... Masks>
- static void apply(auto fn) {
+ static constexpr void apply(auto fn) {
if constexpr (sizeof...(Masks) > 0) {
- auto mask = mergeMasks<Masks...>();
+ constexpr auto mask = mergeMasks<Masks...>();
if constexpr (mask)
write(fn(read(), mask));
} else {
@@ -205,7 +205,7 @@ struct Register {
// Takes a list of bit-masks, and returns a merged mask of those which are
// meant for this register.
template<typename... Masks>
- static auto mergeMasks() {
+ static constexpr auto mergeMasks() {
if constexpr (sizeof...(Masks) > 0) {
if constexpr ((isThis<typename Masks::reg> | ...)) {
auto mask =
diff --git a/svd2funreg/Makefile b/svd2funreg/Makefile
index 743d59a..7fd2c5e 100644
--- a/svd2funreg/Makefile
+++ b/svd2funreg/Makefile
@@ -1,2 +1,2 @@
all:
- g++ -o main main.cpp pugixml/src/pugixml.cpp -I pugixml/src
+ g++ -o main main.cpp pugixml/src/pugixml.cpp -I pugixml/src -std=c++20
diff --git a/svd2funreg/main.cpp b/svd2funreg/main.cpp
index d19d54d..1503381 100644
--- a/svd2funreg/main.cpp
+++ b/svd2funreg/main.cpp
@@ -1,13 +1,50 @@
#include "pugixml.hpp"
+#include <cctype>
#include <cstdint>
#include <cstdlib>
#include <iostream>
+#include <map>
#include <string>
+#include <vector>
-static void parse_peripheral(const pugi::xml_node& node);
-static void parse_register(uint32_t base_address, const pugi::xml_node& node);
-static void parse_field(const char *reg, const pugi::xml_node& node);
+struct Field {
+ std::string reg;
+ std::string name;
+ int offset;
+ int width;
+
+ Field() = default;
+ Field(const char *r, const pugi::xml_node& node);
+ void operator()();
+};
+
+struct Register {
+ std::string name;
+ int offset;
+ int size;
+
+ std::vector<Field> fields;
+
+ Register() = default;
+ Register(std::string peri, const pugi::xml_node& node);
+ void operator()(uint32_t base);
+};
+
+struct Peripheral {
+ std::string name;
+ std::string group;
+ uint32_t base;
+
+ std::vector<Register> registers;
+
+ Peripheral() = default;
+ Peripheral(const pugi::xml_node& node);
+ Peripheral(const pugi::xml_node& node, const Peripheral& derived);
+ void operator()();
+};
+
+std::map<std::string, Peripheral> device;
int main(int argc, char *argv[])
{
@@ -19,63 +56,111 @@ int main(int argc, char *argv[])
if (!result)
return -1;
- std::cout << std::hex;
- std::cout << "namespace " << doc.child("device").child_value("name")
- << " {\n";
-
for (auto node : doc.child("device")
.child("peripherals")
.children("peripheral"))
{
- parse_peripheral(node);
+ const auto df = node.attribute("derivedFrom");
+ Peripheral p = df ? Peripheral {node, device[df.value()]} : Peripheral {node};
+
+ device[p.name] = p;
}
+ std::cout << std::hex;
+ std::cout << "#include \"funreg.hpp\"\n\n"
+ << "namespace " << doc.child("device").child_value("name")
+ << " {\n"
+ << " using namespace fr;\n";
+
+ for (auto& [_, p] : device) p();
+
std::cout << "}\n";
}
-void parse_peripheral(const pugi::xml_node& node)
+Field::Field(const char *r, const pugi::xml_node& node):
+ reg(r),
+ name(node.child_value("name")),
+ offset(std::strtol(node.child_value("bitOffset"), nullptr, 0)),
+ width(std::strtol(node.child_value("bitWidth"), nullptr, 0))
{
- const auto base = std::strtol(node.child_value("baseAddress"), nullptr, 0);
+ if (name == reg)
+ name = "val";
+}
- std::cout << " namespace " << node.child_value("name") << " {\n";
+void Field::operator()()
+{
+ std::cout << " using " << name << " = RegisterMask<"
+ << reg << ", (0x" << (1 << width) - 1 << "u << 0x" << offset << "u)>;\n";
+}
- for (auto n : node.child("registers").children("register"))
- parse_register(base, n);
+Register::Register(std::string peri, const pugi::xml_node& node):
+ name(node.child_value("name")),
+ offset(std::strtol(node.child_value("addressOffset"), nullptr, 0)),
+ size(std::strtol(node.child_value("size"), nullptr, 0))
+{
+ if (isdigit(peri.back())) {
+ if (name.starts_with(name.substr(0, name.size() - 1))
+ && name.at(peri.size() - 1) == '_')
+ {
+ name = name.substr(peri.size());
+ }
+ } else {
+ if (name.starts_with(name.substr(0, name.size()))
+ && name.at(peri.size()) == '_')
+ {
+ name = name.substr(peri.size() + 1);
+ }
+ }
- std::cout << " }\n";
+ for (auto n : node.child("fields").children("field"))
+ fields.emplace_back(name.c_str(), n);
}
-void parse_register(uint32_t base_address, const pugi::xml_node& node)
+void Register::operator()(uint32_t base)
{
- const auto offs = std::strtol(node.child_value("addressOffset"), nullptr, 0);
- const auto size = std::strtol(node.child_value("size"), nullptr, 0);
- const auto name = node.child_value("name");
-
- std::cout << " struct " << name << " : public fr::MemRegister<";
+ std::cout << " struct " << name << " : public MemRegister<";
switch (size) {
case 8: std::cout << "uint8_t, "; break;
case 16: std::cout << "uint16_t, "; break;
case 32:
default: std::cout << "uint32_t, "; break;
}
- std::cout << "0x" << base_address + offs << "> {\n";
+ std::cout << "0x" << base + offset << "> {\n";
- for (auto n : node.child("fields").children("field"))
- parse_field(name, n);
+ for (auto& f : fields) f();
std::cout << " };\n";
}
-void parse_field(const char *reg, const pugi::xml_node& node)
+Peripheral::Peripheral(const pugi::xml_node& node):
+ name(node.child_value("name")),
+ base(std::strtol(node.child_value("baseAddress"), nullptr, 0))
{
- const auto offs = std::strtol(node.child_value("bitOffset"), nullptr, 0);
- const auto width = std::strtol(node.child_value("bitWidth"), nullptr, 0);
- std::string name = node.child_value("name");
+ for (auto n : node.child("registers").children("register")) {
+ registers.emplace_back(name, n);
+ group += registers.back().name;
+ group += ", ";
+ }
+}
- if (name == reg)
- name += "_val";
+Peripheral::Peripheral(const pugi::xml_node& node, const Peripheral& derived):
+ name(node.child_value("name")),
+ base(std::strtol(node.child_value("baseAddress"), nullptr, 0)),
+ registers(derived.registers)
+{
+ for (auto& r : registers) {
+ group += r.name;
+ group += ", ";
+ }
+}
- std::cout << " using " << name << " = fr::RegisterMask<"
- << reg << ", (0x" << (1 << width) - 1 << "u << 0x" << offs << "u)>;\n";
+void Peripheral::operator()()
+{
+ std::cout << " namespace " << name << " {\n";
+
+ for (auto& r : registers) r(base);
+
+ std::cout << " using ALL = RegisterGroup<" << group.substr(0, group.size() - 2) << ">;\n";
+ std::cout << " }\n";
}