diff --git a/Changes b/Changes index 72c929dc7..d8f1d20b5 100644 --- a/Changes +++ b/Changes @@ -17,6 +17,7 @@ Verilator 5.037 devel * Support constrained random for associative arrays (#5985) (#5986). [Yilou Wang] * Support assignments to concatenations with impure RHS (#6002). [Ryszard Rozak, Antmicro Ltd.] * Support SARIF JSON diagnostic output with `--diagnostics-sarif`. (#6017) +* Support parameter forward types. * Add BADVLTPRAGMA on unknown Verilator pragmas (#5945). [Shou-Li Hsu] * Add PROCINITASSIGN on initial assignments to process variables (#2481). [Niraj Menon] * Fix filename backslash escapes in C code (#5947). diff --git a/src/V3Ast.h b/src/V3Ast.h index 2a4f84617..46a0c6f0d 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -287,6 +287,33 @@ public: // ###################################################################### +class VFwdType final { +public: + enum en : uint8_t { NONE, ENUM, STRUCT, UNION, CLASS, INTERFACE_CLASS }; + enum en m_e; + const char* ascii() const { + static const char* const names[] + = {"none", "enum", "struct", "union", "class", "interface class"}; + return names[m_e]; + } + VFwdType() + : m_e{NONE} {} + // cppcheck-suppress noExplicitConstructor + constexpr VFwdType(en _e) + : m_e{_e} {} + explicit VFwdType(int _e) + : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning + constexpr operator en() const { return m_e; } +}; +constexpr bool operator==(const VFwdType& lhs, const VFwdType& rhs) { return lhs.m_e == rhs.m_e; } +constexpr bool operator==(const VFwdType& lhs, VFwdType::en rhs) { return lhs.m_e == rhs; } +constexpr bool operator==(VFwdType::en lhs, const VFwdType& rhs) { return lhs == rhs.m_e; } +inline std::ostream& operator<<(std::ostream& os, const VFwdType& rhs) { + return os << rhs.ascii(); +} + +// ###################################################################### + class VSigning final { public: enum en : uint8_t { diff --git a/src/V3AstNodeDType.h b/src/V3AstNodeDType.h index b27494736..3b4aa1f84 100644 --- a/src/V3AstNodeDType.h +++ b/src/V3AstNodeDType.h @@ -1006,12 +1006,14 @@ class AstParamTypeDType final : public AstNodeDType { // A parameter type statement; much like a var or typedef // @astgen op1 := childDTypep : Optional[AstNodeDType] const VVarType m_varType; // Type of variable (for localparam vs. param) + const VFwdType m_fwdType; // Forward type for lint check string m_name; // Name of variable public: - AstParamTypeDType(FileLine* fl, VVarType type, const string& name, VFlagChildDType, - AstNodeDType* dtp) + AstParamTypeDType(FileLine* fl, VVarType type, VFwdType fwdType, const string& name, + VFlagChildDType, AstNodeDType* dtp) : ASTGEN_SUPER_ParamTypeDType(fl) , m_varType{type} + , m_fwdType{fwdType} , m_name{name} { childDTypep(dtp); // Only for parser dtypep(nullptr); // V3Width will resolve @@ -1036,6 +1038,7 @@ public: bool hasDType() const override VL_MT_SAFE { return true; } void name(const string& flag) override { m_name = flag; } VVarType varType() const { return m_varType; } // * = Type of variable + VFwdType fwdType() const { return m_fwdType; } bool isParam() const { return true; } bool isGParam() const { return (varType() == VVarType::GPARAM); } bool isCompound() const override { @@ -1047,9 +1050,11 @@ class AstParseTypeDType final : public AstNodeDType { // Parents: VAR // During parsing, this indicates the type of a parameter is a "parameter type" // e.g. the data type is a container of any data type + const VFwdType m_fwdType; // Forward type for lint check public: - explicit AstParseTypeDType(FileLine* fl) - : ASTGEN_SUPER_ParseTypeDType(fl) {} + explicit AstParseTypeDType(FileLine* fl, VFwdType fwdType = VFwdType::NONE) + : ASTGEN_SUPER_ParseTypeDType(fl) + , m_fwdType{fwdType} {} ASTGEN_MEMBERS_AstParseTypeDType; AstNodeDType* dtypep() const VL_MT_STABLE { return nullptr; } // METHODS @@ -1061,6 +1066,7 @@ public: v3fatalSrc("call isCompound on subdata type, not reference"); return false; } + VFwdType fwdType() const { return m_fwdType; } }; class AstQueueDType final : public AstNodeDType { // Queue array data type, ie "[ $ ]" diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 1c650b51e..16050d065 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -322,7 +322,7 @@ class LinkParseVisitor final : public VNVisitor { nodep->v3warn(NEWERSTD, "Parameter requires default value, or use IEEE 1800-2009 or later."); } - if (VN_IS(nodep->subDTypep(), ParseTypeDType)) { + if (AstParseTypeDType* const ptypep = VN_CAST(nodep->subDTypep(), ParseTypeDType)) { // It's a parameter type. Use a different node type for this. AstNode* dtypep = nodep->valuep(); if (dtypep) { @@ -331,8 +331,9 @@ class LinkParseVisitor final : public VNVisitor { dtypep = new AstVoidDType{nodep->fileline()}; } AstNode* const newp = new AstParamTypeDType{ - nodep->fileline(), nodep->varType(), nodep->name(), VFlagChildDType{}, - new AstRequireDType{nodep->fileline(), dtypep}}; + nodep->fileline(), nodep->varType(), + ptypep->fwdType(), nodep->name(), + VFlagChildDType{}, new AstRequireDType{nodep->fileline(), dtypep}}; nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); return; diff --git a/src/V3Param.cpp b/src/V3Param.cpp index bfee3e4fe..b0a12f8dd 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -782,6 +782,24 @@ class ParamProcessor final { // Constify may have caused pinp->exprp to change rawTypep = VN_AS(pinp->exprp(), NodeDType); exprp = rawTypep->skipRefToNonRefp(); + bool ok = true; + switch (modvarp->fwdType()) { + case VFwdType::NONE: ok = true; break; + case VFwdType::ENUM: ok = VN_IS(exprp, EnumDType); break; + case VFwdType::STRUCT: ok = VN_IS(exprp, StructDType); break; + case VFwdType::UNION: ok = VN_IS(exprp, UnionDType); break; + case VFwdType::CLASS: ok = VN_IS(exprp, ClassRefDType); break; + case VFwdType::INTERFACE_CLASS: // TODO: Over permissive for now: + ok = VN_IS(exprp, ClassRefDType); + break; + default: modvarp->v3fatalSrc("Bad case"); + } + if (!ok) { + pinp->v3error("Parameter type expression type " + << exprp->prettyDTypeNameQ() + << " violates parameter's forwarding type '" + << modvarp->fwdType().ascii() << "'"); + } if (exprp->similarDType(origp)) { // Setting parameter to its default value. Just ignore it. // This prevents making additional modules, and makes coverage more diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index c7895d3f3..9dededfdb 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -125,6 +125,7 @@ struct V3ParseBisonYYSType final { VAttrType::en attrtypeen; VAssertType::en asserttypeen; VAssertDirectiveType::en assertdirectivetypeen; + VFwdType::en fwdtype; VLifetime::en lifetime; VStrength::en strength; diff --git a/src/verilog.y b/src/verilog.y index 74c322350..3e4ed1251 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -1916,9 +1916,11 @@ parameter_declarationFront: // IEEE: local_ or parameter_declaration w/o ass parameter_declarationTypeFront: // IEEE: local_ or parameter_declaration w/o assignment // // Front must execute first so VARDTYPE is ready before list of vars - varParamReset yTYPE__ETC { /*VARRESET-in-varParam*/ VARDTYPE(new AstParseTypeDType{$2}); } - | varParamReset yTYPE__ETC forward_type { /*VARRESET-in-varParam*/ VARDTYPE(new AstParseTypeDType{$2}); - BBUNSUP($1, "Unsupported: 'parameter type' forward type"); } + varParamReset yTYPE__ETC + { /*VARRESET-in-varParam*/ VARDTYPE(new AstParseTypeDType{$2}); } + | varParamReset yTYPE__ETC forward_type + { /*VARRESET-in-varParam*/ + AstNodeDType* const dtp = new AstParseTypeDType{$2, $3}; VARDTYPE(dtp); } ; parameter_port_declarationFrontE: // IEEE: local_ or parameter_port_declaration w/o assignment @@ -1939,20 +1941,26 @@ parameter_port_declarationTypeFrontE: // IEEE: parameter_port_declaration w/o as // // IEEE: parameter_declaration (minus assignment) // // IEEE: local_parameter_declaration (minus assignment) // // Front must execute first so VARDTYPE is ready before list of vars - varParamReset yTYPE__ETC { /*VARRESET-in-varParam*/ VARDTYPE(new AstParseTypeDType{$2}); } - | varParamReset yTYPE__ETC forward_type { /*VARRESET-in-varParam*/ VARDTYPE(new AstParseTypeDType{$2}); - BBUNSUP($1, "Unsupported: 'parameter type' forward type"); } - | yTYPE__ETC { /*VARRESET-in-varParam*/ VARDTYPE(new AstParseTypeDType{$1}); } - | yTYPE__ETC forward_type { /*VARRESET-in-varParam*/ VARDTYPE(new AstParseTypeDType{$1}); - BBUNSUP($1, "Unsupported: 'parameter type' forward type"); } + varParamReset yTYPE__ETC + { /*VARRESET-in-varParam*/ + AstNodeDType* const dtp = new AstParseTypeDType{$2}; VARDTYPE(dtp); } + | varParamReset yTYPE__ETC forward_type + { /*VARRESET-in-varParam*/ + AstNodeDType* const dtp = new AstParseTypeDType{$2, $3}; VARDTYPE(dtp); } + | yTYPE__ETC + { /*VARRESET-in-varParam*/ + AstNodeDType* const dtp = new AstParseTypeDType{$1}; VARDTYPE(dtp); } + | yTYPE__ETC forward_type + { /*VARRESET-in-varParam*/ + AstNodeDType* const dtp = new AstParseTypeDType{$1, $2}; VARDTYPE(dtp); } ; -forward_type: // ==IEEE: forward_type - yENUM { } - | ySTRUCT { } - | yUNION { } - | yCLASS { } - | yINTERFACE yCLASS { } +forward_type: // ==IEEE: forward_type + yENUM { $$ = VFwdType::ENUM; } + | ySTRUCT { $$ = VFwdType::STRUCT; } + | yUNION { $$ = VFwdType::UNION; } + | yCLASS { $$ = VFwdType::CLASS; } + | yINTERFACE yCLASS { $$ = VFwdType::INTERFACE_CLASS; } ; net_declaration: // IEEE: net_declaration - excluding implict diff --git a/test_regress/t/t_concat_string.py b/test_regress/t/t_concat_string.py index 2b17673d7..262a0d4b4 100755 --- a/test_regress/t/t_concat_string.py +++ b/test_regress/t/t_concat_string.py @@ -12,7 +12,7 @@ import vltest_bootstrap test.scenarios('simulator') -signal.alarm(5) # 5s timeout +signal.alarm(15) # 15s timeout test.compile() diff --git a/test_regress/t/t_param_type_fwd.out b/test_regress/t/t_param_type_fwd.out deleted file mode 100644 index e2b38098f..000000000 --- a/test_regress/t/t_param_type_fwd.out +++ /dev/null @@ -1,32 +0,0 @@ -%Error-UNSUPPORTED: t/t_param_type_fwd.v:10:4: Unsupported: 'parameter type' forward type - 10 | parameter type enum E_t; - | ^~~~~~~~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_param_type_fwd.v:11:4: Unsupported: 'parameter type' forward type - 11 | parameter type struct S_t; - | ^~~~~~~~~ -%Error-UNSUPPORTED: t/t_param_type_fwd.v:12:4: Unsupported: 'parameter type' forward type - 12 | parameter type union U_t; - | ^~~~~~~~~ -%Error-UNSUPPORTED: t/t_param_type_fwd.v:13:4: Unsupported: 'parameter type' forward type - 13 | parameter type class C_t; - | ^~~~~~~~~ -%Error-UNSUPPORTED: t/t_param_type_fwd.v:14:4: Unsupported: 'parameter type' forward type - 14 | parameter type interface class IC_t; - | ^~~~~~~~~ -%Error-UNSUPPORTED: t/t_param_type_fwd.v:17:13: Unsupported: 'parameter type' forward type - 17 | class Cls #(parameter type enum E_t, - | ^~~~~~~~~ -%Error-UNSUPPORTED: t/t_param_type_fwd.v:18:13: Unsupported: 'parameter type' forward type - 18 | parameter type struct S_t, - | ^~~~~~~~~ -%Error-UNSUPPORTED: t/t_param_type_fwd.v:19:13: Unsupported: 'parameter type' forward type - 19 | parameter type union U_t, - | ^~~~~~~~~ -%Error-UNSUPPORTED: t/t_param_type_fwd.v:20:13: Unsupported: 'parameter type' forward type - 20 | parameter type class C_t, - | ^~~~~~~~~ -%Error-UNSUPPORTED: t/t_param_type_fwd.v:21:13: Unsupported: 'parameter type' forward type - 21 | parameter type interface class IC_t); - | ^~~~~~~~~ -%Error: Exiting due to diff --git a/test_regress/t/t_param_type_fwd.py b/test_regress/t/t_param_type_fwd.py index e33e10acf..f81c3d68d 100755 --- a/test_regress/t/t_param_type_fwd.py +++ b/test_regress/t/t_param_type_fwd.py @@ -11,6 +11,6 @@ import vltest_bootstrap test.scenarios('vlt') -test.lint(fails=True, expect_filename=test.golden_filename) +test.lint() test.passes() diff --git a/test_regress/t/t_param_type_fwd.v b/test_regress/t/t_param_type_fwd.v index 375495398..f84a2d567 100644 --- a/test_regress/t/t_param_type_fwd.v +++ b/test_regress/t/t_param_type_fwd.v @@ -4,9 +4,19 @@ // without warranty, 2024 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 -// Test for trace file interface aliasing +typedef enum { ONE } e_t; -module m; +typedef struct { int m_i; } s_t; + +typedef union { int m_i; } u_t; + +class c_t; +endclass + +interface class ic_t; +endclass + +module sub; parameter type enum E_t; parameter type struct S_t; parameter type union U_t; @@ -21,6 +31,10 @@ class Cls #(parameter type enum E_t, parameter type interface class IC_t); endclass -module t (/*AUTOARG*/); - // TODO proper test +module t; + sub #(.E_t(e_t), .S_t(s_t), .U_t(u_t), .C_t(c_t), .IC_t(ic_t)) sub(); + Cls #(.E_t(e_t), .S_t(s_t), .U_t(u_t), .C_t(c_t), .IC_t(ic_t)) c; + initial begin + c = new; + end endmodule diff --git a/test_regress/t/t_param_type_fwd_bad.out b/test_regress/t/t_param_type_fwd_bad.out new file mode 100644 index 000000000..42da02e1f --- /dev/null +++ b/test_regress/t/t_param_type_fwd_bad.out @@ -0,0 +1,42 @@ +%Error: t/t_param_type_fwd_bad.v:25:11: Parameter type expression type 'int' violates parameter's forwarding type 'enum' + : ... note: In instance 't' + 25 | sub #(.E_t(int_t), .S_t(int_t), .U_t(int_t), .C_t(int_t), .IC_t(int_t)) sub(); + | ^~~ + ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. +%Error: t/t_param_type_fwd_bad.v:25:24: Parameter type expression type 'int' violates parameter's forwarding type 'struct' + : ... note: In instance 't' + 25 | sub #(.E_t(int_t), .S_t(int_t), .U_t(int_t), .C_t(int_t), .IC_t(int_t)) sub(); + | ^~~ +%Error: t/t_param_type_fwd_bad.v:25:37: Parameter type expression type 'int' violates parameter's forwarding type 'union' + : ... note: In instance 't' + 25 | sub #(.E_t(int_t), .S_t(int_t), .U_t(int_t), .C_t(int_t), .IC_t(int_t)) sub(); + | ^~~ +%Error: t/t_param_type_fwd_bad.v:25:50: Parameter type expression type 'int' violates parameter's forwarding type 'class' + : ... note: In instance 't' + 25 | sub #(.E_t(int_t), .S_t(int_t), .U_t(int_t), .C_t(int_t), .IC_t(int_t)) sub(); + | ^~~ +%Error: t/t_param_type_fwd_bad.v:25:63: Parameter type expression type 'int' violates parameter's forwarding type 'interface class' + : ... note: In instance 't' + 25 | sub #(.E_t(int_t), .S_t(int_t), .U_t(int_t), .C_t(int_t), .IC_t(int_t)) sub(); + | ^~~~ +%Error: t/t_param_type_fwd_bad.v:26:11: Parameter type expression type 'int' violates parameter's forwarding type 'enum' + : ... note: In instance 't' + 26 | Cls #(.E_t(int_t), .S_t(int_t), .U_t(int_t), .C_t(int_t), .IC_t(int_t)) c; + | ^~~ +%Error: t/t_param_type_fwd_bad.v:26:24: Parameter type expression type 'int' violates parameter's forwarding type 'struct' + : ... note: In instance 't' + 26 | Cls #(.E_t(int_t), .S_t(int_t), .U_t(int_t), .C_t(int_t), .IC_t(int_t)) c; + | ^~~ +%Error: t/t_param_type_fwd_bad.v:26:37: Parameter type expression type 'int' violates parameter's forwarding type 'union' + : ... note: In instance 't' + 26 | Cls #(.E_t(int_t), .S_t(int_t), .U_t(int_t), .C_t(int_t), .IC_t(int_t)) c; + | ^~~ +%Error: t/t_param_type_fwd_bad.v:26:50: Parameter type expression type 'int' violates parameter's forwarding type 'class' + : ... note: In instance 't' + 26 | Cls #(.E_t(int_t), .S_t(int_t), .U_t(int_t), .C_t(int_t), .IC_t(int_t)) c; + | ^~~ +%Error: t/t_param_type_fwd_bad.v:26:63: Parameter type expression type 'int' violates parameter's forwarding type 'interface class' + : ... note: In instance 't' + 26 | Cls #(.E_t(int_t), .S_t(int_t), .U_t(int_t), .C_t(int_t), .IC_t(int_t)) c; + | ^~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_param_type_fwd_bad.py b/test_regress/t/t_param_type_fwd_bad.py new file mode 100755 index 000000000..e33e10acf --- /dev/null +++ b/test_regress/t/t_param_type_fwd_bad.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python3 +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2024 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('vlt') + +test.lint(fails=True, expect_filename=test.golden_filename) + +test.passes() diff --git a/test_regress/t/t_param_type_fwd_bad.v b/test_regress/t/t_param_type_fwd_bad.v new file mode 100644 index 000000000..5a9e1820f --- /dev/null +++ b/test_regress/t/t_param_type_fwd_bad.v @@ -0,0 +1,30 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2025 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +typedef int int_t; + +module sub; + parameter type enum E_t; + parameter type struct S_t; + parameter type union U_t; + parameter type class C_t; + parameter type interface class IC_t; +endmodule + +class Cls #(parameter type enum E_t, + parameter type struct S_t, + parameter type union U_t, + parameter type class C_t, + parameter type interface class IC_t); +endclass + +module t (/*AUTOARG*/); + sub #(.E_t(int_t), .S_t(int_t), .U_t(int_t), .C_t(int_t), .IC_t(int_t)) sub(); + Cls #(.E_t(int_t), .S_t(int_t), .U_t(int_t), .C_t(int_t), .IC_t(int_t)) c; + initial begin + c = new; + end +endmodule