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 "V3Graph.h"
|
||||||
#include "V3MemberMap.h"
|
#include "V3MemberMap.h"
|
||||||
#include "V3Parse.h"
|
#include "V3Parse.h"
|
||||||
|
#include "V3Randomize.h"
|
||||||
#include "V3String.h"
|
#include "V3String.h"
|
||||||
#include "V3SymTable.h"
|
#include "V3SymTable.h"
|
||||||
|
|
||||||
|
|
@ -1103,12 +1104,19 @@ class LinkDotFindVisitor final : public VNVisitor {
|
||||||
VL_RESTORER(m_curSymp);
|
VL_RESTORER(m_curSymp);
|
||||||
VSymEnt* upSymp = m_curSymp;
|
VSymEnt* upSymp = m_curSymp;
|
||||||
{
|
{
|
||||||
if (VN_IS(m_curSymp->nodep(), Class)
|
if (VN_IS(m_curSymp->nodep(), Class)) {
|
||||||
&& VN_AS(m_curSymp->nodep(), Class)->isInterfaceClass() && !nodep->pureVirtual()
|
if (VN_AS(m_curSymp->nodep(), Class)->isInterfaceClass() && !nodep->pureVirtual()
|
||||||
&& !nodep->isConstructor()) {
|
&& !nodep->isConstructor()) {
|
||||||
nodep->v3error("Interface class functions must be pure virtual"
|
nodep->v3error("Interface class functions must be pure virtual"
|
||||||
<< " (IEEE 1800-2023 8.26): " << nodep->prettyNameQ());
|
<< " (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)
|
// Change to appropriate package if extern declaration (vs definition)
|
||||||
if (nodep->classOrPackagep()) {
|
if (nodep->classOrPackagep()) {
|
||||||
AstClassOrPackageRef* const cpackagerefp
|
AstClassOrPackageRef* const cpackagerefp
|
||||||
|
|
@ -3409,6 +3417,14 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||||
return;
|
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
|
VSymEnt* const foundp
|
||||||
= m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot, first);
|
= m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot, first);
|
||||||
AstNodeFTask* const taskp
|
AstNodeFTask* const taskp
|
||||||
|
|
|
||||||
|
|
@ -113,14 +113,7 @@ class LinkResolveVisitor final : public VNVisitor {
|
||||||
// NodeTask: Remember its name for later resolution
|
// NodeTask: Remember its name for later resolution
|
||||||
if (m_underGenerate) nodep->underGenerate(true);
|
if (m_underGenerate) nodep->underGenerate(true);
|
||||||
// Remember the existing symbol table scope
|
// Remember the existing symbol table scope
|
||||||
if (m_classp) {
|
if (m_classp) nodep->classMethod(true);
|
||||||
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);
|
|
||||||
}
|
|
||||||
// V3LinkDot moved the isExternDef into the class, the extern proto was
|
// V3LinkDot moved the isExternDef into the class, the extern proto was
|
||||||
// checked to exist, and now isn't needed
|
// checked to exist, and now isn't needed
|
||||||
nodep->isExternDef(false);
|
nodep->isExternDef(false);
|
||||||
|
|
|
||||||
|
|
@ -1706,6 +1706,7 @@ class RandomizeVisitor final : public VNVisitor {
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
if (!nodep->user1()) return; // Doesn't need randomize, or already processed
|
if (!nodep->user1()) return; // Doesn't need randomize, or already processed
|
||||||
UINFO(9, "Define randomize() for " << nodep << endl);
|
UINFO(9, "Define randomize() for " << nodep << endl);
|
||||||
|
nodep->baseMostClassp()->needRNG(true);
|
||||||
AstFunc* const randomizep = V3Randomize::newRandomizeFunc(m_memberMap, nodep);
|
AstFunc* const randomizep = V3Randomize::newRandomizeFunc(m_memberMap, nodep);
|
||||||
AstVar* const fvarp = VN_AS(randomizep->fvarp(), Var);
|
AstVar* const fvarp = VN_AS(randomizep->fvarp(), Var);
|
||||||
addPrePostCall(nodep, randomizep, "pre_randomize");
|
addPrePostCall(nodep, randomizep, "pre_randomize");
|
||||||
|
|
@ -2027,26 +2028,30 @@ void V3Randomize::randomizeNetlist(AstNetlist* nodep) {
|
||||||
}
|
}
|
||||||
|
|
||||||
AstFunc* V3Randomize::newRandomizeFunc(VMemberMap& memberMap, AstClass* 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);
|
AstFunc* funcp = VN_AS(memberMap.findMember(nodep, name), Func);
|
||||||
if (!funcp) {
|
if (!funcp) {
|
||||||
v3Global.useRandomizeMethods(true);
|
v3Global.useRandomizeMethods(true);
|
||||||
AstNodeDType* const dtypep
|
AstNodeDType* const dtypep
|
||||||
= nodep->findBitDType(32, 32, VSigning::SIGNED); // IEEE says int return of 0/1
|
= childDType
|
||||||
AstVar* const fvarp = new AstVar{nodep->fileline(), VVarType::MEMBER, name, dtypep};
|
? 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->lifetime(VLifetime::AUTOMATIC);
|
||||||
fvarp->funcLocal(true);
|
fvarp->funcLocal(true);
|
||||||
fvarp->funcReturn(true);
|
fvarp->funcReturn(true);
|
||||||
fvarp->direction(VDirection::OUTPUT);
|
fvarp->direction(VDirection::OUTPUT);
|
||||||
nodep->addMembersp(funcp);
|
nodep->addMembersp(funcp);
|
||||||
funcp = new AstFunc{nodep->fileline(), name, nullptr, fvarp};
|
funcp = new AstFunc{nodep->fileline(), name, nullptr, fvarp};
|
||||||
funcp->dtypep(dtypep);
|
if (!childDType) funcp->dtypep(dtypep);
|
||||||
funcp->classMethod(true);
|
funcp->classMethod(true);
|
||||||
funcp->isVirtual(allowVirtual && nodep->isExtended());
|
funcp->isVirtual(allowVirtual && nodep->isExtended());
|
||||||
nodep->addMembersp(funcp);
|
nodep->addMembersp(funcp);
|
||||||
memberMap.insert(nodep, funcp);
|
memberMap.insert(nodep, funcp);
|
||||||
AstClass* const basep = nodep->baseMostClassp();
|
|
||||||
basep->needRNG(true);
|
|
||||||
}
|
}
|
||||||
return funcp;
|
return funcp;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,8 @@ public:
|
||||||
|
|
||||||
static AstFunc* newRandomizeFunc(VMemberMap& memberMap, AstClass* nodep,
|
static AstFunc* newRandomizeFunc(VMemberMap& memberMap, AstClass* nodep,
|
||||||
const std::string& name = "randomize",
|
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;
|
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");
|
UASSERT_OBJ(classp, nodep, "Should have failed in V3LinkDot");
|
||||||
if (nodep->name() == "randomize") {
|
if (nodep->name() == "randomize") {
|
||||||
nodep->taskp(V3Randomize::newRandomizeFunc(m_memberMap, classp));
|
|
||||||
AstClassRefDType* const adtypep
|
AstClassRefDType* const adtypep
|
||||||
= new AstClassRefDType{nodep->fileline(), classp, nullptr};
|
= new AstClassRefDType{nodep->fileline(), classp, nullptr};
|
||||||
v3Global.rootp()->typeTablep()->addTypesp(adtypep);
|
v3Global.rootp()->typeTablep()->addTypesp(adtypep);
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
@ -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