diff --git a/src/V3Ast.h b/src/V3Ast.h index 19103e471..ff783b806 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -2731,6 +2731,7 @@ private: string m_dotted; // Dotted part of scope the name()ed task/func is under or "" string m_inlinedDots; // Dotted hierarchy flattened out AstNodeModule* m_packagep; // Package hierarchy + bool m_pli; // Pli system call ($name) public: AstNodeFTaskRef(AstType t, FileLine* fl, bool statement, AstNode* namep, AstNode* pinsp) : AstNodeStmt(t, fl, statement) @@ -2767,6 +2768,8 @@ public: void dotted(const string& name) { m_dotted = name; } AstNodeModule* packagep() const { return m_packagep; } void packagep(AstNodeModule* nodep) { m_packagep = nodep; } + bool pli() const { return m_pli; } + void pli(bool flag) { m_pli = flag; } // op1 = namep AstNode* namep() const { return op1p(); } // op2 = reserved for AstMethodCall diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index e86386ee1..0886a7f80 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2491,11 +2491,39 @@ private: } else if (VN_IS(nodep, New) && m_statep->forPrearray()) { // Resolved in V3Width } else if (nodep->dotted() == "") { - string suggest = m_statep->suggestSymFallback(dotSymp, nodep->name(), - LinkNodeMatcherFTask()); - nodep->v3error("Can't find definition of task/function: " - << nodep->prettyNameQ() << endl - << (suggest.empty() ? "" : nodep->warnMore() + suggest)); + if (nodep->pli()) { + if (v3Global.opt.bboxSys()) { + AstNode* newp; + if (VN_IS(nodep, FuncRef)) { + newp = new AstConst(nodep->fileline(), AstConst::StringToParse(), + "'0"); + } else { + AstNode* outp = NULL; + while (nodep->pinsp()) { + AstNode* pinp = nodep->pinsp()->unlinkFrBack(); + AstNode* addp = pinp; + if (AstArg* argp = VN_CAST(pinp, Arg)) { + addp = argp->exprp()->unlinkFrBack(); + VL_DO_DANGLING(pinp->deleteTree(), pinp); + } + outp = AstNode::addNext(outp, addp); + } + newp = new AstSysIgnore(nodep->fileline(), outp); + } + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + return; + } else { + nodep->v3error("Unsupported or unknown PLI call: " + << nodep->prettyNameQ() << endl); + } + } else { + string suggest = m_statep->suggestSymFallback(dotSymp, nodep->name(), + LinkNodeMatcherFTask()); + nodep->v3error("Can't find definition of task/function: " + << nodep->prettyNameQ() << endl + << (suggest.empty() ? "" : nodep->warnMore() + suggest)); + } } else { string suggest = m_statep->suggestSymFallback(dotSymp, nodep->name(), LinkNodeMatcherFTask()); diff --git a/src/V3ParseGrammar.cpp b/src/V3ParseGrammar.cpp index 9385ef4b1..bfe861e5a 100644 --- a/src/V3ParseGrammar.cpp +++ b/src/V3ParseGrammar.cpp @@ -65,15 +65,20 @@ void V3ParseImp::parserClear() { //====================================================================== // V3ParseGrammar functions requiring bison state -void V3ParseGrammar::argWrapList(AstNodeFTaskRef* nodep) { +AstNode* V3ParseGrammar::argWrapList(AstNode* nodep) { // Convert list of expressions to list of arguments + if (!nodep) return NULL; AstNode* outp = NULL; - while (nodep->pinsp()) { - AstNode* exprp = nodep->pinsp()->unlinkFrBack(); + AstBegin* tempp = new AstBegin(nodep->fileline(), "[EditWrapper]", nodep); + while (nodep) { + AstNode* nextp = nodep->nextp(); + AstNode* exprp = nodep->unlinkFrBack(); + nodep = nextp; // addNext can handle nulls: outp = AstNode::addNext(outp, new AstArg(exprp->fileline(), "", exprp)); } - if (outp) nodep->addPinsp(outp); + VL_DO_DANGLING(tempp->deleteTree(), tempp); + return outp; } AstNode* V3ParseGrammar::createSupplyExpr(FileLine* fileline, const string& name, int value) { diff --git a/src/verilog.l b/src/verilog.l index a4b83e250..c60c3a2d1 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -44,10 +44,6 @@ extern void yyerrorf(const char* format, ...); #define FL { FL_FWD; yylval.fl = CRELINE(); } -#define RETURN_BBOX_SYS_OR_MSG(msg,yytext) { \ - if (!v3Global.opt.bboxSys()) { yyerrorf(msg, yytext); FL_BRK; } \ - return yaD_IGNORE; } - #define ERROR_RSVD_WORD(language) \ do { FL_FWD; \ yyerrorf("Unsupported: " language " reserved word not implemented: '%s'", yytext); \ @@ -601,10 +597,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} { "$"[a-zA-Z_$][a-zA-Z0-9_$]* { string str (yytext, yyleng); yylval.strp = PARSEP->newString(AstNode::encodeName(str)); - // Lookup unencoded name including the $, to avoid hitting normal signals - if (SYMP->symCurrentp()->findIdFallback(str)) { - FL; return yaD_DPI; - } else { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported or unknown PLI call: %s", yytext); } + FL; return yaD_PLI; } } diff --git a/src/verilog.y b/src/verilog.y index e80712572..4181876ac 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -91,7 +91,7 @@ public: } // METHODS - void argWrapList(AstNodeFTaskRef* nodep); + AstNode* argWrapList(AstNode* nodep); bool allTracingOn(FileLine* fl) { return v3Global.opt.trace() && m_tracingParse && fl->tracingOn(); } @@ -311,8 +311,7 @@ class AstSenTree; %token yVLT_D_TASK "--task" %token yVLT_D_VAR "--var" -%token yaD_IGNORE "${ignored-bbox-sys}" -%token yaD_DPI "${dpi-sys}" +%token yaD_PLI "${pli-system}" %token yaT_RESETALL "`resetall" @@ -3264,12 +3263,7 @@ function_subroutine_callNoMethod: // IEEE: function_subroutine_call (as f system_t_call: // IEEE: system_tf_call (as task) // - yaD_IGNORE parenE { $$ = new AstSysIgnore($1,NULL); } - | yaD_IGNORE '(' exprList ')' { $$ = new AstSysIgnore($1,$3); } - // - | yaD_DPI parenE { $$ = new AstTaskRef($1,*$1,NULL); } - | yaD_DPI '(' exprList ')' { $$ = new AstTaskRef($1, *$1, $3); - GRAMMARP->argWrapList(VN_CAST($$, TaskRef)); } + yaD_PLI systemDpiArgsE { $$ = new AstTaskRef($1, *$1, $2); VN_CAST($$, TaskRef)->pli(true); } // | yD_DUMPPORTS '(' idDotted ',' expr ')' { $$ = new AstDumpCtl($1, VDumpCtlType::FILE, $5); DEL($3); $$->addNext(new AstDumpCtl($1, VDumpCtlType::VARS, @@ -3369,11 +3363,7 @@ system_t_call: // IEEE: system_tf_call (as task) ; system_f_call: // IEEE: system_tf_call (as func) - yaD_IGNORE parenE { $$ = new AstConst($1, AstConst::StringToParse(), "'b0"); } // Unsized 0 - | yaD_IGNORE '(' exprList ')' { $$ = new AstConst($1, AstConst::StringToParse(), "'b0"); } // Unsized 0 - // - | yaD_DPI parenE { $$ = new AstFuncRef($1,*$1,NULL); } - | yaD_DPI '(' exprList ')' { $$ = new AstFuncRef($1,*$1,$3); GRAMMARP->argWrapList(VN_CAST($$, FuncRef)); } + yaD_PLI systemDpiArgsE { $$ = new AstFuncRef($1, *$1, $2); VN_CAST($$, FuncRef)->pli(true); } // | yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? NULL : new AstUCFunc($1,$3)); } | yD_SYSTEM '(' expr ')' { $$ = new AstSystemF($1,$3); } @@ -3381,6 +3371,11 @@ system_f_call: // IEEE: system_tf_call (as func) | system_f_call_or_t { $$ = $1; } ; +systemDpiArgsE: // IEEE: part of system_if_call for aruments of $dpi call + parenE { $$ = NULL; } + | '(' exprList ')' { $$ = GRAMMARP->argWrapList($2); } + ; + system_f_call_or_t: // IEEE: part of system_tf_call (can be task or func) yD_ACOS '(' expr ')' { $$ = new AstAcosD($1,$3); } | yD_ACOSH '(' expr ')' { $$ = new AstAcoshD($1,$3); } diff --git a/test_regress/t/t_pli_bad.out b/test_regress/t/t_pli_bad.out new file mode 100644 index 000000000..b1f752c4f --- /dev/null +++ b/test_regress/t/t_pli_bad.out @@ -0,0 +1,13 @@ +%Error: t/t_pli_bad.v:10:7: Unsupported or unknown PLI call: '$unknown_pli_task' + 10 | $unknown_pli_task; + | ^~~~~~~~~~~~~~~~~ +%Error: t/t_pli_bad.v:11:7: Unsupported or unknown PLI call: '$unknown_pli_task' + 11 | $unknown_pli_task("arg", i); + | ^~~~~~~~~~~~~~~~~ +%Error: t/t_pli_bad.v:12:11: Unsupported or unknown PLI call: '$unknown_pli_function' + 12 | i = $unknown_pli_function; + | ^~~~~~~~~~~~~~~~~~~~~ +%Error: t/t_pli_bad.v:13:11: Unsupported or unknown PLI call: '$unknown_pli_function' + 13 | i = $unknown_pli_function("arg", i); + | ^~~~~~~~~~~~~~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_pli_bad.pl b/test_regress/t/t_pli_bad.pl new file mode 100755 index 000000000..828e0df38 --- /dev/null +++ b/test_regress/t/t_pli_bad.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 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 => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_pli_bad.v b/test_regress/t/t_pli_bad.v new file mode 100644 index 000000000..5ae542377 --- /dev/null +++ b/test_regress/t/t_pli_bad.v @@ -0,0 +1,16 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2019 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; + integer i; + initial begin + $unknown_pli_task; + $unknown_pli_task("arg", i); + i = $unknown_pli_function; + i = $unknown_pli_function("arg", i); + $stop; + end +endmodule diff --git a/test_regress/t/t_pli_bbox.pl b/test_regress/t/t_pli_bbox.pl new file mode 100755 index 000000000..b30ede91e --- /dev/null +++ b/test_regress/t/t_pli_bbox.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(vlt => 1); + +top_filename("t/t_pli_bad.v"); + +lint( + verilator_flags2 => ["--bbox-sys"], + ); + +ok(1); + +1;