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:
parent
68633814d1
commit
54dfd0a702
67
elab_lval.cc
67
elab_lval.cc
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue