diff --git a/elaborate.cc b/elaborate.cc index 63fb5fbcb..51d6d9239 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: elaborate.cc,v 1.82 1999/09/12 01:16:51 steve Exp $" +#ident "$Id: elaborate.cc,v 1.83 1999/09/13 03:10:59 steve Exp $" #endif /* @@ -105,11 +105,17 @@ void PWire::elaborate(Design*des, const string&path) const wtype = NetNet::REG; unsigned wid = 1; + long lsb = 0, msb = 0; if (msb_.count()) { svectormnum (msb_.count()); svectorlnum (msb_.count()); + /* There may be multiple declarations of ranges, because + the symbol may have its range declared in i.e. input + and reg declarations. Calculate *all* the numbers + here. I will resolve the values later. */ + for (unsigned idx = 0 ; idx < msb_.count() ; idx += 1) { verinum*mval = msb_[idx]->eval_const(des,path); if (mval == 0) { @@ -134,6 +140,8 @@ void PWire::elaborate(Design*des, const string&path) const delete lval; } + /* Make sure all the values for msb and lsb match by + value. If not, report an error. */ for (unsigned idx = 1 ; idx < msb_.count() ; idx += 1) { if ((mnum[idx] != mnum[0]) || (lnum[idx] != lnum[0])) { cerr << get_line() << ": Inconsistent width, " @@ -145,6 +153,8 @@ void PWire::elaborate(Design*des, const string&path) const } } + lsb = lnum[0]; + msb = mnum[0]; if (mnum[0] > lnum[0]) wid = mnum[0] - lnum[0] + 1; else @@ -173,7 +183,7 @@ void PWire::elaborate(Design*des, const string&path) const } else { - NetNet*sig = new NetNet(path + "." + name_, wtype, wid); + NetNet*sig = new NetNet(path + "." + name_, wtype, msb, lsb); sig->set_line(*this); sig->port_type(port_type_); sig->set_attributes(attributes); @@ -1255,14 +1265,18 @@ NetExpr* PEIdent::elaborate_expr(Design*des, const string&path) const verinum*msn = msb_->eval_const(des, path); unsigned long lsv = lsn->as_ulong(); unsigned long msv = msn->as_ulong(); - assert(msv >= lsv); - unsigned long wid = msv-lsv+1; + unsigned long wid = 1 + ((msv>lsv)? (msv-lsv) : (lsv-msv)); + assert(wid <= net->pin_count()); + assert(net->sb_to_idx(msv) >= net->sb_to_idx(lsv)); string tname = des->local_symbol(path); NetESignal*tmp = new NetESignal(tname, wid); tmp->set_line(*this); + + // Connect the pins from the lsb up to the msb. + unsigned off = net->sb_to_idx(lsv); for (unsigned idx = 0 ; idx < wid ; idx += 1) - connect(tmp->pin(idx), net->pin(idx+lsv)); + connect(tmp->pin(idx), net->pin(idx+off)); des->add_node(tmp); return tmp; @@ -1373,6 +1387,10 @@ NetProc* PAssign::assign_to_memory_(NetMemory*mem, PExpr*ix, return am; } +/* + * Elaborate an l-value as a NetNet (it may already exist) and make up + * the part select stuff for where the assignment is going to be made. + */ NetNet* PAssign_::elaborate_lval(Design*des, const string&path, unsigned&msb, unsigned&lsb, NetExpr*&mux) const @@ -1453,14 +1471,34 @@ NetNet* PAssign_::elaborate_lval(Design*des, const string&path, } else { assert(id->msb_ == 0); assert(id->lsb_ == 0); - msb = reg->pin_count() - 1; - lsb = 0; + msb = reg->msb(); + lsb = reg->lsb(); mux = 0; } return reg; } +/* + * This funciton transforms an expression by padding the high bits + * with V0 until the expression has the desired width. This may mean + * not transforming the expression at all, if it is already wide + * enough. + */ +static NetExpr*pad_to_width(NetExpr*expr, unsigned wid) +{ + if (wid > expr->expr_width()) { + verinum pad(verinum::V0, wid - expr->expr_width()); + NetEConst*co = new NetEConst(pad); + NetEConcat*cc = new NetEConcat(2); + cc->set(0, co); + cc->set(1, expr); + cc->set_width(wid); + expr = cc; + } + return expr; +} + NetProc* PAssign::elaborate(Design*des, const string&path) const { /* Catch the case where the lvalue is a reference to a memory @@ -1513,9 +1551,9 @@ NetProc* PAssign::elaborate(Design*des, const string&path) const if (rise_time) { string n = des->local_symbol(path); - unsigned wid = msb - lsb + 1; + unsigned wid = reg->pin_count(); - if (! rv->set_width(wid)) { + if (! rv->set_width(reg->pin_count())) { cerr << get_line() << ": Unable to match expression " "width of " << rv->expr_width() << " to l-value" " width of " << wid << "." << endl; @@ -1527,6 +1565,7 @@ NetProc* PAssign::elaborate(Design*des, const string&path) const tmp->set_line(*this); des->add_signal(tmp); + /* Generate an assignment of the l-value to the temporary... */ n = des->local_symbol(path); NetAssign*a1 = new NetAssign(n, des, wid, rv); a1->set_line(*this); @@ -1535,6 +1574,7 @@ NetProc* PAssign::elaborate(Design*des, const string&path) const for (unsigned idx = 0 ; idx < wid ; idx += 1) connect(a1->pin(idx), tmp->pin(idx)); + /* Generate an assignment of the temporary to the r-value... */ n = des->local_symbol(path); NetESignal*sig = new NetESignal(tmp); des->add_node(sig); @@ -1543,8 +1583,9 @@ NetProc* PAssign::elaborate(Design*des, const string&path) const des->add_node(a2); for (unsigned idx = 0 ; idx < wid ; idx += 1) - connect(a2->pin(idx), reg->pin(idx+lsb)); + connect(a2->pin(idx), reg->pin(idx)); + /* And build up the complex statement. */ NetPDelay*de = new NetPDelay(rise_time, a2); NetBlock*bl = new NetBlock(NetBlock::SEQU); @@ -1555,13 +1596,22 @@ NetProc* PAssign::elaborate(Design*des, const string&path) const } if (mux == 0) { - unsigned wid = msb - lsb + 1; + /* This is a simple assign to a register. There may be a + part select, so take care that the width is of the + part, and using the lsb, make sure the correct range + of bits is assigned. */ + unsigned wid = (msb >= lsb)? (msb-lsb+1) : (lsb-msb+1); + assert(wid <= reg->pin_count()); rv->set_width(wid); + rv = pad_to_width(rv, wid); + assert(rv->expr_width() >= wid); cur = new NetAssign(des->local_symbol(path), des, wid, rv); + unsigned off = reg->sb_to_idx(lsb); + assert((off+wid) <= reg->pin_count()); for (unsigned idx = 0 ; idx < wid ; idx += 1) - connect(cur->pin(idx), reg->pin(idx+lsb)); + connect(cur->pin(idx), reg->pin(idx+off)); } else { assert(reg->pin_count() == 1); @@ -1611,18 +1661,9 @@ NetProc* PAssignNB::elaborate(Design*des, const string&path) const unsigned wid = msb - lsb + 1; rv->set_width(wid); + rv = pad_to_width(rv, wid); + assert(wid <= rv->expr_width()); - /* If the l-value is larger then the r-value, then pad - the r-value with 0s. */ - if (wid > rv->expr_width()) { - verinum pad(verinum::V0, wid-rv->expr_width()); - NetEConst*co = new NetEConst(pad); - NetEConcat*cc = new NetEConcat(2); - cc->set(0, co); - cc->set(1, rv); - cc->set_width(wid); - rv = cc; - } cur = new NetAssignNB(des->local_symbol(path), des, wid, rv); for (unsigned idx = 0 ; idx < wid ; idx += 1) connect(cur->pin(idx), reg->pin(idx+lsb)); @@ -2334,6 +2375,12 @@ Design* elaborate(const map&modules, /* * $Log: elaborate.cc,v $ + * Revision 1.83 1999/09/13 03:10:59 steve + * Clarify msb/lsb in context of netlist. Properly + * handle part selects in lval and rval of expressions, + * and document where the least significant bit goes + * in NetNet objects. + * * Revision 1.82 1999/09/12 01:16:51 steve * Pad r-values in certain assignments. * diff --git a/netlist.cc b/netlist.cc index 0d0297f20..10e4921dd 100644 --- a/netlist.cc +++ b/netlist.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: netlist.cc,v 1.60 1999/09/12 01:16:51 steve Exp $" +#ident "$Id: netlist.cc,v 1.61 1999/09/13 03:10:59 steve Exp $" #endif # include @@ -240,6 +240,18 @@ bool NetObj::has_compat_attributes(const NetObj&that) const return true; } +NetObj::Link& NetObj::pin(unsigned idx) +{ + assert(idx < npins_); + return pins_[idx]; +} + +const NetObj::Link& NetObj::pin(unsigned idx) const +{ + assert(idx < npins_); + return pins_[idx]; +} + NetNode::~NetNode() { if (design_) @@ -272,6 +284,14 @@ NetNet::~NetNet() design_->del_signal(this); } +unsigned NetNet::sb_to_idx(long sb) const +{ + if (msb_ >= lsb_) + return sb - lsb_; + else + return lsb_ - sb; +} + NetProc::~NetProc() { } @@ -1762,6 +1782,12 @@ NetNet* Design::find_signal(bool (*func)(const NetNet*)) /* * $Log: netlist.cc,v $ + * Revision 1.61 1999/09/13 03:10:59 steve + * Clarify msb/lsb in context of netlist. Properly + * handle part selects in lval and rval of expressions, + * and document where the least significant bit goes + * in NetNet objects. + * * Revision 1.60 1999/09/12 01:16:51 steve * Pad r-values in certain assignments. * diff --git a/netlist.h b/netlist.h index 361f6980d..2ec149377 100644 --- a/netlist.h +++ b/netlist.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) -#ident "$Id: netlist.h,v 1.62 1999/09/11 04:43:17 steve Exp $" +#ident "$Id: netlist.h,v 1.63 1999/09/13 03:10:59 steve Exp $" #endif /* @@ -170,8 +170,8 @@ class NetObj { bool test_mark() const { return mark_; } void set_mark(bool flag=true) { mark_ = flag; } - Link&pin(unsigned idx) { return pins_[idx]; } - const Link&pin(unsigned idx) const { return pins_[idx]; } + Link&pin(unsigned idx); + const Link&pin(unsigned idx) const; void dump_node_pins(ostream&, unsigned) const; void dump_obj_attr(ostream&, unsigned) const; @@ -220,7 +220,8 @@ class NetNode : public NetObj { * * Note that a net of any sort has exactly one pin. The pins feature * of the NetObj class is used to make a set of identical wires, in - * order to support ranges, or busses. + * order to support ranges, or busses. When dealing with vectors, + * pin(0) is always the least significant bit. */ class NetNet : public NetObj, public LineInfo { @@ -243,15 +244,17 @@ class NetNet : public NetObj, public LineInfo { PortType port_type() const { return port_type_; } void port_type(PortType t) { port_type_ = t; } + /* These methods return the msb and lsb indices for the most + significant and least significant bits. These are signed + longs, and may be different from pin numbers. For example, + reg [1:8] has 8 bits, msb==1 and lsb==8. */ long msb() const { return msb_; } long lsb() const { return lsb_; } - unsigned sb_to_idx(long sb) const - { if (msb_ >= lsb_) - return sb - lsb_; - else - return lsb_ - sb; - } + /* This method converts a signed index (the type that might be + found in the verilog source) to a pin number. It accounts + for variation in the definition of the reg/wire/whatever. */ + unsigned sb_to_idx(long sb) const; bool local_flag() const { return local_flag_; } void local_flag(bool f) { local_flag_ = f; } @@ -1556,6 +1559,12 @@ extern ostream& operator << (ostream&, NetNet::Type); /* * $Log: netlist.h,v $ + * Revision 1.63 1999/09/13 03:10:59 steve + * Clarify msb/lsb in context of netlist. Properly + * handle part selects in lval and rval of expressions, + * and document where the least significant bit goes + * in NetNet objects. + * * Revision 1.62 1999/09/11 04:43:17 steve * Support ternary and <= operators in vvm. *