From 5cddbd7fda48bdbf4f195a44204a31a8eb2916e4 Mon Sep 17 00:00:00 2001 From: Nikolay Puzanov Date: Wed, 22 Apr 2026 19:09:30 +0300 Subject: [PATCH] Fix tracing virtual interface member written from classes (#5044) (#7465) Track AstMemberSel writes through virtual interface refs and connect them to matching interface-member VarScopes, so class-driven interface clocks get proper VCD activity updates. Fixes #5044. --- src/V3Trace.cpp | 32 +++++++++++ test_regress/t/t_trace_vif_class_clk.py | 22 ++++++++ test_regress/t/t_trace_vif_class_clk.v | 45 ++++++++++++++++ test_regress/t/t_trace_vif_class_clk_multi.py | 22 ++++++++ test_regress/t/t_trace_vif_class_clk_multi.v | 53 +++++++++++++++++++ 5 files changed, 174 insertions(+) create mode 100644 test_regress/t/t_trace_vif_class_clk.py create mode 100644 test_regress/t/t_trace_vif_class_clk.v create mode 100644 test_regress/t/t_trace_vif_class_clk_multi.py create mode 100644 test_regress/t/t_trace_vif_class_clk_multi.v diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index e0471ff1c..a9b7b419b 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -47,6 +47,7 @@ #include "V3UniqueNames.h" #include +#include #include #include @@ -216,6 +217,9 @@ class TraceVisitor final : public VNVisitor { using ActCodeSet = std::set; // For activity set, what traces apply using TraceVec = std::multimap; + // Candidate interface-member VarScopes keyed by (interface type, member name) + std::map, std::vector> + m_ifaceMemberVscps; // METHODS @@ -1125,6 +1129,13 @@ class TraceVisitor final : public VNVisitor { if (nodep->isTop()) m_topModp = nodep; iterateChildren(nodep); } + void visit(AstVarScope* nodep) override { + if (!m_finding) { + if (const AstIface* const ifacep = nodep->varp()->sensIfacep()) { + m_ifaceMemberVscps[{ifacep, nodep->varp()->name()}].push_back(nodep); + } + } + } void visit(AstStmtExpr* nodep) override { if (!m_finding && !nodep->user2()) { if (AstCCall* const callp = VN_CAST(nodep->exprp(), CCall)) { @@ -1214,6 +1225,27 @@ class TraceVisitor final : public VNVisitor { } } } + void visit(AstMemberSel* nodep) override { + if (m_cfuncp && m_finding && nodep->access().isWriteOrRW()) { + AstIfaceRefDType* const dtypep + = VN_CAST(nodep->fromp()->dtypep()->skipRefp(), IfaceRefDType); + if (dtypep && dtypep->isVirtual()) { + const auto it = m_ifaceMemberVscps.find({dtypep->ifacep(), nodep->varp()->name()}); + if (it != m_ifaceMemberVscps.end()) { + V3GraphVertex* const funcVtxp = getCFuncVertexp(m_cfuncp); + for (AstVarScope* const vscp : it->second) { + V3GraphVertex* varVtxp = vscp->user1u().toGraphVertex(); + if (!varVtxp) { + varVtxp = new TraceVarVertex{&m_graph, vscp}; + vscp->user1p(varVtxp); + } + new V3GraphEdge{&m_graph, funcVtxp, varVtxp, 1}; + } + } + } + } + iterateChildren(nodep); + } //-------------------- void visit(AstNode* nodep) override { iterateChildren(nodep); } diff --git a/test_regress/t/t_trace_vif_class_clk.py b/test_regress/t/t_trace_vif_class_clk.py new file mode 100644 index 000000000..33e5bb7a9 --- /dev/null +++ b/test_regress/t/t_trace_vif_class_clk.py @@ -0,0 +1,22 @@ +#!/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('simulator') + +test.compile(verilator_flags2=['--binary --trace-vcd --timing']) + +test.execute() + +# Expect 5 posedges and 5 low samples in VCD for the class-driven interface clock. +test.file_grep_count(test.trace_filename, r'(?m)^1[!-~]$', 5) +test.file_grep_count(test.trace_filename, r'(?m)^0[!-~]$', 5) + +test.passes() diff --git a/test_regress/t/t_trace_vif_class_clk.v b/test_regress/t/t_trace_vif_class_clk.v new file mode 100644 index 000000000..6679b0ba9 --- /dev/null +++ b/test_regress/t/t_trace_vif_class_clk.v @@ -0,0 +1,45 @@ +// 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 + +`timescale 1ns/1ns +`define STRINGIFY(x) `"x`" + +interface clk_iface; + bit clk; +endinterface + +class clk_driver; + virtual clk_iface vif; + function new(virtual clk_iface vif); + this.vif = vif; + endfunction + + task run(); + vif.clk = 1'b0; + forever #5 vif.clk = ~vif.clk; + endtask +endclass + +module t; + clk_iface ci(); + clk_driver drv; + + int x = 0; + always @(posedge ci.clk) x = x + 1; + + initial begin + drv = new(ci); + drv.run(); + end + + initial begin + $dumpfile(`STRINGIFY(`TEST_DUMPFILE)); + $dumpvars(0, t); + repeat (5) @(posedge ci.clk); + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_trace_vif_class_clk_multi.py b/test_regress/t/t_trace_vif_class_clk_multi.py new file mode 100644 index 000000000..47372212b --- /dev/null +++ b/test_regress/t/t_trace_vif_class_clk_multi.py @@ -0,0 +1,22 @@ +#!/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('simulator') + +test.compile(verilator_flags2=['--binary --trace-vcd --timing']) + +test.execute() + +# Two class-driven clocks toggle in lockstep: 10 highs and 10 lows total. +test.file_grep_count(test.trace_filename, r'(?m)^1[!-~]$', 10) +test.file_grep_count(test.trace_filename, r'(?m)^0[!-~]$', 10) + +test.passes() diff --git a/test_regress/t/t_trace_vif_class_clk_multi.v b/test_regress/t/t_trace_vif_class_clk_multi.v new file mode 100644 index 000000000..716d88fed --- /dev/null +++ b/test_regress/t/t_trace_vif_class_clk_multi.v @@ -0,0 +1,53 @@ +// 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 + +`timescale 1ns/1ns +`define STRINGIFY(x) `"x`" + +interface clk_iface; + bit clk; +endinterface + +class clk_driver; + virtual clk_iface vif; + function new(virtual clk_iface vif); + this.vif = vif; + endfunction + + task run(); + vif.clk = 1'b0; + forever #5 vif.clk = ~vif.clk; + endtask +endclass + +module t; + clk_iface ci0(); + clk_iface ci1(); + clk_driver drv0; + clk_driver drv1; + + int x0 = 0; + int x1 = 0; + always @(posedge ci0.clk) x0 = x0 + 1; + always @(posedge ci1.clk) x1 = x1 + 1; + + initial begin + drv0 = new(ci0); + drv1 = new(ci1); + fork + drv0.run(); + drv1.run(); + join_none + end + + initial begin + $dumpfile(`STRINGIFY(`TEST_DUMPFILE)); + $dumpvars(0, t); + repeat (5) @(posedge ci0.clk); + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule