summaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2012-11-14 12:35:21 +0100
committerAmaury Pouly <amaury.pouly@gmail.com>2012-11-14 12:35:21 +0100
commit0c6b63479d83ada8782c751f779fef1271e2b874 (patch)
treee2db6cdfa340b9c5e0d2a34b66c71bb45215abcf /utils
parent5ead8f3f441221f19830af2866a33a7f3f03423e (diff)
downloadrockbox-0c6b63479d83ada8782c751f779fef1271e2b874.tar.gz
rockbox-0c6b63479d83ada8782c751f779fef1271e2b874.tar.bz2
rockbox-0c6b63479d83ada8782c751f779fef1271e2b874.zip
imxtools: add regtools to work with register descriptions
These tools allow one to read a register description in a XML file and to produce something useful out of it. Three example programs are written: - tester which simply prints the register tree - headergen which produces a set of headers with the #define - hwemulgen which produces something for the hwemul tool (to come) Change-Id: I52573688b29d5faeaf64ce7c5ffe08ee8db3d33c
Diffstat (limited to 'utils')
-rw-r--r--utils/imxtools/regtools/Makefile28
-rw-r--r--utils/imxtools/regtools/desc_parser.cpp265
-rw-r--r--utils/imxtools/regtools/desc_parser.hpp108
-rw-r--r--utils/imxtools/regtools/headergen.cpp274
-rw-r--r--utils/imxtools/regtools/hwemulgen.cpp387
-rw-r--r--utils/imxtools/regtools/tester.cpp126
6 files changed, 1188 insertions, 0 deletions
diff --git a/utils/imxtools/regtools/Makefile b/utils/imxtools/regtools/Makefile
new file mode 100644
index 0000000000..5dad380e7b
--- /dev/null
+++ b/utils/imxtools/regtools/Makefile
@@ -0,0 +1,28 @@
+DEFINES=
+CC=gcc
+CXX=g++
+LD=g++
+CFLAGS=-g -std=c99 -W -Wall `xml2-config --cflags` $(DEFINES)
+CXXFLAGS=-g -W -Wall `xml2-config --cflags` $(DEFINES)
+LDFLAGS=`xml2-config --libs`
+BINS= tester headergen hwemulgen
+
+all: $(BINS)
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+%.o: %.cpp
+ $(CXX) $(CXXFLAGS) -c -o $@ $<
+
+headergen: headergen.o desc_parser.o
+ $(LD) -o $@ $^ $(LDFLAGS)
+
+hwemulgen: hwemulgen.o desc_parser.o
+ $(LD) -o $@ $^ $(LDFLAGS)
+
+tester: tester.o desc_parser.o
+ $(LD) -o $@ $^ $(LDFLAGS)
+
+clean:
+ rm -fr *.o $(BINS)
diff --git a/utils/imxtools/regtools/desc_parser.cpp b/utils/imxtools/regtools/desc_parser.cpp
new file mode 100644
index 0000000000..940a619f5c
--- /dev/null
+++ b/utils/imxtools/regtools/desc_parser.cpp
@@ -0,0 +1,265 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2002 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "desc_parser.hpp"
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <stdio.h>
+#include <string.h>
+
+#define XML_CHAR_TO_CHAR(s) ((const char *)(s))
+
+#define BEGIN_ATTR_MATCH(attr) \
+ for(xmlAttr *a = attr; a; a = a->next) {
+
+#define MATCH_X_ATTR(attr_name, hook, ...) \
+ if(strcmp(XML_CHAR_TO_CHAR(a->name), attr_name) == 0) { \
+ std::string s; \
+ if(!parse_text_attr(a, s) || !hook(s, __VA_ARGS__)) \
+ return false; \
+ }
+
+#define SOFT_MATCH_X_ATTR(attr_name, hook, ...) \
+ if(strcmp(XML_CHAR_TO_CHAR(a->name), attr_name) == 0) { \
+ std::string s; \
+ if(parse_text_attr(a, s)) \
+ hook(s, __VA_ARGS__); \
+ }
+
+#define SOFT_MATCH_SCT_ATTR(attr_name, var) \
+ SOFT_MATCH_X_ATTR(attr_name, validate_sct_hook, var)
+
+#define MATCH_TEXT_ATTR(attr_name, var) \
+ MATCH_X_ATTR(attr_name, validate_string_hook, var)
+
+#define MATCH_UINT32_ATTR(attr_name, var) \
+ MATCH_X_ATTR(attr_name, validate_uint32_hook, var)
+
+#define MATCH_BITRANGE_ATTR(attr_name, first, last) \
+ MATCH_X_ATTR(attr_name, validate_bitrange_hook, first, last)
+
+#define END_ATTR_MATCH() \
+ }
+
+#define BEGIN_NODE_MATCH(node) \
+ for(xmlNode *sub = node; sub; sub = sub->next) {
+
+#define MATCH_ELEM_NODE(node_name, array, parse_fn) \
+ if(sub->type == XML_ELEMENT_NODE && strcmp(XML_CHAR_TO_CHAR(sub->name), node_name) == 0) { \
+ array.resize(array.size() + 1); \
+ if(!parse_fn(sub, array[array.size() - 1])) \
+ return false; \
+ }
+
+#define SOFT_MATCH_ELEM_NODE(node_name, array, parse_fn) \
+ if(sub->type == XML_ELEMENT_NODE && strcmp(XML_CHAR_TO_CHAR(sub->name), node_name) == 0) { \
+ array.resize(array.size() + 1); \
+ if(!parse_fn(sub, array[array.size() - 1])) \
+ array.pop_back(); \
+ }
+
+#define END_NODE_MATCH() \
+ }
+
+bool validate_string_hook(const std::string& str, std::string& s)
+{
+ s = str;
+ return true;
+}
+
+bool validate_sct_hook(const std::string& str, soc_reg_flags_t& flags)
+{
+ if(str == "yes") flags |= REG_HAS_SCT;
+ else if(str != "no") return false;
+ return true;
+}
+
+bool validate_unsigned_long_hook(const std::string& str, unsigned long& s)
+{
+ char *end;
+ s = strtoul(str.c_str(), &end, 0);
+ return *end == 0;
+}
+
+bool validate_uint32_hook(const std::string& str, uint32_t& s)
+{
+ unsigned long u;
+ if(!validate_unsigned_long_hook(str, u)) return false;
+#if ULONG_MAX > UINT32_MAX
+ if(u > UINT32_MAX) return false;
+#endif
+ s = u;
+ return true;
+}
+
+bool validate_bitrange_hook(const std::string& str, unsigned& first, unsigned& last)
+{
+ unsigned long a, b;
+ size_t sep = str.find(':');
+ if(sep == std::string::npos) return false;
+ if(!validate_unsigned_long_hook(str.substr(0, sep), a)) return false;
+ if(!validate_unsigned_long_hook(str.substr(sep + 1), b)) return false;
+ if(a > 31 || b > 31 || a < b) return false;
+ first = b;
+ last = a;
+ return true;
+}
+
+bool parse_text_attr(xmlAttr *attr, std::string& s)
+{
+ if(attr->children != attr->last)
+ return false;
+ if(attr->children->type != XML_TEXT_NODE)
+ return false;
+ s = XML_CHAR_TO_CHAR(attr->children->content);
+ return true;
+}
+
+bool parse_value_elem(xmlNode *node, soc_reg_field_value_t& value)
+{
+ BEGIN_ATTR_MATCH(node->properties)
+ MATCH_TEXT_ATTR("name", value.name)
+ MATCH_UINT32_ATTR("value", value.value)
+ END_ATTR_MATCH()
+
+ return true;
+}
+
+bool parse_field_elem(xmlNode *node, soc_reg_field_t& field)
+{
+ BEGIN_ATTR_MATCH(node->properties)
+ MATCH_TEXT_ATTR("name", field.name)
+ MATCH_BITRANGE_ATTR("bitrange", field.first_bit, field.last_bit)
+ END_ATTR_MATCH()
+
+ BEGIN_NODE_MATCH(node->children)
+ SOFT_MATCH_ELEM_NODE("value", field.values, parse_value_elem)
+ END_NODE_MATCH()
+
+ return true;
+}
+
+bool parse_reg_elem(xmlNode *node, soc_reg_t& reg)
+{
+ BEGIN_ATTR_MATCH(node->properties)
+ MATCH_TEXT_ATTR("name", reg.name)
+ MATCH_UINT32_ATTR("addr", reg.addr)
+ SOFT_MATCH_SCT_ATTR("sct", reg.flags)
+ END_ATTR_MATCH()
+
+ BEGIN_NODE_MATCH(node->children)
+ MATCH_ELEM_NODE("field", reg.fields, parse_field_elem)
+ END_NODE_MATCH()
+
+ return true;
+}
+
+bool parse_multireg_elem(xmlNode *node, soc_multireg_t& mreg)
+{
+ BEGIN_ATTR_MATCH(node->properties)
+ MATCH_TEXT_ATTR("name", mreg.name)
+ MATCH_UINT32_ATTR("base", mreg.base)
+ MATCH_UINT32_ATTR("count", mreg.count)
+ MATCH_UINT32_ATTR("offset", mreg.offset)
+ SOFT_MATCH_SCT_ATTR("sct", mreg.flags)
+ END_ATTR_MATCH()
+
+ BEGIN_NODE_MATCH(node->children)
+ MATCH_ELEM_NODE("reg", mreg.regs, parse_reg_elem)
+ MATCH_ELEM_NODE("field", mreg.fields, parse_field_elem)
+ END_NODE_MATCH()
+
+ return true;
+}
+
+bool parse_dev_elem(xmlNode *node, soc_dev_t& dev)
+{
+ BEGIN_ATTR_MATCH(node->properties)
+ MATCH_TEXT_ATTR("name", dev.name)
+ MATCH_UINT32_ATTR("addr", dev.addr)
+ MATCH_TEXT_ATTR("long_name", dev.long_name)
+ MATCH_TEXT_ATTR("desc", dev.desc)
+ END_ATTR_MATCH()
+
+ BEGIN_NODE_MATCH(node->children)
+ MATCH_ELEM_NODE("multireg", dev.multiregs, parse_multireg_elem)
+ MATCH_ELEM_NODE("reg", dev.regs, parse_reg_elem)
+ END_NODE_MATCH()
+
+ return true;
+}
+
+bool parse_multidev_elem(xmlNode *node, soc_multidev_t& dev)
+{
+ BEGIN_ATTR_MATCH(node->properties)
+ MATCH_TEXT_ATTR("name", dev.name)
+ MATCH_TEXT_ATTR("long_name", dev.long_name)
+ MATCH_TEXT_ATTR("desc", dev.desc)
+ END_ATTR_MATCH()
+
+ BEGIN_NODE_MATCH(node->children)
+ MATCH_ELEM_NODE("dev", dev.devs, parse_dev_elem)
+ MATCH_ELEM_NODE("multireg", dev.multiregs, parse_multireg_elem)
+ MATCH_ELEM_NODE("reg", dev.regs, parse_reg_elem)
+ END_NODE_MATCH()
+
+ return true;
+}
+
+bool parse_soc_elem(xmlNode *node, soc_t& soc)
+{
+ BEGIN_ATTR_MATCH(node->properties)
+ MATCH_TEXT_ATTR("name", soc.name)
+ MATCH_TEXT_ATTR("desc", soc.desc)
+ END_ATTR_MATCH()
+
+ BEGIN_NODE_MATCH(node->children)
+ MATCH_ELEM_NODE("dev", soc.devs, parse_dev_elem)
+ MATCH_ELEM_NODE("multidev", soc.multidevs, parse_multidev_elem)
+ END_NODE_MATCH()
+
+ return true;
+}
+
+bool parse_root_elem(xmlNode *node, std::vector< soc_t >& socs)
+{
+ BEGIN_NODE_MATCH(node)
+ MATCH_ELEM_NODE("soc", socs, parse_soc_elem)
+ END_NODE_MATCH()
+ return true;
+}
+
+bool parse_soc_desc(const std::string& filename, std::vector< soc_t >& socs)
+{
+ LIBXML_TEST_VERSION
+
+ xmlDoc *doc = xmlReadFile(filename.c_str(), NULL, 0);
+ if(doc == NULL)
+ return false;
+
+ xmlNode *root_element = xmlDocGetRootElement(doc);
+
+ bool ret = parse_root_elem(root_element, socs);
+
+ xmlFreeDoc(doc);
+ xmlCleanupParser();
+
+ return ret;
+} \ No newline at end of file
diff --git a/utils/imxtools/regtools/desc_parser.hpp b/utils/imxtools/regtools/desc_parser.hpp
new file mode 100644
index 0000000000..908cff8940
--- /dev/null
+++ b/utils/imxtools/regtools/desc_parser.hpp
@@ -0,0 +1,108 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2002 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef __DESC_PARSER__
+#define __DESC_PARSER__
+
+#include <stdint.h>
+#include <vector>
+#include <string>
+
+typedef uint32_t soc_addr_t;
+typedef uint32_t soc_word_t;
+typedef uint32_t soc_reg_flags_t;
+
+const soc_addr_t SOC_NO_ADDR = 0xffffffff;
+const soc_reg_flags_t REG_HAS_SCT = 1 << 0;
+
+struct soc_reg_field_value_t
+{
+ std::string name;
+ soc_word_t value;
+};
+
+struct soc_reg_field_t
+{
+ std::string name;
+ unsigned first_bit, last_bit;
+
+ soc_word_t bitmask() const
+ {
+ return ((1 << (last_bit - first_bit + 1)) - 1) << first_bit;
+ }
+
+ std::vector< soc_reg_field_value_t > values;
+};
+
+struct soc_reg_t
+{
+ std::string name;
+ soc_addr_t addr;
+ soc_reg_flags_t flags;
+
+ std::vector< soc_reg_field_t > fields;
+};
+
+struct soc_multireg_t
+{
+ std::string name;
+ soc_addr_t base;
+ unsigned count;
+ soc_addr_t offset;
+ soc_reg_flags_t flags;
+
+ std::vector< soc_reg_t > regs;
+ std::vector< soc_reg_field_t > fields;
+};
+
+struct soc_dev_t
+{
+ std::string name;
+ std::string long_name;
+ std::string desc;
+ soc_addr_t addr;
+
+ std::vector< soc_multireg_t > multiregs;
+ std::vector< soc_reg_t > regs;
+};
+
+struct soc_multidev_t
+{
+ std::string name;
+ std::string long_name;
+ std::string desc;
+
+ std::vector< soc_dev_t > devs;
+ std::vector< soc_multireg_t > multiregs;
+ std::vector< soc_reg_t > regs;
+};
+
+struct soc_t
+{
+ std::string name;
+ std::string desc;
+
+ std::vector< soc_dev_t > devs;
+ std::vector< soc_multidev_t > multidevs;
+};
+
+bool parse_soc_desc(const std::string& filename, std::vector< soc_t >& soc);
+
+#endif /* __DESC_PARSER__ */ \ No newline at end of file
diff --git a/utils/imxtools/regtools/headergen.cpp b/utils/imxtools/regtools/headergen.cpp
new file mode 100644
index 0000000000..b6905363d8
--- /dev/null
+++ b/utils/imxtools/regtools/headergen.cpp
@@ -0,0 +1,274 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2002 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "desc_parser.hpp"
+#include <stdio.h>
+#include <stdlib.h>
+#include <algorithm>
+#include <map>
+
+#define error(...) do{ fprintf(stderr, __VA_ARGS__); exit(1); } while(0)
+
+std::string g_soc_name;
+std::string g_soc_dev;
+std::string g_soc_reg;
+std::string g_soc_dev_regs_base;
+std::string g_soc_dev_reg_core_name;
+
+namespace {
+
+std::string tolower(const std::string s)
+{
+ std::string res = s;
+ std::transform(res.begin(), res.end(), res.begin(), ::tolower);
+ return res;
+}
+
+std::string toupper(const std::string& s)
+{
+ std::string res = s;
+ std::transform(res.begin(), res.end(), res.begin(), ::toupper);
+ return res;
+}
+
+}
+
+void fprint_copyright(FILE *f)
+{
+ fprintf(f,"\
+/***************************************************************************\n\
+ * __________ __ ___.\n\
+ * Open \\______ \\ ____ ____ | | _\\_ |__ _______ ___\n\
+ * Source | _// _ \\_/ ___\\| |/ /| __ \\ / _ \\ \\/ /\n\
+ * Jukebox | | ( <_> ) \\___| < | \\_\\ ( <_> > < <\n\
+ * Firmware |____|_ /\\____/ \\___ >__|_ \\|___ /\\____/__/\\_ \\\n\
+ * \\/ \\/ \\/ \\/ \\/\n\
+ * This file was automatically generated by headergen, DO NOT EDIT it.\n\
+ *\n\
+ * Copyright (C) 2012 by Amaury Pouly\n\
+ *\n\
+ * This program is free software; you can redistribute it and/or\n\
+ * modify it under the terms of the GNU General Public License\n\
+ * as published by the Free Software Foundation; either version 2\n\
+ * of the License, or (at your option) any later version.\n\
+ *\n\
+ * This software is distributed on an \"AS IS\" basis, WITHOUT WARRANTY OF ANY\n\
+ * KIND, either express or implied.\n\
+ *\n\
+ ****************************************************************************/\n");
+}
+
+void fprint_include_guard_ex(FILE *f, bool begin, const std::string& name)
+{
+ if(begin)
+ {
+ fprintf(f, "#ifndef %s\n", name.c_str());
+ fprintf(f, "#define %s\n", name.c_str());
+ fprintf(f, "\n#include \"imx233.h\"\n");
+ }
+ else
+ fprintf(f, "#endif /* %s */\n", name.c_str());
+}
+
+void fprint_include_guard(FILE *f, bool begin)
+{
+ std::string name = "__" + toupper(g_soc_name) + "__" + toupper(g_soc_dev)
+ + "__H__";
+ fprint_include_guard_ex(f, begin, name);
+}
+
+void fprint_fields(FILE *f, const std::vector< soc_reg_field_t >& fields)
+{
+ for(size_t i = 0; i < fields.size(); i++)
+ {
+ fprintf(f, "#define BM_%s_%s %#x\n", g_soc_dev_reg_core_name.c_str(),
+ fields[i].name.c_str(), fields[i].bitmask());
+ fprintf(f, "#define BP_%s_%s %d\n", g_soc_dev_reg_core_name.c_str(),
+ fields[i].name.c_str(), fields[i].first_bit);
+ fprintf(f, "#define BF_%s_%s(v) (((v) << %d) & %#x)\n",
+ g_soc_dev_reg_core_name.c_str(), fields[i].name.c_str(),
+ fields[i].first_bit, fields[i].bitmask());
+ if(fields[i].values.size() > 0)
+ {
+ fprintf(f, "#define BF_%s_%s_V(sym) ((BV_%s_%s__##sym << %d) & %#x)\n",
+ g_soc_dev_reg_core_name.c_str(), fields[i].name.c_str(),
+ g_soc_dev_reg_core_name.c_str(), fields[i].name.c_str(),
+ fields[i].first_bit, fields[i].bitmask());
+ }
+ for(size_t j = 0; j < fields[i].values.size(); j++)
+ {
+ fprintf(f, "#define BV_%s_%s__%s %#x\n", g_soc_dev_reg_core_name.c_str(),
+ fields[i].name.c_str(), fields[i].values[j].name.c_str(),
+ fields[i].values[j].value);
+ }
+ }
+}
+
+void fprint_reg(FILE *f, const soc_reg_t& reg)
+{
+ g_soc_dev_reg_core_name = toupper(g_soc_dev) + "_" + toupper(reg.name);
+
+ fprintf(f, "#define RA_%s %#x\n", g_soc_dev_reg_core_name.c_str(), reg.addr);
+ fprintf(f, "#define HW_%s HW_REG(%s, %s)\n", g_soc_dev_reg_core_name.c_str(),
+ toupper(g_soc_dev).c_str(), toupper(reg.name).c_str());
+ if(reg.flags & REG_HAS_SCT)
+ {
+ fprintf(f, "#define HW_%s_SET HW_SET(%s, %s)\n", g_soc_dev_reg_core_name.c_str(),
+ toupper(g_soc_dev).c_str(), toupper(reg.name).c_str());
+ fprintf(f, "#define HW_%s_CLR HW_CLR(%s, %s)\n", g_soc_dev_reg_core_name.c_str(),
+ toupper(g_soc_dev).c_str(), toupper(reg.name).c_str());
+ fprintf(f, "#define HW_%s_TOG HW_TOG(%s, %s)\n", g_soc_dev_reg_core_name.c_str(),
+ toupper(g_soc_dev).c_str(), toupper(reg.name).c_str());
+ }
+ fprint_fields(f, reg.fields);
+ fprintf(f, "\n");
+}
+
+void fprint_mreg(FILE *f, const soc_multireg_t& mreg)
+{
+}
+
+void gen_dev_header(const std::string& filename, const soc_dev_t& dev)
+{
+ g_soc_dev = dev.name;
+ printf(" Generate header for device %s: write to %s\n", dev.name.c_str(),
+ filename.c_str());
+ FILE *f = fopen(filename.c_str(), "w");
+ if(f == NULL)
+ error("Cannot open file %s\n", filename.c_str());
+ fprint_copyright(f);
+ fprint_include_guard(f, true);
+ fprintf(f, "\n");
+ g_soc_dev_regs_base = "RB_" + toupper(dev.name);
+ fprintf(f, "#define %s %#x\n", g_soc_dev_regs_base.c_str(), dev.addr);
+ fprintf(f, "\n");
+
+ for(size_t i = 0; i < dev.regs.size(); i++)
+ fprint_reg(f, dev.regs[i]);
+ for(size_t i = 0; i < dev.multiregs.size(); i++)
+ fprint_mreg(f, dev.multiregs[i]);
+
+ fprint_include_guard(f, false);
+ fclose(f);
+}
+
+void gen_mdev_header(const std::string& filename, const soc_multidev_t& dev)
+{
+ g_soc_dev = dev.name;
+ printf(" Generate header for multi device %s: write to %s\n", dev.name.c_str(),
+ filename.c_str());
+}
+
+void gen_soc_headers(const std::string& prefix, const soc_t& soc)
+{
+ printf("Generate headers for soc %s: use directory %s (must exists)\n", soc.desc.c_str(),
+ prefix.c_str());
+ for(size_t i = 0; i < soc.devs.size(); i++)
+ {
+ std::string name = soc.devs[i].name;
+ name = tolower(name);
+ gen_dev_header(prefix + "/regs-" + name + ".h", soc.devs[i]);
+ }
+ for(size_t i = 0; i < soc.multidevs.size(); i++)
+ {
+ std::string name = soc.multidevs[i].name;
+ name = tolower(name);
+ gen_mdev_header(prefix + "/regs-" + name + ".h", soc.multidevs[i]);
+ }
+}
+
+void gen_headers(const std::string& prefix, const std::vector< soc_t >& socs)
+{
+ for(size_t i = 0; i < socs.size(); i++)
+ {
+ g_soc_name = socs[i].name;
+ gen_soc_headers(prefix + "/" + socs[i].name, socs[i]);
+ }
+}
+
+typedef std::map< std::string, std::vector< std::string > > general_dev_list_t;
+general_dev_list_t build_general_dev_list(const std::vector< soc_t >& socs)
+{
+ general_dev_list_t map;
+ for(size_t i = 0; i < socs.size(); i++)
+ {
+ for(size_t j = 0; j < socs[i].devs.size(); j++)
+ map[tolower(socs[i].devs[j].name)].push_back(socs[i].name);
+ for(size_t j = 0; j < socs[i].multidevs.size(); j++)
+ map[tolower(socs[i].multidevs[j].name)].push_back(socs[i].name);
+ }
+ return map;
+}
+
+void gen_select_header(const std::string& filename, const std::string& dev,
+ const std::vector< std::string >& socs)
+{
+ printf("Generate select header for device %s: write to %s\n", dev.c_str(),
+ filename.c_str());
+
+ std::string guard = "__SELECT__" + toupper(dev) + "__H__";
+ FILE *f = fopen(filename.c_str(), "w");
+ if(f == NULL)
+ error("Cannot open file %s\n", filename.c_str());
+ fprint_copyright(f);
+ fprint_include_guard_ex(f, true, guard);
+ fprintf(f, "\n");
+
+ for(size_t i = 0; i < socs.size(); i++)
+ {
+ fprintf(f, "#define %s_INCLUDE \"%s/regs-%s.h\"\n",
+ toupper(socs[i]).c_str(), tolower(socs[i]).c_str(),
+ tolower(dev).c_str());
+ }
+ fprintf(f, "\n#include \"regs-select.h\"\n\n");
+ for(size_t i = 0; i < socs.size(); i++)
+ {
+ fprintf(f, "#undef %s_INCLUDE\n", toupper(socs[i]).c_str());
+ }
+ fprintf(f, "\n");
+ fprint_include_guard_ex(f, false, guard);
+ fclose(f);
+}
+
+void gen_selectors(const std::string& prefix, const std::vector< soc_t >& socs)
+{
+ general_dev_list_t map = build_general_dev_list(socs);
+ for(general_dev_list_t::iterator it = map.begin(); it != map.end(); ++it)
+ gen_select_header(prefix + "/regs-" + it->first + ".h", it->first, it->second);
+}
+
+void usage()
+{
+ printf("usage: headergen <desc file> <output prefix>\n");
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ if(argc != 3)
+ usage();
+ std::vector< soc_t > socs;
+ bool ret = parse_soc_desc(argv[1], socs);
+ printf("parse result: %d\n", ret);
+ if(!ret) return 1;
+ gen_headers(argv[2], socs);
+ gen_selectors(argv[2], socs);
+ return 0;
+} \ No newline at end of file
diff --git a/utils/imxtools/regtools/hwemulgen.cpp b/utils/imxtools/regtools/hwemulgen.cpp
new file mode 100644
index 0000000000..ae8b9dbec5
--- /dev/null
+++ b/utils/imxtools/regtools/hwemulgen.cpp
@@ -0,0 +1,387 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2002 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "desc_parser.hpp"
+#include <stdio.h>
+#include <stdlib.h>
+#include <algorithm>
+#include <map>
+
+#define error(...) do{ fprintf(stderr, __VA_ARGS__); exit(1); } while(0)
+
+int g_soc_count;
+int g_reg_count;
+int g_field_count;
+
+namespace {
+
+std::string tolower(const std::string s)
+{
+ std::string res = s;
+ std::transform(res.begin(), res.end(), res.begin(), ::tolower);
+ return res;
+}
+
+std::string toupper(const std::string& s)
+{
+ std::string res = s;
+ std::transform(res.begin(), res.end(), res.begin(), ::toupper);
+ return res;
+}
+
+bool lex_comp(const std::string& a, const std::string& b)
+{
+ return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end());
+}
+
+}
+
+void fprint_copyright(FILE *f)
+{
+ fprintf(f,"\
+/***************************************************************************\n\
+ * __________ __ ___.\n\
+ * Open \\______ \\ ____ ____ | | _\\_ |__ _______ ___\n\
+ * Source | _// _ \\_/ ___\\| |/ /| __ \\ / _ \\ \\/ /\n\
+ * Jukebox | | ( <_> ) \\___| < | \\_\\ ( <_> > < <\n\
+ * Firmware |____|_ /\\____/ \\___ >__|_ \\|___ /\\____/__/\\_ \\\n\
+ * \\/ \\/ \\/ \\/ \\/\n\
+ * This file was automatically generated by hwemulgen, DO NOT EDIT it.\n\
+ *\n\
+ * Copyright (C) 2012 by Amaury Pouly\n\
+ *\n\
+ * This program is free software; you can redistribute it and/or\n\
+ * modify it under the terms of the GNU General Public License\n\
+ * as published by the Free Software Foundation; either version 2\n\
+ * of the License, or (at your option) any later version.\n\
+ *\n\
+ * This software is distributed on an \"AS IS\" basis, WITHOUT WARRANTY OF ANY\n\
+ * KIND, either express or implied.\n\
+ *\n\
+ ****************************************************************************/\n");
+}
+
+void gen_header(const std::string& filename)
+{
+ FILE *f = fopen(filename.c_str(), "w");
+ if(f == NULL)
+ error("Cannot open file %s\n", filename.c_str());
+ fprint_copyright(f);
+ fprintf(f, "#ifndef __HWEMUL_SOC_HEADER__\n");
+ fprintf(f, "#define __HWEMUL_SOC_HEADER__\n");
+ fprintf(f, "\n");
+ fprintf(f, "#include \"stddef.h\"\n");
+ fprintf(f, "#include \"stdint.h\"\n");
+
+ fprintf(f, "\n\
+#define HWEMUL_SOC_REG_HAS_SCT (1 << 0)\n\
+\n\
+struct hwemul_soc_reg_field_t\n\
+{\n\
+ const char *name;\n\
+ unsigned short first_bit, last_bit;\n\
+};\n\
+\n\
+struct hwemul_soc_reg_t\n\
+{\n\
+ const char *name;\n\
+ uint32_t addr;\n\
+ uint32_t flags;\n\
+ size_t nr_fields;\n\
+ struct hwemul_soc_reg_field_t *fields_by_name[]; /* ordered by lexicographic order */\n\
+};\n\
+\n\
+struct hwemul_soc_t\n\
+{\n\
+ const char *name;\n\
+ size_t nr_regs;\n\
+ struct hwemul_soc_reg_t *regs_by_name[]; /* ordered by lexicographic order */\n\
+};\n\
+\n\
+struct hwemul_soc_list_t\n\
+{\n\
+ size_t nr_socs;\n\
+ struct hwemul_soc_t *socs[];\n\
+};\n\
+\n\
+struct hwemul_soc_list_t *hwemul_get_soc_list(void);\n\
+\n");
+
+ fprintf(f, "#endif\n");
+ fclose(f);
+}
+
+std::string extract_last_part(std::string s)
+{
+ size_t pos = s.find_last_of("/\\");
+ if(pos != std::string::npos)
+ s = s.substr(pos + 1);
+ pos = s.find_last_of(".");
+ if(pos != std::string::npos)
+ s = s.substr(0, pos);
+ return s;
+}
+
+std::vector< std::string > gen_fields(FILE *f, std::string prefix,
+ const std::vector< soc_reg_field_t >& fields)
+{
+ std::vector< std::string > list;
+
+ for(size_t i = 0; i < fields.size(); i++)
+ {
+ g_field_count++;
+ std::string var_name = prefix + tolower(fields[i].name);
+ list.push_back(var_name);
+
+ fprintf(f, "\
+static struct hwemul_soc_reg_field_t %s =\n\
+{\n\
+ \"%s\",\n\
+ %d, %d\n\
+};\n\
+\n", var_name.c_str(), fields[i].name.c_str(), fields[i].first_bit, fields[i].last_bit);
+ }
+
+ return list;
+}
+
+std::vector< std::string > gen_common_regs(FILE *f, std::string prefix, std::string devname,
+ soc_addr_t devaddr, const std::vector< soc_reg_t >& regs,
+ const std::vector< soc_multireg_t >& multiregs)
+{
+ std::vector< std::string > list;
+
+ for(size_t i = 0; i < regs.size(); i++)
+ {
+ g_reg_count++;
+ std::string var_name = prefix + tolower(regs[i].name);
+
+ list.push_back(var_name);
+
+ std::vector< std::string > field_vars = gen_fields(f, var_name + "_",
+ regs[i].fields);
+
+ std::sort(field_vars.begin(), field_vars.end(), lex_comp);
+
+ fprintf(f, "\
+static struct hwemul_soc_reg_t %s =\n\
+{\n\
+ \"HW_%s_%s\",\n\
+ %#x,\n\
+ 0", var_name.c_str(), devname.c_str(), regs[i].name.c_str(), devaddr + regs[i].addr);
+ if(regs[i].flags & REG_HAS_SCT)
+ fprintf(f, " | HWEMUL_SOC_REG_HAS_SCT");
+ fprintf(f, ",\n");
+ fprintf(f, "\
+ %u,\n\
+ {", (unsigned)field_vars.size());
+ if(field_vars.size() != 0)
+ fprintf(f, "\n");
+ for(size_t j = 0; j < field_vars.size(); j++)
+ fprintf(f, " &%s,\n", field_vars[j].c_str());
+ if(field_vars.size() != 0)
+ fprintf(f, " ");
+ fprintf(f,"\
+}\n};\n\
+\n");
+ }
+
+ for(size_t i = 0; i < multiregs.size(); i++)
+ {
+ g_reg_count++;
+ std::vector< std::string > field_vars = gen_fields(f,
+ prefix + tolower(multiregs[i].name) + "_", multiregs[i].fields);
+ std::sort(field_vars.begin(), field_vars.end(), lex_comp);
+
+ for(size_t j = 0; j < multiregs[i].regs.size(); j++)
+ {
+ g_reg_count++;
+ std::string var_name = prefix + tolower(multiregs[i].regs[j].name);
+
+ list.push_back(var_name);
+
+ fprintf(f, "\
+static struct hwemul_soc_reg_t %s =\n\
+{\n\
+ \"HW_%s_%s\",\n\
+ %#x,\n\
+ 0", var_name.c_str(), devname.c_str(), multiregs[i].regs[j].name.c_str(), devaddr + multiregs[i].regs[j].addr);
+ if(multiregs[i].flags & REG_HAS_SCT)
+ fprintf(f, " | HWEMUL_SOC_REG_HAS_SCT");
+ fprintf(f, ",\n");
+ fprintf(f,"\
+ %u,\n\
+ {", (unsigned)field_vars.size());
+ if(field_vars.size() != 0)
+ fprintf(f, "\n");
+ for(size_t k = 0; k < field_vars.size(); k++)
+ fprintf(f, " &%s,\n", field_vars[k].c_str());
+ if(field_vars.size() != 0)
+ fprintf(f, " ");
+ fprintf(f,"\
+}\n};\n\
+\n");
+ }
+ }
+
+ return list;
+}
+
+std::vector< std::string > gen_dev_regs(FILE *f, std::string prefix, const soc_dev_t& dev)
+{
+ return gen_common_regs(f, prefix + tolower(dev.name) + "_", dev.name, dev.addr,
+ dev.regs, dev.multiregs);
+}
+
+std::vector< std::string > gen_multidev_regs(FILE *f, std::string prefix, const soc_multidev_t& mdev)
+{
+ std::vector< std::string > list;
+
+ for(size_t i = 0; i < mdev.devs.size(); i++)
+ {
+ std::vector< std::string > sub_list = gen_common_regs(f,
+ prefix + tolower(mdev.devs[i].name) + "_", mdev.devs[i].name,
+ mdev.devs[i].addr, mdev.regs, mdev.multiregs);
+ list.insert(list.end(), sub_list.begin(), sub_list.end());
+ }
+
+ return list;
+}
+
+std::vector< std::string > gen_regs(FILE *f, std::string prefix, const soc_t& soc)
+{
+ std::vector< std::string > list;
+
+ for(size_t i = 0; i < soc.devs.size(); i++)
+ {
+ std::vector< std::string > sub_list = gen_dev_regs(f,
+ prefix, soc.devs[i]);
+ list.insert(list.end(), sub_list.begin(), sub_list.end());
+ }
+
+ for(size_t i = 0; i < soc.multidevs.size(); i++)
+ {
+ std::vector< std::string > sub_list = gen_multidev_regs(f,
+ prefix, soc.multidevs[i]);
+ list.insert(list.end(), sub_list.begin(), sub_list.end());
+ }
+
+ return list;
+}
+
+std::vector< std::string > gen_socs(FILE *f, std::string prefix, const std::vector< soc_t >& socs)
+{
+ std::vector< std::string > list;
+ for(size_t i = 0; i < socs.size(); i++)
+ {
+ g_soc_count++;
+ std::string var_name = prefix + socs[i].name;
+ list.push_back(var_name);
+
+ std::vector< std::string > reg_vars = gen_regs(f, var_name + "_", socs[i]);
+
+ std::sort(reg_vars.begin(), reg_vars.end(), lex_comp);
+
+ fprintf(f, "\
+static struct hwemul_soc_t %s =\n\
+{\n\
+ \"%s\",\n\
+ %u,\n\
+ {\n", var_name.c_str(), socs[i].name.c_str(), (unsigned)reg_vars.size());
+
+ for(size_t j = 0; j < reg_vars.size(); j++)
+ fprintf(f, " &%s,\n", reg_vars[j].c_str());
+ fprintf(f, "\
+ }\n\
+};\n\
+\n");
+ }
+
+ return list;
+}
+
+void gen_impl(const std::string& filename, const std::vector< soc_t >& socs)
+{
+ FILE *f = fopen(filename.c_str(), "w");
+ if(f == NULL)
+ error("Cannot open file %s\n", filename.c_str());
+ fprint_copyright(f);
+ std::string last_part = extract_last_part(filename);
+ fprintf(f, "#include \"%s.h\"\n\n", last_part.c_str());
+
+ std::vector< std::string > socs_var = gen_socs(f, "soc_", socs);
+
+ fprintf(f, "\
+static struct hwemul_soc_list_t hwemul_soc_list =\n\
+{\n\
+ %u,\n\
+ {", (unsigned) socs_var.size());
+
+ for(size_t i = 0; i < socs_var.size(); i++)
+ {
+ fprintf(f, "&%s", socs_var[i].c_str());
+ if(i + 1 != socs_var.size())
+ fprintf(f, ", ");
+ }
+ fprintf(f, "\
+}\n\
+};\n\
+\n");
+
+ fprintf(f,"\
+struct hwemul_soc_list_t *hwemul_get_soc_list(void)\n\
+{\n\
+ return &hwemul_soc_list;\n\
+}\n\
+\n");
+
+ fclose(f);
+}
+
+void gen_files(const std::string& output, const std::vector< soc_t >& socs)
+{
+ gen_header(output + ".h");
+ gen_impl(output + ".c", socs);
+}
+
+void usage()
+{
+ printf("usage: headergen <desc file list> <output file prefix>\n");
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ if(argc < 3)
+ usage();
+ std::vector< soc_t > socs;
+ for(int i = 1; i < argc - 1; i++)
+ {
+ bool ret = parse_soc_desc(argv[i], socs);
+ if(!ret)
+ {
+ printf("Cannot parse '%s'\n", argv[i]);
+ return 1;
+ }
+ }
+ gen_files(argv[argc - 1], socs);
+ printf("%d socs, %d registers and %d fields dumped!\n", g_soc_count, g_reg_count, g_field_count);
+ return 0;
+} \ No newline at end of file
diff --git a/utils/imxtools/regtools/tester.cpp b/utils/imxtools/regtools/tester.cpp
new file mode 100644
index 0000000000..a46d310f2a
--- /dev/null
+++ b/utils/imxtools/regtools/tester.cpp
@@ -0,0 +1,126 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2002 by Amaury Pouly
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "desc_parser.hpp"
+#include <stdio.h>
+#include <stdlib.h>
+
+void print_value_desc(const soc_reg_field_value_t& value)
+{
+ printf(" VALUE %s (%#x)\n", value.name.c_str(), value.value);
+}
+
+void print_field_desc(const soc_reg_field_t& field)
+{
+ printf(" FIELD %s (%d:%d)\n", field.name.c_str(), field.last_bit,
+ field.first_bit);
+ for(size_t i = 0; i < field.values.size(); i++)
+ print_value_desc(field.values[i]);
+}
+
+std::string compute_sct(soc_reg_flags_t f)
+{
+ if(f & REG_HAS_SCT) return "SCT";
+ else return "";
+}
+
+void print_reg_desc(const soc_reg_t& reg, bool in_multi)
+{
+ if(in_multi)
+ {
+ printf(" REG %s (%#x)\n", reg.name.c_str(), reg.addr);
+ }
+ else
+ {
+ std::string sct = compute_sct(reg.flags);
+ printf(" REG %s %s(%#x)\n", reg.name.c_str(), sct.c_str(), reg.addr);
+ for(size_t i = 0; i < reg.fields.size(); i++)
+ print_field_desc(reg.fields[i]);
+ }
+}
+
+void print_multireg_desc(const soc_multireg_t& mreg)
+{
+ std::string sct = compute_sct(mreg.flags);
+ printf(" MULTIREG %s %s(%#x * %d, +%#x)\n", mreg.name.c_str(), sct.c_str(),
+ mreg.base, mreg.count, mreg.offset);
+ for(size_t i = 0; i < mreg.regs.size(); i++)
+ print_reg_desc(mreg.regs[i], true);
+ for(size_t i = 0; i < mreg.fields.size(); i++)
+ print_field_desc(mreg.fields[i]);
+}
+
+
+void print_dev_desc(const soc_dev_t& dev, bool in_multi)
+{
+ if(in_multi)
+ {
+ printf(" DEV %s (%#x)\n", dev.name.c_str(), dev.addr);
+ }
+ else
+ {
+ printf(" DEV %s (%#x, %s, %s)\n", dev.name.c_str(), dev.addr,
+ dev.long_name.c_str(), dev.desc.c_str());
+ for(size_t i = 0; i < dev.multiregs.size(); i++)
+ print_multireg_desc(dev.multiregs[i]);
+ for(size_t i = 0; i < dev.regs.size(); i++)
+ print_reg_desc(dev.regs[i], false);
+ }
+}
+
+void print_multidev_desc(const soc_multidev_t& dev)
+{
+ printf(" MULTIDEV %s (%s, %s)\n", dev.name.c_str(), dev.long_name.c_str(),
+ dev.desc.c_str());
+ for(size_t i = 0; i < dev.devs.size(); i++)
+ print_dev_desc(dev.devs[i], true);
+ for(size_t i = 0; i < dev.multiregs.size(); i++)
+ print_multireg_desc(dev.multiregs[i]);
+ for(size_t i = 0; i < dev.regs.size(); i++)
+ print_reg_desc(dev.regs[i], false);
+}
+
+void print_soc_desc(const soc_t& soc)
+{
+ printf("SOC %s (%s)\n", soc.name.c_str(), soc.desc.c_str());
+ for(size_t i = 0; i < soc.devs.size(); i++)
+ print_dev_desc(soc.devs[i], false);
+ for(size_t i = 0; i < soc.multidevs.size(); i++)
+ print_multidev_desc(soc.multidevs[i]);
+}
+
+void usage()
+{
+ printf("usage: tester <desc file>\n");
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ if(argc != 2)
+ usage();
+ std::vector< soc_t > socs;
+ bool ret = parse_soc_desc(argv[1], socs);
+ printf("parse result: %d\n", ret);
+ if(ret)
+ for(size_t i = 0; i < socs.size(); i++)
+ print_soc_desc(socs[i]);
+ return 0;
+} \ No newline at end of file