mirror of
https://github.com/verilator/verilator.git
synced 2026-10-06 01:54:01 +02:00
Support wildcard bins (#8516)
This commit is contained in:
@@ -1212,6 +1212,12 @@ public:
|
||||
"illegal_bins", "transition", "bins", "wildcard"};
|
||||
return names[m_e];
|
||||
}
|
||||
// Keyword declaring the bins, without any 'wildcard' prefix
|
||||
const char* verilogKwd() const {
|
||||
static const char* const names[] = {"bins", "bins", "bins", "bins", "ignore_bins",
|
||||
"illegal_bins", "bins", "bins", "bins"};
|
||||
return names[m_e];
|
||||
}
|
||||
// VlCovBinKind enumerator naming the bin's set
|
||||
const char* binSetEnum() const {
|
||||
switch (m_e) {
|
||||
|
||||
+294
-44
@@ -228,7 +228,9 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
// NODE STATE
|
||||
// Entire netlist:
|
||||
// AstCoverpoint::user1p() -> AstVar*. Previous-value variable for transition bins
|
||||
// AstCoverpoint::user2() -> bool. Had a bins declaration ignored, so no automatic bins
|
||||
const VNUser1InUse m_inuser1;
|
||||
const VNUser2InUse m_inuser2;
|
||||
|
||||
// STATE
|
||||
std::set<AstCoverpoint*>
|
||||
@@ -266,6 +268,10 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
std::vector<BinRun> runs; // Runs of an array or automatic bins declaration, in order
|
||||
uint32_t count = 0; // Bins across all runs
|
||||
bool unsupported = false; // Too many bins, or invalid: the declaration is ignored
|
||||
// The value of each bin, which names it, of a wildcard array; else the bins are indexed
|
||||
std::vector<std::string> values;
|
||||
// Too many values of an ignore or illegal wildcard array, which is then one bin
|
||||
bool single = false;
|
||||
};
|
||||
struct CrossBinValues final {
|
||||
AstCoverBin* binp; // Declaration owning this Normal bin
|
||||
@@ -458,14 +464,6 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
generateCoverageComputationCode();
|
||||
}
|
||||
|
||||
// Limit on the bins of one array or automatic bins declaration of an integral coverpoint,
|
||||
// and on the automatic bins of option.auto_bin_max: --coverage-max-bins, like other
|
||||
// simulators' limits. It guards against hangs from e.g. signed underflow. Such bins
|
||||
// generate as runs, whose code size does not depend on their number.
|
||||
static uint32_t binsLimit() { return v3Global.opt.coverageMaxBins(); }
|
||||
// Limit on the values of one array bins declaration of a real coverpoint, which generates a
|
||||
// comparison per value (see extractArrayValues): --coverage-max-real-bins
|
||||
static uint32_t realBinsLimit() { return v3Global.opt.coverageMaxRealBins(); }
|
||||
static constexpr size_t VALUE_LIST_ENTRIES = 256; // Metadata entries per constructor call
|
||||
|
||||
// The number of bins a constant array size requests: -1 if it is negative, and saturated
|
||||
@@ -481,7 +479,8 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
const AstConst* const constp = VN_CAST(binp->arraySizep(), Const);
|
||||
if (!constp) return 0;
|
||||
const int64_t count = binsCount(constp);
|
||||
return count < 1 || count > binsLimit() ? 0 : static_cast<uint32_t>(count);
|
||||
return count < 1 || count > v3Global.opt.coverageMaxBins() ? 0
|
||||
: static_cast<uint32_t>(count);
|
||||
}
|
||||
|
||||
// True for a 'bins auto[N]' declaration, or the implicit automatic bins of a coverpoint
|
||||
@@ -497,7 +496,8 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
}
|
||||
|
||||
// Check the sized arrays of bins of a coverpoint, dropping invalid ones. A real
|
||||
// coverpoint's are unsupported, and treated as arrays of a bin per value.
|
||||
// coverpoint's are unsupported, and treated as arrays of a bin per value. A wildcard array
|
||||
// of too many ranges of values is ignored, or if ignore or illegal, treated as one bin.
|
||||
void checkSizedArrays(AstCoverpoint* coverpointp) {
|
||||
const bool integral = coverpointp->exprp()->dtypep()->skipRefp()->isIntegralOrPacked();
|
||||
for (AstNode* nodep = coverpointp->binsp(); nodep;) {
|
||||
@@ -520,6 +520,25 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
"coverpoint (treated as '[]')");
|
||||
VL_DO_DANGLING(pushDeletep(sizep->unlinkFrBack()), sizep);
|
||||
continue;
|
||||
} else if (binp->isWildcard()
|
||||
&& sizedWildcardRuns(binp, coverpointp->exprp())
|
||||
> v3Global.opt.coverageMaxBins()) {
|
||||
// An ignore or illegal array still excludes or checks its values, as one bin
|
||||
const bool single = !binp->binsType().binIsNormal();
|
||||
binp->v3warn(COVERIGN,
|
||||
"Unsupported: sized wildcard array '"
|
||||
<< binp->binsType().verilogKwd()
|
||||
<< "' of more than --coverage-max-bins of "
|
||||
<< v3Global.opt.coverageMaxBins() << " ranges of values; "
|
||||
<< (single ? "treated as one bin" : "bin ignored") << "\n"
|
||||
<< binp->warnMore()
|
||||
<< "... Suggest a larger --coverage-max-bins");
|
||||
if (single) {
|
||||
VL_DO_DANGLING(pushDeletep(sizep->unlinkFrBack()), sizep);
|
||||
binp->isArray(false);
|
||||
continue;
|
||||
}
|
||||
coverpointp->user2(true);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
@@ -527,6 +546,20 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
// The ranges of values the wildcard patterns of a sized wildcard array give, counted up to
|
||||
// more than --coverage-max-bins
|
||||
static size_t sizedWildcardRuns(const AstCoverBin* binp, AstNodeExpr* exprp) {
|
||||
std::vector<std::pair<V3Number, V3Number>> runs;
|
||||
for (AstNode* rangep = binp->rangesp(); rangep; rangep = rangep->nextp()) {
|
||||
if (!VN_IS(rangep, Const)) continue; // A range, or a value known at construction
|
||||
CrossValueRange range{rangep, resolveWidth(rangep, exprp)};
|
||||
if (resolveValue(rangep, exprp, true, true, range) && !crossRangeEmpty(range)) {
|
||||
crossRangeRuns(range, v3Global.opt.coverageMaxBins(), runs);
|
||||
}
|
||||
}
|
||||
return runs.size();
|
||||
}
|
||||
|
||||
// Check the automatic bins declarations of a coverpoint. Each stays one declaration, which
|
||||
// generates as a partition of the coverpoint domain (see autoBinRuns).
|
||||
void checkAutomaticBins(AstCoverpoint* coverpointp, const AstNodeExpr* exprp) {
|
||||
@@ -539,10 +572,10 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
} else if (binsCount(constp) < 1) {
|
||||
cbinp->v3error("Automatic bins array size must be >= 1, got "
|
||||
<< constp->num().toDecimalS());
|
||||
} else if (binsCount(constp) > binsLimit()) {
|
||||
} else if (binsCount(constp) > v3Global.opt.coverageMaxBins()) {
|
||||
cbinp->v3error("Automatic bins array size of "
|
||||
<< constp->num().toDecimalU() << " exceeds limit of " << binsLimit()
|
||||
<< '\n'
|
||||
<< constp->num().toDecimalU() << " exceeds limit of "
|
||||
<< v3Global.opt.coverageMaxBins() << '\n'
|
||||
<< cbinp->warnMore() << "... Suggest a larger --coverage-max-bins");
|
||||
} else if (!exprp->dtypep()->skipRefp()->isIntegralOrPacked()) {
|
||||
cbinp->v3error("Automatic bins are not allowed on a coverpoint of a non-integral "
|
||||
@@ -607,6 +640,7 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
// IEEE 1800-2023 19.5.3/19.11.1: partition first, then apply exclusions. The partition is one
|
||||
// automatic bins declaration, generated as a run like 'bins auto[N]' but numbering its bins.
|
||||
void createImplicitAutoBins(AstCoverpoint* coverpointp, AstNodeExpr* exprp, int autoBinMax) {
|
||||
if (coverpointp->user2()) return; // Declared bins, ignored, leave no bins
|
||||
for (AstNode* nodep = coverpointp->binsp(); nodep; nodep = nodep->nextp()) {
|
||||
const VCoverBinsType kind = VN_AS(nodep, CoverBin)->binsType();
|
||||
if (kind != VCoverBinsType::BINS_IGNORE && kind != VCoverBinsType::BINS_ILLEGAL)
|
||||
@@ -626,15 +660,15 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
"(IEEE 1800-2023 19.5.3).");
|
||||
return;
|
||||
}
|
||||
if (count > binsLimit()) {
|
||||
if (count > v3Global.opt.coverageMaxBins()) {
|
||||
coverpointp->v3warn(COVERIGN, "Unsupported: more than "
|
||||
<< binsLimit()
|
||||
<< v3Global.opt.coverageMaxBins()
|
||||
<< " automatic bins from 'option.auto_bin_max'; "
|
||||
"using "
|
||||
<< binsLimit() << ".\n"
|
||||
<< v3Global.opt.coverageMaxBins() << ".\n"
|
||||
<< coverpointp->warnMore()
|
||||
<< "... Suggest a larger --coverage-max-bins");
|
||||
count = binsLimit();
|
||||
count = v3Global.opt.coverageMaxBins();
|
||||
}
|
||||
FileLine* const fl = coverpointp->fileline();
|
||||
coverpointp->addBinsp(new AstCoverBin{fl, "auto", new AstConst{fl, count},
|
||||
@@ -808,6 +842,8 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
for (AstNode* nodep = coverpointp->binsp(); nodep; nodep = nodep->nextp()) {
|
||||
const AstCoverBin* const binp = VN_AS(nodep, CoverBin);
|
||||
if (!binp->binsType().binIsNormal() || binp->transp() || !binp->rangesp()) continue;
|
||||
// A wildcard array has a bin for each value its elements match, so none empty
|
||||
if (binp->isArray() && binp->isWildcard()) continue;
|
||||
bool empty = true;
|
||||
for (AstNode* valuep = binp->rangesp(); valuep; valuep = valuep->nextp()) {
|
||||
if (binp->isArray() && VN_IS(valuep, InsideRange)) continue;
|
||||
@@ -965,6 +1001,20 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
bins.push_back({{0, maxVal}});
|
||||
return exprp->width() <= 64;
|
||||
}
|
||||
if (cbinp->isArray() && cbinp->isWildcard() && !cbinp->arraySizep()) {
|
||||
// A value is in at most one bin of a wildcard array: one slot covering its values.
|
||||
// Signed values are sign-extended, not unsigned intervals (see computeHitListBound)
|
||||
++slotCount;
|
||||
if (exprp->isSigned() || exprp->width() > 64) return false;
|
||||
const BinRuns runs = wildcardBinRuns(cbinp, exprp, false);
|
||||
if (runs.unsupported) return false;
|
||||
std::vector<std::pair<uint64_t, uint64_t>> ivs;
|
||||
for (const BinRun& run : runs.runs) {
|
||||
ivs.emplace_back(run.m_lo.toUQuad(), run.m_hi.toUQuad());
|
||||
}
|
||||
bins.push_back(std::move(ivs));
|
||||
return true;
|
||||
}
|
||||
if (cbinp->isArray()) return appendArrayBinCrossSlots(cbinp, exprp, bins, slotCount);
|
||||
// Non-array bin: one slot covering the union of its intervals.
|
||||
++slotCount;
|
||||
@@ -983,8 +1033,9 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
bool appendArrayBinCrossSlots(AstCoverBin* cbinp, AstNodeExpr* exprp,
|
||||
std::vector<std::vector<std::pair<uint64_t, uint64_t>>>& bins,
|
||||
int& slotCount) {
|
||||
// Signed values resolve sign-extended, not as unsigned intervals
|
||||
bool exact = !exprp->isSigned();
|
||||
// Signed values resolve sign-extended, not as unsigned intervals, and wildcard patterns
|
||||
// are not intervals
|
||||
bool exact = !exprp->isSigned() && !cbinp->isWildcard();
|
||||
for (AstNode* rp = cbinp->rangesp(); rp; rp = rp->nextp()) {
|
||||
++slotCount;
|
||||
RangeBounds rb;
|
||||
@@ -1094,25 +1145,31 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
}
|
||||
|
||||
// Check that an element of an array bin (bins b[] = {values/ranges}) is a two-state
|
||||
// constant value or range; false if not, after reporting it.
|
||||
static bool checkArrayBinElement(AstCoverBin* arrayBinp, AstNode* rangep) {
|
||||
// constant value or range; false if not, after reporting it if 'report'.
|
||||
static bool checkArrayBinElement(AstCoverBin* arrayBinp, AstNode* rangep, bool report = true) {
|
||||
if (const AstInsideRange* const irp = VN_CAST(rangep, InsideRange)) {
|
||||
const AstConst* const minp = VN_CAST(irp->lhsp(), Const);
|
||||
const AstConst* const maxp = VN_CAST(irp->rhsp(), Const);
|
||||
if ((!minp && !VN_IS(irp->lhsp(), Unbounded))
|
||||
|| (!maxp && !VN_IS(irp->rhsp(), Unbounded))) {
|
||||
arrayBinp->v3error("Non-constant expression in array bins range; "
|
||||
"range bounds must be constants (IEEE 1800-2023 19.5)");
|
||||
if (report) {
|
||||
arrayBinp->v3error("Non-constant expression in array bins range; "
|
||||
"range bounds must be constants (IEEE 1800-2023 19.5)");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if ((minp && minp->num().isFourState()) || (maxp && maxp->num().isFourState())) {
|
||||
arrayBinp->v3error("Four-state (x/z) value in array bins range bound; "
|
||||
"range bounds must be two-state constants");
|
||||
if (report) {
|
||||
arrayBinp->v3error("Four-state (x/z) value in array bins range bound; "
|
||||
"range bounds must be two-state constants");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} else if (!VN_IS(rangep, Const)) {
|
||||
arrayBinp->v3error("Non-constant expression in array bins value list; "
|
||||
"values must be constants (IEEE 1800-2023 19.5)");
|
||||
if (report) {
|
||||
arrayBinp->v3error("Non-constant expression in array bins value list; "
|
||||
"values must be constants (IEEE 1800-2023 19.5)");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -1141,11 +1198,13 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
if (hi < lo) continue; // empty range contributes no bins
|
||||
// Guard against a '$'-bounded or otherwise huge range exploding the bin count.
|
||||
const uint64_t span = hi - lo; // == valueCount - 1 (no overflow: hi >= lo)
|
||||
if (span >= realBinsLimit() || values.size() + span + 1 > realBinsLimit()) {
|
||||
if (span >= v3Global.opt.coverageMaxRealBins()
|
||||
|| values.size() + span + 1 > v3Global.opt.coverageMaxRealBins()) {
|
||||
arrayBinp->v3warn(COVERIGN,
|
||||
"Unsupported: array 'bins' of a real coverpoint "
|
||||
"covering more than "
|
||||
<< realBinsLimit() << " values; bin ignored.\n"
|
||||
<< v3Global.opt.coverageMaxRealBins()
|
||||
<< " values; bin ignored.\n"
|
||||
<< arrayBinp->warnMore()
|
||||
<< "... Suggest a larger --coverage-max-real-bins");
|
||||
unsupportedOut = true;
|
||||
@@ -1222,9 +1281,9 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
// Wider spans exceed any limit
|
||||
count = span.mostSetBitP1() > 32 ? UINT64_MAX : span.toUQuad() + 1;
|
||||
}
|
||||
if (count > binsLimit() - out.count) {
|
||||
if (count > v3Global.opt.coverageMaxBins() - out.count) {
|
||||
arrayBinp->v3warn(COVERIGN, "Unsupported: array 'bins' covering more than "
|
||||
<< binsLimit()
|
||||
<< v3Global.opt.coverageMaxBins()
|
||||
<< " values (e.g. an open '[lo:$]' range over "
|
||||
"a wide coverpoint); bin ignored\n"
|
||||
<< arrayBinp->warnMore()
|
||||
@@ -1241,13 +1300,123 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
return out;
|
||||
}
|
||||
|
||||
// The bins of a wildcard array (wildcard bins b[] = {...}): one for each coverpoint value
|
||||
// an element matches (IEEE 1800-2023 19.5.4, 19.5.7), in value order, and named by the value
|
||||
// (19.5.1), as runs of single-value bins. Errors on a non-constant element. More than
|
||||
// --coverage-max-bins values are unsupported -- emits COVERIGN, and sets unsupported, and for
|
||||
// an ignore or illegal array, single. 'report' false omits these diagnostics.
|
||||
static BinRuns wildcardBinRuns(AstCoverBin* arrayBinp, AstNodeExpr* exprp, bool report) {
|
||||
BinRuns out;
|
||||
const int width = runWidth(exprp);
|
||||
const V3Number one{arrayBinp, width, 1};
|
||||
// Disjoint runs of the values, in value order, each value once
|
||||
std::vector<std::pair<V3Number, V3Number>> spans;
|
||||
uint64_t count = 0; // Values of 'spans'
|
||||
for (AstNode* rangep = arrayBinp->rangesp(); rangep; rangep = rangep->nextp()) {
|
||||
rangep = V3Const::constifyEdit(rangep);
|
||||
if (!checkArrayBinElement(arrayBinp, rangep, report)) {
|
||||
out.unsupported = true;
|
||||
return out;
|
||||
}
|
||||
CrossValueRange range{rangep, resolveWidth(rangep, exprp)};
|
||||
if (!resolveValue(rangep, exprp, true, true, range)) {
|
||||
if (report) {
|
||||
rangep->v3warn(E_UNSUPPORTED, "Unsupported: non-integral value in a "
|
||||
"coverage bin of an integral coverpoint.");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (crossRangeEmpty(range)) continue;
|
||||
std::vector<std::pair<V3Number, V3Number>> found;
|
||||
crossRangeRuns(range, v3Global.opt.coverageMaxBins(), found);
|
||||
for (const std::pair<V3Number, V3Number>& run : found) {
|
||||
// Coverpoint values, sign-extended in both widths
|
||||
spans.emplace_back(V3Number{rangep, width, run.first},
|
||||
V3Number{rangep, width, run.second});
|
||||
}
|
||||
std::sort(spans.begin(), spans.end(), [](const auto& lhs, const auto& rhs) {
|
||||
return crossValueLess(lhs.first, rhs.first);
|
||||
});
|
||||
std::vector<std::pair<V3Number, V3Number>> merged;
|
||||
for (const std::pair<V3Number, V3Number>& span : spans) {
|
||||
// Adjacent or overlapping values join a run; 'first - 1' cannot overflow
|
||||
V3Number before{rangep, width};
|
||||
before.opSub(span.first, one);
|
||||
if (merged.empty() || crossValueLess(merged.back().second, before)) {
|
||||
merged.push_back(span);
|
||||
} else if (crossValueLess(merged.back().second, span.second)) {
|
||||
merged.back().second = span.second;
|
||||
}
|
||||
}
|
||||
count = 0;
|
||||
for (const std::pair<V3Number, V3Number>& span : merged) {
|
||||
V3Number size{rangep, width};
|
||||
size.opSub(span.second, span.first);
|
||||
// Beyond 2^32 values exceed any limit
|
||||
count += size.mostSetBitP1() > 32 ? uint64_t{1} << 33 : size.toUQuad() + 1;
|
||||
if (count > v3Global.opt.coverageMaxBins()) break;
|
||||
}
|
||||
spans = std::move(merged);
|
||||
if (count > v3Global.opt.coverageMaxBins()) {
|
||||
// An ignore or illegal array still excludes or checks its values, as one bin
|
||||
out.single = !arrayBinp->binsType().binIsNormal();
|
||||
if (report) {
|
||||
arrayBinp->v3warn(COVERIGN,
|
||||
"Unsupported: wildcard array '"
|
||||
<< arrayBinp->binsType().verilogKwd()
|
||||
<< "' of more than --coverage-max-bins of "
|
||||
<< v3Global.opt.coverageMaxBins() << " values; "
|
||||
<< (out.single ? "treated as one bin" : "bin ignored")
|
||||
<< "\n"
|
||||
<< arrayBinp->warnMore()
|
||||
<< "... Suggest a larger --coverage-max-bins");
|
||||
}
|
||||
out.unsupported = true;
|
||||
return out;
|
||||
}
|
||||
}
|
||||
for (const std::pair<V3Number, V3Number>& span : spans) {
|
||||
out.runs.emplace_back(arrayBinp, width, 0);
|
||||
BinRun& run = out.runs.back();
|
||||
run.m_lo = span.first;
|
||||
run.m_hi = span.second;
|
||||
// A bin for each value, named by it in the coverpoint's type
|
||||
V3Number value = span.first;
|
||||
while (true) {
|
||||
const V3Number typed{arrayBinp, exprp->width(), value};
|
||||
out.values.push_back(exprp->isSigned() ? typed.toDecimalS() : typed.toDecimalU());
|
||||
++run.m_count;
|
||||
if (value.isCaseEq(span.second)) break;
|
||||
V3Number next{arrayBinp, width};
|
||||
value = next.opAdd(value, one);
|
||||
}
|
||||
}
|
||||
out.count = static_cast<uint32_t>(count);
|
||||
return out;
|
||||
}
|
||||
|
||||
// The runs of an automatic bins declaration, or of an array bin of an integral coverpoint.
|
||||
// False for other bins, which do not generate as runs.
|
||||
// False for other bins, which do not generate as runs, including a wildcard array then one
|
||||
// bin (see BinRuns::single).
|
||||
bool binRunsFor(AstCoverBin* binp, AstNodeExpr* exprp, BinRuns& out) {
|
||||
if (isAutoBins(binp)) {
|
||||
if (!autoBinRuns(binp, exprp, out)) out.unsupported = true;
|
||||
return true;
|
||||
}
|
||||
if (binp->isArray() && binp->isWildcard()) {
|
||||
if (!exprp->dtypep()->skipRefp()->isIntegralOrPacked()) {
|
||||
AstNodeExpr* const falsep = wildcardTypeError(binp, exprp);
|
||||
VL_DO_DANGLING(pushDeletep(falsep), falsep);
|
||||
out.unsupported = true;
|
||||
} else {
|
||||
out = wildcardBinRuns(binp, exprp, true);
|
||||
if (out.single) {
|
||||
binp->isArray(false); // Generates as one bin
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (!binp->isArray() || binp->transp() || binp->isWildcard()
|
||||
|| !exprp->dtypep()->skipRefp()->isIntegralOrPacked()) {
|
||||
return false;
|
||||
@@ -1257,9 +1426,10 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
}
|
||||
|
||||
// Emit a 'this->m_cp->addSingleNamer/addArrayNamer(...)' statement for one bin whose first
|
||||
// runtime bin index is 'declared'
|
||||
// runtime bin index is 'declared'; or with 'valueNames', those naming each bin of an array
|
||||
AstNodeStmt* makeNamer(AstVar* cpVarp, AstCoverBin* binp, int64_t count, uint32_t declared,
|
||||
const std::vector<AstNodeExpr*>& values = {}) {
|
||||
const std::vector<AstNodeExpr*>& values = {},
|
||||
const std::vector<std::string>& valueNames = {}) {
|
||||
FileLine* const fl = binp->fileline();
|
||||
CoverpointBins& bins = m_cpBins.at(cpVarp);
|
||||
const uint32_t normalCount
|
||||
@@ -1279,6 +1449,23 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
// unit filename, per-word bin name). A no-op when --protect-ids is off.
|
||||
const bool prot = v3Global.opt.protectIds();
|
||||
const bool single = count < 0;
|
||||
if (!valueNames.empty()) {
|
||||
// A bin of a wildcard array is named by its value (IEEE 1800-2023 19.5.1)
|
||||
AstNodeStmt* stmtsp = nullptr;
|
||||
for (const std::string& value : valueNames) {
|
||||
const std::string name
|
||||
= VIdProtect::protectWordsIf(binp->name(), prot) + "[" + value + "]";
|
||||
stmtsp = AstNode::addNext(
|
||||
stmtsp,
|
||||
itemCall(fl, cpVarp, VCMethod::COVERGROUP_ADD_SINGLE_NAMER,
|
||||
{ctext(fl, binp->binsType().binSetEnum()), ctext(fl, quoted(name)),
|
||||
ctext(fl, quoted(VIdProtect::protectIf(fl->filename(), prot))),
|
||||
cnum(fl, static_cast<uint32_t>(fl->lineno())),
|
||||
cnum(fl, static_cast<uint32_t>(fl->firstColumn()))})
|
||||
->makeStmt());
|
||||
}
|
||||
return stmtsp;
|
||||
}
|
||||
std::vector<AstNodeExpr*> args{ctext(fl, binp->binsType().binSetEnum())};
|
||||
if (!single) args.push_back(cnum(fl, static_cast<uint32_t>(count))); // value array bin
|
||||
args.push_back(ctext(fl, quoted(VIdProtect::protectWordsIf(binp->name(), prot))));
|
||||
@@ -1416,7 +1603,8 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
"(IEEE 1800-2023 6.20.7)");
|
||||
continue;
|
||||
}
|
||||
generateSizedElement(cpVarp, rangep, exprp, prefix + "_" + cvtToStr(element++));
|
||||
generateSizedElement(cpVarp, rangep, exprp, binp->isWildcard(),
|
||||
prefix + "_" + cvtToStr(element++));
|
||||
}
|
||||
const auto countRef = [&]() { return new AstVarRef{fl, countp, VAccess::READ}; };
|
||||
AstConst* const zerop = new AstConst{fl, AstConst::DTyped{}, countp->dtypep()};
|
||||
@@ -1438,7 +1626,7 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
m_constructorp->addStmtsp(
|
||||
itemCall(fl, cpVarp, VCMethod::COVERGROUP_SIZED_FINISH,
|
||||
{ctext(fl, binp->binsType().binSetEnum()), countValuep, positivep,
|
||||
cnum(fl, binsLimit()),
|
||||
cnum(fl, v3Global.opt.coverageMaxBins()),
|
||||
ctext(fl, quoted(VIdProtect::protectWordsIf(binp->name(), prot))),
|
||||
ctext(fl, quoted(VIdProtect::protectIf(fl->filename(), prot))),
|
||||
cnum(fl, static_cast<uint32_t>(fl->lineno())),
|
||||
@@ -1448,8 +1636,9 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
|
||||
// Emit 'sizedRange(lo, hi)' for the coverpoint values of an element of a sized array of
|
||||
// bins: resolved now if constant, else when constructed by clipping to the coverpoint's
|
||||
// values. 'prefix' names its temporaries.
|
||||
void generateSizedElement(AstVar* cpVarp, AstNode* rangep, AstNodeExpr* exprp,
|
||||
// values. A 'wildcard' pattern's values give a range for each run of them. 'prefix' names
|
||||
// its temporaries.
|
||||
void generateSizedElement(AstVar* cpVarp, AstNode* rangep, AstNodeExpr* exprp, bool wildcard,
|
||||
const string& prefix) {
|
||||
FileLine* const fl = rangep->fileline();
|
||||
const VCMethod method = exprp->isWide() ? VCMethod::COVERGROUP_SIZED_RANGE_W
|
||||
@@ -1475,14 +1664,21 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
return;
|
||||
}
|
||||
CrossValueRange range{rangep, resolveWidth(rangep, exprp)};
|
||||
if (!resolveValue(rangep, exprp, true, false, range)) {
|
||||
if (!resolveValue(rangep, exprp, true, wildcard, range)) {
|
||||
rangep->v3warn(E_UNSUPPORTED, "Unsupported: non-integral value in a coverage bin "
|
||||
"of an integral coverpoint.");
|
||||
} else if (!crossRangeEmpty(range)) {
|
||||
m_constructorp->addStmtsp(itemCall(fl, cpVarp, method,
|
||||
{newValueConst(fl, range.lo, exprp),
|
||||
newValueConst(fl, range.hi, exprp)})
|
||||
->makeStmt());
|
||||
std::vector<std::pair<V3Number, V3Number>> runs{{range.lo, range.hi}};
|
||||
if (range.wildcard) { // checkSizedArrays bounded the runs
|
||||
runs.clear();
|
||||
crossRangeRuns(range, v3Global.opt.coverageMaxBins(), runs);
|
||||
}
|
||||
for (const std::pair<V3Number, V3Number>& run : runs) {
|
||||
m_constructorp->addStmtsp(itemCall(fl, cpVarp, method,
|
||||
{newValueConst(fl, run.first, exprp),
|
||||
newValueConst(fl, run.second, exprp)})
|
||||
->makeStmt());
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1718,7 +1914,8 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
CoverpointBins& bins = m_cpBins.at(cpVarp);
|
||||
const uint32_t firstValue = bins.total;
|
||||
const uint32_t firstDeclared = static_cast<uint32_t>(idx);
|
||||
namerStmts.push_back(makeNamer(cpVarp, cbinp, plan.count, firstDeclared));
|
||||
namerStmts.push_back(
|
||||
makeNamer(cpVarp, cbinp, plan.count, firstDeclared, {}, plan.values));
|
||||
for (BinRun& run : plan.runs) {
|
||||
run.m_declared = static_cast<uint32_t>(idx);
|
||||
bins.runs.push_back(std::move(run));
|
||||
@@ -2502,6 +2699,59 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
return states != 0;
|
||||
}
|
||||
|
||||
// The least value at least 'from' with the non-x bits of 'pattern', in unsigned order; false
|
||||
// if none. A bit scan, which does not enumerate the pattern's x bits.
|
||||
static bool nextPatternValue(const V3Number& pattern, const V3Number& from, V3Number& result) {
|
||||
result.opAssign(from);
|
||||
int carry = -1; // Lowest x bit above the bit scanned where 'from' has a 0
|
||||
for (int bit = from.width() - 1; bit >= 0; --bit) {
|
||||
if (pattern.bitIsXZ(bit)) {
|
||||
if (!from.bitIs1(bit)) carry = bit;
|
||||
continue;
|
||||
}
|
||||
if (pattern.bitIs1(bit) == from.bitIs1(bit)) continue;
|
||||
if (from.bitIs1(bit)) { // Only a greater prefix, an x bit above raised, can match
|
||||
if (carry < 0) return false;
|
||||
bit = carry;
|
||||
}
|
||||
// Then the least such value: the pattern's bits, with x bits of zero
|
||||
result.setBit(bit, 1);
|
||||
while (--bit >= 0) result.setBit(bit, pattern.bitIs1(bit));
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Append to 'runs' the maximal runs of consecutive values of 'range' that its pattern
|
||||
// matches, in value order, until there are more than 'limit'. A match continues through
|
||||
// the pattern's trailing x bits only, which the next value's carry leaves.
|
||||
static void crossRangeRuns(const CrossValueRange& range, size_t limit,
|
||||
std::vector<std::pair<V3Number, V3Number>>& runs) {
|
||||
// Values order signed, which is the unsigned order of values with the sign bit flipped
|
||||
const int sign = range.lo.width() - 1;
|
||||
const auto flipped = [sign](V3Number value) {
|
||||
if (!value.bitIsXZ(sign)) value.setBit(sign, !value.bitIs1(sign));
|
||||
return value;
|
||||
};
|
||||
const V3Number pattern = flipped(range.pattern);
|
||||
const V3Number hi = flipped(range.hi);
|
||||
const V3Number one{&hi, hi.width(), 1};
|
||||
V3Number trailing{&hi, hi.width()};
|
||||
for (int bit = 0; bit <= sign && pattern.bitIsXZ(bit); ++bit) trailing.setBit(bit, 1);
|
||||
V3Number from = flipped(range.lo);
|
||||
V3Number first{&hi, hi.width()};
|
||||
V3Number last{&hi, hi.width()};
|
||||
V3Number less{&hi};
|
||||
while (runs.size() <= limit && nextPatternValue(pattern, from, first)
|
||||
&& less.opLt(hi, first).isEqZero()) {
|
||||
last.opOr(first, trailing);
|
||||
if (!less.opLt(hi, last).isEqZero()) last = hi;
|
||||
runs.emplace_back(flipped(first), flipped(last));
|
||||
if (last.isCaseEq(hi)) break;
|
||||
from.opAdd(last, one);
|
||||
}
|
||||
}
|
||||
|
||||
// True if no coverpoint value participates in a resolved value or range. A value with x
|
||||
// or z bits participates only as a wildcard pattern (IEEE 1800-2023 19.5.7).
|
||||
static bool crossRangeEmpty(const CrossValueRange& range) {
|
||||
|
||||
+2
-5
@@ -343,11 +343,8 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
|
||||
emitCoverageOption(nodep, nodep->typeOption(), nodep->optType(), nodep->valuep());
|
||||
}
|
||||
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;
|
||||
}
|
||||
putfs(nodep, std::string{nodep->isWildcard() ? "wildcard " : ""}
|
||||
+ nodep->binsType().verilogKwd() + " ");
|
||||
puts(nodep->name());
|
||||
if (nodep->isArray()) {
|
||||
puts("[");
|
||||
|
||||
+3
-3
@@ -7207,11 +7207,11 @@ bins_or_options<nodep>: // ==IEEE: bins_or_options
|
||||
| yILLEGAL_BINS idAny/*bin_identifier*/ bins_orBraE '=' id/*cover_point_id*/ yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = nullptr; GRAMMARP->coverBinArrayUnsized($3); BBCOVERIGN($<fl>6, "Unsupported: 'with' in cover bin"); DEL($8, $10); }
|
||||
| yWILDCARD yBINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' iffE
|
||||
{ GRAMMARP->coverBinArrayUnsized($4); $$ = new AstCoverBin{$<fl>3, *$3, $7, false, false, true, $9}; }
|
||||
{ $$ = GRAMMARP->coverBinArray(new AstCoverBin{$<fl>3, *$3, $7, false, false, true, $9}, $4); }
|
||||
| yWILDCARD yIGNORE_BINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' iffE
|
||||
{ GRAMMARP->coverBinArrayUnsized($4); $$ = new AstCoverBin{$<fl>3, *$3, $7, true, false, true, $9}; }
|
||||
{ $$ = GRAMMARP->coverBinArray(new AstCoverBin{$<fl>3, *$3, $7, true, false, true, $9}, $4); }
|
||||
| yWILDCARD yILLEGAL_BINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' iffE
|
||||
{ GRAMMARP->coverBinArrayUnsized($4); $$ = new AstCoverBin{$<fl>3, *$3, $7, false, true, true, $9}; }
|
||||
{ $$ = GRAMMARP->coverBinArray(new AstCoverBin{$<fl>3, *$3, $7, false, true, true, $9}, $4); }
|
||||
| yWILDCARD yBINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = nullptr; GRAMMARP->coverBinArrayUnsized($4); 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
|
||||
|
||||
@@ -238,4 +238,12 @@
|
||||
: ... Suggest a larger --coverage-max-real-bins
|
||||
257 | bins over_limit[] = {[0 : 1024]};
|
||||
| ^~~~~~~~~~
|
||||
%Error: t/t_covergroup_autobins_bad.v:264:21: Non-constant expression in array bins value list; values must be constants (IEEE 1800-2023 19.5)
|
||||
: ... note: In instance 't'
|
||||
264 | wildcard bins value[] = {size_var};
|
||||
| ^~~~~
|
||||
%Error: t/t_covergroup_autobins_bad.v:265:21: Non-constant expression in array bins range; range bounds must be constants (IEEE 1800-2023 19.5)
|
||||
: ... note: In instance 't'
|
||||
265 | wildcard bins range[] = {[0 : size_var]};
|
||||
| ^~~~~
|
||||
%Error: Exiting due to
|
||||
|
||||
@@ -258,6 +258,16 @@ module t;
|
||||
}
|
||||
endgroup
|
||||
|
||||
// Error: non-constant values of wildcard arrays of bins, also of a crossed coverpoint
|
||||
covergroup cg_wild_nonconst;
|
||||
cp_a: coverpoint cp_expr {
|
||||
wildcard bins value[] = {size_var};
|
||||
wildcard bins range[] = {[0 : size_var]};
|
||||
}
|
||||
cp_c: coverpoint cp_expr {bins r = {0}; bins w = {1};}
|
||||
xc: cross cp_a, cp_c;
|
||||
endgroup
|
||||
|
||||
cg1 cg1_inst = new;
|
||||
cg2 cg2_inst = new;
|
||||
cg2b cg2b_inst = new;
|
||||
@@ -280,6 +290,7 @@ module t;
|
||||
cgx_binsof_many_values cgx_binsof_many_values_inst = new;
|
||||
cg_limit cg_limit_inst = new;
|
||||
cg_real cg_real_inst = new;
|
||||
cg_wild_nonconst cg_wild_nonconst_inst = new;
|
||||
|
||||
initial $finish;
|
||||
endmodule
|
||||
|
||||
@@ -193,11 +193,14 @@ cg_wide.wd.hi_x_read [cross]: 1
|
||||
cg_wide.wd.hi_x_write [cross]: 1
|
||||
cg_wide.wd.lo_x_read [cross]: 1
|
||||
cg_wide.wd.lo_x_write [cross]: 1
|
||||
cg_wild_arr.cp_addr.wb: 4
|
||||
cg_wild_arr.cp_addr.wb[0]: 2
|
||||
cg_wild_arr.cp_addr.wb[1]: 2
|
||||
cg_wild_arr.cp_cmd.read: 2
|
||||
cg_wild_arr.cp_cmd.write: 2
|
||||
cg_wild_arr.wa.wb_x_read [cross]: 2
|
||||
cg_wild_arr.wa.wb_x_write [cross]: 2
|
||||
cg_wild_arr.wa.wb[0]_x_read [cross]: 1
|
||||
cg_wild_arr.wa.wb[0]_x_write [cross]: 1
|
||||
cg_wild_arr.wa.wb[1]_x_read [cross]: 1
|
||||
cg_wild_arr.wa.wb[1]_x_write [cross]: 1
|
||||
cg_wild_solo.cp_addr.wb: 2
|
||||
cg_wild_solo.cp_cmd.read: 1
|
||||
cg_wild_solo.cp_cmd.write: 1
|
||||
|
||||
@@ -1,40 +1,54 @@
|
||||
%Error-UNSUPPORTED: t/t_covergroup_exclusions_unsup.v:14:20: Unsupported: non-integral value in a coverage bin of an integral coverpoint.
|
||||
%Error-UNSUPPORTED: t/t_covergroup_exclusions_unsup.v:15:20: Unsupported: non-integral value in a coverage bin of an integral coverpoint.
|
||||
: ... note: In instance 't'
|
||||
14 | bins text = {TEXT};
|
||||
15 | bins text = {TEXT};
|
||||
| ^~~~
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error-UNSUPPORTED: t/t_covergroup_exclusions_unsup.v:15:28: Unsupported: non-integral value in a coverage bin of an integral coverpoint.
|
||||
%Error-UNSUPPORTED: t/t_covergroup_exclusions_unsup.v:16:28: Unsupported: non-integral value in a coverage bin of an integral coverpoint.
|
||||
: ... note: In instance 't'
|
||||
15 | bins text_array[] = {TEXT};
|
||||
16 | bins text_array[] = {TEXT};
|
||||
| ^~~~
|
||||
%Error-UNSUPPORTED: t/t_covergroup_exclusions_unsup.v:16:29: Unsupported: non-integral value in a coverage bin of an integral coverpoint.
|
||||
%Error-UNSUPPORTED: t/t_covergroup_exclusions_unsup.v:18:36: Unsupported: non-integral value in a coverage bin of an integral coverpoint.
|
||||
: ... note: In instance 't'
|
||||
16 | bins text_sized[2] = {TEXT};
|
||||
18 | wildcard bins text_wild[] = {TEXT};
|
||||
| ^~~~
|
||||
%Error-UNSUPPORTED: t/t_covergroup_exclusions_unsup.v:17:29: Unsupported: non-integral value in a coverage bin of an integral coverpoint.
|
||||
: ... note: In instance 't'
|
||||
17 | bins text_sized[2] = {TEXT};
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_exclusions_unsup.v:28:12: Unsupported: 'bins' explicit array size of a real coverpoint (treated as '[]')
|
||||
%Warning-COVERIGN: t/t_covergroup_exclusions_unsup.v:30:12: Unsupported: 'bins' explicit array size of a real coverpoint (treated as '[]')
|
||||
: ... note: In instance 't'
|
||||
28 | bins sized[2] = {1.0, 2.0};
|
||||
30 | bins sized[2] = {1.0, 2.0};
|
||||
| ^~~~~
|
||||
... 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-UNSUPPORTED: t/t_covergroup_exclusions_unsup.v:25:29: Unsupported: non-integral value in a coverage bin of an integral coverpoint.
|
||||
%Error-UNSUPPORTED: t/t_covergroup_exclusions_unsup.v:27:29: Unsupported: non-integral value in a coverage bin of an integral coverpoint.
|
||||
: ... note: In instance 't'
|
||||
25 | bins real_bound[2] = {[lo : 5]};
|
||||
27 | bins real_bound[2] = {[lo : 5]};
|
||||
| ^
|
||||
%Error-UNSUPPORTED: t/t_covergroup_exclusions_unsup.v:34:29: Unsupported: non-integral value in a coverage bin of an integral coverpoint.
|
||||
%Warning-COVERIGN: t/t_covergroup_exclusions_unsup.v:37:21: Unsupported: sized wildcard array 'bins' of more than --coverage-max-bins of 1024 ranges of values; bin ignored
|
||||
: ... note: In instance 't'
|
||||
: ... Suggest a larger --coverage-max-bins
|
||||
37 | wildcard bins runs[2] = {16'b????_????_????_???1};
|
||||
| ^~~~
|
||||
%Error-UNSUPPORTED: t/t_covergroup_exclusions_unsup.v:43:29: Unsupported: non-integral value in a coverage bin of an integral coverpoint.
|
||||
: ... note: In instance 't'
|
||||
34 | wildcard bins text = {TEXT};
|
||||
43 | wildcard bins text = {TEXT};
|
||||
| ^~~~
|
||||
%Error-UNSUPPORTED: t/t_covergroup_exclusions_unsup.v:40:25: Unsupported: non-integral value in a transition bin of a coverpoint with exclusions.
|
||||
%Error-UNSUPPORTED: t/t_covergroup_exclusions_unsup.v:49:25: Unsupported: non-integral value in a transition bin of a coverpoint with exclusions.
|
||||
: ... note: In instance 't'
|
||||
40 | bins text = (1 => TEXT);
|
||||
49 | bins text = (1 => TEXT);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_exclusions_unsup.v:53:59: Unsupported: non-constant or non-integral 'intersect' value, or four-state range bound.
|
||||
%Warning-COVERIGN: t/t_covergroup_exclusions_unsup.v:62:59: Unsupported: non-constant or non-integral 'intersect' value, or four-state range bound.
|
||||
: ... note: In instance 't'
|
||||
53 | static_cross: cross cp_real, cp_plain{bins selected = binsof (cp_real) intersect {1};}
|
||||
62 | static_cross: cross cp_real, cp_plain{bins selected = binsof (cp_real) intersect {1};}
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_exclusions_unsup.v:54:62: Unsupported: non-constant or non-integral 'intersect' value, or four-state range bound.
|
||||
%Warning-COVERIGN: t/t_covergroup_exclusions_unsup.v:63:62: Unsupported: non-constant or non-integral 'intersect' value, or four-state range bound.
|
||||
: ... note: In instance 't'
|
||||
54 | dynamic_cross: cross cp_real, cp_dynamic{bins selected = binsof (cp_real) intersect {1};}
|
||||
63 | dynamic_cross: cross cp_real, cp_dynamic{bins selected = binsof (cp_real) intersect {1};}
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_exclusions_unsup.v:69:29: Unsupported: sized wildcard array 'illegal_bins' of more than --coverage-max-bins of 1024 ranges of values; treated as one bin
|
||||
: ... note: In instance 't'
|
||||
: ... Suggest a larger --coverage-max-bins
|
||||
69 | wildcard illegal_bins runs[2] = {16'b????_????_????_???1};
|
||||
| ^~~~
|
||||
%Error: Exiting due to
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
module t;
|
||||
bit [3:0] value;
|
||||
bit [15:0] wide_value;
|
||||
real real_value;
|
||||
localparam string TEXT = "a";
|
||||
|
||||
@@ -14,6 +15,7 @@ module t;
|
||||
bins text = {TEXT};
|
||||
bins text_array[] = {TEXT};
|
||||
bins text_sized[2] = {TEXT};
|
||||
wildcard bins text_wild[] = {TEXT};
|
||||
ignore_bins ignored = {0};
|
||||
}
|
||||
endgroup
|
||||
@@ -29,6 +31,13 @@ module t;
|
||||
}
|
||||
endgroup
|
||||
|
||||
// A sized wildcard array whose pattern holds more ranges of values than --coverage-max-bins
|
||||
covergroup cg_wild_runs;
|
||||
cp: coverpoint wide_value {
|
||||
wildcard bins runs[2] = {16'b????_????_????_???1};
|
||||
}
|
||||
endgroup
|
||||
|
||||
covergroup cg_wild;
|
||||
cp: coverpoint value {
|
||||
wildcard bins text = {TEXT};
|
||||
@@ -54,11 +63,20 @@ module t;
|
||||
dynamic_cross: cross cp_real, cp_dynamic{bins selected = binsof (cp_real) intersect {1};}
|
||||
endgroup
|
||||
|
||||
// A sized wildcard illegal array of as many ranges of values, treated as one bin
|
||||
covergroup cg_wild_runs_illegal;
|
||||
cp: coverpoint wide_value {
|
||||
wildcard illegal_bins runs[2] = {16'b????_????_????_???1};
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg_values values_cov = new;
|
||||
cg_sized sized_cov = new(1.0);
|
||||
cg_wild_runs wild_runs_cov = new;
|
||||
cg_wild wild_cov = new;
|
||||
cg_transition transition_cov = new;
|
||||
cg_cross cross_cov = new;
|
||||
cg_wild_runs_illegal wild_runs_illegal_cov = new;
|
||||
|
||||
initial $finish;
|
||||
endmodule
|
||||
|
||||
@@ -5,20 +5,30 @@
|
||||
| ^~~~~~~~~~
|
||||
... 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_max_bins_unsup.v:21:12: Automatic bins array size of 4294967296 exceeds limit of 4294967295
|
||||
%Warning-COVERIGN: t/t_covergroup_max_bins_unsup.v:21:21: Unsupported: wildcard array 'bins' of more than --coverage-max-bins of 4294967295 values; bin ignored
|
||||
: ... note: In instance 't'
|
||||
: ... Suggest a larger --coverage-max-bins
|
||||
21 | wildcard bins over_limit[] = {32'h????_????};
|
||||
| ^~~~~~~~~~
|
||||
%Error: t/t_covergroup_max_bins_unsup.v:25:12: Automatic bins array size of 4294967296 exceeds limit of 4294967295
|
||||
: ... note: In instance 't'
|
||||
: ... Suggest a larger --coverage-max-bins
|
||||
21 | bins auto[33'd4294967296];
|
||||
25 | bins auto[33'd4294967296];
|
||||
| ^~~~
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
%Error-UNSUPPORTED: t/t_covergroup_max_bins_unsup.v:24:15: Unsupported: coverpoint with more than 4294967295 bins
|
||||
%Error-UNSUPPORTED: t/t_covergroup_max_bins_unsup.v:28:15: Unsupported: coverpoint with more than 4294967295 bins
|
||||
: ... note: In instance 't'
|
||||
24 | cp_total: coverpoint data {
|
||||
28 | cp_total: coverpoint data {
|
||||
| ^~~~~~~~~~
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Warning-COVERIGN: t/t_covergroup_max_bins_unsup.v:30:12: Unsupported: array 'bins' of a real coverpoint covering more than 2 values; bin ignored.
|
||||
%Warning-COVERIGN: t/t_covergroup_max_bins_unsup.v:34:12: Unsupported: array 'bins' of a real coverpoint covering more than 2 values; bin ignored.
|
||||
: ... note: In instance 't'
|
||||
: ... Suggest a larger --coverage-max-real-bins
|
||||
30 | bins over_limit[] = {[1 : 3]};
|
||||
34 | bins over_limit[] = {[1 : 3]};
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_max_bins_unsup.v:38:28: Unsupported: wildcard array 'ignore_bins' of more than --coverage-max-bins of 4294967295 values; treated as one bin
|
||||
: ... note: In instance 't'
|
||||
: ... Suggest a larger --coverage-max-bins
|
||||
38 | wildcard ignore_bins over_limit[] = {32'h????_????};
|
||||
| ^~~~~~~~~~
|
||||
%Error: Exiting due to
|
||||
|
||||
@@ -16,6 +16,10 @@ module t;
|
||||
cp_array_over: coverpoint data {
|
||||
bins over_limit[] = {[0 : $]};
|
||||
}
|
||||
// Warning (COVERIGN): a wildcard array of more values than the limit
|
||||
cp_wild_over: coverpoint data {
|
||||
wildcard bins over_limit[] = {32'h????_????};
|
||||
}
|
||||
// Error: automatic bins over the limit
|
||||
cp_auto_over: coverpoint data {
|
||||
bins auto[33'd4294967296];
|
||||
@@ -29,6 +33,10 @@ module t;
|
||||
bins at_limit[] = {[1 : 2]};
|
||||
bins over_limit[] = {[1 : 3]}; // Warning (COVERIGN): 3 values
|
||||
}
|
||||
// Warning (COVERIGN): a wildcard ignore array of more values than the limit, as one bin
|
||||
cp_wild_ignore: coverpoint data {
|
||||
wildcard ignore_bins over_limit[] = {32'h????_????};
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg cg_inst = new;
|
||||
|
||||
@@ -20,4 +20,11 @@
|
||||
t/t_covergroup_wild_real_bad.v:18:21: ... Location of wildcard bin
|
||||
18 | wildcard bins open = {[1 : $]};
|
||||
| ^~~~
|
||||
%Error: t/t_covergroup_wild_real_bad.v:20:15: Cannot use a wildcard bin on a coverpoint of type 'real' (IEEE 1800-2023 19.5.4).
|
||||
: ... note: In instance 't'
|
||||
20 | cp_array: coverpoint value {
|
||||
| ^~~~~~~~~~
|
||||
t/t_covergroup_wild_real_bad.v:21:21: ... Location of wildcard bin
|
||||
21 | wildcard bins array[] = {1};
|
||||
| ^~~~~
|
||||
%Error: Exiting due to
|
||||
|
||||
@@ -17,6 +17,9 @@ module t;
|
||||
cp_open: coverpoint value {
|
||||
wildcard bins open = {[1 : $]};
|
||||
}
|
||||
cp_array: coverpoint value {
|
||||
wildcard bins array[] = {1};
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg cov = new;
|
||||
|
||||
@@ -3,3 +3,144 @@ cg.data.low: 2
|
||||
cg.data.mid_range: 1
|
||||
cg.data.pattern: 2
|
||||
cg.data.wc_point: 2
|
||||
cg_arrays.dups.b[11]: 4
|
||||
cg_arrays.dups.b[12]: 4
|
||||
cg_arrays.dups.b[13]: 4
|
||||
cg_arrays.dups.b[14]: 4
|
||||
cg_arrays.dups.b[15]: 4
|
||||
cg_arrays.excl.b[2]: 8
|
||||
cg_arrays.excl.b[3]: 8
|
||||
cg_arrays.excl.i[0] [ignore]: 12
|
||||
cg_arrays.excl.i[1] [ignore]: 12
|
||||
cg_arrays.excl.l[7] [illegal]: 0
|
||||
cg_arrays.excl.others [default]: 24
|
||||
cg_arrays.gaps.b[12]: 4
|
||||
cg_arrays.gaps.b[13]: 4
|
||||
cg_arrays.gaps.b[8]: 4
|
||||
cg_arrays.gaps.b[9]: 4
|
||||
cg_arrays.gated.b[12]: 1
|
||||
cg_arrays.gated.b[14]: 1
|
||||
cg_arrays.ieee.g12_15_array[12]: 4
|
||||
cg_arrays.ieee.g12_15_array[13]: 4
|
||||
cg_arrays.ieee.g12_15_array[14]: 4
|
||||
cg_arrays.ieee.g12_15_array[15]: 4
|
||||
cg_arrays.mixed.b[0]: 4
|
||||
cg_arrays.mixed.b[1]: 4
|
||||
cg_arrays.mixed.b[5]: 4
|
||||
cg_arrays.mixed.b[8]: 4
|
||||
cg_arrays.mixed.b[9]: 4
|
||||
cg_arrays.nonzero.b[2]: 16
|
||||
cg_arrays.nonzero.b[3]: 16
|
||||
cg_arrays.sgn.cast[-1]: 4
|
||||
cg_arrays.sgn.cast[-2]: 4
|
||||
cg_arrays.sgn.cast[-3]: 4
|
||||
cg_arrays.sgn.cast[-4]: 4
|
||||
cg_arrays.sgn.cast[-5]: 4
|
||||
cg_arrays.sgn.cast[-6]: 4
|
||||
cg_arrays.sgn.cast[-7]: 4
|
||||
cg_arrays.sgn.cast[-8]: 4
|
||||
cg_arrays.sgn.ext[-1]: 4
|
||||
cg_arrays.sgn.ext[-2]: 4
|
||||
cg_arrays.sgn.ext[-3]: 4
|
||||
cg_arrays.sgn.ext[-4]: 4
|
||||
cg_arrays.sgn2.b[-1]: 16
|
||||
cg_arrays.sgn2.b[1]: 16
|
||||
cg_arrays.split.b[1]: 12
|
||||
cg_arrays.split.b[5]: 8
|
||||
cg_arrays.split.i[0] [ignore]: 12
|
||||
cg_arrays.split.i[4] [ignore]: 8
|
||||
cg_arrays.wide.keep[12]: 4
|
||||
cg_arrays.wide.keep[13]: 4
|
||||
cg_arrays.wide.keep[14]: 4
|
||||
cg_arrays.wide.keep[15]: 4
|
||||
cg_arrays.wide.keep[1]: 4
|
||||
cg_arrays.wide100.b[16]: 4
|
||||
cg_arrays.wide100.b[17]: 4
|
||||
cg_arrays.wide100.b[18]: 4
|
||||
cg_arrays.wide100.b[19]: 4
|
||||
cg_arrays.wide100.b[20]: 4
|
||||
cg_arrays.wide100.b[21]: 4
|
||||
cg_arrays.wide100.b[22]: 4
|
||||
cg_arrays.wide100.b[23]: 4
|
||||
cg_arrays.wide100.b[24]: 4
|
||||
cg_arrays.wide100.b[25]: 4
|
||||
cg_arrays.wide100.b[26]: 4
|
||||
cg_arrays.wide100.b[27]: 4
|
||||
cg_arrays.wide100.b[28]: 4
|
||||
cg_arrays.wide100.b[29]: 4
|
||||
cg_arrays.wide100.b[30]: 4
|
||||
cg_arrays.wide100.b[31]: 4
|
||||
cg_arrays.wide100.f[24]: 4
|
||||
cg_arrays.wide100.f[25]: 4
|
||||
cg_arrays.wide100.f[28]: 4
|
||||
cg_arrays.wide100.f[29]: 4
|
||||
cg_arrays.ww.b[2]_x_b[16] [cross]: 1
|
||||
cg_arrays.ww.b[2]_x_b[17] [cross]: 1
|
||||
cg_arrays.ww.b[2]_x_b[18] [cross]: 1
|
||||
cg_arrays.ww.b[2]_x_b[19] [cross]: 1
|
||||
cg_arrays.ww.b[2]_x_b[20] [cross]: 1
|
||||
cg_arrays.ww.b[2]_x_b[21] [cross]: 1
|
||||
cg_arrays.ww.b[2]_x_b[22] [cross]: 1
|
||||
cg_arrays.ww.b[2]_x_b[23] [cross]: 1
|
||||
cg_arrays.ww.b[2]_x_b[24] [cross]: 1
|
||||
cg_arrays.ww.b[2]_x_b[25] [cross]: 1
|
||||
cg_arrays.ww.b[2]_x_b[26] [cross]: 1
|
||||
cg_arrays.ww.b[2]_x_b[27] [cross]: 1
|
||||
cg_arrays.ww.b[2]_x_b[28] [cross]: 1
|
||||
cg_arrays.ww.b[2]_x_b[29] [cross]: 1
|
||||
cg_arrays.ww.b[2]_x_b[30] [cross]: 1
|
||||
cg_arrays.ww.b[2]_x_b[31] [cross]: 1
|
||||
cg_arrays.ww.b[2]_x_f[24] [cross]: 1
|
||||
cg_arrays.ww.b[2]_x_f[25] [cross]: 1
|
||||
cg_arrays.ww.b[2]_x_f[28] [cross]: 1
|
||||
cg_arrays.ww.b[2]_x_f[29] [cross]: 1
|
||||
cg_arrays.ww.b[3]_x_b[16] [cross]: 1
|
||||
cg_arrays.ww.b[3]_x_b[17] [cross]: 1
|
||||
cg_arrays.ww.b[3]_x_b[18] [cross]: 1
|
||||
cg_arrays.ww.b[3]_x_b[19] [cross]: 1
|
||||
cg_arrays.ww.b[3]_x_b[20] [cross]: 1
|
||||
cg_arrays.ww.b[3]_x_b[21] [cross]: 1
|
||||
cg_arrays.ww.b[3]_x_b[22] [cross]: 1
|
||||
cg_arrays.ww.b[3]_x_b[23] [cross]: 1
|
||||
cg_arrays.ww.b[3]_x_b[24] [cross]: 1
|
||||
cg_arrays.ww.b[3]_x_b[25] [cross]: 1
|
||||
cg_arrays.ww.b[3]_x_b[26] [cross]: 1
|
||||
cg_arrays.ww.b[3]_x_b[27] [cross]: 1
|
||||
cg_arrays.ww.b[3]_x_b[28] [cross]: 1
|
||||
cg_arrays.ww.b[3]_x_b[29] [cross]: 1
|
||||
cg_arrays.ww.b[3]_x_b[30] [cross]: 1
|
||||
cg_arrays.ww.b[3]_x_b[31] [cross]: 1
|
||||
cg_arrays.ww.b[3]_x_f[24] [cross]: 1
|
||||
cg_arrays.ww.b[3]_x_f[25] [cross]: 1
|
||||
cg_arrays.ww.b[3]_x_f[28] [cross]: 1
|
||||
cg_arrays.ww.b[3]_x_f[29] [cross]: 1
|
||||
cg_arrays.xx.b[2]_x_b[12] [cross]: 1
|
||||
cg_arrays.xx.b[2]_x_b[13] [cross]: 1
|
||||
cg_arrays.xx.b[3]_x_b[12] [cross]: 1
|
||||
cg_arrays.xx.b[3]_x_b[13] [cross]: 1
|
||||
cg_arrays.xx.sel [cross]: 4
|
||||
cg_s64.neg.b[-1]: 1
|
||||
cg_s64.neg.b[-3]: 1
|
||||
cg_s64.nx.b[-1]_x_b [cross]: 1
|
||||
cg_s64.nx.b[-3]_x_b [cross]: 1
|
||||
cg_s64.three.b: 18
|
||||
cg_s64.top.b[-1152921504606846978]: 1
|
||||
cg_s64.top.b[-2305843009213693954]: 1
|
||||
cg_s64.top.b[-2]: 1
|
||||
cg_s64.top.b[-3458764513820540930]: 1
|
||||
cg_s64.top.b[-4611686018427387906]: 1
|
||||
cg_s64.top.b[-5764607523034234882]: 1
|
||||
cg_s64.top.b[-6917529027641081858]: 1
|
||||
cg_s64.top.b[-8070450532247928834]: 1
|
||||
cg_s64.top.b[1152921504606846974]: 1
|
||||
cg_s64.top.b[2305843009213693950]: 1
|
||||
cg_s64.top.b[3458764513820540926]: 1
|
||||
cg_s64.top.b[4611686018427387902]: 1
|
||||
cg_s64.top.b[5764607523034234878]: 1
|
||||
cg_s64.top.b[6917529027641081854]: 1
|
||||
cg_s64.top.b[8070450532247928830]: 1
|
||||
cg_s64.top.b[9223372036854775806]: 1
|
||||
cg_sized.d.b[0]: 1
|
||||
cg_sized.d.b[1]: 1
|
||||
cg_sized.s.b[0]: 1
|
||||
cg_sized.s.b[1]: 1
|
||||
|
||||
@@ -13,6 +13,13 @@
|
||||
|
||||
module t;
|
||||
bit [7:0] data;
|
||||
bit [3:0] v;
|
||||
bit [1:0] v2;
|
||||
bit signed [3:0] sv;
|
||||
bit signed [1:0] sv2;
|
||||
bit [2:0] u;
|
||||
bit [99:0] w;
|
||||
longint l;
|
||||
|
||||
covergroup cg;
|
||||
coverpoint data {
|
||||
@@ -33,6 +40,102 @@ module t;
|
||||
}
|
||||
endgroup
|
||||
|
||||
// Wildcard arrays: a bin for each value a pattern matches, named by the value (IEEE 1800-2023
|
||||
// 19.5.4, 19.5.1)
|
||||
covergroup cg_arrays;
|
||||
// The example of IEEE 1800-2023 19.5.4: 12..15
|
||||
ieee: coverpoint v {
|
||||
wildcard bins g12_15_array[] = {4'b11??};
|
||||
}
|
||||
// Values that are not consecutive: 8, 9, 12, 13
|
||||
gaps: coverpoint v {
|
||||
wildcard bins b[] = {4'b1?0?};
|
||||
}
|
||||
// A value two patterns match has one bin: 11..15
|
||||
dups: coverpoint v {
|
||||
wildcard bins b[] = {4'b11??, 4'b1?11};
|
||||
}
|
||||
// Patterns, values, and ranges: 0, 1, 5, 8, 9
|
||||
mixed: coverpoint v {
|
||||
wildcard bins b[] = {4'b000?, 5, [8 : 9]};
|
||||
}
|
||||
// Only values of the coverpoint type (IEEE 1800-2023 19.5.7): 1 and 12..15, and none
|
||||
wide: coverpoint v {
|
||||
wildcard bins keep[] = {8'b0000_11??, 8'b????_0001};
|
||||
wildcard bins none[] = {8'b1???_0000};
|
||||
}
|
||||
// Signed values: -1 and 1; -4..-1 of a signed pattern, none of a wider unsigned one, and
|
||||
// -8..-1 of one of the same width, cast to the coverpoint type
|
||||
sgn2: coverpoint sv2 {
|
||||
wildcard bins b[] = {2'sb?1};
|
||||
}
|
||||
sgn: coverpoint sv {
|
||||
wildcard bins ext[] = {8'sb1111_11??};
|
||||
wildcard bins none[] = {8'b1111_11??};
|
||||
wildcard bins cast[] = {4'b1???};
|
||||
}
|
||||
// Excluded values leave the array, 0 and 1, and a default bin holds the others: 4..6
|
||||
excl: coverpoint u {
|
||||
wildcard bins b[] = {3'b0??};
|
||||
wildcard ignore_bins i[] = {3'b00?};
|
||||
wildcard illegal_bins l[] = {3'b111};
|
||||
bins others = default;
|
||||
}
|
||||
// Excluded values also leave values that are not consecutive: 1 and 5
|
||||
split: coverpoint u {
|
||||
wildcard bins b[] = {3'b?0?};
|
||||
wildcard ignore_bins i[] = {3'b?00};
|
||||
}
|
||||
gated: coverpoint v {
|
||||
wildcard bins b[] = {4'b11?0} iff (v2 == 3);
|
||||
}
|
||||
nonzero: coverpoint v2 {
|
||||
wildcard bins b[] = {2'b1?};
|
||||
}
|
||||
// Crosses of wildcard arrays, one of whose bins are selected by value
|
||||
xx: cross nonzero, gaps{
|
||||
bins sel = binsof (gaps.b) intersect {[8 : 9]};
|
||||
}
|
||||
// Values beyond 64 bits: 16..31, and 24, 25, 28, 29
|
||||
wide100: coverpoint w {
|
||||
wildcard bins b[] = {100'h1?};
|
||||
wildcard bins f[] = {100'b1_1?0?};
|
||||
}
|
||||
ww: cross nonzero, wide100;
|
||||
endgroup
|
||||
|
||||
// Sized wildcard arrays distribute the values in order, and retain duplicates (IEEE
|
||||
// 1800-2023 19.5.1)
|
||||
covergroup cg_sized;
|
||||
// <8,9>, <12,13>
|
||||
s: coverpoint v {
|
||||
wildcard bins b[2] = {4'b1?0?};
|
||||
}
|
||||
// <12,13,14>, <15,11,15>
|
||||
d: coverpoint v {
|
||||
wildcard bins b[2] = {4'b11??, 4'b1?11};
|
||||
}
|
||||
endgroup
|
||||
|
||||
// Signed 64-bit values: a crossed array of negative ones, and those of a pattern with an x
|
||||
// sign bit, in value order
|
||||
covergroup cg_s64;
|
||||
neg: coverpoint l {
|
||||
wildcard bins b[] = {-1, -3};
|
||||
}
|
||||
top: coverpoint l {
|
||||
wildcard bins b[] = {64'sh?fff_ffff_ffff_fffe};
|
||||
}
|
||||
three: coverpoint v2 {
|
||||
bins b = {3};
|
||||
}
|
||||
nx: cross neg, three;
|
||||
endgroup
|
||||
|
||||
cg_arrays arrays_inst = new;
|
||||
cg_sized sized_inst = new;
|
||||
cg_s64 s64_inst = new;
|
||||
|
||||
initial begin
|
||||
cg cg_inst;
|
||||
|
||||
@@ -74,6 +177,44 @@ module t;
|
||||
cg_inst.sample();
|
||||
`checkr(cg_inst.get_inst_coverage(), 100.0);
|
||||
|
||||
for (int a = 0; a < 4; ++a) begin
|
||||
for (int i = 0; i < 16; ++i) begin
|
||||
v = 4'(i);
|
||||
sv = 4'(i);
|
||||
v2 = 2'(a);
|
||||
sv2 = 2'(a);
|
||||
u = 3'(i % 7);
|
||||
w = 100'(i + 16);
|
||||
arrays_inst.sample();
|
||||
end
|
||||
// With v2 == 0: all but sgn2, gated, nonzero, xx, and ww of the 14 items with bins
|
||||
if (a == 0) `checkr(arrays_inst.get_inst_coverage(), 100.0 * 9 / 14);
|
||||
end
|
||||
`checkr(arrays_inst.get_inst_coverage(), 100.0);
|
||||
|
||||
v = 8;
|
||||
sized_inst.sample();
|
||||
`checkr(sized_inst.get_inst_coverage(), 100.0 * (1.0 / 2 + 0.0) / 2);
|
||||
v = 11;
|
||||
sized_inst.sample();
|
||||
`checkr(sized_inst.get_inst_coverage(), 100.0 * (1.0 / 2 + 1.0 / 2) / 2);
|
||||
v = 13;
|
||||
sized_inst.sample();
|
||||
`checkr(sized_inst.get_inst_coverage(), 100.0);
|
||||
|
||||
v2 = 3;
|
||||
for (int i = 0; i < 16; ++i) begin
|
||||
l = {4'(i), 60'hfff_ffff_ffff_fffe};
|
||||
s64_inst.sample();
|
||||
end
|
||||
// All of top and three, none of neg and nx
|
||||
`checkr(s64_inst.get_inst_coverage(), 100.0 * 2 / 4);
|
||||
l = -1;
|
||||
s64_inst.sample();
|
||||
l = -3;
|
||||
s64_inst.sample();
|
||||
`checkr(s64_inst.get_inst_coverage(), 100.0);
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
cg.ign.all: 8
|
||||
cg.ign.odd [ignore]: 8
|
||||
cg.ign_sized.all: 8
|
||||
cg.ign_sized.odd [ignore]: 8
|
||||
cg.ill.all: 16
|
||||
cg.ill.high [illegal]: 0
|
||||
cg.ill_sized.all: 16
|
||||
cg.ill_sized.odd [illegal]: 0
|
||||
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of either the GNU Lesser General Public License Version 3
|
||||
# or the Perl Artistic License Version 2.0.
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
import coverage_covergroup_common
|
||||
|
||||
test.scenarios('vlt_all')
|
||||
|
||||
coverage_covergroup_common.run(test, verilator_flags2=['--coverage-max-bins 4', '-Wno-COVERIGN'])
|
||||
@@ -0,0 +1,62 @@
|
||||
// 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
|
||||
|
||||
// Wildcard arrays of bins of more values, or ranges of values, than --coverage-max-bins 4. An
|
||||
// ignore or illegal array still excludes or checks all its values, as one bin, and an ignored
|
||||
// array leaves its coverpoint without bins, rather than automatic ones (IEEE 1800-2023 19.11.1).
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkr(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got=%f exp=%f\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
module t;
|
||||
bit [3:0] v;
|
||||
bit [3:0] x;
|
||||
int illegal;
|
||||
|
||||
covergroup cg;
|
||||
// The odd values are excluded, so 'all' holds the even ones
|
||||
ign: coverpoint v {
|
||||
bins all = {[0 : 15]};
|
||||
wildcard ignore_bins odd[] = {4'b???1};
|
||||
}
|
||||
ign_sized: coverpoint v {
|
||||
bins all = {[0 : 15]};
|
||||
wildcard ignore_bins odd[2] = {4'b???1};
|
||||
}
|
||||
// Values 8..15, and the odd values, are illegal
|
||||
ill: coverpoint x {
|
||||
bins all = {[0 : 15]};
|
||||
wildcard illegal_bins high[] = {4'b1???};
|
||||
}
|
||||
ill_sized: coverpoint x {
|
||||
bins all = {[0 : 15]};
|
||||
wildcard illegal_bins odd[2] = {4'b???1};
|
||||
}
|
||||
only: coverpoint v {
|
||||
wildcard bins odd[2] = {4'b???1};
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg cg_inst = new;
|
||||
|
||||
initial begin
|
||||
for (int i = 0; i < 16; ++i) begin
|
||||
v = 4'(i);
|
||||
x = 4'(i % 4 * 2);
|
||||
cg_inst.sample();
|
||||
end
|
||||
// All of the coverpoints with bins, which 'only' is not
|
||||
`checkr(cg_inst.get_inst_coverage(), 100.0);
|
||||
if ($value$plusargs("illegal=%d", illegal)) begin
|
||||
x = 4'(illegal);
|
||||
cg_inst.sample();
|
||||
end
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -0,0 +1,3 @@
|
||||
[0] %Error: t_covergroup_wildcard_max_bins.v:34: Assertion failed in top.t.cg.sample: Illegal bin 'high' hit in coverpoint 'ill'
|
||||
%Error: t/t_covergroup_wildcard_max_bins.v:34: Verilog $stop
|
||||
Aborting...
|
||||
@@ -0,0 +1,24 @@
|
||||
#!/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.top_filename = 't/t_covergroup_wildcard_max_bins.v'
|
||||
|
||||
test.compile(verilator_flags2=['--coverage', '--coverage-max-bins 4', '-Wno-COVERIGN'])
|
||||
|
||||
# An illegal value of the array of more values than the limit
|
||||
test.execute(fails=True,
|
||||
check_finished=False,
|
||||
all_run_flags=['+illegal=8'],
|
||||
expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
@@ -0,0 +1,3 @@
|
||||
[0] %Error: t_covergroup_wildcard_max_bins.v:38: Assertion failed in top.t.cg.sample: Illegal bin 'odd' hit in coverpoint 'ill_sized'
|
||||
%Error: t/t_covergroup_wildcard_max_bins.v:38: Verilog $stop
|
||||
Aborting...
|
||||
@@ -0,0 +1,24 @@
|
||||
#!/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.top_filename = 't/t_covergroup_wildcard_max_bins.v'
|
||||
|
||||
test.compile(verilator_flags2=['--coverage', '--coverage-max-bins 4', '-Wno-COVERIGN'])
|
||||
|
||||
# An illegal value of the sized array of more ranges of values than the limit
|
||||
test.execute(fails=True,
|
||||
check_finished=False,
|
||||
all_run_flags=['+illegal=3'],
|
||||
expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
@@ -801,6 +801,7 @@ module Vt_debug_emitv_t;
|
||||
bins high = {['sh4:'sh6]};
|
||||
bins multi = {'sh0, 'sh1, 'sh2};
|
||||
bins sized['sh2] = {['sh0:'sh5], 'sh7};
|
||||
wildcard bins wild[] = {3'b1z};
|
||||
bins dflt = default;
|
||||
ignore_bins ign = {'sh7};
|
||||
illegal_bins ill = {'sh5};
|
||||
|
||||
@@ -400,6 +400,7 @@ module t (/*AUTOARG*/
|
||||
bins high = {[4:6]};
|
||||
bins multi = {0, 1, 2}; // multiple values in one bins (exercises EmitV range loop)
|
||||
bins sized[2] = {[0:5], 7}; // sized array of bins (exercises EmitV array size)
|
||||
wildcard bins wild[] = {3'b01?}; // wildcard array of bins (exercises EmitV wildcard)
|
||||
bins dflt = default;
|
||||
ignore_bins ign = {7};
|
||||
illegal_bins ill = {5};
|
||||
|
||||
@@ -540,16 +540,21 @@
|
||||
// Crossed coverpoint with a wildcard array bin (wildcard bins wb[] = {2'b0?}): the '0?'
|
||||
// wildcard expands to addr values 0 and 1, each its own array element.
|
||||
covergroup cg_wild_arr;
|
||||
%000004 cp_addr: coverpoint addr {wildcard bins wb[] = {2'b0?};}
|
||||
-000004 point: type=covergroup comment= hier=cg_wild_arr.cp_addr.wb
|
||||
%000002 cp_addr: coverpoint addr {wildcard bins wb[] = {2'b0?};}
|
||||
-000002 point: type=covergroup comment= hier=cg_wild_arr.cp_addr.wb[0]
|
||||
-000002 point: type=covergroup comment= hier=cg_wild_arr.cp_addr.wb[1]
|
||||
%000002 cp_cmd: coverpoint cmd {bins read = {0}; bins write = {1};}
|
||||
-000002 point: type=covergroup comment= hier=cg_wild_arr.cp_cmd.read
|
||||
-000002 point: type=covergroup comment= hier=cg_wild_arr.cp_cmd.write
|
||||
%000002 wa: cross cp_addr, cp_cmd;
|
||||
-000002 point: type=covergroup comment= hier=cg_wild_arr.wa.wb_x_read
|
||||
// cross: [wb, read]
|
||||
-000002 point: type=covergroup comment= hier=cg_wild_arr.wa.wb_x_write
|
||||
// cross: [wb, write]
|
||||
%000001 wa: cross cp_addr, cp_cmd;
|
||||
-000001 point: type=covergroup comment= hier=cg_wild_arr.wa.wb[0]_x_read
|
||||
// cross: [wb[0], read]
|
||||
-000001 point: type=covergroup comment= hier=cg_wild_arr.wa.wb[0]_x_write
|
||||
// cross: [wb[0], write]
|
||||
-000001 point: type=covergroup comment= hier=cg_wild_arr.wa.wb[1]_x_read
|
||||
// cross: [wb[1], read]
|
||||
-000001 point: type=covergroup comment= hier=cg_wild_arr.wa.wb[1]_x_write
|
||||
// cross: [wb[1], write]
|
||||
endgroup
|
||||
|
||||
// Crossed coverpoint with a non-array wildcard bin (wildcard bins wb = {2'b0?}): single
|
||||
|
||||
Reference in New Issue
Block a user