mirror of
https://github.com/verilator/verilator.git
synced 2025-01-01 04:07:34 +00:00
Fix randomize treated as std::randomize in classes (#5436)
This commit is contained in:
parent
2f690c0530
commit
ef259f63ca
@ -69,6 +69,7 @@
|
||||
#include "V3Graph.h"
|
||||
#include "V3MemberMap.h"
|
||||
#include "V3Parse.h"
|
||||
#include "V3Randomize.h"
|
||||
#include "V3String.h"
|
||||
#include "V3SymTable.h"
|
||||
|
||||
@ -1103,11 +1104,18 @@ class LinkDotFindVisitor final : public VNVisitor {
|
||||
VL_RESTORER(m_curSymp);
|
||||
VSymEnt* upSymp = m_curSymp;
|
||||
{
|
||||
if (VN_IS(m_curSymp->nodep(), Class)
|
||||
&& VN_AS(m_curSymp->nodep(), Class)->isInterfaceClass() && !nodep->pureVirtual()
|
||||
&& !nodep->isConstructor()) {
|
||||
nodep->v3error("Interface class functions must be pure virtual"
|
||||
<< " (IEEE 1800-2023 8.26): " << nodep->prettyNameQ());
|
||||
if (VN_IS(m_curSymp->nodep(), Class)) {
|
||||
if (VN_AS(m_curSymp->nodep(), Class)->isInterfaceClass() && !nodep->pureVirtual()
|
||||
&& !nodep->isConstructor()) {
|
||||
nodep->v3error("Interface class functions must be pure virtual"
|
||||
<< " (IEEE 1800-2023 8.26): " << nodep->prettyNameQ());
|
||||
}
|
||||
if (m_statep->forPrimary()
|
||||
&& (nodep->name() == "randomize" || nodep->name() == "srandom")) {
|
||||
nodep->v3error(nodep->prettyNameQ()
|
||||
<< " is a predefined class method; redefinition not allowed"
|
||||
" (IEEE 1800-2023 18.6.3)");
|
||||
}
|
||||
}
|
||||
// Change to appropriate package if extern declaration (vs definition)
|
||||
if (nodep->classOrPackagep()) {
|
||||
@ -3409,6 +3417,14 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (first && nodep->name() == "randomize" && VN_IS(m_modp, Class)) {
|
||||
// need special handling to avoid falling back to std::randomize
|
||||
VMemberMap memberMap;
|
||||
AstFunc* const randFuncp = V3Randomize::newRandomizeFunc(
|
||||
memberMap, VN_AS(m_modp, Class), nodep->name(), true, true);
|
||||
nodep->taskp(randFuncp);
|
||||
m_curSymp = m_statep->insertBlock(m_curSymp, nodep->name(), randFuncp, m_modp);
|
||||
}
|
||||
VSymEnt* const foundp
|
||||
= m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot, first);
|
||||
AstNodeFTask* const taskp
|
||||
|
@ -113,14 +113,7 @@ class LinkResolveVisitor final : public VNVisitor {
|
||||
// NodeTask: Remember its name for later resolution
|
||||
if (m_underGenerate) nodep->underGenerate(true);
|
||||
// Remember the existing symbol table scope
|
||||
if (m_classp) {
|
||||
if (nodep->name() == "randomize" || nodep->name() == "srandom") {
|
||||
nodep->v3error(nodep->prettyNameQ()
|
||||
<< " is a predefined class method; redefinition not allowed"
|
||||
" (IEEE 1800-2023 18.6.3)");
|
||||
}
|
||||
nodep->classMethod(true);
|
||||
}
|
||||
if (m_classp) nodep->classMethod(true);
|
||||
// V3LinkDot moved the isExternDef into the class, the extern proto was
|
||||
// checked to exist, and now isn't needed
|
||||
nodep->isExternDef(false);
|
||||
|
@ -1706,6 +1706,7 @@ class RandomizeVisitor final : public VNVisitor {
|
||||
iterateChildren(nodep);
|
||||
if (!nodep->user1()) return; // Doesn't need randomize, or already processed
|
||||
UINFO(9, "Define randomize() for " << nodep << endl);
|
||||
nodep->baseMostClassp()->needRNG(true);
|
||||
AstFunc* const randomizep = V3Randomize::newRandomizeFunc(m_memberMap, nodep);
|
||||
AstVar* const fvarp = VN_AS(randomizep->fvarp(), Var);
|
||||
addPrePostCall(nodep, randomizep, "pre_randomize");
|
||||
@ -2027,26 +2028,30 @@ void V3Randomize::randomizeNetlist(AstNetlist* nodep) {
|
||||
}
|
||||
|
||||
AstFunc* V3Randomize::newRandomizeFunc(VMemberMap& memberMap, AstClass* nodep,
|
||||
const std::string& name, bool allowVirtual) {
|
||||
const std::string& name, bool allowVirtual,
|
||||
bool childDType) {
|
||||
AstFunc* funcp = VN_AS(memberMap.findMember(nodep, name), Func);
|
||||
if (!funcp) {
|
||||
v3Global.useRandomizeMethods(true);
|
||||
AstNodeDType* const dtypep
|
||||
= nodep->findBitDType(32, 32, VSigning::SIGNED); // IEEE says int return of 0/1
|
||||
AstVar* const fvarp = new AstVar{nodep->fileline(), VVarType::MEMBER, name, dtypep};
|
||||
= childDType
|
||||
? new AstBasicDType{nodep->fileline(), VBasicDTypeKwd::INT}
|
||||
: nodep->findBitDType(32, 32, VSigning::SIGNED); // IEEE says int return of 0/1
|
||||
AstVar* const fvarp = childDType
|
||||
? new AstVar{nodep->fileline(), VVarType::MEMBER, name,
|
||||
VFlagChildDType{}, dtypep}
|
||||
: new AstVar{nodep->fileline(), VVarType::MEMBER, name, dtypep};
|
||||
fvarp->lifetime(VLifetime::AUTOMATIC);
|
||||
fvarp->funcLocal(true);
|
||||
fvarp->funcReturn(true);
|
||||
fvarp->direction(VDirection::OUTPUT);
|
||||
nodep->addMembersp(funcp);
|
||||
funcp = new AstFunc{nodep->fileline(), name, nullptr, fvarp};
|
||||
funcp->dtypep(dtypep);
|
||||
if (!childDType) funcp->dtypep(dtypep);
|
||||
funcp->classMethod(true);
|
||||
funcp->isVirtual(allowVirtual && nodep->isExtended());
|
||||
nodep->addMembersp(funcp);
|
||||
memberMap.insert(nodep, funcp);
|
||||
AstClass* const basep = nodep->baseMostClassp();
|
||||
basep->needRNG(true);
|
||||
}
|
||||
return funcp;
|
||||
}
|
||||
|
@ -32,7 +32,8 @@ public:
|
||||
|
||||
static AstFunc* newRandomizeFunc(VMemberMap& memberMap, AstClass* nodep,
|
||||
const std::string& name = "randomize",
|
||||
bool allowVirtual = true) VL_MT_DISABLED;
|
||||
bool allowVirtual = true,
|
||||
bool childDType = false) VL_MT_DISABLED;
|
||||
static AstFunc* newSRandomFunc(VMemberMap& memberMap, AstClass* nodep) VL_MT_DISABLED;
|
||||
};
|
||||
|
||||
|
@ -6025,7 +6025,6 @@ class WidthVisitor final : public VNVisitor {
|
||||
}
|
||||
UASSERT_OBJ(classp, nodep, "Should have failed in V3LinkDot");
|
||||
if (nodep->name() == "randomize") {
|
||||
nodep->taskp(V3Randomize::newRandomizeFunc(m_memberMap, classp));
|
||||
AstClassRefDType* const adtypep
|
||||
= new AstClassRefDType{nodep->fileline(), classp, nullptr};
|
||||
v3Global.rootp()->typeTablep()->addTypesp(adtypep);
|
||||
|
18
test_regress/t/t_randomize_method_std.py
Executable file
18
test_regress/t/t_randomize_method_std.py
Executable file
@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2024 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()
|
22
test_regress/t/t_randomize_method_std.v
Normal file
22
test_regress/t/t_randomize_method_std.v
Normal file
@ -0,0 +1,22 @@
|
||||
// DESCRIPTION: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2024 by Antmicro Ltd.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
process p; // force importing std into top-level namespace
|
||||
|
||||
class C;
|
||||
function new;
|
||||
if (randomize() != 1) $stop;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
initial begin
|
||||
C c = new;
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user