From a1d4cd658eca25fb94872aa6538d0732a6906605 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 4 Mar 2023 11:31:58 -0500 Subject: [PATCH 001/155] devel release --- CMakeLists.txt | 2 +- Changes | 6 ++++++ configure.ac | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6c5c282ed..4cabd4fbe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ cmake_minimum_required(VERSION 3.15) cmake_policy(SET CMP0091 NEW) # Use MSVC_RUNTIME_LIBRARY to select the runtime project(Verilator - VERSION 5.008 + VERSION 5.009 HOMEPAGE_URL https://verilator.org LANGUAGES CXX ) diff --git a/Changes b/Changes index 583a85abc..bacce15df 100644 --- a/Changes +++ b/Changes @@ -8,6 +8,12 @@ The changes in each Verilator version are described below. The contributors that suggested a given feature are shown in []. Thanks! +Verilator 5.009 devel +========================== + +**Minor:** + + Verilator 5.008 2023-03-04 ========================== diff --git a/configure.ac b/configure.ac index 74d1beb5b..862537ecb 100644 --- a/configure.ac +++ b/configure.ac @@ -10,7 +10,7 @@ # Then 'make maintainer-dist' #AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### devel]) -AC_INIT([Verilator],[5.008 2023-03-04], +AC_INIT([Verilator],[5.009 devel], [https://verilator.org], [verilator],[https://verilator.org]) From 19bc257002e891b53494121b62d2c3fce7b6c024 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 5 Mar 2023 16:45:07 -0500 Subject: [PATCH 002/155] Internals: UNSUPPORTED commentary --- src/verilog.y | 21 ++++++++++++++++----- test_regress/t/t_param_mintypmax.v | 13 +++++++++++++ 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/verilog.y b/src/verilog.y index fbf1142a9..02da23103 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -3228,12 +3228,23 @@ cellparamItemE: // IEEE: named_parameter_assignment + empty | '.' idAny '(' exprOrDataType ')' { $$ = new AstPin{$2, PINNUMINC(), *$2, $4}; $$->svDotName(true); } - //UNSUP '.' idAny '(' exprOrDataType/*expr*/ ':' expr ')' { } - //UNSUP '.' idAny '(' exprOrDataType/*expr*/ ':' expr ':' expr ')' { } + //UNSUP | '.' idAny '(' exprOrDataType/*expr*/ ':' expr ')' + //UNSUP { MINTYPMAXDLYUNSUP($4); DEL($4); + //UNSUP $$ = new AstPin{$2, PINNUMINC(), *$2, $6}; + //UNSUP $$->svDotName(true); } + //UNSUP | '.' idAny '(' exprOrDataType/*expr*/ ':' expr ':' expr ')' + //UNSUP { MINTYPMAXDLYUNSUP($4); DEL($4); DEL($8); + //UNSUP $$ = new AstPin{$2, PINNUMINC(), *$2, $6}; + //UNSUP $$->svDotName(true); } // // data_type for 'parameter type' hookups - | exprOrDataType { $$ = new AstPin{FILELINE_OR_CRE($1), PINNUMINC(), "", $1}; } - //UNSUP exprOrDataType/*expr*/ ':' expr { } - //UNSUP exprOrDataType/*expr*/ ':' expr ':' expr { } + | exprOrDataType + { $$ = new AstPin{FILELINE_OR_CRE($1), PINNUMINC(), "", $1}; } + //UNSUP | exprOrDataType/*expr*/ ':' expr + //UNSUP { MINTYPMAXDLYUNSUP($1); DEL($1); + //UNSUP $$ = new AstPin{FILELINE_OR_CRE($3), PINNUMINC(), "", $3}; } + //UNSUP | exprOrDataType/*expr*/ ':' expr ':' expr + //UNSUP { MINTYPMAXDLYUNSUP($1); DEL($1); DEL($5); + //UNSUP $$ = new AstPin{FILELINE_OR_CRE($3), PINNUMINC(), "", $3}; } ; cellpinItemE: // IEEE: named_port_connection + empty diff --git a/test_regress/t/t_param_mintypmax.v b/test_regress/t/t_param_mintypmax.v index dd9acdb5a..dfc793551 100644 --- a/test_regress/t/t_param_mintypmax.v +++ b/test_regress/t/t_param_mintypmax.v @@ -8,10 +8,23 @@ module t (/*AUTOARG*/); parameter MTM = (1:2:3); + sub sub (); + //UNSUP sub #(.MTM(10:20:30)) sub20name (); + //UNSUP sub #(.MTM(100:200)) sub200name (); + //UNSUP sub #(10:20:30) sub20pos (); + //UNSUP sub #(100:200) sub200pos (); + initial begin if (MTM != 2) $stop; + //UNSUP if (sub20pos.MTM != 20) $stop; + //UNSUP if (sub200pos.MTM != 200) $stop; + //UNSUP if (sub20name.MTM != 20) $stop; + //UNSUP if (sub200name.MTM != 200) $stop; $write("*-* All Finished *-*\n"); $finish; end endmodule + +module sub #(parameter MTM = (1:2:3)) (); +endmodule From a47fd075856d11c511b68b4d7361d56e65bcf7cd Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 5 Mar 2023 16:59:24 -0500 Subject: [PATCH 003/155] Internals: Standard grammar for property_expression |-> |=>. --- src/verilog.y | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/verilog.y b/src/verilog.y index 02da23103..f7c4b3f4c 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -6007,9 +6007,7 @@ pexpr: // IEEE: property_expr (The name pexpr is important as regex ; complex_pexpr: // IEEE: part of property_expr, see comments there - expr yP_ORMINUSGT pexpr { $$ = new AstLogOr{$2, new AstLogNot{$2, $1}, $3}; } - | expr yP_OREQGT pexpr { $$ = new AstImplication{$2, $1, $3}; } - | '(' complex_pexpr ')' { $$ = $2; } + '(' complex_pexpr ')' { $$ = $2; } //UNSUP remove above, use below: // // // IEEE: sequence_expr @@ -6027,8 +6025,8 @@ complex_pexpr: // IEEE: part of property_expr, see comments there // // // IEEE: "sequence_expr yP_ORMINUSGT pexpr" // // Instead we use pexpr to prevent conflicts - //UNSUP ~o~pexpr yP_ORMINUSGT pexpr { } - //UNSUP ~o~pexpr yP_OREQGT pexpr { } + | ~o~pexpr yP_ORMINUSGT pexpr { $$ = new AstLogOr{$2, new AstLogNot{$2, $1}, $3}; } + | ~o~pexpr yP_OREQGT pexpr { $$ = new AstImplication{$2, $1, $3}; } // // // IEEE-2009: property_statement // // IEEE-2012: yIF and yCASE From ae1eb566959d1383cf354f71f9802c9d0dfc99e9 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 5 Mar 2023 17:59:17 -0500 Subject: [PATCH 004/155] Internals: Parser commentary --- src/verilog.y | 56 +++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/verilog.y b/src/verilog.y index f7c4b3f4c..81db2fb99 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -3698,19 +3698,19 @@ finc_or_dec_expression: // ==IEEE: inc_or_dec_expression BISONPRE_COPY(inc_or_dec_expression,{s/~l~/f/g}) // {copied} ; -//UNSUPsinc_or_dec_expression: // IEEE: inc_or_dec_expression (for sequence_expression) +//UNSUPsinc_or_dec_expression: // IEEE: inc_or_dec_expression (for sequence_expression) //UNSUP BISONPRE_COPY(inc_or_dec_expression,{s/~l~/s/g}) // {copied} //UNSUP ; -//UNSUPpinc_or_dec_expression: // IEEE: inc_or_dec_expression (for property_expression) +//UNSUPpinc_or_dec_expression: // IEEE: inc_or_dec_expression (for property_expression) //UNSUP BISONPRE_COPY(inc_or_dec_expression,{s/~l~/p/g}) // {copied} //UNSUP ; -//UNSUPev_inc_or_dec_expression: // IEEE: inc_or_dec_expression (for ev_expr) +//UNSUPev_inc_or_dec_expression: // IEEE: inc_or_dec_expression (for ev_expr) //UNSUP BISONPRE_COPY(inc_or_dec_expression,{s/~l~/ev_/g}) // {copied} //UNSUP ; -//UNSUPpev_inc_or_dec_expression: // IEEE: inc_or_dec_expression (for pev_expr) +//UNSUPpev_inc_or_dec_expression: // IEEE: inc_or_dec_expression (for pev_expr) //UNSUP BISONPRE_COPY(inc_or_dec_expression,{s/~l~/pev_/g}) // {copied} //UNSUP ; @@ -3751,7 +3751,7 @@ caseAttrE: | caseAttrE yVL_PARALLEL_CASE { GRAMMARP->m_caseAttrp->parallelPragma(true); } ; -//UNSUPcase_patternListE: // IEEE: case_pattern_item +//UNSUPcase_patternListE: // IEEE: case_pattern_item //UNSUP // &&& is part of expr so aliases to case_itemList //UNSUP case_itemListE { $$ = $1; } //UNSUP ; @@ -3804,7 +3804,7 @@ value_range: // ==IEEE: value_range | '[' expr ':' expr ']' { $$ = new AstInsideRange{$1, $2, $4}; } ; -//UNSUPcovergroup_value_range: // ==IEEE-2012: covergroup_value_range +//UNSUPcovergroup_value_range: // ==IEEE-2012: covergroup_value_range //UNSUP cgexpr { $$ = $1; } //UNSUP | '[' cgexpr ':' cgexpr ']' { } //UNSUP ; @@ -4311,7 +4311,7 @@ elaboration_system_task_guts: // IEEE: part of elaboration_system_task | yD_FATAL '(' expr ',' exprListE ')' { $$ = new AstElabDisplay{$1, VDisplayType::DT_FATAL, $5}; DEL($3); } ; -//UNSUPproperty_actual_arg: // ==IEEE: property_actual_arg +//UNSUPproperty_actual_arg: // ==IEEE: property_actual_arg //UNSUP // // IEEE: property_expr //UNSUP // // IEEE: sequence_actual_arg //UNSUP pev_expr { $$ = $1; } @@ -4872,7 +4872,7 @@ fexpr: // For use as first part of statement (disam BISONPRE_COPY(expr,{s/~l~/f/g; s/~r~/f/g; s/~f__IGNORE~/__IGNORE/g;}) // {copied} ; -//UNSUPev_expr: // IEEE: event_expression +//UNSUPev_expr: // IEEE: event_expression //UNSUP // // for yOR/, see event_expression //UNSUP // //UNSUP // // IEEE: [ edge_identifier ] expression [ yIFF expression ] @@ -4890,7 +4890,7 @@ fexpr: // For use as first part of statement (disam //UNSUP // //UNSUP //--------------------- //UNSUP // // IEEE: expr -//UNSUP | BISONPRE_COPY(expr,{s/~l~/ev_/g; s/~r~/ev_/g; s/~p~/ev_/g; s/~noPar__IGNORE~/yP_PAR__IGNORE /g;}) // {copied} +//UNSUP | BISONPRE_COPY(expr,{s/~l~/ev_/g; s/~r~/ev_/g; s/~p~/ev_/g; s/~noPar__IGNORE~'.'/yP_PAR__IGNORE /g;}) // {copied} //UNSUP // //UNSUP // // IEEE: '(' event_expression ')' //UNSUP // // expr:'(' x ')' conflicts with event_expression:'(' event_expression ')' @@ -4931,19 +4931,19 @@ fexprOkLvalue: // exprOkLValue, For use as first part of st BISONPRE_COPY(exprOkLvalue,{s/~l~/f/g}) // {copied} ; -//UNSUPsexprOkLvalue: // exprOkLValue, For use by sequence_expr +//UNSUPsexprOkLvalue: // exprOkLValue, For use by sequence_expr //UNSUP BISONPRE_COPY(exprOkLvalue,{s/~l~/s/g}) // {copied} //UNSUP ; -//UNSUPpexprOkLvalue: // exprOkLValue, For use by property_expr +//UNSUPpexprOkLvalue: // exprOkLValue, For use by property_expr //UNSUP BISONPRE_COPY(exprOkLvalue,{s/~l~/p/g}) // {copied} //UNSUP ; -//UNSUPev_exprOkLvalue: // exprOkLValue, For use by ev_expr +//UNSUPev_exprOkLvalue: // exprOkLValue, For use by ev_expr //UNSUP BISONPRE_COPY(exprOkLvalue,{s/~l~/ev_/g}) // {copied} //UNSUP ; -//UNSUPpev_exprOkLvalue: // exprOkLValue, For use by ev_expr +//UNSUPpev_exprOkLvalue: // exprOkLValue, For use by ev_expr //UNSUP BISONPRE_COPY(exprOkLvalue,{s/~l~/pev_/g}) // {copied} //UNSUP ; @@ -4974,19 +4974,19 @@ fexprScope: // exprScope, For use as first part of state BISONPRE_COPY(exprScope,{s/~l~/f/g}) // {copied} ; -//UNSUPsexprScope: // exprScope, For use by sequence_expr +//UNSUPsexprScope: // exprScope, For use by sequence_expr //UNSUP BISONPRE_COPY(exprScope,{s/~l~/s/g}) // {copied} //UNSUP ; -//UNSUPpexprScope: // exprScope, For use by property_expr +//UNSUPpexprScope: // exprScope, For use by property_expr //UNSUP BISONPRE_COPY(exprScope,{s/~l~/p/g}) // {copied} //UNSUP ; -//UNSUPev_exprScope: // exprScope, For use by ev_expr +//UNSUPev_exprScope: // exprScope, For use by ev_expr //UNSUP BISONPRE_COPY(exprScope,{s/~l~/ev_/g}) // {copied} //UNSUP ; -//UNSUPpev_exprScope: // exprScope, For use by ev_expr +//UNSUPpev_exprScope: // exprScope, For use by ev_expr //UNSUP BISONPRE_COPY(exprScope,{s/~l~/pev_/g}) // {copied} //UNSUP ; @@ -5051,7 +5051,7 @@ argsExprListE: // IEEE: part of list_of_arguments | argsExprListE ',' argsExprOneE { $$ = $1->addNext($3); } ; -//UNSUPpev_argsExprListE: // IEEE: part of list_of_arguments - pev_expr at bottom +//UNSUPpev_argsExprListE: // IEEE: part of list_of_arguments - pev_expr at bottom //UNSUP pev_argsExprOneE { $$ = $1; } //UNSUP | pev_argsExprListE ',' pev_argsExprOneE { $$ = addNextNull($1, $3); } //UNSUP ; @@ -5061,7 +5061,7 @@ argsExprOneE: // IEEE: part of list_of_arguments | expr { $$ = new AstArg{$1->fileline(), "", $1}; } ; -//UNSUPpev_argsExprOneE: // IEEE: part of list_of_arguments - pev_expr at bottom +//UNSUPpev_argsExprOneE: // IEEE: part of list_of_arguments - pev_expr at bottom //UNSUP /*empty*/ { $$ = nullptr; } // ,, is legal in list_of_arguments //UNSUP | pev_expr { $$ = $1; } //UNSUP ; @@ -5071,7 +5071,7 @@ argsDottedList: // IEEE: part of list_of_arguments | argsDottedList ',' argsDotted { $$ = addNextNull($1, $3); } ; -//UNSUPpev_argsDottedList: // IEEE: part of list_of_arguments - pev_expr at bottom +//UNSUPpev_argsDottedList: // IEEE: part of list_of_arguments - pev_expr at bottom //UNSUP pev_argsDotted { $$ = $1; } //UNSUP | pev_argsDottedList ',' pev_argsDotted { $$ = addNextNull($1, $3); } //UNSUP ; @@ -5081,7 +5081,7 @@ argsDotted: // IEEE: part of list_of_arguments | '.' idAny '(' expr ')' { $$ = new AstArg{$2, *$2, $4}; } ; -//UNSUPpev_argsDotted: // IEEE: part of list_of_arguments - pev_expr at bottom +//UNSUPpev_argsDotted: // IEEE: part of list_of_arguments - pev_expr at bottom //UNSUP '.' idAny '(' ')' { $$ = new AstArg{$2, *$2, nullptr}; } //UNSUP | '.' idAny '(' pev_expr ')' { $$ = new AstArg{$2, *$2, $4}; } //UNSUP ; @@ -5469,7 +5469,7 @@ variable_lvalueConcList: // IEEE: part of variable_lvalue: '{' variab | variable_lvalueConcList ',' variable_lvalue { $$ = new AstConcat{$2, $1, $3}; } ; -//UNSUPvariable_lvalueList: // IEEE: part of variable_lvalue: variable_lvalue { ',' variable_lvalue } +//UNSUPvariable_lvalueList: // IEEE: part of variable_lvalue: variable_lvalue { ',' variable_lvalue } //UNSUP variable_lvalue { $$ = $1; } //UNSUP | variable_lvalueList ',' variable_lvalue { $$ = addNextNull($1, $3); } //UNSUP ; @@ -5864,7 +5864,7 @@ property_declarationBody: // IEEE: part of property_declaration | property_spec ';' { $$ = $1; } ; -//UNSUPassertion_variable_declarationList: // IEEE: part of assertion_variable_declaration +//UNSUPassertion_variable_declarationList: // IEEE: part of assertion_variable_declaration //UNSUP assertion_variable_declaration { $$ = $1; } //UNSUP | assertion_variable_declarationList assertion_variable_declaration { } //UNSUP ; @@ -5988,7 +5988,7 @@ property_spec: // IEEE: property_spec //UNSUP | BISONPRE_COPY_ONCE(sexpr,{s/~p~s/pev_/g; }) // {copied} //UNSUP // //UNSUP //============= expr rules copied for pev_expr -//UNSUP | BISONPRE_COPY_ONCE(expr,{s/~l~/pev_/g; s/~p~/pev_/g; s/~noPar__IGNORE~/yP_PAR__IGNORE /g; }) // {copied} +//UNSUP | BISONPRE_COPY_ONCE(expr,{s/~l~/pev_/g; s/~p~/pev_/g; s/~noPar__IGNORE~'.'/yP_PAR__IGNORE /g; }) // {copied} //UNSUP ; pexpr: // IEEE: property_expr (The name pexpr is important as regexps just add an "p" to expr.) @@ -6069,10 +6069,10 @@ complex_pexpr: // IEEE: part of property_expr, see comments there //UNSUP BISONPRE_COPY_ONCE(sexpr,{s/~p~s/p/g; }) // {copied} // //============= expr rules copied for property_expr - //UNSUP BISONPRE_COPY_ONCE(expr,{s/~l~/p/g; s/~p~/p/g; s/~noPar__IGNORE~/yP_PAR__IGNORE /g; }) // {copied} + //UNSUP BISONPRE_COPY_ONCE(expr,{s/~l~/p/g; s/~p~/p/g; s/~noPar__IGNORE~'.'/yP_PAR__IGNORE /g; }) // {copied} ; -//UNSUPsexpr: // ==IEEE: sequence_expr (The name sexpr is important as regexps just add an "s" to expr.) +//UNSUPsexpr: // ==IEEE: sequence_expr (The name sexpr is important as regexps just add an "s" to expr.) //UNSUP // // ********* RULES COPIED IN sequence_exprProp //UNSUP // // For precedence, see IEEE 17.7.1 //UNSUP // @@ -6116,7 +6116,7 @@ complex_pexpr: // IEEE: part of property_expr, see comments there //UNSUP | clocking_event ~p~sexpr %prec prSEQ_CLOCKING { } //UNSUP // //UNSUP //============= expr rules copied for sequence_expr -//UNSUP | BISONPRE_COPY_ONCE(expr,{s/~l~/s/g; s/~p~/s/g; s/~noPar__IGNORE~/yP_PAR__IGNORE /g; }) // {copied} +//UNSUP | BISONPRE_COPY_ONCE(expr,{s/~l~/s/g; s/~p~/s/g; s/~noPar__IGNORE~'.'/yP_PAR__IGNORE /g; }) // {copied} //UNSUP ; //UNSUPcycle_delay_range: // IEEE: ==cycle_delay_range @@ -6195,7 +6195,7 @@ complex_pexpr: // IEEE: part of property_expr, see comments there //UNSUP PARSEP->covergroupCb($1, $1, $2); } //UNSUP ; -//UNSUPcgexpr: // IEEE-2012: covergroup_expression, before that just expression +//UNSUPcgexpr: // IEEE-2012: covergroup_expression, before that just expression //UNSUP expr { $$ = $1; } //UNSUP ; From 15dcd326f8b7da571d6dfbe9806f720277689674 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 5 Mar 2023 18:30:43 -0500 Subject: [PATCH 005/155] Internals: Parse weak/strong but do not lex --- src/verilog.y | 122 +++++++++++++++++++++++++------------------------- 1 file changed, 62 insertions(+), 60 deletions(-) diff --git a/src/verilog.y b/src/verilog.y index 81db2fb99..494b3d532 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -722,7 +722,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token ySTATIC__ETC "static" %token ySTATIC__LEX "static-in-lex" %token ySTRING "string" -//UNSUP %token ySTRONG "strong" +%token ySTRONG "strong" %token ySTRONG0 "strong0" %token ySTRONG1 "strong1" %token ySTRUCT "struct" @@ -779,7 +779,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yWAIT "wait" //UNSUP %token yWAIT_ORDER "wait_order" %token yWAND "wand" -//UNSUP %token yWEAK "weak" +%token yWEAK "weak" %token yWEAK0 "weak0" %token yWEAK1 "weak1" %token yWHILE "while" @@ -1005,7 +1005,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yP_COLON__BEGIN ":-begin" %token yP_COLON__FORK ":-fork" -//UNSUP %token yP_PAR__IGNORE "(-ignored" // Used when sequence_expr:expr:( is ignored +%token yP_PAR__IGNORE "(-ignored" // Used when sequence_expr:expr:( is ignored %token yP_PAR__STRENGTH "(-for-strength" %token yP_LTMINUSGT "<->" @@ -3698,9 +3698,9 @@ finc_or_dec_expression: // ==IEEE: inc_or_dec_expression BISONPRE_COPY(inc_or_dec_expression,{s/~l~/f/g}) // {copied} ; -//UNSUPsinc_or_dec_expression: // IEEE: inc_or_dec_expression (for sequence_expression) -//UNSUP BISONPRE_COPY(inc_or_dec_expression,{s/~l~/s/g}) // {copied} -//UNSUP ; +sinc_or_dec_expression: // IEEE: inc_or_dec_expression (for sequence_expression) + BISONPRE_COPY(inc_or_dec_expression,{s/~l~/s/g}) // {copied} + ; //UNSUPpinc_or_dec_expression: // IEEE: inc_or_dec_expression (for property_expression) //UNSUP BISONPRE_COPY(inc_or_dec_expression,{s/~l~/p/g}) // {copied} @@ -4931,9 +4931,9 @@ fexprOkLvalue: // exprOkLValue, For use as first part of st BISONPRE_COPY(exprOkLvalue,{s/~l~/f/g}) // {copied} ; -//UNSUPsexprOkLvalue: // exprOkLValue, For use by sequence_expr -//UNSUP BISONPRE_COPY(exprOkLvalue,{s/~l~/s/g}) // {copied} -//UNSUP ; +sexprOkLvalue: // exprOkLValue, For use by sequence_expr + BISONPRE_COPY(exprOkLvalue,{s/~l~/s/g}) // {copied} + ; //UNSUPpexprOkLvalue: // exprOkLValue, For use by property_expr //UNSUP BISONPRE_COPY(exprOkLvalue,{s/~l~/p/g}) // {copied} @@ -4974,9 +4974,9 @@ fexprScope: // exprScope, For use as first part of state BISONPRE_COPY(exprScope,{s/~l~/f/g}) // {copied} ; -//UNSUPsexprScope: // exprScope, For use by sequence_expr -//UNSUP BISONPRE_COPY(exprScope,{s/~l~/s/g}) // {copied} -//UNSUP ; +sexprScope: // exprScope, For use by sequence_expr + BISONPRE_COPY(exprScope,{s/~l~/s/g}) // {copied} + ; //UNSUPpexprScope: // exprScope, For use by property_expr //UNSUP BISONPRE_COPY(exprScope,{s/~l~/p/g}) // {copied} @@ -6017,8 +6017,10 @@ complex_pexpr: // IEEE: part of property_expr, see comments there // // Expanded below // | yNOT pexpr %prec prNEGATION { $$ = new AstLogNot{$1, $2}; } - //UNSUP ySTRONG '(' sexpr ')' { } - //UNSUP yWEAK '(' sexpr ')' { } + | ySTRONG '(' sexpr ')' + { $$ = $3; BBUNSUP($2, "Unsupported: strong (in property expression)"); } + | yWEAK '(' sexpr ')' + { $$ = $3; BBUNSUP($2, "Unsupported: weak (in property expression)"); } // // IEEE: pexpr yOR pexpr // // IEEE: pexpr yAND pexpr // // Under ~p~sexpr and/or ~p~sexpr @@ -6072,52 +6074,52 @@ complex_pexpr: // IEEE: part of property_expr, see comments there //UNSUP BISONPRE_COPY_ONCE(expr,{s/~l~/p/g; s/~p~/p/g; s/~noPar__IGNORE~'.'/yP_PAR__IGNORE /g; }) // {copied} ; -//UNSUPsexpr: // ==IEEE: sequence_expr (The name sexpr is important as regexps just add an "s" to expr.) -//UNSUP // // ********* RULES COPIED IN sequence_exprProp -//UNSUP // // For precedence, see IEEE 17.7.1 -//UNSUP // -//UNSUP // // IEEE: "cycle_delay_range sequence_expr { cycle_delay_range sequence_expr }" -//UNSUP // // IEEE: "sequence_expr cycle_delay_range sequence_expr { cycle_delay_range sequence_expr }" -//UNSUP // // Both rules basically mean we can repeat sequences, so make it simpler: -//UNSUP cycle_delay_range sexpr %prec yP_POUNDPOUND { } -//UNSUP | ~p~sexpr cycle_delay_range sexpr %prec prPOUNDPOUND_MULTI { } -//UNSUP // -//UNSUP // // IEEE: expression_or_dist [ boolean_abbrev ] -//UNSUP // // Note expression_or_dist includes "expr"! -//UNSUP // // sexpr/*sexpression_or_dist*/ --- Hardcoded below -//UNSUP | ~p~sexpr/*sexpression_or_dist*/ boolean_abbrev { } -//UNSUP // -//UNSUP // // IEEE: "sequence_instance [ sequence_abbrev ]" -//UNSUP // // version without sequence_abbrev looks just like normal function call -//UNSUP // // version w/sequence_abbrev matches above; -//UNSUP // // expression_or_dist:expr:func boolean_abbrev:sequence_abbrev -//UNSUP // -//UNSUP // // IEEE: '(' expression_or_dist {',' sequence_match_item } ')' [ boolean_abbrev ] -//UNSUP // // IEEE: '(' sexpr {',' sequence_match_item } ')' [ sequence_abbrev ] -//UNSUP // // As sequence_expr includes expression_or_dist, and boolean_abbrev includes sequence_abbrev: -//UNSUP // // '(' sequence_expr {',' sequence_match_item } ')' [ boolean_abbrev ] -//UNSUP // // "'(' sexpr ')' boolean_abbrev" matches "[sexpr:'(' expr ')'] boolean_abbrev" so we can drop it -//UNSUP | '(' ~p~sexpr ')' { $$ = $1; $$ = ...; } -//UNSUP | '(' ~p~sexpr ',' sequence_match_itemList ')' { } -//UNSUP // -//UNSUP // // AND/OR are between pexprs OR sexprs -//UNSUP | ~p~sexpr yAND ~p~sexpr { $$ = $1; $$ = ...; } -//UNSUP | ~p~sexpr yOR ~p~sexpr { $$ = $1; $$ = ...; } -//UNSUP // // Intersect always has an sexpr rhs -//UNSUP | ~p~sexpr yINTERSECT sexpr { $$ = $1; $$ = ...; } -//UNSUP // -//UNSUP | yFIRST_MATCH '(' sexpr ')' { } -//UNSUP | yFIRST_MATCH '(' sexpr ',' sequence_match_itemList ')' { } -//UNSUP | ~p~sexpr/*sexpression_or_dist*/ yTHROUGHOUT sexpr { } -//UNSUP // // Below pexpr's are really sequence_expr, but avoid conflict -//UNSUP // // IEEE: sexpr yWITHIN sexpr -//UNSUP | ~p~sexpr yWITHIN sexpr { $$ = $1; $$ = ...; } -//UNSUP // // Note concurrent_assertion had duplicate rule for below -//UNSUP | clocking_event ~p~sexpr %prec prSEQ_CLOCKING { } -//UNSUP // -//UNSUP //============= expr rules copied for sequence_expr -//UNSUP | BISONPRE_COPY_ONCE(expr,{s/~l~/s/g; s/~p~/s/g; s/~noPar__IGNORE~'.'/yP_PAR__IGNORE /g; }) // {copied} -//UNSUP ; +sexpr: // ==IEEE: sequence_expr (The name sexpr is important as regexps just add an "s" to expr.) + // // ********* RULES COPIED IN sequence_exprProp + // // For precedence, see IEEE 17.7.1 + // + // // IEEE: "cycle_delay_range sequence_expr { cycle_delay_range sequence_expr }" + // // IEEE: "sequence_expr cycle_delay_range sequence_expr { cycle_delay_range sequence_expr }" + // // Both rules basically mean we can repeat sequences, so make it simpler: + //UNSUP cycle_delay_range sexpr %prec yP_POUNDPOUND { } + //UNSUP ~p~sexpr cycle_delay_range sexpr %prec prPOUNDPOUND_MULTI { } + // + // // IEEE: expression_or_dist [ boolean_abbrev ] + // // Note expression_or_dist includes "expr"! + // // sexpr/*sexpression_or_dist*/ --- Hardcoded below + //UNSUP ~p~sexpr/*sexpression_or_dist*/ boolean_abbrev { } + // + // // IEEE: "sequence_instance [ sequence_abbrev ]" + // // version without sequence_abbrev looks just like normal function call + // // version w/sequence_abbrev matches above; + // // expression_or_dist:expr:func boolean_abbrev:sequence_abbrev + // + // // IEEE: '(' expression_or_dist {',' sequence_match_item } ')' [ boolean_abbrev ] + // // IEEE: '(' sexpr {',' sequence_match_item } ')' [ sequence_abbrev ] + // // As sequence_expr includes expression_or_dist, and boolean_abbrev includes sequence_abbrev: + // // '(' sequence_expr {',' sequence_match_item } ')' [ boolean_abbrev ] + // // "'(' sexpr ')' boolean_abbrev" matches "[sexpr:'(' expr ')'] boolean_abbrev" so we can drop it + '(' ~p~sexpr ')' { $$ = $2; } + //UNSUP '(' ~p~sexpr ',' sequence_match_itemList ')' { } + // + // // AND/OR are between pexprs OR sexprs + //UNSUP ~p~sexpr yAND ~p~sexpr { $$ = new AstLogAnd{$2, $1, $3}; } + //UNSUP ~p~sexpr yOR ~p~sexpr { $$ = new AstLogOr{$2, $1, $3}; } + // // Intersect always has an sexpr rhs + //UNSUP ~p~sexpr yINTERSECT sexpr { $$ = $1; $$ = ...; } + // + //UNSUP yFIRST_MATCH '(' sexpr ')' { } + //UNSUP yFIRST_MATCH '(' sexpr ',' sequence_match_itemList ')' { } + //UNSUP ~p~sexpr/*sexpression_or_dist*/ yTHROUGHOUT sexpr { } + // // Below pexpr's are really sequence_expr, but avoid conflict + // // IEEE: sexpr yWITHIN sexpr + //UNSUP ~p~sexpr yWITHIN sexpr { $$ = $1; $$ = ...; } + // // Note concurrent_assertion had duplicate rule for below + //UNSUP clocking_event ~p~sexpr %prec prSEQ_CLOCKING { } + // + //============= expr rules copied for sequence_expr + | BISONPRE_COPY_ONCE(expr,{s/~l~/s/g; s/~p~/s/g; s/~noPar__IGNORE~'.'/yP_PAR__IGNORE /g; }) // {copied} + ; //UNSUPcycle_delay_range: // IEEE: ==cycle_delay_range //UNSUP // // These three terms in 1800-2005 ONLY From 90360d40fd6f6d0d6e26ab51d03415cf2ae6d9b4 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 5 Mar 2023 18:52:55 -0500 Subject: [PATCH 006/155] Change property expression handling towards eventual more general expressions. --- src/verilog.y | 41 ++++++++++++----------------------------- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/src/verilog.y b/src/verilog.y index 494b3d532..854136a24 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -3702,9 +3702,9 @@ sinc_or_dec_expression: // IEEE: inc_or_dec_expression (for sequence BISONPRE_COPY(inc_or_dec_expression,{s/~l~/s/g}) // {copied} ; -//UNSUPpinc_or_dec_expression: // IEEE: inc_or_dec_expression (for property_expression) -//UNSUP BISONPRE_COPY(inc_or_dec_expression,{s/~l~/p/g}) // {copied} -//UNSUP ; +pinc_or_dec_expression: // IEEE: inc_or_dec_expression (for property_expression) + BISONPRE_COPY(inc_or_dec_expression,{s/~l~/p/g}) // {copied} + ; //UNSUPev_inc_or_dec_expression: // IEEE: inc_or_dec_expression (for ev_expr) //UNSUP BISONPRE_COPY(inc_or_dec_expression,{s/~l~/ev_/g}) // {copied} @@ -4935,9 +4935,9 @@ sexprOkLvalue: // exprOkLValue, For use by sequence_expr BISONPRE_COPY(exprOkLvalue,{s/~l~/s/g}) // {copied} ; -//UNSUPpexprOkLvalue: // exprOkLValue, For use by property_expr -//UNSUP BISONPRE_COPY(exprOkLvalue,{s/~l~/p/g}) // {copied} -//UNSUP ; +pexprOkLvalue: // exprOkLValue, For use by property_expr + BISONPRE_COPY(exprOkLvalue,{s/~l~/p/g}) // {copied} + ; //UNSUPev_exprOkLvalue: // exprOkLValue, For use by ev_expr //UNSUP BISONPRE_COPY(exprOkLvalue,{s/~l~/ev_/g}) // {copied} @@ -4978,9 +4978,9 @@ sexprScope: // exprScope, For use by sequence_expr BISONPRE_COPY(exprScope,{s/~l~/s/g}) // {copied} ; -//UNSUPpexprScope: // exprScope, For use by property_expr -//UNSUP BISONPRE_COPY(exprScope,{s/~l~/p/g}) // {copied} -//UNSUP ; +pexprScope: // exprScope, For use by property_expr + BISONPRE_COPY(exprScope,{s/~l~/p/g}) // {copied} + ; //UNSUPev_exprScope: // exprScope, For use by ev_expr //UNSUP BISONPRE_COPY(exprScope,{s/~l~/ev_/g}) // {copied} @@ -5992,23 +5992,6 @@ property_spec: // IEEE: property_spec //UNSUP ; pexpr: // IEEE: property_expr (The name pexpr is important as regexps just add an "p" to expr.) - //UNSUP: This rule has been super-specialized to what is supported now - //UNSUP remove below - // - // This rule is divided between expr and complex_pexpr to avoid an ambiguity in SystemVerilog grammar. - // Both pexpr and expr can consist of parentheses, and so a pexpr "((expr))" can be reduced in two ways: - // 1. ((expr)) -> (pexpr) -> pexpr - // 2. ((expr)) -> (expr) -> pexpr - // The division below forces YACC to always assume the parentheses reduce to expr, unless they enclose - // operators that can only appear in a pexpr. - // - complex_pexpr { $$ = $1; } - | expr { $$ = $1; } - ; - -complex_pexpr: // IEEE: part of property_expr, see comments there - '(' complex_pexpr ')' { $$ = $2; } - //UNSUP remove above, use below: // // // IEEE: sequence_expr // // Expanded below @@ -6016,7 +5999,7 @@ complex_pexpr: // IEEE: part of property_expr, see comments there // // IEEE: '(' pexpr ')' // // Expanded below // - | yNOT pexpr %prec prNEGATION { $$ = new AstLogNot{$1, $2}; } + yNOT pexpr %prec prNEGATION { $$ = new AstLogNot{$1, $2}; } | ySTRONG '(' sexpr ')' { $$ = $3; BBUNSUP($2, "Unsupported: strong (in property expression)"); } | yWEAK '(' sexpr ')' @@ -6068,10 +6051,10 @@ complex_pexpr: // IEEE: part of property_expr, see comments there //UNSUP clocking_event yDISABLE yIFF '(' expr ')' pexpr %prec prSEQ_CLOCKING { } // //============= sexpr rules copied for property_expr - //UNSUP BISONPRE_COPY_ONCE(sexpr,{s/~p~s/p/g; }) // {copied} + | BISONPRE_COPY_ONCE(sexpr,{s/~p~s/p/g; }) // {copied} // //============= expr rules copied for property_expr - //UNSUP BISONPRE_COPY_ONCE(expr,{s/~l~/p/g; s/~p~/p/g; s/~noPar__IGNORE~'.'/yP_PAR__IGNORE /g; }) // {copied} + | BISONPRE_COPY_ONCE(expr,{s/~l~/p/g; s/~p~/p/g; s/~noPar__IGNORE~'.'/yP_PAR__IGNORE /g; }) // {copied} ; sexpr: // ==IEEE: sequence_expr (The name sexpr is important as regexps just add an "s" to expr.) From cb89ef9885f1b8aa158638a85defd370d403dbf2 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 5 Mar 2023 19:42:21 -0500 Subject: [PATCH 007/155] Parse more property expression syntax, as still unsupported --- src/verilog.l | 34 ++--- src/verilog.y | 110 +++++++++------- .../t/t_assert_property_pexpr_unsup.out | 92 +++++++++++++ .../t/t_assert_property_pexpr_unsup.pl | 20 +++ .../t/t_assert_property_pexpr_unsup.v | 121 ++++++++++++++++++ 5 files changed, 317 insertions(+), 60 deletions(-) create mode 100644 test_regress/t/t_assert_property_pexpr_unsup.out create mode 100755 test_regress/t/t_assert_property_pexpr_unsup.pl create mode 100644 test_regress/t/t_assert_property_pexpr_unsup.v diff --git a/src/verilog.l b/src/verilog.l index 7793e2205..2672729f1 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -593,28 +593,28 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} /* SystemVerilog 2009 */ { /* Keywords */ - "accept_on" { ERROR_RSVD_WORD("SystemVerilog 2009"); } + "accept_on" { FL; return yACCEPT_ON; } "checker" { FL; return yCHECKER; } "endchecker" { FL; return yENDCHECKER; } - "eventually" { ERROR_RSVD_WORD("SystemVerilog 2009"); } + "eventually" { FL; return yEVENTUALLY; } "global" { FL; return yGLOBAL__LEX; } - "implies" { ERROR_RSVD_WORD("SystemVerilog 2009"); } + "implies" { FL; return yIMPLIES; } "let" { ERROR_RSVD_WORD("SystemVerilog 2009"); } - "nexttime" { ERROR_RSVD_WORD("SystemVerilog 2009"); } - "reject_on" { ERROR_RSVD_WORD("SystemVerilog 2009"); } - "s_always" { ERROR_RSVD_WORD("SystemVerilog 2009"); } - "s_eventually" { ERROR_RSVD_WORD("SystemVerilog 2009"); } - "s_nexttime" { ERROR_RSVD_WORD("SystemVerilog 2009"); } - "s_until" { ERROR_RSVD_WORD("SystemVerilog 2009"); } - "s_until_with" { ERROR_RSVD_WORD("SystemVerilog 2009"); } - "strong" { ERROR_RSVD_WORD("SystemVerilog 2009"); } - "sync_accept_on" { ERROR_RSVD_WORD("SystemVerilog 2009"); } - "sync_reject_on" { ERROR_RSVD_WORD("SystemVerilog 2009"); } + "nexttime" { FL; return yNEXTTIME; } + "reject_on" { FL; return yREJECT_ON; } + "s_always" { FL; return yS_ALWAYS; } + "s_eventually" { FL; return yS_EVENTUALLY; } + "s_nexttime" { FL; return yS_NEXTTIME; } + "s_until" { FL; return yS_UNTIL; } + "s_until_with" { FL; return yS_UNTIL_WITH; } + "strong" { FL; return ySTRONG; } + "sync_accept_on" { FL; return ySYNC_ACCEPT_ON; } + "sync_reject_on" { FL; return ySYNC_REJECT_ON; } "unique0" { FL; return yUNIQUE0; } - "until" { ERROR_RSVD_WORD("SystemVerilog 2009"); } - "until_with" { ERROR_RSVD_WORD("SystemVerilog 2009"); } + "until" { FL; return yUNTIL; } + "until_with" { FL; return yUNTIL_WITH; } "untyped" { FL; return yUNTYPED; } - "weak" { ERROR_RSVD_WORD("SystemVerilog 2009"); } + "weak" { FL; return yWEAK; } } /* System Verilog 2012 */ @@ -875,6 +875,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} ">>>=" { FL; return yP_SSRIGHTEQ; } "->>" { FL; return yP_MINUSGTGT; } "##" { FL; return yP_POUNDPOUND; } + "#-#" { FL; return yP_POUNDMINUSPD; } + "#=#" { FL; return yP_POUNDEQPD; } "@@" { FL; return yP_ATAT; } "::" { FL; return yP_COLONCOLON; } ":=" { FL; return yP_COLONEQ; } diff --git a/src/verilog.y b/src/verilog.y index 854136a24..f7057328f 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -536,7 +536,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) // Double underscores "yX__Y" means token X followed by Y, // and "yX__ETC" means X folled by everything but Y(s). %token ya1STEP "1step" -//UNSUP %token yACCEPT_ON "accept_on" +%token yACCEPT_ON "accept_on" %token yALIAS "alias" %token yALWAYS "always" %token yALWAYS_COMB "always_comb" @@ -606,7 +606,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yENDTASK "endtask" %token yENUM "enum" %token yEVENT "event" -//UNSUP %token yEVENTUALLY "eventually" +%token yEVENTUALLY "eventually" //UNSUP %token yEXPECT "expect" %token yEXPORT "export" %token yEXTENDS "extends" @@ -635,7 +635,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) //UNSUP %token yIGNORE_BINS "ignore_bins" //UNSUP %token yILLEGAL_BINS "illegal_bins" %token yIMPLEMENTS "implements" -//UNSUP %token yIMPLIES "implies" +%token yIMPLIES "implies" %token yIMPORT "import" %token yINITIAL "initial" %token yINOUT "inout" @@ -665,7 +665,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yNEW__ETC "new" %token yNEW__LEX "new-in-lex" %token yNEW__PAREN "new-then-paren" -//UNSUP %token yNEXTTIME "nexttime" +%token yNEXTTIME "nexttime" %token yNMOS "nmos" %token yNOR "nor" %token yNOT "not" @@ -699,7 +699,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yREALTIME "realtime" %token yREF "ref" %token yREG "reg" -//UNSUP %token yREJECT_ON "reject_on" +%token yREJECT_ON "reject_on" %token yRELEASE "release" %token yREPEAT "repeat" %token yRESTRICT "restrict" @@ -729,13 +729,13 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token ySUPER "super" %token ySUPPLY0 "supply0" %token ySUPPLY1 "supply1" -//UNSUP %token ySYNC_ACCEPT_ON "sync_accept_on" -//UNSUP %token ySYNC_REJECT_ON "sync_reject_on" -//UNSUP %token yS_ALWAYS "s_always" -//UNSUP %token yS_EVENTUALLY "s_eventually" -//UNSUP %token yS_NEXTTIME "s_nexttime" -//UNSUP %token yS_UNTIL "s_until" -//UNSUP %token yS_UNTIL_WITH "s_until_with" +%token ySYNC_ACCEPT_ON "sync_accept_on" +%token ySYNC_REJECT_ON "sync_reject_on" +%token yS_ALWAYS "s_always" +%token yS_EVENTUALLY "s_eventually" +%token yS_NEXTTIME "s_nexttime" +%token yS_UNTIL "s_until" +%token yS_UNTIL_WITH "s_until_with" %token yTABLE "table" //UNSUP %token yTAGGED "tagged" %token yTASK "task" @@ -765,8 +765,8 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yUNIQUE "unique" %token yUNIQUE0 "unique0" %token yUNSIGNED "unsigned" -//UNSUP %token yUNTIL "until" -//UNSUP %token yUNTIL_WITH "until_with" +%token yUNTIL "until" +%token yUNTIL_WITH "until_with" %token yUNTYPED "untyped" %token yVAR "var" %token yVECTORED "vectored" @@ -1017,8 +1017,8 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yP_ASTGT "*>" %token yP_ANDANDAND "&&&" %token yP_POUNDPOUND "##" -//UNSUP %token yP_POUNDMINUSPD "#-#" -//UNSUP %token yP_POUNDEQPD "#=#" +%token yP_POUNDMINUSPD "#-#" +%token yP_POUNDEQPD "#=#" %token yP_DOTSTAR ".*" %token yP_ATAT "@@" @@ -1068,15 +1068,14 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) // Lowest precedence // These are in IEEE 17.7.1 -//UNSUP %nonassoc yALWAYS yS_ALWAYS yEVENTUALLY yS_EVENTUALLY yACCEPT_ON yREJECT_ON ySYNC_ACCEPT_ON ySYNC_REJECT_ON +%nonassoc yALWAYS yS_ALWAYS yEVENTUALLY yS_EVENTUALLY yACCEPT_ON yREJECT_ON ySYNC_ACCEPT_ON ySYNC_REJECT_ON -%right yP_ORMINUSGT yP_OREQGT -//UNSUP %right yP_ORMINUSGT yP_OREQGT yP_POUNDMINUSPD yP_POUNDEQPD -//UNSUP %right yUNTIL yS_UNTIL yUNTIL_WITH yS_UNTIL_WITH yIMPLIES +%right yP_ORMINUSGT yP_OREQGT yP_POUNDMINUSPD yP_POUNDEQPD +%right yUNTIL yS_UNTIL yUNTIL_WITH yS_UNTIL_WITH yIMPLIES //UNSUP %right yIFF //UNSUP %left yOR //UNSUP %left yAND -//UNSUP %nonassoc yNOT yNEXTTIME yS_NEXTTIME +%nonassoc yNOT yNEXTTIME yS_NEXTTIME //UNSUP %left yINTERSECT //UNSUP %left yWITHIN //UNSUP %right yTHROUGHOUT @@ -6017,29 +6016,52 @@ pexpr: // IEEE: property_expr (The name pexpr is important as regex // // IEEE-2012: yIF and yCASE //UNSUP property_statementCaseIf { } // - //UNSUP ~o~pexpr/*sexpr*/ yP_POUNDMINUSPD pexpr { } - //UNSUP ~o~pexpr/*sexpr*/ yP_POUNDEQPD pexpr { } - //UNSUP yNEXTTIME pexpr { } - //UNSUP yS_NEXTTIME pexpr { } - //UNSUP yNEXTTIME '[' expr/*const*/ ']' pexpr %prec yNEXTTIME { } - //UNSUP yS_NEXTTIME '[' expr/*const*/ ']' pexpr %prec yS_NEXTTIME { } - //UNSUP yALWAYS pexpr { } - //UNSUP yALWAYS '[' cycle_delay_const_range_expression ']' pexpr %prec yALWAYS { } - //UNSUP yS_ALWAYS '[' constant_range ']' pexpr %prec yS_ALWAYS { } - //UNSUP yS_EVENTUALLY pexpr { } - //UNSUP yEVENTUALLY '[' constant_range ']' pexpr %prec yEVENTUALLY { } - //UNSUP yS_EVENTUALLY '[' cycle_delay_const_range_expression ']' pexpr %prec yS_EVENTUALLY { } - //UNSUP ~o~pexpr yUNTIL pexpr { } - //UNSUP ~o~pexpr yS_UNTIL pexpr { } - //UNSUP ~o~pexpr yUNTIL_WITH pexpr { } - //UNSUP ~o~pexpr yS_UNTIL_WITH pexpr { } - //UNSUP ~o~pexpr yIMPLIES pexpr { } + | ~o~pexpr/*sexpr*/ yP_POUNDMINUSPD pexpr + { $$ = $3; BBUNSUP($2, "Unsupported: #-# (in property expression)"); } + | ~o~pexpr/*sexpr*/ yP_POUNDEQPD pexpr + { $$ = $3; BBUNSUP($2, "Unsupported: #=# (in property expression)"); } + | yNEXTTIME pexpr + { $$ = $2; BBUNSUP($1, "Unsupported: nexttime (in property expression)"); } + | yS_NEXTTIME pexpr + { $$ = $2; BBUNSUP($1, "Unsupported: s_nexttime (in property expression)"); } + | yNEXTTIME '[' constExpr ']' pexpr %prec yNEXTTIME + { $$ = $5; BBUNSUP($1, "Unsupported: nexttime[] (in property expression)"); } + | yS_NEXTTIME '[' constExpr ']' pexpr %prec yS_NEXTTIME + { $$ = $5; BBUNSUP($1, "Unsupported: s_nexttime[] (in property expression)"); } + | yALWAYS pexpr + { $$ = $2; BBUNSUP($1, "Unsupported: always (in property expression)"); } + | yALWAYS anyrange pexpr %prec yALWAYS + { $$ = $3; BBUNSUP($1, "Unsupported: always[] (in property expression)"); } + | yS_ALWAYS anyrange pexpr %prec yS_ALWAYS + { $$ = $3; BBUNSUP($1, "Unsupported: s_always (in property expression)"); } + | yEVENTUALLY pexpr + { $$ = $2; BBUNSUP($1, "Unsupported: eventually (in property expression)"); } + | yS_EVENTUALLY pexpr + { $$ = $2; BBUNSUP($1, "Unsupported: s_eventually (in property expression)"); } + | yEVENTUALLY '[' constExpr ']' pexpr %prec yEVENTUALLY + { $$ = $5; BBUNSUP($1, "Unsupported: eventually[] (in property expression)"); } + | yS_EVENTUALLY anyrange pexpr %prec yS_EVENTUALLY + { $$ = $3; BBUNSUP($1, "Unsupported: s_eventually[] (in property expression)"); } + | ~o~pexpr yUNTIL pexpr + { $$ = $1; BBUNSUP($2, "Unsupported: until (in property expression)"); } + | ~o~pexpr yS_UNTIL pexpr + { $$ = $1; BBUNSUP($2, "Unsupported: s_until (in property expression)"); } + | ~o~pexpr yUNTIL_WITH pexpr + { $$ = $1; BBUNSUP($2, "Unsupported: until_with (in property expression)"); } + | ~o~pexpr yS_UNTIL_WITH pexpr + { $$ = $1; BBUNSUP($2, "Unsupported: s_until_with (in property expression)"); } + | ~o~pexpr yIMPLIES pexpr + { $$ = $1; BBUNSUP($2, "Unsupported: implies (in property expression)"); } // // yIFF also used by event_expression //UNSUP ~o~pexpr yIFF ~o~pexpr { } - //UNSUP yACCEPT_ON '(' expr/*expression_or_dist*/ ')' pexpr %prec yACCEPT_ON { } - //UNSUP yREJECT_ON '(' expr/*expression_or_dist*/ ')' pexpr %prec yREJECT_ON { } - //UNSUP ySYNC_ACCEPT_ON '(' expr/*expression_or_dist*/ ')' pexpr %prec ySYNC_ACCEPT_ON { } - //UNSUP ySYNC_REJECT_ON '(' expr/*expression_or_dist*/ ')' pexpr %prec ySYNC_REJECT_ON { } + | yACCEPT_ON '(' expr/*expression_or_dist*/ ')' pexpr %prec yACCEPT_ON + { $$ = $5; BBUNSUP($2, "Unsupported: accept_on (in property expression)"); } + | yREJECT_ON '(' expr/*expression_or_dist*/ ')' pexpr %prec yREJECT_ON + { $$ = $5; BBUNSUP($2, "Unsupported: reject_on (in property expression)"); } + | ySYNC_ACCEPT_ON '(' expr/*expression_or_dist*/ ')' pexpr %prec ySYNC_ACCEPT_ON + { $$ = $5; BBUNSUP($2, "Unsupported: sync_accept_on (in property expression)"); } + | ySYNC_REJECT_ON '(' expr/*expression_or_dist*/ ')' pexpr %prec ySYNC_REJECT_ON + { $$ = $5; BBUNSUP($2, "Unsupported: sync_reject_on (in property expression)"); } // // // IEEE: "property_instance" // // Looks just like a function/method call @@ -6114,7 +6136,7 @@ sexpr: // ==IEEE: sequence_expr (The name sexpr is important as reg //UNSUP // // UNSUP: This causes a big grammer ambiguity //UNSUP // // as ()'s mismatch between primary and the following statement //UNSUP // // the sv-ac committee has been asked to clarify (Mantis 1901) -//UNSUP | yP_POUNDPOUND '[' cycle_delay_const_range_expression ']' { } +//UNSUP | yP_POUNDPOUND anyrange { } //UNSUP | yP_POUNDPOUND yP_BRASTAR ']' { } //UNSUP | yP_POUNDPOUND yP_BRAPLUSKET { } //UNSUP ; @@ -6145,7 +6167,7 @@ sexpr: // ==IEEE: sequence_expr (The name sexpr is important as reg //UNSUPconst_or_range_expression: // ==IEEE: const_or_range_expression //UNSUP constExpr { $$ = $1; } -//UNSUP | cycle_delay_const_range_expression { } +//UNSUP | cycle_delay_const_range_expression { } // Use anyrange removing [] instead //UNSUP ; //UNSUPconstant_range: // ==IEEE: constant_range diff --git a/test_regress/t/t_assert_property_pexpr_unsup.out b/test_regress/t/t_assert_property_pexpr_unsup.out new file mode 100644 index 000000000..64a7f1351 --- /dev/null +++ b/test_regress/t/t_assert_property_pexpr_unsup.out @@ -0,0 +1,92 @@ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:24:13: Unsupported: strong (in property expression) + 24 | strong(a); + | ^ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:28:11: Unsupported: weak (in property expression) + 28 | weak(a); + | ^ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:32:9: Unsupported: until (in property expression) + 32 | a until b; + | ^~~~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:36:9: Unsupported: s_until (in property expression) + 36 | a s_until b; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:40:9: Unsupported: until_with (in property expression) + 40 | a until_with b; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:44:9: Unsupported: s_until_with (in property expression) + 44 | a s_until_with b; + | ^~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:48:9: Unsupported: implies (in property expression) + 48 | a implies b; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:52:9: Unsupported: #-# (in property expression) + 52 | a #-# b; + | ^~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:56:9: Unsupported: #=# (in property expression) + 56 | a #=# b; + | ^~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:60:7: Unsupported: nexttime (in property expression) + 60 | nexttime a; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:64:7: Unsupported: nexttime[] (in property expression) + 64 | nexttime [2] a; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:68:7: Unsupported: s_nexttime (in property expression) + 68 | s_nexttime a; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:72:7: Unsupported: s_nexttime[] (in property expression) + 72 | s_nexttime [2] a; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:76:16: Unsupported: always (in property expression) + 76 | nexttime always a; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:76:7: Unsupported: nexttime (in property expression) + 76 | nexttime always a; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:80:20: Unsupported: always (in property expression) + 80 | nexttime [2] always a; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:80:7: Unsupported: nexttime[] (in property expression) + 80 | nexttime [2] always a; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:84:16: Unsupported: eventually (in property expression) + 84 | nexttime eventually a; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:84:7: Unsupported: nexttime (in property expression) + 84 | nexttime eventually a; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:88:20: Unsupported: always (in property expression) + 88 | nexttime [2] always a; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:88:7: Unsupported: nexttime[] (in property expression) + 88 | nexttime [2] always a; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:92:16: Unsupported: s_eventually (in property expression) + 92 | nexttime s_eventually a; + | ^~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:92:7: Unsupported: nexttime (in property expression) + 92 | nexttime s_eventually a; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:96:35: Unsupported: always (in property expression) + 96 | nexttime s_eventually [2:$] always a; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:96:16: Unsupported: s_eventually[] (in property expression) + 96 | nexttime s_eventually [2:$] always a; + | ^~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:96:7: Unsupported: nexttime (in property expression) + 96 | nexttime s_eventually [2:$] always a; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:100:17: Unsupported: accept_on (in property expression) + 100 | accept_on (a) b; + | ^ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:104:22: Unsupported: sync_accept_on (in property expression) + 104 | sync_accept_on (a) b; + | ^ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:108:17: Unsupported: reject_on (in property expression) + 108 | reject_on (a) b; + | ^ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:112:22: Unsupported: sync_reject_on (in property expression) + 112 | sync_reject_on (a) b; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_assert_property_pexpr_unsup.pl b/test_regress/t/t_assert_property_pexpr_unsup.pl new file mode 100755 index 000000000..d188a4276 --- /dev/null +++ b/test_regress/t/t_assert_property_pexpr_unsup.pl @@ -0,0 +1,20 @@ +#!/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(vlt => 1); + +compile( + expect_filename => $Self->{golden_filename}, + verilator_flags2 => ['--assert'], + fails => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_assert_property_pexpr_unsup.v b/test_regress/t/t_assert_property_pexpr_unsup.v new file mode 100644 index 000000000..45a0897e5 --- /dev/null +++ b/test_regress/t/t_assert_property_pexpr_unsup.v @@ -0,0 +1,121 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk, a, b + ); + + input clk; + int a; + int b; + int cyc = 0; + + always @(posedge clk) begin + cyc <= cyc + 1; + end + + // NOTE this grammar hasn't been checked with other simulators, + // is here just to avoid uncovered code lines in the grammar. + property p_strong; + strong(a); + endproperty + + property p_weak; + weak(a); + endproperty + + property p_until; + a until b; + endproperty + + property p_suntil; + a s_until b; + endproperty + + property p_untilwith; + a until_with b; + endproperty + + property p_suntilwith; + a s_until_with b; + endproperty + + property p_implies; + a implies b; + endproperty + + property p_poundminuspound1; + a #-# b; + endproperty + + property p_poundeqpound; + a #=# b; + endproperty + + property p_nexttime; + nexttime a; + endproperty + + property p_nexttime2; + nexttime [2] a; + endproperty + + property p_snexttime; + s_nexttime a; + endproperty + + property p_snexttime2; + s_nexttime [2] a; + endproperty + + property p_nexttime_always; + nexttime always a; + endproperty + + property p_nexttime_always2; + nexttime [2] always a; + endproperty + + property p_nexttime_eventually; + nexttime eventually a; + endproperty + + property p_nexttime_eventually2; + nexttime [2] always a; + endproperty + + property p_nexttime_seventually; + nexttime s_eventually a; + endproperty + + property p_nexttime_seventually2; + nexttime s_eventually [2:$] always a; + endproperty + + property p_accepton; + accept_on (a) b; + endproperty + + property p_syncaccepton; + sync_accept_on (a) b; + endproperty + + property p_rejecton; + reject_on (a) b; + endproperty + + property p_syncrejecton; + sync_reject_on (a) b; + endproperty + + always @(posedge clk) begin + if (cyc == 10) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule From d0f5ce0cc462b631a2265e35440c14da2a40f001 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 5 Mar 2023 19:57:09 -0500 Subject: [PATCH 008/155] Parse intersect/throughout/within, still unsupported. --- src/verilog.l | 6 +-- src/verilog.y | 40 +++++++++------ .../t/t_assert_property_pexpr_unsup.out | 3 ++ .../t/t_assert_property_pexpr_unsup.v | 4 ++ test_regress/t/t_sequence_sexpr_unsup.out | 32 ++++++++++++ test_regress/t/t_sequence_sexpr_unsup.pl | 20 ++++++++ test_regress/t/t_sequence_sexpr_unsup.v | 50 +++++++++++++++++++ 7 files changed, 136 insertions(+), 19 deletions(-) create mode 100644 test_regress/t/t_sequence_sexpr_unsup.out create mode 100755 test_regress/t/t_sequence_sexpr_unsup.pl create mode 100644 test_regress/t/t_sequence_sexpr_unsup.v diff --git a/src/verilog.l b/src/verilog.l index 2672729f1..07111af8e 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -539,7 +539,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "inside" { FL; return yINSIDE; } "int" { FL; return yINT; } "interface" { FL; return yINTERFACE; } - "intersect" { ERROR_RSVD_WORD("SystemVerilog 2005"); } + "intersect" { FL; return yINTERSECT; } "join_any" { FL; return yJOIN_ANY; } "join_none" { FL; return yJOIN_NONE; } "local" { FL; return yLOCAL__LEX; } @@ -574,7 +574,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "super" { FL; return ySUPER; } "tagged" { ERROR_RSVD_WORD("SystemVerilog 2005"); } "this" { FL; return yTHIS; } - "throughout" { ERROR_RSVD_WORD("SystemVerilog 2005"); } + "throughout" { FL; return yTHROUGHOUT; } "timeprecision" { FL; return yTIMEPRECISION; } "timeunit" { FL; return yTIMEUNIT; } "type" { FL; return yTYPE__LEX; } @@ -587,7 +587,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "wait_order" { ERROR_RSVD_WORD("SystemVerilog 2005"); } "wildcard" { ERROR_RSVD_WORD("SystemVerilog 2005"); } "with" { FL; return yWITH__LEX; } - "within" { ERROR_RSVD_WORD("SystemVerilog 2005"); } + "within" { FL; return yWITHIN; } } /* SystemVerilog 2009 */ diff --git a/src/verilog.y b/src/verilog.y index f7057328f..156d4a9b6 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -645,7 +645,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yINTEGER "integer" %token yINTERCONNECT "interconnect" %token yINTERFACE "interface" -//UNSUP %token yINTERSECT "intersect" +%token yINTERSECT "intersect" %token yJOIN "join" %token yJOIN_ANY "join_any" %token yJOIN_NONE "join_none" @@ -743,7 +743,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) //UNSUP %token yTASK__LEX "task-in-lex" //UNSUP %token yTASK__aPUREV "task-is-pure-virtual" %token yTHIS "this" -//UNSUP %token yTHROUGHOUT "throughout" +%token yTHROUGHOUT "throughout" %token yTIME "time" %token yTIMEPRECISION "timeprecision" %token yTIMEUNIT "timeunit" @@ -785,7 +785,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yWHILE "while" //UNSUP %token yWILDCARD "wildcard" %token yWIRE "wire" -//UNSUP %token yWITHIN "within" +%token yWITHIN "within" %token yWITH__BRA "with-then-[" %token yWITH__CUR "with-then-{" %token yWITH__ETC "with" @@ -1072,13 +1072,13 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %right yP_ORMINUSGT yP_OREQGT yP_POUNDMINUSPD yP_POUNDEQPD %right yUNTIL yS_UNTIL yUNTIL_WITH yS_UNTIL_WITH yIMPLIES -//UNSUP %right yIFF -//UNSUP %left yOR -//UNSUP %left yAND +%right yIFF +%left yOR +%left yAND %nonassoc yNOT yNEXTTIME yS_NEXTTIME -//UNSUP %left yINTERSECT -//UNSUP %left yWITHIN -//UNSUP %right yTHROUGHOUT +%left yINTERSECT +%left yWITHIN +%right yTHROUGHOUT //UNSUP %left prPOUNDPOUND_MULTI //UNSUP %left yP_POUNDPOUND //UNSUP %left yP_BRASTAR yP_BRAEQ yP_BRAMINUSGT yP_BRAPLUSKET @@ -6053,7 +6053,8 @@ pexpr: // IEEE: property_expr (The name pexpr is important as regex | ~o~pexpr yIMPLIES pexpr { $$ = $1; BBUNSUP($2, "Unsupported: implies (in property expression)"); } // // yIFF also used by event_expression - //UNSUP ~o~pexpr yIFF ~o~pexpr { } + | ~o~pexpr yIFF pexpr + { $$ = $1; BBUNSUP($2, "Unsupported: iff (in property expression)"); } | yACCEPT_ON '(' expr/*expression_or_dist*/ ')' pexpr %prec yACCEPT_ON { $$ = $5; BBUNSUP($2, "Unsupported: accept_on (in property expression)"); } | yREJECT_ON '(' expr/*expression_or_dist*/ ')' pexpr %prec yREJECT_ON @@ -6108,17 +6109,24 @@ sexpr: // ==IEEE: sequence_expr (The name sexpr is important as reg //UNSUP '(' ~p~sexpr ',' sequence_match_itemList ')' { } // // // AND/OR are between pexprs OR sexprs - //UNSUP ~p~sexpr yAND ~p~sexpr { $$ = new AstLogAnd{$2, $1, $3}; } - //UNSUP ~p~sexpr yOR ~p~sexpr { $$ = new AstLogOr{$2, $1, $3}; } + | ~p~sexpr yAND ~p~sexpr + { $$ = new AstLogAnd{$2, $1, $3}; + BBUNSUP($2, "Unsupported: and (in sequence expression)"); } + | ~p~sexpr yOR ~p~sexpr + { $$ = new AstLogOr{$2, $1, $3}; + BBUNSUP($2, "Unsupported: or (in sequence expression)"); } // // Intersect always has an sexpr rhs - //UNSUP ~p~sexpr yINTERSECT sexpr { $$ = $1; $$ = ...; } + | ~p~sexpr yINTERSECT sexpr + { $$ = $1; BBUNSUP($2, "Unsupported: intersect (in sequence expression)"); } // //UNSUP yFIRST_MATCH '(' sexpr ')' { } //UNSUP yFIRST_MATCH '(' sexpr ',' sequence_match_itemList ')' { } - //UNSUP ~p~sexpr/*sexpression_or_dist*/ yTHROUGHOUT sexpr { } + | ~p~sexpr/*sexpression_or_dist*/ yTHROUGHOUT sexpr + { $$ = $1; BBUNSUP($2, "Unsupported: throughout (in sequence expression)"); } // // Below pexpr's are really sequence_expr, but avoid conflict // // IEEE: sexpr yWITHIN sexpr - //UNSUP ~p~sexpr yWITHIN sexpr { $$ = $1; $$ = ...; } + | ~p~sexpr yWITHIN sexpr + { $$ = $1; BBUNSUP($2, "Unsupported: within (in sequence expression)"); } // // Note concurrent_assertion had duplicate rule for below //UNSUP clocking_event ~p~sexpr %prec prSEQ_CLOCKING { } // @@ -6143,7 +6151,7 @@ sexpr: // ==IEEE: sequence_expr (The name sexpr is important as reg //UNSUPsequence_match_itemList: // IEEE: [sequence_match_item] part of sequence_expr //UNSUP sequence_match_item { $$ = $1; } -//UNSUP | sequence_match_itemList ',' sequence_match_item { } +//UNSUP | sequence_match_itemList ',' sequence_match_item { $$ = addNextNull($1, $3); } //UNSUP ; //UNSUPsequence_match_item: // ==IEEE: sequence_match_item diff --git a/test_regress/t/t_assert_property_pexpr_unsup.out b/test_regress/t/t_assert_property_pexpr_unsup.out index 64a7f1351..e70cc0825 100644 --- a/test_regress/t/t_assert_property_pexpr_unsup.out +++ b/test_regress/t/t_assert_property_pexpr_unsup.out @@ -89,4 +89,7 @@ %Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:112:22: Unsupported: sync_reject_on (in property expression) 112 | sync_reject_on (a) b; | ^ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:116:9: Unsupported: iff (in property expression) + 116 | a iff b; + | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_assert_property_pexpr_unsup.v b/test_regress/t/t_assert_property_pexpr_unsup.v index 45a0897e5..dd3977db7 100644 --- a/test_regress/t/t_assert_property_pexpr_unsup.v +++ b/test_regress/t/t_assert_property_pexpr_unsup.v @@ -112,6 +112,10 @@ module t (/*AUTOARG*/ sync_reject_on (a) b; endproperty + property p_iff; + a iff b; + endproperty + always @(posedge clk) begin if (cyc == 10) begin $write("*-* All Finished *-*\n"); diff --git a/test_regress/t/t_sequence_sexpr_unsup.out b/test_regress/t/t_sequence_sexpr_unsup.out new file mode 100644 index 000000000..8e7445790 --- /dev/null +++ b/test_regress/t/t_sequence_sexpr_unsup.out @@ -0,0 +1,32 @@ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:25:14: Unsupported: within (in sequence expression) + 25 | weak(a within(b)); + | ^~~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:25:11: Unsupported: weak (in property expression) + 25 | weak(a within(b)); + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:29:14: Unsupported: and (in sequence expression) + 29 | weak(a and b); + | ^~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:29:11: Unsupported: weak (in property expression) + 29 | weak(a and b); + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:33:14: Unsupported: or (in sequence expression) + 33 | weak(a or b); + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:33:11: Unsupported: weak (in property expression) + 33 | weak(a or b); + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:37:14: Unsupported: throughout (in sequence expression) + 37 | weak(a throughout b); + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:37:11: Unsupported: weak (in property expression) + 37 | weak(a throughout b); + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:41:14: Unsupported: intersect (in sequence expression) + 41 | weak(a intersect b); + | ^~~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:41:11: Unsupported: weak (in property expression) + 41 | weak(a intersect b); + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_sequence_sexpr_unsup.pl b/test_regress/t/t_sequence_sexpr_unsup.pl new file mode 100755 index 000000000..d188a4276 --- /dev/null +++ b/test_regress/t/t_sequence_sexpr_unsup.pl @@ -0,0 +1,20 @@ +#!/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(vlt => 1); + +compile( + expect_filename => $Self->{golden_filename}, + verilator_flags2 => ['--assert'], + fails => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_sequence_sexpr_unsup.v b/test_regress/t/t_sequence_sexpr_unsup.v new file mode 100644 index 000000000..eed60e3f0 --- /dev/null +++ b/test_regress/t/t_sequence_sexpr_unsup.v @@ -0,0 +1,50 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk, a, b + ); + + input clk; + int a; + int b; + int cyc = 0; + + always @(posedge clk) begin + cyc <= cyc + 1; + end + + // NOTE this grammar hasn't been checked with other simulators, + // is here just to avoid uncovered code lines in the grammar. + // NOTE using 'property weak' here as sequence/endsequence not supported + property s_within; + weak(a within(b)); + endproperty + + property s_and; + weak(a and b); + endproperty + + property s_or; + weak(a or b); + endproperty + + property s_throughout; + weak(a throughout b); + endproperty + + property s_intersect; + weak(a intersect b); + endproperty + + always @(posedge clk) begin + if (cyc == 10) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule From 6d7c04a3de4e1cb9e1bd6c537f4c68d79b4e9b46 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 5 Mar 2023 23:22:41 -0500 Subject: [PATCH 009/155] Parse cycle delays and boolean abbrev, still unsupported. --- src/verilog.l | 3 +- src/verilog.y | 118 +++++++++-------- test_regress/t/t_sequence_sexpr_unsup.out | 154 +++++++++++++++++++--- test_regress/t/t_sequence_sexpr_unsup.v | 62 +++++++++ 4 files changed, 263 insertions(+), 74 deletions(-) diff --git a/src/verilog.l b/src/verilog.l index 07111af8e..3aae01d07 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -885,8 +885,9 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "|=>" { FL; return yP_OREQGT; } /* Some simulators allow whitespace here. Grr */ "["{ws}*"*" { FL; return yP_BRASTAR; } - "["{ws}*"=" { FL; return yP_BRAEQ; } + "["{ws}*"+"{ws}*"]" { FL; return yP_BRAPLUSKET; } "["{ws}*"->" { FL; return yP_BRAMINUSGT; } + "["{ws}*"=" { FL; return yP_BRAEQ; } } /* SystemVerilog 2009 Operators */ diff --git a/src/verilog.y b/src/verilog.y index 156d4a9b6..bb3f938f8 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -1030,7 +1030,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yP_BRASTAR "[*" %token yP_BRAEQ "[=" %token yP_BRAMINUSGT "[->" -//UNSUP %token yP_BRAPLUSKET "[+]" +%token yP_BRAPLUSKET "[+]" %token yP_PLUSPLUS "++" %token yP_MINUSMINUS "--" @@ -1079,9 +1079,9 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %left yINTERSECT %left yWITHIN %right yTHROUGHOUT -//UNSUP %left prPOUNDPOUND_MULTI -//UNSUP %left yP_POUNDPOUND -//UNSUP %left yP_BRASTAR yP_BRAEQ yP_BRAMINUSGT yP_BRAPLUSKET +%left prPOUNDPOUND_MULTI +%left yP_POUNDPOUND +%left yP_BRASTAR yP_BRAEQ yP_BRAMINUSGT yP_BRAPLUSKET // Not specified, but needed higher than yOR, lower than normal non-pexpr expressions //UNSUP %left yPOSEDGE yNEGEDGE yEDGE @@ -5823,12 +5823,12 @@ property_port_list: // ==IEEE: property_port_list ; property_port_item: // IEEE: property_port_item/sequence_port_item -//UNSUP // // Merged in sequence_port_item -//UNSUP // // IEEE: property_lvar_port_direction ::= yINPUT -//UNSUP // // prop IEEE: [ yLOCAL [ yINPUT ] ] property_formal_type -//UNSUP // // id {variable_dimension} [ '=' property_actual_arg ] -//UNSUP // // seq IEEE: [ yLOCAL [ sequence_lvar_port_direction ] ] sequence_formal_type -//UNSUP // // id {variable_dimension} [ '=' sequence_actual_arg ] + // // Merged in sequence_port_item + // // IEEE: property_lvar_port_direction ::= yINPUT + // // prop IEEE: [ yLOCAL [ yINPUT ] ] property_formal_type + // // id {variable_dimension} [ '=' property_actual_arg ] + // // seq IEEE: [ yLOCAL [ sequence_lvar_port_direction ] ] sequence_formal_type + // // id {variable_dimension} [ '=' sequence_actual_arg ] property_port_itemFront property_port_itemAssignment { $$ = $2; } ; @@ -6087,13 +6087,16 @@ sexpr: // ==IEEE: sequence_expr (The name sexpr is important as reg // // IEEE: "cycle_delay_range sequence_expr { cycle_delay_range sequence_expr }" // // IEEE: "sequence_expr cycle_delay_range sequence_expr { cycle_delay_range sequence_expr }" // // Both rules basically mean we can repeat sequences, so make it simpler: - //UNSUP cycle_delay_range sexpr %prec yP_POUNDPOUND { } - //UNSUP ~p~sexpr cycle_delay_range sexpr %prec prPOUNDPOUND_MULTI { } + cycle_delay_range sexpr %prec yP_POUNDPOUND + { $$ = $2; BBUNSUP($2->fileline(), "Unsupported: ## (in sequence expression)"); } + | ~p~sexpr cycle_delay_range sexpr %prec prPOUNDPOUND_MULTI + { $$ = $1; BBUNSUP($2->fileline(), "Unsupported: ## (in sequence expression)"); } // // // IEEE: expression_or_dist [ boolean_abbrev ] // // Note expression_or_dist includes "expr"! // // sexpr/*sexpression_or_dist*/ --- Hardcoded below - //UNSUP ~p~sexpr/*sexpression_or_dist*/ boolean_abbrev { } + | ~p~sexpr/*sexpression_or_dist*/ boolean_abbrev + { $$ = $1; BBUNSUP($2->fileline(), "Unsupported: boolean abbrev (in sequence expression)"); } // // // IEEE: "sequence_instance [ sequence_abbrev ]" // // version without sequence_abbrev looks just like normal function call @@ -6105,7 +6108,7 @@ sexpr: // ==IEEE: sequence_expr (The name sexpr is important as reg // // As sequence_expr includes expression_or_dist, and boolean_abbrev includes sequence_abbrev: // // '(' sequence_expr {',' sequence_match_item } ')' [ boolean_abbrev ] // // "'(' sexpr ')' boolean_abbrev" matches "[sexpr:'(' expr ')'] boolean_abbrev" so we can drop it - '(' ~p~sexpr ')' { $$ = $2; } + | '(' ~p~sexpr ')' { $$ = $2; } //UNSUP '(' ~p~sexpr ',' sequence_match_itemList ')' { } // // // AND/OR are between pexprs OR sexprs @@ -6134,20 +6137,32 @@ sexpr: // ==IEEE: sequence_expr (The name sexpr is important as reg | BISONPRE_COPY_ONCE(expr,{s/~l~/s/g; s/~p~/s/g; s/~noPar__IGNORE~'.'/yP_PAR__IGNORE /g; }) // {copied} ; -//UNSUPcycle_delay_range: // IEEE: ==cycle_delay_range -//UNSUP // // These three terms in 1800-2005 ONLY -//UNSUP yP_POUNDPOUND yaINTNUM { } -//UNSUP | yP_POUNDPOUND id { } -//UNSUP | yP_POUNDPOUND '(' constExpr ')' { } -//UNSUP // // In 1800-2009 ONLY: -//UNSUP // // IEEE: yP_POUNDPOUND constant_primary -//UNSUP // // UNSUP: This causes a big grammer ambiguity -//UNSUP // // as ()'s mismatch between primary and the following statement -//UNSUP // // the sv-ac committee has been asked to clarify (Mantis 1901) -//UNSUP | yP_POUNDPOUND anyrange { } -//UNSUP | yP_POUNDPOUND yP_BRASTAR ']' { } -//UNSUP | yP_POUNDPOUND yP_BRAPLUSKET { } -//UNSUP ; +cycle_delay_range: // IEEE: ==cycle_delay_range + // // These three terms in 1800-2005 ONLY + yP_POUNDPOUND intnumAsConst + { $$ = $2; + BBUNSUP($1, "Unsupported: ## () cycle delay range expression"); } + | yP_POUNDPOUND id + { $$ = new AstConst{$1, AstConst::BitFalse{}}; + BBUNSUP($1, "Unsupported: ## id cycle delay range expression"); } + | yP_POUNDPOUND '(' constExpr ')' + { $$ = $3; + BBUNSUP($1, "Unsupported: ## () cycle delay range expression"); } + // // In 1800-2009 ONLY: + // // IEEE: yP_POUNDPOUND constant_primary + // // UNSUP: This causes a big grammer ambiguity + // // as ()'s mismatch between primary and the following statement + // // the sv-ac committee has been asked to clarify (Mantis 1901) + | yP_POUNDPOUND anyrange + { $$ = new AstConst{$1, AstConst::BitFalse{}}; + BBUNSUP($1, "Unsupported: ## range cycle delay range expression"); } + | yP_POUNDPOUND yP_BRASTAR ']' + { $$ = new AstConst{$1, AstConst::BitFalse{}}; + BBUNSUP($1, "Unsupported: ## [*] cycle delay range expression"); } + | yP_POUNDPOUND yP_BRAPLUSKET + { $$ = new AstConst{$1, AstConst::BitFalse{}}; + BBUNSUP($1, "Unsupported: ## [+] cycle delay range expression"); } + ; //UNSUPsequence_match_itemList: // IEEE: [sequence_match_item] part of sequence_expr //UNSUP sequence_match_item { $$ = $1; } @@ -6162,30 +6177,29 @@ sexpr: // ==IEEE: sequence_expr (The name sexpr is important as reg //UNSUP for_step_assignment { $$ = $1; } //UNSUP ; -//UNSUPboolean_abbrev: // ==IEEE: boolean_abbrev -//UNSUP // // IEEE: consecutive_repetition -//UNSUP yP_BRASTAR const_or_range_expression ']' { } -//UNSUP | yP_BRASTAR ']' { } -//UNSUP | yP_BRAPLUSKET { $$ = $1; } -//UNSUP // // IEEE: non_consecutive_repetition -//UNSUP | yP_BRAEQ const_or_range_expression ']' { } -//UNSUP // // IEEE: goto_repetition -//UNSUP | yP_BRAMINUSGT const_or_range_expression ']' { } -//UNSUP ; - -//UNSUPconst_or_range_expression: // ==IEEE: const_or_range_expression -//UNSUP constExpr { $$ = $1; } -//UNSUP | cycle_delay_const_range_expression { } // Use anyrange removing [] instead -//UNSUP ; - -//UNSUPconstant_range: // ==IEEE: constant_range -//UNSUP constExpr ':' constExpr { } -//UNSUP ; - -//UNSUPcycle_delay_const_range_expression: // ==IEEE: cycle_delay_const_range_expression -//UNSUP // // Note '$' is part of constExpr -//UNSUP constExpr ':' constExpr { } -//UNSUP ; +boolean_abbrev: // ==IEEE: boolean_abbrev + // // IEEE: consecutive_repetition + yP_BRASTAR constExpr ']' { } + { $$ = $2; BBUNSUP($1, "Unsupported: [*] boolean abbrev expression"); } + | yP_BRASTAR constExpr ':' constExpr ']' { } + { $$ = $2; BBUNSUP($1, "Unsupported: [*] boolean abbrev expression"); } + | yP_BRASTAR ']' + { $$ = new AstConst{$1, AstConst::BitFalse{}}; + BBUNSUP($1, "Unsupported: [*] boolean abbrev expression"); } + | yP_BRAPLUSKET + { $$ = new AstConst{$1, AstConst::BitFalse{}}; + BBUNSUP($1, "Unsupported: [+] boolean abbrev expression"); } + // // IEEE: non_consecutive_repetition + | yP_BRAEQ constExpr ']' + { $$ = $2; BBUNSUP($1, "Unsupported: [= boolean abbrev expression"); } + | yP_BRAEQ constExpr ':' constExpr ']' + { $$ = $2; BBUNSUP($1, "Unsupported: [= boolean abbrev expression"); } + // // IEEE: goto_repetition + | yP_BRAMINUSGT constExpr ']' + { $$ = $2; BBUNSUP($1, "Unsupported: [-> boolean abbrev expression"); } + | yP_BRAMINUSGT constExpr ':' constExpr ']' + { $$ = $2; BBUNSUP($1, "Unsupported: [-> boolean abbrev expression"); } + ; //************************************************ // Let diff --git a/test_regress/t/t_sequence_sexpr_unsup.out b/test_regress/t/t_sequence_sexpr_unsup.out index 8e7445790..1f322e376 100644 --- a/test_regress/t/t_sequence_sexpr_unsup.out +++ b/test_regress/t/t_sequence_sexpr_unsup.out @@ -1,32 +1,144 @@ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:25:14: Unsupported: within (in sequence expression) - 25 | weak(a within(b)); +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:27:14: Unsupported: within (in sequence expression) + 27 | weak(a within(b)); | ^~~~~~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:25:11: Unsupported: weak (in property expression) - 25 | weak(a within(b)); +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:27:11: Unsupported: weak (in property expression) + 27 | weak(a within(b)); | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:29:14: Unsupported: and (in sequence expression) - 29 | weak(a and b); +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:31:14: Unsupported: and (in sequence expression) + 31 | weak(a and b); | ^~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:29:11: Unsupported: weak (in property expression) - 29 | weak(a and b); +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:31:11: Unsupported: weak (in property expression) + 31 | weak(a and b); | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:33:14: Unsupported: or (in sequence expression) - 33 | weak(a or b); +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:35:14: Unsupported: or (in sequence expression) + 35 | weak(a or b); | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:33:11: Unsupported: weak (in property expression) - 33 | weak(a or b); +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:35:11: Unsupported: weak (in property expression) + 35 | weak(a or b); | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:37:14: Unsupported: throughout (in sequence expression) - 37 | weak(a throughout b); +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:39:14: Unsupported: throughout (in sequence expression) + 39 | weak(a throughout b); | ^~~~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:37:11: Unsupported: weak (in property expression) - 37 | weak(a throughout b); +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:39:11: Unsupported: weak (in property expression) + 39 | weak(a throughout b); | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:41:14: Unsupported: intersect (in sequence expression) - 41 | weak(a intersect b); +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:43:14: Unsupported: intersect (in sequence expression) + 43 | weak(a intersect b); | ^~~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:41:11: Unsupported: weak (in property expression) - 41 | weak(a intersect b); +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:43:11: Unsupported: weak (in property expression) + 43 | weak(a intersect b); | ^ -%Error: Exiting due to +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:47:12: Unsupported: ## () cycle delay range expression + 47 | weak(## 1 b); + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:47:17: Unsupported: ## (in sequence expression) + 47 | weak(## 1 b); + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:47:11: Unsupported: weak (in property expression) + 47 | weak(## 1 b); + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:50:12: Unsupported: ## id cycle delay range expression + 50 | weak(## DELAY b); + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:50:21: Unsupported: ## (in sequence expression) + 50 | weak(## DELAY b); + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:50:11: Unsupported: weak (in property expression) + 50 | weak(## DELAY b); + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:53:12: Unsupported: ## () cycle delay range expression + 53 | weak(## ( DELAY ) b); + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:53:25: Unsupported: ## (in sequence expression) + 53 | weak(## ( DELAY ) b); + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:53:11: Unsupported: weak (in property expression) + 53 | weak(## ( DELAY ) b); + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:56:12: Unsupported: ## range cycle delay range expression + 56 | weak(## [1:2] b); + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:56:21: Unsupported: ## (in sequence expression) + 56 | weak(## [1:2] b); + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:56:11: Unsupported: weak (in property expression) + 56 | weak(## [1:2] b); + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:59:12: Unsupported: ## [*] cycle delay range expression + 59 | weak(## [*] b); + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:59:19: Unsupported: ## (in sequence expression) + 59 | weak(## [*] b); + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:59:11: Unsupported: weak (in property expression) + 59 | weak(## [*] b); + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:62:12: Unsupported: ## [+] cycle delay range expression + 62 | weak(## [+] b); + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:62:19: Unsupported: ## (in sequence expression) + 62 | weak(## [+] b); + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:62:11: Unsupported: weak (in property expression) + 62 | weak(## [+] b); + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:66:14: Unsupported: ## () cycle delay range expression + 66 | weak(a ## 1 b); + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:66:17: Unsupported: ## (in sequence expression) + 66 | weak(a ## 1 b); + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:66:11: Unsupported: weak (in property expression) + 66 | weak(a ## 1 b); + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:69:14: Unsupported: ## id cycle delay range expression + 69 | weak(a ## DELAY b); + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:69:14: Unsupported: ## (in sequence expression) + 69 | weak(a ## DELAY b); + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:69:11: Unsupported: weak (in property expression) + 69 | weak(a ## DELAY b); + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:72:14: Unsupported: ## () cycle delay range expression + 72 | weak(a ## ( DELAY ) b); + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:72:19: Unsupported: ## (in sequence expression) + 72 | weak(a ## ( DELAY ) b); + | ^~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:72:11: Unsupported: weak (in property expression) + 72 | weak(a ## ( DELAY ) b); + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:75:14: Unsupported: ## range cycle delay range expression + 75 | weak(a ## [1:2] b); + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:75:14: Unsupported: ## (in sequence expression) + 75 | weak(a ## [1:2] b); + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:75:11: Unsupported: weak (in property expression) + 75 | weak(a ## [1:2] b); + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:78:14: Unsupported: ## [*] cycle delay range expression + 78 | weak(a ## [*] b); + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:78:14: Unsupported: ## (in sequence expression) + 78 | weak(a ## [*] b); + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:78:11: Unsupported: weak (in property expression) + 78 | weak(a ## [*] b); + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:81:14: Unsupported: ## [+] cycle delay range expression + 81 | weak(a ## [+] b); + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:81:14: Unsupported: ## (in sequence expression) + 81 | weak(a ## [+] b); + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:81:11: Unsupported: weak (in property expression) + 81 | weak(a ## [+] b); + | ^ +%Error: t/t_sequence_sexpr_unsup.v:85:12: syntax error, unexpected [*, expecting TYPE-IDENTIFIER + 85 | weak([* 1 ] a); + | ^~ +%Error: Cannot continue + ... See the manual at https://verilator.org/verilator_doc.html for more assistance. diff --git a/test_regress/t/t_sequence_sexpr_unsup.v b/test_regress/t/t_sequence_sexpr_unsup.v index eed60e3f0..2f92d7f27 100644 --- a/test_regress/t/t_sequence_sexpr_unsup.v +++ b/test_regress/t/t_sequence_sexpr_unsup.v @@ -14,6 +14,8 @@ module t (/*AUTOARG*/ int b; int cyc = 0; + localparam DELAY = 1; + always @(posedge clk) begin cyc <= cyc + 1; end @@ -41,6 +43,66 @@ module t (/*AUTOARG*/ weak(a intersect b); endproperty + property s_uni_cycdelay_int; + weak(## 1 b); + endproperty + property s_uni_cycdelay_id; + weak(## DELAY b); + endproperty + property s_uni_cycdelay_pid; + weak(## ( DELAY ) b); + endproperty + property s_uni_cycdelay_range; + weak(## [1:2] b); + endproperty + property s_uni_cycdelay_star; + weak(## [*] b); + endproperty + property s_uni_cycdelay_plus; + weak(## [+] b); + endproperty + + property s_cycdelay_int; + weak(a ## 1 b); + endproperty + property s_cycdelay_id; + weak(a ## DELAY b); + endproperty + property s_cycdelay_pid; + weak(a ## ( DELAY ) b); + endproperty + property s_cycdelay_range; + weak(a ## [1:2] b); + endproperty + property s_cycdelay_star; + weak(a ## [*] b); + endproperty + property s_cycdelay_plus; + weak(a ## [+] b); + endproperty + + property s_booleanabbrev_brastar_int; + weak([* 1 ] a); + endproperty + property s_booleanabbrev_brastar; + weak([*] a); + endproperty + property s_booleanabbrev_plus; + weak([+] a); + endproperty + property s_booleanabbrev_eq; + weak([= 1] a); + endproperty + property s_booleanabbrev_eq_range; + weak([= 1:2] a); + endproperty + property s_booleanabbrev_minusgt; + weak([-> 1] a); + endproperty + property s_booleanabbrev_minusgt_range; + weak([-> 1:2] a); + endproperty + always @(posedge clk) begin if (cyc == 10) begin $write("*-* All Finished *-*\n"); From 87c3de5aabdb43f6326f47cffa8a2250b7da6d26 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 5 Mar 2023 23:58:54 -0500 Subject: [PATCH 010/155] Parse 'matches', still unsupported. --- src/verilog.l | 2 +- src/verilog.y | 23 +++++++++++++---------- test_regress/t/t_tagged.out | 36 ++++++++++++------------------------ 3 files changed, 26 insertions(+), 35 deletions(-) diff --git a/src/verilog.l b/src/verilog.l index 3aae01d07..26bd7fd10 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -545,7 +545,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "local" { FL; return yLOCAL__LEX; } "logic" { FL; return yLOGIC; } "longint" { FL; return yLONGINT; } - "matches" { ERROR_RSVD_WORD("SystemVerilog 2005"); } + "matches" { FL; return yMATCHES; } "modport" { FL; return yMODPORT; } "new" { FL; return yNEW__LEX; } "null" { FL; return yNULL; } diff --git a/src/verilog.y b/src/verilog.y index bb3f938f8..20d67cc2c 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -656,7 +656,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yLOCAL__LEX "local-in-lex" %token yLOGIC "logic" %token yLONGINT "longint" -//UNSUP %token yMATCHES "matches" +%token yMATCHES "matches" %token yMODPORT "modport" %token yMODULE "module" %token yNAND "nand" @@ -1056,11 +1056,11 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) //UNSUP %token prREDUCTION //UNSUP %token prNEGATION //UNSUP %token prEVENTBEGIN -//UNSUP %token prTAGGED +%token prTAGGED // These prevent other conflicts %left yP_ANDANDAND -//UNSUP %left yMATCHES +%left yMATCHES //UNSUP %left prTAGGED //UNSUP %left prSEQ_CLOCKING @@ -3482,7 +3482,9 @@ statement_item: // IEEE: statement_item if ($1 == uniq_UNIQUE) $2->uniquePragma(true); if ($1 == uniq_UNIQUE0) $2->unique0Pragma(true); if ($1 == uniq_PRIORITY) $2->priorityPragma(true); } - //UNSUP caseStart caseAttrE yMATCHES case_patternListE yENDCASE { } + // &&& is part of expr so case_patternListE aliases to case_itemListE + | unique_priorityE caseStart caseAttrE yMATCHES case_patternListE yENDCASE + { $$ = nullptr; BBUNSUP($4, "Unsupported: matches (for tagged union)"); } | unique_priorityE caseStart caseAttrE yINSIDE case_insideListE yENDCASE { $$ = $2; if ($5) $2->addItemsp($5); if (!$2->caseSimple()) $2->v3error("Illegal to have inside on a casex/casez"); @@ -3750,10 +3752,9 @@ caseAttrE: | caseAttrE yVL_PARALLEL_CASE { GRAMMARP->m_caseAttrp->parallelPragma(true); } ; -//UNSUPcase_patternListE: // IEEE: case_pattern_item -//UNSUP // &&& is part of expr so aliases to case_itemList -//UNSUP case_itemListE { $$ = $1; } -//UNSUP ; +case_patternListE: // IEEE: case_pattern_item + case_itemListE { $$ = $1; } + ; case_itemListE: // IEEE: [ { case_item } ] /* empty */ { $$ = nullptr; } @@ -4859,8 +4860,10 @@ expr: // IEEE: part of expression/constant_expression/ // // IEEE: cond_pattern - here to avoid reduce problems // // "expr yMATCHES pattern" // // IEEE: pattern - expanded here to avoid conflicts - //UNSUP ~l~expr yMATCHES patternNoExpr { UNSUP } - //UNSUP ~l~expr yMATCHES ~r~expr { UNSUP } + | ~l~expr yMATCHES patternNoExpr { $$ = new AstConst{$2, AstConst::BitFalse{}}; + BBUNSUP($2, "Unsupported: matches operator"); } + | ~l~expr yMATCHES ~r~expr { $$ = new AstConst{$2, AstConst::BitFalse{}}; + BBUNSUP($2, "Unsupported: matches operator"); } // // // IEEE: expression_or_dist - here to avoid reduce problems // // "expr yDIST '{' dist_list '}'" diff --git a/test_regress/t/t_tagged.out b/test_regress/t/t_tagged.out index b0279d98d..889926ef0 100644 --- a/test_regress/t/t_tagged.out +++ b/test_regress/t/t_tagged.out @@ -8,61 +8,49 @@ %Error-UNSUPPORTED: t/t_tagged.v:18:11: Unsupported: SystemVerilog 2005 reserved word not implemented: 'tagged' 18 | u = tagged m_invalid; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged.v:21:16: Unsupported: SystemVerilog 2005 reserved word not implemented: 'matches' - 21 | case (u) matches - | ^~~~~~~ %Error-UNSUPPORTED: t/t_tagged.v:22:9: Unsupported: SystemVerilog 2005 reserved word not implemented: 'tagged' 22 | tagged m_invalid: ; | ^~~~~~ %Error-UNSUPPORTED: t/t_tagged.v:23:9: Unsupported: SystemVerilog 2005 reserved word not implemented: 'tagged' 23 | tagged m_int: $stop; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged.v:26:13: Unsupported: SystemVerilog 2005 reserved word not implemented: 'matches' - 26 | if (u matches tagged m_invalid) ; - | ^~~~~~~ +%Error-UNSUPPORTED: t/t_tagged.v:21:16: Unsupported: matches (for tagged union) + 21 | case (u) matches + | ^~~~~~~ %Error-UNSUPPORTED: t/t_tagged.v:26:21: Unsupported: SystemVerilog 2005 reserved word not implemented: 'tagged' 26 | if (u matches tagged m_invalid) ; | ^~~~~~ -%Error: t/t_tagged.v:26:28: syntax error, unexpected IDENTIFIER +%Error-UNSUPPORTED: t/t_tagged.v:26:13: Unsupported: matches operator 26 | if (u matches tagged m_invalid) ; - | ^~~~~~~~~ -%Error-UNSUPPORTED: t/t_tagged.v:27:13: Unsupported: SystemVerilog 2005 reserved word not implemented: 'matches' - 27 | if (u matches tagged m_int .n) $stop; | ^~~~~~~ %Error-UNSUPPORTED: t/t_tagged.v:27:21: Unsupported: SystemVerilog 2005 reserved word not implemented: 'tagged' 27 | if (u matches tagged m_int .n) $stop; | ^~~~~~ -%Error: t/t_tagged.v:27:28: syntax error, unexpected IDENTIFIER +%Error-UNSUPPORTED: t/t_tagged.v:27:13: Unsupported: matches operator 27 | if (u matches tagged m_int .n) $stop; - | ^~~~~ + | ^~~~~~~ %Error-UNSUPPORTED: t/t_tagged.v:29:11: Unsupported: SystemVerilog 2005 reserved word not implemented: 'tagged' 29 | u = tagged m_int (123); | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged.v:32:16: Unsupported: SystemVerilog 2005 reserved word not implemented: 'matches' - 32 | case (u) matches - | ^~~~~~~ %Error-UNSUPPORTED: t/t_tagged.v:33:9: Unsupported: SystemVerilog 2005 reserved word not implemented: 'tagged' 33 | tagged m_invalid: $stop; | ^~~~~~ %Error-UNSUPPORTED: t/t_tagged.v:34:9: Unsupported: SystemVerilog 2005 reserved word not implemented: 'tagged' 34 | tagged m_int .n: if (n !== 123) $stop; | ^~~~~~ -%Error-UNSUPPORTED: t/t_tagged.v:37:13: Unsupported: SystemVerilog 2005 reserved word not implemented: 'matches' - 37 | if (u matches tagged m_invalid) $stop; - | ^~~~~~~ +%Error-UNSUPPORTED: t/t_tagged.v:32:16: Unsupported: matches (for tagged union) + 32 | case (u) matches + | ^~~~~~~ %Error-UNSUPPORTED: t/t_tagged.v:37:21: Unsupported: SystemVerilog 2005 reserved word not implemented: 'tagged' 37 | if (u matches tagged m_invalid) $stop; | ^~~~~~ -%Error: t/t_tagged.v:37:28: syntax error, unexpected IDENTIFIER +%Error-UNSUPPORTED: t/t_tagged.v:37:13: Unsupported: matches operator 37 | if (u matches tagged m_invalid) $stop; - | ^~~~~~~~~ -%Error-UNSUPPORTED: t/t_tagged.v:38:13: Unsupported: SystemVerilog 2005 reserved word not implemented: 'matches' - 38 | if (u matches tagged m_int .n) if (n != 123) $stop; | ^~~~~~~ %Error-UNSUPPORTED: t/t_tagged.v:38:21: Unsupported: SystemVerilog 2005 reserved word not implemented: 'tagged' 38 | if (u matches tagged m_int .n) if (n != 123) $stop; | ^~~~~~ -%Error: t/t_tagged.v:38:28: syntax error, unexpected IDENTIFIER +%Error-UNSUPPORTED: t/t_tagged.v:38:13: Unsupported: matches operator 38 | if (u matches tagged m_int .n) if (n != 123) $stop; - | ^~~~~ + | ^~~~~~~ %Error: Exiting due to From 725ec088ea773da415d46ddc7b2c0f156460874b Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 6 Mar 2023 05:12:09 -0500 Subject: [PATCH 011/155] Parse 'sequence' declarations, property case/if, still unsupported. --- src/verilog.l | 2 +- src/verilog.y | 198 +++++----- .../t/t_assert_property_pexpr_unsup.out | 142 ++++--- .../t/t_assert_property_pexpr_unsup.pl | 2 +- .../t/t_assert_property_pexpr_unsup.v | 23 +- .../t/t_assert_recursive_property_unsup.out | 6 +- test_regress/t/t_sequence_sexpr_unsup.out | 366 +++++++++++------- test_regress/t/t_sequence_sexpr_unsup.pl | 2 +- test_regress/t/t_sequence_sexpr_unsup.v | 162 ++++---- 9 files changed, 531 insertions(+), 372 deletions(-) diff --git a/src/verilog.l b/src/verilog.l index 26bd7fd10..ced9de537 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -564,7 +564,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "ref" { FL; return yREF; } "restrict" { FL; return yRESTRICT; } "return" { FL; return yRETURN; } - "sequence" { ERROR_RSVD_WORD("SystemVerilog 2005"); } + "sequence" { FL; return ySEQUENCE; } "shortint" { FL; return ySHORTINT; } "shortreal" { FL; return ySHORTREAL; } "solve" { FL; return ySOLVE; } diff --git a/src/verilog.y b/src/verilog.y index 20d67cc2c..ee8384990 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -710,7 +710,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yRTRANIF0 "rtranif0" %token yRTRANIF1 "rtranif1" %token ySCALARED "scalared" -//UNSUP %token ySEQUENCE "sequence" +%token ySEQUENCE "sequence" %token ySHORTINT "shortint" %token ySHORTREAL "shortreal" %token ySIGNED "signed" @@ -2509,10 +2509,11 @@ implicit_typeE: // IEEE: part of *data_type_or_implicit { $$ = new AstBasicDType{$1, LOGIC_IMPLICIT, $1}; } ; -//UNSUPassertion_variable_declaration: // IEEE: assertion_variable_declaration -//UNSUP // // IEEE: var_data_type expanded -//UNSUP var_data_type list_of_variable_decl_assignments ';' { } -//UNSUP ; +assertion_variable_declaration: // IEEE: assertion_variable_declaration + // // IEEE: var_data_type expanded + var_data_type { VARRESET_NONLIST(VAR); VARDTYPE_NDECL($1); } + /*cont*/ list_of_variable_decl_assignments ';' { $$ = $3; } + ; type_declaration: // ==IEEE: type_declaration // Data_type expanded @@ -5685,8 +5686,8 @@ cycle_delay: // IEEE: cycle_delay assertion_item_declaration: // ==IEEE: assertion_item_declaration property_declaration { $$ = $1; } -//UNSUP | sequence_declaration { $$ = $1; } -//UNSUP | let_declaration { $$ = $1; } + | sequence_declaration { $$ = $1; } + //UNSUP let_declaration { $$ = $1; } ; assertion_item: // ==IEEE: assertion_item @@ -5780,15 +5781,20 @@ concurrent_assertion_statement: // ==IEEE: concurrent_assertion_statemen { $$ = new AstAssert{$1, new AstSampled{$1, $4}, nullptr, $6, false}; } //UNSUP yASSUME yPROPERTY '(' property_spec ')' action_block { } // // IEEE: cover_property_statement - | yCOVER yPROPERTY '(' property_spec ')' stmtBlock { $$ = new AstCover{$1, $4, $6, false}; } + | yCOVER yPROPERTY '(' property_spec ')' stmtBlock + { $$ = new AstCover{$1, $4, $6, false}; } // // IEEE: cover_sequence_statement - //UNSUP yCOVER ySEQUENCE '(' sexpr ')' stmt { } + | yCOVER ySEQUENCE '(' sexpr ')' stmt + { $$ = nullptr; BBUNSUP($2, "Unsupported: cover sequence"); } // // IEEE: yCOVER ySEQUENCE '(' clocking_event sexpr ')' stmt // // sexpr already includes "clocking_event sexpr" - //UNSUP yCOVER ySEQUENCE '(' clocking_event yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' sexpr ')' stmt { } - //UNSUP yCOVER ySEQUENCE '(' yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' sexpr ')' stmt { } + | yCOVER ySEQUENCE '(' clocking_event yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' sexpr ')' stmt + { $$ = nullptr; BBUNSUP($2, "Unsupported: cover sequence"); } + | yCOVER ySEQUENCE '(' yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' sexpr ')' stmt + { $$ = nullptr; BBUNSUP($2, "Unsupported: cover sequence"); } // // IEEE: restrict_property_statement - | yRESTRICT yPROPERTY '(' property_spec ')' ';' { $$ = new AstRestrict{$1, $4}; } + | yRESTRICT yPROPERTY '(' property_spec ')' ';' + { $$ = new AstRestrict{$1, $4}; } ; elseStmtBlock: // Part of concurrent_assertion_statement @@ -5799,20 +5805,20 @@ elseStmtBlock: // Part of concurrent_assertion_statement property_declaration: // ==IEEE: property_declaration property_declarationFront property_port_listE ';' property_declarationBody yENDPROPERTY endLabelE - { $$ = $1; - $$->addStmtsp($2); - $$->addStmtsp($4); - SYMP->popScope($$); - GRAMMARP->endLabel($6, $$, $6); - GRAMMARP->m_insideProperty = false; - GRAMMARP->m_typedPropertyPort = false; } + { $$ = $1; + $$->addStmtsp($2); + $$->addStmtsp($4); + SYMP->popScope($$); + GRAMMARP->endLabel($6, $$, $6); + GRAMMARP->m_insideProperty = false; + GRAMMARP->m_typedPropertyPort = false; } ; property_declarationFront: // IEEE: part of property_declaration yPROPERTY idAny/*property_identifier*/ - { $$ = new AstProperty{$1, *$2, nullptr}; - GRAMMARP->m_insideProperty = true; - SYMP->pushNewUnderNodeOrCurrent($$, nullptr); } + { $$ = new AstProperty{$2, *$2, nullptr}; + GRAMMARP->m_insideProperty = true; + SYMP->pushNewUnderNodeOrCurrent($$, nullptr); } ; property_port_listE: // IEEE: [ ( [ property_port_list ] ) ] @@ -5848,71 +5854,83 @@ property_port_itemFront: // IEEE: part of property_port_item/sequence_port_item property_port_itemAssignment: // IEEE: part of property_port_item/sequence_port_item/checker_port_direction id variable_dimensionListE { $$ = VARDONEA($1, *$1, $2, nullptr); } -//UNSUP | id variable_dimensionListE '=' property_actual_arg -//UNSUP { VARDONE($1, $1, $2, $4); PINNUMINC(); } + //UNSUP|id variable_dimensionListE '=' property_actual_arg + //UNSUP { VARDONE($1, $1, $2, $4); PINNUMINC(); } ; property_port_itemDirE: /* empty */ { GRAMMARP->m_pinAnsi = true; VARIO(INPUT); } -//UNSUP | yLOCAL__ETC { GRAMMARP->m_pinAnsi = true; VARIO(INPUT); } -//UNSUP | yLOCAL__ETC yINPUT { GRAMMARP->m_pinAnsi = true; VARIO(INPUT); } + //UNSUP|yLOCAL__ETC { GRAMMARP->m_pinAnsi = true; VARIO(INPUT); } + //UNSUP|yLOCAL__ETC yINPUT { GRAMMARP->m_pinAnsi = true; VARIO(INPUT); } ; property_declarationBody: // IEEE: part of property_declaration -//UNSUP assertion_variable_declarationList property_statement_spec { } -//UNSUP // // IEEE-2012: Incorectly hasyCOVER ySEQUENCE then property_spec here. -//UNSUP // // Fixed in IEEE 1800-2017 + //UNSUP assertion_variable_declarationList property_statement_spec {} + // // IEEE-2012: Incorectly hasyCOVER ySEQUENCE then property_spec here. + // // Fixed in IEEE 1800-2017 property_spec { $$ = $1; } | property_spec ';' { $$ = $1; } ; -//UNSUPassertion_variable_declarationList: // IEEE: part of assertion_variable_declaration -//UNSUP assertion_variable_declaration { $$ = $1; } -//UNSUP | assertion_variable_declarationList assertion_variable_declaration { } -//UNSUP ; +assertion_variable_declarationList: // IEEE: part of assertion_variable_declaration + assertion_variable_declaration { $$ = $1; } + | assertion_variable_declarationList assertion_variable_declaration + { $$ = addNextNull($1, $2); } + ; -//UNSUPsequence_declaration: // ==IEEE: sequence_declaration -//UNSUP sequence_declarationFront sequence_port_listE ';' sequence_declarationBody -//UNSUP yENDSEQUENCE endLabelE -//UNSUP { SYMP->popScope($$); } -//UNSUP ; +sequence_declaration: // ==IEEE: sequence_declaration + sequence_declarationFront sequence_port_listE ';' sequence_declarationBody + /*cont*/ yENDSEQUENCE endLabelE + { $$ = $1; + $$->addStmtsp($2); + $$->addStmtsp($4); + SYMP->popScope($$); + GRAMMARP->endLabel($6, $$, $6); } + ; -//UNSUPsequence_declarationFront: // IEEE: part of sequence_declaration -//UNSUP ySEQUENCE idAny/*new_sequence*/ -//UNSUP { SYMP->pushNew($$); } -//UNSUP ; +sequence_declarationFront: // IEEE: part of sequence_declaration + ySEQUENCE idAny/*new_sequence*/ + { BBUNSUP($1, "Unsupported: sequence"); + $$ = new AstProperty{$2, *$2, nullptr}; + SYMP->pushNewUnderNodeOrCurrent($$, nullptr); } + ; -//UNSUPsequence_port_listE: // IEEE: [ ( [ sequence_port_list ] ) ] -//UNSUP // // IEEE: sequence_lvar_port_direction ::= yINPUT | yINOUT | yOUTPUT -//UNSUP // // IEEE: [ yLOCAL [ sequence_lvar_port_direction ] ] sequence_formal_type -//UNSUP // // id {variable_dimension} [ '=' sequence_actual_arg ] -//UNSUP // // All this is almost identically the same as a property. -//UNSUP // // Difference is only yINOUT/yOUTPUT (which might be added to 1800-2012) -//UNSUP // // and yPROPERTY. So save some work. -//UNSUP property_port_listE { $$ = $1; } -//UNSUP ; +sequence_port_listE: // IEEE: [ ( [ sequence_port_list ] ) ] + // // IEEE: sequence_lvar_port_direction ::= yINPUT | yINOUT | yOUTPUT + // // IEEE: [ yLOCAL [ sequence_lvar_port_direction ] ] sequence_formal_type + // // id {variable_dimension} [ '=' sequence_actual_arg ] + // // All this is almost identically the same as a property. + // // Difference is only yINOUT/yOUTPUT (which might be added to 1800-2012) + // // and yPROPERTY. So save some work. + property_port_listE { $$ = $1; } + ; property_formal_typeNoDt: // IEEE: property_formal_type (w/o implicit) sequence_formal_typeNoDt { $$ = $1; } -//UNSUP | yPROPERTY { } + | yPROPERTY + { $$ = nullptr; GRAMMARP->m_typedPropertyPort = false; + BBUNSUP($1, "Unsupported: property argument data type"); } ; sequence_formal_typeNoDt: // ==IEEE: sequence_formal_type (w/o data_type_or_implicit) -// // IEEE: data_type_or_implicit -// // implicit expanded where used -//UNSUP ySEQUENCE { } -// // IEEE-2009: yEVENT -// // already part of data_type. Removed in 1800-2012. - yUNTYPED { $$ = nullptr; GRAMMARP->m_typedPropertyPort = false; } + // IEEE: data_type_or_implicit + // implicit expanded where used + ySEQUENCE + { $$ = nullptr; GRAMMARP->m_typedPropertyPort = false; + BBUNSUP($1, "Unsupported: sequence argument data type"); } + // IEEE-2009: yEVENT + // already part of data_type. Removed in 1800-2012. + | yUNTYPED + { $$ = nullptr; GRAMMARP->m_typedPropertyPort = false; } ; -//UNSUPsequence_declarationBody: // IEEE: part of sequence_declaration -//UNSUP // // 1800-2012 makes ';' optional -//UNSUP assertion_variable_declarationList sexpr { } -//UNSUP | assertion_variable_declarationList sexpr ';' { } -//UNSUP | sexpr { $$ = $1; } -//UNSUP | sexpr ';' { $$ = $1; } -//UNSUP ; +sequence_declarationBody: // IEEE: part of sequence_declaration + // // 1800-2012 makes ';' optional + assertion_variable_declarationList sexpr { $$ = addNextNull($1, $2); } + | assertion_variable_declarationList sexpr ';' { $$ = addNextNull($1, $2); } + | sexpr { $$ = $1; } + | sexpr ';' { $$ = $1; } + ; property_spec: // IEEE: property_spec //UNSUP: This rule has been super-specialized to what is supported now @@ -5945,27 +5963,33 @@ property_spec: // IEEE: property_spec //UNSUP | property_statementCaseIf { $$ = $1; } //UNSUP ; -//UNSUPproperty_statementCaseIf: // IEEE: property_statement - minus pexpr -//UNSUP yCASE '(' expr/*expression_or_dist*/ ')' property_case_itemList yENDCASE { } -//UNSUP | yCASE '(' expr/*expression_or_dist*/ ')' yENDCASE { } -//UNSUP | yIF '(' expr/*expression_or_dist*/ ')' pexpr %prec prLOWER_THAN_ELSE { } -//UNSUP | yIF '(' expr/*expression_or_dist*/ ')' pexpr yELSE pexpr { } -//UNSUP ; +property_statementCaseIf: // IEEE: property_statement - minus pexpr + yCASE '(' expr/*expression_or_dist*/ ')' property_case_itemList yENDCASE + { $$ = new AstConst{$1, AstConst::BitFalse{}}; + BBUNSUP($1, "Unsupported: property case expression"); } + | yCASE '(' expr/*expression_or_dist*/ ')' yENDCASE + { $$ = new AstConst{$1, AstConst::BitFalse{}}; + BBUNSUP($1, "Unsupported: property case expression"); } + | yIF '(' expr/*expression_or_dist*/ ')' pexpr %prec prLOWER_THAN_ELSE + { $$ = $5; BBUNSUP($1, "Unsupported: property case expression"); } + | yIF '(' expr/*expression_or_dist*/ ')' pexpr yELSE pexpr + { $$ = $5; BBUNSUP($1, "Unsupported: property case expression"); } + ; -//UNSUPproperty_case_itemList: // IEEE: {property_case_item} -//UNSUP property_case_item { $$ = $1; } -//UNSUP | property_case_itemList ',' property_case_item { $$ = addNextNull($1, $3); } -//UNSUP ; +property_case_itemList: // IEEE: {property_case_item} + property_case_item { $$ = $1; } + | property_case_itemList ',' property_case_item { $$ = addNextNull($1, $3); } + ; -//UNSUPproperty_case_item: // ==IEEE: property_case_item -//UNSUP // // IEEE: expression_or_dist { ',' expression_or_dist } ':' property_statement -//UNSUP // // IEEE 1800-2012 changed from property_statement to property_expr -//UNSUP // // IEEE 1800-2017 changed to require the semicolon -//UNSUP caseCondList ':' pexpr { } -//UNSUP | caseCondList ':' pexpr ';' { } -//UNSUP | yDEFAULT pexpr { } -//UNSUP | yDEFAULT ':' pexpr ';' { } -//UNSUP ; +property_case_item: // ==IEEE: property_case_item + // // IEEE: expression_or_dist { ',' expression_or_dist } ':' property_statement + // // IEEE 1800-2012 changed from property_statement to property_expr + // // IEEE 1800-2017 changed to require the semicolon + caseCondList ':' pexpr { $$ = new AstCaseItem{$2, $1, $3}; } + | caseCondList ':' pexpr ';' { $$ = new AstCaseItem{$2, $1, $3}; } + | yDEFAULT pexpr { $$ = new AstCaseItem{$1, nullptr, $2}; } + | yDEFAULT ':' pexpr ';' { $$ = new AstCaseItem{$1, nullptr, $3}; } + ; //UNSUPpev_expr: // IEEE: property_actual_arg | expr //UNSUP // // which expands to pexpr | event_expression @@ -6017,7 +6041,7 @@ pexpr: // IEEE: property_expr (The name pexpr is important as regex // // // IEEE-2009: property_statement // // IEEE-2012: yIF and yCASE - //UNSUP property_statementCaseIf { } + | property_statementCaseIf { $$ = $1; } // | ~o~pexpr/*sexpr*/ yP_POUNDMINUSPD pexpr { $$ = $3; BBUNSUP($2, "Unsupported: #-# (in property expression)"); } @@ -6182,9 +6206,9 @@ cycle_delay_range: // IEEE: ==cycle_delay_range boolean_abbrev: // ==IEEE: boolean_abbrev // // IEEE: consecutive_repetition - yP_BRASTAR constExpr ']' { } + yP_BRASTAR constExpr ']' { $$ = $2; BBUNSUP($1, "Unsupported: [*] boolean abbrev expression"); } - | yP_BRASTAR constExpr ':' constExpr ']' { } + | yP_BRASTAR constExpr ':' constExpr ']' { $$ = $2; BBUNSUP($1, "Unsupported: [*] boolean abbrev expression"); } | yP_BRASTAR ']' { $$ = new AstConst{$1, AstConst::BitFalse{}}; diff --git a/test_regress/t/t_assert_property_pexpr_unsup.out b/test_regress/t/t_assert_property_pexpr_unsup.out index e70cc0825..882db1882 100644 --- a/test_regress/t/t_assert_property_pexpr_unsup.out +++ b/test_regress/t/t_assert_property_pexpr_unsup.out @@ -1,95 +1,113 @@ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:24:13: Unsupported: strong (in property expression) - 24 | strong(a); +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:25:13: Unsupported: strong (in property expression) + 25 | strong(a); | ^ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:28:11: Unsupported: weak (in property expression) - 28 | weak(a); +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:29:11: Unsupported: weak (in property expression) + 29 | weak(a); | ^ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:32:9: Unsupported: until (in property expression) - 32 | a until b; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:33:9: Unsupported: until (in property expression) + 33 | a until b; | ^~~~~ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:36:9: Unsupported: s_until (in property expression) - 36 | a s_until b; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:37:9: Unsupported: s_until (in property expression) + 37 | a s_until b; | ^~~~~~~ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:40:9: Unsupported: until_with (in property expression) - 40 | a until_with b; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:41:9: Unsupported: until_with (in property expression) + 41 | a until_with b; | ^~~~~~~~~~ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:44:9: Unsupported: s_until_with (in property expression) - 44 | a s_until_with b; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:45:9: Unsupported: s_until_with (in property expression) + 45 | a s_until_with b; | ^~~~~~~~~~~~ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:48:9: Unsupported: implies (in property expression) - 48 | a implies b; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:49:9: Unsupported: implies (in property expression) + 49 | a implies b; | ^~~~~~~ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:52:9: Unsupported: #-# (in property expression) - 52 | a #-# b; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:53:9: Unsupported: #-# (in property expression) + 53 | a #-# b; | ^~~ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:56:9: Unsupported: #=# (in property expression) - 56 | a #=# b; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:57:9: Unsupported: #=# (in property expression) + 57 | a #=# b; | ^~~ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:60:7: Unsupported: nexttime (in property expression) - 60 | nexttime a; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:61:7: Unsupported: nexttime (in property expression) + 61 | nexttime a; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:64:7: Unsupported: nexttime[] (in property expression) - 64 | nexttime [2] a; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:65:7: Unsupported: nexttime[] (in property expression) + 65 | nexttime [2] a; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:68:7: Unsupported: s_nexttime (in property expression) - 68 | s_nexttime a; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:69:7: Unsupported: s_nexttime (in property expression) + 69 | s_nexttime a; | ^~~~~~~~~~ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:72:7: Unsupported: s_nexttime[] (in property expression) - 72 | s_nexttime [2] a; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:73:7: Unsupported: s_nexttime[] (in property expression) + 73 | s_nexttime [2] a; | ^~~~~~~~~~ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:76:16: Unsupported: always (in property expression) - 76 | nexttime always a; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:77:16: Unsupported: always (in property expression) + 77 | nexttime always a; | ^~~~~~ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:76:7: Unsupported: nexttime (in property expression) - 76 | nexttime always a; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:77:7: Unsupported: nexttime (in property expression) + 77 | nexttime always a; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:80:20: Unsupported: always (in property expression) - 80 | nexttime [2] always a; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:81:20: Unsupported: always (in property expression) + 81 | nexttime [2] always a; | ^~~~~~ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:80:7: Unsupported: nexttime[] (in property expression) - 80 | nexttime [2] always a; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:81:7: Unsupported: nexttime[] (in property expression) + 81 | nexttime [2] always a; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:84:16: Unsupported: eventually (in property expression) - 84 | nexttime eventually a; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:85:16: Unsupported: eventually (in property expression) + 85 | nexttime eventually a; | ^~~~~~~~~~ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:84:7: Unsupported: nexttime (in property expression) - 84 | nexttime eventually a; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:85:7: Unsupported: nexttime (in property expression) + 85 | nexttime eventually a; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:88:20: Unsupported: always (in property expression) - 88 | nexttime [2] always a; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:89:20: Unsupported: always (in property expression) + 89 | nexttime [2] always a; | ^~~~~~ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:88:7: Unsupported: nexttime[] (in property expression) - 88 | nexttime [2] always a; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:89:7: Unsupported: nexttime[] (in property expression) + 89 | nexttime [2] always a; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:92:16: Unsupported: s_eventually (in property expression) - 92 | nexttime s_eventually a; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:93:16: Unsupported: s_eventually (in property expression) + 93 | nexttime s_eventually a; | ^~~~~~~~~~~~ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:92:7: Unsupported: nexttime (in property expression) - 92 | nexttime s_eventually a; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:93:7: Unsupported: nexttime (in property expression) + 93 | nexttime s_eventually a; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:96:35: Unsupported: always (in property expression) - 96 | nexttime s_eventually [2:$] always a; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:97:35: Unsupported: always (in property expression) + 97 | nexttime s_eventually [2:$] always a; | ^~~~~~ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:96:16: Unsupported: s_eventually[] (in property expression) - 96 | nexttime s_eventually [2:$] always a; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:97:16: Unsupported: s_eventually[] (in property expression) + 97 | nexttime s_eventually [2:$] always a; | ^~~~~~~~~~~~ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:96:7: Unsupported: nexttime (in property expression) - 96 | nexttime s_eventually [2:$] always a; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:97:7: Unsupported: nexttime (in property expression) + 97 | nexttime s_eventually [2:$] always a; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:100:17: Unsupported: accept_on (in property expression) - 100 | accept_on (a) b; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:101:17: Unsupported: accept_on (in property expression) + 101 | accept_on (a) b; | ^ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:104:22: Unsupported: sync_accept_on (in property expression) - 104 | sync_accept_on (a) b; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:105:22: Unsupported: sync_accept_on (in property expression) + 105 | sync_accept_on (a) b; | ^ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:108:17: Unsupported: reject_on (in property expression) - 108 | reject_on (a) b; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:109:17: Unsupported: reject_on (in property expression) + 109 | reject_on (a) b; | ^ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:112:22: Unsupported: sync_reject_on (in property expression) - 112 | sync_reject_on (a) b; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:113:22: Unsupported: sync_reject_on (in property expression) + 113 | sync_reject_on (a) b; | ^ -%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:116:9: Unsupported: iff (in property expression) - 116 | a iff b; +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:117:9: Unsupported: iff (in property expression) + 117 | a iff b; | ^~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:120:27: Unsupported: property argument data type + 120 | property p_arg_propery(property inprop); + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:123:27: Unsupported: sequence argument data type + 123 | property p_arg_seqence(sequence inseq); + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:128:7: Unsupported: property case expression + 128 | case (a) endcase + | ^~~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:131:7: Unsupported: property case expression + 131 | case (a) default: b; endcase + | ^~~~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:134:7: Unsupported: property case expression + 134 | if (a) b + | ^~ +%Error-UNSUPPORTED: t/t_assert_property_pexpr_unsup.v:137:7: Unsupported: property case expression + 137 | if (a) b else c + | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_assert_property_pexpr_unsup.pl b/test_regress/t/t_assert_property_pexpr_unsup.pl index d188a4276..c9ca914d8 100755 --- a/test_regress/t/t_assert_property_pexpr_unsup.pl +++ b/test_regress/t/t_assert_property_pexpr_unsup.pl @@ -12,7 +12,7 @@ scenarios(vlt => 1); compile( expect_filename => $Self->{golden_filename}, - verilator_flags2 => ['--assert'], + verilator_flags2 => ['--assert --error-limit 1000'], fails => 1, ); diff --git a/test_regress/t/t_assert_property_pexpr_unsup.v b/test_regress/t/t_assert_property_pexpr_unsup.v index dd3977db7..ec806a492 100644 --- a/test_regress/t/t_assert_property_pexpr_unsup.v +++ b/test_regress/t/t_assert_property_pexpr_unsup.v @@ -6,12 +6,13 @@ module t (/*AUTOARG*/ // Inputs - clk, a, b + clk ); input clk; int a; int b; + int c; int cyc = 0; always @(posedge clk) begin @@ -116,6 +117,26 @@ module t (/*AUTOARG*/ a iff b; endproperty + property p_arg_propery(property inprop); + inprop; + endproperty + property p_arg_seqence(sequence inseq); + inseq; + endproperty + + property p_case_1; + case (a) endcase + endproperty + property p_case_2; + case (a) default: b; endcase + endproperty + property p_if; + if (a) b + endproperty + property p_ifelse; + if (a) b else c + endproperty + always @(posedge clk) begin if (cyc == 10) begin $write("*-* All Finished *-*\n"); diff --git a/test_regress/t/t_assert_recursive_property_unsup.out b/test_regress/t/t_assert_recursive_property_unsup.out index fbca8fd7c..7a2e9e68b 100644 --- a/test_regress/t/t_assert_recursive_property_unsup.out +++ b/test_regress/t/t_assert_recursive_property_unsup.out @@ -1,6 +1,6 @@ -%Error-UNSUPPORTED: t/t_assert_recursive_property_unsup.v:20:4: Unsupported: Recursive property call: 'check' - : ... In instance t +%Error-UNSUPPORTED: t/t_assert_recursive_property_unsup.v:20:13: Unsupported: Recursive property call: 'check' + : ... In instance t 20 | property check(int n); - | ^~~~~~~~ + | ^~~~~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error: Exiting due to diff --git a/test_regress/t/t_sequence_sexpr_unsup.out b/test_regress/t/t_sequence_sexpr_unsup.out index 1f322e376..e128af57a 100644 --- a/test_regress/t/t_sequence_sexpr_unsup.out +++ b/test_regress/t/t_sequence_sexpr_unsup.out @@ -1,144 +1,224 @@ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:27:14: Unsupported: within (in sequence expression) - 27 | weak(a within(b)); - | ^~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:26:4: Unsupported: sequence + 26 | sequence s_a; + | ^~~~~~~~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:27:11: Unsupported: weak (in property expression) - 27 | weak(a within(b)); - | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:31:14: Unsupported: and (in sequence expression) - 31 | weak(a and b); - | ^~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:31:11: Unsupported: weak (in property expression) - 31 | weak(a and b); - | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:35:14: Unsupported: or (in sequence expression) - 35 | weak(a or b); - | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:35:11: Unsupported: weak (in property expression) - 35 | weak(a or b); - | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:39:14: Unsupported: throughout (in sequence expression) - 39 | weak(a throughout b); - | ^~~~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:39:11: Unsupported: weak (in property expression) - 39 | weak(a throughout b); - | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:43:14: Unsupported: intersect (in sequence expression) - 43 | weak(a intersect b); - | ^~~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:43:11: Unsupported: weak (in property expression) - 43 | weak(a intersect b); - | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:47:12: Unsupported: ## () cycle delay range expression - 47 | weak(## 1 b); - | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:47:17: Unsupported: ## (in sequence expression) - 47 | weak(## 1 b); - | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:47:11: Unsupported: weak (in property expression) - 47 | weak(## 1 b); - | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:50:12: Unsupported: ## id cycle delay range expression - 50 | weak(## DELAY b); - | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:50:21: Unsupported: ## (in sequence expression) - 50 | weak(## DELAY b); - | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:50:11: Unsupported: weak (in property expression) - 50 | weak(## DELAY b); - | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:53:12: Unsupported: ## () cycle delay range expression - 53 | weak(## ( DELAY ) b); - | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:53:25: Unsupported: ## (in sequence expression) - 53 | weak(## ( DELAY ) b); - | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:53:11: Unsupported: weak (in property expression) - 53 | weak(## ( DELAY ) b); - | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:56:12: Unsupported: ## range cycle delay range expression - 56 | weak(## [1:2] b); - | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:56:21: Unsupported: ## (in sequence expression) - 56 | weak(## [1:2] b); - | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:56:11: Unsupported: weak (in property expression) - 56 | weak(## [1:2] b); - | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:59:12: Unsupported: ## [*] cycle delay range expression - 59 | weak(## [*] b); - | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:59:19: Unsupported: ## (in sequence expression) - 59 | weak(## [*] b); - | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:59:11: Unsupported: weak (in property expression) - 59 | weak(## [*] b); - | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:62:12: Unsupported: ## [+] cycle delay range expression - 62 | weak(## [+] b); - | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:62:19: Unsupported: ## (in sequence expression) - 62 | weak(## [+] b); - | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:62:11: Unsupported: weak (in property expression) - 62 | weak(## [+] b); - | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:66:14: Unsupported: ## () cycle delay range expression - 66 | weak(a ## 1 b); - | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:66:17: Unsupported: ## (in sequence expression) - 66 | weak(a ## 1 b); - | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:66:11: Unsupported: weak (in property expression) - 66 | weak(a ## 1 b); - | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:69:14: Unsupported: ## id cycle delay range expression - 69 | weak(a ## DELAY b); - | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:69:14: Unsupported: ## (in sequence expression) - 69 | weak(a ## DELAY b); - | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:69:11: Unsupported: weak (in property expression) - 69 | weak(a ## DELAY b); - | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:72:14: Unsupported: ## () cycle delay range expression - 72 | weak(a ## ( DELAY ) b); - | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:72:19: Unsupported: ## (in sequence expression) - 72 | weak(a ## ( DELAY ) b); - | ^~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:72:11: Unsupported: weak (in property expression) - 72 | weak(a ## ( DELAY ) b); - | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:75:14: Unsupported: ## range cycle delay range expression - 75 | weak(a ## [1:2] b); - | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:75:14: Unsupported: ## (in sequence expression) - 75 | weak(a ## [1:2] b); - | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:75:11: Unsupported: weak (in property expression) - 75 | weak(a ## [1:2] b); - | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:78:14: Unsupported: ## [*] cycle delay range expression - 78 | weak(a ## [*] b); - | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:78:14: Unsupported: ## (in sequence expression) - 78 | weak(a ## [*] b); - | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:78:11: Unsupported: weak (in property expression) - 78 | weak(a ## [*] b); - | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:81:14: Unsupported: ## [+] cycle delay range expression - 81 | weak(a ## [+] b); - | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:81:14: Unsupported: ## (in sequence expression) - 81 | weak(a ## [+] b); - | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:81:11: Unsupported: weak (in property expression) - 81 | weak(a ## [+] b); - | ^ -%Error: t/t_sequence_sexpr_unsup.v:85:12: syntax error, unexpected [*, expecting TYPE-IDENTIFIER - 85 | weak([* 1 ] a); - | ^~ -%Error: Cannot continue - ... See the manual at https://verilator.org/verilator_doc.html for more assistance. +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:29:4: Unsupported: sequence + 29 | sequence s_var; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:34:4: Unsupported: sequence + 34 | sequence s_within; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:35:9: Unsupported: within (in sequence expression) + 35 | a within(b); + | ^~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:38:4: Unsupported: sequence + 38 | sequence s_and; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:39:9: Unsupported: and (in sequence expression) + 39 | a and b; + | ^~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:42:4: Unsupported: sequence + 42 | sequence s_or; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:43:9: Unsupported: or (in sequence expression) + 43 | a or b; + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:46:4: Unsupported: sequence + 46 | sequence s_throughout; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:47:9: Unsupported: throughout (in sequence expression) + 47 | a throughout b; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:50:4: Unsupported: sequence + 50 | sequence s_intersect; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:51:9: Unsupported: intersect (in sequence expression) + 51 | a intersect b; + | ^~~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:54:4: Unsupported: sequence + 54 | sequence s_uni_cycdelay_int; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:55:7: Unsupported: ## () cycle delay range expression + 55 | ## 1 b; + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:55:12: Unsupported: ## (in sequence expression) + 55 | ## 1 b; + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:57:4: Unsupported: sequence + 57 | sequence s_uni_cycdelay_id; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:58:7: Unsupported: ## id cycle delay range expression + 58 | ## DELAY b; + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:58:16: Unsupported: ## (in sequence expression) + 58 | ## DELAY b; + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:60:4: Unsupported: sequence + 60 | sequence s_uni_cycdelay_pid; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:61:7: Unsupported: ## () cycle delay range expression + 61 | ## ( DELAY ) b; + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:61:20: Unsupported: ## (in sequence expression) + 61 | ## ( DELAY ) b; + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:63:4: Unsupported: sequence + 63 | sequence s_uni_cycdelay_range; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:64:7: Unsupported: ## range cycle delay range expression + 64 | ## [1:2] b; + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:64:16: Unsupported: ## (in sequence expression) + 64 | ## [1:2] b; + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:66:4: Unsupported: sequence + 66 | sequence s_uni_cycdelay_star; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:67:7: Unsupported: ## [*] cycle delay range expression + 67 | ## [*] b; + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:67:14: Unsupported: ## (in sequence expression) + 67 | ## [*] b; + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:69:4: Unsupported: sequence + 69 | sequence s_uni_cycdelay_plus; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:70:7: Unsupported: ## [+] cycle delay range expression + 70 | ## [+] b; + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:70:14: Unsupported: ## (in sequence expression) + 70 | ## [+] b; + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:73:4: Unsupported: sequence + 73 | sequence s_cycdelay_int; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:74:9: Unsupported: ## () cycle delay range expression + 74 | a ## 1 b; + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:74:12: Unsupported: ## (in sequence expression) + 74 | a ## 1 b; + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:76:4: Unsupported: sequence + 76 | sequence s_cycdelay_id; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:77:9: Unsupported: ## id cycle delay range expression + 77 | a ## DELAY b; + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:77:9: Unsupported: ## (in sequence expression) + 77 | a ## DELAY b; + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:79:4: Unsupported: sequence + 79 | sequence s_cycdelay_pid; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:80:9: Unsupported: ## () cycle delay range expression + 80 | a ## ( DELAY ) b; + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:80:14: Unsupported: ## (in sequence expression) + 80 | a ## ( DELAY ) b; + | ^~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:82:4: Unsupported: sequence + 82 | sequence s_cycdelay_range; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:83:9: Unsupported: ## range cycle delay range expression + 83 | a ## [1:2] b; + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:83:9: Unsupported: ## (in sequence expression) + 83 | a ## [1:2] b; + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:85:4: Unsupported: sequence + 85 | sequence s_cycdelay_star; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:86:9: Unsupported: ## [*] cycle delay range expression + 86 | a ## [*] b; + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:86:9: Unsupported: ## (in sequence expression) + 86 | a ## [*] b; + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:88:4: Unsupported: sequence + 88 | sequence s_cycdelay_plus; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:89:9: Unsupported: ## [+] cycle delay range expression + 89 | a ## [+] b; + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:89:9: Unsupported: ## (in sequence expression) + 89 | a ## [+] b; + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:92:4: Unsupported: sequence + 92 | sequence s_booleanabbrev_brastar_int; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:93:9: Unsupported: [*] boolean abbrev expression + 93 | a [* 1 ]; + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:93:12: Unsupported: boolean abbrev (in sequence expression) + 93 | a [* 1 ]; + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:95:4: Unsupported: sequence + 95 | sequence s_booleanabbrev_brastar; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:96:9: Unsupported: [*] boolean abbrev expression + 96 | a [*]; + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:96:9: Unsupported: boolean abbrev (in sequence expression) + 96 | a [*]; + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:98:4: Unsupported: sequence + 98 | sequence s_booleanabbrev_plus; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:99:9: Unsupported: [+] boolean abbrev expression + 99 | a [+]; + | ^~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:99:9: Unsupported: boolean abbrev (in sequence expression) + 99 | a [+]; + | ^~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:101:4: Unsupported: sequence + 101 | sequence s_booleanabbrev_eq; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:102:9: Unsupported: [= boolean abbrev expression + 102 | a [= 1]; + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:102:12: Unsupported: boolean abbrev (in sequence expression) + 102 | a [= 1]; + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:104:4: Unsupported: sequence + 104 | sequence s_booleanabbrev_eq_range; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:105:9: Unsupported: [= boolean abbrev expression + 105 | a [= 1:2]; + | ^~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:105:12: Unsupported: boolean abbrev (in sequence expression) + 105 | a [= 1:2]; + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:107:4: Unsupported: sequence + 107 | sequence s_booleanabbrev_minusgt; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:108:9: Unsupported: [-> boolean abbrev expression + 108 | a [-> 1]; + | ^~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:108:13: Unsupported: boolean abbrev (in sequence expression) + 108 | a [-> 1]; + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:110:4: Unsupported: sequence + 110 | sequence s_booleanabbrev_minusgt_range; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:111:9: Unsupported: [-> boolean abbrev expression + 111 | a [-> 1:2]; + | ^~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:111:13: Unsupported: boolean abbrev (in sequence expression) + 111 | a [-> 1:2]; + | ^ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:114:4: Unsupported: sequence + 114 | sequence p_arg_seqence(sequence inseq); + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:114:27: Unsupported: sequence argument data type + 114 | sequence p_arg_seqence(sequence inseq); + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:118:10: Unsupported: cover sequence + 118 | cover sequence (s_a) $display(""); + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:119:10: Unsupported: cover sequence + 119 | cover sequence (@(posedge a) disable iff (b) s_a) $display(""); + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:120:10: Unsupported: cover sequence + 120 | cover sequence (disable iff (b) s_a) $display(""); + | ^~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_sequence_sexpr_unsup.pl b/test_regress/t/t_sequence_sexpr_unsup.pl index d188a4276..c9ca914d8 100755 --- a/test_regress/t/t_sequence_sexpr_unsup.pl +++ b/test_regress/t/t_sequence_sexpr_unsup.pl @@ -12,7 +12,7 @@ scenarios(vlt => 1); compile( expect_filename => $Self->{golden_filename}, - verilator_flags2 => ['--assert'], + verilator_flags2 => ['--assert --error-limit 1000'], fails => 1, ); diff --git a/test_regress/t/t_sequence_sexpr_unsup.v b/test_regress/t/t_sequence_sexpr_unsup.v index 2f92d7f27..0ec594255 100644 --- a/test_regress/t/t_sequence_sexpr_unsup.v +++ b/test_regress/t/t_sequence_sexpr_unsup.v @@ -6,7 +6,7 @@ module t (/*AUTOARG*/ // Inputs - clk, a, b + clk ); input clk; @@ -23,85 +23,101 @@ module t (/*AUTOARG*/ // NOTE this grammar hasn't been checked with other simulators, // is here just to avoid uncovered code lines in the grammar. // NOTE using 'property weak' here as sequence/endsequence not supported - property s_within; - weak(a within(b)); - endproperty + sequence s_a; + a; + endsequence : s_a + sequence s_var; + logic l1, l2; + a; + endsequence - property s_and; - weak(a and b); - endproperty + sequence s_within; + a within(b); + endsequence - property s_or; - weak(a or b); - endproperty + sequence s_and; + a and b; + endsequence - property s_throughout; - weak(a throughout b); - endproperty + sequence s_or; + a or b; + endsequence - property s_intersect; - weak(a intersect b); - endproperty + sequence s_throughout; + a throughout b; + endsequence - property s_uni_cycdelay_int; - weak(## 1 b); - endproperty - property s_uni_cycdelay_id; - weak(## DELAY b); - endproperty - property s_uni_cycdelay_pid; - weak(## ( DELAY ) b); - endproperty - property s_uni_cycdelay_range; - weak(## [1:2] b); - endproperty - property s_uni_cycdelay_star; - weak(## [*] b); - endproperty - property s_uni_cycdelay_plus; - weak(## [+] b); - endproperty + sequence s_intersect; + a intersect b; + endsequence - property s_cycdelay_int; - weak(a ## 1 b); - endproperty - property s_cycdelay_id; - weak(a ## DELAY b); - endproperty - property s_cycdelay_pid; - weak(a ## ( DELAY ) b); - endproperty - property s_cycdelay_range; - weak(a ## [1:2] b); - endproperty - property s_cycdelay_star; - weak(a ## [*] b); - endproperty - property s_cycdelay_plus; - weak(a ## [+] b); - endproperty + sequence s_uni_cycdelay_int; + ## 1 b; + endsequence + sequence s_uni_cycdelay_id; + ## DELAY b; + endsequence + sequence s_uni_cycdelay_pid; + ## ( DELAY ) b; + endsequence + sequence s_uni_cycdelay_range; + ## [1:2] b; + endsequence + sequence s_uni_cycdelay_star; + ## [*] b; + endsequence + sequence s_uni_cycdelay_plus; + ## [+] b; + endsequence - property s_booleanabbrev_brastar_int; - weak([* 1 ] a); - endproperty - property s_booleanabbrev_brastar; - weak([*] a); - endproperty - property s_booleanabbrev_plus; - weak([+] a); - endproperty - property s_booleanabbrev_eq; - weak([= 1] a); - endproperty - property s_booleanabbrev_eq_range; - weak([= 1:2] a); - endproperty - property s_booleanabbrev_minusgt; - weak([-> 1] a); - endproperty - property s_booleanabbrev_minusgt_range; - weak([-> 1:2] a); - endproperty + sequence s_cycdelay_int; + a ## 1 b; + endsequence + sequence s_cycdelay_id; + a ## DELAY b; + endsequence + sequence s_cycdelay_pid; + a ## ( DELAY ) b; + endsequence + sequence s_cycdelay_range; + a ## [1:2] b; + endsequence + sequence s_cycdelay_star; + a ## [*] b; + endsequence + sequence s_cycdelay_plus; + a ## [+] b; + endsequence + + sequence s_booleanabbrev_brastar_int; + a [* 1 ]; + endsequence + sequence s_booleanabbrev_brastar; + a [*]; + endsequence + sequence s_booleanabbrev_plus; + a [+]; + endsequence + sequence s_booleanabbrev_eq; + a [= 1]; + endsequence + sequence s_booleanabbrev_eq_range; + a [= 1:2]; + endsequence + sequence s_booleanabbrev_minusgt; + a [-> 1]; + endsequence + sequence s_booleanabbrev_minusgt_range; + a [-> 1:2]; + endsequence + + sequence p_arg_seqence(sequence inseq); + inseq; + endsequence + + cover sequence (s_a) $display(""); + cover sequence (@(posedge a) disable iff (b) s_a) $display(""); + cover sequence (disable iff (b) s_a) $display(""); always @(posedge clk) begin if (cyc == 10) begin From cc45f6428060114cfe58c4435f81f5e840f5cc5b Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Mon, 6 Mar 2023 13:18:48 +0100 Subject: [PATCH 012/155] Add __PVT__ prefix to selects nodes (#4001) --- src/V3Name.cpp | 10 ++++++++-- test_regress/t/t_class_field_name.pl | 21 +++++++++++++++++++++ test_regress/t/t_class_field_name.v | 21 +++++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) create mode 100755 test_regress/t/t_class_field_name.pl create mode 100644 test_regress/t/t_class_field_name.v diff --git a/src/V3Name.cpp b/src/V3Name.cpp index 68a282140..bec3dd9cc 100644 --- a/src/V3Name.cpp +++ b/src/V3Name.cpp @@ -103,13 +103,19 @@ private: } void visit(AstMemberDType* nodep) override { if (!nodep->user1()) { - rename(nodep, false); + rename(nodep, true); iterateChildren(nodep); } } void visit(AstMemberSel* nodep) override { if (!nodep->user1()) { - rename(nodep, false); + rename(nodep, true); + iterateChildren(nodep); + } + } + void visit(AstStructSel* nodep) override { + if (!nodep->user1()) { + rename(nodep, true); iterateChildren(nodep); } } diff --git a/test_regress/t/t_class_field_name.pl b/test_regress/t/t_class_field_name.pl new file mode 100755 index 000000000..aabcde63e --- /dev/null +++ b/test_regress/t/t_class_field_name.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 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); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_field_name.v b/test_regress/t/t_class_field_name.v new file mode 100644 index 000000000..af7a73828 --- /dev/null +++ b/test_regress/t/t_class_field_name.v @@ -0,0 +1,21 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Cls; + int queue; +endclass + +module t (/*AUTOARG*/); + + initial begin + Cls cls = new; + cls.queue = 1; + if (cls.queue == 1) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule From f68c16a5e650e85f1784f120179495d85c895e6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Boro=C5=84ski?= <94375110+kboronski-ant@users.noreply.github.com> Date: Mon, 6 Mar 2023 13:43:58 +0100 Subject: [PATCH 013/155] Fix symbol entries when inheriting classes (#3995) (#3996) --- src/V3LinkDot.cpp | 2 ++ test_regress/t/t_class_extends_vsyment.pl | 17 +++++++++++++++++ test_regress/t/t_class_extends_vsyment.v | 15 +++++++++++++++ 3 files changed, 34 insertions(+) create mode 100755 test_regress/t/t_class_extends_vsyment.pl create mode 100644 test_regress/t/t_class_extends_vsyment.v diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index db591012f..94ac413fb 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -3362,6 +3362,8 @@ private: } } } + m_ds.m_dotSymp = m_curSymp; + iterateChildren(nodep); } // V3Width when determines types needs to find enum values and such diff --git a/test_regress/t/t_class_extends_vsyment.pl b/test_regress/t/t_class_extends_vsyment.pl new file mode 100755 index 000000000..8eeb2a6f6 --- /dev/null +++ b/test_regress/t/t_class_extends_vsyment.pl @@ -0,0 +1,17 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 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(vlt => 1); + +compile( + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_extends_vsyment.v b/test_regress/t/t_class_extends_vsyment.v new file mode 100644 index 000000000..ac17ba1cf --- /dev/null +++ b/test_regress/t/t_class_extends_vsyment.v @@ -0,0 +1,15 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Foo; +endclass + +class Bar extends Foo; + int m_field = get_1(); + function int get_1(); + return 1; + endfunction +endclass From ff889fde18f52cefe48376d3010477c4a3e71229 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 6 Mar 2023 18:22:36 -0500 Subject: [PATCH 014/155] Add debug comment when trace disabled (#4004). --- src/V3TraceDecl.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp index 8c6f73e25..bba3bc78b 100644 --- a/src/V3TraceDecl.cpp +++ b/src/V3TraceDecl.cpp @@ -237,8 +237,9 @@ private: void addIgnore(const char* why) { ++m_statIgnSigs; - addToSubFunc(new AstComment{m_traVscp->fileline(), - "Tracing: " + m_traName + " // Ignored: " + why, true}); + std::string cmt = std::string{"Tracing: "} + m_traName + " // Ignored: " + why; + if (debug() > 3 && m_traVscp) std::cout << "- " << m_traVscp->fileline() << cmt << endl; + addToSubFunc(new AstComment{m_traVscp->fileline(), cmt, true}); } // VISITORS From 13c9877099933c434cc943a838553dc3f1641f58 Mon Sep 17 00:00:00 2001 From: Andrew Nolte Date: Wed, 8 Mar 2023 17:38:26 -0700 Subject: [PATCH 015/155] Add --public-params flag (#3990) --- bin/verilator | 1 + docs/guide/exe_verilator.rst | 6 +++ src/V3LinkParse.cpp | 2 + src/V3Options.cpp | 5 ++- src/V3Options.h | 2 + test_regress/t/t_vpi_param.cpp | 9 ++++- test_regress/t/t_vpi_public_params.pl | 34 ++++++++++++++++ test_regress/t/t_vpi_public_params.v | 58 +++++++++++++++++++++++++++ 8 files changed, 115 insertions(+), 2 deletions(-) create mode 100755 test_regress/t/t_vpi_public_params.pl create mode 100644 test_regress/t/t_vpi_public_params.v diff --git a/bin/verilator b/bin/verilator index 587a9b85f..5bab12f33 100755 --- a/bin/verilator +++ b/bin/verilator @@ -404,6 +404,7 @@ detailed descriptions of these arguments. --protect-key Key for symbol protection --protect-lib Create a DPI protected library --public Debugging; see docs + --public-params Mark all parameters as public_flat --public-flat-rw Mark all variables, etc as public_flat_rw -pvalue+= Overwrite toplevel parameter --quiet-exit Don't print the command on failure diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index 0a4b90249..ee14ca390 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -1101,6 +1101,12 @@ Summary: marking only those signals that need public_flat_rw is typically significantly better performing. +.. option:: --public-params + + Declares all parameters public as if they had + :code:`/*verilator public_flat_rd*/` + metacomments. + .. option:: -pvalue+= Overwrites the given parameter(s) of the top-level module. See diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index c0984fe98..ba3542ff6 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -259,6 +259,8 @@ private: } } + if (v3Global.opt.publicParams() && nodep->isParam()) nodep->sigUserRWPublic(true); + // We used modTrace before leveling, and we may now // want to turn it off now that we know the levelizations if (v3Global.opt.traceDepth() && m_modp diff --git a/src/V3Options.cpp b/src/V3Options.cpp index faec6ba50..6bcdabeec 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -1385,7 +1385,10 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char m_publicFlatRW = flag; v3Global.dpi(true); }); - + DECL_OPTION("-public-params", CbOnOff, [this](bool flag) { + m_public_params = flag; + v3Global.dpi(true); + }); DECL_OPTION("-quiet-exit", OnOff, &m_quietExit); DECL_OPTION("-relative-includes", OnOff, &m_relativeIncludes); diff --git a/src/V3Options.h b/src/V3Options.h index aa681b3ea..46ea949c8 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -262,6 +262,7 @@ private: bool m_protectIds = false; // main switch: --protect-ids bool m_public = false; // main switch: --public bool m_publicFlatRW = false; // main switch: --public-flat-rw + bool m_public_params = false; // main switch: --public-params bool m_quietExit = false; // main switch: --quiet-exit bool m_relativeIncludes = false; // main switch: --relative-includes bool m_reportUnoptflat = false; // main switch: --report-unoptflat @@ -492,6 +493,7 @@ public: bool usesProfiler() const { return profExec() || profPgo(); } bool protectIds() const VL_MT_SAFE { return m_protectIds; } bool allPublic() const { return m_public; } + bool publicParams() const { return m_public_params; } bool publicFlatRW() const { return m_publicFlatRW; } bool lintOnly() const VL_MT_SAFE { return m_lintOnly; } bool ignc() const { return m_ignc; } diff --git a/test_regress/t/t_vpi_param.cpp b/test_regress/t/t_vpi_param.cpp index 8d769ae26..1f2c5d434 100644 --- a/test_regress/t/t_vpi_param.cpp +++ b/test_regress/t/t_vpi_param.cpp @@ -21,9 +21,16 @@ #include "verilated_vcd_c.h" #include "verilated_vpi.h" +#include "svdpi.h" + +#ifdef T_VPI_PARAM #include "Vt_vpi_param.h" #include "Vt_vpi_param__Dpi.h" -#include "svdpi.h" +#elif defined(T_VPI_PUBLIC_PARAMS) +#include "Vt_vpi_public_params.h" +#else +#error "Bad test" +#endif #endif diff --git a/test_regress/t/t_vpi_public_params.pl b/test_regress/t/t_vpi_public_params.pl new file mode 100755 index 000000000..34224a797 --- /dev/null +++ b/test_regress/t/t_vpi_public_params.pl @@ -0,0 +1,34 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2010 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); + +# same vpi script should work with --public-params instead of inline publics +pli_filename("t_vpi_param.cpp"); + +skip("Known compiler limitation") + if $Self->cxx_version =~ /\(GCC\) 4.4/; + +compile( + make_top_shell => 0, + make_main => 0, + make_pli => 1, + iv_flags2 => ["-g2005-sv -D USE_VPI_NOT_DPI"], + v_flags2 => ["+define+USE_VPI_NOT_DPI"], + verilator_flags2 => ["--exe --vpi --no-l2name $Self->{t_dir}/t_vpi_param.cpp --public-params "], + ); + +execute( + use_libvpi => 1, + check_finished => 1 + ); + +ok(1); +1; diff --git a/test_regress/t/t_vpi_public_params.v b/test_regress/t/t_vpi_public_params.v new file mode 100644 index 000000000..6286e7481 --- /dev/null +++ b/test_regress/t/t_vpi_public_params.v @@ -0,0 +1,58 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2010 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 + +`ifdef USE_VPI_NOT_DPI +//We call it via $c so we can verify DPI isn't required - see bug572 +`else +import "DPI-C" context function int mon_check(); +`endif + +// Copy of t_vpi_public_params.v but with the inline public taken out +module t #( + parameter int WIDTH = 32 + ) (/*AUTOARG*/ + // Inputs + clk + ); + +`ifdef VERILATOR +`systemc_header +extern "C" int mon_check(); +`verilog +`endif + + input clk; + + localparam int DEPTH = 16; + localparam longint PARAM_LONG = 64'hFEDCBA9876543210; + localparam string PARAM_STR = "'some string value'"; + + reg [WIDTH-1:0] mem0 [DEPTH:1]; + integer i, status; + + // Test loop + initial begin +`ifdef VERILATOR + status = $c32("mon_check()"); +`endif +`ifdef IVERILOG + status = $mon_check(); +`endif +`ifndef USE_VPI_NOT_DPI + status = mon_check(); +`endif + + if (status!=0) begin + $write("%%Error: t_vpi_param.cpp:%0d: C Test failed\n", status); + $stop; + end + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule : t From 621cd0f008ef6bbebc092e8306b2ba5d96455837 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 8 Mar 2023 21:32:37 -0500 Subject: [PATCH 016/155] Internals: Framework for renaming warnings (#4010 partial) --- src/V3Error.cpp | 1 + src/V3Error.h | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/V3Error.cpp b/src/V3Error.cpp index 2f1a01f20..670dd7185 100644 --- a/src/V3Error.cpp +++ b/src/V3Error.cpp @@ -40,6 +40,7 @@ V3ErrorCode::V3ErrorCode(const char* msgp) { const V3ErrorCode code{codei}; if (0 == VL_STRCASECMP(msgp, code.ascii())) { m_e = code; + if (isRenamed()) m_e = renamedTo().m_e; return; } } diff --git a/src/V3Error.h b/src/V3Error.h index 05f865f13..2c02e8eaa 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -248,6 +248,12 @@ public: return (m_e == UNUSEDGENVAR || m_e == UNUSEDPARAM || m_e == UNUSEDSIGNAL); } + V3ErrorCode renamedTo() const { + // Return a new error this error has been renamed to + // e.g. if (m_e == LITENDIAN) return V3ErrorCode{RANGEASC}; + return V3ErrorCode{EC_MIN}; // Not renamed; see isRenamed() + } + bool isRenamed() const { return renamedTo() != V3ErrorCode{EC_MIN}; } bool isUnder(V3ErrorCode other) { // backwards compatibility inheritance-like warnings if (m_e == other) { return true; } From fc17ab280a8d0cd8388ccd0939e5c7249133e0d0 Mon Sep 17 00:00:00 2001 From: Andrew Nolte Date: Thu, 9 Mar 2023 19:48:05 -0700 Subject: [PATCH 017/155] Add --public-depth to force public to a certain instance depth (#3952) --- docs/guide/exe_verilator.rst | 6 + src/V3LinkParse.cpp | 5 +- src/V3Options.cpp | 1 + src/V3Options.h | 2 + test_regress/t/t_vpi_public_depth.cpp | 247 +++++++++++++++++++++++ test_regress/t/t_vpi_public_depth.pl | 32 +++ test_regress/t/t_vpi_public_depth.v | 125 ++++++++++++ test_regress/t/t_vpi_public_depth_off.pl | 34 ++++ 8 files changed, 451 insertions(+), 1 deletion(-) create mode 100644 test_regress/t/t_vpi_public_depth.cpp create mode 100755 test_regress/t/t_vpi_public_depth.pl create mode 100644 test_regress/t/t_vpi_public_depth.v create mode 100755 test_regress/t/t_vpi_public_depth_off.pl diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index ee14ca390..795b7b141 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -1101,6 +1101,12 @@ Summary: marking only those signals that need public_flat_rw is typically significantly better performing. +.. option:: --public-depth + + Enables public as with :vlopt:`--public-flat-rw`, but only to the specified depth of modules. + It operates at the module maximum level, so if a module's cells are A.B.X and A.X, the + a --public-depth 3 must be used to make module X public, and both A.B.X and A.X will be public. + .. option:: --public-params Declares all parameters public as if they had diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index ba3542ff6..5e0d78d67 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -248,7 +248,10 @@ private: // Maybe this variable has a signal attribute V3Config::applyVarAttr(m_modp, m_ftaskp, nodep); - if (v3Global.opt.publicFlatRW()) { + if (v3Global.opt.publicFlatRW() + || (v3Global.opt.publicDepth() && m_modp + && (m_modp->level() - 1) <= v3Global.opt.publicDepth())) { + switch (nodep->varType()) { case VVarType::VAR: // FALLTHRU case VVarType::GPARAM: // FALLTHRU diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 6bcdabeec..076fff117 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -1381,6 +1381,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char m_protectIds = true; }); DECL_OPTION("-public", OnOff, &m_public); + DECL_OPTION("-public-depth", Set, &m_publicDepth); DECL_OPTION("-public-flat-rw", CbOnOff, [this](bool flag) { m_publicFlatRW = flag; v3Global.dpi(true); diff --git a/src/V3Options.h b/src/V3Options.h index 46ea949c8..12b261003 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -303,6 +303,7 @@ private: int m_outputSplitCFuncs = -1; // main switch: --output-split-cfuncs int m_outputSplitCTrace = -1; // main switch: --output-split-ctrace int m_pinsBv = 65; // main switch: --pins-bv + int m_publicDepth = 0; // main switch: --public-depth int m_reloopLimit = 40; // main switch: --reloop-limit VOptionBool m_skipIdentical; // main switch: --skip-identical int m_threads = 1; // main switch: --threads @@ -521,6 +522,7 @@ public: int outputSplitCFuncs() const { return m_outputSplitCFuncs; } int outputSplitCTrace() const { return m_outputSplitCTrace; } int pinsBv() const { return m_pinsBv; } + int publicDepth() const { return m_publicDepth; } int reloopLimit() const { return m_reloopLimit; } VOptionBool skipIdentical() const { return m_skipIdentical; } int threads() const VL_MT_SAFE { return m_threads; } diff --git a/test_regress/t/t_vpi_public_depth.cpp b/test_regress/t/t_vpi_public_depth.cpp new file mode 100644 index 000000000..ee1217bd4 --- /dev/null +++ b/test_regress/t/t_vpi_public_depth.cpp @@ -0,0 +1,247 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2010-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 +// +//************************************************************************* + +#ifdef IS_VPI + +#include "vpi_user.h" + +#include + +#else + +#include "verilated.h" +#include "verilated_vcd_c.h" +#include "verilated_vpi.h" + +#include VM_PREFIX_INCLUDE +#ifdef T_VPI_PUBLIC_DEPTH +#include "Vt_vpi_public_depth__Dpi.h" +#elif defined(T_VPI_PUBLIC_DEPTH_OFF) +#include "Vt_vpi_public_depth_off__Dpi.h" +#else +#error "Bad test" +#endif +#include "svdpi.h" + +#endif + +#include +#include +#include + +// These require the above. Comment prevents clang-format moving them +#include "TestSimulator.h" +#include "TestVpi.h" + +// __FILE__ is too long +#define FILENM "t_vpi_public_depth.cpp" + +#define DEBUG \ + if (0) printf + +#define CHECK_RESULT_NZ(got) \ + if (!(got)) { \ + printf("%%Error: %s:%d: GOT = NULL EXP = !NULL\n", FILENM, __LINE__); \ + return __LINE__; \ + } + +#define CHECK_RESULT_Z(got) \ + if (got) { \ + printf("%%Error: %s:%d: GOT = !NULL EXP = NULL\n", FILENM, __LINE__); \ + return __LINE__; \ + } + +#define CHECK_RESULT(got, exp) \ + if ((got) != (exp)) { \ + std::cout << std::dec << "%Error: " << FILENM << ":" << __LINE__ << ": GOT = " << (got) \ + << " EXP = " << (exp) << std::endl; \ + return __LINE__; \ + } + +#define CHECK_RESULT_CSTR(got, exp) \ + if (std::strcmp((got), (exp))) { \ + printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", FILENM, __LINE__, \ + (got) ? (got) : "", (exp) ? (exp) : ""); \ + return __LINE__; \ + } + +void modDump(const TestVpiHandle& it, int n) { + while (TestVpiHandle hndl = vpi_scan(it)) { + const char* nm = vpi_get_str(vpiName, hndl); + for (int i = 0; i < n; i++) printf(" "); + printf("%s\n", nm); + TestVpiHandle subIt = vpi_iterate(vpiModule, hndl); + if (subIt) modDump(subIt, n + 1); + } +} + +extern "C" { +int mon_check() { +#ifdef TEST_VERBOSE + printf("-mon_check()\n"); +#endif + + TestVpiHandle it = vpi_iterate(vpiModule, NULL); + CHECK_RESULT_NZ(it); + // Uncomment to see what other simulators return + // modDump(it, 0); + // return 1; + + TestVpiHandle topmod; + // both somepackage and t exist at the top level + while ((topmod = vpi_scan(it))) { + if (vpi_get(vpiType, topmod) == vpiModule) break; + } + CHECK_RESULT_NZ(topmod); + + const char* t_name = vpi_get_str(vpiName, topmod); + CHECK_RESULT_NZ(t_name); + + // Icarus reports the top most module as "top" + if (std::strcmp(t_name, "top") == 0) { + it = vpi_iterate(vpiModule, topmod); + CHECK_RESULT_NZ(it); + CHECK_RESULT(vpi_get(vpiType, it), vpiModule); + topmod = vpi_scan(it); + t_name = vpi_get_str(vpiName, topmod); + CHECK_RESULT_NZ(t_name); + } + CHECK_RESULT_CSTR(t_name, "t"); + TestVpiHandle topmod_done_should_be_0 = (vpi_scan(it)); + it.freed(); // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle + CHECK_RESULT_Z(topmod_done_should_be_0); + + TestVpiHandle it2 = vpi_iterate(vpiModule, topmod); + CHECK_RESULT_NZ(it2); + + TestVpiHandle mod2 = vpi_scan(it2); + CHECK_RESULT_NZ(mod2); + + const char* mod_a_name = vpi_get_str(vpiName, mod2); + CHECK_RESULT_CSTR(mod_a_name, "\\mod.a "); + + TestVpiHandle it3 = vpi_iterate(vpiModule, mod2); + +#ifdef T_VPI_PUBLIC_DEPTH + CHECK_RESULT_NZ(it3); + TestVpiHandle mod3 = vpi_scan(it3); + CHECK_RESULT_NZ(mod3); + + const char* mod_c_name = vpi_get_str(vpiName, mod3); + if (std::strcmp(mod_c_name, "\\mod_b$ ") == 0) { + // Full visibility in other simulators, skip mod_b + TestVpiHandle mod4 = vpi_scan(it3); + CHECK_RESULT_NZ(mod4); + mod_c_name = vpi_get_str(vpiName, mod4); + } + CHECK_RESULT_CSTR(mod_c_name, "\\mod\\c$ "); + +#elif defined(T_VPI_PUBLIC_DEPTH_OFF) + CHECK_RESULT_Z(it3); +#endif + + return 0; // Ok +} +} +//====================================================================== + +#ifdef IS_VPI + +static int mon_check_vpi() { + TestVpiHandle href = vpi_handle(vpiSysTfCall, 0); + s_vpi_value vpi_value; + + vpi_value.format = vpiIntVal; + vpi_value.value.integer = mon_check(); + vpi_put_value(href, &vpi_value, NULL, vpiNoDelay); + + return 0; +} + +static s_vpi_systf_data vpi_systf_data[] = {{vpiSysFunc, vpiIntFunc, (PLI_BYTE8*)"$mon_check", + (PLI_INT32(*)(PLI_BYTE8*))mon_check_vpi, 0, 0, 0}, + 0}; + +// cver entry +void vpi_compat_bootstrap(void) { + p_vpi_systf_data systf_data_p; + systf_data_p = &(vpi_systf_data[0]); + while (systf_data_p->type != 0) vpi_register_systf(systf_data_p++); +} + +// icarus entry +void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0}; + +#else + +int main(int argc, char** argv) { + const std::unique_ptr contextp{new VerilatedContext}; + + uint64_t sim_time = 1100; + contextp->debug(0); + contextp->commandArgs(argc, argv); + // We're going to be checking for these errors so don't crash out + contextp->fatalOnVpiError(0); + + { + // Construct and destroy + const std::unique_ptr topp{ + new VM_PREFIX{contextp.get(), + // Note null name - we're flattening it out + ""}}; + } + + // Test second construction + const std::unique_ptr topp{new VM_PREFIX{contextp.get(), + // Note null name - we're flattening it out + ""}}; + +#ifdef VERILATOR +#ifdef TEST_VERBOSE + contextp->scopesDump(); +#endif +#endif + +#if VM_TRACE + contextp->traceEverOn(true); + VL_PRINTF("Enabling waves...\n"); + VerilatedVcdC* tfp = new VerilatedVcdC; + topp->trace(tfp, 99); + tfp->open(STRINGIFY(TEST_OBJ_DIR) "/simx.vcd"); +#endif + + topp->eval(); + topp->clk = 0; + contextp->timeInc(10); + + while (contextp->time() < sim_time && !contextp->gotFinish()) { + contextp->timeInc(1); + topp->eval(); + VerilatedVpi::callValueCbs(); + topp->clk = !topp->clk; + // mon_do(); +#if VM_TRACE + if (tfp) tfp->dump(contextp->time()); +#endif + } + if (!contextp->gotFinish()) { + vl_fatal(FILENM, __LINE__, "main", "%Error: Timeout; never got a $finish"); + } + topp->final(); + +#if VM_TRACE + if (tfp) tfp->close(); +#endif + + return 0; +} + +#endif diff --git a/test_regress/t/t_vpi_public_depth.pl b/test_regress/t/t_vpi_public_depth.pl new file mode 100755 index 000000000..930a82c94 --- /dev/null +++ b/test_regress/t/t_vpi_public_depth.pl @@ -0,0 +1,32 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2010 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); + +skip("Known compiler limitation") + if $Self->cxx_version =~ /\(GCC\) 4.4/; + +compile( + make_top_shell => 0, + make_main => 0, + make_pli => 1, + iv_flags2 => ["-g2005-sv"], + verilator_flags2 => ["+define+USE_DOLLAR_C32 --exe --vpi --no-l2name $Self->{t_dir}/t_vpi_public_depth.cpp --public-depth 3"], + make_flags => 'CPPFLAGS_ADD=-DTEST_VPI_PUBLIC_DEPTH', + ); + +execute( + use_libvpi => 1, + check_finished => 1, + v_flags2, + ); + +ok(1); +1; diff --git a/test_regress/t/t_vpi_public_depth.v b/test_regress/t/t_vpi_public_depth.v new file mode 100644 index 000000000..eeaedae9a --- /dev/null +++ b/test_regress/t/t_vpi_public_depth.v @@ -0,0 +1,125 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2010 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 + +`ifndef IVERILOG +import "DPI-C" context function int mon_check(); +`endif + +package somepackage; + int someint; +endpackage + +module t (/*AUTOARG*/ + // Inputs + clk + ); + +`ifdef USE_DOLLAR_C32 +`systemc_header +extern "C" int mon_check(); +`verilog +`endif + + input clk; + + integer status; + + wire a, b, x; + + A \mod.a (/*AUTOINST*/ + // Outputs + .x (x), + // Inputs + .clk (clk), + .a (a), + .b (b)); + + // Test loop + initial begin +`ifdef IVERILOG + status = $mon_check(); +`elsif USE_DOLLAR_C32 + status = $c32("mon_check()"); +`else + status = mon_check(); +`endif + if (status!=0) begin + $write("%%Error: t_vpi_module.cpp:%0d: C Test failed\n", status); + $stop; + end + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule : t + +module A(/*AUTOARG*/ + // Outputs + x, + // Inputs + clk, a, b + ); + + input clk; + + input a, b; + output x; + + wire y, c; + + B \mod_b$ (/*AUTOINST*/ + // Outputs + .y (y), + // Inputs + .b (b), + .c (c)); + + C \mod\c$ (/*AUTOINST*/ + // Outputs + .x (x), + // Inputs + .clk (clk), + .a (a), + .y (y)); + +endmodule : A + +module B(/*AUTOARG*/ + // Outputs + y, + // Inputs + b, c + ); + input b, c; + + output reg y; + + always @(*) begin : myproc + y = b ^ c; + end + +endmodule + +module C(/*AUTOARG*/ + // Outputs + x, + // Inputs + clk, a, y + ); + + input clk; + + input a, y; + + output reg x; + + always @(posedge clk) begin + x <= a & y; + end + +endmodule diff --git a/test_regress/t/t_vpi_public_depth_off.pl b/test_regress/t/t_vpi_public_depth_off.pl new file mode 100755 index 000000000..64de60c4d --- /dev/null +++ b/test_regress/t/t_vpi_public_depth_off.pl @@ -0,0 +1,34 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2010 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); + +pli_filename("t_vpi_public_depth.cpp"); +top_filename("t/t_vpi_public_depth.v"); + +skip("Known compiler limitation") + if $Self->cxx_version =~ /\(GCC\) 4.4/; + +compile( + make_top_shell => 0, + make_main => 0, + make_pli => 1, + iv_flags2 => ["-g2005-sv"], + verilator_flags2 => ["+define+USE_DOLLAR_C32 --exe --vpi --no-l2name $Self->{t_dir}/t_vpi_public_depth.cpp --public-depth 2"], + make_flags => 'CPPFLAGS_ADD=-DTEST_VPI_PUBLIC_DEPTH_OFF', + ); + +execute( + use_libvpi => 1, + check_finished => 1, + ); + +ok(1); +1; From 4532680e5f634e99ddcb5ede2840a0f8eba82fe5 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 10 Mar 2023 21:17:54 -0500 Subject: [PATCH 018/155] Internals: Cleanup assert/assume. No functional change. --- src/verilog.y | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/src/verilog.y b/src/verilog.y index ee8384990..64e86a661 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -5741,18 +5741,11 @@ final_zero: // IEEE: part of deferred_immediate_assertion_st deferred_immediate_assertion_statement: // ==IEEE: deferred_immediate_assertion_statement // // IEEE: deferred_immediate_assert_statement - yASSERT final_zero '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE + assertOrAssume final_zero '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE { $$ = new AstAssert{$1, $4, $6, nullptr, true}; } - | yASSERT final_zero '(' expr ')' yELSE stmtBlock + | assertOrAssume final_zero '(' expr ')' yELSE stmtBlock { $$ = new AstAssert{$1, $4, nullptr, $7, true}; } - | yASSERT final_zero '(' expr ')' stmtBlock yELSE stmtBlock - { $$ = new AstAssert{$1, $4, $6, $8, true}; } - // // IEEE: deferred_immediate_assume_statement - | yASSUME final_zero '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE - { $$ = new AstAssert{$1, $4, $6, nullptr, true}; } - | yASSUME final_zero '(' expr ')' yELSE stmtBlock - { $$ = new AstAssert{$1, $4, nullptr, $7, true}; } - | yASSUME final_zero '(' expr ')' stmtBlock yELSE stmtBlock + | assertOrAssume final_zero '(' expr ')' stmtBlock yELSE stmtBlock { $$ = new AstAssert{$1, $4, $6, $8, true}; } // // IEEE: deferred_immediate_cover_statement | yCOVER final_zero '(' expr ')' stmt { $$ = new AstCover{$1, $4, $6, true}; } @@ -5772,14 +5765,11 @@ concurrent_assertion_item: // IEEE: concurrent_assertion_item concurrent_assertion_statement: // ==IEEE: concurrent_assertion_statement // // IEEE: assert_property_statement - //UNSUP remove below: - yASSERT yPROPERTY '(' property_spec ')' elseStmtBlock - { $$ = new AstAssert{$1, new AstSampled{$1, $4}, nullptr, $6, false}; } - //UNSUP yASSERT yPROPERTY '(' property_spec ')' action_block { } // // IEEE: assume_property_statement - | yASSUME yPROPERTY '(' property_spec ')' elseStmtBlock + //UNSUP remove below: + assertOrAssume yPROPERTY '(' property_spec ')' elseStmtBlock { $$ = new AstAssert{$1, new AstSampled{$1, $4}, nullptr, $6, false}; } - //UNSUP yASSUME yPROPERTY '(' property_spec ')' action_block { } + //UNSUP assertOrAssume yPROPERTY '(' property_spec ')' action_block { } // // IEEE: cover_property_statement | yCOVER yPROPERTY '(' property_spec ')' stmtBlock { $$ = new AstCover{$1, $4, $6, false}; } From 81e8388c3f3bbb7ca8e2b25c7810d95beffa91cd Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 10 Mar 2023 21:48:56 -0500 Subject: [PATCH 019/155] Parse 'expect', still unsupported. --- src/verilog.l | 2 +- src/verilog.y | 28 +++++++++++++++++++--------- test_regress/t/t_expect.out | 29 +++++++++++++++++++++++++++++ test_regress/t/t_expect.pl | 20 ++++++++++++++++++++ test_regress/t/t_expect.v | 28 ++++++++++++++++++++++++++++ 5 files changed, 97 insertions(+), 10 deletions(-) create mode 100644 test_regress/t/t_expect.out create mode 100755 test_regress/t/t_expect.pl create mode 100644 test_regress/t/t_expect.v diff --git a/src/verilog.l b/src/verilog.l index ced9de537..d2005168c 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -525,7 +525,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "endproperty" { FL; return yENDPROPERTY; } "endsequence" { FL; return yENDSEQUENCE; } "enum" { FL; return yENUM; } - "expect" { ERROR_RSVD_WORD("SystemVerilog 2005"); } + "expect" { FL; return yEXPECT; } "export" { FL; return yEXPORT; } "extends" { FL; return yEXTENDS; } "extern" { FL; return yEXTERN; } diff --git a/src/verilog.y b/src/verilog.y index 64e86a661..dbd714afb 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -607,7 +607,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yENUM "enum" %token yEVENT "event" %token yEVENTUALLY "eventually" -//UNSUP %token yEXPECT "expect" +%token yEXPECT "expect" %token yEXPORT "export" %token yEXTENDS "extends" %token yEXTERN "extern" @@ -3603,7 +3603,10 @@ statement_item: // IEEE: statement_item // // IEEE: wait_statement | yWAIT '(' expr ')' stmtBlock { $$ = new AstWait{$1, $3, $5}; } | yWAIT yFORK ';' { $$ = new AstWaitFork{$1}; } - //UNSUP yWAIT_ORDER '(' hierarchical_identifierList ')' action_block { UNSUP } + // // action_block expanded here + //UNSUP yWAIT_ORDER '(' hierarchical_identifierList ')' stmt %prec prLOWER_THAN_ELSE { UNSUP } + //UNSUP yWAIT_ORDER '(' hierarchical_identifierList ')' stmt yELSE stmt { UNSUP } + //UNSUP yWAIT_ORDER '(' hierarchical_identifierList ')' yELSE stmt { UNSUP } // // // IEEE: procedural_assertion_statement | procedural_assertion_statement { $$ = $1; } @@ -3613,7 +3616,14 @@ statement_item: // IEEE: statement_item // // IEEE: randcase_statement | yRANDCASE rand_case_itemList yENDCASE { $$ = new AstRandCase{$1, $2}; } // - //UNSUP expect_property_statement { $$ = $1; } + // // IEEE: expect_property_statement + // // action_block expanded here + | yEXPECT '(' property_spec ')' stmt %prec prLOWER_THAN_ELSE + { $$ = nullptr; BBUNSUP($1, "Unsupported: expect"); } + | yEXPECT '(' property_spec ')' stmt yELSE stmt + { $$ = nullptr; BBUNSUP($1, "Unsupported: expect"); } + | yEXPECT '(' property_spec ')' yELSE stmt + { $$ = nullptr; BBUNSUP($1, "Unsupported: expect"); } // | error ';' { $$ = nullptr; } ; @@ -5716,7 +5726,7 @@ immediate_assertion_statement: // ==IEEE: immediate_assertion_statement ; simple_immediate_assertion_statement: // ==IEEE: simple_immediate_assertion_statement - // // action_block expanded here, for compatibility with AstAssert + // // action_block expanded here, for compatibility with AstAssert assertOrAssume '(' expr ')' stmtBlock %prec prLOWER_THAN_ELSE { $$ = new AstAssert{$1, $3, $5, nullptr, true}; } | assertOrAssume '(' expr ')' yELSE stmtBlock @@ -5751,10 +5761,6 @@ deferred_immediate_assertion_statement: // ==IEEE: deferred_immediate_as | yCOVER final_zero '(' expr ')' stmt { $$ = new AstCover{$1, $4, $6, true}; } ; -//UNSUPexpect_property_statement: // ==IEEE: expect_property_statement -//UNSUP yEXPECT '(' property_spec ')' action_block { } -//UNSUP ; - concurrent_assertion_item: // IEEE: concurrent_assertion_item concurrent_assertion_statement { $$ = $1; } | id/*block_identifier*/ ':' concurrent_assertion_statement @@ -5769,7 +5775,11 @@ concurrent_assertion_statement: // ==IEEE: concurrent_assertion_statemen //UNSUP remove below: assertOrAssume yPROPERTY '(' property_spec ')' elseStmtBlock { $$ = new AstAssert{$1, new AstSampled{$1, $4}, nullptr, $6, false}; } - //UNSUP assertOrAssume yPROPERTY '(' property_spec ')' action_block { } + //UNSUP remove above: + // // action_block expanded here + //UNSUP assertOrAssume yPROPERTY '(' property_spec ')' stmt %prec prLOWER_THAN_ELSE {} + //UNSUP assertOrAssume yPROPERTY '(' property_spec ')' stmt yELSE stmt {} + //UNSUP assertOrAssume yPROPERTY '(' property_spec ')' yELSE stmt {} // // IEEE: cover_property_statement | yCOVER yPROPERTY '(' property_spec ')' stmtBlock { $$ = new AstCover{$1, $4, $6, false}; } diff --git a/test_regress/t/t_expect.out b/test_regress/t/t_expect.out new file mode 100644 index 000000000..5df2a5f91 --- /dev/null +++ b/test_regress/t/t_expect.out @@ -0,0 +1,29 @@ +%Error-UNSUPPORTED: t/t_expect.v:19:32: Unsupported: ## () cycle delay range expression + 19 | expect (@(posedge clk) a ##1 b) a = 110; + | ^~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_expect.v:19:34: Unsupported: ## (in sequence expression) + 19 | expect (@(posedge clk) a ##1 b) a = 110; + | ^ +%Error-UNSUPPORTED: t/t_expect.v:19:7: Unsupported: expect + 19 | expect (@(posedge clk) a ##1 b) a = 110; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_expect.v:21:32: Unsupported: ## () cycle delay range expression + 21 | expect (@(posedge clk) a ##1 b) else a = 299; + | ^~ +%Error-UNSUPPORTED: t/t_expect.v:21:34: Unsupported: ## (in sequence expression) + 21 | expect (@(posedge clk) a ##1 b) else a = 299; + | ^ +%Error-UNSUPPORTED: t/t_expect.v:21:7: Unsupported: expect + 21 | expect (@(posedge clk) a ##1 b) else a = 299; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_expect.v:23:32: Unsupported: ## () cycle delay range expression + 23 | expect (@(posedge clk) a ##1 b) a = 300; else a = 399; + | ^~ +%Error-UNSUPPORTED: t/t_expect.v:23:34: Unsupported: ## (in sequence expression) + 23 | expect (@(posedge clk) a ##1 b) a = 300; else a = 399; + | ^ +%Error-UNSUPPORTED: t/t_expect.v:23:7: Unsupported: expect + 23 | expect (@(posedge clk) a ##1 b) a = 300; else a = 399; + | ^~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_expect.pl b/test_regress/t/t_expect.pl new file mode 100755 index 000000000..1e49d46fd --- /dev/null +++ b/test_regress/t/t_expect.pl @@ -0,0 +1,20 @@ +#!/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(vlt => 1); + +compile( + expect_filename => $Self->{golden_filename}, + verilator_flags2 => ['--assert --timing'], + fails => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_expect.v b/test_regress/t/t_expect.v new file mode 100644 index 000000000..e51b22eaf --- /dev/null +++ b/test_regress/t/t_expect.v @@ -0,0 +1,28 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + reg a; + reg b; + + initial begin + #10; + expect (@(posedge clk) a ##1 b) a = 110; + #10; + expect (@(posedge clk) a ##1 b) else a = 299; + #10; + expect (@(posedge clk) a ##1 b) a = 300; else a = 399; + end + + // TODO set a/b appropriately - this is just a parsing test currently + +endmodule From 60a6ed2a202259a6d9247a62e6b56845bd7ae8d9 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 10 Mar 2023 22:13:17 -0500 Subject: [PATCH 020/155] Support assert property statement-else-statement --- src/V3Assert.cpp | 2 +- src/verilog.y | 18 ++++++----------- test_regress/t/t_assert_sampled.v | 33 +++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index ac8d96a42..97259fc5f 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -182,7 +182,7 @@ private: const bool force = VN_IS(nodep, AssertIntrinsic); if (passsp) passsp = newIfAssertOn(passsp, force); if (failsp) failsp = newIfAssertOn(failsp, force); - if (!failsp) failsp = newFireAssertUnchecked(nodep, "'assert' failed."); + if (!passsp && !failsp) failsp = newFireAssertUnchecked(nodep, "'assert' failed."); ifp = new AstIf{nodep->fileline(), propp, passsp, failsp}; ifp->isBoundsCheck(true); // To avoid LATCH warning // It's more LIKELY that we'll take the nullptr if clause diff --git a/src/verilog.y b/src/verilog.y index dbd714afb..147b14539 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -5772,14 +5772,13 @@ concurrent_assertion_item: // IEEE: concurrent_assertion_item concurrent_assertion_statement: // ==IEEE: concurrent_assertion_statement // // IEEE: assert_property_statement // // IEEE: assume_property_statement - //UNSUP remove below: - assertOrAssume yPROPERTY '(' property_spec ')' elseStmtBlock - { $$ = new AstAssert{$1, new AstSampled{$1, $4}, nullptr, $6, false}; } - //UNSUP remove above: // // action_block expanded here - //UNSUP assertOrAssume yPROPERTY '(' property_spec ')' stmt %prec prLOWER_THAN_ELSE {} - //UNSUP assertOrAssume yPROPERTY '(' property_spec ')' stmt yELSE stmt {} - //UNSUP assertOrAssume yPROPERTY '(' property_spec ')' yELSE stmt {} + assertOrAssume yPROPERTY '(' property_spec ')' stmt %prec prLOWER_THAN_ELSE + { $$ = new AstAssert{$1, new AstSampled{$1, $4}, $6, nullptr, false}; } + | assertOrAssume yPROPERTY '(' property_spec ')' stmt yELSE stmt + { $$ = new AstAssert{$1, new AstSampled{$1, $4}, $6, $8, false}; } + | assertOrAssume yPROPERTY '(' property_spec ')' yELSE stmt + { $$ = new AstAssert{$1, new AstSampled{$1, $4}, nullptr, $7, false}; } // // IEEE: cover_property_statement | yCOVER yPROPERTY '(' property_spec ')' stmtBlock { $$ = new AstCover{$1, $4, $6, false}; } @@ -5797,11 +5796,6 @@ concurrent_assertion_statement: // ==IEEE: concurrent_assertion_statemen { $$ = new AstRestrict{$1, $4}; } ; -elseStmtBlock: // Part of concurrent_assertion_statement - ';' { $$ = nullptr; } - | yELSE stmtBlock { $$ = $2; } - ; - property_declaration: // ==IEEE: property_declaration property_declarationFront property_port_listE ';' property_declarationBody yENDPROPERTY endLabelE diff --git a/test_regress/t/t_assert_sampled.v b/test_regress/t/t_assert_sampled.v index 49c7cc71e..27b2e9b70 100644 --- a/test_regress/t/t_assert_sampled.v +++ b/test_regress/t/t_assert_sampled.v @@ -4,6 +4,8 @@ // any use, without warranty, 2022 by Antmicro Ltd. // SPDX-License-Identifier: CC0-1.0 +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); + module t (/*AUTOARG*/ // Inputs clk @@ -14,6 +16,7 @@ module t (/*AUTOARG*/ Test1 t1(clk, a, b); Test2 t2(clk, a, b); + Test3 t3(clk, a, b); initial begin a = 0; @@ -54,3 +57,33 @@ module Test2( assert property (@(posedge clk) a == b); endmodule + +module Test3( + clk, a, b + ); + + input clk; + input [3:0] a, b; + + int hits[10]; + + assert property (@(posedge clk) a == b) hits[1]=1; + assert property (@(posedge clk) a == b) else hits[2]=1; + assert property (@(posedge clk) a == b) hits[3]=1; else hits[4]=1; + + assert property (@(posedge clk) a != b) hits[5]=1; + assert property (@(posedge clk) a != b) else hits[6]=1; + assert property (@(posedge clk) a != b) hits[7]=1; else hits[8]=1; + + final begin + `checkd(hits[1], 1); + `checkd(hits[2], 0); + `checkd(hits[3], 1); + `checkd(hits[4], 0); + `checkd(hits[5], 0); + `checkd(hits[6], 1); + `checkd(hits[7], 0); + `checkd(hits[8], 1); + end + +endmodule From b87669039eb6bc1163e3f53c40b9efed82d0a854 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 10 Mar 2023 22:25:47 -0500 Subject: [PATCH 021/155] Commentary --- src/verilog.y | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/verilog.y b/src/verilog.y index 147b14539..1a676084a 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -564,13 +564,11 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yCHANDLE "chandle" %token yCHECKER "checker" %token yCLASS "class" -//UNSUP %token yCLOCK "clock" %token yCLOCKING "clocking" %token yCMOS "cmos" %token yCONSTRAINT "constraint" %token yCONST__ETC "const" %token yCONST__LEX "const-in-lex" -//UNSUP %token yCONST__LOCAL "const-then-local" %token yCONST__REF "const-then-ref" %token yCONTEXT "context" %token yCONTINUE "continue" @@ -620,9 +618,6 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yFORK "fork" %token yFORKJOIN "forkjoin" %token yFUNCTION "function" -//UNSUP %token yFUNCTION__ETC "function" -//UNSUP %token yFUNCTION__LEX "function-in-lex" -//UNSUP %token yFUNCTION__aPUREV "function-is-pure-virtual" %token yGENERATE "generate" %token yGENVAR "genvar" %token yGLOBAL__CLOCKING "global-then-clocking" @@ -739,9 +734,6 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yTABLE "table" //UNSUP %token yTAGGED "tagged" %token yTASK "task" -//UNSUP %token yTASK__ETC "task" -//UNSUP %token yTASK__LEX "task-in-lex" -//UNSUP %token yTASK__aPUREV "task-is-pure-virtual" %token yTHIS "this" %token yTHROUGHOUT "throughout" %token yTIME "time" From 5c5c758718a034bb427814cffa59390b3358d2eb Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 11 Mar 2023 10:46:37 -0500 Subject: [PATCH 022/155] Parse 'wait_order' and test, still unsupported. --- src/verilog.l | 2 +- src/verilog.y | 11 +++--- test_regress/t/t_wait_order.out | 20 +++++++++++ test_regress/t/t_wait_order.pl | 20 +++++++++++ test_regress/t/t_wait_order.v | 60 +++++++++++++++++++++++++++++++++ 5 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 test_regress/t/t_wait_order.out create mode 100755 test_regress/t/t_wait_order.pl create mode 100644 test_regress/t/t_wait_order.v diff --git a/src/verilog.l b/src/verilog.l index d2005168c..2da54bccd 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -584,7 +584,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "var" { FL; return yVAR; } "virtual" { FL; return yVIRTUAL__LEX; } "void" { FL; return yVOID; } - "wait_order" { ERROR_RSVD_WORD("SystemVerilog 2005"); } + "wait_order" { FL; return yWAIT_ORDER; } "wildcard" { ERROR_RSVD_WORD("SystemVerilog 2005"); } "with" { FL; return yWITH__LEX; } "within" { FL; return yWITHIN; } diff --git a/src/verilog.y b/src/verilog.y index 1a676084a..e14e27207 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -769,7 +769,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yVIRTUAL__anyID "virtual-then-identifier" %token yVOID "void" %token yWAIT "wait" -//UNSUP %token yWAIT_ORDER "wait_order" +%token yWAIT_ORDER "wait_order" %token yWAND "wand" %token yWEAK "weak" %token yWEAK0 "weak0" @@ -3596,9 +3596,12 @@ statement_item: // IEEE: statement_item | yWAIT '(' expr ')' stmtBlock { $$ = new AstWait{$1, $3, $5}; } | yWAIT yFORK ';' { $$ = new AstWaitFork{$1}; } // // action_block expanded here - //UNSUP yWAIT_ORDER '(' hierarchical_identifierList ')' stmt %prec prLOWER_THAN_ELSE { UNSUP } - //UNSUP yWAIT_ORDER '(' hierarchical_identifierList ')' stmt yELSE stmt { UNSUP } - //UNSUP yWAIT_ORDER '(' hierarchical_identifierList ')' yELSE stmt { UNSUP } + | yWAIT_ORDER '(' vrdList ')' stmt %prec prLOWER_THAN_ELSE + { $$ = nullptr; BBUNSUP($4, "Unsupported: wait_order"); } + | yWAIT_ORDER '(' vrdList ')' stmt yELSE stmt + { $$ = nullptr; BBUNSUP($4, "Unsupported: wait_order"); } + | yWAIT_ORDER '(' vrdList ')' yELSE stmt + { $$ = nullptr; BBUNSUP($4, "Unsupported: wait_order"); } // // // IEEE: procedural_assertion_statement | procedural_assertion_statement { $$ = $1; } diff --git a/test_regress/t/t_wait_order.out b/test_regress/t/t_wait_order.out new file mode 100644 index 000000000..df943fb63 --- /dev/null +++ b/test_regress/t/t_wait_order.out @@ -0,0 +1,20 @@ +%Error-UNSUPPORTED: t/t_wait_order.v:16:23: Unsupported: wait_order + 16 | wait_order (a, b) wif[0] = '1; + | ^ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_wait_order.v:19:23: Unsupported: wait_order + 19 | wait_order (b, a) nif[0] = '1; + | ^ +%Error-UNSUPPORTED: t/t_wait_order.v:23:23: Unsupported: wait_order + 23 | wait_order (a, b) else welse[1] = '1; + | ^ +%Error-UNSUPPORTED: t/t_wait_order.v:26:23: Unsupported: wait_order + 26 | wait_order (b, a) else nelse[1] = '1; + | ^ +%Error-UNSUPPORTED: t/t_wait_order.v:30:23: Unsupported: wait_order + 30 | wait_order (a, b) wif[2] = '1; else welse[2] = '1; + | ^ +%Error-UNSUPPORTED: t/t_wait_order.v:33:23: Unsupported: wait_order + 33 | wait_order (b, a) nif[2] = '1; else nelse[2] = '1; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_wait_order.pl b/test_regress/t/t_wait_order.pl new file mode 100755 index 000000000..2e33e5676 --- /dev/null +++ b/test_regress/t/t_wait_order.pl @@ -0,0 +1,20 @@ +#!/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(simulator => 1); + +compile( + expect_filename => $Self->{golden_filename}, + verilator_flags2 => ['--timing'], + fails => $Self->{vlt_all}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_wait_order.v b/test_regress/t/t_wait_order.v new file mode 100644 index 000000000..d08ab7636 --- /dev/null +++ b/test_regress/t/t_wait_order.v @@ -0,0 +1,60 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); + +module t(/*AUTOARG*/); + + event a, b, c; + bit wif[10], welse[10]; + bit nif[10], nelse[10]; + + initial begin + wait_order (a, b) wif[0] = '1; + end + initial begin + wait_order (b, a) nif[0] = '1; + end + + initial begin + wait_order (a, b) else welse[1] = '1; + end + initial begin + wait_order (b, a) else nelse[1] = '1; + end + + initial begin + wait_order (a, b) wif[2] = '1; else welse[2] = '1; + end + initial begin + wait_order (b, a) nif[2] = '1; else nelse[2] = '1; + end + + initial begin + #10; + -> a; + #10; + -> b; + #10; + -> c; + #10; + // NOTE This hasn't been validated against other simulators + `checkd(wif[0], 1'b1); + `checkd(nif[0], 1'b0); + + `checkd(welse[1], 1'b0); + `checkd(nelse[1], 1'b1); + + `checkd(wif[2], 1'b1); + `checkd(welse[2], 1'b0); + `checkd(nif[2], 1'b0); + `checkd(nelse[2], 1'b1); + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From e55e81bcd05c68744d81d417d677cdc6155f6fd7 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 11 Mar 2023 10:53:10 -0500 Subject: [PATCH 023/155] Parse sequence 'local input', still unsupported. --- src/verilog.y | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/verilog.y b/src/verilog.y index e14e27207..b57bae87f 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -5848,9 +5848,14 @@ property_port_itemAssignment: // IEEE: part of property_port_item/sequen ; property_port_itemDirE: - /* empty */ { GRAMMARP->m_pinAnsi = true; VARIO(INPUT); } - //UNSUP|yLOCAL__ETC { GRAMMARP->m_pinAnsi = true; VARIO(INPUT); } - //UNSUP|yLOCAL__ETC yINPUT { GRAMMARP->m_pinAnsi = true; VARIO(INPUT); } + /* empty */ + { GRAMMARP->m_pinAnsi = true; VARIO(INPUT); } + | yLOCAL__ETC + { GRAMMARP->m_pinAnsi = true; VARIO(INPUT); + BBUNSUP($1, "Unsupported: property port 'local'"); } + | yLOCAL__ETC yINPUT + { GRAMMARP->m_pinAnsi = true; VARIO(INPUT); + BBUNSUP($1, "Unsupported: property port 'local'"); } ; property_declarationBody: // IEEE: part of property_declaration From 5489ec6effd842165e1448a3145951c13062cddd Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 11 Mar 2023 11:08:37 -0500 Subject: [PATCH 024/155] Parse 'first_match', and still unsupported. --- src/verilog.l | 2 +- src/verilog.y | 30 ++- test_regress/t/t_sequence_sexpr_unsup.out | 314 ++++++++++++---------- test_regress/t/t_sequence_sexpr_unsup.v | 11 + 4 files changed, 194 insertions(+), 163 deletions(-) diff --git a/src/verilog.l b/src/verilog.l index 2da54bccd..947e9ce03 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -530,7 +530,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "extends" { FL; return yEXTENDS; } "extern" { FL; return yEXTERN; } "final" { FL; return yFINAL; } - "first_match" { ERROR_RSVD_WORD("SystemVerilog 2005"); } + "first_match" { FL; return yFIRST_MATCH; } "forkjoin" { FL; return yFORKJOIN; } "iff" { FL; return yIFF; } "ignore_bins" { ERROR_RSVD_WORD("SystemVerilog 2005"); } diff --git a/src/verilog.y b/src/verilog.y index b57bae87f..e8ee45fd4 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -610,7 +610,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yEXTENDS "extends" %token yEXTERN "extern" %token yFINAL "final" -//UNSUP %token yFIRST_MATCH "first_match" +%token yFIRST_MATCH "first_match" %token yFOR "for" %token yFORCE "force" %token yFOREACH "foreach" @@ -6143,8 +6143,10 @@ sexpr: // ==IEEE: sequence_expr (The name sexpr is important as reg | ~p~sexpr yINTERSECT sexpr { $$ = $1; BBUNSUP($2, "Unsupported: intersect (in sequence expression)"); } // - //UNSUP yFIRST_MATCH '(' sexpr ')' { } - //UNSUP yFIRST_MATCH '(' sexpr ',' sequence_match_itemList ')' { } + | yFIRST_MATCH '(' sexpr ')' + { $$ = nullptr; BBUNSUP($1, "Unsupported: first_match (in sequence expression)"); } + | yFIRST_MATCH '(' sexpr ',' sequence_match_itemList ')' + { $$ = nullptr; BBUNSUP($1, "Unsupported: first_match (in sequence expression)"); } | ~p~sexpr/*sexpression_or_dist*/ yTHROUGHOUT sexpr { $$ = $1; BBUNSUP($2, "Unsupported: throughout (in sequence expression)"); } // // Below pexpr's are really sequence_expr, but avoid conflict @@ -6185,18 +6187,18 @@ cycle_delay_range: // IEEE: ==cycle_delay_range BBUNSUP($1, "Unsupported: ## [+] cycle delay range expression"); } ; -//UNSUPsequence_match_itemList: // IEEE: [sequence_match_item] part of sequence_expr -//UNSUP sequence_match_item { $$ = $1; } -//UNSUP | sequence_match_itemList ',' sequence_match_item { $$ = addNextNull($1, $3); } -//UNSUP ; +sequence_match_itemList: // IEEE: [sequence_match_item] part of sequence_expr + sequence_match_item { $$ = $1; } + | sequence_match_itemList ',' sequence_match_item { $$ = addNextNull($1, $3); } + ; -//UNSUPsequence_match_item: // ==IEEE: sequence_match_item -//UNSUP // // IEEE says: operator_assignment -//UNSUP // // IEEE says: inc_or_dec_expression -//UNSUP // // IEEE says: subroutine_call -//UNSUP // // This is the same list as... -//UNSUP for_step_assignment { $$ = $1; } -//UNSUP ; +sequence_match_item: // ==IEEE: sequence_match_item + // // IEEE says: operator_assignment + // // IEEE says: inc_or_dec_expression + // // IEEE says: subroutine_call + // // This is the same list as... + for_step_assignment { $$ = $1; } + ; boolean_abbrev: // ==IEEE: boolean_abbrev // // IEEE: consecutive_repetition diff --git a/test_regress/t/t_sequence_sexpr_unsup.out b/test_regress/t/t_sequence_sexpr_unsup.out index e128af57a..f72f26834 100644 --- a/test_regress/t/t_sequence_sexpr_unsup.out +++ b/test_regress/t/t_sequence_sexpr_unsup.out @@ -1,224 +1,242 @@ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:26:4: Unsupported: sequence - 26 | sequence s_a; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:27:4: Unsupported: sequence + 27 | sequence s_a; | ^~~~~~~~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:29:4: Unsupported: sequence - 29 | sequence s_var; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:30:4: Unsupported: sequence + 30 | sequence s_var; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:34:4: Unsupported: sequence - 34 | sequence s_within; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:35:4: Unsupported: sequence + 35 | sequence s_within; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:35:9: Unsupported: within (in sequence expression) - 35 | a within(b); +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:36:9: Unsupported: within (in sequence expression) + 36 | a within(b); | ^~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:38:4: Unsupported: sequence - 38 | sequence s_and; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:39:4: Unsupported: sequence + 39 | sequence s_and; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:39:9: Unsupported: and (in sequence expression) - 39 | a and b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:40:9: Unsupported: and (in sequence expression) + 40 | a and b; | ^~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:42:4: Unsupported: sequence - 42 | sequence s_or; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:43:4: Unsupported: sequence + 43 | sequence s_or; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:43:9: Unsupported: or (in sequence expression) - 43 | a or b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:44:9: Unsupported: or (in sequence expression) + 44 | a or b; | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:46:4: Unsupported: sequence - 46 | sequence s_throughout; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:47:4: Unsupported: sequence + 47 | sequence s_throughout; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:47:9: Unsupported: throughout (in sequence expression) - 47 | a throughout b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:48:9: Unsupported: throughout (in sequence expression) + 48 | a throughout b; | ^~~~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:50:4: Unsupported: sequence - 50 | sequence s_intersect; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:51:4: Unsupported: sequence + 51 | sequence s_intersect; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:51:9: Unsupported: intersect (in sequence expression) - 51 | a intersect b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:52:9: Unsupported: intersect (in sequence expression) + 52 | a intersect b; | ^~~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:54:4: Unsupported: sequence - 54 | sequence s_uni_cycdelay_int; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:55:4: Unsupported: sequence + 55 | sequence s_uni_cycdelay_int; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:55:7: Unsupported: ## () cycle delay range expression - 55 | ## 1 b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:56:7: Unsupported: ## () cycle delay range expression + 56 | ## 1 b; | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:55:12: Unsupported: ## (in sequence expression) - 55 | ## 1 b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:56:12: Unsupported: ## (in sequence expression) + 56 | ## 1 b; | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:57:4: Unsupported: sequence - 57 | sequence s_uni_cycdelay_id; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:58:4: Unsupported: sequence + 58 | sequence s_uni_cycdelay_id; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:58:7: Unsupported: ## id cycle delay range expression - 58 | ## DELAY b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:59:7: Unsupported: ## id cycle delay range expression + 59 | ## DELAY b; | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:58:16: Unsupported: ## (in sequence expression) - 58 | ## DELAY b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:59:16: Unsupported: ## (in sequence expression) + 59 | ## DELAY b; | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:60:4: Unsupported: sequence - 60 | sequence s_uni_cycdelay_pid; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:61:4: Unsupported: sequence + 61 | sequence s_uni_cycdelay_pid; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:61:7: Unsupported: ## () cycle delay range expression - 61 | ## ( DELAY ) b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:62:7: Unsupported: ## () cycle delay range expression + 62 | ## ( DELAY ) b; | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:61:20: Unsupported: ## (in sequence expression) - 61 | ## ( DELAY ) b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:62:20: Unsupported: ## (in sequence expression) + 62 | ## ( DELAY ) b; | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:63:4: Unsupported: sequence - 63 | sequence s_uni_cycdelay_range; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:64:4: Unsupported: sequence + 64 | sequence s_uni_cycdelay_range; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:64:7: Unsupported: ## range cycle delay range expression - 64 | ## [1:2] b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:65:7: Unsupported: ## range cycle delay range expression + 65 | ## [1:2] b; | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:64:16: Unsupported: ## (in sequence expression) - 64 | ## [1:2] b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:65:16: Unsupported: ## (in sequence expression) + 65 | ## [1:2] b; | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:66:4: Unsupported: sequence - 66 | sequence s_uni_cycdelay_star; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:67:4: Unsupported: sequence + 67 | sequence s_uni_cycdelay_star; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:67:7: Unsupported: ## [*] cycle delay range expression - 67 | ## [*] b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:68:7: Unsupported: ## [*] cycle delay range expression + 68 | ## [*] b; | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:67:14: Unsupported: ## (in sequence expression) - 67 | ## [*] b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:68:14: Unsupported: ## (in sequence expression) + 68 | ## [*] b; | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:69:4: Unsupported: sequence - 69 | sequence s_uni_cycdelay_plus; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:70:4: Unsupported: sequence + 70 | sequence s_uni_cycdelay_plus; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:70:7: Unsupported: ## [+] cycle delay range expression - 70 | ## [+] b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:71:7: Unsupported: ## [+] cycle delay range expression + 71 | ## [+] b; | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:70:14: Unsupported: ## (in sequence expression) - 70 | ## [+] b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:71:14: Unsupported: ## (in sequence expression) + 71 | ## [+] b; | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:73:4: Unsupported: sequence - 73 | sequence s_cycdelay_int; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:74:4: Unsupported: sequence + 74 | sequence s_cycdelay_int; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:74:9: Unsupported: ## () cycle delay range expression - 74 | a ## 1 b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:75:9: Unsupported: ## () cycle delay range expression + 75 | a ## 1 b; | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:74:12: Unsupported: ## (in sequence expression) - 74 | a ## 1 b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:75:12: Unsupported: ## (in sequence expression) + 75 | a ## 1 b; | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:76:4: Unsupported: sequence - 76 | sequence s_cycdelay_id; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:77:4: Unsupported: sequence + 77 | sequence s_cycdelay_id; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:77:9: Unsupported: ## id cycle delay range expression - 77 | a ## DELAY b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:78:9: Unsupported: ## id cycle delay range expression + 78 | a ## DELAY b; | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:77:9: Unsupported: ## (in sequence expression) - 77 | a ## DELAY b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:78:9: Unsupported: ## (in sequence expression) + 78 | a ## DELAY b; | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:79:4: Unsupported: sequence - 79 | sequence s_cycdelay_pid; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:80:4: Unsupported: sequence + 80 | sequence s_cycdelay_pid; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:80:9: Unsupported: ## () cycle delay range expression - 80 | a ## ( DELAY ) b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:81:9: Unsupported: ## () cycle delay range expression + 81 | a ## ( DELAY ) b; | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:80:14: Unsupported: ## (in sequence expression) - 80 | a ## ( DELAY ) b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:81:14: Unsupported: ## (in sequence expression) + 81 | a ## ( DELAY ) b; | ^~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:82:4: Unsupported: sequence - 82 | sequence s_cycdelay_range; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:83:4: Unsupported: sequence + 83 | sequence s_cycdelay_range; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:83:9: Unsupported: ## range cycle delay range expression - 83 | a ## [1:2] b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:84:9: Unsupported: ## range cycle delay range expression + 84 | a ## [1:2] b; | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:83:9: Unsupported: ## (in sequence expression) - 83 | a ## [1:2] b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:84:9: Unsupported: ## (in sequence expression) + 84 | a ## [1:2] b; | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:85:4: Unsupported: sequence - 85 | sequence s_cycdelay_star; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:86:4: Unsupported: sequence + 86 | sequence s_cycdelay_star; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:86:9: Unsupported: ## [*] cycle delay range expression - 86 | a ## [*] b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:87:9: Unsupported: ## [*] cycle delay range expression + 87 | a ## [*] b; | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:86:9: Unsupported: ## (in sequence expression) - 86 | a ## [*] b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:87:9: Unsupported: ## (in sequence expression) + 87 | a ## [*] b; | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:88:4: Unsupported: sequence - 88 | sequence s_cycdelay_plus; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:89:4: Unsupported: sequence + 89 | sequence s_cycdelay_plus; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:89:9: Unsupported: ## [+] cycle delay range expression - 89 | a ## [+] b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:90:9: Unsupported: ## [+] cycle delay range expression + 90 | a ## [+] b; | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:89:9: Unsupported: ## (in sequence expression) - 89 | a ## [+] b; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:90:9: Unsupported: ## (in sequence expression) + 90 | a ## [+] b; | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:92:4: Unsupported: sequence - 92 | sequence s_booleanabbrev_brastar_int; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:93:4: Unsupported: sequence + 93 | sequence s_booleanabbrev_brastar_int; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:93:9: Unsupported: [*] boolean abbrev expression - 93 | a [* 1 ]; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:94:9: Unsupported: [*] boolean abbrev expression + 94 | a [* 1 ]; | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:93:12: Unsupported: boolean abbrev (in sequence expression) - 93 | a [* 1 ]; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:94:12: Unsupported: boolean abbrev (in sequence expression) + 94 | a [* 1 ]; | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:95:4: Unsupported: sequence - 95 | sequence s_booleanabbrev_brastar; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:96:4: Unsupported: sequence + 96 | sequence s_booleanabbrev_brastar; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:96:9: Unsupported: [*] boolean abbrev expression - 96 | a [*]; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:97:9: Unsupported: [*] boolean abbrev expression + 97 | a [*]; | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:96:9: Unsupported: boolean abbrev (in sequence expression) - 96 | a [*]; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:97:9: Unsupported: boolean abbrev (in sequence expression) + 97 | a [*]; | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:98:4: Unsupported: sequence - 98 | sequence s_booleanabbrev_plus; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:99:4: Unsupported: sequence + 99 | sequence s_booleanabbrev_plus; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:99:9: Unsupported: [+] boolean abbrev expression - 99 | a [+]; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:100:9: Unsupported: [+] boolean abbrev expression + 100 | a [+]; | ^~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:99:9: Unsupported: boolean abbrev (in sequence expression) - 99 | a [+]; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:100:9: Unsupported: boolean abbrev (in sequence expression) + 100 | a [+]; | ^~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:101:4: Unsupported: sequence - 101 | sequence s_booleanabbrev_eq; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:102:4: Unsupported: sequence + 102 | sequence s_booleanabbrev_eq; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:102:9: Unsupported: [= boolean abbrev expression - 102 | a [= 1]; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:103:9: Unsupported: [= boolean abbrev expression + 103 | a [= 1]; | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:102:12: Unsupported: boolean abbrev (in sequence expression) - 102 | a [= 1]; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:103:12: Unsupported: boolean abbrev (in sequence expression) + 103 | a [= 1]; | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:104:4: Unsupported: sequence - 104 | sequence s_booleanabbrev_eq_range; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:105:4: Unsupported: sequence + 105 | sequence s_booleanabbrev_eq_range; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:105:9: Unsupported: [= boolean abbrev expression - 105 | a [= 1:2]; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:106:9: Unsupported: [= boolean abbrev expression + 106 | a [= 1:2]; | ^~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:105:12: Unsupported: boolean abbrev (in sequence expression) - 105 | a [= 1:2]; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:106:12: Unsupported: boolean abbrev (in sequence expression) + 106 | a [= 1:2]; | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:107:4: Unsupported: sequence - 107 | sequence s_booleanabbrev_minusgt; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:108:4: Unsupported: sequence + 108 | sequence s_booleanabbrev_minusgt; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:108:9: Unsupported: [-> boolean abbrev expression - 108 | a [-> 1]; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:109:9: Unsupported: [-> boolean abbrev expression + 109 | a [-> 1]; | ^~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:108:13: Unsupported: boolean abbrev (in sequence expression) - 108 | a [-> 1]; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:109:13: Unsupported: boolean abbrev (in sequence expression) + 109 | a [-> 1]; | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:110:4: Unsupported: sequence - 110 | sequence s_booleanabbrev_minusgt_range; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:111:4: Unsupported: sequence + 111 | sequence s_booleanabbrev_minusgt_range; | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:111:9: Unsupported: [-> boolean abbrev expression - 111 | a [-> 1:2]; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:112:9: Unsupported: [-> boolean abbrev expression + 112 | a [-> 1:2]; | ^~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:111:13: Unsupported: boolean abbrev (in sequence expression) - 111 | a [-> 1:2]; +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:112:13: Unsupported: boolean abbrev (in sequence expression) + 112 | a [-> 1:2]; | ^ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:114:4: Unsupported: sequence - 114 | sequence p_arg_seqence(sequence inseq); +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:115:4: Unsupported: sequence + 115 | sequence p_arg_seqence(sequence inseq); | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:114:27: Unsupported: sequence argument data type - 114 | sequence p_arg_seqence(sequence inseq); +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:115:27: Unsupported: sequence argument data type + 115 | sequence p_arg_seqence(sequence inseq); | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:118:10: Unsupported: cover sequence - 118 | cover sequence (s_a) $display(""); +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:119:4: Unsupported: sequence + 119 | sequence s_firstmatch_a; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:120:7: Unsupported: first_match (in sequence expression) + 120 | first_match (a); + | ^~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:122:4: Unsupported: sequence + 122 | sequence s_firstmatch_ab; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:123:7: Unsupported: first_match (in sequence expression) + 123 | first_match (a, res0 = 1); + | ^~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:125:4: Unsupported: sequence + 125 | sequence s_firstmatch_abc; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:126:7: Unsupported: first_match (in sequence expression) + 126 | first_match (a, res0 = 1, res1 = 2); + | ^~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:129:10: Unsupported: cover sequence + 129 | cover sequence (s_a) $display(""); | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:119:10: Unsupported: cover sequence - 119 | cover sequence (@(posedge a) disable iff (b) s_a) $display(""); +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:130:10: Unsupported: cover sequence + 130 | cover sequence (@(posedge a) disable iff (b) s_a) $display(""); | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:120:10: Unsupported: cover sequence - 120 | cover sequence (disable iff (b) s_a) $display(""); +%Error-UNSUPPORTED: t/t_sequence_sexpr_unsup.v:131:10: Unsupported: cover sequence + 131 | cover sequence (disable iff (b) s_a) $display(""); | ^~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_sequence_sexpr_unsup.v b/test_regress/t/t_sequence_sexpr_unsup.v index 0ec594255..da3b99ec2 100644 --- a/test_regress/t/t_sequence_sexpr_unsup.v +++ b/test_regress/t/t_sequence_sexpr_unsup.v @@ -13,6 +13,7 @@ module t (/*AUTOARG*/ int a; int b; int cyc = 0; + int res0, res1; localparam DELAY = 1; @@ -115,6 +116,16 @@ module t (/*AUTOARG*/ inseq; endsequence + sequence s_firstmatch_a; + first_match (a); + endsequence + sequence s_firstmatch_ab; + first_match (a, res0 = 1); + endsequence + sequence s_firstmatch_abc; + first_match (a, res0 = 1, res1 = 2); + endsequence + cover sequence (s_a) $display(""); cover sequence (@(posedge a) disable iff (b) s_a) $display(""); cover sequence (disable iff (b) s_a) $display(""); From bb45bd048e184a00c8c7257d5d090385b97c17a1 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 11 Mar 2023 11:19:19 -0500 Subject: [PATCH 025/155] Commentary --- src/verilog.y | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/verilog.y b/src/verilog.y index e8ee45fd4..dc42045aa 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -1539,16 +1539,7 @@ port: // ==IEEE: port // // // Note implicit rules looks just line declaring additional followon port // // No VARDECL("port") for implicit, as we don't want to declare variables for them - //UNSUP portDirNetE data_type '.' portSig '(' portAssignExprE ')' sigAttrListE - //UNSUP { UNSUP } - //UNSUP portDirNetE yVAR data_type '.' portSig '(' portAssignExprE ')' sigAttrListE - //UNSUP { UNSUP } - //UNSUP portDirNetE yVAR implicit_type '.' portSig '(' portAssignExprE ')' sigAttrListE - //UNSUP { UNSUP } - //UNSUP portDirNetE signingE rangeList '.' portSig '(' portAssignExprE ')' sigAttrListE - //UNSUP { UNSUP } - //UNSUP portDirNetE /*implicit*/ '.' portSig '(' portAssignExprE ')' sigAttrListE - //UNSUP { UNSUP } + // // IEEE: portDirNetE data_type '.' portSig -> handled with AstDot in expr. // | portDirNetE data_type portSig variable_dimensionListE sigAttrListE { $$ = $3; VARDTYPE($2); addNextNull($$, VARDONEP($$, $4, $5)); } @@ -3657,7 +3648,6 @@ foperator_assignment: // IEEE: operator_assignment (for first part of | fexprLvalue '=' yD_FOPEN '(' expr ')' { $$ = new AstFOpenMcd{$3, $1, $5}; } | fexprLvalue '=' yD_FOPEN '(' expr ',' expr ')' { $$ = new AstFOpen{$3, $1, $5, $7}; } // - //UNSUP ~f~exprLvalue yP_PLUS(etc) expr { UNSUP } | fexprLvalue yP_PLUSEQ expr { $$ = new AstAssign{$2, $1, new AstAdd{$2, $1->cloneTree(true), $3}}; } | fexprLvalue yP_MINUSEQ expr @@ -3680,8 +3670,6 @@ foperator_assignment: // IEEE: operator_assignment (for first part of { $$ = new AstAssign{$2, $1, new AstShiftR{$2, $1->cloneTree(true), $3}}; } | fexprLvalue yP_SSRIGHTEQ expr { $$ = new AstAssign{$2, $1, new AstShiftRS{$2, $1->cloneTree(true), $3}}; } - //UNSUP replace above with: - //UNSUP BISONPRE_COPY(operator_assignment,{s/~f~/f/g}) // {copied} ; inc_or_dec_expression: // ==IEEE: inc_or_dec_expression From 259201b3522ebf103b2c21ca0d436bd17c956813 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 11 Mar 2023 18:11:01 -0500 Subject: [PATCH 026/155] Support $fopen as an expression --- Changes | 2 ++ src/V3AstNodeExpr.h | 40 +++++++++++++++++++++++++ src/V3AstNodeOther.h | 40 ------------------------- src/V3EmitCFunc.h | 6 ++-- src/V3LinkLValue.cpp | 50 ++++---------------------------- src/V3LinkResolve.cpp | 8 ----- src/V3Width.cpp | 6 ++-- src/verilog.y | 4 +-- test_regress/t/t_debug_emitv.out | 6 ++-- 9 files changed, 57 insertions(+), 105 deletions(-) diff --git a/Changes b/Changes index bacce15df..4c45d300d 100644 --- a/Changes +++ b/Changes @@ -13,6 +13,8 @@ Verilator 5.009 devel **Minor:** +* Support $fopen as an expression. + Verilator 5.008 2023-03-04 ========================== diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 3ccc3a36f..4ec2b90c1 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -1112,6 +1112,46 @@ public: bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering bool same(const AstNode* /*samep*/) const override { return true; } }; +class AstFOpen final : public AstNodeExpr { + // @astgen op2 := filenamep : AstNodeExpr + // @astgen op3 := modep : AstNodeExpr +public: + AstFOpen(FileLine* fl, AstNodeExpr* filenamep, AstNodeExpr* modep) + : ASTGEN_SUPER_FOpen(fl) { + this->filenamep(filenamep); + this->modep(modep); + } + ASTGEN_MEMBERS_AstFOpen; + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } + string verilogKwd() const override { return "$fopen"; } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isPure() const override { return false; } + bool isOutputter() const override { return true; } + bool isUnlikely() const override { return true; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstFOpenMcd final : public AstNodeExpr { + // @astgen op2 := filenamep : AstNodeExpr +public: + AstFOpenMcd(FileLine* fl, AstNodeExpr* filenamep) + : ASTGEN_SUPER_FOpenMcd(fl) { + this->filenamep(filenamep); + } + ASTGEN_MEMBERS_AstFOpenMcd; + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } + string verilogKwd() const override { return "$fopen"; } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + bool isPure() const override { return false; } + bool isOutputter() const override { return true; } + bool isUnlikely() const override { return true; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; class AstFRead final : public AstNodeExpr { // @astgen op1 := memp : AstNode // VarRef for result // @astgen op2 := filep : AstNode // file (must be a VarRef) diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 87bad25ba..111b6b3a3 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -2739,46 +2739,6 @@ public: bool isUnlikely() const override { return true; } bool same(const AstNode* /*samep*/) const override { return true; } }; -class AstFOpen final : public AstNodeStmt { - // Although a system function in IEEE, here a statement which sets the file pointer (MCD) - // @astgen op1 := filep : AstNodeExpr - // @astgen op2 := filenamep : AstNodeExpr - // @astgen op3 := modep : AstNodeExpr -public: - AstFOpen(FileLine* fl, AstNodeExpr* filep, AstNodeExpr* filenamep, AstNodeExpr* modep) - : ASTGEN_SUPER_FOpen(fl) { - this->filep(filep); - this->filenamep(filenamep); - this->modep(modep); - } - ASTGEN_MEMBERS_AstFOpen; - string verilogKwd() const override { return "$fopen"; } - bool isGateOptimizable() const override { return false; } - bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } - bool isOutputter() const override { return true; } - bool isUnlikely() const override { return true; } - bool same(const AstNode* /*samep*/) const override { return true; } -}; -class AstFOpenMcd final : public AstNodeStmt { - // Although a system function in IEEE, here a statement which sets the file pointer (MCD) - // @astgen op1 := filep : AstNodeExpr - // @astgen op2 := filenamep : AstNodeExpr -public: - AstFOpenMcd(FileLine* fl, AstNodeExpr* filep, AstNodeExpr* filenamep) - : ASTGEN_SUPER_FOpenMcd(fl) { - this->filep(filep); - this->filenamep(filenamep); - } - ASTGEN_MEMBERS_AstFOpenMcd; - string verilogKwd() const override { return "$fopen"; } - bool isGateOptimizable() const override { return false; } - bool isPredictOptimizable() const override { return false; } - bool isPure() const override { return false; } - bool isOutputter() const override { return true; } - bool isUnlikely() const override { return true; } - bool same(const AstNode* /*samep*/) const override { return true; } -}; class AstFinish final : public AstNodeStmt { public: explicit AstFinish(FileLine* fl) diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index c91112ef0..808fb7e17 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -649,8 +649,7 @@ public: } } void visit(AstFOpen* nodep) override { - iterateAndNextNull(nodep->filep()); - puts(" = VL_FOPEN_NN("); + puts("VL_FOPEN_NN("); emitCvtPackStr(nodep->filenamep()); putbs(", "); if (nodep->modep()->width() > 4 * 8) @@ -659,8 +658,7 @@ public: puts(");\n"); } void visit(AstFOpenMcd* nodep) override { - iterateAndNextNull(nodep->filep()); - puts(" = VL_FOPEN_MCD_N("); + puts("VL_FOPEN_MCD_N("); emitCvtPackStr(nodep->filenamep()); puts(");\n"); } diff --git a/src/V3LinkLValue.cpp b/src/V3LinkLValue.cpp index 5672089fc..ca0f07574 100644 --- a/src/V3LinkLValue.cpp +++ b/src/V3LinkLValue.cpp @@ -116,83 +116,43 @@ private: iterateAndNextNull(nodep->top()); } } - void visit(AstFOpen* nodep) override { - VL_RESTORER(m_setRefLvalue); - { - m_setRefLvalue = VAccess::WRITE; - iterateAndNextNull(nodep->filep()); - m_setRefLvalue = VAccess::NOCHANGE; - iterateAndNextNull(nodep->filenamep()); - iterateAndNextNull(nodep->modep()); - } - } - void visit(AstFOpenMcd* nodep) override { - VL_RESTORER(m_setRefLvalue); - { - m_setRefLvalue = VAccess::WRITE; - iterateAndNextNull(nodep->filep()); - m_setRefLvalue = VAccess::NOCHANGE; - iterateAndNextNull(nodep->filenamep()); - } - } - void visit(AstFClose* nodep) override { - VL_RESTORER(m_setRefLvalue); - { - m_setRefLvalue = VAccess::WRITE; - iterateAndNextNull(nodep->filep()); - } - } void visit(AstFError* nodep) override { VL_RESTORER(m_setRefLvalue); { - m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->filep()); + m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->strp()); } } - void visit(AstFFlush* nodep) override { - VL_RESTORER(m_setRefLvalue); - { - m_setRefLvalue = VAccess::WRITE; - iterateAndNextNull(nodep->filep()); - } - } - void visit(AstFGetC* nodep) override { - VL_RESTORER(m_setRefLvalue); - { - m_setRefLvalue = VAccess::WRITE; - iterateAndNextNull(nodep->filep()); - } - } void visit(AstFGetS* nodep) override { VL_RESTORER(m_setRefLvalue); { - m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->filep()); + m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->strgp()); } } void visit(AstFRead* nodep) override { VL_RESTORER(m_setRefLvalue); { + iterateAndNextNull(nodep->filep()); m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->memp()); - iterateAndNextNull(nodep->filep()); } } void visit(AstFScanF* nodep) override { VL_RESTORER(m_setRefLvalue); { - m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->filep()); + m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->exprsp()); } } void visit(AstFUngetC* nodep) override { VL_RESTORER(m_setRefLvalue); { - m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->filep()); + m_setRefLvalue = VAccess::WRITE; iterateAndNextNull(nodep->rhsp()); } } diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 6ecc90b2c..5f9bcbbef 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -318,14 +318,6 @@ private: if (filep && filep->varp()) filep->varp()->attrFileDescr(true); } - void visit(AstFOpen* nodep) override { - iterateChildren(nodep); - expectDescriptor(nodep, VN_CAST(nodep->filep(), NodeVarRef)); - } - void visit(AstFOpenMcd* nodep) override { - iterateChildren(nodep); - expectDescriptor(nodep, VN_CAST(nodep->filep(), NodeVarRef)); - } void visit(AstFClose* nodep) override { iterateChildren(nodep); expectDescriptor(nodep, VN_CAST(nodep->filep(), NodeVarRef)); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 89ee71e5a..a50697f09 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -4861,15 +4861,13 @@ private: } void visit(AstFOpen* nodep) override { // Although a system function in IEEE, here a statement which sets the file pointer (MCD) - assertAtStatement(nodep); - iterateCheckFileDesc(nodep, nodep->filep(), BOTH); userIterateAndNext(nodep->filenamep(), WidthVP{SELF, BOTH}.p()); userIterateAndNext(nodep->modep(), WidthVP{SELF, BOTH}.p()); + nodep->dtypeSetLogicUnsized(32, 1, VSigning::SIGNED); // Spec says integer return } void visit(AstFOpenMcd* nodep) override { - assertAtStatement(nodep); - iterateCheckFileDesc(nodep, nodep->filep(), BOTH); userIterateAndNext(nodep->filenamep(), WidthVP{SELF, BOTH}.p()); + nodep->dtypeSetLogicUnsized(32, 1, VSigning::SIGNED); // Spec says integer return } void visit(AstFClose* nodep) override { assertAtStatement(nodep); diff --git a/src/verilog.y b/src/verilog.y index dc42045aa..f8408698b 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -3645,8 +3645,6 @@ statementVerilatorPragmas: foperator_assignment: // IEEE: operator_assignment (for first part of expression) fexprLvalue '=' delay_or_event_controlE expr { $$ = new AstAssign{$2, $1, $4, $3}; } - | fexprLvalue '=' yD_FOPEN '(' expr ')' { $$ = new AstFOpenMcd{$3, $1, $5}; } - | fexprLvalue '=' yD_FOPEN '(' expr ',' expr ')' { $$ = new AstFOpen{$3, $1, $5, $7}; } // | fexprLvalue yP_PLUSEQ expr { $$ = new AstAssign{$2, $1, new AstAdd{$2, $1->cloneTree(true), $3}}; } @@ -4208,6 +4206,8 @@ system_f_call_or_t: // IEEE: part of system_tf_call (can be task | yD_FERROR '(' expr ',' idClassSel ')' { $$ = new AstFError{$1, $3, $5}; } | yD_FGETC '(' expr ')' { $$ = new AstFGetC{$1, $3}; } | yD_FGETS '(' expr ',' expr ')' { $$ = new AstFGetS{$1, $3, $5}; } + | yD_FOPEN '(' expr ')' { $$ = new AstFOpenMcd{$1, $3}; } + | yD_FOPEN '(' expr ',' expr ')' { $$ = new AstFOpen{$1, $3, $5}; } | yD_FREAD '(' expr ',' expr ')' { $$ = new AstFRead{$1, $3, $5, nullptr, nullptr}; } | yD_FREAD '(' expr ',' expr ',' expr ')' { $$ = new AstFRead{$1, $3, $5, $7, nullptr}; } | yD_FREAD '(' expr ',' expr ',' expr ',' expr ')' { $$ = new AstFRead{$1, $3, $5, $7, $9}; } diff --git a/test_regress/t/t_debug_emitv.out b/test_regress/t/t_debug_emitv.out index 82db5dfde..2775f2c02 100644 --- a/test_regress/t/t_debug_emitv.out +++ b/test_regress/t/t_debug_emitv.out @@ -169,9 +169,11 @@ module Vt_debug_emitv_t; : $c('sh1e))); $c(;); $display("%d", $c(0)); - $fopen(72'h2f6465762f6e756c6c); + fd = $fopen(72'h2f6465762f6e756c6c); + ; $fclose(fd); - $fopen(72'h2f6465762f6e756c6c, 8'h72); + fd = $fopen(72'h2f6465762f6e756c6c, 8'h72); + ; $fgetc(fd); $fflush(fd); $fscanf(fd, "%d", sum); From 1f1d9312d20aed1db7360ce803e6698e493ef952 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 11 Mar 2023 22:35:18 -0500 Subject: [PATCH 027/155] Parse event 'iff', still unsupported. --- src/verilog.y | 28 ++++++++++++++++++++-------- test_regress/t/t_iff.out | 18 ++++++++++++++---- test_regress/t/t_iff.pl | 1 + test_regress/t/t_iff.v | 29 +++++++++++++++++++++++------ test_regress/t/t_wait_order.out | 19 ++++++++----------- test_regress/t/t_wait_order.v | 4 +++- 6 files changed, 69 insertions(+), 30 deletions(-) diff --git a/src/verilog.y b/src/verilog.y index f8408698b..d44c466ba 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -3302,8 +3302,11 @@ event_expression: // IEEE: event_expression - split over several senitem: // IEEE: part of event_expression, non-'OR' ',' terms senitemEdge { $$ = $1; } - | expr { $$ = new AstSenItem{$1, VEdgeType::ET_CHANGED, $1}; } - //UNSUP expr yIFF expr { UNSUP } + | expr + { $$ = new AstSenItem{$1, VEdgeType::ET_CHANGED, $1}; } + | expr yIFF expr + { $$ = new AstSenItem{$1, VEdgeType::ET_CHANGED, $1}; + if ($2) BBUNSUP($2, "Unsupported: event expression 'iff'"); } ; senitemVar: @@ -3311,12 +3314,21 @@ senitemVar: ; senitemEdge: // IEEE: part of event_expression - yPOSEDGE expr { $$ = new AstSenItem{$1, VEdgeType::ET_POSEDGE, $2}; } - | yNEGEDGE expr { $$ = new AstSenItem{$1, VEdgeType::ET_NEGEDGE, $2}; } - | yEDGE expr { $$ = new AstSenItem{$1, VEdgeType::ET_BOTHEDGE, $2}; } - //UNSUP yPOSEDGE expr yIFF expr { UNSUP } - //UNSUP yNEGEDGE expr yIFF expr { UNSUP } - //UNSUP yEDGE expr yIFF expr { UNSUP } + yPOSEDGE expr + { $$ = new AstSenItem{$1, VEdgeType::ET_POSEDGE, $2}; } + | yNEGEDGE expr + { $$ = new AstSenItem{$1, VEdgeType::ET_NEGEDGE, $2}; } + | yEDGE expr + { $$ = new AstSenItem{$1, VEdgeType::ET_BOTHEDGE, $2}; } + | yPOSEDGE expr yIFF expr + { $$ = new AstSenItem{$1, VEdgeType::ET_POSEDGE, $2}; + BBUNSUP($3, "Unsupported: event expression 'iff'"); } + | yNEGEDGE expr yIFF expr + { $$ = new AstSenItem{$1, VEdgeType::ET_NEGEDGE, $2}; + BBUNSUP($3, "Unsupported: event expression 'iff'"); } + | yEDGE expr yIFF expr + { $$ = new AstSenItem{$1, VEdgeType::ET_BOTHEDGE, $2}; + BBUNSUP($3, "Unsupported: event expression 'iff'"); } ; //************************************************ diff --git a/test_regress/t/t_iff.out b/test_regress/t/t_iff.out index 6680a685b..24dc99876 100644 --- a/test_regress/t/t_iff.out +++ b/test_regress/t/t_iff.out @@ -1,7 +1,17 @@ -%Error: t/t_iff.v:64:15: syntax error, unexpected iff, expecting ')' or ',' or or - 64 | always @(d iff enable == 1) begin +%Error-UNSUPPORTED: t/t_iff.v:66:15: Unsupported: event expression 'iff' + 66 | always @(d iff enable) begin | ^~~ -%Error: t/t_iff.v:69:35: syntax error, unexpected iff, expecting ')' - 69 | assert property (@(posedge clk iff enable) + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_iff.v:71:23: Unsupported: event expression 'iff' + 71 | always @(posedge d iff enable) begin + | ^~~ +%Error-UNSUPPORTED: t/t_iff.v:76:23: Unsupported: event expression 'iff' + 76 | always @(negedge d iff enable) begin + | ^~~ +%Error-UNSUPPORTED: t/t_iff.v:81:20: Unsupported: event expression 'iff' + 81 | always @(edge d iff enable) begin + | ^~~ +%Error-UNSUPPORTED: t/t_iff.v:86:35: Unsupported: event expression 'iff' + 86 | assert property (@(posedge clk iff enable) | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_iff.pl b/test_regress/t/t_iff.pl index 734924e17..2966ed9a2 100755 --- a/test_regress/t/t_iff.pl +++ b/test_regress/t/t_iff.pl @@ -11,6 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( + verilator_flags2 => ['--timing'], fails => $Self->{vlt_all}, # Verilator unsupported, bug1482, iff not supported expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_iff.v b/test_regress/t/t_iff.v index e41a2f746..833bf411f 100644 --- a/test_regress/t/t_iff.v +++ b/test_regress/t/t_iff.v @@ -42,7 +42,7 @@ module t (/*AUTOARG*/ $write("[%0t] cyc==%0d crc=%x sum=%x\n", $time, cyc, crc, sum); if (crc !== 64'hc77bb9b3784ea091) $stop; // What checksum will we end up with (above print should match) -`define EXPECTED_SUM 64'he58508de5310b541 +`define EXPECTED_SUM 64'h390aa8652d33a691 if (sum !== `EXPECTED_SUM) $stop; $write("*-* All Finished *-*\n"); $finish; @@ -59,10 +59,27 @@ module Test output wire [31:0] result); wire enable = crc[32]; - wire [31:0] d = crc[31:0]; - logic [31:0] y; - always @(d iff enable == 1) begin - y <= d; + wire [7:0] d = crc[7:0]; + + + logic [7:0] d0_r; + always @(d iff enable) begin + d0_r <= d; + end + + logic [7:0] d1_r; + always @(posedge d iff enable) begin + d1_r <= d; + end + + logic [7:0] d2_r; + always @(negedge d iff enable) begin + d2_r <= d; + end + + logic [7:0] d3_r; + always @(edge d iff enable) begin + d3_r <= d; end wire reset = (cyc < 10); @@ -71,6 +88,6 @@ module Test (crc != '0)); // Aggregate outputs into a single result vector - assign result = {32'h0, y}; + assign result = {32'h0, d3_r, d2_r, d1_r, d0_r}; endmodule diff --git a/test_regress/t/t_wait_order.out b/test_regress/t/t_wait_order.out index df943fb63..20887769e 100644 --- a/test_regress/t/t_wait_order.out +++ b/test_regress/t/t_wait_order.out @@ -2,19 +2,16 @@ 16 | wait_order (a, b) wif[0] = '1; | ^ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_wait_order.v:19:23: Unsupported: wait_order - 19 | wait_order (b, a) nif[0] = '1; +%Error-UNSUPPORTED: t/t_wait_order.v:25:23: Unsupported: wait_order + 25 | wait_order (a, b) else welse[1] = '1; | ^ -%Error-UNSUPPORTED: t/t_wait_order.v:23:23: Unsupported: wait_order - 23 | wait_order (a, b) else welse[1] = '1; +%Error-UNSUPPORTED: t/t_wait_order.v:28:23: Unsupported: wait_order + 28 | wait_order (b, a) else nelse[1] = '1; | ^ -%Error-UNSUPPORTED: t/t_wait_order.v:26:23: Unsupported: wait_order - 26 | wait_order (b, a) else nelse[1] = '1; +%Error-UNSUPPORTED: t/t_wait_order.v:32:23: Unsupported: wait_order + 32 | wait_order (a, b) wif[2] = '1; else welse[2] = '1; | ^ -%Error-UNSUPPORTED: t/t_wait_order.v:30:23: Unsupported: wait_order - 30 | wait_order (a, b) wif[2] = '1; else welse[2] = '1; - | ^ -%Error-UNSUPPORTED: t/t_wait_order.v:33:23: Unsupported: wait_order - 33 | wait_order (b, a) nif[2] = '1; else nelse[2] = '1; +%Error-UNSUPPORTED: t/t_wait_order.v:35:23: Unsupported: wait_order + 35 | wait_order (b, a) nif[2] = '1; else nelse[2] = '1; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_wait_order.v b/test_regress/t/t_wait_order.v index d08ab7636..3fa46a808 100644 --- a/test_regress/t/t_wait_order.v +++ b/test_regress/t/t_wait_order.v @@ -15,9 +15,11 @@ module t(/*AUTOARG*/); initial begin wait_order (a, b) wif[0] = '1; end +`ifdef FAIL_ASSERT_1 initial begin wait_order (b, a) nif[0] = '1; end +`endif initial begin wait_order (a, b) else welse[1] = '1; @@ -41,7 +43,7 @@ module t(/*AUTOARG*/); #10; -> c; #10; - // NOTE This hasn't been validated against other simulators + `checkd(wif[0], 1'b1); `checkd(nif[0], 1'b0); From 1debd0405be214d094475eb0ecec35905e68ed44 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 12 Mar 2023 10:46:02 -0400 Subject: [PATCH 028/155] Support complicated IEEE 'for' assignments. --- Changes | 2 +- src/verilog.y | 47 +++++++++++++++------------------- test_regress/t/t_for_assign.pl | 21 +++++++++++++++ test_regress/t/t_for_assign.v | 42 ++++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 27 deletions(-) create mode 100755 test_regress/t/t_for_assign.pl create mode 100644 test_regress/t/t_for_assign.v diff --git a/Changes b/Changes index 4c45d300d..a5a16263e 100644 --- a/Changes +++ b/Changes @@ -13,9 +13,9 @@ Verilator 5.009 devel **Minor:** +* Support complicated IEEE 'for' assignments. * Support $fopen as an expression. - Verilator 5.008 2023-03-04 ========================== diff --git a/src/verilog.y b/src/verilog.y index d44c466ba..20ea127fc 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -3503,9 +3503,8 @@ statement_item: // IEEE: statement_item if ($1 == uniq_UNIQUE0) newp->unique0Pragma(true); if ($1 == uniq_PRIORITY) newp->priorityPragma(true); } // - | finc_or_dec_expression ';' { $$ = $1; } // // IEEE: inc_or_dec_expression - // // Below under expr + | finc_or_dec_expression ';' { $$ = $1; } // // // IEEE: subroutine_call_statement // // IEEE says we then expect a function call @@ -3530,18 +3529,8 @@ statement_item: // IEEE: statement_item FileLine* const newfl = new FileLine{$$->fileline()}; newfl->warnOff(V3ErrorCode::IGNOREDRETURN, true); $$->fileline(newfl); } - // // Expr included here to resolve our not knowing what is a method call - // // Expr here must result in a subroutine_call - | task_subroutine_callNoMethod ';' { $$ = $1->makeStmt(); } - //UNSUP fexpr '.' array_methodNoRoot ';' { UNSUP } - | fexpr '.' task_subroutine_callNoMethod ';' { $$ = (new AstDot{$2, false, $1, $3})->makeStmt(); } - | system_t_call ';' { $$ = $1; } - //UNSUP fexprScope ';' { UNSUP } - // // Not here in IEEE; from class_constructor_declaration - // // Because we've joined class_constructor_declaration into generic functions - // // Way over-permissive; - // // IEEE: [ ySUPER '.' yNEW [ '(' list_of_arguments ')' ] ';' ] - | fexpr '.' class_new ';' { $$ = (new AstDot{$2, false, $1, $3})->makeStmt(); } + // + | task_subroutine_callNoSemi ';' { $$ = $1; } // | statementVerilatorPragmas { $$ = $1; } // @@ -3933,18 +3922,11 @@ for_step: // IEEE: for_step | for_step ',' for_step_assignment { $$ = addNextNull($1, $3); } ; -for_step_assignment: // ==IEEE: for_step_assignment - //UNSUP operator_assignment { $$ = $1; } - // - //UNSUP inc_or_dec_expression { $$ = $1; } - // // IEEE: subroutine_call - //UNSUP function_subroutine_callNoMethod { $$ = $1; } - // // method_call:array_method requires a '.' - //UNSUP expr '.' array_methodNoRoot { } - //UNSUP exprScope { $$ = $1; } - //UNSUP remove below - genvar_iteration { $$ = $1; } - //UNSUP remove above +for_step_assignment: // ==IEEE: for_step_assignment + foperator_assignment { $$ = $1; } + | finc_or_dec_expression { $$ = $1; } + // // IEEE: function_subroutine_call + | task_subroutine_callNoSemi { $$ = $1; } ; loop_variables: // IEEE: loop_variables @@ -3981,6 +3963,19 @@ funcRef: // IEEE: part of tf_call //UNSUP: idDotted is really just id to allow dotted method calls ; +task_subroutine_callNoSemi: // similar to IEEE task_subroutine_call but without ';' + // // Expr included here to resolve our not knowing what is a method call + // // Expr here must result in a subroutine_call + task_subroutine_callNoMethod { $$ = $1->makeStmt(); } + | fexpr '.' task_subroutine_callNoMethod { $$ = (new AstDot{$2, false, $1, $3})->makeStmt(); } + | system_t_call { $$ = $1; } + // // Not here in IEEE; from class_constructor_declaration + // // Because we've joined class_constructor_declaration into generic functions + // // Way over-permissive; + // // IEEE: [ ySUPER '.' yNEW [ '(' list_of_arguments ')' ] ';' ] + | fexpr '.' class_new { $$ = (new AstDot{$2, false, $1, $3})->makeStmt(); } + ; + task_subroutine_callNoMethod: // function_subroutine_callNoMethod (as task) // // IEEE: tf_call taskRef { $$ = $1; } diff --git a/test_regress/t/t_for_assign.pl b/test_regress/t/t_for_assign.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_for_assign.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 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); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_for_assign.v b/test_regress/t/t_for_assign.v new file mode 100644 index 000000000..61e0d6c85 --- /dev/null +++ b/test_regress/t/t_for_assign.v @@ -0,0 +1,42 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); + +module t (/*AUTOARG*/); + + int a, b; + int sum; + // Complicated assignment cases + + initial begin + sum = 0; + for (integer a=0; a<3; ) begin + a = a + 1; + sum = sum + a; + end + `checkd(sum, 6); + + // foperator_assignment + sum = 0; + for (integer a=0; a<3; a=a+1, sum += a) ; + `checkd(sum, 6); + + // inc_or_dec_expression + sum = 0; + for (integer a=0; a<3; a++, ++sum) ; + `checkd(sum, 3); + + // task_subroutine_call + sum = 0; + for (integer a=0; a<3; a++, sum += $clog2(a)) ; + `checkd(sum, 3); + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From ba953bfa94b96f24091706f8edcd3022b3eb6e18 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 12 Mar 2023 10:49:19 -0400 Subject: [PATCH 029/155] Commentary: Changes update --- Changes | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Changes b/Changes index a5a16263e..db8c7a161 100644 --- a/Changes +++ b/Changes @@ -13,8 +13,13 @@ Verilator 5.009 devel **Minor:** +* Add --public-depth to force public to a certain instance depth (#3952). [Andrew Nolte] +* Add --public-params flag (#3990). [Andrew Nolte] * Support complicated IEEE 'for' assignments. * Support $fopen as an expression. +* Fix UNDRIVEN warning seg fault (#3989). [Felix Neumärker] +* Fix symbol entries when inheriting classes (#3995) (#3996). [Krzysztof Bieganski, Antmicro Ltd] + Verilator 5.008 2023-03-04 ========================== From 39a5bce8a64ad295c2cbe9619da3c4a919a8a182 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 12 Mar 2023 14:11:11 -0400 Subject: [PATCH 030/155] Parse covergroup, still unsupported. --- src/verilog.l | 18 +- src/verilog.y | 501 ++++++++++++++------------ test_regress/t/t_covergroup_unsup.out | 380 +++++++++++++++++++ test_regress/t/t_covergroup_unsup.pl | 20 + test_regress/t/t_covergroup_unsup.v | 157 ++++++++ 5 files changed, 831 insertions(+), 245 deletions(-) create mode 100644 test_regress/t/t_covergroup_unsup.out create mode 100755 test_regress/t/t_covergroup_unsup.pl create mode 100644 test_regress/t/t_covergroup_unsup.v diff --git a/src/verilog.l b/src/verilog.l index 947e9ce03..8755dd3d8 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -498,8 +498,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "assume" { FL; return yASSUME; } "before" { FL; return yBEFORE; } "bind" { FL; return yBIND; } - "bins" { ERROR_RSVD_WORD("SystemVerilog 2005"); } - "binsof" { ERROR_RSVD_WORD("SystemVerilog 2005"); } + "bins" { FL; return yBINS; } + "binsof" { FL; return yBINSOF; } "bit" { FL; return yBIT; } "break" { FL; return yBREAK; } "byte" { FL; return yBYTE; } @@ -511,14 +511,14 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "context" { FL; return yCONTEXT; } "continue" { FL; return yCONTINUE; } "cover" { FL; return yCOVER; } - "covergroup" { ERROR_RSVD_WORD("SystemVerilog 2005"); } - "coverpoint" { ERROR_RSVD_WORD("SystemVerilog 2005"); } - "cross" { ERROR_RSVD_WORD("SystemVerilog 2005"); } + "covergroup" { FL; return yCOVERGROUP; } + "coverpoint" { FL; return yCOVERPOINT; } + "cross" { FL; return yCROSS; } "dist" { FL; return yDIST; } "do" { FL; return yDO; } "endclass" { FL; return yENDCLASS; } "endclocking" { FL; return yENDCLOCKING; } - "endgroup" { ERROR_RSVD_WORD("SystemVerilog 2005"); } + "endgroup" { FL; return yENDGROUP; } "endinterface" { FL; return yENDINTERFACE; } "endpackage" { FL; return yENDPACKAGE; } "endprogram" { FL; return yENDPROGRAM; } @@ -533,8 +533,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "first_match" { FL; return yFIRST_MATCH; } "forkjoin" { FL; return yFORKJOIN; } "iff" { FL; return yIFF; } - "ignore_bins" { ERROR_RSVD_WORD("SystemVerilog 2005"); } - "illegal_bins" { ERROR_RSVD_WORD("SystemVerilog 2005"); } + "ignore_bins" { FL; return yIGNORE_BINS; } + "illegal_bins" { FL; return yILLEGAL_BINS; } "import" { FL; return yIMPORT; } "inside" { FL; return yINSIDE; } "int" { FL; return yINT; } @@ -585,7 +585,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "virtual" { FL; return yVIRTUAL__LEX; } "void" { FL; return yVOID; } "wait_order" { FL; return yWAIT_ORDER; } - "wildcard" { ERROR_RSVD_WORD("SystemVerilog 2005"); } + "wildcard" { FL; return yWILDCARD; } "with" { FL; return yWITH__LEX; } "within" { FL; return yWITHIN; } } diff --git a/src/verilog.y b/src/verilog.y index 20ea127fc..1fdc118a7 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -550,8 +550,8 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yBEFORE "before" %token yBEGIN "begin" %token yBIND "bind" -//UNSUP %token yBINS "bins" -//UNSUP %token yBINSOF "binsof" +%token yBINS "bins" +%token yBINSOF "binsof" %token yBIT "bit" %token yBREAK "break" %token yBUF "buf" @@ -573,9 +573,9 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yCONTEXT "context" %token yCONTINUE "continue" %token yCOVER "cover" -//UNSUP %token yCOVERGROUP "covergroup" -//UNSUP %token yCOVERPOINT "coverpoint" -//UNSUP %token yCROSS "cross" +%token yCOVERGROUP "covergroup" +%token yCOVERPOINT "coverpoint" +%token yCROSS "cross" %token yDEASSIGN "deassign" %token yDEFAULT "default" %token yDEFPARAM "defparam" @@ -591,7 +591,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yENDCLOCKING "endclocking" %token yENDFUNCTION "endfunction" %token yENDGENERATE "endgenerate" -//UNSUP %token yENDGROUP "endgroup" +%token yENDGROUP "endgroup" %token yENDINTERFACE "endinterface" %token yENDMODULE "endmodule" %token yENDPACKAGE "endpackage" @@ -627,8 +627,8 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yHIGHZ1 "highz1" %token yIF "if" %token yIFF "iff" -//UNSUP %token yIGNORE_BINS "ignore_bins" -//UNSUP %token yILLEGAL_BINS "illegal_bins" +%token yIGNORE_BINS "ignore_bins" +%token yILLEGAL_BINS "illegal_bins" %token yIMPLEMENTS "implements" %token yIMPLIES "implies" %token yIMPORT "import" @@ -775,7 +775,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yWEAK0 "weak0" %token yWEAK1 "weak1" %token yWHILE "while" -//UNSUP %token yWILDCARD "wildcard" +%token yWILDCARD "wildcard" %token yWIRE "wire" %token yWITHIN "within" %token yWITH__BRA "with-then-[" @@ -1261,7 +1261,7 @@ package_or_generate_item_declaration: // ==IEEE: package_or_generate_i // // class_constructor_declaration is part of function_declaration // // local_parameter_declaration under parameter_declaration | parameter_declaration ';' { $$ = $1; } - //UNSUP covergroup_declaration { $$ = $1; } + | covergroup_declaration { $$ = $1; } | assertion_item_declaration { $$ = $1; } | ';' { $$ = nullptr; } ; @@ -1417,18 +1417,18 @@ parameter_port_listE: // IEEE: parameter_port_list + empty == paramete paramPortDeclOrArgList: // IEEE: list_of_param_assignments + { parameter_port_declaration } paramPortDeclOrArg { $$ = $1; } | paramPortDeclOrArgList ',' paramPortDeclOrArg { $$ = $1->addNext($3); } - | paramPortDeclOrArgList sigAttrScope {$$ = $1;} + | paramPortDeclOrArgList sigAttrScope { $$ = $1; } ; paramPortDeclOrArg: // IEEE: param_assignment + parameter_port_declaration // // We combine the two as we can't tell which follows a comma - paramPortDeclOrArgSub {$$ = $1;} + paramPortDeclOrArgSub { $$ = $1; } | vlTag { $$ = nullptr; } ; paramPortDeclOrArgSub: parameter_port_declarationFrontE param_assignment { $$ = $2; } | parameter_port_declarationTypeFrontE type_assignment { $$ = $2; } - | sigAttrScope paramPortDeclOrArgSub {$$ = $2; } + | sigAttrScope paramPortDeclOrArgSub { $$ = $2; } ; portsStarE: // IEEE: .* + list_of_ports + list_of_port_declarations + empty @@ -1683,7 +1683,7 @@ anonymous_program_item: // ==IEEE: anonymous_program_item task_declaration { $$ = $1; } | function_declaration { $$ = $1; } | class_declaration { $$ = $1; } - //UNSUP covergroup_declaration { $$ = $1; } + | covergroup_declaration { $$ = $1; } // // class_constructor_declaration is part of function_declaration | ';' { $$ = nullptr; } ; @@ -3629,21 +3629,6 @@ statementVerilatorPragmas: { $$ = new AstPragma{$1, VPragmaType::COVERAGE_BLOCK_OFF}; } ; -//UNSUPoperator_assignment: // IEEE: operator_assignment -//UNSUP ~f~exprLvalue '=' delay_or_event_controlE expr { } -//UNSUP | ~f~exprLvalue yP_PLUSEQ expr { } -//UNSUP | ~f~exprLvalue yP_MINUSEQ expr { } -//UNSUP | ~f~exprLvalue yP_TIMESEQ expr { } -//UNSUP | ~f~exprLvalue yP_DIVEQ expr { } -//UNSUP | ~f~exprLvalue yP_MODEQ expr { } -//UNSUP | ~f~exprLvalue yP_ANDEQ expr { } -//UNSUP | ~f~exprLvalue yP_OREQ expr { } -//UNSUP | ~f~exprLvalue yP_XOREQ expr { } -//UNSUP | ~f~exprLvalue yP_SLEFTEQ expr { } -//UNSUP | ~f~exprLvalue yP_SRIGHTEQ expr { } -//UNSUP | ~f~exprLvalue yP_SSRIGHTEQ expr { } -//UNSUP ; - foperator_assignment: // IEEE: operator_assignment (for first part of expression) fexprLvalue '=' delay_or_event_controlE expr { $$ = new AstAssign{$2, $1, $4, $3}; } // @@ -3797,10 +3782,11 @@ value_range: // ==IEEE: value_range | '[' expr ':' expr ']' { $$ = new AstInsideRange{$1, $2, $4}; } ; -//UNSUPcovergroup_value_range: // ==IEEE-2012: covergroup_value_range -//UNSUP cgexpr { $$ = $1; } -//UNSUP | '[' cgexpr ':' cgexpr ']' { } -//UNSUP ; +covergroup_value_range: // ==IEEE-2012: covergroup_value_range + cgexpr { $$ = $1; } + | '[' cgexpr ':' cgexpr ']' + { $$ = nullptr; BBUNSUP($1, "Unsupported: covergroup value range"); } + ; caseCondList: // IEEE: part of case_item exprTypeCompare { $$ = $1; } @@ -6225,239 +6211,281 @@ boolean_abbrev: // ==IEEE: boolean_abbrev //************************************************ // Covergroup -//UNSUPcovergroup_declaration: // ==IEEE: covergroup_declaration -//UNSUP covergroup_declarationFront coverage_eventE ';' coverage_spec_or_optionListE -//UNSUP yENDGROUP endLabelE -//UNSUP { PARSEP->endgroupCb($5, $5); -//UNSUP SYMP->popScope($$); } -//UNSUP | covergroup_declarationFront '(' tf_port_listE ')' coverage_eventE ';' coverage_spec_or_optionListE -//UNSUP yENDGROUP endLabelE -//UNSUP { PARSEP->endgroupCb($8, $8); -//UNSUP SYMP->popScope($$); } -//UNSUP ; +covergroup_declaration: // ==IEEE: covergroup_declaration + covergroup_declarationFront coverage_eventE ';' + /*cont*/ coverage_spec_or_optionListE + /*cont*/ yENDGROUP endLabelE + { $$ = $1; + SYMP->popScope($$); + GRAMMARP->endLabel($6, $1, $6); } + | covergroup_declarationFront '(' tf_port_listE ')' + /*cont*/ coverage_eventE ';' coverage_spec_or_optionListE + /*cont*/ yENDGROUP endLabelE + { $$ = $1; + SYMP->popScope($$); + GRAMMARP->endLabel($9, $1, $9); } + ; -//UNSUPcovergroup_declarationFront: // IEEE: part of covergroup_declaration -//UNSUP yCOVERGROUP idAny -//UNSUP { SYMP->pushNew($$); -//UNSUP PARSEP->covergroupCb($1, $1, $2); } -//UNSUP ; +covergroup_declarationFront: // IEEE: part of covergroup_declaration + yCOVERGROUP idAny + { $$ = new AstClass{$2, *$2}; + BBUNSUP($1, "Unsupported: covergroup"); + SYMP->pushNew($$); + v3Global.setHasClasses(); } + ; -//UNSUPcgexpr: // IEEE-2012: covergroup_expression, before that just expression -//UNSUP expr { $$ = $1; } -//UNSUP ; +cgexpr: // IEEE-2012: covergroup_expression, before that just expression + expr { $$ = $1; } + ; -//UNSUPcoverage_spec_or_optionListE: // IEEE: [{coverage_spec_or_option}] -//UNSUP /* empty */ { $$ = nullptr; } -//UNSUP | coverage_spec_or_optionList { $$ = $1; } -//UNSUP ; +coverage_spec_or_optionListE: // IEEE: [{coverage_spec_or_option}] + /* empty */ { $$ = nullptr; } + | coverage_spec_or_optionList { $$ = $1; } + ; -//UNSUPcoverage_spec_or_optionList: // IEEE: {coverage_spec_or_option} -//UNSUP coverage_spec_or_option { $$ = $1; } -//UNSUP | coverage_spec_or_optionList coverage_spec_or_option { $$ = addNextNull($1, $2); } -//UNSUP ; +coverage_spec_or_optionList: // IEEE: {coverage_spec_or_option} + coverage_spec_or_option { $$ = $1; } + | coverage_spec_or_optionList coverage_spec_or_option { $$ = addNextNull($1, $2); } + ; -//UNSUPcoverage_spec_or_option: // ==IEEE: coverage_spec_or_option -//UNSUP // // IEEE: coverage_spec -//UNSUP cover_point { $$ = $1; } -//UNSUP | cover_cross { $$ = $1; } -//UNSUP | coverage_option ';' { $$ = $1; } -//UNSUP | error { $$ = nullptr; } -//UNSUP ; +coverage_spec_or_option: // ==IEEE: coverage_spec_or_option + // // IEEE: coverage_spec + cover_point { $$ = $1; } + | cover_cross { $$ = $1; } + | coverage_option ';' { $$ = $1; } + | error { $$ = nullptr; } + ; -//UNSUPcoverage_option: // ==IEEE: coverage_option -//UNSUP // // option/type_option aren't really keywords -//UNSUP id/*yOPTION | yTYPE_OPTION*/ '.' idAny/*member_identifier*/ '=' expr { } -//UNSUP ; +coverage_option: // ==IEEE: coverage_option + // // option/type_option aren't really keywords + id/*yOPTION | yTYPE_OPTION*/ '.' idAny/*member_identifier*/ '=' expr + { // TODO: check that 'id' is 'option' or 'type_option' + $$ = nullptr; BBUNSUP($1, "Unsupported: coverage option"); } + ; -//UNSUPcover_point: // ==IEEE: cover_point -//UNSUP /**/ yCOVERPOINT expr iffE bins_or_empty { } -//UNSUP // // IEEE-2012: class_scope before an ID -//UNSUP | /**/ /**/ /**/ id ':' yCOVERPOINT expr iffE bins_or_empty { } -//UNSUP | class_scope_id ':' yCOVERPOINT expr iffE bins_or_empty { } -//UNSUP | class_scope_id id data_type id ':' yCOVERPOINT expr iffE bins_or_empty { } -//UNSUP | class_scope_id id /**/ id ':' yCOVERPOINT expr iffE bins_or_empty { } -//UNSUP | /**/ id /**/ id ':' yCOVERPOINT expr iffE bins_or_empty { } -//UNSUP // // IEEE-2012: -//UNSUP | bins_or_empty { $$ = $1; } -//UNSUP; +cover_point: // ==IEEE: cover_point + // // [ [ data_type_or_implicit ] cover_point_identifier ':' ] yCOVERPOINT + yCOVERPOINT expr iffE bins_or_empty + { $$ = nullptr; BBUNSUP($1, "Unsupported: cover point"); } + // // IEEE-2012: class_scope before an ID + | id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty + { $$ = nullptr; BBUNSUP($3, "Unsupported: cover point"); } + // // data_type_or_implicit expansion + | data_type id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty + { $$ = nullptr; BBUNSUP($4, "Unsupported: cover point"); } + | yVAR data_type id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty + { $$ = nullptr; BBUNSUP($5, "Unsupported: cover point"); } + | yVAR implicit_typeE id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty + { $$ = nullptr; BBUNSUP($5, "Unsupported: cover point"); } + | signingE rangeList id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty + { $$ = nullptr; BBUNSUP($5, "Unsupported: cover point"); } + | signing id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty + { $$ = nullptr; BBUNSUP($4, "Unsupported: cover point"); } + // // IEEE-2012: + | bins_or_empty { $$ = $1; } + ; -//UNSUPiffE: // IEEE: part of cover_point, others -//UNSUP /* empty */ { $$ = nullptr; } -//UNSUP | yIFF '(' expr ')' { } -//UNSUP ; +iffE: // IEEE: part of cover_point, others + /* empty */ { $$ = nullptr; } + | yIFF '(' expr ')' + { $$ = nullptr; BBUNSUP($1, "Unsupported: cover 'iff'"); } + ; -//UNSUPbins_or_empty: // ==IEEE: bins_or_empty -//UNSUP '{' bins_or_optionsList '}' { $$ = $2; } -//UNSUP | '{' '}' { $$ = nullptr; } -//UNSUP | ';' { $$ = nullptr; } -//UNSUP ; +bins_or_empty: // ==IEEE: bins_or_empty + '{' bins_or_optionsList '}' { $$ = $2; } + | '{' '}' { $$ = nullptr; } + | ';' { $$ = nullptr; } + ; -//UNSUPbins_or_optionsList: // IEEE: { bins_or_options ';' } -//UNSUP bins_or_options ';' { $$ = $1; } -//UNSUP | bins_or_optionsList bins_or_options ';' { $$ = addNextNull($1, $2); } -//UNSUP ; +bins_or_optionsList: // IEEE: { bins_or_options ';' } + bins_or_options ';' { $$ = $1; } + | bins_or_optionsList bins_or_options ';' { $$ = addNextNull($1, $2); } + ; -//UNSUPbins_or_options: // ==IEEE: bins_or_options -//UNSUP // // Superset of IEEE - we allow []'s in more places -//UNSUP coverage_option { $$ = $1; } -//UNSUP // // Can't use wildcardE as results in conflicts -//UNSUP | /**/ bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' iffE { } -//UNSUP | yWILDCARD bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' iffE { } -//UNSUP | /**/ bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' yWITH__CUR '{' cgexpr ')' iffE { } -//UNSUP | yWILDCARD bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' yWITH__CUR '{' cgexpr ')' iffE { } -//UNSUP // -//UNSUP // // cgexpr part of trans_list -//UNSUP // -//UNSUP | /**/ bins_keyword id/*bin_identifier*/ bins_orBraE '=' trans_list iffE { } -//UNSUP | yWILDCARD bins_keyword id/*bin_identifier*/ bins_orBraE '=' trans_list iffE { } -//UNSUP // -//UNSUP | bins_keyword id/*bin_identifier*/ bins_orBraE '=' yDEFAULT iffE { } -//UNSUP // -//UNSUP | bins_keyword id/*bin_identifier*/ bins_orBraE '=' yDEFAULT ySEQUENCE iffE { } -//UNSUP ; +bins_or_options: // ==IEEE: bins_or_options + // // Superset of IEEE - we allow []'s in more places + coverage_option { $$ = $1; } + // // Can't use wildcardE as results in conflicts + | bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' iffE + { $$ = nullptr; BBUNSUP($4, "Unsupported: cover bin specification"); } + | bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' yWITH__CUR '{' cgexpr '}' iffE + { $$ = nullptr; BBUNSUP($8, "Unsupported: cover bin 'with' specification"); } + | yWILDCARD bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' iffE + { $$ = nullptr; BBUNSUP($5, "Unsupported: cover bin 'wildcard' specification"); } + | yWILDCARD bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' yWITH__CUR '{' cgexpr '}' iffE + { $$ = nullptr; BBUNSUP($9, "Unsupported: cover bin 'wildcard' 'with' specification"); } + // + // // cgexpr part of trans_list + | bins_keyword id/*bin_identifier*/ bins_orBraE '=' trans_list iffE + { $$ = nullptr; BBUNSUP($4, "Unsupported: cover bin trans list"); } + | yWILDCARD bins_keyword id/*bin_identifier*/ bins_orBraE '=' trans_list iffE + { $$ = nullptr; BBUNSUP($1, "Unsupported: cover bin 'wildcard' trans list"); } + // + | bins_keyword id/*bin_identifier*/ bins_orBraE '=' yDEFAULT iffE + { $$ = nullptr; BBUNSUP($5, "Unsupported: cover bin 'default'"); } + | bins_keyword id/*bin_identifier*/ bins_orBraE '=' yDEFAULT ySEQUENCE iffE + { $$ = nullptr; BBUNSUP($6, "Unsupported: cover bin 'default' 'sequence'"); } + ; -//UNSUPbins_orBraE: // IEEE: part of bins_or_options: -//UNSUP /* empty */ { $$ = nullptr; } -//UNSUP | '[' ']' { } -//UNSUP | '[' cgexpr ']' { } -//UNSUP ; +bins_orBraE: // IEEE: part of bins_or_options: + /* empty */ { $$ = nullptr; } + | '[' ']' { $$ = nullptr; /*UNSUP*/ } + | '[' cgexpr ']' { $$ = nullptr; /*UNSUP*/ } + ; -//UNSUPbins_keyword: // ==IEEE: bins_keyword -//UNSUP yBINS { } -//UNSUP | yILLEGAL_BINS { } -//UNSUP | yIGNORE_BINS { } -//UNSUP ; +bins_keyword: // ==IEEE: bins_keyword + yBINS { $$ = $1; /*UNSUP*/ } + | yILLEGAL_BINS { $$ = $1; /*UNSUP*/ } + | yIGNORE_BINS { $$ = $1; /*UNSUP*/ } + ; -//UNSUPcovergroup_range_list: // ==IEEE: covergroup_range_list -//UNSUP covergroup_value_range { $$ = $1; } -//UNSUP | covergroup_range_list ',' covergroup_value_range { $$ = addNextNull($1, $3); } -//UNSUP ; +trans_list: // ==IEEE: trans_list + '(' trans_set ')' { $$ = $2; } + | trans_list ',' '(' trans_set ')' { $$ = addNextNull($1, $4); } + ; -//UNSUPtrans_list: // ==IEEE: trans_list -//UNSUP '(' trans_set ')' { $$ = $2; } -//UNSUP | trans_list ',' '(' trans_set ')' { } -//UNSUP ; +trans_set: // ==IEEE: trans_set + trans_range_list { $$ = $1; } + // // Note the { => } in the grammer, this is really a list + | trans_set yP_EQGT trans_range_list + { $$ = $1; BBUNSUP($2, "Unsupported: cover trans set '=>'"); } + ; -//UNSUPtrans_set: // ==IEEE: trans_set -//UNSUP trans_range_list { $$ = $1; } -//UNSUP // // Note the { => } in the grammer, this is really a list -//UNSUP | trans_set yP_EQGT trans_range_list { } -//UNSUP ; +trans_range_list: // ==IEEE: trans_range_list + trans_item { $$ = $1; } + | trans_item yP_BRASTAR cgexpr ']' + { $$ = nullptr; BBUNSUP($2, "Unsupported: cover '[*'"); } + | trans_item yP_BRASTAR cgexpr ':' cgexpr ']' + { $$ = nullptr; BBUNSUP($2, "Unsupported: cover '[*'"); } + | trans_item yP_BRAMINUSGT cgexpr ']' + { $$ = nullptr; BBUNSUP($2, "Unsupported: cover '[->'"); } + | trans_item yP_BRAMINUSGT cgexpr ':' cgexpr ']' + { $$ = nullptr; BBUNSUP($2, "Unsupported: cover '[->'"); } + | trans_item yP_BRAEQ cgexpr ']' + { $$ = nullptr; BBUNSUP($2, "Unsupported: cover '[='"); } + | trans_item yP_BRAEQ cgexpr ':' cgexpr ']' + { $$ = nullptr; BBUNSUP($2, "Unsupported: cover '[='"); } + ; -//UNSUPtrans_range_list: // ==IEEE: trans_range_list -//UNSUP trans_item { $$ = $1; } -//UNSUP | trans_item yP_BRASTAR repeat_range ']' { } -//UNSUP | trans_item yP_BRAMINUSGT repeat_range ']' { } -//UNSUP | trans_item yP_BRAEQ repeat_range ']' { } -//UNSUP ; +trans_item: // ==IEEE: range_list + covergroup_range_list { $$ = $1; } + ; -//UNSUPtrans_item: // ==IEEE: range_list -//UNSUP covergroup_range_list { $$ = $1; } -//UNSUP ; +covergroup_range_list: // ==IEEE: covergroup_range_list + covergroup_value_range { $$ = $1; } + | covergroup_range_list ',' covergroup_value_range { $$ = addNextNull($1, $3); } + ; -//UNSUPrepeat_range: // ==IEEE: repeat_range -//UNSUP cgexpr { $$ = $1; } -//UNSUP | cgexpr ':' cgexpr { $$ = addNextNull($1, $3); } -//UNSUP ; -//UNSUPcover_cross: // ==IEEE: cover_cross -//UNSUP id/*cover_point_identifier*/ ':' yCROSS list_of_cross_items iffE cross_body { } -//UNSUP | /**/ yCROSS list_of_cross_items iffE cross_body { } -//UNSUP ; +cover_cross: // ==IEEE: cover_cross + id/*cover_point_identifier*/ ':' yCROSS list_of_cross_items iffE cross_body + { $$ = nullptr; BBUNSUP($3, "Unsupported: cross"); } + | yCROSS list_of_cross_items iffE cross_body + { $$ = nullptr; BBUNSUP($1, "Unsupported: cross"); } + ; -//UNSUPlist_of_cross_items: // ==IEEE: list_of_cross_items -//UNSUP cross_item ',' cross_item { $$ = addNextNull($1, $3); } -//UNSUP | cross_item ',' cross_item ',' cross_itemList -//UNSUP { $$ = addNextNull(addNextNull($1, $3), $5); } -//UNSUP ; +list_of_cross_items: // ==IEEE: list_of_cross_items + cross_item ',' cross_item { $$ = addNextNull($1, $3); } + | cross_item ',' cross_item ',' cross_itemList + { $$ = addNextNull(addNextNull($1, $3), $5); } + ; -//UNSUPcross_itemList: // IEEE: part of list_of_cross_items -//UNSUP cross_item { $$ = nullptr; } -//UNSUP | cross_itemList ',' cross_item { $$ = addNextNull($1, $3); } -//UNSUP ; +cross_itemList: // IEEE: part of list_of_cross_items + cross_item { $$ = $1; } + | cross_itemList ',' cross_item { $$ = addNextNull($1, $3); } + ; -//UNSUPcross_item: // ==IEEE: cross_item -//UNSUP idAny/*cover_point_identifier or variable_identifier*/ { $$ = $1; } -//UNSUP ; +cross_item: // ==IEEE: cross_item + idAny/*cover_point_identifier or variable_identifier*/ { $$ = nullptr; /*UNSUP*/ } + ; -//UNSUPcross_body: // ==IEEE: cross_body -//UNSUP '{' '}' { $$ = nullptr; } -//UNSUP // // IEEE-2012: No semicolon here, mistake in spec -//UNSUP | '{' cross_body_itemSemiList '}' { $$ = $1; } -//UNSUP | ';' { $$ = nullptr; } -//UNSUP ; +cross_body: // ==IEEE: cross_body + '{' '}' { $$ = nullptr; } + // // IEEE-2012: No semicolon here, mistake in spec + | '{' cross_body_itemSemiList '}' { $$ = $2; } + | ';' { $$ = nullptr; } + ; -//UNSUPcross_body_itemSemiList: // IEEE: part of cross_body -//UNSUP cross_body_item ';' { $$ = $1; } -//UNSUP | cross_body_itemSemiList cross_body_item ';' { $$ = addNextNull($1, $2); } -//UNSUP ; +cross_body_itemSemiList: // IEEE: part of cross_body + cross_body_item ';' { $$ = $1; } + | cross_body_itemSemiList cross_body_item ';' { $$ = addNextNull($1, $2); } + ; -//UNSUPcross_body_item: // ==IEEE: cross_body_item -//UNSUP // // IEEE: our semicolon is in the list -//UNSUP bins_selection_or_option { $$ = $1; } -//UNSUP | function_declaration { $$ = $1; } -//UNSUP ; +cross_body_item: // ==IEEE: cross_body_item + // // IEEE: our semicolon is in the list + // // IEEE: bins_selection_or_option + coverage_option { $$ = $1; } + // // IEEE: bins_selection + | function_declaration + { $$ = $1; BBUNSUP($1->fileline(), "Unsupported: coverage cross 'function' declaration"); } + | bins_keyword idAny/*new-bin_identifier*/ '=' select_expression iffE + { $$ = nullptr; BBUNSUP($1, "Unsupported: coverage cross bin"); } + ; -//UNSUPbins_selection_or_option: // ==IEEE: bins_selection_or_option -//UNSUP coverage_option { $$ = $1; } -//UNSUP | bins_selection { $$ = $1; } -//UNSUP ; +select_expression: // ==IEEE: select_expression + // // IEEE: select_condition expanded here + yBINSOF '(' bins_expression ')' + { $$ = nullptr; BBUNSUP($1, "Unsupported: coverage select expression 'binsof'"); } + | '!' yBINSOF '(' bins_expression ')' + { $$ = nullptr; BBUNSUP($1, "Unsupported: coverage select expression 'binsof'"); } + | yBINSOF '(' bins_expression ')' yINTERSECT '{' covergroup_range_list '}' + { $$ = nullptr; BBUNSUP($5, "Unsupported: coverage select expression 'intersect'"); } + | '!' yBINSOF '(' bins_expression ')' yINTERSECT '{' covergroup_range_list '}' { } + { $$ = nullptr; BBUNSUP($5, "Unsupported: coverage select expression 'intersect'"); } + | yWITH__PAREN '(' cgexpr ')' + { $$ = nullptr; BBUNSUP($1, "Unsupported: coverage select expression with"); } + | '!' yWITH__PAREN '(' cgexpr ')' + { $$ = nullptr; BBUNSUP($1, "Unsupported: coverage select expression with"); } + // // IEEE-2012: Need clarification as to precedence + //UNSUP yWITH__PAREN '(' cgexpr ')' yMATCHES cgexpr { } + // // IEEE-2012: Need clarification as to precedence + //UNSUP '!' yWITH__PAREN '(' cgexpr ')' yMATCHES cgexpr { } + // + | '(' select_expression ')' { $$ = $2; } + | select_expression yP_ANDAND select_expression + { $$ = nullptr; BBUNSUP($2, "Unsupported: coverage select expression '&&'"); } + | select_expression yP_OROR select_expression + { $$ = nullptr; BBUNSUP($2, "Unsupported: coverage select expression '||'"); } + // // IEEE-2012: cross_identifier + // // Part of covergroup_expression - generic identifier + // // IEEE-2012: Need clarification as to precedence + //UNSUP cgexpr { $$ = nullptr; BBUNSUP($1, "Unsupported: coverage select expression"); } + // + // // Need precedence fix + //UNSUP cgexpr yMATCHES cgexpr {..} + ; -//UNSUPbins_selection: // ==IEEE: bins_selection -//UNSUP bins_keyword idAny/*new-bin_identifier*/ '=' select_expression iffE { } -//UNSUP ; +bins_expression: // ==IEEE: bins_expression + // // "cover_point_identifier" and "variable_identifier" look identical + id/*variable_identifier or cover_point_identifier*/ { $$ = nullptr; /*UNSUP*/ } + | id/*cover_point_identifier*/ '.' idAny/*bins_identifier*/ { $$ = nullptr; /*UNSUP*/ } + ; -//UNSUPselect_expression: // ==IEEE: select_expression -//UNSUP // // IEEE: select_condition expanded here -//UNSUP yBINSOF '(' bins_expression ')' { } -//UNSUP | yBINSOF '(' bins_expression ')' yINTERSECT '{' covergroup_range_list '}' { } -//UNSUP | yWITH__PAREN '(' cgexpr ')' { } -//UNSUP // // IEEE-2012: Need clarification as to precedence -//UNSUP //UNSUP yWITH__PAREN '(' cgexpr ')' yMATCHES cgexpr { } -//UNSUP | '!' yBINSOF '(' bins_expression ')' { } -//UNSUP | '!' yBINSOF '(' bins_expression ')' yINTERSECT '{' covergroup_range_list '}' { } -//UNSUP | '!' yWITH__PAREN '(' cgexpr ')' { } -//UNSUP // // IEEE-2012: Need clarification as to precedence -//UNSUP //UNSUP '!' yWITH__PAREN '(' cgexpr ')' yMATCHES cgexpr { } -//UNSUP | select_expression yP_ANDAND select_expression { } -//UNSUP | select_expression yP_OROR select_expression { } -//UNSUP | '(' select_expression ')' { $$ = $2; } -//UNSUP // // IEEE-2012: cross_identifier -//UNSUP // // Part of covergroup_expression - generic identifier -//UNSUP // // IEEE-2012: Need clarification as to precedence -//UNSUP //UNSUP covergroup_expression [ yMATCHES covergroup_expression ] -//UNSUP ; +coverage_eventE: // IEEE: [ coverage_event ] + /* empty */ { $$ = nullptr; } + | clocking_event + { $$ = nullptr; BBUNSUP($1, "Unsupported: coverage clocking event"); } + | yWITH__ETC yFUNCTION idAny/*"sample"*/ '(' tf_port_listE ')' + { $$ = nullptr; BBUNSUP($1, "Unsupported: coverage 'with' 'function'"); } + | yP_ATAT '(' block_event_expression ')' + { $$ = nullptr; BBUNSUP($1, "Unsupported: coverage '@@' events"); } + ; -//UNSUPbins_expression: // ==IEEE: bins_expression -//UNSUP // // "cover_point_identifier" and "variable_identifier" look identical -//UNSUP id/*variable_identifier or cover_point_identifier*/ { $$ = $1; } -//UNSUP | id/*cover_point_identifier*/ '.' idAny/*bins_identifier*/ { } -//UNSUP ; +block_event_expression: // ==IEEE: block_event_expression + block_event_expressionTerm { $$ = nullptr; /*UNSUP @@*/ } + | block_event_expression yOR block_event_expressionTerm { $$ = nullptr; /*UNSUP @@*/ } + ; -//UNSUPcoverage_eventE: // IEEE: [ coverage_event ] -//UNSUP /* empty */ { $$ = nullptr; } -//UNSUP | clocking_event { $$ = $1; } -//UNSUP | yWITH__ETC function idAny/*"sample"*/ '(' tf_port_listE ')' { } -//UNSUP | yP_ATAT '(' block_event_expression ')' { } -//UNSUP ; +block_event_expressionTerm: // IEEE: part of block_event_expression + yBEGIN hierarchical_btf_identifier { $$ = nullptr; /*UNSUP @@*/ } + | yEND hierarchical_btf_identifier { $$ = nullptr; /*UNSUP @@*/ } + ; -//UNSUPblock_event_expression: // ==IEEE: block_event_expression -//UNSUP block_event_expressionTerm { $$ = $1; } -//UNSUP | block_event_expression yOR block_event_expressionTerm { } -//UNSUP ; - -//UNSUPblock_event_expressionTerm: // IEEE: part of block_event_expression -//UNSUP yBEGIN hierarchical_btf_identifier { } -//UNSUP | yEND hierarchical_btf_identifier { } -//UNSUP ; - -//UNSUPhierarchical_btf_identifier: // ==IEEE: hierarchical_btf_identifier -//UNSUP // // hierarchical_tf_identifier + hierarchical_block_identifier -//UNSUP hierarchical_identifier/*tf_or_block*/ { $$ = $1; } -//UNSUP // // method_identifier -//UNSUP | hierarchical_identifier class_scope_id { } -//UNSUP | hierarchical_identifier id { } -//UNSUP ; +hierarchical_btf_identifier: // ==IEEE: hierarchical_btf_identifier + // // hierarchical_tf_identifier + hierarchical_block_identifier + // // method_identifier + packageClassScopeE idAny { $$ = nullptr; /*UNSUP*/ } + ; //********************************************************************** // Randsequence @@ -6638,7 +6666,7 @@ checker_or_generate_item_declaration: // ==IEEE: checker_or_generate_ite | checker_declaration { $$ = nullptr; BBUNSUP($1, "Unsupported: recursive checker"); } | assertion_item_declaration { $$ = $1; } - //UNSUP covergroup_declaration { $$ = $1; } + | covergroup_declaration { $$ = $1; } // // IEEE deprecated: overload_declaration | genvar_declaration { $$ = $1; } | clocking_declaration { $$ = $1; } @@ -6879,7 +6907,8 @@ class_item: // ==IEEE: class_item | class_declaration { $$ = nullptr; BBUNSUP($1, "Unsupported: class within class"); } | timeunits_declaration { $$ = $1; } - //UNSUP covergroup_declaration { $$ = $1; } + | covergroup_declaration + { $$ = nullptr; BBUNSUP($1, "Unsupported: covergroup within class"); } // // local_parameter_declaration under parameter_declaration | parameter_declaration ';' { $$ = $1; } | ';' { $$ = nullptr; } diff --git a/test_regress/t/t_covergroup_unsup.out b/test_regress/t/t_covergroup_unsup.out new file mode 100644 index 000000000..6a6747e11 --- /dev/null +++ b/test_regress/t/t_covergroup_unsup.out @@ -0,0 +1,380 @@ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:25:4: Unsupported: covergroup + 25 | covergroup cg_empty; + | ^~~~~~~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:28:4: Unsupported: covergroup + 28 | covergroup cg_opt; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:29:7: Unsupported: coverage option + 29 | type_option.weight = 1; + | ^~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:30:7: Unsupported: coverage option + 30 | type_option.goal = 99; + | ^~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:31:7: Unsupported: coverage option + 31 | type_option.comment = "type_option_comment"; + | ^~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:32:7: Unsupported: coverage option + 32 | type_option.strobe = 0; + | ^~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:33:7: Unsupported: coverage option + 33 | type_option.merge_instances = 1; + | ^~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:34:7: Unsupported: coverage option + 34 | type_option.distribuge_first = 1; + | ^~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:35:7: Unsupported: coverage option + 35 | option.name = "the_name"; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:36:7: Unsupported: coverage option + 36 | option.weight = 1; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:37:7: Unsupported: coverage option + 37 | option.goal = 98; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:38:7: Unsupported: coverage option + 38 | option.comment = "option_comment"; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:39:7: Unsupported: coverage option + 39 | option.at_least = 20; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:40:7: Unsupported: coverage option + 40 | option.auto_bin_max = 10; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:41:7: Unsupported: coverage option + 41 | option.cross_num_print_missing = 2; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:42:7: Unsupported: coverage option + 42 | option.detect_overlap = 1; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:43:7: Unsupported: coverage option + 43 | option.per_instance = 1; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:44:7: Unsupported: coverage option + 44 | option.get_inst_coverage = 1; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:47:4: Unsupported: covergroup + 47 | covergroup cg_clockingevent() @(posedge clk); + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:47:34: Unsupported: coverage clocking event + 47 | covergroup cg_clockingevent() @(posedge clk); + | ^ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:49:4: Unsupported: covergroup + 49 | covergroup cg_withfunction() with function sample (a); + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:49:33: Unsupported: coverage 'with' 'function' + 49 | covergroup cg_withfunction() with function sample (a); + | ^~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:51:4: Unsupported: covergroup + 51 | covergroup cg_atat() @@ (begin funca or end funcb); + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:51:25: Unsupported: coverage '@@' events + 51 | covergroup cg_atat() @@ (begin funca or end funcb); + | ^~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:53:4: Unsupported: covergroup + 53 | covergroup cg_bracket; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:56:4: Unsupported: covergroup + 56 | covergroup cg_bracket; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:57:9: Unsupported: coverage option + 57 | { option.name = "option"; } + | ^~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:59:4: Unsupported: covergroup + 59 | covergroup cg_cp; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:60:7: Unsupported: cover point + 60 | coverpoint a; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:62:4: Unsupported: covergroup + 62 | covergroup cg_cp_iff; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:63:20: Unsupported: cover 'iff' + 63 | coverpoint a iff (b); + | ^~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:63:7: Unsupported: cover point + 63 | coverpoint a iff (b); + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:65:4: Unsupported: covergroup + 65 | covergroup cg_id_cp_iff; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:66:24: Unsupported: cover 'iff' + 66 | id: coverpoint a iff (b); + | ^~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:66:11: Unsupported: cover point + 66 | id: coverpoint a iff (b); + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:68:4: Unsupported: covergroup + 68 | covergroup cg_id_cp_id1; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:69:28: Unsupported: cover 'iff' + 69 | int id: coverpoint a iff (b); + | ^~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:69:15: Unsupported: cover point + 69 | int id: coverpoint a iff (b); + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:71:4: Unsupported: covergroup + 71 | covergroup cg_id_cp_id2; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:72:32: Unsupported: cover 'iff' + 72 | var int id: coverpoint a iff (b); + | ^~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:72:19: Unsupported: cover point + 72 | var int id: coverpoint a iff (b); + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:74:4: Unsupported: covergroup + 74 | covergroup cg_id_cp_id3; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:75:34: Unsupported: cover 'iff' + 75 | var [3:0] id: coverpoint a iff (b); + | ^~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:75:21: Unsupported: cover point + 75 | var [3:0] id: coverpoint a iff (b); + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:77:4: Unsupported: covergroup + 77 | covergroup cg_id_cp_id4; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:78:30: Unsupported: cover 'iff' + 78 | [3:0] id: coverpoint a iff (b); + | ^~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:78:17: Unsupported: cover point + 78 | [3:0] id: coverpoint a iff (b); + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:80:4: Unsupported: covergroup + 80 | covergroup cg_id_cp_id5; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:81:31: Unsupported: cover 'iff' + 81 | signed id: coverpoint a iff (b); + | ^~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:81:18: Unsupported: cover point + 81 | signed id: coverpoint a iff (b); + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:84:4: Unsupported: covergroup + 84 | covergroup cg_cross; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:85:18: Unsupported: cover 'iff' + 85 | cross a, b iff (!rst); + | ^~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:85:7: Unsupported: cross + 85 | cross a, b iff (!rst); + | ^~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:87:4: Unsupported: covergroup + 87 | covergroup cg_cross2; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:88:18: Unsupported: cover 'iff' + 88 | cross a, b iff (!rst) {} + | ^~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:88:7: Unsupported: cross + 88 | cross a, b iff (!rst) {} + | ^~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:90:4: Unsupported: covergroup + 90 | covergroup cg_cross3; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:91:20: Unsupported: coverage option + 91 | cross a, b { option.comment = "cross"; option.weight = 12; } + | ^~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:91:46: Unsupported: coverage option + 91 | cross a, b { option.comment = "cross"; option.weight = 12; } + | ^~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:91:7: Unsupported: cross + 91 | cross a, b { option.comment = "cross"; option.weight = 12; } + | ^~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:93:4: Unsupported: covergroup + 93 | covergroup cg_cross3; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:94:34: Unsupported: coverage cross 'function' declaration + 94 | cross a, b { function void crossfunc; endfunction; } + | ^~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:94:7: Unsupported: cross + 94 | cross a, b { function void crossfunc; endfunction; } + | ^~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:96:4: Unsupported: covergroup + 96 | covergroup cg_cross_id; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:97:28: Unsupported: cover 'iff' + 97 | my_cg_id: cross a, b iff (!rst); + | ^~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:97:17: Unsupported: cross + 97 | my_cg_id: cross a, b iff (!rst); + | ^~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:100:4: Unsupported: covergroup + 100 | covergroup cg_binsoroptions_bk1; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:102:17: Unsupported: cover bin specification + 102 | { bins ba = {a}; } + | ^ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:103:24: Unsupported: cover 'iff' + 103 | { bins bar = {a} iff (!rst); } + | ^~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:103:18: Unsupported: cover bin specification + 103 | { bins bar = {a} iff (!rst); } + | ^ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:104:26: Unsupported: cover bin specification + 104 | { illegal_bins ila = {a}; } + | ^ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:105:25: Unsupported: cover bin specification + 105 | { ignore_bins iga = {a}; } + | ^ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:107:19: Unsupported: cover bin specification + 107 | { bins ba[] = {a}; } + | ^ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:108:20: Unsupported: cover bin specification + 108 | { bins ba[2] = {a}; } + | ^ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:110:23: Unsupported: cover bin 'with' specification + 110 | { bins ba = {a} with { b }; } + | ^~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:112:27: Unsupported: cover bin 'wildcard' specification + 112 | { wildcard bins bwa = {a}; } + | ^ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:113:34: Unsupported: cover bin 'wildcard' 'with' specification + 113 | { wildcard bins bwaw = {a} with { b }; } + | ^~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:115:20: Unsupported: cover bin 'default' + 115 | { bins def = default; } + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:116:29: Unsupported: cover bin 'default' 'sequence' + 116 | { bins defs = default sequence; } + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:118:18: Unsupported: cover bin trans list + 118 | { bins bts = ( 1, 2 ); } + | ^ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:119:9: Unsupported: cover bin 'wildcard' trans list + 119 | { wildcard bins wbts = ( 1, 2 ); } + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:120:33: Unsupported: covergroup value range + 120 | { bins bts2 = ( 2, 3 ), ( [5:6] ) ; } + | ^ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:120:19: Unsupported: cover bin trans list + 120 | { bins bts2 = ( 2, 3 ), ( [5:6] ) ; } + | ^ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:122:27: Unsupported: cover trans set '=>' + 122 | { bins bts2 = ( 1,5 => 6,7 ) ; } + | ^~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:122:19: Unsupported: cover bin trans list + 122 | { bins bts2 = ( 1,5 => 6,7 ) ; } + | ^ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:123:25: Unsupported: cover '[*' + 123 | { bins bts2 = ( 3 [*5] ) ; } + | ^~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:123:19: Unsupported: cover bin trans list + 123 | { bins bts2 = ( 3 [*5] ) ; } + | ^ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:124:25: Unsupported: cover '[*' + 124 | { bins bts2 = ( 3 [*5:6] ) ; } + | ^~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:124:19: Unsupported: cover bin trans list + 124 | { bins bts2 = ( 3 [*5:6] ) ; } + | ^ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:125:25: Unsupported: cover '[->' + 125 | { bins bts2 = ( 3 [->5] ) ; } + | ^~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:125:19: Unsupported: cover bin trans list + 125 | { bins bts2 = ( 3 [->5] ) ; } + | ^ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:126:25: Unsupported: cover '[->' + 126 | { bins bts2 = ( 3 [->5:6] ) ; } + | ^~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:126:19: Unsupported: cover bin trans list + 126 | { bins bts2 = ( 3 [->5:6] ) ; } + | ^ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:127:25: Unsupported: cover '[=' + 127 | { bins bts2 = ( 3 [=5] ) ; } + | ^~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:127:19: Unsupported: cover bin trans list + 127 | { bins bts2 = ( 3 [=5] ) ; } + | ^ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:128:25: Unsupported: cover '[=' + 128 | { bins bts2 = ( 3 [=5:6] ) ; } + | ^~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:128:19: Unsupported: cover bin trans list + 128 | { bins bts2 = ( 3 [=5:6] ) ; } + | ^ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:132:4: Unsupported: covergroup + 132 | covergroup cg_cross_bins; + | ^~~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:134:23: Unsupported: coverage select expression 'binsof' + 134 | bins bin_a = binsof(a); + | ^~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:134:10: Unsupported: coverage cross bin + 134 | bins bin_a = binsof(a); + | ^~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:135:24: Unsupported: coverage select expression 'binsof' + 135 | bins bin_ai = binsof(a) iff (!rst); + | ^~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:135:34: Unsupported: cover 'iff' + 135 | bins bin_ai = binsof(a) iff (!rst); + | ^~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:135:10: Unsupported: coverage cross bin + 135 | bins bin_ai = binsof(a) iff (!rst); + | ^~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:136:23: Unsupported: coverage select expression 'binsof' + 136 | bins bin_c = binsof(cp.x); + | ^~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:136:10: Unsupported: coverage cross bin + 136 | bins bin_c = binsof(cp.x); + | ^~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:137:24: Unsupported: coverage select expression 'binsof' + 137 | bins bin_na = ! binsof(a); + | ^ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:137:10: Unsupported: coverage cross bin + 137 | bins bin_na = ! binsof(a); + | ^~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:139:33: Unsupported: coverage select expression 'intersect' + 139 | bins bin_d = binsof(a) intersect { b }; + | ^~~~~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:139:10: Unsupported: coverage cross bin + 139 | bins bin_d = binsof(a) intersect { b }; + | ^~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:140:34: Unsupported: coverage select expression 'intersect' + 140 | bins bin_nd = ! binsof(a) intersect { b }; + | ^ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:140:10: Unsupported: coverage cross bin + 140 | bins bin_nd = ! binsof(a) intersect { b }; + | ^~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:142:23: Unsupported: coverage select expression with + 142 | bins bin_e = with (a); + | ^~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:142:10: Unsupported: coverage cross bin + 142 | bins bin_e = with (a); + | ^~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:143:23: Unsupported: coverage select expression with + 143 | bins bin_e = ! with (a); + | ^ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:143:10: Unsupported: coverage cross bin + 143 | bins bin_e = ! with (a); + | ^~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:145:26: Unsupported: coverage select expression 'binsof' + 145 | bins bin_par = (binsof(a)); + | ^~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:145:10: Unsupported: coverage cross bin + 145 | bins bin_par = (binsof(a)); + | ^~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:146:25: Unsupported: coverage select expression 'binsof' + 146 | bins bin_and = binsof(a) && binsof(b); + | ^~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:146:38: Unsupported: coverage select expression 'binsof' + 146 | bins bin_and = binsof(a) && binsof(b); + | ^~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:146:35: Unsupported: coverage select expression '&&' + 146 | bins bin_and = binsof(a) && binsof(b); + | ^~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:146:10: Unsupported: coverage cross bin + 146 | bins bin_and = binsof(a) && binsof(b); + | ^~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:147:24: Unsupported: coverage select expression 'binsof' + 147 | bins bin_or = binsof(a) || binsof(b); + | ^~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:147:37: Unsupported: coverage select expression 'binsof' + 147 | bins bin_or = binsof(a) || binsof(b); + | ^~~~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:147:34: Unsupported: coverage select expression '||' + 147 | bins bin_or = binsof(a) || binsof(b); + | ^~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:147:10: Unsupported: coverage cross bin + 147 | bins bin_or = binsof(a) || binsof(b); + | ^~~~ +%Error-UNSUPPORTED: t/t_covergroup_unsup.v:133:7: Unsupported: cross + 133 | cross a, b { + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_covergroup_unsup.pl b/test_regress/t/t_covergroup_unsup.pl new file mode 100755 index 000000000..c9ca914d8 --- /dev/null +++ b/test_regress/t/t_covergroup_unsup.pl @@ -0,0 +1,20 @@ +#!/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(vlt => 1); + +compile( + expect_filename => $Self->{golden_filename}, + verilator_flags2 => ['--assert --error-limit 1000'], + fails => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_covergroup_unsup.v b/test_regress/t/t_covergroup_unsup.v new file mode 100644 index 000000000..6fed272bc --- /dev/null +++ b/test_regress/t/t_covergroup_unsup.v @@ -0,0 +1,157 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + int a; + int b; + logic c; + int cyc = 0; + + always @(posedge clk) begin + cyc <= cyc + 1; + end + + // NOTE this grammar hasn't been checked with other simulators, + // is here just to avoid uncovered code lines in the grammar. + + covergroup cg_empty; + endgroup + + covergroup cg_opt; + type_option.weight = 1; // cg, cp, cross + type_option.goal = 99; // cg, cp, cross + type_option.comment = "type_option_comment"; // cg, cp, cross + type_option.strobe = 0; // cg + type_option.merge_instances = 1; // cg + type_option.distribuge_first = 1; // cg + option.name = "the_name"; // cg + option.weight = 1; // cg, cp, cross + option.goal = 98; // cg, cp, cross + option.comment = "option_comment"; // cg, cp, cross + option.at_least = 20; // cg, cp, cross + option.auto_bin_max = 10; // cg, cp + option.cross_num_print_missing = 2; // cg, cross + option.detect_overlap = 1; // cg, cp + option.per_instance = 1; // cg + option.get_inst_coverage = 1; // cg + endgroup + + covergroup cg_clockingevent() @(posedge clk); + endgroup + covergroup cg_withfunction() with function sample (a); + endgroup + covergroup cg_atat() @@ (begin funca or end funcb); + endgroup + covergroup cg_bracket; + {} + endgroup + covergroup cg_bracket; + { option.name = "option"; } + endgroup + covergroup cg_cp; + coverpoint a; + endgroup + covergroup cg_cp_iff; + coverpoint a iff (b); + endgroup + covergroup cg_id_cp_iff; + id: coverpoint a iff (b); + endgroup + covergroup cg_id_cp_id1; + int id: coverpoint a iff (b); + endgroup + covergroup cg_id_cp_id2; + var int id: coverpoint a iff (b); + endgroup + covergroup cg_id_cp_id3; + var [3:0] id: coverpoint a iff (b); + endgroup + covergroup cg_id_cp_id4; + [3:0] id: coverpoint a iff (b); + endgroup + covergroup cg_id_cp_id5; + signed id: coverpoint a iff (b); + endgroup + + covergroup cg_cross; + cross a, b iff (!rst); + endgroup + covergroup cg_cross2; + cross a, b iff (!rst) {} + endgroup + covergroup cg_cross3; + cross a, b { option.comment = "cross"; option.weight = 12; } + endgroup + covergroup cg_cross3; + cross a, b { function void crossfunc; endfunction; } + endgroup + covergroup cg_cross_id; + my_cg_id: cross a, b iff (!rst); + endgroup + + covergroup cg_binsoroptions_bk1; + // bins_keyword id/*bin_identifier*/ bins_orBraE '=' '{' open_range_list '}' iffE + { bins ba = {a}; } + { bins bar = {a} iff (!rst); } + { illegal_bins ila = {a}; } + { ignore_bins iga = {a}; } + + { bins ba[] = {a}; } + { bins ba[2] = {a}; } + + { bins ba = {a} with { b }; } + + { wildcard bins bwa = {a}; } + { wildcard bins bwaw = {a} with { b }; } + + { bins def = default; } + { bins defs = default sequence; } + + { bins bts = ( 1, 2 ); } + { wildcard bins wbts = ( 1, 2 ); } + { bins bts2 = ( 2, 3 ), ( [5:6] ) ; } + + { bins bts2 = ( 1,5 => 6,7 ) ; } + { bins bts2 = ( 3 [*5] ) ; } + { bins bts2 = ( 3 [*5:6] ) ; } + { bins bts2 = ( 3 [->5] ) ; } + { bins bts2 = ( 3 [->5:6] ) ; } + { bins bts2 = ( 3 [=5] ) ; } + { bins bts2 = ( 3 [=5:6] ) ; } + + endgroup + + covergroup cg_cross_bins; + cross a, b { + bins bin_a = binsof(a); + bins bin_ai = binsof(a) iff (!rst); + bins bin_c = binsof(cp.x); + bins bin_na = ! binsof(a); + + bins bin_d = binsof(a) intersect { b }; + bins bin_nd = ! binsof(a) intersect { b }; + + bins bin_e = with (a); + bins bin_e = ! with (a); + + bins bin_par = (binsof(a)); + bins bin_and = binsof(a) && binsof(b); + bins bin_or = binsof(a) || binsof(b); + } + endgroup + + always @(posedge clk) begin + if (cyc == 10) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule From f13e753b52a897d88c5d7e436e77de45f3f692a9 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 12 Mar 2023 21:28:14 -0400 Subject: [PATCH 031/155] Change ZERODLY to a warning. --- Changes | 1 + src/V3Error.h | 4 ++-- test_regress/t/t_delay_var.out | 5 +++-- test_regress/t/t_timing_zerodly_unsup.out | 5 +++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Changes b/Changes index db8c7a161..d11fbc08d 100644 --- a/Changes +++ b/Changes @@ -17,6 +17,7 @@ Verilator 5.009 devel * Add --public-params flag (#3990). [Andrew Nolte] * Support complicated IEEE 'for' assignments. * Support $fopen as an expression. +* Change ZERODLY to a warning. * Fix UNDRIVEN warning seg fault (#3989). [Felix Neumärker] * Fix symbol entries when inheriting classes (#3995) (#3996). [Krzysztof Bieganski, Antmicro Ltd] diff --git a/src/V3Error.h b/src/V3Error.h index 2c02e8eaa..cf0ab5fa6 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -219,11 +219,11 @@ public: || m_e == CONTASSREG || m_e == ENCAPSULATED || m_e == ENDLABEL || m_e == ENUMVALUE || m_e == IMPURE || m_e == PINNOTFOUND || m_e == PKGNODECL || m_e == PROCASSWIRE // Says IEEE - || m_e == ZERODLY); + ); } // Warnings to mention manual bool mentionManual() const VL_MT_SAFE { - return (m_e == EC_FATALSRC || m_e == SYMRSVDWORD || pretendError()); + return (m_e == EC_FATALSRC || m_e == SYMRSVDWORD || m_e == ZERODLY || pretendError()); } // Warnings that are lint only bool lintError() const VL_MT_SAFE { diff --git a/test_regress/t/t_delay_var.out b/test_regress/t/t_delay_var.out index 7c78068df..1ee2ef517 100644 --- a/test_regress/t/t_delay_var.out +++ b/test_regress/t/t_delay_var.out @@ -1,5 +1,6 @@ -%Error-ZERODLY: t/t_delay_var.v:20:7: Unsupported: #0 delays do not schedule process resumption in the Inactive region +%Warning-ZERODLY: t/t_delay_var.v:20:7: Unsupported: #0 delays do not schedule process resumption in the Inactive region 20 | #0 in = 1'b1; | ^ - ... For error description see https://verilator.org/warn/ZERODLY?v=latest + ... For warning description see https://verilator.org/warn/ZERODLY?v=latest + ... Use "/* verilator lint_off ZERODLY */" and lint_on around source to disable this message. %Error: Exiting due to diff --git a/test_regress/t/t_timing_zerodly_unsup.out b/test_regress/t/t_timing_zerodly_unsup.out index 05ffbd7fb..bc85c6dcb 100644 --- a/test_regress/t/t_timing_zerodly_unsup.out +++ b/test_regress/t/t_timing_zerodly_unsup.out @@ -1,5 +1,6 @@ -%Error-ZERODLY: t/t_timing_zerodly_unsup.v:12:13: Unsupported: #0 delays do not schedule process resumption in the Inactive region +%Warning-ZERODLY: t/t_timing_zerodly_unsup.v:12:13: Unsupported: #0 delays do not schedule process resumption in the Inactive region 12 | #0 if (v) $finish; | ^ - ... For error description see https://verilator.org/warn/ZERODLY?v=latest + ... For warning description see https://verilator.org/warn/ZERODLY?v=latest + ... Use "/* verilator lint_off ZERODLY */" and lint_on around source to disable this message. %Error: Exiting due to From 2c62714a30b0437b11bf1cc64f7f0466f35bf58b Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 13 Mar 2023 22:03:53 -0400 Subject: [PATCH 032/155] Fix push to dynamic queue in struct (#4015). --- Changes | 1 + src/V3Width.cpp | 2 ++ test_regress/t/t_queue_struct.pl | 21 +++++++++++++++++++ test_regress/t/t_queue_struct.v | 35 ++++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+) create mode 100755 test_regress/t/t_queue_struct.pl create mode 100644 test_regress/t/t_queue_struct.v diff --git a/Changes b/Changes index d11fbc08d..b24b28d84 100644 --- a/Changes +++ b/Changes @@ -20,6 +20,7 @@ Verilator 5.009 devel * Change ZERODLY to a warning. * Fix UNDRIVEN warning seg fault (#3989). [Felix Neumärker] * Fix symbol entries when inheriting classes (#3995) (#3996). [Krzysztof Bieganski, Antmicro Ltd] +* Fix push to dynamic queue in struct (#4015). [ezchi] Verilator 5.008 2023-03-04 diff --git a/src/V3Width.cpp b/src/V3Width.cpp index a50697f09..fc46c977d 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -3200,6 +3200,8 @@ private: varrefp->access(access); } else if (const AstMemberSel* const ichildp = VN_CAST(childp, MemberSel)) { methodCallLValueRecurse(nodep, ichildp->fromp(), access); + } else if (const AstStructSel* const ichildp = VN_CAST(childp, StructSel)) { + methodCallLValueRecurse(nodep, ichildp->fromp(), access); } else if (const AstNodeSel* const ichildp = VN_CAST(childp, NodeSel)) { methodCallLValueRecurse(nodep, ichildp->fromp(), access); } else { diff --git a/test_regress/t/t_queue_struct.pl b/test_regress/t/t_queue_struct.pl new file mode 100755 index 000000000..9a15dd2cc --- /dev/null +++ b/test_regress/t/t_queue_struct.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2019 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); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_queue_struct.v b/test_regress/t/t_queue_struct.v new file mode 100644 index 000000000..e2f6b6b36 --- /dev/null +++ b/test_regress/t/t_queue_struct.v @@ -0,0 +1,35 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); + +module t (/*AUTOARG*/); + + typedef struct { + int b[$]; + } st_t; + + function automatic st_t bar(); + // verilator no_inline_task + for (int i = 0; i < 4; ++i) begin + bar.b.push_back(i); + end + endfunction // bar + + st_t res; + + initial begin + res = bar(); + `checkd(res.b[0], 0); + `checkd(res.b[1], 1); + `checkd(res.b[2], 2); + `checkd(res.b[3], 3); + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From 1d0a06438c93a5aff1dceb0df61411e0569f3394 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Tue, 14 Mar 2023 09:54:43 +0100 Subject: [PATCH 033/155] Assign unique names for blocks in do..while loop (#4019) --- src/V3AstNodeOther.h | 10 ++----- src/V3LinkJump.cpp | 27 ++++++++++++----- test_regress/t/t_do_while.pl | 21 +++++++++++++ test_regress/t/t_do_while.v | 58 ++++++++++++++++++++++++++++++++++++ 4 files changed, 101 insertions(+), 15 deletions(-) create mode 100755 test_regress/t/t_do_while.pl create mode 100644 test_regress/t/t_do_while.v diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 111b6b3a3..7ad7594ee 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -2651,17 +2651,13 @@ public: bool addNewline() const { return displayType().addNewline(); } }; class AstDoWhile final : public AstNodeStmt { - // @astgen op1 := precondsp : List[AstNode] - // @astgen op2 := condp : AstNodeExpr - // @astgen op3 := stmtsp : List[AstNode] - // @astgen op4 := incsp : List[AstNode] + // @astgen op1 := condp : AstNodeExpr + // @astgen op2 := stmtsp : List[AstNode] public: - AstDoWhile(FileLine* fl, AstNodeExpr* conditionp, AstNode* stmtsp = nullptr, - AstNode* incsp = nullptr) + AstDoWhile(FileLine* fl, AstNodeExpr* conditionp, AstNode* stmtsp = nullptr) : ASTGEN_SUPER_DoWhile(fl) { condp(conditionp); addStmtsp(stmtsp); - addIncsp(incsp); } ASTGEN_MEMBERS_AstDoWhile; bool isGateOptimizable() const override { return false; } diff --git a/src/V3LinkJump.cpp b/src/V3LinkJump.cpp index 14c1eddac..ec1ce3f1a 100644 --- a/src/V3LinkJump.cpp +++ b/src/V3LinkJump.cpp @@ -128,6 +128,19 @@ private: return labelp; } } + void addPrefixToBlocksRecurse(AstNode* nodep) { + // Add do_while_ prefix to blocks + // Used to not have blocks with duplicated names + if (AstBegin* const beginp = VN_CAST(nodep, Begin)) { + if (beginp->name() != "") beginp->name("__Vdo_while_" + beginp->name()); + } + + if (nodep->op1p()) addPrefixToBlocksRecurse(nodep->op1p()); + if (nodep->op2p()) addPrefixToBlocksRecurse(nodep->op2p()); + if (nodep->op3p()) addPrefixToBlocksRecurse(nodep->op3p()); + if (nodep->op4p()) addPrefixToBlocksRecurse(nodep->op4p()); + if (nodep->nextp()) addPrefixToBlocksRecurse(nodep->nextp()); + } // VISITORS void visit(AstNodeModule* nodep) override { @@ -200,23 +213,21 @@ private: void visit(AstDoWhile* nodep) override { // It is converted to AstWhile in this visit method VL_RESTORER(m_loopp); - VL_RESTORER(m_loopInc); { m_loopp = nodep; - m_loopInc = false; - iterateAndNextNull(nodep->precondsp()); iterateAndNextNull(nodep->condp()); iterateAndNextNull(nodep->stmtsp()); - m_loopInc = true; - iterateAndNextNull(nodep->incsp()); } AstNodeExpr* const condp = nodep->condp() ? nodep->condp()->unlinkFrBack() : nullptr; AstNode* const bodyp = nodep->stmtsp() ? nodep->stmtsp()->unlinkFrBack() : nullptr; - AstNode* const incsp = nodep->incsp() ? nodep->incsp()->unlinkFrBack() : nullptr; - AstWhile* const whilep = new AstWhile{nodep->fileline(), condp, bodyp, incsp}; + AstWhile* const whilep = new AstWhile{nodep->fileline(), condp, bodyp}; nodep->replaceWith(whilep); VL_DO_DANGLING(nodep->deleteTree(), nodep); - if (bodyp) whilep->addHereThisAsNext(bodyp->cloneTree(false)); + if (bodyp) { + AstNode* const copiedBodyp = bodyp->cloneTree(false); + addPrefixToBlocksRecurse(copiedBodyp); + whilep->addHereThisAsNext(copiedBodyp); + } } void visit(AstForeach* nodep) override { VL_RESTORER(m_loopp); diff --git a/test_regress/t/t_do_while.pl b/test_regress/t/t_do_while.pl new file mode 100755 index 000000000..aabcde63e --- /dev/null +++ b/test_regress/t/t_do_while.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 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); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_do_while.v b/test_regress/t/t_do_while.v new file mode 100644 index 000000000..9423853f4 --- /dev/null +++ b/test_regress/t/t_do_while.v @@ -0,0 +1,58 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +function automatic int get_1; + int a = 0; + do begin + int x = 1; + a += x; + end while (a < 0); + return a; +endfunction + +module t (/*AUTOARG*/); + int a; + initial begin + if (get_1() != 1) $stop; + + a = 0; + do begin + int x = 1; + a += x; + if (a == 1) begin + a = 2; + end + end while (a < 0); + if (a != 2) $stop; + + a = 1; + do begin + if (a == 1) begin + a = 2; + end + if (a == 2) begin + a = 3; + end + end while (a < 0); + if (a != 3) $stop; + + a = 1; + do begin + if (a == 1) begin + do begin + a++; + end while (a < 5); + end + if (a == 2) begin + a = 3; + end + end while (a < 0); + if (a != 5) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From ed1a9309d450ce39067c0cb5b02b56b022bc0e19 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Tue, 14 Mar 2023 10:03:08 +0100 Subject: [PATCH 034/155] Throw warning if static variable is declared in a loop (#4018) Signed-off-by: Ryszard Rozak --- src/V3LinkParse.cpp | 32 ++++++++++++++++++++--- test_regress/t/t_static_in_loop_unsup.out | 5 ++++ test_regress/t/t_static_in_loop_unsup.pl | 19 ++++++++++++++ test_regress/t/t_static_in_loop_unsup.v | 26 ++++++++++++++++++ 4 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 test_regress/t/t_static_in_loop_unsup.out create mode 100755 test_regress/t/t_static_in_loop_unsup.pl create mode 100644 test_regress/t/t_static_in_loop_unsup.v diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 5e0d78d67..3936eb974 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -65,6 +65,7 @@ private: int m_genblkAbove = 0; // Begin block number of if/case/for above int m_genblkNum = 0; // Begin block number, 0=none seen VLifetime m_lifetime = VLifetime::STATIC; // Propagating lifetime + bool m_insideLoop = false; // True if the node is inside a loop // METHODS void cleanFileline(AstNode* nodep) { @@ -222,6 +223,9 @@ private: void visit(AstVar* nodep) override { cleanFileline(nodep); + if (nodep->lifetime().isStatic() && m_insideLoop) { + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Static variable inside a loop"); + } if (nodep->lifetime().isNone() && nodep->varType() != VVarType::PORT) { nodep->lifetime(m_lifetime); } @@ -459,6 +463,8 @@ private: // 2. ASTSELBIT(first, var0)) // 3. ASTSELLOOPVARS(first, var0..var1)) // 4. DOT(DOT(first, second), ASTSELBIT(third, var0)) + VL_RESTORER(m_insideLoop); + m_insideLoop = true; AstNode* bracketp = nodep->arrayp(); while (AstDot* dotp = VN_CAST(bracketp, Dot)) bracketp = dotp->rhsp(); if (AstSelBit* const selp = VN_CAST(bracketp, SelBit)) { @@ -471,14 +477,34 @@ private: } else if (VN_IS(bracketp, SelLoopVars)) { // Ok } else { - nodep->v3error( - "Syntax error; foreach missing bracketed loop variable (IEEE 1800-2017 12.7.3)"); + nodep->v3error("Syntax error; foreach missing bracketed loop variable (IEEE " + "1800-2017 12.7.3)"); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); return; } iterateChildren(nodep); } - + void visit(AstRepeat* nodep) override { + VL_RESTORER(m_insideLoop); + { + m_insideLoop = true; + iterateChildren(nodep); + } + } + void visit(AstDoWhile* nodep) override { + VL_RESTORER(m_insideLoop); + { + m_insideLoop = true; + iterateChildren(nodep); + } + } + void visit(AstWhile* nodep) override { + VL_RESTORER(m_insideLoop); + { + m_insideLoop = true; + iterateChildren(nodep); + } + } void visit(AstNodeModule* nodep) override { V3Config::applyModule(nodep); diff --git a/test_regress/t/t_static_in_loop_unsup.out b/test_regress/t/t_static_in_loop_unsup.out new file mode 100644 index 000000000..65c68f6e1 --- /dev/null +++ b/test_regress/t/t_static_in_loop_unsup.out @@ -0,0 +1,5 @@ +%Error-UNSUPPORTED: t/t_static_in_loop_unsup.v:14:24: Unsupported: Static variable inside a loop + 14 | static int a = 0; + | ^ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_static_in_loop_unsup.pl b/test_regress/t/t_static_in_loop_unsup.pl new file mode 100755 index 000000000..a5846c699 --- /dev/null +++ b/test_regress/t/t_static_in_loop_unsup.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 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(vlt => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_static_in_loop_unsup.v b/test_regress/t/t_static_in_loop_unsup.v new file mode 100644 index 000000000..87c674688 --- /dev/null +++ b/test_regress/t/t_static_in_loop_unsup.v @@ -0,0 +1,26 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + + +module t; + initial begin + int x = 0; + while (x < 10) begin : outer_loop + int y = 0; + while (y < x) begin : inner_loop + static int a = 0; + a++; + y++; + end + x++; + end + if (outer_loop.inner_loop.a != 45) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From 4e5bd361e0543f650b9292fed9f77f77ada42170 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Tue, 14 Mar 2023 11:54:45 +0100 Subject: [PATCH 035/155] Internal: Fix dumping of AstMethodCall (#4021) --- src/V3AstNodeExpr.h | 1 - src/V3AstNodes.cpp | 9 --------- 2 files changed, 10 deletions(-) diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 4ec2b90c1..bf688422d 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -4052,7 +4052,6 @@ public: BROKEN_RTN(!fromp()); return nullptr; } - void dump(std::ostream& str) const override; }; class AstNew final : public AstNodeFTaskRef { // New as constructor diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 135674029..5e59f023e 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1672,15 +1672,6 @@ const char* AstMemberSel::broken() const { BROKEN_RTN(m_varp && !m_varp->brokeExists()); return nullptr; } -void AstMethodCall::dump(std::ostream& str) const { - this->AstNodeFTaskRef::dump(str); - str << " -> "; - if (taskp()) { - taskp()->dump(str); - } else { - str << " -> UNLINKED"; - } -} void AstModportFTaskRef::dump(std::ostream& str) const { this->AstNode::dump(str); if (isExport()) str << " EXPORT"; From 72963c4e20436b7c9b08b4d36463896dceed3ab2 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 14 Mar 2023 08:29:39 -0400 Subject: [PATCH 036/155] Commentary (#4020) --- docs/guide/connecting.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/guide/connecting.rst b/docs/guide/connecting.rst index 9762e264a..10b35eec9 100644 --- a/docs/guide/connecting.rst +++ b/docs/guide/connecting.rst @@ -120,6 +120,15 @@ code. This is a feature, as using the SystemC pin interconnect scheme everywhere would reduce performance by an order of magnitude. +Verilated API +============= + +The API to a Verilated model is the C++ headers in the include/ directory +in the distribution. These headers use Doxygen comments, `///` and `//<`, +to indicate and document those functions that are part of the Verilated +public API. + + Direct Programming Interface (DPI) ================================== From a8ce272e4a2e397e39abeff7fe06acbd8c5ae0e0 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 14 Mar 2023 08:39:04 -0400 Subject: [PATCH 037/155] Commentary: spelling --- Changes | 12 ++++++------ docs/guide/warnings.rst | 4 ++-- docs/spelling.txt | 18 +++++++++++++++++- src/V3Param.cpp | 2 +- test_regress/t/t_dist_whitespace.pl | 3 ++- 5 files changed, 28 insertions(+), 11 deletions(-) diff --git a/Changes b/Changes index b24b28d84..b3da19ca6 100644 --- a/Changes +++ b/Changes @@ -56,8 +56,8 @@ Verilator 5.008 2023-03-04 * Fix namespace fallback resolution (#3863) (#3942). [Aleksander Kiryk, Antmicro Ltd] * Fix std:: to be parsed first (#3864) (#3928). [Aleksander Kiryk, Antmicro Ltd] * Fix cmake warning if multiple SOURCES w/o PREFIX (#3916) (#3927). [Yoda Lee] -* Fix paramaterized class function linkage (#3917). [Ryszard Rozak] -* Fix static members of type aliases of a parametrized class (#3922). [Ryszard Rozak, Antmicro Ltd] +* Fix parameterized class function linkage (#3917). [Ryszard Rozak] +* Fix static members of type aliases of a parameterized class (#3922). [Ryszard Rozak, Antmicro Ltd] * Fix class extend parameter dot case (#3926). [Ryszard Rozak, Antmicro Ltd] * Fix MsWin missing directory exception, and ::std (#3928) (#3933) (#3935). [Kritik Bhimani] * Fix very long VPI signal names (#3929). [Marlon James] @@ -69,13 +69,13 @@ Verilator 5.008 2023-03-04 * Fix CMake bad C identifiers (#3948) (#3951). [Zixi Li] * Fix build on HP PA architecture (#3954). [John David Anglin] * Fix date on the front page of verilator.pdf (#3956) (#3957). [Larry Doolittle] -* Fix dicts declared with ref type (#3960). [Ryszard Rozak, Antmicro Ltd] +* Fix associative arrays declared with ref type (#3960). [Ryszard Rozak, Antmicro Ltd] * Fix missing error on negative replicate (#3963). [Benjamin Menküc] * Fix self references to parameterized classes (#3962). [Ryszard Rozak, Antmicro Ltd] * Fix LITENDIAN warning is backwards (#3966) (#3967). [Cameron Kirk] * Fix subsequent parameter declarations (#3969). [Ryszard Rozak, Antmicro Ltd] * Fix timing delays to not truncate below 64 bits (#3973) (#3982). [Felix Neumärker] -* Fix cmake on macOS to mark weak symbols with -U linker flag (#3978) (#3979). [Peter Debacker] +* Fix cmake on MacOS to mark weak symbols with -U linker flag (#3978) (#3979). [Peter Debacker] * Fix UNDRIVEN warning seg fault (#3989). [Felix Neumärker] * Fix coverage of class methods (#3998). [Tim Paine] * Fix packed array structure replication. @@ -95,7 +95,7 @@ Verilator 5.006 2023-01-22 * Support import/export lists in modport (#3886). [Gökçe Aydos] * Support class queue equality (#3895). [Ilya Barkov] * Support type case and type equality comparisons. -* Add IMPLICITSTATIC warning when a ftask/function is implicitly static (#3839). [Ryszard Rozak, Antmicro Ltd] +* Add IMPLICITSTATIC warning when a task/function is implicitly static (#3839). [Ryszard Rozak, Antmicro Ltd] * Add VL_VALUE_STRING_MAX_WORDS override (#3869). [Andrew Nolte] * Optimize expansion of extend operators. * Internal multithreading tests. [Mariusz Glebocki, et al, Antmicro Ltd] @@ -109,7 +109,7 @@ Verilator 5.006 2023-01-22 * Fix self references when param class instantiated (#3833). [Ryszard Rozak, Antmicro Ltd] * Fix memory leak in V3Sched, etc. (#3834). [Geza Lore] * Fix compatibility with musl libc / Alpine Linux (#3845). [Sören Tempel] -* Fix empty case items crash (#3851). [rporter] +* Fix empty case items crash (#3851). [Rich Porter] * Fix VL_CPU_RELAX on MIPS/Armel/s390/sparc (#3843) (#3891). [Kamil Rakoczy] * Fix module parameter name collision (#3854) (#3855). [James Shi] * Fix unpacked array expansion (#3861). [Joey Liu] diff --git a/docs/guide/warnings.rst b/docs/guide/warnings.rst index ccfb0e763..e19c6a6a1 100644 --- a/docs/guide/warnings.rst +++ b/docs/guide/warnings.rst @@ -738,7 +738,7 @@ List Of Warnings This is a warning because the static default differs from C++, differs from class member function/tasks. Static is a more dangerous default - then automatic as static prevents the function from being reinterant, + then automatic as static prevents the function from being reentrant, which may be a source of bugs, and/or performance issues. If the function does not require static behavior, change it to "function @@ -1813,7 +1813,7 @@ List Of Warnings .. option:: WIDTHXZEXPAND - A more granular WIDTH warning, for when a value is xz expanded + A more granular WIDTH warning, for when a value is X/Z expanded .. option:: WIDTHCONCAT diff --git a/docs/spelling.txt b/docs/spelling.txt index b77ffb233..9098225a7 100644 --- a/docs/spelling.txt +++ b/docs/spelling.txt @@ -6,6 +6,7 @@ Alexandre Ami Amir Anastasiadis +Anglin Anikin Antmicro Antonin @@ -42,6 +43,7 @@ Chandan Chitlesh Christophe Cochrane +Corteggiani Cuan Cygwin DErrico @@ -96,6 +98,7 @@ Fredieu GTKWave Galbi Gantt +Garnal Gartner Gelinek Geoff @@ -207,6 +210,7 @@ Matveyenko Maupin Mdir Mednick +Menküc Michiels Microsystems Milanovic @@ -223,8 +227,10 @@ Muhlestein Multithreaded Multithreading NOUNOPTFLAT +NaN Nalbantis Narayan +Nassim Nauticus Newgard Nigam @@ -376,6 +382,7 @@ Xuan Xuanqi Yazdanbakhsh Yi +Yike Yinan Yosys Yu @@ -452,6 +459,7 @@ commandArgsPlusMatch compilable concat concats +conf config const constexpr @@ -512,6 +520,7 @@ dumpportson dumpvars dut dx +dynarray elab elike elsif @@ -541,6 +550,7 @@ exe executables expr extern +ezchi fanin fasttrace fauto @@ -635,6 +645,7 @@ lcov ld leavinel len +libc libext libgoogle libsystemc @@ -653,6 +664,7 @@ logicals longint lossy lsb +lubc lvalue lxt macromodule @@ -678,12 +690,15 @@ mtasks mulithreaded mult multidim +multidriven multiinterfaces multiline multipling +multipoint multithread multithreaded multithreading +musl mutexes mux myftptoyman @@ -762,6 +777,7 @@ pulldowns pullup pvalue pwd +py qrq radix randc @@ -909,6 +925,7 @@ vlt vltstd vluint vpi +vpiDefName vpiLeftRange vpiModule vpiSize @@ -938,4 +955,3 @@ ypq yurivict zdave Øyvind - diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 287968268..741d102d8 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -1022,7 +1022,7 @@ class ParamVisitor final : public VNVisitor { m_cellps.emplace(!isIface, nodep); } - // RHSs of AstDots need a relink when LHS is a parametrized class reference + // RHSs of AstDots need a relink when LHS is a parameterized class reference void relinkDots() { for (AstDot* const dotp : m_dots) { const AstClassOrPackageRef* const classRefp = VN_AS(dotp->lhsp(), ClassOrPackageRef); diff --git a/test_regress/t/t_dist_whitespace.pl b/test_regress/t/t_dist_whitespace.pl index 3a09d63e7..5fcf0c9c3 100755 --- a/test_regress/t/t_dist_whitespace.pl +++ b/test_regress/t/t_dist_whitespace.pl @@ -67,7 +67,8 @@ foreach my $file (sort keys %files) { if ($contents =~ /[^[:alnum:][:punct:] \t\r\n]/) { my $unicode_exempt = ($file =~ /Changes$/ || $file =~ /CONTRIBUTORS$/ - || $file =~ /contributors.rst$/); + || $file =~ /contributors.rst$/ + || $file =~ /spelling.txt$/); next if $unicode_exempt; $warns{$file} = "Warning: non-ASCII contents in $file\n"; } From 80b7b8bbdb54afc231500beb5e4813d08acf5d51 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Tue, 14 Mar 2023 14:48:06 +0100 Subject: [PATCH 038/155] Don't call randomize on null field (#4023) Signed-off-by: Ryszard Rozak --- src/V3Randomize.cpp | 31 +++++++++++++++-------------- test_regress/t/t_randomize_method.v | 8 ++++++++ 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 9dfb2a536..a244e1c68 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -232,9 +232,9 @@ private: AstFunc* const funcp = V3Randomize::newRandomizeFunc(nodep); AstVar* const fvarp = VN_AS(funcp->fvarp(), Var); addPrePostCall(nodep, funcp, "pre_randomize"); - funcp->addStmtsp(new AstAssign{ - nodep->fileline(), new AstVarRef{nodep->fileline(), fvarp, VAccess::WRITE}, - new AstConst{nodep->fileline(), AstConst::WidthedValue{}, 32, 1}}); + FileLine* fl = nodep->fileline(); + funcp->addStmtsp(new AstAssign{fl, new AstVarRef{fl, fvarp, VAccess::WRITE}, + new AstConst{fl, AstConst::WidthedValue{}, 32, 1}}); for (AstClass* classp = nodep; classp; classp = classp->extendsp() ? classp->extendsp()->classp() : nullptr) { for (auto* memberp = classp->stmtsp(); memberp; memberp = memberp->nextp()) { @@ -242,24 +242,25 @@ private: if (!memberVarp || !memberVarp->isRand()) continue; const AstNodeDType* const dtypep = memberp->dtypep()->skipRefp(); if (VN_IS(dtypep, BasicDType) || VN_IS(dtypep, StructDType)) { - AstVarRef* const refp - = new AstVarRef{nodep->fileline(), memberVarp, VAccess::WRITE}; - AstNodeStmt* const stmtp = newRandStmtsp(nodep->fileline(), refp); + AstVarRef* const refp = new AstVarRef{fl, memberVarp, VAccess::WRITE}; + AstNodeStmt* const stmtp = newRandStmtsp(fl, refp); funcp->addStmtsp(stmtp); } else if (const auto* const classRefp = VN_CAST(dtypep, ClassRefDType)) { - AstVarRef* const refp - = new AstVarRef{nodep->fileline(), memberVarp, VAccess::WRITE}; + AstVarRef* const refp = new AstVarRef{fl, memberVarp, VAccess::WRITE}; AstFunc* const memberFuncp = V3Randomize::newRandomizeFunc(classRefp->classp()); - AstMethodCall* const callp - = new AstMethodCall{nodep->fileline(), refp, "randomize", nullptr}; + AstMethodCall* const callp = new AstMethodCall{fl, refp, "randomize", nullptr}; callp->taskp(memberFuncp); callp->dtypeFrom(memberFuncp); - funcp->addStmtsp(new AstAssign{ - nodep->fileline(), new AstVarRef{nodep->fileline(), fvarp, VAccess::WRITE}, - new AstAnd{nodep->fileline(), - new AstVarRef{nodep->fileline(), fvarp, VAccess::READ}, - callp}}); + AstAssign* const assignp = new AstAssign{ + fl, new AstVarRef{fl, fvarp, VAccess::WRITE}, + new AstAnd{fl, new AstVarRef{fl, fvarp, VAccess::READ}, callp}}; + AstIf* const assignIfNotNullp + = new AstIf{fl, + new AstNeq{fl, new AstVarRef{fl, memberVarp, VAccess::READ}, + new AstConst{fl, AstConst::Null{}}}, + assignp}; + funcp->addStmtsp(assignIfNotNullp); } else { memberp->v3warn(E_UNSUPPORTED, "Unsupported: random member variables with type " diff --git a/test_regress/t/t_randomize_method.v b/test_regress/t/t_randomize_method.v index 126f0785e..fdbc8cd5d 100644 --- a/test_regress/t/t_randomize_method.v +++ b/test_regress/t/t_randomize_method.v @@ -78,6 +78,10 @@ class OtherCls; endclass +class ContainsNull; + rand BaseCls b; +endclass + module t (/*AUTOARG*/); bit ok = 0; longint checksum; @@ -89,6 +93,7 @@ module t (/*AUTOARG*/); DerivedCls derived; OtherCls other; BaseCls base; + ContainsNull cont; initial begin int rand_result; @@ -96,15 +101,18 @@ module t (/*AUTOARG*/); for (int i = 0; i < 10; i++) begin derived = new; other = new; + cont = new; base = derived; rand_result = base.randomize(); rand_result = other.randomize(); + rand_result = cont.randomize(); if (!(derived.l inside {ONE, TWO, THREE, FOUR})) $stop; if (!(other.str.s.c inside {ONE, TWO, THREE, FOUR})) $stop; if (!(other.str.y inside {ONE, TWO, THREE, FOUR})) $stop; if (derived.i.e != 0) $stop; if (derived.k != 0) $stop; if (other.v != 0) $stop; + if (cont.b != null) $stop; checksum = 0; checksum_next(longint'(derived.i.a)); checksum_next(longint'(derived.i.b)); From fc3fdcc71c6302fdbbaea20494a78348d66ccd29 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Tue, 14 Mar 2023 18:47:43 +0100 Subject: [PATCH 039/155] Tests: Fix randomize_method test (#4024) --- test_regress/t/t_randomize_method.v | 73 ++++++++++++++--------------- 1 file changed, 36 insertions(+), 37 deletions(-) diff --git a/test_regress/t/t_randomize_method.v b/test_regress/t/t_randomize_method.v index fdbc8cd5d..8295dd829 100644 --- a/test_regress/t/t_randomize_method.v +++ b/test_regress/t/t_randomize_method.v @@ -4,6 +4,20 @@ // any use, without warranty, 2020 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 +`define check_rand(cl, field) \ +begin \ + longint prev_result; \ + int ok = 0; \ + for (int i = 0; i < 10; i++) begin \ + longint result; \ + void'(cl.randomize()); \ + result = longint'(field); \ + if (i > 0 && result != prev_result) ok = 1; \ + prev_result = result; \ + end \ + if (ok != 1) $stop; \ +end + typedef enum bit[15:0] { ONE = 3, TWO = 5, @@ -83,12 +97,6 @@ class ContainsNull; endclass module t (/*AUTOARG*/); - bit ok = 0; - longint checksum; - - task checksum_next(longint x); - checksum = x ^ {checksum[62:0],checksum[63]^checksum[2]^checksum[0]}; - endtask; DerivedCls derived; OtherCls other; @@ -97,12 +105,11 @@ module t (/*AUTOARG*/); initial begin int rand_result; - longint prev_checksum; + derived = new; + other = new; + cont = new; + base = derived; for (int i = 0; i < 10; i++) begin - derived = new; - other = new; - cont = new; - base = derived; rand_result = base.randomize(); rand_result = other.randomize(); rand_result = cont.randomize(); @@ -113,32 +120,24 @@ module t (/*AUTOARG*/); if (derived.k != 0) $stop; if (other.v != 0) $stop; if (cont.b != null) $stop; - checksum = 0; - checksum_next(longint'(derived.i.a)); - checksum_next(longint'(derived.i.b)); - checksum_next(longint'(derived.i.c)); - checksum_next(longint'(derived.j)); - checksum_next(longint'(derived.l)); - checksum_next(longint'(other.w)); - checksum_next(longint'(other.x)); - checksum_next(longint'(other.y)); - checksum_next(longint'(other.z)); - checksum_next(longint'(other.str.x)); - checksum_next(longint'(other.str.y)); - checksum_next(longint'(other.str.z)); - checksum_next(longint'(other.str.s.a)); - checksum_next(longint'(other.str.s.b)); - checksum_next(longint'(other.str.s.c)); - $write("checksum: %d\n", checksum); - if (i > 0 && checksum != prev_checksum) begin - ok = 1; - end - prev_checksum = checksum; end - if (ok) begin - $write("*-* All Finished *-*\n"); - $finish; - end - else $stop; + `check_rand(derived, derived.i.a); + `check_rand(derived, derived.i.b); + `check_rand(derived, derived.i.c); + `check_rand(derived, derived.j); + `check_rand(derived, derived.l); + `check_rand(other, other.w); + `check_rand(other, other.x); + `check_rand(other, other.y); + `check_rand(other, other.z); + `check_rand(other, other.str.x); + `check_rand(other, other.str.y); + `check_rand(other, other.str.z); + `check_rand(other, other.str.s.a); + `check_rand(other, other.str.s.b); + `check_rand(other, other.str.s.c); + + $write("*-* All Finished *-*\n"); + $finish; end endmodule From 9e25c21fed23358a9e41cdd869eecc8aa1aadb14 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 14 Mar 2023 19:35:40 -0400 Subject: [PATCH 040/155] Fix unpacked struct clocking --- src/V3EmitV.cpp | 5 +++ test_regress/t/t_interface_typedef.v | 1 + test_regress/t/t_struct_clk.pl | 21 +++++++++++ test_regress/t/t_struct_clk.v | 52 ++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+) create mode 100755 test_regress/t/t_struct_clk.pl create mode 100644 test_regress/t/t_struct_clk.v diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index d9f05b302..61be14c49 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -510,6 +510,11 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { puts("."); puts(nodep->prettyName()); } + void visit(AstStructSel* nodep) override { + iterate(nodep->fromp()); + puts("."); + puts(nodep->prettyName()); + } void visit(AstAttrOf* nodep) override { putfs(nodep, "$_ATTROF("); iterateAndNextConstNull(nodep->fromp()); diff --git a/test_regress/t/t_interface_typedef.v b/test_regress/t/t_interface_typedef.v index a8faecb9b..c3491894d 100644 --- a/test_regress/t/t_interface_typedef.v +++ b/test_regress/t/t_interface_typedef.v @@ -50,6 +50,7 @@ module sub #( initial begin struct_t substruct; substruct.data = '1; + `checkh($bits(struct_t), EXP_WIDTH); `checkh(substruct.data, expval); end diff --git a/test_regress/t/t_struct_clk.pl b/test_regress/t/t_struct_clk.pl new file mode 100755 index 000000000..859050d63 --- /dev/null +++ b/test_regress/t/t_struct_clk.pl @@ -0,0 +1,21 @@ +#!/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); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_struct_clk.v b/test_regress/t/t_struct_clk.v new file mode 100644 index 000000000..e09b4f3de --- /dev/null +++ b/test_regress/t/t_struct_clk.v @@ -0,0 +1,52 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); + +typedef struct { + logic clk1; + logic clk2; + logic rst; +} clks_t; + +module t(/*AUTOARG*/ + // Inputs + clk, fastclk + ); + input clk; + input fastclk; + + int cyc = 0; + + clks_t clks; + always_comb begin + clks.clk1 = clk; + clks.clk2 = fastclk; + end + + // verilator lint_off MULTIDRIVEN + int cyc1 = 0; + int cyc2 = 0; + + always @ (negedge clks.clk1) cyc1 <= cyc1 + 1; + always @ (negedge clks.clk2) cyc2 <= cyc2 + 1; + + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc < 10) begin + cyc1 <= '0; + cyc2 <= '0; + end + else if (cyc == 99) begin + `checkd(cyc1, 90); + `checkd(cyc2, 90*5); + + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule From ea4cc4e0767b1d003240d8b1d19c2c8a4f6ea816 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 14 Mar 2023 19:52:01 -0400 Subject: [PATCH 041/155] Parse nettype with package, still unsupported --- src/verilog.y | 3 +++ test_regress/t/t_nettype.out | 15 +++++++++------ test_regress/t/t_nettype.v | 5 +++++ 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/verilog.y b/src/verilog.y index 1fdc118a7..ec68a46e4 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -2480,6 +2480,9 @@ net_type_declaration: // IEEE: net_type_declaration { $$ = nullptr; BBUNSUP($1, "Unsupported: nettype"); } | yNETTYPE packageClassScopeE id/*net_type_identifier*/ idAny/*net_type_identifier*/ ';' { $$ = nullptr; BBUNSUP($1, "Unsupported: nettype"); } + | yNETTYPE packageClassScopeE id/*net_type_identifier*/ idAny/*net_type_identifier*/ + /*cont*/ yWITH__ETC packageClassScopeE id/*tf_identifier*/ ';' + { $$ = nullptr; BBUNSUP($1, "Unsupported: nettype"); } ; implicit_typeE: // IEEE: part of *data_type_or_implicit diff --git a/test_regress/t/t_nettype.out b/test_regress/t/t_nettype.out index 6811cc566..dc401b4c9 100644 --- a/test_regress/t/t_nettype.out +++ b/test_regress/t/t_nettype.out @@ -1,11 +1,14 @@ -%Error-UNSUPPORTED: t/t_nettype.v:24:4: Unsupported: nettype - 24 | nettype real real1_n with Pkg::resolver; +%Error-UNSUPPORTED: t/t_nettype.v:25:4: Unsupported: nettype + 25 | nettype real real1_n with Pkg::resolver; | ^~~~~~~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_nettype.v:28:4: Unsupported: nettype - 28 | nettype real real2_n with local_resolver; +%Error-UNSUPPORTED: t/t_nettype.v:29:4: Unsupported: nettype + 29 | nettype real real2_n with local_resolver; | ^~~~~~~ -%Error-UNSUPPORTED: t/t_nettype.v:33:4: Unsupported: nettype - 33 | nettype real2_n real3_n; +%Error-UNSUPPORTED: t/t_nettype.v:34:4: Unsupported: nettype + 34 | nettype real2_n real3_n; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_nettype.v:38:4: Unsupported: nettype + 38 | nettype Pkg::real_t real4_n with Pkg::resolver; | ^~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_nettype.v b/test_regress/t/t_nettype.v index 312a5960f..c81792601 100644 --- a/test_regress/t/t_nettype.v +++ b/test_regress/t/t_nettype.v @@ -5,6 +5,7 @@ // SPDX-License-Identifier: CC0-1.0 package Pkg; + typedef real real_t; real last_resolve; function automatic real resolver(input real drivers[]); @@ -34,6 +35,10 @@ module t(/*AUTOARG*/); real3_n real3; assign real3 = 1.23; + nettype Pkg::real_t real4_n with Pkg::resolver; + real4_n real4; + assign real4 = 1.23; + // TODO when implement net types need to check multiple driver cases, across // submodules From 0fc5d37901c303f3840717f01a018fc05fe346e4 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 14 Mar 2023 20:29:47 -0400 Subject: [PATCH 042/155] Fix bounded queues with parameter bounds --- src/V3Width.cpp | 1 + test_regress/t/t_queue_bounded.v | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/V3Width.cpp b/src/V3Width.cpp index fc46c977d..70ced22a4 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1682,6 +1682,7 @@ private: // Iterate into subDTypep() to resolve that type and update pointer. nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); nodep->dtypep(nodep); // The array itself, not subDtype + userIterateAndNext(nodep->boundp(), WidthVP{SELF, BOTH}.p()); if (VN_IS(nodep->boundp(), Unbounded)) { nodep->boundp()->unlinkFrBack()->deleteTree(); // nullptr will represent unbounded } diff --git a/test_regress/t/t_queue_bounded.v b/test_regress/t/t_queue_bounded.v index e6020465b..05653887c 100644 --- a/test_regress/t/t_queue_bounded.v +++ b/test_regress/t/t_queue_bounded.v @@ -6,7 +6,9 @@ module t (/*AUTOARG*/); - int q[$ : 2]; // Shall not go higher than [2], i.e. size 3 + localparam TWO = 2; + + int q[$ : TWO]; // Shall not go higher than [2], i.e. size 3 initial begin q.push_front(3); From 56de6f1a9f3cccb6ecd45d8ad54e9cc8fb092f34 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 14 Mar 2023 20:40:58 -0400 Subject: [PATCH 043/155] Fix min/typ/max internal error --- src/verilog.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/verilog.y b/src/verilog.y index ec68a46e4..33288f922 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -2944,7 +2944,7 @@ delay_control: //== IEEE: delay_control | '#' '(' minTypMax ',' minTypMax ')' { $$ = new AstDelay{$1, $3, false}; RISEFALLDLYUNSUP($3); DEL($5); } | '#' '(' minTypMax ',' minTypMax ',' minTypMax ')' - { $$ = new AstDelay{$1, $3, false}; RISEFALLDLYUNSUP($5); DEL($3); DEL($7); } + { $$ = new AstDelay{$1, $5, false}; RISEFALLDLYUNSUP($5); DEL($3); DEL($7); } ; delay_value: // ==IEEE:delay_value From 2488b5a97f85673e0a3a3a4bfd36ec5f7d15c53f Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 14 Mar 2023 21:14:27 -0400 Subject: [PATCH 044/155] Fix pullup/pulldown to create implicit wires. --- src/V3LinkDot.cpp | 7 +++++++ test_regress/t/t_tri_pull_implicit.pl | 21 +++++++++++++++++++++ test_regress/t/t_tri_pull_implicit.v | 20 ++++++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100755 test_regress/t/t_tri_pull_implicit.pl create mode 100644 test_regress/t/t_tri_pull_implicit.v diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 94ac413fb..113be442d 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -1709,6 +1709,13 @@ private: } iterateChildren(nodep); } + void visit(AstPull* nodep) override { + // Deal with implicit definitions + // We used to nodep->allowImplicit() here, but it turns out + // normal "assigns" can also make implicit wires. Yuk. + pinImplicitExprRecurse(nodep->lhsp()); + iterateChildren(nodep); + } void visit(AstTypedefFwd* nodep) override { VSymEnt* const foundp = m_statep->getNodeSym(nodep)->findIdFallback(nodep->name()); if (!foundp && v3Global.opt.pedantic() diff --git a/test_regress/t/t_tri_pull_implicit.pl b/test_regress/t/t_tri_pull_implicit.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_tri_pull_implicit.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 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); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_tri_pull_implicit.v b/test_regress/t/t_tri_pull_implicit.v new file mode 100644 index 000000000..c0c45e4d6 --- /dev/null +++ b/test_regress/t/t_tri_pull_implicit.v @@ -0,0 +1,20 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + + // verilator lint_off IMPLICIT + pulldown (pd); + pullup (pu); + + initial begin + if (pd != 0) $stop; + if (pu != 1) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From 0f6024ef3c016ad388184d51aa5463aecf2ac1bb Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Wed, 15 Mar 2023 16:48:18 +0100 Subject: [PATCH 045/155] Fix rand fields in base classes (#4025) --- src/V3Randomize.cpp | 98 ++++++++++++------- test_regress/t/t_randomize_method.v | 30 ++++++ .../t/t_randomize_method_types_unsup.out | 12 ++- .../t/t_randomize_method_types_unsup.v | 1 + 4 files changed, 99 insertions(+), 42 deletions(-) diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index a244e1c68..cb2a47f09 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -57,9 +57,11 @@ private: if (VN_IS(memberp, Var) && VN_AS(memberp, Var)->isRand()) { if (const auto* const classRefp = VN_CAST(memberp->dtypep(), ClassRefDType)) { auto* const rclassp = classRefp->classp(); - markMembers(rclassp); - markDerived(rclassp); - rclassp->user1(true); + if (!rclassp->user1()) { + rclassp->user1(true); + markMembers(rclassp); + markDerived(rclassp); + } } } } @@ -69,9 +71,11 @@ private: const auto it = m_baseToDerivedMap.find(nodep); if (it != m_baseToDerivedMap.end()) { for (auto* classp : it->second) { - classp->user1(true); - markMembers(classp); - markDerived(classp); + if (!classp->user1p()) { + classp->user1(true); + markMembers(classp); + markDerived(classp); + } } } } @@ -121,6 +125,7 @@ private: // Cleared on Netlist // AstClass::user1() -> bool. Set true to indicate needs randomize processing // AstEnumDType::user2() -> AstVar*. Pointer to table with enum values + // AstClass::user3() -> AstFunc*. Pointer to randomize() method of a class // VNUser1InUse m_inuser1; (Allocated for use in RandomizeMarkVisitor) const VNUser2InUse m_inuser2; @@ -230,42 +235,59 @@ private: if (!nodep->user1()) return; // Doesn't need randomize, or already processed UINFO(9, "Define randomize() for " << nodep << endl); AstFunc* const funcp = V3Randomize::newRandomizeFunc(nodep); + nodep->user3p(funcp); AstVar* const fvarp = VN_AS(funcp->fvarp(), Var); addPrePostCall(nodep, funcp, "pre_randomize"); FileLine* fl = nodep->fileline(); - funcp->addStmtsp(new AstAssign{fl, new AstVarRef{fl, fvarp, VAccess::WRITE}, - new AstConst{fl, AstConst::WidthedValue{}, 32, 1}}); - for (AstClass* classp = nodep; classp; - classp = classp->extendsp() ? classp->extendsp()->classp() : nullptr) { - for (auto* memberp = classp->stmtsp(); memberp; memberp = memberp->nextp()) { - AstVar* const memberVarp = VN_CAST(memberp, Var); - if (!memberVarp || !memberVarp->isRand()) continue; - const AstNodeDType* const dtypep = memberp->dtypep()->skipRefp(); - if (VN_IS(dtypep, BasicDType) || VN_IS(dtypep, StructDType)) { - AstVarRef* const refp = new AstVarRef{fl, memberVarp, VAccess::WRITE}; - AstNodeStmt* const stmtp = newRandStmtsp(fl, refp); - funcp->addStmtsp(stmtp); - } else if (const auto* const classRefp = VN_CAST(dtypep, ClassRefDType)) { - AstVarRef* const refp = new AstVarRef{fl, memberVarp, VAccess::WRITE}; - AstFunc* const memberFuncp - = V3Randomize::newRandomizeFunc(classRefp->classp()); - AstMethodCall* const callp = new AstMethodCall{fl, refp, "randomize", nullptr}; - callp->taskp(memberFuncp); - callp->dtypeFrom(memberFuncp); - AstAssign* const assignp = new AstAssign{ - fl, new AstVarRef{fl, fvarp, VAccess::WRITE}, - new AstAnd{fl, new AstVarRef{fl, fvarp, VAccess::READ}, callp}}; - AstIf* const assignIfNotNullp - = new AstIf{fl, - new AstNeq{fl, new AstVarRef{fl, memberVarp, VAccess::READ}, - new AstConst{fl, AstConst::Null{}}}, - assignp}; - funcp->addStmtsp(assignIfNotNullp); - } else { - memberp->v3warn(E_UNSUPPORTED, - "Unsupported: random member variables with type " - << memberp->dtypep()->prettyDTypeNameQ()); + + AstNodeExpr* beginValp = nullptr; + if (nodep->extendsp()) { + // Call randomize() from the base class + AstFunc* const baseRandomizep = VN_AS(nodep->extendsp()->classp()->user3p(), Func); + if (baseRandomizep) { + AstFuncRef* const baseRandCallp = new AstFuncRef{fl, "randomize", nullptr}; + baseRandCallp->taskp(baseRandomizep); + baseRandCallp->dtypeFrom(baseRandomizep->dtypep()); + baseRandCallp->classOrPackagep(nodep->extendsp()->classp()); + beginValp = baseRandCallp; + } + } + if (!beginValp) beginValp = new AstConst{fl, AstConst::WidthedValue{}, 32, 1}; + + funcp->addStmtsp(new AstAssign{fl, new AstVarRef{fl, fvarp, VAccess::WRITE}, beginValp}); + + for (auto* memberp = nodep->stmtsp(); memberp; memberp = memberp->nextp()) { + AstVar* const memberVarp = VN_CAST(memberp, Var); + if (!memberVarp || !memberVarp->isRand()) continue; + const AstNodeDType* const dtypep = memberp->dtypep()->skipRefp(); + if (VN_IS(dtypep, BasicDType) || VN_IS(dtypep, StructDType)) { + AstVarRef* const refp = new AstVarRef{fl, memberVarp, VAccess::WRITE}; + AstNodeStmt* const stmtp = newRandStmtsp(fl, refp); + funcp->addStmtsp(stmtp); + } else if (const auto* const classRefp = VN_CAST(dtypep, ClassRefDType)) { + if (classRefp->classp() == nodep) { + memberp->v3warn( + E_UNSUPPORTED, + "Unsupported: random member variable with type of a current class"); + continue; } + AstVarRef* const refp = new AstVarRef{fl, memberVarp, VAccess::WRITE}; + AstFunc* const memberFuncp = V3Randomize::newRandomizeFunc(classRefp->classp()); + AstMethodCall* const callp = new AstMethodCall{fl, refp, "randomize", nullptr}; + callp->taskp(memberFuncp); + callp->dtypeFrom(memberFuncp); + AstAssign* const assignp = new AstAssign{ + fl, new AstVarRef{fl, fvarp, VAccess::WRITE}, + new AstAnd{fl, new AstVarRef{fl, fvarp, VAccess::READ}, callp}}; + AstIf* const assignIfNotNullp + = new AstIf{fl, + new AstNeq{fl, new AstVarRef{fl, memberVarp, VAccess::READ}, + new AstConst{fl, AstConst::Null{}}}, + assignp}; + funcp->addStmtsp(assignIfNotNullp); + } else { + memberp->v3warn(E_UNSUPPORTED, "Unsupported: random member variable with type " + << memberp->dtypep()->prettyDTypeNameQ()); } } addPrePostCall(nodep, funcp, "post_randomize"); diff --git a/test_regress/t/t_randomize_method.v b/test_regress/t/t_randomize_method.v index 8295dd829..dc3fa9561 100644 --- a/test_regress/t/t_randomize_method.v +++ b/test_regress/t/t_randomize_method.v @@ -96,23 +96,46 @@ class ContainsNull; rand BaseCls b; endclass +class ClsWithInt; + rand int a; + int b; +endclass + +class DeriveClsWithInt extends ClsWithInt; +endclass + +class DeriveAndContainClsWithInt extends ClsWithInt; + rand ClsWithInt cls1; + ClsWithInt cls2; + function new; + cls1 = new; + cls2 = new; + endfunction +endclass + module t (/*AUTOARG*/); DerivedCls derived; OtherCls other; BaseCls base; ContainsNull cont; + DeriveClsWithInt der_int; + DeriveAndContainClsWithInt der_contain; initial begin int rand_result; derived = new; other = new; cont = new; + der_int = new; + der_contain = new; base = derived; for (int i = 0; i < 10; i++) begin rand_result = base.randomize(); rand_result = other.randomize(); rand_result = cont.randomize(); + rand_result = der_int.randomize(); + rand_result = der_contain.randomize(); if (!(derived.l inside {ONE, TWO, THREE, FOUR})) $stop; if (!(other.str.s.c inside {ONE, TWO, THREE, FOUR})) $stop; if (!(other.str.y inside {ONE, TWO, THREE, FOUR})) $stop; @@ -120,6 +143,10 @@ module t (/*AUTOARG*/); if (derived.k != 0) $stop; if (other.v != 0) $stop; if (cont.b != null) $stop; + if (der_int.b != 0) $stop; + if (der_contain.cls2.a != 0) $stop; + if (der_contain.cls1.b != 0) $stop; + if (der_contain.b != 0) $stop; end `check_rand(derived, derived.i.a); `check_rand(derived, derived.i.b); @@ -136,6 +163,9 @@ module t (/*AUTOARG*/); `check_rand(other, other.str.s.a); `check_rand(other, other.str.s.b); `check_rand(other, other.str.s.c); + `check_rand(der_int, der_int.a); + `check_rand(der_contain, der_contain.cls1.a); + `check_rand(der_contain, der_contain.a); $write("*-* All Finished *-*\n"); $finish; diff --git a/test_regress/t/t_randomize_method_types_unsup.out b/test_regress/t/t_randomize_method_types_unsup.out index 175d8a134..331acdcd8 100644 --- a/test_regress/t/t_randomize_method_types_unsup.out +++ b/test_regress/t/t_randomize_method_types_unsup.out @@ -1,18 +1,22 @@ -%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:12:13: Unsupported: random member variables with type 'int[string]' +%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:12:13: Unsupported: random member variable with type 'int[string]' : ... In instance t 12 | rand int assocarr[string]; | ^~~~~~~~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:13:13: Unsupported: random member variables with type 'int[]' +%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:13:13: Unsupported: random member variable with type 'int[]' : ... In instance t 13 | rand int dynarr[]; | ^~~~~~ -%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:14:13: Unsupported: random member variables with type 'int$[0:4]' +%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:14:13: Unsupported: random member variable with type 'int$[0:4]' : ... In instance t 14 | rand int unpackarr[5]; | ^~~~~~~~~ -%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:15:15: Unsupported: random member variables with type '$unit::Union' +%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:15:15: Unsupported: random member variable with type '$unit::Union' : ... In instance t 15 | rand Union uni; | ^~~ +%Error-UNSUPPORTED: t/t_randomize_method_types_unsup.v:16:13: Unsupported: random member variable with type of a current class + : ... In instance t + 16 | rand Cls cls; + | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_randomize_method_types_unsup.v b/test_regress/t/t_randomize_method_types_unsup.v index 1595a6c07..fb3fd938d 100644 --- a/test_regress/t/t_randomize_method_types_unsup.v +++ b/test_regress/t/t_randomize_method_types_unsup.v @@ -13,6 +13,7 @@ class Cls; rand int dynarr[]; rand int unpackarr[5]; rand Union uni; + rand Cls cls; endclass module t (/*AUTOARG*/); From 046fecbb350785ae9bc2217a3e1f970f370c4ece Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 15 Mar 2023 20:49:59 -0400 Subject: [PATCH 046/155] Fix fclose(0). --- src/V3AstNodeExpr.h | 2 ++ src/V3EmitCFunc.h | 2 -- test_regress/t/t_sys_file_basic.v | 3 --- test_regress/t/t_sys_file_zero.pl | 21 ++++++++++++++++ test_regress/t/t_sys_file_zero.v | 42 +++++++++++++++++++++++++++++++ 5 files changed, 65 insertions(+), 5 deletions(-) create mode 100755 test_regress/t/t_sys_file_zero.pl create mode 100644 test_regress/t/t_sys_file_zero.v diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index bf688422d..eb0820eb4 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -1109,6 +1109,7 @@ public: string emitC() override { V3ERROR_NA_RETURN(""); } bool cleanOut() const override { return true; } int instrCount() const override { return widthInstrs() * 64; } + bool isPredictOptimizable() const override { return false; } bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering bool same(const AstNode* /*samep*/) const override { return true; } }; @@ -2404,6 +2405,7 @@ public: bool sizeMattersLhs() const override { return false; } bool sizeMattersRhs() const override { return false; } int instrCount() const override { return widthInstrs() * 64; } + bool isPredictOptimizable() const override { return false; } bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering AstNode* filep() const { return lhsp(); } AstNode* charp() const { return rhsp(); } diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 808fb7e17..936196abc 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -715,8 +715,6 @@ public: puts("VL_FCLOSE_I("); iterateAndNextNull(nodep->filep()); puts("); "); - iterateAndNextNull(nodep->filep()); // For safety, so user doesn't later WRITE with it. - puts(" = 0;\n"); } void visit(AstFFlush* nodep) override { if (!nodep->filep()) { diff --git a/test_regress/t/t_sys_file_basic.v b/test_regress/t/t_sys_file_basic.v index 35a0d54a8..7a0f0bda6 100644 --- a/test_regress/t/t_sys_file_basic.v +++ b/test_regress/t/t_sys_file_basic.v @@ -74,10 +74,7 @@ module t; $fflush; $fclose(file); -`ifdef verilator - if (file != 0) $stop(1); // Also test arguments to stop $fwrite(file, "Never printed, file closed\n"); -`endif begin // Check for opening errors diff --git a/test_regress/t/t_sys_file_zero.pl b/test_regress/t/t_sys_file_zero.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_sys_file_zero.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 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); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_sys_file_zero.v b/test_regress/t/t_sys_file_zero.v new file mode 100644 index 000000000..252bf268b --- /dev/null +++ b/test_regress/t/t_sys_file_zero.v @@ -0,0 +1,42 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2003 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); + +module t; + int i; + int v; + string s; + reg [100*8:1] letterl; + + initial begin + // Display formatting + $fwrite(0, "Never printed, file closed\n"); + i = $feof(0); + if (i == 0) $stop; + $fflush(0); + $fclose(0); + i = $ferror(0, letterl); + i = $fgetc(0); + `checkd(i, -1); + i = $ungetc(0, 0); + `checkd(i, -1); + i = $fgets(letterl, 0); + `checkd(i, 0); + i = $fscanf(0, "%x", v); + `checkd(i, -1); + i = $ftell(0); + `checkd(i, -1); + i = $rewind(0); + `checkd(i, -1); + i = $fseek(0, 10, 0); + `checkd(i, -1); + + $write("*-* All Finished *-*\n"); + $finish(0); // Test arguments to finish + end + +endmodule From 45690faea7832978f85d714f75b7a47fd1fd7389 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 15 Mar 2023 21:04:10 -0400 Subject: [PATCH 047/155] Parse defparam = as unsupported --- src/verilog.y | 2 + test_regress/t/t_gen_defparam_multi.out | 17 ++++++ ...m_unsup_bad.pl => t_gen_defparam_multi.pl} | 0 test_regress/t/t_gen_defparam_multi.v | 59 +++++++++++++++++++ test_regress/t/t_gen_defparam_unsup_bad.out | 8 --- test_regress/t/t_gen_defparam_unsup_bad.v | 18 ------ 6 files changed, 78 insertions(+), 26 deletions(-) create mode 100644 test_regress/t/t_gen_defparam_multi.out rename test_regress/t/{t_gen_defparam_unsup_bad.pl => t_gen_defparam_multi.pl} (100%) create mode 100644 test_regress/t/t_gen_defparam_multi.v delete mode 100644 test_regress/t/t_gen_defparam_unsup_bad.out delete mode 100644 test_regress/t/t_gen_defparam_unsup_bad.v diff --git a/src/verilog.y b/src/verilog.y index 33288f922..d98a33172 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -3095,6 +3095,8 @@ list_of_defparam_assignments: //== IEEE: list_of_defparam_assignments defparam_assignment: // ==IEEE: defparam_assignment idAny '.' idAny '=' expr { $$ = new AstDefParam{$4, *$1, *$3, $5}; } + | idAny '=' expr + { $$ = nullptr; BBUNSUP($2, "Unsupported: defparam with no dot"); } | idAny '.' idAny '.' { $$ = nullptr; BBUNSUP($4, "Unsupported: defparam with more than one dot"); } ; diff --git a/test_regress/t/t_gen_defparam_multi.out b/test_regress/t/t_gen_defparam_multi.out new file mode 100644 index 000000000..8b751017c --- /dev/null +++ b/test_regress/t/t_gen_defparam_multi.out @@ -0,0 +1,17 @@ +%Error-UNSUPPORTED: t/t_gen_defparam_multi.v:14:17: Unsupported: defparam with no dot + 14 | defparam PAR = 5; + | ^ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_gen_defparam_multi.v:39:24: Unsupported: defparam with more than one dot + 39 | defparam m2.m3.PAR3 = 80; + | ^ +%Error: t/t_gen_defparam_multi.v:39:25: syntax error, unexpected IDENTIFIER, expecting ',' or ';' + 39 | defparam m2.m3.PAR3 = 80; + | ^~~~ +%Error-UNSUPPORTED: t/t_gen_defparam_multi.v:44:24: Unsupported: defparam with more than one dot + 44 | defparam m2.m3.PAR3 = 40; + | ^ +%Error: t/t_gen_defparam_multi.v:44:25: syntax error, unexpected IDENTIFIER, expecting ',' or ';' + 44 | defparam m2.m3.PAR3 = 40; + | ^~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_gen_defparam_unsup_bad.pl b/test_regress/t/t_gen_defparam_multi.pl similarity index 100% rename from test_regress/t/t_gen_defparam_unsup_bad.pl rename to test_regress/t/t_gen_defparam_multi.pl diff --git a/test_regress/t/t_gen_defparam_multi.v b/test_regress/t/t_gen_defparam_multi.v new file mode 100644 index 000000000..8f4642bc7 --- /dev/null +++ b/test_regress/t/t_gen_defparam_multi.v @@ -0,0 +1,59 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2012 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + parameter PAR = 3; + + defparam PAR = 5; + + wire [31:0] o2a, o2b, o3a, o3b; + + m1 #(0) m1a(.o2(o2a), .o3(o3a)); + m1 #(1) m1b(.o2(o2b), .o3(o3b)); + + always @ (posedge clk) begin + if (PAR != 5) $stop; + if (o2a != 8) $stop; + if (o2b != 4) $stop; + if (o3a != 80) $stop; + if (o3b != 40) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule + +module m1 (output wire [31:0] o2, + output wire [31:0] o3); + parameter W = 0; + generate + if (W == 0) begin + m2 m2 (.*); + defparam m2.PAR2 = 8; + defparam m2.m3.PAR3 = 80; + end + else begin + m2 m2 (.*); + defparam m2.PAR2 = 4; + defparam m2.m3.PAR3 = 40; + end + endgenerate +endmodule + +module m2 (output wire [31:0] o2, + output wire [31:0] o3); + parameter PAR2 = 20; + assign o2 = PAR2; + m3 m3 (.*); +endmodule + +module m3 (output wire [31:0] o3); + parameter PAR3 = 40; + assign o3 = PAR3; +endmodule diff --git a/test_regress/t/t_gen_defparam_unsup_bad.out b/test_regress/t/t_gen_defparam_unsup_bad.out deleted file mode 100644 index 97a834b03..000000000 --- a/test_regress/t/t_gen_defparam_unsup_bad.out +++ /dev/null @@ -1,8 +0,0 @@ -%Error-UNSUPPORTED: t/t_gen_defparam_unsup_bad.v:9:16: Unsupported: defparam with more than one dot - 9 | defparam a.b.W = 3; - | ^ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error: t/t_gen_defparam_unsup_bad.v:9:17: syntax error, unexpected IDENTIFIER, expecting ',' or ';' - 9 | defparam a.b.W = 3; - | ^ -%Error: Exiting due to diff --git a/test_regress/t/t_gen_defparam_unsup_bad.v b/test_regress/t/t_gen_defparam_unsup_bad.v deleted file mode 100644 index 2d2842552..000000000 --- a/test_regress/t/t_gen_defparam_unsup_bad.v +++ /dev/null @@ -1,18 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2012 by Wilson Snyder. -// SPDX-License-Identifier: CC0-1.0 - -module t (/*AUTOARG*/); - a a (); - defparam a.b.W = 3; -endmodule - -module a; - b b(); -endmodule - -module b; - parameter W = 0; -endmodule From 36da6a35636bcb47194d6a648fee660db72af9e7 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 15 Mar 2023 21:22:28 -0400 Subject: [PATCH 048/155] Fix parsing #1_2 delays --- src/verilog.l | 5 ++++- test_regress/t/t_timing_events.v | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/verilog.l b/src/verilog.l index 8755dd3d8..985f89b6a 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -913,7 +913,10 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} /* "# 1'b0" is a delay value so must lex as "#" "1" "'b0" */ if (PARSEP->lexPrevToken()=='#') { int shortlen = 0; - while (std::isdigit(yytext[shortlen])) ++shortlen; + if (std::isdigit(yytext[shortlen])) { + while (std::isdigit(yytext[shortlen]) + || yytext[shortlen]=='_') ++shortlen; + } if (shortlen) { // Push rest past numbers for later parse PARSEP->lexUnputString(yytext + shortlen, yyleng - shortlen); diff --git a/test_regress/t/t_timing_events.v b/test_regress/t/t_timing_events.v index 24065256b..b9ae56964 100644 --- a/test_regress/t/t_timing_events.v +++ b/test_regress/t/t_timing_events.v @@ -28,6 +28,13 @@ module t; $finish; end + int x; + initial begin + x = # 1_1 'd 12_34; // Checks we parse _ correctly + if (x != 1234) $stop; + if ($time != 11) $stop; + end + initial #21 $stop; // timeout endmodule From 8ae79066a2f8397cb76e6e9fcdce1da1d1817493 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 15 Mar 2023 21:56:35 -0400 Subject: [PATCH 049/155] Fix false ENUMVALUE on expressions and arrays. --- Changes | 1 + src/V3Ast.cpp | 4 +++- test_regress/t/t_0.pl | 21 +++++++++++++++++++++ test_regress/t/t_0.v | 21 +++++++++++++++++++++ test_regress/t/t_enum.v | 10 ++++++++++ 5 files changed, 56 insertions(+), 1 deletion(-) create mode 100755 test_regress/t/t_0.pl create mode 100644 test_regress/t/t_0.v diff --git a/Changes b/Changes index b3da19ca6..a5a130b79 100644 --- a/Changes +++ b/Changes @@ -21,6 +21,7 @@ Verilator 5.009 devel * Fix UNDRIVEN warning seg fault (#3989). [Felix Neumärker] * Fix symbol entries when inheriting classes (#3995) (#3996). [Krzysztof Bieganski, Antmicro Ltd] * Fix push to dynamic queue in struct (#4015). [ezchi] +* Fix false ENUMVALUE on expressions and arrays. Verilator 5.008 2023-03-04 diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index db5722c64..8b8fcc7f3 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -1342,7 +1342,9 @@ void AstNode::dtypeChgWidthSigned(int width, int widthMin, VSigning numeric) { dtypeSetLogicUnsized(width, widthMin, numeric); } else { if (width == dtypep()->width() && widthMin == dtypep()->widthMin() - && numeric == dtypep()->numeric()) + && numeric == dtypep()->numeric() + // Enums need to become direct sizes to avoid later ENUMVALUE errors + && !VN_IS(dtypep()->skipRefToEnump(), EnumDType)) return; // Correct already // FUTURE: We may be pointing at a two state data type, and this may // convert it to logic. Since the AstVar remains correct, we diff --git a/test_regress/t/t_0.pl b/test_regress/t/t_0.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_0.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 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); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_0.v b/test_regress/t/t_0.v new file mode 100644 index 000000000..0d26d323e --- /dev/null +++ b/test_regress/t/t_0.v @@ -0,0 +1,21 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2009 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + + enum int unsigned { + FIVE_INT = 5 + } FI; + + int array5i[FIVE_INT]; + + initial begin + if ($size(array5i) != 5) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_enum.v b/test_regress/t/t_enum.v index 2182ce9de..887866a37 100644 --- a/test_regress/t/t_enum.v +++ b/test_regress/t/t_enum.v @@ -31,10 +31,17 @@ module t (/*AUTOARG*/); z5 = e5 } ZN; + enum int unsigned { + FIVE_INT = 5 + } FI; + typedef enum three_t; // Forward typedef enum [2:0] { ONES=~0 } three_t; three_t three = ONES; + int array5[z5]; + int array5i[FIVE_INT]; + var logic [ONES:0] sized_based_on_enum; var enum logic [3:0] { QINVALID='1, QSEND={2'b0,2'h0}, QOP={2'b0,2'h1}, QCL={2'b0,2'h2}, @@ -76,6 +83,9 @@ module t (/*AUTOARG*/); if (QACK != 4) $stop; if (QRSP != 5) $stop; + if ($size(array5) != 5) $stop; + if ($size(array5i) != 5) $stop; + $write("*-* All Finished *-*\n"); $finish; end From 8e55580cde9b38988b3f45402c4b0d6c034f064a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 15 Mar 2023 22:11:06 -0400 Subject: [PATCH 050/155] Update include/gtkwave from upstream --- include/gtkwave/fstapi.c | 68 ++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 41 deletions(-) diff --git a/include/gtkwave/fstapi.c b/include/gtkwave/fstapi.c index 11cb0c501..a3c2dd6ff 100644 --- a/include/gtkwave/fstapi.c +++ b/include/gtkwave/fstapi.c @@ -58,6 +58,7 @@ #endif #ifdef __MINGW32__ +#define WIN32_LEAN_AND_MEAN #include #endif @@ -131,7 +132,7 @@ void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint3 #define FST_GZIO_LEN (32768) #define FST_HDR_FOURPACK_DUO_SIZE (4*1024*1024) -#if defined(__i386__) || defined(__x86_64__) || defined(_AIX) +#if defined(__i386__) || defined(__x86_64__) || defined(_AIX) || defined(__aarch64__) #define FST_DO_MISALIGNED_OPS #endif @@ -334,26 +335,22 @@ return(NULL); /* * mmap compatibility */ -#if defined __CYGWIN__ || defined __MINGW32__ +#if defined __MINGW32__ #include #define fstMmap(__addr,__len,__prot,__flags,__fd,__off) fstMmap2((__len), (__fd), (__off)) -#define fstMunmap(__addr,__len) free(__addr) +#define fstMunmap(__addr,__len) UnmapViewOfFile((LPCVOID)__addr) static void *fstMmap2(size_t __len, int __fd, fst_off_t __off) { -(void)__off; +HANDLE handle = CreateFileMapping((HANDLE)_get_osfhandle(__fd), NULL, + PAGE_READWRITE, (DWORD)(__len >> 32), + (DWORD)__len, NULL); +if (!handle) { return NULL; } -unsigned char *pnt = (unsigned char *)malloc(__len); -fst_off_t cur_offs = lseek(__fd, 0, SEEK_CUR); -size_t i; - -lseek(__fd, 0, SEEK_SET); -for(i=0;i<__len;i+=SSIZE_MAX) - { - read(__fd, pnt + i, ((__len - i) >= SSIZE_MAX) ? SSIZE_MAX : (__len - i)); - } -lseek(__fd, cur_offs, SEEK_SET); -return(pnt); +void *ptr = MapViewOfFileEx(handle, FILE_MAP_READ | FILE_MAP_WRITE, + 0, (DWORD)__off, (SIZE_T)__len, (LPVOID)NULL); +CloseHandle(handle); +return ptr; } #else #include @@ -984,14 +981,26 @@ fflush(xc->handle); */ static void fstWriterMmapSanity(void *pnt, const char *file, int line, const char *usage) { -#if !defined(__CYGWIN__) && !defined(__MINGW32__) -if(pnt == MAP_FAILED) +if(pnt == NULL +#ifdef MAP_FAILED + || pnt == MAP_FAILED +#endif + ) { fprintf(stderr, "fstMmap() assigned to %s failed: errno: %d, file %s, line %d.\n", usage, errno, file, line); +#if !defined(__MINGW32__) perror("Why"); +#else + LPSTR mbuf = NULL; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)&mbuf, 0, NULL); + fprintf(stderr, "%s", mbuf); + LocalFree(mbuf); +#endif pnt = NULL; } -#endif } @@ -1037,34 +1046,11 @@ if(!xc->curval_mem) static void fstDestroyMmaps(struct fstWriterContext *xc, int is_closing) { -#if !defined __CYGWIN__ && !defined __MINGW32__ (void)is_closing; -#endif fstMunmap(xc->valpos_mem, xc->maxhandle * 4 * sizeof(uint32_t)); xc->valpos_mem = NULL; -#if defined __CYGWIN__ || defined __MINGW32__ -if(xc->curval_mem) - { - if(!is_closing) /* need to flush out for next emulated mmap() read */ - { - unsigned char *pnt = xc->curval_mem; - int __fd = fileno(xc->curval_handle); - fst_off_t cur_offs = lseek(__fd, 0, SEEK_CUR); - size_t i; - size_t __len = xc->maxvalpos; - - lseek(__fd, 0, SEEK_SET); - for(i=0;i<__len;i+=SSIZE_MAX) - { - write(__fd, pnt + i, ((__len - i) >= SSIZE_MAX) ? SSIZE_MAX : (__len - i)); - } - lseek(__fd, cur_offs, SEEK_SET); - } - } -#endif - fstMunmap(xc->curval_mem, xc->maxvalpos); xc->curval_mem = NULL; } From 8f4d4f07a4b1783d16c3383d01c1abbbd51fe155 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 16 Mar 2023 07:09:16 -0400 Subject: [PATCH 051/155] Commentary --- Changes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Changes b/Changes index a5a130b79..bfe27ed5c 100644 --- a/Changes +++ b/Changes @@ -19,7 +19,7 @@ Verilator 5.009 devel * Support $fopen as an expression. * Change ZERODLY to a warning. * Fix UNDRIVEN warning seg fault (#3989). [Felix Neumärker] -* Fix symbol entries when inheriting classes (#3995) (#3996). [Krzysztof Bieganski, Antmicro Ltd] +* Fix symbol entries when inheriting classes (#3995) (#3996). [Krzysztof Boroński] * Fix push to dynamic queue in struct (#4015). [ezchi] * Fix false ENUMVALUE on expressions and arrays. From 66e4656a8ebb1d001e3a801e701c61599d917efa Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Thu, 16 Mar 2023 12:12:54 +0100 Subject: [PATCH 052/155] Fix event controls reusing same variable (#4014) --- src/V3SenExprBuilder.h | 8 +- .../t/t_event_control_prev_name_collision.pl | 22 +++++ .../t/t_event_control_prev_name_collision.v | 98 +++++++++++++++++++ 3 files changed, 126 insertions(+), 2 deletions(-) create mode 100755 test_regress/t/t_event_control_prev_name_collision.pl create mode 100644 test_regress/t/t_event_control_prev_name_collision.v diff --git a/src/V3SenExprBuilder.h b/src/V3SenExprBuilder.h index 7188b22fd..6b70e7d23 100644 --- a/src/V3SenExprBuilder.h +++ b/src/V3SenExprBuilder.h @@ -93,8 +93,12 @@ class SenExprBuilder final { FileLine* const flp = exprp->fileline(); const auto rdCurr = [=]() { return getCurr(exprp); }; + AstNode* scopeExprp = exprp; + if (AstVarRef* const refp = VN_CAST(exprp, VarRef)) { + scopeExprp = refp->varScopep()->varp(); + } // Create the 'previous value' variable - auto it = m_prev.find(*exprp); + auto it = m_prev.find(*scopeExprp); if (it == m_prev.end()) { // For readability, use the scoped signal name if the trigger is a simple AstVarRef string name; @@ -117,7 +121,7 @@ class SenExprBuilder final { prevp = new AstVarScope{flp, m_scopep, varp}; m_scopep->addVarsp(prevp); } - it = m_prev.emplace(*exprp, prevp).first; + it = m_prev.emplace(*scopeExprp, prevp).first; // Add the initializer init AstAssign* const initp = new AstAssign{flp, new AstVarRef{flp, prevp, VAccess::WRITE}, diff --git a/test_regress/t/t_event_control_prev_name_collision.pl b/test_regress/t/t_event_control_prev_name_collision.pl new file mode 100755 index 000000000..0fa78eb28 --- /dev/null +++ b/test_regress/t/t_event_control_prev_name_collision.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 2003 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); + +compile( + verilator_flags2 => ["-fno-inline"], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_event_control_prev_name_collision.v b/test_regress/t/t_event_control_prev_name_collision.v new file mode 100644 index 000000000..2b95b86c5 --- /dev/null +++ b/test_regress/t/t_event_control_prev_name_collision.v @@ -0,0 +1,98 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 +module S( + input reset, + io_i, + output io_o +); + reg s; + always @(posedge reset) begin + if (reset) begin + s <= 1'h0; + end + else begin + s <= io_i; + end + end + assign io_o = s; +endmodule + +module Q( + input reset_e, + input reset_d, + output ready_e +); + + wire reset_n; + wire io_v; + wire io_e; + S e ( + .io_i (), + .reset (reset_e | ~reset_n), + .io_o (io_e) + ); + S v ( + .io_i (io_e), + .reset (reset_e), + .io_o (io_v) + ); + assign reset_n = ~reset_d; + assign ready_e = io_v; +endmodule + +module Test( + input reset, + output valid +); + wire ready_e; + + Q q ( + .reset_e (reset), + .reset_d (reset), + .ready_e (ready_e) + ); + + assign valid = ready_e; +endmodule + +module Test2( + input reset, + input valid +); + always begin + if (~reset & valid) begin + $fatal; + end + end +endmodule + +module Dut( + input reset +); + wire valid_g; + + Test t ( + .reset (reset), + .valid (valid_g) + ); + Test2 t2 ( + .reset (reset), + .valid (valid_g) + ); +endmodule + +module t (/*AUTOARG*/ + ); + reg [$bits(dut.reset)-1:0] reset; + + Dut dut ( + .reset(reset) + ); + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From a9b07fe7d763380e98118a859e53aeffdc35ac55 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 16 Mar 2023 18:44:28 -0400 Subject: [PATCH 053/155] Tests: Remove unintended t_0 test --- test_regress/t/t_0.pl | 21 --------------------- test_regress/t/t_0.v | 21 --------------------- 2 files changed, 42 deletions(-) delete mode 100755 test_regress/t/t_0.pl delete mode 100644 test_regress/t/t_0.v diff --git a/test_regress/t/t_0.pl b/test_regress/t/t_0.pl deleted file mode 100755 index b46d46042..000000000 --- a/test_regress/t/t_0.pl +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env perl -if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } -# DESCRIPTION: Verilator: Verilog Test driver/expect definition -# -# Copyright 2003 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); - -compile( - ); - -execute( - check_finished => 1, - ); - -ok(1); -1; diff --git a/test_regress/t/t_0.v b/test_regress/t/t_0.v deleted file mode 100644 index 0d26d323e..000000000 --- a/test_regress/t/t_0.v +++ /dev/null @@ -1,21 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2009 by Wilson Snyder. -// SPDX-License-Identifier: CC0-1.0 - -module t (/*AUTOARG*/); - - enum int unsigned { - FIVE_INT = 5 - } FI; - - int array5i[FIVE_INT]; - - initial begin - if ($size(array5i) != 5) $stop; - $write("*-* All Finished *-*\n"); - $finish; - end - -endmodule From b2ced6ff1d931315f25c9fca58b99fde916de350 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 16 Mar 2023 19:42:13 -0400 Subject: [PATCH 054/155] Add more debug info to --report-unoptflat graph (#4039) --- src/V3SchedAcyclic.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/V3SchedAcyclic.cpp b/src/V3SchedAcyclic.cpp index 5e085f59d..412ac0070 100644 --- a/src/V3SchedAcyclic.cpp +++ b/src/V3SchedAcyclic.cpp @@ -68,12 +68,16 @@ public: : V3GraphVertex{graphp} , m_logicp{logicp} , m_scopep{scopep} {} + virtual V3GraphVertex* clone(V3Graph* graphp) const { + return new LogicVertex{graphp, logicp(), scopep()}; + } + AstNode* logicp() const { return m_logicp; } AstScope* scopep() const { return m_scopep; } // LCOV_EXCL_START // Debug code string name() const override { return m_logicp->fileline()->ascii(); }; - string dotShape() const override { return "rectangle"; } + string dotShape() const override { return "rectangle2"; } // LCOV_EXCL_STOP }; @@ -86,6 +90,7 @@ public: , m_vscp{vscp} {} AstVarScope* vscp() const { return m_vscp; } AstVar* varp() const { return m_vscp->varp(); } + virtual V3GraphVertex* clone(V3Graph* graphp) const { return new VarVertex{graphp, vscp()}; } // LCOV_EXCL_START // Debug code string name() const override { return m_vscp->name(); } From bbf53bd5af9bf4df6c644f0d03d0f6e97e4f73f4 Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Fri, 17 Mar 2023 00:48:56 +0100 Subject: [PATCH 055/155] Add VL_MT_SAFE attribute to several functions. (#3729) --- include/verilatedos.h | 7 ++ nodist/clang_check_attributes | 39 ++++++ src/V3Ast.cpp | 4 +- src/V3Ast.h | 68 +++++------ src/V3AstInlines.h | 26 ++-- src/V3AstNodeDType.h | 165 ++++++++++++++------------ src/V3AstNodeExpr.h | 6 +- src/V3AstNodeOther.h | 20 ++-- src/V3AstNodes.cpp | 8 +- src/V3EmitCBase.h | 8 +- src/V3Error.h | 2 +- src/V3File.cpp | 3 +- src/V3File.h | 4 +- src/V3FileLine.cpp | 2 +- src/V3FileLine.h | 12 +- src/V3Global.h | 2 +- src/V3Hash.cpp | 2 +- src/V3Hash.h | 2 +- src/V3Number.cpp | 22 ++-- src/V3Number.h | 28 ++--- src/V3Options.cpp | 4 +- src/V3Options.h | 4 +- src/V3Os.cpp | 4 +- src/V3Os.h | 7 +- src/V3String.cpp | 14 ++- src/V3String.h | 13 +- src/astgen | 10 +- test_regress/t/t_a5_attributes_src.pl | 2 +- 28 files changed, 279 insertions(+), 209 deletions(-) diff --git a/include/verilatedos.h b/include/verilatedos.h index 7efd61e21..da40b1edd 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -160,6 +160,13 @@ #else # define VL_MT_SAFE #endif +// Comment tag that function is threadsafe, only if +// other threads doesn't change tree topology +#if defined(__clang__) +# define VL_MT_STABLE __attribute__((annotate("MT_STABLE"))) +#else +# define VL_MT_STABLE +#endif // Comment tag that function is threadsafe, only // during normal operation (post-init) #if defined(__clang__) diff --git a/nodist/clang_check_attributes b/nodist/clang_check_attributes index 5c6aec2df..dba884b49 100755 --- a/nodist/clang_check_attributes +++ b/nodist/clang_check_attributes @@ -37,6 +37,7 @@ def fully_qualified_name(node): class VlAnnotations: mt_start: bool = False mt_safe: bool = False + stable_tree: bool = False mt_safe_postinit: bool = False mt_unsafe: bool = False mt_unsafe_one: bool = False @@ -54,6 +55,9 @@ class VlAnnotations: def is_pure_context(self): return self.pure + def is_stabe_tree_context(self): + return self.stable_tree + def is_mt_unsafe_call(self): return self.mt_unsafe or self.mt_unsafe_one @@ -66,6 +70,9 @@ class VlAnnotations: def is_pure_call(self): return self.pure + def is_stabe_tree_call(self): + return self.stable_tree + def __or__(self, other: "VlAnnotations"): result = VlAnnotations() for key, value in dataclasses.asdict(self).items(): @@ -94,6 +101,8 @@ class VlAnnotations: result.mt_start = True elif node.displayname == "MT_SAFE": result.mt_safe = True + elif node.displayname == "MT_STABLE": + result.stable_tree = True elif node.displayname == "MT_SAFE_POSTINIT": result.mt_safe_postinit = True elif node.displayname == "MT_UNSAFE": @@ -196,6 +205,7 @@ class DiagnosticKind(Enum): ANNOTATIONS_DEF_DECL_MISMATCH = enum.auto() NON_PURE_CALL_IN_PURE_CTX = enum.auto() NON_MT_SAFE_CALL_IN_MT_SAFE_CTX = enum.auto() + NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX = enum.auto() def __lt__(self, other): return self.value < other.value @@ -377,6 +387,16 @@ class CallAnnotationsValidator: FunctionInfo.from_node(refd, refd, annotations), DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX) + # stable tree context + if ctx.is_stabe_tree_context(): + if not (annotations.is_stabe_tree_call() + or annotations.is_pure_call() + or self.check_mt_safe_call(node, refd, annotations)): + self.emit_diagnostic( + FunctionInfo.from_node(refd, refd, annotations), + DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX) + + # pure context if ctx.is_pure_context(): if not annotations.is_pure_call(): self.emit_diagnostic( @@ -394,6 +414,16 @@ class CallAnnotationsValidator: self.emit_diagnostic( FunctionInfo.from_node(refd, refd, annotations), DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX) + + # stable tree context + if ctx.is_stabe_tree_context(): + if not (annotations.is_pure_call() + or annotations.is_mt_safe_call() + or annotations.is_stabe_tree_call()): + self.emit_diagnostic( + FunctionInfo.from_node(refd, refd, annotations), + DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX) + # pure context if ctx.is_pure_context(): if not annotations.is_pure_call(): @@ -414,6 +444,13 @@ class CallAnnotationsValidator: self.dispatch_node_inside_definition) self._constructor_context -= 1 + # stable tree context + if ctx.is_stabe_tree_context(): + self._constructor_context += 1 + self.iterate_children(refd.get_children(), + self.dispatch_node_inside_definition) + self._constructor_context -= 1 + # pure context if ctx.is_pure_context(): if not annotations.is_pure_call( @@ -788,6 +825,8 @@ class TopDownSummaryPrinter(): name += "is mtsafe but calls non-mtsafe function(s)" elif func.reason == DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX: name += "is pure but calls non-pure function(s)" + elif func.reason == DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX: + name += "calls stable_tree function(s) but isn't annotated as stable_tree" else: name += "for unknown reason (please add description)" diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 8b8fcc7f3..49d1a0434 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -155,7 +155,7 @@ string AstNode::vcdName(const string& namein) { return prettyName(pretty); } -string AstNode::prettyName(const string& namein) { +string AstNode::prettyName(const string& namein) VL_PURE { // This function is somewhat hot, so we short-circuit some compares string pretty; pretty.reserve(namein.length()); @@ -1079,7 +1079,7 @@ bool AstNode::sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ig //====================================================================== // Debugging -void AstNode::checkTreeIter(const AstNode* prevBackp) const { +void AstNode::checkTreeIter(const AstNode* prevBackp) const VL_MT_STABLE { // private: Check a tree and children UASSERT_OBJ(prevBackp == this->backp(), this, "Back node inconsistent"); switch (this->type()) { diff --git a/src/V3Ast.h b/src/V3Ast.h index eb7d345f7..a325e5620 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -102,11 +102,11 @@ public: : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning constexpr operator en() const VL_MT_SAFE { return m_e; } }; -constexpr bool operator==(const VNType& lhs, const VNType& rhs) VL_MT_SAFE { +constexpr bool operator==(const VNType& lhs, const VNType& rhs) VL_PURE { return lhs.m_e == rhs.m_e; } -constexpr bool operator==(const VNType& lhs, VNType::en rhs) { return lhs.m_e == rhs; } -constexpr bool operator==(VNType::en lhs, const VNType& rhs) { return lhs == rhs.m_e; } +constexpr bool operator==(const VNType& lhs, VNType::en rhs) VL_PURE { return lhs.m_e == rhs; } +constexpr bool operator==(VNType::en lhs, const VNType& rhs) VL_PURE { return lhs == rhs.m_e; } inline std::ostream& operator<<(std::ostream& os, const VNType& rhs) { return os << rhs.ascii(); } // ###################################################################### @@ -1545,7 +1545,7 @@ class AstNode VL_NOT_FINAL { private: AstNode* cloneTreeIter(); AstNode* cloneTreeIterList(); - void checkTreeIter(const AstNode* prevBackp) const VL_MT_SAFE; + void checkTreeIter(const AstNode* prevBackp) const VL_MT_STABLE; bool gateTreeIter() const; static bool sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ignNext, bool gateOnly); @@ -1601,14 +1601,14 @@ public: // ACCESSORS VNType type() const VL_MT_SAFE { return m_type; } const char* typeName() const VL_MT_SAFE { return type().ascii(); } // See also prettyTypeName - AstNode* nextp() const VL_MT_SAFE { return m_nextp; } - AstNode* backp() const VL_MT_SAFE { return m_backp; } + AstNode* nextp() const VL_MT_STABLE { return m_nextp; } + AstNode* backp() const VL_MT_STABLE { return m_backp; } AstNode* abovep() const; // Parent node above, only when no nextp() as otherwise slow - AstNode* op1p() const VL_MT_SAFE { return m_op1p; } - AstNode* op2p() const VL_MT_SAFE { return m_op2p; } - AstNode* op3p() const VL_MT_SAFE { return m_op3p; } - AstNode* op4p() const VL_MT_SAFE { return m_op4p; } - AstNodeDType* dtypep() const VL_MT_SAFE { return m_dtypep; } + AstNode* op1p() const VL_MT_STABLE { return m_op1p; } + AstNode* op2p() const VL_MT_STABLE { return m_op2p; } + AstNode* op3p() const VL_MT_STABLE { return m_op3p; } + AstNode* op4p() const VL_MT_STABLE { return m_op4p; } + AstNodeDType* dtypep() const VL_MT_STABLE { return m_dtypep; } AstNode* clonep() const { return ((m_cloneCnt == s_cloneCntGbl) ? m_clonep : nullptr); } AstNode* firstAbovep() const { // Returns nullptr when second or later in list return ((backp() && backp()->nextp() != this) ? backp() : nullptr); @@ -1663,11 +1663,11 @@ public: virtual void tag(const string& text) {} virtual string tag() const { return ""; } virtual string verilogKwd() const { return ""; } - string nameProtect() const VL_MT_SAFE; // Name with --protect-id applied + string nameProtect() const; // Name with --protect-id applied string origNameProtect() const; // origName with --protect-id applied string shortName() const; // Name with __PVT__ removed for concatenating scopes static string dedotName(const string& namein); // Name with dots removed - static string prettyName(const string& namein); // Name for printing out to the user + static string prettyName(const string& namein) VL_PURE; // Name for printing out to the user static string vpiName(const string& namein); // Name for vpi access static string prettyNameQ(const string& namein) { // Quoted pretty name (for errors) return std::string{"'"} + prettyName(namein) + "'"; @@ -1697,25 +1697,25 @@ public: void protect(bool flag) { m_flags.protect = flag; } // TODO stomp these width functions out, and call via dtypep() instead - inline int width() const VL_MT_SAFE; + inline int width() const VL_MT_STABLE; inline int widthMin() const; int widthMinV() const { return v3Global.widthMinUsage() == VWidthMinUsage::VERILOG_WIDTH ? widthMin() : width(); } int widthWords() const { return VL_WORDS_I(width()); } - bool isQuad() const VL_MT_SAFE { return (width() > VL_IDATASIZE && width() <= VL_QUADSIZE); } - bool isWide() const VL_MT_SAFE { return (width() > VL_QUADSIZE); } - inline bool isDouble() const; - inline bool isSigned() const; - inline bool isString() const; + bool isQuad() const VL_MT_STABLE { return (width() > VL_IDATASIZE && width() <= VL_QUADSIZE); } + bool isWide() const VL_MT_STABLE { return (width() > VL_QUADSIZE); } + inline bool isDouble() const VL_MT_STABLE; + inline bool isSigned() const VL_MT_STABLE; + inline bool isString() const VL_MT_STABLE; // clang-format off - VNUser user1u() const VL_MT_SAFE { + VNUser user1u() const VL_MT_STABLE { // Slows things down measurably, so disabled by default //UASSERT_STATIC(VNUser1InUse::s_userBusy, "userp set w/o busy"); return ((m_user1Cnt==VNUser1InUse::s_userCntGbl) ? m_user1u : VNUser{0}); } - AstNode* user1p() const VL_MT_SAFE { return user1u().toNodep(); } + AstNode* user1p() const VL_MT_STABLE { return user1u().toNodep(); } void user1u(const VNUser& user) { m_user1u=user; m_user1Cnt=VNUser1InUse::s_userCntGbl; } void user1p(void* userp) { user1u(VNUser{userp}); } int user1() const { return user1u().toInt(); } @@ -1724,12 +1724,12 @@ public: int user1SetOnce() { int v=user1(); if (!v) user1(1); return v; } // Better for cache than user1Inc() static void user1ClearTree() { VNUser1InUse::clear(); } // Clear userp()'s across the entire tree - VNUser user2u() const VL_MT_SAFE { + VNUser user2u() const VL_MT_STABLE { // Slows things down measurably, so disabled by default //UASSERT_STATIC(VNUser2InUse::s_userBusy, "userp set w/o busy"); return ((m_user2Cnt==VNUser2InUse::s_userCntGbl) ? m_user2u : VNUser{0}); } - AstNode* user2p() const VL_MT_SAFE { return user2u().toNodep(); } + AstNode* user2p() const VL_MT_STABLE { return user2u().toNodep(); } void user2u(const VNUser& user) { m_user2u=user; m_user2Cnt=VNUser2InUse::s_userCntGbl; } void user2p(void* userp) { user2u(VNUser{userp}); } int user2() const { return user2u().toInt(); } @@ -1738,12 +1738,12 @@ public: int user2SetOnce() { int v=user2(); if (!v) user2(1); return v; } // Better for cache than user2Inc() static void user2ClearTree() { VNUser2InUse::clear(); } // Clear userp()'s across the entire tree - VNUser user3u() const VL_MT_SAFE { + VNUser user3u() const VL_MT_STABLE { // Slows things down measurably, so disabled by default //UASSERT_STATIC(VNUser3InUse::s_userBusy, "userp set w/o busy"); return ((m_user3Cnt==VNUser3InUse::s_userCntGbl) ? m_user3u : VNUser{0}); } - AstNode* user3p() const VL_MT_SAFE { return user3u().toNodep(); } + AstNode* user3p() const VL_MT_STABLE { return user3u().toNodep(); } void user3u(const VNUser& user) { m_user3u=user; m_user3Cnt=VNUser3InUse::s_userCntGbl; } void user3p(void* userp) { user3u(VNUser{userp}); } int user3() const { return user3u().toInt(); } @@ -1752,12 +1752,12 @@ public: int user3SetOnce() { int v=user3(); if (!v) user3(1); return v; } // Better for cache than user3Inc() static void user3ClearTree() { VNUser3InUse::clear(); } // Clear userp()'s across the entire tree - VNUser user4u() const VL_MT_SAFE { + VNUser user4u() const VL_MT_STABLE { // Slows things down measurably, so disabled by default //UASSERT_STATIC(VNUser4InUse::s_userBusy, "userp set w/o busy"); return ((m_user4Cnt==VNUser4InUse::s_userCntGbl) ? m_user4u : VNUser{0}); } - AstNode* user4p() const VL_MT_SAFE { return user4u().toNodep(); } + AstNode* user4p() const VL_MT_STABLE { return user4u().toNodep(); } void user4u(const VNUser& user) { m_user4u=user; m_user4Cnt=VNUser4InUse::s_userCntGbl; } void user4p(void* userp) { user4u(VNUser{userp}); } int user4() const { return user4u().toInt(); } @@ -1766,12 +1766,12 @@ public: int user4SetOnce() { int v=user4(); if (!v) user4(1); return v; } // Better for cache than user4Inc() static void user4ClearTree() { VNUser4InUse::clear(); } // Clear userp()'s across the entire tree - VNUser user5u() const VL_MT_SAFE { + VNUser user5u() const VL_MT_STABLE { // Slows things down measurably, so disabled by default //UASSERT_STATIC(VNUser5InUse::s_userBusy, "userp set w/o busy"); return ((m_user5Cnt==VNUser5InUse::s_userCntGbl) ? m_user5u : VNUser{0}); } - AstNode* user5p() const VL_MT_SAFE { return user5u().toNodep(); } + AstNode* user5p() const VL_MT_STABLE { return user5u().toNodep(); } void user5u(const VNUser& user) { m_user5u=user; m_user5Cnt=VNUser5InUse::s_userCntGbl; } void user5p(void* userp) { user5u(VNUser{userp}); } int user5() const { return user5u().toInt(); } @@ -1907,7 +1907,7 @@ public: // Does tree of this == node2p?, not allowing non-isGateOptimizable inline bool sameGateTree(const AstNode* node2p) const; void deleteTree(); // Always deletes the next link - void checkTree() const VL_MT_SAFE { + void checkTree() const VL_MT_STABLE { if (v3Global.opt.debugCheck()) checkTreeIter(backp()); } void checkIter() const; @@ -1992,7 +1992,7 @@ private: // For internal use only. template - constexpr static bool uselessCast() { + constexpr static bool uselessCast() VL_PURE { using NonRef = typename std::remove_reference::type; using NonPtr = typename std::remove_pointer::type; using NonCV = typename std::remove_cv::type; @@ -2001,7 +2001,7 @@ private: // For internal use only. template - constexpr static bool impossibleCast() { + constexpr static bool impossibleCast() VL_PURE { using NonRef = typename std::remove_reference::type; using NonPtr = typename std::remove_pointer::type; using NonCV = typename std::remove_cv::type; @@ -2035,7 +2035,7 @@ public: // For use via the VN_AS macro only template - static T* privateAs(AstNode* nodep) VL_MT_SAFE { + static T* privateAs(AstNode* nodep) VL_PURE { static_assert(!uselessCast(), "Unnecessary VN_AS, node known to have target type."); static_assert(!impossibleCast(), "Unnecessary VN_AS, node cannot be this type."); UASSERT_OBJ(!nodep || privateTypeTest(nodep), nodep, @@ -2044,7 +2044,7 @@ public: return reinterpret_cast(nodep); } template - static const T* privateAs(const AstNode* nodep) VL_MT_SAFE { + static const T* privateAs(const AstNode* nodep) VL_PURE { static_assert(!uselessCast(), "Unnecessary VN_AS, node known to have target type."); static_assert(!impossibleCast(), "Unnecessary VN_AS, node cannot be this type."); UASSERT_OBJ(!nodep || privateTypeTest(nodep), nodep, diff --git a/src/V3AstInlines.h b/src/V3AstInlines.h index 79023761b..31bb603c9 100644 --- a/src/V3AstInlines.h +++ b/src/V3AstInlines.h @@ -25,7 +25,7 @@ //###################################################################### // Inline METHODS -int AstNode::width() const { return dtypep() ? dtypep()->width() : 0; } +int AstNode::width() const VL_MT_STABLE { return dtypep() ? dtypep()->width() : 0; } int AstNode::widthMin() const { return dtypep() ? dtypep()->widthMin() : 0; } bool AstNode::width1() const { // V3Const uses to know it can optimize return dtypep() && dtypep()->width() == 1; @@ -33,13 +33,13 @@ bool AstNode::width1() const { // V3Const uses to know it can optimize int AstNode::widthInstrs() const { return (!dtypep() ? 1 : (dtypep()->isWide() ? dtypep()->widthWords() : 1)); } -bool AstNode::isDouble() const VL_MT_SAFE { +bool AstNode::isDouble() const VL_MT_STABLE { return dtypep() && VN_IS(dtypep(), BasicDType) && VN_AS(dtypep(), BasicDType)->isDouble(); } -bool AstNode::isString() const VL_MT_SAFE { +bool AstNode::isString() const VL_MT_STABLE { return dtypep() && dtypep()->basicp() && dtypep()->basicp()->isString(); } -bool AstNode::isSigned() const { return dtypep() && dtypep()->isSigned(); } +bool AstNode::isSigned() const VL_MT_STABLE { return dtypep() && dtypep()->isSigned(); } bool AstNode::isZero() const { return (VN_IS(this, Const) && VN_AS(this, Const)->num().isEqZero()); @@ -61,12 +61,12 @@ bool AstNode::sameGateTree(const AstNode* node2p) const { return sameTreeIter(this, node2p, true, true); } -int AstNodeArrayDType::left() const VL_MT_SAFE { return rangep()->leftConst(); } -int AstNodeArrayDType::right() const VL_MT_SAFE { return rangep()->rightConst(); } -int AstNodeArrayDType::hi() const VL_MT_SAFE { return rangep()->hiConst(); } -int AstNodeArrayDType::lo() const VL_MT_SAFE { return rangep()->loConst(); } -int AstNodeArrayDType::elementsConst() const VL_MT_SAFE { return rangep()->elementsConst(); } -VNumRange AstNodeArrayDType::declRange() const VL_MT_SAFE { return VNumRange{left(), right()}; } +int AstNodeArrayDType::left() const VL_MT_STABLE { return rangep()->leftConst(); } +int AstNodeArrayDType::right() const VL_MT_STABLE { return rangep()->rightConst(); } +int AstNodeArrayDType::hi() const VL_MT_STABLE { return rangep()->hiConst(); } +int AstNodeArrayDType::lo() const VL_MT_STABLE { return rangep()->loConst(); } +int AstNodeArrayDType::elementsConst() const VL_MT_STABLE { return rangep()->elementsConst(); } +VNumRange AstNodeArrayDType::declRange() const VL_MT_STABLE { return VNumRange{left(), right()}; } AstRange::AstRange(FileLine* fl, int left, int right) : ASTGEN_SUPER_Range(fl) { @@ -78,16 +78,16 @@ AstRange::AstRange(FileLine* fl, const VNumRange& range) leftp(new AstConst{fl, static_cast(range.left())}); rightp(new AstConst{fl, static_cast(range.right())}); } -int AstRange::leftConst() const { +int AstRange::leftConst() const VL_MT_STABLE { AstConst* const constp = VN_CAST(leftp(), Const); return (constp ? constp->toSInt() : 0); } -int AstRange::rightConst() const { +int AstRange::rightConst() const VL_MT_STABLE { AstConst* const constp = VN_CAST(rightp(), Const); return (constp ? constp->toSInt() : 0); } -int AstQueueDType::boundConst() const VL_MT_SAFE { +int AstQueueDType::boundConst() const VL_MT_STABLE { AstConst* const constp = VN_CAST(boundp(), Const); return (constp ? constp->toSInt() : 0); } diff --git a/src/V3AstNodeDType.h b/src/V3AstNodeDType.h index fd652f595..26f1a740e 100644 --- a/src/V3AstNodeDType.h +++ b/src/V3AstNodeDType.h @@ -63,9 +63,9 @@ public: // Integral or packed, allowed inside an unpacked union/struct virtual bool isIntegralOrPacked() const { return !isCompound(); } // (Slow) recurse down to find basic data type - virtual AstBasicDType* basicp() const = 0; + virtual AstBasicDType* basicp() const VL_MT_STABLE = 0; // recurses over typedefs/const/enum to next non-typeref type - virtual AstNodeDType* skipRefp() const = 0; + virtual AstNodeDType* skipRefp() const VL_MT_STABLE = 0; // recurses over typedefs to next non-typeref-or-const type virtual AstNodeDType* skipRefToConstp() const = 0; // recurses over typedefs/const to next non-typeref-or-enum/struct type @@ -86,7 +86,7 @@ public: // Assignable equivalence. Call skipRefp() on this and samep before calling virtual bool similarDType(const AstNodeDType* samep) const = 0; // Iff has a non-null subDTypep(), as generic node function - virtual AstNodeDType* subDTypep() const { return nullptr; } + virtual AstNodeDType* subDTypep() const VL_MT_SAFE { return nullptr; } virtual bool isFourstate() const; // Ideally an IEEE $typename virtual string prettyDTypeName() const { return prettyTypeName(); } @@ -126,12 +126,13 @@ public: const char* charIQWN() const { return (isString() ? "N" : isWide() ? "W" : isQuad() ? "Q" : "I"); } - string cType(const string& name, bool forFunc, bool isRef) const VL_MT_SAFE; - bool isLiteralType() const VL_MT_SAFE; // Represents a C++ LiteralType? (can be constexpr) + string cType(const string& name, bool forFunc, bool isRef) const VL_MT_STABLE; + // Represents a C++ LiteralType? (can be constexpr) + bool isLiteralType() const VL_MT_STABLE; private: class CTypeRecursed; - CTypeRecursed cTypeRecurse(bool compound) const VL_MT_SAFE; + CTypeRecursed cTypeRecurse(bool compound) const VL_MT_STABLE; }; class AstNodeArrayDType VL_NOT_FINAL : public AstNodeDType { // Array data type, ie "some_dtype var_name [2:0]" @@ -170,29 +171,29 @@ public: && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp())); } AstNodeDType* getChildDTypep() const override { return childDTypep(); } - AstNodeDType* subDTypep() const override VL_MT_SAFE { + AstNodeDType* subDTypep() const override VL_MT_STABLE { return m_refDTypep ? m_refDTypep : childDTypep(); } void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } // METHODS - AstBasicDType* basicp() const override VL_MT_SAFE { + AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type - AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; } + AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; } AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } int widthTotalBytes() const override { return elementsConst() * subDTypep()->widthTotalBytes(); } - inline int left() const; - inline int right() const; - inline int hi() const; - inline int lo() const; - inline int elementsConst() const; - inline VNumRange declRange() const; + inline int left() const VL_MT_STABLE; + inline int right() const VL_MT_STABLE; + inline int hi() const VL_MT_STABLE; + inline int lo() const VL_MT_STABLE; + inline int elementsConst() const VL_MT_STABLE; + inline VNumRange declRange() const VL_MT_STABLE; }; class AstNodeUOrStructDType VL_NOT_FINAL : public AstNodeDType { // A struct or union; common handling @@ -231,7 +232,7 @@ public: : VN_AS(findBitRangeDType(VNumRange{width() - 1, 0}, width(), numeric()), BasicDType)); } - AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; } + AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; } AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) @@ -248,7 +249,7 @@ public: // packed() but as don't support unpacked, presently all structs static bool packedUnsup() { return true; } void isFourstate(bool flag) { m_isFourstate = flag; } - bool isFourstate() const override { return m_isFourstate; } + bool isFourstate() const override VL_MT_SAFE { return m_isFourstate; } void clearCache() { m_members.clear(); } void repairMemberCache(); AstMemberDType* findMember(const string& name) const { @@ -336,7 +337,7 @@ public: void dumpSmall(std::ostream& str) const override; AstNodeDType* getChildDTypep() const override { return childDTypep(); } AstNodeDType* getChild2DTypep() const override { return keyChildDTypep(); } - AstNodeDType* subDTypep() const override VL_MT_SAFE { + AstNodeDType* subDTypep() const override VL_MT_STABLE { return m_refDTypep ? m_refDTypep : childDTypep(); } void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } @@ -345,13 +346,13 @@ public: AstNodeDType* virtRefDType2p() const override { return m_keyDTypep; } void virtRefDType2p(AstNodeDType* nodep) override { keyDTypep(nodep); } // - AstNodeDType* keyDTypep() const VL_MT_SAFE { + AstNodeDType* keyDTypep() const VL_MT_STABLE { return m_keyDTypep ? m_keyDTypep : keyChildDTypep(); } void keyDTypep(AstNodeDType* nodep) { m_keyDTypep = nodep; } // METHODS - AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; } - AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; } + AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; } + AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; } AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } @@ -423,8 +424,8 @@ public: } } // METHODS - AstBasicDType* basicp() const override VL_MT_SAFE { return (AstBasicDType*)this; } - AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; } + AstBasicDType* basicp() const override VL_MT_STABLE { return (AstBasicDType*)this; } + AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; } AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) @@ -491,13 +492,13 @@ public: } ASTGEN_MEMBERS_AstBracketArrayDType; bool similarDType(const AstNodeDType* samep) const override { V3ERROR_NA_RETURN(false); } - AstNodeDType* subDTypep() const override { return childDTypep(); } + AstNodeDType* subDTypep() const override VL_MT_STABLE { return childDTypep(); } // METHODS // Will be removed in V3Width, which relies on this // being a child not a dtype pointed node bool maybePointedTo() const override { return false; } - AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; } - AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; } + AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; } + AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; } AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } int widthAlignBytes() const override { V3ERROR_NA_RETURN(0); } @@ -531,15 +532,15 @@ public: void dump(std::ostream& str = std::cout) const override; void dumpSmall(std::ostream& str) const override; string name() const override; - AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; } - AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; } + AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; } + AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; } AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } int widthAlignBytes() const override { return 0; } int widthTotalBytes() const override { return 0; } AstNodeDType* virtRefDTypep() const override { return nullptr; } void virtRefDTypep(AstNodeDType* nodep) override {} - AstNodeDType* subDTypep() const override { return nullptr; } + AstNodeDType* subDTypep() const override VL_MT_SAFE { return nullptr; } AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } AstClass* classp() const { return m_classp; } @@ -578,13 +579,15 @@ public: return skipRefp()->similarDType(samep->skipRefp()); } AstNodeDType* getChildDTypep() const override { return childDTypep(); } - AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); } + AstNodeDType* subDTypep() const override VL_MT_STABLE { + return m_refDTypep ? m_refDTypep : childDTypep(); + } void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } // METHODS - AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); } - AstNodeDType* skipRefp() const override VL_MT_SAFE { return subDTypep()->skipRefp(); } + AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); } + AstNodeDType* skipRefp() const override VL_MT_STABLE { return subDTypep()->skipRefp(); } AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); } int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } @@ -625,13 +628,15 @@ public: return type() == samep->type() && same(samep); } AstNodeDType* getChildDTypep() const override { return childDTypep(); } - AstNodeDType* subDTypep() const override { return dtypep() ? dtypep() : childDTypep(); } + AstNodeDType* subDTypep() const override VL_MT_STABLE { + return dtypep() ? dtypep() : childDTypep(); + } void* containerp() const { return m_containerp; } // METHODS // op1 = Range of variable AstNodeDType* dtypeSkipRefp() const { return dtypep()->skipRefp(); } - AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); } - AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; } + AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); } + AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; } AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } int widthAlignBytes() const override { return dtypep()->widthAlignBytes(); } @@ -679,15 +684,15 @@ public: string prettyDTypeName() const override; void dumpSmall(std::ostream& str) const override; AstNodeDType* getChildDTypep() const override { return childDTypep(); } - AstNodeDType* subDTypep() const override VL_MT_SAFE { + AstNodeDType* subDTypep() const override VL_MT_STABLE { return m_refDTypep ? m_refDTypep : childDTypep(); } void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } // METHODS - AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; } - AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; } + AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; } + AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; } AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } @@ -706,13 +711,13 @@ public: bool hasDType() const override { return true; } bool maybePointedTo() const override { return true; } bool undead() const override { return true; } - AstNodeDType* subDTypep() const override { return nullptr; } + AstNodeDType* subDTypep() const override VL_MT_SAFE { return nullptr; } AstNodeDType* virtRefDTypep() const override { return nullptr; } void virtRefDTypep(AstNodeDType* nodep) override {} bool similarDType(const AstNodeDType* samep) const override { return this == samep; } - AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; } + AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; } // cppcheck-suppress csyleCast - AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; } + AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; } // cppcheck-suppress csyleCast AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } // cppcheck-suppress csyleCast @@ -756,7 +761,9 @@ public: } bool similarDType(const AstNodeDType* samep) const override { return this == samep; } AstNodeDType* getChildDTypep() const override { return childDTypep(); } - AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); } + AstNodeDType* subDTypep() const override VL_MT_STABLE { + return m_refDTypep ? m_refDTypep : childDTypep(); + } void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } @@ -765,8 +772,8 @@ public: void dump(std::ostream& str = std::cout) const override; void dumpSmall(std::ostream& str) const override; // METHODS - AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); } - AstNodeDType* skipRefp() const override VL_MT_SAFE { return subDTypep()->skipRefp(); } + AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); } + AstNodeDType* skipRefp() const override VL_MT_STABLE { return subDTypep()->skipRefp(); } AstNodeDType* skipRefToConstp() const override { return subDTypep()->skipRefToConstp(); } // cppcheck-suppress csyleCast AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } @@ -818,8 +825,8 @@ public: void dump(std::ostream& str = std::cout) const override; void dumpSmall(std::ostream& str) const override; void cloneRelink() override; - AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; } - AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; } + AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; } + AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; } AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } bool similarDType(const AstNodeDType* samep) const override { return this == samep; } @@ -883,7 +890,9 @@ public: if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); } AstNodeDType* getChildDTypep() const override { return childDTypep(); } - AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); } + AstNodeDType* subDTypep() const override VL_MT_STABLE { + return m_refDTypep ? m_refDTypep : childDTypep(); + } void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } @@ -891,10 +900,10 @@ public: // // (Slow) recurse down to find basic data type (Note don't need virtual - // AstVar isn't a NodeDType) - AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); } + AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); } // op1 = Range of variable (Note don't need virtual - AstVar isn't a NodeDType) AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } - AstNodeDType* skipRefp() const override VL_MT_SAFE { return subDTypep()->skipRefp(); } + AstNodeDType* skipRefp() const override VL_MT_STABLE { return subDTypep()->skipRefp(); } AstNodeDType* skipRefToConstp() const override { return subDTypep()->skipRefToConstp(); } AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); } // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this) @@ -931,9 +940,11 @@ public: ASTGEN_MEMBERS_AstParamTypeDType; void dump(std::ostream& str = std::cout) const override; AstNodeDType* getChildDTypep() const override { return childDTypep(); } - AstNodeDType* subDTypep() const override { return dtypep() ? dtypep() : childDTypep(); } - AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); } - AstNodeDType* skipRefp() const override VL_MT_SAFE { return subDTypep()->skipRefp(); } + AstNodeDType* subDTypep() const override VL_MT_STABLE { + return dtypep() ? dtypep() : childDTypep(); + } + AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); } + AstNodeDType* skipRefp() const override VL_MT_STABLE { return subDTypep()->skipRefp(); } AstNodeDType* skipRefToConstp() const override { return subDTypep()->skipRefToConstp(); } AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); } bool similarDType(const AstNodeDType* samep) const override { @@ -967,8 +978,8 @@ public: AstNodeDType* dtypep() const { return nullptr; } // METHODS bool similarDType(const AstNodeDType* samep) const override { return this == samep; } - AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; } - AstNodeDType* skipRefp() const override VL_MT_SAFE { return nullptr; } + AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; } + AstNodeDType* skipRefp() const override VL_MT_STABLE { return nullptr; } // cppcheck-suppress csyleCast AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } // cppcheck-suppress csyleCast @@ -1022,17 +1033,17 @@ public: void dumpSmall(std::ostream& str) const override; string prettyDTypeName() const override; AstNodeDType* getChildDTypep() const override { return childDTypep(); } - AstNodeDType* subDTypep() const override VL_MT_SAFE { + AstNodeDType* subDTypep() const override VL_MT_STABLE { return m_refDTypep ? m_refDTypep : childDTypep(); } void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } - inline int boundConst() const; + inline int boundConst() const VL_MT_STABLE; AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } // METHODS - AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; } + AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; } // cppcheck-suppress csyleCast - AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; } + AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; } // cppcheck-suppress csyleCast AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } // cppcheck-suppress csyleCast @@ -1086,11 +1097,11 @@ public: string prettyDTypeName() const override { return subDTypep() ? prettyName(subDTypep()->name()) : prettyName(); } - AstBasicDType* basicp() const override VL_MT_SAFE { + AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep() ? subDTypep()->basicp() : nullptr; } - AstNodeDType* subDTypep() const override; - AstNodeDType* skipRefp() const override VL_MT_SAFE { + AstNodeDType* subDTypep() const override VL_MT_STABLE; + AstNodeDType* skipRefp() const override VL_MT_STABLE { // Skip past both the Ref and the Typedef if (subDTypep()) { return subDTypep()->skipRefp(); @@ -1119,9 +1130,9 @@ public: int widthTotalBytes() const override { return dtypeSkipRefp()->widthTotalBytes(); } void name(const string& flag) override { m_name = flag; } AstNodeDType* dtypeSkipRefp() const { return subDTypep()->skipRefp(); } - AstTypedef* typedefp() const { return m_typedefp; } + AstTypedef* typedefp() const VL_MT_SAFE { return m_typedefp; } void typedefp(AstTypedef* nodep) { m_typedefp = nodep; } - AstNodeDType* refDTypep() const { return m_refDTypep; } + AstNodeDType* refDTypep() const VL_MT_SAFE { return m_refDTypep; } void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } AstNodeDType* virtRefDTypep() const override { return refDTypep(); } void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } @@ -1163,13 +1174,15 @@ public: void dumpSmall(std::ostream& str) const override; AstNodeDType* getChildDTypep() const override { return childDTypep(); } // op1 = Range of variable - AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); } + AstNodeDType* subDTypep() const override VL_MT_STABLE { + return m_refDTypep ? m_refDTypep : childDTypep(); + } void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } // METHODS - AstBasicDType* basicp() const override { return subDTypep()->basicp(); } - AstNodeDType* skipRefp() const override { return (AstNodeDType*)this; } + AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); } + AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; } AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } int widthAlignBytes() const override { return sizeof(std::map); } @@ -1201,13 +1214,15 @@ public: bool similarDType(const AstNodeDType* samep) const override; void dumpSmall(std::ostream& str) const override; AstNodeDType* getChildDTypep() const override { return childDTypep(); } - AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); } + AstNodeDType* subDTypep() const override VL_MT_STABLE { + return m_refDTypep ? m_refDTypep : childDTypep(); + } void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } // METHODS - AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); } - AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; } + AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); } + AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; } AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } int widthAlignBytes() const override { return subDTypep()->widthAlignBytes(); } @@ -1226,13 +1241,13 @@ public: bool hasDType() const override { return true; } bool maybePointedTo() const override { return true; } bool undead() const override { return true; } - AstNodeDType* subDTypep() const override { return nullptr; } + AstNodeDType* subDTypep() const override VL_MT_SAFE { return nullptr; } AstNodeDType* virtRefDTypep() const override { return nullptr; } void virtRefDTypep(AstNodeDType* nodep) override {} bool similarDType(const AstNodeDType* samep) const override { return this == samep; } - AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; } + AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; } // cppcheck-suppress csyleCast - AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; } + AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; } // cppcheck-suppress csyleCast AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } // cppcheck-suppress csyleCast @@ -1266,15 +1281,15 @@ public: bool similarDType(const AstNodeDType* samep) const override; void dumpSmall(std::ostream& str) const override; AstNodeDType* getChildDTypep() const override { return childDTypep(); } - AstNodeDType* subDTypep() const override VL_MT_SAFE { + AstNodeDType* subDTypep() const override VL_MT_STABLE { return m_refDTypep ? m_refDTypep : childDTypep(); } void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } // METHODS - AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); } - AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; } + AstBasicDType* basicp() const override VL_MT_STABLE { return subDTypep()->basicp(); } + AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; } AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } int widthAlignBytes() const override { return sizeof(std::map); } diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index eb0820eb4..de4de290c 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -644,7 +644,7 @@ public: string emitC() override { V3ERROR_NA_RETURN(""); } bool cleanOut() const override { V3ERROR_NA_RETURN(true); } AstNodeDType* getChildDTypep() const override { return childDTypep(); } - AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } + AstNodeDType* subDTypep() const VL_MT_STABLE { return dtypep() ? dtypep() : childDTypep(); } }; class AstCastParse final : public AstNodeExpr { // Cast to appropriate type, where we haven't determined yet what the data type is @@ -1574,7 +1574,7 @@ public: bool cleanOut() const override { V3ERROR_NA_RETURN(""); } int instrCount() const override { return widthInstrs(); } AstNodeDType* getChildDTypep() const override { return childDTypep(); } - AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } + AstNodeDType* subDTypep() const VL_MT_STABLE { return dtypep() ? dtypep() : childDTypep(); } }; class AstRand final : public AstNodeExpr { // $random/$random(seed) or $urandom/$urandom(seed) @@ -1972,7 +1972,7 @@ public: bool same(const AstNode* /*samep*/) const override { return true; } bool cleanOut() const override { return true; } AstNodeDType* getChildDTypep() const override { return childDTypep(); } - AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } + AstNodeDType* subDTypep() const VL_MT_STABLE { return dtypep() ? dtypep() : childDTypep(); } }; class AstTimePrecision final : public AstNodeExpr { // Verilog $timeprecision diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 7ad7594ee..607f3f52d 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -1544,7 +1544,9 @@ public: ASTGEN_MEMBERS_AstTypedef; void dump(std::ostream& str) const override; AstNodeDType* getChildDTypep() const override { return childDTypep(); } - virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } + virtual AstNodeDType* subDTypep() const VL_MT_STABLE { + return dtypep() ? dtypep() : childDTypep(); + } // METHODS string name() const override { return m_name; } bool maybePointedTo() const override { return true; } @@ -1793,11 +1795,11 @@ public: string vlPropDecl(const string& propName) const; // Return VerilatorVarProps declaration void combineType(VVarType type); AstNodeDType* getChildDTypep() const override { return childDTypep(); } - AstNodeDType* dtypeSkipRefp() const VL_MT_SAFE { return subDTypep()->skipRefp(); } + AstNodeDType* dtypeSkipRefp() const VL_MT_STABLE { return subDTypep()->skipRefp(); } // (Slow) recurse down to find basic data type (Note don't need virtual - // AstVar isn't a NodeDType) - AstBasicDType* basicp() const VL_MT_SAFE { return subDTypep()->basicp(); } - virtual AstNodeDType* subDTypep() const VL_MT_SAFE { + AstBasicDType* basicp() const VL_MT_STABLE { return subDTypep()->basicp(); } + virtual AstNodeDType* subDTypep() const VL_MT_STABLE { return dtypep() ? dtypep() : childDTypep(); } void ansi(bool flag) { m_ansi = flag; } @@ -2334,19 +2336,19 @@ public: inline AstRange(FileLine* fl, int left, int right); inline AstRange(FileLine* fl, const VNumRange& range); ASTGEN_MEMBERS_AstRange; - inline int leftConst() const VL_MT_SAFE; - inline int rightConst() const VL_MT_SAFE; - int hiConst() const VL_MT_SAFE { + inline int leftConst() const VL_MT_STABLE; + inline int rightConst() const VL_MT_STABLE; + int hiConst() const VL_MT_STABLE { const int l = leftConst(); const int r = rightConst(); return l > r ? l : r; } - int loConst() const VL_MT_SAFE { + int loConst() const VL_MT_STABLE { const int l = leftConst(); const int r = rightConst(); return l > r ? r : l; } - int elementsConst() const VL_MT_SAFE { return hiConst() - loConst() + 1; } + int elementsConst() const VL_MT_STABLE { return hiConst() - loConst() + 1; } bool littleEndian() const { return leftConst() < rightConst(); } void dump(std::ostream& str) const override; virtual string emitC() { V3ERROR_NA_RETURN(""); } diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 5e59f023e..3d3135014 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -704,12 +704,12 @@ public: } }; -string AstNodeDType::cType(const string& name, bool /*forFunc*/, bool isRef) const VL_MT_SAFE { +string AstNodeDType::cType(const string& name, bool /*forFunc*/, bool isRef) const VL_MT_STABLE { const CTypeRecursed info = cTypeRecurse(false); return info.render(name, isRef); } -AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const { +AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const VL_MT_STABLE { // Legacy compound argument currently just passed through and unused CTypeRecursed info; @@ -846,7 +846,7 @@ int AstNodeDType::widthPow2() const { return 1; } -bool AstNodeDType::isLiteralType() const VL_MT_SAFE { +bool AstNodeDType::isLiteralType() const VL_MT_STABLE { if (const auto* const dtypep = VN_CAST(skipRefp(), BasicDType)) { return dtypep->keyword().isLiteralType(); } else if (const auto* const dtypep = VN_CAST(skipRefp(), UnpackArrayDType)) { @@ -1804,7 +1804,7 @@ void AstRefDType::cloneRelink() { m_classOrPackagep = m_classOrPackagep->clonep(); } } -AstNodeDType* AstRefDType::subDTypep() const { +AstNodeDType* AstRefDType::subDTypep() const VL_MT_STABLE { if (typedefp()) return typedefp()->subDTypep(); return refDTypep(); // Maybe nullptr } diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index 39ff0e70e..ebb7ed3f4 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -40,7 +40,7 @@ public: EmitCParentModule(); VL_UNCOPYABLE(EmitCParentModule); - static const AstNodeModule* get(const AstNode* nodep) { + static const AstNodeModule* get(const AstNode* nodep) VL_MT_STABLE { return VN_AS(nodep->user4p(), NodeModule); } }; @@ -70,7 +70,9 @@ public: static string protectWordsIf(const string& name, bool doIt) { return VIdProtect::protectWordsIf(name, doIt); } - static string ifNoProtect(const string& in) { return v3Global.opt.protectIds() ? "" : in; } + static string ifNoProtect(const string& in) VL_MT_SAFE { + return v3Global.opt.protectIds() ? "" : in; + } static string voidSelfAssign(const AstNodeModule* modp) { const string className = prefixNameProtect(modp); return className + "* const __restrict vlSelf VL_ATTR_UNUSED = static_cast<" + className @@ -85,7 +87,7 @@ public: static string prefixNameProtect(const AstNode* nodep) { // C++ name with prefix return v3Global.opt.modPrefix() + "_" + protect(nodep->name()); } - static string topClassName() { // Return name of top wrapper module + static string topClassName() VL_MT_SAFE { // Return name of top wrapper module return v3Global.opt.prefix(); } diff --git a/src/V3Error.h b/src/V3Error.h index cf0ab5fa6..bb6a3d63c 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -648,7 +648,7 @@ inline void v3errorEndFatal(std::ostringstream& sstr) // Helper macros for VL_DEFINE_DEBUG_FUNCTIONS // Takes an optional "name" (as __VA_ARGS__) #define VL_DEFINE_DEBUG(...) \ - VL_ATTR_UNUSED static int debug##__VA_ARGS__() { \ + VL_ATTR_UNUSED static int debug##__VA_ARGS__() VL_MT_SAFE { \ static int level = -1; \ if (VL_UNLIKELY(level < 0)) { \ std::string tag{VL_STRINGIFY(__VA_ARGS__)}; \ diff --git a/src/V3File.cpp b/src/V3File.cpp index 0921f7956..6ae1507e0 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -853,7 +853,8 @@ void V3OutFormatter::putcNoTracking(char chr) { putcOutput(chr); } -string V3OutFormatter::quoteNameControls(const string& namein, V3OutFormatter::Language lang) { +string V3OutFormatter::quoteNameControls(const string& namein, + V3OutFormatter::Language lang) VL_PURE { // Encode control chars into output-appropriate escapes // Reverse is V3Parse::deQuote string out; diff --git a/src/V3File.h b/src/V3File.h index fcee430f8..2c1d34850 100644 --- a/src/V3File.h +++ b/src/V3File.h @@ -39,7 +39,7 @@ public: addSrcDepend(filename); return new_ifstream_nodepend(filename); } - static std::ifstream* new_ifstream_nodepend(const string& filename) { + static std::ifstream* new_ifstream_nodepend(const string& filename) VL_MT_SAFE { return new std::ifstream{filename.c_str()}; } static std::ofstream* new_ofstream(const string& filename, bool append = false) { @@ -171,7 +171,7 @@ public: // STATIC METHODS static string indentSpaces(int num); // Add escaped characters to strings - static string quoteNameControls(const string& namein, Language lang = LA_C); + static string quoteNameControls(const string& namein, Language lang = LA_C) VL_PURE; static bool tokenMatch(const char* cp, const char* cmp); static bool tokenNotStart(const char* cp); // Import/export meaning no endfunction static bool tokenStart(const char* cp); diff --git a/src/V3FileLine.cpp b/src/V3FileLine.cpp index 80c2d1a85..8f7362b38 100644 --- a/src/V3FileLine.cpp +++ b/src/V3FileLine.cpp @@ -39,7 +39,7 @@ VL_DEFINE_DEBUG_FUNCTIONS; //###################################################################### // FileLineSingleton class functions -string FileLineSingleton::filenameLetters(fileNameIdx_t fileno) { +string FileLineSingleton::filenameLetters(fileNameIdx_t fileno) VL_PURE { constexpr int size = 1 + (64 / 4); // Each letter retires more than 4 bits of a > 64 bit number char out[size]; diff --git a/src/V3FileLine.h b/src/V3FileLine.h index 42c72f25b..96a52526c 100644 --- a/src/V3FileLine.h +++ b/src/V3FileLine.h @@ -64,7 +64,7 @@ class FileLineSingleton final { ~FileLineSingleton() = default; fileNameIdx_t nameToNumber(const string& filename); - string numberToName(fileNameIdx_t filenameno) const { return m_names[filenameno]; } + string numberToName(fileNameIdx_t filenameno) const VL_MT_SAFE { return m_names[filenameno]; } V3LangCode numberToLang(fileNameIdx_t filenameno) const { return m_languages[filenameno]; } void numberToLang(fileNameIdx_t filenameno, const V3LangCode& l) { m_languages[filenameno] = l; @@ -75,7 +75,7 @@ class FileLineSingleton final { m_languages.clear(); } void fileNameNumMapDumpXml(std::ostream& os); - static string filenameLetters(fileNameIdx_t fileno); + static string filenameLetters(fileNameIdx_t fileno) VL_PURE; // Add given bitset to the interned bitsets, return interned index msgEnSetIdx_t addMsgEnBitSet(const MsgEnBitSet& bitSet); @@ -159,7 +159,7 @@ protected: private: // CONSTRUCTORS - static FileLineSingleton& singleton() { + static FileLineSingleton& singleton() VL_MT_SAFE { static FileLineSingleton s; return s; } @@ -242,7 +242,7 @@ public: string prettySource() const VL_MT_SAFE; // Source, w/stripped unprintables and newlines FileLine* parent() const VL_MT_SAFE { return m_parent; } V3LangCode language() const { return singleton().numberToLang(filenameno()); } - string ascii() const; + string ascii() const VL_MT_SAFE; string asciiLineCol() const; int filenameno() const VL_MT_SAFE { return m_filenameno; } string filename() const VL_MT_SAFE { return singleton().numberToName(filenameno()); } @@ -270,7 +270,7 @@ public: } void warnOff(V3ErrorCode code, bool flag) { warnOn(code, !flag); } bool warnOff(const string& msg, bool flag); // Returns 1 if ok - bool warnIsOff(V3ErrorCode code) const; + bool warnIsOff(V3ErrorCode code) const VL_MT_SAFE; void warnLintOff(bool flag); void warnStyleOff(bool flag); void warnUnusedOff(bool flag); @@ -362,7 +362,7 @@ public: private: string warnContext() const; string warnContextParent() const VL_REQUIRES(V3Error::s().m_mutex); - const MsgEnBitSet& msgEn() const VL_MT_SAFE { return singleton().msgEn(m_msgEnIdx); } + const MsgEnBitSet& msgEn() const { return singleton().msgEn(m_msgEnIdx); } }; std::ostream& operator<<(std::ostream& os, FileLine* fileline); diff --git a/src/V3Global.h b/src/V3Global.h index 228440e3a..0537f534c 100644 --- a/src/V3Global.h +++ b/src/V3Global.h @@ -143,7 +143,7 @@ public: void widthMinUsage(const VWidthMinUsage& flag) { m_widthMinUsage = flag; } bool constRemoveXs() const { return m_constRemoveXs; } void constRemoveXs(bool flag) { m_constRemoveXs = flag; } - string debugFilename(const string& nameComment, int newNumber = 0); + string debugFilename(const string& nameComment, int newNumber = 0) VL_MT_SAFE; static string digitsFilename(int number); bool needTraceDumper() const { return m_needTraceDumper; } void needTraceDumper(bool flag) { m_needTraceDumper = flag; } diff --git a/src/V3Hash.cpp b/src/V3Hash.cpp index 5fd2d2751..bff44cdf1 100644 --- a/src/V3Hash.cpp +++ b/src/V3Hash.cpp @@ -24,7 +24,7 @@ V3Hash::V3Hash(const std::string& val) : m_value{static_cast(std::hash{}(val))} {} -std::ostream& operator<<(std::ostream& os, const V3Hash& rhs) { +std::ostream& operator<<(std::ostream& os, const V3Hash& rhs) VL_MT_SAFE { return os << 'h' << std::hex << std::setw(8) << std::setfill('0') << rhs.value(); } diff --git a/src/V3Hash.h b/src/V3Hash.h index 7cdfb8749..7e75045ef 100644 --- a/src/V3Hash.h +++ b/src/V3Hash.h @@ -69,7 +69,7 @@ public: } }; -std::ostream& operator<<(std::ostream& os, const V3Hash& rhs); +std::ostream& operator<<(std::ostream& os, const V3Hash& rhs) VL_MT_SAFE; template <> struct std::hash { diff --git a/src/V3Number.cpp b/src/V3Number.cpp index b99717d60..a74d7a64d 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -598,17 +598,17 @@ bool V3Number::displayedFmtLegal(char format, bool isScan) { } } -string V3Number::displayPad(size_t fmtsize, char pad, bool left, const string& in) { +string V3Number::displayPad(size_t fmtsize, char pad, bool left, const string& in) VL_PURE { string padding; if (in.length() < fmtsize) padding = string(fmtsize - in.length(), pad); return left ? (in + padding) : (padding + in); } -string V3Number::displayed(AstNode* nodep, const string& vformat) const { +string V3Number::displayed(AstNode* nodep, const string& vformat) const VL_MT_SAFE { return displayed(nodep->fileline(), vformat); } -string V3Number::displayed(FileLine* fl, const string& vformat) const { +string V3Number::displayed(FileLine* fl, const string& vformat) const VL_MT_SAFE { auto pos = vformat.cbegin(); UASSERT(pos != vformat.cend() && pos[0] == '%', "$display-like function with non format argument " << *this); @@ -913,7 +913,7 @@ uint32_t V3Number::toUInt() const VL_MT_SAFE { return m_data.num()[0].m_value; } -double V3Number::toDouble() const { +double V3Number::toDouble() const VL_MT_SAFE { if (VL_UNCOVERABLE(!isDouble() || width() != 64)) { v3fatalSrc("Real operation on wrong sized/non-real number"); } @@ -926,7 +926,7 @@ double V3Number::toDouble() const { return u.d; } -int32_t V3Number::toSInt() const { +int32_t V3Number::toSInt() const VL_MT_SAFE { if (isSigned()) { const uint32_t v = toUInt(); const uint32_t signExtend = (-(v & (1UL << (width() - 1)))); @@ -996,14 +996,14 @@ uint8_t V3Number::dataByte(int byte) const { return (edataWord(byte / (VL_EDATASIZE / 8)) >> ((byte * 8) % VL_EDATASIZE)) & 0xff; } -bool V3Number::isAllZ() const { +bool V3Number::isAllZ() const VL_MT_SAFE { if (isDouble() || isString()) return false; for (int i = 0; i < width(); i++) { if (!bitIsZ(i)) return false; } return true; } -bool V3Number::isAllX() const { +bool V3Number::isAllX() const VL_MT_SAFE { if (isDouble() || isString()) return false; uint32_t mask = hiWordMask(); for (int i = words() - 1; i >= 0; --i) { @@ -1057,7 +1057,7 @@ bool V3Number::isFourState() const { } return false; } -bool V3Number::isAnyX() const { +bool V3Number::isAnyX() const VL_MT_SAFE { if (isDouble() || isString()) return false; for (int bit = 0; bit < width(); bit++) { if (bitIsX(bit)) return true; @@ -1065,7 +1065,7 @@ bool V3Number::isAnyX() const { return false; } bool V3Number::isAnyXZ() const { return isAnyX() || isAnyZ(); } -bool V3Number::isAnyZ() const { +bool V3Number::isAnyZ() const VL_MT_SAFE { if (isDouble() || isString()) return false; for (int bit = 0; bit < width(); bit++) { if (bitIsZ(bit)) return true; @@ -1082,7 +1082,7 @@ bool V3Number::isLtXZ(const V3Number& rhs) const { } return false; } -int V3Number::countX(int lsb, int nbits) const { +int V3Number::countX(int lsb, int nbits) const VL_MT_SAFE { int count = 0; for (int bitn = 0; bitn < nbits; ++bitn) { if (lsb + bitn >= width()) return count; @@ -1090,7 +1090,7 @@ int V3Number::countX(int lsb, int nbits) const { } return count; } -int V3Number::countZ(int lsb, int nbits) const { +int V3Number::countZ(int lsb, int nbits) const VL_MT_SAFE { int count = 0; for (int bitn = 0; bitn < nbits; ++bitn) { if (lsb + bitn >= width()) return count; diff --git a/src/V3Number.h b/src/V3Number.h index 25b59706a..2afc9354f 100644 --- a/src/V3Number.h +++ b/src/V3Number.h @@ -63,7 +63,7 @@ public: DOUBLE = 2, STRING = 3, }; - friend std::ostream& operator<<(std::ostream& os, const V3NumberDataType& rhs) { + friend std::ostream& operator<<(std::ostream& os, const V3NumberDataType& rhs) VL_MT_SAFE { switch (rhs) { case V3NumberDataType::UNINITIALIZED: return os << "UNINITIALIZED"; case V3NumberDataType::LOGIC: return os << "LOGIC"; @@ -210,7 +210,7 @@ public: UASSERT(isString(), "`str` member accessed when data type is " << m_type); return m_string; } - const std::string& str() const VL_MT_SAFE { + const std::string& str() const { UASSERT(isString(), "`str` member accessed when data type is " << m_type); return m_string; } @@ -383,7 +383,7 @@ public: } private: - char bitIs(int bit) const VL_MT_SAFE { + char bitIs(int bit) const { if (bit >= m_data.width() || bit < 0) { // We never sign extend return '0'; @@ -559,7 +559,7 @@ private: m_data.m_sized = false; } } - static string displayPad(size_t fmtsize, char pad, bool left, const string& in); + static string displayPad(size_t fmtsize, char pad, bool left, const string& in) VL_PURE; string displayed(FileLine* fl, const string& vformat) const VL_MT_SAFE; string displayed(const string& vformat) const VL_MT_SAFE { return displayed(m_fileline, vformat); @@ -583,8 +583,8 @@ public: V3Number& setMask(int nbits); // IE if nbits=1, then 0b1, if 2->0b11, if 3->0b111 etc // ACCESSORS - string ascii(bool prefixed = true, bool cleanVerilog = false) const VL_MT_SAFE; - string displayed(AstNode* nodep, const string& vformat) const; + string ascii(bool prefixed = true, bool cleanVerilog = false) const; + string displayed(AstNode* nodep, const string& vformat) const VL_MT_SAFE; static bool displayedFmtLegal(char format, bool isScan); // Is this a valid format letter? int width() const VL_MT_SAFE { return m_data.width(); } int widthMin() const; // Minimum width that can represent this number (~== log2(num)+1) @@ -612,10 +612,10 @@ public: return m_data.type() == V3NumberDataType::LOGIC || m_data.type() == V3NumberDataType::DOUBLE; } - bool isNegative() const VL_MT_SAFE { return !isString() && bitIs1(width() - 1); } + bool isNegative() const { return !isString() && bitIs1(width() - 1); } bool is1Step() const VL_MT_SAFE { return m_data.m_is1Step; } bool isNull() const VL_MT_SAFE { return m_data.m_isNull; } - bool isFourState() const VL_MT_SAFE; + bool isFourState() const; bool hasZ() const { if (isString()) return false; for (int i = 0; i < words(); i++) { @@ -626,7 +626,7 @@ public: } bool isAllZ() const VL_MT_SAFE; bool isAllX() const VL_MT_SAFE; - bool isEqZero() const VL_MT_SAFE; + bool isEqZero() const; bool isNeqZero() const; bool isBitsZero(int msb, int lsb) const; bool isEqOne() const; @@ -637,13 +637,13 @@ public: bool isAnyXZ() const; bool isAnyZ() const VL_MT_SAFE; bool isMsbXZ() const { return bitIsXZ(m_data.width() - 1); } - uint32_t toUInt() const; + uint32_t toUInt() const VL_MT_SAFE; int32_t toSInt() const VL_MT_SAFE; - uint64_t toUQuad() const; + uint64_t toUQuad() const VL_MT_SAFE; int64_t toSQuad() const VL_MT_SAFE; string toString() const VL_MT_SAFE; - string toDecimalS() const VL_MT_SAFE; // return ASCII signed decimal number - string toDecimalU() const VL_MT_SAFE; // return ASCII unsigned decimal number + string toDecimalS() const; // return ASCII signed decimal number + string toDecimalU() const; // return ASCII unsigned decimal number double toDouble() const VL_MT_SAFE; V3Hash toHash() const; uint32_t edataWord(int eword) const; @@ -777,7 +777,7 @@ public: V3Number& opLtN(const V3Number& lhs, const V3Number& rhs); V3Number& opLteN(const V3Number& lhs, const V3Number& rhs); }; -inline std::ostream& operator<<(std::ostream& os, const V3Number& rhs) { +inline std::ostream& operator<<(std::ostream& os, const V3Number& rhs) VL_MT_SAFE { return os << rhs.ascii(); } diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 076fff117..96996d58c 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -874,7 +874,7 @@ void V3Options::notify() { //###################################################################### // V3 Options accessors -string V3Options::version() { +string V3Options::version() VL_PURE { string ver = DTVERSION; ver += " rev " + cvtToStr(DTVERSION_rev); return ver; @@ -1938,7 +1938,7 @@ unsigned V3Options::dumpLevel(const string& tag) const VL_MT_SAFE { return iter != m_dumpLevel.end() ? iter->second : 0; } -unsigned V3Options::dumpSrcLevel(const string& srcfile_path) const VL_MT_SAFE { +unsigned V3Options::dumpSrcLevel(const string& srcfile_path) const { // For simplicity, calling functions can just use __FILE__ for srcfile. // That means we need to strip the filenames: ../Foo.cpp -> Foo return dumpLevel(V3Os::filenameNonDirExt(srcfile_path)); diff --git a/src/V3Options.h b/src/V3Options.h index 12b261003..26a41f712 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -407,7 +407,7 @@ public: unsigned debugLevel(const string& tag) const VL_MT_SAFE; unsigned debugSrcLevel(const string& srcfile_path) const VL_MT_SAFE; unsigned dumpLevel(const string& tag) const VL_MT_SAFE; - unsigned dumpSrcLevel(const string& srcfile_path) const VL_MT_SAFE; + unsigned dumpSrcLevel(const string& srcfile_path) const; // METHODS void addCppFile(const string& filename); @@ -650,7 +650,7 @@ public: } // METHODS (from main) - static string version(); + static string version() VL_PURE; static string argString(int argc, char** argv); ///< Return list of arguments as simple string string allArgsString() const VL_MT_SAFE; ///< Return all passed arguments as simple string // Return options for child hierarchical blocks when forTop==false, otherwise returns args for diff --git a/src/V3Os.cpp b/src/V3Os.cpp index a18dd6c2f..7a4722839 100644 --- a/src/V3Os.cpp +++ b/src/V3Os.cpp @@ -142,7 +142,7 @@ string V3Os::filenameDir(const string& filename) { } } -string V3Os::filenameNonDir(const string& filename) { +string V3Os::filenameNonDir(const string& filename) VL_PURE { string::size_type pos; if ((pos = filename.rfind('/')) != string::npos) { return filename.substr(pos + 1); @@ -151,7 +151,7 @@ string V3Os::filenameNonDir(const string& filename) { } } -string V3Os::filenameNonExt(const string& filename) { +string V3Os::filenameNonExt(const string& filename) VL_PURE { string base = filenameNonDir(filename); string::size_type pos; if ((pos = base.find('.')) != string::npos) base.erase(pos); diff --git a/src/V3Os.h b/src/V3Os.h index 6b73aa3b5..4300417fd 100644 --- a/src/V3Os.h +++ b/src/V3Os.h @@ -37,10 +37,11 @@ public: // METHODS (generic filename utilities) static string filenameFromDirBase(const string& dir, const string& basename); /// Return non-directory part of filename - static string filenameNonDir(const string& filename); + static string filenameNonDir(const string& filename) VL_PURE; /// Return non-extensioned (no .) part of filename - static string filenameNonExt(const string& filename); - static string filenameNonDirExt(const string& filename) { ///< Return basename of filename + static string filenameNonExt(const string& filename) VL_PURE; + ///< Return basename of filename + static string filenameNonDirExt(const string& filename) VL_PURE { return filenameNonExt(filenameNonDir(filename)); } static string filenameDir(const string& filename); ///< Return directory part of filename diff --git a/src/V3String.cpp b/src/V3String.cpp index f0aa6ecc8..b97a84b26 100644 --- a/src/V3String.cpp +++ b/src/V3String.cpp @@ -36,7 +36,7 @@ std::map VName::s_dehashMap; // Wildcard // Double procedures, inlined, unrolls loop much better -bool VString::wildmatchi(const char* s, const char* p) { +bool VString::wildmatchi(const char* s, const char* p) VL_PURE { for (; *p; s++, p++) { if (*p != '*') { if (((*s) != (*p)) && *p != '?') return false; @@ -52,7 +52,7 @@ bool VString::wildmatchi(const char* s, const char* p) { return (*s == '\0'); } -bool VString::wildmatch(const char* s, const char* p) { +bool VString::wildmatch(const char* s, const char* p) VL_PURE { for (; *p; s++, p++) { if (*p != '*') { if (((*s) != (*p)) && *p != '?') return false; @@ -68,7 +68,7 @@ bool VString::wildmatch(const char* s, const char* p) { return (*s == '\0'); } -bool VString::wildmatch(const string& s, const string& p) { +bool VString::wildmatch(const string& s, const string& p) VL_PURE { return wildmatch(s.c_str(), p.c_str()); } @@ -130,7 +130,7 @@ string VString::escapeStringForPath(const string& str) { return result; } -string VString::spaceUnprintable(const string& str) { +string VString::spaceUnprintable(const string& str) VL_PURE { string out; for (const char c : str) { if (std::isprint(c)) { @@ -216,10 +216,12 @@ static const uint32_t sha256K[] 0xc67178f2}; VL_ATTR_ALWINLINE -static uint32_t shaRotr32(uint32_t lhs, uint32_t rhs) { return lhs >> rhs | lhs << (32 - rhs); } +static uint32_t shaRotr32(uint32_t lhs, uint32_t rhs) VL_PURE { + return lhs >> rhs | lhs << (32 - rhs); +} VL_ATTR_ALWINLINE -static void sha256Block(uint32_t* h, const uint32_t* chunk) { +static void sha256Block(uint32_t* h, const uint32_t* chunk) VL_PURE { uint32_t ah[8]; const uint32_t* p = chunk; diff --git a/src/V3String.h b/src/V3String.h index bbd3ba948..d56589c5e 100644 --- a/src/V3String.h +++ b/src/V3String.h @@ -34,13 +34,14 @@ // Global string-related functions template -std::string cvtToStr(const T& t) { +std::string cvtToStr(const T& t) VL_PURE { std::ostringstream os; os << t; return os.str(); } template -typename std::enable_if::value, std::string>::type cvtToHex(const T tp) { +typename std::enable_if::value, std::string>::type +cvtToHex(const T tp) VL_PURE { std::ostringstream os; os << static_cast(tp); return os.str(); @@ -78,14 +79,14 @@ inline string ucfirst(const string& text) { // VString - String manipulation class VString final { - static bool wildmatchi(const char* s, const char* p); + static bool wildmatchi(const char* s, const char* p) VL_PURE; public: // METHODS (generic string utilities) // Return true if p with ? or *'s matches s - static bool wildmatch(const char* s, const char* p); + static bool wildmatch(const char* s, const char* p) VL_PURE; // Return true if p with ? or *'s matches s - static bool wildmatch(const string& s, const string& p); + static bool wildmatch(const string& s, const string& p) VL_PURE; // Return {a}{dot}{b}, omitting dot if a or b are empty static string dot(const string& a, const string& dot, const string& b); // Convert string to lowercase (tolower) @@ -107,7 +108,7 @@ public: static string quoteStringLiteralForShell(const string& str); // Replace any unprintable with space // This includes removing tabs, so column tracking is correct - static string spaceUnprintable(const string& str); + static string spaceUnprintable(const string& str) VL_PURE; // Remove any whitespace static string removeWhitespace(const string& str); // Return true if only whitespace or "" diff --git a/src/astgen b/src/astgen index 95d609df7..9c30529f7 100755 --- a/src/astgen +++ b/src/astgen @@ -865,7 +865,7 @@ def write_type_enum(prefix, nodeList): fh.write(" _BOUNDS_END\n") fh.write(" };\n") - fh.write(" const char* ascii() const {\n") + fh.write(" const char* ascii() const VL_MT_SAFE {\n") fh.write(" static const char* const names[_ENUM_END + 1] = {\n") for node in sorted(filter(lambda _: _.isLeaf, nodeList), key=lambda _: _.typeId): @@ -931,7 +931,7 @@ def write_ast_macros(filename): static Ast{t}* cloneTreeNull(Ast{t}* nodep, bool cloneNextLink) {{ return nodep ? nodep->cloneTree(cloneNextLink) : nullptr; }} - Ast{t}* clonep() const VL_MT_SAFE {{ return static_cast(AstNode::clonep()); }} + Ast{t}* clonep() const {{ return static_cast(AstNode::clonep()); }} Ast{t}* addNext(Ast{t}* nodep) {{ return static_cast(AstNode::addNext(this, nodep)); }} ''', t=node.name) @@ -952,7 +952,7 @@ def write_ast_macros(filename): "op{n}p()").format(n=n, kind=kind) if monad == "List": emitBlock('''\ - Ast{kind}* {name}() const VL_MT_SAFE {{ return {retrieve}; }} + Ast{kind}* {name}() const VL_MT_STABLE {{ return {retrieve}; }} void add{Name}(Ast{kind}* nodep) {{ addNOp{n}p(reinterpret_cast(nodep)); }} ''', kind=kind, @@ -962,7 +962,7 @@ def write_ast_macros(filename): retrieve=retrieve) elif monad == "Optional": emitBlock('''\ - Ast{kind}* {name}() const VL_MT_SAFE {{ return {retrieve}; }} + Ast{kind}* {name}() const VL_MT_STABLE {{ return {retrieve}; }} void {name}(Ast{kind}* nodep) {{ setNOp{n}p(reinterpret_cast(nodep)); }} ''', kind=kind, @@ -971,7 +971,7 @@ def write_ast_macros(filename): retrieve=retrieve) else: emitBlock('''\ - Ast{kind}* {name}() const VL_MT_SAFE {{ return {retrieve}; }} + Ast{kind}* {name}() const VL_MT_STABLE {{ return {retrieve}; }} void {name}(Ast{kind}* nodep) {{ setOp{n}p(reinterpret_cast(nodep)); }} ''', kind=kind, diff --git a/test_regress/t/t_a5_attributes_src.pl b/test_regress/t/t_a5_attributes_src.pl index 92a4ca5d6..01c750bdf 100755 --- a/test_regress/t/t_a5_attributes_src.pl +++ b/test_regress/t/t_a5_attributes_src.pl @@ -36,7 +36,7 @@ sub check { tee => 1, cmd => ["python3", "$root/nodist/clang_check_attributes --verilator-root=$root --cxxflags='$clang_args' $precompile_args $srcfiles_str"]); - file_grep($Self->{run_log_filename}, "Number of functions reported unsafe: 27"); + file_grep($Self->{run_log_filename}, "Number of functions reported unsafe: 0"); } run_clang_check(); From d1b55cb7aa93ba093689cf44ddfcbda420da69ac Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 16 Mar 2023 20:22:08 -0400 Subject: [PATCH 056/155] Fix compile error last commit (#4029) --- src/V3SchedAcyclic.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/V3SchedAcyclic.cpp b/src/V3SchedAcyclic.cpp index 412ac0070..bed28d66d 100644 --- a/src/V3SchedAcyclic.cpp +++ b/src/V3SchedAcyclic.cpp @@ -68,7 +68,7 @@ public: : V3GraphVertex{graphp} , m_logicp{logicp} , m_scopep{scopep} {} - virtual V3GraphVertex* clone(V3Graph* graphp) const { + V3GraphVertex* clone(V3Graph* graphp) const override { return new LogicVertex{graphp, logicp(), scopep()}; } @@ -90,7 +90,7 @@ public: , m_vscp{vscp} {} AstVarScope* vscp() const { return m_vscp; } AstVar* varp() const { return m_vscp->varp(); } - virtual V3GraphVertex* clone(V3Graph* graphp) const { return new VarVertex{graphp, vscp()}; } + V3GraphVertex* clone(V3Graph* graphp) const override { return new VarVertex{graphp, vscp()}; } // LCOV_EXCL_START // Debug code string name() const override { return m_vscp->name(); } From 51ba4a1531d72a5749534472e31356bf4002448a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 16 Mar 2023 20:48:18 -0400 Subject: [PATCH 057/155] Fix clocking block scope internal error (#4032). --- Changes | 1 + src/V3Scope.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Changes b/Changes index bfe27ed5c..4b756d649 100644 --- a/Changes +++ b/Changes @@ -21,6 +21,7 @@ Verilator 5.009 devel * Fix UNDRIVEN warning seg fault (#3989). [Felix Neumärker] * Fix symbol entries when inheriting classes (#3995) (#3996). [Krzysztof Boroński] * Fix push to dynamic queue in struct (#4015). [ezchi] +* Fix clocking block scope internal error (#4032). [Srinivasan Venkataramanan] * Fix false ENUMVALUE on expressions and arrays. diff --git a/src/V3Scope.cpp b/src/V3Scope.cpp index e10bc172b..2dd807015 100644 --- a/src/V3Scope.cpp +++ b/src/V3Scope.cpp @@ -255,7 +255,7 @@ private: iterateChildren(nodep); if (nodep->varsp()) m_scopep->modp()->addStmtsp(nodep->varsp()->unlinkFrBackWithNext()); if (nodep->eventp()) m_scopep->modp()->addStmtsp(nodep->eventp()->unlinkFrBack()); - VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); } void visit(AstNodeFTask* nodep) override { // Add to list of blocks under this scope From 4240c29f4bd3a2b79e81271964c2f6f31ffd05bf Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 16 Mar 2023 21:14:49 -0400 Subject: [PATCH 058/155] Internals: Fix missing broken check --- src/V3AstNodes.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 3d3135014..bb721a2ee 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -115,6 +115,7 @@ void AstNodeUOrStructDType::repairMemberCache() { } const char* AstNodeUOrStructDType::broken() const { + BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); std::unordered_set exists; for (AstMemberDType* itemp = membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) { exists.insert(itemp); From ed1e377bb1f921f487db5e8be35b5fcb13a4bea9 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 16 Mar 2023 21:40:01 -0400 Subject: [PATCH 059/155] Fix large return blocks with --comp-limit-blocks (#4028). --- Changes | 1 + src/V3DepthBlock.cpp | 1 + test_regress/t/t_func_many_return.pl | 22 +++ test_regress/t/t_func_many_return.v | 251 +++++++++++++++++++++++++++ 4 files changed, 275 insertions(+) create mode 100755 test_regress/t/t_func_many_return.pl create mode 100644 test_regress/t/t_func_many_return.v diff --git a/Changes b/Changes index 4b756d649..bcb61457b 100644 --- a/Changes +++ b/Changes @@ -21,6 +21,7 @@ Verilator 5.009 devel * Fix UNDRIVEN warning seg fault (#3989). [Felix Neumärker] * Fix symbol entries when inheriting classes (#3995) (#3996). [Krzysztof Boroński] * Fix push to dynamic queue in struct (#4015). [ezchi] +* Fix large return blocks with --comp-limit-blocks (#4028). [tenghtt] * Fix clocking block scope internal error (#4032). [Srinivasan Venkataramanan] * Fix false ENUMVALUE on expressions and arrays. diff --git a/src/V3DepthBlock.cpp b/src/V3DepthBlock.cpp index f4e4ec5eb..3023f2457 100644 --- a/src/V3DepthBlock.cpp +++ b/src/V3DepthBlock.cpp @@ -93,6 +93,7 @@ private: } } void visit(AstStmtExpr* nodep) override {} // Stop recursion after introducing new function + void visit(AstJumpBlock*) override {} // Stop recursion as can't break up across a jump void visit(AstNodeStmt* nodep) override { m_depth++; if (m_depth > v3Global.opt.compLimitBlocks()) { // Already done diff --git a/test_regress/t/t_func_many_return.pl b/test_regress/t/t_func_many_return.pl new file mode 100755 index 000000000..b51fe33a6 --- /dev/null +++ b/test_regress/t/t_func_many_return.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 2003 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); + +compile( + verilator_flags2 => ["--comp-limit-blocks 100"], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_func_many_return.v b/test_regress/t/t_func_many_return.v new file mode 100644 index 000000000..c8142f24b --- /dev/null +++ b/test_regress/t/t_func_many_return.v @@ -0,0 +1,251 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2013 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + + function automatic string get_csr_name(input logic [11:0] csr_addr); + // verilator no_inline_task + unique case (csr_addr) + 12'd0000: return "xx0000xxxxx"; + 12'd0001: return "xx0001xxxx"; + 12'd1952: return "xx1952xxxxx"; + 12'd1953: return "xx1953xxx1"; + 12'd1954: return "xx1954xxx2"; + 12'd1955: return "xx1955xxx3"; + 12'd1968: return "xx1968xx"; + 12'd1969: return "xx1969x"; + 12'd1970: return "xx1970xxxxxx"; + 12'd0256: return "xx0256xxxxx"; + 12'd0258: return "xx0258xxxxx"; + 12'd0259: return "xx0259xxxxx"; + 12'd0260: return "xx0260x"; + 12'd0261: return "xx0261xxx"; + 12'd0262: return "xx0262xxxxxxxx"; + 12'd2816: return "xx2816xxxx"; + 12'd2818: return "xx2818xxxxxx"; + 12'd2819: return "xx2819xxxxxxxxx3"; + 12'd2820: return "xx2820xxxxxxxxx4"; + 12'd2821: return "xx2821xxxxxxxxx5"; + 12'd2822: return "xx2822xxxxxxxxx6"; + 12'd2823: return "xx2823xxxxxxxxx7"; + 12'd2824: return "xx2824xxxxxxxxx8"; + 12'd2825: return "xx2825xxxxxxxxx9"; + 12'd2826: return "xx2826xxxxxxxxx10"; + 12'd2827: return "xx2827xxxxxxxxx11"; + 12'd2828: return "xx2828xxxxxxxxx12"; + 12'd2829: return "xx2829xxxxxxxxx13"; + 12'd2830: return "xx2830xxxxxxxxx14"; + 12'd2831: return "xx2831xxxxxxxxx15"; + 12'd2832: return "xx2832xxxxxxxxx16"; + 12'd2833: return "xx2833xxxxxxxxx17"; + 12'd2834: return "xx2834xxxxxxxxx18"; + 12'd2835: return "xx2835xxxxxxxxx19"; + 12'd2836: return "xx2836xxxxxxxxx20"; + 12'd2837: return "xx2837xxxxxxxxx21"; + 12'd2838: return "xx2838xxxxxxxxx22"; + 12'd2839: return "xx2839xxxxxxxxx23"; + 12'd2840: return "xx2840xxxxxxxxx24"; + 12'd2841: return "xx2841xxxxxxxxx25"; + 12'd2842: return "xx2842xxxxxxxxx26"; + 12'd2843: return "xx2843xxxxxxxxx27"; + 12'd2844: return "xx2844xxxxxxxxx28"; + 12'd2845: return "xx2845xxxxxxxxx29"; + 12'd2846: return "xx2846xxxxxxxxx30"; + 12'd2847: return "xx2847xxxxxxxxx31"; + 12'd2944: return "xx2944xxxxx"; + 12'd2946: return "xx2946xxxxxxx"; + 12'd2947: return "xx2947xxxxxxxxx3x"; + 12'd2948: return "xx2948xxxxxxxxx4x"; + 12'd2949: return "xx2949xxxxxxxxx5x"; + 12'd2950: return "xx2950xxxxxxxxx6x"; + 12'd2951: return "xx2951xxxxxxxxx7x"; + 12'd2952: return "xx2952xxxxxxxxx8x"; + 12'd2953: return "xx2953xxxxxxxxx9x"; + 12'd2954: return "xx2954xxxxxxxxx10x"; + 12'd2955: return "xx2955xxxxxxxxx11x"; + 12'd2956: return "xx2956xxxxxxxxx12x"; + 12'd2957: return "xx2957xxxxxxxxx13x"; + 12'd2958: return "xx2958xxxxxxxxx14x"; + 12'd2959: return "xx2959xxxxxxxxx15x"; + 12'd2960: return "xx2960xxxxxxxxx16x"; + 12'd2961: return "xx2961xxxxxxxxx17x"; + 12'd2962: return "xx2962xxxxxxxxx18x"; + 12'd2963: return "xx2963xxxxxxxxx19x"; + 12'd2964: return "xx2964xxxxxxxxx20x"; + 12'd2965: return "xx2965xxxxxxxxx21x"; + 12'd2966: return "xx2966xxxxxxxxx22x"; + 12'd2967: return "xx2967xxxxxxxxx23x"; + 12'd2968: return "xx2968xxxxxxxxx24x"; + 12'd2969: return "xx2969xxxxxxxxx25x"; + 12'd2970: return "xx2970xxxxxxxxx26x"; + 12'd2971: return "xx2971xxxxxxxxx27x"; + 12'd2972: return "xx2972xxxxxxxxx28x"; + 12'd2973: return "xx2973xxxxxxxxx29x"; + 12'd2974: return "xx2974xxxxxxxxx30x"; + 12'd2975: return "xx2975xxxxxxxxx31x"; + 12'd0002: return "xx0002x"; + 12'd3072: return "xx3072xxx"; + 12'd3073: return "xx3073xx"; + 12'd3074: return "xx3074xxxxx"; + 12'd3075: return "xx3075xxxxxxxx3"; + 12'd3076: return "xx3076xxxxxxxx4"; + 12'd3077: return "xx3077xxxxxxxx5"; + 12'd3078: return "xx3078xxxxxxxx6"; + 12'd3079: return "xx3079xxxxxxxx7"; + 12'd3080: return "xx3080xxxxxxxx8"; + 12'd3081: return "xx3081xxxxxxxx9"; + 12'd3082: return "xx3082xxxxxxxx10"; + 12'd3083: return "xx3083xxxxxxxx11"; + 12'd3084: return "xx3084xxxxxxxx12"; + 12'd3085: return "xx3085xxxxxxxx13"; + 12'd3086: return "xx3086xxxxxxxx14"; + 12'd3087: return "xx3087xxxxxxxx15"; + 12'd3088: return "xx3088xxxxxxxx16"; + 12'd3089: return "xx3089xxxxxxxx17"; + 12'd3090: return "xx3090xxxxxxxx18"; + 12'd3091: return "xx3091xxxxxxxx19"; + 12'd3092: return "xx3092xxxxxxxx20"; + 12'd3093: return "xx3093xxxxxxxx21"; + 12'd3094: return "xx3094xxxxxxxx22"; + 12'd3095: return "xx3095xxxxxxxx23"; + 12'd3096: return "xx3096xxxxxxxx24"; + 12'd3097: return "xx3097xxxxxxxx25"; + 12'd3098: return "xx3098xxxxxxxx26"; + 12'd3099: return "xx3099xxxxxxxx27"; + 12'd3100: return "xx3100xxxxxxxx28"; + 12'd3101: return "xx3101xxxxxxxx29"; + 12'd3102: return "xx3102xxxxxxxx30"; + 12'd3103: return "xx3103xxxxxxxx31"; + 12'd3200: return "xx3200xxxx"; + 12'd3201: return "xx3201xxx"; + 12'd3202: return "xx3202xxxxxx"; + 12'd3203: return "xx3203xxxxxxxx3x"; + 12'd3204: return "xx3204xxxxxxxx4x"; + 12'd3205: return "xx3205xxxxxxxx5x"; + 12'd3206: return "xx3206xxxxxxxx6x"; + 12'd3207: return "xx3207xxxxxxxx7x"; + 12'd3208: return "xx3208xxxxxxxx8x"; + 12'd3209: return "xx3209xxxxxxxx9x"; + 12'd0320: return "xx0320xxxxxx"; + 12'd3210: return "xx3210xxxxxxxx10x"; + 12'd3211: return "xx3211xxxxxxxx11x"; + 12'd3212: return "xx3212xxxxxxxx12x"; + 12'd3213: return "xx3213xxxxxxxx13x"; + 12'd3214: return "xx3214xxxxxxxx14x"; + 12'd3215: return "xx3215xxxxxxxx15x"; + 12'd3216: return "xx3216xxxxxxxx16x"; + 12'd3217: return "xx3217xxxxxxxx17x"; + 12'd3218: return "xx3218xxxxxxxx18x"; + 12'd3219: return "xx3219xxxxxxxx19x"; + 12'd3220: return "xx3220xxxxxxxx20x"; + 12'd3221: return "xx3221xxxxxxxx21x"; + 12'd3222: return "xx3222xxxxxxxx22x"; + 12'd3223: return "xx3223xxxxxxxx23x"; + 12'd3224: return "xx3224xxxxxxxx24x"; + 12'd3225: return "xx3225xxxxxxxx25x"; + 12'd3226: return "xx3226xxxxxxxx26x"; + 12'd3227: return "xx3227xxxxxxxx27x"; + 12'd3228: return "xx3228xxxxxxxx28x"; + 12'd3229: return "xx3229xxxxxxxx29x"; + 12'd3230: return "xx3230xxxxxxxx30x"; + 12'd3231: return "xx3231xxxxxxxx31x"; + 12'd3857: return "xx3857xxxxxxx"; + 12'd3858: return "xx3858xxxxx"; + 12'd3859: return "xx3859xxxx"; + 12'd3860: return "xx3860xxxxx"; + 12'd0512: return "xx0512xxxxx"; + 12'd0514: return "xx0514xxxxx"; + 12'd0515: return "xx0515xxxxx"; + 12'd0516: return "xx0516x"; + 12'd0517: return "xx0517xxx"; + 12'd0576: return "xx0576xxxxxx"; + 12'd0577: return "xx0577xx"; + 12'd0578: return "xx0578xxxx"; + 12'd0579: return "xx0579xxxxxx"; + 12'd0580: return "xx0580x"; + 12'd0768: return "xx0768xxxxx"; + 12'd0769: return "xx0769xx"; + 12'd0770: return "xx0770xxxxx"; + 12'd0771: return "xx0771xxxxx"; + 12'd0772: return "xx0772x"; + 12'd0773: return "xx0773xxx"; + 12'd0774: return "xx0774xxxxxxxx"; + 12'd0800: return "xx0800xxxxxxxxxxx"; + 12'd0803: return "xx0803xxxxxxx3"; + 12'd0804: return "xx0804xxxxxxx4"; + 12'd0805: return "xx0805xxxxxxx5"; + 12'd0806: return "xx0806xxxxxxx6"; + 12'd0807: return "xx0807xxxxxxx7"; + 12'd0808: return "xx0808xxxxxxx8"; + 12'd0809: return "xx0809xxxxxxx9"; + 12'd0810: return "xx0810xxxxxxx10"; + 12'd0811: return "xx0811xxxxxxx11"; + 12'd0812: return "xx0812xxxxxxx12"; + 12'd0813: return "xx0813xxxxxxx13"; + 12'd0814: return "xx0814xxxxxxx14"; + 12'd0815: return "xx0815xxxxxxx15"; + 12'd0816: return "xx0816xxxxxxx16"; + 12'd0817: return "xx0817xxxxxxx17"; + 12'd0818: return "xx0818xxxxxxx18"; + 12'd0819: return "xx0819xxxxxxx19"; + 12'd0820: return "xx0820xxxxxxx20"; + 12'd0821: return "xx0821xxxxxxx21"; + 12'd0822: return "xx0822xxxxxxx22"; + 12'd0823: return "xx0823xxxxxxx23"; + 12'd0824: return "xx0824xxxxxxx24"; + 12'd0825: return "xx0825xxxxxxx25"; + 12'd0826: return "xx0826xxxxxxx26"; + 12'd0827: return "xx0827xxxxxxx27"; + 12'd0828: return "xx0828xxxxxxx28"; + 12'd0829: return "xx0829xxxxxxx29"; + 12'd0830: return "xx0830xxxxxxx30"; + 12'd0831: return "xx0831xxxxxxx31"; + 12'd0832: return "xx0832xxxxxx"; + 12'd0833: return "xx0833xx"; + 12'd0834: return "xx0834xxxx"; + 12'd0835: return "xx0835xxx"; + 12'd0836: return "xx0836x"; + 12'd0896: return "xx0896xxx"; + 12'd0897: return "xx0897xxxx"; + 12'd0898: return "xx0898xxxx"; + 12'd0899: return "xx0899xxxxx"; + 12'd0900: return "xx0900xxxx"; + 12'd0901: return "xx0901xxxxx"; + 12'd0928: return "xx0928xxxx0"; + 12'd0929: return "xx0929xxxx1"; + 12'd0930: return "xx0930xxxx2"; + 12'd0931: return "xx0931xxxx3"; + 12'd0944: return "xx0944xxxxx0"; + 12'd0945: return "xx0945xxxxx1"; + 12'd0946: return "xx0946xxxxx2"; + 12'd0947: return "xx0947xxxxx3"; + 12'd0948: return "xx0948xxxxx4"; + 12'd0949: return "xx0949xxxxx5"; + 12'd0950: return "xx0950xxxxx6"; + 12'd0951: return "xx0951xxxxx7"; + 12'd0952: return "xx0952xxxxx8"; + 12'd0953: return "xx0953xxxxx9"; + 12'd0954: return "xx0954xxxxx10"; + 12'd0955: return "xx0955xxxxx11"; + 12'd0956: return "xx0956xxxxx12"; + 12'd0957: return "xx0957xxxxx13"; + 12'd0958: return "xx0958xxxxx14"; + 12'd0959: return "xx0959xxxxx15"; + default: return $sformatf("0x%x", csr_addr); + endcase + endfunction + + int i; + + initial begin + if (get_csr_name(12'd0957) != "xx0957xxxxx13") $stop; + if (get_csr_name(12'd2830) != "xx2830xxxxxxxxx14") $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From 85fd88ace2447fde2986f2861f8f2e66295235d7 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 16 Mar 2023 22:18:03 -0400 Subject: [PATCH 060/155] Optimize duplicate JumpBlocks away (#4028) --- src/V3AstNodeOther.h | 2 +- src/V3Const.cpp | 2 +- src/V3LinkJump.cpp | 19 +++++++++++++++++++ src/V3Simulate.h | 2 +- test_regress/t/t_debug_emitv.out | 10 ++++------ 5 files changed, 26 insertions(+), 9 deletions(-) diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 607f3f52d..72db0c8d0 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -2779,7 +2779,7 @@ public: bool isFirstInMyListOfStatements(AstNode* n) const override { return n == stmtsp(); } }; class AstJumpBlock final : public AstNodeStmt { - // Block of code including a JumpGo and JumpLabel + // Block of code including a single JumpLabel, and 0+ JumpGo's to that label // Parents: {statement list} // Children: {statement list, with JumpGo and JumpLabel below} // @astgen op1 := stmtsp : List[AstNode] diff --git a/src/V3Const.cpp b/src/V3Const.cpp index dc195e158..8824aa2e1 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -3207,7 +3207,7 @@ private: void visit(AstJumpGo* nodep) override { iterateChildren(nodep); - // Jump to label where label immediately follows label is not useful + // Jump to label where label immediately follows this go is not useful if (nodep->labelp() == VN_CAST(nodep->nextp(), JumpLabel)) { VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); // Keep the label, might be other jumps pointing to it, gets cleaned later diff --git a/src/V3LinkJump.cpp b/src/V3LinkJump.cpp index ec1ce3f1a..deba207eb 100644 --- a/src/V3LinkJump.cpp +++ b/src/V3LinkJump.cpp @@ -35,6 +35,7 @@ #include "V3LinkJump.h" #include "V3Ast.h" +#include "V3AstUserAllocator.h" #include "V3Global.h" #include @@ -46,6 +47,12 @@ VL_DEFINE_DEBUG_FUNCTIONS; class LinkJumpVisitor final : public VNVisitor { private: + // NODE STATE + // AstNode::user1() -> AstJumpLabel*, for this block if endOfIter + // AstNode::user2() -> AstJumpLabel*, for this block if !endOfIter + const VNUser1InUse m_user1InUse; + const VNUser2InUse m_user2InUse; + // STATE AstNodeModule* m_modp = nullptr; // Current module AstNodeFTask* m_ftaskp = nullptr; // Current function/task @@ -61,6 +68,13 @@ private: UINFO(4, "Create label for " << nodep << endl); if (VN_IS(nodep, JumpLabel)) return VN_AS(nodep, JumpLabel); // Done + // Made it previously? We always jump to the end, so this works out + if (endOfIter) { + if (nodep->user1p()) return VN_AS(nodep->user1p(), JumpLabel); + } else { + if (nodep->user2p()) return VN_AS(nodep->user2p(), JumpLabel); + } + AstNode* underp = nullptr; bool under_and_next = true; if (VN_IS(nodep, NodeBlock)) { @@ -125,6 +139,11 @@ private: } // Label goes last blockp->addEndStmtsp(labelp); + if (endOfIter) { + nodep->user1p(labelp); + } else { + nodep->user2p(labelp); + } return labelp; } } diff --git a/src/V3Simulate.h b/src/V3Simulate.h index 7668b453d..d8b5e599a 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -103,7 +103,7 @@ private: bool m_isOutputter; // Creates output int m_instrCount; ///< Number of nodes int m_dataCount; ///< Bytes of data - AstJumpGo* m_jumpp; ///< Jump label we're branching from + AstJumpGo* m_jumpp = nullptr; ///< Jump label we're branching from // Simulating: std::unordered_map> m_constps; ///< Lists of all AstConst* allocated per dtype diff --git a/test_regress/t/t_debug_emitv.out b/test_regress/t/t_debug_emitv.out index 2775f2c02..abfcc0c61 100644 --- a/test_regress/t/t_debug_emitv.out +++ b/test_regress/t/t_debug_emitv.out @@ -337,14 +337,12 @@ module Vt_debug_emitv_sub; function f; input signed int [31:0] v; begin : label0 - begin : label0 - if ((v == 'sh0)) begin - f = 'sh21; - disable label0; - end - f = ({32'h1{{31'h0, v[2]}}} + 32'h1); + if ((v == 'sh0)) begin + f = 'sh21; disable label0; end + f = ({32'h1{{31'h0, v[2]}}} + 32'h1); + disable label0; end endfunction signed real r; From 1ac721af8f3d971ee9c3b1ec5e76cb10fd514920 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Fri, 17 Mar 2023 12:48:41 +0100 Subject: [PATCH 061/155] Add STATICVAR warning and convert to automatic (#4027) (#4030) Signed-off-by: Ryszard Rozak --- docs/guide/exe_verilator.rst | 2 +- docs/guide/warnings.rst | 11 +++++++++++ src/V3Error.h | 7 ++++--- src/V3LinkParse.cpp | 6 ++++-- test_regress/t/t_static_in_loop_unsup.out | 5 +++-- 5 files changed, 23 insertions(+), 8 deletions(-) diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index 795b7b141..36ad7a6f4 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -1517,7 +1517,7 @@ Summary: equivalent to ``-Wno-ALWCOMBORDER -Wno-BSSPACE -Wno-CASEINCOMPLETE -Wno-CASEOVERLAP -Wno-CASEX -Wno-CASTCONST -Wno-CASEWITHX -Wno-CMPCONST -Wno-COLONPLUS -Wno-IMPLICIT -Wno-IMPLICITSTATIC -Wno-LITENDIAN -Wno-PINCONNECTEMPTY - -Wno-PINMISSING -Wno-SYNCASYNCNET -Wno-UNDRIVEN -Wno-UNSIGNED + -Wno-PINMISSING -Wno-STATICVAR -Wno-SYNCASYNCNET -Wno-UNDRIVEN -Wno-UNSIGNED -Wno-UNUSEDGENVAR -Wno-UNUSEDPARAM -Wno-UNUSEDSIGNAL -Wno-WIDTH`` plus the list shown for Wno-style. diff --git a/docs/guide/warnings.rst b/docs/guide/warnings.rst index e19c6a6a1..33763ec79 100644 --- a/docs/guide/warnings.rst +++ b/docs/guide/warnings.rst @@ -1302,6 +1302,17 @@ List Of Warnings * The variable is tristate or bidirectional. (e.g., :code:`inout`). +.. option:: STATICVAR + + Warns that a static variable declared in a loop with declaration assignment + was converted to automatic. Often such variables were intended to + instead be declared "automatic". + + Ignoring this warning may make Verilator differ from other simulators, + which will treat the variable as static. Verilator may in future versions also + treat the variable as static. + + .. option:: STMTDLY Warns that the code has a statement with a delayed time in front of it. diff --git a/src/V3Error.h b/src/V3Error.h index bb6a3d63c..4d7f3b1de 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -131,6 +131,7 @@ public: SELRANGE, // Selection index out of range SHORTREAL, // Shortreal not supported SPLITVAR, // Cannot split the variable + STATICVAR, // Static variable declared in a loop with a declaration assignment STMTDLY, // Delayed statement SYMRSVDWORD, // Symbol is Reserved Word SYNCASYNCNET, // Mixed sync + async reset @@ -195,7 +196,7 @@ public: "MULTIDRIVEN", "MULTITOP", "NOLATCH", "NULLPORT", "PINCONNECTEMPTY", "PINMISSING", "PINNOCONNECT", "PINNOTFOUND", "PKGNODECL", "PROCASSWIRE", "PROFOUTOFDATE", "PROTECTED", "RANDC", "REALCVT", "REDEFMACRO", "RISEFALLDLY", - "SELRANGE", "SHORTREAL", "SPLITVAR", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET", + "SELRANGE", "SHORTREAL", "SPLITVAR", "STATICVAR", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET", "TICKCOUNT", "TIMESCALEMOD", "UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS", "UNPACKED", "UNSIGNED", "UNUSEDGENVAR", "UNUSEDPARAM", "UNUSEDSIGNAL", @@ -231,8 +232,8 @@ public: || m_e == CASEOVERLAP || m_e == CASEWITHX || m_e == CASEX || m_e == CASTCONST || m_e == CMPCONST || m_e == COLONPLUS || m_e == IMPLICIT || m_e == IMPLICITSTATIC || m_e == LATCH || m_e == LITENDIAN || m_e == PINMISSING || m_e == REALCVT - || m_e == UNSIGNED || m_e == WIDTH || m_e == WIDTHTRUNC || m_e == WIDTHEXPAND - || m_e == WIDTHXZEXPAND); + || m_e == STATICVAR || m_e == UNSIGNED || m_e == WIDTH || m_e == WIDTHTRUNC + || m_e == WIDTHEXPAND || m_e == WIDTHXZEXPAND); } // Warnings that are style only bool styleError() const VL_MT_SAFE { diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 3936eb974..e92ad24f2 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -223,8 +223,10 @@ private: void visit(AstVar* nodep) override { cleanFileline(nodep); - if (nodep->lifetime().isStatic() && m_insideLoop) { - nodep->v3warn(E_UNSUPPORTED, "Unsupported: Static variable inside a loop"); + if (nodep->lifetime().isStatic() && m_insideLoop && nodep->valuep()) { + nodep->lifetime(VLifetime::AUTOMATIC); + nodep->v3warn(STATICVAR, "Static variable with assignment declaration declared in a " + "loop converted to automatic"); } if (nodep->lifetime().isNone() && nodep->varType() != VVarType::PORT) { nodep->lifetime(m_lifetime); diff --git a/test_regress/t/t_static_in_loop_unsup.out b/test_regress/t/t_static_in_loop_unsup.out index 65c68f6e1..0070d8d3f 100644 --- a/test_regress/t/t_static_in_loop_unsup.out +++ b/test_regress/t/t_static_in_loop_unsup.out @@ -1,5 +1,6 @@ -%Error-UNSUPPORTED: t/t_static_in_loop_unsup.v:14:24: Unsupported: Static variable inside a loop +%Warning-STATICVAR: t/t_static_in_loop_unsup.v:14:24: Static variable with assignment declaration declared in a loop converted to automatic 14 | static int a = 0; | ^ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest + ... For warning description see https://verilator.org/warn/STATICVAR?v=latest + ... Use "/* verilator lint_off STATICVAR */" and lint_on around source to disable this message. %Error: Exiting due to From 371b8310d9ca49ae6fceb258ce85cf3f7692e4cf Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Fri, 17 Mar 2023 13:25:39 +0100 Subject: [PATCH 062/155] Support method calls without parenthesis (#4034) * Support method class without parenthesis Signed-off-by: Ryszard Rozak * Delete replaced nodes Signed-off-by: Ryszard Rozak --------- Signed-off-by: Ryszard Rozak --- src/V3Width.cpp | 8 ++++++++ test_regress/t/t_class_method.v | 1 + 2 files changed, 9 insertions(+) diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 70ced22a4..7e556bca6 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -2667,6 +2667,14 @@ private: } if (AstEnumItemRef* const adfoundp = VN_CAST(foundp, EnumItemRef)) { nodep->replaceWith(adfoundp->cloneTree(false)); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + return; + } + if (AstNodeFTask* const methodp = VN_CAST(foundp, NodeFTask)) { + nodep->replaceWith(new AstMethodCall{nodep->fileline(), + nodep->fromp()->unlinkFrBack(), + nodep->name(), nullptr}); + VL_DO_DANGLING(pushDeletep(nodep), nodep); return; } UINFO(1, "found object " << foundp << endl); diff --git a/test_regress/t/t_class_method.v b/test_regress/t/t_class_method.v index feda390fd..b1aefcb5d 100644 --- a/test_regress/t/t_class_method.v +++ b/test_regress/t/t_class_method.v @@ -24,6 +24,7 @@ module t (/*AUTOARG*/); if (c.get_methoda() != 20) $stop; c.setv_methoda(30); if (c.get_methoda() != 30) $stop; + if (c.get_methoda != 30) $stop; $write("*-* All Finished *-*\n"); $finish; end From d6c5d40f9b73b531ee06bdc5f94667229a3e8d70 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 17 Mar 2023 19:58:53 -0400 Subject: [PATCH 063/155] Internals: Add VNVisitorConst class. --- src/V3Ast.cpp | 16 ++++----- src/V3Ast.h | 81 +++++++++++++++++++++++++++---------------- src/V3AstNodeExpr.h | 4 +-- src/V3Broken.cpp | 4 +-- src/V3Const.cpp | 2 +- src/V3EmitCFunc.h | 6 ++-- src/V3EmitCImp.cpp | 4 +-- src/V3EmitXml.cpp | 2 +- src/V3LinkDot.cpp | 6 ++-- src/V3LinkResolve.cpp | 2 +- src/V3Stats.cpp | 6 ++-- src/V3Tristate.cpp | 2 +- src/V3Width.cpp | 6 ++-- src/astgen | 4 +-- 14 files changed, 83 insertions(+), 62 deletions(-) diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 49d1a0434..86e89fac3 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -907,7 +907,7 @@ void AstNode::iterateChildren(VNVisitor& v) { if (m_op4p) m_op4p->iterateAndNext(v); } -void AstNode::iterateChildrenConst(VNVisitor& v) { +void AstNode::iterateChildrenConst(VNVisitorConst& v) { // This is a very hot function ASTNODE_PREFETCH(m_op1p); ASTNODE_PREFETCH(m_op2p); @@ -954,7 +954,7 @@ void AstNode::iterateAndNext(VNVisitor& v) { } } -void AstNode::iterateListBackwards(VNVisitor& v) { +void AstNode::iterateListBackwardsConst(VNVisitorConst& v) { AstNode* nodep = this; while (nodep->m_nextp) nodep = nodep->m_nextp; while (nodep) { @@ -968,14 +968,14 @@ void AstNode::iterateListBackwards(VNVisitor& v) { } } -void AstNode::iterateChildrenBackwards(VNVisitor& v) { - if (m_op1p) m_op1p->iterateListBackwards(v); - if (m_op2p) m_op2p->iterateListBackwards(v); - if (m_op3p) m_op3p->iterateListBackwards(v); - if (m_op4p) m_op4p->iterateListBackwards(v); +void AstNode::iterateChildrenBackwardsConst(VNVisitorConst& v) { + if (m_op1p) m_op1p->iterateListBackwardsConst(v); + if (m_op2p) m_op2p->iterateListBackwardsConst(v); + if (m_op3p) m_op3p->iterateListBackwardsConst(v); + if (m_op4p) m_op4p->iterateListBackwardsConst(v); } -void AstNode::iterateAndNextConst(VNVisitor& v) { +void AstNode::iterateAndNextConst(VNVisitorConst& v) { // Keep following the current list even if edits change it AstNode* nodep = this; do { diff --git a/src/V3Ast.h b/src/V3Ast.h index a325e5620..0d4ae58a7 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1373,13 +1373,38 @@ public: virtual ~VNDeleter() { doDeletes(); } }; +//###################################################################### +// VNVisitorConst -- Allows new functions to be called on each node +// type without changing the base classes. See "Modern C++ Design". +// This only has the constant fuctions for non-modifying visitors. +// For more typical usage see VNVisitor + +class VNVisitorConst VL_NOT_FINAL : public VNDeleter { + friend class AstNode; + +public: + /// Call visit()s on nodep + inline void iterateConst(AstNode* nodep); + /// Call visit()s on nodep + inline void iterateConstNull(AstNode* nodep); + /// Call visit()s on const nodep's children + inline void iterateChildrenConst(AstNode* nodep); + /// Call visit()s on nodep's children in backp() order + inline void iterateChildrenBackwardsConst(AstNode* nodep); + /// Call visit()s on const nodep (maybe nullptr) and nodep's nextp() list + inline void iterateAndNextConstNull(AstNode* nodep); + /// Call visit()s on const nodep (maybe nullptr) and nodep's nextp() list, in reverse order + inline void iterateAndNextConstNullBackwards(AstNode* nodep); + + virtual void visit(AstNode* nodep) = 0; +#include "V3Ast__gen_visitor_decls.h" // From ./astgen +}; + //###################################################################### // VNVisitor -- Allows new functions to be called on each node // type without changing the base classes. See "Modern C++ Design". -class VNVisitor VL_NOT_FINAL : public VNDeleter { - friend class AstNode; - +class VNVisitor VL_NOT_FINAL : public VNVisitorConst { public: /// Call visit()s on nodep inline void iterate(AstNode* nodep); @@ -1387,21 +1412,10 @@ public: inline void iterateNull(AstNode* nodep); /// Call visit()s on nodep's children inline void iterateChildren(AstNode* nodep); - /// Call visit()s on nodep's children in backp() order - inline void iterateChildrenBackwards(AstNode* nodep); - /// Call visit()s on const nodep's children - inline void iterateChildrenConst(AstNode* nodep); /// Call visit()s on nodep (maybe nullptr) and nodep's nextp() list inline void iterateAndNextNull(AstNode* nodep); - /// Call visit()s on const nodep (maybe nullptr) and nodep's nextp() list - inline void iterateAndNextConstNull(AstNode* nodep); - /// Call visit()s on const nodep (maybe nullptr) and nodep's nextp() list, in reverse order - inline void iterateAndNextConstNullBackwards(AstNode* nodep); /// Return edited nodep; see comments in V3Ast.cpp inline AstNode* iterateSubtreeReturnEdits(AstNode* nodep); - - virtual void visit(AstNode* nodep) = 0; -#include "V3Ast__gen_visitor_decls.h" // From ./astgen }; //###################################################################### @@ -1631,6 +1645,7 @@ public: bool brokeExistsAbove() const { return brokeExists() && (m_brokenState >> 7); } bool brokeExistsBelow() const { return brokeExists() && !(m_brokenState >> 7); } // Note: brokeExistsBelow is not quite precise, as it is true for sibling nodes as well + bool brokeIterpp() const { return !!m_iterpp; } // CONSTRUCTORS virtual ~AstNode() = default; @@ -1964,26 +1979,27 @@ public: virtual const char* broken() const { return nullptr; } // INVOKERS - virtual void accept(VNVisitor& v) = 0; + virtual void accept(VNVisitorConst& v) = 0; protected: // All VNVisitor related functions are called as methods off the visitor friend class VNVisitor; + friend class VNVisitorConst; // Use instead VNVisitor::iterateChildren void iterateChildren(VNVisitor& v); - // Use instead VNVisitor::iterateChildrenBackwards - void iterateChildrenBackwards(VNVisitor& v); + // Use instead VNVisitor::iterateChildrenBackwardsConst + void iterateChildrenBackwardsConst(VNVisitorConst& v); // Use instead VNVisitor::iterateChildrenConst - void iterateChildrenConst(VNVisitor& v); + void iterateChildrenConst(VNVisitorConst& v); // Use instead VNVisitor::iterateAndNextNull void iterateAndNext(VNVisitor& v); // Use instead VNVisitor::iterateAndNextConstNull - void iterateAndNextConst(VNVisitor& v); + void iterateAndNextConst(VNVisitorConst& v); // Use instead VNVisitor::iterateSubtreeReturnEdits AstNode* iterateSubtreeReturnEdits(VNVisitor& v); private: - void iterateListBackwards(VNVisitor& v); + void iterateListBackwardsConst(VNVisitorConst& v); // For internal use only. // Note: specializations for particular node types are provided by 'astgen' @@ -2483,24 +2499,29 @@ struct std::equal_to> final { //###################################################################### // Inline VNVisitor METHODS +void VNVisitorConst::iterateConst(AstNode* nodep) { nodep->accept(*this); } +void VNVisitorConst::iterateConstNull(AstNode* nodep) { + if (VL_LIKELY(nodep)) nodep->accept(*this); +} +void VNVisitorConst::iterateChildrenConst(AstNode* nodep) { nodep->iterateChildrenConst(*this); } +void VNVisitorConst::iterateChildrenBackwardsConst(AstNode* nodep) { + nodep->iterateChildrenBackwardsConst(*this); +} +void VNVisitorConst::iterateAndNextConstNullBackwards(AstNode* nodep) { + if (VL_LIKELY(nodep)) nodep->iterateListBackwardsConst(*this); +} +void VNVisitorConst::iterateAndNextConstNull(AstNode* nodep) { + if (VL_LIKELY(nodep)) nodep->iterateAndNextConst(*this); +} + void VNVisitor::iterate(AstNode* nodep) { nodep->accept(*this); } void VNVisitor::iterateNull(AstNode* nodep) { if (VL_LIKELY(nodep)) nodep->accept(*this); } void VNVisitor::iterateChildren(AstNode* nodep) { nodep->iterateChildren(*this); } -void VNVisitor::iterateChildrenBackwards(AstNode* nodep) { - nodep->iterateChildrenBackwards(*this); -} -void VNVisitor::iterateChildrenConst(AstNode* nodep) { nodep->iterateChildrenConst(*this); } void VNVisitor::iterateAndNextNull(AstNode* nodep) { if (VL_LIKELY(nodep)) nodep->iterateAndNext(*this); } -void VNVisitor::iterateAndNextConstNullBackwards(AstNode* nodep) { - if (VL_LIKELY(nodep)) nodep->iterateListBackwards(*this); -} -void VNVisitor::iterateAndNextConstNull(AstNode* nodep) { - if (VL_LIKELY(nodep)) nodep->iterateAndNextConst(*this); -} AstNode* VNVisitor::iterateSubtreeReturnEdits(AstNode* nodep) { return nodep->iterateSubtreeReturnEdits(*this); } diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index de4de290c..5e12b2bd1 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -322,7 +322,7 @@ public: ASTGEN_MEMBERS_AstNodeTermop; // Know no children, and hot function, so skip iterator for speed // cppcheck-suppress functionConst - void iterateChildren(VNVisitor& v) {} + void iterateChildren(VNVisitorConst& v) {} void dump(std::ostream& str) const override; }; class AstNodeTriop VL_NOT_FINAL : public AstNodeExpr { @@ -492,7 +492,7 @@ public: void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } // Know no children, and hot function, so skip iterator for speed // cppcheck-suppress functionConst - void iterateChildren(VNVisitor& v) {} + void iterateChildren(VNVisitorConst& v) {} }; // === Concrete node types ===================================================== diff --git a/src/V3Broken.cpp b/src/V3Broken.cpp index aa02b4dd3..09ab9b7ef 100644 --- a/src/V3Broken.cpp +++ b/src/V3Broken.cpp @@ -144,7 +144,7 @@ bool V3Broken::isLinkable(const AstNode* nodep) { return s_linkableTable.isLinka //###################################################################### // Check every node in tree -class BrokenCheckVisitor final : public VNVisitor { +class BrokenCheckVisitor final : public VNVisitorConst { bool m_inScope = false; // Under AstScope // Constants for marking we are under/not under a node @@ -312,7 +312,7 @@ private: public: // CONSTRUCTORS - explicit BrokenCheckVisitor(AstNetlist* nodep) { iterate(nodep); } + explicit BrokenCheckVisitor(AstNetlist* nodep) { iterateConstNull(nodep); } ~BrokenCheckVisitor() override = default; }; diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 8824aa2e1..6d7a9751c 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -2265,7 +2265,7 @@ private: // VISITORS void visit(AstNetlist* nodep) override { // Iterate modules backwards, in bottom-up order. That's faster - iterateChildrenBackwards(nodep); + iterateChildrenBackwardsConst(nodep); } void visit(AstNodeModule* nodep) override { VL_RESTORER(m_modp); diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 936196abc..a2bb47892 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -34,7 +34,7 @@ constexpr int EMITC_NUM_CONSTW = 8; //###################################################################### // Emit lazy forward declarations -class EmitCLazyDecls final : public VNVisitor { +class EmitCLazyDecls final : public VNVisitorConst { // NODE STATE/TYPES // None allowed to support threaded emitting @@ -72,12 +72,12 @@ class EmitCLazyDecls final : public VNVisitor { // VISITORS void visit(AstNodeCCall* nodep) override { lazyDeclare(nodep->funcp()); - iterateChildren(nodep); + iterateChildrenConst(nodep); } void visit(AstAddrOfCFunc* nodep) override { lazyDeclare(nodep->funcp()); - iterateChildren(nodep); + iterateChildrenConst(nodep); } void visit(AstVarRef* nodep) override { diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index 8bfc9fcfc..4a96fa118 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -33,7 +33,7 @@ VL_DEFINE_DEBUG_FUNCTIONS; //###################################################################### // Visitor that gathers the headers required by an AstCFunc -class EmitCGatherDependencies final : VNVisitor { +class EmitCGatherDependencies final : VNVisitorConst { // Ordered set, as it is used as a key in another map. std::set m_dependencies; // Header names to be included in output C++ file @@ -142,7 +142,7 @@ class EmitCGatherDependencies final : VNVisitor { // declaration of the receiver class, but their body very likely includes at least one // relative reference, so we are probably not loosing much. addModDependency(EmitCParentModule::get(cfuncp)); - iterate(cfuncp); + iterateConst(cfuncp); } public: diff --git a/src/V3EmitXml.cpp b/src/V3EmitXml.cpp index ef8071a20..d38df87ae 100644 --- a/src/V3EmitXml.cpp +++ b/src/V3EmitXml.cpp @@ -334,7 +334,7 @@ private: // VISITORS void visit(AstNetlist* nodep) override { // Children are iterated backwards to ensure correct compilation order - iterateChildrenBackwards(nodep); + iterateChildrenBackwardsConst(nodep); } void visit(AstNodeModule* nodep) override { // Only list modules and interfaces diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 113be442d..9a4cdffcd 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -780,7 +780,7 @@ class LinkDotFindVisitor final : public VNVisitor { // First back iterate, to find all packages. Backward as must do base // packages before using packages - iterateChildrenBackwards(nodep); + iterateChildrenBackwardsConst(nodep); // The first modules in the list are always the top modules // (sorted before this is called). @@ -1756,7 +1756,7 @@ class LinkDotScopeVisitor final : public VNVisitor { // VISITs void visit(AstNetlist* nodep) override { // Recurse..., backward as must do packages before using packages - iterateChildrenBackwards(nodep); + iterateChildrenBackwardsConst(nodep); } void visit(AstConstPool*) override {} void visit(AstScope* nodep) override { @@ -2238,7 +2238,7 @@ private: // VISITs void visit(AstNetlist* nodep) override { // Recurse..., backward as must do packages before using packages - iterateChildrenBackwards(nodep); + iterateChildrenBackwardsConst(nodep); } void visit(AstTypeTable*) override {} void visit(AstConstPool*) override {} diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 5f9bcbbef..6620c845d 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -454,7 +454,7 @@ private: // VISITs void visit(AstNetlist* nodep) override { // Iterate modules backwards, in bottom-up order. - iterateChildrenBackwards(nodep); + iterateChildrenBackwardsConst(nodep); } void visit(AstNodeModule* nodep) override { VL_RESTORER(m_modp); diff --git a/src/V3Stats.cpp b/src/V3Stats.cpp index df38e83ac..f79da45e4 100644 --- a/src/V3Stats.cpp +++ b/src/V3Stats.cpp @@ -33,7 +33,7 @@ VL_DEFINE_DEBUG_FUNCTIONS; //###################################################################### // Stats class functions -class StatsVisitor final : public VNVisitor { +class StatsVisitor final : public VNVisitorConst { private: // NODE STATE/TYPES @@ -175,7 +175,7 @@ private: if (m_fast && !nodep->funcp()->entryPoint()) { // Enter the function and trace it m_tracingCall = true; - iterate(nodep->funcp()); + iterateConst(nodep->funcp()); } } void visit(AstCFunc* nodep) override { @@ -218,7 +218,7 @@ public: // Initialize arrays m_statTypeCount.resize(VNType::_ENUM_END); // Process - iterate(nodep); + iterateConst(nodep); } ~StatsVisitor() override { // Done. Publish statistics diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index 9837dbb92..26f2e0343 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -1793,7 +1793,7 @@ class TristateVisitor final : public TristateBaseVisitor { iterateChildren(nodep); } - void visit(AstNetlist* nodep) override { iterateChildrenBackwards(nodep); } + void visit(AstNetlist* nodep) override { iterateChildrenBackwardsConst(nodep); } // Default: Just iterate void visit(AstNode* nodep) override { diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 7e556bca6..d6fde7ff4 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -5608,7 +5608,7 @@ private: } void visit(AstNetlist* nodep) override { // Iterate modules backwards, in bottom-up order. That's faster - userIterateChildrenBackwards(nodep, nullptr); + userIterateChildrenBackwardsConst(nodep, nullptr); } //-------------------- @@ -7351,12 +7351,12 @@ private: iterateChildren(nodep); } } - void userIterateChildrenBackwards(AstNode* nodep, WidthVP* vup) { + void userIterateChildrenBackwardsConst(AstNode* nodep, WidthVP* vup) { if (!nodep) return; { VL_RESTORER(m_vup); m_vup = vup; - iterateChildrenBackwards(nodep); + iterateChildrenBackwardsConst(nodep); } } diff --git a/src/astgen b/src/astgen index 9c30529f7..e567b4c21 100755 --- a/src/astgen +++ b/src/astgen @@ -938,7 +938,7 @@ def write_ast_macros(filename): if node.isLeaf: emitBlock('''\ - void accept(VNVisitor& v) override {{ v.visit(this); }} + void accept(VNVisitorConst& v) override {{ v.visit(this); }} AstNode* clone() override {{ return new Ast{t}(*this); }} ''', t=node.name) @@ -1343,7 +1343,7 @@ if Args.classes: # Write Ast code write_forward_class_decls("Ast", AstNodeList) write_visitor_decls("Ast", AstNodeList) - write_visitor_defns("Ast", AstNodeList, "VNVisitor") + write_visitor_defns("Ast", AstNodeList, "VNVisitorConst") write_type_enum("Ast", AstNodeList) write_type_tests("Ast", AstNodeList) write_ast_macros("V3Ast__gen_macros.h") From 798d7346cfb8b8cd3d81ec188359ecbc7c6b4f49 Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Sat, 18 Mar 2023 01:24:15 +0100 Subject: [PATCH 064/155] Internals: Add VL_MT_SAFE attribute to functions that requires locking. (#3805) --- src/V3Active.cpp | 2 +- src/V3Ast.cpp | 4 ++- src/V3Ast.h | 6 ++-- src/V3AstNodeDType.h | 20 ++++++------ src/V3AstNodeExpr.h | 44 +++++++++++++------------- src/V3AstNodeOther.h | 68 ++++++++++++++++++++-------------------- src/V3Config.cpp | 21 +++++++++---- src/V3EmitCBase.h | 6 ++-- src/V3File.cpp | 32 +++++++++++-------- src/V3File.h | 10 +++--- src/V3FileLine.cpp | 6 ++-- src/V3FileLine.h | 9 ++++-- src/V3Gate.cpp | 8 +++-- src/V3Global.h | 4 +-- src/V3GraphTest.cpp | 2 +- src/V3LinkCells.cpp | 6 ++-- src/V3Number.cpp | 4 +-- src/V3Number.h | 4 +-- src/V3Options.cpp | 4 ++- src/V3Options.h | 2 +- src/V3OrderGraph.h | 4 +-- src/V3OrderMoveGraph.h | 2 +- src/V3Os.cpp | 4 ++- src/V3Os.h | 2 +- src/V3Partition.cpp | 2 +- src/V3PartitionGraph.h | 2 +- src/V3SchedAcyclic.cpp | 4 +-- src/V3SchedPartition.cpp | 4 +-- src/V3SchedReplicate.cpp | 4 +-- src/V3Split.cpp | 8 +++-- src/V3Task.cpp | 6 ++-- src/V3Timing.cpp | 2 +- src/V3Tristate.cpp | 2 +- src/V3Waiver.cpp | 10 ++++-- src/V3Waiver.h | 10 ++++-- 35 files changed, 185 insertions(+), 143 deletions(-) diff --git a/src/V3Active.cpp b/src/V3Active.cpp index 68ef3dbf1..2ad8a1a8f 100644 --- a/src/V3Active.cpp +++ b/src/V3Active.cpp @@ -68,7 +68,7 @@ public: : V3GraphVertex{graphp} , m_name{name} , m_type{type} {} - string name() const override { return m_name + " " + typestr(); } + string name() const override VL_MT_STABLE { return m_name + " " + typestr(); } string dotColor() const override { return user() ? "green" : "black"; } virtual int type() const { return m_type; } }; diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 86e89fac3..c60db662f 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -125,7 +125,9 @@ string AstNode::encodeNumber(int64_t num) { } } -string AstNode::nameProtect() const { return VIdProtect::protectIf(name(), protect()); } +string AstNode::nameProtect() const VL_MT_STABLE { + return VIdProtect::protectIf(name(), protect()); +} string AstNode::origNameProtect() const { return VIdProtect::protectIf(origName(), protect()); } string AstNode::shortName() const { diff --git a/src/V3Ast.h b/src/V3Ast.h index 0d4ae58a7..cee54c5b8 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1670,7 +1670,7 @@ public: static constexpr int INSTR_COUNT_PLI = 20; // PLI routines // ACCESSORS - virtual string name() const VL_MT_SAFE { return ""; } + virtual string name() const VL_MT_STABLE { return ""; } virtual string origName() const { return ""; } virtual void name(const string& name) { this->v3fatalSrc("name() called on object without name() method"); @@ -1678,7 +1678,7 @@ public: virtual void tag(const string& text) {} virtual string tag() const { return ""; } virtual string verilogKwd() const { return ""; } - string nameProtect() const; // Name with --protect-id applied + string nameProtect() const VL_MT_STABLE; // Name with --protect-id applied string origNameProtect() const; // origName with --protect-id applied string shortName() const; // Name with __PVT__ removed for concatenating scopes static string dedotName(const string& namein); // Name with dots removed @@ -1691,7 +1691,7 @@ public: encodeName(const string& namein); // Encode user name into internal C representation static string encodeNumber(int64_t num); // Encode number into internal C representation static string vcdName(const string& namein); // Name for printing out to vcd files - string prettyName() const VL_MT_SAFE { return prettyName(name()); } + string prettyName() const VL_MT_STABLE { return prettyName(name()); } string prettyNameQ() const { return prettyNameQ(name()); } string prettyTypeName() const; // "VARREF" for error messages (NOT dtype's pretty name) virtual string prettyOperatorName() const { return "operator " + prettyTypeName(); } diff --git a/src/V3AstNodeDType.h b/src/V3AstNodeDType.h index 26f1a740e..97eaacc5b 100644 --- a/src/V3AstNodeDType.h +++ b/src/V3AstNodeDType.h @@ -242,7 +242,7 @@ public: bool similarDType(const AstNodeDType* samep) const override { return this == samep; // We don't compare members, require exact equivalence } - string name() const override { return m_name; } + string name() const override VL_MT_STABLE { return m_name; } void name(const string& flag) override { m_name = flag; } bool packed() const VL_MT_SAFE { return m_packed; } void packed(bool flag) { m_packed = flag; } @@ -281,7 +281,7 @@ public: this->valuep(valuep); } ASTGEN_MEMBERS_AstEnumItem; - string name() const override { return m_name; } + string name() const override VL_MT_STABLE { return m_name; } bool maybePointedTo() const override { return true; } bool hasDType() const override { return true; } void name(const string& flag) override { m_name = flag; } @@ -409,7 +409,7 @@ public: bool similarDType(const AstNodeDType* samep) const override { return type() == samep->type() && same(samep); } - string name() const override { return m.m_keyword.ascii(); } + string name() const override VL_MT_STABLE { return m.m_keyword.ascii(); } string prettyDTypeName() const override; const char* broken() const override { BROKEN_RTN(dtypep() != this); @@ -531,7 +531,7 @@ public: } void dump(std::ostream& str = std::cout) const override; void dumpSmall(std::ostream& str) const override; - string name() const override; + string name() const override VL_MT_STABLE; AstBasicDType* basicp() const override VL_MT_STABLE { return nullptr; } AstNodeDType* skipRefp() const override VL_MT_STABLE { return (AstNodeDType*)this; } AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } @@ -543,7 +543,7 @@ public: AstNodeDType* subDTypep() const override VL_MT_SAFE { return nullptr; } AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } - AstClass* classp() const { return m_classp; } + AstClass* classp() const VL_MT_STABLE { return m_classp; } void classp(AstClass* nodep) { m_classp = nodep; } bool isCompound() const override { return true; } }; @@ -641,7 +641,7 @@ public: AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } int widthAlignBytes() const override { return dtypep()->widthAlignBytes(); } int widthTotalBytes() const override { return dtypep()->widthTotalBytes(); } - string name() const override { return m_name; } + string name() const override VL_MT_STABLE { return m_name; } void name(const string& flag) override { m_name = flag; } bool isCompound() const override { return false; } }; @@ -767,7 +767,7 @@ public: void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } AstNodeDType* virtRefDTypep() const override { return m_refDTypep; } void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } - string name() const override { return m_name; } + string name() const override VL_MT_STABLE { return m_name; } void name(const string& flag) override { m_name = flag; } void dump(std::ostream& str = std::cout) const override; void dumpSmall(std::ostream& str) const override; @@ -879,7 +879,7 @@ public: } ASTGEN_MEMBERS_AstMemberDType; void dumpSmall(std::ostream& str) const override; - string name() const override { return m_name; } // * = Var name + string name() const override VL_MT_STABLE { return m_name; } // * = Var name bool hasDType() const override { return true; } bool maybePointedTo() const override { return true; } const char* broken() const override { @@ -955,7 +955,7 @@ public: int widthAlignBytes() const override { return dtypep()->widthAlignBytes(); } int widthTotalBytes() const override { return dtypep()->widthTotalBytes(); } // METHODS - string name() const override { return m_name; } + string name() const override VL_MT_STABLE { return m_name; } bool maybePointedTo() const override { return true; } bool hasDType() const override { return true; } void name(const string& flag) override { m_name = flag; } @@ -1093,7 +1093,7 @@ public: } void dump(std::ostream& str = std::cout) const override; void dumpSmall(std::ostream& str) const override; - string name() const override { return m_name; } + string name() const override VL_MT_STABLE { return m_name; } string prettyDTypeName() const override { return subDTypep() ? prettyName(subDTypep()->name()) : prettyName(); } diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 5e12b2bd1..575bac814 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -236,7 +236,7 @@ public: const char* broken() const override; void cloneRelink() override; void dump(std::ostream& str = std::cout) const override; - string name() const override { return m_name; } // * = Var name + string name() const override VL_MT_STABLE { return m_name; } // * = Var name bool isGateOptimizable() const override; string dotted() const { return m_dotted; } // * = Scope name or "" string inlinedDots() const { return m_inlinedDots; } @@ -474,7 +474,7 @@ public: const char* broken() const override; int instrCount() const override { return widthInstrs(); } void cloneRelink() override; - string name() const override { return m_name; } // * = Var name + string name() const override VL_MT_STABLE { return m_name; } // * = Var name void name(const string& name) override { m_name = name; } VAccess access() const { return m_access; } void access(const VAccess& flag) { m_access = flag; } // Avoid using this; Set in constructor @@ -532,7 +532,7 @@ public: } ASTGEN_MEMBERS_AstArg; bool hasDType() const override { return false; } - string name() const override { return m_name; } // * = Pin name, ""=go by number + string name() const override VL_MT_STABLE { return m_name; } // * = Pin name, ""=go by number void name(const string& name) override { m_name = name; } bool emptyConnectNoNext() const { return !exprp() && name() == "" && !nextp(); } @@ -610,7 +610,7 @@ public: this->addPinsp(pinsp); } ASTGEN_MEMBERS_AstCMethodHard; - string name() const override { return m_name; } // * = Var name + string name() const override VL_MT_STABLE { return m_name; } // * = Var name void name(const string& name) override { m_name = name; } bool same(const AstNode* samep) const override { const AstCMethodHard* asamep = static_cast(samep); @@ -689,7 +689,7 @@ public: } ASTGEN_MEMBERS_AstCellArrayRef; // ACCESSORS - string name() const override { return m_name; } // * = Array name + string name() const override VL_MT_STABLE { return m_name; } // * = Array name string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); } @@ -710,7 +710,7 @@ public: } ASTGEN_MEMBERS_AstCellRef; // ACCESSORS - string name() const override { return m_name; } // * = Array name + string name() const override VL_MT_STABLE { return m_name; } // * = Array name string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); } @@ -746,7 +746,7 @@ public: == static_cast(samep)->m_classOrPackageNodep); } void dump(std::ostream& str = std::cout) const override; - string name() const override { return m_name; } // * = Var name + string name() const override VL_MT_STABLE { return m_name; } // * = Var name AstNode* classOrPackageNodep() const { return m_classOrPackageNodep; } void classOrPackageNodep(AstNode* nodep) { m_classOrPackageNodep = nodep; } AstNodeModule* classOrPackagep() const; @@ -990,7 +990,7 @@ public: initWithNumber(); } ASTGEN_MEMBERS_AstConst; - string name() const override { return num().ascii(); } // * = Value + string name() const override VL_MT_STABLE { return num().ascii(); } // * = Value const V3Number& num() const VL_MT_SAFE { return m_num; } // * = Value V3Number& num() { return m_num; } // * = Value uint32_t toUInt() const { return num().toUInt(); } @@ -1058,7 +1058,7 @@ public: } ASTGEN_MEMBERS_AstEnumItemRef; void dump(std::ostream& str) const override; - string name() const override { return itemp()->name(); } + string name() const override VL_MT_STABLE { return itemp()->name(); } int instrCount() const override { return 0; } const char* broken() const override; void cloneRelink() override { @@ -1068,7 +1068,7 @@ public: const AstEnumItemRef* const sp = static_cast(samep); return itemp() == sp->itemp(); } - AstEnumItem* itemp() const { return m_itemp; } + AstEnumItem* itemp() const VL_MT_STABLE { return m_itemp; } string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); } bool cleanOut() const override { return true; } @@ -1209,7 +1209,7 @@ public: this->filep(filep); } ASTGEN_MEMBERS_AstFScanF; - string name() const override { return m_text; } + string name() const override VL_MT_STABLE { return m_text; } string verilogKwd() const override { return "$fscanf"; } string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); } @@ -1406,7 +1406,7 @@ public: string emitC() override { V3ERROR_NA_RETURN(""); } bool cleanOut() const override { return true; } int instrCount() const override { return widthInstrs(); } - string name() const override { return m_name; } // * = Var name + string name() const override VL_MT_STABLE { return m_name; } // * = Var name void name(const string& name) override { m_name = name; } bool index() const { return m_index; } }; @@ -1432,7 +1432,7 @@ public: void cloneRelink() override; const char* broken() const override; void dump(std::ostream& str) const override; - string name() const override { return m_name; } + string name() const override VL_MT_STABLE { return m_name; } void name(const string& name) override { m_name = name; } string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); } @@ -1497,7 +1497,7 @@ public: } ASTGEN_MEMBERS_AstParseRef; void dump(std::ostream& str) const override; - string name() const override { return m_name; } // * = Var name + string name() const override VL_MT_STABLE { return m_name; } // * = Var name bool same(const AstNode* samep) const override { const AstParseRef* const asamep = static_cast(samep); return (expect() == asamep->expect() && m_name == asamep->m_name); @@ -1671,7 +1671,7 @@ public: addExprsp(exprsp); } ASTGEN_MEMBERS_AstSFormatF; - string name() const override { return m_text; } + string name() const override VL_MT_STABLE { return m_text; } int instrCount() const override { return INSTR_COUNT_PLI; } bool same(const AstNode* samep) const override { return text() == static_cast(samep)->text(); @@ -1706,7 +1706,7 @@ public: this->fromp(fromp); } ASTGEN_MEMBERS_AstSScanF; - string name() const override { return m_text; } + string name() const override VL_MT_STABLE { return m_text; } string verilogKwd() const override { return "$sscanf"; } string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); } @@ -1891,7 +1891,7 @@ public: dtypep(nullptr); // V3Width will resolve } ASTGEN_MEMBERS_AstStructSel; - string name() const override { return m_name; } + string name() const override VL_MT_STABLE { return m_name; } void name(const string& name) override { m_name = name; } string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); } @@ -2200,7 +2200,7 @@ public: void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { out.opCompareNN(lhs, rhs, m_ignoreCase); } - string name() const override { return m_ignoreCase ? "icompare" : "compare"; } + string name() const override VL_MT_STABLE { return m_ignoreCase ? "icompare" : "compare"; } string emitVerilog() override { return m_ignoreCase ? "%k(%l.icompare(%r))" : "%k(%l.compare(%r))"; } @@ -2424,7 +2424,7 @@ public: void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { out.opGetcN(lhs, rhs); } - string name() const override { return "getc"; } + string name() const override VL_MT_STABLE { return "getc"; } string emitVerilog() override { return "%k(%l.getc(%r))"; } string emitC() override { return "VL_GETC_N(%li,%ri)"; } string emitSimpleOperator() override { return ""; } @@ -4304,7 +4304,7 @@ public: const V3Number& ths) override { out.opPutcN(lhs, rhs, ths); } - string name() const override { return "putc"; } + string name() const override VL_MT_STABLE { return "putc"; } string emitVerilog() override { return "%k(%l.putc(%r,%t))"; } string emitC() override { return "VL_PUTC_N(%li,%ri,%ti)"; } string emitSimpleOperator() override { return ""; } @@ -4411,7 +4411,7 @@ public: const V3Number& ths) override { out.opSubstrN(lhs, rhs, ths); } - string name() const override { return "substr"; } + string name() const override VL_MT_STABLE { return "substr"; } string emitVerilog() override { return "%k(%l.substr(%r,%t))"; } string emitC() override { return "VL_SUBSTR_N(%li,%ri,%ti)"; } string emitSimpleOperator() override { return ""; } @@ -4488,7 +4488,7 @@ public: } ASTGEN_MEMBERS_AstAtoN; void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAtoN(lhs, m_fmt); } - string name() const override { + string name() const override VL_MT_STABLE { switch (m_fmt) { case ATOI: return "atoi"; case ATOHEX: return "atohex"; diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 72db0c8d0..ed0bf5098 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -48,7 +48,7 @@ protected: public: ASTGEN_MEMBERS_AstNodeBlock; void dump(std::ostream& str) const override; - string name() const override { return m_name; } // * = Block name + string name() const override VL_MT_STABLE { return m_name; } // * = Block name void name(const string& name) override { m_name = name; } bool unnamed() const { return m_unnamed; } bool isFirstInMyListOfStatements(AstNode* nodep) const override { return nodep == stmtsp(); } @@ -118,7 +118,7 @@ protected: public: ASTGEN_MEMBERS_AstNodeFTask; void dump(std::ostream& str = std::cout) const override; - string name() const override { return m_name; } // * = Var name + string name() const override VL_MT_STABLE { return m_name; } // * = Var name bool maybePointedTo() const override { return true; } bool isGateOptimizable() const override { return !((m_dpiExport || m_dpiImport) && !m_pure); } // {AstFunc only} op1 = Range output variable @@ -186,7 +186,7 @@ public: , m_name{name} {} ASTGEN_MEMBERS_AstNodeFile; void dump(std::ostream& str) const override; - string name() const override { return m_name; } + string name() const override VL_MT_STABLE { return m_name; } bool same(const AstNode* /*samep*/) const override { return true; } }; class AstNodeModule VL_NOT_FINAL : public AstNode { @@ -234,7 +234,7 @@ public: ASTGEN_MEMBERS_AstNodeModule; void dump(std::ostream& str) const override; bool maybePointedTo() const override { return true; } - string name() const override { return m_name; } + string name() const override VL_MT_STABLE { return m_name; } virtual bool timescaleMatters() const = 0; // ACCESSORS void name(const string& name) override { m_name = name; } @@ -373,7 +373,7 @@ public: this->addPasssp(passsp); } ASTGEN_MEMBERS_AstNodeCoverOrAssert; - string name() const override { return m_name; } // * = Var name + string name() const override VL_MT_STABLE { return m_name; } // * = Var name bool same(const AstNode* samep) const override { return samep->name() == name(); } void name(const string& name) override { m_name = name; } void dump(std::ostream& str = std::cout) const override; @@ -512,7 +512,7 @@ public: } ASTGEN_MEMBERS_AstActive; void dump(std::ostream& str = std::cout) const override; - string name() const override { return m_name; } + string name() const override VL_MT_STABLE { return m_name; } const char* broken() const override; void cloneRelink() override; // Statements are broken into pieces, as some must come before others. @@ -537,7 +537,7 @@ public: } ASTGEN_MEMBERS_AstBind; // ACCESSORS - string name() const override { return m_name; } // * = Bind Target name + string name() const override VL_MT_STABLE { return m_name; } // * = Bind Target name void name(const string& name) override { m_name = name; } }; class AstCFunc final : public AstNode { @@ -607,7 +607,7 @@ public: m_dpiTraceInit = false; } ASTGEN_MEMBERS_AstCFunc; - string name() const override { return m_name; } + string name() const override VL_MT_STABLE { return m_name; } const char* broken() const override; void cloneRelink() override; bool maybePointedTo() const override { return true; } @@ -702,7 +702,7 @@ public: , m_useType{useType} {} ASTGEN_MEMBERS_AstCUse; void dump(std::ostream& str = std::cout) const override; - string name() const override { return m_name; } + string name() const override VL_MT_STABLE { return m_name; } VUseType useType() const { return m_useType; } }; class AstCaseItem final : public AstNode { @@ -755,7 +755,7 @@ public: const char* broken() const override; bool maybePointedTo() const override { return true; } // ACCESSORS - string name() const override { return m_name; } // * = Cell name + string name() const override VL_MT_STABLE { return m_name; } // * = Cell name void name(const string& name) override { m_name = name; } string origName() const override { return m_origName; } // * = Original name void origName(const string& name) { m_origName = name; } @@ -794,7 +794,7 @@ public: void dump(std::ostream& str) const override; const char* broken() const override; // ACCESSORS - string name() const override { return m_name; } // * = Cell name + string name() const override VL_MT_STABLE { return m_name; } // * = Cell name string origModName() const { return m_origModName; } // * = modp()->origName() before inlining void name(const string& name) override { m_name = name; } void scopep(AstScope* scp) { m_scopep = scp; } @@ -845,7 +845,7 @@ public: } ASTGEN_MEMBERS_AstClocking; void dump(std::ostream& str) const override; - std::string name() const override { return m_name; } + std::string name() const override VL_MT_STABLE { return m_name; } bool isDefault() const { return m_isDefault; } bool isGlobal() const { return m_isGlobal; } }; @@ -916,7 +916,7 @@ public: , m_path{path} { this->rhsp(rhsp); } - string name() const override { return m_name; } // * = Scope name + string name() const override VL_MT_STABLE { return m_name; } // * = Scope name ASTGEN_MEMBERS_AstDefParam; bool same(const AstNode*) const override { return true; } string path() const { return m_path; } @@ -934,7 +934,7 @@ public: , m_name{vname} , m_cname{cname} {} ASTGEN_MEMBERS_AstDpiExport; - string name() const override { return m_name; } + string name() const override VL_MT_STABLE { return m_name; } void name(const string& name) override { m_name = name; } string cname() const { return m_cname; } void cname(const string& cname) { m_cname = cname; } @@ -995,7 +995,7 @@ public: BROKEN_RTN(!m_depGraphp); return nullptr; } - string name() const override { return m_name; } + string name() const override VL_MT_STABLE { return m_name; } V3Graph* depGraphp() { return m_depGraphp; } const V3Graph* depGraphp() const { return m_depGraphp; } }; @@ -1033,7 +1033,7 @@ public: AstIntfRef(FileLine* fl, const string& name) : ASTGEN_SUPER_IntfRef(fl) , m_name{name} {} - string name() const override { return m_name; } + string name() const override VL_MT_STABLE { return m_name; } ASTGEN_MEMBERS_AstIntfRef; }; class AstMTaskBody final : public AstNode { @@ -1070,7 +1070,7 @@ public: , m_name{name} { this->addVarsp(varsp); } - string name() const override { return m_name; } + string name() const override VL_MT_STABLE { return m_name; } bool maybePointedTo() const override { return true; } ASTGEN_MEMBERS_AstModport; }; @@ -1092,7 +1092,7 @@ public: const char* broken() const override; void cloneRelink() override; void dump(std::ostream& str) const override; - string name() const override { return m_name; } + string name() const override VL_MT_STABLE { return m_name; } bool isImport() const { return !m_export; } bool isExport() const { return m_export; } AstNodeFTask* ftaskp() const { return m_ftaskp; } // [After Link] Pointer to variable @@ -1115,7 +1115,7 @@ public: const char* broken() const override; void cloneRelink() override; void dump(std::ostream& str) const override; - string name() const override { return m_name; } + string name() const override VL_MT_STABLE { return m_name; } void direction(const VDirection& flag) { m_direction = flag; } VDirection direction() const { return m_direction; } AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable @@ -1149,7 +1149,7 @@ public: ASTGEN_MEMBERS_AstNetlist; const char* broken() const override; void cloneRelink() override { V3ERROR_NA; } - string name() const override { return "$root"; } + string name() const override VL_MT_STABLE { return "$root"; } void dump(std::ostream& str) const override; AstNodeModule* topModulep() const { // Top module in hierarchy return modulesp(); // First one in the list, for now @@ -1198,7 +1198,7 @@ public: const char* broken() const override; void cloneRelink() override; void dump(std::ostream& str) const override; - string name() const override { return m_name; } + string name() const override VL_MT_STABLE { return m_name; } AstPackage* packagep() const { return m_packagep; } void packagep(AstPackage* nodep) { m_packagep = nodep; } }; @@ -1224,7 +1224,7 @@ public: const char* broken() const override; void cloneRelink() override; void dump(std::ostream& str) const override; - string name() const override { return m_name; } + string name() const override VL_MT_STABLE { return m_name; } AstPackage* packagep() const { return m_packagep; } void packagep(AstPackage* nodep) { m_packagep = nodep; } }; @@ -1250,7 +1250,7 @@ public: ASTGEN_MEMBERS_AstPin; void dump(std::ostream& str) const override; const char* broken() const override; - string name() const override { return m_name; } // * = Pin name, ""=go by number + string name() const override VL_MT_STABLE { return m_name; } // * = Pin name, ""=go by number void name(const string& name) override { m_name = name; } string prettyOperatorName() const override; bool dotStar() const { return name() == ".*"; } // Fake name for .* connections until linked @@ -1278,7 +1278,7 @@ public: , m_pinNum{pinnum} , m_name{name} {} ASTGEN_MEMBERS_AstPort; - string name() const override { return m_name; } // * = Port name + string name() const override VL_MT_STABLE { return m_name; } // * = Port name int pinNum() const { return m_pinNum; } // * = Pin number, for order based instantiation }; class AstPragma final : public AstNode { @@ -1356,7 +1356,7 @@ public: void cloneRelink() override; const char* broken() const override; bool maybePointedTo() const override { return true; } - string name() const override { return m_name; } // * = Scope name + string name() const override VL_MT_STABLE { return m_name; } // * = Scope name void name(const string& name) override { m_name = name; } void dump(std::ostream& str) const override; string nameDotless() const; @@ -1548,7 +1548,7 @@ public: return dtypep() ? dtypep() : childDTypep(); } // METHODS - string name() const override { return m_name; } + string name() const override VL_MT_STABLE { return m_name; } bool maybePointedTo() const override { return true; } bool hasDType() const override { return true; } void name(const string& flag) override { m_name = flag; } @@ -1568,7 +1568,7 @@ public: , m_name{name} {} ASTGEN_MEMBERS_AstTypedefFwd; // METHODS - string name() const override { return m_name; } + string name() const override VL_MT_STABLE { return m_name; } bool maybePointedTo() const override { return true; } }; class AstUdpTable final : public AstNode { @@ -1588,7 +1588,7 @@ public: : ASTGEN_SUPER_UdpTableLine(fl) , m_text{text} {} ASTGEN_MEMBERS_AstUdpTableLine; - string name() const override { return m_text; } + string name() const override VL_MT_STABLE { return m_text; } string text() const { return m_text; } }; class AstVar final : public AstNode { @@ -1758,7 +1758,7 @@ public: } ASTGEN_MEMBERS_AstVar; void dump(std::ostream& str) const override; - string name() const override VL_MT_SAFE { return m_name; } // * = Var name + string name() const override VL_MT_STABLE VL_MT_SAFE { return m_name; } // * = Var name bool hasDType() const override { return true; } bool maybePointedTo() const override { return true; } string origName() const override { return m_origName; } // * = Original name @@ -1998,7 +1998,7 @@ public: return nullptr; } bool maybePointedTo() const override { return true; } - string name() const override { return scopep()->name() + "->" + varp()->name(); } + string name() const override VL_MT_STABLE { return scopep()->name() + "->" + varp()->name(); } void dump(std::ostream& str) const override; bool hasDType() const override { return true; } AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable @@ -2452,7 +2452,7 @@ public: , m_name{name} , m_showAt{showAt} {} ASTGEN_MEMBERS_AstComment; - string name() const override { return m_name; } // * = Text + string name() const override VL_MT_STABLE { return m_name; } // * = Text bool same(const AstNode* samep) const override { return true; } // Ignore name in comments virtual bool showAt() const { return m_showAt; } }; @@ -2593,7 +2593,7 @@ public: : ASTGEN_SUPER_Disable(fl) , m_name{name} {} ASTGEN_MEMBERS_AstDisable; - string name() const override { return m_name; } // * = Block name + string name() const override VL_MT_STABLE { return m_name; } // * = Block name void name(const string& flag) override { m_name = flag; } bool isBrancher() const override { return true; // SPECIAL: We don't process code after breaks @@ -2884,7 +2884,7 @@ public: : ASTGEN_SUPER_PrintTimeScale(fl) {} ASTGEN_MEMBERS_AstPrintTimeScale; void name(const string& name) override { m_name = name; } - string name() const override { return m_name; } // * = Var name + string name() const override VL_MT_STABLE { return m_name; } // * = Var name void dump(std::ostream& str) const override; string verilogKwd() const override { return "$printtimescale"; } bool isGateOptimizable() const override { return false; } @@ -3103,7 +3103,7 @@ public: void dump(std::ostream& str) const override; int instrCount() const override { return 100; } // Large... ASTGEN_MEMBERS_AstTraceDecl; - string name() const override { return m_showname; } + string name() const override VL_MT_STABLE { return m_showname; } bool maybePointedTo() const override { return true; } bool hasDType() const override { return true; } bool same(const AstNode* samep) const override { return false; } diff --git a/src/V3Config.cpp b/src/V3Config.cpp index b6ede32c0..c6fb382c3 100644 --- a/src/V3Config.cpp +++ b/src/V3Config.cpp @@ -40,25 +40,31 @@ template class V3ConfigWildcardResolver final { using Map = std::map; - Map m_mapWildcard; // Wildcard strings to entities - Map m_mapResolved; // Resolved strings to converged entities + mutable VerilatedMutex m_mutex; // protects members + Map m_mapWildcard VL_GUARDED_BY(m_mutex); // Wildcard strings to entities + Map m_mapResolved VL_GUARDED_BY(m_mutex); // Resolved strings to converged entities public: V3ConfigWildcardResolver() = default; ~V3ConfigWildcardResolver() = default; /// Update into maps from other - void update(const V3ConfigWildcardResolver& other) { + void update(const V3ConfigWildcardResolver& other) VL_MT_SAFE_EXCLUDES(m_mutex) + VL_EXCLUDES(other.m_mutex) { + VerilatedLockGuard lock{m_mutex}; + VerilatedLockGuard otherLock{other.m_mutex}; for (const auto& itr : other.m_mapResolved) m_mapResolved[itr.first].update(itr.second); for (const auto& itr : other.m_mapWildcard) m_mapWildcard[itr.first].update(itr.second); } // Access and create a (wildcard) entity - T& at(const string& name) { + T& at(const string& name) VL_MT_SAFE_EXCLUDES(m_mutex) { + VerilatedLockGuard lock{m_mutex}; // Don't store into wildcards if the name is not a wildcard string return m_mapWildcard[name]; } // Access an entity and resolve wildcards that match it - T* resolve(const string& name) { + T* resolve(const string& name) VL_MT_SAFE_EXCLUDES(m_mutex) { + VerilatedLockGuard lock{m_mutex}; // Lookup if it was resolved before, typically not auto it = m_mapResolved.find(name); if (VL_UNLIKELY(it != m_mapResolved.end())) return &it->second; @@ -78,7 +84,10 @@ public: return newp; } // Flush on update - void flush() { m_mapResolved.clear(); } + void flush() VL_MT_SAFE_EXCLUDES(m_mutex) { + VerilatedLockGuard lock{m_mutex}; + m_mapResolved.clear(); + } }; // Only public_flat_rw has the sensitity tree diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index ebb7ed3f4..a183b4e78 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -63,7 +63,9 @@ public: void putsQuoted(const string& str) { ofp()->putsQuoted(str); } void ensureNewLine() { ofp()->ensureNewLine(); } bool optSystemC() { return v3Global.opt.systemC(); } - static string protect(const string& name) { return VIdProtect::protectIf(name, true); } + static string protect(const string& name) VL_MT_SAFE { + return VIdProtect::protectIf(name, true); + } static string protectIf(const string& name, bool doIt) { return VIdProtect::protectIf(name, doIt); } @@ -84,7 +86,7 @@ public: return symClassName() + "* const __restrict vlSymsp VL_ATTR_UNUSED = vlSelf->vlSymsp;\n"; } static string funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp = nullptr); - static string prefixNameProtect(const AstNode* nodep) { // C++ name with prefix + static string prefixNameProtect(const AstNode* nodep) VL_MT_SAFE { // C++ name with prefix return v3Global.opt.modPrefix() + "_" + protect(nodep->name()); } static string topClassName() VL_MT_SAFE { // Return name of top wrapper module diff --git a/src/V3File.cpp b/src/V3File.cpp index 6ae1507e0..5fd603d6e 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -108,7 +108,8 @@ class V3FileDependImp final { }; // MEMBERS - std::set m_filenameSet; // Files generated (elim duplicates) + VerilatedMutex m_mutex; // Protects members + std::set m_filenameSet VL_GUARDED_BY(m_mutex); // Files generated (elim duplicates) std::set m_filenameList; // Files sourced/generated static string stripQuotes(const string& in) { @@ -121,7 +122,8 @@ class V3FileDependImp final { public: // ACCESSOR METHODS - void addSrcDepend(const string& filename) { + void addSrcDepend(const string& filename) VL_MT_SAFE_EXCLUDES(m_mutex) { + const VerilatedLockGuard lock{m_mutex}; const auto itFoundPair = m_filenameSet.insert(filename); if (itFoundPair.second) { DependFile df{filename, false}; @@ -129,7 +131,8 @@ public: m_filenameList.insert(df); } } - void addTgtDepend(const string& filename) { + void addTgtDepend(const string& filename) VL_MT_SAFE_EXCLUDES(m_mutex) { + const VerilatedLockGuard lock{m_mutex}; const auto itFoundPair = m_filenameSet.insert(filename); if (itFoundPair.second) m_filenameList.insert(DependFile{filename, true}); } @@ -297,8 +300,8 @@ bool V3FileDependImp::checkTimes(const string& filename, const string& cmdlineIn //###################################################################### // V3File -void V3File::addSrcDepend(const string& filename) { dependImp.addSrcDepend(filename); } -void V3File::addTgtDepend(const string& filename) { dependImp.addTgtDepend(filename); } +void V3File::addSrcDepend(const string& filename) VL_MT_SAFE { dependImp.addSrcDepend(filename); } +void V3File::addTgtDepend(const string& filename) VL_MT_SAFE { dependImp.addTgtDepend(filename); } void V3File::writeDepend(const string& filename) { dependImp.writeDepend(filename); } std::vector V3File::getAllDeps() { return dependImp.getAllDeps(); } void V3File::writeTimes(const string& filename, const string& cmdlineIn) { @@ -954,12 +957,13 @@ void V3OutCFile::putsGuard() { class VIdProtectImp final { // MEMBERS + VerilatedMutex m_mutex; // Protects members std::map m_nameMap; // Map of old name into new name - std::unordered_set m_newIdSet; // Which new names exist + std::unordered_set m_newIdSet VL_GUARDED_BY(m_mutex); // Which new names exist protected: // CONSTRUCTORS friend class VIdProtect; - static VIdProtectImp& singleton() { + static VIdProtectImp& singleton() VL_MT_SAFE { static VIdProtectImp s; return s; } @@ -973,8 +977,9 @@ public: } ~VIdProtectImp() = default; // METHODS - string passthru(const string& old) { + string passthru(const string& old) VL_MT_SAFE_EXCLUDES(m_mutex) { if (!v3Global.opt.protectIds()) return old; + const VerilatedLockGuard lock{m_mutex}; const auto it = m_nameMap.find(old); if (it != m_nameMap.end()) { // No way to go back and correct the older crypt name @@ -986,8 +991,9 @@ public: } return old; } - string protectIf(const string& old, bool doIt) { + string protectIf(const string& old, bool doIt) VL_MT_SAFE_EXCLUDES(m_mutex) { if (!v3Global.opt.protectIds() || old.empty() || !doIt) return old; + const VerilatedLockGuard lock{m_mutex}; const auto it = m_nameMap.find(old); if (it != m_nameMap.end()) { return it->second; @@ -1017,7 +1023,7 @@ public: return out; } } - string protectWordsIf(const string& old, bool doIt) { + string protectWordsIf(const string& old, bool doIt) VL_MT_SAFE { // Split at " " (for traces), "." (for scopes), "->", "(", "&", ")" (for self pointers) if (!(doIt && v3Global.opt.protectIds())) return old; string out; @@ -1056,7 +1062,7 @@ public: private: void trySep(const string& old, string::size_type start, const string& trySep, - string::size_type& posr, string& separatorr) { + string::size_type& posr, string& separatorr) VL_PURE { const string::size_type trypos = old.find(trySep, start); if (trypos != string::npos) { if (posr == string::npos || (posr > trypos)) { @@ -1067,10 +1073,10 @@ private: } }; -string VIdProtect::protectIf(const string& old, bool doIt) { +string VIdProtect::protectIf(const string& old, bool doIt) VL_MT_SAFE { return VIdProtectImp::singleton().protectIf(old, doIt); } -string VIdProtect::protectWordsIf(const string& old, bool doIt) { +string VIdProtect::protectWordsIf(const string& old, bool doIt) VL_MT_SAFE { return VIdProtectImp::singleton().protectWordsIf(old, doIt); } void VIdProtect::writeMapFile(const string& filename) { diff --git a/src/V3File.h b/src/V3File.h index 2c1d34850..3f1cbebc2 100644 --- a/src/V3File.h +++ b/src/V3File.h @@ -61,8 +61,8 @@ public: } // Dependencies - static void addSrcDepend(const string& filename); - static void addTgtDepend(const string& filename); + static void addSrcDepend(const string& filename) VL_MT_SAFE; + static void addTgtDepend(const string& filename) VL_MT_SAFE; static void writeDepend(const string& filename); static std::vector getAllDeps(); static void writeTimes(const string& filename, const string& cmdlineIn); @@ -318,10 +318,10 @@ class VIdProtect final { public: // METHODS // Rename to a new encoded string (unless earlier passthru'ed) - static string protect(const string& old) { return protectIf(old, true); } - static string protectIf(const string& old, bool doIt = true); + static string protect(const string& old) VL_MT_SAFE { return protectIf(old, true); } + static string protectIf(const string& old, bool doIt = true) VL_MT_SAFE; // Rename words to a new encoded string - static string protectWordsIf(const string& old, bool doIt = true); + static string protectWordsIf(const string& old, bool doIt = true) VL_MT_SAFE; // Write map of renames to output file static void writeMapFile(const string& filename); }; diff --git a/src/V3FileLine.cpp b/src/V3FileLine.cpp index 8f7362b38..839bd4573 100644 --- a/src/V3FileLine.cpp +++ b/src/V3FileLine.cpp @@ -87,7 +87,9 @@ void FileLineSingleton::fileNameNumMapDumpXml(std::ostream& os) { os << "\n"; } -FileLineSingleton::msgEnSetIdx_t FileLineSingleton::addMsgEnBitSet(const MsgEnBitSet& bitSet) { +FileLineSingleton::msgEnSetIdx_t FileLineSingleton::addMsgEnBitSet(const MsgEnBitSet& bitSet) + VL_MT_SAFE_EXCLUDES(m_mutex) { + VerilatedLockGuard lock{m_mutex}; const auto pair = m_internedMsgEnIdxs.emplace(bitSet, 0); msgEnSetIdx_t& idx = pair.first->second; if (pair.second) { @@ -100,7 +102,7 @@ FileLineSingleton::msgEnSetIdx_t FileLineSingleton::addMsgEnBitSet(const MsgEnBi return idx; } -FileLineSingleton::msgEnSetIdx_t FileLineSingleton::defaultMsgEnIndex() { +FileLineSingleton::msgEnSetIdx_t FileLineSingleton::defaultMsgEnIndex() VL_MT_SAFE { MsgEnBitSet msgEnBitSet; for (int i = V3ErrorCode::EC_MIN; i < V3ErrorCode::_ENUM_MAX; ++i) { msgEnBitSet.set(i, !V3ErrorCode{i}.defaultsOff()); diff --git a/src/V3FileLine.h b/src/V3FileLine.h index 96a52526c..6f66277c1 100644 --- a/src/V3FileLine.h +++ b/src/V3FileLine.h @@ -20,6 +20,8 @@ #include "config_build.h" #include "verilatedos.h" +#include "verilated_threads.h" + #include "V3Error.h" #include "V3LangCode.h" @@ -50,12 +52,13 @@ class FileLineSingleton final { using MsgEnBitSet = std::bitset; // MEMBERS + VerilatedMutex m_mutex; // protects members std::map m_namemap; // filenameno for each filename std::deque m_names; // filename text for each filenameno std::deque m_languages; // language for each filenameno // Map from flag set to the index in m_internedMsgEns for interning - std::unordered_map m_internedMsgEnIdxs; + std::unordered_map m_internedMsgEnIdxs VL_GUARDED_BY(m_mutex); // Interned message enablement flag sets std::vector m_internedMsgEns; @@ -78,9 +81,9 @@ class FileLineSingleton final { static string filenameLetters(fileNameIdx_t fileno) VL_PURE; // Add given bitset to the interned bitsets, return interned index - msgEnSetIdx_t addMsgEnBitSet(const MsgEnBitSet& bitSet); + msgEnSetIdx_t addMsgEnBitSet(const MsgEnBitSet& bitSet) VL_MT_SAFE_EXCLUDES(m_mutex); // Add index of default bitset - msgEnSetIdx_t defaultMsgEnIndex(); + msgEnSetIdx_t defaultMsgEnIndex() VL_MT_SAFE; // Set bitIdx to value in bitset at interned index setIdx, return interned index of result msgEnSetIdx_t msgEnSetBit(msgEnSetIdx_t setIdx, size_t bitIdx, bool value); // Return index to intersection set diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 3b450856f..4c4ef2e7d 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -134,7 +134,9 @@ public: ~GateVarVertex() override = default; // ACCESSORS AstVarScope* varScp() const { return m_varScp; } - string name() const override { return (cvtToHex(m_varScp) + " " + varScp()->name()); } + string name() const override VL_MT_STABLE { + return (cvtToHex(m_varScp) + " " + varScp()->name()); + } string dotColor() const override { return "blue"; } bool isTop() const { return m_isTop; } void setIsTop() { m_isTop = true; } @@ -174,7 +176,9 @@ public: , m_slow{slow} {} ~GateLogicVertex() override = default; // ACCESSORS - string name() const override { return (cvtToHex(m_nodep) + "@" + scopep()->prettyName()); } + string name() const override VL_MT_STABLE { + return (cvtToHex(m_nodep) + "@" + scopep()->prettyName()); + } string dotColor() const override { return "purple"; } FileLine* fileline() const override { return nodep()->fileline(); } AstNode* nodep() const { return m_nodep; } diff --git a/src/V3Global.h b/src/V3Global.h index 0537f534c..db6dc04ba 100644 --- a/src/V3Global.h +++ b/src/V3Global.h @@ -98,7 +98,7 @@ class V3Global final { VWidthMinUsage m_widthMinUsage = VWidthMinUsage::LINT_WIDTH; // What AstNode::widthMin() is used for - int m_debugFileNumber = 0; // Number to append to debug files created + std::atomic_int m_debugFileNumber{0}; // Number to append to debug files created bool m_assertDTypesResolved = false; // Tree should have dtypep()'s bool m_assertScoped = false; // Tree is scoped bool m_constRemoveXs = false; // Const needs to strip any Xs @@ -143,7 +143,7 @@ public: void widthMinUsage(const VWidthMinUsage& flag) { m_widthMinUsage = flag; } bool constRemoveXs() const { return m_constRemoveXs; } void constRemoveXs(bool flag) { m_constRemoveXs = flag; } - string debugFilename(const string& nameComment, int newNumber = 0) VL_MT_SAFE; + string debugFilename(const string& nameComment, int newNumber = 0); static string digitsFilename(int number); bool needTraceDumper() const { return m_needTraceDumper; } void needTraceDumper(bool flag) { m_needTraceDumper = flag; } diff --git a/src/V3GraphTest.cpp b/src/V3GraphTest.cpp index cb48888a6..8a9637cdf 100644 --- a/src/V3GraphTest.cpp +++ b/src/V3GraphTest.cpp @@ -60,7 +60,7 @@ public: , m_name{name} {} ~V3GraphTestVertex() override = default; // ACCESSORS - string name() const override { return m_name; } + string name() const override VL_MT_STABLE { return m_name; } }; class V3GraphTestVarVertex final : public V3GraphTestVertex { diff --git a/src/V3LinkCells.cpp b/src/V3LinkCells.cpp index 20f5e545c..f30bb9601 100644 --- a/src/V3LinkCells.cpp +++ b/src/V3LinkCells.cpp @@ -59,8 +59,8 @@ public: : V3GraphVertex{graphp} , m_modp{modp} {} ~LinkCellsVertex() override = default; - AstNodeModule* modp() const { return m_modp; } - string name() const override { return modp()->name(); } + AstNodeModule* modp() const VL_MT_STABLE { return m_modp; } + string name() const override VL_MT_STABLE { return modp()->name(); } FileLine* fileline() const override { return modp()->fileline(); } // Recursive modules get space for maximum recursion uint32_t rankAdder() const override { @@ -73,7 +73,7 @@ public: explicit LibraryVertex(V3Graph* graphp) : V3GraphVertex{graphp} {} ~LibraryVertex() override = default; - string name() const override { return "*LIBRARY*"; } + string name() const override VL_MT_STABLE { return "*LIBRARY*"; } }; void LinkCellsGraph::loopsMessageCb(V3GraphVertex* vertexp) { diff --git a/src/V3Number.cpp b/src/V3Number.cpp index a74d7a64d..7defef9a5 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -498,7 +498,7 @@ V3Number& V3Number::setMask(int nbits) { //====================================================================== // ACCESSORS - as strings -string V3Number::ascii(bool prefixed, bool cleanVerilog) const { +string V3Number::ascii(bool prefixed, bool cleanVerilog) const VL_MT_SAFE { std::ostringstream out; if (is1Step()) { @@ -1050,7 +1050,7 @@ bool V3Number::isEqAllOnes(int optwidth) const { } return true; } -bool V3Number::isFourState() const { +bool V3Number::isFourState() const VL_MT_SAFE { if (isDouble() || isString()) return false; for (int i = 0; i < words(); ++i) { if (m_data.num()[i].m_valueX) return true; diff --git a/src/V3Number.h b/src/V3Number.h index 2afc9354f..b94a212fb 100644 --- a/src/V3Number.h +++ b/src/V3Number.h @@ -583,7 +583,7 @@ public: V3Number& setMask(int nbits); // IE if nbits=1, then 0b1, if 2->0b11, if 3->0b111 etc // ACCESSORS - string ascii(bool prefixed = true, bool cleanVerilog = false) const; + string ascii(bool prefixed = true, bool cleanVerilog = false) const VL_MT_SAFE; string displayed(AstNode* nodep, const string& vformat) const VL_MT_SAFE; static bool displayedFmtLegal(char format, bool isScan); // Is this a valid format letter? int width() const VL_MT_SAFE { return m_data.width(); } @@ -615,7 +615,7 @@ public: bool isNegative() const { return !isString() && bitIs1(width() - 1); } bool is1Step() const VL_MT_SAFE { return m_data.m_is1Step; } bool isNull() const VL_MT_SAFE { return m_data.m_isNull; } - bool isFourState() const; + bool isFourState() const VL_MT_SAFE; bool hasZ() const { if (isString()) return false; for (int i = 0; i < words(); i++) { diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 96996d58c..ea3fcf25f 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -880,7 +880,9 @@ string V3Options::version() VL_PURE { return ver; } -string V3Options::protectKeyDefaulted() { +string V3Options::protectKeyDefaulted() VL_MT_SAFE { + static VerilatedMutex mutex; + const VerilatedLockGuard lock{mutex}; if (m_protectKey.empty()) { // Create a key with a human-readable symbol-like name. // This conversion drops ~2 bits of entropy out of 256, shouldn't matter. diff --git a/src/V3Options.h b/src/V3Options.h index 26a41f712..7e6b639b3 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -573,7 +573,7 @@ public: string prefix() const VL_MT_SAFE { return m_prefix; } // Not just called protectKey() to avoid bugs of not using protectKeyDefaulted() bool protectKeyProvided() const { return !m_protectKey.empty(); } - string protectKeyDefaulted(); // Set default key if not set by user + string protectKeyDefaulted() VL_MT_SAFE; // Set default key if not set by user string topModule() const { return m_topModule; } string unusedRegexp() const { return m_unusedRegexp; } string waiverOutput() const { return m_waiverOutput; } diff --git a/src/V3OrderGraph.h b/src/V3OrderGraph.h index 5cc0ea85b..c1e3f2a91 100644 --- a/src/V3OrderGraph.h +++ b/src/V3OrderGraph.h @@ -159,7 +159,7 @@ public: AstSenTree* hybridp() const { return m_hybridp; } // LCOV_EXCL_START // Debug code - string name() const override { + string name() const override VL_MT_STABLE { return (cvtToHex(m_nodep) + "\\n " + cvtToStr(nodep()->typeName())); } string dotShape() const override { return VN_IS(m_nodep, Active) ? "doubleoctagon" : "rect"; } @@ -182,7 +182,7 @@ public: // LCOV_EXCL_START // Debug code string dotShape() const override final { return "ellipse"; } virtual string nameSuffix() const = 0; - string name() const override final { + string name() const override final VL_MT_STABLE { return cvtToHex(m_vscp) + " " + nameSuffix() + "\\n " + m_vscp->name(); } // LCOV_EXCL_STOP diff --git a/src/V3OrderMoveGraph.h b/src/V3OrderMoveGraph.h index c0187a68f..622ffd5d9 100644 --- a/src/V3OrderMoveGraph.h +++ b/src/V3OrderMoveGraph.h @@ -64,7 +64,7 @@ public: } } - string name() const override { + string name() const override VL_MT_STABLE { string nm; if (VL_UNCOVERABLE(!logicp())) { // Avoid crash when debugging nm = "nul"; // LCOV_EXCL_LINE diff --git a/src/V3Os.cpp b/src/V3Os.cpp index 7a4722839..377e3594f 100644 --- a/src/V3Os.cpp +++ b/src/V3Os.cpp @@ -28,6 +28,8 @@ #include "config_build.h" #include "verilatedos.h" +#include "verilated_threads.h" + // Limited V3 headers here - this is a base class for Vlc etc #include "V3Os.h" #include "V3String.h" @@ -286,7 +288,7 @@ uint64_t V3Os::rand64(std::array& stater) { return result; } -string V3Os::trueRandom(size_t size) { +string V3Os::trueRandom(size_t size) VL_MT_SAFE { string result(size, '\xFF'); char* const data = const_cast(result.data()); // Note: std::string.data() returns a non-const Char* from C++17 onwards. diff --git a/src/V3Os.h b/src/V3Os.h index 4300417fd..4f4d44bb9 100644 --- a/src/V3Os.h +++ b/src/V3Os.h @@ -59,7 +59,7 @@ public: // METHODS (random) static uint64_t rand64(std::array& stater); - static string trueRandom(size_t size); + static string trueRandom(size_t size) VL_MT_SAFE; // METHODS (time & performance) static void u_sleep(int64_t usec); ///< Sleep for a given number of microseconds. diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp index 82b41ca32..45976fe76 100644 --- a/src/V3Partition.cpp +++ b/src/V3Partition.cpp @@ -321,7 +321,7 @@ public: void checkRelativesCp(GraphWay way) const; - string name() const override { + string name() const override VL_MT_STABLE { // Display forward and reverse critical path costs. This gives a quick // read on whether graph partitioning looks reasonable or bad. std::ostringstream out; diff --git a/src/V3PartitionGraph.h b/src/V3PartitionGraph.h index fc16c81c6..b83679a06 100644 --- a/src/V3PartitionGraph.h +++ b/src/V3PartitionGraph.h @@ -85,7 +85,7 @@ public: // If this MTask maps to a C function, this should be the name return std::string{"__Vmtask"} + "__" + cvtToStr(m_id); } - string name() const override { return std::string{"mt"} + cvtToStr(id()); } + string name() const override VL_MT_STABLE { return std::string{"mt"} + cvtToStr(id()); } string hashName() const { return m_hashName; } void hashName(const string& name) { m_hashName = name; } void dump(std::ostream& str) const { diff --git a/src/V3SchedAcyclic.cpp b/src/V3SchedAcyclic.cpp index bed28d66d..ac9bec353 100644 --- a/src/V3SchedAcyclic.cpp +++ b/src/V3SchedAcyclic.cpp @@ -76,7 +76,7 @@ public: AstScope* scopep() const { return m_scopep; } // LCOV_EXCL_START // Debug code - string name() const override { return m_logicp->fileline()->ascii(); }; + string name() const override VL_MT_STABLE { return m_logicp->fileline()->ascii(); }; string dotShape() const override { return "rectangle2"; } // LCOV_EXCL_STOP }; @@ -93,7 +93,7 @@ public: V3GraphVertex* clone(V3Graph* graphp) const override { return new VarVertex{graphp, vscp()}; } // LCOV_EXCL_START // Debug code - string name() const override { return m_vscp->name(); } + string name() const override VL_MT_STABLE { return m_vscp->name(); } string dotShape() const override { return "ellipse"; } string dotColor() const override { return "blue"; } // LCOV_EXCL_STOP diff --git a/src/V3SchedPartition.cpp b/src/V3SchedPartition.cpp index 0234dab01..849ff16e7 100644 --- a/src/V3SchedPartition.cpp +++ b/src/V3SchedPartition.cpp @@ -89,7 +89,7 @@ public: AstNode* logicp() const { return m_logicp; } // LCOV_EXCL_START // Debug code - string name() const override { + string name() const override VL_MT_STABLE { return m_logicp->typeName() + ("\n" + m_logicp->fileline()->ascii()); }; string dotShape() const override { return "rectangle"; } @@ -105,7 +105,7 @@ public: , m_vscp{vscp} {} // LCOV_EXCL_START // Debug code - string name() const override { return m_vscp->name(); } + string name() const override VL_MT_STABLE { return m_vscp->name(); } string dotShape() const override { return m_vscp->scopep()->isTop() && m_vscp->varp()->isNonOutput() ? "invhouse" : "ellipse"; } diff --git a/src/V3SchedReplicate.cpp b/src/V3SchedReplicate.cpp index 0564bb60d..7db10cabf 100644 --- a/src/V3SchedReplicate.cpp +++ b/src/V3SchedReplicate.cpp @@ -109,7 +109,7 @@ public: RegionFlags assignedRegion() const { return m_assignedRegion; } // For graph dumping - string name() const override { return m_logicp->fileline()->ascii(); }; + string name() const override VL_MT_STABLE { return m_logicp->fileline()->ascii(); }; string dotShape() const override { return "rectangle"; } }; @@ -134,7 +134,7 @@ public: AstScope* scopep() const { return m_vscp->scopep(); } // For graph dumping - string name() const override { return m_vscp->name(); } + string name() const override VL_MT_STABLE { return m_vscp->name(); } string dotShape() const override { return varp()->isPrimaryInish() ? "invhouse" : "ellipse"; } }; diff --git a/src/V3Split.cpp b/src/V3Split.cpp index db8a8da73..0c135d3e9 100644 --- a/src/V3Split.cpp +++ b/src/V3Split.cpp @@ -109,7 +109,9 @@ protected: // ACCESSORS // Do not make accessor for nodep(), It may change due to // reordering a lower block, but we don't repair it - string name() const override { return cvtToHex(m_nodep) + ' ' + m_nodep->prettyTypeName(); } + string name() const override VL_MT_STABLE { + return cvtToHex(m_nodep) + ' ' + m_nodep->prettyTypeName(); + } FileLine* fileline() const override { return nodep()->fileline(); } public: @@ -121,7 +123,7 @@ public: explicit SplitPliVertex(V3Graph* graphp, AstNode* nodep) : SplitNodeVertex{graphp, nodep} {} ~SplitPliVertex() override = default; - string name() const override { return "*PLI*"; } + string name() const override VL_MT_STABLE { return "*PLI*"; } string dotColor() const override { return "green"; } }; @@ -146,7 +148,7 @@ public: SplitVarPostVertex(V3Graph* graphp, AstNode* nodep) : SplitNodeVertex{graphp, nodep} {} ~SplitVarPostVertex() override = default; - string name() const override { return string("POST ") + SplitNodeVertex::name(); } + string name() const override VL_MT_STABLE { return string("POST ") + SplitNodeVertex::name(); } string dotColor() const override { return "CadetBlue"; } }; diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 500d8e6dc..64567e122 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -67,8 +67,8 @@ public: : TaskBaseVertex{graphp} , m_nodep{nodep} {} ~TaskFTaskVertex() override = default; - AstNodeFTask* nodep() const { return m_nodep; } - string name() const override { return nodep()->name(); } + AstNodeFTask* nodep() const VL_MT_STABLE { return m_nodep; } + string name() const override VL_MT_STABLE { return nodep()->name(); } string dotColor() const override { return pure() ? "black" : "red"; } AstCFunc* cFuncp() const { return m_cFuncp; } void cFuncp(AstCFunc* nodep) { m_cFuncp = nodep; } @@ -80,7 +80,7 @@ public: explicit TaskCodeVertex(V3Graph* graphp) : TaskBaseVertex{graphp} {} ~TaskCodeVertex() override = default; - string name() const override { return "*CODE*"; } + string name() const override VL_MT_STABLE { return "*CODE*"; } string dotColor() const override { return "green"; } }; diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index 0a096661e..afbba68f5 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -67,7 +67,7 @@ private: class DependencyVertex final : public V3GraphVertex { AstNode* const m_nodep; // AST node represented by this graph vertex // ACCESSORS - string name() const override { + string name() const override VL_MT_STABLE { return cvtToHex(nodep()) + ' ' + nodep()->prettyTypeName(); } FileLine* fileline() const override { return nodep()->fileline(); } diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index 26f2e0343..0028d2bc8 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -154,7 +154,7 @@ public: // ACCESSORS AstNode* nodep() const { return m_nodep; } const AstVar* varp() const { return VN_CAST(nodep(), Var); } - string name() const override { + string name() const override VL_MT_STABLE { return ((isTristate() ? "tri\\n" : feedsTri() ? "feed\\n" : "-\\n") diff --git a/src/V3Waiver.cpp b/src/V3Waiver.cpp index 606aa0b46..1650fdefa 100644 --- a/src/V3Waiver.cpp +++ b/src/V3Waiver.cpp @@ -23,8 +23,9 @@ #include #include -void V3Waiver::addEntry(V3ErrorCode errorCode, const std::string& filename, - const std::string& str) { +void V3Waiver::addEntry(V3ErrorCode errorCode, const std::string& filename, const std::string& str) + VL_MT_SAFE_EXCLUDES(s_mutex) { + const VerilatedLockGuard lock{s_mutex}; std::stringstream entry; const size_t pos = str.find('\n'); entry << "lint_off -rule " << errorCode.ascii() << " -file \"*" << filename << "\" -match \"" @@ -34,7 +35,7 @@ void V3Waiver::addEntry(V3ErrorCode errorCode, const std::string& filename, s_waiverList.push_back(entry.str()); } -void V3Waiver::write(const std::string& filename) { +void V3Waiver::write(const std::string& filename) VL_MT_SAFE_EXCLUDES(s_mutex) { const std::unique_ptr ofp{V3File::new_ofstream(filename)}; if (ofp->fail()) v3fatal("Can't write " << filename); @@ -48,9 +49,12 @@ void V3Waiver::write(const std::string& filename) { *ofp << "// 2. Keep the waiver permanently if you are sure this is okay\n"; *ofp << "// 3. Keep the waiver temporarily to suppress the output\n\n"; + const VerilatedLockGuard lock{s_mutex}; + if (s_waiverList.empty()) *ofp << "// No waivers needed - great!\n"; for (const auto& i : s_waiverList) *ofp << "// " << i << "\n\n"; } +VerilatedMutex V3Waiver::s_mutex; V3Waiver::WaiverList V3Waiver::s_waiverList; diff --git a/src/V3Waiver.h b/src/V3Waiver.h index 10f711d1c..c8ca73137 100644 --- a/src/V3Waiver.h +++ b/src/V3Waiver.h @@ -17,6 +17,8 @@ #ifndef VERILATOR_V3WAIVER_H_ #define VERILATOR_V3WAIVER_H_ +#include "verilated_threads.h" + #include "V3Error.h" #include @@ -25,11 +27,13 @@ class V3Waiver final { // TYPES using WaiverList = std::vector; - static WaiverList s_waiverList; + static VerilatedMutex s_mutex; // Protect members + static WaiverList s_waiverList VL_GUARDED_BY(s_mutex); public: - static void addEntry(V3ErrorCode errorCode, const string& filename, const std::string& str); - static void write(const std::string& filename); + static void addEntry(V3ErrorCode errorCode, const string& filename, const std::string& str) + VL_MT_SAFE_EXCLUDES(s_mutex); + static void write(const std::string& filename) VL_MT_SAFE_EXCLUDES(s_mutex); }; #endif // Guard From 80cbf81b3b394d547a0e85a9e1e5bb592f9cb6b5 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 17 Mar 2023 22:27:55 -0400 Subject: [PATCH 065/155] Internals: Fix missing relink() and add assert --- src/V3Ast.h | 8 +++++++- src/V3Clock.cpp | 6 ++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/V3Ast.h b/src/V3Ast.h index cee54c5b8..cae837a51 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1440,6 +1440,13 @@ protected: public: VNRelinker() = default; + ~VNRelinker() { + // Relink is needed so m_iterpp's get restored, e.g. can't have: + // ->unlinkFrBack(relinker); + // if (only_sometimes) relinker.relink(newp); + UDEBUGONLY( + UASSERT_STATIC(!m_backp, "Active linker must be relink()ed before destruction");); + } inline void relink(AstNode* newp); AstNode* oldp() const { return m_oldp; } void dump(std::ostream& str = std::cout) const; @@ -1645,7 +1652,6 @@ public: bool brokeExistsAbove() const { return brokeExists() && (m_brokenState >> 7); } bool brokeExistsBelow() const { return brokeExists() && !(m_brokenState >> 7); } // Note: brokeExistsBelow is not quite precise, as it is true for sibling nodes as well - bool brokeIterpp() const { return !!m_iterpp; } // CONSTRUCTORS virtual ~AstNode() = default; diff --git a/src/V3Clock.cpp b/src/V3Clock.cpp index f2a537555..1a7be8041 100644 --- a/src/V3Clock.cpp +++ b/src/V3Clock.cpp @@ -146,17 +146,19 @@ private: UASSERT_OBJ(nodep->hasClocked(), nodep, "Should have been converted by V3Sched"); UASSERT_OBJ(nodep->stmtsp(), nodep, "Should not have been created if empty"); - VNRelinker relinker; - nodep->unlinkFrBack(&relinker); AstNode* const stmtsp = nodep->stmtsp()->unlinkFrBackWithNext(); // Create 'if' statement, if needed if (!m_lastSenp || !nodep->sensesp()->sameTree(m_lastSenp)) { + VNRelinker relinker; + nodep->unlinkFrBack(&relinker); clearLastSen(); m_lastSenp = nodep->sensesp(); // Make a new if statement m_lastIfp = makeActiveIf(m_lastSenp); relinker.relink(m_lastIfp); + } else { + nodep->unlinkFrBack(); } // Move statements to if From 70c2d1eded95e843338535c8bf037782930ce056 Mon Sep 17 00:00:00 2001 From: Yu-Sheng Lin Date: Sat, 18 Mar 2023 19:38:09 +0800 Subject: [PATCH 066/155] Fix install, standardization in cmake CMakeLists.txt (#3974) --- CMakeLists.txt | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4cabd4fbe..c6da1a1a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,8 @@ project(Verilator option(DEBUG_AND_RELEASE_AND_COVERAGE "Builds both the debug and release binaries, overriding CMAKE_BUILD_TYPE. Not supported under MSBuild.") -set(PYTHON3 python) +find_package(Python3 COMPONENTS Interpreter) +set(PYTHON3 Python3::Interpreter) set(CMAKE_INSTALL_DATADIR ${CMAKE_INSTALL_PREFIX}) include(GNUInstallDirs) include(CMakePackageConfigHelpers) @@ -44,15 +45,7 @@ if (MSVC) if (NOT WIN_FLEX_BISON) message(FATAL_ERROR "Please install https://github.com/lexxmark/winflexbison and set WIN_FLEX_BISON environment variable. Please use install cmake target after a successful build.") endif() - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /std:c++20") -else() - if (NOT DEFINED ENV{FLEX_INCLUDE}) - message(FATAL_ERROR "Please set environment variable FLEX_INCLUDE to the directory containing FlexLexer.h") - endif() - set(WIN_FLEX_BISON "$ENV{FLEX_INCLUDE}") - if (WIN32 AND NOT MINGW) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++20") - endif() + set(CMAKE_CXX_STANDARD 20) endif() find_package(BISON) @@ -99,6 +92,7 @@ configure_package_config_file(verilator-config-version.cmake.in verilator-config install(FILES ${CMAKE_CURRENT_BINARY_DIR}/verilator-config-version.cmake DESTINATION ${CMAKE_INSTALL_PREFIX}) foreach (program + verilator verilator_gantt verilator_ccache_report verilator_difftree From d60a3e2b66972cade86235f1d1f92ed0bf5ca7b4 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 18 Mar 2023 09:47:46 -0400 Subject: [PATCH 067/155] Fix random internal crashes (#666). Internally, in V3Broken check m_interpp for null, and make several cleanups in the addNext/addNextHere/unlinkFr* methods. --- Changes | 1 + src/V3Ast.cpp | 48 +++++++++++++++++++++++++++++++----------------- src/V3Broken.cpp | 5 +++++ src/V3Broken.h | 3 +++ src/V3Error.cpp | 1 + 5 files changed, 41 insertions(+), 17 deletions(-) diff --git a/Changes b/Changes index bcb61457b..87cc38c96 100644 --- a/Changes +++ b/Changes @@ -23,6 +23,7 @@ Verilator 5.009 devel * Fix push to dynamic queue in struct (#4015). [ezchi] * Fix large return blocks with --comp-limit-blocks (#4028). [tenghtt] * Fix clocking block scope internal error (#4032). [Srinivasan Venkataramanan] +* Fix random internal crashes (#666). [Dag Lem] * Fix false ENUMVALUE on expressions and arrays. diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index c60db662f..e19729116 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -298,17 +298,19 @@ void AstNode::debugTreeChange(const AstNode* nodep, const char* prefix, int line // Called on all major tree changers. // Only for use for those really nasty bugs relating to internals // Note this may be null. -// if (debug()) cout<<"-treeChange: V3Ast.cpp:"<"<" +// << "m_iterpp=" << (void*)nodep->m_iterpp << endl; // if (debug()) { // cout<<"-treeChange: V3Ast.cpp:"<dumpTree("- treeChange: "); -// if (next||1) this->dumpTreeAndNext(cout, prefix); -// else this->dumpTree(prefix); -// this->checkTree(); +// if (next||1) nodep->dumpTreeAndNext(cout, prefix); +// else nodep->dumpTree(prefix); +// nodep->checkTree(); // v3Global.rootp()->checkTree(); //} #endif @@ -347,7 +349,8 @@ AstNode* AstNode::addNext(AstNode* nodep, AstNode* newp) { newtailp->m_headtailp = headp; headp->m_headtailp = newtailp; newp->editCountInc(); - if (oldtailp->m_iterpp) *(oldtailp->m_iterpp) = newp; // Iterate on new item + // No change of m_iterpp, as only changing m_nextp of current node; + // the current node is still the one at the iteration point } debugTreeChange(nodep, "-addNextOut:", __LINE__, true); return nodep; @@ -397,7 +400,8 @@ void AstNode::addNextHere(AstNode* newp) { } // else is head, and we're inserting into the middle, so no other change } - if (this->m_iterpp) *(this->m_iterpp) = newp; // Iterate on new item + // No change of m_iterpp, as adding after current node; + // the current node is still the one at the iteration point debugTreeChange(this, "-addHereOut: ", __LINE__, true); } @@ -565,8 +569,10 @@ AstNode* AstNode::unlinkFrBackWithNext(VNRelinker* linkerp) { // Relink oldp->m_backp = nullptr; // Iterator fixup - if (oldp->m_iterpp) *(oldp->m_iterpp) = nullptr; - oldp->m_iterpp = nullptr; + if (oldp->m_iterpp) { + *(oldp->m_iterpp) = nullptr; + oldp->m_iterpp = nullptr; + } debugTreeChange(oldp, "-unlinkWNextOut: ", __LINE__, true); return oldp; } @@ -580,7 +586,11 @@ AstNode* AstNode::unlinkFrBack(VNRelinker* linkerp) { if (linkerp) { linkerp->m_oldp = oldp; linkerp->m_backp = backp; - linkerp->m_iterpp = oldp->m_iterpp; + if (oldp->m_iterpp) { // Assumes we will always relink() if want to keep iterating + linkerp->m_iterpp = oldp->m_iterpp; + *(oldp->m_iterpp) = nullptr; + oldp->m_iterpp = nullptr; + } if (backp->m_nextp == oldp) { linkerp->m_chg = VNRelinker::RELINK_NEXT; } else if (backp->m_op1p == oldp) { @@ -625,12 +635,15 @@ AstNode* AstNode::unlinkFrBack(VNRelinker* linkerp) { } } // Iterator fixup - if (oldp->m_iterpp) *(oldp->m_iterpp) = oldp->m_nextp; + if (oldp->m_iterpp) { // Only if no linker, point to next in list + if (oldp->m_nextp) oldp->m_nextp->m_iterpp = oldp->m_iterpp; + *(oldp->m_iterpp) = oldp->m_nextp; + oldp->m_iterpp = nullptr; + } // Relink oldp->m_nextp = nullptr; oldp->m_backp = nullptr; - oldp->m_headtailp = this; - oldp->m_iterpp = nullptr; + oldp->m_headtailp = oldp; debugTreeChange(oldp, "-unlinkFrBkOut: ", __LINE__, true); return oldp; } @@ -668,12 +681,12 @@ void AstNode::relink(VNRelinker* linkerp) { // Iterator fixup if (linkerp->m_iterpp) { // If we're iterating over a next() link, we need to follow links off the - // NEW node. Thus we pass iteration information via a pointer in the node. + // NEW node, which is always assumed to be what we are relinking to. // This adds a unfortunate hot 8 bytes to every AstNode, but is faster than passing // across every function. // If anyone has a cleaner way, I'd be grateful. - *(linkerp->m_iterpp) = newp; newp->m_iterpp = linkerp->m_iterpp; + *(newp->m_iterpp) = newp; } // Empty the linker so not used twice accidentally linkerp->m_backp = nullptr; @@ -835,6 +848,7 @@ void AstNode::deleteNode() { this->m_op2p = reinterpret_cast(0x1); this->m_op3p = reinterpret_cast(0x1); this->m_op4p = reinterpret_cast(0x1); + this->m_iterpp = reinterpret_cast(0x1); if ( #if !defined(VL_DEBUG) || defined(VL_LEAK_CHECKS) true @@ -950,7 +964,7 @@ void AstNode::iterateAndNext(VNVisitor& v) { niterp->m_iterpp = nullptr; if (VL_UNLIKELY(niterp != nodep)) { // Edited node inside accept nodep = niterp; - } else { // Unchanged node, just continue loop + } else { // Unchanged node (though maybe updated m_next), just continue loop nodep = niterp->m_nextp; } } @@ -1131,7 +1145,7 @@ void AstNode::checkIter() const { if (m_iterpp) { dumpPtrs(cout); // Perhaps something forgot to clear m_iterpp? - this->v3fatalSrc("Iteration link should be nullptr"); + this->v3fatalSrc("Iteration link m_iterpp should be nullptr"); } } diff --git a/src/V3Broken.cpp b/src/V3Broken.cpp index 09ab9b7ef..14c01d029 100644 --- a/src/V3Broken.cpp +++ b/src/V3Broken.cpp @@ -62,6 +62,8 @@ public: } } s_brokenCntGlobal; +static bool s_brokenAllowMidvisitorCheck = false; + //###################################################################### // Table of allocated AstNode pointers @@ -172,6 +174,7 @@ private: const char* const whyp = nodep->broken(); UASSERT_OBJ(!whyp, nodep, "Broken link in node (or something without maybePointedTo): " << whyp); + if (!s_brokenAllowMidvisitorCheck) nodep->checkIter(); if (nodep->dtypep()) { UASSERT_OBJ(nodep->dtypep()->brokeExists(), nodep, "Broken link in node->dtypep() to " << cvtToHex(nodep->dtypep())); @@ -351,6 +354,8 @@ void V3Broken::brokenAll(AstNetlist* nodep) { } } +void V3Broken::allowMidvisitorCheck(bool flag) { s_brokenAllowMidvisitorCheck = flag; } + //###################################################################### // Self test diff --git a/src/V3Broken.h b/src/V3Broken.h index 6f4822642..d98add08b 100644 --- a/src/V3Broken.h +++ b/src/V3Broken.h @@ -32,6 +32,9 @@ public: static bool isLinkable(const AstNode* nodep); static void addNewed(const AstNode* nodep); static void deleted(const AstNode* nodep); + // Called on error to say may be inside visitor, + // Disables checks that may misfire if not called at stable point between visitors + static void allowMidvisitorCheck(bool flag); static void selfTest(); }; diff --git a/src/V3Error.cpp b/src/V3Error.cpp index 670dd7185..9eaaf9b0d 100644 --- a/src/V3Error.cpp +++ b/src/V3Error.cpp @@ -221,6 +221,7 @@ void V3ErrorGuarded::v3errorEnd(std::ostringstream& sstr, const string& extra) } #ifndef V3ERROR_NO_GLOBAL_ if (dumpTree() || debug()) { + V3Broken::allowMidvisitorCheck(true); V3ThreadPool::s().requestExclusiveAccess([&]() VL_REQUIRES(m_mutex) { if (dumpTree()) { v3Global.rootp()->dumpTreeFile( From ba9e141faebe66c9fe6f5d9548334cefd427d8d7 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 18 Mar 2023 10:23:19 -0400 Subject: [PATCH 068/155] Commentary: Update CONTRIBUTING and internals xrefs (#4043) --- docs/CONTRIBUTING.rst | 35 +++++++++++++++++++++-------------- docs/spelling.txt | 4 ++++ 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/docs/CONTRIBUTING.rst b/docs/CONTRIBUTING.rst index 1e81842ad..c7a4de79d 100644 --- a/docs/CONTRIBUTING.rst +++ b/docs/CONTRIBUTING.rst @@ -10,9 +10,12 @@ contributions flow more efficiently. Did you find a bug? ------------------- -- Please **Ensure the bug was not already reported** by searching +- Please **ensure the bug was not already reported** by searching `Verilator Issues `__. +- Please **download the latest development GitHub version**, build, and see + if the issue has been fixed. + - If you're unable to find an open issue addressing the problem, `open a new Verilator issue `__. @@ -20,21 +23,28 @@ Did you find a bug? demonstrating the bug and expected behavior that is not occurring. - The ideal example works against other simulators, and is in the - test_regress/t test format, as described in `docs/internals - `__. + test_regress/t test format, as described in + `Verilator Internals Documentation + `__. Did you write a patch that fixes a bug? --------------------------------------- -- Please `Open a new issue `__. +- Please `Open a new Verilator issue `__ + if there is not one already describing the bug. -- You may attach a patch to the issue, or (preferred) may request a - GitHub pull request. +- Please `Open a Verilator pull request + `__. - - Verilator uses GitHub Actions to provide continuous integration. You - may want to enable Actions on your GitHub branch to ensure your changes - keep the tests passing. See `docs/internals `__. +- See the coding conventions, and other developer information in + ``docs/internals.rst`` in the distribution, or as rendered at + `Verilator Internals Documentation + `__. + +- Verilator uses GitHub Actions to provide continuous integration. You + may want to enable Actions on your GitHub branch to ensure your changes + keep the tests passing. - Your source-code contributions must be certified as open source, under the `Developer Certificate of @@ -56,13 +66,10 @@ Did you write a patch that fixes a bug? contribution. - Your test contributions are generally considered released into the - Creative Commons Public Domain (CC0), unless you request otherwise or + Creative Commons Public Domain (CC0), unless you request otherwise, or put a GNU/Artistic license on your file. -- Most important is we get your patch. If you'd like to clean up - indentation and related issues ahead of our feedback, that is - appreciated; please see the coding conventions in `docs/internals - `__. +- Most important is we get your patch. Do you have questions? diff --git a/docs/spelling.txt b/docs/spelling.txt index 9098225a7..7d6a7c5d5 100644 --- a/docs/spelling.txt +++ b/docs/spelling.txt @@ -191,6 +191,7 @@ Laurens Lavino Leber Leendert +Lem Lesik Liland Liu @@ -301,6 +302,7 @@ Solomatnikov Solt Southwell Srini +Srinivasan Stamness Stephane Stoddard @@ -349,6 +351,7 @@ Vdeeptemp Vdly Vemumtab Vemuri +Venkataramanan Veriable Verialted Verilate @@ -854,6 +857,7 @@ svdpi swrite sys systemc +tenghtt testbench threadsafe threashold From 053f760e2a05ae079059b629d7dcf7c18bbb72e2 Mon Sep 17 00:00:00 2001 From: Tim Snyder Date: Sat, 18 Mar 2023 10:25:27 -0500 Subject: [PATCH 069/155] Fix characters from DEFENV literals for conda (#4035) (#4044) The baked in DEFENV paths might end up with extra NULL characters at the end if the binaries are installed by something that patches them for relocatable installs (e.g. conda). Avoid this issue by immediately passing them through std::string::c_str() method to stop at the first NULL --- src/V3Options.cpp | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/src/V3Options.cpp b/src/V3Options.cpp index ea3fcf25f..25283e424 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -656,8 +656,11 @@ string V3Options::getenvPERL() { // string V3Options::getenvSYSTEMC() { string var = V3Os::getenvStr("SYSTEMC", ""); - if (var == "" && string(DEFENV_SYSTEMC) != "") { - var = DEFENV_SYSTEMC; + // Treat compiled-in DEFENV string literals as C-strings to enable + // binary patching for relocatable installs (e.g. conda) + string defenv = string{DEFENV_SYSTEMC}.c_str(); + if (var == "" && defenv != "") { + var = defenv; V3Os::setenvStr("SYSTEMC", var, "Hardcoded at build time"); } return var; @@ -665,8 +668,11 @@ string V3Options::getenvSYSTEMC() { string V3Options::getenvSYSTEMC_ARCH() { string var = V3Os::getenvStr("SYSTEMC_ARCH", ""); - if (var == "" && string(DEFENV_SYSTEMC_ARCH) != "") { - var = DEFENV_SYSTEMC_ARCH; + // Treat compiled-in DEFENV string literals as C-strings to enable + // binary patching for relocatable installs (e.g. conda) + string defenv = string{DEFENV_SYSTEMC_ARCH}.c_str(); + if (var == "" && defenv != "") { + var = defenv; V3Os::setenvStr("SYSTEMC_ARCH", var, "Hardcoded at build time"); } if (var == "") { @@ -697,8 +703,11 @@ string V3Options::getenvSYSTEMC_ARCH() { string V3Options::getenvSYSTEMC_INCLUDE() { string var = V3Os::getenvStr("SYSTEMC_INCLUDE", ""); - if (var == "" && string(DEFENV_SYSTEMC_INCLUDE) != "") { - var = DEFENV_SYSTEMC_INCLUDE; + // Treat compiled-in DEFENV string literals as C-strings to enable + // binary patching for relocatable installs (e.g. conda) + string defenv = string{DEFENV_SYSTEMC_INCLUDE}.c_str(); + if (var == "" && defenv != "") { + var = defenv; V3Os::setenvStr("SYSTEMC_INCLUDE", var, "Hardcoded at build time"); } if (var == "") { @@ -710,8 +719,11 @@ string V3Options::getenvSYSTEMC_INCLUDE() { string V3Options::getenvSYSTEMC_LIBDIR() { string var = V3Os::getenvStr("SYSTEMC_LIBDIR", ""); - if (var == "" && string(DEFENV_SYSTEMC_LIBDIR) != "") { - var = DEFENV_SYSTEMC_LIBDIR; + // Treat compiled-in DEFENV string literals as C-strings to enable + // binary patching for relocatable installs (e.g. conda) + string defenv = string{DEFENV_SYSTEMC_LIBDIR}.c_str(); + if (var == "" && defenv != "") { + var = defenv; V3Os::setenvStr("SYSTEMC_LIBDIR", var, "Hardcoded at build time"); } if (var == "") { @@ -724,8 +736,11 @@ string V3Options::getenvSYSTEMC_LIBDIR() { string V3Options::getenvVERILATOR_ROOT() { string var = V3Os::getenvStr("VERILATOR_ROOT", ""); - if (var == "" && string(DEFENV_VERILATOR_ROOT) != "") { - var = DEFENV_VERILATOR_ROOT; + // Treat compiled-in DEFENV string literals as C-strings to enable + // binary patching for relocatable installs (e.g. conda) + string defenv = string{DEFENV_VERILATOR_ROOT}.c_str(); + if (var == "" && defenv != "") { + var = defenv; V3Os::setenvStr("VERILATOR_ROOT", var, "Hardcoded at build time"); } if (var == "") v3fatal("$VERILATOR_ROOT needs to be in environment\n"); From 82e653a73916c72ff2196a5511ed75e023f64e2e Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 18 Mar 2023 12:05:29 -0400 Subject: [PATCH 070/155] Internals: Avoid emit inheritance in V3EmitCBase. No functional change intended. --- src/V3AstNodes.cpp | 6 ++-- src/V3CCtors.cpp | 2 +- src/V3Common.cpp | 8 +++--- src/V3DepthBlock.cpp | 2 +- src/V3EmitCBase.h | 61 +++++++++++++++++++++-------------------- src/V3EmitCFunc.h | 2 +- src/V3EmitCHeaders.cpp | 2 +- src/V3EmitCImp.cpp | 11 ++++---- src/V3Partition.cpp | 4 +-- src/V3Sched.cpp | 2 +- src/V3SchedTiming.cpp | 2 +- src/V3Task.cpp | 7 ++--- src/V3Trace.cpp | 10 +++---- src/V3TraceDecl.cpp | 2 +- src/V3VariableOrder.cpp | 2 +- 15 files changed, 61 insertions(+), 62 deletions(-) diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index bb721a2ee..0e09698e0 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -735,9 +735,9 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const VL_M const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(true); info.m_type = "VlSampleQueue<" + sub.m_type + ">"; } else if (const auto* const adtypep = VN_CAST(dtypep, ClassRefDType)) { - info.m_type = "VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(adtypep) + ">"; + info.m_type = "VlClassRef<" + EmitCBase::prefixNameProtect(adtypep) + ">"; } else if (const auto* const adtypep = VN_CAST(dtypep, IfaceRefDType)) { - info.m_type = EmitCBaseVisitor::prefixNameProtect(adtypep->ifaceViaCellp()) + "*"; + info.m_type = EmitCBase::prefixNameProtect(adtypep->ifaceViaCellp()) + "*"; } else if (const auto* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) { if (adtypep->isCompound()) compound = true; const CTypeRecursed sub = adtypep->subDTypep()->cTypeRecurse(compound); @@ -746,7 +746,7 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const VL_M info.m_type += ">"; } else if (VN_IS(dtypep, NodeUOrStructDType) && !VN_AS(dtypep, NodeUOrStructDType)->packed()) { const auto* const sdtypep = VN_AS(dtypep, NodeUOrStructDType); - info.m_type = EmitCBaseVisitor::prefixNameProtect(sdtypep); + info.m_type = EmitCBase::prefixNameProtect(sdtypep); } else if (const AstBasicDType* const bdtypep = dtypep->basicp()) { // We don't print msb()/lsb() as multidim packed would require recursion, // and may confuse users as C++ data is stored always with bit 0 used diff --git a/src/V3CCtors.cpp b/src/V3CCtors.cpp index c70e11b2a..216f8141e 100644 --- a/src/V3CCtors.cpp +++ b/src/V3CCtors.cpp @@ -70,7 +70,7 @@ private: funcp->slow(!m_type.isClass()); // Only classes construct on fast path string preventUnusedStmt; if (m_type.isClass()) { - funcp->argTypes(EmitCBaseVisitor::symClassVar()); + funcp->argTypes(EmitCBase::symClassVar()); preventUnusedStmt = "if (false && vlSymsp) {} // Prevent unused\n"; } else if (m_type.isCoverage()) { funcp->argTypes("bool first"); diff --git a/src/V3Common.cpp b/src/V3Common.cpp index 72f900eb1..b5f5a4c8c 100644 --- a/src/V3Common.cpp +++ b/src/V3Common.cpp @@ -37,7 +37,7 @@ VL_DEFINE_DEBUG_FUNCTIONS; static void makeVlToString(AstClass* nodep) { AstCFunc* const funcp = new AstCFunc{nodep->fileline(), "VL_TO_STRING", nullptr, "std::string"}; - funcp->argTypes("const VlClassRef<" + EmitCBaseVisitor::prefixNameProtect(nodep) + ">& obj"); + funcp->argTypes("const VlClassRef<" + EmitCBase::prefixNameProtect(nodep) + ">& obj"); funcp->isMethod(false); funcp->isConst(false); funcp->isStatic(false); @@ -51,7 +51,7 @@ static void makeVlToString(AstClass* nodep) { static void makeVlToString(AstIface* nodep) { AstCFunc* const funcp = new AstCFunc{nodep->fileline(), "VL_TO_STRING", nullptr, "std::string"}; - funcp->argTypes("const " + EmitCBaseVisitor::prefixNameProtect(nodep) + "* obj"); + funcp->argTypes("const " + EmitCBase::prefixNameProtect(nodep) + "* obj"); funcp->isMethod(false); funcp->isConst(false); funcp->isStatic(false); @@ -65,7 +65,7 @@ static void makeVlToString(AstNodeUOrStructDType* nodep) { AstNodeModule* const modp = nodep->classOrPackagep(); AstCFunc* const funcp = new AstCFunc{nodep->fileline(), "VL_TO_STRING", nullptr, "std::string"}; - funcp->argTypes("const " + EmitCBaseVisitor::prefixNameProtect(nodep) + "& obj"); + funcp->argTypes("const " + EmitCBase::prefixNameProtect(nodep) + "& obj"); funcp->isMethod(false); funcp->isConst(false); funcp->isStatic(false); @@ -137,7 +137,7 @@ static void makeToStringMiddle(AstClass* nodep) { string stmt = "out += "; if (!comma.empty()) stmt += "\", \"+ "; // comma = ", "; // Nothing further so not needed - stmt += EmitCBaseVisitor::prefixNameProtect(nodep->extendsp()->dtypep()); + stmt += EmitCBase::prefixNameProtect(nodep->extendsp()->dtypep()); stmt += "::to_string_middle();\n"; nodep->user1(true); // So what we extend dumps this funcp->addStmtsp(new AstCStmt{nodep->fileline(), stmt}); diff --git a/src/V3DepthBlock.cpp b/src/V3DepthBlock.cpp index 3023f2457..889601de2 100644 --- a/src/V3DepthBlock.cpp +++ b/src/V3DepthBlock.cpp @@ -63,7 +63,7 @@ private: AstCCall* const callp = new AstCCall{nodep->fileline(), funcp}; callp->dtypeSetVoid(); if (VN_IS(m_modp, Class)) { - funcp->argTypes(EmitCBaseVisitor::symClassVar()); + funcp->argTypes(EmitCBase::symClassVar()); callp->argTypes("vlSymsp"); } UINFO(6, " New " << callp << endl); diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index a183b4e78..523072e18 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -48,7 +48,36 @@ public: //###################################################################### // Base Visitor class -- holds output file pointer -class EmitCBaseVisitor VL_NOT_FINAL : public VNVisitor { +class EmitCBase VL_NOT_FINAL { +public: + static string voidSelfAssign(const AstNodeModule* modp) { + const string className = prefixNameProtect(modp); + return className + "* const __restrict vlSelf VL_ATTR_UNUSED = static_cast<" + className + + "*>(voidSelf);\n"; + } + static string symClassName() { + return v3Global.opt.prefix() + "_" + VIdProtect::protect("_Syms"); + } + static string symClassVar() { return symClassName() + "* __restrict vlSymsp"; } + static string symClassAssign() { + return symClassName() + "* const __restrict vlSymsp VL_ATTR_UNUSED = vlSelf->vlSymsp;\n"; + } + static string prefixNameProtect(const AstNode* nodep) VL_MT_SAFE { // C++ name with prefix + return v3Global.opt.modPrefix() + "_" + VIdProtect::protect(nodep->name()); + } + static bool isAnonOk(const AstVar* varp) { + return v3Global.opt.compLimitMembers() != 0 // Enabled + && !varp->isStatic() // Not a static variable + && !varp->isSc() // Aggregates can't be anon + && !VN_IS(varp->dtypep()->skipRefp(), SampleQueueDType) // Aggregates can't be anon + && (varp->basicp() && !varp->basicp()->isOpaque()); // Aggregates can't be anon + } + static bool isConstPoolMod(const AstNode* modp) { + return modp == v3Global.rootp()->constPoolp()->modp(); + } +}; + +class EmitCBaseVisitor VL_NOT_FINAL : public VNVisitor, public EmitCBase { public: // STATE V3OutCFile* m_ofp = nullptr; @@ -63,9 +92,7 @@ public: void putsQuoted(const string& str) { ofp()->putsQuoted(str); } void ensureNewLine() { ofp()->ensureNewLine(); } bool optSystemC() { return v3Global.opt.systemC(); } - static string protect(const string& name) VL_MT_SAFE { - return VIdProtect::protectIf(name, true); - } + static string protect(const string& name) VL_MT_SAFE { return VIdProtect::protect(name); } static string protectIf(const string& name, bool doIt) { return VIdProtect::protectIf(name, doIt); } @@ -75,36 +102,10 @@ public: static string ifNoProtect(const string& in) VL_MT_SAFE { return v3Global.opt.protectIds() ? "" : in; } - static string voidSelfAssign(const AstNodeModule* modp) { - const string className = prefixNameProtect(modp); - return className + "* const __restrict vlSelf VL_ATTR_UNUSED = static_cast<" + className - + "*>(voidSelf);\n"; - } - static string symClassName() { return v3Global.opt.prefix() + "_" + protect("_Syms"); } - static string symClassVar() { return symClassName() + "* __restrict vlSymsp"; } - static string symClassAssign() { - return symClassName() + "* const __restrict vlSymsp VL_ATTR_UNUSED = vlSelf->vlSymsp;\n"; - } static string funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp = nullptr); - static string prefixNameProtect(const AstNode* nodep) VL_MT_SAFE { // C++ name with prefix - return v3Global.opt.modPrefix() + "_" + protect(nodep->name()); - } static string topClassName() VL_MT_SAFE { // Return name of top wrapper module return v3Global.opt.prefix(); } - - static bool isConstPoolMod(const AstNode* modp) { - return modp == v3Global.rootp()->constPoolp()->modp(); - } - - static bool isAnonOk(const AstVar* varp) { - return v3Global.opt.compLimitMembers() != 0 // Enabled - && !varp->isStatic() // Not a static variable - && !varp->isSc() // Aggregates can't be anon - && !VN_IS(varp->dtypep()->skipRefp(), SampleQueueDType) // Aggregates can't be anon - && (varp->basicp() && !varp->basicp()->isOpaque()); // Aggregates can't be anon - } - static AstCFile* newCFile(const string& filename, bool slow, bool source, bool add = true); string cFuncArgs(const AstCFunc* nodep); void emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp, bool withScope); diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index a2bb47892..7ea87dac3 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -83,7 +83,7 @@ class EmitCLazyDecls final : public VNVisitorConst { void visit(AstVarRef* nodep) override { AstVar* const varp = nodep->varp(); // Only constant pool symbols are lazy declared for now ... - if (EmitCBaseVisitor::isConstPoolMod(EmitCParentModule::get(varp))) { + if (EmitCBase::isConstPoolMod(EmitCParentModule::get(varp))) { lazyDeclareConstPoolVar(varp); } } diff --git a/src/V3EmitCHeaders.cpp b/src/V3EmitCHeaders.cpp index eadea126f..986ae5a08 100644 --- a/src/V3EmitCHeaders.cpp +++ b/src/V3EmitCHeaders.cpp @@ -224,7 +224,7 @@ class EmitCHeader final : public EmitCConstInit { } } puts(sdtypep->verilogKwd()); // "struct"/"union" - puts(" " + EmitCBaseVisitor::prefixNameProtect(sdtypep) + " {\n"); + puts(" " + EmitCBase::prefixNameProtect(sdtypep) + " {\n"); for (const AstMemberDType* itemp = sdtypep->membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) { puts(itemp->dtypep()->cType(itemp->nameProtect(), false, false)); diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index 4a96fa118..33a2d3a89 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -38,23 +38,22 @@ class EmitCGatherDependencies final : VNVisitorConst { std::set m_dependencies; // Header names to be included in output C++ file // METHODS - void addSymsDependency() { m_dependencies.insert(EmitCBaseVisitor::symClassName()); } + void addSymsDependency() { m_dependencies.insert(EmitCBase::symClassName()); } void addModDependency(const AstNodeModule* modp) { if (const AstClass* const classp = VN_CAST(modp, Class)) { - m_dependencies.insert(EmitCBaseVisitor::prefixNameProtect(classp->classOrPackagep())); + m_dependencies.insert(EmitCBase::prefixNameProtect(classp->classOrPackagep())); } else { - m_dependencies.insert(EmitCBaseVisitor::prefixNameProtect(modp)); + m_dependencies.insert(EmitCBase::prefixNameProtect(modp)); } } void addDTypeDependency(const AstNodeDType* nodep) { if (const AstClassRefDType* const dtypep = VN_CAST(nodep, ClassRefDType)) { m_dependencies.insert( - EmitCBaseVisitor::prefixNameProtect(dtypep->classp()->classOrPackagep())); + EmitCBase::prefixNameProtect(dtypep->classp()->classOrPackagep())); } else if (const AstNodeUOrStructDType* const dtypep = VN_CAST(nodep, NodeUOrStructDType)) { if (!dtypep->packed()) { - m_dependencies.insert( - EmitCBaseVisitor::prefixNameProtect(dtypep->classOrPackagep())); + m_dependencies.insert(EmitCBase::prefixNameProtect(dtypep->classOrPackagep())); } } } diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp index 45976fe76..04d34e842 100644 --- a/src/V3Partition.cpp +++ b/src/V3Partition.cpp @@ -3129,8 +3129,8 @@ static const std::vector createThreadFunctions(const ThreadSchedule& funcp->argTypes("void* voidSelf, bool even_cycle"); // Setup vlSelf an vlSyms - funcp->addStmtsp(new AstCStmt{fl, EmitCBaseVisitor::voidSelfAssign(modp)}); - funcp->addStmtsp(new AstCStmt{fl, EmitCBaseVisitor::symClassAssign()}); + funcp->addStmtsp(new AstCStmt{fl, EmitCBase::voidSelfAssign(modp)}); + funcp->addStmtsp(new AstCStmt{fl, EmitCBase::symClassAssign()}); // Invoke each mtask scheduled to this thread from the thread function for (const ExecMTask* const mtaskp : thread) { diff --git a/src/V3Sched.cpp b/src/V3Sched.cpp index 601b82c7b..c1652e040 100644 --- a/src/V3Sched.cpp +++ b/src/V3Sched.cpp @@ -607,7 +607,7 @@ std::pair makeEvalLoop(AstNetlist* netlistp, const s AstTextBlock* const blockp = new AstTextBlock{flp}; failp->addThensp(blockp); FileLine* const locp = netlistp->topModulep()->fileline(); - const string& file = EmitCBaseVisitor::protect(locp->filename()); + const string& file = VIdProtect::protect(locp->filename()); const string& line = cvtToStr(locp->lineno()); const auto add = [&](const string& text) { blockp->addText(flp, text, true); }; add("#ifdef VL_DEBUG\n"); diff --git a/src/V3SchedTiming.cpp b/src/V3SchedTiming.cpp index 212163164..e772d1bcb 100644 --- a/src/V3SchedTiming.cpp +++ b/src/V3SchedTiming.cpp @@ -362,7 +362,7 @@ void transformForks(AstNetlist* const netlistp) { // If we're in a class, add a vlSymsp arg if (m_inClass) { newfuncp->addInitsp(new AstCStmt{nodep->fileline(), "VL_KEEP_THIS;\n"}); - newfuncp->argTypes(EmitCBaseVisitor::symClassVar()); + newfuncp->argTypes(EmitCBase::symClassVar()); callp->argTypes("vlSymsp"); } // Put the begin's statements in the function, delete the begin diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 64567e122..ea12eb5f3 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -802,7 +802,7 @@ private: // Convert input/inout DPI arguments to Internal types string args; - args += ("(" + EmitCBaseVisitor::symClassName() + args += ("(" + EmitCBase::symClassName() + "*)(__Vscopep->symsp())"); // Upcast w/o overhead AstNode* argnodesp = nullptr; for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { @@ -1181,15 +1181,14 @@ private: cfuncp->isConstructor(true); AstClass* const classp = m_statep->getClassp(nodep); if (classp->extendsp()) { - cfuncp->baseCtors( - EmitCBaseVisitor::prefixNameProtect(classp->extendsp()->classp())); + cfuncp->baseCtors(EmitCBase::prefixNameProtect(classp->extendsp()->classp())); } } if (cfuncp->dpiExportImpl()) cfuncp->cname(nodep->cname()); if (!nodep->dpiImport() && !nodep->taskPublic()) { // Need symbol table - cfuncp->argTypes(EmitCBaseVisitor::symClassVar()); + cfuncp->argTypes(EmitCBase::symClassVar()); if (cfuncp->name() == "new") { const string stmt = VIdProtect::protect("_ctor_var_reset") + "(vlSymsp);\n"; cfuncp->addInitsp(new AstCStmt{nodep->fileline(), stmt}); diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index 32dbd8471..d7669f62d 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -154,7 +154,7 @@ public: //###################################################################### // Trace state, as a visitor of each AstNode -class TraceVisitor final : public EmitCBaseVisitor { +class TraceVisitor final : public VNVisitor { private: // NODE STATE // V3Hasher in V3DupFinder @@ -511,8 +511,8 @@ private: funcp->argTypes("void* voidSelf, " + v3Global.opt.traceClassBase() + "::" + (v3Global.opt.useTraceOffload() ? "OffloadBuffer" : "Buffer") + "* bufp"); - addInitStr(voidSelfAssign(m_topModp)); - addInitStr(symClassAssign()); + addInitStr(EmitCBase::voidSelfAssign(m_topModp)); + addInitStr(EmitCBase::symClassAssign()); // Add global activity check to change dump functions if (!full) { // addInitStr("if (VL_UNLIKELY(!vlSymsp->__Vm_activity)) return;\n"); @@ -709,8 +709,8 @@ private: cleanupFuncp->isStatic(true); cleanupFuncp->isLoose(true); m_topScopep->addBlocksp(cleanupFuncp); - cleanupFuncp->addInitsp(new AstCStmt{fl, voidSelfAssign(m_topModp)}); - cleanupFuncp->addInitsp(new AstCStmt{fl, symClassAssign()}); + cleanupFuncp->addInitsp(new AstCStmt{fl, EmitCBase::voidSelfAssign(m_topModp)}); + cleanupFuncp->addInitsp(new AstCStmt{fl, EmitCBase::symClassAssign()}); // Register it m_regFuncp->addStmtsp(new AstText{fl, "tracep->addCleanupCb(", true}); diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp index bba3bc78b..704d1d4b4 100644 --- a/src/V3TraceDecl.cpp +++ b/src/V3TraceDecl.cpp @@ -93,7 +93,7 @@ public: //###################################################################### // TraceDecl state, as a visitor of each AstNode -class TraceDeclVisitor final : public EmitCBaseVisitor { +class TraceDeclVisitor final : public VNVisitor { private: // NODE STATE diff --git a/src/V3VariableOrder.cpp b/src/V3VariableOrder.cpp index bdff566ba..6f19fe113 100644 --- a/src/V3VariableOrder.cpp +++ b/src/V3VariableOrder.cpp @@ -169,7 +169,7 @@ class VariableOrder final { : (sigbytes == 1) ? 2 : 10; // Anonymous structure ok - attributes.anonOk = EmitCBaseVisitor::isAnonOk(varp); + attributes.anonOk = EmitCBase::isAnonOk(varp); } } From f2aac8c49a38f24dd0d0c4911585c1ac2216e58e Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 18 Mar 2023 12:17:25 -0400 Subject: [PATCH 071/155] Internals: Use VNVisitorConst where possible, for better performance. No functional change indended. --- src/V3Active.cpp | 10 +- src/V3Branch.cpp | 14 +-- src/V3Case.cpp | 10 +- src/V3Const.cpp | 20 ++-- src/V3EmitCBase.cpp | 21 ++-- src/V3EmitCBase.h | 6 +- src/V3EmitCConstInit.h | 6 +- src/V3EmitCConstPool.cpp | 2 +- src/V3EmitCFunc.cpp | 18 ++-- src/V3EmitCFunc.h | 222 +++++++++++++++++++-------------------- src/V3EmitCHeaders.cpp | 4 +- src/V3EmitCImp.cpp | 12 +-- src/V3EmitCInlines.cpp | 16 +-- src/V3EmitCMain.cpp | 4 +- src/V3EmitCModel.cpp | 2 +- src/V3EmitCSyms.cpp | 14 +-- src/V3EmitV.cpp | 52 ++++----- src/V3EmitXml.cpp | 41 ++++---- src/V3Gate.cpp | 20 ++-- src/V3Hasher.cpp | 75 ++++++------- src/V3Inst.cpp | 8 +- src/V3InstrCount.cpp | 40 +++---- src/V3LinkResolve.cpp | 12 +-- src/V3MergeCond.cpp | 2 +- src/V3Randomize.cpp | 10 +- src/V3Simulate.h | 118 ++++++++++----------- src/V3Split.cpp | 8 +- src/V3Undriven.cpp | 28 ++--- 28 files changed, 397 insertions(+), 398 deletions(-) diff --git a/src/V3Active.cpp b/src/V3Active.cpp index 2ad8a1a8f..a333f65f7 100644 --- a/src/V3Active.cpp +++ b/src/V3Active.cpp @@ -309,7 +309,7 @@ AstActive*& ActiveNamer::getSpecialActive() { //###################################################################### // Latch checking visitor -class ActiveLatchCheckVisitor final : public VNVisitor { +class ActiveLatchCheckVisitor final : public VNVisitorConst { private: // NODE STATE // Input: @@ -329,20 +329,20 @@ private: LatchDetectGraphVertex* const parentp = m_graph.currentp(); LatchDetectGraphVertex* const branchp = m_graph.addPathVertex(parentp, "BRANCH", true); m_graph.addPathVertex(branchp, "IF"); - iterateAndNextNull(nodep->thensp()); + iterateAndNextConstNull(nodep->thensp()); m_graph.addPathVertex(branchp, "ELSE"); - iterateAndNextNull(nodep->elsesp()); + iterateAndNextConstNull(nodep->elsesp()); m_graph.currentp(parentp); } } //-------------------- - void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } public: // CONSTRUCTORS ActiveLatchCheckVisitor(AstNode* nodep, bool expectLatch) { m_graph.begin(); - iterate(nodep); + iterateConst(nodep); m_graph.latchCheck(nodep, expectLatch); } ~ActiveLatchCheckVisitor() override = default; diff --git a/src/V3Branch.cpp b/src/V3Branch.cpp index 003b0cb24..019f442c5 100644 --- a/src/V3Branch.cpp +++ b/src/V3Branch.cpp @@ -38,7 +38,7 @@ VL_DEFINE_DEBUG_FUNCTIONS; //###################################################################### // Branch state, as a visitor of each AstNode -class BranchVisitor final : public VNVisitor { +class BranchVisitor final : public VNVisitorConst { private: // NODE STATE // Entire netlist: @@ -71,12 +71,12 @@ private: { // Do if reset(); - iterateAndNextNull(nodep->thensp()); + iterateAndNextConstNull(nodep->thensp()); const int ifLikely = m_likely; const int ifUnlikely = m_unlikely; // Do else reset(); - iterateAndNextNull(nodep->elsesp()); + iterateAndNextConstNull(nodep->elsesp()); const int elseLikely = m_likely; const int elseUnlikely = m_unlikely; // Compute @@ -91,16 +91,16 @@ private: void visit(AstNodeCCall* nodep) override { checkUnlikely(nodep); nodep->funcp()->user1Inc(); - iterateChildren(nodep); + iterateChildrenConst(nodep); } void visit(AstCFunc* nodep) override { checkUnlikely(nodep); m_cfuncsp.push_back(nodep); - iterateChildren(nodep); + iterateChildrenConst(nodep); } void visit(AstNode* nodep) override { checkUnlikely(nodep); - iterateChildren(nodep); + iterateChildrenConst(nodep); } // METHODS @@ -114,7 +114,7 @@ public: // CONSTRUCTORS explicit BranchVisitor(AstNetlist* nodep) { reset(); - iterateChildren(nodep); + iterateChildrenConst(nodep); calc_tasks(); } ~BranchVisitor() override = default; diff --git a/src/V3Case.cpp b/src/V3Case.cpp index 8a3857c17..4ae5969ad 100644 --- a/src/V3Case.cpp +++ b/src/V3Case.cpp @@ -53,7 +53,7 @@ VL_DEFINE_DEBUG_FUNCTIONS; //###################################################################### -class CaseLintVisitor final : public VNVisitor { +class CaseLintVisitor final : public VNVisitorConst { private: const AstNodeCase* m_caseExprp = nullptr; // Under a CASE value node, if so the relevant case statement @@ -79,10 +79,10 @@ private: // Check for X/Z in non-casex statements { m_caseExprp = nodep; - iterate(nodep->exprp()); + iterateConst(nodep->exprp()); for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp = VN_AS(itemp->nextp(), CaseItem)) { - iterateAndNextNull(itemp->condsp()); + iterateAndNextConstNull(itemp->condsp()); } m_caseExprp = nullptr; } @@ -108,11 +108,11 @@ private: } } } - void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } public: // CONSTRUCTORS - explicit CaseLintVisitor(AstNodeCase* nodep) { iterate(nodep); } + explicit CaseLintVisitor(AstNodeCase* nodep) { iterateConst(nodep); } ~CaseLintVisitor() override = default; }; diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 6d7a9751c..da4a74f62 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -70,7 +70,7 @@ static int countTrailingZeroes(uint64_t val) { // This visitor can be used in the post-expanded Ast from V3Expand, where the Ast satisfies: // - Constants are 64 bit at most (because words are accessed via AstWordSel) // - Variables are scoped. -class ConstBitOpTreeVisitor final : public VNVisitor { +class ConstBitOpTreeVisitor final : public VNVisitorConst { // NODE STATE // AstVarRef::user4u -> Base index of m_varInfos that points VarInfo // AstVarScope::user4u -> Same as AstVarRef::user4 @@ -416,7 +416,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor { { VL_RESTORER(m_leafp); m_leafp = &info; - iterate(nodep); + iterateConst(nodep); } bool ok = !m_failed; @@ -431,7 +431,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor { // VISITORS void visit(AstNode* nodep) override { CONST_BITOP_SET_FAILED("Hit unexpected op", nodep); } void visit(AstCCast* nodep) override { - iterateChildren(nodep); + iterateChildrenConst(nodep); if (m_leafp) m_leafp->updateBitRange(nodep); } void visit(AstShiftR* nodep) override { @@ -440,7 +440,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor { CONST_BITOP_RETURN_IF(!constp, nodep->rhsp()); m_lsb += constp->toUInt(); incrOps(nodep, __LINE__); - iterate(nodep->lhsp()); + iterateConst(nodep->lhsp()); m_leafp->updateBitRange(nodep); m_lsb -= constp->toUInt(); } @@ -454,7 +454,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor { lhsp); incrOps(nodep, __LINE__); m_polarity = !m_polarity; - iterateChildren(nodep); + iterateChildrenConst(nodep); // Don't restore m_polarity for Xor as it counts parity of the entire tree if (!isXorTree()) m_polarity = !m_polarity; if (m_leafp && castp) m_leafp->updateBitRange(castp); @@ -465,7 +465,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor { CONST_BITOP_RETURN_IF(!constp, nodep->rhsp()); UASSERT_OBJ(m_leafp->wordIdx() == -1, nodep, "Unexpected nested WordSel"); m_leafp->wordIdx(constp->toSInt()); - iterate(nodep->fromp()); + iterateConst(nodep->fromp()); } void visit(AstVarRef* nodep) override { CONST_BITOP_RETURN_IF(!m_leafp, nodep); @@ -529,7 +529,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor { // Always reach past a plain making AND Restorer restorer{*this}; incrOps(nodep, __LINE__); - iterate(nodep->rhsp()); + iterateConst(nodep->rhsp()); CONST_BITOP_RETURN_IF(m_failed, nodep->rhsp()); restorer.disableRestore(); // Now all checks passed } else if (nodep->type() == m_rootp->type()) { // And, Or, Xor @@ -542,7 +542,7 @@ class ConstBitOpTreeVisitor final : public VNVisitor { m_leafp = &leafInfo; AstNodeExpr* opp = right ? nodep->rhsp() : nodep->lhsp(); const bool origFailed = m_failed; - iterate(opp); + iterateConst(opp); if (leafInfo.constp() || m_failed) { // Revert changes in leaf restorer.restoreNow(); @@ -647,11 +647,11 @@ class ConstBitOpTreeVisitor final : public VNVisitor { m_varInfos.push_back(nullptr); CONST_BITOP_RETURN_IF(!isAndTree() && !isOrTree() && !isXorTree(), nodep); if (AstNodeBiop* const biopp = VN_CAST(nodep, NodeBiop)) { - iterate(biopp); + iterateConst(biopp); } else { UASSERT_OBJ(VN_IS(nodep, RedXor), nodep, "Must be RedXor"); incrOps(nodep, __LINE__); - iterateChildren(nodep); + iterateChildrenConst(nodep); } for (auto&& entry : m_bitPolarities) { getVarInfo(entry.m_info).setPolarity(entry.m_polarity, entry.m_bit); diff --git a/src/V3EmitCBase.cpp b/src/V3EmitCBase.cpp index 884950da2..e8384456d 100644 --- a/src/V3EmitCBase.cpp +++ b/src/V3EmitCBase.cpp @@ -39,7 +39,7 @@ EmitCParentModule::EmitCParentModule() { //###################################################################### // EmitCBaseVisitor implementation -string EmitCBaseVisitor::funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp) { +string EmitCBaseVisitorConst::funcNameProtect(const AstCFunc* nodep, const AstNodeModule* modp) { modp = modp ? modp : EmitCParentModule::get(nodep); string name; if (nodep->isConstructor()) { @@ -57,7 +57,8 @@ string EmitCBaseVisitor::funcNameProtect(const AstCFunc* nodep, const AstNodeMod return name; } -AstCFile* EmitCBaseVisitor::newCFile(const string& filename, bool slow, bool source, bool add) { +AstCFile* EmitCBaseVisitorConst::newCFile(const string& filename, bool slow, bool source, + bool add) { AstCFile* const cfilep = new AstCFile{v3Global.rootp()->fileline(), filename}; cfilep->slow(slow); cfilep->source(source); @@ -65,7 +66,7 @@ AstCFile* EmitCBaseVisitor::newCFile(const string& filename, bool slow, bool sou return cfilep; } -string EmitCBaseVisitor::cFuncArgs(const AstCFunc* nodep) { +string EmitCBaseVisitorConst::cFuncArgs(const AstCFunc* nodep) { // Return argument list for given C function string args; if (nodep->isLoose() && !nodep->isStatic()) { @@ -95,8 +96,8 @@ string EmitCBaseVisitor::cFuncArgs(const AstCFunc* nodep) { return args; } -void EmitCBaseVisitor::emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp, - bool withScope) { +void EmitCBaseVisitorConst::emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp, + bool withScope) { if (funcp->slow()) puts("VL_ATTR_COLD "); if (!funcp->isConstructor() && !funcp->isDestructor()) { puts(funcp->rtnTypeVoid()); @@ -114,8 +115,8 @@ void EmitCBaseVisitor::emitCFuncHeader(const AstCFunc* funcp, const AstNodeModul if (funcp->isConst().trueKnown() && funcp->isProperMethod()) puts(" const"); } -void EmitCBaseVisitor::emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp, - bool cLinkage) { +void EmitCBaseVisitorConst::emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp, + bool cLinkage) { ensureNewLine(); if (!funcp->ifdef().empty()) puts("#ifdef " + funcp->ifdef() + "\n"); if (cLinkage) puts("extern \"C\" "); @@ -129,7 +130,7 @@ void EmitCBaseVisitor::emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* if (!funcp->ifdef().empty()) puts("#endif // " + funcp->ifdef() + "\n"); } -void EmitCBaseVisitor::emitVarDecl(const AstVar* nodep, bool asRef) { +void EmitCBaseVisitorConst::emitVarDecl(const AstVar* nodep, bool asRef) { const AstBasicDType* const basicp = nodep->basicp(); bool refNeedParens = VN_IS(nodep->dtypeSkipRefp(), UnpackArrayDType); @@ -217,7 +218,7 @@ void EmitCBaseVisitor::emitVarDecl(const AstVar* nodep, bool asRef) { } } -void EmitCBaseVisitor::emitModCUse(const AstNodeModule* modp, VUseType useType) { +void EmitCBaseVisitorConst::emitModCUse(const AstNodeModule* modp, VUseType useType) { string nl; for (AstNode* itemp = modp->stmtsp(); itemp; itemp = itemp->nextp()) { if (AstCUse* const usep = VN_CAST(itemp, CUse)) { @@ -235,7 +236,7 @@ void EmitCBaseVisitor::emitModCUse(const AstNodeModule* modp, VUseType useType) puts(nl); } -void EmitCBaseVisitor::emitTextSection(const AstNodeModule* modp, VNType type) { +void EmitCBaseVisitorConst::emitTextSection(const AstNodeModule* modp, VNType type) { // Short circuit if nothing to do. This can save a lot of time on large designs as this // function needs to traverse the entire module linearly. if (!v3Global.hasSCTextSections()) return; diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index 523072e18..aef367177 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -77,7 +77,7 @@ public: } }; -class EmitCBaseVisitor VL_NOT_FINAL : public VNVisitor, public EmitCBase { +class EmitCBaseVisitorConst VL_NOT_FINAL : public VNVisitorConst, public EmitCBase { public: // STATE V3OutCFile* m_ofp = nullptr; @@ -115,8 +115,8 @@ public: void emitTextSection(const AstNodeModule* modp, VNType type); // CONSTRUCTORS - EmitCBaseVisitor() = default; - ~EmitCBaseVisitor() override = default; + EmitCBaseVisitorConst() = default; + ~EmitCBaseVisitorConst() override = default; }; #endif // guard diff --git a/src/V3EmitCConstInit.h b/src/V3EmitCConstInit.h index 9113348e5..22f8082a1 100644 --- a/src/V3EmitCConstInit.h +++ b/src/V3EmitCConstInit.h @@ -26,7 +26,7 @@ //###################################################################### // Emitter that can emit constant initializer expressions -class EmitCConstInit VL_NOT_FINAL : public EmitCBaseVisitor { +class EmitCConstInit VL_NOT_FINAL : public EmitCBaseVisitorConst { // MEMBERS uint32_t m_unpackedWord = 0; bool m_inUnpacked = false; @@ -64,7 +64,7 @@ protected: ofp()->printf("%" PRIx64 "ULL", itr.first); ofp()->putsNoTracking(":"); ofp()->putsNoTracking("{"); - iterate(nodep->getIndexValuep(itr.first)); + iterateConst(nodep->getIndexValuep(itr.first)); ofp()->putsNoTracking("}"); } puts("\n"); @@ -83,7 +83,7 @@ protected: for (uint64_t n = 0; n < size; ++n) { m_unpackedWord = n; if (n) puts((n % tabMod) ? ", " : ",\n"); - iterate(nodep->getIndexDefaultedValuep(n)); + iterateConst(nodep->getIndexDefaultedValuep(n)); } puts("\n"); puts("}"); diff --git a/src/V3EmitCConstPool.cpp b/src/V3EmitCConstPool.cpp index 6ba5c33bc..27503551c 100644 --- a/src/V3EmitCConstPool.cpp +++ b/src/V3EmitCConstPool.cpp @@ -87,7 +87,7 @@ class EmitCConstPool final : public EmitCConstInit { puts("extern const "); puts(varp->dtypep()->cType(nameProtect, false, false)); puts(" = "); - iterate(varp->valuep()); + iterateConst(varp->valuep()); puts(";\n"); // Keep track of stats if (VN_IS(varp->dtypep(), UnpackArrayDType)) { diff --git a/src/V3EmitCFunc.cpp b/src/V3EmitCFunc.cpp index 7f60b5371..498c46f1e 100644 --- a/src/V3EmitCFunc.cpp +++ b/src/V3EmitCFunc.cpp @@ -138,7 +138,7 @@ void EmitCFunc::emitOpName(AstNode* nodep, const string& format, AstNode* lhsp, case 'i': COMMA; UASSERT_OBJ(detailp, nodep, "emitOperator() references undef node"); - iterateAndNextNull(detailp); + iterateAndNextConstNull(detailp); needComma = true; break; default: @@ -174,7 +174,7 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) { if (const AstFScanF* const dispp = VN_CAST(nodep, FScanF)) { isStmt = false; puts("VL_FSCANF_IX("); - iterate(dispp->filep()); + iterateConst(dispp->filep()); puts(","); } else if (const AstSScanF* const dispp = VN_CAST(nodep, SScanF)) { isStmt = false; @@ -184,13 +184,13 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) { puts("X("); puts(cvtToStr(dispp->fromp()->widthMin())); puts(","); - iterate(dispp->fromp()); + iterateConst(dispp->fromp()); puts(","); } else if (const AstDisplay* const dispp = VN_CAST(nodep, Display)) { isStmt = true; if (dispp->filep()) { puts("VL_FWRITEF("); - iterate(dispp->filep()); + iterateConst(dispp->filep()); puts(","); } else { puts("VL_WRITEF("); @@ -200,7 +200,7 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) { puts("VL_SFORMAT_X("); puts(cvtToStr(dispp->lhsp()->widthMin())); putbs(","); - iterate(dispp->lhsp()); + iterateConst(dispp->lhsp()); putbs(","); } else if (VN_IS(nodep, SFormatF)) { isStmt = false; @@ -223,7 +223,7 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) { } else if (argp) { const bool addrof = isScan || (fmt == '@'); if (addrof) puts("&("); - iterate(argp); + iterateConst(argp); if (!addrof) emitDatap(argp); if (addrof) puts(")"); } @@ -452,16 +452,16 @@ void EmitCFunc::emitCvtPackStr(AstNode* nodep) { puts(cvtToStr(nodep->widthWords())); puts(", "); } - iterateAndNextNull(nodep); + iterateAndNextConstNull(nodep); puts(")"); } } void EmitCFunc::emitCvtWideArray(AstNode* nodep, AstNode* fromp) { putbs("VL_CVT_W_A("); - iterate(nodep); + iterateConst(nodep); puts(", "); - iterate(fromp); + iterateConst(fromp); putbs(".atDefault()"); // Not accessed; only to get the proper type of values puts(")"); } diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 7ea87dac3..432f2368b 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -40,7 +40,7 @@ class EmitCLazyDecls final : public VNVisitorConst { // MEMBERS std::unordered_set m_emittedManually; // Set of names already declared manually. - EmitCBaseVisitor& m_emitter; // For access to file output + EmitCBaseVisitorConst& m_emitter; // For access to file output bool m_needsBlankLine = false; // Emit blank line if any declarations were emitted (cosmetic) std::set m_emitted; // -> in set. Already emitted decl for symbols. @@ -91,7 +91,7 @@ class EmitCLazyDecls final : public VNVisitorConst { void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } public: - explicit EmitCLazyDecls(EmitCBaseVisitor& emitter) + explicit EmitCLazyDecls(EmitCBaseVisitorConst& emitter) : m_emitter(emitter) {} void emit(AstNode* nodep) { m_needsBlankLine = false; @@ -203,12 +203,12 @@ public: // variables. That way we could just invoke the appropriate emitter as needed. VL_RESTORER(m_emitConstInit); m_emitConstInit = true; - iterate(initp); + iterateConst(initp); } void putCommaIterateNext(AstNode* nodep, bool comma = false) { for (AstNode* subnodep = nodep; subnodep; subnodep = subnodep->nextp()) { if (comma) puts(", "); - iterate(subnodep); + iterateConst(subnodep); comma = true; } } @@ -273,17 +273,17 @@ public: if (nodep->initsp()) { putsDecoration("// Init\n"); - iterateAndNextNull(nodep->initsp()); + iterateAndNextConstNull(nodep->initsp()); } if (nodep->stmtsp()) { putsDecoration("// Body\n"); - iterateAndNextNull(nodep->stmtsp()); + iterateAndNextConstNull(nodep->stmtsp()); } if (nodep->finalsp()) { putsDecoration("// Final\n"); - iterateAndNextNull(nodep->finalsp()); + iterateAndNextConstNull(nodep->finalsp()); } puts("}\n"); @@ -309,9 +309,9 @@ public: } else { puts("I("); } - iterateAndNextNull(selp->lsbp()); + iterateAndNextConstNull(selp->lsbp()); puts(", "); - iterateAndNextNull(selp->fromp()); + iterateAndNextConstNull(selp->fromp()); if (rhs) puts(", "); } else { putbs("VL_ASSIGNSEL_"); @@ -320,18 +320,18 @@ public: puts("("); puts(cvtToStr(selp->fromp()->widthMin()) + ","); puts(cvtToStr(nodep->widthMin()) + ","); - iterateAndNextNull(selp->lsbp()); + iterateAndNextConstNull(selp->lsbp()); puts(", "); - iterateAndNextNull(selp->fromp()); + iterateAndNextConstNull(selp->fromp()); puts(", "); } } else if (const AstGetcRefN* const selp = VN_CAST(nodep->lhsp(), GetcRefN)) { - iterateAndNextNull(selp->lhsp()); + iterateAndNextConstNull(selp->lhsp()); puts(" = "); putbs("VL_PUTC_N("); - iterateAndNextNull(selp->lhsp()); + iterateAndNextConstNull(selp->lhsp()); puts(", "); - iterateAndNextNull(selp->rhsp()); + iterateAndNextConstNull(selp->rhsp()); puts(", "); } else if (AstVar* const varp = AstVar::scVarRecurse(nodep->lhsp())) { putbs("VL_ASSIGN_"); // Set a systemC variable @@ -339,7 +339,7 @@ public: emitIQW(nodep); puts("("); puts(cvtToStr(nodep->widthMin()) + ","); - iterateAndNextNull(nodep->lhsp()); + iterateAndNextConstNull(nodep->lhsp()); puts(", "); } else if (AstVar* const varp = AstVar::scVarRecurse(nodep->rhsp())) { putbs("VL_ASSIGN_"); // Get a systemC variable @@ -347,7 +347,7 @@ public: emitScIQW(varp); puts("("); puts(cvtToStr(nodep->widthMin()) + ","); - iterateAndNextNull(nodep->lhsp()); + iterateAndNextConstNull(nodep->lhsp()); puts(", "); } else if (nodep->isWide() && VN_IS(nodep->lhsp(), VarRef) // && !VN_IS(nodep->rhsp(), CExpr) // @@ -361,41 +361,41 @@ public: } else if (nodep->isWide() && !VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType)) { putbs("VL_ASSIGN_W("); puts(cvtToStr(nodep->widthMin()) + ","); - iterateAndNextNull(nodep->lhsp()); + iterateAndNextConstNull(nodep->lhsp()); puts(", "); } else { paren = false; - iterateAndNextNull(nodep->lhsp()); + iterateAndNextConstNull(nodep->lhsp()); puts(" "); ofp()->blockInc(); decind = true; if (!VN_IS(nodep->rhsp(), Const)) ofp()->putBreak(); puts("= "); } - if (rhs) iterateAndNextNull(nodep->rhsp()); + if (rhs) iterateAndNextConstNull(nodep->rhsp()); if (paren) puts(")"); if (decind) ofp()->blockDec(); puts(";\n"); } void visit(AstAlwaysPublic*) override {} void visit(AstAssocSel* nodep) override { - iterateAndNextNull(nodep->fromp()); + iterateAndNextConstNull(nodep->fromp()); putbs(".at("); AstAssocArrayDType* const adtypep = VN_AS(nodep->fromp()->dtypep(), AssocArrayDType); UASSERT_OBJ(adtypep, nodep, "Associative select on non-associative type"); if (adtypep->keyDTypep()->isWide()) { emitCvtWideArray(nodep->bitp(), nodep->fromp()); } else { - iterateAndNextNull(nodep->bitp()); + iterateAndNextConstNull(nodep->bitp()); } puts(")"); } void visit(AstWildcardSel* nodep) override { - iterateAndNextNull(nodep->fromp()); + iterateAndNextConstNull(nodep->fromp()); putbs(".at("); AstWildcardArrayDType* const adtypep = VN_AS(nodep->fromp()->dtypep(), WildcardArrayDType); UASSERT_OBJ(adtypep, nodep, "Wildcard select on non-wildcard-associative type"); - iterateAndNextNull(nodep->bitp()); + iterateAndNextConstNull(nodep->bitp()); puts(")"); } void visit(AstCCall* nodep) override { @@ -427,14 +427,14 @@ public: void visit(AstCMethodCall* nodep) override { const AstCFunc* const funcp = nodep->funcp(); UASSERT_OBJ(!funcp->isLoose(), nodep, "Loose method called via AstCMethodCall"); - iterate(nodep->fromp()); + iterateConst(nodep->fromp()); putbs("->"); puts(funcp->nameProtect()); emitCCallArgs(nodep, ""); } void visit(AstCAwait* nodep) override { puts("co_await "); - iterate(nodep->exprp()); + iterateConst(nodep->exprp()); } void visit(AstCNew* nodep) override { if (VN_IS(nodep->dtypep(), VoidDType)) { @@ -447,7 +447,7 @@ public: puts(")"); } void visit(AstCMethodHard* nodep) override { - iterate(nodep->fromp()); + iterateConst(nodep->fromp()); puts("."); puts(nodep->name()); puts("("); @@ -458,7 +458,7 @@ public: if (VN_IS(nodep->fromp()->dtypep(), QueueDType) && subnodep->dtypep()->isWide()) { emitCvtWideArray(subnodep, nodep->fromp()); } else { - iterate(subnodep); + iterateConst(subnodep); } comma = true; } @@ -477,7 +477,7 @@ public: } // Probably fragile, V3Task may need to convert to a AstCReturn puts(") { return "); - iterateAndNextNull(nodep->exprp()); + iterateAndNextConstNull(nodep->exprp()); puts("; }\n"); } void visit(AstNodeCase* nodep) override { // LCOV_EXCL_LINE @@ -494,7 +494,7 @@ public: if (!(nodep->protect() && v3Global.opt.protectIds())) { putsDecoration(string("// ") + nodep->name() + at + "\n"); } - iterateChildren(nodep); + iterateChildrenConst(nodep); } void visit(AstCoverDecl* nodep) override { puts("vlSelf->__vlCoverInsert("); // As Declared in emitCoverageDecl @@ -537,7 +537,7 @@ public: } void visit(AstCReturn* nodep) override { puts("return ("); - iterateAndNextNull(nodep->lhsp()); + iterateAndNextConstNull(nodep->lhsp()); puts(");\n"); } void visit(AstDisplay* nodep) override { @@ -615,7 +615,7 @@ public: emitCvtPackStr(nodep->searchp()); puts(", "); putbs(""); - iterateAndNextNull(nodep->outp()); + iterateAndNextConstNull(nodep->outp()); puts(")"); } void visit(AstTestPlusArgs* nodep) override { @@ -626,13 +626,13 @@ public: void visit(AstFError* nodep) override { puts("VL_FERROR_I"); puts(nodep->strp()->isString() ? "N(" : "W("); - iterateAndNextNull(nodep->filep()); + iterateAndNextConstNull(nodep->filep()); putbs(", "); if (nodep->strp()->isWide()) { puts(cvtToStr(nodep->strp()->widthWords())); putbs(", "); } - iterateAndNextNull(nodep->strp()); + iterateAndNextConstNull(nodep->strp()); puts(")"); } void visit(AstFGetS* nodep) override { @@ -694,18 +694,18 @@ public: { const bool need_ptr = !VN_IS(nodep->memp()->dtypep(), AssocArrayDType); if (need_ptr) puts(" &("); - iterateAndNextNull(nodep->memp()); + iterateAndNextConstNull(nodep->memp()); if (need_ptr) puts(")"); } putbs(", "); if (nodep->lsbp()) { - iterateAndNextNull(nodep->lsbp()); + iterateAndNextConstNull(nodep->lsbp()); } else { puts(cvtToStr(array_lo)); } putbs(", "); if (nodep->msbp()) { - iterateAndNextNull(nodep->msbp()); + iterateAndNextConstNull(nodep->msbp()); } else { puts("~0ULL"); } @@ -713,7 +713,7 @@ public: } void visit(AstFClose* nodep) override { puts("VL_FCLOSE_I("); - iterateAndNextNull(nodep->filep()); + iterateAndNextConstNull(nodep->filep()); puts("); "); } void visit(AstFFlush* nodep) override { @@ -721,29 +721,29 @@ public: puts("Verilated::runFlushCallbacks();\n"); } else { puts("if ("); - iterateAndNextNull(nodep->filep()); + iterateAndNextConstNull(nodep->filep()); puts(") { VL_FFLUSH_I("); - iterateAndNextNull(nodep->filep()); + iterateAndNextConstNull(nodep->filep()); puts("); }\n"); } } void visit(AstFSeek* nodep) override { puts("(VL_FSEEK_I("); - iterateAndNextNull(nodep->filep()); + iterateAndNextConstNull(nodep->filep()); puts(","); - iterateAndNextNull(nodep->offset()); + iterateAndNextConstNull(nodep->offset()); puts(","); - iterateAndNextNull(nodep->operation()); + iterateAndNextConstNull(nodep->operation()); puts(") == -1 ? -1 : 0)"); } void visit(AstFTell* nodep) override { puts("VL_FTELL_I("); - iterateAndNextNull(nodep->filep()); + iterateAndNextConstNull(nodep->filep()); puts(")"); } void visit(AstFRewind* nodep) override { puts("(VL_FSEEK_I("); - iterateAndNextNull(nodep->filep()); + iterateAndNextConstNull(nodep->filep()); puts(", 0, 0) == -1 ? -1 : 0)"); } void visit(AstFRead* nodep) override { @@ -771,19 +771,19 @@ public: puts(cvtToStr(array_size)); putbs(", "); puts("&("); - iterateAndNextNull(nodep->memp()); + iterateAndNextConstNull(nodep->memp()); puts(")"); putbs(", "); - iterateAndNextNull(nodep->filep()); + iterateAndNextConstNull(nodep->filep()); putbs(", "); if (nodep->startp()) { - iterateAndNextNull(nodep->startp()); + iterateAndNextConstNull(nodep->startp()); } else { puts(cvtToStr(array_lo)); } putbs(", "); if (nodep->countp()) { - iterateAndNextNull(nodep->countp()); + iterateAndNextConstNull(nodep->countp()); } else { puts(cvtToStr(array_size)); } @@ -791,7 +791,7 @@ public: } void visit(AstSysFuncAsTask* nodep) override { if (!nodep->lhsp()->isWide()) puts("(void)"); - iterateAndNextNull(nodep->lhsp()); + iterateAndNextConstNull(nodep->lhsp()); if (!nodep->lhsp()->isWide()) puts(";"); } void visit(AstStackTraceF* nodep) override { puts("VL_STACKTRACE_N()"); } @@ -805,7 +805,7 @@ public: putbs(", "); } checkMaxWords(nodep->lhsp()); - iterateAndNextNull(nodep->lhsp()); + iterateAndNextConstNull(nodep->lhsp()); puts(");\n"); } void visit(AstSystemF* nodep) override { @@ -817,18 +817,18 @@ public: putbs(", "); } checkMaxWords(nodep->lhsp()); - iterateAndNextNull(nodep->lhsp()); + iterateAndNextConstNull(nodep->lhsp()); puts(")"); } void visit(AstStmtExpr* node) override { - iterate(node->exprp()); + iterateConst(node->exprp()); puts(";\n"); } void visit(AstJumpBlock* nodep) override { nodep->labelNum(++m_labelNum); puts("{\n"); // Make it visually obvious label jumps outside these - iterateAndNextNull(nodep->stmtsp()); - iterateAndNextNull(nodep->endStmtsp()); + iterateAndNextConstNull(nodep->stmtsp()); + iterateAndNextConstNull(nodep->endStmtsp()); puts("}\n"); } void visit(AstJumpGo* nodep) override { @@ -838,13 +838,13 @@ public: puts("__Vlabel" + cvtToStr(nodep->blockp()->labelNum()) + ": ;\n"); } void visit(AstWhile* nodep) override { - iterateAndNextNull(nodep->precondsp()); + iterateAndNextConstNull(nodep->precondsp()); puts("while ("); - iterateAndNextNull(nodep->condp()); + iterateAndNextConstNull(nodep->condp()); puts(") {\n"); - iterateAndNextNull(nodep->stmtsp()); - iterateAndNextNull(nodep->incsp()); - iterateAndNextNull(nodep->precondsp()); // Need to recompute before next loop + iterateAndNextConstNull(nodep->stmtsp()); + iterateAndNextConstNull(nodep->incsp()); + iterateAndNextConstNull(nodep->precondsp()); // Need to recompute before next loop puts("}\n"); } void visit(AstNodeIf* nodep) override { @@ -853,20 +853,20 @@ public: puts(nodep->branchPred().ascii()); puts("("); } - iterateAndNextNull(nodep->condp()); + iterateAndNextConstNull(nodep->condp()); if (!nodep->branchPred().unknown()) puts(")"); puts(") {\n"); - iterateAndNextNull(nodep->thensp()); + iterateAndNextConstNull(nodep->thensp()); puts("}"); if (!nodep->elsesp()) { puts("\n"); } else { if (VN_IS(nodep->elsesp(), NodeIf) && !nodep->elsesp()->nextp()) { puts(" else "); - iterateAndNextNull(nodep->elsesp()); + iterateAndNextConstNull(nodep->elsesp()); } else { puts(" else {\n"); - iterateAndNextNull(nodep->elsesp()); + iterateAndNextConstNull(nodep->elsesp()); puts("}\n"); } } @@ -875,9 +875,9 @@ public: // GCC allows compound statements in expressions, but this is not standard. // So we use an immediate-evaluation lambda and comma operator putbs("([&]() {\n"); - iterateAndNextNull(nodep->stmtsp()); + iterateAndNextConstNull(nodep->stmtsp()); puts("}(), "); - iterateAndNextNull(nodep->resultp()); + iterateAndNextConstNull(nodep->resultp()); puts(")"); } void visit(AstStop* nodep) override { @@ -921,13 +921,13 @@ public: } void visit(AstTimeFormat* nodep) override { puts("VL_TIMEFORMAT_IINI("); - iterateAndNextNull(nodep->unitsp()); + iterateAndNextConstNull(nodep->unitsp()); puts(", "); - iterateAndNextNull(nodep->precisionp()); + iterateAndNextConstNull(nodep->precisionp()); puts(", "); emitCvtPackStr(nodep->suffixp()); puts(", "); - iterateAndNextNull(nodep->widthp()); + iterateAndNextConstNull(nodep->widthp()); puts(", vlSymsp->_vm_contextp__);\n"); } void visit(AstTimePrecision* nodep) override { @@ -946,23 +946,23 @@ public: void visit(AstTextBlock* nodep) override { visit(static_cast(nodep)); for (AstNode* childp = nodep->nodesp(); childp; childp = childp->nextp()) { - iterate(childp); + iterateConst(childp); if (nodep->commas() && childp->nextp()) puts(", "); } } void visit(AstCStmt* nodep) override { putbs(""); - iterateAndNextNull(nodep->exprsp()); + iterateAndNextConstNull(nodep->exprsp()); } void visit(AstCExpr* nodep) override { putbs(""); - iterateAndNextNull(nodep->exprsp()); + iterateAndNextConstNull(nodep->exprsp()); } void visit(AstUCStmt* nodep) override { VL_RESTORER(m_inUC); m_inUC = true; putsDecoration(ifNoProtect("// $c statement at " + nodep->fileline()->ascii() + "\n")); - iterateAndNextNull(nodep->exprsp()); + iterateAndNextConstNull(nodep->exprsp()); puts("\n"); } void visit(AstUCFunc* nodep) override { @@ -970,7 +970,7 @@ public: m_inUC = true; puts("\n"); putsDecoration(ifNoProtect("// $c function at " + nodep->fileline()->ascii() + "\n")); - iterateAndNextNull(nodep->exprsp()); + iterateAndNextConstNull(nodep->exprsp()); puts("\n"); } @@ -992,7 +992,7 @@ public: putbs("("); puts(nodep->emitSimpleOperator()); puts(" "); - iterateAndNextNull(nodep->lhsp()); + iterateAndNextConstNull(nodep->lhsp()); puts(")"); } else { emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nullptr, nullptr); @@ -1008,11 +1008,11 @@ public: } if (emitSimpleOk(nodep)) { putbs("("); - iterateAndNextNull(nodep->lhsp()); + iterateAndNextConstNull(nodep->lhsp()); puts(" "); putbs(nodep->emitSimpleOperator()); puts(" "); - iterateAndNextNull(nodep->rhsp()); + iterateAndNextConstNull(nodep->rhsp()); puts(")"); } else { emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), nullptr); @@ -1034,7 +1034,7 @@ public: putbs("VL_REDXOR_"); puts(cvtToStr(widthPow2)); puts("("); - iterateAndNextNull(nodep->lhsp()); + iterateAndNextConstNull(nodep->lhsp()); puts(")"); } } @@ -1045,7 +1045,7 @@ public: } else { puts("(QData)("); } - iterateAndNextNull(nodep->lhsp()); + iterateAndNextConstNull(nodep->lhsp()); puts(")"); } void visit(AstNodeCond* nodep) override { @@ -1054,27 +1054,27 @@ public: emitOpName(nodep, nodep->emitC(), nodep->condp(), nodep->thenp(), nodep->elsep()); } else { putbs("("); - iterateAndNextNull(nodep->condp()); + iterateAndNextConstNull(nodep->condp()); putbs(" ? "); - iterateAndNextNull(nodep->thenp()); + iterateAndNextConstNull(nodep->thenp()); putbs(" : "); - iterateAndNextNull(nodep->elsep()); + iterateAndNextConstNull(nodep->elsep()); puts(")"); } } void visit(AstMemberSel* nodep) override { - iterateAndNextNull(nodep->fromp()); + iterateAndNextConstNull(nodep->fromp()); putbs("->"); puts(nodep->varp()->nameProtect()); } void visit(AstStructSel* nodep) override { - iterateAndNextNull(nodep->fromp()); + iterateAndNextConstNull(nodep->fromp()); putbs("."); puts(nodep->nameProtect()); } void visit(AstNullCheck* nodep) override { puts("VL_NULL_CHECK("); - iterateAndNextNull(nodep->lhsp()); + iterateAndNextConstNull(nodep->lhsp()); puts(", "); putsQuoted(protect(nodep->fileline()->filename())); puts(", "); @@ -1084,7 +1084,7 @@ public: void visit(AstNewCopy* nodep) override { puts("VL_NEW(" + prefixNameProtect(nodep->dtypep()) + ", "); puts("*"); // i.e. make into a reference - iterateAndNextNull(nodep->rhsp()); + iterateAndNextConstNull(nodep->rhsp()); puts(")"); } void visit(AstSel* nodep) override { @@ -1102,9 +1102,9 @@ public: puts("OI("); if (nodep->lhsp()) puts(cvtToStr(nodep->lhsp()->widthMin())); puts(","); - iterateAndNextNull(nodep->lhsp()); + iterateAndNextConstNull(nodep->lhsp()); puts(", "); - iterateAndNextNull(nodep->rhsp()); + iterateAndNextConstNull(nodep->rhsp()); puts(")"); } else { emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), nullptr); @@ -1122,7 +1122,7 @@ public: puts("I("); puts(cvtToStr(nodep->lhsp()->widthMin())); puts(", "); - iterateAndNextNull(nodep->lhsp()); + iterateAndNextConstNull(nodep->lhsp()); puts(", "); const uint32_t rd_log2 = V3Number::log2b(VN_AS(nodep->rhsp(), Const)->toUInt()); puts(cvtToStr(rd_log2) + ")"); @@ -1134,9 +1134,9 @@ public: } void visit(AstCastDynamic* nodep) override { putbs("VL_CAST_DYNAMIC("); - iterateAndNextNull(nodep->lhsp()); + iterateAndNextConstNull(nodep->lhsp()); puts(", "); - iterateAndNextNull(nodep->rhsp()); + iterateAndNextConstNull(nodep->rhsp()); puts(")"); } void visit(AstCountBits* nodep) override { @@ -1150,16 +1150,16 @@ public: // (which is always 32) puts(", "); } - iterateAndNextNull(nodep->lhsp()); + iterateAndNextConstNull(nodep->lhsp()); puts(", "); - iterateAndNextNull(nodep->rhsp()); + iterateAndNextConstNull(nodep->rhsp()); puts(", "); - iterateAndNextNull(nodep->thsp()); + iterateAndNextConstNull(nodep->thsp()); puts(", "); - iterateAndNextNull(nodep->fhsp()); + iterateAndNextConstNull(nodep->fhsp()); puts(")"); } - void visit(AstInitItem* nodep) override { iterateChildren(nodep); } + void visit(AstInitItem* nodep) override { iterateChildrenConst(nodep); } // Terminals void visit(AstVarRef* nodep) override { const AstVar* const varp = nodep->varp(); @@ -1217,17 +1217,17 @@ public: puts("()"); if (nodep->defaultp()) { putbs(".setDefault("); - iterateAndNextNull(nodep->defaultp()); + iterateAndNextConstNull(nodep->defaultp()); puts(")"); } } void visit(AstSetAssoc* nodep) override { - iterateAndNextNull(nodep->lhsp()); + iterateAndNextConstNull(nodep->lhsp()); putbs(".set("); - iterateAndNextNull(nodep->keyp()); + iterateAndNextConstNull(nodep->keyp()); puts(", "); putbs(""); - iterateAndNextNull(nodep->valuep()); + iterateAndNextConstNull(nodep->valuep()); puts(")"); } void visit(AstConsWildcard* nodep) override { @@ -1235,17 +1235,17 @@ public: puts("()"); if (nodep->defaultp()) { putbs(".setDefault("); - iterateAndNextNull(nodep->defaultp()); + iterateAndNextConstNull(nodep->defaultp()); puts(")"); } } void visit(AstSetWildcard* nodep) override { - iterateAndNextNull(nodep->lhsp()); + iterateAndNextConstNull(nodep->lhsp()); putbs(".set("); - iterateAndNextNull(nodep->keyp()); + iterateAndNextConstNull(nodep->keyp()); puts(", "); putbs(""); - iterateAndNextNull(nodep->valuep()); + iterateAndNextConstNull(nodep->valuep()); puts(")"); } void visit(AstConsDynArray* nodep) override { @@ -1254,12 +1254,12 @@ public: puts("()"); } else { puts("::cons("); - iterateAndNextNull(nodep->lhsp()); + iterateAndNextConstNull(nodep->lhsp()); if (nodep->rhsp()) { puts(", "); putbs(""); } - iterateAndNextNull(nodep->rhsp()); + iterateAndNextConstNull(nodep->rhsp()); puts(")"); } } @@ -1267,7 +1267,7 @@ public: putbs(nodep->dtypep()->cType("", false, false)); puts("{"); for (AstNode* memberp = nodep->membersp(); memberp; memberp = memberp->nextp()) { - iterate(memberp); + iterateConst(memberp); if (memberp->nextp()) { puts(", "); } } puts("}"); @@ -1277,7 +1277,7 @@ public: putbs("."); puts(vdtypep->name()); puts(" = "); - iterate(nodep->rhsp()); + iterateConst(nodep->rhsp()); } void visit(AstConsQueue* nodep) override { putbs(nodep->dtypep()->cType("", false, false)); @@ -1285,12 +1285,12 @@ public: puts("()"); } else { puts("::cons("); - iterateAndNextNull(nodep->lhsp()); + iterateAndNextConstNull(nodep->lhsp()); if (nodep->rhsp()) { puts(", "); putbs(""); } - iterateAndNextNull(nodep->rhsp()); + iterateAndNextConstNull(nodep->rhsp()); puts(")"); } } @@ -1308,7 +1308,7 @@ public: // Default void visit(AstNode* nodep) override { puts(string("\n???? // ") + nodep->prettyTypeName() + "\n"); - iterateChildren(nodep); + iterateChildrenConst(nodep); // LCOV_EXCL_START if (!v3Global.opt.lintOnly()) { // An internal problem, so suppress nodep->v3fatalSrc("Unknown node type reached emitter: " << nodep->prettyTypeName()); @@ -1322,7 +1322,7 @@ public: : EmitCFunc{} { m_ofp = ofp; m_trackText = trackText; - iterate(nodep); + iterateConst(nodep); } ~EmitCFunc() override = default; }; diff --git a/src/V3EmitCHeaders.cpp b/src/V3EmitCHeaders.cpp index 986ae5a08..bf11c92f3 100644 --- a/src/V3EmitCHeaders.cpp +++ b/src/V3EmitCHeaders.cpp @@ -136,7 +136,7 @@ class EmitCHeader final : public EmitCConstInit { puts(varp->dtypep()->cType(varp->nameProtect(), false, false)); if (canBeConstexpr) { puts(" = "); - iterate(varp->valuep()); + iterateConst(varp->valuep()); } puts(";\n"); } @@ -200,7 +200,7 @@ class EmitCHeader final : public EmitCConstInit { } puts(itemp->nameProtect()); puts(" = "); - iterate(itemp->valuep()); + iterateConst(itemp->valuep()); if (VN_IS(itemp->nextp(), EnumItem)) puts(","); puts("\n"); } diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index 33a2d3a89..d231d7058 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -262,7 +262,7 @@ class EmitCImp final : EmitCFunc { puts(", "); puts(varp->nameProtect()); puts("("); - iterate(varp->valuep()); + iterateConst(varp->valuep()); puts(")\n"); } else if (varp->isIO() && varp->isSc()) { puts(", "); @@ -522,7 +522,7 @@ class EmitCImp final : EmitCFunc { for (AstCFunc* const funcp : pair.second) { VL_RESTORER(m_modp); m_modp = EmitCParentModule::get(funcp); - iterate(funcp); + iterateConst(funcp); } // Close output file VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); @@ -774,7 +774,7 @@ class EmitCTrace final : EmitCFunc { } void emitTraceChangeOne(AstTraceInc* nodep, int arrayindex) { - iterateAndNextNull(nodep->precondsp()); + iterateAndNextConstNull(nodep->precondsp()); const string func = nodep->full() ? "full" : "chg"; bool emitWidth = true; if (nodep->dtypep()->basicp()->isDouble()) { @@ -817,7 +817,7 @@ class EmitCTrace final : EmitCFunc { } else if (emitTraceIsScBv(nodep)) { puts("VL_SC_BV_DATAP("); } - iterate(varrefp); // Put var name out + iterateConst(varrefp); // Put var name out // Tracing only supports 1D arrays if (nodep->declp()->arrayRange().ranged()) { if (arrayindex == -2) { @@ -839,7 +839,7 @@ class EmitCTrace final : EmitCFunc { puts(")"); } else { puts("("); - iterate(nodep->valuep()); + iterateConst(nodep->valuep()); puts(")"); } } @@ -901,7 +901,7 @@ class EmitCTrace final : EmitCFunc { openNextOutputFile(); // Emit functions for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { - if (AstCFunc* const funcp = VN_CAST(nodep, CFunc)) { iterate(funcp); } + if (AstCFunc* const funcp = VN_CAST(nodep, CFunc)) { iterateConst(funcp); } } // Close output file VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); diff --git a/src/V3EmitCInlines.cpp b/src/V3EmitCInlines.cpp index 338b956ec..86da5ff14 100644 --- a/src/V3EmitCInlines.cpp +++ b/src/V3EmitCInlines.cpp @@ -28,7 +28,7 @@ VL_DEFINE_DEBUG_FUNCTIONS; //###################################################################### -class EmitCInlines final : EmitCBaseVisitor { +class EmitCInlines final : EmitCBaseVisitorConst { // STATE // METHODS @@ -37,26 +37,26 @@ class EmitCInlines final : EmitCBaseVisitor { void visit(AstCNew* nodep) override { if (v3Global.opt.savable()) v3warn(E_UNSUPPORTED, "Unsupported: --savable with dynamic new"); - iterateChildren(nodep); + iterateChildrenConst(nodep); } void visit(AstDumpCtl* nodep) override { if (v3Global.opt.trace()) v3Global.needTraceDumper(true); - iterateChildren(nodep); + iterateChildrenConst(nodep); } void visit(AstNodeDistBiop* nodep) override { v3Global.setUsesProbDist(); - iterateChildren(nodep); + iterateChildrenConst(nodep); } void visit(AstNodeDistTriop* nodep) override { v3Global.setUsesProbDist(); - iterateChildren(nodep); + iterateChildrenConst(nodep); } //--------------------------------------- - void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } public: - explicit EmitCInlines(AstNetlist* nodep) { iterate(nodep); } + explicit EmitCInlines(AstNetlist* nodep) { iterateConst(nodep); } }; //###################################################################### @@ -64,5 +64,5 @@ public: void V3EmitC::emitcInlines() { UINFO(2, __FUNCTION__ << ": " << endl); - EmitCInlines(v3Global.rootp()); + { EmitCInlines visitor{v3Global.rootp()}; } } diff --git a/src/V3EmitCMain.cpp b/src/V3EmitCMain.cpp index 352e15603..10216025b 100644 --- a/src/V3EmitCMain.cpp +++ b/src/V3EmitCMain.cpp @@ -29,12 +29,12 @@ VL_DEFINE_DEBUG_FUNCTIONS; //###################################################################### -class EmitCMain final : EmitCBaseVisitor { +class EmitCMain final : EmitCBaseVisitorConst { // METHODS // VISITORS // This visitor doesn't really iterate, but exist to appease base class - void visit(AstNode* nodep) override { iterateChildren(nodep); } // LCOV_EXCL_LINE + void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } // LCOV_EXCL_LINE public: // CONSTRUCTORS diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp index 94567f1a8..e7debc3cd 100644 --- a/src/V3EmitCModel.cpp +++ b/src/V3EmitCModel.cpp @@ -658,7 +658,7 @@ class EmitCModel final : public EmitCFunc { puts("\n"); } - iterate(funcp); + iterateConst(funcp); } if (m_ofp) { VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); } diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 2ae694b48..d9d865324 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -32,7 +32,7 @@ VL_DEFINE_DEBUG_FUNCTIONS; //###################################################################### // Symbol table emitting -class EmitCSyms final : EmitCBaseVisitor { +class EmitCSyms final : EmitCBaseVisitorConst { // NODE STATE // Cleared on Netlist // AstNodeModule::user1() -> bool. Set true __Vconfigure called @@ -278,7 +278,7 @@ class EmitCSyms final : EmitCBaseVisitor { // VISITORS void visit(AstNetlist* nodep) override { // Collect list of scopes - iterateChildren(nodep); + iterateChildrenConst(nodep); varsExpand(); if (v3Global.opt.vpi()) buildVpiHierarchy(); @@ -304,7 +304,7 @@ class EmitCSyms final : EmitCBaseVisitor { VL_RESTORER(m_modp); { m_modp = nodep; - iterateChildren(nodep); + iterateChildrenConst(nodep); } } void visit(AstCellInline* nodep) override { @@ -356,7 +356,7 @@ class EmitCSyms final : EmitCBaseVisitor { } void visit(AstVar* nodep) override { nameCheck(nodep); - iterateChildren(nodep); + iterateChildrenConst(nodep); if (nodep->isSigUserRdPublic() && !m_cfuncp) m_modVars.emplace_back(std::make_pair(m_modp, nodep)); } @@ -372,18 +372,18 @@ class EmitCSyms final : EmitCBaseVisitor { VL_RESTORER(m_cfuncp); { m_cfuncp = nodep; - iterateChildren(nodep); + iterateChildrenConst(nodep); } } //--------------------------------------- void visit(AstConst*) override {} - void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } public: explicit EmitCSyms(AstNetlist* nodep, bool dpiHdrOnly) : m_dpiHdrOnly{dpiHdrOnly} { - iterate(nodep); + iterateConst(nodep); } }; diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index 61be14c49..67c0a274a 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -31,7 +31,7 @@ VL_DEFINE_DEBUG_FUNCTIONS; // ###################################################################### // Emit statements and expressions -class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { +class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst { // MEMBERS bool m_suppressSemi = false; const bool m_suppressUnknown = false; @@ -166,7 +166,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { // AstSenItem is called for dumping in isolation by V3Order putfs(nodep, "@("); for (AstNode* expp = nodep->sensesp(); expp; expp = expp->nextp()) { - iterate(expp); + iterateConst(expp); if (expp->nextp()) putqs(expp->nextp(), " or "); } puts(")"); @@ -382,7 +382,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { void visit(AstStop* nodep) override { putfs(nodep, "$stop;\n"); } void visit(AstFinish* nodep) override { putfs(nodep, "$finish;\n"); } void visit(AstStmtExpr* nodep) override { - iterate(nodep->exprp()); + iterateConst(nodep->exprp()); puts(";\n"); } void visit(AstNodeSimpleText* nodep) override { @@ -398,7 +398,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { VL_RESTORER(m_suppressSemi); m_suppressVarSemi = nodep->commas(); for (AstNode* childp = nodep->nodesp(); childp; childp = childp->nextp()) { - iterate(childp); + iterateConst(childp); if (nodep->commas() && childp->nextp()) puts(", "); } } @@ -426,11 +426,11 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { } void visit(AstCMethodHard* nodep) override { - iterate(nodep->fromp()); + iterateConst(nodep->fromp()); puts("." + nodep->name() + "("); for (AstNode* pinp = nodep->pinsp(); pinp; pinp = pinp->nextp()) { if (pinp != nodep->pinsp()) puts(", "); - iterate(pinp); + iterateConst(pinp); } puts(")"); } @@ -506,12 +506,12 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { nodep->thsp()); } void visit(AstMemberSel* nodep) override { - iterate(nodep->fromp()); + iterateConst(nodep->fromp()); puts("."); puts(nodep->prettyName()); } void visit(AstStructSel* nodep) override { - iterate(nodep->fromp()); + iterateConst(nodep->fromp()); puts("."); puts(nodep->prettyName()); } @@ -533,7 +533,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { puts(cvtToStr(itr.first)); puts(":"); AstNode* const valuep = itr.second->valuep(); - iterate(valuep); + iterateConst(valuep); } puts("}"); } @@ -613,13 +613,13 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { } void visit(AstConstDType* nodep) override { putfs(nodep, "const "); - iterate(nodep->subDTypep()); + iterateConst(nodep->subDTypep()); } void visit(AstNodeArrayDType* nodep) override { - iterate(nodep->subDTypep()); + iterateConst(nodep->subDTypep()); iterateAndNextConstNull(nodep->rangep()); } - void visit(AstRefDType* nodep) override { iterate(nodep->skipRefp()); } + void visit(AstRefDType* nodep) override { iterateConst(nodep->skipRefp()); } void visit(AstNodeUOrStructDType* nodep) override { puts(nodep->verilogKwd() + " "); if (nodep->packed()) puts("packed "); @@ -627,13 +627,13 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { puts("{"); for (AstMemberDType* itemp = nodep->membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) { - iterate(itemp); + iterateConst(itemp); puts(";"); } puts("}"); } void visit(AstMemberDType* nodep) override { - iterate(nodep->subDTypep()); + iterateConst(nodep->subDTypep()); puts(" "); puts(nodep->name()); } @@ -698,7 +698,7 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { unpackps.push_back(unpackp); dtypep = unpackp->subDTypep(); } else { - iterate(dtypep); + iterateConst(dtypep); puts(" "); puts(nodep->prettyName()); dtypep = nullptr; @@ -740,16 +740,16 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { public: bool m_suppressVarSemi = false; // Suppress emitting semicolon for AstVars - explicit EmitVBaseVisitor(bool suppressUnknown, AstSenTree* domainp) + explicit EmitVBaseVisitorConst(bool suppressUnknown, AstSenTree* domainp) : m_suppressUnknown{suppressUnknown} , m_sensesp{domainp} {} - ~EmitVBaseVisitor() override = default; + ~EmitVBaseVisitorConst() override = default; }; //###################################################################### // Emit to an output file -class EmitVFileVisitor final : public EmitVBaseVisitor { +class EmitVFileVisitor final : public EmitVBaseVisitorConst { // METHODS void puts(const string& str) override { ofp()->puts(str); } void putbs(const string& str) override { ofp()->putbs(str); } @@ -759,10 +759,10 @@ class EmitVFileVisitor final : public EmitVBaseVisitor { public: EmitVFileVisitor(AstNode* nodep, V3OutVFile* ofp, bool trackText, bool suppressUnknown) - : EmitVBaseVisitor{suppressUnknown, nullptr} { + : EmitVBaseVisitorConst{suppressUnknown, nullptr} { m_ofp = ofp; m_trackText = trackText; - iterate(nodep); + iterateConst(nodep); } ~EmitVFileVisitor() override = default; }; @@ -770,7 +770,7 @@ public: //###################################################################### // Emit to a stream (perhaps stringstream) -class EmitVStreamVisitor final : public EmitVBaseVisitor { +class EmitVStreamVisitor final : public EmitVBaseVisitorConst { // MEMBERS std::ostream& m_os; // METHODS @@ -782,9 +782,9 @@ class EmitVStreamVisitor final : public EmitVBaseVisitor { public: EmitVStreamVisitor(const AstNode* nodep, std::ostream& os) - : EmitVBaseVisitor{false, nullptr} + : EmitVBaseVisitorConst{false, nullptr} , m_os(os) { // Need () or GCC 4.8 false warning - iterate(const_cast(nodep)); + iterateConst(const_cast(nodep)); } ~EmitVStreamVisitor() override = default; }; @@ -837,7 +837,7 @@ public: } }; -class EmitVPrefixedVisitor final : public EmitVBaseVisitor { +class EmitVPrefixedVisitor final : public EmitVBaseVisitorConst { // MEMBERS EmitVPrefixedFormatter m_formatter; // Special verilog formatter (Way down the // inheritance is another unused V3OutFormatter) @@ -861,10 +861,10 @@ class EmitVPrefixedVisitor final : public EmitVBaseVisitor { public: EmitVPrefixedVisitor(const AstNode* nodep, std::ostream& os, const string& prefix, int flWidth, AstSenTree* domainp, bool user3mark) - : EmitVBaseVisitor{false, domainp} + : EmitVBaseVisitorConst{false, domainp} , m_formatter{os, prefix, flWidth} { if (user3mark) VNUser3InUse::check(); - iterate(const_cast(nodep)); + iterateConst(const_cast(nodep)); } ~EmitVPrefixedVisitor() override = default; }; diff --git a/src/V3EmitXml.cpp b/src/V3EmitXml.cpp index d38df87ae..2c2404d44 100644 --- a/src/V3EmitXml.cpp +++ b/src/V3EmitXml.cpp @@ -31,7 +31,7 @@ VL_DEFINE_DEBUG_FUNCTIONS; // ###################################################################### // Emit statements and expressions -class EmitXmlFileVisitor final : public VNVisitor { +class EmitXmlFileVisitor final : public VNVisitorConst { // NODE STATE // Entire netlist: // AstNode::user1 -> uint64_t, number to connect crossrefs @@ -94,7 +94,7 @@ class EmitXmlFileVisitor final : public VNVisitor { if (tag == "") tag = VString::downcase(nodep->typeName()); if (nodep->op1p() || nodep->op2p() || nodep->op3p() || nodep->op4p()) { puts(">\n"); - iterateChildren(nodep); + iterateChildrenConst(nodep); puts("\n"); } else { puts("/>\n"); @@ -117,13 +117,13 @@ class EmitXmlFileVisitor final : public VNVisitor { void visit(AstNodeIf* nodep) override { outputTag(nodep, "if"); puts(">\n"); - iterateAndNextNull(nodep->condp()); + iterateAndNextConstNull(nodep->condp()); puts("\n"); - iterateAndNextNull(nodep->thensp()); + iterateAndNextConstNull(nodep->thensp()); puts("\n"); if (nodep->elsesp()) { puts("\n"); - iterateAndNextNull(nodep->elsesp()); + iterateAndNextConstNull(nodep->elsesp()); puts("\n"); } puts("\n"); @@ -132,34 +132,34 @@ class EmitXmlFileVisitor final : public VNVisitor { outputTag(nodep, "while"); puts(">\n"); puts("\n"); - iterateAndNextNull(nodep->precondsp()); + iterateAndNextConstNull(nodep->precondsp()); puts("\n"); if (nodep->condp()) { puts("\n"); - iterateAndNextNull(nodep->condp()); + iterateAndNextConstNull(nodep->condp()); puts("\n"); } if (nodep->stmtsp()) { puts("\n"); - iterateAndNextNull(nodep->stmtsp()); + iterateAndNextConstNull(nodep->stmtsp()); puts("\n"); } if (nodep->incsp()) { puts("\n"); - iterateAndNextNull(nodep->incsp()); + iterateAndNextConstNull(nodep->incsp()); puts("\n"); } puts("\n"); } void visit(AstNetlist* nodep) override { puts("\n"); - iterateChildren(nodep); + iterateChildrenConst(nodep); puts("\n"); } void visit(AstConstPool* nodep) override { if (!v3Global.opt.xmlOnly()) { puts("\n"); - iterateChildren(nodep); + iterateChildrenConst(nodep); puts("\n"); } } @@ -170,7 +170,7 @@ class EmitXmlFileVisitor final : public VNVisitor { puts("\n"); - iterateChildren(itr.second); + iterateChildrenConst(itr.second); puts("\n"); } puts("\n"); @@ -314,7 +314,7 @@ class EmitXmlFileVisitor final : public VNVisitor { public: EmitXmlFileVisitor(AstNode* nodep, V3OutFile* ofp) : m_ofp{ofp} { - iterate(nodep); + iterateConst(nodep); } ~EmitXmlFileVisitor() override = default; }; @@ -322,7 +322,7 @@ public: //###################################################################### // List of module files xml visitor -class ModuleFilesXmlVisitor final : public VNVisitor { +class ModuleFilesXmlVisitor final : public VNVisitorConst { private: // MEMBERS std::ostream& m_os; @@ -354,7 +354,7 @@ public: ModuleFilesXmlVisitor(AstNetlist* nodep, std::ostream& os) : m_os(os) { // Need () or GCC 4.8 false warning // Operate on whole netlist - nodep->accept(*this); + iterateConst(nodep); // Xml output m_os << "\n"; for (const FileLine* ifp : m_nodeModules) { @@ -369,7 +369,7 @@ public: //###################################################################### // Hierarchy of Cells visitor -class HierCellsXmlVisitor final : public VNVisitor { +class HierCellsXmlVisitor final : public VNVisitorConst { private: // MEMBERS std::ostream& m_os; @@ -391,7 +391,7 @@ private: << " hier=\"" << nodep->prettyName() << "\""; m_hier = nodep->prettyName() + "."; m_hasChildren = false; - iterateChildren(nodep); + iterateChildrenConst(nodep); if (m_hasChildren) { m_os << "\n"; } else { @@ -410,7 +410,7 @@ private: const std::string hier = m_hier; m_hier += nodep->name() + "."; m_hasChildren = false; - iterateChildren(nodep->modp()); + iterateChildrenConst(nodep->modp()); if (m_hasChildren) { m_os << "\n"; } else { @@ -420,14 +420,13 @@ private: m_hasChildren = true; } //----- - void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } public: // CONSTRUCTORS HierCellsXmlVisitor(AstNetlist* nodep, std::ostream& os) : m_os(os) { // Need () or GCC 4.8 false warning - // Operate on whole netlist - nodep->accept(*this); + iterateConst(nodep); } ~HierCellsXmlVisitor() override = default; }; diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 4c4ef2e7d..2929916bc 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -192,7 +192,7 @@ public: // ###################################################################### // Is this a simple expression with a single input and single output? -class GateOkVisitor final : public VNVisitor { +class GateOkVisitor final : public VNVisitorConst { private: // RETURN STATE bool m_isSimple = true; // Set false when we know it isn't simple @@ -215,7 +215,7 @@ private: // VISITORS void visit(AstNodeVarRef* nodep) override { ++m_ops; - iterateChildren(nodep); + iterateChildrenConst(nodep); // We only allow a LHS ref for the var being set, and a RHS ref for // something else being read. if (nodep->varScopep()->varp()->isSc()) { @@ -246,7 +246,7 @@ private: } else if (nodep->isTimingControl()) { clearSimple("Timing control"); } else { - iterateChildren(nodep); + iterateChildrenConst(nodep); } // We don't push logic other then assignments/NOTs into SenItems // This avoids a mess in computing what exactly a POSEDGE is @@ -271,7 +271,7 @@ private: UINFO(5, "Non optimizable type: " << nodep << endl); clearSimple("Non optimizable type"); } else { - iterateChildren(nodep); + iterateChildrenConst(nodep); } } @@ -281,7 +281,7 @@ public: m_buffersOnly = buffersOnly; m_dedupe = dedupe; // Iterate - iterate(nodep); + iterateConst(nodep); // Check results if (!m_substTreep) clearSimple("No assignment found\n"); for (GateVarRefList::const_iterator it = m_rhsVarRefs.begin(); it != m_rhsVarRefs.end(); @@ -1292,7 +1292,7 @@ void GateVisitor::mergeAssigns() { //###################################################################### // Find a var's offset in a concatenation -class GateConcatVisitor final : public VNVisitor { +class GateConcatVisitor final : public VNVisitorConst { private: // STATE const AstVarScope* m_vscp = nullptr; // Varscope we're trying to find @@ -1315,11 +1315,11 @@ private: } void visit(AstConcat* nodep) override { UINFO(9, "CLK DECOMP Concat search (off = " << m_offset << ") - " << nodep << endl); - iterate(nodep->rhsp()); - iterate(nodep->lhsp()); + iterateConst(nodep->rhsp()); + iterateConst(nodep->lhsp()); } //-------------------- - void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } public: // CONSTRUCTORS @@ -1331,7 +1331,7 @@ public: m_offset = 0; m_found = false; // Iterate - iterate(concatp); + iterateConst(concatp); UINFO(9, "CLK DECOMP Concat Offset (found = " << m_found << ") (" << m_found_offset << ") - " << concatp << " : " << vscp << endl); diff --git a/src/V3Hasher.cpp b/src/V3Hasher.cpp index 0dfdee7b3..c68f1167e 100644 --- a/src/V3Hasher.cpp +++ b/src/V3Hasher.cpp @@ -26,7 +26,7 @@ VL_DEFINE_DEBUG_FUNCTIONS; //###################################################################### // Visitor that computes node hashes -class HasherVisitor final : public VNVisitor { +class HasherVisitor final : public VNVisitorConst { private: // NODE STATE // AstNode::user4() -> V3Hash. Hash value of this node (hash of 0 is illegal) @@ -48,7 +48,8 @@ private: // Reset accumulator m_hash = V3Hash{nodep->type()}; // Node type f(); // Node specific hash - if (hashDType && nodep != nodep->dtypep()) iterateNull(nodep->dtypep()); // Node dtype + if (hashDType && nodep != nodep->dtypep()) + iterateConstNull(nodep->dtypep()); // Node dtype if (hashChildren) iterateChildrenConst(nodep); // Children if (m_cacheInUser4) nodep->user4(m_hash.value()); return m_hash; @@ -92,7 +93,7 @@ private: // AstNodeDType void visit(AstNodeArrayDType* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { - iterateNull(nodep->virtRefDTypep()); + iterateConstNull(nodep->virtRefDTypep()); m_hash += nodep->left(); m_hash += nodep->right(); }); @@ -120,23 +121,23 @@ private: } void visit(AstAssocArrayDType* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { - iterateNull(nodep->virtRefDTypep()); - iterateNull(nodep->virtRefDType2p()); + iterateConstNull(nodep->virtRefDTypep()); + iterateConstNull(nodep->virtRefDType2p()); }); } void visit(AstDynArrayDType* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // - iterateNull(nodep->virtRefDTypep()); + iterateConstNull(nodep->virtRefDTypep()); }); } void visit(AstUnsizedArrayDType* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // - iterateNull(nodep->virtRefDTypep()); + iterateConstNull(nodep->virtRefDTypep()); }); } void visit(AstWildcardArrayDType* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // - iterateNull(nodep->virtRefDTypep()); + iterateConstNull(nodep->virtRefDTypep()); }); } void visit(AstBasicDType* nodep) override { @@ -148,29 +149,29 @@ private: } void visit(AstConstDType* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // - iterateNull(nodep->virtRefDTypep()); + iterateConstNull(nodep->virtRefDTypep()); }); } void visit(AstClassRefDType* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // - iterateNull(nodep->classp()); + iterateConstNull(nodep->classp()); }); } void visit(AstIfaceRefDType* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // - iterateNull(nodep->cellp()); + iterateConstNull(nodep->cellp()); }); } void visit(AstQueueDType* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // - iterateNull(nodep->virtRefDTypep()); + iterateConstNull(nodep->virtRefDTypep()); }); } void visit(AstRefDType* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { m_hash += nodep->name(); - iterateNull(nodep->typedefp()); - iterateNull(nodep->refDTypep()); + iterateConstNull(nodep->typedefp()); + iterateConstNull(nodep->refDTypep()); }); } void visit(AstVoidDType* nodep) override { @@ -203,16 +204,16 @@ private: void visit(AstVarRef* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { if (nodep->varScopep()) { - iterateNull(nodep->varScopep()); + iterateConstNull(nodep->varScopep()); } else { - iterateNull(nodep->varp()); + iterateConstNull(nodep->varp()); m_hash += nodep->selfPointer(); } }); } void visit(AstVarXRef* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { - iterateNull(nodep->varp()); + iterateConstNull(nodep->varp()); m_hash += nodep->dotted(); }); } @@ -233,7 +234,7 @@ private: } void visit(AstAddrOfCFunc* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // - iterateNull(nodep->funcp()); + iterateConstNull(nodep->funcp()); }); } @@ -249,13 +250,13 @@ private: } void visit(AstNodeCCall* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // - iterateNull(nodep->funcp()); + iterateConstNull(nodep->funcp()); }); } void visit(AstNodeFTaskRef* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { - iterateNull(nodep->taskp()); - iterateNull(nodep->classOrPackagep()); + iterateConstNull(nodep->taskp()); + iterateConstNull(nodep->classOrPackagep()); }); } void visit(AstCMethodHard* nodep) override { @@ -265,12 +266,12 @@ private: } void visit(AstCAwait* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // - iterateNull(nodep->sensesp()); + iterateConstNull(nodep->sensesp()); }); } void visit(AstCoverInc* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // - iterateNull(nodep->declp()); + iterateConstNull(nodep->declp()); }); } void visit(AstDisplay* nodep) override { @@ -285,12 +286,12 @@ private: } void visit(AstJumpGo* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // - iterateNull(nodep->labelp()); + iterateConstNull(nodep->labelp()); }); } void visit(AstTraceInc* nodep) override { m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // - iterateNull(nodep->declp()); + iterateConstNull(nodep->declp()); }); } void visit(AstNodeCoverOrAssert* nodep) override { @@ -332,7 +333,7 @@ private: } void visit(AstClassOrPackageRef* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // - iterateNull(nodep->classOrPackageNodep()); + iterateConstNull(nodep->classOrPackageNodep()); }); } void visit(AstSenItem* nodep) override { @@ -376,7 +377,7 @@ private: if (dtypep) { const uint32_t size = dtypep->elementsConst(); for (uint32_t n = 0; n < size; ++n) { // - iterateNull(nodep->getIndexDefaultedValuep(n)); + iterateConstNull(nodep->getIndexDefaultedValuep(n)); } } }); @@ -417,13 +418,13 @@ private: void visit(AstScope* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, false, [=]() { m_hash += nodep->name(); - iterateNull(nodep->aboveScopep()); + iterateConstNull(nodep->aboveScopep()); }); } void visit(AstVarScope* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { - iterateNull(nodep->varp()); - iterateNull(nodep->scopep()); + iterateConstNull(nodep->varp()); + iterateConstNull(nodep->scopep()); }); } void visit(AstEnumItem* nodep) override { @@ -443,19 +444,19 @@ private: } void visit(AstActive* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // - iterateNull(nodep->sensesp()); + iterateConstNull(nodep->sensesp()); }); } void visit(AstCell* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { m_hash += nodep->name(); - iterateNull(nodep->modp()); + iterateConstNull(nodep->modp()); }); } void visit(AstCellInline* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { m_hash += nodep->name(); - iterateNull(nodep->scopep()); + iterateConstNull(nodep->scopep()); }); } void visit(AstNodeFTask* nodep) override { @@ -471,13 +472,13 @@ private: void visit(AstModportVarRef* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { m_hash += nodep->name(); - iterateNull(nodep->varp()); + iterateConstNull(nodep->varp()); }); } void visit(AstModportFTaskRef* nodep) override { m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { m_hash += nodep->name(); - iterateNull(nodep->ftaskp()); + iterateConstNull(nodep->ftaskp()); }); } void visit(AstMTaskBody* nodep) override { @@ -502,12 +503,12 @@ public: // CONSTRUCTORS explicit HasherVisitor(AstNode* nodep) : m_cacheInUser4{true} { - iterate(nodep); + iterateConst(nodep); } class Uncached {}; HasherVisitor(const AstNode* nodep, Uncached) : m_cacheInUser4{false} { - iterate(const_cast(nodep)); + iterateConst(const_cast(nodep)); } V3Hash finalHash() const { return m_hash; } ~HasherVisitor() override = default; diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index 78ea53c8f..02db2fd98 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -139,7 +139,7 @@ public: //###################################################################### -class InstDeModVarVisitor final : public VNVisitor { +class InstDeModVarVisitor final : public VNVisitorConst { // Expand all module variables, and save names for later reference private: // STATE @@ -151,10 +151,10 @@ private: UINFO(8, " dm-1-VAR " << nodep << endl); insert(nodep); } - iterateChildren(nodep); + iterateChildrenConst(nodep); } void visit(AstNodeExpr*) override {} // Accelerate - void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } public: // METHODS @@ -182,7 +182,7 @@ public: void main(AstNodeModule* nodep) { UINFO(8, " dmMODULE " << nodep << endl); m_modVarNameMap.clear(); - iterate(nodep); + iterateConst(nodep); } }; diff --git a/src/V3InstrCount.cpp b/src/V3InstrCount.cpp index 96d19aa90..68574f6c9 100644 --- a/src/V3InstrCount.cpp +++ b/src/V3InstrCount.cpp @@ -32,7 +32,7 @@ VL_DEFINE_DEBUG_FUNCTIONS; /// we'll count instructions from either the 'if' or the 'else' branch, /// whichever is larger. We know we won't run both. -class InstrCountVisitor final : public VNVisitor { +class InstrCountVisitor final : public VNVisitorConst { private: // NODE STATE // AstNode::user4() -> int. Path cost + 1, 0 means don't dump @@ -76,7 +76,7 @@ public: : m_startNodep{nodep} , m_assertNoDups{assertNoDups} , m_osp{osp} { - if (nodep) iterate(nodep); + if (nodep) iterateConst(nodep); } ~InstrCountVisitor() override = default; @@ -135,7 +135,7 @@ private: // Hence, exclude the child of the AstWordSel from the computation, // whose cost scales with the size of the entire (maybe large) vector. const VisitBase vb{this, nodep}; - iterateAndNextNull(nodep->bitp()); + iterateAndNextConstNull(nodep->bitp()); } void visit(AstSel* nodep) override { if (m_ignoreRemaining) return; @@ -144,8 +144,8 @@ private: // its width) and the cost of the lsbp() and widthp() nodes, but not // the fromp() node which could be disproportionately large. const VisitBase vb{this, nodep}; - iterateAndNextNull(nodep->lsbp()); - iterateAndNextNull(nodep->widthp()); + iterateAndNextConstNull(nodep->lsbp()); + iterateAndNextConstNull(nodep->widthp()); } void visit(AstSliceSel* nodep) override { // LCOV_EXCL_LINE nodep->v3fatalSrc("AstSliceSel unhandled"); @@ -177,18 +177,18 @@ private: void visit(AstNodeIf* nodep) override { if (m_ignoreRemaining) return; const VisitBase vb{this, nodep}; - iterateAndNextNull(nodep->condp()); + iterateAndNextConstNull(nodep->condp()); const uint32_t savedCount = m_instrCount; UINFO(8, "thensp:\n"); reset(); - iterateAndNextNull(nodep->thensp()); + iterateAndNextConstNull(nodep->thensp()); uint32_t ifCount = m_instrCount; if (nodep->branchPred().unlikely()) ifCount = 0; UINFO(8, "elsesp:\n"); reset(); - iterateAndNextNull(nodep->elsesp()); + iterateAndNextConstNull(nodep->elsesp()); uint32_t elseCount = m_instrCount; if (nodep->branchPred().likely()) elseCount = 0; @@ -206,17 +206,17 @@ private: // Just like if/else above, the ternary operator only evaluates // one of the two expressions, so only count the max. const VisitBase vb{this, nodep}; - iterateAndNextNull(nodep->condp()); + iterateAndNextConstNull(nodep->condp()); const uint32_t savedCount = m_instrCount; UINFO(8, "?\n"); reset(); - iterateAndNextNull(nodep->thenp()); + iterateAndNextConstNull(nodep->thenp()); const uint32_t ifCount = m_instrCount; UINFO(8, ":\n"); reset(); - iterateAndNextNull(nodep->elsep()); + iterateAndNextConstNull(nodep->elsep()); const uint32_t elseCount = m_instrCount; reset(); @@ -230,7 +230,7 @@ private: } void visit(AstCAwait* nodep) override { if (m_ignoreRemaining) return; - iterateChildren(nodep); + iterateChildrenConst(nodep); // Anything past a co_await is irrelevant m_ignoreRemaining = true; } @@ -241,7 +241,7 @@ private: // Sum counts in each statement until the first await for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { reset(); - iterate(stmtp); + iterateConst(stmtp); totalCount += m_instrCount; } m_instrCount = totalCount; @@ -266,9 +266,9 @@ private: void visit(AstNodeCCall* nodep) override { if (m_ignoreRemaining) return; const VisitBase vb{this, nodep}; - iterateChildren(nodep); + iterateChildrenConst(nodep); m_tracingCall = true; - iterate(nodep->funcp()); + iterateConst(nodep->funcp()); UASSERT_OBJ(!m_tracingCall, nodep, "visit(AstCFunc) should have cleared m_tracingCall."); } void visit(AstCFunc* nodep) override { @@ -282,21 +282,21 @@ private: { m_inCFunc = true; const VisitBase vb{this, nodep}; - iterateChildren(nodep); + iterateChildrenConst(nodep); } m_ignoreRemaining = false; } void visit(AstNode* nodep) override { if (m_ignoreRemaining) return; const VisitBase vb{this, nodep}; - iterateChildren(nodep); + iterateChildrenConst(nodep); } VL_UNCOPYABLE(InstrCountVisitor); }; // Iterate the graph printing the critical path marked by previous visitation -class InstrCountDumpVisitor final : public VNVisitor { +class InstrCountDumpVisitor final : public VNVisitorConst { private: // NODE STATE // AstNode::user4() -> int. Path cost, 0 means don't dump @@ -311,7 +311,7 @@ public: : m_osp{osp} { // No check for nullptr output, so... UASSERT_OBJ(osp, nodep, "Don't call if not dumping"); - if (nodep) iterate(nodep); + if (nodep) iterateConst(nodep); } ~InstrCountDumpVisitor() override = default; @@ -323,7 +323,7 @@ private: if (unsigned costPlus1 = nodep->user4()) { *m_osp << " " << indent() << "cost " << std::setw(6) << std::left << (costPlus1 - 1) << " " << nodep << '\n'; - iterateChildren(nodep); + iterateChildrenConst(nodep); } --m_depth; } diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 6620c845d..55428d1df 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -446,7 +446,7 @@ public: // Recurses cells backwards, so we can pick up those things that propagate // from child cells up to the top module. -class LinkBotupVisitor final : public VNVisitor { +class LinkBotupVisitor final : public VNVisitorConst { private: // STATE AstNodeModule* m_modp = nullptr; // Current module @@ -458,10 +458,8 @@ private: } void visit(AstNodeModule* nodep) override { VL_RESTORER(m_modp); - { - m_modp = nodep; - iterateChildren(nodep); - } + m_modp = nodep; + iterateChildrenConst(nodep); } void visit(AstCell* nodep) override { // Parent module inherits child's publicity @@ -469,11 +467,11 @@ private: //** No iteration for speed } void visit(AstNodeExpr*) override {} // Accelerate - void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } public: // CONSTRUCTORS - explicit LinkBotupVisitor(AstNetlist* rootp) { iterate(rootp); } + explicit LinkBotupVisitor(AstNetlist* rootp) { iterateConst(rootp); } ~LinkBotupVisitor() override = default; }; diff --git a/src/V3MergeCond.cpp b/src/V3MergeCond.cpp index c7fe8ec75..d5756cc67 100644 --- a/src/V3MergeCond.cpp +++ b/src/V3MergeCond.cpp @@ -158,7 +158,7 @@ using StmtPropertiesAllocator = AstUser3Allocator; // Pure analysis visitor that build the StmtProperties for each statement in the given // AstNode list (following AstNode::nextp()) -class CodeMotionAnalysisVisitor final : public VNVisitor { +class CodeMotionAnalysisVisitor final : public VNVisitorConst { // NODE STATE // AstNodeStmt::user3 -> StmtProperties (accessed via m_stmtProperties, managed externally, // see MergeCondVisitor::process) diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index cb2a47f09..1f50e83b3 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -36,7 +36,7 @@ VL_DEFINE_DEBUG_FUNCTIONS; //###################################################################### // Visitor that marks classes needing a randomize() method -class RandomizeMarkVisitor final : public VNVisitor { +class RandomizeMarkVisitor final : public VNVisitorConst { private: // NODE STATE // Cleared on Netlist @@ -87,7 +87,7 @@ private: // VISITORS void visit(AstClass* nodep) override { - iterateChildren(nodep); + iterateChildrenConst(nodep); if (nodep->extendsp()) { // Save pointer to derived class AstClass* const basep = nodep->extendsp()->classp(); @@ -95,7 +95,7 @@ private: } } void visit(AstMethodCall* nodep) override { - iterateChildren(nodep); + iterateChildrenConst(nodep); if (nodep->name() != "randomize") return; if (const AstClassRefDType* const classRefp = VN_CAST(nodep->fromp()->dtypep(), ClassRefDType)) { @@ -105,12 +105,12 @@ private: } } - void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } public: // CONSTRUCTORS explicit RandomizeMarkVisitor(AstNetlist* nodep) { - iterate(nodep); + iterateConst(nodep); markAllDerived(); } ~RandomizeMarkVisitor() override = default; diff --git a/src/V3Simulate.h b/src/V3Simulate.h index d8b5e599a..05fac3e7a 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -64,7 +64,7 @@ public: ~SimStackNode() = default; }; -class SimulateVisitor VL_NOT_FINAL : public VNVisitor { +class SimulateVisitor VL_NOT_FINAL : public VNVisitorConst { // Simulate a node tree, returning value of variables // Two major operating modes: // Test the tree to see if it is conformant @@ -400,7 +400,7 @@ private: void visit(AstAlways* nodep) override { if (jumpingOver(nodep)) return; checkNodeInfo(nodep); - iterateChildren(nodep); + iterateChildrenConst(nodep); } void visit(AstSenTree* nodep) override { // Sensitivities aren't inputs per se; we'll keep our tree under the same sens. @@ -409,7 +409,7 @@ private: if (jumpingOver(nodep)) return; if (!optimizable()) return; // Accelerate UASSERT_OBJ(nodep->varp(), nodep, "Unlinked"); - iterateChildren(nodep->varp()); + iterateChildrenConst(nodep->varp()); AstNode* const vscp = varOrScope(nodep); // We can't have non-delayed assignments with same value on LHS and RHS @@ -502,7 +502,7 @@ private: clearOptimizable(nodep, "Constant function called under generate"); } checkNodeInfo(nodep); - iterateChildren(nodep); + iterateChildrenConst(nodep); } void visit(AstInitialStatic* nodep) override { if (jumpingOver(nodep)) return; @@ -511,21 +511,21 @@ private: return; } checkNodeInfo(nodep); - iterateChildren(nodep); + iterateChildrenConst(nodep); } void visit(AstNodeIf* nodep) override { if (jumpingOver(nodep)) return; UINFO(5, " IF " << nodep << endl); checkNodeInfo(nodep); if (m_checkOnly) { - iterateChildren(nodep); + iterateChildrenConst(nodep); } else { - iterateAndNextNull(nodep->condp()); + iterateAndNextConstNull(nodep->condp()); if (optimizable()) { if (fetchConst(nodep->condp())->num().isNeqZero()) { - iterateAndNextNull(nodep->thensp()); + iterateAndNextConstNull(nodep->thensp()); } else { - iterateAndNextNull(nodep->elsesp()); + iterateAndNextConstNull(nodep->elsesp()); } } } @@ -544,7 +544,7 @@ private: if (!m_checkOnly && optimizable()) { AstNode* const valuep = nodep->itemp()->valuep(); if (valuep) { - iterateAndNextNull(valuep); + iterateAndNextConstNull(valuep); if (optimizable()) newValue(nodep, fetchValue(valuep)); } else { clearOptimizable(nodep, "No value found for enum item"); // LCOV_EXCL_LINE @@ -554,7 +554,7 @@ private: void visit(AstNodeUniop* nodep) override { if (!optimizable()) return; // Accelerate checkNodeInfo(nodep); - iterateChildren(nodep); + iterateChildrenConst(nodep); if (!m_checkOnly && optimizable()) { nodep->numberOperate(newConst(nodep)->num(), fetchConst(nodep->lhsp())->num()); } @@ -562,7 +562,7 @@ private: void visit(AstNodeBiop* nodep) override { if (!optimizable()) return; // Accelerate checkNodeInfo(nodep); - iterateChildren(nodep); + iterateChildrenConst(nodep); if (!m_checkOnly && optimizable()) { nodep->numberOperate(newConst(nodep)->num(), fetchConst(nodep->lhsp())->num(), fetchConst(nodep->rhsp())->num()); @@ -571,7 +571,7 @@ private: void visit(AstNodeTriop* nodep) override { if (!optimizable()) return; // Accelerate checkNodeInfo(nodep); - iterateChildren(nodep); + iterateChildrenConst(nodep); if (!m_checkOnly && optimizable()) { nodep->numberOperate(newConst(nodep)->num(), fetchConst(nodep->lhsp())->num(), fetchConst(nodep->rhsp())->num(), @@ -581,7 +581,7 @@ private: void visit(AstNodeQuadop* nodep) override { if (!optimizable()) return; // Accelerate checkNodeInfo(nodep); - iterateChildren(nodep); + iterateChildrenConst(nodep); if (!m_checkOnly && optimizable()) { nodep->numberOperate(newConst(nodep)->num(), fetchConst(nodep->lhsp())->num(), fetchConst(nodep->rhsp())->num(), @@ -594,12 +594,12 @@ private: if (!optimizable()) return; // Accelerate checkNodeInfo(nodep); if (m_checkOnly) { - iterateChildren(nodep); + iterateChildrenConst(nodep); } else { - iterate(nodep->lhsp()); + iterateConst(nodep->lhsp()); if (optimizable()) { if (fetchConst(nodep->lhsp())->num().isNeqZero()) { - iterate(nodep->rhsp()); + iterateConst(nodep->rhsp()); newValue(nodep, fetchValue(nodep->rhsp())); } else { newValue(nodep, fetchValue(nodep->lhsp())); // a zero @@ -612,14 +612,14 @@ private: if (!optimizable()) return; // Accelerate checkNodeInfo(nodep); if (m_checkOnly) { - iterateChildren(nodep); + iterateChildrenConst(nodep); } else { - iterate(nodep->lhsp()); + iterateConst(nodep->lhsp()); if (optimizable()) { if (fetchConst(nodep->lhsp())->num().isNeqZero()) { newValue(nodep, fetchValue(nodep->lhsp())); // a one } else { - iterate(nodep->rhsp()); + iterateConst(nodep->rhsp()); newValue(nodep, fetchValue(nodep->rhsp())); } } @@ -630,16 +630,16 @@ private: if (!optimizable()) return; // Accelerate checkNodeInfo(nodep); if (m_checkOnly) { - iterateChildren(nodep); + iterateChildrenConst(nodep); } else { - iterate(nodep->lhsp()); + iterateConst(nodep->lhsp()); if (optimizable()) { if (fetchConst(nodep->lhsp())->num().isEqZero()) { const AstConst cnst{nodep->fileline(), AstConst::WidthedValue{}, 1, 1}; // a one newValue(nodep, &cnst); // a one } else { - iterate(nodep->rhsp()); + iterateConst(nodep->rhsp()); newValue(nodep, fetchValue(nodep->rhsp())); } } @@ -652,15 +652,15 @@ private: if (!optimizable()) return; // Accelerate checkNodeInfo(nodep); if (m_checkOnly) { - iterateChildren(nodep); + iterateChildrenConst(nodep); } else { - iterate(nodep->condp()); + iterateConst(nodep->condp()); if (optimizable()) { if (fetchConst(nodep->condp())->num().isNeqZero()) { - iterate(nodep->thenp()); + iterateConst(nodep->thenp()); newValue(nodep, fetchValue(nodep->thenp())); } else { - iterate(nodep->elsep()); + iterateConst(nodep->elsep()); newValue(nodep, fetchValue(nodep->elsep())); } } @@ -668,11 +668,11 @@ private: } void handleAssignArray(AstNodeAssign* nodep, AstArraySel* selp) { - iterateAndNextNull(nodep->rhsp()); // Value to assign + iterateAndNextConstNull(nodep->rhsp()); // Value to assign // At present we only handle single dimensional assignments // To do better, we need the concept of lvalues, or similar, to know where/how to insert checkNodeInfo(selp); - iterateAndNextNull(selp->bitp()); // Bit index + iterateAndNextConstNull(selp->bitp()); // Bit index AstVarRef* const varrefp = VN_CAST(selp->fromp(), VarRef); if (!varrefp) { clearOptimizable(nodep, "Array select LHS isn't simple variable"); @@ -719,7 +719,7 @@ private: void handleAssignSel(AstNodeAssign* nodep, AstSel* selp) { AstVarRef* varrefp = nullptr; V3Number lsb{nodep}; - iterateAndNextNull(nodep->rhsp()); // Value to assign + iterateAndNextConstNull(nodep->rhsp()); // Value to assign handleAssignSelRecurse(nodep, selp, varrefp /*ref*/, lsb /*ref*/, 0); if (!m_checkOnly && optimizable()) { UASSERT_OBJ(varrefp, nodep, @@ -748,7 +748,7 @@ private: // Recurse down to find final variable being set (outVarrefp), with // lsb to be eventually set on lsbRef checkNodeInfo(selp); - iterateAndNextNull(selp->lsbp()); // Bit index + iterateAndNextConstNull(selp->lsbp()); // Bit index if (AstVarRef* const varrefp = VN_CAST(selp->fromp(), VarRef)) { outVarrefpRef = varrefp; lsbRef = fetchConst(selp->lsbp())->num(); @@ -798,9 +798,9 @@ private: } else if (!VN_IS(nodep->lhsp(), VarRef)) { clearOptimizable(nodep, "LHS isn't simple variable"); } else if (m_checkOnly) { - iterateChildren(nodep); + iterateChildrenConst(nodep); } else if (optimizable()) { - iterateAndNextNull(nodep->rhsp()); + iterateAndNextConstNull(nodep->rhsp()); if (optimizable()) { AstNode* const vscp = varOrScope(VN_CAST(nodep->lhsp(), VarRef)); assignOutValue(nodep, vscp, fetchValue(nodep->rhsp())); @@ -809,7 +809,7 @@ private: } void visit(AstArraySel* nodep) override { checkNodeInfo(nodep); - iterateChildren(nodep); + iterateChildrenConst(nodep); if (AstInitArray* const initp = VN_CAST(fetchValueNull(nodep->fromp()), InitArray)) { AstConst* const indexp = fetchConst(nodep->bitp()); const uint32_t offset = indexp->num().toUInt(); @@ -826,28 +826,28 @@ private: } void visit(AstBegin* nodep) override { checkNodeInfo(nodep); - iterateChildren(nodep); + iterateChildrenConst(nodep); } void visit(AstNodeCase* nodep) override { if (jumpingOver(nodep)) return; UINFO(5, " CASE " << nodep << endl); checkNodeInfo(nodep); if (m_checkOnly) { - iterateChildren(nodep); + iterateChildrenConst(nodep); } else if (optimizable()) { - iterateAndNextNull(nodep->exprp()); + iterateAndNextConstNull(nodep->exprp()); bool hit = false; for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp = VN_AS(itemp->nextp(), CaseItem)) { if (!itemp->isDefault()) { for (AstNode* ep = itemp->condsp(); ep; ep = ep->nextp()) { if (hit) break; - iterateAndNextNull(ep); + iterateAndNextConstNull(ep); if (optimizable()) { V3Number match{nodep, 1}; match.opEq(fetchConst(nodep->exprp())->num(), fetchConst(ep)->num()); if (match.isNeqZero()) { - iterateAndNextNull(itemp->stmtsp()); + iterateAndNextConstNull(itemp->stmtsp()); hit = true; } } @@ -859,7 +859,7 @@ private: itemp = VN_AS(itemp->nextp(), CaseItem)) { if (hit) break; if (!hit && itemp->isDefault()) { - iterateAndNextNull(itemp->stmtsp()); + iterateAndNextConstNull(itemp->stmtsp()); hit = true; } } @@ -870,7 +870,7 @@ private: // Real handling is in AstNodeCase if (jumpingOver(nodep)) return; checkNodeInfo(nodep); - iterateChildren(nodep); + iterateChildrenConst(nodep); } void visit(AstComment*) override {} @@ -878,12 +878,12 @@ private: void visit(AstStmtExpr* nodep) override { if (jumpingOver(nodep)) return; checkNodeInfo(nodep); - iterateChildren(nodep); + iterateChildrenConst(nodep); } void visit(AstJumpBlock* nodep) override { if (jumpingOver(nodep)) return; - iterateChildren(nodep); + iterateChildrenConst(nodep); } void visit(AstJumpGo* nodep) override { if (jumpingOver(nodep)) return; @@ -898,7 +898,7 @@ private: // AstJumpGo::broken uses brokeExistsBelow() to check this. if (jumpingOver(nodep)) return; checkNodeInfo(nodep); - iterateChildren(nodep); + iterateChildrenConst(nodep); if (m_jumpp && m_jumpp->labelp() == nodep) { UINFO(5, " JUMP DONE " << nodep << endl); m_jumpp = nullptr; @@ -924,19 +924,19 @@ private: } checkNodeInfo(nodep); if (m_checkOnly) { - iterateChildren(nodep); + iterateChildrenConst(nodep); } else if (optimizable()) { int loops = 0; - iterateAndNextNull(nodep->initsp()); + iterateAndNextConstNull(nodep->initsp()); while (true) { UINFO(5, " FOR-ITER " << nodep << endl); - iterateAndNextNull(nodep->condp()); + iterateAndNextConstNull(nodep->condp()); if (!optimizable()) break; if (!fetchConst(nodep->condp())->num().isNeqZero()) { // break; } - iterateAndNextNull(nodep->stmtsp()); - iterateAndNextNull(nodep->incsp()); + iterateAndNextConstNull(nodep->stmtsp()); + iterateAndNextConstNull(nodep->incsp()); if (loops++ > unrollCount() * 16) { clearOptimizable(nodep, "Loop unrolling took too long; probably this is an" "infinite loop, or set --unroll-count above " @@ -957,22 +957,22 @@ private: } checkNodeInfo(nodep); if (m_checkOnly) { - iterateChildren(nodep); + iterateChildrenConst(nodep); } else if (optimizable()) { int loops = 0; while (true) { UINFO(5, " WHILE-ITER " << nodep << endl); - iterateAndNextNull(nodep->precondsp()); + iterateAndNextConstNull(nodep->precondsp()); if (jumpingOver(nodep)) break; - iterateAndNextNull(nodep->condp()); + iterateAndNextConstNull(nodep->condp()); if (jumpingOver(nodep)) break; if (!optimizable()) break; if (!fetchConst(nodep->condp())->num().isNeqZero()) { // break; } - iterateAndNextNull(nodep->stmtsp()); + iterateAndNextConstNull(nodep->stmtsp()); if (jumpingOver(nodep)) break; - iterateAndNextNull(nodep->incsp()); + iterateAndNextConstNull(nodep->incsp()); if (jumpingOver(nodep)) break; // Prep for next loop @@ -1024,7 +1024,7 @@ private: return; } // Evaluate pin value - iterate(pinp); + iterateConst(pinp); } } for (V3TaskConnects::iterator it = tconnects.begin(); it != tconnects.end(); ++it) { @@ -1050,7 +1050,7 @@ private: newValue(funcp->fvarp(), &cnst); } // Evaluate the function - iterate(funcp); + iterateConst(funcp); m_callStack.pop_back(); if (!m_checkOnly && optimizable()) { // Grab return value from output variable (if it's a function) @@ -1076,7 +1076,7 @@ private: if (jumpingOver(nodep)) return; if (!optimizable()) return; // Accelerate checkNodeInfo(nodep); - iterateChildren(nodep); + iterateChildrenConst(nodep); if (m_params) { AstNode* nextArgp = nodep->exprsp(); @@ -1139,7 +1139,7 @@ private: // We ignore isPredictOptimizable as $display is often in constant // functions and we want them to work if used with parameters checkNodeInfo(nodep, /*display:*/ true); - iterateChildren(nodep); + iterateChildrenConst(nodep); if (m_params) { AstConst* const textp = fetchConst(nodep->fmtp()); switch (nodep->displayType()) { @@ -1171,7 +1171,7 @@ private: m_params = params; } void mainGuts(AstNode* nodep) { - iterate(nodep); + iterateConst(nodep); UASSERT_OBJ(!m_jumpp, m_jumpp, "JumpGo branched to label that wasn't found"); } diff --git a/src/V3Split.cpp b/src/V3Split.cpp index 0c135d3e9..774d2989d 100644 --- a/src/V3Split.cpp +++ b/src/V3Split.cpp @@ -622,7 +622,7 @@ private: using ColorSet = std::unordered_set; using AlwaysVec = std::vector; -class IfColorVisitor final : public VNVisitor { +class IfColorVisitor final : public VNVisitorConst { // MEMBERS ColorSet m_colors; // All colors in the original always block @@ -636,7 +636,7 @@ class IfColorVisitor final : public VNVisitor { public: // Visit through *nodep and map each AstNodeIf within to the set of // colors it will participate in. Also find the whole set of colors. - explicit IfColorVisitor(AstAlways* nodep) { iterate(nodep); } + explicit IfColorVisitor(AstAlways* nodep) { iterateConst(nodep); } ~IfColorVisitor() override = default; // METHODS @@ -667,12 +667,12 @@ protected: void visit(AstNodeIf* nodep) override { m_ifStack.push_back(nodep); trackNode(nodep); - iterateChildren(nodep); + iterateChildrenConst(nodep); m_ifStack.pop_back(); } void visit(AstNode* nodep) override { trackNode(nodep); - iterateChildren(nodep); + iterateChildrenConst(nodep); } private: diff --git a/src/V3Undriven.cpp b/src/V3Undriven.cpp index 398abf29a..af60b39a0 100644 --- a/src/V3Undriven.cpp +++ b/src/V3Undriven.cpp @@ -269,7 +269,7 @@ public: //###################################################################### // Undriven state, as a visitor of each AstNode -class UndrivenVisitor final : public VNVisitor { +class UndrivenVisitor final : public VNVisitorConst { private: // NODE STATE // Netlist: @@ -344,15 +344,15 @@ private: if (nodep->valuep()) entryp->drivenWhole(); } // Discover variables used in bit definitions, etc - iterateChildren(nodep); + iterateChildrenConst(nodep); } void visit(AstArraySel* nodep) override { // Arrays are rarely constant assigned, so for now we punt and do all entries - iterateChildren(nodep); + iterateChildrenConst(nodep); } void visit(AstSliceSel* nodep) override { // Arrays are rarely constant assigned, so for now we punt and do all entries - iterateChildren(nodep); + iterateChildrenConst(nodep); } void visit(AstSel* nodep) override { AstNodeVarRef* const varrefp = VN_CAST(nodep->fromp(), NodeVarRef); @@ -375,7 +375,7 @@ private: } } else { // else other varrefs handled as unknown mess in AstVarRef - iterateChildren(nodep); + iterateChildrenConst(nodep); } } void visit(AstNodeVarRef* nodep) override { @@ -460,7 +460,7 @@ private: VL_RESTORER(m_inBBox); { m_inBBox = true; - iterateChildren(nodep); + iterateChildrenConst(nodep); } } @@ -468,21 +468,21 @@ private: VL_RESTORER(m_inProcAssign); { m_inProcAssign = true; - iterateChildren(nodep); + iterateChildrenConst(nodep); } } void visit(AstAssignDly* nodep) override { VL_RESTORER(m_inProcAssign); { m_inProcAssign = true; - iterateChildren(nodep); + iterateChildrenConst(nodep); } } void visit(AstAssignW* nodep) override { VL_RESTORER(m_inContAssign); { m_inContAssign = true; - iterateChildren(nodep); + iterateChildrenConst(nodep); } } void visit(AstAlways* nodep) override { @@ -495,7 +495,7 @@ private: } else { m_alwaysCombp = nullptr; } - iterateChildren(nodep); + iterateChildrenConst(nodep); if (nodep->keyword() == VAlwaysKwd::ALWAYS_COMB) UINFO(9, " Done " << nodep << endl); } } @@ -504,13 +504,13 @@ private: VL_RESTORER(m_taskp); { m_taskp = nodep; - iterateChildren(nodep); + iterateChildrenConst(nodep); } } void visit(AstPin* nodep) override { VL_RESTORER(m_inInoutPin); m_inInoutPin = nodep->modVarp()->isInoutish(); - iterateChildren(nodep); + iterateChildrenConst(nodep); } // Until we support tables, primitives will have undriven and unused I/Os @@ -525,11 +525,11 @@ private: // iterate void visit(AstConst* nodep) override {} - void visit(AstNode* nodep) override { iterateChildren(nodep); } + void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } public: // CONSTRUCTORS - explicit UndrivenVisitor(AstNetlist* nodep) { iterate(nodep); } + explicit UndrivenVisitor(AstNetlist* nodep) { iterateConst(nodep); } ~UndrivenVisitor() override { for (UndrivenVarEntry* ip : m_entryps[1]) ip->reportViolations(); for (int usr = 1; usr < 3; ++usr) { From 5f02f95ce6ce4950ee9f45deb889e84ba0792724 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 18 Mar 2023 15:49:11 -0400 Subject: [PATCH 072/155] Commentary (#3906) (#3931) --- Changes | 1 - 1 file changed, 1 deletion(-) diff --git a/Changes b/Changes index 87cc38c96..849ff3ca8 100644 --- a/Changes +++ b/Changes @@ -50,7 +50,6 @@ Verilator 5.008 2023-03-04 * Support function calls without parenthesis (#3903) (#3902). [Ryszard Rozak, Antmicro Ltd] * Support class extending its parameter (#3904). [Ryszard Rozak, Antmicro Ltd] * Support static function variables (#3830). [Ryszard Rozak, Antmicro Ltd] -* Support vpiDefName (#3906) (#3931). [Andrew Nolte] * Support recursive methods (#3987). [Ryszard Rozak, Antmicro Ltd] * Fix real parameters of infinity and NaN. * Fix pattern assignment to unpacked structs (#3510). [Mostafa Garnal] From 895ab8789b61050c3048256e745853c9a9b0e87d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 18 Mar 2023 17:11:39 -0400 Subject: [PATCH 073/155] Internals: Fix recently added assertion false firing --- src/V3Task.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/V3Task.cpp b/src/V3Task.cpp index ea12eb5f3..a46b8932a 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -673,19 +673,25 @@ private: void unlinkAndClone(AstNodeFTask* funcp, AstNode* nodep, bool withNext) { UASSERT_OBJ(nodep, funcp, "null in function object clone"); - VNRelinker relinkHandle; - if (withNext) { - nodep->unlinkFrBackWithNext(&relinkHandle); - } else { - nodep->unlinkFrBack(&relinkHandle); - } if (funcp->recursive()) { + VNRelinker relinkHandle; + if (withNext) { + nodep->unlinkFrBackWithNext(&relinkHandle); + } else { + nodep->unlinkFrBack(&relinkHandle); + } // Recursive functions require the original argument list to // still be live for linking purposes. // The old function gets clone, so that node pointers are mostly // retained through the V3Task transformations AstNode* const newp = nodep->cloneTree(withNext); relinkHandle.relink(newp); + } else { + if (withNext) { + nodep->unlinkFrBackWithNext(); + } else { + nodep->unlinkFrBack(); + } } } From 2b21697b868a203b0184e2c321b6f8c62dfd9ee3 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 18 Mar 2023 17:26:36 -0400 Subject: [PATCH 074/155] Support class extends of package::class. --- Changes | 1 + src/V3LinkDot.cpp | 26 ++++++++++++++++-------- test_regress/t/t_class_extends2.out | 5 ----- test_regress/t/t_class_extends2.pl | 11 ++++++---- test_regress/t/t_class_extends_colon.out | 5 ----- test_regress/t/t_class_extends_colon.pl | 11 ++++++---- 6 files changed, 33 insertions(+), 26 deletions(-) delete mode 100644 test_regress/t/t_class_extends2.out delete mode 100644 test_regress/t/t_class_extends_colon.out diff --git a/Changes b/Changes index 849ff3ca8..e913ad400 100644 --- a/Changes +++ b/Changes @@ -17,6 +17,7 @@ Verilator 5.009 devel * Add --public-params flag (#3990). [Andrew Nolte] * Support complicated IEEE 'for' assignments. * Support $fopen as an expression. +* Support class extends of package::class. * Change ZERODLY to a warning. * Fix UNDRIVEN warning seg fault (#3989). [Felix Neumärker] * Fix symbol entries when inheriting classes (#3995) (#3996). [Krzysztof Boroński] diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 9a4cdffcd..05440ea5b 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -3272,17 +3272,26 @@ private: " (IEEE 1800-2017 8.13)"); } if (cextp->childDTypep() || cextp->dtypep()) continue; // Already converted - if (VN_IS(cextp->classOrPkgsp(), Dot)) { - itemp->v3warn(E_UNSUPPORTED, "Unsupported: Hierarchical class references"); - continue; + AstNode* cprp = cextp->classOrPkgsp(); + VSymEnt* lookSymp = m_curSymp; + if (AstDot* const dotp = VN_CAST(cextp->classOrPkgsp(), Dot)) { + dotp->user3(true); + if (AstClassOrPackageRef* lookNodep + = VN_CAST(dotp->lhsp(), ClassOrPackageRef)) { + iterate(lookNodep); + cprp = dotp->rhsp(); + lookSymp = m_statep->getNodeSym(lookNodep->classOrPackagep()); + } else { + dotp->lhsp()->v3error("Attempting to extend" // LCOV_EXCL_LINE + " using non-class under dot"); + } } - AstClassOrPackageRef* const cpackagerefp - = VN_CAST(cextp->classOrPkgsp(), ClassOrPackageRef); + AstClassOrPackageRef* const cpackagerefp = VN_CAST(cprp, ClassOrPackageRef); if (VL_UNCOVERABLE(!cpackagerefp)) { // Linking the extend gives an error before this is hit cextp->v3error("Attempting to extend using non-class"); // LCOV_EXCL_LINE } else { - VSymEnt* const foundp = m_curSymp->findIdFallback(cpackagerefp->name()); + VSymEnt* const foundp = lookSymp->findIdFallback(cpackagerefp->name()); if (foundp) { AstClassRefDType* classRefDtypep = nullptr; AstClass* classp = VN_CAST(foundp->nodep(), Class); @@ -3353,8 +3362,9 @@ private: if (!cextp->isImplements()) { m_curSymp->importFromClass(m_statep->symsp(), srcp); } - VL_DO_DANGLING(cpackagerefp->unlinkFrBack()->deleteTree(), - cpackagerefp); + VL_DO_DANGLING( + cextp->classOrPkgsp()->unlinkFrBack()->deleteTree(), + cpackagerefp); } } } else { diff --git a/test_regress/t/t_class_extends2.out b/test_regress/t/t_class_extends2.out deleted file mode 100644 index 9b587f905..000000000 --- a/test_regress/t/t_class_extends2.out +++ /dev/null @@ -1,5 +0,0 @@ -%Error-UNSUPPORTED: t/t_class_extends2.v:18:19: Unsupported: Hierarchical class references - 18 | class Ext extends Pkg::Base0; - | ^~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error: Exiting due to diff --git a/test_regress/t/t_class_extends2.pl b/test_regress/t/t_class_extends2.pl index 8a9b721f2..696e24d17 100755 --- a/test_regress/t/t_class_extends2.pl +++ b/test_regress/t/t_class_extends2.pl @@ -8,11 +8,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios(linter => 1); +scenarios(simulator => 1); -lint( - fails => $Self->{vlt}, - expect_filename => $Self->{golden_filename}, +compile( + make_flags => 'VM_PARALLEL_BUILDS=1', # bug2775 + ); + +execute( + check_finished => 1, ); ok(1); diff --git a/test_regress/t/t_class_extends_colon.out b/test_regress/t/t_class_extends_colon.out deleted file mode 100644 index ae67bbf79..000000000 --- a/test_regress/t/t_class_extends_colon.out +++ /dev/null @@ -1,5 +0,0 @@ -%Error-UNSUPPORTED: t/t_class_extends_colon.v:20:21: Unsupported: Hierarchical class references - 20 | class Cls12 extends Pkg::Icls1; - | ^~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error: Exiting due to diff --git a/test_regress/t/t_class_extends_colon.pl b/test_regress/t/t_class_extends_colon.pl index 8a9b721f2..696e24d17 100755 --- a/test_regress/t/t_class_extends_colon.pl +++ b/test_regress/t/t_class_extends_colon.pl @@ -8,11 +8,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios(linter => 1); +scenarios(simulator => 1); -lint( - fails => $Self->{vlt}, - expect_filename => $Self->{golden_filename}, +compile( + make_flags => 'VM_PARALLEL_BUILDS=1', # bug2775 + ); + +execute( + check_finished => 1, ); ok(1); From 9b869edd903f02199fa91644ab9db61a262c12ce Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 18 Mar 2023 19:28:48 -0400 Subject: [PATCH 075/155] Internals: Fix cppcheck warnings. No functional change. --- include/verilated.cpp | 1 - include/verilated.h | 1 + include/verilated_vpi.cpp | 2 -- src/V3AstNodeOther.h | 4 ++-- src/V3CCtors.cpp | 2 +- src/V3EmitCInlines.cpp | 2 +- src/V3Error.h | 3 +-- src/VlcSource.h | 2 +- src/VlcTop.cpp | 2 +- 9 files changed, 8 insertions(+), 11 deletions(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index 995656840..bcc4f65e8 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -1871,7 +1871,6 @@ IData VL_ATOI_N(const std::string& str, int base) VL_PURE { IData VL_NTOI_I(int obits, const std::string& str) VL_PURE { return VL_NTOI_Q(obits, str); } QData VL_NTOI_Q(int obits, const std::string& str) VL_PURE { QData out = 0; - const size_t procLen = std::min(str.length(), static_cast(8)); const char* const datap = str.data(); int pos = static_cast(str.length()) - 1; int bit = 0; diff --git a/include/verilated.h b/include/verilated.h index 822fc89fa..70c12f362 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -607,6 +607,7 @@ public: // But for internal use only VerilatedEvalMsgQueue* __Vm_evalMsgQp; explicit VerilatedSyms(VerilatedContext* contextp); // Pass null for default context ~VerilatedSyms(); + VL_UNCOPYABLE(VerilatedSyms); }; //=========================================================================== diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index 4c255ed79..4d84eca49 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -791,7 +791,6 @@ void VerilatedVpiImp::dumpCbs() VL_MT_UNSAFE_ONE { } for (auto& ifuture : s().m_nextCbs) { const QData time = ifuture.first.first; - const uint64_t id = ifuture.first.second; VerilatedVpiCbHolder& ho = ifuture.second; if (VL_UNLIKELY(!ho.invalid())) { VL_DBG_MSGF("- vpi: time=%" PRId64 "(NEXT) reason=%d=%s id=%" PRId64 "\n", time, @@ -802,7 +801,6 @@ void VerilatedVpiImp::dumpCbs() VL_MT_UNSAFE_ONE { } for (auto& ifuture : s().m_futureCbs) { const QData time = ifuture.first.first; - const uint64_t id = ifuture.first.second; VerilatedVpiCbHolder& ho = ifuture.second; if (VL_UNLIKELY(!ho.invalid())) { VL_DBG_MSGF("- vpi: time=%" PRId64 " reason=%d=%s id=%" PRId64 "\n", time, diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index ed0bf5098..a37d2abe7 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -863,8 +863,8 @@ public: : ASTGEN_SUPER_ClockingItem(fl) { m_direction = direction; this->skewp(skewp); - if (AstAssign* const assignp = VN_CAST(clockingDeclp, Assign)) { - this->assignp(assignp); + if (AstAssign* const clkAssignp = VN_CAST(clockingDeclp, Assign)) { + this->assignp(clkAssignp); } else { exprp(VN_AS(clockingDeclp, NodeExpr)); } diff --git a/src/V3CCtors.cpp b/src/V3CCtors.cpp index 216f8141e..bfe88f481 100644 --- a/src/V3CCtors.cpp +++ b/src/V3CCtors.cpp @@ -201,7 +201,7 @@ private: public: // CONSTRUCTORS - CCtorsVisitor(AstNode* nodep) { iterate(nodep); } + explicit CCtorsVisitor(AstNode* nodep) { iterate(nodep); } ~CCtorsVisitor() override = default; }; diff --git a/src/V3EmitCInlines.cpp b/src/V3EmitCInlines.cpp index 86da5ff14..e2603371e 100644 --- a/src/V3EmitCInlines.cpp +++ b/src/V3EmitCInlines.cpp @@ -64,5 +64,5 @@ public: void V3EmitC::emitcInlines() { UINFO(2, __FUNCTION__ << ": " << endl); - { EmitCInlines visitor{v3Global.rootp()}; } + { EmitCInlines{v3Global.rootp()}; } } diff --git a/src/V3Error.h b/src/V3Error.h index 4d7f3b1de..43ab1b696 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -259,8 +259,7 @@ public: // backwards compatibility inheritance-like warnings if (m_e == other) { return true; } if (other == V3ErrorCode::WIDTH) { - return (m_e == WIDTH || m_e == WIDTHEXPAND || m_e == WIDTHTRUNC - || m_e == WIDTHXZEXPAND); + return (m_e == WIDTHEXPAND || m_e == WIDTHTRUNC || m_e == WIDTHXZEXPAND); } if (other == V3ErrorCode::I_UNUSED) { return (m_e == UNUSEDGENVAR || m_e == UNUSEDPARAM || m_e == UNUSEDSIGNAL); diff --git a/src/VlcSource.h b/src/VlcSource.h index f08188e1e..788945787 100644 --- a/src/VlcSource.h +++ b/src/VlcSource.h @@ -43,7 +43,7 @@ private: public: // CONSTRUCTORS - VlcSourceCount(int lineno) + explicit VlcSourceCount(int lineno) : m_lineno{lineno} {} ~VlcSourceCount() = default; diff --git a/src/VlcTop.cpp b/src/VlcTop.cpp index 728813622..db60851b0 100644 --- a/src/VlcTop.cpp +++ b/src/VlcTop.cpp @@ -288,7 +288,7 @@ void VlcTop::annotateOutputFiles(const string& dirname) { const auto lit = lines.find(lineno); if (lit == lines.end()) { os << " " << line << '\n'; - } else if (lit != lines.end()) { + } else { VlcSourceCount& sc = lit->second; // UINFO(0,"Source // "< Date: Tue, 21 Mar 2023 01:44:11 +0100 Subject: [PATCH 076/155] Change range order warning from LITENDIAN to ASCRANGE (#4010) --- docs/guide/exe_verilator.rst | 6 +- docs/guide/warnings.rst | 34 ++-- docs/spelling.txt | 1 + src/V3Ast.h | 12 +- src/V3AstInlines.h | 4 +- src/V3AstNodeDType.h | 6 +- src/V3AstNodeOther.h | 2 +- src/V3AstNodes.cpp | 2 +- src/V3Error.h | 15 +- src/V3Inst.cpp | 14 +- src/V3Slice.cpp | 13 +- src/V3SplitVar.cpp | 6 +- src/V3Undriven.cpp | 2 +- src/V3Width.cpp | 21 ++- src/V3WidthSel.cpp | 33 ++-- test_regress/t/t_array_backw_index_bad.out | 8 +- test_regress/t/t_array_packed_endian.v | 12 +- test_regress/t/t_array_packed_sysfunct.v | 108 +++++------ test_regress/t/t_array_packed_write_read.v | 168 +++++++++--------- test_regress/t/t_array_pattern_packed.v | 110 ++++++------ test_regress/t/t_array_pattern_unpacked.v | 2 +- test_regress/t/t_array_query.v | 4 +- test_regress/t/t_array_rev.v | 4 +- test_regress/t/t_clk_concat3.v | 2 +- test_regress/t/t_dist_warn_coverage.pl | 2 +- test_regress/t/t_foreach.v | 2 +- test_regress/t/t_inst_array_connect.v | 2 +- test_regress/t/t_interface_array_nocolon.v | 8 +- .../t/t_interface_array_nocolon_bad.out | 20 +-- .../t/t_interface_array_nocolon_bad.v | 2 +- test_regress/t/t_lib_prot.v | 4 +- test_regress/t/t_lib_prot_secret.v | 4 +- test_regress/t/t_lint_historical.v | 2 +- test_regress/t/t_mem_fifo.v | 4 +- test_regress/t/t_mem_first.v | 4 +- test_regress/t/t_mem_multidim.v | 4 +- test_regress/t/t_mem_multiwire.v | 4 +- test_regress/t/t_metacmt_onoff.out | 18 +- test_regress/t/t_metacmt_onoff.v | 2 +- test_regress/t/t_mod_interface_array1.v | 4 +- test_regress/t/t_mod_interface_array2.v | 2 +- test_regress/t/t_param_module.v | 2 +- test_regress/t/t_param_repl.v | 4 +- test_regress/t/t_select_ascending.pl | 21 +++ test_regress/t/t_select_ascending.v | 75 ++++++++ test_regress/t/t_select_bad_msb.out | 10 +- test_regress/t/t_select_bad_range4.out | 2 +- test_regress/t/t_select_little_pack.v | 2 +- test_regress/t/t_split_var_0.v | 24 +-- test_regress/t/t_struct_packed_sysfunct.v | 36 ++-- test_regress/t/t_struct_packed_value_list.v | 94 +++++----- test_regress/t/t_struct_packed_write_read.v | 106 +++++------ test_regress/t/t_sys_readmem.v | 4 +- ...tendian.out => t_trace_ascendingrange.out} | 0 ...litendian.pl => t_trace_ascendingrange.pl} | 2 +- ...e_litendian.v => t_trace_ascendingrange.v} | 0 ...fst.out => t_trace_ascendingrange_fst.out} | 0 ...n_fst.pl => t_trace_ascendingrange_fst.pl} | 4 +- ....out => t_trace_ascendingrange_fst_sc.out} | 0 ...sc.pl => t_trace_ascendingrange_fst_sc.pl} | 4 +- test_regress/t/t_trace_public.v | 4 +- test_regress/t/t_typedef_array.v | 4 +- test_regress/t/t_vpi_var.v | 4 +- test_regress/t/t_vpi_var2.v | 4 +- 64 files changed, 596 insertions(+), 487 deletions(-) create mode 100755 test_regress/t/t_select_ascending.pl create mode 100644 test_regress/t/t_select_ascending.v rename test_regress/t/{t_trace_litendian.out => t_trace_ascendingrange.out} (100%) rename test_regress/t/{t_trace_litendian.pl => t_trace_ascendingrange.pl} (92%) rename test_regress/t/{t_trace_litendian.v => t_trace_ascendingrange.v} (100%) rename test_regress/t/{t_trace_litendian_fst.out => t_trace_ascendingrange_fst.out} (100%) rename test_regress/t/{t_trace_litendian_fst.pl => t_trace_ascendingrange_fst.pl} (88%) rename test_regress/t/{t_trace_litendian_fst_sc.out => t_trace_ascendingrange_fst_sc.out} (100%) rename test_regress/t/{t_trace_litendian_fst_sc.pl => t_trace_ascendingrange_fst_sc.pl} (94%) diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index 36ad7a6f4..604db0702 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -1514,9 +1514,9 @@ Summary: .. option:: -Wno-lint Disable all lint-related warning messages, and all style warnings. This is - equivalent to ``-Wno-ALWCOMBORDER -Wno-BSSPACE -Wno-CASEINCOMPLETE + equivalent to ``-Wno-ALWCOMBORDER -Wno-ASCRANGE -Wno-BSSPACE -Wno-CASEINCOMPLETE -Wno-CASEOVERLAP -Wno-CASEX -Wno-CASTCONST -Wno-CASEWITHX -Wno-CMPCONST -Wno-COLONPLUS - -Wno-IMPLICIT -Wno-IMPLICITSTATIC -Wno-LITENDIAN -Wno-PINCONNECTEMPTY + -Wno-IMPLICIT -Wno-IMPLICITSTATIC -Wno-PINCONNECTEMPTY -Wno-PINMISSING -Wno-STATICVAR -Wno-SYNCASYNCNET -Wno-UNDRIVEN -Wno-UNSIGNED -Wno-UNUSEDGENVAR -Wno-UNUSEDPARAM -Wno-UNUSEDSIGNAL -Wno-WIDTH`` plus the list shown for Wno-style. @@ -1554,7 +1554,7 @@ Summary: enabled), but do not affect style messages. This is equivalent to ``-Wwarn-ALWCOMBORDER -Wwarn-BSSPACE -Wwarn-CASEINCOMPLETE -Wwarn-CASEOVERLAP -Wwarn-CASEX -Wwarn-CASTCONST -Wwarn-CASEWITHX -Wwarn-CMPCONST - -Wwarn-COLONPLUS -Wwarn-IMPLICIT -Wwarn-LITENDIAN + -Wwarn-COLONPLUS -Wwarn-IMPLICIT -Wwarn-ASCRANGE -Wwarn-PINMISSING -Wwarn-REALCVT -Wwarn-UNSIGNED -Wwarn-WIDTH``. .. option:: -Wwarn-style diff --git a/docs/guide/warnings.rst b/docs/guide/warnings.rst index 33763ec79..fe406c8a2 100644 --- a/docs/guide/warnings.rst +++ b/docs/guide/warnings.rst @@ -97,6 +97,24 @@ List Of Warnings simulate correctly. +.. option:: ASCRANGE + + .. TODO better example + + Warns that a packed vector is declared with ascending bit range + (i.e. [0:7]). Descending bit range is now the overwhelming standard, + and ascending ranges are now thus often due to simple oversight + instead of intent (a notable exception is the OpenPOWER code base). + + It also warns that an instance is declared with ascending range + (i.e. [0:7] or [7]) and is connected to an N-wide signal. + The bits will likely be in the reversed order from what people may expect + (i.e., instance [0] will connect to signal bit [N-1] not bit [0]). + + Ignoring this warning will only suppress the lint check; it will + simulate correctly. + + .. option:: ASSIGNDLY .. TODO better example @@ -850,18 +868,10 @@ List Of Warnings .. TODO better example - Warns that a packed vector is declared with big endian bit numbering - (i.e. [0:7]). Little endian bit numbering is now the overwhelming - standard, and big numbering is now thus often due to simple oversight - instead of intent. - - It also warns that an instance is declared with big endian range - (i.e. [0:7] or [7]) and is connected to an N-wide signal. - The bits will likely be backward from what people may expect - (i.e., instance [0] will connect to signal bit [N-1] not bit [0]). - - Ignoring this warning will only suppress the lint check; it will - simulate correctly. + The naming of this worning is in contradiction with the common + interpretation of little endian. It was therefore renamed to + :option:`ASCRANGE`. While :option:`LITENDIAN` remains for + backwards compatibility, new projects should use :option:`ASCRANGE`. .. option:: MINTYPMAX diff --git a/docs/spelling.txt b/docs/spelling.txt index 7d6a7c5d5..4f73b0a0e 100644 --- a/docs/spelling.txt +++ b/docs/spelling.txt @@ -532,6 +532,7 @@ endcelldefine endfunction endgenerate endian +endianness endif endmodule endprotect diff --git a/src/V3Ast.h b/src/V3Ast.h index cae837a51..ea3c1bb61 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1097,21 +1097,21 @@ public: } // VNumRange() = default; - VNumRange(int hi, int lo, bool littleEndian) { init(hi, lo, littleEndian); } + VNumRange(int hi, int lo, bool ascending) { init(hi, lo, ascending); } VNumRange(int left, int right) : m_left{left} , m_right{right} , m_ranged{true} {} ~VNumRange() = default; // MEMBERS - void init(int hi, int lo, bool littleEndian) { + void init(int hi, int lo, bool ascending) { if (lo > hi) { const int t = hi; hi = lo; lo = t; } - m_left = littleEndian ? lo : hi; - m_right = littleEndian ? hi : lo; + m_left = ascending ? lo : hi; + m_right = ascending ? hi : lo; m_ranged = true; } int left() const { return m_left; } @@ -1122,10 +1122,10 @@ public: int lo() const VL_MT_SAFE { return m_left > m_right ? m_right : m_left; } // How to show a declaration - int leftToRightInc() const { return littleEndian() ? 1 : -1; } + int leftToRightInc() const { return ascending() ? 1 : -1; } int elements() const VL_MT_SAFE { return hi() - lo() + 1; } bool ranged() const { return m_ranged; } - bool littleEndian() const { return m_left < m_right; } + bool ascending() const { return m_left < m_right; } int hiMaxSelect() const { return (lo() < 0 ? hi() - lo() : hi()); } // Maximum value a [] select may index diff --git a/src/V3AstInlines.h b/src/V3AstInlines.h index 31bb603c9..9ca54f137 100644 --- a/src/V3AstInlines.h +++ b/src/V3AstInlines.h @@ -123,8 +123,8 @@ int AstBasicDType::lo() const { return (rangep() ? rangep()->loConst() : m.m_nra int AstBasicDType::elements() const { return (rangep() ? rangep()->elementsConst() : m.m_nrange.elements()); } -bool AstBasicDType::littleEndian() const { - return (rangep() ? rangep()->littleEndian() : m.m_nrange.littleEndian()); +bool AstBasicDType::ascending() const { + return (rangep() ? rangep()->ascending() : m.m_nrange.ascending()); } bool AstActive::hasClocked() const { return m_sensesp->hasClocked(); } diff --git a/src/V3AstNodeDType.h b/src/V3AstNodeDType.h index 97eaacc5b..41c512617 100644 --- a/src/V3AstNodeDType.h +++ b/src/V3AstNodeDType.h @@ -468,9 +468,9 @@ public: inline int hi() const; inline int lo() const; inline int elements() const; - int left() const { return littleEndian() ? lo() : hi(); } // How to show a declaration - int right() const { return littleEndian() ? hi() : lo(); } - inline bool littleEndian() const; + int left() const { return ascending() ? lo() : hi(); } // How to show a declaration + int right() const { return ascending() ? hi() : lo(); } + inline bool ascending() const; bool implicit() const { return keyword() == VBasicDTypeKwd::LOGIC_IMPLICIT; } bool untyped() const { return keyword() == VBasicDTypeKwd::UNTYPED; } VNumRange declRange() const { return isRanged() ? VNumRange{left(), right()} : VNumRange{}; } diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index a37d2abe7..f137413fe 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -2349,7 +2349,7 @@ public: return l > r ? r : l; } int elementsConst() const VL_MT_STABLE { return hiConst() - loConst() + 1; } - bool littleEndian() const { return leftConst() < rightConst(); } + bool ascending() const { return leftConst() < rightConst(); } void dump(std::ostream& str) const override; virtual string emitC() { V3ERROR_NA_RETURN(""); } bool same(const AstNode* /*samep*/) const override { return true; } diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 0e09698e0..d9b8146ab 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1759,7 +1759,7 @@ void AstTypedef::dump(std::ostream& str) const { void AstNodeRange::dump(std::ostream& str) const { this->AstNode::dump(str); } void AstRange::dump(std::ostream& str) const { this->AstNodeRange::dump(str); - if (littleEndian()) str << " [LITTLE]"; + if (ascending()) str << " [ASCENDING]"; } void AstParamTypeDType::dump(std::ostream& str) const { this->AstNodeDType::dump(str); diff --git a/src/V3Error.h b/src/V3Error.h index 43ab1b696..b63dfdf2d 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -70,6 +70,7 @@ public: EC_FIRST_WARN, // Just a code so the program knows where to start warnings // ALWCOMBORDER, // Always_comb with unordered statements + ASCRANGE, // Ascending bit range vector ASSIGNDLY, // Assignment delays ASSIGNIN, // Assigning to input BADSTDPRAGMA, // Any error related to pragmas @@ -109,7 +110,7 @@ public: INITIALDLY, // Initial delayed statement INSECURE, // Insecure options LATCH, // Latch detected outside of always_latch block - LITENDIAN, // Little bit endian vector + LITENDIAN, // Little endian, renamed to ASCRANGE MINTYPMAXDLY, // Unsupported: min/typ/max delay expressions MODDUP, // Duplicate module MULTIDRIVEN, // Driven from multiple blocks @@ -183,7 +184,7 @@ public: "PORTSHORT", "UNSUPPORTED", "TASKNSVAR", "NEEDTIMINGOPT", "NOTIMING", // Warnings " EC_FIRST_WARN", - "ALWCOMBORDER", "ASSIGNDLY", "ASSIGNIN", "BADSTDPRAGMA", + "ALWCOMBORDER", "ASCRANGE", "ASSIGNDLY", "ASSIGNIN", "BADSTDPRAGMA", "BLKANDNBLK", "BLKLOOPINIT", "BLKSEQ", "BSSPACE", "CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CASTCONST", "CDCRSTLOGIC", "CLKDATA", "CMPCONST", "COLONPLUS", "COMBDLY", "CONTASSREG", @@ -228,12 +229,12 @@ public: } // Warnings that are lint only bool lintError() const VL_MT_SAFE { - return (m_e == ALWCOMBORDER || m_e == BSSPACE || m_e == CASEINCOMPLETE + return (m_e == ALWCOMBORDER || m_e == ASCRANGE || m_e == BSSPACE || m_e == CASEINCOMPLETE || m_e == CASEOVERLAP || m_e == CASEWITHX || m_e == CASEX || m_e == CASTCONST || m_e == CMPCONST || m_e == COLONPLUS || m_e == IMPLICIT || m_e == IMPLICITSTATIC - || m_e == LATCH || m_e == LITENDIAN || m_e == PINMISSING || m_e == REALCVT - || m_e == STATICVAR || m_e == UNSIGNED || m_e == WIDTH || m_e == WIDTHTRUNC - || m_e == WIDTHEXPAND || m_e == WIDTHXZEXPAND); + || m_e == LATCH || m_e == PINMISSING || m_e == REALCVT || m_e == STATICVAR + || m_e == UNSIGNED || m_e == WIDTH || m_e == WIDTHTRUNC || m_e == WIDTHEXPAND + || m_e == WIDTHXZEXPAND); } // Warnings that are style only bool styleError() const VL_MT_SAFE { @@ -251,7 +252,7 @@ public: V3ErrorCode renamedTo() const { // Return a new error this error has been renamed to - // e.g. if (m_e == LITENDIAN) return V3ErrorCode{RANGEASC}; + if (m_e == LITENDIAN) return V3ErrorCode{ASCRANGE}; return V3ErrorCode{EC_MIN}; // Not renamed; see isRenamed() } bool isRenamed() const { return renamedTo() != V3ErrorCode{EC_MIN}; } diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index 02db2fd98..74fe5d504 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -252,7 +252,7 @@ private: // Make all of the required clones for (int i = 0; i < m_cellRangep->elementsConst(); i++) { m_instSelNum - = m_cellRangep->littleEndian() ? (m_cellRangep->elementsConst() - 1 - i) : i; + = m_cellRangep->ascending() ? (m_cellRangep->elementsConst() - 1 - i) : i; const int instNum = m_cellRangep->loConst() + i; AstCell* const newp = nodep->cloneTree(false); @@ -331,7 +331,7 @@ private: // Connection to array, where array dimensions match the instant dimension const AstRange* const rangep = VN_AS(nodep->exprp()->dtypep(), UnpackArrayDType)->rangep(); - const int arraySelNum = rangep->littleEndian() + const int arraySelNum = rangep->ascending() ? (rangep->elementsConst() - 1 - m_instSelNum) : m_instSelNum; AstNodeExpr* exprp = VN_AS(nodep->exprp(), NodeExpr)->unlinkFrBack(); @@ -342,11 +342,11 @@ private: } else if (expwidth == modwidth * m_cellRangep->elementsConst()) { // Arrayed instants: one bit for each of the instants (each // assign is 1 modwidth wide) - if (m_cellRangep->littleEndian()) { - nodep->exprp()->v3warn(LITENDIAN, "Big endian instance range connecting to " - "vector: left < right of instance range: [" - << m_cellRangep->leftConst() << ":" - << m_cellRangep->rightConst() << "]"); + if (m_cellRangep->ascending()) { + nodep->exprp()->v3warn(ASCRANGE, "Ascending instance range connecting to " + "vector: left < right of instance range: [" + << m_cellRangep->leftConst() << ":" + << m_cellRangep->rightConst() << "]"); } AstNodeExpr* exprp = VN_AS(nodep->exprp(), NodeExpr)->unlinkFrBack(); const bool inputPin = nodep->modVarp()->isNonOutput(); diff --git a/src/V3Slice.cpp b/src/V3Slice.cpp index 17ad58852..4c5a392cd 100644 --- a/src/V3Slice.cpp +++ b/src/V3Slice.cpp @@ -90,7 +90,7 @@ class SliceVisitor final : public VNVisitor { AstNodeExpr* newp; if (const AstInitArray* const initp = VN_CAST(nodep, InitArray)) { UINFO(9, " cloneInitArray(" << elements << "," << offset << ") " << nodep << endl); - const int leOffset = !arrayp->rangep()->littleEndian() + const int leOffset = !arrayp->rangep()->ascending() ? arrayp->rangep()->elementsConst() - 1 - offset : offset; AstNodeExpr* const itemp = initp->getIndexDefaultedValuep(leOffset); @@ -107,14 +107,14 @@ class SliceVisitor final : public VNVisitor { } else if (const AstSliceSel* const snodep = VN_CAST(nodep, SliceSel)) { UINFO(9, " cloneSliceSel(" << elements << "," << offset << ") " << nodep << endl); const int leOffset = (snodep->declRange().lo() - + (!snodep->declRange().littleEndian() + + (!snodep->declRange().ascending() ? snodep->declRange().elements() - 1 - offset : offset)); newp = new AstArraySel{nodep->fileline(), snodep->fromp()->cloneTree(false), leOffset}; } else if (VN_IS(nodep, ArraySel) || VN_IS(nodep, NodeVarRef) || VN_IS(nodep, NodeSel) || VN_IS(nodep, CMethodHard) || VN_IS(nodep, MemberSel)) { UINFO(9, " cloneSel(" << elements << "," << offset << ") " << nodep << endl); - const int leOffset = !arrayp->rangep()->littleEndian() + const int leOffset = !arrayp->rangep()->ascending() ? arrayp->rangep()->elementsConst() - 1 - offset : offset; newp = new AstArraySel{nodep->fileline(), VN_AS(nodep, NodeExpr)->cloneTree(false), @@ -139,9 +139,10 @@ class SliceVisitor final : public VNVisitor { if (debug() >= 9) nodep->dumpTree("- Deslice-In: "); AstNodeDType* const dtp = nodep->lhsp()->dtypep()->skipRefp(); if (const AstUnpackArrayDType* const arrayp = VN_CAST(dtp, UnpackArrayDType)) { - // Left and right could have different msb/lsbs/endianness, but #elements is common - // and all variables are realigned to start at zero - // Assign of a little endian'ed slice to a big endian one must reverse the elements + // Left and right could have different ascending/descending range, + // but #elements is common and all variables are realigned to start at zero + // Assign of an ascending range slice to a descending range one must reverse the + // elements AstNodeAssign* newlistp = nullptr; const int elements = arrayp->rangep()->elementsConst(); for (int offset = 0; offset < elements; ++offset) { diff --git a/src/V3SplitVar.cpp b/src/V3SplitVar.cpp index 43af5a4a2..4550ee310 100644 --- a/src/V3SplitVar.cpp +++ b/src/V3SplitVar.cpp @@ -591,7 +591,7 @@ class SplitUnpackedVarVisitor final : public VNVisitor, public SplitVarImpl { // restore the original decl range here. const VNumRange selRange{nodep->declRange().hi() + dtypep->declRange().lo(), nodep->declRange().lo() + dtypep->declRange().lo(), - nodep->declRange().littleEndian()}; + nodep->declRange().ascending()}; UASSERT_OBJ(dtypep->lo() <= selRange.lo() && selRange.hi() <= dtypep->hi(), nodep, "Range check for AstSliceSel must have been finished in V3Width.cpp"); UINFO(4, "add " << nodep << " for " << refp->varp()->prettyName() << "\n"); @@ -1071,7 +1071,7 @@ class SplitPackedVarVisitor final : public VNVisitor, public SplitVarImpl { for (SplitNewVar& newvar : vars) { int left = newvar.msb(); int right = newvar.lsb(); - if (basicp->littleEndian()) std::swap(left, right); + if (basicp->ascending()) std::swap(left, right); const std::string name = (left == right) ? varp->name() + "__BRA__" + AstNode::encodeNumber(left) + "__KET__" @@ -1091,7 +1091,7 @@ class SplitPackedVarVisitor final : public VNVisitor, public SplitVarImpl { default: UASSERT_OBJ(false, basicp, "Only bit and logic are allowed"); } dtypep->rangep(new AstRange{ - varp->fileline(), VNumRange{newvar.msb(), newvar.lsb(), basicp->littleEndian()}}); + varp->fileline(), VNumRange{newvar.msb(), newvar.lsb(), basicp->ascending()}}); newvar.varp(new AstVar{varp->fileline(), VVarType::VAR, name, dtypep}); newvar.varp()->propagateAttrFrom(varp); newvar.varp()->funcLocal(varp->isFuncLocal() || varp->isFuncReturn()); diff --git a/src/V3Undriven.cpp b/src/V3Undriven.cpp index af60b39a0..84e7aba35 100644 --- a/src/V3Undriven.cpp +++ b/src/V3Undriven.cpp @@ -101,7 +101,7 @@ private: if (lsb == msb) { bits += cvtToStr(lsb + bdtypep->lo()); } else { - if (bdtypep->littleEndian()) { + if (bdtypep->ascending()) { bits += cvtToStr(lsb + bdtypep->lo()) + ":" + cvtToStr(msb + bdtypep->lo()); } else { diff --git a/src/V3Width.cpp b/src/V3Width.cpp index d6fde7ff4..726b209a4 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -858,11 +858,11 @@ private: << std::hex << width); } // Note width() not set on range; use elementsConst() - if (nodep->littleEndian() && !VN_IS(nodep->backp(), UnpackArrayDType) + if (nodep->ascending() && !VN_IS(nodep->backp(), UnpackArrayDType) && !VN_IS(nodep->backp(), Cell)) { // For cells we warn in V3Inst - nodep->v3warn(LITENDIAN, "Big bit endian vector: left < right of bit range: [" - << nodep->leftConst() << ":" << nodep->rightConst() - << "]"); + nodep->v3warn(ASCRANGE, "Ascending bit range vector: left < right of bit range: [" + << nodep->leftConst() << ":" << nodep->rightConst() + << "]"); } } } @@ -1101,18 +1101,18 @@ private: // Add subtracted value to get the original range const VNumRange declRange{nodep->declRange().hi() + subtracted, nodep->declRange().lo() + subtracted, - nodep->declRange().littleEndian()}; + nodep->declRange().ascending()}; if ((declRange.hi() > adtypep->declRange().hi()) || declRange.lo() < adtypep->declRange().lo()) { // Other simulators warn too nodep->v3error("Slice selection index '" << declRange << "'" << " outside data type's '" << adtypep->declRange() << "'"); - } else if ((declRange.littleEndian() != adtypep->declRange().littleEndian()) + } else if ((declRange.ascending() != adtypep->declRange().ascending()) && declRange.hi() != declRange.lo()) { nodep->v3error("Slice selection '" << declRange << "'" - << " has backward indexing versus data type's '" + << " has reversed range order versus data type's '" << adtypep->declRange() << "'"); } } @@ -6351,9 +6351,8 @@ private: constp->fileline(), lhsDTypep, new AstConst{constp->fileline(), AstConst::WidthedValue{}, 8, 0}}; for (int aindex = arrayp->lo(); aindex <= arrayp->hi(); ++aindex) { - int cindex = arrayp->declRange().littleEndian() - ? (arrayp->hi() - aindex) - : (aindex - arrayp->lo()); + int cindex = arrayp->declRange().ascending() ? (arrayp->hi() - aindex) + : (aindex - arrayp->lo()); V3Number selected{constp, 8}; selected.opSel(constp->num(), cindex * 8 + 7, cindex * 8); UINFO(0, " aindex=" << aindex << " cindex=" << cindex @@ -6970,7 +6969,7 @@ private: case VAttrType::DIM_LOW: val = !declRange.ranged() ? 0 : declRange.lo(); break; case VAttrType::DIM_RIGHT: val = !declRange.ranged() ? 0 : declRange.right(); break; case VAttrType::DIM_INCREMENT: - val = (declRange.ranged() && declRange.littleEndian()) ? -1 : 1; + val = (declRange.ranged() && declRange.ascending()) ? -1 : 1; break; case VAttrType::DIM_SIZE: val = !declRange.ranged() ? 0 : declRange.elements(); break; default: nodep->v3fatalSrc("Missing DIM ATTR type case"); break; diff --git a/src/V3WidthSel.cpp b/src/V3WidthSel.cpp index 20b2741b7..a4a1628b3 100644 --- a/src/V3WidthSel.cpp +++ b/src/V3WidthSel.cpp @@ -19,7 +19,7 @@ // Replace SELEXTRACT with SEL // Replace SELBIT with SEL or ARRAYSEL // -// This code was once in V3LinkResolve, but little endian bit vectors won't +// This code was once in V3LinkResolve, but ascending bit range vectors won't // work that early. It was considered for V3Width and V3Param, but is // fairly ugly both places as the nodes change in too strongly // interconnected ways. @@ -162,7 +162,7 @@ private: // vector without range, or 0 lsb is ok, for example a INTEGER x; y = x[21:0]; return underp; } else { - if (fromRange.littleEndian()) { + if (fromRange.ascending()) { // reg [1:3] was swapped to [3:1] (lsbEndianedp==3) and needs a SUB(3,under) return newSubNeg(fromRange.hi(), underp); } else { @@ -180,7 +180,7 @@ private: } else { // Need a slice data type, which is an array of the extracted // type, but with (presumably) different size - const VNumRange newRange{msb, lsb, nodep->declRange().littleEndian()}; + const VNumRange newRange{msb, lsb, nodep->declRange().ascending()}; AstNodeDType* const vardtypep = new AstPackArrayDType{nodep->fileline(), nodep->subDTypep(), // Need to strip off array reference @@ -227,7 +227,7 @@ private: } else if (const AstPackArrayDType* const adtypep = VN_CAST(ddtypep, PackArrayDType)) { // SELBIT(array, index) -> SEL(array, index*width-of-subindex, width-of-subindex) AstNodeExpr* subp = rhsp; - if (fromRange.littleEndian()) { + if (fromRange.ascending()) { subp = newSubNeg(fromRange.hi(), subp); } else { subp = newSubNeg(subp, fromRange.lo()); @@ -375,8 +375,8 @@ private: adtypep, "Array extraction with width miscomputed " << adtypep->width() << "/" << fromRange.elements()); - if (fromRange.littleEndian()) { - // Below code assumes big bit endian; just works out if we swap + if (fromRange.ascending()) { + // Below code assumes descending bit range; just works out if we swap const int x = msb; msb = lsb; lsb = x; @@ -385,7 +385,7 @@ private: nodep->v3warn( SELRANGE, "[" << msb << ":" << lsb - << "] Range extract has backward bit ordering, perhaps you wanted [" << lsb + << "] Slice range has ascending bit ordering, perhaps you wanted [" << lsb << ":" << msb << "]"); const int x = msb; msb = lsb; @@ -405,8 +405,8 @@ private: nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } else if (VN_IS(ddtypep, BasicDType)) { - if (fromRange.littleEndian()) { - // Below code assumes big bit endian; just works out if we swap + if (fromRange.ascending()) { + // Below code assumes descending bit range; just works out if we swap const int x = msb; msb = lsb; lsb = x; @@ -415,7 +415,7 @@ private: nodep->v3warn( SELRANGE, "[" << msb << ":" << lsb - << "] Range extract has backward bit ordering, perhaps you wanted [" << lsb + << "] Slice range has ascending bit ordering, perhaps you wanted [" << lsb << ":" << msb << "]"); const int x = msb; msb = lsb; @@ -432,12 +432,12 @@ private: nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } else if (VN_IS(ddtypep, NodeUOrStructDType)) { - // Classes aren't little endian + // Classes don't have an ascending range if (lsb > msb) { nodep->v3warn( SELRANGE, "[" << msb << ":" << lsb - << "] Range extract has backward bit ordering, perhaps you wanted [" << lsb + << "] Slice range has ascending bit ordering, perhaps you wanted [" << lsb << ":" << msb << "]"); const int x = msb; msb = lsb; @@ -485,7 +485,8 @@ private: V3Width::widthParamsEdit(nodep->rhsp()); // constifyEdit doesn't ensure widths finished V3Const::constifyEdit(nodep->rhsp()); // May relink pointed to node, ok if not const V3Const::constifyParamsEdit(nodep->thsp()); // May relink pointed to node - checkConstantOrReplace(nodep->thsp(), "Width of :+ or :- bit extract isn't a constant"); + checkConstantOrReplace(nodep->thsp(), + "Width of :+ or :- bit slice range isn't a constant"); if (debug() >= 9) nodep->dumpTree("- SELPM3: "); // Now replace it with an AstSel AstNodeExpr* const fromp = nodep->fromp()->unlinkFrBack(); @@ -521,7 +522,7 @@ private: const int32_t msb = VN_IS(nodep, SelPlus) ? rhs + width - 1 : rhs; const int32_t lsb = VN_IS(nodep, SelPlus) ? rhs : rhs - width + 1; AstSliceSel* const newp = new AstSliceSel{ - nodep->fileline(), fromp, VNumRange{msb, lsb, fromRange.littleEndian()}}; + nodep->fileline(), fromp, VNumRange{msb, lsb, fromRange.ascending()}}; nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } else { @@ -539,7 +540,7 @@ private: } AstNodeExpr* newlsbp = nullptr; if (VN_IS(nodep, SelPlus)) { - if (fromRange.littleEndian()) { + if (fromRange.ascending()) { // SELPLUS(from,lsb,width) -> SEL(from, (vector_msb-width+1)-sel, width) newlsbp = newSubNeg((fromRange.hi() - width + 1), rhsp); } else { @@ -547,7 +548,7 @@ private: newlsbp = newSubNeg(rhsp, fromRange.lo()); } } else if (VN_IS(nodep, SelMinus)) { - if (fromRange.littleEndian()) { + if (fromRange.ascending()) { // SELMINUS(from,msb,width) -> SEL(from, msb-[bit]) newlsbp = newSubNeg(fromRange.hi(), rhsp); } else { diff --git a/test_regress/t/t_array_backw_index_bad.out b/test_regress/t/t_array_backw_index_bad.out index 83ee4b870..f49d74019 100644 --- a/test_regress/t/t_array_backw_index_bad.out +++ b/test_regress/t/t_array_backw_index_bad.out @@ -1,16 +1,16 @@ -%Error: t/t_array_backw_index_bad.v:17:19: Slice selection '[1:3]' has backward indexing versus data type's '[3:0]' +%Error: t/t_array_backw_index_bad.v:17:19: Slice selection '[1:3]' has reversed range order versus data type's '[3:0]' : ... In instance t 17 | array_assign[1:3] = '{32'd4, 32'd3, 32'd2}; | ^ -%Error: t/t_array_backw_index_bad.v:18:20: Slice selection '[3:1]' has backward indexing versus data type's '[0:3]' +%Error: t/t_array_backw_index_bad.v:18:20: Slice selection '[3:1]' has reversed range order versus data type's '[0:3]' : ... In instance t 18 | larray_assign[3:1] = '{32'd4, 32'd3, 32'd2}; | ^ -%Error: t/t_array_backw_index_bad.v:19:20: Slice selection '[4:6]' has backward indexing versus data type's '[6:3]' +%Error: t/t_array_backw_index_bad.v:19:20: Slice selection '[4:6]' has reversed range order versus data type's '[6:3]' : ... In instance t 19 | array_assign2[4:6] = '{32'd4, 32'd3, 32'd2}; | ^ -%Error: t/t_array_backw_index_bad.v:20:21: Slice selection '[6:4]' has backward indexing versus data type's '[3:6]' +%Error: t/t_array_backw_index_bad.v:20:21: Slice selection '[6:4]' has reversed range order versus data type's '[3:6]' : ... In instance t 20 | larray_assign2[6:4] = '{32'd4, 32'd3, 32'd2}; | ^ diff --git a/test_regress/t/t_array_packed_endian.v b/test_regress/t/t_array_packed_endian.v index 5a4fa03f0..a0f3300ff 100644 --- a/test_regress/t/t_array_packed_endian.v +++ b/test_regress/t/t_array_packed_endian.v @@ -12,27 +12,27 @@ typedef struct packed { } tb_t; typedef struct packed { - // verilator lint_off LITENDIAN + // verilator lint_off ASCRANGE logic [0:7] a; - // verilator lint_on LITENDIAN + // verilator lint_on ASCRANGE } tl_t; typedef struct packed { logic [7:0] bb; - // verilator lint_off LITENDIAN + // verilator lint_off ASCRANGE tb_t [0:1] cbl; tb_t [1:0] cbb; tl_t [0:1] cll; tl_t [1:0] clb; logic [0:7] dl; - // verilator lint_on LITENDIAN + // verilator lint_on ASCRANGE } t2; logic [2:0][31:0] test2l; -// verilator lint_off LITENDIAN +// verilator lint_off ASCRANGE logic [0:2][31:0] test2b; logic [0:2][31:0] test1b; -// verilator lint_on LITENDIAN +// verilator lint_on ASCRANGE logic [2:0][31:0] test1l; module t; diff --git a/test_regress/t/t_array_packed_sysfunct.v b/test_regress/t/t_array_packed_sysfunct.v index 2c3c7520f..4a8ce3f9a 100644 --- a/test_regress/t/t_array_packed_sysfunct.v +++ b/test_regress/t/t_array_packed_sysfunct.v @@ -19,10 +19,10 @@ module t (/*AUTOARG*/ localparam WC = 8; // 2D packed arrays - logic [WA+1:2] [WB+1:2] [WC+1:2] array_bg; // big endian array - /* verilator lint_off LITENDIAN */ - logic [2:WA+1] [2:WB+1] [2:WC+1] array_lt; // little endian array - /* verilator lint_on LITENDIAN */ + logic [WA+1:2] [WB+1:2] [WC+1:2] array_dsc; // descending range array + /* verilator lint_off ASCRANGE */ + logic [2:WA+1] [2:WB+1] [2:WC+1] array_asc; // ascending range array + /* verilator lint_on ASCRANGE */ logic [1:0] array_unpk [3:2][1:0]; @@ -83,84 +83,84 @@ module t (/*AUTOARG*/ $write("cnt[30:4]=%0d slc=%0d dim=%0d wdt=%0d\n", cnt[30:4], slc, dim, wdt); `endif if (cnt[30:4]==1) begin - // big endian + // descending range if (slc==0) begin // full array - `checkh($dimensions (array_bg), 3); - `checkh($bits (array_bg), WA*WB*WC); + `checkh($dimensions (array_dsc), 3); + `checkh($bits (array_dsc), WA*WB*WC); if ((dim>=1)&&(dim<=3)) begin - `checkh($left (array_bg, dim), wdt+1); - `checkh($right (array_bg, dim), 2 ); - `checkh($low (array_bg, dim), 2 ); - `checkh($high (array_bg, dim), wdt+1); - `checkh($increment (array_bg, dim), 1 ); - `checkh($size (array_bg, dim), wdt ); + `checkh($left (array_dsc, dim), wdt+1); + `checkh($right (array_dsc, dim), 2 ); + `checkh($low (array_dsc, dim), 2 ); + `checkh($high (array_dsc, dim), wdt+1); + `checkh($increment (array_dsc, dim), 1 ); + `checkh($size (array_dsc, dim), wdt ); end end else if (slc==1) begin // single array element - `checkh($dimensions (array_bg[2]), 2); - `checkh($bits (array_bg[2]), WB*WC); + `checkh($dimensions (array_dsc[2]), 2); + `checkh($bits (array_dsc[2]), WB*WC); if ((dim>=2)&&(dim<=3)) begin - `checkh($left (array_bg[2], dim-1), wdt+1); - `checkh($right (array_bg[2], dim-1), 2 ); - `checkh($low (array_bg[2], dim-1), 2 ); - `checkh($high (array_bg[2], dim-1), wdt+1); - `checkh($increment (array_bg[2], dim-1), 1 ); - `checkh($size (array_bg[2], dim-1), wdt ); + `checkh($left (array_dsc[2], dim-1), wdt+1); + `checkh($right (array_dsc[2], dim-1), 2 ); + `checkh($low (array_dsc[2], dim-1), 2 ); + `checkh($high (array_dsc[2], dim-1), wdt+1); + `checkh($increment (array_dsc[2], dim-1), 1 ); + `checkh($size (array_dsc[2], dim-1), wdt ); end `ifndef VERILATOR // Unsupported slices don't maintain size correctly end else if (slc==2) begin // half array - `checkh($dimensions (array_bg[WA/2+1:2]), 3); - `checkh($bits (array_bg[WA/2+1:2]), WA/2*WB*WC); + `checkh($dimensions (array_dsc[WA/2+1:2]), 3); + `checkh($bits (array_dsc[WA/2+1:2]), WA/2*WB*WC); if ((dim>=1)&&(dim<=3)) begin - `checkh($left (array_bg[WA/2+1:2], dim), wdt+1); - `checkh($right (array_bg[WA/2+1:2], dim), 2 ); - `checkh($low (array_bg[WA/2+1:2], dim), 2 ); - `checkh($high (array_bg[WA/2+1:2], dim), wdt+1); - `checkh($increment (array_bg[WA/2+1:2], dim), 1 ); - `checkh($size (array_bg[WA/2+1:2], dim), wdt); + `checkh($left (array_dsc[WA/2+1:2], dim), wdt+1); + `checkh($right (array_dsc[WA/2+1:2], dim), 2 ); + `checkh($low (array_dsc[WA/2+1:2], dim), 2 ); + `checkh($high (array_dsc[WA/2+1:2], dim), wdt+1); + `checkh($increment (array_dsc[WA/2+1:2], dim), 1 ); + `checkh($size (array_dsc[WA/2+1:2], dim), wdt); end `endif end end else if (cnt[30:4]==2) begin - // little endian + // ascending range if (slc==0) begin // full array - `checkh($dimensions (array_lt), 3); - `checkh($bits (array_lt), WA*WB*WC); + `checkh($dimensions (array_asc), 3); + `checkh($bits (array_asc), WA*WB*WC); if ((dim>=1)&&(dim<=3)) begin - `checkh($left (array_lt, dim), 2 ); - `checkh($right (array_lt, dim), wdt+1); - `checkh($low (array_lt, dim), 2 ); - `checkh($high (array_lt, dim), wdt+1); - `checkh($increment (array_lt, dim), -1 ); - `checkh($size (array_lt, dim), wdt ); + `checkh($left (array_asc, dim), 2 ); + `checkh($right (array_asc, dim), wdt+1); + `checkh($low (array_asc, dim), 2 ); + `checkh($high (array_asc, dim), wdt+1); + `checkh($increment (array_asc, dim), -1 ); + `checkh($size (array_asc, dim), wdt ); end end else if (slc==1) begin // single array element - `checkh($dimensions (array_lt[2]), 2); - `checkh($bits (array_lt[2]), WB*WC); + `checkh($dimensions (array_asc[2]), 2); + `checkh($bits (array_asc[2]), WB*WC); if ((dim>=2)&&(dim<=3)) begin - `checkh($left (array_lt[2], dim-1), 2 ); - `checkh($right (array_lt[2], dim-1), wdt+1); - `checkh($low (array_lt[2], dim-1), 2 ); - `checkh($high (array_lt[2], dim-1), wdt+1); - `checkh($increment (array_lt[2], dim-1), -1 ); - `checkh($size (array_lt[2], dim-1), wdt ); + `checkh($left (array_asc[2], dim-1), 2 ); + `checkh($right (array_asc[2], dim-1), wdt+1); + `checkh($low (array_asc[2], dim-1), 2 ); + `checkh($high (array_asc[2], dim-1), wdt+1); + `checkh($increment (array_asc[2], dim-1), -1 ); + `checkh($size (array_asc[2], dim-1), wdt ); end `ifndef VERILATOR // Unsupported slices don't maintain size correctly end else if (slc==2) begin // half array - `checkh($dimensions (array_lt[2:WA/2+1]), 3); - `checkh($bits (array_lt[2:WA/2+1]), WA/2*WB*WC); + `checkh($dimensions (array_asc[2:WA/2+1]), 3); + `checkh($bits (array_asc[2:WA/2+1]), WA/2*WB*WC); if ((dim>=1)&&(dim<=3)) begin - `checkh($left (array_lt[2:WA/2+1], dim), 2 ); - `checkh($right (array_lt[2:WA/2+1], dim), wdt+1); - `checkh($low (array_lt[2:WA/2+1], dim), 2 ); - `checkh($high (array_lt[2:WA/2+1], dim), wdt+1); - `checkh($increment (array_lt[2:WA/2+1], dim), -1 ); - `checkh($size (array_lt[2:WA/2+1], dim), wdt ); + `checkh($left (array_asc[2:WA/2+1], dim), 2 ); + `checkh($right (array_asc[2:WA/2+1], dim), wdt+1); + `checkh($low (array_asc[2:WA/2+1], dim), 2 ); + `checkh($high (array_asc[2:WA/2+1], dim), wdt+1); + `checkh($increment (array_asc[2:WA/2+1], dim), -1 ); + `checkh($size (array_asc[2:WA/2+1], dim), wdt ); end `endif end diff --git a/test_regress/t/t_array_packed_write_read.v b/test_regress/t/t_array_packed_write_read.v index 0da8351b4..1e2bf3d15 100644 --- a/test_regress/t/t_array_packed_write_read.v +++ b/test_regress/t/t_array_packed_write_read.v @@ -18,10 +18,10 @@ module t (/*AUTOARG*/ localparam NO = 10; // number of access events // 2D packed arrays - logic [WA-1:0] [WB-1:0] array_bg; // big endian array - /* verilator lint_off LITENDIAN */ - logic [0:WA-1] [0:WB-1] array_lt; // little endian array - /* verilator lint_on LITENDIAN */ + logic [WA-1:0] [WB-1:0] array_dsc; // descending range array + /* verilator lint_off ASCRANGE */ + logic [0:WA-1] [0:WB-1] array_asc; // ascending range array + /* verilator lint_on ASCRANGE */ integer cnt = 0; @@ -41,108 +41,108 @@ module t (/*AUTOARG*/ $finish; end - // big endian + // descending range always @ (posedge clk) if (cnt[1:0]==2'd0) begin // initialize to defaaults (all bits to 0) - if (cnt[30:2]==0) array_bg <= '0; - else if (cnt[30:2]==1) array_bg <= '0; - else if (cnt[30:2]==2) array_bg <= '0; - else if (cnt[30:2]==3) array_bg <= '0; - else if (cnt[30:2]==4) array_bg <= '0; - else if (cnt[30:2]==5) array_bg <= '0; - else if (cnt[30:2]==6) array_bg <= '0; - else if (cnt[30:2]==7) array_bg <= '0; - else if (cnt[30:2]==8) array_bg <= '0; - else if (cnt[30:2]==9) array_bg <= '0; + if (cnt[30:2]==0) array_dsc <= '0; + else if (cnt[30:2]==1) array_dsc <= '0; + else if (cnt[30:2]==2) array_dsc <= '0; + else if (cnt[30:2]==3) array_dsc <= '0; + else if (cnt[30:2]==4) array_dsc <= '0; + else if (cnt[30:2]==5) array_dsc <= '0; + else if (cnt[30:2]==6) array_dsc <= '0; + else if (cnt[30:2]==7) array_dsc <= '0; + else if (cnt[30:2]==8) array_dsc <= '0; + else if (cnt[30:2]==9) array_dsc <= '0; end else if (cnt[1:0]==2'd1) begin // write value to array if (cnt[30:2]==0) begin end - else if (cnt[30:2]==1) array_bg <= {WA *WB +0{1'b1}}; - else if (cnt[30:2]==2) array_bg [WA/2-1:0 ] <= {WA/2*WB +0{1'b1}}; - else if (cnt[30:2]==3) array_bg [WA -1:WA/2] <= {WA/2*WB +0{1'b1}}; - else if (cnt[30:2]==4) array_bg [ 0 ] <= {1 *WB +0{1'b1}}; - else if (cnt[30:2]==5) array_bg [WA -1 ] <= {1 *WB +0{1'b1}}; - else if (cnt[30:2]==6) array_bg [ 0 ][WB/2-1:0 ] <= {1 *WB/2+0{1'b1}}; - else if (cnt[30:2]==7) array_bg [WA -1 ][WB -1:WB/2] <= {1 *WB/2+0{1'b1}}; - else if (cnt[30:2]==8) array_bg [ 0 ][ 0 ] <= {1 *1 +0{1'b1}}; - else if (cnt[30:2]==9) array_bg [WA -1 ][WB -1 ] <= {1 *1 +0{1'b1}}; + else if (cnt[30:2]==1) array_dsc <= {WA *WB +0{1'b1}}; + else if (cnt[30:2]==2) array_dsc [WA/2-1:0 ] <= {WA/2*WB +0{1'b1}}; + else if (cnt[30:2]==3) array_dsc [WA -1:WA/2] <= {WA/2*WB +0{1'b1}}; + else if (cnt[30:2]==4) array_dsc [ 0 ] <= {1 *WB +0{1'b1}}; + else if (cnt[30:2]==5) array_dsc [WA -1 ] <= {1 *WB +0{1'b1}}; + else if (cnt[30:2]==6) array_dsc [ 0 ][WB/2-1:0 ] <= {1 *WB/2+0{1'b1}}; + else if (cnt[30:2]==7) array_dsc [WA -1 ][WB -1:WB/2] <= {1 *WB/2+0{1'b1}}; + else if (cnt[30:2]==8) array_dsc [ 0 ][ 0 ] <= {1 *1 +0{1'b1}}; + else if (cnt[30:2]==9) array_dsc [WA -1 ][WB -1 ] <= {1 *1 +0{1'b1}}; end else if (cnt[1:0]==2'd2) begin // check array value - if (cnt[30:2]==0) begin if (array_bg !== 64'b0000000000000000000000000000000000000000000000000000000000000000) begin $display("%b", array_bg); $stop(); end end - else if (cnt[30:2]==1) begin if (array_bg !== 64'b1111111111111111111111111111111111111111111111111111111111111111) begin $display("%b", array_bg); $stop(); end end - else if (cnt[30:2]==2) begin if (array_bg !== 64'b0000000000000000000000000000000011111111111111111111111111111111) begin $display("%b", array_bg); $stop(); end end - else if (cnt[30:2]==3) begin if (array_bg !== 64'b1111111111111111111111111111111100000000000000000000000000000000) begin $display("%b", array_bg); $stop(); end end - else if (cnt[30:2]==4) begin if (array_bg !== 64'b0000000000000000000000000000000000000000000000000000000011111111) begin $display("%b", array_bg); $stop(); end end - else if (cnt[30:2]==5) begin if (array_bg !== 64'b1111111100000000000000000000000000000000000000000000000000000000) begin $display("%b", array_bg); $stop(); end end - else if (cnt[30:2]==6) begin if (array_bg !== 64'b0000000000000000000000000000000000000000000000000000000000001111) begin $display("%b", array_bg); $stop(); end end - else if (cnt[30:2]==7) begin if (array_bg !== 64'b1111000000000000000000000000000000000000000000000000000000000000) begin $display("%b", array_bg); $stop(); end end - else if (cnt[30:2]==8) begin if (array_bg !== 64'b0000000000000000000000000000000000000000000000000000000000000001) begin $display("%b", array_bg); $stop(); end end - else if (cnt[30:2]==9) begin if (array_bg !== 64'b1000000000000000000000000000000000000000000000000000000000000000) begin $display("%b", array_bg); $stop(); end end + if (cnt[30:2]==0) begin if (array_dsc !== 64'b0000000000000000000000000000000000000000000000000000000000000000) begin $display("%b", array_dsc); $stop(); end end + else if (cnt[30:2]==1) begin if (array_dsc !== 64'b1111111111111111111111111111111111111111111111111111111111111111) begin $display("%b", array_dsc); $stop(); end end + else if (cnt[30:2]==2) begin if (array_dsc !== 64'b0000000000000000000000000000000011111111111111111111111111111111) begin $display("%b", array_dsc); $stop(); end end + else if (cnt[30:2]==3) begin if (array_dsc !== 64'b1111111111111111111111111111111100000000000000000000000000000000) begin $display("%b", array_dsc); $stop(); end end + else if (cnt[30:2]==4) begin if (array_dsc !== 64'b0000000000000000000000000000000000000000000000000000000011111111) begin $display("%b", array_dsc); $stop(); end end + else if (cnt[30:2]==5) begin if (array_dsc !== 64'b1111111100000000000000000000000000000000000000000000000000000000) begin $display("%b", array_dsc); $stop(); end end + else if (cnt[30:2]==6) begin if (array_dsc !== 64'b0000000000000000000000000000000000000000000000000000000000001111) begin $display("%b", array_dsc); $stop(); end end + else if (cnt[30:2]==7) begin if (array_dsc !== 64'b1111000000000000000000000000000000000000000000000000000000000000) begin $display("%b", array_dsc); $stop(); end end + else if (cnt[30:2]==8) begin if (array_dsc !== 64'b0000000000000000000000000000000000000000000000000000000000000001) begin $display("%b", array_dsc); $stop(); end end + else if (cnt[30:2]==9) begin if (array_dsc !== 64'b1000000000000000000000000000000000000000000000000000000000000000) begin $display("%b", array_dsc); $stop(); end end end else if (cnt[1:0]==2'd3) begin // read value from array (not a very good test for now) - if (cnt[30:2]==0) begin if (array_bg !== {WA *WB {1'b0}}) $stop(); end - else if (cnt[30:2]==1) begin if (array_bg !== {WA *WB +0{1'b1}}) $stop(); end - else if (cnt[30:2]==2) begin if (array_bg [WA/2-1:0 ] !== {WA/2*WB +0{1'b1}}) $stop(); end - else if (cnt[30:2]==3) begin if (array_bg [WA -1:WA/2] !== {WA/2*WB +0{1'b1}}) $stop(); end - else if (cnt[30:2]==4) begin if (array_bg [ 0 ] !== {1 *WB +0{1'b1}}) $stop(); end - else if (cnt[30:2]==5) begin if (array_bg [WA -1 ] !== {1 *WB +0{1'b1}}) $stop(); end - else if (cnt[30:2]==6) begin if (array_bg [ 0 ][WB/2-1:0 ] !== {1 *WB/2+0{1'b1}}) $stop(); end - else if (cnt[30:2]==7) begin if (array_bg [WA -1 ][WB -1:WB/2] !== {1 *WB/2+0{1'b1}}) $stop(); end - else if (cnt[30:2]==8) begin if (array_bg [ 0 ][ 0 ] !== {1 *1 +0{1'b1}}) $stop(); end - else if (cnt[30:2]==9) begin if (array_bg [WA -1 ][WB -1 ] !== {1 *1 +0{1'b1}}) $stop(); end + if (cnt[30:2]==0) begin if (array_dsc !== {WA *WB {1'b0}}) $stop(); end + else if (cnt[30:2]==1) begin if (array_dsc !== {WA *WB +0{1'b1}}) $stop(); end + else if (cnt[30:2]==2) begin if (array_dsc [WA/2-1:0 ] !== {WA/2*WB +0{1'b1}}) $stop(); end + else if (cnt[30:2]==3) begin if (array_dsc [WA -1:WA/2] !== {WA/2*WB +0{1'b1}}) $stop(); end + else if (cnt[30:2]==4) begin if (array_dsc [ 0 ] !== {1 *WB +0{1'b1}}) $stop(); end + else if (cnt[30:2]==5) begin if (array_dsc [WA -1 ] !== {1 *WB +0{1'b1}}) $stop(); end + else if (cnt[30:2]==6) begin if (array_dsc [ 0 ][WB/2-1:0 ] !== {1 *WB/2+0{1'b1}}) $stop(); end + else if (cnt[30:2]==7) begin if (array_dsc [WA -1 ][WB -1:WB/2] !== {1 *WB/2+0{1'b1}}) $stop(); end + else if (cnt[30:2]==8) begin if (array_dsc [ 0 ][ 0 ] !== {1 *1 +0{1'b1}}) $stop(); end + else if (cnt[30:2]==9) begin if (array_dsc [WA -1 ][WB -1 ] !== {1 *1 +0{1'b1}}) $stop(); end end - // little endian + // ascending range always @ (posedge clk) if (cnt[1:0]==2'd0) begin // initialize to defaaults (all bits to 0) - if (cnt[30:2]==0) array_lt <= '0; - else if (cnt[30:2]==1) array_lt <= '0; - else if (cnt[30:2]==2) array_lt <= '0; - else if (cnt[30:2]==3) array_lt <= '0; - else if (cnt[30:2]==4) array_lt <= '0; - else if (cnt[30:2]==5) array_lt <= '0; - else if (cnt[30:2]==6) array_lt <= '0; - else if (cnt[30:2]==7) array_lt <= '0; - else if (cnt[30:2]==8) array_lt <= '0; - else if (cnt[30:2]==9) array_lt <= '0; + if (cnt[30:2]==0) array_asc <= '0; + else if (cnt[30:2]==1) array_asc <= '0; + else if (cnt[30:2]==2) array_asc <= '0; + else if (cnt[30:2]==3) array_asc <= '0; + else if (cnt[30:2]==4) array_asc <= '0; + else if (cnt[30:2]==5) array_asc <= '0; + else if (cnt[30:2]==6) array_asc <= '0; + else if (cnt[30:2]==7) array_asc <= '0; + else if (cnt[30:2]==8) array_asc <= '0; + else if (cnt[30:2]==9) array_asc <= '0; end else if (cnt[1:0]==2'd1) begin // write value to array if (cnt[30:2]==0) begin end - else if (cnt[30:2]==1) array_lt <= {WA *WB +0{1'b1}}; - else if (cnt[30:2]==2) array_lt [0 :WA/2-1] <= {WA/2*WB +0{1'b1}}; - else if (cnt[30:2]==3) array_lt [WA/2:WA -1] <= {WA/2*WB +0{1'b1}}; - else if (cnt[30:2]==4) array_lt [0 ] <= {1 *WB +0{1'b1}}; - else if (cnt[30:2]==5) array_lt [ WA -1] <= {1 *WB +0{1'b1}}; - else if (cnt[30:2]==6) array_lt [0 ][0 :WB/2-1] <= {1 *WB/2+0{1'b1}}; - else if (cnt[30:2]==7) array_lt [ WA -1][WB/2:WB -1] <= {1 *WB/2+0{1'b1}}; - else if (cnt[30:2]==8) array_lt [0 ][0 ] <= {1 *1 +0{1'b1}}; - else if (cnt[30:2]==9) array_lt [ WA -1][ WB -1] <= {1 *1 +0{1'b1}}; + else if (cnt[30:2]==1) array_asc <= {WA *WB +0{1'b1}}; + else if (cnt[30:2]==2) array_asc [0 :WA/2-1] <= {WA/2*WB +0{1'b1}}; + else if (cnt[30:2]==3) array_asc [WA/2:WA -1] <= {WA/2*WB +0{1'b1}}; + else if (cnt[30:2]==4) array_asc [0 ] <= {1 *WB +0{1'b1}}; + else if (cnt[30:2]==5) array_asc [ WA -1] <= {1 *WB +0{1'b1}}; + else if (cnt[30:2]==6) array_asc [0 ][0 :WB/2-1] <= {1 *WB/2+0{1'b1}}; + else if (cnt[30:2]==7) array_asc [ WA -1][WB/2:WB -1] <= {1 *WB/2+0{1'b1}}; + else if (cnt[30:2]==8) array_asc [0 ][0 ] <= {1 *1 +0{1'b1}}; + else if (cnt[30:2]==9) array_asc [ WA -1][ WB -1] <= {1 *1 +0{1'b1}}; end else if (cnt[1:0]==2'd2) begin // check array value - if (cnt[30:2]==0) begin if (array_lt !== 64'b0000000000000000000000000000000000000000000000000000000000000000) begin $display("%b", array_lt); $stop(); end end - else if (cnt[30:2]==1) begin if (array_lt !== 64'b1111111111111111111111111111111111111111111111111111111111111111) begin $display("%b", array_lt); $stop(); end end - else if (cnt[30:2]==2) begin if (array_lt !== 64'b1111111111111111111111111111111100000000000000000000000000000000) begin $display("%b", array_lt); $stop(); end end - else if (cnt[30:2]==3) begin if (array_lt !== 64'b0000000000000000000000000000000011111111111111111111111111111111) begin $display("%b", array_lt); $stop(); end end - else if (cnt[30:2]==4) begin if (array_lt !== 64'b1111111100000000000000000000000000000000000000000000000000000000) begin $display("%b", array_lt); $stop(); end end - else if (cnt[30:2]==5) begin if (array_lt !== 64'b0000000000000000000000000000000000000000000000000000000011111111) begin $display("%b", array_lt); $stop(); end end - else if (cnt[30:2]==6) begin if (array_lt !== 64'b1111000000000000000000000000000000000000000000000000000000000000) begin $display("%b", array_lt); $stop(); end end - else if (cnt[30:2]==7) begin if (array_lt !== 64'b0000000000000000000000000000000000000000000000000000000000001111) begin $display("%b", array_lt); $stop(); end end - else if (cnt[30:2]==8) begin if (array_lt !== 64'b1000000000000000000000000000000000000000000000000000000000000000) begin $display("%b", array_lt); $stop(); end end - else if (cnt[30:2]==9) begin if (array_lt !== 64'b0000000000000000000000000000000000000000000000000000000000000001) begin $display("%b", array_lt); $stop(); end end + if (cnt[30:2]==0) begin if (array_asc !== 64'b0000000000000000000000000000000000000000000000000000000000000000) begin $display("%b", array_asc); $stop(); end end + else if (cnt[30:2]==1) begin if (array_asc !== 64'b1111111111111111111111111111111111111111111111111111111111111111) begin $display("%b", array_asc); $stop(); end end + else if (cnt[30:2]==2) begin if (array_asc !== 64'b1111111111111111111111111111111100000000000000000000000000000000) begin $display("%b", array_asc); $stop(); end end + else if (cnt[30:2]==3) begin if (array_asc !== 64'b0000000000000000000000000000000011111111111111111111111111111111) begin $display("%b", array_asc); $stop(); end end + else if (cnt[30:2]==4) begin if (array_asc !== 64'b1111111100000000000000000000000000000000000000000000000000000000) begin $display("%b", array_asc); $stop(); end end + else if (cnt[30:2]==5) begin if (array_asc !== 64'b0000000000000000000000000000000000000000000000000000000011111111) begin $display("%b", array_asc); $stop(); end end + else if (cnt[30:2]==6) begin if (array_asc !== 64'b1111000000000000000000000000000000000000000000000000000000000000) begin $display("%b", array_asc); $stop(); end end + else if (cnt[30:2]==7) begin if (array_asc !== 64'b0000000000000000000000000000000000000000000000000000000000001111) begin $display("%b", array_asc); $stop(); end end + else if (cnt[30:2]==8) begin if (array_asc !== 64'b1000000000000000000000000000000000000000000000000000000000000000) begin $display("%b", array_asc); $stop(); end end + else if (cnt[30:2]==9) begin if (array_asc !== 64'b0000000000000000000000000000000000000000000000000000000000000001) begin $display("%b", array_asc); $stop(); end end end else if (cnt[1:0]==2'd3) begin // read value from array (not a very good test for now) - if (cnt[30:2]==0) begin if (array_lt !== {WA *WB {1'b0}}) $stop(); end - else if (cnt[30:2]==1) begin if (array_lt !== {WA *WB +0{1'b1}}) $stop(); end - else if (cnt[30:2]==2) begin if (array_lt [0 :WA/2-1] !== {WA/2*WB +0{1'b1}}) $stop(); end - else if (cnt[30:2]==3) begin if (array_lt [WA/2:WA -1] !== {WA/2*WB +0{1'b1}}) $stop(); end - else if (cnt[30:2]==4) begin if (array_lt [0 ] !== {1 *WB +0{1'b1}}) $stop(); end - else if (cnt[30:2]==5) begin if (array_lt [ WA -1] !== {1 *WB +0{1'b1}}) $stop(); end - else if (cnt[30:2]==6) begin if (array_lt [0 ][0 :WB/2-1] !== {1 *WB/2+0{1'b1}}) $stop(); end - else if (cnt[30:2]==7) begin if (array_lt [ WA -1][WB/2:WB -1] !== {1 *WB/2+0{1'b1}}) $stop(); end - else if (cnt[30:2]==8) begin if (array_lt [0 ][0 ] !== {1 *1 +0{1'b1}}) $stop(); end - else if (cnt[30:2]==9) begin if (array_lt [ WA -1][ WB -1] !== {1 *1 +0{1'b1}}) $stop(); end + if (cnt[30:2]==0) begin if (array_asc !== {WA *WB {1'b0}}) $stop(); end + else if (cnt[30:2]==1) begin if (array_asc !== {WA *WB +0{1'b1}}) $stop(); end + else if (cnt[30:2]==2) begin if (array_asc [0 :WA/2-1] !== {WA/2*WB +0{1'b1}}) $stop(); end + else if (cnt[30:2]==3) begin if (array_asc [WA/2:WA -1] !== {WA/2*WB +0{1'b1}}) $stop(); end + else if (cnt[30:2]==4) begin if (array_asc [0 ] !== {1 *WB +0{1'b1}}) $stop(); end + else if (cnt[30:2]==5) begin if (array_asc [ WA -1] !== {1 *WB +0{1'b1}}) $stop(); end + else if (cnt[30:2]==6) begin if (array_asc [0 ][0 :WB/2-1] !== {1 *WB/2+0{1'b1}}) $stop(); end + else if (cnt[30:2]==7) begin if (array_asc [ WA -1][WB/2:WB -1] !== {1 *WB/2+0{1'b1}}) $stop(); end + else if (cnt[30:2]==8) begin if (array_asc [0 ][0 ] !== {1 *1 +0{1'b1}}) $stop(); end + else if (cnt[30:2]==9) begin if (array_asc [ WA -1][ WB -1] !== {1 *1 +0{1'b1}}) $stop(); end end endmodule diff --git a/test_regress/t/t_array_pattern_packed.v b/test_regress/t/t_array_pattern_packed.v index 8023dae9f..0c3eff320 100644 --- a/test_regress/t/t_array_pattern_packed.v +++ b/test_regress/t/t_array_pattern_packed.v @@ -11,7 +11,7 @@ module t (/*AUTOARG*/ input clk; - logic [1:0] [3:0] [3:0] array_simp; // big endian array + logic [1:0] [3:0] [3:0] array_simp; // descending range array logic [3:0] array_oned; @@ -61,10 +61,10 @@ module t (/*AUTOARG*/ localparam NO = 11; // number of access events // 2D packed arrays - logic [WA-1:0] [WB-1:0] array_bg; // big endian array - /* verilator lint_off LITENDIAN */ - logic [0:WA-1] [0:WB-1] array_lt; // little endian array - /* verilator lint_on LITENDIAN */ + logic [WA-1:0] [WB-1:0] array_dsc; // descending range array + /* verilator lint_off ASCRANGE */ + logic [0:WA-1] [0:WB-1] array_asc; // ascending range array + /* verilator lint_on ASCRANGE */ integer cnt = 0; @@ -80,74 +80,74 @@ module t (/*AUTOARG*/ $finish; end - // big endian + // descending range always @ (posedge clk) if (cnt[1:0]==2'd0) begin // initialize to defaults (all bits 1'b0) - if (cnt[30:2]== 0) array_bg <= '0; - else if (cnt[30:2]== 1) array_bg <= '0; - else if (cnt[30:2]== 2) array_bg <= '0; - else if (cnt[30:2]== 3) array_bg <= '0; - else if (cnt[30:2]== 4) array_bg <= '0; - else if (cnt[30:2]== 5) array_bg <= '0; - else if (cnt[30:2]== 6) array_bg <= '0; - else if (cnt[30:2]== 7) array_bg <= '0; - else if (cnt[30:2]== 8) array_bg <= '0; - else if (cnt[30:2]== 9) array_bg <= '0; - else if (cnt[30:2]==10) array_bg <= '0; + if (cnt[30:2]== 0) array_dsc <= '0; + else if (cnt[30:2]== 1) array_dsc <= '0; + else if (cnt[30:2]== 2) array_dsc <= '0; + else if (cnt[30:2]== 3) array_dsc <= '0; + else if (cnt[30:2]== 4) array_dsc <= '0; + else if (cnt[30:2]== 5) array_dsc <= '0; + else if (cnt[30:2]== 6) array_dsc <= '0; + else if (cnt[30:2]== 7) array_dsc <= '0; + else if (cnt[30:2]== 8) array_dsc <= '0; + else if (cnt[30:2]== 9) array_dsc <= '0; + else if (cnt[30:2]==10) array_dsc <= '0; end else if (cnt[1:0]==2'd1) begin // write data into whole or part of the array using literals if (cnt[30:2]== 0) begin end - else if (cnt[30:2]== 1) array_bg <= '{ 3 ,2 ,1, 0 }; - else if (cnt[30:2]== 2) array_bg <= '{default:13}; - else if (cnt[30:2]== 3) array_bg <= '{0:4, 1:5, 2:6, 3:7}; - else if (cnt[30:2]== 4) array_bg <= '{2:15, default:13}; - else if (cnt[30:2]== 5) array_bg <= '{WA { {WB/2 {2'b10}} }}; - else if (cnt[30:2]== 6) array_bg <= '{cnt[3:0]+0, cnt[3:0]+1, cnt[3:0]+2, cnt[3:0]+3}; + else if (cnt[30:2]== 1) array_dsc <= '{ 3 ,2 ,1, 0 }; + else if (cnt[30:2]== 2) array_dsc <= '{default:13}; + else if (cnt[30:2]== 3) array_dsc <= '{0:4, 1:5, 2:6, 3:7}; + else if (cnt[30:2]== 4) array_dsc <= '{2:15, default:13}; + else if (cnt[30:2]== 5) array_dsc <= '{WA { {WB/2 {2'b10}} }}; + else if (cnt[30:2]== 6) array_dsc <= '{cnt[3:0]+0, cnt[3:0]+1, cnt[3:0]+2, cnt[3:0]+3}; end else if (cnt[1:0]==2'd2) begin // chack array agains expected value - if (cnt[30:2]== 0) begin if (array_bg !== 16'b0000000000000000) begin $display("%b", array_bg); $stop(); end end - else if (cnt[30:2]== 1) begin if (array_bg !== 16'b0011001000010000) begin $display("%b", array_bg); $stop(); end end - else if (cnt[30:2]== 2) begin if (array_bg !== 16'b1101110111011101) begin $display("%b", array_bg); $stop(); end end - else if (cnt[30:2]== 3) begin if (array_bg !== 16'b0111011001010100) begin $display("%b", array_bg); $stop(); end end - else if (cnt[30:2]== 4) begin if (array_bg !== 16'b1101111111011101) begin $display("%b", array_bg); $stop(); end end - else if (cnt[30:2]== 5) begin if (array_bg !== 16'b1010101010101010) begin $display("%b", array_bg); $stop(); end end - else if (cnt[30:2]== 6) begin if (array_bg !== 16'b1001101010111100) begin $display("%b", array_bg); $stop(); end end + if (cnt[30:2]== 0) begin if (array_dsc !== 16'b0000000000000000) begin $display("%b", array_dsc); $stop(); end end + else if (cnt[30:2]== 1) begin if (array_dsc !== 16'b0011001000010000) begin $display("%b", array_dsc); $stop(); end end + else if (cnt[30:2]== 2) begin if (array_dsc !== 16'b1101110111011101) begin $display("%b", array_dsc); $stop(); end end + else if (cnt[30:2]== 3) begin if (array_dsc !== 16'b0111011001010100) begin $display("%b", array_dsc); $stop(); end end + else if (cnt[30:2]== 4) begin if (array_dsc !== 16'b1101111111011101) begin $display("%b", array_dsc); $stop(); end end + else if (cnt[30:2]== 5) begin if (array_dsc !== 16'b1010101010101010) begin $display("%b", array_dsc); $stop(); end end + else if (cnt[30:2]== 6) begin if (array_dsc !== 16'b1001101010111100) begin $display("%b", array_dsc); $stop(); end end end - // little endian + // ascending range always @ (posedge clk) if (cnt[1:0]==2'd0) begin // initialize to defaults (all bits 1'b0) - if (cnt[30:2]== 0) array_lt <= '0; - else if (cnt[30:2]== 1) array_lt <= '0; - else if (cnt[30:2]== 2) array_lt <= '0; - else if (cnt[30:2]== 3) array_lt <= '0; - else if (cnt[30:2]== 4) array_lt <= '0; - else if (cnt[30:2]== 5) array_lt <= '0; - else if (cnt[30:2]== 6) array_lt <= '0; - else if (cnt[30:2]== 7) array_lt <= '0; - else if (cnt[30:2]== 8) array_lt <= '0; - else if (cnt[30:2]== 9) array_lt <= '0; - else if (cnt[30:2]==10) array_lt <= '0; + if (cnt[30:2]== 0) array_asc <= '0; + else if (cnt[30:2]== 1) array_asc <= '0; + else if (cnt[30:2]== 2) array_asc <= '0; + else if (cnt[30:2]== 3) array_asc <= '0; + else if (cnt[30:2]== 4) array_asc <= '0; + else if (cnt[30:2]== 5) array_asc <= '0; + else if (cnt[30:2]== 6) array_asc <= '0; + else if (cnt[30:2]== 7) array_asc <= '0; + else if (cnt[30:2]== 8) array_asc <= '0; + else if (cnt[30:2]== 9) array_asc <= '0; + else if (cnt[30:2]==10) array_asc <= '0; end else if (cnt[1:0]==2'd1) begin // write data into whole or part of the array using literals if (cnt[30:2]== 0) begin end - else if (cnt[30:2]== 1) array_lt <= '{ 3 ,2 ,1, 0 }; - else if (cnt[30:2]== 2) array_lt <= '{default:13}; - else if (cnt[30:2]== 3) array_lt <= '{3:4, 2:5, 1:6, 0:7}; - else if (cnt[30:2]== 4) array_lt <= '{1:15, default:13}; - else if (cnt[30:2]== 5) array_lt <= '{WA { {WB/2 {2'b10}} }}; - else if (cnt[30:2]==10) array_lt <= '{cnt[3:0]+0, cnt[3:0]+1, cnt[3:0]+2, cnt[3:0]+3}; + else if (cnt[30:2]== 1) array_asc <= '{ 3 ,2 ,1, 0 }; + else if (cnt[30:2]== 2) array_asc <= '{default:13}; + else if (cnt[30:2]== 3) array_asc <= '{3:4, 2:5, 1:6, 0:7}; + else if (cnt[30:2]== 4) array_asc <= '{1:15, default:13}; + else if (cnt[30:2]== 5) array_asc <= '{WA { {WB/2 {2'b10}} }}; + else if (cnt[30:2]==10) array_asc <= '{cnt[3:0]+0, cnt[3:0]+1, cnt[3:0]+2, cnt[3:0]+3}; end else if (cnt[1:0]==2'd2) begin // chack array agains expected value - if (cnt[30:2]== 0) begin if (array_lt !== 16'b0000000000000000) begin $display("%b", array_lt); $stop(); end end - else if (cnt[30:2]== 1) begin if (array_lt !== 16'b0011001000010000) begin $display("%b", array_lt); $stop(); end end - else if (cnt[30:2]== 2) begin if (array_lt !== 16'b1101110111011101) begin $display("%b", array_lt); $stop(); end end - else if (cnt[30:2]== 3) begin if (array_lt !== 16'b0111011001010100) begin $display("%b", array_lt); $stop(); end end - else if (cnt[30:2]== 4) begin if (array_lt !== 16'b1101111111011101) begin $display("%b", array_lt); $stop(); end end - else if (cnt[30:2]== 5) begin if (array_lt !== 16'b1010101010101010) begin $display("%b", array_lt); $stop(); end end - else if (cnt[30:2]==10) begin if (array_lt !== 16'b1001101010111100) begin $display("%b", array_lt); $stop(); end end + if (cnt[30:2]== 0) begin if (array_asc !== 16'b0000000000000000) begin $display("%b", array_asc); $stop(); end end + else if (cnt[30:2]== 1) begin if (array_asc !== 16'b0011001000010000) begin $display("%b", array_asc); $stop(); end end + else if (cnt[30:2]== 2) begin if (array_asc !== 16'b1101110111011101) begin $display("%b", array_asc); $stop(); end end + else if (cnt[30:2]== 3) begin if (array_asc !== 16'b0111011001010100) begin $display("%b", array_asc); $stop(); end end + else if (cnt[30:2]== 4) begin if (array_asc !== 16'b1101111111011101) begin $display("%b", array_asc); $stop(); end end + else if (cnt[30:2]== 5) begin if (array_asc !== 16'b1010101010101010) begin $display("%b", array_asc); $stop(); end end + else if (cnt[30:2]==10) begin if (array_asc !== 16'b1001101010111100) begin $display("%b", array_asc); $stop(); end end end endmodule diff --git a/test_regress/t/t_array_pattern_unpacked.v b/test_regress/t/t_array_pattern_unpacked.v index aaf1db6c4..60e710d92 100644 --- a/test_regress/t/t_array_pattern_unpacked.v +++ b/test_regress/t/t_array_pattern_unpacked.v @@ -6,7 +6,7 @@ module t (/*AUTOARG*/); - logic [3:0] array_simp [1:0] [3:0]; // big endian array + logic [3:0] array_simp [1:0] [3:0]; // descending range array int irep[1:2][1:6]; diff --git a/test_regress/t/t_array_query.v b/test_regress/t/t_array_query.v index b57a10494..963495080 100644 --- a/test_regress/t/t_array_query.v +++ b/test_regress/t/t_array_query.v @@ -40,9 +40,9 @@ module array_test input clk; - // verilator lint_off LITENDIAN + // verilator lint_off ASCRANGE reg [7:0] a [LEFT:RIGHT]; - // verilator lint_on LITENDIAN + // verilator lint_on ASCRANGE typedef reg [7:0] r_t; diff --git a/test_regress/t/t_array_rev.v b/test_regress/t/t_array_rev.v index 47594bf5f..6d06bbd9d 100644 --- a/test_regress/t/t_array_rev.v +++ b/test_regress/t/t_array_rev.v @@ -12,9 +12,9 @@ module t (/*AUTOARG*/ input clk; integer cyc = 0; - // verilator lint_off LITENDIAN + // verilator lint_off ASCRANGE logic arrd [0:1] = '{ 1'b1, 1'b0 }; - // verilator lint_on LITENDIAN + // verilator lint_on ASCRANGE logic y0, y1; logic localbkw [1:0]; diff --git a/test_regress/t/t_clk_concat3.v b/test_regress/t/t_clk_concat3.v index 87fb40db8..fe68657cb 100644 --- a/test_regress/t/t_clk_concat3.v +++ b/test_regress/t/t_clk_concat3.v @@ -4,7 +4,7 @@ // without warranty. // SPDX-License-Identifier: CC0-1.0 -/* verilator lint_off LITENDIAN */ +/* verilator lint_off ASCRANGE */ module some_module ( input wrclk ); diff --git a/test_regress/t/t_dist_warn_coverage.pl b/test_regress/t/t_dist_warn_coverage.pl index 7fb44afc5..349fd4737 100755 --- a/test_regress/t/t_dist_warn_coverage.pl +++ b/test_regress/t/t_dist_warn_coverage.pl @@ -31,7 +31,7 @@ foreach my $s ( 'dynamic new() not expected in this context (expected under an assign)', # Instead get syntax error # Not yet analyzed ' is not an in/out/inout/param/interface: ', - 'Big endian instance range connecting to ', + 'Descending instance range connecting to ', ' loading non-variable', '--pipe-filter protocol error, unexpected: ', '/*verilator sformat*/ can only be applied to last argument of ', diff --git a/test_regress/t/t_foreach.v b/test_regress/t/t_foreach.v index e7f75f0a5..4cdf96180 100644 --- a/test_regress/t/t_foreach.v +++ b/test_regress/t/t_foreach.v @@ -8,7 +8,7 @@ module t (/*AUTOARG*/); - // verilator lint_off LITENDIAN + // verilator lint_off ASCRANGE // verilator lint_off WIDTH reg [63:0] sum; // Checked not in objects diff --git a/test_regress/t/t_inst_array_connect.v b/test_regress/t/t_inst_array_connect.v index 48d5af727..af08f7c30 100644 --- a/test_regress/t/t_inst_array_connect.v +++ b/test_regress/t/t_inst_array_connect.v @@ -20,7 +20,7 @@ module t (/*AUTOARG*/ assign inc = 4'b0001; - // verilator lint_off LITENDIAN + // verilator lint_off ASCRANGE COUNTER UCOUNTER1[N-1:0] ( diff --git a/test_regress/t/t_interface_array_nocolon.v b/test_regress/t/t_interface_array_nocolon.v index 7536b49ce..370ca35fd 100644 --- a/test_regress/t/t_interface_array_nocolon.v +++ b/test_regress/t/t_interface_array_nocolon.v @@ -22,13 +22,13 @@ module t (); wire [2:0] X = 3'b110; - // Should not cause LITENDIAN warning, as no harm in array selections. - // verilator lint_on LITENDIAN + // Should not cause ASCRANGE warning, as no harm in array selections. + // verilator lint_on ASCRANGE foo_intf foo1 [N] (.x(1'b1)); foo_subm sub1 [N] (.x(1'b1)); - // Will cause LITENDIAN warning? - // verilator lint_off LITENDIAN + // Will cause ASCRANGE warning? + // verilator lint_off ASCRANGE foo_intf foos [N] (.x(X)); foo_intf fool [1:3] (.x(X)); foo_intf foom [3:1] (.x(X)); diff --git a/test_regress/t/t_interface_array_nocolon_bad.out b/test_regress/t/t_interface_array_nocolon_bad.out index b189edec7..744b81d20 100644 --- a/test_regress/t/t_interface_array_nocolon_bad.out +++ b/test_regress/t/t_interface_array_nocolon_bad.out @@ -1,19 +1,19 @@ -%Warning-LITENDIAN: t/t_interface_array_nocolon_bad.v:26:26: Big endian instance range connecting to vector: left < right of instance range: [0:2] - : ... In instance t +%Warning-ASCRANGE: t/t_interface_array_nocolon_bad.v:26:26: Ascending instance range connecting to vector: left < right of instance range: [0:2] + : ... In instance t 26 | foo_intf foos [N] (.x(X)); | ^ - ... For warning description see https://verilator.org/warn/LITENDIAN?v=latest - ... Use "/* verilator lint_off LITENDIAN */" and lint_on around source to disable this message. -%Warning-LITENDIAN: t/t_interface_array_nocolon_bad.v:27:28: Big endian instance range connecting to vector: left < right of instance range: [1:3] - : ... In instance t + ... For warning description see https://verilator.org/warn/ASCRANGE?v=latest + ... Use "/* verilator lint_off ASCRANGE */" and lint_on around source to disable this message. +%Warning-ASCRANGE: t/t_interface_array_nocolon_bad.v:27:28: Ascending instance range connecting to vector: left < right of instance range: [1:3] + : ... In instance t 27 | foo_intf fool [1:3] (.x(X)); | ^ -%Warning-LITENDIAN: t/t_interface_array_nocolon_bad.v:30:26: Big endian instance range connecting to vector: left < right of instance range: [0:2] - : ... In instance t +%Warning-ASCRANGE: t/t_interface_array_nocolon_bad.v:30:26: Ascending instance range connecting to vector: left < right of instance range: [0:2] + : ... In instance t 30 | foo_subm subs [N] (.x(X)); | ^ -%Warning-LITENDIAN: t/t_interface_array_nocolon_bad.v:31:28: Big endian instance range connecting to vector: left < right of instance range: [1:3] - : ... In instance t +%Warning-ASCRANGE: t/t_interface_array_nocolon_bad.v:31:28: Ascending instance range connecting to vector: left < right of instance range: [1:3] + : ... In instance t 31 | foo_subm subl [1:3] (.x(X)); | ^ %Error: Exiting due to diff --git a/test_regress/t/t_interface_array_nocolon_bad.v b/test_regress/t/t_interface_array_nocolon_bad.v index 94431d640..088f38ef1 100644 --- a/test_regress/t/t_interface_array_nocolon_bad.v +++ b/test_regress/t/t_interface_array_nocolon_bad.v @@ -22,7 +22,7 @@ module t (); wire [2:0] X = 3'b110; - // Will cause LITENDIAN warning? + // Will cause ASCRANGE warning? foo_intf foos [N] (.x(X)); // bad foo_intf fool [1:3] (.x(X)); // bad foo_intf foom [3:1] (.x(X)); // ok diff --git a/test_regress/t/t_lib_prot.v b/test_regress/t/t_lib_prot.v index 7fa639835..464f91426 100644 --- a/test_regress/t/t_lib_prot.v +++ b/test_regress/t/t_lib_prot.v @@ -57,10 +57,10 @@ module t #(parameter GATED_CLK = 0) (/*AUTOARG*/ logic [128:0] s129_out; logic [3:0] [31:0] s4x32_in; logic [3:0] [31:0] s4x32_out; - /*verilator lint_off LITENDIAN*/ + /*verilator lint_off ASCRANGE*/ logic [0:15] s6x16up_in[0:1][2:0]; logic [0:15] s6x16up_out[0:1][2:0]; - /*verilator lint_on LITENDIAN*/ + /*verilator lint_on ASCRANGE*/ logic [15:0] s8x16up_in[1:0][0:3]; logic [15:0] s8x16up_out[1:0][0:3]; logic [15:0] s8x16up_3d_in[1:0][0:1][0:1]; diff --git a/test_regress/t/t_lib_prot_secret.v b/test_regress/t/t_lib_prot_secret.v index 1ed4dae83..44e055cfe 100644 --- a/test_regress/t/t_lib_prot_secret.v +++ b/test_regress/t/t_lib_prot_secret.v @@ -27,10 +27,10 @@ module secret #(parameter GATED_CLK = 0) output logic [128:0] s129_out, input [3:0] [31:0] s4x32_in, output logic [3:0] [31:0] s4x32_out, - /*verilator lint_off LITENDIAN*/ + /*verilator lint_off ASCRANGE*/ input [0:15] s6x16up_in[0:1][2:0], output logic [0:15] s6x16up_out[0:1][2:0], - /*verilator lint_on LITENDIAN*/ + /*verilator lint_on ASCRANGE*/ input [15:0] s8x16up_in[1:0][0:3], output logic [15:0] s8x16up_out[1:0][0:3], input [15:0] s8x16up_3d_in[1:0][0:1][0:1], diff --git a/test_regress/t/t_lint_historical.v b/test_regress/t/t_lint_historical.v index 8647a070c..b1c1caf24 100644 --- a/test_regress/t/t_lint_historical.v +++ b/test_regress/t/t_lint_historical.v @@ -45,7 +45,7 @@ module t; // verilator lint_off INITIALDLY // verilator lint_off INSECURE // verilator lint_off LATCH - // verilator lint_off LITENDIAN + // verilator lint_off ASCRANGE // verilator lint_off MODDUP // verilator lint_off MULTIDRIVEN // verilator lint_off MULTITOP diff --git a/test_regress/t/t_mem_fifo.v b/test_regress/t/t_mem_fifo.v index e76ec783a..ca1e13940 100644 --- a/test_regress/t/t_mem_fifo.v +++ b/test_regress/t/t_mem_fifo.v @@ -89,9 +89,9 @@ module fifo (/*AUTOARG*/ reg [65:0] outData; // verilator lint_off VARHIDDEN - // verilator lint_off LITENDIAN + // verilator lint_off ASCRANGE reg [65:0] fifo[0:fifoDepth-1]; - // verilator lint_on LITENDIAN + // verilator lint_on ASCRANGE // verilator lint_on VARHIDDEN //reg [65:0] temp; diff --git a/test_regress/t/t_mem_first.v b/test_regress/t/t_mem_first.v index 372032a77..dfda7d9cb 100644 --- a/test_regress/t/t_mem_first.v +++ b/test_regress/t/t_mem_first.v @@ -12,13 +12,13 @@ module t (/*AUTOARG*/ input clk; integer _mode; initial _mode = 0; - // verilator lint_off LITENDIAN + // verilator lint_off ASCRANGE reg [7:0] mem_narrow [0:31]; //surefire lint_off_line RD_WRT WRTWRT NBAJAM reg [77:0] mem_wide [1024:0]; //surefire lint_off_line RD_WRT WRTWRT NBAJAM reg [7:0] mem_dly_narrow [0:1]; //surefire lint_off_line RD_WRT WRTWRT NBAJAM reg [77:0] mem_dly_wide [1:0]; //surefire lint_off_line RD_WRT WRTWRT NBAJAM reg [34:0] vec_wide; - // verilator lint_on LITENDIAN + // verilator lint_on ASCRANGE reg [31:0] wrd0 [15:0]; wire [3:0] sel = 4'h3; diff --git a/test_regress/t/t_mem_multidim.v b/test_regress/t/t_mem_multidim.v index 9f68b4d5d..a81d5319d 100644 --- a/test_regress/t/t_mem_multidim.v +++ b/test_regress/t/t_mem_multidim.v @@ -11,7 +11,7 @@ module t (/*AUTOARG*/ input clk; - // verilator lint_off LITENDIAN + // verilator lint_off ASCRANGE // verilator lint_off BLKANDNBLK // 3 3 4 reg [71:0] memw [2:0][1:3][5:2]; @@ -29,7 +29,7 @@ module t (/*AUTOARG*/ integer imem[2:0][1:3]; reg [2:0] cstyle[2]; - // verilator lint_on LITENDIAN + // verilator lint_on ASCRANGE initial begin for (i0=0; i0<3; i0=i0+1) begin diff --git a/test_regress/t/t_mem_multiwire.v b/test_regress/t/t_mem_multiwire.v index 24a53f502..15569e2f7 100644 --- a/test_regress/t/t_mem_multiwire.v +++ b/test_regress/t/t_mem_multiwire.v @@ -11,10 +11,10 @@ module t (/*AUTOARG*/ input clk; - // verilator lint_off LITENDIAN + // verilator lint_off ASCRANGE wire [7:0] array [2:0][1:3]; wire [7:0] arrayNoColon [2][3]; - // verilator lint_on LITENDIAN + // verilator lint_on ASCRANGE integer cyc; initial cyc = 0; integer i0,i1,i2; diff --git a/test_regress/t/t_metacmt_onoff.out b/test_regress/t/t_metacmt_onoff.out index 4c6ca3bf2..7b912780c 100644 --- a/test_regress/t/t_metacmt_onoff.out +++ b/test_regress/t/t_metacmt_onoff.out @@ -1,11 +1,11 @@ -%Warning-LITENDIAN: t/t_metacmt_onoff.v:8:8: Big bit endian vector: left < right of bit range: [0:1] - : ... In instance t - 8 | reg [0:1] show1; /*verilator lint_off LITENDIAN*/ reg [0:2] ign2; /*verilator lint_on LITENDIAN*/ reg [0:3] show3; +%Warning-ASCRANGE: t/t_metacmt_onoff.v:8:8: Ascending bit range vector: left < right of bit range: [0:1] + : ... In instance t + 8 | reg [0:1] show1; /*verilator lint_off ASCRANGE*/ reg [0:2] ign2; /*verilator lint_on ASCRANGE*/ reg [0:3] show3; | ^ - ... For warning description see https://verilator.org/warn/LITENDIAN?v=latest - ... Use "/* verilator lint_off LITENDIAN */" and lint_on around source to disable this message. -%Warning-LITENDIAN: t/t_metacmt_onoff.v:8:109: Big bit endian vector: left < right of bit range: [0:3] - : ... In instance t - 8 | reg [0:1] show1; /*verilator lint_off LITENDIAN*/ reg [0:2] ign2; /*verilator lint_on LITENDIAN*/ reg [0:3] show3; - | ^ + ... For warning description see https://verilator.org/warn/ASCRANGE?v=latest + ... Use "/* verilator lint_off ASCRANGE */" and lint_on around source to disable this message. +%Warning-ASCRANGE: t/t_metacmt_onoff.v:8:107: Ascending bit range vector: left < right of bit range: [0:3] + : ... In instance t + 8 | reg [0:1] show1; /*verilator lint_off ASCRANGE*/ reg [0:2] ign2; /*verilator lint_on ASCRANGE*/ reg [0:3] show3; + | ^ %Error: Exiting due to diff --git a/test_regress/t/t_metacmt_onoff.v b/test_regress/t/t_metacmt_onoff.v index 7b7c5735e..91dc5eeae 100644 --- a/test_regress/t/t_metacmt_onoff.v +++ b/test_regress/t/t_metacmt_onoff.v @@ -5,7 +5,7 @@ module t; // Test turning on and off a message on the same line; only middle reg shouldn't warn - reg [0:1] show1; /*verilator lint_off LITENDIAN*/ reg [0:2] ign2; /*verilator lint_on LITENDIAN*/ reg [0:3] show3; + reg [0:1] show1; /*verilator lint_off ASCRANGE*/ reg [0:2] ign2; /*verilator lint_on ASCRANGE*/ reg [0:3] show3; initial begin $write("*-* All Finished *-*\n"); $finish; diff --git a/test_regress/t/t_mod_interface_array1.v b/test_regress/t/t_mod_interface_array1.v index bd497af90..f16a65b41 100644 --- a/test_regress/t/t_mod_interface_array1.v +++ b/test_regress/t/t_mod_interface_array1.v @@ -44,9 +44,9 @@ module t logic [N-1:0] a_in; logic [N-1:0] a_out; logic [N-1:0] ack_out; - // verilator lint_off LITENDIAN + // verilator lint_off ASCRANGE a_if #(.PARAM(1)) tl_intf [N] (); - // verilator lint_on LITENDIAN + // verilator lint_on ASCRANGE intf_source source(a_in, tl_intf); intf_sink sink(a_out, tl_intf); diff --git a/test_regress/t/t_mod_interface_array2.v b/test_regress/t/t_mod_interface_array2.v index b7f7647f8..b2f15dc04 100644 --- a/test_regress/t/t_mod_interface_array2.v +++ b/test_regress/t/t_mod_interface_array2.v @@ -5,7 +5,7 @@ // SPDX-License-Identifier: CC0-1.0 parameter N = 4; -// verilator lint_off LITENDIAN +// verilator lint_off ASCRANGE interface a_if #(parameter PARAM = 0) (); logic long_name; diff --git a/test_regress/t/t_param_module.v b/test_regress/t/t_param_module.v index 18369db2c..c83a8e805 100644 --- a/test_regress/t/t_param_module.v +++ b/test_regress/t/t_param_module.v @@ -7,7 +7,7 @@ // used in the test module to set the value of MSB. A number of warnings and // errors follow, starting with: // -// %Warning-LITENDIAN: t/t_param_module.v:42: Big bit endian vector: MSB +// %Warning-ASCRANGE: t/t_param_module.v:42: Ascending bit range vector: MSB // < LSB of bit range: -17:0 // // This file ONLY is placed into the Public Domain, for any use, without diff --git a/test_regress/t/t_param_repl.v b/test_regress/t/t_param_repl.v index 0cc2c107a..cc7b04d40 100644 --- a/test_regress/t/t_param_repl.v +++ b/test_regress/t/t_param_repl.v @@ -21,9 +21,9 @@ module t (/*AUTOARG*/ parameter DWORDS_LOG2 = 7; parameter DWORDS = (1< 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_select_ascending.v b/test_regress/t/t_select_ascending.v new file mode 100644 index 000000000..0f37470d9 --- /dev/null +++ b/test_regress/t/t_select_ascending.v @@ -0,0 +1,75 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2009 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc = 0; + reg [63:0] crc; + reg [63:0] sum; + + // verilator lint_off ASCRANGE + wire [10:41] sel2 = crc[31:0]; + wire [10:100] sel3 = {crc[26:0],crc}; + + wire out20 = sel2[{1'b0,crc[3:0]} + 11]; + wire [3:0] out21 = sel2[13 : 16]; + wire [3:0] out22 = sel2[{1'b0,crc[3:0]} + 20 +: 4]; + wire [3:0] out23 = sel2[{1'b0,crc[3:0]} + 20 -: 4]; + + wire out30 = sel3[{2'b0,crc[3:0]} + 11]; + wire [3:0] out31 = sel3[13 : 16]; + wire [3:0] out32 = sel3[crc[5:0] + 20 +: 4]; + wire [3:0] out33 = sel3[crc[5:0] + 20 -: 4]; + + // Aggregate outputs into a single result vector + wire [63:0] result = {38'h0, out20, out21, out22, out23, out30, out31, out32, out33}; + + reg [19:50] sel1; + initial begin + // Path clearing + // 122333445 + // 826048260 + sel1 = 32'h12345678; + if (sel1 != 32'h12345678) $stop; + if (sel1[47 : 50] != 4'h8) $stop; + if (sel1[31 : 34] != 4'h4) $stop; + if (sel1[27 +: 4] != 4'h3) $stop; //==[27:30], in memory as [23:20] + if (sel1[26 -: 4] != 4'h2) $stop; //==[23:26], in memory as [27:24] + end + + // Test loop + always @ (posedge clk) begin +`ifdef TEST_VERBOSE + $write("[%0t] sels=%x,%x,%x,%x %x,%x,%x,%x\n", $time, out20,out21,out22,out23, out30,out31,out32,out33); + $write("[%0t] cyc==%0d crc=%x result=%x\n", $time, cyc, crc, result); +`endif + cyc <= cyc + 1; + crc <= {crc[62:0], crc[63] ^ crc[2] ^ crc[0]}; + sum <= result ^ {sum[62:0], sum[63] ^ sum[2] ^ sum[0]}; + if (cyc==0) begin + // Setup + crc <= 64'h5aef0c8d_d70a4497; + end + else if (cyc<10) begin + sum <= 64'h0; + end + else if (cyc<90) begin + end + else if (cyc==99) begin + $write("[%0t] cyc==%0d crc=%x sum=%x\n", $time, cyc, crc, sum); + if (crc !== 64'hc77bb9b3784ea091) $stop; +`define EXPECTED_SUM 64'h28bf65439eb12c00 + if (sum !== `EXPECTED_SUM) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule diff --git a/test_regress/t/t_select_bad_msb.out b/test_regress/t/t_select_bad_msb.out index 1ec1c350e..84e30c325 100644 --- a/test_regress/t/t_select_bad_msb.out +++ b/test_regress/t/t_select_bad_msb.out @@ -1,10 +1,10 @@ -%Warning-LITENDIAN: t/t_select_bad_msb.v:12:8: Big bit endian vector: left < right of bit range: [0:22] - : ... In instance t +%Warning-ASCRANGE: t/t_select_bad_msb.v:12:8: Ascending bit range vector: left < right of bit range: [0:22] + : ... In instance t 12 | reg [0:22] backwd; | ^ - ... For warning description see https://verilator.org/warn/LITENDIAN?v=latest - ... Use "/* verilator lint_off LITENDIAN */" and lint_on around source to disable this message. -%Warning-SELRANGE: t/t_select_bad_msb.v:16:16: [1:4] Range extract has backward bit ordering, perhaps you wanted [4:1] + ... For warning description see https://verilator.org/warn/ASCRANGE?v=latest + ... Use "/* verilator lint_off ASCRANGE */" and lint_on around source to disable this message. +%Warning-SELRANGE: t/t_select_bad_msb.v:16:16: [1:4] Slice range has ascending bit ordering, perhaps you wanted [4:1] : ... In instance t 16 | sel2 = mi[1:4]; | ^ diff --git a/test_regress/t/t_select_bad_range4.out b/test_regress/t/t_select_bad_range4.out index 302b44d6e..cff72fd9a 100644 --- a/test_regress/t/t_select_bad_range4.out +++ b/test_regress/t/t_select_bad_range4.out @@ -36,7 +36,7 @@ : ... In instance t 22 | sel2 = mi[44 +: nonconst]; | ^~~~~~~~ -%Error: t/t_select_bad_range4.v:22:23: Width of :+ or :- bit extract isn't a constant +%Error: t/t_select_bad_range4.v:22:23: Width of :+ or :- bit slice range isn't a constant : ... In instance t 22 | sel2 = mi[44 +: nonconst]; | ^~~~~~~~ diff --git a/test_regress/t/t_select_little_pack.v b/test_regress/t/t_select_little_pack.v index e265f3b1f..3f7492a84 100644 --- a/test_regress/t/t_select_little_pack.v +++ b/test_regress/t/t_select_little_pack.v @@ -10,7 +10,7 @@ module t (/*AUTOARG*/ ); input clk; - // No endian warning here + // No ascending range warning here reg [7:0] pack [3:0]; initial begin diff --git a/test_regress/t/t_split_var_0.v b/test_regress/t/t_split_var_0.v index ee3db8562..6b316d6f3 100644 --- a/test_regress/t/t_split_var_0.v +++ b/test_regress/t/t_split_var_0.v @@ -175,9 +175,9 @@ module barshift_2d_packed_array #(parameter DEPTH = 2, localparam WIDTH = 2**DEP (input [WIDTH-1:0] in, input [DEPTH-1:0] shift, output [WIDTH-1:0] out); localparam OFFSET = -2; - /*verilator lint_off LITENDIAN*/ + /*verilator lint_off ASCRANGE*/ reg [OFFSET:DEPTH+OFFSET][WIDTH-1:0] tmp /*verilator split_var*/; - /*verilator lint_on LITENDIAN*/ + /*verilator lint_on ASCRANGE*/ generate for(genvar i = 0; i < DEPTH; ++i) begin @@ -201,9 +201,9 @@ module barshift_2d_packed_array_le #(parameter DEPTH = 2, localparam WIDTH = 2** (input [WIDTH-1:0] in, input [DEPTH-1:0] shift, output [WIDTH-1:0] out); localparam OFFSET = -2; - /*verilator lint_off LITENDIAN*/ + /*verilator lint_off ASCRANGE*/ reg [OFFSET:DEPTH+OFFSET][OFFSET:WIDTH-1+OFFSET] tmp /*verilator split_var*/; - /*verilator lint_on LITENDIAN*/ + /*verilator lint_on ASCRANGE*/ generate for(genvar i = 0; i < DEPTH; ++i) begin @@ -245,9 +245,9 @@ endmodule module barshift_bitslice #(parameter DEPTH = 2, localparam WIDTH = 2**DEPTH) (input [WIDTH-1:0] in, input [DEPTH-1:0] shift, output [WIDTH-1:0] out); - /*verilator lint_off LITENDIAN*/ + /*verilator lint_off ASCRANGE*/ wire [0:WIDTH*(DEPTH+1) - 1] tmp /*verilator split_var*/; - /*verilator lint_on LITENDIAN*/ + /*verilator lint_on ASCRANGE*/ generate for(genvar i = 0; i < DEPTH; ++i) begin @@ -267,10 +267,10 @@ endmodule module var_decl_with_init(); - /*verilator lint_off LITENDIAN*/ + /*verilator lint_off ASCRANGE*/ logic [-1:30] var0 /* verilator split_var */ = {4'd0, 4'd1, 4'd2, 4'd3, 4'd4, 4'd5, 4'd6, 4'd7}; logic [-1:30] var2 /* verilator split_var */; - /*verilator lint_on LITENDIAN*/ + /*verilator lint_on ASCRANGE*/ logic [30:-1] var1 /* verilator split_var */ = {4'd0, 4'd1, 4'd2, 4'd3, 4'd4, 4'd5, 4'd6, 4'd7}; logic [30:-1] var3 /* verilator split_var */; @@ -290,9 +290,9 @@ module t_array_rev(clk); // from t_array_rev.v input clk; integer cyc = 0; - // verilator lint_off LITENDIAN + // verilator lint_off ASCRANGE logic arrd [0:1] /*verilator split_var*/ = '{ 1'b1, 1'b0 }; - // verilator lint_on LITENDIAN + // verilator lint_on ASCRANGE logic y0, y1; logic localbkw [1:0]/*verilator split_var*/ ; @@ -442,11 +442,11 @@ module t(/*AUTOARG*/ clk); t_array_rev i_t_array_rev(clk); assign in = 8'b10001110; - /*verilator lint_off LITENDIAN*/ + /*verilator lint_off ASCRANGE*/ logic [7:0] [7:0] expc = {8'b10001110, 8'b01000111, 8'b10100011, 8'b11010001, 8'b11101000, 8'b01110100, 8'b00111010, 8'b00011101}; - /*verilator lint_on LITENDIAN*/ + /*verilator lint_on ASCRANGE*/ always @(posedge clk) begin : always_block automatic bit failed = 0; $display("in:%b shift:%d expc:%b", in, shift, expc[7-shift]); diff --git a/test_regress/t/t_struct_packed_sysfunct.v b/test_regress/t/t_struct_packed_sysfunct.v index acbe00291..540f27dcb 100644 --- a/test_regress/t/t_struct_packed_sysfunct.v +++ b/test_regress/t/t_struct_packed_sysfunct.v @@ -17,15 +17,15 @@ module t (/*AUTOARG*/ logic [1:0] e1; logic [3:0] e2; logic [7:0] e3; - } struct_bg; // big endian structure - /* verilator lint_off LITENDIAN */ + } struct_dsc; // descendng range structure + /* verilator lint_off ASCRANGE */ struct packed { logic e0; logic [0:1] e1; logic [0:3] e2; logic [0:7] e3; - } struct_lt; // little endian structure - /* verilator lint_on LITENDIAN */ + } struct_asc; // ascending range structure + /* verilator lint_on ASCRANGE */ integer cnt = 0; @@ -44,20 +44,20 @@ module t (/*AUTOARG*/ always @ (posedge clk) if (cnt==1) begin - // big endian - if ($bits (struct_bg ) != 15) $stop; - if ($bits (struct_bg.e0) != 1) $stop; - if ($bits (struct_bg.e1) != 2) $stop; - if ($bits (struct_bg.e2) != 4) $stop; - if ($bits (struct_bg.e3) != 8) $stop; - if ($increment (struct_bg, 1) != 1) $stop; - // little endian - if ($bits (struct_lt ) != 15) $stop; - if ($bits (struct_lt.e0) != 1) $stop; - if ($bits (struct_lt.e1) != 2) $stop; - if ($bits (struct_lt.e2) != 4) $stop; - if ($bits (struct_lt.e3) != 8) $stop; - if ($increment (struct_lt, 1) != 1) $stop; // Structure itself always big numbered + // descending range + if ($bits (struct_dsc ) != 15) $stop; + if ($bits (struct_dsc.e0) != 1) $stop; + if ($bits (struct_dsc.e1) != 2) $stop; + if ($bits (struct_dsc.e2) != 4) $stop; + if ($bits (struct_dsc.e3) != 8) $stop; + if ($increment (struct_dsc, 1) != 1) $stop; + // ascending range + if ($bits (struct_asc ) != 15) $stop; + if ($bits (struct_asc.e0) != 1) $stop; + if ($bits (struct_asc.e1) != 2) $stop; + if ($bits (struct_asc.e2) != 4) $stop; + if ($bits (struct_asc.e3) != 8) $stop; + if ($increment (struct_asc, 1) != 1) $stop; // Structure itself always big numbered end endmodule diff --git a/test_regress/t/t_struct_packed_value_list.v b/test_regress/t/t_struct_packed_value_list.v index 41c84d3b9..3321d3d9e 100644 --- a/test_regress/t/t_struct_packed_value_list.v +++ b/test_regress/t/t_struct_packed_value_list.v @@ -19,17 +19,17 @@ module t (/*AUTOARG*/ logic [1:0] e1; logic [3:0] e2; logic [7:0] e3; - } struct_bg; // big endian structure - /* verilator lint_off LITENDIAN */ + } struct_dsc; // descending range structure + /* verilator lint_off ASCRANGE */ struct packed { logic e0; logic [0:1] e1; logic [0:3] e2; logic [0:7] e3; - } struct_lt; // little endian structure - /* verilator lint_on LITENDIAN */ + } struct_asc; // ascending range structure + /* verilator lint_on ASCRANGE */ - localparam WS = 15; // $bits(struct_bg) + localparam WS = 15; // $bits(struct_dsc) integer cnt = 0; @@ -46,70 +46,70 @@ module t (/*AUTOARG*/ $finish; end - // big endian + // descending range always @ (posedge clk) if (cnt[1:0]==2'd0) begin // initialize to defaults (all bits 1'b0) - if (cnt[30:2]==0) struct_bg <= '0; - else if (cnt[30:2]==1) struct_bg <= '0; - else if (cnt[30:2]==2) struct_bg <= '0; - else if (cnt[30:2]==3) struct_bg <= '0; - else if (cnt[30:2]==4) struct_bg <= '0; - else if (cnt[30:2]==5) struct_bg <= '0; - else if (cnt[30:2]==6) struct_bg <= '0; + if (cnt[30:2]==0) struct_dsc <= '0; + else if (cnt[30:2]==1) struct_dsc <= '0; + else if (cnt[30:2]==2) struct_dsc <= '0; + else if (cnt[30:2]==3) struct_dsc <= '0; + else if (cnt[30:2]==4) struct_dsc <= '0; + else if (cnt[30:2]==5) struct_dsc <= '0; + else if (cnt[30:2]==6) struct_dsc <= '0; end else if (cnt[1:0]==2'd1) begin // write data into whole or part of the array using literals if (cnt[30:2]==0) begin end - else if (cnt[30:2]==1) struct_bg <= '{0 ,1 , 2, 3}; - else if (cnt[30:2]==2) struct_bg <= '{e0:1, e1:2, e2:3, e3:4}; - else if (cnt[30:2]==3) struct_bg <= '{e3:6, e2:4, e1:2, e0:0}; + else if (cnt[30:2]==1) struct_dsc <= '{0 ,1 , 2, 3}; + else if (cnt[30:2]==2) struct_dsc <= '{e0:1, e1:2, e2:3, e3:4}; + else if (cnt[30:2]==3) struct_dsc <= '{e3:6, e2:4, e1:2, e0:0}; // verilator lint_off WIDTH - else if (cnt[30:2]==4) struct_bg <= '{default:13}; - else if (cnt[30:2]==5) struct_bg <= '{e2:8'haa, default:1}; - else if (cnt[30:2]==6) struct_bg <= '{cnt+0 ,cnt+1 , cnt+2, cnt+3}; + else if (cnt[30:2]==4) struct_dsc <= '{default:13}; + else if (cnt[30:2]==5) struct_dsc <= '{e2:8'haa, default:1}; + else if (cnt[30:2]==6) struct_dsc <= '{cnt+0 ,cnt+1 , cnt+2, cnt+3}; // verilator lint_on WIDTH end else if (cnt[1:0]==2'd2) begin // chack array agains expected value - if (cnt[30:2]==0) begin if (struct_bg !== 15'b0_00_0000_00000000) begin $display("%b", struct_bg); $stop(); end end - else if (cnt[30:2]==1) begin if (struct_bg !== 15'b0_01_0010_00000011) begin $display("%b", struct_bg); $stop(); end end - else if (cnt[30:2]==2) begin if (struct_bg !== 15'b1_10_0011_00000100) begin $display("%b", struct_bg); $stop(); end end - else if (cnt[30:2]==3) begin if (struct_bg !== 15'b0_10_0100_00000110) begin $display("%b", struct_bg); $stop(); end end - else if (cnt[30:2]==4) begin if (struct_bg !== 15'b1_01_1101_00001101) begin $display("%b", struct_bg); $stop(); end end - else if (cnt[30:2]==5) begin if (struct_bg !== 15'b1_01_1010_00000001) begin $display("%b", struct_bg); $stop(); end end - else if (cnt[30:2]==6) begin if (struct_bg !== 15'b1_10_1011_00011100) begin $display("%b", struct_bg); $stop(); end end + if (cnt[30:2]==0) begin if (struct_dsc !== 15'b0_00_0000_00000000) begin $display("%b", struct_dsc); $stop(); end end + else if (cnt[30:2]==1) begin if (struct_dsc !== 15'b0_01_0010_00000011) begin $display("%b", struct_dsc); $stop(); end end + else if (cnt[30:2]==2) begin if (struct_dsc !== 15'b1_10_0011_00000100) begin $display("%b", struct_dsc); $stop(); end end + else if (cnt[30:2]==3) begin if (struct_dsc !== 15'b0_10_0100_00000110) begin $display("%b", struct_dsc); $stop(); end end + else if (cnt[30:2]==4) begin if (struct_dsc !== 15'b1_01_1101_00001101) begin $display("%b", struct_dsc); $stop(); end end + else if (cnt[30:2]==5) begin if (struct_dsc !== 15'b1_01_1010_00000001) begin $display("%b", struct_dsc); $stop(); end end + else if (cnt[30:2]==6) begin if (struct_dsc !== 15'b1_10_1011_00011100) begin $display("%b", struct_dsc); $stop(); end end end - // little endian + // ascending range always @ (posedge clk) if (cnt[1:0]==2'd0) begin // initialize to defaults (all bits 1'b0) - if (cnt[30:2]==0) struct_lt <= '0; - else if (cnt[30:2]==1) struct_lt <= '0; - else if (cnt[30:2]==2) struct_lt <= '0; - else if (cnt[30:2]==3) struct_lt <= '0; - else if (cnt[30:2]==4) struct_lt <= '0; - else if (cnt[30:2]==5) struct_lt <= '0; - else if (cnt[30:2]==6) struct_lt <= '0; + if (cnt[30:2]==0) struct_asc <= '0; + else if (cnt[30:2]==1) struct_asc <= '0; + else if (cnt[30:2]==2) struct_asc <= '0; + else if (cnt[30:2]==3) struct_asc <= '0; + else if (cnt[30:2]==4) struct_asc <= '0; + else if (cnt[30:2]==5) struct_asc <= '0; + else if (cnt[30:2]==6) struct_asc <= '0; end else if (cnt[1:0]==2'd1) begin // write data into whole or part of the array using literals if (cnt[30:2]==0) begin end - else if (cnt[30:2]==1) struct_lt <= '{0 ,1 , 2, 3}; - else if (cnt[30:2]==2) struct_lt <= '{e0:1, e1:2, e2:3, e3:4}; - else if (cnt[30:2]==3) struct_lt <= '{e3:6, e2:4, e1:2, e0:0}; + else if (cnt[30:2]==1) struct_asc <= '{0 ,1 , 2, 3}; + else if (cnt[30:2]==2) struct_asc <= '{e0:1, e1:2, e2:3, e3:4}; + else if (cnt[30:2]==3) struct_asc <= '{e3:6, e2:4, e1:2, e0:0}; // verilator lint_off WIDTH - else if (cnt[30:2]==4) struct_lt <= '{default:13}; - else if (cnt[30:2]==5) struct_lt <= '{e2:8'haa, default:1}; - else if (cnt[30:2]==6) struct_lt <= '{cnt+0 ,cnt+1 , cnt+2, cnt+3}; + else if (cnt[30:2]==4) struct_asc <= '{default:13}; + else if (cnt[30:2]==5) struct_asc <= '{e2:8'haa, default:1}; + else if (cnt[30:2]==6) struct_asc <= '{cnt+0 ,cnt+1 , cnt+2, cnt+3}; // verilator lint_on WIDTH end else if (cnt[1:0]==2'd2) begin // chack array agains expected value - if (cnt[30:2]==0) begin if (struct_lt !== 15'b0_00_0000_00000000) begin $display("%b", struct_lt); $stop(); end end - else if (cnt[30:2]==1) begin if (struct_lt !== 15'b0_01_0010_00000011) begin $display("%b", struct_lt); $stop(); end end - else if (cnt[30:2]==2) begin if (struct_lt !== 15'b1_10_0011_00000100) begin $display("%b", struct_lt); $stop(); end end - else if (cnt[30:2]==3) begin if (struct_lt !== 15'b0_10_0100_00000110) begin $display("%b", struct_lt); $stop(); end end - else if (cnt[30:2]==4) begin if (struct_lt !== 15'b1_01_1101_00001101) begin $display("%b", struct_lt); $stop(); end end - else if (cnt[30:2]==5) begin if (struct_lt !== 15'b1_01_1010_00000001) begin $display("%b", struct_lt); $stop(); end end - else if (cnt[30:2]==6) begin if (struct_lt !== 15'b1_10_1011_00011100) begin $display("%b", struct_lt); $stop(); end end + if (cnt[30:2]==0) begin if (struct_asc !== 15'b0_00_0000_00000000) begin $display("%b", struct_asc); $stop(); end end + else if (cnt[30:2]==1) begin if (struct_asc !== 15'b0_01_0010_00000011) begin $display("%b", struct_asc); $stop(); end end + else if (cnt[30:2]==2) begin if (struct_asc !== 15'b1_10_0011_00000100) begin $display("%b", struct_asc); $stop(); end end + else if (cnt[30:2]==3) begin if (struct_asc !== 15'b0_10_0100_00000110) begin $display("%b", struct_asc); $stop(); end end + else if (cnt[30:2]==4) begin if (struct_asc !== 15'b1_01_1101_00001101) begin $display("%b", struct_asc); $stop(); end end + else if (cnt[30:2]==5) begin if (struct_asc !== 15'b1_01_1010_00000001) begin $display("%b", struct_asc); $stop(); end end + else if (cnt[30:2]==6) begin if (struct_asc !== 15'b1_10_1011_00011100) begin $display("%b", struct_asc); $stop(); end end end endmodule diff --git a/test_regress/t/t_struct_packed_write_read.v b/test_regress/t/t_struct_packed_write_read.v index 7616b1593..fa7761d7d 100644 --- a/test_regress/t/t_struct_packed_write_read.v +++ b/test_regress/t/t_struct_packed_write_read.v @@ -19,17 +19,17 @@ module t (/*AUTOARG*/ logic [1:0] e1; logic [3:0] e2; logic [7:0] e3; - } struct_bg; // big endian structure - /* verilator lint_off LITENDIAN */ + } struct_dsc; // descending range structure + /* verilator lint_off ASCRANGE */ struct packed { logic e0; logic [0:1] e1; logic [0:3] e2; logic [0:7] e3; - } struct_lt; // little endian structure - /* verilator lint_on LITENDIAN */ + } struct_asc; // ascending range structure + /* verilator lint_on ASCRANGE */ - localparam WS = 15; // $bits(struct_bg) + localparam WS = 15; // $bits(struct_dsc) integer cnt = 0; @@ -46,76 +46,76 @@ module t (/*AUTOARG*/ $finish; end - // big endian + // descending range always @ (posedge clk) if (cnt[1:0]==2'd0) begin // initialize to defaaults (all bits to 0) - if (cnt[30:2]==0) struct_bg <= '0; - else if (cnt[30:2]==1) struct_bg <= '0; - else if (cnt[30:2]==2) struct_bg <= '0; - else if (cnt[30:2]==3) struct_bg <= '0; - else if (cnt[30:2]==4) struct_bg <= '0; - else if (cnt[30:2]==5) struct_bg <= '0; + if (cnt[30:2]==0) struct_dsc <= '0; + else if (cnt[30:2]==1) struct_dsc <= '0; + else if (cnt[30:2]==2) struct_dsc <= '0; + else if (cnt[30:2]==3) struct_dsc <= '0; + else if (cnt[30:2]==4) struct_dsc <= '0; + else if (cnt[30:2]==5) struct_dsc <= '0; end else if (cnt[1:0]==2'd1) begin // write value to structure if (cnt[30:2]==0) begin end - else if (cnt[30:2]==1) struct_bg <= '1; - else if (cnt[30:2]==2) struct_bg.e0 <= '1; - else if (cnt[30:2]==3) struct_bg.e1 <= '1; - else if (cnt[30:2]==4) struct_bg.e2 <= '1; - else if (cnt[30:2]==5) struct_bg.e3 <= '1; + else if (cnt[30:2]==1) struct_dsc <= '1; + else if (cnt[30:2]==2) struct_dsc.e0 <= '1; + else if (cnt[30:2]==3) struct_dsc.e1 <= '1; + else if (cnt[30:2]==4) struct_dsc.e2 <= '1; + else if (cnt[30:2]==5) struct_dsc.e3 <= '1; end else if (cnt[1:0]==2'd2) begin // check structure value - if (cnt[30:2]==0) begin if (struct_bg !== 15'b000000000000000) begin $display("%b", struct_bg); $stop(); end end - else if (cnt[30:2]==1) begin if (struct_bg !== 15'b111111111111111) begin $display("%b", struct_bg); $stop(); end end - else if (cnt[30:2]==2) begin if (struct_bg !== 15'b100000000000000) begin $display("%b", struct_bg); $stop(); end end - else if (cnt[30:2]==3) begin if (struct_bg !== 15'b011000000000000) begin $display("%b", struct_bg); $stop(); end end - else if (cnt[30:2]==4) begin if (struct_bg !== 15'b000111100000000) begin $display("%b", struct_bg); $stop(); end end - else if (cnt[30:2]==5) begin if (struct_bg !== 15'b000000011111111) begin $display("%b", struct_bg); $stop(); end end + if (cnt[30:2]==0) begin if (struct_dsc !== 15'b000000000000000) begin $display("%b", struct_dsc); $stop(); end end + else if (cnt[30:2]==1) begin if (struct_dsc !== 15'b111111111111111) begin $display("%b", struct_dsc); $stop(); end end + else if (cnt[30:2]==2) begin if (struct_dsc !== 15'b100000000000000) begin $display("%b", struct_dsc); $stop(); end end + else if (cnt[30:2]==3) begin if (struct_dsc !== 15'b011000000000000) begin $display("%b", struct_dsc); $stop(); end end + else if (cnt[30:2]==4) begin if (struct_dsc !== 15'b000111100000000) begin $display("%b", struct_dsc); $stop(); end end + else if (cnt[30:2]==5) begin if (struct_dsc !== 15'b000000011111111) begin $display("%b", struct_dsc); $stop(); end end end else if (cnt[1:0]==2'd3) begin // read value from structure (not a very good test for now) - if (cnt[30:2]==0) begin if (struct_bg !== {WS{1'b0}}) $stop(); end - else if (cnt[30:2]==1) begin if (struct_bg !== {WS{1'b1}}) $stop(); end - else if (cnt[30:2]==2) begin if (struct_bg.e0 !== { 1{1'b1}}) $stop(); end - else if (cnt[30:2]==3) begin if (struct_bg.e1 !== { 2{1'b1}}) $stop(); end - else if (cnt[30:2]==4) begin if (struct_bg.e2 !== { 4{1'b1}}) $stop(); end - else if (cnt[30:2]==5) begin if (struct_bg.e3 !== { 8{1'b1}}) $stop(); end + if (cnt[30:2]==0) begin if (struct_dsc !== {WS{1'b0}}) $stop(); end + else if (cnt[30:2]==1) begin if (struct_dsc !== {WS{1'b1}}) $stop(); end + else if (cnt[30:2]==2) begin if (struct_dsc.e0 !== { 1{1'b1}}) $stop(); end + else if (cnt[30:2]==3) begin if (struct_dsc.e1 !== { 2{1'b1}}) $stop(); end + else if (cnt[30:2]==4) begin if (struct_dsc.e2 !== { 4{1'b1}}) $stop(); end + else if (cnt[30:2]==5) begin if (struct_dsc.e3 !== { 8{1'b1}}) $stop(); end end - // little endian + // ascending range always @ (posedge clk) if (cnt[1:0]==2'd0) begin // initialize to defaaults (all bits to 0) - if (cnt[30:2]==0) struct_lt <= '0; - else if (cnt[30:2]==1) struct_lt <= '0; - else if (cnt[30:2]==2) struct_lt <= '0; - else if (cnt[30:2]==3) struct_lt <= '0; - else if (cnt[30:2]==4) struct_lt <= '0; - else if (cnt[30:2]==5) struct_lt <= '0; + if (cnt[30:2]==0) struct_asc <= '0; + else if (cnt[30:2]==1) struct_asc <= '0; + else if (cnt[30:2]==2) struct_asc <= '0; + else if (cnt[30:2]==3) struct_asc <= '0; + else if (cnt[30:2]==4) struct_asc <= '0; + else if (cnt[30:2]==5) struct_asc <= '0; end else if (cnt[1:0]==2'd1) begin // write value to structure if (cnt[30:2]==0) begin end - else if (cnt[30:2]==1) struct_lt <= '1; - else if (cnt[30:2]==2) struct_lt.e0 <= '1; - else if (cnt[30:2]==3) struct_lt.e1 <= '1; - else if (cnt[30:2]==4) struct_lt.e2 <= '1; - else if (cnt[30:2]==5) struct_lt.e3 <= '1; + else if (cnt[30:2]==1) struct_asc <= '1; + else if (cnt[30:2]==2) struct_asc.e0 <= '1; + else if (cnt[30:2]==3) struct_asc.e1 <= '1; + else if (cnt[30:2]==4) struct_asc.e2 <= '1; + else if (cnt[30:2]==5) struct_asc.e3 <= '1; end else if (cnt[1:0]==2'd2) begin // check structure value - if (cnt[30:2]==0) begin if (struct_lt !== 15'b000000000000000) begin $display("%b", struct_lt); $stop(); end end - else if (cnt[30:2]==1) begin if (struct_lt !== 15'b111111111111111) begin $display("%b", struct_lt); $stop(); end end - else if (cnt[30:2]==2) begin if (struct_lt !== 15'b100000000000000) begin $display("%b", struct_lt); $stop(); end end - else if (cnt[30:2]==3) begin if (struct_lt !== 15'b011000000000000) begin $display("%b", struct_lt); $stop(); end end - else if (cnt[30:2]==4) begin if (struct_lt !== 15'b000111100000000) begin $display("%b", struct_lt); $stop(); end end - else if (cnt[30:2]==5) begin if (struct_lt !== 15'b000000011111111) begin $display("%b", struct_lt); $stop(); end end + if (cnt[30:2]==0) begin if (struct_asc !== 15'b000000000000000) begin $display("%b", struct_asc); $stop(); end end + else if (cnt[30:2]==1) begin if (struct_asc !== 15'b111111111111111) begin $display("%b", struct_asc); $stop(); end end + else if (cnt[30:2]==2) begin if (struct_asc !== 15'b100000000000000) begin $display("%b", struct_asc); $stop(); end end + else if (cnt[30:2]==3) begin if (struct_asc !== 15'b011000000000000) begin $display("%b", struct_asc); $stop(); end end + else if (cnt[30:2]==4) begin if (struct_asc !== 15'b000111100000000) begin $display("%b", struct_asc); $stop(); end end + else if (cnt[30:2]==5) begin if (struct_asc !== 15'b000000011111111) begin $display("%b", struct_asc); $stop(); end end end else if (cnt[1:0]==2'd3) begin // read value from structure (not a very good test for now) - if (cnt[30:2]==0) begin if (struct_lt !== {WS{1'b0}}) $stop(); end - else if (cnt[30:2]==1) begin if (struct_lt !== {WS{1'b1}}) $stop(); end - else if (cnt[30:2]==2) begin if (struct_lt.e0 !== { 1{1'b1}}) $stop(); end - else if (cnt[30:2]==3) begin if (struct_lt.e1 !== { 2{1'b1}}) $stop(); end - else if (cnt[30:2]==4) begin if (struct_lt.e2 !== { 4{1'b1}}) $stop(); end - else if (cnt[30:2]==5) begin if (struct_lt.e3 !== { 8{1'b1}}) $stop(); end + if (cnt[30:2]==0) begin if (struct_asc !== {WS{1'b0}}) $stop(); end + else if (cnt[30:2]==1) begin if (struct_asc !== {WS{1'b1}}) $stop(); end + else if (cnt[30:2]==2) begin if (struct_asc.e0 !== { 1{1'b1}}) $stop(); end + else if (cnt[30:2]==3) begin if (struct_asc.e1 !== { 2{1'b1}}) $stop(); end + else if (cnt[30:2]==4) begin if (struct_asc.e2 !== { 4{1'b1}}) $stop(); end + else if (cnt[30:2]==5) begin if (struct_asc.e3 !== { 8{1'b1}}) $stop(); end end endmodule diff --git a/test_regress/t/t_sys_readmem.v b/test_regress/t/t_sys_readmem.v index ca79d8b0c..98a025ee8 100644 --- a/test_regress/t/t_sys_readmem.v +++ b/test_regress/t/t_sys_readmem.v @@ -14,7 +14,7 @@ module t; - // verilator lint_off LITENDIAN + // verilator lint_off ASCRANGE reg [5:0] binary_string [2:15]; reg [5:0] binary_nostart [2:15]; reg [5:0] binary_start [0:15]; @@ -30,7 +30,7 @@ module t; reg [(32*6)-1:0] hex_align_tmp [0:15]; string fns_tmp; `endif - // verilator lint_on LITENDIAN + // verilator lint_on ASCRANGE integer i; diff --git a/test_regress/t/t_trace_litendian.out b/test_regress/t/t_trace_ascendingrange.out similarity index 100% rename from test_regress/t/t_trace_litendian.out rename to test_regress/t/t_trace_ascendingrange.out diff --git a/test_regress/t/t_trace_litendian.pl b/test_regress/t/t_trace_ascendingrange.pl similarity index 92% rename from test_regress/t/t_trace_litendian.pl rename to test_regress/t/t_trace_ascendingrange.pl index 3ecfa6bc6..aedb9ce36 100755 --- a/test_regress/t/t_trace_litendian.pl +++ b/test_regress/t/t_trace_ascendingrange.pl @@ -14,7 +14,7 @@ scenarios(simulator => 1); # %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads. # Strangely, asking for more threads makes it go away. compile( - verilator_flags2 => ['--cc --trace --trace-params -Wno-LITENDIAN'], + verilator_flags2 => ['--cc --trace --trace-params -Wno-ASCRANGE'], threads => $Self->{vltmt} ? 6 : 1 ); diff --git a/test_regress/t/t_trace_litendian.v b/test_regress/t/t_trace_ascendingrange.v similarity index 100% rename from test_regress/t/t_trace_litendian.v rename to test_regress/t/t_trace_ascendingrange.v diff --git a/test_regress/t/t_trace_litendian_fst.out b/test_regress/t/t_trace_ascendingrange_fst.out similarity index 100% rename from test_regress/t/t_trace_litendian_fst.out rename to test_regress/t/t_trace_ascendingrange_fst.out diff --git a/test_regress/t/t_trace_litendian_fst.pl b/test_regress/t/t_trace_ascendingrange_fst.pl similarity index 88% rename from test_regress/t/t_trace_litendian_fst.pl rename to test_regress/t/t_trace_ascendingrange_fst.pl index 754bea6fd..54e75cec9 100755 --- a/test_regress/t/t_trace_litendian_fst.pl +++ b/test_regress/t/t_trace_ascendingrange_fst.pl @@ -10,13 +10,13 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -top_filename("t/t_trace_litendian.v"); +top_filename("t/t_trace_ascendingrange.v"); # CI environment offers 2 VCPUs, 2 thread setting causes the following warning. # %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads. # Strangely, asking for more threads makes it go away. compile( - verilator_flags2 => ['--cc --trace-fst --trace-params -Wno-LITENDIAN'], + verilator_flags2 => ['--cc --trace-fst --trace-params -Wno-ASCRANGE'], threads => $Self->{vltmt} ? 6 : 1 ); diff --git a/test_regress/t/t_trace_litendian_fst_sc.out b/test_regress/t/t_trace_ascendingrange_fst_sc.out similarity index 100% rename from test_regress/t/t_trace_litendian_fst_sc.out rename to test_regress/t/t_trace_ascendingrange_fst_sc.out diff --git a/test_regress/t/t_trace_litendian_fst_sc.pl b/test_regress/t/t_trace_ascendingrange_fst_sc.pl similarity index 94% rename from test_regress/t/t_trace_litendian_fst_sc.pl rename to test_regress/t/t_trace_ascendingrange_fst_sc.pl index 40366a231..864a69b97 100755 --- a/test_regress/t/t_trace_litendian_fst_sc.pl +++ b/test_regress/t/t_trace_ascendingrange_fst_sc.pl @@ -14,13 +14,13 @@ if (!$Self->have_sc) { skip("No SystemC installed"); } else { - top_filename("t/t_trace_litendian.v"); + top_filename("t/t_trace_ascendingrange.v"); # CI environment offers 2 VCPUs, 2 thread setting causes the following warning. # %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads. # Strangely, asking for more threads makes it go away. compile( - verilator_flags2 => ['--sc --trace-fst --trace-params -Wno-LITENDIAN'], + verilator_flags2 => ['--sc --trace-fst --trace-params -Wno-ASCRANGE'], threads => $Self->{vltmt} ? 6 : 1 ); diff --git a/test_regress/t/t_trace_public.v b/test_regress/t/t_trace_public.v index c3d0c9603..e6ea04953 100644 --- a/test_regress/t/t_trace_public.v +++ b/test_regress/t/t_trace_public.v @@ -68,11 +68,11 @@ module little ( input clk ); - // verilator lint_off LITENDIAN + // verilator lint_off ASCRANGE reg [0:7] i8; initial i8 = '0; reg [1:49] i48; initial i48 = '0; reg [63:190] i128; initial i128 = '0; - // verilator lint_on LITENDIAN + // verilator lint_on ASCRANGE always @ (posedge clk) begin i8 <= ~i8; diff --git a/test_regress/t/t_typedef_array.v b/test_regress/t/t_typedef_array.v index 018d6abbd..8fe08ffcc 100644 --- a/test_regress/t/t_typedef_array.v +++ b/test_regress/t/t_typedef_array.v @@ -8,9 +8,9 @@ typedef logic logic_alias_t; module t; logic_alias_t [6:1] signal; - // verilator lint_off LITENDIAN + // verilator lint_off ASCRANGE logic_alias_t [1:6] signal2; - // verilator lint_on LITENDIAN + // verilator lint_on ASCRANGE initial begin signal[6:1] = 'b100001; diff --git a/test_regress/t/t_vpi_var.v b/test_regress/t/t_vpi_var.v index ebc707eb3..80188af11 100644 --- a/test_regress/t/t_vpi_var.v +++ b/test_regress/t/t_vpi_var.v @@ -30,9 +30,9 @@ extern "C" int mon_check(); reg [2:1] fourthreetwoone[4:3] /*verilator public_flat_rw @(posedge clk) */; reg LONGSTART_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_LONGEND /*verilator public_flat_rw*/; - // verilator lint_off LITENDIAN + // verilator lint_off ASCRANGE reg [0:61] quads[2:3] /*verilator public_flat_rw @(posedge clk) */; - // verilator lint_on LITENDIAN + // verilator lint_on ASCRANGE reg [31:0] count /*verilator public_flat_rd */; reg [31:0] half_count /*verilator public_flat_rd */; diff --git a/test_regress/t/t_vpi_var2.v b/test_regress/t/t_vpi_var2.v index ca24c06f2..dc04a1c7f 100644 --- a/test_regress/t/t_vpi_var2.v +++ b/test_regress/t/t_vpi_var2.v @@ -39,11 +39,11 @@ extern "C" int mon_check(); reg [2:1] twoone; reg [2:1] fourthreetwoone[4:3]; reg LONGSTART_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_LONGEND; - // verilator lint_off LITENDIAN + // verilator lint_off ASCRANGE reg [0:61] quads[2:3] /*verilator public_flat_rw @(posedge clk)*/; /*verilator public_off*/ reg invisible1; - // verilator lint_on LITENDIAN + // verilator lint_on ASCRANGE /*verilator public_flat_rd_on*/ reg [31:0] count; From daf157e6c07078d8762da5c5408b81fefe175734 Mon Sep 17 00:00:00 2001 From: Jesse Taube Date: Tue, 21 Mar 2023 04:42:19 -0400 Subject: [PATCH 077/155] Fix false LATCH warning on --assert 'unique else if' (#4033) (#4054). --- Changes | 1 + docs/CONTRIBUTORS | 1 + src/V3Const.cpp | 1 + 3 files changed, 3 insertions(+) diff --git a/Changes b/Changes index e913ad400..9219179df 100644 --- a/Changes +++ b/Changes @@ -19,6 +19,7 @@ Verilator 5.009 devel * Support $fopen as an expression. * Support class extends of package::class. * Change ZERODLY to a warning. +* Fix false LATCH warning on --assert 'unique else if' (#4033). [Jesse Taube] * Fix UNDRIVEN warning seg fault (#3989). [Felix Neumärker] * Fix symbol entries when inheriting classes (#3995) (#3996). [Krzysztof Boroński] * Fix push to dynamic queue in struct (#4015). [ezchi] diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index aad4beb04..215fb6bd8 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -61,6 +61,7 @@ Jamie Iles Jan Van Winkel Jean Berniolles Jeremy Bennett +Jesse Taube Jevin Sweval Jiacheng Qian Jiuyang Liu diff --git a/src/V3Const.cpp b/src/V3Const.cpp index da4a74f62..abe512fef 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -2975,6 +2975,7 @@ private: AstNode* const thensp = nodep->thensp()->unlinkFrBackWithNext(); AstNode* const elsesp = nodep->elsesp()->unlinkFrBackWithNext(); AstIf* const ifp = new AstIf{nodep->fileline(), condp, elsesp, thensp}; + ifp->isBoundsCheck(nodep->isBoundsCheck()); // Copy bounds check info ifp->branchPred(nodep->branchPred().invert()); nodep->replaceWith(ifp); VL_DO_DANGLING(nodep->deleteTree(), nodep); From 71a37484f5304ffae477d47a4ba4dfe4c0289b2e Mon Sep 17 00:00:00 2001 From: github action Date: Tue, 21 Mar 2023 08:43:31 +0000 Subject: [PATCH 078/155] Apply 'make format' --- src/V3Const.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/V3Const.cpp b/src/V3Const.cpp index abe512fef..146386acc 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -2975,7 +2975,7 @@ private: AstNode* const thensp = nodep->thensp()->unlinkFrBackWithNext(); AstNode* const elsesp = nodep->elsesp()->unlinkFrBackWithNext(); AstIf* const ifp = new AstIf{nodep->fileline(), condp, elsesp, thensp}; - ifp->isBoundsCheck(nodep->isBoundsCheck()); // Copy bounds check info + ifp->isBoundsCheck(nodep->isBoundsCheck()); // Copy bounds check info ifp->branchPred(nodep->branchPred().invert()); nodep->replaceWith(ifp); VL_DO_DANGLING(nodep->deleteTree(), nodep); From 577e0700ba881a77ab0db758ff3e4566519711e5 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 21 Mar 2023 04:52:12 -0400 Subject: [PATCH 079/155] Commentary: Changes update --- Changes | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Changes b/Changes index 9219179df..1541a09df 100644 --- a/Changes +++ b/Changes @@ -15,17 +15,26 @@ Verilator 5.009 devel * Add --public-depth to force public to a certain instance depth (#3952). [Andrew Nolte] * Add --public-params flag (#3990). [Andrew Nolte] +* Add STATICVAR warning and convert to automatic (#4018) (#4027) (#4030). [Ryszard Rozak, Antmicro Ltd] +* Support class extends of package::class. +* Support method calls without parenthesis (#4034). [Ryszard Rozak, Antmicro Ltd] * Support complicated IEEE 'for' assignments. * Support $fopen as an expression. -* Support class extends of package::class. +* Change range order warning from LITENDIAN to ASCRANGE (#4010). [Iztok Jeras] * Change ZERODLY to a warning. -* Fix false LATCH warning on --assert 'unique else if' (#4033). [Jesse Taube] +* Fix random internal crashes (#666). [Dag Lem] +* Fix install, standardization in cmake CMakeLists.txt (#3974). [Yu-Sheng Lin] * Fix UNDRIVEN warning seg fault (#3989). [Felix Neumärker] * Fix symbol entries when inheriting classes (#3995) (#3996). [Krzysztof Boroński] +* Fix event controls reusing same variable (#4014). Kamil Rakoczy * Fix push to dynamic queue in struct (#4015). [ezchi] +* Fix names for blocks in do..while loop (#4019). [Ryszard Rozak, Antmicro Ltd] +* Fix randomize on null field (#4023). [Ryszard Rozak, Antmicro Ltd] +* Fix rand fields in base classes (#4025). [Ryszard Rozak, Antmicro Ltd] * Fix large return blocks with --comp-limit-blocks (#4028). [tenghtt] * Fix clocking block scope internal error (#4032). [Srinivasan Venkataramanan] -* Fix random internal crashes (#666). [Dag Lem] +* Fix false LATCH warning on --assert 'unique else if' (#4033) ($4054). [Jesse Taube] +* Fix characters from DEFENV literals for conda (#4035) (#4044). [Tim Snyder] * Fix false ENUMVALUE on expressions and arrays. From 5de8ccbf321ff747531def28d4522f27de28bfc5 Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Tue, 21 Mar 2023 13:50:53 +0100 Subject: [PATCH 080/155] Fix task calls as fork statements (#4055) Before this patch, calling tasks directly under forks would result in each statement of these tasks being executed concurrently. This was due to Verilator inlining tasks most of the time. Such inlined tasks' statements would simply replace the original call, and there would be no indication that these used to be grouped together. Ultimately resulting in `V3Timing` treating each statement as a separate process. The solution is simply to wrap each fork sub-statement in a begin in `V3Begin` (except for the ones that are begins, as that would be pointless). `V3Begin` is already aware of forks, and is supposed to avoid issues like this one, so it seems like a natural fit. This also protects us from similar bugs, i.e. if some statement gets replaced or expanded into multiple statements. Signed-off-by: Krzysztof Bieganski --- src/V3Begin.cpp | 13 ++++++++++- test_regress/t/t_timing_debug2.out | 2 +- test_regress/t/t_timing_fork_taskcall.pl | 28 ++++++++++++++++++++++++ test_regress/t/t_timing_fork_taskcall.v | 23 +++++++++++++++++++ 4 files changed, 64 insertions(+), 2 deletions(-) create mode 100755 test_regress/t/t_timing_fork_taskcall.pl create mode 100644 test_regress/t/t_timing_fork_taskcall.v diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index b936e33bb..c2a06df4b 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -144,9 +144,20 @@ private: // VISITORS void visit(AstFork* nodep) override { - // Keep this begin to group its statements together + // Keep begins in forks to group their statements together VL_RESTORER(m_keepBegins); m_keepBegins = true; + // If a statement is not a begin, wrap it in a begin. This fixes an issue when the + // statement is a task call that gets inlined later (or any other statement that gets + // replaced with multiple statements) + for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { + if (!VN_IS(stmtp, Begin)) { + AstBegin* const beginp = new AstBegin{stmtp->fileline(), "", nullptr}; + stmtp->replaceWith(beginp); + beginp->addStmtsp(stmtp); + stmtp = beginp; + } + } dotNames(nodep, "__FORK__"); nodep->name(""); } diff --git a/test_regress/t/t_timing_debug2.out b/test_regress/t/t_timing_debug2.out index bbb0b3fe2..3a4ac0ecb 100644 --- a/test_regress/t/t_timing_debug2.out +++ b/test_regress/t/t_timing_debug2.out @@ -526,7 +526,7 @@ -V{t#,#} Resuming delayed processes -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:91 -V{t#,#} Resuming: Process waiting at t/t_timing_class.v:89 --V{t#,#}+ Vt_timing_debug2_t____Vfork_h########__0__1 +-V{t#,#}+ Vt_timing_debug2_t____Vfork_h########__0__0 -V{t#,#}+ Vt_timing_debug2_t__03a__03aAssignDelayClass::__VnoInFunc_do_assign -V{t#,#}+ Vt_timing_debug2___024root___eval_act -V{t#,#}+ Vt_timing_debug2___024root___eval_triggers__act diff --git a/test_regress/t/t_timing_fork_taskcall.pl b/test_regress/t/t_timing_fork_taskcall.pl new file mode 100755 index 000000000..439181d0a --- /dev/null +++ b/test_regress/t/t_timing_fork_taskcall.pl @@ -0,0 +1,28 @@ +#!/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 Antmicro Ltd. 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); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_timing_fork_taskcall.v b/test_regress/t/t_timing_fork_taskcall.v new file mode 100644 index 000000000..f2b45b66b --- /dev/null +++ b/test_regress/t/t_timing_fork_taskcall.v @@ -0,0 +1,23 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t; + task foo; + #1 if ($time != 1) $stop; + #1 if ($time != 2) $stop; + #1 if ($time != 3) $stop; + endtask + + initial fork + foo; + foo; + foo; + #4 begin + $write("*-* All Finished *-*\n"); + $finish; + end + join +endmodule From 277bd67f721aa412f257c62771075c95dc9df9c9 Mon Sep 17 00:00:00 2001 From: Aleksander Kiryk Date: Tue, 21 Mar 2023 15:39:29 +0100 Subject: [PATCH 081/155] Fix NBAs inside fork-joins (#4050) --- src/V3Delayed.cpp | 4 +++- test_regress/t/t_timing_fork_nba.pl | 23 +++++++++++++++++++++++ test_regress/t/t_timing_fork_nba.v | 20 ++++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100755 test_regress/t/t_timing_fork_nba.pl create mode 100644 test_regress/t/t_timing_fork_nba.v diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index 2c30c392e..d249b2637 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -474,7 +474,9 @@ private: m_inSuspendableOrFork = true; iterateChildren(nodep); } - void visit(AstCAwait* nodep) override { m_timingDomains.insert(nodep->sensesp()); } + void visit(AstCAwait* nodep) override { + if (nodep->sensesp()) m_timingDomains.insert(nodep->sensesp()); + } void visit(AstFireEvent* nodep) override { UASSERT_OBJ(v3Global.hasEvents(), nodep, "Inconsistent"); FileLine* const flp = nodep->fileline(); diff --git a/test_regress/t/t_timing_fork_nba.pl b/test_regress/t/t_timing_fork_nba.pl new file mode 100755 index 000000000..372246cb3 --- /dev/null +++ b/test_regress/t/t_timing_fork_nba.pl @@ -0,0 +1,23 @@ +#!/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); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--exe --timing"], + ); +} + +ok(1); +1; diff --git a/test_regress/t/t_timing_fork_nba.v b/test_regress/t/t_timing_fork_nba.v new file mode 100644 index 000000000..013367bdf --- /dev/null +++ b/test_regress/t/t_timing_fork_nba.v @@ -0,0 +1,20 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + reg b = 0, c = 1; + + always @(posedge clk) begin + fork + b <= c; + c <= b; + join + end +endmodule From f439a7927f93ed522b850fcab6214a7e4d95b474 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Thu, 23 Mar 2023 10:20:35 +0100 Subject: [PATCH 082/155] Fix parameters in a class body to be localparam (#4061) --- src/verilog.y | 10 +++++- .../t/t_class_param_override_local_bad.out | 14 ++++++++ .../t/t_class_param_override_local_bad.pl | 19 +++++++++++ .../t/t_class_param_override_local_bad.v | 34 +++++++++++++++++++ 4 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 test_regress/t/t_class_param_override_local_bad.out create mode 100755 test_regress/t/t_class_param_override_local_bad.pl create mode 100644 test_regress/t/t_class_param_override_local_bad.v diff --git a/src/verilog.y b/src/verilog.y index d98a33172..e2e0cd2e2 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -96,6 +96,7 @@ public: bool m_pinAnsi = false; // In ANSI port list bool m_tracingParse = true; // Tracing disable for parser bool m_inImplements = false; // Is inside class implements list + bool m_insideClass = false; // Is inside a class body bool m_insideProperty = false; // Is inside property declaration bool m_typedPropertyPort = false; // Typed property port occurred on port lists bool m_modportImpExpActive @@ -1947,7 +1948,12 @@ net_type: // ==IEEE: net_type ; varParamReset: - yPARAMETER { VARRESET_NONLIST(GPARAM); } + yPARAMETER + { if (GRAMMARP->m_insideClass) { + VARRESET_NONLIST(LPARAM); + } else { + VARRESET_NONLIST(GPARAM); + } } | yLOCALPARAM { VARRESET_NONLIST(LPARAM); } ; @@ -6708,6 +6714,7 @@ class_declaration: // ==IEEE: part of class_declaration classFront parameter_port_listE classExtendsE classImplementsE ';' /*mid*/ { // Allow resolving types declared in base extends class if ($3) SYMP->importExtends($3); + GRAMMARP->m_insideClass = true; } /*cont*/ class_itemListE yENDCLASS endLabelE { $$ = $1; $1->addMembersp($2); @@ -6715,6 +6722,7 @@ class_declaration: // ==IEEE: part of class_declaration $1->addExtendsp($4); $1->addMembersp($7); SYMP->popScope($$); + GRAMMARP->m_insideClass = false; GRAMMARP->endLabel($9, $1, $9); } ; diff --git a/test_regress/t/t_class_param_override_local_bad.out b/test_regress/t/t_class_param_override_local_bad.out new file mode 100644 index 000000000..dacafe468 --- /dev/null +++ b/test_regress/t/t_class_param_override_local_bad.out @@ -0,0 +1,14 @@ +%Error-PINNOTFOUND: t/t_class_param_override_local_bad.v:23:30: Parameter pin not found: '__paramNumber1' + 23 | class Cls3 implements Icls1#(2), Icls2#(0); + | ^ + ... For error description see https://verilator.org/warn/PINNOTFOUND?v=latest +%Error-PINNOTFOUND: t/t_class_param_override_local_bad.v:23:41: Parameter pin not found: '__paramNumber1' + 23 | class Cls3 implements Icls1#(2), Icls2#(0); + | ^ +%Error-PINNOTFOUND: t/t_class_param_override_local_bad.v:29:23: Parameter pin not found: '__paramNumber1' + 29 | automatic Cls1#(bit) cls1 = new; + | ^~~ +%Error-PINNOTFOUND: t/t_class_param_override_local_bad.v:30:23: Parameter pin not found: '__paramNumber1' + 30 | automatic Cls2#(1) cls2 = new; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_class_param_override_local_bad.pl b/test_regress/t/t_class_param_override_local_bad.pl new file mode 100755 index 000000000..a5846c699 --- /dev/null +++ b/test_regress/t/t_class_param_override_local_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 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(vlt => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_param_override_local_bad.v b/test_regress/t/t_class_param_override_local_bad.v new file mode 100644 index 000000000..a608fbefa --- /dev/null +++ b/test_regress/t/t_class_param_override_local_bad.v @@ -0,0 +1,34 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Cls1; + parameter type T = int; +endclass + +class Cls2; + localparam int P = 0; +endclass + +interface class Icls1; + localparam LP1 = 1; +endclass + +interface class Icls2; + parameter LP1 = 1; +endclass + +class Cls3 implements Icls1#(2), Icls2#(0); +endclass + +module t (/*AUTOARG*/); + + initial begin + automatic Cls1#(bit) cls1 = new; + automatic Cls2#(1) cls2 = new; + automatic Cls3 cls3 = new; + $stop; + end +endmodule From 449ac4413191c8cafc16a4b262fbdee19b1c1ce1 Mon Sep 17 00:00:00 2001 From: Josep Sans Date: Fri, 24 Mar 2023 11:51:02 +0100 Subject: [PATCH 083/155] Fix _Vilp used before declaration (#4057) (#4062) --- docs/CONTRIBUTORS | 1 + src/V3Reloop.cpp | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 215fb6bd8..cede3c759 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -70,6 +70,7 @@ John Coiner John Demme Jonathan Drolet Joseph Nwabueze +Josep Sans Josh Redford Julie Schwartz Julien Margetts diff --git a/src/V3Reloop.cpp b/src/V3Reloop.cpp index 5f605ebcf..bd2d110c0 100644 --- a/src/V3Reloop.cpp +++ b/src/V3Reloop.cpp @@ -75,7 +75,10 @@ private: const string newvarname{"__Vilp"}; varp = new AstVar{fl, VVarType::STMTTEMP, newvarname, VFlagLogicPacked{}, 32}; UASSERT_OBJ(cfuncp, fl, "Assignment not under a function"); - cfuncp->addInitsp(varp); + if (cfuncp->initsp()) + cfuncp->initsp()->addNextHere(varp); + else + cfuncp->addInitsp(varp); cfuncp->user1p(varp); } return varp; From 5b86248b5460133978ed44a7f382d80b55e9121c Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Fri, 24 Mar 2023 18:18:20 +0100 Subject: [PATCH 084/155] Add error if class types don't match (#4064) --- src/V3Width.cpp | 19 ++++++++++++---- test_regress/t/t_class_assign_bad.out | 32 ++++++++++++++++++++------- test_regress/t/t_class_assign_bad.v | 14 ++++++++++++ test_regress/t/t_class_new_bad.out | 8 ++----- 4 files changed, 55 insertions(+), 18 deletions(-) diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 726b209a4..f805c2b2a 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -6249,12 +6249,23 @@ private: } return false; // No change } - + bool isBaseClassRecurse(const AstClass* const cls1p, const AstClass* const cls2p) { + // Returns true if cls1p and cls2p are equal or if cls1p is a base class of cls2p + if (cls1p == cls2p) return true; + for (const AstClassExtends* cextp = cls2p->extendsp(); cextp; + cextp = VN_CAST(cextp->nextp(), ClassExtends)) { + if (isBaseClassRecurse(cls1p, cextp->classp())) return true; + } + return false; + } void checkClassAssign(AstNode* nodep, const char* side, AstNode* rhsp, AstNodeDType* lhsDTypep) { - if (VN_IS(lhsDTypep, ClassRefDType) - && !(rhsp->dtypep() && VN_IS(rhsp->dtypep()->skipRefp(), ClassRefDType))) { - if (auto* const constp = VN_CAST(rhsp, Const)) { + if (AstClassRefDType* const lhsClassRefp = VN_CAST(lhsDTypep, ClassRefDType)) { + UASSERT_OBJ(rhsp->dtypep(), rhsp, "Node has no type"); + if (AstClassRefDType* const rhsClassRefp + = VN_CAST(rhsp->dtypep()->skipRefp(), ClassRefDType)) { + if (isBaseClassRecurse(lhsClassRefp->classp(), rhsClassRefp->classp())) return; + } else if (auto* const constp = VN_CAST(rhsp, Const)) { if (constp->num().isNull()) return; } nodep->v3error(side << " expects a " << lhsDTypep->prettyTypeName()); diff --git a/test_regress/t/t_class_assign_bad.out b/test_regress/t/t_class_assign_bad.out index f93dffe76..6c909e986 100644 --- a/test_regress/t/t_class_assign_bad.out +++ b/test_regress/t/t_class_assign_bad.out @@ -1,17 +1,33 @@ -%Error: t/t_class_assign_bad.v:16:9: Assign RHS expects a CLASSREFDTYPE 'Cls' +%Error: t/t_class_assign_bad.v:25:9: Assign RHS expects a CLASSREFDTYPE 'Cls' : ... In instance t - 16 | c = 0; + 25 | c = 0; | ^ -%Error: t/t_class_assign_bad.v:17:9: Assign RHS expects a CLASSREFDTYPE 'Cls' +%Error: t/t_class_assign_bad.v:26:9: Assign RHS expects a CLASSREFDTYPE 'Cls' : ... In instance t - 17 | c = 1; + 26 | c = 1; | ^ -%Error: t/t_class_assign_bad.v:18:7: Function Argument expects a CLASSREFDTYPE 'Cls' +%Error: t/t_class_assign_bad.v:27:9: Assign RHS expects a CLASSREFDTYPE 'Cls' : ... In instance t - 18 | t(0); + 27 | c = c2; + | ^ +%Error: t/t_class_assign_bad.v:28:13: Assign RHS expects a CLASSREFDTYPE 'ClsExt' + : ... In instance t + 28 | c_ext = c; + | ^ +%Error: t/t_class_assign_bad.v:30:7: Function Argument expects a CLASSREFDTYPE 'Cls' + : ... In instance t + 30 | t(0); | ^ -%Error: t/t_class_assign_bad.v:19:7: Function Argument expects a CLASSREFDTYPE 'Cls' +%Error: t/t_class_assign_bad.v:31:7: Function Argument expects a CLASSREFDTYPE 'Cls' : ... In instance t - 19 | t(1); + 31 | t(1); + | ^ +%Error: t/t_class_assign_bad.v:32:7: Function Argument expects a CLASSREFDTYPE 'Cls' + : ... In instance t + 32 | t(c2); + | ^ +%Error: t/t_class_assign_bad.v:33:7: Function Argument expects a CLASSREFDTYPE 'ClsExt' + : ... In instance t + 33 | f(c); | ^ %Error: Exiting due to diff --git a/test_regress/t/t_class_assign_bad.v b/test_regress/t/t_class_assign_bad.v index 97b7b9f46..46045ee5c 100644 --- a/test_regress/t/t_class_assign_bad.v +++ b/test_regress/t/t_class_assign_bad.v @@ -7,15 +7,29 @@ class Cls; endclass : Cls +class Cls2; +endclass + +class ClsExt extends Cls; +endclass + module t (/*AUTOARG*/); Cls c; + Cls2 c2; + ClsExt c_ext; task t(Cls c); endtask + function f(ClsExt c); endfunction initial begin c = 0; c = 1; + c = c2; + c_ext = c; + t(0); t(1); + t(c2); + f(c); end endmodule diff --git a/test_regress/t/t_class_new_bad.out b/test_regress/t/t_class_new_bad.out index 425a7898e..454eae5d6 100644 --- a/test_regress/t/t_class_new_bad.out +++ b/test_regress/t/t_class_new_bad.out @@ -14,11 +14,7 @@ : ... In instance t 34 | c1 = new[2]; | ^~~ -%Error: t/t_class_new_bad.v:34:10: Assign RHS expects a CLASSREFDTYPE 'ClsNoArg' - : ... In instance t - 34 | c1 = new[2]; - | ^ -%Error: Internal Error: t/t_class_new_bad.v:34:10: ../V3Width.cpp:#: Node has no type +%Error: Internal Error: t/t_class_new_bad.v:34:12: ../V3Width.cpp:#: Node has no type : ... In instance t 34 | c1 = new[2]; - | ^ + | ^~~ From c55df02b1adc64fdd65c44d8bfd27c046997c530 Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Fri, 24 Mar 2023 18:18:59 +0100 Subject: [PATCH 085/155] Fix C++ compile errors when passing class refs as task arg (#4063) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Fixes passing a null reference as a task argument. Before this patch it would cause a C++ compile error like `cannot convert ‘VlNull’ to ‘VlClassRef<...>’`. 2. Fixes passing a class reference as a task argument when the argument is a reference to a base class. Before the patch it would cause a C++ compile error like `cannot convert ‘VlClassRef<{DERIVED_CLASS}>’ to ‘VlClassRef<{BASE_CLASS}>`. --- include/verilated_types.h | 13 ++++++++++++- test_regress/t/t_class_ref_as_arg_cast.pl | 17 +++++++++++++++++ test_regress/t/t_class_ref_as_arg_cast.v | 21 +++++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100755 test_regress/t/t_class_ref_as_arg_cast.pl create mode 100644 test_regress/t/t_class_ref_as_arg_cast.v diff --git a/include/verilated_types.h b/include/verilated_types.h index cb7265e32..cd00c5710 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -1166,7 +1166,8 @@ public: // CONSTRUCTORS VlClassRef() = default; // Init with nullptr - explicit VlClassRef(VlNull){}; + // cppcheck-suppress noExplicitConstructor + VlClassRef(VlNull){}; template VlClassRef(VlDeleter& deleter, T_Args&&... args) // () required here to avoid narrowing conversion warnings, @@ -1188,6 +1189,16 @@ public: // cppcheck-suppress noExplicitConstructor VlClassRef(VlClassRef&& moved) : m_objp{vlstd::exchange(moved.m_objp, nullptr)} {} + // cppcheck-suppress noExplicitConstructor + template + VlClassRef(const VlClassRef& copied) + : m_objp{copied.m_objp} { + refCountInc(); + } + // cppcheck-suppress noExplicitConstructor + template + VlClassRef(VlClassRef&& moved) + : m_objp{vlstd::exchange(moved.m_objp, nullptr)} {} ~VlClassRef() { refCountDec(); } // METHODS diff --git a/test_regress/t/t_class_ref_as_arg_cast.pl b/test_regress/t/t_class_ref_as_arg_cast.pl new file mode 100755 index 000000000..4a65b0092 --- /dev/null +++ b/test_regress/t/t_class_ref_as_arg_cast.pl @@ -0,0 +1,17 @@ +#!/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 Antmicro Ltd. 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); + +compile( + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_ref_as_arg_cast.v b/test_regress/t/t_class_ref_as_arg_cast.v new file mode 100644 index 000000000..d1d5f25d0 --- /dev/null +++ b/test_regress/t/t_class_ref_as_arg_cast.v @@ -0,0 +1,21 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Foo; + static task bar(Foo f); + endtask +endclass + +class Qux extends Foo; +endclass + +module t; + initial begin + Qux qux = new; + Foo::bar(qux); + Foo::bar(null); + end +endmodule From 14c8f072f128cbe903e054381cc22d6aca658573 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 24 Mar 2023 19:06:07 -0400 Subject: [PATCH 086/155] Commentary --- test_regress/t/t_class_ref_as_arg_cast.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_regress/t/t_class_ref_as_arg_cast.pl b/test_regress/t/t_class_ref_as_arg_cast.pl index 4a65b0092..8c2ca139b 100755 --- a/test_regress/t/t_class_ref_as_arg_cast.pl +++ b/test_regress/t/t_class_ref_as_arg_cast.pl @@ -2,7 +2,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } # DESCRIPTION: Verilator: Verilog Test driver/expect definition # -# Copyright 2023 by Antmicro Ltd. This program is free software; you +# 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. From 2290e6ccf2934b37ad783ab0045cab119df26ea0 Mon Sep 17 00:00:00 2001 From: Srinivasan Venkataramanan Date: Fri, 24 Mar 2023 19:22:48 -0400 Subject: [PATCH 087/155] Fix info message prints under --assert (#4036) (#4053) --- docs/CONTRIBUTORS | 1 + src/V3Assert.cpp | 23 +++++++++++++------ test_regress/t/t_assert_synth.v | 5 ++++ test_regress/t/t_assert_synth_full.out | 3 +++ test_regress/t/t_assert_synth_full_vlt.out | 3 +++ test_regress/t/t_assert_synth_parallel.out | 3 +++ .../t/t_assert_synth_parallel_vlt.out | 3 +++ 7 files changed, 34 insertions(+), 7 deletions(-) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index cede3c759..30b2aae06 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -127,6 +127,7 @@ Samuel Riedel Sean Cross Sebastien Van Cauwenberghe Sergi Granell +Srinivasan Venkataramanan Stefan Wallentowitz Stephen Henry Steven Hugg diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index 97259fc5f..8607c05fa 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -51,14 +51,22 @@ private: bool m_inSampled = false; // True inside a sampled expression // METHODS - string assertDisplayMessage(AstNode* nodep, const string& prefix, const string& message) { - return (string("[%0t] " + prefix + ": ") + nodep->fileline()->filebasename() + ":" - + cvtToStr(nodep->fileline()->lineno()) + ": Assertion failed in %m" - + ((message != "") ? ": " : "") + message + "\n"); + string assertDisplayMessage(AstNode* nodep, const string& prefix, const string& message, + VDisplayType severity) { + if (severity == VDisplayType::DT_ERROR || severity == VDisplayType::DT_FATAL) { + return (string("[%0t] " + prefix + ": ") + nodep->fileline()->filebasename() + ":" + + cvtToStr(nodep->fileline()->lineno()) + ": Assertion failed in %m" + + ((message != "") ? ": " : "") + message + "\n"); + } else { + return (string("[%0t] " + prefix + ": ") + nodep->fileline()->filebasename() + ":" + + cvtToStr(nodep->fileline()->lineno()) + ": %m" + + ((message != "") ? ": " : "") + message + "\n"); + } } void replaceDisplay(AstDisplay* nodep, const string& prefix) { + nodep->fmtp()->text( + assertDisplayMessage(nodep, prefix, nodep->fmtp()->text(), nodep->displayType())); nodep->displayType(VDisplayType::DT_WRITE); - nodep->fmtp()->text(assertDisplayMessage(nodep, prefix, nodep->fmtp()->text())); // cppcheck-suppress nullPointer AstNodeExpr* const timenewp = new AstTime{nodep->fileline(), m_modp->timeunit()}; if (AstNodeExpr* const timesp = nodep->fmtp()->exprsp()) { @@ -419,9 +427,10 @@ private: replaceDisplay(nodep, "-Info"); } else if (nodep->displayType() == VDisplayType::DT_WARNING) { replaceDisplay(nodep, "%%Warning"); - } else if (nodep->displayType() == VDisplayType::DT_ERROR - || nodep->displayType() == VDisplayType::DT_FATAL) { + } else if (nodep->displayType() == VDisplayType::DT_ERROR) { replaceDisplay(nodep, "%%Error"); + } else if (nodep->displayType() == VDisplayType::DT_FATAL) { + replaceDisplay(nodep, "%%Fatal"); } else if (nodep->displayType() == VDisplayType::DT_MONITOR) { nodep->displayType(VDisplayType::DT_DISPLAY); const auto fl = nodep->fileline(); diff --git a/test_regress/t/t_assert_synth.v b/test_regress/t/t_assert_synth.v index f9d10ea2d..9eeda9ac7 100644 --- a/test_regress/t/t_assert_synth.v +++ b/test_regress/t/t_assert_synth.v @@ -111,4 +111,9 @@ module t (/*AUTOARG*/ end end + initial begin : test_info + $info ("Start of $info test"); + $info ("Middle of $info test"); + $info ("End of $info test"); + end : test_info endmodule diff --git a/test_regress/t/t_assert_synth_full.out b/test_regress/t/t_assert_synth_full.out index cf081f789..2ba86e3b5 100644 --- a/test_regress/t/t_assert_synth_full.out +++ b/test_regress/t/t_assert_synth_full.out @@ -1,3 +1,6 @@ +[0] -Info: t_assert_synth.v:115: top.t.test_info: Start of $info test +[0] -Info: t_assert_synth.v:116: top.t.test_info: Middle of $info test +[0] -Info: t_assert_synth.v:117: top.t.test_info: End of $info test [40] %Error: t_assert_synth.v:31: Assertion failed in top.t: synthesis full_case, but non-match found %Error: t/t_assert_synth.v:31: Verilog $stop Aborting... diff --git a/test_regress/t/t_assert_synth_full_vlt.out b/test_regress/t/t_assert_synth_full_vlt.out index 72ae3003f..a9e2a1ef4 100644 --- a/test_regress/t/t_assert_synth_full_vlt.out +++ b/test_regress/t/t_assert_synth_full_vlt.out @@ -1,3 +1,6 @@ +[0] -Info: t_assert_synth.v:115: top.t.test_info: Start of $info test +[0] -Info: t_assert_synth.v:116: top.t.test_info: Middle of $info test +[0] -Info: t_assert_synth.v:117: top.t.test_info: End of $info test [40] %Error: t_assert_synth.v:40: Assertion failed in top.t: synthesis full_case, but non-match found %Error: t/t_assert_synth.v:40: Verilog $stop Aborting... diff --git a/test_regress/t/t_assert_synth_parallel.out b/test_regress/t/t_assert_synth_parallel.out index 6bf8c8773..6ba0e76e8 100644 --- a/test_regress/t/t_assert_synth_parallel.out +++ b/test_regress/t/t_assert_synth_parallel.out @@ -1,3 +1,6 @@ +[0] -Info: t_assert_synth.v:115: top.t.test_info: Start of $info test +[0] -Info: t_assert_synth.v:116: top.t.test_info: Middle of $info test +[0] -Info: t_assert_synth.v:117: top.t.test_info: End of $info test [40] %Error: t_assert_synth.v:50: Assertion failed in top.t: synthesis parallel_case, but multiple matches found %Error: t/t_assert_synth.v:50: Verilog $stop Aborting... diff --git a/test_regress/t/t_assert_synth_parallel_vlt.out b/test_regress/t/t_assert_synth_parallel_vlt.out index f0adb9c21..b406ba1b3 100644 --- a/test_regress/t/t_assert_synth_parallel_vlt.out +++ b/test_regress/t/t_assert_synth_parallel_vlt.out @@ -1,3 +1,6 @@ +[0] -Info: t_assert_synth.v:115: top.t.test_info: Start of $info test +[0] -Info: t_assert_synth.v:116: top.t.test_info: Middle of $info test +[0] -Info: t_assert_synth.v:117: top.t.test_info: End of $info test [40] %Error: t_assert_synth.v:55: Assertion failed in top.t: synthesis parallel_case, but multiple matches found %Error: t/t_assert_synth.v:55: Verilog $stop Aborting... From 990b19e048a811a2060115c74fc6aa57f861c4fc Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Sun, 26 Mar 2023 16:29:10 +0900 Subject: [PATCH 088/155] Fix incorrect optimization of bit op tree (#4059) (#4070) --- src/V3Const.cpp | 3 ++- test_regress/t/t_const_opt.pl | 2 +- test_regress/t/t_const_opt.v | 36 +++++++++++++++++++++++++++++++++-- 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 146386acc..0d3e7d707 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -548,7 +548,8 @@ class ConstBitOpTreeVisitor final : public VNVisitorConst { restorer.restoreNow(); // Reach past a cast then add to frozen nodes to be added to final reduction if (const AstCCast* const castp = VN_CAST(opp, CCast)) opp = castp->lhsp(); - m_frozenNodes.emplace_back(opp, FrozenNodeInfo{m_polarity, m_lsb}); + const bool pol = isXorTree() || m_polarity; // Only AND/OR tree needs polarity + m_frozenNodes.emplace_back(opp, FrozenNodeInfo{pol, m_lsb}); m_failed = origFailed; continue; } diff --git a/test_regress/t/t_const_opt.pl b/test_regress/t/t_const_opt.pl index bf8d4b3a3..b0d5b518a 100755 --- a/test_regress/t/t_const_opt.pl +++ b/test_regress/t/t_const_opt.pl @@ -20,7 +20,7 @@ execute( ); if ($Self->{vlt}) { - file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 16); + file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 29); } ok(1); 1; diff --git a/test_regress/t/t_const_opt.v b/test_regress/t/t_const_opt.v index dcdc1419e..843bd8870 100644 --- a/test_regress/t/t_const_opt.v +++ b/test_regress/t/t_const_opt.v @@ -62,7 +62,7 @@ module t(/*AUTOARG*/ $write("[%0t] cyc==%0d crc=%x sum=%x\n", $time, cyc, crc, sum); if (crc !== 64'hc77bb9b3784ea091) $stop; // What checksum will we end up with (above print should match) -`define EXPECTED_SUM 64'he65eec57cf769267 +`define EXPECTED_SUM 64'hf5498264b93d4b48 if (sum !== `EXPECTED_SUM) $stop; $write("*-* All Finished *-*\n"); @@ -92,10 +92,11 @@ module Test(/*AUTOARG*/ wire bug3399_out1; logic bug3786_out; logic bug3824_out; + logic bug4059_out; output logic o; - logic [13:0] tmp; + logic [14:0] tmp; assign o = ^tmp; always_ff @(posedge clk) begin @@ -125,6 +126,7 @@ module Test(/*AUTOARG*/ tmp[11]<= bug3399_out1; tmp[12]<= bug3786_out; tmp[13]<= bug3824_out; + tmp[14]<= bug4059_out; end bug3182 i_bug3182(.in(d[4:0]), .out(bug3182_out)); @@ -135,6 +137,7 @@ module Test(/*AUTOARG*/ bug3399 i_bug3399(.clk(clk), .in(d), .out0(bug3399_out0), .out1(bug3399_out1)); bug3786 i_bug3786(.clk(clk), .in(d), .out(bug3786_out)); bug3824 i_bug3824(.clk(clk), .in(d), .out(bug3824_out)); + bug4059 i_bug4059(.clk(clk), .in(d), .out(bug4059_out)); endmodule @@ -364,3 +367,32 @@ module bug3824(input wire clk, input wire [31:0] in, output wire out); assign out = d_and ^ d_or ^ d_xor; endmodule + +/// Bug4059 +// Frozen node in an xor tree held unnecessary poloarity. +// In an XOR tree, the entire result is flipped if necessary according to +// total polarity. This bug was introduced when fixing #3445. +module bug4059(input wire clk, input wire [31:0] in, output wire out); + wire [127:0] words_i; + logic [127:0] words_i; + for (genvar i = 0; i < $bits(in); ++i) begin + always_ff @(posedge clk) + words_i[4 * i +: 4] <= {4{in[i]}}; + end + + wire _000_ = ~(words_i[104] ^ words_i[96]); + wire _001_ = ~(words_i[88] ^ words_i[80]); + wire _002_ = ~(_000_ ^ _001_); + wire _003_ = words_i[72] ^ words_i[64]; + wire _004_ = words_i[120] ^ words_i[112]; + wire _005_ = ~(_003_ ^ _004_); + wire _006_ = ~(_002_ ^ _005_); + wire _007_ = words_i[40] ^ words_i[32]; + wire _008_ = ~(words_i[24] ^ words_i[16]); + wire _009_ = ~(_007_ ^ _008_); + wire _010_ = words_i[8] ^ words_i[0]; + wire _011_ = words_i[56] ^ words_i[48]; + wire _012_ = ~(_010_ ^ _011_); + wire _013_ = ~(_009_ ^ _012_); + assign out = ~(_006_ ^ _013_); +endmodule From d4107dce52149f6416cb02aa42a281a5b3883c90 Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Sun, 26 Mar 2023 20:36:32 +0900 Subject: [PATCH 089/155] Improve xor tree optimization (#4071) * AstNot does not have to be frozen in an xor tree during BitOp tree optimization. * Tests: Update stats. --- src/V3Const.cpp | 4 +--- test_regress/t/t_const_opt.pl | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 0d3e7d707..277d6988b 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -449,9 +449,7 @@ class ConstBitOpTreeVisitor final : public VNVisitorConst { AstNode* lhsp = nodep->lhsp(); AstCCast* const castp = VN_CAST(lhsp, CCast); if (castp) lhsp = castp->lhsp(); - CONST_BITOP_RETURN_IF(!VN_IS(lhsp, VarRef) && !VN_IS(lhsp, Xor) && !VN_IS(lhsp, RedXor) - && !VN_IS(lhsp, ShiftR), - lhsp); + CONST_BITOP_RETURN_IF(!isXorTree() && !VN_IS(lhsp, VarRef) && !VN_IS(lhsp, ShiftR), lhsp); incrOps(nodep, __LINE__); m_polarity = !m_polarity; iterateChildrenConst(nodep); diff --git a/test_regress/t/t_const_opt.pl b/test_regress/t/t_const_opt.pl index b0d5b518a..c01b55613 100755 --- a/test_regress/t/t_const_opt.pl +++ b/test_regress/t/t_const_opt.pl @@ -20,7 +20,7 @@ execute( ); if ($Self->{vlt}) { - file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 29); + file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 39); } ok(1); 1; From 947402bc57625106e1387255772fdb5d850a6c65 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 26 Mar 2023 08:48:54 -0400 Subject: [PATCH 090/155] Fix interface generate begin (#4065). --- Changes | 1 + src/verilog.y | 24 +++++++++--- test_regress/t/t_interface_gen13.pl | 21 ++++++++++ test_regress/t/t_interface_gen13.v | 59 +++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 6 deletions(-) create mode 100755 test_regress/t/t_interface_gen13.pl create mode 100644 test_regress/t/t_interface_gen13.v diff --git a/Changes b/Changes index 1541a09df..624ac0552 100644 --- a/Changes +++ b/Changes @@ -35,6 +35,7 @@ Verilator 5.009 devel * Fix clocking block scope internal error (#4032). [Srinivasan Venkataramanan] * Fix false LATCH warning on --assert 'unique else if' (#4033) ($4054). [Jesse Taube] * Fix characters from DEFENV literals for conda (#4035) (#4044). [Tim Snyder] +* Fix interface generate begin (#4065). [Srinivasan Venkataramanan] * Fix false ENUMVALUE on expressions and arrays. diff --git a/src/verilog.y b/src/verilog.y index e2e0cd2e2..eb06172e6 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -1636,7 +1636,7 @@ interface_item: // IEEE: interface_item + non_port_interface_ite port_declaration ';' { $$ = $1; } // // IEEE: non_port_interface_item // // IEEE: generate_region - | interface_generate_region { $$ = $1; } + | i_generate_region { $$ = $1; } | interface_or_generate_item { $$ = $1; } | program_declaration { $$ = nullptr; BBUNSUP(CRELINE(), "Unsupported: program decls within interface decls"); } @@ -1649,11 +1649,6 @@ interface_item: // IEEE: interface_item + non_port_interface_ite | module_common_item { $$ = $1; } ; -interface_generate_region: // ==IEEE: generate_region - yGENERATE interface_itemList yENDGENERATE { $$ = $2; } - | yGENERATE yENDGENERATE { $$ = nullptr; } - ; - interface_or_generate_item: // ==IEEE: interface_or_generate_item // // module_common_item in interface_item, as otherwise duplicated // // with module_or_generate_item's module_common_item @@ -2733,6 +2728,10 @@ c_generate_region: // IEEE: generate_region (for checkers) BISONPRE_COPY(generate_region,{s/~c~/c_/g}) // {copied} ; +i_generate_region: // IEEE: generate_region (for interface) + BISONPRE_COPY(generate_region,{s/~c~/i_/g}) // {copied} + ; + generate_block_or_null: // IEEE: generate_block_or_null (called from gencase/genif/genfor) // ';' // is included in // // IEEE: generate_block @@ -2765,6 +2764,10 @@ c_genItemBegin: // IEEE: part of generate_block (for checkers) BISONPRE_COPY(genItemBegin,{s/~c~/c_/g}) // {copied} ; +i_genItemBegin: // IEEE: part of generate_block (for interfaces) + BISONPRE_COPY(genItemBegin,{s/~c~/i_/g}) // {copied} + ; + genItemOrBegin: // Not in IEEE, but our begin isn't under generate_item ~c~generate_item { $$ = $1; } | ~c~genItemBegin { $$ = $1; } @@ -2774,6 +2777,11 @@ c_genItemOrBegin: // (for checkers) BISONPRE_COPY(genItemOrBegin,{s/~c~/c_/g}) // {copied} ; +i_genItemOrBegin: // (for interfaces) + interface_item { $$ = $1; } + | i_genItemBegin { $$ = $1; } + ; + genItemList: ~c~genItemOrBegin { $$ = $1; } | ~c~genItemList ~c~genItemOrBegin { $$ = addNextNull($1, $2); } @@ -2783,6 +2791,10 @@ c_genItemList: // (for checkers) BISONPRE_COPY(genItemList,{s/~c~/c_/g}) // {copied} ; +i_genItemList: // (for interfaces) + BISONPRE_COPY(genItemList,{s/~c~/i_/g}) // {copied} + ; + generate_item: // IEEE: module_or_interface_or_generate_item // // Only legal when in a generate under a module (or interface under a module) module_or_generate_item { $$ = $1; } diff --git a/test_regress/t/t_interface_gen13.pl b/test_regress/t/t_interface_gen13.pl new file mode 100755 index 000000000..f60fd309f --- /dev/null +++ b/test_regress/t/t_interface_gen13.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 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); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_interface_gen13.v b/test_regress/t/t_interface_gen13.v new file mode 100644 index 000000000..0435dda0e --- /dev/null +++ b/test_regress/t/t_interface_gen13.v @@ -0,0 +1,59 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty. +// SPDX-License-Identifier: CC0-1.0 + +// bug998 + +interface intf + #(parameter PARAM = 0) + (); + + int p1; + generate + initial p1 = 1; + endgenerate + + int p2; + generate begin + initial p2 = 1; + end + endgenerate + + int p3; + int p3_no; + if (PARAM == 1) initial p3 = 1; else initial p3_no = 1; + + int p4; + int p4_no; + case (PARAM) + 1: initial p4 = 1; + default: initial p4_no = 1; + endcase + + int p5; + for (genvar g=0; g<=PARAM; ++g) initial p5 = 1; + +endinterface + +module t(/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + intf #(.PARAM(1)) my_intf (); + + always @ (posedge clk) begin + if (my_intf.p1 != 1) $stop; + if (my_intf.p2 != 1) $stop; + if (my_intf.p3 != 1) $stop; + if (my_intf.p3_no != 0) $stop; + if (my_intf.p4 != 1) $stop; + if (my_intf.p4_no != 0) $stop; + if (my_intf.p5 != 1) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From 0b96789e6579ab38c1860415b3b9f52e886e262f Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Mon, 27 Mar 2023 16:46:51 +0200 Subject: [PATCH 091/155] Add error on static access to non-static class member (#4072) Before this patch, it was possible to access non-static class members using static access, which resulted in C++ compilation errors. This adds verilation-time checks for such situations. --- src/V3LinkDot.cpp | 12 ++++++++++++ test_regress/t/t_class_fwd_cc.v | 2 +- test_regress/t/t_class_member_bad3.out | 7 +++++++ test_regress/t/t_class_member_bad3.pl | 19 +++++++++++++++++++ test_regress/t/t_class_member_bad3.v | 19 +++++++++++++++++++ 5 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 test_regress/t/t_class_member_bad3.out create mode 100755 test_regress/t/t_class_member_bad3.pl create mode 100644 test_regress/t/t_class_member_bad3.v diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 05440ea5b..28ba20462 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2534,12 +2534,14 @@ private: string expectWhat; bool allowScope = false; bool allowVar = false; + bool staticAccess = false; if (m_ds.m_dotPos == DP_PACKAGE) { // {package}::{a} AstNodeModule* classOrPackagep = nullptr; expectWhat = "scope/variable"; allowScope = true; allowVar = true; + staticAccess = true; UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), ClassOrPackageRef), m_ds.m_dotp->lhsp(), "Bad package link"); AstClassOrPackageRef* const cpackagerefp @@ -2667,6 +2669,10 @@ private: newp = refp; } } else { + if (staticAccess && !varp->lifetime().isStatic() && !varp->isParam()) { + nodep->v3error("Static access to non-static member variable " + << varp->prettyNameQ() << endl); + } AstVarRef* const refp = new AstVarRef{ nodep->fileline(), varp, VAccess::READ}; // lvalue'ness computed later refp->classOrPackagep(foundp->classOrPackagep()); @@ -2980,6 +2986,7 @@ private: iterateChildren(nodep); } + bool staticAccess = false; if (m_ds.m_unresolvedClass) { // Unable to link before V3Param return; @@ -2995,6 +3002,7 @@ private: } else if (m_ds.m_dotp && m_ds.m_dotPos == DP_PACKAGE) { UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), ClassOrPackageRef), m_ds.m_dotp->lhsp(), "Bad package link"); + staticAccess = true; AstClassOrPackageRef* const cpackagerefp = VN_AS(m_ds.m_dotp->lhsp(), ClassOrPackageRef); if (cpackagerefp->name() == "local") { @@ -3066,6 +3074,10 @@ private: AstNodeFTask* const taskp = foundp ? VN_CAST(foundp->nodep(), NodeFTask) : nullptr; // Maybe nullptr if (taskp) { + if (staticAccess && !taskp->lifetime().isStatic()) { + nodep->v3error("Static access to non-static task/function " + << taskp->prettyNameQ() << endl); + } nodep->taskp(taskp); nodep->classOrPackagep(foundp->classOrPackagep()); UINFO(7, " Resolved " << nodep << endl); // Also prints taskp diff --git a/test_regress/t/t_class_fwd_cc.v b/test_regress/t/t_class_fwd_cc.v index dce477fdf..cfb6c3696 100644 --- a/test_regress/t/t_class_fwd_cc.v +++ b/test_regress/t/t_class_fwd_cc.v @@ -15,7 +15,7 @@ package Pkg; endfunction endclass class Fwd; - function Fwd m_uvm_get_root(); + static function Fwd m_uvm_get_root(); return null; endfunction endclass diff --git a/test_regress/t/t_class_member_bad3.out b/test_regress/t/t_class_member_bad3.out new file mode 100644 index 000000000..4712e0838 --- /dev/null +++ b/test_regress/t/t_class_member_bad3.out @@ -0,0 +1,7 @@ +%Error: t/t_class_member_bad3.v:16:12: Static access to non-static member variable 'member' + 16 | Foo::member = 1; + | ^~~~~~ +%Error: t/t_class_member_bad3.v:17:12: Static access to non-static task/function 'method' + 17 | Foo::method(); + | ^~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_member_bad3.pl b/test_regress/t/t_class_member_bad3.pl new file mode 100755 index 000000000..9c3b25c46 --- /dev/null +++ b/test_regress/t/t_class_member_bad3.pl @@ -0,0 +1,19 @@ +#!/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 Antmicro Ltd. 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); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_member_bad3.v b/test_regress/t/t_class_member_bad3.v new file mode 100644 index 000000000..ccde97456 --- /dev/null +++ b/test_regress/t/t_class_member_bad3.v @@ -0,0 +1,19 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Foo; + int member; + + task method; endtask +endclass + +module t; + initial begin + Foo foo = new; + Foo::member = 1; + Foo::method(); + end +endmodule From d012563ab13911cda37ccb670fab43a362223c8e Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Fri, 31 Mar 2023 19:51:31 +0200 Subject: [PATCH 092/155] Fix tracing with awaits at end of block (#4075) (#4076) Given an await at the end of a block, e.g. at the end of a loop body, a trace activity setter was not inserted, as there were no following statements. This patch makes the activity update unconditional. --- src/V3Trace.cpp | 2 +- test_regress/t/t_timing_trace.out | 90 ++++++++++++++++----------- test_regress/t/t_timing_trace.v | 16 +++-- test_regress/t/t_timing_trace_fst.out | 30 ++++++--- 4 files changed, 84 insertions(+), 54 deletions(-) diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index d7669f62d..44a12ba59 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -437,7 +437,7 @@ private: funcp->stmtsp()->foreachAndNext([&](AstCAwait* awaitp) { AstNode* stmtp = awaitp->backp(); while (VN_IS(stmtp, NodeExpr)) stmtp = stmtp->backp(); - if (stmtp->nextp()) stmtp->addNextHere(setterp->cloneTree(false)); + stmtp->addNextHere(setterp->cloneTree(false)); }); } funcp->addStmtsp(setterp); diff --git a/test_regress/t/t_timing_trace.out b/test_regress/t/t_timing_trace.out index f1a84fcb5..9328aceca 100644 --- a/test_regress/t/t_timing_trace.out +++ b/test_regress/t/t_timing_trace.out @@ -1,5 +1,4 @@ $version Generated by VerilatedVcd $end -$date Tue Nov 22 16:48:14 2022 $end $timescale 1ps $end $scope module TOP $end @@ -7,11 +6,11 @@ $timescale 1ps $end $var wire 32 + CLK_HALF_PERIOD [31:0] $end $var wire 32 * CLK_PERIOD [31:0] $end $var wire 1 $ a $end - $var wire 1 % b $end - $var wire 1 & c $end - $var wire 1 ) clk $end - $var wire 1 ' d $end - $var event 1 ( ev $end + $var wire 1 ) b $end + $var wire 1 % c $end + $var wire 1 ( clk $end + $var wire 1 & d $end + $var event 1 ' ev $end $var wire 1 # rst $end $upscope $end $upscope $end @@ -21,60 +20,77 @@ $enddefinitions $end #0 1# 0$ -0% +1% 0& -0' -0) +1' +0( +1) b00000000000000000000000000001010 * b00000000000000000000000000000101 + #5 -1) +1( #10 -0# -1% -1( -0) +0% +1' +0( #15 -1) -#20 1( -0) +#20 +1% +1' +0( #25 -1) +1( #30 -0) +0% +1' +0( #35 -1) +1( #40 -0) +1% +1' +0( #45 -1) +1( #50 -0) +0% +1' +0( #55 -1) +1( #60 -0) +1% +1' +0( #65 -1) +1( #70 -0) +0% +1' +0( #75 -1) +1( #80 -0) +1% +1' +0( #85 -1) +1( #90 -0) +0% +1' +0( #95 -1) +1( #100 +1% +1' +0( 0) #105 -1) -#110 -1# -0% 1( -0) +#110 +1' +0( +1) diff --git a/test_regress/t/t_timing_trace.v b/test_regress/t/t_timing_trace.v index 9893856cc..fa1471eb5 100644 --- a/test_regress/t/t_timing_trace.v +++ b/test_regress/t/t_timing_trace.v @@ -29,18 +29,16 @@ module t; clk = 0; a = 0; c = 0; - b = 0; + b = ~b; d = 0; - #CLK_PERIOD; - rst = 0; - b = 1; - -> ev ; - #CLK_PERIOD; - -> ev ; + fork #(10 * CLK_PERIOD) b = 0; join_none - #(9 * CLK_PERIOD); - -> ev ; + while (b) begin + c = ~c; + -> ev ; + #CLK_PERIOD; + end $write("*-* All Finished *-*\n"); $finish; diff --git a/test_regress/t/t_timing_trace_fst.out b/test_regress/t/t_timing_trace_fst.out index a0170939c..44e15ea4b 100644 --- a/test_regress/t/t_timing_trace_fst.out +++ b/test_regress/t/t_timing_trace_fst.out @@ -1,5 +1,5 @@ $date - Tue Nov 22 18:14:18 2022 + Fri Mar 31 18:34:51 2023 $end $version @@ -26,8 +26,8 @@ $enddefinitions $end $dumpvars 1) 0( -0' -0& +1' +1& 0% 0$ 1# @@ -38,50 +38,66 @@ $end 1$ #10 0$ -0# -1& +0' 1) #15 1$ #20 0$ 1) +1' #25 1$ #30 0$ +0' +1) #35 1$ #40 0$ +1) +1' #45 1$ #50 0$ +0' +1) #55 1$ #60 0$ +1) +1' #65 1$ #70 0$ +0' +1) #75 1$ #80 0$ +1) +1' #85 1$ #90 0$ +0' +1) #95 1$ #100 0$ +1) +1' +0& #105 1$ #110 0$ +1& 1) -0& -1# From 93c598dd19d2728cacdc87b2d276aa81b162700b Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 1 Apr 2023 10:38:33 -0400 Subject: [PATCH 093/155] Commentary --- test_regress/t/t_class_member_bad3.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_regress/t/t_class_member_bad3.pl b/test_regress/t/t_class_member_bad3.pl index 9c3b25c46..376c2d2ee 100755 --- a/test_regress/t/t_class_member_bad3.pl +++ b/test_regress/t/t_class_member_bad3.pl @@ -2,7 +2,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } # DESCRIPTION: Verilator: Verilog Test driver/expect definition # -# Copyright 2023 by Antmicro Ltd. This program is free software; you +# 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. From 28eadded870468c5bfc3cb77daffd37261dadfb9 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 1 Apr 2023 10:38:47 -0400 Subject: [PATCH 094/155] Update include/gtkwave from upstream --- include/gtkwave/fstapi.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/include/gtkwave/fstapi.c b/include/gtkwave/fstapi.c index a3c2dd6ff..df8b23866 100644 --- a/include/gtkwave/fstapi.c +++ b/include/gtkwave/fstapi.c @@ -3398,6 +3398,7 @@ int flat_hier_alloc_len; unsigned do_rewind : 1; char str_scope_nam[FST_ID_NAM_SIZ+1]; char str_scope_comp[FST_ID_NAM_SIZ+1]; +char *str_scope_attr; unsigned fseek_failed : 1; @@ -4126,7 +4127,7 @@ if(!(isfeof=feof(xc->fh))) cl = 0; while((ch = fgetc(xc->fh))) { - if(cl <= FST_ID_NAM_SIZ) + if(cl < FST_ID_NAM_SIZ) { pnt[cl++] = ch; } @@ -4138,7 +4139,7 @@ if(!(isfeof=feof(xc->fh))) cl = 0; while((ch = fgetc(xc->fh))) { - if(cl <= FST_ID_NAM_SIZ) + if(cl < FST_ID_NAM_SIZ) { pnt[cl++] = ch; } @@ -4155,15 +4156,19 @@ if(!(isfeof=feof(xc->fh))) xc->hier.htyp = FST_HT_ATTRBEGIN; xc->hier.u.attr.typ = fgetc(xc->fh); xc->hier.u.attr.subtype = fgetc(xc->fh); - xc->hier.u.attr.name = pnt = xc->str_scope_nam; + if(!xc->str_scope_attr) + { + xc->str_scope_attr = (char *)calloc(1, FST_ID_NAM_ATTR_SIZ+1); + } + xc->hier.u.attr.name = pnt = xc->str_scope_attr; cl = 0; while((ch = fgetc(xc->fh))) { - if(cl <= FST_ID_NAM_SIZ) + if(cl < FST_ID_NAM_ATTR_SIZ) { pnt[cl++] = ch; } - }; /* scopename */ + }; /* attrname */ pnt[cl] = 0; xc->hier.u.attr.name_length = cl; @@ -4223,7 +4228,7 @@ if(!(isfeof=feof(xc->fh))) cl = 0; while((ch = fgetc(xc->fh))) { - if(cl <= FST_ID_NAM_SIZ) + if(cl < FST_ID_NAM_SIZ) { pnt[cl++] = ch; } @@ -4362,7 +4367,7 @@ while(!feof(xc->fh)) cl = 0; while((ch = fgetc(xc->fh))) { - if(cl <= FST_ID_NAM_ATTR_SIZ) + if(cl < FST_ID_NAM_ATTR_SIZ) { pnt[cl++] = ch; } @@ -4384,7 +4389,7 @@ while(!feof(xc->fh)) cl = 0; while((ch = fgetc(xc->fh))) { - if(cl <= FST_ID_NAM_ATTR_SIZ) + if(cl < FST_ID_NAM_ATTR_SIZ) { pnt[cl++] = ch; } @@ -4473,7 +4478,7 @@ while(!feof(xc->fh)) cl = 0; while((ch = fgetc(xc->fh))) { - if(cl <= FST_ID_NAM_ATTR_SIZ) + if(cl < FST_ID_NAM_ATTR_SIZ) { pnt[cl++] = ch; } @@ -4960,6 +4965,7 @@ if(xc) free(xc->signal_typs); xc->signal_typs = NULL; free(xc->signal_lens); xc->signal_lens = NULL; free(xc->filename); xc->filename = NULL; + free(xc->str_scope_attr); xc->str_scope_attr = NULL; if(xc->fh) { From 69121633cff2cf44e55e61a50d4c7ee7e8f07edf Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 1 Apr 2023 10:50:27 -0400 Subject: [PATCH 095/155] Support class srandom and class random stability. --- Changes | 1 + include/verilated.cpp | 72 ++++++++++-- include/verilated_types.h | 31 ++++- src/V3AstNodeExpr.h | 20 ++++ src/V3AstNodeOther.h | 5 + src/V3AstNodes.cpp | 7 ++ src/V3EmitCFunc.h | 3 + src/V3EmitCHeaders.cpp | 7 +- src/V3LinkDot.cpp | 2 + src/V3LinkResolve.cpp | 2 +- src/V3Premit.cpp | 4 + src/V3Randomize.cpp | 34 +++++- src/V3Randomize.h | 1 + src/V3Width.cpp | 22 +++- test_regress/t/t_randomize_method_bad.out | 3 + test_regress/t/t_randomize_method_bad.v | 2 + .../t/t_randomize_method_nclass_bad.out | 9 ++ .../t/t_randomize_method_nclass_bad.pl | 19 ++++ .../t/t_randomize_method_nclass_bad.v | 12 ++ test_regress/t/t_randomize_srandom.pl | 21 ++++ test_regress/t/t_randomize_srandom.v | 106 ++++++++++++++++++ 21 files changed, 361 insertions(+), 22 deletions(-) create mode 100644 test_regress/t/t_randomize_method_nclass_bad.out create mode 100755 test_regress/t/t_randomize_method_nclass_bad.pl create mode 100644 test_regress/t/t_randomize_method_nclass_bad.v create mode 100755 test_regress/t/t_randomize_srandom.pl create mode 100644 test_regress/t/t_randomize_srandom.v diff --git a/Changes b/Changes index 624ac0552..23fb8fa80 100644 --- a/Changes +++ b/Changes @@ -17,6 +17,7 @@ Verilator 5.009 devel * Add --public-params flag (#3990). [Andrew Nolte] * Add STATICVAR warning and convert to automatic (#4018) (#4027) (#4030). [Ryszard Rozak, Antmicro Ltd] * Support class extends of package::class. +* Support class srandom and class random stability. * Support method calls without parenthesis (#4034). [Ryszard Rozak, Antmicro Ltd] * Support complicated IEEE 'for' assignments. * Support $fopen as an expression. diff --git a/include/verilated.cpp b/include/verilated.cpp index bcc4f65e8..26f9e32fa 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -279,6 +279,52 @@ void VL_PRINTF_MT(const char* formatp, ...) VL_MT_SAFE { //=========================================================================== // Random -- Mostly called at init time, so not inline. +VlRNG::VlRNG() VL_MT_SAFE { + // Starting point for this new class comes from the global RNG + VlRNG& fromr = vl_thread_rng(); + m_state = fromr.m_state; + // Advance the *source* so it can later generate a new number + // Xoroshiro128+ algorithm + fromr.m_state[1] ^= fromr.m_state[0]; + fromr.m_state[0] = (((fromr.m_state[0] << 55) | (fromr.m_state[0] >> 9)) ^ fromr.m_state[1] + ^ (fromr.m_state[1] << 14)); + fromr.m_state[1] = (fromr.m_state[1] << 36) | (fromr.m_state[1] >> 28); +} +uint64_t VlRNG::rand64() VL_MT_UNSAFE { + // Xoroshiro128+ algorithm + const uint64_t result = m_state[0] + m_state[1]; + m_state[1] ^= m_state[0]; + m_state[0] = (((m_state[0] << 55) | (m_state[0] >> 9)) ^ m_state[1] ^ (m_state[1] << 14)); + m_state[1] = (m_state[1] << 36) | (m_state[1] >> 28); + return result; +} +uint64_t VlRNG::vl_thread_rng_rand64() VL_MT_SAFE { + VlRNG& fromr = vl_thread_rng(); + const uint64_t result = fromr.m_state[0] + fromr.m_state[1]; + fromr.m_state[1] ^= fromr.m_state[0]; + fromr.m_state[0] = (((fromr.m_state[0] << 55) | (fromr.m_state[0] >> 9)) ^ fromr.m_state[1] + ^ (fromr.m_state[1] << 14)); + fromr.m_state[1] = (fromr.m_state[1] << 36) | (fromr.m_state[1] >> 28); + return result; +} +void VlRNG::srandom(uint64_t n) VL_MT_UNSAFE { + m_state[0] = n; + m_state[1] = m_state[0]; + // Fix state as algorithm is slow to randomize if many zeros + // This causes a loss of ~ 1 bit of seed entropy, no big deal + if (VL_COUNTONES_I(m_state[0]) < 10) m_state[0] = ~m_state[0]; + if (VL_COUNTONES_I(m_state[1]) < 10) m_state[1] = ~m_state[1]; +} +// Unused: void VlRNG::set_randstate(const std::string& state) VL_MT_UNSAFE { +// Unused: if (VL_LIKELY(state.length() == sizeof(m_state))) { +// Unused: memcpy(m_state, state.data(), sizeof(m_state)); +// Unused: } +// Unused: } +// Unused: std::string VlRNG::get_randstate() const VL_MT_UNSAFE { +// Unused: std::string out{reinterpret_cast(&m_state), sizeof(m_state)}; +// Unused: return out; +// Unused: } + static uint32_t vl_sys_rand32() VL_MT_SAFE { // Return random 32-bits using system library. // Used only to construct seed for Verilator's PRNG. @@ -292,27 +338,23 @@ static uint32_t vl_sys_rand32() VL_MT_SAFE { #endif } -uint64_t vl_rand64() VL_MT_SAFE { - static thread_local uint64_t t_state[2]; +VlRNG& VlRNG::vl_thread_rng() VL_MT_SAFE { + static thread_local VlRNG t_rng{0}; static thread_local uint32_t t_seedEpoch = 0; // For speed, we use a thread-local epoch number to know when to reseed // A thread always belongs to a single context, so this works out ok if (VL_UNLIKELY(t_seedEpoch != VerilatedContextImp::randSeedEpoch())) { // Set epoch before state, to avoid race case with new seeding t_seedEpoch = VerilatedContextImp::randSeedEpoch(); - t_state[0] = Verilated::threadContextp()->impp()->randSeedDefault64(); - t_state[1] = t_state[0]; + // Same as srandom() but here as needs to be VL_MT_SAFE + t_rng.m_state[0] = Verilated::threadContextp()->impp()->randSeedDefault64(); + t_rng.m_state[1] = t_rng.m_state[0]; // Fix state as algorithm is slow to randomize if many zeros // This causes a loss of ~ 1 bit of seed entropy, no big deal - if (VL_COUNTONES_I(t_state[0]) < 10) t_state[0] = ~t_state[0]; - if (VL_COUNTONES_I(t_state[1]) < 10) t_state[1] = ~t_state[1]; + if (VL_COUNTONES_I(t_rng.m_state[0]) < 10) t_rng.m_state[0] = ~t_rng.m_state[0]; + if (VL_COUNTONES_I(t_rng.m_state[1]) < 10) t_rng.m_state[1] = ~t_rng.m_state[1]; } - // Xoroshiro128+ algorithm - const uint64_t result = t_state[0] + t_state[1]; - t_state[1] ^= t_state[0]; - t_state[0] = (((t_state[0] << 55) | (t_state[0] >> 9)) ^ t_state[1] ^ (t_state[1] << 14)); - t_state[1] = (t_state[1] << 36) | (t_state[1] >> 28); - return result; + return t_rng; } WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE { @@ -321,6 +363,12 @@ WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE { return outwp; } +WDataOutP VL_RANDOM_RNG_W(VlRNG& rngr, int obits, WDataOutP outwp) VL_MT_UNSAFE { + for (int i = 0; i < VL_WORDS_I(obits); ++i) outwp[i] = rngr.rand64(); + // Last word is unclean + return outwp; +} + IData VL_RANDOM_SEEDED_II(IData& seedr) VL_MT_SAFE { // $random - seed is a new seed to apply, then we return new seed Verilated::threadContextp()->randSeed(static_cast(seedr)); diff --git a/include/verilated_types.h b/include/verilated_types.h index cd00c5710..d506a54d6 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -136,14 +136,34 @@ public: }; inline std::string VL_TO_STRING(const VlEvent& e) { - return std::string("triggered=") + (e.isTriggered() ? "true" : "false"); + return std::string{"triggered="} + (e.isTriggered() ? "true" : "false"); } //=================================================================== -// Shuffle RNG +// Random -extern uint64_t vl_rand64() VL_MT_SAFE; +// Random Number Generator with internal state +class VlRNG final { + std::array m_state; +public: + // The default constructor simply sets state, to avoid vl_rand64() + // having to check for construction at each call + // Alternative: seed with zero and check on rand64() call + VlRNG() VL_MT_SAFE; + VlRNG(uint64_t seed0) VL_MT_SAFE : m_state{0x12341234UL, seed0} {} + void srandom(uint64_t n) VL_MT_UNSAFE; + // Unused: std::string get_randstate() const VL_MT_UNSAFE; + // Unused: void set_randstate(const std::string& state) VL_MT_UNSAFE; + uint64_t rand64() VL_MT_UNSAFE; + // Threadsafe, but requires use on vl_thread_rng + static uint64_t vl_thread_rng_rand64() VL_MT_SAFE; + static VlRNG& vl_thread_rng() VL_MT_SAFE; +}; + +inline uint64_t vl_rand64() VL_MT_SAFE { return VlRNG::vl_thread_rng_rand64(); } + +// RNG for shuffle() class VlURNG final { public: using result_type = size_t; @@ -152,6 +172,11 @@ public: size_t operator()() { return VL_MASK_I(31) & vl_rand64(); } }; +// These require the class object to have the thread safety lock +inline IData VL_RANDOM_RNG_I(VlRNG& rngr) VL_MT_UNSAFE { return rngr.rand64(); } +inline QData VL_RANDOM_RNG_Q(VlRNG& rngr) VL_MT_UNSAFE { return rngr.rand64(); } +extern WDataOutP VL_RANDOM_RNG_W(VlRNG& rngr, int obits, WDataOutP outwp) VL_MT_UNSAFE; + //=================================================================== // Readmem/Writemem operation classes diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 575bac814..635b9edb4 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -1620,6 +1620,26 @@ public: bool reset() const { return m_reset; } bool urandom() const { return m_urandom; } }; +class AstRandRNG final : public AstNodeExpr { + // Random used in a class using VlRNG + // Return a random number, based upon width() +public: + AstRandRNG(FileLine* fl, AstNodeDType* dtp) + : ASTGEN_SUPER_RandRNG(fl) { + dtypep(dtp); + } + ASTGEN_MEMBERS_AstRandRNG; + string emitVerilog() override { return "%f$rngrandom()"; } + string emitC() override { + return isWide() ? "VL_RANDOM_RNG_%nq(__Vm_rng, %nw, %P)" // + : "VL_RANDOM_RNG_%nq(__Vm_rng)"; + } + bool cleanOut() const override { return false; } + bool isGateOptimizable() const override { return false; } + bool isPredictOptimizable() const override { return false; } + int instrCount() const override { return INSTR_COUNT_PLI; } + bool same(const AstNode* /*samep*/) const override { return true; } +}; class AstRose final : public AstNodeExpr { // Verilog $rose // @astgen op1 := exprp : AstNodeExpr diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index f137413fe..a9b1ecb10 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -2116,6 +2116,7 @@ class AstClass final : public AstNodeModule { AstClassPackage* m_classOrPackagep = nullptr; // Class package this is under bool m_extended = false; // Is extension or extended by other classes bool m_interfaceClass = false; // Interface class + bool m_needRNG = false; // Need RNG, uses srandom/randomize bool m_virtual = false; // Virtual class void insertCache(AstNode* nodep); @@ -2148,9 +2149,13 @@ public: void isInterfaceClass(bool flag) { m_interfaceClass = flag; } bool isVirtual() const { return m_virtual; } void isVirtual(bool flag) { m_virtual = flag; } + bool needRNG() const { return m_needRNG; } + void needRNG(bool flag) { m_needRNG = flag; } // Return true if this class is an extension of base class (SLOW) // Accepts nullptrs static bool isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp); + // Return the lowest class extended from, or this class + AstClass* baseMostClassp(); }; class AstClassPackage final : public AstNodeModule { // The static information portion of a class (treated similarly to a package) diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index d9b8146ab..fd7d78fc5 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1455,6 +1455,13 @@ void AstClass::repairCache() { } } } +AstClass* AstClass::baseMostClassp() { + AstClass* basep = this; + while (basep->extendsp() && basep->extendsp()->classp()) { + basep = basep->extendsp()->classp(); + } + return basep; +} bool AstClass::isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp) { // TAIL RECURSIVE if (!refClassp || !baseClassp) return false; diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 432f2368b..83997f570 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -905,6 +905,9 @@ public: void visit(AstRand* nodep) override { emitOpName(nodep, nodep->emitC(), nodep->seedp(), nullptr, nullptr); } + void visit(AstRandRNG* nodep) override { + emitOpName(nodep, nodep->emitC(), nullptr, nullptr, nullptr); + } void visit(AstTime* nodep) override { puts("VL_TIME_UNITED_Q("); if (nodep->timeunit().isNone()) nodep->v3fatalSrc("$time has no units"); diff --git a/src/V3EmitCHeaders.cpp b/src/V3EmitCHeaders.cpp index bf11c92f3..63a06a956 100644 --- a/src/V3EmitCHeaders.cpp +++ b/src/V3EmitCHeaders.cpp @@ -117,7 +117,12 @@ class EmitCHeader final : public EmitCConstInit { emitCurrentList(); } void emitInternalVarDecls(const AstNodeModule* modp) { - if (!VN_IS(modp, Class)) { + if (const AstClass* const classp = VN_CAST(modp, Class)) { + if (classp->needRNG()) { + putsDecoration("\n// INTERNAL VARIABLES\n"); + puts("VlRNG __Vm_rng;\n"); + } + } else { // not class putsDecoration("\n// INTERNAL VARIABLES\n"); puts(symClassName() + "* const vlSymsp;\n"); } diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 28ba20462..f6e4c97fb 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -3102,6 +3102,8 @@ private: } } else if (VN_IS(nodep, New) && m_statep->forPrearray()) { // Resolved in V3Width + } else if (nodep->name() == "randomize" || nodep->name() == "srandom") { + // Resolved in V3Width } else if (nodep->dotted() == "") { if (nodep->pli()) { if (v3Global.opt.bboxSys()) { diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 55428d1df..df1872d19 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -115,7 +115,7 @@ private: if (m_underGenerate) nodep->underGenerate(true); // Remember the existing symbol table scope if (m_classp) { - if (nodep->name() == "randomize") { + if (nodep->name() == "randomize" || nodep->name() == "srandom") { nodep->v3error(nodep->prettyNameQ() << " is a predefined class method; redefinition not allowed" " (IEEE 1800-2017 18.6.3)"); diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 540d1526d..5cc257f7e 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -287,6 +287,10 @@ private: iterateChildren(nodep); checkNode(nodep); } + void visit(AstRandRNG* nodep) override { + iterateChildren(nodep); + checkNode(nodep); + } void visit(AstUCFunc* nodep) override { iterateChildren(nodep); checkNode(nodep); diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index 1f50e83b3..34c90bf9a 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -188,15 +188,15 @@ private: AstVarRef* const tabRefp = new AstVarRef{fl, enumValueTabp(enumDtp), VAccess::READ}; tabRefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp()); - AstRand* const randp = new AstRand{fl, nullptr, false}; + AstRandRNG* const randp + = new AstRandRNG{fl, varrefp->findBasicDType(VBasicDTypeKwd::UINT32)}; AstNodeExpr* const moddivp = new AstModDiv{ fl, randp, new AstConst{fl, static_cast(enumDtp->itemCount())}}; - randp->dtypep(varrefp->findBasicDType(VBasicDTypeKwd::UINT32)); moddivp->dtypep(enumDtp); valp = new AstArraySel{fl, tabRefp, moddivp}; } else { - valp = new AstRand{fl, nullptr, false}; - valp->dtypep(memberp ? memberp->dtypep() : varrefp->varp()->dtypep()); + valp = new AstRandRNG{fl, + (memberp ? memberp->dtypep() : varrefp->varp()->dtypep())}; } return new AstAssign{fl, new AstSel{fl, varrefp, offset + (memberp ? memberp->lsb() : 0), @@ -374,6 +374,7 @@ void V3Randomize::randomizeNetlist(AstNetlist* nodep) { AstFunc* V3Randomize::newRandomizeFunc(AstClass* nodep) { AstFunc* funcp = VN_AS(nodep->findMember("randomize"), Func); if (!funcp) { + v3Global.useRandomizeMethods(true); AstNodeDType* const dtypep = nodep->findBitDType(32, 32, VSigning::SIGNED); // IEEE says int return of 0/1 AstVar* const fvarp = new AstVar{nodep->fileline(), VVarType::MEMBER, "randomize", dtypep}; @@ -387,6 +388,31 @@ AstFunc* V3Randomize::newRandomizeFunc(AstClass* nodep) { funcp->isVirtual(nodep->isExtended()); nodep->addMembersp(funcp); nodep->repairCache(); + AstClass* const basep = nodep->baseMostClassp(); + basep->needRNG(true); + } + return funcp; +} + +AstFunc* V3Randomize::newSRandomFunc(AstClass* nodep) { + AstClass* const basep = nodep->baseMostClassp(); + AstFunc* funcp = VN_AS(basep->findMember("srandom"), Func); + if (!funcp) { + v3Global.useRandomizeMethods(true); + AstNodeDType* const dtypep + = basep->findBitDType(32, 32, VSigning::SIGNED); // IEEE says argument 0/1 + AstVar* const ivarp = new AstVar{basep->fileline(), VVarType::MEMBER, "seed", dtypep}; + ivarp->lifetime(VLifetime::AUTOMATIC); + ivarp->funcLocal(true); + ivarp->direction(VDirection::INPUT); + funcp = new AstFunc{basep->fileline(), "srandom", ivarp, nullptr}; + funcp->dtypep(basep->findVoidDType()); + funcp->classMethod(true); + funcp->isVirtual(false); + basep->addMembersp(funcp); + basep->repairCache(); + funcp->addStmtsp(new AstCStmt{basep->fileline(), "__Vm_rng.srandom(seed);\n"}); + basep->needRNG(true); } return funcp; } diff --git a/src/V3Randomize.h b/src/V3Randomize.h index ff56f9a86..223575203 100644 --- a/src/V3Randomize.h +++ b/src/V3Randomize.h @@ -29,6 +29,7 @@ public: static void randomizeNetlist(AstNetlist* nodep); static AstFunc* newRandomizeFunc(AstClass* nodep); + static AstFunc* newSRandomFunc(AstClass* nodep); }; #endif // Guard diff --git a/src/V3Width.cpp b/src/V3Width.cpp index f805c2b2a..bd70ab255 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -224,6 +224,7 @@ private: // STATE WidthVP* m_vup = nullptr; // Current node state + AstClass* m_classp = nullptr; // Current class const AstCell* m_cellp = nullptr; // Current cell for arrayed instantiations const AstEnumItem* m_enumItemp = nullptr; // Current enum item const AstNodeFTask* m_ftaskp = nullptr; // Current function/task @@ -2596,6 +2597,8 @@ private: if (nodep->didWidthAndSet()) return; // Must do extends first, as we may in functions under this class // start following a tree of extends that takes us to other classes + VL_RESTORER(m_classp); + m_classp = nodep; userIterateAndNext(nodep->extendsp(), nullptr); userIterateChildren(nodep, nullptr); // First size all members nodep->repairCache(); @@ -2611,6 +2614,7 @@ private: // userIterateChildren(nodep->classp(), nullptr); } void visit(AstNodeModule* nodep) override { + // Visitor does not include AstClass - specialized visitor above VL_RESTORER(m_modp); m_modp = nodep; userIterateChildren(nodep, nullptr); @@ -3460,8 +3464,9 @@ private: // No need to width-resolve the class, as it was done when we did the child AstClass* const first_classp = adtypep->classp(); if (nodep->name() == "randomize") { - v3Global.useRandomizeMethods(true); V3Randomize::newRandomizeFunc(first_classp); + } else if (nodep->name() == "srandom") { + V3Randomize::newSRandomFunc(first_classp); } UASSERT_OBJ(first_classp, nodep, "Unlinked"); for (AstClass* classp = first_classp; classp;) { @@ -5504,6 +5509,21 @@ private: // For arguments, is assignment-like context; see IEEE rules in AstNodeAssign // Function hasn't been widthed, so make it so. UINFO(5, " FTASKREF " << nodep << endl); + if (nodep->name() == "randomize" || nodep->name() == "srandom") { + // TODO perhaps this should move to V3LinkDot + if (!m_classp) { + nodep->v3error("Calling implicit class method " << nodep->prettyNameQ() + << " without being under class"); + nodep->replaceWith(new AstConst{nodep->fileline(), 0}); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + return; + } + if (nodep->name() == "randomize") { + nodep->taskp(V3Randomize::newRandomizeFunc(m_classp)); + } else { + nodep->taskp(V3Randomize::newSRandomFunc(m_classp)); + } + } UASSERT_OBJ(nodep->taskp(), nodep, "Unlinked"); if (nodep->didWidth()) return; userIterate(nodep->taskp(), nullptr); diff --git a/test_regress/t/t_randomize_method_bad.out b/test_regress/t/t_randomize_method_bad.out index 80f06eb60..421ba63cf 100644 --- a/test_regress/t/t_randomize_method_bad.out +++ b/test_regress/t/t_randomize_method_bad.out @@ -4,4 +4,7 @@ %Error: t/t_randomize_method_bad.v:14:18: 'randomize' is a predefined class method; redefinition not allowed (IEEE 1800-2017 18.6.3) 14 | function void randomize(int x); | ^~~~~~~~~ +%Error: t/t_randomize_method_bad.v:16:18: 'srandom' is a predefined class method; redefinition not allowed (IEEE 1800-2017 18.6.3) + 16 | function void srandom(int seed); + | ^~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_randomize_method_bad.v b/test_regress/t/t_randomize_method_bad.v index 72da52529..cae21a9b9 100644 --- a/test_regress/t/t_randomize_method_bad.v +++ b/test_regress/t/t_randomize_method_bad.v @@ -13,6 +13,8 @@ endclass class Cls2; function void randomize(int x); endfunction + function void srandom(int seed); + endfunction endclass module t (/*AUTOARG*/); diff --git a/test_regress/t/t_randomize_method_nclass_bad.out b/test_regress/t/t_randomize_method_nclass_bad.out new file mode 100644 index 000000000..6c48315e6 --- /dev/null +++ b/test_regress/t/t_randomize_method_nclass_bad.out @@ -0,0 +1,9 @@ +%Error: t/t_randomize_method_nclass_bad.v:9:7: Calling implicit class method 'randomize' without being under class + : ... In instance t + 9 | randomize(1); + | ^~~~~~~~~ +%Error: t/t_randomize_method_nclass_bad.v:10:7: Calling implicit class method 'srandom' without being under class + : ... In instance t + 10 | srandom(1); + | ^~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_randomize_method_nclass_bad.pl b/test_regress/t/t_randomize_method_nclass_bad.pl new file mode 100755 index 000000000..66fa61649 --- /dev/null +++ b/test_regress/t/t_randomize_method_nclass_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 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); + +lint( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_randomize_method_nclass_bad.v b/test_regress/t/t_randomize_method_nclass_bad.v new file mode 100644 index 000000000..6b58cf27f --- /dev/null +++ b/test_regress/t/t_randomize_method_nclass_bad.v @@ -0,0 +1,12 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + initial begin + randomize(1); + srandom(1); + end +endmodule diff --git a/test_regress/t/t_randomize_srandom.pl b/test_regress/t/t_randomize_srandom.pl new file mode 100755 index 000000000..aabcde63e --- /dev/null +++ b/test_regress/t/t_randomize_srandom.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 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); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_randomize_srandom.v b/test_regress/t/t_randomize_srandom.v new file mode 100644 index 000000000..4fb3a3e8e --- /dev/null +++ b/test_regress/t/t_randomize_srandom.v @@ -0,0 +1,106 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define stop $stop +`define checkeq(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0) +`define checkne(gotv,expv) do if ((gotv) === (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0) + +class Cls; + bit [63:0] m_sum; + rand int m_r; + function void hash_init(); + m_sum = 64'h5aef0c8d_d70a4497; + endfunction + function void hash(int res); + $display(" res %x", res); + m_sum = {32'h0, res} ^ {m_sum[62:0], m_sum[63] ^ m_sum[2] ^ m_sum[0]}; + endfunction + + function bit [63:0] test1(); + Cls o; + // Affected by srandom + $display(" init for randomize"); + hash_init; + // TODO: Support this.randomize() + o = this; + void'(o.randomize()); + hash(m_r); + void'(o.randomize()); + hash(m_r); + return m_sum; + endfunction + + function bit [63:0] test2(int seed); + $display(" init for seeded randomize"); + hash_init; + this.srandom(seed); + void'(this.randomize()); + hash(m_r); + return m_sum; + endfunction + + function bit [63:0] test3(int seed); + $display(" init for seeded randomize"); + hash_init; + srandom(seed); + void'(randomize()); + hash(m_r); + return m_sum; + endfunction +endclass + +module t(/*AUTOARG*/); + + Cls ca; + Cls cb; + + bit [63:0] sa; + bit [63:0] sb; + + initial begin + // Each class gets different seed from same thread, + // so the randomization should be different + $display("New"); + ca = new; + cb = new; + + sa = ca.test1(); + sb = cb.test1(); + `checkne(sa, sb); // Could false-fail 2^-32 + + // Seed the classes to be synced + $display("Seed"); + ca.srandom(123); + cb.srandom(123); + + sa = ca.test1(); + sb = cb.test1(); + `checkeq(sa, sb); + + // Check using this + $display("this.srandom"); + sa = ca.test2(1); + sb = cb.test2(2); + `checkne(sa, sb); + + sa = ca.test2(3); + sb = cb.test2(3); + `checkeq(sa, sb); + + // Check using direct call + $display("srandom"); + sa = ca.test3(1); + sb = cb.test3(2); + `checkne(sa, sb); + + sa = ca.test3(3); + sb = cb.test3(3); + `checkeq(sa, sb); + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From 90e049c6741de452e0a1dba2b94808bf4cbae7ea Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 1 Apr 2023 11:46:43 -0400 Subject: [PATCH 096/155] Internals: Remove unneeded variable. No functional change. --- include/verilated_types.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/include/verilated_types.h b/include/verilated_types.h index d506a54d6..469852b98 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -395,18 +395,17 @@ public: // Can't just overload operator[] or provide a "at" reference to set, // because we need to be able to insert only when the value is set T_Value& at(int32_t index) { - static thread_local T_Value s_throwAway; + static thread_local T_Value t_throwAway; // Needs to work for dynamic arrays, so does not use T_MaxSize if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) { - s_throwAway = atDefault(); - return s_throwAway; + t_throwAway = atDefault(); + return t_throwAway; } else { return m_deque[index]; } } // Accessing. Verilog: v = assoc[index] const T_Value& at(int32_t index) const { - static thread_local T_Value s_throwAway; // Needs to work for dynamic arrays, so does not use T_MaxSize if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) { return atDefault(); From 9ffd0a4e702dcbfb3bfbf290c357128a625370bc Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 1 Apr 2023 15:23:39 -0400 Subject: [PATCH 097/155] Support queue[$-1] selects. --- include/verilated_types.h | 10 +++++ src/V3Width.cpp | 16 ++++---- src/V3WidthSel.cpp | 70 ++++++++++++++++++++++++---------- test_regress/t/t_queue_back.pl | 21 ++++++++++ test_regress/t/t_queue_back.v | 36 +++++++++++++++++ 5 files changed, 124 insertions(+), 29 deletions(-) create mode 100755 test_regress/t/t_queue_back.pl create mode 100644 test_regress/t/t_queue_back.v diff --git a/include/verilated_types.h b/include/verilated_types.h index 469852b98..5cc66b1ea 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -413,6 +413,10 @@ public: return m_deque[index]; } } + // Access with an index counted from end (e.g. q[$]) + T_Value& atBack(int32_t index) { return at(m_deque.size() - 1 - index); } + const T_Value& atBack(int32_t index) const { return at(m_deque.size() - 1 - index); } + // function void q.insert(index, value); void insert(int32_t index, const T_Value& value) { if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) return; @@ -428,6 +432,12 @@ public: for (int32_t i = lsb; i <= msb; ++i) out.push_back(m_deque[i]); return out; } + VlQueue sliceFrontBack(int32_t lsb, int32_t msb) const { + return slice(lsb, m_deque.size() - 1 - msb); + } + VlQueue sliceBackBack(int32_t lsb, int32_t msb) const { + return slice(m_deque.size() - 1 - lsb, m_deque.size() - 1 - msb); + } // For save/restore const_iterator begin() const { return m_deque.begin(); } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index bd70ab255..5bec957ad 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -1297,15 +1297,15 @@ private: if (const auto* const varp = VN_CAST(nodep->backp(), Var)) { if (varp->isParam()) return; // Ok, leave } - // queue_slice[#:$] - if (const auto* const selp = VN_CAST(nodep->backp(), SelExtract)) { - if (VN_IS(selp->fromp()->dtypep(), QueueDType)) { - nodep->replaceWith( - new AstConst(nodep->fileline(), AstConst::Signed32{}, 0x7FFFFFFF)); - VL_DO_DANGLING(nodep->deleteTree(), nodep); - return; - } + AstNode* backp = nodep->backp(); + if (VN_IS(backp, Sub)) backp = backp->backp(); + if (const auto* const selp = VN_CAST(backp, SelExtract)) { + if (VN_IS(selp->fromp()->dtypep(), QueueDType)) return; } + if (const auto* const selp = VN_CAST(backp, SelBit)) { + if (VN_IS(selp->fromp()->dtypep(), QueueDType)) return; + } + // queue_slice[#:$] and queue_bitsel[$] etc handled in V3WidthSel nodep->v3warn(E_UNSUPPORTED, "Unsupported/illegal unbounded ('$') in this context."); } void visit(AstIsUnbounded* nodep) override { diff --git a/src/V3WidthSel.cpp b/src/V3WidthSel.cpp index a4a1628b3..c6308416b 100644 --- a/src/V3WidthSel.cpp +++ b/src/V3WidthSel.cpp @@ -190,6 +190,18 @@ private: } } + AstNodeExpr* selQueueBackness(AstNode* nodep) { + if (VN_IS(nodep, Unbounded)) { // e.g. "[$]" + return new AstConst{nodep->fileline(), AstConst::Signed32{}, 0}; + } else if (VN_IS(nodep, Sub) && VN_IS(VN_CAST(nodep, Sub)->lhsp(), Unbounded)) { + // e.g. "q[$ - 1]", where 1 is subnodep + AstNodeExpr* subrhsp = VN_CAST(nodep, Sub)->rhsp()->unlinkFrBack(); + return subrhsp; + } else { + return nullptr; + } + } + void warnTri(AstNode* nodep) { if (VN_IS(nodep, Const) && VN_AS(nodep, Const)->num().isFourState()) { nodep->v3error( @@ -250,8 +262,7 @@ private: VL_DO_DANGLING(pushDeletep(nodep), nodep); } else if (const AstAssocArrayDType* const adtypep = VN_CAST(ddtypep, AssocArrayDType)) { // SELBIT(array, index) -> ASSOCSEL(array, index) - AstNodeExpr* const subp = rhsp; - AstAssocSel* const newp = new AstAssocSel{nodep->fileline(), fromp, subp}; + AstAssocSel* const newp = new AstAssocSel{nodep->fileline(), fromp, rhsp}; newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference if (debug() >= 9) newp->dumpTree("- SELBTn: "); nodep->replaceWith(newp); @@ -259,24 +270,26 @@ private: } else if (const AstWildcardArrayDType* const adtypep = VN_CAST(ddtypep, WildcardArrayDType)) { // SELBIT(array, index) -> WILDCARDSEL(array, index) - AstNodeExpr* const subp = rhsp; - AstWildcardSel* const newp = new AstWildcardSel{nodep->fileline(), fromp, subp}; + AstWildcardSel* const newp = new AstWildcardSel{nodep->fileline(), fromp, rhsp}; newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference if (debug() >= 9) newp->dumpTree("- SELBTn: "); nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } else if (const AstDynArrayDType* const adtypep = VN_CAST(ddtypep, DynArrayDType)) { // SELBIT(array, index) -> CMETHODCALL(queue, "at", index) - AstNodeExpr* const subp = rhsp; - AstCMethodHard* const newp = new AstCMethodHard{nodep->fileline(), fromp, "at", subp}; + AstCMethodHard* const newp = new AstCMethodHard{nodep->fileline(), fromp, "at", rhsp}; newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off queue reference if (debug() >= 9) newp->dumpTree("- SELBTq: "); nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); } else if (const AstQueueDType* const adtypep = VN_CAST(ddtypep, QueueDType)) { // SELBIT(array, index) -> CMETHODCALL(queue, "at", index) - AstNodeExpr* const subp = rhsp; - AstCMethodHard* const newp = new AstCMethodHard{nodep->fileline(), fromp, "at", subp}; + AstCMethodHard* newp; + if (AstNodeExpr* const backnessp = selQueueBackness(rhsp)) { + newp = new AstCMethodHard{nodep->fileline(), fromp, "atBack", backnessp}; + } else { + newp = new AstCMethodHard{nodep->fileline(), fromp, "at", rhsp}; + } newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off queue reference if (debug() >= 9) newp->dumpTree("- SELBTq: "); nodep->replaceWith(newp); @@ -338,19 +351,43 @@ private: V3Const::constifyParamsEdit(nodep->leftp()); // May relink pointed to node V3Const::constifyParamsEdit(nodep->rightp()); // May relink pointed to node // if (debug() >= 9) nodep->dumpTree("- SELEX3: "); + AstNodeExpr* const fromp = nodep->fromp()->unlinkFrBack(); + const FromData fromdata = fromDataForArray(nodep, fromp); + AstNodeDType* const ddtypep = fromdata.m_dtypep; + const VNumRange fromRange = fromdata.m_fromRange; + if (VN_IS(ddtypep, QueueDType)) { + AstNodeExpr* const qleftp = nodep->rhsp()->unlinkFrBack(); + AstNodeExpr* const qrightp = nodep->thsp()->unlinkFrBack(); + AstNodeExpr* const qleftBacknessp = selQueueBackness(qleftp); + AstNodeExpr* const qrightBacknessp = selQueueBackness(qrightp); + // Use special methods to refer to back rather than math using + // queue size, this allows a single queue reference, to support + // for equations in side effects that select the queue to + // operate upon. + std::string name = (qleftBacknessp ? "sliceBackBack" + : qrightBacknessp ? "sliceFrontBack" + : "slice"); + auto* const newp = new AstCMethodHard{nodep->fileline(), fromp, name, + qleftBacknessp ? qleftBacknessp : qleftp}; + newp->addPinsp(qrightBacknessp ? qrightBacknessp : qrightp); + newp->dtypep(ddtypep); + newp->didWidth(true); + newp->protect(false); + UINFO(6, " new " << newp << endl); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + return; + } + // Non-queue checkConstantOrReplace(nodep->leftp(), "First value of [a:b] isn't a constant, maybe you want +: or -:"); checkConstantOrReplace(nodep->rightp(), "Second value of [a:b] isn't a constant, maybe you want +: or -:"); - AstNodeExpr* const fromp = nodep->fromp()->unlinkFrBack(); AstNodeExpr* const msbp = nodep->rhsp()->unlinkFrBack(); AstNodeExpr* const lsbp = nodep->thsp()->unlinkFrBack(); int32_t msb = VN_AS(msbp, Const)->toSInt(); int32_t lsb = VN_AS(lsbp, Const)->toSInt(); const int32_t elem = (msb > lsb) ? (msb - lsb + 1) : (lsb - msb + 1); - const FromData fromdata = fromDataForArray(nodep, fromp); - AstNodeDType* const ddtypep = fromdata.m_dtypep; - const VNumRange fromRange = fromdata.m_fromRange; if (VN_IS(ddtypep, UnpackArrayDType)) { // Slice extraction if (fromRange.elements() == elem @@ -453,15 +490,6 @@ private: // if (debug() >= 9) newp->dumpTree("- SELEXnew: "); nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); - } else if (VN_IS(ddtypep, QueueDType)) { - auto* const newp = new AstCMethodHard{nodep->fileline(), fromp, "slice", msbp}; - msbp->addNext(lsbp); - newp->dtypep(ddtypep); - newp->didWidth(true); - newp->protect(false); - UINFO(6, " new " << newp << endl); - nodep->replaceWith(newp); - VL_DO_DANGLING(pushDeletep(nodep), nodep); } else { // nullptr=bad extract, or unknown node type nodep->v3error("Illegal range select; type already selected, or bad dimension: " << "data type is " << fromdata.m_errp->prettyDTypeNameQ()); diff --git a/test_regress/t/t_queue_back.pl b/test_regress/t/t_queue_back.pl new file mode 100755 index 000000000..1aa73f80a --- /dev/null +++ b/test_regress/t/t_queue_back.pl @@ -0,0 +1,21 @@ +#!/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(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_queue_back.v b/test_regress/t/t_queue_back.v new file mode 100644 index 000000000..1d8d2bb90 --- /dev/null +++ b/test_regress/t/t_queue_back.v @@ -0,0 +1,36 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + + int q[$]; + int r; + + initial begin + q = { 20, 30, 40 }; + + r = q[$]; + if (r != 40) $stop; + + r = q[$-1]; + if (r != 30) $stop; + + q = q[0:$-1]; // void'(q.pop_back()) or q.delete(q.size-1) + if (q.size != 2) $stop; + if (q[0] != 20) $stop; + if (q[1] != 30) $stop; + + q = { 20, 30, 40 }; + q = q[$-1:$]; + if (q.size != 2) $stop; + if (q[0] != 30) $stop; + if (q[1] != 40) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From 3a01c32bf9d6f32330c86967ac32201f7945ea1b Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 1 Apr 2023 15:45:34 -0400 Subject: [PATCH 098/155] Revert false-positive static error (#4072) (#4077) --- src/V3LinkDot.cpp | 5 +++-- test_regress/t/t_class_member_bad3.out | 3 --- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index f6e4c97fb..61bb446ca 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -3075,8 +3075,9 @@ private: = foundp ? VN_CAST(foundp->nodep(), NodeFTask) : nullptr; // Maybe nullptr if (taskp) { if (staticAccess && !taskp->lifetime().isStatic()) { - nodep->v3error("Static access to non-static task/function " - << taskp->prettyNameQ() << endl); + // TODO bug4077 + // nodep->v3error("Static access to non-static task/function " + // << taskp->prettyNameQ() << endl); } nodep->taskp(taskp); nodep->classOrPackagep(foundp->classOrPackagep()); diff --git a/test_regress/t/t_class_member_bad3.out b/test_regress/t/t_class_member_bad3.out index 4712e0838..aadcca95d 100644 --- a/test_regress/t/t_class_member_bad3.out +++ b/test_regress/t/t_class_member_bad3.out @@ -1,7 +1,4 @@ %Error: t/t_class_member_bad3.v:16:12: Static access to non-static member variable 'member' 16 | Foo::member = 1; | ^~~~~~ -%Error: t/t_class_member_bad3.v:17:12: Static access to non-static task/function 'method' - 17 | Foo::method(); - | ^~~~~~ %Error: Exiting due to From 3219ffddd47bcc91da183fb152de129bd64d0418 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 1 Apr 2023 18:17:45 -0400 Subject: [PATCH 099/155] Tests: Ignore commented out messages --- test_regress/t/t_dist_warn_coverage.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_regress/t/t_dist_warn_coverage.pl b/test_regress/t/t_dist_warn_coverage.pl index 349fd4737..4646bb95e 100755 --- a/test_regress/t/t_dist_warn_coverage.pl +++ b/test_regress/t/t_dist_warn_coverage.pl @@ -31,7 +31,6 @@ foreach my $s ( 'dynamic new() not expected in this context (expected under an assign)', # Instead get syntax error # Not yet analyzed ' is not an in/out/inout/param/interface: ', - 'Descending instance range connecting to ', ' loading non-variable', '--pipe-filter protocol error, unexpected: ', '/*verilator sformat*/ can only be applied to last argument of ', @@ -177,6 +176,7 @@ sub read_messages { line: while (my $origline = ($fh && $fh->getline)) { my $line = $origline; + next if $line =~ m!^\s*//!; ++$lineno; if ($line =~ /\b(v3error|v3warn)\b\($/g) { $read_next = 1 if $line !~ /LCOV_EXCL_LINE/; From 86156dd05b2ab26173373943b2bfdbfc5b8ade67 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 1 Apr 2023 18:54:37 -0400 Subject: [PATCH 100/155] Revert false-positive static error (#4072) (#4077) --- src/V3LinkDot.cpp | 5 +++-- test_regress/t/t_class_member_bad3.out | 3 +++ test_regress/t/t_class_member_bad3.pl | 4 ++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 61bb446ca..3486d277f 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2670,8 +2670,9 @@ private: } } else { if (staticAccess && !varp->lifetime().isStatic() && !varp->isParam()) { - nodep->v3error("Static access to non-static member variable " - << varp->prettyNameQ() << endl); + // TODO bug4077 + // nodep->v3error("Static access to non-static member variable " + // << varp->prettyNameQ() << endl); } AstVarRef* const refp = new AstVarRef{ nodep->fileline(), varp, VAccess::READ}; // lvalue'ness computed later diff --git a/test_regress/t/t_class_member_bad3.out b/test_regress/t/t_class_member_bad3.out index aadcca95d..4712e0838 100644 --- a/test_regress/t/t_class_member_bad3.out +++ b/test_regress/t/t_class_member_bad3.out @@ -1,4 +1,7 @@ %Error: t/t_class_member_bad3.v:16:12: Static access to non-static member variable 'member' 16 | Foo::member = 1; | ^~~~~~ +%Error: t/t_class_member_bad3.v:17:12: Static access to non-static task/function 'method' + 17 | Foo::method(); + | ^~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_class_member_bad3.pl b/test_regress/t/t_class_member_bad3.pl index 376c2d2ee..55ca436af 100755 --- a/test_regress/t/t_class_member_bad3.pl +++ b/test_regress/t/t_class_member_bad3.pl @@ -11,8 +11,8 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(linter => 1); lint( - fails => 1, - expect_filename => $Self->{golden_filename}, + # fails => 1, # TODO bug4077 + # expect_filename => $Self->{golden_filename}, ); ok(1); From fc5a5ea53d64b7c01192a1a5222d4fd882c449e0 Mon Sep 17 00:00:00 2001 From: Robert Balas <13798471+bluewww@users.noreply.github.com> Date: Sun, 2 Apr 2023 02:45:28 +0200 Subject: [PATCH 101/155] Commentary: Fix spelling mistakes (#4080) Co-authored-by: Robert Balas --- configure.ac | 2 +- docs/CONTRIBUTORS | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 862537ecb..ebcd6d579 100644 --- a/configure.ac +++ b/configure.ac @@ -68,7 +68,7 @@ AC_MSG_CHECKING(whether to use -m32) AC_ARG_ENABLE([m32], [AS_HELP_STRING([--enable-m32], [Use -m32 for all compilation and link, - including Verialtor and generated models.])], + including Verilator and generated models.])], [case "${enableval}" in yes) CFG_ENABLE_M32=yes ;; no) CFG_ENABLE_M32=no ;; diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 30b2aae06..404584aba 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -121,6 +121,7 @@ Qingyao Sun Rafal Kapuscik Raynard Qiao Richard Myers +Robert Balas Rupert Swarbrick Ryszard Rozak Samuel Riedel From 921fd919b56d20724b6d159a90b50b260a104167 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 1 Apr 2023 23:10:05 -0400 Subject: [PATCH 102/155] Tests: Improve short circuit test --- test_regress/t/t_dpi_shortcircuit.out | 38 ++++++++++++++----------- test_regress/t/t_dpi_shortcircuit.v | 28 ++++++++++++++---- test_regress/t/t_dpi_shortcircuit_c.cpp | 2 +- 3 files changed, 44 insertions(+), 24 deletions(-) diff --git a/test_regress/t/t_dpi_shortcircuit.out b/test_regress/t/t_dpi_shortcircuit.out index e1463672b..53f6dc0e8 100644 --- a/test_regress/t/t_dpi_shortcircuit.out +++ b/test_regress/t/t_dpi_shortcircuit.out @@ -1,18 +1,22 @@ -%Error: Line 60: Bad result, got=1 expect=0 -%Error: Line 64: Bad result, got=1 expect=0 -%Error: Line 75: Bad result, got=0 expect=1 -%Error: Line 98: Bad result, got=1 expect=0 -%Error: Line 102: Bad result, got=1 expect=0 -%Error: Line 112: Bad result, got=0 expect=1 -%Error: Line 132: Bad result, got=1 expect=0 -%Error: Line 136: Bad result, got=1 expect=0 -%Error: Line 150: Bad result, got=1 expect=0 -%Error: Line 154: Bad result, got=1 expect=0 -%Error: Line 163: Bad result, got=0 expect=1 -%Error: Line 203: Bad result, got=64 expect=32 -%Error: Line 204: Bad result, got=64 expect=16 -%Error: Line 205: Bad result, got=64 expect=16 -%Error: Line 206: Bad result, got=64 expect=36 -%Error: Line 207: Bad result, got=64 expect=46 -%Error: t/t_dpi_shortcircuit.v:209: Verilog $stop +%Error: Line 62: Bad result, got=1 expect=0 +%Error: Line 66: Bad result, got=1 expect=0 +%Error: Line 69: Bad result, got=0 expect=1 +%Error: Line 81: Bad result, got=0 expect=1 +%Error: Line 91: Bad result, got=0 expect=1 +%Error: Line 108: Bad result, got=1 expect=0 +%Error: Line 112: Bad result, got=1 expect=0 +%Error: Line 114: Bad result, got=0 expect=1 +%Error: Line 126: Bad result, got=0 expect=1 +%Error: Line 136: Bad result, got=0 expect=1 +%Error: Line 148: Bad result, got=1 expect=0 +%Error: Line 152: Bad result, got=1 expect=0 +%Error: Line 166: Bad result, got=1 expect=0 +%Error: Line 170: Bad result, got=1 expect=0 +%Error: Line 179: Bad result, got=0 expect=1 +%Error: Line 219: Bad result, got=64 expect=32 +%Error: Line 220: Bad result, got=64 expect=16 +%Error: Line 221: Bad result, got=64 expect=16 +%Error: Line 222: Bad result, got=64 expect=36 +%Error: Line 223: Bad result, got=64 expect=46 +%Error: t/t_dpi_shortcircuit.v:225: Verilog $stop Aborting... diff --git a/test_regress/t/t_dpi_shortcircuit.v b/test_regress/t/t_dpi_shortcircuit.v index b89cdffd4..e6be0315a 100644 --- a/test_regress/t/t_dpi_shortcircuit.v +++ b/test_regress/t/t_dpi_shortcircuit.v @@ -54,6 +54,8 @@ module t (/*AUTOARG*/); check1(`__LINE__, (dpii_inc1(4) && dpii_inc0(5)), 1'b0); check1(`__LINE__, (dpii_inc0(6) && dpii_inc1(7)), 1'b0); check1(`__LINE__, (!(dpii_inc1(8) && dpii_inc1(9))), 1'b0); + check1(`__LINE__, (dpii_inc0(10) && 1'b0), 1'b0); + check1(`__LINE__, (dpii_inc0(11) && 1'b1), 1'b0); check (`__LINE__, dpii_count(0), 0); check (`__LINE__, dpii_count(1), 1); check (`__LINE__, dpii_count(2), 1); @@ -64,6 +66,8 @@ module t (/*AUTOARG*/); check (`__LINE__, dpii_count(7), 0); check (`__LINE__, dpii_count(8), 1); check (`__LINE__, dpii_count(9), 1); + check (`__LINE__, dpii_count(10), 1); + check (`__LINE__, dpii_count(11), 1); // dpii_clear(); check1(`__LINE__, (1'b0 & dpii_inc0(0)), 1'b0); @@ -72,6 +76,8 @@ module t (/*AUTOARG*/); check1(`__LINE__, (dpii_inc1(4) & dpii_inc0(5)), 1'b0); check1(`__LINE__, (dpii_inc0(6) & dpii_inc1(7)), 1'b0); check1(`__LINE__, (!(dpii_inc1(8) & dpii_inc1(9))), 1'b0); + check1(`__LINE__, (dpii_inc0(10) & 1'b0), 1'b0); + check1(`__LINE__, (dpii_inc0(11) & 1'b1), 1'b0); check (`__LINE__, dpii_count(0), 1); check (`__LINE__, dpii_count(1), 1); check (`__LINE__, dpii_count(2), 1); @@ -82,6 +88,8 @@ module t (/*AUTOARG*/); check (`__LINE__, dpii_count(7), 1); check (`__LINE__, dpii_count(8), 1); check (`__LINE__, dpii_count(9), 1); + check (`__LINE__, dpii_count(10), 1); + check (`__LINE__, dpii_count(11), 1); // dpii_clear(); check1(`__LINE__, (1'b0 || dpii_inc0(0)), 1'b0); @@ -90,6 +98,8 @@ module t (/*AUTOARG*/); check1(`__LINE__, (dpii_inc1(4) || dpii_inc0(5)), 1'b1); check1(`__LINE__, (dpii_inc0(6) || dpii_inc1(7)), 1'b1); check1(`__LINE__, (!(dpii_inc1(8) || dpii_inc1(9))), 1'b0); + check1(`__LINE__, (dpii_inc0(10) || 1'b0), 1'b0); + check1(`__LINE__, (dpii_inc0(11) || 1'b1), 1'b1); check (`__LINE__, dpii_count(0), 1); check (`__LINE__, dpii_count(1), 0); check (`__LINE__, dpii_count(2), 1); @@ -100,6 +110,8 @@ module t (/*AUTOARG*/); check (`__LINE__, dpii_count(7), 1); check (`__LINE__, dpii_count(8), 1); check (`__LINE__, dpii_count(9), 0); + check (`__LINE__, dpii_count(10), 1); + check (`__LINE__, dpii_count(11), 1); // dpii_clear(); check1(`__LINE__, (1'b0 | dpii_inc0(0)), 1'b0); @@ -108,6 +120,8 @@ module t (/*AUTOARG*/); check1(`__LINE__, (dpii_inc1(4) | dpii_inc0(5)), 1'b1); check1(`__LINE__, (dpii_inc0(6) | dpii_inc1(7)), 1'b1); check1(`__LINE__, (!(dpii_inc1(8) | dpii_inc1(9))), 1'b0); + check1(`__LINE__, (dpii_inc0(10) | 1'b0), 1'b0); + check1(`__LINE__, (dpii_inc0(11) | 1'b1), 1'b1); check (`__LINE__, dpii_count(0), 1); check (`__LINE__, dpii_count(1), 1); check (`__LINE__, dpii_count(2), 1); @@ -118,6 +132,8 @@ module t (/*AUTOARG*/); check (`__LINE__, dpii_count(7), 1); check (`__LINE__, dpii_count(8), 1); check (`__LINE__, dpii_count(9), 1); + check (`__LINE__, dpii_count(10), 1); + check (`__LINE__, dpii_count(11), 1); // dpii_clear(); check1(`__LINE__, (1'b0 -> dpii_inc0(0)), 1'b1); @@ -192,12 +208,12 @@ module t (/*AUTOARG*/); // Something a lot more complicated dpii_clear(); for (i=0; i<64; i++) begin - b = ( ((dpii_incx(0,i[0]) - && (dpii_incx(1,i[1]) - || dpii_incx(2,i[2]) - | dpii_incx(3,i[3]))) // | not || - || dpii_incx(4,i[4])) - -> dpii_incx(5,i[5])); + b = ( ((dpii_incx(0,i[0]) + && (dpii_incx(1,i[1]) + || dpii_incx(2,i[2]) + | dpii_incx(3,i[3]))) // | not || + || dpii_incx(4,i[4])) + -> dpii_incx(5,i[5])); end check (`__LINE__, dpii_count(0), 64); check (`__LINE__, dpii_count(1), 32); diff --git a/test_regress/t/t_dpi_shortcircuit_c.cpp b/test_regress/t/t_dpi_shortcircuit_c.cpp index 12ff41438..9a352a6b6 100644 --- a/test_regress/t/t_dpi_shortcircuit_c.cpp +++ b/test_regress/t/t_dpi_shortcircuit_c.cpp @@ -54,7 +54,7 @@ void dpii_clear() { } int dpii_count(int idx) { return (idx >= 0 && idx < COUNTERS) ? global_count[idx] : -1; } unsigned char dpii_incx(int idx, unsigned char value) { - if (idx >= 0 && idx < COUNTERS) global_count[idx]++; + if (idx >= 0 && idx < COUNTERS) ++global_count[idx]; return value; } unsigned char dpii_inc0(int idx) { return dpii_incx(idx, 0); } From 7e1980af7a67f90967556dda5be07fef72452876 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 2 Apr 2023 15:10:45 -0400 Subject: [PATCH 103/155] Tests: Avoid t_dist failures on deleted files. --- test_regress/t/t_dist_cinclude.pl | 1 + test_regress/t/t_dist_copyright.pl | 21 ++++++++++++--------- test_regress/t/t_dist_fixme.pl | 5 ++++- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/test_regress/t/t_dist_cinclude.pl b/test_regress/t/t_dist_cinclude.pl index da88adfc7..f006eae01 100755 --- a/test_regress/t/t_dist_cinclude.pl +++ b/test_regress/t/t_dist_cinclude.pl @@ -26,6 +26,7 @@ if (!-r catfile($root, ".git")) { next if $file =~ m!include/vltstd/vpi_user.h!; # IEEE Standard file - can't change it next if $file =~ m!include/gtkwave/!; # Standard file - can't change it my $filename = catfile($root, $file); + next if !-r $filename; @lines = split /\n/, file_contents($filename); @include_lines = grep(/include/, @lines); foreach my $line (@include_lines) { diff --git a/test_regress/t/t_dist_copyright.pl b/test_regress/t/t_dist_copyright.pl index 809b9af7b..065f54ff5 100755 --- a/test_regress/t/t_dist_copyright.pl +++ b/test_regress/t/t_dist_copyright.pl @@ -11,6 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di use IO::File; use POSIX qw(strftime); use strict; +use File::Spec::Functions 'catfile'; scenarios(dist => 1); @@ -74,8 +75,10 @@ if (!-r "$root/.git") { $added{$1} = 1; } - foreach my $filename (sort keys %files) { - my $fh = IO::File->new("<$root/$filename") or error("$! $filename"); + foreach my $file (sort keys %files) { + my $filename = catfile($root, $file); + next if !-r $filename; + my $fh = IO::File->new("<$filename") or error("$! $filename"); next if !$fh; my $spdx; my $copyright; @@ -86,12 +89,12 @@ if (!-r "$root/.git") { } elsif ($line =~ /Copyright 20[0-9][0-9]/) { $copyright = $line; if ($line =~ /Wilson Snyder/) { - } elsif (!$added{$filename} && $line =~ /Antmicro|Geza Lore|Todd Strader/) { - } elsif ($filename =~ /$Exempt_Author_Re/) { + } elsif (!$added{$file} && $line =~ /Antmicro|Geza Lore|Todd Strader/) { + } elsif ($file =~ /$Exempt_Author_Re/) { } else { - my $yeardash = ($filename =~ m!test_regress/t!) ? $year : $year."-".$year; + my $yeardash = ($file =~ m!test_regress/t!) ? $year : $year."-".$year; warn " ".$copyright; - error("$filename: Please use standard 'Copyright $yeardash by Wilson Snyder'"); + error("$file: Please use standard 'Copyright $yeardash by Wilson Snyder'"); } } elsif ($line =~ m!Creative Commons Public Domain! || $line =~ m!freely copied and/or distributed! @@ -100,14 +103,14 @@ if (!-r "$root/.git") { } } my $release_note; - if ($release && $filename !~ /$Release_Ok_Re/) { + if ($release && $file !~ /$Release_Ok_Re/) { $release_note = " (has copyright release, but not part of $Release_Ok_Re)"; } if (!$copyright && (!$release || $release_note)) { - error("$filename: Please add standard 'Copyright $year ...', similar to in other files" . $release_note); + error("$file: Please add standard 'Copyright $year ...', similar to in other files" . $release_note); } if (!$spdx) { - error("$filename: Please add standard 'SPDX-License_Identifier: ...', similar to in other files"); + error("$file: Please add standard 'SPDX-License_Identifier: ...', similar to in other files"); } } } diff --git a/test_regress/t/t_dist_fixme.pl b/test_regress/t/t_dist_fixme.pl index 0f36f4486..20079a96c 100755 --- a/test_regress/t/t_dist_fixme.pl +++ b/test_regress/t/t_dist_fixme.pl @@ -9,6 +9,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 use IO::File; +use File::Spec::Functions 'catfile'; scenarios(dist => 1); @@ -28,7 +29,9 @@ if (!-r "$root/.git") { my $n = 0; my $re = qr/(FIX[M]E|BO[Z]O)/; foreach my $file (split /\s+/, $files) { - my $wholefile = file_contents($root . "/" . $file); + my $filename = catfile($root, $file); + next if !-r $filename; + my $wholefile = file_contents($filename); if ($wholefile =~ /$re/) { $names{$file} = 1; } From a3f9221a67f3c7b2cb5f534229d8419a21f1fdd8 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Wed, 5 Apr 2023 02:56:18 +0200 Subject: [PATCH 104/155] Fix importing symbols from base class (#4084) --- src/V3LinkDot.cpp | 20 +++++++----- test_regress/t/t_randomize_srandom.v | 48 ++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 8 deletions(-) diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 3486d277f..1028ac62e 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2234,6 +2234,12 @@ private: } } } + void importSymbolsFromExtended(AstClass* const nodep, AstClassExtends* const cextp) { + AstClass* const classp = cextp->classp(); + VSymEnt* const srcp = m_statep->getNodeSym(classp); + if (classp->isInterfaceClass()) importImplementsClass(nodep, srcp, classp); + if (!cextp->isImplements()) m_curSymp->importFromClass(m_statep->symsp(), srcp); + } // VISITs void visit(AstNetlist* nodep) override { @@ -3287,7 +3293,11 @@ private: cextp->v3error("Multiple inheritance illegal on non-interface classes" " (IEEE 1800-2017 8.13)"); } - if (cextp->childDTypep() || cextp->dtypep()) continue; // Already converted + if (cextp->childDTypep() || cextp->dtypep()) { + // Already converted. Update symbol table to link unlinked members + importSymbolsFromExtended(nodep, cextp); + continue; + } AstNode* cprp = cextp->classOrPkgsp(); VSymEnt* lookSymp = m_curSymp; if (AstDot* const dotp = VN_CAST(cextp->classOrPkgsp(), Dot)) { @@ -3371,13 +3381,7 @@ private: cextp->childDTypep(classRefDtypep); classp->isExtended(true); nodep->isExtended(true); - VSymEnt* const srcp = m_statep->getNodeSym(classp); - if (classp->isInterfaceClass()) { - importImplementsClass(nodep, srcp, classp); - } - if (!cextp->isImplements()) { - m_curSymp->importFromClass(m_statep->symsp(), srcp); - } + importSymbolsFromExtended(nodep, cextp); VL_DO_DANGLING( cextp->classOrPkgsp()->unlinkFrBack()->deleteTree(), cpackagerefp); diff --git a/test_regress/t/t_randomize_srandom.v b/test_regress/t/t_randomize_srandom.v index 4fb3a3e8e..218565138 100644 --- a/test_regress/t/t_randomize_srandom.v +++ b/test_regress/t/t_randomize_srandom.v @@ -52,10 +52,39 @@ class Cls; endfunction endclass +class Foo; +endclass + +class Bar extends Foo; + bit [63:0] m_sum; + rand int m_r; + function void hash_init(); + m_sum = 64'h5aef0c8d_d70a4497; + endfunction + function void hash(int res); + $display(" res %x", res); + m_sum = {32'h0, res} ^ {m_sum[62:0], m_sum[63] ^ m_sum[2] ^ m_sum[0]}; + endfunction + + function void this_srandom(int seed); + this.srandom(seed); + endfunction + + function bit [63:0] test2; + $display(" init for seeded randomize"); + hash_init; + $display("%d", m_r); + hash(m_r); + return m_sum; + endfunction +endclass + module t(/*AUTOARG*/); Cls ca; Cls cb; + Bar b1; + Bar b2; bit [63:0] sa; bit [63:0] sb; @@ -66,6 +95,8 @@ module t(/*AUTOARG*/); $display("New"); ca = new; cb = new; + b1 = new; + b2 = new; sa = ca.test1(); sb = cb.test1(); @@ -90,6 +121,23 @@ module t(/*AUTOARG*/); sb = cb.test2(3); `checkeq(sa, sb); + $display("this.srandom - Bar class"); + b1.this_srandom(1); + b2.this_srandom(2); + void'(b1.randomize()); + void'(b2.randomize()); + sa = b1.test2; + sb = b2.test2; + `checkne(sa, sb); + + b1.this_srandom(3); + b2.this_srandom(3); + void'(b1.randomize()); + void'(b2.randomize()); + sa = b1.test2; + sb = b2.test2; + `checkeq(sa, sb); + // Check using direct call $display("srandom"); sa = ca.test3(1); From 05660d11188f6df59ace0340a240bc731e6270b0 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 5 Apr 2023 21:27:37 -0400 Subject: [PATCH 105/155] Add CONSTRAINTIGN warning when constraint ignored. Likewise ignore constraint_mode, rand_mode. --- Changes | 1 + docs/guide/warnings.rst | 10 ++++ src/V3Const.cpp | 2 +- src/V3Error.h | 3 +- src/V3Width.cpp | 26 +++++++- src/verilog.y | 8 ++- test_regress/t/t_constraint.pl | 23 ++++++++ test_regress/t/t_constraint.v | 31 ++++++++++ test_regress/t/t_constraint_mode.pl | 23 ++++++++ test_regress/t/t_constraint_mode.v | 59 +++++++++++++++++++ test_regress/t/t_constraint_mode_warn_bad.out | 54 +++++++++++++++++ test_regress/t/t_constraint_mode_warn_bad.pl | 21 +++++++ test_regress/t/t_randomize.out | 19 ++++++ 13 files changed, 275 insertions(+), 5 deletions(-) create mode 100755 test_regress/t/t_constraint.pl create mode 100644 test_regress/t/t_constraint.v create mode 100755 test_regress/t/t_constraint_mode.pl create mode 100644 test_regress/t/t_constraint_mode.v create mode 100644 test_regress/t/t_constraint_mode_warn_bad.out create mode 100755 test_regress/t/t_constraint_mode_warn_bad.pl diff --git a/Changes b/Changes index 23fb8fa80..304f6200c 100644 --- a/Changes +++ b/Changes @@ -15,6 +15,7 @@ Verilator 5.009 devel * Add --public-depth to force public to a certain instance depth (#3952). [Andrew Nolte] * Add --public-params flag (#3990). [Andrew Nolte] +* Add CONSTRAINTIGN warning when constraint ignored. * Add STATICVAR warning and convert to automatic (#4018) (#4027) (#4030). [Ryszard Rozak, Antmicro Ltd] * Support class extends of package::class. * Support class srandom and class random stability. diff --git a/docs/guide/warnings.rst b/docs/guide/warnings.rst index fe406c8a2..1a754c8f6 100644 --- a/docs/guide/warnings.rst +++ b/docs/guide/warnings.rst @@ -396,6 +396,16 @@ List Of Warnings simulators. +.. option:: CONSTRAINTIGN + + Warns that Verilator does not support :code:`constraint`, + :code:`constraint_mode`, or :code:`rand_mode`, and the construct was are + ignored. + + Ignoring this warning may make Verilator randomize() simulations differ + from other simulators. + + .. option:: CONTASSREG .. TODO better example diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 277d6988b..232d4ebca 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -3188,7 +3188,7 @@ private: void visit(AstStmtExpr* nodep) override { iterateChildren(nodep); - if (!nodep->exprp()) { + if (!nodep->exprp() || VN_IS(nodep->exprp(), Const)) { VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); return; } diff --git a/src/V3Error.h b/src/V3Error.h index b63dfdf2d..ddff5baf2 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -88,6 +88,7 @@ public: CMPCONST, // Comparison is constant due to limited range COLONPLUS, // :+ instead of +: COMBDLY, // Combinatorial delayed assignment + CONSTRAINTIGN, // Constraint ignored CONTASSREG, // Continuous assignment on reg DECLFILENAME, // Declaration doesn't match filename DEFPARAM, // Style: Defparam @@ -187,7 +188,7 @@ public: "ALWCOMBORDER", "ASCRANGE", "ASSIGNDLY", "ASSIGNIN", "BADSTDPRAGMA", "BLKANDNBLK", "BLKLOOPINIT", "BLKSEQ", "BSSPACE", "CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CASTCONST", "CDCRSTLOGIC", "CLKDATA", - "CMPCONST", "COLONPLUS", "COMBDLY", "CONTASSREG", + "CMPCONST", "COLONPLUS", "COMBDLY", "CONSTRAINTIGN", "CONTASSREG", "DECLFILENAME", "DEFPARAM", "DEPRECATED", "ENCAPSULATED", "ENDLABEL", "ENUMVALUE", "EOFNEWLINE", "GENCLK", "HIERBLOCK", "IFDEPTH", "IGNOREDRETURN", diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 5bec957ad..bb5e25edb 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -2829,7 +2829,9 @@ private: AstBasicDType* const basicp = fromDtp ? fromDtp->basicp() : nullptr; UINFO(9, " from dt " << fromDtp << endl); userIterate(fromDtp, WidthVP{SELF, BOTH}.p()); - if (AstEnumDType* const adtypep = VN_CAST(fromDtp, EnumDType)) { + if (nodep->name() == "rand_mode") { + methodCallRandMode(nodep); + } else if (AstEnumDType* const adtypep = VN_CAST(fromDtp, EnumDType)) { methodCallEnum(nodep, adtypep); } else if (AstAssocArrayDType* const adtypep = VN_CAST(fromDtp, AssocArrayDType)) { methodCallAssoc(nodep, adtypep); @@ -2843,6 +2845,8 @@ private: methodCallClass(nodep, adtypep); } else if (AstUnpackArrayDType* const adtypep = VN_CAST(fromDtp, UnpackArrayDType)) { methodCallUnpack(nodep, adtypep); + } else if (basicp && nodep->name() == "constraint_mode") { + methodCallConstraint(nodep, basicp); } else if (basicp && basicp->isEvent()) { methodCallEvent(nodep, basicp); } else if (basicp && basicp->isString()) { @@ -3533,6 +3537,26 @@ private: } nodep->dtypeSetSigned32(); // Guess on error } + void methodCallConstraint(AstMethodCall* nodep, AstBasicDType*) { + // Method call on constraint (currently hacked as just a var) + if (nodep->name() == "constraint_mode") { + methodOkArguments(nodep, 0, 1); + nodep->v3warn(CONSTRAINTIGN, "constraint_mode ignored (unsupported)"); + // Constraints ignored, so we just return "OFF" + nodep->replaceWith(new AstConst{nodep->fileline(), AstConst::BitFalse{}}); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } else { + nodep->v3fatalSrc("Unknown built-in constraint method " << nodep->prettyNameQ()); + } + } + void methodCallRandMode(AstMethodCall* nodep) { + // Method call on constraint (currently hacked as just a var) + methodOkArguments(nodep, 0, 1); + nodep->v3warn(CONSTRAINTIGN, "rand_mode ignored (unsupported)"); + // Disables ignored, so we just return "ON" + nodep->replaceWith(new AstConst{nodep->fileline(), AstConst::BitTrue{}}); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } void methodCallUnpack(AstMethodCall* nodep, AstUnpackArrayDType* adtypep) { enum : uint8_t { UNKNOWN = 0, diff --git a/src/verilog.y b/src/verilog.y index eb06172e6..571f51876 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -6992,9 +6992,13 @@ class_constraint: // ==IEEE: class_constraint // // IEEE: constraint_declaration // // UNSUP: We have the unsupported warning on the randomize() call, so don't bother on // // constraint blocks. When we support randomize we need to make AST nodes for below rules - constraintStaticE yCONSTRAINT idAny constraint_block { $$ = nullptr; /*UNSUP*/ } + constraintStaticE yCONSTRAINT idAny constraint_block + { // Variable so we can link and later ignore constraint_mode() methods + $$ = new AstVar{$3, VVarType::MEMBER, *$3, VFlagBitPacked{}, 1}; + $2->v3warn(CONSTRAINTIGN, "Constraint ignored (unsupported)"); } // // IEEE: constraint_prototype + constraint_prototype_qualifier - | constraintStaticE yCONSTRAINT idAny ';' { $$ = nullptr; } + | constraintStaticE yCONSTRAINT idAny ';' + { $$ = nullptr; } | yEXTERN constraintStaticE yCONSTRAINT idAny ';' { $$ = nullptr; BBUNSUP($1, "Unsupported: extern constraint"); } | yPURE constraintStaticE yCONSTRAINT idAny ';' diff --git a/test_regress/t/t_constraint.pl b/test_regress/t/t_constraint.pl new file mode 100755 index 000000000..11d21fc86 --- /dev/null +++ b/test_regress/t/t_constraint.pl @@ -0,0 +1,23 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2019 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); + +compile( + verilator_flags2 => ['-Wno-CONSTRAINTIGN'], + ); + +execute( + check_finished => 1, + ); + + +ok(1); +1; diff --git a/test_regress/t/t_constraint.v b/test_regress/t/t_constraint.v new file mode 100644 index 000000000..59dea5195 --- /dev/null +++ b/test_regress/t/t_constraint.v @@ -0,0 +1,31 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Packet; + rand int one; + + constraint a { one > 0 && one < 2; } + +endclass + +module t (/*AUTOARG*/); + + Packet p; + + int v; + + initial begin + p = new; + v = p.randomize(); + if (v != 1) $stop; +`ifndef VERILATOR + if (p.one != 1) $stop; +`endif + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_constraint_mode.pl b/test_regress/t/t_constraint_mode.pl new file mode 100755 index 000000000..11d21fc86 --- /dev/null +++ b/test_regress/t/t_constraint_mode.pl @@ -0,0 +1,23 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2019 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); + +compile( + verilator_flags2 => ['-Wno-CONSTRAINTIGN'], + ); + +execute( + check_finished => 1, + ); + + +ok(1); +1; diff --git a/test_regress/t/t_constraint_mode.v b/test_regress/t/t_constraint_mode.v new file mode 100644 index 000000000..6d18156bc --- /dev/null +++ b/test_regress/t/t_constraint_mode.v @@ -0,0 +1,59 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Packet; + rand int one; + + constraint a { one > 0 && one < 2; } + + task test1; + // TODO Verilator ignores this setting currently, always returning 1 (rand on) + one.rand_mode(0); + one.rand_mode(1); + if (one.rand_mode() != 1) $stop; + + // TODO Verilator ignores this setting currently, always returning 0 (constraint off) + a.constraint_mode(1); + a.constraint_mode(0); + if (a.constraint_mode() != 0) $stop; + endtask + +endclass + +module t (/*AUTOARG*/); + + Packet p; + + int v; + + initial begin + p = new; + v = p.randomize(); + if (v != 1) $stop; +`ifndef VERILATOR + if (p.one != 1) $stop; +`endif + + // TODO Verilator ignores this setting currently, always returning 1 (rand on) + p.one.rand_mode(0); + p.one.rand_mode(1); + if (p.one.rand_mode() != 1) $stop; + + // TODO Verilator ignores this setting currently, always returning 0 (constraint off) + p.a.constraint_mode(1); + p.a.constraint_mode(0); + if (p.a.constraint_mode() != 0) $stop; + + p.test1(); + + // TODO test can't redefine constraint_mode + // TODO test can't redefine rand_mode + // TODO test can't call constraint_mode on non-constraint + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_constraint_mode_warn_bad.out b/test_regress/t/t_constraint_mode_warn_bad.out new file mode 100644 index 000000000..478853c43 --- /dev/null +++ b/test_regress/t/t_constraint_mode_warn_bad.out @@ -0,0 +1,54 @@ +%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:10:4: Constraint ignored (unsupported) + 10 | constraint a { one > 0 && one < 2; } + | ^~~~~~~~~~ + ... For warning description see https://verilator.org/warn/CONSTRAINTIGN?v=latest + ... Use "/* verilator lint_off CONSTRAINTIGN */" and lint_on around source to disable this message. +%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:14:11: rand_mode ignored (unsupported) + : ... In instance t + 14 | one.rand_mode(0); + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:15:11: rand_mode ignored (unsupported) + : ... In instance t + 15 | one.rand_mode(1); + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:16:15: rand_mode ignored (unsupported) + : ... In instance t + 16 | if (one.rand_mode() != 1) $stop; + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:19:9: constraint_mode ignored (unsupported) + : ... In instance t + 19 | a.constraint_mode(1); + | ^~~~~~~~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:20:9: constraint_mode ignored (unsupported) + : ... In instance t + 20 | a.constraint_mode(0); + | ^~~~~~~~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:21:13: constraint_mode ignored (unsupported) + : ... In instance t + 21 | if (a.constraint_mode() != 0) $stop; + | ^~~~~~~~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:41:13: rand_mode ignored (unsupported) + : ... In instance t + 41 | p.one.rand_mode(0); + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:42:13: rand_mode ignored (unsupported) + : ... In instance t + 42 | p.one.rand_mode(1); + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:43:17: rand_mode ignored (unsupported) + : ... In instance t + 43 | if (p.one.rand_mode() != 1) $stop; + | ^~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:46:11: constraint_mode ignored (unsupported) + : ... In instance t + 46 | p.a.constraint_mode(1); + | ^~~~~~~~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:47:11: constraint_mode ignored (unsupported) + : ... In instance t + 47 | p.a.constraint_mode(0); + | ^~~~~~~~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_constraint_mode.v:48:15: constraint_mode ignored (unsupported) + : ... In instance t + 48 | if (p.a.constraint_mode() != 0) $stop; + | ^~~~~~~~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_constraint_mode_warn_bad.pl b/test_regress/t/t_constraint_mode_warn_bad.pl new file mode 100755 index 000000000..96addf7c7 --- /dev/null +++ b/test_regress/t/t_constraint_mode_warn_bad.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2019 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(vlt => 1); + +top_filename("t/t_constraint_mode.v"); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_randomize.out b/test_regress/t/t_randomize.out index 334f02e8a..82e50c3f1 100644 --- a/test_regress/t/t_randomize.out +++ b/test_regress/t/t_randomize.out @@ -2,12 +2,31 @@ 11 | extern constraint ex; | ^~~~~~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Warning-CONSTRAINTIGN: t/t_randomize.v:13:4: Constraint ignored (unsupported) + 13 | constraint a { header > 0 && header < 1000; } + | ^~~~~~~~~~ + ... Use "/* verilator lint_off CONSTRAINTIGN */" and lint_on around source to disable this message. +%Warning-CONSTRAINTIGN: t/t_randomize.v:14:4: Constraint ignored (unsupported) + 14 | constraint b { + | ^~~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_randomize.v:19:4: Constraint ignored (unsupported) + 19 | constraint c { + | ^~~~~~~~~~ +%Warning-CONSTRAINTIGN: t/t_randomize.v:23:4: Constraint ignored (unsupported) + 23 | constraint d { + | ^~~~~~~~~~ %Error-UNSUPPORTED: t/t_randomize.v:29:29: Unsupported: solve before 29 | constraint order { solve length before header; } | ^~~~~~ +%Warning-CONSTRAINTIGN: t/t_randomize.v:29:4: Constraint ignored (unsupported) + 29 | constraint order { solve length before header; } + | ^~~~~~~~~~ %Error-UNSUPPORTED: t/t_randomize.v:32:9: Unsupported: dist 32 | x dist { [100:102] :/ 1, 200 := 2, 300 := 5, 400}; | ^~~~ +%Warning-CONSTRAINTIGN: t/t_randomize.v:30:4: Constraint ignored (unsupported) + 30 | constraint dis { + | ^~~~~~~~~~ %Error-UNSUPPORTED: t/t_randomize.v:37:1: Unsupported: extern constraint 37 | constraint Packet::ex { header > 0 }; | ^~~~~~~~~~ From cdb61842d6d8c7c844badc68cd1f8a230dfdf2ba Mon Sep 17 00:00:00 2001 From: Krzysztof Bieganski Date: Thu, 6 Apr 2023 16:31:52 +0200 Subject: [PATCH 106/155] Internals: Remove `VlNow` (#4089) `VlNow{}` is completely unnecessary, as coroutines are always on the heap (unless optimized out). Also fix access of var ref passed to forked processes. --- docs/internals.rst | 18 ++++++------------ include/verilated_timing.h | 10 ---------- src/V3SchedTiming.cpp | 23 +++++++++++------------ 3 files changed, 17 insertions(+), 34 deletions(-) diff --git a/docs/internals.rst b/docs/internals.rst index 12cbd720c..c78e0197b 100644 --- a/docs/internals.rst +++ b/docs/internals.rst @@ -628,16 +628,12 @@ coroutines ``co_await`` its ``join`` function, and forked ones call ``done`` when they're finished. Once the required number of coroutines (set using ``setCounter``) finish execution, the forking coroutine is resumed. -Awaitable Utilities -~~~~~~~~~~~~~~~~~~~ +``VlForever`` +~~~~~~~~~~~~~ -There are also two small utility awaitable types: - -* ``VlNow`` is an awaitable that suspends and immediately resumes coroutines. - It is used for forcing a coroutine to be moved onto the heap. See the `Forks` - section for more detail. -* ``VlForever`` is used for blocking a coroutine forever. See the `Timing pass` - section for more detail. +A small utility awaitable type. It allows for blocking a coroutine forever. It +is currently only used for ``wait`` statements that await a constant false +condition. See the `Timing Pass` section for more details. Timing Pass ~~~~~~~~~~~ @@ -749,9 +745,7 @@ doesn't suspend the forking process. In forked processes, references to local variables are only allowed in ``fork..join``, as this is the only case that ensures the lifetime of these -locals are at least as long as the execution of the forked processes. This is -where ``VlNow`` is used, to ensure the locals are moved to the heap before they -are passed by reference to the forked processes. +locals are at least as long as the execution of the forked processes. Multithreaded Mode diff --git a/include/verilated_timing.h b/include/verilated_timing.h index 535839389..019573185 100644 --- a/include/verilated_timing.h +++ b/include/verilated_timing.h @@ -312,16 +312,6 @@ public: } }; -//============================================================================= -// VlNow is a helper awaitable type that always suspends, and then immediately resumes a coroutine. -// Allows forcing the move of coroutine locals to the heap. - -struct VlNow { - bool await_ready() const { return false; } // Always suspend - bool await_suspend(std::coroutine_handle<>) const { return false; } // Resume immediately - void await_resume() const {} -}; - //============================================================================= // VlForever is a helper awaitable type for suspending coroutines forever. Used for constant // wait statements. diff --git a/src/V3SchedTiming.cpp b/src/V3SchedTiming.cpp index e772d1bcb..0b3da2451 100644 --- a/src/V3SchedTiming.cpp +++ b/src/V3SchedTiming.cpp @@ -272,22 +272,20 @@ void transformForks(AstNetlist* const netlistp) { // If it a fork sync or an intra-assignment variable, pass it by value const bool passByValue = (dtypep && dtypep->isForkSync()) || VString::startsWith(varp->name(), "__Vintra"); - // Only handle vars passed by value or locals declared before the fork - if (!passByValue && (!varp->user1() || !varp->isFuncLocal())) return; if (passByValue) { // We can just pass it to the new function + } else if (!varp->user1() || !varp->isFuncLocal()) { + // Not func local, or not declared before the fork. Their lifetime is longer + // than the forked process. Skip + return; } else if (m_forkp->joinType().join()) { // If it's fork..join, we can refer to variables from the parent process - if (!m_funcp->user1SetOnce()) { // Only do this once per function - // Move all locals to the heap before the fork - AstCExpr* const nowp - = new AstCExpr{m_forkp->fileline(), "VlNow{}", 0, true}; - nowp->dtypeSetVoid(); // TODO: this is sloppy but harmless - AstCAwait* const awaitp = new AstCAwait{m_forkp->fileline(), nowp}; - awaitp->dtypeSetVoid(); - m_forkp->addHereThisAsNext(awaitp->makeStmt()); - } } else { + // TODO: It is possible to relax this by allowing the use of such variables up + // until the first await. Also, variables defined within a forked process + // (inside a begin) are extracted out by V3Begin, so they also trigger this + // error. Preventing this (or detecting such cases and moving the vars back) + // would also allow for using them freely. refp->v3warn(E_UNSUPPORTED, "Unsupported: variable local to a forking process " "accessed in a fork..join_any or fork..join_none"); return; @@ -305,7 +303,8 @@ void transformForks(AstNetlist* const netlistp) { = new AstVarScope{newvarp->fileline(), funcp->scopep(), newvarp}; funcp->scopep()->addVarsp(newvscp); vscp->user2p(newvscp); - callp->addArgsp(new AstVarRef{refp->fileline(), vscp, VAccess::READ}); + callp->addArgsp(new AstVarRef{ + refp->fileline(), vscp, passByValue ? VAccess::READ : VAccess::READWRITE}); } AstVarScope* const newvscp = VN_AS(vscp->user2p(), VarScope); refp->varScopep(newvscp); From 8caf9be3e6d63bac684b794a8e57bee1aa2aaa85 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 6 Apr 2023 21:00:10 -0400 Subject: [PATCH 107/155] Internals: Favor {} constructor syntax. No functional change intended. --- src/V3Assert.cpp | 4 ++-- src/V3AssertPre.cpp | 4 ++-- src/V3AstNodeOther.h | 8 ++++---- src/V3AstNodes.cpp | 8 ++++---- src/V3Begin.cpp | 2 +- src/V3Clock.cpp | 2 +- src/V3Delayed.cpp | 16 ++++++++-------- src/V3Descope.cpp | 4 ++-- src/V3EmitCFunc.cpp | 6 +++--- src/V3EmitCFunc.h | 4 ++-- src/V3EmitCImp.cpp | 4 ++-- src/V3EmitCSyms.cpp | 2 +- src/V3EmitMk.cpp | 18 +++++++++--------- src/V3Error.cpp | 2 +- src/V3Global.cpp | 2 +- src/V3Inst.cpp | 2 +- src/V3LinkInc.cpp | 2 +- src/V3LinkJump.cpp | 2 +- src/V3Options.cpp | 4 ++-- src/V3Order.cpp | 2 +- src/V3OrderMoveGraph.h | 4 ++-- src/V3ParseImp.cpp | 2 +- src/V3Split.cpp | 6 +++--- src/V3Task.cpp | 8 ++++---- src/verilog.y | 8 ++++---- 25 files changed, 63 insertions(+), 63 deletions(-) diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index 8607c05fa..15969106a 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -54,11 +54,11 @@ private: string assertDisplayMessage(AstNode* nodep, const string& prefix, const string& message, VDisplayType severity) { if (severity == VDisplayType::DT_ERROR || severity == VDisplayType::DT_FATAL) { - return (string("[%0t] " + prefix + ": ") + nodep->fileline()->filebasename() + ":" + return (string{"[%0t] " + prefix + ": "} + nodep->fileline()->filebasename() + ":" + cvtToStr(nodep->fileline()->lineno()) + ": Assertion failed in %m" + ((message != "") ? ": " : "") + message + "\n"); } else { - return (string("[%0t] " + prefix + ": ") + nodep->fileline()->filebasename() + ":" + return (string{"[%0t] " + prefix + ": "} + nodep->fileline()->filebasename() + ":" + cvtToStr(nodep->fileline()->lineno()) + ": %m" + ((message != "") ? ": " : "") + message + "\n"); } diff --git a/src/V3AssertPre.cpp b/src/V3AssertPre.cpp index 8221ee0ab..51a12ad14 100644 --- a/src/V3AssertPre.cpp +++ b/src/V3AssertPre.cpp @@ -229,7 +229,7 @@ private: // always queue.push(); AstCMethodHard* const pushp = new AstCMethodHard{ flp, new AstVarRef{flp, queueVarp, VAccess::WRITE}, "push", - new AstTime(nodep->fileline(), m_modp->timeunit())}; + new AstTime{nodep->fileline(), m_modp->timeunit()}}; pushp->addPinsp(exprp->cloneTree(false)); pushp->dtypeSetVoid(); m_clockingp->addNextHere( @@ -238,7 +238,7 @@ private: // always @ queue.pop(, /*out*/}); AstCMethodHard* const popp = new AstCMethodHard{ flp, new AstVarRef{flp, queueVarp, VAccess::READWRITE}, "pop", - new AstTime(nodep->fileline(), m_modp->timeunit())}; + new AstTime{nodep->fileline(), m_modp->timeunit()}}; popp->addPinsp(skewp->unlinkFrBack()); popp->addPinsp(refp); popp->dtypeSetVoid(); diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index a9b1ecb10..e923385d3 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -952,7 +952,7 @@ public: BROKEN_RTN(!fmtp()); return nullptr; } - string verilogKwd() const override { return (string("$") + string(displayType().ascii())); } + string verilogKwd() const override { return string{"$"} + string{displayType().ascii()}; } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering @@ -1360,7 +1360,7 @@ public: void name(const string& name) override { m_name = name; } void dump(std::ostream& str) const override; string nameDotless() const; - string nameVlSym() const { return ((string("vlSymsp->")) + nameDotless()); } + string nameVlSym() const { return string{"vlSymsp->"} + nameDotless(); } AstNodeModule* modp() const { return m_modp; } // AstScope* aboveScopep() const VL_MT_SAFE { return m_aboveScopep; } @@ -2640,8 +2640,8 @@ public: return nullptr; } string verilogKwd() const override { - return (filep() ? string("$f") + string(displayType().ascii()) - : string("$") + string(displayType().ascii())); + return (filep() ? string{"$f"} + string{displayType().ascii()} + : string{"$"} + string{displayType().ascii()}); } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index fd7d78fc5..9b84b5c4b 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -574,7 +574,7 @@ string AstVar::dpiArgType(bool named, bool forReturn) const { } else { class converter final : public dpiTypesToStringConverter { string bitLogicVector(const AstVar* varp, bool isBit) const override { - return string(varp->isReadOnly() ? "const " : "") + return string{varp->isReadOnly() ? "const " : ""} + dpiTypesToStringConverter::bitLogicVector(varp, isBit) + '*'; } string primitive(const AstVar* varp) const override { @@ -637,13 +637,13 @@ string AstVar::dpiTmpVarType(const string& varName) const { string AstVar::scType() const { if (isScBigUint()) { - return (string("sc_biguint<") + cvtToStr(widthMin()) + return (string{"sc_biguint<"} + cvtToStr(widthMin()) + "> "); // Keep the space so don't get >> } else if (isScUint()) { - return (string("sc_uint<") + cvtToStr(widthMin()) + return (string{"sc_uint<"} + cvtToStr(widthMin()) + "> "); // Keep the space so don't get >> } else if (isScBv()) { - return (string("sc_bv<") + cvtToStr(widthMin()) + "> "); // Keep the space so don't get >> + return (string{"sc_bv<"} + cvtToStr(widthMin()) + "> "); // Keep the space so don't get >> } else if (widthMin() == 1) { return "bool"; } else if (widthMin() <= VL_IDATASIZE) { diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index c2a06df4b..b7707754d 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -299,7 +299,7 @@ private: // To keep correct visual order, must add before other Text's AstText* const afterp = nodep->scopeAttrp(); if (afterp) afterp->unlinkFrBackWithNext(); - nodep->addScopeAttrp(new AstText{nodep->fileline(), string("__DOT__") + scname}); + nodep->addScopeAttrp(new AstText{nodep->fileline(), string{"__DOT__"} + scname}); if (afterp) nodep->addScopeAttrp(afterp); } iterateChildren(nodep); diff --git a/src/V3Clock.cpp b/src/V3Clock.cpp index 1a7be8041..bf374d2a3 100644 --- a/src/V3Clock.cpp +++ b/src/V3Clock.cpp @@ -95,7 +95,7 @@ private: if (vscp->user1p()) return VN_AS(vscp->user1p(), VarScope); const AstVar* const varp = vscp->varp(); const string newvarname - = string("__Vsampled__") + vscp->scopep()->nameDotless() + "__" + varp->name(); + = string{"__Vsampled__"} + vscp->scopep()->nameDotless() + "__" + varp->name(); FileLine* const flp = vscp->fileline(); AstVar* const newvarp = new AstVar{flp, VVarType::MODULETEMP, newvarname, varp->dtypep()}; newvarp->noReset(true); // Reset by below assign diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index d249b2637..1a491422d 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -262,8 +262,8 @@ private: if (VN_IS(dimp, Const)) { // bit = const, can just use it dimreadps.push_front(dimp); } else { - const string bitvarname = (string("__Vdlyvdim") + cvtToStr(dimension) + "__" - + oldvarp->shortName() + "__v" + cvtToStr(modVecNum)); + const string bitvarname = string{"__Vdlyvdim"} + cvtToStr(dimension) + "__" + + oldvarp->shortName() + "__v" + cvtToStr(modVecNum); AstVarScope* const bitvscp = createVarSc(varrefp->varScopep(), bitvarname, dimp->width(), nullptr); AstAssign* const bitassignp = new AstAssign{ @@ -282,8 +282,8 @@ private: // vlsb = constant, can just push constant into where we use it bitreadp = lsbvaluep; } else { - const string bitvarname = (string("__Vdlyvlsb__") + oldvarp->shortName() + "__v" - + cvtToStr(modVecNum)); + const string bitvarname + = string{"__Vdlyvlsb__"} + oldvarp->shortName() + "__v" + cvtToStr(modVecNum); AstVarScope* const bitvscp = createVarSc(varrefp->varScopep(), bitvarname, lsbvaluep->width(), nullptr); AstAssign* const bitassignp = new AstAssign{ @@ -301,7 +301,7 @@ private: valreadp = nodep->rhsp()->unlinkFrBack(); } else { const string valvarname - = (string("__Vdlyvval__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum)); + = string{"__Vdlyvval__"} + oldvarp->shortName() + "__v" + cvtToStr(modVecNum); AstVarScope* const valvscp = createVarSc(varrefp->varScopep(), valvarname, 0, nodep->rhsp()->dtypep()); newlhsp = new AstVarRef{nodep->fileline(), valvscp, VAccess::WRITE}; @@ -321,7 +321,7 @@ private: ++m_statSharedSet; } else { // Create new one const string setvarname - = (string("__Vdlyvset__") + oldvarp->shortName() + "__v" + cvtToStr(modVecNum)); + = string{"__Vdlyvset__"} + oldvarp->shortName() + "__v" + cvtToStr(modVecNum); setvscp = createVarSc(varrefp->varScopep(), setvarname, 1, nullptr); if (!m_inSuspendableOrFork) { // Suspendables reset __Vdlyvset__ in the AstAlwaysPost @@ -483,7 +483,7 @@ private: if (nodep->isDelayed()) { AstVarRef* const vrefp = VN_AS(nodep->operandp(), VarRef); vrefp->unlinkFrBack(); - const string newvarname = (string("__Vdly__") + vrefp->varp()->shortName()); + const string newvarname = string{"__Vdly__"} + vrefp->varp()->shortName(); AstVarScope* const dlyvscp = createVarSc(vrefp->varScopep(), newvarname, 1, nullptr); const auto dlyRef = [=](VAccess access) { @@ -572,7 +572,7 @@ private: checkActivePost(nodep, oldactivep); } if (!dlyvscp) { // First use of this delayed variable - const string newvarname = (string("__Vdly__") + nodep->varp()->shortName()); + const string newvarname = string{"__Vdly__"} + nodep->varp()->shortName(); dlyvscp = createVarSc(oldvscp, newvarname, 0, nullptr); AstNodeAssign* const prep = new AstAssignPre{ nodep->fileline(), diff --git a/src/V3Descope.cpp b/src/V3Descope.cpp index fded54459..3c1eeb518 100644 --- a/src/V3Descope.cpp +++ b/src/V3Descope.cpp @@ -166,7 +166,7 @@ private: new AstEq{ funcp->fileline(), new AstCExpr{funcp->fileline(), "this", 64}, new AstCExpr{funcp->fileline(), - string("&(") + funcp->scopep()->nameVlSym() + ")", + string{"&("} + funcp->scopep()->nameVlSym() + ")", 64}}, returnp}; newfuncp->addStmtsp(ifp); @@ -178,7 +178,7 @@ private: // to come up with some return value // newfuncp->addStmtsp(new AstDisplay(newfuncp->fileline(), // VDisplayType::DT_WARNING, - // string("%%Error: ")+name+"() called with bad + // string{"%%Error: "}+name+"() called with bad // scope", nullptr)); // newfuncp->addStmtsp(new AstStop(newfuncp->fileline())); if (debug() >= 9) newfuncp->dumpTree("- newfunc: "); diff --git a/src/V3EmitCFunc.cpp b/src/V3EmitCFunc.cpp index 498c46f1e..9160e5068 100644 --- a/src/V3EmitCFunc.cpp +++ b/src/V3EmitCFunc.cpp @@ -275,9 +275,9 @@ void EmitCFunc::displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const double dchars = mantissabits / 3.321928094887362 + 1.0; if (fmtLetter == 'd') dchars++; // space for sign const int nchars = int(dchars); - pfmt = string("%") + cvtToStr(nchars) + fmtLetter; + pfmt = string{"%"} + cvtToStr(nchars) + fmtLetter; } else { - pfmt = string("%") + vfmt + fmtLetter; + pfmt = string{"%"} + vfmt + fmtLetter; } m_emitDispState.pushFormat(pfmt); if (!ignore) { @@ -672,7 +672,7 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, const string& varNameP } else if (const AstUnpackArrayDType* const adtypep = VN_CAST(dtypep, UnpackArrayDType)) { UASSERT_OBJ(adtypep->hi() >= adtypep->lo(), varp, "Should have swapped msb & lsb earlier."); - const string ivar = string("__Vi") + cvtToStr(depth); + const string ivar = string{"__Vi"} + cvtToStr(depth); const string pre = ("for (int " + ivar + " = " + cvtToStr(0) + "; " + ivar + " < " + cvtToStr(adtypep->elementsConst()) + "; ++" + ivar + ") {\n"); const string below = emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(), diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 83997f570..1149c728f 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -492,7 +492,7 @@ public: if (!v3Global.opt.protectIds()) return; } if (!(nodep->protect() && v3Global.opt.protectIds())) { - putsDecoration(string("// ") + nodep->name() + at + "\n"); + putsDecoration(string{"// "} + nodep->name() + at + "\n"); } iterateChildrenConst(nodep); } @@ -1310,7 +1310,7 @@ public: // Default void visit(AstNode* nodep) override { - puts(string("\n???? // ") + nodep->prettyTypeName() + "\n"); + puts(string{"\n???? // "} + nodep->prettyTypeName() + "\n"); iterateChildrenConst(nodep); // LCOV_EXCL_START if (!v3Global.opt.lintOnly()) { // An internal problem, so suppress diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index d231d7058..ead32fb03 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -401,7 +401,7 @@ class EmitCImp final : EmitCFunc { const int vecnum = vects++; UASSERT_OBJ(arrayp->hi() >= arrayp->lo(), varp, "Should have swapped msb & lsb earlier."); - const string ivar = string("__Vi") + cvtToStr(vecnum); + const string ivar = string{"__Vi"} + cvtToStr(vecnum); puts("for (int __Vi" + cvtToStr(vecnum) + " = " + cvtToStr(0)); puts("; " + ivar + " < " + cvtToStr(arrayp->elementsConst())); puts("; ++" + ivar + ") {\n"); @@ -415,7 +415,7 @@ class EmitCImp final : EmitCFunc { if (elementp->isWide() && !(basicp && basicp->keyword() == VBasicDTypeKwd::STRING)) { const int vecnum = vects++; - const string ivar = string("__Vi") + cvtToStr(vecnum); + const string ivar = string{"__Vi"} + cvtToStr(vecnum); puts("for (int __Vi" + cvtToStr(vecnum) + " = " + cvtToStr(0)); puts("; " + ivar + " < " + cvtToStr(elementp->widthWords())); puts("; ++" + ivar + ") {\n"); diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index d9d865324..a1b64ea7f 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -516,7 +516,7 @@ void EmitCSyms::emitSymHdr() { puts("\n// CONSTRUCTORS\n"); puts(symClassName() + "(VerilatedContext* contextp, const char* namep, " + topClassName() + "* modelp);\n"); - puts(string("~") + symClassName() + "();\n"); + puts(string{"~"} + symClassName() + "();\n"); for (const auto& i : m_usesVfinal) { puts("void " + symClassName() + "_" + cvtToStr(i.first) + "("); diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp index 86f325c2f..02696c342 100644 --- a/src/V3EmitMk.cpp +++ b/src/V3EmitMk.cpp @@ -156,9 +156,9 @@ public: of.puts("# Path to Verilator kit (from $VERILATOR_ROOT)\n"); of.puts("VERILATOR_ROOT = " + V3Options::getenvVERILATOR_ROOT() + "\n"); of.puts("# SystemC include directory with systemc.h (from $SYSTEMC_INCLUDE)\n"); - of.puts(string("SYSTEMC_INCLUDE ?= ") + V3Options::getenvSYSTEMC_INCLUDE() + "\n"); + of.puts(string{"SYSTEMC_INCLUDE ?= "} + V3Options::getenvSYSTEMC_INCLUDE() + "\n"); of.puts("# SystemC library directory with libsystemc.a (from $SYSTEMC_LIBDIR)\n"); - of.puts(string("SYSTEMC_LIBDIR ?= ") + V3Options::getenvSYSTEMC_LIBDIR() + "\n"); + of.puts(string{"SYSTEMC_LIBDIR ?= "} + V3Options::getenvSYSTEMC_LIBDIR() + "\n"); // Only check it if we really need the value if (v3Global.opt.systemC() && !V3Options::systemCFound()) { @@ -169,22 +169,22 @@ public: of.puts("\n### Switches...\n"); of.puts("# C++ code coverage 0/1 (from --prof-c)\n"); - of.puts(string("VM_PROFC = ") + ((v3Global.opt.profC()) ? "1" : "0") + "\n"); + of.puts(string{"VM_PROFC = "} + ((v3Global.opt.profC()) ? "1" : "0") + "\n"); of.puts("# SystemC output mode? 0/1 (from --sc)\n"); - of.puts(string("VM_SC = ") + ((v3Global.opt.systemC()) ? "1" : "0") + "\n"); + of.puts(string{"VM_SC = "} + ((v3Global.opt.systemC()) ? "1" : "0") + "\n"); of.puts("# Legacy or SystemC output mode? 0/1 (from --sc)\n"); - of.puts(string("VM_SP_OR_SC = $(VM_SC)\n")); + of.puts(string{"VM_SP_OR_SC = $(VM_SC)\n"}); of.puts("# Deprecated\n"); - of.puts(string("VM_PCLI = ") + (v3Global.opt.systemC() ? "0" : "1") + "\n"); + of.puts(string{"VM_PCLI = "} + (v3Global.opt.systemC() ? "0" : "1") + "\n"); of.puts( "# Deprecated: SystemC architecture to find link library path (from $SYSTEMC_ARCH)\n"); - of.puts(string("VM_SC_TARGET_ARCH = ") + V3Options::getenvSYSTEMC_ARCH() + "\n"); + of.puts(string{"VM_SC_TARGET_ARCH = "} + V3Options::getenvSYSTEMC_ARCH() + "\n"); of.puts("\n### Vars...\n"); of.puts("# Design prefix (from --prefix)\n"); - of.puts(string("VM_PREFIX = ") + v3Global.opt.prefix() + "\n"); + of.puts(string{"VM_PREFIX = "} + v3Global.opt.prefix() + "\n"); of.puts("# Module prefix (from --prefix)\n"); - of.puts(string("VM_MODPREFIX = ") + v3Global.opt.modPrefix() + "\n"); + of.puts(string{"VM_MODPREFIX = "} + v3Global.opt.modPrefix() + "\n"); of.puts("# User CFLAGS (from -CFLAGS on Verilator command line)\n"); of.puts("VM_USER_CFLAGS = \\\n"); diff --git a/src/V3Error.cpp b/src/V3Error.cpp index 9eaaf9b0d..6fc051edc 100644 --- a/src/V3Error.cpp +++ b/src/V3Error.cpp @@ -257,7 +257,7 @@ void V3Error::init() { describedEachWarn(static_cast(i), false); pretendError(static_cast(i), V3ErrorCode{i}.pretendError()); } - if (VL_UNCOVERABLE(string(V3ErrorCode{V3ErrorCode::_ENUM_MAX}.ascii()) != " MAX")) { + if (VL_UNCOVERABLE(string{V3ErrorCode{V3ErrorCode::_ENUM_MAX}.ascii()} != " MAX")) { v3fatalSrc("Enum table in V3ErrorCode::EC_ascii() is munged"); } } diff --git a/src/V3Global.cpp b/src/V3Global.cpp index 81f24ade4..a9300eaf3 100644 --- a/src/V3Global.cpp +++ b/src/V3Global.cpp @@ -52,7 +52,7 @@ void V3Global::readFiles() { VInFilter filter{v3Global.opt.pipeFilter()}; V3ParseSym parseSyms{v3Global.rootp()}; // Symbol table must be common across all parsing - V3Parse parser(v3Global.rootp(), &filter, &parseSyms); + V3Parse parser{v3Global.rootp(), &filter, &parseSyms}; // Parse the std package if (v3Global.opt.std()) { diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index 74fe5d504..061e5caeb 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -555,7 +555,7 @@ public: V3Inst::checkOutputShort(pinp); AstNodeExpr* const pinexprp = VN_AS(pinp->exprp(), NodeExpr)->unlinkFrBack(); const string newvarname - = (string(pinVarp->isWritable() ? "__Vcellout" : "__Vcellinp") + = (string{pinVarp->isWritable() ? "__Vcellout" : "__Vcellinp"} // Prevent name conflict if both tri & non-tri add signals + (forTristate ? "t" : "") + "__" + cellp->name() + "__" + pinp->name()); AstVar* const newvarp diff --git a/src/V3LinkInc.cpp b/src/V3LinkInc.cpp index 4a2bb0c1c..ac89c57ee 100644 --- a/src/V3LinkInc.cpp +++ b/src/V3LinkInc.cpp @@ -253,7 +253,7 @@ private: // Prepare a temporary variable FileLine* const fl = backp->fileline(); - const string name = string("__Vincrement") + cvtToStr(++m_modIncrementsNum); + const string name = string{"__Vincrement"} + cvtToStr(++m_modIncrementsNum); AstVar* const varp = new AstVar{fl, VVarType::BLOCKTEMP, name, VFlagChildDType{}, varrefp->varp()->subDTypep()->cloneTree(true)}; if (m_ftaskp) varp->funcLocal(true); diff --git a/src/V3LinkJump.cpp b/src/V3LinkJump.cpp index deba207eb..7ac37ade3 100644 --- a/src/V3LinkJump.cpp +++ b/src/V3LinkJump.cpp @@ -192,7 +192,7 @@ private: // REPEAT(count,body) -> loop=count,WHILE(loop>0) { body, loop-- } // Note var can be signed or unsigned based on original number. AstNodeExpr* const countp = nodep->countp()->unlinkFrBackWithNext(); - const string name = string("__Vrepeat") + cvtToStr(m_modRepeatNum++); + const string name = string{"__Vrepeat"} + cvtToStr(m_modRepeatNum++); // Spec says value is integral, if negative is ignored AstVar* const varp = new AstVar{nodep->fileline(), VVarType::BLOCKTEMP, name, nodep->findSigned32DType()}; diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 25283e424..31d37e4b9 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -966,9 +966,9 @@ void V3Options::parseOpts(FileLine* fl, int argc, char** argv) { // Default prefix to the filename if (prefix() == "" && topModule() != "") - m_prefix = string("V") + AstNode::encodeName(topModule()); + m_prefix = string{"V"} + AstNode::encodeName(topModule()); if (prefix() == "" && vFilesList.size() >= 1) - m_prefix = string("V") + AstNode::encodeName(V3Os::filenameNonExt(*(vFilesList.begin()))); + m_prefix = string{"V"} + AstNode::encodeName(V3Os::filenameNonExt(*(vFilesList.begin()))); if (modPrefix() == "") m_modPrefix = prefix(); // Find files in makedir diff --git a/src/V3Order.cpp b/src/V3Order.cpp index a81a8afe0..dc1905f97 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -510,7 +510,7 @@ public: } } string name() const { - return (string("MDS:") + " d=" + cvtToHex(domainp()) + " s=" + cvtToHex(scopep())); + return string{"MDS:"} + " d=" + cvtToHex(domainp()) + " s=" + cvtToHex(scopep()); } }; diff --git a/src/V3OrderMoveGraph.h b/src/V3OrderMoveGraph.h index 622ffd5d9..426b410ff 100644 --- a/src/V3OrderMoveGraph.h +++ b/src/V3OrderMoveGraph.h @@ -70,7 +70,7 @@ public: nm = "nul"; // LCOV_EXCL_LINE } else { nm = logicp()->name(); - nm += (string("\\nMV:") + " d=" + cvtToHex(logicp()->domainp()) + nm += (string{"\\nMV:"} + " d=" + cvtToHex(logicp()->domainp()) + " s=" + cvtToHex(logicp()->scopep())); } return nm; @@ -127,7 +127,7 @@ public: string nm; if (logicp()) { nm = logicp()->name(); - nm += (string("\\nMV:") + " d=" + cvtToHex(logicp()->domainp()) + " s=" + nm += (string{"\\nMV:"} + " d=" + cvtToHex(logicp()->domainp()) + " s=" + cvtToHex(logicp()->scopep()) // "color()" represents the mtask ID. + "\\nt=" + cvtToStr(color())); diff --git a/src/V3ParseImp.cpp b/src/V3ParseImp.cpp index b310beb96..cbf1808d5 100644 --- a/src/V3ParseImp.cpp +++ b/src/V3ParseImp.cpp @@ -554,7 +554,7 @@ void V3ParseImp::tokenPipelineSym() { } if (foundp && !v3Global.usesStdPackage()) { AstPackageImport* const impp - = new AstPackageImport(stdpkgp->fileline(), stdpkgp, "*"); + = new AstPackageImport{stdpkgp->fileline(), stdpkgp, "*"}; unitPackage(stdpkgp->fileline())->addStmtsp(impp); v3Global.setUsesStdPackage(); } diff --git a/src/V3Split.cpp b/src/V3Split.cpp index 774d2989d..88cd94652 100644 --- a/src/V3Split.cpp +++ b/src/V3Split.cpp @@ -148,7 +148,7 @@ public: SplitVarPostVertex(V3Graph* graphp, AstNode* nodep) : SplitNodeVertex{graphp, nodep} {} ~SplitVarPostVertex() override = default; - string name() const override VL_MT_STABLE { return string("POST ") + SplitNodeVertex::name(); } + string name() const override VL_MT_STABLE { return string{"POST "} + SplitNodeVertex::name(); } string dotColor() const override { return "CadetBlue"; } }; @@ -513,10 +513,10 @@ protected: // And a real ordering to get the statements into something reasonable // We don't care if there's cutable violations here... // Non-cutable violations should be impossible; as those edges are program-order - if (dumpGraph() >= 9) m_graph.dumpDotFilePrefixed(string("splitg_preo"), false); + if (dumpGraph() >= 9) m_graph.dumpDotFilePrefixed("splitg_preo", false); m_graph.acyclic(&SplitEdge::followCyclic); m_graph.rank(&SplitEdge::followCyclic); // Or order(), but that's more expensive - if (dumpGraph() >= 9) m_graph.dumpDotFilePrefixed(string("splitg_opt"), false); + if (dumpGraph() >= 9) m_graph.dumpDotFilePrefixed("splitg_opt", false); } void reorderBlock(AstNode* nodep) { diff --git a/src/V3Task.cpp b/src/V3Task.cpp index a46b8932a..94c45b035 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -323,7 +323,7 @@ struct TaskDpiUtils { return true; } else { const AstNodeDType* const dtypep = portp->dtypep()->skipRefp(); - frstmt = "VL_SET_" + string(dtypep->charIQWN()) + "_" + frSvType + "("; + frstmt = "VL_SET_" + string{dtypep->charIQWN()} + "_" + frSvType + "("; if (VN_IS(dtypep, UnpackArrayDType)) frstmt += "&"; frstmt += frName; ket = ")"; @@ -425,7 +425,7 @@ private: AstNode* const newbodysp = AstNode::cloneTreeNull(refp->taskp()->stmtsp(), true); // Maybe nullptr AstNode* const beginp - = new AstComment{refp->fileline(), string("Function: ") + refp->name(), true}; + = new AstComment{refp->fileline(), string{"Function: "} + refp->name(), true}; if (newbodysp) beginp->addNext(newbodysp); if (debug() >= 9) beginp->dumpTreeAndNext(cout, "- newbegi: "); // @@ -542,7 +542,7 @@ private: UASSERT_OBJ(cfuncp, refp, "No non-inline task associated with this task call?"); // AstNode* const beginp - = new AstComment{refp->fileline(), string("Function: ") + refp->name(), true}; + = new AstComment{refp->fileline(), string{"Function: "} + refp->name(), true}; AstNodeCCall* ccallp; if (VN_IS(refp, New)) { AstCNew* const cnewp = new AstCNew{refp->fileline(), cfuncp}; @@ -1725,7 +1725,7 @@ string V3Task::assignInternalToDpi(AstVar* portp, bool isPtr, const string& frSu stmt = "for (size_t " + idx + " = 0; " + idx + " < " + cvtToStr(unpackSize) + "; ++" + idx + ") "; stmt += (isBit ? "VL_SET_SVBV_" : "VL_SET_SVLV_") - + string(portp->dtypep()->skipRefp()->charIQWN()) + "(" + cvtToStr(portp->width()) + + string{portp->dtypep()->skipRefp()->charIQWN()} + "(" + cvtToStr(portp->width()) + ", "; stmt += toName + " + " + cvtToStr(portp->dtypep()->skipRefp()->widthWords()) + " * " + idx + ", "; diff --git a/src/verilog.y b/src/verilog.y index 571f51876..b8290953a 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -1803,11 +1803,11 @@ modportPortsDecl: // // IEEE: modport_simple_ports_declaration | modportSimplePortOrTFPort { $$ = GRAMMARP->m_modportImpExpActive ? static_cast( - new AstModportFTaskRef( - $1, *$1, GRAMMARP->m_modportImpExpLastIsExport) ) : + new AstModportFTaskRef{ + $1, *$1, GRAMMARP->m_modportImpExpLastIsExport} ) : static_cast( - new AstModportVarRef( - $1, *$1, GRAMMARP->m_varIO) ); } + new AstModportVarRef{ + $1, *$1, GRAMMARP->m_varIO} ); } ; modportSimplePortOrTFPort:// IEEE: modport_simple_port or modport_tf_port, depending what keyword was earlier From 6c21b21ecc477071882383b170db423b7df99db2 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 6 Apr 2023 21:27:16 -0400 Subject: [PATCH 108/155] Internals: Indent verilated_std.sv with Verilog-mode. No functional change. --- include/verilated_std.sv | 144 +++++++++++++++++++-------------------- 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/include/verilated_std.sv b/include/verilated_std.sv index 1c7e60e0e..354901753 100644 --- a/include/verilated_std.sv +++ b/include/verilated_std.sv @@ -26,93 +26,93 @@ // verilator lint_off TIMESCALEMOD // verilator lint_off UNUSEDSIGNAL package std; - // The process class is not implemented, but it's predeclared here, - // so the linter accepts references to it. - typedef class process; + // The process class is not implemented, but it's predeclared here, + // so the linter accepts references to it. + typedef class process; - class mailbox #(type T); - protected int m_bound; - protected T m_queue[$]; + class mailbox #(type T); + protected int m_bound; + protected T m_queue[$]; - function new(int bound = 0); - m_bound = bound; - endfunction + function new(int bound = 0); + m_bound = bound; + endfunction - function int num(); - return m_queue.size(); - endfunction + function int num(); + return m_queue.size(); + endfunction - task put(T message); - `ifdef VERILATOR_TIMING - if (m_bound != 0) - wait (m_queue.size() < m_bound); + task put(T message); +`ifdef VERILATOR_TIMING + if (m_bound != 0) + wait (m_queue.size() < m_bound); + m_queue.push_back(message); +`endif + endtask + + function int try_put(T message); + if (num() < m_bound) begin m_queue.push_back(message); - `endif - endtask + return 1; + end + return 0; + endfunction - function int try_put(T message); - if (num() < m_bound) begin - m_queue.push_back(message); - return 1; - end - return 0; - endfunction + task get(ref T message); +`ifdef VERILATOR_TIMING + wait (m_queue.size() > 0); + message = m_queue.pop_front(); +`endif + endtask - task get(ref T message); - `ifdef VERILATOR_TIMING - wait (m_queue.size() > 0); + function int try_get(ref T message); + if (num() > 0) begin message = m_queue.pop_front(); - `endif - endtask + return 1; + end + return 0; + endfunction - function int try_get(ref T message); - if (num() > 0) begin - message = m_queue.pop_front(); - return 1; - end - return 0; - endfunction + task peek(ref T message); +`ifdef VERILATOR_TIMING + wait (m_queue.size() > 0); + message = m_queue[0]; +`endif + endtask - task peek(ref T message); - `ifdef VERILATOR_TIMING - wait (m_queue.size() > 0); + function int try_peek(ref T message); + if (num() > 0) begin message = m_queue[0]; - `endif - endtask + return 1; + end + return 0; + endfunction + endclass - function int try_peek(ref T message); - if (num() > 0) begin - message = m_queue[0]; - return 1; - end - return 0; - endfunction - endclass + class semaphore; + protected int m_keyCount; - class semaphore; - protected int m_keyCount; + function new(int keyCount = 0); + m_keyCount = keyCount; + endfunction - function new(int keyCount = 0); - m_keyCount = keyCount; - endfunction + function void put(int keyCount = 1); + m_keyCount += keyCount; + endfunction - function void put(int keyCount = 1); - m_keyCount += keyCount; - endfunction + task get(int keyCount = 1); +`ifdef VERILATOR_TIMING + wait (m_keyCount >= keyCount); + m_keyCount -= keyCount; +`endif + endtask - task get(int keyCount = 1); - `ifdef VERILATOR_TIMING - wait (m_keyCount >= keyCount); + function int try_get(int keyCount = 1); + if (m_keyCount >= keyCount) begin m_keyCount -= keyCount; - `endif - endtask - - function int try_get(int keyCount = 1); - if (m_keyCount >= keyCount) begin - m_keyCount -= keyCount; - return 1; - end - return 0; - endfunction - endclass + return 1; + end + return 0; + endfunction + endclass endpackage From 38000a3da07de85f37abcce14a4a4ab81254996d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 6 Apr 2023 21:43:23 -0400 Subject: [PATCH 109/155] Fix unnecessary verilated_std.sv waivers in --waiver-output. --- Changes | 1 + src/V3Waiver.cpp | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Changes b/Changes index 304f6200c..7ad1c2e30 100644 --- a/Changes +++ b/Changes @@ -39,6 +39,7 @@ Verilator 5.009 devel * Fix characters from DEFENV literals for conda (#4035) (#4044). [Tim Snyder] * Fix interface generate begin (#4065). [Srinivasan Venkataramanan] * Fix false ENUMVALUE on expressions and arrays. +* Fix unnecessary verilated_std.sv waivers in --waiver-output. Verilator 5.008 2023-03-04 diff --git a/src/V3Waiver.cpp b/src/V3Waiver.cpp index 1650fdefa..909a762bc 100644 --- a/src/V3Waiver.cpp +++ b/src/V3Waiver.cpp @@ -19,6 +19,7 @@ #include "V3Waiver.h" #include "V3File.h" +#include "V3Options.h" #include #include @@ -26,6 +27,7 @@ void V3Waiver::addEntry(V3ErrorCode errorCode, const std::string& filename, const std::string& str) VL_MT_SAFE_EXCLUDES(s_mutex) { const VerilatedLockGuard lock{s_mutex}; + if (filename == V3Options::getStdPackagePath()) return; std::stringstream entry; const size_t pos = str.find('\n'); entry << "lint_off -rule " << errorCode.ascii() << " -file \"*" << filename << "\" -match \"" From 2530cda5079af4ec2c2aa91f2fd165642cb8568d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 6 Apr 2023 21:43:39 -0400 Subject: [PATCH 110/155] Fix debug crash when no std:: used --- src/V3Global.cpp | 18 ++++++++++-------- src/V3Global.h | 1 + src/Verilator.cpp | 1 + 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/V3Global.cpp b/src/V3Global.cpp index a9300eaf3..82dd6e584 100644 --- a/src/V3Global.cpp +++ b/src/V3Global.cpp @@ -77,14 +77,6 @@ void V3Global::readFiles() { "Cannot find file containing library module: "); } - // Delete the std package if unused - if (!usesStdPackage()) { - if (AstNodeModule* stdp = v3Global.rootp()->stdPackagep()) { - v3Global.rootp()->stdPackagep(nullptr); - VL_DO_DANGLING(stdp->unlinkFrBack()->deleteTree(), stdp); - } - } - // v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("parse.tree")); V3Error::abortIfErrors(); @@ -94,6 +86,16 @@ void V3Global::readFiles() { } } +void V3Global::removeStd() { + // Delete the std package if unused + if (!usesStdPackage()) { + if (AstNodeModule* stdp = v3Global.rootp()->stdPackagep()) { + v3Global.rootp()->stdPackagep(nullptr); + VL_DO_DANGLING(stdp->unlinkFrBack()->deleteTree(), stdp); + } + } +} + string V3Global::debugFilename(const string& nameComment, int newNumber) { ++m_debugFileNumber; if (newNumber) m_debugFileNumber = newNumber; diff --git a/src/V3Global.h b/src/V3Global.h index db6dc04ba..fcb4b7e20 100644 --- a/src/V3Global.h +++ b/src/V3Global.h @@ -135,6 +135,7 @@ public: // METHODS void readFiles(); + void removeStd(); void checkTree() const; static void dumpCheckGlobalTree(const string& stagename, int newNumber = 0, bool doDump = true); diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 7ee1fb9e1..65acb5a6f 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -618,6 +618,7 @@ static void verilate(const string& argString) { // Read first filename v3Global.readFiles(); + v3Global.removeStd(); // Link, etc, if needed if (!v3Global.opt.preprocOnly()) { // From 827cbf22c991510eef0ad4e9e5ccac39694bdd31 Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Fri, 7 Apr 2023 13:23:37 +0200 Subject: [PATCH 111/155] Fix sense expression variable naming (#4081) --- src/V3SenExprBuilder.h | 23 ++++---- test_regress/t/t_event_control_scope_var.pl | 22 ++++++++ test_regress/t/t_event_control_scope_var.v | 61 +++++++++++++++++++++ test_regress/t/t_protect_ids_key.out | 2 +- test_regress/t/t_xml_debugcheck.out | 10 ++-- 5 files changed, 99 insertions(+), 19 deletions(-) create mode 100755 test_regress/t/t_event_control_scope_var.pl create mode 100644 test_regress/t/t_event_control_scope_var.v diff --git a/src/V3SenExprBuilder.h b/src/V3SenExprBuilder.h index 6b70e7d23..86b09d03f 100644 --- a/src/V3SenExprBuilder.h +++ b/src/V3SenExprBuilder.h @@ -94,24 +94,21 @@ class SenExprBuilder final { const auto rdCurr = [=]() { return getCurr(exprp); }; AstNode* scopeExprp = exprp; - if (AstVarRef* const refp = VN_CAST(exprp, VarRef)) { - scopeExprp = refp->varScopep()->varp(); - } + if (AstVarRef* const refp = VN_CAST(exprp, VarRef)) scopeExprp = refp->varScopep(); // Create the 'previous value' variable auto it = m_prev.find(*scopeExprp); if (it == m_prev.end()) { - // For readability, use the scoped signal name if the trigger is a simple AstVarRef - string name; - if (AstVarRef* const refp = VN_CAST(exprp, VarRef)) { - AstVarScope* vscp = refp->varScopep(); - name = "__Vtrigrprev__" + vscp->scopep()->nameDotless() + "__" - + vscp->varp()->name(); - } else { - name = m_prevNames.get(exprp); - } - AstVarScope* prevp; if (m_scopep->isTop()) { + // For readability, use the scoped signal name if the trigger is a simple AstVarRef + string name; + if (AstVarRef* const refp = VN_CAST(exprp, VarRef)) { + AstVarScope* const vscp = refp->varScopep(); + name = "__" + vscp->scopep()->nameDotless() + "__" + vscp->varp()->name(); + name = m_prevNames.get(name); + } else { + name = m_prevNames.get(exprp); + } prevp = m_scopep->createTemp(name, exprp->dtypep()); } else { AstVar* const varp = new AstVar{flp, VVarType::BLOCKTEMP, m_prevNames.get(exprp), diff --git a/test_regress/t/t_event_control_scope_var.pl b/test_regress/t/t_event_control_scope_var.pl new file mode 100755 index 000000000..d78b3ff03 --- /dev/null +++ b/test_regress/t/t_event_control_scope_var.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 2003 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); + +compile( + verilator_flags2 => ['-fno-inline', '-Wno-WIDTHTRUNC'], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_event_control_scope_var.v b/test_regress/t/t_event_control_scope_var.v new file mode 100644 index 000000000..e976b1c60 --- /dev/null +++ b/test_regress/t/t_event_control_scope_var.v @@ -0,0 +1,61 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module test_mod(input reg clk, input reg reset, output integer result); + always @(reset) begin + result <= 1; + end +endmodule + +module Dut(input clk); + integer num; + integer result1; + integer result2; + reg reset1; + reg reset2; + initial begin + reset1 = $random; + reset2 = $random; + end + always @(posedge clk) begin + num <= num + 1; + if (num == 5) begin + reset1 <= 1'b1; + end + if (num == 10) begin + // display to prevent optimalization + $display("result1: %d", result1); + $display("result2: %d", result2); + $write("*-* All Finished *-*\n"); + $finish; + end + end + always @(reset1) begin + reset2 <= t.reset; + end + + test_mod t ( + .clk(clk), + .reset(reset1), + .result(result1) + ); + test_mod t2 ( + .clk(clk), + .reset(reset2), + .result(result2)); + endmodule + +module Dut_wrapper(input clk); + + Dut d(.clk(clk)); + Dut d2(.clk(clk)); +endmodule + +module t (/*AUTOARG*/ + clk); + input clk; + Dut_wrapper d_w(.clk(clk)); +endmodule diff --git a/test_regress/t/t_protect_ids_key.out b/test_regress/t/t_protect_ids_key.out index 5f362ac43..117c4a728 100644 --- a/test_regress/t/t_protect_ids_key.out +++ b/test_regress/t/t_protect_ids_key.out @@ -28,7 +28,7 @@ - + diff --git a/test_regress/t/t_xml_debugcheck.out b/test_regress/t/t_xml_debugcheck.out index ff409ca14..e99f614c6 100644 --- a/test_regress/t/t_xml_debugcheck.out +++ b/test_regress/t/t_xml_debugcheck.out @@ -22,7 +22,7 @@ - + @@ -49,7 +49,7 @@ - + @@ -607,7 +607,7 @@ - + @@ -618,7 +618,7 @@ - + @@ -1688,7 +1688,7 @@ - + From d67d75282c8550e7f5ac24a344517523f2d9e594 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 7 Apr 2023 20:57:17 -0400 Subject: [PATCH 112/155] Support ++/-- on dotted member variables. --- Changes | 1 + src/V3LinkInc.cpp | 23 ++++---- test_regress/t/t_class_inc.pl | 21 +++++++ test_regress/t/t_class_inc.v | 37 +++++++++++++ test_regress/t/t_increment_bad.out | 3 - test_regress/t/t_math_real.v | 10 ++++ test_regress/t/t_math_wide_inc.pl | 21 +++++++ test_regress/t/t_math_wide_inc.v | 89 ++++++++++++++++++++++++++++++ 8 files changed, 191 insertions(+), 14 deletions(-) create mode 100755 test_regress/t/t_class_inc.pl create mode 100644 test_regress/t/t_class_inc.v create mode 100755 test_regress/t/t_math_wide_inc.pl create mode 100644 test_regress/t/t_math_wide_inc.v diff --git a/Changes b/Changes index 7ad1c2e30..52905d12a 100644 --- a/Changes +++ b/Changes @@ -22,6 +22,7 @@ Verilator 5.009 devel * Support method calls without parenthesis (#4034). [Ryszard Rozak, Antmicro Ltd] * Support complicated IEEE 'for' assignments. * Support $fopen as an expression. +* Support ++/-- on dotted member variables. * Change range order warning from LITENDIAN to ASCRANGE (#4010). [Iztok Jeras] * Change ZERODLY to a warning. * Fix random internal crashes (#666). [Dag Lem] diff --git a/src/V3LinkInc.cpp b/src/V3LinkInc.cpp index ac89c57ee..e420d1276 100644 --- a/src/V3LinkInc.cpp +++ b/src/V3LinkInc.cpp @@ -240,11 +240,12 @@ private: return; } - const AstNodeVarRef* varrefp = nullptr; - if (m_unsupportedHere || !(varrefp = VN_CAST(nodep->rhsp(), VarRef))) { + if (m_unsupportedHere) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: Incrementation in this context."); return; } + AstNodeExpr* const readp = nodep->rhsp(); + AstNodeExpr* const writep = nodep->thsp(); AstConst* const constp = VN_AS(nodep->lhsp(), Const); UASSERT_OBJ(nodep, constp, "Expecting CONST"); @@ -254,8 +255,9 @@ private: // Prepare a temporary variable FileLine* const fl = backp->fileline(); const string name = string{"__Vincrement"} + cvtToStr(++m_modIncrementsNum); - AstVar* const varp = new AstVar{fl, VVarType::BLOCKTEMP, name, VFlagChildDType{}, - varrefp->varp()->subDTypep()->cloneTree(true)}; + AstVar* const varp = new AstVar{ + fl, VVarType::BLOCKTEMP, name, VFlagChildDType{}, + new AstRefDType{fl, AstRefDType::FlagTypeOfExpr{}, readp->cloneTree(true)}}; if (m_ftaskp) varp->funcLocal(true); // Declare the variable @@ -264,30 +266,29 @@ private: // Define what operation will we be doing AstNodeExpr* operp; if (VN_IS(nodep, PostSub) || VN_IS(nodep, PreSub)) { - operp = new AstSub{fl, new AstVarRef{fl, varrefp->varp(), VAccess::READ}, newconstp}; + operp = new AstSub{fl, readp->cloneTree(true), newconstp}; } else { - operp = new AstAdd{fl, new AstVarRef{fl, varrefp->varp(), VAccess::READ}, newconstp}; + operp = new AstAdd{fl, readp->cloneTree(true), newconstp}; } if (VN_IS(nodep, PreAdd) || VN_IS(nodep, PreSub)) { // PreAdd/PreSub operations // Immediately after declaration - increment it by one - varp->addNextHere(new AstAssign{fl, new AstVarRef{fl, varrefp->varp(), VAccess::WRITE}, + varp->addNextHere(new AstAssign{fl, writep->cloneTree(true), new AstVarRef{fl, varp, VAccess::READ}}); // Immediately after incrementing - assign it to the original variable varp->addNextHere(new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, operp}); } else { // PostAdd/PostSub operations // assign the original variable to the temporary one - varp->addNextHere( - new AstAssign{fl, new AstVarRef{fl, varrefp->varp(), VAccess::WRITE}, operp}); + varp->addNextHere(new AstAssign{fl, writep->cloneTree(true), operp}); // Increment the original variable by one varp->addNextHere(new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, - new AstVarRef{fl, varrefp->varp(), VAccess::READ}}); + readp->cloneTree(true)}); } // Replace the node with the temporary - nodep->replaceWith(new AstVarRef{varrefp->fileline(), varp, VAccess::READ}); + nodep->replaceWith(new AstVarRef{readp->fileline(), varp, VAccess::READ}); VL_DO_DANGLING(nodep->deleteTree(), nodep); } void visit(AstPreAdd* nodep) override { prepost_visit(nodep); } diff --git a/test_regress/t/t_class_inc.pl b/test_regress/t/t_class_inc.pl new file mode 100755 index 000000000..859050d63 --- /dev/null +++ b/test_regress/t/t_class_inc.pl @@ -0,0 +1,21 @@ +#!/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); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_inc.v b/test_regress/t/t_class_inc.v new file mode 100644 index 000000000..446df0c3f --- /dev/null +++ b/test_regress/t/t_class_inc.v @@ -0,0 +1,37 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Base #(type T = integer); + T m_count; + + function void test1(); + if (this.m_count != 0) $stop; + if (this.m_count++ != 0) $stop; + if (this.m_count != 1) $stop; + if (m_count++ != 1) $stop; + if (this.m_count != 2) $stop; + endfunction +endclass + +class Cls #(type T = integer) extends Base #(T); +endclass + +module t; + Cls #(int) c; + + initial begin + c = new; + c.test1(); + + c.m_count = 0; + if (c.m_count != 0) $stop; + if (c.m_count++ != 0) $stop; + if (c.m_count != 1) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_increment_bad.out b/test_regress/t/t_increment_bad.out index 026148082..08749d938 100644 --- a/test_regress/t/t_increment_bad.out +++ b/test_regress/t/t_increment_bad.out @@ -17,9 +17,6 @@ %Error-UNSUPPORTED: t/t_increment_bad.v:27:29: Unsupported: Incrementation in this context. 27 | pos = (a > 0) ? a++ : --b; | ^~ -%Error-UNSUPPORTED: t/t_increment_bad.v:29:24: Unsupported: Incrementation in this context. - 29 | pos = array[0][0]++; - | ^~ %Error-UNSUPPORTED: t/t_increment_bad.v:32:37: Unsupported: Incrementation in this context. 32 | assert property (@(posedge clk) a++ >= 0); | ^~ diff --git a/test_regress/t/t_math_real.v b/test_regress/t/t_math_real.v index 8798f1cdb..661837d61 100644 --- a/test_regress/t/t_math_real.v +++ b/test_regress/t/t_math_real.v @@ -138,6 +138,16 @@ module t (/*AUTOARG*/ r = real'(96'shf0000000_00000000_00000000); if (r != -4951760157141521099596496896.0) $stop; + r = 1.5; + if (r++ != 1.5) $stop; + if (r != 2.5) $stop; + if (r-- != 2.5) $stop; + if (r != 1.5) $stop; + if (++r != 2.5) $stop; + if (r != 2.5) $stop; + if (--r != 1.5) $stop; + if (r != 1.5) $stop; + r = 1.23456; s = $sformatf("%g", r); `checks(s, "1.23456"); diff --git a/test_regress/t/t_math_wide_inc.pl b/test_regress/t/t_math_wide_inc.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_math_wide_inc.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 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); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_math_wide_inc.v b/test_regress/t/t_math_wide_inc.v new file mode 100644 index 000000000..1d62ca03f --- /dev/null +++ b/test_regress/t/t_math_wide_inc.v @@ -0,0 +1,89 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// 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 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer i; + reg [6:0] w7; + reg [14:0] w15; + reg [30:0] w31; + reg [62:0] w63; + reg [94:0] w95; + + integer cyc = 0; + + // Test loop + always @ (posedge clk) begin +`ifdef TEST_VERBOSE + $write("[%0t] cyc==%0d\n", $time, cyc); +`endif + cyc <= cyc + 1; + if (cyc==0) begin + // Setup + w7 = {7{1'b1}}; + w15 = {15{1'b1}}; + w31 = {31{1'b1}}; + w63 = {63{1'b1}}; + w95 = {95{1'b1}}; + end + else if (cyc == 1) begin + if (w7++ != {7{1'b1}}) $stop; + if (w7 != {7{1'b0}}) $stop; + if (w7-- != {7{1'b0}}) $stop; + if (w7 != {7{1'b1}}) $stop; + if (++w7 != {7{1'b0}}) $stop; + if (w7 != {7{1'b0}}) $stop; + if (--w7 != {7{1'b1}}) $stop; + if (w7 != {7{1'b1}}) $stop; + + if (w15++ != {15{1'b1}}) $stop; + if (w15 != {15{1'b0}}) $stop; + if (w15-- != {15{1'b0}}) $stop; + if (w15 != {15{1'b1}}) $stop; + if (++w15 != {15{1'b0}}) $stop; + if (w15 != {15{1'b0}}) $stop; + if (--w15 != {15{1'b1}}) $stop; + if (w15 != {15{1'b1}}) $stop; + + if (w31++ != {31{1'b1}}) $stop; + if (w31 != {31{1'b0}}) $stop; + if (w31-- != {31{1'b0}}) $stop; + if (w31 != {31{1'b1}}) $stop; + if (++w31 != {31{1'b0}}) $stop; + if (w31 != {31{1'b0}}) $stop; + if (--w31 != {31{1'b1}}) $stop; + if (w31 != {31{1'b1}}) $stop; + + if (w63++ != {63{1'b1}}) $stop; + if (w63 != {63{1'b0}}) $stop; + if (w63-- != {63{1'b0}}) $stop; + if (w63 != {63{1'b1}}) $stop; + if (++w63 != {63{1'b0}}) $stop; + if (w63 != {63{1'b0}}) $stop; + if (--w63 != {63{1'b1}}) $stop; + if (w63 != {63{1'b1}}) $stop; + + if (w95++ != {95{1'b1}}) $stop; + if (w95 != {95{1'b0}}) $stop; + if (w95-- != {95{1'b0}}) $stop; + if (w95 != {95{1'b1}}) $stop; + if (++w95 != {95{1'b0}}) $stop; + if (w95 != {95{1'b0}}) $stop; + if (--w95 != {95{1'b1}}) $stop; + if (w95 != {95{1'b1}}) $stop; + end + else if (cyc==99) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule From 13a87e551419a1e0b683ad42794980b53441bdbb Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 8 Apr 2023 15:04:42 -0400 Subject: [PATCH 113/155] Parse process class, and report runtime errors (#3612) --- include/verilated_std.sv | 41 ++++++++++++++++++++++++++ test_regress/driver.pl | 1 + test_regress/t/t_dist_warn_coverage.pl | 2 ++ test_regress/t/t_process.out | 27 ++--------------- test_regress/t/t_process.pl | 8 ++--- test_regress/t/t_process_bad.out | 18 +++++------ test_regress/t/t_process_std.out | 27 ++--------------- test_regress/t/t_process_std.pl | 8 ++--- 8 files changed, 67 insertions(+), 65 deletions(-) diff --git a/include/verilated_std.sv b/include/verilated_std.sv index 354901753..9a1153c76 100644 --- a/include/verilated_std.sv +++ b/include/verilated_std.sv @@ -115,4 +115,45 @@ package std; return 0; endfunction endclass + + class process; + typedef enum { FINISHED, RUNNING, WAITING, SUSPENDED, KILLED } state; + static process _s_global_process; + static function process self(); + // Unsupported, emulating with single process' state + if (!_s_global_process) _s_global_process = new; + return _s_global_process; + endfunction + function state status(); + // Unsupported, emulating with single process' state + return RUNNING; + endfunction + function void kill(); + $error("std::process::kill() not supported"); + endfunction + task await(); + $error("std::process::await() not supported"); + endtask + function void suspend(); + $error("std::process::suspend() not supported"); + endfunction + function void resume(); + $error("std::process::resume() not supported"); + endfunction + // When really implemented, srandom must operates on the process, but for + // now rely on the srandom() that is automatically generated for all + // classes. + // function void srandom(int seed); + // endfunction + function string get_randstate(); + // Could operate on all proceses for now + // No error, as harmless until set_randstate is called + return "NOT_SUPPORTED"; + endfunction + function void set_randstate(string randstate); + $error("std::process::set_randstate() not supported"); + // Could operate on all proceses for now + endfunction + endclass + endpackage diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 2a1685e4e..6bf8240c8 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -2227,6 +2227,7 @@ sub files_identical { $l1[$l] =~ s/CPU Time: +[0-9.]+ seconds[^\n]+/CPU Time: ###/mig; $l1[$l] =~ s/\?v=[0-9.]+/?v=latest/mig; # warning URL $l1[$l] =~ s/_h[0-9a-f]{8}_/_h########_/mg; + $l1[$l] =~ s/ \/[^ ]+\/verilated_std.sv/ verilated_std.sv/mg; if ($l1[$l] =~ s/Exiting due to.*/Exiting due to/mig) { splice @l1, $l+1; # Trunc rest last; diff --git a/test_regress/t/t_dist_warn_coverage.pl b/test_regress/t/t_dist_warn_coverage.pl index 4646bb95e..234e2bce3 100755 --- a/test_regress/t/t_dist_warn_coverage.pl +++ b/test_regress/t/t_dist_warn_coverage.pl @@ -42,6 +42,7 @@ foreach my $s ( 'Assignment pattern with no members', 'Assignment pattern with too many elements', 'Attempted parameter setting of non-parameter: Param ', + 'Can\'t find typedef: ', 'Can\'t find varpin scope of ', 'Can\'t resolve module reference: \'', 'Cannot mix DPI import, DPI export, class methods, and/or public ', @@ -52,6 +53,7 @@ foreach my $s ( 'Exceeded limit of ', 'Extern declaration\'s scope is not a defined class', 'Format to $display-like function must have constant format string', + 'Forward typedef used as class/package does not resolve to class/package: ', 'Illegal +: or -: select; type already selected, or bad dimension: ', 'Illegal bit or array select; type already selected, or bad dimension: ', 'Illegal range select; type already selected, or bad dimension: ', diff --git a/test_regress/t/t_process.out b/test_regress/t/t_process.out index 74d069569..ab04bc4e8 100644 --- a/test_regress/t/t_process.out +++ b/test_regress/t/t_process.out @@ -1,24 +1,3 @@ -%Error: t/t_process.v:26:11: Forward typedef used as class/package does not resolve to class/package: 'process' - 26 | p = process::self(); - | ^~~~~~~ -%Error: t/t_process.v:27:25: Forward typedef used as class/package does not resolve to class/package: 'process' - 27 | if (p.status() != process::RUNNING) $stop; - | ^~~~~~~ -%Error: t/t_process.v:28:25: Forward typedef used as class/package does not resolve to class/package: 'process' - 28 | if (p.status() == process::WAITING) $stop; - | ^~~~~~~ -%Error: t/t_process.v:29:25: Forward typedef used as class/package does not resolve to class/package: 'process' - 29 | if (p.status() == process::SUSPENDED) $stop; - | ^~~~~~~ -%Error: t/t_process.v:30:25: Forward typedef used as class/package does not resolve to class/package: 'process' - 30 | if (p.status() == process::KILLED) $stop; - | ^~~~~~~ -%Error: t/t_process.v:31:25: Forward typedef used as class/package does not resolve to class/package: 'process' - 31 | if (p.status() == process::FINISHED) $stop; - | ^~~~~~~ -%Error: t/t_process.v:22:4: Can't find typedef: 'process' - 22 | process p; - | ^~~~~~~ -%Error: Internal Error: t/t_process.v:26:11: ../V3LinkDot.cpp:#: Bad package link - 26 | p = process::self(); - | ^~~~~~~ +[0] %Error: verilated_std.sv:154: Assertion failed in top.std.process.set_randstate: std::process::set_randstate() not supported +%Error: verilated_std.sv:154: Verilog $stop +Aborting... diff --git a/test_regress/t/t_process.pl b/test_regress/t/t_process.pl index 2ad4a887d..39ea187ff 100755 --- a/test_regress/t/t_process.pl +++ b/test_regress/t/t_process.pl @@ -11,13 +11,13 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, ); execute( - check_finished => 1, - ) if !$Self->{vlt_all}; + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + check_finished => !$Self->{vlt_all}, + ); ok(1); 1; diff --git a/test_regress/t/t_process_bad.out b/test_regress/t/t_process_bad.out index 3e6f927d1..0c696d1d4 100644 --- a/test_regress/t/t_process_bad.out +++ b/test_regress/t/t_process_bad.out @@ -1,9 +1,9 @@ -%Error: t/t_process_bad.v:12:11: Forward typedef used as class/package does not resolve to class/package: 'process' - 12 | p = process::self(); - | ^~~~~~~ -%Error: t/t_process_bad.v:8:4: Can't find typedef: 'process' - 8 | process p; - | ^~~~~~~ -%Error: Internal Error: t/t_process_bad.v:12:11: ../V3LinkDot.cpp:#: Bad package link - 12 | p = process::self(); - | ^~~~~~~ +%Error: t/t_process_bad.v:13:13: Class method 'bad_method' not found in class 'process' + : ... In instance t + 13 | if (p.bad_method() != 0) $stop; + | ^~~~~~~~~~ +%Error: t/t_process_bad.v:15:9: Class method 'bad_method_2' not found in class 'process' + : ... In instance t + 15 | p.bad_method_2(); + | ^~~~~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_process_std.out b/test_regress/t/t_process_std.out index 74d069569..ab04bc4e8 100644 --- a/test_regress/t/t_process_std.out +++ b/test_regress/t/t_process_std.out @@ -1,24 +1,3 @@ -%Error: t/t_process.v:26:11: Forward typedef used as class/package does not resolve to class/package: 'process' - 26 | p = process::self(); - | ^~~~~~~ -%Error: t/t_process.v:27:25: Forward typedef used as class/package does not resolve to class/package: 'process' - 27 | if (p.status() != process::RUNNING) $stop; - | ^~~~~~~ -%Error: t/t_process.v:28:25: Forward typedef used as class/package does not resolve to class/package: 'process' - 28 | if (p.status() == process::WAITING) $stop; - | ^~~~~~~ -%Error: t/t_process.v:29:25: Forward typedef used as class/package does not resolve to class/package: 'process' - 29 | if (p.status() == process::SUSPENDED) $stop; - | ^~~~~~~ -%Error: t/t_process.v:30:25: Forward typedef used as class/package does not resolve to class/package: 'process' - 30 | if (p.status() == process::KILLED) $stop; - | ^~~~~~~ -%Error: t/t_process.v:31:25: Forward typedef used as class/package does not resolve to class/package: 'process' - 31 | if (p.status() == process::FINISHED) $stop; - | ^~~~~~~ -%Error: t/t_process.v:22:4: Can't find typedef: 'process' - 22 | process p; - | ^~~~~~~ -%Error: Internal Error: t/t_process.v:26:11: ../V3LinkDot.cpp:#: Bad package link - 26 | p = process::self(); - | ^~~~~~~ +[0] %Error: verilated_std.sv:154: Assertion failed in top.std.process.set_randstate: std::process::set_randstate() not supported +%Error: verilated_std.sv:154: Verilog $stop +Aborting... diff --git a/test_regress/t/t_process_std.pl b/test_regress/t/t_process_std.pl index 0c23347b2..64cabbccb 100755 --- a/test_regress/t/t_process_std.pl +++ b/test_regress/t/t_process_std.pl @@ -14,13 +14,13 @@ top_filename("t/t_process.v"); compile( v_flags2 => ["+define+T_PROCESS+std::process"], + ); + +execute( + check_finished => !$Self->{vlt_all}, fails => $Self->{vlt_all}, expect_filename => $Self->{golden_filename}, ); -execute( - check_finished => 1, - ) if !$Self->{vlt_all}; - ok(1); 1; From 114d93b21243fd7200b8da3412074bc2a37f3eea Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 8 Apr 2023 15:11:26 -0400 Subject: [PATCH 114/155] Internals: Move -debug-exit-uvm to post V3LinkDot, just before V3Param (#1538) --- src/Verilator.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 65acb5a6f..785553361 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -125,12 +125,6 @@ static void process() { // Convert parseref's to varrefs, and other directly post parsing fixups V3LinkParse::linkParse(v3Global.rootp()); - if (v3Global.opt.debugExitUvm()) { - V3Error::abortIfErrors(); - cout << "--debug-exit-uvm: Exiting after UVM-supported pass\n"; - std::exit(0); - } - // Cross-link signal names // Cross-link dotted hierarchical references V3LinkDot::linkDotPrimary(v3Global.rootp()); @@ -148,6 +142,11 @@ static void process() { V3Error::abortIfErrors(); if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "Link"); + if (v3Global.opt.debugExitUvm()) { + V3Error::abortIfErrors(); + cout << "--debug-exit-uvm: Exiting after UVM-supported pass\n"; + std::exit(0); + } // Remove parameters by cloning modules to de-parameterized versions // This requires some width calculations and constant propagation From 7ae0c5d546c403290bab39e025709d680137ddc0 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 8 Apr 2023 21:36:32 -0400 Subject: [PATCH 115/155] Internals: cppcheck fixes. No functional change intended --- include/verilated_types.h | 2 +- src/V3CCtors.cpp | 1 + src/V3LinkLevel.cpp | 2 +- src/V3Width.cpp | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/verilated_types.h b/include/verilated_types.h index 5cc66b1ea..940aeafe9 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -151,7 +151,7 @@ public: // having to check for construction at each call // Alternative: seed with zero and check on rand64() call VlRNG() VL_MT_SAFE; - VlRNG(uint64_t seed0) VL_MT_SAFE : m_state{0x12341234UL, seed0} {} + explicit VlRNG(uint64_t seed0) VL_MT_SAFE : m_state{0x12341234UL, seed0} {} void srandom(uint64_t n) VL_MT_UNSAFE; // Unused: std::string get_randstate() const VL_MT_UNSAFE; // Unused: void set_randstate(const std::string& state) VL_MT_UNSAFE; diff --git a/src/V3CCtors.cpp b/src/V3CCtors.cpp index bfe88f481..a079006ec 100644 --- a/src/V3CCtors.cpp +++ b/src/V3CCtors.cpp @@ -148,6 +148,7 @@ private: m_modp = nodep; V3CCtorsBuilder var_reset{nodep, "_ctor_var_reset", VN_IS(nodep, Class) ? VCtorType::CLASS : VCtorType::MODULE}; + // cppcheck-suppress danglingLifetime m_varResetp = &var_reset; iterateChildren(nodep); diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp index 9718b9b67..11fffed29 100644 --- a/src/V3LinkLevel.cpp +++ b/src/V3LinkLevel.cpp @@ -59,7 +59,7 @@ void V3LinkLevel::modSortByLevel() { if (tops.size() >= 2) { const AstNode* const secp = tops[1]; // Complain about second one, as first often intended if (!secp->fileline()->warnIsOff(V3ErrorCode::MULTITOP)) { - auto warnTopModules = [](std::string warnMore, ModVec tops) + auto warnTopModules = [](const std::string& warnMore, ModVec tops) VL_REQUIRES(V3Error::s().m_mutex) -> std::string { std::stringstream ss; for (AstNode* alsop : tops) { diff --git a/src/V3Width.cpp b/src/V3Width.cpp index bb5e25edb..962af7e9f 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -3798,7 +3798,7 @@ private: } // The AstNodeAssign visitor will be soon be replacing this node, make sure it gets it if (!VN_IS(nodep->backp(), NodeAssign)) { - if (adtypep) UINFO(1, "Got backp " << nodep->backp() << endl); + UINFO(1, "Got backp " << nodep->backp() << endl); nodep->v3error( "dynamic new() not expected in this context (expected under an assign)"); return; From fff0eb5d88c851496f05e6368e164dfbc9c2f5ed Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 8 Apr 2023 22:11:28 -0400 Subject: [PATCH 116/155] Internals: Use standard 'result' name for return variable. No functional change. --- include/verilated.cpp | 46 +++++++++++------------ include/verilated_cov.cpp | 6 +-- include/verilated_funcs.h | 8 ++-- src/V3AstNodes.cpp | 6 +-- src/V3File.cpp | 12 +++--- src/V3FileLine.cpp | 8 ++-- src/V3Options.cpp | 8 ++-- src/V3Os.cpp | 10 ++--- src/V3PreLex.l | 8 ++-- src/V3String.cpp | 78 +++++++++++++++++++-------------------- src/V3String.h | 6 +-- 11 files changed, 98 insertions(+), 98 deletions(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index 26f9e32fa..63affb724 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -232,9 +232,9 @@ std::string _vl_string_vprintf(const char* formatp, va_list ap) VL_MT_SAFE { char* const bufp = new char[len + 1]; VL_VSNPRINTF(bufp, len + 1, formatp, ap); - std::string out{bufp, len}; // Not const to allow move optimization + std::string result{bufp, len}; // Not const to allow move optimization delete[] bufp; - return out; + return result; } uint64_t _vl_dbg_sequence_number() VL_MT_SAFE { @@ -255,24 +255,24 @@ void VL_DBG_MSGF(const char* formatp, ...) VL_MT_SAFE { // includes that otherwise would be required in every Verilated module va_list ap; va_start(ap, formatp); - const std::string out = _vl_string_vprintf(formatp, ap); + const std::string result = _vl_string_vprintf(formatp, ap); va_end(ap); // printf("-imm-V{t%d,%" PRId64 "}%s", VL_THREAD_ID(), _vl_dbg_sequence_number(), - // out.c_str()); + // result.c_str()); // Using VL_PRINTF not VL_PRINTF_MT so that we can call VL_DBG_MSGF // from within the guts of the thread execution machinery (and it goes // to the screen and not into the queues we're debugging) - VL_PRINTF("-V{t%u,%" PRIu64 "}%s", VL_THREAD_ID(), _vl_dbg_sequence_number(), out.c_str()); + VL_PRINTF("-V{t%u,%" PRIu64 "}%s", VL_THREAD_ID(), _vl_dbg_sequence_number(), result.c_str()); } void VL_PRINTF_MT(const char* formatp, ...) VL_MT_SAFE { va_list ap; va_start(ap, formatp); - const std::string out = _vl_string_vprintf(formatp, ap); + const std::string result = _vl_string_vprintf(formatp, ap); va_end(ap); VerilatedThreadMsgQueue::post(VerilatedMsg{[=]() { // - VL_PRINTF("%s", out.c_str()); + VL_PRINTF("%s", result.c_str()); }}); } @@ -321,8 +321,8 @@ void VlRNG::srandom(uint64_t n) VL_MT_UNSAFE { // Unused: } // Unused: } // Unused: std::string VlRNG::get_randstate() const VL_MT_UNSAFE { -// Unused: std::string out{reinterpret_cast(&m_state), sizeof(m_state)}; -// Unused: return out; +// Unused: std::string result{reinterpret_cast(&m_state), sizeof(m_state)}; +// Unused: return result; // Unused: } static uint32_t vl_sys_rand32() VL_MT_SAFE { @@ -566,12 +566,12 @@ QData VL_POW_QQW(int, int, int rbits, QData lhs, const WDataInP rwp) VL_MT_SAFE // Skip check for rhs == 0, as short-circuit doesn't save time if (VL_UNLIKELY(lhs == 0)) return 0; QData power = lhs; - QData out = 1ULL; + QData result = 1ULL; for (int bit = 0; bit < rbits; ++bit) { if (bit > 0) power = power * power; - if (VL_BITISSET_W(rwp, bit)) out *= power; + if (VL_BITISSET_W(rwp, bit)) result *= power; } - return out; + return result; } WDataOutP VL_POWSS_WWW(int obits, int, int rbits, WDataOutP owp, const WDataInP lwp, @@ -1699,15 +1699,15 @@ std::string VL_STACKTRACE_N() VL_MT_SAFE { // cppcheck-suppress knownConditionTrueFalse if (!strings) return "Unable to backtrace\n"; - std::string out = "Backtrace:\n"; - for (int j = 0; j < nptrs; j++) out += std::string{strings[j]} + std::string{"\n"}; + std::string result = "Backtrace:\n"; + for (int j = 0; j < nptrs; j++) result += std::string{strings[j]} + std::string{"\n"}; free(strings); - return out; + return result; } void VL_STACKTRACE() VL_MT_SAFE { - const std::string out = VL_STACKTRACE_N(); - VL_PRINTF("%s", out.c_str()); + const std::string result = VL_STACKTRACE_N(); + VL_PRINTF("%s", result.c_str()); } IData VL_SYSTEM_IQ(QData lhs) VL_MT_SAFE { @@ -1853,14 +1853,14 @@ std::string VL_TO_STRING_W(int words, const WDataInP obj) { } std::string VL_TOLOWER_NN(const std::string& ld) VL_PURE { - std::string out = ld; - for (auto& cr : out) cr = std::tolower(cr); - return out; + std::string result = ld; + for (auto& cr : result) cr = std::tolower(cr); + return result; } std::string VL_TOUPPER_NN(const std::string& ld) VL_PURE { - std::string out = ld; - for (auto& cr : out) cr = std::toupper(cr); - return out; + std::string result = ld; + for (auto& cr : result) cr = std::toupper(cr); + return result; } std::string VL_CVT_PACK_STR_NW(int lwords, const WDataInP lwp) VL_PURE { diff --git a/include/verilated_cov.cpp b/include/verilated_cov.cpp index 23953173c..7ed7e0031 100644 --- a/include/verilated_cov.cpp +++ b/include/verilated_cov.cpp @@ -208,11 +208,11 @@ private: // Forward to . so we have a whole word const std::string suffix = *bpost ? std::string{bpost + 1} : ""; - std::string out = prefix + "*" + suffix; + std::string result = prefix + "*" + suffix; // cout << "\nch pre="<parent()) { if (parentFl->filenameIsGlobal()) break; - out += parentFl->warnOther() + "... note: In file included from " - + parentFl->filebasename() + "\n"; + result += parentFl->warnOther() + "... note: In file included from " + + parentFl->filebasename() + "\n"; } - return out; + return result; } #ifdef VL_LEAK_CHECKS std::unordered_set fileLineLeakChecks; diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 31d37e4b9..7227ae1ba 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -395,12 +395,12 @@ void V3Options::addForceInc(const string& filename) { m_forceIncs.push_back(file void V3Options::addArg(const string& arg) { m_impp->m_allArgs.push_back(arg); } string V3Options::allArgsString() const VL_MT_SAFE { - string out; + string result; for (const string& i : m_impp->m_allArgs) { - if (out != "") out += " "; - out += i; + if (result != "") result += " "; + result += i; } - return out; + return result; } // Delete some options for Verilation of the hierarchical blocks. diff --git a/src/V3Os.cpp b/src/V3Os.cpp index 377e3594f..9d2fd0918 100644 --- a/src/V3Os.cpp +++ b/src/V3Os.cpp @@ -161,7 +161,7 @@ string V3Os::filenameNonExt(const string& filename) VL_PURE { } string V3Os::filenameSubstitute(const string& filename) { - string out; + string result; // cppcheck-has-bug-suppress unusedLabel enum : uint8_t { NONE, PAREN, CURLY } brackets = NONE; for (string::size_type pos = 0; pos < filename.length(); ++pos) { @@ -188,20 +188,20 @@ string V3Os::filenameSubstitute(const string& filename) { string envvalue; if (!envvar.empty()) envvalue = getenvStr(envvar, ""); if (!envvalue.empty()) { - out += envvalue; + result += envvalue; if (brackets == NONE) { pos = endpos; } else { pos = endpos + 1; } } else { - out += filename[pos]; // *pos == '$' + result += filename[pos]; // *pos == '$' } } else { - out += filename[pos]; + result += filename[pos]; } } - return out; + return result; } string V3Os::filenameRealPath(const string& filename) { diff --git a/src/V3PreLex.l b/src/V3PreLex.l index 3168f7025..4524374b4 100644 --- a/src/V3PreLex.l +++ b/src/V3PreLex.l @@ -720,11 +720,11 @@ void V3PreLex::dumpStack() { } string V3PreLex::cleanDbgStrg(const string& in) { - string out = in; + string result = in; string::size_type pos; - while ((pos = out.find('\n')) != string::npos) { out.replace(pos, 1, "\\n"); } - while ((pos = out.find('\r')) != string::npos) { out.replace(pos, 1, "\\r"); } - return out; + while ((pos = result.find('\n')) != string::npos) result.replace(pos, 1, "\\n"); + while ((pos = result.find('\r')) != string::npos) result.replace(pos, 1, "\\r"); + return result; } void V3PreLex::unused() { diff --git a/src/V3String.cpp b/src/V3String.cpp index b97a84b26..5dcf0f63d 100644 --- a/src/V3String.cpp +++ b/src/V3String.cpp @@ -79,24 +79,24 @@ string VString::dot(const string& a, const string& dot, const string& b) { } string VString::downcase(const string& str) { - string out = str; - for (auto& cr : out) cr = std::tolower(cr); - return out; + string result = str; + for (char& cr : result) cr = std::tolower(cr); + return result; } string VString::upcase(const string& str) { - string out = str; - for (auto& cr : out) cr = std::toupper(cr); - return out; + string result = str; + for (char& cr : result) cr = std::toupper(cr); + return result; } string VString::quoteAny(const string& str, char tgt, char esc) { - string out; + string result; for (const char c : str) { - if (c == tgt) out += esc; - out += c; + if (c == tgt) result += esc; + result += c; } - return out; + return result; } string VString::quoteStringLiteralForShell(const string& str) { @@ -131,24 +131,24 @@ string VString::escapeStringForPath(const string& str) { } string VString::spaceUnprintable(const string& str) VL_PURE { - string out; + string result; for (const char c : str) { if (std::isprint(c)) { - out += c; + result += c; } else { - out += ' '; + result += ' '; } } - return out; + return result; } string VString::removeWhitespace(const string& str) { - string out; - out.reserve(str.size()); + string result; + result.reserve(str.size()); for (const char c : str) { - if (!std::isspace(c)) out += c; + if (!std::isspace(c)) result += c; } - return out; + return result; } bool VString::isWhitespace(const string& str) { @@ -331,34 +331,34 @@ void VHashSha256::finalize() { string VHashSha256::digestBinary() { finalize(); - string out; - out.reserve(32); + string result; + result.reserve(32); for (size_t i = 0; i < 32; ++i) { - out += (m_inthash[i >> 2] >> (((3 - i) & 0x3) << 3)) & 0xff; + result += (m_inthash[i >> 2] >> (((3 - i) & 0x3) << 3)) & 0xff; } - return out; + return result; } uint64_t VHashSha256::digestUInt64() { const string& binhash = digestBinary(); - uint64_t out = 0; + uint64_t result = 0; for (size_t byte = 0; byte < sizeof(uint64_t); ++byte) { const unsigned char c = binhash[byte]; - out = (out << 8) | c; + result = (result << 8) | c; } - return out; + return result; } string VHashSha256::digestHex() { static const char* const digits = "0123456789abcdef"; const string& binhash = digestBinary(); - string out; - out.reserve(70); + string result; + result.reserve(70); for (size_t byte = 0; byte < 32; ++byte) { - out += digits[(binhash[byte] >> 4) & 0xf]; - out += digits[(binhash[byte] >> 0) & 0xf]; + result += digits[(binhash[byte] >> 4) & 0xf]; + result += digits[(binhash[byte] >> 0) & 0xf]; } - return out; + return result; } string VHashSha256::digestSymbol() { @@ -369,19 +369,19 @@ string VHashSha256::digestSymbol() { static const char* const digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"; const string& binhash = digestBinary(); - string out; - out.reserve(28); + string result; + result.reserve(28); int pos = 0; for (; pos < (256 / 8) - 2; pos += 3) { - out += digits[((binhash[pos] >> 2) & 0x3f)]; - out += digits[((binhash[pos] & 0x3) << 4) - | (static_cast(binhash[pos + 1] & 0xf0) >> 4)]; - out += digits[((binhash[pos + 1] & 0xf) << 2) - | (static_cast(binhash[pos + 2] & 0xc0) >> 6)]; - out += digits[((binhash[pos + 2] & 0x3f))]; + result += digits[((binhash[pos] >> 2) & 0x3f)]; + result += digits[((binhash[pos] & 0x3) << 4) + | (static_cast(binhash[pos + 1] & 0xf0) >> 4)]; + result += digits[((binhash[pos + 1] & 0xf) << 2) + | (static_cast(binhash[pos + 2] & 0xc0) >> 6)]; + result += digits[((binhash[pos + 2] & 0x3f))]; } // Any leftover bits don't matter for our purpose - return out; + return result; } void VHashSha256::selfTestOne(const string& data, const string& data2, const string& exp, diff --git a/src/V3String.h b/src/V3String.h index d56589c5e..bd31909cc 100644 --- a/src/V3String.h +++ b/src/V3String.h @@ -70,9 +70,9 @@ inline uint32_t cvtToHash(const void* vp) { } inline string ucfirst(const string& text) { - string out = text; - out[0] = std::toupper(out[0]); - return out; + string result = text; + result[0] = std::toupper(result[0]); + return result; } //###################################################################### From d4bb58630efcdfdcfae09bd691561720173a8ffc Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 9 Apr 2023 09:56:39 -0400 Subject: [PATCH 117/155] Support 'for' initialization with comma --- src/verilog.y | 3 +- .../t/{t_for_comma_bad.pl => t_for_comma.pl} | 10 +-- test_regress/t/t_for_comma.v | 61 +++++++++++++++++++ test_regress/t/t_for_comma_bad.out | 11 ---- test_regress/t/t_for_comma_bad.v | 34 ----------- 5 files changed, 68 insertions(+), 51 deletions(-) rename test_regress/t/{t_for_comma_bad.pl => t_for_comma.pl} (83%) create mode 100644 test_regress/t/t_for_comma.v delete mode 100644 test_regress/t/t_for_comma_bad.out delete mode 100644 test_regress/t/t_for_comma_bad.v diff --git a/src/verilog.y b/src/verilog.y index b8290953a..58f527ef9 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -3897,8 +3897,7 @@ for_initialization: // ==IEEE: for_initialization + for_variable_dec for_initializationItemList: // IEEE: [for_variable_declaration...] for_initializationItem { $$ = $1; } - | for_initializationItemList ',' for_initializationItem - { $$ = $1; BBUNSUP($2, "Unsupported: for loop initialization after the first comma"); } + | for_initializationItemList ',' for_initializationItem { $$ = addNextNull($1, $3); } ; for_initializationItem: // IEEE: variable_assignment + for_variable_declaration diff --git a/test_regress/t/t_for_comma_bad.pl b/test_regress/t/t_for_comma.pl similarity index 83% rename from test_regress/t/t_for_comma_bad.pl rename to test_regress/t/t_for_comma.pl index a60503a1f..b46d46042 100755 --- a/test_regress/t/t_for_comma_bad.pl +++ b/test_regress/t/t_for_comma.pl @@ -8,11 +8,13 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios(linter => 1); +scenarios(simulator => 1); -lint( - fails => 1, - expect_filename => $Self->{golden_filename}, +compile( + ); + +execute( + check_finished => 1, ); ok(1); diff --git a/test_regress/t/t_for_comma.v b/test_regress/t/t_for_comma.v new file mode 100644 index 000000000..86ae62a87 --- /dev/null +++ b/test_regress/t/t_for_comma.v @@ -0,0 +1,61 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define checkc(expc) \ + do begin \ + if (c !== expc) begin \ + $write("%%Error: %s:%0d: a=%0d b=%0d c=%0d expc=%0d\n", `__FILE__,`__LINE__, a, b, c, (expc)); \ + $stop; \ + end \ + a=0; b=0; c=0; \ + end while(0); + +module t (/*AUTOARG*/); + + int a, b, c; + + initial begin + for (; ; ) begin c = c + 1 + a + b; break; end + `checkc(1); + for (; ; a = a + 1) begin c = c + 1 + a + b; break; end + `checkc(1); + for (; ; a = a + 1, b = b + 1) begin c = c + 1 + a + b; break; end + `checkc(1); + for (; a < 3; ) begin c = c + 1 + a + b; break; end + `checkc(1); + for (; a < 3; a = a + 1) begin c = c + 1 + a + b; break; end + `checkc(1); + for (; a < 3; a = a + 1, b = b + 1) begin c = c + 1 + a + b; break; end + `checkc(1); + for (a = 1; a < 3; ) begin c = c + 1 + a + b; a = a + 10; end + `checkc(2); + for (a = 1; a < 3; a = a + 1) begin c = c + 1 + a + b; end + `checkc(5); + for (a = 1; a < 3; a = a + 1, b = b + 1) begin c = c + 1 + a + b; end + `checkc(6); + for (int a = 1; a < 3; ) begin c = c + 1 + a + b; a = a + 10; end + `checkc(2); + for (int a = 1; a < 3; a = a + 1) begin c = c + 1 + a + b; end + `checkc(5); + for (int a = 1; a < 3; a = a + 1, b = b + 1) begin c = c + 1 + a + b; end + `checkc(6); + for (var int a = 1; a < 3; ) begin c = c + 1 + a + b; a = a + 10; end + `checkc(2); + for (var int a = 1; a < 3; a = a + 1) begin c = c + 1 + a + b; end + `checkc(5); + for (var int a = 1; a < 3; a = a + 1, b = b + 1) begin c = c + 1 + a + b; end + `checkc(6); + for (int a = 1, int b = 1; a < 3; ) begin c = c + 1 + a + b; a = a + 10; end + `checkc(3); + for (int a = 1, int b = 1; a < 3; a = a + 1) begin c = c + 1 + a + b; end + `checkc(7); + for (int a = 1, int b = 1; a < 3; a = a + 1, b = b + 1) begin c = c + 1 + a + b; end + `checkc(8); + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_for_comma_bad.out b/test_regress/t/t_for_comma_bad.out deleted file mode 100644 index d430f98c9..000000000 --- a/test_regress/t/t_for_comma_bad.out +++ /dev/null @@ -1,11 +0,0 @@ -%Error-UNSUPPORTED: t/t_for_comma_bad.v:27:23: Unsupported: for loop initialization after the first comma - 27 | for (integer a=0, integer b=0; a<1; ) ; - | ^ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_for_comma_bad.v:28:23: Unsupported: for loop initialization after the first comma - 28 | for (integer a=0, integer b=0; a<1; a=a+1) ; - | ^ -%Error-UNSUPPORTED: t/t_for_comma_bad.v:29:23: Unsupported: for loop initialization after the first comma - 29 | for (integer a=0, integer b=0; a<1; a=a+1, b=b+1) ; - | ^ -%Error: Exiting due to diff --git a/test_regress/t/t_for_comma_bad.v b/test_regress/t/t_for_comma_bad.v deleted file mode 100644 index 384b9c517..000000000 --- a/test_regress/t/t_for_comma_bad.v +++ /dev/null @@ -1,34 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2003 by Wilson Snyder. -// SPDX-License-Identifier: CC0-1.0 - -module t (/*AUTOARG*/); - - integer a, b; - - initial begin - for (; ; ) ; - for (; ; a=a+1) ; - for (; ; a=a+1, b=b+1) ; - for (; a<1; ) ; - for (; a<1; a=a+1) ; - for (; a<1; a=a+1, b=b+1) ; - for (a=0; a<1; ) ; - for (a=0; a<1; a=a+1) ; - for (a=0; a<1; a=a+1, b=b+1) ; - for (integer a=0; a<1; ) ; - for (integer a=0; a<1; a=a+1) ; - for (integer a=0; a<1; a=a+1, b=b+1) ; - for (var integer a=0; a<1; ) ; - for (var integer a=0; a<1; a=a+1) ; - for (var integer a=0; a<1; a=a+1, b=b+1) ; - for (integer a=0, integer b=0; a<1; ) ; - for (integer a=0, integer b=0; a<1; a=a+1) ; - for (integer a=0, integer b=0; a<1; a=a+1, b=b+1) ; - $write("*-* All Finished *-*\n"); - $finish; - end - -endmodule From bf5cbb512efc3b39e0d70b6c992c9a8267f17f2d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 9 Apr 2023 10:11:47 -0400 Subject: [PATCH 118/155] Add UNSUPPORTED on dotted disable instead of syntax error --- src/verilog.y | 4 +++- test_regress/t/t_for_disable_dot.out | 5 +++++ test_regress/t/t_for_disable_dot.pl | 19 +++++++++++++++++++ test_regress/t/t_for_disable_dot.v | 22 ++++++++++++++++++++++ 4 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 test_regress/t/t_for_disable_dot.out create mode 100755 test_regress/t/t_for_disable_dot.pl create mode 100644 test_regress/t/t_for_disable_dot.v diff --git a/src/verilog.y b/src/verilog.y index 58f527ef9..a7c3c70ff 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -3559,8 +3559,10 @@ statement_item: // IEEE: statement_item // // // IEEE: disable_statement | yDISABLE yFORK ';' { $$ = new AstDisableFork{$1}; } - | yDISABLE idAny/*hierarchical_identifier-task_or_block*/ ';' + | yDISABLE idAny/*UNSUP: hierarchical_identifier-task_or_block*/ ';' { $$ = new AstDisable{$1, *$2}; } + | yDISABLE idAny '.' idDotted ';' + { $$ = nullptr; BBUNSUP($4, "Unsupported: disable with '.'"); } // // IEEE: event_trigger | yP_MINUSGT idDotted/*hierarchical_identifier-event*/ ';' { $$ = new AstFireEvent{$1, $2, false}; } diff --git a/test_regress/t/t_for_disable_dot.out b/test_regress/t/t_for_disable_dot.out new file mode 100644 index 000000000..fe6edd7f7 --- /dev/null +++ b/test_regress/t/t_for_disable_dot.out @@ -0,0 +1,5 @@ +%Error-UNSUPPORTED: t/t_for_disable_dot.v:14:35: Unsupported: disable with '.' + 14 | if (i == 5) disable t.named; + | ^~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_for_disable_dot.pl b/test_regress/t/t_for_disable_dot.pl new file mode 100755 index 000000000..59ba0d6c6 --- /dev/null +++ b/test_regress/t/t_for_disable_dot.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 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); + +lint( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_for_disable_dot.v b/test_regress/t/t_for_disable_dot.v new file mode 100644 index 000000000..5e062b077 --- /dev/null +++ b/test_regress/t/t_for_disable_dot.v @@ -0,0 +1,22 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + + int i; + + initial begin + begin : named + for (i = 0; i < 10; ++i) begin : loop + if (i == 5) disable t.named; + end + end + if (i != 5) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From 663d6a1c8d5f26b89a32e9b8654f541532abeb04 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 9 Apr 2023 10:23:35 -0400 Subject: [PATCH 119/155] Commentary --- docs/internals.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/internals.rst b/docs/internals.rst index c78e0197b..c055aae8c 100644 --- a/docs/internals.rst +++ b/docs/internals.rst @@ -1801,8 +1801,6 @@ IEEE 1800-2017 6.12 "shortreal" Little/no tool support, and easily promoted to real. IEEE 1800-2017 11.11 Min, typ, max No SDF support, so will always use typical. -IEEE 1800-2017 11.12 "let" - Little/no tool support, makes it difficult to implement parsers. IEEE 1800-2017 20.16 Stochastic analysis Little industry use. IEEE 1800-2017 20.17 PLA modeling From e3bdae77a0cb5a3ac3f89f50cb604d9199828343 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 9 Apr 2023 17:08:04 -0400 Subject: [PATCH 120/155] Tests: Add randsequence test --- test_regress/t/t_randsequence_bad.out | 20 ++++++++++++++++++++ test_regress/t/t_randsequence_bad.pl | 19 +++++++++++++++++++ test_regress/t/t_randsequence_bad.v | 25 +++++++++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 test_regress/t/t_randsequence_bad.out create mode 100755 test_regress/t/t_randsequence_bad.pl create mode 100644 test_regress/t/t_randsequence_bad.v diff --git a/test_regress/t/t_randsequence_bad.out b/test_regress/t/t_randsequence_bad.out new file mode 100644 index 000000000..9cc011c04 --- /dev/null +++ b/test_regress/t/t_randsequence_bad.out @@ -0,0 +1,20 @@ +%Error-UNSUPPORTED: t/t_randsequence_bad.v:13:25: Unsupported: randsequence production + 13 | such_production: { }; + | ^ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_randsequence_bad.v:12:7: Unsupported: randsequence + 12 | randsequence(no_such_production) + | ^~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_randsequence_bad.v:17:16: Unsupported: randsequence production id + 17 | main: production_bad; + | ^~~~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_randsequence_bad.v:17:14: Unsupported: randsequence production + 17 | main: production_bad; + | ^ +%Error-UNSUPPORTED: t/t_randsequence_bad.v:18:24: Unsupported: randsequence production + 18 | production_baa: {}; + | ^ +%Error-UNSUPPORTED: t/t_randsequence_bad.v:16:7: Unsupported: randsequence + 16 | randsequence(main) + | ^~~~~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_randsequence_bad.pl b/test_regress/t/t_randsequence_bad.pl new file mode 100755 index 000000000..a083f46f5 --- /dev/null +++ b/test_regress/t/t_randsequence_bad.pl @@ -0,0 +1,19 @@ +#!/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(vlt => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_randsequence_bad.v b/test_regress/t/t_randsequence_bad.v new file mode 100644 index 000000000..5e335f237 --- /dev/null +++ b/test_regress/t/t_randsequence_bad.v @@ -0,0 +1,25 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// 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 + +module t(/*AUTOARG*/); + + initial begin; + randsequence(no_such_production) // Bad + such_production: { }; + endsequence + + randsequence(main) + main: production_bad; // Bad + production_baa: {}; + endsequence + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From 2ab34b5eeb2ccae756c7d47fde72eb1b7b5529fa Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 9 Apr 2023 19:46:47 -0400 Subject: [PATCH 121/155] Fix false error on new const assignment (#4098). --- Changes | 1 + src/V3Width.cpp | 4 ++-- test_regress/t/t_class_new.v | 5 +++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Changes b/Changes index 52905d12a..715c7827b 100644 --- a/Changes +++ b/Changes @@ -39,6 +39,7 @@ Verilator 5.009 devel * Fix false LATCH warning on --assert 'unique else if' (#4033) ($4054). [Jesse Taube] * Fix characters from DEFENV literals for conda (#4035) (#4044). [Tim Snyder] * Fix interface generate begin (#4065). [Srinivasan Venkataramanan] +* Fix false error on new const assignment (#4098). [Tudor Timi] * Fix false ENUMVALUE on expressions and arrays. * Fix unnecessary verilated_std.sv waivers in --waiver-output. diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 962af7e9f..849eb393b 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -5287,6 +5287,8 @@ private: // Function hasn't been widthed, so make it so. // Would use user1 etc, but V3Width called from too many places to spend a user nodep->doingWidth(true); + VL_RESTORER(m_funcp); + VL_RESTORER(m_ftaskp); m_ftaskp = nodep; // First width the function variable, as if is a recursive function we need data type if (nodep->fvarp()) userIterate(nodep->fvarp(), nullptr); @@ -5306,8 +5308,6 @@ private: nodep->didWidth(true); nodep->doingWidth(false); - m_funcp = nullptr; - m_ftaskp = nullptr; if (nodep->dpiImport() && !nodep->dpiOpenParent() && markHasOpenArray(nodep)) { nodep->dpiOpenParentInc(); // Mark so V3Task will wait for a child to build calling // func diff --git a/test_regress/t/t_class_new.v b/test_regress/t/t_class_new.v index f15328470..9d625c5a5 100644 --- a/test_regress/t/t_class_new.v +++ b/test_regress/t/t_class_new.v @@ -7,8 +7,13 @@ class ClsNoArg; const int imembera; // Ok for new() to assign to a const function new(); + int other = other_func(); imembera = 5; + if (other != 6) $stop; endfunction : new + function int other_func(); + return 6; + endfunction endclass class ClsArg; From 722ab9306a3a8b84b48b47b64d217185ef5f5390 Mon Sep 17 00:00:00 2001 From: Srinivasan Venkataramanan Date: Tue, 11 Apr 2023 05:07:24 +0530 Subject: [PATCH 122/155] Support class method calls without parenthesis (#3902) (#4082) --- src/V3LinkDot.cpp | 8 ++++++-- src/V3LinkParse.cpp | 3 +++ test_regress/t/t_class_method.v | 5 ++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 1028ac62e..bda97c8c2 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2765,11 +2765,15 @@ private: m_ds.m_dotSymp = foundp; ok = m_ds.m_dotPos == DP_SCOPE; } else if (const AstNodeFTask* const ftaskp = VN_CAST(foundp->nodep(), NodeFTask)) { - if (!ftaskp->isFunction()) { + + if (!ftaskp->isFunction() || + ftaskp->classMethod() ) { ok = m_ds.m_dotPos == DP_NONE; if (ok) { - // The condition is true for tasks, properties and void functions. + // The condition is true for tasks, + // properties and void functions. // In these cases, the parentheses may be skipped. + // Also SV class methods can be called without parens AstFuncRef* const funcRefp = new AstFuncRef{nodep->fileline(), nodep->name(), nullptr}; nodep->replaceWith(funcRefp); diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index e92ad24f2..621dd013d 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -135,6 +135,9 @@ private: // VISITs void visit(AstNodeFTask* nodep) override { if (!nodep->user1SetOnce()) { // Process only once. + // Mark class methods + if (VN_IS(m_modp, Class)) nodep->classMethod(true); + V3Config::applyFTask(m_modp, nodep); cleanFileline(nodep); VL_RESTORER(m_ftaskp); diff --git a/test_regress/t/t_class_method.v b/test_regress/t/t_class_method.v index b1aefcb5d..0ecf6f832 100644 --- a/test_regress/t/t_class_method.v +++ b/test_regress/t/t_class_method.v @@ -15,6 +15,7 @@ endclass : Cls module t (/*AUTOARG*/); initial begin + int tmp_i; Cls c; if (c != null) $stop; c = new; @@ -24,7 +25,9 @@ module t (/*AUTOARG*/); if (c.get_methoda() != 20) $stop; c.setv_methoda(30); if (c.get_methoda() != 30) $stop; - if (c.get_methoda != 30) $stop; + c.setv_methoda(300); + tmp_i = c.get_methoda; + if (tmp_i != 300) $stop; $write("*-* All Finished *-*\n"); $finish; end From fc70876aa9422f3def567596213a368b6f829912 Mon Sep 17 00:00:00 2001 From: github action Date: Mon, 10 Apr 2023 23:38:20 +0000 Subject: [PATCH 123/155] Apply 'make format' --- src/V3LinkDot.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index bda97c8c2..d16fcf454 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2766,8 +2766,7 @@ private: ok = m_ds.m_dotPos == DP_SCOPE; } else if (const AstNodeFTask* const ftaskp = VN_CAST(foundp->nodep(), NodeFTask)) { - if (!ftaskp->isFunction() || - ftaskp->classMethod() ) { + if (!ftaskp->isFunction() || ftaskp->classMethod()) { ok = m_ds.m_dotPos == DP_NONE; if (ok) { // The condition is true for tasks, From 3aa013c8db80fffad4c27586f181464f9fce7a1b Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 9 Apr 2023 22:56:17 -0400 Subject: [PATCH 124/155] Tests: Remove old file --- test_regress/t/t_probdist.out | 43 ----------------------------------- 1 file changed, 43 deletions(-) delete mode 100644 test_regress/t/t_probdist.out diff --git a/test_regress/t/t_probdist.out b/test_regress/t/t_probdist.out deleted file mode 100644 index a41967f44..000000000 --- a/test_regress/t/t_probdist.out +++ /dev/null @@ -1,43 +0,0 @@ -%Error: t/t_probdist.v:18:11: Unsupported or unknown PLI call: '$dist_chi_square' - 18 | r = $dist_chi_square(seed, 5); - | ^~~~~~~~~~~~~~~~ -%Error: t/t_probdist.v:22:25: Unsupported or unknown PLI call: '$dist_chi_square' - 22 | repeat(20) sum += $dist_chi_square(seed, 5); - | ^~~~~~~~~~~~~~~~ -%Error: t/t_probdist.v:26:11: Unsupported or unknown PLI call: '$dist_erlang' - 26 | r = $dist_erlang(seed, 5, 10); - | ^~~~~~~~~~~~ -%Error: t/t_probdist.v:30:25: Unsupported or unknown PLI call: '$dist_erlang' - 30 | repeat(20) sum += $dist_erlang(seed, 5, 10); - | ^~~~~~~~~~~~ -%Error: t/t_probdist.v:34:11: Unsupported or unknown PLI call: '$dist_exponential' - 34 | r = $dist_exponential(seed, 5); - | ^~~~~~~~~~~~~~~~~ -%Error: t/t_probdist.v:38:25: Unsupported or unknown PLI call: '$dist_exponential' - 38 | repeat(20) sum += $dist_exponential(seed, 5); - | ^~~~~~~~~~~~~~~~~ -%Error: t/t_probdist.v:42:11: Unsupported or unknown PLI call: '$dist_normal' - 42 | r = $dist_normal(seed, 5, 10); - | ^~~~~~~~~~~~ -%Error: t/t_probdist.v:46:25: Unsupported or unknown PLI call: '$dist_normal' - 46 | repeat(20) sum += $dist_normal(seed, 5, 10); - | ^~~~~~~~~~~~ -%Error: t/t_probdist.v:50:11: Unsupported or unknown PLI call: '$dist_poisson' - 50 | r = $dist_poisson(seed, 5); - | ^~~~~~~~~~~~~ -%Error: t/t_probdist.v:54:25: Unsupported or unknown PLI call: '$dist_poisson' - 54 | repeat(20) sum += $dist_poisson(seed, 5); - | ^~~~~~~~~~~~~ -%Error: t/t_probdist.v:58:11: Unsupported or unknown PLI call: '$dist_t' - 58 | r = $dist_t(seed, 5); - | ^~~~~~~ -%Error: t/t_probdist.v:62:25: Unsupported or unknown PLI call: '$dist_t' - 62 | repeat(20) sum += $dist_t(seed, 5); - | ^~~~~~~ -%Error: t/t_probdist.v:66:11: Unsupported or unknown PLI call: '$dist_uniform' - 66 | r = $dist_uniform(seed, 5, 10); - | ^~~~~~~~~~~~~ -%Error: t/t_probdist.v:70:25: Unsupported or unknown PLI call: '$dist_uniform' - 70 | repeat(20) sum += $dist_uniform(seed, 5, 10); - | ^~~~~~~~~~~~~ -%Error: Exiting due to From 0307d59c1f72c0e5a65be643164f167a9a05a20d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 10 Apr 2023 19:40:17 -0400 Subject: [PATCH 125/155] Fix unpacked structs under classes (#4102). --- Changes | 1 + src/V3Class.cpp | 3 ++- src/V3EmitCImp.cpp | 2 +- src/V3File.cpp | 2 +- test_regress/t/t_struct_unpacked.v | 18 ++++++++++++++++++ 5 files changed, 23 insertions(+), 3 deletions(-) diff --git a/Changes b/Changes index 715c7827b..75c95ee2f 100644 --- a/Changes +++ b/Changes @@ -40,6 +40,7 @@ Verilator 5.009 devel * Fix characters from DEFENV literals for conda (#4035) (#4044). [Tim Snyder] * Fix interface generate begin (#4065). [Srinivasan Venkataramanan] * Fix false error on new const assignment (#4098). [Tudor Timi] +* Fix unpacked structs under classes (#4102). [Tudor Timi] * Fix false ENUMVALUE on expressions and arrays. * Fix unnecessary verilated_std.sv waivers in --waiver-output. diff --git a/src/V3Class.cpp b/src/V3Class.cpp index 61513782a..3c726a3a6 100644 --- a/src/V3Class.cpp +++ b/src/V3Class.cpp @@ -178,7 +178,7 @@ private: void setStructModulep(AstNodeUOrStructDType* const dtypep) { // Give it a pointer to its package and a final name - dtypep->classOrPackagep(m_modp); + dtypep->classOrPackagep(m_classPackagep ? m_classPackagep : m_modp); dtypep->name(dtypep->name() + (VN_IS(dtypep, UnionDType) ? "__union" : "__struct") + cvtToStr(dtypep->uniqueNum())); @@ -193,6 +193,7 @@ private: void visit(AstTypedef* nodep) override { if (nodep->user1SetOnce()) return; iterateChildren(nodep); + if (m_classPackagep) m_classPackagep->addStmtsp(nodep->unlinkFrBack()); AstNodeUOrStructDType* const dtypep = VN_CAST(nodep->dtypep(), NodeUOrStructDType); if (dtypep && !dtypep->packed()) { diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index ead32fb03..ee9a96306 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -514,7 +514,7 @@ class EmitCImp final : EmitCFunc { // Compute the hash of the dependencies, so we can add it to the filenames to // disambiguate them V3Hash hash; - for (const string& name : *m_requiredHeadersp) { hash += name; } + for (const string& name : *m_requiredHeadersp) hash += name; m_subFileName = "DepSet_" + hash.toString(); // Open output file openNextOutputFile(*m_requiredHeadersp, m_subFileName); diff --git a/src/V3File.cpp b/src/V3File.cpp index 506f67a64..89d82c17f 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -937,7 +937,7 @@ V3OutFile::~V3OutFile() { void V3OutFile::putsForceIncs() { const V3StringList& forceIncs = v3Global.opt.forceIncs(); - for (const string& i : forceIncs) { puts("#include \"" + i + "\"\n"); } + for (const string& i : forceIncs) puts("#include \"" + i + "\"\n"); } void V3OutCFile::putsGuard() { diff --git a/test_regress/t/t_struct_unpacked.v b/test_regress/t/t_struct_unpacked.v index 14190f693..ef0ad6b2a 100644 --- a/test_regress/t/t_struct_unpacked.v +++ b/test_regress/t/t_struct_unpacked.v @@ -7,6 +7,19 @@ `define stop $stop `define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +class Cls; + typedef struct { + string m_strg; + } underclass_t; + + underclass_t m_cstr; + function underclass_t get_cstr(); + m_cstr.m_strg = "foo"; + return m_cstr; + endfunction +endclass + + module x; typedef struct { int a, b; @@ -27,6 +40,7 @@ module x; embedded_t t [1:0]; istr_t istr; string s; + Cls c; initial begin t[1].a = 2; @@ -43,6 +57,10 @@ module x; s = $sformatf("%p", istr); `checks(s, "'{m_i:'hffff, m_s:\"str2\"}"); + c = new; + s = c.get_cstr().m_strg; + `checks(s, "foo"); + $write("*-* All Finished *-*\n"); $finish; end From b6dcec27104a0c703664a9cd0db56355225cc993 Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Tue, 11 Apr 2023 13:23:24 +0200 Subject: [PATCH 126/155] Internals: Split Mutex class used in verilated code and verilator (#4048) --- include/verilated.h | 7 ++ src/Makefile_obj.in | 1 + src/V3Config.cpp | 12 ++-- src/V3Config.h | 1 + src/V3Error.h | 46 ++++++------ src/V3File.cpp | 12 ++-- src/V3FileLine.cpp | 4 +- src/V3FileLine.h | 5 +- src/V3Mutex.h | 164 +++++++++++++++++++++++++++++++++++++++++++ src/V3Number.cpp | 6 +- src/V3Options.cpp | 4 +- src/V3Options.h | 1 + src/V3Os.cpp | 2 - src/V3ThreadPool.cpp | 27 +++---- src/V3ThreadPool.h | 18 ++--- src/V3Waiver.cpp | 6 +- src/V3Waiver.h | 5 +- src/Verilator.cpp | 2 + 18 files changed, 249 insertions(+), 74 deletions(-) create mode 100644 src/V3Mutex.h diff --git a/include/verilated.h b/include/verilated.h index 70c12f362..02de0ea12 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -30,6 +30,13 @@ #ifndef VERILATOR_VERILATED_H_ #define VERILATOR_VERILATED_H_ #define VERILATOR_VERILATED_H_INTERNAL_ +#ifdef VERILATOR_INTERNAL_ +// This file contains definition of VerilationMutex that should +// only be used by verilated code. Verilator itself should use +// mutex from V3Mutex.h. Make sure this file isn't included in +// verilator code. +#error "verilated.h should only be included in verilated code" +#endif // clang-format off #include "verilatedos.h" diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index 1db782e52..617a8880c 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -92,6 +92,7 @@ endif # -lfl not needed as Flex invoked with %nowrap option LIBS = $(CFG_LIBS) -lm +CPPFLAGS += -DVERILATOR_INTERNAL_ CPPFLAGS += -MMD CPPFLAGS += -I. -I$(bldsrc) -I$(srcdir) -I$(incdir) -I../../include #CPPFLAGS += -DVL_LEAK_CHECKS # If running valgrind or other hunting tool diff --git a/src/V3Config.cpp b/src/V3Config.cpp index c6fb382c3..7bcb4b72c 100644 --- a/src/V3Config.cpp +++ b/src/V3Config.cpp @@ -40,7 +40,7 @@ template class V3ConfigWildcardResolver final { using Map = std::map; - mutable VerilatedMutex m_mutex; // protects members + mutable V3Mutex m_mutex; // protects members Map m_mapWildcard VL_GUARDED_BY(m_mutex); // Wildcard strings to entities Map m_mapResolved VL_GUARDED_BY(m_mutex); // Resolved strings to converged entities public: @@ -50,21 +50,21 @@ public: /// Update into maps from other void update(const V3ConfigWildcardResolver& other) VL_MT_SAFE_EXCLUDES(m_mutex) VL_EXCLUDES(other.m_mutex) { - VerilatedLockGuard lock{m_mutex}; - VerilatedLockGuard otherLock{other.m_mutex}; + V3LockGuard lock{m_mutex}; + V3LockGuard otherLock{other.m_mutex}; for (const auto& itr : other.m_mapResolved) m_mapResolved[itr.first].update(itr.second); for (const auto& itr : other.m_mapWildcard) m_mapWildcard[itr.first].update(itr.second); } // Access and create a (wildcard) entity T& at(const string& name) VL_MT_SAFE_EXCLUDES(m_mutex) { - VerilatedLockGuard lock{m_mutex}; + V3LockGuard lock{m_mutex}; // Don't store into wildcards if the name is not a wildcard string return m_mapWildcard[name]; } // Access an entity and resolve wildcards that match it T* resolve(const string& name) VL_MT_SAFE_EXCLUDES(m_mutex) { - VerilatedLockGuard lock{m_mutex}; + V3LockGuard lock{m_mutex}; // Lookup if it was resolved before, typically not auto it = m_mapResolved.find(name); if (VL_UNLIKELY(it != m_mapResolved.end())) return &it->second; @@ -85,7 +85,7 @@ public: } // Flush on update void flush() VL_MT_SAFE_EXCLUDES(m_mutex) { - VerilatedLockGuard lock{m_mutex}; + V3LockGuard lock{m_mutex}; m_mapResolved.clear(); } }; diff --git a/src/V3Config.h b/src/V3Config.h index eff00b846..2ae32ef0d 100644 --- a/src/V3Config.h +++ b/src/V3Config.h @@ -23,6 +23,7 @@ #include "V3Ast.h" #include "V3Error.h" #include "V3FileLine.h" +#include "V3Mutex.h" //###################################################################### diff --git a/src/V3Error.h b/src/V3Error.h index ddff5baf2..01578fa0e 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -20,7 +20,7 @@ #include "config_build.h" #include "verilatedos.h" -#include "verilated_threads.h" +#include "V3Mutex.h" // Limited V3 headers here - this is a base class for Vlc etc #include "V3String.h" @@ -315,7 +315,7 @@ private: bool m_warnFatal VL_GUARDED_BY(m_mutex) = true; // Option: --warnFatal Warnings are fatal std::ostringstream m_errorStr VL_GUARDED_BY(m_mutex); // Error string being formed public: - VerilatedMutex m_mutex; // Make sure only single thread is in class + V3RecursiveMutex m_mutex; // Make sure only single thread is in class string msgPrefix() VL_REQUIRES(m_mutex); // returns %Error/%Warn string warnMore() VL_REQUIRES(m_mutex); @@ -408,57 +408,57 @@ public: static void debugDefault(int level) VL_MT_UNSAFE { s().debugDefault(level); } static int debugDefault() VL_MT_SAFE { return s().debugDefault(); } static void errorLimit(int level) VL_MT_SAFE_EXCLUDES(s().m_mutex) { - const VerilatedLockGuard guard{s().m_mutex}; + const V3RecursiveLockGuard guard{s().m_mutex}; s().errorLimit(level); } static int errorLimit() VL_MT_SAFE_EXCLUDES(s().m_mutex) { - const VerilatedLockGuard guard{s().m_mutex}; + const V3RecursiveLockGuard guard{s().m_mutex}; return s().errorLimit(); } static void warnFatal(bool flag) VL_MT_SAFE_EXCLUDES(s().m_mutex) { - const VerilatedLockGuard guard{s().m_mutex}; + const V3RecursiveLockGuard guard{s().m_mutex}; s().warnFatal(flag); } static bool warnFatal() VL_MT_SAFE_EXCLUDES(s().m_mutex) { - const VerilatedLockGuard guard{s().m_mutex}; + const V3RecursiveLockGuard guard{s().m_mutex}; return s().warnFatal(); } // returns %Error/%Warn static string msgPrefix() VL_MT_SAFE_EXCLUDES(s().m_mutex) { - const VerilatedLockGuard guard{s().m_mutex}; + const V3RecursiveLockGuard guard{s().m_mutex}; return s().msgPrefix(); } static int errorCount() VL_MT_SAFE_EXCLUDES(s().m_mutex) { - const VerilatedLockGuard guard{s().m_mutex}; + const V3RecursiveLockGuard guard{s().m_mutex}; return s().errorCount(); } static bool pretendError(int errorCode) VL_MT_SAFE_EXCLUDES(s().m_mutex) { - const VerilatedLockGuard guard{s().m_mutex}; + const V3RecursiveLockGuard guard{s().m_mutex}; return s().pretendError(errorCode); } static int warnCount() VL_MT_SAFE_EXCLUDES(s().m_mutex) { - const VerilatedLockGuard guard{s().m_mutex}; + const V3RecursiveLockGuard guard{s().m_mutex}; return s().warnCount(); } static bool errorContexted() VL_MT_SAFE_EXCLUDES(s().m_mutex) { - const VerilatedLockGuard guard{s().m_mutex}; + const V3RecursiveLockGuard guard{s().m_mutex}; return s().errorContexted(); } static void errorContexted(bool flag) VL_MT_SAFE_EXCLUDES(s().m_mutex) { - const VerilatedLockGuard guard{s().m_mutex}; + const V3RecursiveLockGuard guard{s().m_mutex}; s().errorContexted(flag); } static void describedEachWarn(V3ErrorCode code, bool flag) VL_MT_SAFE_EXCLUDES(s().m_mutex) { - const VerilatedLockGuard guard{s().m_mutex}; + const V3RecursiveLockGuard guard{s().m_mutex}; s().describedEachWarn(code, flag); } // METHODS static void incErrors() VL_MT_SAFE_EXCLUDES(s().m_mutex) { - const VerilatedLockGuard guard{s().m_mutex}; + const V3RecursiveLockGuard guard{s().m_mutex}; s().incErrors(); } static void incWarnings() VL_MT_SAFE_EXCLUDES(s().m_mutex) { - const VerilatedLockGuard guard{s().m_mutex}; + const V3RecursiveLockGuard guard{s().m_mutex}; s().incWarnings(); } static void init(); @@ -468,20 +468,20 @@ public: static void abortIfWarnings(); // Suppress next %Warn if user has it off static void suppressThisWarning() VL_MT_SAFE_EXCLUDES(s().m_mutex) { - const VerilatedLockGuard guard{s().m_mutex}; + const V3RecursiveLockGuard guard{s().m_mutex}; s().suppressThisWarning(); } static void pretendError(V3ErrorCode code, bool flag) VL_MT_SAFE_EXCLUDES(s().m_mutex) { - const VerilatedLockGuard guard{s().m_mutex}; + const V3RecursiveLockGuard guard{s().m_mutex}; s().pretendError(code, flag); } static string lineStr(const char* filename, int lineno) VL_PURE; static V3ErrorCode errorCode() VL_MT_SAFE_EXCLUDES(s().m_mutex) { - const VerilatedLockGuard guard{s().m_mutex}; + const V3RecursiveLockGuard guard{s().m_mutex}; return s().errorCode(); } static void errorExitCb(V3ErrorGuarded::ErrorExitCb cb) VL_MT_SAFE_EXCLUDES(s().m_mutex) { - const VerilatedLockGuard guard{s().m_mutex}; + const V3RecursiveLockGuard guard{s().m_mutex}; s().errorExitCb(cb); } @@ -492,7 +492,7 @@ public: // streamed directly to cerr. // Use with caution as this function isn't MT_SAFE. static string warnMoreStandalone() VL_EXCLUDES(s().m_mutex) VL_MT_UNSAFE { - const VerilatedLockGuard guard{s().m_mutex}; + const V3RecursiveLockGuard guard{s().m_mutex}; return s().warnMore(); } // This function marks place in error message from which point message @@ -508,18 +508,18 @@ public: // Internals for v3error()/v3fatal() macros only // Error end takes the string stream to output, be careful to seek() as needed static void v3errorPrep(V3ErrorCode code) VL_MT_SAFE_EXCLUDES(s().m_mutex) { - const VerilatedLockGuard guard{s().m_mutex}; + const V3RecursiveLockGuard guard{s().m_mutex}; s().v3errorPrep(code); } static std::ostringstream& v3errorStr() VL_MT_SAFE_EXCLUDES(s().m_mutex) { - const VerilatedLockGuard guard{s().m_mutex}; + const V3RecursiveLockGuard guard{s().m_mutex}; return s().v3errorStr(); } static void vlAbort(); // static, but often overridden in classes. static void v3errorEnd(std::ostringstream& sstr, const string& extra = "") VL_MT_SAFE_EXCLUDES(s().m_mutex) VL_MT_SAFE { - const VerilatedLockGuard guard{s().m_mutex}; + const V3RecursiveLockGuard guard{s().m_mutex}; s().v3errorEnd(sstr, extra); } // We can't call 's().v3errorEnd' directly in 'v3ErrorEnd'/'v3errorEndFatal', diff --git a/src/V3File.cpp b/src/V3File.cpp index 89d82c17f..a197f6d6c 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -108,7 +108,7 @@ class V3FileDependImp final { }; // MEMBERS - VerilatedMutex m_mutex; // Protects members + V3Mutex m_mutex; // Protects members std::set m_filenameSet VL_GUARDED_BY(m_mutex); // Files generated (elim duplicates) std::set m_filenameList; // Files sourced/generated @@ -123,7 +123,7 @@ class V3FileDependImp final { public: // ACCESSOR METHODS void addSrcDepend(const string& filename) VL_MT_SAFE_EXCLUDES(m_mutex) { - const VerilatedLockGuard lock{m_mutex}; + const V3LockGuard lock{m_mutex}; const auto itFoundPair = m_filenameSet.insert(filename); if (itFoundPair.second) { DependFile df{filename, false}; @@ -132,7 +132,7 @@ public: } } void addTgtDepend(const string& filename) VL_MT_SAFE_EXCLUDES(m_mutex) { - const VerilatedLockGuard lock{m_mutex}; + const V3LockGuard lock{m_mutex}; const auto itFoundPair = m_filenameSet.insert(filename); if (itFoundPair.second) m_filenameList.insert(DependFile{filename, true}); } @@ -957,7 +957,7 @@ void V3OutCFile::putsGuard() { class VIdProtectImp final { // MEMBERS - VerilatedMutex m_mutex; // Protects members + V3Mutex m_mutex; // Protects members std::map m_nameMap; // Map of old name into new name std::unordered_set m_newIdSet VL_GUARDED_BY(m_mutex); // Which new names exist protected: @@ -979,7 +979,7 @@ public: // METHODS string passthru(const string& old) VL_MT_SAFE_EXCLUDES(m_mutex) { if (!v3Global.opt.protectIds()) return old; - const VerilatedLockGuard lock{m_mutex}; + const V3LockGuard lock{m_mutex}; const auto it = m_nameMap.find(old); if (it != m_nameMap.end()) { // No way to go back and correct the older crypt name @@ -993,7 +993,7 @@ public: } string protectIf(const string& old, bool doIt) VL_MT_SAFE_EXCLUDES(m_mutex) { if (!v3Global.opt.protectIds() || old.empty() || !doIt) return old; - const VerilatedLockGuard lock{m_mutex}; + const V3LockGuard lock{m_mutex}; const auto it = m_nameMap.find(old); if (it != m_nameMap.end()) { return it->second; diff --git a/src/V3FileLine.cpp b/src/V3FileLine.cpp index b54443916..06421f12a 100644 --- a/src/V3FileLine.cpp +++ b/src/V3FileLine.cpp @@ -89,7 +89,7 @@ void FileLineSingleton::fileNameNumMapDumpXml(std::ostream& os) { FileLineSingleton::msgEnSetIdx_t FileLineSingleton::addMsgEnBitSet(const MsgEnBitSet& bitSet) VL_MT_SAFE_EXCLUDES(m_mutex) { - VerilatedLockGuard lock{m_mutex}; + V3LockGuard lock{m_mutex}; const auto pair = m_internedMsgEnIdxs.emplace(bitSet, 0); msgEnSetIdx_t& idx = pair.first->second; if (pair.second) { @@ -418,7 +418,7 @@ string FileLine::warnOther() const VL_REQUIRES(V3Error::s().m_mutex) { } }; string FileLine::warnOtherStandalone() const VL_EXCLUDES(V3Error::s().m_mutex) VL_MT_UNSAFE { - const VerilatedLockGuard guard{V3Error::s().m_mutex}; + const V3RecursiveLockGuard guard{V3Error::s().m_mutex}; return warnOther(); } diff --git a/src/V3FileLine.h b/src/V3FileLine.h index 6f66277c1..0bf14ae3f 100644 --- a/src/V3FileLine.h +++ b/src/V3FileLine.h @@ -20,10 +20,9 @@ #include "config_build.h" #include "verilatedos.h" -#include "verilated_threads.h" - #include "V3Error.h" #include "V3LangCode.h" +#include "V3Mutex.h" #include #include @@ -52,7 +51,7 @@ class FileLineSingleton final { using MsgEnBitSet = std::bitset; // MEMBERS - VerilatedMutex m_mutex; // protects members + V3Mutex m_mutex; // protects members std::map m_namemap; // filenameno for each filename std::deque m_names; // filename text for each filenameno std::deque m_languages; // language for each filenameno diff --git a/src/V3Mutex.h b/src/V3Mutex.h new file mode 100644 index 000000000..b1ee4b021 --- /dev/null +++ b/src/V3Mutex.h @@ -0,0 +1,164 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Thread pool for Verilator itself +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2005-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 +// +//************************************************************************* +/// +/// \file +/// \brief Verilator Mutex and LockGuard used only in verilator. +/// +/// This file defines Mutex and LockGuard that is used in verilator +/// source code. It shouldn't be used by verilated code. +/// In contrast to VerilatedMutex that is used by verilated code, +/// this mutex can be configured and disabled when verilation is using +/// single thread. +/// +/// This implementation also allows using different base mutex class in +/// wrapper V3Mutex class. +/// +//************************************************************************* + +#ifndef VERILATOR_V3MUTEX_H_ +#define VERILATOR_V3MUTEX_H_ 1 + +#include "verilatedos.h" + +#include +#include +#include + +#define VL_LOCK_SPINS 50000 /// Number of times to spin for a mutex before yielding + +// MutexConfig class that allows to configure how mutex and lockgurads behave +// once configured and locked, it cannot be changed. Configuration and lock needs to be +// done before starting any additional threads. +class V3MutexConfig final { +private: + // Allows to disable mutexes and lockguards. + // Use carefully as it can cause undefined behavior when used inappropriately. + // All mutexes needs to be unlocked. + bool m_enable = false; // Allows locking on mutexes, default don't lock mutexes + bool m_lockConfig = false; // After set, configuration cannot be changed + + V3MutexConfig() = default; + ~V3MutexConfig() = default; + +public: + static V3MutexConfig& s() VL_MT_SAFE { + static V3MutexConfig s; + return s; + } + + // configures class + void configure(bool enable) VL_MT_UNSAFE { + if (!s().m_lockConfig) { + s().m_enable = enable; + s().m_lockConfig = true; + } else { + // requires + // avoided to reduce compile time + // std::cerr << "%Error: V3Mutex already configured." << std::endl; + std::abort(); + } + } + bool lockConfig() VL_MT_SAFE { return m_lockConfig; } + bool enable() VL_MT_SAFE { return m_enable; } +}; + +/// Mutex, wrapped to allow -fthread_safety checks +template +class VL_CAPABILITY("mutex") V3MutexImp final { +private: + T m_mutex; // Mutex + +public: + /// Construct mutex (without locking it) + V3MutexImp() = default; + ~V3MutexImp() = default; + const V3MutexImp& operator!() const { return *this; } // For -fthread_safety + /// Acquire/lock mutex + void lock() VL_ACQUIRE() VL_MT_SAFE { + if (V3MutexConfig::s().enable()) { + // Try to acquire the lock by spinning. If the wait is short, + // avoids a trap to the OS plus OS scheduler overhead. + if (VL_LIKELY(try_lock())) return; // Short circuit loop + for (int i = 0; i < VL_LOCK_SPINS; ++i) { + if (VL_LIKELY(try_lock())) return; + VL_CPU_RELAX(); + } + // Spinning hasn't worked, pay the cost of blocking. + m_mutex.lock(); + } + } + /// Release/unlock mutex + void unlock() VL_RELEASE() VL_MT_SAFE { + if (V3MutexConfig::s().enable()) { m_mutex.unlock(); } + } + /// Try to acquire mutex. Returns true on success, and false on failure. + bool try_lock() VL_TRY_ACQUIRE(true) VL_MT_SAFE { + return V3MutexConfig::s().enable() ? m_mutex.try_lock() : true; + } + /// Acquire/lock mutex and check for stop request + /// It tries to lock the mutex and if it fails, it check if stop request was send. + /// It returns after locking mutex. + /// This function should be extracted to V3ThreadPool, but due to clang thread-safety + /// limitations it needs to be placed here. + void lockCheckStopRequest(std::function checkStopRequestFunction) + VL_ACQUIRE() VL_MT_SAFE { + if (V3MutexConfig::s().enable()) { + while (true) { + checkStopRequestFunction(); + if (m_mutex.try_lock()) return; + VL_CPU_RELAX(); + } + } + } +}; + +/// Lock guard for mutex (ala std::unique_lock), wrapped to allow -fthread_safety checks +template +class VL_SCOPED_CAPABILITY V3LockGuardImp final { + VL_UNCOPYABLE(V3LockGuardImp); + +private: + T& m_mutexr; + +public: + /// Construct and hold given mutex lock until destruction or unlock() + explicit V3LockGuardImp(T& mutexr) VL_ACQUIRE(mutexr) VL_MT_SAFE + : m_mutexr(mutexr) { // Need () or GCC 4.8 false warning + m_mutexr.lock(); + } + /// Destruct and unlock the mutex + ~V3LockGuardImp() VL_RELEASE() { m_mutexr.unlock(); } + /// Lock the mutex + void lock() VL_ACQUIRE() VL_MT_SAFE { m_mutexr.lock(); } + /// Unlock the mutex + void unlock() VL_RELEASE() VL_MT_SAFE { m_mutexr.unlock(); } + /// Acquire/lock mutex and check for stop request. + /// It tries to lock the mutex and if it fails, it check if stop request was send. + /// It returns after locking mutex. + /// This function should be extracted to V3ThreadPool, but due to clang thread-safety + /// limitations it needs to be placed here. + void lockCheckStopRequest(std::function checkStopRequestFunction) + VL_ACQUIRE() VL_MT_SAFE { + m_mutexr.lockCheckStopRequest(checkStopRequestFunction); + } +}; + +using V3Mutex = V3MutexImp; +using V3RecursiveMutex = V3MutexImp; +using V3LockGuard = V3LockGuardImp; +using V3RecursiveLockGuard = V3LockGuardImp; + +#endif // guard diff --git a/src/V3Number.cpp b/src/V3Number.cpp index 7defef9a5..3a80da8c2 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -2232,8 +2232,10 @@ V3Number& V3Number::opNToI(const V3Number& lhs) { const string& str = lhs.toString(); for (size_t n = 0; n < str.length(); ++n) { const char c = str[str.length() - 1 - n]; - for (size_t cbit = 0; cbit < 8; ++cbit) - setBit(n * 8 + cbit, VL_BITISSET_I(c, cbit) ? 1 : 0); + for (size_t cbit = 0; cbit < 8; ++cbit) { + const std::bitset<8> sbit{static_cast(c)}; + setBit(n * 8 + cbit, sbit.test(cbit) ? 1 : 0); + } } return *this; } diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 7227ae1ba..3b8a26040 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -896,8 +896,8 @@ string V3Options::version() VL_PURE { } string V3Options::protectKeyDefaulted() VL_MT_SAFE { - static VerilatedMutex mutex; - const VerilatedLockGuard lock{mutex}; + static V3Mutex mutex; + const V3LockGuard lock{mutex}; if (m_protectKey.empty()) { // Create a key with a human-readable symbol-like name. // This conversion drops ~2 bits of entropy out of 256, shouldn't matter. diff --git a/src/V3Options.h b/src/V3Options.h index 7e6b639b3..360c28b53 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -22,6 +22,7 @@ #include "V3Error.h" #include "V3LangCode.h" +#include "V3Mutex.h" #include #include diff --git a/src/V3Os.cpp b/src/V3Os.cpp index 9d2fd0918..4a80f98ac 100644 --- a/src/V3Os.cpp +++ b/src/V3Os.cpp @@ -28,8 +28,6 @@ #include "config_build.h" #include "verilatedos.h" -#include "verilated_threads.h" - // Limited V3 headers here - this is a base class for Vlc etc #include "V3Os.h" #include "V3String.h" diff --git a/src/V3ThreadPool.cpp b/src/V3ThreadPool.cpp index 6f4ba5ed6..bcea59291 100644 --- a/src/V3ThreadPool.cpp +++ b/src/V3ThreadPool.cpp @@ -25,8 +25,10 @@ constexpr unsigned int V3ThreadPool::FUTUREWAITFOR_MS; void V3ThreadPool::resize(unsigned n) VL_MT_UNSAFE { // This function is not thread-safe and can result in race between threads - VerilatedLockGuard lock{m_mutex}; - VerilatedLockGuard stoppedJobsLock{m_stoppedJobsMutex}; + UASSERT(V3MutexConfig::s().lockConfig(), + "Mutex config needs to be locked before starting ThreadPool"); + V3LockGuard lock{m_mutex}; + V3LockGuard stoppedJobsLock{m_stoppedJobsMutex}; UASSERT(m_queue.empty(), "Resizing busy thread pool"); // Shut down old threads m_shutdown = true; @@ -57,7 +59,7 @@ void V3ThreadPool::workerJobLoop(int id) VL_MT_SAFE { waitIfStopRequested(); job_t job; { - VerilatedLockGuard lock(m_mutex); + V3LockGuard lock(m_mutex); m_cv.wait(lock, [&]() VL_REQUIRES(m_mutex) { return !m_queue.empty() || m_shutdown || m_stopRequested; }); @@ -82,7 +84,7 @@ void V3ThreadPool::pushJob(std::shared_ptr>& prom, f(); prom->set_value(); } else { - const VerilatedLockGuard lock{m_mutex}; + const V3LockGuard lock{m_mutex}; m_queue.push([prom, f] { f(); prom->set_value(); @@ -95,7 +97,7 @@ void V3ThreadPool::requestExclusiveAccess(const V3ThreadPool::job_t&& exclusiveA if (willExecuteSynchronously()) { exclusiveAccessJob(); } else { - VerilatedLockGuard stoppedJobLock{m_stoppedJobsMutex}; + V3LockGuard stoppedJobLock{m_stoppedJobsMutex}; // if some other job already requested exclusive access // wait until it stops if (stopRequested()) { waitStopRequested(stoppedJobLock); } @@ -110,14 +112,13 @@ void V3ThreadPool::requestExclusiveAccess(const V3ThreadPool::job_t&& exclusiveA } bool V3ThreadPool::waitIfStopRequested() VL_MT_SAFE { - VerilatedLockGuard stoppedJobLock(m_stoppedJobsMutex); + V3LockGuard stoppedJobLock(m_stoppedJobsMutex); if (!stopRequested()) return false; waitStopRequested(stoppedJobLock); return true; } -void V3ThreadPool::waitStopRequested(VerilatedLockGuard& stoppedJobLock) - VL_REQUIRES(m_stoppedJobsMutex) { +void V3ThreadPool::waitStopRequested(V3LockGuard& stoppedJobLock) VL_REQUIRES(m_stoppedJobsMutex) { ++m_stoppedJobs; m_stoppedJobsCV.notify_all(); m_stoppedJobsCV.wait( @@ -126,8 +127,8 @@ void V3ThreadPool::waitStopRequested(VerilatedLockGuard& stoppedJobLock) m_stoppedJobsCV.notify_all(); } -void V3ThreadPool::waitOtherThreads(VerilatedLockGuard& stoppedJobLock) - VL_MT_SAFE_EXCLUDES(m_mutex) VL_REQUIRES(m_stoppedJobsMutex) { +void V3ThreadPool::waitOtherThreads(V3LockGuard& stoppedJobLock) VL_MT_SAFE_EXCLUDES(m_mutex) + VL_REQUIRES(m_stoppedJobsMutex) { ++m_stoppedJobs; m_stoppedJobsCV.notify_all(); m_cv.notify_all(); @@ -139,7 +140,7 @@ void V3ThreadPool::waitOtherThreads(VerilatedLockGuard& stoppedJobLock) } void V3ThreadPool::selfTest() { - VerilatedMutex commonMutex; + V3Mutex commonMutex; int commonValue{0}; auto firstJob = [&](int sleep) -> void { @@ -151,7 +152,7 @@ void V3ThreadPool::selfTest() { }); }; auto secondJob = [&](int sleep) -> void { - VerilatedLockGuard lock{commonMutex}; + V3LockGuard lock{commonMutex}; lock.unlock(); s().waitIfStopRequested(); lock.lock(); @@ -159,7 +160,7 @@ void V3ThreadPool::selfTest() { commonValue = 1000; }; auto thirdJob = [&](int sleep) -> void { - VerilatedLockGuard lock{commonMutex}; + V3LockGuard lock{commonMutex}; std::this_thread::sleep_for(std::chrono::milliseconds{sleep}); lock.unlock(); s().requestExclusiveAccess([&]() { firstJob(sleep); }); diff --git a/src/V3ThreadPool.h b/src/V3ThreadPool.h index b074491be..76eaecfbb 100644 --- a/src/V3ThreadPool.h +++ b/src/V3ThreadPool.h @@ -17,7 +17,7 @@ #ifndef _V3THREADPOOL_H_ #define _V3THREADPOOL_H_ 1 -#include "verilated_threads.h" +#include "V3Mutex.h" #include #include @@ -34,7 +34,7 @@ class V3ThreadPool final { static constexpr unsigned int FUTUREWAITFOR_MS = 100; using job_t = std::function; - mutable VerilatedMutex m_mutex; // Mutex for use by m_queue + mutable V3Mutex m_mutex; // Mutex for use by m_queue std::queue m_queue VL_GUARDED_BY(m_mutex); // Queue of jobs // We don't need to guard this condition_variable as // both `notify_one` and `notify_all` functions are atomic, @@ -42,7 +42,7 @@ class V3ThreadPool final { // used by this condition_variable, so clang checks that we have mutex locked std::condition_variable_any m_cv; // Conditions to wake up workers std::list m_workers; // Worker threads - VerilatedMutex m_stoppedJobsMutex; // Used to signal stopped jobs + V3Mutex m_stoppedJobsMutex; // Used to signal stopped jobs // Conditions to wake up stopped jobs std::condition_variable_any m_stoppedJobsCV VL_GUARDED_BY(m_stoppedJobsMutex); std::atomic_uint m_stoppedJobs{0}; // Currently stopped jobs waiting for wake up @@ -54,7 +54,7 @@ class V3ThreadPool final { // CONSTRUCTORS V3ThreadPool() = default; ~V3ThreadPool() { - VerilatedLockGuard lock{m_mutex}; + V3LockGuard lock{m_mutex}; m_queue = {}; // make sure queue is empty lock.unlock(); resize(0); @@ -106,15 +106,15 @@ private: } bool stopRequestedStandalone() VL_MT_SAFE_EXCLUDES(m_stoppedJobsMutex) { - const VerilatedLockGuard lock{m_stoppedJobsMutex}; + const V3LockGuard lock{m_stoppedJobsMutex}; return stopRequested(); } // Waits until exclusive access job completes its job - void waitStopRequested(VerilatedLockGuard& stoppedJobLock) VL_REQUIRES(m_stoppedJobsMutex); + void waitStopRequested(V3LockGuard& stoppedJobLock) VL_REQUIRES(m_stoppedJobsMutex); // Waits until all other jobs are stopped - void waitOtherThreads(VerilatedLockGuard& stoppedJobLock) VL_MT_SAFE_EXCLUDES(m_mutex) + void waitOtherThreads(V3LockGuard& stoppedJobLock) VL_MT_SAFE_EXCLUDES(m_mutex) VL_REQUIRES(m_stoppedJobsMutex); template @@ -146,7 +146,7 @@ std::future V3ThreadPool::enqueue(std::function&& f) VL_MT_SAFE { std::shared_ptr> prom = std::make_shared>(); std::future result = prom->get_future(); pushJob(prom, std::move(f)); - const VerilatedLockGuard guard{m_mutex}; + const V3LockGuard guard{m_mutex}; m_cv.notify_one(); return result; } @@ -157,7 +157,7 @@ void V3ThreadPool::pushJob(std::shared_ptr>& prom, if (willExecuteSynchronously()) { prom->set_value(f()); } else { - const VerilatedLockGuard guard{m_mutex}; + const V3LockGuard guard{m_mutex}; m_queue.push([prom, f] { prom->set_value(f()); }); } } diff --git a/src/V3Waiver.cpp b/src/V3Waiver.cpp index 909a762bc..deb9ec6f7 100644 --- a/src/V3Waiver.cpp +++ b/src/V3Waiver.cpp @@ -26,8 +26,8 @@ void V3Waiver::addEntry(V3ErrorCode errorCode, const std::string& filename, const std::string& str) VL_MT_SAFE_EXCLUDES(s_mutex) { - const VerilatedLockGuard lock{s_mutex}; if (filename == V3Options::getStdPackagePath()) return; + const V3LockGuard lock{s_mutex}; std::stringstream entry; const size_t pos = str.find('\n'); entry << "lint_off -rule " << errorCode.ascii() << " -file \"*" << filename << "\" -match \"" @@ -51,12 +51,12 @@ void V3Waiver::write(const std::string& filename) VL_MT_SAFE_EXCLUDES(s_mutex) { *ofp << "// 2. Keep the waiver permanently if you are sure this is okay\n"; *ofp << "// 3. Keep the waiver temporarily to suppress the output\n\n"; - const VerilatedLockGuard lock{s_mutex}; + const V3LockGuard lock{s_mutex}; if (s_waiverList.empty()) *ofp << "// No waivers needed - great!\n"; for (const auto& i : s_waiverList) *ofp << "// " << i << "\n\n"; } -VerilatedMutex V3Waiver::s_mutex; +V3Mutex V3Waiver::s_mutex; V3Waiver::WaiverList V3Waiver::s_waiverList; diff --git a/src/V3Waiver.h b/src/V3Waiver.h index c8ca73137..8ad1e62dc 100644 --- a/src/V3Waiver.h +++ b/src/V3Waiver.h @@ -17,9 +17,8 @@ #ifndef VERILATOR_V3WAIVER_H_ #define VERILATOR_V3WAIVER_H_ -#include "verilated_threads.h" - #include "V3Error.h" +#include "V3Mutex.h" #include #include @@ -27,7 +26,7 @@ class V3Waiver final { // TYPES using WaiverList = std::vector; - static VerilatedMutex s_mutex; // Protect members + static V3Mutex s_mutex; // Protect members static WaiverList s_waiverList VL_GUARDED_BY(s_mutex); public: diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 785553361..a833335ea 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -590,6 +590,8 @@ static void verilate(const string& argString) { v3fatalSrc("VERILATOR_DEBUG_SKIP_IDENTICAL w/ --skip-identical: Changes found\n"); } // LCOV_EXCL_STOP + // Disable mutexes in single-thread verilation + V3MutexConfig::s().configure(v3Global.opt.verilateJobs() > 1 /*enable*/); // Adjust thread pool size V3ThreadPool::s().resize(v3Global.opt.verilateJobs()); From e38b359d756b0cb525162675eeaf8e870a273b18 Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Tue, 11 Apr 2023 13:25:10 +0200 Subject: [PATCH 127/155] Internals: Refactor for better clang thread-safety analysis (#4092) --- src/V3EmitCBase.cpp | 11 ++++++++--- src/V3EmitCBase.h | 4 +++- src/V3EmitCImp.cpp | 16 +++++++--------- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/V3EmitCBase.cpp b/src/V3EmitCBase.cpp index e8384456d..1bec37b9c 100644 --- a/src/V3EmitCBase.cpp +++ b/src/V3EmitCBase.cpp @@ -57,12 +57,17 @@ string EmitCBaseVisitorConst::funcNameProtect(const AstCFunc* nodep, const AstNo return name; } -AstCFile* EmitCBaseVisitorConst::newCFile(const string& filename, bool slow, bool source, - bool add) { +AstCFile* EmitCBaseVisitorConst::newCFile(const string& filename, bool slow, bool source) { + AstCFile* const cfilep = createCFile(filename, slow, source); + v3Global.rootp()->addFilesp(cfilep); + return cfilep; +} + +AstCFile* EmitCBaseVisitorConst::createCFile(const string& filename, bool slow, + bool source) VL_MT_SAFE { AstCFile* const cfilep = new AstCFile{v3Global.rootp()->fileline(), filename}; cfilep->slow(slow); cfilep->source(source); - if (add) v3Global.rootp()->addFilesp(cfilep); return cfilep; } diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index aef367177..e3c001be9 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -85,6 +85,7 @@ public: // METHODS V3OutCFile* ofp() const VL_MT_SAFE { return m_ofp; } void puts(const string& str) { ofp()->puts(str); } + void putsHeader() { ofp()->putsHeader(); } void putbs(const string& str) { ofp()->putbs(str); } void putsDecoration(const string& str) { if (v3Global.opt.decoration()) puts(str); @@ -106,7 +107,8 @@ public: static string topClassName() VL_MT_SAFE { // Return name of top wrapper module return v3Global.opt.prefix(); } - static AstCFile* newCFile(const string& filename, bool slow, bool source, bool add = true); + static AstCFile* newCFile(const string& filename, bool slow, bool source); + static AstCFile* createCFile(const string& filename, bool slow, bool source) VL_MT_SAFE; string cFuncArgs(const AstCFunc* nodep); void emitCFuncHeader(const AstCFunc* funcp, const AstNodeModule* modp, bool withScope); void emitCFuncDecl(const AstCFunc* funcp, const AstNodeModule* modp, bool cLinkage = false); diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index ee9a96306..f8b121040 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -174,8 +174,7 @@ class EmitCImp final : EmitCFunc { // Unfortunately we have some lint checks here, so we can't just skip processing. // We should move them to a different stage. const string filename = VL_DEV_NULL; - m_cfilesr.push_back( - newCFile(filename, /* slow: */ m_slow, /* source: */ true, /* add */ false)); + m_cfilesr.push_back(createCFile(filename, /* slow: */ m_slow, /* source: */ true)); m_ofp = new V3OutCFile{filename}; } else { string filename = v3Global.opt.makeDir() + "/" + prefixNameProtect(m_fileModp); @@ -185,12 +184,11 @@ class EmitCImp final : EmitCFunc { } if (m_slow) filename += "__Slow"; filename += ".cpp"; - m_cfilesr.push_back( - newCFile(filename, /* slow: */ m_slow, /* source: */ true, /* add */ false)); + m_cfilesr.push_back(createCFile(filename, /* slow: */ m_slow, /* source: */ true)); m_ofp = v3Global.opt.systemC() ? new V3OutScFile{filename} : new V3OutCFile{filename}; } - ofp()->putsHeader(); + putsHeader(); puts("// DESCRIPTION: Verilator output: Design implementation internals\n"); puts("// See " + topClassName() + ".h for the primary calling header\n"); @@ -597,7 +595,7 @@ class EmitCTrace final : EmitCFunc { if (m_slow) filename += "__Slow"; filename += ".cpp"; - AstCFile* const cfilep = newCFile(filename, m_slow, true /*source*/, false /*add*/); + AstCFile* const cfilep = createCFile(filename, m_slow, true /*source*/); cfilep->support(true); m_cfilesr.push_back(cfilep); @@ -606,9 +604,9 @@ class EmitCTrace final : EmitCFunc { } else { m_ofp = new V3OutCFile{filename}; } - m_ofp->putsHeader(); - m_ofp->puts("// DESCR" - "IPTION: Verilator output: Tracing implementation internals\n"); + putsHeader(); + puts("// DESCR" + "IPTION: Verilator output: Tracing implementation internals\n"); // Includes puts("#include \"" + v3Global.opt.traceSourceLang() + ".h\"\n"); From e1683afb3145de9e49efd5f78dde8ebcbff60c4a Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Wed, 12 Apr 2023 14:49:48 +0200 Subject: [PATCH 128/155] Internals: V3ThreadPool: add function waiting for list of futures (#4112) --- src/V3ThreadPool.cpp | 12 +++------- src/V3ThreadPool.h | 52 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 11 deletions(-) diff --git a/src/V3ThreadPool.cpp b/src/V3ThreadPool.cpp index bcea59291..47750a093 100644 --- a/src/V3ThreadPool.cpp +++ b/src/V3ThreadPool.cpp @@ -182,18 +182,12 @@ void V3ThreadPool::selfTest() { } futures.push_back(s().enqueue(std::bind(thirdJob, 100))); futures.push_back(s().enqueue(std::bind(thirdJob, 100))); - while (!futures.empty()) { - s().waitForFuture(futures.front()); - futures.pop_front(); - } + V3ThreadPool::waitForFutures(futures); s().waitIfStopRequested(); s().requestExclusiveAccess(std::bind(firstJob, 100)); auto forthJob = [&]() -> int { return 1234; }; std::list> futuresInt; futuresInt.push_back(s().enqueue(forthJob)); - while (!futuresInt.empty()) { - int result = s().waitForFuture(futuresInt.front()); - UASSERT(result == 1234, "unexpected future result = " << commonValue); - futuresInt.pop_front(); - } + auto result = V3ThreadPool::waitForFutures(futuresInt); + UASSERT(result.back() == 1234, "unexpected future result = " << result.back()); } diff --git a/src/V3ThreadPool.h b/src/V3ThreadPool.h index 76eaecfbb..c7f92195a 100644 --- a/src/V3ThreadPool.h +++ b/src/V3ThreadPool.h @@ -27,6 +27,19 @@ #include #include +namespace future_type { +template +struct return_type { + typedef std::list type; +}; + +template <> +struct return_type { + typedef void type; +}; + +} // namespace future_type + //============================================================================ class V3ThreadPool final { @@ -88,12 +101,47 @@ public: // Returns true if request was send and we waited, otherwise false bool waitIfStopRequested() VL_MT_SAFE; + // Waits for future. + // This function can be interupted by exclusive access request. + // When other thread requested exclusive access to processing, + // current thread is stopped and waits until it is resumed. + // Returns future result template - T waitForFuture(std::future& future) VL_MT_SAFE_EXCLUDES(m_mutex); + static T waitForFuture(std::future& future) VL_MT_SAFE_EXCLUDES(m_mutex); + + // Waits for list of futures + // This function can be interupted by exclusive access request. + // When other thread requested exclusive access to processing, + // current thread is stopped and waits until it is resumed. + // This function uses function overload instead of template + // specialization as C++11 requires them to be inside namespace scope + // Returns list of future result or void + template + static typename future_type::return_type::type + waitForFutures(std::list>& futures) { + return waitForFuturesImp(futures); + } static void selfTest(); private: + template + static typename future_type::return_type::type + waitForFuturesImp(std::list>& futures) { + typename future_type::return_type::type results; + while (!futures.empty()) { + results.push_back(V3ThreadPool::waitForFuture(futures.front())); + futures.pop_front(); + } + return results; + } + + static void waitForFuturesImp(std::list>& futures) { + while (!futures.empty()) { + V3ThreadPool::waitForFuture(futures.front()); + futures.pop_front(); + } + } bool willExecuteSynchronously() const VL_MT_SAFE { return m_workers.empty() || m_exclusiveAccess; } @@ -128,7 +176,7 @@ private: template T V3ThreadPool::waitForFuture(std::future& future) VL_MT_SAFE_EXCLUDES(m_mutex) { while (true) { - waitIfStopRequested(); + V3ThreadPool::s().waitIfStopRequested(); { std::future_status status = future.wait_for(std::chrono::milliseconds(V3ThreadPool::FUTUREWAITFOR_MS)); From 37e7b5dfc7836f7be7310a097d6129d746287b89 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Thu, 13 Apr 2023 12:11:39 +0100 Subject: [PATCH 129/155] Fix unused/hard-coded argument No functional change. --- src/V3Sched.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/V3Sched.cpp b/src/V3Sched.cpp index c1652e040..71e6ecdc9 100644 --- a/src/V3Sched.cpp +++ b/src/V3Sched.cpp @@ -311,10 +311,11 @@ struct TriggerKit { // No VL_UNCOPYABLE(TriggerKit) as causes C++20 errors on MSVC // Utility that assigns the given index trigger to fire when the given variable is zero - void addFirstIterationTriggerAssignment(AstVarScope* counterp, uint32_t /*index*/) const { + void addFirstIterationTriggerAssignment(AstVarScope* counterp, uint32_t index) const { FileLine* const flp = counterp->fileline(); AstVarRef* const vrefp = new AstVarRef{flp, m_vscp, VAccess::WRITE}; - AstCMethodHard* const callp = new AstCMethodHard{flp, vrefp, "at", new AstConst{flp, 0}}; + AstCMethodHard* const callp + = new AstCMethodHard{flp, vrefp, "at", new AstConst{flp, index}}; callp->dtypeSetBit(); callp->pure(true); m_funcp->stmtsp()->addHereThisAsNext(new AstAssign{ From 23f90b13f34bd6286cc42561bcd0c05a03a88090 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Thu, 13 Apr 2023 14:01:16 +0100 Subject: [PATCH 130/155] Do not create unnecessary DPI AstSenTrees No functional change --- src/V3Sched.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/V3Sched.cpp b/src/V3Sched.cpp index 71e6ecdc9..9f8896641 100644 --- a/src/V3Sched.cpp +++ b/src/V3Sched.cpp @@ -355,6 +355,7 @@ struct EvalKit { // Create an AstSenTree that is sensitive to the given trigger index. Must not exist yet! AstSenTree* createTriggerSenTree(AstNetlist* netlistp, AstVarScope* const vscp, uint32_t index) { + UASSERT_OBJ(index != std::numeric_limits::max(), netlistp, "Invalid trigger index"); AstTopScope* const topScopep = netlistp->topScopep(); FileLine* const flp = topScopep->fileline(); AstVarRef* const vrefp = new AstVarRef{flp, vscp, VAccess::READ}; @@ -752,7 +753,8 @@ AstNode* createInputCombLoop(AstNetlist* netlistp, AstCFunc* const initFuncp, // The DPI Export trigger AstSenTree* const dpiExportTriggered - = createTriggerSenTree(netlistp, trig.m_vscp, dpiExportTriggerIndex); + = dpiExportTriggerVscp ? createTriggerSenTree(netlistp, trig.m_vscp, dpiExportTriggerIndex) + : nullptr; // Create and Order the body function AstCFunc* const icoFuncp @@ -1112,7 +1114,9 @@ void schedule(AstNetlist* netlistp) { // The DPI Export trigger AstSenTree AstSenTree* const dpiExportTriggeredAct - = createTriggerSenTree(netlistp, actTrig.m_vscp, dpiExportTriggerIndex); + = dpiExportTriggerVscp + ? createTriggerSenTree(netlistp, actTrig.m_vscp, dpiExportTriggerIndex) + : nullptr; AstCFunc* const actFuncp = V3Order::order( netlistp, {&logicRegions.m_pre, &logicRegions.m_act, &logicReplicas.m_act}, trigToSenAct, @@ -1140,7 +1144,9 @@ void schedule(AstNetlist* netlistp) { invertAndMergeSenTreeMap(trigToSen, trigMap); AstSenTree* const dpiExportTriggered - = createTriggerSenTree(netlistp, trigVscp, dpiExportTriggerIndex); + = dpiExportTriggerVscp + ? createTriggerSenTree(netlistp, trigVscp, dpiExportTriggerIndex) + : nullptr; const auto& timingDomains = timingKit.remapDomains(trigMap); AstCFunc* const funcp = V3Order::order( From fa16eff003b78dcebe5fa77a9ff98a0aa26657be Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 13 Apr 2023 22:09:55 -0400 Subject: [PATCH 131/155] Commentary (#4118) --- docs/guide/simulating.rst | 17 +++++++++++++++++ docs/guide/warnings.rst | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/docs/guide/simulating.rst b/docs/guide/simulating.rst index b65573be1..5f9440da9 100644 --- a/docs/guide/simulating.rst +++ b/docs/guide/simulating.rst @@ -498,3 +498,20 @@ Clang. The process in GCC 10 was as follows: Clang and GCC also support -fauto-profile, which uses sample-based feedback-directed optimization. See the appropriate compiler documentation. + + +.. _Runtime Debugging + +Runtime Debugging +================= + +To debug a Verilated executable, use the standard GNU debugger ``gdb`` or a +similar tool. Typically you will want to have debugger symbols inserted by +the compiler, assertions enabled in the C library, and assertions enabled +in the Verilated library. (These options slow down the executable, so do +this only when debugging.) To enable this, Verilate with: + + -CFLAGS -ggdb -LDFLAGS -ggdb -CFLAGS -DVL_DEBUG=1 -CFLAGS -D_GLIBCXX_DEBUG + +The :vlopt:`-CFLAGS` and/or :vlopt:`-LDFLAGS` options pass arguments +directly to the compiler or linker. diff --git a/docs/guide/warnings.rst b/docs/guide/warnings.rst index 1a754c8f6..b88f2ce20 100644 --- a/docs/guide/warnings.rst +++ b/docs/guide/warnings.rst @@ -878,7 +878,7 @@ List Of Warnings .. TODO better example - The naming of this worning is in contradiction with the common + The naming of this warning is in contradiction with the common interpretation of little endian. It was therefore renamed to :option:`ASCRANGE`. While :option:`LITENDIAN` remains for backwards compatibility, new projects should use :option:`ASCRANGE`. From f95ce886f1b3f5b98e2ebb658f2145535975c377 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Fri, 14 Apr 2023 12:51:33 +0200 Subject: [PATCH 132/155] Fix duplicating parameter class types (#4115) --- src/V3AstNodeDType.h | 5 +---- src/V3AstNodes.cpp | 9 +++++++++ src/V3Param.cpp | 3 ++- test_regress/t/t_class_param_type.v | 20 ++++++++++++++++++++ 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/V3AstNodeDType.h b/src/V3AstNodeDType.h index 41c512617..10d90c33f 100644 --- a/src/V3AstNodeDType.h +++ b/src/V3AstNodeDType.h @@ -402,10 +402,7 @@ public: ASTGEN_MEMBERS_AstBasicDType; void dump(std::ostream& str) const override; // width/widthMin/numeric compared elsewhere - bool same(const AstNode* samep) const override { - const AstBasicDType* const sp = static_cast(samep); - return m == sp->m; - } + bool same(const AstNode* samep) const override; bool similarDType(const AstNodeDType* samep) const override { return type() == samep->type() && same(samep); } diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 9f2dc67bb..a88ef0a06 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -233,6 +233,15 @@ int AstBasicDType::widthTotalBytes() const { } } +bool AstBasicDType::same(const AstNode* samep) const { + const AstBasicDType* const sp = static_cast(samep); + if (!rangep() && !sp->rangep() && m == sp->m) { + return true; + } else { + return m == sp->m && rangep() && rangep()->sameTree(sp->rangep()); + } +} + int AstNodeUOrStructDType::widthTotalBytes() const { if (width() <= 8) { return 1; diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 741d102d8..b10521f90 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -342,6 +342,7 @@ class ParamProcessor final { // TODO: This parameter value number lookup via a constructed key string is not // particularly robust for type parameters. We should really have a type // equivalence predicate function. + if (const AstRefDType* const refp = VN_CAST(nodep, RefDType)) nodep = refp->skipRefp(); const string key = paramValueKey(nodep); // cppcheck-has-bug-suppress unreadVariable V3Hash hash = V3Hasher::uncachedHash(nodep); @@ -705,7 +706,7 @@ class ParamProcessor final { << modvarp->prettyNameQ()); } else { UINFO(9, "Parameter type assignment expr=" << exprp << " to " << origp << endl); - if (exprp->sameTree(origp)) { + if (exprp->similarDType(origp)) { // Setting parameter to its default value. Just ignore it. // This prevents making additional modules, and makes coverage more // obvious as it won't show up under a unique module page name. diff --git a/test_regress/t/t_class_param_type.v b/test_regress/t/t_class_param_type.v index 1501f0819..45a1b78ed 100644 --- a/test_regress/t/t_class_param_type.v +++ b/test_regress/t/t_class_param_type.v @@ -18,12 +18,32 @@ class Cls; endfunction endclass +class ParclsDefaultType #(type T=Cls); + static function int get_p; + return T::get_p(); + endfunction +endclass + typedef Cls cls_t; typedef cls_t cls2_t; module t (/*AUTOARG*/); initial begin + automatic ParclsDefaultType#(Cls) pdt1 = new; + automatic ParclsDefaultType#(cls_t) pdt2 = pdt1; + automatic ParclsDefaultType#(cls2_t) pdt3 = pdt2; + automatic Parcls#(Cls) p1 = new; + automatic Parcls#(cls_t) p2 = p1; + automatic Parcls#(cls2_t) p3 = p2; + + if (pdt1 != pdt2) $stop; + if (pdt2 != pdt3) $stop; + if (p1 != p2) $stop; + if (p2 != p3) $stop; + + if (p1.get_p() != 20) $stop; + if (pdt1.get_p() != 20) $stop; if (Parcls#(cls2_t)::get_p() != 20) $stop; $write("*-* All Finished *-*\n"); From d1b80ffa2919dd337d8f75bb7e7d8d2f43cab193 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Fri, 14 Apr 2023 14:52:43 +0200 Subject: [PATCH 133/155] Support parameterized return types of methods (#4122) --- src/V3Param.cpp | 3 +++ test_regress/t/t_class_param_type.v | 31 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/V3Param.cpp b/src/V3Param.cpp index b10521f90..977a0a803 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -546,6 +546,9 @@ class ParamProcessor final { } void replaceRefsRecurse(AstNode* const nodep, const AstClass* const oldClassp, AstClass* const newClassp) { + // Some of the nodes may be already marked as visited, because they were copied. They + // should be marked as unvisited, because parameterized references have to be handled. + nodep->user5(false); if (AstClassRefDType* const classRefp = VN_CAST(nodep, ClassRefDType)) { if (classRefp->classp() == oldClassp) classRefp->classp(newClassp); } else if (AstClassOrPackageRef* const classRefp = VN_CAST(nodep, ClassOrPackageRef)) { diff --git a/test_regress/t/t_class_param_type.v b/test_regress/t/t_class_param_type.v index 45a1b78ed..31402e10a 100644 --- a/test_regress/t/t_class_param_type.v +++ b/test_regress/t/t_class_param_type.v @@ -27,6 +27,23 @@ endclass typedef Cls cls_t; typedef cls_t cls2_t; +class Singleton #(type T=int); + static function Singleton#(T) self; + Singleton#(T) c = new; + return c; + endfunction + function int get_size; + return $bits(T); + endfunction +endclass + +class SingletonUnusedDefault #(type T=int); + static function SingletonUnusedDefault#(T) self; + SingletonUnusedDefault#(T) c = new; + return c; + endfunction +endclass + module t (/*AUTOARG*/); initial begin @@ -37,11 +54,25 @@ module t (/*AUTOARG*/); automatic Parcls#(cls_t) p2 = p1; automatic Parcls#(cls2_t) p3 = p2; + automatic Singleton #(int) s_int1 = Singleton#(int)::self(); + automatic Singleton #(int) s_int2 = Singleton#(int)::self(); + automatic Singleton #(bit) s_bit1 = Singleton#(bit)::self(); + automatic Singleton #(bit) s_bit2 = Singleton#(bit)::self(); + automatic SingletonUnusedDefault #(bit) sud1 = SingletonUnusedDefault#(bit)::self(); + automatic SingletonUnusedDefault #(bit) sud2 = SingletonUnusedDefault#(bit)::self(); + if (pdt1 != pdt2) $stop; if (pdt2 != pdt3) $stop; if (p1 != p2) $stop; if (p2 != p3) $stop; + if (s_int1 != s_int2) $stop; + if (s_bit1 != s_bit2) $stop; + if (sud1 != sud2) $stop; + + if (s_int1.get_size() != 32) $stop; + if (s_bit1.get_size() != 1) $stop; + if (p1.get_p() != 20) $stop; if (pdt1.get_p() != 20) $stop; if (Parcls#(cls2_t)::get_p() != 20) $stop; From 7d3b3761b28b4923decb4935321a6e7a997687aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Boro=C5=84ski?= <94375110+kboronski-ant@users.noreply.github.com> Date: Fri, 14 Apr 2023 17:53:27 +0200 Subject: [PATCH 134/155] Fix including __Syms header in generated C++ files (#4123) --- src/V3EmitCImp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index f8b121040..679f392ce 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -196,6 +196,7 @@ class EmitCImp final : EmitCFunc { puts("\n#include \"verilated.h\"\n"); if (v3Global.dpi()) puts("#include \"verilated_dpi.h\"\n"); puts("\n"); + puts("#include \"" + symClassName() + ".h\"\n"); for (const string& name : headers) puts("#include \"" + name + ".h\"\n"); emitTextSection(m_modp, VNType::atScImpHdr); From 754a0b832008a3bfc6d5e2cc3f2de26311e49851 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Boro=C5=84ski?= <94375110+kboronski-ant@users.noreply.github.com> Date: Sat, 15 Apr 2023 00:52:05 +0200 Subject: [PATCH 135/155] Fix to use parallel build for projects with a lot of files (#4116) --- src/V3EmitMk.h | 3 +++ src/Verilator.cpp | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/src/V3EmitMk.h b/src/V3EmitMk.h index a23748fb0..0ddfdba66 100644 --- a/src/V3EmitMk.h +++ b/src/V3EmitMk.h @@ -26,6 +26,9 @@ class V3HierBlockPlan; class V3EmitMk final { public: + // Number of source files after which to use parallel compiles + static const size_t PARALLEL_FILE_CNT_THRESHOLD = 128; + static void emitmk(); static void emitHierVerilation(const V3HierBlockPlan* planp); }; diff --git a/src/Verilator.cpp b/src/Verilator.cpp index a833335ea..294320613 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -565,6 +565,13 @@ static void process() { reportStatsIfEnabled(); if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && !v3Global.opt.dpiHdrOnly()) { + size_t src_f_cnt = 0; + for (AstNode* nodep = v3Global.rootp()->filesp(); nodep; nodep = nodep->nextp()) { + if (const AstCFile* cfilep = VN_CAST(nodep, CFile)) + src_f_cnt += cfilep->source() ? 1 : 0; + } + if (src_f_cnt >= V3EmitMk::PARALLEL_FILE_CNT_THRESHOLD) v3Global.useParallelBuild(true); + // Makefile must be after all other emitters if (v3Global.opt.main()) V3EmitCMain::emit(); if (v3Global.opt.cmake()) V3EmitCMake::emit(); From 7f49b6c1020680eb323875b68c8a449f0c15c750 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 16 Apr 2023 17:23:16 -0400 Subject: [PATCH 136/155] Parse 'let' as unsupported --- src/verilog.l | 2 +- src/verilog.y | 50 +++++++++++++++++++++++++++++++++--- test_regress/t/t_let.out | 41 +++++++++++++++++++++++++++++ test_regress/t/t_let.pl | 23 +++++++++++++++++ test_regress/t/t_let.v | 36 ++++++++++++++++++++++++++ test_regress/t/t_let_bad.out | 11 ++++++++ test_regress/t/t_let_bad.pl | 19 ++++++++++++++ test_regress/t/t_let_bad.v | 20 +++++++++++++++ 8 files changed, 198 insertions(+), 4 deletions(-) create mode 100644 test_regress/t/t_let.out create mode 100755 test_regress/t/t_let.pl create mode 100644 test_regress/t/t_let.v create mode 100644 test_regress/t/t_let_bad.out create mode 100755 test_regress/t/t_let_bad.pl create mode 100644 test_regress/t/t_let_bad.v diff --git a/src/verilog.l b/src/verilog.l index 985f89b6a..eec6be4ed 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -599,7 +599,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "eventually" { FL; return yEVENTUALLY; } "global" { FL; return yGLOBAL__LEX; } "implies" { FL; return yIMPLIES; } - "let" { ERROR_RSVD_WORD("SystemVerilog 2009"); } + "let" { FL; return yLET; } "nexttime" { FL; return yNEXTTIME; } "reject_on" { FL; return yREJECT_ON; } "s_always" { FL; return yS_ALWAYS; } diff --git a/src/verilog.y b/src/verilog.y index a7c3c70ff..844853f10 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -645,7 +645,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yJOIN "join" %token yJOIN_ANY "join_any" %token yJOIN_NONE "join_none" -//UNSUP %token yLET "let" +%token yLET "let" %token yLOCALPARAM "localparam" %token yLOCAL__COLONCOLON "local-then-::" %token yLOCAL__ETC "local" @@ -1815,6 +1815,7 @@ modportSimplePortOrTFPort:// IEEE: modport_simple_port or modport_tf_port, | '.' idAny '(' ')' { $$ = $2; BBUNSUP($1, "Unsupported: Modport dotted port name"); } | '.' idAny '(' expr ')' { $$ = $2; BBUNSUP($1, "Unsupported: Modport dotted port name"); } ; + //************************************************ // Variable Declarations @@ -3450,7 +3451,7 @@ block_item_declarationList: // IEEE: [ block_item_declaration ] block_item_declaration: // ==IEEE: block_item_declaration data_declaration { $$ = $1; } | parameter_declaration ';' { $$ = $1; } - //UNSUP let_declaration { $$ = $1; } + | let_declaration { $$ = $1; } ; stmtList: @@ -5151,6 +5152,49 @@ stream_expressionOrDataType: // IEEE: from streaming_concatenation { $$ = $1; BBUNSUP($2, "Unsupported: with[] stream expression"); } ; +//************************************************ +// Let + +letId: // IEEE: pert of let_declaration + idAny/*let_identifieer*/ + { $$ = $1; + $$ = nullptr; + // No unsupported message as caller has one, for now just use a func + $$ = new AstFunc{$$, *$1, nullptr, nullptr}; + SYMP->pushNewUnderNodeOrCurrent($$, $$); } + ; + +let_declaration: // IEEE: let_declaration + yLET letId '=' expr ';' + { $$ = nullptr; + SYMP->popScope($2); + BBUNSUP($1, "Unsupported: let"); } + | yLET letId '(' let_port_listE ')' '=' expr ';' + { $$ = nullptr; + SYMP->popScope($2); + BBUNSUP($1, "Unsupported: let"); } + ; + +let_port_listE: // IEEE: [ let_port_list ] + /*empty*/ { $$ = nullptr; } + | let_port_list { $$ = $1; } + ; + +let_port_list: // IEEE: let_port_list + let_port_item { $$ = $1; } + | let_port_list ',' let_port_item { $$ = addNextNull($1, $3); } + ; + +let_port_item: // IEEE: let_port_Item + // // IEEE: Expanded let_formal_type + yUNTYPED idAny/*formal_port_identifier*/ variable_dimensionListE exprEqE + { $$ = nullptr; BBUNSUP($1, "Unsupported: let untyped ports"); } + | data_type id/*formal_port_identifier*/ variable_dimensionListE exprEqE + { $$ = nullptr; BBUNSUP($1, "Unsupported: let ports"); } + | implicit_typeE id/*formal_port_identifier*/ variable_dimensionListE exprEqE + { $$ = nullptr; BBUNSUP($1, "Unsupported: let ports"); } + ; + //************************************************ // Gate declarations @@ -5697,7 +5741,7 @@ cycle_delay: // IEEE: cycle_delay assertion_item_declaration: // ==IEEE: assertion_item_declaration property_declaration { $$ = $1; } | sequence_declaration { $$ = $1; } - //UNSUP let_declaration { $$ = $1; } + | let_declaration { $$ = $1; } ; assertion_item: // ==IEEE: assertion_item diff --git a/test_regress/t/t_let.out b/test_regress/t/t_let.out new file mode 100644 index 000000000..aca0f5993 --- /dev/null +++ b/test_regress/t/t_let.out @@ -0,0 +1,41 @@ +%Error-UNSUPPORTED: t/t_let.v:8:4: Unsupported: let + 8 | let P = 11; + | ^~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_let.v:13:4: Unsupported: let + 13 | let A = 10; + | ^~~ +%Error-UNSUPPORTED: t/t_let.v:14:4: Unsupported: let + 14 | let B() = 20; + | ^~~ +%Error-UNSUPPORTED: t/t_let.v:13:14: Unsupported: let ports + 13 | let A = 10; + | ^ +%Error-UNSUPPORTED: t/t_let.v:15:4: Unsupported: let + 15 | let C(a) = 30 + a; + | ^~~ +%Error-UNSUPPORTED: t/t_let.v:15:13: Unsupported: let ports + 15 | let C(a) = 30 + a; + | ^ +%Error-UNSUPPORTED: t/t_let.v:16:4: Unsupported: let + 16 | let D(a, b) = 30 + a + b; + | ^~~ +%Error-UNSUPPORTED: t/t_let.v:16:16: Unsupported: let ports + 16 | let D(a, b) = 30 + a + b; + | ^ +%Error-UNSUPPORTED: t/t_let.v:17:4: Unsupported: let + 17 | let E(a, b=7) = 30 + a + b; + | ^~~ +%Error-UNSUPPORTED: t/t_let.v:18:10: Unsupported: let untyped ports + 18 | let F(untyped a) = 30 + a; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_let.v:18:4: Unsupported: let + 18 | let F(untyped a) = 30 + a; + | ^~~ +%Error-UNSUPPORTED: t/t_let.v:19:10: Unsupported: let ports + 19 | let G(int a) = 30 + a; + | ^~~ +%Error-UNSUPPORTED: t/t_let.v:19:4: Unsupported: let + 19 | let G(int a) = 30 + a; + | ^~~ +%Error: Exiting due to diff --git a/test_regress/t/t_let.pl b/test_regress/t/t_let.pl new file mode 100755 index 000000000..c18ffc8f0 --- /dev/null +++ b/test_regress/t/t_let.pl @@ -0,0 +1,23 @@ +#!/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(vlt => 1); + +compile( + expect_filename => $Self->{golden_filename}, + fails => 1, + ); + +#execute( +# check_finished => 1, +# ); + +ok(1); +1; diff --git a/test_regress/t/t_let.v b/test_regress/t/t_let.v new file mode 100644 index 000000000..b8d010fb3 --- /dev/null +++ b/test_regress/t/t_let.v @@ -0,0 +1,36 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +package Pkg; + let P = 11; +endpackage + +module t(/*AUTOARG*/); + + let A = 10; + let B() = 20; + let C(a) = 30 + a; + let D(a, b) = 30 + a + b; + let E(a, b=7) = 30 + a + b; + let F(untyped a) = 30 + a; + let G(int a) = 30 + a; + + initial begin + if (A != 10) $stop; + if (A() != 10) $stop; + if (B != 20) $stop; + if (B() != 20) $stop; + if (C(1) != (30 + 1)) $stop; + if (D(1, 2) != (30 + 1 + 2)) $stop; + if (E(1) != (30 + 1 + 7)) $stop; + if (F(1) != (30 + 1)) $stop; + if (G(1) != (30 + 1)) $stop; + if (Pkg::P != 11) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_let_bad.out b/test_regress/t/t_let_bad.out new file mode 100644 index 000000000..ce76ac770 --- /dev/null +++ b/test_regress/t/t_let_bad.out @@ -0,0 +1,11 @@ +%Error-UNSUPPORTED: t/t_let_bad.v:9:4: Unsupported: let + 9 | let NO_ARG = 10; + | ^~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_let_bad.v:9:19: Unsupported: let ports + 9 | let NO_ARG = 10; + | ^ +%Error-UNSUPPORTED: t/t_let_bad.v:10:4: Unsupported: let + 10 | let ONE_ARG(a) = 10; + | ^~~ +%Error: Exiting due to diff --git a/test_regress/t/t_let_bad.pl b/test_regress/t/t_let_bad.pl new file mode 100755 index 000000000..882bc2418 --- /dev/null +++ b/test_regress/t/t_let_bad.pl @@ -0,0 +1,19 @@ +#!/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(linter => 1); + +compile( + expect_filename => $Self->{golden_filename}, + fails => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_let_bad.v b/test_regress/t/t_let_bad.v new file mode 100644 index 000000000..816b46651 --- /dev/null +++ b/test_regress/t/t_let_bad.v @@ -0,0 +1,20 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + + let NO_ARG = 10; + let ONE_ARG(a) = 10; + + initial begin + if (NO_ARG(10) != 10) $stop; // BAD + if (ONE_ARG() != 10) $stop; // BAD + if (ONE_ARG(10, 20) != 10) $stop; // BAD + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From df86e39845220b6d64cb448f0307d44e9756e32c Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Mon, 17 Apr 2023 09:57:29 +0000 Subject: [PATCH 137/155] Fix systemc namespace issues (#4126) (#4127) * replaces use of "systemc.h" with to avoid default namespace import --- docs/CONTRIBUTORS | 1 + examples/make_hello_sc/sc_main.cpp | 4 +++- examples/make_tracing_sc/sc_main.cpp | 4 +++- include/verilated.h | 14 +++++++------- include/verilated_fst_sc.h | 22 +++++++++++----------- include/verilated_funcs.h | 2 +- include/verilated_sc.h | 6 +++--- include/verilated_vcd_sc.h | 18 +++++++++--------- 8 files changed, 38 insertions(+), 33 deletions(-) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 404584aba..40c782fb0 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -29,6 +29,7 @@ Drew Taussig Driss Hafdi Edgar E. Iglesias Eric Rippey +Eyck Jentzsch Fan Shupei Felix Neumärker Felix Yan diff --git a/examples/make_hello_sc/sc_main.cpp b/examples/make_hello_sc/sc_main.cpp index 91fe02220..5f9ab2429 100644 --- a/examples/make_hello_sc/sc_main.cpp +++ b/examples/make_hello_sc/sc_main.cpp @@ -7,7 +7,7 @@ //====================================================================== // SystemC global header -#include +#include // Include common routines #include @@ -15,6 +15,8 @@ // Include model header, generated from Verilating "top.v" #include "Vtop.h" +using namespace sc_core; + int sc_main(int argc, char* argv[]) { // See a similar example walkthrough in the verilator manpage. diff --git a/examples/make_tracing_sc/sc_main.cpp b/examples/make_tracing_sc/sc_main.cpp index 223cce885..44e69c7f0 100644 --- a/examples/make_tracing_sc/sc_main.cpp +++ b/examples/make_tracing_sc/sc_main.cpp @@ -10,7 +10,7 @@ #include // SystemC global header -#include +#include // Include common routines #include @@ -23,6 +23,8 @@ // Include model header, generated from Verilating "top.v" #include "Vtop.h" +using namespace sc_core; + int sc_main(int argc, char* argv[]) { // This is a more complicated example, please also see the simpler examples/make_hello_c. diff --git a/include/verilated.h b/include/verilated.h index 02de0ea12..a1bad1d49 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -953,18 +953,18 @@ void VerilatedContext::timeprecision(int value) VL_MT_SAFE { const VerilatedLockGuard lock{m_mutex}; m_s.m_timeprecision = value; #if VM_SC - const sc_time sc_res = sc_get_time_resolution(); - if (sc_res == sc_time(1, SC_SEC)) { + const sc_core::sc_time sc_res = sc_core::sc_get_time_resolution(); + if (sc_res == sc_core::sc_time(1, sc_core::SC_SEC)) { sc_prec = 0; - } else if (sc_res == sc_time(1, SC_MS)) { + } else if (sc_res == sc_core::sc_time(1, sc_core::SC_MS)) { sc_prec = 3; - } else if (sc_res == sc_time(1, SC_US)) { + } else if (sc_res == sc_core::sc_time(1, sc_core::SC_US)) { sc_prec = 6; - } else if (sc_res == sc_time(1, SC_NS)) { + } else if (sc_res == sc_core::sc_time(1, sc_core::SC_NS)) { sc_prec = 9; - } else if (sc_res == sc_time(1, SC_PS)) { + } else if (sc_res == sc_core::sc_time(1, sc_core::SC_PS)) { sc_prec = 12; - } else if (sc_res == sc_time(1, SC_FS)) { + } else if (sc_res == sc_core::sc_time(1, sc_core::SC_FS)) { sc_prec = 15; } #endif diff --git a/include/verilated_fst_sc.h b/include/verilated_fst_sc.h index 0f0cc9e2d..af288f11b 100644 --- a/include/verilated_fst_sc.h +++ b/include/verilated_fst_sc.h @@ -19,8 +19,8 @@ /// //============================================================================= -#ifndef VERILATOR_VERILATED_VCD_SC_H_ -#define VERILATOR_VERILATED_VCD_SC_H_ +#ifndef VERILATOR_VERILATED_FST_SC_H_ +#define VERILATOR_VERILATED_FST_SC_H_ #include "verilatedos.h" @@ -36,23 +36,23 @@ /// with the SystemC simulation kernel, just like a SystemC-documented /// trace format. -class VerilatedFstSc final : sc_trace_file, public VerilatedFstC { +class VerilatedFstSc final : sc_core::sc_trace_file, public VerilatedFstC { // CONSTRUCTORS VL_UNCOPYABLE(VerilatedFstSc); public: /// Construct a SC trace object, and register with the SystemC kernel VerilatedFstSc() { - sc_get_curr_simcontext()->add_trace_file(this); + sc_core::sc_get_curr_simcontext()->add_trace_file(this); // We want to avoid a depreciated warning, but still be back compatible. // Turning off the message just for this still results in an // annoying "to turn off" message. - const sc_time t1sec{1, SC_SEC}; + const sc_core::sc_time t1sec{1, sc_core::SC_SEC}; if (t1sec.to_default_time_units() != 0) { - const sc_time tunits{1.0 / t1sec.to_default_time_units(), SC_SEC}; + const sc_core::sc_time tunits{1.0 / t1sec.to_default_time_units(), sc_core::SC_SEC}; spTrace()->set_time_unit(tunits.to_string()); } - spTrace()->set_time_resolution(sc_get_time_resolution().to_string()); + spTrace()->set_time_resolution(sc_core::sc_get_time_resolution().to_string()); } /// Destruct, flush, and close the dump ~VerilatedFstSc() override { close(); } @@ -60,7 +60,7 @@ public: // METHODS - for SC kernel // Called by SystemC simulate() void cycle(bool delta_cycle) override { - if (!delta_cycle) this->dump(sc_time_stamp().to_double()); + if (!delta_cycle) this->dump(sc_core::sc_time_stamp().to_double()); } // Override VerilatedFstC. Must be called after starting simulation. @@ -79,7 +79,7 @@ private: // Cadence Incisive has these as abstract functions so we must create them void set_time_unit(int exponent10_seconds) override {} // deprecated #endif - void set_time_unit(double v, sc_time_unit tu) override {} // LCOV_EXCL_LINE + void set_time_unit(double v, sc_core::sc_time_unit tu) override {} // LCOV_EXCL_LINE //-------------------------------------------------- // SystemC 2.1.v1 @@ -96,8 +96,8 @@ private: // Formatting matches that of sc_trace.h // LCOV_EXCL_START #if (SYSTEMC_VERSION >= 20171012) - DECL_TRACE_METHOD_A( sc_event ) - DECL_TRACE_METHOD_A( sc_time ) + DECL_TRACE_METHOD_A( sc_core::sc_event ) + DECL_TRACE_METHOD_A( sc_core::sc_time ) #endif DECL_TRACE_METHOD_A( bool ) diff --git a/include/verilated_funcs.h b/include/verilated_funcs.h index 6a1696e6f..983f19b4c 100644 --- a/include/verilated_funcs.h +++ b/include/verilated_funcs.h @@ -260,7 +260,7 @@ extern void _vl_debug_print_w(int lbits, WDataInP const iwp) VL_MT_SAFE; #if defined(SYSTEMC_VERSION) /// Return current simulation time // Already defined: extern sc_time sc_time_stamp(); -inline uint64_t vl_time_stamp64() VL_MT_SAFE { return sc_time_stamp().value(); } +inline uint64_t vl_time_stamp64() VL_MT_SAFE { return sc_core::sc_time_stamp().value(); } #else // Non-SystemC # if !defined(VL_TIME_CONTEXT) && !defined(VL_NO_LEGACY) # ifdef VL_TIME_STAMP64 diff --git a/include/verilated_sc.h b/include/verilated_sc.h index da6c479ba..81777c3c9 100644 --- a/include/verilated_sc.h +++ b/include/verilated_sc.h @@ -29,7 +29,7 @@ #include "verilatedos.h" -#include "systemc.h" +#include //============================================================================= // For \internal use, get a pointer to m_data in the sc_bv_base class, @@ -37,9 +37,9 @@ // use cast magic to get at it. Saves patching get_datap in SystemC. #define VL_SC_BV_DATAP(bv) (VlScBvExposer::sp_datap(bv)) // This class is thread safe (though most of SystemC is not). -class VlScBvExposer final : public sc_bv_base { +class VlScBvExposer final : public sc_dt::sc_bv_base { public: - static const uint32_t* sp_datap(const sc_bv_base& base) VL_MT_SAFE { + static const uint32_t* sp_datap(const sc_dt::sc_bv_base& base) VL_MT_SAFE { return static_cast(&base)->sp_datatp(); } const uint32_t* sp_datatp() const { return reinterpret_cast(m_data); } diff --git a/include/verilated_vcd_sc.h b/include/verilated_vcd_sc.h index 4ef558fb4..53d5efe43 100644 --- a/include/verilated_vcd_sc.h +++ b/include/verilated_vcd_sc.h @@ -36,23 +36,23 @@ /// with the SystemC simulation kernel, just like a SystemC-documented /// trace format. -class VerilatedVcdSc final : sc_trace_file, public VerilatedVcdC { +class VerilatedVcdSc final : sc_core::sc_trace_file, public VerilatedVcdC { // CONSTRUCTORS VL_UNCOPYABLE(VerilatedVcdSc); public: /// Construct a SC trace object, and register with the SystemC kernel VerilatedVcdSc() { - sc_get_curr_simcontext()->add_trace_file(this); + sc_core::sc_get_curr_simcontext()->add_trace_file(this); // We want to avoid a depreciated warning, but still be back compatible. // Turning off the message just for this still results in an // annoying "to turn off" message. - const sc_time t1sec{1, SC_SEC}; + const sc_core::sc_time t1sec{1, sc_core::SC_SEC}; if (t1sec.to_default_time_units() != 0) { - const sc_time tunits{1.0 / t1sec.to_default_time_units(), SC_SEC}; + const sc_core::sc_time tunits{1.0 / t1sec.to_default_time_units(), sc_core::SC_SEC}; spTrace()->set_time_unit(tunits.to_string()); } - spTrace()->set_time_resolution(sc_get_time_resolution().to_string()); + spTrace()->set_time_resolution(sc_core::sc_get_time_resolution().to_string()); } /// Destruct, flush, and close the dump ~VerilatedVcdSc() override { close(); } @@ -60,7 +60,7 @@ public: // METHODS - for SC kernel // Called by SystemC simulate() void cycle(bool delta_cycle) override { - if (!delta_cycle) this->dump(sc_time_stamp().to_double()); + if (!delta_cycle) this->dump(sc_core::sc_time_stamp().to_double()); } // Override VerilatedVcdC. Must be called after starting simulation. @@ -78,7 +78,7 @@ private: // Cadence Incisive has these as abstract functions so we must create them void set_time_unit(int exponent10_seconds) override {} // deprecated #endif - void set_time_unit(double v, sc_time_unit tu) override {} // LCOV_EXCL_LINE + void set_time_unit(double v, sc_core::sc_time_unit tu) override {} // LCOV_EXCL_LINE //-------------------------------------------------- // SystemC 2.1.v1 @@ -95,8 +95,8 @@ private: // Formatting matches that of sc_trace.h // LCOV_EXCL_START #if (SYSTEMC_VERSION >= 20171012) - DECL_TRACE_METHOD_A( sc_event ) - DECL_TRACE_METHOD_A( sc_time ) + DECL_TRACE_METHOD_A( sc_core::sc_event ) + DECL_TRACE_METHOD_A( sc_core::sc_time ) #endif DECL_TRACE_METHOD_A( bool ) From a10b51705f8ed2634608097f8be1be96c4a1532b Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Mon, 17 Apr 2023 14:08:57 +0200 Subject: [PATCH 138/155] Fix class param extends A=B (#4128) Visit global class params even if a class extends a param --- src/V3LinkDot.cpp | 34 ++++++++++++++++---- test_regress/t/t_class_param_type.v | 48 ++++++++++++++++++++++++++++- 2 files changed, 75 insertions(+), 7 deletions(-) diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index d16fcf454..79de07076 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2011,9 +2011,6 @@ private: // *::user4() -> See LinkDotState // Cleared on Cell // AstVar::user5() // bool. True if pin used in this cell - // AstClass::user5() // bool. True if class has a parameter - // as a (possibly indirect) base class. - // Used only in LDS_PRIMARY pass const VNUser3InUse m_inuser3; const VNUser5InUse m_inuser5; @@ -2037,6 +2034,7 @@ private: int m_modportNum = 0; // Uniqueify modport numbers bool m_inSens = false; // True if in senitem std::set m_ifClassImpNames; // Names imported from interface class + std::set m_extendsParam; // Classes that has a parameter as its super class struct DotStates { DotPosition m_dotPos; // Scope part of dotted resolution @@ -2240,6 +2238,26 @@ private: if (classp->isInterfaceClass()) importImplementsClass(nodep, srcp, classp); if (!cextp->isImplements()) m_curSymp->importFromClass(m_statep->symsp(), srcp); } + void visitGlobalClassParams(AstClass* const nodep) { + // Parameters from port parameter list are at the beginning of the members list, so if a + // node, that isn't a parameter, is encountered, all nodes after aren't global parameters + // too. + for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { + // Global parameters are at the beginning of the members list, so if a node, that isn't + // a global parameter, is encountered, all nodes after it aren't global parameters too. + bool globalParam = false; + if (const AstParamTypeDType* const parp = VN_CAST(stmtp, ParamTypeDType)) { + if (parp->isGParam()) globalParam = true; + } else if (const AstVar* const varp = VN_CAST(stmtp, Var)) { + if (varp->isGParam()) globalParam = true; + } + if (globalParam) { + iterate(stmtp); + } else { + break; + } + } + } // VISITs void visit(AstNetlist* nodep) override { @@ -3330,9 +3348,13 @@ private: // function iterate(classp); } - if (classp->user5()) { + if (m_statep->forPrimary() + && m_extendsParam.find(classp) != m_extendsParam.end()) { // Has a parameter as its base class - nodep->user5(true); + m_extendsParam.insert(nodep); + // Link global parameters. They are declared before the extends + // statement, so should be unrelated to the base class + visitGlobalClassParams(nodep); return; } AstPin* paramsp = cpackagerefp->paramsp(); @@ -3345,7 +3367,7 @@ private: // Extending has to be handled after V3Param.cpp, but the type // reference has to be visited iterate(paramp); - nodep->user5(true); + m_extendsParam.insert(nodep); return; } else { AstNodeDType* const paramTypep = paramp->getChildDTypep(); diff --git a/test_regress/t/t_class_param_type.v b/test_regress/t/t_class_param_type.v index 31402e10a..f636b4336 100644 --- a/test_regress/t/t_class_param_type.v +++ b/test_regress/t/t_class_param_type.v @@ -1,7 +1,7 @@ // DESCRIPTION: Verilator: Verilog Test module // // This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2022 by Arkadiusz Kozdra. +// any use, without warranty, 2023 by Antmicro Ltd. // SPDX-License-Identifier: CC0-1.0 // See also t_class_param.v @@ -44,6 +44,36 @@ class SingletonUnusedDefault #(type T=int); endfunction endclass +class Empty; +endclass + +class Foo #(type IF=Empty) extends IF; + typedef Foo foo_t; + int a = 1; +endclass + +class Bar #(type A=int, type B=A) extends Foo; + function int get_size_A; + return $bits(A); + endfunction + function int get_size_B; + return $bits(B); + endfunction +endclass + +class Empty2; +endclass + +class Baz #(type T=Empty2) extends Foo; +endclass + +class Getter1 extends Baz; + function int get_1; + foo_t f = new; + return f.a; + endfunction +endclass + module t (/*AUTOARG*/); initial begin @@ -61,6 +91,20 @@ module t (/*AUTOARG*/); automatic SingletonUnusedDefault #(bit) sud1 = SingletonUnusedDefault#(bit)::self(); automatic SingletonUnusedDefault #(bit) sud2 = SingletonUnusedDefault#(bit)::self(); + automatic Getter1 getter1 = new; + + typedef bit my_bit_t; + Bar#(.A(my_bit_t)) bar_a_bit = new; + Bar#(.B(my_bit_t)) bar_b_bit = new; + Bar#() bar_default = new; + + if (bar_a_bit.get_size_A != 1) $stop; + if (bar_a_bit.get_size_B != 1) $stop; + if (bar_b_bit.get_size_A != 32) $stop; + if (bar_b_bit.get_size_B != 1) $stop; + if (bar_default.get_size_A != 32) $stop; + if (bar_default.get_size_B != 32) $stop; + if (pdt1 != pdt2) $stop; if (pdt2 != pdt3) $stop; if (p1 != p2) $stop; @@ -77,6 +121,8 @@ module t (/*AUTOARG*/); if (pdt1.get_p() != 20) $stop; if (Parcls#(cls2_t)::get_p() != 20) $stop; + if (getter1.get_1() != 1) $stop; + $write("*-* All Finished *-*\n"); $finish; end From 843fdd3e57fbe32e61298b129943c5b6487215e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Boro=C5=84ski?= <94375110+kboronski-ant@users.noreply.github.com> Date: Thu, 20 Apr 2023 00:05:37 +0200 Subject: [PATCH 139/155] Resolve class lvalues after parameterization (#4131) --- src/Verilator.cpp | 1 + test_regress/t/t_class_param_lvalue.pl | 17 +++++++++++++++++ test_regress/t/t_class_param_lvalue.v | 15 +++++++++++++++ 3 files changed, 33 insertions(+) create mode 100755 test_regress/t/t_class_param_lvalue.pl create mode 100644 test_regress/t/t_class_param_lvalue.v diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 294320613..6c6940b0c 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -152,6 +152,7 @@ static void process() { // This requires some width calculations and constant propagation V3Param::param(v3Global.rootp()); V3LinkDot::linkDotParamed(v3Global.rootp()); // Cleanup as made new modules + V3LinkLValue::linkLValue(v3Global.rootp()); // Resolve new VarRefs V3Error::abortIfErrors(); // Remove any modules that were parameterized and are no longer referenced. diff --git a/test_regress/t/t_class_param_lvalue.pl b/test_regress/t/t_class_param_lvalue.pl new file mode 100755 index 000000000..13587bf85 --- /dev/null +++ b/test_regress/t/t_class_param_lvalue.pl @@ -0,0 +1,17 @@ +#!/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(linter => 1); + +lint( + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_param_lvalue.v b/test_regress/t/t_class_param_lvalue.v new file mode 100644 index 000000000..879693876 --- /dev/null +++ b/test_regress/t/t_class_param_lvalue.v @@ -0,0 +1,15 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Foo; +endclass + +class Bar #(type BASE=Foo) extends BASE; + task body(); + int v = 0; + v = 1; + endtask +endclass From 65a484e00b52f5ee4a03b2fcd03896ecc4809dcd Mon Sep 17 00:00:00 2001 From: Kamil Rakoczy Date: Thu, 20 Apr 2023 13:02:31 +0200 Subject: [PATCH 140/155] Internal: Update clang_check_annotations conditions (#4134) --- include/verilated.cpp | 2 +- include/verilated_imp.h | 2 +- include/verilatedos.h | 6 +- nodist/clang_check_attributes | 75 +++++++++++++----------- src/V3Active.cpp | 2 +- src/V3Ast.cpp | 2 +- src/V3Ast.h | 9 +-- src/V3AstNodeOther.h | 8 +-- src/V3AstNodes.cpp | 2 +- src/V3EmitCBase.h | 4 +- src/V3FileLine.h | 4 +- src/V3Gate.cpp | 4 +- src/V3Number.cpp | 14 ++--- src/V3Number.h | 22 +++---- src/V3OrderGraph.h | 16 ++--- src/V3OrderMoveGraph.h | 2 +- src/V3Partition.cpp | 2 +- src/V3PartitionGraph.h | 2 +- src/V3ThreadPool.h | 10 +++- src/V3Timing.cpp | 2 +- src/V3Tristate.cpp | 6 +- test_regress/t/t_dist_attributes_bad.out | 26 ++++---- 22 files changed, 120 insertions(+), 102 deletions(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index 63affb724..dc23517cc 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -693,7 +693,7 @@ std::string VL_DECIMAL_NW(int width, const WDataInP lwp) VL_MT_SAFE { } template -std::string _vl_vsformat_time(char* tmp, T ld, int timeunit, bool left, size_t width) { +std::string _vl_vsformat_time(char* tmp, T ld, int timeunit, bool left, size_t width) VL_MT_SAFE { const VerilatedContextImp* const ctxImpp = Verilated::threadContextp()->impp(); const std::string suffix = ctxImpp->timeFormatSuffix(); const int userUnits = ctxImpp->timeFormatUnits(); // 0..-15 diff --git a/include/verilated_imp.h b/include/verilated_imp.h index e357ddcc8..dfc1cdf92 100644 --- a/include/verilated_imp.h +++ b/include/verilated_imp.h @@ -148,7 +148,7 @@ public: private: VL_UNCOPYABLE(VerilatedThreadMsgQueue); // METHODS - static VerilatedThreadMsgQueue& threadton() { + static VerilatedThreadMsgQueue& threadton() VL_MT_SAFE { static thread_local VerilatedThreadMsgQueue t_s; return t_s; } diff --git a/include/verilatedos.h b/include/verilatedos.h index da40b1edd..625552d4f 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -603,8 +603,12 @@ reverse_wrapper reverse_view(const T& v) { } // C++17's std::as_const +// `VL_MT_SAFE` annotation only applies to this function. +// Object that is returned by this function is not considered +// as MT_SAFE and any function call on this object still +// needs to be `VL_MT_SAFE`. template -T const& as_const(T& v) { +T const& as_const(T& v) VL_MT_SAFE { return v; } diff --git a/nodist/clang_check_attributes b/nodist/clang_check_attributes index dba884b49..0cea38289 100755 --- a/nodist/clang_check_attributes +++ b/nodist/clang_check_attributes @@ -49,14 +49,16 @@ class VlAnnotations: release: bool = False def is_mt_safe_context(self): - return (not (self.mt_unsafe or self.mt_unsafe_one) - and (self.mt_safe or self.mt_start)) + return (not (self.mt_unsafe or self.mt_unsafe_one) and self.mt_safe) def is_pure_context(self): return self.pure def is_stabe_tree_context(self): - return self.stable_tree + # stable tree context requires calls to be marked + # as MT_SAFE or MT_STABLE + # Functions in MT_START needs to be MT_SAFE or MT_STABLE + return self.stable_tree or self.mt_start def is_mt_unsafe_call(self): return self.mt_unsafe or self.mt_unsafe_one @@ -389,7 +391,8 @@ class CallAnnotationsValidator: # stable tree context if ctx.is_stabe_tree_context(): - if not (annotations.is_stabe_tree_call() + if annotations.is_mt_unsafe_call() or not ( + annotations.is_stabe_tree_call() or annotations.is_pure_call() or self.check_mt_safe_call(node, refd, annotations)): self.emit_diagnostic( @@ -417,7 +420,8 @@ class CallAnnotationsValidator: # stable tree context if ctx.is_stabe_tree_context(): - if not (annotations.is_pure_call() + if annotations.is_mt_unsafe_call() or not ( + annotations.is_pure_call() or annotations.is_mt_safe_call() or annotations.is_stabe_tree_call()): self.emit_diagnostic( @@ -465,11 +469,19 @@ class CallAnnotationsValidator: if not supported: self.iterate_children(node.get_children(), self.dispatch_node_inside_definition) - return + return True assert refd is not None if self._is_ignored_call(refd): - return + return True + + if "std::function" in refd.displayname: + # Workaroud for missing support for lambda annotations + # in c++11. + # If function takes std::function as argument, + # assume, that this std::function will be called inside it. + self.process_function_definition(node) + return False assert self._call_location is not None node_file = os.path.abspath(node.location.file.name) @@ -481,47 +493,40 @@ class CallAnnotationsValidator: or refd.kind == CursorKind.CXX_METHOD and refd.is_static_method()): self.process_function_call(refd, annotations) - self.iterate_children(node.get_children(), - self.dispatch_node_inside_definition) - return # Function pointer - if refd.kind in [ + elif refd.kind in [ CursorKind.VAR_DECL, CursorKind.FIELD_DECL, CursorKind.PARM_DECL ]: self.process_function_call(refd, annotations) - self.iterate_children(node.get_children(), - self.dispatch_node_inside_definition) - return # Non-static class methods - if refd.kind == CursorKind.CXX_METHOD: + elif refd.kind == CursorKind.CXX_METHOD: self.process_method_call(node, refd, annotations) - self.iterate_children(node.get_children(), - self.dispatch_node_inside_definition) - return # Conversion method (e.g. `operator int()`) - if refd.kind == CursorKind.CONVERSION_FUNCTION: + elif refd.kind == CursorKind.CONVERSION_FUNCTION: self.process_method_call(node, refd, annotations) - self.iterate_children(node.get_children(), - self.dispatch_node_inside_definition) - return # Constructors - if refd.kind == CursorKind.CONSTRUCTOR: + elif refd.kind == CursorKind.CONSTRUCTOR: self.process_constructor_call(refd, annotations) - self.iterate_children(node.get_children(), - self.dispatch_node_inside_definition) - return - - # Ignore other callables - print(f"{refd.location.file.name}:{refd.location.line}: " - f"{refd.displayname} {refd.kind}\n" - f" from: {node.location.file.name}:{node.location.line}") + else: + # Ignore other callables, but report them + print("Unknown callable: " + f"{refd.location.file.name}:{refd.location.line}: " + f"{refd.displayname} {refd.kind}\n" + f" from: {node.location.file.name}:{node.location.line}") + return True # Definition handling def dispatch_node_inside_definition(self, node: clang.cindex.Cursor): if node.kind == CursorKind.CALL_EXPR: - self.dispatch_call_node(node) + if self.dispatch_call_node(node) is False: + return None + elif node.is_definition() and node.kind in [ + CursorKind.CXX_METHOD, CursorKind.FUNCTION_DECL, + CursorKind.CONSTRUCTOR, CursorKind.CONVERSION_FUNCTION + ]: + self.process_function_definition(node) return None return self.iterate_children(node.get_children(), @@ -556,12 +561,14 @@ class CallAnnotationsValidator: # for callees validation. self._caller = FunctionInfo.from_node(node, refd, def_annotations | annotations) + prev_call_location = self._call_location self._call_location = self._caller self.iterate_children(node_children, self.dispatch_node_inside_definition) - self._call_location = None + self._call_location = prev_call_location + self._caller = prev_call_location return None @@ -826,7 +833,7 @@ class TopDownSummaryPrinter(): elif func.reason == DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX: name += "is pure but calls non-pure function(s)" elif func.reason == DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX: - name += "calls stable_tree function(s) but isn't annotated as stable_tree" + name += "is stable_tree but calls non-stable_tree or non-mtsafe" else: name += "for unknown reason (please add description)" diff --git a/src/V3Active.cpp b/src/V3Active.cpp index a333f65f7..87194907f 100644 --- a/src/V3Active.cpp +++ b/src/V3Active.cpp @@ -54,7 +54,7 @@ private: const string m_name; // Only used for .dot file generation const VertexType m_type; // Vertex type (BLOCK/BRANCH/OUTPUT) - string typestr() const { // " + string typestr() const VL_MT_SAFE { // " switch (m_type) { case VT_BLOCK: return "(||)"; // basic block node case VT_BRANCH: return "(&&)"; // if/else branch mode diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index e19729116..dcc43148c 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -285,7 +285,7 @@ string AstNode::vpiName(const string& namein) { return pretty; } -string AstNode::prettyTypeName() const { +string AstNode::prettyTypeName() const VL_MT_STABLE { if (name() == "") return typeName(); return std::string{typeName()} + " '" + prettyName() + "'"; } diff --git a/src/V3Ast.h b/src/V3Ast.h index ea3c1bb61..6a286bde8 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -470,7 +470,7 @@ public: _ENUM_MAX }; enum en m_e; - const char* ascii() const { + const char* ascii() const VL_MT_SAFE { static const char* const names[] = {"%E-unk", "bit", "byte", @@ -1693,13 +1693,14 @@ public: static string prettyNameQ(const string& namein) { // Quoted pretty name (for errors) return std::string{"'"} + prettyName(namein) + "'"; } - static string - encodeName(const string& namein); // Encode user name into internal C representation + // Encode user name into internal C representation + static string encodeName(const string& namein); static string encodeNumber(int64_t num); // Encode number into internal C representation static string vcdName(const string& namein); // Name for printing out to vcd files string prettyName() const VL_MT_STABLE { return prettyName(name()); } string prettyNameQ() const { return prettyNameQ(name()); } - string prettyTypeName() const; // "VARREF" for error messages (NOT dtype's pretty name) + // "VARREF" for error messages (NOT dtype's pretty name) + string prettyTypeName() const VL_MT_STABLE; virtual string prettyOperatorName() const { return "operator " + prettyTypeName(); } FileLine* fileline() const VL_MT_SAFE { return m_fileline; } void fileline(FileLine* fl) { m_fileline = fl; } diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index e923385d3..cff2cfdbe 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -1151,7 +1151,7 @@ public: void cloneRelink() override { V3ERROR_NA; } string name() const override VL_MT_STABLE { return "$root"; } void dump(std::ostream& str) const override; - AstNodeModule* topModulep() const { // Top module in hierarchy + AstNodeModule* topModulep() const VL_MT_STABLE { // Top module in hierarchy return modulesp(); // First one in the list, for now } AstTypeTable* typeTablep() { return m_typeTablep; } @@ -1789,7 +1789,7 @@ public: string dpiTmpVarType(const string& varName) const; // Return Verilator internal type for argument: CData, SData, IData, WData string vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc = "", - bool asRef = false) const VL_MT_SAFE; + bool asRef = false) const VL_MT_STABLE; string vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc string vlEnumDir() const; // Return VerilatorVarDir: VLVD_INOUT, etc string vlPropDecl(const string& propName) const; // Return VerilatorVarProps declaration @@ -2001,8 +2001,8 @@ public: string name() const override VL_MT_STABLE { return scopep()->name() + "->" + varp()->name(); } void dump(std::ostream& str) const override; bool hasDType() const override { return true; } - AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable - AstScope* scopep() const { return m_scopep; } // Pointer to scope it's under + AstVar* varp() const VL_MT_STABLE { return m_varp; } // [After Link] Pointer to variable + AstScope* scopep() const VL_MT_STABLE { return m_scopep; } // Pointer to scope it's under void scopep(AstScope* nodep) { m_scopep = nodep; } bool isTrace() const { return m_trace; } void trace(bool flag) { m_trace = flag; } diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index a88ef0a06..3ebd67499 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -397,7 +397,7 @@ string AstVar::verilogKwd() const { } string AstVar::vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc, - bool asRef) const VL_MT_SAFE { + bool asRef) const VL_MT_STABLE { UASSERT_OBJ(!forReturn, this, "Internal data is never passed as return, but as first argument"); string ostatic; diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index e3c001be9..5ae0074c4 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -55,14 +55,14 @@ public: return className + "* const __restrict vlSelf VL_ATTR_UNUSED = static_cast<" + className + "*>(voidSelf);\n"; } - static string symClassName() { + static string symClassName() VL_MT_STABLE { return v3Global.opt.prefix() + "_" + VIdProtect::protect("_Syms"); } static string symClassVar() { return symClassName() + "* __restrict vlSymsp"; } static string symClassAssign() { return symClassName() + "* const __restrict vlSymsp VL_ATTR_UNUSED = vlSelf->vlSymsp;\n"; } - static string prefixNameProtect(const AstNode* nodep) VL_MT_SAFE { // C++ name with prefix + static string prefixNameProtect(const AstNode* nodep) VL_MT_STABLE { // C++ name with prefix return v3Global.opt.modPrefix() + "_" + VIdProtect::protect(nodep->name()); } static bool isAnonOk(const AstVar* varp) { diff --git a/src/V3FileLine.h b/src/V3FileLine.h index 0bf14ae3f..8f1cf140b 100644 --- a/src/V3FileLine.h +++ b/src/V3FileLine.h @@ -165,7 +165,7 @@ private: static FileLineSingleton s; return s; } - static FileLine& defaultFileLine() { + static FileLine& defaultFileLine() VL_MT_SAFE { static FileLine s; return s; } @@ -364,7 +364,7 @@ public: private: string warnContext() const; string warnContextParent() const VL_REQUIRES(V3Error::s().m_mutex); - const MsgEnBitSet& msgEn() const { return singleton().msgEn(m_msgEnIdx); } + const MsgEnBitSet& msgEn() const VL_MT_SAFE { return singleton().msgEn(m_msgEnIdx); } }; std::ostream& operator<<(std::ostream& os, FileLine* fileline); diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 2929916bc..640cade21 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -76,7 +76,7 @@ public: ~GateEitherVertex() override = default; // ACCESSORS string dotStyle() const override { return m_consumed ? "" : "dotted"; } - AstScope* scopep() const { return m_scopep; } + AstScope* scopep() const VL_MT_STABLE { return m_scopep; } bool reducible() const { return m_reducible; } bool dedupable() const { return m_dedupable; } void setConsumed(const char* /*consumedReason*/) { @@ -133,7 +133,7 @@ public: , m_varScp{varScp} {} ~GateVarVertex() override = default; // ACCESSORS - AstVarScope* varScp() const { return m_varScp; } + AstVarScope* varScp() const VL_MT_STABLE { return m_varScp; } string name() const override VL_MT_STABLE { return (cvtToHex(m_varScp) + " " + varScp()->name()); } diff --git a/src/V3Number.cpp b/src/V3Number.cpp index 3a80da8c2..9e5e295c5 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -385,7 +385,7 @@ void V3Number::create(const char* sourcep) { // m_value[0]); } -void V3Number::nodep(AstNode* nodep) { +void V3Number::nodep(AstNode* nodep) VL_MT_STABLE { m_nodep = nodep; if (!nodep) return; m_fileline = nodep->fileline(); @@ -498,7 +498,7 @@ V3Number& V3Number::setMask(int nbits) { //====================================================================== // ACCESSORS - as strings -string V3Number::ascii(bool prefixed, bool cleanVerilog) const VL_MT_SAFE { +string V3Number::ascii(bool prefixed, bool cleanVerilog) const VL_MT_STABLE { std::ostringstream out; if (is1Step()) { @@ -604,11 +604,11 @@ string V3Number::displayPad(size_t fmtsize, char pad, bool left, const string& i return left ? (in + padding) : (padding + in); } -string V3Number::displayed(AstNode* nodep, const string& vformat) const VL_MT_SAFE { +string V3Number::displayed(AstNode* nodep, const string& vformat) const VL_MT_STABLE { return displayed(nodep->fileline(), vformat); } -string V3Number::displayed(FileLine* fl, const string& vformat) const VL_MT_SAFE { +string V3Number::displayed(FileLine* fl, const string& vformat) const VL_MT_STABLE { auto pos = vformat.cbegin(); UASSERT(pos != vformat.cend() && pos[0] == '%', "$display-like function with non format argument " << *this); @@ -847,7 +847,7 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const VL_MT_SAFE } } -string V3Number::toDecimalS() const { +string V3Number::toDecimalS() const VL_MT_STABLE { if (isNegative()) { V3Number lhsNoSign = *this; lhsNoSign.opNegate(*this); @@ -857,7 +857,7 @@ string V3Number::toDecimalS() const { } } -string V3Number::toDecimalU() const { +string V3Number::toDecimalU() const VL_MT_STABLE { const int maxdecwidth = (width() + 3) * 4 / 3; // Or (maxdecwidth+7)/8], but can't have more than 4 BCD bits per word @@ -1013,7 +1013,7 @@ bool V3Number::isAllX() const VL_MT_SAFE { } return true; } -bool V3Number::isEqZero() const { +bool V3Number::isEqZero() const VL_MT_SAFE { if (isString()) return m_data.str().empty(); for (int i = 0; i < words(); i++) { const ValueAndX v = m_data.num()[i]; diff --git a/src/V3Number.h b/src/V3Number.h index b94a212fb..46ba16094 100644 --- a/src/V3Number.h +++ b/src/V3Number.h @@ -52,7 +52,7 @@ public: uint32_t m_value; // Each bit is true if it's X or Z, 10=z, 11=x uint32_t m_valueX; - bool operator==(const ValueAndX& other) const { + bool operator==(const ValueAndX& other) const VL_MT_SAFE { return m_value == other.m_value && m_valueX == other.m_valueX; } }; @@ -210,7 +210,7 @@ public: UASSERT(isString(), "`str` member accessed when data type is " << m_type); return m_string; } - const std::string& str() const { + const std::string& str() const VL_MT_SAFE { UASSERT(isString(), "`str` member accessed when data type is " << m_type); return m_string; } @@ -356,7 +356,7 @@ class V3Number final { void opCleanThis(bool warnOnTruncation = false); public: - void nodep(AstNode* nodep); + void nodep(AstNode* nodep) VL_MT_STABLE; FileLine* fileline() const VL_MT_SAFE { return m_fileline; } V3Number& setZero(); V3Number& setQuad(uint64_t value); @@ -560,8 +560,8 @@ private: } } static string displayPad(size_t fmtsize, char pad, bool left, const string& in) VL_PURE; - string displayed(FileLine* fl, const string& vformat) const VL_MT_SAFE; - string displayed(const string& vformat) const VL_MT_SAFE { + string displayed(FileLine* fl, const string& vformat) const VL_MT_STABLE; + string displayed(const string& vformat) const VL_MT_STABLE { return displayed(m_fileline, vformat); } @@ -583,8 +583,8 @@ public: V3Number& setMask(int nbits); // IE if nbits=1, then 0b1, if 2->0b11, if 3->0b111 etc // ACCESSORS - string ascii(bool prefixed = true, bool cleanVerilog = false) const VL_MT_SAFE; - string displayed(AstNode* nodep, const string& vformat) const VL_MT_SAFE; + string ascii(bool prefixed = true, bool cleanVerilog = false) const VL_MT_STABLE; + string displayed(AstNode* nodep, const string& vformat) const VL_MT_STABLE; static bool displayedFmtLegal(char format, bool isScan); // Is this a valid format letter? int width() const VL_MT_SAFE { return m_data.width(); } int widthMin() const; // Minimum width that can represent this number (~== log2(num)+1) @@ -612,7 +612,7 @@ public: return m_data.type() == V3NumberDataType::LOGIC || m_data.type() == V3NumberDataType::DOUBLE; } - bool isNegative() const { return !isString() && bitIs1(width() - 1); } + bool isNegative() const VL_MT_SAFE { return !isString() && bitIs1(width() - 1); } bool is1Step() const VL_MT_SAFE { return m_data.m_is1Step; } bool isNull() const VL_MT_SAFE { return m_data.m_isNull; } bool isFourState() const VL_MT_SAFE; @@ -626,7 +626,7 @@ public: } bool isAllZ() const VL_MT_SAFE; bool isAllX() const VL_MT_SAFE; - bool isEqZero() const; + bool isEqZero() const VL_MT_SAFE; bool isNeqZero() const; bool isBitsZero(int msb, int lsb) const; bool isEqOne() const; @@ -642,8 +642,8 @@ public: uint64_t toUQuad() const VL_MT_SAFE; int64_t toSQuad() const VL_MT_SAFE; string toString() const VL_MT_SAFE; - string toDecimalS() const; // return ASCII signed decimal number - string toDecimalU() const; // return ASCII unsigned decimal number + string toDecimalS() const VL_MT_STABLE; // return ASCII signed decimal number + string toDecimalU() const VL_MT_STABLE; // return ASCII unsigned decimal number double toDouble() const VL_MT_SAFE; V3Hash toHash() const; uint32_t edataWord(int eword) const; diff --git a/src/V3OrderGraph.h b/src/V3OrderGraph.h index c1e3f2a91..d51a540a0 100644 --- a/src/V3OrderGraph.h +++ b/src/V3OrderGraph.h @@ -123,7 +123,7 @@ public: virtual bool domainMatters() = 0; // ACCESSORS - AstSenTree* domainp() const { return m_domainp; } + AstSenTree* domainp() const VL_MT_STABLE { return m_domainp; } void domainp(AstSenTree* domainp) { #if VL_DEBUG UASSERT(!m_domainp, "Domain should only be set once"); @@ -154,8 +154,8 @@ public: bool domainMatters() override { return true; } // ACCESSORS - AstNode* nodep() const { return m_nodep; } - AstScope* scopep() const { return m_scopep; } + AstNode* nodep() const VL_MT_STABLE { return m_nodep; } + AstScope* scopep() const VL_MT_STABLE { return m_scopep; } AstSenTree* hybridp() const { return m_hybridp; } // LCOV_EXCL_START // Debug code @@ -181,7 +181,7 @@ public: // LCOV_EXCL_START // Debug code string dotShape() const override final { return "ellipse"; } - virtual string nameSuffix() const = 0; + virtual string nameSuffix() const VL_MT_SAFE = 0; string name() const override final VL_MT_STABLE { return cvtToHex(m_vscp) + " " + nameSuffix() + "\\n " + m_vscp->name(); } @@ -199,7 +199,7 @@ public: bool domainMatters() override { return true; } // LCOV_EXCL_START // Debug code - string nameSuffix() const override { return ""; } + string nameSuffix() const override VL_MT_SAFE { return ""; } string dotColor() const override { return "grey"; } // LCOV_EXCL_STOP }; @@ -215,7 +215,7 @@ public: bool domainMatters() override { return false; } // LCOV_EXCL_START // Debug code - string nameSuffix() const override { return "PRE"; } + string nameSuffix() const override VL_MT_SAFE { return "PRE"; } string dotColor() const override { return "green"; } // LCOV_EXCL_STOP }; @@ -231,7 +231,7 @@ public: bool domainMatters() override { return false; } // LCOV_EXCL_START // Debug code - string nameSuffix() const override { return "POST"; } + string nameSuffix() const override VL_MT_SAFE { return "POST"; } string dotColor() const override { return "red"; } // LCOV_EXCL_STOP }; @@ -247,7 +247,7 @@ public: bool domainMatters() override { return false; } // LCOV_EXCL_START // Debug code - string nameSuffix() const override { return "PORD"; } + string nameSuffix() const override VL_MT_SAFE { return "PORD"; } string dotColor() const override { return "blue"; } // LCOV_EXCL_STOP }; diff --git a/src/V3OrderMoveGraph.h b/src/V3OrderMoveGraph.h index 426b410ff..fb54ac7a0 100644 --- a/src/V3OrderMoveGraph.h +++ b/src/V3OrderMoveGraph.h @@ -75,7 +75,7 @@ public: } return nm; } - OrderLogicVertex* logicp() const { return m_logicp; } + OrderLogicVertex* logicp() const VL_MT_STABLE { return m_logicp; } bool isWait() const { return m_state == POM_WAIT; } void setReady() { UASSERT(m_state == POM_WAIT, "Wait->Ready on node not in proper state"); diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp index 04d34e842..a10ffec1c 100644 --- a/src/V3Partition.cpp +++ b/src/V3Partition.cpp @@ -268,7 +268,7 @@ public: uint32_t id() const override { return m_serialId; } void id(uint32_t id) { m_serialId = id; } // Abstract cost of every logic mtask - uint32_t cost() const override { return m_cost; } + uint32_t cost() const override VL_MT_SAFE { return m_cost; } void setCost(uint32_t cost) { m_cost = cost; } // For tests only uint32_t stepCost() const { return stepCost(m_cost); } static uint32_t stepCost(uint32_t cost) { diff --git a/src/V3PartitionGraph.h b/src/V3PartitionGraph.h index b83679a06..0827ca381 100644 --- a/src/V3PartitionGraph.h +++ b/src/V3PartitionGraph.h @@ -72,7 +72,7 @@ public: , m_bodyp{bodyp} , m_id{id} {} AstMTaskBody* bodyp() const { return m_bodyp; } - uint32_t id() const override { return m_id; } + uint32_t id() const override VL_MT_SAFE { return m_id; } uint32_t priority() const { return m_priority; } void priority(uint32_t pri) { m_priority = pri; } uint32_t cost() const override { return m_cost; } diff --git a/src/V3ThreadPool.h b/src/V3ThreadPool.h index c7f92195a..69e093fcc 100644 --- a/src/V3ThreadPool.h +++ b/src/V3ThreadPool.h @@ -85,8 +85,14 @@ public: void resize(unsigned n) VL_MT_UNSAFE; // Enqueue a job for asynchronous execution + // Due to missing support for lambda annotations in c++11, + // `clang_check_attributes` script assumes that if + // function takes `std::function` as argument, it + // will call it. `VL_MT_START` here indicates that + // every function call inside this `std::function` requires + // annotations. template - std::future enqueue(std::function&& f) VL_MT_SAFE; + std::future enqueue(std::function&& f) VL_MT_START; // Request exclusive access to processing. // It sends request to stop all other threads and waits for them to stop. @@ -190,7 +196,7 @@ T V3ThreadPool::waitForFuture(std::future& future) VL_MT_SAFE_EXCLUDES(m_mute } template -std::future V3ThreadPool::enqueue(std::function&& f) VL_MT_SAFE { +std::future V3ThreadPool::enqueue(std::function&& f) VL_MT_START { std::shared_ptr> prom = std::make_shared>(); std::future result = prom->get_future(); pushJob(prom, std::move(f)); diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index afbba68f5..a71ad592e 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -81,7 +81,7 @@ private: ~DependencyVertex() override = default; // ACCESSORS - virtual AstNode* nodep() const { return m_nodep; } + virtual AstNode* nodep() const VL_MT_STABLE { return m_nodep; } }; // NODE STATE diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index 0028d2bc8..61720c2a4 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -152,7 +152,7 @@ public: , m_nodep{nodep} {} ~TristateVertex() override = default; // ACCESSORS - AstNode* nodep() const { return m_nodep; } + AstNode* nodep() const VL_MT_STABLE { return m_nodep; } const AstVar* varp() const { return VN_CAST(nodep(), Var); } string name() const override VL_MT_STABLE { return ((isTristate() ? "tri\\n" @@ -170,9 +170,9 @@ public: } FileLine* fileline() const override { return nodep()->fileline(); } void isTristate(bool flag) { m_isTristate = flag; } - bool isTristate() const { return m_isTristate; } + bool isTristate() const VL_MT_SAFE { return m_isTristate; } void feedsTri(bool flag) { m_feedsTri = flag; } - bool feedsTri() const { return m_feedsTri; } + bool feedsTri() const VL_MT_SAFE { return m_feedsTri; } void processed(bool flag) { m_processed = flag; } bool processed() const { return m_processed; } }; diff --git a/test_regress/t/t_dist_attributes_bad.out b/test_regress/t/t_dist_attributes_bad.out index e7649a02f..fea14b7b0 100644 --- a/test_regress/t/t_dist_attributes_bad.out +++ b/test_regress/t/t_dist_attributes_bad.out @@ -65,7 +65,7 @@ t/t_dist_attributes_bad.h:204: [mt_unsafe_one] TestCla t/t_dist_attributes_bad.h:209: [mt_safe, mt_unsafe, pure] TestClass::cm_ea_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:209: [mt_safe, mt_unsafe_one, pure] TestClass::cm_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) -%Error: "TestClass::cm_test_caller_smethod_VL_MT_START(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) +%Error: "TestClass::cm_test_caller_smethod_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe t/t_dist_attributes_bad.cpp:155: [mt_start] TestClass::cm_test_caller_smethod_VL_MT_START(VerilatedMutex &) t/t_dist_attributes_bad.h:191: [mt_unsafe] TestClass::cm_au_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:191: [mt_unsafe_one] TestClass::cm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) @@ -143,7 +143,7 @@ t/t_dist_attributes_bad.h:204: [mt_unsafe_one] TestCla t/t_dist_attributes_bad.h:209: [mt_safe, mt_unsafe, pure] TestClass::cm_ea_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:209: [mt_safe, mt_unsafe_one, pure] TestClass::cm_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) -%Error: "TestClass::cm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) +%Error: "TestClass::cm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe t/t_dist_attributes_bad.h:212: [mt_start] TestClass::cm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &) t/t_dist_attributes_bad.h:191: [mt_unsafe] TestClass::cm_au_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:191: [mt_unsafe_one] TestClass::cm_au_VL_MT_UNSAFE_ONE(VerilatedMutex &) @@ -273,7 +273,7 @@ t/t_dist_attributes_bad.cpp:175: [mt_safe] TestClass t/t_dist_attributes_bad.h:235: [mt_unsafe] TestClass::icm_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:235: [mt_unsafe_one] TestClass::icm_VL_MT_UNSAFE_ONE(VerilatedMutex &) -%Error: "TestClass::icm_test_caller_smethod_VL_MT_START(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) +%Error: "TestClass::icm_test_caller_smethod_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe t/t_dist_attributes_bad.cpp:175: [mt_start] TestClass::icm_test_caller_smethod_VL_MT_START(VerilatedMutex &) t/t_dist_attributes_bad.h:235: [mt_unsafe] TestClass::icm_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:235: [mt_unsafe_one] TestClass::icm_VL_MT_UNSAFE_ONE(VerilatedMutex &) @@ -299,7 +299,7 @@ t/t_dist_attributes_bad.h:238: [mt_safe] TestClass t/t_dist_attributes_bad.h:235: [mt_unsafe] TestClass::icm_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:235: [mt_unsafe_one] TestClass::icm_VL_MT_UNSAFE_ONE(VerilatedMutex &) -%Error: "TestClass::icm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) +%Error: "TestClass::icm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe t/t_dist_attributes_bad.h:238: [mt_start] TestClass::icm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &) t/t_dist_attributes_bad.h:235: [mt_unsafe] TestClass::icm_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:235: [mt_unsafe_one] TestClass::icm_VL_MT_UNSAFE_ONE(VerilatedMutex &) @@ -327,7 +327,7 @@ t/t_dist_attributes_bad.h:170: [mt_start] TestCla t/t_dist_attributes_bad.h:170: [mt_unsafe] TestClass::iscm_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:170: [mt_unsafe_one] TestClass::iscm_VL_MT_UNSAFE_ONE(VerilatedMutex &) -%Error: "TestClass::iscm_test_caller_smethod_VL_MT_START(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) +%Error: "TestClass::iscm_test_caller_smethod_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe t/t_dist_attributes_bad.cpp:119: [mt_start] TestClass::iscm_test_caller_smethod_VL_MT_START(VerilatedMutex &) t/t_dist_attributes_bad.h:170: [] TestClass::iscm_NO_ANNOTATION(VerilatedMutex &) t/t_dist_attributes_bad.h:170: [mt_start] TestClass::iscm_VL_MT_START(VerilatedMutex &) @@ -357,7 +357,7 @@ t/t_dist_attributes_bad.h:170: [mt_start] TestCla t/t_dist_attributes_bad.h:170: [mt_unsafe] TestClass::iscm_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:170: [mt_unsafe_one] TestClass::iscm_VL_MT_UNSAFE_ONE(VerilatedMutex &) -%Error: "TestClass::iscm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) +%Error: "TestClass::iscm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe t/t_dist_attributes_bad.h:173: [mt_start] TestClass::iscm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &) t/t_dist_attributes_bad.h:170: [] TestClass::iscm_NO_ANNOTATION(VerilatedMutex &) t/t_dist_attributes_bad.h:170: [mt_start] TestClass::iscm_VL_MT_START(VerilatedMutex &) @@ -467,7 +467,7 @@ t/t_dist_attributes_bad.h:133: [mt_unsafe_one] TestCla t/t_dist_attributes_bad.h:138: [mt_safe, mt_unsafe, pure] TestClass::scm_ea_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:138: [mt_safe, mt_unsafe_one, pure] TestClass::scm_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) -%Error: "TestClass::scm_test_caller_smethod_VL_MT_START(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) +%Error: "TestClass::scm_test_caller_smethod_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe t/t_dist_attributes_bad.cpp:93: [mt_start] TestClass::scm_test_caller_smethod_VL_MT_START(VerilatedMutex &) t/t_dist_attributes_bad.h:120: [] TestClass::scm_au_NO_ANNOTATION(VerilatedMutex &) t/t_dist_attributes_bad.h:120: [mt_start] TestClass::scm_au_VL_MT_START(VerilatedMutex &) @@ -585,7 +585,7 @@ t/t_dist_attributes_bad.h:133: [mt_unsafe_one] TestCla t/t_dist_attributes_bad.h:138: [mt_safe, mt_unsafe, pure] TestClass::scm_ea_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:138: [mt_safe, mt_unsafe_one, pure] TestClass::scm_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) -%Error: "TestClass::scm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) +%Error: "TestClass::scm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe t/t_dist_attributes_bad.h:141: [mt_start] TestClass::scm_test_caller_smethod_hdr_VL_MT_START(VerilatedMutex &) t/t_dist_attributes_bad.h:120: [] TestClass::scm_au_NO_ANNOTATION(VerilatedMutex &) t/t_dist_attributes_bad.h:120: [mt_start] TestClass::scm_au_VL_MT_START(VerilatedMutex &) @@ -759,7 +759,7 @@ t/t_dist_attributes_bad.h:94: [mt_start] ifh_VL_ t/t_dist_attributes_bad.h:94: [mt_unsafe] ifh_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:94: [mt_unsafe_one] ifh_VL_MT_UNSAFE_ONE(VerilatedMutex &) -%Error: "ifh_test_caller_func_VL_MT_START(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) +%Error: "ifh_test_caller_func_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe t/t_dist_attributes_bad.cpp:53: [mt_start] ifh_test_caller_func_VL_MT_START(VerilatedMutex &) t/t_dist_attributes_bad.h:94: [] ifh_NO_ANNOTATION(VerilatedMutex &) t/t_dist_attributes_bad.h:94: [mt_start] ifh_VL_MT_START(VerilatedMutex &) @@ -789,7 +789,7 @@ t/t_dist_attributes_bad.h:94: [mt_start] ifh_VL_ t/t_dist_attributes_bad.h:94: [mt_unsafe] ifh_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:94: [mt_unsafe_one] ifh_VL_MT_UNSAFE_ONE(VerilatedMutex &) -%Error: "ifh_test_caller_func_hdr_VL_MT_START(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) +%Error: "ifh_test_caller_func_hdr_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe t/t_dist_attributes_bad.h:97: [mt_start] ifh_test_caller_func_hdr_VL_MT_START(VerilatedMutex &) t/t_dist_attributes_bad.h:94: [] ifh_NO_ANNOTATION(VerilatedMutex &) t/t_dist_attributes_bad.h:94: [mt_start] ifh_VL_MT_START(VerilatedMutex &) @@ -899,7 +899,7 @@ t/t_dist_attributes_bad.h:75: [mt_unsafe_one] nsf_ae_ t/t_dist_attributes_bad.h:80: [mt_safe, mt_unsafe, pure] nsf_ea_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:80: [mt_safe, mt_unsafe_one, pure] nsf_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) -%Error: "nsf_test_caller_func_VL_MT_START(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) +%Error: "nsf_test_caller_func_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe t/t_dist_attributes_bad.cpp:42: [mt_start] nsf_test_caller_func_VL_MT_START(VerilatedMutex &) t/t_dist_attributes_bad.h:62: [] nsf_au_NO_ANNOTATION(VerilatedMutex &) t/t_dist_attributes_bad.h:62: [mt_start] nsf_au_VL_MT_START(VerilatedMutex &) @@ -1017,7 +1017,7 @@ t/t_dist_attributes_bad.h:75: [mt_unsafe_one] nsf_ae_ t/t_dist_attributes_bad.h:80: [mt_safe, mt_unsafe, pure] nsf_ea_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:80: [mt_safe, mt_unsafe_one, pure] nsf_ea_VL_MT_UNSAFE_ONE(VerilatedMutex &) -%Error: "nsf_test_caller_func_hdr_VL_MT_START(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) +%Error: "nsf_test_caller_func_hdr_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe t/t_dist_attributes_bad.h:83: [mt_start] nsf_test_caller_func_hdr_VL_MT_START(VerilatedMutex &) t/t_dist_attributes_bad.h:62: [] nsf_au_NO_ANNOTATION(VerilatedMutex &) t/t_dist_attributes_bad.h:62: [mt_start] nsf_au_VL_MT_START(VerilatedMutex &) @@ -1163,7 +1163,7 @@ t/t_dist_attributes_bad.cpp:60: [mt_start] sfc_VL_ t/t_dist_attributes_bad.cpp:60: [mt_unsafe] sfc_VL_MT_UNSAFE(VerilatedMutex &) t/t_dist_attributes_bad.cpp:60: [mt_unsafe_one] sfc_VL_MT_UNSAFE_ONE(VerilatedMutex &) -%Error: "sfc_test_caller_func_VL_MT_START(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) +%Error: "sfc_test_caller_func_VL_MT_START(VerilatedMutex &)" is stable_tree but calls non-stable_tree or non-mtsafe t/t_dist_attributes_bad.cpp:63: [mt_start] sfc_test_caller_func_VL_MT_START(VerilatedMutex &) t/t_dist_attributes_bad.cpp:60: [] sfc_NO_ANNOTATION(VerilatedMutex &) t/t_dist_attributes_bad.cpp:60: [mt_start] sfc_VL_MT_START(VerilatedMutex &) From 84a46939b348836ab8abbd79f61386e403997720 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Thu, 20 Apr 2023 13:11:35 +0200 Subject: [PATCH 141/155] Fix class extend param references (#4136) Signed-off-by: Ryszard Rozak --- src/V3LinkDot.cpp | 64 +++++++++++--------------- src/V3Param.cpp | 18 ++++---- test_regress/t/t_class_extends_param.v | 4 +- test_regress/t/t_class_param_type.v | 28 +++++++++-- 4 files changed, 64 insertions(+), 50 deletions(-) diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 79de07076..150c5d4c2 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2035,6 +2035,8 @@ private: bool m_inSens = false; // True if in senitem std::set m_ifClassImpNames; // Names imported from interface class std::set m_extendsParam; // Classes that has a parameter as its super class + bool m_insideClassExtParam = false; // Inside a class that extends a parameter. + // It may be set only in linkDotPrimary. struct DotStates { DotPosition m_dotPos; // Scope part of dotted resolution @@ -2238,26 +2240,6 @@ private: if (classp->isInterfaceClass()) importImplementsClass(nodep, srcp, classp); if (!cextp->isImplements()) m_curSymp->importFromClass(m_statep->symsp(), srcp); } - void visitGlobalClassParams(AstClass* const nodep) { - // Parameters from port parameter list are at the beginning of the members list, so if a - // node, that isn't a parameter, is encountered, all nodes after aren't global parameters - // too. - for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { - // Global parameters are at the beginning of the members list, so if a node, that isn't - // a global parameter, is encountered, all nodes after it aren't global parameters too. - bool globalParam = false; - if (const AstParamTypeDType* const parp = VN_CAST(stmtp, ParamTypeDType)) { - if (parp->isGParam()) globalParam = true; - } else if (const AstVar* const varp = VN_CAST(stmtp, Var)) { - if (varp->isGParam()) globalParam = true; - } - if (globalParam) { - iterate(stmtp); - } else { - break; - } - } - } // VISITs void visit(AstNetlist* nodep) override { @@ -2424,12 +2406,17 @@ private: nodep->v3error("'super' used on non-extended class (IEEE 1800-2017 8.15)"); m_ds.m_dotErr = true; } else { - const auto cextp = classp->extendsp(); - UASSERT_OBJ(cextp, nodep, "Bad super extends link"); - const auto sclassp = cextp->classp(); - UASSERT_OBJ(sclassp, nodep, "Bad superclass"); - m_ds.m_dotSymp = m_statep->getNodeSym(sclassp); - UINFO(8, " super. " << m_ds.ascii() << endl); + if (m_statep->forPrimary() + && m_extendsParam.find(classp) != m_extendsParam.end()) { + m_ds.m_unresolvedClass = true; + } else { + const auto cextp = classp->extendsp(); + UASSERT_OBJ(cextp, nodep, "Bad super extends link"); + const auto sclassp = cextp->classp(); + UASSERT_OBJ(sclassp, nodep, "Bad superclass"); + m_ds.m_dotSymp = m_statep->getNodeSym(sclassp); + UINFO(8, " super. " << m_ds.ascii() << endl); + } } } } else if (VN_IS(nodep->lhsp(), ClassOrPackageRef)) { @@ -2798,8 +2785,10 @@ private: } } } - // - if (!ok) { + // Don't throw error ifthe reference is inside a class that extends a param, because + // some members can't be linked in such a case. m_insideClassExtParam may be true only + // in the first stage of linking. + if (!ok && !m_insideClassExtParam) { // Cells/interfaces can't be implicit const bool isCell = foundp ? VN_IS(foundp->nodep(), Cell) : false; const bool checkImplicit = (!m_ds.m_dotp && m_ds.m_dotText == "" && !isCell); @@ -3110,6 +3099,10 @@ private: nodep->taskp(taskp); nodep->classOrPackagep(foundp->classOrPackagep()); UINFO(7, " Resolved " << nodep << endl); // Also prints taskp + } else if (m_insideClassExtParam) { + // The reference may point to a method declared in a super class, which is proved + // by a parameter. In such a case, it can't be linked at the first stage. + return; } else { // Note ParseRef has similar error handling/message output UINFO(7, " ErrFtask curSymp=se" << cvtToHex(m_curSymp) << " dotSymp=se" @@ -3300,6 +3293,7 @@ private: VL_RESTORER(m_curSymp); VL_RESTORER(m_modSymp); VL_RESTORER(m_ifClassImpNames); + VL_RESTORER(m_insideClassExtParam); { m_ds.init(m_curSymp); // Until overridden by a SCOPE @@ -3352,10 +3346,7 @@ private: && m_extendsParam.find(classp) != m_extendsParam.end()) { // Has a parameter as its base class m_extendsParam.insert(nodep); - // Link global parameters. They are declared before the extends - // statement, so should be unrelated to the base class - visitGlobalClassParams(nodep); - return; + m_insideClassExtParam = true; } AstPin* paramsp = cpackagerefp->paramsp(); if (paramsp) paramsp = paramsp->cloneTree(true); @@ -3364,13 +3355,12 @@ private: } else if (AstParamTypeDType* const paramp = VN_CAST(foundp->nodep(), ParamTypeDType)) { if (m_statep->forPrimary()) { - // Extending has to be handled after V3Param.cpp, but the type - // reference has to be visited - iterate(paramp); + // Extending has to be handled after V3Param.cpp m_extendsParam.insert(nodep); - return; + m_insideClassExtParam = true; + continue; } else { - AstNodeDType* const paramTypep = paramp->getChildDTypep(); + AstNodeDType* const paramTypep = paramp->subDTypep(); classRefDtypep = VN_CAST(paramTypep->cloneTree(false), ClassRefDType); if (!classRefDtypep) { diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 977a0a803..b1324d5a8 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -949,16 +949,18 @@ class ParamVisitor final : public VNVisitor { // Process once; note user5 will be cleared on specialization, so we will do the // specialized module if needed - if (modp->user5SetOnce()) continue; + if (!modp->user5SetOnce()) { - // TODO: this really should be an assert, but classes and hier_blocks are special... - if (modp->someInstanceName().empty()) modp->someInstanceName(modp->origName()); + // TODO: this really should be an assert, but classes and hier_blocks are + // special... + if (modp->someInstanceName().empty()) modp->someInstanceName(modp->origName()); - // Iterate the body - { - VL_RESTORER(m_modp); - m_modp = modp; - iterateChildren(modp); + // Iterate the body + { + VL_RESTORER(m_modp); + m_modp = modp; + iterateChildren(modp); + } } // Process interface cells, then non-interface cells, which may reference an interface diff --git a/test_regress/t/t_class_extends_param.v b/test_regress/t/t_class_extends_param.v index 0d5e8cf36..cdec1c149 100644 --- a/test_regress/t/t_class_extends_param.v +++ b/test_regress/t/t_class_extends_param.v @@ -30,7 +30,7 @@ module t (/*AUTOARG*/ endfunction endclass - class ExtendBar extends Bar; + class ExtendBar extends Bar#(); function int get_x; return super.get_x(); endfunction @@ -39,7 +39,7 @@ module t (/*AUTOARG*/ endfunction endclass - Bar bar_foo_i; + Bar #() bar_foo_i; Bar #(Baz) bar_baz_i; ExtendBar extend_bar_i; diff --git a/test_regress/t/t_class_param_type.v b/test_regress/t/t_class_param_type.v index f636b4336..86b1d8f67 100644 --- a/test_regress/t/t_class_param_type.v +++ b/test_regress/t/t_class_param_type.v @@ -52,7 +52,7 @@ class Foo #(type IF=Empty) extends IF; int a = 1; endclass -class Bar #(type A=int, type B=A) extends Foo; +class Bar #(type A=int, type B=A) extends Foo#(); function int get_size_A; return $bits(A); endfunction @@ -64,16 +64,32 @@ endclass class Empty2; endclass -class Baz #(type T=Empty2) extends Foo; +class Baz #(type T=Empty2) extends Foo#(); endclass -class Getter1 extends Baz; +class Getter1 extends Baz#(); function int get_1; foo_t f = new; return f.a; endfunction endclass +class MyInt1; + int x = 1; +endclass + +class MyInt2; + int x = 2; +endclass + +class ExtendsMyInt #(type T=MyInt1) extends T; + typedef ExtendsMyInt#(T) this_type; + function int get_this_type_x; + this_type t = new; + return t.x; + endfunction +endclass + module t (/*AUTOARG*/); initial begin @@ -93,6 +109,9 @@ module t (/*AUTOARG*/); automatic Getter1 getter1 = new; + automatic ExtendsMyInt#() ext1 = new; + automatic ExtendsMyInt#(MyInt2) ext2 = new; + typedef bit my_bit_t; Bar#(.A(my_bit_t)) bar_a_bit = new; Bar#(.B(my_bit_t)) bar_b_bit = new; @@ -123,6 +142,9 @@ module t (/*AUTOARG*/); if (getter1.get_1() != 1) $stop; + if (ext1.get_this_type_x() != 1) $stop; + if (ext2.get_this_type_x() != 2) $stop; + $write("*-* All Finished *-*\n"); $finish; end From 08330bad0b902e291ddfd73b866b7d2b207bf4a4 Mon Sep 17 00:00:00 2001 From: Peter Monsson Date: Fri, 21 Apr 2023 14:07:22 +0200 Subject: [PATCH 142/155] Fix variables in class methods to be automatic (#4111) (#4137) --- src/V3LinkParse.cpp | 3 ++ test_regress/t/t_class_param_type.v | 4 +- test_regress/t/t_static_function_in_class.pl | 21 ++++++++ test_regress/t/t_static_function_in_class.v | 51 ++++++++++++++++++++ 4 files changed, 77 insertions(+), 2 deletions(-) create mode 100755 test_regress/t/t_static_function_in_class.pl create mode 100644 test_regress/t/t_static_function_in_class.v diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 621dd013d..3b7d8eb0a 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -231,6 +231,9 @@ private: nodep->v3warn(STATICVAR, "Static variable with assignment declaration declared in a " "loop converted to automatic"); } + if (m_ftaskp && m_ftaskp->classMethod() && nodep->lifetime().isNone()) { + nodep->lifetime(VLifetime::AUTOMATIC); + } if (nodep->lifetime().isNone() && nodep->varType() != VVarType::PORT) { nodep->lifetime(m_lifetime); } diff --git a/test_regress/t/t_class_param_type.v b/test_regress/t/t_class_param_type.v index 86b1d8f67..e9f17ef14 100644 --- a/test_regress/t/t_class_param_type.v +++ b/test_regress/t/t_class_param_type.v @@ -29,7 +29,7 @@ typedef cls_t cls2_t; class Singleton #(type T=int); static function Singleton#(T) self; - Singleton#(T) c = new; + static Singleton#(T) c = new; return c; endfunction function int get_size; @@ -39,7 +39,7 @@ endclass class SingletonUnusedDefault #(type T=int); static function SingletonUnusedDefault#(T) self; - SingletonUnusedDefault#(T) c = new; + static SingletonUnusedDefault#(T) c = new; return c; endfunction endclass diff --git a/test_regress/t/t_static_function_in_class.pl b/test_regress/t/t_static_function_in_class.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_static_function_in_class.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 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); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_static_function_in_class.v b/test_regress/t/t_static_function_in_class.v new file mode 100644 index 000000000..ab9a80288 --- /dev/null +++ b/test_regress/t/t_static_function_in_class.v @@ -0,0 +1,51 @@ +// DESCRIPTION: Verilator: Simple static elaboration case +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2015 by Todd Strader. +// SPDX-License-Identifier: CC0-1.0 + +class string_utils; + typedef string array_of_string[]; + + static function array_of_string split_by_dash(string s); + string parts[$]; + int last_char_position = -1; + for (int i = 0; i < s.len(); i++) begin + if (i == s.len()-1) begin + parts.push_back(s.substr(last_char_position+1, i)); + end + // Can't remove this, because then the code will work + if (string'(s[i]) == "-") begin + parts.push_back(s.substr(last_char_position+1, i-1)); + last_char_position = i; + end + end // for (int i = 0; i < s.len(); i++) + return parts; + endfunction // split_by_dash +endclass // string_utils + +class filter; + local static filter single_instance; + + static function filter get(); + if (single_instance == null) + single_instance = new(); + return single_instance; + endfunction // get + + local function new(); + string parts[] = string_utils::split_by_dash("*"); + if (parts.size() != 1) + $fatal(0, "Expected single element"); + if (parts[0] != "*") + $fatal(0, "Expected element to be *"); + endfunction // new +endclass // filter + +module t (/*AUTOARG*/); + const filter _filter = filter::get(); + initial begin + $write("*-* All Finished *-*\n"); + $finish(); + end +endmodule From cac634d39b7cfbedb49d37160d4e518dea9aae5b Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Sun, 23 Apr 2023 14:49:44 +0200 Subject: [PATCH 143/155] Fix DfgToAst conversion of CountBits (#4101) (#4143) --- Changes | 1 + src/V3DfgDfgToAst.cpp | 3 +-- test_regress/t/t_dfg_4104.pl | 16 ++++++++++++++++ test_regress/t/t_dfg_4104.v | 12 ++++++++++++ 4 files changed, 30 insertions(+), 2 deletions(-) create mode 100755 test_regress/t/t_dfg_4104.pl create mode 100644 test_regress/t/t_dfg_4104.v diff --git a/Changes b/Changes index 75c95ee2f..8f4241c80 100644 --- a/Changes +++ b/Changes @@ -41,6 +41,7 @@ Verilator 5.009 devel * Fix interface generate begin (#4065). [Srinivasan Venkataramanan] * Fix false error on new const assignment (#4098). [Tudor Timi] * Fix unpacked structs under classes (#4102). [Tudor Timi] +* Fix DFG error on $countbits (#4101). [Paul Donahue] * Fix false ENUMVALUE on expressions and arrays. * Fix unnecessary verilated_std.sv waivers in --waiver-output. diff --git a/src/V3DfgDfgToAst.cpp b/src/V3DfgDfgToAst.cpp index 3932162be..6667ee35f 100644 --- a/src/V3DfgDfgToAst.cpp +++ b/src/V3DfgDfgToAst.cpp @@ -59,8 +59,7 @@ AstCountOnes* makeNode( // const DfgCountOnes* vtxp, AstNodeExpr* op1) { AstCountOnes* const nodep = new AstCountOnes{vtxp->fileline(), op1}; // Set dtype same as V3Width - const int selwidth = V3Number::log2b(nodep->lhsp()->width()) + 1; - nodep->dtypeSetLogicSized(selwidth, VSigning::UNSIGNED); + nodep->dtypeSetLogicSized(32, VSigning::UNSIGNED); return nodep; } diff --git a/test_regress/t/t_dfg_4104.pl b/test_regress/t/t_dfg_4104.pl new file mode 100755 index 000000000..4087b203c --- /dev/null +++ b/test_regress/t/t_dfg_4104.pl @@ -0,0 +1,16 @@ +#!/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 Geza Lore. 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(vlt => 1); + +compile(); + +ok(1); +1; diff --git a/test_regress/t/t_dfg_4104.v b/test_regress/t/t_dfg_4104.v new file mode 100644 index 000000000..508f93a57 --- /dev/null +++ b/test_regress/t/t_dfg_4104.v @@ -0,0 +1,12 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Geza Lore. +// SPDX-License-Identifier: CC0-1.0 + +module v(input logic t); +endmodule + +module top(input logic [2:0] c); + v v1((int'(c) + int'($countones(c))) > 2); +endmodule From 5a98c1a3b19ea9ab7f2c158141fbfa9f38e5de16 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 23 Apr 2023 10:10:05 -0400 Subject: [PATCH 144/155] Commentary --- test_regress/t/t_dfg_4104.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_regress/t/t_dfg_4104.pl b/test_regress/t/t_dfg_4104.pl index 4087b203c..32bdf873d 100755 --- a/test_regress/t/t_dfg_4104.pl +++ b/test_regress/t/t_dfg_4104.pl @@ -2,7 +2,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } # DESCRIPTION: Verilator: Verilog Test driver/expect definition # -# Copyright 2023 by Geza Lore. This program is free software; you +# 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. From cbeb9d39ff7c3ee4ce696943532b90cf83041fc0 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 23 Apr 2023 10:18:48 -0400 Subject: [PATCH 145/155] Fix -CFLAGS to allow overriding optimization levels (#4140). --- Changes | 1 + include/verilated.mk.in | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Changes b/Changes index 8f4241c80..c10b4aa9d 100644 --- a/Changes +++ b/Changes @@ -42,6 +42,7 @@ Verilator 5.009 devel * Fix false error on new const assignment (#4098). [Tudor Timi] * Fix unpacked structs under classes (#4102). [Tudor Timi] * Fix DFG error on $countbits (#4101). [Paul Donahue] +* Fix -CFLAGS to allow overriding optimization levels (#4140). [Peter Monsson] * Fix false ENUMVALUE on expressions and arrays. * Fix unnecessary verilated_std.sv waivers in --waiver-output. diff --git a/include/verilated.mk.in b/include/verilated.mk.in index 56257b9f4..7a2d51ff6 100644 --- a/include/verilated.mk.in +++ b/include/verilated.mk.in @@ -235,14 +235,16 @@ $(VM_PREFIX)__ALL.a: $(VK_OBJS) $(VM_HIER_LIBS) ifneq ($(VM_DEFAULT_RULES),0) # Anything not in $(VK_SLOW_OBJS) or $(VK_GLOBAL_OBJS), including verilated.o # and user files passed on the Verilator command line use this rule. +# We put OPT_FAST/OPT_SLOW/OPT_GLOBAL before the other flags to +# allow USER_CPPFLAGS to override them %.o: %.cpp - $(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o $@ $< + $(OBJCACHE) $(CXX) $(OPT_FAST) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $< $(VK_SLOW_OBJS): %.o: %.cpp - $(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_SLOW) -c -o $@ $< + $(OBJCACHE) $(CXX) $(OPT_SLOW) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $< $(VK_GLOBAL_OBJS): %.o: %.cpp - $(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_GLOBAL) -c -o $@ $< + $(OBJCACHE) $(CXX) $(OPT_GLOBAL) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $< endif #Default rule embedded in make: From 0e769d42a12765c4318810093dfe0f6bc8ef7068 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Thu, 13 Apr 2023 13:44:54 +0100 Subject: [PATCH 146/155] Optimize trigger evaluation Pack the elements of VlTriggerVec as dense bits (instead of a 1 byte bool per bit), and check whether they are set on a word granularity. This effectively transforms conditions of the form `if (trig.at(0) | trig.at(2) | trig.at(64))` into `if (trig.word(0) & 0x5 | trig.word(1) & 0x1)`. This improves OpenTitan ST by about 1%, worth more on some other designs. --- Changes | 1 + include/verilated.h | 9 ++ include/verilated_types.h | 22 ++-- include/verilated_vcd_c.cpp | 10 -- src/V3AstNodes.cpp | 2 +- src/V3Const.cpp | 179 +++++++++++++++++----------- src/V3Sched.cpp | 79 +++++++----- test_regress/t/t_xml_debugcheck.out | 73 +++++++----- 8 files changed, 224 insertions(+), 151 deletions(-) diff --git a/Changes b/Changes index c10b4aa9d..1c7cf0e4b 100644 --- a/Changes +++ b/Changes @@ -23,6 +23,7 @@ Verilator 5.009 devel * Support complicated IEEE 'for' assignments. * Support $fopen as an expression. * Support ++/-- on dotted member variables. +* Optimize static trigger evaluation (#4142). [Geza Lore, X-EPIC] * Change range order warning from LITENDIAN to ASCRANGE (#4010). [Iztok Jeras] * Change ZERODLY to a warning. * Fix random internal crashes (#666). [Dag Lem] diff --git a/include/verilated.h b/include/verilated.h index a1bad1d49..ac2d3c773 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -149,6 +149,15 @@ enum VerilatedVarFlags { VLVF_DPI_CLAY = (1 << 10) // DPI compatible C standard layout }; +//============================================================================= +// Utility functions + +template +inline constexpr size_t roundUpToMultipleOf(size_t value) { + static_assert((N & (N - 1)) == 0, "'N' must be a power of 2"); + return (value + N - 1) & ~(N - 1); +} + //========================================================================= // Mutex and threading support diff --git a/include/verilated_types.h b/include/verilated_types.h index 940aeafe9..0214e8fb4 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -79,9 +79,9 @@ extern std::string VL_TO_STRING_W(int words, const WDataInP obj); template // class VlTriggerVec final { // TODO: static assert T_size > 0, and don't generate when empty -private: + // MEMBERS - std::array m_flags; // State of the assoc array + alignas(16) std::array(T_size) / 64> m_flags; // The flags public: // CONSTRUCTOR @@ -91,10 +91,18 @@ public: // METHODS // Set all elements to false - void clear() { m_flags.fill(false); } + void clear() { m_flags.fill(0); } - // Reference to element at 'index' - bool& at(size_t index) { return m_flags.at(index); } + // Word at given 'wordIndex' + uint64_t word(size_t wordIndex) const { return m_flags[wordIndex]; } + + // Set specified flag to given value + void set(size_t index, bool value) { + uint64_t& w = m_flags[index / 64]; + const size_t bitIndex = index % 64; + w &= ~(1ULL << bitIndex); + w |= (static_cast(value) << bitIndex); + } // Return true iff at least one element is set bool any() const { @@ -104,13 +112,13 @@ public: } // Set all elements true in 'this' that are set in 'other' - void set(const VlTriggerVec& other) { + void thisOr(const VlTriggerVec& other) { for (size_t i = 0; i < m_flags.size(); ++i) m_flags[i] |= other.m_flags[i]; } // Set elements of 'this' to 'a & !b' element-wise void andNot(const VlTriggerVec& a, const VlTriggerVec& b) { - for (size_t i = 0; i < m_flags.size(); ++i) m_flags[i] = a.m_flags[i] && !b.m_flags[i]; + for (size_t i = 0; i < m_flags.size(); ++i) m_flags[i] = a.m_flags[i] & ~b.m_flags[i]; } }; diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index f1d93a183..e9efd953c 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -61,16 +61,6 @@ constexpr unsigned VL_TRACE_MAX_VCD_CODE_SIZE = 5; // Maximum length of a VCD s // cache-lines. constexpr unsigned VL_TRACE_SUFFIX_ENTRY_SIZE = 8; // Size of a suffix entry -//============================================================================= -// Utility functions: TODO: put these in a common place and share them. - -template -static size_t roundUpToMultipleOf(size_t value) { - static_assert((N & (N - 1)) == 0, "'N' must be a power of 2"); - size_t mask = N - 1; - return (value + mask) & ~mask; -} - //============================================================================= // Specialization of the generics for this trace format diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 3ebd67499..6c300058f 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -2321,7 +2321,7 @@ int AstCMethodHard::instrCount() const { if (AstBasicDType* const basicp = fromp()->dtypep()->basicp()) { // TODO: add a more structured description of library methods, rather than using string // matching. See #3715. - if (basicp->isTriggerVec() && m_name == "at") { + if (basicp->isTriggerVec() && m_name == "word") { // This is an important special case for scheduling so we compute it precisely, // it is simply a load. return INSTR_COUNT_LD; diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 232d4ebca..47f1a4b05 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -2746,52 +2746,74 @@ private: } } - struct SenItemCmp { - bool operator()(const AstSenItem* lhsp, const AstSenItem* rhsp) const { - if (lhsp->type() < rhsp->type()) return true; - if (lhsp->type() > rhsp->type()) return false; - // Looks visually better if we keep sorted by name - if (!lhsp->sensp() && rhsp->sensp()) return true; - if (lhsp->sensp() && !rhsp->sensp()) return false; - if (lhsp->varrefp() && !rhsp->varrefp()) return true; - if (!lhsp->varrefp() && rhsp->varrefp()) return false; - if (lhsp->varrefp() && rhsp->varrefp()) { - if (lhsp->varrefp()->name() < rhsp->varrefp()->name()) return true; - if (lhsp->varrefp()->name() > rhsp->varrefp()->name()) return false; + class SenItemCmp final { + static int cmp(const AstNodeExpr* ap, const AstNodeExpr* bp) { + const VNType aType = ap->type(); + const VNType bType = bp->type(); + if (aType != bType) return static_cast(bType) - static_cast(aType); + + if (const AstVarRef* const aRefp = VN_CAST(ap, VarRef)) { + const AstVarRef* const bRefp = VN_AS(bp, VarRef); + // Looks visually better if we keep sorted by name + if (aRefp->name() < bRefp->name()) return -1; + if (aRefp->name() > bRefp->name()) return 1; // But might be same name with different scopes - if (lhsp->varrefp()->varScopep() < rhsp->varrefp()->varScopep()) return true; - if (lhsp->varrefp()->varScopep() > rhsp->varrefp()->varScopep()) return false; + if (aRefp->varScopep() < bRefp->varScopep()) return -1; + if (aRefp->varScopep() > bRefp->varScopep()) return 1; // Or rarely, different data types - if (lhsp->varrefp()->dtypep() < rhsp->varrefp()->dtypep()) return true; - if (lhsp->varrefp()->dtypep() > rhsp->varrefp()->dtypep()) return false; - } else if (AstCMethodHard* const lp = VN_CAST(lhsp->sensp(), CMethodHard)) { - if (AstCMethodHard* const rp = VN_CAST(rhsp->sensp(), CMethodHard)) { - if (AstVarRef* const lRefp = VN_CAST(lp->fromp(), VarRef)) { - if (AstVarRef* const rRefp = VN_CAST(rp->fromp(), VarRef)) { - if (lRefp->name() < rRefp->name()) return true; - if (lRefp->name() > rRefp->name()) return false; - // But might be same name with different scopes - if (lRefp->varScopep() < rRefp->varScopep()) return true; - if (lRefp->varScopep() > rRefp->varScopep()) return false; - // Or rarely, different data types - if (lRefp->dtypep() < rRefp->dtypep()) return true; - if (lRefp->dtypep() > rRefp->dtypep()) return false; - } - } - if (AstConst* lConstp = VN_CAST(lp->pinsp(), Const)) { - if (AstConst* rConstp = VN_CAST(rp->pinsp(), Const)) { - if (lConstp->toUInt() < rConstp->toUInt()) return true; - if (lConstp->toUInt() > rConstp->toUInt()) return false; - } - } - } + if (aRefp->dtypep() < bRefp->dtypep()) return -1; + if (aRefp->dtypep() > bRefp->dtypep()) return 1; + return 0; } - // Sort by edge, AFTER variable, as we want multiple edges for same var adjacent. - // note the SenTree optimizer requires this order (more - // general first, less general last) - if (lhsp->edgeType() < rhsp->edgeType()) return true; - if (lhsp->edgeType() > rhsp->edgeType()) return false; - return false; + + if (const AstConst* const aConstp = VN_CAST(ap, Const)) { + const AstConst* const bConstp = VN_AS(bp, Const); + if (aConstp->toUQuad() < bConstp->toUQuad()) return -1; + if (aConstp->toUQuad() > bConstp->toUQuad()) return 1; + return 0; + } + + if (const AstNodeBiop* const aBiOpp = VN_CAST(ap, NodeBiop)) { + const AstNodeBiop* const bBiOpp = VN_AS(bp, NodeBiop); + // Compare RHSs first as LHS might be const, but the variable term should become + // adjacent for optimization if identical. + if (const int c = cmp(aBiOpp->rhsp(), bBiOpp->rhsp())) return c; + return cmp(aBiOpp->lhsp(), bBiOpp->lhsp()); + } + + if (const AstCMethodHard* const aCallp = VN_CAST(ap, CMethodHard)) { + const AstCMethodHard* const bCallp = VN_AS(bp, CMethodHard); + if (aCallp->name() < bCallp->name()) return -1; + if (aCallp->name() > bCallp->name()) return 1; + if (const int c = cmp(aCallp->fromp(), bCallp->fromp())) return c; + AstNodeExpr* aPinsp = aCallp->pinsp(); + AstNodeExpr* bPinsp = bCallp->pinsp(); + while (aPinsp && bPinsp) { + if (const int c = cmp(aPinsp, bPinsp)) return c; + aPinsp = VN_AS(aPinsp->nextp(), NodeExpr); + bPinsp = VN_AS(bPinsp->nextp(), NodeExpr); + } + return aPinsp ? -1 : bPinsp ? 1 : 0; + } + + return 0; + } + + public: + bool operator()(const AstSenItem* lhsp, const AstSenItem* rhsp) const { + AstNodeExpr* const lSensp = lhsp->sensp(); + AstNodeExpr* const rSensp = rhsp->sensp(); + if (lSensp && rSensp) { + // If both terms have sensitivity expressions, recursively compare them + if (const int c = cmp(lSensp, rSensp)) return c < 0; + } else if (lSensp || rSensp) { + // Terms with sensitivity expressions come after those without + return rSensp; + } + // Finally sort by edge, AFTER variable, as we want multiple edges for same var + // adjacent. note the SenTree optimizer requires this order (more general first, + // less general last) + return lhsp->edgeType() < rhsp->edgeType(); } }; @@ -2816,9 +2838,8 @@ private: } } - // Sort the sensitivity names so "posedge a or b" and "posedge b or a" end up together. - // Also, remove duplicate assignments, and fold POS&NEGs into ANYEDGEs - // Make things a little faster; check first if we need a sort + // Pass 1: Sort the sensitivity items so "posedge a or b" and "posedge b or a" and + // similar, optimizable expressions end up next to each other. for (AstSenItem *nextp, *senp = nodep->sensesp(); senp; senp = nextp) { nextp = VN_AS(senp->nextp(), SenItem); // cppcheck-suppress unassignedVariable // cppcheck bug @@ -2838,35 +2859,53 @@ private: } } - // Pass2, remove dup edges - for (AstSenItem *nextp, *senp = nodep->sensesp(); senp; senp = nextp) { + // Pass 2, remove duplicates and simplify adjacent terms if possible + for (AstSenItem *senp = nodep->sensesp(), *nextp; senp; senp = nextp) { nextp = VN_AS(senp->nextp(), SenItem); - AstSenItem* const litemp = senp; - AstSenItem* const ritemp = nextp; - if (ritemp) { - if ((litemp->sensp() && ritemp->sensp() - && litemp->sensp()->sameGateTree(ritemp->sensp())) - || (!litemp->sensp() && !ritemp->sensp())) { - // We've sorted in the order ANY, BOTH, POS, NEG, - // so we don't need to try opposite orders - if ((litemp->edgeType() == VEdgeType::ET_POSEDGE // POS or NEG -> BOTH - && ritemp->edgeType() == VEdgeType::ET_NEGEDGE) - || (litemp->edgeType() == ritemp->edgeType()) // Identical edges - ) { - // Fix edge of old node - if (litemp->edgeType() == VEdgeType::ET_POSEDGE - && ritemp->edgeType() == VEdgeType::ET_NEGEDGE) - litemp->edgeType(VEdgeType::ET_BOTHEDGE); - // Remove redundant node - VL_DO_DANGLING(ritemp->unlinkFrBack()->deleteTree(), ritemp); - VL_DANGLING(ritemp); - // Try to collapse again - nextp = litemp; + if (!nextp) break; + AstSenItem* const lItemp = senp; + AstSenItem* const rItemp = nextp; + AstNodeExpr* const lSenp = lItemp->sensp(); + AstNodeExpr* const rSenp = rItemp->sensp(); + if (!lSenp || !rSenp) continue; + + if (lSenp->sameGateTree(rSenp)) { + // POSEDGE or NEGEDGE -> BOTHEDGE. (We've sorted POSEDGE, before NEGEDGE, so we + // do not need to test for the opposite orders.) + if (lItemp->edgeType() == VEdgeType::ET_POSEDGE + && rItemp->edgeType() == VEdgeType::ET_NEGEDGE) { + // Make both terms BOTHEDGE, the second will be removed below + lItemp->edgeType(VEdgeType::ET_BOTHEDGE); + rItemp->edgeType(VEdgeType::ET_BOTHEDGE); + } + + // Remove identical expressions + if (lItemp->edgeType() == rItemp->edgeType()) { + VL_DO_DANGLING(rItemp->unlinkFrBack()->deleteTree(), rItemp); + nextp = lItemp; + } + + continue; + } + + // Not identical terms, check if they can be combined + if (lSenp->width() != rSenp->width()) continue; + if (AstAnd* const lAndp = VN_CAST(lSenp, And)) { + if (AstAnd* const rAndp = VN_CAST(rSenp, And)) { + if (AstConst* const lConstp = VN_CAST(lAndp->lhsp(), Const)) { + if (AstConst* const rConstp = VN_CAST(rAndp->lhsp(), Const)) { + if (lAndp->rhsp()->sameTree(rAndp->rhsp())) { + const V3Number lNum{lConstp->num()}; + lConstp->num().opOr(lNum, rConstp->num()); + // Remove redundant term + VL_DO_DANGLING(rItemp->unlinkFrBack()->deleteTree(), rItemp); + nextp = lItemp; + } + } } } } } - // nodep->dumpTree("- ssou: "); } } diff --git a/src/V3Sched.cpp b/src/V3Sched.cpp index 9f8896641..f9ac9cc8e 100644 --- a/src/V3Sched.cpp +++ b/src/V3Sched.cpp @@ -314,25 +314,23 @@ struct TriggerKit { void addFirstIterationTriggerAssignment(AstVarScope* counterp, uint32_t index) const { FileLine* const flp = counterp->fileline(); AstVarRef* const vrefp = new AstVarRef{flp, m_vscp, VAccess::WRITE}; - AstCMethodHard* const callp - = new AstCMethodHard{flp, vrefp, "at", new AstConst{flp, index}}; - callp->dtypeSetBit(); - callp->pure(true); - m_funcp->stmtsp()->addHereThisAsNext(new AstAssign{ - flp, callp, - new AstEq{flp, new AstVarRef{flp, counterp, VAccess::READ}, new AstConst{flp, 0}}}); + AstCMethodHard* const callp = new AstCMethodHard{flp, vrefp, "set"}; + callp->addPinsp(new AstConst{flp, index}); + callp->addPinsp( + new AstEq{flp, new AstVarRef{flp, counterp, VAccess::READ}, new AstConst{flp, 0}}); + callp->dtypeSetVoid(); + m_funcp->stmtsp()->addHereThisAsNext(callp->makeStmt()); } // Utility to set then clear the dpiExportTrigger trigger void addDpiExportTriggerAssignment(AstVarScope* dpiExportTriggerVscp, uint32_t index) const { FileLine* const flp = dpiExportTriggerVscp->fileline(); AstVarRef* const vrefp = new AstVarRef{flp, m_vscp, VAccess::WRITE}; - AstCMethodHard* const callp - = new AstCMethodHard{flp, vrefp, "at", new AstConst{flp, index}}; - callp->dtypeSetBit(); - callp->pure(true); - AstNode* stmtp - = new AstAssign{flp, callp, new AstVarRef{flp, dpiExportTriggerVscp, VAccess::READ}}; + AstCMethodHard* const callp = new AstCMethodHard{flp, vrefp, "set"}; + callp->addPinsp(new AstConst{flp, index}); + callp->addPinsp(new AstVarRef{flp, dpiExportTriggerVscp, VAccess::READ}); + callp->dtypeSetVoid(); + AstNode* const stmtp = callp->makeStmt(); stmtp->addNext(new AstAssign{flp, new AstVarRef{flp, dpiExportTriggerVscp, VAccess::WRITE}, new AstConst{flp, AstConst::BitFalse{}}}); m_funcp->stmtsp()->addHereThisAsNext(stmtp); @@ -359,10 +357,15 @@ AstSenTree* createTriggerSenTree(AstNetlist* netlistp, AstVarScope* const vscp, AstTopScope* const topScopep = netlistp->topScopep(); FileLine* const flp = topScopep->fileline(); AstVarRef* const vrefp = new AstVarRef{flp, vscp, VAccess::READ}; - AstCMethodHard* const callp = new AstCMethodHard{flp, vrefp, "at", new AstConst{flp, index}}; - callp->dtypeSetBit(); + const uint32_t wordIndex = index / 64; + const uint32_t bitIndex = index % 64; + AstCMethodHard* const callp + = new AstCMethodHard{flp, vrefp, "word", new AstConst{flp, wordIndex}}; + callp->dtypeSetUInt64(); callp->pure(true); - AstSenItem* const senItemp = new AstSenItem{flp, VEdgeType::ET_TRUE, callp}; + AstNodeExpr* const termp + = new AstAnd{flp, new AstConst{flp, AstConst::Unsized64{}, 1ULL << bitIndex}, callp}; + AstSenItem* const senItemp = new AstSenItem{flp, VEdgeType::ET_TRUE, termp}; AstSenTree* const resultp = new AstSenTree{flp, senItemp}; topScopep->addSenTreesp(resultp); return resultp; @@ -427,14 +430,28 @@ const TriggerKit createTriggers(AstNetlist* netlistp, AstCFunc* const initFuncp, new AstText{flp, "VL_DBG_MSGF(\" No triggers active\\n\");\n", true}); } + // Set the given trigger to the given value + const auto setTrig = [&](uint32_t index, AstNodeExpr* valp) { + AstVarRef* const vrefp = new AstVarRef{flp, vscp, VAccess::WRITE}; + AstCMethodHard* const callp = new AstCMethodHard{flp, vrefp, "set"}; + callp->addPinsp(new AstConst{flp, index}); + callp->addPinsp(valp); + callp->dtypeSetVoid(); + return callp->makeStmt(); + }; + // Create a reference to a trigger flag - const auto getTrigRef = [&](uint32_t index, VAccess access) { - AstVarRef* const vrefp = new AstVarRef{flp, vscp, access}; - AstConst* const idxp = new AstConst{flp, index}; - AstCMethodHard* callp = new AstCMethodHard{flp, vrefp, "at", idxp}; - callp->dtypeSetBit(); + const auto getTrig = [&](uint32_t index) { + AstVarRef* const vrefp = new AstVarRef{flp, vscp, VAccess::READ}; + const uint32_t wordIndex = index / 64; + const uint32_t bitIndex = index % 64; + AstCMethodHard* const callp + = new AstCMethodHard{flp, vrefp, "word", new AstConst{flp, wordIndex}}; + callp->dtypeSetUInt64(); callp->pure(true); - return callp; + AstNodeExpr* const termp + = new AstAnd{flp, new AstConst{flp, AstConst::Unsized64{}, 1ULL << bitIndex}, callp}; + return termp; }; // Add a debug dumping statement for this trigger @@ -446,7 +463,7 @@ const TriggerKit createTriggers(AstNetlist* netlistp, AstCFunc* const initFuncp, ss << "\\n\");\n"; const string message{ss.str()}; - AstIf* const ifp = new AstIf{flp, getTrigRef(index, VAccess::READ)}; + AstIf* const ifp = new AstIf{flp, getTrig(index)}; dumpp->addStmtsp(ifp); ifp->addThensp(new AstText{flp, message, true}); }; @@ -458,13 +475,13 @@ const TriggerKit createTriggers(AstNetlist* netlistp, AstCFunc* const initFuncp, // Add trigger computation uint32_t triggerNumber = extraTriggers.size(); - AstNode* initialTrigsp = nullptr; + AstNodeStmt* initialTrigsp = nullptr; for (const AstSenTree* const senTreep : senTreeps) { UASSERT_OBJ(senTreep->hasClocked() || senTreep->hasHybrid(), senTreep, "Cannot create trigger expression for non-clocked sensitivity"); - // Create the trigger AstSenTrees and associate it with the original AstSenTree - AstCMethodHard* const senp = getTrigRef(triggerNumber, VAccess::READ); + // Create the trigger AstSenTrees and associate them with the original AstSenTree + AstNodeExpr* const senp = getTrig(triggerNumber); AstSenItem* const senItemp = new AstSenItem{flp, VEdgeType::ET_TRUE, senp}; AstSenTree* const trigpSenp = new AstSenTree{flp, senItemp}; topScopep->addSenTreesp(trigpSenp); @@ -472,14 +489,12 @@ const TriggerKit createTriggers(AstNetlist* netlistp, AstCFunc* const initFuncp, // Add the trigger computation const auto& pair = senExprBuilder.build(senTreep); - funcp->addStmtsp( - new AstAssign{flp, getTrigRef(triggerNumber, VAccess::WRITE), pair.first}); + funcp->addStmtsp(setTrig(triggerNumber, pair.first)); // Add initialization time trigger if (pair.second || v3Global.opt.xInitialEdge()) { - AstNode* const assignp = new AstAssign{flp, getTrigRef(triggerNumber, VAccess::WRITE), - new AstConst{flp, 1}}; - initialTrigsp = AstNode::addNext(initialTrigsp, assignp); + initialTrigsp + = AstNode::addNext(initialTrigsp, setTrig(triggerNumber, new AstConst{flp, 1})); } // Add a debug statement for this trigger @@ -803,7 +818,7 @@ AstStmtExpr* createTriggerSetCall(FileLine* const flp, AstVarScope* const toVscp AstVarScope* const fromVscp) { AstVarRef* const lhsp = new AstVarRef{flp, toVscp, VAccess::WRITE}; AstVarRef* const argp = new AstVarRef{flp, fromVscp, VAccess::READ}; - AstCMethodHard* const callp = new AstCMethodHard{flp, lhsp, "set", argp}; + AstCMethodHard* const callp = new AstCMethodHard{flp, lhsp, "thisOr", argp}; callp->dtypeSetVoid(); return callp->makeStmt(); } diff --git a/test_regress/t/t_xml_debugcheck.out b/test_regress/t/t_xml_debugcheck.out index e99f614c6..11a9f8501 100644 --- a/test_regress/t/t_xml_debugcheck.out +++ b/test_regress/t/t_xml_debugcheck.out @@ -600,22 +600,22 @@ - - - - - - - - - - - - + + + + + + + + + + + + - + @@ -647,10 +647,13 @@ - - - - + + + + + + + @@ -673,10 +676,13 @@ - - - - + + + + + + + @@ -1505,10 +1511,13 @@ - - - - + + + + + + + @@ -1609,7 +1618,7 @@ - + @@ -1668,7 +1677,7 @@ - + @@ -1763,7 +1772,7 @@ - + @@ -1775,7 +1784,7 @@ - + @@ -1795,16 +1804,18 @@ - + + + - + From f794180865968608255a5fae1a88d04ec1ac80a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Risto=20Peja=C5=A1inovi=C4=87?= Date: Mon, 24 Apr 2023 13:28:29 +0200 Subject: [PATCH 147/155] Fix hier attribute of --xml-only cell section to respect begin blocks (#4129) (#4133) Co-authored-by: Risto Pejasinovic --- Changes | 1 + docs/CONTRIBUTORS | 1 + src/V3EmitXml.cpp | 9 +++- test_regress/t/t_xml_begin_hier.out | 82 +++++++++++++++++++++++++++++ test_regress/t/t_xml_begin_hier.pl | 25 +++++++++ test_regress/t/t_xml_begin_hier.v | 33 ++++++++++++ 6 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 test_regress/t/t_xml_begin_hier.out create mode 100755 test_regress/t/t_xml_begin_hier.pl create mode 100644 test_regress/t/t_xml_begin_hier.v diff --git a/Changes b/Changes index 1c7cf0e4b..360662687 100644 --- a/Changes +++ b/Changes @@ -46,6 +46,7 @@ Verilator 5.009 devel * Fix -CFLAGS to allow overriding optimization levels (#4140). [Peter Monsson] * Fix false ENUMVALUE on expressions and arrays. * Fix unnecessary verilated_std.sv waivers in --waiver-output. +* Fix missing begin block hierarchy in --xml-only cells section (#4129). [Risto Pejašinović] Verilator 5.008 2023-03-04 diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 40c782fb0..5c6a0ee2c 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -122,6 +122,7 @@ Qingyao Sun Rafal Kapuscik Raynard Qiao Richard Myers +Risto Pejašinović Robert Balas Rupert Swarbrick Ryszard Rozak diff --git a/src/V3EmitXml.cpp b/src/V3EmitXml.cpp index 2c2404d44..c3e3cfeac 100644 --- a/src/V3EmitXml.cpp +++ b/src/V3EmitXml.cpp @@ -403,8 +403,8 @@ private: void visit(AstCell* nodep) override { if (nodep->modp()->dead()) return; if (!m_hasChildren) m_os << ">\n"; - m_os << "fileline()->xmlDetailedLocation() << " name=\"" << nodep->name() - << "\"" + m_os << "fileline()->xmlDetailedLocation() + << " name=\"" << nodep->name() << "\"" << " submodname=\"" << nodep->modName() << "\"" << " hier=\"" << m_hier + nodep->name() << "\""; const std::string hier = m_hier; @@ -419,6 +419,11 @@ private: m_hier = hier; m_hasChildren = true; } + void visit(AstBegin* nodep) override { + VL_RESTORER(m_hier); + if (nodep->name() != "") m_hier += nodep->name() + "."; + iterateChildrenConst(nodep); + } //----- void visit(AstNode* nodep) override { iterateChildrenConst(nodep); } diff --git a/test_regress/t/t_xml_begin_hier.out b/test_regress/t/t_xml_begin_hier.out new file mode 100644 index 000000000..0a71073d6 --- /dev/null +++ b/test_regress/t/t_xml_begin_hier.out @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test_regress/t/t_xml_begin_hier.pl b/test_regress/t/t_xml_begin_hier.pl new file mode 100755 index 000000000..d25c191ff --- /dev/null +++ b/test_regress/t/t_xml_begin_hier.pl @@ -0,0 +1,25 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2012 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(vlt => 1); + +my $out_filename = "$Self->{obj_dir}/V$Self->{name}.xml"; + +compile( + verilator_flags2 => ['--no-std', '--xml-only'], + verilator_make_gmake => 0, + make_top_shell => 0, + make_main => 0, + ); + +files_identical("$out_filename", $Self->{golden_filename}); + +ok(1); +1; diff --git a/test_regress/t/t_xml_begin_hier.v b/test_regress/t/t_xml_begin_hier.v new file mode 100644 index 000000000..1e29f0133 --- /dev/null +++ b/test_regress/t/t_xml_begin_hier.v @@ -0,0 +1,33 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Risto Pejasinovic. +// SPDX-License-Identifier: CC0-1.0 + +module submod2 (); +endmodule + +module submod #( +)(); + if(1) begin : submod_gen + wire l1_sig; + if(1) begin : nested_gen + submod2 submod_nested(); + end + submod2 submod_l1(); + end + submod2 submod_l0(); +endmodule + +module test( +); + genvar N; + generate for(N=0; N<2; N=N+1) + begin : FOR_GENERATE + submod submod_for(); + if(1) begin + submod submod_2(); + end + submod submod_3(); + end endgenerate +endmodule From c6bf9fb89e78cd9061aeff94c5d6b9fd707fafee Mon Sep 17 00:00:00 2001 From: github action Date: Mon, 24 Apr 2023 11:29:33 +0000 Subject: [PATCH 148/155] Apply 'make format' --- src/V3EmitXml.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/V3EmitXml.cpp b/src/V3EmitXml.cpp index c3e3cfeac..5dc1ed39e 100644 --- a/src/V3EmitXml.cpp +++ b/src/V3EmitXml.cpp @@ -403,8 +403,8 @@ private: void visit(AstCell* nodep) override { if (nodep->modp()->dead()) return; if (!m_hasChildren) m_os << ">\n"; - m_os << "fileline()->xmlDetailedLocation() - << " name=\"" << nodep->name() << "\"" + m_os << "fileline()->xmlDetailedLocation() << " name=\"" << nodep->name() + << "\"" << " submodname=\"" << nodep->modName() << "\"" << " hier=\"" << m_hier + nodep->name() << "\""; const std::string hier = m_hier; From 621b7e63cfff5c3bd58bd411c4f40d8e09a94c89 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Mon, 24 Apr 2023 23:24:04 +0200 Subject: [PATCH 149/155] Print the type of provided RHS in class type check (#4145) --- src/V3Width.cpp | 7 ++++--- test_regress/t/t_class_assign_bad.out | 16 ++++++++-------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 849eb393b..d1583e1c4 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -6306,13 +6306,14 @@ private: AstNodeDType* lhsDTypep) { if (AstClassRefDType* const lhsClassRefp = VN_CAST(lhsDTypep, ClassRefDType)) { UASSERT_OBJ(rhsp->dtypep(), rhsp, "Node has no type"); - if (AstClassRefDType* const rhsClassRefp - = VN_CAST(rhsp->dtypep()->skipRefp(), ClassRefDType)) { + AstNodeDType* const rhsDtypep = rhsp->dtypep()->skipRefp(); + if (AstClassRefDType* const rhsClassRefp = VN_CAST(rhsDtypep, ClassRefDType)) { if (isBaseClassRecurse(lhsClassRefp->classp(), rhsClassRefp->classp())) return; } else if (auto* const constp = VN_CAST(rhsp, Const)) { if (constp->num().isNull()) return; } - nodep->v3error(side << " expects a " << lhsDTypep->prettyTypeName()); + nodep->v3error(side << " expects a " << lhsDTypep->prettyTypeName() << ", got " + << rhsDtypep->prettyTypeName()); } } static bool similarDTypeRecurse(AstNodeDType* node1p, AstNodeDType* node2p) { diff --git a/test_regress/t/t_class_assign_bad.out b/test_regress/t/t_class_assign_bad.out index 6c909e986..38ab6fe11 100644 --- a/test_regress/t/t_class_assign_bad.out +++ b/test_regress/t/t_class_assign_bad.out @@ -1,32 +1,32 @@ -%Error: t/t_class_assign_bad.v:25:9: Assign RHS expects a CLASSREFDTYPE 'Cls' +%Error: t/t_class_assign_bad.v:25:9: Assign RHS expects a CLASSREFDTYPE 'Cls', got BASICDTYPE 'logic' : ... In instance t 25 | c = 0; | ^ -%Error: t/t_class_assign_bad.v:26:9: Assign RHS expects a CLASSREFDTYPE 'Cls' +%Error: t/t_class_assign_bad.v:26:9: Assign RHS expects a CLASSREFDTYPE 'Cls', got BASICDTYPE 'logic' : ... In instance t 26 | c = 1; | ^ -%Error: t/t_class_assign_bad.v:27:9: Assign RHS expects a CLASSREFDTYPE 'Cls' +%Error: t/t_class_assign_bad.v:27:9: Assign RHS expects a CLASSREFDTYPE 'Cls', got CLASSREFDTYPE 'Cls2' : ... In instance t 27 | c = c2; | ^ -%Error: t/t_class_assign_bad.v:28:13: Assign RHS expects a CLASSREFDTYPE 'ClsExt' +%Error: t/t_class_assign_bad.v:28:13: Assign RHS expects a CLASSREFDTYPE 'ClsExt', got CLASSREFDTYPE 'Cls' : ... In instance t 28 | c_ext = c; | ^ -%Error: t/t_class_assign_bad.v:30:7: Function Argument expects a CLASSREFDTYPE 'Cls' +%Error: t/t_class_assign_bad.v:30:7: Function Argument expects a CLASSREFDTYPE 'Cls', got BASICDTYPE 'logic' : ... In instance t 30 | t(0); | ^ -%Error: t/t_class_assign_bad.v:31:7: Function Argument expects a CLASSREFDTYPE 'Cls' +%Error: t/t_class_assign_bad.v:31:7: Function Argument expects a CLASSREFDTYPE 'Cls', got BASICDTYPE 'logic' : ... In instance t 31 | t(1); | ^ -%Error: t/t_class_assign_bad.v:32:7: Function Argument expects a CLASSREFDTYPE 'Cls' +%Error: t/t_class_assign_bad.v:32:7: Function Argument expects a CLASSREFDTYPE 'Cls', got CLASSREFDTYPE 'Cls2' : ... In instance t 32 | t(c2); | ^ -%Error: t/t_class_assign_bad.v:33:7: Function Argument expects a CLASSREFDTYPE 'ClsExt' +%Error: t/t_class_assign_bad.v:33:7: Function Argument expects a CLASSREFDTYPE 'ClsExt', got CLASSREFDTYPE 'Cls' : ... In instance t 33 | f(c); | ^ From ee5c0a29024dc6777491e78c913e9efc1bcdbe6f Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Mon, 24 Apr 2023 23:25:53 +0200 Subject: [PATCH 150/155] Support parameterized class references in extends statement (#4146) --- src/V3LinkDot.cpp | 209 ++++++++++++------------- test_regress/t/t_class_extends_param.v | 36 ++++- 2 files changed, 139 insertions(+), 106 deletions(-) diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 150c5d4c2..e86b2df33 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -3287,7 +3287,7 @@ private: iterateChildren(nodep); } void visit(AstClass* nodep) override { - nodep->user3SetOnce(); + if (nodep->user3SetOnce()) return; UINFO(5, " " << nodep << endl); checkNoDot(nodep); VL_RESTORER(m_curSymp); @@ -3300,117 +3300,116 @@ private: m_ds.m_dotSymp = m_curSymp = m_modSymp = m_statep->getNodeSym(nodep); m_modp = nodep; int next = 0; - for (AstNode* itemp = nodep->extendsp(); itemp; itemp = itemp->nextp()) { - if (AstClassExtends* const cextp = VN_CAST(itemp, ClassExtends)) { - // Replace abstract reference with hard pointer - // Will need later resolution when deal with parameters - if (++next == 2 && !nodep->isInterfaceClass() && !cextp->isImplements()) { - cextp->v3error("Multiple inheritance illegal on non-interface classes" - " (IEEE 1800-2017 8.13)"); - } - if (cextp->childDTypep() || cextp->dtypep()) { - // Already converted. Update symbol table to link unlinked members - importSymbolsFromExtended(nodep, cextp); - continue; - } - AstNode* cprp = cextp->classOrPkgsp(); - VSymEnt* lookSymp = m_curSymp; - if (AstDot* const dotp = VN_CAST(cextp->classOrPkgsp(), Dot)) { - dotp->user3(true); - if (AstClassOrPackageRef* lookNodep - = VN_CAST(dotp->lhsp(), ClassOrPackageRef)) { - iterate(lookNodep); - cprp = dotp->rhsp(); - lookSymp = m_statep->getNodeSym(lookNodep->classOrPackagep()); - } else { - dotp->lhsp()->v3error("Attempting to extend" // LCOV_EXCL_LINE - " using non-class under dot"); - } - } - AstClassOrPackageRef* const cpackagerefp = VN_CAST(cprp, ClassOrPackageRef); - if (VL_UNCOVERABLE(!cpackagerefp)) { - // Linking the extend gives an error before this is hit - cextp->v3error("Attempting to extend using non-class"); // LCOV_EXCL_LINE + for (AstClassExtends* cextp = nodep->extendsp(); cextp; + cextp = VN_AS(cextp->nextp(), ClassExtends)) { + // Replace abstract reference with hard pointer + // Will need later resolution when deal with parameters + if (++next == 2 && !nodep->isInterfaceClass() && !cextp->isImplements()) { + cextp->v3error("Multiple inheritance illegal on non-interface classes" + " (IEEE 1800-2017 8.13)"); + } + if (cextp->childDTypep() || cextp->dtypep()) { + // Already converted. Update symbol table to link unlinked members. + // Base class has to be visited in a case if its extends statement + // needs to be handled. Recursive inheritance was already checked. + iterate(cextp->classp()); + importSymbolsFromExtended(nodep, cextp); + continue; + } + AstNode* cprp = cextp->classOrPkgsp(); + VSymEnt* lookSymp = m_curSymp; + if (AstDot* const dotp = VN_CAST(cprp, Dot)) { + dotp->user3(true); + if (AstClassOrPackageRef* lookNodep + = VN_CAST(dotp->lhsp(), ClassOrPackageRef)) { + iterate(lookNodep); + cprp = dotp->rhsp(); + lookSymp = m_statep->getNodeSym(lookNodep->classOrPackagep()); } else { - VSymEnt* const foundp = lookSymp->findIdFallback(cpackagerefp->name()); - if (foundp) { - AstClassRefDType* classRefDtypep = nullptr; - AstClass* classp = VN_CAST(foundp->nodep(), Class); - if (classp) { - if (classp != nodep) { - // Case with recursive inheritance is handled later in this - // function - iterate(classp); - } - if (m_statep->forPrimary() - && m_extendsParam.find(classp) != m_extendsParam.end()) { - // Has a parameter as its base class - m_extendsParam.insert(nodep); - m_insideClassExtParam = true; - } - AstPin* paramsp = cpackagerefp->paramsp(); - if (paramsp) paramsp = paramsp->cloneTree(true); - classRefDtypep - = new AstClassRefDType{nodep->fileline(), classp, paramsp}; - } else if (AstParamTypeDType* const paramp - = VN_CAST(foundp->nodep(), ParamTypeDType)) { - if (m_statep->forPrimary()) { - // Extending has to be handled after V3Param.cpp - m_extendsParam.insert(nodep); - m_insideClassExtParam = true; - continue; - } else { - AstNodeDType* const paramTypep = paramp->subDTypep(); - classRefDtypep - = VN_CAST(paramTypep->cloneTree(false), ClassRefDType); - if (!classRefDtypep) { - paramTypep->v3error( - "Attempting to extend using non-class"); - } else { - classp = classRefDtypep->classp(); - } - } - } else { - cextp->v3warn(E_UNSUPPORTED, - "Unsupported: " << foundp->nodep()->prettyTypeName() - << " in AstClassExtends"); + dotp->lhsp()->v3error("Attempting to extend" // LCOV_EXCL_LINE + " using non-class under dot"); + } + } + AstClassOrPackageRef* const cpackagerefp = VN_CAST(cprp, ClassOrPackageRef); + if (VL_UNCOVERABLE(!cpackagerefp)) { + // Linking the extend gives an error before this is hit + cextp->v3error("Attempting to extend using non-class"); // LCOV_EXCL_LINE + } else { + VSymEnt* const foundp = lookSymp->findIdFallback(cpackagerefp->name()); + if (foundp) { + AstClassRefDType* classRefDtypep = nullptr; + AstClass* classp = VN_CAST(foundp->nodep(), Class); + if (classp) { + if (classp != nodep) { + // Case with recursive inheritance is handled later in this + // function + iterate(classp); } - - if (classp) { - UINFO(8, "Import to " << nodep << " from export class " << classp - << endl); - if (classp == nodep) { - cextp->v3error("Attempting to extend class " - << nodep->prettyNameQ() << " from itself"); - } else if (cextp->isImplements() && !classp->isInterfaceClass()) { - cextp->v3error( - "Attempting to implement from non-interface class " - << classp->prettyNameQ() << '\n' - << "... Suggest use 'extends'"); - } else if (!cextp->isImplements() && !nodep->isInterfaceClass() - && classp->isInterfaceClass()) { - cextp->v3error("Attempting to extend from interface class " - << classp->prettyNameQ() << '\n' - << "... Suggest use 'implements'"); + if (m_statep->forPrimary() + && m_extendsParam.find(classp) != m_extendsParam.end()) { + // Has a parameter as its base class + m_extendsParam.insert(nodep); + m_insideClassExtParam = true; + } + AstPin* paramsp = cpackagerefp->paramsp(); + if (paramsp) paramsp = paramsp->cloneTree(true); + classRefDtypep + = new AstClassRefDType{nodep->fileline(), classp, paramsp}; + } else if (AstParamTypeDType* const paramp + = VN_CAST(foundp->nodep(), ParamTypeDType)) { + if (m_statep->forPrimary()) { + // Extending has to be handled after V3Param.cpp + m_extendsParam.insert(nodep); + m_insideClassExtParam = true; + continue; + } else { + AstNodeDType* const paramTypep = paramp->subDTypep(); + classRefDtypep + = VN_CAST(paramTypep->cloneTree(false), ClassRefDType); + if (!classRefDtypep) { + paramTypep->v3error("Attempting to extend using non-class"); } else { - cextp->childDTypep(classRefDtypep); - classp->isExtended(true); - nodep->isExtended(true); - importSymbolsFromExtended(nodep, cextp); - VL_DO_DANGLING( - cextp->classOrPkgsp()->unlinkFrBack()->deleteTree(), - cpackagerefp); + classp = classRefDtypep->classp(); } } } else { - const string suggest = m_statep->suggestSymFallback( - m_curSymp, cpackagerefp->name(), LinkNodeMatcherClass{}); - cpackagerefp->v3error( - "Class for '" - << cextp->verilogKwd() // extends/implements - << "' not found: " << cpackagerefp->prettyNameQ() << '\n' - << (suggest.empty() ? "" : cpackagerefp->warnMore() + suggest)); + cextp->v3warn(E_UNSUPPORTED, + "Unsupported: " << foundp->nodep()->prettyTypeName() + << " in AstClassExtends"); } + + if (classp) { + UINFO(8, "Import to " << nodep << " from export class " << classp + << endl); + if (classp == nodep) { + cextp->v3error("Attempting to extend class " + << nodep->prettyNameQ() << " from itself"); + } else if (cextp->isImplements() && !classp->isInterfaceClass()) { + cextp->v3error("Attempting to implement from non-interface class " + << classp->prettyNameQ() << '\n' + << "... Suggest use 'extends'"); + } else if (!cextp->isImplements() && !nodep->isInterfaceClass() + && classp->isInterfaceClass()) { + cextp->v3error("Attempting to extend from interface class " + << classp->prettyNameQ() << '\n' + << "... Suggest use 'implements'"); + } else { + cextp->childDTypep(classRefDtypep); + classp->isExtended(true); + nodep->isExtended(true); + importSymbolsFromExtended(nodep, cextp); + VL_DO_DANGLING(cextp->classOrPkgsp()->unlinkFrBack()->deleteTree(), + cpackagerefp); + } + } + } else { + const string suggest = m_statep->suggestSymFallback( + m_curSymp, cpackagerefp->name(), LinkNodeMatcherClass{}); + cpackagerefp->v3error( + "Class for '" + << cextp->verilogKwd() // extends/implements + << "' not found: " << cpackagerefp->prettyNameQ() << '\n' + << (suggest.empty() ? "" : cpackagerefp->warnMore() + suggest)); } } } diff --git a/test_regress/t/t_class_extends_param.v b/test_regress/t/t_class_extends_param.v index cdec1c149..aaaedce8a 100644 --- a/test_regress/t/t_class_extends_param.v +++ b/test_regress/t/t_class_extends_param.v @@ -39,17 +39,51 @@ module t (/*AUTOARG*/ endfunction endclass + class ExtendBar1 extends Bar #(Foo); + function int get_x; + return super.get_x(); + endfunction + function int get_6; + return 2 * get_3(); + endfunction + endclass + + class ExtendBarBaz extends Bar #(Baz); + function int get_x; + return super.get_x(); + endfunction + function int get_8; + return 2 * get_4(); + endfunction + endclass + + class ExtendExtendBar extends ExtendBar; + function int get_12; + return 4 * get_3(); + endfunction + endclass + Bar #() bar_foo_i; Bar #(Baz) bar_baz_i; ExtendBar extend_bar_i; + ExtendBar1 extend_bar1_i; + ExtendBarBaz extend_bar_baz_i; + ExtendExtendBar extend_extend_bar_i; initial begin bar_foo_i = new; bar_baz_i = new; extend_bar_i = new; + extend_bar1_i = new; + extend_bar_baz_i = new; + extend_extend_bar_i = new; if (bar_foo_i.get_x() == 1 && bar_foo_i.get_3() == 3 && bar_baz_i.get_x() == 2 && bar_baz_i.get_4() == 4 && - extend_bar_i.get_x() == 1 && extend_bar_i.get_6() == 6) begin + extend_bar_i.get_x() == 1 && extend_bar_i.get_6() == 6 && + extend_bar_i.get_x() == 1 && extend_bar_i.get_6() == 6 && + extend_bar1_i.get_x() == 1 && extend_bar1_i.get_6() == 6 && + extend_bar_baz_i.get_x() == 2 && extend_bar_baz_i.get_8() == 8 && + extend_extend_bar_i.get_x() == 1 && extend_extend_bar_i.get_12() == 12) begin $write("*-* All Finished *-*\n"); $finish; end From 09e856d2f3721c77f537e5f98bdacd524349d2f9 Mon Sep 17 00:00:00 2001 From: Ryszard Rozak Date: Fri, 28 Apr 2023 13:20:25 +0200 Subject: [PATCH 151/155] Fix deleting unused parameterized classes (#4150) --- src/V3AstNodeOther.h | 3 ++ src/V3LinkDot.cpp | 15 ---------- src/V3Param.cpp | 30 +++++++++++++++++-- src/verilog.y | 1 + .../t/t_class_extends_int_param_bad.out | 2 +- .../t/t_class_extends_int_param_bad.v | 3 +- .../t/t_class_extends_param_unused.pl | 21 +++++++++++++ test_regress/t/t_class_extends_param_unused.v | 15 ++++++++++ test_regress/t/t_class_param_type.v | 14 +++++++++ .../t/t_class_param_unused_default.pl | 21 +++++++++++++ test_regress/t/t_class_param_unused_default.v | 26 ++++++++++++++++ 11 files changed, 131 insertions(+), 20 deletions(-) create mode 100755 test_regress/t/t_class_extends_param_unused.pl create mode 100644 test_regress/t/t_class_extends_param_unused.v create mode 100755 test_regress/t/t_class_param_unused_default.pl create mode 100644 test_regress/t/t_class_param_unused_default.v diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index cff2cfdbe..fc998872b 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -2118,6 +2118,7 @@ class AstClass final : public AstNodeModule { bool m_interfaceClass = false; // Interface class bool m_needRNG = false; // Need RNG, uses srandom/randomize bool m_virtual = false; // Virtual class + bool m_parameterized = false; // Parameterized class void insertCache(AstNode* nodep); public: @@ -2151,6 +2152,8 @@ public: void isVirtual(bool flag) { m_virtual = flag; } bool needRNG() const { return m_needRNG; } void needRNG(bool flag) { m_needRNG = flag; } + bool isParameterized() const { return m_parameterized; } + void isParameterized(bool flag) { m_parameterized = flag; } // Return true if this class is an extension of base class (SLOW) // Accepts nullptrs static bool isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp); diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index e86b2df33..498763fac 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -161,7 +161,6 @@ private: bool m_forPrimary; // First link bool m_forPrearray; // Compress cell__[array] refs bool m_forScopeCreation; // Remove VarXRefs for V3Scope - bool m_removeVoidParamedClasses; // Remove classes with void params public: // METHODS @@ -208,7 +207,6 @@ public: m_forPrimary = (step == LDS_PRIMARY); m_forPrearray = (step == LDS_PARAMED || step == LDS_PRIMARY); m_forScopeCreation = (step == LDS_SCOPED); - m_removeVoidParamedClasses = (step == LDS_PARAMED); s_errorThisp = this; V3Error::errorExitCb(preErrorDumpHandler); // If get error, dump self } @@ -222,7 +220,6 @@ public: bool forPrimary() const { return m_forPrimary; } bool forPrearray() const { return m_forPrearray; } bool forScopeCreation() const { return m_forScopeCreation; } - bool removeVoidParamedClasses() const { return m_removeVoidParamedClasses; } // METHODS static string nodeTextType(AstNode* nodep) { @@ -916,18 +913,6 @@ class LinkDotFindVisitor final : public VNVisitor { void visit(AstClass* nodep) override { UASSERT_OBJ(m_curSymp, nodep, "Class not under module/package/$unit"); UINFO(8, " " << nodep << endl); - // Remove classes that have void params, as they were only used for the parameterization - // step and will not be instantiated - if (m_statep->removeVoidParamedClasses()) { - for (auto* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { - if (auto* dtypep = VN_CAST(stmtp, ParamTypeDType)) { - if (VN_IS(dtypep->subDTypep(), VoidDType)) { - VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - return; - } - } - } - } VL_RESTORER(m_scope); VL_RESTORER(m_classOrPackagep); VL_RESTORER(m_modSymp); diff --git a/src/V3Param.cpp b/src/V3Param.cpp index b1324d5a8..e15d38834 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -567,8 +567,9 @@ class ParamProcessor final { // 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* const newmodp = srcModp->cloneTree(false); - if (VN_IS(srcModp, Class)) { - replaceRefsRecurse(newmodp->stmtsp(), VN_AS(newmodp, Class), VN_AS(srcModp, Class)); + if (AstClass* const newClassp = VN_CAST(newmodp, Class)) { + newClassp->isParameterized(false); + replaceRefsRecurse(newmodp->stmtsp(), newClassp, VN_AS(srcModp, Class)); } newmodp->name(newname); @@ -809,6 +810,9 @@ class ParamProcessor final { if (!any_overrides) { UINFO(8, "Cell parameters all match original values, skipping expansion.\n"); + // Mark that the defeult instance is used. + // It will be checked only if srcModpr is a class. + srcModpr->user2(true); } else if (AstNodeModule* const paramedModp = m_hierBlocks.findByParams(srcModpr->name(), paramsp, m_modp)) { paramedModp->dead(false); @@ -916,7 +920,7 @@ public: class ParamVisitor final : public VNVisitor { // NODE STATE // AstNodeModule::user1 -> bool: already fixed level - + // AstClass::user2 -> bool: Referenced (value read only in parameterized classes) // STATE ParamProcessor m_processor; // De-parameterize a cell, build modules UnrollStateful m_unroller; // Loop unroller @@ -928,6 +932,7 @@ class ParamVisitor final : public VNVisitor { std::vector m_dots; // Dot references to process std::multimap m_cellps; // Cells left to process (in current module) std::multimap m_workQueue; // Modules left to process + std::vector m_paramClasses; // Parameterized classes // Map from AstNodeModule to set of all AstNodeModules that instantiates it. std::unordered_map> m_parentps; @@ -1047,6 +1052,14 @@ class ParamVisitor final : public VNVisitor { void visit(AstNodeModule* nodep) override { if (nodep->recursiveClone()) nodep->dead(true); // Fake, made for recursive elimination if (nodep->dead()) return; // Marked by LinkDot (and above) + if (AstClass* const classp = VN_CAST(nodep, Class)) { + if (classp->isParameterized()) { + // Don't enter into a definition. + // If a class is used, it will be visited through a reference + m_paramClasses.push_back(classp); + return; + } + } if (m_iterateModule) { // Iterating body UINFO(4, " MOD-under-MOD. " << nodep << endl); @@ -1363,6 +1376,17 @@ public: // Re-insert modules for (AstNodeModule* const modp : modps) netlistp->addModulesp(modp); + + for (AstClass* const classp : m_paramClasses) { + if (!classp->user2()) { + // Unreferenced, so it can be removed + VL_DO_DANGLING(pushDeletep(classp->unlinkFrBack()), classp); + } else { + // Referenced. classp became a specialized class with the default + // values of parameters and is not a parameterized class anymore + classp->isParameterized(false); + } + } } } ~ParamVisitor() override = default; diff --git a/src/verilog.y b/src/verilog.y index 844853f10..c7d17f3fd 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -6775,6 +6775,7 @@ class_declaration: // ==IEEE: part of class_declaration } /*cont*/ class_itemListE yENDCLASS endLabelE { $$ = $1; $1->addMembersp($2); + if ($2) $1->isParameterized(true); $1->addExtendsp($3); $1->addExtendsp($4); $1->addMembersp($7); diff --git a/test_regress/t/t_class_extends_int_param_bad.out b/test_regress/t/t_class_extends_int_param_bad.out index 8f75bf3af..e16b75da5 100644 --- a/test_regress/t/t_class_extends_int_param_bad.out +++ b/test_regress/t/t_class_extends_int_param_bad.out @@ -1,5 +1,5 @@ %Error: t/t_class_extends_int_param_bad.v:9:23: Attempting to extend using non-class : ... In instance t - 9 | class bar #(type T=int) extends T; + 9 | class Bar #(type T=int) extends T; | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_class_extends_int_param_bad.v b/test_regress/t/t_class_extends_int_param_bad.v index f5ee566eb..062bb014c 100644 --- a/test_regress/t/t_class_extends_int_param_bad.v +++ b/test_regress/t/t_class_extends_int_param_bad.v @@ -6,10 +6,11 @@ module t (/*AUTOARG*/); - class bar #(type T=int) extends T; + class Bar #(type T=int) extends T; endclass initial begin + Bar#() bar; $stop; end endmodule diff --git a/test_regress/t/t_class_extends_param_unused.pl b/test_regress/t/t_class_extends_param_unused.pl new file mode 100755 index 000000000..aabcde63e --- /dev/null +++ b/test_regress/t/t_class_extends_param_unused.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 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); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_extends_param_unused.v b/test_regress/t/t_class_extends_param_unused.v new file mode 100644 index 000000000..fcc46a865 --- /dev/null +++ b/test_regress/t/t_class_extends_param_unused.v @@ -0,0 +1,15 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Foo#(type T = logic) extends T; +endclass + +module t (/*AUTOARG*/); + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_param_type.v b/test_regress/t/t_class_param_type.v index e9f17ef14..24b7da7a7 100644 --- a/test_regress/t/t_class_param_type.v +++ b/test_regress/t/t_class_param_type.v @@ -90,6 +90,16 @@ class ExtendsMyInt #(type T=MyInt1) extends T; endfunction endclass +class StaticX; + static int val = 1; +endclass + +class GetStaticXVal #(type T = int); + static function int get; + return T::val; + endfunction +endclass + module t (/*AUTOARG*/); initial begin @@ -112,6 +122,8 @@ module t (/*AUTOARG*/); automatic ExtendsMyInt#() ext1 = new; automatic ExtendsMyInt#(MyInt2) ext2 = new; + automatic GetStaticXVal#(StaticX) get_statix_x_val = new; + typedef bit my_bit_t; Bar#(.A(my_bit_t)) bar_a_bit = new; Bar#(.B(my_bit_t)) bar_b_bit = new; @@ -145,6 +157,8 @@ module t (/*AUTOARG*/); if (ext1.get_this_type_x() != 1) $stop; if (ext2.get_this_type_x() != 2) $stop; + if (get_statix_x_val.get() != 1) $stop; + $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_class_param_unused_default.pl b/test_regress/t/t_class_param_unused_default.pl new file mode 100755 index 000000000..aabcde63e --- /dev/null +++ b/test_regress/t/t_class_param_unused_default.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 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); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_param_unused_default.v b/test_regress/t/t_class_param_unused_default.v new file mode 100644 index 000000000..e031fa36f --- /dev/null +++ b/test_regress/t/t_class_param_unused_default.v @@ -0,0 +1,26 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Bar#(type T = int); + T t; + function new; + t = new; + endfunction +endclass + +class Baz; + int x = 1; +endclass + +module t (/*AUTOARG*/); + initial begin + Bar#(Baz) bar_baz = new; + if (bar_baz.t.x != 1) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From 9130eb8b99dc1bac4d12c352968a90b373bacda3 Mon Sep 17 00:00:00 2001 From: Toru Niina Date: Fri, 28 Apr 2023 20:21:09 +0900 Subject: [PATCH 152/155] Fix DPI function type alias (#4148) (#4149) --- docs/CONTRIBUTORS | 1 + src/V3EmitCSyms.cpp | 3 ++- test_regress/t/t_timing_dpi.cpp | 12 +++++++++ test_regress/t/t_timing_dpi.pl | 28 ++++++++++++++++++++ test_regress/t/t_timing_dpi.v | 46 +++++++++++++++++++++++++++++++++ 5 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 test_regress/t/t_timing_dpi.cpp create mode 100755 test_regress/t/t_timing_dpi.pl create mode 100644 test_regress/t/t_timing_dpi.v diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 5c6a0ee2c..629517575 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -142,6 +142,7 @@ Tobias Wölfel Todd Strader Tomasz Gorochowik Topa Topino +Toru Niina Tymoteusz Blazejczyk Udi Finkelstein Unai Martinez-Corral diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index a1b64ea7f..59b299d7b 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -432,7 +432,8 @@ void EmitCSyms::emitSymHdr() { if (funcp->dpiExportImpl()) { const string cbtype = protect(v3Global.opt.prefix() + "__Vcb_" + funcp->cname() + "_t"); - types["using " + cbtype + " = void (*) (" + cFuncArgs(funcp) + ");\n"] = 1; + const string functype = funcp->rtnTypeVoid() + " (*) (" + cFuncArgs(funcp) + ")"; + types["using " + cbtype + " = " + functype + ";\n"] = 1; } } for (const auto& i : types) puts(i.first); diff --git a/test_regress/t/t_timing_dpi.cpp b/test_regress/t/t_timing_dpi.cpp new file mode 100644 index 000000000..d8b610a03 --- /dev/null +++ b/test_regress/t/t_timing_dpi.cpp @@ -0,0 +1,12 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Toru Niina. +// SPDX-License-Identifier: CC0-1.0 + +#include "Vt_timing_dpi__Dpi.h" + +int tb_c_wait() { + tb_sv_wait(10); + return 0; +} diff --git a/test_regress/t/t_timing_dpi.pl b/test_regress/t/t_timing_dpi.pl new file mode 100755 index 000000000..2c494cced --- /dev/null +++ b/test_regress/t/t_timing_dpi.pl @@ -0,0 +1,28 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# This file ONLY is placed under the Creative Commons Public Domain, for +# any use, without warranty, 2023 by Toru Niina. +# SPDX-License-Identifier: CC0-1.0 + + +scenarios(vlt => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support") +} +else { + compile( + v_flags2 => ["t/t_timing_dpi.cpp"], + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + + execute( + check_finished => 1, + ); +} + +ok(1); +1 diff --git a/test_regress/t/t_timing_dpi.v b/test_regress/t/t_timing_dpi.v new file mode 100644 index 000000000..63d3bd43d --- /dev/null +++ b/test_regress/t/t_timing_dpi.v @@ -0,0 +1,46 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Toru Niina. +// SPDX-License-Identifier: CC0-1.0 + +`ifdef TEST_VERBOSE + `define WRITE_VERBOSE(msg) $write(msg) +`else + `define WRITE_VERBOSE(msg) +`endif + +`default_nettype none +`timescale 1ns/1ps + +module t; + + localparam cycle = 1000.0 / 100.0; + localparam halfcycle = 0.5 * cycle; + + logic clk = '0; + + import "DPI-C" context task tb_c_wait(); + + export "DPI-C" task tb_sv_wait; + task automatic tb_sv_wait(input int n); + `WRITE_VERBOSE("tb_sv_wait start..."); + repeat(n) @(negedge clk); + `WRITE_VERBOSE("tb_sv_wait done!"); + endtask + + always #halfcycle clk = ~clk; + + initial begin + `WRITE_VERBOSE("test start"); + repeat(10) @(posedge clk); + `WRITE_VERBOSE("calling tb_c_wait..."); + tb_c_wait(); + `WRITE_VERBOSE("tb_c_wait finish"); + repeat(10) @(posedge clk); + $write("*-* All Finished *-*\n"); + $finish; + end + + initial #(cycle*30) $stop; // timeout +endmodule From e15f5266a38e90b33bd48e5feffe6d2f8508b2ac Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 29 Apr 2023 22:16:53 -0400 Subject: [PATCH 153/155] Commentary: Changes update --- Changes | 31 ++++++++++++++++++++++++++++--- docs/spelling.txt | 6 ++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/Changes b/Changes index 360662687..cfa90a663 100644 --- a/Changes +++ b/Changes @@ -17,13 +17,18 @@ Verilator 5.009 devel * Add --public-params flag (#3990). [Andrew Nolte] * Add CONSTRAINTIGN warning when constraint ignored. * Add STATICVAR warning and convert to automatic (#4018) (#4027) (#4030). [Ryszard Rozak, Antmicro Ltd] +* Add error if class types don't match (#4064). [Ryszard Rozak, Antmicro Ltd] * Support class extends of package::class. * Support class srandom and class random stability. +* Support class method calls without parenthesis (#3902) (#4082). [Srinivasan Venkataramanan] * Support method calls without parenthesis (#4034). [Ryszard Rozak, Antmicro Ltd] +* Support parameterized return types of methods (#4122). [Ryszard Rozak, Antmicro Ltd] +* Support parameterized class references in extends statement (#4146). [Ryszard Rozak, Antmicro Ltd] * Support complicated IEEE 'for' assignments. * Support $fopen as an expression. * Support ++/-- on dotted member variables. * Optimize static trigger evaluation (#4142). [Geza Lore, X-EPIC] +* Optimize more xor trees (#4071). [Yutetsu TAKATSUKASA] * Change range order warning from LITENDIAN to ASCRANGE (#4010). [Iztok Jeras] * Change ZERODLY to a warning. * Fix random internal crashes (#666). [Dag Lem] @@ -38,15 +43,35 @@ Verilator 5.009 devel * Fix large return blocks with --comp-limit-blocks (#4028). [tenghtt] * Fix clocking block scope internal error (#4032). [Srinivasan Venkataramanan] * Fix false LATCH warning on --assert 'unique else if' (#4033) ($4054). [Jesse Taube] -* Fix characters from DEFENV literals for conda (#4035) (#4044). [Tim Snyder] +* Fix characters from DEFENV literals for Conda (#4035) (#4044). [Tim Snyder] +* Fix info message prints under --assert (#4036) (#4053). [Srinivasan Venkataramanan] +* Fix C++ compile errors when passing class refs as task argument (#4063). [Krzysztof Bieganski, Antmicro Ltd] +* Fix NBAs inside fork-joins (#4050). [Aleksander Kiryk, Antmicro Ltd] +* Fix task calls as fork statements (#4055). [Krzysztof Bieganski, Antmicro Ltd] +* Fix _Vilp used before declaration (#4057) (#4062). [Josep Sans] +* Fix incorrect optimization of bit op tree (#4059) (#4070). [Yutetsu TAKATSUKASA] +* Fix parameters in a class body to be localparam (#4061). [Ryszard Rozak, Antmicro Ltd] * Fix interface generate begin (#4065). [Srinivasan Venkataramanan] +* Fix tracing with awaits at end of block (#4075) (#4076). [Krzysztof Bieganski, Antmicro Ltd] +* Fix sense expression variable naming (#4081). [Kamil Rakoczy] +* Fix importing symbols from base class (#4084). [Ryszard Rozak, Antmicro Ltd] * Fix false error on new const assignment (#4098). [Tudor Timi] * Fix unpacked structs under classes (#4102). [Tudor Timi] -* Fix DFG error on $countbits (#4101). [Paul Donahue] +* Fix variables in class methods to be automatic (#4111) (#4137). [Peter Monsson] +* Fix to use parallel build for projects with a lot of files (#4116). [Krzysztof Boroński] +* Fix including __Syms header in generated C++ files (#4123). [Krzysztof Boroński] +* Fix systemc namespace issues (#4126) (#4127). [Eyck Jentzsch] +* Fix class param extends A=B (#4128). [Ryszard Rozak, Antmicro Ltd] +* Fix missing begin block hierarchy in --xml-only cells section (#4129) (#4133). [Risto Pejašinović] +* Fix resolution of class lvalues after parameterization (#4131). [Krzysztof Boroński] +* Fix DFG error on $countbits (#4101) (#4143). [Paul Donahue] +* Fix duplicating parameter class types (#4115). [Ryszard Rozak, Antmicro Ltd] +* Fix class extend param references (#4136). [Ryszard Rozak, Antmicro Ltd] * Fix -CFLAGS to allow overriding optimization levels (#4140). [Peter Monsson] +* Fix DPI function type alias (#4148) (#4149). [Toru Niina] +* Fix deleting unused parameterized classes (#4150). [Ryszard Rozak, Antmicro Ltd] * Fix false ENUMVALUE on expressions and arrays. * Fix unnecessary verilated_std.sv waivers in --waiver-output. -* Fix missing begin block hierarchy in --xml-only cells section (#4129). [Risto Pejašinović] Verilator 5.008 2023-03-04 diff --git a/docs/spelling.txt b/docs/spelling.txt index 4f73b0a0e..f4660bed4 100644 --- a/docs/spelling.txt +++ b/docs/spelling.txt @@ -43,6 +43,7 @@ Chandan Chitlesh Christophe Cochrane +Conda Corteggiani Cuan Cygwin @@ -327,6 +328,7 @@ Thiede Thierry Thyer Tichelaar +Timi Tomov Tood Topa @@ -362,6 +364,7 @@ Verilator Verilog Vighnesh Viktor +Vilp Vm Vukobratovic Wai @@ -670,6 +673,7 @@ lossy lsb lubc lvalue +lvalues lxt macromodule makefile @@ -733,6 +737,7 @@ ortegon oversubscription parallelized param +parameterization parameterized params parens @@ -827,6 +832,7 @@ specparam splitme spp sqrt +srandom src srcdir srcfile From 3d21a79148d518b5261e6dab3c985e63fc086269 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 29 Apr 2023 22:22:38 -0400 Subject: [PATCH 154/155] Fix pylint warning --- nodist/clang_check_attributes | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nodist/clang_check_attributes b/nodist/clang_check_attributes index 0cea38289..36c5be05f 100755 --- a/nodist/clang_check_attributes +++ b/nodist/clang_check_attributes @@ -49,7 +49,7 @@ class VlAnnotations: release: bool = False def is_mt_safe_context(self): - return (not (self.mt_unsafe or self.mt_unsafe_one) and self.mt_safe) + return self.mt_safe and not (self.mt_unsafe or self.mt_unsafe_one) def is_pure_context(self): return self.pure From 5d3a9eec7f4cd757f1928cb483d7a08cba509ada Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 30 Apr 2023 07:08:27 -0400 Subject: [PATCH 155/155] Version bump --- CMakeLists.txt | 2 +- Changes | 2 +- configure.ac | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c6da1a1a8..2f323c05f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ cmake_minimum_required(VERSION 3.15) cmake_policy(SET CMP0091 NEW) # Use MSVC_RUNTIME_LIBRARY to select the runtime project(Verilator - VERSION 5.009 + VERSION 5.010 HOMEPAGE_URL https://verilator.org LANGUAGES CXX ) diff --git a/Changes b/Changes index cfa90a663..637d4196d 100644 --- a/Changes +++ b/Changes @@ -8,7 +8,7 @@ The changes in each Verilator version are described below. The contributors that suggested a given feature are shown in []. Thanks! -Verilator 5.009 devel +Verilator 5.010 2023-04-30 ========================== **Minor:** diff --git a/configure.ac b/configure.ac index ebcd6d579..3e45cc298 100644 --- a/configure.ac +++ b/configure.ac @@ -10,7 +10,7 @@ # Then 'make maintainer-dist' #AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### devel]) -AC_INIT([Verilator],[5.009 devel], +AC_INIT([Verilator],[5.010 2023-04-30], [https://verilator.org], [verilator],[https://verilator.org])