diff options
author | Amaury Pouly <amaury.pouly@gmail.com> | 2016-02-06 15:01:24 +0000 |
---|---|---|
committer | Amaury Pouly <amaury.pouly@gmail.com> | 2016-02-06 15:12:55 +0000 |
commit | 0f701a64bee43e79f95970ae9c0ec43ea7fcdf17 (patch) | |
tree | c8ac6b5516eac120797eb6a06f633919e9f48f9b /utils/regtools/swiss_knife.cpp | |
parent | 16c915ec1826dcef2e58ecc055a3f5dfcefb235a (diff) |
regtools: update v2 specification, library and tools
A v2 register description file can now include register variants and instances
addresses can now be a list (previously it could only be a stride or a formula).
Update the library to deal with that. The convert option of swiss_knife was
updated and one incompatible change was introduce: if a v1 device has several
addresses, those are converted to a single v2 instance with list (instead of
several single instances). This should have been the behaviour from the start.
Swiss_knife can now also convert regdumps, in which case it needs to be given
both the dump and register description file. Also introduce two register
descriptions files (vsoc1000 and vsoc2000) which give more complicated examples
of v2 register description files.
Change-Id: Id9415b8363269ffaf9216abfc6dd1bd1adbfcf8d
Diffstat (limited to 'utils/regtools/swiss_knife.cpp')
-rw-r--r-- | utils/regtools/swiss_knife.cpp | 259 |
1 files changed, 241 insertions, 18 deletions
diff --git a/utils/regtools/swiss_knife.cpp b/utils/regtools/swiss_knife.cpp index eaa2519a27..fb65b5ca24 100644 --- a/utils/regtools/swiss_knife.cpp +++ b/utils/regtools/swiss_knife.cpp @@ -20,11 +20,14 @@ ****************************************************************************/ #include "soc_desc.hpp" #include "soc_desc_v1.hpp" -#include <stdio.h> -#include <stdlib.h> +#include <cstdio> +#include <cstdlib> #include <map> #include <set> #include <cstring> +#include <fstream> +#include <sstream> +#include <cstring> using namespace soc_desc; @@ -88,7 +91,6 @@ bool convert_v1_to_v2(const soc_desc_v1::soc_reg_t& in, node_t& out, error_conte { std::string loc = _loc + "." + in.name; out.name = in.name; - out.desc = in.desc; if(in.formula.type == soc_desc_v1::REG_FORMULA_NONE) { out.instance.resize(in.addr.size()); @@ -133,6 +135,7 @@ bool convert_v1_to_v2(const soc_desc_v1::soc_reg_t& in, node_t& out, error_conte } out.register_.resize(1); out.register_[0].width = 32; + out.register_[0].desc = in.desc; out.register_[0].field.resize(in.field.size()); for(size_t i = 0; i < in.field.size(); i++) if(!convert_v1_to_v2(in.field[i], out.register_[0].field[i], ctx)) @@ -140,15 +143,12 @@ bool convert_v1_to_v2(const soc_desc_v1::soc_reg_t& in, node_t& out, error_conte /* sct */ if(in.flags & soc_desc_v1::REG_HAS_SCT) { - out.node.resize(1); - out.node[0].name = "SCT"; - out.node[0].instance.resize(3); - const char *names[3] = {"SET", "CLR", "TOG"}; + out.register_[0].variant.resize(3); + const char *names[3] = {"set", "clr", "tog"}; for(size_t i = 0; i < 3; i++) { - out.node[0].instance[i].name = names[i]; - out.node[0].instance[i].type = instance_t::SINGLE; - out.node[0].instance[i].addr = 4 + i *4; + out.register_[0].variant[i].type = names[i]; + out.register_[0].variant[i].offset = 4 + i *4; } } return true; @@ -171,10 +171,23 @@ bool convert_v1_to_v2(const soc_desc_v1::soc_dev_t& in, node_t& out, error_conte out.name = in.name; out.title = in.long_name; out.desc = in.desc; - out.instance.resize(in.addr.size()); - for(size_t i = 0; i < in.addr.size(); i++) - if(!convert_v1_to_v2(in.addr[i], out.instance[i], ctx)) - return false; + out.instance.resize(1); + if(in.addr.size() == 1) + { + out.instance[0].type = instance_t::SINGLE; + out.instance[0].name = in.addr[0].name; + out.instance[0].addr = in.addr[0].addr; + } + else + { + out.instance[0].type = instance_t::RANGE; + out.instance[0].name = in.name; + out.instance[0].range.type = range_t::LIST; + out.instance[0].range.first = 1; + out.instance[0].range.list.resize(in.addr.size()); + for(size_t i = 0; i < in.addr.size(); i++) + out.instance[0].range.list[i] = in.addr[i].addr; + } out.node.resize(in.reg.size()); for(size_t i = 0; i < in.reg.size(); i++) if(!convert_v1_to_v2(in.reg[i], out.node[i], ctx, loc)) @@ -195,8 +208,21 @@ bool convert_v1_to_v2(const soc_desc_v1::soc_t& in, soc_t& out, error_context_t& int do_convert(int argc, char **argv) { - if(argc != 2) - return printf("convert mode expects two arguments\n"); + std::vector< std::string > authors; + std::string version; + while(argc >= 2) + { + if(strcmp(argv[0], "--author") == 0) + authors.push_back(argv[1]); + else if(strcmp(argv[0], "--version") == 0) + version = argv[1]; + else + break; + argc -= 2; + argv += 2; + } + if(argc < 2) + return printf("convert mode expects at least one description file and an output file\n"); soc_desc_v1::soc_t soc; if(!soc_desc_v1::parse_xml(argv[0], soc)) return printf("cannot read file '%s'\n", argv[0]); @@ -207,6 +233,8 @@ int do_convert(int argc, char **argv) print_context(ctx); return printf("cannot convert from v1 to v2\n"); } + new_soc.author = authors; + new_soc.version = version; if(!produce_xml(argv[1], new_soc, ctx)) { print_context(ctx); @@ -392,7 +420,7 @@ void check_node(const std::string& _path, const node_t& node, error_context_t& c std::string path = _path + "." + node.name; check_name(_path, node.name, ctx); if(node.instance.empty()) - ctx.add(error_t(error_t::FATAL, path, "subnode with no instances")); + ctx.add(error_t(error_t::WARNING, path, "subnode with no instances")); for(size_t j = 0; j < node.instance.size(); j++) check_instance(path, node.instance[j], ctx); for(size_t i = 0; i < node.register_.size(); i++) @@ -506,6 +534,12 @@ void print_reg(register_ref_t reg, unsigned flags) printf(":[%u-%u]=", (unsigned)(f->pos + f->width - 1), (unsigned)f->pos); printf("%s\n", f->name.c_str()); } + std::vector< variant_ref_t > variants = reg.variants(); + for(size_t i = 0; i < variants.size(); i++) + { + print_path(node, false); + printf(":%s@+0x%x\n", variants[i].type().c_str(), variants[i].offset()); + } } void do_dump(node_ref_t node, unsigned flags) @@ -576,6 +610,178 @@ int do_dump(int argc, char **argv) return 0; } +std::string trim(const std::string& s) +{ + std::string ss = s.substr(s.find_first_not_of(" \t")); + return ss.substr(0, ss.find_last_not_of(" \t") + 1); +} + +bool parse_key(const std::string& key, std::string& dev, std::string& reg) +{ + if(key.substr(0, 3) != "HW.") + return false; + std::string s = key.substr(3); + size_t idx = s.find('.'); + if(idx == std::string::npos) + return false; + dev = s.substr(0, idx); + reg = s.substr(idx + 1); + return true; +} + +bool find_addr(const soc_desc_v1::soc_dev_t& dev, + const std::string& reg, soc_desc_v1::soc_addr_t& addr) +{ + for(size_t i = 0; i < dev.reg.size(); i++) + for(size_t j = 0; j < dev.reg[i].addr.size(); j++) + if(dev.reg[i].addr[j].name == reg) + { + addr += dev.reg[i].addr[j].addr; + return true; + } + return false; +} + +bool find_addr(const soc_desc_v1::soc_t& soc, const std::string& dev, + const std::string& reg, soc_desc_v1::soc_addr_t& addr) +{ + addr = 0; + for(size_t i = 0; i < soc.dev.size(); i++) + for(size_t j = 0; j < soc.dev[i].addr.size(); j++) + if(soc.dev[i].addr[j].name == dev) + { + addr += soc.dev[i].addr[j].addr; + return find_addr(soc.dev[i], reg, addr); + } + return false; +} + +int convert_dump(const std::map< std::string, std::string >& entries, + const soc_desc_v1::soc_t& soc, std::ofstream& fout) +{ + std::map< std::string, std::string >::const_iterator it = entries.begin(); + for(; it != entries.end(); ++it) + { + char *end; + soc_desc_v1::soc_word_t v = strtoul(it->second.c_str(), &end, 0); + if(*end != 0) + { + printf("because of invalid value '%s': ignore key '%s'\n", + it->second.c_str(), it->first.c_str()); + continue; + } + std::string dev, reg; + if(!parse_key(it->first, dev, reg)) + { + printf("invalid key format, ignore key '%s'\n", it->first.c_str()); + continue; + } + soc_desc_v1::soc_addr_t addr; + if(!find_addr(soc, dev, reg, addr)) + { + printf("cannot find register in description, ignore key '%s'\n", + it->first.c_str()); + continue; + } + fout << "0x" << std::hex << addr << " = 0x" << std::hex << v << "\n"; + } + return 0; +} + +int do_convertdump(int argc, char **argv) +{ + if(argc < 3) + { + printf("you must specify at least one description file, one input file and one output file\n"); + return 1; + } + std::vector< soc_desc_v1::soc_t > socs; + for(int i = 0; i < argc - 2; i++) + { + socs.resize(socs.size() + 1); + if(!parse_xml(argv[i], socs.back())) + { + socs.pop_back(); + printf("cannot parse description file '%s'\n", argv[i]); + } + } + std::ifstream fin(argv[argc - 2]); + if(!fin) + { + printf("cannot open input file\n"); + return 1; + } + std::map< std::string, std::string > entries; + std::string line; + while(std::getline(fin, line)) + { + size_t idx = line.find('='); + if(idx == std::string::npos) + { + printf("ignore invalid line '%s'\n", line.c_str()); + continue; + } + std::string key = trim(line.substr(0, idx)); + std::string value = trim(line.substr(idx + 1)); + entries[key] = value; + } + if(entries.find("HW") == entries.end()) + { + printf("invalid dump file: missing HW key\n"); + return 1; + } + std::string soc = entries["HW"]; + soc_desc_v1::soc_t *psoc = 0; + for(size_t i = 0; i < socs.size(); i++) + if(socs[i].name == soc) + psoc = &socs[i]; + if(psoc == 0) + { + printf("cannot convert dump: please provide the description file for the soc '%s'\n", soc.c_str()); + return 1; + } + entries.erase(entries.find("HW")); + std::ofstream fout(argv[argc - 1]); + if(!fout) + { + printf("cannot open output file\n"); + return 1; + } + fout << "soc = " << soc << "\n"; + return convert_dump(entries, *psoc, fout); +} + +int do_normalize(int argc, char **argv) +{ + if(argc != 2) + { + printf("normalize takes two arguments\n"); + return 1; + } + error_context_t ctx; + soc_t soc; + bool ret = parse_xml(argv[0], soc, ctx); + if(ctx.count() != 0) + printf("In file %s:\n", argv[0]); + print_context(ctx); + if(!ret) + { + printf("cannot parse file '%s'\n", argv[1]); + return 2; + } + normalize(soc); + ret = produce_xml(argv[1], soc, ctx); + if(ctx.count() != 0) + printf("In file %s:\n", argv[1]); + print_context(ctx); + if(!ret) + { + printf("cannot write file '%s'\n", argv[1]); + return 3; + } + return 0; +} + void usage() { printf("usage: swiss_knife <mode> [options]\n"); @@ -583,9 +789,22 @@ void usage() printf(" read <files...>\n"); printf(" write <read file> <write file>\n"); printf(" eval [<formula>|--var <name>=<val>]...\n"); - printf(" convert <input file> <output file>\n"); + printf(" convert [--author <auth>] [--version <ver>] <input file> <output file>\n"); printf(" check <files...>\n"); printf(" dump [--nodes] [--instances] [--registers] [--verbose] <files...>\n"); + printf(" convertdump <desc file> ... <desc file> <input dump file> <output dump file>\n"); + printf(" normalize <desc file> <output desc file>\n"); + printf("\n"); + printf("The following operations are performed in each mode:\n"); + printf("* read: open and parse the files, reports any obvious errors\n"); + printf("* write: open, parse a file and write it back, checks the parser/generator match\n"); + printf("* eval: evaluate a formula with the formula parser\n"); + printf("* convert: convert a description file from version 1 to version 2\n"); + printf("* check: performs deep checks on description files\n"); + printf("* dump: debug tool to dump internal structures\n"); + printf("* convertdump: convert a register dump from version 1 to version 2\n"); + printf(" NOTE: description file must be a v1 file\n"); + printf("* normalize: normalise a description file\n"); exit(1); } @@ -606,6 +825,10 @@ int main(int argc, char **argv) return do_check(argc - 2, argv + 2); else if(mode == "dump") return do_dump(argc - 2, argv + 2); + else if(mode == "convertdump") + return do_convertdump(argc - 2, argv + 2); + else if(mode == "normalize") + return do_normalize(argc - 2, argv + 2); else usage(); return 0; |