diff --git a/elab_sig.cc b/elab_sig.cc index 06854a52b..c030fa6f6 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -826,6 +826,93 @@ static netstruct_t* elaborate_struct_type(Design*des, NetScope*scope, return res; } +static bool evaluate_ranges(Design*des, NetScope*scope, + list&llist, + const list&rlist) +{ + bool bad_msb = false, bad_lsb = false; + + for (list::const_iterator cur = rlist.begin() + ; cur != rlist.end() ; ++cur) { + NetNet::range_t lrng; + + NetExpr*texpr = elab_and_eval(des, scope, cur->msb, -1, true); + if (! eval_as_long(lrng.msb, texpr)) { + cerr << cur->msb->get_fileline() << ": error: " + "Range expressions must be constant." << endl; + cerr << cur->msb->get_fileline() << " : " + "This MSB expression violates the rule: " + << *cur->msb << endl; + des->errors += 1; + bad_msb = true; + } + + delete texpr; + + texpr = elab_and_eval(des, scope, cur->lsb, -1, true); + if (! eval_as_long(lrng.lsb, texpr)) { + cerr << cur->lsb->get_fileline() << ": error: " + "Range expressions must be constant." << endl; + cerr << cur->lsb->get_fileline() << " : " + "This LSB expression violates the rule: " + << *cur->lsb << endl; + des->errors += 1; + bad_lsb = true; + } + + delete texpr; + + llist.push_back(lrng); + } + + return bad_msb | bad_lsb; +} + +bool test_ranges_eeq(const list&lef, const list&rig) +{ + if (lef.size() != rig.size()) + return false; + + list::const_iterator lcur = lef.begin(); + list::const_iterator rcur = rig.begin(); + while (lcur != lef.end()) { + if (lcur->msb != rcur->msb) + return false; + if (lcur->lsb != rcur->lsb) + return false; + + ++ lcur; + ++ rcur; + } + + return true; +} + +static unsigned packed_ranges_to_wid(const list&packed) +{ + unsigned wid = 1; + for (list::const_iterator cur = packed.begin() + ; cur != packed.begin() ; ++cur) { + unsigned use_wid; + if (cur->msb >= cur->lsb) + use_wid = cur->msb - cur->lsb + 1; + else + use_wid = cur->lsb - cur->msb + 1; + wid *= use_wid; + } + + return wid; +} + +static ostream&operator<<(ostream&out, const list&rlist) +{ + for (list::const_iterator cur = rlist.begin() + ; cur != rlist.end() ; ++cur) { + out << "[" << cur->msb << ":" << cur->lsb << "]"; + } + return out; +} + /* * Elaborate a source wire. The "wire" is the declaration of wires, * registers, ports and memories. The parser has already merged the @@ -847,7 +934,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const } unsigned wid = 1; - long lsb = 0, msb = 0; + listpacked_dimensions; des->errors += error_cnt_; @@ -887,101 +974,43 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const } if (port_set_ || net_set_) { - long pmsb = 0, plsb = 0, nmsb = 0, nlsb = 0; - bool bad_lsb = false, bad_msb = false; + bool bad_range = false; + list plist, nlist; /* If they exist get the port definition MSB and LSB */ if (port_set_ && !port_.empty()) { - assert(port_.size() == 1); - PWire::range_t rng = port_.front(); - NetExpr*texpr = elab_and_eval(des, scope, rng.msb, -1, true); - - if (! eval_as_long(pmsb, texpr)) { - cerr << rng.msb->get_fileline() << ": error: " - "Range expressions must be constant." << endl; - cerr << rng.msb->get_fileline() << " : " - "This MSB expression violates the rule: " - << *rng.msb << endl; - des->errors += 1; - bad_msb = true; - } - - delete texpr; - - texpr = elab_and_eval(des, scope, rng.lsb, -1, true); - - if (! eval_as_long(plsb, texpr)) { - cerr << rng.lsb->get_fileline() << ": error: " - "Range expressions must be constant." << endl; - cerr << rng.lsb->get_fileline() << " : " - "This LSB expression violates the rule: " - << *rng.lsb << endl; - des->errors += 1; - bad_lsb = true; - } - - delete texpr; - nmsb = pmsb; - nlsb = plsb; + bad_range |= evaluate_ranges(des, scope, plist, port_); + nlist = plist; /* An implicit port can have a range so note that here. */ is_implicit_scalar = false; } - if (!port_set_) assert(port_.empty()); - - if (net_.size() > 1) { - cerr << net_.back().msb->get_fileline() << ": sorry: " - << "Multi-dimension packed arrays not supported." - << endl; - des->errors += 1; - } + assert(port_set_ || port_.empty()); /* If they exist get the net/etc. definition MSB and LSB */ - if (net_set_ && !net_.empty() && !bad_msb && !bad_lsb) { - PWire::range_t rng = net_.front(); - NetExpr*texpr = elab_and_eval(des, scope, rng.msb, -1, true); - - if (! eval_as_long(nmsb, texpr)) { - cerr << rng.msb->get_fileline() << ": error: " - "Range expressions must be constant." << endl; - cerr << rng.msb->get_fileline() << " : " - "This MSB expression violates the rule: " - << *rng.msb << endl; - des->errors += 1; - bad_msb = true; - } - - delete texpr; - - texpr = elab_and_eval(des, scope, rng.lsb, -1, true); - - if (! eval_as_long(nlsb, texpr)) { - cerr << rng.lsb->get_fileline() << ": error: " - "Range expressions must be constant." << endl; - cerr << rng.lsb->get_fileline() << " : " - "This LSB expression violates the rule: " - << *rng.lsb << endl; - des->errors += 1; - bad_lsb = true; - } - - delete texpr; + if (net_set_ && !net_.empty() && !bad_range) { + nlist.clear(); + bad_range |= evaluate_ranges(des, scope, nlist, net_); } - if (!net_set_) assert(net_.empty()); + assert(net_set_ || net_.empty()); + + /* If we find errors here, then give up on this signal. */ + if (bad_range) + return 0; /* We have a port size error */ - if (port_set_ && net_set_ && (pmsb != nmsb || plsb != nlsb)) { + if (port_set_ && net_set_ && !test_ranges_eeq(plist, nlist)) { /* Scalar port with a vector net/etc. definition */ if (port_.empty()) { if (!gn_io_range_error_flag) { cerr << get_fileline() << ": warning: Scalar port ``" << name_ - << "'' has a vectored net declaration [" - << nmsb << ":" << nlsb << "]." << endl; + << "'' has a vectored net declaration " + << nlist << "." << endl; } else { cerr << get_fileline() << ": error: Scalar port ``" << name_ - << "'' has a vectored net declaration [" - << nmsb << ":" << nlsb << "]." << endl; + << "'' has a vectored net declaration " + << nlist << "." << endl; des->errors += 1; return 0; } @@ -991,8 +1020,8 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const if (net_.empty()) { cerr << port_.front().msb->get_fileline() << ": error: Vectored port ``" - << name_ << "'' [" << pmsb << ":" << plsb - << "] has a scalar net declaration at " + << name_ << "'' " << plist + << " has a scalar net declaration at " << get_fileline() << "." << endl; des->errors += 1; return 0; @@ -1002,26 +1031,17 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const if (!port_.empty() && !net_.empty()) { cerr << port_.front().msb->get_fileline() << ": error: Vectored port ``" - << name_ << "'' [" << pmsb << ":" << plsb - << "] has a net declaration [" << nmsb << ":" - << nlsb << "] at " << net_.front().msb->get_fileline() + << name_ << "'' " << plist + << " has a net declaration " << nlist + << " at " << net_.front().msb->get_fileline() << " that does not match." << endl; des->errors += 1; return 0; } } - /* Attempt to recover from errors. */ - if (bad_lsb) nlsb = 0; - if (bad_msb) nmsb = nlsb; - - lsb = nlsb; - msb = nmsb; - if (nmsb > nlsb) - wid = nmsb - nlsb + 1; - else - wid = nlsb - nmsb + 1; - + packed_dimensions = nlist; + wid = packed_ranges_to_wid(packed_dimensions); } @@ -1073,13 +1093,13 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const array_dimensions = 1; } - if (data_type_ == IVL_VT_REAL && (msb != 0 || lsb != 0)) { + if (data_type_ == IVL_VT_REAL && !packed_dimensions.empty()) { cerr << get_fileline() << ": error: real "; if (wtype == NetNet::REG) cerr << "variable"; else cerr << "net"; cerr << " '" << name_ - << "' cannot be declared as a vector, found a range [" - << msb << ":" << lsb << "]." << endl; + << "' cannot be declared as a vector, found a range " + << packed_dimensions << "." << endl; des->errors += 1; return 0; } @@ -1143,7 +1163,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const if (debug_elaborate) { cerr << get_fileline() << ": debug: Create signal " << wtype; if (!get_scalar()) { - cerr << " ["< 0) { @@ -1152,6 +1172,16 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const cerr << " in scope " << scope_path(scope) << endl; } + if (packed_dimensions.size() > 1) { + cerr << get_fileline() << ": sorry: Multi-dimension " + << "packed arrays not supported." << endl; + des->errors += 1; + } + long msb = 0, lsb = 0; + if (packed_dimensions.size() >= 1) { + msb = packed_dimensions.front().msb; + lsb = packed_dimensions.front().lsb; + } sig = array_dimensions > 0 ? new NetNet(scope, name_, wtype, msb, lsb, array_s0, array_e0) : new NetNet(scope, name_, wtype, msb, lsb); diff --git a/netlist.cc b/netlist.cc index ed07fda91..704960ed2 100644 --- a/netlist.cc +++ b/netlist.cc @@ -860,13 +860,13 @@ unsigned NetNet::peek_eref() const * Test each of the bits in the range, and set them. If any bits are * already set then return true. */ -bool NetNet::test_part_lref(unsigned msb, unsigned lsb) +bool NetNet::test_part_lref(unsigned pmsb, unsigned plsb) { if (lref_mask_.size() == 0) lref_mask_.resize(vector_width()); bool rc = false; - for (unsigned idx = lsb ; idx <= msb ; idx += 1) { + for (unsigned idx = plsb ; idx <= pmsb ; idx += 1) { if (lref_mask_[idx]) rc = true; else diff --git a/netlist.h b/netlist.h index cae9e3a1e..94b2ca5e5 100644 --- a/netlist.h +++ b/netlist.h @@ -1,7 +1,7 @@ #ifndef __netlist_H #define __netlist_H /* - * Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2012 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -563,6 +563,12 @@ class NetNet : public NetObj { enum PortType { NOT_A_PORT, PIMPLICIT, PINPUT, POUTPUT, PINOUT }; + struct range_t { + long msb; + long lsb; + }; + + public: // The width in this case is a shorthand for ms=width-1 and // ls=0. Only one pin is created, the width is of the vector // that passed through.