Use PartSelect/PV and VP to handle part selects through ports.
This commit is contained in:
parent
6c711ee4d8
commit
9e94afe399
8
PExpr.h
8
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 <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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
346
elab_net.cc
346
elab_net.cc
|
|
@ -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
|
||||
|
|
|
|||
138
elaborate.cc
138
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<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.
|
||||
|
|
|
|||
27
ivl_target.h
27
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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
37
netlist.cc
37
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.
|
||||
|
|
|
|||
50
netlist.h
50
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.
|
||||
|
|
|
|||
20
t-dll-api.cc
20
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.
|
||||
|
|
|
|||
59
t-dll.cc
59
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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Reference in New Issue