Fix randomize treated as std::randomize in classes (#5436)

This commit is contained in:
Arkadiusz Kozdra 2024-09-10 15:10:36 +02:00 committed by GitHub
parent 2f690c0530
commit ef259f63ca
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 75 additions and 21 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

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

View 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