Fix using type in parameterized classes without #() (#4281) (#4440)

* Check whether a class is parameterized or not with AstClass::isParameterized method

* Fix usage conflict of user2 pointer in V3Param.cpp
This commit is contained in:
Anthony Donlon 2023-08-26 21:06:26 +08:00 committed by GitHub
parent e66b28823d
commit 63db60f646
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 120 additions and 19 deletions

View File

@ -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);

View File

@ -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 {

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;