Refactoring node locations and enums ; Delete coverpoints after V3Covergroup so they don't accidentally hit the generators

Signed-off-by: Matthew Ballance <matt.ballance@gmail.com>
This commit is contained in:
Matthew Ballance 2026-02-28 20:10:20 +00:00
parent 30ca516362
commit 07f959d31d
12 changed files with 173 additions and 466 deletions

View File

@ -365,14 +365,14 @@ appropriate width.
Assertions
----------
Verilator is beginning to add support for assertions and functional coverage.
Verilator partially supports assertions and functional coverage.
Verilator currently converts assertions to simple ``if (...) error`` statements,
and simple coverage statements to increment the line counters described in the
:ref:`coverage section<Coverage>`.
Verilator also partially supports SystemVerilog functional coverage with
``covergroup``, ``coverpoint``, bins, cross coverage, and transition bins. See
the :ref:`Functional Coverage<user coverage>` section for details on using
:ref:`Functional Coverage<user coverage>` for details on using
covergroups for comprehensive coverage analysis.
Verilator does not support SEREs yet. All assertion and coverage statements

View File

@ -184,7 +184,8 @@ Verilator supports adding code to the Verilated model to support
SystemVerilog code coverage. With :vlopt:`--coverage`, Verilator enables
all forms of coverage:
- :ref:`User Coverage`
- :ref:`Property Coverage`
- :ref:`Covergroup Coverage`
- :ref:`Line Coverage`
- :ref:`Toggle Coverage`
@ -192,19 +193,14 @@ When a model with coverage is executed, it will create a coverage file for
collection and later analysis, see :ref:`Coverage Collection`.
.. _user coverage:
.. _property coverage:
Functional Coverage
-------------------
Property Coverage
-----------------
With :vlopt:`--coverage` or :vlopt:`--coverage-user`, Verilator will
translate functional coverage points the user has inserted manually in
SystemVerilog code through into the Verilated model. Verilator supports both
simple coverage points and full covergroup-based functional coverage as
defined in IEEE 1800-2023 Section 19.
Simple Coverage Points
^^^^^^^^^^^^^^^^^^^^^^
translate property coverage points the user has inserted manually in
SystemVerilog code into the Verilated model.
For simple coverage points, use the ``cover property`` construct:
@ -214,14 +210,15 @@ For simple coverage points, use the ``cover property`` construct:
This adds a coverage point that tracks whether the condition has been observed.
Covergroups
^^^^^^^^^^^
.. _covergroup coverage:
Verilator supports SystemVerilog covergroups for comprehensive functional
coverage. A covergroup defines a set of coverage points (coverpoints) with
bins that track specific values or value ranges.
Covergroup Coverage
-------------------
**Basic Example:**
With :vlopt:`--coverage` or :vlopt:`--coverage-user`, Verilator will
translate covergroup coverage points the user has inserted manually in
SystemVerilog code into the Verilated model. Verilator supports
coverpoints with value and transition bins, and cross points.
.. code-block:: sv
@ -250,200 +247,26 @@ bins that track specific values or value ranges.
end
endmodule
**Important:** Verilator requires explicit ``sample()`` calls. The automatic
sampling syntax ``covergroup cg @(posedge clk);`` is parsed but the automatic
sampling is not performed. Always call ``sample()`` explicitly in your code.
Coverpoint Bins
^^^^^^^^^^^^^^^
Bins define which values to track for coverage. Verilator supports several bin types:
**Value Bins:**
.. code-block:: sv
coverpoint state {
bins idle = {0};
bins active = {1, 2, 3};
bins error = {4};
}
**Range Bins:**
.. code-block:: sv
coverpoint addr {
bins low = {[0:63]};
bins medium = {[64:127]};
bins high = {[128:255]};
}
**Array Bins (Automatic):**
.. code-block:: sv
coverpoint state {
bins state[] = {[0:3]}; // Creates bins: state[0], state[1], state[2], state[3]
}
**Wildcard Bins:**
.. code-block:: sv
coverpoint opcode {
wildcard bins load_ops = {4'b00??}; // Matches 0000, 0001, 0010, 0011
wildcard bins store_ops = {4'b01??}; // Matches 0100, 0101, 0110, 0111
}
**Special Bins:**
.. code-block:: sv
coverpoint value {
bins valid[] = {[0:10]};
ignore_bins unused = {11, 12, 13}; // Don't track these values
illegal_bins bad = {[14:15]}; // Report error if seen
}
The ``ignore_bins`` are excluded from coverage calculation, while ``illegal_bins``
will cause a runtime error if sampled.
**Default Bins:**
.. code-block:: sv
coverpoint state {
bins defined = {0, 1, 2};
bins others = default; // Catches all other values
}
Cross Coverage
^^^^^^^^^^^^^^
Cross coverage tracks combinations of values from multiple coverpoints:
.. code-block:: sv
covergroup cg;
cp_cmd: coverpoint cmd;
cp_addr: coverpoint addr {
bins low = {[0:127]};
bins high = {[128:255]};
}
// Cross coverage of command and address
cross_cmd_addr: cross cp_cmd, cp_addr;
endgroup
The cross automatically creates bins for all combinations: ``(read, low)``,
``(read, high)``, ``(write, low)``, ``(write, high)``.
Verilator supports arbitrary N-way cross coverage.
Transition Bins
^^^^^^^^^^^^^^^
Transition bins track sequences of values across multiple samples:
.. code-block:: sv
covergroup cg;
coverpoint state {
bins trans_idle_active = (0 => 1); // idle to active
bins trans_active_done = (1 => 2); // active to done
bins trans_done_idle = (2 => 0); // done back to idle
}
endgroup
**Supported Syntax:**
Verilator supports multi-value transition sequences:
.. code-block:: sv
coverpoint state {
// Two-value transitions
bins trans_2 = (0 => 1);
// Multi-value transitions
bins trans_3 = (0 => 1 => 2);
bins trans_4 = (0 => 1 => 2 => 3);
// Transitions with value sets
bins trans_set = (0, 1 => 2, 3); // (0=>2), (0=>3), (1=>2), (1=>3)
}
**Unsupported Repetition Operators:**
Verilator does not currently support IEEE 1800-2023 transition bin repetition
operators. The following syntax will generate a ``COVERIGN`` warning and be
ignored:
* **Consecutive repetition** ``[*N]`` - Repeat value N times consecutively
.. code-block:: sv
bins trans = (1 => 2 [*3] => 3); // Unsupported: 1, 2, 2, 2, 3
* **Goto repetition** ``[->N]`` - See value N times with any gaps, next value follows immediately
.. code-block:: sv
bins trans = (1 => 2 [->3] => 3); // Unsupported: 1, 2, X, 2, Y, 2, 3
* **Nonconsecutive repetition** ``[=N]`` - See value N times with gaps allowed everywhere
.. code-block:: sv
bins trans = (1 => 2 [=3] => 3); // Unsupported: 1, 2, X, 2, Y, 2, Z, 3
If you need repetition behavior, consider using multiple bins to represent the
desired sequences explicitly.
Bin Options
^^^^^^^^^^^
Individual bins can have options:
.. code-block:: sv
coverpoint state {
bins idle = {0} with (option.at_least = 10); // Must see 10 times
}
Querying Coverage
^^^^^^^^^^^^^^^^^
To get the current coverage percentage:
.. code-block:: sv
real cov = cg_inst.get_inst_coverage();
$display("Coverage: %0.1f%%", cov);
The ``get_inst_coverage()`` method returns a real value from 0.0 to 100.0
representing the percentage of bins that have been hit.
Coverage Reports
^^^^^^^^^^^^^^^^
When running with :vlopt:`--coverage`, Verilator generates coverage data files
that can be analyzed with the :ref:`verilator_coverage<Verilator Coverage>`
tool:
.. code-block:: bash
# Run simulation with coverage enabled
$ verilator --coverage --exe --build sim.cpp top.v
$ ./obj_dir/Vtop
# Generate coverage report
$ verilator_coverage --annotate coverage_report coverage.dat
$ verilator_coverage --write merged.dat coverage.dat
The coverage data integrates with Verilator's existing coverage infrastructure,
so you can view functional coverage alongside line and toggle coverage.
Supported Features
^^^^^^^^^^^^^^^^^^
* Coverpoints on integral expressions with value, range, wildcard, and transition bins
* Conditional coverpoint sampling (iff)
* Explicit and clocked sampling, with sample-function parameters
* at_least and auto_bin_max options on covergroups and coverpoints
* Cross points with auto-bins
Unsupported Features
^^^^^^^^^^^^^^^^^^^^
* Coverpoints on real (floating-point) expressions
* Coverpoint bin filtering (with)
* Coverpoint bin conditional sampling (iff)
* Transition bins with repetition operators ([\*N], [->N], [=N])
* Explicitly-typed coverpoints
* Block-event sampling
* Covergroup inheritance (extends)
* Cross points with user-defined bins
Functional Coverage Data Format
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -477,143 +300,6 @@ with :command:`verilator_coverage`:
# Exclude functional coverage
$ verilator_coverage --filter-type '!funccov' --annotate report coverage.dat
Covergroup Options
^^^^^^^^^^^^^^^^^^
Covergroups support various options:
.. code-block:: sv
covergroup cg with function sample(logic [7:0] addr);
option.name = "my_covergroup";
option.comment = "Address coverage";
coverpoint addr;
endgroup
Parameterized sampling allows passing values directly to ``sample()``:
.. code-block:: sv
cg cg_inst = new;
cg_inst.sample(addr_value);
Dynamic Covergroup Creation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Covergroups can be created dynamically at runtime:
.. code-block:: sv
cg cg_inst;
initial begin
if (enable_coverage) begin
cg_inst = new;
end
end
Covergroups in Classes
^^^^^^^^^^^^^^^^^^^^^^^
Covergroups can be defined inside classes:
.. code-block:: sv
class MyClass;
logic [7:0] data;
covergroup cg;
coverpoint data;
endgroup
function new();
cg = new;
endfunction
task record();
cg.sample();
endtask
endclass
Limitations and Unsupported Features
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
**Automatic Sampling:** The syntax ``covergroup cg @(posedge clk);`` is parsed
but automatic sampling is not performed. Use explicit ``sample()`` calls:
.. code-block:: sv
// Instead of this:
covergroup cg @(posedge clk); // Automatic sampling not supported
...
endgroup
// Do this:
covergroup cg;
...
endgroup
cg cg_inst = new;
always @(posedge clk) cg_inst.sample(); // Explicit sampling
**Covergroup Inheritance:** Covergroup inheritance using the ``extends`` keyword
is not currently supported. This will generate an error:
.. code-block:: sv
covergroup base_cg;
coverpoint value;
endgroup
covergroup derived_cg extends base_cg; // Not supported
coverpoint other_value;
endgroup
As a workaround, duplicate the coverpoint definitions in each covergroup.
**Type-Level (Static) Coverage:** Aggregated type-level coverage using the
static ``get_coverage()`` method is not currently supported. Only instance-level
coverage via ``get_inst_coverage()`` is available:
.. code-block:: sv
covergroup cg;
coverpoint value;
endgroup
cg cg1 = new;
cg cg2 = new;
// This works - instance-level coverage
real inst_cov = cg1.get_inst_coverage();
// This is not supported - type-level coverage
// real type_cov = cg::get_coverage(); // Will not aggregate across instances
**Advanced Transition Features:** Complex transition patterns including
multi-value transitions with more than 2 states may have incomplete case
statement coverage in generated code. Simple 2-state transitions work correctly:
.. code-block:: sv
coverpoint state {
// This works well
bins trans_2state = (0 => 1);
// This may generate incomplete case statements
bins trans_3state = (0 => 1 => 2); // Limited support
}
**Transition Bin Repetition Operators:** The repetition operators ``[*N]``,
``[->N]``, and ``[=N]`` for transition bins are not supported. Use multiple
explicit bins to represent repeated sequences. See the
:ref:`Transition Bins<Transition Bins>` section for details.
For a complete list of supported features and current implementation status,
see the functional coverage plan in the Verilator source tree at
``docs/functional_coverage_plan.md``.
.. _line coverage:

View File

@ -783,10 +783,10 @@ class CovergroupSamplingVisitor final : public VNVisitor {
UINFO(4, "Fixed VarRef in SenTree: " << refp->varp()->name() << " -> "
<< vscp->name() << endl);
} else {
UINFO(4, "WARNING: Could not find VarScope for "
<< refp->varp()->name() << " in scope " << m_scopep->name()
<< " - automatic sampling may not work for internal clocks"
<< endl);
refp->v3fatalSrc("Could not find VarScope for clock signal '"
<< refp->varp()->name() << "' in scope "
<< m_scopep->name()
<< " when creating covergroup sampling active");
}
}
});

