Merge 199cb3dc14 into 7dcf586807
This commit is contained in:
commit
0c12f214c8
|
|
@ -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,60 @@ 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
|
||||
|
||||
|
||||
.. _line coverage:
|
||||
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ set(HEADERS
|
|||
V3Control.h
|
||||
V3Coverage.h
|
||||
V3CoverageJoin.h
|
||||
V3Covergroup.h
|
||||
V3Dead.h
|
||||
V3DebugBisect.h
|
||||
V3Delayed.h
|
||||
|
|
@ -237,6 +238,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 \
|
||||
|
|
|
|||
158
src/V3Active.cpp
158
src/V3Active.cpp
|
|
@ -619,11 +619,169 @@ public:
|
|||
~ActiveVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Shared state for covergroup sampling passes
|
||||
|
||||
struct CovergroupState final {
|
||||
std::unordered_map<const AstClass*, AstCFunc*> m_sampleFuncs; // Class -> sample CFunc
|
||||
std::unordered_map<const AstClass*, AstSenTree*>
|
||||
m_samplingEvents; // Class -> owned sampling event (if any)
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Pass 1: collect sample CFuncs and sampling events from covergroup class scopes
|
||||
|
||||
class CovergroupCollectVisitor final : public VNVisitor {
|
||||
// STATE
|
||||
CovergroupState& m_state;
|
||||
AstClass* m_classp = nullptr; // Current covergroup class context, or nullptr
|
||||
|
||||
// VISITORS
|
||||
void visit(AstClass* nodep) override {
|
||||
if (!nodep->isCovergroup()) return;
|
||||
VL_RESTORER(m_classp);
|
||||
m_classp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
void visit(AstScope* nodep) override {
|
||||
if (AstClass* const classp = VN_CAST(nodep->modp(), Class)) {
|
||||
if (classp->isCovergroup()) {
|
||||
VL_RESTORER(m_classp);
|
||||
m_classp = classp;
|
||||
iterateChildren(nodep);
|
||||
return;
|
||||
}
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
void visit(AstCFunc* nodep) override {
|
||||
if (!m_classp) return;
|
||||
if (nodep->name().find("sample") != string::npos) {
|
||||
m_state.m_sampleFuncs[m_classp] = nodep;
|
||||
nodep->isCovergroupSample(true);
|
||||
}
|
||||
}
|
||||
|
||||
void visit(AstCovergroup* nodep) override {
|
||||
// V3Covergroup guarantees: only supported-event covergroups survive to V3Active,
|
||||
// and they are always inside a covergroup class (so m_classp is set).
|
||||
// Unlink eventp from cgp so it survives cgp's deletion,
|
||||
// then take ownership in the map for use during the second pass.
|
||||
m_state.m_samplingEvents[m_classp] = nodep->eventp()->unlinkFrBack();
|
||||
nodep->unlinkFrBack();
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
|
||||
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
CovergroupCollectVisitor(AstNetlist* nodep, CovergroupState& state)
|
||||
: m_state{state} {
|
||||
iterate(nodep);
|
||||
}
|
||||
~CovergroupCollectVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Pass 2: inject automatic sample() calls for covergroup instances
|
||||
|
||||
class CovergroupInjectVisitor final : public VNVisitor {
|
||||
// STATE
|
||||
CovergroupState& m_state;
|
||||
ActiveNamer m_namer; // Reuse active naming infrastructure
|
||||
|
||||
// VISITORS
|
||||
void visit(AstScope* nodep) override {
|
||||
m_namer.main(nodep); // Initialize active naming for this scope
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
void visit(AstVarScope* nodep) override {
|
||||
// Get the underlying var
|
||||
AstVar* const varp = nodep->varp();
|
||||
UASSERT_OBJ(varp, nodep, "AstVarScope must have non-null varp");
|
||||
|
||||
// Check if the variable is of covergroup class type
|
||||
const AstNodeDType* const dtypep = varp->dtypep();
|
||||
UASSERT_OBJ(dtypep, nodep, "AstVar must have non-null dtypep after V3Width");
|
||||
|
||||
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
|
||||
const auto evtIt = m_state.m_samplingEvents.find(classp);
|
||||
if (evtIt == m_state.m_samplingEvents.end())
|
||||
return; // No automatic sampling for this covergroup
|
||||
AstSenTree* const eventp = evtIt->second;
|
||||
|
||||
// V3Covergroup guarantees every supported-event covergroup has a registered sample CFunc
|
||||
const auto it = m_state.m_sampleFuncs.find(classp);
|
||||
UASSERT_OBJ(it != m_state.m_sampleFuncs.end(), nodep,
|
||||
"No sample() CFunc found for covergroup " << classp->name());
|
||||
AstCFunc* const sampleCFuncp = it->second;
|
||||
|
||||
// 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};
|
||||
|
||||
cmethodCallp->dtypeSetVoid();
|
||||
cmethodCallp->argTypes("vlSymsp");
|
||||
|
||||
// Clone the sensitivity for this active block.
|
||||
// V3Scope has already resolved all VarRefs in eventp, so the clone
|
||||
// inherits correct varScopep values with no fixup needed.
|
||||
AstSenTree* senTreep = eventp->cloneTree(false);
|
||||
|
||||
// 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);
|
||||
|
||||
// Wrap the sample() call in an AstAlways so SchedPartition handles it
|
||||
// via visit(AstNodeProcedure*) like any other clocked always block.
|
||||
activep->addStmtsp(
|
||||
new AstAlways{fl, VAlwaysKwd::ALWAYS_FF, nullptr, cmethodCallp->makeStmt()});
|
||||
|
||||
UINFO(4, " Added automatic sample() call for covergroup "
|
||||
<< varp->name()); // LCOV_EXCL_BR_LINE
|
||||
}
|
||||
|
||||
void visit(AstActive*) override {} // Don't iterate into actives
|
||||
void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
CovergroupInjectVisitor(AstNetlist* nodep, CovergroupState& state)
|
||||
: m_state{state} {
|
||||
iterate(nodep);
|
||||
}
|
||||
~CovergroupInjectVisitor() override = default;
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Active class functions
|
||||
|
||||
void V3Active::activeAll(AstNetlist* nodep) {
|
||||
UINFO(2, __FUNCTION__ << ":");
|
||||
{ ActiveVisitor{nodep}; } // Destruct before checking
|
||||
if (v3Global.useCovergroup()) {
|
||||
// Add automatic covergroup sampling in two focused passes
|
||||
CovergroupState state;
|
||||
CovergroupCollectVisitor{nodep, state}; // Pass 1: collect CFuncs and events
|
||||
CovergroupInjectVisitor{nodep, state}; // Pass 2: inject sample() calls
|
||||
for (const auto& itpair : state.m_samplingEvents) itpair.second->deleteTree();
|
||||
}
|
||||
V3Global::dumpCheckGlobalTree("active", 0, dumpTreeEitherLevel() >= 3);
|
||||
}
|
||||
|
|
|
|||
107
src/V3AstAttr.h
107
src/V3AstAttr.h
|
|
@ -1107,6 +1107,113 @@ inline std::ostream& operator<<(std::ostream& os, const VCastable& rhs) {
|
|||
|
||||
//######################################################################
|
||||
|
||||
class VCoverBinsType final {
|
||||
public:
|
||||
enum en : uint8_t {
|
||||
BINS_USER, // Single bin with one or more values/ranges
|
||||
BINS_ARRAY, // Array of bins with user-speciifed size
|
||||
BINS_AUTO, // Auto-sized array of bins (eg auto_bin_max)
|
||||
BINS_IGNORE, // Ignore bin
|
||||
BINS_ILLEGAL, // Illegal bin
|
||||
BINS_DEFAULT, // Default bin
|
||||
BINS_WILDCARD, // Wildcard bin
|
||||
BINS_TRANSITION // Transition bin
|
||||
};
|
||||
enum en m_e;
|
||||
VCoverBinsType()
|
||||
: m_e{BINS_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 };
|
||||
|
|
|
|||
|
|
@ -721,6 +721,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;
|
||||
|
|
|
|||
|
|
@ -253,6 +253,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:
|
||||
|
|
@ -513,6 +527,7 @@ class AstCFunc final : public AstNode {
|
|||
bool m_recursive : 1; // Recursive or part of recursion
|
||||
bool m_noLife : 1; // Disable V3Life on this function - has multiple calls, and reads Syms
|
||||
// state
|
||||
bool m_isCovergroupSample : 1; // Automatic covergroup sample() function
|
||||
int m_cost; // Function call cost
|
||||
public:
|
||||
AstCFunc(FileLine* fl, const string& name, AstScope* scopep, const string& rtnType = "")
|
||||
|
|
@ -543,6 +558,7 @@ public:
|
|||
m_dpiImportWrapper = false;
|
||||
m_recursive = false;
|
||||
m_noLife = false;
|
||||
m_isCovergroupSample = false;
|
||||
m_cost = v3Global.opt.instrCountDpi(); // As proxy for unknown general DPI cost
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCFunc;
|
||||
|
|
@ -618,6 +634,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 {
|
||||
|
|
@ -1020,6 +1038,142 @@ public:
|
|||
bool isPredictOptimizable() const override { return false; }
|
||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||
};
|
||||
|
||||
class AstCoverBin final : public AstNode {
|
||||
// Captures data for a coverpoint 'bins' declaration
|
||||
// @astgen op1 := rangesp : List[AstNode]
|
||||
// @astgen op2 := iffp : Optional[AstNodeExpr]
|
||||
// @astgen op3 := arraySizep : Optional[AstNodeExpr]
|
||||
// @astgen op4 := transp : List[AstCoverTransSet]
|
||||
const string m_name; // Base name of the bin
|
||||
const VCoverBinsType m_type; // Bin type (eg AUTO, IGNORE, ILLEGAL)
|
||||
bool m_isArray = false; // Bin is either an auto-sized array of values or transitions
|
||||
|
||||
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::BINS_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::BINS_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,
|
||||
VCoverBinsType type = VCoverBinsType::BINS_TRANSITION, bool isArrayBin = false)
|
||||
: ASTGEN_SUPER_CoverBin(fl)
|
||||
, m_name{name}
|
||||
, m_type{type}
|
||||
, m_isArray{isArrayBin} {
|
||||
UASSERT(transp, "AstCoverBin transition constructor requires non-null 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 AstCoverOption final : public AstNode {
|
||||
// Coverage-option assignment
|
||||
// @astgen op1 := valuep : AstNodeExpr
|
||||
const VCoverOptionType m_type; // Option being assigned
|
||||
|
||||
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 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]
|
||||
const 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;
|
||||
};
|
||||
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 {
|
||||
// Represents a covergroup declaration. V3LinkParse transforms this
|
||||
// into an AstClass with isCovergroup==true and attaches the clocking
|
||||
// event as a new AstCovergroup sentinel in class membersp.
|
||||
// @astgen op1 := argsp : List[AstVar]
|
||||
// @astgen op2 := membersp : List[AstNode]
|
||||
// @astgen op3 := eventp : Optional[AstSenTree]
|
||||
// @astgen op4 := sampleArgsp : List[AstVar]
|
||||
string m_name; // covergroup name
|
||||
|
||||
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;
|
||||
string name() const override VL_MT_STABLE { return m_name; }
|
||||
void name(const string& name) override { m_name = name; }
|
||||
bool maybePointedTo() const override { return true; }
|
||||
};
|
||||
class AstCoverpointRef final : public AstNode {
|
||||
// Reference to a coverpoint used in a cross
|
||||
const string m_name; // coverpoint 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; }
|
||||
};
|
||||
class AstDefParam final : public AstNode {
|
||||
// A defparam assignment
|
||||
// Parents: MODULE
|
||||
|
|
@ -2535,6 +2689,39 @@ 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 := optionsp : List[AstCoverOption] // post-LinkParse only
|
||||
// @astgen op3 := rawBodyp : List[AstNode] // Parse: raw cross_body items;
|
||||
// // post-LinkParse: empty
|
||||
public:
|
||||
AstCoverCross(FileLine* fl, const string& name, AstCoverpointRef* itemsp)
|
||||
: ASTGEN_SUPER_CoverCross(fl, name) {
|
||||
UASSERT(itemsp, "AstCoverCross requires at least one coverpoint reference");
|
||||
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[AstNode] // Parse: mixed AstCoverBin/AstCgOptionAssign;
|
||||
// post-LinkParse: AstCoverBin only
|
||||
// @astgen op3 := iffp : Optional[AstNodeExpr]
|
||||
// @astgen op4 := optionsp : List[AstCoverOption]
|
||||
public:
|
||||
AstCoverpoint(FileLine* fl, const string& name, AstNodeExpr* exprp,
|
||||
AstNodeExpr* iffp = nullptr, AstNode* binsp = nullptr)
|
||||
: ASTGEN_SUPER_Coverpoint(fl, name) {
|
||||
this->exprp(exprp);
|
||||
this->iffp(iffp);
|
||||
if (binsp) addBinsp(binsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCoverpoint;
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
};
|
||||
|
||||
// === AstNodeGen ===
|
||||
class AstGenBlock final : public AstNodeGen {
|
||||
|
|
@ -2617,6 +2804,8 @@ class AstClass final : public AstNodeModule {
|
|||
bool m_needRNG = false; // Need RNG, uses srandom/randomize
|
||||
bool m_useVirtualPublic = false; // Subclasses need virtual public as uses interface class
|
||||
bool m_virtual = false; // Virtual class
|
||||
// Covergroup options (when m_covergroup is true)
|
||||
int m_cgAutoBinMax = -1; // option.auto_bin_max value (-1 = not set, use default 64)
|
||||
|
||||
public:
|
||||
AstClass(FileLine* fl, const string& name, const string& libname)
|
||||
|
|
@ -2644,6 +2833,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);
|
||||
|
|
|
|||
|
|
@ -3495,3 +3495,54 @@ const char* AstNot::widthMismatch() const VL_MT_STABLE {
|
|||
BROKEN_RTN(lhsp()->widthMin() != widthMin());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// Functional coverage dump methods
|
||||
|
||||
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_type.ascii();
|
||||
if (m_isArray) str << "[]";
|
||||
}
|
||||
|
||||
void AstCoverBin::dumpJson(std::ostream& str) const {
|
||||
this->AstNode::dumpJson(str);
|
||||
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); }
|
||||
|
||||
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 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); }
|
||||
|
||||
void AstCoverpointRef::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
|
||||
|
|
@ -282,6 +282,13 @@ class DataflowOptimize final {
|
|||
if (hasExtWr) DfgVertexVar::setHasExtWrRefs(vscp);
|
||||
return;
|
||||
}
|
||||
// TODO: remove once Actives can tolerate NEVER SenItems
|
||||
if (AstSenItem* senItemp = VN_CAST(nodep, SenItem)) {
|
||||
senItemp->foreach([](const AstVarRef* refp) {
|
||||
DfgVertexVar::setHasExtRdRefs(refp->varScopep());
|
||||
});
|
||||
return;
|
||||
}
|
||||
// Check direct references
|
||||
if (const AstVarRef* const refp = VN_CAST(nodep, VarRef)) {
|
||||
if (refp->access().isRW()) DfgVertexVar::setHasRWRefs(refp->varScopep());
|
||||
|
|
|
|||
|
|
@ -267,7 +267,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 ");
|
||||
|
|
@ -307,6 +306,72 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
|
|||
void visit(AstCoverInc*) override {} // N/A
|
||||
void visit(AstCoverToggle*) override {} // N/A
|
||||
|
||||
void visit(AstCovergroup* nodep) override {
|
||||
// AstCovergroup appears as a member inside the lowered AstClass body.
|
||||
// The outer covergroup/endcovergroup wrapper is already emitted by the
|
||||
// AstNodeModule visitor (verilogKwd()="covergroup" on AstClass::isCovergroup).
|
||||
// Here we only emit the clocking event, if any.
|
||||
if (nodep->eventp()) {
|
||||
putfs(nodep, "");
|
||||
iterateConst(nodep->eventp());
|
||||
}
|
||||
}
|
||||
void visit(AstCoverpoint* nodep) override {
|
||||
putfs(nodep, nodep->name() + ": coverpoint ");
|
||||
iterateAndNextConstNull(nodep->exprp());
|
||||
if (nodep->binsp() || nodep->optionsp()) {
|
||||
puts(" {\n");
|
||||
iterateAndNextConstNull(nodep->optionsp());
|
||||
iterateAndNextConstNull(nodep->binsp());
|
||||
puts("}");
|
||||
}
|
||||
puts(";\n");
|
||||
}
|
||||
void visit(AstCoverBin* nodep) override {
|
||||
switch (nodep->binsType()) {
|
||||
case VCoverBinsType::BINS_IGNORE: putfs(nodep, "ignore_bins "); break;
|
||||
case VCoverBinsType::BINS_ILLEGAL: putfs(nodep, "illegal_bins "); break;
|
||||
default: putfs(nodep, "bins "); break;
|
||||
}
|
||||
puts(nodep->name());
|
||||
if (nodep->binsType() == VCoverBinsType::BINS_DEFAULT) {
|
||||
puts(" = default");
|
||||
} else if (nodep->transp()) {
|
||||
puts(" = ");
|
||||
for (AstNode* setp = nodep->transp(); setp; setp = setp->nextp()) {
|
||||
if (setp != nodep->transp()) puts(", ");
|
||||
iterateConst(setp);
|
||||
}
|
||||
} else if (nodep->rangesp()) { // LCOV_EXCL_BR_LINE - false: CoverBin always has
|
||||
// transp/rangesp/default
|
||||
puts(" = {");
|
||||
for (AstNode* rangep = nodep->rangesp(); rangep; rangep = rangep->nextp()) {
|
||||
if (rangep != nodep->rangesp()) puts(", ");
|
||||
iterateConst(rangep);
|
||||
}
|
||||
puts("}");
|
||||
}
|
||||
puts(";\n");
|
||||
}
|
||||
void visit(AstCoverpointRef* nodep) override { putfs(nodep, nodep->name()); }
|
||||
void visit(AstCoverCross* nodep) override {
|
||||
putfs(nodep, nodep->name() + ": cross ");
|
||||
for (AstNode* itemp = nodep->itemsp(); itemp; itemp = itemp->nextp()) {
|
||||
if (itemp != nodep->itemsp()) puts(", ");
|
||||
iterateConst(itemp);
|
||||
}
|
||||
puts(";\n");
|
||||
}
|
||||
void visit(AstCoverTransSet* nodep) override {
|
||||
puts("(");
|
||||
for (AstNode* itemp = nodep->itemsp(); itemp; itemp = itemp->nextp()) {
|
||||
if (itemp != nodep->itemsp()) puts(" => ");
|
||||
iterateConst(itemp);
|
||||
}
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstCoverTransItem* nodep) override { iterateChildrenConst(nodep); }
|
||||
|
||||
void visit(AstCvtPackString* nodep) override {
|
||||
putfs(nodep, "");
|
||||
if (AstConst* const lhsConstp = VN_CAST(nodep->lhsp(), Const)) {
|
||||
|
|
@ -745,6 +810,13 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
|
|||
iterateAndNextConstNull(nodep->elsep());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstInsideRange* nodep) override {
|
||||
puts("[");
|
||||
iterateAndNextConstNull(nodep->lhsp());
|
||||
puts(":");
|
||||
iterateAndNextConstNull(nodep->rhsp());
|
||||
puts("]");
|
||||
}
|
||||
void visit(AstRange* nodep) override {
|
||||
puts("[");
|
||||
if (VN_IS(nodep->leftp(), Const) && VN_IS(nodep->rightp(), Const)) {
|
||||
|
|
@ -942,6 +1014,12 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
|
|||
puts("\n???? // "s + nodep->prettyTypeName() + " -> UNLINKED\n");
|
||||
}
|
||||
}
|
||||
void visit(AstClassRefDType* nodep) override {
|
||||
putfs(nodep, nodep->classp() ? EmitCUtil::prefixNameProtect(
|
||||
nodep->classp()) // LCOV_EXCL_BR_LINE - false: classp
|
||||
// always set after linking
|
||||
: nodep->prettyDTypeName(false));
|
||||
}
|
||||
void visit(AstRequireDType* nodep) override { iterateConst(nodep->lhsp()); }
|
||||
void visit(AstModport* nodep) override {
|
||||
puts(nodep->verilogKwd());
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -1118,6 +1118,263 @@ 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.
|
||||
// At this point the only AstFunc in the class is the "new" constructor
|
||||
// created just above; other members are AstVar or AstCovergroup sentinel.
|
||||
AstFunc* newFuncp = nullptr;
|
||||
for (AstNode* memberp = nodep->membersp(); memberp; memberp = memberp->nextp()) {
|
||||
if (AstFunc* const funcp = VN_CAST(memberp, Func)) {
|
||||
UASSERT_OBJ(
|
||||
funcp->name() == "new", funcp,
|
||||
"Unexpected non-new function in covergroup class during arg setup");
|
||||
newFuncp = funcp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
UASSERT_OBJ(newFuncp, nodep,
|
||||
"Covergroup class must have a 'new' constructor function");
|
||||
// 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()) {
|
||||
AstVar* const origVarp = VN_AS(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 / type_option members allow external access (cg_inst.option.X)
|
||||
// and require std:: types; std:: is kept because setUsesStdPackage() is called
|
||||
// at parse time for every covergroup declaration.
|
||||
{
|
||||
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);
|
||||
}
|
||||
{
|
||||
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()) {
|
||||
AstVar* const origVarp = VN_AS(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()) {
|
||||
AstVar* const origVarp = VN_AS(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()) {
|
||||
AstVar* const origVarp = VN_AS(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(AstCoverpoint* nodep) override {
|
||||
cleanFileline(nodep);
|
||||
// Re-sort the parse-time mixed bins list (AstCoverBin + AstCgOptionAssign)
|
||||
// into the typed binsp and optionsp slots. The grammar attaches both node types
|
||||
// to binsp (op2) as a raw List[AstNode]; now that they are properly parented we
|
||||
// can iterate and split them without any temporary-parent tricks.
|
||||
for (AstNode *itemp = nodep->binsp(), *nextp; itemp; itemp = nextp) {
|
||||
nextp = itemp->nextp();
|
||||
if (AstCgOptionAssign* const optp = VN_CAST(itemp, CgOptionAssign)) {
|
||||
optp->unlinkFrBack();
|
||||
VCoverOptionType optType = VCoverOptionType::COMMENT;
|
||||
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->prettyNameQ());
|
||||
}
|
||||
nodep->addOptionsp(new AstCoverOption{optp->fileline(), optType,
|
||||
optp->valuep()->cloneTree(false)});
|
||||
VL_DO_DANGLING(optp->deleteTree(), optp);
|
||||
}
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
void visit(AstCoverCross* nodep) override {
|
||||
cleanFileline(nodep);
|
||||
// Distribute the parse-time raw cross_body list (rawBodyp, op3) into the
|
||||
// typed optionsp slot. Nodes are properly in-tree here so
|
||||
// unlinkFrBack() works cleanly with no bison-list hackery.
|
||||
for (AstNode *itemp = nodep->rawBodyp(), *nextp; itemp; itemp = nextp) {
|
||||
nextp = itemp->nextp();
|
||||
itemp->unlinkFrBack();
|
||||
if (AstCoverOption* const optp = VN_CAST(itemp, CoverOption)) {
|
||||
nodep->addOptionsp(optp);
|
||||
} else {
|
||||
// AstCgOptionAssign, AstFunc, and other unsupported items
|
||||
VL_DO_DANGLING(itemp->deleteTree(), itemp);
|
||||
}
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
void visit(AstNode* nodep) override {
|
||||
// Default: Just iterate
|
||||
cleanFileline(nodep);
|
||||
|
|
|
|||
|
|
@ -296,6 +296,7 @@ class CodeMotionAnalysisVisitor final : public VNVisitorConst {
|
|||
}
|
||||
|
||||
// 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)
|
||||
|
|
|
|||
|
|
@ -15,11 +15,13 @@
|
|||
//*************************************************************************
|
||||
|
||||
#include "V3Ast.h"
|
||||
#include "V3Const.h"
|
||||
#include "V3Control.h"
|
||||
#include "V3Global.h"
|
||||
#include "V3ParseImp.h" // Defines YYTYPE; before including bison header
|
||||
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
|
||||
class V3ParseGrammar final {
|
||||
public:
|
||||
|
|
@ -94,97 +96,6 @@ 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);
|
||||
|
||||
// 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()
|
||||
{
|
||||
AstFunc* const funcp = new AstFunc{nodep->fileline(), "sample", nullptr, nullptr};
|
||||
funcp->addStmtsp(sampleArgs);
|
||||
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);
|
||||
}
|
||||
}
|
||||
AstDisplay* createDisplayError(FileLine* fileline) {
|
||||
AstDisplay* nodep = new AstDisplay{fileline, VDisplayType::DT_ERROR, "", nullptr, nullptr};
|
||||
AstNode::addNext<AstNode, AstNode>(nodep, new AstStop{fileline, false});
|
||||
|
|
|
|||
|
|
@ -343,11 +343,15 @@ class TimingSuspendableVisitor final : public VNVisitor {
|
|||
}
|
||||
}
|
||||
void visit(AstNodeCCall* nodep) override {
|
||||
new V3GraphEdge{&m_suspGraph, getSuspendDepVtx(nodep->funcp()), getSuspendDepVtx(m_procp),
|
||||
P_CALL};
|
||||
AstCFunc* const funcp = nodep->funcp();
|
||||
UASSERT_OBJ(funcp, nodep, "AstNodeCCall must have non-null funcp post-link");
|
||||
UASSERT_OBJ(m_procp, nodep, "AstNodeCCall must be inside a procedure/CFunc/Begin");
|
||||
|
||||
new V3GraphEdge{&m_procGraph, getNeedsProcDepVtx(nodep->funcp()),
|
||||
getNeedsProcDepVtx(m_procp), P_CALL};
|
||||
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);
|
||||
}
|
||||
|
|
@ -961,8 +965,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()});
|
||||
|
|
|
|||
|
|
@ -224,6 +224,7 @@ class WidthVisitor final : public VNVisitor {
|
|||
const AstCell* m_cellp = nullptr; // Current cell for arrayed instantiations
|
||||
const AstEnumItem* m_enumItemp = nullptr; // Current enum item
|
||||
AstNodeFTask* m_ftaskp = nullptr; // Current function/task
|
||||
AstClass* m_cgClassp = nullptr; // Current covergroup class
|
||||
AstNodeModule* m_modep = nullptr; // Current module
|
||||
const AstConstraint* m_constraintp = nullptr; // Current constraint
|
||||
AstNodeProcedure* m_procedurep = nullptr; // Current final/always
|
||||
|
|
@ -1744,8 +1745,20 @@ 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.
|
||||
// m_cgClassp is always set here: AstCgOptionAssign only appears in covergroup
|
||||
// class bodies, and visitClass sets m_cgClassp before iterating children.
|
||||
if (nodep->name() == "auto_bin_max" && !nodep->typeOption()) {
|
||||
// Extract constant value
|
||||
if (AstConst* constp = VN_CAST(nodep->valuep(), Const)) {
|
||||
m_cgClassp->cgAutoBinMax(constp->toSInt());
|
||||
UINFO(6, " Covergroup " << m_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 {
|
||||
|
|
@ -3387,7 +3400,16 @@ class WidthVisitor final : public VNVisitor {
|
|||
return AstEqWild::newTyped(itemp->fileline(), exprp, itemp->unlinkFrBack());
|
||||
}
|
||||
void visit(AstInsideRange* nodep) override {
|
||||
// Just do each side; AstInside will rip these nodes out later
|
||||
// Just do each side; AstInside will rip these nodes out later.
|
||||
// When m_vup is null, this range appears outside a normal expression context (e.g.
|
||||
// in a covergroup bin declaration). Pre-fold constant arithmetic in that case
|
||||
// (e.g., AstNegate(Const) -> Const) so children have their types set before widthing.
|
||||
// We cannot do this unconditionally: in a normal 'inside' expression (m_vup set),
|
||||
// range bounds may be enum refs not yet widthed, and constifyEdit would crash.
|
||||
if (!m_vup) {
|
||||
V3Const::constifyEdit(nodep->lhsp()); // lhsp may change
|
||||
V3Const::constifyEdit(nodep->rhsp()); // rhsp may change
|
||||
}
|
||||
userIterateAndNext(nodep->lhsp(), m_vup);
|
||||
userIterateAndNext(nodep->rhsp(), m_vup);
|
||||
nodep->dtypeFrom(nodep->lhsp());
|
||||
|
|
@ -7460,6 +7482,8 @@ class WidthVisitor final : public VNVisitor {
|
|||
// Must do extends first, as we may in functions under this class
|
||||
// start following a tree of extends that takes us to other classes
|
||||
userIterateAndNext(nodep->extendsp(), nullptr);
|
||||
VL_RESTORER(m_cgClassp);
|
||||
if (nodep->isCovergroup()) m_cgClassp = nodep;
|
||||
userIterateChildren(nodep, nullptr); // First size all members
|
||||
}
|
||||
void visit(AstNodeModule* nodep) override {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -236,6 +237,10 @@ static void process() {
|
|||
// Before we do dead code elimination and inlining, or we'll lose it.
|
||||
if (v3Global.opt.coverage()) V3Coverage::coverage(v3Global.rootp());
|
||||
|
||||
// Functional coverage code generation
|
||||
// Generate code for covergroups/coverpoints
|
||||
if (v3Global.useCovergroup()) V3Covergroup::covergroup(v3Global.rootp());
|
||||
|
||||
// Resolve randsequence if they are used by the design
|
||||
if (v3Global.useRandSequence()) V3RandSequence::randSequenceNetlist(v3Global.rootp());
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ void VlcOptions::parseOptsList(int argc, char** argv) {
|
|||
DECL_OPTION("-annotate-all", OnOff, &m_annotateAll);
|
||||
DECL_OPTION("-annotate-min", Set, &m_annotateMin);
|
||||
DECL_OPTION("-annotate-points", OnOff, &m_annotatePoints);
|
||||
DECL_OPTION("-covergroup", OnOff, &m_covergroup);
|
||||
DECL_OPTION("-debug", CbCall, []() { V3Error::debugDefault(3); });
|
||||
DECL_OPTION("-debugi", CbVal, [](int v) { V3Error::debugDefault(v); });
|
||||
DECL_OPTION("-filter-type", Set, &m_filterType);
|
||||
|
|
@ -143,6 +144,8 @@ int main(int argc, char** argv) {
|
|||
V3Error::abortIfWarnings();
|
||||
if (!top.opt.annotateOut().empty()) top.annotate(top.opt.annotateOut());
|
||||
|
||||
if (top.opt.covergroup()) top.covergroup();
|
||||
|
||||
if (top.opt.rank()) {
|
||||
top.rank();
|
||||
top.tests().dump(false);
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ class VlcOptions final {
|
|||
bool m_annotateAll = false; // main switch: --annotate-all
|
||||
int m_annotateMin = 10; // main switch: --annotate-min I<count>
|
||||
bool m_annotatePoints = false; // main switch: --annotate-points
|
||||
bool m_covergroup = false; // main switch: --covergroup
|
||||
string m_filterType = "*"; // main switch: --filter-type
|
||||
VlStringSet m_readFiles; // main switch: --read
|
||||
bool m_rank = false; // main switch: --rank
|
||||
|
|
@ -67,6 +68,7 @@ public:
|
|||
int annotateMin() const { return m_annotateMin; }
|
||||
bool countOk(uint64_t count) const { return count >= static_cast<uint64_t>(m_annotateMin); }
|
||||
bool annotatePoints() const { return m_annotatePoints; }
|
||||
bool covergroup() const { return m_covergroup; }
|
||||
bool rank() const { return m_rank; }
|
||||
bool unlink() const { return m_unlink; }
|
||||
string writeFile() const { return m_writeFile; }
|
||||
|
|
|
|||
|
|
@ -65,6 +65,11 @@ public:
|
|||
string comment() const { return keyExtract(VL_CIK_COMMENT, m_name.c_str()); }
|
||||
string hier() const { return keyExtract(VL_CIK_HIER, m_name.c_str()); }
|
||||
string type() const { return typeExtract(m_name.c_str()); }
|
||||
// Covergroup-specific key accessors (long keys, no short-key alias)
|
||||
string page() const { return keyExtract("page", m_name.c_str()); }
|
||||
string bin() const { return keyExtract("bin", m_name.c_str()); }
|
||||
string binType() const { return keyExtract("bin_type", m_name.c_str()); }
|
||||
bool isCross() const { return !keyExtract("cross", m_name.c_str()).empty(); }
|
||||
string thresh() const {
|
||||
// string as maybe ""
|
||||
return keyExtract(VL_CIK_THRESH, m_name.c_str());
|
||||
|
|
|
|||
168
src/VlcTop.cpp
168
src/VlcTop.cpp
|
|
@ -25,6 +25,9 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
|
@ -205,6 +208,171 @@ void VlcTop::rank() {
|
|||
}
|
||||
}
|
||||
|
||||
void VlcTop::covergroup() {
|
||||
UINFO(2, "covergroup...");
|
||||
// Structs for accumulating report data
|
||||
struct BinEntry final {
|
||||
std::string name;
|
||||
std::string binType; // "ignore", "illegal", or "" (normal)
|
||||
bool covered = false;
|
||||
uint64_t count = 0;
|
||||
};
|
||||
struct CpEntry final {
|
||||
std::string name;
|
||||
bool isCross = false;
|
||||
std::vector<BinEntry> bins;
|
||||
uint64_t normalTotal = 0;
|
||||
uint64_t normalCovered = 0;
|
||||
};
|
||||
struct CgEntry final {
|
||||
std::string typeName;
|
||||
std::string filename;
|
||||
int lineno = 0;
|
||||
std::vector<CpEntry> coverpoints;
|
||||
std::map<std::string, size_t> cpIndex;
|
||||
};
|
||||
|
||||
std::map<std::string, CgEntry> cgMap;
|
||||
|
||||
// Collect covergroup points from all loaded coverage data
|
||||
for (const auto& nameNum : m_points) {
|
||||
const VlcPoint& pt = m_points.pointNumber(nameNum.second);
|
||||
if (pt.type() != "covergroup") continue;
|
||||
|
||||
const std::string page = pt.page();
|
||||
// Page format: "v_covergroup/<cgTypeName>"
|
||||
const std::string pagePrefix = "v_covergroup/";
|
||||
if (page.size() <= pagePrefix.size()) continue;
|
||||
const std::string cgTypeName = page.substr(pagePrefix.size());
|
||||
|
||||
// Parse hier: "<cg_type>.<cp_name>.<bin_name>"
|
||||
const std::string hier = pt.hier();
|
||||
const size_t dot1 = hier.find('.');
|
||||
if (dot1 == std::string::npos) continue;
|
||||
const size_t dot2 = hier.find('.', dot1 + 1);
|
||||
if (dot2 == std::string::npos) continue;
|
||||
const std::string cpName = hier.substr(dot1 + 1, dot2 - dot1 - 1);
|
||||
const std::string binName = hier.substr(dot2 + 1);
|
||||
|
||||
auto& cg = cgMap[cgTypeName];
|
||||
if (cg.typeName.empty()) {
|
||||
cg.typeName = cgTypeName;
|
||||
cg.filename = pt.filename();
|
||||
cg.lineno = pt.lineno();
|
||||
}
|
||||
|
||||
auto it = cg.cpIndex.find(cpName);
|
||||
size_t cpIdx;
|
||||
if (it == cg.cpIndex.end()) {
|
||||
cpIdx = cg.coverpoints.size();
|
||||
cg.cpIndex[cpName] = cpIdx;
|
||||
CpEntry cp;
|
||||
cp.name = cpName;
|
||||
cp.isCross = pt.isCross();
|
||||
cg.coverpoints.push_back(cp);
|
||||
} else {
|
||||
cpIdx = it->second;
|
||||
}
|
||||
|
||||
BinEntry bin;
|
||||
bin.name = binName;
|
||||
bin.binType = pt.binType();
|
||||
// Threshold: use per-bin thresh key (option.at_least) if present, else 1 (SV default)
|
||||
const std::string threshStr = pt.thresh();
|
||||
const uint64_t binThresh = threshStr.empty() ? 1 : std::stoull(threshStr);
|
||||
bin.count = pt.count();
|
||||
bin.covered = (bin.count >= binThresh);
|
||||
cg.coverpoints[cpIdx].bins.push_back(bin);
|
||||
|
||||
if (bin.binType.empty()) {
|
||||
++cg.coverpoints[cpIdx].normalTotal;
|
||||
if (bin.covered) ++cg.coverpoints[cpIdx].normalCovered;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute grand totals
|
||||
uint64_t grandTotal = 0, grandCovered = 0, grandIgnored = 0, grandIllegal = 0;
|
||||
for (const auto& cgPair : cgMap) {
|
||||
for (const auto& cp : cgPair.second.coverpoints) {
|
||||
grandTotal += cp.normalTotal;
|
||||
grandCovered += cp.normalCovered;
|
||||
for (const auto& bin : cp.bins) {
|
||||
if (bin.binType == "ignore")
|
||||
++grandIgnored;
|
||||
else if (bin.binType == "illegal")
|
||||
++grandIllegal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Format a percentage string "xx.xx"
|
||||
const auto pctStr = [](uint64_t covered, uint64_t total) -> std::string {
|
||||
std::ostringstream oss;
|
||||
const double pct = (total == 0) ? 100.0 : (100.0 * covered / total);
|
||||
oss << std::fixed << std::setprecision(2) << pct;
|
||||
return oss.str();
|
||||
};
|
||||
|
||||
const std::string divider(78, '-');
|
||||
|
||||
// Header and grand total
|
||||
std::cout << "COVERGROUP COVERAGE REPORT\n";
|
||||
std::cout << "==========================\n";
|
||||
std::cout << "\n";
|
||||
std::cout << "TOTAL: " << grandCovered << "/" << grandTotal << " bins covered ("
|
||||
<< pctStr(grandCovered, grandTotal) << "%)\n";
|
||||
if (grandIgnored || grandIllegal)
|
||||
std::cout << " (" << grandIgnored << " ignored, " << grandIllegal << " illegal)\n";
|
||||
|
||||
// One section per covergroup type (map is sorted alphabetically)
|
||||
for (const auto& cgPair : cgMap) {
|
||||
const CgEntry& cg = cgPair.second;
|
||||
|
||||
uint64_t cgTotal = 0, cgCovered = 0;
|
||||
for (const auto& cp : cg.coverpoints) {
|
||||
cgTotal += cp.normalTotal;
|
||||
cgCovered += cp.normalCovered;
|
||||
}
|
||||
|
||||
std::cout << "\n" << divider << "\n";
|
||||
std::cout << "Covergroup Type: " << cg.typeName << " [" << cg.filename << ":" << cg.lineno
|
||||
<< "]\n";
|
||||
std::cout << " Type Coverage: " << cgCovered << "/" << cgTotal << " bins ("
|
||||
<< pctStr(cgCovered, cgTotal) << "%)\n";
|
||||
|
||||
for (const auto& cp : cg.coverpoints) {
|
||||
std::cout << "\n";
|
||||
std::cout << " " << (cp.isCross ? "Cross" : "Coverpoint") << ": " << cp.name << "\n";
|
||||
std::cout << " Coverage: " << cp.normalCovered << "/" << cp.normalTotal << " bins ("
|
||||
<< pctStr(cp.normalCovered, cp.normalTotal) << "%)\n";
|
||||
std::cout << " Bins:\n";
|
||||
|
||||
// Align bin name column to max name length in this coverpoint
|
||||
size_t maxNameLen = 0;
|
||||
for (const auto& bin : cp.bins)
|
||||
if (bin.name.size() > maxNameLen) maxNameLen = bin.name.size();
|
||||
|
||||
for (const auto& bin : cp.bins) {
|
||||
const char* status;
|
||||
if (bin.binType == "ignore")
|
||||
status = "IGNORE ";
|
||||
else if (bin.binType == "illegal")
|
||||
status = "ILLEGAL";
|
||||
else if (bin.covered)
|
||||
status = "COVERED";
|
||||
else
|
||||
status = "ZERO ";
|
||||
|
||||
std::cout << " " << status << " " << std::left
|
||||
<< std::setw(static_cast<int>(maxNameLen)) << bin.name << std::right
|
||||
<< " " << bin.count << " hits\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "\n" << divider << "\n";
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
||||
void VlcTop::annotateCalc() {
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ public:
|
|||
|
||||
// METHODS
|
||||
void annotate(const string& dirname);
|
||||
void covergroup();
|
||||
void readCoverage(const string& filename, bool nonfatal = false);
|
||||
void writeCoverage(const string& filename);
|
||||
void writeInfo(const string& filename);
|
||||
|
|
|
|||
308
src/verilog.y
308
src/verilog.y
|
|
@ -3958,16 +3958,16 @@ value_range<nodeExprp>: // ==IEEE: value_range/open_value_range
|
|||
covergroup_value_range<nodeExprp>: // ==IEEE-2012: covergroup_value_range
|
||||
cgexpr { $$ = $1; }
|
||||
| '[' cgexpr ':' cgexpr ']'
|
||||
{ $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: covergroup value range"); DEL($2, $4); }
|
||||
{ $$ = nullptr; BBCOVERIGN($1, "Unsupported: covergroup value range '[...]'"); DEL($2, $4); }
|
||||
// // IEEE-2023: added all four:
|
||||
// // Skipped as '$' is part of our expr
|
||||
// // IEEE-2023: '[' '$' ':' cgexpr ']'
|
||||
// // Skipped as '$' is part of our expr
|
||||
// // IEEE-2023: '[' cgexpr ':' '$' ']'
|
||||
| '[' cgexpr yP_PLUSSLASHMINUS cgexpr ']'
|
||||
{ $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: covergroup value range"); DEL($2, $4); }
|
||||
{ $$ = nullptr; BBCOVERIGN($1, "Unsupported: covergroup value range '[...]'"); DEL($2, $4); }
|
||||
| '[' cgexpr yP_PLUSPCTMINUS cgexpr ']'
|
||||
{ $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: covergroup value range"); DEL($2, $4); }
|
||||
{ $$ = nullptr; BBCOVERIGN($1, "Unsupported: covergroup value range '[...]'"); DEL($2, $4); }
|
||||
;
|
||||
|
||||
caseCondList<nodeExprp>: // IEEE: part of case_item
|
||||
|
|
@ -6933,40 +6933,27 @@ 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};
|
||||
// Every covergroup has option/type_option members (added by V3LinkParse)
|
||||
// referencing std:: types, so mark std as needed at parse time.
|
||||
v3Global.setUsesStdPackage();
|
||||
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");
|
||||
}
|
||||
{ $$ = nullptr;
|
||||
BBUNSUP($1, "Unsupported: covergroup inheritance (extends)");
|
||||
DEL($5); }
|
||||
;
|
||||
|
||||
cgPortListE<nodep>:
|
||||
|
|
@ -7013,29 +7000,33 @@ 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); }
|
||||
{ $$ = new AstCoverpoint{$<fl>1, "", $2, $3, $4}; }
|
||||
// // 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);}
|
||||
{ $$ = new AstCoverpoint{$<fl>3, *$1, $4, $5, $6}; }
|
||||
// // 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);}
|
||||
{ $$ = new AstCoverpoint{$<fl>4, *$2, $5, $6, $7};
|
||||
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); }
|
||||
{ $$ = new AstCoverpoint{$<fl>5, *$3, $6, $7, $8};
|
||||
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); }
|
||||
{ $$ = new AstCoverpoint{$<fl>5, *$3, $6, $7, $8};
|
||||
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); }
|
||||
{ $$ = new AstCoverpoint{$<fl>5, *$3, $6, $7, $8};
|
||||
DEL($2); }
|
||||
| signing id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>4, "Ignoring unsupported: coverpoint"); DEL($5, $6, $7); }
|
||||
{ $$ = new AstCoverpoint{$<fl>4, *$2, $5, $6, $7}; }
|
||||
// // IEEE-2012:
|
||||
| bins_or_empty { $$ = $1; }
|
||||
;
|
||||
|
||||
iffE<nodep>: // IEEE: part of cover_point, others
|
||||
iffE<nodeExprp>: // IEEE: part of cover_point, others
|
||||
/* empty */ { $$ = nullptr; }
|
||||
| yIFF '(' expr ')'
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>1, "Ignoring unsupported: cover 'iff'"); DEL($3); }
|
||||
{ $$ = $3; /* Keep iff condition for coverpoint */ }
|
||||
;
|
||||
|
||||
bins_or_empty<nodep>: // ==IEEE: bins_or_empty
|
||||
|
|
@ -7059,39 +7050,104 @@ 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
|
||||
{ AstCoverBin* const binp = new AstCoverBin{$<fl>2, *$2, $6, false, false};
|
||||
if ($3) binp->isArray(true);
|
||||
$$ = binp; 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, "Unsupported: 'bins' array (non-auto)");
|
||||
DEL($4, $6);
|
||||
}
|
||||
}
|
||||
| yIGNORE_BINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' iffE
|
||||
{ AstCoverBin* const binp = new AstCoverBin{$<fl>2, *$2, $6, true, false};
|
||||
if ($3) binp->isArray(true);
|
||||
$$ = binp; DEL($8); }
|
||||
| yILLEGAL_BINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' iffE
|
||||
{ AstCoverBin* const binp = new AstCoverBin{$<fl>2, *$2, $6, false, true};
|
||||
if ($3) binp->isArray(true);
|
||||
$$ = binp; DEL($8); }
|
||||
| yBINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ AstCoverBin* const binp = new AstCoverBin{$<fl>2, *$2, $6, false, false};
|
||||
BBCOVERIGN($<fl>8, "Unsupported: 'with' in cover bin (bin created without filter)");
|
||||
DEL($10, $12); $$ = binp; }
|
||||
| yIGNORE_BINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ AstCoverBin* const binp = new AstCoverBin{$<fl>2, *$2, $6, true, false};
|
||||
BBCOVERIGN($<fl>8, "Unsupported: 'with' in cover bin (bin created without filter)");
|
||||
DEL($10, $12); $$ = binp; }
|
||||
| yILLEGAL_BINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ AstCoverBin* const binp = new AstCoverBin{$<fl>2, *$2, $6, false, true};
|
||||
BBCOVERIGN($<fl>8, "Unsupported: 'with' in cover bin (bin created without filter)");
|
||||
DEL($10, $12); $$ = binp; }
|
||||
| yBINS idAny/*bin_identifier*/ bins_orBraE '=' id/*cover_point_id*/ yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>6, "Unsupported: 'with' in cover bin"); DEL($8, $10); }
|
||||
| yIGNORE_BINS idAny/*bin_identifier*/ bins_orBraE '=' id/*cover_point_id*/ yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>6, "Unsupported: 'with' in cover bin"); DEL($8, $10); }
|
||||
| yILLEGAL_BINS idAny/*bin_identifier*/ bins_orBraE '=' id/*cover_point_id*/ yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>6, "Unsupported: 'with' in cover bin"); 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, "Unsupported: 'with' in wildcard cover bin"); DEL($7, $11, $13); }
|
||||
| yWILDCARD yIGNORE_BINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>9, "Unsupported: 'with' in wildcard cover bin"); DEL($7, $11, $13); }
|
||||
| yWILDCARD yILLEGAL_BINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>9, "Unsupported: 'with' in wildcard cover bin"); 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), VCoverBinsType{VCoverBinsType::BINS_TRANSITION}, 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), VCoverBinsType{VCoverBinsType::BINS_IGNORE}, 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), VCoverBinsType{VCoverBinsType::BINS_ILLEGAL}, isArray != nullptr};
|
||||
DEL($6); }
|
||||
| yWILDCARD yBINS idAny/*bin_identifier*/ bins_orBraE '=' trans_list iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>1, "Unsupported: 'wildcard' transition list in cover bin"); DEL($6, $7);}
|
||||
| yWILDCARD yIGNORE_BINS idAny/*bin_identifier*/ bins_orBraE '=' trans_list iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>1, "Unsupported: 'wildcard' transition list in cover bin"); DEL($6, $7);}
|
||||
| yWILDCARD yILLEGAL_BINS idAny/*bin_identifier*/ bins_orBraE '=' trans_list iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>1, "Unsupported: 'wildcard' transition list in cover bin"); 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::BINS_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, "Unsupported: 'sequence' in default cover bin"); DEL($7); }
|
||||
| yIGNORE_BINS idAny/*bin_identifier*/ bins_orBraE '=' yDEFAULT ySEQUENCE iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>6, "Unsupported: 'sequence' in default cover bin"); DEL($7); }
|
||||
| yILLEGAL_BINS idAny/*bin_identifier*/ bins_orBraE '=' yDEFAULT ySEQUENCE iffE
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>6, "Unsupported: 'sequence' in default cover bin"); 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*/ }
|
||||
| '[' cgexpr ']' { $$ = nullptr; /*UNSUP*/ DEL($2); }
|
||||
;
|
||||
|
||||
bins_keyword<fl>: // ==IEEE: bins_keyword
|
||||
yBINS { $$ = $1; /*UNSUP*/ }
|
||||
| yILLEGAL_BINS { $$ = $1; /*UNSUP*/ }
|
||||
| yIGNORE_BINS { $$ = $1; /*UNSUP*/ }
|
||||
| '[' ']' { $$ = $<fl>1; /* Mark as array */ }
|
||||
| '[' cgexpr ']' { BBCOVERIGN($<fl>1, "Unsupported: 'bins' explicit array size (treated as '[]')"); DEL($2); $$ = $<fl>1; }
|
||||
;
|
||||
|
||||
trans_list<nodep>: // ==IEEE: trans_list
|
||||
|
|
@ -7099,30 +7155,40 @@ trans_list<nodep>: // ==IEEE: trans_list
|
|||
| 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 {
|
||||
AstCoverTransItem* const itemp = static_cast<AstCoverTransItem*>($1);
|
||||
$$ = new AstCoverTransSet{$<fl>1, itemp};
|
||||
}
|
||||
| trans_set yP_EQGT trans_range_list
|
||||
{ $$ = $1; BBCOVERIGN($<fl>2, "Ignoring unsupported: cover trans set '=>'"); DEL($3); }
|
||||
{
|
||||
AstCoverTransSet* const setp = static_cast<AstCoverTransSet*>($1);
|
||||
AstCoverTransItem* const itemp = static_cast<AstCoverTransItem*>($3);
|
||||
setp->addItemsp(itemp);
|
||||
$$ = setp;
|
||||
}
|
||||
;
|
||||
|
||||
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); }
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>2, "Unsupported: '[*]' in cover transition"); DEL($1, $3); }
|
||||
| trans_item yP_BRASTAR cgexpr ':' cgexpr ']'
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>2, "Ignoring unsupported: cover '[*'"); DEL($1, $3, $5); }
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>2, "Unsupported: '[*]' in cover transition"); DEL($1, $3, $5); }
|
||||
| trans_item yP_BRAMINUSGT cgexpr ']'
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>2, "Ignoring unsupported: cover '[->'"); DEL($1, $3); }
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>2, "Unsupported: '[->' in cover transition"); DEL($1, $3); }
|
||||
| trans_item yP_BRAMINUSGT cgexpr ':' cgexpr ']'
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>2, "Ignoring unsupported: cover '[->'"); DEL($1, $3, $5); }
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>2, "Unsupported: '[->' in cover transition"); DEL($1, $3, $5); }
|
||||
| trans_item yP_BRAEQ cgexpr ']'
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>2, "Ignoring unsupported: cover '[='"); DEL($1, $3); }
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>2, "Unsupported: '[=]' in cover transition"); DEL($1, $3); }
|
||||
| trans_item yP_BRAEQ cgexpr ':' cgexpr ']'
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>2, "Ignoring unsupported: cover '[='"); DEL($1, $3, $5); }
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>2, "Unsupported: '[=]' in cover transition"); DEL($1, $3, $5); }
|
||||
;
|
||||
|
||||
trans_item<nodep>: // ==IEEE: range_list
|
||||
trans_item<nodep>: // ==IEEE: range_list (returns range list node)
|
||||
covergroup_range_list { $$ = $1; }
|
||||
;
|
||||
|
||||
|
|
@ -7134,9 +7200,28 @@ 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) nodep->addRawBodyp($6);
|
||||
if ($5) {
|
||||
$5->v3warn(COVERIGN, "Unsupported: 'iff' in coverage cross");
|
||||
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) nodep->addRawBodyp($4);
|
||||
if ($3) {
|
||||
$3->v3warn(COVERIGN, "Unsupported: 'iff' in coverage cross");
|
||||
VL_DO_DANGLING($3->deleteTree(), $3);
|
||||
}
|
||||
$$ = nodep;
|
||||
}
|
||||
;
|
||||
|
||||
list_of_cross_items<nodep>: // ==IEEE: list_of_cross_items
|
||||
|
|
@ -7151,7 +7236,8 @@ cross_itemList<nodep>: // IEEE: part of list_of_cross_items
|
|||
;
|
||||
|
||||
cross_item<nodep>: // ==IEEE: cross_item
|
||||
idDotted/*cover_point_identifier or variable_identifier*/ { $1->deleteTree(); $$ = nullptr; /*UNSUP*/ }
|
||||
id/*cover_point_identifier*/
|
||||
{ $$ = new AstCoverpointRef{$<fl>1, *$1}; }
|
||||
;
|
||||
|
||||
cross_body<nodep>: // ==IEEE: cross_body
|
||||
|
|
@ -7171,12 +7257,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(), "Unsupported: 'function' in coverage cross body"); 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, "Unsupported: explicit coverage cross bins"); DEL($4, $5); }
|
||||
| yIGNORE_BINS idAny/*new-bin_identifier*/ '=' select_expression iffE ';'
|
||||
{ $$ = nullptr; BBCOVERIGN($1, "Unsupported: explicit coverage cross bins"); DEL($4, $5); }
|
||||
| yILLEGAL_BINS idAny/*new-bin_identifier*/ '=' select_expression iffE ';'
|
||||
{ $$ = nullptr; BBCOVERIGN($1, "Unsupported: explicit coverage cross bins"); DEL($4, $5); }
|
||||
| error ';' { $$ = nullptr; } // LCOV_EXCL_LINE
|
||||
;
|
||||
|
||||
|
|
@ -7184,28 +7274,28 @@ select_expression<nodep>: // ==IEEE: select_expression
|
|||
select_expression_r
|
||||
{ $$ = $1; }
|
||||
| select_expression yP_ANDAND select_expression
|
||||
{ $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: coverage select expression '&&'"); DEL($1, $3); }
|
||||
{ $$ = nullptr; BBCOVERIGN($2, "Unsupported: '&&' in coverage select expression"); DEL($1, $3); }
|
||||
| select_expression yP_OROR select_expression
|
||||
{ $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: coverage select expression '||'"); DEL($1, $3); }
|
||||
{ $$ = nullptr; BBCOVERIGN($2, "Unsupported: '||' in coverage select expression"); DEL($1, $3); }
|
||||
;
|
||||
|
||||
// This non-terminal exists to disambiguate select_expression and make "with" bind tighter
|
||||
select_expression_r<nodep>:
|
||||
// // IEEE: select_condition expanded here
|
||||
yBINSOF '(' bins_expression ')'
|
||||
{ $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage select expression 'binsof'"); DEL($3); }
|
||||
{ $$ = nullptr; BBCOVERIGN($1, "Unsupported: 'binsof' in coverage select expression"); DEL($3); }
|
||||
| '!' yBINSOF '(' bins_expression ')'
|
||||
{ $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage select expression 'binsof'"); DEL($4); }
|
||||
{ $$ = nullptr; BBCOVERIGN($1, "Unsupported: 'binsof' in coverage select expression"); DEL($4); }
|
||||
| yBINSOF '(' bins_expression ')' yINTERSECT '{' covergroup_range_list '}'
|
||||
{ $$ = nullptr; BBCOVERIGN($5, "Ignoring unsupported: coverage select expression 'intersect'"); DEL($3, $7); }
|
||||
{ $$ = nullptr; BBCOVERIGN($5, "Unsupported: 'intersect' in coverage select expression"); DEL($7); }
|
||||
| '!' yBINSOF '(' bins_expression ')' yINTERSECT '{' covergroup_range_list '}' { }
|
||||
{ $$ = nullptr; BBCOVERIGN($5, "Ignoring unsupported: coverage select expression 'intersect'"); DEL($4, $8); }
|
||||
{ $$ = nullptr; BBCOVERIGN($5, "Unsupported: 'intersect' in coverage select expression"); DEL($4, $8); }
|
||||
| yWITH__PAREN '(' cgexpr ')'
|
||||
{ $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage select expression with"); DEL($3); }
|
||||
{ $$ = nullptr; BBCOVERIGN($1, "Unsupported: 'with' in coverage select expression"); DEL($3); }
|
||||
| '!' yWITH__PAREN '(' cgexpr ')'
|
||||
{ $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage select expression with"); DEL($4); }
|
||||
{ $$ = nullptr; BBCOVERIGN($1, "Unsupported: 'with' in coverage select expression"); DEL($4); }
|
||||
| select_expression_r yWITH__PAREN '(' cgexpr ')'
|
||||
{ $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: coverage select expression with"); DEL($1, $4); }
|
||||
{ $$ = nullptr; BBCOVERIGN($2, "Unsupported: 'with' in coverage select expression"); DEL($1, $4); }
|
||||
// // IEEE-2012: Need clarification as to precedence
|
||||
//UNSUP yWITH__PAREN '(' cgexpr ')' yMATCHES cgexpr { }
|
||||
// // IEEE-2012: Need clarification as to precedence
|
||||
|
|
@ -7223,7 +7313,7 @@ select_expression_r<nodep>:
|
|||
//UNSUP cgexpr yMATCHES cgexpr {..}
|
||||
//UNSUP // Below are all removed
|
||||
| idAny '(' list_of_argumentsE ')'
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>1, "Ignoring unsupported: coverage select function call"); DEL($3); }
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>1, "Unsupported: function call in coverage select expression"); DEL($3); }
|
||||
//UNSUP // Above are all removed, replace with:
|
||||
;
|
||||
|
||||
|
|
@ -7242,7 +7332,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'");
|
||||
|
|
@ -7253,7 +7343,7 @@ coverage_eventE<nodep>: // IEEE: [ coverage_event ]
|
|||
}
|
||||
}
|
||||
| yP_ATAT '(' block_event_expression ')'
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>1, "Ignoring unsupported: coverage '@@' events"); DEL($3); }
|
||||
{ $$ = nullptr; BBCOVERIGN($<fl>1, "Unsupported: '@@' coverage event"); DEL($3); }
|
||||
;
|
||||
|
||||
block_event_expression<nodep>: // ==IEEE: block_event_expression
|
||||
|
|
@ -7751,11 +7841,15 @@ class_item<nodep>: // ==IEEE: class_item
|
|||
| timeunits_declaration { $$ = $1; }
|
||||
| covergroup_declaration
|
||||
{
|
||||
const string cgName = $1->name();
|
||||
$1->name("__vlAnonCG_" + cgName);
|
||||
AstVar* const newp = new AstVar{$1->fileline(), VVarType::VAR, cgName,
|
||||
VFlagChildDType{}, new AstRefDType($1->fileline(), $1->name())};
|
||||
$$ = addNextNull($1, newp);
|
||||
if ($1) {
|
||||
const string cgName = $1->name();
|
||||
$1->name("__vlAnonCG_" + cgName);
|
||||
AstVar* const newp = new AstVar{$1->fileline(), VVarType::VAR, cgName,
|
||||
VFlagChildDType{}, new AstRefDType($1->fileline(), $1->name())};
|
||||
$$ = addNextNull($1, newp);
|
||||
} else {
|
||||
$$ = nullptr;
|
||||
}
|
||||
}
|
||||
// // local_parameter_declaration under parameter_declaration
|
||||
| parameter_declaration ';' { $$ = $1; }
|
||||
|
|
|
|||
|
|
@ -2802,6 +2802,41 @@ class VlTest:
|
|||
self._file_contents_cache[filename] = str(fh.read())
|
||||
return self._file_contents_cache[filename]
|
||||
|
||||
def covergroup_coverage_report(self, outfile: str = None) -> str:
|
||||
"""Parse coverage.dat and write a sorted covergroup bin hit-count report.
|
||||
|
||||
Lines have the form: <hierarchy>[ [bin_type]]: <count>
|
||||
ignore_bins and illegal_bins are annotated with [ignore] / [illegal].
|
||||
|
||||
Returns the path to the written report file.
|
||||
"""
|
||||
if outfile is None:
|
||||
outfile = self.obj_dir + "/covergroup_report.txt"
|
||||
contents = self.file_contents(self.coverage_filename)
|
||||
entries = []
|
||||
for m in re.finditer(r"C '([^']+)' (\d+)", contents):
|
||||
entry, count = m.group(1), m.group(2)
|
||||
if '\x01t\x02covergroup' not in entry:
|
||||
continue
|
||||
h_m = re.search(r'\x01h\x02([^\x01]+)', entry)
|
||||
if not h_m:
|
||||
continue
|
||||
hier = h_m.group(1)
|
||||
bt_m = re.search(r'\x01bin_type\x02([^\x01]+)', entry)
|
||||
cross_m = re.search(r'\x01cross\x021', entry)
|
||||
annotations = []
|
||||
if bt_m:
|
||||
annotations.append(bt_m.group(1))
|
||||
if cross_m:
|
||||
annotations.append("cross")
|
||||
label = f"{hier} [{','.join(annotations)}]" if annotations else hier
|
||||
entries.append((hier, label, int(count)))
|
||||
entries.sort()
|
||||
with open(outfile, 'w', encoding='utf-8') as fh:
|
||||
for _hier, label, count in entries:
|
||||
fh.write(f"{label}: {count}\n")
|
||||
return outfile
|
||||
|
||||
@staticmethod
|
||||
def _file_contents_static(filename: str) -> str:
|
||||
if filename not in VlTest._file_contents_cache:
|
||||
|
|
|
|||
|
|
@ -4,17 +4,23 @@
|
|||
// SPDX-FileCopyrightText: 2025 Antmicro
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// A plain (non-covergroup) class - exercises the non-covergroup class scope/varscope paths
|
||||
class PlainClass;
|
||||
int x;
|
||||
endclass
|
||||
|
||||
// verilator lint_off COVERIGN
|
||||
module t;
|
||||
|
||||
int i, j;
|
||||
|
||||
covergroup cg(int var1, int var2 = 42);
|
||||
cp1: coverpoint i; // Non-empty body with args: exercises constructor-body path
|
||||
endgroup
|
||||
|
||||
cg cov1 = new(69, 77);
|
||||
cg cov2 = new(69);
|
||||
|
||||
int i, j;
|
||||
real r;
|
||||
PlainClass plain_inst = new; // Non-covergroup class instance: exercises early-return paths
|
||||
|
||||
function void x();
|
||||
cov1.set_inst_name("the_inst_name");
|
||||
|
|
@ -23,16 +29,14 @@ module t;
|
|||
cov1.stop();
|
||||
|
||||
void'(cov2.get_coverage());
|
||||
r = cov2.get_coverage();
|
||||
r = cov2.get_coverage(i, j);
|
||||
void'(cov2.get_coverage(i, j));
|
||||
// verilator lint_off IGNOREDRETURN
|
||||
cov2.get_inst_coverage();
|
||||
// verilator lint_on IGNOREDRETURN
|
||||
r = cov2.get_inst_coverage(i, j);
|
||||
void'(cov2.get_inst_coverage(i, j));
|
||||
|
||||
cg::get_coverage();
|
||||
r = cg::get_coverage();
|
||||
r = cg::get_coverage(i, j);
|
||||
void'(cg::get_coverage());
|
||||
void'(cg::get_coverage(i, j));
|
||||
endfunction
|
||||
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
cg.data.grouped: 2
|
||||
cg.data.values: 3
|
||||
cg2.cp.range_arr: 3
|
||||
cg3.cp.range_sized: 3
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#!/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 --Wno-COVERIGN'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.covergroup_coverage_report()
|
||||
test.files_identical(test.obj_dir + '/covergroup_report.txt', test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
// 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, including InsideRange and AstRange
|
||||
|
||||
module t;
|
||||
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
|
||||
|
||||
// cg2: exercises InsideRange in array bins (e.g., bins r[] = {[0:3]})
|
||||
covergroup cg2;
|
||||
cp: coverpoint data {
|
||||
bins range_arr[] = {[0:3]}; // InsideRange -> 4 separate bins
|
||||
}
|
||||
endgroup
|
||||
|
||||
// cg3: exercises AstRange in array bins (e.g., bins r[N] = {[lo:hi]})
|
||||
covergroup cg3;
|
||||
cp: coverpoint data {
|
||||
bins range_sized[4] = {[4:7]}; // AstRange with explicit count
|
||||
}
|
||||
endgroup
|
||||
|
||||
initial begin
|
||||
cg cg_inst;
|
||||
cg2 cg2_inst;
|
||||
cg3 cg3_inst;
|
||||
|
||||
cg_inst = new();
|
||||
cg2_inst = new();
|
||||
cg3_inst = new();
|
||||
|
||||
// Hit first array bin value (1)
|
||||
data = 1;
|
||||
cg_inst.sample();
|
||||
|
||||
// Hit second array bin value (5)
|
||||
data = 5;
|
||||
cg_inst.sample();
|
||||
|
||||
// Hit the grouped bin (covers all of 2, 6, 10)
|
||||
data = 6;
|
||||
cg_inst.sample();
|
||||
|
||||
// Hit third array bin value (9)
|
||||
data = 9;
|
||||
cg_inst.sample();
|
||||
|
||||
// Verify hitting other values in grouped bin doesn't increase coverage
|
||||
data = 2;
|
||||
cg_inst.sample();
|
||||
|
||||
// Hit range_arr bins (InsideRange [0:3])
|
||||
data = 0; cg2_inst.sample();
|
||||
data = 1; cg2_inst.sample();
|
||||
data = 2; cg2_inst.sample();
|
||||
|
||||
// Hit range_sized bins (AstRange [4:7])
|
||||
data = 4; cg3_inst.sample();
|
||||
data = 5; cg3_inst.sample();
|
||||
data = 6; cg3_inst.sample();
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
cg1.cp_data3.auto_0: 1
|
||||
cg1.cp_data3.auto_1: 0
|
||||
cg1.cp_data3.auto_2: 0
|
||||
cg1.cp_data3.auto_3: 1
|
||||
cg1.cp_data3.auto_4: 0
|
||||
cg1.cp_data3.auto_5: 0
|
||||
cg1.cp_data3.auto_6: 0
|
||||
cg1.cp_data3.auto_7: 0
|
||||
cg2.cp_data3.auto_0: 1
|
||||
cg2.cp_data3.auto_1: 0
|
||||
cg2.cp_data3.auto_2: 1
|
||||
cg2.cp_data3.auto_3: 0
|
||||
cg3.cp_data3.auto_0: 1
|
||||
cg3.cp_data3.auto_1: 1
|
||||
cg4.cp.auto_0: 0
|
||||
cg4.cp.auto_1: 1
|
||||
cg4.cp.auto_2: 1
|
||||
cg4.cp.auto_3: 1
|
||||
cg4.cp.ign [ignore]: 0
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#!/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=['--coverage', '-Wno-UNSIGNED', '-Wno-CMPCONST'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.covergroup_coverage_report()
|
||||
test.files_identical(test.obj_dir + '/covergroup_report.txt', test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
// 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-FileCopyrightText: 2024 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test implicit auto-bin creation (no explicit bins) and option.auto_bin_max
|
||||
|
||||
module t;
|
||||
|
||||
logic [2:0] data3;
|
||||
logic [3:0] data4; // 4-bit signal for range-bin path tests
|
||||
|
||||
// Test 1: auto_bin_max default (64) - creates 8 bins for 3-bit signal
|
||||
covergroup cg1;
|
||||
cp_data3: coverpoint data3;
|
||||
endgroup
|
||||
|
||||
// Test 2: auto_bin_max = 4 at covergroup level - creates 4 bins: [0:1],[2:3],[4:5],[6:7]
|
||||
covergroup cg2;
|
||||
option.auto_bin_max = 4;
|
||||
cp_data3: coverpoint data3;
|
||||
endgroup
|
||||
|
||||
// Test 3: auto_bin_max and at_least at *coverpoint* level (lines 207, 209)
|
||||
covergroup cg3;
|
||||
cp_data3: coverpoint data3 {
|
||||
option.auto_bin_max = 2; // coverpoint-level: creates 2 bins [0:3],[4:7]
|
||||
option.at_least = 3; // coverpoint-level at_least
|
||||
}
|
||||
endgroup
|
||||
|
||||
// Test 4: range-bin skip path (lines 287, 356-359).
|
||||
// auto_bin_max=4 on 4-bit signal -> 4 range bins: [0:3],[4:7],[8:11],[12:15].
|
||||
// ignore_bins {[0:3]} excludes all values in the first range -> that bin is skipped.
|
||||
covergroup cg4;
|
||||
option.auto_bin_max = 4;
|
||||
cp: coverpoint data4 {
|
||||
ignore_bins ign = {[0:3]}; // first range excluded from coverage
|
||||
}
|
||||
endgroup
|
||||
|
||||
initial begin
|
||||
cg1 cg1_inst;
|
||||
cg2 cg2_inst;
|
||||
cg3 cg3_inst;
|
||||
cg4 cg4_inst;
|
||||
|
||||
cg1_inst = new;
|
||||
cg2_inst = new;
|
||||
cg3_inst = new;
|
||||
cg4_inst = new;
|
||||
|
||||
data3 = 0; cg1_inst.sample();
|
||||
data3 = 3; cg1_inst.sample();
|
||||
|
||||
data3 = 0; cg2_inst.sample();
|
||||
data3 = 4; cg2_inst.sample();
|
||||
|
||||
data3 = 1; cg3_inst.sample();
|
||||
data3 = 5; cg3_inst.sample();
|
||||
|
||||
// Sample valid (non-ignored) values for cg4
|
||||
data4 = 4; cg4_inst.sample(); // [4:7] bin
|
||||
data4 = 8; cg4_inst.sample(); // [8:11] bin
|
||||
data4 = 12; cg4_inst.sample(); // [12:15] bin
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
cg.data.auto[0]: 1
|
||||
cg.data.auto[1]: 1
|
||||
cg.data.auto[2]: 1
|
||||
cg.data.auto[3]: 1
|
||||
cg2.data64.auto_0: 1
|
||||
cg2.data64.auto_1: 1
|
||||
cg_4bit.data4.auto[0]: 1
|
||||
cg_4bit.data4.auto[1]: 1
|
||||
cg_4bit.data4.auto[2]: 1
|
||||
cg_4bit.data4.auto[3]: 1
|
||||
cg_4bit_excl.data4.auto[0]: 1
|
||||
cg_4bit_excl.data4.auto[1]: 0
|
||||
cg_4bit_excl.data4.auto[2]: 1
|
||||
cg_4bit_excl.data4.auto[3]: 0
|
||||
cg_4bit_excl.data4.bad [ignore]: 0
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#!/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_all')
|
||||
|
||||
test.compile(verilator_flags2=['--coverage'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.covergroup_coverage_report()
|
||||
test.files_identical(test.obj_dir + '/covergroup_report.txt', test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// Test automatic bins: bins auto[N]
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2026 by Wilson Snyder.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t;
|
||||
/* verilator lint_off CMPCONST */
|
||||
logic [2:0] data; // 3-bit: 0-7
|
||||
logic [3:0] data4; // 4-bit: exercises width<64 path in maxVal computation
|
||||
logic [63:0] data64; // 64-bit: exercises width>=64 (UINT64_MAX) path
|
||||
|
||||
covergroup cg;
|
||||
coverpoint data {
|
||||
bins auto[4]; // Should create 4 bins: [0:1], [2:3], [4:5], [6:7]
|
||||
}
|
||||
endgroup
|
||||
|
||||
// 4-bit auto bins: exercises (width < 64) path: maxVal = (1<<4)-1 = 15
|
||||
covergroup cg_4bit;
|
||||
coverpoint data4 {
|
||||
bins auto[4]; // Creates 4 bins: [0:3], [4:7], [8:11], [12:15]
|
||||
}
|
||||
endgroup
|
||||
|
||||
// 4-bit auto bins with ignore_bins: exercises excluded-value skip path
|
||||
covergroup cg_4bit_excl;
|
||||
coverpoint data4 {
|
||||
ignore_bins bad = {0}; // value 0 excluded from auto expansion
|
||||
bins auto[4];
|
||||
}
|
||||
endgroup
|
||||
|
||||
// auto_bin_max=2 on 64-bit: exercises numTotalValues=UINT64_MAX path
|
||||
covergroup cg2;
|
||||
option.auto_bin_max = 2;
|
||||
coverpoint data64;
|
||||
endgroup
|
||||
/* verilator lint_on CMPCONST */
|
||||
|
||||
initial begin
|
||||
automatic cg cg_inst = new;
|
||||
automatic cg_4bit cg4_inst = new;
|
||||
automatic cg_4bit_excl cg4e_inst = new;
|
||||
automatic cg2 cg2_inst = new;
|
||||
|
||||
// Sample 3-bit cg: one value per bin
|
||||
data = 0; cg_inst.sample();
|
||||
data = 2; cg_inst.sample();
|
||||
data = 5; cg_inst.sample();
|
||||
data = 7; cg_inst.sample();
|
||||
|
||||
// Sample 4-bit bins
|
||||
data4 = 0; cg4_inst.sample(); // bin [0:3]
|
||||
data4 = 7; cg4_inst.sample(); // bin [4:7]
|
||||
data4 = 10; cg4_inst.sample(); // bin [8:11]
|
||||
data4 = 14; cg4_inst.sample(); // bin [12:15]
|
||||
|
||||
// Sample 4-bit with exclusion (value 0 excluded; bins start at 1)
|
||||
data4 = 1; cg4e_inst.sample();
|
||||
data4 = 8; cg4e_inst.sample();
|
||||
|
||||
// Sample both 64-bit range bins
|
||||
data64 = 64'd0; cg2_inst.sample(); // auto[0]
|
||||
data64 = 64'hFFFF_FFFF_FFFF_FFFF; cg2_inst.sample(); // auto[1]
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// -*- 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-FileCopyrightText: 2026 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,21 @@
|
|||
#!/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')
|
||||
|
||||
# Use the same .v file as the non-timing test
|
||||
test.top_filename = "t/t_covergroup_clocked_sample.v"
|
||||
|
||||
test.compile(v_flags2=["--timing"])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
%Error: t/t_covergroup_autobins_bad.v:17:12: 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:12: Automatic bins array size must be >= 1, got 0
|
||||
: ... note: In instance 't'
|
||||
24 | bins auto[0];
|
||||
| ^~~~
|
||||
%Error: t/t_covergroup_autobins_bad.v:34:26: Non-constant expression in bin value list; values must be constants
|
||||
: ... note: In instance 't'
|
||||
34 | ignore_bins ign = {size_var};
|
||||
| ^~~~~~~~
|
||||
%Error: t/t_covergroup_autobins_bad.v:31:12: Non-constant expression in array bins range; range bounds must be constants
|
||||
: ... note: In instance 't'
|
||||
31 | bins b[] = {[size_var:size_var]};
|
||||
| ^
|
||||
%Error: t/t_covergroup_autobins_bad.v:32:12: Non-constant expression in array bins range; range bounds must be constants
|
||||
: ... note: In instance 't'
|
||||
32 | bins b_mixed[] = {[0:size_var]};
|
||||
| ^~~~~~~
|
||||
%Error: t/t_covergroup_autobins_bad.v:33:18: Non-constant expression in bin range; values must be constants
|
||||
: ... note: In instance 't'
|
||||
33 | bins b2 = {size_var};
|
||||
| ^~~~~~~~
|
||||
%Error: t/t_covergroup_autobins_bad.v:34:26: Non-constant expression in bin range; values must be constants
|
||||
: ... note: In instance 't'
|
||||
34 | ignore_bins ign = {size_var};
|
||||
| ^~~~~~~~
|
||||
%Error: Exiting due to
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
# 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-FileCopyrightText: 2025 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
|
@ -12,7 +12,7 @@ import vltest_bootstrap
|
|||
test.scenarios('vlt')
|
||||
|
||||
test.lint(expect_filename=test.golden_filename,
|
||||
verilator_flags2=['--assert --error-limit 1000'],
|
||||
verilator_flags2=['--error-limit 1000'],
|
||||
fails=True)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
// 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 (zero)
|
||||
covergroup cg2;
|
||||
cp1: coverpoint cp_expr {
|
||||
bins auto[0];
|
||||
}
|
||||
endgroup
|
||||
|
||||
// Error: non-constant value in bin ranges
|
||||
covergroup cg3;
|
||||
cp1: coverpoint cp_expr {
|
||||
bins b[] = {[size_var:size_var]}; // non-constant array bins range (both bounds non-const)
|
||||
bins b_mixed[] = {[0:size_var]}; // non-constant array bins range (max bound non-const)
|
||||
bins b2 = {size_var}; // non-constant simple bin value
|
||||
ignore_bins ign = {size_var}; // non-constant ignore_bins value
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg1 cg1_inst = new;
|
||||
cg2 cg2_inst = new;
|
||||
cg3 cg3_inst = new;
|
||||
|
||||
initial $finish;
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
cg.data.low: 3
|
||||
cg.data.zero: 1
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#!/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()
|
||||
|
||||
test.covergroup_coverage_report()
|
||||
test.files_identical(test.obj_dir + '/covergroup_report.txt', test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// 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*/);
|
||||
logic [3:0] data;
|
||||
|
||||
covergroup cg;
|
||||
coverpoint data {
|
||||
bins zero = {0};
|
||||
bins low = {[1:3]};
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg cg_inst;
|
||||
|
||||
initial begin
|
||||
cg_inst = new;
|
||||
|
||||
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
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
cg.cp_data.one: 1
|
||||
cg.cp_data.three: 1
|
||||
cg.cp_data.two: 1
|
||||
cg.cp_data.zero: 2
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#!/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_all')
|
||||
|
||||
test.compile(verilator_flags2=['--coverage'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.covergroup_coverage_report()
|
||||
test.files_identical(test.obj_dir + '/covergroup_report.txt', test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
// DESCRIPTION: Verilator: Test covergroup clocked (automatic) sampling
|
||||
// Tests --no-timing (default) mode; see t_covergroup_auto_sample_timing for --timing variant.
|
||||
// This file ONLY is placed into the Public Domain, for any use, without warranty.
|
||||
// SPDX-FileCopyrightText: 2025 Wilson Snyder
|
||||
// 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;
|
||||
1: data <= 2'b01;
|
||||
2: data <= 2'b10;
|
||||
3: data <= 2'b11;
|
||||
4: begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endcase
|
||||
|
||||
// NOTE: NO manual .sample() call - relying on automatic sampling!
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
cg.data.high: 1
|
||||
cg.data.low: 1
|
||||
cg.data.mid: 1
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#!/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()
|
||||
|
||||
test.covergroup_coverage_report()
|
||||
test.files_identical(test.obj_dir + '/covergroup_report.txt', test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
// 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*/);
|
||||
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;
|
||||
|
||||
// Sample low bin - should be 33.3% (1 of 3 bins)
|
||||
data = 1;
|
||||
cg_inst.sample();
|
||||
$display("After low: %0.1f%%", cg_inst.get_inst_coverage());
|
||||
|
||||
// Sample mid bin - should be 66.7% (2 of 3 bins)
|
||||
data = 5;
|
||||
cg_inst.sample();
|
||||
$display("After mid: %0.1f%%", cg_inst.get_inst_coverage());
|
||||
|
||||
// Sample high bin - should be 100.0% (3 of 3 bins)
|
||||
data = 10;
|
||||
cg_inst.sample();
|
||||
$display("After high: %0.1f%%", cg_inst.get_inst_coverage());
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
%Warning-COVERIGN: t/t_covergroup_coverpoint_method_unsup.v:21:32: Unsupported: 'bins' explicit array size (treated as '[]')
|
||||
21 | coverpoint b {bins the_bins[5] = {[0 : 20]};}
|
||||
| ^
|
||||
... For warning description see https://verilator.org/warn/COVERIGN?v=latest
|
||||
... Use "/* verilator lint_off COVERIGN */" and lint_on around source to disable this message.
|
||||
%Error: t/t_covergroup_coverpoint_method_unsup.v:31:42: Member 'a' not found in covergroup 'cg'
|
||||
: ... note: In instance 't'
|
||||
31 | $display("coverage a = %f", the_cg.a.get_inst_coverage());
|
||||
| ^
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
%Error-UNSUPPORTED: t/t_covergroup_coverpoint_method_unsup.v:31:44: Unsupported: Member call on object 'CONST '1'h0'' which is a 'BASICDTYPE 'bit''
|
||||
: ... note: In instance 't'
|
||||
31 | $display("coverage a = %f", the_cg.a.get_inst_coverage());
|
||||
| ^~~~~~~~~~~~~~~~~
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error: t/t_covergroup_coverpoint_method_unsup.v:32:42: Member 'b' not found in covergroup 'cg'
|
||||
: ... note: In instance 't'
|
||||
32 | $display("coverage b = %f", the_cg.b.get_inst_coverage());
|
||||
| ^
|
||||
%Error-UNSUPPORTED: t/t_covergroup_coverpoint_method_unsup.v:32:44: Unsupported: Member call on object 'CONST '1'h0'' which is a 'BASICDTYPE 'bit''
|
||||
: ... note: In instance 't'
|
||||
32 | $display("coverage b = %f", the_cg.b.get_inst_coverage());
|
||||
| ^~~~~~~~~~~~~~~~~
|
||||
%Error: t/t_covergroup_coverpoint_method_unsup.v:33:18: Member 'a' not found in covergroup 'cg'
|
||||
: ... note: In instance 't'
|
||||
33 | if (the_cg.a.get_inst_coverage() != 15 / 16.0) $stop();
|
||||
| ^
|
||||
%Error-UNSUPPORTED: t/t_covergroup_coverpoint_method_unsup.v:33:20: Unsupported: Member call on object 'CONST '1'h0'' which is a 'BASICDTYPE 'bit''
|
||||
: ... note: In instance 't'
|
||||
33 | if (the_cg.a.get_inst_coverage() != 15 / 16.0) $stop();
|
||||
| ^~~~~~~~~~~~~~~~~
|
||||
%Error: t/t_covergroup_coverpoint_method_unsup.v:34:18: Member 'b' not found in covergroup 'cg'
|
||||
: ... note: In instance 't'
|
||||
34 | if (the_cg.b.get_inst_coverage() != 4 / 5.0) $stop();
|
||||
| ^
|
||||
%Error-UNSUPPORTED: t/t_covergroup_coverpoint_method_unsup.v:34:20: Unsupported: Member call on object 'CONST '1'h0'' which is a 'BASICDTYPE 'bit''
|
||||
: ... note: In instance 't'
|
||||
34 | if (the_cg.b.get_inst_coverage() != 4 / 5.0) $stop();
|
||||
| ^~~~~~~~~~~~~~~~~
|
||||
%Error: Exiting due to
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
%Warning-COVERIGN: t/t_covergroup_coverpoints_unsup.v:19:17: Ignoring unsupported: coverage clocking event
|
||||
19 | 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:20:5: Ignoring unsupported: coverpoint
|
||||
20 | coverpoint a;
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_coverpoints_unsup.v:21:36: Ignoring unsupported: cover bin specification
|
||||
21 | coverpoint b {bins the_bins[5] = {[0 : 20]};}
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_coverpoints_unsup.v:21:5: Ignoring unsupported: coverpoint
|
||||
21 | coverpoint b {bins the_bins[5] = {[0 : 20]};}
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_coverpoints_unsup.v:19:3: Ignoring unsupported: covergroup
|
||||
19 | covergroup cg @(posedge clk);
|
||||
| ^~~~~~~~~~
|
||||
%Error: t/t_covergroup_coverpoints_unsup.v:31:42: Member 'a' not found in covergroup 'cg'
|
||||
: ... note: In instance 't'
|
||||
31 | $display("coverage a = %f", the_cg.a.get_inst_coverage());
|
||||
| ^
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
%Error-UNSUPPORTED: t/t_covergroup_coverpoints_unsup.v:31:44: Unsupported: Member call on object 'CONST '1'h0'' which is a 'BASICDTYPE 'bit''
|
||||
: ... note: In instance 't'
|
||||
31 | $display("coverage a = %f", the_cg.a.get_inst_coverage());
|
||||
| ^~~~~~~~~~~~~~~~~
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error: t/t_covergroup_coverpoints_unsup.v:32:42: Member 'b' not found in covergroup 'cg'
|
||||
: ... note: In instance 't'
|
||||
32 | $display("coverage b = %f", the_cg.b.get_inst_coverage());
|
||||
| ^
|
||||
%Error-UNSUPPORTED: t/t_covergroup_coverpoints_unsup.v:32:44: Unsupported: Member call on object 'CONST '1'h0'' which is a 'BASICDTYPE 'bit''
|
||||
: ... note: In instance 't'
|
||||
32 | $display("coverage b = %f", the_cg.b.get_inst_coverage());
|
||||
| ^~~~~~~~~~~~~~~~~
|
||||
%Error: t/t_covergroup_coverpoints_unsup.v:33:18: Member 'a' not found in covergroup 'cg'
|
||||
: ... note: In instance 't'
|
||||
33 | if (the_cg.a.get_inst_coverage() != 15 / 16.0) $stop();
|
||||
| ^
|
||||
%Error-UNSUPPORTED: t/t_covergroup_coverpoints_unsup.v:33:20: Unsupported: Member call on object 'CONST '1'h0'' which is a 'BASICDTYPE 'bit''
|
||||
: ... note: In instance 't'
|
||||
33 | if (the_cg.a.get_inst_coverage() != 15 / 16.0) $stop();
|
||||
| ^~~~~~~~~~~~~~~~~
|
||||
%Error: t/t_covergroup_coverpoints_unsup.v:34:18: Member 'b' not found in covergroup 'cg'
|
||||
: ... note: In instance 't'
|
||||
34 | if (the_cg.b.get_inst_coverage() != 4 / 5.0) $stop();
|
||||
| ^
|
||||
%Error-UNSUPPORTED: t/t_covergroup_coverpoints_unsup.v:34:20: Unsupported: Member call on object 'CONST '1'h0'' which is a 'BASICDTYPE 'bit''
|
||||
: ... note: In instance 't'
|
||||
34 | if (the_cg.b.get_inst_coverage() != 4 / 5.0) $stop();
|
||||
| ^~~~~~~~~~~~~~~~~
|
||||
%Error: Exiting due to
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
cg2.addr_cmd.addr0_x_read [cross]: 1
|
||||
cg2.addr_cmd.addr0_x_write [cross]: 1
|
||||
cg2.addr_cmd.addr1_x_read [cross]: 1
|
||||
cg2.addr_cmd.addr1_x_write [cross]: 1
|
||||
cg2.cp_addr.addr0: 2
|
||||
cg2.cp_addr.addr1: 2
|
||||
cg2.cp_cmd.read: 2
|
||||
cg2.cp_cmd.write: 2
|
||||
cg3.addr_cmd_mode.addr0_x_read_x_debug [cross]: 0
|
||||
cg3.addr_cmd_mode.addr0_x_read_x_normal [cross]: 1
|
||||
cg3.addr_cmd_mode.addr0_x_write_x_debug [cross]: 1
|
||||
cg3.addr_cmd_mode.addr0_x_write_x_normal [cross]: 0
|
||||
cg3.addr_cmd_mode.addr1_x_read_x_debug [cross]: 0
|
||||
cg3.addr_cmd_mode.addr1_x_read_x_normal [cross]: 0
|
||||
cg3.addr_cmd_mode.addr1_x_write_x_debug [cross]: 0
|
||||
cg3.addr_cmd_mode.addr1_x_write_x_normal [cross]: 1
|
||||
cg3.addr_cmd_mode.addr2_x_read_x_debug [cross]: 1
|
||||
cg3.addr_cmd_mode.addr2_x_read_x_normal [cross]: 0
|
||||
cg3.addr_cmd_mode.addr2_x_write_x_debug [cross]: 0
|
||||
cg3.addr_cmd_mode.addr2_x_write_x_normal [cross]: 0
|
||||
cg3.cp_addr.addr0: 2
|
||||
cg3.cp_addr.addr1: 1
|
||||
cg3.cp_addr.addr2: 1
|
||||
cg3.cp_cmd.read: 2
|
||||
cg3.cp_cmd.write: 2
|
||||
cg3.cp_mode.debug: 2
|
||||
cg3.cp_mode.normal: 2
|
||||
cg4.addr_cmd_mode_parity.addr0_x_read_x_debug_x_even [cross]: 0
|
||||
cg4.addr_cmd_mode_parity.addr0_x_read_x_debug_x_odd [cross]: 0
|
||||
cg4.addr_cmd_mode_parity.addr0_x_read_x_normal_x_even [cross]: 1
|
||||
cg4.addr_cmd_mode_parity.addr0_x_read_x_normal_x_odd [cross]: 0
|
||||
cg4.addr_cmd_mode_parity.addr0_x_write_x_debug_x_even [cross]: 1
|
||||
cg4.addr_cmd_mode_parity.addr0_x_write_x_debug_x_odd [cross]: 0
|
||||
cg4.addr_cmd_mode_parity.addr0_x_write_x_normal_x_even [cross]: 0
|
||||
cg4.addr_cmd_mode_parity.addr0_x_write_x_normal_x_odd [cross]: 0
|
||||
cg4.addr_cmd_mode_parity.addr1_x_read_x_debug_x_even [cross]: 0
|
||||
cg4.addr_cmd_mode_parity.addr1_x_read_x_debug_x_odd [cross]: 1
|
||||
cg4.addr_cmd_mode_parity.addr1_x_read_x_normal_x_even [cross]: 0
|
||||
cg4.addr_cmd_mode_parity.addr1_x_read_x_normal_x_odd [cross]: 0
|
||||
cg4.addr_cmd_mode_parity.addr1_x_write_x_debug_x_even [cross]: 0
|
||||
cg4.addr_cmd_mode_parity.addr1_x_write_x_debug_x_odd [cross]: 0
|
||||
cg4.addr_cmd_mode_parity.addr1_x_write_x_normal_x_even [cross]: 0
|
||||
cg4.addr_cmd_mode_parity.addr1_x_write_x_normal_x_odd [cross]: 1
|
||||
cg4.cp_addr.addr0: 2
|
||||
cg4.cp_addr.addr1: 2
|
||||
cg4.cp_cmd.read: 2
|
||||
cg4.cp_cmd.write: 2
|
||||
cg4.cp_mode.debug: 2
|
||||
cg4.cp_mode.normal: 2
|
||||
cg4.cp_parity.even: 2
|
||||
cg4.cp_parity.odd: 2
|
||||
cg5.addr_cmd_opt.addr0_x_read [cross]: 1
|
||||
cg5.addr_cmd_opt.addr0_x_write [cross]: 0
|
||||
cg5.addr_cmd_opt.addr1_x_read [cross]: 0
|
||||
cg5.addr_cmd_opt.addr1_x_write [cross]: 1
|
||||
cg5.cp_addr.addr0: 1
|
||||
cg5.cp_addr.addr1: 1
|
||||
cg5.cp_cmd.read: 1
|
||||
cg5.cp_cmd.write: 1
|
||||
cg_ignore.cp_addr.a0: 2
|
||||
cg_ignore.cp_addr.a1: 2
|
||||
cg_ignore.cp_addr.ign [ignore]: 1
|
||||
cg_ignore.cp_cmd.read: 3
|
||||
cg_ignore.cp_cmd.write: 2
|
||||
cg_ignore.cross_ab.a0_x_read [cross]: 1
|
||||
cg_ignore.cross_ab.a0_x_write [cross]: 1
|
||||
cg_ignore.cross_ab.a1_x_read [cross]: 1
|
||||
cg_ignore.cross_ab.a1_x_write [cross]: 1
|
||||
cg_range.addr_cmd_range.hi_range_x_read [cross]: 1
|
||||
cg_range.addr_cmd_range.hi_range_x_write [cross]: 1
|
||||
cg_range.addr_cmd_range.lo_range_x_read [cross]: 1
|
||||
cg_range.addr_cmd_range.lo_range_x_write [cross]: 1
|
||||
cg_range.cp_addr.hi_range: 2
|
||||
cg_range.cp_addr.lo_range: 2
|
||||
cg_range.cp_cmd.read: 2
|
||||
cg_range.cp_cmd.write: 2
|
||||
cg_unnamed_cross.__cross7.a0_x_read [cross]: 1
|
||||
cg_unnamed_cross.__cross7.a0_x_write [cross]: 0
|
||||
cg_unnamed_cross.__cross7.a1_x_read [cross]: 0
|
||||
cg_unnamed_cross.__cross7.a1_x_write [cross]: 1
|
||||
cg_unnamed_cross.cp_a.a0: 1
|
||||
cg_unnamed_cross.cp_a.a1: 1
|
||||
cg_unnamed_cross.cp_c.read: 1
|
||||
cg_unnamed_cross.cp_c.write: 1
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#!/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_all')
|
||||
|
||||
test.compile(verilator_flags2=['--coverage --dumpi-tree 3 --dumpi-tree-json 3'])
|
||||
|
||||
test.execute()
|
||||
|
||||
test.covergroup_coverage_report()
|
||||
test.files_identical(test.obj_dir + '/covergroup_report.txt', test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,169 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test cross coverage: 2-way, 3-way, and 4-way crosses
|
||||
|
||||
module t;
|
||||
logic [1:0] addr;
|
||||
logic cmd;
|
||||
logic mode;
|
||||
logic parity;
|
||||
|
||||
// 2-way cross
|
||||
covergroup cg2;
|
||||
cp_addr: coverpoint addr {
|
||||
bins addr0 = {0};
|
||||
bins addr1 = {1};
|
||||
}
|
||||
cp_cmd: coverpoint cmd {
|
||||
bins read = {0};
|
||||
bins write = {1};
|
||||
}
|
||||
addr_cmd: cross cp_addr, cp_cmd;
|
||||
endgroup
|
||||
|
||||
// 3-way cross
|
||||
covergroup cg3;
|
||||
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};
|
||||
}
|
||||
addr_cmd_mode: cross cp_addr, cp_cmd, cp_mode;
|
||||
endgroup
|
||||
|
||||
// 4-way cross
|
||||
covergroup cg4;
|
||||
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};
|
||||
}
|
||||
addr_cmd_mode_parity: cross cp_addr, cp_cmd, cp_mode, cp_parity;
|
||||
endgroup
|
||||
|
||||
// Cross with option inside body: exercises addOptionsp in visit(AstCoverCross*)
|
||||
covergroup cg5;
|
||||
cp_addr: coverpoint addr {
|
||||
bins addr0 = {0};
|
||||
bins addr1 = {1};
|
||||
}
|
||||
cp_cmd: coverpoint cmd {
|
||||
bins read = {0};
|
||||
bins write = {1};
|
||||
}
|
||||
addr_cmd_opt: cross cp_addr, cp_cmd {
|
||||
option.weight = 2;
|
||||
}
|
||||
endgroup
|
||||
|
||||
// 2-way cross with range bin: exercises lo!=hi path in buildBinCondition
|
||||
covergroup cg_range;
|
||||
cp_addr: coverpoint addr {
|
||||
bins lo_range = {[0:1]}; // range bin (lo != hi) -> makeRangeCondition path
|
||||
bins hi_range = {[2:3]};
|
||||
}
|
||||
cp_cmd: coverpoint cmd {
|
||||
bins read = {0};
|
||||
bins write = {1};
|
||||
}
|
||||
addr_cmd_range: cross cp_addr, cp_cmd;
|
||||
endgroup
|
||||
|
||||
// Cross where one coverpoint has ignore_bins: exercises BINS_USER FALSE branch
|
||||
// in collectBins during cross code generation (L1139)
|
||||
covergroup cg_ignore;
|
||||
cp_addr: coverpoint addr {
|
||||
ignore_bins ign = {3}; // BINS_IGNORE: not BINS_USER, exercises L1139 FALSE path
|
||||
bins a0 = {0};
|
||||
bins a1 = {1};
|
||||
}
|
||||
cp_cmd: coverpoint cmd {
|
||||
bins read = {0};
|
||||
bins write = {1};
|
||||
}
|
||||
cross_ab: cross cp_addr, cp_cmd;
|
||||
endgroup
|
||||
|
||||
// Covergroup with unnamed cross: exercises crossName.empty() fallback to "cross" (L1395)
|
||||
covergroup cg_unnamed_cross;
|
||||
cp_a: coverpoint addr { bins a0 = {0}; bins a1 = {1}; }
|
||||
cp_c: coverpoint cmd { bins read = {0}; bins write = {1}; }
|
||||
cross cp_a, cp_c; // no label -> crossName is empty
|
||||
endgroup
|
||||
|
||||
cg2 cg2_inst = new;
|
||||
cg_ignore cg_ignore_inst = new;
|
||||
cg_range cg_range_inst = new;
|
||||
cg3 cg3_inst = new;
|
||||
cg4 cg4_inst = new;
|
||||
cg5 cg5_inst = new;
|
||||
cg_unnamed_cross cg_unnamed_cross_inst = new;
|
||||
|
||||
initial begin
|
||||
// Sample 2-way: hit all 4 combinations
|
||||
addr = 0; cmd = 0; mode = 0; parity = 0; cg2_inst.sample(); // addr0 x read
|
||||
addr = 1; cmd = 1; mode = 0; parity = 0; cg2_inst.sample(); // addr1 x write
|
||||
addr = 0; cmd = 1; mode = 0; parity = 0; cg2_inst.sample(); // addr0 x write
|
||||
addr = 1; cmd = 0; mode = 0; parity = 0; cg2_inst.sample(); // addr1 x read
|
||||
|
||||
// Sample 3-way: hit 4 of 12 combinations
|
||||
addr = 0; cmd = 0; mode = 0; cg3_inst.sample(); // addr0 x read x normal
|
||||
addr = 1; cmd = 1; mode = 0; cg3_inst.sample(); // addr1 x write x normal
|
||||
addr = 2; cmd = 0; mode = 1; cg3_inst.sample(); // addr2 x read x debug
|
||||
addr = 0; cmd = 1; mode = 1; cg3_inst.sample(); // addr0 x write x debug
|
||||
|
||||
// Sample 4-way: hit 4 of 16 combinations
|
||||
addr = 0; cmd = 0; mode = 0; parity = 0; cg4_inst.sample();
|
||||
addr = 1; cmd = 1; mode = 0; parity = 1; cg4_inst.sample();
|
||||
addr = 0; cmd = 1; mode = 1; parity = 0; cg4_inst.sample();
|
||||
addr = 1; cmd = 0; mode = 1; parity = 1; cg4_inst.sample();
|
||||
|
||||
// Sample cg5 (cross with option)
|
||||
addr = 0; cmd = 0; cg5_inst.sample();
|
||||
addr = 1; cmd = 1; cg5_inst.sample();
|
||||
|
||||
// Sample cg_ignore: addr=3 is in ignore_bins so no cross bins for it
|
||||
addr = 0; cmd = 0; cg_ignore_inst.sample(); // a0 x read
|
||||
addr = 1; cmd = 1; cg_ignore_inst.sample(); // a1 x write
|
||||
addr = 0; cmd = 1; cg_ignore_inst.sample(); // a0 x write
|
||||
addr = 1; cmd = 0; cg_ignore_inst.sample(); // a1 x read
|
||||
addr = 3; cmd = 0; cg_ignore_inst.sample(); // ignored (addr=3 in ignore_bins)
|
||||
|
||||
// Sample range-bin cross
|
||||
addr = 0; cmd = 0; cg_range_inst.sample(); // lo_range x read
|
||||
addr = 2; cmd = 1; cg_range_inst.sample(); // hi_range x write
|
||||
addr = 1; cmd = 1; cg_range_inst.sample(); // lo_range x write
|
||||
addr = 3; cmd = 0; cg_range_inst.sample(); // hi_range x read
|
||||
|
||||
// Sample cg_unnamed_cross: exercises unnamed cross (crossName fallback to "cross")
|
||||
addr = 0; cmd = 0; cg_unnamed_cross_inst.sample(); // a0 x read
|
||||
addr = 1; cmd = 1; cg_unnamed_cross_inst.sample(); // a1 x write
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// 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-FileCopyrightText: 2024 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,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')
|
||||
|
||||
test.compile(verilator_flags2=['--coverage'])
|
||||
|
||||
test.execute()
|
||||
|
||||
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')
|
||||
|
||||
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,20 @@
|
|||
cg.data.high: 1
|
||||
cg.data.low: 1
|
||||
cg.data.other: 2
|
||||
cg2.cp_only_default.all: 4
|
||||
cg3.data.bad [ignore]: 1
|
||||
cg3.data.err [illegal]: 0
|
||||
cg3.data.normal: 2
|
||||
cg3.data.other: 2
|
||||
cg4.cp_idx.auto_0: 1
|
||||
cg4.cp_idx.auto_1: 1
|
||||
cg4.cp_idx.auto_2: 1
|
||||
cg4.cp_idx.skip [ignore]: 0
|
||||
cg5.cp_data64.auto[0]: 2
|
||||
cg5.cp_data64.auto[1]: 0
|
||||
cg5.cp_data64.auto[2]: 0
|
||||
cg5.cp_data64.auto[3]: 0
|
||||
cg6.cp_data65.hi: 1
|
||||
cg6.cp_data65.lo: 1
|
||||
cg7.data.hi: 1
|
||||
cg7.data.lo: 1
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#!/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()
|
||||
|
||||
test.covergroup_coverage_report()
|
||||
test.files_identical(test.obj_dir + '/covergroup_report.txt', test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
// 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
|
||||
|
||||
// Non-covergroup class: exercises V3Active isCovergroup()=false branch
|
||||
class DataHelper;
|
||||
bit [7:0] val;
|
||||
function new(bit [7:0] v); val = v; endfunction
|
||||
endclass
|
||||
|
||||
module t;
|
||||
bit [7:0] data;
|
||||
logic [1:0] idx;
|
||||
logic [63:0] data64; // 64-bit: exercises width>=64 auto-bin path (L139)
|
||||
logic [64:0] data65; // 65-bit: exercises exprWidth>64 in makeRangeCondition
|
||||
DataHelper helper; // Module-level class var: exercises V3Active isCovergroup()=false
|
||||
|
||||
covergroup cg;
|
||||
coverpoint data {
|
||||
bins low = {[0:3]};
|
||||
bins high = {[12:15]};
|
||||
bins other = default; // Catches everything else (4-11, 16+)
|
||||
}
|
||||
endgroup
|
||||
|
||||
// Covergroup with default as the ONLY bin: exercises defaultCondp=BitTrue path
|
||||
covergroup cg2;
|
||||
cp_only_default: coverpoint data {
|
||||
bins all = default;
|
||||
}
|
||||
endgroup
|
||||
|
||||
// Covergroup with default + ignore + illegal bins: exercises BINS_IGNORE/BINS_ILLEGAL
|
||||
// skip paths in generateDefaultBinMatchCode (L558-L559)
|
||||
covergroup cg3;
|
||||
coverpoint data {
|
||||
ignore_bins bad = {255}; // BINS_IGNORE skip path
|
||||
illegal_bins err = {254}; // BINS_ILLEGAL skip path
|
||||
bins normal = {[1:10]};
|
||||
bins other = default;
|
||||
}
|
||||
endgroup
|
||||
|
||||
// Covergroup with auto-bins + ignore_bins on small range: exercises L295 excluded-value continue
|
||||
// When numValidValues <= auto_bin_max, single-value auto-bins are created per value; the
|
||||
// excluded.find() check at L295 fires for the ignore_bins value (idx=2).
|
||||
covergroup cg4;
|
||||
cp_idx: coverpoint idx {
|
||||
ignore_bins skip = {2}; // value 2 excluded; auto-bins created for 0,1,3
|
||||
}
|
||||
endgroup
|
||||
|
||||
// 64-bit signal with 4 auto-bins: exercises width>=64 branch in auto-bin range calculation
|
||||
covergroup cg5;
|
||||
cp_data64: coverpoint data64 { bins auto[4]; }
|
||||
endgroup
|
||||
|
||||
// 65-bit signal with range bins: exercises exprWidth>64 path in makeRangeCondition
|
||||
covergroup cg6;
|
||||
cp_data65: coverpoint data65 { bins lo = {[0:15]}; bins hi = {[100:200]}; }
|
||||
endgroup
|
||||
|
||||
// Unlabeled coverpoint: exercises cpName fallback via exprp()->name() (L1394-1398)
|
||||
covergroup cg7;
|
||||
coverpoint data { bins lo = {[0:7]}; bins hi = {[8:15]}; }
|
||||
endgroup
|
||||
|
||||
initial begin
|
||||
cg cg_inst;
|
||||
cg2 cg2_inst;
|
||||
cg3 cg3_inst;
|
||||
cg4 cg4_inst;
|
||||
cg5 cg5_inst;
|
||||
cg6 cg6_inst;
|
||||
cg7 cg7_inst;
|
||||
|
||||
cg_inst = new();
|
||||
cg2_inst = new();
|
||||
cg3_inst = new();
|
||||
cg4_inst = new();
|
||||
cg5_inst = new();
|
||||
cg6_inst = new();
|
||||
cg7_inst = new();
|
||||
helper = new(8'h42);
|
||||
data = helper.val; // Use helper to avoid optimization
|
||||
|
||||
// Hit low bin
|
||||
data = 2;
|
||||
cg_inst.sample();
|
||||
cg2_inst.sample();
|
||||
|
||||
// Hit high bin
|
||||
data = 14;
|
||||
cg_inst.sample();
|
||||
cg2_inst.sample();
|
||||
|
||||
// Hit default bin with value 7 (not in low or high)
|
||||
data = 7;
|
||||
cg_inst.sample();
|
||||
cg2_inst.sample();
|
||||
|
||||
// Hit another default value (should not increase coverage)
|
||||
data = 20;
|
||||
cg_inst.sample();
|
||||
cg2_inst.sample();
|
||||
|
||||
// Sample cg3: exercises BINS_IGNORE/BINS_ILLEGAL skip in default-bin detection loop
|
||||
data = 2; cg3_inst.sample(); // hits normal bin
|
||||
data = 7; cg3_inst.sample(); // hits normal bin again
|
||||
data = 255; cg3_inst.sample(); // ignore_bins (not counted)
|
||||
// note: do not sample 254 (illegal_bins would cause runtime assertion)
|
||||
data = 100; cg3_inst.sample(); // hits default (other) bin
|
||||
|
||||
// Sample cg4: exercises auto-bin generation with excluded value (L295)
|
||||
// idx=2 is in ignore_bins, so auto-bins cover 0,1,3 only
|
||||
idx = 0; cg4_inst.sample();
|
||||
idx = 1; cg4_inst.sample();
|
||||
idx = 3; cg4_inst.sample();
|
||||
|
||||
// Sample cg5: 64-bit signal, sample into bin b[0] (value 0 is in first quarter)
|
||||
data64 = 0; cg5_inst.sample();
|
||||
data64 = 5; cg5_inst.sample();
|
||||
|
||||
// Sample cg6: 65-bit signal with range bins
|
||||
data65 = 5; cg6_inst.sample(); // hits bin lo=[0:15]
|
||||
data65 = 150; cg6_inst.sample(); // hits bin hi=[100:200]
|
||||
|
||||
// Sample cg7: unlabeled coverpoint (exercises exprp()->name() path)
|
||||
data = 3; cg7_inst.sample(); // hits bin lo
|
||||
data = 10; cg7_inst.sample(); // hits bin hi
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
cg.data.high: 1
|
||||
cg.data.low: 2
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#!/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()
|
||||
|
||||
test.covergroup_coverage_report()
|
||||
test.files_identical(test.obj_dir + '/covergroup_report.txt', test.golden_filename)
|
||||
|
||||
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, 2024 by Wilson Snyder.
|
||||
// SPDX-FileCopyrightText: 2024 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;
|
||||
|
||||
// Create first dynamic instance
|
||||
cg_inst = new;
|
||||
data = 0; cg_inst.sample(); // low bin
|
||||
data = 2; cg_inst.sample(); // high bin
|
||||
|
||||
// Create second independent instance
|
||||
begin
|
||||
cg cg2;
|
||||
cg2 = new;
|
||||
data = 0; cg2.sample(); // low bin
|
||||
end
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
// -*- 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-FileCopyrightText: 2026 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,2 @@
|
|||
Empty covergroup coverage: 100.000000%
|
||||
*-* All Finished *-*
|
||||
|
|
@ -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(expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module - Edge case: empty covergroup
|
||||
// This file ONLY is placed into the Public Domain, for any use, without warranty.
|
||||
// SPDX-FileCopyrightText: 2025 Wilson Snyder
|
||||
// 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
|
||||
real cov;
|
||||
cov = cg_inst.get_inst_coverage();
|
||||
$display("Empty covergroup coverage: %f%%", cov);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (cyc > 10) begin
|
||||
$display("ERROR: Test timed out");
|
||||
$stop;
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain
|
||||
// SPDX-FileCopyrightText: 2025 Antmicro
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
/* verilator lint_off COVERIGN */
|
||||
module t;
|
||||
class base;
|
||||
enum {red, green, blue} color;
|
||||
covergroup g1 (bit [3:0] a) with function sample(bit b);
|
||||
option.weight = 10;
|
||||
option.per_instance = 1;
|
||||
coverpoint a;
|
||||
coverpoint b;
|
||||
c: coverpoint color;
|
||||
endgroup
|
||||
function new();
|
||||
g1 = new(0);
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class derived extends base;
|
||||
bit d;
|
||||
covergroup extends g1;
|
||||
option.weight = 1; // overrides the weight from base g1
|
||||
// uses per_instance = 1 from base g1
|
||||
c: coverpoint color // overrides the c coverpoint in base g1
|
||||
{
|
||||
ignore_bins ignore = {blue};
|
||||
}
|
||||
coverpoint d; // adds new coverpoint
|
||||
cross a, d; // crosses new coverpoint with inherited one
|
||||
endgroup :g1
|
||||
function new();
|
||||
super.new();
|
||||
endfunction
|
||||
endclass
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
%Error-UNSUPPORTED: t/t_covergroup_extends_newfirst.v:29:5: Unsupported: covergroup inheritance (extends) is not implemented
|
||||
29 | covergroup extends g1;
|
||||
| ^~~~~~~~~~
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error: Exiting due to
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
%Error-UNSUPPORTED: t/t_covergroup_extends_unsup.v:26:5: Unsupported: covergroup inheritance (extends)
|
||||
26 | covergroup extends g1;
|
||||
| ^~~~~~~~~~
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error: Exiting due to
|
||||
|
|
@ -11,6 +11,6 @@ import vltest_bootstrap
|
|||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.compile()
|
||||
test.lint(expect_filename=test.golden_filename, fails=True)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -1,15 +1,13 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// Covergroup inheritance with 'extends' is not yet supported
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain
|
||||
// SPDX-FileCopyrightText: 2025 Antmicro
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
/* verilator lint_off COVERIGN */
|
||||
module t;
|
||||
class base;
|
||||
function new();
|
||||
g1 = new(0);
|
||||
endfunction
|
||||
enum {red, green, blue} color;
|
||||
covergroup g1 (bit [3:0] a) with function sample(bit b);
|
||||
option.weight = 10;
|
||||
|
|
@ -18,13 +16,13 @@ module t;
|
|||
coverpoint b;
|
||||
c: coverpoint color;
|
||||
endgroup
|
||||
function new();
|
||||
g1 = new(0);
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class derived extends base;
|
||||
bit d;
|
||||
function new();
|
||||
super.new();
|
||||
endfunction
|
||||
covergroup extends g1;
|
||||
option.weight = 1; // overrides the weight from base g1
|
||||
// uses per_instance = 1 from base g1
|
||||
|
|
@ -35,5 +33,8 @@ module t;
|
|||
coverpoint d; // adds new coverpoint
|
||||
cross a, d; // crosses new coverpoint with inherited one
|
||||
endgroup :g1
|
||||
function new();
|
||||
super.new();
|
||||
endfunction
|
||||
endclass
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
cg_array_iff.cp.arr: 1
|
||||
cg_default_iff.cp.def: 1
|
||||
cg_default_iff.cp.known: 1
|
||||
cg_iff.cp_value.disabled_hi: 0
|
||||
cg_iff.cp_value.disabled_lo: 0
|
||||
cg_iff.cp_value.enabled_hi: 1
|
||||
cg_iff.cp_value.enabled_lo: 1
|
||||
cg_trans2_iff.cp.t2: 1
|
||||
cg_trans3_iff.cp.t3: 1
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#!/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()
|
||||
|
||||
test.covergroup_coverage_report()
|
||||
test.files_identical(test.obj_dir + '/covergroup_report.txt', test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
// 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-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Test iff (enable) guard: sampling is gated by the enable condition.
|
||||
// Covers iff on explicit value bins, default bin, array bins,
|
||||
// simple 2-step transition, and 3-step transition.
|
||||
|
||||
module t;
|
||||
logic enable;
|
||||
int value;
|
||||
|
||||
// --- Original: iff on explicit value bins (lines 565-567) ---
|
||||
covergroup cg_iff;
|
||||
cp_value: coverpoint value iff (enable) {
|
||||
bins disabled_lo = {1};
|
||||
bins disabled_hi = {2};
|
||||
bins enabled_lo = {3};
|
||||
bins enabled_hi = {4};
|
||||
}
|
||||
endgroup
|
||||
|
||||
// --- iff on default bin (lines 633-635/641) ---
|
||||
covergroup cg_default_iff;
|
||||
cp: coverpoint value iff (enable) {
|
||||
bins known = {10};
|
||||
bins def = default; // default bin with coverpoint-level iff
|
||||
}
|
||||
endgroup
|
||||
|
||||
// --- iff on array bins (lines 982-983) ---
|
||||
covergroup cg_array_iff;
|
||||
cp: coverpoint value iff (enable) {
|
||||
bins arr[] = {5, 6, 7}; // array bins, all gated by iff
|
||||
}
|
||||
endgroup
|
||||
|
||||
// --- iff on 2-step transition (lines 1109-1110) ---
|
||||
covergroup cg_trans2_iff;
|
||||
cp: coverpoint value iff (enable) {
|
||||
bins t2 = (1 => 2);
|
||||
}
|
||||
endgroup
|
||||
|
||||
// --- iff on 3-step transition (lines 724-725, 762-763) ---
|
||||
covergroup cg_trans3_iff;
|
||||
cp: coverpoint value iff (enable) {
|
||||
bins t3 = (1 => 2 => 3);
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg_iff cg1 = new;
|
||||
cg_default_iff cg2 = new;
|
||||
cg_array_iff cg3 = new;
|
||||
cg_trans2_iff cg4 = new;
|
||||
cg_trans3_iff cg5 = new;
|
||||
|
||||
initial begin
|
||||
// Sample disabled_lo and disabled_hi with enable=0 -- must not be recorded
|
||||
enable = 0;
|
||||
value = 1; cg1.sample();
|
||||
value = 2; cg1.sample();
|
||||
|
||||
// Sample enabled_lo and enabled_hi with enable=1 -- must be recorded
|
||||
enable = 1;
|
||||
value = 3; cg1.sample();
|
||||
value = 4; cg1.sample();
|
||||
|
||||
// cg2: default bin -- enable=1 lets known and default through
|
||||
enable = 1;
|
||||
value = 10; cg2.sample(); // hits 'known'
|
||||
value = 99; cg2.sample(); // hits 'def' (default)
|
||||
enable = 0;
|
||||
value = 99; cg2.sample(); // gated by iff -- must NOT hit 'def'
|
||||
|
||||
// cg3: array bins with iff
|
||||
enable = 1;
|
||||
value = 5; cg3.sample(); // arr[5] hit
|
||||
enable = 0;
|
||||
value = 6; cg3.sample(); // gated
|
||||
|
||||
// cg4: 2-step transition with iff
|
||||
enable = 1;
|
||||
value = 1; cg4.sample();
|
||||
value = 2; cg4.sample(); // (1=>2) hit with enable=1
|
||||
enable = 0;
|
||||
value = 1; cg4.sample();
|
||||
value = 2; cg4.sample(); // (1=>2) gated by iff
|
||||
|
||||
// cg5: 3-step transition with iff
|
||||
enable = 1;
|
||||
value = 1; cg5.sample();
|
||||
value = 2; cg5.sample(); // mid-sequence, enable=1
|
||||
enable = 0;
|
||||
value = 3; cg5.sample(); // iff fails at step 3 -- triggers restart path (line 762-763)
|
||||
enable = 1;
|
||||
value = 1; cg5.sample();
|
||||
value = 2; cg5.sample();
|
||||
value = 3; cg5.sample(); // (1=>2=>3) fully hit with enable=1
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
cg.data.catch_all [ignore]: 0
|
||||
cg.data.high: 1
|
||||
cg.data.low: 1
|
||||
cg.data.reserved [ignore]: 1
|
||||
cg.data.wib: 0
|
||||
cg2.cp_auto.auto_0: 1
|
||||
cg2.cp_auto.auto_1: 1
|
||||
cg2.cp_auto.ign [ignore]: 2
|
||||
cg2.cp_auto.ign_trans [ignore]: 1
|
||||
cg2.cp_bounds.hi: 2
|
||||
cg2.cp_bounds.lo: 2
|
||||
cg2.cp_full.all: 4
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#!/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()
|
||||
|
||||
test.covergroup_coverage_report()
|
||||
test.files_identical(test.obj_dir + '/covergroup_report.txt', test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
// 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*/);
|
||||
logic [3:0] data;
|
||||
logic [1:0] data2; // 2-bit signal for range-boundary tests
|
||||
|
||||
covergroup cg;
|
||||
coverpoint data {
|
||||
bins low = {[0:3]};
|
||||
bins high = {[8:11]};
|
||||
ignore_bins reserved = {[12:15]};
|
||||
ignore_bins catch_all = default; // null rangesp: exercises generateBinMatchCode !fullCondp
|
||||
wildcard ignore_bins wib = {4'b1?00}; // wildcard ignore bins (L7084-7085)
|
||||
}
|
||||
endgroup
|
||||
|
||||
// Exercises:
|
||||
// extractValuesFromRange AstInsideRange branch (ignore_bins range, no regular bins)
|
||||
// createImplicitAutoBins with excluded range values
|
||||
// makeRangeCondition: skipUpperCheck=true (hi=maxVal) and both-skip (BitTrue)
|
||||
// ignore_bins with transition list (L7102-7104)
|
||||
covergroup cg2;
|
||||
cp_auto: coverpoint data2 {
|
||||
ignore_bins ign = {[2:3]}; // range ignore, no regular bins -> auto-bins created
|
||||
ignore_bins ign_trans = (0 => 1); // ignore_bins with transition (L7102-7104)
|
||||
}
|
||||
cp_bounds: coverpoint data2 {
|
||||
bins lo = {[0:1]}; // lo=0: skipLowerCheck -> AstLte
|
||||
bins hi = {[2:3]}; // hi=maxVal (2-bit): skipUpperCheck -> AstGte
|
||||
}
|
||||
cp_full: coverpoint data2 {
|
||||
bins all = {[0:3]}; // lo=0 and hi=maxVal: both skip -> AstConst(BitTrue)
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg cg_inst;
|
||||
cg2 cg2_inst;
|
||||
|
||||
initial begin
|
||||
cg_inst = new;
|
||||
cg2_inst = new;
|
||||
|
||||
data = 13; cg_inst.sample(); // reserved - ignored
|
||||
data = 1; cg_inst.sample(); // low
|
||||
data = 10; cg_inst.sample(); // high
|
||||
|
||||
data2 = 0; cg2_inst.sample(); // auto_0, lo, all
|
||||
data2 = 1; cg2_inst.sample(); // auto_1, lo, all
|
||||
data2 = 2; cg2_inst.sample(); // ign, hi, all
|
||||
data2 = 3; cg2_inst.sample(); // ign, hi, all
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
cg.data.forbidden [illegal]: 0
|
||||
cg.data.high: 1
|
||||
cg.data.low: 1
|
||||
cg.data.mid: 1
|
||||
cg2.cp_arr.bad_arr [illegal]: 0
|
||||
cg2.cp_arr.ok: 1
|
||||
cg2.cp_arr.wlib: 0
|
||||
cg2.cp_trans.bad_2step [illegal]: 0
|
||||
cg2.cp_trans.bad_3step [illegal]: 0
|
||||
cg2.cp_trans.lib_default [illegal]: 0
|
||||
cg2.cp_trans.ok: 1
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#!/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()
|
||||
|
||||
test.covergroup_coverage_report()
|
||||
test.files_identical(test.obj_dir + '/covergroup_report.txt', test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// Test that illegal_bins are excluded from coverage (like ignore_bins)
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2026 by Wilson Snyder.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t;
|
||||
logic [1:0] data;
|
||||
logic [3:0] data4;
|
||||
|
||||
covergroup cg;
|
||||
coverpoint data {
|
||||
bins low = {0};
|
||||
bins mid = {1};
|
||||
bins high = {2};
|
||||
illegal_bins forbidden = {3};
|
||||
}
|
||||
endgroup
|
||||
|
||||
// cg2: exercises illegal_bins with 3-step transition (lines 744-747) and
|
||||
// illegal_bins array notation (lines 996-998)
|
||||
covergroup cg2;
|
||||
cp_trans: coverpoint data4 {
|
||||
bins ok = {0};
|
||||
illegal_bins bad_2step = (1 => 2); // 2-step illegal transition (simple path)
|
||||
illegal_bins bad_3step = (1 => 2 => 3); // multi-step illegal transition
|
||||
illegal_bins lib_default = default; // illegal_bins = default (L7123-7124)
|
||||
}
|
||||
cp_arr: coverpoint data4 {
|
||||
bins ok = {0};
|
||||
illegal_bins bad_arr[] = {8, 9, 10}; // illegal array bins
|
||||
wildcard illegal_bins wlib = {4'b1?00}; // wildcard illegal bins (L7087-7088)
|
||||
}
|
||||
endgroup
|
||||
|
||||
initial begin
|
||||
automatic cg cg_inst = new;
|
||||
automatic cg2 cg2_inst = new;
|
||||
|
||||
// Sample legal values only
|
||||
data = 0; cg_inst.sample();
|
||||
data = 1; cg_inst.sample();
|
||||
data = 2; cg_inst.sample();
|
||||
|
||||
// Sample cg2 - only safe values, never triggering illegal bins
|
||||
data4 = 0; cg2_inst.sample();
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain
|
||||
// SPDX-FileCopyrightText: 2025 Antmicro
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
/* verilator lint_off COVERIGN */
|
||||
class myClass;
|
||||
covergroup embeddedCg;
|
||||
|
||||
endgroup
|
||||
|
||||
function new();
|
||||
real r;
|
||||
embeddedCg = new();
|
||||
embeddedCg.sample();
|
||||
r = embeddedCg.get_coverage();
|
||||
endfunction
|
||||
endclass
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -11,6 +11,6 @@ import vltest_bootstrap
|
|||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.compile()
|
||||
test.compile(verilator_flags2=['--coverage'])
|
||||
|
||||
test.passes()
|
||||
|
|
@ -4,17 +4,15 @@
|
|||
// SPDX-FileCopyrightText: 2025 Antmicro
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
/* verilator lint_off COVERIGN */
|
||||
class myClass;
|
||||
covergroup embeddedCg;
|
||||
|
||||
endgroup
|
||||
|
||||
function new();
|
||||
real r;
|
||||
embeddedCg = new();
|
||||
embeddedCg.sample();
|
||||
r = embeddedCg.get_coverage();
|
||||
void'(embeddedCg.get_coverage());
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
|
|
@ -24,9 +22,8 @@ class secondClass;
|
|||
endgroup
|
||||
|
||||
function new();
|
||||
real r;
|
||||
embeddedCg = new();
|
||||
embeddedCg.sample();
|
||||
r = embeddedCg.get_coverage();
|
||||
void'(embeddedCg.get_coverage());
|
||||
endfunction
|
||||
endclass
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
#!/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.compile()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain
|
||||
// SPDX-FileCopyrightText: 2025 Antmicro
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
/* verilator lint_off COVERIGN */
|
||||
class C;
|
||||
covergroup embedded(int x) with function sample (int a, bit b);
|
||||
endgroup
|
||||
function new();
|
||||
embedded = new(1);
|
||||
embedded.sample(2, 1'b0);
|
||||
endfunction
|
||||
endclass
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
%Warning-COVERIGN: t/t_covergroup_member_event_unsup.v:11:5: Unsupported: 'covergroup' clocking event on member variable
|
||||
: ... note: In instance 't'
|
||||
11 | covergroup cov1 @m_z;
|
||||
| ^~~~~~~~~~
|
||||
... 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
|
||||
|
|
@ -11,8 +11,6 @@ import vltest_bootstrap
|
|||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.lint(expect_filename=test.golden_filename,
|
||||
verilator_flags2=['--assert --error-limit 1000'],
|
||||
fails=True)
|
||||
test.lint(expect_filename=test.golden_filename, verilator_flags2=['--assert'], fails=True)
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2024 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t(input clk);
|
||||
class Packet;
|
||||
int m_z;
|
||||
int m_x;
|
||||
covergroup cov1 @m_z;
|
||||
coverpoint m_x;
|
||||
endgroup
|
||||
endclass
|
||||
initial begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
%Error: t/t_covergroup_method_bad.v:16:10: Member 'some_unknown_method' not found in covergroup 'cg'
|
||||
: ... note: In instance 't'
|
||||
16 | cov1.some_unknown_method.name = "new_cov1_name";
|
||||
| ^~~~~~~~~~~~~~~~~~~
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
%Error-UNSUPPORTED: t/t_covergroup_method_bad.v:16:30: Unsupported: Member call on object 'CONST '1'h0'' which is a 'BASICDTYPE 'bit''
|
||||
: ... note: In instance 't'
|
||||
16 | cov1.some_unknown_method.name = "new_cov1_name";
|
||||
| ^~~~
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error: Exiting due to
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2023 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
module t;
|
||||
// verilator lint_off COVERIGN
|
||||
covergroup cg();
|
||||
endgroup
|
||||
|
||||
cg cov1;
|
||||
|
||||
initial begin
|
||||
cov1 = new;
|
||||
cov1.some_unknown_method.name = "new_cov1_name"; // <-- BAD
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
cg.opcode.arith: 1
|
||||
cg.opcode.load: 1
|
||||
cg.opcode.nop: 1
|
||||
cg.opcode.others: 1
|
||||
cg.opcode.store: 1
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#!/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()
|
||||
|
||||
test.covergroup_coverage_report()
|
||||
test.files_identical(test.obj_dir + '/covergroup_report.txt', test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue