better svd parsing

This commit is contained in:
Clyne 2025-02-05 15:53:00 -05:00
parent 6d33ec1220
commit 9be811f585
Signed by: clyne
GPG Key ID: 3267C8EBF3F9AFC7
3 changed files with 124 additions and 39 deletions

View File

@ -192,9 +192,9 @@ struct Register {
// bit-mask created by merging all provided bit-masks. // bit-mask created by merging all provided bit-masks.
// If no masks are given, a mask selecting all bits is used. // If no masks are given, a mask selecting all bits is used.
template<typename... Masks> template<typename... Masks>
static void apply(auto fn) { static constexpr void apply(auto fn) {
if constexpr (sizeof...(Masks) > 0) { if constexpr (sizeof...(Masks) > 0) {
auto mask = mergeMasks<Masks...>(); constexpr auto mask = mergeMasks<Masks...>();
if constexpr (mask) if constexpr (mask)
write(fn(read(), mask)); write(fn(read(), mask));
} else { } else {
@ -205,7 +205,7 @@ struct Register {
// Takes a list of bit-masks, and returns a merged mask of those which are // Takes a list of bit-masks, and returns a merged mask of those which are
// meant for this register. // meant for this register.
template<typename... Masks> template<typename... Masks>
static auto mergeMasks() { static constexpr auto mergeMasks() {
if constexpr (sizeof...(Masks) > 0) { if constexpr (sizeof...(Masks) > 0) {
if constexpr ((isThis<typename Masks::reg> | ...)) { if constexpr ((isThis<typename Masks::reg> | ...)) {
auto mask = auto mask =

View File

@ -1,2 +1,2 @@
all: 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

View File

@ -1,13 +1,50 @@
#include "pugixml.hpp" #include "pugixml.hpp"
#include <cctype>
#include <cstdint> #include <cstdint>
#include <cstdlib> #include <cstdlib>
#include <iostream> #include <iostream>
#include <map>
#include <string> #include <string>
#include <vector>
static void parse_peripheral(const pugi::xml_node& node); struct Field {
static void parse_register(uint32_t base_address, const pugi::xml_node& node); std::string reg;
static void parse_field(const char *reg, const pugi::xml_node& node); 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[]) int main(int argc, char *argv[])
{ {
@ -19,63 +56,111 @@ int main(int argc, char *argv[])
if (!result) if (!result)
return -1; return -1;
std::cout << std::hex;
std::cout << "namespace " << doc.child("device").child_value("name")
<< " {\n";
for (auto node : doc.child("device") for (auto node : doc.child("device")
.child("peripherals") .child("peripherals")
.children("peripheral")) .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"; 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";
for (auto n : node.child("registers").children("register"))
parse_register(base, n);
std::cout << " }\n";
} }
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); std::cout << " using " << name << " = RegisterMask<"
const auto size = std::strtol(node.child_value("size"), nullptr, 0); << reg << ", (0x" << (1 << width) - 1 << "u << 0x" << offset << "u)>;\n";
const auto name = node.child_value("name"); }
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) { switch (size) {
case 8: std::cout << "uint8_t, "; break; case 8: std::cout << "uint8_t, "; break;
case 16: std::cout << "uint16_t, "; break; case 16: std::cout << "uint16_t, "; break;
case 32: case 32:
default: std::cout << "uint32_t, "; break; 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")) for (auto& f : fields) f();
parse_field(name, n);
std::cout << " };\n"; 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); for (auto n : node.child("registers").children("register")) {
const auto width = std::strtol(node.child_value("bitWidth"), nullptr, 0); registers.emplace_back(name, n);
std::string name = node.child_value("name"); group += registers.back().name;
group += ", ";
if (name == reg) }
name += "_val"; }
std::cout << " using " << name << " = fr::RegisterMask<" Peripheral::Peripheral(const pugi::xml_node& node, const Peripheral& derived):
<< reg << ", (0x" << (1 << width) - 1 << "u << 0x" << offs << "u)>;\n"; 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";
} }