mirror of
https://github.com/verilator/verilator.git
synced 2026-10-06 01:54:01 +02:00
Support rand dynamic arrays used inside with clause of randomize (#8246)
Signed-off-by: Kamil Danecki <[email protected]> Signed-off-by: Igor Zaworski <[email protected]>
This commit is contained in:
+59
-40
@@ -1465,7 +1465,7 @@ class ConstraintExprVisitor final : public VNVisitor {
|
||||
AstMemberSel* const memberselp, const std::string& smtName,
|
||||
AstNodeModule* const classOrPackagep) const {
|
||||
uint32_t unpackedDims = 0;
|
||||
if (varp->dtypep()->isNonPackedArray()) {
|
||||
if (varp->dtypeSkipRefp()->isNonPackedArray()) {
|
||||
unpackedDims = varp->dtypep()->dimensions(false).second;
|
||||
}
|
||||
if (VN_IS(varp->dtypeSkipRefp(), StructDType)
|
||||
@@ -2688,47 +2688,66 @@ class ConstraintExprVisitor final : public VNVisitor {
|
||||
if (editFormat(nodep)) return;
|
||||
FileLine* const fl = nodep->fileline();
|
||||
|
||||
if (nodep->method() == VCMethod::ARRAY_AT && nodep->fromp()->user1()) {
|
||||
// Queue/dynamic element: pre-edit clone for the rand_mode hoist, non-rand index only.
|
||||
// A std::randomize() with-clause argument carries no rand qualifier
|
||||
// of its own but is still part of the solve.
|
||||
bool indexIsRand = false;
|
||||
if (nodep->pinsp()) {
|
||||
nodep->pinsp()->foreach([&](const AstNodeVarRef* vrefp) {
|
||||
if (vrefp->varp()->rand().isRandomizable()
|
||||
|| vrefp->varp()->isStdRandomizeArg()) {
|
||||
indexIsRand = true;
|
||||
if (nodep->method() == VCMethod::ARRAY_AT) {
|
||||
const bool indexIsRand = nodep->pinsp()->exists([](const AstNodeVarRef* const vrefp) {
|
||||
return vrefp->varp()->rand().isRandomizable();
|
||||
});
|
||||
if (nodep->fromp()->user1()) {
|
||||
// Queue/dynamic element: pre-edit clone for the rand_mode hoist, non-rand index
|
||||
// only. A std::randomize() with-clause argument carries no rand qualifier of its
|
||||
// own but is still part of the solve.
|
||||
{
|
||||
const AstNode* const basep = nodep->baseFromp(true);
|
||||
if (basep->name() == "__Vthis"
|
||||
&& VN_AS(basep->backp(), MemberSel)->varp()->isRand()) {
|
||||
nodep->fromp()->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: Complex expression captured from "
|
||||
"current scope with randomized variable");
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
AstNodeExpr* const origp = indexIsRand ? nullptr : nodep->cloneTree(false);
|
||||
AstCMethodHard* const sizep
|
||||
= m_structSel ? new AstCMethodHard{fl, nodep->fromp()->cloneTreePure(false),
|
||||
VCMethod::DYN_SIZE}
|
||||
: nullptr;
|
||||
AstNodeExpr* const originalPinp = nodep->pinsp();
|
||||
iterateChildren(nodep);
|
||||
AstNodeExpr* const pinp = nodep->pinsp()->unlinkFrBack();
|
||||
if (VN_IS(pinp, SFormatF) && m_structSel) VN_AS(pinp, SFormatF)->name("%x");
|
||||
AstSFormatF* newp;
|
||||
if (m_structSel) {
|
||||
AstNodeExpr* const argsp = AstNode::addNext(nodep->fromp()->unlinkFrBack(), pinp);
|
||||
sizep->dtypeSetInt();
|
||||
AstLogAnd* const condp = new AstLogAnd{
|
||||
fl,
|
||||
new AstLteS{
|
||||
fl, new AstConst{fl, AstConst::WidthedValue{}, originalPinp->width(), 0},
|
||||
originalPinp->cloneTreePure(false)},
|
||||
new AstLtS{fl, originalPinp->cloneTreePure(false), sizep}};
|
||||
m_conditionp = m_conditionp ? new AstLogAnd{fl, m_conditionp, condp} : condp;
|
||||
newp = new AstSFormatF{fl, "%s.%s", false, argsp};
|
||||
}
|
||||
AstNodeExpr* const origp = indexIsRand ? nullptr : nodep->cloneTree(false);
|
||||
AstCMethodHard* const sizep
|
||||
= m_structSel ? new AstCMethodHard{fl, nodep->fromp()->cloneTreePure(false),
|
||||
VCMethod::DYN_SIZE}
|
||||
: nullptr;
|
||||
AstNodeExpr* const originalPinp = nodep->pinsp();
|
||||
iterateChildren(nodep);
|
||||
AstNodeExpr* const pinp = nodep->pinsp()->unlinkFrBack();
|
||||
AstSFormatF* newp;
|
||||
if (m_structSel) {
|
||||
if (AstSFormatF* const sformatfp = VN_CAST(pinp, SFormatF)) {
|
||||
sformatfp->name("%x");
|
||||
}
|
||||
AstNodeExpr* const argsp
|
||||
= AstNode::addNext(nodep->fromp()->unlinkFrBack(), pinp);
|
||||
sizep->dtypeSetInt();
|
||||
AstLogAnd* const condp
|
||||
= new AstLogAnd{fl,
|
||||
new AstLteS{fl,
|
||||
new AstConst{fl, AstConst::WidthedValue{},
|
||||
originalPinp->width(), 0},
|
||||
originalPinp->cloneTreePure(false)},
|
||||
new AstLtS{fl, originalPinp->cloneTreePure(false), sizep}};
|
||||
m_conditionp = m_conditionp ? new AstLogAnd{fl, m_conditionp, condp} : condp;
|
||||
newp = new AstSFormatF{fl, "%s.%s", false, argsp};
|
||||
} else {
|
||||
newp = createSolverArrDerefp(fl, nodep->fromp()->unlinkFrBack(), pinp);
|
||||
}
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
if (origp && !hoistRandModeOverSelect(newp, origp)) {
|
||||
VL_DO_DANGLING(origp->deleteTree(), origp);
|
||||
}
|
||||
|
||||
} else if (indexIsRand) {
|
||||
nodep->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: Randomization of an index to a non-random variable");
|
||||
|
||||
} else {
|
||||
newp = createSolverArrDerefp(fl, nodep->fromp()->unlinkFrBack(), pinp);
|
||||
}
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
if (origp && !hoistRandModeOverSelect(newp, origp)) {
|
||||
VL_DO_DANGLING(origp->deleteTree(), origp);
|
||||
nodep->user1(false);
|
||||
UASSERT_OBJ(editFormat(nodep), nodep,
|
||||
"editFormat should return true when user1 is false");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Executable
+21
@@ -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
|
||||
|
||||
if not test.have_solver:
|
||||
test.skip("No constraint solver installed")
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile()
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
@@ -0,0 +1,112 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain
|
||||
// SPDX-FileCopyrightText: 2026 Antmicro
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`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);
|
||||
`define check_range(gotv,minv,maxv) do if ((gotv) < (minv) || (gotv) > (maxv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d-%0d\n", `__FILE__,`__LINE__, (gotv), (minv), (maxv)); `stop; end while(0);
|
||||
`define checkd_ne(gotv,expv) do if ((gotv) === (expv)) begin $write("%%Error: %s:%0d: got=%0d expected any other value\n", `__FILE__,`__LINE__, (gotv)); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
typedef int int_arr_t[];
|
||||
|
||||
class A;
|
||||
rand int x;
|
||||
endclass
|
||||
|
||||
class Cls;
|
||||
rand int_arr_t arr;
|
||||
function int foo();
|
||||
return arr[0];
|
||||
endfunction
|
||||
task body();
|
||||
int ok;
|
||||
A a;
|
||||
int prev = -1;
|
||||
a = new;
|
||||
arr = new[2];
|
||||
arr[0] = 111112300;
|
||||
arr[1] = 123000000;
|
||||
repeat (40) begin
|
||||
ok = a.randomize() with {x >= 0; x <= arr[1];};
|
||||
`checkd(ok, 1);
|
||||
`check_range(a.x, 0, 123000000);
|
||||
`checkd_ne(a.x, prev);
|
||||
prev = a.x;
|
||||
end
|
||||
prev = -1;
|
||||
repeat (40) begin
|
||||
ok = a.randomize() with {x >= 0; x <= foo();};
|
||||
`checkd(ok, 1);
|
||||
`check_range(a.x, 0, 111112300);
|
||||
`checkd_ne(a.x, prev);
|
||||
prev = a.x;
|
||||
end
|
||||
endtask
|
||||
endclass
|
||||
|
||||
class B;
|
||||
rand int x;
|
||||
rand int_arr_t arr;
|
||||
endclass
|
||||
|
||||
class Cls2;
|
||||
task body();
|
||||
int ok;
|
||||
B b;
|
||||
int prev = -1;
|
||||
b = new;
|
||||
b.arr = new[2];
|
||||
b.x = 1;
|
||||
b.arr[1] = 200000;
|
||||
repeat (40) begin
|
||||
ok = b.randomize() with {x == arr[1];};
|
||||
`checkd(ok, 1);
|
||||
`checkd(b.x, b.arr[1]);
|
||||
`checkd_ne(b.x, prev);
|
||||
prev = b.x;
|
||||
end
|
||||
endtask
|
||||
endclass
|
||||
|
||||
class Cls3;
|
||||
rand int_arr_t arr;
|
||||
task body();
|
||||
int ok;
|
||||
B b;
|
||||
int prev = -1;
|
||||
b = new;
|
||||
b.arr = new[2];
|
||||
b.x = 1;
|
||||
b.arr[1] = 30000000;
|
||||
arr = new[2];
|
||||
arr[1] = 3;
|
||||
repeat (40) begin
|
||||
ok = b.randomize() with {x == arr[1];};
|
||||
`checkd(ok, 1);
|
||||
`checkd(arr[1], 3);
|
||||
`checkd(b.x, b.arr[1]);
|
||||
`checkd_ne(b.x, prev);
|
||||
prev = b.x;
|
||||
end
|
||||
endtask
|
||||
endclass
|
||||
|
||||
module t;
|
||||
Cls c;
|
||||
Cls2 c2;
|
||||
Cls3 c3;
|
||||
initial begin
|
||||
c = new;
|
||||
c2 = new;
|
||||
c3 = new;
|
||||
c.body();
|
||||
c2.body();
|
||||
c3.body();
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
+21
@@ -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
|
||||
|
||||
if not test.have_solver:
|
||||
test.skip("No constraint solver installed")
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile()
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
@@ -0,0 +1,92 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain
|
||||
// SPDX-FileCopyrightText: 2026 Antmicro
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`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
|
||||
|
||||
typedef int int_arr_t[];
|
||||
|
||||
class A;
|
||||
rand int x;
|
||||
endclass
|
||||
|
||||
class Cls;
|
||||
int_arr_t arr[];
|
||||
task body();
|
||||
int ok;
|
||||
A a;
|
||||
a = new;
|
||||
arr = new[2];
|
||||
arr[1] = new[2];
|
||||
arr[1][1] = 123;
|
||||
repeat (40) begin
|
||||
ok = a.randomize() with {x == arr[1][1];};
|
||||
`checkd(ok, 1);
|
||||
`checkd(a.x, arr[1][1]);
|
||||
end
|
||||
endtask
|
||||
endclass
|
||||
|
||||
class B;
|
||||
rand int x;
|
||||
rand int arr[][];
|
||||
endclass
|
||||
|
||||
class Cls2;
|
||||
task body();
|
||||
int ok;
|
||||
B b;
|
||||
b = new;
|
||||
b.arr = new[2];
|
||||
b.arr[1] = new[2];
|
||||
b.x = 1;
|
||||
b.arr[1][1] = 2;
|
||||
repeat (40) begin
|
||||
ok = b.randomize() with {x == arr[1][1];};
|
||||
`checkd(ok, 1);
|
||||
`checkd(b.x, b.arr[1][1]);
|
||||
end
|
||||
endtask
|
||||
endclass
|
||||
|
||||
class Cls3;
|
||||
rand int_arr_t arr;
|
||||
task body();
|
||||
int ok;
|
||||
B b;
|
||||
b = new;
|
||||
b.arr = new[2];
|
||||
b.arr[1] = new[2];
|
||||
b.x = 1;
|
||||
b.arr[1][1] = 2;
|
||||
arr = new[2];
|
||||
arr[1] = 3;
|
||||
repeat (40) begin
|
||||
ok = b.randomize() with {x == arr[1][1];};
|
||||
`checkd(ok, 1);
|
||||
`checkd(b.x, b.arr[1][1]);
|
||||
`checkd(arr[1], 3);
|
||||
end
|
||||
endtask
|
||||
endclass
|
||||
|
||||
module t;
|
||||
Cls c;
|
||||
Cls2 c2;
|
||||
Cls3 c3;
|
||||
initial begin
|
||||
c = new;
|
||||
c2 = new;
|
||||
c3 = new;
|
||||
c.body();
|
||||
c2.body();
|
||||
c3.body();
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -0,0 +1,5 @@
|
||||
%Error-UNSUPPORTED: t/t_randomize_with_dyn_arr_multi_dyn_unsup.v:28:40: Unsupported: Complex expression captured from current scope with randomized variable
|
||||
28 | ok = a.randomize() with {x == arr[1][1];};
|
||||
| ^
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error: Exiting due to
|
||||
@@ -0,0 +1,16 @@
|
||||
#!/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('linter')
|
||||
|
||||
test.lint(fails=True, expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
@@ -0,0 +1,43 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain
|
||||
// SPDX-FileCopyrightText: 2026 Antmicro
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`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
|
||||
|
||||
typedef int int_arr_t[];
|
||||
|
||||
class A;
|
||||
rand int x;
|
||||
endclass
|
||||
|
||||
class Cls;
|
||||
rand int_arr_t arr[];
|
||||
task body();
|
||||
int ok;
|
||||
A a;
|
||||
a = new;
|
||||
arr = new[2];
|
||||
arr[1] = new[2];
|
||||
arr[1][1] = 123;
|
||||
repeat (40) begin
|
||||
ok = a.randomize() with {x == arr[1][1];};
|
||||
`checkd(ok, 1);
|
||||
`checkd(a.x, arr[1][1]);
|
||||
end
|
||||
endtask
|
||||
endclass
|
||||
|
||||
module t;
|
||||
Cls c;
|
||||
initial begin
|
||||
c = new;
|
||||
c.body();
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -0,0 +1,5 @@
|
||||
%Error-UNSUPPORTED: t/t_randomize_with_dyn_arr_unsup.v:28:59: Unsupported: Randomization of an index to a non-random variable
|
||||
28 | if (c.randomize() with {solve foo before x; x == arr[bit'(foo)]; foo <= 1;} != 1) $stop;
|
||||
| ^
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error: Exiting due to
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
#!/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('linter')
|
||||
|
||||
test.lint(fails=True, expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
@@ -0,0 +1,42 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain
|
||||
// SPDX-FileCopyrightText: 2026 Antmicro
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`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
|
||||
|
||||
typedef int int_arr_t[];
|
||||
|
||||
class C;
|
||||
rand int x;
|
||||
rand bit [1:0] foo;
|
||||
endclass
|
||||
|
||||
class Cls4;
|
||||
int_arr_t arr;
|
||||
task body();
|
||||
C c;
|
||||
c = new;
|
||||
arr = new[2];
|
||||
arr[0] = 123;
|
||||
arr[1] = 124;
|
||||
repeat (40) begin
|
||||
if (c.randomize() with {solve foo before x; x == arr[bit'(foo)]; foo <= 1;} != 1) $stop;
|
||||
`checkd(c.x, arr[bit'(c.foo)]);
|
||||
end
|
||||
endtask
|
||||
endclass
|
||||
|
||||
module t;
|
||||
Cls4 c4;
|
||||
initial begin
|
||||
c4 = new;
|
||||
c4.body();
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
Reference in New Issue
Block a user