diff --git a/Changes b/Changes index a129fd136..659bca130 100644 --- a/Changes +++ b/Changes @@ -6,6 +6,8 @@ The contributors that suggested a given feature are shown in []. Thanks! *** Support trig functions ($sin() etc), bug1281. [Patrick Stewart] +*** Support calling system functions as tasks, bug1285. [Joel Holdsworth] + **** Fix GCC 8.0 issues, bug1273. **** Fix pullup/pulldowns on bit selects, bug1274. [Rob Stoddard] diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index be0745701..684bcf783 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -2594,6 +2594,26 @@ public: void lhsp(AstNode* nodep) { setOp3p(nodep); } }; +class AstSysFuncAsTask : public AstNodeStmt { + // Call what is normally a system function (with a return) in a non-return context + // Parents: stmtlist + // Children: a system function +public: + AstSysFuncAsTask(FileLine* fileline, AstNode* exprsp) + : AstNodeStmt (fileline) { addNOp1p(exprsp); } + ASTNODE_NODE_FUNCS(SysFuncAsTask) + virtual string verilogKwd() const { return ""; } + virtual bool isGateOptimizable() const { return true; } + virtual bool isPredictOptimizable() const { return true; } + virtual bool isPure() const { return true; } + virtual bool isOutputter() const { return false; } + virtual int instrCount() const { return 0; } + virtual V3Hash sameHash() const { return V3Hash(); } + virtual bool same(const AstNode* samep) const { return true; } + AstNode* lhsp() const { return op1p(); } // op1 = Expressions to eval + void lhsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to eval +}; + class AstSysIgnore : public AstNodeStmt { // Parents: stmtlist // Children: varrefs or exprs diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 8590eeb81..4e2214edd 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -374,6 +374,11 @@ public: puts(")); }\n"); } } + virtual void visit(AstSysFuncAsTask* nodep) { + if (!nodep->lhsp()->isWide()) puts("(void)"); + nodep->lhsp()->iterateAndNext(*this); + if (!nodep->lhsp()->isWide()) puts(";"); + } virtual void visit(AstSystemT* nodep) { puts("(void)VL_SYSTEM_I"); emitIQW(nodep->lhsp()); diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index 11f4e4650..117eac41d 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -278,6 +278,10 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { if (nodep->msbp()) { putbs(","); nodep->msbp()->iterateAndNext(*this); } puts(");\n"); } + virtual void visit(AstSysFuncAsTask* nodep) { + nodep->lhsp()->iterateAndNext(*this); + puts(";\n"); + } virtual void visit(AstSysIgnore* nodep) { putfs(nodep,nodep->verilogKwd()); putbs(" ("); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 0dd48eaa6..f98eef88a 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -2188,6 +2188,10 @@ private: nodep->dtypeSetSigned32(); // Spec says integer return } } + virtual void visit(AstSysFuncAsTask* nodep) { + assertAtStatement(nodep); + userIterateAndNext(nodep->lhsp(), WidthVP(SELF,BOTH).p()); + } virtual void visit(AstSystemT* nodep) { assertAtStatement(nodep); userIterateAndNext(nodep->lhsp(), WidthVP(SELF,BOTH).p()); diff --git a/src/verilog.y b/src/verilog.y index a45928dca..140ba1502 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -2663,6 +2663,8 @@ system_t_call: // IEEE: system_tf_call (as task) | yaD_DPI '(' exprList ')' { $$ = new AstTaskRef($2,*$1,$3); GRAMMARP->argWrapList($$->castTaskRef()); } // | yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? NULL : new AstUCStmt($1,$3)); } + | yD_SYSTEM '(' expr ')' { $$ = new AstSystemT($1,$3); } + // | yD_FCLOSE '(' idClassSel ')' { $$ = new AstFClose($1, $3); } | yD_FFLUSH parenE { $1->v3error("Unsupported: $fflush of all handles does not map to C++."); } | yD_FFLUSH '(' expr ')' { $$ = new AstFFlush($1, $3); } @@ -2673,7 +2675,6 @@ system_t_call: // IEEE: system_tf_call (as task) // | yD_SFORMAT '(' expr ',' str commaEListE ')' { $$ = new AstSFormat($1,$3,*$5,$6); } | yD_SWRITE '(' expr ',' str commaEListE ')' { $$ = new AstSFormat($1,$3,*$5,$6); } - | yD_SYSTEM '(' expr ')' { $$ = new AstSystemT($1,$3); } // | yD_DISPLAY parenE { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY,NULL,NULL); } | yD_DISPLAY '(' exprList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY,NULL,$3); } @@ -2698,6 +2699,9 @@ system_t_call: // IEEE: system_tf_call (as task) | yD_READMEMH '(' expr ',' idClassSel ')' { $$ = new AstReadMem($1,true, $3,$5,NULL,NULL); } | yD_READMEMH '(' expr ',' idClassSel ',' expr ')' { $$ = new AstReadMem($1,true, $3,$5,$7,NULL); } | yD_READMEMH '(' expr ',' idClassSel ',' expr ',' expr ')' { $$ = new AstReadMem($1,true, $3,$5,$7,$9); } + // + // Any system function as a task + | system_f_call_or_t { $$ = new AstSysFuncAsTask($1, $1); } ; system_f_call: // IEEE: system_tf_call (as func) @@ -2707,7 +2711,14 @@ system_f_call: // IEEE: system_tf_call (as func) | yaD_DPI parenE { $$ = new AstFuncRef($1,*$1,NULL); } | yaD_DPI '(' exprList ')' { $$ = new AstFuncRef($2,*$1,$3); GRAMMARP->argWrapList($$->castFuncRef()); } // - | yD_ACOS '(' expr ')' { $$ = new AstAcosD($1,$3); } + | yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? NULL : new AstUCFunc($1,$3)); } + | yD_SYSTEM '(' expr ')' { $$ = new AstSystemF($1,$3); } + // + | system_f_call_or_t { $$ = $1; } + ; + +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); } | yD_ASIN '(' expr ')' { $$ = new AstAsinD($1,$3); } | yD_ASINH '(' expr ')' { $$ = new AstAsinhD($1,$3); } @@ -2717,7 +2728,6 @@ system_f_call: // IEEE: system_tf_call (as func) | yD_BITS '(' exprOrDataType ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_BITS,$3); } | yD_BITS '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_BITS,$3,$5); } | yD_BITSTOREAL '(' expr ')' { $$ = new AstBitsToRealD($1,$3); } - | yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? NULL : new AstUCFunc($1,$3)); } | yD_CEIL '(' expr ')' { $$ = new AstCeilD($1,$3); } | yD_CLOG2 '(' expr ')' { $$ = new AstCLog2($1,$3); } | yD_COS '(' expr ')' { $$ = new AstCosD($1,$3); } @@ -2762,7 +2772,6 @@ system_f_call: // IEEE: system_tf_call (as func) | yD_SQRT '(' expr ')' { $$ = new AstSqrtD($1,$3); } | yD_SSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstSScanF($1,*$5,$3,$6); } | yD_STIME parenE { $$ = new AstSel($1,new AstTime($1),0,32); } - | yD_SYSTEM '(' expr ')' { $$ = new AstSystemF($1,$3); } | yD_TAN '(' expr ')' { $$ = new AstTanD($1,$3); } | yD_TANH '(' expr ')' { $$ = new AstTanhD($1,$3); } | yD_TESTPLUSARGS '(' str ')' { $$ = new AstTestPlusArgs($1,*$3); } diff --git a/test_regress/t/t_sys_plusargs.v b/test_regress/t/t_sys_plusargs.v index f0956f3fb..8de3437ae 100644 --- a/test_regress/t/t_sys_plusargs.v +++ b/test_regress/t/t_sys_plusargs.v @@ -45,6 +45,11 @@ module t; $display("str='%s'",sv_str); if (sv_str != "T=1234") $stop; + sv_str = "none"; + $value$plusargs("IN%s", sv_str); + $display("str='%s'",sv_str); + if (sv_str != "T=1234") $stop; + p_in = "IN%s"; `ifdef VERILATOR p_in = $c(p_in); // Prevent constant propagation