Permalink
Browse files

Handle part selects of nets that fall of the ends of the identifier.

The Verilog LRM specifies that it is legal to give constant part
selects that are beyond the bounds of the identifier being selected.
But elaboration was flagging that as an error. This patch changes it
to a warning, and handles the cases by generating 'bx bits as needed.
  • Loading branch information...
steveicarus committed May 10, 2008
1 parent a33619a commit dfb7bf52115e39dc53d48e71847acc9767f1cc47
Showing with 123 additions and 21 deletions.
  1. +1 −1 PExpr.h
  2. +120 −18 elab_net.cc
  3. +1 −1 netlist.cc
  4. +1 −1 netlist.h
View
@@ -387,7 +387,7 @@ class PEIdent : public PExpr {
NetNet*make_implicit_net_(Design*des, NetScope*scope) const;
bool eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
- unsigned&midx, unsigned&lidx) const;
+ long&midx, long&lidx) const;
NetNet*process_select_(Design*des, NetScope*scope, NetNet*sig) const;
};
View
@@ -1894,10 +1894,11 @@ NetNet* PEIdent::process_select_(Design*des, NetScope*scope,
// dimensions, then treat them as word part selects. For
// example, if this is a memory array, then array dimensions
// is the first and part select the remainder.
- unsigned midx, lidx;
+ long midx, lidx;
if (! eval_part_select_(des, scope, sig, midx, lidx))
return sig;
+ ivl_assert(*this, lidx >= 0);
unsigned part_count = midx-lidx+1;
// Maybe this is a full-width constant part select? If
@@ -1963,12 +1964,70 @@ NetNet* PEIdent::elaborate_net_net_(Design*des, NetScope*scope,
delete mval;
}
- unsigned midx, lidx;
+ long midx, lidx;
if (! eval_part_select_(des, scope, sig, midx, lidx))
return 0;
unsigned part_count = midx-lidx+1;
+ unsigned output_width = part_count;
+
+ /* Detect and handle the special case that the entire part
+ select is outside the range of the signal. Return a
+ constant xxx. */
+ if (midx < 0 || lidx >= (long)sig->vector_width()) {
+ ivl_assert(*this, sig->data_type() == IVL_VT_LOGIC);
+ verinum xxx (verinum::Vx, part_count);
+ NetConst*con = new NetConst(scope, scope->local_symbol(), xxx);
+ con->set_line(*sig);
+ des->add_node(con);
+
+ NetNet*tmp = new NetNet(scope, scope->local_symbol(),
+ NetNet::WIRE, part_count-1, 0);
+ tmp->data_type( sig->data_type() );
+ tmp->local_flag(true);
+ connect(tmp->pin(0), con->pin(0));
+ return tmp;
+ }
+
+ NetNet*below = 0;
+ if (lidx < 0) {
+ ivl_assert(*this, sig->data_type() == IVL_VT_LOGIC);
+ unsigned xxx_wid = 0-lidx;
+ verinum xxx (verinum::Vx, xxx_wid);
+ NetConst*con = new NetConst(scope, scope->local_symbol(), xxx);
+ con->set_line(*sig);
+ des->add_node(con);
+
+ below = new NetNet(scope, scope->local_symbol(),
+ NetNet::WIRE, xxx_wid);
+ below->data_type( sig->data_type() );
+ below->local_flag(true);
+ connect(below->pin(0), con->pin(0));
+
+ lidx = 0;
+ part_count = midx-lidx+1;
+ }
+
+ NetNet*above = 0;
+ if (midx >= (long)sig->vector_width()) {
+ ivl_assert(*this, sig->data_type() == IVL_VT_LOGIC);
+ unsigned xxx_wid = midx - sig->vector_width() + 1;
+ verinum xxx (verinum::Vx, xxx_wid);
+ NetConst*con = new NetConst(scope, scope->local_symbol(), xxx);
+ con->set_line(*sig);
+ des->add_node(con);
+
+ above = new NetNet(scope, scope->local_symbol(),
+ NetNet::WIRE, xxx_wid);
+ above->data_type( sig->data_type() );
+ above->local_flag(true);
+ connect(above->pin(0), con->pin(0));
+
+ midx = sig->vector_width()-1;
+ part_count = midx-lidx+1;
+ }
+ ivl_assert(*this, lidx >= 0);
if (part_count != sig->vector_width()) {
if (debug_elaborate) {
cerr << get_fileline() << ": debug: Elaborate part select "
@@ -1990,7 +2049,36 @@ NetNet* PEIdent::elaborate_net_net_(Design*des, NetScope*scope,
sig = tmp;
}
+ unsigned segment_count = 1;
+ if (below) segment_count += 1;
+ if (above) segment_count += 1;
+ if (segment_count > 1) {
+ NetConcat*cc = new NetConcat(scope, scope->local_symbol(),
+ output_width, segment_count);
+ cc->set_line(*sig);
+ des->add_node(cc);
+
+ NetNet*tmp = new NetNet(scope, scope->local_symbol(),
+ NetNet::WIRE, output_width);
+ tmp->data_type( sig->data_type() );
+ tmp->local_flag(true);
+ connect(tmp->pin(0), cc->pin(0));
+
+ unsigned pdx = 1;
+ if (below) {
+ connect(cc->pin(pdx), below->pin(0));
+ pdx += 1;
+ }
+ connect(cc->pin(pdx), sig->pin(0));
+ pdx += 1;
+ if (above) {
+ connect(cc->pin(pdx), above->pin(0));
+ pdx += 1;
+ }
+ ivl_assert(*sig, segment_count == pdx-1);
+ sig = tmp;
+ }
return sig;
}
@@ -2385,7 +2473,7 @@ NetNet* PEIdent::make_implicit_net_(Design*des, NetScope*scope) const
* 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
+ long&midx, long&lidx) const
{
const name_component_t&name_tail = path_.back();
// Only treat as part/bit selects any index that is beyond the
@@ -2449,31 +2537,36 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
long msb, lsb;
/* bool flag = */ calculate_parts_(des, scope, msb, lsb);
- lidx = sig->sb_to_idx(lsb);
- midx = sig->sb_to_idx(msb);
+ long lidx_tmp = sig->sb_to_idx(lsb);
+ long midx_tmp = sig->sb_to_idx(msb);
/* Detect reversed indices of a part select. */
- if (lidx > midx) {
+ if (lidx_tmp > midx_tmp) {
cerr << get_fileline() << ": error: Part select "
<< sig->name() << "[" << msb << ":"
<< lsb << "] indices reversed." << endl;
cerr << get_fileline() << ": : Did you mean "
<< sig->name() << "[" << lsb << ":"
<< msb << "]?" << endl;
- unsigned tmp = midx;
- midx = lidx;
- lidx = tmp;
+ long tmp = midx_tmp;
+ midx_tmp = lidx_tmp;
+ lidx_tmp = tmp;
des->errors += 1;
}
/* Detect a part select out of range. */
- if (midx >= sig->vector_width()) {
- cerr << get_fileline() << ": error: Part select "
+ if (midx_tmp >= (long)sig->vector_width() || lidx_tmp < 0) {
+ cerr << get_fileline() << ": warning: Part select "
<< sig->name() << "[" << msb << ":"
<< lsb << "] out of range." << endl;
- midx = sig->vector_width() - 1;
- lidx = 0;
+#if 0
+ midx_tmp = sig->vector_width() - 1;
+ lidx_tmp = 0;
des->errors += 1;
+#endif
}
+
+ midx = midx_tmp;
+ lidx = lidx_tmp;
break;
}
@@ -2494,7 +2587,7 @@ bool PEIdent::eval_part_select_(Design*des, NetScope*scope, NetNet*sig,
assert(mval);
midx = sig->sb_to_idx(mval->as_long());
- if (midx >= sig->vector_width()) {
+ if (midx >= (long)sig->vector_width()) {
cerr << get_fileline() << ": error: Index " << sig->name()
<< "[" << mval->as_long() << "] out of range."
<< endl;
@@ -2610,12 +2703,21 @@ NetNet* PEIdent::elaborate_lnet_common_(Design*des, NetScope*scope,
/* The array has a part/bit select at the end. */
if (name_tail.index.size() > sig->array_dimensions()) {
- if (! eval_part_select_(des, scope, sig, midx, lidx))
+ long midx_tmp, lidx_tmp;
+ if (! eval_part_select_(des, scope, sig, midx_tmp, lidx_tmp))
return 0;
+ ivl_assert(*this, lidx_tmp >= 0);
+ midx = midx_tmp;
+ lidx = lidx_tmp;
}
} else if (!name_tail.index.empty()) {
- if (! eval_part_select_(des, scope, sig, midx, lidx))
+ long midx_tmp, lidx_tmp;
+ if (! eval_part_select_(des, scope, sig, midx_tmp, lidx_tmp))
return 0;
+
+ ivl_assert(*this, lidx_tmp >= 0);
+ midx = midx_tmp;
+ lidx = lidx_tmp;
}
unsigned subnet_wid = midx-lidx+1;
@@ -2737,8 +2839,8 @@ NetNet* PEIdent::elaborate_port(Design*des, NetScope*scope) const
return 0;
}
- unsigned midx;
- unsigned lidx;
+ long midx;
+ long lidx;
/* Evaluate the part/bit select expressions, to get the part
select of the signal that attaches to the port. Also handle
View
@@ -648,7 +648,7 @@ bool NetNet::sb_is_valid(long sb) const
return (sb <= lsb_) && (sb >= msb_);
}
-unsigned NetNet::sb_to_idx(long sb) const
+long NetNet::sb_to_idx(long sb) const
{
if (msb_ >= lsb_)
return sb - lsb_;
View
@@ -510,7 +510,7 @@ class NetNet : public NetObj {
/* 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;
+ long sb_to_idx(long sb) const;
/* This method checks that the signed index is valid for this
signal. If it is, the above sb_to_idx can be used to get

0 comments on commit dfb7bf5

Please sign in to comment.