From 388fb9db2df31639a66c8f84d15979c5dcaf515b Mon Sep 17 00:00:00 2001 From: Leela Pakanati Date: Thu, 5 Feb 2026 22:06:23 -0600 Subject: [PATCH 1/3] Fix parameterized class typedef as interface type parameter (#7000) Enhance similarDTypeNode for ClassRefDType to compare type parameters, not just class pointers. Add resolveDotToTypedef in V3Param to handle ParamTypeDType whose value is a parameterized class needing specialization. This fixes patterns like: interface outer #(parameter type C = class_with_typedef#(T)); inner #(.P(C::typedef_name)) i(); endinterface --- src/V3AstNodeDType.h | 6 +- src/V3AstNodes.cpp | 15 ++++ src/V3Param.cpp | 37 ++++++++ .../t/t_iface_param_class_type_param.py | 18 ++++ .../t/t_iface_param_class_type_param.v | 87 +++++++++++++++++++ .../t/t_iface_param_class_type_param_noinl.py | 20 +++++ 6 files changed, 178 insertions(+), 5 deletions(-) create mode 100755 test_regress/t/t_iface_param_class_type_param.py create mode 100644 test_regress/t/t_iface_param_class_type_param.v create mode 100755 test_regress/t/t_iface_param_class_type_param_noinl.py diff --git a/src/V3AstNodeDType.h b/src/V3AstNodeDType.h index b1cdba11c..472bfc233 100644 --- a/src/V3AstNodeDType.h +++ b/src/V3AstNodeDType.h @@ -585,11 +585,7 @@ public: const AstClassRefDType* const asamep = VN_DBG_AS(samep, ClassRefDType); return (m_classp == asamep->m_classp && m_classOrPackagep == asamep->m_classOrPackagep); } - bool similarDTypeNode(const AstNodeDType* samep) const override { - // Doesn't need to compare m_classOrPackagep - const AstClassRefDType* const asamep = VN_DBG_AS(samep, ClassRefDType); - return m_classp == asamep->m_classp; - } + bool similarDTypeNode(const AstNodeDType* samep) const override; void dump(std::ostream& str = std::cout) const override; void dumpJson(std::ostream& str = std::cout) const override; void dumpSmall(std::ostream& str) const override; diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index a436b8b42..3120daea2 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1894,6 +1894,21 @@ void AstClassRefDType::dumpSmall(std::ostream& str) const { } string AstClassRefDType::prettyDTypeName(bool) const { return "class{}"s + prettyName(); } string AstClassRefDType::name() const { return classp() ? classp()->name() : ""; } +bool AstClassRefDType::similarDTypeNode(const AstNodeDType* samep) const { + // Doesn't need to compare m_classOrPackagep + const AstClassRefDType* const asamep = VN_DBG_AS(samep, ClassRefDType); + if (m_classp != asamep->m_classp) return false; + // Also compare type parameters - C#(int) != C#(string) + const AstPin* lp = paramsp(); + const AstPin* rp = asamep->paramsp(); + while (lp && rp) { + if (!lp->exprp() != !rp->exprp()) return false; + if (lp->exprp() && !lp->exprp()->sameTree(rp->exprp())) return false; + lp = VN_CAST(lp->nextp(), Pin); + rp = VN_CAST(rp->nextp(), Pin); + } + return !lp && !rp; +} void AstNodeCoverOrAssert::dump(std::ostream& str) const { this->AstNodeStmt::dump(str); str << " ["s + this->type().ascii() + "]"; diff --git a/src/V3Param.cpp b/src/V3Param.cpp index aeddbbeb4..710e83355 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -948,6 +948,39 @@ class ParamProcessor final { if (!parseRefp) return; const AstClass* lhsClassp = VN_CAST(classRefp->classOrPackageSkipp(), Class); + + // If the ClassOrPackageRef points to a type parameter (ParamTypeDType), we need + // to check if the parameter's value contains a parameterized class that needs + // specialization. This handles patterns like: + // interface outer #(parameter type C = class_with_type_param#(T)); + // inner #(.P(C::typedef_name)) i(); // C is a type parameter + // endinterface + AstParamTypeDType* const paramTypep + = VN_CAST(classRefp->classOrPackageNodep(), ParamTypeDType); + if (paramTypep) { + // Traverse through the type parameter to find if there's a ClassRefDType + // with parameters that needs specialization + AstNodeDType* const dtypep = paramTypep->subDTypep(); + AstClassRefDType* const classRefDTypep + = dtypep ? VN_CAST(dtypep->skipRefp(), ClassRefDType) : nullptr; + if (classRefDTypep) { + AstClass* const srcClassp = classRefDTypep->classp(); + if (srcClassp && srcClassp->hasGParam() && classRefDTypep->paramsp()) { + // The type parameter's value is a parameterized class - specialize it + if (lhsClassp == srcClassp || !lhsClassp) { + UINFO(9, "resolveDotToTypedef: specializing type param class " + << srcClassp->name() << endl); + classRefDeparam(classRefDTypep, srcClassp); + lhsClassp = classRefDTypep->classp(); + } else { + UINFO(9, "resolveDotToTypedef: type param class " + << srcClassp->name() + << " already specialized to " << lhsClassp->name() << endl); + } + } + } + } + if (classRefp->paramsp()) { // ClassOrPackageRef has parameters - may need to specialize the class AstClass* const srcClassp = VN_CAST(classRefp->classOrPackageNodep(), Class); @@ -957,6 +990,10 @@ class ParamProcessor final { UINFO(9, "resolveDotToTypedef: specializing " << srcClassp->name() << endl); classRefDeparam(classRefp, srcClassp); lhsClassp = VN_CAST(classRefp->classOrPackageSkipp(), Class); + } else { + UINFO(9, "resolveDotToTypedef: class " << srcClassp->name() + << " already specialized to " + << lhsClassp->name() << endl); } } } diff --git a/test_regress/t/t_iface_param_class_type_param.py b/test_regress/t/t_iface_param_class_type_param.py new file mode 100755 index 000000000..6fe7d000c --- /dev/null +++ b/test_regress/t/t_iface_param_class_type_param.py @@ -0,0 +1,18 @@ +#!/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('simulator') + +test.compile(verilator_flags2=["--binary"]) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_iface_param_class_type_param.v b/test_regress/t/t_iface_param_class_type_param.v new file mode 100644 index 000000000..bf05026e7 --- /dev/null +++ b/test_regress/t/t_iface_param_class_type_param.v @@ -0,0 +1,87 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Leela Pakanati +// SPDX-License-Identifier: CC0-1.0 + +// Test that parameterized class typedefs work as interface type parameters +// when the class itself has type parameters. +// See issue #7000 + +// Class with single type parameter +class C #(parameter type T = logic); + typedef struct packed { T data; } td_t; +endclass + +// Class with multiple type parameters and multiple typedefs +class multi_param #(parameter type ADDR_T = logic, parameter type DATA_T = logic); + typedef struct packed { ADDR_T addr; } addr_td_t; + typedef struct packed { DATA_T data; } data_td_t; +endclass + +// verilog_format: off +`define stop $stop +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +// verilog_format: on + +// Leaf interface: holds a value of parameterized type +interface l0 #(type P = logic); + P p; +endinterface + +// 1-level nesting: wraps l0 with a class typedef parameter +interface l1 #(parameter type X = C#(logic)); + l0 #(.P(X::td_t)) sub(); +endinterface + +// 2-level nesting: forwards type param through l1 to l0 +interface l2 #(parameter type X = C#(logic)); + l1 #(.X(X)) sub(); +endinterface + +// Multi-param leaf: holds two values of different parameterized types +interface multi_l0 #(type P = logic, type Q = logic); + P p; + Q q; +endinterface + +// Multi-param nesting: accesses different typedefs from same class +interface multi_l1 #( + parameter type CFG = multi_param#(logic, logic) +); + multi_l0 #(.P(CFG::addr_td_t), .Q(CFG::data_td_t)) sub(); +endinterface + +module t; + // Test 1-level nesting with different parameterizations + l1 #(.X(C#(logic[7:0]))) l1_i1(); + l1 #(.X(C#(logic[15:0]))) l1_i2(); + // Test default type parameter (C#(logic) -> td_t is struct packed { logic data; }) + l1 l1_default(); + + // Test 2-level nesting - type parameter passed through multiple levels + l2 #(.X(C#(logic[31:0]))) l2_i(); + + // Test multiple type params - different parameterizations accessing multiple typedefs + multi_l1 #(.CFG(multi_param#(logic[7:0], logic[31:0]))) ml1_i1(); + multi_l1 #(.CFG(multi_param#(logic[15:0], logic[63:0]))) ml1_i2(); + + initial begin + // 1-level nesting + `checkd($bits(l1_i1.sub.p), 8); + `checkd($bits(l1_i2.sub.p), 16); + `checkd($bits(l1_default.sub.p), 1); // default C#(logic) -> 1-bit + + // 2-level nesting + `checkd($bits(l2_i.sub.sub.p), 32); + + // Multiple type params passed to sub-interface - two different typedefs + `checkd($bits(ml1_i1.sub.p), 8); // addr_td_t from ADDR_T=logic[7:0] + `checkd($bits(ml1_i1.sub.q), 32); // data_td_t from DATA_T=logic[31:0] + `checkd($bits(ml1_i2.sub.p), 16); // addr_td_t from ADDR_T=logic[15:0] + `checkd($bits(ml1_i2.sub.q), 64); // data_td_t from DATA_T=logic[63:0] + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_iface_param_class_type_param_noinl.py b/test_regress/t/t_iface_param_class_type_param_noinl.py new file mode 100755 index 000000000..dbae0db07 --- /dev/null +++ b/test_regress/t/t_iface_param_class_type_param_noinl.py @@ -0,0 +1,20 @@ +#!/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('simulator') + +test.top_filename = "t/t_iface_param_class_type_param.v" + +test.compile(verilator_flags2=['--binary', '-fno-inline']) + +test.execute() + +test.passes() From c2d3655569b701cfddb430c1e852ad60d46dc4a2 Mon Sep 17 00:00:00 2001 From: Leela Pakanati Date: Thu, 5 Feb 2026 22:06:31 -0600 Subject: [PATCH 2/3] Fix typedef of parameterized class for member access (#5977) Defer RefDType resolution in linkDotPrimary when the classOrPackageRef target is a typedef to a parameterized class. Previously only direct class references were deferred, so `typedef outer_cls#(params) drv_t; drv_t::beat_t x;` would resolve against the generic class which V3Param later deletes. --- src/V3LinkDot.cpp | 5 +++ test_regress/t/t_class_param_typedef8.py | 18 ++++++++ test_regress/t/t_class_param_typedef8.v | 45 +++++++++++++++++++ .../t/t_class_param_typedef8_noinl.py | 20 +++++++++ 4 files changed, 88 insertions(+) create mode 100644 test_regress/t/t_class_param_typedef8.py create mode 100644 test_regress/t/t_class_param_typedef8.v create mode 100644 test_regress/t/t_class_param_typedef8_noinl.py diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index ec680a11d..0353e7480 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -5310,6 +5310,11 @@ class LinkDotResolveVisitor final : public VNVisitor { iterate(cpackagep); return; } + // Also defer if target is a typedef to a parameterized class (#5977) + if (m_statep->forPrimary() && isParamedClassRef(cpackagerefp)) { + iterate(cpackagep); + return; + } if (!cpackagerefp->classOrPackageSkipp()) { VSymEnt* const foundp = m_statep->resolveClassOrPackage( m_ds.m_dotSymp, cpackagerefp, true, false, "class/package reference"); diff --git a/test_regress/t/t_class_param_typedef8.py b/test_regress/t/t_class_param_typedef8.py new file mode 100644 index 000000000..6fe7d000c --- /dev/null +++ b/test_regress/t/t_class_param_typedef8.py @@ -0,0 +1,18 @@ +#!/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('simulator') + +test.compile(verilator_flags2=["--binary"]) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_class_param_typedef8.v b/test_regress/t/t_class_param_typedef8.v new file mode 100644 index 000000000..e516c3e87 --- /dev/null +++ b/test_regress/t/t_class_param_typedef8.v @@ -0,0 +1,45 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Leela Pakanati +// SPDX-License-Identifier: CC0-1.0 + +// Test for issue #5977: Typedef of parameterized class for member access + +// verilog_format: off +`define stop $stop +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +// verilog_format: on + +package pkg; + class cls_l0 #(parameter AW = 32); + logic [AW-1:0] addr; + function new(); + addr = '0; + endfunction + endclass + + class cls_l1 #(parameter int AW = 32); + typedef cls_l0 #(.AW(AW)) beat_t; + endclass +endpackage + +module t; + // Typedef of parameterized class, then access member typedef via :: + typedef pkg::cls_l1 #(.AW(64)) drv64_t; + typedef pkg::cls_l1 #(.AW(128)) drv128_t; + + initial begin + // Access class-type typedef member through module-level typedef + automatic drv64_t::beat_t item1 = new; + automatic drv128_t::beat_t item2 = new; + item1.addr = 64'hDEAD_BEEF_CAFE_BABE; + + `checkd(item1.addr, 64'hDEAD_BEEF_CAFE_BABE); + `checkd($bits(item1.addr), 64); + `checkd($bits(item2.addr), 128); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_param_typedef8_noinl.py b/test_regress/t/t_class_param_typedef8_noinl.py new file mode 100644 index 000000000..2aecdefad --- /dev/null +++ b/test_regress/t/t_class_param_typedef8_noinl.py @@ -0,0 +1,20 @@ +#!/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('simulator') + +test.top_filename = "t/t_class_param_typedef8.v" + +test.compile(verilator_flags2=['--binary', '-fno-inline']) + +test.execute() + +test.passes() From 3301c7c699908c75fdb411a6b6f93a12d7793872 Mon Sep 17 00:00:00 2001 From: Leela Pakanati Date: Thu, 5 Feb 2026 22:06:39 -0600 Subject: [PATCH 3/3] Fix class parameter type using parameterized class typedef (#5461) When a class parameter type references a typedef inside a parameterized class (e.g., `class cls2 #(cls1#()::bool_t param)`), the RefDType is deferred during linkDotPrimary but never resolved before V3Param tries to traverse the type chain. Add resolveParamClassRefDType() to specialize the referenced class and resolve the typedef in cellPinCleanup before skipRefToNonRefp() is called. --- src/V3Param.cpp | 65 +++++++++++++++++++ test_regress/t/t_class_param_typedef7.py | 18 +++++ test_regress/t/t_class_param_typedef7.v | 61 +++++++++++++++++ .../t/t_class_param_typedef7_noinl.py | 20 ++++++ 4 files changed, 164 insertions(+) create mode 100644 test_regress/t/t_class_param_typedef7.py create mode 100644 test_regress/t/t_class_param_typedef7.v create mode 100644 test_regress/t/t_class_param_typedef7_noinl.py diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 710e83355..b2b360ce9 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -1009,10 +1009,65 @@ class ParamProcessor final { } } + // Resolve a deferred RefDType referencing a typedef inside a parameterized class (#5461). + // When a formal parameter's type is `cls1#()::bool_t`, the RefDType for `bool_t` is + // left unresolved during linkDotPrimary. We resolve it here by specializing the class + // and looking up the typedef in the specialized class. + void resolveParamClassRefDType(AstNodeDType* dtypep) { + AstRefDType* const refp = dtypep ? VN_CAST(dtypep, RefDType) : nullptr; + if (!refp) return; + if (refp->typedefp() || refp->refDTypep()) return; // Already resolved + + AstClassOrPackageRef* const classRefp + = VN_CAST(refp->classOrPackageOpp(), ClassOrPackageRef); + if (!classRefp) return; + + AstClass* srcClassp = VN_CAST(classRefp->classOrPackageNodep(), Class); + if (srcClassp && srcClassp->hasGParam()) { + // Direct class reference with parameters on the ClassOrPackageRef + // (classRefDeparam also resolves the RefDType via its backp() check + // when the ClassOrPackageRef is a child of RefDType) + classRefDeparam(classRefp, srcClassp); + return; + } + + // ClassOrPackageRef targets a typedef to a parameterized class (e.g., + // typedef cls#(N) alias; typedef alias::member_t m_t;). + // Follow the typedef chain to find the ClassRefDType with the actual class. + AstNode* targetp = classRefp->classOrPackageNodep(); + while (const AstTypedef* const tdefp = VN_CAST(targetp, Typedef)) + targetp = tdefp->subDTypep(); + if (AstNodeDType* const dtargetp = VN_CAST(targetp, NodeDType)) + targetp = dtargetp->skipRefOrNullp(); + if (!targetp) return; + AstClassRefDType* const classRefDTypep = VN_CAST(targetp, ClassRefDType); + if (!classRefDTypep) return; + srcClassp = classRefDTypep->classp(); + if (!srcClassp) return; + + AstClass* newClassp = srcClassp; + if (srcClassp->hasGParam()) { + // Specialize using the ClassRefDType (which has the actual parameters) + classRefDeparam(classRefDTypep, srcClassp); + newClassp = classRefDTypep->classp(); + } + // else: class already specialized, use it directly + + // Look up the member typedef in the specialized class + AstTypedef* const typedefp + = VN_CAST(m_memberMap.findMember(newClassp, refp->name()), Typedef); + if (typedefp) { + refp->typedefp(typedefp); + refp->classOrPackagep(newClassp); + } + } + void cellPinCleanup(AstNode* nodep, AstPin* pinp, AstNodeModule* srcModp, string& longnamer, bool& any_overridesr) { if (!pinp->exprp()) return; // No-connect if (AstVar* const modvarp = pinp->modVarp()) { + // Resolve deferred formal param type referencing parameterized class typedef (#5461) + resolveParamClassRefDType(modvarp->subDTypep()); if (!modvarp->isGParam()) { pinp->v3fatalSrc("Attempted parameter setting of non-parameter: Param " << pinp->prettyNameQ() << " of " << nodep->prettyNameQ()); @@ -1071,6 +1126,16 @@ class ParamProcessor final { // 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()); + // Resolve deferred formal param type referencing parameterized class typedef (#5461) + resolveParamClassRefDType(modvarp->subDTypep()); + // Also resolve deferred RefDType inside the pin expression's typedef chain. + // Handles: typedef cls#(N) alias; typedef alias::member_t m_t; mod#(.T(m_t)) + // where alias::member_t was deferred during linkDotPrimary (#5977). + if (const AstRefDType* const pinRefp = VN_CAST(pinp->exprp(), RefDType)) { + if (const AstTypedef* const tdefp = pinRefp->typedefp()) { + resolveParamClassRefDType(tdefp->subDTypep()); + } + } AstNodeDType* rawTypep = VN_CAST(pinp->exprp(), NodeDType); if (rawTypep) V3Width::widthParamsEdit(rawTypep); diff --git a/test_regress/t/t_class_param_typedef7.py b/test_regress/t/t_class_param_typedef7.py new file mode 100644 index 000000000..6fe7d000c --- /dev/null +++ b/test_regress/t/t_class_param_typedef7.py @@ -0,0 +1,18 @@ +#!/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('simulator') + +test.compile(verilator_flags2=["--binary"]) + +test.execute() + +test.passes() diff --git a/test_regress/t/t_class_param_typedef7.v b/test_regress/t/t_class_param_typedef7.v new file mode 100644 index 000000000..257e7d805 --- /dev/null +++ b/test_regress/t/t_class_param_typedef7.v @@ -0,0 +1,61 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain. +// SPDX-FileCopyrightText: 2026 Leela Pakanati +// SPDX-License-Identifier: CC0-1.0 + +// Test for issue #5461: Class parameter type using cls#()::typedef + +// verilog_format: off +`define stop $stop +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +// verilog_format: on + +// Basic parameterized class with a typedef +class cls1 #(bit PARAM = 0); + typedef bit bool_t; + typedef logic [7:0] byte_t; +endclass + +// Class whose parameter TYPE is a typedef from a parameterized class (default params) +class cls2 #(cls1#()::bool_t PARAM = 1); + function int get_param(); + return int'(PARAM); + endfunction +endclass + +// Class using non-default params for the referenced class +class cls3 #(cls1#(1)::bool_t PARAM = 0); + function int get_param(); + return int'(PARAM); + endfunction +endclass + +// Class using a wider typedef from the parameterized class +class cls4 #(cls1#()::byte_t PARAM = 8'hAB); + function int get_param(); + return int'(PARAM); + endfunction +endclass + +module t; + initial begin + automatic cls2#(1) obj2 = new; + automatic cls3#(1) obj3 = new; + automatic cls4#(8'hCD) obj4 = new; + // Default param + automatic cls2 obj2d = new; + + `checkd(obj2.get_param(), 1); + `checkd(obj3.get_param(), 1); + `checkd(obj4.get_param(), 'hCD); + `checkd(obj2d.get_param(), 1); + + `checkd($bits(cls1#()::bool_t), 1); + `checkd($bits(cls1#(1)::bool_t), 1); + `checkd($bits(cls1#()::byte_t), 8); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_param_typedef7_noinl.py b/test_regress/t/t_class_param_typedef7_noinl.py new file mode 100644 index 000000000..32db738ac --- /dev/null +++ b/test_regress/t/t_class_param_typedef7_noinl.py @@ -0,0 +1,20 @@ +#!/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('simulator') + +test.top_filename = "t/t_class_param_typedef7.v" + +test.compile(verilator_flags2=['--binary', '-fno-inline']) + +test.execute() + +test.passes()