View File

@ -1107,6 +1107,113 @@ inline std::ostream& operator<<(std::ostream& os, const VCastable& rhs) {
//######################################################################
class VCoverBinsType final {
public:
enum en : uint8_t {
USER,
ARRAY,
AUTO,
BINS_IGNORE, // Renamed to avoid Windows macro conflict
BINS_ILLEGAL, // Renamed to avoid Windows macro conflict
DEFAULT,
BINS_WILDCARD, // Renamed to avoid Windows macro conflict
TRANSITION
};
enum en m_e;
VCoverBinsType()
: m_e{USER} {}
// cppcheck-suppress noExplicitConstructor
constexpr VCoverBinsType(en _e)
: m_e{_e} {}
explicit VCoverBinsType(int _e)
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
constexpr operator en() const { return m_e; }
const char* ascii() const {
static const char* const names[]
= {"user", "array", "auto", "ignore", "illegal", "default", "wildcard", "transition"};
return names[m_e];
}
};
constexpr bool operator==(const VCoverBinsType& lhs, const VCoverBinsType& rhs) {
return lhs.m_e == rhs.m_e;
}
constexpr bool operator==(const VCoverBinsType& lhs, VCoverBinsType::en rhs) {
return lhs.m_e == rhs;
}
constexpr bool operator==(VCoverBinsType::en lhs, const VCoverBinsType& rhs) {
return lhs == rhs.m_e;
}
//######################################################################
class VCoverOptionType final {
public:
enum en : uint8_t { WEIGHT, GOAL, AT_LEAST, AUTO_BIN_MAX, PER_INSTANCE, COMMENT };
enum en m_e;
VCoverOptionType()
: m_e{WEIGHT} {}
// cppcheck-suppress noExplicitConstructor
constexpr VCoverOptionType(en _e)
: m_e{_e} {}
explicit VCoverOptionType(int _e)
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
constexpr operator en() const { return m_e; }
const char* ascii() const {
static const char* const names[]
= {"weight", "goal", "at_least", "auto_bin_max", "per_instance", "comment"};
return names[m_e];
}
};
constexpr bool operator==(const VCoverOptionType& lhs, const VCoverOptionType& rhs) {
return lhs.m_e == rhs.m_e;
}
constexpr bool operator==(const VCoverOptionType& lhs, VCoverOptionType::en rhs) {
return lhs.m_e == rhs;
}
constexpr bool operator==(VCoverOptionType::en lhs, const VCoverOptionType& rhs) {
return lhs == rhs.m_e;
}
//######################################################################
class VTransRepType final {
public:
enum en : uint8_t {
NONE, // No repetition
CONSEC, // Consecutive repetition [*]
GOTO, // Goto repetition [->]
NONCONS // Nonconsecutive repetition [=]
};
enum en m_e;
VTransRepType()
: m_e{NONE} {}
// cppcheck-suppress noExplicitConstructor
constexpr VTransRepType(en _e)
: m_e{_e} {}
explicit VTransRepType(int _e)
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
constexpr operator en() const { return m_e; }
const char* ascii() const {
static const char* const names[] = {"", "[*]", "[->]", "[=]"};
return names[m_e];
}
const char* asciiJson() const {
static const char* const names[] = {"", "\"consec\"", "\"goto\"", "\"noncons\""};
return names[m_e];
}
};
constexpr bool operator==(const VTransRepType& lhs, const VTransRepType& rhs) {
return lhs.m_e == rhs.m_e;
}
constexpr bool operator==(const VTransRepType& lhs, VTransRepType::en rhs) {
return lhs.m_e == rhs;
}
constexpr bool operator==(VTransRepType::en lhs, const VTransRepType& rhs) {
return lhs == rhs.m_e;
}
//######################################################################
class VDirection final {
public:
enum en : uint8_t { NONE, INPUT, OUTPUT, INOUT, REF, CONSTREF };

View File

@ -1043,32 +1043,6 @@ public:
class AstCoverTransSet;
class AstCoverSelectExpr;
enum class VCoverBinsType : uint8_t {
USER,
ARRAY,
AUTO,
BINS_IGNORE, // Renamed to avoid Windows macro conflict
BINS_ILLEGAL, // Renamed to avoid Windows macro conflict
DEFAULT,
BINS_WILDCARD, // Renamed to avoid Windows macro conflict
TRANSITION
};
enum class VCoverOptionType : uint8_t {
WEIGHT,
GOAL,
AT_LEAST,
AUTO_BIN_MAX,
PER_INSTANCE,
COMMENT
};
enum class VTransRepType : uint8_t {
NONE, // No repetition
CONSEC, // Consecutive repetition [*]
GOTO, // Goto repetition [->]
NONCONS // Nonconsecutive repetition [=]
};
class AstCoverBin final : public AstNode {
// @astgen op1 := rangesp : List[AstNode]

View File

@ -3506,9 +3506,8 @@ void AstCovergroup::dump(std::ostream& str) const {
}
void AstCovergroup::dumpJson(std::ostream& str) const {
this->AstNode::dumpJson(str);
str << ", \"name\": " << VString::quotePercent(name());
if (m_isClass) str << ", \"isClass\": true";
dumpJsonBoolFuncIf(str, isClass);
dumpJsonGen(str);
}
void AstCoverpoint::dump(std::ostream& str) const { this->AstNodeFuncCovItem::dump(str); }
@ -3517,57 +3516,26 @@ void AstCoverpoint::dumpJson(std::ostream& str) const { this->AstNodeFuncCovItem
void AstCoverBin::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " " << m_name << " ";
switch (m_type) {
case VCoverBinsType::USER: str << "user"; break;
case VCoverBinsType::ARRAY: str << "array"; break;
case VCoverBinsType::AUTO: str << "auto"; break;
case VCoverBinsType::BINS_IGNORE: str << "ignore"; break;
case VCoverBinsType::BINS_ILLEGAL: str << "illegal"; break;
case VCoverBinsType::DEFAULT: str << "default"; break;
case VCoverBinsType::BINS_WILDCARD: str << "wildcard"; break;
case VCoverBinsType::TRANSITION: str << "transition"; break;
}
str << " " << m_name << " " << m_type.ascii();
if (m_isArray) str << "[]";
}
void AstCoverBin::dumpJson(std::ostream& str) const {
this->AstNode::dumpJson(str);
str << ", \"name\": " << VString::quotePercent(m_name);
str << ", \"binsType\": ";
switch (m_type) {
case VCoverBinsType::USER: str << "\"user\""; break;
case VCoverBinsType::ARRAY: str << "\"array\""; break;
case VCoverBinsType::AUTO: str << "\"auto\""; break;
case VCoverBinsType::BINS_IGNORE: str << "\"ignore\""; break;
case VCoverBinsType::BINS_ILLEGAL: str << "\"illegal\""; break;
case VCoverBinsType::DEFAULT: str << "\"default\""; break;
case VCoverBinsType::BINS_WILDCARD: str << "\"wildcard\""; break;
case VCoverBinsType::TRANSITION: str << "\"transition\""; break;
}
str << ", \"binsType\": \"" << m_type.ascii() << "\"";
if (m_isArray) str << ", \"isArray\": true";
}
void AstCoverTransItem::dump(std::ostream& str) const {
this->AstNode::dump(str);
switch (m_repType) {
case VTransRepType::NONE: break;
case VTransRepType::CONSEC: str << " [*]"; break;
case VTransRepType::GOTO: str << " [->]"; break;
case VTransRepType::NONCONS: str << " [=]"; break;
}
if (m_repType != VTransRepType::NONE) str << " " << m_repType.ascii();
}
void AstCoverTransItem::dumpJson(std::ostream& str) const {
this->AstNode::dumpJson(str);
if (m_repType != VTransRepType::NONE) {
str << ", \"repType\": ";
switch (m_repType) {
case VTransRepType::NONE: break;
case VTransRepType::CONSEC: str << "\"consec\""; break;
case VTransRepType::GOTO: str << "\"goto\""; break;
case VTransRepType::NONCONS: str << "\"noncons\""; break;
}
str << ", \"repType\": " << m_repType.asciiJson();
}
}
@ -3594,28 +3562,12 @@ void AstCoverCrossBins::dumpJson(std::ostream& str) const {
void AstCoverOption::dump(std::ostream& str) const {
this->AstNode::dump(str);
str << " ";
switch (m_type) {
case VCoverOptionType::WEIGHT: str << "weight"; break;
case VCoverOptionType::GOAL: str << "goal"; break;
case VCoverOptionType::AT_LEAST: str << "at_least"; break;
case VCoverOptionType::AUTO_BIN_MAX: str << "auto_bin_max"; break;
case VCoverOptionType::PER_INSTANCE: str << "per_instance"; break;
case VCoverOptionType::COMMENT: str << "comment"; break;
}
str << " " << m_type.ascii();
}
void AstCoverOption::dumpJson(std::ostream& str) const {
this->AstNode::dumpJson(str);
str << ", \"optionType\": ";
switch (m_type) {
case VCoverOptionType::WEIGHT: str << "\"weight\""; break;
case VCoverOptionType::GOAL: str << "\"goal\""; break;
case VCoverOptionType::AT_LEAST: str << "\"at_least\""; break;
case VCoverOptionType::AUTO_BIN_MAX: str << "\"auto_bin_max\""; break;
case VCoverOptionType::PER_INSTANCE: str << "\"per_instance\""; break;
case VCoverOptionType::COMMENT: str << "\"comment\""; break;
}
str << ", \"optionType\": \"" << m_type.ascii() << "\"";
}
void AstCoverpointRef::dump(std::ostream& str) const {

View File

@ -544,7 +544,7 @@ class FunctionalCoverageVisitor final : public VNVisitor {
// Note: Coverage database registration happens later via VL_COVER_INSERT
// (see generateCoverageDeclarations() method around line 1164)
// Classes use "v_funccov/" hier prefix vs modules
// Classes use "v_covergroup/" hier prefix vs modules
// Generate bin matching code in sample()
// Handle transition bins specially
@ -1745,15 +1745,15 @@ class FunctionalCoverageVisitor final : public VNVisitor {
}
hierName += "." + binName;
// Generate: VL_COVER_INSERT(contextp, hier, &binVar, "page", "v_funccov/...", ...)
// Generate: VL_COVER_INSERT(contextp, hier, &binVar, "page", "v_covergroup/...", ...)
UINFO(6, " Registering bin: " << hierName << " -> " << varp->name() << endl);
// Build the coverage insert as a C statement
// The variable reference needs to be &this->varname, where varname gets mangled to
// __PVT__varname Use "page" field with v_funccov prefix so type is extracted correctly
// __PVT__varname Use "page" field with v_covergroup prefix so type is extracted correctly
// (consistent with code coverage)
std::string pageName = "v_funccov/" + m_covergroupp->name();
std::string pageName = "v_covergroup/" + m_covergroupp->name();
std::string insertCall = "VL_COVER_INSERT(vlSymsp->_vm_contextp__->coveragep(), ";
insertCall += "\"" + hierName + "\", ";
insertCall += "&(this->__PVT__" + varp->name() + "), ";
@ -1840,6 +1840,16 @@ class FunctionalCoverageVisitor final : public VNVisitor {
iterateChildren(nodep);
processCovergroup();
// Remove lowered coverpoints/crosses from the class - they have been
// fully translated into C++ code and must not reach downstream passes
for (AstCoverpoint* cpp : m_coverpoints) {
cpp->unlinkFrBack();
VL_DO_DANGLING(cpp->deleteTree(), cpp);
}
for (AstCoverCross* crossp : m_coverCrosses) {
crossp->unlinkFrBack();
VL_DO_DANGLING(crossp->deleteTree(), crossp);
}
} else {
iterateChildren(nodep);
}

View File

@ -285,9 +285,7 @@ class DataflowOptimize final {
// TODO: remove once Actives can tolerate NEVER SenItems
if (AstSenItem* senItemp = VN_CAST(nodep, SenItem)) {
senItemp->foreach([](const AstVarRef* refp) {
// Check varScopep exists before accessing (may be null for covergroup
// events)
if (refp->varScopep()) DfgVertexVar::setHasExtRdRefs(refp->varScopep());
DfgVertexVar::setHasExtRdRefs(refp->varScopep());
});
return;
}

View File

@ -1785,20 +1785,6 @@ public:
iterateChildrenConst(nodep);
}
// Functional coverage nodes - not yet implemented, just skip for now
void visit(AstCoverpoint* nodep) override {
// Functional coverage nodes are handled during the coverage transformation pass
// They should not reach the C++ emitter
}
void visit(AstCoverBin* nodep) override {
// Functional coverage nodes are handled during the coverage transformation pass
// They should not reach the C++ emitter
}
void visit(AstCoverCross* nodep) override {
// Functional coverage nodes are handled during the coverage transformation pass
// They should not reach the C++ emitter
}
// Default
void visit(AstNode* nodep) override { // LCOV_EXCL_START
putns(nodep, "\n???? // "s + nodep->prettyTypeName() + "\n");

View File

@ -299,12 +299,6 @@ class CodeMotionAnalysisVisitor final : public VNVisitorConst {
iterateChildrenConst(nodep);
}
// VISITORS
void visit(AstCoverpoint* nodep) override {
// Coverpoints are not statements, so don't analyze their expressions
// They will be handled during code generation
// Just skip them to avoid null pointer access in m_propsp
}
void visit(AstNode* nodep) override {
// Push a new stack entry at the start of a list, but only if the list is not a
// single element (this saves a lot of allocations in expressions)

View File

@ -16,8 +16,8 @@ test.compile(verilator_flags2=['--coverage'])
test.execute()
# Check that coverage database contains functional coverage entries
# Format uses control characters as delimiters: C '^At^Bfunccov^Apage...bin^Blow...h^Bcg.cp.low' count
test.file_grep(test.coverage_filename, r'funccov')
# Format uses control characters as delimiters: C '^At^Bcovergroup^Apage...bin^Blow...h^Bcg.cp.low' count
test.file_grep(test.coverage_filename, r'covergroup')
test.file_grep(test.coverage_filename, r'bin.{0,2}low') # binlow with possible delimiter
test.file_grep(test.coverage_filename, r'bin.{0,2}high') # binhigh with possible delimiter
test.file_grep(test.coverage_filename, r'cg\.cp\.low')

View File

@ -5,10 +5,10 @@
// SPDX-License-Identifier: CC0-1.0
// Test that functional coverage is properly written to coverage database
// Checks that coverage.dat contains funccov entries with correct format
// Checks that coverage.dat contains covergroup entries with correct format
// Expected coverage database entries will contain:
// - Type "funccov"
// - Type "covergroup"
// - Bin names ("low", "high")
// - Hierarchy ("cg.cp.low", "cg.cp.high")