summaryrefslogtreecommitdiffstats
path: root/utils/regtools/lib/soc_desc.cpp
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2016-02-06 15:01:24 +0000
committerAmaury Pouly <amaury.pouly@gmail.com>2016-02-06 15:12:55 +0000
commit0f701a64bee43e79f95970ae9c0ec43ea7fcdf17 (patch)
treec8ac6b5516eac120797eb6a06f633919e9f48f9b /utils/regtools/lib/soc_desc.cpp
parent16c915ec1826dcef2e58ecc055a3f5dfcefb235a (diff)
downloadrockbox-0f701a64bee43e79f95970ae9c0ec43ea7fcdf17.tar.gz
rockbox-0f701a64bee43e79f95970ae9c0ec43ea7fcdf17.tar.bz2
rockbox-0f701a64bee43e79f95970ae9c0ec43ea7fcdf17.zip
regtools: update v2 specification, library and tools
A v2 register description file can now include register variants and instances addresses can now be a list (previously it could only be a stride or a formula). Update the library to deal with that. The convert option of swiss_knife was updated and one incompatible change was introduce: if a v1 device has several addresses, those are converted to a single v2 instance with list (instead of several single instances). This should have been the behaviour from the start. Swiss_knife can now also convert regdumps, in which case it needs to be given both the dump and register description file. Also introduce two register descriptions files (vsoc1000 and vsoc2000) which give more complicated examples of v2 register description files. Change-Id: Id9415b8363269ffaf9216abfc6dd1bd1adbfcf8d
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));