mirror of
https://github.com/verilator/verilator.git
synced 2026-10-02 16:13:34 +02:00
Support coverpoint bin 'with' filters (#8518)
This commit is contained in:
@@ -26,6 +26,7 @@
|
||||
#include "verilated.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <tuple>
|
||||
|
||||
// This file is compiled whenever covergroups are used, with or without
|
||||
@@ -121,7 +122,21 @@ struct VlCoverpoint::ValueData final {
|
||||
std::vector<SizedElement> m_elements; // In declaration order
|
||||
std::vector<SizedFast> m_fast; // The elements, if none is wider than 64 bits
|
||||
uint64_t m_fastPerBin = 0; // B, with m_fast
|
||||
bool m_sorted = false; // Elements disjoint and in value order
|
||||
bool m_unit = false; // B is one, so positions, which are bins, are below 2^33
|
||||
};
|
||||
// The bins of a 'with' filter being built (IEEE 1800-2023 19.5.1.1)
|
||||
struct With final {
|
||||
VlCovBinGrouping m_grouping = VlCovBinGrouping::Single; // How the bins hold values
|
||||
uint32_t m_limit = 0; // Most bins, or runs of values kept
|
||||
size_t m_next = 0; // Candidate runs withNext() gave, of m_sizedElements
|
||||
bool m_candidates = false; // More than CANDIDATE_LIMIT candidates: no bins
|
||||
bool m_full = false; // Too many values kept: no bins
|
||||
std::vector<Range> m_kept; // Runs of values kept, in order
|
||||
Value m_values; // Values of m_kept, a position, for Values grouping
|
||||
};
|
||||
// Candidates each bin's filter may evaluate, when the covergroup is constructed
|
||||
static constexpr QData CANDIDATE_LIMIT = 1ULL << 32;
|
||||
|
||||
// MEMBERS
|
||||
const uint32_t m_bits; // Width of the coverpoint's effective integral type
|
||||
@@ -134,6 +149,7 @@ struct VlCoverpoint::ValueData final {
|
||||
std::vector<uint32_t> m_reported; // Declared bins that have values, in declaration order
|
||||
std::vector<Sized> m_sized; // Sized arrays, in sizedFinish() order
|
||||
std::vector<SizedElement> m_sizedElements; // sizedRange() elements of the next array
|
||||
With m_with; // The bins of a 'with' filter being built
|
||||
|
||||
ValueData(uint32_t bits, bool isSigned, uint32_t bins)
|
||||
: m_bits{bits}
|
||||
@@ -215,6 +231,36 @@ struct VlCoverpoint::ValueData final {
|
||||
uint64_t orderValue(uint64_t value) const {
|
||||
return m_isSigned ? value ^ VL_BIT_Q(m_bits - 1) : value;
|
||||
}
|
||||
// Add the number of values lo..hi, lo not after hi, to the position 'total'
|
||||
void countValues(const Value& lo, const Value& hi, Value& total) const {
|
||||
increase(total, distance(view(lo), view(hi)));
|
||||
increase(total, toPosition(1));
|
||||
}
|
||||
// The decimal value of a bin of a 'with' filter's array of a bin per value, which names it
|
||||
std::string valueName(uint32_t bin) const {
|
||||
// Arrays hold consecutive bins, so the last array starting at or before the bin holds it
|
||||
const Sized& sized = *std::prev(std::upper_bound(
|
||||
m_sized.begin(), m_sized.end(), bin,
|
||||
[](uint32_t index, const Sized& array) { return index < array.m_first; }));
|
||||
const uint32_t offset = bin - sized.m_first;
|
||||
// Its elements are runs of its bins' values, each at the position of its first's bin
|
||||
const SizedElement& element
|
||||
= *std::prev(std::upper_bound(sized.m_elements.begin(), sized.m_elements.end(), offset,
|
||||
[](uint32_t index, const SizedElement& run) {
|
||||
return index < number(run.m_position);
|
||||
}));
|
||||
Value value = element.m_lo;
|
||||
add(value, toPosition(offset - number(element.m_position)));
|
||||
if (m_bits <= VL_QUADSIZE) {
|
||||
const uint64_t word = number(value);
|
||||
return m_isSigned
|
||||
? std::to_string(static_cast<int64_t>(VL_EXTENDS_QQ(64, m_bits, word)))
|
||||
: std::to_string(word);
|
||||
}
|
||||
return VL_SFORMATF_N_NX("%0d", 1,
|
||||
m_isSigned ? VL_VFORMATATTR_SIGNED : VL_VFORMATATTR_UNSIGNED,
|
||||
static_cast<int>(m_bits), value.data());
|
||||
}
|
||||
bool contains(const Range& range, WDataInP value) const {
|
||||
if (less(value, range.m_lo) || less(range.m_hi, value)) return false;
|
||||
if (!range.m_mask.empty()) {
|
||||
@@ -652,6 +698,21 @@ void VlCoverpoint::sizedRangeW(WDataInP lop, WDataInP hip) {
|
||||
data.m_sizedElements.push_back({data.read(lop), data.read(hip), {}});
|
||||
}
|
||||
|
||||
// Warn that the bins 'name' are ignored, because of 'reason'. From an mtask, VL_WARN_MT reports
|
||||
// after returning, so the text is kept for the program, once for all instances.
|
||||
static void _vl_cov_warn_ignored(const char* file, int line, const char* reason,
|
||||
const char* name) VL_MT_SAFE {
|
||||
static VerilatedMutex s_mutex;
|
||||
static std::set<std::string> s_texts; // Texts of the warnings
|
||||
std::string text = std::string{reason} + "; bin '" + name + "' ignored";
|
||||
const char* textp;
|
||||
{
|
||||
const VerilatedLockGuard lock{s_mutex};
|
||||
textp = s_texts.insert(std::move(text)).first->c_str();
|
||||
}
|
||||
VL_WARN_MT(file, line, "", textp);
|
||||
}
|
||||
|
||||
void VlCoverpoint::sizedFinish(VlCovBinKind kind, QData count, bool positive, uint32_t limit,
|
||||
const char* name, const char* file, int line, int col) {
|
||||
ValueData& data = *m_valuesp;
|
||||
@@ -664,9 +725,9 @@ void VlCoverpoint::sizedFinish(VlCovBinKind kind, QData count, bool positive, ui
|
||||
if (VL_UNLIKELY(!positive)) {
|
||||
// An error, after which (+verilator+error+limit) the array has no bins
|
||||
sized.m_elements.clear();
|
||||
VL_PRINTF_MT("%%Error: %s:%d: Coverage bin array size must be a positive integer"
|
||||
VL_PRINTF_MT("%%Error: %s:%d: Coverage bin array '%s' size must be a positive integer"
|
||||
" (IEEE 1800-2023 19.5.1)\n",
|
||||
file, line);
|
||||
file, line, name);
|
||||
VL_STOP_MT(file, line, "");
|
||||
return;
|
||||
}
|
||||
@@ -684,14 +745,20 @@ void VlCoverpoint::sizedFinish(VlCovBinKind kind, QData count, bool positive, ui
|
||||
const ValueData::Value& bins = fewer ? total : declared;
|
||||
if (data.compare(bins, data.toPosition(std::min(limit, UINT32_MAX - m_total))) > 0) {
|
||||
sized.m_elements.clear();
|
||||
VL_WARN_MT(file, line, "",
|
||||
"Coverage bin array needs more bins than --coverage-max-bins; bin ignored");
|
||||
_vl_cov_warn_ignored(file, line,
|
||||
"Coverage bin array needs more bins than --coverage-max-bins", name);
|
||||
return;
|
||||
}
|
||||
sized.m_count = bins[0];
|
||||
if (!sized.m_count) return;
|
||||
sized.m_perBin = one;
|
||||
if (!fewer) data.quotient(total, declared, sized.m_perBin);
|
||||
sized.m_unit = data.compare(sized.m_perBin, one) == 0;
|
||||
// Disjoint elements in value order hold a value in one at most, which a binary search finds
|
||||
sized.m_sorted = true;
|
||||
for (size_t i = 1; sized.m_sorted && i < sized.m_elements.size(); ++i) {
|
||||
sized.m_sorted = data.less(sized.m_elements[i - 1].m_hi, sized.m_elements[i].m_lo);
|
||||
}
|
||||
assert(m_nextBase == m_total);
|
||||
m_total += sized.m_count;
|
||||
m_counts.resize(m_total, 0);
|
||||
@@ -751,6 +818,170 @@ uint32_t VlCoverpoint::sizedEnd(uint32_t sized) const {
|
||||
return data.m_first + data.m_count;
|
||||
}
|
||||
|
||||
void VlCoverpoint::withBegin(VlCovBinGrouping grouping, uint32_t limit) {
|
||||
ValueData& data = *m_valuesp;
|
||||
ValueData::With& with = data.m_with;
|
||||
with = ValueData::With{};
|
||||
with.m_grouping = grouping;
|
||||
with.m_limit = std::min(limit, UINT32_MAX - m_total); // Bins index with 32 bits
|
||||
with.m_values = ValueData::Value{data.positionWords()};
|
||||
std::vector<ValueData::SizedElement>& elements = data.m_sizedElements;
|
||||
if (grouping != VlCovBinGrouping::Fixed) {
|
||||
// One bin, or a bin per value, holds a set of values, so the filter tests each
|
||||
// candidate once, in value order: then the values it keeps come in order, and the
|
||||
// limits hold when checked as they come
|
||||
std::vector<ValueData::Range> ranges;
|
||||
for (ValueData::SizedElement& element : elements) {
|
||||
ranges.push_back({std::move(element.m_lo), std::move(element.m_hi), {}});
|
||||
}
|
||||
data.normalize(ranges);
|
||||
elements.clear();
|
||||
for (ValueData::Range& range : ranges) {
|
||||
elements.push_back({std::move(range.m_lo), std::move(range.m_hi), {}});
|
||||
}
|
||||
}
|
||||
// The filter is evaluated for each candidate, so bound the construction time
|
||||
ValueData::Value candidates{data.positionWords()};
|
||||
for (const ValueData::SizedElement& element : elements) {
|
||||
data.countValues(element.m_lo, element.m_hi, candidates);
|
||||
}
|
||||
with.m_candidates = data.compare(candidates, data.toPosition(ValueData::CANDIDATE_LIMIT)) > 0;
|
||||
if (with.m_candidates) elements.clear();
|
||||
}
|
||||
|
||||
bool VlCoverpoint::withNext() {
|
||||
ValueData& data = *m_valuesp;
|
||||
ValueData::With& with = data.m_with;
|
||||
if (with.m_full || with.m_next == data.m_sizedElements.size()) return false;
|
||||
++with.m_next;
|
||||
return true;
|
||||
}
|
||||
|
||||
QData VlCoverpoint::withLo() const {
|
||||
const ValueData& data = *m_valuesp;
|
||||
return ValueData::number(data.m_sizedElements[data.m_with.m_next - 1].m_lo);
|
||||
}
|
||||
|
||||
void VlCoverpoint::withLoW(WDataOutP valuep) const {
|
||||
const ValueData& data = *m_valuesp;
|
||||
const ValueData::Value& value = data.m_sizedElements[data.m_with.m_next - 1].m_lo;
|
||||
std::copy(value.begin(), value.end(), valuep.datap());
|
||||
}
|
||||
|
||||
QData VlCoverpoint::withHi() const {
|
||||
const ValueData& data = *m_valuesp;
|
||||
return ValueData::number(data.m_sizedElements[data.m_with.m_next - 1].m_hi);
|
||||
}
|
||||
|
||||
void VlCoverpoint::withHiW(WDataOutP valuep) const {
|
||||
const ValueData& data = *m_valuesp;
|
||||
const ValueData::Value& value = data.m_sizedElements[data.m_with.m_next - 1].m_hi;
|
||||
std::copy(value.begin(), value.end(), valuep.datap());
|
||||
}
|
||||
|
||||
bool VlCoverpoint::withRun(QData lo, QData hi) {
|
||||
VlWide<VL_WQ_WORDS_E> low;
|
||||
VlWide<VL_WQ_WORDS_E> high;
|
||||
VL_SET_WQ(low, lo);
|
||||
VL_SET_WQ(high, hi);
|
||||
return withRunW(low, high);
|
||||
}
|
||||
|
||||
bool VlCoverpoint::withRunW(WDataInP lop, WDataInP hip) {
|
||||
ValueData& data = *m_valuesp;
|
||||
ValueData::With& with = data.m_with;
|
||||
ValueData::Value lo = data.read(lop);
|
||||
ValueData::Value hi = data.read(hip);
|
||||
const bool values = with.m_grouping == VlCovBinGrouping::Values;
|
||||
if (values) data.countValues(lo, hi, with.m_values);
|
||||
std::vector<ValueData::Range>& kept = with.m_kept;
|
||||
ValueData::Value next;
|
||||
if (!kept.empty()) {
|
||||
next = kept.back().m_hi;
|
||||
data.increment(next);
|
||||
}
|
||||
if (!kept.empty() && next == lo && data.less(kept.back().m_hi, lo)) {
|
||||
kept.back().m_hi = std::move(hi); // Continues the last run
|
||||
} else {
|
||||
kept.push_back({std::move(lo), std::move(hi), {}});
|
||||
}
|
||||
// Bins each of a value, or runs of values, beyond the limit have too much memory. Neither
|
||||
// count decreases as values come, so the bins are then ignored.
|
||||
with.m_full = values ? data.compare(with.m_values, data.toPosition(with.m_limit)) > 0
|
||||
: kept.size() > with.m_limit;
|
||||
return !with.m_full;
|
||||
}
|
||||
|
||||
void VlCoverpoint::withFinish(VlCovBinKind kind, QData count, bool positive, const char* name,
|
||||
const char* file, int line, int col) {
|
||||
ValueData& data = *m_valuesp;
|
||||
assert(!data.m_frozen);
|
||||
ValueData::With& with = data.m_with;
|
||||
std::vector<ValueData::Range> kept;
|
||||
kept.swap(with.m_kept);
|
||||
data.m_sizedElements.clear();
|
||||
const bool values = with.m_grouping == VlCovBinGrouping::Values;
|
||||
if (VL_UNLIKELY(with.m_candidates || with.m_full)) {
|
||||
kept.clear();
|
||||
_vl_cov_warn_ignored(
|
||||
file, line,
|
||||
with.m_candidates ? "Coverage bin 'with' filter has more than 2**32 candidate values"
|
||||
: values ? "Coverage bin array needs more bins than --coverage-max-bins"
|
||||
: "Coverage bin 'with' filter keeps values in more ranges than"
|
||||
" --coverage-max-bins",
|
||||
name);
|
||||
}
|
||||
if (with.m_grouping == VlCovBinGrouping::Fixed) {
|
||||
// Filtered first, then distributed (IEEE 1800-2023 19.5.1.1)
|
||||
for (ValueData::Range& range : kept) {
|
||||
data.m_sizedElements.push_back({std::move(range.m_lo), std::move(range.m_hi), {}});
|
||||
}
|
||||
sizedFinish(kind, count, positive, with.m_limit, name, file, line, col);
|
||||
return;
|
||||
}
|
||||
data.m_sized.emplace_back();
|
||||
ValueData::Sized& sized = data.m_sized.back();
|
||||
sized.m_kind = kind;
|
||||
sized.m_first = m_total;
|
||||
if (kept.empty()) return; // No bin without a value (IEEE 1800-2023 19.11.1)
|
||||
// The values, disjoint runs in order (see withBegin), of a bin each at its position, or of
|
||||
// one bin
|
||||
ValueData::Value position{data.positionWords()};
|
||||
for (const ValueData::Range& range : kept) {
|
||||
sized.m_elements.push_back({range.m_lo, range.m_hi, position});
|
||||
if (data.m_bits <= VL_QUADSIZE) {
|
||||
sized.m_fast.push_back({data.orderValue(ValueData::number(range.m_lo)),
|
||||
data.orderValue(ValueData::number(range.m_hi)),
|
||||
ValueData::number(position)});
|
||||
}
|
||||
if (values) data.countValues(range.m_lo, range.m_hi, position);
|
||||
}
|
||||
sized.m_count = values ? static_cast<uint32_t>(ValueData::number(position)) : 1;
|
||||
sized.m_perBin = data.toPosition(1);
|
||||
sized.m_fastPerBin = 1;
|
||||
sized.m_sorted = true;
|
||||
sized.m_unit = true;
|
||||
assert(m_nextBase == m_total);
|
||||
m_total += sized.m_count;
|
||||
m_counts.resize(m_total, 0);
|
||||
m_crossIdx.resize(m_total, -1);
|
||||
data.m_values.resize(m_total);
|
||||
addNamer(kind, sized.m_count, values ? VlCovBinNaming::Values : VlCovBinNaming::Single, name,
|
||||
file, line, col);
|
||||
// Give each bin its values, for exclusions and cross selections
|
||||
uint32_t bin = sized.m_first;
|
||||
for (ValueData::Range& range : kept) {
|
||||
if (!values) {
|
||||
data.m_values[bin].m_ranges.push_back(std::move(range));
|
||||
continue;
|
||||
}
|
||||
for (ValueData::Value value = range.m_lo; true; data.increment(value)) {
|
||||
data.m_values[bin++].m_ranges.push_back({value, value, {}});
|
||||
if (value == range.m_hi) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool VlCoverpoint::sizedSample(uint32_t sized, QData value, bool enabled) {
|
||||
ValueData& data = *m_valuesp;
|
||||
const ValueData::Sized& array = data.m_sized[sized];
|
||||
@@ -760,8 +991,19 @@ bool VlCoverpoint::sizedSample(uint32_t sized, QData value, bool enabled) {
|
||||
return sizedSampleW(sized, words, enabled);
|
||||
}
|
||||
const uint64_t ordered = data.orderValue(value);
|
||||
auto beginIt = array.m_fast.begin();
|
||||
auto endIt = array.m_fast.end();
|
||||
if (array.m_sorted) {
|
||||
// Of disjoint runs in value order, only the last one starting by the value may hold it
|
||||
endIt = std::upper_bound(beginIt, endIt, ordered,
|
||||
[](uint64_t candidate, const ValueData::SizedFast& run) {
|
||||
return candidate < run.m_lo;
|
||||
});
|
||||
if (endIt != beginIt) beginIt = std::prev(endIt);
|
||||
}
|
||||
uint32_t last = UINT32_MAX; // No bin yet; bins index below UINT32_MAX
|
||||
for (const ValueData::SizedFast& element : array.m_fast) {
|
||||
for (auto it = beginIt; it != endIt; ++it) {
|
||||
const ValueData::SizedFast& element = *it;
|
||||
if (ordered < element.m_lo || ordered > element.m_hi) continue;
|
||||
const uint64_t bin = (element.m_position + (ordered - element.m_lo)) / array.m_fastPerBin;
|
||||
// Bins past the last hold none; it holds the remaining values
|
||||
@@ -775,16 +1017,36 @@ bool VlCoverpoint::sizedSample(uint32_t sized, QData value, bool enabled) {
|
||||
bool VlCoverpoint::sizedSampleW(uint32_t sized, WDataInP valuep, bool enabled) {
|
||||
ValueData& data = *m_valuesp;
|
||||
const ValueData::Sized& array = data.m_sized[sized];
|
||||
auto beginIt = array.m_elements.begin();
|
||||
auto endIt = array.m_elements.end();
|
||||
if (array.m_sorted) {
|
||||
// Of disjoint runs in value order, only the last one starting by the value may hold it
|
||||
endIt = std::upper_bound(beginIt, endIt, valuep,
|
||||
[&](WDataInP candidate, const ValueData::SizedElement& element) {
|
||||
return data.less(candidate, element.m_lo);
|
||||
});
|
||||
if (endIt != beginIt) beginIt = std::prev(endIt);
|
||||
}
|
||||
uint32_t last = UINT32_MAX; // No bin yet; bins index below UINT32_MAX
|
||||
for (const ValueData::SizedElement& element : array.m_elements) {
|
||||
for (auto it = beginIt; it != endIt; ++it) {
|
||||
const ValueData::SizedElement& element = *it;
|
||||
if (data.less(valuep, element.m_lo) || data.less(element.m_hi, valuep)) continue;
|
||||
ValueData::Value position = data.distance(ValueData::view(element.m_lo), valuep);
|
||||
data.increase(position, element.m_position);
|
||||
ValueData::Value bin{data.positionWords()};
|
||||
data.quotient(position, array.m_perBin, bin);
|
||||
const bool past = !data.narrow(bin) || ValueData::number(bin) >= array.m_count;
|
||||
uint64_t bin = UINT64_MAX; // Past the last bin
|
||||
if (array.m_unit) {
|
||||
// A value's position is its bin, below 2^33 (see m_unit): the sum of the element's
|
||||
// position and the low 64 bits of the value's distance from the element's first value
|
||||
bin = ValueData::number(element.m_position)
|
||||
+ (VL_SET_QW(valuep) - ValueData::number(element.m_lo));
|
||||
} else {
|
||||
ValueData::Value position = data.distance(ValueData::view(element.m_lo), valuep);
|
||||
data.increase(position, element.m_position);
|
||||
ValueData::Value quotient{data.positionWords()};
|
||||
data.quotient(position, array.m_perBin, quotient);
|
||||
if (data.narrow(quotient)) bin = ValueData::number(quotient);
|
||||
}
|
||||
// Bins past the last hold none; it holds the remaining values
|
||||
sizedHit(array.m_kind,
|
||||
array.m_first + (past ? array.m_count - 1 : static_cast<uint32_t>(bin[0])),
|
||||
array.m_first + static_cast<uint32_t>(std::min<uint64_t>(bin, array.m_count - 1)),
|
||||
enabled, last);
|
||||
}
|
||||
return last != UINT32_MAX;
|
||||
@@ -847,6 +1109,8 @@ std::string VlCoverpoint::declaredBinName(uint32_t bin) const {
|
||||
name += '[' + std::to_string(bin - nm.base()) + ']';
|
||||
} else if (nm.naming() == VlCovBinNaming::Numbered) {
|
||||
name += '_' + std::to_string(bin - nm.base());
|
||||
} else if (nm.naming() == VlCovBinNaming::Values) {
|
||||
name += '[' + m_valuesp->valueName(bin) + ']';
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -51,6 +51,14 @@ enum class VlCovBinNaming : uint8_t {
|
||||
Single, // "<name>" one bin
|
||||
Array, // "<name>[i]" bins b[N] value array
|
||||
Numbered, // "<name>_<i>" automatic bins of a coverpoint without bins
|
||||
Values, // "<name>[v]" bins b[] with a 'with' filter, a bin per value v
|
||||
};
|
||||
|
||||
// How the bins of a 'with' filter (IEEE 1800-2023 19.5.1.1) hold the values it keeps
|
||||
enum class VlCovBinGrouping : uint8_t {
|
||||
Single, // bins b = ...: one bin
|
||||
Values, // bins b[] = ...: a bin for each value, in value order
|
||||
Fixed, // bins b[N] = ...: distributed over N bins, as a sized array's
|
||||
};
|
||||
|
||||
// Specifies the naming scheme for a range of bins, allowing the
|
||||
@@ -192,6 +200,24 @@ public:
|
||||
/// sizedFinish() order, for cross selections.
|
||||
uint32_t sizedFirst(uint32_t sized) const;
|
||||
uint32_t sizedEnd(uint32_t sized) const;
|
||||
/// Begin the bins of a 'with' filter (IEEE 1800-2023 19.5.1.1), whose candidates are the
|
||||
/// values sizedRange() added, and whose bins then count as a sized array's. At most
|
||||
/// 'limit' bins, or runs of values kept.
|
||||
void withBegin(VlCovBinGrouping grouping, uint32_t limit);
|
||||
/// Advance to the next run of candidates, withLo() to withHi(); false after the last, or
|
||||
/// once too many values are kept
|
||||
bool withNext();
|
||||
QData withLo() const;
|
||||
void withLoW(WDataOutP valuep) const;
|
||||
QData withHi() const;
|
||||
void withHiW(WDataOutP valuep) const;
|
||||
/// Keep the values lo..hi, in the order the filter kept them; false once too many are
|
||||
bool withRun(QData lo, QData hi);
|
||||
bool withRunW(WDataInP lop, WDataInP hip);
|
||||
/// Make the bins of the values kept, a sized array 'name[count]' for Fixed grouping (see
|
||||
/// sizedFinish())
|
||||
void withFinish(VlCovBinKind kind, QData count, bool positive, const char* name,
|
||||
const char* file, int line, int col);
|
||||
|
||||
// ---- hot path (from generated sample()) ----
|
||||
// Clear the hit list at the start of each sample() for a cross-fed coverpoint.
|
||||
|
||||
@@ -915,6 +915,15 @@ inline std::ostream& operator<<(std::ostream& os, const VBranchPred& rhs) {
|
||||
macro(COVERGROUP_VALUE_TRANSITIONS, "valueTransitions", false, "r") \
|
||||
macro(COVERGROUP_VALUE_TYPE, "valueType", false, "rr") \
|
||||
macro(COVERGROUP_WEIGHT, "weight", false, "rr") \
|
||||
macro(COVERGROUP_WITH_BEGIN, "withBegin", false, "rr") \
|
||||
macro(COVERGROUP_WITH_FINISH, "withFinish", false, "r+") \
|
||||
macro(COVERGROUP_WITH_HI, "withHi", false, "") \
|
||||
macro(COVERGROUP_WITH_HI_W, "withHiW", false, "w") \
|
||||
macro(COVERGROUP_WITH_LO, "withLo", false, "") \
|
||||
macro(COVERGROUP_WITH_LO_W, "withLoW", false, "w") \
|
||||
macro(COVERGROUP_WITH_NEXT, "withNext", false, "") \
|
||||
macro(COVERGROUP_WITH_RUN, "withRun", false, "rr") \
|
||||
macro(COVERGROUP_WITH_RUN_W, "withRunW", false, "rr") \
|
||||
macro(DYN_AT_WRITE_APPEND, "atWriteAppend", false, "r") \
|
||||
macro(DYN_AT_WRITE_APPEND_BACK, "atWriteAppendBack", false, "r") \
|
||||
macro(DYN_CLEAR, "clear", false, "") \
|
||||
|
||||
@@ -1254,6 +1254,20 @@ public:
|
||||
void dump(std::ostream& str) const override;
|
||||
void dumpJson(std::ostream& str) const override;
|
||||
};
|
||||
class AstCoverWith final : public AstNode {
|
||||
// The values of a coverpoint bin for which a 'with' filter is true (IEEE 1800-2023
|
||||
// 19.5.1.1), the only range list element of its AstCoverBin
|
||||
// @astgen op1 := subp : List[AstNode] // Range list, or AstCoverpointRef for all values
|
||||
// @astgen op2 := filterp : AstNodeExpr
|
||||
// @astgen op3 := itemp : Optional[AstVar] // Candidate value 'item', from V3LinkParse
|
||||
public:
|
||||
AstCoverWith(FileLine* fl, AstNode* subp, AstNodeExpr* filterp)
|
||||
: ASTGEN_SUPER_CoverWith(fl) {
|
||||
addSubp(subp);
|
||||
this->filterp(filterp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstCoverWith;
|
||||
};
|
||||
class AstCovergroup final : public AstNode {
|
||||
// Represents a covergroup declaration. V3LinkParse transforms this
|
||||
// into an AstClass with isCovergroup==true and attaches the clocking
|
||||
|
||||
+447
-123
@@ -30,6 +30,7 @@
|
||||
#include "V3Error.h"
|
||||
#include "V3File.h"
|
||||
#include "V3MemberMap.h"
|
||||
#include "V3UniqueNames.h"
|
||||
|
||||
#include <bitset>
|
||||
#include <cmath>
|
||||
@@ -295,6 +296,11 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
std::deque<BinRun> runs; // Runs 'values' refers to
|
||||
};
|
||||
std::map<AstVar*, CoverpointBins> m_cpBins; // Runtime coverpoint -> binsof index ranges
|
||||
// Names of the bins declarations each coverpoint ignored, which binsof selects as no bins
|
||||
std::map<const AstCoverpoint*, std::vector<std::string>> m_droppedBins;
|
||||
// Prefixes of the constructor temporaries of constructed bins, as coverpoint and bin names
|
||||
// alone may repeat: coverpoint 'a_' bins 'b', and coverpoint 'a' bins '_b'
|
||||
V3UniqueNames m_sizedNames{"__Vsized"};
|
||||
std::vector<AstNodeExpr*> m_detachedValues; // Array-bin values m_cpBins refers to
|
||||
std::set<AstCoverCross*>
|
||||
m_droppedCrosses; // Crosses with a bare-variable item: drop (COVERIGN)
|
||||
@@ -372,6 +378,8 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
m_crossedCpNames.clear();
|
||||
m_cpVarMap.clear();
|
||||
m_cpBins.clear();
|
||||
m_droppedBins.clear();
|
||||
m_sizedNames.reset();
|
||||
m_runtimePoints.clear();
|
||||
m_runtimeCrosses.clear();
|
||||
m_excludedVars.clear();
|
||||
@@ -400,12 +408,13 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
std::map<AstCoverpoint*, std::vector<AstCoverCross*>> consumers;
|
||||
std::map<AstCoverCross*, std::vector<AstCoverpoint*>> inputs;
|
||||
for (AstCoverpoint* const cpp : m_coverpoints) {
|
||||
checkSizedArrays(cpp);
|
||||
checkBinNames(cpp);
|
||||
checkConstructedBins(cpp);
|
||||
if (!cpp->exprp()->dtypep()->skipRefp()->isIntegralOrPacked()) continue;
|
||||
// Bins without values leave the report (IEEE 1800-2023 19.11.1), exclusions or not.
|
||||
// A sized array of bins gets its values when the covergroup is constructed.
|
||||
// Constructed bins get their values when the covergroup is constructed.
|
||||
if (!coverpointHasStateExclusions(cpp) && !coverpointHasEmptyBins(cpp)
|
||||
&& !coverpointHasSizedArrays(cpp)) {
|
||||
&& !coverpointHasConstructedBins(cpp)) {
|
||||
continue;
|
||||
}
|
||||
m_runtimePoints.insert(cpp);
|
||||
@@ -495,62 +504,176 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
return binp->arraySizep() && !isAutoBins(binp);
|
||||
}
|
||||
|
||||
// Check the sized arrays of bins of a coverpoint, dropping invalid ones. A real
|
||||
// coverpoint's are unsupported, and treated as arrays of a bin per value. A wildcard array
|
||||
// of too many ranges of values is ignored, or if ignore or illegal, treated as one bin.
|
||||
void checkSizedArrays(AstCoverpoint* coverpointp) {
|
||||
const bool integral = coverpointp->exprp()->dtypep()->skipRefp()->isIntegralOrPacked();
|
||||
// The 'with' filter of a bin, if any (IEEE 1800-2023 19.5.1.1)
|
||||
static AstCoverWith* binWith(const AstCoverBin* binp) {
|
||||
return VN_CAST(binp->rangesp(), CoverWith);
|
||||
}
|
||||
|
||||
// True for bins whose values the covergroup constructor computes: a sized array, or bins of
|
||||
// the values a 'with' filter keeps
|
||||
static bool isConstructedBins(const AstCoverBin* binp) {
|
||||
return isSizedArray(binp) || binWith(binp);
|
||||
}
|
||||
|
||||
// The range list of a bin's values, or of the candidates of its 'with' filter; null for all
|
||||
// of the coverpoint's values, which a filter of the coverpoint's name has
|
||||
static AstNode* binRangesp(const AstCoverBin* binp) {
|
||||
const AstCoverWith* const withp = binWith(binp);
|
||||
if (!withp) return binp->rangesp();
|
||||
return VN_IS(withp->subp(), CoverpointRef) ? nullptr : withp->subp();
|
||||
}
|
||||
|
||||
// Report and delete a bins declaration of a name that another of its coverpoint has
|
||||
void checkBinNames(AstCoverpoint* coverpointp) {
|
||||
std::set<std::string> names;
|
||||
for (AstNode* nodep = coverpointp->binsp(); nodep;) {
|
||||
AstCoverBin* const binp = VN_AS(nodep, CoverBin);
|
||||
nodep = nodep->nextp();
|
||||
if (!isSizedArray(binp)) continue;
|
||||
AstNodeExpr* const sizep = binp->arraySizep();
|
||||
const AstConst* const constp = VN_CAST(sizep, Const);
|
||||
if (VN_IS(sizep, Unbounded)) { // A parameter of '$'; see bins_orBraE
|
||||
binp->v3error("Bins array size must be integral, not '$' (IEEE 1800-2023 19.5.1)");
|
||||
} else if (!sizep->dtypep()->skipRefp()->isIntegralOrPacked()) {
|
||||
sizep->v3error("Bins array size must be integral (IEEE 1800-2023 19.5.1)");
|
||||
} else if (constp && (constp->num().isFourState() || binsCount(constp) < 1)) {
|
||||
sizep->v3error("Bins array size must be >= 1, got "
|
||||
<< (constp->num().isFourState() ? constp->num().ascii(false)
|
||||
: constp->num().toDecimalS())
|
||||
<< " (IEEE 1800-2023 19.5.1)");
|
||||
} else if (!integral) {
|
||||
binp->v3warn(COVERIGN, "Unsupported: 'bins' explicit array size of a real "
|
||||
"coverpoint (treated as '[]')");
|
||||
VL_DO_DANGLING(pushDeletep(sizep->unlinkFrBack()), sizep);
|
||||
continue;
|
||||
} else if (binp->isWildcard()
|
||||
&& sizedWildcardRuns(binp, coverpointp->exprp())
|
||||
> v3Global.opt.coverageMaxBins()) {
|
||||
// An ignore or illegal array still excludes or checks its values, as one bin
|
||||
const bool single = !binp->binsType().binIsNormal();
|
||||
binp->v3warn(COVERIGN,
|
||||
"Unsupported: sized wildcard array '"
|
||||
<< binp->binsType().verilogKwd()
|
||||
<< "' of more than --coverage-max-bins of "
|
||||
<< v3Global.opt.coverageMaxBins() << " ranges of values; "
|
||||
<< (single ? "treated as one bin" : "bin ignored") << "\n"
|
||||
<< binp->warnMore()
|
||||
<< "... Suggest a larger --coverage-max-bins");
|
||||
if (single) {
|
||||
VL_DO_DANGLING(pushDeletep(sizep->unlinkFrBack()), sizep);
|
||||
binp->isArray(false);
|
||||
continue;
|
||||
}
|
||||
coverpointp->user2(true);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
if (names.emplace(binp->name()).second) continue;
|
||||
binp->v3error("Duplicate bin " << binp->prettyNameQ() << " in coverpoint "
|
||||
<< coverpointp->prettyNameQ()
|
||||
<< " (IEEE 1800-2023 3.13)");
|
||||
VL_DO_DANGLING(pushDeletep(binp->unlinkFrBack()), binp);
|
||||
}
|
||||
}
|
||||
|
||||
// The ranges of values the wildcard patterns of a sized wildcard array give, counted up to
|
||||
// more than --coverage-max-bins
|
||||
// Delete an ignored bins declaration, which binsof then selects as no bins
|
||||
void dropBins(const AstCoverpoint* coverpointp, AstCoverBin* binp) {
|
||||
m_droppedBins[coverpointp].push_back(binp->name());
|
||||
VL_DO_DANGLING(pushDeletep(binp->unlinkFrBack()), binp);
|
||||
}
|
||||
|
||||
// Check the size of a sized array of bins, which drops an invalid array. A real coverpoint's
|
||||
// are unsupported, and treated as arrays of a bin per value. False unless it stays sized.
|
||||
bool checkBinsArraySize(const AstCoverpoint* coverpointp, AstCoverBin* binp, bool integral) {
|
||||
AstNodeExpr* const sizep = binp->arraySizep();
|
||||
const AstConst* const constp = VN_CAST(sizep, Const);
|
||||
if (VN_IS(sizep, Unbounded)) { // A parameter of '$'; see bins_orBraE
|
||||
binp->v3error("Bins array size must be integral, not '$' (IEEE 1800-2023 19.5.1)");
|
||||
} else if (!sizep->dtypep()->skipRefp()->isIntegralOrPacked()) {
|
||||
sizep->v3error("Bins array size must be integral (IEEE 1800-2023 19.5.1)");
|
||||
} else if (constp && (constp->num().isFourState() || binsCount(constp) < 1)) {
|
||||
sizep->v3error("Bins array size must be >= 1, got "
|
||||
<< (constp->num().isFourState() ? constp->num().ascii(false)
|
||||
: constp->num().toDecimalS())
|
||||
<< " (IEEE 1800-2023 19.5.1)");
|
||||
} else if (!integral) {
|
||||
binp->v3warn(COVERIGN, "Unsupported: 'bins' explicit array size of a real "
|
||||
"coverpoint (treated as '[]')");
|
||||
VL_DO_DANGLING(pushDeletep(sizep->unlinkFrBack()), sizep);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
dropBins(coverpointp, binp);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check the bins of a coverpoint whose values the constructor computes, dropping invalid
|
||||
// ones. A wildcard array of too many ranges of values is ignored, or if ignore or illegal,
|
||||
// treated as one bin; filtering too many ranges of values ignores the bins.
|
||||
void checkConstructedBins(AstCoverpoint* coverpointp) {
|
||||
const bool integral = coverpointp->exprp()->dtypep()->skipRefp()->isIntegralOrPacked();
|
||||
for (AstNode* nodep = coverpointp->binsp(); nodep;) {
|
||||
AstCoverBin* const binp = VN_AS(nodep, CoverBin);
|
||||
nodep = nodep->nextp();
|
||||
if (!isConstructedBins(binp)) continue;
|
||||
if (isSizedArray(binp) && !checkBinsArraySize(coverpointp, binp, integral)) continue;
|
||||
if (!binp->isWildcard()
|
||||
|| sizedWildcardRuns(binp, coverpointp->exprp())
|
||||
<= v3Global.opt.coverageMaxBins()) {
|
||||
if (binWith(binp) && withCandidatesOver(binp, coverpointp->exprp())) {
|
||||
binp->v3warn(COVERIGN, "Unsupported: 'with' filter of more than 2**32 "
|
||||
"candidate values; bin "
|
||||
<< binp->prettyNameQ() << " ignored");
|
||||
if (binp->binsType().binIsNormal()) coverpointp->user2(true);
|
||||
dropBins(coverpointp, binp);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// An ignore or illegal array still excludes or checks its values, as one bin
|
||||
const bool single = !binp->binsType().binIsNormal() && !binWith(binp);
|
||||
binp->v3warn(COVERIGN,
|
||||
"Unsupported: " << (binWith(binp) ? "'with' filter of wildcard '"
|
||||
: "sized wildcard array '")
|
||||
<< binp->binsType().verilogKwd()
|
||||
<< "' of more than --coverage-max-bins of "
|
||||
<< v3Global.opt.coverageMaxBins()
|
||||
<< " ranges of values; bin " << binp->prettyNameQ()
|
||||
<< (single ? " treated as one bin" : " ignored") << "\n"
|
||||
<< binp->warnMore()
|
||||
<< "... Suggest a larger --coverage-max-bins");
|
||||
if (single) {
|
||||
AstNodeExpr* const sizep = binp->arraySizep();
|
||||
VL_DO_DANGLING(pushDeletep(sizep->unlinkFrBack()), sizep);
|
||||
binp->isArray(false);
|
||||
continue;
|
||||
}
|
||||
if (binp->binsType().binIsNormal()) coverpointp->user2(true);
|
||||
dropBins(coverpointp, binp);
|
||||
}
|
||||
}
|
||||
|
||||
// True if a 'with' filter would be evaluated for more than 2**32 candidate values, known
|
||||
// now for the coverpoint's name, or for a range list of constants: each is evaluated once
|
||||
// but for an array 'b[N]', which keeps their order and duplicates (see withBegin())
|
||||
static bool withCandidatesOver(AstCoverBin* binp, AstNodeExpr* exprp) {
|
||||
const int width = runWidth(exprp);
|
||||
std::vector<std::pair<V3Number, V3Number>> runs;
|
||||
if (!binRangesp(binp)) runs = coverpointValues(binp, exprp);
|
||||
const auto constant
|
||||
= [](const AstNode* nodep) { return VN_IS(nodep, Const) || VN_IS(nodep, Unbounded); };
|
||||
for (AstNode* rangep = binRangesp(binp); rangep; rangep = rangep->nextp()) {
|
||||
const AstInsideRange* const irp = VN_CAST(rangep, InsideRange);
|
||||
// Else known when constructed
|
||||
if (irp ? !constant(irp->lhsp()) || !constant(irp->rhsp()) : !VN_IS(rangep, Const)) {
|
||||
return false;
|
||||
}
|
||||
CrossValueRange range{rangep, resolveWidth(rangep, exprp)};
|
||||
if (!resolveValue(rangep, exprp, true, binp->isWildcard(), range)
|
||||
|| crossRangeEmpty(range)) {
|
||||
continue;
|
||||
}
|
||||
std::vector<std::pair<V3Number, V3Number>> found{{range.lo, range.hi}};
|
||||
if (range.wildcard) { // checkConstructedBins bounded the runs
|
||||
found.clear();
|
||||
crossRangeRuns(range, v3Global.opt.coverageMaxBins(), found);
|
||||
}
|
||||
for (const std::pair<V3Number, V3Number>& run : found) {
|
||||
runs.emplace_back(V3Number{rangep, width, run.first},
|
||||
V3Number{rangep, width, run.second});
|
||||
}
|
||||
}
|
||||
if (!isSizedArray(binp)) { // The union of the values
|
||||
std::sort(runs.begin(), runs.end(), [](const auto& lhs, const auto& rhs) {
|
||||
return crossValueLess(lhs.first, rhs.first);
|
||||
});
|
||||
std::vector<std::pair<V3Number, V3Number>> merged;
|
||||
for (const std::pair<V3Number, V3Number>& run : runs) {
|
||||
if (merged.empty() || crossValueLess(merged.back().second, run.first)) {
|
||||
merged.push_back(run);
|
||||
} else if (crossValueLess(merged.back().second, run.second)) {
|
||||
merged.back().second = run.second;
|
||||
}
|
||||
}
|
||||
runs = std::move(merged);
|
||||
}
|
||||
uint64_t count = 0;
|
||||
for (const std::pair<V3Number, V3Number>& run : runs) {
|
||||
V3Number span{exprp, width};
|
||||
span.opSub(run.second, run.first);
|
||||
if (span.mostSetBitP1() > 32) return true; // More than 2**32 values
|
||||
count += span.toUQuad() + 1;
|
||||
if (count > (uint64_t{1} << 32)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// The ranges of values the wildcard patterns of a sized wildcard array, or of a 'with'
|
||||
// filter's candidates, give, counted up to more than --coverage-max-bins
|
||||
static size_t sizedWildcardRuns(const AstCoverBin* binp, AstNodeExpr* exprp) {
|
||||
std::vector<std::pair<V3Number, V3Number>> runs;
|
||||
for (AstNode* rangep = binp->rangesp(); rangep; rangep = rangep->nextp()) {
|
||||
for (AstNode* rangep = binRangesp(binp); rangep; rangep = rangep->nextp()) {
|
||||
if (!VN_IS(rangep, Const)) continue; // A range, or a value known at construction
|
||||
CrossValueRange range{rangep, resolveWidth(rangep, exprp)};
|
||||
if (resolveValue(rangep, exprp, true, true, range) && !crossRangeEmpty(range)) {
|
||||
@@ -797,8 +920,8 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
|| cbinp->binsType() == VCoverBinsType::BINS_IGNORE
|
||||
|| cbinp->binsType() == VCoverBinsType::BINS_ILLEGAL)
|
||||
continue;
|
||||
// The values of a sized array are known at construction; see emitSizedSample
|
||||
if (isSizedArray(cbinp)) continue;
|
||||
// The values of constructed bins are known at construction; see emitSizedSample
|
||||
if (isConstructedBins(cbinp)) continue;
|
||||
if (isAutoBins(cbinp)) {
|
||||
// Automatic bins partition the whole domain, leaving no default value
|
||||
if (anyBinMatchp) VL_DO_DANGLING(pushDeletep(anyBinMatchp), anyBinMatchp);
|
||||
@@ -828,9 +951,9 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool coverpointHasSizedArrays(const AstCoverpoint* coverpointp) {
|
||||
static bool coverpointHasConstructedBins(const AstCoverpoint* coverpointp) {
|
||||
for (const AstNode* nodep = coverpointp->binsp(); nodep; nodep = nodep->nextp()) {
|
||||
if (isSizedArray(VN_AS(nodep, CoverBin))) return true;
|
||||
if (isConstructedBins(VN_AS(nodep, CoverBin))) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -842,8 +965,9 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
for (AstNode* nodep = coverpointp->binsp(); nodep; nodep = nodep->nextp()) {
|
||||
const AstCoverBin* const binp = VN_AS(nodep, CoverBin);
|
||||
if (!binp->binsType().binIsNormal() || binp->transp() || !binp->rangesp()) continue;
|
||||
// A wildcard array has a bin for each value its elements match, so none empty
|
||||
if (binp->isArray() && binp->isWildcard()) continue;
|
||||
// A wildcard array has a bin for each value its elements match, so none empty, and
|
||||
// the constructor creates no bin without values of a 'with' filter
|
||||
if ((binp->isArray() && binp->isWildcard()) || binWith(binp)) continue;
|
||||
bool empty = true;
|
||||
for (AstNode* valuep = binp->rangesp(); valuep; valuep = valuep->nextp()) {
|
||||
if (binp->isArray() && VN_IS(valuep, InsideRange)) continue;
|
||||
@@ -1001,6 +1125,17 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
bins.push_back({{0, maxVal}});
|
||||
return exprp->width() <= 64;
|
||||
}
|
||||
if (binWith(cbinp)) {
|
||||
// A value is in one bin of a filter's, but of a sized array, in one for each range
|
||||
// list element holding it; the coverpoint's name is one element
|
||||
int elements = 0;
|
||||
for (const AstNode* rp = binRangesp(cbinp); rp && isSizedArray(cbinp);
|
||||
rp = rp->nextp()) {
|
||||
++elements;
|
||||
}
|
||||
slotCount += std::max(1, elements);
|
||||
return false;
|
||||
}
|
||||
if (cbinp->isArray() && cbinp->isWildcard() && !cbinp->arraySizep()) {
|
||||
// A value is in at most one bin of a wildcard array: one slot covering its values.
|
||||
// Signed values are sign-extended, not unsigned intervals (see computeHitListBound)
|
||||
@@ -1203,8 +1338,8 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
arrayBinp->v3warn(COVERIGN,
|
||||
"Unsupported: array 'bins' of a real coverpoint "
|
||||
"covering more than "
|
||||
<< v3Global.opt.coverageMaxRealBins()
|
||||
<< " values; bin ignored.\n"
|
||||
<< v3Global.opt.coverageMaxRealBins() << " values; bin "
|
||||
<< arrayBinp->prettyNameQ() << " ignored.\n"
|
||||
<< arrayBinp->warnMore()
|
||||
<< "... Suggest a larger --coverage-max-real-bins");
|
||||
unsupportedOut = true;
|
||||
@@ -1285,7 +1420,8 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
arrayBinp->v3warn(COVERIGN, "Unsupported: array 'bins' covering more than "
|
||||
<< v3Global.opt.coverageMaxBins()
|
||||
<< " values (e.g. an open '[lo:$]' range over "
|
||||
"a wide coverpoint); bin ignored\n"
|
||||
"a wide coverpoint); bin "
|
||||
<< arrayBinp->prettyNameQ() << " ignored\n"
|
||||
<< arrayBinp->warnMore()
|
||||
<< "... Suggest a larger --coverage-max-bins");
|
||||
out.runs.clear();
|
||||
@@ -1361,15 +1497,15 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
// An ignore or illegal array still excludes or checks its values, as one bin
|
||||
out.single = !arrayBinp->binsType().binIsNormal();
|
||||
if (report) {
|
||||
arrayBinp->v3warn(COVERIGN,
|
||||
"Unsupported: wildcard array '"
|
||||
<< arrayBinp->binsType().verilogKwd()
|
||||
<< "' of more than --coverage-max-bins of "
|
||||
<< v3Global.opt.coverageMaxBins() << " values; "
|
||||
<< (out.single ? "treated as one bin" : "bin ignored")
|
||||
<< "\n"
|
||||
<< arrayBinp->warnMore()
|
||||
<< "... Suggest a larger --coverage-max-bins");
|
||||
arrayBinp->v3warn(
|
||||
COVERIGN, "Unsupported: wildcard array '"
|
||||
<< arrayBinp->binsType().verilogKwd()
|
||||
<< "' of more than --coverage-max-bins of "
|
||||
<< v3Global.opt.coverageMaxBins() << " values; bin "
|
||||
<< arrayBinp->prettyNameQ()
|
||||
<< (out.single ? " treated as one bin" : " ignored") << "\n"
|
||||
<< arrayBinp->warnMore()
|
||||
<< "... Suggest a larger --coverage-max-bins");
|
||||
}
|
||||
out.unsupported = true;
|
||||
return out;
|
||||
@@ -1539,16 +1675,31 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
void emitSizedSample(AstCoverpoint* coverpointp, AstCoverBin* binp, AstVar* cpVarp,
|
||||
AstNodeExpr* exprp, uint32_t sized, AstVar* matchedp) {
|
||||
FileLine* const fl = binp->fileline();
|
||||
AstNodeExpr* const enabledp
|
||||
AstNodeExpr* enabledp
|
||||
= binCondition(coverpointp, binp, cpVarp, new AstConst{fl, AstConst::BitTrue{}});
|
||||
UASSERT_OBJ(m_sampleFuncp, binp, "sample() CFunc not set for coverpoint");
|
||||
const bool illegal = binp->binsType() == VCoverBinsType::BINS_ILLEGAL;
|
||||
if (illegal) {
|
||||
// The illegal action reads the condition too, which is evaluated once, as the guard
|
||||
// may have side effects
|
||||
AstVar* const varp
|
||||
= new AstVar{fl, VVarType::BLOCKTEMP,
|
||||
"__VcpEnabled_" + sanitizeGeneratedName(coverpointp->name()) + "_"
|
||||
+ cvtToStr(sized),
|
||||
binp->findBitDType()};
|
||||
varp->funcLocal(true);
|
||||
m_sampleFuncp->addStmtsp(varp);
|
||||
m_sampleFuncp->addStmtsp(
|
||||
new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, enabledp});
|
||||
enabledp = new AstVarRef{fl, varp, VAccess::READ};
|
||||
}
|
||||
AstCMethodHard* const callp
|
||||
= itemCall(fl, cpVarp,
|
||||
exprp->isWide() ? VCMethod::COVERGROUP_SIZED_SAMPLE_W
|
||||
: VCMethod::COVERGROUP_SIZED_SAMPLE,
|
||||
{cnum(fl, sized), exprp->cloneTree(false), enabledp});
|
||||
callp->dtypeSetBit();
|
||||
UASSERT_OBJ(m_sampleFuncp, binp, "sample() CFunc not set for coverpoint");
|
||||
if (binp->binsType() == VCoverBinsType::BINS_ILLEGAL) {
|
||||
if (illegal) {
|
||||
m_sampleFuncp->addStmtsp(
|
||||
new AstIf{fl, new AstLogAnd{fl, callp, enabledp->cloneTree(false)},
|
||||
makeIllegalBinAction(fl, "Illegal bin " + binp->prettyNameQ()
|
||||
@@ -1585,61 +1736,223 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
return valuep;
|
||||
}
|
||||
|
||||
// Emit the constructor code building the sized array of bins 'binp': the values of each
|
||||
// element that are coverpoint values (IEEE 1800-2023 19.5.7), then its bins
|
||||
void generateSizedArray(AstCoverpoint* coverpointp, AstCoverBin* binp, AstVar* cpVarp,
|
||||
AstNodeExpr* exprp) {
|
||||
// The values of a coverpoint, which its name denotes (IEEE 1800-2023 19.5.1.1), as runs in
|
||||
// value order: an enumerated type's values (6.19), else all values of its type. Bounds
|
||||
// are at runWidth(), sign-extended like a CrossValueRange's.
|
||||
static std::vector<std::pair<V3Number, V3Number>> coverpointValues(AstNode* nodep,
|
||||
AstNodeExpr* exprp) {
|
||||
const int width = runWidth(exprp);
|
||||
std::vector<std::pair<V3Number, V3Number>> runs;
|
||||
const AstEnumDType* const enump = VN_CAST(exprp->dtypep()->skipRefToEnump(), EnumDType);
|
||||
if (!enump) {
|
||||
const CrossValueRange domain
|
||||
= crossValueDomain(nodep, exprp->width(), exprp->isSigned(), width);
|
||||
runs.emplace_back(domain.lo, domain.hi);
|
||||
return runs;
|
||||
}
|
||||
std::vector<V3Number> values;
|
||||
for (const AstEnumItem* itemp = enump->itemsp(); itemp;
|
||||
itemp = VN_AS(itemp->nextp(), EnumItem)) {
|
||||
const V3Number& num = VN_AS(itemp->valuep(), Const)->num();
|
||||
if (num.isFourState()) continue; // Not a coverpoint value (19.5.7)
|
||||
values.emplace_back(nodep, width);
|
||||
if (exprp->isSigned()) {
|
||||
values.back().opExtendS(num, num.width());
|
||||
} else {
|
||||
values.back().opAssign(num);
|
||||
}
|
||||
}
|
||||
std::sort(values.begin(), values.end(), crossValueLess);
|
||||
const V3Number one{nodep, width, 1};
|
||||
for (const V3Number& value : values) {
|
||||
V3Number next{nodep, width};
|
||||
if (!runs.empty() && next.opAdd(runs.back().second, one).isCaseEq(value)) {
|
||||
runs.back().second = value;
|
||||
} else {
|
||||
runs.emplace_back(value, value);
|
||||
}
|
||||
}
|
||||
return runs;
|
||||
}
|
||||
|
||||
// Emit the constructor code building the bins 'binp' whose values it computes: the values of
|
||||
// each element that are coverpoint values (IEEE 1800-2023 19.5.7), those a 'with' filter
|
||||
// keeps (19.5.1.1), then its bins
|
||||
void generateConstructedBins(AstCoverpoint* coverpointp, AstCoverBin* binp, AstVar* cpVarp,
|
||||
AstNodeExpr* exprp) {
|
||||
FileLine* const fl = binp->fileline();
|
||||
const string prefix
|
||||
= "__Vsized_" + sanitizeGeneratedName(coverpointp->name() + "__" + binp->name());
|
||||
AstNodeExpr* const sizep = binp->arraySizep();
|
||||
AstVar* const countp = constructorTemp(fl, prefix + "_count", sizep->dtypep());
|
||||
m_constructorp->addStmtsp(
|
||||
new AstAssign{fl, new AstVarRef{fl, countp, VAccess::WRITE}, sizep->cloneTree(false)});
|
||||
= m_sizedNames.get(sanitizeGeneratedName(coverpointp->name() + "__" + binp->name()));
|
||||
AstVar* countp = nullptr;
|
||||
if (AstNodeExpr* const sizep = binp->arraySizep()) {
|
||||
countp = constructorTemp(fl, prefix + "_count", sizep->dtypep());
|
||||
m_constructorp->addStmtsp(new AstAssign{fl, new AstVarRef{fl, countp, VAccess::WRITE},
|
||||
sizep->cloneTree(false)});
|
||||
}
|
||||
AstCoverWith* const withp = binWith(binp);
|
||||
if (withp && !binRangesp(binp)) { // The coverpoint's name: all of its values
|
||||
for (const std::pair<V3Number, V3Number>& run : coverpointValues(binp, exprp)) {
|
||||
m_constructorp->addStmtsp(itemCall(fl, cpVarp,
|
||||
exprp->isWide()
|
||||
? VCMethod::COVERGROUP_SIZED_RANGE_W
|
||||
: VCMethod::COVERGROUP_SIZED_RANGE,
|
||||
{newValueConst(fl, run.first, exprp),
|
||||
newValueConst(fl, run.second, exprp)})
|
||||
->makeStmt());
|
||||
}
|
||||
}
|
||||
uint32_t element = 0;
|
||||
for (AstNode* rangep = binp->rangesp(); rangep; rangep = rangep->nextp()) {
|
||||
for (AstNode* rangep = binRangesp(binp); rangep; rangep = rangep->nextp()) {
|
||||
if (VN_IS(rangep, Unbounded)) { // A parameter of '$'
|
||||
binp->v3error("Bins value may not be '$', which may only bound a range "
|
||||
"(IEEE 1800-2023 6.20.7)");
|
||||
continue;
|
||||
}
|
||||
generateSizedElement(cpVarp, rangep, exprp, binp->isWildcard(),
|
||||
prefix + "_" + cvtToStr(element++));
|
||||
generateSizedElement(cpVarp, binp, rangep, exprp, prefix + "_" + cvtToStr(element++));
|
||||
}
|
||||
const auto countRef = [&]() { return new AstVarRef{fl, countp, VAccess::READ}; };
|
||||
AstConst* const zerop = new AstConst{fl, AstConst::DTyped{}, countp->dtypep()};
|
||||
AstNodeExpr* const positivep
|
||||
= countp->isSigned() ? static_cast<AstNodeExpr*>(new AstGtS{fl, countRef(), zerop})
|
||||
: new AstNeq{fl, countRef(), zerop};
|
||||
// Saturate a count wider than 64 bits: min(N, T) is unchanged, or over any bins limit
|
||||
AstNodeExpr* countValuep = resizeValue(countRef(), countp->findUInt64DType());
|
||||
if (countp->width() > VL_QUADSIZE) {
|
||||
countValuep = new AstCond{
|
||||
fl,
|
||||
new AstRedOr{
|
||||
fl, new AstSel{fl, countRef(), VL_QUADSIZE, countp->width() - VL_QUADSIZE}},
|
||||
new AstConst{fl, AstConst::Unsized64{}, std::numeric_limits<uint64_t>::max()},
|
||||
countValuep};
|
||||
countValuep->dtypeSetUInt64();
|
||||
if (withp) generateWithFilter(binp, withp, cpVarp, exprp, prefix);
|
||||
AstNodeExpr* countValuep;
|
||||
AstNodeExpr* positivep;
|
||||
if (countp) {
|
||||
const auto countRef = [&]() { return new AstVarRef{fl, countp, VAccess::READ}; };
|
||||
AstConst* const zerop = new AstConst{fl, AstConst::DTyped{}, countp->dtypep()};
|
||||
positivep = countp->isSigned()
|
||||
? static_cast<AstNodeExpr*>(new AstGtS{fl, countRef(), zerop})
|
||||
: new AstNeq{fl, countRef(), zerop};
|
||||
// Saturate a count wider than 64 bits: min(N, T) is unchanged, or over any limit
|
||||
countValuep = resizeValue(countRef(), countp->findUInt64DType());
|
||||
if (countp->width() > VL_QUADSIZE) {
|
||||
countValuep = new AstCond{
|
||||
fl,
|
||||
new AstRedOr{fl, new AstSel{fl, countRef(), VL_QUADSIZE,
|
||||
countp->width() - VL_QUADSIZE}},
|
||||
new AstConst{fl, AstConst::Unsized64{}, std::numeric_limits<uint64_t>::max()},
|
||||
countValuep};
|
||||
countValuep->dtypeSetUInt64();
|
||||
}
|
||||
} else { // Of a filter's scalar bin, or bin per value
|
||||
countValuep = new AstConst{fl, AstConst::Unsized64{}, 1};
|
||||
positivep = new AstConst{fl, AstConst::BitTrue{}};
|
||||
}
|
||||
std::vector<AstNodeExpr*> args{ctext(fl, binp->binsType().binSetEnum()), countValuep,
|
||||
positivep};
|
||||
// A filter's bins have the limit it began with
|
||||
if (!withp) args.push_back(cnum(fl, v3Global.opt.coverageMaxBins()));
|
||||
const bool prot = v3Global.opt.protectIds();
|
||||
args.push_back(ctext(fl, quoted(VIdProtect::protectWordsIf(binp->name(), prot))));
|
||||
args.push_back(ctext(fl, quoted(VIdProtect::protectIf(fl->filename(), prot))));
|
||||
args.push_back(cnum(fl, static_cast<uint32_t>(fl->lineno())));
|
||||
args.push_back(cnum(fl, static_cast<uint32_t>(fl->firstColumn())));
|
||||
m_constructorp->addStmtsp(
|
||||
itemCall(fl, cpVarp, VCMethod::COVERGROUP_SIZED_FINISH,
|
||||
{ctext(fl, binp->binsType().binSetEnum()), countValuep, positivep,
|
||||
cnum(fl, v3Global.opt.coverageMaxBins()),
|
||||
ctext(fl, quoted(VIdProtect::protectWordsIf(binp->name(), prot))),
|
||||
ctext(fl, quoted(VIdProtect::protectIf(fl->filename(), prot))),
|
||||
cnum(fl, static_cast<uint32_t>(fl->lineno())),
|
||||
cnum(fl, static_cast<uint32_t>(fl->firstColumn()))})
|
||||
itemCall(fl, cpVarp,
|
||||
withp ? VCMethod::COVERGROUP_WITH_FINISH : VCMethod::COVERGROUP_SIZED_FINISH,
|
||||
args)
|
||||
->makeStmt());
|
||||
}
|
||||
|
||||
// Emit 'sizedRange(lo, hi)' for the coverpoint values of an element of a sized array of
|
||||
// bins: resolved now if constant, else when constructed by clipping to the coverpoint's
|
||||
// values. A 'wildcard' pattern's values give a range for each run of them. 'prefix' names
|
||||
// its temporaries.
|
||||
void generateSizedElement(AstVar* cpVarp, AstNode* rangep, AstNodeExpr* exprp, bool wildcard,
|
||||
const string& prefix) {
|
||||
// Emit the constructor code evaluating the 'with' filter of 'binp' for each of its candidate
|
||||
// values, which sizedRange() added, passing the runs of values it keeps (IEEE 1800-2023
|
||||
// 19.5.1.1). The filter is evaluated in a loop, whose code does not grow with the elements:
|
||||
// withBegin(grouping, limit);
|
||||
// more = 1;
|
||||
// while (withNext()) {
|
||||
// value = withLo(); last = withHi(); run = 0;
|
||||
// while (true) {
|
||||
// item = value;
|
||||
// if (filter) { if (!run) { first = value; run = 1; } }
|
||||
// else if (run) { more = withRun(first, value - 1); run = 0; }
|
||||
// if (!more || value == last) break;
|
||||
// ++value;
|
||||
// }
|
||||
// if (run) more = withRun(first, last);
|
||||
// }
|
||||
void generateWithFilter(AstCoverBin* binp, AstCoverWith* withp, AstVar* cpVarp,
|
||||
AstNodeExpr* exprp, const string& prefix) {
|
||||
FileLine* const fl = withp->fileline();
|
||||
const bool wide = exprp->isWide();
|
||||
const string grouping = !binp->isArray() ? "Single"
|
||||
: binp->arraySizep() ? "Fixed"
|
||||
: "Values";
|
||||
m_constructorp->addStmtsp(itemCall(fl, cpVarp, VCMethod::COVERGROUP_WITH_BEGIN,
|
||||
{ctext(fl, "VlCovBinGrouping::" + grouping),
|
||||
cnum(fl, v3Global.opt.coverageMaxBins())})
|
||||
->makeStmt());
|
||||
// The candidates count in the coverpoint's width, and the filter reads each as 'item',
|
||||
// of the coverpoint's type, so that a filter changing 'item' cannot change the loop
|
||||
AstNodeDType* const valueDTypep
|
||||
= exprp->findLogicDType(exprp->width(), exprp->width(),
|
||||
exprp->isSigned() ? VSigning::SIGNED : VSigning::UNSIGNED);
|
||||
AstVar* const valuep = constructorTemp(fl, prefix + "_value", valueDTypep);
|
||||
AstVar* const lastp = constructorTemp(fl, prefix + "_last", valueDTypep);
|
||||
AstVar* const firstp = constructorTemp(fl, prefix + "_first", valueDTypep);
|
||||
AstVar* const runp = constructorTemp(fl, prefix + "_run", binp->findBitDType());
|
||||
AstVar* const morep = constructorTemp(fl, prefix + "_more", binp->findBitDType());
|
||||
AstVar* const itemp = withp->itemp()->unlinkFrBack();
|
||||
itemp->name(prefix + "_item");
|
||||
m_constructorp->addStmtsp(itemp);
|
||||
const auto ref = [&](AstVar* varp) { return new AstVarRef{fl, varp, VAccess::READ}; };
|
||||
const auto assign = [&](AstVar* varp, AstNodeExpr* rhsp) -> AstNode* {
|
||||
return new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, rhsp};
|
||||
};
|
||||
const auto flag = [&](AstVar* varp, bool value) {
|
||||
return assign(varp, value ? new AstConst{fl, AstConst::BitTrue{}}
|
||||
: new AstConst{fl, AstConst::BitFalse{}});
|
||||
};
|
||||
const auto bound = [&](VCMethod narrow, VCMethod wideMethod, AstVar* varp) -> AstNode* {
|
||||
if (wide) {
|
||||
return itemCall(fl, cpVarp, wideMethod, {new AstVarRef{fl, varp, VAccess::WRITE}})
|
||||
->makeStmt();
|
||||
}
|
||||
AstCMethodHard* const callp = itemCall(fl, cpVarp, narrow);
|
||||
callp->dtypeSetUInt64();
|
||||
return assign(varp, resizeValue(callp, valueDTypep));
|
||||
};
|
||||
const auto keep = [&](AstNodeExpr* lop, AstNodeExpr* hip) {
|
||||
AstCMethodHard* const callp = itemCall(
|
||||
fl, cpVarp, wide ? VCMethod::COVERGROUP_WITH_RUN_W : VCMethod::COVERGROUP_WITH_RUN,
|
||||
{lop, hip});
|
||||
callp->dtypeSetBit();
|
||||
return assign(morep, callp);
|
||||
};
|
||||
const auto step = [&](bool up) {
|
||||
AstConst* const onep = new AstConst{fl, AstConst::WidthedValue{}, exprp->width(), 1};
|
||||
AstNodeExpr* const stepp
|
||||
= up ? static_cast<AstNodeExpr*>(new AstAdd{fl, ref(valuep), onep})
|
||||
: new AstSub{fl, ref(valuep), onep};
|
||||
stepp->dtypep(valueDTypep);
|
||||
return stepp;
|
||||
};
|
||||
AstLoop* const innerp = new AstLoop{fl};
|
||||
innerp->addStmtsp(assign(itemp, ref(valuep)));
|
||||
innerp->addStmtsp(new AstIf{
|
||||
fl, withp->filterp()->unlinkFrBack(),
|
||||
new AstIf{fl, new AstNot{fl, ref(runp)},
|
||||
assign(firstp, ref(valuep))->addNext(flag(runp, true))},
|
||||
new AstIf{fl, ref(runp), keep(ref(firstp), step(false))->addNext(flag(runp, false))}});
|
||||
innerp->addStmtsp(new AstLoopTest{
|
||||
fl, innerp, new AstLogAnd{fl, ref(morep), new AstNeq{fl, ref(valuep), ref(lastp)}}});
|
||||
innerp->addStmtsp(assign(valuep, step(true)));
|
||||
AstLoop* const outerp = new AstLoop{fl};
|
||||
AstCMethodHard* const nextp = itemCall(fl, cpVarp, VCMethod::COVERGROUP_WITH_NEXT);
|
||||
nextp->dtypeSetBit();
|
||||
outerp->addStmtsp(new AstLoopTest{fl, outerp, nextp});
|
||||
outerp->addStmtsp(
|
||||
bound(VCMethod::COVERGROUP_WITH_LO, VCMethod::COVERGROUP_WITH_LO_W, valuep));
|
||||
outerp->addStmtsp(
|
||||
bound(VCMethod::COVERGROUP_WITH_HI, VCMethod::COVERGROUP_WITH_HI_W, lastp));
|
||||
outerp->addStmtsp(flag(runp, false));
|
||||
outerp->addStmtsp(innerp);
|
||||
outerp->addStmtsp(new AstIf{fl, ref(runp), keep(ref(firstp), ref(lastp))});
|
||||
m_constructorp->addStmtsp(flag(morep, true));
|
||||
m_constructorp->addStmtsp(outerp);
|
||||
}
|
||||
|
||||
// Emit 'sizedRange(lo, hi)' for the coverpoint values of an element of bins 'binp', whose
|
||||
// values the constructor computes: resolved now if constant, else when constructed by
|
||||
// clipping to the coverpoint's values. A wildcard pattern's values give a range for each
|
||||
// run of them. 'prefix' names its temporaries.
|
||||
void generateSizedElement(AstVar* cpVarp, const AstCoverBin* binp, AstNode* rangep,
|
||||
AstNodeExpr* exprp, const string& prefix) {
|
||||
FileLine* const fl = rangep->fileline();
|
||||
const VCMethod method = exprp->isWide() ? VCMethod::COVERGROUP_SIZED_RANGE_W
|
||||
: VCMethod::COVERGROUP_SIZED_RANGE;
|
||||
@@ -1659,17 +1972,18 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
return constp && constp->num().isFourState();
|
||||
};
|
||||
if (irp && (fourState(lowp) || fourState(highp))) {
|
||||
rangep->v3error("Four-state (x/z) value in array bins range bound; range bounds "
|
||||
"must be two-state constants");
|
||||
rangep->v3error("Four-state (x/z) value in "
|
||||
<< (binp->isArray() ? "array bins" : "bin")
|
||||
<< " range bound; range bounds must be two-state constants");
|
||||
return;
|
||||
}
|
||||
CrossValueRange range{rangep, resolveWidth(rangep, exprp)};
|
||||
if (!resolveValue(rangep, exprp, true, wildcard, range)) {
|
||||
if (!resolveValue(rangep, exprp, true, binp->isWildcard(), range)) {
|
||||
rangep->v3warn(E_UNSUPPORTED, "Unsupported: non-integral value in a coverage bin "
|
||||
"of an integral coverpoint.");
|
||||
} else if (!crossRangeEmpty(range)) {
|
||||
std::vector<std::pair<V3Number, V3Number>> runs{{range.lo, range.hi}};
|
||||
if (range.wildcard) { // checkSizedArrays bounded the runs
|
||||
if (range.wildcard) { // checkConstructedBins bounded the runs
|
||||
runs.clear();
|
||||
crossRangeRuns(range, v3Global.opt.coverageMaxBins(), runs);
|
||||
}
|
||||
@@ -1864,8 +2178,8 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
}
|
||||
|
||||
// Walk bins (non-default, then default), assigning sequential indices that match the
|
||||
// namer append order; emit sample increments and collect namer statements. A sized
|
||||
// array's bins follow them all, placed when the coverpoint is constructed.
|
||||
// namer append order; emit sample increments and collect namer statements. Constructed
|
||||
// bins follow them all, placed when the coverpoint is constructed.
|
||||
std::vector<AstNodeStmt*> namerStmts;
|
||||
std::vector<AstCoverBin*> defaultBins;
|
||||
std::vector<AstCoverBin*> sizedBins;
|
||||
@@ -1879,8 +2193,8 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
defaultBins.push_back(cbinp);
|
||||
continue;
|
||||
}
|
||||
if (isSizedArray(cbinp)) {
|
||||
UASSERT_OBJ(dynamic, cbinp, "Sized bin array without value metadata");
|
||||
if (isConstructedBins(cbinp)) {
|
||||
UASSERT_OBJ(dynamic, cbinp, "Constructed bins without value metadata");
|
||||
BinSpan span;
|
||||
span.sized = static_cast<int32_t>(sizedBins.size());
|
||||
m_cpBins.at(cpVarp).spans.emplace(cbinp->name(), span);
|
||||
@@ -1910,7 +2224,10 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
if (binRunsFor(cbinp, exprp, plan)) {
|
||||
// Array elements and automatic bins generate as runs, so neither sample() nor
|
||||
// the constructor grows with their number of bins.
|
||||
if (plan.unsupported) continue; // bin ignored or invalid; reserve no slot
|
||||
if (plan.unsupported) { // bin ignored or invalid; reserve no slot
|
||||
m_droppedBins[coverpointp].push_back(cbinp->name());
|
||||
continue;
|
||||
}
|
||||
CoverpointBins& bins = m_cpBins.at(cpVarp);
|
||||
const uint32_t firstValue = bins.total;
|
||||
const uint32_t firstDeclared = static_cast<uint32_t>(idx);
|
||||
@@ -1942,7 +2259,10 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
UASSERT_OBJ(!dynamic, cbinp, "Runtime value metadata for a real coverpoint");
|
||||
bool unsupported = false;
|
||||
std::vector<AstNodeExpr*> values = extractArrayValues(cbinp, exprp, unsupported);
|
||||
if (unsupported) continue; // bin ignored (COVERIGN emitted); reserve no slot
|
||||
if (unsupported) { // bin ignored (COVERIGN emitted); reserve no slot
|
||||
m_droppedBins[coverpointp].push_back(cbinp->name());
|
||||
continue;
|
||||
}
|
||||
namerStmts.push_back(makeNamer(cpVarp, cbinp, static_cast<int64_t>(values.size()),
|
||||
static_cast<uint32_t>(idx), values));
|
||||
for (AstNodeExpr* valuep : values) {
|
||||
@@ -1966,7 +2286,11 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
++idx;
|
||||
}
|
||||
}
|
||||
// A value a sized array's bin holds is no default bin's; only sampling tells which do
|
||||
// A cross selecting an ignored bins declaration selects no bins
|
||||
for (const std::string& name : m_droppedBins[coverpointp]) {
|
||||
m_cpBins.at(cpVarp).spans.emplace(name, BinSpan{});
|
||||
}
|
||||
// A value a constructed bin holds is no default bin's; only sampling tells which do
|
||||
AstVar* sizedMatchedp = nullptr;
|
||||
if (!defaultBins.empty()
|
||||
&& std::any_of(sizedBins.begin(), sizedBins.end(), [](const AstCoverBin* binp) {
|
||||
@@ -2043,7 +2367,7 @@ class FunctionalCoverageVisitor final : public VNVisitor {
|
||||
emitValueList(fl, cpVarp, VCMethod::COVERGROUP_VALUE_PATTERNS, lists.m_patterns);
|
||||
emitValueList(fl, cpVarp, VCMethod::COVERGROUP_VALUE_TRANSITIONS, lists.m_transitions);
|
||||
for (AstCoverBin* const binp : sizedBins) {
|
||||
generateSizedArray(coverpointp, binp, cpVarp, exprp);
|
||||
generateConstructedBins(coverpointp, binp, cpVarp, exprp);
|
||||
}
|
||||
m_constructorp->addStmtsp(
|
||||
itemCall(fl, cpVarp, VCMethod::COVERGROUP_VALUE_FINALIZE)->makeStmt());
|
||||
|
||||
@@ -359,6 +359,9 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
|
||||
if (setp != nodep->transp()) puts(", ");
|
||||
iterateConst(setp);
|
||||
}
|
||||
} else if (VN_IS(nodep->rangesp(), CoverWith)) {
|
||||
puts(" = ");
|
||||
iterateConst(nodep->rangesp());
|
||||
} else if (nodep->rangesp()) { // LCOV_EXCL_BR_LINE - false: CoverBin always has
|
||||
// transp/rangesp/default
|
||||
puts(" = {");
|
||||
@@ -375,6 +378,15 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst {
|
||||
}
|
||||
puts(";\n");
|
||||
}
|
||||
void visit(AstCoverWith* nodep) override {
|
||||
const bool rangeList = !VN_IS(nodep->subp(), CoverpointRef);
|
||||
if (rangeList) putfs(nodep, "{");
|
||||
iterateAndCommaConstNull(nodep->subp());
|
||||
if (rangeList) puts("}");
|
||||
puts(" with (");
|
||||
iterateConst(nodep->filterp());
|
||||
puts(")");
|
||||
}
|
||||
void visit(AstCoverBinsof* nodep) override {
|
||||
putfs(nodep, nodep->isNegated() ? "!binsof(" : "binsof(");
|
||||
iterateConst(nodep->pointp());
|
||||
|
||||
@@ -2319,6 +2319,17 @@ class LinkDotFindVisitor final : public VNVisitor {
|
||||
nullptr);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstCoverWith* nodep) override { // FindVisitor::
|
||||
// The range list is outside the scope of the filter, which declares 'item'
|
||||
iterateAndNextNull(nodep->subp());
|
||||
VL_RESTORER(m_curSymp);
|
||||
++m_modWithNum;
|
||||
m_curSymp = m_statep->insertBlock(m_curSymp, "__VcoverWith" + cvtToStr(m_modWithNum),
|
||||
nodep, m_classOrPackagep);
|
||||
m_curSymp->fallbackp(VL_RESTORER_PREV(m_curSymp));
|
||||
iterateAndNextNull(nodep->itemp());
|
||||
iterateAndNextNull(nodep->filterp());
|
||||
}
|
||||
|
||||
void visit(AstNode* nodep) override { iterateChildren(nodep); } // FindVisitor::
|
||||
|
||||
@@ -5751,6 +5762,19 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
||||
nodep->prodp(findProd(nodep, m_curSymp, nodep->name()));
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstCoverWith* nodep) override {
|
||||
LINKDOT_VISIT_START();
|
||||
UINFO(5, indent() << "visit " << nodep);
|
||||
checkNoDot(nodep);
|
||||
iterateAndNextNull(nodep->subp());
|
||||
// The type of 'item' is that of the coverpoint expression, which may name 'item' too
|
||||
iterateAndNextNull(nodep->itemp()->childDTypep());
|
||||
VL_RESTORER(m_curSymp);
|
||||
m_ds.m_dotSymp = m_curSymp = m_statep->getNodeSym(nodep);
|
||||
iterateAndNextNull(nodep->itemp());
|
||||
iterateAndNextNull(nodep->filterp());
|
||||
m_ds.m_dotSymp = VL_RESTORER_PREV(m_curSymp);
|
||||
}
|
||||
void visit(AstWith* nodep) override {
|
||||
LINKDOT_VISIT_START();
|
||||
UINFO(5, indent() << "visit " << nodep);
|
||||
|
||||
@@ -63,6 +63,7 @@ class LinkParseVisitor final : public VNVisitor {
|
||||
AstNodeDType* m_dtypep = nullptr; // Current data type
|
||||
AstNodeExpr* m_defaultInSkewp = nullptr; // Current default input skew
|
||||
AstNodeExpr* m_defaultOutSkewp = nullptr; // Current default output skew
|
||||
AstCoverpoint* m_coverpointp = nullptr; // Current coverpoint
|
||||
int m_anonUdpId = 0; // Counter for anonymous UDP instances
|
||||
int m_coverpointNum = 0; // Counter for unnamed coverpoints within current covergroup
|
||||
int m_genblkAbove = 0; // Begin block number of if/case/for above
|
||||
@@ -1435,6 +1436,47 @@ class LinkParseVisitor final : public VNVisitor {
|
||||
VL_DO_DANGLING(optp->deleteTree(), optp);
|
||||
}
|
||||
}
|
||||
VL_RESTORER(m_coverpointp);
|
||||
m_coverpointp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
void visit(AstCoverBin* nodep) override {
|
||||
cleanFileline(nodep);
|
||||
if (!m_coverpointp && VN_IS(nodep->rangesp(), CoverWith)) {
|
||||
// A 'with' filter's candidates are of its coverpoint's type
|
||||
nodep->rangesp()->v3warn(COVERIGN, "Unsupported: 'with' in cover bin outside a "
|
||||
"coverpoint; bin "
|
||||
<< nodep->prettyNameQ() << " ignored");
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
return;
|
||||
}
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
void visit(AstCoverWith* nodep) override {
|
||||
cleanFileline(nodep);
|
||||
UASSERT_OBJ(m_coverpointp, nodep, "Bin 'with' filter outside a coverpoint");
|
||||
if (const AstCoverpointRef* const refp = VN_CAST(nodep->subp(), CoverpointRef)) {
|
||||
if (refp->name() != m_coverpointp->name()) {
|
||||
refp->v3error("A bin 'with' filter may name only its own coverpoint "
|
||||
<< m_coverpointp->prettyNameQ() << ", not " << refp->prettyNameQ()
|
||||
<< " (IEEE 1800-2023 19.5.1.1)");
|
||||
}
|
||||
}
|
||||
// The candidate value, of the coverpoint's type, which a filter need not read. The
|
||||
// standard names it, so it hides another 'item' in the filter without a warning.
|
||||
FileLine* const fl = nodep->fileline();
|
||||
FileLine* const flNoWarn = new FileLine{fl};
|
||||
flNoWarn->modifyWarnOff(V3ErrorCode::UNUSEDSIGNAL, true);
|
||||
flNoWarn->modifyWarnOff(V3ErrorCode::VARHIDDEN, true);
|
||||
AstVar* const varp = new AstVar{flNoWarn, VVarType::VAR, "item", VFlagChildDType{},
|
||||
new AstRefDType{fl, AstRefDType::FlagTypeOfExpr{},
|
||||
m_coverpointp->exprp()->cloneTree(false)}};
|
||||
varp->funcLocal(true);
|
||||
varp->noReset(true);
|
||||
varp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
|
||||
nodep->itemp(varp);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
|
||||
|
||||
@@ -2169,6 +2169,15 @@ class WidthVisitor final : public VNVisitor {
|
||||
" type coverage is the weighted average of the"
|
||||
" instances");
|
||||
}
|
||||
} else if (nodep->optType() == VCoverOptionType::DISTRIBUTE_FIRST) {
|
||||
// A bins 'with' filter applies before the values are distributed to the bins
|
||||
// (IEEE 1800-2023 19.5.1.1)
|
||||
const AstConst* const constp = VN_CAST(nodep->valuep(), Const);
|
||||
if (!constp || !constp->num().isEqZero()) {
|
||||
nodep->v3warn(COVERIGN, "Ignoring unsupported: 'type_option.distribute_first';"
|
||||
" 'with' filters apply before values are distributed"
|
||||
" to bins");
|
||||
}
|
||||
}
|
||||
// Add more options here as needed (goal, at_least, per_instance, comment)
|
||||
|
||||
@@ -2220,6 +2229,8 @@ class WidthVisitor final : public VNVisitor {
|
||||
userIterate(rangep, nullptr);
|
||||
fill(rangep->lhsp());
|
||||
fill(rangep->rhsp());
|
||||
} else if (VN_IS(itemp, CoverWith)) {
|
||||
userIterate(itemp, m_vup);
|
||||
} else {
|
||||
itemp = userIterateSubtreeReturnEdits(itemp, WidthVP{SELF, BOTH}.p());
|
||||
fill(V3Const::constifyEdit(itemp));
|
||||
@@ -2242,6 +2253,37 @@ class WidthVisitor final : public VNVisitor {
|
||||
}
|
||||
userIterateAndNext(nodep->transp(), m_vup);
|
||||
}
|
||||
void visit(AstCoverWith* nodep) override {
|
||||
// The candidate value 'item' has the coverpoint's type (IEEE 1800-2023 19.5.1.1)
|
||||
userIterateAndNext(nodep->itemp(), nullptr);
|
||||
if (!nodep->itemp()->dtypeSkipRefp()->isIntegralOrPacked()) {
|
||||
nodep->v3error("Bin 'with' filters are not allowed on a coverpoint of a "
|
||||
"non-integral expression (IEEE 1800-2023 19.5.1.1)");
|
||||
}
|
||||
if (!VN_IS(nodep->subp(), CoverpointRef)) {
|
||||
widthCovergroupRanges(nodep->subp(), m_vup->dtypep()->width());
|
||||
}
|
||||
// The filter is true for a nonzero value (IEEE 1800-2023 12.4), of a type assignment
|
||||
// compatible with an integral type (19.5.1.1)
|
||||
AstNodeExpr* const filterp = VN_AS(
|
||||
userIterateSubtreeReturnEdits(nodep->filterp(), WidthVP{SELF, BOTH}.p()), NodeExpr);
|
||||
FileLine* const fl = filterp->fileline();
|
||||
const AstNodeDType* const resultp = filterp->dtypep()->skipRefp();
|
||||
if (resultp->isDouble()) {
|
||||
VNRelinker relinker;
|
||||
filterp->unlinkFrBack(&relinker);
|
||||
relinker.relink(
|
||||
new AstNeqD{fl, filterp, new AstConst{fl, AstConst::RealDouble{}, 0.0}});
|
||||
} else if (!resultp->isIntegralOrPacked()) {
|
||||
filterp->v3error("Bin 'with' filter must be assignment compatible with an integral "
|
||||
"type, not "
|
||||
<< resultp->prettyDTypeNameQ() << " (IEEE 1800-2023 19.5.1.1)");
|
||||
filterp->replaceWith(new AstConst{fl, AstConst::BitFalse{}});
|
||||
VL_DO_DANGLING(pushDeletep(filterp), filterp);
|
||||
} else {
|
||||
fixWidthReduce(filterp);
|
||||
}
|
||||
}
|
||||
void visit(AstCoverTransSet* nodep) override { userIterateAndNext(nodep->itemsp(), m_vup); }
|
||||
void visit(AstCoverTransItem* nodep) override {
|
||||
widthCovergroupRanges(nodep->valuesp(), m_vup ? m_vup->dtypep()->width() : 0);
|
||||
|
||||
+15
-18
@@ -7186,26 +7186,17 @@ bins_or_options<nodep>: // ==IEEE: bins_or_options
|
||||
| yILLEGAL_BINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' iffE
|
||||
{ $$ = GRAMMARP->coverBinArray(new AstCoverBin{$<fl>2, *$2, $6, false, true, false, $8}, $3); }
|
||||
| yBINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ GRAMMARP->coverBinArrayUnsized($3);
|
||||
AstCoverBin* const binp = new AstCoverBin{$<fl>2, *$2, $6, false, false};
|
||||
BBCOVERIGN($<fl>8, "Unsupported: 'with' in cover bin (bin created without filter)");
|
||||
DEL($10, $12); $$ = binp; }
|
||||
{ $$ = GRAMMARP->coverBinArray(new AstCoverBin{$<fl>2, *$2, new AstCoverWith{$8, $6, $10}, false, false, false, $12}, $3); }
|
||||
| yIGNORE_BINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ GRAMMARP->coverBinArrayUnsized($3);
|
||||
AstCoverBin* const binp = new AstCoverBin{$<fl>2, *$2, $6, true, false};
|
||||
BBCOVERIGN($<fl>8, "Unsupported: 'with' in cover bin (bin created without filter)");
|
||||
DEL($10, $12); $$ = binp; }
|
||||
{ $$ = GRAMMARP->coverBinArray(new AstCoverBin{$<fl>2, *$2, new AstCoverWith{$8, $6, $10}, true, false, false, $12}, $3); }
|
||||
| yILLEGAL_BINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ GRAMMARP->coverBinArrayUnsized($3);
|
||||
AstCoverBin* const binp = new AstCoverBin{$<fl>2, *$2, $6, false, true};
|
||||
BBCOVERIGN($<fl>8, "Unsupported: 'with' in cover bin (bin created without filter)");
|
||||
DEL($10, $12); $$ = binp; }
|
||||
{ $$ = GRAMMARP->coverBinArray(new AstCoverBin{$<fl>2, *$2, new AstCoverWith{$8, $6, $10}, false, true, false, $12}, $3); }
|
||||
| yBINS idAny/*bin_identifier*/ bins_orBraE '=' id/*cover_point_id*/ yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = nullptr; GRAMMARP->coverBinArrayUnsized($3); BBCOVERIGN($<fl>6, "Unsupported: 'with' in cover bin"); DEL($8, $10); }
|
||||
{ $$ = GRAMMARP->coverBinArray(new AstCoverBin{$<fl>2, *$2, new AstCoverWith{$6, new AstCoverpointRef{$<fl>5, *$5}, $8}, false, false, false, $10}, $3); }
|
||||
| yIGNORE_BINS idAny/*bin_identifier*/ bins_orBraE '=' id/*cover_point_id*/ yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = nullptr; GRAMMARP->coverBinArrayUnsized($3); BBCOVERIGN($<fl>6, "Unsupported: 'with' in cover bin"); DEL($8, $10); }
|
||||
{ $$ = GRAMMARP->coverBinArray(new AstCoverBin{$<fl>2, *$2, new AstCoverWith{$6, new AstCoverpointRef{$<fl>5, *$5}, $8}, true, false, false, $10}, $3); }
|
||||
| yILLEGAL_BINS idAny/*bin_identifier*/ bins_orBraE '=' id/*cover_point_id*/ yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = nullptr; GRAMMARP->coverBinArrayUnsized($3); BBCOVERIGN($<fl>6, "Unsupported: 'with' in cover bin"); DEL($8, $10); }
|
||||
{ $$ = GRAMMARP->coverBinArray(new AstCoverBin{$<fl>2, *$2, new AstCoverWith{$6, new AstCoverpointRef{$<fl>5, *$5}, $8}, false, true, false, $10}, $3); }
|
||||
| yWILDCARD yBINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' iffE
|
||||
{ $$ = GRAMMARP->coverBinArray(new AstCoverBin{$<fl>3, *$3, $7, false, false, true, $9}, $4); }
|
||||
| yWILDCARD yIGNORE_BINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' iffE
|
||||
@@ -7213,11 +7204,17 @@ bins_or_options<nodep>: // ==IEEE: bins_or_options
|
||||
| yWILDCARD yILLEGAL_BINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' iffE
|
||||
{ $$ = GRAMMARP->coverBinArray(new AstCoverBin{$<fl>3, *$3, $7, false, true, true, $9}, $4); }
|
||||
| yWILDCARD yBINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = nullptr; GRAMMARP->coverBinArrayUnsized($4); BBCOVERIGN($<fl>9, "Unsupported: 'with' in wildcard cover bin"); DEL($7, $11, $13); }
|
||||
{ $$ = GRAMMARP->coverBinArray(new AstCoverBin{$<fl>3, *$3, new AstCoverWith{$9, $7, $11}, false, false, true, $13}, $4); }
|
||||
| yWILDCARD yIGNORE_BINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = nullptr; GRAMMARP->coverBinArrayUnsized($4); BBCOVERIGN($<fl>9, "Unsupported: 'with' in wildcard cover bin"); DEL($7, $11, $13); }
|
||||
{ $$ = GRAMMARP->coverBinArray(new AstCoverBin{$<fl>3, *$3, new AstCoverWith{$9, $7, $11}, true, false, true, $13}, $4); }
|
||||
| yWILDCARD yILLEGAL_BINS idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = nullptr; GRAMMARP->coverBinArrayUnsized($4); BBCOVERIGN($<fl>9, "Unsupported: 'with' in wildcard cover bin"); DEL($7, $11, $13); }
|
||||
{ $$ = GRAMMARP->coverBinArray(new AstCoverBin{$<fl>3, *$3, new AstCoverWith{$9, $7, $11}, false, true, true, $13}, $4); }
|
||||
| yWILDCARD yBINS idAny/*bin_identifier*/ bins_orBraE '=' id/*cover_point_id*/ yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = GRAMMARP->coverBinArray(new AstCoverBin{$<fl>3, *$3, new AstCoverWith{$7, new AstCoverpointRef{$<fl>6, *$6}, $9}, false, false, true, $11}, $4); }
|
||||
| yWILDCARD yIGNORE_BINS idAny/*bin_identifier*/ bins_orBraE '=' id/*cover_point_id*/ yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = GRAMMARP->coverBinArray(new AstCoverBin{$<fl>3, *$3, new AstCoverWith{$7, new AstCoverpointRef{$<fl>6, *$6}, $9}, true, false, true, $11}, $4); }
|
||||
| yWILDCARD yILLEGAL_BINS idAny/*bin_identifier*/ bins_orBraE '=' id/*cover_point_id*/ yWITH__PAREN '(' cgexpr ')' iffE
|
||||
{ $$ = GRAMMARP->coverBinArray(new AstCoverBin{$<fl>3, *$3, new AstCoverWith{$7, new AstCoverpointRef{$<fl>6, *$6}, $9}, false, true, true, $11}, $4); }
|
||||
//
|
||||
// // cgexpr part of trans_list
|
||||
| yBINS idAny/*bin_identifier*/ bins_orBraE '=' trans_list iffE
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
: ... note: In instance 't'
|
||||
70 | bins b_xz_arr_hi[] = {[4'h0:4'bzzzz]};
|
||||
| ^~~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_autobins_bad.v:77:12: Unsupported: array 'bins' covering more than 1024 values (e.g. an open '[lo:$]' range over a wide coverpoint); bin ignored
|
||||
%Warning-COVERIGN: t/t_covergroup_autobins_bad.v:77:12: Unsupported: array 'bins' covering more than 1024 values (e.g. an open '[lo:$]' range over a wide coverpoint); bin 'b_huge' ignored
|
||||
: ... note: In instance 't'
|
||||
: ... Suggest a larger --coverage-max-bins
|
||||
77 | bins b_huge[] = {[0:$]};
|
||||
@@ -215,12 +215,12 @@
|
||||
: ... note: In instance 't'
|
||||
196 | ignore_bins nonconstant = {size_var};
|
||||
| ^~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_autobins_bad.v:243:12: Unsupported: array 'bins' covering more than 1024 values (e.g. an open '[lo:$]' range over a wide coverpoint); bin ignored
|
||||
%Warning-COVERIGN: t/t_covergroup_autobins_bad.v:243:12: Unsupported: array 'bins' covering more than 1024 values (e.g. an open '[lo:$]' range over a wide coverpoint); bin 'over_limit' ignored
|
||||
: ... note: In instance 't'
|
||||
: ... Suggest a larger --coverage-max-bins
|
||||
243 | bins over_limit[] = {[0 : 1024]};
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_autobins_bad.v:244:12: Unsupported: array 'bins' covering more than 1024 values (e.g. an open '[lo:$]' range over a wide coverpoint); bin ignored
|
||||
%Warning-COVERIGN: t/t_covergroup_autobins_bad.v:244:12: Unsupported: array 'bins' covering more than 1024 values (e.g. an open '[lo:$]' range over a wide coverpoint); bin 'split_over_limit' ignored
|
||||
: ... note: In instance 't'
|
||||
: ... Suggest a larger --coverage-max-bins
|
||||
244 | bins split_over_limit[] = {[0 : 511], [512 : 1024]};
|
||||
@@ -233,7 +233,7 @@
|
||||
: ... note: In instance 't'
|
||||
253 | bins auto[4];
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_autobins_bad.v:257:12: Unsupported: array 'bins' of a real coverpoint covering more than 1024 values; bin ignored.
|
||||
%Warning-COVERIGN: t/t_covergroup_autobins_bad.v:257:12: Unsupported: array 'bins' of a real coverpoint covering more than 1024 values; bin 'over_limit' ignored.
|
||||
: ... note: In instance 't'
|
||||
: ... Suggest a larger --coverage-max-real-bins
|
||||
257 | bins over_limit[] = {[0 : 1024]};
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
%Error: t/t_covergroup_bins_dup_bad.v:14:12: Duplicate bin 'a' in coverpoint 'filtered' (IEEE 1800-2023 3.13)
|
||||
: ... note: In instance 't'
|
||||
14 | bins a = {[4 : 7]} with (item > 5);
|
||||
| ^
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
%Error: t/t_covergroup_bins_dup_bad.v:18:19: Duplicate bin 'a' in coverpoint 'kinds' (IEEE 1800-2023 3.13)
|
||||
: ... note: In instance 't'
|
||||
18 | ignore_bins a = {[4 : 7]};
|
||||
| ^
|
||||
%Error: Exiting due to
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of either the GNU Lesser General Public License Version 3
|
||||
# or the Perl Artistic License Version 2.0.
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('linter')
|
||||
|
||||
test.lint(fails=True, expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
@@ -0,0 +1,27 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// A bins declaration may not redeclare a bin name of its coverpoint (IEEE 1800-2023 3.13)
|
||||
|
||||
module t;
|
||||
bit [3:0] v;
|
||||
covergroup cg;
|
||||
filtered: coverpoint v {
|
||||
bins a = {[0 : 3]} with (item > 1);
|
||||
bins a = {[4 : 7]} with (item > 5); // <--- Bad: duplicate name
|
||||
}
|
||||
kinds: coverpoint v {
|
||||
bins a = {[0 : 3]};
|
||||
ignore_bins a = {[4 : 7]}; // <--- Bad: duplicate name
|
||||
}
|
||||
// Bin names are those of their coverpoint
|
||||
other: coverpoint v {
|
||||
bins a = {[0 : 3]};
|
||||
}
|
||||
endgroup
|
||||
cg inst = new;
|
||||
initial $finish;
|
||||
endmodule
|
||||
@@ -25,7 +25,7 @@
|
||||
: ... note: In instance 't'
|
||||
27 | bins real_bound[2] = {[lo : 5]};
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_exclusions_unsup.v:37:21: Unsupported: sized wildcard array 'bins' of more than --coverage-max-bins of 1024 ranges of values; bin ignored
|
||||
%Warning-COVERIGN: t/t_covergroup_exclusions_unsup.v:37:21: Unsupported: sized wildcard array 'bins' of more than --coverage-max-bins of 1024 ranges of values; bin 'runs' ignored
|
||||
: ... note: In instance 't'
|
||||
: ... Suggest a larger --coverage-max-bins
|
||||
37 | wildcard bins runs[2] = {16'b????_????_????_???1};
|
||||
@@ -46,7 +46,7 @@
|
||||
: ... note: In instance 't'
|
||||
63 | dynamic_cross: cross cp_real, cp_dynamic{bins selected = binsof (cp_real) intersect {1};}
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_exclusions_unsup.v:69:29: Unsupported: sized wildcard array 'illegal_bins' of more than --coverage-max-bins of 1024 ranges of values; treated as one bin
|
||||
%Warning-COVERIGN: t/t_covergroup_exclusions_unsup.v:69:29: Unsupported: sized wildcard array 'illegal_bins' of more than --coverage-max-bins of 1024 ranges of values; bin 'runs' treated as one bin
|
||||
: ... note: In instance 't'
|
||||
: ... Suggest a larger --coverage-max-bins
|
||||
69 | wildcard illegal_bins runs[2] = {16'b????_????_????_???1};
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
%Warning-COVERIGN: t/t_covergroup_max_bins_unsup.v:17:12: Unsupported: array 'bins' covering more than 4294967295 values (e.g. an open '[lo:$]' range over a wide coverpoint); bin ignored
|
||||
%Warning-COVERIGN: t/t_covergroup_max_bins_unsup.v:17:12: Unsupported: array 'bins' covering more than 4294967295 values (e.g. an open '[lo:$]' range over a wide coverpoint); bin 'over_limit' ignored
|
||||
: ... note: In instance 't'
|
||||
: ... Suggest a larger --coverage-max-bins
|
||||
17 | bins over_limit[] = {[0 : $]};
|
||||
| ^~~~~~~~~~
|
||||
... For warning description see https://verilator.org/warn/COVERIGN?v=latest
|
||||
... Use "/* verilator lint_off COVERIGN */" and lint_on around source to disable this message.
|
||||
%Warning-COVERIGN: t/t_covergroup_max_bins_unsup.v:21:21: Unsupported: wildcard array 'bins' of more than --coverage-max-bins of 4294967295 values; bin ignored
|
||||
%Warning-COVERIGN: t/t_covergroup_max_bins_unsup.v:21:21: Unsupported: wildcard array 'bins' of more than --coverage-max-bins of 4294967295 values; bin 'over_limit' ignored
|
||||
: ... note: In instance 't'
|
||||
: ... Suggest a larger --coverage-max-bins
|
||||
21 | wildcard bins over_limit[] = {32'h????_????};
|
||||
@@ -21,12 +21,12 @@
|
||||
28 | cp_total: coverpoint data {
|
||||
| ^~~~~~~~~~
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Warning-COVERIGN: t/t_covergroup_max_bins_unsup.v:34:12: Unsupported: array 'bins' of a real coverpoint covering more than 2 values; bin ignored.
|
||||
%Warning-COVERIGN: t/t_covergroup_max_bins_unsup.v:34:12: Unsupported: array 'bins' of a real coverpoint covering more than 2 values; bin 'over_limit' ignored.
|
||||
: ... note: In instance 't'
|
||||
: ... Suggest a larger --coverage-max-real-bins
|
||||
34 | bins over_limit[] = {[1 : 3]};
|
||||
| ^~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_max_bins_unsup.v:38:28: Unsupported: wildcard array 'ignore_bins' of more than --coverage-max-bins of 4294967295 values; treated as one bin
|
||||
%Warning-COVERIGN: t/t_covergroup_max_bins_unsup.v:38:28: Unsupported: wildcard array 'ignore_bins' of more than --coverage-max-bins of 4294967295 values; bin 'over_limit' treated as one bin
|
||||
: ... note: In instance 't'
|
||||
: ... Suggest a larger --coverage-max-bins
|
||||
38 | wildcard ignore_bins over_limit[] = {32'h????_????};
|
||||
|
||||
@@ -11,16 +11,20 @@
|
||||
: ... note: In instance 't'
|
||||
18 | bins fraction[1.5] = {[0 : 3]};
|
||||
| ^~~
|
||||
%Error: t/t_covergroup_sized_bad.v:20:12: Bins array size must be integral, not '$' (IEEE 1800-2023 19.5.1)
|
||||
%Error: t/t_covergroup_sized_bad.v:21:12: Bins array size must be integral, not '$' (IEEE 1800-2023 19.5.1)
|
||||
: ... note: In instance 't'
|
||||
20 | bins param_size[UNBOUNDED] = {[0 : 3]};
|
||||
21 | bins param_size[UNBOUNDED] = {[0 : 3]};
|
||||
| ^~~~~~~~~~
|
||||
%Error: t/t_covergroup_sized_bad.v:19:29: Four-state (x/z) value in array bins range bound; range bounds must be two-state constants
|
||||
: ... note: In instance 't'
|
||||
19 | bins four_state[2] = {[4'b000x : 4'hf]};
|
||||
| ^
|
||||
%Error: t/t_covergroup_sized_bad.v:21:12: Bins value may not be '$', which may only bound a range (IEEE 1800-2023 6.20.7)
|
||||
%Error: t/t_covergroup_sized_bad.v:20:31: Four-state (x/z) value in bin range bound; range bounds must be two-state constants
|
||||
: ... note: In instance 't'
|
||||
21 | bins param_value[2] = {UNBOUNDED};
|
||||
20 | bins four_state_with = {[4'b000x : 4'hf]} with (1);
|
||||
| ^
|
||||
%Error: t/t_covergroup_sized_bad.v:22:12: Bins value may not be '$', which may only bound a range (IEEE 1800-2023 6.20.7)
|
||||
: ... note: In instance 't'
|
||||
22 | bins param_value[2] = {UNBOUNDED};
|
||||
| ^~~~~~~~~~~
|
||||
%Error: Exiting due to
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// A sized array of bins needs a positive integral size (IEEE 1800-2023 19.5.1), and two-state
|
||||
// range bounds, of which '$' may only be a whole bound (6.20.7)
|
||||
// range bounds, as do bins with a 'with' filter, of which '$' may only be a whole bound (6.20.7)
|
||||
|
||||
module t;
|
||||
logic [3:0] value;
|
||||
@@ -17,6 +17,7 @@ module t;
|
||||
bins negative[-1] = {[0 : 3]}; // <--- Bad: negative
|
||||
bins fraction[1.5] = {[0 : 3]}; // <--- Bad: not integral
|
||||
bins four_state[2] = {[4'b000x : 4'hf]}; // <--- Bad: x bound
|
||||
bins four_state_with = {[4'b000x : 4'hf]} with (1); // <--- Bad: x bound
|
||||
bins param_size[UNBOUNDED] = {[0 : 3]}; // <--- Bad: '$'
|
||||
bins param_value[2] = {UNBOUNDED}; // <--- Bad: '$'
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
%Error: t/t_covergroup_sized_run_bad.v:21: Coverage bin array size must be a positive integer (IEEE 1800-2023 19.5.1)
|
||||
%Error: t/t_covergroup_sized_run_bad.v:21: Coverage bin array 'b' size must be a positive integer (IEEE 1800-2023 19.5.1)
|
||||
-Info: t/t_covergroup_sized_run_bad.v:21: Verilog $stop, ignored due to +verilator+error+limit
|
||||
%Error: t/t_covergroup_sized_run_bad.v:21: Coverage bin array size must be a positive integer (IEEE 1800-2023 19.5.1)
|
||||
%Warning: t/t_covergroup_sized_run_bad.v:27: Coverage bin array needs more bins than --coverage-max-bins; bin ignored
|
||||
%Error: t/t_covergroup_sized_run_bad.v:21: Coverage bin array 'b' size must be a positive integer (IEEE 1800-2023 19.5.1)
|
||||
%Warning: t/t_covergroup_sized_run_bad.v:27: Coverage bin array needs more bins than --coverage-max-bins; bin 'b' ignored
|
||||
%Warning: t/t_covergroup_sized_run_bad.v:45: Unsupported: cross coverage with more than 2^32-1 tuples; cross ignored
|
||||
*-* All Finished *-*
|
||||
|
||||
@@ -9,12 +9,6 @@
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:103:18: Unsupported: function call in coverage select expression
|
||||
103 | bins one = crossfunc();
|
||||
| ^~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:117:21: Unsupported: 'with' in cover bin (bin created without filter)
|
||||
117 | { bins ba = {a} with ( b ); }
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:120:32: Unsupported: 'with' in wildcard cover bin
|
||||
120 | { wildcard bins bwaw = {a} with ( b ); }
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:123:27: Unsupported: 'sequence' in default cover bin
|
||||
123 | { bins defs = default sequence; }
|
||||
| ^~~~~~~~
|
||||
@@ -51,24 +45,6 @@
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:141:12: Unsupported: 'bins' array (non-auto)
|
||||
141 | { bins nonAuto[4]; }
|
||||
| ^~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:143:35: Unsupported: 'with' in cover bin (bin created without filter)
|
||||
143 | { ignore_bins ib_with = {1,2} with ( b ); }
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:144:37: Unsupported: 'with' in cover bin (bin created without filter)
|
||||
144 | { illegal_bins lib_with = {1,2} with ( b ); }
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:146:29: Unsupported: 'with' in cover bin
|
||||
146 | { ignore_bins ib_cp = a with ( b ); }
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:147:31: Unsupported: 'with' in cover bin
|
||||
147 | { illegal_bins lib_cp = a with ( b ); }
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:149:45: Unsupported: 'with' in wildcard cover bin
|
||||
149 | { wildcard ignore_bins wib_with = {1,2} with ( b ); }
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:150:47: Unsupported: 'with' in wildcard cover bin
|
||||
150 | { wildcard illegal_bins wlib_with = {1,2} with ( b ); }
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:152:7: Unsupported: 'wildcard' transition list in cover bin
|
||||
152 | { wildcard ignore_bins wib_trans = ( 1 => 2 ); }
|
||||
| ^~~~~~~~
|
||||
@@ -84,35 +60,29 @@
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:158:24: Unsupported: 'bins' explicit array size (treated as '[]')
|
||||
158 | { bins trans_sized[2] = ( 1 => 2 ); }
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:163:24: Unsupported: 'with' in cover bin
|
||||
163 | bins div_by_2 = a with (item % 2 == 0);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:164:32: Unsupported: 'with' in cover bin
|
||||
164 | bins div_by_2_paren[] = a with (item % 2 == 0);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:170:20: Unsupported: 'with' in coverage select expression
|
||||
170 | bins bin_e = with (a);
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:163:20: Unsupported: 'with' in coverage select expression
|
||||
163 | bins bin_e = with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:171:24: Unsupported: 'with' in coverage select expression
|
||||
171 | bins bin_not_e = ! with (a);
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:164:24: Unsupported: 'with' in coverage select expression
|
||||
164 | bins bin_not_e = ! with (a);
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:173:33: Unsupported: 'with' in coverage select expression
|
||||
173 | bins bin_with = binsof(a) with (a);
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:166:33: Unsupported: 'with' in coverage select expression
|
||||
166 | bins bin_with = binsof(a) with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:174:49: Unsupported: 'with' in coverage select expression
|
||||
174 | bins bin_or_with = binsof(a) || binsof(a) with (a);
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:167:49: Unsupported: 'with' in coverage select expression
|
||||
167 | bins bin_or_with = binsof(a) || binsof(a) with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:175:50: Unsupported: 'with' in coverage select expression
|
||||
175 | bins bin_and_with = binsof(a) && binsof(a) with (a);
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:168:50: Unsupported: 'with' in coverage select expression
|
||||
168 | bins bin_and_with = binsof(a) && binsof(a) with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:177:40: Unsupported: 'with' in coverage select expression
|
||||
177 | ignore_bins ib_cross = binsof(a) with (a);
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:170:40: Unsupported: 'with' in coverage select expression
|
||||
170 | ignore_bins ib_cross = binsof(a) with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:178:42: Unsupported: 'with' in coverage select expression
|
||||
178 | illegal_bins lib_cross = binsof(a) with (a);
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:171:42: Unsupported: 'with' in coverage select expression
|
||||
171 | illegal_bins lib_cross = binsof(a) with (a);
|
||||
| ^~~~
|
||||
%Error-UNSUPPORTED: t/t_covergroup_unsup.v:203:5: Unsupported: covergroup inheritance (extends)
|
||||
203 | covergroup extends cg_empty;
|
||||
%Error-UNSUPPORTED: t/t_covergroup_unsup.v:196:5: Unsupported: covergroup inheritance (extends)
|
||||
196 | covergroup extends cg_empty;
|
||||
| ^~~~~~~~~~
|
||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
||||
%Error: Exiting due to
|
||||
|
||||
@@ -158,13 +158,6 @@ module t (
|
||||
{ bins trans_sized[2] = ( 1 => 2 ); }
|
||||
endgroup
|
||||
|
||||
covergroup cg_coverpoint_ref;
|
||||
coverpoint a {
|
||||
bins div_by_2 = a with (item % 2 == 0);
|
||||
bins div_by_2_paren[] = a with (item % 2 == 0);
|
||||
}
|
||||
endgroup
|
||||
|
||||
covergroup cg_cross_bins;
|
||||
cross a, b {
|
||||
bins bin_e = with (a);
|
||||
|
||||
@@ -9,12 +9,6 @@
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:103:18: Unsupported: function call in coverage select expression
|
||||
103 | bins one = crossfunc();
|
||||
| ^~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:117:21: Unsupported: 'with' in cover bin (bin created without filter)
|
||||
117 | { bins ba = {a} with ( b ); }
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:120:32: Unsupported: 'with' in wildcard cover bin
|
||||
120 | { wildcard bins bwaw = {a} with ( b ); }
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:123:27: Unsupported: 'sequence' in default cover bin
|
||||
123 | { bins defs = default sequence; }
|
||||
| ^~~~~~~~
|
||||
@@ -51,24 +45,6 @@
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:141:12: Unsupported: 'bins' array (non-auto)
|
||||
141 | { bins nonAuto[4]; }
|
||||
| ^~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:143:35: Unsupported: 'with' in cover bin (bin created without filter)
|
||||
143 | { ignore_bins ib_with = {1,2} with ( b ); }
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:144:37: Unsupported: 'with' in cover bin (bin created without filter)
|
||||
144 | { illegal_bins lib_with = {1,2} with ( b ); }
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:146:29: Unsupported: 'with' in cover bin
|
||||
146 | { ignore_bins ib_cp = a with ( b ); }
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:147:31: Unsupported: 'with' in cover bin
|
||||
147 | { illegal_bins lib_cp = a with ( b ); }
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:149:45: Unsupported: 'with' in wildcard cover bin
|
||||
149 | { wildcard ignore_bins wib_with = {1,2} with ( b ); }
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:150:47: Unsupported: 'with' in wildcard cover bin
|
||||
150 | { wildcard illegal_bins wlib_with = {1,2} with ( b ); }
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:152:7: Unsupported: 'wildcard' transition list in cover bin
|
||||
152 | { wildcard ignore_bins wib_trans = ( 1 => 2 ); }
|
||||
| ^~~~~~~~
|
||||
@@ -84,32 +60,26 @@
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:158:24: Unsupported: 'bins' explicit array size (treated as '[]')
|
||||
158 | { bins trans_sized[2] = ( 1 => 2 ); }
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:163:24: Unsupported: 'with' in cover bin
|
||||
163 | bins div_by_2 = a with (item % 2 == 0);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:164:32: Unsupported: 'with' in cover bin
|
||||
164 | bins div_by_2_paren[] = a with (item % 2 == 0);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:170:20: Unsupported: 'with' in coverage select expression
|
||||
170 | bins bin_e = with (a);
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:163:20: Unsupported: 'with' in coverage select expression
|
||||
163 | bins bin_e = with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:171:24: Unsupported: 'with' in coverage select expression
|
||||
171 | bins bin_not_e = ! with (a);
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:164:24: Unsupported: 'with' in coverage select expression
|
||||
164 | bins bin_not_e = ! with (a);
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:173:33: Unsupported: 'with' in coverage select expression
|
||||
173 | bins bin_with = binsof(a) with (a);
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:166:33: Unsupported: 'with' in coverage select expression
|
||||
166 | bins bin_with = binsof(a) with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:174:49: Unsupported: 'with' in coverage select expression
|
||||
174 | bins bin_or_with = binsof(a) || binsof(a) with (a);
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:167:49: Unsupported: 'with' in coverage select expression
|
||||
167 | bins bin_or_with = binsof(a) || binsof(a) with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:175:50: Unsupported: 'with' in coverage select expression
|
||||
175 | bins bin_and_with = binsof(a) && binsof(a) with (a);
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:168:50: Unsupported: 'with' in coverage select expression
|
||||
168 | bins bin_and_with = binsof(a) && binsof(a) with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:177:40: Unsupported: 'with' in coverage select expression
|
||||
177 | ignore_bins ib_cross = binsof(a) with (a);
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:170:40: Unsupported: 'with' in coverage select expression
|
||||
170 | ignore_bins ib_cross = binsof(a) with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:178:42: Unsupported: 'with' in coverage select expression
|
||||
178 | illegal_bins lib_cross = binsof(a) with (a);
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:171:42: Unsupported: 'with' in coverage select expression
|
||||
171 | illegal_bins lib_cross = binsof(a) with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:98:18: Ignoring unsupported coverage cross option: 'comment'
|
||||
98 | cross a, b { option.comment = "cross"; option.weight = 12; option.per_instance = 1; }
|
||||
@@ -120,37 +90,65 @@
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:103:7: Unsupported: explicit coverage cross bins
|
||||
103 | bins one = crossfunc();
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:170:7: Unsupported: explicit coverage cross bins
|
||||
170 | bins bin_e = with (a);
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:117:21: Unsupported: 'with' in cover bin outside a coverpoint; bin 'ba' ignored
|
||||
117 | { bins ba = {a} with ( b ); }
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:120:32: Unsupported: 'with' in cover bin outside a coverpoint; bin 'bwaw' ignored
|
||||
120 | { wildcard bins bwaw = {a} with ( b ); }
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:143:35: Unsupported: 'with' in cover bin outside a coverpoint; bin 'ib_with' ignored
|
||||
143 | { ignore_bins ib_with = {1,2} with ( b ); }
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:144:37: Unsupported: 'with' in cover bin outside a coverpoint; bin 'lib_with' ignored
|
||||
144 | { illegal_bins lib_with = {1,2} with ( b ); }
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:146:29: Unsupported: 'with' in cover bin outside a coverpoint; bin 'ib_cp' ignored
|
||||
146 | { ignore_bins ib_cp = a with ( b ); }
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:147:31: Unsupported: 'with' in cover bin outside a coverpoint; bin 'lib_cp' ignored
|
||||
147 | { illegal_bins lib_cp = a with ( b ); }
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:149:45: Unsupported: 'with' in cover bin outside a coverpoint; bin 'wib_with' ignored
|
||||
149 | { wildcard ignore_bins wib_with = {1,2} with ( b ); }
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:150:47: Unsupported: 'with' in cover bin outside a coverpoint; bin 'wlib_with' ignored
|
||||
150 | { wildcard illegal_bins wlib_with = {1,2} with ( b ); }
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:163:7: Unsupported: explicit coverage cross bins
|
||||
163 | bins bin_e = with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:171:7: Unsupported: explicit coverage cross bins
|
||||
171 | bins bin_not_e = ! with (a);
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:164:7: Unsupported: explicit coverage cross bins
|
||||
164 | bins bin_not_e = ! with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:173:7: Unsupported: explicit coverage cross bins
|
||||
173 | bins bin_with = binsof(a) with (a);
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:166:7: Unsupported: explicit coverage cross bins
|
||||
166 | bins bin_with = binsof(a) with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:174:7: Unsupported: explicit coverage cross bins
|
||||
174 | bins bin_or_with = binsof(a) || binsof(a) with (a);
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:167:7: Unsupported: explicit coverage cross bins
|
||||
167 | bins bin_or_with = binsof(a) || binsof(a) with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:175:7: Unsupported: explicit coverage cross bins
|
||||
175 | bins bin_and_with = binsof(a) && binsof(a) with (a);
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:168:7: Unsupported: explicit coverage cross bins
|
||||
168 | bins bin_and_with = binsof(a) && binsof(a) with (a);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:176:47: Unsupported: 'binsof' in coverage select expression
|
||||
176 | bins bin_multiple_fields = binsof(a) && binsof(p.inner_packet.field);
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:169:47: Unsupported: 'binsof' in coverage select expression
|
||||
169 | bins bin_multiple_fields = binsof(a) && binsof(p.inner_packet.field);
|
||||
| ^~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:176:7: Unsupported: explicit coverage cross bins
|
||||
176 | bins bin_multiple_fields = binsof(a) && binsof(p.inner_packet.field);
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:169:7: Unsupported: explicit coverage cross bins
|
||||
169 | bins bin_multiple_fields = binsof(a) && binsof(p.inner_packet.field);
|
||||
| ^~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:177:7: Unsupported: explicit coverage cross bins
|
||||
177 | ignore_bins ib_cross = binsof(a) with (a);
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:170:7: Unsupported: explicit coverage cross bins
|
||||
170 | ignore_bins ib_cross = binsof(a) with (a);
|
||||
| ^~~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:178:7: Unsupported: explicit coverage cross bins
|
||||
178 | illegal_bins lib_cross = binsof(a) with (a);
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:171:7: Unsupported: explicit coverage cross bins
|
||||
171 | illegal_bins lib_cross = binsof(a) with (a);
|
||||
| ^~~~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:46:5: Ignoring unsupported: 'type_option.merge_instances'; type coverage is the weighted average of the instances
|
||||
: ... note: In instance 't'
|
||||
46 | type_option.merge_instances = 1;
|
||||
| ^~~~~~~~~~~
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:47:5: Ignoring unsupported: 'type_option.distribute_first'; 'with' filters apply before values are distributed to bins
|
||||
: ... note: In instance 't'
|
||||
47 | type_option.distribute_first = 1;
|
||||
| ^~~~~~~~~~~
|
||||
%Warning-WIDTHTRUNC: t/t_covergroup_unsup.v:76:5: Logical operator COVERPOINT 'a' expects 1 bit on the iff condition, but iff condition's VARREF 'b' generates 32 bits.
|
||||
: ... note: In instance 't'
|
||||
76 | coverpoint a iff (b);
|
||||
@@ -189,7 +187,7 @@
|
||||
: ... note: In instance 't'
|
||||
101 | cross a, b {
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:169:11: Unsupported: cross of 'a' which is not a coverpoint (implicit coverpoint)
|
||||
%Warning-COVERIGN: t/t_covergroup_unsup.v:162:11: Unsupported: cross of 'a' which is not a coverpoint (implicit coverpoint)
|
||||
: ... note: In instance 't'
|
||||
169 | cross a, b {
|
||||
162 | cross a, b {
|
||||
| ^
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
cg.ct.auto_0: 4
|
||||
cg.ct.auto_1: 4
|
||||
cg.ct.auto_2: 4
|
||||
cg.ct.auto_3: 4
|
||||
cg.ign.all: 8
|
||||
cg.ign.odd [ignore]: 8
|
||||
cg.ign_sized.all: 8
|
||||
@@ -6,3 +10,6 @@ cg.ill.all: 16
|
||||
cg.ill.high [illegal]: 0
|
||||
cg.ill_sized.all: 16
|
||||
cg.ill_sized.odd [illegal]: 0
|
||||
cg.mixed.low: 4
|
||||
cg.with_ign.all: 16
|
||||
cg.xm.sel_low [cross]: 4
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
// Wildcard arrays of bins of more values, or ranges of values, than --coverage-max-bins 4. An
|
||||
// ignore or illegal array still excludes or checks all its values, as one bin, and an ignored
|
||||
// array leaves its coverpoint without bins, rather than automatic ones (IEEE 1800-2023 19.11.1).
|
||||
// Bins filtering as many ranges of values with 'with' are ignored, excluding no values.
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
@@ -17,6 +18,7 @@ module t;
|
||||
bit [3:0] v;
|
||||
bit [3:0] x;
|
||||
int illegal;
|
||||
bit [1:0] t;
|
||||
|
||||
covergroup cg;
|
||||
// The odd values are excluded, so 'all' holds the even ones
|
||||
@@ -40,6 +42,27 @@ module t;
|
||||
only: coverpoint v {
|
||||
wildcard bins odd[2] = {4'b???1};
|
||||
}
|
||||
with_only: coverpoint v {
|
||||
wildcard bins odd[] = {4'b???1} with (1);
|
||||
}
|
||||
with_ign: coverpoint v {
|
||||
bins all = {[0 : 15]};
|
||||
wildcard ignore_bins odd = {4'b???1} with (item > 1);
|
||||
}
|
||||
// A cross selects the bins ignored as no bins, which it then does not have
|
||||
mixed: coverpoint v {
|
||||
bins low = {[0 : 3]};
|
||||
wildcard bins odd[] = {4'b???1} with (item > 8);
|
||||
wildcard bins odd_sized[2] = {4'b???1};
|
||||
bins many[] = {[0 : 15]};
|
||||
}
|
||||
ct: coverpoint t;
|
||||
xm: cross mixed, ct{
|
||||
bins sel_odd = binsof (mixed.odd);
|
||||
bins sel_sized = binsof (mixed.odd_sized);
|
||||
bins sel_many = binsof (mixed.many);
|
||||
bins sel_low = binsof (mixed.low);
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg cg_inst = new;
|
||||
@@ -48,9 +71,10 @@ module t;
|
||||
for (int i = 0; i < 16; ++i) begin
|
||||
v = 4'(i);
|
||||
x = 4'(i % 4 * 2);
|
||||
t = 2'(i);
|
||||
cg_inst.sample();
|
||||
end
|
||||
// All of the coverpoints with bins, which 'only' is not
|
||||
// All of the coverpoints with bins, which 'only' and 'with_only' are not
|
||||
`checkr(cg_inst.get_inst_coverage(), 100.0);
|
||||
if ($value$plusargs("illegal=%d", illegal)) begin
|
||||
x = 4'(illegal);
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
[0] %Error: t_covergroup_wildcard_max_bins.v:34: Assertion failed in top.t.cg.sample: Illegal bin 'high' hit in coverpoint 'ill'
|
||||
%Error: t/t_covergroup_wildcard_max_bins.v:34: Verilog $stop
|
||||
[0] %Error: t_covergroup_wildcard_max_bins.v:36: Assertion failed in top.t.cg.sample: Illegal bin 'high' hit in coverpoint 'ill'
|
||||
%Error: t/t_covergroup_wildcard_max_bins.v:36: Verilog $stop
|
||||
Aborting...
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
[0] %Error: t_covergroup_wildcard_max_bins.v:38: Assertion failed in top.t.cg.sample: Illegal bin 'odd' hit in coverpoint 'ill_sized'
|
||||
%Error: t/t_covergroup_wildcard_max_bins.v:38: Verilog $stop
|
||||
[0] %Error: t_covergroup_wildcard_max_bins.v:40: Assertion failed in top.t.cg.sample: Illegal bin 'odd' hit in coverpoint 'ill_sized'
|
||||
%Error: t/t_covergroup_wildcard_max_bins.v:40: Verilog $stop
|
||||
Aborting...
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
__vlAnonCG_cg.cp.selected[1]: 1
|
||||
__vlAnonCG_cg.cp.selected[2]: 1
|
||||
__vlAnonCG_cg.cp.selected[3]: 1
|
||||
__vlAnonCG_cg.cp.selected[4]: 1
|
||||
__vlAnonCG_cg_member.cp.b[2]: 3
|
||||
__vlAnonCG_cg_member.cp.b[3]: 4
|
||||
cg_bounds.lower.lower[2]: 1
|
||||
cg_bounds.lower.lower[3]: 1
|
||||
cg_bounds.lower.lower[4]: 1
|
||||
cg_bounds.single.single[2]: 1
|
||||
cg_bounds.upper.upper[0]: 1
|
||||
cg_bounds.upper.upper[1]: 2
|
||||
cg_capture.ar.b[0]: 0
|
||||
cg_capture.ar.b[1]: 0
|
||||
cg_capture.ar.b[2]: 0
|
||||
cg_capture.sc.b: 0
|
||||
cg_cross.aa.even_values[0]: 4
|
||||
cg_cross.aa.even_values[2]: 4
|
||||
cg_cross.bb.sized[0]: 8
|
||||
cg_cross.bb.sized[1]: 8
|
||||
cg_cross.xx.even_values[0]_x_sized[0] [cross]: 2
|
||||
cg_cross.xx.sized_one [cross]: 4
|
||||
cg_cross.xx.two [cross]: 3
|
||||
cg_default.cp.gated: 1
|
||||
cg_default.cp.remaining [default]: 6
|
||||
cg_domain.cp.ignored [ignore]: 1
|
||||
cg_domain.cp.illegal [illegal]: 0
|
||||
cg_domain.cp.selected[0]: 1
|
||||
cg_domain.cp.selected[1]: 1
|
||||
cg_domain.cp.selected[2]: 1
|
||||
cg_domain.cp.selected[3]: 1
|
||||
cg_domain.cp__05b0__05d.excluded [ignore]: 2
|
||||
cg_domain.cp__05b0__05d.remaining [default]: 9
|
||||
cg_domain.cp__05b0__05d.selected: 2
|
||||
cg_domain.wild.ignored [ignore]: 1
|
||||
cg_domain.wild.ignored_set [ignore]: 0
|
||||
cg_domain.wild.illegal [illegal]: 0
|
||||
cg_domain.wild.illegal_set [illegal]: 0
|
||||
cg_domain.wild.selected[0]: 1
|
||||
cg_domain.wild.selected[1]: 1
|
||||
cg_domain.wild.selected[2]: 1
|
||||
cg_domain.wild.selected[3]: 1
|
||||
cg_guard.filtered.auto_1: 0
|
||||
cg_guard.filtered.auto_2: 0
|
||||
cg_guard.filtered.auto_3: 0
|
||||
cg_guard.filtered.auto_4: 0
|
||||
cg_guard.filtered.auto_5: 0
|
||||
cg_guard.filtered.auto_6: 0
|
||||
cg_guard.filtered.auto_7: 0
|
||||
cg_guard.filtered.bad [illegal]: 0
|
||||
cg_guard.sized.auto_2: 0
|
||||
cg_guard.sized.auto_3: 0
|
||||
cg_guard.sized.auto_4: 0
|
||||
cg_guard.sized.auto_5: 0
|
||||
cg_guard.sized.auto_6: 0
|
||||
cg_guard.sized.auto_7: 0
|
||||
cg_guard.sized.bad[0] [illegal]: 0
|
||||
cg_guard.sized.bad[1] [illegal]: 0
|
||||
cg_iff.checked.listed [illegal]: 0
|
||||
cg_iff.checked.named [illegal]: 0
|
||||
cg_iff.checked.probe[0]: 2
|
||||
cg_iff.checked.probe[5]: 1
|
||||
cg_iff.checked.wild_listed [illegal]: 0
|
||||
cg_iff.checked.wild_named [illegal]: 0
|
||||
cg_iff.counted.listed: 1
|
||||
cg_iff.counted.named[0]: 0
|
||||
cg_iff.counted.named[1]: 1
|
||||
cg_iff.counted.wild_listed: 1
|
||||
cg_iff.counted.wild_named[0]: 0
|
||||
cg_iff.counted.wild_named[1]: 1
|
||||
cg_iff.ignored.listed [ignore]: 1
|
||||
cg_iff.ignored.named [ignore]: 0
|
||||
cg_iff.ignored.probe[0]: 1
|
||||
cg_iff.ignored.probe[5]: 1
|
||||
cg_iff.ignored.wild_listed [ignore]: 0
|
||||
cg_iff.ignored.wild_named [ignore]: 0
|
||||
cg_ignore.auto_max.auto_1: 2
|
||||
cg_ignore.auto_max.auto_2: 1
|
||||
cg_ignore.auto_max.auto_3: 0
|
||||
cg_ignore.auto_max.ignored [ignore]: 4
|
||||
cg_ignore.cp.auto_0: 1
|
||||
cg_ignore.cp.auto_2: 1
|
||||
cg_ignore.cp.auto_4: 1
|
||||
cg_ignore.cp.never [illegal]: 0
|
||||
cg_ignore.cp.odd [ignore]: 4
|
||||
cg_ignore.wide.excluded [ignore]: 1
|
||||
cg_ignore.wide.values: 6
|
||||
cg_item_arg.listed.b[0]: 1
|
||||
cg_item_arg.listed.b[2]: 3
|
||||
cg_item_arg.sized.b[0]: 5
|
||||
cg_item_arg.sized.b[1]: 6
|
||||
cg_item_arg.sized.b[2]: 15
|
||||
cg_item_names.flag.on: 36
|
||||
cg_item_names.item.b[6]: 7
|
||||
cg_item_names.item.b[7]: 8
|
||||
cg_item_names.named.guarded: 7
|
||||
cg_item_names.named.item: 3
|
||||
cg_item_names.named.outer: 8
|
||||
cg_item_names.named.scoped[0]: 1
|
||||
cg_item_names.named.scoped[1]: 2
|
||||
cg_item_names.named.scoped[3]: 4
|
||||
cg_item_names.x.guarded_x_on [cross]: 7
|
||||
cg_item_names.x.outer_x_on [cross]: 8
|
||||
cg_item_names.x.scoped[0]_x_on [cross]: 1
|
||||
cg_item_names.x.scoped[1]_x_on [cross]: 2
|
||||
cg_item_names.x.scoped[3]_x_on [cross]: 4
|
||||
cg_item_names.x.sel [cross]: 3
|
||||
cg_item_ref.cp.b[0]: 1
|
||||
cg_item_ref.cp.b[1]: 2
|
||||
cg_item_sample.cp.b[6]: 7
|
||||
cg_item_sample.cp.b[7]: 8
|
||||
cg_joined.p._q[5]: 6
|
||||
cg_joined.p._q[6]: 7
|
||||
cg_joined.p._q[7]: 8
|
||||
cg_joined.p_.q[1]: 2
|
||||
cg_joined.p_.q[2]: 3
|
||||
cg_joined.p_.q[3]: 4
|
||||
cg_types.calls.c_code: 4
|
||||
cg_types.calls.inside_set[100]: 0
|
||||
cg_types.calls.inside_set[101]: 1
|
||||
cg_types.calls.inside_set[3]: 1
|
||||
cg_types.calls.pow2[16]: 0
|
||||
cg_types.calls.pow2[1]: 1
|
||||
cg_types.calls.pow2[2]: 1
|
||||
cg_types.calls.pow2[4]: 1
|
||||
cg_types.calls.pow2[8]: 1
|
||||
cg_types.calls.sv_function[1]: 1
|
||||
cg_types.calls.sv_function[2]: 1
|
||||
cg_types.ee.chosen[2]: 5
|
||||
cg_types.ee.chosen[4]: 5
|
||||
cg_types.ee.named[0]: 8
|
||||
cg_types.ee.named[2]: 5
|
||||
cg_types.ee.named[4]: 5
|
||||
cg_types.ee.named_fixed[0]: 8
|
||||
cg_types.ee.named_fixed[1]: 5
|
||||
cg_types.ee.named_single: 13
|
||||
cg_types.oe.named_fixed[0]: 18
|
||||
cg_types.oe.named_fixed[1]: 0
|
||||
cg_types.pp.cast_one[13]: 1
|
||||
cg_types.pp.cast_one[1]: 1
|
||||
cg_types.pp.cast_one[5]: 1
|
||||
cg_types.pp.cast_one[9]: 1
|
||||
cg_types.pp.high_two: 4
|
||||
cg_types.pp.lo_one[13]: 1
|
||||
cg_types.pp.lo_one[1]: 1
|
||||
cg_types.pp.lo_one[5]: 1
|
||||
cg_types.pp.lo_one[9]: 1
|
||||
cg_types.se.named[-1]: 10
|
||||
cg_types.se.named[-2]: 8
|
||||
cg_types.se.named[1]: 0
|
||||
cg_types.se.named[2]: 0
|
||||
cg_types.se.named_fixed[0]: 8
|
||||
cg_types.se.named_fixed[1]: 10
|
||||
cg_types.se.named_fixed[2]: 0
|
||||
cg_types.ss.negatives[-1]: 3
|
||||
cg_types.ss.negatives[-2]: 3
|
||||
cg_types.ss.negatives[-3]: 3
|
||||
cg_types.truth.all: 18
|
||||
cg_types.truth.literal_truth: 18
|
||||
cg_types.truth.real_truth: 18
|
||||
cg_types.truth.wide_truth: 11
|
||||
cg_types.wild.selected[12]: 1
|
||||
cg_types.wild.selected[13]: 1
|
||||
cg_types.wild.selected[8]: 1
|
||||
cg_types.ws.values[-1]: 8
|
||||
cg_types.ws.values[-590295810358705651711]: 1
|
||||
cg_types.ws.values[3]: 9
|
||||
cg_types.ww.fixed[0]: 4
|
||||
cg_types.ww.fixed[1]: 10
|
||||
cg_types.ww.selected[18446744073709551617]: 4
|
||||
cg_types.ww.single: 8
|
||||
cg_values.dupfix.duplicated[0]: 1
|
||||
cg_values.dupfix.duplicated[1]: 3
|
||||
cg_values.dupran.duplicate_ranges[0]: 1
|
||||
cg_values.dupran.duplicate_ranges[1]: 2
|
||||
cg_values.dupran.duplicate_ranges[2]: 1
|
||||
cg_values.dupran.duplicate_ranges[3]: 1
|
||||
cg_values.dupran.duplicate_ranges[4]: 1
|
||||
cg_values.dupran.duplicate_ranges[5]: 1
|
||||
cg_values.dupval.duplicate_values[0]: 1
|
||||
cg_values.dupval.duplicate_values[1]: 2
|
||||
cg_values.dupval.duplicate_values[2]: 1
|
||||
cg_values.empty.some: 1
|
||||
cg_values.evens.evens[0]: 1
|
||||
cg_values.evens.evens[2]: 1
|
||||
cg_values.evens.evens[4]: 1
|
||||
cg_values.evens.evens[6]: 1
|
||||
cg_values.fixed.fixed[0]: 2
|
||||
cg_values.fixed.fixed[1]: 2
|
||||
cg_values.gated.gated: 1
|
||||
cg_values.joined.joined: 5
|
||||
cg_values.low.low_values: 4
|
||||
cg_values.order.ordered[0]: 3
|
||||
cg_values.order.ordered[1]: 2
|
||||
cg_values.outer.outer_item: 1
|
||||
cg_wide.fixed.b[0]: 1
|
||||
cg_wide.fixed.b[1]: 1
|
||||
cg_wide.fixed.b[2]: 1
|
||||
cg_wide.fixed_dup.b[0]: 2
|
||||
cg_wide.fixed_dup.b[1]: 2
|
||||
cg_wide.plain.b[0]: 1
|
||||
cg_wide.plain.b[1]: 1
|
||||
cg_wide.q_fixed.b[0]: 2
|
||||
cg_wide.q_fixed.b[1]: 2
|
||||
cg_wide.q_fixed.b[2]: 0
|
||||
cg_wide.q_fixed.b[3]: 0
|
||||
cg_wide.single.b: 3
|
||||
cg_wide.unit.b[0]: 1
|
||||
cg_wide.unit.b[1]: 0
|
||||
cg_wide.unit.b[2]: 0
|
||||
cg_wide.unit.b[3]: 1
|
||||
cg_wide.values.b[18446744073709551612]: 0
|
||||
cg_wide.values.b[18446744073709551614]: 1
|
||||
cg_wide.values.b[18446744073709551616]: 0
|
||||
cg_wide.values.b[18446744073709551618]: 0
|
||||
Executable
+15
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of either the GNU Lesser General Public License Version 3
|
||||
# or the Perl Artistic License Version 2.0.
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
import coverage_covergroup_common
|
||||
|
||||
test.scenarios('vlt_all')
|
||||
|
||||
coverage_covergroup_common.run(test)
|
||||
@@ -0,0 +1,589 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Coverpoint bins with 'with' filters (IEEE 1800-2023 19.5.1.1)
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkr(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got=%f exp=%f\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
`ifdef verilator
|
||||
`define no_optimize(v) $c(v)
|
||||
`else
|
||||
`define no_optimize(v) (v)
|
||||
`endif
|
||||
// verilog_format: on
|
||||
|
||||
// A constant 'item', which a filter names through its package
|
||||
package item_pkg;
|
||||
localparam bit [2:0] item = 2;
|
||||
endpackage
|
||||
|
||||
module t;
|
||||
typedef logic signed [6:0] signed_t;
|
||||
typedef struct packed {
|
||||
logic [1:0] hi;
|
||||
logic [1:0] lo;
|
||||
} packed_t;
|
||||
typedef enum logic [2:0] {
|
||||
ZERO = 0,
|
||||
TWO = 2,
|
||||
FOUR = 4
|
||||
} enum_t;
|
||||
typedef enum logic [2:0] {
|
||||
C = 4,
|
||||
A = 0,
|
||||
B = 2,
|
||||
D = 6
|
||||
} order_t;
|
||||
typedef enum logic signed [2:0] {
|
||||
MINUS_TWO = -2,
|
||||
PLUS_ONE = 1,
|
||||
MINUS_ONE = -1,
|
||||
PLUS_TWO = 2
|
||||
} signed_enum_t;
|
||||
localparam logic [70:0] BASE = 71'h1_0000_0000_0000_0000;
|
||||
localparam bit [64:0] B65 = 65'h1_0000_0000_0000_0000;
|
||||
localparam int item = 7;
|
||||
|
||||
logic [2:0] value;
|
||||
logic [1:0] a, b;
|
||||
bit enabled;
|
||||
int cutoff;
|
||||
signed_t signed_value;
|
||||
packed_t packed_value;
|
||||
enum_t enum_value;
|
||||
order_t order_value;
|
||||
signed_enum_t signed_enum_value;
|
||||
logic [70:0] wide_value;
|
||||
logic signed [69:0] wide_signed;
|
||||
logic [3:0] nibble;
|
||||
logic [17:0] big;
|
||||
bit [64:0] w65;
|
||||
bit [63:0] q64;
|
||||
|
||||
function automatic bit even(input int candidate);
|
||||
return candidate % 2 == 0;
|
||||
endfunction
|
||||
|
||||
// Guards true on their second call only
|
||||
int with_calls;
|
||||
int sized_calls;
|
||||
function automatic bit with_second();
|
||||
++with_calls;
|
||||
return with_calls == 2;
|
||||
endfunction
|
||||
function automatic bit sized_second();
|
||||
++sized_calls;
|
||||
return sized_calls == 2;
|
||||
endfunction
|
||||
|
||||
// Filtered first, then grouped; bins keep the order and duplicates of the values
|
||||
covergroup cg_values;
|
||||
// One bin of 0, 1, 2
|
||||
low: coverpoint value {
|
||||
bins low_values = {[0 : 7]} with (item < 3);
|
||||
}
|
||||
// The range list's 'item' is the parameter; the filter's the candidate
|
||||
outer: coverpoint value {
|
||||
bins outer_item = {item} with (item == 7);
|
||||
}
|
||||
// All of the coverpoint's values, a bin for each even one
|
||||
evens: coverpoint value {
|
||||
bins evens[] = evens with (even(int'(item)));
|
||||
}
|
||||
// <0, 2>, <4, 6>
|
||||
fixed: coverpoint value {
|
||||
bins fixed[2] = {[0 : 7]} with (item % 2 == 0);
|
||||
}
|
||||
// Kept duplicates distribute: <0, 0>, <1, 2>
|
||||
dupfix: coverpoint value {
|
||||
bins duplicated[2] = {0, 0, 1, 2, 3, 4} with (item < 3);
|
||||
}
|
||||
// A bin per distinct value, in value order
|
||||
dupval: coverpoint value {
|
||||
bins duplicate_values[] = {2, 0, 0, 1, 1} with (item < 3);
|
||||
}
|
||||
dupran: coverpoint value {
|
||||
bins duplicate_ranges[] = {[4 : 7], [0 : 3], [2 : 5]} with (item < 6);
|
||||
}
|
||||
// Filtered values distribute in list order: <5, 1>, <3, 7>
|
||||
order: coverpoint value {
|
||||
bins ordered[2] = {5, 1, 3, 7} with (1);
|
||||
}
|
||||
// Runs of values continue over elements
|
||||
joined: coverpoint value {
|
||||
bins joined = {[0 : 1], [2 : 3], 4} with (item != 3);
|
||||
}
|
||||
// The bin counts only when enabled
|
||||
gated: coverpoint value {
|
||||
bins gated = {[0 : 7]} with (item < 3) iff (enabled);
|
||||
}
|
||||
// A bin without values is not created
|
||||
empty: coverpoint value {
|
||||
bins some = {0};
|
||||
bins none[] = empty with (item > 7);
|
||||
bins no_value = {1} with (0);
|
||||
}
|
||||
endgroup
|
||||
|
||||
// A default bin excludes a filtered bin's values, even when its guard is false
|
||||
covergroup cg_default;
|
||||
cp: coverpoint value {
|
||||
bins gated = {0, 1} with (item < 2) iff (enabled);
|
||||
bins remaining = default;
|
||||
}
|
||||
endgroup
|
||||
|
||||
// Each form of guarded bins counts or reports a value only when its guard is true, while
|
||||
// ignore and illegal bins exclude their values from other bins regardless
|
||||
covergroup cg_iff;
|
||||
counted: coverpoint nibble {
|
||||
bins listed = {[0 : 3]} with (item > 0) iff (enabled);
|
||||
bins named[] = counted with (item < 2) iff (enabled);
|
||||
wildcard bins wild_listed = {4'b00??} with (item > 0) iff (enabled);
|
||||
wildcard bins wild_named[] = counted with (item < 2) iff (enabled);
|
||||
}
|
||||
ignored: coverpoint nibble {
|
||||
ignore_bins listed = {[0 : 3]} with (item == 1) iff (enabled);
|
||||
ignore_bins named = ignored with (item == 2) iff (enabled);
|
||||
wildcard ignore_bins wild_listed = {4'b00??} with (item == 3) iff (enabled);
|
||||
wildcard ignore_bins wild_named = ignored with (item == 4) iff (enabled);
|
||||
bins probe[] = {[0 : 5]};
|
||||
}
|
||||
checked: coverpoint value {
|
||||
illegal_bins listed = {[0 : 3]} with (item == 1) iff (enabled);
|
||||
illegal_bins named = checked with (item == 2) iff (enabled);
|
||||
wildcard illegal_bins wild_listed = {3'b0??} with (item == 3) iff (enabled);
|
||||
wildcard illegal_bins wild_named = checked with (item == 4) iff (enabled);
|
||||
bins probe[] = {[0 : 5]};
|
||||
}
|
||||
endgroup
|
||||
|
||||
// Bins of values over the 64-bit word boundary, and sized arrays of elements in value order
|
||||
covergroup cg_wide;
|
||||
single: coverpoint w65 {
|
||||
bins b = {[B65 - 8 : B65 + 7]} with (item % 2 == 0);
|
||||
}
|
||||
values: coverpoint w65 {
|
||||
bins b[] = {[B65 - 4 : B65 + 3]} with (item % 2 == 0);
|
||||
}
|
||||
// <B-8, B-6>, <B-4, B-2>, <B, B+2, B+4, B+6>
|
||||
fixed: coverpoint w65 {
|
||||
bins b[3] = {[B65 - 8 : B65 + 7]} with (item % 2 == 0);
|
||||
}
|
||||
// A value per bin: <B-2>, <B-1>, <B>, <B+1>
|
||||
unit: coverpoint w65 {
|
||||
bins b[4] = {[B65 - 2 : B65 + 1]} with (1);
|
||||
}
|
||||
// Elements out of order: <B-2, B-1, B+1>, <B-2, B-1, B+1>
|
||||
fixed_dup: coverpoint w65 {
|
||||
bins b[2] = {[B65 - 2 : B65 + 1], [B65 - 2 : B65 + 1]} with (item != B65);
|
||||
}
|
||||
// <B-3, B-2>, <B+1, B+2>
|
||||
plain: coverpoint w65 {
|
||||
bins b[2] = {[B65 - 3 : B65 - 2], [B65 + 1 : B65 + 2]};
|
||||
}
|
||||
// 256 values per bin
|
||||
q_fixed: coverpoint q64 {
|
||||
bins b[4] = {[0 : 2047]} with (item % 2 == 0);
|
||||
}
|
||||
endgroup
|
||||
|
||||
// An illegal bin's guard is evaluated once per sample, as for sized arrays of bins
|
||||
covergroup cg_guard;
|
||||
filtered: coverpoint value {
|
||||
illegal_bins bad = {0} with (1) iff (with_second());
|
||||
}
|
||||
sized: coverpoint value {
|
||||
illegal_bins bad[2] = {0, 1} iff (sized_second());
|
||||
}
|
||||
endgroup
|
||||
|
||||
// Filtered bins as cross dimensions
|
||||
covergroup cg_cross;
|
||||
aa: coverpoint a {
|
||||
bins even_values[] = aa with (item % 2 == 0);
|
||||
}
|
||||
bb: coverpoint b {
|
||||
bins sized[2] = {[0 : 3], [2 : 3]} with (item != 1);
|
||||
}
|
||||
xx: cross aa, bb{
|
||||
bins two = binsof (aa.even_values) intersect {2};
|
||||
bins sized_one = binsof (bb.sized) intersect {3};
|
||||
}
|
||||
endgroup
|
||||
|
||||
// Coverpoints of various types; the candidate has the coverpoint's type
|
||||
covergroup cg_types;
|
||||
// -3, -2, -1
|
||||
ss: coverpoint signed_value {
|
||||
bins negatives[] = {[-3 : 2]} with (item < 0);
|
||||
}
|
||||
// A filter is true for a nonzero value: all values but in 'none', which has none
|
||||
truth: coverpoint signed_value {
|
||||
bins all = truth with (1);
|
||||
bins real_truth = truth with (0.25);
|
||||
bins literal_truth = truth with (bit'("yes"));
|
||||
bins wide_truth = truth with (item & 7'sh40);
|
||||
bins none = truth with (0);
|
||||
}
|
||||
// 1, 5, 9, 13, by member and by cast
|
||||
pp: coverpoint packed_value {
|
||||
bins lo_one[] = {[0 : 15]} with (item.lo == 1);
|
||||
bins cast_one[] = {[0 : 15]} with (int'(item) % 4 == 1);
|
||||
bins high_two = {[0 : 15]} with (item[3: 2] == 2);
|
||||
}
|
||||
// Named by value: 2, 4
|
||||
ee: coverpoint enum_value {
|
||||
bins chosen[] = {ZERO, TWO, FOUR} with (item != ZERO);
|
||||
// The coverpoint's name denotes its enumerated values: 0, 2, 4; <0>, <4>
|
||||
bins named[] = ee with (1);
|
||||
bins named_fixed[2] = ee with (item != TWO);
|
||||
bins named_single = ee with (item != TWO);
|
||||
}
|
||||
// In value order, whatever the declaration order: <0, 2>, <4, 6>
|
||||
oe: coverpoint order_value {
|
||||
bins named_fixed[2] = oe with (1);
|
||||
}
|
||||
// In signed value order: -2, -1, 1, 2; <-2>, <-1>, <1, 2>
|
||||
se: coverpoint signed_enum_value {
|
||||
bins named[] = se with (1);
|
||||
bins named_fixed[3] = se with (1);
|
||||
}
|
||||
// BASE + 1; BASE and BASE + 2; <BASE + 1, BASE + 2>, <BASE + 3>
|
||||
ww: coverpoint wide_value {
|
||||
bins selected[] = {[BASE : BASE + 71'd3]} with ((item & 71'd3) == 1);
|
||||
bins single = {[BASE : BASE + 71'd3]} with (item[0] == 0);
|
||||
bins fixed[2] = {[BASE : BASE + 71'd3]} with (item != BASE);
|
||||
}
|
||||
// -2**69 + 1, -1, 3
|
||||
ws: coverpoint wide_signed {
|
||||
bins values[] = {-70'sd1, 3, -70'sh20_0000_0000_0000_0000 + 1} with (1);
|
||||
}
|
||||
// 8, 12, 13
|
||||
wild: coverpoint nibble {
|
||||
wildcard bins selected[] = {4'b1?0?} with (item != 9);
|
||||
}
|
||||
// Calls: an SV function of a variable, C++ code, and a system function
|
||||
calls: coverpoint big {
|
||||
bins sv_function[] = {[0 : 200003]} with (int'(item) < cutoff && int'(item) >= 1);
|
||||
bins c_code = {[0 : 9]} with (`no_optimize(int'(item)) % 3 == 0);
|
||||
bins pow2[] = {[1 : 20]} with ($countones(item) == 1);
|
||||
bins inside_set[] = calls with (item inside {3, [100 : 101]});
|
||||
}
|
||||
endgroup
|
||||
|
||||
// Automatic bins partition before the filtered exclusions: those of 0, 2, 4
|
||||
covergroup cg_ignore;
|
||||
cp: coverpoint value {
|
||||
ignore_bins odd = {[0 : 7]} with (item % 2 != 0);
|
||||
illegal_bins never = {[0 : 7]} with (item == 6);
|
||||
}
|
||||
// Of auto_bin_max 4, the bins [2:3], [4:5], [6:7] keep values
|
||||
auto_max: coverpoint value {
|
||||
option.auto_bin_max = 4;
|
||||
ignore_bins ignored = {[0 : 1], [5 : 6]} with (1);
|
||||
}
|
||||
wide: coverpoint wide_value {
|
||||
bins values = {[0 : 3]};
|
||||
ignore_bins excluded = {3} with (1);
|
||||
}
|
||||
endgroup
|
||||
|
||||
// Constructor arguments in bounds, counts and filters
|
||||
covergroup cg_bounds(input bit [2:0] low, input bit [2:0] high, input bit [2:0] count);
|
||||
// <2>, <3, 4>
|
||||
upper: coverpoint signed_value {
|
||||
bins upper[count] = {[low : $]} with (item <= signed_t'(high));
|
||||
}
|
||||
// 2, 3, 4
|
||||
lower: coverpoint signed_value {
|
||||
bins lower[] = {[$ : high]} with (item >= signed_t'(low));
|
||||
}
|
||||
single: coverpoint signed_value {
|
||||
bins single[] = {low} with (1);
|
||||
}
|
||||
endgroup
|
||||
|
||||
// The coverpoint's name under its guard; a wildcard filter of it has no patterns
|
||||
covergroup cg_domain;
|
||||
cp: coverpoint value iff (enabled) {
|
||||
bins selected[] = cp with (item < 4);
|
||||
ignore_bins ignored = cp with (item == 4);
|
||||
illegal_bins illegal = cp with (item == 5);
|
||||
}
|
||||
wild: coverpoint value iff (enabled) {
|
||||
wildcard bins selected[] = wild with (item < 4);
|
||||
wildcard ignore_bins ignored = wild with (item == 4);
|
||||
wildcard illegal_bins illegal = wild with (item == 5);
|
||||
wildcard ignore_bins ignored_set = {3'b11?} with (item == 6);
|
||||
wildcard illegal_bins illegal_set = {3'b11?} with (item == 7);
|
||||
}
|
||||
\cp[0] : coverpoint value {
|
||||
bins selected = {0, 1} with (item != 0);
|
||||
ignore_bins excluded = {2};
|
||||
bins remaining = default;
|
||||
}
|
||||
endgroup
|
||||
|
||||
// Filters are evaluated when constructed: later changes do not redefine the bins
|
||||
covergroup cg_capture;
|
||||
sc: coverpoint nibble {
|
||||
bins b = {[0 : 15]} with (int'(item) < cutoff);
|
||||
}
|
||||
ar: coverpoint nibble {
|
||||
bins b[] = {[0 : 15]} with (int'(item) < cutoff);
|
||||
}
|
||||
endgroup
|
||||
|
||||
// Members of an enclosing class, for each instance
|
||||
class Base;
|
||||
bit [2:0] value;
|
||||
int minimum;
|
||||
int limit;
|
||||
endclass
|
||||
|
||||
class Holder extends Base;
|
||||
covergroup cg(input int offset);
|
||||
cp: coverpoint value {
|
||||
bins selected[] = {[minimum + offset : 7]} with (int'(item) < limit);
|
||||
}
|
||||
endgroup
|
||||
function new(int first, int last);
|
||||
minimum = first;
|
||||
limit = last;
|
||||
cg = new(.offset(1));
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
// 'item' is the candidate only in a filter, which is its scope (IEEE 1800-2023 7.12); elsewhere
|
||||
// it is the parameter, 7, as bins and coverpoints named 'item' are no variables (19.5)
|
||||
covergroup cg_item_names;
|
||||
// The bin 'item' of 0, 1; 7; 6, counted as 'item' is 7; 0, 1, 3
|
||||
named: coverpoint value {
|
||||
bins item = {[0 : 7]} with (item < 2);
|
||||
bins outer = {item};
|
||||
bins guarded = {[0 : 7]} with (item == 6) iff (item == 7);
|
||||
bins scoped[] = {[0 : 3]} with (item != item_pkg::item);
|
||||
}
|
||||
// The coverpoint 'item': 6, 7
|
||||
item: coverpoint value {
|
||||
bins b[] = item with (item > 5);
|
||||
}
|
||||
flag: coverpoint enabled {
|
||||
bins on = {1};
|
||||
}
|
||||
x: cross named, flag{bins sel = binsof (named.item);}
|
||||
endgroup
|
||||
|
||||
// An argument 'item', 3, sets the range list and the array size: 0, 2; <4>, <5>, <6, 7>
|
||||
covergroup cg_item_arg(input bit [2:0] item);
|
||||
listed: coverpoint value {
|
||||
bins b[] = {[0 : item]} with (item % 2 == 0);
|
||||
}
|
||||
sized: coverpoint value {
|
||||
bins b[item] = {[0 : 7]} with (item > 3);
|
||||
}
|
||||
endgroup
|
||||
|
||||
// Arguments 'item' as the coverpoint expression, whose type the candidate has: 6, 7; 0, 1
|
||||
covergroup cg_item_sample with function sample (bit [2:0] item);
|
||||
cp: coverpoint item {
|
||||
bins b[] = cp with (item > 5);
|
||||
}
|
||||
endgroup
|
||||
covergroup cg_item_ref(ref logic [2:0] item);
|
||||
cp: coverpoint item {
|
||||
bins b[] = cp with (item < 2);
|
||||
}
|
||||
endgroup
|
||||
|
||||
// A member 'item' as the coverpoint expression: 2, 3
|
||||
class ItemMember;
|
||||
bit [2:0] item;
|
||||
covergroup cg_member;
|
||||
cp: coverpoint item {
|
||||
bins b[] = cp with (item inside {[2 : 3]});
|
||||
}
|
||||
endgroup
|
||||
function new;
|
||||
cg_member = new;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
// Coverpoints and bins whose names join alike, 'p_' of 'q' and 'p' of '_q': 1, 2, 3; 5, 6, 7
|
||||
covergroup cg_joined;
|
||||
p_: coverpoint value {
|
||||
bins q[] = {[0 : 3]} with (item > 0);
|
||||
}
|
||||
p: coverpoint value {
|
||||
bins _q[] = {[4 : 7]} with (item > 4);
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg_values values_inst = new;
|
||||
cg_default default_inst = new;
|
||||
cg_cross cross_inst = new;
|
||||
cg_types types_inst;
|
||||
cg_ignore ignore_inst = new;
|
||||
cg_bounds bounds_inst = new(2, 4, 2);
|
||||
cg_domain domain_inst = new;
|
||||
cg_capture capture_inst;
|
||||
cg_guard guard_inst = new;
|
||||
cg_wide wide_inst = new;
|
||||
cg_iff iff_inst = new;
|
||||
cg_item_names item_names_inst = new;
|
||||
cg_item_arg item_arg_inst = new(3);
|
||||
cg_item_sample item_sample_inst = new;
|
||||
cg_item_ref item_ref_inst;
|
||||
cg_joined joined_inst = new;
|
||||
ItemMember item_member;
|
||||
Holder low_holder;
|
||||
Holder high_holder;
|
||||
|
||||
initial begin
|
||||
wide_value = 0;
|
||||
cutoff = 3;
|
||||
types_inst = new;
|
||||
capture_inst = new;
|
||||
cutoff = 10;
|
||||
low_holder = new(0, 3);
|
||||
high_holder = new(2, 5);
|
||||
low_holder.minimum = 7;
|
||||
low_holder.limit = 0;
|
||||
high_holder.minimum = 7;
|
||||
high_holder.limit = 0;
|
||||
|
||||
enabled = 0;
|
||||
for (int i = 0; i < 8; ++i) begin
|
||||
value = 3'(i);
|
||||
values_inst.sample();
|
||||
default_inst.sample();
|
||||
domain_inst.sample();
|
||||
end
|
||||
enabled = 1;
|
||||
value = 1;
|
||||
values_inst.sample();
|
||||
default_inst.sample();
|
||||
for (int i = 0; i < 5; ++i) begin
|
||||
value = 3'(i);
|
||||
domain_inst.sample();
|
||||
end
|
||||
for (int i = 0; i < 6; ++i) begin
|
||||
value = 3'(i);
|
||||
ignore_inst.sample();
|
||||
end
|
||||
|
||||
for (int i = 0; i < 4; ++i) begin
|
||||
for (int j = 0; j < 4; ++j) begin
|
||||
a = 2'(i);
|
||||
b = 2'(j);
|
||||
cross_inst.sample();
|
||||
end
|
||||
end
|
||||
|
||||
for (int i = 0; i < 16; ++i) begin
|
||||
signed_value = signed_t'(i % 6 - 3);
|
||||
packed_value = packed_t'(i);
|
||||
case (i % 3)
|
||||
0: enum_value = ZERO;
|
||||
1: enum_value = TWO;
|
||||
default: enum_value = FOUR;
|
||||
endcase
|
||||
order_value = i % 2 == 0 ? A : B;
|
||||
signed_enum_value = i % 2 == 0 ? MINUS_TWO : MINUS_ONE;
|
||||
wide_value = BASE + 71'(i % 4);
|
||||
wide_signed = i % 2 == 0 ? -70'sd1 : 70'sd3;
|
||||
nibble = 4'(i);
|
||||
big = 18'(i);
|
||||
types_inst.sample();
|
||||
end
|
||||
signed_value = 7'sh40;
|
||||
types_inst.sample();
|
||||
wide_signed = -70'sh20_0000_0000_0000_0000 + 1;
|
||||
big = 101;
|
||||
types_inst.sample();
|
||||
|
||||
for (int i = 2; i <= 4; ++i) begin
|
||||
signed_value = signed_t'(i);
|
||||
bounds_inst.sample();
|
||||
end
|
||||
wide_value = 3;
|
||||
ignore_inst.sample();
|
||||
|
||||
nibble = 5;
|
||||
capture_inst.sample();
|
||||
`checkr(capture_inst.get_inst_coverage(), 0.0);
|
||||
|
||||
low_holder.value = 1;
|
||||
high_holder.value = 3;
|
||||
low_holder.cg.sample();
|
||||
high_holder.cg.sample();
|
||||
`checkr(low_holder.cg.get_inst_coverage(), 50.0);
|
||||
`checkr(high_holder.cg.get_inst_coverage(), 50.0);
|
||||
low_holder.value = 2;
|
||||
high_holder.value = 4;
|
||||
low_holder.cg.sample();
|
||||
high_holder.cg.sample();
|
||||
`checkr(low_holder.cg.get_inst_coverage(), 100.0);
|
||||
`checkr(high_holder.cg.get_inst_coverage(), 100.0);
|
||||
|
||||
`checkr(values_inst.get_inst_coverage(), 100.0);
|
||||
`checkr(default_inst.get_inst_coverage(), 100.0);
|
||||
`checkr(cross_inst.get_inst_coverage(), 100.0);
|
||||
`checkr(bounds_inst.get_inst_coverage(), 100.0);
|
||||
`checkr(item, 7);
|
||||
w65 = B65 - 6;
|
||||
q64 = 0;
|
||||
wide_inst.sample();
|
||||
w65 = B65 - 2;
|
||||
q64 = 1000;
|
||||
wide_inst.sample();
|
||||
w65 = B65 + 1;
|
||||
q64 = 0;
|
||||
wide_inst.sample();
|
||||
w65 = B65 + 4;
|
||||
q64 = 1000;
|
||||
wide_inst.sample();
|
||||
|
||||
// The guards were false when evaluated, so no illegal bin was hit
|
||||
value = 0;
|
||||
guard_inst.sample();
|
||||
`checkd(with_calls, 1);
|
||||
`checkd(sized_calls, 1);
|
||||
|
||||
enabled = 0;
|
||||
for (int i = 0; i < 6; ++i) begin
|
||||
nibble = 4'(i);
|
||||
value = 3'(i);
|
||||
iff_inst.sample();
|
||||
end
|
||||
enabled = 1;
|
||||
nibble = 1;
|
||||
value = 0;
|
||||
iff_inst.sample();
|
||||
|
||||
// Each value v is sampled v + 1 times, so the counts tell the values of each bin
|
||||
item_ref_inst = new(value);
|
||||
item_member = new;
|
||||
enabled = 1;
|
||||
for (int i = 0; i < 8; ++i) begin
|
||||
repeat (i + 1) begin
|
||||
value = 3'(i);
|
||||
item_member.item = 3'(i);
|
||||
item_names_inst.sample();
|
||||
item_arg_inst.sample();
|
||||
item_sample_inst.sample(3'(i));
|
||||
item_ref_inst.sample();
|
||||
item_member.cg_member.sample();
|
||||
joined_inst.sample();
|
||||
end
|
||||
end
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -0,0 +1,8 @@
|
||||
%Error: t/t_covergroup_with_bad.v:15:18: A bin 'with' filter may name only its own coverpoint 'bb', not 'aa' (IEEE 1800-2023 19.5.1.1)
|
||||
15 | bins x[] = aa with (item > 1);
|
||||
| ^~
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
%Error: t/t_covergroup_with_bad.v:19:24: Can't find definition of variable: 'item'
|
||||
19 | bins y[] = {[0 : item]} with (item > 1);
|
||||
| ^~~~
|
||||
%Error: Exiting due to
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of either the GNU Lesser General Public License Version 3
|
||||
# or the Perl Artistic License Version 2.0.
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('linter')
|
||||
|
||||
test.lint(fails=True, expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
@@ -0,0 +1,24 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Invalid names in coverpoint bin 'with' filters (IEEE 1800-2023 19.5.1.1)
|
||||
|
||||
module t;
|
||||
bit [3:0] a, b;
|
||||
covergroup cg;
|
||||
aa: coverpoint a;
|
||||
// Only the coverpoint of the bin may be named
|
||||
bb: coverpoint b {
|
||||
bins x[] = aa with (item > 1);
|
||||
}
|
||||
// The candidate 'item' is only in the filter, not in the range list
|
||||
cc: coverpoint b {
|
||||
bins y[] = {[0 : item]} with (item > 1);
|
||||
}
|
||||
endgroup
|
||||
cg inst = new;
|
||||
initial $finish;
|
||||
endmodule
|
||||
@@ -0,0 +1,3 @@
|
||||
[0] %Error: t_covergroup_with_illegal_bad.v:22: Assertion failed in top.t.cg.sample: Illegal bin 'bad' hit in coverpoint 'cp'
|
||||
%Error: t/t_covergroup_with_illegal_bad.v:22: Verilog $stop
|
||||
Aborting...
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of either the GNU Lesser General Public License Version 3
|
||||
# or the Perl Artistic License Version 2.0.
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
test.compile()
|
||||
|
||||
test.execute(fails=True, check_finished=False, expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
@@ -0,0 +1,34 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// An illegal bin of a 'with' filter is hit when its guard, evaluated once, is true
|
||||
|
||||
module t;
|
||||
bit [2:0] value;
|
||||
int calls;
|
||||
|
||||
// True on the first call only
|
||||
function automatic bit first_call();
|
||||
++calls;
|
||||
return calls == 1;
|
||||
endfunction
|
||||
|
||||
covergroup cg;
|
||||
cp: coverpoint value {
|
||||
bins valid = {[0 : 3]};
|
||||
illegal_bins bad = {[4 : 7]} with (item != 5) iff (first_call());
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg inst = new;
|
||||
|
||||
initial begin
|
||||
value = 4;
|
||||
inst.sample(); // <--- Bad: illegal
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -0,0 +1,9 @@
|
||||
%Warning: t/t_covergroup_with_limits.v:21: Coverage bin 'with' filter has more than 2**32 candidate values; bin 'b' ignored
|
||||
%Warning: t/t_covergroup_with_limits.v:25: Coverage bin 'with' filter has more than 2**32 candidate values; bin 'b' ignored
|
||||
%Warning: t/t_covergroup_with_limits.v:33: Coverage bin array needs more bins than --coverage-max-bins; bin 'b' ignored
|
||||
%Warning: t/t_covergroup_with_limits.v:41: Coverage bin 'with' filter keeps values in more ranges than --coverage-max-bins; bin 'b' ignored
|
||||
%Warning: t/t_covergroup_with_limits.v:49: Coverage bin 'with' filter keeps values in more ranges than --coverage-max-bins; bin 'b' ignored
|
||||
%Warning: t/t_covergroup_with_limits.v:52: Coverage bin array needs more bins than --coverage-max-bins; bin 'b' ignored
|
||||
%Error: t/t_covergroup_with_limits.v:55: Coverage bin array 'b' size must be a positive integer (IEEE 1800-2023 19.5.1)
|
||||
-Info: t/t_covergroup_with_limits.v:55: Verilog $stop, ignored due to +verilator+error+limit
|
||||
*-* All Finished *-*
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of either the GNU Lesser General Public License Version 3
|
||||
# or the Perl Artistic License Version 2.0.
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt')
|
||||
|
||||
if test.tsan:
|
||||
test.skip("ThreadSanitizer not compatible with AddressSanitizer\n")
|
||||
|
||||
# Bins of filters ignored when constructed, under AddressSanitizer
|
||||
test.compile(verilator_flags2=[
|
||||
'--coverage-max-bins 8', '-CFLAGS -fsanitize=address -LDFLAGS -fsanitize=address'
|
||||
])
|
||||
|
||||
test.execute(all_run_flags=['+verilator+error+limit+100'], expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
@@ -0,0 +1,91 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Limits of the bins of 'with' filters, which are found when the covergroup is constructed
|
||||
|
||||
// verilog_format: off
|
||||
`define stop $stop
|
||||
`define checkr(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got=%f exp=%f\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||
// verilog_format: on
|
||||
|
||||
module t;
|
||||
bit [32:0] v33;
|
||||
bit [7:0] v8;
|
||||
|
||||
// Each is evaluated for at most 2**32 candidates, which bounds known when constructed give
|
||||
covergroup cg_candidates(bit [32:0] high, bit [32:0] low);
|
||||
all: coverpoint v33 {
|
||||
bins b = {[0 : high]} with (item < 5); // <--- Bad: 2**33 candidates
|
||||
bins other = {[5 : 10]};
|
||||
}
|
||||
listed: coverpoint v33 {
|
||||
bins b = {[0 : 33'h7fff_ffff], [low : 33'h1_8000_0000]} with (item == 1); // <--- Bad: 2**32 + 1 candidates
|
||||
}
|
||||
endgroup
|
||||
|
||||
// Of --coverage-max-bins 8
|
||||
covergroup cg_kept(int count);
|
||||
// 9 values, once duplicates are merged
|
||||
values: coverpoint v8 {
|
||||
bins b[] = {[0 : 5], [0 : 5], [3 : 8]} with (1); // <--- Bad: bins
|
||||
}
|
||||
// 8 values, of 14 before duplicates are merged
|
||||
merged: coverpoint v8 {
|
||||
bins b[] = {[0 : 5], [0 : 5], [3 : 7]} with (1);
|
||||
}
|
||||
// 11 runs of values
|
||||
runs: coverpoint v8 {
|
||||
bins b = {[0 : 40]} with (item % 4 == 0); // <--- Bad: runs
|
||||
}
|
||||
// 9 runs of one value
|
||||
single: coverpoint v8 {
|
||||
bins b = {1, 1, 1, 1, 1, 1, 1, 1, 1} with (1);
|
||||
}
|
||||
// A sized array keeps its duplicates
|
||||
fixed: coverpoint v8 {
|
||||
bins b[2] = {1, 1, 1, 1, 1, 1, 1, 1, 1} with (1); // <--- Bad: runs
|
||||
}
|
||||
many: coverpoint v8 {
|
||||
bins b[9] = {[0 : 20]} with (1); // <--- Bad: bins
|
||||
}
|
||||
counted: coverpoint v8 {
|
||||
bins b[count] = {[0 : 3]} with (1); // <--- Bad: count
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg_candidates candidates_inst;
|
||||
// The limits apply to the values kept, whatever the order of the candidates
|
||||
covergroup cg_order;
|
||||
// 9 values, then a range holding them: one range of values
|
||||
listed: coverpoint v8 {
|
||||
bins b = {0, 2, 4, 6, 8, 10, 12, 14, 16, [0 : 16]} with (1);
|
||||
}
|
||||
// 8 values, each listed twice
|
||||
twice: coverpoint v8 {
|
||||
bins b[] = {[0 : 15], [0 : 15]} with (item % 2 == 0);
|
||||
}
|
||||
endgroup
|
||||
|
||||
cg_kept kept_inst;
|
||||
cg_order order_inst;
|
||||
|
||||
initial begin
|
||||
candidates_inst = new(33'h1_ffff_ffff, 33'h1_0000_0000);
|
||||
kept_inst = new(0);
|
||||
order_inst = new;
|
||||
v33 = 5;
|
||||
v8 = 1;
|
||||
candidates_inst.sample();
|
||||
kept_inst.sample();
|
||||
`checkr(candidates_inst.get_inst_coverage(), 100.0);
|
||||
`checkr(kept_inst.get_inst_coverage(), (100.0 / 8.0 + 100.0) / 2.0);
|
||||
v8 = 16;
|
||||
order_inst.sample();
|
||||
`checkr(order_inst.get_inst_coverage(), 50.0);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
Executable
+23
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of either the GNU Lesser General Public License Version 3
|
||||
# or the Perl Artistic License Version 2.0.
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('linter')
|
||||
test.top_filename = 't/t_covergroup_with.v'
|
||||
|
||||
test.lint(verilator_flags2=['-Wwarn-UNUSEDSIGNAL', '-Wwarn-VARHIDDEN', '-Wno-fatal'])
|
||||
|
||||
# A 'with' filter may read all, some, or none of the bits of its implicit candidate 'item'
|
||||
test.file_grep_not(test.compile_log_filename, r"_item'")
|
||||
# The candidate hides another 'item' in the filter without a warning, unlike the declarations
|
||||
# the test names 'item', of the members and arguments of classes and covergroups
|
||||
test.file_grep_count(test.compile_log_filename, r"hides declaration in upper scope: 'item'", 4)
|
||||
|
||||
test.passes()
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of either the GNU Lesser General Public License Version 3
|
||||
# or the Perl Artistic License Version 2.0.
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('vlt_all')
|
||||
test.top_filename = 't/t_covergroup_with.v'
|
||||
|
||||
test.compile()
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
@@ -0,0 +1,14 @@
|
||||
%Error: t/t_covergroup_with_type_bad.v:16:26: Bin 'with' filters are not allowed on a coverpoint of a non-integral expression (IEEE 1800-2023 19.5.1.1)
|
||||
: ... note: In instance 't'
|
||||
16 | bins b = {[0 : 3]} with (item > 1);
|
||||
| ^~~~
|
||||
... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance.
|
||||
%Error: t/t_covergroup_with_type_bad.v:19:22: Bin 'with' filters are not allowed on a coverpoint of a non-integral expression (IEEE 1800-2023 19.5.1.1)
|
||||
: ... note: In instance 't'
|
||||
19 | bins b = {"a"} with (1);
|
||||
| ^~~~
|
||||
%Error: t/t_covergroup_with_type_bad.v:23:34: Bin 'with' filter must be assignment compatible with an integral type, not 'string' (IEEE 1800-2023 19.5.1.1)
|
||||
: ... note: In instance 't'
|
||||
23 | bins b[] = {[0 : 3]} with (s);
|
||||
| ^
|
||||
%Error: Exiting due to
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of either the GNU Lesser General Public License Version 3
|
||||
# or the Perl Artistic License Version 2.0.
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('linter')
|
||||
|
||||
test.lint(fails=True, expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
@@ -0,0 +1,28 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Invalid types of coverpoint bin 'with' filters (IEEE 1800-2023 19.5.1.1)
|
||||
|
||||
module t;
|
||||
real r;
|
||||
bit [3:0] a;
|
||||
string s = "x";
|
||||
covergroup cg;
|
||||
// Not allowed for a real coverpoint, nor other non-integral ones
|
||||
rr: coverpoint r {
|
||||
bins b = {[0 : 3]} with (item > 1);
|
||||
}
|
||||
ss: coverpoint s {
|
||||
bins b = {"a"} with (1);
|
||||
}
|
||||
// The result must be assignment compatible with an integral type
|
||||
aa: coverpoint a {
|
||||
bins b[] = {[0 : 3]} with (s);
|
||||
}
|
||||
endgroup
|
||||
cg inst = new;
|
||||
initial $finish;
|
||||
endmodule
|
||||
@@ -0,0 +1,34 @@
|
||||
%Warning-COVERIGN: t/t_covergroup_with_unsup.v:33:5: Ignoring unsupported: 'type_option.distribute_first'; 'with' filters apply before values are distributed to bins
|
||||
: ... note: In instance 't'
|
||||
33 | type_option.distribute_first = 1;
|
||||
| ^~~~~~~~~~~
|
||||
... For warning description see https://verilator.org/warn/COVERIGN?v=latest
|
||||
... Use "/* verilator lint_off COVERIGN */" and lint_on around source to disable this message.
|
||||
%Warning-COVERIGN: t/t_covergroup_with_unsup.v:17:21: Unsupported: 'with' filter of wildcard 'bins' of more than --coverage-max-bins of 8 ranges of values; bin 'odd' ignored
|
||||
: ... note: In instance 't'
|
||||
: ... Suggest a larger --coverage-max-bins
|
||||
17 | wildcard bins odd[] = {8'b???????1} with (1);
|
||||
| ^~~
|
||||
%Warning-COVERIGN: t/t_covergroup_with_unsup.v:21:28: Unsupported: 'with' filter of wildcard 'ignore_bins' of more than --coverage-max-bins of 8 ranges of values; bin 'odd' ignored
|
||||
: ... note: In instance 't'
|
||||
: ... Suggest a larger --coverage-max-bins
|
||||
21 | wildcard ignore_bins odd = {8'b???????1} with (item > 1);
|
||||
| ^~~
|
||||
%Warning-COVERIGN: t/t_covergroup_with_unsup.v:26:21: Unsupported: 'with' filter of wildcard 'bins' of more than --coverage-max-bins of 8 ranges of values; bin 'odd' ignored
|
||||
: ... note: In instance 't'
|
||||
: ... Suggest a larger --coverage-max-bins
|
||||
26 | wildcard bins odd[] = {8'b???????1} with (item > 1);
|
||||
| ^~~
|
||||
%Warning-COVERIGN: t/t_covergroup_with_unsup.v:47:12: Unsupported: 'with' filter of more than 2**32 candidate values; bin 'b' ignored
|
||||
: ... note: In instance 't'
|
||||
47 | bins b = all with (item < 5);
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_with_unsup.v:50:12: Unsupported: 'with' filter of more than 2**32 candidate values; bin 'b' ignored
|
||||
: ... note: In instance 't'
|
||||
50 | bins b = {[0 : 33'h1_0000_0000]} with (item < 5);
|
||||
| ^
|
||||
%Warning-COVERIGN: t/t_covergroup_with_unsup.v:53:12: Unsupported: 'with' filter of more than 2**32 candidate values; bin 'fixed' ignored
|
||||
: ... note: In instance 't'
|
||||
53 | bins fixed[2] = {[0 : 33'h0_ffff_ffff], [0 : 33'h0_ffff_ffff]} with (item < 5);
|
||||
| ^~~~~
|
||||
%Error: Exiting due to
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of either the GNU Lesser General Public License Version 3
|
||||
# or the Perl Artistic License Version 2.0.
|
||||
# SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('linter')
|
||||
|
||||
test.lint(verilator_flags2=['--coverage-max-bins 8'],
|
||||
fails=True,
|
||||
expect_filename=test.golden_filename)
|
||||
|
||||
test.passes()
|
||||
@@ -0,0 +1,62 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain.
|
||||
// SPDX-FileCopyrightText: 2026 Wilson Snyder
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// Unsupported 'with' filters: of wildcard patterns of more ranges of values than
|
||||
// --coverage-max-bins 8, or distributed first
|
||||
|
||||
module t;
|
||||
bit [7:0] v;
|
||||
bit [1:0] t;
|
||||
bit [32:0] v33;
|
||||
covergroup cg;
|
||||
// The odd values are 128 ranges; the coverpoint is left without bins
|
||||
normal: coverpoint v {
|
||||
wildcard bins odd[] = {8'b???????1} with (1);
|
||||
}
|
||||
excluded: coverpoint v {
|
||||
bins low = {[0 : 3]};
|
||||
wildcard ignore_bins odd = {8'b???????1} with (item > 1);
|
||||
}
|
||||
// A cross selects the bins ignored as no bins
|
||||
mixed: coverpoint v {
|
||||
bins low = {[0 : 3]};
|
||||
wildcard bins odd[] = {8'b???????1} with (item > 1);
|
||||
}
|
||||
ct: coverpoint t;
|
||||
x: cross mixed, ct{bins sel = binsof (mixed.odd);}
|
||||
endgroup
|
||||
// Filters apply before values are distributed (IEEE 1800-2023 19.5.1.1)
|
||||
covergroup cg_first;
|
||||
type_option.distribute_first = 1; // <--- Unsupported
|
||||
cp: coverpoint v {
|
||||
bins f[3] = {[0 : 5]} with (item < 3);
|
||||
}
|
||||
endgroup
|
||||
covergroup cg_default;
|
||||
type_option.distribute_first = 0;
|
||||
cp: coverpoint v {
|
||||
bins f[3] = {[0 : 5]} with (item < 3);
|
||||
}
|
||||
endgroup
|
||||
// Each is evaluated for at most 2**32 candidates, known when verilated
|
||||
covergroup cg_candidates;
|
||||
all: coverpoint v33 {
|
||||
bins b = all with (item < 5); // <--- Unsupported: 2**33 candidates
|
||||
}
|
||||
listed: coverpoint v33 {
|
||||
bins b = {[0 : 33'h1_0000_0000]} with (item < 5); // <--- Unsupported: 2**32 + 1
|
||||
// 2**32, as the values are evaluated once
|
||||
bins merged = {[0 : 33'h0_ffff_ffff], [0 : 33'h0_ffff_ffff]} with (item < 5);
|
||||
bins fixed[2] = {[0 : 33'h0_ffff_ffff], [0 : 33'h0_ffff_ffff]} with (item < 5); // <--- Unsupported: 2**33
|
||||
bins at_limit = {[0 : 33'h0_ffff_ffff]} with (item < 5);
|
||||
}
|
||||
endgroup
|
||||
cg inst = new;
|
||||
cg_first first_inst = new;
|
||||
cg_candidates candidates_inst = new;
|
||||
cg_default default_inst = new;
|
||||
initial $finish;
|
||||
endmodule
|
||||
@@ -802,6 +802,13 @@ module Vt_debug_emitv_t;
|
||||
bins multi = {'sh0, 'sh1, 'sh2};
|
||||
bins sized['sh2] = {['sh0:'sh5], 'sh7};
|
||||
wildcard bins wild[] = {3'b1z};
|
||||
bins filtered[] = {['sh0:'sh7]} with ((
|
||||
(item
|
||||
%
|
||||
'sh2)
|
||||
==
|
||||
'sh0));
|
||||
bins named = cp_sig with ((item > 'sh5));
|
||||
bins dflt = default;
|
||||
ignore_bins ign = {'sh7};
|
||||
illegal_bins ill = {'sh5};
|
||||
|
||||
@@ -401,6 +401,8 @@ module t (/*AUTOARG*/
|
||||
bins multi = {0, 1, 2}; // multiple values in one bins (exercises EmitV range loop)
|
||||
bins sized[2] = {[0:5], 7}; // sized array of bins (exercises EmitV array size)
|
||||
wildcard bins wild[] = {3'b01?}; // wildcard array of bins (exercises EmitV wildcard)
|
||||
bins filtered[] = {[0:7]} with (item % 2 == 0); // 'with' filter of a range list
|
||||
bins named = cp_sig with (item > 5); // 'with' filter of the coverpoint's values
|
||||
bins dflt = default;
|
||||
ignore_bins ign = {7};
|
||||
illegal_bins ill = {5};
|
||||
|
||||
Reference in New Issue
Block a user