diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 6a5295ad1..35d0ec859 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1775,7 +1775,7 @@ void AstCellInlineScope::dumpJson(std::ostream& str) const { dumpJsonGen(str); } bool AstClass::isCacheableChild(const AstNode* nodep) { - return VN_IS(nodep, Var) + return VN_IS(nodep, Var) || VN_IS(nodep, Typedef) || (VN_IS(nodep, Constraint) && !VN_AS(nodep, Constraint)->isExternProto()) || VN_IS(nodep, EnumItemRef) || (VN_IS(nodep, NodeFTask) && !VN_AS(nodep, NodeFTask)->isExternProto()) diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 0687fb103..ffb712a10 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -54,6 +54,7 @@ #include "V3EmitV.h" #include "V3Hasher.h" #include "V3LinkDotIfaceCapture.h" +#include "V3MemberMap.h" #include "V3Os.h" #include "V3Parse.h" #include "V3Simulate.h" @@ -291,6 +292,9 @@ class ParamProcessor final { std::vector> m_classParams; std::unordered_map m_paramIndex; + // member names cached for fast lookup + VMemberMap m_memberMap; + // METHODS static void makeSmallNames(AstNodeModule* modp) { @@ -846,7 +850,10 @@ class ParamProcessor final { pinExprp->replaceWith(new AstConst{pinp->fileline(), AstConst::WidthedValue{}, modvarp->width(), 0}); VL_DO_DANGLING(pinExprp->deleteTree(), pinExprp); - } else if (origp && exprp->sameTree(origp)) { + } else if (origp + && (exprp->sameTree(origp) + || (exprp->num().width() == origp->num().width() + && ParameterizedHierBlocks::areSame(exprp, origp)))) { // Setting parameter to its default value. Just ignore it. // This prevents making additional modules, and makes coverage more // obvious as it won't show up under a unique module page name. @@ -1246,17 +1253,13 @@ class ParamProcessor final { AstRefDType* const refDTypep = VN_CAST(nodep->backp(), RefDType); AstClass* const newClassp = refDTypep ? VN_CAST(newModp, Class) : nullptr; if (newClassp && !refDTypep->typedefp() && !refDTypep->subDTypep()) { - for (AstNode* itemp = newClassp->membersp(); itemp; itemp = itemp->nextp()) { - if (AstTypedef* const typedefp = VN_CAST(itemp, Typedef)) { - if (typedefp->name() == refDTypep->name()) { - refDTypep->typedefp(typedefp); - refDTypep->classOrPackagep(newClassp); - UINFO(9, "Resolved parameterized class typedef: " - << refDTypep->name() << " -> " << typedefp << " in " - << newClassp->name()); - break; - } - } + if (AstTypedef* const typedefp + = VN_CAST(m_memberMap.findMember(newClassp, refDTypep->name()), Typedef)) { + refDTypep->typedefp(typedefp); + refDTypep->classOrPackagep(newClassp); + UINFO(9, "Resolved parameterized class typedef: " << refDTypep->name() << " -> " + << typedefp << " in " + << newClassp->name()); } } return newModp; diff --git a/test_regress/t/t_class_param_typedef5.v b/test_regress/t/t_class_param_typedef5.v index fb3fdbe92..29a7e9942 100644 --- a/test_regress/t/t_class_param_typedef5.v +++ b/test_regress/t/t_class_param_typedef5.v @@ -16,8 +16,8 @@ class func_c #(parameter p_width=4); endclass module modA #(parameter p_width = 7)( - input func_c#(p_width)::my_type_t sig_a - ,output func_c#(p_width)::my_type_t sig_b + input func_c#(p_width)::my_type_t sig_a, + output func_c#(p_width)::my_type_t sig_b ); assign sig_b.data = func_c#(p_width)::func(sig_a); endmodule @@ -28,8 +28,8 @@ module the_top(); func_c#(Size)::my_type_t sig_a, sig_b, sig_c; modA #(.p_width(Size)) modA( - .sig_a(sig_a) - ,.sig_b(sig_b) + .sig_a(sig_a), + .sig_b(sig_b) ); initial begin diff --git a/test_regress/t/t_class_param_typedef6.v b/test_regress/t/t_class_param_typedef6.v index 1be0a302f..53f200f0e 100644 --- a/test_regress/t/t_class_param_typedef6.v +++ b/test_regress/t/t_class_param_typedef6.v @@ -35,7 +35,8 @@ endmodule module the_top #() (); typedef logic [7:0] my_t; - typedef pipeline_class #(my_t)::if_id_t if_id_t; + typedef pipeline_class #(my_t)::if_id_t if_id2_t; + typedef if_id2_t if_id_t; pipe_reg #(if_id_t) if_id_reg(); initial begin diff --git a/test_regress/t/t_param_pattern3.py b/test_regress/t/t_param_pattern3.py new file mode 100755 index 000000000..c6e56559a --- /dev/null +++ b/test_regress/t/t_param_pattern3.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_param_pattern3.v b/test_regress/t/t_param_pattern3.v new file mode 100644 index 000000000..9a846b82f --- /dev/null +++ b/test_regress/t/t_param_pattern3.v @@ -0,0 +1,34 @@ +// 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 + +`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); + +class Class_A #(parameter int myparam = 32); +endclass + +module tb_top; + localparam int WIDTH_A=32; + localparam int WIDTH_B=2*16; + + Class_A#(32) a; + Class_A#(WIDTH_A) b; + Class_A#(WIDTH_B) c; + + initial begin + #1; + + a = b; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule