rockbox/utils/regtools/lib/soc_desc.cpp
Aidan MacDonald 387f67cab6 headergen_v2: add floating instances and nochild flag
Floating instances don't have an address and will only generate
child nodes and registers with offsets. The 'nochild' flag will
disable generating the children for a node but will generate the
node's own address, which can be used to generate base addresses.

Change-Id: Ib1014de94531436d5708db46aa684741e7740ace
2025-04-20 15:53:54 -04:00

1741 lines
49 KiB
C++

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* 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
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include "soc_desc.hpp"
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xmlsave.h>
#include <libxml/xmlwriter.h>
#include <stdio.h>
#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) { \
bool used = false;
#define MATCH_UNIQUE_ATTR(attr_name, val, has, parse_fn, ctx) \
if(strcmp(XML_CHAR_TO_CHAR(a->name), attr_name) == 0) { \
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; \
used = true; \
}
#define MATCH_UNUSED_ATTR(parse_fn, ctx) \
if(!used) { \
ret = ret && parse_fn(a, ctx); \
}
#define END_ATTR_MATCH() \
}
#define BEGIN_NODE_MATCH(node) \
for(xmlNode *sub = node; sub; sub = sub->next) { \
bool used = false; \
#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(), ctx)) \
ret = false; \
array.back().id = array.size(); \
used = true; \
}
#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); \
ret = ret && parse_fn(sub, array.back(), content, ctx); \
xmlFree(content); \
used = true; \
}
#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; \
used = true; \
}
#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); \
used = true; \
}
#define MATCH_UNUSED_NODE(parse_fn, ctx) \
if(!used) { \
ret = ret && parse_fn(sub, ctx); \
}
#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 is_real_text_node(xmlNode *node)
{
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;
}
std::string xml_loc(xmlNode *node)
{
std::ostringstream oss;
oss << "line " << node->line;
return oss.str();
}
std::string xml_loc(xmlAttr *attr)
{
return xml_loc(attr->parent);
}
template<typename T>
bool add_error(error_context_t& ctx, err_t::level_t lvl, T *node,
const std::string& msg)
{
ctx.add(err_t(lvl, xml_loc(node), msg));
return false;
}
template<typename T>
bool add_fatal(error_context_t& ctx, T *node, const std::string& msg)
{
return add_error(ctx, err_t::FATAL, node, msg);
}
template<typename T>
bool add_warning(error_context_t& ctx, T *node, const std::string& msg)
{
return add_error(ctx, err_t::WARNING, node, msg);
}
bool parse_wrong_version_error(xmlNode *node, error_context_t& ctx)
{
std::ostringstream oss;
oss << "unknown version, only version " << MAJOR_VERSION << " is supported";
return add_fatal(ctx, node, oss.str());
}
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_not_unique_attr_error(xmlAttr *attr, error_context_t& ctx)
{
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());
}
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());
}
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_conflict_error(xmlNode *node, const char *name1, const char *name2,
error_context_t& ctx)
{
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());
}
bool parse_not_text_error(xmlNode *node, error_context_t& ctx)
{
return add_fatal(ctx, node, "this is not a text element");
}
bool parse_not_text_attr_error(xmlAttr *attr, error_context_t& ctx)
{
return add_fatal(ctx, attr, "this is not a text attribute");
}
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_unknown_elem(xmlNode *node, error_context_t& ctx)
{
/* ignore blank nodes */
if(xmlIsBlankNode(node))
return true;
std::ostringstream oss;
oss << "unknown <" << XML_CHAR_TO_CHAR(node->name) << "> element";
return add_fatal(ctx, node, oss.str());
}
bool parse_access_elem(xmlNode *node, access_t& acc, xmlChar *content, error_context_t& ctx)
{
const char *text = XML_CHAR_TO_CHAR(content);
if(strcmp(text, "read-only") == 0)
acc = READ_ONLY;
else if(strcmp(text, "read-write") == 0)
acc = READ_WRITE;
else if(strcmp(text, "write-only") == 0)
acc = WRITE_ONLY;
else
return add_fatal(ctx, node, "unknown access type " + std::string(text));
return true;
}
template<typename T, typename U>
bool parse_unsigned_text(U *node, T& res, xmlChar *content, error_context_t& ctx)
{
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;
}
template<typename T>
bool parse_unsigned_elem(xmlNode *node, T& res, xmlChar *content, error_context_t& ctx)
{
return parse_unsigned_text(node, res, content, ctx);
}
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);
}
bool parse_text_attr_internal(xmlAttr *attr, xmlChar*& res, error_context_t& ctx)
{
if(attr->children != attr->last)
return false;
if(attr->children->type != XML_TEXT_NODE)
return parse_not_text_attr_error(attr, ctx);
res = attr->children->content;
return true;
}
bool parse_text_attr(xmlAttr *attr, std::string& res, xmlChar *content, error_context_t& ctx)
{
res = XML_CHAR_TO_CHAR(content);
return true;
}
bool parse_unknown_attr(xmlAttr *attr, error_context_t& ctx)
{
std::ostringstream oss;
oss << "unknown '" << XML_CHAR_TO_CHAR(attr->name) << "' attribute";
return add_fatal(ctx, attr, oss.str());
}
bool parse_enum_elem(xmlNode *node, enum_t& reg, error_context_t& ctx)
{
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)
MATCH_UNUSED_NODE(parse_unknown_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_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)
MATCH_UNUSED_NODE(parse_unknown_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;
}
bool parse_variant_elem(xmlNode *node, variant_t& variant, error_context_t& ctx)
{
bool ret = true;
bool has_type = false, has_offset = false, has_access = false;
BEGIN_NODE_MATCH(node->children)
MATCH_UNIQUE_TEXT_NODE("type", variant.type, has_type, parse_name_elem, ctx)
MATCH_UNIQUE_TEXT_NODE("offset", variant.offset, has_offset, parse_unsigned_elem, ctx)
MATCH_UNIQUE_TEXT_NODE("access", variant.access, has_access, parse_access_elem, ctx)
MATCH_UNUSED_NODE(parse_unknown_elem, ctx)
END_NODE_MATCH()
CHECK_HAS(node, "type", has_type, ctx)
CHECK_HAS(node, "offset", has_offset, ctx)
if(!has_access)
variant.access = UNSPECIFIED;
return ret;
}
bool parse_register_elem(xmlNode *node, register_t& reg, error_context_t& ctx)
{
bool ret = true;
bool has_width = false, has_desc = false, has_access = false;
BEGIN_NODE_MATCH(node->children)
MATCH_UNIQUE_TEXT_NODE("desc", reg.desc, has_desc, parse_text_elem, ctx)
MATCH_UNIQUE_TEXT_NODE("width", reg.width, has_width, parse_unsigned_elem, ctx)
MATCH_UNIQUE_TEXT_NODE("access", reg.access, has_access, parse_access_elem, ctx)
MATCH_ELEM_NODE("field", reg.field, parse_field_elem, ctx)
MATCH_ELEM_NODE("variant", reg.variant, parse_variant_elem, ctx)
MATCH_UNUSED_NODE(parse_unknown_elem, ctx)
END_NODE_MATCH()
if(!has_width)
reg.width = 32;
if(!has_access)
reg.access = UNSPECIFIED;
return ret;
}
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_UNIQUE_ATTR("variable", range.variable, has_var, parse_text_attr, ctx)
MATCH_UNUSED_ATTR(parse_unknown_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_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)
MATCH_TEXT_NODE("address", range.list, parse_unsigned_elem, ctx)
MATCH_UNUSED_NODE(parse_unknown_elem, ctx)
END_NODE_MATCH()
CHECK_HAS(node, "first", has_first, ctx)
if(range.list.size() == 0)
{
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;
}
else
{
if(has_base)
ret = ret && parse_conflict_error(node, "base", "addr", ctx);
if(has_count)
ret = ret && parse_conflict_error(node, "count", "addr", ctx);
if(has_formula)
ret = ret && parse_conflict_error(node, "formula", "addr", ctx);
if(has_stride)
ret = ret && parse_conflict_error(node, "stride", "addr", ctx);
range.type = range_t::LIST;
}
return ret;
}
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, has_floating = false, has_nochild = false;
unsigned floating = 0, nochild = 0;
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("nochild", nochild, has_nochild, parse_unsigned_elem, ctx)
MATCH_UNIQUE_TEXT_NODE("floating", floating, has_floating, parse_unsigned_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)
MATCH_UNUSED_NODE(parse_unknown_elem, ctx)
END_NODE_MATCH()
CHECK_HAS(node, "name", has_name, ctx)
if(!has_address && !has_range && !floating)
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(floating && has_address)
ret = ret && parse_conflict_error(node, "floating", "address", ctx);
if(floating && has_range)
ret = ret && parse_conflict_error(node, "floating", "range", ctx);
if(floating && nochild)
ret = ret && parse_conflict_error(node, "floating", "nochild", ctx);
if(floating)
inst.type = instance_t::FLOATING;
else if(has_address)
inst.type = instance_t::SINGLE;
else
inst.type = instance_t::RANGE;
if (nochild)
inst.nochild = true;
return ret;
}
bool parse_node_elem(xmlNode *node_, node_t& node, error_context_t& ctx)
{
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)
MATCH_UNUSED_NODE(parse_unknown_elem, ctx)
END_NODE_MATCH()
CHECK_HAS(node_, "name", has_name, 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)
MATCH_UNUSED_NODE(parse_unknown_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)
MATCH_UNUSED_ATTR(parse_unknown_attr, ctx)
END_ATTR_MATCH()
if(!has_version)
{
ctx.add(err_t(err_t::FATAL, xml_loc(node), "no version attribute, is this a v1 file ?"));
return false;
}
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)
MATCH_UNUSED_NODE(parse_unknown_elem, ctx)
END_NODE_MATCH()
CHECK_HAS(node, "soc", has_soc, ctx)
return ret;
}
}
bool parse_xml(const std::string& filename, soc_t& soc,
error_context_t& error_ctx)
{
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, soc, error_ctx);
xmlFreeDoc(doc);
return ret;
}
/**
* Normalizer
*/
namespace
{
struct soc_sorter
{
/* returns the lowest address of an instance, or 0 if none
* and 0xffffffff if cannot evaluate */
soc_addr_t first_addr(const instance_t& inst) const
{
if(inst.type == instance_t::SINGLE)
return inst.addr;
/* sanity check */
if(inst.type != instance_t::RANGE)
{
printf("Warning: unknown instance type %d\n", inst.type);
return 0;
}
if(inst.range.type == range_t::STRIDE)
return inst.range.base; /* assume positive stride */
if(inst.range.type == range_t::LIST)
{
soc_addr_t min = 0xffffffff;
for(size_t i = 0; i < inst.range.list.size(); i++)
if(inst.range.list[i] < min)
min = inst.range.list[i];
return min;
}
/* sanity check */
if(inst.range.type != range_t::FORMULA)
{
printf("Warning: unknown range type %d\n", inst.range.type);
return 0;
}
soc_addr_t min = 0xffffffff;
std::map< std::string, soc_word_t > vars;
for(size_t i = 0; i < inst.range.count; i++)
{
soc_word_t res;
vars[inst.range.variable] = inst.range.first;
error_context_t ctx;
if(evaluate_formula(inst.range.formula, vars, res, "", ctx) && res < min)
min = res;
}
return min;
}
/* return smallest address among all instances */
soc_addr_t first_addr(const node_t& node) const
{
soc_addr_t min = 0xffffffff;
for(size_t i = 0; i < node.instance.size(); i++)
min = std::min(min, first_addr(node.instance[i]));
return min;
}
/* sort instances by first address */
bool operator()(const instance_t& a, const instance_t& b) const
{
return first_addr(a) < first_addr(b);
}
/* sort nodes by first address of first instance (which is the lowest of
* any instance if instances are sorted) */
bool operator()(const node_t& a, const node_t& b) const
{
soc_addr_t addr_a = first_addr(a);
soc_addr_t addr_b = first_addr(b);
/* It may happen that two nodes have the same first instance address,
* for example if one logically splits a block into two blocks with
* the same base. In this case, sort by name */
if(addr_a == addr_b)
return a.name < b.name;
return addr_a < addr_b;
}
/* sort fields by decreasing position */
bool operator()(const field_t& a, const field_t& b) const
{
/* in the unlikely case where two fields have the same position, use name */
if(a.pos == b.pos)
return a.name < b.name;
return a.pos > b.pos;
}
/* sort enum values by value, then by name */
bool operator()(const enum_t& a, const enum_t& b) const
{
if(a.value == b.value)
return a.name < b.name;
return a.value < b.value;
}
};
void normalize(field_t& field)
{
std::sort(field.enum_.begin(), field.enum_.end(), soc_sorter());
}
void normalize(register_t& reg)
{
for(size_t i = 0; i < reg.field.size(); i++)
normalize(reg.field[i]);
std::sort(reg.field.begin(), reg.field.end(), soc_sorter());
}
void normalize(node_t& node)
{
for(size_t i = 0; i < node.register_.size(); i++)
normalize(node.register_[i]);
for(size_t i = 0; i < node.node.size(); i++)
normalize(node.node[i]);
std::sort(node.node.begin(), node.node.end(), soc_sorter());
std::sort(node.instance.begin(), node.instance.end(), soc_sorter());
}
} /* namespace */
void normalize(soc_t& soc)
{
for(size_t i = 0; i < soc.node.size(); i++)
normalize(soc.node[i]);
std::sort(soc.node.begin(), soc.node.end(), soc_sorter());
}
/**
* Producer
*/
namespace
{
#define SAFE(x) \
do{ \
if((x) < 0) { \
std::ostringstream oss; \
oss << __FILE__ << ":" << __LINE__; \
ctx.add(err_t(err_t::FATAL, oss.str(), "write error")); \
return -1; \
} \
}while(0)
int produce_range(xmlTextWriterPtr writer, const range_t& range, error_context_t& ctx)
{
/* <range> */
SAFE(xmlTextWriterStartElement(writer, BAD_CAST "range"));
/* <first/> */
SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "first", "%lu", range.first));
if(range.type == range_t::STRIDE)
{
/* <count/> */
SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "count", "%lu", range.count));
/* <base/> */
SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "base", "0x%x", range.base));
/* <stride/> */
SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "stride", "0x%x", range.stride));
}
/* <formula> */
else if(range.type == range_t::FORMULA)
{
/* <count/> */
SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "count", "%lu", range.count));
/* <formula> */
SAFE(xmlTextWriterStartElement(writer, BAD_CAST "formula"));
/* 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));
}
else if(range.type == range_t::LIST)
{
for(size_t i = 0; i < range.list.size(); i++)
SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "address", "0x%x", range.list[i]));
}
/* </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;
}
const char *access_string(access_t acc)
{
switch(acc)
{
case READ_ONLY: return "read-only";
case READ_WRITE: return "read-write";
case WRITE_ONLY: return "write-only";
default: return "bug-invalid-access";
}
}
int produce_variant(xmlTextWriterPtr writer, const variant_t& variant, error_context_t& ctx)
{
/* <variant> */
SAFE(xmlTextWriterStartElement(writer, BAD_CAST "variant"));
/* <name/> */
SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "type", BAD_CAST variant.type.c_str()));
/* <position/> */
SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "offset", "%lu", (unsigned long)variant.offset));
/* <access/> */
if(variant.access != UNSPECIFIED)
SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "access", BAD_CAST access_string(variant.access)));
/* </variant> */
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));
/* <desc/> */
if(!reg.desc.empty())
SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "desc", BAD_CAST reg.desc.c_str()));
/* <access/> */
if(reg.access != UNSPECIFIED)
SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "access", BAD_CAST access_string(reg.access)));
/* fields */
for(size_t i = 0; i < reg.field.size(); i++)
SAFE(produce_field(writer, reg.field[i], ctx));
/* variants */
for(size_t i = 0; i < reg.variant.size(); i++)
SAFE(produce_variant(writer, reg.variant[i], ctx));
/* </register> */
SAFE(xmlTextWriterEndElement(writer));
return 0;
}
int produce_node(xmlTextWriterPtr writer, const node_t& node, error_context_t& ctx)
{
/* <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));
return 0;
}
#undef SAFE
}
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) do{if((x) < 0) goto Lerr;}while(0)
SAFE(xmlTextWriterSetIndent(writer, 1));
SAFE(xmlTextWriterSetIndentString(writer, BAD_CAST " "));
/* <xml> */
SAFE(xmlTextWriterStartDocument(writer, NULL, NULL, NULL));
/* <soc> */
SAFE(xmlTextWriterStartElement(writer, BAD_CAST "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));
xmlFreeTextWriter(writer);
return true;
#undef SAFE
Lerr:
xmlFreeTextWriter(writer);
return false;
}
/**
* utils
*/
namespace
{
template< typename T >
soc_id_t gen_fresh_id(const std::vector< T >& list)
{
soc_id_t id = 0;
for(size_t i = 0; i < list.size(); i++)
id = std::max(id, list[i].id);
return id + 1;
}
}
/**
* soc_ref_t
*/
soc_ref_t::soc_ref_t():m_soc(0)
{
}
soc_ref_t::soc_ref_t(soc_t *soc):m_soc(soc)
{
}
bool soc_ref_t::valid() const
{
return get() != 0;
}
soc_t *soc_ref_t::get() const
{
return m_soc;
}
bool soc_ref_t::operator==(const soc_ref_t& ref) const
{
return m_soc == ref.m_soc;
}
node_ref_t soc_ref_t::root() const
{
return node_ref_t(*this);
}
node_inst_t soc_ref_t::root_inst() const
{
return node_inst_t(*this);
}
void soc_ref_t::reset()
{
m_soc = 0;
}
/**
* node_ref_t */
node_ref_t::node_ref_t(soc_ref_t soc):m_soc(soc)
{
}
node_ref_t::node_ref_t(soc_ref_t soc, const std::vector< soc_id_t >& path)
:m_soc(soc), m_path(path)
{
}
node_ref_t::node_ref_t()
{
}
bool node_ref_t::valid() const
{
return (m_soc.valid() && is_root()) || get() != 0;
}
bool node_ref_t::is_root() const
{
return m_path.empty();
}
void node_ref_t::reset()
{
m_soc.reset();
}
namespace
{
std::vector< node_t > *get_children(node_ref_t node)
{
if(node.is_root())
return node.soc().valid() ? &node.soc().get()->node : 0;
node_t *n = node.get();
return n == 0 ? 0 : &n->node;
}
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;
}
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;
}
}
/* 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++)
{
n = get_child(nodes, m_path[i]);
if(n == 0)
return 0;
nodes = &n->node;
}
return n;
}
soc_ref_t node_ref_t::soc() const
{
return m_soc;
}
node_ref_t node_ref_t::parent(unsigned level) const
{
if(level > depth())
return node_ref_t();
std::vector< soc_id_t > path = m_path;
path.resize(depth() - level);
return node_ref_t(m_soc, path);
}
unsigned node_ref_t::depth() const
{
return m_path.size();
}
register_ref_t node_ref_t::reg() const
{
node_t *n = get();
if(n == 0)
return register_ref_t();
if(n->register_.empty())
return parent().reg();
else
return register_ref_t(*this);
}
register_ref_t node_ref_t::create_reg(size_t width) const
{
node_t *n = get();
if(n == 0)
return register_ref_t();
if(!n->register_.empty())
return register_ref_t();
n->register_.resize(1);
n->register_[0].width = width;
return register_ref_t(*this);
}
node_ref_t node_ref_t::child(const std::string& name) const
{
/* 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++)
{
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)
{
path.clear();
return path;
}
path.push_back(n->name);
nodes = &n->node;
}
return path;
}
std::string node_ref_t::name() const
{
node_t *n = get();
return n == 0 ? "" : n->name;
}
bool node_ref_t::operator==(const node_ref_t& ref) const
{
return m_soc == ref.m_soc && m_path == ref.m_path;
}
void node_ref_t::remove()
{
if(is_root())
{
soc_t *s = soc().get();
if(s)
s->node.clear();
}
else
{
std::vector< node_t > *list = get_children(parent());
if(list == 0)
return;
for(size_t i = 0; i < list->size(); i++)
if((*list)[i].id == m_path.back())
{
list->erase(list->begin() + i);
return;
}
}
}
node_ref_t node_ref_t::create() const
{
std::vector< node_t > *list = get_children(*this);
if(list == 0)
return node_ref_t();
node_t n;
n.id = gen_fresh_id(*list);
list->push_back(n);
std::vector< soc_id_t > path = m_path;
path.push_back(n.id);
return node_ref_t(soc(), path);
}
/**
* register_ref_t
*/
register_ref_t::register_ref_t(node_ref_t node)
:m_node(node)
{
}
register_ref_t::register_ref_t()
{
}
bool register_ref_t::valid() const
{
return get() != 0;
}
void register_ref_t::reset()
{
m_node.reset();
}
register_t *register_ref_t::get() const
{
node_t *n = m_node.get();
if(n == 0 || n->register_.empty())
return 0;
return &n->register_[0];
}
node_ref_t register_ref_t::node() const
{
return m_node;
}
std::vector< field_ref_t > register_ref_t::fields() const
{
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< variant_ref_t > register_ref_t::variants() const
{
std::vector< variant_ref_t > variants;
register_t *r = get();
if(r == 0)
return variants;
for(size_t i = 0; i < r->variant.size(); i++)
variants.push_back(variant_ref_t(*this, r->variant[i].id));
return variants;
}
field_ref_t register_ref_t::field(const std::string& name) const
{
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();
}
variant_ref_t register_ref_t::variant(const std::string& type) const
{
register_t *r = get();
if(r == 0)
return variant_ref_t();
for(size_t i = 0; i < r->variant.size(); i++)
if(r->variant[i].type == type)
return variant_ref_t(*this, r->variant[i].id);
return variant_ref_t();
}
void register_ref_t::remove()
{
node_t *n = node().get();
if(n)
n->register_.clear();
}
field_ref_t register_ref_t::create_field() const
{
register_t *r = get();
if(r == 0)
return field_ref_t();
field_t f;
f.id = gen_fresh_id(r->field);
r->field.push_back(f);
return field_ref_t(*this, f.id);
}
variant_ref_t register_ref_t::create_variant() const
{
register_t *r = get();
if(r == 0)
return variant_ref_t();
variant_t v;
v.id = gen_fresh_id(r->variant);
r->variant.push_back(v);
return variant_ref_t(*this, v.id);
}
/**
* field_ref_t
*/
field_ref_t::field_ref_t(register_ref_t reg, soc_id_t id)
:m_reg(reg), m_id(id)
{
}
field_ref_t::field_ref_t()
{
}
bool field_ref_t::valid() const
{
return get() != 0;
}
void field_ref_t::reset()
{
m_reg.reset();
}
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;
}
std::vector< enum_ref_t > field_ref_t::enums() const
{
std::vector< enum_ref_t > enums;
field_t *f = get();
if(f == 0)
return enums;
for(size_t i = 0; i < f->enum_.size(); i++)
enums.push_back(enum_ref_t(*this, f->enum_[i].id));
return enums;
}
register_ref_t field_ref_t::reg() const
{
return m_reg;
}
enum_ref_t field_ref_t::create_enum() const
{
field_t *f = get();
if(f == 0)
return enum_ref_t();
enum_t e;
e.id = gen_fresh_id(f->enum_);
f->enum_.push_back(e);
return enum_ref_t(*this, e.id);
}
/**
* enum_ref_t
*/
enum_ref_t::enum_ref_t(field_ref_t field, soc_id_t id)
:m_field(field), m_id(id)
{
}
enum_ref_t::enum_ref_t()
{
}
bool enum_ref_t::valid() const
{
return get() != 0;
}
void enum_ref_t::reset()
{
m_field.reset();
}
enum_t *enum_ref_t::get() const
{
field_t *field = m_field.get();
if(field == 0)
return 0;
for(size_t i = 0; i < field->enum_.size(); i++)
if(field->enum_[i].id == m_id)
return &field->enum_[i];
return 0;
}
field_ref_t enum_ref_t::field() const
{
return m_field;
}
/**
* variant_ref_t
*/
variant_ref_t::variant_ref_t(register_ref_t reg, soc_id_t id)
:m_reg(reg), m_id(id)
{
}
variant_ref_t::variant_ref_t()
{
}
bool variant_ref_t::valid() const
{
return get() != 0;
}
void variant_ref_t::reset()
{
m_reg.reset();
}
variant_t *variant_ref_t::get() const
{
register_t *reg = m_reg.get();
if(reg == 0)
return 0;
for(size_t i = 0; i < reg->variant.size(); i++)
if(reg->variant[i].id == m_id)
return &reg->variant[i];
return 0;
}
register_ref_t variant_ref_t::reg() const
{
return m_reg;
}
std::string variant_ref_t::type() const
{
variant_t *v = get();
return v ? v->type : std::string();
}
soc_word_t variant_ref_t::offset() const
{
variant_t *v = get();
return v ? v->offset : 0;
}
/**
* node_inst_t
*/
namespace
{
const size_t INST_NO_INDEX = std::numeric_limits<std::size_t>::max();
bool get_inst_addr(range_t& range, size_t index, soc_addr_t& addr)
{
if(index < range.first || index >= range.first + range.size())
return false;
switch(range.type)
{
case range_t::STRIDE:
addr += range.base + (index - range.first) * range.stride;
return true;
case range_t::FORMULA:
{
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;
}
case range_t::LIST:
addr += range.list[index - range.first];
return true;
default:
return false;
}
}
bool get_inst_addr(instance_t *inst, size_t index, soc_addr_t& addr)
{
if(inst == 0)
return false;
switch(inst->type)
{
case instance_t::SINGLE:
if(index != INST_NO_INDEX)
return false;
addr += inst->addr;
return true;
case instance_t::RANGE:
if(index == INST_NO_INDEX)
return false;
return get_inst_addr(inst->range, index, addr);
default:
return false;
}
}
}
node_inst_t::node_inst_t(soc_ref_t soc)
:m_node(soc.root())
{
}
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)
{
}
node_inst_t::node_inst_t()
{
}
bool node_inst_t::valid() const
{
return (is_root() && node().valid()) || get() != 0;
}
void node_inst_t::reset()
{
m_node.reset();
}
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(unsigned level) const
{
if(level > depth())
return node_inst_t();
std::vector< soc_id_t > ids = m_id_path;
std::vector< size_t > indexes = m_index_path;
ids.resize(depth() - level);
indexes.resize(depth() - level);
return node_inst_t(m_node.parent(level), ids, indexes);
}
unsigned node_inst_t::depth() const
{
return m_id_path.size();
}
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(!valid() || 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 || is_nochild())
return node_inst_t();
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++)
{
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);
indexes.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 || is_nochild())
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::FLOATING:
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.size(); 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;
}
bool node_inst_t::is_nochild() const
{
instance_t *inst = get();
return inst == 0 ? false : inst->nochild;
}
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;
}
size_t node_inst_t::index() const
{
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
* 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