Fixes #7993.
This commit is contained in:
parent
a6f4dd031f
commit
5fd1c93d43
|
|
@ -39,6 +39,7 @@ Aylon Chaim Porat
|
|||
Bartłomiej Chmiel
|
||||
Bartosz Skorowski
|
||||
Benjamin Collier
|
||||
BRDR LIFE
|
||||
Brian Li
|
||||
Cameron Kirk
|
||||
Cameron Waite
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
|
|
@ -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
|
||||
Loading…
Reference in New Issue