From 7e3cd8af655c6d9425c4500afcd48e74736c6bc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Chmiel?= Date: Thu, 8 Jan 2026 21:10:19 +0100 Subject: [PATCH] Fix tracing signals with escaped dots in names (#6897) --- src/V3TraceDecl.cpp | 17 +++++++++------- test_regress/t/t_var_escape_noinl.py | 30 ++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 7 deletions(-) create mode 100755 test_regress/t/t_var_escape_noinl.py diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp index 9a8ad49b2..8cc34b198 100644 --- a/src/V3TraceDecl.cpp +++ b/src/V3TraceDecl.cpp @@ -262,15 +262,17 @@ class TraceDeclVisitor final : public VNVisitor { // Find the scope for the path. As we are working based on cell names, // it is possible there is no corresponding scope (e.g.: for an empty // module). - const auto it = m_pathToScopep.find(path); + const auto it = m_pathToScopep.find(AstNode::prettyName(path)); if (it != m_pathToScopep.end()) { const AstScope* const scopep = it->second; FileLine* const flp = placeholderp->fileline(); // Pick up the last path element. The prefixes have already been pushed - // when building the initialization functions - const size_t pos = path.rfind('.'); - const std::string name = path.substr(pos == string::npos ? 0 : pos + 1); + // when building the initialization. + // We still need to find __DOT__ as cell names may have such. + const std::string dot = "__DOT__"; + const size_t pos = path.rfind(dot); + const std::string name = path.substr(pos == string::npos ? 0 : pos + dot.size()); // Compute the type of the scope being fixed up const AstCell* const cellp = scopep->aboveCellp(); @@ -280,7 +282,8 @@ class TraceDeclVisitor final : public VNVisitor { : VTracePrefixType::SCOPE_MODULE; // Push the scope prefix - AstNodeStmt* const pushp = new AstTracePushPrefix{flp, name, scopeType}; + AstNodeStmt* const pushp + = new AstTracePushPrefix{flp, AstNode::prettyName(name), scopeType}; // Call the initialization functions for the scope for (AstCFunc* const subFuncp : m_scopeInitFuncps.at(scopep)) { @@ -308,7 +311,7 @@ class TraceDeclVisitor final : public VNVisitor { const AstScope* const parentp = std::get<0>(item); const AstCell* const cellp = std::get<1>(item); AstNodeStmt* const placeholderp = std::get<2>(item); - const std::string path = AstNode::prettyName(parentp->name() + "." + cellp->name()); + const std::string path = parentp->name() + "__DOT__" + cellp->name(); fixupPlaceholder(path, placeholderp); } @@ -316,7 +319,7 @@ class TraceDeclVisitor final : public VNVisitor { for (const auto& item : m_ifaceRefInitPlaceholders) { const AstVarScope* const vscp = std::get<0>(item); AstNodeStmt* const placeholderp = std::get<1>(item); - const std::string path = vscp->prettyName(); + const std::string path = vscp->scopep()->name() + "__DOT__" + vscp->varp()->name(); fixupPlaceholder(path, placeholderp); } } diff --git a/test_regress/t/t_var_escape_noinl.py b/test_regress/t/t_var_escape_noinl.py new file mode 100755 index 000000000..dc717ba7e --- /dev/null +++ b/test_regress/t/t_var_escape_noinl.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2026 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') +test.top_filename = "t/t_var_escape.v" +test.golden_filename = "t/t_var_escape.out" + +test.compile( + # Access is so we can dump waves + v_flags2=['-trace' if test.vlt_all else ' +access+rwc', '-fno-inline']) + +test.execute() + +if test.vlt_all: + test.file_grep(test.trace_filename, r'\$enddefinitions') + sigre = re.escape("bra[ket]slash/dash-colon:9") + test.file_grep(test.trace_filename, sigre) + test.file_grep(test.trace_filename, r' other\.cyc ') + test.file_grep(test.trace_filename, r' module mod\.with_dot ') + test.vcd_identical(test.trace_filename, test.golden_filename) + +test.passes()