diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index ea1180588..6fa174ed0 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -739,7 +739,7 @@ class TristateVisitor final : public TristateBaseVisitor { // Check if the var is owned by a different module (cross-module reference). // For interface vars this is expected; for regular modules it's unsupported. AstNodeModule* const ownerModp = findParentModule(invarp); - const bool isCrossModule = ownerModp && ownerModp != nodep && !invarp->isIO(); + const bool isCrossModule = ownerModp && ownerModp != nodep; const bool isIfaceTri = isCrossModule && VN_IS(ownerModp, Iface); if (isCrossModule && !isIfaceTri) { @@ -778,7 +778,7 @@ class TristateVisitor final : public TristateBaseVisitor { kv.second.inlinedDots, findModportForDotted(nodep, kv.first)); } - } else if (VN_IS(nodep, Iface)) { + } else if (VN_IS(nodep, Iface) && !invarp->isIO()) { // Local driver in an interface module - use contribution mechanism // so it can be combined with any external drivers later insertTristatesSignal(nodep, invarp, refsp, true, "", "", nullptr); diff --git a/test_regress/t/t_tri_iface_port.py b/test_regress/t/t_tri_iface_port.py new file mode 100755 index 000000000..4348f3df1 --- /dev/null +++ b/test_regress/t/t_tri_iface_port.py @@ -0,0 +1,16 @@ +#!/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') + +test.compile() + +test.passes() diff --git a/test_regress/t/t_tri_iface_port.v b/test_regress/t/t_tri_iface_port.v new file mode 100644 index 000000000..366ad995c --- /dev/null +++ b/test_regress/t/t_tri_iface_port.v @@ -0,0 +1,65 @@ +// DESCRIPTION: Verilator: Interface inout port driven locally and externally +// +// 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 + +interface zest_if_local ( + inout [0:0] U27 +); + assign U27[0] = 1'b1; +endinterface + +interface zest_if_ext ( + inout [0:0] U28 +); +endinterface + +module ext_drv ( + zest_if_ext zif, + input drive_en +); + assign zif.U28[0] = drive_en ? 1'b1 : 1'bz; +endmodule + +interface zest_if_ext_mp ( + inout [0:0] U29 +); + modport drv(inout U29); +endinterface + +module ext_drv_mp ( + zest_if_ext_mp.drv zif, + input drive_en +); + assign zif.U29[0] = drive_en ? 1'b0 : 1'bz; +endmodule + +module t ( + inout [0:0] bus_local, + inout [0:0] bus_ext, + inout [0:0] bus_ext_mp, + input drive_en +); + zest_if_local zif_local ( + .U27(bus_local) + ); + + zest_if_ext zif_ext ( + .U28(bus_ext) + ); + ext_drv u_ext_drv ( + .zif(zif_ext), + .drive_en(drive_en) + ); + + zest_if_ext_mp zif_ext_mp ( + .U29(bus_ext_mp) + ); + ext_drv_mp u_ext_drv_mp ( + .zif(zif_ext_mp), + .drive_en(drive_en) + ); +endmodule