summaryrefslogtreecommitdiffstats
path: root/utils/regtools/lib
diff options
context:
space:
mode:
Diffstat (limited to 'utils/regtools/lib')
-rw-r--r--utils/regtools/lib/Makefile23
-rw-r--r--utils/regtools/lib/soc_desc.cpp268
-rw-r--r--utils/regtools/lib/soc_desc.hpp147
3 files changed, 438 insertions, 0 deletions
diff --git a/utils/regtools/lib/Makefile b/utils/regtools/lib/Makefile
new file mode 100644
index 0000000000..ef8d4c0533
--- /dev/null
+++ b/utils/regtools/lib/Makefile
@@ -0,0 +1,23 @@
+CC=gcc
+CXX=g++
+AR=ar
+CFLAGS=-Wall -O2 `xml2-config --cflags` -std=c99 -g -fPIC
+CXXFLAGS=-Wall -O2 `xml2-config --cflags` -g -fPIC
+LIB=libsocdesc.a
+SRC=$(wildcard *.c)
+SRCXX=$(wildcard *.cpp)
+OBJ=$(SRC:.c=.o) $(SRCXX:.cpp=.o)
+
+all: $(LIB) $(EXEC)
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+%.o: %.cpp
+ $(CXX) $(CXXFLAGS) -c -o $@ $<
+
+$(LIB): $(OBJ)
+ $(AR) rcs $@ $^
+
+clean:
+ rm -rf $(OBJ) $(LIB) \ No newline at end of file
diff --git a/utils/regtools/lib/soc_desc.cpp b/utils/regtools/lib/soc_desc.cpp
new file mode 100644
index 0000000000..413c30936f
--- /dev/null
+++ b/utils/regtools/lib/soc_desc.cpp
@@ -0,0 +1,268 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2012 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 "soc_desc.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.value, parse_value_elem)
+ END_NODE_MATCH()
+
+ return true;
+}
+
+bool parse_reg_addr_elem(xmlNode *node, soc_reg_addr_t& addr)
+{
+ BEGIN_ATTR_MATCH(node->properties)
+ MATCH_TEXT_ATTR("name", addr.name)
+ MATCH_UINT32_ATTR("addr", addr.addr)
+ END_ATTR_MATCH()
+
+ return true;
+}
+
+bool parse_reg_formula_elem(xmlNode *node, soc_reg_formula_t& formula)
+{
+ BEGIN_ATTR_MATCH(node->properties)
+ MATCH_TEXT_ATTR("string", formula.string)
+ END_ATTR_MATCH()
+
+ formula.type = REG_FORMULA_STRING;
+
+ return true;
+}
+
+bool parse_reg_elem(xmlNode *node, soc_reg_t& reg)
+{
+ std::vector< soc_reg_formula_t > formulas;
+ BEGIN_ATTR_MATCH(node->properties)
+ MATCH_TEXT_ATTR("name", reg.name)
+ SOFT_MATCH_SCT_ATTR("sct", reg.flags)
+ END_ATTR_MATCH()
+
+ BEGIN_NODE_MATCH(node->children)
+ MATCH_ELEM_NODE("addr", reg.addr, parse_reg_addr_elem)
+ MATCH_ELEM_NODE("formula", formulas, parse_reg_formula_elem)
+ MATCH_ELEM_NODE("field", reg.field, parse_field_elem)
+ END_NODE_MATCH()
+
+ if(formulas.size() > 1)
+ {
+ fprintf(stderr, "Only one formula is allowed per register\n");
+ return false;
+ }
+ if(formulas.size() == 1)
+ reg.formula = formulas[0];
+
+ return true;
+}
+
+bool parse_dev_addr_elem(xmlNode *node, soc_dev_addr_t& addr)
+{
+ BEGIN_ATTR_MATCH(node->properties)
+ MATCH_TEXT_ATTR("name", addr.name)
+ MATCH_UINT32_ATTR("addr", addr.addr)
+ END_ATTR_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_TEXT_ATTR("version", dev.version)
+ END_ATTR_MATCH()
+
+ BEGIN_NODE_MATCH(node->children)
+ MATCH_ELEM_NODE("addr", dev.addr, parse_dev_addr_elem)
+ MATCH_ELEM_NODE("reg", dev.reg, 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.dev, parse_dev_elem)
+ END_NODE_MATCH()
+
+ return true;
+}
+
+bool parse_root_elem(xmlNode *node, std::vector< soc_t >& soc)
+{
+ BEGIN_NODE_MATCH(node)
+ MATCH_ELEM_NODE("soc", soc, parse_soc_elem)
+ END_NODE_MATCH()
+ return true;
+}
+
+bool soc_desc_parse_xml(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/regtools/lib/soc_desc.hpp b/utils/regtools/lib/soc_desc.hpp
new file mode 100644
index 0000000000..476ea1d242
--- /dev/null
+++ b/utils/regtools/lib/soc_desc.hpp
@@ -0,0 +1,147 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2012 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 __SOC_DESC__
+#define __SOC_DESC__
+
+#include <stdint.h>
+#include <vector>
+#include <string>
+
+/**
+ * These data structures represent the SoC register in a convenient way.
+ * The basic structure is the following:
+ * - each SoC has several devices
+ * - each device has a generic name, a list of {name,address} and several registers
+ * - each register has a generic name, a list of {name,address}, flags,
+ * several fields
+ * - each field has a name, a first and last bit position, can apply either
+ * to all addresses of a register or be specific to one only and has several values
+ * - each field value has a name and a value
+ *
+ * All addresses, values and names are relative to the parents. For example a field
+ * value BV_LCDIF_CTRL_WORD_LENGTH_18_BIT is represented has:
+ * - device LCDIF, register CTRL, field WORD_LENGTH, value 16_BIT
+ * The address of CTRL is related to the address of LCDIF, the value of 16_BIT
+ * ignores the position of the WORD_LENGTH field in the register.
+ */
+
+/**
+ * Typedef for SoC types: word, address and flags */
+typedef uint32_t soc_addr_t;
+typedef uint32_t soc_word_t;
+typedef uint32_t soc_reg_flags_t;
+
+/** SoC register generic formula */
+enum soc_reg_formula_type_t
+{
+ REG_FORMULA_NONE, /// register has no generic formula
+ REG_FORMULA_STRING, /// register has a generic formula represented by a string
+};
+
+/** <soc_reg_t>.<flags> values */
+const soc_reg_flags_t REG_HAS_SCT = 1 << 0; /// register SCT variants
+
+/** SoC register field named value */
+struct soc_reg_field_value_t
+{
+ std::string name;
+ soc_word_t value;
+};
+
+/** SoC register field */
+struct soc_reg_field_t
+{
+ std::string name;
+ unsigned first_bit, last_bit;
+
+ soc_word_t bitmask() const
+ {
+ // WARNING beware of the case where first_bit=0 and last_bit=31
+ if(first_bit == 0 && last_bit == 31)
+ return 0xffffffff;
+ else
+ return ((1 << (last_bit - first_bit + 1)) - 1) << first_bit;
+ }
+
+ bool is_reserved() const
+ {
+ return name.substr(0, 4) == "RSVD" || name.substr(0, 5) == "RSRVD";
+ }
+
+ std::vector< soc_reg_field_value_t > value;
+};
+
+/** SoC register address */
+struct soc_reg_addr_t
+{
+ std::string name; /// actual register name
+ soc_addr_t addr;
+};
+
+/** SoC register formula */
+struct soc_reg_formula_t
+{
+ enum soc_reg_formula_type_t type;
+ std::string string; /// for STRING
+};
+
+/** SoC register */
+struct soc_reg_t
+{
+ std::string name; /// generic name (for multi registers) or actual name
+ std::vector< soc_reg_addr_t > addr;
+ soc_reg_formula_t formula;
+ soc_reg_flags_t flags; /// ORed value
+
+ std::vector< soc_reg_field_t > field;
+};
+
+/** Soc device address */
+struct soc_dev_addr_t
+{
+ std::string name; /// actual device name
+ soc_addr_t addr;
+};
+
+/** SoC device */
+struct soc_dev_t
+{
+ std::string name; /// generic name (of multi devices) or actual name
+ std::string version; /// description version
+ std::vector< soc_dev_addr_t > addr;
+
+ std::vector< soc_reg_t > reg;
+};
+
+/** SoC */
+struct soc_t
+{
+ std::string name; /// codename (rockbox)
+ std::string desc; /// SoC name
+
+ std::vector< soc_dev_t > dev;
+};
+
+/** Parse a SoC description from a XML file, append it to <soc>. A file
+ * can contain multiple SoC descriptions */
+bool soc_desc_parse_xml(const std::string& filename, std::vector< soc_t >& soc);
+
+#endif /* __SOC_DESC__ */ \ No newline at end of file