diff options
Diffstat (limited to 'utils/regtools/lib/soc_desc.cpp')
-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 | |||
570 | 570 | ||
571 | struct soc_sorter | 571 | struct soc_sorter |
572 | { | 572 | { |
573 | /* returns the first (lowest) address of an instance */ | 573 | /* returns the lowest address of an instance, or 0 if none |
574 | * and 0xffffffff if cannot evaluate */ | ||
574 | soc_addr_t first_addr(const instance_t& inst) const | 575 | soc_addr_t first_addr(const instance_t& inst) const |
575 | { | 576 | { |
576 | if(inst.type == instance_t::SINGLE) | 577 | if(inst.type == instance_t::SINGLE) |
577 | return inst.addr; | 578 | return inst.addr; |
579 | /* sanity check */ | ||
580 | if(inst.type != instance_t::RANGE) | ||
581 | { | ||
582 | printf("Warning: unknown instance type %d\n", inst.type); | ||
583 | return 0; | ||
584 | } | ||
578 | if(inst.range.type == range_t::STRIDE) | 585 | if(inst.range.type == range_t::STRIDE) |
579 | return inst.range.base; | 586 | return inst.range.base; /* assume positive stride */ |
580 | soc_word_t res; | 587 | if(inst.range.type == range_t::LIST) |
588 | { | ||
589 | soc_addr_t min = 0xffffffff; | ||
590 | for(size_t i = 0; i < inst.range.list.size(); i++) | ||
591 | if(inst.range.list[i] < min) | ||
592 | min = inst.range.list[i]; | ||
593 | return min; | ||
594 | } | ||
595 | /* sanity check */ | ||
596 | if(inst.range.type != range_t::FORMULA) | ||
597 | { | ||
598 | printf("Warning: unknown range type %d\n", inst.range.type); | ||
599 | return 0; | ||
600 | } | ||
601 | soc_addr_t min = 0xffffffff; | ||
581 | std::map< std::string, soc_word_t > vars; | 602 | std::map< std::string, soc_word_t > vars; |
582 | vars[inst.range.variable] = inst.range.first; | 603 | for(size_t i = 0; i < inst.range.count; i++) |
583 | error_context_t ctx; | 604 | { |
584 | if(!evaluate_formula(inst.range.formula, vars, res, "", ctx)) | 605 | soc_word_t res; |
585 | return 0xffffffff; | 606 | vars[inst.range.variable] = inst.range.first; |
586 | return res; | 607 | error_context_t ctx; |
608 | if(evaluate_formula(inst.range.formula, vars, res, "", ctx) && res < min) | ||
609 | min = res; | ||
610 | } | ||
611 | return min; | ||
612 | } | ||
613 | |||
614 | /* return smallest address among all instances */ | ||
615 | soc_addr_t first_addr(const node_t& node) const | ||
616 | { | ||
617 | soc_addr_t min = 0xffffffff; | ||
618 | for(size_t i = 0; i < node.instance.size(); i++) | ||
619 | min = std::min(min, first_addr(node.instance[i])); | ||
620 | return min; | ||
587 | } | 621 | } |
588 | 622 | ||
589 | /* sort instances by first address */ | 623 | /* sort instances by first address */ |
@@ -596,23 +630,30 @@ struct soc_sorter | |||
596 | * any instance if instances are sorted) */ | 630 | * any instance if instances are sorted) */ |
597 | bool operator()(const node_t& a, const node_t& b) const | 631 | bool operator()(const node_t& a, const node_t& b) const |
598 | { | 632 | { |
599 | /* borderline cases: no instances is lower than with instances */ | 633 | soc_addr_t addr_a = first_addr(a); |
600 | if(a.instance.size() == 0) | 634 | soc_addr_t addr_b = first_addr(b); |
601 | return b.instance.size() > 0; | 635 | /* It may happen that two nodes have the same first instance address, |
602 | if(b.instance.size() == 0) | 636 | * for example if one logically splits a block into two blocks with |
603 | return false; | 637 | * the same base. In this case, sort by name */ |
604 | return first_addr(a.instance[0]) < first_addr(b.instance[0]); | 638 | if(addr_a == addr_b) |
639 | return a.name < b.name; | ||
640 | return addr_a < addr_b; | ||
605 | } | 641 | } |
606 | 642 | ||
607 | /* sort fields by decreasing position */ | 643 | /* sort fields by decreasing position */ |
608 | bool operator()(const field_t& a, const field_t& b) const | 644 | bool operator()(const field_t& a, const field_t& b) const |
609 | { | 645 | { |
646 | /* in the unlikely case where two fields have the same position, use name */ | ||
647 | if(a.pos == b.pos) | ||
648 | return a.name < b.name; | ||
610 | return a.pos > b.pos; | 649 | return a.pos > b.pos; |
611 | } | 650 | } |
612 | 651 | ||
613 | /* sort enum values by value */ | 652 | /* sort enum values by value, then by name */ |
614 | bool operator()(const enum_t& a, const enum_t& b) const | 653 | bool operator()(const enum_t& a, const enum_t& b) const |
615 | { | 654 | { |
655 | if(a.value == b.value) | ||
656 | return a.name < b.name; | ||
616 | return a.value < b.value; | 657 | return a.value < b.value; |
617 | } | 658 | } |
618 | }; | 659 | }; |
@@ -639,7 +680,7 @@ void normalize(node_t& node) | |||
639 | std::sort(node.instance.begin(), node.instance.end(), soc_sorter()); | 680 | std::sort(node.instance.begin(), node.instance.end(), soc_sorter()); |
640 | } | 681 | } |
641 | 682 | ||
642 | } | 683 | } /* namespace */ |
643 | 684 | ||
644 | void normalize(soc_t& soc) | 685 | void normalize(soc_t& soc) |
645 | { | 686 | { |