From 3556013eb167a93937b49702fe2fb26ee90f82c0 Mon Sep 17 00:00:00 2001 From: Jeffrey Song Date: Sun, 12 Jul 2026 19:44:16 -0700 Subject: [PATCH] Route std randomize through process RNG std::randomize used a private VlStdRandomizer RNG, so process::self().srandom(seed) did not make repeated std::randomize calls reproducible from the process seed. Use VlProcess::currentRng() for unconstrained and inline-constrained std::randomize paths. Keep the regression solver-independent for unconstrained scalar and 95-bit wide values. The harness adds a test-only define when a solver is available so the constrained-with path remains covered without skipping solverless builds. This change remains stacked on the preceding snprintf cleanup needed for --enable-ccwarn on macOS. Red: with the private RNG restored and solvers removed from PATH, t_std_randomize_process_seed failed its same-seed scalar comparison (got=-1251328343, exp=-1023341800). Green: solverless/no-define and solver-enabled/defined t_std_randomize_process_seed runs; t_std_randomize; t_std_randomize_with; t_process; t_randomize_inside_cond; t_dist_whitespace; t_dist_cppstyle; t_dist_copyright; cppcheck-runtime; lint-py-pylint-tests; clang-format-18; verilog_format; yapf; py_compile; git diff --check. --- include/verilated_random.h | 11 ++- .../t/t_std_randomize_process_seed.py | 20 ++++++ test_regress/t/t_std_randomize_process_seed.v | 67 +++++++++++++++++++ 3 files changed, 91 insertions(+), 7 deletions(-) create mode 100755 test_regress/t/t_std_randomize_process_seed.py create mode 100644 test_regress/t/t_std_randomize_process_seed.v diff --git a/include/verilated_random.h b/include/verilated_random.h index 964898713..bbcd3ba16 100644 --- a/include/verilated_random.h +++ b/include/verilated_random.h @@ -692,9 +692,6 @@ public: // Light wrapper for RNG used by std::randomize() to support scope-level randomization. class VlStdRandomizer final : public VlRandomizer { - // MEMBERS - VlRNG m_rng; // Random number generator - public: // CONSTRUCTORS VlStdRandomizer() = default; @@ -705,7 +702,7 @@ private: template typename std::enable_if::value, bool>::type basicStdRandomizationImpl(T& value, size_t width) { - VL_RANDOM_RNG_W(m_rng, width, value); + VL_RANDOM_RNG_W(VlProcess::currentRng(), width, value); // Mask off garbage bits in last word const int words = VL_WORDS_I(width); const int bitsInLastWord = width & VL_SIZEBITS_I; @@ -718,9 +715,9 @@ private: typename std::enable_if::value, bool>::type basicStdRandomizationImpl(T& value, size_t width) { if (width <= 32) { - value = VL_MASK_I(width) & VL_RANDOM_RNG_I(m_rng); + value = VL_MASK_I(width) & VL_RANDOM_RNG_I(VlProcess::currentRng()); } else { - value = VL_MASK_Q(width) & VL_RANDOM_RNG_Q(m_rng); + value = VL_MASK_Q(width) & VL_RANDOM_RNG_Q(VlProcess::currentRng()); } return true; } @@ -755,7 +752,7 @@ public: } return true; } - bool next() { return VlRandomizer::next(m_rng); } + bool next() { return VlRandomizer::next(VlProcess::currentRng()); } }; #endif // Guard diff --git a/test_regress/t/t_std_randomize_process_seed.py b/test_regress/t/t_std_randomize_process_seed.py new file mode 100755 index 000000000..22bb2884a --- /dev/null +++ b/test_regress/t/t_std_randomize_process_seed.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: std::randomize follows process RNG seeding +# +# 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") + +v_flags = ["+define+TEST_CONSTRAINT_SOLVER"] if test.have_solver else [] + +test.compile(v_flags2=v_flags, verilator_flags2=["--timing"]) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_std_randomize_process_seed.v b/test_regress/t/t_std_randomize_process_seed.v new file mode 100644 index 000000000..0424df65b --- /dev/null +++ b/test_regress/t/t_std_randomize_process_seed.v @@ -0,0 +1,67 @@ +// DESCRIPTION: Verilator: std::randomize follows process RNG seeding +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Wilson Snyder +// SPDX-License-Identifier: CC0-1.0 + +// verilog_format: off +`define stop $stop +`define checkd(gotv, expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__, `__LINE__, (gotv), (expv)); `stop; end while (0); +`define checkh(gotv, expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__, `__LINE__, (gotv), (expv)); `stop; end while (0); +// verilog_format: on + +module t; + typedef bit [94:0] wide_t; + + task automatic sample_after_process_seed(input int seed, output int scalar_values[4], + output wide_t wide_values[4]); + process p; + p = process::self(); + p.srandom(seed); + foreach (scalar_values[i]) begin + `checkd(std::randomize(scalar_values[i]), 1); + `checkd(std::randomize(wide_values[i]), 1); + end + endtask + +`ifdef TEST_CONSTRAINT_SOLVER + task automatic sample_with_after_process_seed(input int seed, output int values[4]); + process p; + p = process::self(); + p.srandom(seed); + foreach (values[i]) begin + `checkd(std::randomize(values[i]) with {values[i] inside {[32'h1000_0000 : 32'h7fff_ffff]};}, + 1); + end + endtask +`endif + + initial begin + int scalar_first[4]; + int scalar_second[4]; + wide_t wide_first[4]; + wide_t wide_second[4]; +`ifdef TEST_CONSTRAINT_SOLVER + int constrained_first[4]; + int constrained_second[4]; +`endif + + sample_after_process_seed(32'h1357_2468, scalar_first, wide_first); + sample_after_process_seed(32'h1357_2468, scalar_second, wide_second); + + foreach (scalar_first[i]) begin + `checkd(scalar_second[i], scalar_first[i]); + `checkh(wide_second[i], wide_first[i]); + end + +`ifdef TEST_CONSTRAINT_SOLVER + sample_with_after_process_seed(32'h1357_2468, constrained_first); + sample_with_after_process_seed(32'h1357_2468, constrained_second); + + foreach (constrained_first[i]) `checkd(constrained_second[i], constrained_first[i]); +`endif + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule