diff options
author | Amaury Pouly <amaury.pouly@gmail.com> | 2017-01-23 16:07:41 +0100 |
---|---|---|
committer | Amaury Pouly <amaury.pouly@gmail.com> | 2017-01-24 15:17:46 +0100 |
commit | 6ef3f7c13b086dfac9aa697fae47024316f6174e (patch) | |
tree | be1a80d5224ac9773d57b9bc554b94731f584911 | |
parent | 28bf763373ef35ac27a70d5af4afee22bf25e15b (diff) |
regtools: fix normalization procedure
The code was not updated when I added support for list and other stuff, and thus
it did not properly sort by addresses.
Change-Id: Iaed0717b607beedfb2856c020c2a760e7a5667c5
-rw-r--r-- | utils/regtools/lib/soc_desc.cpp | 73 |
1 files changed, 57 insertions, 16 deletions
diff --git a/utils/regtools/lib/soc_desc.cpp b/utils/regtools/lib/soc_desc.cpp index ef8aeb5a17..1cfbdac1f4 100644 --- a/utils/regtools/lib/soc_desc.cpp +++ b/utils/regtools/lib/soc_desc.cpp @@ -570,20 +570,54 @@ namespace struct soc_sorter { - /* returns the first (lowest) address of an instance */ + /* 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; - soc_word_t res; + 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; - vars[inst.range.variable] = inst.range.first; - error_context_t ctx; - if(!evaluate_formula(inst.range.formula, vars, res, "", ctx)) - return 0xffffffff; - return res; + 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 */ @@ -596,23 +630,30 @@ struct soc_sorter * 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]); + 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 */ + /* 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; } }; @@ -639,7 +680,7 @@ void normalize(node_t& node) std::sort(node.instance.begin(), node.instance.end(), soc_sorter()); } -} +} /* namespace */ void normalize(soc_t& soc) { |