Use PartSelect/PV and VP to handle part selects through ports.

This commit is contained in:
steve 2005-01-09 20:16:00 +00:00
parent 6c711ee4d8
commit 9e94afe399
12 changed files with 475 additions and 310 deletions

View File

@ -19,7 +19,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: PExpr.h,v 1.67 2004/12/29 23:55:43 steve Exp $"
#ident "$Id: PExpr.h,v 1.68 2005/01/09 20:16:00 steve Exp $"
#endif
# include <string>
@ -276,6 +276,9 @@ class PEIdent : public PExpr {
NetAssign_* elaborate_mem_lval_(Design*des, NetScope*scope,
NetMemory*mem) const;
bool eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
unsigned&midx, unsigned&lidx) const;
};
class PENumber : public PExpr {
@ -503,6 +506,9 @@ class PECallFunction : public PExpr {
/*
* $Log: PExpr.h,v $
* Revision 1.68 2005/01/09 20:16:00 steve
* Use PartSelect/PV and VP to handle part selects through ports.
*
* Revision 1.67 2004/12/29 23:55:43 steve
* Unify elaboration of l-values for all proceedural assignments,
* including assing, cassign and force.

View File

@ -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.151 2004/12/29 23:55:43 steve Exp $"
#ident "$Id: design_dump.cc,v 1.152 2005/01/09 20:16:00 steve Exp $"
#endif
# include "config.h"
@ -356,7 +356,19 @@ void NetModulo::dump_node(ostream&o, unsigned ind) const
void NetPartSelect::dump_node(ostream&o, unsigned ind) const
{
o << setw(ind) << "" << "NetPartSelect: "
const char*pt = "";
switch (dir_) {
case VP:
pt = "VP";
break;
case PV:
pt = "PV";
break;
case BI:
pt = "BI";
break;
}
o << setw(ind) << "" << "NetPartSelect(" << pt << "): "
<< name() << " off=" << off_ << " wid=" << wid_ <<endl;
dump_node_pins(o, ind+4);
dump_obj_attr(o, ind+4);
@ -1097,6 +1109,9 @@ void Design::dump(ostream&o) const
/*
* $Log: design_dump.cc,v $
* Revision 1.152 2005/01/09 20:16:00 steve
* Use PartSelect/PV and VP to handle part selects through ports.
*
* Revision 1.151 2004/12/29 23:55:43 steve
* Unify elaboration of l-values for all proceedural assignments,
* including assing, cassign and force.

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: elab_net.cc,v 1.139 2004/12/11 02:31:25 steve Exp $"
#ident "$Id: elab_net.cc,v 1.140 2005/01/09 20:16:00 steve Exp $"
#endif
# include "config.h"
@ -1557,76 +1557,33 @@ NetNet* PEIdent::elaborate_net(Design*des, NetScope*scope,
assert(sig);
if (msb_ && lsb_) {
/* Catch the case of a non-constant bit select. That should be
handled elsewhere. */
if (msb_ && !lsb_) {
verinum*mval = msb_->eval_const(des, scope);
if (mval == 0) {
cerr << msb_->get_line() << ": error: unable to "
"evaluate constant MSB expression: " << *msb_ <<
endl;
des->errors += 1;
return 0;
return elaborate_net_bitmux_(des, scope, sig, rise,
fall, decay, drive0, drive1);
}
verinum*lval = lsb_->eval_const(des, scope);
if (lval == 0) {
cerr << lsb_->get_line() << ": error: unable to "
"evaluate constant LSB expression: " << *lsb_ <<
endl;
delete mval;
des->errors += 1;
return 0;
}
delete mval;
}
assert(mval);
assert(lval);
unsigned midx, lidx;
if (! eval_part_select_(des, scope, sig, midx, lidx))
return 0;
long mbit = mval->as_long();
long lbit = lval->as_long();
/* Check that the part select is valid. Both ends of the
constant part select must be within the range of the
signal for the part select to be correct. */
if (! (sig->sb_is_valid(mbit) && sig->sb_is_valid(lbit))) {
cerr << get_line() << ": error: bit/part select ["
<< mbit << ":" << lbit
<< "] out of range for " << sig->name() << endl;
des->errors += 1;
return sig;
}
unsigned midx = sig->sb_to_idx(mbit);
unsigned lidx = sig->sb_to_idx(lbit);
/* This is a part select, create a new NetNet object
that connects to just the desired parts of the
identifier. Make sure the NetNet::Type is compatible
with the sig type.
Be careful to check the bit ordering. If the msb is
less significant then the msb, then the source is
broken. I can hack it in order to go on, but report
an error. */
if (midx < lidx) {
cerr << get_line() << ": error: part select "
<< sig->name() << "[" << mval->as_long() << ":"
<< lval->as_long() << "] "
<< "has bit order reversed." << endl;
des->errors += 1;
unsigned tmp = midx;
midx = lidx;
lidx = tmp;
}
unsigned part_count = midx-lidx+1;
unsigned part_count = midx-lidx+1;
if (part_count != sig->vector_width()) {
if (debug_elaborate) {
cerr << get_line() << ": debug: Elaborate part select "
<< sig->name() << "["<<mbit<<":"<<lbit<<"]" << endl;
<< sig->name() << "[base="<<lidx
<< " wid=" << part_count << "]" << endl;
}
NetPartSelect*ps = new NetPartSelect(sig, lidx, part_count);
NetPartSelect*ps = new NetPartSelect(sig, lidx, part_count,
NetPartSelect::VP);
ps->set_line(*sig);
des->add_node(ps);
@ -1636,48 +1593,9 @@ NetNet* PEIdent::elaborate_net(Design*des, NetScope*scope,
connect(tmp->pin(0), ps->pin(0));
sig = tmp;
} else if (msb_) {
verinum*mval = msb_->eval_const(des, scope);
if (mval == 0) {
return elaborate_net_bitmux_(des, scope, sig, rise,
fall, decay, drive0, drive1);
}
assert(mval);
long mbit = mval->as_long();
/* Check that the part select is valid. Both ends of the
constant part select must be within the range of the
signal for the part select to be correct. */
if (! sig->sb_is_valid(mbit)) {
cerr << get_line() << ": error: bit/part select ["
<< mbit
<< "] out of range for " << sig->name() << endl;
des->errors += 1;
return sig;
}
unsigned midx = sig->sb_to_idx(mbit);
if (debug_elaborate) {
cerr << get_line() << ": debug: Elaborate part select "
<< sig->name() << "["<<mval->as_long()<<"]" << endl;
}
NetPartSelect*ps = new NetPartSelect(sig, midx, 1);
ps->set_line(*sig);
des->add_node(ps);
NetNet*tmp = new NetNet(scope, scope->local_symbol(),
NetNet::WIRE, 1, 0);
tmp->local_flag(true);
connect(tmp->pin(0), ps->pin(0));
sig = tmp;
}
return sig;
}
@ -1804,7 +1722,8 @@ NetNet* PEConcat::elaborate_lnet(Design*des, NetScope*scope,
for (unsigned idx = 0 ; idx < nets.count() ; idx += 1) {
unsigned wid = nets[idx]->vector_width();
unsigned off = width - wid;
NetPartSelect*ps = new NetPartSelect(osig, off, wid);
NetPartSelect*ps = new NetPartSelect(osig, off, wid,
NetPartSelect::VP);
des->add_node(ps);
connect(ps->pin(1), osig->pin(0));
@ -1819,6 +1738,79 @@ NetNet* PEConcat::elaborate_lnet(Design*des, NetScope*scope,
return osig;
}
/*
* This private method evaluates the part selects (if any) for the
* signal. The sig argument is the NetNet already located for the
* PEIdent name. The midx and lidx arguments are loaded with the
* results, which may be the whole vector, or a single bit, or
* anything in between. The values are in canonical indices.
*/
bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
unsigned&midx, unsigned&lidx) const
{
if (msb_ && lsb_) {
verinum*mval = msb_->eval_const(des, scope);
assert(mval);
verinum*lval = lsb_->eval_const(des, scope);
assert(lval);
midx = sig->sb_to_idx(mval->as_long());
lidx = sig->sb_to_idx(lval->as_long());
/* Detect reversed indices of a part select. */
if (lidx > midx) {
cerr << get_line() << ": error: Part select "
<< sig->name() << "[" << mval->as_long() << ":"
<< lval->as_long() << "] indices reversed." << endl;
cerr << get_line() << ": : Did you mean "
<< sig->name() << "[" << lval->as_long() << ":"
<< mval->as_long() << "]?" << endl;
unsigned tmp = midx;
midx = lidx;
lidx = tmp;
des->errors += 1;
}
/* Detect a part select out of range. */
if (midx >= sig->vector_width()) {
cerr << get_line() << ": error: Part select "
<< sig->name() << "[" << mval->as_long() << ":"
<< lval->as_long() << "] out of range." << endl;
midx = sig->vector_width() - 1;
lidx = 0;
des->errors += 1;
}
} else if (msb_) {
verinum*mval = msb_->eval_const(des, scope);
if (mval == 0) {
cerr << get_line() << ": index of " << path_ <<
" needs to be constant in this context." <<
endl;
des->errors += 1;
return false;
}
assert(mval);
midx = sig->sb_to_idx(mval->as_long());
if (midx >= sig->vector_width()) {
cerr << get_line() << ": error: Index " << sig->name()
<< "[" << mval->as_long() << "] out of range."
<< endl;
des->errors += 1;
midx = 0;
}
lidx = midx;
} else {
assert(msb_ == 0 && lsb_ == 0);
midx = sig->vector_width() - 1;
lidx = 0;
}
return true;
}
/*
* Identifiers in continuous assignment l-values are limited to wires
* and that ilk. Detect registers and memories here and report errors.
@ -1895,65 +1887,37 @@ NetNet* PEIdent::elaborate_lnet(Design*des, NetScope*scope,
sig->port_type(NetNet::PINOUT);
}
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, scope);
assert(mval);
verinum*lval = lsb_->eval_const(des, scope);
assert(lval);
unsigned midx = sig->sb_to_idx(mval->as_long());
unsigned lidx = sig->sb_to_idx(lval->as_long());
unsigned midx, lidx;
if (! eval_part_select_(des, scope, sig, midx, lidx))
return 0;
if (midx >= lidx) {
unsigned subnet_wid = midx-lidx+1;
if (subnet_wid > sig->pin_count()) {
cerr << get_line() << ": bit select out of "
<< "range for " << sig->name() << endl;
return sig;
}
unsigned subnet_wid = midx-lidx+1;
NetSubnet*tmp = new NetSubnet(sig, lidx, subnet_wid);
/* If the desired l-value vector is narrower then the
signal itself, then use a NetPartSelect node to
arrange for connection to the desired bits. All this
can be skipped if the desired with matches the
original vector. */
sig = tmp;
if (subnet_wid != sig->vector_width()) {
if (debug_elaborate)
cerr << get_line() << ": debug: "
<< "Elaborate lnet part select "
<< sig->name()
<< "[base=" << lidx
<< " wid=" << subnet_wid <<"]"
<< endl;
} else {
unsigned subnet_wid = midx-lidx+1;
NetNet*subsig = new NetNet(sig->scope(),
sig->scope()->local_symbol(),
NetNet::WIRE, subnet_wid);
if (subnet_wid > sig->pin_count()) {
cerr << get_line() << ": error: "
<< "part select out of range for "
<< sig->name() << "." << endl;
des->errors += 1;
return sig;
}
NetPartSelect*sub = new NetPartSelect(sig, lidx, subnet_wid,
NetPartSelect::PV);
des->add_node(sub);
connect(sub->pin(0), subsig->pin(0));
NetSubnet*tmp = new NetSubnet(sig, lidx, subnet_wid);
sig = tmp;
}
} else if (msb_) {
verinum*mval = msb_->eval_const(des, scope);
if (mval == 0) {
cerr << get_line() << ": error: index of " << path_ <<
" needs to be constant in l-value of assignment." <<
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;
}
NetSubnet*tmp = new NetSubnet(sig, idx, 1);
sig = tmp;
sig = subsig;
}
return sig;
@ -1962,7 +1926,10 @@ NetNet* PEIdent::elaborate_lnet(Design*des, NetScope*scope,
/*
* 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.
* port. This elaboration is done inside the module, and is only done
* to PEIdent objects. This method is used by elaboration of a module
* instantiation (PGModule::elaborate_mod_) to get NetNet objects for
* the port.
*/
NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const
{
@ -1974,6 +1941,8 @@ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const
return 0;
}
/* Check the port_type of the signal to make sure it is really
a port, and its direction is resolved. */
switch (sig->port_type()) {
case NetNet::PINPUT:
case NetNet::POUTPUT:
@ -2004,64 +1973,22 @@ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const
return 0;
}
unsigned midx;
unsigned lidx;
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, scope);
assert(mval);
verinum*lval = lsb_->eval_const(des, scope);
assert(lval);
unsigned midx = sig->sb_to_idx(mval->as_long());
unsigned lidx = sig->sb_to_idx(lval->as_long());
/* Evaluate the part/bit select expressions, to get the part
select of the signal that attaches to the port. Also handle
range and direction checking here. */
if (midx >= lidx) {
unsigned part_count = midx-lidx+1;
if (part_count > sig->pin_count()) {
cerr << get_line() << ": bit select out of "
<< "range for " << sig->name() << endl;
return sig;
}
if (! eval_part_select_(des, scope, sig, midx, lidx))
return 0;
NetSubnet*tmp = new NetSubnet(sig, lidx, part_count);
for (unsigned idx = lidx ; idx <= midx ; idx += 1)
connect(tmp->pin(idx-lidx), sig->pin(idx));
sig = tmp;
unsigned swid = midx - lidx + 1;
} else {
/* XXXX Signals reversed?? */
unsigned part_count = lidx-midx+1;
assert(part_count <= sig->pin_count());
NetSubnet*tmp = new NetSubnet(sig, midx, part_count);
for (unsigned idx = midx ; idx >= lidx ; idx -= 1)
connect(tmp->pin(idx-midx), sig->pin(idx));
sig = tmp;
}
} else if (msb_) {
verinum*mval = msb_->eval_const(des, scope);
if (mval == 0) {
cerr << get_line() << ": index of " << path_ <<
" needs to be constant in port 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;
}
NetSubnet*tmp = new NetSubnet(sig, idx, 1);
connect(tmp->pin(0), sig->pin(idx));
sig = tmp;
if (swid < sig->vector_width()) {
cerr << get_line() << ": XXXX: Forgot to implement part select"
<< " of signal port." << endl;
}
return sig;
@ -2560,6 +2487,9 @@ NetNet* PEUnary::elaborate_net(Design*des, NetScope*scope,
/*
* $Log: elab_net.cc,v $
* Revision 1.140 2005/01/09 20:16:00 steve
* Use PartSelect/PV and VP to handle part selects through ports.
*
* Revision 1.139 2004/12/11 02:31:25 steve
* Rework of internals to carry vectors through nexus instead
* of single bits. Make the ivl, tgt-vvp and vvp initial changes

View File

@ -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.312 2004/12/29 23:55:43 steve Exp $"
#ident "$Id: elaborate.cc,v 1.313 2005/01/09 20:16:01 steve Exp $"
#endif
# include "config.h"
@ -312,7 +312,7 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
instance_width = count;
count = 1;
if (debug_elaborate)
if (debug_elaborate && instance_width != 1)
cerr << get_line() << ": debug: PGBuiltin: "
"Collapsed gate array into single wide "
"(" << instance_width << ") instance." << endl;
@ -507,7 +507,8 @@ void PGBuiltin::elaborate(Design*des, NetScope*scope) const
} else for (unsigned gdx = 0 ; gdx < count ; gdx += 1) {
/* Use part selects to get the bits
connected to the inputs of out gate. */
NetPartSelect*tmp1 = new NetPartSelect(sig, gdx, 1);
NetPartSelect*tmp1 = new NetPartSelect(sig, gdx, 1,
NetPartSelect::VP);
tmp1->set_line(*this);
des->add_node(tmp1);
connect(tmp1->pin(1), sig->pin(0));
@ -603,7 +604,7 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
} else {
/* Otherwise, this is a positional list of fort
/* Otherwise, this is a positional list of port
connections. In this case, the port count must be
right. Check that is is, the get the pin list. */
@ -685,8 +686,8 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
svector<PEIdent*> mport = rmod->get_port(idx);
svector<NetNet*>prts (mport.count() * instance.count());
// Count the internal pins of the port.
unsigned prts_pin_count = 0;
// Count the internal vector bits of the port.
unsigned prts_vector_width = 0;
for (unsigned inst = 0 ; inst < instance.count() ; inst += 1) {
NetScope*inst_scope = instance[inst];
@ -702,21 +703,21 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
continue;
assert(prts[lbase + ldx]);
prts_pin_count += prts[lbase + ldx]->pin_count();
prts_vector_width += prts[lbase + ldx]->vector_width();
}
}
// If I find that the port in unconnected inside the
// If I find that the port is unconnected inside the
// module, then there is nothing to connect. Skip the
// argument.
if (prts_pin_count == 0) {
if (prts_vector_width == 0) {
continue;
}
// 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);
assert(prts_vector_width % instance.count() == 0);
// Elaborate the expression that connects to the
// module[s] port. sig is the thing outside the module
@ -744,12 +745,12 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
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;
unsigned desired_vector_width = prts_vector_width;
if (instance.count() != 1)
desired_pin_count = 0;
desired_vector_width = 0;
sig = pins[idx]->elaborate_net(des, scope,
desired_pin_count,
desired_vector_width,
0, 0, 0);
if (sig == 0) {
cerr << pins[idx]->get_line()
@ -771,12 +772,12 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
/* 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())) {
&& (sig->vector_width() != prts_vector_width)
&& (sig->vector_width() != prts_vector_width/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())
<< "Port expression width " << sig->vector_width()
<< " does not match expected width "<< prts_vector_width
<< " or " << (prts_vector_width/instance.count())
<< "." << endl;
des->errors += 1;
continue;
@ -786,20 +787,20 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
// not, they are different widths. Note that idx is 0
// based, but users count parameter positions from 1.
if ((instance.count() == 1)
&& (prts_pin_count != sig->pin_count())) {
&& (prts_vector_width != sig->vector_width())) {
cerr << get_line() << ": warning: Port " << (idx+1)
<< " (" << rmod->ports[idx]->name << ") of "
<< type_ << " expects " << prts_pin_count <<
" bits, got " << sig->pin_count() << "." << endl;
<< type_ << " expects " << prts_vector_width <<
" bits, got " << sig->vector_width() << "." << endl;
if (prts_pin_count > sig->pin_count()) {
if (prts_vector_width > sig->vector_width()) {
cerr << get_line() << ": : Leaving "
<< (prts_pin_count-sig->pin_count())
<< (prts_vector_width-sig->vector_width())
<< " high bits of the port unconnected."
<< endl;
} else {
cerr << get_line() << ": : Leaving "
<< (sig->pin_count()-prts_pin_count)
<< (sig->vector_width()-prts_vector_width)
<< " high bits of the expression dangling."
<< endl;
}
@ -815,41 +816,85 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
// the number of connections to make.
// 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 (instance.count() == 1 && sig->pin_count() < ccount)
ccount = sig->pin_count();
// is too small, then reduce the number of connects.
unsigned ccount = prts_vector_width;
if (instance.count() == 1 && sig->vector_width() < ccount)
ccount = sig->vector_width();
// 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;
unsigned spin_modulus = prts_vector_width;
if (instance.count() != 1)
spin_modulus = sig->pin_count();
spin_modulus = sig->vector_width();
// Now scan the concatenation that makes up the port,
// connecting pins until we run out of port pins or sig
// pins.
// pins. The sig object is the NetNet that is connected
// to the port from the outside, and the prts object is
// an array of signals to be connected to the sig.
NetConcat*ctmp;
unsigned spin = 0;
for (unsigned ldx = prts.count() ; ldx > 0 ; ldx -= 1) {
unsigned cnt = prts[ldx-1]->pin_count();
if (cnt > ccount)
cnt = ccount;
for (unsigned p = 0 ; p < cnt ; p += 1) {
connect(sig->pin(spin%spin_modulus),
prts[ldx-1]->pin(p));
ccount -= 1;
spin += 1;
if (prts.count() == 1) {
// The simplest case, there are no
// parts/concatenations on the inside of the
// module, so the port and sig need simply be
// connected directly.
connect(prts[0]->pin(0), sig->pin(0));
} else if (sig->vector_width() == prts_vector_width/instance.count()) {
// The signal width is exactly the width of a
// single instance of the port. In this case,
// connect the sig to all the ports identically.
for (unsigned ldx = 0 ; ldx < prts.count() ; ldx += 1)
connect(prts[ldx]->pin(0), sig->pin(0));
} else switch (prts[0]->port_type()) {
case NetNet::POUTPUT:
ctmp = new NetConcat(scope, scope->local_symbol(),
prts_vector_width,
prts.count());
des->add_node(ctmp);
connect(ctmp->pin(0), sig->pin(0));
for (unsigned ldx = 0 ; ldx < prts.count() ; ldx += 1) {
connect(ctmp->pin(ldx+1),
prts[prts.count()-ldx-1]->pin(0));
}
if (ccount == 0)
break;
break;
case NetNet::PINPUT:
for (unsigned ldx = 0 ; ldx < prts.count() ; ldx += 1) {
NetNet*sp = prts[prts.count()-ldx-1];
NetPartSelect*ptmp = new NetPartSelect(sig, spin,
sp->vector_width(),
NetPartSelect::VP);
des->add_node(ptmp);
connect(ptmp->pin(0), sp->pin(0));
spin += sp->vector_width();
}
break;
case NetNet::PINOUT:
cerr << get_line() << ": XXXX: "
<< "Forgot how to bind input ports!" << endl;
des->errors += 1;
break;
case NetNet::PIMPLICIT:
cerr << get_line() << ": internal error: "
<< "Unexpected IMPLICIT port" << endl;
des->errors += 1;
break;
case NetNet::NOT_A_PORT:
cerr << get_line() << ": internal error: "
<< "Unexpected NOT_A_PORT port." << endl;
des->errors += 1;
break;
}
if (NetSubnet*tmp = dynamic_cast<NetSubnet*>(sig))
delete tmp;
}
}
@ -2845,6 +2890,9 @@ Design* elaborate(list<perm_string>roots)
/*
* $Log: elaborate.cc,v $
* Revision 1.313 2005/01/09 20:16:01 steve
* Use PartSelect/PV and VP to handle part selects through ports.
*
* Revision 1.312 2004/12/29 23:55:43 steve
* Unify elaboration of l-values for all proceedural assignments,
* including assing, cassign and force.

View File

@ -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.130 2004/12/29 23:55:43 steve Exp $"
#ident "$Id: ivl_target.h,v 1.131 2005/01/09 20:16:01 steve Exp $"
#endif
#ifdef __cplusplus
@ -232,7 +232,8 @@ typedef enum ivl_lpm_type_e {
IVL_LPM_MOD = 13,
IVL_LPM_MULT = 4,
IVL_LPM_MUX = 5,
IVL_LPM_PART = 15, /* part select */
IVL_LPM_PART_VP= 15, /* part select: vector to part */
IVL_LPM_PART_PV= 17, /* part select: part written to vector */
IVL_LPM_SHIFTL = 6,
IVL_LPM_SHIFTR = 7,
IVL_LPM_SUB = 8,
@ -733,6 +734,25 @@ extern const char* ivl_udp_name(ivl_udp_t net);
* The ivl_lpm_data function returns the connections for the inputs to
* the concatentation. The ivl_lpm_size function returns the number of
* inputs help by the device.
*
* - Part Select (IVL_LPM_PART_VP and IVL_LPM_PART_PV)
* There are two part select devices, one that extracts a part from a
* vector, and another that writes a part of a vector. The _VP is
* Vector-to-Part, and _PV is Part-to-Vector. The _VP form is meant to
* model part/bin selects in r-value expressions, where the _PV from
* is meant to model part selects in l-value nets.
*
* In both cases, ivl_lpm_data is the input pin, and ivl_lpm_q is the
* output. In the case of the _VP device, the vector is input and the
* part is the output. In the case of the _PV device, the part is the
* input and the vector is the output.
*
* Also in both cases, the width of the device is the width of the
* part. In the _VP case, this is obvious as the output nexus has the
* part width. In the _PV case, this is a little less obvious, but
* still correct. The output being written to the wider vector is
* indeed the width of the part, even though it is written to a wider
* gate. The target will need to handle this case specially.
*/
extern const char* ivl_lpm_name(ivl_lpm_t net); /* (Obsolete) */
@ -1393,6 +1413,9 @@ _END_DECL
/*
* $Log: ivl_target.h,v $
* Revision 1.131 2005/01/09 20:16:01 steve
* Use PartSelect/PV and VP to handle part selects through ports.
*
* Revision 1.130 2004/12/29 23:55:43 steve
* Unify elaboration of l-values for all proceedural assignments,
* including assing, cassign and force.

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: net_link.cc,v 1.14 2004/02/18 17:11:56 steve Exp $"
#ident "$Id: net_link.cc,v 1.15 2005/01/09 20:16:01 steve Exp $"
#endif
# include "config.h"
@ -364,7 +364,7 @@ const char* Nexus::name() const
}
assert(sig);
ostringstream tmp;
tmp << sig->name();
tmp << sig->scope()->name() << "." << sig->name();
if (sig->pin_count() > 1)
tmp << "<" << pin << ">";
@ -499,6 +499,9 @@ bool NexusSet::intersect(const NexusSet&that) const
/*
* $Log: net_link.cc,v $
* Revision 1.15 2005/01/09 20:16:01 steve
* Use PartSelect/PV and VP to handle part selects through ports.
*
* Revision 1.14 2004/02/18 17:11:56 steve
* Use perm_strings for named langiage items.
*

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: netlist.cc,v 1.228 2004/12/29 23:55:43 steve Exp $"
#ident "$Id: netlist.cc,v 1.229 2005/01/09 20:16:01 steve Exp $"
#endif
# include "config.h"
@ -393,7 +393,7 @@ long NetNet::msb() const
return msb_;
}
long NetNet::vector_width() const
unsigned long NetNet::vector_width() const
{
if (msb_ > lsb_)
return msb_ - lsb_ + 1;
@ -466,17 +466,30 @@ NetSubnet::NetSubnet(NetNet*sig, unsigned off, unsigned wid)
set_line(*sig);
}
NetPartSelect::NetPartSelect(NetNet*sig, unsigned off, unsigned wid)
NetPartSelect::NetPartSelect(NetNet*sig, unsigned off, unsigned wid,
NetPartSelect::dir_t dir)
: NetNode(sig->scope(), sig->scope()->local_symbol(), 2),
off_(off), wid_(wid)
off_(off), wid_(wid), dir_(dir)
{
connect(pin(1), sig->pin(0));
set_line(*sig);
pin(0).set_dir(Link::OUTPUT);
pin(1).set_dir(Link::INPUT);
pin(0).set_name(perm_string::literal("O"), 0);
pin(1).set_name(perm_string::literal("I"), 0);
switch (dir_) {
case NetPartSelect::VP:
pin(0).set_dir(Link::OUTPUT);
pin(1).set_dir(Link::INPUT);
break;
case NetPartSelect::PV:
pin(0).set_dir(Link::INPUT);
pin(1).set_dir(Link::OUTPUT);
break;
case NetPartSelect::BI:
pin(0).set_dir(Link::PASSIVE);
pin(1).set_dir(Link::PASSIVE);
break;
}
pin(0).set_name(perm_string::literal("Part"), 0);
pin(1).set_name(perm_string::literal("Vect"), 0);
}
NetPartSelect::~NetPartSelect()
@ -493,6 +506,11 @@ unsigned NetPartSelect::base() const
return off_;
}
NetPartSelect::dir_t NetPartSelect::dir() const
{
return dir_;
}
NetProc::NetProc()
: next_(0)
{
@ -2326,6 +2344,9 @@ const NetProc*NetTaskDef::proc() const
/*
* $Log: netlist.cc,v $
* Revision 1.229 2005/01/09 20:16:01 steve
* Use PartSelect/PV and VP to handle part selects through ports.
*
* Revision 1.228 2004/12/29 23:55:43 steve
* Unify elaboration of l-values for all proceedural assignments,
* including assing, cassign and force.

View File

@ -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.323 2004/12/29 23:55:43 steve Exp $"
#ident "$Id: netlist.h,v 1.324 2005/01/09 20:16:01 steve Exp $"
#endif
/*
@ -400,7 +400,7 @@ class NetNet : public NetObj {
reg [1:8] has 8 bits, msb==1 and lsb==8. */
long msb() const;
long lsb() const;
long vector_width() const;
unsigned long vector_width() const;
/* This method converts a signed index (the type that might be
found in the verilog source) to a pin number. It accounts
@ -591,6 +591,10 @@ class NetCompare : public NetNode {
* remaining pins are the input that are combined to make the
* output. It is seperated out because it it generally a special case
* for the code generators.
*
* When constructing the node, the width is the vector_width of the
* output, and the cnt is the number of pins. (1 + the number of input
* vectors.)
*/
class NetConcat : public NetNode {
@ -1163,19 +1167,45 @@ class NetSubnet : public NetNet {
};
/*
* The NetPartSelect device represents an r-value part select of a
* signal. The output (pin 0) is a vector that is a part select of the
* input (pin 1). The part to be selected is the canonical (0-based)
* offset and the specified number of bits (wid).
* The NetPartSelect device represents a netlist part select of a
* signal vector. Pin 0 is a vector that is a part select of pin 1,
* which connected to the NetNet of the signal being selected from.
*
* The part to be selected is the canonical (0-based) offset and the
* specified number of bits (wid).
*
* The NetPartSelect can be output from the signal (i.e. reading a
* part), input into the signal, or bi-directional. The DIR method
* gives the type of the node.
*
* VP (Vector-to-Part)
* Output pin 0 is the part select, and input pin 1 is connected to
* the NetNet object.
*
* PV (Part-to-Vector)
* Output pin 1 is connected to the NetNet, and input pin 0 is the
* part select. In this case, the node is driving the NetNet.
*
* BI (BI-directional)
* Pin 0 is the part select and pin 1 is connected to the NetNet, but
* the ports are intended to be bi-directional.
*
* Note that whatever the direction that data is intended to flow,
* pin-0 is the part select and pin-1 is connected to the NetNet.
*/
class NetPartSelect : public NetNode {
public:
explicit NetPartSelect(NetNet*sig, unsigned off, unsigned wid);
// enum for the device direction
enum dir_t { VP, PV, BI };
explicit NetPartSelect(NetNet*sig,
unsigned off, unsigned wid, dir_t dir);
~NetPartSelect();
unsigned width() const;
unsigned base() const;
unsigned width() const;
dir_t dir() const;
virtual void dump_node(ostream&, unsigned ind) const;
bool emit_node(struct target_t*tgt) const;
@ -1183,6 +1213,7 @@ class NetPartSelect : public NetNode {
private:
unsigned off_;
unsigned wid_;
dir_t dir_;
};
/*
@ -3380,6 +3411,9 @@ extern ostream& operator << (ostream&, NetNet::Type);
/*
* $Log: netlist.h,v $
* Revision 1.324 2005/01/09 20:16:01 steve
* Use PartSelect/PV and VP to handle part selects through ports.
*
* Revision 1.323 2004/12/29 23:55:43 steve
* Unify elaboration of l-values for all proceedural assignments,
* including assing, cassign and force.

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: t-dll-api.cc,v 1.112 2004/12/29 23:55:43 steve Exp $"
#ident "$Id: t-dll-api.cc,v 1.113 2005/01/09 20:16:01 steve Exp $"
#endif
# include "config.h"
@ -682,7 +682,8 @@ extern "C" unsigned ivl_lpm_base(ivl_lpm_t net)
{
assert(net);
switch (net->type) {
case IVL_LPM_PART:
case IVL_LPM_PART_VP:
case IVL_LPM_PART_PV:
return net->u_.part.base;
default:
assert(0);
@ -789,7 +790,8 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx)
assert(idx < net->u_.concat.inputs);
return net->u_.concat.pins[idx+1];
case IVL_LPM_PART:
case IVL_LPM_PART_VP:
case IVL_LPM_PART_PV:
assert(idx == 0);
return net->u_.part.a;
@ -939,7 +941,8 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx)
case IVL_LPM_CONCAT:
return net->u_.concat.pins[0];
case IVL_LPM_PART:
case IVL_LPM_PART_VP:
case IVL_LPM_PART_PV:
assert(idx == 0);
return net->u_.part.q;
@ -1027,7 +1030,8 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net)
return 0;
case IVL_LPM_CONCAT: // Concatenations are always unsigned
return 0;
case IVL_LPM_PART:
case IVL_LPM_PART_VP:
case IVL_LPM_PART_PV:
return net->u_.part.signed_flag;
default:
assert(0);
@ -1079,7 +1083,8 @@ extern "C" unsigned ivl_lpm_width(ivl_lpm_t net)
return net->u_.ufunc.port_wid[0];
case IVL_LPM_CONCAT:
return net->u_.concat.width;
case IVL_LPM_PART:
case IVL_LPM_PART_VP:
case IVL_LPM_PART_PV:
return net->u_.part.width;
default:
assert(0);
@ -1963,6 +1968,9 @@ extern "C" ivl_variable_type_t ivl_variable_type(ivl_variable_t net)
/*
* $Log: t-dll-api.cc,v $
* Revision 1.113 2005/01/09 20:16:01 steve
* Use PartSelect/PV and VP to handle part selects through ports.
*
* Revision 1.112 2004/12/29 23:55:43 steve
* Unify elaboration of l-values for all proceedural assignments,
* including assing, cassign and force.

View File

@ -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.133 2004/12/29 23:55:43 steve Exp $"
#ident "$Id: t-dll.cc,v 1.134 2005/01/09 20:16:01 steve Exp $"
#endif
# include "config.h"
@ -1898,7 +1898,17 @@ bool dll_target::concat(const NetConcat*net)
bool dll_target::part_select(const NetPartSelect*net)
{
ivl_lpm_t obj = new struct ivl_lpm_s;
obj->type = IVL_LPM_PART;
switch (net->dir()) {
case NetPartSelect::VP:
obj->type = IVL_LPM_PART_VP;
break;
case NetPartSelect::PV:
obj->type = IVL_LPM_PART_PV;
break;
case NetPartSelect::BI:
assert(0); // XXXX Not supported yet
break;
}
obj->name = net->name(); // NetPartSelect names are permallocated.
assert(net->scope());
obj->scope = find_scope(des_, net->scope());
@ -1912,18 +1922,40 @@ bool dll_target::part_select(const NetPartSelect*net)
obj->u_.part.signed_flag = 0;
const Nexus*nex;
/* NetPartSelect:pin(0) is the output pin. */
nex = net->pin(0).nexus();
assert(nex->t_cookie());
switch (obj->type) {
case IVL_LPM_PART_VP:
/* NetPartSelect:pin(0) is the output pin. */
nex = net->pin(0).nexus();
assert(nex->t_cookie());
obj->u_.part.q = (ivl_nexus_t) nex->t_cookie();
/* NetPartSelect:pin(1) is the input pin. */
nex = net->pin(1).nexus();
assert(nex->t_cookie());
obj->u_.part.a = (ivl_nexus_t) nex->t_cookie();
break;
case IVL_LPM_PART_PV:
/* NetPartSelect:pin(1) is the output pin. */
nex = net->pin(1).nexus();
assert(nex->t_cookie());
obj->u_.part.q = (ivl_nexus_t) nex->t_cookie();
/* NetPartSelect:pin(0) is the input pin. */
nex = net->pin(0).nexus();
assert(nex->t_cookie());
obj->u_.part.a = (ivl_nexus_t) nex->t_cookie();
break;
default:
assert(0);
}
obj->u_.part.q = (ivl_nexus_t) nex->t_cookie();
nexus_lpm_add(obj->u_.part.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG);
/* NetPartSelect:pin(1) is the input pin. */
nex = net->pin(1).nexus();
assert(nex->t_cookie());
obj->u_.part.a = (ivl_nexus_t) nex->t_cookie();
nexus_lpm_add(obj->u_.part.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ);
scope_add_lpm(obj->scope, obj);
@ -2207,6 +2239,9 @@ extern const struct target tgt_dll = { "dll", &dll_target_obj };
/*
* $Log: t-dll.cc,v $
* Revision 1.134 2005/01/09 20:16:01 steve
* Use PartSelect/PV and VP to handle part selects through ports.
*
* Revision 1.133 2004/12/29 23:55:43 steve
* Unify elaboration of l-values for all proceedural assignments,
* including assing, cassign and force.

View File

@ -17,7 +17,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: stub.c,v 1.94 2004/12/29 23:55:43 steve Exp $"
#ident "$Id: stub.c,v 1.95 2005/01/09 20:16:01 steve Exp $"
#endif
# include "config.h"
@ -406,8 +406,17 @@ static void show_lpm(ivl_lpm_t net)
break;
}
case IVL_LPM_PART: {
fprintf(out, " LPM_PART %s: <width=%u, base=%u, signed=%d>\n",
case IVL_LPM_PART_VP: {
fprintf(out, " LPM_PART_VP %s: <width=%u, base=%u, signed=%d>\n",
ivl_lpm_basename(net),
width, ivl_lpm_base(net), ivl_lpm_signed(net));
fprintf(out, " O: %s\n", ivl_nexus_name(ivl_lpm_q(net,0)));
fprintf(out, " I: %s\n", ivl_nexus_name(ivl_lpm_data(net,0)));
break;
}
case IVL_LPM_PART_PV: {
fprintf(out, " LPM_PART_PV %s: <width=%u, base=%u, signed=%d>\n",
ivl_lpm_basename(net),
width, ivl_lpm_base(net), ivl_lpm_signed(net));
fprintf(out, " O: %s\n", ivl_nexus_name(ivl_lpm_q(net,0)));
@ -584,13 +593,21 @@ static void show_signal(ivl_signal_t net)
const char*dr1 = str_tab[ivl_nexus_ptr_drive1(ptr)];
if ((sig = ivl_nexus_ptr_sig(ptr))) {
fprintf(out, " %s[%u] (%s0, %s1)\n",
ivl_signal_name(sig),
ivl_nexus_ptr_pin(ptr), dr0, dr1);
fprintf(out, " SIG %s (%s0, %s1)",
ivl_signal_name(sig), dr0, dr1);
/* Only pin-0 of signals is used. If this is
something other then pin-0, report an error. */
if (ivl_nexus_ptr_pin(ptr) != 0)
fprintf(out, " (pin=%u, should be 0)",
ivl_nexus_ptr_pin(ptr));
fprintf(out, "\n");
} else if ((log = ivl_nexus_ptr_log(ptr))) {
fprintf(out, " %s[%u] (%s0, %s1)\n",
ivl_logic_name(log),
fprintf(out, " LOG %s.%s[%u] (%s0, %s1)\n",
ivl_scope_name(ivl_logic_scope(log)),
ivl_logic_basename(log),
ivl_nexus_ptr_pin(ptr), dr0, dr1);
} else if ((lpm = ivl_nexus_ptr_lpm(ptr))) {
@ -810,6 +827,9 @@ int target_design(ivl_design_t des)
/*
* $Log: stub.c,v $
* Revision 1.95 2005/01/09 20:16:01 steve
* Use PartSelect/PV and VP to handle part selects through ports.
*
* Revision 1.94 2004/12/29 23:55:43 steve
* Unify elaboration of l-values for all proceedural assignments,
* including assing, cassign and force.

View File

@ -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.105 2004/12/29 23:52:09 steve Exp $"
#ident "$Id: vvp_scope.c,v 1.106 2005/01/09 20:16:01 steve Exp $"
#endif
# include "vvp_priv.h"
@ -431,6 +431,7 @@ static const char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
case IVL_LPM_RAM:
case IVL_LPM_ADD:
case IVL_LPM_CONCAT:
case IVL_LPM_SHIFTL:
case IVL_LPM_SHIFTR:
case IVL_LPM_SUB:
@ -438,7 +439,8 @@ static const char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
case IVL_LPM_DIVIDE:
case IVL_LPM_MOD:
case IVL_LPM_UFUNC:
case IVL_LPM_PART:
case IVL_LPM_PART_VP:
case IVL_LPM_PART_PV: /* NOTE: This is onlt a partial driver. */
if (ivl_lpm_q(lpm, 0) == nex) {
sprintf(result, "L_%p", lpm);
return result;
@ -446,7 +448,6 @@ static const char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr)
break;
case IVL_LPM_CONCAT:
case IVL_LPM_CMP_GE:
case IVL_LPM_CMP_GT:
case IVL_LPM_CMP_EQ:
@ -1299,9 +1300,7 @@ static void draw_lpm_concat(ivl_lpm_t net)
/* XXXX For now, only handle concatenation of 4 values. */
assert(icnt <= 4);
fprintf(vvp_out, "L_%s.%s .concat [",
vvp_mangle_id(ivl_scope_name(ivl_lpm_scope(net))),
vvp_mangle_id(ivl_lpm_basename(net)));
fprintf(vvp_out, "L_%p .concat [", net);
for (idx = 0 ; idx < icnt ; idx += 1) {
ivl_nexus_t nex = ivl_lpm_data(net, idx);
@ -1310,7 +1309,7 @@ static void draw_lpm_concat(ivl_lpm_t net)
}
for ( ; idx < 4 ; idx += 1)
fpritnf(vvp_out, " 0");
fprintf(vvp_out, " 0");
fprintf(vvp_out, "]");
@ -1569,6 +1568,22 @@ static void draw_lpm_part(ivl_lpm_t net)
fprintf(vvp_out, ", %u, %u;\n", base, width);
}
/*
* Handle a PART SELECT PV device. Generate a .part/pv node that
* includes the part input, and the geometry of the part.
*/
static void draw_lpm_part_pv(ivl_lpm_t net)
{
unsigned width = ivl_lpm_width(net);
unsigned base = ivl_lpm_base(net);
unsigned signal_width = width_of_nexus(ivl_lpm_q(net,0));
fprintf(vvp_out, "L_%p .part/pv ", net);
draw_input_from_net(ivl_lpm_data(net, 0));
fprintf(vvp_out, ", %u, %u, %u;\n", base, width, signal_width);
}
static void draw_lpm_in_scope(ivl_lpm_t net)
{
switch (ivl_lpm_type(net)) {
@ -1585,10 +1600,14 @@ static void draw_lpm_in_scope(ivl_lpm_t net)
draw_lpm_add(net);
return;
case IVL_LPM_PART:
case IVL_LPM_PART_VP:
draw_lpm_part(net);
return;
case IVL_LPM_PART_PV:
draw_lpm_part_pv(net);
return;
case IVL_LPM_CONCAT:
draw_lpm_concat(net);
return;
@ -1743,6 +1762,9 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent)
/*
* $Log: vvp_scope.c,v $
* Revision 1.106 2005/01/09 20:16:01 steve
* Use PartSelect/PV and VP to handle part selects through ports.
*
* Revision 1.105 2004/12/29 23:52:09 steve
* Generate code for the .concat functors, from NetConcat objects.
* Generate C<> constants of correct widths for functor arguments.