diff --git a/src/V3Covergroup.cpp b/src/V3Covergroup.cpp index 13d54f14e..9eab4cb62 100644 --- a/src/V3Covergroup.cpp +++ b/src/V3Covergroup.cpp @@ -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 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; } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 113c6e4d2..549f814e8 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -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 diff --git a/test_regress/t/t_covergroup_args_expr_bad.out b/test_regress/t/t_covergroup_args_expr_bad.out index 8feca1573..b438e990a 100644 --- a/test_regress/t/t_covergroup_args_expr_bad.out +++ b/test_regress/t/t_covergroup_args_expr_bad.out @@ -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]};} | ^ diff --git a/test_regress/t/t_covergroup_autobins_bad.out b/test_regress/t/t_covergroup_autobins_bad.out index 8756ad725..55c506bf8 100644 --- a/test_regress/t/t_covergroup_autobins_bad.out +++ b/test_regress/t/t_covergroup_autobins_bad.out @@ -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 diff --git a/test_regress/t/t_covergroup_autobins_bad.v b/test_regress/t/t_covergroup_autobins_bad.v index 1e9362e54..f193ca42e 100644 --- a/test_regress/t/t_covergroup_autobins_bad.v +++ b/test_regress/t/t_covergroup_autobins_bad.v @@ -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) diff --git a/test_regress/t/t_covergroup_bin_const_expr.py b/test_regress/t/t_covergroup_bin_const_expr.py new file mode 100755 index 000000000..512f5ec41 --- /dev/null +++ b/test_regress/t/t_covergroup_bin_const_expr.py @@ -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() diff --git a/test_regress/t/t_covergroup_bin_const_expr.v b/test_regress/t/t_covergroup_bin_const_expr.v new file mode 100644 index 000000000..5d25ed3d5 --- /dev/null +++ b/test_regress/t/t_covergroup_bin_const_expr.v @@ -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