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 - static void apply(auto fn) { + static constexpr void apply(auto fn) { if constexpr (sizeof...(Masks) > 0) { - auto mask = mergeMasks(); + constexpr auto mask = mergeMasks(); 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 - static auto mergeMasks() { + static constexpr auto mergeMasks() { if constexpr (sizeof...(Masks) > 0) { if constexpr ((isThis | ...)) { 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 #include #include #include +#include #include +#include -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 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 registers; + + Peripheral() = default; + Peripheral(const pugi::xml_node& node); + Peripheral(const pugi::xml_node& node, const Peripheral& derived); + void operator()(); +}; + +std::map 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); - - std::cout << " namespace " << node.child_value("name") << " {\n"; - - for (auto n : node.child("registers").children("register")) - parse_register(base, n); - - std::cout << " }\n"; + if (name == reg) + name = "val"; } -void parse_register(uint32_t base_address, const pugi::xml_node& node) +void Field::operator()() { - 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 << " using " << name << " = RegisterMask<" + << reg << ", (0x" << (1 << width) - 1 << "u << 0x" << offset << "u)>;\n"; +} - std::cout << " struct " << name << " : public fr::MemRegister<"; +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); + } + } + + for (auto n : node.child("fields").children("field")) + fields.emplace_back(name.c_str(), n); +} + +void Register::operator()(uint32_t base) +{ + 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"); - - if (name == reg) - name += "_val"; - - std::cout << " using " << name << " = fr::RegisterMask<" - << reg << ", (0x" << (1 << width) - 1 << "u << 0x" << offs << "u)>;\n"; + for (auto n : node.child("registers").children("register")) { + registers.emplace_back(name, n); + group += registers.back().name; + group += ", "; + } +} + +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 += ", "; + } +} + +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"; }