From f4654a451bc2eba472357e6818d03bdf007b6ee3 Mon Sep 17 00:00:00 2001 From: Yilou Wang Date: Wed, 26 Nov 2025 13:50:24 +0100 Subject: [PATCH] Support array reference arguments into 'std::randomize()' (#6384) (#6719) --- include/verilated_random.h | 35 +++++++++++++++++++++- src/V3Randomize.cpp | 7 +++-- src/V3Width.cpp | 2 +- test_regress/t/t_std_randomize.py | 7 ++++- test_regress/t/t_std_randomize.v | 49 +++++++++++++++++++++++-------- 5 files changed, 82 insertions(+), 18 deletions(-) diff --git a/include/verilated_random.h b/include/verilated_random.h index bd3a27442..0b68eadcf 100644 --- a/include/verilated_random.h +++ b/include/verilated_random.h @@ -590,9 +590,42 @@ public: VlStdRandomizer() = default; ~VlStdRandomizer() = default; +private: + // Wide type specialization (>64 bits) + template + typename std::enable_if::value, bool>::type + basicStdRandomizationImpl(T& value, size_t width) { + VL_RANDOM_RNG_W(m_rng, width, value); + // Mask off garbage bits in last word + const int words = VL_WORDS_I(width); + const int bitsInLastWord = width & VL_SIZEBITS_I; + if (bitsInLastWord) value.at(words - 1) &= VL_MASK_I(bitsInLastWord); + return true; + } + + // Scalar type specialization (<=64 bits) + template + 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); + } else { + value = VL_MASK_Q(width) & VL_RANDOM_RNG_Q(m_rng); + } + return true; + } + +public: + // Scalar/wide randomization template bool basicStdRandomization(T& value, size_t width) { - value = VL_MASK_I(width) & VL_RANDOM_RNG_I(m_rng); + return basicStdRandomizationImpl(value, width); + } + + // Unpacked array randomization + template + bool basicStdRandomization(VlUnpacked& value, size_t width) { + for (size_t i = 0; i < N_Depth; ++i) { basicStdRandomization(value.operator[](i), width); } return true; } bool next() { return VlRandomizer::next(m_rng); } diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 6ee477439..0c397538a 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -539,10 +539,11 @@ class RandomizeMarkVisitor final : public VNVisitor { randVarp = memberSelp->varp(); exprp = memberSelp->fromp(); } else { - AstVarRef* const varrefp = VN_AS(exprp, VarRef); + AstVarRef* varrefp = nullptr; + varrefp = VN_AS(exprp, VarRef); randVarp = varrefp->varp(); - exprp = nullptr; varrefp->user1(true); + exprp = nullptr; } UASSERT_OBJ(randVarp, nodep, "No rand variable found"); AstNode* backp = randVarp; @@ -2930,7 +2931,7 @@ AstFunc* V3Randomize::newRandomizeStdFunc(VMemberMap& memberMap, AstNodeModule* if (VN_IS(nodep, Class)) { funcp->classMethod(true); } else { - funcp->classMethod(false); + funcp->classMethod(true); funcp->isStatic(true); } nodep->addStmtsp(funcp); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index b63a7eef7..e06a9d914 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -6678,7 +6678,7 @@ class WidthVisitor final : public VNVisitor { // IEEE 1800-2023 (18.12) limits args to current scope variables. // Verilator accepts this for compatibility with other simulators. continue; - } else if (VN_IS(exprp, VarRef)) { + } else if (VN_IS(exprp, VarRef) || VN_IS(exprp, ArraySel)) { // Valid usage continue; } else { diff --git a/test_regress/t/t_std_randomize.py b/test_regress/t/t_std_randomize.py index 6815786ce..466368b3d 100755 --- a/test_regress/t/t_std_randomize.py +++ b/test_regress/t/t_std_randomize.py @@ -11,6 +11,11 @@ import vltest_bootstrap test.scenarios('simulator') -test.lint(verilator_flags2=["--binary"]) +if not test.have_solver: + test.skip("No constraint solver installed") + +test.compile() + +test.execute() test.passes() diff --git a/test_regress/t/t_std_randomize.v b/test_regress/t/t_std_randomize.v index d62656019..1a44dffa5 100644 --- a/test_regress/t/t_std_randomize.v +++ b/test_regress/t/t_std_randomize.v @@ -4,6 +4,9 @@ // any use, without warranty, 2025 by PlanV GmbH. // SPDX-License-Identifier: CC0-1.0 +`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); + class std_randomize_class; rand bit [7:0] addr; @@ -34,6 +37,12 @@ endclass module t_scope_std_randomize; bit [7:0] addr; bit [15:0] data; + int limit[10]; + bit [6:0] limit_7bits[10]; + bit [14:0] limit_15bits[10]; + bit [30:0] limit_31bits[10]; + bit [62:0] limit_63bits[10]; + bit [94:0] limit_95bits[10]; function bit run(); int ready; @@ -57,23 +66,39 @@ module t_scope_std_randomize; std_randomize_class test; initial begin - bit ok = 0; - int success; - + // Test class member randomization test = new(); test.old_addr = test.addr; test.old_data = test.data; test.old_data_x_4 = test.data_x_4; - success = std::randomize(test.addr, test.data); - ok = (success == 1) && !(test.addr == test.old_addr || test.data == test.old_data) && test.data_x_4 == test.old_data_x_4; - if (!ok) $stop; + `checkd(std::randomize(test.addr, test.data), 1); + if (test.addr == test.old_addr && test.data == test.old_data) $stop; + `checkd(test.data_x_4, test.old_data_x_4); - ok = 0; - ok = run(); - if (!ok) $stop; - ok = 0; - ok = test.std_randomize(); - if (!ok) $stop; + // Test function-based randomization + `checkd(run(), 1); + `checkd(test.std_randomize(), 1); + + // Test array randomization with constraints + /* verilator lint_off WIDTHEXPAND */ + `checkd(std::randomize(limit) with { foreach (limit[i]) { limit[i] < 100;}}, 1); + foreach (limit[i]) if (limit[i] >= 100) $stop; + + `checkd(std::randomize(limit_7bits) with { foreach (limit_7bits[i]) { limit_7bits[i] < 10;}}, 1); + foreach (limit_7bits[i]) if (limit_7bits[i] >= 10) $stop; + + `checkd(std::randomize(limit_15bits) with { foreach (limit_15bits[i]) { limit_15bits[i] < 1000;}}, 1); + foreach (limit_15bits[i]) if (limit_15bits[i] >= 1000) $stop; + + `checkd(std::randomize(limit_31bits) with { foreach (limit_31bits[i]) { limit_31bits[i] < 100000;}}, 1); + foreach (limit_31bits[i]) if (limit_31bits[i] >= 100000) $stop; + + `checkd(std::randomize(limit_63bits) with { foreach (limit_63bits[i]) { limit_63bits[i] < 64'd10000000000;}}, 1); + foreach (limit_63bits[i]) if (limit_63bits[i] >= 64'd10000000000) $stop; + + `checkd(std::randomize(limit_95bits) with { foreach (limit_95bits[i]) { limit_95bits[i] < 96'd1000000000000;}}, 1); + foreach (limit_95bits[i]) if (limit_95bits[i] >= 96'd1000000000000) $stop; + /* verilator lint_on WIDTHEXPAND */ $write("*-* All Finished *-*\n"); $finish;