mirror of
https://github.com/verilator/verilator.git
synced 2025-07-30 15:36:11 +00:00
Support randomize() class method and rand
This commit is contained in:
parent
cd248f6bd7
commit
cf7ea06b5d
@ -228,6 +228,7 @@ RAW_OBJS = \
|
||||
V3PreShell.o \
|
||||
V3Premit.o \
|
||||
V3ProtectLib.o \
|
||||
V3Randomize.o \
|
||||
V3Reloop.o \
|
||||
V3Scope.o \
|
||||
V3Scoreboard.o \
|
||||
|
@ -1484,6 +1484,11 @@ public:
|
||||
virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
|
||||
virtual int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); }
|
||||
virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); }
|
||||
int itemCount() const {
|
||||
size_t count = 0;
|
||||
for (AstNode* itemp = itemsp(); itemp; itemp = itemp->nextp()) count++;
|
||||
return count;
|
||||
}
|
||||
};
|
||||
|
||||
class AstParseTypeDType final : public AstNodeDType {
|
||||
@ -1892,6 +1897,7 @@ private:
|
||||
bool m_attrSFormat : 1; // User sformat attribute
|
||||
bool m_attrSplitVar : 1; // declared with split_var metacomment
|
||||
bool m_fileDescr : 1; // File descriptor
|
||||
bool m_isRand : 1; // Random variable
|
||||
bool m_isConst : 1; // Table contains constant data
|
||||
bool m_isStatic : 1; // Static C variable (for Verilog see instead isAutomatic)
|
||||
bool m_isPulldown : 1; // Tri0
|
||||
@ -2081,6 +2087,7 @@ public:
|
||||
void sc(bool flag) { m_sc = flag; }
|
||||
void scSensitive(bool flag) { m_scSensitive = flag; }
|
||||
void primaryIO(bool flag) { m_primaryIO = flag; }
|
||||
void isRand(bool flag) { m_isRand = flag; }
|
||||
void isConst(bool flag) { m_isConst = flag; }
|
||||
void isStatic(bool flag) { m_isStatic = flag; }
|
||||
void isIfaceParent(bool flag) { m_isIfaceParent = flag; }
|
||||
@ -2149,6 +2156,7 @@ public:
|
||||
bool isSigUserRdPublic() const { return m_sigUserRdPublic; }
|
||||
bool isSigUserRWPublic() const { return m_sigUserRWPublic; }
|
||||
bool isTrace() const { return m_trace; }
|
||||
bool isRand() const { return m_isRand; }
|
||||
bool isConst() const { return m_isConst; }
|
||||
bool isStatic() const { return m_isStatic; }
|
||||
bool isFuncLocal() const { return m_funcLocal; }
|
||||
@ -5450,9 +5458,9 @@ public:
|
||||
: (m_urandom ? "%f$urandom()" : "%f$random()");
|
||||
}
|
||||
virtual string emitC() override {
|
||||
return m_reset
|
||||
? "VL_RAND_RESET_%nq(%nw, %P)"
|
||||
: seedp() ? "VL_RANDOM_SEEDED_%nq%lq(%nw, %P, %li)" : "VL_RANDOM_%nq(%nw, %P)";
|
||||
return m_reset ? "VL_RAND_RESET_%nq(%nw, %P)"
|
||||
: seedp() ? "VL_RANDOM_SEEDED_%nq%lq(%nw, %P, %li)"
|
||||
: "VL_RANDOM_%nq(%nw, %P)";
|
||||
}
|
||||
virtual bool cleanOut() const override { return true; }
|
||||
virtual bool isGateOptimizable() const override { return false; }
|
||||
|
@ -101,6 +101,7 @@ class V3Global final {
|
||||
bool m_needTraceDumper = false; // Need __Vm_dumperp in symbols
|
||||
bool m_dpi = false; // Need __Dpi include files
|
||||
bool m_useParallelBuild = false; // Use parallel build for model
|
||||
bool m_useRandomizeMethods = false; // Need to define randomize() class methods
|
||||
|
||||
// Memory address to short string mapping (for debug)
|
||||
typedef std::unordered_map<const void*, std::string> PtrToIdMap; // The map type
|
||||
@ -158,6 +159,8 @@ public:
|
||||
}
|
||||
void useParallelBuild(bool flag) { m_useParallelBuild = flag; }
|
||||
bool useParallelBuild() const { return m_useParallelBuild; }
|
||||
void useRandomizeMethods(bool flag) { m_useRandomizeMethods = flag; }
|
||||
bool useRandomizeMethods() const { return m_useRandomizeMethods; }
|
||||
const std::string& ptrToId(const void* p);
|
||||
};
|
||||
|
||||
|
@ -112,7 +112,16 @@ private:
|
||||
virtual void visit(AstNodeFTask* nodep) override {
|
||||
// NodeTask: Remember its name for later resolution
|
||||
// Remember the existing symbol table scope
|
||||
if (m_classp) nodep->classMethod(true);
|
||||
if (m_classp) {
|
||||
if (nodep->name() == "pre_randomize" || nodep->name() == "post_randomize") {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: " << nodep->prettyNameQ());
|
||||
} else if (nodep->name() == "randomize") {
|
||||
nodep->v3error(nodep->prettyNameQ()
|
||||
<< " is a predefined class method; redefinition not allowed (IEEE "
|
||||
"1800-2017 18.6.3)");
|
||||
}
|
||||
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);
|
||||
|
@ -50,7 +50,7 @@ struct VMemberQualifiers {
|
||||
struct {
|
||||
uint32_t m_local : 1; // Local class item (ignored until warning implemented)
|
||||
uint32_t m_protected : 1; // Protected class item (ignored until warning implemented)
|
||||
uint32_t m_rand : 1; // Rand property/member qualifier (ignored until supported)
|
||||
uint32_t m_rand : 1; // Rand property/member qualifier
|
||||
uint32_t m_randc : 1; // Randc property/member qualifier (ignored until supported)
|
||||
uint32_t m_virtual : 1; // Virtual property/method qualifier
|
||||
uint32_t m_automatic : 1; // Automatic property/method qualifier
|
||||
@ -83,8 +83,8 @@ struct VMemberQualifiers {
|
||||
}
|
||||
void applyToNodes(AstVar* nodesp) const {
|
||||
for (AstVar* nodep = nodesp; nodep; nodep = VN_CAST(nodep->nextp(), Var)) {
|
||||
// Ignored for now: m_rand
|
||||
// Ignored for now: m_randc
|
||||
if (m_rand) nodep->isRand(true);
|
||||
if (m_local) nodep->isHideLocal(true);
|
||||
if (m_protected) nodep->isHideProtected(true);
|
||||
if (m_automatic) nodep->lifetime(VLifetime::AUTOMATIC);
|
||||
|
273
src/V3Randomize.cpp
Normal file
273
src/V3Randomize.cpp
Normal file
@ -0,0 +1,273 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Expression width calculations
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2020 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
|
||||
//
|
||||
//*************************************************************************
|
||||
// V3Randomize's Transformations:
|
||||
//
|
||||
// Each randomize() method call:
|
||||
// Mark class of object on which randomize() is called
|
||||
// Mark all classes that inherit from previously marked classed
|
||||
// Mark all classes whose instances are randomized member variables of marked classes
|
||||
// Each marked class:
|
||||
// define a virtual randomize() method that randomizes its random variables
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3Randomize.h"
|
||||
|
||||
//######################################################################
|
||||
// Visitor that marks classes needing a randomize() method
|
||||
|
||||
class RandomizeMarkVisitor final : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Cleared on Netlist
|
||||
// AstClass::user1() -> bool. Set true to indicate needs randomize processing
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
typedef std::unordered_set<AstClass*> DerivedSet;
|
||||
typedef std::unordered_map<AstClass*, DerivedSet> BaseToDerivedMap;
|
||||
|
||||
BaseToDerivedMap m_baseToDerivedMap; // Mapping from base classes to classes that extend them
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC;
|
||||
|
||||
void markMembers(AstClass* nodep) {
|
||||
for (auto* classp = nodep; classp;
|
||||
classp = classp->extendsp() ? classp->extendsp()->classp() : nullptr) {
|
||||
for (auto* memberp = classp->stmtsp(); memberp; memberp = memberp->nextp()) {
|
||||
// If member is rand and of class type, mark its class
|
||||
if (VN_IS(memberp, Var) && VN_CAST(memberp, Var)->isRand()) {
|
||||
if (auto* classRefp = VN_CAST(memberp->dtypep(), ClassRefDType)) {
|
||||
auto* classp = classRefp->classp();
|
||||
markMembers(classp);
|
||||
markDerived(classp);
|
||||
classRefp->classp()->user1(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void markDerived(AstClass* nodep) {
|
||||
const auto it = m_baseToDerivedMap.find(nodep);
|
||||
if (it != m_baseToDerivedMap.end()) {
|
||||
for (auto* classp : it->second) {
|
||||
classp->user1(true);
|
||||
markMembers(classp);
|
||||
markDerived(classp);
|
||||
}
|
||||
}
|
||||
}
|
||||
void markAllDerived() {
|
||||
for (auto p : m_baseToDerivedMap) {
|
||||
if (p.first->user1()) markDerived(p.first);
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstClass* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (nodep->extendsp()) {
|
||||
// Save pointer to derived class
|
||||
auto* basep = nodep->extendsp()->classp();
|
||||
m_baseToDerivedMap[basep].insert(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstMethodCall* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (nodep->name() != "randomize") return;
|
||||
if (AstClassRefDType* classRefp = VN_CAST(nodep->fromp()->dtypep(), ClassRefDType)) {
|
||||
auto* classp = classRefp->classp();
|
||||
classp->user1(true);
|
||||
markMembers(classp);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit RandomizeMarkVisitor(AstNetlist* nodep) {
|
||||
iterate(nodep);
|
||||
markAllDerived();
|
||||
}
|
||||
virtual ~RandomizeMarkVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Visitor that defines a randomize method where needed
|
||||
|
||||
class RandomizeVisitor final : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Cleared on Netlist
|
||||
// AstClass::user1() -> bool. Set true to indicate needs randomize processing
|
||||
// AstEnumDType::user2() -> AstVar*. Pointer to table with enum values
|
||||
// AstUser1InUse m_inuser1; (Allocated for use in RandomizeMarkVisitor)
|
||||
AstUser2InUse m_inuser2;
|
||||
|
||||
// STATE
|
||||
size_t m_enumValueTabCount = 0; // Number of tables with enum values created
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC;
|
||||
|
||||
AstVar* enumValueTabp(AstEnumDType* nodep) {
|
||||
if (nodep->user2p()) return VN_CAST(nodep->user2p(), Var);
|
||||
UINFO(9, "Construct Venumvaltab " << nodep << endl);
|
||||
AstNodeArrayDType* vardtypep
|
||||
= new AstUnpackArrayDType(nodep->fileline(), nodep->dtypep(),
|
||||
new AstRange(nodep->fileline(), nodep->itemCount(), 0));
|
||||
AstInitArray* initp = new AstInitArray(nodep->fileline(), vardtypep, nullptr);
|
||||
v3Global.rootp()->typeTablep()->addTypesp(vardtypep);
|
||||
AstVar* varp = new AstVar(nodep->fileline(), AstVarType::MODULETEMP,
|
||||
"__Venumvaltab_" + cvtToStr(m_enumValueTabCount++), vardtypep);
|
||||
varp->isConst(true);
|
||||
varp->isStatic(true);
|
||||
varp->valuep(initp);
|
||||
// Add to root, as don't know module we are in, and aids later structure sharing
|
||||
v3Global.rootp()->dollarUnitPkgAddp()->addStmtp(varp);
|
||||
UASSERT_OBJ(nodep->itemsp(), nodep, "Enum without items");
|
||||
for (AstEnumItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), EnumItem)) {
|
||||
AstConst* vconstp = VN_CAST(itemp->valuep(), Const);
|
||||
UASSERT_OBJ(vconstp, nodep, "Enum item without constified value");
|
||||
initp->addValuep(vconstp->cloneTree(false));
|
||||
}
|
||||
nodep->user2p(varp);
|
||||
return varp;
|
||||
}
|
||||
AstNodeStmt* newRandStmtsp(FileLine* fl, AstNodeVarRef* varrefp, int offset = 0,
|
||||
AstMemberDType* memberp = nullptr) {
|
||||
if (auto* structDtp
|
||||
= VN_CAST(memberp ? memberp->subDTypep()->skipRefp() : varrefp->dtypep()->skipRefp(),
|
||||
StructDType)) {
|
||||
AstNodeStmt* stmtsp = nullptr;
|
||||
offset += memberp ? memberp->lsb() : 0;
|
||||
for (auto* memberp = structDtp->membersp(); memberp;
|
||||
memberp = VN_CAST(memberp->nextp(), MemberDType)) {
|
||||
auto* randp = newRandStmtsp(fl, stmtsp ? varrefp->cloneTree(false) : varrefp,
|
||||
offset, memberp);
|
||||
if (stmtsp) {
|
||||
stmtsp->addNext(randp);
|
||||
} else {
|
||||
stmtsp = randp;
|
||||
}
|
||||
}
|
||||
return stmtsp;
|
||||
} else {
|
||||
AstNodeMath* valp;
|
||||
if (auto* enumDtp = VN_CAST(memberp ? memberp->subDTypep()->subDTypep()
|
||||
: varrefp->dtypep()->subDTypep(),
|
||||
EnumDType)) {
|
||||
AstVarRef* tabRefp = new AstVarRef(fl, enumValueTabp(enumDtp), VAccess::READ);
|
||||
tabRefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp());
|
||||
auto* randp = new AstRand(fl, nullptr, false);
|
||||
auto* moddivp = new AstModDiv(fl, randp, new AstConst(fl, enumDtp->itemCount()));
|
||||
randp->dtypep(varrefp->findBasicDType(AstBasicDTypeKwd::UINT32));
|
||||
moddivp->dtypep(enumDtp);
|
||||
valp = new AstArraySel(fl, tabRefp, moddivp);
|
||||
} else {
|
||||
valp = new AstRand(fl, nullptr, false);
|
||||
valp->dtypep(memberp ? memberp->dtypep() : varrefp->varp()->dtypep());
|
||||
}
|
||||
return new AstAssign(fl,
|
||||
new AstSel(fl, varrefp, offset + (memberp ? memberp->lsb() : 0),
|
||||
memberp ? memberp->width() : varrefp->width()),
|
||||
valp);
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstClass* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (!nodep->user1()) return; // Doesn't need randomize, or already processed
|
||||
UINFO(9, "Define randomize() for " << nodep << endl);
|
||||
auto* funcp = V3Randomize::newRandomizeFunc(nodep);
|
||||
auto* fvarp = VN_CAST(funcp->fvarp(), Var);
|
||||
funcp->addStmtsp(new AstAssign(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), fvarp, VAccess::WRITE),
|
||||
new AstConst(nodep->fileline(), AstConst::WidthedValue(), 32, 1)));
|
||||
for (auto* classp = nodep; classp;
|
||||
classp = classp->extendsp() ? classp->extendsp()->classp() : nullptr) {
|
||||
for (auto* memberp = classp->stmtsp(); memberp; memberp = memberp->nextp()) {
|
||||
auto* memberVarp = VN_CAST(memberp, Var);
|
||||
if (!memberVarp || !memberVarp->isRand()) continue;
|
||||
auto* dtypep = memberp->dtypep()->skipRefp();
|
||||
if (VN_IS(dtypep, BasicDType) || VN_IS(dtypep, StructDType)) {
|
||||
auto* refp = new AstVarRef(nodep->fileline(), memberVarp, VAccess::WRITE);
|
||||
auto* stmtp = newRandStmtsp(nodep->fileline(), refp);
|
||||
funcp->addStmtsp(stmtp);
|
||||
} else if (auto* classRefp = VN_CAST(dtypep, ClassRefDType)) {
|
||||
auto* refp = new AstVarRef(nodep->fileline(), memberVarp, VAccess::WRITE);
|
||||
auto* memberFuncp = V3Randomize::newRandomizeFunc(classRefp->classp());
|
||||
auto* callp = new AstMethodCall(nodep->fileline(), refp, "randomize", nullptr);
|
||||
callp->taskp(memberFuncp);
|
||||
callp->dtypeFrom(memberFuncp);
|
||||
funcp->addStmtsp(new AstAssign(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), fvarp, VAccess::WRITE),
|
||||
new AstAnd(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), fvarp, VAccess::READ),
|
||||
callp)));
|
||||
} else {
|
||||
memberp->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: random member variables with type "
|
||||
<< memberp->dtypep()->prettyDTypeNameQ());
|
||||
}
|
||||
}
|
||||
}
|
||||
nodep->user1(false);
|
||||
}
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit RandomizeVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~RandomizeVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Randomize method class functions
|
||||
|
||||
void V3Randomize::randomizeNetlist(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{
|
||||
RandomizeMarkVisitor markVisitor(nodep);
|
||||
RandomizeVisitor visitor(nodep);
|
||||
}
|
||||
V3Global::dumpCheckGlobalTree("randomize", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
AstFunc* V3Randomize::newRandomizeFunc(AstClass* nodep) {
|
||||
auto* funcp = VN_CAST(nodep->findMember("randomize"), Func);
|
||||
if (!funcp) {
|
||||
auto* dtypep
|
||||
= nodep->findBitDType(32, 32, VSigning::SIGNED); // IEEE says int return of 0/1
|
||||
auto* fvarp = new AstVar(nodep->fileline(), AstVarType::MEMBER, "randomize", dtypep);
|
||||
fvarp->lifetime(VLifetime::AUTOMATIC);
|
||||
fvarp->funcLocal(true);
|
||||
fvarp->funcReturn(true);
|
||||
fvarp->direction(VDirection::OUTPUT);
|
||||
funcp = new AstFunc(nodep->fileline(), "randomize", nullptr, fvarp);
|
||||
funcp->dtypep(dtypep);
|
||||
funcp->classMethod(true);
|
||||
funcp->isVirtual(nodep->isExtended());
|
||||
nodep->addMembersp(funcp);
|
||||
nodep->repairCache();
|
||||
}
|
||||
return funcp;
|
||||
}
|
32
src/V3Randomize.h
Normal file
32
src/V3Randomize.h
Normal file
@ -0,0 +1,32 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Node attributes/ expression widths
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2020 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
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef _V3RANDOMIZE_METHOD_H_
|
||||
#define _V3RANDOMIZE_METHOD_H_ 1
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "V3Ast.h"
|
||||
|
||||
class V3Randomize final {
|
||||
public:
|
||||
static void randomizeNetlist(AstNetlist* nodep);
|
||||
|
||||
static AstFunc* newRandomizeFunc(AstClass* nodep);
|
||||
};
|
||||
|
||||
#endif // Guard
|
@ -70,6 +70,7 @@
|
||||
#include "V3Width.h"
|
||||
#include "V3Number.h"
|
||||
#include "V3Const.h"
|
||||
#include "V3Randomize.h"
|
||||
#include "V3String.h"
|
||||
#include "V3Task.h"
|
||||
|
||||
@ -2937,6 +2938,10 @@ private:
|
||||
void methodCallClass(AstMethodCall* nodep, AstClassRefDType* adtypep) {
|
||||
// No need to width-resolve the class, as it was done when we did the child
|
||||
AstClass* first_classp = adtypep->classp();
|
||||
if (nodep->name() == "randomize") {
|
||||
v3Global.useRandomizeMethods(true);
|
||||
V3Randomize::newRandomizeFunc(first_classp);
|
||||
}
|
||||
UASSERT_OBJ(first_classp, nodep, "Unlinked");
|
||||
for (AstClass* classp = first_classp; classp;) {
|
||||
if (AstNodeFTask* ftaskp = VN_CAST(classp->findMember(nodep->name()), NodeFTask)) {
|
||||
|
@ -75,6 +75,7 @@
|
||||
#include "V3PreShell.h"
|
||||
#include "V3Premit.h"
|
||||
#include "V3ProtectLib.h"
|
||||
#include "V3Randomize.h"
|
||||
#include "V3Reloop.h"
|
||||
#include "V3Scope.h"
|
||||
#include "V3Scoreboard.h"
|
||||
@ -179,6 +180,9 @@ static void process() {
|
||||
// Before we do dead code elimination and inlining, or we'll lose it.
|
||||
if (v3Global.opt.coverage()) V3Coverage::coverage(v3Global.rootp());
|
||||
|
||||
// Add randomize() class methods if they are used by the design
|
||||
if (v3Global.useRandomizeMethods()) V3Randomize::randomizeNetlist(v3Global.rootp());
|
||||
|
||||
// Push constants, but only true constants preserving liveness
|
||||
// so V3Undriven sees variables to be eliminated, ie "if (0 && foo) ..."
|
||||
V3Const::constifyAllLive(v3Global.rootp());
|
||||
|
21
test_regress/t/t_randomize_method.pl
Normal file
21
test_regress/t/t_randomize_method.pl
Normal file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2020 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
|
||||
|
||||
scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
136
test_regress/t/t_randomize_method.v
Normal file
136
test_regress/t/t_randomize_method.v
Normal file
@ -0,0 +1,136 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2020 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
typedef enum bit[15:0] {
|
||||
ONE = 3,
|
||||
TWO = 5,
|
||||
THREE = 8,
|
||||
FOUR = 13
|
||||
} Enum;
|
||||
|
||||
typedef struct packed {
|
||||
int a;
|
||||
bit b;
|
||||
Enum c;
|
||||
} StructInner;
|
||||
|
||||
typedef struct packed {
|
||||
bit x;
|
||||
StructInner s;
|
||||
Enum y;
|
||||
longint z;
|
||||
} StructOuter;
|
||||
|
||||
class BaseCls;
|
||||
endclass
|
||||
|
||||
class Inner;
|
||||
rand logic[7:0] a;
|
||||
rand logic[15:0] b;
|
||||
rand logic[3:0] c;
|
||||
rand logic[11:0] d;
|
||||
int e;
|
||||
|
||||
function new;
|
||||
a = 0;
|
||||
b = 0;
|
||||
c = 0;
|
||||
d = 0;
|
||||
e = 0;
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
class DerivedCls extends BaseCls;
|
||||
rand Inner i;
|
||||
rand int j;
|
||||
int k;
|
||||
rand Enum l;
|
||||
|
||||
function new;
|
||||
i = new;
|
||||
j = 0;
|
||||
k = 0;
|
||||
l = ONE;
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
class OtherCls;
|
||||
logic[63:0] v;
|
||||
rand logic[63:0] w;
|
||||
rand logic[47:0] x;
|
||||
rand logic[31:0] y;
|
||||
rand logic[23:0] z;
|
||||
rand StructOuter str;
|
||||
|
||||
function new;
|
||||
v = 0;
|
||||
w = 0;
|
||||
x = 0;
|
||||
y = 0;
|
||||
z = 0;
|
||||
str = '{x: 1'b0, y: ONE, z: 64'd0, s: '{a: 32'd0, b: 1'b0, c: ONE}};
|
||||
endfunction
|
||||
|
||||
endclass
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
bit ok = 0;
|
||||
longint checksum;
|
||||
|
||||
task checksum_next(longint x);
|
||||
checksum = x ^ {checksum[62:0],checksum[63]^checksum[2]^checksum[0]};
|
||||
endtask;
|
||||
|
||||
DerivedCls derived;
|
||||
OtherCls other;
|
||||
BaseCls base;
|
||||
|
||||
initial begin
|
||||
int rand_result;
|
||||
longint prev_checksum;
|
||||
for (int i = 0; i < 10; i++) begin
|
||||
derived = new;
|
||||
other = new;
|
||||
base = derived;
|
||||
rand_result = base.randomize();
|
||||
rand_result = other.randomize();
|
||||
if (!(derived.l inside {ONE, TWO, THREE, FOUR})) $stop;
|
||||
if (!(other.str.s.c inside {ONE, TWO, THREE, FOUR})) $stop;
|
||||
if (!(other.str.y inside {ONE, TWO, THREE, FOUR})) $stop;
|
||||
if (derived.i.e != 0) $stop;
|
||||
if (derived.k != 0) $stop;
|
||||
if (other.v != 0) $stop;
|
||||
checksum = 0;
|
||||
checksum_next(longint'(derived.i.a));
|
||||
checksum_next(longint'(derived.i.b));
|
||||
checksum_next(longint'(derived.i.c));
|
||||
checksum_next(longint'(derived.j));
|
||||
checksum_next(longint'(derived.l));
|
||||
checksum_next(longint'(other.w));
|
||||
checksum_next(longint'(other.x));
|
||||
checksum_next(longint'(other.y));
|
||||
checksum_next(longint'(other.z));
|
||||
checksum_next(longint'(other.str.x));
|
||||
checksum_next(longint'(other.str.y));
|
||||
checksum_next(longint'(other.str.z));
|
||||
checksum_next(longint'(other.str.s.a));
|
||||
checksum_next(longint'(other.str.s.b));
|
||||
checksum_next(longint'(other.str.s.c));
|
||||
$write("checksum: %d\n", checksum);
|
||||
if (i > 0 && checksum != prev_checksum) begin
|
||||
ok = 1;
|
||||
end
|
||||
prev_checksum = checksum;
|
||||
end
|
||||
if (ok) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
else $stop;
|
||||
end
|
||||
endmodule
|
7
test_regress/t/t_randomize_method_bad.out
Normal file
7
test_regress/t/t_randomize_method_bad.out
Normal file
@ -0,0 +1,7 @@
|
||||
%Error: t/t_randomize_method_bad.v:8:17: 'randomize' is a predefined class method; redefinition not allowed (IEEE 1800-2017 18.6.3)
|
||||
8 | function int randomize;
|
||||
| ^~~~~~~~~
|
||||
%Error: t/t_randomize_method_bad.v:14:18: 'randomize' is a predefined class method; redefinition not allowed (IEEE 1800-2017 18.6.3)
|
||||
14 | function void randomize(int x);
|
||||
| ^~~~~~~~~
|
||||
%Error: Exiting due to
|
19
test_regress/t/t_randomize_method_bad.pl
Normal file
19
test_regress/t/t_randomize_method_bad.pl
Normal file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2020 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
|
||||
|
||||
scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
fails => $Self->{vlt_all},
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
19
test_regress/t/t_randomize_method_bad.v
Normal file
19
test_regress/t/t_randomize_method_bad.v
Normal file
@ -0,0 +1,19 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2020 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
class Cls1;
|
||||
function int randomize;
|
||||
return 1;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class Cls2;
|
||||
function void randomize(int x);
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
endmodule
|
17
test_regress/t/t_randomize_method_types_unsup.out
Normal file
17
test_regress/t/t_randomize_method_types_unsup.out
Normal file
@ -0,0 +1,17 @@
|
||||
%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:12:13: Unsupported: random member variables with type 'int[string]'
|
||||
: ... In instance t
|
||||
12 | rand int assocarr[string];
|
||||
| ^~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:13:13: Unsupported: random member variables with type 'int[]'
|
||||
: ... In instance t
|
||||
13 | rand int dynarr[];
|
||||
| ^~~~~~
|
||||
%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:14:13: Unsupported: random member variables with type 'int$[0:4]'
|
||||
: ... In instance t
|
||||
14 | rand int unpackarr[5];
|
||||
| ^~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:15:15: Unsupported: random member variables with type '__024unit::Union'
|
||||
: ... In instance t
|
||||
15 | rand Union uni;
|
||||
| ^~~
|
||||
%Error: Exiting due to
|
19
test_regress/t/t_randomize_method_types_unsup.pl
Normal file
19
test_regress/t/t_randomize_method_types_unsup.pl
Normal file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2020 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
|
||||
|
||||
scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
fails => $Self->{vlt_all},
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
25
test_regress/t/t_randomize_method_types_unsup.v
Normal file
25
test_regress/t/t_randomize_method_types_unsup.v
Normal file
@ -0,0 +1,25 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2020 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
typedef union packed {
|
||||
int x;
|
||||
} Union;
|
||||
|
||||
class Cls;
|
||||
rand int assocarr[string];
|
||||
rand int dynarr[];
|
||||
rand int unpackarr[5];
|
||||
rand Union uni;
|
||||
endclass
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
Cls obj;
|
||||
|
||||
initial begin
|
||||
obj = new;
|
||||
obj.randomize();
|
||||
end
|
||||
endmodule
|
7
test_regress/t/t_randomize_method_unsup.out
Normal file
7
test_regress/t/t_randomize_method_unsup.out
Normal file
@ -0,0 +1,7 @@
|
||||
%Error-UNSUPPORTED: t/t_randomize_method_unsup.v:8:18: Unsupported: 'pre_randomize'
|
||||
8 | function void pre_randomize;
|
||||
| ^~~~~~~~~~~~~
|
||||
%Error-UNSUPPORTED: t/t_randomize_method_unsup.v:11:18: Unsupported: 'post_randomize'
|
||||
11 | function void post_randomize;
|
||||
| ^~~~~~~~~~~~~~
|
||||
%Error: Exiting due to
|
19
test_regress/t/t_randomize_method_unsup.pl
Normal file
19
test_regress/t/t_randomize_method_unsup.pl
Normal file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2020 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
|
||||
|
||||
scenarios(simulator => 1);
|
||||
|
||||
compile(
|
||||
fails => $Self->{vlt_all},
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
16
test_regress/t/t_randomize_method_unsup.v
Normal file
16
test_regress/t/t_randomize_method_unsup.v
Normal file
@ -0,0 +1,16 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2020 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
class Cls;
|
||||
function void pre_randomize;
|
||||
endfunction;
|
||||
|
||||
function void post_randomize;
|
||||
endfunction;
|
||||
endclass
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user