Support constant expressions in bins (#8309)

Signed-off-by: Bartosz Skorowski <[email protected]>
This commit is contained in:
Bartosz Skorowski
2026-09-15 21:15:25 -04:00
committed by GitHub
parent e0e0011b36
commit 3e30f4476a
7 changed files with 237 additions and 68 deletions
+21 -13
View File
@@ -375,6 +375,7 @@ class FunctionalCoverageVisitor final : public VNVisitor {
// auto-bins are per-value only for small domains, so a partial set is harmless here.
constexpr size_t maxEnumerate = 1ULL << 16;
for (AstNode* np = nodep; np; np = np->nextp()) {
np = V3Const::constifyEdit(np);
if (AstConst* constp = VN_CAST(np, Const)) {
if (constp->num().isFourState())
continue; // wildcard patterns can't be enumerated
@@ -388,7 +389,7 @@ class FunctionalCoverageVisitor final : public VNVisitor {
AstConst* const hiConstp = VN_CAST(rhsp, Const);
if ((!loConstp && !loUnbounded) || (!hiConstp && !hiUnbounded)) {
rangep->v3error("Non-constant expression in bin range; "
"range bounds must be constants");
"range bounds must be constants (IEEE 1800-2023 19.5)");
continue;
}
if ((loConstp && loConstp->num().isFourState())
@@ -401,7 +402,8 @@ class FunctionalCoverageVisitor final : public VNVisitor {
values.insert(v);
}
} else {
np->v3error("Non-constant expression in bin value list; values must be constants");
np->v3error("Non-constant expression in bin value list; values must be constants "
"(IEEE 1800-2023 19.5)");
}
}
}
@@ -905,16 +907,17 @@ class FunctionalCoverageVisitor final : public VNVisitor {
const uint64_t maxVal = (width >= 64) ? UINT64_MAX : ((1ULL << width) - 1);
std::vector<AstNodeExpr*> values;
for (AstNode* rangep = arrayBinp->rangesp(); rangep; rangep = rangep->nextp()) {
rangep = V3Const::constifyEdit(rangep);
if (AstInsideRange* const irp = VN_CAST(rangep, InsideRange)) {
AstNodeExpr* const lhsp = V3Const::constifyEdit(irp->lhsp());
AstNodeExpr* const rhsp = V3Const::constifyEdit(irp->rhsp());
AstNodeExpr* const lhsp = irp->lhsp();
AstNodeExpr* const rhsp = irp->rhsp();
const bool loUnb = VN_IS(lhsp, Unbounded);
const bool hiUnb = VN_IS(rhsp, Unbounded);
AstConst* const minp = VN_CAST(lhsp, Const);
AstConst* const maxp = VN_CAST(rhsp, Const);
if ((!minp && !loUnb) || (!maxp && !hiUnb)) {
arrayBinp->v3error("Non-constant expression in array bins range; "
"range bounds must be constants");
"range bounds must be constants (IEEE 1800-2023 19.5)");
return values;
}
if ((minp && minp->num().isFourState()) || (maxp && maxp->num().isFourState())) {
@@ -945,7 +948,7 @@ class FunctionalCoverageVisitor final : public VNVisitor {
values.push_back(VN_AS(rangep->cloneTree(false), NodeExpr));
} else {
arrayBinp->v3error("Non-constant expression in array bins value list; "
"values must be constants");
"values must be constants (IEEE 1800-2023 19.5)");
return values;
}
}
@@ -1365,11 +1368,15 @@ class FunctionalCoverageVisitor final : public VNVisitor {
for (AstNode* valp = itemp->valuesp(); valp; valp = valp->nextp()) {
AstNodeExpr* singleCondp = nullptr;
AstConst* const constp = VN_AS(valp, Const);
valp = V3Const::constifyEdit(valp);
AstConst* const constp = VN_CAST(valp, Const);
if (!constp) {
valp->v3error("Non-constant expression in transition bin; "
"values must be constants (IEEE 1800-2023 19.5)");
return new AstConst{valp->fileline(), AstConst::BitFalseErroring{}};
}
singleCondp
= new AstEq{constp->fileline(), exprp->cloneTree(false), constp->cloneTree(false)};
if (condp) {
condp = new AstOr{itemp->fileline(), condp, singleCondp};
} else {
@@ -2200,6 +2207,7 @@ class FunctionalCoverageVisitor final : public VNVisitor {
for (AstNode* currRangep = rangep; currRangep; currRangep = currRangep->nextp()) {
AstNodeExpr* rangeCondp = nullptr;
currRangep = V3Const::constifyEdit(currRangep);
if (AstInsideRange* irp = VN_CAST(currRangep, InsideRange)) {
AstNodeExpr* const minExprp = irp->lhsp();
@@ -2216,7 +2224,7 @@ class FunctionalCoverageVisitor final : public VNVisitor {
rangeCondp = new AstConst{irp->fileline(), AstConst::BitTrue{}};
} else if (!boundp) {
irp->v3error("Non-constant expression in bin range; "
"range bounds must be constants");
"range bounds must be constants (IEEE 1800-2023 19.5)");
if (fullCondp) VL_DO_DANGLING(pushDeletep(fullCondp), fullCondp);
return nullptr;
} else if (boundp->num().isFourState()) {
@@ -2230,7 +2238,7 @@ class FunctionalCoverageVisitor final : public VNVisitor {
}
} else if (!minConstp || !maxConstp) {
irp->v3error("Non-constant expression in bin range; "
"range bounds must be constants");
"range bounds must be constants (IEEE 1800-2023 19.5)");
if (fullCondp) VL_DO_DANGLING(pushDeletep(fullCondp), fullCondp);
return nullptr;
} else if (minConstp->num().isFourState() || maxConstp->num().isFourState()) {
@@ -2260,8 +2268,8 @@ class FunctionalCoverageVisitor final : public VNVisitor {
constp->cloneTree(false)};
}
} else {
currRangep->v3error(
"Non-constant expression in bin range; values must be constants");
currRangep->v3error("Non-constant expression in bin range; values must be "
"constants (IEEE 1800-2023 19.5)");
if (fullCondp) VL_DO_DANGLING(pushDeletep(fullCondp), fullCondp);
return nullptr;
}
+6 -2
View File
@@ -2091,8 +2091,8 @@ class WidthVisitor final : public VNVisitor {
if (VN_IS(itemp, InsideRange)) {
userIterate(itemp, nullptr);
} else {
userIterate(itemp, WidthVP{SELF, BOTH}.p());
V3Const::constifyEdit(itemp); // itemp may change
itemp = userIterateSubtreeReturnEdits(itemp, WidthVP{SELF, BOTH}.p());
V3Const::constifyEdit(itemp);
}
}
}
@@ -2106,6 +2106,10 @@ class WidthVisitor final : public VNVisitor {
userIterateAndNext(nodep->arraySizep(), nullptr);
userIterateAndNext(nodep->transp(), nullptr);
}
void visit(AstCoverTransSet* nodep) override { userIterateAndNext(nodep->itemsp(), nullptr); }
void visit(AstCoverTransItem* nodep) override {
userIterateAndNext(nodep->valuesp(), WidthVP{SELF, BOTH}.p());
}
void visit(AstPow* nodep) override {
// Pow is special, output sign only depends on LHS sign, but
// function result depends on both signs
@@ -25,11 +25,11 @@
| ^~~~~
... For warning description see https://verilator.org/warn/COVERIGN?v=latest
... Use "/* verilator lint_off COVERIGN */" and lint_on around source to disable this message.
%Error: t/t_covergroup_args_expr_bad.v:19:26: Non-constant expression in bin range; values must be constants
%Error: t/t_covergroup_args_expr_bad.v:19:26: Non-constant expression in bin range; values must be constants (IEEE 1800-2023 19.5)
: ... note: In instance 't'
19 | bins ref_bin = {0, function_ref(value)};
| ^~~~~~~~~~~~
%Error: t/t_covergroup_args_expr_bad.v:20:26: Non-constant expression in bin range; values must be constants
%Error: t/t_covergroup_args_expr_bad.v:20:26: Non-constant expression in bin range; values must be constants (IEEE 1800-2023 19.5)
: ... note: In instance 't'
20 | bins output_bin = {function_output(value)};
| ^~~~~~~~~~~~~~~
@@ -37,11 +37,11 @@
: ... note: In instance 't'
26 | cp_constructor_ref: coverpoint value {bins bad = {value};}
| ^~~~~
%Error: t/t_covergroup_args_expr_bad.v:26:55: Non-constant expression in bin range; values must be constants
%Error: t/t_covergroup_args_expr_bad.v:26:55: Non-constant expression in bin range; values must be constants (IEEE 1800-2023 19.5)
: ... note: In instance 't'
26 | cp_constructor_ref: coverpoint value {bins bad = {value};}
| ^~~~~
%Error: t/t_covergroup_args_expr_bad.v:31:47: Non-constant expression in bin range; range bounds must be constants
%Error: t/t_covergroup_args_expr_bad.v:31:47: Non-constant expression in bin range; range bounds must be constants (IEEE 1800-2023 19.5)
: ... note: In instance 't'
31 | cp_bad: coverpoint 0 iff (1) {bins bad = {[0 : nonconstant_bound]};}
| ^
+65 -49
View File
@@ -11,35 +11,35 @@
: ... note: In instance 't'
32 | bins auto[1001];
| ^~~~
%Error: t/t_covergroup_autobins_bad.v:44:26: Non-constant expression in bin value list; values must be constants
%Error: t/t_covergroup_autobins_bad.v:44:26: Non-constant expression in bin value list; values must be constants (IEEE 1800-2023 19.5)
: ... note: In instance 't'
44 | ignore_bins ign = {size_var};
| ^~~~~~~~
%Error: t/t_covergroup_autobins_bad.v:45:32: Non-constant expression in bin range; range bounds must be constants
%Error: t/t_covergroup_autobins_bad.v:45:32: Non-constant expression in bin range; range bounds must be constants (IEEE 1800-2023 19.5)
: ... note: In instance 't'
45 | ignore_bins ign_range = {[0:size_var]};
| ^
%Error: t/t_covergroup_autobins_bad.v:39:12: Non-constant expression in array bins range; range bounds must be constants
%Error: t/t_covergroup_autobins_bad.v:39:12: Non-constant expression in array bins range; range bounds must be constants (IEEE 1800-2023 19.5)
: ... note: In instance 't'
39 | bins b[] = {[size_var:size_var]};
| ^
%Error: t/t_covergroup_autobins_bad.v:40:12: Non-constant expression in array bins range; range bounds must be constants
%Error: t/t_covergroup_autobins_bad.v:40:12: Non-constant expression in array bins range; range bounds must be constants (IEEE 1800-2023 19.5)
: ... note: In instance 't'
40 | bins b_mixed[] = {[0:size_var]};
| ^~~~~~~
%Error: t/t_covergroup_autobins_bad.v:41:23: Non-constant expression in bin range; range bounds must be constants
%Error: t/t_covergroup_autobins_bad.v:41:23: Non-constant expression in bin range; range bounds must be constants (IEEE 1800-2023 19.5)
: ... note: In instance 't'
41 | bins b_range = {[size_var:4]};
| ^
%Error: t/t_covergroup_autobins_bad.v:42:24: Non-constant expression in bin range; range bounds must be constants
%Error: t/t_covergroup_autobins_bad.v:42:24: Non-constant expression in bin range; range bounds must be constants (IEEE 1800-2023 19.5)
: ... note: In instance 't'
42 | bins b_range2 = {[0:size_var]};
| ^
%Error: t/t_covergroup_autobins_bad.v:43:18: Non-constant expression in bin range; values must be constants
%Error: t/t_covergroup_autobins_bad.v:43:18: Non-constant expression in bin range; values must be constants (IEEE 1800-2023 19.5)
: ... note: In instance 't'
43 | bins b2 = {size_var};
| ^~~~~~~~
%Error: t/t_covergroup_autobins_bad.v:44:26: Non-constant expression in bin range; values must be constants
%Error: t/t_covergroup_autobins_bad.v:44:26: Non-constant expression in bin range; values must be constants (IEEE 1800-2023 19.5)
: ... note: In instance 't'
44 | ignore_bins ign = {size_var};
| ^~~~~~~~
@@ -49,7 +49,7 @@
| ^~~~~~~~
... For warning description see https://verilator.org/warn/COVERIGN?v=latest
... Use "/* verilator lint_off COVERIGN */" and lint_on around source to disable this message.
%Error: t/t_covergroup_autobins_bad.v:62:31: Non-constant expression in bin range; range bounds must be constants
%Error: t/t_covergroup_autobins_bad.v:62:31: Non-constant expression in bin range; range bounds must be constants (IEEE 1800-2023 19.5)
: ... note: In instance 't'
62 | ignore_bins ign_nclo = {[size_var:4]};
| ^
@@ -65,7 +65,7 @@
: ... note: In instance 't'
61 | ignore_bins ign_xz_hi = {[4'h0:4'bzzzz]};
| ^
%Error: t/t_covergroup_autobins_bad.v:63:23: Non-constant expression in bin range; range bounds must be constants
%Error: t/t_covergroup_autobins_bad.v:63:23: Non-constant expression in bin range; range bounds must be constants (IEEE 1800-2023 19.5)
: ... note: In instance 't'
63 | bins b_nc_ub = {[size_var:$]};
| ^
@@ -85,80 +85,96 @@
: ... note: In instance 't'
73 | bins b_huge[] = {[0:$]};
| ^~~~~~
%Error: t/t_covergroup_autobins_bad.v:84:41: Non-constant expression in bin range; values must be constants
%Error: t/t_covergroup_autobins_bad.v:78:25: Non-constant expression in transition bin; values must be constants (IEEE 1800-2023 19.5)
: ... note: In instance 't'
84 | cp_a: coverpoint cp_expr {bins x = {size_var};}
78 | bins bns1 = (1 => size_var);
| ^~~~~~~~
%Error: t/t_covergroup_autobins_bad.v:79:20: Non-constant expression in transition bin; values must be constants (IEEE 1800-2023 19.5)
: ... note: In instance 't'
79 | bins bns2 = (size_var => 2);
| ^~~~~~~~
%Error: t/t_covergroup_autobins_bad.v:80:20: Non-constant expression in transition bin; values must be constants (IEEE 1800-2023 19.5)
: ... note: In instance 't'
80 | bins bns3 = (size_var => size_var);
| ^~~~~~~~
%Error: t/t_covergroup_autobins_bad.v:80:32: Non-constant expression in transition bin; values must be constants (IEEE 1800-2023 19.5)
: ... note: In instance 't'
80 | bins bns3 = (size_var => size_var);
| ^~~~~~~~
%Error: t/t_covergroup_autobins_bad.v:91:41: Non-constant expression in bin range; values must be constants (IEEE 1800-2023 19.5)
: ... note: In instance 't'
91 | cp_a: coverpoint cp_expr {bins x = {size_var};}
| ^~~~~~~~
%Warning-COVERIGN: t/t_covergroup_autobins_bad.v:87:23: Unsupported: non-constant or non-integral 'intersect' value, or four-state range bound.
%Warning-COVERIGN: t/t_covergroup_autobins_bad.v:94:23: Unsupported: non-constant or non-integral 'intersect' value, or four-state range bound.
: ... note: In instance 't'
87 | bins filtered = binsof(cp_a) intersect {0};
94 | bins filtered = binsof(cp_a) intersect {0};
| ^~~~~~
%Error: t/t_covergroup_autobins_bad.v:91:41: Non-constant expression in bin range; range bounds must be constants
%Error: t/t_covergroup_autobins_bad.v:98:41: Non-constant expression in bin range; range bounds must be constants (IEEE 1800-2023 19.5)
: ... note: In instance 't'
91 | cp_a: coverpoint cp_expr {bins x = {[size_var : 1]};}
98 | cp_a: coverpoint cp_expr {bins x = {[size_var : 1]};}
| ^
%Error: t/t_covergroup_autobins_bad.v:96:41: Non-constant expression in bin range; range bounds must be constants
: ... note: In instance 't'
96 | cp_a: coverpoint cp_expr {bins x = {[0 : size_var]};}
%Error: t/t_covergroup_autobins_bad.v:103:41: Non-constant expression in bin range; range bounds must be constants (IEEE 1800-2023 19.5)
: ... note: In instance 't'
103 | cp_a: coverpoint cp_expr {bins x = {[0 : size_var]};}
| ^
%Error: t/t_covergroup_autobins_bad.v:101:36: Four-state (x/z) value in array bins range bound; range bounds must be two-state constants
%Error: t/t_covergroup_autobins_bad.v:108:36: Four-state (x/z) value in array bins range bound; range bounds must be two-state constants
: ... note: In instance 't'
101 | cp_a: coverpoint cp_expr {bins x[] = {[4'b000x : 4'hF]};}
108 | cp_a: coverpoint cp_expr {bins x[] = {[4'b000x : 4'hF]};}
| ^
%Error: t/t_covergroup_autobins_bad.v:106:36: Four-state (x/z) value in array bins range bound; range bounds must be two-state constants
%Error: t/t_covergroup_autobins_bad.v:113:36: Four-state (x/z) value in array bins range bound; range bounds must be two-state constants
: ... note: In instance 't'
106 | cp_a: coverpoint cp_expr {bins x[] = {[4'h0 : 4'b000x]};}
113 | cp_a: coverpoint cp_expr {bins x[] = {[4'h0 : 4'b000x]};}
| ^
%Error: t/t_covergroup_autobins_bad.v:111:36: Non-constant expression in array bins value list; values must be constants
%Error: t/t_covergroup_autobins_bad.v:118:36: Non-constant expression in array bins value list; values must be constants (IEEE 1800-2023 19.5)
: ... note: In instance 't'
111 | cp_a: coverpoint cp_expr {bins x[] = {size_var};}
118 | cp_a: coverpoint cp_expr {bins x[] = {size_var};}
| ^
%Error: t/t_covergroup_autobins_bad.v:126:28: binsof coverpoint 'missing' is not an item of cross 'xc' (IEEE 1800-2012 19.6.1).
%Error: t/t_covergroup_autobins_bad.v:133:28: binsof coverpoint 'missing' is not an item of cross 'xc' (IEEE 1800-2012 19.6.1).
: ... note: In instance 't'
126 | bins missing_point = binsof(missing);
133 | bins missing_point = binsof(missing);
| ^~~~~~
%Error: t/t_covergroup_autobins_bad.v:127:30: binsof coverpoint 'cp_other' is not an item of cross 'xc' (IEEE 1800-2012 19.6.1).
%Error: t/t_covergroup_autobins_bad.v:134:30: binsof coverpoint 'cp_other' is not an item of cross 'xc' (IEEE 1800-2012 19.6.1).
: ... note: In instance 't'
127 | bins uncrossed_point = binsof(cp_other);
134 | bins uncrossed_point = binsof(cp_other);
| ^~~~~~
%Error: t/t_covergroup_autobins_bad.v:128:26: Cannot find bin 'missing' in coverpoint 'cp_a' (IEEE 1800-2012 19.6.1).
%Error: t/t_covergroup_autobins_bad.v:135:26: Cannot find bin 'missing' in coverpoint 'cp_a' (IEEE 1800-2012 19.6.1).
: ... note: In instance 't'
128 | bins missing_bin = binsof(cp_a.missing);
135 | bins missing_bin = binsof(cp_a.missing);
| ^~~~~~
%Error: t/t_covergroup_autobins_bad.v:130:7: Duplicate cross bin 'duplicate' (IEEE 1800-2012 19.6.1).
%Error: t/t_covergroup_autobins_bad.v:137:7: Duplicate cross bin 'duplicate' (IEEE 1800-2012 19.6.1).
: ... note: In instance 't'
130 | bins duplicate = binsof(cp_b);
137 | bins duplicate = binsof(cp_b);
| ^~~~
%Warning-COVERIGN: t/t_covergroup_autobins_bad.v:131:26: Unsupported: non-constant or non-integral 'intersect' value, or four-state range bound.
%Warning-COVERIGN: t/t_covergroup_autobins_bad.v:138:26: Unsupported: non-constant or non-integral 'intersect' value, or four-state range bound.
: ... note: In instance 't'
131 | bins nonconstant = binsof(cp_a) intersect {size_var} || binsof(cp_b);
138 | bins nonconstant = binsof(cp_a) intersect {size_var} || binsof(cp_b);
| ^~~~~~
%Warning-COVERIGN: t/t_covergroup_autobins_bad.v:132:32: Unsupported: non-constant or non-integral 'intersect' value, or four-state range bound.
%Warning-COVERIGN: t/t_covergroup_autobins_bad.v:139:32: Unsupported: non-constant or non-integral 'intersect' value, or four-state range bound.
: ... note: In instance 't'
132 | bins nonconstant_range = binsof(cp_a) intersect {[0:size_var]};
139 | bins nonconstant_range = binsof(cp_a) intersect {[0:size_var]};
| ^~~~~~
%Warning-COVERIGN: t/t_covergroup_autobins_bad.v:143:9: Unsupported: cross coverage with more than 2^32-1 tuples.
%Warning-COVERIGN: t/t_covergroup_autobins_bad.v:150:9: Unsupported: cross coverage with more than 2^32-1 tuples.
: ... note: In instance 't'
143 | xc: cross cp_a, cp_b, cp_c, cp_d, cp_e, cp_f {
150 | xc: cross cp_a, cp_b, cp_c, cp_d, cp_e, cp_f {
| ^~~~~
%Warning-COVERIGN: t/t_covergroup_autobins_bad.v:146:16: Unsupported: cross coverage with more than 2^32-1 tuples.
%Warning-COVERIGN: t/t_covergroup_autobins_bad.v:153:16: Unsupported: cross coverage with more than 2^32-1 tuples.
: ... note: In instance 't'
146 | auto_only: cross cp_a, cp_b, cp_c, cp_d, cp_e, cp_f;
153 | auto_only: cross cp_a, cp_b, cp_c, cp_d, cp_e, cp_f;
| ^~~~~
%Error: t/t_covergroup_autobins_bad.v:152:34: Non-constant expression in bin value list; values must be constants
%Error: t/t_covergroup_autobins_bad.v:159:34: Non-constant expression in bin value list; values must be constants (IEEE 1800-2023 19.5)
: ... note: In instance 't'
152 | ignore_bins nonconstant = {size_var};
159 | ignore_bins nonconstant = {size_var};
| ^~~~~~~~
%Error: t/t_covergroup_autobins_bad.v:152:34: Non-constant expression in bin range; values must be constants
%Error: t/t_covergroup_autobins_bad.v:159:34: Non-constant expression in bin range; values must be constants (IEEE 1800-2023 19.5)
: ... note: In instance 't'
152 | ignore_bins nonconstant = {size_var};
159 | ignore_bins nonconstant = {size_var};
| ^~~~~~~~
%Warning-COVERIGN: t/t_covergroup_autobins_bad.v:156:23: Unsupported: non-constant or non-integral 'intersect' value, or four-state range bound.
%Warning-COVERIGN: t/t_covergroup_autobins_bad.v:163:23: Unsupported: non-constant or non-integral 'intersect' value, or four-state range bound.
: ... note: In instance 't'
156 | bins selected = binsof(cp_a) intersect {0};
163 | bins selected = binsof(cp_a) intersect {0};
| ^~~~~~
%Warning-COVERIGN: t/t_covergroup_autobins_bad.v:195:23: Unsupported: 'intersect' exclusion matching exceeds the selection work limit.
%Warning-COVERIGN: t/t_covergroup_autobins_bad.v:202:23: Unsupported: 'intersect' exclusion matching exceeds the selection work limit.
: ... note: In instance 't'
195 | bins selected = binsof(cp_a.whole) intersect {[0:30'h3fffffff]} && binsof(cp_b);
202 | bins selected = binsof(cp_a.whole) intersect {[0:30'h3fffffff]} && binsof(cp_b);
| ^~~~~~
%Error: Exiting due to
@@ -73,6 +73,13 @@ module t;
bins b_huge[] = {[0:$]}; // open '[lo:$]' over 16-bit coverpoint exceeds bin limit
}
endgroup
covergroup cg_nonconst_transition;
coverpoint cp_expr {
bins bns1 = (1 => size_var); // Transition values must be constant expr
bins bns2 = (size_var => 2);
bins bns3 = (size_var => size_var);
}
endgroup
// Malformed bins on a coverpoint that feeds a *cross*. The cross path
// sizes the coverpoint's hit list (computeHitListBound/extractRangeIntervals)
+18
View File
@@ -0,0 +1,18 @@
#!/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')
test.compile(verilator_flags2=["--top-module", "t"])
test.execute()
test.passes()
@@ -0,0 +1,116 @@
// 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 checkr(gotv,expv) do if ((roundTo5Dec(gotv)) !== (roundTo5Dec(expv))) begin $write("%%Error: %s:%0d: got=%f exp=%f\n", `__FILE__,`__LINE__, (gotv), expv); `stop; end while(0);
// verilog_format: on
function automatic real roundTo5Dec(real x);
int ix = int'(x * 100_000);
return ix / 100_000.0;
endfunction
`define BIN_PERCENTAGE(covered, TOTAL_BINS) ((covered / TOTAL_BINS) * 100.0)
// Values covergroup helper
`define VBIN_PERCENTAGE(covered) `BIN_PERCENTAGE(covered,7)
// Ranges covergroup helper
`define RBIN_PERCENTAGE(covered) `BIN_PERCENTAGE(covered,35)
module t #(
parameter int PARAM = 9
) ();
logic [5:0] val;
localparam logic [5:0] LOCAL_PARAM = 0;
covergroup c_trans;
coverpoint val {
bins bins1 = (1 + 1 => 2 + 2 => 3 + 3 => PARAM => LOCAL_PARAM); // 2 => 4 => 6 => 9 => 0
}
endgroup
covergroup c_values;
coverpoint val {
// 1,2,3,4,5,9,0
bins bins2[] = {(1 & 1) ^ 0, 2 * 1, 3 * 4 / 2 / 2, 4, (5 ** 2) - 20, PARAM, LOCAL_PARAM};
}
endgroup
covergroup c_ranges;
coverpoint val {
// 27:51 and [0:9] == 35 total bins
bins bins3[] = {[3 ** 3 : 58 - 7], [LOCAL_PARAM : PARAM]};
}
endgroup
c_trans ctrans;
c_values cvalues;
c_ranges cranges;
initial begin
ctrans = new();
cvalues = new();
cranges = new();
// Transition
`checkr(ctrans.get_inst_coverage(), 0.0);
val = 2;
ctrans.sample();
val = 4;
ctrans.sample();
val = 6;
ctrans.sample();
val = 9;
ctrans.sample();
val = 0;
ctrans.sample();
`checkr(ctrans.get_inst_coverage(), 100.0);
// Value array
`checkr(cvalues.get_inst_coverage(), 0.0);
val = 1;
cvalues.sample();
`checkr(cvalues.get_inst_coverage(), `VBIN_PERCENTAGE(1.0));
val = 2;
cvalues.sample();
`checkr(cvalues.get_inst_coverage(), `VBIN_PERCENTAGE(2.0));
val = 3;
cvalues.sample();
`checkr(cvalues.get_inst_coverage(), `VBIN_PERCENTAGE(3.0));
val = 4;
cvalues.sample();
`checkr(cvalues.get_inst_coverage(), `VBIN_PERCENTAGE(4.0));
val = 5;
cvalues.sample();
`checkr(cvalues.get_inst_coverage(), `VBIN_PERCENTAGE(5.0));
val = 9;
cvalues.sample();
`checkr(cvalues.get_inst_coverage(), `VBIN_PERCENTAGE(6.0));
val = 0;
cvalues.sample();
`checkr(cvalues.get_inst_coverage(), `VBIN_PERCENTAGE(7.0));
// Ranges
`checkr(cranges.get_inst_coverage(), 0.0);
val = 27;
cranges.sample();
`checkr(cranges.get_inst_coverage(), `RBIN_PERCENTAGE(1.0));
val = 40;
cranges.sample();
`checkr(cranges.get_inst_coverage(), `RBIN_PERCENTAGE(2.0));
val = 48;
cranges.sample();
`checkr(cranges.get_inst_coverage(), `RBIN_PERCENTAGE(3.0));
val = 0;
cranges.sample();
`checkr(cranges.get_inst_coverage(), `RBIN_PERCENTAGE(4.0));
val = 5;
cranges.sample();
`checkr(cranges.get_inst_coverage(), `RBIN_PERCENTAGE(5.0));
val = 9;
cranges.sample();
`checkr(cranges.get_inst_coverage(), `RBIN_PERCENTAGE(6.0));
$finish;
end
endmodule