diff --git a/include/verilated_std.sv b/include/verilated_std.sv index 8c5ac2d0a..2741f03bc 100644 --- a/include/verilated_std.sv +++ b/include/verilated_std.sv @@ -195,4 +195,7 @@ package std; $urandom(s.atoi()); // Set the seed using a string endfunction endclass + function int randomize(); + randomize = 0; + endfunction endpackage diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 0617d46cc..fd1f57d90 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1508,11 +1508,15 @@ class LinkDotFindVisitor final : public VNVisitor { void visit(AstWithParse* nodep) override { // Change WITHPARSE(FUNCREF, equation) to FUNCREF(WITH(equation)) - const auto funcrefp = VN_AS(nodep->funcrefp(), NodeFTaskRef); + AstNodeFTaskRef* funcrefp = VN_CAST(nodep->funcrefp(), NodeFTaskRef); + if (const AstDot* const dotp = VN_CAST(nodep->funcrefp(), Dot)) + funcrefp = VN_CAST(dotp->rhsp(), NodeFTaskRef); UASSERT_OBJ(funcrefp, nodep, "'with' only can operate on a function/task"); string name = "item"; FileLine* argFl = nodep->fileline(); - if (const auto argp = VN_CAST(funcrefp->pinsp(), Arg)) { + AstArg* argp = VN_CAST(funcrefp->pinsp(), Arg); + if (argp) argp->unlinkFrBackWithNext(); + if (argp && funcrefp->name() != "randomize") { if (const auto parserefp = VN_CAST(argp->exprp(), ParseRef)) { name = parserefp->name(); argFl = parserefp->fileline(); @@ -1521,7 +1525,7 @@ class LinkDotFindVisitor final : public VNVisitor { } if (argp->nextp()) argp->nextp()->v3error("'with' function expects only up to one argument"); - VL_DO_DANGLING(argp->unlinkFrBackWithNext()->deleteTree(), argp); + VL_DO_DANGLING(argp->deleteTree(), argp); } // Type depends on the method used, let V3Width figure it out later if (nodep->exprsp()) { // Else empty expression and pretend no "with" @@ -1531,7 +1535,8 @@ class LinkDotFindVisitor final : public VNVisitor { nodep->exprsp()->unlinkFrBackWithNext()}; funcrefp->addPinsp(newp); } - nodep->replaceWith(funcrefp->unlinkFrBack()); + funcrefp->addPinsp(argp); + nodep->replaceWith(nodep->funcrefp()->unlinkFrBack()); VL_DO_DANGLING(nodep->deleteTree(), nodep); } void visit(AstWith* nodep) override { diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 745939466..84c567177 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -5917,6 +5917,18 @@ class WidthVisitor final : public VNVisitor { || nodep->name() == "set_randstate"))) { // TODO perhaps this should move to V3LinkDot AstClass* const classp = VN_CAST(nodep->classOrPackagep(), Class); + if (!classp) { + AstNodeDType* const adtypep = nodep->findBitDType(); + withp = methodWithArgument(nodep, false, false, adtypep->findVoidDType(), + adtypep->findBitDType(), adtypep); + for (const AstNode* argp = nodep->pinsp(); argp; argp = argp->nextp()) + userIterateAndNext(VN_AS(argp, Arg)->exprp(), WidthVP{SELF, BOTH}.p()); + nodep->addPinsp(withp); + nodep->v3warn(CONSTRAINTIGN, "std::randomize ignored (unsupported)"); + nodep->replaceWith(new AstConst{nodep->fileline(), 0}); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + return; + } UASSERT_OBJ(classp, nodep, "Should have failed in V3LinkDot"); if (nodep->name() == "randomize") { nodep->taskp(V3Randomize::newRandomizeFunc(m_memberMap, classp)); diff --git a/test_regress/t/t_std_randomize_unsup_bad.out b/test_regress/t/t_std_randomize_unsup_bad.out new file mode 100644 index 000000000..ebaa0ee6a --- /dev/null +++ b/test_regress/t/t_std_randomize_unsup_bad.out @@ -0,0 +1,11 @@ +%Warning-CONSTRAINTIGN: t/t_std_randomize_unsup_bad.v:10:16: std::randomize ignored (unsupported) + : ... note: In instance 't' + 10 | if (std::randomize(a, b) != 1) $stop; + | ^~~~~~~~~ + ... 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_std_randomize_unsup_bad.v:11:16: std::randomize ignored (unsupported) + : ... note: In instance 't' + 11 | if (std::randomize(a, b) with { 2 < a; a < 7; b < a; } != 1) $stop; + | ^~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_std_randomize_unsup_bad.pl b/test_regress/t/t_std_randomize_unsup_bad.pl new file mode 100755 index 000000000..a60503a1f --- /dev/null +++ b/test_regress/t/t_std_randomize_unsup_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 2003 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(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_std_randomize_unsup_bad.v b/test_regress/t/t_std_randomize_unsup_bad.v new file mode 100644 index 000000000..c848a3e43 --- /dev/null +++ b/test_regress/t/t_std_randomize_unsup_bad.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, 2024 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t; + initial begin + int a, b; + if (std::randomize(a, b) != 1) $stop; + if (std::randomize(a, b) with { 2 < a; a < 7; b < a; } != 1) $stop; + if (!(2 < a && a < 7 && b < a)) $stop; + $write("-*-* All Finished *-*-\n"); + $finish; + end +endmodule