diff options
Diffstat (limited to 'utils/regtools/lib/soc_desc.cpp')
| -rw-r--r-- | utils/regtools/lib/soc_desc.cpp | 473 |
1 files changed, 442 insertions, 31 deletions
diff --git a/utils/regtools/lib/soc_desc.cpp b/utils/regtools/lib/soc_desc.cpp index 4e0e46f..e6c58d4 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 ®->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)); |