diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 735b171c2..0e43b1cee 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -557,6 +557,21 @@ class ConstraintExprVisitor final : public VNVisitor { return new AstSFormatF{fl, fmt.str(), false, exprsp}; } + AstNodeExpr* newSel(FileLine* fl, AstNodeExpr* arrayp, AstNodeExpr* idxp) { + // similar to V3WidthSel.cpp + AstNodeDType* const arrDtp = arrayp->unlinkFrBack()->dtypep(); + AstNodeExpr* selp = nullptr; + if (VN_IS(arrDtp, QueueDType) || VN_IS(arrDtp, DynArrayDType)) + selp = new AstCMethodHard{fl, arrayp, "at", idxp}; + else if (VN_IS(arrDtp, UnpackArrayDType)) + selp = new AstArraySel{fl, arrayp, idxp}; + else if (VN_IS(arrDtp, AssocArrayDType)) + selp = new AstAssocSel{fl, arrayp, idxp}; + UASSERT_OBJ(selp, arrayp, "Selecting from non-array?"); + selp->dtypep(arrDtp->subDTypep()); + return selp; + } + // VISITORS void visit(AstNodeVarRef* nodep) override { AstVar* const varp = nodep->varp(); @@ -699,8 +714,7 @@ class ConstraintExprVisitor final : public VNVisitor { new AstForeach{fl, nodep->arrayp()->unlinkFrBack(), new AstCStmt{fl, cstmtp}}, false, true}); exprsp->addNext( - new AstText{fl, "return ret.empty() ? \"#b1\" : \"(bvand \" + ret + \")\";"}); - exprsp->addNext(new AstText{fl, "return ret + \")\"; })()"}); + new AstText{fl, "return ret.empty() ? \"#b1\" : \"(bvand\" + ret + \")\";})()"}); AstNodeExpr* const newp = new AstCExpr{fl, exprsp}; newp->dtypeSetString(); nodep->replaceWith(new AstSFormatF{fl, "%@", false, newp}); @@ -741,18 +755,45 @@ class ConstraintExprVisitor final : public VNVisitor { } void visit(AstCMethodHard* nodep) override { if (editFormat(nodep)) return; + FileLine* const fl = nodep->fileline(); if (nodep->name() == "at" && nodep->fromp()->user1()) { iterateChildren(nodep); AstNodeExpr* const argsp = AstNode::addNext(nodep->fromp()->unlinkFrBack(), nodep->pinsp()->unlinkFrBack()); - AstSFormatF* const newp - = new AstSFormatF{nodep->fileline(), "(select %@ %@)", false, argsp}; + AstSFormatF* const newp = new AstSFormatF{fl, "(select %@ %@)", false, argsp}; nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); return; } + if (nodep->name() == "inside") { + bool randArr = nodep->fromp()->user1(); + + AstVar* const newVarp + = new AstVar{fl, VVarType::BLOCKTEMP, "__Vinside", nodep->findSigned32DType()}; + AstNodeExpr* const idxRefp = new AstVarRef{nodep->fileline(), newVarp, VAccess::READ}; + AstSelLoopVars* const arrayp + = new AstSelLoopVars{fl, nodep->fromp()->cloneTreePure(false), newVarp}; + AstNodeExpr* const selp = newSel(nodep->fileline(), nodep->fromp(), idxRefp); + selp->user1(randArr); + AstNode* const itemp = new AstEq{fl, selp, nodep->pinsp()->unlinkFrBack()}; + itemp->user1(true); + AstNode* const cstmtp = new AstText{fl, "ret += \" \" + "}; + cstmtp->addNext(iterateSubtreeReturnEdits(itemp)); + cstmtp->addNext(new AstText{fl, ";"}); + AstNode* const exprsp = new AstText{fl, "([&]{ std::string ret;"}; + exprsp->addNext(new AstBegin{ + fl, "", new AstForeach{fl, arrayp, new AstCStmt{fl, cstmtp}}, false, true}); + exprsp->addNext( + new AstText{fl, "return ret.empty() ? \"#b0\" : \"(bvor\" + ret + \")\";})()"}); + AstNodeExpr* const newp = new AstCExpr{fl, exprsp}; + newp->dtypeSetString(); + nodep->replaceWith(new AstSFormatF{fl, "%@", false, newp}); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + return; + } + nodep->v3warn(CONSTRAINTIGN, "Unsupported: randomizing this expression, treating as state"); nodep->user1(false); diff --git a/test_regress/t/t_constraint_dist.v b/test_regress/t/t_constraint_dist.v index 2077ec821..ce695844c 100644 --- a/test_regress/t/t_constraint_dist.v +++ b/test_regress/t/t_constraint_dist.v @@ -20,12 +20,18 @@ begin \ end class C; - rand int x, y; + rand int x, y, z, w; + int que[$] = '{3, 4, 5}; + int arr[3] = '{5, 6, 7}; constraint distrib { x dist { [1:3] := 0, [5:6], [9:15] :/ 0 }; y dist { [1:3] := 0, 5, 6 := 8, [9:15] :/ 0 }; x < 20; }; + constraint distinside { + z dist {que}; + w dist {arr}; + }; endclass module t; @@ -33,6 +39,8 @@ module t; C c = new; `check_rand(c, c.x, 5 <= c.x && c.x <= 6); `check_rand(c, c.y, 5 <= c.y && c.y <= 6); + `check_rand(c, c.z, 3 <= c.z && c.z <= 5); + `check_rand(c, c.w, 5 <= c.w && c.w <= 7); $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_constraint_dist_unsup.out b/test_regress/t/t_constraint_dist_unsup.out deleted file mode 100644 index bfb970312..000000000 --- a/test_regress/t/t_constraint_dist_unsup.out +++ /dev/null @@ -1,17 +0,0 @@ -%Warning-CONSTRAINTIGN: t/t_constraint_dist_unsup.v:27:10: Constraint expression ignored (imperfect distribution) - : ... note: In instance 't' - 27 | x dist {que}; - | ^~~~ - ... 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. -%Warning-CONSTRAINTIGN: t/t_constraint_dist_unsup.v:28:10: Constraint expression ignored (imperfect distribution) - : ... note: In instance 't' - 28 | y dist {arr}; - | ^~~~ -%Warning-CONSTRAINTIGN: t/t_constraint_dist_unsup.v:27:10: Unsupported: randomizing this expression, treating as state - 27 | x dist {que}; - | ^~~~ -%Warning-CONSTRAINTIGN: t/t_constraint_dist_unsup.v:28:10: Unsupported: randomizing this expression, treating as state - 28 | y dist {arr}; - | ^~~~ -%Error: Exiting due to diff --git a/test_regress/t/t_constraint_dist_unsup.py b/test_regress/t/t_constraint_dist_unsup.py deleted file mode 100755 index 272fc1280..000000000 --- a/test_regress/t/t_constraint_dist_unsup.py +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env python3 -# 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 - -import vltest_bootstrap - -test.scenarios('linter') - -test.lint(fails=test.vlt_all, expect_filename=test.golden_filename) - -test.passes() diff --git a/test_regress/t/t_constraint_dist_unsup.v b/test_regress/t/t_constraint_dist_unsup.v deleted file mode 100644 index 9f25aacda..000000000 --- a/test_regress/t/t_constraint_dist_unsup.v +++ /dev/null @@ -1,40 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2024 by Antmicro Ltd. -// 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 - -class C; - int que[$] = '{3, 4, 5}; - int arr[3] = '{5, 6, 7}; - rand int x, y; - constraint distrib { - x dist {que}; - y dist {arr}; - }; -endclass - -module t; - initial begin - C c = new; - `check_rand(c, c.x, 3 <= c.x && c.x <= 5); - `check_rand(c, c.y, 5 <= c.y && c.y <= 7); - $write("*-* All Finished *-*\n"); - $finish; - end -endmodule