From a7e6efb4c031560b0f3769c404243ec09991e275 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 27 Sep 2025 20:54:26 -0400 Subject: [PATCH] Internals: Some prep from branch towards multitrace (#5813 prep) --- src/V3EmitCImp.cpp | 8 ++-- src/V3EmitCModel.cpp | 7 ++-- src/V3EmitCSyms.cpp | 5 ++- src/V3Global.cpp | 3 +- src/V3Options.cpp | 63 +++++++++++++++++++++------- src/V3Options.h | 58 +++++++------------------ test_regress/t/t_trace_multi_bad.out | 3 ++ test_regress/t/t_trace_multi_bad.py | 18 ++++++++ test_regress/t/t_trace_multi_bad.v | 9 ++++ 9 files changed, 106 insertions(+), 68 deletions(-) create mode 100644 test_regress/t/t_trace_multi_bad.out create mode 100755 test_regress/t/t_trace_multi_bad.py create mode 100644 test_regress/t/t_trace_multi_bad.v diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index ac64dfdad..b6efbbcb1 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -664,7 +664,8 @@ class EmitCTrace final : EmitCFunc { "IPTION: Verilator output: Tracing implementation internals\n"); // Includes - puts("#include \"" + v3Global.opt.traceSourceLang() + ".h\"\n"); + for (const string& base : v3Global.opt.traceSourceLangs()) + puts("#include \"" + base + ".h\"\n"); puts("#include \"" + EmitCUtil::symClassName() + ".h\"\n"); puts("\n"); } @@ -693,7 +694,8 @@ class EmitCTrace final : EmitCFunc { "IPTION: Verilator output: Tracing declarations\n"); // Includes - typesFp()->puts("#include \"" + v3Global.opt.traceSourceLang() + ".h\"\n"); + for (const string& base : v3Global.opt.traceSourceLangs()) + typesFp()->puts("#include \"" + base + ".h\"\n"); typesFp()->puts("\n"); typesFp()->puts("\nvoid " + EmitCUtil::prefixNameProtect(m_modp) + "__" @@ -860,7 +862,7 @@ class EmitCTrace final : EmitCFunc { int emitTraceDeclDType(AstNodeDType* nodep) { // Return enum number or -1 for none - if (v3Global.opt.traceFormat().fst()) { + if (v3Global.opt.traceEnabledFst()) { // Skip over refs-to-refs, but stop before final ref so can get data type name // Alternatively back in V3Width we could push enum names from upper typedefs if (AstEnumDType* const enump = VN_CAST(nodep->skipRefToEnump(), EnumDType)) { diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp index b425dabe8..5de7f3b97 100644 --- a/src/V3EmitCModel.cpp +++ b/src/V3EmitCModel.cpp @@ -82,7 +82,7 @@ class EmitCModel final : public EmitCFunc { puts("\n"); puts("class " + EmitCUtil::symClassName() + ";\n"); puts("class " + EmitCUtil::prefixNameProtect(modp) + ";\n"); // For rootp pointer only - if (v3Global.opt.trace()) puts("class " + v3Global.opt.traceClassLang() + ";\n"); + for (const string& base : v3Global.opt.traceClassLangs()) puts("class " + base + ";\n"); emitModCUse(modp, VUseType::INT_FWD_CLASS); // Note: This is needed for cell forwarding puts("\n"); @@ -637,9 +637,8 @@ class EmitCModel final : public EmitCFunc { puts("\n"); puts("#include \"" + EmitCUtil::pchClassName() + ".h\"\n"); - if (v3Global.opt.trace()) { - puts("#include \"" + v3Global.opt.traceSourceLang() + ".h\"\n"); - } + for (const string& base : v3Global.opt.traceSourceLangs()) + puts("#include \"" + base + ".h\"\n"); emitConstructorImplementation(modp); emitDestructorImplementation(); diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index b1cb2e428..b92daaa72 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -416,7 +416,8 @@ void EmitCSyms::emitSymHdr() { ofp()->putsIntTopInclude(); puts("#include \"verilated.h\"\n"); if (v3Global.needTraceDumper()) { - puts("#include \"" + v3Global.opt.traceSourceLang() + ".h\"\n"); + for (const string& base : v3Global.opt.traceSourceLangs()) + puts("#include \"" + base + ".h\"\n"); } if (v3Global.opt.usesProfiler()) puts("#include \"verilated_profiler.h\"\n"); @@ -747,7 +748,7 @@ void EmitCSyms::emitSymImp() { puts("if (VL_UNLIKELY(!__Vm_dumperp)) {\n"); puts("__Vm_dumperp = new " + v3Global.opt.traceClassLang() + "();\n"); puts("__Vm_modelp->trace(__Vm_dumperp, 0, 0);\n"); - puts("std::string dumpfile = _vm_contextp__->dumpfileCheck();\n"); + puts("const std::string dumpfile = _vm_contextp__->dumpfileCheck();\n"); puts("__Vm_dumperp->open(dumpfile.c_str());\n"); puts("__Vm_dumping = true;\n"); puts("}\n"); diff --git a/src/V3Global.cpp b/src/V3Global.cpp index 5c705fba9..8cbc03372 100644 --- a/src/V3Global.cpp +++ b/src/V3Global.cpp @@ -226,7 +226,8 @@ std::vector V3Global::verilatedCppFiles() { if (v3Global.opt.vpi()) result.emplace_back("verilated_vpi.cpp"); if (v3Global.opt.savable()) result.emplace_back("verilated_save.cpp"); if (v3Global.opt.coverage()) result.emplace_back("verilated_cov.cpp"); - if (v3Global.opt.trace()) result.emplace_back(v3Global.opt.traceSourceBase() + "_c.cpp"); + for (const string& base : v3Global.opt.traceSourceBases()) + result.emplace_back(base + "_c.cpp"); if (v3Global.usesProbDist()) result.emplace_back("verilated_probdist.cpp"); if (v3Global.usesTiming()) result.emplace_back("verilated_timing.cpp"); if (v3Global.useRandomizeMethods()) result.emplace_back("verilated_random.cpp"); diff --git a/src/V3Options.cpp b/src/V3Options.cpp index bb1a3ac37..c6888012f 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -477,6 +477,41 @@ void V3Options::decorations(FileLine* fl, const string& arg) { // --decorations } } +std::vector V3Options::traceClassBases() const VL_MT_SAFE { + std::vector result; + if (traceEnabledFst()) result.emplace_back("VerilatedFst"); + if (traceEnabledSaif()) result.emplace_back("VerilatedSaif"); + if (traceEnabledVcd()) result.emplace_back("VerilatedVcd"); + return result; +} +std::vector V3Options::traceClassLangs() const VL_MT_SAFE { + std::vector result; + for (auto& cbase : traceClassBases()) result.emplace_back(cbase + (systemC() ? "Sc" : "C")); + return result; +} +std::vector V3Options::traceSourceBases() const VL_MT_SAFE { + std::vector result; + if (traceEnabledFst()) result.emplace_back("verilated_fst"); + if (traceEnabledSaif()) result.emplace_back("verilated_saif"); + if (traceEnabledVcd()) result.emplace_back("verilated_vcd"); + return result; +} +std::vector V3Options::traceSourceLangs() const VL_MT_SAFE { + std::vector result = traceSourceBases(); + for (std::string& str : result) str += systemC() ? "_sc"s : "_c"s; + return result; +} +std::string V3Options::traceClassBase() const VL_MT_SAFE { + // Deprecated - Needs to be fixed to support multiple trace, issue #5813 + UASSERT(!traceClassBases().empty(), "Call traceClassBase only when trace() enabled"); + return traceClassBases().front(); +} +std::string V3Options::traceClassLang() const VL_MT_SAFE { + // Deprecated - Needs to be fixed to support multiple trace, issue #5813 + UASSERT(!traceClassBases().empty(), "Call traceClassLang only when trace() enabled"); + return traceClassLangs().front(); +} + //###################################################################### // File searching @@ -903,6 +938,14 @@ void V3Options::notify() VL_MT_DISABLED { m_main = false; } + if (trace() && !traceEnabledFst() && !traceEnabledSaif() && !traceEnabledVcd()) { + m_traceEnabledVcd = true; // No format, with --trace means wanted --trace-vcd + } + if (traceEnabledFst() || traceEnabledSaif() || traceEnabledVcd()) m_trace = true; + const int ntraces = traceEnabledFst() + traceEnabledSaif() + traceEnabledVcd(); + if (ntraces > 1) // Issue #5813 + cmdfl->v3error("Only one of --trace-fst, --trace-saif or --trace--vcd may be used"); + if (protectIds()) { if (allPublic()) { // We always call protect() on names, we don't check if public or not @@ -940,7 +983,7 @@ void V3Options::notify() VL_MT_DISABLED { if (trace()) { // With --trace-vcd, --trace-threads is ignored - if (traceFormat().vcd()) m_traceThreads = 1; + if (traceEnabledVcd()) m_traceThreads = 1; } UASSERT(!(useTraceParallel() && useTraceOffload()), @@ -1671,20 +1714,15 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, DECL_OPTION("-top", Set, &m_topModule); DECL_OPTION("-top-module", Set, &m_topModule); DECL_OPTION("-trace", OnOff, &m_trace); - DECL_OPTION("-trace-saif", CbCall, [this]() { - m_trace = true; - m_traceFormat = TraceFormat::SAIF; - }); + DECL_OPTION("-trace-saif", CbCall, [this]() { m_traceEnabledSaif = true; }); DECL_OPTION("-trace-coverage", OnOff, &m_traceCoverage); DECL_OPTION("-trace-depth", Set, &m_traceDepth); DECL_OPTION("-trace-fst", CbCall, [this]() { - m_trace = true; - m_traceFormat = TraceFormat::FST; + m_traceEnabledFst = true; addLdLibs("-lz"); }); DECL_OPTION("-trace-fst-thread", CbCall, [this, fl]() { - m_trace = true; - m_traceFormat = TraceFormat::FST; + m_traceEnabledFst = true; addLdLibs("-lz"); fl->v3warn(DEPRECATED, "Option --trace-fst-thread is deprecated. " "Use --trace-fst with --trace-threads > 0."); @@ -1701,10 +1739,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, }); DECL_OPTION("-no-trace-top", Set, &m_noTraceTop); DECL_OPTION("-trace-underscore", OnOff, &m_traceUnderscore); - DECL_OPTION("-trace-vcd", CbCall, [this]() { - m_trace = true; - m_traceFormat = TraceFormat::VCD; - }); + DECL_OPTION("-trace-vcd", CbCall, [this]() { m_traceEnabledVcd = true; }); DECL_OPTION("-U", CbPartialMatch, &V3PreShell::undef); DECL_OPTION("-underline-zero", OnOff, &m_underlineZero); // Deprecated @@ -2127,8 +2162,6 @@ void V3Options::showVersion(bool verbose) { V3Options::V3Options() { m_impp = new V3OptionsImp; - m_traceFormat = TraceFormat::VCD; - m_makeDir = "obj_dir"; m_unusedRegexp = "*unused*"; m_xAssign = "fast"; diff --git a/src/V3Options.h b/src/V3Options.h index d57dce68e..61a76798e 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -159,35 +159,6 @@ inline std::ostream& operator<<(std::ostream& os, const VTimescale& rhs) { // ###################################################################### -class TraceFormat final { -public: - enum en : uint8_t { VCD = 0, FST, SAIF } m_e; - // cppcheck-suppress noExplicitConstructor - constexpr TraceFormat(en _e = VCD) - : m_e{_e} {} - explicit TraceFormat(int _e) - : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning - constexpr operator en() const { return m_e; } - bool fst() const { return m_e == FST; } - bool saif() const { return m_e == SAIF; } - bool vcd() const { return m_e == VCD; } - string classBase() const VL_MT_SAFE { - static const char* const names[] = {"VerilatedVcd", "VerilatedFst", "VerilatedSaif"}; - return names[m_e]; - } - string sourceName() const VL_MT_SAFE { - static const char* const names[] = {"verilated_vcd", "verilated_fst", "verilated_saif"}; - return names[m_e]; - } -}; -constexpr bool operator==(const TraceFormat& lhs, const TraceFormat& rhs) { - return lhs.m_e == rhs.m_e; -} -constexpr bool operator==(const TraceFormat& lhs, TraceFormat::en rhs) { return lhs.m_e == rhs; } -constexpr bool operator==(TraceFormat::en lhs, const TraceFormat& rhs) { return lhs == rhs.m_e; } - -// ###################################################################### - // Information given by --hierarchical-block option class V3HierarchicalBlockOption final { public: @@ -321,6 +292,9 @@ private: VOptionBool m_timing; // main switch: --timing bool m_trace = false; // main switch: --trace bool m_traceCoverage = false; // main switch: --trace-coverage + bool m_traceEnabledFst = false; // main switch: --trace-fst + bool m_traceEnabledSaif = false; // main switch: --trace-saif + bool m_traceEnabledVcd = false; // main switch: --trace-vcd bool m_traceParams = true; // main switch: --trace-params bool m_traceStructs = false; // main switch: --trace-structs bool m_noTraceTop = false; // main switch: --no-trace-top @@ -366,7 +340,6 @@ private: VTimescale m_timeOverridePrec; // main switch: --timescale-override VTimescale m_timeOverrideUnit; // main switch: --timescale-override int m_traceDepth = 0; // main switch: --trace-depth - TraceFormat m_traceFormat; // main switch: --trace or --trace-fst int m_traceMaxArray = 32; // main switch: --trace-max-array int m_traceMaxWidth = 256; // main switch: --trace-max-width int m_traceThreads = 0; // main switch: --trace-threads @@ -565,6 +538,9 @@ public: VOptionBool timing() const { return m_timing; } bool trace() const { return m_trace; } bool traceCoverage() const { return m_traceCoverage; } + bool traceEnabledFst() const { return m_traceEnabledFst; } + bool traceEnabledSaif() const { return m_traceEnabledSaif; } + bool traceEnabledVcd() const { return m_traceEnabledVcd; } bool traceParams() const { return m_traceParams; } bool traceStructs() const { return m_traceStructs; } bool traceUnderscore() const { return m_traceUnderscore; } @@ -638,18 +614,14 @@ public: VTimescale timeComputePrec(const VTimescale& flag) const; VTimescale timeComputeUnit(const VTimescale& flag) const; int traceDepth() const { return m_traceDepth; } - TraceFormat traceFormat() const { return m_traceFormat; } - bool traceEnabledFst() const { return trace() && traceFormat().fst(); } - bool traceEnabledSaif() const { return trace() && traceFormat().saif(); } - bool traceEnabledVcd() const { return trace() && traceFormat().vcd(); } int traceMaxArray() const { return m_traceMaxArray; } int traceMaxWidth() const { return m_traceMaxWidth; } int traceThreads() const { return m_traceThreads; } - bool useTraceOffload() const { return trace() && traceFormat().fst() && traceThreads() > 1; } + bool useTraceOffload() const { return trace() && traceEnabledFst() && traceThreads() > 1; } bool useTraceParallel() const { - return trace() && traceFormat().vcd() && (threads() > 1 || hierChild() > 1); + return trace() && traceEnabledVcd() && (threads() > 1 || hierChild() > 1); } - bool useFstWriterThread() const { return traceThreads() && traceFormat().fst(); } + bool useFstWriterThread() const { return traceThreads() && traceEnabledFst(); } unsigned vmTraceThreads() const { return useTraceParallel() ? threads() : useTraceOffload() ? 1 : 0; } @@ -762,12 +734,12 @@ public: bool fTaskifyAll() const { return m_fTaskifyAll; } bool fVarSplit() const { return m_fVarSplit; } - string traceClassBase() const VL_MT_SAFE { return m_traceFormat.classBase(); } - string traceClassLang() const { return m_traceFormat.classBase() + (systemC() ? "Sc" : "C"); } - string traceSourceBase() const { return m_traceFormat.sourceName(); } - string traceSourceLang() const VL_MT_SAFE { - return m_traceFormat.sourceName() + (systemC() ? "_sc" : "_c"); - } + std::string traceClassBase() const VL_MT_SAFE; // Deprecated + std::string traceClassLang() const VL_MT_SAFE; // Deprecated + std::vector traceClassBases() const VL_MT_SAFE; + std::vector traceClassLangs() const VL_MT_SAFE; + std::vector traceSourceBases() const VL_MT_SAFE; + std::vector traceSourceLangs() const VL_MT_SAFE; bool hierarchical() const { return m_hierarchical; } int hierChild() const VL_MT_SAFE { return m_hierChild; } diff --git a/test_regress/t/t_trace_multi_bad.out b/test_regress/t/t_trace_multi_bad.out new file mode 100644 index 000000000..793d7a4b1 --- /dev/null +++ b/test_regress/t/t_trace_multi_bad.out @@ -0,0 +1,3 @@ +%Error: Only one of --trace-fst, --trace-saif or --trace--vcd may be used + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. +%Error: Exiting due to diff --git a/test_regress/t/t_trace_multi_bad.py b/test_regress/t/t_trace_multi_bad.py new file mode 100755 index 000000000..4d6bcd9ce --- /dev/null +++ b/test_regress/t/t_trace_multi_bad.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2025 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('vlt') + +test.lint(verilator_flags=['--trace-fst --trace-vcd'], + fails=True, + expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_trace_multi_bad.v b/test_regress/t/t_trace_multi_bad.v new file mode 100644 index 000000000..fbcbd7ce9 --- /dev/null +++ b/test_regress/t/t_trace_multi_bad.v @@ -0,0 +1,9 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; + initial $finish; +endmodule