Support randomize() on class member selects (#6161)

This commit is contained in:
Igor Zaworski 2025-07-10 10:59:05 +02:00 committed by GitHub
parent 9ad0de1efd
commit 31c279a7b3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 576 additions and 19 deletions

View File

@ -2648,6 +2648,46 @@ class LinkDotResolveVisitor final : public VNVisitor {
m_ds.init(m_curSymp);
iterateNull(nodep);
}
static const AstNodeDType* getElemDTypep(const AstNodeDType* dtypep) {
dtypep = dtypep->skipRefp();
while (true) {
if (const AstBracketArrayDType* const adtypep = VN_CAST(dtypep, BracketArrayDType)) {
dtypep = adtypep->childDTypep()->skipRefp();
} else if (const AstDynArrayDType* const adtypep = VN_CAST(dtypep, DynArrayDType)) {
dtypep = adtypep->childDTypep()->skipRefp();
} else if (const AstQueueDType* const adtypep = VN_CAST(dtypep, QueueDType)) {
dtypep = adtypep->childDTypep()->skipRefp();
} else {
break;
}
}
return dtypep;
}
static const AstNodeDType* getExprDTypep(const AstNodeExpr* selp) {
while (const AstNodePreSel* const sp = VN_CAST(selp, NodePreSel)) selp = sp->fromp();
if (const AstMemberSel* const sp = VN_CAST(selp, MemberSel)) {
if (const AstNodeDType* dtypep = getExprDTypep(sp->fromp())) {
if (const AstClassRefDType* const classRefp = VN_CAST(dtypep, ClassRefDType)) {
const AstClass* const classp = classRefp->classp();
const bool found = classp->existsMember(
[&dtypep, name = selp->name()](const AstClass*, const AstVar* nodep) {
dtypep = nodep->childDTypep();
return nodep->name() == name;
});
if (found) return getElemDTypep(dtypep);
selp->v3error("Class " << classRefp->prettyNameQ()
<< " does not contain field " << selp->prettyNameQ());
} else {
selp->v3fatalSrc("Member selection on expression of type "
<< dtypep->prettyDTypeNameQ()
<< ", which is not a class type");
}
}
} else if (const AstNodeVarRef* const varRefp = VN_CAST(selp, NodeVarRef)) {
return getElemDTypep(varRefp->varp()->childDTypep());
}
return nullptr;
}
#define LINKDOT_VISIT_START() \
VL_RESTORER(m_indent); \
@ -3746,17 +3786,8 @@ class LinkDotResolveVisitor final : public VNVisitor {
if (!fromDtp) {
if (const AstNodeVarRef* const varRefp = VN_CAST(nodep->fromp(), NodeVarRef)) {
fromDtp = varRefp->varp()->subDTypep();
} else if (const AstNodeSel* const selp = VN_CAST(nodep->fromp(), NodeSel)) {
if (const AstNodeVarRef* const varRefp
= VN_CAST(selp->fromp(), NodeVarRef)) {
fromDtp = varRefp->varp()->dtypeSkipRefp()->subDTypep();
}
} else if (const AstNodePreSel* const selp
= VN_CAST(nodep->fromp(), NodePreSel)) {
if (const AstNodeVarRef* const varRefp
= VN_CAST(selp->fromp(), NodeVarRef)) {
fromDtp = varRefp->varp()->dtypeSkipRefp()->subDTypep();
}
} else {
fromDtp = getExprDTypep(nodep->fromp());
}
if (!fromDtp) {
if (VN_IS(nodep->pinsp(), With)) {

View File

@ -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()

View File

@ -0,0 +1,53 @@
// 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 SubClass;
rand bit [2:0] field;
function new ();
field = 0;
endfunction
endclass
class MyClass;
SubClass sc_inst2;
function new ();
sc_inst2 = new;
endfunction
endclass;
class Deep;
MyClass sc_inst1;
function new ();
sc_inst1 = new;
endfunction
endclass;
class WeNeedToGoDeeper;
Deep sc_inst;
function new ();
sc_inst = new;
endfunction
endclass;
module t;
initial begin
WeNeedToGoDeeper cl_inst = new;
MyClass cl_inst2 = new;
repeat(10) begin
if (cl_inst.sc_inst.sc_inst1.sc_inst2.randomize() with {field inside {1, 2, 3};} == 0) begin
$stop;
end
if (cl_inst.sc_inst.sc_inst1.sc_inst2.field < 1 || cl_inst.sc_inst.sc_inst1.sc_inst2.field > 3) begin
$stop;
end
if (cl_inst2.sc_inst2.randomize() with {field inside {1, 2, 3};} == 0) begin
$stop;
end
if (cl_inst2.sc_inst2.field < 1 || cl_inst2.sc_inst2.field > 3) begin
$stop;
end
end
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,21 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2024 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()

View File

@ -0,0 +1,55 @@
// 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 SubClass;
rand bit [2:0] field;
function new ();
field = 0;
endfunction
endclass
class MyClass;
SubClass sc_inst2[2];
function new ();
sc_inst2[1] = new;
endfunction
endclass;
class Deep;
MyClass sc_inst1;
function new ();
sc_inst1 = new;
endfunction
endclass;
class WeNeedToGoDeeper;
Deep sc_inst;
function new ();
sc_inst = new;
endfunction
endclass;
module t;
initial begin
WeNeedToGoDeeper cl_inst[100];
MyClass cl_inst2[2];
cl_inst[1] = new;
cl_inst2[0] = new;
repeat(10) begin
if (cl_inst[1].sc_inst.sc_inst1.sc_inst2[1].randomize() with {field inside {1, 2, 3};} == 0) begin
$stop;
end
if (cl_inst[1].sc_inst.sc_inst1.sc_inst2[1].field < 1 || cl_inst[1].sc_inst.sc_inst1.sc_inst2[1].field > 3) begin
$stop;
end
if (cl_inst2[0].sc_inst2[1].randomize() with {field inside {1, 2, 3};} == 0) begin
$stop;
end
if (cl_inst2[0].sc_inst2[1].field < 1 || cl_inst2[0].sc_inst2[1].field > 3) begin
$stop;
end
end
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,21 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2024 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()

View File

@ -0,0 +1,55 @@
// 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 SubClass;
rand bit [2:0] field;
function new ();
field = 0;
endfunction
endclass
class MyClass;
SubClass sc_inst2[int];
function new ();
sc_inst2[1] = new;
endfunction
endclass;
class Deep;
MyClass sc_inst1;
function new ();
sc_inst1 = new;
endfunction
endclass;
class WeNeedToGoDeeper;
Deep sc_inst;
function new ();
sc_inst = new;
endfunction
endclass;
module t;
initial begin
WeNeedToGoDeeper cl_inst[string];
MyClass cl_inst2[int];
cl_inst["val1"] = new;
cl_inst2[0] = new;
repeat(10) begin
if (cl_inst["val1"].sc_inst.sc_inst1.sc_inst2[1].randomize() with {field inside {1, 2, 3};} == 0) begin
$stop;
end
if (cl_inst["val1"].sc_inst.sc_inst1.sc_inst2[1].field < 1 || cl_inst["val1"].sc_inst.sc_inst1.sc_inst2[1].field > 3) begin
$stop;
end
if (cl_inst2[0].sc_inst2[1].randomize() with {field inside {1, 2, 3};} == 0) begin
$stop;
end
if (cl_inst2[0].sc_inst2[1].field < 1 || cl_inst2[0].sc_inst2[1].field > 3) begin
$stop;
end
end
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,21 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2024 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()

View File

@ -0,0 +1,56 @@
// 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 SubClass;
rand bit [2:0] field;
function new ();
field = 0;
endfunction
endclass
class MyClass;
SubClass sc_inst2[];
function new ();
sc_inst2 = new [7];
sc_inst2[1] = new;
endfunction
endclass;
class Deep;
MyClass sc_inst1;
function new ();
sc_inst1 = new;
endfunction
endclass;
class WeNeedToGoDeeper;
Deep sc_inst;
function new ();
sc_inst = new;
endfunction
endclass;
module t;
initial begin
WeNeedToGoDeeper cl_inst[];
MyClass cl_inst2[];
cl_inst = new [3];
cl_inst2 = new [5];
cl_inst[1] = new;
cl_inst2[0] = new;
if (cl_inst[1].sc_inst.sc_inst1.sc_inst2[1].randomize() with {field inside {1, 2, 3};} == 0) begin
$stop;
end
if (cl_inst[1].sc_inst.sc_inst1.sc_inst2[1].field < 1 || cl_inst[1].sc_inst.sc_inst1.sc_inst2[1].field > 3) begin
$stop;
end
if (cl_inst2[0].sc_inst2[1].randomize() with {field inside {1, 2, 3};} == 0) begin
$stop;
end
if (cl_inst2[0].sc_inst2[1].field < 1 || cl_inst2[0].sc_inst2[1].field > 3) begin
$stop;
end
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,12 @@
%Error: t/t_randomize_complex_member_bad.v:36:28: Class 'Deep' does not contain field 'sc_inst2'
36 | if (cl_inst[1].sc_inst.sc_inst2.sc_inst2[1].randomize() with {field inside {1, 2, 3};} == 0) begin
| ^~~~~~~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error-UNSUPPORTED: t/t_randomize_complex_member_bad.v:36:49: Unsupported: 'randomize() with' on complex expressions
36 | if (cl_inst[1].sc_inst.sc_inst2.sc_inst2[1].randomize() with {field inside {1, 2, 3};} == 0) begin
| ^~~~~~~~~
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error: t/t_randomize_complex_member_bad.v:36:67: Can't find definition of variable: 'field'
36 | if (cl_inst[1].sc_inst.sc_inst2.sc_inst2[1].randomize() with {field inside {1, 2, 3};} == 0) begin
| ^~~~~
%Error: Exiting due to

View File

@ -0,0 +1,19 @@
#!/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('linter')
if not test.have_solver:
test.skip("No constraint solver installed")
test.lint(verilator_flags2=["--lint-only"], fails=True, expect_filename=test.golden_filename)
test.passes()

View File

@ -0,0 +1,40 @@
// 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 SubClass;
rand bit [2:0] field;
function new ();
field = 0;
endfunction
endclass
class MyClass;
SubClass sc_inst2[2];
function new ();
sc_inst2[1] = new;
endfunction
endclass;
class Deep;
MyClass sc_inst1;
function new ();
sc_inst1 = new;
endfunction
endclass;
class WeNeedToGoDeeper;
Deep sc_inst;
function new ();
sc_inst = new;
endfunction
endclass;
module t;
initial begin
WeNeedToGoDeeper cl_inst[100];
cl_inst[1] = new;
if (cl_inst[1].sc_inst.sc_inst2.sc_inst2[1].randomize() with {field inside {1, 2, 3};} == 0) begin
$stop;
end
end
endmodule

View File

@ -0,0 +1,21 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2024 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()

View File

@ -0,0 +1,56 @@
// 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 SubClass;
rand bit [2:0] field;
function new ();
field = 0;
endfunction
endclass
class MyClass;
SubClass sc_inst2[$];
function new ();
SubClass inst = new;
sc_inst2 = { inst };
endfunction
endclass;
class Deep;
MyClass sc_inst1;
function new ();
sc_inst1 = new;
endfunction
endclass;
class WeNeedToGoDeeper;
Deep sc_inst;
function new ();
sc_inst = new;
endfunction
endclass;
module t;
initial begin
WeNeedToGoDeeper inst = new;
MyClass inst2 = new;
WeNeedToGoDeeper cl_inst[$] = { inst };
MyClass cl_inst2[$] = { inst2 };
repeat(10) begin
if (cl_inst[0].sc_inst.sc_inst1.sc_inst2[0].randomize() with {field inside {1, 2, 3};} == 0) begin
$stop;
end
if (cl_inst[0].sc_inst.sc_inst1.sc_inst2[0].field < 1 || cl_inst[0].sc_inst.sc_inst1.sc_inst2[0].field > 3) begin
$stop;
end
if (cl_inst2[0].sc_inst2[0].randomize() with {field inside {1, 2, 3};} == 0) begin
$stop;
end
if (cl_inst2[0].sc_inst2[0].field < 1 || cl_inst2[0].sc_inst2[0].field > 3) begin
$stop;
end
end
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -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()

View File

@ -0,0 +1,61 @@
// 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 SubClass;
rand bit [2:0] field;
function new ();
field = 0;
endfunction
endclass
typedef SubClass Sc_t;
class MyClass;
Sc_t sc_inst2[2];
function new ();
sc_inst2[1] = new;
endfunction
endclass;
typedef MyClass Mc_t;
class Deep;
Mc_t sc_inst1;
function new ();
sc_inst1 = new;
endfunction
endclass;
typedef Deep D_t;
class WeNeedToGoDeeper;
D_t sc_inst;
function new ();
sc_inst = new;
endfunction
endclass;
typedef WeNeedToGoDeeper WNTGDA_t[100];
typedef MyClass MCA_t[2];
module t;
initial begin
WNTGDA_t cl_inst;
MCA_t cl_inst2;
cl_inst[1] = new;
cl_inst2[0] = new;
repeat(10) begin
if (cl_inst[1].sc_inst.sc_inst1.sc_inst2[1].randomize() with {field inside {1, 2, 3};} == 0) begin
$stop;
end
if (cl_inst[1].sc_inst.sc_inst1.sc_inst2[1].field < 1 || cl_inst[1].sc_inst.sc_inst1.sc_inst2[1].field > 3) begin
$stop;
end
if (cl_inst2[0].sc_inst2[1].randomize() with {field inside {1, 2, 3};} == 0) begin
$stop;
end
if (cl_inst2[0].sc_inst2[1].field < 1 || cl_inst2[0].sc_inst2[1].field > 3) begin
$stop;
end
end
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -1,14 +1,7 @@
%Error-UNSUPPORTED: t/t_randomize_method_complex_bad.v:16:11: Unsupported: 'randomize() with' on complex expressions
16 | x.f.randomize() with { r < 5; },
| ^~~~~~~~~
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error: t/t_randomize_method_complex_bad.v:16:30: Can't find definition of variable: 'r'
16 | x.f.randomize() with { r < 5; },
| ^
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: t/t_randomize_method_complex_bad.v:17:9: 'randomize() with' on a non-class-instance 'int'
17 | i.randomize() with { v < 5; });
| ^~~~~~~~~
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
%Error: t/t_randomize_method_complex_bad.v:17:28: Can't find definition of variable: 'v'
17 | i.randomize() with { v < 5; });
| ^