mirror of
https://github.com/verilator/verilator.git
synced 2026-10-02 16:13:34 +02:00
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:
+13
-1
@@ -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
@@ -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");
|
||||
|
||||
@@ -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 *-*
|
||||
Executable
+53
@@ -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()
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user