diff --git a/src/V3AstInlines.h b/src/V3AstInlines.h index a3822d737..7e55bee79 100644 --- a/src/V3AstInlines.h +++ b/src/V3AstInlines.h @@ -160,6 +160,10 @@ AstCExpr::AstCExpr(FileLine* fl, const string& textStmt, int setwidth, bool clea AstVarRef::AstVarRef(FileLine* fl, AstVar* varp, const VAccess& access) : ASTGEN_SUPER_VarRef(fl, varp, access) {} +AstVarRef::AstVarRef(FileLine* fl, AstNodeModule* pkgp, AstVar* varp, const VAccess& access) + : AstVarRef{fl, varp, access} { + classOrPackagep(pkgp); +} // This form only allowed post-link (see above) AstVarRef::AstVarRef(FileLine* fl, AstVarScope* varscp, const VAccess& access) : ASTGEN_SUPER_VarRef(fl, varscp->varp(), access) { diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 42050c20d..f8d35f2d1 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -5659,6 +5659,8 @@ public: // This form only allowed post-link because output/wire compression may // lead to deletion of AstVar's inline AstVarRef(FileLine* fl, AstVar* varp, const VAccess& access); + inline AstVarRef(FileLine* fl, AstNodeModule* classOrPackagep, AstVar* varp, + const VAccess& access); // This form only allowed post-link (see above) inline AstVarRef(FileLine* fl, AstVarScope* varscp, const VAccess& access); ASTGEN_MEMBERS_AstVarRef; diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 6b7525810..b2c7eb005 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -2334,6 +2334,21 @@ public: // Return the lowest class extended from, or this class AstClass* baseMostClassp(); static bool isCacheableChild(const AstNode* nodep); + // Iterates top level members of the class, taking into account inheritance (starting from the + // root superclass). Note: after V3Scope, several children are moved under an AstScope and will + // not be found by this. + template + void foreachMember(const Callable& visit) { + using T_Node = typename FunctionArgNoPointerNoCV::type; + if (AstClassExtends* const extendsp = this->extendsp()) { + extendsp->classp()->foreachMember(visit); + } + for (AstNode* stmtp = stmtsp(); stmtp; stmtp = stmtp->nextp()) { + if (T_Node* memberp = AstNode::privateCast(stmtp)) { + visit(this, memberp); + } + } + } }; class AstClassPackage final : public AstNodeModule { // The static information portion of a class (treated similarly to a package) diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index c9992fa90..d0bf961e6 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -50,7 +50,9 @@ class RandomizeMarkVisitor final : public VNVisitorConst { // AstClass::user1() -> bool. Set true to indicate needs randomize processing // AstNodeExpr::user1() -> bool. Set true to indicate constraint expression depending on a // randomized variable + // AstVar::user2p() -> AstNodeModule*. Pointer to containing module const VNUser1InUse m_inuser1; + const VNUser2InUse m_inuser2; using DerivedSet = std::unordered_set; using BaseToDerivedMap = std::unordered_map; @@ -59,7 +61,6 @@ class RandomizeMarkVisitor final : public VNVisitorConst { AstClass* m_classp = nullptr; // Current class AstNode* m_constraintExprp = nullptr; // Current constraint expression AstNodeModule* m_modp; // Current module - std::map m_moduleMap; // Variable -> module under which it is std::set m_staticRefs; // References to static variables under `with` clauses // METHODS @@ -102,14 +103,15 @@ class RandomizeMarkVisitor final : public VNVisitorConst { void setPackageRefs() { for (AstNodeVarRef* staticRefp : m_staticRefs) { UINFO(9, "Updated classOrPackage ref for " << staticRefp->name() << endl); - staticRefp->classOrPackagep(m_moduleMap[staticRefp->varp()]); + staticRefp->classOrPackagep(VN_AS(staticRefp->varp()->user2p(), NodeModule)); } } // VISITORS void visit(AstClass* nodep) override { VL_RESTORER(m_classp); - m_classp = nodep; + VL_RESTORER(m_modp); + m_modp = m_classp = nodep; iterateChildrenConst(nodep); if (nodep->extendsp()) { // Save pointer to derived class @@ -118,7 +120,6 @@ class RandomizeMarkVisitor final : public VNVisitorConst { } } void visit(AstMethodCall* nodep) override { - iterateChildrenConst(nodep); if (nodep->name() != "randomize") return; if (const AstClassRefDType* const classRefp = VN_CAST(nodep->fromp()->dtypep()->skipRefp(), ClassRefDType)) { @@ -126,6 +127,7 @@ class RandomizeMarkVisitor final : public VNVisitorConst { classp->user1(true); markMembers(classp); } + iterateChildrenConst(nodep); } void visit(AstNodeFTaskRef* nodep) override { iterateChildrenConst(nodep); @@ -162,7 +164,7 @@ class RandomizeMarkVisitor final : public VNVisitorConst { iterateChildrenConst(nodep); } void visit(AstVar* nodep) override { - m_moduleMap.emplace(nodep, m_modp); + nodep->user2p(m_modp); iterateChildrenConst(nodep); } @@ -183,14 +185,15 @@ public: class ConstraintExprVisitor final : public VNVisitor { // NODE STATE - // AstVar::user4() -> bool. Handled in constraints + // AstVar::user3() -> bool. Handled in constraints // AstNodeExpr::user1() -> bool. Depending on a randomized variable - // VNUser4InUse m_inuser4; (Allocated for use in RandomizeVisitor) + // VNuser3InUse m_inuser3; (Allocated for use in RandomizeVisitor) - AstNodeFTask* const m_taskp; // Method to add write_var calls to + AstNodeFTask* const m_inlineInitTaskp; // Method to add write_var calls to + // (may be null, then new() is used) AstVar* const m_genp; // VlRandomizer variable of the class - bool m_markDeclaredConstrs; // Mark constraints as aready setup with `write_var`. bool m_wantSingle = false; // Whether to merge constraint expressions with LOGAND + VMemberMap& m_memberMap; // Member names cached for fast lookup bool editFormat(AstNodeExpr* nodep) { if (nodep->user1()) return false; @@ -288,13 +291,16 @@ class ConstraintExprVisitor final : public VNVisitor { VL_DO_DANGLING(pushDeletep(nodep), nodep); - if (!varp->user4()) { - varp->user4(m_markDeclaredConstrs); + if (!varp->user3()) { AstCMethodHard* const methodp = new AstCMethodHard{ - varp->fileline(), new AstVarRef{varp->fileline(), m_genp, VAccess::READWRITE}, + varp->fileline(), + new AstVarRef{varp->fileline(), VN_AS(m_genp->user2p(), NodeModule), m_genp, + VAccess::READWRITE}, "write_var"}; methodp->dtypeSetVoid(); - AstVarRef* varRefp = new AstVarRef{varp->fileline(), varp, VAccess::WRITE}; + AstClass* const classp = VN_AS(varp->user2p(), Class); + AstVarRef* const varRefp + = new AstVarRef{varp->fileline(), classp, varp, VAccess::WRITE}; methodp->addPinsp(varRefp); methodp->addPinsp(new AstConst{varp->dtypep()->fileline(), AstConst::Unsized64{}, (size_t)varp->width()}); @@ -302,7 +308,13 @@ class ConstraintExprVisitor final : public VNVisitor { = new AstCExpr{varp->fileline(), "\"" + smtName + "\"", varp->width()}; varnamep->dtypep(varp->dtypep()); methodp->addPinsp(varnamep); - m_taskp->addStmtsp(methodp->makeStmt()); + AstNodeFTask* initTaskp = m_inlineInitTaskp; + if (!initTaskp) { + varp->user3(true); // Mark as set up in new() + initTaskp = VN_AS(m_memberMap.findMember(classp, "new"), NodeFTask); + UASSERT_OBJ(initTaskp, classp, "No new() in class"); + } + initTaskp->addStmtsp(methodp->makeStmt()); } } void visit(AstNodeBiop* nodep) override { @@ -381,7 +393,9 @@ class ConstraintExprVisitor final : public VNVisitor { } // Only hard constraints are currently supported AstCMethodHard* const callp = new AstCMethodHard{ - nodep->fileline(), new AstVarRef{nodep->fileline(), m_genp, VAccess::READWRITE}, + nodep->fileline(), + new AstVarRef{nodep->fileline(), VN_AS(m_genp->user2p(), NodeModule), m_genp, + VAccess::READWRITE}, "hard", nodep->exprp()->unlinkFrBack()}; callp->dtypeSetVoid(); nodep->replaceWith(callp->makeStmt()); @@ -415,11 +429,11 @@ class ConstraintExprVisitor final : public VNVisitor { public: // CONSTRUCTORS - explicit ConstraintExprVisitor(AstNode* nodep, AstNodeFTask* taskp, AstVar* genp, - bool markDeclaredConstrs) - : m_taskp(taskp) - , m_genp(genp) - , m_markDeclaredConstrs(markDeclaredConstrs) { + explicit ConstraintExprVisitor(VMemberMap& memberMap, AstNode* nodep, + AstNodeFTask* inlineInitTaskp, AstVar* genp) + : m_inlineInitTaskp{inlineInitTaskp} + , m_genp{genp} + , m_memberMap{memberMap} { iterateAndNextNull(nodep); } }; @@ -518,15 +532,15 @@ class RandomizeVisitor final : public VNVisitor { // NODE STATE // Cleared on Netlist // AstClass::user1() -> bool. Set true to indicate needs randomize processing + // AstVar::user2p() -> AstClass*. Pointer to containing class // AstEnumDType::user2() -> AstVar*. Pointer to table with enum values // AstConstraint::user2p() -> AstTask*. Pointer to constraint setup procedure - // AstClass::user3p() -> AstFunc*. Pointer to randomize() method of a class - // AstVar::user4() -> bool. Handled in constraints - // AstClass::user4() -> AstVar*. Constrained randomizer variable + // AstClass::user2p() -> AstTask*. Pointer to full constraint setup procedure + // AstVar::user3() -> bool. Handled in constraints + // AstClass::user3p() -> AstVar*. Constrained randomizer variable // VNUser1InUse m_inuser1; (Allocated for use in RandomizeMarkVisitor) - const VNUser2InUse m_inuser2; + // VNUser2InUse m_inuser2; (Allocated for use in RandomizeMarkVisitor) const VNUser3InUse m_inuser3; - const VNUser4InUse m_inuser4; // STATE V3UniqueNames m_inlineUniqueNames; // For generating unique function names @@ -536,7 +550,6 @@ class RandomizeVisitor final : public VNVisitor { size_t m_enumValueTabCount = 0; // Number of tables with enum values created int m_randCaseNum = 0; // Randcase number within a module for var naming std::map m_randcDtypes; // RandC data type deduplication - bool m_inline = false; // Constraints are inline // METHODS AstVar* enumValueTabp(AstEnumDType* const nodep) { @@ -688,7 +701,9 @@ class RandomizeVisitor final : public VNVisitor { } AstNodeStmt* implementConstraintsClear(FileLine* const fileline, AstVar* const genp) { AstCMethodHard* const clearp = new AstCMethodHard{ - fileline, new AstVarRef{fileline, genp, VAccess::READWRITE}, "clear"}; + fileline, + new AstVarRef{fileline, VN_AS(genp->user2p(), NodeModule), genp, VAccess::READWRITE}, + "clear"}; clearp->dtypeSetVoid(); return clearp->makeStmt(); } @@ -706,6 +721,29 @@ class RandomizeVisitor final : public VNVisitor { m_ftaskp = nodep; iterateChildren(nodep); } + AstVar* getCreateRandomGenerator(AstClass* classp) { + if (classp->user3p()) return VN_AS(classp->user3p(), Var); + AstVar* genp = nullptr; + if (classp->extendsp()) genp = getCreateRandomGenerator(classp->extendsp()->classp()); + if (!genp) { + genp = new AstVar{classp->fileline(), VVarType::MEMBER, "constraint", + classp->findBasicDType(VBasicDTypeKwd::RANDOM_GENERATOR)}; + genp->user2p(classp); + classp->addMembersp(genp); + classp->user3p(genp); + } + return genp; + } + AstTask* getCreateConstraintSetupFunc(AstClass* classp) { + if (classp->user2p()) return VN_AS(classp->user2p(), Task); + AstTask* const setupAllTaskp + = new AstTask{classp->fileline(), "__Vsetup_constraints", nullptr}; + setupAllTaskp->classMethod(true); + setupAllTaskp->isVirtual(true); + classp->addMembersp(setupAllTaskp); + classp->user2p(setupAllTaskp); + return setupAllTaskp; + } void visit(AstClass* nodep) override { VL_RESTORER(m_modp); VL_RESTORER(m_randCaseNum); @@ -715,107 +753,96 @@ 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); - AstFunc* const funcp = V3Randomize::newRandomizeFunc(m_memberMap, nodep); - nodep->user3p(funcp); - AstVar* const fvarp = VN_AS(funcp->fvarp(), Var); - addPrePostCall(nodep, funcp, "pre_randomize"); + AstFunc* const randomizep = V3Randomize::newRandomizeFunc(m_memberMap, nodep); + AstVar* const fvarp = VN_AS(randomizep->fvarp(), Var); + addPrePostCall(nodep, randomizep, "pre_randomize"); FileLine* fl = nodep->fileline(); AstNodeExpr* beginValp = nullptr; - if (nodep->extendsp()) { - // Call randomize() from the base class - AstFunc* const baseRandomizep = VN_AS(nodep->extendsp()->classp()->user3p(), Func); - if (baseRandomizep) { - AstFuncRef* const baseRandCallp = new AstFuncRef{fl, "randomize", nullptr}; - baseRandCallp->taskp(baseRandomizep); - baseRandCallp->dtypeFrom(baseRandomizep->dtypep()); - baseRandCallp->classOrPackagep(nodep->extendsp()->classp()); - baseRandCallp->superReference(true); - beginValp = baseRandCallp; + AstVar* genp = nullptr; + nodep->foreachMember([&](AstClass* classp, AstConstraint* constrp) { + AstTask* taskp = VN_AS(constrp->user2p(), Task); + if (!taskp) { + taskp = newSetupConstraintTask(classp, constrp->name()); + constrp->user2p(taskp); } - } - if (m_modp->user4p()) { - AstVarRef* const genRefp = new AstVarRef{ - nodep->fileline(), VN_AS(m_modp->user4p(), Var), VAccess::READWRITE}; - genRefp->AstNode::addNext(new AstText{fl, ".next(__Vm_rng)"}); - AstNodeExpr* const solverCallp = new AstCExpr{fl, genRefp}; + AstTaskRef* const setupTaskRefp + = new AstTaskRef{constrp->fileline(), taskp->name(), nullptr}; + setupTaskRefp->taskp(taskp); + setupTaskRefp->classOrPackagep(classp); + + genp = getCreateRandomGenerator(nodep); + AstTask* setupAllTaskp = getCreateConstraintSetupFunc(nodep); + + setupAllTaskp->addStmtsp(setupTaskRefp->makeStmt()); + + ConstraintExprVisitor{m_memberMap, constrp->itemsp(), nullptr, genp}; + if (constrp->itemsp()) taskp->addStmtsp(constrp->itemsp()->unlinkFrBackWithNext()); + }); + if (genp) { + randomizep->addStmtsp(implementConstraintsClear(fl, genp)); + AstTask* setupAllTaskp = getCreateConstraintSetupFunc(nodep); + AstTaskRef* const setupTaskRefp = new AstTaskRef{fl, setupAllTaskp->name(), nullptr}; + setupTaskRefp->taskp(setupAllTaskp); + randomizep->addStmtsp(implementConstraintsClear(fl, genp)); + randomizep->addStmtsp(setupTaskRefp->makeStmt()); + + AstVarRef* genRefp + = new AstVarRef{fl, VN_AS(genp->user2p(), NodeModule), genp, VAccess::READWRITE}; + AstNode* const argsp = genRefp; + argsp->addNext(new AstText{fl, ".next(__Vm_rng)"}); + AstNodeExpr* const solverCallp = new AstCExpr{fl, argsp}; solverCallp->dtypeSetBit(); - beginValp = beginValp ? new AstLogAnd{fl, beginValp, solverCallp} : solverCallp; + beginValp = solverCallp; + } else { + beginValp = new AstConst{fl, AstConst::WidthedValue{}, 32, 1}; } - if (!beginValp) beginValp = new AstConst{fl, AstConst::WidthedValue{}, 32, 1}; AstVarRef* const fvarRefp = new AstVarRef{fl, fvarp, VAccess::WRITE}; - funcp->addStmtsp(new AstAssign{fl, fvarRefp, beginValp}); + randomizep->addStmtsp(new AstAssign{fl, fvarRefp, beginValp}); - for (AstNode* memberp = nodep->stmtsp(); memberp; memberp = memberp->nextp()) { - AstVar* const memberVarp = VN_CAST(memberp, Var); - if (!memberVarp || !memberVarp->isRand() || memberVarp->user4()) continue; + AstNodeFTask* const newp = VN_AS(m_memberMap.findMember(nodep, "new"), NodeFTask); + UASSERT_OBJ(newp, nodep, "No new() in class"); + + nodep->foreachMember([&](AstClass* classp, AstVar* memberVarp) { + if (!memberVarp->isRand() || memberVarp->user3()) return; const AstNodeDType* const dtypep = memberVarp->dtypep()->skipRefp(); if (VN_IS(dtypep, BasicDType) || VN_IS(dtypep, StructDType)) { AstVar* const randcVarp = newRandcVarsp(memberVarp); - AstVarRef* const refp = new AstVarRef{fl, memberVarp, VAccess::WRITE}; + AstVarRef* const refp = new AstVarRef{fl, classp, memberVarp, VAccess::WRITE}; AstNodeStmt* const stmtp = newRandStmtsp(fl, refp, randcVarp); - funcp->addStmtsp(stmtp); + randomizep->addStmtsp(stmtp); } else if (const AstClassRefDType* const classRefp = VN_CAST(dtypep, ClassRefDType)) { if (classRefp->classp() == nodep) { - memberVarp->v3warn( - E_UNSUPPORTED, - "Unsupported: random member variable with type of a current class"); - continue; + memberVarp->v3warn(E_UNSUPPORTED, + "Unsupported: random member variable with the " + "type of the containing class"); + return; } AstFunc* const memberFuncp = V3Randomize::newRandomizeFunc(m_memberMap, classRefp->classp()); - AstMethodCall* const callp = new AstMethodCall{ - fl, new AstVarRef{fl, memberVarp, VAccess::WRITE}, "randomize", nullptr}; + AstMethodCall* const callp + = new AstMethodCall{fl, new AstVarRef{fl, classp, memberVarp, VAccess::WRITE}, + "randomize", nullptr}; callp->taskp(memberFuncp); callp->dtypeFrom(memberFuncp); AstVarRef* fvarRefReadp = fvarRefp->cloneTree(false); fvarRefReadp->access(VAccess::READ); - AstIf* const assignIfNotNullp - = new AstIf{fl, - new AstNeq{fl, new AstVarRef{fl, memberVarp, VAccess::READ}, - new AstConst{fl, AstConst::Null{}}}, - new AstAssign{fl, fvarRefp->cloneTree(false), - new AstAnd{fl, fvarRefReadp, callp}}}; - funcp->addStmtsp(assignIfNotNullp); + AstIf* const assignIfNotNullp = new AstIf{ + fl, + new AstNeq{fl, new AstVarRef{fl, classp, memberVarp, VAccess::READ}, + new AstConst{fl, AstConst::Null{}}}, + new AstAssign{fl, fvarRefp->cloneTree(false), + new AstAnd{fl, fvarRefReadp, callp}}}; + randomizep->addStmtsp(assignIfNotNullp); } else { memberVarp->v3warn(E_UNSUPPORTED, "Unsupported: random member variable with type " << memberVarp->dtypep()->prettyDTypeNameQ()); } - } - addPrePostCall(nodep, funcp, "post_randomize"); + }); + addPrePostCall(nodep, randomizep, "post_randomize"); nodep->user1(false); } - void visit(AstConstraint* nodep) override { - if (nodep->user2p()) return; // Already visited - AstNodeFTask* const newp = VN_AS(m_memberMap.findMember(m_modp, "new"), NodeFTask); - UASSERT_OBJ(newp, m_modp, "No new() in class"); - AstFunc* const randomizep - = V3Randomize::newRandomizeFunc(m_memberMap, VN_AS(m_modp, Class)); - AstTask* const taskp = newSetupConstraintTask(VN_AS(m_modp, Class), nodep->name()); - nodep->user2p(taskp); - AstTaskRef* const setupTaskRefp - = new AstTaskRef{nodep->fileline(), taskp->name(), nullptr}; - setupTaskRefp->taskp(taskp); - - AstVar* genp = VN_AS(m_modp->user4p(), Var); - if (!genp) { - genp = VN_AS(m_memberMap.findMember(m_modp, "constraint"), Var); - if (!genp) { - genp = new AstVar{nodep->fileline(), VVarType::MEMBER, "constraint", - m_modp->findBasicDType(VBasicDTypeKwd::RANDOM_GENERATOR)}; - } - VN_AS(m_modp, Class)->addMembersp(genp); - m_modp->user4p(genp); - } - - if (!randomizep->stmtsp()) { - randomizep->addStmtsp(implementConstraintsClear(randomizep->fileline(), genp)); - } - randomizep->addStmtsp(setupTaskRefp->makeStmt()); - { ConstraintExprVisitor{nodep->itemsp(), (m_inline ? taskp : newp), genp, !m_inline}; } - if (nodep->itemsp()) taskp->addStmtsp(nodep->itemsp()->unlinkFrBackWithNext()); - } void visit(AstRandCase* nodep) override { // RANDCASE // CASEITEM expr1 : stmt1 @@ -882,8 +909,6 @@ class RandomizeVisitor final : public VNVisitor { return; } - VL_RESTORER(m_inline); - m_inline = true; iterateChildren(nodep); UASSERT_OBJ(nodep->fromp()->dtypep(), nodep->fromp(), "Object dtype is not linked"); @@ -902,7 +927,7 @@ class RandomizeVisitor final : public VNVisitor { iterate(classp); } - AstVar* const classGenp = VN_CAST(classp->user4p(), Var); + AstVar* const classGenp = getCreateRandomGenerator(classp); AstVar* const localGenp = new AstVar{nodep->fileline(), VVarType::BLOCKTEMP, "randomizer", classp->findBasicDType(VBasicDTypeKwd::RANDOM_GENERATOR)}; @@ -936,22 +961,20 @@ class RandomizeVisitor final : public VNVisitor { // Copy (derive) class constraints if present if (classGenp) { - classp->foreach([&](AstConstraint* constrp) { - AstTask* constrSetupFuncp = VN_AS(constrp->user2p(), Task); - UASSERT_OBJ(constrSetupFuncp, constrp, "Constraint not linked to setup procudure"); - auto callp = new AstTaskRef{nodep->fileline(), constrSetupFuncp->name(), nullptr}; - callp->taskp(constrSetupFuncp); - randomizeFuncp->addStmtsp(callp->makeStmt()); - }); - + AstTask* const constrSetupFuncp = getCreateConstraintSetupFunc(classp); + AstTaskRef* const callp + = new AstTaskRef{nodep->fileline(), constrSetupFuncp->name(), nullptr}; + callp->taskp(constrSetupFuncp); + randomizeFuncp->addStmtsp(callp->makeStmt()); randomizeFuncp->addStmtsp(new AstAssign{ nodep->fileline(), new AstVarRef{nodep->fileline(), localGenp, VAccess::WRITE}, - new AstVarRef{nodep->fileline(), classGenp, VAccess::READ}}); + new AstVarRef{nodep->fileline(), VN_AS(classGenp->user2p(), NodeModule), classGenp, + VAccess::READ}}); } // Generate constraint setup code and a hardcoded call to the solver randomizeFuncp->addStmtsp(captured.getTree()); - { ConstraintExprVisitor{captured.getTree(), randomizeFuncp, localGenp, !m_inline}; } + ConstraintExprVisitor{m_memberMap, captured.getTree(), randomizeFuncp, localGenp}; // Call the solver and set return value AstVarRef* const randNextp diff --git a/test_regress/t/t_constraint_inheritance.pl b/test_regress/t/t_constraint_inheritance.pl new file mode 100755 index 000000000..7b520d284 --- /dev/null +++ b/test_regress/t/t_constraint_inheritance.pl @@ -0,0 +1,25 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# 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 + +scenarios(simulator => 1); + +if (!$Self->have_solver) { + skip("No constraint solver installed"); +} else { + compile( + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_constraint_inheritance.v b/test_regress/t/t_constraint_inheritance.v new file mode 100644 index 000000000..e37040c4d --- /dev/null +++ b/test_regress/t/t_constraint_inheritance.v @@ -0,0 +1,62 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Antmicro. +// SPDX-License-Identifier: CC0-1.0 + +`define check_rand(cl, field, cond) \ +begin \ + longint prev_result; \ + int ok = 0; \ + for (int i = 0; i < 10; i++) begin \ + longint result; \ + if (!bit'(cl.randomize())) $stop; \ + result = longint'(field); \ + if (!(cond)) $stop; \ + if (i > 0 && result != prev_result) ok = 1; \ + prev_result = result; \ + end \ + if (ok != 1) $stop; \ +end + +typedef class C; + +class D extends C; + constraint x_lt_y { x < y; } +endclass + +class A; +endclass + +class B extends A; + rand int x; + constraint x_gt_0 { x > 0; } +endclass + +class C extends B; + rand int y; +endclass + +class E extends C; + constraint x_lt_20 { x < 20; } + constraint x_gt_y { x > y; } +endclass + +module t; + initial begin + B b = new; + C c = new; + D d = new; + E e = new; + A a = b; + `check_rand(a, b.x, b.x > 0); + `check_rand(c, c.x, c.x > 0); + `check_rand(c, c.y, c.x > 0); + `check_rand(d, d.x, d.x > 0 && d.x < d.y); + `check_rand(d, d.y, d.x > 0 && d.x < d.y); + `check_rand(e, e.x, e.x > 0 && e.x < 20 && e.x > e.y); + `check_rand(e, e.y, e.x > 0 && e.x < 20 && e.x > e.y); + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_constraint_inheritance_with.pl b/test_regress/t/t_constraint_inheritance_with.pl new file mode 100755 index 000000000..7b520d284 --- /dev/null +++ b/test_regress/t/t_constraint_inheritance_with.pl @@ -0,0 +1,25 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# 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 + +scenarios(simulator => 1); + +if (!$Self->have_solver) { + skip("No constraint solver installed"); +} else { + compile( + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_constraint_inheritance_with.v b/test_regress/t/t_constraint_inheritance_with.v new file mode 100644 index 000000000..2a1e4a020 --- /dev/null +++ b/test_regress/t/t_constraint_inheritance_with.v @@ -0,0 +1,62 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Antmicro. +// SPDX-License-Identifier: CC0-1.0 + +`define check_rand(cl, field, constr, cond) \ +begin \ + longint prev_result; \ + int ok = 0; \ + for (int i = 0; i < 10; i++) begin \ + longint result; \ + if (!bit'(cl.randomize() with { constr; })) $stop; \ + result = longint'(field); \ + if (!(cond)) $stop; \ + if (i > 0 && result != prev_result) ok = 1; \ + prev_result = result; \ + end \ + if (ok != 1) $stop; \ +end + +typedef class C; + +class D extends C; + rand int z; + constraint x_lt_y { x < y; } +endclass + +class A; + rand int x; +endclass + +class B extends A; + constraint x_gt_0 { x > 0; } +endclass + +class C extends B; + rand int y; +endclass + +class E extends C; + constraint x_gt_y { x > y; } +endclass + +module t; + initial begin + B b = new; + C c = new; + D d = new; + E e = new; + A a = b; + `check_rand(a, a.x, x < 10, a.x > 0 && a.x < 10); + `check_rand(c, c.x, x < 100, c.x > 0 && c.x < 100); + `check_rand(c, c.y, x == 5, c.x == 5); + `check_rand(d, d.x, z > x && z < y, d.x > 0 && d.x < d.y); + `check_rand(d, d.y, z > x && z < y, d.x > 0 && d.x < d.y); + `check_rand(e, e.x, x inside {[10:20]}, e.x inside {[10:20]} && e.x > e.y); + `check_rand(e, e.y, x inside {[10:20]}, e.x inside {[10:20]} && e.x > e.y); + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_constraint_json_only.out b/test_regress/t/t_constraint_json_only.out index 4a6ffec9b..271c0c636 100644 --- a/test_regress/t/t_constraint_json_only.out +++ b/test_regress/t/t_constraint_json_only.out @@ -48,272 +48,7 @@ {"type":"VARREF","name":"strings_equal","addr":"(JB)","loc":"d,62:7,62:13","dtypep":"(U)","access":"WR","varp":"(BB)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} ],"timingControlp": []} ],"scopeNamep": []}, - {"type":"FUNC","name":"new","addr":"(KB)","loc":"d,7:1,7:6","dtypep":"(LB)","method":true,"dpiExport":false,"dpiImport":false,"dpiOpenChild":false,"dpiOpenParent":false,"prototype":false,"recursive":false,"taskPublic":false,"cname":"new","fvarp": [],"classOrPackagep": [], - "stmtsp": [ - {"type":"STMTEXPR","name":"","addr":"(MB)","loc":"d,8:13,8:19", - "exprp": [ - {"type":"CMETHODHARD","name":"write_var","addr":"(NB)","loc":"d,8:13,8:19","dtypep":"(LB)", - "fromp": [ - {"type":"VARREF","name":"constraint","addr":"(OB)","loc":"d,8:13,8:19","dtypep":"(PB)","access":"RW","varp":"(QB)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} - ], - "pinsp": [ - {"type":"VARREF","name":"header","addr":"(RB)","loc":"d,8:13,8:19","dtypep":"(Q)","access":"WR","varp":"(P)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"}, - {"type":"CONST","name":"64'h20","addr":"(SB)","loc":"d,8:9,8:12","dtypep":"(TB)"}, - {"type":"CEXPR","name":"","addr":"(UB)","loc":"d,8:13,8:19","dtypep":"(Q)", - "exprsp": [ - {"type":"TEXT","name":"","addr":"(VB)","loc":"d,8:13,8:19","shortText":"\"header\""} - ]} - ]} - ]}, - {"type":"STMTEXPR","name":"","addr":"(WB)","loc":"d,9:13,9:19", - "exprp": [ - {"type":"CMETHODHARD","name":"write_var","addr":"(XB)","loc":"d,9:13,9:19","dtypep":"(LB)", - "fromp": [ - {"type":"VARREF","name":"constraint","addr":"(YB)","loc":"d,9:13,9:19","dtypep":"(PB)","access":"RW","varp":"(QB)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} - ], - "pinsp": [ - {"type":"VARREF","name":"length","addr":"(ZB)","loc":"d,9:13,9:19","dtypep":"(Q)","access":"WR","varp":"(R)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"}, - {"type":"CONST","name":"64'h20","addr":"(AC)","loc":"d,8:9,8:12","dtypep":"(TB)"}, - {"type":"CEXPR","name":"","addr":"(BC)","loc":"d,9:13,9:19","dtypep":"(Q)", - "exprsp": [ - {"type":"TEXT","name":"","addr":"(CC)","loc":"d,9:13,9:19","shortText":"\"length\""} - ]} - ]} - ]}, - {"type":"STMTEXPR","name":"","addr":"(DC)","loc":"d,11:13,11:17", - "exprp": [ - {"type":"CMETHODHARD","name":"write_var","addr":"(EC)","loc":"d,11:13,11:17","dtypep":"(LB)", - "fromp": [ - {"type":"VARREF","name":"constraint","addr":"(FC)","loc":"d,11:13,11:17","dtypep":"(PB)","access":"RW","varp":"(QB)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} - ], - "pinsp": [ - {"type":"VARREF","name":"if_4","addr":"(GC)","loc":"d,11:13,11:17","dtypep":"(U)","access":"WR","varp":"(T)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"}, - {"type":"CONST","name":"64'h1","addr":"(HC)","loc":"d,11:9,11:12","dtypep":"(TB)"}, - {"type":"CEXPR","name":"","addr":"(IC)","loc":"d,11:13,11:17","dtypep":"(U)", - "exprsp": [ - {"type":"TEXT","name":"","addr":"(JC)","loc":"d,11:13,11:17","shortText":"\"if_4\""} - ]} - ]} - ]}, - {"type":"STMTEXPR","name":"","addr":"(KC)","loc":"d,12:13,12:20", - "exprp": [ - {"type":"CMETHODHARD","name":"write_var","addr":"(LC)","loc":"d,12:13,12:20","dtypep":"(LB)", - "fromp": [ - {"type":"VARREF","name":"constraint","addr":"(MC)","loc":"d,12:13,12:20","dtypep":"(PB)","access":"RW","varp":"(QB)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} - ], - "pinsp": [ - {"type":"VARREF","name":"iff_5_6","addr":"(NC)","loc":"d,12:13,12:20","dtypep":"(U)","access":"WR","varp":"(V)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"}, - {"type":"CONST","name":"64'h1","addr":"(OC)","loc":"d,11:9,11:12","dtypep":"(TB)"}, - {"type":"CEXPR","name":"","addr":"(PC)","loc":"d,12:13,12:20","dtypep":"(U)", - "exprsp": [ - {"type":"TEXT","name":"","addr":"(QC)","loc":"d,12:13,12:20","shortText":"\"iff_5_6\""} - ]} - ]} - ]}, - {"type":"STMTEXPR","name":"","addr":"(RC)","loc":"d,10:13,10:22", - "exprp": [ - {"type":"CMETHODHARD","name":"write_var","addr":"(SC)","loc":"d,10:13,10:22","dtypep":"(LB)", - "fromp": [ - {"type":"VARREF","name":"constraint","addr":"(TC)","loc":"d,10:13,10:22","dtypep":"(PB)","access":"RW","varp":"(QB)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} - ], - "pinsp": [ - {"type":"VARREF","name":"sublength","addr":"(UC)","loc":"d,10:13,10:22","dtypep":"(Q)","access":"WR","varp":"(S)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"}, - {"type":"CONST","name":"64'h20","addr":"(VC)","loc":"d,8:9,8:12","dtypep":"(TB)"}, - {"type":"CEXPR","name":"","addr":"(WC)","loc":"d,10:13,10:22","dtypep":"(Q)", - "exprsp": [ - {"type":"TEXT","name":"","addr":"(XC)","loc":"d,10:13,10:22","shortText":"\"sublength\""} - ]} - ]} - ]}, - {"type":"STMTEXPR","name":"","addr":"(YC)","loc":"d,13:13,13:24", - "exprp": [ - {"type":"CMETHODHARD","name":"write_var","addr":"(ZC)","loc":"d,13:13,13:24","dtypep":"(LB)", - "fromp": [ - {"type":"VARREF","name":"constraint","addr":"(AD)","loc":"d,13:13,13:24","dtypep":"(PB)","access":"RW","varp":"(QB)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} - ], - "pinsp": [ - {"type":"VARREF","name":"if_state_ok","addr":"(BD)","loc":"d,13:13,13:24","dtypep":"(U)","access":"WR","varp":"(W)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"}, - {"type":"CONST","name":"64'h1","addr":"(CD)","loc":"d,11:9,11:12","dtypep":"(TB)"}, - {"type":"CEXPR","name":"","addr":"(DD)","loc":"d,13:13,13:24","dtypep":"(U)", - "exprsp": [ - {"type":"TEXT","name":"","addr":"(ED)","loc":"d,13:13,13:24","shortText":"\"if_state_ok\""} - ]} - ]} - ]} - ],"scopeNamep": []}, - {"type":"FUNC","name":"randomize","addr":"(FD)","loc":"d,7:1,7:6","dtypep":"(GD)","method":true,"dpiExport":false,"dpiImport":false,"dpiOpenChild":false,"dpiOpenParent":false,"prototype":false,"recursive":false,"taskPublic":false,"cname":"randomize", - "fvarp": [ - {"type":"VAR","name":"randomize","addr":"(HD)","loc":"d,7:1,7:6","dtypep":"(GD)","origName":"randomize","isSc":false,"isPrimaryIO":false,"direction":"OUTPUT","isConst":false,"isPullup":false,"isPulldown":false,"isUsedClock":false,"isSigPublic":false,"isLatched":false,"isUsedLoopIdx":false,"noReset":false,"attrIsolateAssign":false,"attrFileDescr":false,"isDpiOpenArray":false,"isFuncReturn":true,"isFuncLocal":true,"attrClocker":"UNKNOWN","lifetime":"VAUTOM","varType":"MEMBER","dtypeName":"bit","isSigUserRdPublic":false,"isSigUserRWPublic":false,"isGParam":false,"isParam":false,"attrScBv":false,"attrSFormat":false,"sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []} - ],"classOrPackagep": [], - "stmtsp": [ - {"type":"STMTEXPR","name":"","addr":"(ID)","loc":"d,7:1,7:6", - "exprp": [ - {"type":"CMETHODHARD","name":"clear","addr":"(JD)","loc":"d,7:1,7:6","dtypep":"(LB)", - "fromp": [ - {"type":"VARREF","name":"constraint","addr":"(KD)","loc":"d,7:1,7:6","dtypep":"(PB)","access":"RW","varp":"(QB)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} - ],"pinsp": []} - ]}, - {"type":"STMTEXPR","name":"","addr":"(LD)","loc":"d,19:15,19:20", - "exprp": [ - {"type":"TASKREF","name":"empty_setup_constraint","addr":"(MD)","loc":"d,19:15,19:20","dtypep":"(LB)","dotted":"","taskp":"(ND)","classOrPackagep":"UNLINKED","namep": [],"pinsp": [],"scopeNamep": []} - ]}, - {"type":"STMTEXPR","name":"","addr":"(OD)","loc":"d,21:15,21:19", - "exprp": [ - {"type":"TASKREF","name":"size_setup_constraint","addr":"(PD)","loc":"d,21:15,21:19","dtypep":"(LB)","dotted":"","taskp":"(QD)","classOrPackagep":"UNLINKED","namep": [],"pinsp": [],"scopeNamep": []} - ]}, - {"type":"STMTEXPR","name":"","addr":"(RD)","loc":"d,28:15,28:18", - "exprp": [ - {"type":"TASKREF","name":"ifs_setup_constraint","addr":"(SD)","loc":"d,28:15,28:18","dtypep":"(LB)","dotted":"","taskp":"(TD)","classOrPackagep":"UNLINKED","namep": [],"pinsp": [],"scopeNamep": []} - ]}, - {"type":"STMTEXPR","name":"","addr":"(UD)","loc":"d,41:15,41:23", - "exprp": [ - {"type":"TASKREF","name":"arr_uniq_setup_constraint","addr":"(VD)","loc":"d,41:15,41:23","dtypep":"(LB)","dotted":"","taskp":"(WD)","classOrPackagep":"UNLINKED","namep": [],"pinsp": [],"scopeNamep": []} - ]}, - {"type":"STMTEXPR","name":"","addr":"(XD)","loc":"d,48:15,48:20", - "exprp": [ - {"type":"TASKREF","name":"order_setup_constraint","addr":"(YD)","loc":"d,48:15,48:20","dtypep":"(LB)","dotted":"","taskp":"(ZD)","classOrPackagep":"UNLINKED","namep": [],"pinsp": [],"scopeNamep": []} - ]}, - {"type":"STMTEXPR","name":"","addr":"(AE)","loc":"d,50:15,50:18", - "exprp": [ - {"type":"TASKREF","name":"dis_setup_constraint","addr":"(BE)","loc":"d,50:15,50:18","dtypep":"(LB)","dotted":"","taskp":"(CE)","classOrPackagep":"UNLINKED","namep": [],"pinsp": [],"scopeNamep": []} - ]}, - {"type":"STMTEXPR","name":"","addr":"(DE)","loc":"d,56:15,56:19", - "exprp": [ - {"type":"TASKREF","name":"meth_setup_constraint","addr":"(EE)","loc":"d,56:15,56:19","dtypep":"(LB)","dotted":"","taskp":"(FE)","classOrPackagep":"UNLINKED","namep": [],"pinsp": [],"scopeNamep": []} - ]} - ],"scopeNamep": []}, - {"type":"TASK","name":"empty_setup_constraint","addr":"(ND)","loc":"d,7:1,7:6","method":true,"dpiExport":false,"dpiImport":false,"dpiOpenChild":false,"dpiOpenParent":false,"prototype":false,"recursive":false,"taskPublic":false,"cname":"empty_setup_constraint","fvarp": [],"classOrPackagep": [],"stmtsp": [],"scopeNamep": []}, - {"type":"VAR","name":"constraint","addr":"(QB)","loc":"d,19:15,19:20","dtypep":"(PB)","origName":"constraint","isSc":false,"isPrimaryIO":false,"direction":"NONE","isConst":false,"isPullup":false,"isPulldown":false,"isUsedClock":false,"isSigPublic":false,"isLatched":false,"isUsedLoopIdx":false,"noReset":false,"attrIsolateAssign":false,"attrFileDescr":false,"isDpiOpenArray":false,"isFuncReturn":false,"isFuncLocal":false,"attrClocker":"UNKNOWN","lifetime":"NONE","varType":"MEMBER","dtypeName":"VlRandomizer","isSigUserRdPublic":false,"isSigUserRWPublic":false,"isGParam":false,"isParam":false,"attrScBv":false,"attrSFormat":false,"sensIfacep":"UNLINKED","childDTypep": [],"delayp": [],"valuep": [],"attrsp": []}, - {"type":"TASK","name":"size_setup_constraint","addr":"(QD)","loc":"d,7:1,7:6","method":true,"dpiExport":false,"dpiImport":false,"dpiOpenChild":false,"dpiOpenParent":false,"prototype":false,"recursive":false,"taskPublic":false,"cname":"size_setup_constraint","fvarp": [],"classOrPackagep": [], - "stmtsp": [ - {"type":"STMTEXPR","name":"","addr":"(GE)","loc":"d,22:18,22:20", - "exprp": [ - {"type":"CMETHODHARD","name":"hard","addr":"(HE)","loc":"d,22:18,22:20","dtypep":"(LB)", - "fromp": [ - {"type":"VARREF","name":"constraint","addr":"(IE)","loc":"d,22:18,22:20","dtypep":"(PB)","access":"RW","varp":"(QB)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} - ], - "pinsp": [ - {"type":"CONST","name":"\\\"(and (bvsgt header #x00000000) (bvsle header #x00000007))\\\"","addr":"(JE)","loc":"d,22:18,22:20","dtypep":"(M)"} - ]} - ]}, - {"type":"STMTEXPR","name":"","addr":"(KE)","loc":"d,23:14,23:16", - "exprp": [ - {"type":"CMETHODHARD","name":"hard","addr":"(LE)","loc":"d,23:14,23:16","dtypep":"(LB)", - "fromp": [ - {"type":"VARREF","name":"constraint","addr":"(ME)","loc":"d,23:14,23:16","dtypep":"(PB)","access":"RW","varp":"(QB)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} - ], - "pinsp": [ - {"type":"CONST","name":"\\\"(bvsle length #x0000000f)\\\"","addr":"(NE)","loc":"d,23:14,23:16","dtypep":"(M)"} - ]} - ]}, - {"type":"STMTEXPR","name":"","addr":"(OE)","loc":"d,24:14,24:16", - "exprp": [ - {"type":"CMETHODHARD","name":"hard","addr":"(PE)","loc":"d,24:14,24:16","dtypep":"(LB)", - "fromp": [ - {"type":"VARREF","name":"constraint","addr":"(QE)","loc":"d,24:14,24:16","dtypep":"(PB)","access":"RW","varp":"(QB)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} - ], - "pinsp": [ - {"type":"CONST","name":"\\\"(bvsge length header)\\\"","addr":"(RE)","loc":"d,24:14,24:16","dtypep":"(M)"} - ]} - ]}, - {"type":"STMTEXPR","name":"","addr":"(SE)","loc":"d,25:14,25:18", - "exprp": [ - {"type":"CMETHODHARD","name":"hard","addr":"(TE)","loc":"d,25:14,25:18","dtypep":"(LB)", - "fromp": [ - {"type":"VARREF","name":"constraint","addr":"(UE)","loc":"d,25:14,25:18","dtypep":"(PB)","access":"RW","varp":"(QB)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} - ], - "pinsp": [ - {"type":"CONST","name":"\\\"true\\\"","addr":"(VE)","loc":"d,25:14,25:18","dtypep":"(M)"} - ]} - ]} - ],"scopeNamep": []}, - {"type":"TASK","name":"ifs_setup_constraint","addr":"(TD)","loc":"d,7:1,7:6","method":true,"dpiExport":false,"dpiImport":false,"dpiOpenChild":false,"dpiOpenParent":false,"prototype":false,"recursive":false,"taskPublic":false,"cname":"ifs_setup_constraint","fvarp": [],"classOrPackagep": [], - "stmtsp": [ - {"type":"STMTEXPR","name":"","addr":"(WE)","loc":"d,29:7,29:9", - "exprp": [ - {"type":"CMETHODHARD","name":"hard","addr":"(XE)","loc":"d,29:7,29:9","dtypep":"(LB)", - "fromp": [ - {"type":"VARREF","name":"constraint","addr":"(YE)","loc":"d,29:7,29:9","dtypep":"(PB)","access":"RW","varp":"(QB)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} - ], - "pinsp": [ - {"type":"CONST","name":"\\\"(=> (bvsgt header #x00000004) (= if_4 #b1))\\\"","addr":"(ZE)","loc":"d,29:7,29:9","dtypep":"(M)"} - ]} - ]}, - {"type":"STMTEXPR","name":"","addr":"(AF)","loc":"d,32:7,32:9", - "exprp": [ - {"type":"CMETHODHARD","name":"hard","addr":"(BF)","loc":"d,32:7,32:9","dtypep":"(LB)", - "fromp": [ - {"type":"VARREF","name":"constraint","addr":"(CF)","loc":"d,32:7,32:9","dtypep":"(PB)","access":"RW","varp":"(QB)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} - ], - "pinsp": [ - {"type":"CONST","name":"\\\"(ite (or (= header #x00000005) (= header #x00000006)) (and (= iff_5_6 #b1) (= iff_5_6 #b1) (= iff_5_6 #b1)) (= iff_5_6 #b0))\\\"","addr":"(DF)","loc":"d,32:7,32:9","dtypep":"(M)"} - ]} - ]} - ],"scopeNamep": []}, - {"type":"TASK","name":"arr_uniq_setup_constraint","addr":"(WD)","loc":"d,7:1,7:6","method":true,"dpiExport":false,"dpiImport":false,"dpiOpenChild":false,"dpiOpenParent":false,"prototype":false,"recursive":false,"taskPublic":false,"cname":"arr_uniq_setup_constraint","fvarp": [],"classOrPackagep": [],"stmtsp": [],"scopeNamep": []}, - {"type":"TASK","name":"order_setup_constraint","addr":"(ZD)","loc":"d,7:1,7:6","method":true,"dpiExport":false,"dpiImport":false,"dpiOpenChild":false,"dpiOpenParent":false,"prototype":false,"recursive":false,"taskPublic":false,"cname":"order_setup_constraint","fvarp": [],"classOrPackagep": [],"stmtsp": [],"scopeNamep": []}, - {"type":"TASK","name":"dis_setup_constraint","addr":"(CE)","loc":"d,7:1,7:6","method":true,"dpiExport":false,"dpiImport":false,"dpiOpenChild":false,"dpiOpenParent":false,"prototype":false,"recursive":false,"taskPublic":false,"cname":"dis_setup_constraint","fvarp": [],"classOrPackagep": [], - "stmtsp": [ - {"type":"STMTEXPR","name":"","addr":"(EF)","loc":"d,51:7,51:11", - "exprp": [ - {"type":"CMETHODHARD","name":"hard","addr":"(FF)","loc":"d,51:7,51:11","dtypep":"(LB)", - "fromp": [ - {"type":"VARREF","name":"constraint","addr":"(GF)","loc":"d,51:7,51:11","dtypep":"(PB)","access":"RW","varp":"(QB)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} - ], - "pinsp": [ - {"type":"CONST","name":"\\\"sublength\\\"","addr":"(HF)","loc":"d,51:12,51:21","dtypep":"(M)"} - ]} - ]}, - {"type":"STMTEXPR","name":"","addr":"(IF)","loc":"d,52:7,52:14", - "exprp": [ - {"type":"CMETHODHARD","name":"hard","addr":"(JF)","loc":"d,52:7,52:14","dtypep":"(LB)", - "fromp": [ - {"type":"VARREF","name":"constraint","addr":"(KF)","loc":"d,52:7,52:14","dtypep":"(PB)","access":"RW","varp":"(QB)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} - ], - "pinsp": [ - {"type":"CONST","name":"\\\"sublength\\\"","addr":"(LF)","loc":"d,52:20,52:29","dtypep":"(M)"} - ]} - ]}, - {"type":"STMTEXPR","name":"","addr":"(MF)","loc":"d,53:17,53:19", - "exprp": [ - {"type":"CMETHODHARD","name":"hard","addr":"(NF)","loc":"d,53:17,53:19","dtypep":"(LB)", - "fromp": [ - {"type":"VARREF","name":"constraint","addr":"(OF)","loc":"d,53:17,53:19","dtypep":"(PB)","access":"RW","varp":"(QB)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} - ], - "pinsp": [ - {"type":"CONST","name":"\\\"(bvsle sublength length)\\\"","addr":"(PF)","loc":"d,53:17,53:19","dtypep":"(M)"} - ]} - ]} - ],"scopeNamep": []}, - {"type":"TASK","name":"meth_setup_constraint","addr":"(FE)","loc":"d,7:1,7:6","method":true,"dpiExport":false,"dpiImport":false,"dpiOpenChild":false,"dpiOpenParent":false,"prototype":false,"recursive":false,"taskPublic":false,"cname":"meth_setup_constraint","fvarp": [],"classOrPackagep": [], - "stmtsp": [ - {"type":"STMTEXPR","name":"","addr":"(QF)","loc":"d,57:7,57:9", - "exprp": [ - {"type":"CMETHODHARD","name":"hard","addr":"(RF)","loc":"d,57:7,57:9","dtypep":"(LB)", - "fromp": [ - {"type":"VARREF","name":"constraint","addr":"(SF)","loc":"d,57:7,57:9","dtypep":"(PB)","access":"RW","varp":"(QB)","varScopep":"UNLINKED","classOrPackagep":"UNLINKED"} - ], - "pinsp": [ - {"type":"SFORMATF","name":"(=> %@ (= if_state_ok #b1))","addr":"(TF)","loc":"d,57:7,57:9","dtypep":"(M)", - "exprsp": [ - {"type":"SFORMATF","name":"#b%b","addr":"(UF)","loc":"d,57:11,57:24","dtypep":"(M)", - "exprsp": [ - {"type":"FUNCREF","name":"strings_equal","addr":"(VF)","loc":"d,57:11,57:24","dtypep":"(U)","dotted":"","taskp":"(AB)","classOrPackagep":"(O)","namep": [], - "pinsp": [ - {"type":"ARG","name":"","addr":"(WF)","loc":"d,57:25,57:30", - "exprp": [ - {"type":"VARREF","name":"state","addr":"(XF)","loc":"d,57:25,57:30","dtypep":"(M)","access":"RD","varp":"(Z)","varScopep":"UNLINKED","classOrPackagep":"(O)"} - ]}, - {"type":"ARG","name":"","addr":"(YF)","loc":"d,57:32,57:36", - "exprp": [ - {"type":"CONST","name":"\\\"ok\\\"","addr":"(ZF)","loc":"d,57:32,57:36","dtypep":"(M)"} - ]} - ],"scopeNamep": []} - ],"scopeNamep": []} - ],"scopeNamep": []} - ]} - ]} - ],"scopeNamep": []} + {"type":"FUNC","name":"new","addr":"(KB)","loc":"d,7:1,7:6","dtypep":"(LB)","method":true,"dpiExport":false,"dpiImport":false,"dpiOpenChild":false,"dpiOpenParent":false,"prototype":false,"recursive":false,"taskPublic":false,"cname":"new","fvarp": [],"classOrPackagep": [],"stmtsp": [],"scopeNamep": []} ],"activesp": [],"extendsp": []} ],"activesp": []} ],"filesp": [], @@ -321,31 +56,28 @@ {"type":"TYPETABLE","name":"","addr":"(C)","loc":"a,0:0,0:0","constraintRefp":"UNLINKED","emptyQueuep":"UNLINKED","queueIndexp":"UNLINKED","streamp":"UNLINKED","voidp":"(LB)", "typesp": [ {"type":"BASICDTYPE","name":"logic","addr":"(GB)","loc":"d,22:14,22:15","dtypep":"(GB)","keyword":"logic","generic":true,"rangep": []}, - {"type":"BASICDTYPE","name":"logic","addr":"(AG)","loc":"d,25:21,25:22","dtypep":"(AG)","keyword":"logic","range":"31:0","generic":true,"rangep": []}, + {"type":"BASICDTYPE","name":"logic","addr":"(MB)","loc":"d,25:21,25:22","dtypep":"(MB)","keyword":"logic","range":"31:0","generic":true,"rangep": []}, {"type":"BASICDTYPE","name":"string","addr":"(M)","loc":"d,73:7,73:13","dtypep":"(M)","keyword":"string","generic":true,"rangep": []}, {"type":"BASICDTYPE","name":"int","addr":"(Q)","loc":"d,8:9,8:12","dtypep":"(Q)","keyword":"int","range":"31:0","generic":true,"rangep": []}, {"type":"BASICDTYPE","name":"bit","addr":"(U)","loc":"d,11:9,11:12","dtypep":"(U)","keyword":"bit","generic":true,"rangep": []}, {"type":"UNPACKARRAYDTYPE","name":"","addr":"(Y)","loc":"d,15:18,15:19","dtypep":"(Y)","isCompound":false,"declRange":"[0:1]","generic":false,"refDTypep":"(Q)","childDTypep": [], "rangep": [ - {"type":"RANGE","name":"","addr":"(BG)","loc":"d,15:18,15:19","ascending":true, + {"type":"RANGE","name":"","addr":"(NB)","loc":"d,15:18,15:19","ascending":true, "leftp": [ - {"type":"CONST","name":"32'h0","addr":"(CG)","loc":"d,15:19,15:20","dtypep":"(AG)"} + {"type":"CONST","name":"32'h0","addr":"(OB)","loc":"d,15:19,15:20","dtypep":"(MB)"} ], "rightp": [ - {"type":"CONST","name":"32'h1","addr":"(DG)","loc":"d,15:19,15:20","dtypep":"(AG)"} + {"type":"CONST","name":"32'h1","addr":"(PB)","loc":"d,15:19,15:20","dtypep":"(MB)"} ]} ]}, {"type":"VOIDDTYPE","name":"","addr":"(LB)","loc":"d,7:1,7:6","dtypep":"(LB)","generic":false}, - {"type":"CLASSREFDTYPE","name":"Packet","addr":"(H)","loc":"d,69:4,69:10","dtypep":"(H)","generic":false,"classp":"(O)","classOrPackagep":"(O)","paramsp": []}, - {"type":"BASICDTYPE","name":"bit","addr":"(GD)","loc":"d,7:1,7:6","dtypep":"(GD)","keyword":"bit","range":"31:0","generic":true,"rangep": []}, - {"type":"BASICDTYPE","name":"VlRandomizer","addr":"(PB)","loc":"d,7:1,7:6","dtypep":"(PB)","keyword":"VlRandomizer","generic":true,"rangep": []}, - {"type":"BASICDTYPE","name":"logic","addr":"(TB)","loc":"d,8:9,8:12","dtypep":"(TB)","keyword":"logic","range":"63:0","generic":true,"rangep": []} + {"type":"CLASSREFDTYPE","name":"Packet","addr":"(H)","loc":"d,69:4,69:10","dtypep":"(H)","generic":false,"classp":"(O)","classOrPackagep":"(O)","paramsp": []} ]}, {"type":"CONSTPOOL","name":"","addr":"(D)","loc":"a,0:0,0:0", "modulep": [ - {"type":"MODULE","name":"@CONST-POOL@","addr":"(EG)","loc":"a,0:0,0:0","origName":"@CONST-POOL@","level":0,"modPublic":false,"inLibrary":false,"dead":false,"recursiveClone":false,"recursive":false,"timeunit":"NONE","inlinesp": [], + {"type":"MODULE","name":"@CONST-POOL@","addr":"(QB)","loc":"a,0:0,0:0","origName":"@CONST-POOL@","level":0,"modPublic":false,"inLibrary":false,"dead":false,"recursiveClone":false,"recursive":false,"timeunit":"NONE","inlinesp": [], "stmtsp": [ - {"type":"SCOPE","name":"@CONST-POOL@","addr":"(FG)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(EG)","varsp": [],"blocksp": [],"inlinesp": []} + {"type":"SCOPE","name":"@CONST-POOL@","addr":"(RB)","loc":"a,0:0,0:0","aboveScopep":"UNLINKED","aboveCellp":"UNLINKED","modp":"(QB)","varsp": [],"blocksp": [],"inlinesp": []} ],"activesp": []} ]} ]} diff --git a/test_regress/t/t_constraint_xml.out b/test_regress/t/t_constraint_xml.out index 8eb09eba6..6b763d041 100644 --- a/test_regress/t/t_constraint_xml.out +++ b/test_regress/t/t_constraint_xml.out @@ -47,199 +47,23 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - - + + - - - diff --git a/test_regress/t/t_randomize_method.v b/test_regress/t/t_randomize_method.v index 1309f9f03..9db38279b 100644 --- a/test_regress/t/t_randomize_method.v +++ b/test_regress/t/t_randomize_method.v @@ -1,4 +1,4 @@ -// DESCRIPTION: Verilator: Verilog Test module +// DESCRIPTION: Verilog Test module // // This file ONLY is placed under the Creative Commons Public Domain, for // any use, without warranty, 2020 by Wilson Snyder. @@ -45,7 +45,7 @@ typedef struct { longint z; } StructUnpacked; -class BaseCls; +class BaseCls1; endclass class Inner; @@ -65,7 +65,7 @@ class Inner; endclass -class DerivedCls extends BaseCls; +class DerivedCls1 extends BaseCls1; rand Inner i; rand int j; int k; @@ -80,6 +80,24 @@ class DerivedCls extends BaseCls; endclass +class BaseCls2; + rand int i; + + function new; + i = 0; + endfunction +endclass + +class DerivedCls2 extends BaseCls2; + rand int j; + + function new; + super.new; + j = 0; + endfunction +endclass + + class OtherCls; logic[63:0] v; rand logic[63:0] w; @@ -102,7 +120,7 @@ class OtherCls; endclass class ContainsNull; - rand BaseCls b; + rand BaseCls1 b; endclass class ClsWithInt; @@ -137,35 +155,37 @@ endclass module t (/*AUTOARG*/); - DerivedCls derived; + DerivedCls1 derived1; + DerivedCls2 derived2; OtherCls other; - BaseCls base; + BaseCls1 base; ContainsNull cont; DeriveClsWithInt der_int; DeriveAndContainClsWithInt der_contain; ClsContainUsedOnlyHere cls_cont_used; initial begin - int rand_result; - derived = new; + derived1 = new; + derived2 = new; other = new; cont = new; der_int = new; der_contain = new; - base = derived; + base = derived1; cls_cont_used = new; for (int i = 0; i < 10; i++) begin - rand_result = base.randomize(); - rand_result = other.randomize(); - rand_result = cont.randomize(); - rand_result = der_int.randomize(); - rand_result = der_contain.randomize(); - if (!(derived.l inside {ONE, TWO, THREE, FOUR})) $stop; + void'(base.randomize()); + void'(derived2.randomize()); + void'(other.randomize()); + void'(cont.randomize()); + void'(der_int.randomize()); + void'(der_contain.randomize()); + if (!(derived1.l inside {ONE, TWO, THREE, FOUR})) $stop; if (!(other.str.j.s.c inside {ONE, TWO, THREE, FOUR})) $stop; if (!(other.str.j.y inside {ONE, TWO, THREE, FOUR})) $stop; if (!(other.str.k inside {ONE, TWO, THREE, FOUR})) $stop; - if (derived.i.e != 0) $stop; - if (derived.k != 0) $stop; + if (derived1.i.e != 0) $stop; + if (derived1.k != 0) $stop; if (other.v != 0) $stop; if (cont.b != null) $stop; if (der_int.b != 0) $stop; @@ -173,11 +193,13 @@ module t (/*AUTOARG*/); if (der_contain.cls1.b != 0) $stop; if (der_contain.b != 0) $stop; end - `check_rand(derived, derived.i.a); - `check_rand(derived, derived.i.b); - `check_rand(derived, derived.i.c); - `check_rand(derived, derived.j); - `check_rand(derived, derived.l); + `check_rand(derived1, derived1.i.a); + `check_rand(derived1, derived1.i.b); + `check_rand(derived1, derived1.i.c); + `check_rand(derived1, derived1.j); + `check_rand(derived1, derived1.l); + `check_rand(derived2, derived2.i); + `check_rand(derived2, derived2.j); `check_rand(other, other.w); `check_rand(other, other.x); `check_rand(other, other.y); diff --git a/test_regress/t/t_randomize_method_types_unsup.out b/test_regress/t/t_randomize_method_types_unsup.out index acbf6feba..cddf650b2 100644 --- a/test_regress/t/t_randomize_method_types_unsup.out +++ b/test_regress/t/t_randomize_method_types_unsup.out @@ -14,7 +14,7 @@ : ... note: In instance 't' 15 | rand Union uni; | ^~~ -%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:16:13: Unsupported: random member variable with type of a current class +%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:16:13: Unsupported: random member variable with the type of the containing class : ... note: In instance 't' 16 | rand Cls cls; | ^~~