diff --git a/src/V3VariableOrder.cpp b/src/V3VariableOrder.cpp index cccfbc48a..ec5963a2c 100644 --- a/src/V3VariableOrder.cpp +++ b/src/V3VariableOrder.cpp @@ -177,10 +177,17 @@ class VariableOrder final { // cppcheck-suppress constParameterPointer void orderModuleVars(AstNodeModule* modp) { + // Top level ports stay first in source order, as a --lib-create wrapper must match + // the interface of the module it replaces + std::vector portps; // Unlink all module variables from the module, compute attributes for (AstNode *nodep = modp->stmtsp(), *nextp; nodep; nodep = nextp) { nextp = nodep->nextp(); if (AstVar* const varp = VN_CAST(nodep, Var)) { + if (modp->isTop() && varp->isIO()) { + portps.push_back(varp); + continue; + } m_varps.push_back(varp); // Compute attributes up front @@ -207,6 +214,7 @@ class VariableOrder final { mtaskSortVars(m_varps); } } + m_varps.insert(m_varps.begin(), portps.begin(), portps.end()); } public: diff --git a/test_regress/t/t_lib_port_order.py b/test_regress/t/t_lib_port_order.py new file mode 100755 index 000000000..0d77e05f1 --- /dev/null +++ b/test_regress/t/t_lib_port_order.py @@ -0,0 +1,30 @@ +#!/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') + +lib_dir = test.obj_dir + "/sub" +test.mkdir_ok(lib_dir) + +test.run(logfile=lib_dir + "/verilator.log", + cmd=[ + "perl", os.environ["VERILATOR_ROOT"] + "/bin/verilator", "-cc", "-Mdir", lib_dir, + "--lib-create", "sub", "--prefix", "Vsub", "+define+LIB_CREATE", test.top_filename + ], + verilator_run=True) + +test.run(logfile=lib_dir + "/make.log", cmd=[os.environ["MAKE"], "-C", lib_dir, "-f", "Vsub.mk"]) + +test.compile(verilator_flags2=["--binary", "-LDFLAGS", "sub/libsub.a", lib_dir + "/sub.sv"]) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_lib_port_order.v b/test_regress/t/t_lib_port_order.v new file mode 100644 index 000000000..9b01a5f61 --- /dev/null +++ b/test_regress/t/t_lib_port_order.v @@ -0,0 +1,77 @@ +// 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 checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +// verilog_format: on + +`ifdef LIB_CREATE +// This is built with --lib-create. The ports have different sizes, so ordering +// variables for layout would reorder them. + +module sub ( + input logic [62:0] wide, + input logic clk, + input logic [6:0] narrow, + output logic [30:0] sum, + output logic flag +); + + always_ff @(posedge clk) begin + sum <= wide[30:0] + {24'd0, narrow}; + flag <= ^wide; + end + +endmodule + +`else +// This is built as the top level + +module top; + + logic clk = 1'b0; + int cyc = 0; + logic [62:0] wide = 63'h01234567_89abcdef; + logic [6:0] narrow = 7'h5a; + logic [30:0] sum; + logic flag; + logic [30:0] exp_sum; + logic exp_flag; + + always #5 clk = ~clk; + + // Positional connections need the library wrapper to keep the source port order + sub sub_i ( + wide, + clk, + narrow, + sum, + flag + ); + + always @(posedge clk) begin + cyc <= cyc + 1; + wide <= {wide[61:0], wide[62] ^ wide[61]}; + narrow <= narrow + 7'd3; + exp_sum <= wide[30:0] + {24'd0, narrow}; + exp_flag <= ^wide; + end + + always @(negedge clk) begin + if (cyc > 0) begin + `checkh(sum, exp_sum); + `checkh(flag, exp_flag); + end + if (cyc == 20) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule + +`endif