diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 3cdf22e39..ad87ed3b6 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -39,6 +39,7 @@ Aylon Chaim Porat Bartłomiej Chmiel Bartosz Skorowski Benjamin Collier +BRDR LIFE Brian Li Cameron Kirk Cameron Waite diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 39ed3b44d..6bfd27823 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2195,7 +2195,7 @@ class LinkDotFindVisitor final : public VNVisitor { 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"; + string name = funcrefp->name() == "randomize" ? "__Vrandwith_obj" : "item"; FileLine* argFl = nodep->fileline(); AstArg* const argsp = funcrefp->argsp(); if (argsp) { @@ -4298,7 +4298,7 @@ class LinkDotResolveVisitor final : public VNVisitor { } UINFO(9, indent() << "randomize-with fromSym " << foundp->nodep()); AstLambdaArgRef* const lambdaRefp - = new AstLambdaArgRef{nodep->fileline(), "item", false}; + = new AstLambdaArgRef{nodep->fileline(), "__Vrandwith_obj", false}; AstMemberSel* newp = new AstMemberSel{nodep->fileline(), lambdaRefp, VFlagChildDType{}, nodep->name()}; nodep->replaceWith(newp); @@ -5259,7 +5259,8 @@ class LinkDotResolveVisitor final : public VNVisitor { } if (m_ds.m_dotPos != DP_NONE) m_ds.m_dotPos = DP_MEMBER; AstNode* const newp = new AstMethodCall{ - nodep->fileline(), new AstLambdaArgRef{nodep->fileline(), "item", false}, + nodep->fileline(), + new AstLambdaArgRef{nodep->fileline(), "__Vrandwith_obj", false}, VFlagChildDType{}, nodep->name(), argsp}; nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); diff --git a/test_regress/t/t_debug_emitv.out b/test_regress/t/t_debug_emitv.out index 2574d2c56..b88e201e3 100644 --- a/test_regress/t/t_debug_emitv.out +++ b/test_regress/t/t_debug_emitv.out @@ -1287,7 +1287,7 @@ package Vt_debug_emitv___024unit; begin : label8 rand_restricted = randomize() with ( ???? // CONSTRAINTEXPR - (item.rmember1 < member)) ; + (__Vrandwith_obj.rmember1 < member)) ; disable label8; end endfunction diff --git a/test_regress/t/t_randomize_with_item_name.py b/test_regress/t/t_randomize_with_item_name.py new file mode 100755 index 000000000..db1adb3f9 --- /dev/null +++ b/test_regress/t/t_randomize_with_item_name.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2026 Wilson Snyder +# 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_with_item_name.v b/test_regress/t/t_randomize_with_item_name.v new file mode 100644 index 000000000..664c1c9f1 --- /dev/null +++ b/test_regress/t/t_randomize_with_item_name.v @@ -0,0 +1,124 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Wilson Snyder +// SPDX-License-Identifier: CC0-1.0 + +// verilog_format: off +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0x exp=%0x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +// verilog_format: on + +// IEEE 1800-2023 7.12.1 gives array-method 'with' clauses a default iterator +// named 'item'. randomize() with (18.7) has no such iterator, so a user +// variable named 'item' must resolve normally inside the constraint. + +class Payload; + rand bit [31:0] addr; +endclass + +// The randomized class's own member is spelled 'item'. An undotted name in a +// randomize() with resolves in the object's scope first (18.7), so this must +// reach the member being randomized and not any outer 'item'. +class Tagged; + rand bit [31:0] item; + rand bit [31:0] other; +endclass + +// A queue to fold with an array-method 'with', from inside a randomize 'with'. +class Summed; + rand bit [31:0] other; + int q[$] = '{1, 4, 2, 7}; +endclass + +class Seq; + Payload item; // class member deliberately named 'item' + + function new(); + item = new(); + item.addr = 32'h8000_0084; + endfunction + + // Member handle named 'item', dereferenced in the constraint. + function void check_member_handle(); + Payload r = new(); + int ok; + ok = r.randomize() with {addr == item.addr;}; + `checkd(ok, 1) + `checkh(r.addr, 32'h8000_0084) + endfunction + + // Same, but not a tautology even when misbound. Before the fix this became + // 'addr == addr + 1' and randomize() returned 0. + function void check_not_tautology(); + Payload r = new(); + int ok; + ok = r.randomize() with {addr == item.addr + 1;}; + `checkd(ok, 1) + `checkh(r.addr, 32'h8000_0085) + endfunction + + + // A local, rather than a member, also named 'item'. + function void check_local_handle(); + Payload r = new(); + Payload item = new(); + int ok; + item.addr = 32'hdead_beef; + ok = r.randomize() with {addr == item.addr;}; + `checkd(ok, 1) + `checkh(r.addr, 32'hdead_beef) + endfunction + + + // The array-method iterator must keep working, in a class that also has a + // variable named 'item'. This is what the name exists for. + function void check_array_method_iterator(); + int q[$] = '{1, 4, 2, 7}; + int found[$]; + found = q.find with (item > 3); + `checkd(found.size(), 2) + `checkd(found[0], 4) + `checkd(found[1], 7) + endfunction + + // A rand member of the randomized class named 'item', referenced undotted. + // The member wins over the caller's own 'item'. + function void check_target_member(); + Tagged t = new(); + int ok; + ok = t.randomize() with { + item == 32'd42; + other == item + 1; + }; + `checkd(ok, 1) + `checkh(t.item, 32'd42) + `checkh(t.other, 32'd43) + endfunction + + // An array-method 'with' nested inside a randomize() 'with'. The two now use + // different implicit names, so both must bind: the inner 'item' to the queue + // element, the constraint to the object being randomized. + function void check_nested_iterator(); + Summed t = new(); + int ok; + ok = t.randomize() with {other == q.sum() with (item);}; + `checkd(ok, 1) + `checkh(t.other, 32'd14) + endfunction +endclass + +module t ( /*AUTOARG*/); + initial begin + automatic Seq s = new(); + s.check_member_handle(); + s.check_not_tautology(); + s.check_local_handle(); + s.check_array_method_iterator(); + s.check_target_member(); + s.check_nested_iterator(); + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_randomize_with_item_name_types.py b/test_regress/t/t_randomize_with_item_name_types.py new file mode 100755 index 000000000..db1adb3f9 --- /dev/null +++ b/test_regress/t/t_randomize_with_item_name_types.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# 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-FileCopyrightText: 2026 Wilson Snyder +# 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_with_item_name_types.v b/test_regress/t/t_randomize_with_item_name_types.v new file mode 100644 index 000000000..cc3cf9380 --- /dev/null +++ b/test_regress/t/t_randomize_with_item_name_types.v @@ -0,0 +1,87 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Wilson Snyder +// SPDX-License-Identifier: CC0-1.0 + +// verilog_format: off +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0x exp=%0x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +// verilog_format: on + +// IEEE 1800-2023 7.12.1 gives array-method 'with' clauses a default iterator +// named 'item'. randomize() with (18.7) has no such iterator, so a user +// variable named 'item' must resolve normally inside the constraint. + +class Payload; + rand bit [31:0] addr; +endclass + +class Other; + bit [31:0] tag; +endclass + +class Seq; + Other item; // class member named 'item', of a type with no 'addr' + + function new(); + item = new(); + item.tag = 32'h5a5a_5a5a; + endfunction + + // Before the fix 'item' bound to the randomize target, so this failed + // elaboration with "Member 'tag' not found in class 'Payload'". + function void check_other_type(); + Payload r = new(); + int ok; + ok = r.randomize() with {addr == item.tag;}; + `checkd(ok, 1) + `checkh(r.addr, 32'h5a5a_5a5a) + endfunction + + // Undotted scalar named 'item'. Before the fix this produced C++ that did + // not compile: "'item' was not declared in this scope". + function void check_bare_scalar(); + Payload r = new(); + bit [31:0] item = 32'hcafe_f00d; + int ok; + ok = r.randomize() with {addr == item;}; + `checkd(ok, 1) + `checkh(r.addr, 32'hcafe_f00d) + endfunction + + // A queue member named 'item'. The randomize target has no such member, so + // this must resolve to the caller's queue and index it normally. + function void check_queue_element(); + Payload r = new(); + bit [31:0] item[$] = '{32'h1111_1111, 32'h2222_2222}; + int ok; + ok = r.randomize() with {addr == item[1];}; + `checkd(ok, 1) + `checkh(r.addr, 32'h2222_2222) + endfunction +endclass + +module t ( /*AUTOARG*/); + // std::randomize() with reaches the 'with' clause through a different call + // site than a class randomize(), and must not shadow 'item' either. + function automatic void check_std_randomize(); + bit [31:0] item = 32'h5eed_5eed; + bit [31:0] v; + int ok; + ok = std::randomize(v) with {v == item;}; + `checkd(ok, 1) + `checkh(v, 32'h5eed_5eed) + endfunction + + initial begin + automatic Seq s = new(); + s.check_other_type(); + s.check_bare_scalar(); + s.check_queue_element(); + check_std_randomize(); + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule