// -*- 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 #include #include class VerilatedCovContext; // How a namer builds the names of the bins it covers. enum class VlCovBinNaming : uint8_t { Single, // "" one bin Array, // "[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 m_counts; // [m_total], one per bin std::vector 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