Support array reference arguments into 'std::randomize()' (#6384) (#6719)

This commit is contained in:
Yilou Wang 2025-11-26 13:50:24 +01:00 committed by GitHub
parent 8293a8d035
commit f4654a451b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 82 additions and 18 deletions

View File

@ -590,9 +590,42 @@ public:
VlStdRandomizer() = default;
~VlStdRandomizer() = default;
private:
// Wide type specialization (>64 bits)
template <typename T>
typename std::enable_if<VlIsVlWide<T>::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 T>
typename std::enable_if<!VlIsVlWide<T>::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 <typename T>
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 <typename T_Unpacked, std::size_t N_Depth>
bool basicStdRandomization(VlUnpacked<T_Unpacked, N_Depth>& 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); }

View File

@ -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);

View File

@ -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 {

View File

@ -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()

View File

@ -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;