diff --git a/elab_lval.cc b/elab_lval.cc index 4f1859c43..f3858d86a 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -528,9 +528,8 @@ bool PEIdent::elaborate_lval_net_bit_(Design*des, bool need_const_idx, bool is_force) const { - listprefix_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 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::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(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. + listprefix_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 diff --git a/ivtest/ivltests/br_gh521.v b/ivtest/ivltests/br_gh521.v new file mode 100644 index 000000000..fb8bf40e2 --- /dev/null +++ b/ivtest/ivltests/br_gh521.v @@ -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 diff --git a/ivtest/regress-sv.list b/ivtest/regress-sv.list index ded8b92a1..76846780a 100644 --- a/ivtest/regress-sv.list +++ b/ivtest/regress-sv.list @@ -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