Fix #521: Allow variable indices in outer packed dimensions

In multi-dimensional packed arrays, allow variable indices in the outer
(prefix) dimensions, not just the final dimension. For example:

  logic [3:0][3:0] a;
  for (int i=0; i<4; i++)
    a[i][3] = 1;  // Previously error, now works

The fix checks if any packed prefix indices are non-constant. If so,
use collapse_array_exprs() to compute the bit offset as an expression
rather than requiring constant indices.

This removes an artificial restriction that had no justification in
the IEEE standard, as noted by maintainers in the GitHub issue.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Andrew Pullin 2026-01-23 14:43:03 -08:00
parent 68633814d1
commit 54dfd0a702
3 changed files with 82 additions and 5 deletions

View File

@ -528,9 +528,8 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
bool need_const_idx,
bool is_force) const
{
list<long>prefix_indices;
bool rc = calculate_packed_indices_(des, scope, lv->sig(), prefix_indices);
if (!rc) return false;
NetNet*reg = lv->sig();
ivl_assert(*this, reg);
const name_component_t&name_tail = path_.back();
ivl_assert(*this, !name_tail.index.empty());
@ -539,8 +538,66 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des,
ivl_assert(*this, index_tail.msb != 0);
ivl_assert(*this, index_tail.lsb == 0);
NetNet*reg = lv->sig();
ivl_assert(*this, reg);
// First, check if packed prefix indices contain any variable expressions.
// Build the list of packed indices (excluding unpacked dimensions).
list<index_component_t> packed_index;
packed_index = name_tail.index;
for (size_t idx = 0 ; idx < reg->unpacked_dimensions() ; idx += 1)
packed_index.pop_front();
// For multi-dimensional packed arrays, check if the prefix indices
// (all but the final) contain any non-constant expressions.
bool has_variable_prefix = false;
if (packed_index.size() > 1) {
list<index_component_t>::const_iterator icur = packed_index.begin();
for (size_t idx = 0 ; (idx+1) < packed_index.size() ; idx += 1, ++icur) {
NetExpr*texpr = elab_and_eval(des, scope, icur->msb, -1, false);
if (texpr == 0 || !dynamic_cast<NetEConst*>(texpr)) {
has_variable_prefix = true;
}
delete texpr;
if (has_variable_prefix) break;
}
}
// If prefix indices are variable, handle using expression-based path.
if (has_variable_prefix) {
if (need_const_idx) {
cerr << get_fileline() << ": error: '" << reg->name()
<< "' index must be a constant in this context."
<< endl;
des->errors += 1;
return false;
}
if ((reg->type()==NetNet::UNRESOLVED_WIRE) && !is_force) {
ivl_assert(*this, reg->coerced_to_uwire());
report_mixed_assignment_conflict_("bit select");
des->errors += 1;
return false;
}
// Use collapse_array_exprs to compute the bit offset as an expression.
NetExpr*base_expr = collapse_array_exprs(des, scope, this, reg, packed_index);
if (base_expr == 0) {
des->errors += 1;
return false;
}
if (debug_elaborate) {
cerr << get_fileline() << ": PEIdent::elaborate_lval_net_bit_: "
<< "Variable packed prefix, base_expr=" << *base_expr
<< endl;
}
lv->set_part(base_expr, 1);
return true;
}
// All prefix indices are constant. Use the existing code path.
list<long>prefix_indices;
bool rc = calculate_packed_indices_(des, scope, reg, prefix_indices);
if (!rc) return false;
// Bit selects have a single select expression. Evaluate the
// constant value and treat it as a part select with a bit

View File

@ -0,0 +1,19 @@
// Test for GitHub issue #521
// Loop index should be allowed in outer dimension of multi-dimensional packed arrays
module test;
logic [3:0][3:0] a;
initial begin
a = 0;
for (int i=0; i<4; i++)
a[i][3] = 1;
// Each 4-bit sub-array has bit 3 set to 1, so each nibble is 0x8
if (a !== 16'h8888) begin
$display("FAILED: a = %h, expected 8888", a);
$finish;
end
$display("PASSED");
end
endmodule

View File

@ -212,6 +212,7 @@ br_gh477 normal,-g2009 ivltests
br_gh478 normal,-g2009 ivltests
br_gh498 normal,-g2009 ivltests
br_gh508a normal,-g2009 ivltests
br_gh521 normal,-g2012 ivltests
br_gh527 normal,-g2009 ivltests
br_gh530 CO,-g2009 ivltests
br_gh540 normal,-g2009 ivltests