diff --git a/src/V3Covergroup.cpp b/src/V3Covergroup.cpp index aebfd1bd4..e013d23e8 100644 --- a/src/V3Covergroup.cpp +++ b/src/V3Covergroup.cpp @@ -493,12 +493,31 @@ class FunctionalCoverageVisitor final : public VNVisitor { } // IEEE 1800-2023 19.5.3/19.11.1: partition first, then apply exclusions. + // IEEE 1800-2023 19.5.2: an enum coverpoint has one automatic bin per enumeration value + void createEnumAutoBins(AstCoverpoint* coverpointp, AstNodeExpr* exprp, + const AstEnumDType* enump) { + FileLine* const fl = coverpointp->fileline(); + for (const AstEnumItem* itemp = enump->itemsp(); itemp; + itemp = VN_AS(itemp->nextp(), EnumItem)) { + AstConst* const lop = newValueConst(fl, VN_AS(itemp->valuep(), Const)->num(), exprp); + AstInsideRange* const rangep = new AstInsideRange{fl, lop, lop->cloneTree(false)}; + rangep->dtypeFrom(exprp); + coverpointp->addBinsp( + new AstCoverBin{fl, "auto[" + itemp->name() + "]", rangep, false, false}); + } + } + void createImplicitAutoBins(AstCoverpoint* coverpointp, AstNodeExpr* exprp, int autoBinMax) { for (AstNode* nodep = coverpointp->binsp(); nodep; nodep = nodep->nextp()) { const VCoverBinsType kind = VN_AS(nodep, CoverBin)->binsType(); if (kind != VCoverBinsType::BINS_IGNORE && kind != VCoverBinsType::BINS_ILLEGAL) return; } + if (const AstEnumDType* const enump + = VN_CAST(exprp->dtypep()->skipRefToEnump(), EnumDType)) { + createEnumAutoBins(coverpointp, exprp, enump); + return; + } const int width = exprp->width(); const int arithmeticWidth = width + 1; V3Number total{coverpointp, arithmeticWidth}; diff --git a/test_regress/t/t_covergroup_enum_autobins.out b/test_regress/t/t_covergroup_enum_autobins.out new file mode 100644 index 000000000..96ace2635 --- /dev/null +++ b/test_regress/t/t_covergroup_enum_autobins.out @@ -0,0 +1,20 @@ +cg.cp_call.auto[A]: 0 +cg.cp_call.auto[B]: 0 +cg.cp_call.auto[C]: 2 +cg.cp_max.auto[A]: 0 +cg.cp_max.auto[B]: 1 +cg.cp_max.auto[C]: 1 +cg.cp_var.auto[A]: 0 +cg.cp_var.auto[B]: 1 +cg.cp_var.auto[C]: 1 +cg.cp_wide.auto[E01]: 0 +cg.cp_wide.auto[ELARGE]: 1 +cg.cx.auto[A]_x_auto[A] [cross]: 0 +cg.cx.auto[A]_x_auto[B] [cross]: 0 +cg.cx.auto[A]_x_auto[C] [cross]: 0 +cg.cx.auto[B]_x_auto[A] [cross]: 0 +cg.cx.auto[B]_x_auto[B] [cross]: 0 +cg.cx.auto[B]_x_auto[C] [cross]: 1 +cg.cx.auto[C]_x_auto[A] [cross]: 0 +cg.cx.auto[C]_x_auto[B] [cross]: 0 +cg.cx.auto[C]_x_auto[C] [cross]: 1 diff --git a/test_regress/t/t_covergroup_enum_autobins.py b/test_regress/t/t_covergroup_enum_autobins.py new file mode 100755 index 000000000..c2434ea87 --- /dev/null +++ b/test_regress/t/t_covergroup_enum_autobins.py @@ -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 + +import coverage_covergroup_common + +test.scenarios('vlt_all') + +coverage_covergroup_common.run(test) diff --git a/test_regress/t/t_covergroup_enum_autobins.v b/test_regress/t/t_covergroup_enum_autobins.v new file mode 100644 index 000000000..96d622dbd --- /dev/null +++ b/test_regress/t/t_covergroup_enum_autobins.v @@ -0,0 +1,55 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain +// SPDX-FileCopyrightText: 2026 David Harris +// SPDX-License-Identifier: CC0-1.0 + +// Test automatic bins of an enum coverpoint: one bin per enumeration value + +typedef enum logic [2:0] { + A = 3'd5, + B = 3'd1, + C = 3'd7 +} e_t; + +typedef enum logic [59:0] { + E01 = 60'h1, + ELARGE = 60'h1234_4567_abcd +} wide_t; + +class Item; + e_t e; + function e_t get_e(); + return e; + endfunction +endclass + +module t; + e_t v; + wide_t w; + + covergroup cg with function sample(Item item); + cp_var: coverpoint v; + cp_call: coverpoint item.get_e(); + cp_max: coverpoint v {option.auto_bin_max = 2;} + cx: cross cp_var, cp_call; + cp_wide: coverpoint w; + endgroup + + cg cg_i = new; + + initial begin + Item item; + item = new; + v = B; + item.e = C; + w = ELARGE; + cg_i.sample(item); + v = C; + item.e = C; + w = wide_t'(60'h1_0000_0001); // not an enum value; aliases E01 in the low 32 bits + cg_i.sample(item); + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule