Module ports are really special PEIdent

expressions, because a name can be used
 many places in the port list.
This commit is contained in:
steve 2000-05-16 04:05:15 +00:00
parent addedf7231
commit 3676d66408
8 changed files with 226 additions and 82 deletions

View File

@ -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<Module::port_t*>*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<PWire*>& Module::get_port(unsigned idx) const
const svector<PEIdent*>& 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<PProcess*>& 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.
*

View File

@ -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 <list>
@ -29,6 +29,7 @@
# include <string>
class PEvent;
class PExpr;
class PEIdent;
class PGate;
class PTask;
class PFunction;
@ -53,9 +54,7 @@ class Module {
public:
struct port_t {
string name;
svector<PWire*>wires;
port_t(int c=0) : wires(c) { }
svector<PEIdent*> expr;
};
public:
@ -100,7 +99,7 @@ class Module {
void add_function(const string&name, PFunction*def);
unsigned port_count() const;
const svector<PWire*>& get_port(unsigned idx) const;
const svector<PEIdent*>& 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.
*

11
PExpr.h
View File

@ -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 <string>
@ -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.

View File

@ -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.
*

View File

@ -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<PWire*> mport = rmod->get_port(idx);
svector<PEIdent*> mport = rmod->get_port(idx);
svector<NetNet*>prts (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<string,Module*>&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.
*

95
parse.y
View File

@ -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<PEIdent*>(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<PEIdent*>(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<PEIdent*>(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<PEIdent*>(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<PWire*>(tmp->wires, $3->wires);
tmp->expr = svector<PEIdent*>(tmp->expr, $3->expr);
delete $3;
$$ = tmp;
}

View File

@ -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<string>*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<string,Module*>&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.
*

View File

@ -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.
*