diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 2718e5c37..3a1819911 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -3553,7 +3553,8 @@ private: if (nodep->user3SetOnce()) return; if (AstNode* const cpackagep = nodep->classOrPackageOpp()) { if (AstClassOrPackageRef* const cpackagerefp = VN_CAST(cpackagep, ClassOrPackageRef)) { - if (cpackagerefp->paramsp()) { + const AstClass* const clsp = VN_CAST(cpackagerefp->classOrPackageNodep(), Class); + if (clsp && clsp->isParameterized()) { // Unable to link before the instantiation of parameter classes. // The class reference node has to be visited to properly link parameters. iterate(cpackagep); diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 2502bc459..1539ce3c4 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -18,7 +18,7 @@ // For each cell: // If parameterized, // Determine all parameter widths, constant values. -// (Interfaces also matter, as if an interface is parameterized +// (Interfaces also matter, as if a module is parameterized // this effectively changes the width behavior of all that // reference the iface.) // Clone module cell calls, renaming with __{par1}_{par2}_... @@ -227,6 +227,10 @@ class ParamProcessor final : public VNDeleter { // // (0=not processed, 1=iterated, but no number, // // 65+ parameter numbered) // NODE STATE - Shared with ParamVisitor + // AstClass::user4p() // AstClass* Unchanged copy of the parameterized class node. + // The class node may be modified according to parameter + // values and an unchanged copy is needed to instantiate + // classes with different parameters. // AstNodeModule::user5() // bool True if processed // AstGenFor::user5() // bool True if processed // AstVar::user5() // bool True if constant propagated @@ -574,8 +578,8 @@ class ParamProcessor final : public VNDeleter { // Note all module internal variables will be re-linked to the new modules by clone // However links outside the module (like on the upper cells) will not. AstNodeModule* newmodp; - if (srcModp->user2p()) { - newmodp = VN_CAST(srcModp->user2p()->cloneTree(false), NodeModule); + if (srcModp->user4p()) { + newmodp = VN_CAST(srcModp->user4p()->cloneTree(false), NodeModule); } else { newmodp = srcModp->cloneTree(false); } @@ -617,7 +621,7 @@ class ParamProcessor final : public VNDeleter { // Grab all I/O so we can remap our pins later // Note we allow multiple users of a parameterized model, // thus we need to stash this info. - collectPins(clonemapp, newmodp, srcModp->user2p()); + collectPins(clonemapp, newmodp, srcModp->user4p()); // Relink parameter vars to the new module relinkPins(clonemapp, paramsp); // Fix any interface references @@ -856,14 +860,14 @@ class ParamProcessor final : public VNDeleter { if (!any_overrides) { UINFO(8, "Cell parameters all match original values, skipping expansion.\n"); - // If it's the first use of the default instance, create a copy and store it in user2p. - // user2p will also be used to check if the default instance is used. - if (!srcModpr->user2p() && VN_IS(srcModpr, Class)) { + // If it's the first use of the default instance, create a copy and store it in user4p. + // user4p will also be used to check if the default instance is used. + if (!srcModpr->user4p() && VN_IS(srcModpr, Class)) { AstClass* classCopyp = VN_AS(srcModpr, Class)->cloneTree(false); // It is a temporary copy of the original class node, stored in order to create // another instances. It is needed only during class instantiation. pushDeletep(classCopyp); - srcModpr->user2p(classCopyp); + srcModpr->user4p(classCopyp); storeOriginalParams(classCopyp); } } else if (AstNodeModule* const paramedModp @@ -972,11 +976,7 @@ public: class ParamVisitor final : public VNVisitor { // NODE STATE - // AstNodeModule::user1 -> bool: already fixed level - // AstClass::user2p -> AstClass*: Unchanged copy of the parameterized class node. - // The class node may be modified according to parameter - // values and an unchanged copy is needed to instantiate - // classes with different parameters. + // AstNodeModule::user1 -> bool: already fixed level (temporary) // STATE ParamProcessor m_processor; // De-parameterize a cell, build modules @@ -1435,7 +1435,7 @@ public: for (AstNodeModule* const modp : modps) netlistp->addModulesp(modp); for (AstClass* const classp : m_paramClasses) { - if (!classp->user2p()) { + if (!classp->user4p()) { // The default value isn't referenced, so it can be removed VL_DO_DANGLING(pushDeletep(classp->unlinkFrBack()), classp); } else { diff --git a/test_regress/t/t_class_param.v b/test_regress/t/t_class_param.v index e16f409a6..ae0a4386a 100644 --- a/test_regress/t/t_class_param.v +++ b/test_regress/t/t_class_param.v @@ -138,9 +138,9 @@ module t (/*AUTOARG*/); Wrap #(.P(16)) w16; Wrap2 #(.P(32)) w32; SelfRefClassTypeParam src_logic; - SelfRefClassTypeParam::self_int_t src_int; + SelfRefClassTypeParam#()::self_int_t src_int; SelfRefClassIntParam src1; - SelfRefClassIntParam::self_int_t src10; + SelfRefClassIntParam#()::self_int_t src10; IntQueue qi; ClsWithParamField cls_param_field; DictOperator #(DictWrapper) dict_op; diff --git a/test_regress/t/t_class_param_mod.v b/test_regress/t/t_class_param_mod.v index e117fa2ec..93ebe28e6 100644 --- a/test_regress/t/t_class_param_mod.v +++ b/test_regress/t/t_class_param_mod.v @@ -60,9 +60,9 @@ endclass Wrap #(.P(16)) w16; Wrap2 #(.P(32)) w32; SelfRefClassTypeParam src_logic; - SelfRefClassTypeParam::self_int_t src_int; + SelfRefClassTypeParam#()::self_int_t src_int; SelfRefClassIntParam src1; - SelfRefClassIntParam::self_int_t src10; + SelfRefClassIntParam#()::self_int_t src10; initial begin c12 = new; c4 = new; diff --git a/test_regress/t/t_class_param_subtype.v b/test_regress/t/t_class_param_subtype.v new file mode 100644 index 000000000..6799c43e6 --- /dev/null +++ b/test_regress/t/t_class_param_subtype.v @@ -0,0 +1,49 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Anthony Donlon. +// SPDX-License-Identifier: CC0-1.0 + +// Test for bug4281 + +class CParam #(parameter PARAM=10); + typedef int type_t; +endclass + +class CParam2 #(parameter PARAM=10); + typedef int type_t; + + typedef logic [PARAM-1:0] type2_t; +endclass + +`ifdef CONSTSIM +module sub(); + parameter N = 32; + for (genvar i = 0; i < N/8; i = i + 1) begin + initial begin + end + end + // Test for bug4281, usage conflict of user2 with constant simulator in V3Param.cpp +endmodule +`endif + +module t; +`ifdef BAD_PAREN + CParam::type_t val_0 = 100; +`else + CParam#()::type_t val_0 = 100; +`endif + CParam2#()::type_t val_2 = 200; + +`ifdef CONSTSIM + + sub i_sub(); +`endif + + initial begin + if (val_0 != 100) $stop; + if (val_2 != 200) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_param_subtype_bad_paren.out b/test_regress/t/t_class_param_subtype_bad_paren.out new file mode 100644 index 000000000..a9ec2d035 --- /dev/null +++ b/test_regress/t/t_class_param_subtype_bad_paren.out @@ -0,0 +1,5 @@ +%Error: t/t_class_param_subtype.v:32:5: Reference to parameterized class without #() (IEEE 1800-2017 8.25.1) + : ... Suggest use 'CParam#()' + 32 | CParam::type_t val_0 = 100; + | ^~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_param_subtype_bad_paren.pl b/test_regress/t/t_class_param_subtype_bad_paren.pl new file mode 100755 index 000000000..13944a9e5 --- /dev/null +++ b/test_regress/t/t_class_param_subtype_bad_paren.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 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 + +scenarios(linter => 1); + +top_filename("t/t_class_param_subtype.v"); + +lint( + fails => 1, + v_flags2 => ['+define+BAD_PAREN'], + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_param_subtype_constsim.pl b/test_regress/t/t_class_param_subtype_constsim.pl new file mode 100755 index 000000000..2336fb402 --- /dev/null +++ b/test_regress/t/t_class_param_subtype_constsim.pl @@ -0,0 +1,24 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 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 + +scenarios(simulator => 1); + +top_filename("t/t_class_param_subtype.v"); + +compile( + v_flags2 => ['+define+CONSTSIM'], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1;