diff --git a/PExpr.h b/PExpr.h index 510963246..888f22a55 100644 --- a/PExpr.h +++ b/PExpr.h @@ -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 @@ -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. diff --git a/design_dump.cc b/design_dump.cc index c1912ac8e..112f1bf39 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.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_ <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() << "["<name() << "[base="<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() << "["<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 diff --git a/elaborate.cc b/elaborate.cc index e013346b5..0086d1168 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.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 mport = rmod->get_port(idx); svectorprts (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(sig)) - delete tmp; } } @@ -2845,6 +2890,9 @@ Design* elaborate(listroots) /* * $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. diff --git a/ivl_target.h b/ivl_target.h index bad0cfbf0..853a92635 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.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. diff --git a/net_link.cc b/net_link.cc index d30e96167..a4fc08681 100644 --- a/net_link.cc +++ b/net_link.cc @@ -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. * diff --git a/netlist.cc b/netlist.cc index edaa588d7..2161dc79d 100644 --- a/netlist.cc +++ b/netlist.cc @@ -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. diff --git a/netlist.h b/netlist.h index 0b8f474be..6f8cc206a 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.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. diff --git a/t-dll-api.cc b/t-dll-api.cc index fda6ee180..02c449688 100644 --- a/t-dll-api.cc +++ b/t-dll-api.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-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. diff --git a/t-dll.cc b/t-dll.cc index 25e33c268..c8f861979 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.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. diff --git a/tgt-stub/stub.c b/tgt-stub/stub.c index 32407e429..8099b3260 100644 --- a/tgt-stub/stub.c +++ b/tgt-stub/stub.c @@ -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: \n", + case IVL_LPM_PART_VP: { + fprintf(out, " LPM_PART_VP %s: \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: \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. diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 20afcf5e4..04cb0d211 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.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.