From cf7ea06b5de6951bace50a8ec116325dfa749b9e Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Mon, 7 Dec 2020 23:55:22 +0100 Subject: [PATCH] Support randomize() class method and rand --- src/Makefile_obj.in | 1 + src/V3AstNodes.h | 14 +- src/V3Global.h | 3 + src/V3LinkResolve.cpp | 11 +- src/V3ParseImp.h | 4 +- src/V3Randomize.cpp | 273 ++++++++++++++++++ src/V3Randomize.h | 32 ++ src/V3Width.cpp | 5 + src/Verilator.cpp | 4 + test_regress/t/t_randomize_method.pl | 21 ++ test_regress/t/t_randomize_method.v | 136 +++++++++ test_regress/t/t_randomize_method_bad.out | 7 + test_regress/t/t_randomize_method_bad.pl | 19 ++ test_regress/t/t_randomize_method_bad.v | 19 ++ .../t/t_randomize_method_types_unsup.out | 17 ++ .../t/t_randomize_method_types_unsup.pl | 19 ++ .../t/t_randomize_method_types_unsup.v | 25 ++ test_regress/t/t_randomize_method_unsup.out | 7 + test_regress/t/t_randomize_method_unsup.pl | 19 ++ test_regress/t/t_randomize_method_unsup.v | 16 + 20 files changed, 646 insertions(+), 6 deletions(-) create mode 100644 src/V3Randomize.cpp create mode 100644 src/V3Randomize.h create mode 100644 test_regress/t/t_randomize_method.pl create mode 100644 test_regress/t/t_randomize_method.v create mode 100644 test_regress/t/t_randomize_method_bad.out create mode 100644 test_regress/t/t_randomize_method_bad.pl create mode 100644 test_regress/t/t_randomize_method_bad.v create mode 100644 test_regress/t/t_randomize_method_types_unsup.out create mode 100644 test_regress/t/t_randomize_method_types_unsup.pl create mode 100644 test_regress/t/t_randomize_method_types_unsup.v create mode 100644 test_regress/t/t_randomize_method_unsup.out create mode 100644 test_regress/t/t_randomize_method_unsup.pl create mode 100644 test_regress/t/t_randomize_method_unsup.v diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index b686d5775..036ddd118 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -228,6 +228,7 @@ RAW_OBJS = \ V3PreShell.o \ V3Premit.o \ V3ProtectLib.o \ + V3Randomize.o \ V3Reloop.o \ V3Scope.o \ V3Scoreboard.o \ diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index aeb8ef8bd..e7f9a6473 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -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; } diff --git a/src/V3Global.h b/src/V3Global.h index f9fff4eb6..43500078b 100644 --- a/src/V3Global.h +++ b/src/V3Global.h @@ -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 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); }; diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 3bbb8243f..6e8c4ca45 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -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); diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index eb5dc8a6f..d14ac1986 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -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); diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp new file mode 100644 index 000000000..d1bbf3c51 --- /dev/null +++ b/src/V3Randomize.cpp @@ -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 DerivedSet; + typedef std::unordered_map 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; +} diff --git a/src/V3Randomize.h b/src/V3Randomize.h new file mode 100644 index 000000000..c3e423605 --- /dev/null +++ b/src/V3Randomize.h @@ -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 diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 0b4a685e7..75a1e2b54 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -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)) { diff --git a/src/Verilator.cpp b/src/Verilator.cpp index a676082b5..2dc857cff 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -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()); diff --git a/test_regress/t/t_randomize_method.pl b/test_regress/t/t_randomize_method.pl new file mode 100644 index 000000000..aabcde63e --- /dev/null +++ b/test_regress/t/t_randomize_method.pl @@ -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; diff --git a/test_regress/t/t_randomize_method.v b/test_regress/t/t_randomize_method.v new file mode 100644 index 000000000..126f0785e --- /dev/null +++ b/test_regress/t/t_randomize_method.v @@ -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 diff --git a/test_regress/t/t_randomize_method_bad.out b/test_regress/t/t_randomize_method_bad.out new file mode 100644 index 000000000..80f06eb60 --- /dev/null +++ b/test_regress/t/t_randomize_method_bad.out @@ -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 diff --git a/test_regress/t/t_randomize_method_bad.pl b/test_regress/t/t_randomize_method_bad.pl new file mode 100644 index 000000000..6ad7137de --- /dev/null +++ b/test_regress/t/t_randomize_method_bad.pl @@ -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; diff --git a/test_regress/t/t_randomize_method_bad.v b/test_regress/t/t_randomize_method_bad.v new file mode 100644 index 000000000..72da52529 --- /dev/null +++ b/test_regress/t/t_randomize_method_bad.v @@ -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 diff --git a/test_regress/t/t_randomize_method_types_unsup.out b/test_regress/t/t_randomize_method_types_unsup.out new file mode 100644 index 000000000..a84c9ae0e --- /dev/null +++ b/test_regress/t/t_randomize_method_types_unsup.out @@ -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 diff --git a/test_regress/t/t_randomize_method_types_unsup.pl b/test_regress/t/t_randomize_method_types_unsup.pl new file mode 100644 index 000000000..6ad7137de --- /dev/null +++ b/test_regress/t/t_randomize_method_types_unsup.pl @@ -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; diff --git a/test_regress/t/t_randomize_method_types_unsup.v b/test_regress/t/t_randomize_method_types_unsup.v new file mode 100644 index 000000000..1595a6c07 --- /dev/null +++ b/test_regress/t/t_randomize_method_types_unsup.v @@ -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 diff --git a/test_regress/t/t_randomize_method_unsup.out b/test_regress/t/t_randomize_method_unsup.out new file mode 100644 index 000000000..5012993da --- /dev/null +++ b/test_regress/t/t_randomize_method_unsup.out @@ -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 diff --git a/test_regress/t/t_randomize_method_unsup.pl b/test_regress/t/t_randomize_method_unsup.pl new file mode 100644 index 000000000..6ad7137de --- /dev/null +++ b/test_regress/t/t_randomize_method_unsup.pl @@ -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; diff --git a/test_regress/t/t_randomize_method_unsup.v b/test_regress/t/t_randomize_method_unsup.v new file mode 100644 index 000000000..898bf9fff --- /dev/null +++ b/test_regress/t/t_randomize_method_unsup.v @@ -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