This commit is contained in:
Matthew Ballance 2026-06-28 08:18:23 -07:00 committed by GitHub
commit 8bce24c7dc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 1470 additions and 681 deletions

View File

@ -41,9 +41,13 @@ enum class VlCovBinKind : uint8_t {
//============================================================================= //=============================================================================
// VlCoverpointIf // VlCoverpointIf
/// Read-side view of a coverpoint. The writer queries bins by index; the /// Read-side view of a coverpoint -- a named, index-addressable set of bins
/// implementor computes names/kinds on demand. Bounded bin count, so random /// with a coverage fraction. A cross is also a coverpoint from this view: its
/// access by index is the primary usage. /// 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 { class VlCoverpointIf VL_NOT_FINAL {
public: public:
@ -53,9 +57,9 @@ public:
// METHODS // METHODS
// All bins, across every set; index range [0, binCount()) // All bins, across every set; index range [0, binCount())
virtual int binCount() const = 0; 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 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 // Bins covered / effective total (Normal set only) for the coverage calc
virtual void coverageParts(double& covered, double& total) const = 0; virtual void coverageParts(double& covered, double& total) const = 0;
}; };

View File

@ -29,13 +29,28 @@ void VlCoverpoint::init(const char* hier, uint32_t atLeast, int nBins) {
m_atLeast = atLeast; m_atLeast = atLeast;
m_total = nBins; m_total = nBins;
m_counts.assign(nBins, 0); m_counts.assign(nBins, 0);
m_crossIdx.assign(nBins, -1);
} }
void VlCoverpoint::addNamer(VlCovBinKind set, int count, VlCovBinNaming naming, const char* name, void VlCoverpoint::addNamer(VlCovBinKind set, int count, VlCovBinNaming naming, const char* name,
const char* file, int line, int col) { const char* file, int line, int col) {
m_namers.emplace_back(set, count, m_nextBase, naming, name, file, line, 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; 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 { const VlCovNamer& VlCoverpoint::namerFor(int i) const {
@ -44,7 +59,7 @@ const VlCovNamer& VlCoverpoint::namerFor(int i) const {
for (const VlCovNamer& nm : m_namers) { for (const VlCovNamer& nm : m_namers) {
if (i < nm.base() + nm.count()) return nm; if (i < nm.base() + nm.count()) return nm;
} }
VL_UNREACHABLE; VL_UNREACHABLE; // LCOV_EXCL_LINE
} }
std::string VlCoverpoint::binName(int i) const { 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());
}
}

View File

@ -87,16 +87,25 @@ public:
/// bin's set/name come from the owning namer. coverage() is computed on demand /// 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. /// by scanning bin counts, keeping the sample() hot path a plain counter bump.
class VlCoverpoint final : public VlCoverpointIf { // Base coverpoint runtime (read side + collection logic, no hit-list storage).
// MEMBERS // 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" std::string m_hier; // "covergroup.coverpoint"
uint32_t m_atLeast = 1; // option.at_least (coverpoint-wide) uint32_t m_atLeast = 1; // option.at_least (coverpoint-wide)
int m_total = 0; // bins across all sets int m_total = 0; // bins across all sets
int m_normal = 0; // Normal bins (coverage denominator) int m_normal = 0; // Normal bins (coverage denominator)
int m_nextBase = 0; // running append cursor 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<uint32_t> m_counts; // [m_total], one per bin
std::vector<VlCovNamer> m_namers; // appended in declaration order 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 // PRIVATE METHODS
const VlCovNamer& namerFor(int i) const; // obtain the bin-specific name producer const VlCovNamer& namerFor(int i) const; // obtain the bin-specific name producer
void addNamer(VlCovBinKind set, int count, VlCovBinNaming naming, const char* name, void addNamer(VlCovBinKind set, int count, VlCovBinNaming naming, const char* name,
@ -119,13 +128,26 @@ public:
void registerBins(VerilatedCovContext* covcontextp, const char* page); void registerBins(VerilatedCovContext* covcontextp, const char* page);
// ---- hot path (from generated sample()) ---- // ---- hot path (from generated sample()) ----
void incrementBin(int i) { ++m_counts[i]; } // Normal bin: count only // Clear the hit list at the start of each sample() for a cross-fed coverpoint.
void recordHit(int i) { ++m_counts[i]; } // Ignore/Illegal/Default: count only 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 ---- // ---- VlCoverpointIf ----
int binCount() const override { return m_total; } int binCount() const override { return m_total; }
std::string binName(int i) const override; 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 { void coverageParts(double& covered, double& total) const override {
// Count Normal bins that reached option.at_least on demand, so the hot // Count Normal bins that reached option.at_least on demand, so the hot
// path (incrementBin) stays a plain counter bump. // path (incrementBin) stays a plain counter bump.
@ -141,4 +163,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 #endif // Guard

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,6 @@ cg7.cp.rev[0]: 1
cg7.cp.rev[1]: 0 cg7.cp.rev[1]: 0
cg8.cp.w[0]: 0 cg8.cp.w[0]: 0
cg8.cp.w[1]: 1 cg8.cp.w[1]: 1
cg9.__cross7.cumulative_x_lo [cross]: 1
cg9.__cross7.ok_x_lo [cross]: 1 cg9.__cross7.ok_x_lo [cross]: 1
cg9.cpA.ok: 1 cg9.cpA.ok: 1
cg9.cpB.lo: 1 cg9.cpB.lo: 1

View File

@ -85,4 +85,28 @@
: ... note: In instance 't' : ... note: In instance 't'
73 | bins b_huge[] = {[0:$]}; 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 %Error: Exiting due to

View File

@ -74,6 +74,48 @@ module t;
} }
endgroup 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; cg1 cg1_inst = new;
cg2 cg2_inst = new; cg2 cg2_inst = new;
cg2b cg2b_inst = new; cg2b cg2b_inst = new;
@ -81,6 +123,13 @@ module t;
cg4 cg4_inst = new; cg4 cg4_inst = new;
cg5 cg5_inst = new; cg5 cg5_inst = new;
cg6 cg6_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; initial $finish;
endmodule endmodule

View File

@ -57,6 +57,27 @@ cg5.cp_addr.addr0: 1
cg5.cp_addr.addr1: 1 cg5.cp_addr.addr1: 1
cg5.cp_cmd.read: 1 cg5.cp_cmd.read: 1
cg5.cp_cmd.write: 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_read [cross]: 1
cg_at_least.addr_cmd_al.addr0_x_write [cross]: 0 cg_at_least.addr_cmd_al.addr0_x_write [cross]: 0
cg_at_least.addr_cmd_al.addr1_x_read [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.axc.a1_x_write [cross]: 0
cg_def_cross.cp_a.a0: 1 cg_def_cross.cp_a.a0: 1
cg_def_cross.cp_a.a1: 0 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.read: 1
cg_def_cross.cp_c.write: 1 cg_def_cross.cp_c.write: 1
cg_goal.addr_cmd_goal.addr0_x_read [cross]: 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.a0_x_write [cross]: 1
cg_ignore.cross_ab.a1_x_read [cross]: 1 cg_ignore.cross_ab.a1_x_read [cross]: 1
cg_ignore.cross_ab.a1_x_write [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_read [cross]: 1
cg_mixed.ab.addr0_x_write [cross]: 1 cg_mixed.ab.addr0_x_write [cross]: 1
cg_mixed.ab.addr1_x_read [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_cmd.write: 2
cg_mixed.cp_solo.debug: 2 cg_mixed.cp_solo.debug: 2
cg_mixed.cp_solo.normal: 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_read [cross]: 1
cg_range.addr_cmd_range.hi_range_x_write [cross]: 1 cg_range.addr_cmd_range.hi_range_x_write [cross]: 1
cg_range.addr_cmd_range.lo_range_x_read [cross]: 1 cg_range.addr_cmd_range.lo_range_x_read [cross]: 1
@ -109,6 +154,11 @@ cg_range.cp_addr.hi_range: 2
cg_range.cp_addr.lo_range: 2 cg_range.cp_addr.lo_range: 2
cg_range.cp_cmd.read: 2 cg_range.cp_cmd.read: 2
cg_range.cp_cmd.write: 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_read [cross]: 1
cg_unnamed_cross.__cross8.a0_x_write [cross]: 0 cg_unnamed_cross.__cross8.a0_x_write [cross]: 0
cg_unnamed_cross.__cross8.a1_x_read [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_addr.addr1: 1
cg_unsup_cross_opt.cp_cmd.read: 1 cg_unsup_cross_opt.cp_cmd.read: 1
cg_unsup_cross_opt.cp_cmd.write: 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

View File

@ -16,6 +16,9 @@ module t;
logic cmd; logic cmd;
logic mode; logic mode;
logic parity; 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; typedef struct packed {logic m_p; logic h_mode;} cfg_t;
cfg_t s_cfg = '0; cfg_t s_cfg = '0;
@ -108,8 +111,8 @@ module t;
cross cp_a, cp_c; // no label: reported under the default cross name cross cp_a, cp_c; // no label: reported under the default cross name
endgroup endgroup
// Cross plus an un-crossed coverpoint: get_inst_coverage must combine the converted // Cross plus an un-crossed coverpoint: get_inst_coverage must combine the un-crossed
// (VlCoverpoint) coverpoint cp_solo with the legacy cross/crossed-coverpoint bins. // coverpoint cp_solo with the cross and its crossed coverpoints.
covergroup cg_mixed; covergroup cg_mixed;
cp_addr: coverpoint addr {bins addr0 = {0}; bins addr1 = {1};} cp_addr: coverpoint addr {bins addr0 = {0}; bins addr1 = {1};}
cp_cmd: coverpoint cmd {bins read = {0}; bins write = {1};} cp_cmd: coverpoint cmd {bins read = {0}; bins write = {1};}
@ -117,14 +120,108 @@ module t;
ab: cross cp_addr, cp_cmd; ab: cross cp_addr, cp_cmd;
endgroup endgroup
// Crossed (hence non-convertible) coverpoint that also has a default bin: exercises the // Crossed coverpoint that also has a default bin: exercises default-bin handling on a
// legacy default-bin codegen path that converted coverpoints bypass. // coverpoint that feeds a cross.
covergroup cg_def_cross; covergroup cg_def_cross;
cp_a: coverpoint addr iff (mode) {bins a0 = {0}; bins a1 = {1}; bins ad = default;} 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};} cp_c: coverpoint cmd {bins read = {0}; bins write = {1};}
axc: cross cp_a, cp_c; axc: cross cp_a, cp_c;
endgroup 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; cg2 cg2_inst = new;
cg_ignore cg_ignore_inst = new; cg_ignore cg_ignore_inst = new;
cg_range cg_range_inst = new; cg_range cg_range_inst = new;
@ -137,6 +234,17 @@ module t;
cg_unnamed_cross cg_unnamed_cross_inst = new; cg_unnamed_cross cg_unnamed_cross_inst = new;
cg_mixed cg_mixed_inst = new; cg_mixed cg_mixed_inst = new;
cg_def_cross cg_def_cross_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 initial begin
// Sample 2-way: hit all 4 combinations // 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 = 0; cmd = 0; cg_def_cross_inst.sample(); // a0, read
addr = 2; cmd = 1; cg_def_cross_inst.sample(); // ad (default), write 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"); $write("*-* All Finished *-*\n");
$finish; $finish;
end end

View File

@ -7,5 +7,7 @@ cg.cp_trans2.trans2: 1
cg.cp_trans2.trans3: 1 cg.cp_trans2.trans3: 1
cg.cp_trans3.seq_a: 1 cg.cp_trans3.seq_a: 1
cg.cp_trans3.seq_b: 1 cg.cp_trans3.seq_b: 1
cg_legacy.cp_mix.tr: 1 cg_array.cp_mix.tr: 1
cg_legacy.cp_mix.vals: 1 cg_array.cp_mix.vals[0]: 1
cg_array.cp_mix.vals[1]: 0
cg_array.cp_mix.vals[2]: 0

View File

@ -39,17 +39,18 @@ module t;
} }
endgroup endgroup
// Non-convertible coverpoint (it has a transition bin) that also carries a value-array bin, // Coverpoint mixing a transition bin and a value-array bin: both route through the
// so the legacy array codegen path (which converted coverpoints bypass) is still exercised. // VlCoverpoint runtime (the value array reports indexed as vals[0]..vals[N-1], like every
covergroup cg_legacy; // other array bin; the transition records into its own runtime bin).
covergroup cg_array;
cp_mix: coverpoint state { cp_mix: coverpoint state {
bins tr = (0 => 1); 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 endgroup
cg cg_inst = new; cg cg_inst = new;
cg_legacy cg_legacy_inst = new; cg_array cg_array_inst = new;
initial begin initial begin
// Drive sequence 0->1->2->3->4 which hits all bins // 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 cg_inst.sample(); // 3=>4: seq_b done
`checkr(cg_inst.get_inst_coverage(), 100.0); `checkr(cg_inst.get_inst_coverage(), 100.0);
// cg_legacy: exercise legacy array codegen (non-convertible coverpoint) // cg_array: exercise the mixed transition + value-array coverpoint
state = 0; cg_legacy_inst.sample(); state = 0; cg_array_inst.sample();
state = 1; cg_legacy_inst.sample(); // 0=>1: tr state = 1; cg_array_inst.sample(); // 0=>1: tr
state = 2; cg_legacy_inst.sample(); // vals state = 2; cg_array_inst.sample(); // vals
state = 3; cg_legacy_inst.sample(); // vals state = 3; cg_array_inst.sample(); // vals
$write("*-* All Finished *-*\n"); $write("*-* All Finished *-*\n");
$finish; $finish;

View File

@ -14,9 +14,9 @@
module t; module t;
%000001 logic [1:0] addr; %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 -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 -000000 point: type=toggle comment=addr[1]:1->0 hier=top.t
%000001 logic cmd; %000001 logic cmd;
-000001 point: type=toggle comment=cmd:0->1 hier=top.t -000001 point: type=toggle comment=cmd:0->1 hier=top.t
@ -27,6 +27,153 @@
%000001 logic parity; %000001 logic parity;
-000001 point: type=toggle comment=parity:0->1 hier=top.t -000001 point: type=toggle comment=parity:0->1 hier=top.t
-000000 point: type=toggle comment=parity:1->0 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; typedef struct packed {logic m_p; logic h_mode;} cfg_t;
%000001 cfg_t s_cfg = '0; %000001 cfg_t s_cfg = '0;
@ -292,8 +439,8 @@
// cross: [a1, write] // cross: [a1, write]
endgroup endgroup
// Cross plus an un-crossed coverpoint: get_inst_coverage must combine the converted // Cross plus an un-crossed coverpoint: get_inst_coverage must combine the un-crossed
// (VlCoverpoint) coverpoint cp_solo with the legacy cross/crossed-coverpoint bins. // coverpoint cp_solo with the cross and its crossed coverpoints.
covergroup cg_mixed; covergroup cg_mixed;
%000002 cp_addr: coverpoint addr {bins addr0 = {0}; bins addr1 = {1};} %000002 cp_addr: coverpoint addr {bins addr0 = {0}; bins addr1 = {1};}
-000002 point: type=covergroup comment= hier=cg_mixed.cp_addr.addr0 -000002 point: type=covergroup comment= hier=cg_mixed.cp_addr.addr0
@ -315,8 +462,8 @@
// cross: [addr1, write] // cross: [addr1, write]
endgroup endgroup
// Crossed (hence non-convertible) coverpoint that also has a default bin: exercises the // Crossed coverpoint that also has a default bin: exercises default-bin handling on a
// legacy default-bin codegen path that converted coverpoints bypass. // coverpoint that feeds a cross.
covergroup cg_def_cross; covergroup cg_def_cross;
%000001 cp_a: coverpoint addr iff (mode) {bins a0 = {0}; bins a1 = {1}; bins ad = default;} %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 -000001 point: type=covergroup comment= hier=cg_def_cross.cp_a.a0
@ -336,6 +483,198 @@
// cross: [a1, write] // cross: [a1, write]
endgroup 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 cg2 cg2_inst = new;
-000001 point: type=line comment=block hier=top.t -000001 point: type=line comment=block hier=top.t
%000001 cg_ignore cg_ignore_inst = new; %000001 cg_ignore cg_ignore_inst = new;
@ -360,6 +699,28 @@
-000001 point: type=line comment=block hier=top.t -000001 point: type=line comment=block hier=top.t
%000001 cg_def_cross cg_def_cross_inst = new; %000001 cg_def_cross cg_def_cross_inst = new;
-000001 point: type=line comment=block hier=top.t -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 initial begin
-000001 point: type=line comment=block hier=top.t -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 addr = 2; cmd = 1; cg_def_cross_inst.sample(); // ad (default), write
-000001 point: type=line comment=block hier=top.t -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 $write("*-* All Finished *-*\n");
-000001 point: type=line comment=block hier=top.t -000001 point: type=line comment=block hier=top.t
%000001 $finish; %000001 $finish;