diff --git a/elab_expr.cc b/elab_expr.cc index fa8b3368a..251a7189c 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -3668,8 +3668,35 @@ NetExpr* PEIdent::elaborate_expr_net_part_(Design*des, NetScope*scope, tmp->set_line(*this); return tmp; } - long sb_lsb = net->sig()->sb_to_idx(prefix_indices, lsv); - long sb_msb = net->sig()->sb_to_idx(prefix_indices, msv); + long sb_lsb, sb_msb; + if (prefix_indices.size()+1 < net->sig()->packed_dims().size()) { + // Here we have a slice that doesn't have enough indices + // to get to a single slice. For example: + // wire [9:0][5:1] foo + // ... foo[4:3] ... + // Make this work by finding the indexed slices and + // creating a generated slice that spans the whole + // range. + long loff, moff; + unsigned long lwid, mwid; + bool lrc; + lrc = net->sig()->sb_to_slice(prefix_indices, lsv, loff, lwid); + lrc = net->sig()->sb_to_slice(prefix_indices, msv, moff, mwid); + + if (moff > loff) { + sb_lsb = loff; + sb_msb = moff + mwid - 1; + } else { + sb_lsb = moff; + sb_msb = loff + lwid - 1; + } + } else { + // This case, the prefix indices are enough to index + // down to a single bit/slice. + ivl_assert(*this, prefix_indices.size()+1 == net->sig()->packed_dims().size()); + sb_lsb = net->sig()->sb_to_idx(prefix_indices, lsv); + sb_msb = net->sig()->sb_to_idx(prefix_indices, msv); + } if (sb_msb < sb_lsb) { cerr << get_fileline() << ": error: part select " << net->name(); diff --git a/elab_lval.cc b/elab_lval.cc index 5dd5d9a8f..9e3e9776c 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -560,25 +560,38 @@ bool PEIdent::elaborate_lval_net_part_(Design*des, const vector&packed = reg->packed_dims(); - // Part selects cannot select slices. So there must be enough - // prefix_indices to get all the way to the final dimension. + long loff, moff; + long wid; if (prefix_indices.size()+1 < packed.size()) { - cerr << get_fileline() << ": error: Cannot select a range " - << "of slices from a packed array." << endl; - des->errors += 1; - return false; - } + // If there are fewer indices then there are packed + // dimensions, then this is a range of slices. Calculate + // it into a big slice. + bool lrc; + unsigned long tmp_lwid, tmp_mwid; + lrc = reg->sb_to_slice(prefix_indices,lsb, loff, tmp_lwid); + lrc = reg->sb_to_slice(prefix_indices,msb, moff, tmp_mwid); - long loff = reg->sb_to_idx(prefix_indices,lsb); - long moff = reg->sb_to_idx(prefix_indices,msb); - long wid = moff - loff + 1; + if (loff < moff) { + moff = moff + tmp_mwid - 1; + } else { + long ltmp = moff; + moff = loff + tmp_lwid - 1; + loff = ltmp; + } + wid = moff - loff + 1; - if (moff < loff) { - cerr << get_fileline() << ": error: part select " - << reg->name() << "[" << msb<<":"<errors += 1; - return false; + } else { + loff = reg->sb_to_idx(prefix_indices,lsb); + moff = reg->sb_to_idx(prefix_indices,msb); + wid = moff - loff + 1; + + if (moff < loff) { + cerr << get_fileline() << ": error: part select " + << reg->name() << "[" << msb<<":"<errors += 1; + return false; + } } // Special case: The range winds up selecting the entire