diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 920b5bd75..12ab9539e 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -2058,7 +2058,7 @@ AstMemberSel::AstMemberSel(FileLine* fl, AstNodeExpr* fromp, AstVar* varp) bool AstMemberSel::sameNode(const AstNode* samep) const { const AstMemberSel* const sp = VN_DBG_AS(samep, MemberSel); return sp && access() == sp->access() && fromp()->isSame(sp->fromp()) && name() == sp->name() - && (varp() && sp->varp() && varp()->sameNode(sp->varp())); + && (varp() == sp->varp() || (varp() && sp->varp() && varp()->sameNode(sp->varp()))); } void AstMemberSel::dump(std::ostream& str) const { diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 7d7552171..f2b97b849 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -54,6 +54,8 @@ class LinkResolveVisitor final : public VNVisitor { int m_senitemCvtNum = 0; // Temporary signal counter std::deque m_underGenFors; // Stack of GenFor underneath bool m_underGenerate = false; // Under GenFor/GenIf + AstNodeExpr* m_currentRandomizeSelectp = nullptr; // fromp() of current `randomize()` call + bool m_inRandomizeWith = false; // If in randomize() with (and no other with afterwards) // VISITORS // TODO: Most of these visitors are here for historical reasons. @@ -185,6 +187,18 @@ class LinkResolveVisitor final : public VNVisitor { if (nodep->dpiExport()) nodep->scopeNamep(new AstScopeName{nodep->fileline(), false}); } void visit(AstNodeFTaskRef* nodep) override { + VL_RESTORER(m_currentRandomizeSelectp); + + if (nodep->name() == "randomize") { + if (const AstMethodCall* const methodcallp = VN_CAST(nodep, MethodCall)) { + if (m_inRandomizeWith) { + nodep->v3warn( + E_UNSUPPORTED, + "Unsupported: randomize() nested in inline randomize() constraints"); + } + m_currentRandomizeSelectp = methodcallp->fromp(); + } + } iterateChildren(nodep); if (AstLet* letp = VN_CAST(nodep->taskp(), Let)) { UINFO(7, "letSubstitute() " << nodep << " <- " << letp); @@ -525,6 +539,30 @@ class LinkResolveVisitor final : public VNVisitor { iterateChildren(nodep); } + void visit(AstMemberSel* nodep) override { + if (m_inRandomizeWith && nodep->fromp()->isSame(m_currentRandomizeSelectp)) { + // Replace member selects to the element + // on which the randomize() is called with LambdaArgRef + // This allows V3Randomize to work properly when + // constrained variables are referred using that object + AstNodeExpr* const prevFromp = nodep->fromp(); + prevFromp->replaceWith( + new AstLambdaArgRef{prevFromp->fileline(), prevFromp->name(), false}); + pushDeletep(prevFromp); + } + iterateChildren(nodep); + } + + void visit(AstWith* nodep) override { + VL_RESTORER(m_inRandomizeWith); + if (const AstMethodCall* const methodCallp = VN_CAST(nodep->backp(), MethodCall)) { + m_inRandomizeWith = methodCallp->name() == "randomize"; + } else { + m_inRandomizeWith = false; + } + iterateChildren(nodep); + } + void visit(AstNode* nodep) override { iterateChildren(nodep); } public: diff --git a/test_regress/t/t_randomize_member_select.py b/test_regress/t/t_randomize_member_select.py new file mode 100755 index 000000000..466368b3d --- /dev/null +++ b/test_regress/t/t_randomize_member_select.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2025 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('simulator') + +if not test.have_solver: + test.skip("No constraint solver installed") + +test.compile() + +test.execute() + +test.passes() diff --git a/test_regress/t/t_randomize_member_select.v b/test_regress/t/t_randomize_member_select.v new file mode 100644 index 000000000..d0bd36df5 --- /dev/null +++ b/test_regress/t/t_randomize_member_select.v @@ -0,0 +1,50 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by Antmicro. +// SPDX-License-Identifier: CC0-1.0 + +class B; + rand int insideB; + constraint i { + insideB inside {[0:10]}; + }; +endclass + +class A; + rand logic[31:0] rdata; + rand int delay; + int i = 97; + rand B b; + function new(); + b = new; + endfunction + constraint delay_bounds { + delay inside {[0:2]}; + } +endclass + +module t; + A a; + int i; + int delay; + logic[31:0] rdata; + int b; + initial begin + a = new; + i = 7; + repeat (120) begin + a.b.insideB = 3; + a.delay = 1; + a.rdata = 3; + if (a.randomize() with {if (a.delay == 1) a.rdata == i;} == 0) $stop; + if (a.b.randomize() with {a.b.insideB < 3;} == 0) $stop; + if (a.delay == 1 && a.rdata != 97) $stop; + if (a.b.insideB >= 3) $stop; + if (a.randomize() with {if (a.delay == 1) a.rdata == local::i;} == 0) $stop; + if (a.delay == 1 && a.rdata != 7) $stop; + end + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_randomize_neasted_unsup.out b/test_regress/t/t_randomize_neasted_unsup.out new file mode 100644 index 000000000..61a5c5a27 --- /dev/null +++ b/test_regress/t/t_randomize_neasted_unsup.out @@ -0,0 +1,5 @@ +%Error-UNSUPPORTED: t/t_randomize_neasted_unsup.v:17:41: Unsupported: randomize() nested in inline randomize() constraints + 17 | if (a.randomize() with {rdata == aa.randomize();} == 0) $stop; + | ^~~~~~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_randomize_neasted_unsup.py b/test_regress/t/t_randomize_neasted_unsup.py new file mode 100755 index 000000000..1bf1426f9 --- /dev/null +++ b/test_regress/t/t_randomize_neasted_unsup.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2025 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('vlt') + +test.lint(fails=True, expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_randomize_neasted_unsup.v b/test_regress/t/t_randomize_neasted_unsup.v new file mode 100644 index 000000000..8a47d9167 --- /dev/null +++ b/test_regress/t/t_randomize_neasted_unsup.v @@ -0,0 +1,21 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by Antmicro. +// SPDX-License-Identifier: CC0-1.0 + +class A; + rand logic[31:0] rdata; +endclass + +module t; + A a; + A aa; + initial begin + a = new; + aa = new; + if (a.randomize() with {rdata == aa.randomize();} == 0) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule