From 2995748d46e9e684c7c98fd522ab15e5f4d7d7ca Mon Sep 17 00:00:00 2001 From: em2machine <92717390+em2machine@users.noreply.github.com> Date: Fri, 12 Dec 2025 13:17:08 +0100 Subject: [PATCH] Fix parameterized class function (#6659) (#6802) --- src/V3Param.cpp | 13 +++++-- test_regress/t/t_class_param_typedef3.py | 18 ++++++++++ test_regress/t/t_class_param_typedef3.v | 43 ++++++++++++++++++++++++ test_regress/t/t_class_param_typedef4.py | 18 ++++++++++ test_regress/t/t_class_param_typedef4.v | 43 ++++++++++++++++++++++++ 5 files changed, 133 insertions(+), 2 deletions(-) create mode 100755 test_regress/t/t_class_param_typedef3.py create mode 100644 test_regress/t/t_class_param_typedef3.v create mode 100755 test_regress/t/t_class_param_typedef4.py create mode 100644 test_regress/t/t_class_param_typedef4.v diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 5faf49a77..69bedbdbb 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -1313,11 +1313,20 @@ class ClassRefUnlinkerVisitor final : public VNVisitor { public: explicit ClassRefUnlinkerVisitor(AstNetlist* netlistp) { iterate(netlistp); } - void visit(AstClassOrPackageRef* nodep) override { if (nodep->paramsp()) { if (AstClass* const classp = VN_CAST(nodep->classOrPackageSkipp(), Class)) { - if (!classp->user3p()) VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); + if (!classp->user3p()) { + // Check if this ClassOrPackageRef is the lhsp of a DOT node + AstDot* const dotp = VN_CAST(nodep->backp(), Dot); + if (dotp && dotp->lhsp() == nodep) { + // Replace DOT with just its rhsp to avoid leaving DOT with null lhsp + dotp->replaceWith(dotp->rhsp()->unlinkFrBack()); + VL_DO_DANGLING2(pushDeletep(dotp), dotp, nodep); + } else { + VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); + } + } } } } diff --git a/test_regress/t/t_class_param_typedef3.py b/test_regress/t/t_class_param_typedef3.py new file mode 100755 index 000000000..c53b55262 --- /dev/null +++ b/test_regress/t/t_class_param_typedef3.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 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_class_param_typedef3.v b/test_regress/t/t_class_param_typedef3.v new file mode 100644 index 000000000..6472b906c --- /dev/null +++ b/test_regress/t/t_class_param_typedef3.v @@ -0,0 +1,43 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty. +// SPDX-License-Identifier: CC0-1.0 + +class func_c #(parameter p_width=4); + static function logic[p_width-1:0] func( + input logic[p_width-1:0] inb + ); + func = inb; + endfunction +endclass + +module modA #(parameter p_width = 7)( + input logic [p_width-1:0] sig_a + ,output logic [p_width-1:0] sig_b +); + assign sig_b = func_c#(p_width)::func(sig_a); +endmodule + +module the_top(); + localparam int Size = 3; + + logic [Size-1:0] sig_a; + logic [Size-1:0] sig_b; + + modA #(.p_width(Size)) modA( + .sig_a(sig_a) + ,.sig_b(sig_b) + ); + + //assign sig_b = func_c#(p_width)::func(inb_i); + + initial begin + sig_a = 'h3; + #1; + $display("sig_a=%d, sig_b=%d", sig_a, sig_b); + if(sig_b != 'h3) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_param_typedef4.py b/test_regress/t/t_class_param_typedef4.py new file mode 100755 index 000000000..c53b55262 --- /dev/null +++ b/test_regress/t/t_class_param_typedef4.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 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_class_param_typedef4.v b/test_regress/t/t_class_param_typedef4.v new file mode 100644 index 000000000..a3b623ca5 --- /dev/null +++ b/test_regress/t/t_class_param_typedef4.v @@ -0,0 +1,43 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty. +// SPDX-License-Identifier: CC0-1.0 + +class func_c #(parameter p_width=4); + static function logic[p_width-1:0] func( + input logic[p_width-1:0] inb + ); + func = inb; + endfunction +endclass + +module modA #(parameter p_width = 7)( + input logic [p_width-1:0] sig_a + ,output logic [p_width-1:0] sig_b +); + assign sig_b = func_c#(p_width)::func(sig_a); +endmodule + +module the_top(); + localparam int Size = 3; + + logic [Size-1:0] sig_a; + logic [Size-1:0] sig_b; + logic [Size-1:0] sig_c; + + modA #(.p_width(Size)) modA( + .sig_a(sig_a) + ,.sig_b(sig_b) + ); + + initial begin + sig_a = 'h3; + sig_c = func_c#(Size)::func('h5); + #1; + if(sig_b != 'h3) $stop; + if(sig_c != 'h5) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule