Fixes #7993.
This commit is contained in:
parent
a6f4dd031f
commit
5fd1c93d43
|
|
@ -39,6 +39,7 @@ Aylon Chaim Porat
|
||||||
Bartłomiej Chmiel
|
Bartłomiej Chmiel
|
||||||
Bartosz Skorowski
|
Bartosz Skorowski
|
||||||
Benjamin Collier
|
Benjamin Collier
|
||||||
|
BRDR LIFE
|
||||||
Brian Li
|
Brian Li
|
||||||
Cameron Kirk
|
Cameron Kirk
|
||||||
Cameron Waite
|
Cameron Waite
|
||||||
|
|
|
||||||
|
|
@ -2195,7 +2195,7 @@ class LinkDotFindVisitor final : public VNVisitor {
|
||||||
if (const AstDot* const dotp = VN_CAST(nodep->funcrefp(), Dot))
|
if (const AstDot* const dotp = VN_CAST(nodep->funcrefp(), Dot))
|
||||||
funcrefp = VN_CAST(dotp->rhsp(), NodeFTaskRef);
|
funcrefp = VN_CAST(dotp->rhsp(), NodeFTaskRef);
|
||||||
UASSERT_OBJ(funcrefp, nodep, "'with' only can operate on a function/task");
|
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();
|
FileLine* argFl = nodep->fileline();
|
||||||
AstArg* const argsp = funcrefp->argsp();
|
AstArg* const argsp = funcrefp->argsp();
|
||||||
if (argsp) {
|
if (argsp) {
|
||||||
|
|
@ -4298,7 +4298,7 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||||
}
|
}
|
||||||
UINFO(9, indent() << "randomize-with fromSym " << foundp->nodep());
|
UINFO(9, indent() << "randomize-with fromSym " << foundp->nodep());
|
||||||
AstLambdaArgRef* const lambdaRefp
|
AstLambdaArgRef* const lambdaRefp
|
||||||
= new AstLambdaArgRef{nodep->fileline(), "item", false};
|
= new AstLambdaArgRef{nodep->fileline(), "__Vrandwith_obj", false};
|
||||||
AstMemberSel* newp = new AstMemberSel{nodep->fileline(), lambdaRefp,
|
AstMemberSel* newp = new AstMemberSel{nodep->fileline(), lambdaRefp,
|
||||||
VFlagChildDType{}, nodep->name()};
|
VFlagChildDType{}, nodep->name()};
|
||||||
nodep->replaceWith(newp);
|
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;
|
if (m_ds.m_dotPos != DP_NONE) m_ds.m_dotPos = DP_MEMBER;
|
||||||
AstNode* const newp = new AstMethodCall{
|
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};
|
VFlagChildDType{}, nodep->name(), argsp};
|
||||||
nodep->replaceWith(newp);
|
nodep->replaceWith(newp);
|
||||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
|
|
|
||||||
|
|
@ -1287,7 +1287,7 @@ package Vt_debug_emitv___024unit;
|
||||||
begin : label8
|
begin : label8
|
||||||
rand_restricted = randomize() with (
|
rand_restricted = randomize() with (
|
||||||
???? // CONSTRAINTEXPR
|
???? // CONSTRAINTEXPR
|
||||||
(item.rmember1 < member)) ;
|
(__Vrandwith_obj.rmember1 < member)) ;
|
||||||
disable label8;
|
disable label8;
|
||||||
end
|
end
|
||||||
endfunction
|
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