From 128c621e8540b0a68145094fa876dc5de073c9a6 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 19 Jun 2026 21:43:33 -0700 Subject: [PATCH 1/2] Fix width calculation for packed array bounds Variable select base normalization extends the base expression to cover the packed array bounds. The current code compared min_wid against num_bits() of each bound, but then assigned the bound value itself to min_wid. For positive bounds this can make the generated index expression much wider than required. For negative bounds the effect is much worse since min_wid is unsigned. Assigning a negative bound converts it to a huge width, causing elaboration to try to pad the expression to that size and abort or run out of memory for otherwise valid variable selects. Use the bit width of the bound instead of the bound value. Signed-off-by: Lars-Peter Clausen --- netmisc.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/netmisc.cc b/netmisc.cc index a5af12d76..2ace3f59e 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -423,8 +423,10 @@ NetExpr *normalize_variable_slice_base(const list&indices, NetExpr*base, unsigned min_wid = base->expr_width(); if ((sb < 0) && !base->has_sign()) min_wid += 1; - if (min_wid < num_bits(pcur->get_lsb())) min_wid = pcur->get_lsb(); - if (min_wid < num_bits(pcur->get_msb())) min_wid = pcur->get_msb(); + if (min_wid < num_bits(pcur->get_lsb())) + min_wid = num_bits(pcur->get_lsb()); + if (min_wid < num_bits(pcur->get_msb())) + min_wid = num_bits(pcur->get_msb()); base = pad_to_width(base, min_wid, *base); if ((sb < 0) && !base->has_sign()) { NetESelect *tmp = new NetESelect(base, 0 , min_wid); From 6326c5b1babc6d6d6d782b7cbc6780d705609d42 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Fri, 19 Jun 2026 21:43:57 -0700 Subject: [PATCH 2/2] Add regression test for negative packed array bounds Check that variable selects of a packed array with negative bounds use the correct index width and can read back assigned elements. Signed-off-by: Lars-Peter Clausen --- .../ivltests/sv_partsel_var_negative_packed.v | 33 +++++++++++++++++++ ivtest/regress-vvp.list | 1 + .../sv_partsel_var_negative_packed.json | 8 +++++ 3 files changed, 42 insertions(+) create mode 100644 ivtest/ivltests/sv_partsel_var_negative_packed.v create mode 100644 ivtest/vvp_tests/sv_partsel_var_negative_packed.json diff --git a/ivtest/ivltests/sv_partsel_var_negative_packed.v b/ivtest/ivltests/sv_partsel_var_negative_packed.v new file mode 100644 index 000000000..bf9a28720 --- /dev/null +++ b/ivtest/ivltests/sv_partsel_var_negative_packed.v @@ -0,0 +1,33 @@ +// Check variable selects of packed arrays with negative bounds. + +module test; + + reg failed; + reg [-8:-1][3:0] a; + reg signed [2:0] i; + + `define check(val, exp) \ + if (val !== exp) begin \ + $display("FAILED(%0d). '%s' expected %b, got %b", `__LINE__, \ + `"val`", exp, val); \ + failed = 1'b1; \ + end + + initial begin + failed = 1'b0; + a = '0; + + i = -1; + a[i] = 4'ha; + i = -2; + a[i] = 4'h5; + + `check(a[-1], 4'ha); + `check(a[-2], 4'h5); + + if (!failed) begin + $display("PASSED"); + end + end + +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index e17f69eee..1611df5d0 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -352,6 +352,7 @@ sv_net_decl_assign vvp_tests/sv_net_decl_assign.json sv_package_lifetime vvp_tests/sv_package_lifetime.json sv_package_lifetime_fail vvp_tests/sv_package_lifetime_fail.json sv_parameter_type vvp_tests/sv_parameter_type.json +sv_partsel_var_negative_packed vvp_tests/sv_partsel_var_negative_packed.json sv_queue_ap_method vvp_tests/sv_queue_ap_method.json sv_queue_assign_op vvp_tests/sv_queue_assign_op.json sv_queue_method_insert_too_few_arg_fail vvp_tests/sv_queue_method_insert_too_few_arg_fail.json diff --git a/ivtest/vvp_tests/sv_partsel_var_negative_packed.json b/ivtest/vvp_tests/sv_partsel_var_negative_packed.json new file mode 100644 index 000000000..0d0e5f9d2 --- /dev/null +++ b/ivtest/vvp_tests/sv_partsel_var_negative_packed.json @@ -0,0 +1,8 @@ +{ + "type" : "normal", + "source" : "sv_partsel_var_negative_packed.v", + "iverilog-args" : [ "-g2005-sv" ], + "vlog95" : { + "iverilog-args" : [ "-pallowsigned=1" ] + } +}