Merge d23db1915a into 3bc73cc768
This commit is contained in:
commit
fa08863253
|
|
@ -121,6 +121,23 @@ set(PACKAGE_VERSION ${PROJECT_VERSION})
|
|||
set(CXX ${CMAKE_CXX_COMPILER})
|
||||
set(AR ${CMAKE_AR})
|
||||
|
||||
# Detect precompiled header include flag (matches configure.ac logic)
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_CXX_COMPILER} --help
|
||||
OUTPUT_VARIABLE _cxx_help
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
ERROR_QUIET
|
||||
)
|
||||
if(_cxx_help MATCHES "include-pch")
|
||||
# clang
|
||||
set(CFG_CXXFLAGS_PCH_I "-include-pch")
|
||||
set(CFG_GCH_IF_CLANG ".gch")
|
||||
else()
|
||||
# GCC
|
||||
set(CFG_CXXFLAGS_PCH_I "-include")
|
||||
set(CFG_GCH_IF_CLANG "")
|
||||
endif()
|
||||
|
||||
configure_file(include/verilated_config.h.in include/verilated_config.h @ONLY)
|
||||
configure_file(include/verilated.mk.in include/verilated.mk @ONLY)
|
||||
|
||||
|
|
|
|||
|
|
@ -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`, `covergroup`, `user` and
|
||||
a wildcard with `\*` or `?`. The default value is `\*`.
|
||||
|
||||
The `covergroup` 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 partially supports assertions and functional coverage.
|
||||
Verilator currently converts assertions to simple ``if (...) error`` statements,
|
||||
and simple coverage statements to increment the line counters described in the
|
||||
:ref:`coverage section<Coverage>`.
|
||||
|
||||
Verilator also partially supports SystemVerilog functional coverage with
|
||||
``covergroup``, ``coverpoint``, bins, cross coverage, and transition bins. See
|
||||
:ref:`Functional Coverage<user coverage>` for details on using
|
||||
covergroups for comprehensive coverage analysis.
|
||||
|
||||
Verilator does not support SEREs yet. All assertion and coverage statements
|
||||
must be simple expressions that complete in one cycle.
|
||||
|
|
|
|||
|
|
@ -184,7 +184,8 @@ Verilator supports adding code to the Verilated model to support
|
|||
SystemVerilog code coverage. With :vlopt:`--coverage`, Verilator enables
|
||||
all forms of coverage:
|
||||
|
||||
- :ref:`User Coverage`
|
||||
- :ref:`Property Coverage`
|
||||
- :ref:`Covergroup Coverage`
|
||||
- :ref:`Line Coverage`
|
||||
- :ref:`Toggle Coverage`
|
||||
|
||||
|
|
@ -192,22 +193,113 @@ When a model with coverage is executed, it will create a coverage file for
|
|||
collection and later analysis, see :ref:`Coverage Collection`.
|
||||
|
||||
|
||||
.. _user coverage:
|
||||
.. _property coverage:
|
||||
|
||||
Functional Coverage
|
||||
-------------------
|
||||
Property Coverage
|
||||
-----------------
|
||||
|
||||
With :vlopt:`--coverage` or :vlopt:`--coverage-user`, Verilator will
|
||||
translate functional coverage points the user has inserted manually in
|
||||
SystemVerilog code through into the Verilated model.
|
||||
translate property coverage points the user has inserted manually in
|
||||
SystemVerilog code into the Verilated model.
|
||||
|
||||
For example, the following SystemVerilog statement will add a coverage
|
||||
point under the coverage name "DefaultClock":
|
||||
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.
|
||||
|
||||
.. _covergroup coverage:
|
||||
|
||||
Covergroup Coverage
|
||||
-------------------
|
||||
|
||||
With :vlopt:`--coverage` or :vlopt:`--coverage-user`, Verilator will
|
||||
translate covergroup coverage points the user has inserted manually in
|
||||
SystemVerilog code into the Verilated model. Verilator supports
|
||||
coverpoints with value and transition bins, and cross points.
|
||||
|
||||
.. code-block:: sv
|
||||
|
||||
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
|
||||
|
||||
|
||||
Supported Features
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
* Coverpoints on integral expressions with value, range, wildcard, and transition bins
|
||||
* Conditional coverpoint sampling (iff)
|
||||
* Explicit and clocked sampling, with sample-function parameters
|
||||
* at_least and auto_bin_max options on covergroups and coverpoints
|
||||
* Cross points with auto-bins
|
||||
|
||||
Unsupported Features
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
* Coverpoints on real (floating-point) expressions
|
||||
* Coverpoint bin filtering (with)
|
||||
* Coverpoint bin conditional sampling (iff)
|
||||
* Transition bins with repetition operators ([\*N], [->N], [=N])
|
||||
* Explicitly-typed coverpoints
|
||||
* Block-event sampling
|
||||
* Covergroup inheritance (extends)
|
||||
* Cross points with user-defined bins
|
||||
|
||||
Functional Coverage Data Format
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
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
|
||||
|
||||
|
||||
.. _line coverage:
|
||||
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ set(HEADERS
|
|||
V3Control.h
|
||||
V3Coverage.h
|
||||
V3CoverageJoin.h
|
||||
V3Covergroup.h
|
||||
V3Dead.h
|
||||
V3Delayed.h
|
||||
V3Depth.h
|
||||
|
|
@ -235,6 +236,7 @@ set(COMMON_SOURCES
|
|||
V3Const__gen.cpp
|
||||
V3Coverage.cpp
|
||||
V3CoverageJoin.cpp
|
||||
V3Covergroup.cpp
|
||||
V3Dead.cpp
|
||||
V3Delayed.cpp
|
||||
V3Depth.cpp
|
||||
|
|
|
|||
|
|
@ -249,6 +249,7 @@ RAW_OBJS_PCH_ASTNOMT = \
|
|||
V3Combine.o \
|
||||
V3Common.o \
|
||||
V3Coverage.o \
|
||||
V3Covergroup.o \
|
||||
V3CoverageJoin.o \
|
||||
V3Dead.o \
|
||||
V3Delayed.o \
|
||||
|
|
|
|||
225
src/V3Active.cpp
225
src/V3Active.cpp
|
|
@ -619,11 +619,236 @@ 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 V3Covergroup
|
||||
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 {
|
||||
refp->v3fatalSrc("Could not find VarScope for clock signal '"
|
||||
<< refp->varp()->name() << "' in scope " << m_scopep->name()
|
||||
<< " when creating covergroup sampling active");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
|
|
|||
107
src/V3AstAttr.h
107
src/V3AstAttr.h
|
|
@ -1052,6 +1052,113 @@ inline std::ostream& operator<<(std::ostream& os, const VCastable& rhs) {
|
|||
|
||||
//######################################################################
|
||||
|
||||
class VCoverBinsType final {
|
||||
public:
|
||||
enum en : uint8_t {
|
||||
USER,
|
||||
ARRAY,
|
||||
AUTO,
|
||||
BINS_IGNORE, // Renamed to avoid Windows macro conflict
|
||||
BINS_ILLEGAL, // Renamed to avoid Windows macro conflict
|
||||
DEFAULT,
|
||||
BINS_WILDCARD, // Renamed to avoid Windows macro conflict
|
||||
TRANSITION
|
||||
};
|
||||
enum en m_e;
|
||||
VCoverBinsType()
|
||||
: m_e{USER} {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
constexpr VCoverBinsType(en _e)
|
||||
: m_e{_e} {}
|
||||
explicit VCoverBinsType(int _e)
|
||||
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
||||
constexpr operator en() const { return m_e; }
|
||||
const char* ascii() const {
|
||||
static const char* const names[]
|
||||
= {"user", "array", "auto", "ignore", "illegal", "default", "wildcard", "transition"};
|
||||
return names[m_e];
|
||||
}
|
||||
};
|
||||
constexpr bool operator==(const VCoverBinsType& lhs, const VCoverBinsType& rhs) {
|
||||
return lhs.m_e == rhs.m_e;
|
||||
}
|
||||
constexpr bool operator==(const VCoverBinsType& lhs, VCoverBinsType::en rhs) {
|
||||
return lhs.m_e == rhs;
|
||||
}
|
||||
constexpr bool operator==(VCoverBinsType::en lhs, const VCoverBinsType& rhs) {
|
||||
return lhs == rhs.m_e;
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
||||
class VCoverOptionType final {
|
||||
public:
|
||||
enum en : uint8_t { WEIGHT, GOAL, AT_LEAST, AUTO_BIN_MAX, PER_INSTANCE, COMMENT };
|
||||
enum en m_e;
|
||||
VCoverOptionType()
|
||||
: m_e{WEIGHT} {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
constexpr VCoverOptionType(en _e)
|
||||
: m_e{_e} {}
|
||||
explicit VCoverOptionType(int _e)
|
||||
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
||||
constexpr operator en() const { return m_e; }
|
||||
const char* ascii() const {
|
||||
static const char* const names[]
|
||||
= {"weight", "goal", "at_least", "auto_bin_max", "per_instance", "comment"};
|
||||
return names[m_e];
|
||||
}
|
||||
};
|
||||
constexpr bool operator==(const VCoverOptionType& lhs, const VCoverOptionType& rhs) {
|
||||
return lhs.m_e == rhs.m_e;
|
||||
}
|
||||
constexpr bool operator==(const VCoverOptionType& lhs, VCoverOptionType::en rhs) {
|
||||
return lhs.m_e == rhs;
|
||||
}
|
||||
constexpr bool operator==(VCoverOptionType::en lhs, const VCoverOptionType& rhs) {
|
||||
return lhs == rhs.m_e;
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
||||
class VTransRepType final {
|
||||
public:
|
||||
enum en : uint8_t {
|
||||
NONE, // No repetition
|
||||
CONSEC, // Consecutive repetition [*]
|
||||
GOTO, // Goto repetition [->]
|
||||
NONCONS // Nonconsecutive repetition [=]
|
||||
};
|
||||
enum en m_e;
|
||||
VTransRepType()
|
||||
: m_e{NONE} {}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
constexpr VTransRepType(en _e)
|
||||
: m_e{_e} {}
|
||||
explicit VTransRepType(int _e)
|
||||
: m_e(static_cast<en>(_e)) {} // Need () or GCC 4.8 false warning
|
||||
constexpr operator en() const { return m_e; }
|
||||
const char* ascii() const {
|
||||
static const char* const names[] = {"", "[*]", "[->]", "[=]"};
|
||||
return names[m_e];
|
||||
}
|
||||
const char* asciiJson() const {
|
||||
static const char* const names[] = {"", "\"consec\"", "\"goto\"", "\"noncons\""};
|
||||
return names[m_e];
|
||||
}
|
||||
};
|
||||
constexpr bool operator==(const VTransRepType& lhs, const VTransRepType& rhs) {
|
||||
return lhs.m_e == rhs.m_e;
|
||||
}
|
||||
constexpr bool operator==(const VTransRepType& lhs, VTransRepType::en rhs) {
|
||||
return lhs.m_e == rhs;
|
||||
}
|
||||
constexpr bool operator==(VTransRepType::en lhs, const VTransRepType& rhs) {
|
||||
return lhs == rhs.m_e;
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
||||
class VDirection final {
|
||||
public:
|
||||
enum en : uint8_t { NONE, INPUT, OUTPUT, INOUT, REF, CONSTREF };
|
||||
|
|
|
|||
|
|
@ -719,6 +719,7 @@ public:
|
|||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||
string emitC() override { V3ERROR_NA_RETURN(""); }
|
||||
bool cleanOut() const override { return true; }
|
||||
bool isExprCoverageEligible() const override { return false; }
|
||||
const char* broken() const override {
|
||||
BROKEN_RTN(!VN_IS(backp(), NodeAssign)); // V3Emit* assumption
|
||||
return nullptr;
|
||||
|
|
|
|||
|
|
@ -250,6 +250,20 @@ public:
|
|||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
class AstNodeFuncCovItem VL_NOT_FINAL : public AstNode {
|
||||
// Base class for functional coverage items (coverpoints, crosses)
|
||||
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; }
|
||||
};
|
||||
class AstNodeGen VL_NOT_FINAL : public AstNode {
|
||||
// Generate construct
|
||||
public:
|
||||
|
|
@ -506,6 +520,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 = "")
|
||||
|
|
@ -536,6 +551,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;
|
||||
|
|
@ -611,6 +627,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 {
|
||||
|
|
@ -1013,6 +1031,175 @@ public:
|
|||
bool isPredictOptimizable() const override { return false; }
|
||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
|
||||
// Forward declarations for types used in constructors below
|
||||
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} {}
|
||||
// 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;
|
||||
};
|
||||
class AstCoverTransItem final : public AstNode {
|
||||
// Represents a single transition item: value or value[*N] or value[->N] or value[=N]
|
||||
// @astgen op1 := valuesp : List[AstNode]
|
||||
// @astgen op2 := repMinp : Optional[AstNodeExpr]
|
||||
// @astgen op3 := repMaxp : Optional[AstNodeExpr]
|
||||
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; }
|
||||
};
|
||||
class AstCoverTransSet final : public AstNode {
|
||||
// Represents a transition set: value1 => value2 => value3
|
||||
// @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]
|
||||
// @astgen op4 := sampleArgsp : List[AstVar]
|
||||
string m_name;
|
||||
bool m_isClass = false;
|
||||
|
||||
public:
|
||||
AstCovergroup(FileLine* fl, const string& name, AstVar* argsp, AstVar* sampleArgsp,
|
||||
AstNode* membersp, AstSenTree* eventp)
|
||||
: ASTGEN_SUPER_Covergroup(fl)
|
||||
, m_name{name} {
|
||||
if (argsp) addArgsp(argsp);
|
||||
if (sampleArgsp) addSampleArgsp(sampleArgsp);
|
||||
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 AstDefParam final : public AstNode {
|
||||
// A defparam assignment
|
||||
// Parents: MODULE
|
||||
|
|
@ -2495,6 +2682,33 @@ public:
|
|||
void dump(std::ostream& str = std::cout) const override;
|
||||
void dumpJson(std::ostream& str = std::cout) const override;
|
||||
};
|
||||
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;
|
||||
};
|
||||
|
||||
// === AstNodeGen ===
|
||||
class AstGenBlock final : public AstNodeGen {
|
||||
|
|
@ -2577,6 +2791,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)
|
||||
|
|
@ -2604,6 +2820,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);
|
||||
|
|
|
|||
|
|
@ -3443,3 +3443,89 @@ const char* AstNot::widthMismatch() const VL_MT_STABLE {
|
|||
BROKEN_RTN(lhsp()->widthMin() != widthMin());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// Functional coverage 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 {
|
||||
dumpJsonBoolFuncIf(str, isClass);
|
||||
dumpJsonGen(str);
|
||||
}
|
||||
|
||||
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 << " " << m_type.ascii();
|
||||
if (m_isArray) str << "[]";
|
||||
}
|
||||
|
||||
void AstCoverBin::dumpJson(std::ostream& str) const {
|
||||
this->AstNode::dumpJson(str);
|
||||
str << ", \"name\": " << VString::quotePercent(m_name);
|
||||
str << ", \"binsType\": \"" << m_type.ascii() << "\"";
|
||||
if (m_isArray) str << ", \"isArray\": true";
|
||||
}
|
||||
|
||||
void AstCoverTransItem::dump(std::ostream& str) const {
|
||||
this->AstNode::dump(str);
|
||||
if (m_repType != VTransRepType::NONE) str << " " << m_repType.ascii();
|
||||
}
|
||||
|
||||
void AstCoverTransItem::dumpJson(std::ostream& str) const {
|
||||
this->AstNode::dumpJson(str);
|
||||
if (m_repType != VTransRepType::NONE) { str << ", \"repType\": " << m_repType.asciiJson(); }
|
||||
}
|
||||
|
||||
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 << " " << m_type.ascii();
|
||||
}
|
||||
|
||||
void AstCoverOption::dumpJson(std::ostream& str) const {
|
||||
this->AstNode::dumpJson(str);
|
||||
str << ", \"optionType\": \"" << m_type.ascii() << "\"";
|
||||
}
|
||||
|
||||
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); }
|
||||
|
|
|
|||
|
|
@ -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: Covergroup 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_V3COVERGROUP_H_
|
||||
#define VERILATOR_V3COVERGROUP_H_
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Error.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Covergroup final {
|
||||
public:
|
||||
static void covergroup(AstNetlist* nodep);
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
|
@ -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());
|
||||
|
|
@ -267,7 +273,6 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
|
|||
if (nodep->sensp()) puts(" ");
|
||||
iterateChildrenConst(nodep);
|
||||
}
|
||||
void visit(AstCReset* nodep) override { puts("/*CRESET*/"); }
|
||||
void visit(AstCase* nodep) override {
|
||||
putfs(nodep, "");
|
||||
if (nodep->priorityPragma()) puts("priority ");
|
||||
|
|
|
|||
|
|
@ -130,6 +130,7 @@ class V3Global final {
|
|||
bool m_hasSystemCSections = false; // Has AstSystemCSection that need to be emitted
|
||||
bool m_useParallelBuild = false; // Use parallel build for model
|
||||
bool m_useRandSequence = false; // Has `randsequence`
|
||||
bool m_useCovergroup = false; // Has covergroup declarations
|
||||
bool m_useRandomizeMethods = false; // Need to define randomize() class methods
|
||||
uint64_t m_currentHierBlockCost = 0; // Total cost of this hier block, used for scheduling
|
||||
|
||||
|
|
@ -213,6 +214,8 @@ public:
|
|||
void useParallelBuild(bool flag) { m_useParallelBuild = flag; }
|
||||
bool useRandSequence() const { return m_useRandSequence; }
|
||||
void useRandSequence(bool flag) { m_useRandSequence = flag; }
|
||||
bool useCovergroup() const { return m_useCovergroup; }
|
||||
void useCovergroup(bool flag) { m_useCovergroup = flag; }
|
||||
bool useRandomizeMethods() const { return m_useRandomizeMethods; }
|
||||
void useRandomizeMethods(bool flag) { m_useRandomizeMethods = flag; }
|
||||
void saveJsonPtrFieldName(const std::string& fieldName);
|
||||
|
|
|
|||
|
|
@ -308,7 +308,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
|
||||
|
|
|
|||
|
|
@ -1107,6 +1107,216 @@ class LinkParseVisitor final : public VNVisitor {
|
|||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
// Create boilerplate covergroup methods on the given AstClass.
|
||||
// argsp/sampleArgsp are the raw arg lists still owned by the caller; they are iterated
|
||||
// (cloned) but not deleted here.
|
||||
static void createCovergroupMethods(AstClass* nodep, AstNode* argsp, AstNode* sampleArgsp) {
|
||||
// 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
|
||||
if (argsp) {
|
||||
// Find the 'new' function to add parameters to
|
||||
AstFunc* newFuncp = nullptr;
|
||||
for (AstNode* memberp = nodep->membersp(); memberp; memberp = memberp->nextp()) {
|
||||
if (AstFunc* const 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
|
||||
for (AstNode* argp = argsp; argp; argp = argp->nextp()) {
|
||||
if (AstVar* const origVarp = VN_CAST(argp, Var)) {
|
||||
AstVar* const paramp = origVarp->cloneTree(false);
|
||||
paramp->funcLocal(true);
|
||||
paramp->direction(VDirection::INPUT);
|
||||
newFuncp->addStmtsp(paramp);
|
||||
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});
|
||||
}
|
||||
}
|
||||
if (existingBodyp) newFuncp->addStmtsp(existingBodyp);
|
||||
}
|
||||
}
|
||||
|
||||
// IEEE: option
|
||||
{
|
||||
v3Global.setUsesStdPackage();
|
||||
AstVar* const varp
|
||||
= new AstVar{nodep->fileline(), VVarType::MEMBER, "option", VFlagChildDType{},
|
||||
new AstRefDType{nodep->fileline(), "vl_covergroup_options_t",
|
||||
new AstClassOrPackageRef{nodep->fileline(), "std",
|
||||
nullptr, nullptr},
|
||||
nullptr}};
|
||||
nodep->addMembersp(varp);
|
||||
}
|
||||
|
||||
// IEEE: type_option
|
||||
{
|
||||
v3Global.setUsesStdPackage();
|
||||
AstVar* const varp
|
||||
= new AstVar{nodep->fileline(), VVarType::MEMBER, "type_option", VFlagChildDType{},
|
||||
new AstRefDType{nodep->fileline(), "vl_covergroup_type_options_t",
|
||||
new AstClassOrPackageRef{nodep->fileline(), "std",
|
||||
nullptr, nullptr},
|
||||
nullptr}};
|
||||
nodep->addMembersp(varp);
|
||||
}
|
||||
|
||||
// IEEE: function void sample([arguments])
|
||||
{
|
||||
AstFunc* const funcp = new AstFunc{nodep->fileline(), "sample", nullptr, nullptr};
|
||||
if (sampleArgsp) {
|
||||
for (AstNode* argp = sampleArgsp; argp; argp = argp->nextp()) {
|
||||
if (AstVar* const origVarp = VN_CAST(argp, Var)) {
|
||||
AstVar* const paramp = origVarp->cloneTree(false);
|
||||
paramp->funcLocal(true);
|
||||
paramp->direction(VDirection::INPUT);
|
||||
funcp->addStmtsp(paramp);
|
||||
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);
|
||||
}
|
||||
|
||||
// IEEE: function void start(), void stop()
|
||||
for (const string& name : {"start"s, "stop"s}) {
|
||||
AstFunc* const funcp = new AstFunc{nodep->fileline(), name, nullptr, nullptr};
|
||||
funcp->classMethod(true);
|
||||
funcp->dtypep(funcp->findVoidDType());
|
||||
nodep->addMembersp(funcp);
|
||||
}
|
||||
|
||||
// IEEE: static function real get_coverage(optional ref int, optional ref int)
|
||||
// IEEE: function real get_inst_coverage(optional ref int, optional ref int)
|
||||
for (const string& name : {"get_coverage"s, "get_inst_coverage"s}) {
|
||||
AstFunc* const funcp = new AstFunc{nodep->fileline(), name, nullptr, nullptr};
|
||||
funcp->fileline()->warnOff(V3ErrorCode::NORETURN, true);
|
||||
funcp->isStatic(name == "get_coverage");
|
||||
funcp->classMethod(true);
|
||||
funcp->dtypep(funcp->findVoidDType());
|
||||
nodep->addMembersp(funcp);
|
||||
{
|
||||
AstVar* const varp = new AstVar{nodep->fileline(), VVarType::MEMBER, name,
|
||||
nodep->findDoubleDType()};
|
||||
varp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
|
||||
varp->funcLocal(true);
|
||||
varp->direction(VDirection::OUTPUT);
|
||||
varp->funcReturn(true);
|
||||
funcp->fvarp(varp);
|
||||
}
|
||||
for (const string& varname : {"covered_bins"s, "total_bins"s}) {
|
||||
AstVar* const varp = new AstVar{nodep->fileline(), VVarType::MEMBER, varname,
|
||||
nodep->findStringDType()};
|
||||
varp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
|
||||
varp->funcLocal(true);
|
||||
varp->direction(VDirection::INPUT);
|
||||
varp->valuep(new AstVarRef{nodep->fileline(), defaultVarp, VAccess::READ});
|
||||
funcp->addStmtsp(varp);
|
||||
}
|
||||
}
|
||||
|
||||
// IEEE: function void set_inst_name(string)
|
||||
{
|
||||
AstFunc* const funcp
|
||||
= new AstFunc{nodep->fileline(), "set_inst_name", nullptr, nullptr};
|
||||
funcp->classMethod(true);
|
||||
funcp->dtypep(funcp->findVoidDType());
|
||||
nodep->addMembersp(funcp);
|
||||
AstVar* const varp = new AstVar{nodep->fileline(), VVarType::MEMBER, "name",
|
||||
nodep->findStringDType()};
|
||||
varp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
|
||||
varp->funcLocal(true);
|
||||
varp->direction(VDirection::INPUT);
|
||||
funcp->addStmtsp(varp);
|
||||
}
|
||||
}
|
||||
|
||||
void visit(AstCovergroup* nodep) override {
|
||||
// If we're already inside a covergroup class, this is the sentinel AstCovergroup
|
||||
// node carrying the clocking event for V3Covergroup - don't re-transform it.
|
||||
if (m_modp && VN_IS(m_modp, Class) && VN_CAST(m_modp, Class)->isCovergroup()) return;
|
||||
|
||||
// Transform raw parse-time AstCovergroup into a fully-formed AstClass
|
||||
cleanFileline(nodep);
|
||||
|
||||
const string libname = m_modp ? m_modp->libname() : "";
|
||||
AstClass* const cgClassp = new AstClass{nodep->fileline(), nodep->name(), libname};
|
||||
cgClassp->isCovergroup(true);
|
||||
v3Global.useCovergroup(true);
|
||||
|
||||
// Clocking event: unlink before deleteTree, attach as AstCovergroup child on class
|
||||
if (AstSenTree* const eventp = nodep->eventp()) {
|
||||
eventp->unlinkFrBack();
|
||||
AstCovergroup* const cgNodep = new AstCovergroup{
|
||||
nodep->fileline(), nodep->name(), nullptr, nullptr, nullptr, eventp};
|
||||
cgClassp->addMembersp(cgNodep);
|
||||
}
|
||||
|
||||
// Convert constructor args to member variables
|
||||
for (AstNode* argp = nodep->argsp(); argp; argp = argp->nextp()) {
|
||||
if (AstVar* const origVarp = VN_CAST(argp, Var)) {
|
||||
AstVar* const memberp = origVarp->cloneTree(false);
|
||||
memberp->varType(VVarType::MEMBER);
|
||||
memberp->funcLocal(false);
|
||||
memberp->direction(VDirection::NONE);
|
||||
cgClassp->addMembersp(memberp);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert sample args to member variables
|
||||
for (AstNode* argp = nodep->sampleArgsp(); argp; argp = argp->nextp()) {
|
||||
if (AstVar* const origVarp = VN_CAST(argp, Var)) {
|
||||
AstVar* const memberp = origVarp->cloneTree(false);
|
||||
memberp->varType(VVarType::MEMBER);
|
||||
memberp->funcLocal(false);
|
||||
memberp->direction(VDirection::NONE);
|
||||
cgClassp->addMembersp(memberp);
|
||||
}
|
||||
}
|
||||
|
||||
// Create the constructor; detach membersp (coverage body) and use as its body
|
||||
{
|
||||
AstFunc* const newp = new AstFunc{nodep->fileline(), "new", nullptr, nullptr};
|
||||
newp->fileline()->warnOff(V3ErrorCode::NORETURN, true);
|
||||
newp->classMethod(true);
|
||||
newp->isConstructor(true);
|
||||
newp->dtypep(cgClassp->dtypep());
|
||||
if (AstNode* const bodyp = nodep->membersp()) {
|
||||
bodyp->unlinkFrBackWithNext();
|
||||
newp->addStmtsp(bodyp);
|
||||
}
|
||||
cgClassp->addMembersp(newp);
|
||||
}
|
||||
|
||||
// Add all boilerplate covergroup methods (reads argsp/sampleArgsp from nodep)
|
||||
createCovergroupMethods(cgClassp, nodep->argsp(), nodep->sampleArgsp());
|
||||
|
||||
// Replace AstCovergroup with AstClass and process the new class normally
|
||||
nodep->replaceWith(cgClassp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
iterate(cgClassp);
|
||||
}
|
||||
|
||||
void visit(AstNode* nodep) override {
|
||||
// Default: Just iterate
|
||||
cleanFileline(nodep);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
@ -295,7 +299,6 @@ class CodeMotionAnalysisVisitor final : public VNVisitorConst {
|
|||
iterateChildrenConst(nodep);
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
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:
|
||||
|
|
@ -92,96 +94,65 @@ public:
|
|||
nodep->trace(singletonp()->allTracingOn(fileline));
|
||||
return nodep;
|
||||
}
|
||||
void createCoverGroupMethods(AstClass* nodep, 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);
|
||||
// Helper to move bins from parser list to coverpoint
|
||||
void addCoverpointBins(AstCoverpoint* cp, AstNode* binsList) {
|
||||
if (!binsList) return;
|
||||
|
||||
// IEEE: option
|
||||
{
|
||||
v3Global.setUsesStdPackage();
|
||||
AstVar* const varp
|
||||
= new AstVar{nodep->fileline(), VVarType::MEMBER, "option", VFlagChildDType{},
|
||||
new AstRefDType{nodep->fileline(), "vl_covergroup_options_t",
|
||||
new AstClassOrPackageRef{nodep->fileline(), "std",
|
||||
nullptr, nullptr},
|
||||
nullptr}};
|
||||
nodep->addMembersp(varp);
|
||||
}
|
||||
// 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;
|
||||
|
||||
// IEEE: type_option
|
||||
{
|
||||
v3Global.setUsesStdPackage();
|
||||
AstVar* const varp
|
||||
= new AstVar{nodep->fileline(), VVarType::MEMBER, "type_option", VFlagChildDType{},
|
||||
new AstRefDType{nodep->fileline(), "vl_covergroup_type_options_t",
|
||||
new AstClassOrPackageRef{nodep->fileline(), "std",
|
||||
nullptr, nullptr},
|
||||
nullptr}};
|
||||
nodep->addMembersp(varp);
|
||||
}
|
||||
// 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
|
||||
|
||||
// IEEE: function void sample()
|
||||
{
|
||||
AstFunc* const funcp = new AstFunc{nodep->fileline(), "sample", nullptr, nullptr};
|
||||
funcp->addStmtsp(sampleArgs);
|
||||
funcp->classMethod(true);
|
||||
funcp->dtypep(funcp->findVoidDType());
|
||||
nodep->addMembersp(funcp);
|
||||
}
|
||||
// Now unlink all bins - they all have backp now
|
||||
for (AstNode *binp = binsList, *nextp; binp; binp = nextp) {
|
||||
nextp = binp->nextp();
|
||||
|
||||
// IEEE: function void start(), void stop()
|
||||
for (const string& name : {"start"s, "stop"s}) {
|
||||
AstFunc* const funcp = new AstFunc{nodep->fileline(), name, nullptr, nullptr};
|
||||
funcp->classMethod(true);
|
||||
funcp->dtypep(funcp->findVoidDType());
|
||||
nodep->addMembersp(funcp);
|
||||
}
|
||||
|
||||
// IEEE: static function real get_coverage(optional ref int, optional ref int)
|
||||
// IEEE: function real get_inst_coverage(optional ref int, optional ref int)
|
||||
for (const string& name : {"get_coverage"s, "get_inst_coverage"s}) {
|
||||
AstFunc* const funcp = new AstFunc{nodep->fileline(), name, nullptr, nullptr};
|
||||
funcp->fileline()->warnOff(V3ErrorCode::NORETURN, true);
|
||||
funcp->isStatic(name == "get_coverage");
|
||||
funcp->classMethod(true);
|
||||
funcp->dtypep(funcp->findVoidDType());
|
||||
nodep->addMembersp(funcp);
|
||||
{
|
||||
AstVar* const varp = new AstVar{nodep->fileline(), VVarType::MEMBER, name,
|
||||
nodep->findDoubleDType()};
|
||||
varp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
|
||||
varp->funcLocal(true);
|
||||
varp->direction(VDirection::OUTPUT);
|
||||
varp->funcReturn(true);
|
||||
funcp->fvarp(varp);
|
||||
}
|
||||
for (const string& varname : {"covered_bins"s, "total_bins"s}) {
|
||||
AstVar* const varp = new AstVar{nodep->fileline(), VVarType::MEMBER, varname,
|
||||
nodep->findStringDType()};
|
||||
varp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
|
||||
varp->funcLocal(true);
|
||||
varp->direction(VDirection::INPUT);
|
||||
varp->valuep(new AstVarRef{nodep->fileline(), defaultVarp, VAccess::READ});
|
||||
funcp->addStmtsp(varp);
|
||||
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);
|
||||
}
|
||||
}
|
||||
// IEEE: function void set_inst_name(string)
|
||||
{
|
||||
AstFunc* const funcp
|
||||
= new AstFunc{nodep->fileline(), "set_inst_name", nullptr, nullptr};
|
||||
funcp->classMethod(true);
|
||||
funcp->dtypep(funcp->findVoidDType());
|
||||
nodep->addMembersp(funcp);
|
||||
AstVar* const varp = new AstVar{nodep->fileline(), VVarType::MEMBER, "name",
|
||||
nodep->findStringDType()};
|
||||
varp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
|
||||
varp->funcLocal(true);
|
||||
varp->direction(VDirection::INPUT);
|
||||
funcp->addStmtsp(varp);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
|
@ -914,8 +933,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()});
|
||||
|
|
|
|||
|
|
@ -1699,8 +1699,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 {
|
||||
|
|
@ -3320,6 +3344,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());
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
#include "V3Control.h"
|
||||
#include "V3Coverage.h"
|
||||
#include "V3CoverageJoin.h"
|
||||
#include "V3Covergroup.h"
|
||||
#include "V3Dead.h"
|
||||
#include "V3Delayed.h"
|
||||
#include "V3Depth.h"
|
||||
|
|
@ -156,7 +157,10 @@ static void process() {
|
|||
}
|
||||
|
||||
// Convert parseref's to varrefs, and other directly post parsing fixups
|
||||
// Note: must run before removeStd() as it may create std:: references (e.g. covergroups)
|
||||
V3LinkParse::linkParse(v3Global.rootp());
|
||||
// Remove std package if unused (must be after V3LinkParse which may set usesStdPackage)
|
||||
v3Global.removeStd();
|
||||
// Cross-link signal names
|
||||
// Cross-link dotted hierarchical references
|
||||
V3LinkDot::linkDotPrimary(v3Global.rootp());
|
||||
|
|
@ -230,6 +234,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
|
||||
if (v3Global.useCovergroup()) V3Covergroup::covergroup(v3Global.rootp());
|
||||
|
||||
// Resolve randsequence if they are used by the design
|
||||
if (v3Global.useRandSequence()) V3RandSequence::randSequenceNetlist(v3Global.rootp());
|
||||
|
||||
|
|
@ -737,7 +745,6 @@ static bool verilate(const string& argString) {
|
|||
|
||||
// Read first filename
|
||||
v3Global.readFiles();
|
||||
v3Global.removeStd();
|
||||
|
||||
// Link, etc, if needed
|
||||
if (!v3Global.opt.preprocOnly()) { //
|
||||
|
|
|
|||
332
src/verilog.y
332
src/verilog.y
|
|
@ -6895,40 +6895,23 @@ covergroup_declaration<nodep>: // ==IEEE: covergroup_declaration
|
|||
yCOVERGROUP idAny cgPortListE coverage_eventE ';'
|
||||
/*cont*/ coverage_spec_or_optionListE
|
||||
/*cont*/ yENDGROUP endLabelE
|
||||
{ AstClass *cgClassp = new AstClass{$<fl>2, *$2, PARSEP->libname()};
|
||||
cgClassp->isCovergroup(true);
|
||||
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);
|
||||
|
||||
$$ = cgClassp;
|
||||
GRAMMARP->endLabel($<fl>8, $$, $8);
|
||||
BBCOVERIGN($<fl>1, "Ignoring unsupported: covergroup");
|
||||
}
|
||||
{ AstSenTree* clockp = nullptr;
|
||||
AstNode* sampleArgsp = nullptr;
|
||||
if ($4) {
|
||||
if (VN_IS($4, SenItem))
|
||||
clockp = new AstSenTree{$<fl>1, VN_AS($4, SenItem)};
|
||||
else
|
||||
sampleArgsp = $4;
|
||||
}
|
||||
$$ = new AstCovergroup{$<fl>1, *$2, static_cast<AstVar*>($3),
|
||||
static_cast<AstVar*>(sampleArgsp), $6, clockp};
|
||||
GRAMMARP->endLabel($<fl>8, $$, $8); }
|
||||
| yCOVERGROUP yEXTENDS idAny ';'
|
||||
/*cont*/ coverage_spec_or_optionListE
|
||||
/*cont*/ yENDGROUP endLabelE
|
||||
{ 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);
|
||||
newp->classMethod(true);
|
||||
newp->isConstructor(true);
|
||||
newp->dtypep(cgClassp->dtypep());
|
||||
newp->addStmtsp($5);
|
||||
cgClassp->addMembersp(newp);
|
||||
GRAMMARP->createCoverGroupMethods(cgClassp, nullptr);
|
||||
|
||||
$$ = cgClassp;
|
||||
GRAMMARP->endLabel($<fl>7, $$, $7);
|
||||
BBCOVERIGN($<fl>1, "Ignoring unsupported: covergroup");
|
||||
}
|
||||
{ BBCOVERIGN($1, "Ignoring unsupported: covergroup inheritance (extends)");
|
||||
$$ = new AstCovergroup{$<fl>3, *$3, nullptr, nullptr, $5, nullptr};
|
||||
GRAMMARP->endLabel($<fl>7, $$, $7); }
|
||||
;
|
||||
|
||||
cgPortListE<nodep>:
|
||||
|
|
@ -6975,21 +6958,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); }
|
||||
{ AstCoverpoint* const 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);}
|
||||
{ AstCoverpoint* const 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);}
|
||||
{ AstCoverpoint* const 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); }
|
||||
{ AstCoverpoint* const 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); }
|
||||
{ AstCoverpoint* const 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); }
|
||||
{ AstCoverpoint* const 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); }
|
||||
{ AstCoverpoint* const 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; }
|
||||
;
|
||||
|
|
@ -6997,7 +7005,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
|
||||
|
|
@ -7021,55 +7029,127 @@ 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 ']'
|
||||
|
|
@ -7084,7 +7164,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; }
|
||||
;
|
||||
|
||||
|
|
@ -7096,9 +7176,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
|
||||
|
|
@ -7113,7 +7278,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
|
||||
|
|
@ -7133,12 +7299,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
|
||||
;
|
||||
|
||||
|
|
@ -7159,7 +7329,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 ')'
|
||||
|
|
@ -7204,7 +7374,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,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,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,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,51 @@
|
|||
// 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 viewing individual bin hit counts
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
/* verilator lint_off UNSIGNED */
|
||||
logic [3:0] data;
|
||||
|
||||
covergroup cg;
|
||||
coverpoint data {
|
||||
bins zero = {0};
|
||||
bins low = {[1:3]};
|
||||
bins mid = {[4:7]};
|
||||
bins high = {[8:15]};
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg cg_inst;
|
||||
|
||||
initial begin
|
||||
cg_inst = new;
|
||||
|
||||
// Sample various values with different frequencies
|
||||
data = 0; cg_inst.sample(); // zero: 1
|
||||
data = 1; cg_inst.sample(); // low: 1
|
||||
data = 2; cg_inst.sample(); // low: 2
|
||||
data = 2; cg_inst.sample(); // low: 3
|
||||
data = 5; cg_inst.sample(); // mid: 1
|
||||
data = 10; cg_inst.sample(); // high: 1
|
||||
|
||||
// Verify coverage is 100% (all 4 bins hit)
|
||||
check_coverage(100.0, "final");
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
task check_coverage(real expected, string label);
|
||||
real cov;
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display("Coverage %s: %0.2f%% (expected ~%0.2f%%)", label, cov, expected);
|
||||
if (cov < expected - 0.5 || cov > expected + 0.5) begin
|
||||
$error("Coverage mismatch: got %0.2f%%, expected ~%0.2f%%", cov, expected);
|
||||
$stop;
|
||||
end
|
||||
endtask
|
||||
endmodule
|
||||
|
|
@ -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 bin options: at_least, weight, goal
|
||||
|
||||
module t;
|
||||
/* verilator lint_off UNSIGNED */
|
||||
bit [7:0] addr;
|
||||
|
||||
covergroup cg;
|
||||
option.per_instance = 1;
|
||||
option.comment = "Test covergroup with options";
|
||||
|
||||
coverpoint addr {
|
||||
option.at_least = 2; // Each bin needs at least 2 hits
|
||||
option.weight = 10; // This coverpoint has weight 10
|
||||
|
||||
bins low = {[0:3]};
|
||||
bins mid = {[4:7]};
|
||||
bins high = {[8:15]};
|
||||
}
|
||||
endgroup
|
||||
|
||||
initial begin
|
||||
cg cg_inst;
|
||||
real cov;
|
||||
|
||||
cg_inst = new();
|
||||
|
||||
// Hit low once - should be 0% because at_least = 2
|
||||
addr = 2;
|
||||
cg_inst.sample();
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display("After 1 hit: %0.2f%%", cov);
|
||||
if (cov != 0.0) begin
|
||||
$error("Expected 0%% (bin needs 2 hits), got %0.2f%%", cov);
|
||||
end
|
||||
|
||||
// Hit low again - should be 33.33% (1/3 bins)
|
||||
addr = 1;
|
||||
cg_inst.sample();
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display("After 2 hits to low: %0.2f%%", cov);
|
||||
if (cov < 30.0 || cov > 35.0) begin
|
||||
$error("Expected ~33.33%%, got %0.2f%%", cov);
|
||||
end
|
||||
|
||||
// Hit mid twice - should be 66.67% (2/3 bins)
|
||||
addr = 5; cg_inst.sample();
|
||||
addr = 6; cg_inst.sample();
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display("After mid hits: %0.2f%%", cov);
|
||||
if (cov < 63.0 || cov > 70.0) begin
|
||||
$error("Expected ~66.67%%, got %0.2f%%", cov);
|
||||
end
|
||||
|
||||
// Hit high twice - should be 100%
|
||||
addr = 10; cg_inst.sample();
|
||||
addr = 12; cg_inst.sample();
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display("After all bins hit: %0.2f%%", cov);
|
||||
if (cov != 100.0) begin
|
||||
$error("Expected 100%%, got %0.2f%%", cov);
|
||||
end
|
||||
|
||||
$display("Bin options test PASSED");
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
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,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,63 @@
|
|||
// 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 querying coverage values via get_inst_coverage
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
/* verilator lint_off UNSIGNED */
|
||||
logic [3:0] data;
|
||||
|
||||
covergroup cg;
|
||||
coverpoint data {
|
||||
bins low = {[0:3]};
|
||||
bins mid = {[4:7]};
|
||||
bins high = {[8:15]};
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg cg_inst;
|
||||
|
||||
initial begin
|
||||
cg_inst = new;
|
||||
|
||||
// Initially no coverage
|
||||
check_coverage(0.0, "initial");
|
||||
|
||||
// Sample low bin - should be 33.33% (1 of 3 bins)
|
||||
data = 1;
|
||||
cg_inst.sample();
|
||||
check_coverage(33.33, "after low");
|
||||
|
||||
// Sample mid bin - should be 66.67% (2 of 3 bins)
|
||||
data = 5;
|
||||
cg_inst.sample();
|
||||
check_coverage(66.67, "after mid");
|
||||
|
||||
// Sample high bin - should be 100% (3 of 3 bins)
|
||||
data = 10;
|
||||
cg_inst.sample();
|
||||
check_coverage(100.0, "after high");
|
||||
|
||||
// Sample again - coverage should still be 100%
|
||||
data = 2;
|
||||
cg_inst.sample();
|
||||
check_coverage(100.0, "after resample");
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
task check_coverage(real expected, string label);
|
||||
real cov;
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display("Coverage %s: %0.2f%% (expected ~%0.2f%%)", label, cov, expected);
|
||||
// Allow 0.5% tolerance for floating point
|
||||
if (cov < expected - 0.5 || cov > expected + 0.5) begin
|
||||
$error("Coverage mismatch: got %0.2f%%, expected ~%0.2f%%", cov, expected);
|
||||
$stop;
|
||||
end
|
||||
endtask
|
||||
endmodule
|
||||
|
|
@ -1,20 +1,3 @@
|
|||
%Warning-COVERIGN: t/t_covergroup_coverpoints_unsup.v:21:19: Ignoring unsupported: coverage clocking event
|
||||
21 | covergroup cg @(posedge clk);
|
||||
| ^
|
||||
... 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_coverpoints_unsup.v:22:9: Ignoring unsupported: coverpoint
|
||||
22 | coverpoint a;
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_coverpoints_unsup.v:24:31: Ignoring unsupported: cover bin specification
|
||||
24 | bins the_bins [5] = { [0:20] };
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_coverpoints_unsup.v:23:9: Ignoring unsupported: coverpoint
|
||||
23 | coverpoint b {
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_coverpoints_unsup.v:21:5: Ignoring unsupported: covergroup
|
||||
21 | covergroup cg @(posedge clk);
|
||||
| ^~~~~~~~~~
|
||||
%Error: t/t_covergroup_coverpoints_unsup.v:35:48: Member 'a' not found in covergroup 'cg'
|
||||
: ... note: In instance 't'
|
||||
35 | $display("coverage a = %f", the_cg.a.get_inst_coverage());
|
||||
|
|
|
|||
|
|
@ -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,83 @@
|
|||
// 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 functionality
|
||||
|
||||
module t;
|
||||
/* verilator lint_off UNSIGNED */
|
||||
bit [7:0] addr;
|
||||
bit [7:0] cmd;
|
||||
|
||||
covergroup cg;
|
||||
// Two coverpoints with 2 bins each
|
||||
a: coverpoint addr {
|
||||
bins low = {[0:3]};
|
||||
bins high = {[4:7]};
|
||||
}
|
||||
|
||||
b: coverpoint cmd {
|
||||
bins read = {0};
|
||||
bins write = {1};
|
||||
}
|
||||
|
||||
// 2-way cross creates 4 bins: lowread, lowwrite, highread, highwrite
|
||||
c: cross a, b;
|
||||
endgroup
|
||||
|
||||
initial begin
|
||||
cg cg_inst;
|
||||
real cov;
|
||||
|
||||
cg_inst = new();
|
||||
|
||||
// Initially coverage should be 0%
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
if (cov != 0.0) begin
|
||||
$error("Initial coverage should be 0%%, got %0.2f%%", cov);
|
||||
end
|
||||
|
||||
// Hit lowread
|
||||
addr = 2; cmd = 0;
|
||||
cg_inst.sample();
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
// Should have: a.low(1), b.read(1), c.low_x__read(1) = 3/8 = 37.5%
|
||||
if (cov < 35.0 || cov > 40.0) begin
|
||||
$error("After 1 sample, expected ~37.5%%, got %0.2f%%", cov);
|
||||
end
|
||||
|
||||
// Hit highwrite
|
||||
addr = 5; cmd = 1;
|
||||
cg_inst.sample();
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
// Should have: a.low(1), a.high(1), b.read(1), b.write(1),
|
||||
// c.low_x__read(1), c.high_x__write(1) = 6/8 = 75%
|
||||
if (cov < 70.0 || cov > 80.0) begin
|
||||
$error("After 2 samples, expected ~75%%, got %0.2f%%", cov);
|
||||
end
|
||||
|
||||
// Hit lowwrite
|
||||
addr = 1; cmd = 1;
|
||||
cg_inst.sample();
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
// Should have 7/8 = 87.5%
|
||||
if (cov < 85.0 || cov > 90.0) begin
|
||||
$error("After 3 samples, expected ~87.5%%, got %0.2f%%", cov);
|
||||
end
|
||||
|
||||
// Hit highread for 100% coverage
|
||||
addr = 7; cmd = 0;
|
||||
cg_inst.sample();
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
// Should have 8/8 = 100%
|
||||
if (cov != 100.0) begin
|
||||
$error("After all bins hit, expected 100%%, got %0.2f%%", cov);
|
||||
end
|
||||
|
||||
$display("Cross coverage test PASSED - final coverage: %0.2f%%", cov);
|
||||
$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,30 @@
|
|||
#!/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=['--coverage'])
|
||||
|
||||
test.execute()
|
||||
|
||||
# Check that coverage database contains functional coverage entries
|
||||
# Format uses control characters as delimiters: C '^At^Bcovergroup^Apage...bin^Blow...h^Bcg.cp.low' count
|
||||
test.file_grep(test.coverage_filename, r'covergroup')
|
||||
test.file_grep(test.coverage_filename, r'bin.{0,2}low') # binlow with possible delimiter
|
||||
test.file_grep(test.coverage_filename, r'bin.{0,2}high') # binhigh with possible delimiter
|
||||
test.file_grep(test.coverage_filename, r'cg\.cp\.low')
|
||||
test.file_grep(test.coverage_filename, r'cg\.cp\.high')
|
||||
|
||||
# Verify both bins have non-zero counts (they were both sampled)
|
||||
test.file_grep(test.coverage_filename, r'.*bin.{0,2}low.*\' [1-9]')
|
||||
test.file_grep(test.coverage_filename, r'.*bin.{0,2}high.*\' [1-9]')
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Antmicro
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test that functional coverage is properly written to coverage database
|
||||
// Checks that coverage.dat contains covergroup entries with correct format
|
||||
|
||||
// Expected coverage database entries will contain:
|
||||
// - Type "covergroup"
|
||||
// - Bin names ("low", "high")
|
||||
// - Hierarchy ("cg.cp.low", "cg.cp.high")
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
logic [1:0] data;
|
||||
|
||||
covergroup cg;
|
||||
cp: coverpoint data {
|
||||
bins low = {2'b00};
|
||||
bins high = {2'b11};
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg cg_inst = new;
|
||||
|
||||
initial begin
|
||||
// Sample both bins
|
||||
data = 2'b00;
|
||||
cg_inst.sample();
|
||||
|
||||
data = 2'b11;
|
||||
cg_inst.sample();
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
// 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 default bins - catch-all for values not in other bins
|
||||
|
||||
module t;
|
||||
/* verilator lint_off UNSIGNED */
|
||||
bit [7:0] data;
|
||||
|
||||
covergroup cg;
|
||||
coverpoint data {
|
||||
bins low = {[0:3]};
|
||||
bins high = {[12:15]};
|
||||
bins other = default; // Catches everything else (4-11, 16+)
|
||||
}
|
||||
endgroup
|
||||
|
||||
initial begin
|
||||
cg cg_inst;
|
||||
real cov;
|
||||
|
||||
cg_inst = new();
|
||||
|
||||
// Hit low bin
|
||||
data = 2;
|
||||
cg_inst.sample();
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display("After low: %0.2f%%", cov);
|
||||
if (cov < 30.0 || cov > 35.0) begin
|
||||
$error("Expected ~33.33%% (1/3 bins), got %0.2f%%", cov);
|
||||
end
|
||||
|
||||
// Hit high bin
|
||||
data = 14;
|
||||
cg_inst.sample();
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display("After high: %0.2f%%", cov);
|
||||
if (cov < 63.0 || cov > 70.0) begin
|
||||
$error("Expected ~66.67%% (2/3 bins), got %0.2f%%", cov);
|
||||
end
|
||||
|
||||
// Hit default bin with value 7 (not in low or high)
|
||||
data = 7;
|
||||
cg_inst.sample();
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display("After default (7): %0.2f%%", cov);
|
||||
if (cov != 100.0) begin
|
||||
$error("Expected 100%% (3/3 bins), got %0.2f%%", cov);
|
||||
end
|
||||
|
||||
// Hit another default value (should not increase coverage)
|
||||
data = 20;
|
||||
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("Default bins test PASSED");
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
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,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,63 @@
|
|||
// 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 ignore_bins - excluded from coverage
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
/* verilator lint_off UNSIGNED */
|
||||
logic [3:0] data;
|
||||
|
||||
covergroup cg;
|
||||
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
|
||||
|
||||
cg cg_inst;
|
||||
|
||||
initial begin
|
||||
cg_inst = new;
|
||||
|
||||
// Initially 0% (0 of 3 regular bins)
|
||||
check_coverage(0.0, "initial");
|
||||
|
||||
// Hit reserved bin - should still be 0%
|
||||
data = 13;
|
||||
cg_inst.sample();
|
||||
check_coverage(0.0, "after reserved");
|
||||
|
||||
// Hit low bin - now 33.33% (1 of 3)
|
||||
data = 1;
|
||||
cg_inst.sample();
|
||||
check_coverage(33.33, "after low");
|
||||
|
||||
// Hit another reserved value - still 33.33%
|
||||
data = 15;
|
||||
cg_inst.sample();
|
||||
check_coverage(33.33, "after another reserved");
|
||||
|
||||
// Complete regular bins
|
||||
data = 5; cg_inst.sample(); // mid
|
||||
data = 10; cg_inst.sample(); // high
|
||||
check_coverage(100.0, "complete");
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
task check_coverage(real expected, string label);
|
||||
real cov;
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display("Coverage %s: %0.2f%% (expected ~%0.2f%%)", label, cov, expected);
|
||||
if (cov < expected - 0.5 || cov > expected + 0.5) begin
|
||||
$error("Coverage mismatch: got %0.2f%%, expected ~%0.2f%%", cov, expected);
|
||||
$stop;
|
||||
end
|
||||
endtask
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Test that illegal_bins are excluded from coverage (like ignore_bins)
|
||||
#
|
||||
# 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,39 @@
|
|||
// 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 */
|
||||
logic [1:0] data;
|
||||
|
||||
covergroup cg;
|
||||
coverpoint data {
|
||||
bins low = {0};
|
||||
bins mid = {1};
|
||||
bins high = {2};
|
||||
illegal_bins forbidden = {3};
|
||||
}
|
||||
endgroup
|
||||
|
||||
initial begin
|
||||
automatic cg cg_inst = new;
|
||||
|
||||
// Sample legal values only
|
||||
data = 0;
|
||||
cg_inst.sample();
|
||||
$display("Coverage after low: %f%% (expected ~33.33%%)", cg_inst.get_inst_coverage());
|
||||
|
||||
data = 1;
|
||||
cg_inst.sample();
|
||||
$display("Coverage after mid: %f%% (expected ~66.67%%)", cg_inst.get_inst_coverage());
|
||||
|
||||
data = 2;
|
||||
cg_inst.sample();
|
||||
$display("Coverage complete: %f%% (expected ~100.00%%)", cg_inst.get_inst_coverage());
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
%Error: t/t_covergroup_in_class_duplicate_bad.v:13:14: Duplicate declaration of CLASS '__vlAnonCG_embeddedCg': '__vlAnonCG_embeddedCg'
|
||||
%Error: t/t_covergroup_in_class_duplicate_bad.v:13:3: Duplicate declaration of CLASS '__vlAnonCG_embeddedCg': '__vlAnonCG_embeddedCg'
|
||||
13 | covergroup embeddedCg;
|
||||
| ^~~~~~~~~~
|
||||
t/t_covergroup_in_class_duplicate_bad.v:9:14: ... Location of original declaration
|
||||
| ^~~~~~~~~~
|
||||
t/t_covergroup_in_class_duplicate_bad.v:9:3: ... Location of original declaration
|
||||
9 | covergroup embeddedCg;
|
||||
| ^~~~~~~~~~
|
||||
| ^~~~~~~~~~
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
%Error: Exiting due to
|
||||
|
|
|
|||
|
|
@ -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,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,59 @@
|
|||
// 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 mixed bin types: single values and ranges
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
/* verilator lint_off UNSIGNED */
|
||||
logic [7:0] opcode;
|
||||
|
||||
covergroup cg;
|
||||
coverpoint opcode {
|
||||
bins nop = {8'h00};
|
||||
bins load = {8'h01, 8'h02, 8'h03};
|
||||
bins store = {8'h04, 8'h05};
|
||||
bins arith = {[8'h10:8'h1F]};
|
||||
bins others = {[8'h20:8'hFE]}; // Avoid 0xFF to prevent CMPCONST warning
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg cg_inst;
|
||||
|
||||
initial begin
|
||||
cg_inst = new;
|
||||
|
||||
// Test single value bins
|
||||
opcode = 8'h00; cg_inst.sample(); // nop
|
||||
check_coverage(20.0, "after nop");
|
||||
|
||||
// Test multi-value list bin
|
||||
opcode = 8'h02; cg_inst.sample(); // load
|
||||
check_coverage(40.0, "after load");
|
||||
|
||||
opcode = 8'h05; cg_inst.sample(); // store
|
||||
check_coverage(60.0, "after store");
|
||||
|
||||
// Test range bin
|
||||
opcode = 8'h15; cg_inst.sample(); // arith
|
||||
check_coverage(80.0, "after arith");
|
||||
|
||||
opcode = 8'h80; cg_inst.sample(); // others
|
||||
check_coverage(100.0, "after others");
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
task check_coverage(real expected, string label);
|
||||
real cov;
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display("Coverage %s: %0.2f%% (expected ~%0.2f%%)", label, cov, expected);
|
||||
if (cov < expected - 0.5 || cov > expected + 0.5) begin
|
||||
$error("Coverage mismatch: got %0.2f%%, expected ~%0.2f%%", cov, expected);
|
||||
$stop;
|
||||
end
|
||||
endtask
|
||||
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,60 @@
|
|||
// 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 multiple covergroup instances with separate tracking
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
/* verilator lint_off UNSIGNED */
|
||||
logic [3:0] data1, data2;
|
||||
|
||||
covergroup cg;
|
||||
coverpoint data1 {
|
||||
bins low = {[0:3]};
|
||||
bins high = {[4:15]};
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg cg_inst1, cg_inst2;
|
||||
|
||||
initial begin
|
||||
cg_inst1 = new;
|
||||
cg_inst2 = new;
|
||||
|
||||
// Initially both have 0% coverage
|
||||
check_coverage(cg_inst1, 0.0, "inst1 initial");
|
||||
check_coverage(cg_inst2, 0.0, "inst2 initial");
|
||||
|
||||
// Sample different values in each instance
|
||||
data1 = 1;
|
||||
cg_inst1.sample(); // inst1: low covered (50%)
|
||||
check_coverage(cg_inst1, 50.0, "inst1 after low");
|
||||
check_coverage(cg_inst2, 0.0, "inst2 still empty");
|
||||
|
||||
data1 = 10;
|
||||
cg_inst2.sample(); // inst2: high covered (50%)
|
||||
check_coverage(cg_inst1, 50.0, "inst1 still 50%");
|
||||
check_coverage(cg_inst2, 50.0, "inst2 after high");
|
||||
|
||||
// Complete coverage in inst1
|
||||
data1 = 8;
|
||||
cg_inst1.sample(); // inst1: both covered (100%)
|
||||
check_coverage(cg_inst1, 100.0, "inst1 complete");
|
||||
check_coverage(cg_inst2, 50.0, "inst2 still 50%");
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
task check_coverage(cg inst, real expected, string label);
|
||||
real cov;
|
||||
cov = inst.get_inst_coverage();
|
||||
$display("Coverage %s: %0.2f%% (expected ~%0.2f%%)", label, cov, expected);
|
||||
if (cov < expected - 0.5 || cov > expected + 0.5) begin
|
||||
$error("Coverage mismatch: got %0.2f%%, expected ~%0.2f%%", cov, expected);
|
||||
$stop;
|
||||
end
|
||||
endtask
|
||||
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()
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
// 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
|
||||
|
||||
// Realistic example: Bus transaction coverage
|
||||
|
||||
module t (/*AUTOARG*/);
|
||||
/* verilator lint_off UNSIGNED */
|
||||
logic [31:0] addr;
|
||||
logic [1:0] burst_type;
|
||||
logic valid;
|
||||
|
||||
// Coverage for a memory bus interface
|
||||
covergroup bus_cg;
|
||||
// Address coverage with interesting regions
|
||||
coverpoint addr {
|
||||
bins zero_page = {[32'h0000_0000:32'h0000_00FF]};
|
||||
bins boot_rom = {[32'h0000_1000:32'h0000_1FFF]};
|
||||
bins dram = {[32'h4000_0000:32'h7FFF_FFFF]};
|
||||
bins peripherals = {[32'h8000_0000:32'h9FFF_FFFF]};
|
||||
}
|
||||
|
||||
// Burst type coverage (only when valid)
|
||||
coverpoint burst_type iff (valid) {
|
||||
bins single = {2'b00};
|
||||
bins incr = {2'b01};
|
||||
bins wrap = {2'b10};
|
||||
bins reserved = {2'b11};
|
||||
}
|
||||
endgroup
|
||||
|
||||
bus_cg cg_inst;
|
||||
|
||||
initial begin
|
||||
cg_inst = new;
|
||||
|
||||
// Test various transactions
|
||||
|
||||
// Boot sequence - should hit zero_page and boot_rom
|
||||
valid = 1;
|
||||
addr = 32'h0000_0010; burst_type = 2'b00; cg_inst.sample();
|
||||
addr = 32'h0000_1100; burst_type = 2'b01; cg_inst.sample();
|
||||
|
||||
// After boot
|
||||
check_coverage(50.0, "after boot");
|
||||
|
||||
// DRAM access with wrap burst
|
||||
addr = 32'h4000_0000; burst_type = 2'b10; cg_inst.sample();
|
||||
check_coverage(75.0, "after dram access");
|
||||
|
||||
// Peripheral access completes all addr bins
|
||||
addr = 32'h8000_0100; burst_type = 2'b11; cg_inst.sample();
|
||||
check_coverage(100.0, "complete");
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
task check_coverage(real expected, string label);
|
||||
real cov;
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display("Bus Coverage %s: %0.2f%% (expected ~%0.2f%%)", label, cov, expected);
|
||||
if (cov < expected - 1.0 || cov > expected + 1.0) begin
|
||||
$error("Coverage mismatch: got %0.2f%%, expected ~%0.2f%%", cov, expected);
|
||||
$stop;
|
||||
end
|
||||
endtask
|
||||
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()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue