From 0f701a64bee43e79f95970ae9c0ec43ea7fcdf17 Mon Sep 17 00:00:00 2001 From: Amaury Pouly Date: Sat, 6 Feb 2016 15:01:24 +0000 Subject: 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 --- utils/regtools/lib/soc_desc.cpp | 473 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 442 insertions(+), 31 deletions(-) (limited to 'utils/regtools/lib/soc_desc.cpp') 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 or 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")); /* */ SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "first", "%lu", range.first)); - /* */ - SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "count", "%lu", range.count)); - /* */ if(range.type == range_t::STRIDE) { + /* */ + SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "count", "%lu", range.count)); + /* */ SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "base", "0x%x", range.base)); + /* */ SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "stride", "0x%x", range.stride)); } /* */ else if(range.type == range_t::FORMULA) { + /* */ + SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "count", "%lu", range.count)); /* */ SAFE(xmlTextWriterStartElement(writer, BAD_CAST "formula")); /* variable */ @@ -508,6 +628,11 @@ int produce_range(xmlTextWriterPtr writer, const range_t& range, error_context_t /* */ 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])); + } /* */ 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) +{ + /* */ + SAFE(xmlTextWriterStartElement(writer, BAD_CAST "variant")); + /* */ + SAFE(xmlTextWriterWriteElement(writer, BAD_CAST "type", BAD_CAST variant.type.c_str())); + /* */ + SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "offset", "%lu", (unsigned long)variant.offset)); + /* */ + SAFE(xmlTextWriterEndElement(writer)); + return 0; +} + int produce_register(xmlTextWriterPtr writer, const register_t& reg, error_context_t& ctx) { /* */ @@ -582,9 +720,15 @@ int produce_register(xmlTextWriterPtr writer, const register_t& reg, error_conte /* */ if(reg.width != 32) SAFE(xmlTextWriterWriteFormatElement(writer, BAD_CAST "width", "%lu", reg.width)); + /* */ + 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)); /* */ SAFE(xmlTextWriterEndElement(writer)); return 0; @@ -670,6 +814,24 @@ Lerr: 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 */ @@ -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 ®->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::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)); -- cgit