From f508dadc9734f332b7ba33bc1feca05cd30a22fc Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 28 Jun 2025 08:23:43 -0400 Subject: [PATCH] Support `specparam` (#5767). --- Changes | 1 + src/V3Ast.h | 13 +++-- src/V3ParseImp.cpp | 8 +++- src/verilog.y | 48 +++++++++++++++++-- test_regress/t/t_flag_wpedantic_bad.out | 2 +- test_regress/t/t_lint_pkg_colon_bad.out | 2 +- test_regress/t/t_param_type_bad.out | 2 +- test_regress/t/t_pp_circ_subst_bad.out | 2 +- test_regress/t/t_pp_circ_subst_bad2.out | 2 +- .../{t_specparam_unsup.py => t_specparam.py} | 4 +- test_regress/t/t_specparam.v | 44 +++++++++++++++++ test_regress/t/t_specparam_unsup.out | 5 -- test_regress/t/t_specparam_unsup.v | 16 ------- 13 files changed, 113 insertions(+), 36 deletions(-) rename test_regress/t/{t_specparam_unsup.py => t_specparam.py} (87%) create mode 100644 test_regress/t/t_specparam.v delete mode 100644 test_regress/t/t_specparam_unsup.out delete mode 100644 test_regress/t/t_specparam_unsup.v diff --git a/Changes b/Changes index 0395f46bf..797a9217f 100644 --- a/Changes +++ b/Changes @@ -19,6 +19,7 @@ Verilator 5.037 devel * Support SARIF JSON diagnostic output with `--diagnostics-sarif`. (#6017) * Support 1-bit params with -G and -pvalue (#6051) (#6082). [Paul Swirhun] * Support `$timeformat` with missing arguments (#6113). [Alex Solomatnikov] +* Support `specparam` (#5767). * Support parameter forward types. * Add PROCINITASSIGN on initial assignments to process variables (#2481). [Niraj Menon] * Add BADVLTPRAGMA on unknown Verilator pragmas (#5945). [Shou-Li Hsu] diff --git a/src/V3Ast.h b/src/V3Ast.h index 54ebbe1a8..e7ae60bf6 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -923,6 +923,7 @@ public: UNKNOWN, GPARAM, LPARAM, + SPECPARAM, GENVAR, VAR, // Reg, integer, logic, etc SUPPLY0, @@ -951,9 +952,10 @@ public: constexpr operator en() const { return m_e; } const char* ascii() const { static const char* const names[] - = {"?", "GPARAM", "LPARAM", "GENVAR", "VAR", "SUPPLY0", "SUPPLY1", - "WIRE", "WREAL", "TRIAND", "TRIOR", "TRIWIRE", "TRI0", "TRI1", - "PORT", "BLOCKTEMP", "MODULETEMP", "STMTTEMP", "XTEMP", "IFACEREF", "MEMBER"}; + = {"?", "GPARAM", "LPARAM", "SPECPARAM", "GENVAR", "VAR", + "SUPPLY0", "SUPPLY1", "WIRE", "WREAL", "TRIAND", "TRIOR", + "TRIWIRE", "TRI0", "TRI1", "PORT", "BLOCKTEMP", "MODULETEMP", + "STMTTEMP", "XTEMP", "IFACEREF", "MEMBER"}; return names[m_e]; } bool isParam() const { return m_e == GPARAM || m_e == LPARAM; } @@ -983,8 +985,8 @@ public: return (m_e == BLOCKTEMP || m_e == MODULETEMP || m_e == STMTTEMP || m_e == XTEMP); } bool isVPIAccessible() const { - return (m_e == VAR || m_e == GPARAM || m_e == LPARAM || m_e == PORT || m_e == WIRE - || m_e == TRI0 || m_e == TRI1); + return (m_e == VAR || m_e == GPARAM || m_e == LPARAM || m_e == SPECPARAM || m_e == PORT + || m_e == WIRE || m_e == TRI0 || m_e == TRI1); } const char* traceSigKind() const { @@ -993,6 +995,7 @@ public: /* UNKNOWN: */ "", // Should not be traced /* GPARAM: */ "PARAMETER", /* LPARAM: */ "PARAMETER", + /* SPECPARAM: */ "PARAMETER", /* GENVAR: */ "PARAMETER", /* VAR: */ "VAR", /* SUPPLY0: */ "SUPPLY0", diff --git a/src/V3ParseImp.cpp b/src/V3ParseImp.cpp index 3c2f7bc93..e50935548 100644 --- a/src/V3ParseImp.cpp +++ b/src/V3ParseImp.cpp @@ -688,7 +688,13 @@ void V3ParseImp::tokenPipelineSym() { int token = yylval.token; if (token == yaID__LEX || token == yaID__CC || token == yaID__aTYPE) { importIfInStd(yylval.fl, *(yylval.strp)); - if (token == yaID__LEX) token = yaID__ETC; + if (token == yaID__LEX) { + if (VString::startsWith(*(yylval.strp), "PATHPULSE__024a")) { + token = yaID__PATHPULSE; + } else { + token = yaID__ETC; + } + } } m_afterColonColon = token == yP_COLONCOLON; yylval.token = token; diff --git a/src/verilog.y b/src/verilog.y index 832af56b7..ccbb6c084 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -426,6 +426,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yaID__ETC "IDENTIFIER" %token yaID__CC "IDENTIFIER-::" %token yaID__LEX "IDENTIFIER-in-lex" +%token yaID__PATHPULSE "IDENTIFIER-for-pathpulse" %token yaID__aINST "IDENTIFIER-for-instance" %token yaID__aTYPE "IDENTIFIER-for-type" // Can't predecode aFUNCTION, can declare after use @@ -5787,12 +5788,42 @@ specify_itemList: // IEEE: { specify_item } ; specify_item: // ==IEEE: specify_item - system_timing_check { $$ = $1; } + specparam_declaration { $$ = $1; } + | system_timing_check { $$ = $1; } | junkToSemiList ';' { $$ = nullptr; } ; specparam_declaration: // ==IEEE: specparam_declaration - ySPECPARAM junkToSemiList ';' { $$ = nullptr; } + specparam_declarationFront list_of_specparam_assignments ';' + { $$ = $2; } + ; + +specparam_declarationFront: // IEEE: part of specparam_declaration + // // Front must execute first so VARDTYPE is ready before list of vars + ySPECPARAM + { VARRESET_NONLIST(SPECPARAM); + AstNodeDType* dtp = new AstBasicDType{$1, VBasicDTypeKwd::DOUBLE}; + VARDTYPE(dtp); } + | ySPECPARAM packed_dimension + { VARRESET_NONLIST(SPECPARAM); + AstNodeDType* const dtp = GRAMMARP->addRange( + new AstBasicDType{$2->fileline(), LOGIC_IMPLICIT}, $2, true); + VARDTYPE(dtp); } + ; + +list_of_specparam_assignments: // ==IEEE: list_of_specparam_assignments + specparam_assignment { $$ = $1; } + | list_of_specparam_assignments ',' specparam_assignment { $$ = $1->addNext($3); } + ; + +specparam_assignment: // ==IEEE: specparam_assignment + idNotPathpulse sigAttrListE '=' minTypMax + { $$ = VARDONEA($1, *$1, nullptr, $2); + if ($4) $$->valuep($4); } + // // IEEE: pulse_control_specparam + | idPathpulse sigAttrListE '=' '(' minTypMax ',' minTypMax ')' + { $$ = VARDONEA($1, *$1, nullptr, $2); + if ($5) $$->valuep($5); } ; system_timing_check: // ==IEEE: system_timing_check @@ -5851,7 +5882,7 @@ junkToSemiList: ; junkToSemi: - BISONPRE_NOT(';',yENDSPECIFY,yENDMODULE,yD_SETUPHOLD) { } + BISONPRE_NOT(';',yD_SETUPHOLD,yENDMODULE,yENDSPECIFY,ySPECPARAM) { } | error {} ; @@ -5860,16 +5891,27 @@ junkToSemi: id: yaID__ETC { $$ = $1; $$ = $1; } + | yaID__PATHPULSE { $$ = $1; $$ = $1; } | idRandomize { $$ = $1; $$ = $1; } ; idAny: // Any kind of identifier yaID__ETC { $$ = $1; $$ = $1; } + | yaID__PATHPULSE { $$ = $1; $$ = $1; } | yaID__aINST { $$ = $1; $$ = $1; } | yaID__aTYPE { $$ = $1; $$ = $1; } | idRandomize { $$ = $1; $$ = $1; } ; +idNotPathpulse: // Id excluding specparam PATHPULSE$, IEEE: part of specparam_assignment + yaID__ETC { $$ = $1; $$ = $1; } + | idRandomize { $$ = $1; $$ = $1; } + ; + +idPathpulse: // Id for specparam PATHPULSE$, IEEE: part of pulse_control_specparam + yaID__PATHPULSE { $$ = $1; $$ = $1; } + ; + idAnyAsParseRef: // Any kind of identifier as a ParseRef idAny { $$ = new AstParseRef{$1, VParseRefExp::PX_TEXT, *$1}; } diff --git a/test_regress/t/t_flag_wpedantic_bad.out b/test_regress/t/t_flag_wpedantic_bad.out index c955c513e..0942660a4 100644 --- a/test_regress/t/t_flag_wpedantic_bad.out +++ b/test_regress/t/t_flag_wpedantic_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_flag_wpedantic_bad.v:8:8: syntax error, unexpected global, expecting IDENTIFIER or do or final or randomize +%Error: t/t_flag_wpedantic_bad.v:8:8: syntax error, unexpected global 8 | reg global; | ^~~~~~ ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. diff --git a/test_regress/t/t_lint_pkg_colon_bad.out b/test_regress/t/t_lint_pkg_colon_bad.out index b0e76fd25..184edb770 100644 --- a/test_regress/t/t_lint_pkg_colon_bad.out +++ b/test_regress/t/t_lint_pkg_colon_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_lint_pkg_colon_bad.v:8:8: syntax error, unexpected IDENTIFIER-::, expecting IDENTIFIER or do or final or randomize +%Error: t/t_lint_pkg_colon_bad.v:8:8: syntax error, unexpected IDENTIFIER-:: 8 | reg mispkgb::bar_t b; | ^~~~~~~ ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. diff --git a/test_regress/t/t_param_type_bad.out b/test_regress/t/t_param_type_bad.out index a9bf7634b..4e3c370a5 100644 --- a/test_regress/t/t_param_type_bad.out +++ b/test_regress/t/t_param_type_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_param_type_bad.v:9:27: syntax error, unexpected INTEGER NUMBER, expecting IDENTIFIER or IDENTIFIER-for-instance or IDENTIFIER-for-type or randomize +%Error: t/t_param_type_bad.v:9:27: syntax error, unexpected INTEGER NUMBER 9 | localparam type bad2 = 2; | ^ ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. diff --git a/test_regress/t/t_pp_circ_subst_bad.out b/test_regress/t/t_pp_circ_subst_bad.out index d45c9c044..d84fad3d0 100644 --- a/test_regress/t/t_pp_circ_subst_bad.out +++ b/test_regress/t/t_pp_circ_subst_bad.out @@ -1,4 +1,4 @@ %Error: t/t_pp_circ_subst_bad.v:8:80001: Too many preprocessor tokens on a line (>40000); perhaps recursive `define ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. -%Error: t/t_pp_circ_subst_bad.v:8:5: syntax error, unexpected IDENTIFIER-for-type, expecting IDENTIFIER or do or final or randomize +%Error: t/t_pp_circ_subst_bad.v:8:5: syntax error, unexpected IDENTIFIER-for-type %Error: Exiting due to diff --git a/test_regress/t/t_pp_circ_subst_bad2.out b/test_regress/t/t_pp_circ_subst_bad2.out index 5af9aac7f..03c509a5c 100644 --- a/test_regress/t/t_pp_circ_subst_bad2.out +++ b/test_regress/t/t_pp_circ_subst_bad2.out @@ -1,4 +1,4 @@ %Error: t/t_pp_circ_subst_bad.v:8:40002: Too many preprocessor tokens on a line (>20000); perhaps recursive `define ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. -%Error: t/t_pp_circ_subst_bad.v:8:5: syntax error, unexpected IDENTIFIER-for-type, expecting IDENTIFIER or do or final or randomize +%Error: t/t_pp_circ_subst_bad.v:8:5: syntax error, unexpected IDENTIFIER-for-type %Error: Exiting due to diff --git a/test_regress/t/t_specparam_unsup.py b/test_regress/t/t_specparam.py similarity index 87% rename from test_regress/t/t_specparam_unsup.py rename to test_regress/t/t_specparam.py index e33e10acf..c78c28783 100755 --- a/test_regress/t/t_specparam_unsup.py +++ b/test_regress/t/t_specparam.py @@ -11,6 +11,8 @@ import vltest_bootstrap test.scenarios('vlt') -test.lint(fails=True, expect_filename=test.golden_filename) +test.compile(verilator_flags2=['--binary']) + +test.execute() test.passes() diff --git a/test_regress/t/t_specparam.v b/test_regress/t/t_specparam.v new file mode 100644 index 000000000..67ab38219 --- /dev/null +++ b/test_regress/t/t_specparam.v @@ -0,0 +1,44 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2025 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; + specify + specparam tdevice_PU = 3e8; + specparam Tdelay11 = 1.1; + // verilator lint_off MINTYPMAXDLY + specparam Tmintypmax = 1.0:1.1:1.2; + specparam PATHPULSE$a$b = (3.0:3.1:3.2, 4.0:4.1:4.2); + specparam randomize = 1; // Special parser corner-case + endspecify + + // Support in other simulators is limited for module specparams + specparam Tmod34 = 3.4, Tmod35 = 3.5; // IEEE 6.20.5 allowed in body + // Support in other simulators is limited for ranged specparams + specparam [5:2] Tranged = 4'b1011; + + localparam real PATHPULSE$normal$var = 6.78; + + reg PoweredUp; + wire DelayIn, DelayOut; + + assign #tdevice_PU DelayOut = DelayIn; + + initial begin + PoweredUp = 1'b0; + #tdevice_PU PoweredUp = 1'b1; + if (Tdelay11 != 1.1) $stop; +`ifdef VERILATOR + if (Tmintypmax != 1.1) $stop; + if (PATHPULSE$a$b != 3.1) $stop; +`endif + if (Tranged != 4'b1011) $stop; + if (Tmod34 != 3.4) $stop; + if (Tmod35 != 3.5) $stop; + if (PATHPULSE$normal$var != 6.78) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_specparam_unsup.out b/test_regress/t/t_specparam_unsup.out deleted file mode 100644 index 776aaa222..000000000 --- a/test_regress/t/t_specparam_unsup.out +++ /dev/null @@ -1,5 +0,0 @@ -%Error: t/t_specparam_unsup.v:14:8: Can't find definition of variable: 'tdevice_PU' - 14 | #tdevice_PU PoweredUp = 1'b1; - | ^~~~~~~~~~ - ... See the manual at https://verilator.org/verilator_doc.html?v=latest for more assistance. -%Error: Exiting due to diff --git a/test_regress/t/t_specparam_unsup.v b/test_regress/t/t_specparam_unsup.v deleted file mode 100644 index cd0a08072..000000000 --- a/test_regress/t/t_specparam_unsup.v +++ /dev/null @@ -1,16 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2025 by Wilson Snyder. -// SPDX-License-Identifier: CC0-1.0 - -module t (); - reg PoweredUp; - specify - specparam tdevice_PU = 3e8; - endspecify - initial begin - PoweredUp = 1'b0; - #tdevice_PU PoweredUp = 1'b1; - end -endmodule