Support soft foreach in constraint (#8174)

This commit is contained in:
Kamil Danecki
2026-08-26 11:05:12 -04:00
committed by GitHub
parent 7f9333723f
commit f055eeabe0
8 changed files with 172 additions and 2 deletions
+8 -2
View File
@@ -1675,10 +1675,16 @@ public:
// === AstNodeForeach ===
class AstConstraintForeach final : public AstNodeForeach {
// Constraint foreach statement
bool m_soft; // is soft foreach, non-standard extension
public:
AstConstraintForeach(FileLine* fl, AstForeachHeader* headerp, AstNode* bodyp)
: ASTGEN_SUPER_ConstraintForeach(fl, headerp, bodyp) {}
AstConstraintForeach(FileLine* fl, AstForeachHeader* headerp, AstNode* bodyp,
bool soft = false)
: ASTGEN_SUPER_ConstraintForeach(fl, headerp, bodyp)
, m_soft{soft} {}
ASTGEN_MEMBERS_AstConstraintForeach;
bool isSoft() const { return m_soft; }
void dump(std::ostream& str) const override;
void dumpJson(std::ostream& str) const override;
};
class AstForeach final : public AstNodeForeach {
public:
+8
View File
@@ -2307,6 +2307,14 @@ void AstCover::dumpJson(std::ostream& str) const {
dumpJsonBoolFuncIf(str, isSeqEvent);
this->AstNodeCoverOrAssert::dumpJson(str);
}
void AstConstraintForeach::dump(std::ostream& str) const {
this->AstNodeForeach::dump(str);
if (isSoft()) str << "[SOFT]";
}
void AstConstraintForeach::dumpJson(std::ostream& str) const {
dumpJsonBoolFuncIf(str, isSoft);
dumpJsonGen(str);
}
void AstClocking::dump(std::ostream& str) const {
this->AstNode::dump(str);
if (isDefault()) str << " [DEFAULT]";
+6
View File
@@ -298,6 +298,12 @@ class LinkParseVisitor final : public VNVisitor {
v3Global.useRandomizeMethods(true);
iterateChildren(nodep);
}
void visit(AstConstraintForeach* nodep) override {
if (nodep->isSoft()) {
nodep->v3warn(NONSTD, "Non-standard soft foreach");
nodep->foreach([](AstConstraintExpr* exprp) { exprp->isSoft(true); });
}
}
void visit(AstEnumDType* nodep) override {
if (nodep->name() == "") {
nodep->name(nameFromTypedef(nodep)); // Might still remain ""
+3
View File
@@ -8166,6 +8166,9 @@ constraint_expression<nodep>: // ==IEEE: constraint_expression
// // IEEE says array_identifier here, but dotted accepted in VMM + 1800-2009
| yFOREACH '(' idClassSelForeach ')' constraint_set
{ $$ = new AstConstraintForeach{$1, $3, $5}; }
// // Non-IEEE extension, soft foreach
| ySOFT yFOREACH '(' idClassSelForeach ')' constraint_set
{ $$ = new AstConstraintForeach{$2, $4, $6, true}; }
// // soft is 1800-2012
| yDISABLE ySOFT constraint_primary ';'
{ AstConstraintExpr* const newp = new AstConstraintExpr{$1, $3};
+21
View File
@@ -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(verilator_flags2=["--Wno-NONSTD"])
test.execute()
test.passes()
+94
View File
@@ -0,0 +1,94 @@
// 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);
// verilog_format: on
class Cls1;
rand int arr[10];
constraint c_cls {
soft foreach(arr[i]) arr[i] == i;
}
endclass
class Cls2;
rand int arr[10];
constraint c_cls {
soft foreach(arr[i]) arr[i] == i;
arr[1] == 10;
}
endclass
class Cls3;
rand int arr[10];
constraint c_cls {
soft foreach(arr[i]) arr[i] < i;
arr[5] == 3;
}
endclass
class Cls4;
rand int arr[10][20];
rand bit a;
constraint c_cls {
soft foreach(arr[i])
foreach (arr[i][j])
soft arr[i][j] == i + j;
arr[5][10] == 2;
}
endclass
module t;
Cls1 cls1;
Cls2 cls2;
Cls3 cls3;
Cls4 cls4;
int ok;
initial begin
cls1 = new;
cls2 = new;
cls3 = new;
cls4 = new;
ok = cls1.randomize();
`checkd(ok, 1);
foreach(cls1.arr[i]) begin
`checkd(cls1.arr[i], i);
end
ok = cls2.randomize();
`checkd(ok, 1);
foreach(cls2.arr[i]) begin
if (i != 1)
`checkd(cls2.arr[i], i);
end
`checkd(cls2.arr[1], 10);
repeat (10) begin
ok = cls3.randomize();
`checkd(ok, 1);
foreach(cls3.arr[i]) begin
if (cls3.arr[i] >= i) $stop;
end
`checkd(cls3.arr[5], 3);
end
ok = cls4.randomize();
`checkd(ok, 1);
foreach(cls4.arr[i, j]) begin
if (i != 5 || j != 10) begin
`checkd(cls4.arr[i][j], i+j);
end
end
`checkd(cls4.arr[5][10], 2);
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
@@ -0,0 +1,15 @@
%Warning-NONSTD: t/t_randomize_soft_foreach.v:16:10: Non-standard soft foreach
16 | soft foreach(arr[i]) arr[i] == i;
| ^~~~~~~
... For warning description see https://verilator.org/warn/NONSTD?v=latest
... Use "/* verilator lint_off NONSTD */" and lint_on around source to disable this message.
%Warning-NONSTD: t/t_randomize_soft_foreach.v:23:10: Non-standard soft foreach
23 | soft foreach(arr[i]) arr[i] == i;
| ^~~~~~~
%Warning-NONSTD: t/t_randomize_soft_foreach.v:31:10: Non-standard soft foreach
31 | soft foreach(arr[i]) arr[i] < i;
| ^~~~~~~
%Warning-NONSTD: t/t_randomize_soft_foreach.v:40:10: Non-standard soft foreach
40 | soft foreach(arr[i])
| ^~~~~~~
%Error: Exiting due to
+17
View File
@@ -0,0 +1,17 @@
#!/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.top_filename = 't/t_randomize_soft_foreach.v'
test.lint(fails=True, expect_filename=test.golden_filename)
test.passes()