Fix randomize on function-local variable (#6234).

This commit is contained in:
Wilson Snyder 2025-08-27 21:25:40 -04:00
parent 54efa86a6c
commit e32108713d
4 changed files with 66 additions and 2 deletions

View File

@ -75,6 +75,7 @@ Verilator 5.039 devel
* Fix `--stats` overridden by skipping identical build (#6220). [Geza Lore]
* Fix MODDUP with duplicate packages to take first package (#6222).
* Fix replicate with unsigned count but MSB set (#6231) (#6233). [Geza Lore]
* Fix randomize on function-local variable (#6234).
* Fix queue typedef with unbounded slice (#6236).
* Fix error when force assignment is used with ref function args (#6244). [Ryszard Rozak, Antmicro Ltd.]
* Fix write of 0 in '%c' (#6248) (#6249). [Rodrigo Batista de Moraes]

View File

@ -1373,6 +1373,7 @@ class RandomizeVisitor final : public VNVisitor {
AstVar* const stdgenp
= new AstVar{modp->fileline(), VVarType::MEMBER, "stdrand",
modp->findBasicDType(VBasicDTypeKwd::RANDOM_STDGENERATOR)};
stdgenp->fileline()->warnOff(V3ErrorCode::IMPURE, true);
modp->addStmtsp(stdgenp);
m_stdMap.emplace(modp, stdgenp);
return stdgenp;
@ -2283,6 +2284,8 @@ class RandomizeVisitor final : public VNVisitor {
if (nodep->name() != "randomize") return;
if (nodep->classOrPackagep() && nodep->classOrPackagep()->name() == "std") {
// Handle std::randomize; create wrapper function that calls basicStdRandomization on
// each varref argument, then transform nodep to call that wrapper
AstVar* const stdrand = createStdRandomGenerator(m_modp);
AstFunc* const randomizeFuncp = V3Randomize::newRandomizeStdFunc(
m_memberMap, m_modp, m_inlineUniqueStdName.get(nodep));
@ -2291,19 +2294,32 @@ class RandomizeVisitor final : public VNVisitor {
new AstVarRef{nodep->fileline(), VN_AS(randomizeFuncp->fvarp(), Var),
VAccess::WRITE},
new AstConst{nodep->fileline(), AstConst::WidthedValue{}, 32, 1}});
int argn = 0;
for (AstNode* pinp = nodep->pinsp(); pinp; pinp = pinp->nextp()) {
AstArg* const argp = VN_CAST(pinp, Arg);
if (!argp) continue;
AstNodeExpr* exprp = argp->exprp();
AstCMethodHard* const basicMethodp = new AstCMethodHard{
nodep->fileline(),
new AstVarRef{nodep->fileline(), stdrand, VAccess::READWRITE},
"basicStdRandomization"};
AstVar* const refvarp
= new AstVar{exprp->fileline(), VVarType::MEMBER,
"__Varg"s + std::to_string(++argn), exprp->dtypep()};
refvarp->direction(VDirection::REF);
refvarp->funcLocal(true);
refvarp->lifetime(VLifetime::AUTOMATIC);
randomizeFuncp->addStmtsp(refvarp);
const size_t width = exprp->width();
basicMethodp->addPinsp(exprp->unlinkFrBack());
basicMethodp->addPinsp(
new AstVarRef{exprp->fileline(), refvarp, VAccess::READWRITE});
basicMethodp->addPinsp(
new AstConst{nodep->fileline(), AstConst::Unsized64{}, width});
basicMethodp->dtypeSetBit();
randomizeFuncp->addStmtsp(new AstAssign{
nodep->fileline(),
new AstVarRef{nodep->fileline(), VN_AS(randomizeFuncp->fvarp(), Var),
@ -2318,7 +2334,8 @@ class RandomizeVisitor final : public VNVisitor {
nodep->taskp(randomizeFuncp);
nodep->dtypeFrom(randomizeFuncp->dtypep());
if (VN_IS(m_modp, Class)) nodep->classOrPackagep(m_modp);
if (nodep->pinsp()) pushDeletep(nodep->pinsp()->unlinkFrBackWithNext());
UINFOTREE(9, nodep, "", "std::rnd-call");
UINFOTREE(9, randomizeFuncp, "", "std::rnd-func");
return;
}
handleRandomizeArgs(nodep);

View File

@ -0,0 +1,18 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2025 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
test.scenarios('simulator')
test.compile()
test.execute()
test.passes()

View File

@ -0,0 +1,28 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2025 by Wilson Snyder.
// SPDX-License-Identifier: CC0-1.0
class Cls;
function int do_randomize();
int flocal, success;
success = std::randomize(flocal);
if (success !== 1) $stop;
do_randomize = flocal;
endfunction
endclass
module t;
int r1, r2, r3;
initial begin
Cls c;
c = new;
r1 = c.do_randomize();
r2 = c.do_randomize();
r3 = c.do_randomize();
$display("%x %x %x", r1, r2, r3);
if (r1 == r2 && r2 == r3) $stop; // Not impossible but 2^63 odds of failure
$finish;
end
endmodule