From 3ceac0b37e1903adf0a9224f8e309fc314f18c39 Mon Sep 17 00:00:00 2001 From: em2machine <92717390+em2machine@users.noreply.github.com> Date: Fri, 19 Dec 2025 18:57:15 +0100 Subject: [PATCH] Fix parameterized class module parameters (#6754) (#6834) --- src/V3AstNodeExpr.h | 2 +- src/V3Const.cpp | 3 +- src/V3LinkDot.cpp | 14 ++++++ src/V3LinkDotIfaceCapture.cpp | 29 +++++++++-- src/V3LinkDotIfaceCapture.h | 8 ++- src/V3Param.cpp | 25 +++++++++ test_regress/t/t_mod_param_class_typedef1.py | 18 +++++++ test_regress/t/t_mod_param_class_typedef1.v | 41 +++++++++++++++ test_regress/t/t_mod_param_class_typedef2.py | 18 +++++++ test_regress/t/t_mod_param_class_typedef2.v | 44 ++++++++++++++++ test_regress/t/t_mod_param_class_typedef3.py | 18 +++++++ test_regress/t/t_mod_param_class_typedef3.v | 41 +++++++++++++++ test_regress/t/t_mod_param_class_typedef4.py | 18 +++++++ test_regress/t/t_mod_param_class_typedef4.v | 47 +++++++++++++++++ test_regress/t/t_mod_param_class_typedef5.py | 18 +++++++ test_regress/t/t_mod_param_class_typedef5.v | 42 ++++++++++++++++ test_regress/t/t_mod_param_class_typedef6.py | 18 +++++++ test_regress/t/t_mod_param_class_typedef6.v | 29 +++++++++++ test_regress/t/t_mod_param_class_typedef7.py | 18 +++++++ test_regress/t/t_mod_param_class_typedef7.v | 53 ++++++++++++++++++++ 20 files changed, 497 insertions(+), 7 deletions(-) create mode 100755 test_regress/t/t_mod_param_class_typedef1.py create mode 100644 test_regress/t/t_mod_param_class_typedef1.v create mode 100755 test_regress/t/t_mod_param_class_typedef2.py create mode 100644 test_regress/t/t_mod_param_class_typedef2.v create mode 100755 test_regress/t/t_mod_param_class_typedef3.py create mode 100644 test_regress/t/t_mod_param_class_typedef3.v create mode 100755 test_regress/t/t_mod_param_class_typedef4.py create mode 100644 test_regress/t/t_mod_param_class_typedef4.v create mode 100755 test_regress/t/t_mod_param_class_typedef5.py create mode 100644 test_regress/t/t_mod_param_class_typedef5.v create mode 100755 test_regress/t/t_mod_param_class_typedef6.py create mode 100644 test_regress/t/t_mod_param_class_typedef6.v create mode 100755 test_regress/t/t_mod_param_class_typedef7.py create mode 100644 test_regress/t/t_mod_param_class_typedef7.v diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index cd6d9c71d..32e6f9688 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -796,7 +796,7 @@ public: void classOrPackagep(AstNodeModule* nodep) { m_classOrPackageNodep = reinterpret_cast(nodep); } - + bool hasDType() const override VL_MT_SAFE { return false; } string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); } bool cleanOut() const override { V3ERROR_NA_RETURN(true); } diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 6f56bc6e2..8baeb6f29 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -4138,7 +4138,8 @@ class ConstVisitor final : public VNVisitor { void visit(AstNode* nodep) override { // Default: Just iterate if (m_required) { - if (VN_IS(nodep, NodeDType) || VN_IS(nodep, Range) || VN_IS(nodep, SliceSel)) { + if (VN_IS(nodep, NodeDType) || VN_IS(nodep, Range) || VN_IS(nodep, SliceSel) + || VN_IS(nodep, Dot)) { // Ignore dtypes for parameter type pins } else { nodep->v3error("Expecting expression to be constant, but can't convert a " diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 07914fab5..1ce93ff9f 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -5345,6 +5345,20 @@ class LinkDotResolveVisitor final : public VNVisitor { nodep->typedefp(defp); nodep->classOrPackagep(foundp->classOrPackagep()); resolvedCapturedTypedef = true; + + // class capture: capture typedef references inside parameterized classes + // Only capture if we're referencing from OUTSIDE the class (not + // self-references) + if (m_statep->forPrimary()) { + AstClass* const classp = VN_CAST(nodep->classOrPackagep(), Class); + if (classp && classp->hasGParam() && classp != m_modp) { + UINFO(9, indent() + << "class capture add typedef name=" << nodep->name() + << " class=" << classp->name() << " typedef=" << defp); + V3LinkDotIfaceCapture::addClass(nodep, classp, m_modp, defp); + } + } + } else if (AstParamTypeDType* const defp = foundp ? VN_CAST(foundp->nodep(), ParamTypeDType) : nullptr) { if (defp == nodep->backp()) { // Where backp is typically typedef diff --git a/src/V3LinkDotIfaceCapture.cpp b/src/V3LinkDotIfaceCapture.cpp index b11e622d8..7bb3b5c63 100644 --- a/src/V3LinkDotIfaceCapture.cpp +++ b/src/V3LinkDotIfaceCapture.cpp @@ -57,13 +57,22 @@ void V3LinkDotIfaceCapture::add(AstRefDType* refp, AstCell* cellp, AstNodeModule AstTypedef* typedefp, AstNodeModule* typedefOwnerModp, AstVar* ifacePortVarp) { if (!refp) return; - if (!typedefp) typedefp = refp->typedefp(); - if (!typedefOwnerModp && typedefp) typedefOwnerModp = findOwnerModule(typedefp); - s_map[refp] = CapturedIfaceTypedef{ - refp, cellp, ownerModp, typedefp, typedefOwnerModp, nullptr, ifacePortVarp}; + CaptureType::IFACE, refp, cellp, nullptr, ownerModp, typedefp, + typedefOwnerModp, nullptr, ifacePortVarp}; +} + +void V3LinkDotIfaceCapture::addClass(AstRefDType* refp, AstClass* origClassp, + AstNodeModule* ownerModp, AstTypedef* typedefp, + AstNodeModule* typedefOwnerModp) { + if (!refp) return; + if (!typedefp) typedefp = refp->typedefp(); + if (!typedefOwnerModp && typedefp) typedefOwnerModp = findOwnerModule(typedefp); + s_map[refp] = CapturedIfaceTypedef{CaptureType::CLASS, refp, nullptr, + origClassp, ownerModp, typedefp, + typedefOwnerModp, nullptr, nullptr}; } const V3LinkDotIfaceCapture::CapturedIfaceTypedef* @@ -99,6 +108,18 @@ bool V3LinkDotIfaceCapture::replaceTypedef(const AstRefDType* refp, AstTypedef* if (it == s_map.end()) return false; it->second.typedefp = newTypedefp; it->second.typedefOwnerModp = findOwnerModule(newTypedefp); + + // For CLASS captures, update the RefDType node directly + if (it->second.captureType == CaptureType::CLASS && it->second.refp) { + it->second.refp->typedefp(newTypedefp); + // Also update classOrPackagep to point to the specialized class + if (AstClass* const newClassp = VN_CAST(it->second.typedefOwnerModp, Class)) { + it->second.refp->classOrPackagep(newClassp); + } + UINFO(9, "class capture updated RefDType typedefp: " << it->second.refp << " -> " + << newTypedefp); + } + finalizeCapturedEntry(it, "typedef clone"); return true; } diff --git a/src/V3LinkDotIfaceCapture.h b/src/V3LinkDotIfaceCapture.h index 8a3517aa0..1e5a26ab4 100644 --- a/src/V3LinkDotIfaceCapture.h +++ b/src/V3LinkDotIfaceCapture.h @@ -31,9 +31,12 @@ class V3LinkDotIfaceCapture final { public: + enum class CaptureType { IFACE, CLASS }; struct CapturedIfaceTypedef final { + CaptureType captureType = CaptureType::IFACE; AstRefDType* refp = nullptr; - AstCell* cellp = nullptr; + AstCell* cellp = nullptr; // now for IFACE captures + AstClass* origClassp = nullptr; // new for CLASS captures // Module where the RefDType lives AstNodeModule* ownerModp = nullptr; // Typedef definition being referenced @@ -69,6 +72,9 @@ public: static void add(AstRefDType* refp, AstCell* cellp, AstNodeModule* ownerModp, AstTypedef* typedefp = nullptr, AstNodeModule* typedefOwnerModp = nullptr, AstVar* ifacePortVarp = nullptr); + static void addClass(AstRefDType* refp, AstClass* origClassp, AstNodeModule* ownerModp, + AstTypedef* typedefp = nullptr, + AstNodeModule* typedefOwnerModp = nullptr); static const CapturedIfaceTypedef* find(const AstRefDType* refp); static void forEach(const std::function& fn); static void forEachOwned(const AstNodeModule* ownerModp, diff --git a/src/V3Param.cpp b/src/V3Param.cpp index ffb712a10..68f378fd1 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -810,6 +810,27 @@ class ParamProcessor final { } } + // Helper to resolve DOT to RefDType for class type references + void resolveDotToTypedef(AstNode* exprp) { + AstDot* const dotp = VN_CAST(exprp, Dot); + if (!dotp) return; + const AstClassOrPackageRef* const classRefp = VN_CAST(dotp->lhsp(), ClassOrPackageRef); + if (!classRefp) return; + const AstClass* const lhsClassp = VN_CAST(classRefp->classOrPackageSkipp(), Class); + if (!lhsClassp) return; + AstParseRef* const parseRefp = VN_CAST(dotp->rhsp(), ParseRef); + if (!parseRefp) return; + + AstTypedef* const tdefp + = VN_CAST(m_memberMap.findMember(lhsClassp, parseRefp->name()), Typedef); + if (tdefp) { + AstRefDType* const refp = new AstRefDType{dotp->fileline(), tdefp->name()}; + refp->typedefp(tdefp); + dotp->replaceWith(refp); + VL_DO_DANGLING(dotp->deleteTree(), dotp); + } + } + void cellPinCleanup(AstNode* nodep, AstPin* pinp, AstNodeModule* srcModp, string& longnamer, bool& any_overridesr) { if (!pinp->exprp()) return; // No-connect @@ -869,6 +890,10 @@ class ParamProcessor final { } } } else if (AstParamTypeDType* const modvarp = pinp->modPTypep()) { + // Handle DOT with ParseRef RHS (e.g., p_class#(8)::p_type) + // by this point ClassOrPackageRef should be updated to point to the specialized class. + resolveDotToTypedef(pinp->exprp()); + AstNodeDType* rawTypep = VN_CAST(pinp->exprp(), NodeDType); if (rawTypep) V3Width::widthParamsEdit(rawTypep); AstNodeDType* exprp = rawTypep ? rawTypep->skipRefToNonRefp() : nullptr; diff --git a/test_regress/t/t_mod_param_class_typedef1.py b/test_regress/t/t_mod_param_class_typedef1.py new file mode 100755 index 000000000..c6e56559a --- /dev/null +++ b/test_regress/t/t_mod_param_class_typedef1.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_mod_param_class_typedef1.v b/test_regress/t/t_mod_param_class_typedef1.v new file mode 100644 index 000000000..4da5e7a31 --- /dev/null +++ b/test_regress/t/t_mod_param_class_typedef1.v @@ -0,0 +1,41 @@ +// 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 + +// verilog_format: off +`define stop $stop +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0); +// verilog_format: on + +class p_class #( + parameter TLEN = 2, + localparam type T = logic [TLEN-1:0] +); + typedef struct packed { + T a; + } p_type; +endclass + +module p_mod #( + parameter type T = logic +); + initial begin + #1; + `checkd($bits(T), 8); + end +endmodule + +module the_top #()(); + typedef p_class#(8)::p_type p_type_t; + p_mod #(p_type_t) p1(); + + p_mod #( p_class#(8)::p_type ) p2(); + + initial begin + #2; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_mod_param_class_typedef2.py b/test_regress/t/t_mod_param_class_typedef2.py new file mode 100755 index 000000000..c6e56559a --- /dev/null +++ b/test_regress/t/t_mod_param_class_typedef2.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_mod_param_class_typedef2.v b/test_regress/t/t_mod_param_class_typedef2.v new file mode 100644 index 000000000..a749557a3 --- /dev/null +++ b/test_regress/t/t_mod_param_class_typedef2.v @@ -0,0 +1,44 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by 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 (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0); +// verilog_format: on + +class p_class #( + parameter TLEN = 2, + localparam type T = logic [TLEN-1:0] +); + typedef struct packed { + T a, b; + } p_type; +endclass + +module p_mod #( + parameter type T = logic +); + initial begin + #1; + `checkd($bits(T), 16); + end +endmodule + +module the_top #() (); + p_mod #(.T(p_class#(8)::p_type)) p1(); + + typedef p_class#(8) p_class_8; + p_mod #(.T(p_class_8::p_type)) p2(); + + typedef p_class#(8)::p_type p_class_type_8; + p_mod #(.T(p_class_type_8)) p4(); + + initial begin + #2; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_mod_param_class_typedef3.py b/test_regress/t/t_mod_param_class_typedef3.py new file mode 100755 index 000000000..c6e56559a --- /dev/null +++ b/test_regress/t/t_mod_param_class_typedef3.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_mod_param_class_typedef3.v b/test_regress/t/t_mod_param_class_typedef3.v new file mode 100644 index 000000000..08bcd004b --- /dev/null +++ b/test_regress/t/t_mod_param_class_typedef3.v @@ -0,0 +1,41 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by 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 (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0); +// verilog_format: on + +class p_class #( + parameter TLEN = 2, + localparam type T = logic [TLEN-1:0] +); + typedef struct packed { + T a, b; + } p_type; +endclass + +module p_mod #( + parameter type T = logic +); + initial begin + #1; + `checkd($bits(T), 16); + end +endmodule + +module the_top #() (); + + typedef p_class#(8) p_class_8; + typedef p_class_8::p_type p_type_8; + p_mod #(.T(p_type_8)) p3(); + + initial begin + #2; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_mod_param_class_typedef4.py b/test_regress/t/t_mod_param_class_typedef4.py new file mode 100755 index 000000000..c6e56559a --- /dev/null +++ b/test_regress/t/t_mod_param_class_typedef4.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_mod_param_class_typedef4.v b/test_regress/t/t_mod_param_class_typedef4.v new file mode 100644 index 000000000..08142c739 --- /dev/null +++ b/test_regress/t/t_mod_param_class_typedef4.v @@ -0,0 +1,47 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by 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 (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0); +// verilog_format: on + +class p_class #( + parameter TLEN = 2, + localparam type T = logic [TLEN-1:0] +); + typedef struct packed { + T a, b; + } p_type; +endclass + +module p_mod #( + parameter type T = logic +); + initial begin + #1; + `checkd($bits(T), 16); + end +endmodule + +module the_top #() (); + p_mod #(.T(p_class#(8)::p_type)) p1(); + + typedef p_class#(8) p_class_8; + p_mod #(.T(p_class_8::p_type)) p2(); + + typedef p_class_8::p_type p_type_8; + p_mod #(.T(p_type_8)) p3(); + + typedef p_class#(8)::p_type p_class_type_8; + p_mod #(.T(p_class_type_8)) p4(); + + initial begin + #2; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_mod_param_class_typedef5.py b/test_regress/t/t_mod_param_class_typedef5.py new file mode 100755 index 000000000..c6e56559a --- /dev/null +++ b/test_regress/t/t_mod_param_class_typedef5.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_mod_param_class_typedef5.v b/test_regress/t/t_mod_param_class_typedef5.v new file mode 100644 index 000000000..63542975a --- /dev/null +++ b/test_regress/t/t_mod_param_class_typedef5.v @@ -0,0 +1,42 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by 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 (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0); +// verilog_format: on + +class xxx_class #(parameter int X = 1); + typedef logic [X-1:0] cmd_tag_t; +endclass + +module mod_a #(parameter p_width=16) (); +endmodule + +module mod_b #(parameter type io_type_t = logic) ( + io_type_t io +); + + initial begin + #1; + `checkd($bits(io), 16); + end +endmodule + +module the_top(); + xxx_class#(16)::cmd_tag_t tag; + mod_a #($bits(tag)) t0(); + + typedef xxx_class#(16)::cmd_tag_t tag_t; + tag_t tag_io; + mod_b #(tag_t) t1(tag_io); + + initial begin + #2; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_mod_param_class_typedef6.py b/test_regress/t/t_mod_param_class_typedef6.py new file mode 100755 index 000000000..c6e56559a --- /dev/null +++ b/test_regress/t/t_mod_param_class_typedef6.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_mod_param_class_typedef6.v b/test_regress/t/t_mod_param_class_typedef6.v new file mode 100644 index 000000000..fc4d675e6 --- /dev/null +++ b/test_regress/t/t_mod_param_class_typedef6.v @@ -0,0 +1,29 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by 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 (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0); +// verilog_format: on + +class xxx_class #(parameter int X = 1); + typedef logic [X-1:0] cmd_tag_t; +endclass + +module mod_a #(parameter p_width=16) (); +endmodule + +module the_top(); + xxx_class#(16)::cmd_tag_t tag; + mod_a #($bits(tag)) t0(); + + initial begin + #2; + `checkd($bits(tag), 16); + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_mod_param_class_typedef7.py b/test_regress/t/t_mod_param_class_typedef7.py new file mode 100755 index 000000000..c6e56559a --- /dev/null +++ b/test_regress/t/t_mod_param_class_typedef7.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_mod_param_class_typedef7.v b/test_regress/t/t_mod_param_class_typedef7.v new file mode 100644 index 000000000..b4859c879 --- /dev/null +++ b/test_regress/t/t_mod_param_class_typedef7.v @@ -0,0 +1,53 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by 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 (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0); +// verilog_format: on + +package pf; + typedef struct packed { + int unsigned CcNumTl; + int unsigned PqSize; + } cfg_t; +endpackage + +virtual class xxx_class #(parameter pf::cfg_t Cfg); + typedef struct packed { + logic [$clog2(Cfg.CcNumTl)-1:0] tl_index; + logic [$clog2(Cfg.PqSize)-1:0] pq_index; + } cmd_tag_t; +endclass + +module mod2 #(parameter p_width=16) ( + output logic [p_width-1:0] q, + input logic [p_width-1:0] d +); + assign q = d; + + initial begin + #1; + `checkd(p_width, 7); + end +endmodule + +module top(); + localparam pf::cfg_t Cfg0 = '{ + CcNumTl:8 + ,PqSize:12 + }; + + xxx_class#(Cfg0)::cmd_tag_t tag, tag_q; + + mod2 #($bits(tag)) t0(tag_q, tag); + + initial begin + #1; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule