From 0aac3074b607898d988aab6138eedfc0b94bccf2 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 12 Mar 2025 17:57:02 -0400 Subject: [PATCH] Fix recursive error on virtual interfaces (#5854). --- Changes | 1 + src/V3LinkCells.cpp | 6 +-- test_regress/t/t_virtual_interface_pkg.py | 18 +++++++ test_regress/t/t_virtual_interface_pkg.v | 64 +++++++++++++++++++++++ 4 files changed, 86 insertions(+), 3 deletions(-) create mode 100755 test_regress/t/t_virtual_interface_pkg.py create mode 100644 test_regress/t/t_virtual_interface_pkg.v diff --git a/Changes b/Changes index 33c252fda..80261cb9c 100644 --- a/Changes +++ b/Changes @@ -42,6 +42,7 @@ Verilator 5.035 devel * Fix NBA shared flag reuse (#5848). [Geza Lore] * Fix removal of callbacks no longer in current list (#5851) (#5852). [Gilberto Abram] * Fix segmentation fault on member compare (#5853). +* Fix recursive error on virtual interfaces (#5854). [Yilou Wang] Verilator 5.034 2025-02-24 diff --git a/src/V3LinkCells.cpp b/src/V3LinkCells.cpp index 6e3d13fe3..21bec741b 100644 --- a/src/V3LinkCells.cpp +++ b/src/V3LinkCells.cpp @@ -125,8 +125,8 @@ class LinkCellsVisitor final : public VNVisitor { return nodep->user1u().toGraphVertex(); } void newEdge(V3GraphVertex* fromp, V3GraphVertex* top, int weight, bool cuttable) { - UINFO(9, "newEdge " << fromp->name() << " -> " << top->name() << endl); - new V3GraphEdge{&m_graph, fromp, top, weight, cuttable}; + V3GraphEdge* const edgep = new V3GraphEdge{&m_graph, fromp, top, weight, cuttable}; + UINFO(9, " newEdge " << edgep << " " << fromp->name() << " -> " << top->name() << endl); } AstNodeModule* findModuleSym(const string& modName) { @@ -237,7 +237,7 @@ class LinkCellsVisitor final : public VNVisitor { if (modp) { if (VN_IS(modp, Iface)) { // Track module depths, so can sort list from parent down to children - newEdge(vertex(m_modp), vertex(modp), 1, false); + if (!nodep->isVirtual()) { newEdge(vertex(m_modp), vertex(modp), 1, false); } if (!nodep->cellp()) nodep->ifacep(VN_AS(modp, Iface)); } else if (VN_IS(modp, NotFoundModule)) { // Will error out later } else { diff --git a/test_regress/t/t_virtual_interface_pkg.py b/test_regress/t/t_virtual_interface_pkg.py new file mode 100755 index 000000000..bd059b0f2 --- /dev/null +++ b/test_regress/t/t_virtual_interface_pkg.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2025 by Wilson Snyder. 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-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +import vltest_bootstrap + +test.scenarios('simulator') + +test.compile(verilator_flags2=['--binary']) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_virtual_interface_pkg.v b/test_regress/t/t_virtual_interface_pkg.v new file mode 100644 index 000000000..0167863c1 --- /dev/null +++ b/test_regress/t/t_virtual_interface_pkg.v @@ -0,0 +1,64 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by Yilou Wang. +// SPDX-License-Identifier: CC0-1.0 + +package my_pkg; + + virtual class CallBackBase; + pure virtual function void add(int a, int b); + endclass + + class my_class extends CallBackBase; + virtual my_interface vif; + + function new(virtual my_interface vif); + this.vif = vif; + $display("my_class::new"); + vif.register_callback(this); + endfunction + + function void add(int a, int b); + // $display("a + b = %0d", a + b); + endfunction + endclass + +endpackage + +interface my_interface; + import my_pkg::*; + CallBackBase callback_obj; + + function void register_callback(CallBackBase obj); + callback_obj = obj; + endfunction + + logic clk; + always @(posedge clk) begin + if (callback_obj != null) + callback_obj.add(1, 2); + else $display("callback_obj is null"); + end +endinterface + +module t; + import my_pkg::*; + logic clk = 0; + my_interface vif(); + my_class cl; + + assign vif.clk = clk; + + initial begin + forever #5 clk = ~clk; + end + + initial begin + #10; + cl = new(vif); + #100; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule