From 920c8012dee73facd4bb36b76bc5d6430304cf23 Mon Sep 17 00:00:00 2001 From: Yilou Wang <140522618+YilouWang@users.noreply.github.com> Date: Tue, 8 Oct 2024 16:54:20 +0200 Subject: [PATCH] Support unconstrained randomization for associative array and queue (#5515) --- src/V3Randomize.cpp | 47 +++++++++++------- test_regress/t/t_randomize_array.v | 49 ++++++++++++++++++- .../t/t_randomize_method_types_unsup.out | 4 -- 3 files changed, 76 insertions(+), 24 deletions(-) diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 14539771c..41ab822e9 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -1380,6 +1380,13 @@ class RandomizeVisitor final : public VNVisitor { AstVar* randLoopIndxp = nullptr; AstNodeStmt* stmtsp = nullptr; auto createLoopIndex = [&](AstNodeDType* tempDTypep) { + if (VN_IS(tempDTypep, AssocArrayDType)) { + return new AstVar{ + fl, VVarType::VAR, uniqueNamep->get(""), + dtypep->findBasicDType( + ((AstBasicDType*)VN_AS(tempDTypep, AssocArrayDType)->keyDTypep()) + ->keyword())}; + } return new AstVar{fl, VVarType::VAR, uniqueNamep->get(""), dtypep->findBasicDType(VBasicDTypeKwd::UINT32)}; }; @@ -1398,17 +1405,20 @@ class RandomizeVisitor final : public VNVisitor { return new AstForeach{fl, randLoopVarp, newRandStmtsp(fl, tempElementp, nullptr)}; }; AstNodeExpr* tempElementp = nullptr; - while (VN_CAST(tempDTypep, DynArrayDType) || VN_CAST(tempDTypep, UnpackArrayDType)) { + while (VN_IS(tempDTypep, DynArrayDType) || VN_IS(tempDTypep, UnpackArrayDType) + || VN_IS(tempDTypep, AssocArrayDType) || VN_IS(tempDTypep, QueueDType)) { AstVar* const newRandLoopIndxp = createLoopIndex(tempDTypep); randLoopIndxp = AstNode::addNext(randLoopIndxp, newRandLoopIndxp); - tempElementp - = VN_CAST(tempDTypep, DynArrayDType) - ? static_cast( - new AstCMethodHard{fl, tempElementp ? tempElementp : exprp, "atWrite", - new AstVarRef{fl, newRandLoopIndxp, VAccess::READ}}) - : static_cast( - new AstArraySel{fl, tempElementp ? tempElementp : exprp, - new AstVarRef{fl, newRandLoopIndxp, VAccess::READ}}); + AstNodeExpr* tempExprp = tempElementp ? tempElementp : exprp; + AstVarRef* tempRefp = new AstVarRef{fl, newRandLoopIndxp, VAccess::READ}; + if (VN_IS(tempDTypep, DynArrayDType)) + tempElementp = new AstCMethodHard{fl, tempExprp, "atWrite", tempRefp}; + else if (VN_IS(tempDTypep, UnpackArrayDType)) + tempElementp = new AstArraySel{fl, tempExprp, tempRefp}; + else if (VN_IS(tempDTypep, AssocArrayDType)) + tempElementp = new AstAssocSel{fl, tempExprp, tempRefp}; + else if (VN_IS(tempDTypep, QueueDType)) + tempElementp = new AstCMethodHard{fl, tempExprp, "atWriteAppend", tempRefp}; tempElementp->dtypep(tempDTypep->subDTypep()); tempDTypep = tempDTypep->virtRefDTypep(); } @@ -1449,9 +1459,13 @@ class RandomizeVisitor final : public VNVisitor { return newRandStmtsp(fl, exprp, nullptr, offset, firstMemberp); } else if (AstDynArrayDType* const dynarrayDtp = VN_CAST(memberDtp, DynArrayDType)) { return createArrayForeachLoop(fl, dynarrayDtp, exprp); + } else if (AstQueueDType* const queueDtp = VN_CAST(memberDtp, QueueDType)) { + return createArrayForeachLoop(fl, queueDtp, exprp); } else if (AstUnpackArrayDType* const unpackarrayDtp = VN_CAST(memberDtp, UnpackArrayDType)) { return createArrayForeachLoop(fl, unpackarrayDtp, exprp); + } else if (AstAssocArrayDType* const assocarrayDtp = VN_CAST(memberDtp, AssocArrayDType)) { + return createArrayForeachLoop(fl, assocarrayDtp, exprp); } else { AstNodeExpr* valp; if (AstEnumDType* const enumDtp = VN_CAST(memberp ? memberp->subDTypep()->subDTypep() @@ -1631,14 +1645,7 @@ class RandomizeVisitor final : public VNVisitor { } if (memberVarp->user3()) return; // Handled in constraints const AstNodeDType* const dtypep = memberVarp->dtypep()->skipRefp(); - if (VN_IS(dtypep, BasicDType) || VN_IS(dtypep, StructDType) - || VN_IS(dtypep, UnionDType) || VN_IS(dtypep, PackArrayDType) - || VN_IS(dtypep, UnpackArrayDType) || VN_IS(dtypep, DynArrayDType)) { - AstVar* const randcVarp = newRandcVarsp(memberVarp); - AstVarRef* const refp = new AstVarRef{fl, classp, memberVarp, VAccess::WRITE}; - AstNodeStmt* const stmtp = newRandStmtsp(fl, refp, randcVarp); - basicRandomizep->addStmtsp(new AstBegin{fl, "", stmtp}); - } else if (const AstClassRefDType* const classRefp = VN_CAST(dtypep, ClassRefDType)) { + if (const AstClassRefDType* const classRefp = VN_CAST(dtypep, ClassRefDType)) { if (classRefp->classp() == nodep) { memberVarp->v3warn(E_UNSUPPORTED, "Unsupported: random member variable with the " @@ -1662,8 +1669,10 @@ class RandomizeVisitor final : public VNVisitor { new AstAnd{fl, basicFvarRefReadp, callp}}}; basicRandomizep->addStmtsp(wrapIfRandMode(nodep, memberVarp, assignIfNotNullp)); } else { - memberVarp->v3warn(E_UNSUPPORTED, "Unsupported: random member variable with type " - << memberVarp->dtypep()->prettyDTypeNameQ()); + AstVar* const randcVarp = newRandcVarsp(memberVarp); + AstVarRef* const refp = new AstVarRef{fl, classp, memberVarp, VAccess::WRITE}; + AstNodeStmt* const stmtp = newRandStmtsp(fl, refp, randcVarp); + basicRandomizep->addStmtsp(new AstBegin{fl, "", stmtp}); } }); } diff --git a/test_regress/t/t_randomize_array.v b/test_regress/t/t_randomize_array.v index 58ffb0ac4..bd165adc0 100755 --- a/test_regress/t/t_randomize_array.v +++ b/test_regress/t/t_randomize_array.v @@ -106,11 +106,47 @@ class unconstrained_struct_with_array_test; endclass +class unconstrained_associative_array_test; + + rand int associative_array[string]; + + function new(); + associative_array["key1"] = 0; + associative_array["key2"] = 0; + endfunction + + function void check_randomization(); + `check_rand(this, associative_array["key1"]); + `check_rand(this, associative_array["key2"]); + endfunction + +endclass + +class unconstrained_queue_test; + + rand int queue_array[$]; + + function new(); + for (int i = 0; i < 3; i++) begin + queue_array.push_back('h0 + i); + end + endfunction + + function void check_randomization(); + foreach (queue_array[i]) begin + `check_rand(this, queue_array[i]); + end + endfunction + +endclass + module t_randomize_array; unconstrained_packed_array_test packed_class; unconstrained_unpacked_array_test unpacked_class; unconstrained_dynamic_array_test dynamic_class; unconstrained_struct_with_array_test struct_with_array_class; + unconstrained_associative_array_test associative_array_class; + unconstrained_queue_test queue_class; initial begin // Test 1: Packed Array Unconstrained Constrained Test @@ -132,12 +168,23 @@ module t_randomize_array; end // Test 4: Struct Containing Array Test - struct_with_array_class = new(); repeat(2) begin struct_with_array_class.check_randomization(); end + // Test 5: Associative Array Unconstrained Test + associative_array_class = new(); + repeat(2) begin + associative_array_class.check_randomization(); + end + + // Test 6: Queue Unconstrained Test + queue_class = new(); + repeat(2) begin + queue_class.check_randomization(); + end + $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_randomize_method_types_unsup.out b/test_regress/t/t_randomize_method_types_unsup.out index 165fc83d1..2526171bc 100644 --- a/test_regress/t/t_randomize_method_types_unsup.out +++ b/test_regress/t/t_randomize_method_types_unsup.out @@ -3,10 +3,6 @@ | ^~~~ ... For warning description see https://verilator.org/warn/CONSTRAINTIGN?v=latest ... Use "/* verilator lint_off CONSTRAINTIGN */" and lint_on around source to disable this message. -%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:8:13: Unsupported: random member variable with type 'int$[string]' - : ... note: In instance 't' - 8 | rand int assocarr[string]; - | ^~~~~~~~ %Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:10:13: Unsupported: random member variable with the type of the containing class : ... note: In instance 't' 10 | rand Cls cls;