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.
This commit is contained in:
Stephen Williams 2008-06-30 03:46:46 +02:00
parent d9b02657a7
commit e02d186946
4 changed files with 127 additions and 25 deletions

View File

@ -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()
{
list<NetScope*>tmp_list;
for (set<NetScope*>::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(list<perm_string>roots)
// 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<elaborator_work_item_t*> 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)

View File

@ -20,6 +20,7 @@
# include "config.h"
# include <iostream>
# include <set>
# include <cstdlib>
/*
@ -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<NetScope*> target_scopes;
list<pair<list<hname_t>,NetExpr*> > defparams_even_later;
while (! defparams_later.empty()) {
pair<list<hname_t>,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<NetScope*>::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<NetScope*>::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<list<hname_t>,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<string,const char*>::const_iterator tmp = flags_.find(key);

View File

@ -29,6 +29,7 @@
# include <map>
# include <list>
# include <vector>
# include <set>
# include <utility>
# 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 {
list<elaborator_work_item_t*>elaboration_work_list;
void run_elaboration_work(void);
set<NetScope*> 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

View File

@ -30,6 +30,7 @@
# include <malloc.h>
#endif
# include <stdlib.h>
# 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;
}