Add function coverage (funccov) and covergroup support
Implement functional coverage collection via covergroups, coverpoints, and cross coverage bins. Introduces V3CoverageFunctional pass and verilated_funccov.h runtime support. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
9f4546fcb9
commit
20970c7dde
|
|
@ -129,9 +129,13 @@ verilator_coverage Arguments
|
|||
.. option:: --filter-type <regex>
|
||||
|
||||
Skips records of coverage types that matches with <regex>
|
||||
Possible values are `toggle`, `line`, `branch`, `expr`, `user` and
|
||||
Possible values are `toggle`, `line`, `branch`, `expr`, `funccov`, `user` and
|
||||
a wildcard with `\*` or `?`. The default value is `\*`.
|
||||
|
||||
The `funccov` type represents SystemVerilog functional coverage including
|
||||
covergroups, coverpoints, bins, and cross coverage as defined in IEEE
|
||||
1800-2023 Section 19.
|
||||
|
||||
.. option:: --help
|
||||
|
||||
Displays a help summary, the program version, and exits.
|
||||
|
|
|
|||
|
|
@ -40,8 +40,10 @@ union, var, void, priority case/if, and unique case/if.
|
|||
|
||||
It also supports .name and .\* interconnection.
|
||||
|
||||
Verilator partially supports concurrent assert and cover statements; see
|
||||
the enclosed coverage tests for the allowed syntax.
|
||||
Verilator partially supports concurrent assert and cover statements, as well as
|
||||
SystemVerilog functional coverage with ``covergroup``, ``coverpoint``, bins,
|
||||
cross coverage, and transition bins. See :ref:`Functional Coverage<user
|
||||
coverage>` for details.
|
||||
|
||||
Verilator has limited support for class and related object-oriented
|
||||
constructs.
|
||||
|
|
@ -363,10 +365,15 @@ appropriate width.
|
|||
Assertions
|
||||
----------
|
||||
|
||||
Verilator is beginning to add support for assertions. Verilator currently
|
||||
only converts assertions to simple ``if (...) error`` statements, and
|
||||
coverage statements to increment the line counters described in the
|
||||
coverage section.
|
||||
Verilator is beginning to add support for 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
|
||||
covergroups for comprehensive coverage analysis.
|
||||
|
||||
Verilator does not support SEREs yet. All assertion and coverage statements
|
||||
must be simple expressions that complete in one cycle.
|
||||
|
|
|
|||
|
|
@ -199,15 +199,421 @@ Functional 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.
|
||||
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.
|
||||
|
||||
For example, the following SystemVerilog statement will add a coverage
|
||||
point under the coverage name "DefaultClock":
|
||||
Simple Coverage Points
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
For simple coverage points, use the ``cover property`` construct:
|
||||
|
||||
.. code-block:: sv
|
||||
|
||||
DefaultClock: cover property (@(posedge clk) cyc==3);
|
||||
|
||||
This adds a coverage point that tracks whether the condition has been observed.
|
||||
|
||||
Covergroups
|
||||
^^^^^^^^^^^
|
||||
|
||||
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.
|
||||
|
||||
**Basic Example:**
|
||||
|
||||
.. code-block:: sv
|
||||
|
||||
module top;
|
||||
logic [7:0] addr;
|
||||
logic cmd;
|
||||
|
||||
// Define a covergroup
|
||||
covergroup cg;
|
||||
cp_addr: coverpoint addr {
|
||||
bins low = {[0:127]};
|
||||
bins high = {[128:255]};
|
||||
}
|
||||
cp_cmd: coverpoint cmd {
|
||||
bins read = {0};
|
||||
bins write = {1};
|
||||
}
|
||||
endgroup
|
||||
|
||||
// Instantiate the covergroup
|
||||
cg cg_inst = new;
|
||||
|
||||
always @(posedge clk) begin
|
||||
// Sample coverage explicitly
|
||||
cg_inst.sample();
|
||||
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.
|
||||
|
||||
Functional Coverage Data Format
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Functional coverage data is stored in the coverage data file (typically
|
||||
:file:`coverage.dat`) using the standard Verilator coverage format. Each
|
||||
functional coverage bin is recorded as a coverage point with:
|
||||
|
||||
* **Type**: ``funccov`` - identifies the record as functional coverage
|
||||
* **Page**: ``v_funccov/<covergroup_name>`` - groups bins by their covergroup
|
||||
* **Hierarchy**: ``<covergroup>.<coverpoint>.<bin>`` for coverpoints, or
|
||||
``<covergroup>.<cross>.<bin>`` for cross coverage
|
||||
* **Count**: Number of times the bin was hit during simulation
|
||||
|
||||
Example coverage.dat entries:
|
||||
|
||||
.. code-block::
|
||||
|
||||
C 'tfunccovpagev_funccov/cgftest.vl28hcg.cp_a.low' 150
|
||||
C 'tfunccovpagev_funccov/cgftest.vl29hcg.cp_a.high' 75
|
||||
C 'tfunccovpagev_funccov/cgftest.vl35hcg.cross_ab.a0_b1' 25
|
||||
|
||||
To filter functional coverage data, use the :option:`--filter-type` option
|
||||
with :command:`verilator_coverage`:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Only process functional coverage
|
||||
$ verilator_coverage --filter-type funccov --annotate report coverage.dat
|
||||
|
||||
# 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:
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,300 @@
|
|||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//=============================================================================
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
// 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-2026 by Wilson Snyder
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
//
|
||||
//=============================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief Verilated functional coverage support header
|
||||
///
|
||||
/// This file provides runtime support for SystemVerilog functional coverage
|
||||
/// constructs (covergroups, coverpoints, bins, cross coverage).
|
||||
///
|
||||
//=============================================================================
|
||||
|
||||
#ifndef VERILATOR_VERILATED_FUNCCOV_H_
|
||||
#define VERILATOR_VERILATED_FUNCCOV_H_
|
||||
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "verilated.h"
|
||||
#include "verilated_cov.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedCoverBin - Represents a single bin in a coverpoint
|
||||
|
||||
class VerilatedCoverBin VL_NOT_FINAL {
|
||||
private:
|
||||
std::string m_name; // Bin name
|
||||
std::string m_rangeStr; // String representation of range (e.g., "0:15")
|
||||
uint32_t m_count = 0; // Hit count
|
||||
uint32_t* m_countp = nullptr; // Pointer to counter (for coverage registration)
|
||||
|
||||
public:
|
||||
VerilatedCoverBin(const std::string& name, const std::string& rangeStr)
|
||||
: m_name{name}
|
||||
, m_rangeStr{rangeStr}
|
||||
, m_countp{&m_count} {}
|
||||
|
||||
virtual ~VerilatedCoverBin() = default;
|
||||
|
||||
// Accessors
|
||||
const std::string& name() const { return m_name; }
|
||||
const std::string& rangeStr() const { return m_rangeStr; }
|
||||
uint32_t count() const { return m_count; }
|
||||
uint32_t* countp() { return m_countp; }
|
||||
|
||||
// Increment hit count
|
||||
void hit() { ++m_count; }
|
||||
|
||||
// Check if value matches this bin (to be overridden by specific bin types)
|
||||
virtual bool matches(uint64_t value) const { return false; }
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedCoverRangeBin - Bin that matches a value range
|
||||
|
||||
class VerilatedCoverRangeBin final : public VerilatedCoverBin {
|
||||
private:
|
||||
uint64_t m_min;
|
||||
uint64_t m_max;
|
||||
|
||||
public:
|
||||
VerilatedCoverRangeBin(const std::string& name, uint64_t min, uint64_t max)
|
||||
: VerilatedCoverBin(name, std::to_string(min) + ":" + std::to_string(max))
|
||||
, m_min{min}
|
||||
, m_max{max} {}
|
||||
|
||||
bool matches(uint64_t value) const override { return value >= m_min && value <= m_max; }
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedCoverpoint - Represents a coverage point
|
||||
|
||||
class VerilatedCoverpoint VL_NOT_FINAL {
|
||||
private:
|
||||
std::string m_name; // Coverpoint name
|
||||
std::vector<VerilatedCoverBin*> m_bins; // Bins in this coverpoint
|
||||
bool m_enabled = true; // Coverage collection enabled
|
||||
|
||||
public:
|
||||
explicit VerilatedCoverpoint(const std::string& name)
|
||||
: m_name{name} {}
|
||||
|
||||
~VerilatedCoverpoint() {
|
||||
for (auto* bin : m_bins) delete bin;
|
||||
}
|
||||
|
||||
// Accessors
|
||||
const std::string& name() const { return m_name; }
|
||||
const std::vector<VerilatedCoverBin*>& bins() const { return m_bins; }
|
||||
bool enabled() const { return m_enabled; }
|
||||
void enabled(bool flag) { m_enabled = flag; }
|
||||
|
||||
// Add a bin to this coverpoint
|
||||
void addBin(VerilatedCoverBin* binp) { m_bins.push_back(binp); }
|
||||
|
||||
// Sample a value and update bin counts
|
||||
void sample(uint64_t value) {
|
||||
if (!m_enabled) return;
|
||||
for (auto* bin : m_bins) {
|
||||
if (bin->matches(value)) { bin->hit(); }
|
||||
}
|
||||
}
|
||||
|
||||
// Compute coverage percentage
|
||||
double getCoverage(uint32_t atLeast = 1) const {
|
||||
if (m_bins.empty()) return 100.0;
|
||||
int coveredBins = 0;
|
||||
for (const auto* bin : m_bins) {
|
||||
if (bin->count() >= atLeast) ++coveredBins;
|
||||
}
|
||||
return (100.0 * coveredBins) / m_bins.size();
|
||||
}
|
||||
|
||||
// Register bins with coverage infrastructure
|
||||
void registerCoverage(VerilatedCovContext* contextp, const std::string& hier,
|
||||
const std::string& cgName) {
|
||||
for (auto* bin : m_bins) {
|
||||
const std::string fullName = cgName + "." + m_name;
|
||||
const std::string& binName = bin->name();
|
||||
const std::string& binRange = bin->rangeStr();
|
||||
VL_COVER_INSERT(contextp, hier.c_str(), bin->countp(), "type", "coverpoint", "name",
|
||||
fullName.c_str(), "bin", binName.c_str(), "range", binRange.c_str());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedCoverCross - Represents cross coverage between coverpoints
|
||||
|
||||
class VerilatedCoverCross VL_NOT_FINAL {
|
||||
private:
|
||||
std::string m_name; // Cross name
|
||||
std::vector<VerilatedCoverpoint*> m_coverpoints; // Coverpoints being crossed
|
||||
std::map<std::string, uint32_t> m_crossBins; // Sparse storage: "<bin1,bin2>" -> count
|
||||
bool m_enabled = true;
|
||||
|
||||
public:
|
||||
explicit VerilatedCoverCross(const std::string& name)
|
||||
: m_name{name} {}
|
||||
|
||||
// Accessors
|
||||
const std::string& name() const { return m_name; }
|
||||
bool enabled() const { return m_enabled; }
|
||||
void enabled(bool flag) { m_enabled = flag; }
|
||||
|
||||
// Add a coverpoint to cross
|
||||
void addCoverpoint(VerilatedCoverpoint* cpp) { m_coverpoints.push_back(cpp); }
|
||||
|
||||
// Sample cross product (to be called after coverpoints are sampled)
|
||||
void sample(const std::vector<uint64_t>& values) {
|
||||
if (!m_enabled || values.size() != m_coverpoints.size()) return;
|
||||
|
||||
// Build cross bin key from matched bins
|
||||
std::string key = "<";
|
||||
bool first = true;
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
// Find which bin matched for this coverpoint
|
||||
for (const auto* bin : m_coverpoints[i]->bins()) {
|
||||
if (bin->matches(values[i])) {
|
||||
if (!first) key += ",";
|
||||
key += bin->name();
|
||||
first = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
key += ">";
|
||||
|
||||
// Increment cross bin count
|
||||
m_crossBins[key]++;
|
||||
}
|
||||
|
||||
// Compute coverage percentage
|
||||
double getCoverage(uint32_t atLeast = 1) const {
|
||||
if (m_crossBins.empty()) return 100.0;
|
||||
int coveredBins = 0;
|
||||
for (const auto& pair : m_crossBins) {
|
||||
if (pair.second >= atLeast) ++coveredBins;
|
||||
}
|
||||
// Total possible bins is product of coverpoint bin counts
|
||||
size_t totalBins = 1;
|
||||
for (const auto* cp : m_coverpoints) { totalBins *= cp->bins().size(); }
|
||||
return (100.0 * coveredBins) / totalBins;
|
||||
}
|
||||
|
||||
// Register cross bins with coverage infrastructure
|
||||
void registerCoverage(VerilatedCovContext* contextp, const std::string& hier,
|
||||
const std::string& cgName) {
|
||||
// Cross bins are registered dynamically as they're hit
|
||||
// For now, we'll register them all upfront (can be optimized later)
|
||||
std::string fullName = cgName + "." + m_name;
|
||||
for (const auto& pair : m_crossBins) {
|
||||
// Note: We need a persistent counter, so we use the map value's address
|
||||
// This is safe because std::map doesn't reallocate on insert
|
||||
const std::string& binName = pair.first;
|
||||
VL_COVER_INSERT(contextp, hier.c_str(), const_cast<uint32_t*>(&pair.second), "type",
|
||||
"cross", "name", fullName.c_str(), "bin", binName.c_str());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedCovergroup - Represents a covergroup instance
|
||||
|
||||
class VerilatedCovergroup VL_NOT_FINAL {
|
||||
private:
|
||||
std::string m_name; // Covergroup type name
|
||||
std::string m_instName; // Instance name
|
||||
std::vector<VerilatedCoverpoint*> m_coverpoints;
|
||||
std::vector<VerilatedCoverCross*> m_crosses;
|
||||
bool m_enabled = true;
|
||||
|
||||
// Coverage options
|
||||
uint32_t m_weight = 1;
|
||||
uint32_t m_goal = 100;
|
||||
uint32_t m_atLeast = 1;
|
||||
std::string m_comment;
|
||||
|
||||
public:
|
||||
explicit VerilatedCovergroup(const std::string& name)
|
||||
: m_name{name}
|
||||
, m_instName{name} {}
|
||||
|
||||
~VerilatedCovergroup() {
|
||||
for (auto* cp : m_coverpoints) delete cp;
|
||||
for (auto* cross : m_crosses) delete cross;
|
||||
}
|
||||
|
||||
// Accessors
|
||||
const std::string& name() const { return m_name; }
|
||||
const std::string& instName() const { return m_instName; }
|
||||
void instName(const std::string& name) { m_instName = name; }
|
||||
bool enabled() const { return m_enabled; }
|
||||
|
||||
// Options
|
||||
void weight(uint32_t w) { m_weight = w; }
|
||||
void goal(uint32_t g) { m_goal = g; }
|
||||
void atLeast(uint32_t a) { m_atLeast = a; }
|
||||
void comment(const std::string& c) { m_comment = c; }
|
||||
|
||||
// Add components
|
||||
void addCoverpoint(VerilatedCoverpoint* cpp) { m_coverpoints.push_back(cpp); }
|
||||
void addCross(VerilatedCoverCross* cross) { m_crosses.push_back(cross); }
|
||||
|
||||
// Predefined methods per IEEE 1800-2023 Section 19.9
|
||||
void sample() {
|
||||
if (!m_enabled) return;
|
||||
// Sampling is done by generated code calling coverpoint sample() methods
|
||||
}
|
||||
|
||||
void start() { m_enabled = true; }
|
||||
void stop() { m_enabled = false; }
|
||||
|
||||
void set_inst_name(const std::string& name) { m_instName = name; }
|
||||
|
||||
// Get type coverage (0-100)
|
||||
double get_coverage() const {
|
||||
if (m_coverpoints.empty()) return 100.0;
|
||||
double totalCov = 0.0;
|
||||
uint32_t totalWeight = 0;
|
||||
for (const auto* cp : m_coverpoints) {
|
||||
totalCov += cp->getCoverage(m_atLeast) * m_weight;
|
||||
totalWeight += m_weight;
|
||||
}
|
||||
for (const auto* cross : m_crosses) {
|
||||
totalCov += cross->getCoverage(m_atLeast) * m_weight;
|
||||
totalWeight += m_weight;
|
||||
}
|
||||
return totalWeight > 0 ? totalCov / totalWeight : 100.0;
|
||||
}
|
||||
|
||||
// Get instance coverage (same as type coverage for now)
|
||||
double get_inst_coverage() const { return get_coverage(); }
|
||||
|
||||
// Register all coverage points with coverage infrastructure
|
||||
void registerCoverage(VerilatedCovContext* contextp, const std::string& hier) {
|
||||
// Register covergroup metadata
|
||||
// (Will be extended when we add metadata output)
|
||||
|
||||
// Register all coverpoints
|
||||
for (auto* cp : m_coverpoints) { cp->registerCoverage(contextp, hier, m_name); }
|
||||
|
||||
// Register all crosses
|
||||
for (auto* cross : m_crosses) { cross->registerCoverage(contextp, hier, m_name); }
|
||||
}
|
||||
};
|
||||
|
||||
#endif // guard
|
||||
|
|
@ -70,6 +70,8 @@ set(HEADERS
|
|||
V3Control.h
|
||||
V3Coverage.h
|
||||
V3CoverageJoin.h
|
||||
V3CoverageFunctional.h
|
||||
V3AstNodeFuncCov.h
|
||||
V3Dead.h
|
||||
V3DebugBisect.h
|
||||
V3Delayed.h
|
||||
|
|
@ -237,6 +239,8 @@ set(COMMON_SOURCES
|
|||
V3Const__gen.cpp
|
||||
V3Coverage.cpp
|
||||
V3CoverageJoin.cpp
|
||||
V3CoverageFunctional.cpp
|
||||
V3AstNodeFuncCov.cpp
|
||||
V3Dead.cpp
|
||||
V3Delayed.cpp
|
||||
V3Depth.cpp
|
||||
|
|
@ -401,7 +405,7 @@ add_custom_command(
|
|||
ARGS
|
||||
${ASTGEN} -I "${srcdir}" --astdef V3AstNodeDType.h --astdef
|
||||
V3AstNodeExpr.h --astdef V3AstNodeOther.h --astdef V3AstNodeStmt.h
|
||||
--dfgdef V3DfgVertices.h --classes
|
||||
--astdef V3AstNodeFuncCov.h --dfgdef V3DfgVertices.h --classes
|
||||
)
|
||||
list(
|
||||
APPEND GENERATED_FILES
|
||||
|
|
@ -513,7 +517,8 @@ foreach(astgen_name ${ASTGENERATED_NAMES})
|
|||
ARGS
|
||||
${ASTGEN} -I "${srcdir}" --astdef V3AstNodeDType.h --astdef
|
||||
V3AstNodeExpr.h --astdef V3AstNodeOther.h --astdef V3AstNodeStmt.h
|
||||
--dfgdef V3DfgVertices.h ${astgen_name}.cpp
|
||||
--astdef V3AstNodeFuncCov.h --dfgdef V3DfgVertices.h
|
||||
${astgen_name}.cpp
|
||||
)
|
||||
list(APPEND GENERATED_FILES ${astgen_name}__gen.cpp)
|
||||
endforeach()
|
||||
|
|
|
|||
|
|
@ -207,6 +207,7 @@ RAW_OBJS = \
|
|||
|
||||
RAW_OBJS_PCH_ASTMT = \
|
||||
V3Ast.o \
|
||||
V3AstNodeFuncCov.o \
|
||||
V3AstNodes.o \
|
||||
V3Broken.o \
|
||||
V3Control.o \
|
||||
|
|
@ -249,6 +250,7 @@ RAW_OBJS_PCH_ASTNOMT = \
|
|||
V3Combine.o \
|
||||
V3Common.o \
|
||||
V3Coverage.o \
|
||||
V3CoverageFunctional.o \
|
||||
V3CoverageJoin.o \
|
||||
V3Dead.o \
|
||||
V3Delayed.o \
|
||||
|
|
@ -360,6 +362,7 @@ NON_STANDALONE_HEADERS = \
|
|||
V3AstInlines.h \
|
||||
V3AstNodeDType.h \
|
||||
V3AstNodeExpr.h \
|
||||
V3AstNodeFuncCov.h \
|
||||
V3AstNodeOther.h \
|
||||
V3AstNodeStmt.h \
|
||||
V3DebugBisect.h \
|
||||
|
|
@ -370,6 +373,7 @@ NON_STANDALONE_HEADERS = \
|
|||
AST_DEFS := \
|
||||
V3AstNodeDType.h \
|
||||
V3AstNodeExpr.h \
|
||||
V3AstNodeFuncCov.h \
|
||||
V3AstNodeOther.h \
|
||||
V3AstNodeStmt.h \
|
||||
|
||||
|
|
|
|||
226
src/V3Active.cpp
226
src/V3Active.cpp
|
|
@ -619,11 +619,237 @@ public:
|
|||
~ActiveVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Automatic covergroup sampling visitor
|
||||
// This runs after ActiveVisitor to add automatic sample() calls for covergroups
|
||||
// declared with sensitivity events (e.g., covergroup cg @(posedge clk);)
|
||||
|
||||
class CovergroupSamplingVisitor final : public VNVisitor {
|
||||
// STATE
|
||||
ActiveNamer m_namer; // Reuse active naming infrastructure
|
||||
AstScope* m_scopep = nullptr; // Current scope
|
||||
bool m_inFirstPass = true; // First pass collects CFuncs, second pass adds sampling
|
||||
std::unordered_map<const AstClass*, AstCFunc*>
|
||||
m_covergroupSampleFuncs; // Class -> sample CFunc
|
||||
|
||||
// Helper to get the clocking event from a covergroup class
|
||||
AstSenTree* getCovergroupEvent(AstClass* classp) {
|
||||
// The AstCovergroup (holding the SenTree) was left in membersp by V3CoverageFunctional
|
||||
for (AstNode* memberp = classp->membersp(); memberp; memberp = memberp->nextp()) {
|
||||
if (AstCovergroup* const cgp = VN_CAST(memberp, Covergroup)) {
|
||||
if (cgp->eventp()) return cgp->eventp();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
void visit(AstScope* nodep) override {
|
||||
m_scopep = nodep;
|
||||
m_namer.main(nodep); // Initialize active naming for this scope
|
||||
|
||||
// First pass: collect sample CFuncs from covergroup class scopes
|
||||
if (m_inFirstPass) {
|
||||
// Check if this is a covergroup class scope (contains sample CFunc)
|
||||
for (AstNode* itemp = m_scopep->blocksp(); itemp; itemp = itemp->nextp()) {
|
||||
if (AstCFunc* const cfuncp = VN_CAST(itemp, CFunc)) {
|
||||
if (cfuncp->name().find("sample") != string::npos) {
|
||||
// This is a covergroup class scope - find the class and store the CFunc
|
||||
// The scope name is like "TOP.t__03a__03acg", extract class name
|
||||
string scopeName = nodep->name();
|
||||
size_t dotPos = scopeName.find('.');
|
||||
if (dotPos != string::npos) {
|
||||
string className = scopeName.substr(dotPos + 1);
|
||||
// Search netlist for the matching covergroup class
|
||||
for (AstNode* modp = v3Global.rootp()->modulesp(); modp;
|
||||
modp = modp->nextp()) {
|
||||
if (AstClass* const classp = VN_CAST(modp, Class)) {
|
||||
if (classp->isCovergroup() && classp->name() == className) {
|
||||
m_covergroupSampleFuncs[classp] = cfuncp;
|
||||
cfuncp->isCovergroupSample(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
iterateChildren(nodep);
|
||||
m_scopep = nullptr;
|
||||
}
|
||||
|
||||
void visit(AstVarScope* nodep) override {
|
||||
// Only process VarScopes in the second pass
|
||||
if (m_inFirstPass) return;
|
||||
|
||||
// Get the underlying var
|
||||
AstVar* const varp = nodep->varp();
|
||||
if (!varp) return;
|
||||
|
||||
// Check if the variable is of covergroup class type
|
||||
const AstNodeDType* const dtypep = varp->dtypep();
|
||||
if (!dtypep) return;
|
||||
|
||||
const AstClassRefDType* const classRefp = VN_CAST(dtypep, ClassRefDType);
|
||||
if (!classRefp) return;
|
||||
|
||||
AstClass* const classp = classRefp->classp();
|
||||
if (!classp || !classp->isCovergroup()) return;
|
||||
|
||||
// Check if this covergroup has an automatic sampling event
|
||||
AstSenTree* const eventp = getCovergroupEvent(classp);
|
||||
if (!eventp) return; // No automatic sampling for this covergroup
|
||||
|
||||
// Get the sample CFunc - we need to find it in the class scope
|
||||
// The class scope name is like "TOP.t__03a__03acg" for class "t__03a__03acg"
|
||||
const string classScopeName = string("TOP.") + classp->name();
|
||||
|
||||
AstCFunc* sampleCFuncp = nullptr;
|
||||
// Search through all scopes to find the class scope and its sample CFunc
|
||||
for (AstNode* scopeNode = m_scopep; scopeNode; scopeNode = scopeNode->backp()) {
|
||||
if (AstNetlist* netlistp = VN_CAST(scopeNode, Netlist)) {
|
||||
// Found netlist, search its modules for scopes
|
||||
for (AstNode* modp = netlistp->modulesp(); modp; modp = modp->nextp()) {
|
||||
if (AstScope* scopep = VN_CAST(modp, Scope)) {
|
||||
if (scopep->name() == classScopeName) {
|
||||
// Found the class scope, now find the sample CFunc
|
||||
for (AstNode* itemp = scopep->blocksp(); itemp;
|
||||
itemp = itemp->nextp()) {
|
||||
if (AstCFunc* cfuncp = VN_CAST(itemp, CFunc)) {
|
||||
if (cfuncp->name().find("sample") != string::npos) {
|
||||
sampleCFuncp = cfuncp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!sampleCFuncp) {
|
||||
// Fallback: try the cached version
|
||||
auto it = m_covergroupSampleFuncs.find(classp);
|
||||
if (it != m_covergroupSampleFuncs.end()) { sampleCFuncp = it->second; }
|
||||
}
|
||||
|
||||
if (!sampleCFuncp) {
|
||||
UINFO(4, "Could not find sample() CFunc for covergroup " << classp->name() << endl);
|
||||
return; // CFunc not found
|
||||
}
|
||||
UASSERT_OBJ(sampleCFuncp, nodep, "Sample CFunc is null for covergroup");
|
||||
|
||||
// Create a VarRef to the covergroup instance for the method call
|
||||
FileLine* const fl = nodep->fileline();
|
||||
AstVarRef* const varrefp = new AstVarRef{fl, nodep, VAccess::READ};
|
||||
|
||||
// Create the CMethodCall to sample()
|
||||
// Note: We don't pass arguments in argsp since vlSymsp is passed via argTypes
|
||||
AstCMethodCall* const cmethodCallp
|
||||
= new AstCMethodCall{fl, varrefp, sampleCFuncp, nullptr};
|
||||
|
||||
// Set dtype to void since sample() doesn't return a value
|
||||
cmethodCallp->dtypeSetVoid();
|
||||
|
||||
// Set argTypes to "vlSymsp" so the emit code will pass it automatically
|
||||
cmethodCallp->argTypes("vlSymsp");
|
||||
|
||||
// Clone the sensitivity for this active block
|
||||
// Each VarRef in the sensitivity needs to be updated for the current scope
|
||||
AstSenTree* senTreep = eventp->cloneTree(false);
|
||||
|
||||
// Fix up VarRefs in the cloned sensitivity - they need varScopep set
|
||||
senTreep->foreach([this](AstVarRef* refp) {
|
||||
if (!refp->varScopep() && refp->varp()) {
|
||||
// Find the VarScope for this Var in the current scope
|
||||
AstVarScope* vscp = nullptr;
|
||||
for (AstNode* itemp = m_scopep->varsp(); itemp; itemp = itemp->nextp()) {
|
||||
if (AstVarScope* const vsp = VN_CAST(itemp, VarScope)) {
|
||||
if (vsp->varp() == refp->varp()) {
|
||||
vscp = vsp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (vscp) {
|
||||
refp->varScopep(vscp);
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Get or create the AstActive node for this sensitivity
|
||||
// senTreep is a template used by getActive() which clones it into the AstActive;
|
||||
// delete it afterwards as it is not added to the AST directly.
|
||||
AstActive* const activep = m_namer.getActive(fl, senTreep);
|
||||
VL_DO_DANGLING(senTreep->deleteTree(), senTreep);
|
||||
|
||||
// Add the CMethodCall statement to the active domain
|
||||
activep->addStmtsp(cmethodCallp->makeStmt());
|
||||
|
||||
UINFO(4, " Added automatic sample() call for covergroup " << varp->name() << endl);
|
||||
}
|
||||
|
||||
void visit(AstActive*) override {} // Don't iterate into actives
|
||||
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit CovergroupSamplingVisitor(AstNetlist* nodep) {
|
||||
// NOTE: Automatic sampling now works with --timing
|
||||
// Previously disabled due to compatibility issues with V3Timing transformations
|
||||
// The current implementation injects sampling before V3Active, allowing both modes to work
|
||||
|
||||
UINFO(4, "CovergroupSamplingVisitor: Starting" << endl);
|
||||
|
||||
// First pass: collect sample CFuncs from covergroup class scopes
|
||||
m_inFirstPass = true;
|
||||
iterate(nodep);
|
||||
|
||||
// Second pass: add automatic sampling to covergroup instances
|
||||
m_inFirstPass = false;
|
||||
iterate(nodep);
|
||||
|
||||
UINFO(4, "CovergroupSamplingVisitor: Complete" << endl);
|
||||
}
|
||||
~CovergroupSamplingVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Active class functions
|
||||
|
||||
void V3Active::activeAll(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ":");
|
||||
{ ActiveVisitor{nodep}; } // Destruct before checking
|
||||
{ CovergroupSamplingVisitor{nodep}; } // Add automatic covergroup sampling
|
||||
// Delete AstCovergroup nodes (event holders) left in covergroup classes by
|
||||
// V3CoverageFunctional. They were kept in the AST to avoid orphaned SenTree nodes;
|
||||
// now that V3Active has consumed them we can delete them.
|
||||
for (AstNode* modp = nodep->modulesp(); modp; modp = modp->nextp()) {
|
||||
if (AstClass* const classp = VN_CAST(modp, Class)) {
|
||||
if (!classp->isCovergroup()) continue;
|
||||
for (AstNode* memberp = classp->membersp(); memberp;) {
|
||||
AstNode* const nextp = memberp->nextp();
|
||||
if (AstCovergroup* const cgp = VN_CAST(memberp, Covergroup)) {
|
||||
cgp->unlinkFrBack();
|
||||
VL_DO_DANGLING(cgp->deleteTree(), cgp);
|
||||
}
|
||||
memberp = nextp;
|
||||
}
|
||||
}
|
||||
}
|
||||
V3Global::dumpCheckGlobalTree("active", 0, dumpTreeEitherLevel() >= 3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1583,6 +1583,7 @@ AstNode* VNVisitor::iterateSubtreeReturnEdits(AstNode* nodep) {
|
|||
#include "V3AstNodeOther.h"
|
||||
#include "V3AstNodeExpr.h"
|
||||
#include "V3AstNodeStmt.h"
|
||||
#include "V3AstNodeFuncCov.h"
|
||||
// clang-format on
|
||||
|
||||
// Inline function definitions need to go last
|
||||
|
|
|
|||
|
|
@ -0,0 +1,155 @@
|
|||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: AstNode implementation for functional coverage nodes
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// 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-2026 by Wilson Snyder
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "V3PchAstMT.h"
|
||||
|
||||
#include "V3AstNodeFuncCov.h"
|
||||
|
||||
//######################################################################
|
||||
// Dump methods
|
||||
|
||||
void AstCovergroup::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
str << " " << m_name;
|
||||
if (m_isClass) str << " [class]";
|
||||
}
|
||||
|
||||
void AstCovergroup::dumpJson(std::ostream& str) const {
|
||||
this->AstNode::dumpJson(str);
|
||||
str << ", \"name\": " << VString::quotePercent(name());
|
||||
if (m_isClass) str << ", \"isClass\": true";
|
||||
}
|
||||
|
||||
void AstCoverpoint::dump(std::ostream& str) const { this->AstNodeFuncCovItem::dump(str); }
|
||||
|
||||
void AstCoverpoint::dumpJson(std::ostream& str) const { this->AstNodeFuncCovItem::dumpJson(str); }
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AstCoverTransSet::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
str << " trans_set";
|
||||
}
|
||||
|
||||
void AstCoverTransSet::dumpJson(std::ostream& str) const { this->AstNode::dumpJson(str); }
|
||||
|
||||
void AstCoverCross::dump(std::ostream& str) const { this->AstNodeFuncCovItem::dump(str); }
|
||||
|
||||
void AstCoverCross::dumpJson(std::ostream& str) const { this->AstNodeFuncCovItem::dumpJson(str); }
|
||||
|
||||
void AstCoverCrossBins::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
str << " " << m_name;
|
||||
}
|
||||
|
||||
void AstCoverCrossBins::dumpJson(std::ostream& str) const {
|
||||
this->AstNode::dumpJson(str);
|
||||
str << ", \"name\": " << VString::quotePercent(m_name);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
void AstCoverpointRef::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
str << " " << m_name;
|
||||
}
|
||||
|
||||
void AstCoverpointRef::dumpJson(std::ostream& str) const {
|
||||
this->AstNode::dumpJson(str);
|
||||
str << ", \"name\": " << VString::quotePercent(m_name);
|
||||
}
|
||||
|
||||
void AstCoverSelectExpr::dump(std::ostream& str) const { this->AstNode::dump(str); }
|
||||
|
||||
void AstCoverSelectExpr::dumpJson(std::ostream& str) const { this->AstNode::dumpJson(str); }
|
||||
|
|
@ -0,0 +1,289 @@
|
|||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: AstNode sub-types for functional coverage
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// 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-2026 by Wilson Snyder
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// This file contains AST nodes for SystemVerilog functional coverage
|
||||
// (IEEE 1800-2023 Section 19)
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef VERILATOR_V3ASTNODEFUNCCOV_H_
|
||||
#define VERILATOR_V3ASTNODEFUNCCOV_H_
|
||||
|
||||
#ifndef VERILATOR_V3AST_H_
|
||||
#error "Use V3Ast.h as the include"
|
||||
#include "V3Ast.h"
|
||||
#define VL_NOT_FINAL
|
||||
#endif
|
||||
|
||||
//######################################################################
|
||||
// Enumerations
|
||||
|
||||
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 [=]
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Base classes
|
||||
|
||||
class AstNodeFuncCovItem VL_NOT_FINAL : public AstNode {
|
||||
protected:
|
||||
string m_name;
|
||||
|
||||
public:
|
||||
AstNodeFuncCovItem(VNType t, FileLine* fl, const string& name)
|
||||
: AstNode{t, fl}
|
||||
, m_name{name} {}
|
||||
ASTGEN_MEMBERS_AstNodeFuncCovItem;
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
void name(const string& flag) override { m_name = flag; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Concrete nodes - ORDER MATTERS FOR ASTGEN!
|
||||
// Must be in order: CoverBin, CoverCrossBins, CoverOption, CoverSelectExpr,
|
||||
// CoverTransItem, CoverTransSet, Covergroup, CoverpointRef, CoverCross,
|
||||
// Coverpoint
|
||||
|
||||
// Forward declarations for types used in constructors
|
||||
class AstCoverTransSet;
|
||||
class AstCoverSelectExpr;
|
||||
|
||||
class AstCoverBin final : public AstNode {
|
||||
// @astgen op1 := rangesp : List[AstNode]
|
||||
// @astgen op2 := iffp : Optional[AstNodeExpr]
|
||||
// @astgen op3 := arraySizep : Optional[AstNodeExpr]
|
||||
// @astgen op4 := transp : List[AstCoverTransSet]
|
||||
string m_name;
|
||||
VCoverBinsType m_type;
|
||||
bool m_isArray = false;
|
||||
|
||||
public:
|
||||
AstCoverBin(FileLine* fl, const string& name, AstNode* rangesp, bool isIgnore, bool isIllegal,
|
||||
bool isWildcard = false)
|
||||
: ASTGEN_SUPER_CoverBin(fl)
|
||||
, m_name{name}
|
||||
, m_type{isWildcard ? VCoverBinsType::BINS_WILDCARD
|
||||
: (isIllegal ? VCoverBinsType::BINS_ILLEGAL
|
||||
: (isIgnore ? VCoverBinsType::BINS_IGNORE
|
||||
: VCoverBinsType::USER))} {
|
||||
if (rangesp) addRangesp(rangesp);
|
||||
}
|
||||
// Constructor for automatic bins
|
||||
AstCoverBin(FileLine* fl, const string& name, AstNodeExpr* arraySizep)
|
||||
: ASTGEN_SUPER_CoverBin(fl)
|
||||
, m_name{name}
|
||||
, m_type{VCoverBinsType::AUTO}
|
||||
, m_isArray{true} {
|
||||
this->arraySizep(arraySizep);
|
||||
}
|
||||
// Constructor for default bins (catch-all)
|
||||
AstCoverBin(FileLine* fl, const string& name, VCoverBinsType type)
|
||||
: ASTGEN_SUPER_CoverBin(fl)
|
||||
, m_name{name}
|
||||
, m_type{type} {
|
||||
// DEFAULT bins have no ranges - they catch everything not in other bins
|
||||
}
|
||||
// Constructor for transition bins
|
||||
AstCoverBin(FileLine* fl, const string& name, AstCoverTransSet* transp, bool isIgnore,
|
||||
bool isIllegal, bool isArrayBin = false)
|
||||
: ASTGEN_SUPER_CoverBin(fl)
|
||||
, m_name{name}
|
||||
, m_type{isIllegal ? VCoverBinsType::BINS_ILLEGAL
|
||||
: (isIgnore ? VCoverBinsType::BINS_IGNORE : VCoverBinsType::TRANSITION)}
|
||||
, m_isArray{isArrayBin} {
|
||||
if (transp) addTransp(transp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCoverBin;
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
VCoverBinsType binsType() const { return m_type; }
|
||||
bool isArray() const { return m_isArray; }
|
||||
void isArray(bool flag) { m_isArray = flag; }
|
||||
};
|
||||
|
||||
class AstCoverCrossBins final : public AstNode {
|
||||
// @astgen op1 := selectp : Optional[AstCoverSelectExpr]
|
||||
string m_name;
|
||||
|
||||
public:
|
||||
AstCoverCrossBins(FileLine* fl, const string& name, AstCoverSelectExpr* selectp)
|
||||
: ASTGEN_SUPER_CoverCrossBins(fl)
|
||||
, m_name{name} {
|
||||
this->selectp(selectp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCoverCrossBins;
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
};
|
||||
|
||||
class AstCoverOption final : public AstNode {
|
||||
// @astgen op1 := valuep : AstNodeExpr
|
||||
VCoverOptionType m_type;
|
||||
|
||||
public:
|
||||
AstCoverOption(FileLine* fl, VCoverOptionType type, AstNodeExpr* valuep)
|
||||
: ASTGEN_SUPER_CoverOption(fl)
|
||||
, m_type{type} {
|
||||
this->valuep(valuep);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCoverOption;
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
VCoverOptionType optionType() const { return m_type; }
|
||||
};
|
||||
|
||||
class AstCoverSelectExpr final : public AstNode {
|
||||
// @astgen op1 := exprp : AstNodeExpr
|
||||
public:
|
||||
AstCoverSelectExpr(FileLine* fl, AstNodeExpr* exprp)
|
||||
: ASTGEN_SUPER_CoverSelectExpr(fl) {
|
||||
this->exprp(exprp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCoverSelectExpr;
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
};
|
||||
|
||||
// Represents a single transition item: value or value[*N] or value[->N] or value[=N]
|
||||
class AstCoverTransItem final : public AstNode {
|
||||
// @astgen op1 := valuesp : List[AstNode] // Range list (values or ranges)
|
||||
// @astgen op2 := repMinp : Optional[AstNodeExpr] // Repetition min count (for [*], [->], [=])
|
||||
// @astgen op3 := repMaxp : Optional[AstNodeExpr] // Repetition max count (for ranges)
|
||||
VTransRepType m_repType;
|
||||
|
||||
public:
|
||||
AstCoverTransItem(FileLine* fl, AstNode* valuesp, VTransRepType repType = VTransRepType::NONE)
|
||||
: ASTGEN_SUPER_CoverTransItem(fl)
|
||||
, m_repType{repType} {
|
||||
if (valuesp) addValuesp(valuesp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCoverTransItem;
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
VTransRepType repType() const { return m_repType; }
|
||||
};
|
||||
|
||||
// Represents a transition set: value1 => value2 => value3
|
||||
class AstCoverTransSet final : public AstNode {
|
||||
// @astgen op1 := itemsp : List[AstCoverTransItem]
|
||||
public:
|
||||
AstCoverTransSet(FileLine* fl, AstCoverTransItem* itemsp)
|
||||
: ASTGEN_SUPER_CoverTransSet(fl) {
|
||||
if (itemsp) addItemsp(itemsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCoverTransSet;
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
};
|
||||
|
||||
class AstCovergroup final : public AstNode {
|
||||
// @astgen op1 := argsp : List[AstVar]
|
||||
// @astgen op2 := membersp : List[AstNode]
|
||||
// @astgen op3 := eventp : Optional[AstSenTree]
|
||||
string m_name;
|
||||
bool m_isClass = false;
|
||||
|
||||
public:
|
||||
AstCovergroup(FileLine* fl, const string& name, AstNode* membersp, AstSenTree* eventp)
|
||||
: ASTGEN_SUPER_Covergroup(fl)
|
||||
, m_name{name} {
|
||||
if (membersp) addMembersp(membersp);
|
||||
this->eventp(eventp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCovergroup;
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
void name(const string& name) override { m_name = name; }
|
||||
bool isClass() const { return m_isClass; }
|
||||
void isClass(bool flag) { m_isClass = flag; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
};
|
||||
|
||||
class AstCoverpointRef final : public AstNode {
|
||||
// @astgen ptr := m_coverpointp : Optional[AstCoverpoint]
|
||||
string m_name;
|
||||
|
||||
public:
|
||||
AstCoverpointRef(FileLine* fl, const string& name)
|
||||
: ASTGEN_SUPER_CoverpointRef(fl)
|
||||
, m_name{name} {}
|
||||
ASTGEN_MEMBERS_AstCoverpointRef;
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
AstCoverpoint* coverpointp() const { return m_coverpointp; }
|
||||
void coverpointp(AstCoverpoint* nodep) { m_coverpointp = nodep; }
|
||||
};
|
||||
|
||||
class AstCoverCross final : public AstNodeFuncCovItem {
|
||||
// @astgen op1 := itemsp : List[AstCoverpointRef]
|
||||
// @astgen op2 := binsp : List[AstCoverCrossBins]
|
||||
// @astgen op3 := optionsp : List[AstCoverOption]
|
||||
public:
|
||||
AstCoverCross(FileLine* fl, const string& name, AstCoverpointRef* itemsp)
|
||||
: ASTGEN_SUPER_CoverCross(fl, name) {
|
||||
if (itemsp) addItemsp(itemsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCoverCross;
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
};
|
||||
|
||||
class AstCoverpoint final : public AstNodeFuncCovItem {
|
||||
// @astgen op1 := exprp : AstNodeExpr
|
||||
// @astgen op2 := binsp : List[AstCoverBin]
|
||||
// @astgen op3 := iffp : Optional[AstNodeExpr]
|
||||
// @astgen op4 := optionsp : List[AstCoverOption]
|
||||
public:
|
||||
AstCoverpoint(FileLine* fl, const string& name, AstNodeExpr* exprp)
|
||||
: ASTGEN_SUPER_Coverpoint(fl, name) {
|
||||
this->exprp(exprp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCoverpoint;
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
#endif // Guard
|
||||
|
|
@ -513,6 +513,7 @@ class AstCFunc final : public AstNode {
|
|||
bool m_recursive : 1; // Recursive or part of recursion
|
||||
bool m_noLife : 1; // Disable V3Life on this function - has multiple calls, and reads Syms
|
||||
// state
|
||||
bool m_isCovergroupSample : 1; // Automatic covergroup sample() function
|
||||
int m_cost; // Function call cost
|
||||
public:
|
||||
AstCFunc(FileLine* fl, const string& name, AstScope* scopep, const string& rtnType = "")
|
||||
|
|
@ -543,6 +544,7 @@ public:
|
|||
m_dpiImportWrapper = false;
|
||||
m_recursive = false;
|
||||
m_noLife = false;
|
||||
m_isCovergroupSample = false;
|
||||
m_cost = v3Global.opt.instrCountDpi(); // As proxy for unknown general DPI cost
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCFunc;
|
||||
|
|
@ -618,6 +620,8 @@ public:
|
|||
bool recursive() const { return m_recursive; }
|
||||
void noLife(bool flag) { m_noLife = flag; }
|
||||
bool noLife() const { return m_noLife; }
|
||||
bool isCovergroupSample() const { return m_isCovergroupSample; }
|
||||
void isCovergroupSample(bool flag) { m_isCovergroupSample = flag; }
|
||||
void cost(int cost) { m_cost = cost; }
|
||||
// Special methods
|
||||
bool emptyBody() const {
|
||||
|
|
@ -2617,6 +2621,8 @@ class AstClass final : public AstNodeModule {
|
|||
bool m_needRNG = false; // Need RNG, uses srandom/randomize
|
||||
bool m_useVirtualPublic = false; // Subclasses need virtual public as uses interface class
|
||||
bool m_virtual = false; // Virtual class
|
||||
// Covergroup options (when m_covergroup is true)
|
||||
int m_cgAutoBinMax = -1; // option.auto_bin_max value (-1 = not set, use default 64)
|
||||
|
||||
public:
|
||||
AstClass(FileLine* fl, const string& name, const string& libname)
|
||||
|
|
@ -2644,6 +2650,9 @@ public:
|
|||
void needRNG(bool flag) { m_needRNG = flag; }
|
||||
bool useVirtualPublic() const { return m_useVirtualPublic; }
|
||||
void useVirtualPublic(bool flag) { m_useVirtualPublic = flag; }
|
||||
// Covergroup options accessors
|
||||
int cgAutoBinMax() const { return m_cgAutoBinMax; }
|
||||
void cgAutoBinMax(int value) { m_cgAutoBinMax = value; }
|
||||
// Return true if this class is an extension of base class (SLOW)
|
||||
// Accepts nullptrs
|
||||
static bool isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp);
|
||||
|
|
|
|||
|
|
@ -3259,6 +3259,7 @@ void AstCoverToggleDecl::dumpJson(std::ostream& str) const {
|
|||
std::to_string(range().left()) + ":" + std::to_string(range().right()));
|
||||
}
|
||||
}
|
||||
// NOTE: AstCoverBin and AstCoverpoint dump methods removed - moved to V3AstNodeFuncCov.cpp
|
||||
void AstCoverInc::dump(std::ostream& str) const {
|
||||
this->AstNodeStmt::dump(str);
|
||||
str << " -> ";
|
||||
|
|
|
|||
|
|
@ -797,7 +797,6 @@ class CoverageVisitor final : public VNVisitor {
|
|||
pair.first->second = varp;
|
||||
if (m_ftaskp) {
|
||||
varp->funcLocal(true);
|
||||
varp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
|
||||
m_ftaskp->stmtsp()->addHereThisAsNext(varp);
|
||||
} else {
|
||||
m_modp->stmtsp()->addHereThisAsNext(varp);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,30 @@
|
|||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Functional coverage implementation
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// 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: 2003-2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef VERILATOR_V3COVERAGEFUNCTIONAL_H_
|
||||
#define VERILATOR_V3COVERAGEFUNCTIONAL_H_
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Error.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3CoverageFunctional final {
|
||||
public:
|
||||
static void coverageFunctional(AstNetlist* nodep);
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
|
@ -282,6 +282,15 @@ class DataflowOptimize final {
|
|||
if (hasExtWr) DfgVertexVar::setHasExtWrRefs(vscp);
|
||||
return;
|
||||
}
|
||||
// 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());
|
||||
});
|
||||
return;
|
||||
}
|
||||
// Check direct references
|
||||
if (const AstVarRef* const refp = VN_CAST(nodep, VarRef)) {
|
||||
if (refp->access().isRW()) DfgVertexVar::setHasRWRefs(refp->varScopep());
|
||||
|
|
|
|||
|
|
@ -1785,6 +1785,20 @@ 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");
|
||||
|
|
|
|||
|
|
@ -227,6 +227,12 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
|
|||
iterateAndNextConstNull(nodep->rhsp());
|
||||
if (!m_suppressSemi) puts(";\n");
|
||||
}
|
||||
void visit(AstAssignDly* nodep) override {
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
putfs(nodep, " <= ");
|
||||
iterateAndNextConstNull(nodep->rhsp());
|
||||
puts(";\n");
|
||||
}
|
||||
void visit(AstAlias* nodep) override {
|
||||
putbs("alias ");
|
||||
iterateConst(nodep->itemsp());
|
||||
|
|
|
|||
|
|
@ -309,7 +309,6 @@ class LinkIncVisitor final : public VNVisitor {
|
|||
AstVar* const varp = new AstVar{
|
||||
fl, VVarType::BLOCKTEMP, name, VFlagChildDType{},
|
||||
new AstRefDType{fl, AstRefDType::FlagTypeOfExpr{}, readp->cloneTree(true)}};
|
||||
varp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
|
||||
if (m_ftaskp) varp->funcLocal(true);
|
||||
|
||||
// Declare the variable
|
||||
|
|
|
|||
|
|
@ -250,6 +250,10 @@ class CodeMotionAnalysisVisitor final : public VNVisitorConst {
|
|||
void analyzeVarRef(AstVarRef* nodep) {
|
||||
const VAccess access = nodep->access();
|
||||
AstVar* const varp = nodep->varp();
|
||||
// Add null check - varp can be null in some contexts (e.g., SenTree VarRefs)
|
||||
if (!varp) return;
|
||||
// Skip if not in a statement context (m_propsp can be null)
|
||||
if (!m_propsp) return;
|
||||
// Gather read and written variables
|
||||
if (access.isReadOrRW()) m_propsp->m_rdVars.insert(varp);
|
||||
if (access.isWriteOrRW()) m_propsp->m_wrVars.insert(varp);
|
||||
|
|
@ -296,6 +300,11 @@ class CodeMotionAnalysisVisitor final : public VNVisitorConst {
|
|||
}
|
||||
|
||||
// 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)
|
||||
|
|
|
|||
|
|
@ -331,6 +331,16 @@ class OrderGraphBuilder final : public VNVisitor {
|
|||
void visit(AstCoverToggle* nodep) override { //
|
||||
iterateLogic(nodep);
|
||||
}
|
||||
void visit(AstStmtExpr* nodep) override {
|
||||
// StmtExpr wraps expressions used as statements (e.g., method calls).
|
||||
// If it's under an AstActive but not already in a logic context, treat it as logic.
|
||||
// Otherwise just iterate normally.
|
||||
if (!m_logicVxp && m_domainp) {
|
||||
iterateLogic(nodep);
|
||||
} else {
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
}
|
||||
|
||||
//--- Ignored nodes
|
||||
void visit(AstVar*) override {}
|
||||
|
|
|
|||
|
|
@ -15,11 +15,13 @@
|
|||
//*************************************************************************
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Const.h"
|
||||
#include "V3Control.h"
|
||||
#include "V3Global.h"
|
||||
#include "V3ParseImp.h" // Defines YYTYPE; before including bison header
|
||||
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
class V3ParseGrammar final {
|
||||
public:
|
||||
|
|
@ -94,13 +96,57 @@ public:
|
|||
nodep->trace(singletonp()->allTracingOn(fileline));
|
||||
return nodep;
|
||||
}
|
||||
void createCoverGroupMethods(AstClass* nodep, AstNode* sampleArgs) {
|
||||
void createCoverGroupMethods(AstClass* nodep, AstNode* constructorArgs, AstNode* sampleArgs) {
|
||||
// Hidden static to take unspecified reference argument results
|
||||
AstVar* const defaultVarp
|
||||
= new AstVar{nodep->fileline(), VVarType::MEMBER, "__Vint", nodep->findIntDType()};
|
||||
defaultVarp->lifetime(VLifetime::STATIC_EXPLICIT);
|
||||
nodep->addStmtsp(defaultVarp);
|
||||
|
||||
// Handle constructor arguments - add function parameters and assignments
|
||||
// Member variables have already been created in verilog.y
|
||||
if (constructorArgs) {
|
||||
// Find the 'new' function to add parameters to
|
||||
AstFunc* newFuncp = nullptr;
|
||||
for (AstNode* memberp = nodep->membersp(); memberp; memberp = memberp->nextp()) {
|
||||
if (AstFunc* funcp = VN_CAST(memberp, Func)) {
|
||||
if (funcp->name() == "new") {
|
||||
newFuncp = funcp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newFuncp) {
|
||||
// Save the existing body statements and unlink them
|
||||
AstNode* const existingBodyp = newFuncp->stmtsp();
|
||||
if (existingBodyp) existingBodyp->unlinkFrBackWithNext();
|
||||
|
||||
// Add function parameters and assignments
|
||||
AstNode* nextArgp = nullptr;
|
||||
for (AstNode* argp = constructorArgs; argp; argp = nextArgp) {
|
||||
nextArgp = argp->nextp(); // Save next before any modifications
|
||||
if (AstVar* const origVarp = VN_CAST(argp, Var)) {
|
||||
// Create a constructor parameter
|
||||
AstVar* const paramp = origVarp->cloneTree(false);
|
||||
paramp->funcLocal(true);
|
||||
paramp->direction(VDirection::INPUT);
|
||||
newFuncp->addStmtsp(paramp);
|
||||
|
||||
// Create assignment: member = parameter
|
||||
AstNodeExpr* const lhsp
|
||||
= new AstParseRef{origVarp->fileline(), origVarp->name()};
|
||||
AstNodeExpr* const rhsp
|
||||
= new AstParseRef{paramp->fileline(), paramp->name()};
|
||||
newFuncp->addStmtsp(new AstAssign{origVarp->fileline(), lhsp, rhsp});
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, add back the existing body
|
||||
if (existingBodyp) newFuncp->addStmtsp(existingBodyp);
|
||||
}
|
||||
}
|
||||
|
||||
// IEEE: option
|
||||
{
|
||||
v3Global.setUsesStdPackage();
|
||||
|
|
@ -125,10 +171,34 @@ public:
|
|||
nodep->addMembersp(varp);
|
||||
}
|
||||
|
||||
// IEEE: function void sample()
|
||||
// IEEE: function void sample([arguments])
|
||||
{
|
||||
AstFunc* const funcp = new AstFunc{nodep->fileline(), "sample", nullptr, nullptr};
|
||||
funcp->addStmtsp(sampleArgs);
|
||||
|
||||
// Add sample arguments as function parameters and assignments
|
||||
// Member variables have already been created in verilog.y
|
||||
if (sampleArgs) {
|
||||
// Add function parameters and assignments
|
||||
AstNode* nextArgp = nullptr;
|
||||
for (AstNode* argp = sampleArgs; argp; argp = nextArgp) {
|
||||
nextArgp = argp->nextp(); // Save next before any modifications
|
||||
if (AstVar* const origVarp = VN_CAST(argp, Var)) {
|
||||
// Create a function parameter
|
||||
AstVar* const paramp = origVarp->cloneTree(false);
|
||||
paramp->funcLocal(true);
|
||||
paramp->direction(VDirection::INPUT);
|
||||
funcp->addStmtsp(paramp);
|
||||
|
||||
// Create assignment: member = parameter
|
||||
AstNodeExpr* const lhsp
|
||||
= new AstParseRef{origVarp->fileline(), origVarp->name()};
|
||||
AstNodeExpr* const rhsp
|
||||
= new AstParseRef{paramp->fileline(), paramp->name()};
|
||||
funcp->addStmtsp(new AstAssign{origVarp->fileline(), lhsp, rhsp});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
funcp->classMethod(true);
|
||||
funcp->dtypep(funcp->findVoidDType());
|
||||
nodep->addMembersp(funcp);
|
||||
|
|
@ -184,6 +254,70 @@ public:
|
|||
varp->direction(VDirection::INPUT);
|
||||
funcp->addStmtsp(varp);
|
||||
}
|
||||
|
||||
// The original arg lists were cloned above; delete the orphaned originals
|
||||
if (constructorArgs) VL_DO_DANGLING(constructorArgs->deleteTree(), constructorArgs);
|
||||
if (sampleArgs) VL_DO_DANGLING(sampleArgs->deleteTree(), sampleArgs);
|
||||
}
|
||||
// Helper to move bins from parser list to coverpoint
|
||||
void addCoverpointBins(AstCoverpoint* cp, AstNode* binsList) {
|
||||
if (!binsList) return;
|
||||
|
||||
// CRITICAL FIX: The parser creates a linked list of bins. When we try to move them
|
||||
// to the coverpoint one by one while they're still linked, the addNext() logic
|
||||
// that updates headtailp pointers creates circular references. We must fully
|
||||
// unlink ALL bins before adding ANY to the coverpoint.
|
||||
std::vector<AstCoverBin*> bins;
|
||||
std::vector<AstCoverOption*> options;
|
||||
|
||||
// To unlink the head node (which has no backp), create a temporary parent
|
||||
AstBegin* tempParent = new AstBegin{binsList->fileline(), "[TEMP]", nullptr, true};
|
||||
tempParent->addStmtsp(binsList); // Now binsList has a backp
|
||||
|
||||
// Now unlink all bins - they all have backp now
|
||||
for (AstNode *binp = binsList, *nextp; binp; binp = nextp) {
|
||||
nextp = binp->nextp();
|
||||
|
||||
if (AstCoverBin* cbinp = VN_CAST(binp, CoverBin)) {
|
||||
cbinp->unlinkFrBack(); // Now this works for all bins including head
|
||||
bins.push_back(cbinp);
|
||||
} else if (AstCgOptionAssign* optp = VN_CAST(binp, CgOptionAssign)) {
|
||||
optp->unlinkFrBack();
|
||||
// Convert AstCgOptionAssign to AstCoverOption
|
||||
VCoverOptionType optType = VCoverOptionType::COMMENT; // default
|
||||
if (optp->name() == "at_least") {
|
||||
optType = VCoverOptionType::AT_LEAST;
|
||||
} else if (optp->name() == "weight") {
|
||||
optType = VCoverOptionType::WEIGHT;
|
||||
} else if (optp->name() == "goal") {
|
||||
optType = VCoverOptionType::GOAL;
|
||||
} else if (optp->name() == "auto_bin_max") {
|
||||
optType = VCoverOptionType::AUTO_BIN_MAX;
|
||||
} else if (optp->name() == "per_instance") {
|
||||
optType = VCoverOptionType::PER_INSTANCE;
|
||||
} else if (optp->name() == "comment") {
|
||||
optType = VCoverOptionType::COMMENT;
|
||||
} else {
|
||||
optp->v3warn(COVERIGN,
|
||||
"Ignoring unsupported coverage option: " + optp->name());
|
||||
}
|
||||
AstCoverOption* coverOptp = new AstCoverOption{optp->fileline(), optType,
|
||||
optp->valuep()->cloneTree(false)};
|
||||
options.push_back(coverOptp);
|
||||
VL_DO_DANGLING(optp->deleteTree(), optp);
|
||||
} else {
|
||||
binp->v3warn(COVERIGN,
|
||||
"Unexpected node in bins list, ignoring"); // LCOV_EXCL_LINE
|
||||
VL_DO_DANGLING(binp->deleteTree(), binp);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the temporary parent
|
||||
VL_DO_DANGLING(tempParent->deleteTree(), tempParent);
|
||||
|
||||
// Now add standalone bins and options to coverpoint
|
||||
for (AstCoverBin* cbinp : bins) { cp->addBinsp(cbinp); }
|
||||
for (AstCoverOption* optp : options) { cp->addOptionsp(optp); }
|
||||
}
|
||||
AstDisplay* createDisplayError(FileLine* fileline) {
|
||||
AstDisplay* nodep = new AstDisplay{fileline, VDisplayType::DT_ERROR, "", nullptr, nullptr};
|
||||
|
|
|
|||
|
|
@ -240,6 +240,9 @@ class SchedGraphBuilder final : public VNVisitor {
|
|||
void visit(AstNodeProcedure* nodep) override { visitLogic(nodep); }
|
||||
void visit(AstNodeAssign* nodep) override { visitLogic(nodep); }
|
||||
void visit(AstCoverToggle* nodep) override { visitLogic(nodep); }
|
||||
void visit(AstStmtExpr* nodep) override {
|
||||
visitLogic(nodep);
|
||||
} // Handle statement expressions like method calls
|
||||
|
||||
// Pre and Post logic are handled separately
|
||||
void visit(AstAlwaysPre* nodep) override {}
|
||||
|
|
|
|||
|
|
@ -343,11 +343,30 @@ class TimingSuspendableVisitor final : public VNVisitor {
|
|||
}
|
||||
}
|
||||
void visit(AstNodeCCall* nodep) override {
|
||||
new V3GraphEdge{&m_suspGraph, getSuspendDepVtx(nodep->funcp()), getSuspendDepVtx(m_procp),
|
||||
P_CALL};
|
||||
// Skip automatic covergroup sampling calls (marked with user3==1)
|
||||
if (nodep->user3()) {
|
||||
iterateChildren(nodep);
|
||||
return;
|
||||
}
|
||||
|
||||
new V3GraphEdge{&m_procGraph, getNeedsProcDepVtx(nodep->funcp()),
|
||||
getNeedsProcDepVtx(m_procp), P_CALL};
|
||||
AstCFunc* funcp = nodep->funcp();
|
||||
if (!funcp) {
|
||||
iterateChildren(nodep);
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip if we're not inside a function/procedure (m_procp would be null)
|
||||
// This can happen for calls in Active nodes at module scope
|
||||
if (!m_procp) {
|
||||
iterateChildren(nodep);
|
||||
return;
|
||||
}
|
||||
|
||||
UINFO(9, "V3Timing: Processing CCall to " << funcp->name() << " in dependency graph\n");
|
||||
new V3GraphEdge{&m_suspGraph, getSuspendDepVtx(funcp), getSuspendDepVtx(m_procp), P_CALL};
|
||||
|
||||
new V3GraphEdge{&m_procGraph, getNeedsProcDepVtx(funcp), getNeedsProcDepVtx(m_procp),
|
||||
P_CALL};
|
||||
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
|
@ -947,8 +966,16 @@ class TimingControlVisitor final : public VNVisitor {
|
|||
}
|
||||
}
|
||||
void visit(AstNodeCCall* nodep) override {
|
||||
if (nodep->funcp()->needProcess()) m_hasProcess = true;
|
||||
if (hasFlags(nodep->funcp(), T_SUSPENDEE) && !nodep->user1SetOnce()) { // If suspendable
|
||||
AstCFunc* const funcp = nodep->funcp();
|
||||
|
||||
// Skip automatic covergroup sampling calls
|
||||
if (funcp->isCovergroupSample()) {
|
||||
iterateChildren(nodep);
|
||||
return;
|
||||
}
|
||||
|
||||
if (funcp->needProcess()) m_hasProcess = true;
|
||||
if (hasFlags(funcp, T_SUSPENDEE) && !nodep->user1SetOnce()) { // If suspendable
|
||||
// Calls to suspendables are always void return type, hence parent must be StmtExpr
|
||||
AstStmtExpr* const stmtp = VN_AS(nodep->backp(), StmtExpr);
|
||||
stmtp->replaceWith(new AstCAwait{nodep->fileline(), nodep->unlinkFrBack()});
|
||||
|
|
|
|||
|
|
@ -1725,8 +1725,32 @@ class WidthVisitor final : public VNVisitor {
|
|||
if (m_vup->prelim()) iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH);
|
||||
}
|
||||
void visit(AstCgOptionAssign* nodep) override {
|
||||
// We report COVERIGN on the whole covergroup; if get more fine-grained add this
|
||||
// nodep->v3warn(COVERIGN, "Ignoring unsupported: coverage option");
|
||||
// Extract covergroup option values and store in AstClass before deleting
|
||||
// Find parent covergroup (AstClass with isCovergroup() == true)
|
||||
AstClass* cgClassp = nullptr;
|
||||
for (AstNode* parentp = nodep->backp(); parentp; parentp = parentp->backp()) {
|
||||
if (AstClass* classp = VN_CAST(parentp, Class)) {
|
||||
if (classp->isCovergroup()) {
|
||||
cgClassp = classp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cgClassp) {
|
||||
// Process supported options
|
||||
if (nodep->name() == "auto_bin_max" && !nodep->typeOption()) {
|
||||
// Extract constant value
|
||||
if (AstConst* constp = VN_CAST(nodep->valuep(), Const)) {
|
||||
cgClassp->cgAutoBinMax(constp->toSInt());
|
||||
UINFO(6, " Covergroup " << cgClassp->name() << " option.auto_bin_max = "
|
||||
<< constp->toSInt() << endl);
|
||||
}
|
||||
}
|
||||
// Add more options here as needed (weight, goal, at_least, per_instance, comment)
|
||||
}
|
||||
|
||||
// Delete the assignment node (we've extracted the value)
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
}
|
||||
void visit(AstPow* nodep) override {
|
||||
|
|
@ -3369,6 +3393,9 @@ class WidthVisitor final : public VNVisitor {
|
|||
}
|
||||
void visit(AstInsideRange* nodep) override {
|
||||
// Just do each side; AstInside will rip these nodes out later
|
||||
// Constant-fold range bounds (e.g., NEGATE(100) becomes -100)
|
||||
V3Const::constifyParamsEdit(nodep->lhsp()); // May relink pointed to node
|
||||
V3Const::constifyParamsEdit(nodep->rhsp()); // May relink pointed to node
|
||||
userIterateAndNext(nodep->lhsp(), m_vup);
|
||||
userIterateAndNext(nodep->rhsp(), m_vup);
|
||||
nodep->dtypeFrom(nodep->lhsp());
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
#include "V3Const.h"
|
||||
#include "V3Control.h"
|
||||
#include "V3Coverage.h"
|
||||
#include "V3CoverageFunctional.h"
|
||||
#include "V3CoverageJoin.h"
|
||||
#include "V3Dead.h"
|
||||
#include "V3Delayed.h"
|
||||
|
|
@ -236,6 +237,10 @@ static void process() {
|
|||
// Before we do dead code elimination and inlining, or we'll lose it.
|
||||
if (v3Global.opt.coverage()) V3Coverage::coverage(v3Global.rootp());
|
||||
|
||||
// Functional coverage code generation
|
||||
// Generate code for covergroups/coverpoints
|
||||
V3CoverageFunctional::coverageFunctional(v3Global.rootp());
|
||||
|
||||
// Resolve randsequence if they are used by the design
|
||||
if (v3Global.useRandSequence()) V3RandSequence::randSequenceNetlist(v3Global.rootp());
|
||||
|
||||
|
|
|
|||
359
src/verilog.y
359
src/verilog.y
|
|
@ -3751,7 +3751,7 @@ statement_item<nodeStmtp>: // IEEE: statement_item
|
|||
| yWAIT_ORDER '(' vrdList ')' stmt yELSE stmt
|
||||
{ $$ = nullptr; BBUNSUP($4, "Unsupported: wait_order"); DEL($3, $5, $7);}
|
||||
| yWAIT_ORDER '(' vrdList ')' yELSE stmt
|
||||
{ $$ = nullptr; BBUNSUP($4, "Unsupported: wait_order"); DEL($3, $6); }
|
||||
{ $$ = nullptr; BBUNSUP($4, "Unsupported: wait_order"); DEL($6); }
|
||||
//
|
||||
// // IEEE: procedural_assertion_statement
|
||||
| procedural_assertion_statement { $$ = $1; }
|
||||
|
|
@ -3768,7 +3768,7 @@ statement_item<nodeStmtp>: // IEEE: statement_item
|
|||
| yEXPECT '(' property_spec ')' stmt yELSE stmt
|
||||
{ $$ = nullptr; BBUNSUP($1, "Unsupported: expect"); DEL($3, $5, $7); }
|
||||
| yEXPECT '(' property_spec ')' yELSE stmt
|
||||
{ $$ = nullptr; BBUNSUP($1, "Unsupported: expect"); DEL($3, $6); }
|
||||
{ $$ = nullptr; BBUNSUP($1, "Unsupported: expect"); DEL($6); }
|
||||
;
|
||||
|
||||
statementVerilatorPragmas<pragmap>:
|
||||
|
|
@ -6663,7 +6663,7 @@ property_exprCaseIf<nodeExprp>: // IEEE: part of property_expr for if/case
|
|||
| yIF '(' expr/*expression_or_dist*/ ')' pexpr %prec prLOWER_THAN_ELSE
|
||||
{ $$ = $5; BBUNSUP($<fl>1, "Unsupported: property case expression"); DEL($3); }
|
||||
| yIF '(' expr/*expression_or_dist*/ ')' pexpr yELSE pexpr
|
||||
{ $$ = $5; BBUNSUP($<fl>1, "Unsupported: property case expression"); DEL($3, $7); }
|
||||
{ $$ = $5; BBUNSUP($<fl>1, "Unsupported: property case expression"); DEL($7); }
|
||||
;
|
||||
|
||||
property_case_itemList<caseItemp>: // IEEE: {property_case_item}
|
||||
|
|
@ -6935,24 +6935,73 @@ covergroup_declaration<nodep>: // ==IEEE: covergroup_declaration
|
|||
/*cont*/ yENDGROUP endLabelE
|
||||
{ AstClass *cgClassp = new AstClass{$<fl>2, *$2, PARSEP->libname()};
|
||||
cgClassp->isCovergroup(true);
|
||||
|
||||
AstNode* sampleArgs = nullptr;
|
||||
|
||||
// coverage_eventE can be either a clocking event or sample arguments
|
||||
if ($4) {
|
||||
if (VN_IS($4, SenItem)) {
|
||||
// Clocking event: @(posedge clk)
|
||||
// Create an AstCovergroup node to hold the clocking event
|
||||
AstSenTree* senTreep = new AstSenTree{$<fl>1, VN_AS($4, SenItem)};
|
||||
AstCovergroup* const cgNodep = new AstCovergroup{$<fl>1, *$2, nullptr, senTreep};
|
||||
cgClassp->addMembersp(cgNodep);
|
||||
} else {
|
||||
// Sample arguments: with function sample(...)
|
||||
sampleArgs = $4;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert constructor parameters to member variables
|
||||
// This must happen BEFORE the covergroup body is added,
|
||||
// so coverpoints can reference these members
|
||||
// We iterate carefully to avoid issues with modified AST
|
||||
if ($3) {
|
||||
AstNode* nextArgp = nullptr;
|
||||
for (AstNode* argp = $3; argp; argp = nextArgp) {
|
||||
nextArgp = argp->nextp(); // Save next before any modifications
|
||||
if (AstVar* origVarp = VN_CAST(argp, Var)) {
|
||||
AstVar* memberp = origVarp->cloneTree(false);
|
||||
memberp->varType(VVarType::MEMBER);
|
||||
memberp->funcLocal(false);
|
||||
memberp->direction(VDirection::NONE);
|
||||
cgClassp->addMembersp(memberp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert sample parameters to member variables
|
||||
if (sampleArgs) {
|
||||
AstNode* nextArgp = nullptr;
|
||||
for (AstNode* argp = sampleArgs; argp; argp = nextArgp) {
|
||||
nextArgp = argp->nextp(); // Save next before any modifications
|
||||
if (AstVar* origVarp = VN_CAST(argp, Var)) {
|
||||
AstVar* memberp = origVarp->cloneTree(false);
|
||||
memberp->varType(VVarType::MEMBER);
|
||||
memberp->funcLocal(false);
|
||||
memberp->direction(VDirection::NONE);
|
||||
cgClassp->addMembersp(memberp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AstFunc* const newp = new AstFunc{$<fl>1, "new", nullptr, nullptr};
|
||||
newp->fileline()->warnOff(V3ErrorCode::NORETURN, true);
|
||||
newp->classMethod(true);
|
||||
newp->isConstructor(true);
|
||||
newp->dtypep(cgClassp->dtypep());
|
||||
newp->addStmtsp($3);
|
||||
newp->addStmtsp($6);
|
||||
cgClassp->addMembersp(newp);
|
||||
GRAMMARP->createCoverGroupMethods(cgClassp, $4);
|
||||
GRAMMARP->createCoverGroupMethods(cgClassp, $3, sampleArgs);
|
||||
|
||||
$$ = cgClassp;
|
||||
GRAMMARP->endLabel($<fl>8, $$, $8);
|
||||
BBCOVERIGN($<fl>1, "Ignoring unsupported: covergroup");
|
||||
}
|
||||
| yCOVERGROUP yEXTENDS idAny ';'
|
||||
/*cont*/ coverage_spec_or_optionListE
|
||||
/*cont*/ yENDGROUP endLabelE
|
||||
{ AstClass *cgClassp = new AstClass{$<fl>3, *$3, PARSEP->libname()};
|
||||
{ BBCOVERIGN($1, "Ignoring unsupported: covergroup inheritance (extends)");
|
||||
AstClass *cgClassp = new AstClass{$<fl>3, *$3, PARSEP->libname()};
|
||||
cgClassp->isCovergroup(true);
|
||||
AstFunc* const newp = new AstFunc{$<fl>1, "new", nullptr, nullptr};
|
||||
newp->fileline()->warnOff(V3ErrorCode::NORETURN, true);
|
||||
|
|
@ -6961,11 +7010,10 @@ covergroup_declaration<nodep>: // ==IEEE: covergroup_declaration
|
|||
newp->dtypep(cgClassp->dtypep());
|
||||
newp->addStmtsp($5);
|
||||
cgClassp->addMembersp(newp);
|
||||
GRAMMARP->createCoverGroupMethods(cgClassp, nullptr);
|
||||
GRAMMARP->createCoverGroupMethods(cgClassp, nullptr, nullptr);
|
||||
|
||||
$$ = cgClassp;
|
||||
GRAMMARP->endLabel($<fl>7, $$, $7);
|
||||
BBCOVERIGN($<fl>1, "Ignoring unsupported: covergroup");
|
||||
}
|
||||
;
|
||||
|
||||
|
|
@ -7013,21 +7061,46 @@ coverage_option<nodep>: // ==IEEE: coverage_option
|
|||
cover_point<nodep>: // ==IEEE: cover_point
|
||||
// // [ [ data_type_or_implicit ] cover_point_identifier ':' ] yCOVERPOINT
|
||||
yCOVERPOINT expr iffE bins_or_empty
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>1, "Ignoring unsupported: coverpoint"); DEL($2, $3, $4); }
|
||||
{ auto* cp = new AstCoverpoint{$<fl>1, "", $2};
|
||||
if ($3) cp->iffp(VN_AS($3, NodeExpr));
|
||||
GRAMMARP->addCoverpointBins(cp, $4);
|
||||
$$ = cp; }
|
||||
// // IEEE-2012: class_scope before an ID
|
||||
| id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>3, "Ignoring unsupported: coverpoint"); DEL($4, $5, $6);}
|
||||
{ auto* cp = new AstCoverpoint{$<fl>3, *$1, $4};
|
||||
if ($5) cp->iffp(VN_AS($5, NodeExpr));
|
||||
GRAMMARP->addCoverpointBins(cp, $6);
|
||||
$$ = cp; }
|
||||
// // data_type_or_implicit expansion
|
||||
| data_type id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>4, "Ignoring unsupported: coverpoint"); DEL($1, $5, $6, $7);}
|
||||
{ auto* cp = new AstCoverpoint{$<fl>4, *$2, $5};
|
||||
if ($6) cp->iffp(VN_AS($6, NodeExpr));
|
||||
GRAMMARP->addCoverpointBins(cp, $7);
|
||||
$$ = cp;
|
||||
DEL($1); }
|
||||
| yVAR data_type id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>5, "Ignoring unsupported: coverpoint"); DEL($2, $6, $7, $8); }
|
||||
{ auto* cp = new AstCoverpoint{$<fl>5, *$3, $6};
|
||||
if ($7) cp->iffp(VN_AS($7, NodeExpr));
|
||||
GRAMMARP->addCoverpointBins(cp, $8);
|
||||
$$ = cp;
|
||||
DEL($2); }
|
||||
| yVAR implicit_typeE id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>5, "Ignoring unsupported: coverpoint"); DEL($2, $6, $7, $8); }
|
||||
{ auto* cp = new AstCoverpoint{$<fl>5, *$3, $6};
|
||||
if ($7) cp->iffp(VN_AS($7, NodeExpr));
|
||||
GRAMMARP->addCoverpointBins(cp, $8);
|
||||
$$ = cp;
|
||||
DEL($2); }
|
||||
| signingE rangeList id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>5, "Ignoring unsupported: coverpoint"); DEL($2, $6, $7, $8); }
|
||||
{ auto* cp = new AstCoverpoint{$<fl>5, *$3, $6};
|
||||
if ($7) cp->iffp(VN_AS($7, NodeExpr));
|
||||
GRAMMARP->addCoverpointBins(cp, $8);
|
||||
$$ = cp;
|
||||
DEL($2); }
|
||||
| signing id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>4, "Ignoring unsupported: coverpoint"); DEL($5, $6, $7); }
|
||||
{ auto* cp = new AstCoverpoint{$<fl>4, *$2, $5};
|
||||
if ($6) cp->iffp(VN_AS($6, NodeExpr));
|
||||
GRAMMARP->addCoverpointBins(cp, $7);
|
||||
$$ = cp; }
|
||||
// // IEEE-2012:
|
||||
| bins_or_empty { $$ = $1; }
|
||||
;
|
||||
|
|
@ -7035,7 +7108,7 @@ cover_point<nodep>: // ==IEEE: cover_point
|
|||
iffE<nodep>: // IEEE: part of cover_point, others
|
||||
/* empty */ { $$ = nullptr; }
|
||||
| yIFF '(' expr ')'
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>1, "Ignoring unsupported: cover 'iff'"); DEL($3); }
|
||||
{ $$ = $3; /* Keep iff condition for coverpoint */ }
|
||||
;
|
||||
|
||||
bins_or_empty<nodep>: // ==IEEE: bins_or_empty
|
||||
|
|
@ -7059,55 +7132,133 @@ bins_or_options<nodep>: // ==IEEE: bins_or_options
|
|||
// // Superset of IEEE - we allow []'s in more places
|
||||
coverage_option { $$ = $1; }
|
||||
// // Can't use wildcardE as results in conflicts
|
||||
| bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>4, "Ignoring unsupported: cover bin specification"); DEL($3, $6, $8); }
|
||||
| bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>8, "Ignoring unsupported: cover bin 'with' specification"); DEL($3, $6, $10, $12); }
|
||||
| bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' id/*cover_point_id*/ yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>6, "Ignoring unsupported: cover bin 'with' specification"); DEL($3, $8, $10); }
|
||||
| yWILDCARD bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>5, "Ignoring unsupported: cover bin 'wildcard' specification"); DEL($4, $7, $9); }
|
||||
| yWILDCARD bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>9, "Ignoring unsupported: cover bin 'wildcard' 'with' specification"); DEL($4, $7, $11, $13); }
|
||||
| yBINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' iffE
|
||||
{ $$ = new AstCoverBin{$<fl>2, *$2, $6, false, false};
|
||||
if ($3) VN_AS($$, CoverBin)->isArray(true); // If bins_orBraE returned non-null, it's array
|
||||
DEL($8); }
|
||||
| yBINS idAny/*bin_identifier*/ '[' cgexpr ']' iffE
|
||||
{ // Check for automatic bins: bins auto[N]
|
||||
if (*$2 == "auto") {
|
||||
$$ = new AstCoverBin{$<fl>2, *$2, $4};
|
||||
DEL($6);
|
||||
} else {
|
||||
$$ = nullptr;
|
||||
BBCOVERIGN($<fl>2, "Ignoring unsupported: bin array (non-auto)");
|
||||
DEL($4, $6);
|
||||
}
|
||||
}
|
||||
| yIGNORE_BINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' iffE
|
||||
{ $$ = new AstCoverBin{$<fl>2, *$2, $6, true, false};
|
||||
if ($3) VN_AS($$, CoverBin)->isArray(true);
|
||||
DEL($8); }
|
||||
| yILLEGAL_BINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' iffE
|
||||
{ $$ = new AstCoverBin{$<fl>2, *$2, $6, false, true};
|
||||
if ($3) VN_AS($$, CoverBin)->isArray(true);
|
||||
DEL($8); }
|
||||
| yBINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = new AstCoverBin{$<fl>2, *$2, $6, false, false};
|
||||
DEL($10, $12); /* TODO: Support 'with' clause */ }
|
||||
| yIGNORE_BINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = new AstCoverBin{$<fl>2, *$2, $6, true, false};
|
||||
DEL($10, $12); /* TODO: Support 'with' clause */ }
|
||||
| yILLEGAL_BINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = new AstCoverBin{$<fl>2, *$2, $6, false, true};
|
||||
DEL($10, $12); /* TODO: Support 'with' clause */ }
|
||||
| yBINS idAny/*bin_identifier*/ bins_orBraE '=' id/*cover_point_id*/ yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>6, "Ignoring unsupported: cover bin 'with' specification"); DEL($8, $10); }
|
||||
| yIGNORE_BINS idAny/*bin_identifier*/ bins_orBraE '=' id/*cover_point_id*/ yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>6, "Ignoring unsupported: cover bin 'with' specification"); DEL($8, $10); }
|
||||
| yILLEGAL_BINS idAny/*bin_identifier*/ bins_orBraE '=' id/*cover_point_id*/ yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>6, "Ignoring unsupported: cover bin 'with' specification"); DEL($8, $10); }
|
||||
| yWILDCARD yBINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' iffE
|
||||
{ $$ = new AstCoverBin{$<fl>3, *$3, $7, false, false, true};
|
||||
DEL($9); }
|
||||
| yWILDCARD yIGNORE_BINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' iffE
|
||||
{ $$ = new AstCoverBin{$<fl>3, *$3, $7, true, false, true};
|
||||
DEL($9); }
|
||||
| yWILDCARD yILLEGAL_BINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' iffE
|
||||
{ $$ = new AstCoverBin{$<fl>3, *$3, $7, false, true, true};
|
||||
DEL($9); }
|
||||
| yWILDCARD yBINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>9, "Ignoring unsupported: cover bin 'wildcard' 'with' specification"); DEL($7, $11, $13); }
|
||||
| yWILDCARD yIGNORE_BINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>9, "Ignoring unsupported: cover bin 'wildcard' 'with' specification"); DEL($7, $11, $13); }
|
||||
| yWILDCARD yILLEGAL_BINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>9, "Ignoring unsupported: cover bin 'wildcard' 'with' specification"); DEL($7, $11, $13); }
|
||||
//
|
||||
// // cgexpr part of trans_list
|
||||
| bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' trans_list iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>4, "Ignoring unsupported: cover bin trans list"); DEL($3, $5, $6); }
|
||||
| yWILDCARD bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' trans_list iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>1, "Ignoring unsupported: cover bin 'wildcard' trans list"); DEL($4, $6, $7);}
|
||||
| yBINS idAny/*bin_identifier*/ bins_orBraE '=' trans_list iffE
|
||||
{
|
||||
FileLine* isArray = $<fl>3;
|
||||
$$ = new AstCoverBin{$<fl>2, *$2, static_cast<AstCoverTransSet*>($5), false, false, isArray != nullptr};
|
||||
DEL($6);
|
||||
}
|
||||
| yIGNORE_BINS idAny/*bin_identifier*/ bins_orBraE '=' trans_list iffE
|
||||
{
|
||||
FileLine* isArray = $<fl>3;
|
||||
$$ = new AstCoverBin{$<fl>2, *$2, static_cast<AstCoverTransSet*>($5), true, false, isArray != nullptr};
|
||||
DEL($6);
|
||||
}
|
||||
| yILLEGAL_BINS idAny/*bin_identifier*/ bins_orBraE '=' trans_list iffE
|
||||
{
|
||||
FileLine* isArray = $<fl>3;
|
||||
$$ = new AstCoverBin{$<fl>2, *$2, static_cast<AstCoverTransSet*>($5), false, true, isArray != nullptr};
|
||||
DEL($6);
|
||||
}
|
||||
| yWILDCARD yBINS idAny/*bin_identifier*/ bins_orBraE '=' trans_list iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>1, "Ignoring unsupported: cover bin 'wildcard' trans list"); DEL($6, $7);}
|
||||
| yWILDCARD yIGNORE_BINS idAny/*bin_identifier*/ bins_orBraE '=' trans_list iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>1, "Ignoring unsupported: cover bin 'wildcard' trans list"); DEL($6, $7);}
|
||||
| yWILDCARD yILLEGAL_BINS idAny/*bin_identifier*/ bins_orBraE '=' trans_list iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>1, "Ignoring unsupported: cover bin 'wildcard' trans list"); DEL($6, $7);}
|
||||
//
|
||||
| bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' yDEFAULT iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>5, "Ignoring unsupported: cover bin 'default'"); DEL($3, $6); }
|
||||
| bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' yDEFAULT ySEQUENCE iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>6, "Ignoring unsupported: cover bin 'default' 'sequence'"); DEL($3, $7); }
|
||||
| yBINS idAny/*bin_identifier*/ bins_orBraE '=' yDEFAULT iffE
|
||||
{ $$ = new AstCoverBin{$<fl>2, *$2, VCoverBinsType::DEFAULT};
|
||||
DEL($6); }
|
||||
| yIGNORE_BINS idAny/*bin_identifier*/ bins_orBraE '=' yDEFAULT iffE
|
||||
{ $$ = new AstCoverBin{$<fl>2, *$2, VCoverBinsType::BINS_IGNORE};
|
||||
DEL($6); }
|
||||
| yILLEGAL_BINS idAny/*bin_identifier*/ bins_orBraE '=' yDEFAULT iffE
|
||||
{ $$ = new AstCoverBin{$<fl>2, *$2, VCoverBinsType::BINS_ILLEGAL};
|
||||
DEL($6); }
|
||||
| yBINS idAny/*bin_identifier*/ bins_orBraE '=' yDEFAULT ySEQUENCE iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>6, "Ignoring unsupported: cover bin 'default' 'sequence'"); DEL($7); }
|
||||
| yIGNORE_BINS idAny/*bin_identifier*/ bins_orBraE '=' yDEFAULT ySEQUENCE iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>6, "Ignoring unsupported: cover bin 'default' 'sequence'"); DEL($7); }
|
||||
| yILLEGAL_BINS idAny/*bin_identifier*/ bins_orBraE '=' yDEFAULT ySEQUENCE iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>6, "Ignoring unsupported: cover bin 'default' 'sequence'"); DEL($7); }
|
||||
;
|
||||
|
||||
bins_orBraE<nodep>: // IEEE: part of bins_or_options:
|
||||
bins_orBraE<fl>: // IEEE: part of bins_or_options: returns fileline (abuse for boolean flag)
|
||||
/* empty */ { $$ = nullptr; }
|
||||
| '[' ']' { $$ = nullptr; /*UNSUP*/ }
|
||||
| '[' ']' { $$ = $<fl>1; /* Mark as array */ }
|
||||
| '[' cgexpr ']' { $$ = nullptr; /*UNSUP*/ DEL($2); }
|
||||
;
|
||||
|
||||
bins_keyword<fl>: // ==IEEE: bins_keyword
|
||||
yBINS { $$ = $1; /*UNSUP*/ }
|
||||
| yILLEGAL_BINS { $$ = $1; /*UNSUP*/ }
|
||||
| yIGNORE_BINS { $$ = $1; /*UNSUP*/ }
|
||||
;
|
||||
|
||||
trans_list<nodep>: // ==IEEE: trans_list
|
||||
'(' trans_set ')' { $$ = $2; }
|
||||
| trans_list ',' '(' trans_set ')' { $$ = addNextNull($1, $4); }
|
||||
;
|
||||
|
||||
trans_set<nodep>: // ==IEEE: trans_set
|
||||
trans_range_list { $$ = $1; }
|
||||
// // Note the { => } in the grammar, this is really a list
|
||||
trans_set<nodep>: // ==IEEE: trans_set (returns AstCoverTransSet)
|
||||
trans_range_list {
|
||||
// Single transition item - wrap in AstCoverTransSet
|
||||
$$ = new AstCoverTransSet{$<fl>1, static_cast<AstCoverTransItem*>($1)};
|
||||
}
|
||||
| trans_set yP_EQGT trans_range_list
|
||||
{ $$ = $1; BBCOVERIGN($<fl>2, "Ignoring unsupported: cover trans set '=>'"); DEL($3); }
|
||||
{
|
||||
// Chain transition items with => operator
|
||||
// Add new item to existing set
|
||||
$$ = $1;
|
||||
static_cast<AstCoverTransSet*>($$)->addItemsp(static_cast<AstCoverTransItem*>($3));
|
||||
}
|
||||
;
|
||||
|
||||
trans_range_list<nodep>: // ==IEEE: trans_range_list
|
||||
trans_item { $$ = $1; }
|
||||
trans_range_list<nodep>: // ==IEEE: trans_range_list (returns AstCoverTransItem)
|
||||
trans_item {
|
||||
// Simple transition item without repetition
|
||||
$$ = new AstCoverTransItem{$<fl>1, $1, VTransRepType::NONE};
|
||||
}
|
||||
| trans_item yP_BRASTAR cgexpr ']'
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>2, "Ignoring unsupported: cover '[*'"); DEL($1, $3); }
|
||||
| trans_item yP_BRASTAR cgexpr ':' cgexpr ']'
|
||||
|
|
@ -7122,7 +7273,7 @@ trans_range_list<nodep>: // ==IEEE: trans_range_list
|
|||
{ $$ = nullptr; BBCOVERIGN($<fl>2, "Ignoring unsupported: cover '[='"); DEL($1, $3, $5); }
|
||||
;
|
||||
|
||||
trans_item<nodep>: // ==IEEE: range_list
|
||||
trans_item<nodep>: // ==IEEE: range_list (returns range list node)
|
||||
covergroup_range_list { $$ = $1; }
|
||||
;
|
||||
|
||||
|
|
@ -7134,9 +7285,94 @@ covergroup_range_list<nodep>: // ==IEEE: covergroup_range_list
|
|||
|
||||
cover_cross<nodep>: // ==IEEE: cover_cross
|
||||
id/*cover_point_identifier*/ ':' yCROSS list_of_cross_items iffE cross_body
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>3, "Ignoring unsupported: cover cross"); DEL($4, $5, $6); }
|
||||
{
|
||||
AstCoverCross* const nodep = new AstCoverCross{$<fl>3, *$1,
|
||||
VN_AS($4, CoverpointRef)};
|
||||
if ($6) { // cross_body items (options, bins)
|
||||
for (AstNode* itemp = $6; itemp; ) {
|
||||
AstNode* const nextp = itemp->nextp();
|
||||
// Helper: unlink itemp from the standalone bison list.
|
||||
// Head nodes have m_backp==nullptr; use nextp->unlinkFrBackWithNext()
|
||||
// to detach the rest of the list so itemp->m_nextp becomes null.
|
||||
const auto unlinkItem = [&]() {
|
||||
if (itemp->backp()) {
|
||||
itemp->unlinkFrBack();
|
||||
} else if (nextp) {
|
||||
nextp->unlinkFrBackWithNext();
|
||||
}
|
||||
};
|
||||
if (AstCoverOption* optp = VN_CAST(itemp, CoverOption)) {
|
||||
unlinkItem();
|
||||
nodep->addOptionsp(optp);
|
||||
} else if (AstCoverCrossBins* binp = VN_CAST(itemp, CoverCrossBins)) {
|
||||
unlinkItem();
|
||||
nodep->addBinsp(binp);
|
||||
} else if (VN_IS(itemp, CgOptionAssign)) {
|
||||
unlinkItem();
|
||||
VL_DO_DANGLING(itemp->deleteTree(), itemp);
|
||||
} else if (VN_IS(itemp, Func)) {
|
||||
// Function declarations in cross bodies are unsupported
|
||||
// Skip them - they will be deleted when bins expressions referencing
|
||||
// them are deleted via DEL() in the cross_body_item rules
|
||||
} else {
|
||||
// Delete other unsupported items
|
||||
unlinkItem();
|
||||
VL_DO_DANGLING(itemp->deleteTree(), itemp);
|
||||
}
|
||||
itemp = nextp;
|
||||
}
|
||||
}
|
||||
if ($5) {
|
||||
$5->v3warn(COVERIGN, "Ignoring unsupported: cross iff condition");
|
||||
VL_DO_DANGLING($5->deleteTree(), $5);
|
||||
}
|
||||
$$ = nodep;
|
||||
}
|
||||
| yCROSS list_of_cross_items iffE cross_body
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>1, "Ignoring unsupported: cover cross"); DEL($2, $3, $4); }
|
||||
{
|
||||
AstCoverCross* const nodep = new AstCoverCross{$<fl>1,
|
||||
"__cross" + cvtToStr(GRAMMARP->s_typeImpNum++),
|
||||
VN_AS($2, CoverpointRef)};
|
||||
if ($4) { // cross_body items (options, bins)
|
||||
for (AstNode* itemp = $4; itemp; ) {
|
||||
AstNode* const nextp = itemp->nextp();
|
||||
// Helper: unlink itemp from the standalone bison list.
|
||||
// Head nodes have m_backp==nullptr; use nextp->unlinkFrBackWithNext()
|
||||
// to detach the rest of the list so itemp->m_nextp becomes null.
|
||||
const auto unlinkItem = [&]() {
|
||||
if (itemp->backp()) {
|
||||
itemp->unlinkFrBack();
|
||||
} else if (nextp) {
|
||||
nextp->unlinkFrBackWithNext();
|
||||
}
|
||||
};
|
||||
if (AstCoverOption* optp = VN_CAST(itemp, CoverOption)) {
|
||||
unlinkItem();
|
||||
nodep->addOptionsp(optp);
|
||||
} else if (AstCoverCrossBins* binp = VN_CAST(itemp, CoverCrossBins)) {
|
||||
unlinkItem();
|
||||
nodep->addBinsp(binp);
|
||||
} else if (VN_IS(itemp, CgOptionAssign)) {
|
||||
unlinkItem();
|
||||
VL_DO_DANGLING(itemp->deleteTree(), itemp);
|
||||
} else if (VN_IS(itemp, Func)) {
|
||||
// Function declarations in cross bodies are unsupported
|
||||
// Skip them - they will be deleted when bins expressions referencing
|
||||
// them are deleted via DEL() in the cross_body_item rules
|
||||
} else {
|
||||
// Delete other unsupported items
|
||||
unlinkItem();
|
||||
VL_DO_DANGLING(itemp->deleteTree(), itemp);
|
||||
}
|
||||
itemp = nextp;
|
||||
}
|
||||
}
|
||||
if ($3) {
|
||||
$3->v3warn(COVERIGN, "Ignoring unsupported: cross iff condition");
|
||||
VL_DO_DANGLING($3->deleteTree(), $3);
|
||||
}
|
||||
$$ = nodep;
|
||||
}
|
||||
;
|
||||
|
||||
list_of_cross_items<nodep>: // ==IEEE: list_of_cross_items
|
||||
|
|
@ -7151,7 +7387,8 @@ cross_itemList<nodep>: // IEEE: part of list_of_cross_items
|
|||
;
|
||||
|
||||
cross_item<nodep>: // ==IEEE: cross_item
|
||||
idDotted/*cover_point_identifier or variable_identifier*/ { $1->deleteTree(); $$ = nullptr; /*UNSUP*/ }
|
||||
id/*cover_point_identifier*/
|
||||
{ $$ = new AstCoverpointRef{$<fl>1, *$1}; }
|
||||
;
|
||||
|
||||
cross_body<nodep>: // ==IEEE: cross_body
|
||||
|
|
@ -7171,12 +7408,16 @@ cross_body_itemList<nodep>: // IEEE: part of cross_body
|
|||
|
||||
cross_body_item<nodep>: // ==IEEE: cross_body_item
|
||||
function_declaration
|
||||
{ $$ = $1; BBCOVERIGN($1->fileline(), "Ignoring unsupported: coverage cross 'function' declaration"); }
|
||||
{ $$ = nullptr; BBCOVERIGN($1->fileline(), "Ignoring unsupported: coverage cross 'function' declaration"); DEL($1); }
|
||||
// // IEEE: bins_selection_or_option
|
||||
| coverage_option ';' { $$ = $1; }
|
||||
// // IEEE: bins_selection
|
||||
| bins_keyword idAny/*new-bin_identifier*/ '=' select_expression iffE ';'
|
||||
{ $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage cross bin"); DEL($4, $5); }
|
||||
// // IEEE: bins_selection - for now, we ignore explicit cross bins
|
||||
| yBINS idAny/*new-bin_identifier*/ '=' select_expression iffE ';'
|
||||
{ $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: explicit coverage cross bins"); DEL($4, $5); }
|
||||
| yIGNORE_BINS idAny/*new-bin_identifier*/ '=' select_expression iffE ';'
|
||||
{ $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: explicit coverage cross bins"); DEL($4, $5); }
|
||||
| yILLEGAL_BINS idAny/*new-bin_identifier*/ '=' select_expression iffE ';'
|
||||
{ $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: explicit coverage cross bins"); DEL($4, $5); }
|
||||
| error ';' { $$ = nullptr; } // LCOV_EXCL_LINE
|
||||
;
|
||||
|
||||
|
|
@ -7197,7 +7438,7 @@ select_expression_r<nodep>:
|
|||
| '!' yBINSOF '(' bins_expression ')'
|
||||
{ $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage select expression 'binsof'"); DEL($4); }
|
||||
| yBINSOF '(' bins_expression ')' yINTERSECT '{' covergroup_range_list '}'
|
||||
{ $$ = nullptr; BBCOVERIGN($5, "Ignoring unsupported: coverage select expression 'intersect'"); DEL($3, $7); }
|
||||
{ $$ = nullptr; BBCOVERIGN($5, "Ignoring unsupported: coverage select expression 'intersect'"); DEL($7); }
|
||||
| '!' yBINSOF '(' bins_expression ')' yINTERSECT '{' covergroup_range_list '}' { }
|
||||
{ $$ = nullptr; BBCOVERIGN($5, "Ignoring unsupported: coverage select expression 'intersect'"); DEL($4, $8); }
|
||||
| yWITH__PAREN '(' cgexpr ')'
|
||||
|
|
@ -7242,7 +7483,7 @@ bins_expression<nodep>: // ==IEEE: bins_expression
|
|||
coverage_eventE<nodep>: // IEEE: [ coverage_event ]
|
||||
/* empty */ { $$ = nullptr; }
|
||||
| clocking_event
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>1, "Ignoring unsupported: coverage clocking event"); DEL($1); }
|
||||
{ $$ = $1; } // Keep the clocking event for automatic sampling
|
||||
| yWITH__ETC yFUNCTION idAny/*"sample"*/ '(' tf_port_listE ')'
|
||||
{ if (*$3 != "sample") {
|
||||
$<fl>3->v3error("Coverage sampling function must be named 'sample'");
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
// Simple test harness for t_covergroup_auto_sample - provides clock
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2026 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
#include "verilated.h"
|
||||
|
||||
#include "Vt_covergroup_auto_sample.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
Verilated::commandArgs(argc, argv);
|
||||
Vt_covergroup_auto_sample* top = new Vt_covergroup_auto_sample;
|
||||
|
||||
// Run for 20 cycles
|
||||
for (int i = 0; i < 20; i++) {
|
||||
top->clk = 0;
|
||||
top->eval();
|
||||
top->clk = 1;
|
||||
top->eval();
|
||||
|
||||
if (Verilated::gotFinish()) break;
|
||||
}
|
||||
|
||||
delete top;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#!/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 automatic sampling with --no-timing (default)
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.compile()
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
// DESCRIPTION: Verilator: Test automatic sampling with clocking events
|
||||
// This file ONLY is placed into the Public Domain, for any use, without warranty.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
logic [1:0] data;
|
||||
|
||||
// Covergroup with automatic sampling on posedge clk
|
||||
covergroup cg @(posedge clk);
|
||||
cp_data: coverpoint data {
|
||||
bins zero = {2'b00};
|
||||
bins one = {2'b01};
|
||||
bins two = {2'b10};
|
||||
bins three = {2'b11};
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg cg_inst = new;
|
||||
|
||||
int cyc = 0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
|
||||
case (cyc)
|
||||
0: data <= 2'b00; // Hit bin zero
|
||||
1: data <= 2'b01; // Hit bin one
|
||||
2: data <= 2'b10; // Hit bin two
|
||||
3: data <= 2'b11; // Hit bin three
|
||||
4: begin
|
||||
$display("Coverage: %f%%", cg_inst.get_inst_coverage());
|
||||
if (cg_inst.get_inst_coverage() >= 99.0) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end else begin
|
||||
$display("ERROR: Expected 100%% coverage, got %f%%", cg_inst.get_inst_coverage());
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
|
||||
// NOTE: NO manual .sample() call - relying on automatic sampling!
|
||||
|
||||
// Auto-stop after 10 cycles to prevent infinite loop
|
||||
if (cyc > 10) begin
|
||||
$display("ERROR: Test timed out");
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
#!/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 automatic sampling with --timing
|
||||
test.scenarios('vlt')
|
||||
|
||||
# Use the same .v file as the non-timing test
|
||||
test.top_filename = "t/t_covergroup_auto_sample.v"
|
||||
|
||||
test.compile(v_flags2=["--timing"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -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: 2024 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.compile(verilator_flags2=["-Wno-UNSIGNED -Wno-CMPCONST"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2024 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test automatic bin creation when coverpoint has no explicit bins
|
||||
|
||||
module t(/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
logic [2:0] data3; // 3-bit: values 0-7
|
||||
logic [1:0] data2; // 2-bit: values 0-3
|
||||
|
||||
// Test 1: auto_bin_max default (64) - should create 8 bins for 3-bit signal
|
||||
// Each value should get its own bin since 2^3 = 8 < 64
|
||||
covergroup cg1;
|
||||
cp_data3: coverpoint data3; // No bins specified - autobins
|
||||
endgroup
|
||||
|
||||
// Test 2: With option.auto_bin_max = 4
|
||||
// Should create 4 bins: [0:1], [2:3], [4:5], [6:7]
|
||||
covergroup cg2;
|
||||
option.auto_bin_max = 4;
|
||||
cp_data3: coverpoint data3; // No bins specified - autobins
|
||||
endgroup
|
||||
|
||||
// Test 3: With ignore bins - should still auto-create for non-ignored values
|
||||
// Autobins created, but value 7 is ignored
|
||||
covergroup cg3;
|
||||
cp_data3: coverpoint data3 {
|
||||
ignore_bins reserved = {7};
|
||||
}
|
||||
endgroup
|
||||
|
||||
// Test 4: Smaller signal - 2-bit
|
||||
// Should create 4 bins (one per value) since 2^2 = 4 < 64
|
||||
covergroup cg4;
|
||||
cp_data2: coverpoint data2; // No bins specified - autobins
|
||||
endgroup
|
||||
|
||||
// Test 5: With auto_bin_max smaller than signal range
|
||||
// 2-bit signal (0-3) with auto_bin_max=2 should create 2 bins: [0:1], [2:3]
|
||||
covergroup cg5;
|
||||
option.auto_bin_max = 2;
|
||||
cp_data2: coverpoint data2; // No bins specified - autobins
|
||||
endgroup
|
||||
|
||||
initial begin
|
||||
cg1 cg1_inst;
|
||||
cg2 cg2_inst;
|
||||
cg3 cg3_inst;
|
||||
cg4 cg4_inst;
|
||||
cg5 cg5_inst;
|
||||
|
||||
cg1_inst = new;
|
||||
cg2_inst = new;
|
||||
cg3_inst = new;
|
||||
cg4_inst = new;
|
||||
cg5_inst = new;
|
||||
|
||||
// Test CG1: Hit values 0, 1, 2 (3 of 8 bins = 37.5%)
|
||||
data3 = 0; cg1_inst.sample();
|
||||
data3 = 1; cg1_inst.sample();
|
||||
data3 = 2; cg1_inst.sample();
|
||||
|
||||
// Test CG2: Hit values 0, 1, 4 (bins [0:1] and [4:5], 2 of 4 bins = 50%)
|
||||
data3 = 0; cg2_inst.sample();
|
||||
data3 = 1; cg2_inst.sample();
|
||||
data3 = 4; cg2_inst.sample();
|
||||
|
||||
// Test CG3: Hit values 0, 1, 7 (7 is ignored, so 2 of 7 valid bins = 28.6%)
|
||||
data3 = 0; cg3_inst.sample();
|
||||
data3 = 1; cg3_inst.sample();
|
||||
data3 = 7; cg3_inst.sample(); // Ignored
|
||||
|
||||
// Test CG4: Hit all values 0-3 (4 of 4 bins = 100%)
|
||||
data2 = 0; cg4_inst.sample();
|
||||
data2 = 1; cg4_inst.sample();
|
||||
data2 = 2; cg4_inst.sample();
|
||||
data2 = 3; cg4_inst.sample();
|
||||
|
||||
// Test CG5: Hit values 0, 3 (bins [0:1] and [2:3], 2 of 2 bins = 100%)
|
||||
data2 = 0; cg5_inst.sample();
|
||||
data2 = 3; cg5_inst.sample();
|
||||
|
||||
$display("CG1 (8 autobins): %0.1f%%", cg1_inst.get_inst_coverage());
|
||||
$display("CG2 (4 autobins w/ option): %0.1f%%", cg2_inst.get_inst_coverage());
|
||||
$display("CG3 (7 autobins w/ ignore): %0.1f%%", cg3_inst.get_inst_coverage());
|
||||
$display("CG4 (4 autobins): %0.1f%%", cg4_inst.get_inst_coverage());
|
||||
$display("CG5 (2 autobins w/ option): %0.1f%%", cg5_inst.get_inst_coverage());
|
||||
|
||||
// Validate coverage results
|
||||
if (cg1_inst.get_inst_coverage() < 30.0 || cg1_inst.get_inst_coverage() > 45.0) begin
|
||||
$display("FAIL: CG1 coverage out of range");
|
||||
$stop;
|
||||
end
|
||||
if (cg2_inst.get_inst_coverage() < 45.0 || cg2_inst.get_inst_coverage() > 55.0) begin
|
||||
$display("FAIL: CG2 coverage should be 50%% (2/4 bins with auto_bin_max=4)");
|
||||
$stop;
|
||||
end
|
||||
if (cg3_inst.get_inst_coverage() < 27.0 || cg3_inst.get_inst_coverage() > 30.0) begin
|
||||
$display("FAIL: CG3 coverage should be ~28.6%% (2/7 valid bins, value 7 ignored)");
|
||||
$stop;
|
||||
end
|
||||
if (cg4_inst.get_inst_coverage() < 95.0) begin
|
||||
$display("FAIL: CG4 coverage should be 100%%");
|
||||
$stop;
|
||||
end
|
||||
if (cg5_inst.get_inst_coverage() < 99.0) begin
|
||||
$display("FAIL: CG5 coverage should be 100%% (2/2 bins with auto_bin_max=2)");
|
||||
$stop;
|
||||
end
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
%Error: t/t_covergroup_autobins_bad.v:17:18: Automatic bins array size must be a constant
|
||||
: ... note: In instance 't'
|
||||
17 | bins auto[size_var];
|
||||
| ^~~~
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
%Error: t/t_covergroup_autobins_bad.v:24:18: Automatic bins array size must be 1-10000, got 0
|
||||
: ... note: In instance 't'
|
||||
24 | bins auto[0];
|
||||
| ^~~~
|
||||
%Error: t/t_covergroup_autobins_bad.v:31:18: Automatic bins array size must be 1-10000, got 10001
|
||||
: ... note: In instance 't'
|
||||
31 | bins auto[10001];
|
||||
| ^~~~
|
||||
%Error: Exiting due to
|
||||
|
|
@ -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: 2025 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.lint(expect_filename=test.golden_filename,
|
||||
verilator_flags2=['--error-limit 1000'],
|
||||
fails=True)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-FileCopyrightText: 2025 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Tests for automatic bins error conditions
|
||||
|
||||
module t;
|
||||
int size_var;
|
||||
logic [3:0] cp_expr;
|
||||
|
||||
// Error: array size must be a constant
|
||||
covergroup cg1;
|
||||
cp1: coverpoint cp_expr {
|
||||
bins auto[size_var];
|
||||
}
|
||||
endgroup
|
||||
|
||||
// Error: array size must be 1-10000 (zero)
|
||||
covergroup cg2;
|
||||
cp1: coverpoint cp_expr {
|
||||
bins auto[0];
|
||||
}
|
||||
endgroup
|
||||
|
||||
// Error: array size must be 1-10000 (too large)
|
||||
covergroup cg3;
|
||||
cp1: coverpoint cp_expr {
|
||||
bins auto[10001];
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg1 cg1_inst = new;
|
||||
cg2 cg2_inst = new;
|
||||
cg3 cg3_inst = new;
|
||||
|
||||
initial $finish;
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2024 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test advanced bin types that ARE supported:
|
||||
// - ignore_bins
|
||||
// - wildcard bins
|
||||
// - array bins (explicit values only, not ranges yet)
|
||||
|
||||
module t;
|
||||
|
||||
logic [3:0] data;
|
||||
int error_count = 0;
|
||||
|
||||
// Test 1: ignore_bins
|
||||
covergroup cg_ignore;
|
||||
coverpoint data {
|
||||
bins low = {[0:3]};
|
||||
bins mid = {[4:7]};
|
||||
bins high = {[8:11]};
|
||||
ignore_bins reserved = {[12:15]}; // Should not count toward coverage
|
||||
}
|
||||
endgroup
|
||||
|
||||
// Test 2: Array bins (with ranges - now working!)
|
||||
covergroup cg_array;
|
||||
coverpoint data {
|
||||
bins values[] = {[0:3]}; // Creates 4 bins: values[0], values[1], values[2], values[3]
|
||||
}
|
||||
endgroup
|
||||
|
||||
// Test 3: wildcard bins (with don't-care bits)
|
||||
covergroup cg_wildcard;
|
||||
coverpoint data {
|
||||
wildcard bins pattern0 = {4'b00??}; // Matches 0,1,2,3
|
||||
wildcard bins pattern1 = {4'b01??}; // Matches 4,5,6,7
|
||||
wildcard bins pattern2 = {4'b10??}; // Matches 8,9,10,11
|
||||
wildcard bins pattern3 = {4'b11??}; // Matches 12,13,14,15
|
||||
}
|
||||
endgroup
|
||||
|
||||
initial begin
|
||||
cg_ignore cg1;
|
||||
cg_array cg2;
|
||||
cg_wildcard cg3;
|
||||
real cov;
|
||||
|
||||
cg1 = new;
|
||||
cg2 = new;
|
||||
cg3 = new;
|
||||
|
||||
// Test 1: ignore_bins
|
||||
$display("Test 1: ignore_bins");
|
||||
data = 0; cg1.sample(); // low
|
||||
data = 5; cg1.sample(); // mid
|
||||
data = 9; cg1.sample(); // high
|
||||
data = 12; cg1.sample(); // ignored - should not affect coverage
|
||||
data = 13; cg1.sample(); // ignored
|
||||
|
||||
cov = cg1.get_inst_coverage();
|
||||
$display(" Coverage with ignore_bins: %0.1f%% (expect 100%%)", cov);
|
||||
// 3 out of 3 non-ignored bins = 100%
|
||||
if (cov < 99.0 || cov > 101.0) begin
|
||||
$display("%%Error: Expected 100%%, got %0.1f%%", cov);
|
||||
error_count++;
|
||||
end
|
||||
|
||||
// Test 2: Array bins
|
||||
$display("Test 2: Array bins (with ranges)");
|
||||
data = 0; cg2.sample(); // values[0]
|
||||
data = 1; cg2.sample(); // values[1]
|
||||
data = 2; cg2.sample(); // values[2]
|
||||
// Note: values[3] not sampled, so 75% coverage expected
|
||||
|
||||
cov = cg2.get_inst_coverage();
|
||||
$display(" Coverage with array bins: %0.1f%% (expect 75%%)", cov);
|
||||
// 3 out of 4 bins = 75%
|
||||
if (cov < 74.0 || cov > 76.0) begin
|
||||
$display("%%Error: Expected 75%%, got %0.1f%%", cov);
|
||||
error_count++;
|
||||
end
|
||||
|
||||
// Test 3: Wildcard bins
|
||||
$display("Test 3: Wildcard bins");
|
||||
data = 2; cg3.sample(); // pattern0 (00??)
|
||||
data = 5; cg3.sample(); // pattern1 (01??)
|
||||
data = 10; cg3.sample(); // pattern2 (10??)
|
||||
// pattern3 not sampled, so 75% coverage
|
||||
|
||||
cov = cg3.get_inst_coverage();
|
||||
$display(" Coverage with wildcard bins: %0.1f%% (expect 75%%)", cov);
|
||||
// 3 out of 4 bins = 75%
|
||||
if (cov < 74.0 || cov > 76.0) begin
|
||||
$display("%%Error: Expected 75%%, got %0.1f%%", cov);
|
||||
error_count++;
|
||||
end
|
||||
|
||||
if (error_count == 0) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
end else begin
|
||||
$display("%%Error: %0d test(s) failed", error_count);
|
||||
$stop;
|
||||
end
|
||||
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2024 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test default bins and illegal_bins
|
||||
|
||||
module t;
|
||||
|
||||
logic [3:0] data;
|
||||
int error_count = 0;
|
||||
|
||||
// Test 1: default bins
|
||||
covergroup cg_default;
|
||||
coverpoint data {
|
||||
bins special = {0, 5, 10};
|
||||
bins others = default; // Catch-all for uncovered values
|
||||
}
|
||||
endgroup
|
||||
|
||||
// Test 2: illegal_bins (we'll test it doesn't crash on valid values)
|
||||
covergroup cg_valid;
|
||||
coverpoint data {
|
||||
bins valid = {[0:10]};
|
||||
illegal_bins reserved = {[11:15]};
|
||||
}
|
||||
endgroup
|
||||
|
||||
initial begin
|
||||
cg_default cg1;
|
||||
cg_valid cg2;
|
||||
real cov;
|
||||
|
||||
cg1 = new;
|
||||
cg2 = new;
|
||||
|
||||
// Test 1: default bins
|
||||
$display("Test 1: default bins");
|
||||
data = 0; cg1.sample(); // special bin
|
||||
data = 1; cg1.sample(); // default/others bin
|
||||
data = 5; cg1.sample(); // special bin
|
||||
data = 7; cg1.sample(); // default/others bin
|
||||
data = 10; cg1.sample(); // special bin
|
||||
|
||||
cov = cg1.get_inst_coverage();
|
||||
$display(" Coverage with default bins: %0.1f%%", cov);
|
||||
// Both bins hit: special (3 values: 0,5,10) and default (2 values: 1,7)
|
||||
// Expected: 2/2 = 100%
|
||||
if (cov < 99.0 || cov > 101.0) begin
|
||||
$display("%%Error: Expected 100%%, got %0.1f%%", cov);
|
||||
error_count++;
|
||||
end
|
||||
|
||||
// Test 2: illegal_bins (test with valid values only)
|
||||
$display("Test 2: illegal_bins (sampling valid values)");
|
||||
data = 0; cg2.sample(); // valid
|
||||
data = 5; cg2.sample(); // valid
|
||||
data = 10; cg2.sample(); // valid
|
||||
|
||||
cov = cg2.get_inst_coverage();
|
||||
$display(" Coverage with illegal_bins: %0.1f%%", cov);
|
||||
// Only the valid bin counts, illegal bins don't count toward coverage
|
||||
// 1 bin out of 1 = 100%
|
||||
if (cov < 99.0 || cov > 101.0) begin
|
||||
$display("%%Error: Expected 100%%, got %0.1f%%", cov);
|
||||
error_count++;
|
||||
end
|
||||
|
||||
if (error_count == 0) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
end else begin
|
||||
$display("%%Error: %0d test(s) failed", error_count);
|
||||
$stop;
|
||||
end
|
||||
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
#!/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('vlt')
|
||||
|
||||
# This test documents a known Verilator timing limitation:
|
||||
# Internal clocks (generated via `always #5 clk = ~clk`) don't properly
|
||||
# trigger procedural blocks in --timing mode. Even explicit .sample() calls
|
||||
# in always @(posedge clk) blocks don't execute.
|
||||
#
|
||||
# Root cause: Timing scheduler doesn't trigger NBA/active regions for
|
||||
# internally generated clock edges.
|
||||
#
|
||||
# Workaround: Use module input clocks (see t_covergroup_auto_sample.v)
|
||||
test.compile(verilator_flags2=["--timing"])
|
||||
|
||||
test.execute(fails=True, expect=r'%Error: .*Timeout')
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test: Covergroup with INTERNAL clock using explicit sampling
|
||||
// This demonstrates the workaround for internally generated clocks.
|
||||
//
|
||||
// Note: Auto-sampling with clocking events (@(posedge clk)) does NOT work
|
||||
// for internal clocks due to Verilator timing scheduler limitations.
|
||||
// The sample() call is generated but the NBA region isn't triggered.
|
||||
//
|
||||
// Solution: Call .sample() explicitly in an always block.
|
||||
|
||||
module t;
|
||||
logic clk = 0;
|
||||
always #5 clk = ~clk;
|
||||
|
||||
logic [1:0] data;
|
||||
|
||||
/* verilator lint_off UNSIGNED */
|
||||
covergroup cg; // NOTE: No clocking event - we'll sample explicitly
|
||||
cp: coverpoint data {
|
||||
bins val0 = {2'b00};
|
||||
bins val1 = {2'b01};
|
||||
bins val2 = {2'b10};
|
||||
bins val3 = {2'b11};
|
||||
}
|
||||
endgroup
|
||||
/* verilator lint_on UNSIGNED */
|
||||
|
||||
cg cg_inst = new;
|
||||
|
||||
// Explicit sampling workaround for internal clocks
|
||||
always @(posedge clk) begin
|
||||
cg_inst.sample();
|
||||
end
|
||||
|
||||
initial begin
|
||||
// Cycle 0
|
||||
data = 2'b00;
|
||||
@(posedge clk);
|
||||
|
||||
// Cycle 1
|
||||
data = 2'b01;
|
||||
@(posedge clk);
|
||||
|
||||
// Cycle 2
|
||||
data = 2'b10;
|
||||
@(posedge clk);
|
||||
|
||||
// Cycle 3
|
||||
data = 2'b11;
|
||||
@(posedge clk);
|
||||
|
||||
// Check coverage
|
||||
#1; // Small delay to ensure last sample completes
|
||||
|
||||
begin
|
||||
automatic real cov = cg_inst.get_inst_coverage();
|
||||
$display("Coverage: %0.1f%%", cov);
|
||||
|
||||
// Should have hit all 4 bins = 100%
|
||||
if (cov >= 99.0) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end else begin
|
||||
$display("ERROR: Expected 100%% coverage, got %f%%", cov);
|
||||
$display("ERROR: This is a known limitation - auto-sampling doesn't work with internal clocks");
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -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('vlt')
|
||||
|
||||
test.compile()
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test: Covergroup with clocking event using MODULE INPUT clock
|
||||
// Status: WORKS - Verilator correctly auto-samples when clk is a module port
|
||||
|
||||
module t(/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
logic [1:0] data;
|
||||
|
||||
/* verilator lint_off UNSIGNED */
|
||||
covergroup cg @(posedge clk);
|
||||
cp: coverpoint data {
|
||||
bins val0 = {2'b00};
|
||||
bins val1 = {2'b01};
|
||||
bins val2 = {2'b10};
|
||||
bins val3 = {2'b11};
|
||||
}
|
||||
endgroup
|
||||
/* verilator lint_on UNSIGNED */
|
||||
|
||||
cg cg_inst = new;
|
||||
|
||||
int cyc = 0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
|
||||
// Change data each cycle
|
||||
data <= cyc[1:0];
|
||||
|
||||
if (cyc == 5) begin
|
||||
/* verilator lint_off IMPLICITSTATIC */
|
||||
real cov = cg_inst.get_inst_coverage();
|
||||
/* verilator lint_on IMPLICITSTATIC */
|
||||
$display("Coverage: %0.1f%%", cov);
|
||||
|
||||
// Should have hit all 4 bins (cycles 0-3) = 100%
|
||||
if (cov >= 99.0) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end else begin
|
||||
$display("ERROR: Expected 100%% coverage, got %f%%", cov);
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
|
||||
if (cyc > 10) begin
|
||||
$display("ERROR: Test timeout");
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2024 by Wilson Snyder. 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: 2024 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.compile(verilator_flags2=['--timing'])
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2024 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
logic [1:0] data;
|
||||
|
||||
// Covergroup with 4 bins
|
||||
covergroup cg @(posedge clk);
|
||||
cp: coverpoint data {
|
||||
bins low = {2'b00};
|
||||
bins mid1 = {2'b01};
|
||||
bins mid2 = {2'b10};
|
||||
bins high = {2'b11};
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg cg_inst = new;
|
||||
|
||||
initial begin
|
||||
// Initially no bins covered - should be 0%
|
||||
real cov;
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display("Coverage after 0 samples: %f", cov);
|
||||
if (cov != 0.0) $stop;
|
||||
|
||||
// Cover 1 bin (low) - should be 25%
|
||||
@(posedge clk);
|
||||
data = 2'b00;
|
||||
@(posedge clk);
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display("Coverage after 1/4 bins: %f", cov);
|
||||
if (cov < 24.9 || cov > 25.1) begin
|
||||
$display("%%Error: Expected 25%%, got %f", cov);
|
||||
$stop;
|
||||
end
|
||||
|
||||
// Cover 2nd bin (mid1) - should be 50%
|
||||
@(posedge clk);
|
||||
data = 2'b01;
|
||||
@(posedge clk);
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display("Coverage after 2/4 bins: %f", cov);
|
||||
if (cov < 49.9 || cov > 50.1) begin
|
||||
$display("%%Error: Expected 50%%, got %f", cov);
|
||||
$stop;
|
||||
end
|
||||
|
||||
// Cover 3rd bin (mid2) - should be 75%
|
||||
@(posedge clk);
|
||||
data = 2'b10;
|
||||
@(posedge clk);
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display("Coverage after 3/4 bins: %f", cov);
|
||||
if (cov < 74.9 || cov > 75.1) begin
|
||||
$display("%%Error: Expected 75%%, got %f", cov);
|
||||
$stop;
|
||||
end
|
||||
|
||||
// Cover 4th bin (high) - should be 100%
|
||||
@(posedge clk);
|
||||
data = 2'b11;
|
||||
@(posedge clk);
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display("Coverage after 4/4 bins: %f", cov);
|
||||
if (cov < 99.9 || cov > 100.1) begin
|
||||
$display("%%Error: Expected 100%%, got %f", cov);
|
||||
$stop;
|
||||
end
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2024 by Wilson Snyder. 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: 2024 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.compile()
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain
|
||||
// SPDX-FileCopyrightText: 2026 Matthew Ballance
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test 3-way cross coverage
|
||||
|
||||
module t;
|
||||
logic [1:0] addr;
|
||||
logic cmd;
|
||||
logic mode;
|
||||
|
||||
// Covergroup with 3-way cross coverage
|
||||
covergroup cg;
|
||||
cp_addr: coverpoint addr {
|
||||
bins addr0 = {0};
|
||||
bins addr1 = {1};
|
||||
bins addr2 = {2};
|
||||
}
|
||||
cp_cmd: coverpoint cmd {
|
||||
bins read = {0};
|
||||
bins write = {1};
|
||||
}
|
||||
cp_mode: coverpoint mode {
|
||||
bins normal = {0};
|
||||
bins debug = {1};
|
||||
}
|
||||
// 3-way cross: addr x cmd x mode = 3 x 2 x 2 = 12 cross bins
|
||||
addr_cmd_mode: cross cp_addr, cp_cmd, cp_mode;
|
||||
endgroup
|
||||
|
||||
cg cg_inst = new;
|
||||
|
||||
initial begin
|
||||
// Hit different 3-way cross bins
|
||||
addr = 0; cmd = 0; mode = 0; cg_inst.sample(); // addr0 x read x normal
|
||||
$display("Sample 1: addr=%0d, cmd=%0d, mode=%0d", addr, cmd, mode);
|
||||
|
||||
addr = 1; cmd = 1; mode = 0; cg_inst.sample(); // addr1 x write x normal
|
||||
$display("Sample 2: addr=%0d, cmd=%0d, mode=%0d", addr, cmd, mode);
|
||||
|
||||
addr = 2; cmd = 0; mode = 1; cg_inst.sample(); // addr2 x read x debug
|
||||
$display("Sample 3: addr=%0d, cmd=%0d, mode=%0d", addr, cmd, mode);
|
||||
|
||||
addr = 0; cmd = 1; mode = 1; cg_inst.sample(); // addr0 x write x debug
|
||||
$display("Sample 4: addr=%0d, cmd=%0d, mode=%0d", addr, cmd, mode);
|
||||
|
||||
addr = 1; cmd = 0; mode = 1; cg_inst.sample(); // addr1 x read x debug
|
||||
$display("Sample 5: addr=%0d, cmd=%0d, mode=%0d", addr, cmd, mode);
|
||||
|
||||
// Check coverage
|
||||
// Total bins:
|
||||
// - 3 bins in cp_addr (addr0, addr1, addr2)
|
||||
// - 2 bins in cp_cmd (read, write)
|
||||
// - 2 bins in cp_mode (normal, debug)
|
||||
// - 12 bins in 3-way cross (3 x 2 x 2)
|
||||
// Total = 19 bins
|
||||
// Hit: addr0, addr1, addr2 (3), read, write (2), normal, debug (2), 5 cross bins
|
||||
// Total = 12 out of 19 = 63.2%
|
||||
$display("Coverage: %0.1f%%", cg_inst.get_inst_coverage());
|
||||
|
||||
if (cg_inst.get_inst_coverage() < 62.0 || cg_inst.get_inst_coverage() > 64.0) begin
|
||||
$display("%%Error: Expected coverage around 63%%, got %0.1f%%",
|
||||
cg_inst.get_inst_coverage());
|
||||
$stop;
|
||||
end
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2024 by Wilson Snyder. 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: 2024 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.compile()
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain
|
||||
// SPDX-FileCopyrightText: 2026 Matthew Ballance
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test 4-way cross coverage
|
||||
|
||||
module t;
|
||||
logic [1:0] addr;
|
||||
logic cmd;
|
||||
logic mode;
|
||||
logic parity;
|
||||
|
||||
// Covergroup with 4-way cross coverage
|
||||
covergroup cg;
|
||||
cp_addr: coverpoint addr {
|
||||
bins addr0 = {0};
|
||||
bins addr1 = {1};
|
||||
}
|
||||
cp_cmd: coverpoint cmd {
|
||||
bins read = {0};
|
||||
bins write = {1};
|
||||
}
|
||||
cp_mode: coverpoint mode {
|
||||
bins normal = {0};
|
||||
bins debug = {1};
|
||||
}
|
||||
cp_parity: coverpoint parity {
|
||||
bins even = {0};
|
||||
bins odd = {1};
|
||||
}
|
||||
// 4-way cross: addr x cmd x mode x parity = 2 x 2 x 2 x 2 = 16 cross bins
|
||||
addr_cmd_mode_parity: cross cp_addr, cp_cmd, cp_mode, cp_parity;
|
||||
endgroup
|
||||
|
||||
cg cg_inst = new;
|
||||
|
||||
initial begin
|
||||
// Hit different 4-way cross bins
|
||||
addr = 0; cmd = 0; mode = 0; parity = 0; cg_inst.sample();
|
||||
$display("Sample 1: addr=%0d, cmd=%0d, mode=%0d, parity=%0d", addr, cmd, mode, parity);
|
||||
|
||||
addr = 1; cmd = 1; mode = 0; parity = 1; cg_inst.sample();
|
||||
$display("Sample 2: addr=%0d, cmd=%0d, mode=%0d, parity=%0d", addr, cmd, mode, parity);
|
||||
|
||||
addr = 0; cmd = 1; mode = 1; parity = 0; cg_inst.sample();
|
||||
$display("Sample 3: addr=%0d, cmd=%0d, mode=%0d, parity=%0d", addr, cmd, mode, parity);
|
||||
|
||||
addr = 1; cmd = 0; mode = 1; parity = 1; cg_inst.sample();
|
||||
$display("Sample 4: addr=%0d, cmd=%0d, mode=%0d, parity=%0d", addr, cmd, mode, parity);
|
||||
|
||||
// Check coverage
|
||||
// Total bins:
|
||||
// - 2 bins in cp_addr
|
||||
// - 2 bins in cp_cmd
|
||||
// - 2 bins in cp_mode
|
||||
// - 2 bins in cp_parity
|
||||
// - 16 bins in 4-way cross (2 x 2 x 2 x 2)
|
||||
// Total = 24 bins
|
||||
// Hit: 2+2+2+2+4 = 12 out of 24 = 50%
|
||||
$display("Coverage: %0.1f%%", cg_inst.get_inst_coverage());
|
||||
|
||||
if (cg_inst.get_inst_coverage() < 49.0 || cg_inst.get_inst_coverage() > 51.0) begin
|
||||
$display("%%Error: Expected coverage around 50%%, got %0.1f%%",
|
||||
cg_inst.get_inst_coverage());
|
||||
$stop;
|
||||
end
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2024 by Wilson Snyder. 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: 2024 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.compile(make_main=False,
|
||||
verilator_flags2=["--coverage-user", "--exe", "t/t_covergroup_cross_large_main.cpp"])
|
||||
test.execute(check_finished=True)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2024 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test large cross coverage with sparse map implementation
|
||||
|
||||
module t(/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
int cyc = 0;
|
||||
|
||||
logic [3:0] a;
|
||||
logic [3:0] b;
|
||||
logic [3:0] c;
|
||||
logic [3:0] d;
|
||||
|
||||
covergroup cg @(posedge clk);
|
||||
option.per_instance = 1;
|
||||
|
||||
// Each coverpoint has 4 bins, total cross: 4444 = 256 bins
|
||||
// This exceeds threshold of 64, so should use sparse map
|
||||
cp_a: coverpoint a {
|
||||
bins a0 = {0,1,2,3};
|
||||
bins a1 = {4,5,6,7};
|
||||
bins a2 = {8,9,10,11};
|
||||
bins a3 = {12,13,14,15};
|
||||
}
|
||||
|
||||
cp_b: coverpoint b {
|
||||
bins b0 = {0,1,2,3};
|
||||
bins b1 = {4,5,6,7};
|
||||
bins b2 = {8,9,10,11};
|
||||
bins b3 = {12,13,14,15};
|
||||
}
|
||||
|
||||
cp_c: coverpoint c {
|
||||
bins c0 = {0,1,2,3};
|
||||
bins c1 = {4,5,6,7};
|
||||
bins c2 = {8,9,10,11};
|
||||
bins c3 = {12,13,14,15};
|
||||
}
|
||||
|
||||
cp_d: coverpoint d {
|
||||
bins d0 = {0,1,2,3};
|
||||
bins d1 = {4,5,6,7};
|
||||
bins d2 = {8,9,10,11};
|
||||
bins d3 = {12,13,14,15};
|
||||
}
|
||||
|
||||
// 4-way cross: 4444 = 256 bins (> 64 threshold)
|
||||
cross_abcd: cross cp_a, cp_b, cp_c, cp_d;
|
||||
endgroup
|
||||
|
||||
cg cg_inst = new;
|
||||
|
||||
always @(posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
|
||||
// Generate some cross coverage
|
||||
a <= cyc[3:0];
|
||||
b <= cyc[7:4];
|
||||
c <= cyc[3:0]; // Intentionally correlate some
|
||||
d <= cyc[7:4];
|
||||
|
||||
if (cyc == 20) begin
|
||||
/* verilator lint_off IMPLICITSTATIC */
|
||||
real inst_cov = cg_inst.get_inst_coverage();
|
||||
/* verilator lint_on IMPLICITSTATIC */
|
||||
$display("Coverage: %0.1f%%", inst_cov);
|
||||
|
||||
if (inst_cov < 1.0 || inst_cov > 100.0) begin
|
||||
$display("%%Error: Invalid coverage value");
|
||||
$stop;
|
||||
end
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2024 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
#include <verilated.h>
|
||||
|
||||
#include "Vt_covergroup_cross_large.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||
contextp->commandArgs(argc, argv);
|
||||
const std::unique_ptr<Vt_covergroup_cross_large> topp{
|
||||
new Vt_covergroup_cross_large{contextp.get()}};
|
||||
|
||||
topp->clk = 0;
|
||||
|
||||
while (!contextp->gotFinish() && contextp->time() < 100) {
|
||||
topp->clk = !topp->clk;
|
||||
topp->eval();
|
||||
contextp->timeInc(1);
|
||||
}
|
||||
|
||||
topp->final();
|
||||
contextp->coveragep()->write();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2024 by Wilson Snyder. 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: 2024 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.compile()
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain
|
||||
// SPDX-FileCopyrightText: 2026 Matthew Ballance
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test basic cross coverage with 2-way cross
|
||||
|
||||
module t;
|
||||
logic [1:0] addr;
|
||||
logic cmd;
|
||||
logic clk;
|
||||
|
||||
// Covergroup with cross coverage
|
||||
covergroup cg;
|
||||
cp_addr: coverpoint addr {
|
||||
bins addr0 = {0};
|
||||
bins addr1 = {1};
|
||||
bins addr2 = {2};
|
||||
bins addr3 = {3};
|
||||
}
|
||||
cp_cmd: coverpoint cmd {
|
||||
bins read = {0};
|
||||
bins write = {1};
|
||||
}
|
||||
// Cross coverage: addr x cmd = 4 x 2 = 8 bins
|
||||
addr_cmd: cross cp_addr, cp_cmd;
|
||||
endgroup
|
||||
|
||||
cg cg_inst = new;
|
||||
|
||||
initial begin
|
||||
// Hit different cross bins
|
||||
addr = 0; cmd = 0; cg_inst.sample(); // addr0 x read
|
||||
$display("After sample 1: addr=%0d, cmd=%0d", addr, cmd);
|
||||
|
||||
addr = 1; cmd = 1; cg_inst.sample(); // addr1 x write
|
||||
$display("After sample 2: addr=%0d, cmd=%0d", addr, cmd);
|
||||
|
||||
addr = 2; cmd = 0; cg_inst.sample(); // addr2 x read
|
||||
$display("After sample 3: addr=%0d, cmd=%0d", addr, cmd);
|
||||
|
||||
addr = 0; cmd = 1; cg_inst.sample(); // addr0 x write
|
||||
$display("After sample 4: addr=%0d, cmd=%0d", addr, cmd);
|
||||
|
||||
// Check coverage - should be 50% (4 out of 8 bins hit)
|
||||
// Actually, with cross bins, we have:
|
||||
// - 4 bins in cp_addr: addr0, addr1, addr2, addr3
|
||||
// - 2 bins in cp_cmd: read, write
|
||||
// - 8 bins in cross (4 x 2)
|
||||
// Hit: addr0, addr1, addr2 (3 bins), read, write (2 bins), 4 cross bins
|
||||
// Total = 9 out of 14 = 64.3%
|
||||
$display("Coverage: %0.1f%%", cg_inst.get_inst_coverage());
|
||||
|
||||
if (cg_inst.get_inst_coverage() < 63.0 || cg_inst.get_inst_coverage() > 65.0) begin
|
||||
$display("%%Error: Expected coverage around 64%%, got %0.1f%%",
|
||||
cg_inst.get_inst_coverage());
|
||||
$stop;
|
||||
end
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2024 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test small cross coverage with inline implementation
|
||||
|
||||
module t(/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
int cyc = 0;
|
||||
|
||||
logic [3:0] a;
|
||||
logic [3:0] b;
|
||||
|
||||
covergroup cg @(posedge clk);
|
||||
option.per_instance = 1;
|
||||
|
||||
// 2-way cross: 44 = 16 bins (< 64 threshold, should use inline)
|
||||
cp_a: coverpoint a {
|
||||
bins a0 = {0,1,2,3};
|
||||
bins a1 = {4,5,6,7};
|
||||
bins a2 = {8,9,10,11};
|
||||
bins a3 = {12,13,14,15};
|
||||
}
|
||||
|
||||
cp_b: coverpoint b {
|
||||
bins b0 = {0,1,2,3};
|
||||
bins b1 = {4,5,6,7};
|
||||
bins b2 = {8,9,10,11};
|
||||
bins b3 = {12,13,14,15};
|
||||
}
|
||||
|
||||
cross_ab: cross cp_a, cp_b;
|
||||
endgroup
|
||||
|
||||
cg cg_inst = new;
|
||||
|
||||
always @(posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
|
||||
a <= cyc[3:0];
|
||||
b <= cyc[7:4];
|
||||
|
||||
if (cyc == 20) begin
|
||||
/* verilator lint_off IMPLICITSTATIC */
|
||||
real inst_cov = cg_inst.get_inst_coverage();
|
||||
/* verilator lint_on IMPLICITSTATIC */
|
||||
$display("Coverage: %0.1f%%", inst_cov);
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2024 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test dynamic covergroup creation with 'new' operator
|
||||
|
||||
module t;
|
||||
|
||||
covergroup cg;
|
||||
coverpoint data {
|
||||
bins low = {[0:1]};
|
||||
bins high = {[2:3]};
|
||||
}
|
||||
endgroup
|
||||
|
||||
int data;
|
||||
|
||||
initial begin
|
||||
cg cg_inst;
|
||||
real cov;
|
||||
|
||||
// Test 1: Create single dynamic instance
|
||||
$display("Test 1: Single dynamic instance");
|
||||
cg_inst = new;
|
||||
|
||||
// Initially no coverage
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display(" Initial coverage: %f", cov);
|
||||
if (cov != 0.0) $stop;
|
||||
|
||||
// Sample low bin
|
||||
data = 0;
|
||||
cg_inst.sample();
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display(" After sampling low: %f", cov);
|
||||
if (cov < 49.0 || cov > 51.0) $stop; // ~50%
|
||||
|
||||
// Sample high bin
|
||||
data = 2;
|
||||
cg_inst.sample();
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display(" After sampling high: %f", cov);
|
||||
if (cov < 99.0 || cov > 101.0) $stop; // ~100%
|
||||
|
||||
// Test 2: Multiple dynamic instances
|
||||
$display("Test 2: Multiple dynamic instances");
|
||||
begin
|
||||
cg cg1, cg2, cg3;
|
||||
|
||||
cg1 = new;
|
||||
cg2 = new;
|
||||
cg3 = new;
|
||||
|
||||
// Sample different bins in each
|
||||
data = 0;
|
||||
cg1.sample();
|
||||
|
||||
data = 2;
|
||||
cg2.sample();
|
||||
|
||||
data = 1;
|
||||
cg3.sample();
|
||||
|
||||
// Check individual coverage
|
||||
cov = cg1.get_inst_coverage();
|
||||
$display(" cg1 coverage: %f", cov);
|
||||
if (cov < 49.0 || cov > 51.0) $stop; // 50%
|
||||
|
||||
cov = cg2.get_inst_coverage();
|
||||
$display(" cg2 coverage: %f", cov);
|
||||
if (cov < 49.0 || cov > 51.0) $stop; // 50%
|
||||
|
||||
cov = cg3.get_inst_coverage();
|
||||
$display(" cg3 coverage: %f", cov);
|
||||
if (cov < 49.0 || cov > 51.0) $stop; // 50%
|
||||
end
|
||||
|
||||
// Test 3: Reassignment (old instance should be cleaned up)
|
||||
$display("Test 3: Instance reassignment");
|
||||
cg_inst = new; // Create new, old should be freed
|
||||
|
||||
// New instance starts with 0% coverage
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display(" New instance coverage: %f", cov);
|
||||
if (cov != 0.0) $stop;
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
// Simple test harness for t_covergroup_empty - provides clock
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2026 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
#include "verilated.h"
|
||||
|
||||
#include "Vt_covergroup_empty.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
Verilated::commandArgs(argc, argv);
|
||||
Vt_covergroup_empty* top = new Vt_covergroup_empty;
|
||||
|
||||
// Run for 20 cycles
|
||||
for (int i = 0; i < 20; i++) {
|
||||
top->clk = 0;
|
||||
top->eval();
|
||||
top->clk = 1;
|
||||
top->eval();
|
||||
|
||||
if (Verilated::gotFinish()) break;
|
||||
}
|
||||
|
||||
delete top;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.compile()
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module - Edge case: empty covergroup
|
||||
// This file ONLY is placed into the Public Domain, for any use, without warranty.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test: Empty covergroup (no coverpoints)
|
||||
// Expected: Should compile, coverage should be 100% (nothing to cover)
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
logic [7:0] value;
|
||||
|
||||
// Empty covergroup - no coverpoints defined
|
||||
covergroup cg_empty;
|
||||
// Intentionally empty
|
||||
endgroup
|
||||
|
||||
cg_empty cg_inst = new;
|
||||
|
||||
int cyc = 0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
value <= value + 1;
|
||||
|
||||
cg_inst.sample();
|
||||
|
||||
if (cyc == 5) begin
|
||||
// Get coverage - should be 100% (nothing to fail)
|
||||
begin
|
||||
real cov;
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display("Empty covergroup coverage: %f%%", cov);
|
||||
|
||||
// Empty covergroup should report 100% coverage
|
||||
if (cov >= 99.9) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end else begin
|
||||
$display("ERROR: Expected 100%% coverage for empty covergroup, got %f%%", cov);
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (cyc > 10) begin
|
||||
$display("ERROR: Test timed out");
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -11,6 +11,11 @@ import vltest_bootstrap
|
|||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.compile()
|
||||
# Covergroup inheritance with 'extends' is not yet supported
|
||||
test.compile(
|
||||
fails=test.vlt_all,
|
||||
expect=
|
||||
r'%Error: t/t_covergroup_extends.v:\d+:\d+: Unsupported: covergroup inheritance \(extends\) is not implemented'
|
||||
)
|
||||
|
||||
test.passes()
|
||||
|
|
|
|||
|
|
@ -11,6 +11,11 @@ import vltest_bootstrap
|
|||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.compile()
|
||||
# Covergroup inheritance with 'extends' is not yet supported
|
||||
test.compile(
|
||||
fails=test.vlt_all,
|
||||
expect=
|
||||
r'%Error: t/t_covergroup_extends_newfirst.v:\d+:\d+: Unsupported: covergroup inheritance \(extends\) is not implemented'
|
||||
)
|
||||
|
||||
test.passes()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.compile()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2026 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t (input clk);
|
||||
int value = 0;
|
||||
|
||||
covergroup cg;
|
||||
cp: coverpoint value {
|
||||
bins low = {[0:5]};
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg my_cg = new;
|
||||
|
||||
always @(posedge clk) begin
|
||||
real cov;
|
||||
cov = my_cg.get_inst_coverage();
|
||||
my_cg.sample();
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -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
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.compile()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2026 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t (input clk);
|
||||
logic enable = 0;
|
||||
int value = 0;
|
||||
|
||||
covergroup cg_iff;
|
||||
cp_value: coverpoint value iff (enable) {
|
||||
bins low = {[0:5]};
|
||||
bins mid = {[6:10]};
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg_iff cg = new;
|
||||
|
||||
always @(posedge clk) begin
|
||||
cg.sample();
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
Coverage: 0.0%
|
||||
*-* All Finished *-*
|
||||
|
|
@ -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('vlt')
|
||||
|
||||
test.compile()
|
||||
|
||||
test.execute(expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain
|
||||
// SPDX-FileCopyrightText: 2026 Matthew Ballance
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Minimal test for covergroup parsing and code generation
|
||||
|
||||
module t;
|
||||
int unsigned addr; // Use unsigned to avoid comparison warnings
|
||||
|
||||
covergroup cg;
|
||||
cp_addr: coverpoint addr {
|
||||
bins low = {[0:127]};
|
||||
bins high = {[128:255]};
|
||||
}
|
||||
endgroup
|
||||
|
||||
initial begin
|
||||
cg cg_inst;
|
||||
cg_inst = new;
|
||||
|
||||
// Sample some values
|
||||
addr = 10;
|
||||
cg_inst.sample();
|
||||
|
||||
addr = 200;
|
||||
cg_inst.sample();
|
||||
|
||||
$display("Coverage: %0.1f%%", cg_inst.get_coverage());
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.compile()
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module - Edge case: multiple instances
|
||||
// This file ONLY is placed into the Public Domain, for any use, without warranty.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test: Multiple instances of same covergroup type sampling the same coverpoint
|
||||
// Expected: Each instance tracks coverage independently, achieving same coverage
|
||||
// since they all sample the same expression (value1)
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
logic [2:0] value1;
|
||||
|
||||
covergroup cg;
|
||||
cp: coverpoint value1 {
|
||||
bins low = {[0:3]};
|
||||
bins high = {[4:7]};
|
||||
}
|
||||
endgroup
|
||||
|
||||
// Create three independent instances
|
||||
cg cg_inst1 = new;
|
||||
cg cg_inst2 = new;
|
||||
cg cg_inst3 = new;
|
||||
|
||||
int cyc = 0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
|
||||
case (cyc)
|
||||
0: begin
|
||||
value1 <= 1; // low bin for all instances
|
||||
end
|
||||
1: begin
|
||||
value1 <= 6; // high bin for all instances -> 100%
|
||||
end
|
||||
2: begin
|
||||
begin
|
||||
real cov1, cov2, cov3;
|
||||
cov1 = cg_inst1.get_inst_coverage();
|
||||
cov2 = cg_inst2.get_inst_coverage();
|
||||
cov3 = cg_inst3.get_inst_coverage();
|
||||
|
||||
$display("Instance 1 coverage: %f%%", cov1);
|
||||
$display("Instance 2 coverage: %f%%", cov2);
|
||||
$display("Instance 3 coverage: %f%%", cov3);
|
||||
|
||||
// All instances sample the same coverpoint (value1), so they should all be 100%
|
||||
// This tests that multiple instances track coverage independently,
|
||||
// even when sampling the same expression
|
||||
if (cov1 >= 99.0 && cov2 >= 99.0 && cov3 >= 99.0) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end else begin
|
||||
$display("ERROR: Coverage mismatch");
|
||||
$display(" Expected: inst1=100%%, inst2=100%%, inst3=100%%");
|
||||
$display(" Got: inst1=%f%%, inst2=%f%%, inst3=%f%%", cov1, cov2, cov3);
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
end
|
||||
endcase
|
||||
|
||||
// Each instance samples the same value (value1)
|
||||
// But tracks coverage independently
|
||||
cg_inst1.sample();
|
||||
cg_inst2.sample();
|
||||
cg_inst3.sample();
|
||||
|
||||
if (cyc > 10) begin
|
||||
$display("ERROR: Test timed out");
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.compile()
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module - Edge case: negative value ranges
|
||||
// This file ONLY is placed into the Public Domain, for any use, without warranty.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test: Bins with negative value ranges
|
||||
// Expected: Should handle negative numbers correctly
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
int signed value;
|
||||
|
||||
/* verilator lint_off CMPCONST */
|
||||
covergroup cg;
|
||||
cp_neg: coverpoint value {
|
||||
bins negative = {[-100:-1]};
|
||||
bins zero = {0};
|
||||
bins positive = {[1:100]};
|
||||
bins mixed = {[-10:10]};
|
||||
}
|
||||
endgroup
|
||||
/* verilator lint_on CMPCONST */
|
||||
|
||||
cg cg_inst = new;
|
||||
|
||||
int cyc = 0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
|
||||
case (cyc)
|
||||
0: value <= -50; // Hit negative bin
|
||||
1: value <= 0; // Hit zero bin
|
||||
2: value <= 50; // Hit positive bin
|
||||
3: value <= -5; // Hit mixed bin (also negative)
|
||||
4: value <= 5; // Hit mixed bin (also positive)
|
||||
5: begin
|
||||
begin
|
||||
real cov;
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display("Coverage with negative ranges: %f%%", cov);
|
||||
|
||||
// All 4 bins should be hit = 100%
|
||||
if (cov >= 99.0) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end else begin
|
||||
$display("ERROR: Expected 100%% coverage, got %f%%", cov);
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
end
|
||||
endcase
|
||||
|
||||
cg_inst.sample();
|
||||
|
||||
if (cyc > 10) begin
|
||||
$display("ERROR: Test timed out");
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
%Warning-COVERIGN: t/t_covergroup_option_unsup.v:15:13: Ignoring unsupported coverage option: foobar
|
||||
15 | option.foobar = 1;
|
||||
| ^~~~~~
|
||||
... 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: Exiting due to
|
||||
|
|
@ -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: 2025 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.lint(expect_filename=test.golden_filename, fails=True)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-FileCopyrightText: 2025 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test: unsupported coverage option name in a coverpoint
|
||||
|
||||
module t;
|
||||
logic [3:0] cp_expr;
|
||||
|
||||
covergroup cg;
|
||||
cp1: coverpoint cp_expr {
|
||||
option.foobar = 1;
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg cg_inst = new;
|
||||
initial $finish;
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2024 by Wilson Snyder. 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: 2024 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
test.compile(verilator_flags2=["--coverage-user"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain
|
||||
// SPDX-FileCopyrightText: 2026 Matthew Ballance
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Performance test for functional coverage - measures sample() overhead
|
||||
|
||||
module t;
|
||||
logic [7:0] data;
|
||||
logic [3:0] state;
|
||||
logic [15:0] addr;
|
||||
|
||||
// Large covergroup with multiple coverpoints and many bins
|
||||
covergroup cg_perf;
|
||||
// Coverpoint with many bins
|
||||
cp_data: coverpoint data {
|
||||
bins d0 = {0};
|
||||
bins d1 = {1};
|
||||
bins d2 = {2};
|
||||
bins d3 = {3};
|
||||
bins d4 = {4};
|
||||
bins d5 = {5};
|
||||
bins d6 = {6};
|
||||
bins d7 = {7};
|
||||
bins d8 = {8};
|
||||
bins d9 = {9};
|
||||
bins d10 = {[10:19]};
|
||||
bins d20 = {[20:29]};
|
||||
bins d30 = {[30:39]};
|
||||
bins d40 = {[40:49]};
|
||||
bins d50 = {[50:59]};
|
||||
bins rest = {[60:255]};
|
||||
}
|
||||
|
||||
cp_state: coverpoint state {
|
||||
bins s0 = {0};
|
||||
bins s1 = {1};
|
||||
bins s2 = {2};
|
||||
bins s3 = {3};
|
||||
bins s4 = {4};
|
||||
bins s5 = {5};
|
||||
bins s6 = {6};
|
||||
bins s7 = {7};
|
||||
bins s8 = {8};
|
||||
bins s9 = {9};
|
||||
bins s10 = {10};
|
||||
bins s11 = {11};
|
||||
bins s12 = {12};
|
||||
bins s13 = {13};
|
||||
bins s14 = {14};
|
||||
bins s15 = {15};
|
||||
}
|
||||
|
||||
// verilator lint_off UNSIGNED
|
||||
// verilator lint_off CMPCONST
|
||||
cp_addr: coverpoint addr {
|
||||
bins low = {[16'h0000:16'h03FF]}; // [0:1023]
|
||||
bins mid = {[16'h0400:16'h07FF]}; // [1024:2047]
|
||||
bins high = {[16'h0800:16'hFFFF]}; // [2048:65535]
|
||||
}
|
||||
// verilator lint_on CMPCONST
|
||||
// verilator lint_on UNSIGNED
|
||||
|
||||
// Cross coverage adds more bins
|
||||
cross_data_state: cross cp_data, cp_state;
|
||||
endgroup
|
||||
|
||||
cg_perf cg_inst = new;
|
||||
|
||||
initial begin
|
||||
automatic longint start_time, end_time, elapsed;
|
||||
automatic int iterations = 100000;
|
||||
automatic real avg_time_ns;
|
||||
|
||||
$display("=== Functional Coverage Performance Test ===");
|
||||
$display("Iterations: %0d", iterations);
|
||||
|
||||
// Measure sample() overhead
|
||||
start_time = $time;
|
||||
|
||||
for (int i = 0; i < iterations; i++) begin
|
||||
// Vary the data to hit different bins
|
||||
data = i[7:0];
|
||||
state = i[3:0];
|
||||
addr = i[15:0];
|
||||
|
||||
cg_inst.sample();
|
||||
end
|
||||
|
||||
end_time = $time;
|
||||
elapsed = end_time - start_time;
|
||||
|
||||
avg_time_ns = real'(elapsed) / real'(iterations);
|
||||
|
||||
$display("Total time: %0d time units", elapsed);
|
||||
$display("Average time per sample(): %0.2f time units", avg_time_ns);
|
||||
$display("Coverage: %0.1f%%", cg_inst.get_inst_coverage());
|
||||
|
||||
// Performance target: < 100 cycles per sample()
|
||||
// Assuming 1 time unit = 1 ns, typical CPU @ 3 GHz = 0.33 ns/cycle
|
||||
// 100 cycles = 33 ns
|
||||
if (avg_time_ns < 33.0) begin
|
||||
$display("PASS: Performance within target (< 100 cycles)");
|
||||
end else begin
|
||||
$display("WARNING: Performance may need optimization (> 100 cycles)");
|
||||
end
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -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('vlt')
|
||||
|
||||
test.compile(verilator_flags2=['--timing'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain
|
||||
// SPDX-FileCopyrightText: 2026 Matthew Ballance
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test basic covergroup with simple coverpoint
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
logic [7:0] addr;
|
||||
logic cmd;
|
||||
|
||||
// Simple covergroup with two coverpoints
|
||||
covergroup cg @(posedge clk);
|
||||
cp_addr: coverpoint addr {
|
||||
bins low = {[0:127]};
|
||||
bins high = {[128:255]};
|
||||
}
|
||||
cp_cmd: coverpoint cmd {
|
||||
bins read = {0};
|
||||
bins write = {1};
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg cg_inst = new;
|
||||
|
||||
initial begin
|
||||
// Sample some values
|
||||
addr = 10; cmd = 0;
|
||||
@(posedge clk);
|
||||
|
||||
addr = 200; cmd = 1;
|
||||
@(posedge clk);
|
||||
|
||||
addr = 50; cmd = 0;
|
||||
@(posedge clk);
|
||||
|
||||
$display("Coverage: %0.1f%%", cg_inst.get_coverage());
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -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: 2024 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
# Type-level (static) coverage using cg::get_coverage() compiles but returns placeholder value
|
||||
# Test compiles successfully but runtime behavior is incorrect (returns 0.0)
|
||||
test.compile()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2024 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test static get_coverage() with multiple instances
|
||||
|
||||
module t;
|
||||
|
||||
covergroup cg;
|
||||
coverpoint data {
|
||||
bins low = {[0:1]};
|
||||
bins mid = {[2:3]};
|
||||
bins high = {[4:5]};
|
||||
}
|
||||
endgroup
|
||||
|
||||
int data;
|
||||
|
||||
initial begin
|
||||
cg cg1, cg2, cg3;
|
||||
real type_cov;
|
||||
|
||||
cg1 = new;
|
||||
cg2 = new;
|
||||
cg3 = new;
|
||||
|
||||
// Initially, no bins covered - should be 0%
|
||||
type_cov = cg::get_coverage();
|
||||
$display("Initial type coverage: %f", type_cov);
|
||||
if (type_cov != 0.0) $stop;
|
||||
|
||||
// Sample cg1 with low bin
|
||||
data = 0;
|
||||
cg1.sample();
|
||||
type_cov = cg::get_coverage();
|
||||
$display("After cg1.sample(low): %f", type_cov);
|
||||
// 1 bin covered out of 3 = 33.33%
|
||||
if (type_cov < 33.0 || type_cov > 34.0) $stop;
|
||||
|
||||
// Sample cg2 with mid bin
|
||||
data = 2;
|
||||
cg2.sample();
|
||||
type_cov = cg::get_coverage();
|
||||
$display("After cg2.sample(mid): %f", type_cov);
|
||||
// 2 bins covered out of 3 = 66.67%
|
||||
if (type_cov < 66.0 || type_cov > 67.0) $stop;
|
||||
|
||||
// Sample cg3 with high bin
|
||||
data = 4;
|
||||
cg3.sample();
|
||||
type_cov = cg::get_coverage();
|
||||
$display("After cg3.sample(high): %f", type_cov);
|
||||
// 3 bins covered out of 3 = 100%
|
||||
if (type_cov < 99.9 || type_cov > 100.1) $stop;
|
||||
|
||||
// Sample cg1 again with same bin - should not change coverage
|
||||
data = 1;
|
||||
cg1.sample();
|
||||
type_cov = cg::get_coverage();
|
||||
$display("After cg1.sample(low again): %f", type_cov);
|
||||
if (type_cov < 99.9 || type_cov > 100.1) $stop;
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#!/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('vlt')
|
||||
|
||||
# Multi-value (3+) transition bins generate incomplete case statements
|
||||
# This is a known limitation - complex transitions not fully supported
|
||||
test.compile(fails=test.vlt_all,
|
||||
expect=r'%Warning-CASEINCOMPLETE:.*Case values incompletely covered')
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
// DESCRIPTION: Verilator: Test transition bins - 3-value sequences
|
||||
// This file ONLY is placed into the Public Domain, for any use, without warranty.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t;
|
||||
logic [2:0] state;
|
||||
int errors = 0;
|
||||
|
||||
covergroup cg;
|
||||
cp_state: coverpoint state {
|
||||
bins trans_3val = (0 => 1 => 2); // 3-value sequence
|
||||
bins trans_3val_2 = (2 => 3 => 4); // Another 3-value sequence
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg cg_inst = new;
|
||||
|
||||
initial begin
|
||||
// Test sequence 1: 0 => 1 => 2 (should complete trans_3val)
|
||||
state = 0;
|
||||
cg_inst.sample();
|
||||
|
||||
state = 1; // 0 => 1 (state machine now at position 1)
|
||||
cg_inst.sample();
|
||||
|
||||
state = 2; // 1 => 2 (completes trans_3val: 0=>1=>2)
|
||||
cg_inst.sample();
|
||||
|
||||
// Test sequence 2: 2 => 3 => 4 (should complete trans_3val_2)
|
||||
state = 3; // 2 => 3 (state machine now at position 1 for trans_3val_2)
|
||||
cg_inst.sample();
|
||||
|
||||
state = 4; // 3 => 4 (completes trans_3val_2: 2=>3=>4)
|
||||
cg_inst.sample();
|
||||
|
||||
// Check coverage
|
||||
$display("Coverage: %f%%", cg_inst.get_inst_coverage());
|
||||
if (cg_inst.get_inst_coverage() < 99.0) begin
|
||||
$display("ERROR: Expected 100%% coverage, got %f%%", cg_inst.get_inst_coverage());
|
||||
errors++;
|
||||
end
|
||||
|
||||
if (errors == 0) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
end else begin
|
||||
$display("*-* FAILED with %0d errors *-*", errors);
|
||||
end
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
%Warning-COVERIGN: t/t_covergroup_trans_empty_bad.v:15:26: Ignoring unsupported: cover '[*'
|
||||
15 | bins t1 = (1 [*2]);
|
||||
| ^~
|
||||
... 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_trans_empty_bad.v:15:18: Transition set without items
|
||||
: ... note: In instance 't'
|
||||
15 | bins t1 = (1 [*2]);
|
||||
| ^~
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
%Error: Exiting due to
|
||||
|
|
@ -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: 2025 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.lint(expect_filename=test.golden_filename, fails=True)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-FileCopyrightText: 2025 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test: transition bin with unsupported repetition operator causes empty transition set
|
||||
|
||||
module t;
|
||||
logic [3:0] cp_expr;
|
||||
|
||||
covergroup cg;
|
||||
cp1: coverpoint cp_expr {
|
||||
bins t1 = (1 [*2]);
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg cg_inst = new;
|
||||
initial $finish;
|
||||
endmodule
|
||||
|
|
@ -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('vlt')
|
||||
|
||||
# Transition array bins are now supported
|
||||
test.compile(verilator_flags2=["-Wno-IMPLICITSTATIC"])
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
// DESCRIPTION: Verilator: Test transition bins - array bins
|
||||
// This file ONLY is placed into the Public Domain, for any use, without warranty.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
logic [2:0] state;
|
||||
|
||||
covergroup cg;
|
||||
// Test array bins: creates separate bin for each transition
|
||||
cp_array: coverpoint state {
|
||||
bins trans_array[] = (0 => 1), (1 => 2), (2 => 3);
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg cg_inst = new;
|
||||
|
||||
int cyc = 0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
|
||||
case (cyc)
|
||||
0: state <= 0;
|
||||
1: state <= 1; // 0 => 1 (hits trans_array[0=>1])
|
||||
2: state <= 2; // 1 => 2 (hits trans_array[1=>2])
|
||||
3: state <= 3; // 2 => 3 (hits trans_array[2=>3])
|
||||
4: begin
|
||||
real cov = cg_inst.get_inst_coverage();
|
||||
$display("Coverage: %f%%", cov);
|
||||
// We should have hit all 3 array bins = 100%
|
||||
if (cov >= 99.0) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end else begin
|
||||
$display("ERROR: Expected 100%% coverage, got %f%%", cov);
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
|
||||
cg_inst.sample();
|
||||
|
||||
if (cyc > 10) begin
|
||||
$display("ERROR: Test timed out");
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
#!/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('vlt')
|
||||
|
||||
# Multi-value transition bins with restart semantics generate incomplete case statements
|
||||
# This is a known limitation - complex transitions not fully supported
|
||||
test.compile(fails=test.vlt_all,
|
||||
expect=r'%Warning-CASEINCOMPLETE:.*Case values incompletely covered')
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
// DESCRIPTION: Verilator: Test transition bins - restart behavior
|
||||
// This file ONLY is placed into the Public Domain, for any use, without warranty.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t;
|
||||
logic [2:0] state;
|
||||
int errors = 0;
|
||||
|
||||
covergroup cg;
|
||||
cp_state: coverpoint state {
|
||||
bins trans_restart = (1 => 2 => 3); // Should handle restart correctly
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg cg_inst = new;
|
||||
|
||||
initial begin
|
||||
// Sequence: 1, 2, 1, 2, 3
|
||||
// This tests restart logic: when we see 1 again while in middle of sequence,
|
||||
// we should restart from position 1 (not reset to 0)
|
||||
|
||||
state = 1; // Start: position = 1
|
||||
cg_inst.sample();
|
||||
$display("After state=1: seqpos should be 1");
|
||||
|
||||
state = 2; // Advance: position = 2
|
||||
cg_inst.sample();
|
||||
$display("After state=2: seqpos should be 2");
|
||||
|
||||
state = 1; // Restart! Should go to position 1 (not 0)
|
||||
cg_inst.sample();
|
||||
$display("After state=1 (restart): seqpos should be 1");
|
||||
|
||||
state = 2; // Advance: position = 2
|
||||
cg_inst.sample();
|
||||
$display("After state=2: seqpos should be 2");
|
||||
|
||||
state = 3; // Complete! Bin should increment
|
||||
cg_inst.sample();
|
||||
$display("After state=3: bin should have incremented, seqpos reset to 0");
|
||||
|
||||
// Check coverage
|
||||
$display("Coverage: %f%%", cg_inst.get_inst_coverage());
|
||||
if (cg_inst.get_inst_coverage() < 99.0) begin
|
||||
$display("ERROR: Expected 100%% coverage, got %f%%", cg_inst.get_inst_coverage());
|
||||
errors++;
|
||||
end
|
||||
|
||||
if (errors == 0) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
end else begin
|
||||
$display("*-* FAILED with %0d errors *-*", errors);
|
||||
end
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
// DESCRIPTION: Verilator: Test transition bins - simple two-value transitions
|
||||
// This file ONLY is placed into the Public Domain, for any use, without warranty.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
logic [2:0] state;
|
||||
|
||||
covergroup cg;
|
||||
cp_state: coverpoint state {
|
||||
bins trans1 = (0 => 1);
|
||||
bins trans2 = (1 => 2);
|
||||
bins trans3 = (2 => 3);
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg cg_inst = new;
|
||||
|
||||
int cyc = 0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
cyc <= cyc + 1;
|
||||
|
||||
case (cyc)
|
||||
0: state <= 0;
|
||||
1: state <= 1; // 0 => 1 (trans1 should hit)
|
||||
2: state <= 2; // 1 => 2 (trans2 should hit)
|
||||
3: state <= 3; // 2 => 3 (trans3 should hit)
|
||||
4: begin
|
||||
$display("Coverage: %f%%", cg_inst.get_inst_coverage());
|
||||
if (cg_inst.get_inst_coverage() >= 99.0) begin // Allow for rounding
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end else begin
|
||||
$display("ERROR: Expected 100%% coverage, got %f%%", cg_inst.get_inst_coverage());
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
|
||||
// Sample the covergroup manually each clock
|
||||
cg_inst.sample();
|
||||
|
||||
// Auto-stop after 10 cycles to prevent infinite loop
|
||||
if (cyc > 10) begin
|
||||
$display("ERROR: Test timed out");
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
%Error: t/t_covergroup_trans_single_bad.v:15:18: Transition requires at least two values
|
||||
: ... note: In instance 't'
|
||||
15 | bins t1 = (1);
|
||||
| ^~
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
%Error: Exiting due to
|
||||
|
|
@ -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: 2025 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.lint(expect_filename=test.golden_filename, fails=True)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2025 by Wilson Snyder.
|
||||
// SPDX-FileCopyrightText: 2025 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test: transition bin requires at least two values
|
||||
|
||||
module t;
|
||||
logic [3:0] cp_expr;
|
||||
|
||||
covergroup cg;
|
||||
cp1: coverpoint cp_expr {
|
||||
bins t1 = (1);
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg cg_inst = new;
|
||||
initial $finish;
|
||||
endmodule
|
||||
|
|
@ -1,408 +1,220 @@
|
|||
%Warning-COVERIGN: t/t_covergroup_unsup.v:38:3: Ignoring unsupported: covergroup
|
||||
38 | covergroup cg_empty;
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:65:25: Ignoring unsupported: coverage '@@' events
|
||||
65 | covergroup cg_atat() @@ (begin funca or end funcb);
|
||||
| ^~
|
||||
... 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.
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:41:3: Ignoring unsupported: covergroup
|
||||
41 | covergroup cg_opt;
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:60:33: Ignoring unsupported: coverage clocking event
|
||||
60 | covergroup cg_clockingevent() @(posedge clk);
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:60:3: Ignoring unsupported: covergroup
|
||||
60 | covergroup cg_clockingevent() @(posedge clk);
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:62:3: Ignoring unsupported: covergroup
|
||||
62 | covergroup cg_withfunction() with function sample (a);
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:64:24: Ignoring unsupported: coverage '@@' events
|
||||
64 | covergroup cg_atat() @@ (begin funca or end funcb);
|
||||
| ^~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:64:3: Ignoring unsupported: covergroup
|
||||
64 | covergroup cg_atat() @@ (begin funca or end funcb);
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:66:3: Ignoring unsupported: covergroup
|
||||
66 | covergroup cg_bracket;
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:69:3: Ignoring unsupported: covergroup
|
||||
69 | covergroup cg_bracket2;
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:73:5: Ignoring unsupported: coverpoint
|
||||
73 | coverpoint a;
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:72:3: Ignoring unsupported: covergroup
|
||||
72 | covergroup cg_cp;
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:76:18: Ignoring unsupported: cover 'iff'
|
||||
76 | coverpoint a iff (b);
|
||||
| ^~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:76:5: Ignoring unsupported: coverpoint
|
||||
76 | coverpoint a iff (b);
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:75:3: Ignoring unsupported: covergroup
|
||||
75 | covergroup cg_cp_iff;
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:79:22: Ignoring unsupported: cover 'iff'
|
||||
79 | id: coverpoint a iff (b);
|
||||
| ^~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:79:9: Ignoring unsupported: coverpoint
|
||||
79 | id: coverpoint a iff (b);
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:78:3: Ignoring unsupported: covergroup
|
||||
78 | covergroup cg_id_cp_iff;
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:82:26: Ignoring unsupported: cover 'iff'
|
||||
82 | int id: coverpoint a iff (b);
|
||||
| ^~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:82:13: Ignoring unsupported: coverpoint
|
||||
82 | int id: coverpoint a iff (b);
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:81:3: Ignoring unsupported: covergroup
|
||||
81 | covergroup cg_id_cp_id1;
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:85:30: Ignoring unsupported: cover 'iff'
|
||||
85 | var int id: coverpoint a iff (b);
|
||||
| ^~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:85:17: Ignoring unsupported: coverpoint
|
||||
85 | var int id: coverpoint a iff (b);
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:84:3: Ignoring unsupported: covergroup
|
||||
84 | covergroup cg_id_cp_id2;
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:88:32: Ignoring unsupported: cover 'iff'
|
||||
88 | var [3:0] id: coverpoint a iff (b);
|
||||
| ^~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:88:19: Ignoring unsupported: coverpoint
|
||||
88 | var [3:0] id: coverpoint a iff (b);
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:87:3: Ignoring unsupported: covergroup
|
||||
87 | covergroup cg_id_cp_id3;
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:91:28: Ignoring unsupported: cover 'iff'
|
||||
91 | [3:0] id: coverpoint a iff (b);
|
||||
| ^~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:91:15: Ignoring unsupported: coverpoint
|
||||
91 | [3:0] id: coverpoint a iff (b);
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:90:3: Ignoring unsupported: covergroup
|
||||
90 | covergroup cg_id_cp_id4;
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:94:29: Ignoring unsupported: cover 'iff'
|
||||
94 | signed id: coverpoint a iff (b);
|
||||
| ^~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:94:16: Ignoring unsupported: coverpoint
|
||||
94 | signed id: coverpoint a iff (b);
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:93:3: Ignoring unsupported: covergroup
|
||||
93 | covergroup cg_id_cp_id5;
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:98:16: Ignoring unsupported: cover 'iff'
|
||||
98 | cross a, b iff (!rst);
|
||||
| ^~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:98:5: Ignoring unsupported: cover cross
|
||||
98 | cross a, b iff (!rst);
|
||||
| ^~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:97:3: Ignoring unsupported: covergroup
|
||||
97 | covergroup cg_cross;
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:101:16: Ignoring unsupported: cover 'iff'
|
||||
101 | cross a, b iff (!rst) {}
|
||||
| ^~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:101:5: Ignoring unsupported: cover cross
|
||||
101 | cross a, b iff (!rst) {}
|
||||
| ^~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:100:3: Ignoring unsupported: covergroup
|
||||
100 | covergroup cg_cross2;
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:104:5: Ignoring unsupported: cover cross
|
||||
104 | cross a, b { option.comment = "cross"; option.weight = 12; }
|
||||
| ^~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:103:3: Ignoring unsupported: covergroup
|
||||
103 | covergroup cg_cross3;
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:108:21: Ignoring unsupported: coverage cross 'function' declaration
|
||||
108 | function void crossfunc; endfunction
|
||||
| ^~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:109:18: Ignoring unsupported: coverage select function call
|
||||
109 | bins one = crossfunc();
|
||||
| ^~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:109:7: Ignoring unsupported: coverage cross bin
|
||||
109 | bins one = crossfunc();
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:107:5: Ignoring unsupported: cover cross
|
||||
107 | cross a, b {
|
||||
| ^~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:106:3: Ignoring unsupported: covergroup
|
||||
106 | covergroup cg_cross4;
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:113:26: Ignoring unsupported: cover 'iff'
|
||||
113 | my_cg_id: cross a, b iff (!rst);
|
||||
| ^~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:113:15: Ignoring unsupported: cover cross
|
||||
113 | my_cg_id: cross a, b iff (!rst);
|
||||
| ^~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:112:3: Ignoring unsupported: covergroup
|
||||
112 | covergroup cg_cross_id;
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:118:15: Ignoring unsupported: cover bin specification
|
||||
118 | { bins ba = {a}; }
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:119:22: Ignoring unsupported: cover 'iff'
|
||||
119 | { bins bar = {a} iff (!rst); }
|
||||
| ^~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:119:16: Ignoring unsupported: cover bin specification
|
||||
119 | { bins bar = {a} iff (!rst); }
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:120:24: Ignoring unsupported: cover bin specification
|
||||
120 | { illegal_bins ila = {a}; }
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:121:23: Ignoring unsupported: cover bin specification
|
||||
121 | { ignore_bins iga = {a}; }
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:99:23: Ignoring unsupported: cross iff condition
|
||||
99 | cross a, b iff (!rst);
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:123:17: Ignoring unsupported: cover bin specification
|
||||
123 | { bins ba[] = {a}; }
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:124:18: Ignoring unsupported: cover bin specification
|
||||
124 | { bins ba[2] = {a}; }
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:126:21: Ignoring unsupported: cover bin 'with' specification
|
||||
126 | { bins ba = {a} with ( b ); }
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:128:25: Ignoring unsupported: cover bin 'wildcard' specification
|
||||
128 | { wildcard bins bwa = {a}; }
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:129:32: Ignoring unsupported: cover bin 'wildcard' 'with' specification
|
||||
129 | { wildcard bins bwaw = {a} with ( b ); }
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:131:18: Ignoring unsupported: cover bin 'default'
|
||||
131 | { bins def = default; }
|
||||
| ^~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:132:27: Ignoring unsupported: cover bin 'default' 'sequence'
|
||||
132 | { bins defs = default sequence; }
|
||||
| ^~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:134:16: Ignoring unsupported: cover bin trans list
|
||||
134 | { bins bts = ( 1, 2 ); }
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:135:7: Ignoring unsupported: cover bin 'wildcard' trans list
|
||||
135 | { wildcard bins wbts = ( 1, 2 ); }
|
||||
| ^~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:136:31: Ignoring unsupported: covergroup value range
|
||||
136 | { bins bts2 = ( 2, 3 ), ( [5:6] ), ( [5 +/- 2] ), ( [ 5 +%- 20.0] ) ; }
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:136:42: Ignoring unsupported: covergroup value range
|
||||
136 | { bins bts2 = ( 2, 3 ), ( [5:6] ), ( [5 +/- 2] ), ( [ 5 +%- 20.0] ) ; }
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:136:57: Ignoring unsupported: covergroup value range
|
||||
136 | { bins bts2 = ( 2, 3 ), ( [5:6] ), ( [5 +/- 2] ), ( [ 5 +%- 20.0] ) ; }
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:136:17: Ignoring unsupported: cover bin trans list
|
||||
136 | { bins bts2 = ( 2, 3 ), ( [5:6] ), ( [5 +/- 2] ), ( [ 5 +%- 20.0] ) ; }
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:138:25: Ignoring unsupported: cover trans set '=>'
|
||||
138 | { bins bts2 = ( 1,5 => 6,7 ) ; }
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:102:23: Ignoring unsupported: cross iff condition
|
||||
102 | cross a, b iff (!rst) {}
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:109:24: Ignoring unsupported: coverage cross 'function' declaration
|
||||
109 | function void crossfunc; endfunction
|
||||
| ^~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:110:21: Ignoring unsupported: coverage select function call
|
||||
110 | bins one = crossfunc();
|
||||
| ^~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:110:10: Ignoring unsupported: explicit coverage cross bins
|
||||
110 | bins one = crossfunc();
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:114:33: Ignoring unsupported: cross iff condition
|
||||
114 | my_cg_id: cross a, b iff (!rst);
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:130:34: Ignoring unsupported: cover bin 'wildcard' 'with' specification
|
||||
130 | { wildcard bins bwaw = {a} with ( b ); }
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:133:29: Ignoring unsupported: cover bin 'default' 'sequence'
|
||||
133 | { bins defs = default sequence; }
|
||||
| ^~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:136:9: Ignoring unsupported: cover bin 'wildcard' trans list
|
||||
136 | { wildcard bins wbts = ( 1, 2 ); }
|
||||
| ^~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:137:33: Ignoring unsupported: covergroup value range
|
||||
137 | { bins bts2 = ( 2, 3 ), ( [5:6] ), ( [5 +/- 2] ), ( [ 5 +%- 20.0] ) ; }
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:137:44: Ignoring unsupported: covergroup value range
|
||||
137 | { bins bts2 = ( 2, 3 ), ( [5:6] ), ( [5 +/- 2] ), ( [ 5 +%- 20.0] ) ; }
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:137:59: Ignoring unsupported: covergroup value range
|
||||
137 | { bins bts2 = ( 2, 3 ), ( [5:6] ), ( [5 +/- 2] ), ( [ 5 +%- 20.0] ) ; }
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:140:25: Ignoring unsupported: cover '[*'
|
||||
140 | { bins bts2 = ( 3 [*5] ) ; }
|
||||
| ^~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:138:17: Ignoring unsupported: cover bin trans list
|
||||
138 | { bins bts2 = ( 1,5 => 6,7 ) ; }
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:139:23: Ignoring unsupported: cover '[*'
|
||||
139 | { bins bts2 = ( 3 [*5] ) ; }
|
||||
| ^~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:139:17: Ignoring unsupported: cover bin trans list
|
||||
139 | { bins bts2 = ( 3 [*5] ) ; }
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:140:23: Ignoring unsupported: cover '[*'
|
||||
140 | { bins bts2 = ( 3 [*5:6] ) ; }
|
||||
| ^~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:140:17: Ignoring unsupported: cover bin trans list
|
||||
140 | { bins bts2 = ( 3 [*5:6] ) ; }
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:141:23: Ignoring unsupported: cover '[->'
|
||||
141 | { bins bts2 = ( 3 [->5] ) ; }
|
||||
| ^~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:141:17: Ignoring unsupported: cover bin trans list
|
||||
141 | { bins bts2 = ( 3 [->5] ) ; }
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:142:23: Ignoring unsupported: cover '[->'
|
||||
142 | { bins bts2 = ( 3 [->5:6] ) ; }
|
||||
| ^~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:142:17: Ignoring unsupported: cover bin trans list
|
||||
142 | { bins bts2 = ( 3 [->5:6] ) ; }
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:143:23: Ignoring unsupported: cover '[='
|
||||
143 | { bins bts2 = ( 3 [=5] ) ; }
|
||||
| ^~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:143:17: Ignoring unsupported: cover bin trans list
|
||||
143 | { bins bts2 = ( 3 [=5] ) ; }
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:144:23: Ignoring unsupported: cover '[='
|
||||
144 | { bins bts2 = ( 3 [=5:6] ) ; }
|
||||
| ^~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:144:17: Ignoring unsupported: cover bin trans list
|
||||
144 | { bins bts2 = ( 3 [=5:6] ) ; }
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:116:3: Ignoring unsupported: covergroup
|
||||
116 | covergroup cg_binsoroptions_bk1;
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:149:24: Ignoring unsupported: cover bin 'with' specification
|
||||
149 | bins div_by_2 = a with (item % 2 == 0);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:150:32: Ignoring unsupported: cover bin 'with' specification
|
||||
150 | bins div_by_2_paren[] = a with (item % 2 == 0);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:148:5: Ignoring unsupported: coverpoint
|
||||
148 | coverpoint a {
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:147:3: Ignoring unsupported: covergroup
|
||||
147 | covergroup cg_coverpoint_ref;
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:156:20: Ignoring unsupported: coverage select expression 'binsof'
|
||||
156 | bins bin_a = binsof(a);
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:156:7: Ignoring unsupported: coverage cross bin
|
||||
156 | bins bin_a = binsof(a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:157:21: Ignoring unsupported: coverage select expression 'binsof'
|
||||
157 | bins bin_ai = binsof(a) iff (!rst);
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:157:31: Ignoring unsupported: cover 'iff'
|
||||
157 | bins bin_ai = binsof(a) iff (!rst);
|
||||
| ^~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:157:7: Ignoring unsupported: coverage cross bin
|
||||
157 | bins bin_ai = binsof(a) iff (!rst);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:158:20: Ignoring unsupported: coverage select expression 'binsof'
|
||||
158 | bins bin_c = binsof(cp.x);
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:158:7: Ignoring unsupported: coverage cross bin
|
||||
158 | bins bin_c = binsof(cp.x);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:159:21: Ignoring unsupported: coverage select expression 'binsof'
|
||||
159 | bins bin_na = ! binsof(a);
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:159:7: Ignoring unsupported: coverage cross bin
|
||||
159 | bins bin_na = ! binsof(a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:161:30: Ignoring unsupported: coverage select expression 'intersect'
|
||||
161 | bins bin_d = binsof(a) intersect { b };
|
||||
| ^~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:161:7: Ignoring unsupported: coverage cross bin
|
||||
161 | bins bin_d = binsof(a) intersect { b };
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:162:31: Ignoring unsupported: coverage select expression 'intersect'
|
||||
162 | bins bin_nd = ! binsof(a) intersect { b };
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:162:7: Ignoring unsupported: coverage cross bin
|
||||
162 | bins bin_nd = ! binsof(a) intersect { b };
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:164:20: Ignoring unsupported: coverage select expression with
|
||||
164 | bins bin_e = with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:164:7: Ignoring unsupported: coverage cross bin
|
||||
164 | bins bin_e = with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:165:24: Ignoring unsupported: coverage select expression with
|
||||
165 | bins bin_not_e = ! with (a);
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:141:25: Ignoring unsupported: cover '[*'
|
||||
141 | { bins bts2 = ( 3 [*5:6] ) ; }
|
||||
| ^~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:142:25: Ignoring unsupported: cover '[->'
|
||||
142 | { bins bts2 = ( 3 [->5] ) ; }
|
||||
| ^~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:143:25: Ignoring unsupported: cover '[->'
|
||||
143 | { bins bts2 = ( 3 [->5:6] ) ; }
|
||||
| ^~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:144:25: Ignoring unsupported: cover '[='
|
||||
144 | { bins bts2 = ( 3 [=5] ) ; }
|
||||
| ^~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:145:25: Ignoring unsupported: cover '[='
|
||||
145 | { bins bts2 = ( 3 [=5:6] ) ; }
|
||||
| ^~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:150:26: Ignoring unsupported: cover bin 'with' specification
|
||||
150 | bins div_by_2 = a with (item % 2 == 0);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:151:34: Ignoring unsupported: cover bin 'with' specification
|
||||
151 | bins div_by_2_paren[] = a with (item % 2 == 0);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:157:23: Ignoring unsupported: coverage select expression 'binsof'
|
||||
157 | bins bin_a = binsof(a);
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:157:10: Ignoring unsupported: explicit coverage cross bins
|
||||
157 | bins bin_a = binsof(a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:158:24: Ignoring unsupported: coverage select expression 'binsof'
|
||||
158 | bins bin_ai = binsof(a) iff (!rst);
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:158:10: Ignoring unsupported: explicit coverage cross bins
|
||||
158 | bins bin_ai = binsof(a) iff (!rst);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:159:23: Ignoring unsupported: coverage select expression 'binsof'
|
||||
159 | bins bin_c = binsof(cp.x);
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:159:10: Ignoring unsupported: explicit coverage cross bins
|
||||
159 | bins bin_c = binsof(cp.x);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:160:24: Ignoring unsupported: coverage select expression 'binsof'
|
||||
160 | bins bin_na = ! binsof(a);
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:165:7: Ignoring unsupported: coverage cross bin
|
||||
165 | bins bin_not_e = ! with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:167:23: Ignoring unsupported: coverage select expression 'binsof'
|
||||
167 | bins bin_par = (binsof(a));
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:167:7: Ignoring unsupported: coverage cross bin
|
||||
167 | bins bin_par = (binsof(a));
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:168:22: Ignoring unsupported: coverage select expression 'binsof'
|
||||
168 | bins bin_and = binsof(a) && binsof(b);
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:168:35: Ignoring unsupported: coverage select expression 'binsof'
|
||||
168 | bins bin_and = binsof(a) && binsof(b);
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:168:32: Ignoring unsupported: coverage select expression '&&'
|
||||
168 | bins bin_and = binsof(a) && binsof(b);
|
||||
| ^~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:168:7: Ignoring unsupported: coverage cross bin
|
||||
168 | bins bin_and = binsof(a) && binsof(b);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:169:21: Ignoring unsupported: coverage select expression 'binsof'
|
||||
169 | bins bin_or = binsof(a) || binsof(b);
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:169:34: Ignoring unsupported: coverage select expression 'binsof'
|
||||
169 | bins bin_or = binsof(a) || binsof(b);
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:169:31: Ignoring unsupported: coverage select expression '||'
|
||||
169 | bins bin_or = binsof(a) || binsof(b);
|
||||
| ^~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:169:7: Ignoring unsupported: coverage cross bin
|
||||
169 | bins bin_or = binsof(a) || binsof(b);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:170:23: Ignoring unsupported: coverage select expression 'binsof'
|
||||
170 | bins bin_with = binsof(a) with (a);
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:170:33: Ignoring unsupported: coverage select expression with
|
||||
170 | bins bin_with = binsof(a) with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:170:7: Ignoring unsupported: coverage cross bin
|
||||
170 | bins bin_with = binsof(a) with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:171:26: Ignoring unsupported: coverage select expression 'binsof'
|
||||
171 | bins bin_or_with = binsof(a) || binsof(a) with (a);
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:160:10: Ignoring unsupported: explicit coverage cross bins
|
||||
160 | bins bin_na = ! binsof(a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:162:33: Ignoring unsupported: coverage select expression 'intersect'
|
||||
162 | bins bin_d = binsof(a) intersect { b };
|
||||
| ^~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:162:10: Ignoring unsupported: explicit coverage cross bins
|
||||
162 | bins bin_d = binsof(a) intersect { b };
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:163:34: Ignoring unsupported: coverage select expression 'intersect'
|
||||
163 | bins bin_nd = ! binsof(a) intersect { b };
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:163:10: Ignoring unsupported: explicit coverage cross bins
|
||||
163 | bins bin_nd = ! binsof(a) intersect { b };
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:165:23: Ignoring unsupported: coverage select expression with
|
||||
165 | bins bin_e = with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:165:10: Ignoring unsupported: explicit coverage cross bins
|
||||
165 | bins bin_e = with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:166:27: Ignoring unsupported: coverage select expression with
|
||||
166 | bins bin_not_e = ! with (a);
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:166:10: Ignoring unsupported: explicit coverage cross bins
|
||||
166 | bins bin_not_e = ! with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:168:26: Ignoring unsupported: coverage select expression 'binsof'
|
||||
168 | bins bin_par = (binsof(a));
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:171:39: Ignoring unsupported: coverage select expression 'binsof'
|
||||
171 | bins bin_or_with = binsof(a) || binsof(a) with (a);
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:171:49: Ignoring unsupported: coverage select expression with
|
||||
171 | bins bin_or_with = binsof(a) || binsof(a) with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:171:36: Ignoring unsupported: coverage select expression '||'
|
||||
171 | bins bin_or_with = binsof(a) || binsof(a) with (a);
|
||||
| ^~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:171:7: Ignoring unsupported: coverage cross bin
|
||||
171 | bins bin_or_with = binsof(a) || binsof(a) with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:172:27: Ignoring unsupported: coverage select expression 'binsof'
|
||||
172 | bins bin_and_with = binsof(a) && binsof(a) with (a);
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:172:40: Ignoring unsupported: coverage select expression 'binsof'
|
||||
172 | bins bin_and_with = binsof(a) && binsof(a) with (a);
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:172:50: Ignoring unsupported: coverage select expression with
|
||||
172 | bins bin_and_with = binsof(a) && binsof(a) with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:172:37: Ignoring unsupported: coverage select expression '&&'
|
||||
172 | bins bin_and_with = binsof(a) && binsof(a) with (a);
|
||||
| ^~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:172:7: Ignoring unsupported: coverage cross bin
|
||||
172 | bins bin_and_with = binsof(a) && binsof(a) with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:173:34: Ignoring unsupported: coverage select expression 'binsof'
|
||||
173 | bins bin_multiple_fields = binsof(p.inner_packet.field);
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:173:7: Ignoring unsupported: coverage cross bin
|
||||
173 | bins bin_multiple_fields = binsof(p.inner_packet.field);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:155:5: Ignoring unsupported: cover cross
|
||||
155 | cross a, b {
|
||||
| ^~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:154:3: Ignoring unsupported: covergroup
|
||||
154 | covergroup cg_cross_bins;
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:177:3: Ignoring unsupported: covergroup
|
||||
177 | covergroup cgArgs(int cg_lim);
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:184:21: Ignoring unsupported: coverage clocking event
|
||||
184 | covergroup cov1 @m_z;
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:185:7: Ignoring unsupported: coverpoint
|
||||
185 | coverpoint m_x;
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:168:10: Ignoring unsupported: explicit coverage cross bins
|
||||
168 | bins bin_par = (binsof(a));
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:169:25: Ignoring unsupported: coverage select expression 'binsof'
|
||||
169 | bins bin_and = binsof(a) && binsof(b);
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:169:38: Ignoring unsupported: coverage select expression 'binsof'
|
||||
169 | bins bin_and = binsof(a) && binsof(b);
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:169:35: Ignoring unsupported: coverage select expression '&&'
|
||||
169 | bins bin_and = binsof(a) && binsof(b);
|
||||
| ^~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:169:10: Ignoring unsupported: explicit coverage cross bins
|
||||
169 | bins bin_and = binsof(a) && binsof(b);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:170:24: Ignoring unsupported: coverage select expression 'binsof'
|
||||
170 | bins bin_or = binsof(a) || binsof(b);
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:170:37: Ignoring unsupported: coverage select expression 'binsof'
|
||||
170 | bins bin_or = binsof(a) || binsof(b);
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:170:34: Ignoring unsupported: coverage select expression '||'
|
||||
170 | bins bin_or = binsof(a) || binsof(b);
|
||||
| ^~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:170:10: Ignoring unsupported: explicit coverage cross bins
|
||||
170 | bins bin_or = binsof(a) || binsof(b);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:171:26: Ignoring unsupported: coverage select expression 'binsof'
|
||||
171 | bins bin_with = binsof(a) with (a);
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:171:36: Ignoring unsupported: coverage select expression with
|
||||
171 | bins bin_with = binsof(a) with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:171:10: Ignoring unsupported: explicit coverage cross bins
|
||||
171 | bins bin_with = binsof(a) with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:172:29: Ignoring unsupported: coverage select expression 'binsof'
|
||||
172 | bins bin_or_with = binsof(a) || binsof(a) with (a);
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:172:42: Ignoring unsupported: coverage select expression 'binsof'
|
||||
172 | bins bin_or_with = binsof(a) || binsof(a) with (a);
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:172:52: Ignoring unsupported: coverage select expression with
|
||||
172 | bins bin_or_with = binsof(a) || binsof(a) with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:172:39: Ignoring unsupported: coverage select expression '||'
|
||||
172 | bins bin_or_with = binsof(a) || binsof(a) with (a);
|
||||
| ^~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:172:10: Ignoring unsupported: explicit coverage cross bins
|
||||
172 | bins bin_or_with = binsof(a) || binsof(a) with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:173:30: Ignoring unsupported: coverage select expression 'binsof'
|
||||
173 | bins bin_and_with = binsof(a) && binsof(a) with (a);
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:173:43: Ignoring unsupported: coverage select expression 'binsof'
|
||||
173 | bins bin_and_with = binsof(a) && binsof(a) with (a);
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:173:53: Ignoring unsupported: coverage select expression with
|
||||
173 | bins bin_and_with = binsof(a) && binsof(a) with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:173:40: Ignoring unsupported: coverage select expression '&&'
|
||||
173 | bins bin_and_with = binsof(a) && binsof(a) with (a);
|
||||
| ^~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:173:10: Ignoring unsupported: explicit coverage cross bins
|
||||
173 | bins bin_and_with = binsof(a) && binsof(a) with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:174:37: Ignoring unsupported: coverage select expression 'binsof'
|
||||
174 | bins bin_multiple_fields = binsof(p.inner_packet.field);
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:174:10: Ignoring unsupported: explicit coverage cross bins
|
||||
174 | bins bin_multiple_fields = binsof(p.inner_packet.field);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:195:7: Ignoring unsupported: covergroup inheritance (extends)
|
||||
195 | covergroup extends cg_empty;
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:186:7: Ignoring unsupported: coverpoint
|
||||
186 | coverpoint m_y;
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:99:13: Ignoring unsupported: cross references unknown coverpoint: a
|
||||
: ... note: In instance 't'
|
||||
99 | cross a, b iff (!rst);
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:102:13: Ignoring unsupported: cross references unknown coverpoint: a
|
||||
: ... note: In instance 't'
|
||||
102 | cross a, b iff (!rst) {}
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:105:13: Ignoring unsupported: cross references unknown coverpoint: a
|
||||
: ... note: In instance 't'
|
||||
105 | cross a, b { option.comment = "cross"; option.weight = 12; }
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:108:13: Ignoring unsupported: cross references unknown coverpoint: a
|
||||
: ... note: In instance 't'
|
||||
108 | cross a, b {
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:114:23: Ignoring unsupported: cross references unknown coverpoint: a
|
||||
: ... note: In instance 't'
|
||||
114 | my_cg_id: cross a, b iff (!rst);
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:156:13: Ignoring unsupported: cross references unknown coverpoint: a
|
||||
: ... note: In instance 't'
|
||||
156 | cross a, b {
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:185:7: Ignoring unsupported: covergroup clocking event on member variable
|
||||
: ... note: In instance 't'
|
||||
185 | covergroup cov1 @m_z;
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:184:5: Ignoring unsupported: covergroup
|
||||
184 | covergroup cov1 @m_z;
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:194:5: Ignoring unsupported: covergroup
|
||||
194 | covergroup extends cg_empty;
|
||||
| ^~~~~~~~~~
|
||||
%Error: Exiting due to
|
||||
|
|
|
|||
|
|
@ -33,7 +33,9 @@ module Vt_debug_emitv_t;
|
|||
function ident;
|
||||
input int signed value;
|
||||
begin : label0
|
||||
ident = /*CRESET*/;
|
||||
ident =
|
||||
???? // CRESET
|
||||
;
|
||||
ident = value;
|
||||
disable label0;
|
||||
end
|
||||
|
|
|
|||
|
|
@ -156,6 +156,10 @@ for s in [
|
|||
'is not an unpacked array, but is in an unpacked array context',
|
||||
'loading other than unpacked-array variable',
|
||||
'loading other than unpacked/associative-array variable',
|
||||
# These are safety limits requiring >1000 bins or >10000 members to trigger
|
||||
'Too many bins or infinite loop detected in bin iteration',
|
||||
'Too many members or infinite loop in membersp iteration (1)',
|
||||
'Too many members or infinite loop in membersp iteration (3)',
|
||||
]:
|
||||
Suppressed[s] = True
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain
|
||||
// SPDX-FileCopyrightText: 2026 Matthew Ballance
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test array bins - separate bin per value
|
||||
|
||||
module t;
|
||||
/* verilator lint_off UNSIGNED */
|
||||
bit [7:0] data;
|
||||
|
||||
covergroup cg;
|
||||
coverpoint data {
|
||||
// Array bins: creates 3 separate bins
|
||||
bins values[] = {1, 5, 9};
|
||||
|
||||
// Non-array bin: creates 1 bin covering all values
|
||||
bins grouped = {2, 6, 10};
|
||||
}
|
||||
endgroup
|
||||
|
||||
initial begin
|
||||
cg cg_inst;
|
||||
real cov;
|
||||
|
||||
cg_inst = new();
|
||||
|
||||
// Initial coverage should be 0%
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
if (cov != 0.0) begin
|
||||
$error("Expected 0%% coverage, got %0.2f%%", cov);
|
||||
end
|
||||
|
||||
// Hit first array bin value (1)
|
||||
data = 1;
|
||||
cg_inst.sample();
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display("After hitting value 1: %0.2f%%", cov);
|
||||
// 1 bin out of 4 total bins (3 array bins + 1 grouped bin)
|
||||
if (cov < 23.0 || cov > 27.0) begin
|
||||
$error("Expected ~25%% (1/4 bins), got %0.2f%%", cov);
|
||||
end
|
||||
|
||||
// Hit second array bin value (5)
|
||||
data = 5;
|
||||
cg_inst.sample();
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display("After hitting value 5: %0.2f%%", cov);
|
||||
// 2 bins out of 4
|
||||
if (cov < 48.0 || cov > 52.0) begin
|
||||
$error("Expected ~50%% (2/4 bins), got %0.2f%%", cov);
|
||||
end
|
||||
|
||||
// Hit the grouped bin (covers all of 2, 6, 10)
|
||||
data = 6;
|
||||
cg_inst.sample();
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display("After hitting grouped bin: %0.2f%%", cov);
|
||||
// 3 bins out of 4
|
||||
if (cov < 73.0 || cov > 77.0) begin
|
||||
$error("Expected ~75%% (3/4 bins), got %0.2f%%", cov);
|
||||
end
|
||||
|
||||
// Hit third array bin value (9)
|
||||
data = 9;
|
||||
cg_inst.sample();
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display("After hitting value 9: %0.2f%%", cov);
|
||||
// All 4 bins covered
|
||||
if (cov != 100.0) begin
|
||||
$error("Expected 100%% (4/4 bins), got %0.2f%%", cov);
|
||||
end
|
||||
|
||||
// Verify hitting other values in grouped bin doesn't increase coverage
|
||||
data = 2;
|
||||
cg_inst.sample();
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
if (cov != 100.0) begin
|
||||
$error("Coverage should stay 100%%, got %0.2f%%", cov);
|
||||
end
|
||||
|
||||
$display("Array bins test PASSED");
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Test automatic bins: bins auto[N]
|
||||
#
|
||||
# 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('vlt')
|
||||
|
||||
test.compile()
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2026 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t;
|
||||
/* verilator lint_off UNSIGNED */
|
||||
/* verilator lint_off CMPCONST */
|
||||
logic [2:0] data; // 3-bit: 0-7
|
||||
|
||||
covergroup cg;
|
||||
coverpoint data {
|
||||
bins auto[4]; // Should create 4 bins: [0:1], [2:3], [4:5], [6:7]
|
||||
}
|
||||
endgroup
|
||||
/* verilator lint_on CMPCONST */
|
||||
|
||||
initial begin
|
||||
automatic cg cg_inst = new;
|
||||
|
||||
// Initial coverage should be 0%
|
||||
$display("Coverage initial: %f%% (expected ~0.00%%)", cg_inst.get_inst_coverage());
|
||||
|
||||
// Sample first bin: 0 or 1
|
||||
data = 0;
|
||||
cg_inst.sample();
|
||||
$display("Coverage after 0: %f%% (expected ~25.00%%)", cg_inst.get_inst_coverage());
|
||||
|
||||
// Sample second bin: 2 or 3
|
||||
data = 2;
|
||||
cg_inst.sample();
|
||||
$display("Coverage after 2: %f%% (expected ~50.00%%)", cg_inst.get_inst_coverage());
|
||||
|
||||
// Sample third bin: 4 or 5
|
||||
data = 5;
|
||||
cg_inst.sample();
|
||||
$display("Coverage after 5: %f%% (expected ~75.00%%)", cg_inst.get_inst_coverage());
|
||||
|
||||
// Sample fourth bin: 6 or 7
|
||||
data = 7;
|
||||
cg_inst.sample();
|
||||
$display("Coverage complete: %f%% (expected ~100.00%%)", cg_inst.get_inst_coverage());
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -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('vlt')
|
||||
|
||||
test.compile(verilator_flags2=["--exe", "t/t_funccov_basic_main.cpp"], make_main=False)
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue