Add runtime covergroup support for cross-points
Signed-off-by: Matthew Ballance <matt.ballance@gmail.com>
This commit is contained in:
parent
3853301367
commit
8271a1bc0e
|
|
@ -41,9 +41,13 @@ enum class VlCovBinKind : uint8_t {
|
|||
|
||||
//=============================================================================
|
||||
// VlCoverpointIf
|
||||
/// Read-side view of a coverpoint. The writer queries bins by index; the
|
||||
/// implementor computes names/kinds on demand. Bounded bin count, so random
|
||||
/// access by index is the primary usage.
|
||||
/// Read-side view of a coverpoint -- a named, index-addressable set of bins
|
||||
/// with a coverage fraction. A cross is also a coverpoint from this view: its
|
||||
/// auto cross bins (one per element of the Cartesian product of the feeding
|
||||
/// coverpoints' Normal bins) are all Normal, and their names are built on
|
||||
/// demand by concatenating the feeding coverpoints' bin names. The writer
|
||||
/// queries bins by index; the implementor computes names/kinds on demand.
|
||||
/// Bounded bin count, so random access by index is the primary usage.
|
||||
|
||||
class VlCoverpointIf VL_NOT_FINAL {
|
||||
public:
|
||||
|
|
@ -53,9 +57,9 @@ public:
|
|||
// METHODS
|
||||
// All bins, across every set; index range [0, binCount())
|
||||
virtual int binCount() const = 0;
|
||||
// Bin name in declaration order (e.g. "myBin" or "b[3]")
|
||||
// Bin name in declaration order (e.g. "myBin" or "b[3]"); for a cross,
|
||||
// the concatenated cross bin name (e.g. "b1_x_b2_x_b3")
|
||||
virtual std::string binName(int i) const = 0;
|
||||
virtual VlCovBinKind binKind(int i) const = 0;
|
||||
// Bins covered / effective total (Normal set only) for the coverage calc
|
||||
virtual void coverageParts(double& covered, double& total) const = 0;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -29,13 +29,28 @@ void VlCoverpoint::init(const char* hier, uint32_t atLeast, int nBins) {
|
|||
m_atLeast = atLeast;
|
||||
m_total = nBins;
|
||||
m_counts.assign(nBins, 0);
|
||||
m_crossIdx.assign(nBins, -1);
|
||||
}
|
||||
|
||||
void VlCoverpoint::addNamer(VlCovBinKind set, int count, VlCovBinNaming naming, const char* name,
|
||||
const char* file, int line, int col) {
|
||||
m_namers.emplace_back(set, count, m_nextBase, naming, name, file, line, col);
|
||||
if (set == VlCovBinKind::KIND_NORMAL) {
|
||||
// Assign each Normal bin its cross index (Normal-only re-indexing); ignore/
|
||||
// illegal/default bins keep -1 and never enter a cross.
|
||||
for (int b = m_nextBase; b < m_nextBase + count; ++b) m_crossIdx[b] = m_nextCrossIdx++;
|
||||
m_normal += count;
|
||||
}
|
||||
m_nextBase += count;
|
||||
if (set == VlCovBinKind::KIND_NORMAL) m_normal += count;
|
||||
}
|
||||
|
||||
std::string VlCoverpoint::normalBinName(int crossIdx) const {
|
||||
// Map a cross (Normal-only) index back to its full bin index, then build its name.
|
||||
// Called only at cross registration, so a linear scan is acceptable.
|
||||
for (int i = 0; i < m_total; ++i) {
|
||||
if (m_crossIdx[i] == crossIdx) return binName(i);
|
||||
}
|
||||
VL_UNREACHABLE; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
const VlCovNamer& VlCoverpoint::namerFor(int i) const {
|
||||
|
|
@ -44,7 +59,7 @@ const VlCovNamer& VlCoverpoint::namerFor(int i) const {
|
|||
for (const VlCovNamer& nm : m_namers) {
|
||||
if (i < nm.base() + nm.count()) return nm;
|
||||
}
|
||||
VL_UNREACHABLE;
|
||||
VL_UNREACHABLE; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
std::string VlCoverpoint::binName(int i) const {
|
||||
|
|
@ -76,3 +91,81 @@ void VlCoverpoint::registerBins(VerilatedCovContext* covcontextp, const char* pa
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// VlCoverCross
|
||||
|
||||
void VlCoverCross::init(const char* hier, int dims, VlCoverpoint* const* cps, const char* file,
|
||||
int line, int col) {
|
||||
m_hier = hier;
|
||||
m_file = file;
|
||||
m_line = line;
|
||||
m_col = col;
|
||||
m_dims = dims;
|
||||
m_cps.assign(cps, cps + dims);
|
||||
m_cpBinCounts.resize(dims);
|
||||
m_numAutoBins = 1;
|
||||
for (int d = 0; d < dims; ++d) {
|
||||
m_cpBinCounts[d] = cps[d]->normalBinCount();
|
||||
m_numAutoBins *= m_cpBinCounts[d];
|
||||
}
|
||||
// stride[d] = product of the Normal bin counts of all dimensions after d.
|
||||
m_stride.assign(dims, 1);
|
||||
for (int d = dims - 2; d >= 0; --d) m_stride[d] = m_stride[d + 1] * m_cpBinCounts[d + 1];
|
||||
m_flatCounts.assign(m_numAutoBins, 0);
|
||||
}
|
||||
|
||||
void VlCoverCross::iterateProduct(VlCoverpoint* const* cps, int dim, int64_t baseIdx) {
|
||||
const int hits = cps[dim]->hitCount();
|
||||
const int* const list = cps[dim]->hitList();
|
||||
const bool last = (dim == m_dims - 1);
|
||||
const int64_t stride = m_stride[dim];
|
||||
for (int hit = 0; hit < hits; ++hit) {
|
||||
const int64_t idx = baseIdx + static_cast<int64_t>(list[hit]) * stride;
|
||||
if (last) {
|
||||
incrementTuple(idx);
|
||||
} else {
|
||||
iterateProduct(cps, dim + 1, idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VlCoverCross::sample(VlCoverpoint* const* cps) {
|
||||
// Fast path: if any dimension had no Normal-bin hit, the cross cannot hit.
|
||||
for (int d = 0; d < m_dims; ++d) {
|
||||
if (cps[d]->hitCount() == 0) return;
|
||||
}
|
||||
iterateProduct(cps, 0, 0);
|
||||
}
|
||||
|
||||
std::string VlCoverCross::binName(int flat) const {
|
||||
// Built on demand by concatenating each coverpoint's own bin name.
|
||||
std::string name;
|
||||
for (int d = 0; d < m_dims; ++d) {
|
||||
const int crossIdx = static_cast<int>((flat / m_stride[d]) % m_cpBinCounts[d]);
|
||||
if (d > 0) name += "_x_";
|
||||
name += m_cps[d]->normalBinName(crossIdx);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
void VlCoverCross::registerBins(VerilatedCovContext* covcontextp, const char* page) {
|
||||
// Register every auto cross bin (zero-count bins included), so the report
|
||||
// shows the full Cartesian product of cross bins. Names are built on the fly.
|
||||
const std::string lineStr = std::to_string(m_line);
|
||||
const std::string colStr = std::to_string(m_col);
|
||||
for (int flat = 0; flat < binCount(); ++flat) {
|
||||
const std::string bin = binName(flat); // "b1_x_b2_x_..."
|
||||
// cross_bins metadata: the same components joined by ',' (not read by the report)
|
||||
std::string crossBins;
|
||||
for (int d = 0; d < m_dims; ++d) {
|
||||
const int crossIdx = static_cast<int>((flat / m_stride[d]) % m_cpBinCounts[d]);
|
||||
if (d > 0) crossBins += ",";
|
||||
crossBins += m_cps[d]->normalBinName(crossIdx);
|
||||
}
|
||||
const std::string full = m_hier + "." + bin;
|
||||
VL_COVER_INSERT(covcontextp, full.c_str(), &m_flatCounts[flat], "page", page, "filename",
|
||||
m_file, "lineno", lineStr.c_str(), "column", colStr.c_str(), "bin",
|
||||
bin.c_str(), "cross", "1", "cross_bins", crossBins.c_str());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,16 +87,24 @@ public:
|
|||
/// bin's set/name come from the owning namer. coverage() is computed on demand
|
||||
/// by scanning bin counts, keeping the sample() hot path a plain counter bump.
|
||||
|
||||
class VlCoverpoint final : public VlCoverpointIf {
|
||||
// MEMBERS
|
||||
// Base coverpoint runtime (read side + collection logic, no hit-list storage).
|
||||
// VlCoverpointT<MaxHits> adds the inline hit-list array and the incrementBin write
|
||||
// path; the cross holds VlCoverpoint* and reads via hitCount()/hitList().
|
||||
class VlCoverpoint VL_NOT_FINAL : public VlCoverpointIf {
|
||||
protected:
|
||||
// MEMBERS (protected so VlCoverpointT::incrementBin can update them)
|
||||
std::string m_hier; // "covergroup.coverpoint"
|
||||
uint32_t m_atLeast = 1; // option.at_least (coverpoint-wide)
|
||||
int m_total = 0; // bins across all sets
|
||||
int m_normal = 0; // Normal bins (coverage denominator)
|
||||
int m_nextBase = 0; // running append cursor
|
||||
int m_nextCrossIdx = 0; // running cross-index cursor (Normal bins only)
|
||||
std::vector<uint32_t> m_counts; // [m_total], one per bin
|
||||
std::vector<VlCovNamer> m_namers; // appended in declaration order
|
||||
std::vector<int> m_crossIdx; // [m_total] full bin idx -> cross idx (Normal-only), -1 otherwise
|
||||
int m_hitCount = 0; // entries valid in the hit list this sample
|
||||
|
||||
private:
|
||||
// PRIVATE METHODS
|
||||
const VlCovNamer& namerFor(int i) const; // obtain the bin-specific name producer
|
||||
void addNamer(VlCovBinKind set, int count, VlCovBinNaming naming, const char* name,
|
||||
|
|
@ -119,13 +127,26 @@ public:
|
|||
void registerBins(VerilatedCovContext* covcontextp, const char* page);
|
||||
|
||||
// ---- hot path (from generated sample()) ----
|
||||
void incrementBin(int i) { ++m_counts[i]; } // Normal bin: count only
|
||||
void recordHit(int i) { ++m_counts[i]; } // Ignore/Illegal/Default: count only
|
||||
// Clear the hit list at the start of each sample() for a cross-fed coverpoint.
|
||||
void clearHitList() { m_hitCount = 0; }
|
||||
// Ignore/Illegal/Default: count only; never propagates to cross coverage.
|
||||
void recordHit(int i) { ++m_counts[i]; }
|
||||
// incrementBin (Normal bin: count + hit-list append) lives in VlCoverpointT<MaxHits>,
|
||||
// where MaxHits is the gen-time max per-sample bin overlap.
|
||||
|
||||
// ---- cross support (read by VlCoverCross) ----
|
||||
int hitCount() const { return m_hitCount; }
|
||||
virtual const int* hitList() const = 0; // provided by VlCoverpointT
|
||||
int normalBinCount() const { return m_normal; } // cross dimension size (Normal bins)
|
||||
std::string normalBinName(int crossIdx) const; // name of the crossIdx-th Normal bin
|
||||
|
||||
// ---- VlCoverpointIf ----
|
||||
int binCount() const override { return m_total; }
|
||||
std::string binName(int i) const override;
|
||||
VlCovBinKind binKind(int i) const override { return namerFor(i).set(); }
|
||||
// Deliberately not on VlCoverpointIf: only registerBins() needs it, via the
|
||||
// concrete coverpoint. A cross has all-Normal bins and exposes no kind, so the
|
||||
// interface omits it; add it back only if a writer needs it polymorphically.
|
||||
VlCovBinKind binKind(int i) const { return namerFor(i).set(); }
|
||||
void coverageParts(double& covered, double& total) const override {
|
||||
// Count Normal bins that reached option.at_least on demand, so the hot
|
||||
// path (incrementBin) stays a plain counter bump.
|
||||
|
|
@ -141,4 +162,84 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VlCoverpointT
|
||||
/// Concrete coverpoint with an inline hit-list array sized to MaxHits -- the
|
||||
/// gen-time maximum number of Normal bins one sample value can match (1 for the
|
||||
/// common non-overlapping case). The bound is a compile-time constant, so for
|
||||
/// MaxHits == 1 incrementBin collapses to a single store. Generated code holds
|
||||
/// the coverpoint as VlCoverpointT<K> and calls incrementBin via the concrete
|
||||
/// type; the cross reads it polymorphically through VlCoverpoint*.
|
||||
|
||||
template <int MaxHits>
|
||||
class VlCoverpointT final : public VlCoverpoint {
|
||||
// MEMBERS
|
||||
int m_hits[MaxHits]; // cross indices of Normal bins hit this sample
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VlCoverpointT() = default;
|
||||
|
||||
// METHODS
|
||||
// Normal bin: bump count and append the bin's cross index to the hit list.
|
||||
// m_hitCount can never exceed MaxHits (the gen-time overlap bound), so no hit
|
||||
// is ever dropped; the bound check is a compile-time-folded safety net.
|
||||
void incrementBin(int i) {
|
||||
++m_counts[i];
|
||||
const int cx = m_crossIdx[i];
|
||||
if (cx >= 0 && m_hitCount < MaxHits) m_hits[m_hitCount++] = cx;
|
||||
}
|
||||
const int* hitList() const override { return m_hits; }
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VlCoverCross
|
||||
/// Per-instance auto cross runtime. Holds flat uint32_t[] storage over the
|
||||
/// Cartesian product of the feeding coverpoints' Normal bins. Each sample()
|
||||
/// walks the coverpoint hit lists (O(hits), not O(product)). Bin names are
|
||||
/// built on demand from the coverpoints, so no per-bin name is stored.
|
||||
|
||||
class VlCoverCross final : public VlCoverpointIf {
|
||||
// MEMBERS
|
||||
std::string m_hier; // "covergroup.cross"
|
||||
const char* m_file = nullptr; // cross declaration file (registration metadata)
|
||||
int m_line = 0; // cross declaration line
|
||||
int m_col = 0; // cross declaration column
|
||||
int m_dims = 0; // number of feeding coverpoints
|
||||
int64_t m_numAutoBins = 0; // product of per-dim Normal bin counts
|
||||
int m_numCovered = 0; // distinct bins hit >= 1 (maintained incrementally)
|
||||
std::vector<int> m_cpBinCounts; // [m_dims] Normal bin count per dimension
|
||||
std::vector<int64_t> m_stride; // [m_dims] flat-index stride per dimension
|
||||
std::vector<uint32_t> m_flatCounts; // [m_numAutoBins] per-bin hit counts
|
||||
std::vector<VlCoverpoint*> m_cps; // feeding coverpoints (the only name source)
|
||||
|
||||
// PRIVATE METHODS
|
||||
void iterateProduct(VlCoverpoint* const* cps, int dim, int64_t baseIdx);
|
||||
void incrementTuple(int64_t idx) {
|
||||
if (m_flatCounts[idx]++ == 0) ++m_numCovered;
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VlCoverCross() = default;
|
||||
|
||||
// METHODS
|
||||
// ---- configuration (from generated constructor, after coverpoints init'd) ----
|
||||
void init(const char* hier, int dims, VlCoverpoint* const* cps, const char* file, int line,
|
||||
int col);
|
||||
void registerBins(VerilatedCovContext* covcontextp, const char* page);
|
||||
|
||||
// ---- hot path (from generated sample(), after all coverpoints sampled) ----
|
||||
void sample(VlCoverpoint* const* cps);
|
||||
|
||||
// ---- VlCoverpointIf ----
|
||||
// A cross is a coverpoint whose bins are the auto cross bins (all Normal).
|
||||
int binCount() const override { return static_cast<int>(m_numAutoBins); }
|
||||
std::string binName(int flat) const override;
|
||||
void coverageParts(double& covered, double& total) const override {
|
||||
covered = m_numCovered;
|
||||
total = static_cast<double>(m_numAutoBins);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
|
|
|||
1032
src/V3Covergroup.cpp
1032
src/V3Covergroup.cpp
File diff suppressed because it is too large
Load Diff
|
|
@ -22,7 +22,6 @@ cg7.cp.rev[0]: 1
|
|||
cg7.cp.rev[1]: 0
|
||||
cg8.cp.w[0]: 0
|
||||
cg8.cp.w[1]: 1
|
||||
cg9.__cross7.cumulative_x_lo [cross]: 1
|
||||
cg9.__cross7.ok_x_lo [cross]: 1
|
||||
cg9.cpA.ok: 1
|
||||
cg9.cpB.lo: 1
|
||||
|
|
|
|||
|
|
@ -85,4 +85,28 @@
|
|||
: ... note: In instance 't'
|
||||
73 | bins b_huge[] = {[0:$]};
|
||||
| ^~~~~~
|
||||
%Error: t/t_covergroup_autobins_bad.v:84:41: Non-constant expression in bin range; values must be constants
|
||||
: ... note: In instance 't'
|
||||
84 | cp_a: coverpoint cp_expr {bins x = {size_var};}
|
||||
| ^~~~~~~~
|
||||
%Error: t/t_covergroup_autobins_bad.v:89:41: Non-constant expression in bin range; range bounds must be constants
|
||||
: ... note: In instance 't'
|
||||
89 | cp_a: coverpoint cp_expr {bins x = {[size_var : 1]};}
|
||||
| ^
|
||||
%Error: t/t_covergroup_autobins_bad.v:94:41: Non-constant expression in bin range; range bounds must be constants
|
||||
: ... note: In instance 't'
|
||||
94 | cp_a: coverpoint cp_expr {bins x = {[0 : size_var]};}
|
||||
| ^
|
||||
%Error: t/t_covergroup_autobins_bad.v:99:36: Four-state (x/z) value in array bins range bound; range bounds must be two-state constants
|
||||
: ... note: In instance 't'
|
||||
99 | cp_a: coverpoint cp_expr {bins x[] = {[4'b000x : 4'hF]};}
|
||||
| ^
|
||||
%Error: t/t_covergroup_autobins_bad.v:104:36: Four-state (x/z) value in array bins range bound; range bounds must be two-state constants
|
||||
: ... note: In instance 't'
|
||||
104 | cp_a: coverpoint cp_expr {bins x[] = {[4'h0 : 4'b000x]};}
|
||||
| ^
|
||||
%Error: t/t_covergroup_autobins_bad.v:109:36: Non-constant expression in array bins value list; values must be constants
|
||||
: ... note: In instance 't'
|
||||
109 | cp_a: coverpoint cp_expr {bins x[] = {size_var};}
|
||||
| ^
|
||||
%Error: Exiting due to
|
||||
|
|
|
|||
|
|
@ -74,6 +74,48 @@ module t;
|
|||
}
|
||||
endgroup
|
||||
|
||||
// Malformed bins on a coverpoint that feeds a *cross*. The cross path
|
||||
// sizes the coverpoint's hit list (computeHitListBound/extractRangeIntervals)
|
||||
// before the bin condition is built, so the malformed-bin guards there run gracefully and
|
||||
// the user error is then diagnosed downstream by the bin-condition / array-value builders.
|
||||
// (Without a cross the same errors fire via cg3/cg5 above; the cross also exercises the
|
||||
// hit-list-sizing guard path.)
|
||||
covergroup cgx_nc_value; // non-constant value, non-array bin
|
||||
cp_a: coverpoint cp_expr {bins x = {size_var};}
|
||||
cp_c: coverpoint cp_expr {bins r = {0}; bins w = {1};}
|
||||
xc: cross cp_a, cp_c;
|
||||
endgroup
|
||||
covergroup cgx_nc_range_lo; // non-constant low bound, non-array range
|
||||
cp_a: coverpoint cp_expr {bins x = {[size_var : 1]};}
|
||||
cp_c: coverpoint cp_expr {bins r = {0}; bins w = {1};}
|
||||
xc: cross cp_a, cp_c;
|
||||
endgroup
|
||||
covergroup cgx_nc_range_hi; // non-constant high bound, non-array range
|
||||
cp_a: coverpoint cp_expr {bins x = {[0 : size_var]};}
|
||||
cp_c: coverpoint cp_expr {bins r = {0}; bins w = {1};}
|
||||
xc: cross cp_a, cp_c;
|
||||
endgroup
|
||||
covergroup cgx_arr_4state_lo; // four-state low bound, array range
|
||||
cp_a: coverpoint cp_expr {bins x[] = {[4'b000x : 4'hF]};}
|
||||
cp_c: coverpoint cp_expr {bins r = {0}; bins w = {1};}
|
||||
xc: cross cp_a, cp_c;
|
||||
endgroup
|
||||
covergroup cgx_arr_4state_hi; // four-state high bound, array range
|
||||
cp_a: coverpoint cp_expr {bins x[] = {[4'h0 : 4'b000x]};}
|
||||
cp_c: coverpoint cp_expr {bins r = {0}; bins w = {1};}
|
||||
xc: cross cp_a, cp_c;
|
||||
endgroup
|
||||
covergroup cgx_arr_ncval; // non-constant value, array value list
|
||||
cp_a: coverpoint cp_expr {bins x[] = {size_var};}
|
||||
cp_c: coverpoint cp_expr {bins r = {0}; bins w = {1};}
|
||||
xc: cross cp_a, cp_c;
|
||||
endgroup
|
||||
covergroup cgx_arr_open; // open-ended ('$') bounds, array range
|
||||
cp_a: coverpoint cp_expr {bins x[] = {[2 : $], [$ : 1]};}
|
||||
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;
|
||||
|
|
@ -81,6 +123,13 @@ module t;
|
|||
cg4 cg4_inst = new;
|
||||
cg5 cg5_inst = new;
|
||||
cg6 cg6_inst = new;
|
||||
cgx_nc_value cgx_nc_value_inst = new;
|
||||
cgx_nc_range_lo cgx_nc_range_lo_inst = new;
|
||||
cgx_nc_range_hi cgx_nc_range_hi_inst = new;
|
||||
cgx_arr_4state_lo cgx_arr_4state_lo_inst = new;
|
||||
cgx_arr_4state_hi cgx_arr_4state_hi_inst = new;
|
||||
cgx_arr_ncval cgx_arr_ncval_inst = new;
|
||||
cgx_arr_open cgx_arr_open_inst = new;
|
||||
|
||||
initial $finish;
|
||||
endmodule
|
||||
|
|
|
|||
|
|
@ -57,6 +57,27 @@ cg5.cp_addr.addr0: 1
|
|||
cg5.cp_addr.addr1: 1
|
||||
cg5.cp_cmd.read: 1
|
||||
cg5.cp_cmd.write: 1
|
||||
cg_arr_4state.a4.av[0]_x_read [cross]: 1
|
||||
cg_arr_4state.a4.av[0]_x_write [cross]: 1
|
||||
cg_arr_4state.cp_addr.av[0]: 2
|
||||
cg_arr_4state.cp_cmd.read: 1
|
||||
cg_arr_4state.cp_cmd.write: 1
|
||||
cg_arr_range.ar.av[0]_x_read [cross]: 1
|
||||
cg_arr_range.ar.av[0]_x_write [cross]: 1
|
||||
cg_arr_range.ar.av[1]_x_read [cross]: 1
|
||||
cg_arr_range.ar.av[1]_x_write [cross]: 1
|
||||
cg_arr_range.cp_addr.av[0]: 2
|
||||
cg_arr_range.cp_addr.av[1]: 2
|
||||
cg_arr_range.cp_cmd.read: 2
|
||||
cg_arr_range.cp_cmd.write: 2
|
||||
cg_arr_vals.av.av[0]_x_read [cross]: 1
|
||||
cg_arr_vals.av.av[0]_x_write [cross]: 1
|
||||
cg_arr_vals.av.av[1]_x_read [cross]: 1
|
||||
cg_arr_vals.av.av[1]_x_write [cross]: 1
|
||||
cg_arr_vals.cp_addr.av[0]: 2
|
||||
cg_arr_vals.cp_addr.av[1]: 2
|
||||
cg_arr_vals.cp_cmd.read: 2
|
||||
cg_arr_vals.cp_cmd.write: 2
|
||||
cg_at_least.addr_cmd_al.addr0_x_read [cross]: 1
|
||||
cg_at_least.addr_cmd_al.addr0_x_write [cross]: 0
|
||||
cg_at_least.addr_cmd_al.addr1_x_read [cross]: 0
|
||||
|
|
@ -71,7 +92,7 @@ cg_def_cross.axc.a1_x_read [cross]: 0
|
|||
cg_def_cross.axc.a1_x_write [cross]: 0
|
||||
cg_def_cross.cp_a.a0: 1
|
||||
cg_def_cross.cp_a.a1: 0
|
||||
cg_def_cross.cp_a.ad: 1
|
||||
cg_def_cross.cp_a.ad [default]: 1
|
||||
cg_def_cross.cp_c.read: 1
|
||||
cg_def_cross.cp_c.write: 1
|
||||
cg_goal.addr_cmd_goal.addr0_x_read [cross]: 1
|
||||
|
|
@ -91,6 +112,11 @@ 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_inv.cp_addr.inv: 0
|
||||
cg_inv.cp_cmd.read: 1
|
||||
cg_inv.cp_cmd.write: 1
|
||||
cg_inv.iv.inv_x_read [cross]: 0
|
||||
cg_inv.iv.inv_x_write [cross]: 0
|
||||
cg_mixed.ab.addr0_x_read [cross]: 1
|
||||
cg_mixed.ab.addr0_x_write [cross]: 1
|
||||
cg_mixed.ab.addr1_x_read [cross]: 1
|
||||
|
|
@ -101,6 +127,25 @@ cg_mixed.cp_cmd.read: 2
|
|||
cg_mixed.cp_cmd.write: 2
|
||||
cg_mixed.cp_solo.debug: 2
|
||||
cg_mixed.cp_solo.normal: 2
|
||||
cg_noNormal.cp_addr.ig [ignore]: 2
|
||||
cg_noNormal.cp_cmd.read: 1
|
||||
cg_noNormal.cp_cmd.write: 1
|
||||
cg_openrange.cp_addr.hi: 2
|
||||
cg_openrange.cp_addr.lo: 2
|
||||
cg_openrange.cp_cmd.read: 2
|
||||
cg_openrange.cp_cmd.write: 2
|
||||
cg_openrange.orc.hi_x_read [cross]: 1
|
||||
cg_openrange.orc.hi_x_write [cross]: 1
|
||||
cg_openrange.orc.lo_x_read [cross]: 1
|
||||
cg_openrange.orc.lo_x_write [cross]: 1
|
||||
cg_overlap.cp_addr.hi: 3
|
||||
cg_overlap.cp_addr.lo: 3
|
||||
cg_overlap.cp_cmd.read: 3
|
||||
cg_overlap.cp_cmd.write: 2
|
||||
cg_overlap.ov.hi_x_read [cross]: 2
|
||||
cg_overlap.ov.hi_x_write [cross]: 1
|
||||
cg_overlap.ov.lo_x_read [cross]: 2
|
||||
cg_overlap.ov.lo_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
|
||||
|
|
@ -109,6 +154,11 @@ 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_trans.cp_t.t01: 1
|
||||
cg_trans.cp_v.v5: 2
|
||||
cg_trans.cp_v.v6: 1
|
||||
cg_trans.tx.t01_x_v5 [cross]: 1
|
||||
cg_trans.tx.t01_x_v6 [cross]: 0
|
||||
cg_unnamed_cross.__cross8.a0_x_read [cross]: 1
|
||||
cg_unnamed_cross.__cross8.a0_x_write [cross]: 0
|
||||
cg_unnamed_cross.__cross8.a1_x_read [cross]: 0
|
||||
|
|
@ -125,3 +175,21 @@ cg_unsup_cross_opt.cp_addr.addr0: 1
|
|||
cg_unsup_cross_opt.cp_addr.addr1: 1
|
||||
cg_unsup_cross_opt.cp_cmd.read: 1
|
||||
cg_unsup_cross_opt.cp_cmd.write: 1
|
||||
cg_wide.cp_cmd.read: 2
|
||||
cg_wide.cp_cmd.write: 2
|
||||
cg_wide.cp_wide.hi: 2
|
||||
cg_wide.cp_wide.lo: 2
|
||||
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_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_solo.cp_addr.wb: 2
|
||||
cg_wild_solo.cp_cmd.read: 1
|
||||
cg_wild_solo.cp_cmd.write: 1
|
||||
cg_wild_solo.ws.wb_x_read [cross]: 1
|
||||
cg_wild_solo.ws.wb_x_write [cross]: 1
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@ module t;
|
|||
logic cmd;
|
||||
logic mode;
|
||||
logic parity;
|
||||
logic [63:0] wide;
|
||||
logic [3:0] state;
|
||||
logic [3:0] val;
|
||||
|
||||
typedef struct packed {logic m_p; logic h_mode;} cfg_t;
|
||||
cfg_t s_cfg = '0;
|
||||
|
|
@ -108,8 +111,8 @@ module t;
|
|||
cross cp_a, cp_c; // no label: reported under the default cross name
|
||||
endgroup
|
||||
|
||||
// Cross plus an un-crossed coverpoint: get_inst_coverage must combine the converted
|
||||
// (VlCoverpoint) coverpoint cp_solo with the legacy cross/crossed-coverpoint bins.
|
||||
// Cross plus an un-crossed coverpoint: get_inst_coverage must combine the un-crossed
|
||||
// coverpoint cp_solo with the cross and its crossed coverpoints.
|
||||
covergroup cg_mixed;
|
||||
cp_addr: coverpoint addr {bins addr0 = {0}; bins addr1 = {1};}
|
||||
cp_cmd: coverpoint cmd {bins read = {0}; bins write = {1};}
|
||||
|
|
@ -117,14 +120,108 @@ module t;
|
|||
ab: cross cp_addr, cp_cmd;
|
||||
endgroup
|
||||
|
||||
// Crossed (hence non-convertible) coverpoint that also has a default bin: exercises the
|
||||
// legacy default-bin codegen path that converted coverpoints bypass.
|
||||
// Crossed coverpoint that also has a default bin: exercises default-bin handling on a
|
||||
// coverpoint that feeds a cross.
|
||||
covergroup cg_def_cross;
|
||||
cp_a: coverpoint addr iff (mode) {bins a0 = {0}; bins a1 = {1}; bins ad = default;}
|
||||
cp_c: coverpoint cmd {bins read = {0}; bins write = {1};}
|
||||
axc: cross cp_a, cp_c;
|
||||
endgroup
|
||||
|
||||
// Crossed coverpoint with an array range bin (bins av[] = {[0:1]}): exercises the
|
||||
// coverpoint hit-list sizing for array range elements feeding a cross.
|
||||
covergroup cg_arr_range;
|
||||
cp_addr: coverpoint addr {bins av[] = {[0 : 1]};} // -> av[0]=0, av[1]=1
|
||||
cp_cmd: coverpoint cmd {bins read = {0}; bins write = {1};}
|
||||
ar: cross cp_addr, cp_cmd;
|
||||
endgroup
|
||||
|
||||
// Crossed coverpoint with an array value bin (bins av[] = {0, 2}): array value elements.
|
||||
covergroup cg_arr_vals;
|
||||
cp_addr: coverpoint addr {bins av[] = {0, 2};} // -> av[0]=0, av[1]=2
|
||||
cp_cmd: coverpoint cmd {bins read = {0}; bins write = {1};}
|
||||
av: cross cp_addr, cp_cmd;
|
||||
endgroup
|
||||
|
||||
// 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;
|
||||
cp_addr: coverpoint addr {wildcard bins wb[] = {2'b0?};}
|
||||
cp_cmd: coverpoint cmd {bins read = {0}; bins write = {1};}
|
||||
wa: cross cp_addr, cp_cmd;
|
||||
endgroup
|
||||
|
||||
// Crossed coverpoint with a non-array wildcard bin (wildcard bins wb = {2'b0?}): single
|
||||
// wildcard bin matching addr 0 or 1, feeding a cross.
|
||||
covergroup cg_wild_solo;
|
||||
cp_addr: coverpoint addr {wildcard bins wb = {2'b0?};}
|
||||
cp_cmd: coverpoint cmd {bins read = {0}; bins write = {1};}
|
||||
ws: cross cp_addr, cp_cmd;
|
||||
endgroup
|
||||
|
||||
// Crossed coverpoint with a four-state literal in a non-wildcard array bin
|
||||
// (bins av[] = {2'b0x}): LRM 1800-2023 19.5.4 permits 4-state values in a bin definition.
|
||||
// The hit-list sizing cannot statically analyze a 4-state value, so it falls back to the
|
||||
// safe slot count. Under Verilator's 2-state simulation the value matches addr=0.
|
||||
covergroup cg_arr_4state;
|
||||
cp_addr: coverpoint addr {bins av[] = {2'b0x};}
|
||||
cp_cmd: coverpoint cmd {bins read = {0}; bins write = {1};}
|
||||
a4: cross cp_addr, cp_cmd;
|
||||
endgroup
|
||||
|
||||
// Crossed coverpoint with two *overlapping* Normal range bins (addr=1 is in both lo and
|
||||
// hi): the hit-list sizing must report a bound > 1 (a single sample can fall in two bins),
|
||||
// exercising the max-overlap computation in computeHitListBound.
|
||||
covergroup cg_overlap;
|
||||
cp_addr: coverpoint addr {bins lo = {[0 : 1]}; bins hi = {[1 : 2]};} // overlap at addr=1
|
||||
cp_cmd: coverpoint cmd {bins read = {0}; bins write = {1};}
|
||||
ov: cross cp_addr, cp_cmd;
|
||||
endgroup
|
||||
|
||||
// Crossed coverpoint whose sampled expression is wider than 64 bits: exercises the
|
||||
// width>=64 max-value path in the hit-list sizing (where 1<<width would overflow).
|
||||
covergroup cg_wide;
|
||||
cp_wide: coverpoint wide {bins lo = {[0 : 1]}; bins hi = {[2 : 3]};}
|
||||
cp_cmd: coverpoint cmd {bins read = {0}; bins write = {1};}
|
||||
wd: cross cp_wide, cp_cmd;
|
||||
endgroup
|
||||
|
||||
// Crossed coverpoint with open-ended ('$') range bins: 'lo' is open-low ([$:1]) and 'hi'
|
||||
// is open-high ([2:$]); exercises the unbounded-bound interval handling in the hit-list
|
||||
// sizing (lo clamps to 0, hi clamps to the type max).
|
||||
covergroup cg_openrange;
|
||||
cp_addr: coverpoint addr {bins lo = {[$ : 1]}; bins hi = {[2 : $]};}
|
||||
cp_cmd: coverpoint cmd {bins read = {0}; bins write = {1};}
|
||||
orc: cross cp_addr, cp_cmd;
|
||||
endgroup
|
||||
|
||||
// Crossed coverpoint with an inverted range bin (lo bound > hi bound): the bin matches no
|
||||
// value, so the hit-list sizing rejects it (lo > hi) and falls back to the safe slot count.
|
||||
// The 'inv' bin and its cross bins are therefore never hit (coverage stays at 40%).
|
||||
covergroup cg_inv;
|
||||
cp_addr: coverpoint addr {bins inv = {[3 : 0]};} // inverted -> never matches
|
||||
cp_cmd: coverpoint cmd {bins read = {0}; bins write = {1};}
|
||||
iv: cross cp_addr, cp_cmd;
|
||||
endgroup
|
||||
|
||||
// Crossed coverpoint with *no* Normal bins (only ignore_bins): the cross has an empty bin
|
||||
// product, so the hit-list sizing returns the safe bound of 1. Coverage is the cmd
|
||||
// coverpoint alone (vacuously 100% once both cmd bins are hit).
|
||||
covergroup cg_noNormal;
|
||||
cp_addr: coverpoint addr {ignore_bins ig = {[0 : 3]};} // zero Normal bins
|
||||
cp_cmd: coverpoint cmd {bins read = {0}; bins write = {1};}
|
||||
nn: cross cp_addr, cp_cmd;
|
||||
endgroup
|
||||
|
||||
// Cross of a *transition* coverpoint with a value coverpoint. Transition coverpoints route
|
||||
// through the VlCoverpoint runtime (their completion appends to the hit list), so a cross
|
||||
// can read them like any other coverpoint.
|
||||
covergroup cg_trans;
|
||||
cp_t: coverpoint state {bins t01 = (0 => 1);} // one Normal (transition) bin
|
||||
cp_v: coverpoint val {bins v5 = {5}; bins v6 = {6};}
|
||||
tx: cross cp_t, cp_v;
|
||||
endgroup
|
||||
|
||||
cg2 cg2_inst = new;
|
||||
cg_ignore cg_ignore_inst = new;
|
||||
cg_range cg_range_inst = new;
|
||||
|
|
@ -137,6 +234,17 @@ module t;
|
|||
cg_unnamed_cross cg_unnamed_cross_inst = new;
|
||||
cg_mixed cg_mixed_inst = new;
|
||||
cg_def_cross cg_def_cross_inst = new;
|
||||
cg_arr_range cg_arr_range_inst = new;
|
||||
cg_arr_vals cg_arr_vals_inst = new;
|
||||
cg_wild_arr cg_wild_arr_inst = new;
|
||||
cg_wild_solo cg_wild_solo_inst = new;
|
||||
cg_arr_4state cg_arr_4state_inst = new;
|
||||
cg_overlap cg_overlap_inst = new;
|
||||
cg_wide cg_wide_inst = new;
|
||||
cg_openrange cg_openrange_inst = new;
|
||||
cg_inv cg_inv_inst = new;
|
||||
cg_noNormal cg_noNormal_inst = new;
|
||||
cg_trans cg_trans_inst = new;
|
||||
|
||||
initial begin
|
||||
// Sample 2-way: hit all 4 combinations
|
||||
|
|
@ -320,6 +428,87 @@ module t;
|
|||
addr = 0; cmd = 0; cg_def_cross_inst.sample(); // a0, read
|
||||
addr = 2; cmd = 1; cg_def_cross_inst.sample(); // ad (default), write
|
||||
|
||||
// Sample cg_arr_range: array range bin {[0:1]} -> av[0]=0, av[1]=1; cross 2x2
|
||||
// cg_arr_range: 2+2+4=8 bins; sample all combinations -> 100%
|
||||
addr = 0; cmd = 0; cg_arr_range_inst.sample(); // av[0] x read
|
||||
addr = 0; cmd = 1; cg_arr_range_inst.sample(); // av[0] x write
|
||||
addr = 1; cmd = 0; cg_arr_range_inst.sample(); // av[1] x read
|
||||
addr = 1; cmd = 1; cg_arr_range_inst.sample(); // av[1] x write
|
||||
`checkr(cg_arr_range_inst.get_inst_coverage(), 100.0); // 8/8
|
||||
|
||||
// Sample cg_arr_vals: array value bin {0,2} -> av[0]=0, av[1]=2; cross 2x2
|
||||
// cg_arr_vals: 2+2+4=8 bins; sample all combinations -> 100%
|
||||
addr = 0; cmd = 0; cg_arr_vals_inst.sample(); // av[0] x read
|
||||
addr = 0; cmd = 1; cg_arr_vals_inst.sample(); // av[0] x write
|
||||
addr = 2; cmd = 0; cg_arr_vals_inst.sample(); // av[1] x read
|
||||
addr = 2; cmd = 1; cg_arr_vals_inst.sample(); // av[1] x write
|
||||
`checkr(cg_arr_vals_inst.get_inst_coverage(), 100.0); // 8/8
|
||||
|
||||
// Sample cg_wild_arr: wildcard array {2'b0?} matches addr 0,1; cross 2x2
|
||||
// cg_wild_arr: 2+2+4=8 bins; sample all combinations -> 100%
|
||||
addr = 0; cmd = 0; cg_wild_arr_inst.sample();
|
||||
addr = 0; cmd = 1; cg_wild_arr_inst.sample();
|
||||
addr = 1; cmd = 0; cg_wild_arr_inst.sample();
|
||||
addr = 1; cmd = 1; cg_wild_arr_inst.sample();
|
||||
`checkr(cg_wild_arr_inst.get_inst_coverage(), 100.0); // 8/8
|
||||
|
||||
// Sample cg_wild_solo: single wildcard bin {2'b0?} matches addr 0,1; cross 1x2
|
||||
// cg_wild_solo: 1+2+2=5 bins; sample both cmd values -> 100%
|
||||
addr = 0; cmd = 0; cg_wild_solo_inst.sample();
|
||||
addr = 0; cmd = 1; cg_wild_solo_inst.sample();
|
||||
`checkr(cg_wild_solo_inst.get_inst_coverage(), 100.0); // 5/5
|
||||
|
||||
// Sample cg_arr_4state: 4-state literal bin {2'b0x} matches addr=0 (2-state sim); cross 1x2
|
||||
// cg_arr_4state: 1+2+2=5 bins; sample both cmd values -> 100%
|
||||
addr = 0; cmd = 0; cg_arr_4state_inst.sample();
|
||||
addr = 0; cmd = 1; cg_arr_4state_inst.sample();
|
||||
`checkr(cg_arr_4state_inst.get_inst_coverage(), 100.0); // 5/5
|
||||
|
||||
// Sample cg_overlap: overlapping range bins lo={0,1}, hi={1,2}; cross 2x2
|
||||
// cg_overlap: 2+2+4=8 bins; cover lo/hi via addr 0 and 2, plus addr=1 double-hits both
|
||||
addr = 0; cmd = 0; cg_overlap_inst.sample(); // lo x read
|
||||
addr = 0; cmd = 1; cg_overlap_inst.sample(); // lo x write
|
||||
addr = 2; cmd = 0; cg_overlap_inst.sample(); // hi x read
|
||||
addr = 2; cmd = 1; cg_overlap_inst.sample(); // hi x write
|
||||
addr = 1; cmd = 0; cg_overlap_inst.sample(); // addr=1 in both lo and hi (hit-list bound 2)
|
||||
`checkr(cg_overlap_inst.get_inst_coverage(), 100.0); // 8/8
|
||||
|
||||
// Sample cg_wide: 64-bit coverpoint, lo={0,1}, hi={2,3}; cross 2x2
|
||||
// cg_wide: 2+2+4=8 bins; sample all combinations -> 100%
|
||||
wide = 0; cmd = 0; cg_wide_inst.sample(); // lo x read
|
||||
wide = 0; cmd = 1; cg_wide_inst.sample(); // lo x write
|
||||
wide = 2; cmd = 0; cg_wide_inst.sample(); // hi x read
|
||||
wide = 2; cmd = 1; cg_wide_inst.sample(); // hi x write
|
||||
`checkr(cg_wide_inst.get_inst_coverage(), 100.0); // 8/8
|
||||
|
||||
// Sample cg_openrange: lo=[$:1] matches 0,1; hi=[2:$] matches 2,3; cross 2x2
|
||||
// cg_openrange: 2+2+4=8 bins; sample all combinations -> 100%
|
||||
addr = 0; cmd = 0; cg_openrange_inst.sample(); // lo x read
|
||||
addr = 0; cmd = 1; cg_openrange_inst.sample(); // lo x write
|
||||
addr = 2; cmd = 0; cg_openrange_inst.sample(); // hi x read
|
||||
addr = 2; cmd = 1; cg_openrange_inst.sample(); // hi x write
|
||||
`checkr(cg_openrange_inst.get_inst_coverage(), 100.0); // 8/8
|
||||
|
||||
// Sample cg_inv: inverted range bin never matches; only cmd bins are hittable
|
||||
// cg_inv: 1+2+2=5 bins; inv and its 2 cross bins never hit -> 2/5=40%
|
||||
addr = 0; cmd = 0; cg_inv_inst.sample(); // read
|
||||
addr = 1; cmd = 1; cg_inv_inst.sample(); // write
|
||||
`checkr(cg_inv_inst.get_inst_coverage(), 40.0); // 2/5: read + write only
|
||||
|
||||
// Sample cg_noNormal: coverpoint has no Normal bins; cross product is empty
|
||||
// cg_noNormal: 0+2+0=2 bins (cmd only); both hit -> 100%
|
||||
addr = 0; cmd = 0; cg_noNormal_inst.sample(); // read
|
||||
addr = 1; cmd = 1; cg_noNormal_inst.sample(); // write
|
||||
`checkr(cg_noNormal_inst.get_inst_coverage(), 100.0); // 2/2
|
||||
|
||||
// Sample cg_trans: transition coverpoint crossed with a value coverpoint
|
||||
// cg_trans: 1+2+2=5 bins; t01_x_v6 never completes -> 4/5=80%
|
||||
// __Vprev_cp_t initializes to 0.
|
||||
state = 0; val = 5; cg_trans_inst.sample(); // prev=0,cur=0: no t01; v5
|
||||
state = 1; val = 5; cg_trans_inst.sample(); // prev=0,cur=1: t01 completes; t01_x_v5
|
||||
state = 0; val = 6; cg_trans_inst.sample(); // prev=1,cur=0: no t01; v6 (no cross)
|
||||
`checkr(cg_trans_inst.get_inst_coverage(), 80.0); // 4/5: t01_x_v6 not hit
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,5 +7,7 @@ cg.cp_trans2.trans2: 1
|
|||
cg.cp_trans2.trans3: 1
|
||||
cg.cp_trans3.seq_a: 1
|
||||
cg.cp_trans3.seq_b: 1
|
||||
cg_legacy.cp_mix.tr: 1
|
||||
cg_legacy.cp_mix.vals: 1
|
||||
cg_array.cp_mix.tr: 1
|
||||
cg_array.cp_mix.vals[0]: 1
|
||||
cg_array.cp_mix.vals[1]: 0
|
||||
cg_array.cp_mix.vals[2]: 0
|
||||
|
|
|
|||
|
|
@ -39,17 +39,18 @@ module t;
|
|||
}
|
||||
endgroup
|
||||
|
||||
// Non-convertible coverpoint (it has a transition bin) that also carries a value-array bin,
|
||||
// so the legacy array codegen path (which converted coverpoints bypass) is still exercised.
|
||||
covergroup cg_legacy;
|
||||
// Coverpoint mixing a transition bin and a value-array bin: both route through the
|
||||
// VlCoverpoint runtime (the value array reports indexed as vals[0]..vals[N-1], like every
|
||||
// other array bin; the transition records into its own runtime bin).
|
||||
covergroup cg_array;
|
||||
cp_mix: coverpoint state {
|
||||
bins tr = (0 => 1);
|
||||
bins vals[] = {2, [4:5]}; // discrete + range elements (both legacy array paths)
|
||||
bins vals[] = {2, [4:5]}; // discrete + range elements
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg cg_inst = new;
|
||||
cg_legacy cg_legacy_inst = new;
|
||||
cg_array cg_array_inst = new;
|
||||
|
||||
initial begin
|
||||
// Drive sequence 0->1->2->3->4 which hits all bins
|
||||
|
|
@ -66,11 +67,11 @@ module t;
|
|||
cg_inst.sample(); // 3=>4: seq_b done
|
||||
`checkr(cg_inst.get_inst_coverage(), 100.0);
|
||||
|
||||
// cg_legacy: exercise legacy array codegen (non-convertible coverpoint)
|
||||
state = 0; cg_legacy_inst.sample();
|
||||
state = 1; cg_legacy_inst.sample(); // 0=>1: tr
|
||||
state = 2; cg_legacy_inst.sample(); // vals
|
||||
state = 3; cg_legacy_inst.sample(); // vals
|
||||
// cg_array: exercise the mixed transition + value-array coverpoint
|
||||
state = 0; cg_array_inst.sample();
|
||||
state = 1; cg_array_inst.sample(); // 0=>1: tr
|
||||
state = 2; cg_array_inst.sample(); // vals
|
||||
state = 3; cg_array_inst.sample(); // vals
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@
|
|||
|
||||
module t;
|
||||
%000001 logic [1:0] addr;
|
||||
-000000 point: type=toggle comment=addr[0]:0->1 hier=top.t
|
||||
-000001 point: type=toggle comment=addr[0]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=addr[0]:1->0 hier=top.t
|
||||
-000001 point: type=toggle comment=addr[1]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=addr[1]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=addr[1]:1->0 hier=top.t
|
||||
%000001 logic cmd;
|
||||
-000001 point: type=toggle comment=cmd:0->1 hier=top.t
|
||||
|
|
@ -27,6 +27,153 @@
|
|||
%000001 logic parity;
|
||||
-000001 point: type=toggle comment=parity:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=parity:1->0 hier=top.t
|
||||
%000001 logic [63:0] wide;
|
||||
-000000 point: type=toggle comment=wide[0]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[0]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[10]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[10]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[11]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[11]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[12]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[12]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[13]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[13]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[14]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[14]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[15]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[15]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[16]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[16]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[17]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[17]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[18]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[18]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[19]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[19]:1->0 hier=top.t
|
||||
-000001 point: type=toggle comment=wide[1]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[1]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[20]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[20]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[21]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[21]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[22]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[22]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[23]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[23]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[24]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[24]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[25]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[25]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[26]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[26]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[27]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[27]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[28]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[28]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[29]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[29]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[2]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[2]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[30]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[30]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[31]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[31]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[32]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[32]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[33]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[33]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[34]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[34]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[35]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[35]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[36]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[36]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[37]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[37]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[38]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[38]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[39]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[39]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[3]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[3]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[40]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[40]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[41]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[41]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[42]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[42]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[43]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[43]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[44]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[44]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[45]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[45]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[46]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[46]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[47]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[47]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[48]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[48]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[49]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[49]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[4]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[4]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[50]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[50]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[51]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[51]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[52]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[52]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[53]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[53]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[54]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[54]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[55]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[55]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[56]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[56]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[57]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[57]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[58]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[58]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[59]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[59]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[5]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[5]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[60]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[60]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[61]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[61]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[62]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[62]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[63]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[63]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[6]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[6]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[7]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[7]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[8]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[8]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[9]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=wide[9]:1->0 hier=top.t
|
||||
%000000 logic [3:0] state;
|
||||
-000000 point: type=toggle comment=state[0]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=state[0]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=state[1]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=state[1]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=state[2]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=state[2]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=state[3]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=state[3]:1->0 hier=top.t
|
||||
%000001 logic [3:0] val;
|
||||
-000000 point: type=toggle comment=val[0]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=val[0]:1->0 hier=top.t
|
||||
-000001 point: type=toggle comment=val[1]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=val[1]:1->0 hier=top.t
|
||||
-000001 point: type=toggle comment=val[2]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=val[2]:1->0 hier=top.t
|
||||
-000000 point: type=toggle comment=val[3]:0->1 hier=top.t
|
||||
-000000 point: type=toggle comment=val[3]:1->0 hier=top.t
|
||||
|
||||
typedef struct packed {logic m_p; logic h_mode;} cfg_t;
|
||||
%000001 cfg_t s_cfg = '0;
|
||||
|
|
@ -292,8 +439,8 @@
|
|||
// cross: [a1, write]
|
||||
endgroup
|
||||
|
||||
// Cross plus an un-crossed coverpoint: get_inst_coverage must combine the converted
|
||||
// (VlCoverpoint) coverpoint cp_solo with the legacy cross/crossed-coverpoint bins.
|
||||
// Cross plus an un-crossed coverpoint: get_inst_coverage must combine the un-crossed
|
||||
// coverpoint cp_solo with the cross and its crossed coverpoints.
|
||||
covergroup cg_mixed;
|
||||
%000002 cp_addr: coverpoint addr {bins addr0 = {0}; bins addr1 = {1};}
|
||||
-000002 point: type=covergroup comment= hier=cg_mixed.cp_addr.addr0
|
||||
|
|
@ -315,8 +462,8 @@
|
|||
// cross: [addr1, write]
|
||||
endgroup
|
||||
|
||||
// Crossed (hence non-convertible) coverpoint that also has a default bin: exercises the
|
||||
// legacy default-bin codegen path that converted coverpoints bypass.
|
||||
// Crossed coverpoint that also has a default bin: exercises default-bin handling on a
|
||||
// coverpoint that feeds a cross.
|
||||
covergroup cg_def_cross;
|
||||
%000001 cp_a: coverpoint addr iff (mode) {bins a0 = {0}; bins a1 = {1}; bins ad = default;}
|
||||
-000001 point: type=covergroup comment= hier=cg_def_cross.cp_a.a0
|
||||
|
|
@ -336,6 +483,198 @@
|
|||
// cross: [a1, write]
|
||||
endgroup
|
||||
|
||||
// Crossed coverpoint with an array range bin (bins av[] = {[0:1]}): exercises the
|
||||
// coverpoint hit-list sizing for array range elements feeding a cross.
|
||||
covergroup cg_arr_range;
|
||||
%000002 cp_addr: coverpoint addr {bins av[] = {[0 : 1]};} // -> av[0]=0, av[1]=1
|
||||
-000002 point: type=covergroup comment= hier=cg_arr_range.cp_addr.av[0]
|
||||
-000002 point: type=covergroup comment= hier=cg_arr_range.cp_addr.av[1]
|
||||
%000002 cp_cmd: coverpoint cmd {bins read = {0}; bins write = {1};}
|
||||
-000002 point: type=covergroup comment= hier=cg_arr_range.cp_cmd.read
|
||||
-000002 point: type=covergroup comment= hier=cg_arr_range.cp_cmd.write
|
||||
%000001 ar: cross cp_addr, cp_cmd;
|
||||
-000001 point: type=covergroup comment= hier=cg_arr_range.ar.av[0]_x_read
|
||||
// cross: [av[0], read]
|
||||
-000001 point: type=covergroup comment= hier=cg_arr_range.ar.av[0]_x_write
|
||||
// cross: [av[0], write]
|
||||
-000001 point: type=covergroup comment= hier=cg_arr_range.ar.av[1]_x_read
|
||||
// cross: [av[1], read]
|
||||
-000001 point: type=covergroup comment= hier=cg_arr_range.ar.av[1]_x_write
|
||||
// cross: [av[1], write]
|
||||
endgroup
|
||||
|
||||
// Crossed coverpoint with an array value bin (bins av[] = {0, 2}): array value elements.
|
||||
covergroup cg_arr_vals;
|
||||
%000002 cp_addr: coverpoint addr {bins av[] = {0, 2};} // -> av[0]=0, av[1]=2
|
||||
-000002 point: type=covergroup comment= hier=cg_arr_vals.cp_addr.av[0]
|
||||
-000002 point: type=covergroup comment= hier=cg_arr_vals.cp_addr.av[1]
|
||||
%000002 cp_cmd: coverpoint cmd {bins read = {0}; bins write = {1};}
|
||||
-000002 point: type=covergroup comment= hier=cg_arr_vals.cp_cmd.read
|
||||
-000002 point: type=covergroup comment= hier=cg_arr_vals.cp_cmd.write
|
||||
%000001 av: cross cp_addr, cp_cmd;
|
||||
-000001 point: type=covergroup comment= hier=cg_arr_vals.av.av[0]_x_read
|
||||
// cross: [av[0], read]
|
||||
-000001 point: type=covergroup comment= hier=cg_arr_vals.av.av[0]_x_write
|
||||
// cross: [av[0], write]
|
||||
-000001 point: type=covergroup comment= hier=cg_arr_vals.av.av[1]_x_read
|
||||
// cross: [av[1], read]
|
||||
-000001 point: type=covergroup comment= hier=cg_arr_vals.av.av[1]_x_write
|
||||
// cross: [av[1], write]
|
||||
endgroup
|
||||
|
||||
// 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_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]
|
||||
endgroup
|
||||
|
||||
// Crossed coverpoint with a non-array wildcard bin (wildcard bins wb = {2'b0?}): single
|
||||
// wildcard bin matching addr 0 or 1, feeding a cross.
|
||||
covergroup cg_wild_solo;
|
||||
%000002 cp_addr: coverpoint addr {wildcard bins wb = {2'b0?};}
|
||||
-000002 point: type=covergroup comment= hier=cg_wild_solo.cp_addr.wb
|
||||
%000001 cp_cmd: coverpoint cmd {bins read = {0}; bins write = {1};}
|
||||
-000001 point: type=covergroup comment= hier=cg_wild_solo.cp_cmd.read
|
||||
-000001 point: type=covergroup comment= hier=cg_wild_solo.cp_cmd.write
|
||||
%000001 ws: cross cp_addr, cp_cmd;
|
||||
-000001 point: type=covergroup comment= hier=cg_wild_solo.ws.wb_x_read
|
||||
// cross: [wb, read]
|
||||
-000001 point: type=covergroup comment= hier=cg_wild_solo.ws.wb_x_write
|
||||
// cross: [wb, write]
|
||||
endgroup
|
||||
|
||||
// Crossed coverpoint with a four-state literal in a non-wildcard array bin
|
||||
// (bins av[] = {2'b0x}): LRM 1800-2023 19.5.4 permits 4-state values in a bin definition.
|
||||
// The hit-list sizing cannot statically analyze a 4-state value, so it falls back to the
|
||||
// safe slot count. Under Verilator's 2-state simulation the value matches addr=0.
|
||||
covergroup cg_arr_4state;
|
||||
%000002 cp_addr: coverpoint addr {bins av[] = {2'b0x};}
|
||||
-000002 point: type=covergroup comment= hier=cg_arr_4state.cp_addr.av[0]
|
||||
%000001 cp_cmd: coverpoint cmd {bins read = {0}; bins write = {1};}
|
||||
-000001 point: type=covergroup comment= hier=cg_arr_4state.cp_cmd.read
|
||||
-000001 point: type=covergroup comment= hier=cg_arr_4state.cp_cmd.write
|
||||
%000001 a4: cross cp_addr, cp_cmd;
|
||||
-000001 point: type=covergroup comment= hier=cg_arr_4state.a4.av[0]_x_read
|
||||
// cross: [av[0], read]
|
||||
-000001 point: type=covergroup comment= hier=cg_arr_4state.a4.av[0]_x_write
|
||||
// cross: [av[0], write]
|
||||
endgroup
|
||||
|
||||
// Crossed coverpoint with two *overlapping* Normal range bins (addr=1 is in both lo and
|
||||
// hi): the hit-list sizing must report a bound > 1 (a single sample can fall in two bins),
|
||||
// exercising the max-overlap computation in computeHitListBound.
|
||||
covergroup cg_overlap;
|
||||
%000003 cp_addr: coverpoint addr {bins lo = {[0 : 1]}; bins hi = {[1 : 2]};} // overlap at addr=1
|
||||
-000003 point: type=covergroup comment= hier=cg_overlap.cp_addr.lo
|
||||
-000003 point: type=covergroup comment= hier=cg_overlap.cp_addr.hi
|
||||
%000003 cp_cmd: coverpoint cmd {bins read = {0}; bins write = {1};}
|
||||
-000003 point: type=covergroup comment= hier=cg_overlap.cp_cmd.read
|
||||
-000002 point: type=covergroup comment= hier=cg_overlap.cp_cmd.write
|
||||
%000002 ov: cross cp_addr, cp_cmd;
|
||||
-000002 point: type=covergroup comment= hier=cg_overlap.ov.hi_x_read
|
||||
// cross: [hi, read]
|
||||
-000001 point: type=covergroup comment= hier=cg_overlap.ov.hi_x_write
|
||||
// cross: [hi, write]
|
||||
-000002 point: type=covergroup comment= hier=cg_overlap.ov.lo_x_read
|
||||
// cross: [lo, read]
|
||||
-000001 point: type=covergroup comment= hier=cg_overlap.ov.lo_x_write
|
||||
// cross: [lo, write]
|
||||
endgroup
|
||||
|
||||
// Crossed coverpoint whose sampled expression is wider than 64 bits: exercises the
|
||||
// width>=64 max-value path in the hit-list sizing (where 1<<width would overflow).
|
||||
covergroup cg_wide;
|
||||
%000002 cp_wide: coverpoint wide {bins lo = {[0 : 1]}; bins hi = {[2 : 3]};}
|
||||
-000002 point: type=covergroup comment= hier=cg_wide.cp_wide.lo
|
||||
-000002 point: type=covergroup comment= hier=cg_wide.cp_wide.hi
|
||||
%000002 cp_cmd: coverpoint cmd {bins read = {0}; bins write = {1};}
|
||||
-000002 point: type=covergroup comment= hier=cg_wide.cp_cmd.read
|
||||
-000002 point: type=covergroup comment= hier=cg_wide.cp_cmd.write
|
||||
%000001 wd: cross cp_wide, cp_cmd;
|
||||
-000001 point: type=covergroup comment= hier=cg_wide.wd.hi_x_read
|
||||
// cross: [hi, read]
|
||||
-000001 point: type=covergroup comment= hier=cg_wide.wd.hi_x_write
|
||||
// cross: [hi, write]
|
||||
-000001 point: type=covergroup comment= hier=cg_wide.wd.lo_x_read
|
||||
// cross: [lo, read]
|
||||
-000001 point: type=covergroup comment= hier=cg_wide.wd.lo_x_write
|
||||
// cross: [lo, write]
|
||||
endgroup
|
||||
|
||||
// Crossed coverpoint with open-ended ('$') range bins: 'lo' is open-low ([$:1]) and 'hi'
|
||||
// is open-high ([2:$]); exercises the unbounded-bound interval handling in the hit-list
|
||||
// sizing (lo clamps to 0, hi clamps to the type max).
|
||||
covergroup cg_openrange;
|
||||
%000002 cp_addr: coverpoint addr {bins lo = {[$ : 1]}; bins hi = {[2 : $]};}
|
||||
-000002 point: type=covergroup comment= hier=cg_openrange.cp_addr.lo
|
||||
-000002 point: type=covergroup comment= hier=cg_openrange.cp_addr.hi
|
||||
%000002 cp_cmd: coverpoint cmd {bins read = {0}; bins write = {1};}
|
||||
-000002 point: type=covergroup comment= hier=cg_openrange.cp_cmd.read
|
||||
-000002 point: type=covergroup comment= hier=cg_openrange.cp_cmd.write
|
||||
%000001 orc: cross cp_addr, cp_cmd;
|
||||
-000001 point: type=covergroup comment= hier=cg_openrange.orc.hi_x_read
|
||||
// cross: [hi, read]
|
||||
-000001 point: type=covergroup comment= hier=cg_openrange.orc.hi_x_write
|
||||
// cross: [hi, write]
|
||||
-000001 point: type=covergroup comment= hier=cg_openrange.orc.lo_x_read
|
||||
// cross: [lo, read]
|
||||
-000001 point: type=covergroup comment= hier=cg_openrange.orc.lo_x_write
|
||||
// cross: [lo, write]
|
||||
endgroup
|
||||
|
||||
// Crossed coverpoint with an inverted range bin (lo bound > hi bound): the bin matches no
|
||||
// value, so the hit-list sizing rejects it (lo > hi) and falls back to the safe slot count.
|
||||
// The 'inv' bin and its cross bins are therefore never hit (coverage stays at 40%).
|
||||
covergroup cg_inv;
|
||||
%000000 cp_addr: coverpoint addr {bins inv = {[3 : 0]};} // inverted -> never matches
|
||||
-000000 point: type=covergroup comment= hier=cg_inv.cp_addr.inv
|
||||
%000001 cp_cmd: coverpoint cmd {bins read = {0}; bins write = {1};}
|
||||
-000001 point: type=covergroup comment= hier=cg_inv.cp_cmd.read
|
||||
-000001 point: type=covergroup comment= hier=cg_inv.cp_cmd.write
|
||||
%000000 iv: cross cp_addr, cp_cmd;
|
||||
-000000 point: type=covergroup comment= hier=cg_inv.iv.inv_x_read
|
||||
// cross: [inv, read]
|
||||
-000000 point: type=covergroup comment= hier=cg_inv.iv.inv_x_write
|
||||
// cross: [inv, write]
|
||||
endgroup
|
||||
|
||||
// Crossed coverpoint with *no* Normal bins (only ignore_bins): the cross has an empty bin
|
||||
// product, so the hit-list sizing returns the safe bound of 1. Coverage is the cmd
|
||||
// coverpoint alone (vacuously 100% once both cmd bins are hit).
|
||||
covergroup cg_noNormal;
|
||||
%000002 cp_addr: coverpoint addr {ignore_bins ig = {[0 : 3]};} // zero Normal bins
|
||||
-000002 point: type=covergroup comment= hier=cg_noNormal.cp_addr.ig
|
||||
%000001 cp_cmd: coverpoint cmd {bins read = {0}; bins write = {1};}
|
||||
-000001 point: type=covergroup comment= hier=cg_noNormal.cp_cmd.read
|
||||
-000001 point: type=covergroup comment= hier=cg_noNormal.cp_cmd.write
|
||||
nn: cross cp_addr, cp_cmd;
|
||||
endgroup
|
||||
|
||||
// Cross of a *transition* coverpoint with a value coverpoint. Transition coverpoints route
|
||||
// through the VlCoverpoint runtime (their completion appends to the hit list), so a cross
|
||||
// can read them like any other coverpoint.
|
||||
covergroup cg_trans;
|
||||
%000001 cp_t: coverpoint state {bins t01 = (0 => 1);} // one Normal (transition) bin
|
||||
-000001 point: type=covergroup comment= hier=cg_trans.cp_t.t01
|
||||
%000002 cp_v: coverpoint val {bins v5 = {5}; bins v6 = {6};}
|
||||
-000002 point: type=covergroup comment= hier=cg_trans.cp_v.v5
|
||||
-000001 point: type=covergroup comment= hier=cg_trans.cp_v.v6
|
||||
%000001 tx: cross cp_t, cp_v;
|
||||
-000001 point: type=covergroup comment= hier=cg_trans.tx.t01_x_v5
|
||||
// cross: [t01, v5]
|
||||
-000000 point: type=covergroup comment= hier=cg_trans.tx.t01_x_v6
|
||||
// cross: [t01, v6]
|
||||
endgroup
|
||||
|
||||
%000001 cg2 cg2_inst = new;
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 cg_ignore cg_ignore_inst = new;
|
||||
|
|
@ -360,6 +699,28 @@
|
|||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 cg_def_cross cg_def_cross_inst = new;
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 cg_arr_range cg_arr_range_inst = new;
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 cg_arr_vals cg_arr_vals_inst = new;
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 cg_wild_arr cg_wild_arr_inst = new;
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 cg_wild_solo cg_wild_solo_inst = new;
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 cg_arr_4state cg_arr_4state_inst = new;
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 cg_overlap cg_overlap_inst = new;
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 cg_wide cg_wide_inst = new;
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 cg_openrange cg_openrange_inst = new;
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 cg_inv cg_inv_inst = new;
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 cg_noNormal cg_noNormal_inst = new;
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 cg_trans cg_trans_inst = new;
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
|
||||
%000001 initial begin
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
|
|
@ -737,6 +1098,156 @@
|
|||
%000001 addr = 2; cmd = 1; cg_def_cross_inst.sample(); // ad (default), write
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
|
||||
// Sample cg_arr_range: array range bin {[0:1]} -> av[0]=0, av[1]=1; cross 2x2
|
||||
// cg_arr_range: 2+2+4=8 bins; sample all combinations -> 100%
|
||||
%000001 addr = 0; cmd = 0; cg_arr_range_inst.sample(); // av[0] x read
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 addr = 0; cmd = 1; cg_arr_range_inst.sample(); // av[0] x write
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 addr = 1; cmd = 0; cg_arr_range_inst.sample(); // av[1] x read
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 addr = 1; cmd = 1; cg_arr_range_inst.sample(); // av[1] x write
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 `checkr(cg_arr_range_inst.get_inst_coverage(), 100.0); // 8/8
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
-000000 point: type=line comment=block hier=top.t
|
||||
-000001 point: type=line comment=else hier=top.t
|
||||
|
||||
// Sample cg_arr_vals: array value bin {0,2} -> av[0]=0, av[1]=2; cross 2x2
|
||||
// cg_arr_vals: 2+2+4=8 bins; sample all combinations -> 100%
|
||||
%000001 addr = 0; cmd = 0; cg_arr_vals_inst.sample(); // av[0] x read
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 addr = 0; cmd = 1; cg_arr_vals_inst.sample(); // av[0] x write
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 addr = 2; cmd = 0; cg_arr_vals_inst.sample(); // av[1] x read
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 addr = 2; cmd = 1; cg_arr_vals_inst.sample(); // av[1] x write
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 `checkr(cg_arr_vals_inst.get_inst_coverage(), 100.0); // 8/8
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
-000000 point: type=line comment=block hier=top.t
|
||||
-000001 point: type=line comment=else hier=top.t
|
||||
|
||||
// Sample cg_wild_arr: wildcard array {2'b0?} matches addr 0,1; cross 2x2
|
||||
// cg_wild_arr: 2+2+4=8 bins; sample all combinations -> 100%
|
||||
%000001 addr = 0; cmd = 0; cg_wild_arr_inst.sample();
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 addr = 0; cmd = 1; cg_wild_arr_inst.sample();
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 addr = 1; cmd = 0; cg_wild_arr_inst.sample();
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 addr = 1; cmd = 1; cg_wild_arr_inst.sample();
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 `checkr(cg_wild_arr_inst.get_inst_coverage(), 100.0); // 8/8
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
-000000 point: type=line comment=block hier=top.t
|
||||
-000001 point: type=line comment=else hier=top.t
|
||||
|
||||
// Sample cg_wild_solo: single wildcard bin {2'b0?} matches addr 0,1; cross 1x2
|
||||
// cg_wild_solo: 1+2+2=5 bins; sample both cmd values -> 100%
|
||||
%000001 addr = 0; cmd = 0; cg_wild_solo_inst.sample();
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 addr = 0; cmd = 1; cg_wild_solo_inst.sample();
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 `checkr(cg_wild_solo_inst.get_inst_coverage(), 100.0); // 5/5
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
-000000 point: type=line comment=block hier=top.t
|
||||
-000001 point: type=line comment=else hier=top.t
|
||||
|
||||
// Sample cg_arr_4state: 4-state literal bin {2'b0x} matches addr=0 (2-state sim); cross 1x2
|
||||
// cg_arr_4state: 1+2+2=5 bins; sample both cmd values -> 100%
|
||||
%000001 addr = 0; cmd = 0; cg_arr_4state_inst.sample();
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 addr = 0; cmd = 1; cg_arr_4state_inst.sample();
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 `checkr(cg_arr_4state_inst.get_inst_coverage(), 100.0); // 5/5
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
-000000 point: type=line comment=block hier=top.t
|
||||
-000001 point: type=line comment=else hier=top.t
|
||||
|
||||
// Sample cg_overlap: overlapping range bins lo={0,1}, hi={1,2}; cross 2x2
|
||||
// cg_overlap: 2+2+4=8 bins; cover lo/hi via addr 0 and 2, plus addr=1 double-hits both
|
||||
%000001 addr = 0; cmd = 0; cg_overlap_inst.sample(); // lo x read
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 addr = 0; cmd = 1; cg_overlap_inst.sample(); // lo x write
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 addr = 2; cmd = 0; cg_overlap_inst.sample(); // hi x read
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 addr = 2; cmd = 1; cg_overlap_inst.sample(); // hi x write
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 addr = 1; cmd = 0; cg_overlap_inst.sample(); // addr=1 in both lo and hi (hit-list bound 2)
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 `checkr(cg_overlap_inst.get_inst_coverage(), 100.0); // 8/8
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
-000000 point: type=line comment=block hier=top.t
|
||||
-000001 point: type=line comment=else hier=top.t
|
||||
|
||||
// Sample cg_wide: 64-bit coverpoint, lo={0,1}, hi={2,3}; cross 2x2
|
||||
// cg_wide: 2+2+4=8 bins; sample all combinations -> 100%
|
||||
%000001 wide = 0; cmd = 0; cg_wide_inst.sample(); // lo x read
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 wide = 0; cmd = 1; cg_wide_inst.sample(); // lo x write
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 wide = 2; cmd = 0; cg_wide_inst.sample(); // hi x read
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 wide = 2; cmd = 1; cg_wide_inst.sample(); // hi x write
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 `checkr(cg_wide_inst.get_inst_coverage(), 100.0); // 8/8
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
-000000 point: type=line comment=block hier=top.t
|
||||
-000001 point: type=line comment=else hier=top.t
|
||||
|
||||
// Sample cg_openrange: lo=[$:1] matches 0,1; hi=[2:$] matches 2,3; cross 2x2
|
||||
// cg_openrange: 2+2+4=8 bins; sample all combinations -> 100%
|
||||
%000001 addr = 0; cmd = 0; cg_openrange_inst.sample(); // lo x read
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 addr = 0; cmd = 1; cg_openrange_inst.sample(); // lo x write
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 addr = 2; cmd = 0; cg_openrange_inst.sample(); // hi x read
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 addr = 2; cmd = 1; cg_openrange_inst.sample(); // hi x write
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 `checkr(cg_openrange_inst.get_inst_coverage(), 100.0); // 8/8
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
-000000 point: type=line comment=block hier=top.t
|
||||
-000001 point: type=line comment=else hier=top.t
|
||||
|
||||
// Sample cg_inv: inverted range bin never matches; only cmd bins are hittable
|
||||
// cg_inv: 1+2+2=5 bins; inv and its 2 cross bins never hit -> 2/5=40%
|
||||
%000001 addr = 0; cmd = 0; cg_inv_inst.sample(); // read
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 addr = 1; cmd = 1; cg_inv_inst.sample(); // write
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 `checkr(cg_inv_inst.get_inst_coverage(), 40.0); // 2/5: read + write only
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
-000000 point: type=line comment=block hier=top.t
|
||||
-000001 point: type=line comment=else hier=top.t
|
||||
|
||||
// Sample cg_noNormal: coverpoint has no Normal bins; cross product is empty
|
||||
// cg_noNormal: 0+2+0=2 bins (cmd only); both hit -> 100%
|
||||
%000001 addr = 0; cmd = 0; cg_noNormal_inst.sample(); // read
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 addr = 1; cmd = 1; cg_noNormal_inst.sample(); // write
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 `checkr(cg_noNormal_inst.get_inst_coverage(), 100.0); // 2/2
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
-000000 point: type=line comment=block hier=top.t
|
||||
-000001 point: type=line comment=else hier=top.t
|
||||
|
||||
// Sample cg_trans: transition coverpoint crossed with a value coverpoint
|
||||
// cg_trans: 1+2+2=5 bins; t01_x_v6 never completes -> 4/5=80%
|
||||
// __Vprev_cp_t initializes to 0.
|
||||
%000001 state = 0; val = 5; cg_trans_inst.sample(); // prev=0,cur=0: no t01; v5
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 state = 1; val = 5; cg_trans_inst.sample(); // prev=0,cur=1: t01 completes; t01_x_v5
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 state = 0; val = 6; cg_trans_inst.sample(); // prev=1,cur=0: no t01; v6 (no cross)
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 `checkr(cg_trans_inst.get_inst_coverage(), 80.0); // 4/5: t01_x_v6 not hit
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
-000000 point: type=line comment=block hier=top.t
|
||||
-000001 point: type=line comment=else hier=top.t
|
||||
|
||||
%000001 $write("*-* All Finished *-*\n");
|
||||
-000001 point: type=line comment=block hier=top.t
|
||||
%000001 $finish;
|
||||
|
|
|
|||
Loading…
Reference in New Issue