From e02d186946dc9e2fb78f46270586611b82fc4eff Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 30 Jun 2008 03:46:46 +0200 Subject: [PATCH] Handle multiple passes of scope and defparam elaboration. When generate schems and instance arrays are nested, it takes multiple iterations of elaborate scope, defparams and evaluate parameters before everything is worked out. Rework the work item processing so that the loop elaborates scopes and runs defparams in phases. The phases are needed so that we can tell when the remaining defparams are orphaned. --- elaborate.cc | 55 +++++++++++++++++++++++++++++++--- net_design.cc | 81 ++++++++++++++++++++++++++++++++++++++------------- netlist.h | 8 +++++ t-dll.cc | 8 +++++ 4 files changed, 127 insertions(+), 25 deletions(-) diff --git a/elaborate.cc b/elaborate.cc index 4cb32bdf7..f22e38f00 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -3819,6 +3819,32 @@ class top_defparams : public elaborator_work_item_t { } }; +class later_defparams : public elaborator_work_item_t { + public: + later_defparams(Design*des) + : elaborator_work_item_t(des) + { } + + ~later_defparams() { } + + virtual void elaborate_runrun() + { + listtmp_list; + for (set::iterator cur = des->defparams_later.begin() + ; cur != des->defparams_later.end() ; cur ++ ) + tmp_list.push_back(*cur); + + des->defparams_later.clear(); + + while (! tmp_list.empty()) { + NetScope*cur = tmp_list.front(); + tmp_list.pop_front(); + cur->run_defparams_later(des); + } + des->evaluate_parameters(); + } +}; + /* * This function is the root of all elaboration. The input is the list * of root module names. The function locates the Module definitions @@ -3890,12 +3916,33 @@ Design* elaborate(listroots) // empty. This list is initially populated above where the // initial root scopes are primed. while (! des->elaboration_work_list.empty()) { - elaborator_work_item_t*tmp = des->elaboration_work_list.front(); - des->elaboration_work_list.pop_front(); - tmp->elaborate_runrun(); - delete tmp; + // Transfer the queue to a temporary queue. + list cur_queue; + while (! des->elaboration_work_list.empty()) { + cur_queue.push_back(des->elaboration_work_list.front()); + des->elaboration_work_list.pop_front(); + } + + // Run from the temporary queue. If the temporary queue + // items create new work queue items, they will show up + // in the elaboration_work_list and then we get to run + // through them in the next pass. + while (! cur_queue.empty()) { + elaborator_work_item_t*tmp = cur_queue.front(); + cur_queue.pop_front(); + tmp->elaborate_runrun(); + delete tmp; + } + + if (! des->elaboration_work_list.empty()) { + des->elaboration_work_list.push_back(new later_defparams(des)); + } } + // Look for residual defparams (that point to a non-existent + // scope) and clean them out. + des->residual_defparams(); + // Errors already? Probably missing root modules. Just give up // now and return nothing. if (des->errors > 0) diff --git a/net_design.cc b/net_design.cc index 98900b180..595c1a44a 100644 --- a/net_design.cc +++ b/net_design.cc @@ -20,6 +20,7 @@ # include "config.h" # include +# include # include /* @@ -199,22 +200,6 @@ void Design::run_defparams() (*scope)->run_defparams(this); } -class run_defparams_later_t : public elaborator_work_item_t { - public: - run_defparams_later_t(Design*des, NetScope*scope) - : elaborator_work_item_t(des), scope_(scope) - { } - - void elaborate_runrun(); - private: - NetScope*scope_; -}; - -void run_defparams_later_t::elaborate_runrun() -{ - scope_->run_defparams_later(des); -} - void NetScope::run_defparams(Design*des) { { NetScope*cur = sub_; @@ -262,13 +247,19 @@ void NetScope::run_defparams(Design*des) } } - if (! defparams_later.empty()) { - des->elaboration_work_list.push_back(new run_defparams_later_t(des, this)); - } + + // If some of the defparams didn't find a scope in the name, + // then try again later. It may be that the target scope is + // created later by generate scheme or instance array. + if (! defparams_later.empty()) + des->defparams_later.insert(this); } void NetScope::run_defparams_later(Design*des) { + set target_scopes; + list,NetExpr*> > defparams_even_later; + while (! defparams_later.empty()) { pair,NetExpr*> cur = defparams_later.front(); defparams_later.pop_front(); @@ -281,8 +272,11 @@ void NetScope::run_defparams_later(Design*des) NetScope*targ_scope = des->find_scope(this, eval_path); if (targ_scope == 0) { - cerr << val->get_fileline() << ": warning: scope of " << - eval_path << "." << name << " not found." << endl; + // If a scope in the target path is not found, + // then push this defparam for handling even + // later. Maybe a later generate scheme or + // instance array will create the scope. + defparams_even_later.push_back(cur); continue; } @@ -296,7 +290,23 @@ void NetScope::run_defparams_later(Design*des) << name << " not found in " << scope_path(targ_scope) << "." << endl; } + + // We'll need to re-evaluate parameters in this scope + target_scopes.insert(targ_scope); } + + // All the scopes that this defparam set touched should have + // their parameters re-evaluated. + for (set::iterator cur = target_scopes.begin() + ; cur != target_scopes.end() ; cur ++ ) + (*cur)->evaluate_parameters(des); + + // If there are some scopes that still have missing scopes, + // then sav them back into the defparams_later list for a + // later pass. + defparams_later = defparams_even_later; + if (! defparams_later.empty()) + des->defparams_later.insert(this); } void Design::evaluate_parameters() @@ -576,6 +586,9 @@ void NetScope::evaluate_parameters(Design*des) cur = cur->sib_; } + if (debug_scopes) + cerr << ":0" << ": debug: " + << "Evaluate parameters in " << scope_path(this) << endl; // Evaluate the parameter values. The parameter expressions // have already been elaborated and replaced by the scope @@ -610,6 +623,32 @@ void NetScope::evaluate_parameters(Design*des) } +void Design::residual_defparams() +{ + for (list::const_iterator scope = root_scopes_.begin(); + scope != root_scopes_.end(); scope++) + (*scope)->residual_defparams(this); +} + +void NetScope::residual_defparams(Design*des) +{ + // Clean out the list of defparams that never managed to match + // a scope. Print a warning for each. + while (! defparams_later.empty()) { + pair,NetExpr*> cur = defparams_later.front(); + defparams_later.pop_front(); + + cerr << cur.second->get_fileline() << ": warning: " + << "Scope of " << cur.first << " not found." << endl; + } + + NetScope*cur = sub_; + while (cur) { + cur->residual_defparams(des); + cur = cur->sib_; + } +} + const char* Design::get_flag(const string&key) const { map::const_iterator tmp = flags_.find(key); diff --git a/netlist.h b/netlist.h index 5057af231..d6e01bab2 100644 --- a/netlist.h +++ b/netlist.h @@ -29,6 +29,7 @@ # include # include # include +# include # include # include "ivl_target.h" # include "pform_types.h" @@ -723,6 +724,9 @@ class NetScope : public Attrib { void evaluate_parameters(class Design*); + // Look for defparams that never matched, and print warnings. + void residual_defparams(class Design*); + /* This method generates a non-hierarchical name that is guaranteed to be unique within this scope. */ perm_string local_symbol(); @@ -3672,10 +3676,14 @@ class Design { listelaboration_work_list; void run_elaboration_work(void); + set defparams_later; + // PARAMETERS void run_defparams(); void evaluate_parameters(); + // Look for defparams that never matched, and print warnings. + void residual_defparams(); /* This method locates a signal, starting at a given scope. The name parameter may be partially hierarchical, so diff --git a/t-dll.cc b/t-dll.cc index 0d9380ac4..06cd40220 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -30,6 +30,7 @@ # include #endif # include +# include "ivl_assert.h" #if defined(__WIN32__) @@ -538,6 +539,13 @@ void dll_target::make_scope_param_expr(ivl_parameter_t cur_par, NetExpr*etmp) } + if (expr_ == 0) { + cerr << etmp->get_fileline() << ": internal error: " + << "Parameter expression not reduced to constant? " + << *etmp << endl; + } + ivl_assert(*etmp, expr_); + cur_par->value = expr_; expr_ = 0; }