diff --git a/Changes b/Changes index 0013c80da..89dcee298 100644 --- a/Changes +++ b/Changes @@ -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] diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index f13b07e09..815a598a7 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -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); diff --git a/test_regress/t/t_randomize_inline_funclocal.py b/test_regress/t/t_randomize_inline_funclocal.py new file mode 100755 index 000000000..f989a35fb --- /dev/null +++ b/test_regress/t/t_randomize_inline_funclocal.py @@ -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() diff --git a/test_regress/t/t_randomize_inline_funclocal.v b/test_regress/t/t_randomize_inline_funclocal.v new file mode 100644 index 000000000..12940c650 --- /dev/null +++ b/test_regress/t/t_randomize_inline_funclocal.v @@ -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