From f001d0001af8d9a19e9e65817707dd4f0e786876 Mon Sep 17 00:00:00 2001 From: steve Date: Mon, 10 Apr 2006 00:37:42 +0000 Subject: [PATCH] Add support for generate loops w/ wires and gates. --- Makefile.in | 4 +- Module.h | 55 +++++------------- PGate.h | 13 +++-- PWire.h | 7 ++- design_dump.cc | 8 ++- elab_scope.cc | 112 ++++++++++++++++++++++++++++++++++- elab_sig.cc | 54 ++++++++++++++++- elaborate.cc | 47 ++++++++++++++- eval.cc | 15 ++++- ivl_target.h | 8 ++- lexor_keyword.gperf | 3 + netlist.h | 13 ++++- parse.y | 43 +++++++++++++- pform.cc | 138 ++++++++++++++++++++++++++++++++++++++++---- pform.h | 21 ++++++- pform_dump.cc | 98 ++++++++++++++++++++++++------- t-dll.cc | 9 ++- tgt-vvp/vvp_scope.c | 6 +- vvp/vpi_scope.cc | 27 ++++----- 19 files changed, 567 insertions(+), 114 deletions(-) diff --git a/Makefile.in b/Makefile.in index b3fa0c47d..27edfc8ed 100644 --- a/Makefile.in +++ b/Makefile.in @@ -16,7 +16,7 @@ # 59 Temple Place - Suite 330 # Boston, MA 02111-1307, USA # -#ident "$Id: Makefile.in,v 1.174 2006/02/15 18:42:42 steve Exp $" +#ident "$Id: Makefile.in,v 1.175 2006/04/10 00:37:42 steve Exp $" # # SHELL = /bin/sh @@ -111,7 +111,7 @@ parse.o parse_misc.o pform.o pform_dump.o \ set_width.o symbol_search.o sync.o sys_funcs.o \ verinum.o verireal.o target.o targets.o \ Attrib.o HName.o LineInfo.o Module.o PDelays.o PEvent.o \ -PExpr.o PGate.o \ +PExpr.o PGate.o PGenerate.o \ PTask.o PUdp.o PFunction.o PWire.o Statement.o StringHeap.o \ $(FF) $(TT) diff --git a/Module.h b/Module.h index 37d5f59aa..7c217b7dc 100644 --- a/Module.h +++ b/Module.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: Module.h,v 1.39 2006/03/30 01:49:07 steve Exp $" +#ident "$Id: Module.h,v 1.40 2006/04/10 00:37:42 steve Exp $" #endif # include @@ -34,6 +34,7 @@ class PEvent; class PExpr; class PEIdent; class PGate; +class PGenerate; class PTask; class PFunction; class PWire; @@ -113,6 +114,14 @@ class Module : public LineInfo { set by the `timescale directive. */ int time_unit, time_precision; + /* The module has a list of genvars that may be used in + various generate schemes. */ + list genvars; + + /* the module has a list of generate schemes that appear in + the module definition. These are used at elaboration time. */ + list generate_schemes; + perm_string mod_name() const { return name_; } void add_gate(PGate*gate); @@ -164,51 +173,13 @@ class Module : public LineInfo { /* * $Log: Module.h,v $ + * Revision 1.40 2006/04/10 00:37:42 steve + * Add support for generate loops w/ wires and gates. + * * Revision 1.39 2006/03/30 01:49:07 steve * Fix instance arrays indexed by overridden parameters. * * Revision 1.38 2005/07/11 16:56:50 steve * Remove NetVariable and ivl_variable_t structures. - * - * Revision 1.37 2004/06/13 04:56:53 steve - * Add support for the default_nettype directive. - * - * Revision 1.36 2004/05/25 19:21:06 steve - * More identifier lists use perm_strings. - * - * Revision 1.35 2004/02/20 18:53:33 steve - * Addtrbute keys are perm_strings. - * - * Revision 1.34 2004/02/20 06:22:56 steve - * parameter keys are per_strings. - * - * Revision 1.33 2004/02/18 17:11:54 steve - * Use perm_strings for named langiage items. - * - * Revision 1.32 2003/06/20 00:53:19 steve - * Module attributes from the parser - * through to elaborated form. - * - * Revision 1.31 2003/06/13 19:10:45 steve - * Properly manage real variables in subscopes. - * - * Revision 1.30 2003/03/06 04:37:12 steve - * lex_strings.add module names earlier. - * - * Revision 1.29 2003/02/27 06:45:11 steve - * specparams as far as pform. - * - * Revision 1.28 2003/01/26 21:15:58 steve - * Rework expression parsing and elaboration to - * accommodate real/realtime values and expressions. - * - * Revision 1.27 2002/08/19 02:39:16 steve - * Support parameters with defined ranges. - * - * Revision 1.26 2002/08/12 01:34:58 steve - * conditional ident string using autoconfig. - * - * Revision 1.25 2002/05/19 23:37:28 steve - * Parse port_declaration_lists from the 2001 Standard. */ #endif diff --git a/PGate.h b/PGate.h index 29f14aa8c..34f09dbb5 100644 --- a/PGate.h +++ b/PGate.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: PGate.h,v 1.31 2006/01/03 05:22:14 steve Exp $" +#ident "$Id: PGate.h,v 1.32 2006/04/10 00:37:42 steve Exp $" #endif # include "svector.h" @@ -94,7 +94,7 @@ class PGate : public LineInfo { map attributes; - virtual void dump(ostream&out) const; + virtual void dump(ostream&out, unsigned ind =4) const; virtual void elaborate(Design*des, NetScope*scope) const; virtual void elaborate_scope(Design*des, NetScope*sc) const; virtual bool elaborate_sig(Design*des, NetScope*scope) const; @@ -128,7 +128,7 @@ class PGAssign : public PGate { explicit PGAssign(svector*pins, svector*dels); ~PGAssign(); - void dump(ostream&out) const; + void dump(ostream&out, unsigned ind =4) const; virtual void elaborate(Design*des, NetScope*scope) const; private: @@ -165,7 +165,7 @@ class PGBuiltin : public PGate { Type type() const { return type_; } void set_range(PExpr*msb, PExpr*lsb); - virtual void dump(ostream&out) const; + virtual void dump(ostream&out, unsigned ind =4) const; virtual void elaborate(Design*, NetScope*scope) const; private: @@ -208,7 +208,7 @@ class PGModule : public PGate { // method to pass the range to the pform. void set_range(PExpr*msb, PExpr*lsb); - virtual void dump(ostream&out) const; + virtual void dump(ostream&out, unsigned ind =4) const; virtual void elaborate(Design*, NetScope*scope) const; virtual void elaborate_scope(Design*des, NetScope*sc) const; virtual bool elaborate_sig(Design*des, NetScope*scope) const; @@ -239,6 +239,9 @@ class PGModule : public PGate { /* * $Log: PGate.h,v $ + * Revision 1.32 2006/04/10 00:37:42 steve + * Add support for generate loops w/ wires and gates. + * * Revision 1.31 2006/01/03 05:22:14 steve * Handle complex net node delays. * diff --git a/PWire.h b/PWire.h index 398fe1f09..2ac181395 100644 --- a/PWire.h +++ b/PWire.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: PWire.h,v 1.18 2005/07/07 16:22:49 steve Exp $" +#ident "$Id: PWire.h,v 1.19 2006/04/10 00:37:42 steve Exp $" #endif # include "netlist.h" @@ -81,7 +81,7 @@ class PWire : public LineInfo { map attributes; // Write myself to the specified stream. - void dump(ostream&out) const; + void dump(ostream&out, unsigned ind=4) const; void elaborate_sig(Design*, NetScope*scope) const; @@ -110,6 +110,9 @@ class PWire : public LineInfo { /* * $Log: PWire.h,v $ + * Revision 1.19 2006/04/10 00:37:42 steve + * Add support for generate loops w/ wires and gates. + * * Revision 1.18 2005/07/07 16:22:49 steve * Generalize signals to carry types. * diff --git a/design_dump.cc b/design_dump.cc index 4d4c45b9e..353fbf18f 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: design_dump.cc,v 1.164 2006/02/02 02:43:57 steve Exp $" +#ident "$Id: design_dump.cc,v 1.165 2006/04/10 00:37:42 steve Exp $" #endif # include "config.h" @@ -811,6 +811,9 @@ void NetScope::dump(ostream&o) const case TASK: o << " task"; break; + case GENBLOCK: + o << " generate block"; + break; } o << endl; @@ -1170,6 +1173,9 @@ void Design::dump(ostream&o) const /* * $Log: design_dump.cc,v $ + * Revision 1.165 2006/04/10 00:37:42 steve + * Add support for generate loops w/ wires and gates. + * * Revision 1.164 2006/02/02 02:43:57 steve * Allow part selects of memory words in l-values. * diff --git a/elab_scope.cc b/elab_scope.cc index c468a040f..660a4a727 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.38 2006/03/30 01:49:07 steve Exp $" +#ident "$Id: elab_scope.cc,v 1.39 2006/04/10 00:37:42 steve Exp $" #endif # include "config.h" @@ -37,6 +37,7 @@ # include "PEvent.h" # include "PExpr.h" # include "PGate.h" +# include "PGenerate.h" # include "PTask.h" # include "PWire.h" # include "Statement.h" @@ -220,6 +221,17 @@ bool Module::elaborate_scope(Design*des, NetScope*scope, delete[]attr; + // Generate schemes can create new scopes in the form of + // generated code. Scan the generate schemes, and *generate* + // new scopes, which is slightly different from simple + // elaboration. + + typedef list::const_iterator generate_it_t; + for (generate_it_t cur = generate_schemes.begin() + ; cur != generate_schemes.end() ; cur ++ ) { + (*cur) -> generate_scope(des, scope); + } + // Tasks introduce new scopes, so scan the tasks in this // module. Create a scope for the task and pass that to the @@ -289,6 +301,101 @@ bool Module::elaborate_scope(Design*des, NetScope*scope, return des->errors == 0; } +bool PGenerate::generate_scope(Design*des, NetScope*container) +{ + switch (scheme_type) { + case GS_LOOP: + return generate_scope_loop_(des, container); + + default: + cerr << get_line() << ": sorry: Generate of this sort" + << " is not supported yet!" << endl; + return false; + } +} + +/* + * This is the elaborate scope method for a generate loop. + */ +bool PGenerate::generate_scope_loop_(Design*des, NetScope*container) +{ + // We're going to need a genvar... + int genvar; + + // The initial value for the genvar does not need (nor can it + // use) the genvar itself, so we can evaluate this expression + // the same way any other paramter value is evaluated. + NetExpr*init_ex = elab_and_eval(des, container, loop_init); + NetEConst*init = dynamic_cast (init_ex); + if (init == 0) { + cerr << get_line() << ": error: Cannot evaluate genvar" + << " init expression: " << *loop_init << endl; + des->errors += 1; + return false; + } + + genvar = init->value().as_long(); + delete init_ex; + + if (debug_elaborate) + cerr << get_line() << ": debug: genvar init = " << genvar << endl; + + container->genvar_tmp = loop_index; + container->genvar_tmp_val = 0; + verinum*test = loop_test->eval_const(des, container); + assert(test); + while (test->as_long()) { + + // The actual name of the scope includes the genvar so + // that each instance has a unique name in the + // container. The format of using [] is part of the + // Verilog standard. + char name_buf[128]; + snprintf(name_buf, sizeof name_buf, + "%s[%d]", scope_name.str(), genvar); + perm_string use_name = lex_strings.make(name_buf); + + if (debug_elaborate) + cerr << get_line() << ": debug: " + << "Create generated scope " << use_name << endl; + + NetScope*scope = new NetScope(container, use_name, + NetScope::GENBLOCK); + + // Set in the scope a localparam for the value of the + // genvar within this instance of the generate + // block. Code within this scope thus has access to the + // genvar as a constant. + { + verinum genvar_verinum(genvar); + genvar_verinum.has_sign(true); + NetEConstParam*gp = new NetEConstParam(scope, + loop_index, + genvar_verinum); + scope->set_localparam(loop_index, gp); + } + + scope_list_.push_back(scope); + + // Calculate the step for the loop variable. + verinum*step = loop_step->eval_const(des, container); + assert(step); + if (debug_elaborate) + cerr << get_line() << ": debug: genvar step from " + << genvar << " to " << step->as_long() << endl; + + genvar = step->as_long(); + container->genvar_tmp_val = genvar; + delete step; + delete test; + test = loop_test->eval_const(des, container); + } + + container->genvar_tmp = perm_string(); + + return true; +} + void PGModule::elaborate_scope_mod_(Design*des, Module*mod, NetScope*sc) const { if (get_name() == "") { @@ -635,6 +742,9 @@ void PWhile::elaborate_scope(Design*des, NetScope*scope) const /* * $Log: elab_scope.cc,v $ + * Revision 1.39 2006/04/10 00:37:42 steve + * Add support for generate loops w/ wires and gates. + * * Revision 1.38 2006/03/30 01:49:07 steve * Fix instance arrays indexed by overridden parameters. * diff --git a/elab_sig.cc b/elab_sig.cc index 978c5388a..38463355f 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.40 2005/07/11 16:56:50 steve Exp $" +#ident "$Id: elab_sig.cc,v 1.41 2006/04/10 00:37:42 steve Exp $" #endif # include "config.h" @@ -27,6 +27,7 @@ # include "Module.h" # include "PExpr.h" # include "PGate.h" +# include "PGenerate.h" # include "PTask.h" # include "PWire.h" # include "compiler.h" @@ -158,6 +159,16 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const des->errors += 1; } + } + + // Run through all the generate schemes to enaborate the + // signals that they hold. Note that the generate schemes hold + // the scopes that they instantiated, so we don't pass any + // scope in. + typedef list::const_iterator generate_it_t; + for (generate_it_t cur = generate_schemes.begin() + ; cur != generate_schemes.end() ; cur ++ ) { + (*cur) -> elaborate_sig(des); } // Get all the gates of the module and elaborate them by @@ -238,6 +249,44 @@ bool PGModule::elaborate_sig_mod_(Design*des, NetScope*scope, return flag; } +bool PGenerate::elaborate_sig(Design*des) const +{ + bool flag = true; + + typedef list::const_iterator scope_list_it_t; + for (scope_list_it_t cur = scope_list_.begin() + ; cur != scope_list_.end() ; cur ++ ) { + + if (debug_elaborate) + cerr << get_line() << ": debug: Elaborate nets in " + << "scope " << (*cur)->name() << endl; + flag = elaborate_sig_(des, *cur) & flag; + } + + return flag; +} + +bool PGenerate::elaborate_sig_(Design*des, NetScope*scope) const +{ + // Scan the declared PWires to elaborate the obvious signals + // in the current scope. + typedef map::const_iterator wires_it_t; + for (wires_it_t wt = wires.begin() + ; wt != wires.end() ; wt ++ ) { + + PWire*cur = (*wt).second; + + if (debug_elaborate) + cerr << get_line() << ": debug: Elaborate PWire " + << cur->path() << " in scope " << scope->name() << endl; + + cur->elaborate_sig(des, scope); + } + + return true; +} + + /* * A function definition exists within an elaborated module. This * matters when elaborating signals, as the ports of the function are @@ -671,6 +720,9 @@ void PWire::elaborate_sig(Design*des, NetScope*scope) const /* * $Log: elab_sig.cc,v $ + * Revision 1.41 2006/04/10 00:37:42 steve + * Add support for generate loops w/ wires and gates. + * * Revision 1.40 2005/07/11 16:56:50 steve * Remove NetVariable and ivl_variable_t structures. * diff --git a/elaborate.cc b/elaborate.cc index 90a07c622..770c06c00 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.335 2006/03/30 01:49:07 steve Exp $" +#ident "$Id: elaborate.cc,v 1.336 2006/04/10 00:37:42 steve Exp $" #endif # include "config.h" @@ -34,6 +34,7 @@ # include # include "pform.h" # include "PEvent.h" +# include "PGenerate.h" # include "netlist.h" # include "netmisc.h" # include "util.h" @@ -2846,6 +2847,12 @@ bool Module::elaborate(Design*des, NetScope*scope) const { bool result_flag = true; + // Elaborate within the generate blocks. + typedef list::const_iterator generate_it_t; + for (generate_it_t cur = generate_schemes.begin() + ; cur != generate_schemes.end() ; cur ++ ) { + (*cur)->elaborate(des); + } // Elaborate functions. typedef map::const_iterator mfunc_it_t; @@ -2966,6 +2973,35 @@ bool Module::elaborate(Design*des, NetScope*scope) const return result_flag; } +bool PGenerate::elaborate(Design*des) const +{ + bool flag = true; + + typedef list::const_iterator scope_list_it_t; + for (scope_list_it_t cur = scope_list_.begin() + ; cur != scope_list_.end() ; cur ++ ) { + + if (debug_elaborate) + cerr << get_line() << ": debug: Elaborate in " + << "scope " << (*cur)->name() << endl; + + flag = elaborate_(des, *cur) & flag; + } + + return flag; +} + +bool PGenerate::elaborate_(Design*des, NetScope*scope) const +{ + typedef list::const_iterator gates_it_t; + for (gates_it_t cur = gates.begin() ; cur != gates.end() ; cur ++ ) { + + (*cur)->elaborate(des, scope); + } + + return true; +} + struct root_elem { Module *mod; NetScope *scope; @@ -2981,6 +3017,7 @@ Design* elaborate(listroots) // module and elaborate what I find. Design*des = new Design; + // Scan the root modules, and elaborate their scopes. for (list::const_iterator root = roots.begin() ; root != roots.end() ; root++) { @@ -2996,6 +3033,7 @@ Design* elaborate(listroots) continue; } + // Get the module definition for this root instance. Module *rmod = (*mod).second; // Make the root scope. @@ -3006,7 +3044,9 @@ Design* elaborate(listroots) des->set_precision(rmod->time_precision); Module::replace_t stub; - // Recursively elaborate from this root scope down. + + // Recursively elaborate from this root scope down. This + // does a lot of the grunt work of creating sub-scopes, etc. if (! rmod->elaborate_scope(des, scope, stub)) { delete des; return 0; @@ -3071,6 +3111,9 @@ Design* elaborate(listroots) /* * $Log: elaborate.cc,v $ + * Revision 1.336 2006/04/10 00:37:42 steve + * Add support for generate loops w/ wires and gates. + * * Revision 1.335 2006/03/30 01:49:07 steve * Fix instance arrays indexed by overridden parameters. * diff --git a/eval.cc b/eval.cc index 202aec1de..0c861d334 100644 --- a/eval.cc +++ b/eval.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: eval.cc,v 1.39 2005/12/07 04:04:23 steve Exp $" +#ident "$Id: eval.cc,v 1.40 2006/04/10 00:37:42 steve Exp $" #endif # include "config.h" @@ -168,11 +168,19 @@ verinum* PEConcat::eval_const(const Design*des, NetScope*scope) const verinum* PEIdent::eval_const(const Design*des, NetScope*scope) const { assert(scope); - //const NetExpr*expr = des->find_parameter(scope, path_); NetNet*net; NetMemory*mem; NetEvent*eve; const NetExpr*expr; + + // Handle the special case that this ident is a genvar + // variable name. In that case, the genvar meaning preempts + // everything and we just return that value immediately. + if (scope->genvar_tmp + && strcmp(path_.peek_tail_name(),scope->genvar_tmp) == 0) { + return new verinum(scope->genvar_tmp_val); + } + NetScope*found_in = symbol_search(des, scope, path_, net, mem, expr, eve); @@ -263,6 +271,9 @@ verinum* PEUnary::eval_const(const Design*des, NetScope*scope) const /* * $Log: eval.cc,v $ + * Revision 1.40 2006/04/10 00:37:42 steve + * Add support for generate loops w/ wires and gates. + * * Revision 1.39 2005/12/07 04:04:23 steve * Allow constant concat expressions. * diff --git a/ivl_target.h b/ivl_target.h index 0e5ee9ccd..b641a5957 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: ivl_target.h,v 1.165 2006/02/02 02:43:58 steve Exp $" +#ident "$Id: ivl_target.h,v 1.166 2006/04/10 00:37:42 steve Exp $" #endif #ifdef __cplusplus @@ -266,7 +266,8 @@ typedef enum ivl_scope_type_e { IVL_SCT_FUNCTION= 1, IVL_SCT_TASK = 2, IVL_SCT_BEGIN = 3, - IVL_SCT_FORK = 4 + IVL_SCT_FORK = 4, + IVL_SCT_GENERATE= 5 } ivl_scope_type_t; /* Signals (ivl_signal_t) that are ports into the scope that contains @@ -1707,6 +1708,9 @@ _END_DECL /* * $Log: ivl_target.h,v $ + * Revision 1.166 2006/04/10 00:37:42 steve + * Add support for generate loops w/ wires and gates. + * * Revision 1.165 2006/02/02 02:43:58 steve * Allow part selects of memory words in l-values. * diff --git a/lexor_keyword.gperf b/lexor_keyword.gperf index f45d9ba99..556859e7c 100644 --- a/lexor_keyword.gperf +++ b/lexor_keyword.gperf @@ -31,6 +31,7 @@ else, K_else end, K_end endcase, K_endcase endfunction, K_endfunction +endgenerate, K_endgenerate endmodule, K_endmodule endprimitive, K_endprimitive endspecify, K_endspecify @@ -42,6 +43,8 @@ force, K_force forever, K_forever fork, K_fork function, K_function +generate, K_generate +genvar, K_genvar highz0, K_highz0 highz1, K_highz1 if, K_if diff --git a/netlist.h b/netlist.h index d434e1bf7..164779a54 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.356 2006/03/18 22:53:04 steve Exp $" +#ident "$Id: netlist.h,v 1.357 2006/04/10 00:37:42 steve Exp $" #endif /* @@ -3137,7 +3137,7 @@ class NetESignal : public NetExpr { class NetScope : public Attrib { public: - enum TYPE { MODULE, TASK, FUNC, BEGIN_END, FORK_JOIN }; + enum TYPE { MODULE, TASK, FUNC, BEGIN_END, FORK_JOIN, GENBLOCK }; /* Create a new scope, and attach it to the given parent. The name is expected to have been permallocated. */ @@ -3281,6 +3281,12 @@ class NetScope : public Attrib { typedef svector scope_vec_t; mapinstance_arrays; + /* Loop generate uses this as scratch space during + elaboration. Expression evaluation can use this to match + names. */ + perm_string genvar_tmp; + long genvar_tmp_val; + private: TYPE type_; perm_string name_; @@ -3458,6 +3464,9 @@ extern ostream& operator << (ostream&, NetNet::Type); /* * $Log: netlist.h,v $ + * Revision 1.357 2006/04/10 00:37:42 steve + * Add support for generate loops w/ wires and gates. + * * Revision 1.356 2006/03/18 22:53:04 steve * Properly handle signedness in compare. * diff --git a/parse.y b/parse.y index 8393b4a88..ba9add9d0 100644 --- a/parse.y +++ b/parse.y @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: parse.y,v 1.212 2006/03/30 05:22:34 steve Exp $" +#ident "$Id: parse.y,v 1.213 2006/04/10 00:37:42 steve Exp $" #endif # include "config.h" @@ -137,9 +137,10 @@ const static struct str_pair_t str_strength = { PGate::STRONG, PGate::STRONG }; %token K_LOR K_LAND K_NAND K_NOR K_NXOR K_TRIGGER %token K_always K_and K_assign K_begin K_bool K_buf K_bufif0 K_bufif1 K_case %token K_casex K_casez K_cmos K_deassign K_default K_defparam K_disable -%token K_edge K_else K_end K_endcase K_endfunction K_endmodule +%token K_edge K_else K_end K_endcase K_endfunction K_endgenerate K_endmodule %token K_endprimitive K_endspecify K_endtable K_endtask K_event K_for -%token K_force K_forever K_fork K_function K_highz0 K_highz1 K_if +%token K_force K_forever K_fork K_function K_generate K_genvar +%token K_highz0 K_highz1 K_if %token K_initial K_inout K_input K_integer K_join K_large K_localparam %token K_logic K_macromodule %token K_medium K_module K_nand K_negedge K_nmos K_nor K_not K_notif0 @@ -1807,6 +1808,27 @@ module_item delete $3; } + /* A generate region can contain further module items. Actually, it + is supposed to be limited to certain kinds of module items, but + the semantic tests will check that for us. */ + + | K_generate module_item_list_opt K_endgenerate + + | K_genvar list_of_identifiers ';' + { pform_genvars($2); } + + | K_for '(' IDENTIFIER '=' expression ';' + expression ';' + IDENTIFIER '=' expression ')' + { pform_start_generate_for(@1, $3, $5, $7, $9, $11); } + generate_block + { pform_endgenerate(); } + + | K_if '(' expression ')' generate_block_opt K_else generate_block + { yyerror(@1, "sorry: Condition generate not supported yet."); + } + + /* specify blocks are parsed but ignored. */ | K_specify K_endspecify @@ -1873,6 +1895,21 @@ module_item_list_opt | ; + /* A generate block is the thing within a generate scheme. It may be + a single module item, an anonymous block of module items, or a + named module item. In all cases, the meat is in the module items + inside, and the processing is done by the module_item rules. We + only need to take note here of the scope name, if any. */ + +generate_block + : module_item + | K_begin module_item_list_opt K_end + | K_begin ':' IDENTIFIER module_item_list_opt K_end + { pform_generate_block_name($3); } + ; + +generate_block_opt : generate_block | ; + /* A net declaration assignment allows the programmer to combine the net declaration and the continuous assignment into a single diff --git a/pform.cc b/pform.cc index 17aa1cb21..4204a06ef 100644 --- a/pform.cc +++ b/pform.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: pform.cc,v 1.134 2006/03/30 05:22:34 steve Exp $" +#ident "$Id: pform.cc,v 1.135 2006/04/10 00:37:42 steve Exp $" #endif # include "config.h" @@ -28,6 +28,7 @@ # include "parse_api.h" # include "PEvent.h" # include "PUdp.h" +# include "PGenerate.h" # include # include # include @@ -44,7 +45,17 @@ string vl_file = ""; extern int VLparse(); + /* This tracks the current module being processed. There can only be + exactly one module currently being parsed, since verilog does not + allow nested module definitions. */ static Module*pform_cur_module = 0; + /* increment this for generate schemes within a module, and set it + to zero when a new module starts. */ +static unsigned scope_generate_counter = 1; + + /* This tracks the current generate scheme being processed. This is + always within a module. */ +static PGenerate*pform_cur_generate = 0; static NetNet::Type pform_default_nettype = NetNet::WIRE; @@ -63,10 +74,13 @@ static unsigned pform_timescale_line = 0; * of scope. As I enter a scope, the push function is called, and as I * leave a scope the pop function is called. Entering tasks, functions * and named blocks causes scope to be pushed and popped. The module - * name is not included it this scope stack. + * name is not included in this scope stack. * - * The hier_name function, therefore, returns the name path of a - * function relative the current function. + * The hier_name function, therefore, converts the name to the scope + * of the module currently in progress. + * + * The scope stack does not include any scope created by a generate + * scheme. */ static hname_t scope_stack; @@ -90,6 +104,18 @@ static hname_t hier_name(const char*tail) return name; } +static PWire*get_wire_in_module(const hname_t&name) +{ + /* Note that if we are processing a generate, then the + scope depth will be empty because generate schemes + cannot be within sub-scopes. Only directly in + modules. */ + if (pform_cur_generate) + return pform_cur_generate->get_wire(name); + + return pform_cur_module->get_wire(name); +} + void pform_set_default_nettype(NetNet::Type type, const char*file, unsigned lineno) { @@ -216,6 +242,10 @@ void pform_startmodule(const char*name, const char*file, unsigned lineno, pform_cur_module->set_file(file); pform_cur_module->set_lineno(lineno); + /* The generate scheme numbering starts with *1*, not + zero. That's just the way it is, thanks to the standard. */ + scope_generate_counter = 1; + if (warn_timescale && pform_timescale_file && (strcmp(pform_timescale_file,file) != 0)) { @@ -292,6 +322,58 @@ void pform_endmodule(const char*name) pform_cur_module = 0; } +void pform_genvars(list*names) +{ + list::const_iterator cur; + for (cur = names->begin(); cur != names->end() ; *cur++) { + pform_cur_module->genvars.push_back( *cur ); + } + + delete names; +} + +void pform_start_generate_for(const struct vlltype&li, + char*ident1, PExpr*init, + PExpr*test, + char*ident2, PExpr*next) +{ + PGenerate*gen = new PGenerate(scope_generate_counter++); + + gen->set_file(li.text); + gen->set_lineno(li.first_line); + + // For now, assume that generates do not nest. + assert(pform_cur_generate == 0); + pform_cur_generate = gen; + + pform_cur_generate->scheme_type = PGenerate::GS_LOOP; + + pform_cur_generate->loop_index = lex_strings.make(ident1); + pform_cur_generate->loop_init = init; + pform_cur_generate->loop_test = test; + pform_cur_generate->loop_step = next; + + delete[]ident1; + delete[]ident2; +} + +void pform_generate_block_name(char*name) +{ + assert(pform_cur_generate != 0); + assert(pform_cur_generate->scope_name == 0); + pform_cur_generate->scope_name = lex_strings.make(name); + delete[]name; +} + +void pform_endgenerate() +{ + assert(pform_cur_generate != 0); + assert(pform_cur_module); + + pform_cur_module->generate_schemes.push_back(pform_cur_generate); + pform_cur_generate = 0; +} + bool pform_expression_is_constant(const PExpr*ex) { return ex->is_constant(pform_cur_module); @@ -695,8 +777,7 @@ static void pform_set_net_range(const char* name, bool signed_flag, ivl_variable_type_t dt) { - - PWire*cur = pform_cur_module->get_wire(hier_name(name)); + PWire*cur = get_wire_in_module(hier_name(name)); if (cur == 0) { VLerror("error: name is not a valid net."); return; @@ -796,7 +877,10 @@ void pform_makegate(PGBuiltin::Type type, cur->set_file(info.file); cur->set_lineno(info.lineno); - pform_cur_module->add_gate(cur); + if (pform_cur_generate) + pform_cur_generate->add_gate(cur); + else + pform_cur_module->add_gate(cur); } void pform_makegates(PGBuiltin::Type type, @@ -854,7 +938,10 @@ static void pform_make_modgate(perm_string type, cur->set_parameters(overrides->by_order); } - pform_cur_module->add_gate(cur); + if (pform_cur_generate) + pform_cur_generate->add_gate(cur); + else + pform_cur_module->add_gate(cur); } static void pform_make_modgate(perm_string type, @@ -956,7 +1043,11 @@ static PGAssign* pform_make_pgassign(PExpr*lval, PExpr*rval, cur->strength0(str.str0); cur->strength1(str.str1); - pform_cur_module->add_gate(cur); + if (pform_cur_generate) + pform_cur_generate->add_gate(cur); + else + pform_cur_module->add_gate(cur); + return cur; } @@ -1089,13 +1180,22 @@ void pform_module_define_port(const struct vlltype&li, * do check to see if the name has already been declared, as this * function is called for every declaration. */ + +/* + * this is the basic form of pform_makwire. This takes a single simple + * name, port type, net type, data type, and attributes, and creates + * the variable/net. Other forms of pform_makewire ultimately call + * this one to create the wire and stash it. + */ void pform_makewire(const vlltype&li, const char*nm, NetNet::Type type, NetNet::PortType pt, ivl_variable_type_t dt, svector*attr) { hname_t name = hier_name(nm); - PWire*cur = pform_cur_module->get_wire(name); + + PWire*cur = get_wire_in_module(name); + if (cur) { if ((cur->get_wire_type() != NetNet::IMPLICIT) && (cur->get_wire_type() != NetNet::IMPLICIT_REG)) { @@ -1130,9 +1230,17 @@ void pform_makewire(const vlltype&li, const char*nm, } } - pform_cur_module->add_wire(cur); + if (pform_cur_generate) + pform_cur_generate->add_wire(cur); + else + pform_cur_module->add_wire(cur); } +/* + * This form takes a list of names and some type information, and + * generates a bunch of variables/nets. We hse the basic + * pform_makewire above. + */ void pform_makewire(const vlltype&li, svector*range, bool signed_flag, @@ -1155,6 +1263,9 @@ void pform_makewire(const vlltype&li, delete range; } +/* + * This form makes nets with delays and continuous assignments. + */ void pform_makewire(const vlltype&li, svector*range, bool signed_flag, @@ -1174,7 +1285,7 @@ void pform_makewire(const vlltype&li, pform_set_net_range(first->name, range, signed_flag, dt); hname_t name = hier_name(first->name); - PWire*cur = pform_cur_module->get_wire(name); + PWire*cur = get_wire_in_module(name); if (cur != 0) { PEIdent*lval = new PEIdent(hname_t(first->name)); lval->set_file(li.text); @@ -1596,6 +1707,9 @@ int pform_parse(const char*path, FILE*file) /* * $Log: pform.cc,v $ + * Revision 1.135 2006/04/10 00:37:42 steve + * Add support for generate loops w/ wires and gates. + * * Revision 1.134 2006/03/30 05:22:34 steve * task/function ports can have types. * diff --git a/pform.h b/pform.h index b9138a09b..de10c243b 100644 --- a/pform.h +++ b/pform.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: pform.h,v 1.85 2006/03/30 05:22:34 steve Exp $" +#ident "$Id: pform.h,v 1.86 2006/04/10 00:37:42 steve Exp $" #endif # include "netlist.h" @@ -167,6 +167,22 @@ extern void pform_pop_scope(); extern verinum* pform_verinum_with_size(verinum*s, verinum*val, const char*file, unsigned loneno); +/* + * This function takes the list of names as new genvars to declare in + * the current module scope. + */ +extern void pform_genvars(list*names); + +extern void pform_start_generate_for(const struct vlltype&li, + char*ident1, + PExpr*init, + PExpr*test, + char*ident2, + PExpr*next); +extern void pform_generate_block_name(char*name); +extern void pform_endgenerate(); + + /* * The makewire functions announce to the pform code new wires. These * go into a module that is currently opened. @@ -307,6 +323,9 @@ extern void pform_dump(ostream&out, Module*mod); /* * $Log: pform.h,v $ + * Revision 1.86 2006/04/10 00:37:42 steve + * Add support for generate loops w/ wires and gates. + * * Revision 1.85 2006/03/30 05:22:34 steve * task/function ports can have types. * diff --git a/pform_dump.cc b/pform_dump.cc index ad9a7404a..b7377011f 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2004 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2006 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: pform_dump.cc,v 1.91 2005/10/04 04:09:26 steve Exp $" +#ident "$Id: pform_dump.cc,v 1.92 2006/04/10 00:37:42 steve Exp $" #endif # include "config.h" @@ -30,6 +30,7 @@ */ # include "pform.h" # include "PEvent.h" +# include "PGenerate.h" # include # include # include @@ -211,9 +212,9 @@ void PEBinary::dump(ostream&out) const } -void PWire::dump(ostream&out) const +void PWire::dump(ostream&out, unsigned ind) const { - out << " " << type_; + out << setw(ind) << "" << type_; switch (port_type_) { case NetNet::PIMPLICIT: @@ -303,9 +304,9 @@ void PGate::dump_delays(ostream&out) const delay_.dump_delays(out); } -void PGate::dump(ostream&out) const +void PGate::dump(ostream&out, unsigned ind) const { - out << " " << typeid(*this).name() << " "; + out << setw(ind) << "" << typeid(*this).name() << " "; delay_.dump_delays(out); out << " " << get_name() << "("; dump_pins(out); @@ -313,45 +314,47 @@ void PGate::dump(ostream&out) const } -void PGAssign::dump(ostream&out) const +void PGAssign::dump(ostream&out, unsigned ind) const { - out << " assign (" << strength0() << "0 " << strength1() << "1) "; + out << setw(ind) << ""; + out << "assign (" << strength0() << "0 " << strength1() << "1) "; dump_delays(out); out << " " << *pin(0) << " = " << *pin(1) << ";" << endl; } -void PGBuiltin::dump(ostream&out) const +void PGBuiltin::dump(ostream&out, unsigned ind) const { + out << setw(ind) << ""; switch (type()) { case PGBuiltin::BUFIF0: - out << " bufif0 "; + out << "bufif0 "; break; case PGBuiltin::BUFIF1: - out << " bufif1 "; + out << "bufif1 "; break; case PGBuiltin::NOTIF0: - out << " bufif0 "; + out << "bufif0 "; break; case PGBuiltin::NOTIF1: - out << " bufif1 "; + out << "bufif1 "; break; case PGBuiltin::NAND: - out << " nand "; + out << "nand "; break; case PGBuiltin::NMOS: - out << " nmos "; + out << "nmos "; break; case PGBuiltin::RNMOS: - out << " rnmos "; + out << "rnmos "; break; case PGBuiltin::RPMOS: - out << " rpmos "; + out << "rpmos "; break; case PGBuiltin::PMOS: - out << " pmos "; + out << "pmos "; break; default: - out << " builtin gate "; + out << "builtin gate "; } out << "(" << strength0() << "0 " << strength1() << "1) "; @@ -367,9 +370,9 @@ void PGBuiltin::dump(ostream&out) const out << ");" << endl; } -void PGModule::dump(ostream&out) const +void PGModule::dump(ostream&out, unsigned ind) const { - out << " " << type_ << " "; + out << setw(ind) << "" << type_ << " "; // If parameters are overridden by order, dump them. if (overrides_) { @@ -731,6 +734,44 @@ void PProcess::dump(ostream&out, unsigned ind) const statement_->dump(out, ind+2); } +void PGenerate::dump(ostream&out) const +{ + out << " generate(" << id_number << ")"; + + switch (scheme_type) { + case GS_NONE: + break; + case GS_LOOP: + out << " for (" + << loop_index + << "=" << *loop_init + << "; " << *loop_test + << "; " << loop_index + << "=" << *loop_step << ")"; + break; + case GS_CONDIT: + break; + } + + if (scope_name) + out << " : " << scope_name; + + out << endl; + + for (map::const_iterator idx = wires.begin() + ; idx != wires.end() ; idx++) { + + (*idx).second->dump(out, 6); + } + + for (list::const_iterator idx = gates.begin() + ; idx != gates.end() ; idx++) { + (*idx)->dump(out, 6); + } + + out << " endgenerate" << endl; +} + void Module::dump(ostream&out) const { if (attributes.begin() != attributes.end()) { @@ -796,6 +837,18 @@ void Module::dump(ostream&out) const out << "/* ERROR */;" << endl; } + typedef list::const_iterator genvar_iter_t; + for (genvar_iter_t cur = genvars.begin() + ; cur != genvars.end() ; cur++) { + out << " genvar " << (*cur) << ";" << endl; + } + + typedef list::const_iterator genscheme_iter_t; + for (genscheme_iter_t cur = generate_schemes.begin() + ; cur != generate_schemes.end() ; cur++) { + (*cur)->dump(out); + } + typedef map::const_iterator specparm_iter_t; for (specparm_iter_t cur = specparams.begin() ; cur != specparams.end() ; cur ++) { @@ -914,6 +967,9 @@ void PUdp::dump(ostream&out) const /* * $Log: pform_dump.cc,v $ + * Revision 1.92 2006/04/10 00:37:42 steve + * Add support for generate loops w/ wires and gates. + * * Revision 1.91 2005/10/04 04:09:26 steve * Add support for indexed select attached to parameters. * diff --git a/t-dll.cc b/t-dll.cc index 34fa463d8..f90768a1e 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: t-dll.cc,v 1.155 2006/01/02 05:33:19 steve Exp $" +#ident "$Id: t-dll.cc,v 1.156 2006/04/10 00:37:42 steve Exp $" #endif # include "config.h" @@ -2018,6 +2018,10 @@ void dll_target::scope(const NetScope*net) scope->type_ = IVL_SCT_FORK; scope->tname_ = scope->name_; break; + case NetScope::GENBLOCK: + scope->type_ = IVL_SCT_GENERATE; + scope->tname_ = scope->name_; + break; } assert(scope->parent != 0); @@ -2163,6 +2167,9 @@ extern const struct target tgt_dll = { "dll", &dll_target_obj }; /* * $Log: t-dll.cc,v $ + * Revision 1.156 2006/04/10 00:37:42 steve + * Add support for generate loops w/ wires and gates. + * * Revision 1.155 2006/01/02 05:33:19 steve * Node delays can be more general expressions in structural contexts. * diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index c712286ef..27a92c39f 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: vvp_scope.c,v 1.142 2006/03/18 22:53:38 steve Exp $" +#ident "$Id: vvp_scope.c,v 1.143 2006/04/10 00:37:42 steve Exp $" #endif # include "vvp_priv.h" @@ -2107,6 +2107,7 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent) case IVL_SCT_TASK: type = "task"; break; case IVL_SCT_BEGIN: type = "begin"; break; case IVL_SCT_FORK: type = "fork"; break; + case IVL_SCT_GENERATE: type = "generate"; break; default: type = "?"; assert(0); } @@ -2204,6 +2205,9 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent) /* * $Log: vvp_scope.c,v $ + * Revision 1.143 2006/04/10 00:37:42 steve + * Add support for generate loops w/ wires and gates. + * * Revision 1.142 2006/03/18 22:53:38 steve * Support more parameter syntax. * diff --git a/vvp/vpi_scope.cc b/vvp/vpi_scope.cc index 109d26062..13bf3d27d 100644 --- a/vvp/vpi_scope.cc +++ b/vvp/vpi_scope.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: vpi_scope.cc,v 1.35 2006/03/06 05:43:15 steve Exp $" +#ident "$Id: vpi_scope.cc,v 1.36 2006/04/10 00:37:43 steve Exp $" #endif # include "compile.h" @@ -292,23 +292,21 @@ compile_scope_decl(char*label, char*type, char*name, char*tname, char*parent) struct __vpiScope*scope = new struct __vpiScope; count_vpi_scopes += 1; - switch(type[2]) { - case 'd': /* type == moDule */ + if (strcmp(type,"module") == 0) scope->base.vpi_type = &vpip_scope_module_rt; - break; - case 'n': /* type == fuNction */ + else if (strcmp(type,"function") == 0) scope->base.vpi_type = &vpip_scope_function_rt; - break; - case 's': /* type == taSk */ + else if (strcmp(type,"task") == 0) scope->base.vpi_type = &vpip_scope_task_rt; - break; - case 'r': /* type == foRk */ + else if (strcmp(type,"fork") == 0) scope->base.vpi_type = &vpip_scope_fork_rt; - break; - case 'g': /* type == beGin */ + else if (strcmp(type,"begin") == 0) scope->base.vpi_type = &vpip_scope_begin_rt; - break; - default: + else if (strcmp(type,"generate") == 0) + // Generate blocks are not really modules, but this is a + // hack that will work for now. + scope->base.vpi_type = &vpip_scope_module_rt; + else { scope->base.vpi_type = &vpip_scope_module_rt; assert(0); } @@ -389,6 +387,9 @@ void vpip_attach_to_current_scope(vpiHandle obj) /* * $Log: vpi_scope.cc,v $ + * Revision 1.36 2006/04/10 00:37:43 steve + * Add support for generate loops w/ wires and gates. + * * Revision 1.35 2006/03/06 05:43:15 steve * Cleanup vpi_const to use vec4 values. *