From 9de786fc449250dd5cef1f143fbcd63e46cd3b5f Mon Sep 17 00:00:00 2001 From: steve Date: Sun, 5 Sep 2004 17:44:41 +0000 Subject: [PATCH] Add support for module instance arrays. --- README.txt | 3 - compiler.h | 7 +- elab_scope.cc | 197 ++++++++++++++++++++++++++++++++++---------------- elab_sig.cc | 41 +++++++---- elaborate.cc | 118 ++++++++++++++++++++---------- main.cc | 20 ++++- netlist.h | 10 ++- 7 files changed, 273 insertions(+), 123 deletions(-) diff --git a/README.txt b/README.txt index 646877abc..9858adb42 100644 --- a/README.txt +++ b/README.txt @@ -344,9 +344,6 @@ constructs. - tran primitives, i.e. tran, tranif1, tranif0, rtran, rtranif1 and rtranif0 are not supported. - - Module instance arrays are not supported, although gate instance - arrays do work. - - Net delays, of the form "wire #N foo;" do not work. Delays in every other context do work properly, including the V2001 form "wire #5 foo = bar;" diff --git a/compiler.h b/compiler.h index 9440bd37e..d444d2617 100644 --- a/compiler.h +++ b/compiler.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: compiler.h,v 1.22 2004/03/10 04:51:24 steve Exp $" +#ident "$Id: compiler.h,v 1.23 2004/09/05 17:44:41 steve Exp $" #endif # include @@ -81,6 +81,8 @@ extern bool warn_portbinding; /* This is true if verbose output is requested. */ extern bool verbose_flag; +extern bool debug_scopes; + /* Path to a directory useful for finding subcomponents. */ extern const char*basedir; @@ -132,6 +134,9 @@ extern int load_sys_func_table(const char*path); /* * $Log: compiler.h,v $ + * Revision 1.23 2004/09/05 17:44:41 steve + * Add support for module instance arrays. + * * Revision 1.22 2004/03/10 04:51:24 steve * Add support for system function table files. * diff --git a/elab_scope.cc b/elab_scope.cc index ba56635f4..c1d4e3d74 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: elab_scope.cc,v 1.33 2004/08/26 04:02:03 steve Exp $" +#ident "$Id: elab_scope.cc,v 1.34 2004/09/05 17:44:41 steve Exp $" #endif # include "config.h" @@ -46,6 +46,11 @@ bool Module::elaborate_scope(Design*des, NetScope*scope) const { + if (debug_scopes) { + cerr << get_line() << ": debug: Elaborate scope " + << scope->name() << "." << endl; + } + // Generate all the parameters that this instance of this // module introduces to the design. This loop elaborates the // parameters, but doesn't evaluate references to @@ -219,7 +224,6 @@ bool Module::elaborate_scope(Design*des, NetScope*scope) const // scan all of them to create those scopes. typedef list::const_iterator gates_it_t; - for (gates_it_t cur = gates_.begin() ; cur != gates_.end() ; cur ++ ) { @@ -305,80 +309,142 @@ void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const return; } - // Create the new scope as a MODULE with my name. - NetScope*my_scope = new NetScope(sc, get_name(), NetScope::MODULE); - my_scope->set_module_name(mod->mod_name()); - my_scope->default_nettype(mod->default_nettype); + verinum*msb = msb_ ? msb_->eval_const(des, sc) : 0; + verinum*lsb = lsb_ ? lsb_->eval_const(des, sc) : 0; - // Set time units and precision. - my_scope->time_unit(mod->time_unit); - my_scope->time_precision(mod->time_precision); - des->set_precision(mod->time_precision); + assert( (msb == 0) || (lsb != 0) ); - // This call actually arranges for the description of the - // module type to process this instance and handle parameters - // and sub-scopes that might occur. Parameters are also - // created in that scope, as they exist. (I'll override them - // later.) - mod->elaborate_scope(des, my_scope); + long instance_low = 0; + long instance_high = 0; + long instance_count = 1; + bool instance_array = false; - // Look for module parameter replacements. The "replace" map - // maps parameter name to replacement expression that is - // passed. It is built up by the ordered overrides or named - // overrides. + if (msb) { + instance_array = true; + instance_high = msb->as_long(); + instance_low = lsb->as_long(); + if (instance_high > instance_low) + instance_count = instance_high - instance_low + 1; + else + instance_count = instance_low - instance_high + 1; + } - typedef map::const_iterator mparm_it_t; - map replace; + NetScope::scope_vec_t instances (instance_count); + if (debug_scopes) { + cerr << get_line() << ": debug: Create " << instance_count + << " instances of " << get_name() + << "." << endl; + } + + // Run through the module instances, and make scopes out of + // them. Also do parameter overrides that are done on the + // instantiation line. + for (int idx = 0 ; idx < instance_count ; idx += 1) { + + perm_string use_name = get_name(); + + if (instance_array) { + char name_buf[128]; + int instance_idx = idx; + if (instance_low < instance_high) + instance_idx = instance_low + idx; + else + instance_idx = instance_low - idx; + + snprintf(name_buf, sizeof name_buf, + "%s[%d]", get_name().str(), instance_idx); + use_name = lex_strings.make(name_buf); + } + + if (debug_scopes) { + cerr << get_line() << ": debug: Module instance " << use_name + << " becomes child of " << sc->name() + << "." << endl; + } + + // Create the new scope as a MODULE with my name. + NetScope*my_scope = new NetScope(sc, use_name, NetScope::MODULE); + my_scope->set_module_name(mod->mod_name()); + my_scope->default_nettype(mod->default_nettype); + + instances[idx] = my_scope; + + // Set time units and precision. + my_scope->time_unit(mod->time_unit); + my_scope->time_precision(mod->time_precision); + des->set_precision(mod->time_precision); + + // This call actually arranges for the description of the + // module type to process this instance and handle parameters + // and sub-scopes that might occur. Parameters are also + // created in that scope, as they exist. (I'll override them + // later.) + mod->elaborate_scope(des, my_scope); + + // Look for module parameter replacements. The "replace" map + // maps parameter name to replacement expression that is + // passed. It is built up by the ordered overrides or named + // overrides. + + typedef map::const_iterator mparm_it_t; + map replace; - // Positional parameter overrides are matched to parameter - // names by using the param_names list of parameter - // names. This is an ordered list of names so the first name - // is parameter 0, the second parameter 1, and so on. + // Positional parameter overrides are matched to parameter + // names by using the param_names list of parameter + // names. This is an ordered list of names so the first name + // is parameter 0, the second parameter 1, and so on. - if (overrides_) { - assert(parms_ == 0); - list::const_iterator cur = mod->param_names.begin(); - unsigned idx = 0; - for (;;) { - if (idx >= overrides_->count()) - break; - if (cur == mod->param_names.end()) - break; + if (overrides_) { + assert(parms_ == 0); + list::const_iterator cur + = mod->param_names.begin(); + unsigned idx = 0; + for (;;) { + if (idx >= overrides_->count()) + break; + if (cur == mod->param_names.end()) + break; - replace[*cur] = (*overrides_)[idx]; + replace[*cur] = (*overrides_)[idx]; - idx += 1; - cur ++; + idx += 1; + cur ++; + } + } + + // Named parameter overrides carry a name with each override + // so the mapping into the replace list is much easier. + if (parms_) { + assert(overrides_ == 0); + for (unsigned idx = 0 ; idx < nparms_ ; idx += 1) + replace[parms_[idx].name] = parms_[idx].parm; + + } + + + // And here we scan the replacements we collected. Elaborate + // the expression in my context, then replace the sub-scope + // parameter value with the new expression. + + for (mparm_it_t cur = replace.begin() + ; cur != replace.end() ; cur ++ ) { + + PExpr*tmp = (*cur).second; + NetExpr*val = tmp->elaborate_pexpr(des, sc); + bool flag = my_scope->replace_parameter((*cur).first, val); + if (! flag) { + cerr << val->get_line() << ": warning: parameter " + << (*cur).first << " not found in " + << sc->name() << "." << endl; + } } } - // Named parameter overrides carry a name with each override - // so the mapping into the replace list is much easier. - if (parms_) { - assert(overrides_ == 0); - for (unsigned idx = 0 ; idx < nparms_ ; idx += 1) - replace[parms_[idx].name] = parms_[idx].parm; - - } - - - // And here we scan the replacements we collected. Elaborate - // the expression in my context, then replace the sub-scope - // parameter value with the new expression. - - for (mparm_it_t cur = replace.begin() - ; cur != replace.end() ; cur ++ ) { - - PExpr*tmp = (*cur).second; - NetExpr*val = tmp->elaborate_pexpr(des, sc); - bool flag = my_scope->replace_parameter((*cur).first, val); - if (! flag) { - cerr << val->get_line() << ": warning: parameter " - << (*cur).first << " not found in " - << sc->name() << "." << endl; - } - } + /* Stash the instance array of scopes into the parent + scope. Later elaboration passes will use this vector to + further elaborate the array. */ + sc->instance_arrays[get_name()] = instances; } /* @@ -568,6 +634,9 @@ void PWhile::elaborate_scope(Design*des, NetScope*scope) const /* * $Log: elab_scope.cc,v $ + * Revision 1.34 2004/09/05 17:44:41 steve + * Add support for module instance arrays. + * * Revision 1.33 2004/08/26 04:02:03 steve * Add support for localparam ranges. * diff --git a/elab_sig.cc b/elab_sig.cc index 0506304bf..0787d535f 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: elab_sig.cc,v 1.34 2004/05/31 23:34:37 steve Exp $" +#ident "$Id: elab_sig.cc,v 1.35 2004/09/05 17:44:41 steve Exp $" #endif # include "config.h" @@ -211,23 +211,31 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const bool PGModule::elaborate_sig_mod_(Design*des, NetScope*scope, Module*rmod) const { - // Missing module instance names have already been rejected. - assert(get_name() != ""); + bool flag = true; + + NetScope::scope_vec_t instance = scope->instance_arrays[get_name()]; + + for (unsigned idx = 0 ; idx < instance.count() ; idx += 1) { + // I know a priori that the elaborate_scope created the scope + // already, so just look it up as a child of the current scope. + NetScope*my_scope = instance[idx]; + assert(my_scope); + + if (my_scope->parent() != scope) { + cerr << get_line() << ": internal error: " + << "Instance " << my_scope->name() + << " is in parent " << my_scope->parent()->name() + << " instead of " << scope->name() + << endl; + } + assert(my_scope->parent() == scope); + + if (! rmod->elaborate_sig(des, my_scope)) + flag = false; - if (msb_) { - cerr << get_line() << ": sorry: Module instantiation arrays " - "are not yet supported." << endl; - des->errors += 1; - return false; } - - // I know a priori that the elaborate_scope created the scope - // already, so just look it up as a child of the current scope. - NetScope*my_scope = scope->child(get_name()); - assert(my_scope); - - return rmod->elaborate_sig(des, my_scope); + return flag; } /* @@ -607,6 +615,9 @@ void PWire::elaborate_sig(Design*des, NetScope*scope) const /* * $Log: elab_sig.cc,v $ + * Revision 1.35 2004/09/05 17:44:41 steve + * Add support for module instance arrays. + * * Revision 1.34 2004/05/31 23:34:37 steve * Rewire/generalize parsing an elaboration of * function return values to allow for better diff --git a/elaborate.cc b/elaborate.cc index 9b357699a..bcd6d307e 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: elaborate.cc,v 1.305 2004/06/30 15:32:02 steve Exp $" +#ident "$Id: elaborate.cc,v 1.306 2004/09/05 17:44:41 steve Exp $" #endif # include "config.h" @@ -492,23 +492,9 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const */ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const { - // Missing module instance names have already been rejected. - assert(get_name() != 0); - - if (msb_) { - cerr << get_line() << ": sorry: Module instantiation arrays " - "are not yet supported." << endl; - des->errors += 1; - return; - } assert(scope); - // I know a priori that the elaborate_scope created the scope - // already, so just look it up as a child of the current scope. - NetScope*my_scope = scope->child(get_name()); - assert(my_scope); - // This is the array of pin expressions, shuffled to match the // order of the declaration. If the source instantiation uses // bind by order, this is the same as the source @@ -589,11 +575,18 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const pins = get_pins(); } - // Elaborate this instance of the module. The recursive + + // Elaborate these instances of the module. The recursive // elaboration causes the module to generate a netlist with // the ports represented by NetNet objects. I will find them // later. - rmod->elaborate(des, my_scope); + + NetScope::scope_vec_t&instance = scope->instance_arrays[get_name()]; + for (unsigned inst = 0 ; inst < instance.count() ; inst += 1) { + rmod->elaborate(des, instance[inst]); + } + + // Now connect the ports of the newly elaborated designs to // the expressions that are the instantiation parameters. Scan @@ -621,7 +614,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const if (mport.count() == 0) continue; - NetNet*tmp = des->find_signal(my_scope, + NetNet*tmp = des->find_signal(instance[0], mport[0]->path()); assert(tmp); @@ -639,36 +632,48 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const } - // Inside the module, the port is zero or more signals // that were already elaborated. List all those signals - // and the NetNet equivalents. + // and the NetNet equivalents, for all the instances. svector mport = rmod->get_port(idx); - svectorprts (mport.count()); + svectorprts (mport.count() * instance.count()); // Count the internal pins of the port. unsigned prts_pin_count = 0; - for (unsigned ldx = 0 ; ldx < mport.count() ; ldx += 1) { - PEIdent*pport = mport[ldx]; - assert(pport); - prts[ldx] = pport->elaborate_port(des, my_scope); - if (prts[ldx] == 0) - continue; - assert(prts[ldx]); - prts_pin_count += prts[ldx]->pin_count(); + for (unsigned inst = 0 ; inst < instance.count() ; inst += 1) { + NetScope*inst_scope = instance[inst]; + + // Scan the module sub-ports for this instance... + for (unsigned ldx = 0 ; ldx < mport.count() ; ldx += 1) { + unsigned lbase = inst * mport.count(); + PEIdent*pport = mport[ldx]; + assert(pport); + prts[lbase + ldx] + = pport->elaborate_port(des, inst_scope); + if (prts[lbase + ldx] == 0) + continue; + + assert(prts[lbase + ldx]); + prts_pin_count += prts[lbase + ldx]->pin_count(); + } } // If I find that the port in unconnected inside the // module, then there is nothing to connect. Skip the - // parameter. + // argument. if (prts_pin_count == 0) { continue; } - // Elaborate the expression that connects to the module - // port. sig is the thing outside the module that - // connects to the port. + // We know by design that each instance has the same + // width port. Therefore, the prts_pin_count must be an + // even multiple of the instance count. + assert(prts_pin_count % instance.count() == 0); + + // Elaborate the expression that connects to the + // module[s] port. sig is the thing outside the module + // that connects to the port. NetNet*sig; if ((prts.count() >= 1) @@ -687,9 +692,18 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const } } else { + /* Input to module. elaborate the expression to + the desired width. If this in an instance + array, then let the net determine it's own + width. We use that, then, to decide how to hook + it up. */ + unsigned desired_pin_count = prts_pin_count; + if (instance.count() != 1) + desired_pin_count = 0; + sig = pins[idx]->elaborate_net(des, scope, - prts_pin_count, - 0, 0, 0); + desired_pin_count, + 0, 0, 0); if (sig == 0) { cerr << pins[idx]->get_line() << ": internal error: Port expression " @@ -707,10 +721,25 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const } #endif + /* If we are working with an instance array, then the + signal width must match the port width exactly. */ + if ((instance.count() != 1) + && (sig->pin_count() != prts_pin_count) + && (sig->pin_count() != prts_pin_count/instance.count())) { + cerr << pins[idx]->get_line() << ": error: " + << "Port expression width " << sig->pin_count() + << " does not match expected width " << prts_pin_count + << " or " << (prts_pin_count/instance.count()) + << "." << endl; + des->errors += 1; + continue; + } + // Check that the parts have matching pin counts. If // not, they are different widths. Note that idx is 0 // based, but users count parameter positions from 1. - if (prts_pin_count != sig->pin_count()) { + if ((instance.count() == 1) + && (prts_pin_count != sig->pin_count())) { cerr << get_line() << ": warning: Port " << (idx+1) << " (" << rmod->ports[idx]->name << ") of " << type_ << " expects " << prts_pin_count << @@ -741,9 +770,17 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const // Connect this many of the port pins. If the expression // is too small, the reduce the number of connects. unsigned ccount = prts_pin_count; - if (sig->pin_count() < ccount) + if (instance.count() == 1 && sig->pin_count() < ccount) ccount = sig->pin_count(); + // The spin_modulus is the width of the signal (not the + // port) if this is an instance array. This causes + // signals wide enough for a single instance to be + // connected to all the instances. + unsigned spin_modulus = prts_pin_count; + if (instance.count() != 1) + spin_modulus = sig->pin_count(); + // Now scan the concatenation that makes up the port, // connecting pins until we run out of port pins or sig // pins. @@ -754,7 +791,8 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const if (cnt > ccount) cnt = ccount; for (unsigned p = 0 ; p < cnt ; p += 1) { - connect(sig->pin(spin), prts[ldx-1]->pin(p)); + connect(sig->pin(spin%spin_modulus), + prts[ldx-1]->pin(p)); ccount -= 1; spin += 1; } @@ -766,6 +804,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const if (NetSubnet*tmp = dynamic_cast(sig)) delete tmp; } + } /* @@ -2720,6 +2759,9 @@ Design* elaborate(listroots) /* * $Log: elaborate.cc,v $ + * Revision 1.306 2004/09/05 17:44:41 steve + * Add support for module instance arrays. + * * Revision 1.305 2004/06/30 15:32:02 steve * Propagate source line number in synthetic delay statements. * diff --git a/main.cc b/main.cc index e2a85ad95..4858cf7c3 100644 --- a/main.cc +++ b/main.cc @@ -19,7 +19,7 @@ const char COPYRIGHT[] = * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: main.cc,v 1.82 2004/03/10 04:51:24 steve Exp $" +#ident "$Id: main.cc,v 1.83 2004/09/05 17:44:42 steve Exp $" #endif # include "config.h" @@ -106,6 +106,11 @@ bool warn_portbinding = false; bool error_implicit = false; +/* + * Debug message class flags. + */ +bool debug_scopes = false; + /* * Verbose messages enabled. */ @@ -228,6 +233,9 @@ static void parm_to_flagmap(const string&flag) * basedir: * Location to look for installed sub-components * + * debug: + * Activate a class of debug messages. + * * depfile: * Give the path to an output dependency file. * @@ -295,6 +303,13 @@ static void read_iconfig_file(const char*ipath) if (strcmp(buf, "basedir") == 0) { basedir = strdup(cp); + } else if (strcmp(buf, "debug") == 0) { + if (strcmp(cp, "scope") == 0) { + debug_scopes = true; + cerr << "debug: Enable scope debug" << endl; + } else { + } + } else if (strcmp(buf, "depfile") == 0) { depfile_name = strdup(cp); @@ -722,6 +737,9 @@ int main(int argc, char*argv[]) /* * $Log: main.cc,v $ + * Revision 1.83 2004/09/05 17:44:42 steve + * Add support for module instance arrays. + * * Revision 1.82 2004/03/10 04:51:24 steve * Add support for system function table files. * diff --git a/netlist.h b/netlist.h index bff391c3d..6d4884829 100644 --- a/netlist.h +++ b/netlist.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: netlist.h,v 1.318 2004/09/04 04:24:15 steve Exp $" +#ident "$Id: netlist.h,v 1.319 2004/09/05 17:44:42 steve Exp $" #endif /* @@ -3168,6 +3168,11 @@ class NetScope : public Attrib { mapparameters; maplocalparams; + /* Module instance arrays are collected here for access during + the multiple elaboration passes. */ + typedef svector scope_vec_t; + mapinstance_arrays; + private: TYPE type_; perm_string name_; @@ -3356,6 +3361,9 @@ extern ostream& operator << (ostream&, NetNet::Type); /* * $Log: netlist.h,v $ + * Revision 1.319 2004/09/05 17:44:42 steve + * Add support for module instance arrays. + * * Revision 1.318 2004/09/04 04:24:15 steve * PR1026: assignment statements can have sensitivities in the l-values. *