Skip to content

Commit

Permalink
Allow nets & variables to be elaborated early on demand.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
martinwhitaker committed Apr 6, 2024
1 parent ff4cd2c commit ca30705
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 2 deletions.
4 changes: 3 additions & 1 deletion PWire.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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
Expand Down
30 changes: 30 additions & 0 deletions elab_scope.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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.

Expand Down Expand Up @@ -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);

Expand All @@ -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);

Expand Down Expand Up @@ -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);
}
Expand Down
19 changes: 18 additions & 1 deletion elab_sig.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 changes: 19 additions & 0 deletions net_scope.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
# include "netvector.h"
# include "PExpr.h"
# include "PPackage.h"
# include "PWire.h"
# include <cstring>
# include <cstdlib>
# include <sstream>
Expand Down Expand Up @@ -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;
Expand Down
12 changes: 12 additions & 0 deletions netlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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_;
Expand Down
17 changes: 17 additions & 0 deletions symbol_search.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
# include "netmisc.h"
# include "compiler.h"
# include "PPackage.h"
# include "PWire.h"
# include "ivl_assert.h"

using namespace std;
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit ca30705

Please sign in to comment.