Fix %m in hierarchical models (#8575)

The model of a hierarchical block, or of a --lib-create library, is
named after the %m of its instance in the parent model, but %m within it
also used to include the name of its top module (l2-name within the
partition), adding an extra level per block. %m now matches across
non-hierarchical, --hierarchical and manual --lib-create builds.

before: top.t.u_sub.sub.u_leaf.leaf
after:  top.t.u_sub.u_leaf
This commit is contained in:
Geza Lore
2026-10-02 14:20:41 +01:00
committed by GitHub
parent 93e9660ea5
commit e4cc6cadca
5 changed files with 135 additions and 2 deletions
+13 -1
View File
@@ -57,6 +57,8 @@ class ScopeVisitor final : public VNVisitor {
AstCell* m_aboveCellp = nullptr; // Cell that instantiates this module
AstScope* m_aboveScopep = nullptr; // Scope that instantiates this scope
bool m_last = false; // Scoping the last instantiation of the current module
// The name length of the scope of the library top module instance, while within it
size_t m_libTopNameLen = 0;
std::unordered_map<AstNodeModule*, AstScope*>
m_classOrPackageScopes; // Scopes for each class or package
@@ -136,12 +138,18 @@ class ScopeVisitor final : public VNVisitor {
cleanupVarRefs();
}
void visit(AstNodeModule* nodep) override {
VL_RESTORER(m_libTopNameLen);
// Create required blocks and add to module
string scopename;
if (!m_aboveScopep) {
scopename = "TOP";
} else {
scopename = m_aboveScopep->name() + "." + m_aboveCellp->name();
// The top module is the only module directly under 'TOP'
if (!v3Global.opt.libCreate().empty() && m_aboveScopep->isTop()
&& VN_IS(nodep, Module)) {
m_libTopNameLen = scopename.size();
}
}
UINFO(4, " MOD AT " << scopename << " " << nodep);
@@ -318,7 +326,11 @@ class ScopeVisitor final : public VNVisitor {
}
void visit(AstScopeName* nodep) override {
// If there's a %m in the display text, we add a special node that will contain the name()
const string prefix = "__DOT__"s + m_scopep->name();
std::string scopeName = m_scopep->name();
// Drop the "l2-name" (name of the top module) for library builds, otherwise
// would get "top.u_lib.lib.foo" instead of correct hierarchical path "top.u_lib.foo"
if (m_libTopNameLen) scopeName = "TOP" + scopeName.substr(m_libTopNameLen);
const string prefix = "__DOT__"s + scopeName;
// TOP and above will be the user's name().
// Note 'TOP.' is stripped by scopePrettyName
// To keep correct visual order, must add before existing
+9 -1
View File
@@ -391,13 +391,21 @@ class TraceDeclVisitor final : public VNVisitor {
void fixupLibStub(const std::string& path, AstNodeStmt* placeholderp) {
FileLine* const flp = placeholderp->fileline();
// The library instance's model is named after its %m within the parent model,
// which does not include the "l2-name" (top module) of the library
std::string name = AstNode::prettyName(path);
if (!v3Global.opt.libCreate().empty()) {
const std::string topPrefix = v3Global.rootp()->traceLibTopName() + ".";
if (VString::startsWith(name, topPrefix)) name = name.substr(topPrefix.size());
}
// Call the initialization function for the library instance
AstCStmt* const initp = new AstCStmt{flp};
initp->add("{\n");
initp->add("std::string __VlibName = vlSymsp->name();\n");
initp->add("if (!__VlibName.empty()) __VlibName += '.';\n");
initp->add("__VlibName += ");
initp->add(new AstConst{flp, AstConst::String{}, AstNode::prettyName(path)});
initp->add(new AstConst{flp, AstConst::String{}, name});
initp->add(";\n");
initp->add("tracep->initLib(__VlibName);\n");
initp->add("}\n");
+6
View File
@@ -0,0 +1,6 @@
[1] sub: top.t.u_sub
[2] sub begin: top.t.u_sub.blk
[3] sub task: top.t.u_sub.show
[4] leaf: top.t.u_sub.u_leaf
[5] leaf begin: top.t.u_sub.u_leaf.blk
*-* All Finished *-*
+53
View File
@@ -0,0 +1,53 @@
#!/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_all')
# Build 3 flavours: flat, --hierarchical, manual --lib-create, all should be the same
def lib_create(name, extra_flags):
test.vm_prefix = "Vlib_" + name
# Single threaded, as the library is evaluated within the threads of the model using it
test.compile(make_main=False,
threads=1,
verilator_make_gmake=False,
verilator_flags2=extra_flags + ["--lib-create", name, "--top-module", name])
test.run(logfile=test.obj_dir + "/" + test.vm_prefix + "_make.log",
cmd=[
os.environ["MAKE"], "-C", test.obj_dir, "-f", test.vm_prefix + ".mk",
"lib" + name + ".a"
])
lib_create("leaf", [])
lib_create("sub", ["+define+USE_LIB_LEAF", test.obj_dir + "/leaf.sv", "libleaf.a"])
def compile_model(prefix, extra_flags):
test.vm_prefix = prefix
# Each model needs its own main, as they share the object directory
test.main_filename = test.obj_dir + "/" + test.vm_prefix + "__main.cpp"
test.compile(verilator_flags2=extra_flags)
compile_model("Vnonh", [])
compile_model("Vhier", ["--hierarchical"])
compile_model("Vlibs", [
"+define+USE_LIB_LEAF", "+define+USE_LIB_SUB", test.obj_dir + "/sub.sv", "libsub.a",
"libleaf.a"
])
# Hierarchical, non-hierarchical and library builds must all print the same %m
for prefix in ("Vnonh", "Vhier", "Vlibs"):
test.execute(executable=test.obj_dir + "/" + prefix, expect_filename=test.golden_filename)
test.passes()
+54
View File
@@ -0,0 +1,54 @@
// 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
module t (
input clk
);
int cyc = 0;
always @(posedge clk) begin
cyc <= cyc + 1;
if (cyc == 9) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
sub u_sub (.clk(clk), .cyc(cyc));
endmodule
`ifndef USE_LIB_SUB
module sub (
input clk,
input int cyc
);
/*verilator hier_block*/
task automatic show();
$display("[%0d] sub task: %m", cyc);
endtask
always @(posedge clk) begin
if (cyc == 1) $display("[%0d] sub: %m", cyc);
if (cyc == 2) begin : blk
$display("[%0d] sub begin: %m", cyc);
end
if (cyc == 3) show();
end
leaf u_leaf (.clk(clk), .cyc(cyc));
endmodule
`endif
`ifndef USE_LIB_LEAF
module leaf (
input clk,
input int cyc
);
/*verilator hier_block*/
always @(posedge clk) begin
if (cyc == 4) $display("[%0d] leaf: %m", cyc);
if (cyc == 5) begin : blk
$display("[%0d] leaf begin: %m", cyc);
end
end
endmodule
`endif