diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 6ddd0d783..6ab50c073 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -2120,10 +2120,14 @@ class ConstraintExprVisitor final : public VNVisitor { FileLine* const fl = nodep->fileline(); VNRelinker handle; // Check if index actually references a rand variable (not just user1, - // which can be over-marked in sum/with expansion contexts) + // which can be over-marked in sum/with expansion contexts). A + // std::randomize() with-clause argument carries no rand qualifier of + // its own but is still part of the solve. bool indexIsRand = false; nodep->bitp()->foreach([&](const AstNodeVarRef* vrefp) { - if (vrefp->varp()->rand().isRandomizable()) indexIsRand = true; + if (vrefp->varp()->rand().isRandomizable() || vrefp->varp()->isStdRandomizeArg()) { + indexIsRand = true; + } }); if (indexIsRand) { // Index depends on rand variable -- keep as SMT symbol. @@ -2631,10 +2635,15 @@ class ConstraintExprVisitor final : public VNVisitor { if (nodep->method() == VCMethod::ARRAY_AT && nodep->fromp()->user1()) { // Queue/dynamic element: pre-edit clone for the rand_mode hoist, non-rand index only. + // A std::randomize() with-clause argument carries no rand qualifier + // of its own but is still part of the solve. bool indexIsRand = false; if (nodep->pinsp()) { nodep->pinsp()->foreach([&](const AstNodeVarRef* vrefp) { - if (vrefp->varp()->rand().isRandomizable()) indexIsRand = true; + if (vrefp->varp()->rand().isRandomizable() + || vrefp->varp()->isStdRandomizeArg()) { + indexIsRand = true; + } }); } AstNodeExpr* const origp = indexIsRand ? nullptr : nodep->cloneTree(false); diff --git a/test_regress/t/t_randomize_std_array_index.py b/test_regress/t/t_randomize_std_array_index.py new file mode 100755 index 000000000..db1adb3f9 --- /dev/null +++ b/test_regress/t/t_randomize_std_array_index.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of either the GNU Lesser General Public License Version 3 +# or the Perl Artistic License Version 2.0. +# SPDX-FileCopyrightText: 2026 Wilson Snyder +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +if not test.have_solver: + test.skip("No constraint solver installed") + +test.compile() + +test.execute() + +test.passes() diff --git a/test_regress/t/t_randomize_std_array_index.v b/test_regress/t/t_randomize_std_array_index.v new file mode 100644 index 000000000..e6ee27ddf --- /dev/null +++ b/test_regress/t/t_randomize_std_array_index.v @@ -0,0 +1,41 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Aditya Shevade +// SPDX-License-Identifier: CC0-1.0 + +// A std::randomize() with-clause argument used as an index has no rand +// qualifier of its own, but must still be treated as part of the solve. + +module t; + bit [7:0] probe[2]; + bit [7:0] cube[4][2]; + bit [7:0] p0; + bit [7:0] q[$]; + int i; + int ok; + + initial begin + repeat (30) begin + ok = std::randomize(probe, cube, i) with { i inside {[0:3]}; probe == cube[i]; }; + if (ok != 1) $stop; + if (probe != cube[i]) $stop; + end + + repeat (30) begin + ok = std::randomize(p0, cube, i) with { i inside {[0:3]}; p0 == cube[i][0]; }; + if (ok != 1) $stop; + if (p0 != cube[i][0]) $stop; + end + + repeat (30) begin + q = {8'h1, 8'h2, 8'h3, 8'h4}; + ok = std::randomize(p0, q, i) with { i inside {[0:3]}; p0 == q[i]; }; + if (ok != 1) $stop; + if (p0 != q[i]) $stop; + end + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule