Support `specparam` (#5767).

This commit is contained in:
Wilson Snyder 2025-06-28 08:23:43 -04:00
parent 189d094202
commit f508dadc97
13 changed files with 113 additions and 36 deletions

View File

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

View File

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

View File

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

View File

@ -426,6 +426,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
%token<strp> yaID__ETC "IDENTIFIER"
%token<strp> yaID__CC "IDENTIFIER-::"
%token<strp> yaID__LEX "IDENTIFIER-in-lex"
%token<strp> yaID__PATHPULSE "IDENTIFIER-for-pathpulse"
%token<strp> yaID__aINST "IDENTIFIER-for-instance"
%token<strp> yaID__aTYPE "IDENTIFIER-for-type"
// Can't predecode aFUNCTION, can declare after use
@ -5787,12 +5788,42 @@ specify_itemList<nodep>: // IEEE: { specify_item }
;
specify_item<nodep>: // ==IEEE: specify_item
system_timing_check { $$ = $1; }
specparam_declaration { $$ = $1; }
| system_timing_check { $$ = $1; }
| junkToSemiList ';' { $$ = nullptr; }
;
specparam_declaration<nodep>: // ==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<varp>: // ==IEEE: list_of_specparam_assignments
specparam_assignment { $$ = $1; }
| list_of_specparam_assignments ',' specparam_assignment { $$ = $1->addNext($3); }
;
specparam_assignment<varp>: // ==IEEE: specparam_assignment
idNotPathpulse sigAttrListE '=' minTypMax
{ $$ = VARDONEA($<fl>1, *$1, nullptr, $2);
if ($4) $$->valuep($4); }
// // IEEE: pulse_control_specparam
| idPathpulse sigAttrListE '=' '(' minTypMax ',' minTypMax ')'
{ $$ = VARDONEA($<fl>1, *$1, nullptr, $2);
if ($5) $$->valuep($5); }
;
system_timing_check<nodep>: // ==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<strp>:
yaID__ETC { $$ = $1; $<fl>$ = $<fl>1; }
| yaID__PATHPULSE { $$ = $1; $<fl>$ = $<fl>1; }
| idRandomize { $$ = $1; $<fl>$ = $<fl>1; }
;
idAny<strp>: // Any kind of identifier
yaID__ETC { $$ = $1; $<fl>$ = $<fl>1; }
| yaID__PATHPULSE { $$ = $1; $<fl>$ = $<fl>1; }
| yaID__aINST { $$ = $1; $<fl>$ = $<fl>1; }
| yaID__aTYPE { $$ = $1; $<fl>$ = $<fl>1; }
| idRandomize { $$ = $1; $<fl>$ = $<fl>1; }
;
idNotPathpulse<strp>: // Id excluding specparam PATHPULSE$, IEEE: part of specparam_assignment
yaID__ETC { $$ = $1; $<fl>$ = $<fl>1; }
| idRandomize { $$ = $1; $<fl>$ = $<fl>1; }
;
idPathpulse<strp>: // Id for specparam PATHPULSE$, IEEE: part of pulse_control_specparam
yaID__PATHPULSE { $$ = $1; $<fl>$ = $<fl>1; }
;
idAnyAsParseRef<parseRefp>: // Any kind of identifier as a ParseRef
idAny
{ $$ = new AstParseRef{$<fl>1, VParseRefExp::PX_TEXT, *$1}; }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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