145 lines
5.6 KiB
C++
145 lines
5.6 KiB
C++
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
|
//=============================================================================
|
|
//
|
|
// Code available from: https://verilator.org
|
|
//
|
|
// This program is free software; you can redistribute it and/or modify it
|
|
// under the terms of either the GNU Lesser General Public License Version 3
|
|
// or the Perl Artistic License Version 2.0.
|
|
// SPDX-FileCopyrightText: 2024-2026 Wilson Snyder
|
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
//
|
|
//=============================================================================
|
|
///
|
|
/// \file
|
|
/// \brief Verilated functional-coverage collection runtime
|
|
///
|
|
/// VlCoverpoint owns per-instance bin-count storage for one coverpoint,
|
|
/// computes coverage, builds bin names on demand, and registers bins with the
|
|
/// coverage database. It implements the VlCoverpointIf read interface.
|
|
///
|
|
/// Generated covergroup code holds one VlCoverpoint per coverpoint, configures
|
|
/// it in the constructor (init + add*Namer), increments bins from sample(),
|
|
/// and registers via registerBins().
|
|
///
|
|
//=============================================================================
|
|
|
|
#ifndef VERILATOR_VERILATED_COVERGROUP_H_
|
|
#define VERILATOR_VERILATED_COVERGROUP_H_
|
|
|
|
#include "verilatedos.h"
|
|
|
|
#include "verilated_cov_model.h"
|
|
|
|
#include <cstdint>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
class VerilatedCovContext;
|
|
|
|
// How a namer builds the names of the bins it covers.
|
|
enum class VlCovBinNaming : uint8_t {
|
|
Single, // "<name>" one bin
|
|
Array, // "<name>[i]" bins b[N] value array
|
|
};
|
|
|
|
// Specifies the naming scheme for a range of bins, allowing the
|
|
// specific name to be computed on-demand.
|
|
// All name strings are borrowed literals from the generated code.
|
|
class VlCovNamer final {
|
|
// MEMBERS
|
|
VlCovBinKind m_set; // which set the bins belong to
|
|
int m_count; // bins this namer covers (1 for Single)
|
|
int m_base; // first bin index (declaration order), assigned on append
|
|
VlCovBinNaming m_naming; // how bin names are built
|
|
const char* m_name; // bin name (Single) or array base name (Array)
|
|
const char* m_file; // declaration file
|
|
int m_line; // declaration line
|
|
int m_col; // declaration column
|
|
|
|
public:
|
|
// CONSTRUCTORS
|
|
VlCovNamer(VlCovBinKind set, int count, int base, VlCovBinNaming naming, const char* name,
|
|
const char* file, int line, int col)
|
|
: m_set{set}
|
|
, m_count{count}
|
|
, m_base{base}
|
|
, m_naming{naming}
|
|
, m_name{name}
|
|
, m_file{file}
|
|
, m_line{line}
|
|
, m_col{col} {}
|
|
|
|
// METHODS
|
|
VlCovBinKind set() const { return m_set; }
|
|
int count() const { return m_count; }
|
|
int base() const { return m_base; }
|
|
VlCovBinNaming naming() const { return m_naming; }
|
|
const char* name() const { return m_name; }
|
|
const char* file() const { return m_file; }
|
|
int line() const { return m_line; }
|
|
int col() const { return m_col; }
|
|
};
|
|
|
|
//=============================================================================
|
|
// VlCoverpoint
|
|
/// Per-instance coverpoint runtime. Bins are stored in declaration order; a
|
|
/// bin's set/name come from the owning namer. coverage() is computed on demand
|
|
/// by scanning bin counts, keeping the sample() hot path a plain counter bump.
|
|
|
|
class VlCoverpoint final : public VlCoverpointIf {
|
|
// MEMBERS
|
|
std::string m_hier; // "covergroup.coverpoint"
|
|
uint32_t m_atLeast = 1; // option.at_least (coverpoint-wide)
|
|
int m_total = 0; // bins across all sets
|
|
int m_normal = 0; // Normal bins (coverage denominator)
|
|
int m_nextBase = 0; // running append cursor
|
|
std::vector<uint32_t> m_counts; // [m_total], one per bin
|
|
std::vector<VlCovNamer> m_namers; // appended in declaration order
|
|
|
|
// PRIVATE METHODS
|
|
const VlCovNamer& namerFor(int i) const; // obtain the bin-specific name producer
|
|
void addNamer(VlCovBinKind set, int count, VlCovBinNaming naming, const char* name,
|
|
const char* file, int line, int col);
|
|
|
|
public:
|
|
// CONSTRUCTORS
|
|
VlCoverpoint() = default;
|
|
|
|
// METHODS
|
|
// ---- configuration (from generated constructor) ----
|
|
void init(const char* hier, uint32_t atLeast, int nBins);
|
|
void addSingleNamer(VlCovBinKind set, const char* name, const char* file, int line, int col) {
|
|
addNamer(set, 1, VlCovBinNaming::Single, name, file, line, col);
|
|
}
|
|
void addArrayNamer(VlCovBinKind set, int count, const char* name, const char* file, int line,
|
|
int col) {
|
|
addNamer(set, count, VlCovBinNaming::Array, name, file, line, col);
|
|
}
|
|
void registerBins(VerilatedCovContext* covcontextp, const char* page);
|
|
|
|
// ---- hot path (from generated sample()) ----
|
|
void incrementBin(int i) { ++m_counts[i]; } // Normal bin: count only
|
|
void recordHit(int i) { ++m_counts[i]; } // Ignore/Illegal/Default: count only
|
|
|
|
// ---- VlCoverpointIf ----
|
|
int binCount() const override { return m_total; }
|
|
std::string binName(int i) const override;
|
|
VlCovBinKind binKind(int i) const override { return namerFor(i).set(); }
|
|
void coverageParts(double& covered, double& total) const override {
|
|
// Count Normal bins that reached option.at_least on demand, so the hot
|
|
// path (incrementBin) stays a plain counter bump.
|
|
int numCovered = 0;
|
|
for (const VlCovNamer& nm : m_namers) {
|
|
if (nm.set() != VlCovBinKind::KIND_NORMAL) continue;
|
|
for (int i = nm.base(); i < nm.base() + nm.count(); ++i) {
|
|
if (m_counts[i] >= m_atLeast) ++numCovered;
|
|
}
|
|
}
|
|
covered = numCovered;
|
|
total = m_normal;
|
|
}
|
|
};
|
|
|
|
#endif // Guard
|