From c749ff09b4dee56abdf9698acbe09e44440f30ae Mon Sep 17 00:00:00 2001 From: Matthew Ballance Date: Wed, 25 Feb 2026 01:16:55 +0000 Subject: [PATCH] Refactoring before renaming tests Signed-off-by: Matthew Ballance --- include/verilated_funccov.h | 300 ------------------ src/CMakeLists.txt | 10 +- src/Makefile_obj.in | 5 +- src/V3Active.cpp | 2 +- src/V3Ast.h | 1 - src/V3AstNodeFuncCov.cpp | 155 --------- src/V3AstNodeFuncCov.h | 289 ----------------- src/V3AstNodeOther.h | 234 ++++++++++++++ src/V3AstNodes.cpp | 137 +++++++- src/V3Coverage.cpp | 1 + ...overageFunctional.cpp => V3Covergroup.cpp} | 4 +- ...{V3CoverageFunctional.h => V3Covergroup.h} | 10 +- src/V3EmitV.cpp | 6 - src/V3LinkInc.cpp | 1 + src/Verilator.cpp | 4 +- test_regress/t/t_funccov_basic.py | 18 -- test_regress/t/t_funccov_basic.v | 25 -- test_regress/t/t_funccov_basic_main.cpp | 112 ------- test_regress/t/t_verilated_all.py | 3 +- 19 files changed, 388 insertions(+), 929 deletions(-) delete mode 100644 include/verilated_funccov.h delete mode 100644 src/V3AstNodeFuncCov.cpp delete mode 100644 src/V3AstNodeFuncCov.h rename src/{V3CoverageFunctional.cpp => V3Covergroup.cpp} (99%) rename src/{V3CoverageFunctional.h => V3Covergroup.h} (76%) delete mode 100755 test_regress/t/t_funccov_basic.py delete mode 100644 test_regress/t/t_funccov_basic.v delete mode 100644 test_regress/t/t_funccov_basic_main.cpp diff --git a/include/verilated_funccov.h b/include/verilated_funccov.h deleted file mode 100644 index 7ef17e3cc..000000000 --- a/include/verilated_funccov.h +++ /dev/null @@ -1,300 +0,0 @@ -// -*- 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: 2026-2026 by Wilson Snyder -// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -// -//============================================================================= -/// -/// \file -/// \brief Verilated functional coverage support header -/// -/// This file provides runtime support for SystemVerilog functional coverage -/// constructs (covergroups, coverpoints, bins, cross coverage). -/// -//============================================================================= - -#ifndef VERILATOR_VERILATED_FUNCCOV_H_ -#define VERILATOR_VERILATED_FUNCCOV_H_ - -#include "verilatedos.h" - -#include "verilated.h" -#include "verilated_cov.h" - -#include -#include -#include - -//============================================================================= -// VerilatedCoverBin - Represents a single bin in a coverpoint - -class VerilatedCoverBin VL_NOT_FINAL { -private: - std::string m_name; // Bin name - std::string m_rangeStr; // String representation of range (e.g., "0:15") - uint32_t m_count = 0; // Hit count - uint32_t* m_countp = nullptr; // Pointer to counter (for coverage registration) - -public: - VerilatedCoverBin(const std::string& name, const std::string& rangeStr) - : m_name{name} - , m_rangeStr{rangeStr} - , m_countp{&m_count} {} - - virtual ~VerilatedCoverBin() = default; - - // Accessors - const std::string& name() const { return m_name; } - const std::string& rangeStr() const { return m_rangeStr; } - uint32_t count() const { return m_count; } - uint32_t* countp() { return m_countp; } - - // Increment hit count - void hit() { ++m_count; } - - // Check if value matches this bin (to be overridden by specific bin types) - virtual bool matches(uint64_t value) const { return false; } -}; - -//============================================================================= -// VerilatedCoverRangeBin - Bin that matches a value range - -class VerilatedCoverRangeBin final : public VerilatedCoverBin { -private: - uint64_t m_min; - uint64_t m_max; - -public: - VerilatedCoverRangeBin(const std::string& name, uint64_t min, uint64_t max) - : VerilatedCoverBin(name, std::to_string(min) + ":" + std::to_string(max)) - , m_min{min} - , m_max{max} {} - - bool matches(uint64_t value) const override { return value >= m_min && value <= m_max; } -}; - -//============================================================================= -// VerilatedCoverpoint - Represents a coverage point - -class VerilatedCoverpoint VL_NOT_FINAL { -private: - std::string m_name; // Coverpoint name - std::vector m_bins; // Bins in this coverpoint - bool m_enabled = true; // Coverage collection enabled - -public: - explicit VerilatedCoverpoint(const std::string& name) - : m_name{name} {} - - ~VerilatedCoverpoint() { - for (auto* bin : m_bins) delete bin; - } - - // Accessors - const std::string& name() const { return m_name; } - const std::vector& bins() const { return m_bins; } - bool enabled() const { return m_enabled; } - void enabled(bool flag) { m_enabled = flag; } - - // Add a bin to this coverpoint - void addBin(VerilatedCoverBin* binp) { m_bins.push_back(binp); } - - // Sample a value and update bin counts - void sample(uint64_t value) { - if (!m_enabled) return; - for (auto* bin : m_bins) { - if (bin->matches(value)) { bin->hit(); } - } - } - - // Compute coverage percentage - double getCoverage(uint32_t atLeast = 1) const { - if (m_bins.empty()) return 100.0; - int coveredBins = 0; - for (const auto* bin : m_bins) { - if (bin->count() >= atLeast) ++coveredBins; - } - return (100.0 * coveredBins) / m_bins.size(); - } - - // Register bins with coverage infrastructure - void registerCoverage(VerilatedCovContext* contextp, const std::string& hier, - const std::string& cgName) { - for (auto* bin : m_bins) { - const std::string fullName = cgName + "." + m_name; - const std::string& binName = bin->name(); - const std::string& binRange = bin->rangeStr(); - VL_COVER_INSERT(contextp, hier.c_str(), bin->countp(), "type", "coverpoint", "name", - fullName.c_str(), "bin", binName.c_str(), "range", binRange.c_str()); - } - } -}; - -//============================================================================= -// VerilatedCoverCross - Represents cross coverage between coverpoints - -class VerilatedCoverCross VL_NOT_FINAL { -private: - std::string m_name; // Cross name - std::vector m_coverpoints; // Coverpoints being crossed - std::map m_crossBins; // Sparse storage: "" -> count - bool m_enabled = true; - -public: - explicit VerilatedCoverCross(const std::string& name) - : m_name{name} {} - - // Accessors - const std::string& name() const { return m_name; } - bool enabled() const { return m_enabled; } - void enabled(bool flag) { m_enabled = flag; } - - // Add a coverpoint to cross - void addCoverpoint(VerilatedCoverpoint* cpp) { m_coverpoints.push_back(cpp); } - - // Sample cross product (to be called after coverpoints are sampled) - void sample(const std::vector& values) { - if (!m_enabled || values.size() != m_coverpoints.size()) return; - - // Build cross bin key from matched bins - std::string key = "<"; - bool first = true; - for (size_t i = 0; i < values.size(); ++i) { - // Find which bin matched for this coverpoint - for (const auto* bin : m_coverpoints[i]->bins()) { - if (bin->matches(values[i])) { - if (!first) key += ","; - key += bin->name(); - first = false; - break; - } - } - } - key += ">"; - - // Increment cross bin count - m_crossBins[key]++; - } - - // Compute coverage percentage - double getCoverage(uint32_t atLeast = 1) const { - if (m_crossBins.empty()) return 100.0; - int coveredBins = 0; - for (const auto& pair : m_crossBins) { - if (pair.second >= atLeast) ++coveredBins; - } - // Total possible bins is product of coverpoint bin counts - size_t totalBins = 1; - for (const auto* cp : m_coverpoints) { totalBins *= cp->bins().size(); } - return (100.0 * coveredBins) / totalBins; - } - - // Register cross bins with coverage infrastructure - void registerCoverage(VerilatedCovContext* contextp, const std::string& hier, - const std::string& cgName) { - // Cross bins are registered dynamically as they're hit - // For now, we'll register them all upfront (can be optimized later) - std::string fullName = cgName + "." + m_name; - for (const auto& pair : m_crossBins) { - // Note: We need a persistent counter, so we use the map value's address - // This is safe because std::map doesn't reallocate on insert - const std::string& binName = pair.first; - VL_COVER_INSERT(contextp, hier.c_str(), const_cast(&pair.second), "type", - "cross", "name", fullName.c_str(), "bin", binName.c_str()); - } - } -}; - -//============================================================================= -// VerilatedCovergroup - Represents a covergroup instance - -class VerilatedCovergroup VL_NOT_FINAL { -private: - std::string m_name; // Covergroup type name - std::string m_instName; // Instance name - std::vector m_coverpoints; - std::vector m_crosses; - bool m_enabled = true; - - // Coverage options - uint32_t m_weight = 1; - uint32_t m_goal = 100; - uint32_t m_atLeast = 1; - std::string m_comment; - -public: - explicit VerilatedCovergroup(const std::string& name) - : m_name{name} - , m_instName{name} {} - - ~VerilatedCovergroup() { - for (auto* cp : m_coverpoints) delete cp; - for (auto* cross : m_crosses) delete cross; - } - - // Accessors - const std::string& name() const { return m_name; } - const std::string& instName() const { return m_instName; } - void instName(const std::string& name) { m_instName = name; } - bool enabled() const { return m_enabled; } - - // Options - void weight(uint32_t w) { m_weight = w; } - void goal(uint32_t g) { m_goal = g; } - void atLeast(uint32_t a) { m_atLeast = a; } - void comment(const std::string& c) { m_comment = c; } - - // Add components - void addCoverpoint(VerilatedCoverpoint* cpp) { m_coverpoints.push_back(cpp); } - void addCross(VerilatedCoverCross* cross) { m_crosses.push_back(cross); } - - // Predefined methods per IEEE 1800-2023 Section 19.9 - void sample() { - if (!m_enabled) return; - // Sampling is done by generated code calling coverpoint sample() methods - } - - void start() { m_enabled = true; } - void stop() { m_enabled = false; } - - void set_inst_name(const std::string& name) { m_instName = name; } - - // Get type coverage (0-100) - double get_coverage() const { - if (m_coverpoints.empty()) return 100.0; - double totalCov = 0.0; - uint32_t totalWeight = 0; - for (const auto* cp : m_coverpoints) { - totalCov += cp->getCoverage(m_atLeast) * m_weight; - totalWeight += m_weight; - } - for (const auto* cross : m_crosses) { - totalCov += cross->getCoverage(m_atLeast) * m_weight; - totalWeight += m_weight; - } - return totalWeight > 0 ? totalCov / totalWeight : 100.0; - } - - // Get instance coverage (same as type coverage for now) - double get_inst_coverage() const { return get_coverage(); } - - // Register all coverage points with coverage infrastructure - void registerCoverage(VerilatedCovContext* contextp, const std::string& hier) { - // Register covergroup metadata - // (Will be extended when we add metadata output) - - // Register all coverpoints - for (auto* cp : m_coverpoints) { cp->registerCoverage(contextp, hier, m_name); } - - // Register all crosses - for (auto* cross : m_crosses) { cross->registerCoverage(contextp, hier, m_name); } - } -}; - -#endif // guard diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 884168f03..30a1becd7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -70,8 +70,7 @@ set(HEADERS V3Control.h V3Coverage.h V3CoverageJoin.h - V3CoverageFunctional.h - V3AstNodeFuncCov.h + V3Covergroup.h V3Dead.h V3DebugBisect.h V3Delayed.h @@ -239,8 +238,7 @@ set(COMMON_SOURCES V3Const__gen.cpp V3Coverage.cpp V3CoverageJoin.cpp - V3CoverageFunctional.cpp - V3AstNodeFuncCov.cpp + V3Covergroup.cpp V3Dead.cpp V3Delayed.cpp V3Depth.cpp @@ -405,7 +403,7 @@ add_custom_command( ARGS ${ASTGEN} -I "${srcdir}" --astdef V3AstNodeDType.h --astdef V3AstNodeExpr.h --astdef V3AstNodeOther.h --astdef V3AstNodeStmt.h - --astdef V3AstNodeFuncCov.h --dfgdef V3DfgVertices.h --classes + --dfgdef V3DfgVertices.h --classes ) list( APPEND GENERATED_FILES @@ -517,7 +515,7 @@ foreach(astgen_name ${ASTGENERATED_NAMES}) ARGS ${ASTGEN} -I "${srcdir}" --astdef V3AstNodeDType.h --astdef V3AstNodeExpr.h --astdef V3AstNodeOther.h --astdef V3AstNodeStmt.h - --astdef V3AstNodeFuncCov.h --dfgdef V3DfgVertices.h + --dfgdef V3DfgVertices.h ${astgen_name}.cpp ) list(APPEND GENERATED_FILES ${astgen_name}__gen.cpp) diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index 4e2e7644b..b1384d69f 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -207,7 +207,6 @@ RAW_OBJS = \ RAW_OBJS_PCH_ASTMT = \ V3Ast.o \ - V3AstNodeFuncCov.o \ V3AstNodes.o \ V3Broken.o \ V3Control.o \ @@ -250,7 +249,7 @@ RAW_OBJS_PCH_ASTNOMT = \ V3Combine.o \ V3Common.o \ V3Coverage.o \ - V3CoverageFunctional.o \ + V3Covergroup.o \ V3CoverageJoin.o \ V3Dead.o \ V3Delayed.o \ @@ -362,7 +361,6 @@ NON_STANDALONE_HEADERS = \ V3AstInlines.h \ V3AstNodeDType.h \ V3AstNodeExpr.h \ - V3AstNodeFuncCov.h \ V3AstNodeOther.h \ V3AstNodeStmt.h \ V3DebugBisect.h \ @@ -373,7 +371,6 @@ NON_STANDALONE_HEADERS = \ AST_DEFS := \ V3AstNodeDType.h \ V3AstNodeExpr.h \ - V3AstNodeFuncCov.h \ V3AstNodeOther.h \ V3AstNodeStmt.h \ diff --git a/src/V3Active.cpp b/src/V3Active.cpp index 4262fb8c6..7410851e5 100644 --- a/src/V3Active.cpp +++ b/src/V3Active.cpp @@ -634,7 +634,7 @@ class CovergroupSamplingVisitor final : public VNVisitor { // Helper to get the clocking event from a covergroup class AstSenTree* getCovergroupEvent(AstClass* classp) { - // The AstCovergroup (holding the SenTree) was left in membersp by V3CoverageFunctional + // The AstCovergroup (holding the SenTree) was left in membersp by V3Covergroup for (AstNode* memberp = classp->membersp(); memberp; memberp = memberp->nextp()) { if (AstCovergroup* const cgp = VN_CAST(memberp, Covergroup)) { if (cgp->eventp()) return cgp->eventp(); diff --git a/src/V3Ast.h b/src/V3Ast.h index d80395364..0e8b1ea21 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1583,7 +1583,6 @@ AstNode* VNVisitor::iterateSubtreeReturnEdits(AstNode* nodep) { #include "V3AstNodeOther.h" #include "V3AstNodeExpr.h" #include "V3AstNodeStmt.h" -#include "V3AstNodeFuncCov.h" // clang-format on // Inline function definitions need to go last diff --git a/src/V3AstNodeFuncCov.cpp b/src/V3AstNodeFuncCov.cpp deleted file mode 100644 index 98f621c89..000000000 --- a/src/V3AstNodeFuncCov.cpp +++ /dev/null @@ -1,155 +0,0 @@ -// -*- mode: C++; c-file-style: "cc-mode" -*- -//************************************************************************* -// DESCRIPTION: Verilator: AstNode implementation for functional coverage nodes -// -// 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: 2026-2026 by Wilson Snyder -// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -// -//************************************************************************* - -#include "V3PchAstMT.h" - -#include "V3AstNodeFuncCov.h" - -//###################################################################### -// Dump methods - -void AstCovergroup::dump(std::ostream& str) const { - this->AstNode::dump(str); - str << " " << m_name; - if (m_isClass) str << " [class]"; -} - -void AstCovergroup::dumpJson(std::ostream& str) const { - this->AstNode::dumpJson(str); - str << ", \"name\": " << VString::quotePercent(name()); - if (m_isClass) str << ", \"isClass\": true"; -} - -void AstCoverpoint::dump(std::ostream& str) const { this->AstNodeFuncCovItem::dump(str); } - -void AstCoverpoint::dumpJson(std::ostream& str) const { this->AstNodeFuncCovItem::dumpJson(str); } - -void AstCoverBin::dump(std::ostream& str) const { - this->AstNode::dump(str); - str << " " << m_name << " "; - switch (m_type) { - case VCoverBinsType::USER: str << "user"; break; - case VCoverBinsType::ARRAY: str << "array"; break; - case VCoverBinsType::AUTO: str << "auto"; break; - case VCoverBinsType::BINS_IGNORE: str << "ignore"; break; - case VCoverBinsType::BINS_ILLEGAL: str << "illegal"; break; - case VCoverBinsType::DEFAULT: str << "default"; break; - case VCoverBinsType::BINS_WILDCARD: str << "wildcard"; break; - case VCoverBinsType::TRANSITION: str << "transition"; break; - } - if (m_isArray) str << "[]"; -} - -void AstCoverBin::dumpJson(std::ostream& str) const { - this->AstNode::dumpJson(str); - str << ", \"name\": " << VString::quotePercent(m_name); - str << ", \"binsType\": "; - switch (m_type) { - case VCoverBinsType::USER: str << "\"user\""; break; - case VCoverBinsType::ARRAY: str << "\"array\""; break; - case VCoverBinsType::AUTO: str << "\"auto\""; break; - case VCoverBinsType::BINS_IGNORE: str << "\"ignore\""; break; - case VCoverBinsType::BINS_ILLEGAL: str << "\"illegal\""; break; - case VCoverBinsType::DEFAULT: str << "\"default\""; break; - case VCoverBinsType::BINS_WILDCARD: str << "\"wildcard\""; break; - case VCoverBinsType::TRANSITION: str << "\"transition\""; break; - } - if (m_isArray) str << ", \"isArray\": true"; -} - -void AstCoverTransItem::dump(std::ostream& str) const { - this->AstNode::dump(str); - switch (m_repType) { - case VTransRepType::NONE: break; - case VTransRepType::CONSEC: str << " [*]"; break; - case VTransRepType::GOTO: str << " [->]"; break; - case VTransRepType::NONCONS: str << " [=]"; break; - } -} - -void AstCoverTransItem::dumpJson(std::ostream& str) const { - this->AstNode::dumpJson(str); - if (m_repType != VTransRepType::NONE) { - str << ", \"repType\": "; - switch (m_repType) { - case VTransRepType::NONE: break; - case VTransRepType::CONSEC: str << "\"consec\""; break; - case VTransRepType::GOTO: str << "\"goto\""; break; - case VTransRepType::NONCONS: str << "\"noncons\""; break; - } - } -} - -void AstCoverTransSet::dump(std::ostream& str) const { - this->AstNode::dump(str); - str << " trans_set"; -} - -void AstCoverTransSet::dumpJson(std::ostream& str) const { this->AstNode::dumpJson(str); } - -void AstCoverCross::dump(std::ostream& str) const { this->AstNodeFuncCovItem::dump(str); } - -void AstCoverCross::dumpJson(std::ostream& str) const { this->AstNodeFuncCovItem::dumpJson(str); } - -void AstCoverCrossBins::dump(std::ostream& str) const { - this->AstNode::dump(str); - str << " " << m_name; -} - -void AstCoverCrossBins::dumpJson(std::ostream& str) const { - this->AstNode::dumpJson(str); - str << ", \"name\": " << VString::quotePercent(m_name); -} - -void AstCoverOption::dump(std::ostream& str) const { - this->AstNode::dump(str); - str << " "; - switch (m_type) { - case VCoverOptionType::WEIGHT: str << "weight"; break; - case VCoverOptionType::GOAL: str << "goal"; break; - case VCoverOptionType::AT_LEAST: str << "at_least"; break; - case VCoverOptionType::AUTO_BIN_MAX: str << "auto_bin_max"; break; - case VCoverOptionType::PER_INSTANCE: str << "per_instance"; break; - case VCoverOptionType::COMMENT: str << "comment"; break; - } -} - -void AstCoverOption::dumpJson(std::ostream& str) const { - this->AstNode::dumpJson(str); - str << ", \"optionType\": "; - switch (m_type) { - case VCoverOptionType::WEIGHT: str << "\"weight\""; break; - case VCoverOptionType::GOAL: str << "\"goal\""; break; - case VCoverOptionType::AT_LEAST: str << "\"at_least\""; break; - case VCoverOptionType::AUTO_BIN_MAX: str << "\"auto_bin_max\""; break; - case VCoverOptionType::PER_INSTANCE: str << "\"per_instance\""; break; - case VCoverOptionType::COMMENT: str << "\"comment\""; break; - } -} - -void AstCoverpointRef::dump(std::ostream& str) const { - this->AstNode::dump(str); - str << " " << m_name; -} - -void AstCoverpointRef::dumpJson(std::ostream& str) const { - this->AstNode::dumpJson(str); - str << ", \"name\": " << VString::quotePercent(m_name); -} - -void AstCoverSelectExpr::dump(std::ostream& str) const { this->AstNode::dump(str); } - -void AstCoverSelectExpr::dumpJson(std::ostream& str) const { this->AstNode::dumpJson(str); } diff --git a/src/V3AstNodeFuncCov.h b/src/V3AstNodeFuncCov.h deleted file mode 100644 index 2f8216b7b..000000000 --- a/src/V3AstNodeFuncCov.h +++ /dev/null @@ -1,289 +0,0 @@ -// -*- mode: C++; c-file-style: "cc-mode" -*- -//************************************************************************* -// DESCRIPTION: Verilator: AstNode sub-types for functional coverage -// -// 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: 2026-2026 by Wilson Snyder -// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -// -//************************************************************************* -// -// This file contains AST nodes for SystemVerilog functional coverage -// (IEEE 1800-2023 Section 19) -// -//************************************************************************* - -#ifndef VERILATOR_V3ASTNODEFUNCCOV_H_ -#define VERILATOR_V3ASTNODEFUNCCOV_H_ - -#ifndef VERILATOR_V3AST_H_ -#error "Use V3Ast.h as the include" -#include "V3Ast.h" -#define VL_NOT_FINAL -#endif - -//###################################################################### -// Enumerations - -enum class VCoverBinsType : uint8_t { - USER, - ARRAY, - AUTO, - BINS_IGNORE, // Renamed to avoid Windows macro conflict - BINS_ILLEGAL, // Renamed to avoid Windows macro conflict - DEFAULT, - BINS_WILDCARD, // Renamed to avoid Windows macro conflict - TRANSITION -}; - -enum class VCoverOptionType : uint8_t { - WEIGHT, - GOAL, - AT_LEAST, - AUTO_BIN_MAX, - PER_INSTANCE, - COMMENT -}; - -enum class VTransRepType : uint8_t { - NONE, // No repetition - CONSEC, // Consecutive repetition [*] - GOTO, // Goto repetition [->] - NONCONS // Nonconsecutive repetition [=] -}; - -//###################################################################### -// Base classes - -class AstNodeFuncCovItem VL_NOT_FINAL : public AstNode { -protected: - string m_name; - -public: - AstNodeFuncCovItem(VNType t, FileLine* fl, const string& name) - : AstNode{t, fl} - , m_name{name} {} - ASTGEN_MEMBERS_AstNodeFuncCovItem; - string name() const override VL_MT_STABLE { return m_name; } - void name(const string& flag) override { m_name = flag; } - bool maybePointedTo() const override { return true; } -}; - -//###################################################################### -// Concrete nodes - ORDER MATTERS FOR ASTGEN! -// Must be in order: CoverBin, CoverCrossBins, CoverOption, CoverSelectExpr, -// CoverTransItem, CoverTransSet, Covergroup, CoverpointRef, CoverCross, -// Coverpoint - -// Forward declarations for types used in constructors -class AstCoverTransSet; -class AstCoverSelectExpr; - -class AstCoverBin final : public AstNode { - // @astgen op1 := rangesp : List[AstNode] - // @astgen op2 := iffp : Optional[AstNodeExpr] - // @astgen op3 := arraySizep : Optional[AstNodeExpr] - // @astgen op4 := transp : List[AstCoverTransSet] - string m_name; - VCoverBinsType m_type; - bool m_isArray = false; - -public: - AstCoverBin(FileLine* fl, const string& name, AstNode* rangesp, bool isIgnore, bool isIllegal, - bool isWildcard = false) - : ASTGEN_SUPER_CoverBin(fl) - , m_name{name} - , m_type{isWildcard ? VCoverBinsType::BINS_WILDCARD - : (isIllegal ? VCoverBinsType::BINS_ILLEGAL - : (isIgnore ? VCoverBinsType::BINS_IGNORE - : VCoverBinsType::USER))} { - if (rangesp) addRangesp(rangesp); - } - // Constructor for automatic bins - AstCoverBin(FileLine* fl, const string& name, AstNodeExpr* arraySizep) - : ASTGEN_SUPER_CoverBin(fl) - , m_name{name} - , m_type{VCoverBinsType::AUTO} - , m_isArray{true} { - this->arraySizep(arraySizep); - } - // Constructor for default bins (catch-all) - AstCoverBin(FileLine* fl, const string& name, VCoverBinsType type) - : ASTGEN_SUPER_CoverBin(fl) - , m_name{name} - , m_type{type} { - // DEFAULT bins have no ranges - they catch everything not in other bins - } - // Constructor for transition bins - AstCoverBin(FileLine* fl, const string& name, AstCoverTransSet* transp, bool isIgnore, - bool isIllegal, bool isArrayBin = false) - : ASTGEN_SUPER_CoverBin(fl) - , m_name{name} - , m_type{isIllegal ? VCoverBinsType::BINS_ILLEGAL - : (isIgnore ? VCoverBinsType::BINS_IGNORE : VCoverBinsType::TRANSITION)} - , m_isArray{isArrayBin} { - if (transp) addTransp(transp); - } - ASTGEN_MEMBERS_AstCoverBin; - void dump(std::ostream& str) const override; - void dumpJson(std::ostream& str) const override; - string name() const override VL_MT_STABLE { return m_name; } - VCoverBinsType binsType() const { return m_type; } - bool isArray() const { return m_isArray; } - void isArray(bool flag) { m_isArray = flag; } -}; - -class AstCoverCrossBins final : public AstNode { - // @astgen op1 := selectp : Optional[AstCoverSelectExpr] - string m_name; - -public: - AstCoverCrossBins(FileLine* fl, const string& name, AstCoverSelectExpr* selectp) - : ASTGEN_SUPER_CoverCrossBins(fl) - , m_name{name} { - this->selectp(selectp); - } - ASTGEN_MEMBERS_AstCoverCrossBins; - void dump(std::ostream& str) const override; - void dumpJson(std::ostream& str) const override; - string name() const override VL_MT_STABLE { return m_name; } -}; - -class AstCoverOption final : public AstNode { - // @astgen op1 := valuep : AstNodeExpr - VCoverOptionType m_type; - -public: - AstCoverOption(FileLine* fl, VCoverOptionType type, AstNodeExpr* valuep) - : ASTGEN_SUPER_CoverOption(fl) - , m_type{type} { - this->valuep(valuep); - } - ASTGEN_MEMBERS_AstCoverOption; - void dump(std::ostream& str) const override; - void dumpJson(std::ostream& str) const override; - VCoverOptionType optionType() const { return m_type; } -}; - -class AstCoverSelectExpr final : public AstNode { - // @astgen op1 := exprp : AstNodeExpr -public: - AstCoverSelectExpr(FileLine* fl, AstNodeExpr* exprp) - : ASTGEN_SUPER_CoverSelectExpr(fl) { - this->exprp(exprp); - } - ASTGEN_MEMBERS_AstCoverSelectExpr; - void dump(std::ostream& str) const override; - void dumpJson(std::ostream& str) const override; -}; - -// Represents a single transition item: value or value[*N] or value[->N] or value[=N] -class AstCoverTransItem final : public AstNode { - // @astgen op1 := valuesp : List[AstNode] // Range list (values or ranges) - // @astgen op2 := repMinp : Optional[AstNodeExpr] // Repetition min count (for [*], [->], [=]) - // @astgen op3 := repMaxp : Optional[AstNodeExpr] // Repetition max count (for ranges) - VTransRepType m_repType; - -public: - AstCoverTransItem(FileLine* fl, AstNode* valuesp, VTransRepType repType = VTransRepType::NONE) - : ASTGEN_SUPER_CoverTransItem(fl) - , m_repType{repType} { - if (valuesp) addValuesp(valuesp); - } - ASTGEN_MEMBERS_AstCoverTransItem; - void dump(std::ostream& str) const override; - void dumpJson(std::ostream& str) const override; - VTransRepType repType() const { return m_repType; } -}; - -// Represents a transition set: value1 => value2 => value3 -class AstCoverTransSet final : public AstNode { - // @astgen op1 := itemsp : List[AstCoverTransItem] -public: - AstCoverTransSet(FileLine* fl, AstCoverTransItem* itemsp) - : ASTGEN_SUPER_CoverTransSet(fl) { - if (itemsp) addItemsp(itemsp); - } - ASTGEN_MEMBERS_AstCoverTransSet; - void dump(std::ostream& str) const override; - void dumpJson(std::ostream& str) const override; -}; - -class AstCovergroup final : public AstNode { - // @astgen op1 := argsp : List[AstVar] - // @astgen op2 := membersp : List[AstNode] - // @astgen op3 := eventp : Optional[AstSenTree] - string m_name; - bool m_isClass = false; - -public: - AstCovergroup(FileLine* fl, const string& name, AstNode* membersp, AstSenTree* eventp) - : ASTGEN_SUPER_Covergroup(fl) - , m_name{name} { - if (membersp) addMembersp(membersp); - this->eventp(eventp); - } - ASTGEN_MEMBERS_AstCovergroup; - void dump(std::ostream& str) const override; - void dumpJson(std::ostream& str) const override; - string name() const override VL_MT_STABLE { return m_name; } - void name(const string& name) override { m_name = name; } - bool isClass() const { return m_isClass; } - void isClass(bool flag) { m_isClass = flag; } - bool maybePointedTo() const override { return true; } -}; - -class AstCoverpointRef final : public AstNode { - // @astgen ptr := m_coverpointp : Optional[AstCoverpoint] - string m_name; - -public: - AstCoverpointRef(FileLine* fl, const string& name) - : ASTGEN_SUPER_CoverpointRef(fl) - , m_name{name} {} - ASTGEN_MEMBERS_AstCoverpointRef; - void dump(std::ostream& str) const override; - void dumpJson(std::ostream& str) const override; - string name() const override VL_MT_STABLE { return m_name; } - AstCoverpoint* coverpointp() const { return m_coverpointp; } - void coverpointp(AstCoverpoint* nodep) { m_coverpointp = nodep; } -}; - -class AstCoverCross final : public AstNodeFuncCovItem { - // @astgen op1 := itemsp : List[AstCoverpointRef] - // @astgen op2 := binsp : List[AstCoverCrossBins] - // @astgen op3 := optionsp : List[AstCoverOption] -public: - AstCoverCross(FileLine* fl, const string& name, AstCoverpointRef* itemsp) - : ASTGEN_SUPER_CoverCross(fl, name) { - if (itemsp) addItemsp(itemsp); - } - ASTGEN_MEMBERS_AstCoverCross; - void dump(std::ostream& str) const override; - void dumpJson(std::ostream& str) const override; -}; - -class AstCoverpoint final : public AstNodeFuncCovItem { - // @astgen op1 := exprp : AstNodeExpr - // @astgen op2 := binsp : List[AstCoverBin] - // @astgen op3 := iffp : Optional[AstNodeExpr] - // @astgen op4 := optionsp : List[AstCoverOption] -public: - AstCoverpoint(FileLine* fl, const string& name, AstNodeExpr* exprp) - : ASTGEN_SUPER_Coverpoint(fl, name) { - this->exprp(exprp); - } - ASTGEN_MEMBERS_AstCoverpoint; - void dump(std::ostream& str) const override; - void dumpJson(std::ostream& str) const override; -}; - -//###################################################################### - -#endif // Guard diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 79d24b0f6..27a3e12bc 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -253,6 +253,20 @@ public: string name() const override VL_MT_STABLE { return m_name; } bool sameNode(const AstNode* /*samep*/) const override { return true; } }; +class AstNodeFuncCovItem VL_NOT_FINAL : public AstNode { + // Base class for functional coverage items (coverpoints, crosses) +protected: + string m_name; + +public: + AstNodeFuncCovItem(VNType t, FileLine* fl, const string& name) + : AstNode{t, fl} + , m_name{name} {} + ASTGEN_MEMBERS_AstNodeFuncCovItem; + string name() const override VL_MT_STABLE { return m_name; } + void name(const string& flag) override { m_name = flag; } + bool maybePointedTo() const override { return true; } +}; class AstNodeGen VL_NOT_FINAL : public AstNode { // Generate construct public: @@ -1024,6 +1038,198 @@ public: bool isPredictOptimizable() const override { return false; } bool sameNode(const AstNode* /*samep*/) const override { return true; } }; + +// Forward declarations for types used in constructors below +class AstCoverTransSet; +class AstCoverSelectExpr; + +enum class VCoverBinsType : uint8_t { + USER, + ARRAY, + AUTO, + BINS_IGNORE, // Renamed to avoid Windows macro conflict + BINS_ILLEGAL, // Renamed to avoid Windows macro conflict + DEFAULT, + BINS_WILDCARD, // Renamed to avoid Windows macro conflict + TRANSITION +}; + +enum class VCoverOptionType : uint8_t { + WEIGHT, + GOAL, + AT_LEAST, + AUTO_BIN_MAX, + PER_INSTANCE, + COMMENT +}; + +enum class VTransRepType : uint8_t { + NONE, // No repetition + CONSEC, // Consecutive repetition [*] + GOTO, // Goto repetition [->] + NONCONS // Nonconsecutive repetition [=] +}; + +class AstCoverBin final : public AstNode { + // @astgen op1 := rangesp : List[AstNode] + // @astgen op2 := iffp : Optional[AstNodeExpr] + // @astgen op3 := arraySizep : Optional[AstNodeExpr] + // @astgen op4 := transp : List[AstCoverTransSet] + string m_name; + VCoverBinsType m_type; + bool m_isArray = false; + +public: + AstCoverBin(FileLine* fl, const string& name, AstNode* rangesp, bool isIgnore, bool isIllegal, + bool isWildcard = false) + : ASTGEN_SUPER_CoverBin(fl) + , m_name{name} + , m_type{isWildcard ? VCoverBinsType::BINS_WILDCARD + : (isIllegal ? VCoverBinsType::BINS_ILLEGAL + : (isIgnore ? VCoverBinsType::BINS_IGNORE + : VCoverBinsType::USER))} { + if (rangesp) addRangesp(rangesp); + } + // Constructor for automatic bins + AstCoverBin(FileLine* fl, const string& name, AstNodeExpr* arraySizep) + : ASTGEN_SUPER_CoverBin(fl) + , m_name{name} + , m_type{VCoverBinsType::AUTO} + , m_isArray{true} { + this->arraySizep(arraySizep); + } + // Constructor for default bins (catch-all) + AstCoverBin(FileLine* fl, const string& name, VCoverBinsType type) + : ASTGEN_SUPER_CoverBin(fl) + , m_name{name} + , m_type{type} {} + // Constructor for transition bins + AstCoverBin(FileLine* fl, const string& name, AstCoverTransSet* transp, bool isIgnore, + bool isIllegal, bool isArrayBin = false) + : ASTGEN_SUPER_CoverBin(fl) + , m_name{name} + , m_type{isIllegal ? VCoverBinsType::BINS_ILLEGAL + : (isIgnore ? VCoverBinsType::BINS_IGNORE : VCoverBinsType::TRANSITION)} + , m_isArray{isArrayBin} { + if (transp) addTransp(transp); + } + ASTGEN_MEMBERS_AstCoverBin; + void dump(std::ostream& str) const override; + void dumpJson(std::ostream& str) const override; + string name() const override VL_MT_STABLE { return m_name; } + VCoverBinsType binsType() const { return m_type; } + bool isArray() const { return m_isArray; } + void isArray(bool flag) { m_isArray = flag; } +}; +class AstCoverCrossBins final : public AstNode { + // @astgen op1 := selectp : Optional[AstCoverSelectExpr] + string m_name; + +public: + AstCoverCrossBins(FileLine* fl, const string& name, AstCoverSelectExpr* selectp) + : ASTGEN_SUPER_CoverCrossBins(fl) + , m_name{name} { + this->selectp(selectp); + } + ASTGEN_MEMBERS_AstCoverCrossBins; + void dump(std::ostream& str) const override; + void dumpJson(std::ostream& str) const override; + string name() const override VL_MT_STABLE { return m_name; } +}; +class AstCoverOption final : public AstNode { + // @astgen op1 := valuep : AstNodeExpr + VCoverOptionType m_type; + +public: + AstCoverOption(FileLine* fl, VCoverOptionType type, AstNodeExpr* valuep) + : ASTGEN_SUPER_CoverOption(fl) + , m_type{type} { + this->valuep(valuep); + } + ASTGEN_MEMBERS_AstCoverOption; + void dump(std::ostream& str) const override; + void dumpJson(std::ostream& str) const override; + VCoverOptionType optionType() const { return m_type; } +}; +class AstCoverSelectExpr final : public AstNode { + // @astgen op1 := exprp : AstNodeExpr +public: + AstCoverSelectExpr(FileLine* fl, AstNodeExpr* exprp) + : ASTGEN_SUPER_CoverSelectExpr(fl) { + this->exprp(exprp); + } + ASTGEN_MEMBERS_AstCoverSelectExpr; + void dump(std::ostream& str) const override; + void dumpJson(std::ostream& str) const override; +}; +class AstCoverTransItem final : public AstNode { + // Represents a single transition item: value or value[*N] or value[->N] or value[=N] + // @astgen op1 := valuesp : List[AstNode] + // @astgen op2 := repMinp : Optional[AstNodeExpr] + // @astgen op3 := repMaxp : Optional[AstNodeExpr] + VTransRepType m_repType; + +public: + AstCoverTransItem(FileLine* fl, AstNode* valuesp, VTransRepType repType = VTransRepType::NONE) + : ASTGEN_SUPER_CoverTransItem(fl) + , m_repType{repType} { + if (valuesp) addValuesp(valuesp); + } + ASTGEN_MEMBERS_AstCoverTransItem; + void dump(std::ostream& str) const override; + void dumpJson(std::ostream& str) const override; + VTransRepType repType() const { return m_repType; } +}; +class AstCoverTransSet final : public AstNode { + // Represents a transition set: value1 => value2 => value3 + // @astgen op1 := itemsp : List[AstCoverTransItem] +public: + AstCoverTransSet(FileLine* fl, AstCoverTransItem* itemsp) + : ASTGEN_SUPER_CoverTransSet(fl) { + if (itemsp) addItemsp(itemsp); + } + ASTGEN_MEMBERS_AstCoverTransSet; + void dump(std::ostream& str) const override; + void dumpJson(std::ostream& str) const override; +}; +class AstCovergroup final : public AstNode { + // @astgen op1 := argsp : List[AstVar] + // @astgen op2 := membersp : List[AstNode] + // @astgen op3 := eventp : Optional[AstSenTree] + string m_name; + bool m_isClass = false; + +public: + AstCovergroup(FileLine* fl, const string& name, AstNode* membersp, AstSenTree* eventp) + : ASTGEN_SUPER_Covergroup(fl) + , m_name{name} { + if (membersp) addMembersp(membersp); + this->eventp(eventp); + } + ASTGEN_MEMBERS_AstCovergroup; + void dump(std::ostream& str) const override; + void dumpJson(std::ostream& str) const override; + string name() const override VL_MT_STABLE { return m_name; } + void name(const string& name) override { m_name = name; } + bool isClass() const { return m_isClass; } + void isClass(bool flag) { m_isClass = flag; } + bool maybePointedTo() const override { return true; } +}; +class AstCoverpointRef final : public AstNode { + // @astgen ptr := m_coverpointp : Optional[AstCoverpoint] + string m_name; + +public: + AstCoverpointRef(FileLine* fl, const string& name) + : ASTGEN_SUPER_CoverpointRef(fl) + , m_name{name} {} + ASTGEN_MEMBERS_AstCoverpointRef; + void dump(std::ostream& str) const override; + void dumpJson(std::ostream& str) const override; + string name() const override VL_MT_STABLE { return m_name; } + AstCoverpoint* coverpointp() const { return m_coverpointp; } + void coverpointp(AstCoverpoint* nodep) { m_coverpointp = nodep; } +}; class AstDefParam final : public AstNode { // A defparam assignment // Parents: MODULE @@ -2539,6 +2745,33 @@ public: void dump(std::ostream& str = std::cout) const override; void dumpJson(std::ostream& str = std::cout) const override; }; +class AstCoverCross final : public AstNodeFuncCovItem { + // @astgen op1 := itemsp : List[AstCoverpointRef] + // @astgen op2 := binsp : List[AstCoverCrossBins] + // @astgen op3 := optionsp : List[AstCoverOption] +public: + AstCoverCross(FileLine* fl, const string& name, AstCoverpointRef* itemsp) + : ASTGEN_SUPER_CoverCross(fl, name) { + if (itemsp) addItemsp(itemsp); + } + ASTGEN_MEMBERS_AstCoverCross; + void dump(std::ostream& str) const override; + void dumpJson(std::ostream& str) const override; +}; +class AstCoverpoint final : public AstNodeFuncCovItem { + // @astgen op1 := exprp : AstNodeExpr + // @astgen op2 := binsp : List[AstCoverBin] + // @astgen op3 := iffp : Optional[AstNodeExpr] + // @astgen op4 := optionsp : List[AstCoverOption] +public: + AstCoverpoint(FileLine* fl, const string& name, AstNodeExpr* exprp) + : ASTGEN_SUPER_Coverpoint(fl, name) { + this->exprp(exprp); + } + ASTGEN_MEMBERS_AstCoverpoint; + void dump(std::ostream& str) const override; + void dumpJson(std::ostream& str) const override; +}; // === AstNodeGen === class AstGenBlock final : public AstNodeGen { @@ -2964,4 +3197,5 @@ public: bool sameNode(const AstNode* /*samep*/) const override { return true; } }; + #endif // Guard diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index e8f78d849..455b9dc68 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -3259,7 +3259,6 @@ void AstCoverToggleDecl::dumpJson(std::ostream& str) const { std::to_string(range().left()) + ":" + std::to_string(range().right())); } } -// NOTE: AstCoverBin and AstCoverpoint dump methods removed - moved to V3AstNodeFuncCov.cpp void AstCoverInc::dump(std::ostream& str) const { this->AstNodeStmt::dump(str); str << " -> "; @@ -3496,3 +3495,139 @@ const char* AstNot::widthMismatch() const VL_MT_STABLE { BROKEN_RTN(lhsp()->widthMin() != widthMin()); return nullptr; } + +//###################################################################### +// Functional coverage dump methods + +void AstCovergroup::dump(std::ostream& str) const { + this->AstNode::dump(str); + str << " " << m_name; + if (m_isClass) str << " [class]"; +} + +void AstCovergroup::dumpJson(std::ostream& str) const { + this->AstNode::dumpJson(str); + str << ", \"name\": " << VString::quotePercent(name()); + if (m_isClass) str << ", \"isClass\": true"; +} + +void AstCoverpoint::dump(std::ostream& str) const { this->AstNodeFuncCovItem::dump(str); } + +void AstCoverpoint::dumpJson(std::ostream& str) const { this->AstNodeFuncCovItem::dumpJson(str); } + +void AstCoverBin::dump(std::ostream& str) const { + this->AstNode::dump(str); + str << " " << m_name << " "; + switch (m_type) { + case VCoverBinsType::USER: str << "user"; break; + case VCoverBinsType::ARRAY: str << "array"; break; + case VCoverBinsType::AUTO: str << "auto"; break; + case VCoverBinsType::BINS_IGNORE: str << "ignore"; break; + case VCoverBinsType::BINS_ILLEGAL: str << "illegal"; break; + case VCoverBinsType::DEFAULT: str << "default"; break; + case VCoverBinsType::BINS_WILDCARD: str << "wildcard"; break; + case VCoverBinsType::TRANSITION: str << "transition"; break; + } + if (m_isArray) str << "[]"; +} + +void AstCoverBin::dumpJson(std::ostream& str) const { + this->AstNode::dumpJson(str); + str << ", \"name\": " << VString::quotePercent(m_name); + str << ", \"binsType\": "; + switch (m_type) { + case VCoverBinsType::USER: str << "\"user\""; break; + case VCoverBinsType::ARRAY: str << "\"array\""; break; + case VCoverBinsType::AUTO: str << "\"auto\""; break; + case VCoverBinsType::BINS_IGNORE: str << "\"ignore\""; break; + case VCoverBinsType::BINS_ILLEGAL: str << "\"illegal\""; break; + case VCoverBinsType::DEFAULT: str << "\"default\""; break; + case VCoverBinsType::BINS_WILDCARD: str << "\"wildcard\""; break; + case VCoverBinsType::TRANSITION: str << "\"transition\""; break; + } + if (m_isArray) str << ", \"isArray\": true"; +} + +void AstCoverTransItem::dump(std::ostream& str) const { + this->AstNode::dump(str); + switch (m_repType) { + case VTransRepType::NONE: break; + case VTransRepType::CONSEC: str << " [*]"; break; + case VTransRepType::GOTO: str << " [->]"; break; + case VTransRepType::NONCONS: str << " [=]"; break; + } +} + +void AstCoverTransItem::dumpJson(std::ostream& str) const { + this->AstNode::dumpJson(str); + if (m_repType != VTransRepType::NONE) { + str << ", \"repType\": "; + switch (m_repType) { + case VTransRepType::NONE: break; + case VTransRepType::CONSEC: str << "\"consec\""; break; + case VTransRepType::GOTO: str << "\"goto\""; break; + case VTransRepType::NONCONS: str << "\"noncons\""; break; + } + } +} + +void AstCoverTransSet::dump(std::ostream& str) const { + this->AstNode::dump(str); + str << " trans_set"; +} + +void AstCoverTransSet::dumpJson(std::ostream& str) const { this->AstNode::dumpJson(str); } + +void AstCoverCross::dump(std::ostream& str) const { this->AstNodeFuncCovItem::dump(str); } + +void AstCoverCross::dumpJson(std::ostream& str) const { this->AstNodeFuncCovItem::dumpJson(str); } + +void AstCoverCrossBins::dump(std::ostream& str) const { + this->AstNode::dump(str); + str << " " << m_name; +} + +void AstCoverCrossBins::dumpJson(std::ostream& str) const { + this->AstNode::dumpJson(str); + str << ", \"name\": " << VString::quotePercent(m_name); +} + +void AstCoverOption::dump(std::ostream& str) const { + this->AstNode::dump(str); + str << " "; + switch (m_type) { + case VCoverOptionType::WEIGHT: str << "weight"; break; + case VCoverOptionType::GOAL: str << "goal"; break; + case VCoverOptionType::AT_LEAST: str << "at_least"; break; + case VCoverOptionType::AUTO_BIN_MAX: str << "auto_bin_max"; break; + case VCoverOptionType::PER_INSTANCE: str << "per_instance"; break; + case VCoverOptionType::COMMENT: str << "comment"; break; + } +} + +void AstCoverOption::dumpJson(std::ostream& str) const { + this->AstNode::dumpJson(str); + str << ", \"optionType\": "; + switch (m_type) { + case VCoverOptionType::WEIGHT: str << "\"weight\""; break; + case VCoverOptionType::GOAL: str << "\"goal\""; break; + case VCoverOptionType::AT_LEAST: str << "\"at_least\""; break; + case VCoverOptionType::AUTO_BIN_MAX: str << "\"auto_bin_max\""; break; + case VCoverOptionType::PER_INSTANCE: str << "\"per_instance\""; break; + case VCoverOptionType::COMMENT: str << "\"comment\""; break; + } +} + +void AstCoverpointRef::dump(std::ostream& str) const { + this->AstNode::dump(str); + str << " " << m_name; +} + +void AstCoverpointRef::dumpJson(std::ostream& str) const { + this->AstNode::dumpJson(str); + str << ", \"name\": " << VString::quotePercent(m_name); +} + +void AstCoverSelectExpr::dump(std::ostream& str) const { this->AstNode::dump(str); } + +void AstCoverSelectExpr::dumpJson(std::ostream& str) const { this->AstNode::dumpJson(str); } diff --git a/src/V3Coverage.cpp b/src/V3Coverage.cpp index d5ebea939..7f25d6b5b 100644 --- a/src/V3Coverage.cpp +++ b/src/V3Coverage.cpp @@ -797,6 +797,7 @@ class CoverageVisitor final : public VNVisitor { pair.first->second = varp; if (m_ftaskp) { varp->funcLocal(true); + varp->lifetime(VLifetime::AUTOMATIC_EXPLICIT); m_ftaskp->stmtsp()->addHereThisAsNext(varp); } else { m_modp->stmtsp()->addHereThisAsNext(varp); diff --git a/src/V3CoverageFunctional.cpp b/src/V3Covergroup.cpp similarity index 99% rename from src/V3CoverageFunctional.cpp rename to src/V3Covergroup.cpp index 82de86961..6aeea2f67 100644 --- a/src/V3CoverageFunctional.cpp +++ b/src/V3Covergroup.cpp @@ -24,7 +24,7 @@ #include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT -#include "V3CoverageFunctional.h" +#include "V3Covergroup.h" VL_DEFINE_DEBUG_FUNCTIONS; @@ -1886,7 +1886,7 @@ public: //###################################################################### // Functional coverage class functions -void V3CoverageFunctional::coverageFunctional(AstNetlist* nodep) { +void V3Covergroup::covergroup(AstNetlist* nodep) { UINFO(4, __FUNCTION__ << ": " << endl); { FunctionalCoverageVisitor{nodep}; } // Destruct before checking V3Global::dumpCheckGlobalTree("coveragefunc", 0, dumpTreeEitherLevel() >= 3); diff --git a/src/V3CoverageFunctional.h b/src/V3Covergroup.h similarity index 76% rename from src/V3CoverageFunctional.h rename to src/V3Covergroup.h index d3f10b54e..949b1484b 100644 --- a/src/V3CoverageFunctional.h +++ b/src/V3Covergroup.h @@ -1,6 +1,6 @@ // -*- mode: C++; c-file-style: "cc-mode" -*- //************************************************************************* -// DESCRIPTION: Verilator: Functional coverage implementation +// DESCRIPTION: Verilator: Covergroup implementation // // Code available from: https://verilator.org // @@ -14,17 +14,17 @@ // //************************************************************************* -#ifndef VERILATOR_V3COVERAGEFUNCTIONAL_H_ -#define VERILATOR_V3COVERAGEFUNCTIONAL_H_ +#ifndef VERILATOR_V3COVERGROUP_H_ +#define VERILATOR_V3COVERGROUP_H_ #include "V3Ast.h" #include "V3Error.h" //============================================================================ -class V3CoverageFunctional final { +class V3Covergroup final { public: - static void coverageFunctional(AstNetlist* nodep); + static void covergroup(AstNetlist* nodep); }; #endif // Guard diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index f93266cd2..0272c62db 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -227,12 +227,6 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst { iterateAndNextConstNull(nodep->rhsp()); if (!m_suppressSemi) puts(";\n"); } - void visit(AstAssignDly* nodep) override { - iterateAndNextConstNull(nodep->lhsp()); - putfs(nodep, " <= "); - iterateAndNextConstNull(nodep->rhsp()); - puts(";\n"); - } void visit(AstAlias* nodep) override { putbs("alias "); iterateConst(nodep->itemsp()); diff --git a/src/V3LinkInc.cpp b/src/V3LinkInc.cpp index 3fbb7999a..a770b7017 100644 --- a/src/V3LinkInc.cpp +++ b/src/V3LinkInc.cpp @@ -309,6 +309,7 @@ class LinkIncVisitor final : public VNVisitor { AstVar* const varp = new AstVar{ fl, VVarType::BLOCKTEMP, name, VFlagChildDType{}, new AstRefDType{fl, AstRefDType::FlagTypeOfExpr{}, readp->cloneTree(true)}}; + varp->lifetime(VLifetime::AUTOMATIC_EXPLICIT); if (m_ftaskp) varp->funcLocal(true); // Declare the variable diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 675c20474..5eefa8a1a 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -37,7 +37,7 @@ #include "V3Const.h" #include "V3Control.h" #include "V3Coverage.h" -#include "V3CoverageFunctional.h" +#include "V3Covergroup.h" #include "V3CoverageJoin.h" #include "V3Dead.h" #include "V3Delayed.h" @@ -239,7 +239,7 @@ static void process() { // Functional coverage code generation // Generate code for covergroups/coverpoints - V3CoverageFunctional::coverageFunctional(v3Global.rootp()); + V3Covergroup::covergroup(v3Global.rootp()); // Resolve randsequence if they are used by the design if (v3Global.useRandSequence()) V3RandSequence::randSequenceNetlist(v3Global.rootp()); diff --git a/test_regress/t/t_funccov_basic.py b/test_regress/t/t_funccov_basic.py deleted file mode 100755 index 25d903c62..000000000 --- a/test_regress/t/t_funccov_basic.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/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(verilator_flags2=["--exe", "t/t_funccov_basic_main.cpp"], make_main=False) - -test.execute() - -test.passes() diff --git a/test_regress/t/t_funccov_basic.v b/test_regress/t/t_funccov_basic.v deleted file mode 100644 index 447b78aff..000000000 --- a/test_regress/t/t_funccov_basic.v +++ /dev/null @@ -1,25 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// This file ONLY is placed under the Creative Commons Public Domain -// SPDX-FileCopyrightText: 2026 Matthew Ballance -// SPDX-License-Identifier: CC0-1.0 - -// Test basic functional coverage infrastructure - -module t; - /* verilator lint_off UNSIGNED */ - int addr; - int cmd; - - // For now, this is just a placeholder until parser support is added - // We'll test the runtime infrastructure directly from C++ - - initial begin - addr = 10; - cmd = 1; - $display("Test placeholder for functional coverage"); - $write("*-* All Finished *-*\n"); - $finish; - end - -endmodule diff --git a/test_regress/t/t_funccov_basic_main.cpp b/test_regress/t/t_funccov_basic_main.cpp deleted file mode 100644 index 37e2f92f6..000000000 --- a/test_regress/t/t_funccov_basic_main.cpp +++ /dev/null @@ -1,112 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test main for functional coverage -// -// 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 Matthew Ballance -// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 - -#include "verilated.h" -#include "verilated_funccov.h" -#include VM_PREFIX_INCLUDE - -#include -#include - -// Test the functional coverage runtime infrastructure -void testFuncCovInfrastructure() { - std::cout << "Testing functional coverage infrastructure..." << std::endl; - - // Create a covergroup - VerilatedCovergroup cg("test_cg"); - - // Create a coverpoint with automatic bins - auto* cp_addr = new VerilatedCoverpoint{"cp_addr"}; - cp_addr->addBin(new VerilatedCoverRangeBin{"low", 0, 127}); - cp_addr->addBin(new VerilatedCoverRangeBin{"high", 128, 255}); - cg.addCoverpoint(cp_addr); - - // Create another coverpoint - auto* cp_cmd = new VerilatedCoverpoint{"cp_cmd"}; - cp_cmd->addBin(new VerilatedCoverRangeBin{"read", 0, 0}); - cp_cmd->addBin(new VerilatedCoverRangeBin{"write", 1, 1}); - cg.addCoverpoint(cp_cmd); - - // Create a cross coverage - auto* cross = new VerilatedCoverCross{"cross_cmd_addr"}; - cross->addCoverpoint(cp_addr); - cross->addCoverpoint(cp_cmd); - cg.addCross(cross); - - // Sample some values - std::cout << "Sampling values..." << std::endl; - cp_addr->sample(10); // low bin - cp_cmd->sample(0); // read bin - cross->sample({10, 0}); - - cp_addr->sample(200); // high bin - cp_cmd->sample(1); // write bin - cross->sample({200, 1}); - - cp_addr->sample(50); // low bin again - cp_cmd->sample(0); // read bin again - cross->sample({50, 0}); - - // Check coverage - double addr_cov = cp_addr->getCoverage(); - double cmd_cov = cp_cmd->getCoverage(); - double cross_cov = cross->getCoverage(); - double cg_cov = cg.get_coverage(); - - std::cout << "cp_addr coverage: " << addr_cov << "%" << std::endl; - std::cout << "cp_cmd coverage: " << cmd_cov << "%" << std::endl; - std::cout << "cross coverage: " << cross_cov << "%" << std::endl; - std::cout << "Covergroup coverage: " << cg_cov << "%" << std::endl; - - // Verify results - if (addr_cov != 100.0) { - std::cerr << "ERROR: Expected addr coverage 100%, got " << addr_cov << std::endl; - exit(1); - } - if (cmd_cov != 100.0) { - std::cerr << "ERROR: Expected cmd coverage 100%, got " << cmd_cov << std::endl; - exit(1); - } - // Cross coverage should be 50% (2 out of 4 possible cross products covered) - if (cross_cov < 49.9 || cross_cov > 50.1) { - std::cerr << "ERROR: Expected cross coverage ~50%, got " << cross_cov << std::endl; - exit(1); - } - // Overall covergroup coverage is weighted average of all components - // (100 + 100 + 50) / 3 = 83.33% - if (cg_cov < 83.0 || cg_cov > 84.0) { - std::cerr << "ERROR: Expected covergroup coverage ~83.33%, got " << cg_cov << std::endl; - exit(1); - } - - std::cout << "Functional coverage infrastructure test PASSED" << std::endl; -} - -int main(int argc, char** argv) { - // Standard Verilator setup - const std::unique_ptr contextp{new VerilatedContext}; - contextp->commandArgs(argc, argv); - - const std::unique_ptr topp{new VM_PREFIX{contextp.get()}}; - - // Test functional coverage infrastructure - testFuncCovInfrastructure(); - - // Run the Verilog simulation briefly - contextp->timeInc(1); - topp->eval(); - - // Check for finish - if (!contextp->gotFinish()) { - VL_PRINTF("%%Error: main.cpp didn't finish\n"); - exit(1); - } - - std::cout << "*-* All Finished *-*" << std::endl; - return 0; -} diff --git a/test_regress/t/t_verilated_all.py b/test_regress/t/t_verilated_all.py index 3f9d30d2e..28cd6b097 100755 --- a/test_regress/t/t_verilated_all.py +++ b/test_regress/t/t_verilated_all.py @@ -44,8 +44,7 @@ for dfile in test.glob_some(test.obj_dir + "/*.d"): hit[filename] = True for filename in sorted(hit.keys()): - if (not hit[filename] and filename != "verilated_funccov.h" - and not re.search(r'_sc', filename) and not re.search(r'_fst', filename) + if (not hit[filename] and not re.search(r'_sc', filename) and not re.search(r'_fst', filename) and not re.search(r'_saif', filename) and not re.search(r'_thread', filename) and (not re.search(r'_timing', filename) or test.have_coroutines)): test.error("Include file not covered by t_verilated_all test: ", filename)