From b080950f76f95fae962b0edde006ab46cd9b28c3 Mon Sep 17 00:00:00 2001 From: Michael Bedford Taylor Date: Fri, 2 Oct 2026 10:23:56 -0700 Subject: [PATCH] Fix hierarchical library block source ordering (#8578) (#8579) --- src/V3EmitMkJson.cpp | 9 +--- src/V3HierBlock.cpp | 16 +++++-- src/V3HierBlock.h | 2 + test_regress/t/t_hier_block_libdir_pkg.py | 23 ++++++++++ test_regress/t/t_hier_block_libdir_pkg.v | 42 +++++++++++++++++++ test_regress/t/t_hier_block_libdir_pkg/blk.v | 14 +++++++ .../t/t_hier_block_libdir_pkg/blk_param.v | 17 ++++++++ .../t/t_hier_block_libdir_pkg/hier.vlt | 9 ++++ test_regress/t/t_hier_block_libdir_pkg/pkg.vh | 9 ++++ .../t/t_hier_block_libdir_pkg_cmake.py | 27 ++++++++++++ 10 files changed, 157 insertions(+), 11 deletions(-) create mode 100755 test_regress/t/t_hier_block_libdir_pkg.py create mode 100644 test_regress/t/t_hier_block_libdir_pkg.v create mode 100644 test_regress/t/t_hier_block_libdir_pkg/blk.v create mode 100644 test_regress/t/t_hier_block_libdir_pkg/blk_param.v create mode 100644 test_regress/t/t_hier_block_libdir_pkg/hier.vlt create mode 100644 test_regress/t/t_hier_block_libdir_pkg/pkg.vh create mode 100755 test_regress/t/t_hier_block_libdir_pkg_cmake.py diff --git a/src/V3EmitMkJson.cpp b/src/V3EmitMkJson.cpp index a63eed840..8993eaea4 100644 --- a/src/V3EmitMkJson.cpp +++ b/src/V3EmitMkJson.cpp @@ -127,11 +127,7 @@ class V3EmitMkJsonEmitter final { sources.emplace_back(makeDir + "/" + dependencyp->hierWrapperFilename(true)); } - const std::string vFile = hblockp->vFileIfNecessary(); - if (!vFile.empty()) sources.emplace_back(vFile); - - for (const VFileLibName& i : v3Global.opt.vFiles()) { - const std::string fname = i.filename(); + for (const string& fname : V3HierGraph::sourceFiles(hblockp->vFileIfNecessary())) { sources.emplace_back(V3Os::filenameSlashPath(V3Os::filenameRealPath(fname))); } @@ -159,8 +155,7 @@ class V3EmitMkJsonEmitter final { sources.emplace_back(makeDir + "/" + blockp->hierWrapperFilename(true)); } - for (const VFileLibName& i : v3Global.opt.vFiles()) { - const std::string fname = i.filename(); + for (const string& fname : V3HierGraph::sourceFiles()) { sources.emplace_back(V3Os::filenameSlashPath(V3Os::filenameRealPath(fname))); } diff --git a/src/V3HierBlock.cpp b/src/V3HierBlock.cpp index 0bb96054c..d4ca15822 100644 --- a/src/V3HierBlock.cpp +++ b/src/V3HierBlock.cpp @@ -112,11 +112,10 @@ static string V3HierParametersFileName(const string& prefix) { } static void V3HierWriteCommonInputs(const V3HierBlock* hblockp, std::ostream* of, bool forMkJson) { - string topModuleFile; - if (hblockp) topModuleFile = hblockp->vFileIfNecessary(); + const string topModuleFile = hblockp ? hblockp->vFileIfNecessary() : ""; if (!forMkJson) { - if (!topModuleFile.empty()) *of << topModuleFile << "\n"; - for (const auto& i : v3Global.opt.vFiles()) *of << i.filename() << "\n"; + for (const string& filename : V3HierGraph::sourceFiles(topModuleFile)) + *of << filename << "\n"; } for (const auto& i : v3Global.opt.libraryFiles()) { if (V3Os::filenameRealPath(i.filename()) != topModuleFile) @@ -393,6 +392,15 @@ public: } }; +VStringList V3HierGraph::sourceFiles(const string& topModuleFile) { + VStringList sources; + sources.reserve(v3Global.opt.vFiles().size() + 1); + for (const VFileLibName& vfile : v3Global.opt.vFiles()) sources.emplace_back(vfile.filename()); + // Library-discovered blocks may depend on packages in the explicit input files. + if (!topModuleFile.empty()) sources.emplace_back(topModuleFile); + return sources; +} + void V3HierGraph::writeCommandArgsFiles(bool forMkJson) const { for (const V3GraphVertex& vtx : vertices()) { diff --git a/src/V3HierBlock.h b/src/V3HierBlock.h index 72877594c..0f24d10b3 100644 --- a/src/V3HierBlock.h +++ b/src/V3HierBlock.h @@ -44,6 +44,8 @@ public: VL_UNCOPYABLE(V3HierGraph); VL_UNMOVABLE(V3HierGraph); + // Explicit HDL inputs followed by the library-discovered top module file, if any. + static VStringList sourceFiles(const string& topModuleFile = "") VL_MT_DISABLED; // Write command line arguments to .f files for child Verilation run void writeCommandArgsFiles(bool forMkJson) const VL_MT_DISABLED; void writeParametersFiles() const VL_MT_DISABLED; diff --git a/test_regress/t/t_hier_block_libdir_pkg.py b/test_regress/t/t_hier_block_libdir_pkg.py new file mode 100755 index 000000000..defc2710f --- /dev/null +++ b/test_regress/t/t_hier_block_libdir_pkg.py @@ -0,0 +1,23 @@ +#!/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') +test.clean_objs() + +test.compile(verilator_flags2=[ + '--hierarchical', test.t_dir + '/t_hier_block_libdir_pkg/hier.vlt', '-y', + test.t_dir + '/t_hier_block_libdir_pkg', test.t_dir + '/t_hier_block_libdir_pkg/pkg.vh' +], + threads=(2 if test.vltmt else 1)) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_hier_block_libdir_pkg.v b/test_regress/t/t_hier_block_libdir_pkg.v new file mode 100644 index 000000000..b7f944399 --- /dev/null +++ b/test_regress/t/t_hier_block_libdir_pkg.v @@ -0,0 +1,42 @@ +// 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 + +// verilog_format: off +`define stop $stop +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +// verilog_format: on + +module t ( + input clk +); + logic [7:0] c; + logic [6:0] c_param; + int cycles = 0; + + blk u ( + .clk(clk), + .cnt_o(c) + ); + blk_param #( + .T(logic [6:0]), + .STEP(3) + ) u_param ( + .clk(clk), + .cnt_o(c_param) + ); + + always @(negedge clk) begin + cycles = cycles + 1; + `checkd(c, 8'(cycles)); + `checkd(c_param, 7'(cycles * 3)); + if (cycles == 10) begin + `checkd(c, 8'd10); + `checkd(c_param, 7'd30); + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_hier_block_libdir_pkg/blk.v b/test_regress/t/t_hier_block_libdir_pkg/blk.v new file mode 100644 index 000000000..49cdf50bf --- /dev/null +++ b/test_regress/t/t_hier_block_libdir_pkg/blk.v @@ -0,0 +1,14 @@ +// 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 blk + import my_pkg::*; +( + input clk, + output byte_t cnt_o +); + always @(posedge clk) cnt_o <= cnt_o + 1; +endmodule diff --git a/test_regress/t/t_hier_block_libdir_pkg/blk_param.v b/test_regress/t/t_hier_block_libdir_pkg/blk_param.v new file mode 100644 index 000000000..346b222c2 --- /dev/null +++ b/test_regress/t/t_hier_block_libdir_pkg/blk_param.v @@ -0,0 +1,17 @@ +// 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 blk_param + import my_pkg::*; +#( + parameter type T = byte_t, + parameter byte_t STEP = 1 +) ( + input clk, + output T cnt_o +); + always @(posedge clk) cnt_o <= cnt_o + T'(STEP); +endmodule diff --git a/test_regress/t/t_hier_block_libdir_pkg/hier.vlt b/test_regress/t/t_hier_block_libdir_pkg/hier.vlt new file mode 100644 index 000000000..c581df48c --- /dev/null +++ b/test_regress/t/t_hier_block_libdir_pkg/hier.vlt @@ -0,0 +1,9 @@ +// 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 + +`verilator_config +hier_block -module "blk" +hier_block -module "blk_param" diff --git a/test_regress/t/t_hier_block_libdir_pkg/pkg.vh b/test_regress/t/t_hier_block_libdir_pkg/pkg.vh new file mode 100644 index 000000000..c74eed8d5 --- /dev/null +++ b/test_regress/t/t_hier_block_libdir_pkg/pkg.vh @@ -0,0 +1,9 @@ +// 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 + +package my_pkg; + typedef logic [7:0] byte_t; +endpackage diff --git a/test_regress/t/t_hier_block_libdir_pkg_cmake.py b/test_regress/t/t_hier_block_libdir_pkg_cmake.py new file mode 100755 index 000000000..568ae9b6a --- /dev/null +++ b/test_regress/t/t_hier_block_libdir_pkg_cmake.py @@ -0,0 +1,27 @@ +#!/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') +test.top_filename = test.t_dir + '/t_hier_block_libdir_pkg.v' +test.clean_objs() + +test.compile(verilator_make_cmake=True, + verilator_make_gmake=False, + verilator_flags2=[ + '--hierarchical', test.t_dir + '/t_hier_block_libdir_pkg/hier.vlt', '-y', + test.t_dir + '/t_hier_block_libdir_pkg', + test.t_dir + '/t_hier_block_libdir_pkg/pkg.vh' + ], + threads=(2 if test.vltmt else 1)) + +test.execute() + +test.passes()