diff options
| author | Amaury Pouly <amaury.pouly@gmail.com> | 2014-12-14 11:53:55 +0100 |
|---|---|---|
| committer | Amaury Pouly <amaury.pouly@gmail.com> | 2015-09-11 16:40:19 +0200 |
| commit | 1cada1f8339d6b5f8506277f80e62aaef77ab774 (patch) | |
| tree | 8477120e97832d659d2ffc471a8bfde73ad4c36e /utils/regtools/lib/soc_desc.cpp | |
| parent | c8d3638b9ebc24e4766714da1c9f961e350799c6 (diff) | |
| download | rockbox-1cada1f8339d6b5f8506277f80e62aaef77ab774.zip rockbox-1cada1f8339d6b5f8506277f80e62aaef77ab774.tar.gz rockbox-1cada1f8339d6b5f8506277f80e62aaef77ab774.tar.bz2 rockbox-1cada1f8339d6b5f8506277f80e62aaef77ab774.tar.xz | |
soc_desc: new version of the desc file format
Fix qeditor to use the old soc_desc_v1.
Port hwstub_shell to the new description format.
Change-Id: I9fefbff534bfaa5c3603bb3dd8307a2b76e88cfc
Diffstat (limited to 'utils/regtools/lib/soc_desc.cpp')
| -rw-r--r-- | utils/regtools/lib/soc_desc.cpp | 1530 |
1 files changed, 866 insertions, 664 deletions
diff --git a/utils/regtools/lib/soc_desc.cpp b/utils/regtools/lib/soc_desc.cpp index 90e4e0e..4e0e46f 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 ®->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 + |