Allow nets & variables to be elaborated early on demand.
If a net or variable is referenced in another net or variable declaration or in a value parameter definition (e.g. when using the $bits function) and hasn't already been elaborated, we need to elaborate it early. So during the scope elaboration phase, add placeholders in each NetScope object to record the PWire objects that are yet to be elaborated. This allows the symbol_search() function to find the unelaborated objects and to trigger early elaboration. Add a flag in the PWire object to indicate when we are elaborating it. This allows us to detect circular references and avoid an infinite loop. This fixes issue #483, issue #575, and issue #1097.
This commit is contained in:
parent
ff4cd2c5da
commit
ca307053f2
4
PWire.h
4
PWire.h
|
|
@ -91,7 +91,7 @@ class PWire : public PNamedItem {
|
|||
// Write myself to the specified stream.
|
||||
void dump(std::ostream&out, unsigned ind=4) const;
|
||||
|
||||
NetNet* elaborate_sig(Design*, NetScope*scope) const;
|
||||
NetNet* elaborate_sig(Design*, NetScope*scope);
|
||||
|
||||
SymbolType symbol_type() const;
|
||||
|
||||
|
|
@ -110,6 +110,8 @@ class PWire : public PNamedItem {
|
|||
// Whether the wire is variable declared with the const keyword.
|
||||
bool is_const_ = false;
|
||||
|
||||
bool is_elaborating_ = false;
|
||||
|
||||
// These members hold expressions for the bit width of the
|
||||
// wire. If they do not exist, the wire is 1 bit wide. If they
|
||||
// do exist, they represent the packed dimensions of the
|
||||
|
|
|
|||
|
|
@ -160,6 +160,22 @@ static void collect_scope_specparams(Design*des, NetScope*scope,
|
|||
}
|
||||
}
|
||||
|
||||
static void collect_scope_signals(NetScope*scope,
|
||||
const map<perm_string,PWire*>&wires)
|
||||
{
|
||||
for (map<perm_string,PWire*>::const_iterator cur = wires.begin()
|
||||
; cur != wires.end() ; ++ cur ) {
|
||||
|
||||
PWire*wire = (*cur).second;
|
||||
if (debug_scopes) {
|
||||
cerr << wire->get_fileline() << ": " << __func__ << ": "
|
||||
<< "adding placeholder for signal '" << wire->basename()
|
||||
<< "' in scope '" << scope_path(scope) << "'." << endl;
|
||||
}
|
||||
scope->add_signal_placeholder(wire);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Elaborate the enumeration into the given scope.
|
||||
*/
|
||||
|
|
@ -498,6 +514,8 @@ static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass)
|
|||
|
||||
collect_scope_parameters(des, class_scope, pclass->parameters);
|
||||
|
||||
collect_scope_signals(class_scope, pclass->wires);
|
||||
|
||||
// Elaborate enum types declared in the class. We need these
|
||||
// now because enumeration constants can be used during scope
|
||||
// elaboration.
|
||||
|
|
@ -725,6 +743,8 @@ bool PPackage::elaborate_scope(Design*des, NetScope*scope)
|
|||
|
||||
collect_scope_parameters(des, scope, parameters);
|
||||
|
||||
collect_scope_signals(scope, wires);
|
||||
|
||||
if (debug_scopes) {
|
||||
cerr << get_fileline() << ": PPackage::elaborate_scope: "
|
||||
<< "Elaborate " << enum_sets.size() << " enumerations"
|
||||
|
|
@ -765,6 +785,8 @@ bool Module::elaborate_scope(Design*des, NetScope*scope,
|
|||
|
||||
collect_scope_specparams(des, scope, specparams);
|
||||
|
||||
collect_scope_signals(scope, wires);
|
||||
|
||||
// Run parameter replacements that were collected from the
|
||||
// containing scope and meant for me.
|
||||
|
||||
|
|
@ -1239,6 +1261,8 @@ void PGenerate::elaborate_subscope_(Design*des, NetScope*scope)
|
|||
// module have been done.
|
||||
collect_scope_parameters(des, scope, parameters);
|
||||
|
||||
collect_scope_signals(scope, wires);
|
||||
|
||||
// Run through the defparams for this scope and save the result
|
||||
// in a table for later final override.
|
||||
|
||||
|
|
@ -1577,6 +1601,8 @@ void PFunction::elaborate_scope(Design*des, NetScope*scope) const
|
|||
|
||||
collect_scope_parameters(des, scope, parameters);
|
||||
|
||||
collect_scope_signals(scope, wires);
|
||||
|
||||
// Scan through all the named events in this scope.
|
||||
elaborate_scope_events_(des, scope, events);
|
||||
|
||||
|
|
@ -1595,6 +1621,8 @@ void PTask::elaborate_scope(Design*des, NetScope*scope) const
|
|||
|
||||
collect_scope_parameters(des, scope, parameters);
|
||||
|
||||
collect_scope_signals(scope, wires);
|
||||
|
||||
// Scan through all the named events in this scope.
|
||||
elaborate_scope_events_(des, scope, events);
|
||||
|
||||
|
|
@ -1643,6 +1671,8 @@ void PBlock::elaborate_scope(Design*des, NetScope*scope) const
|
|||
|
||||
collect_scope_parameters(des, my_scope, parameters);
|
||||
|
||||
collect_scope_signals(my_scope, wires);
|
||||
|
||||
// Scan through all the named events in this scope.
|
||||
elaborate_scope_events_(des, my_scope, events);
|
||||
}
|
||||
|
|
|
|||
19
elab_sig.cc
19
elab_sig.cc
|
|
@ -1011,13 +1011,27 @@ ivl_type_t PWire::elaborate_type(Design*des, NetScope*scope,
|
|||
* elaboration this creates an object in the design that represents the
|
||||
* defined item.
|
||||
*/
|
||||
NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
||||
NetNet* PWire::elaborate_sig(Design*des, NetScope*scope)
|
||||
{
|
||||
// This sets the vector or array dimension size that will
|
||||
// cause a warning. For now, these warnings are permanently
|
||||
// enabled.
|
||||
const long warn_dimension_size = 1 << 30;
|
||||
|
||||
// Check if we elaborated this signal earlier because it was
|
||||
// used in another declaration.
|
||||
if (NetNet*sig = scope->find_signal(name_))
|
||||
return sig;
|
||||
|
||||
if (is_elaborating_) {
|
||||
cerr << get_fileline() << ": error: Circular dependency "
|
||||
"detected in declaration of '" << name_ << "'."
|
||||
<< endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
is_elaborating_ = true;
|
||||
|
||||
NetNet::Type wtype = type_;
|
||||
if (wtype == NetNet::IMPLICIT)
|
||||
wtype = NetNet::WIRE;
|
||||
|
|
@ -1223,5 +1237,8 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
|
|||
|
||||
sig->set_const(is_const_);
|
||||
|
||||
scope->rem_signal_placeholder(this);
|
||||
is_elaborating_ = false;
|
||||
|
||||
return sig;
|
||||
}
|
||||
|
|
|
|||
19
net_scope.cc
19
net_scope.cc
|
|
@ -27,6 +27,7 @@
|
|||
# include "netvector.h"
|
||||
# include "PExpr.h"
|
||||
# include "PPackage.h"
|
||||
# include "PWire.h"
|
||||
# include <cstring>
|
||||
# include <cstdlib>
|
||||
# include <sstream>
|
||||
|
|
@ -702,6 +703,24 @@ LineInfo* NetScope::find_genvar(perm_string name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void NetScope::add_signal_placeholder(PWire*wire)
|
||||
{
|
||||
signal_placeholders_[wire->basename()] = wire;
|
||||
}
|
||||
|
||||
void NetScope::rem_signal_placeholder(PWire*wire)
|
||||
{
|
||||
signal_placeholders_.erase(wire->basename());
|
||||
}
|
||||
|
||||
PWire* NetScope::find_signal_placeholder(perm_string name)
|
||||
{
|
||||
if (signal_placeholders_.find(name) != signal_placeholders_.end())
|
||||
return signal_placeholders_[name];
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NetScope::add_signal(NetNet*net)
|
||||
{
|
||||
signals_map_[net->name()]=net;
|
||||
|
|
|
|||
12
netlist.h
12
netlist.h
|
|
@ -81,6 +81,7 @@ class PExpr;
|
|||
class PFunction;
|
||||
class PPackage;
|
||||
class PTaskFunc;
|
||||
class PWire;
|
||||
class data_type_t;
|
||||
struct enum_type_t;
|
||||
class netclass_t;
|
||||
|
|
@ -1013,6 +1014,15 @@ class NetScope : public Definitions, public Attrib {
|
|||
void add_genvar(perm_string name, LineInfo *li);
|
||||
LineInfo* find_genvar(perm_string name);
|
||||
|
||||
/* These methods manage unelaborated signals. These are added to
|
||||
the scope as placeholders during the scope elaboration phase,
|
||||
to allow signal declarations to refer to other signals (e.g.
|
||||
when using $bits in a range definition), regardless of the
|
||||
order in which the signals are elaborated. */
|
||||
void add_signal_placeholder(PWire*);
|
||||
void rem_signal_placeholder(PWire*);
|
||||
PWire* find_signal_placeholder(perm_string name);
|
||||
|
||||
/* These methods manage signals. The add_ and rem_signal
|
||||
methods are used by the NetNet objects to make themselves
|
||||
available to the scope, and the find_signal method can be
|
||||
|
|
@ -1314,6 +1324,8 @@ class NetScope : public Definitions, public Attrib {
|
|||
|
||||
std::map<perm_string,LineInfo*> genvars_;
|
||||
|
||||
std::map<perm_string,PWire*> signal_placeholders_;
|
||||
|
||||
typedef std::map<perm_string,NetNet*>::const_iterator signals_map_iter_t;
|
||||
std::map <perm_string,NetNet*> signals_map_;
|
||||
perm_string module_name_;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
# include "netmisc.h"
|
||||
# include "compiler.h"
|
||||
# include "PPackage.h"
|
||||
# include "PWire.h"
|
||||
# include "ivl_assert.h"
|
||||
|
||||
using namespace std;
|
||||
|
|
@ -219,6 +220,22 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope,
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally check the rare case of a signal that hasn't
|
||||
// been elaborated yet.
|
||||
if (PWire*wire = scope->find_signal_placeholder(path_tail.name)) {
|
||||
if (prefix_scope || (wire->lexical_pos() <= lexical_pos)) {
|
||||
NetNet*net = wire->elaborate_sig(des, scope);
|
||||
if (!net)
|
||||
return false;
|
||||
path.push_back(path_tail);
|
||||
res->scope = scope;
|
||||
res->net = net;
|
||||
res->type = net->net_type();
|
||||
res->path_head = path;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Could not find an object. Maybe this is a child scope name? If
|
||||
|
|
|
|||
Loading…
Reference in New Issue