From 3676d664083472c70a89b8f397e128320966164f Mon Sep 17 00:00:00 2001 From: steve Date: Tue, 16 May 2000 04:05:15 +0000 Subject: [PATCH] Module ports are really special PEIdent expressions, because a name can be used many places in the port list. --- Module.cc | 32 +++++------------ Module.h | 14 +++++--- PExpr.h | 11 +++++- elab_net.cc | 86 +++++++++++++++++++++++++++++++++++++++++++++- elaborate.cc | 20 ++++++++--- parse.y | 95 ++++++++++++++++++++++++++++++++++++++------------- pform.cc | 14 +++++--- pform_dump.cc | 36 ++++++++----------- 8 files changed, 226 insertions(+), 82 deletions(-) diff --git a/Module.cc b/Module.cc index d2936a897..488320b99 100644 --- a/Module.cc +++ b/Module.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) && !defined(macintosh) -#ident "$Id: Module.cc,v 1.11 2000/03/12 17:09:40 steve Exp $" +#ident "$Id: Module.cc,v 1.12 2000/05/16 04:05:15 steve Exp $" #endif # include "Module.h" @@ -28,28 +28,9 @@ Module::Module(const string&name, const svector*pp) : name_(name) { - if (pp) { - // Save the list of ports, then scan the list to make - // the implicit wires. Add those wires to the wire map. + if (pp) ports_ = *pp; - for (unsigned idx = 0 ; idx < ports_.count() ; idx += 1) { - port_t*cur = ports_[idx]; - if (cur == 0) - continue; - // The port can actually be a list of wires, to - // remember to scan the set. Also note the case - // where a wire may be connected to multiple - // ports, and reuse the link if that happens. - for (unsigned jdx = 0; jdx < cur->wires.count(); jdx += 1) { - PWire*tmp = add_wire(cur->wires[jdx]); - if (tmp != cur->wires[jdx]) { - delete cur->wires[jdx]; - cur->wires[jdx] = tmp; - } - } - } - } } void Module::add_gate(PGate*gate) @@ -87,10 +68,10 @@ unsigned Module::port_count() const return ports_.count(); } -const svector& Module::get_port(unsigned idx) const +const svector& Module::get_port(unsigned idx) const { assert(idx < ports_.count()); - return ports_[idx]->wires; + return ports_[idx]->expr; } unsigned Module::find_port(const string&name) const @@ -144,6 +125,11 @@ const list& Module::get_behaviors() const /* * $Log: Module.cc,v $ + * Revision 1.12 2000/05/16 04:05:15 steve + * Module ports are really special PEIdent + * expressions, because a name can be used + * many places in the port list. + * * Revision 1.11 2000/03/12 17:09:40 steve * Support localparam. * diff --git a/Module.h b/Module.h index a4c3229b9..e95a3f387 100644 --- a/Module.h +++ b/Module.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) && !defined(macintosh) -#ident "$Id: Module.h,v 1.18 2000/05/02 16:27:38 steve Exp $" +#ident "$Id: Module.h,v 1.19 2000/05/16 04:05:15 steve Exp $" #endif # include @@ -29,6 +29,7 @@ # include class PEvent; class PExpr; +class PEIdent; class PGate; class PTask; class PFunction; @@ -53,9 +54,7 @@ class Module { public: struct port_t { string name; - svectorwires; - - port_t(int c=0) : wires(c) { } + svector expr; }; public: @@ -100,7 +99,7 @@ class Module { void add_function(const string&name, PFunction*def); unsigned port_count() const; - const svector& get_port(unsigned idx) const; + const svector& get_port(unsigned idx) const; unsigned find_port(const string&) const; // Find a wire by name. This is used for connecting gates to @@ -137,6 +136,11 @@ class Module { /* * $Log: Module.h,v $ + * Revision 1.19 2000/05/16 04:05:15 steve + * Module ports are really special PEIdent + * expressions, because a name can be used + * many places in the port list. + * * Revision 1.18 2000/05/02 16:27:38 steve * Move signal elaboration to a seperate pass. * diff --git a/PExpr.h b/PExpr.h index 49aef8c2e..152298a72 100644 --- a/PExpr.h +++ b/PExpr.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) && !defined(macintosh) -#ident "$Id: PExpr.h,v 1.37 2000/05/07 04:37:56 steve Exp $" +#ident "$Id: PExpr.h,v 1.38 2000/05/16 04:05:15 steve Exp $" #endif # include @@ -171,6 +171,10 @@ class PEIdent : public PExpr { virtual NetExpr*elaborate_expr(Design*des, NetScope*) const; virtual NetExpr*elaborate_pexpr(Design*des, NetScope*sc) const; + // Elaborate the PEIdent as a port to a module. This method + // only applies to Ident expressions. + NetNet* elaborate_port(Design*des, NetScope*sc) const; + virtual bool is_constant(Module*) const; verinum* eval_const(const Design*des, const string&path) const; @@ -375,6 +379,11 @@ class PECallFunction : public PExpr { /* * $Log: PExpr.h,v $ + * Revision 1.38 2000/05/16 04:05:15 steve + * Module ports are really special PEIdent + * expressions, because a name can be used + * many places in the port list. + * * Revision 1.37 2000/05/07 04:37:56 steve * Carry strength values from Verilog source to the * pform and netlist for gates. diff --git a/elab_net.cc b/elab_net.cc index 0552735d3..c7673203d 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) && !defined(macintosh) -#ident "$Id: elab_net.cc,v 1.36 2000/05/07 20:48:14 steve Exp $" +#ident "$Id: elab_net.cc,v 1.37 2000/05/16 04:05:15 steve Exp $" #endif # include "PExpr.h" @@ -1158,6 +1158,85 @@ NetNet* PEIdent::elaborate_lnet(Design*des, const string&path) const return sig; } +/* + * This method is used to elaborate identifiers that are ports to a + * scope. The scope is presumed to be that of the module that has the + * port. + */ +NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const +{ + const string path = scope->name(); + + NetNet*sig = des->find_signal(scope, text_); + if (sig == 0) { + cerr << get_line() << ": error: no wire/reg " << text_ + << " in module " << scope->name() << "." << endl; + des->errors += 1; + return 0; + } + + + if (msb_ && lsb_) { + /* Detect a part select. Evaluate the bits and elaborate + the l-value by creating a sub-net that links to just + the right pins. */ + verinum*mval = msb_->eval_const(des, path); + assert(mval); + verinum*lval = lsb_->eval_const(des, path); + assert(lval); + unsigned midx = sig->sb_to_idx(mval->as_long()); + unsigned lidx = sig->sb_to_idx(lval->as_long()); + + if (midx >= lidx) { + NetTmp*tmp = new NetTmp(scope, des->local_symbol(path), + midx-lidx+1); + if (tmp->pin_count() > sig->pin_count()) { + cerr << get_line() << ": bit select out of " + << "range for " << sig->name() << endl; + return sig; + } + + for (unsigned idx = lidx ; idx <= midx ; idx += 1) + connect(tmp->pin(idx-lidx), sig->pin(idx)); + + sig = tmp; + + } else { + NetTmp*tmp = new NetTmp(scope, des->local_symbol(path), + lidx-midx+1); + assert(tmp->pin_count() <= sig->pin_count()); + for (unsigned idx = lidx ; idx >= midx ; idx -= 1) + connect(tmp->pin(idx-midx), sig->pin(idx)); + + sig = tmp; + } + + } else if (msb_) { + verinum*mval = msb_->eval_const(des, path); + if (mval == 0) { + cerr << get_line() << ": index of " << text_ << + " needs to be constant in this context." << + endl; + des->errors += 1; + return 0; + } + assert(mval); + unsigned idx = sig->sb_to_idx(mval->as_long()); + if (idx >= sig->pin_count()) { + cerr << get_line() << "; index " << sig->name() << + "[" << mval->as_long() << "] out of range." << endl; + des->errors += 1; + idx = 0; + } + NetTmp*tmp = new NetTmp(scope, des->local_symbol(path), 1); + connect(tmp->pin(0), sig->pin(idx)); + sig = tmp; + } + + return sig; +} + + /* * Elaborate a number as a NetConst object. */ @@ -1480,6 +1559,11 @@ NetNet* PEUnary::elaborate_net(Design*des, const string&path, /* * $Log: elab_net.cc,v $ + * Revision 1.37 2000/05/16 04:05:15 steve + * Module ports are really special PEIdent + * expressions, because a name can be used + * many places in the port list. + * * Revision 1.36 2000/05/07 20:48:14 steve * Properly elaborate repeat concatenations. * diff --git a/elaborate.cc b/elaborate.cc index 8d68a8355..ce03e2e15 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) && !defined(macintosh) -#ident "$Id: elaborate.cc,v 1.172 2000/05/11 23:37:27 steve Exp $" +#ident "$Id: elaborate.cc,v 1.173 2000/05/16 04:05:16 steve Exp $" #endif /* @@ -414,13 +414,20 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, const string&path) const // Inside the module, the port is one or more signals, // that were already elaborated. List all those signals, // and I will connect them up later. - svector mport = rmod->get_port(idx); + svector mport = rmod->get_port(idx); svectorprts (mport.count()); unsigned prts_pin_count = 0; for (unsigned ldx = 0 ; ldx < mport.count() ; ldx += 1) { - PWire*pport = mport[ldx]; - prts[ldx] = des->find_signal(my_scope, pport->name()); + PEIdent*pport = mport[ldx]; + prts[ldx] = pport->elaborate_port(des, my_scope); + if (prts[ldx] == 0) { + cerr << pport->get_line() << ": internal error: " + << "Failed to elaborate port expr: " + << *pport << endl; + des->errors += 1; + continue; + } assert(prts[ldx]); prts_pin_count += prts[ldx]->pin_count(); } @@ -2422,6 +2429,11 @@ Design* elaborate(const map&modules, /* * $Log: elaborate.cc,v $ + * Revision 1.173 2000/05/16 04:05:16 steve + * Module ports are really special PEIdent + * expressions, because a name can be used + * many places in the port list. + * * Revision 1.172 2000/05/11 23:37:27 steve * Add support for procedural continuous assignment. * diff --git a/parse.y b/parse.y index 275052dd0..17e1f3a65 100644 --- a/parse.y +++ b/parse.y @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) && !defined(macintosh) -#ident "$Id: parse.y,v 1.96 2000/05/11 23:37:27 steve Exp $" +#ident "$Id: parse.y,v 1.97 2000/05/16 04:05:16 steve Exp $" #endif # include "parse_misc.h" @@ -1478,9 +1478,10 @@ parameter_value_byname_list } ; + /* The port (of a module) is a fairly complex item. Each port is handled as a Module::port_t object. A simple port reference has a - name and a PWire object, but more complex constructs are possible + name and a PExpr object, but more complex constructs are possible where the name can be attached to a list of PWire objects. The port_reference returns a Module::port_t, and so does the @@ -1494,17 +1495,32 @@ parameter_value_byname_list port : port_reference { $$ = $1; } + + /* This syntax attaches an external name to the port reference so + that the caller can bind by name to non-trivial port + references. The port_t object gets its PWire from the + port_reference, but its name from the PORTNAME. */ + | PORTNAME '(' port_reference ')' { Module::port_t*tmp = $3; tmp->name = $1; delete $1; $$ = tmp; } + + /* A port can also be a concatenation of port references. In this + case the port does not have a name available to the outside, only + positional parameter passing is possible here. */ + | '{' port_reference_list '}' { Module::port_t*tmp = $2; tmp->name = ""; $$ = tmp; } + + /* This attaches a name to a port reference contatenation list so + that parameter passing be name is possible. */ + | PORTNAME '(' '{' port_reference_list '}' ')' { Module::port_t*tmp = $4; tmp->name = $1; @@ -1518,58 +1534,91 @@ port_opt | { $$ = 0; } ; + + /* A port reference is an internal (to the module) name of the port, + possibly with a part of bit select to attach it to specific bits + of a signal fully declared inside the module. + + The parser creates a PEIdent for every port reference, even if the + signal is bound to different ports. The elaboration figures out + the mess that this creates. The port_reference (and the + port_reference_list below) puts the port reference PEIdent into the + port_t object to pass it up to the module declaration code. */ + port_reference + : IDENTIFIER - { Module::port_t*ptmp = new Module::port_t(1); - PWire*wtmp = new PWire($1, NetNet::IMPLICIT, - NetNet::PIMPLICIT); - wtmp->set_file(@1.text); - wtmp->set_lineno(@1.first_line); + { Module::port_t*ptmp = new Module::port_t; + PEIdent*tmp = new PEIdent($1); + tmp->set_file(@1.text); + tmp->set_lineno(@1.first_line); ptmp->name = $1; - ptmp->wires[0] = wtmp; + ptmp->expr = svector(1); + ptmp->expr[0] = tmp; delete $1; $$ = ptmp; } + | IDENTIFIER '[' expression ':' expression ']' - { PWire*wtmp = new PWire($1, NetNet::IMPLICIT, - NetNet::PIMPLICIT); + { PEIdent*wtmp = new PEIdent($1); wtmp->set_file(@1.text); wtmp->set_lineno(@1.first_line); if (!pform_expression_is_constant($3)) { - yyerror(@3, "error: msb expression of port bit select " - "must be constant."); + yyerror(@3, "error: msb expression of " + "port part select must be constant."); } if (!pform_expression_is_constant($5)) { - yyerror(@5, "error: lsb expression of port bit select " - "must be constant."); + yyerror(@5, "error: lsb expression of " + "port part select must be constant."); } - wtmp->set_range($3, $5); - Module::port_t*ptmp = new Module::port_t(1); - ptmp->name = $1; - ptmp->wires[0] = wtmp; + wtmp->msb_ = $3; + wtmp->lsb_ = $5; + Module::port_t*ptmp = new Module::port_t; + ptmp->name = ""; + ptmp->expr = svector(1); + ptmp->expr[0] = wtmp; delete $1; $$ = ptmp; } + + | IDENTIFIER '[' expression ']' + { PEIdent*tmp = new PEIdent($1); + tmp->set_file(@1.text); + tmp->set_lineno(@1.first_line); + if (!pform_expression_is_constant($3)) { + yyerror(@3, "error: port bit select " + "must be constant."); + } + tmp->msb_ = $3; + Module::port_t*ptmp = new Module::port_t; + ptmp->name = ""; + ptmp->expr = svector(1); + ptmp->expr[0] = tmp; + delete $1; + $$ = ptmp; + } + | IDENTIFIER '[' error ']' { yyerror(@1, "error: invalid port bit select"); - Module::port_t*ptmp = new Module::port_t(1); - PWire*wtmp = new PWire($1, NetNet::IMPLICIT, - NetNet::PIMPLICIT); + Module::port_t*ptmp = new Module::port_t; + PEIdent*wtmp = new PEIdent($1); wtmp->set_file(@1.text); wtmp->set_lineno(@1.first_line); ptmp->name = $1; - ptmp->wires[0] = wtmp; + ptmp->expr = svector(1); + ptmp->expr[0] = wtmp; delete $1; $$ = ptmp; } ; + port_reference_list : port_reference { $$ = $1; } | port_reference_list ',' port_reference { Module::port_t*tmp = $1; - tmp->wires = svector(tmp->wires, $3->wires); + tmp->expr = svector(tmp->expr, $3->expr); delete $3; $$ = tmp; } diff --git a/pform.cc b/pform.cc index 9aaeaec6c..53cfa817c 100644 --- a/pform.cc +++ b/pform.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) && !defined(macintosh) -#ident "$Id: pform.cc,v 1.59 2000/05/08 05:30:20 steve Exp $" +#ident "$Id: pform.cc,v 1.60 2000/05/16 04:05:16 steve Exp $" #endif # include "compiler.h" @@ -567,12 +567,13 @@ void pform_makewire(const vlltype&li, const list*names, } -void pform_set_port_type(const string&name, NetNet::PortType pt) +void pform_set_port_type(const string&nm, NetNet::PortType pt) { + const string name = scoped_name(nm); PWire*cur = pform_cur_module->get_wire(name); if (cur == 0) { - VLerror("name is not a port."); - return; + cur = new PWire(name, NetNet::IMPLICIT, pt); + pform_cur_module->add_wire(cur); } if (! cur->set_port_type(pt)) @@ -864,6 +865,11 @@ int pform_parse(const char*path, map&modules, /* * $Log: pform.cc,v $ + * Revision 1.60 2000/05/16 04:05:16 steve + * Module ports are really special PEIdent + * expressions, because a name can be used + * many places in the port list. + * * Revision 1.59 2000/05/08 05:30:20 steve * Deliver gate output strengths to the netlist. * diff --git a/pform_dump.cc b/pform_dump.cc index 13429ec89..b8ad64e9d 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) && !defined(macintosh) -#ident "$Id: pform_dump.cc,v 1.58 2000/05/11 23:37:27 steve Exp $" +#ident "$Id: pform_dump.cc,v 1.59 2000/05/16 04:05:16 steve Exp $" #endif /* @@ -211,9 +211,13 @@ void PWire::dump(ostream&out) const break; } + assert(msb_.count() == lsb_.count()); for (unsigned idx = 0 ; idx < msb_.count() ; idx += 1) { - assert(lsb_[idx] && msb_[idx]); - out << " [" << *msb_[idx] << ":" << *lsb_[idx] << "]"; + assert(msb_[idx]); + if (lsb_[idx]) + out << " [" << *msb_[idx] << ":" << *lsb_[idx] << "]"; + else + out << " [" << *msb_[idx] << "]"; } out << " " << name_; @@ -634,24 +638,9 @@ void Module::dump(ostream&out) const continue; } - switch (cur->wires[0]->get_port_type()) { - case NetNet::PINPUT: - out << " input ." << cur->name << "("; - break; - case NetNet::POUTPUT: - out << " output ." << cur->name << "("; - break; - case NetNet::PINOUT: - out << " inout ." << cur->name << "("; - break; - default: - out << " XXXX ." << cur->name << "("; - break; - } - - out << cur->wires[0]->name(); - for (unsigned wdx = 1 ; wdx < cur->wires.count() ; wdx += 1) { - out << ", " << cur->wires[wdx]->name(); + out << " ." << cur->name << "(" << *cur->expr[0]; + for (unsigned wdx = 1 ; wdx < cur->expr.count() ; wdx += 1) { + out << ", " << *cur->expr[wdx]; } out << ")" << endl; @@ -785,6 +774,11 @@ void PUdp::dump(ostream&out) const /* * $Log: pform_dump.cc,v $ + * Revision 1.59 2000/05/16 04:05:16 steve + * Module ports are really special PEIdent + * expressions, because a name can be used + * many places in the port list. + * * Revision 1.58 2000/05/11 23:37:27 steve * Add support for procedural continuous assignment. *