summaryrefslogtreecommitdiffstats
path: root/utils/regtools/lib/soc_desc.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/regtools/lib/soc_desc.cpp')
-rw-r--r--utils/regtools/lib/soc_desc.cpp473
1 files changed, 442 insertions, 31 deletions
diff --git a/utils/regtools/lib/soc_desc.cpp b/utils/regtools/lib/soc_desc.cpp
index 4e0e46f00e..e6c58d4814 100644
--- a/utils/regtools/lib/soc_desc.cpp
+++ b/utils/regtools/lib/soc_desc.cpp
@@ -308,13 +308,28 @@ bool parse_field_elem(xmlNode *node, field_t& field, error_context_t& ctx)
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;
+ 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)
+ END_NODE_MATCH()
+ CHECK_HAS(node, "type", has_type, ctx)
+ CHECK_HAS(node, "offset", has_offset, ctx)
+ return ret;
+}
+
bool parse_register_elem(xmlNode *node, register_t& reg, error_context_t& ctx)
{
bool ret = true;
- bool has_width = false;
+ bool has_width = false, has_desc = 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_ELEM_NODE("field", reg.field, parse_field_elem, ctx)
+ MATCH_ELEM_NODE("variant", reg.variant, parse_variant_elem, ctx)
END_NODE_MATCH()
if(!has_width)
reg.width = 32;
@@ -344,21 +359,37 @@ bool parse_range_elem(xmlNode *node, range_t& range, error_context_t& 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)
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;
+ 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
- range.type = range_t::FORMULA;
+ {
+ 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;
}
@@ -400,7 +431,6 @@ bool parse_node_elem(xmlNode *node_, node_t& node, error_context_t& ctx)
MATCH_ELEM_NODE("instance", node.instance, parse_instance_elem, ctx)
END_NODE_MATCH()
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;
@@ -466,6 +496,93 @@ bool parse_xml(const std::string& filename, soc_t& soc,
}
/**
+ * Normalizer
+ */
+
+namespace
+{
+
+struct soc_sorter
+{
+ /* returns the first (lowest) address of an instance */
+ soc_addr_t first_addr(const instance_t& inst) const
+ {
+ if(inst.type == instance_t::SINGLE)
+ return inst.addr;
+ if(inst.range.type == range_t::STRIDE)
+ return inst.range.base;
+ soc_word_t res;
+ std::map< std::string, soc_word_t > vars;
+ vars[inst.range.variable] = inst.range.first;
+ error_context_t ctx;
+ if(!evaluate_formula(inst.range.formula, vars, res, "", ctx))
+ return 0xffffffff;
+ return res;
+ }
+
+ /* 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
+ {
+ /* borderline cases: no instances is lower than with instances */
+ if(a.instance.size() == 0)
+ return b.instance.size() > 0;
+ if(b.instance.size() == 0)
+ return false;
+ return first_addr(a.instance[0]) < first_addr(b.instance[0]);
+ }
+
+ /* sort fields by decreasing position */
+ bool operator()(const field_t& a, const field_t& b) const
+ {
+ return a.pos > b.pos;
+ }
+
+ /* sort enum values by value */
+ bool operator()(const enum_t& a, const enum_t& b) const
+ {
+ 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());
+}
+
+}
+
+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
*/
@@ -488,17 +605,20 @@ int produce_range(xmlTextWriterPtr writer, const range_t& range, error_context_t
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)
{
+ /* <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 */
@@ -508,6 +628,11 @@ int produce_range(xmlTextWriterPtr writer, const range_t& range, error_context_t
/* </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));
@@ -575,6 +700,19 @@ int produce_field(xmlTextWriterPtr writer, const field_t& field, error_context_t
return 0;
}
+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));
+ /* </variant> */
+ SAFE(xmlTextWriterEndElement(writer));
+ return 0;
+}
+
int produce_register(xmlTextWriterPtr writer, const register_t& reg, error_context_t& ctx)
{
/* <register> */
@@ -582,9 +720,15 @@ int produce_register(xmlTextWriterPtr writer, const register_t& reg, error_conte
/* <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()));
/* 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;
@@ -671,6 +815,24 @@ Lerr:
}
/**
+ * 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
*/
@@ -707,6 +869,11 @@ 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 */
@@ -733,6 +900,11 @@ bool node_ref_t::is_root() const
return m_path.empty();
}
+void node_ref_t::reset()
+{
+ m_soc.reset();
+}
+
namespace
{
@@ -789,14 +961,20 @@ soc_ref_t node_ref_t::soc() const
return m_soc;
}
-node_ref_t node_ref_t::parent() const
+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;
- if(!path.empty())
- path.pop_back();
+ 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();
@@ -808,6 +986,18 @@ register_ref_t node_ref_t::reg() const
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 */
@@ -867,6 +1057,41 @@ 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
*/
@@ -885,6 +1110,11 @@ 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();
@@ -909,6 +1139,17 @@ std::vector< field_ref_t > register_ref_t::fields() const
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();
@@ -920,6 +1161,46 @@ field_ref_t register_ref_t::field(const std::string& name) const
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
*/
@@ -938,6 +1219,11 @@ 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();
@@ -949,11 +1235,123 @@ field_t *field_ref_t::get() const
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
*/
@@ -965,8 +1363,8 @@ 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.count)
- return false;
+ if(index < range.first || index >= range.first + range.size())
+ return false;
switch(range.type)
{
case range_t::STRIDE:
@@ -983,6 +1381,9 @@ bool get_inst_addr(range_t& range, size_t index, soc_addr_t& addr)
addr += res;
return true;
}
+ case range_t::LIST:
+ addr += range.list[index - range.first];
+ return true;
default:
return false;
}
@@ -1030,6 +1431,11 @@ bool node_inst_t::valid() const
return is_root() || get() != 0;
}
+void node_inst_t::reset()
+{
+ m_node.reset();
+}
+
node_ref_t node_inst_t::node() const
{
return m_node;
@@ -1045,15 +1451,20 @@ bool node_inst_t::is_root() const
return m_node.is_root();
}
-node_inst_t node_inst_t::parent() const
+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;
- if(!ids.empty())
- ids.pop_back();
- if(!indexes.empty())
- indexes.pop_back();
- return node_inst_t(m_node.parent(), ids, indexes);
+ 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
@@ -1069,7 +1480,7 @@ instance_t *node_inst_t::get() const
soc_addr_t node_inst_t::addr() const
{
- if(is_root())
+ if(!valid() || is_root())
return 0;
soc_addr_t addr = parent().addr();
if(!get_inst_addr(get(), m_index_path.back(), addr))
@@ -1100,7 +1511,7 @@ node_inst_t node_inst_t::child(const std::string& name, size_t index) const
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);
+ indexes.push_back(index);
return node_inst_t(child_node, ids, indexes);
}
child_node.m_path.pop_back();
@@ -1133,7 +1544,7 @@ std::vector< node_inst_t > node_inst_t::children() const
i_path.pop_back();
break;
case instance_t::RANGE:
- for(size_t i = 0; i < inst.range.count; i++)
+ 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));