diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index a244e1c68..cb2a47f09 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -57,9 +57,11 @@ private: if (VN_IS(memberp, Var) && VN_AS(memberp, Var)->isRand()) { if (const auto* const classRefp = VN_CAST(memberp->dtypep(), ClassRefDType)) { auto* const rclassp = classRefp->classp(); - markMembers(rclassp); - markDerived(rclassp); - rclassp->user1(true); + if (!rclassp->user1()) { + rclassp->user1(true); + markMembers(rclassp); + markDerived(rclassp); + } } } } @@ -69,9 +71,11 @@ private: const auto it = m_baseToDerivedMap.find(nodep); if (it != m_baseToDerivedMap.end()) { for (auto* classp : it->second) { - classp->user1(true); - markMembers(classp); - markDerived(classp); + if (!classp->user1p()) { + classp->user1(true); + markMembers(classp); + markDerived(classp); + } } } } @@ -121,6 +125,7 @@ private: // Cleared on Netlist // AstClass::user1() -> bool. Set true to indicate needs randomize processing // AstEnumDType::user2() -> AstVar*. Pointer to table with enum values + // AstClass::user3() -> AstFunc*. Pointer to randomize() method of a class // VNUser1InUse m_inuser1; (Allocated for use in RandomizeMarkVisitor) const VNUser2InUse m_inuser2; @@ -230,42 +235,59 @@ private: if (!nodep->user1()) return; // Doesn't need randomize, or already processed UINFO(9, "Define randomize() for " << nodep << endl); AstFunc* const funcp = V3Randomize::newRandomizeFunc(nodep); + nodep->user3p(funcp); AstVar* const fvarp = VN_AS(funcp->fvarp(), Var); addPrePostCall(nodep, funcp, "pre_randomize"); FileLine* fl = nodep->fileline(); - funcp->addStmtsp(new AstAssign{fl, new AstVarRef{fl, fvarp, VAccess::WRITE}, - new AstConst{fl, AstConst::WidthedValue{}, 32, 1}}); - for (AstClass* classp = nodep; classp; - classp = classp->extendsp() ? classp->extendsp()->classp() : nullptr) { - for (auto* memberp = classp->stmtsp(); memberp; memberp = memberp->nextp()) { - AstVar* const memberVarp = VN_CAST(memberp, Var); - if (!memberVarp || !memberVarp->isRand()) continue; - const AstNodeDType* const dtypep = memberp->dtypep()->skipRefp(); - if (VN_IS(dtypep, BasicDType) || VN_IS(dtypep, StructDType)) { - AstVarRef* const refp = new AstVarRef{fl, memberVarp, VAccess::WRITE}; - AstNodeStmt* const stmtp = newRandStmtsp(fl, refp); - funcp->addStmtsp(stmtp); - } else if (const auto* const classRefp = VN_CAST(dtypep, ClassRefDType)) { - AstVarRef* const refp = new AstVarRef{fl, memberVarp, VAccess::WRITE}; - AstFunc* const memberFuncp - = V3Randomize::newRandomizeFunc(classRefp->classp()); - AstMethodCall* const callp = new AstMethodCall{fl, refp, "randomize", nullptr}; - callp->taskp(memberFuncp); - callp->dtypeFrom(memberFuncp); - AstAssign* const assignp = new AstAssign{ - fl, new AstVarRef{fl, fvarp, VAccess::WRITE}, - new AstAnd{fl, new AstVarRef{fl, fvarp, VAccess::READ}, callp}}; - AstIf* const assignIfNotNullp - = new AstIf{fl, - new AstNeq{fl, new AstVarRef{fl, memberVarp, VAccess::READ}, - new AstConst{fl, AstConst::Null{}}}, - assignp}; - funcp->addStmtsp(assignIfNotNullp); - } else { - memberp->v3warn(E_UNSUPPORTED, - "Unsupported: random member variables with type " - << memberp->dtypep()->prettyDTypeNameQ()); + + 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()); + beginValp = baseRandCallp; + } + } + if (!beginValp) beginValp = new AstConst{fl, AstConst::WidthedValue{}, 32, 1}; + + funcp->addStmtsp(new AstAssign{fl, new AstVarRef{fl, fvarp, VAccess::WRITE}, beginValp}); + + for (auto* memberp = nodep->stmtsp(); memberp; memberp = memberp->nextp()) { + AstVar* const memberVarp = VN_CAST(memberp, Var); + if (!memberVarp || !memberVarp->isRand()) continue; + const AstNodeDType* const dtypep = memberp->dtypep()->skipRefp(); + if (VN_IS(dtypep, BasicDType) || VN_IS(dtypep, StructDType)) { + AstVarRef* const refp = new AstVarRef{fl, memberVarp, VAccess::WRITE}; + AstNodeStmt* const stmtp = newRandStmtsp(fl, refp); + funcp->addStmtsp(stmtp); + } else if (const auto* const classRefp = VN_CAST(dtypep, ClassRefDType)) { + if (classRefp->classp() == nodep) { + memberp->v3warn( + E_UNSUPPORTED, + "Unsupported: random member variable with type of a current class"); + continue; } + AstVarRef* const refp = new AstVarRef{fl, memberVarp, VAccess::WRITE}; + AstFunc* const memberFuncp = V3Randomize::newRandomizeFunc(classRefp->classp()); + AstMethodCall* const callp = new AstMethodCall{fl, refp, "randomize", nullptr}; + callp->taskp(memberFuncp); + callp->dtypeFrom(memberFuncp); + AstAssign* const assignp = new AstAssign{ + fl, new AstVarRef{fl, fvarp, VAccess::WRITE}, + new AstAnd{fl, new AstVarRef{fl, fvarp, VAccess::READ}, callp}}; + AstIf* const assignIfNotNullp + = new AstIf{fl, + new AstNeq{fl, new AstVarRef{fl, memberVarp, VAccess::READ}, + new AstConst{fl, AstConst::Null{}}}, + assignp}; + funcp->addStmtsp(assignIfNotNullp); + } else { + memberp->v3warn(E_UNSUPPORTED, "Unsupported: random member variable with type " + << memberp->dtypep()->prettyDTypeNameQ()); } } addPrePostCall(nodep, funcp, "post_randomize"); diff --git a/test_regress/t/t_randomize_method.v b/test_regress/t/t_randomize_method.v index 8295dd829..dc3fa9561 100644 --- a/test_regress/t/t_randomize_method.v +++ b/test_regress/t/t_randomize_method.v @@ -96,23 +96,46 @@ class ContainsNull; rand BaseCls b; endclass +class ClsWithInt; + rand int a; + int b; +endclass + +class DeriveClsWithInt extends ClsWithInt; +endclass + +class DeriveAndContainClsWithInt extends ClsWithInt; + rand ClsWithInt cls1; + ClsWithInt cls2; + function new; + cls1 = new; + cls2 = new; + endfunction +endclass + module t (/*AUTOARG*/); DerivedCls derived; OtherCls other; BaseCls base; ContainsNull cont; + DeriveClsWithInt der_int; + DeriveAndContainClsWithInt der_contain; initial begin int rand_result; derived = new; other = new; cont = new; + der_int = new; + der_contain = new; base = derived; 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; if (!(other.str.s.c inside {ONE, TWO, THREE, FOUR})) $stop; if (!(other.str.y inside {ONE, TWO, THREE, FOUR})) $stop; @@ -120,6 +143,10 @@ module t (/*AUTOARG*/); if (derived.k != 0) $stop; if (other.v != 0) $stop; if (cont.b != null) $stop; + if (der_int.b != 0) $stop; + if (der_contain.cls2.a != 0) $stop; + 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); @@ -136,6 +163,9 @@ module t (/*AUTOARG*/); `check_rand(other, other.str.s.a); `check_rand(other, other.str.s.b); `check_rand(other, other.str.s.c); + `check_rand(der_int, der_int.a); + `check_rand(der_contain, der_contain.cls1.a); + `check_rand(der_contain, der_contain.a); $write("*-* All Finished *-*\n"); $finish; diff --git a/test_regress/t/t_randomize_method_types_unsup.out b/test_regress/t/t_randomize_method_types_unsup.out index 175d8a134..331acdcd8 100644 --- a/test_regress/t/t_randomize_method_types_unsup.out +++ b/test_regress/t/t_randomize_method_types_unsup.out @@ -1,18 +1,22 @@ -%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:12:13: Unsupported: random member variables with type 'int[string]' +%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:12:13: Unsupported: random member variable with type 'int[string]' : ... In instance t 12 | rand int assocarr[string]; | ^~~~~~~~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:13:13: Unsupported: random member variables with type 'int[]' +%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:13:13: Unsupported: random member variable 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]' +%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:14:13: Unsupported: random member variable 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 '$unit::Union' +%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:15:15: Unsupported: random member variable with type '$unit::Union' : ... 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 + : ... In instance t + 16 | rand Cls cls; + | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_randomize_method_types_unsup.v b/test_regress/t/t_randomize_method_types_unsup.v index 1595a6c07..fb3fd938d 100644 --- a/test_regress/t/t_randomize_method_types_unsup.v +++ b/test_regress/t/t_randomize_method_types_unsup.v @@ -13,6 +13,7 @@ class Cls; rand int dynarr[]; rand int unpackarr[5]; rand Union uni; + rand Cls cls; endclass module t (/*AUTOARG*/);