diff --git a/Changes b/Changes index 16bc08ed5..0a8c09d3c 100644 --- a/Changes +++ b/Changes @@ -41,6 +41,7 @@ Verilator 5.045 devel * Fix error when calling non-static method (#6916). [Artur Bieniek, Antmicro Ltd.] * Fix memory leak in vpi_put_value and vpi_get_value (#6917). [Christian Hecken] * Fix segfault after assignment pattern XOR error (#6928) (#6931). [emmettifelts] +* Fix `--top-module` with underscores (#6940). [Christopher Batten] Verilator 5.044 2026-01-01 diff --git a/src/V3HierBlock.cpp b/src/V3HierBlock.cpp index 3dff65f84..11e96a2b6 100644 --- a/src/V3HierBlock.cpp +++ b/src/V3HierBlock.cpp @@ -164,7 +164,8 @@ VStringList V3HierBlock::commandArgs(bool forMkJson) const { if (!forMkJson) { opts.push_back(" --prefix " + prefix); opts.push_back(" --mod-prefix " + prefix); - opts.push_back(" --top-module " + modp()->name()); + // Similar to --top-module but need to use encoded name(), not prettyName() + opts.push_back(" --top-module-encoded " + modp()->name()); } opts.push_back(" --lib-create " + modp()->name()); // possibly mangled name if (v3Global.opt.protectKeyProvided()) diff --git a/src/V3LinkCells.cpp b/src/V3LinkCells.cpp index ec493696a..1d4c7f0e8 100644 --- a/src/V3LinkCells.cpp +++ b/src/V3LinkCells.cpp @@ -429,8 +429,19 @@ class LinkCellsVisitor final : public VNVisitor { } } if (v3Global.opt.topModule() != "" && !m_topVertexp) { - v3error("Specified --top-module '" << v3Global.opt.topModule() - << "' was not found in design."); + VSpellCheck spell; + for (V3GraphVertex& vtx : m_graph.vertices()) { + if (const LinkCellsVertex* const vvertexp = vtx.cast()) { + AstNodeModule* const modp = vvertexp->modp(); + if (VN_IS(modp, Module)) spell.pushCandidate(modp->prettyName()); + } + } + const string suggest + = spell.bestCandidateMsg(AstNode::prettyName(v3Global.opt.topModule())); + v3error("Specified --top-module '" + << AstNode::prettyName(v3Global.opt.topModule()) + << "' was not found in design.\n" + << (suggest.empty() ? "" : V3Error::warnMore() + suggest)); } } void visit(AstConstPool* nodep) override {} @@ -473,8 +484,9 @@ class LinkCellsVisitor final : public VNVisitor { UINFO(2, "Link --top-module: " << nodep); nodep->inLibrary(false); // Safer to make sure it doesn't disappear } - if (v3Global.opt.topModule() == "" ? nodep->inLibrary() // Library cells are lower - : !topMatch) { // Any non-specified module is lower + if (v3Global.opt.topModule().empty() + ? nodep->inLibrary() // Library cells are lower + : !topMatch) { // Any non-specified module is lower // Put under a fake vertex so that the graph ranking won't indicate // this is a top level module if (!m_libVertexp) m_libVertexp = new LibraryVertex{&m_graph}; diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 381fe4c90..ea7f42a20 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -1789,8 +1789,11 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, } }); DECL_OPTION("-timing", OnOff, &m_timing); - DECL_OPTION("-top", Set, &m_topModule); - DECL_OPTION("-top-module", Set, &m_topModule); + DECL_OPTION("-top", CbVal, + [this](const std::string& flag) { m_topModule = AstNode::encodeName(flag); }); + DECL_OPTION("-top-module", CbVal, + [this](const std::string& flag) { m_topModule = AstNode::encodeName(flag); }); + DECL_OPTION("-top-module-encoded", Set, &m_topModule).undocumented(); DECL_OPTION("-trace", OnOff, &m_trace); DECL_OPTION("-trace-saif", CbCall, [this]() { m_traceEnabledSaif = true; }); DECL_OPTION("-trace-coverage", OnOff, &m_traceCoverage); diff --git a/src/V3Options.h b/src/V3Options.h index cabbcbec7..a5f06c38f 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -668,7 +668,7 @@ public: // Not just called protectKey() to avoid bugs of not using protectKeyDefaulted() bool protectKeyProvided() const { return !m_protectKey.empty(); } string protectKeyDefaulted() VL_MT_SAFE; // Set default key if not set by user - string topModule() const { return m_topModule; } + string topModule() const { return m_topModule; } // As AstNode::encodeName() bool noTraceTop() const { return m_noTraceTop; } string unusedRegexp() const { return m_unusedRegexp; } string waiverOutput() const { return m_waiverOutput; } diff --git a/test_regress/t/t_flag_topmodule_bad3.out b/test_regress/t/t_flag_topmodule_bad3.out new file mode 100644 index 000000000..324be4de9 --- /dev/null +++ b/test_regress/t/t_flag_topmodule_bad3.out @@ -0,0 +1,4 @@ +%Error: Specified --top-module 'notfound' was not found in design. + ... Suggested alternative: 'notfound1' + ... 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_flag_topmodule_bad3.py b/test_regress/t/t_flag_topmodule_bad3.py new file mode 100755 index 000000000..11018c930 --- /dev/null +++ b/test_regress/t/t_flag_topmodule_bad3.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 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(fails=True, v_flags2=["--top-module notfound"], expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_flag_topmodule_bad3.v b/test_regress/t/t_flag_topmodule_bad3.v new file mode 100644 index 000000000..2540d03d8 --- /dev/null +++ b/test_regress/t/t_flag_topmodule_bad3.v @@ -0,0 +1,11 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2026 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module notfound1; +endmodule + +module notfound2; +endmodule diff --git a/test_regress/t/t_mod_topmodule__underunder.py b/test_regress/t/t_mod_topmodule__underunder.py new file mode 100755 index 000000000..f6f795c3a --- /dev/null +++ b/test_regress/t/t_mod_topmodule__underunder.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 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.compile(verilator_flags2=["--top-module t_mod_topmodule__underunder"]) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_mod_topmodule__underunder.v b/test_regress/t/t_mod_topmodule__underunder.v new file mode 100644 index 000000000..a496e04f4 --- /dev/null +++ b/test_regress/t/t_mod_topmodule__underunder.v @@ -0,0 +1,16 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This test verifies that a top-module can be specified which +// is instantiated beneath another module in the compiled source +// code. +// +// 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_mod_topmodule__underunder; + initial $finish; +endmodule + +module faketop; +endmodule