summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2017-01-23 16:07:41 +0100
committerAmaury Pouly <amaury.pouly@gmail.com>2017-01-24 15:17:46 +0100
commit6ef3f7c13b086dfac9aa697fae47024316f6174e (patch)
treebe1a80d5224ac9773d57b9bc554b94731f584911
parent28bf763373ef35ac27a70d5af4afee22bf25e15b (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.cpp73
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)
{