summaryrefslogtreecommitdiffstats
path: root/utils/regtools/lib
diff options
context:
space:
mode:
Diffstat (limited to 'utils/regtools/lib')
-rw-r--r--utils/regtools/lib/Makefile9
-rw-r--r--utils/regtools/lib/formula.cpp214
-rw-r--r--utils/regtools/lib/soc_desc.cpp1530
-rw-r--r--utils/regtools/lib/soc_desc.hpp228
-rw-r--r--utils/regtools/lib/soc_desc_v1.cpp990
5 files changed, 2073 insertions, 898 deletions
diff --git a/utils/regtools/lib/Makefile b/utils/regtools/lib/Makefile
index 08021ef941..d7d6c1b07a 100644
--- a/utils/regtools/lib/Makefile
+++ b/utils/regtools/lib/Makefile
@@ -1,18 +1,15 @@
CC?=gcc
CXX?=g++
AR?=ar
-CFLAGS=-Wall -O2 `xml2-config --cflags` -std=c99 -g -fPIC
-CXXFLAGS=-Wall -O2 `xml2-config --cflags` -g -fPIC
+INCLUDE=../include/
+CXXFLAGS=-Wall -O2 `xml2-config --cflags` -g -fPIC -I$(INCLUDE)
LIB=libsocdesc.a
SRC=$(wildcard *.c)
SRCXX=$(wildcard *.cpp)
-OBJ=$(SRC:.c=.o) $(SRCXX:.cpp=.o)
+OBJ=$(SRCXX:.cpp=.o)
all: $(LIB) $(EXEC)
-%.o: %.c
- $(CC) $(CFLAGS) -c -o $@ $<
-
%.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o $@ $<
diff --git a/utils/regtools/lib/formula.cpp b/utils/regtools/lib/formula.cpp
new file mode 100644
index 0000000000..1a6b16c773
--- /dev/null
+++ b/utils/regtools/lib/formula.cpp
@@ -0,0 +1,214 @@
+#include "soc_desc.hpp"
+#include <cstdarg>
+#include <cstdio>
+
+using namespace soc_desc;
+
+namespace soc_desc
+{
+
+namespace
+{
+
+struct formula_evaluator
+{
+ std::string formula;
+ size_t pos;
+ error_context_t& ctx;
+ std::string m_loc;
+
+ bool err(const char *fmt, ...)
+ {
+ char buffer[256];
+ va_list args;
+ va_start(args, fmt);
+ vsnprintf(buffer,sizeof(buffer), fmt, args);
+ va_end(args);
+ ctx.add(error_t(error_t::FATAL, m_loc, buffer));
+ return false;
+ }
+
+ formula_evaluator(const std::string& s, error_context_t& ctx):pos(0),ctx(ctx)
+ {
+ for(size_t i = 0; i < s.size(); i++)
+ if(!isspace(s[i]))
+ formula.push_back(s[i]);
+ }
+
+ void set_location(const std::string& loc)
+ {
+ m_loc = loc;
+ }
+
+ void adv()
+ {
+ pos++;
+ }
+
+ char cur()
+ {
+ return end() ? 0 : formula[pos];
+ }
+
+ bool end()
+ {
+ return pos >= formula.size();
+ }
+
+ bool parse_digit(char c, int basis, soc_word_t& res)
+ {
+ c = tolower(c);
+ if(isdigit(c))
+ {
+ res = c - '0';
+ return true;
+ }
+ if(basis == 16 && isxdigit(c))
+ {
+ res = c + 10 - 'a';
+ return true;
+ }
+ return false;
+ }
+
+ bool parse_signed(soc_word_t& res)
+ {
+ char op = cur();
+ if(op == '+' || op == '-')
+ {
+ adv();
+ if(!parse_signed(res))
+ return false;
+ if(op == '-')
+ res *= -1;
+ return true;
+ }
+ else if(op == '(')
+ {
+ adv();
+ if(!parse_expression(res))
+ return false;
+ if(cur() != ')')
+ return err("expected ')', got '%c'", cur());
+ adv();
+ return true;
+ }
+ else if(isdigit(op))
+ {
+ res = op - '0';
+ adv();
+ int basis = 10;
+ if(op == '0' && cur() == 'x')
+ {
+ basis = 16;
+ adv();
+ }
+ soc_word_t digit = 0;
+ while(parse_digit(cur(), basis, digit))
+ {
+ res = res * basis + digit;
+ adv();
+ }
+ return true;
+ }
+ else if(isalpha(op) || op == '_')
+ {
+ std::string name;
+ while(isalnum(cur()) || cur() == '_')
+ {
+ name.push_back(cur());
+ adv();
+ }
+ return get_variable(name, res);
+ }
+ else
+ return err("express signed expression, got '%c'", op);
+ }
+
+ bool parse_term(soc_word_t& res)
+ {
+ if(!parse_signed(res))
+ return false;
+ while(cur() == '*' || cur() == '/' || cur() == '%')
+ {
+ char op = cur();
+ adv();
+ soc_word_t tmp;
+ if(!parse_signed(tmp))
+ return false;
+ if(op == '*')
+ res *= tmp;
+ else if(tmp != 0)
+ res = op == '/' ? res / tmp : res % tmp;
+ else
+ return err("division by 0");
+ }
+ return true;
+ }
+
+ bool parse_expression(soc_word_t& res)
+ {
+ if(!parse_term(res))
+ return false;
+ while(!end() && (cur() == '+' || cur() == '-'))
+ {
+ char op = cur();
+ adv();
+ soc_word_t tmp;
+ if(!parse_term(tmp))
+ return false;
+ if(op == '+')
+ res += tmp;
+ else
+ res -= tmp;
+ }
+ return true;
+ }
+
+ bool parse(soc_word_t& res)
+ {
+ bool ok = parse_expression(res);
+ if(ok && !end())
+ err("unexpected character '%c'", cur());
+ return ok && end();
+ }
+
+ virtual bool get_variable(std::string name, soc_word_t& res)
+ {
+ return err("unknown variable '%s'", name.c_str());
+ }
+};
+
+struct my_evaluator : public formula_evaluator
+{
+ const std::map< std::string, soc_word_t>& var;
+
+ my_evaluator(const std::string& formula, const std::map< std::string, soc_word_t>& _var,
+ error_context_t& ctx)
+ :formula_evaluator(formula, ctx), var(_var) {}
+
+ virtual bool get_variable(std::string name, soc_word_t& res)
+ {
+ std::map< std::string, soc_word_t>::const_iterator it = var.find(name);
+ if(it == var.end())
+ return formula_evaluator::get_variable(name, res);
+ else
+ {
+ res = it->second;
+ return true;
+ }
+ }
+};
+
+}
+
+bool evaluate_formula(const std::string& formula,
+ const std::map< std::string, soc_word_t>& var, soc_word_t& result,
+ const std::string& loc, error_context_t& error)
+{
+ my_evaluator e(formula, var, error);
+ e.set_location(loc);
+ return e.parse(result);
+}
+
+} // soc_desc
diff --git a/utils/regtools/lib/soc_desc.cpp b/utils/regtools/lib/soc_desc.cpp
index 90e4e0eb81..4e0e46f00e 100644
--- a/utils/regtools/lib/soc_desc.cpp
+++ b/utils/regtools/lib/soc_desc.cpp
@@ -7,7 +7,7 @@
* \/ \/ \/ \/ \/
* $Id$
*
- * Copyright (C) 2012 by Amaury Pouly
+ * Copyright (C) 2014 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
@@ -27,261 +27,429 @@
#include <string.h>
#include <algorithm>
#include <cctype>
+#include <sstream>
+#include <limits>
+
+namespace soc_desc
+{
+
+/**
+ * Parser
+ */
#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, ...) \
+#define MATCH_UNIQUE_ATTR(attr_name, val, has, parse_fn, ctx) \
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; \
+ if(has) \
+ return parse_not_unique_attr_error(a, ctx); \
+ has = true; \
+ xmlChar *str = NULL; \
+ if(!parse_text_attr_internal(a, str, ctx) || !parse_fn(a, val, str, ctx)) \
+ ret = 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) \
+#define MATCH_ELEM_NODE(node_name, array, parse_fn, ctx) \
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.back())) \
- return false; \
+ if(!parse_fn(sub, array.back(), ctx)) \
+ ret = false; \
+ array.back().id = array.size(); \
}
-#define SOFT_MATCH_ELEM_NODE(node_name, array, parse_fn) \
+#define MATCH_TEXT_NODE(node_name, array, parse_fn, ctx) \
if(sub->type == XML_ELEMENT_NODE && strcmp(XML_CHAR_TO_CHAR(sub->name), node_name) == 0) { \
+ if(!is_real_text_node(sub)) \
+ return parse_not_text_error(sub, ctx); \
+ xmlChar *content = xmlNodeGetContent(sub); \
array.resize(array.size() + 1); \
- if(!parse_fn(sub, array.back())) \
- array.pop_back(); \
+ ret = ret && parse_fn(sub, array.back(), content, ctx); \
+ xmlFree(content); \
+ }
+
+#define MATCH_UNIQUE_ELEM_NODE(node_name, val, has, parse_fn, ctx) \
+ if(sub->type == XML_ELEMENT_NODE && strcmp(XML_CHAR_TO_CHAR(sub->name), node_name) == 0) { \
+ if(has) \
+ return parse_not_unique_error(sub, ctx); \
+ has = true; \
+ if(!parse_fn(sub, val, ctx)) \
+ ret = false; \
+ }
+
+#define MATCH_UNIQUE_TEXT_NODE(node_name, val, has, parse_fn, ctx) \
+ if(sub->type == XML_ELEMENT_NODE && strcmp(XML_CHAR_TO_CHAR(sub->name), node_name) == 0) { \
+ if(has) \
+ return parse_not_unique_error(sub, ctx); \
+ if(!is_real_text_node(sub)) \
+ return parse_not_text_error(sub, ctx); \
+ has = true; \
+ xmlChar *content = xmlNodeGetContent(sub); \
+ ret = ret && parse_fn(sub, val, content, ctx); \
+ xmlFree(content); \
}
#define END_NODE_MATCH() \
}
+#define CHECK_HAS(node, node_name, has, ctx) \
+ if(!has) \
+ ret = ret && parse_missing_error(node, node_name, ctx);
+
+#define CHECK_HAS_ATTR(node, attr_name, has, ctx) \
+ if(!has) \
+ ret = ret && parse_missing_attr_error(node, attr_name, ctx);
+
namespace
{
-bool validate_string_hook(const std::string& str, std::string& s)
+bool is_real_text_node(xmlNode *node)
{
- s = str;
+ for(xmlNode *sub = node->children; sub; sub = sub->next)
+ if(sub->type != XML_TEXT_NODE && sub->type != XML_ENTITY_REF_NODE)
+ return false;
return true;
}
-bool validate_sct_hook(const std::string& str, soc_reg_flags_t& flags)
+std::string xml_loc(xmlNode *node)
{
- if(str == "yes") flags |= REG_HAS_SCT;
- else if(str != "no") return false;
- return true;
+ std::ostringstream oss;
+ oss << "line " << node->line;
+ return oss.str();
}
-bool validate_unsigned_long_hook(const std::string& str, unsigned long& s)
+std::string xml_loc(xmlAttr *attr)
{
- char *end;
- s = strtoul(str.c_str(), &end, 0);
- return *end == 0;
+ return xml_loc(attr->parent);
}
-bool validate_uint32_hook(const std::string& str, uint32_t& s)
+template<typename T>
+bool add_error(error_context_t& ctx, error_t::level_t lvl, T *node,
+ const std::string& msg)
{
- unsigned long u;
- if(!validate_unsigned_long_hook(str, u)) return false;
-#if ULONG_MAX > 0xffffffff
- if(u > 0xffffffff) return false;
-#endif
- s = u;
- return true;
+ ctx.add(error_t(lvl, xml_loc(node), msg));
+ return false;
}
-bool validate_bitrange_hook(const std::string& str, unsigned& first, unsigned& last)
+template<typename T>
+bool add_fatal(error_context_t& ctx, T *node, const std::string& msg)
{
- 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;
+ return add_error(ctx, error_t::FATAL, node, msg);
}
-bool parse_text_attr(xmlAttr *attr, std::string& s)
+template<typename T>
+bool add_warning(error_context_t& ctx, T *node, const std::string& msg)
{
- 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;
+ return add_error(ctx, error_t::WARNING, node, msg);
}
-bool parse_value_elem(xmlNode *node, soc_reg_field_value_t& value)
+bool parse_wrong_version_error(xmlNode *node, error_context_t& ctx)
{
- BEGIN_ATTR_MATCH(node->properties)
- MATCH_TEXT_ATTR("name", value.name)
- MATCH_UINT32_ATTR("value", value.value)
- MATCH_TEXT_ATTR("desc", value.desc)
- END_ATTR_MATCH()
+ std::ostringstream oss;
+ oss << "unknown version, only version " << MAJOR_VERSION << " is supported";
+ return add_fatal(ctx, node, oss.str());
+}
- return true;
+bool parse_not_unique_error(xmlNode *node, error_context_t& ctx)
+{
+ std::ostringstream oss;
+ oss << "there must be a unique <" << XML_CHAR_TO_CHAR(node->name) << "> element";
+ if(node->parent->name)
+ oss << " in <" << XML_CHAR_TO_CHAR(node->parent->name) << ">";
+ else
+ oss << " at root level";
+ return add_fatal(ctx, node, oss.str());
}
-bool parse_field_elem(xmlNode *node, soc_reg_field_t& field)
+bool parse_not_unique_attr_error(xmlAttr *attr, error_context_t& ctx)
{
- BEGIN_ATTR_MATCH(node->properties)
- MATCH_TEXT_ATTR("name", field.name)
- MATCH_BITRANGE_ATTR("bitrange", field.first_bit, field.last_bit)
- MATCH_TEXT_ATTR("desc", field.desc)
- END_ATTR_MATCH()
+ std::ostringstream oss;
+ oss << "there must be a unique " << XML_CHAR_TO_CHAR(attr->name) << " attribute";
+ oss << " in <" << XML_CHAR_TO_CHAR(attr->parent->name) << ">";
+ return add_fatal(ctx, attr, oss.str());
+}
- BEGIN_NODE_MATCH(node->children)
- SOFT_MATCH_ELEM_NODE("value", field.value, parse_value_elem)
- END_NODE_MATCH()
+bool parse_missing_error(xmlNode *node, const char *name, error_context_t& ctx)
+{
+ std::ostringstream oss;
+ oss << "missing <" << name << "> element";
+ if(node->parent->name)
+ oss << " in <" << XML_CHAR_TO_CHAR(node->parent->name) << ">";
+ else
+ oss << " at root level";
+ return add_fatal(ctx, node, oss.str());
+}
- return true;
+bool parse_missing_attr_error(xmlNode *node, const char *name, error_context_t& ctx)
+{
+ std::ostringstream oss;
+ oss << "missing " << name << " attribute";
+ oss << " in <" << XML_CHAR_TO_CHAR(node->name) << ">";
+ return add_fatal(ctx, node, oss.str());
}
-bool parse_reg_addr_elem(xmlNode *node, soc_reg_addr_t& addr)
+bool parse_conflict_error(xmlNode *node, const char *name1, const char *name2,
+ error_context_t& ctx)
{
- BEGIN_ATTR_MATCH(node->properties)
- MATCH_TEXT_ATTR("name", addr.name)
- MATCH_UINT32_ATTR("addr", addr.addr)
- END_ATTR_MATCH()
+ std::ostringstream oss;
+ oss << "conflicting <" << name1 << "> and <" << name2 << "> elements";
+ if(node->parent->name)
+ oss << " in <" << XML_CHAR_TO_CHAR(node->parent->name) << ">";
+ else
+ oss << " at root level";
+ return add_fatal(ctx, node, oss.str());
+}
- return true;
+bool parse_not_text_error(xmlNode *node, error_context_t& ctx)
+{
+ return add_fatal(ctx, node, "this is not a text element");
}
-bool parse_reg_formula_elem(xmlNode *node, soc_reg_formula_t& formula)
+bool parse_not_text_attr_error(xmlAttr *attr, error_context_t& ctx)
{
- BEGIN_ATTR_MATCH(node->properties)
- MATCH_TEXT_ATTR("string", formula.string)
- END_ATTR_MATCH()
+ return add_fatal(ctx, attr, "this is not a text attribute");
+}
- formula.type = REG_FORMULA_STRING;
+bool parse_text_elem(xmlNode *node, std::string& name, xmlChar *content, error_context_t& ctx)
+{
+ name = XML_CHAR_TO_CHAR(content);
+ return true;
+}
+bool parse_name_elem(xmlNode *node, std::string& name, xmlChar *content, error_context_t& ctx)
+{
+ name = XML_CHAR_TO_CHAR(content);
+ if(name.size() == 0)
+ return add_fatal(ctx, node, "name cannot be empty");
+ for(size_t i = 0; i < name.size(); i++)
+ if(!isalnum(name[i]) && name[i] != '_')
+ return add_fatal(ctx, node, "name must only contain alphanumeric characters or _");
return true;
}
-bool parse_add_trivial_addr(const std::string& str, soc_reg_t& reg)
+template<typename T, typename U>
+bool parse_unsigned_text(U *node, T& res, xmlChar *content, error_context_t& ctx)
{
- soc_reg_addr_t a;
- a.name = reg.name;
- if(!validate_uint32_hook(str, a.addr))
- return false;
- reg.addr.push_back(a);
+ char *end;
+ unsigned long uns = strtoul(XML_CHAR_TO_CHAR(content), &end, 0);
+ if(*end != 0)
+ return add_fatal(ctx, node, "content must be an unsigned integer");
+ res = uns;
+ if(res != uns)
+ return add_fatal(ctx, node, "value does not fit into allowed range");
return true;
}
-bool parse_reg_elem(xmlNode *node, soc_reg_t& reg)
+template<typename T>
+bool parse_unsigned_elem(xmlNode *node, T& res, xmlChar *content, error_context_t& ctx)
{
- std::list< soc_reg_formula_t > formulas;
- BEGIN_ATTR_MATCH(node->properties)
- MATCH_TEXT_ATTR("name", reg.name)
- SOFT_MATCH_SCT_ATTR("sct", reg.flags)
- SOFT_MATCH_X_ATTR("addr", parse_add_trivial_addr, reg)
- MATCH_TEXT_ATTR("desc", reg.desc)
- END_ATTR_MATCH()
+ return parse_unsigned_text(node, res, content, ctx);
+}
- 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()
+template<typename T>
+bool parse_unsigned_attr(xmlAttr *attr, T& res, xmlChar *content, error_context_t& ctx)
+{
+ return parse_unsigned_text(attr, res, content, ctx);
+}
- if(formulas.size() > 1)
- {
- fprintf(stderr, "Only one formula is allowed per register\n");
+bool parse_text_attr_internal(xmlAttr *attr, xmlChar*& res, error_context_t& ctx)
+{
+ if(attr->children != attr->last)
return false;
- }
- if(formulas.size() == 1)
- reg.formula = formulas.front();
-
+ if(attr->children->type != XML_TEXT_NODE)
+ return parse_not_text_attr_error(attr, ctx);
+ res = attr->children->content;
return true;
}
-bool parse_dev_addr_elem(xmlNode *node, soc_dev_addr_t& addr)
+bool parse_text_attr(xmlAttr *attr, std::string& res, xmlChar *content, error_context_t& ctx)
{
- BEGIN_ATTR_MATCH(node->properties)
- MATCH_TEXT_ATTR("name", addr.name)
- MATCH_UINT32_ATTR("addr", addr.addr)
- END_ATTR_MATCH()
-
+ res = XML_CHAR_TO_CHAR(content);
return true;
}
-bool parse_dev_elem(xmlNode *node, soc_dev_t& dev)
+bool parse_enum_elem(xmlNode *node, enum_t& reg, error_context_t& ctx)
{
- 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)
- MATCH_TEXT_ATTR("version", dev.version)
- END_ATTR_MATCH()
+ bool ret = true;
+ bool has_name = false, has_value = false, has_desc = false;
+ BEGIN_NODE_MATCH(node->children)
+ MATCH_UNIQUE_TEXT_NODE("name", reg.name, has_name, parse_name_elem, ctx)
+ MATCH_UNIQUE_TEXT_NODE("value", reg.value, has_value, parse_unsigned_elem, ctx)
+ MATCH_UNIQUE_TEXT_NODE("desc", reg.desc, has_desc, parse_text_elem, ctx)
+ END_NODE_MATCH()
+ CHECK_HAS(node, "name", has_name, ctx)
+ CHECK_HAS(node, "value", has_value, ctx)
+ return ret;
+}
+bool parse_field_elem(xmlNode *node, field_t& field, error_context_t& ctx)
+{
+ bool ret = true;
+ bool has_name = false, has_pos = false, has_desc = false, has_width = false;
BEGIN_NODE_MATCH(node->children)
- MATCH_ELEM_NODE("addr", dev.addr, parse_dev_addr_elem)
- MATCH_ELEM_NODE("reg", dev.reg, parse_reg_elem)
+ MATCH_UNIQUE_TEXT_NODE("name", field.name, has_name, parse_name_elem, ctx)
+ MATCH_UNIQUE_TEXT_NODE("position", field.pos, has_pos, parse_unsigned_elem, ctx)
+ MATCH_UNIQUE_TEXT_NODE("width", field.width, has_width, parse_unsigned_elem, ctx)
+ MATCH_UNIQUE_TEXT_NODE("desc", field.desc, has_desc, parse_text_elem, ctx)
+ MATCH_ELEM_NODE("enum", field.enum_, parse_enum_elem, ctx)
END_NODE_MATCH()
+ CHECK_HAS(node, "name", has_name, ctx)
+ CHECK_HAS(node, "position", has_pos, ctx)
+ if(!has_width)
+ field.width = 1;
+ return ret;
+}
- return true;
+bool parse_register_elem(xmlNode *node, register_t& reg, error_context_t& ctx)
+{
+ bool ret = true;
+ bool has_width = false;
+ BEGIN_NODE_MATCH(node->children)
+ MATCH_UNIQUE_TEXT_NODE("width", reg.width, has_width, parse_unsigned_elem, ctx)
+ MATCH_ELEM_NODE("field", reg.field, parse_field_elem, ctx)
+ END_NODE_MATCH()
+ if(!has_width)
+ reg.width = 32;
+ return ret;
}
-bool parse_soc_elem(xmlNode *node, soc_t& soc)
+bool parse_formula_elem(xmlNode *node, range_t& range, error_context_t& ctx)
{
+ bool ret = true;
+ bool has_var = false;
BEGIN_ATTR_MATCH(node->properties)
- MATCH_TEXT_ATTR("name", soc.name)
- MATCH_TEXT_ATTR("desc", soc.desc)
- END_ATTR_MATCH()
+ MATCH_UNIQUE_ATTR("variable", range.variable, has_var, parse_text_attr, ctx)
+ END_NODE_MATCH()
+ CHECK_HAS_ATTR(node, "variable", has_var, ctx)
+ return ret;
+}
+bool parse_range_elem(xmlNode *node, range_t& range, error_context_t& ctx)
+{
+ bool ret = true;
+ bool has_first = false, has_count = false, has_stride = false, has_base = false;
+ bool has_formula = false, has_formula_attr = false;
BEGIN_NODE_MATCH(node->children)
- MATCH_ELEM_NODE("dev", soc.dev, parse_dev_elem)
+ MATCH_UNIQUE_TEXT_NODE("first", range.first, has_first, parse_unsigned_elem, ctx)
+ MATCH_UNIQUE_TEXT_NODE("count", range.count, has_count, parse_unsigned_elem, ctx)
+ MATCH_UNIQUE_TEXT_NODE("base", range.base, has_base, parse_unsigned_elem, ctx)
+ MATCH_UNIQUE_TEXT_NODE("stride", range.stride, has_stride, parse_unsigned_elem, ctx)
+ MATCH_UNIQUE_ELEM_NODE("formula", range, has_formula_attr, parse_formula_elem, ctx)
+ MATCH_UNIQUE_TEXT_NODE("formula", range.formula, has_formula, parse_text_elem, ctx)
END_NODE_MATCH()
+ CHECK_HAS(node, "first", has_first, ctx)
+ CHECK_HAS(node, "count", has_count, ctx)
+ if(!has_base && !has_formula)
+ ret = ret && parse_missing_error(node, "base> or <formula", ctx);
+ if(has_base && has_formula)
+ return parse_conflict_error(node, "base", "formula", ctx);
+ if(has_base)
+ CHECK_HAS(node, "stride", has_stride, ctx)
+ if(has_stride && !has_base)
+ ret = ret && parse_conflict_error(node, "stride", "formula", ctx);
+ if(has_stride)
+ range.type = range_t::STRIDE;
+ else
+ range.type = range_t::FORMULA;
+ return ret;
+}
- return true;
+bool parse_instance_elem(xmlNode *node, instance_t& inst, error_context_t& ctx)
+{
+ bool ret = true;
+ bool has_name = false, has_title = false, has_desc = false, has_range = false;
+ bool has_address = false;
+ BEGIN_NODE_MATCH(node->children)
+ MATCH_UNIQUE_TEXT_NODE("name", inst.name, has_name, parse_name_elem, ctx)
+ MATCH_UNIQUE_TEXT_NODE("title", inst.title, has_title, parse_text_elem, ctx)
+ MATCH_UNIQUE_TEXT_NODE("desc", inst.desc, has_desc, parse_text_elem, ctx)
+ MATCH_UNIQUE_TEXT_NODE("address", inst.addr, has_address, parse_unsigned_elem, ctx)
+ MATCH_UNIQUE_ELEM_NODE("range", inst.range, has_range, parse_range_elem, ctx)
+ END_NODE_MATCH()
+ CHECK_HAS(node, "name", has_name, ctx)
+ if(!has_address && !has_range)
+ ret = ret && parse_missing_error(node, "address> or <range", ctx);
+ if(has_address && has_range)
+ ret = ret && parse_conflict_error(node, "address", "range", ctx);
+ if(has_address)
+ inst.type = instance_t::SINGLE;
+ else
+ inst.type = instance_t::RANGE;
+ return ret;
}
-bool parse_root_elem(xmlNode *node, soc_t& soc)
+bool parse_node_elem(xmlNode *node_, node_t& node, error_context_t& ctx)
{
- std::vector< soc_t > socs;
- BEGIN_NODE_MATCH(node)
- MATCH_ELEM_NODE("soc", socs, parse_soc_elem)
+ bool ret = true;
+ register_t reg;
+ bool has_title = false, has_desc = false, has_register = false, has_name = false;
+ BEGIN_NODE_MATCH(node_->children)
+ MATCH_UNIQUE_TEXT_NODE("name", node.name, has_name, parse_name_elem, ctx)
+ MATCH_UNIQUE_TEXT_NODE("title", node.title, has_title, parse_text_elem, ctx)
+ MATCH_UNIQUE_TEXT_NODE("desc", node.desc, has_desc, parse_text_elem, ctx)
+ MATCH_UNIQUE_ELEM_NODE("register", reg, has_register, parse_register_elem, ctx)
+ MATCH_ELEM_NODE("node", node.node, parse_node_elem, ctx)
+ MATCH_ELEM_NODE("instance", node.instance, parse_instance_elem, ctx)
END_NODE_MATCH()
- if(socs.size() != 1)
+ CHECK_HAS(node_, "name", has_name, ctx)
+ CHECK_HAS(node_, "instance", !node.instance.empty(), ctx)
+ if(has_register)
+ node.register_.push_back(reg);
+ return ret;
+}
+
+bool parse_soc_elem(xmlNode *node, soc_t& soc, error_context_t& ctx)
+{
+ bool ret = true;
+ bool has_name = false, has_title = false, has_desc = false, has_version = false;
+ bool has_isa = false;
+ BEGIN_NODE_MATCH(node->children)
+ MATCH_UNIQUE_TEXT_NODE("name", soc.name, has_name, parse_name_elem, ctx)
+ MATCH_UNIQUE_TEXT_NODE("title", soc.title, has_title, parse_text_elem, ctx)
+ MATCH_UNIQUE_TEXT_NODE("desc", soc.desc, has_desc, parse_text_elem, ctx)
+ MATCH_UNIQUE_TEXT_NODE("version", soc.version, has_version, parse_text_elem, ctx)
+ MATCH_UNIQUE_TEXT_NODE("isa", soc.isa, has_isa, parse_text_elem, ctx)
+ MATCH_TEXT_NODE("author", soc.author, parse_text_elem, ctx)
+ MATCH_ELEM_NODE("node", soc.node, parse_node_elem, ctx)
+ END_NODE_MATCH()
+ CHECK_HAS(node, "name", has_name, ctx)
+ return ret;
+}
+
+bool parse_root_elem(xmlNode *node, soc_t& soc, error_context_t& ctx)
+{
+ size_t ver = 0;
+ bool ret = true;
+ bool has_soc = false, has_version = false;
+ BEGIN_ATTR_MATCH(node->properties)
+ MATCH_UNIQUE_ATTR("version", ver, has_version, parse_unsigned_attr, ctx)
+ END_ATTR_MATCH()
+ if(!has_version)
{
- fprintf(stderr, "A description file must contain exactly one soc element\n");
+ ctx.add(error_t(error_t::FATAL, xml_loc(node), "no version attribute, is this a v1 file ?"));
return false;
}
- soc = socs[0];
- return true;
+ if(ver != MAJOR_VERSION)
+ return parse_wrong_version_error(node, ctx);
+ BEGIN_NODE_MATCH(node)
+ MATCH_UNIQUE_ELEM_NODE("soc", soc, has_soc, parse_soc_elem, ctx)
+ END_NODE_MATCH()
+ CHECK_HAS(node, "soc", has_soc, ctx)
+ return ret;
}
}
-bool soc_desc_parse_xml(const std::string& filename, soc_t& socs)
+bool parse_xml(const std::string& filename, soc_t& soc,
+ error_context_t& error_ctx)
{
LIBXML_TEST_VERSION
@@ -290,156 +458,207 @@ bool soc_desc_parse_xml(const std::string& filename, soc_t& socs)
return false;
xmlNodePtr root_element = xmlDocGetRootElement(doc);
- bool ret = parse_root_elem(root_element, socs);
+ bool ret = parse_root_elem(root_element, soc, error_ctx);
xmlFreeDoc(doc);
return ret;
}
+/**
+ * Producer
+ */
+
namespace
{
-int produce_field(xmlTextWriterPtr writer, const soc_reg_field_t& field)
+#define SAFE(x) \
+ do{ \
+ if((x) < 0) { \
+ std::ostringstream oss; \
+ oss << __FILE__ << ":" << __LINE__; \
+ ctx.add(error_t(error_t::FATAL, oss.str(), "write error")); \
+ return -1; \
+ } \
+ }while(0)
+
+int produce_range(xmlTextWriterPtr writer, const range_t& range, error_context_t& ctx)
{
-#define SAFE(x) if((x) < 0) return -1;
- /* <field> */
- SAFE(xmlTextWriterStartElement(writer, BAD_CAST "field"));
- /* name */
- SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST field.name.c_str()));
- /* desc */
- SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST field.desc.c_str()));
- /* bitrange */
- SAFE(xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "bitrange", "%d:%d",
- field.last_bit, field.first_bit));
- /* values */
- for(size_t i = 0; i < field.value.size(); i++)
+ /* <range> */
+ SAFE(xmlTextWriterStartElement(writer, BAD_CAST "range"));
+ /* <first/> */
+ SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "first", "%lu", range.first));
+ /* <count/> */
+ SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "count", "%lu", range.count));
+ /* <base/><stride/> */
+ if(range.type == range_t::STRIDE)
{
- /* <value> */
- SAFE(xmlTextWriterStartElement(writer, BAD_CAST "value"));
- /* name */
- SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST field.value[i].name.c_str()));
- /* value */
- SAFE(xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "value", "0x%x", field.value[i].value));
- /* name */
- SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST field.value[i].desc.c_str()));
- /* </value> */
- SAFE(xmlTextWriterEndElement(writer));
+ SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "base", "0x%x", range.base));
+ SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "stride", "0x%x", range.stride));
}
- /* </field> */
- SAFE(xmlTextWriterEndElement(writer));
-#undef SAFE
- return 0;
-}
-
-int produce_reg(xmlTextWriterPtr writer, const soc_reg_t& reg)
-{
-#define SAFE(x) if((x) < 0) return -1;
- /* <reg> */
- SAFE(xmlTextWriterStartElement(writer, BAD_CAST "reg"));
- /* name */
- SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST reg.name.c_str()));
- /* name */
- SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST reg.desc.c_str()));
- /* flags */
- if(reg.flags & REG_HAS_SCT)
- SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "sct", BAD_CAST "yes"));
- /* formula */
- if(reg.formula.type != REG_FORMULA_NONE)
+ /* <formula> */
+ else if(range.type == range_t::FORMULA)
{
/* <formula> */
SAFE(xmlTextWriterStartElement(writer, BAD_CAST "formula"));
- switch(reg.formula.type)
- {
- case REG_FORMULA_STRING:
- SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "string",
- BAD_CAST reg.formula.string.c_str()));
- break;
- default:
- break;
- }
+ /* variable */
+ SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "variable", BAD_CAST range.variable.c_str()));
+ /* content */
+ SAFE(xmlTextWriterWriteString(writer, BAD_CAST range.formula.c_str()));
/* </formula> */
SAFE(xmlTextWriterEndElement(writer));
}
- /* addresses */
- for(size_t i = 0; i < reg.addr.size(); i++)
- {
- /* <addr> */
- SAFE(xmlTextWriterStartElement(writer, BAD_CAST "addr"));
- /* name */
- SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST reg.addr[i].name.c_str()));
- /* addr */
- SAFE(xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "addr", "0x%x", reg.addr[i].addr));
- /* </addr> */
- SAFE(xmlTextWriterEndElement(writer));
- }
+ /* </range> */
+ SAFE(xmlTextWriterEndElement(writer));
+
+ return 0;
+}
+
+int produce_instance(xmlTextWriterPtr writer, const instance_t& inst, error_context_t& ctx)
+{
+ /* <instance> */
+ SAFE(xmlTextWriterStartElement(writer, BAD_CAST "instance"));
+ /* <name/> */
+ SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "name", BAD_CAST inst.name.c_str()));
+ /* <title/> */
+ if(!inst.title.empty())
+ SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "title", BAD_CAST inst.title.c_str()));
+ /* <desc/> */
+ if(!inst.desc.empty())
+ SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "desc", BAD_CAST inst.desc.c_str()));
+ /* <address/> */
+ if(inst.type == instance_t::SINGLE)
+ SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "address", "0x%x", inst.addr));
+ /* <range/> */
+ else if(inst.type == instance_t::RANGE)
+ SAFE(produce_range(writer, inst.range, ctx));
+ /* </instance> */
+ SAFE(xmlTextWriterEndElement(writer));
+ return 0;
+}
+
+int produce_enum(xmlTextWriterPtr writer, const enum_t& enum_, error_context_t& ctx)
+{
+ /* <enum> */
+ SAFE(xmlTextWriterStartElement(writer, BAD_CAST "enum"));
+ /* <name/> */
+ SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "name", BAD_CAST enum_.name.c_str()));
+ /* <desc/> */
+ if(!enum_.desc.empty())
+ SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "desc", BAD_CAST enum_.desc.c_str()));
+ /* <value/> */
+ SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "value", "0x%x", enum_.value));
+ /* </enum> */
+ SAFE(xmlTextWriterEndElement(writer));
+ return 0;
+}
+
+int produce_field(xmlTextWriterPtr writer, const field_t& field, error_context_t& ctx)
+{
+ /* <field> */
+ SAFE(xmlTextWriterStartElement(writer, BAD_CAST "field"));
+ /* <name/> */
+ SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "name", BAD_CAST field.name.c_str()));
+ /* <desc/> */
+ if(!field.desc.empty())
+ SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "desc", BAD_CAST field.desc.c_str()));
+ /* <position/> */
+ SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "position", "%lu", field.pos));
+ /* <width/> */
+ if(field.width != 1)
+ SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "width", "%lu", field.width));
+ /* enums */
+ for(size_t i = 0; i < field.enum_.size(); i++)
+ SAFE(produce_enum(writer, field.enum_[i], ctx));
+ /* </field> */
+ SAFE(xmlTextWriterEndElement(writer));
+ return 0;
+}
+
+int produce_register(xmlTextWriterPtr writer, const register_t& reg, error_context_t& ctx)
+{
+ /* <register> */
+ SAFE(xmlTextWriterStartElement(writer, BAD_CAST "register"));
+ /* <width/> */
+ if(reg.width != 32)
+ SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "width", "%lu", reg.width));
/* fields */
for(size_t i = 0; i < reg.field.size(); i++)
- produce_field(writer, reg.field[i]);
- /* </reg> */
+ SAFE(produce_field(writer, reg.field[i], ctx));
+ /* </register> */
SAFE(xmlTextWriterEndElement(writer));
-#undef SAFE
return 0;
}
-int produce_dev(xmlTextWriterPtr writer, const soc_dev_t& dev)
+int produce_node(xmlTextWriterPtr writer, const node_t& node, error_context_t& ctx)
{
-#define SAFE(x) if((x) < 0) return -1;
- /* <dev> */
- SAFE(xmlTextWriterStartElement(writer, BAD_CAST "dev"));
- /* name */
- SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST dev.name.c_str()));
- /* long_name */
- SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "long_name", BAD_CAST dev.long_name.c_str()));
- /* desc */
- SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST dev.desc.c_str()));
- /* version */
- SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "version", BAD_CAST dev.version.c_str()));
- /* addresses */
- for(size_t i = 0; i < dev.addr.size(); i++)
- {
- /* <addr> */
- SAFE(xmlTextWriterStartElement(writer, BAD_CAST "addr"));
- /* name */
- SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST dev.addr[i].name.c_str()));
- /* addr */
- SAFE(xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "addr", "0x%x", dev.addr[i].addr));
- /* </addr> */
- SAFE(xmlTextWriterEndElement(writer));
- }
- /* registers */
- for(size_t i = 0; i < dev.reg.size(); i++)
- produce_reg(writer, dev.reg[i]);
- /* </dev> */
+ /* <node> */
+ SAFE(xmlTextWriterStartElement(writer, BAD_CAST "node"));
+ /* <name/> */
+ SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "name", BAD_CAST node.name.c_str()));
+ /* <title/> */
+ if(!node.title.empty())
+ SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "title", BAD_CAST node.title.c_str()));
+ /* <desc/> */
+ if(!node.desc.empty())
+ SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "desc", BAD_CAST node.desc.c_str()));
+ /* instances */
+ for(size_t i = 0; i < node.instance.size(); i++)
+ SAFE(produce_instance(writer, node.instance[i], ctx));
+ /* register */
+ for(size_t i = 0; i < node.register_.size(); i++)
+ SAFE(produce_register(writer, node.register_[i], ctx));
+ /* nodes */
+ for(size_t i = 0; i < node.node.size(); i++)
+ SAFE(produce_node(writer, node.node[i], ctx));
+ /* </node> */
SAFE(xmlTextWriterEndElement(writer));
-#undef SAFE
return 0;
}
+#undef SAFE
+
}
-bool soc_desc_produce_xml(const std::string& filename, const soc_t& soc)
+bool produce_xml(const std::string& filename, const soc_t& soc, error_context_t& ctx)
{
LIBXML_TEST_VERSION
+ std::ostringstream oss;
xmlTextWriterPtr writer = xmlNewTextWriterFilename(filename.c_str(), 0);
if(writer == NULL)
return false;
-#define SAFE(x) if((x) < 0) goto Lerr
+#define SAFE(x) do{if((x) < 0) goto Lerr;}while(0)
SAFE(xmlTextWriterSetIndent(writer, 1));
- SAFE(xmlTextWriterSetIndentString(writer, BAD_CAST " "));
+ SAFE(xmlTextWriterSetIndentString(writer, BAD_CAST " "));
/* <xml> */
SAFE(xmlTextWriterStartDocument(writer, NULL, NULL, NULL));
/* <soc> */
SAFE(xmlTextWriterStartElement(writer, BAD_CAST "soc"));
- /* name */
- SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST soc.name.c_str()));
- /* desc */
- SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST soc.desc.c_str()));
- /* devices */
- for(size_t i = 0; i < soc.dev.size(); i++)
- SAFE(produce_dev(writer, soc.dev[i]));
- /* end <soc> */
+ /* version */
+ oss << MAJOR_VERSION;
+ SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "version", BAD_CAST oss.str().c_str()));
+ /* <name/> */
+ SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "name", BAD_CAST soc.name.c_str()));
+ /* <title/> */
+ if(!soc.title.empty())
+ SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "title", BAD_CAST soc.title.c_str()));
+ /* <desc/> */
+ if(!soc.desc.empty())
+ SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "desc", BAD_CAST soc.desc.c_str()));
+ /* <author/> */
+ for(size_t i = 0; i < soc.author.size(); i++)
+ SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "author", BAD_CAST soc.author[i].c_str()));
+ /* <isa/> */
+ if(!soc.isa.empty())
+ SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "isa", BAD_CAST soc.isa.c_str()));
+ /* <version/> */
+ if(!soc.version.empty())
+ SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "version", BAD_CAST soc.version.c_str()));
+ /* nodes */
+ for(size_t i = 0; i < soc.node.size(); i++)
+ SAFE(produce_node(writer, soc.node[i], ctx));
+ /* </soc> */
SAFE(xmlTextWriterEndElement(writer));
/* </xml> */
SAFE(xmlTextWriterEndDocument(writer));
@@ -451,520 +670,500 @@ Lerr:
return false;
}
-namespace
+/**
+ * soc_ref_t
+ */
+
+soc_ref_t::soc_ref_t():m_soc(0)
{
+}
-struct soc_sorter
+soc_ref_t::soc_ref_t(soc_t *soc):m_soc(soc)
{
- bool operator()(const soc_dev_t& a, const soc_dev_t& b) const
- {
- return a.name < b.name;
- }
+}
- bool operator()(const soc_dev_addr_t& a, const soc_dev_addr_t& b) const
- {
- return a.name < b.name;
- }
+bool soc_ref_t::valid() const
+{
+ return get() != 0;
+}
- bool operator()(const soc_reg_t& a, const soc_reg_t& b) const
- {
- soc_addr_t aa = a.addr.size() > 0 ? a.addr[0].addr : 0;
- soc_addr_t ab = b.addr.size() > 0 ? b.addr[0].addr : 0;
- return aa < ab;
- }
+soc_t *soc_ref_t::get() const
+{
+ return m_soc;
+}
- bool operator()(const soc_reg_addr_t& a, const soc_reg_addr_t& b) const
- {
- return a.addr < b.addr;
- }
+bool soc_ref_t::operator==(const soc_ref_t& ref) const
+{
+ return m_soc == ref.m_soc;
+}
- bool operator()(const soc_reg_field_t& a, const soc_reg_field_t& b) const
- {
- return a.last_bit > b.last_bit;
- }
+node_ref_t soc_ref_t::root() const
+{
+ return node_ref_t(*this);
+}
- bool operator()(const soc_reg_field_value_t a, const soc_reg_field_value_t& b) const
- {
- return a.value < b.value;
- }
-};
+node_inst_t soc_ref_t::root_inst() const
+{
+ return node_inst_t(*this);
+}
-void normalize(soc_reg_field_t& field)
+/**
+ * node_ref_t */
+
+node_ref_t::node_ref_t(soc_ref_t soc):m_soc(soc)
{
- std::sort(field.value.begin(), field.value.end(), soc_sorter());
}
-void normalize(soc_reg_t& reg)
+node_ref_t::node_ref_t(soc_ref_t soc, const std::vector< soc_id_t >& path)
+ :m_soc(soc), m_path(path)
{
- std::sort(reg.addr.begin(), reg.addr.end(), soc_sorter());
- std::sort(reg.field.begin(), reg.field.end(), soc_sorter());
- for(size_t i = 0; i < reg.field.size(); i++)
- normalize(reg.field[i]);
}
-void normalize(soc_dev_t& dev)
+node_ref_t::node_ref_t()
{
- std::sort(dev.addr.begin(), dev.addr.end(), soc_sorter());
- std::sort(dev.reg.begin(), dev.reg.end(), soc_sorter());
- for(size_t i = 0; i < dev.reg.size(); i++)
- normalize(dev.reg[i]);
}
+bool node_ref_t::valid() const
+{
+ return (m_soc.valid() && is_root()) || get() != 0;
}
-void soc_desc_normalize(soc_t& soc)
+bool node_ref_t::is_root() const
{
- std::sort(soc.dev.begin(), soc.dev.end(), soc_sorter());
- for(size_t i = 0; i < soc.dev.size(); i++)
- normalize(soc.dev[i]);
+ return m_path.empty();
}
namespace
{
- soc_error_t make_error(soc_error_level_t lvl, std::string at, std::string what)
- {
- soc_error_t err;
- err.level = lvl;
- err.location = at;
- err.message = what;
- return err;
- }
- soc_error_t make_warning(std::string at, std::string what)
- {
- return make_error(SOC_ERROR_WARNING, at, what);
- }
-
- soc_error_t make_fatal(std::string at, std::string what)
- {
- return make_error(SOC_ERROR_FATAL, at, what);
- }
+std::vector< node_t > *get_children(node_ref_t node)
+{
+ if(node.is_root())
+ return &node.soc().get()->node;
+ node_t *n = node.get();
+ return n == 0 ? 0 : &n->node;
+}
- soc_error_t prefix(soc_error_t err, const std::string& prefix_at)
- {
- err.location = prefix_at + "." + err.location;
- return err;
- }
+node_t *get_child(std::vector< node_t > *nodes, soc_id_t id)
+{
+ if(nodes == 0)
+ return 0;
+ for(size_t i = 0; i < nodes->size(); i++)
+ if((*nodes)[i].id == id)
+ return &(*nodes)[i];
+ return 0;
+}
- void add_errors(std::vector< soc_error_t >& errors,
- const std::vector< soc_error_t >& new_errors, const std::string& prefix_at)
- {
- for(size_t i = 0; i < new_errors.size(); i++)
- errors.push_back(prefix(new_errors[i], prefix_at));
- }
+node_t *get_child(std::vector< node_t > *nodes, const std::string& name)
+{
+ if(nodes == 0)
+ return 0;
+ for(size_t i = 0; i < nodes->size(); i++)
+ if((*nodes)[i].name == name)
+ return &(*nodes)[i];
+ return 0;
+}
- std::vector< soc_error_t > no_error()
- {
- std::vector< soc_error_t > s;
- return s;
- }
+}
- std::vector< soc_error_t > one_error(const soc_error_t& err)
+/* NOTE: valid() is implemented using get() != 0, so don't use it in get() ! */
+node_t *node_ref_t::get() const
+{
+ if(!soc().valid())
+ return 0;
+ /* we could do it recursively but it would make plenty of copies */
+ node_t *n = 0;
+ std::vector< node_t > *nodes = &soc().get()->node;
+ for(size_t i = 0; i < m_path.size(); i++)
{
- std::vector< soc_error_t > s;
- s.push_back(err);
- return s;
+ n = get_child(nodes, m_path[i]);
+ if(n == 0)
+ return 0;
+ nodes = &n->node;
}
+ return n;
+}
- bool name_valid(char c)
- {
- return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
- (c >= 'A' && c <= 'Z') || c == '_';
- }
+soc_ref_t node_ref_t::soc() const
+{
+ return m_soc;
+}
- bool name_valid(const std::string& s)
- {
- for(size_t i = 0; i < s.size(); i++)
- if(!name_valid(s[i]))
- return false;
- return true;
- }
+node_ref_t node_ref_t::parent() const
+{
+ std::vector< soc_id_t > path = m_path;
+ if(!path.empty())
+ path.pop_back();
+ return node_ref_t(m_soc, path);
}
-std::vector< soc_error_t > soc_reg_field_value_t::errors(bool recursive)
+register_ref_t node_ref_t::reg() const
{
- (void) recursive;
- if(name.size() == 0)
- return one_error(make_fatal(name, "empty name"));
- else if(!name_valid(name))
- return one_error(make_fatal(name, "invalid name"));
+ node_t *n = get();
+ if(n == 0)
+ return register_ref_t();
+ if(n->register_.empty())
+ return parent().reg();
else
- return no_error();
+ return register_ref_t(*this);
}
-std::vector< soc_error_t > soc_reg_field_t::errors(bool recursive)
+node_ref_t node_ref_t::child(const std::string& name) const
{
- std::vector< soc_error_t > err;
- std::string at(name);
- if(name.size() == 0)
- err.push_back(make_fatal(at, "empty name"));
- else if(!name_valid(name))
- err.push_back(make_fatal(at, "invalid name"));
- if(last_bit > 31)
- err.push_back(make_fatal(at, "last bit is greater than 31"));
- if(first_bit > last_bit)
- err.push_back(make_fatal(at, "last bit is greater than first bit"));
- for(size_t i = 0; i < value.size(); i++)
+ /* check the node exists */
+ node_t *n = get_child(get_children(*this), name);
+ if(n == 0)
+ return node_ref_t();
+ std::vector< soc_id_t > path = m_path;
+ path.push_back(n->id);
+ return node_ref_t(m_soc, path);
+}
+
+std::vector< node_ref_t > node_ref_t::children() const
+{
+ std::vector< node_ref_t > nodes;
+ std::vector< node_t > *children = get_children(*this);
+ if(children == 0)
+ return nodes;
+ for(size_t i = 0; i < children->size(); i++)
{
- for(size_t j = 0; j < value.size(); j++)
+ std::vector< soc_id_t > path = m_path;
+ path.push_back((*children)[i].id);
+ nodes.push_back(node_ref_t(m_soc, path));
+ }
+ return nodes;
+}
+
+std::vector< std::string > node_ref_t::path() const
+{
+ std::vector< std::string > path;
+ if(!soc().valid())
+ return path;
+ /* we could do it recursively but this is more efficient */
+ node_t *n = 0;
+ std::vector< node_t > *nodes = &soc().get()->node;
+ for(size_t i = 0; i < m_path.size(); i++)
+ {
+ n = get_child(nodes, m_path[i]);
+ if(n == 0)
{
- if(i == j)
- continue;
- if(value[i].name == value[j].name)
- err.push_back(prefix(make_fatal(value[i].name,
- "there are several values with the same name"), at));
- if(value[i].value == value[j].value)
- err.push_back(prefix(make_warning(value[i].name,
- "there are several values with the same value"), at));
+ path.clear();
+ return path;
}
- if(value[i].value > (bitmask() >> first_bit))
- err.push_back(prefix(make_warning(at, "value doesn't fit into the field"), value[i].name));
- if(recursive)
- add_errors(err, value[i].errors(true), at);
+ path.push_back(n->name);
+ nodes = &n->node;
}
- return err;
+ return path;
}
-std::vector< soc_error_t > soc_reg_addr_t::errors(bool recursive)
+std::string node_ref_t::name() const
{
- (void) recursive;
- if(name.size() == 0)
- return one_error(make_fatal("", "empty name"));
- else if(!name_valid(name))
- return one_error(make_fatal(name, "invalid name"));
- else
- return no_error();
+ node_t *n = get();
+ return n == 0 ? "" : n->name;
}
-std::vector< soc_error_t > soc_reg_formula_t::errors(bool recursive)
+bool node_ref_t::operator==(const node_ref_t& ref) const
{
- (void) recursive;
- if(type == REG_FORMULA_STRING && string.size() == 0)
- return one_error(make_fatal("", "empty string formula"));
- else
- return no_error();
+ return m_soc == ref.m_soc && m_path == ref.m_path;
}
-namespace
+/**
+ * register_ref_t
+ */
+
+register_ref_t::register_ref_t(node_ref_t node)
+ :m_node(node)
{
+}
-bool field_overlap(const soc_reg_field_t& a, const soc_reg_field_t& b)
+register_ref_t::register_ref_t()
{
- return !(a.first_bit > b.last_bit || b.first_bit > a.last_bit);
}
+bool register_ref_t::valid() const
+{
+ return get() != 0;
}
-std::vector< soc_error_t > soc_reg_t::errors(bool recursive)
+register_t *register_ref_t::get() const
{
- std::vector< soc_error_t > err;
- std::string at(name);
- if(name.size() == 0)
- err.push_back(make_fatal(at, "empty name"));
- else if(!name_valid(name))
- err.push_back(make_fatal(at, "invalid name"));
- for(size_t i = 0; i < addr.size(); i++)
- {
- for(size_t j = 0; j < addr.size(); j++)
- {
- if(i == j)
- continue;
- if(addr[i].name == addr[j].name)
- err.push_back(prefix(make_fatal(addr[i].name,
- "there are several instances with the same name"), at));
- if(addr[i].addr == addr[j].addr)
- err.push_back(prefix(make_fatal(addr[i].name,
- "there are several instances with the same address"), at));
- }
- if(recursive)
- add_errors(err, addr[i].errors(true), at);
- }
- if(recursive)
- add_errors(err, formula.errors(true), at);
- for(size_t i = 0; i < field.size(); i++)
- {
- for(size_t j = 0; j < field.size(); j++)
- {
- if(i == j)
- continue;
- if(field[i].name == field[j].name)
- err.push_back(prefix(make_fatal(field[i].name,
- "there are several fields with the same name"), at));
- if(field_overlap(field[i], field[j]))
- err.push_back(prefix(make_fatal(field[i].name,
- "there are overlapping fields"), at));
- }
- if(recursive)
- add_errors(err, field[i].errors(true), at);
- }
- return err;
+ node_t *n = m_node.get();
+ if(n == 0 || n->register_.empty())
+ return 0;
+ return &n->register_[0];
}
-std::vector< soc_error_t > soc_dev_addr_t::errors(bool recursive)
+node_ref_t register_ref_t::node() const
{
- (void) recursive;
- if(name.size() == 0)
- return one_error(make_fatal("", "empty name"));
- else if(!name_valid(name))
- return one_error(make_fatal(name, "invalid name"));
- else
- return no_error();
+ return m_node;
}
-std::vector< soc_error_t > soc_dev_t::errors(bool recursive)
+std::vector< field_ref_t > register_ref_t::fields() const
{
- std::vector< soc_error_t > err;
- std::string at(name);
- if(name.size() == 0)
- err.push_back(make_fatal(at, "empty name"));
- else if(!name_valid(name))
- err.push_back(make_fatal(at, "invalid name"));
- for(size_t i = 0; i < addr.size(); i++)
- {
- for(size_t j = 0; j < addr.size(); j++)
- {
- if(i == j)
- continue;
- if(addr[i].name == addr[j].name)
- err.push_back(prefix(make_fatal(addr[i].name,
- "there are several instances with the same name"), at));
- if(addr[i].addr == addr[j].addr)
- err.push_back(prefix(make_fatal(addr[i].name,
- "there are several instances with the same address"), at));
- }
- if(recursive)
- add_errors(err, addr[i].errors(true), at);
- }
- for(size_t i = 0; i < reg.size(); i++)
- {
- for(size_t j = 0; j < reg.size(); j++)
- {
- if(i == j)
- continue;
- if(reg[i].name == reg[j].name)
- err.push_back(prefix(make_fatal(reg[i].name,
- "there are several registers with the same name"), at));
- }
- if(recursive)
- add_errors(err, reg[i].errors(true), at);
- }
- return err;
+ std::vector< field_ref_t > fields;
+ register_t *r = get();
+ if(r == 0)
+ return fields;
+ for(size_t i = 0; i < r->field.size(); i++)
+ fields.push_back(field_ref_t(*this, r->field[i].id));
+ return fields;
}
-std::vector< soc_error_t > soc_t::errors(bool recursive)
+field_ref_t register_ref_t::field(const std::string& name) const
{
- std::vector< soc_error_t > err;
- std::string at(name);
- for(size_t i = 0; i < dev.size(); i++)
- {
- for(size_t j = 0; j < dev.size(); j++)
- {
- if(i == j)
- continue;
- if(dev[i].name == dev[j].name)
- err.push_back(prefix(make_fatal(dev[i].name,
- "there are several devices with the same name"), at));
- }
- if(recursive)
- add_errors(err, dev[i].errors(true), at);
- }
- return err;
+ register_t *r = get();
+ if(r == 0)
+ return field_ref_t();
+ for(size_t i = 0; i < r->field.size(); i++)
+ if(r->field[i].name == name)
+ return field_ref_t(*this, r->field[i].id);
+ return field_ref_t();
}
-namespace
+/**
+ * field_ref_t
+ */
+
+field_ref_t::field_ref_t(register_ref_t reg, soc_id_t id)
+ :m_reg(reg), m_id(id)
{
+}
-struct formula_evaluator
+field_ref_t::field_ref_t()
{
- std::string formula;
- size_t pos;
- std::string error;
+}
- bool err(const char *fmt, ...)
- {
- char buffer[256];
- va_list args;
- va_start(args, fmt);
- vsnprintf(buffer,sizeof(buffer), fmt, args);
- va_end(args);
- error = buffer;
- return false;
- }
+bool field_ref_t::valid() const
+{
+ return get() != 0;
+}
- formula_evaluator(const std::string& s):pos(0)
- {
- for(size_t i = 0; i < s.size(); i++)
- if(!isspace(s[i]))
- formula.push_back(s[i]);
- }
+field_t *field_ref_t::get() const
+{
+ register_t *reg = m_reg.get();
+ if(reg == 0)
+ return 0;
+ for(size_t i = 0; i < reg->field.size(); i++)
+ if(reg->field[i].id == m_id)
+ return &reg->field[i];
+ return 0;
+}
- void adv()
- {
- pos++;
- }
+register_ref_t field_ref_t::reg() const
+{
+ return m_reg;
+}
- char cur()
- {
- return end() ? 0 : formula[pos];
- }
+/**
+ * node_inst_t
+ */
- bool end()
- {
- return pos >= formula.size();
- }
+namespace
+{
+
+const size_t INST_NO_INDEX = std::numeric_limits<std::size_t>::max();
- bool parse_digit(char c, int basis, soc_word_t& res)
+bool get_inst_addr(range_t& range, size_t index, soc_addr_t& addr)
+{
+ if(index < range.first || index >= range.first + range.count)
+ return false;
+ switch(range.type)
{
- c = tolower(c);
- if(isdigit(c))
- {
- res = c - '0';
+ case range_t::STRIDE:
+ addr += range.base + (index - range.first) * range.stride;
return true;
- }
- if(basis == 16 && isxdigit(c))
+ case range_t::FORMULA:
{
- res = c + 10 - 'a';
+ soc_word_t res;
+ std::map< std::string, soc_word_t > vars;
+ vars[range.variable] = index;
+ error_context_t ctx;
+ if(!evaluate_formula(range.formula, vars, res, "", ctx))
+ return false;
+ addr += res;
return true;
}
- return err("invalid digit '%c'", c);
+ default:
+ return false;
}
+}
- bool parse_signed(soc_word_t& res)
+bool get_inst_addr(instance_t *inst, size_t index, soc_addr_t& addr)
+{
+ if(inst == 0)
+ return false;
+ switch(inst->type)
{
- char op = cur();
- if(op == '+' || op == '-')
- {
- adv();
- if(!parse_signed(res))
+ case instance_t::SINGLE:
+ if(index != INST_NO_INDEX)
return false;
- if(op == '-')
- res *= -1;
+ addr += inst->addr;
return true;
- }
- else if(op == '(')
- {
- adv();
- if(!parse_expression(res))
+ case instance_t::RANGE:
+ if(index == INST_NO_INDEX)
return false;
- if(cur() != ')')
- return err("expected ')', got '%c'", cur());
- adv();
- return true;
- }
- else if(isdigit(op))
- {
- res = op - '0';
- adv();
- int basis = 10;
- if(op == '0' && cur() == 'x')
- {
- basis = 16;
- adv();
- }
- soc_word_t digit = 0;
- while(parse_digit(cur(), basis, digit))
- {
- res = res * basis + digit;
- adv();
- }
- return true;
- }
- else if(isalpha(op) || op == '_')
- {
- std::string name;
- while(isalnum(cur()) || cur() == '_')
- {
- name.push_back(cur());
- adv();
- }
- return get_variable(name, res);
- }
- else
- return err("express signed expression, got '%c'", op);
- }
-
- bool parse_term(soc_word_t& res)
- {
- if(!parse_signed(res))
+ return get_inst_addr(inst->range, index, addr);
+ default:
return false;
- while(cur() == '*' || cur() == '/' || cur() == '%')
- {
- char op = cur();
- adv();
- soc_word_t tmp;
- if(!parse_signed(tmp))
- return false;
- if(op == '*')
- res *= tmp;
- else if(tmp != 0)
- res = op == '/' ? res / tmp : res % tmp;
- else
- return err("division by 0");
- }
- return true;
}
+}
- bool parse_expression(soc_word_t& res)
- {
- if(!parse_term(res))
- return false;
- while(!end() && (cur() == '+' || cur() == '-'))
- {
- char op = cur();
- adv();
- soc_word_t tmp;
- if(!parse_term(tmp))
- return false;
- if(op == '+')
- res += tmp;
- else
- res -= tmp;
- }
- return true;
- }
+}
- bool parse(soc_word_t& res, std::string& _error)
- {
- bool ok = parse_expression(res);
- if(ok && !end())
- err("unexpected character '%c'", cur());
- _error = error;
- return ok && end();
- }
+node_inst_t::node_inst_t(soc_ref_t soc)
+ :m_node(soc.root())
+{
+}
- virtual bool get_variable(std::string name, soc_word_t& res)
- {
- return err("unknown variable '%s'", name.c_str());
- }
-};
+node_inst_t::node_inst_t(node_ref_t node, const std::vector< soc_id_t >& ids,
+ const std::vector< size_t >& indexes)
+ :m_node(node), m_id_path(ids), m_index_path(indexes)
+{
+}
-struct my_evaluator : public formula_evaluator
+node_inst_t::node_inst_t()
{
- const std::map< std::string, soc_word_t>& var;
+}
- my_evaluator(const std::string& formula, const std::map< std::string, soc_word_t>& _var)
- :formula_evaluator(formula), var(_var) {}
+bool node_inst_t::valid() const
+{
+ return is_root() || get() != 0;
+}
- virtual bool get_variable(std::string name, soc_word_t& res)
+node_ref_t node_inst_t::node() const
+{
+ return m_node;
+}
+
+soc_ref_t node_inst_t::soc() const
+{
+ return m_node.soc();
+}
+
+bool node_inst_t::is_root() const
+{
+ return m_node.is_root();
+}
+
+node_inst_t node_inst_t::parent() const
+{
+ std::vector< soc_id_t > ids = m_id_path;
+ std::vector< size_t > indexes = m_index_path;
+ if(!ids.empty())
+ ids.pop_back();
+ if(!indexes.empty())
+ indexes.pop_back();
+ return node_inst_t(m_node.parent(), ids, indexes);
+}
+
+instance_t *node_inst_t::get() const
+{
+ node_t *n = m_node.get();
+ if(n == 0)
+ return 0;
+ for(size_t i = 0; i < n->instance.size(); i++)
+ if(n->instance[i].id == m_id_path.back())
+ return &n->instance[i];
+ return 0;
+}
+
+soc_addr_t node_inst_t::addr() const
+{
+ if(is_root())
+ return 0;
+ soc_addr_t addr = parent().addr();
+ if(!get_inst_addr(get(), m_index_path.back(), addr))
+ return 0;
+ return addr;
+}
+
+node_inst_t node_inst_t::child(const std::string& name) const
+{
+ return child(name, INST_NO_INDEX);
+}
+
+
+node_inst_t node_inst_t::child(const std::string& name, size_t index) const
+{
+ std::vector< node_t > *nodes = get_children(m_node);
+ if(nodes == 0)
+ return node_inst_t();
+ node_ref_t child_node = m_node;
+ for(size_t i = 0; i < nodes->size(); i++)
{
- std::map< std::string, soc_word_t>::const_iterator it = var.find(name);
- if(it == var.end())
- return formula_evaluator::get_variable(name, res);
- else
+ node_t& node = (*nodes)[i];
+ child_node.m_path.push_back(node.id);
+ for(size_t j = 0; j < node.instance.size(); j++)
{
- res = it->second;
- return true;
+ if(node.instance[j].name != name)
+ continue;
+ std::vector< soc_id_t > ids = m_id_path;
+ std::vector< size_t > indexes = m_index_path;
+ ids.push_back(node.instance[j].id);
+ ids.push_back(index);
+ return node_inst_t(child_node, ids, indexes);
}
+ child_node.m_path.pop_back();
}
-};
+ return node_inst_t();
+}
+
+std::vector< node_inst_t > node_inst_t::children() const
+{
+ std::vector< node_inst_t > list;
+ std::vector< node_t > *nodes = get_children(m_node);
+ std::vector< soc_id_t > n_path = m_id_path;
+ std::vector< size_t > i_path = m_index_path;
+ if(nodes == 0)
+ return list;
+ node_ref_t child_node = m_node;
+ for(size_t i = 0; i < nodes->size(); i++)
+ {
+ node_t& node = (*nodes)[i];
+ child_node.m_path.push_back(node.id);
+ for(size_t j = 0; j < node.instance.size(); j++)
+ {
+ instance_t& inst = node.instance[j];
+ n_path.push_back(inst.id);
+ switch(inst.type)
+ {
+ case instance_t::SINGLE:
+ i_path.push_back(INST_NO_INDEX);
+ list.push_back(node_inst_t(child_node, n_path, i_path));
+ i_path.pop_back();
+ break;
+ case instance_t::RANGE:
+ for(size_t i = 0; i < inst.range.count; i++)
+ {
+ i_path.push_back(inst.range.first + i);
+ list.push_back(node_inst_t(child_node, n_path, i_path));
+ i_path.pop_back();
+ }
+ break;
+ default:
+ break;
+ }
+ n_path.pop_back();
+ }
+ child_node.m_path.pop_back();
+ }
+ return list;
+}
+
+std::string node_inst_t::name() const
+{
+ instance_t *inst = get();
+ return inst == 0 ? "" : inst->name;
+}
+bool node_inst_t:: is_indexed() const
+{
+ return !m_index_path.empty() && m_index_path.back() != INST_NO_INDEX;
}
-bool soc_desc_evaluate_formula(const std::string& formula,
- const std::map< std::string, soc_word_t>& var, soc_word_t& result, std::string& error)
+size_t node_inst_t::index() const
{
- my_evaluator e(formula, var);
- return e.parse(result, error);
+ return m_index_path.empty() ? INST_NO_INDEX : m_index_path.back();
}
/** WARNING we need to call xmlInitParser() to init libxml2 but it needs to
@@ -982,4 +1181,7 @@ public:
};
xml_parser_init __xml_parser_init;
-} \ No newline at end of file
+}
+
+} // soc_desc_v1
+
diff --git a/utils/regtools/lib/soc_desc.hpp b/utils/regtools/lib/soc_desc.hpp
deleted file mode 100644
index bb8eb4ba8d..0000000000
--- a/utils/regtools/lib/soc_desc.hpp
+++ /dev/null
@@ -1,228 +0,0 @@
-/***************************************************************************
- * __________ __ ___.
- * 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 <list>
-#include <string>
-#include <map>
-
-/**
- * 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.
- */
-
-#define SOCDESC_VERSION_MAJOR 1
-#define SOCDESC_VERSION_MINOR 4
-#define SOCDESC_VERSION_REV 1
-
-#define SOCDESC_VERSION__(maj,min,rev) #maj"."#min"."#rev
-#define SOCDESC_VERSION_(maj,min,rev) SOCDESC_VERSION__(maj,min,rev)
-#define SOCDESC_VERSION SOCDESC_VERSION_(SOCDESC_VERSION_MAJOR,SOCDESC_VERSION_MINOR,SOCDESC_VERSION_REV)
-
-/**
- * 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 error gravity level */
-enum soc_error_level_t
-{
- SOC_ERROR_WARNING,
- SOC_ERROR_FATAL,
-};
-
-/** SoC description error */
-struct soc_error_t
-{
- soc_error_level_t level; /// level (warning, fatal, ...)
- std::string location; /// human description of the location
- std::string message; /// message
-};
-
-/** 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; /// name of the value
- soc_word_t value; /// numeric value
- std::string desc; /// human description
-
- std::vector< soc_error_t > errors(bool recursive);
-};
-
-/** SoC register field */
-struct soc_reg_field_t
-{
- std::string name; /// name of the field
- std::string desc; /// human description
- unsigned first_bit, last_bit; /// bit range of the field
-
- soc_reg_field_t():first_bit(0), last_bit(31) {}
-
- /** Return field bitmask in register */
- 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;
- }
-
- /** Extract field value from register value */
- soc_word_t extract(soc_word_t reg_val) const
- {
- return (reg_val & bitmask()) >> first_bit;
- }
-
- /** Replace the field value in a register value */
- soc_word_t replace(soc_word_t reg_val, soc_word_t field_val) const
- {
- return (reg_val & ~bitmask()) | ((field_val << first_bit) & bitmask());
- }
-
- bool is_reserved() const
- {
- return name.substr(0, 4) == "RSVD" || name.substr(0, 5) == "RSRVD";
- }
-
- /** Return field value index, or -1 if none */
- int find_value(soc_word_t v) const
- {
- for(size_t i = 0; i < value.size(); i++)
- if(value[i].value == v)
- return i;
- return -1;
- }
-
- std::vector< soc_reg_field_value_t > value;
-
- std::vector< soc_error_t > errors(bool recursive);
-};
-
-/** SoC register address */
-struct soc_reg_addr_t
-{
- std::string name; /// actual register name
- soc_addr_t addr; /// actual register address (relative to device)
-
- std::vector< soc_error_t > errors(bool recursive);
-};
-
-/** SoC register formula */
-struct soc_reg_formula_t
-{
- enum soc_reg_formula_type_t type;
- std::string string; /// for STRING
-
- std::vector< soc_error_t > errors(bool recursive);
-};
-
-/** SoC register */
-struct soc_reg_t
-{
- std::string name; /// generic name (for multi registers) or actual name
- std::string desc; /// human description
- std::vector< soc_reg_addr_t > addr; /// instances of the registers
- soc_reg_formula_t formula; /// formula for the instance addresses
- soc_reg_flags_t flags; /// ORed value
-
- std::vector< soc_reg_field_t > field;
-
- std::vector< soc_error_t > errors(bool recursive);
-};
-
-/** Soc device address */
-struct soc_dev_addr_t
-{
- std::string name; /// actual device name
- soc_addr_t addr;
-
- std::vector< soc_error_t > errors(bool recursive);
-};
-
-/** SoC device */
-struct soc_dev_t
-{
- std::string name; /// generic name (of multi devices) or actual name
- std::string long_name; /// human friendly name
- std::string desc; /// human description
- std::string version; /// description version
- std::vector< soc_dev_addr_t > addr;
-
- std::vector< soc_reg_t > reg;
-
- std::vector< soc_error_t > errors(bool recursive);
-};
-
-/** SoC */
-struct soc_t
-{
- std::string name; /// codename (rockbox)
- std::string desc; /// SoC name
-
- std::vector< soc_dev_t > dev;
-
- std::vector< soc_error_t > errors(bool recursive);
-};
-
-/** Parse a SoC description from a XML file, append it to <soc>. */
-bool soc_desc_parse_xml(const std::string& filename, soc_t& soc);
-/** Write a SoC description to a XML file, overwriting it. A file can contain
- * multiple Soc descriptions */
-bool soc_desc_produce_xml(const std::string& filename, const soc_t& soc);
-/** Normalise a soc description by reordering elemnts so that:
- * - devices are sorted by first name
- * - registers are sorted by first address
- * - fields are sorted by last bit
- * - values are sorted by value */
-void soc_desc_normalize(soc_t& soc);
-/** Formula parser: try to parse and evaluate a formula to a specific value of 'n' */
-bool soc_desc_evaluate_formula(const std::string& formula,
- const std::map< std::string, soc_word_t>& var, soc_word_t& result, std::string& error);
-
-#endif /* __SOC_DESC__ */ \ No newline at end of file
diff --git a/utils/regtools/lib/soc_desc_v1.cpp b/utils/regtools/lib/soc_desc_v1.cpp
new file mode 100644
index 0000000000..d585485493
--- /dev/null
+++ b/utils/regtools/lib/soc_desc_v1.cpp
@@ -0,0 +1,990 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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_v1.hpp"
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xmlsave.h>
+#include <libxml/xmlwriter.h>
+#include <stdio.h>
+#include <string.h>
+#include <algorithm>
+#include <cctype>
+
+namespace soc_desc_v1
+{
+
+#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.back())) \
+ 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.back())) \
+ array.pop_back(); \
+ }
+
+#define END_NODE_MATCH() \
+ }
+
+namespace
+{
+
+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 > 0xffffffff
+ if(u > 0xffffffff) 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)
+ MATCH_TEXT_ATTR("desc", value.desc)
+ 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)
+ MATCH_TEXT_ATTR("desc", field.desc)
+ 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_add_trivial_addr(const std::string& str, soc_reg_t& reg)
+{
+ soc_reg_addr_t a;
+ a.name = reg.name;
+ if(!validate_uint32_hook(str, a.addr))
+ return false;
+ reg.addr.push_back(a);
+ return true;
+}
+
+bool parse_reg_elem(xmlNode *node, soc_reg_t& reg)
+{
+ std::list< soc_reg_formula_t > formulas;
+ BEGIN_ATTR_MATCH(node->properties)
+ MATCH_TEXT_ATTR("name", reg.name)
+ SOFT_MATCH_SCT_ATTR("sct", reg.flags)
+ SOFT_MATCH_X_ATTR("addr", parse_add_trivial_addr, reg)
+ MATCH_TEXT_ATTR("desc", reg.desc)
+ 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.front();
+
+ 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("long_name", dev.long_name)
+ MATCH_TEXT_ATTR("desc", dev.desc)
+ 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, soc_t& soc)
+{
+ std::vector< soc_t > socs;
+ BEGIN_NODE_MATCH(node)
+ MATCH_ELEM_NODE("soc", socs, parse_soc_elem)
+ END_NODE_MATCH()
+ if(socs.size() != 1)
+ {
+ fprintf(stderr, "A description file must contain exactly one soc element\n");
+ return false;
+ }
+ soc = socs[0];
+ return true;
+}
+
+}
+
+bool parse_xml(const std::string& filename, soc_t& socs)
+{
+ LIBXML_TEST_VERSION
+
+ xmlDocPtr doc = xmlReadFile(filename.c_str(), NULL, 0);
+ if(doc == NULL)
+ return false;
+
+ xmlNodePtr root_element = xmlDocGetRootElement(doc);
+ bool ret = parse_root_elem(root_element, socs);
+
+ xmlFreeDoc(doc);
+
+ return ret;
+}
+
+namespace
+{
+
+int produce_field(xmlTextWriterPtr writer, const soc_reg_field_t& field)
+{
+#define SAFE(x) if((x) < 0) return -1;
+ /* <field> */
+ SAFE(xmlTextWriterStartElement(writer, BAD_CAST "field"));
+ /* name */
+ SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST field.name.c_str()));
+ /* desc */
+ SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST field.desc.c_str()));
+ /* bitrange */
+ SAFE(xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "bitrange", "%d:%d",
+ field.last_bit, field.first_bit));
+ /* values */
+ for(size_t i = 0; i < field.value.size(); i++)
+ {
+ /* <value> */
+ SAFE(xmlTextWriterStartElement(writer, BAD_CAST "value"));
+ /* name */
+ SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST field.value[i].name.c_str()));
+ /* value */
+ SAFE(xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "value", "0x%x", field.value[i].value));
+ /* name */
+ SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST field.value[i].desc.c_str()));
+ /* </value> */
+ SAFE(xmlTextWriterEndElement(writer));
+ }
+ /* </field> */
+ SAFE(xmlTextWriterEndElement(writer));
+#undef SAFE
+ return 0;
+}
+
+int produce_reg(xmlTextWriterPtr writer, const soc_reg_t& reg)
+{
+#define SAFE(x) if((x) < 0) return -1;
+ /* <reg> */
+ SAFE(xmlTextWriterStartElement(writer, BAD_CAST "reg"));
+ /* name */
+ SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST reg.name.c_str()));
+ /* name */
+ SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST reg.desc.c_str()));
+ /* flags */
+ if(reg.flags & REG_HAS_SCT)
+ SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "sct", BAD_CAST "yes"));
+ /* formula */
+ if(reg.formula.type != REG_FORMULA_NONE)
+ {
+ /* <formula> */
+ SAFE(xmlTextWriterStartElement(writer, BAD_CAST "formula"));
+ switch(reg.formula.type)
+ {
+ case REG_FORMULA_STRING:
+ SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "string",
+ BAD_CAST reg.formula.string.c_str()));
+ break;
+ default:
+ break;
+ }
+ /* </formula> */
+ SAFE(xmlTextWriterEndElement(writer));
+ }
+ /* addresses */
+ for(size_t i = 0; i < reg.addr.size(); i++)
+ {
+ /* <addr> */
+ SAFE(xmlTextWriterStartElement(writer, BAD_CAST "addr"));
+ /* name */
+ SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST reg.addr[i].name.c_str()));
+ /* addr */
+ SAFE(xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "addr", "0x%x", reg.addr[i].addr));
+ /* </addr> */
+ SAFE(xmlTextWriterEndElement(writer));
+ }
+ /* fields */
+ for(size_t i = 0; i < reg.field.size(); i++)
+ produce_field(writer, reg.field[i]);
+ /* </reg> */
+ SAFE(xmlTextWriterEndElement(writer));
+#undef SAFE
+ return 0;
+}
+
+int produce_dev(xmlTextWriterPtr writer, const soc_dev_t& dev)
+{
+#define SAFE(x) if((x) < 0) return -1;
+ /* <dev> */
+ SAFE(xmlTextWriterStartElement(writer, BAD_CAST "dev"));
+ /* name */
+ SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST dev.name.c_str()));
+ /* long_name */
+ SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "long_name", BAD_CAST dev.long_name.c_str()));
+ /* desc */
+ SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST dev.desc.c_str()));
+ /* version */
+ SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "version", BAD_CAST dev.version.c_str()));
+ /* addresses */
+ for(size_t i = 0; i < dev.addr.size(); i++)
+ {
+ /* <addr> */
+ SAFE(xmlTextWriterStartElement(writer, BAD_CAST "addr"));
+ /* name */
+ SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST dev.addr[i].name.c_str()));
+ /* addr */
+ SAFE(xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "addr", "0x%x", dev.addr[i].addr));
+ /* </addr> */
+ SAFE(xmlTextWriterEndElement(writer));
+ }
+ /* registers */
+ for(size_t i = 0; i < dev.reg.size(); i++)
+ produce_reg(writer, dev.reg[i]);
+ /* </dev> */
+ SAFE(xmlTextWriterEndElement(writer));
+#undef SAFE
+ return 0;
+}
+
+}
+
+bool produce_xml(const std::string& filename, const soc_t& soc)
+{
+ LIBXML_TEST_VERSION
+
+ xmlTextWriterPtr writer = xmlNewTextWriterFilename(filename.c_str(), 0);
+ if(writer == NULL)
+ return false;
+#define SAFE(x) if((x) < 0) goto Lerr
+ SAFE(xmlTextWriterSetIndent(writer, 1));
+ SAFE(xmlTextWriterSetIndentString(writer, BAD_CAST " "));
+ /* <xml> */
+ SAFE(xmlTextWriterStartDocument(writer, NULL, NULL, NULL));
+ /* <soc> */
+ SAFE(xmlTextWriterStartElement(writer, BAD_CAST "soc"));
+ /* name */
+ SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST soc.name.c_str()));
+ /* desc */
+ SAFE(xmlTextWriterWriteAttribute(writer, BAD_CAST "desc", BAD_CAST soc.desc.c_str()));
+ /* devices */
+ for(size_t i = 0; i < soc.dev.size(); i++)
+ SAFE(produce_dev(writer, soc.dev[i]));
+ /* end <soc> */
+ SAFE(xmlTextWriterEndElement(writer));
+ /* </xml> */
+ SAFE(xmlTextWriterEndDocument(writer));
+ xmlFreeTextWriter(writer);
+ return true;
+#undef SAFE
+Lerr:
+ xmlFreeTextWriter(writer);
+ return false;
+}
+
+namespace
+{
+
+struct soc_sorter
+{
+ bool operator()(const soc_dev_t& a, const soc_dev_t& b) const
+ {
+ return a.name < b.name;
+ }
+
+ bool operator()(const soc_dev_addr_t& a, const soc_dev_addr_t& b) const
+ {
+ return a.name < b.name;
+ }
+
+ bool operator()(const soc_reg_t& a, const soc_reg_t& b) const
+ {
+ soc_addr_t aa = a.addr.size() > 0 ? a.addr[0].addr : 0;
+ soc_addr_t ab = b.addr.size() > 0 ? b.addr[0].addr : 0;
+ return aa < ab;
+ }
+
+ bool operator()(const soc_reg_addr_t& a, const soc_reg_addr_t& b) const
+ {
+ return a.addr < b.addr;
+ }
+
+ bool operator()(const soc_reg_field_t& a, const soc_reg_field_t& b) const
+ {
+ return a.last_bit > b.last_bit;
+ }
+
+ bool operator()(const soc_reg_field_value_t a, const soc_reg_field_value_t& b) const
+ {
+ return a.value < b.value;
+ }
+};
+
+void normalize(soc_reg_field_t& field)
+{
+ std::sort(field.value.begin(), field.value.end(), soc_sorter());
+}
+
+void normalize(soc_reg_t& reg)
+{
+ std::sort(reg.addr.begin(), reg.addr.end(), soc_sorter());
+ std::sort(reg.field.begin(), reg.field.end(), soc_sorter());
+ for(size_t i = 0; i < reg.field.size(); i++)
+ normalize(reg.field[i]);
+}
+
+void normalize(soc_dev_t& dev)
+{
+ std::sort(dev.addr.begin(), dev.addr.end(), soc_sorter());
+ std::sort(dev.reg.begin(), dev.reg.end(), soc_sorter());
+ for(size_t i = 0; i < dev.reg.size(); i++)
+ normalize(dev.reg[i]);
+}
+
+}
+
+void normalize(soc_t& soc)
+{
+ std::sort(soc.dev.begin(), soc.dev.end(), soc_sorter());
+ for(size_t i = 0; i < soc.dev.size(); i++)
+ normalize(soc.dev[i]);
+}
+
+namespace
+{
+ soc_error_t make_error(soc_error_level_t lvl, std::string at, std::string what)
+ {
+ soc_error_t err;
+ err.level = lvl;
+ err.location = at;
+ err.message = what;
+ return err;
+ }
+
+ soc_error_t make_warning(std::string at, std::string what)
+ {
+ return make_error(SOC_ERROR_WARNING, at, what);
+ }
+
+ soc_error_t make_fatal(std::string at, std::string what)
+ {
+ return make_error(SOC_ERROR_FATAL, at, what);
+ }
+
+ soc_error_t prefix(soc_error_t err, const std::string& prefix_at)
+ {
+ err.location = prefix_at + "." + err.location;
+ return err;
+ }
+
+ void add_errors(std::vector< soc_error_t >& errors,
+ const std::vector< soc_error_t >& new_errors, const std::string& prefix_at)
+ {
+ for(size_t i = 0; i < new_errors.size(); i++)
+ errors.push_back(prefix(new_errors[i], prefix_at));
+ }
+
+ std::vector< soc_error_t > no_error()
+ {
+ std::vector< soc_error_t > s;
+ return s;
+ }
+
+ std::vector< soc_error_t > one_error(const soc_error_t& err)
+ {
+ std::vector< soc_error_t > s;
+ s.push_back(err);
+ return s;
+ }
+
+ bool name_valid(char c)
+ {
+ return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') || c == '_';
+ }
+
+ bool name_valid(const std::string& s)
+ {
+ for(size_t i = 0; i < s.size(); i++)
+ if(!name_valid(s[i]))
+ return false;
+ return true;
+ }
+}
+
+std::vector< soc_error_t > soc_reg_field_value_t::errors(bool recursive)
+{
+ (void) recursive;
+ if(name.size() == 0)
+ return one_error(make_fatal(name, "empty name"));
+ else if(!name_valid(name))
+ return one_error(make_fatal(name, "invalid name"));
+ else
+ return no_error();
+}
+
+std::vector< soc_error_t > soc_reg_field_t::errors(bool recursive)
+{
+ std::vector< soc_error_t > err;
+ std::string at(name);
+ if(name.size() == 0)
+ err.push_back(make_fatal(at, "empty name"));
+ else if(!name_valid(name))
+ err.push_back(make_fatal(at, "invalid name"));
+ if(last_bit > 31)
+ err.push_back(make_fatal(at, "last bit is greater than 31"));
+ if(first_bit > last_bit)
+ err.push_back(make_fatal(at, "last bit is greater than first bit"));
+ for(size_t i = 0; i < value.size(); i++)
+ {
+ for(size_t j = 0; j < value.size(); j++)
+ {
+ if(i == j)
+ continue;
+ if(value[i].name == value[j].name)
+ err.push_back(prefix(make_fatal(value[i].name,
+ "there are several values with the same name"), at));
+ if(value[i].value == value[j].value)
+ err.push_back(prefix(make_warning(value[i].name,
+ "there are several values with the same value"), at));
+ }
+ if(value[i].value > (bitmask() >> first_bit))
+ err.push_back(prefix(make_warning(at, "value doesn't fit into the field"), value[i].name));
+ if(recursive)
+ add_errors(err, value[i].errors(true), at);
+ }
+ return err;
+}
+
+std::vector< soc_error_t > soc_reg_addr_t::errors(bool recursive)
+{
+ (void) recursive;
+ if(name.size() == 0)
+ return one_error(make_fatal("", "empty name"));
+ else if(!name_valid(name))
+ return one_error(make_fatal(name, "invalid name"));
+ else
+ return no_error();
+}
+
+std::vector< soc_error_t > soc_reg_formula_t::errors(bool recursive)
+{
+ (void) recursive;
+ if(type == REG_FORMULA_STRING && string.size() == 0)
+ return one_error(make_fatal("", "empty string formula"));
+ else
+ return no_error();
+}
+
+namespace
+{
+
+bool field_overlap(const soc_reg_field_t& a, const soc_reg_field_t& b)
+{
+ return !(a.first_bit > b.last_bit || b.first_bit > a.last_bit);
+}
+
+}
+
+std::vector< soc_error_t > soc_reg_t::errors(bool recursive)
+{
+ std::vector< soc_error_t > err;
+ std::string at(name);
+ if(name.size() == 0)
+ err.push_back(make_fatal(at, "empty name"));
+ else if(!name_valid(name))
+ err.push_back(make_fatal(at, "invalid name"));
+ for(size_t i = 0; i < addr.size(); i++)
+ {
+ for(size_t j = 0; j < addr.size(); j++)
+ {
+ if(i == j)
+ continue;
+ if(addr[i].name == addr[j].name)
+ err.push_back(prefix(make_fatal(addr[i].name,
+ "there are several instances with the same name"), at));
+ if(addr[i].addr == addr[j].addr)
+ err.push_back(prefix(make_fatal(addr[i].name,
+ "there are several instances with the same address"), at));
+ }
+ if(recursive)
+ add_errors(err, addr[i].errors(true), at);
+ }
+ if(recursive)
+ add_errors(err, formula.errors(true), at);
+ for(size_t i = 0; i < field.size(); i++)
+ {
+ for(size_t j = 0; j < field.size(); j++)
+ {
+ if(i == j)
+ continue;
+ if(field[i].name == field[j].name)
+ err.push_back(prefix(make_fatal(field[i].name,
+ "there are several fields with the same name"), at));
+ if(field_overlap(field[i], field[j]))
+ err.push_back(prefix(make_fatal(field[i].name,
+ "there are overlapping fields"), at));
+ }
+ if(recursive)
+ add_errors(err, field[i].errors(true), at);
+ }
+ return err;
+}
+
+std::vector< soc_error_t > soc_dev_addr_t::errors(bool recursive)
+{
+ (void) recursive;
+ if(name.size() == 0)
+ return one_error(make_fatal("", "empty name"));
+ else if(!name_valid(name))
+ return one_error(make_fatal(name, "invalid name"));
+ else
+ return no_error();
+}
+
+std::vector< soc_error_t > soc_dev_t::errors(bool recursive)
+{
+ std::vector< soc_error_t > err;
+ std::string at(name);
+ if(name.size() == 0)
+ err.push_back(make_fatal(at, "empty name"));
+ else if(!name_valid(name))
+ err.push_back(make_fatal(at, "invalid name"));
+ for(size_t i = 0; i < addr.size(); i++)
+ {
+ for(size_t j = 0; j < addr.size(); j++)
+ {
+ if(i == j)
+ continue;
+ if(addr[i].name == addr[j].name)
+ err.push_back(prefix(make_fatal(addr[i].name,
+ "there are several instances with the same name"), at));
+ if(addr[i].addr == addr[j].addr)
+ err.push_back(prefix(make_fatal(addr[i].name,
+ "there are several instances with the same address"), at));
+ }
+ if(recursive)
+ add_errors(err, addr[i].errors(true), at);
+ }
+ for(size_t i = 0; i < reg.size(); i++)
+ {
+ for(size_t j = 0; j < reg.size(); j++)
+ {
+ if(i == j)
+ continue;
+ if(reg[i].name == reg[j].name)
+ err.push_back(prefix(make_fatal(reg[i].name,
+ "there are several registers with the same name"), at));
+ }
+ if(recursive)
+ add_errors(err, reg[i].errors(true), at);
+ }
+ return err;
+}
+
+std::vector< soc_error_t > soc_t::errors(bool recursive)
+{
+ std::vector< soc_error_t > err;
+ std::string at(name);
+ for(size_t i = 0; i < dev.size(); i++)
+ {
+ for(size_t j = 0; j < dev.size(); j++)
+ {
+ if(i == j)
+ continue;
+ if(dev[i].name == dev[j].name)
+ err.push_back(prefix(make_fatal(dev[i].name,
+ "there are several devices with the same name"), at));
+ }
+ if(recursive)
+ add_errors(err, dev[i].errors(true), at);
+ }
+ return err;
+}
+
+namespace
+{
+
+struct formula_evaluator
+{
+ std::string formula;
+ size_t pos;
+ std::string error;
+
+ bool err(const char *fmt, ...)
+ {
+ char buffer[256];
+ va_list args;
+ va_start(args, fmt);
+ vsnprintf(buffer,sizeof(buffer), fmt, args);
+ va_end(args);
+ error = buffer;
+ return false;
+ }
+
+ formula_evaluator(const std::string& s):pos(0)
+ {
+ for(size_t i = 0; i < s.size(); i++)
+ if(!isspace(s[i]))
+ formula.push_back(s[i]);
+ }
+
+ void adv()
+ {
+ pos++;
+ }
+
+ char cur()
+ {
+ return end() ? 0 : formula[pos];
+ }
+
+ bool end()
+ {
+ return pos >= formula.size();
+ }
+
+ bool parse_digit(char c, int basis, soc_word_t& res)
+ {
+ c = tolower(c);
+ if(isdigit(c))
+ {
+ res = c - '0';
+ return true;
+ }
+ if(basis == 16 && isxdigit(c))
+ {
+ res = c + 10 - 'a';
+ return true;
+ }
+ return err("invalid digit '%c'", c);
+ }
+
+ bool parse_signed(soc_word_t& res)
+ {
+ char op = cur();
+ if(op == '+' || op == '-')
+ {
+ adv();
+ if(!parse_signed(res))
+ return false;
+ if(op == '-')
+ res *= -1;
+ return true;
+ }
+ else if(op == '(')
+ {
+ adv();
+ if(!parse_expression(res))
+ return false;
+ if(cur() != ')')
+ return err("expected ')', got '%c'", cur());
+ adv();
+ return true;
+ }
+ else if(isdigit(op))
+ {
+ res = op - '0';
+ adv();
+ int basis = 10;
+ if(op == '0' && cur() == 'x')
+ {
+ basis = 16;
+ adv();
+ }
+ soc_word_t digit = 0;
+ while(parse_digit(cur(), basis, digit))
+ {
+ res = res * basis + digit;
+ adv();
+ }
+ return true;
+ }
+ else if(isalpha(op) || op == '_')
+ {
+ std::string name;
+ while(isalnum(cur()) || cur() == '_')
+ {
+ name.push_back(cur());
+ adv();
+ }
+ return get_variable(name, res);
+ }
+ else
+ return err("express signed expression, got '%c'", op);
+ }
+
+ bool parse_term(soc_word_t& res)
+ {
+ if(!parse_signed(res))
+ return false;
+ while(cur() == '*' || cur() == '/' || cur() == '%')
+ {
+ char op = cur();
+ adv();
+ soc_word_t tmp;
+ if(!parse_signed(tmp))
+ return false;
+ if(op == '*')
+ res *= tmp;
+ else if(tmp != 0)
+ res = op == '/' ? res / tmp : res % tmp;
+ else
+ return err("division by 0");
+ }
+ return true;
+ }
+
+ bool parse_expression(soc_word_t& res)
+ {
+ if(!parse_term(res))
+ return false;
+ while(!end() && (cur() == '+' || cur() == '-'))
+ {
+ char op = cur();
+ adv();
+ soc_word_t tmp;
+ if(!parse_term(tmp))
+ return false;
+ if(op == '+')
+ res += tmp;
+ else
+ res -= tmp;
+ }
+ return true;
+ }
+
+ bool parse(soc_word_t& res, std::string& _error)
+ {
+ bool ok = parse_expression(res);
+ if(ok && !end())
+ err("unexpected character '%c'", cur());
+ _error = error;
+ return ok && end();
+ }
+
+ virtual bool get_variable(std::string name, soc_word_t& res)
+ {
+ return err("unknown variable '%s'", name.c_str());
+ }
+};
+
+struct my_evaluator : public formula_evaluator
+{
+ const std::map< std::string, soc_word_t>& var;
+
+ my_evaluator(const std::string& formula, const std::map< std::string, soc_word_t>& _var)
+ :formula_evaluator(formula), var(_var) {}
+
+ virtual bool get_variable(std::string name, soc_word_t& res)
+ {
+ std::map< std::string, soc_word_t>::const_iterator it = var.find(name);
+ if(it == var.end())
+ return formula_evaluator::get_variable(name, res);
+ else
+ {
+ res = it->second;
+ return true;
+ }
+ }
+};
+
+}
+
+bool evaluate_formula(const std::string& formula,
+ const std::map< std::string, soc_word_t>& var, soc_word_t& result, std::string& error)
+{
+ my_evaluator e(formula, var);
+ return e.parse(result, error);
+}
+
+/** WARNING we need to call xmlInitParser() to init libxml2 but it needs to
+ * called from the main thread, which is a super strong requirement, so do it
+ * using a static constructor */
+namespace
+{
+class xml_parser_init
+{
+public:
+ xml_parser_init()
+ {
+ xmlInitParser();
+ }
+};
+
+xml_parser_init __xml_parser_init;
+}
+
+} // soc_desc_v1