diff --git a/PWire.h b/PWire.h index 4ab66d430..a63687ac2 100644 --- a/PWire.h +++ b/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 diff --git a/elab_scope.cc b/elab_scope.cc index aa97a9027..0c21459dd 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -160,6 +160,22 @@ static void collect_scope_specparams(Design*des, NetScope*scope, } } +static void collect_scope_signals(NetScope*scope, + const map&wires) +{ + for (map::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); } diff --git a/elab_sig.cc b/elab_sig.cc index 65c2899f7..2cfcfef7c 100644 --- a/elab_sig.cc +++ b/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; } diff --git a/net_scope.cc b/net_scope.cc index 76d29c601..1380a7fef 100644 --- a/net_scope.cc +++ b/net_scope.cc @@ -27,6 +27,7 @@ # include "netvector.h" # include "PExpr.h" # include "PPackage.h" +# include "PWire.h" # include # include # include @@ -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; diff --git a/netlist.h b/netlist.h index d2a039e44..8e453a4eb 100644 --- a/netlist.h +++ b/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 genvars_; + std::map signal_placeholders_; + typedef std::map::const_iterator signals_map_iter_t; std::map signals_map_; perm_string module_name_; diff --git a/symbol_search.cc b/symbol_search.cc index 8479ff268..be8580018 100644 --- a/symbol_search.cc +++ b/symbol_search.cc @@ -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