From e5de75923676bf5e41c4eace8a5c99d14fb597f4 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 14 Feb 2011 19:25:30 -0500 Subject: [PATCH] Report error on function call output tied to constant. Fix internal error on functions called as SV tasks. --- Changes | 4 ++ src/V3Link.cpp | 1 + src/V3Task.cpp | 82 ++++++++++++++----------------- test_regress/t/t_func.v | 14 ++++++ test_regress/t/t_func_task_bad.pl | 19 +++++++ test_regress/t/t_func_task_bad.v | 16 ++++++ test_regress/t/t_func_tie_bad.pl | 19 +++++++ test_regress/t/t_func_tie_bad.v | 19 +++++++ 8 files changed, 129 insertions(+), 45 deletions(-) create mode 100755 test_regress/t/t_func_task_bad.pl create mode 100644 test_regress/t/t_func_task_bad.v create mode 100755 test_regress/t/t_func_tie_bad.pl create mode 100644 test_regress/t/t_func_tie_bad.v diff --git a/Changes b/Changes index 8f7e18198..bf3541f35 100644 --- a/Changes +++ b/Changes @@ -7,8 +7,12 @@ indicates the contributor was also the author of the fix; Thanks! **** Report errors on duplicated or empty pins, bug321. [Christian Leber] +**** Report error on function call output tied to constant. [Bernard Deadman] + **** Throw UNUSED/UNDRIVEN only once per net in a parametrized module. +**** Fix internal error on functions called as SV tasks. [Bernard Deadman] + **** Fix internal error on non-inlined inout pins. [Jeff Winston] **** Fix false BLKSEQ on non-unrolled for loop indexes. [Jeff Winston] diff --git a/src/V3Link.cpp b/src/V3Link.cpp index 12c336c7a..bc028aa83 100644 --- a/src/V3Link.cpp +++ b/src/V3Link.cpp @@ -500,6 +500,7 @@ private: if (!taskp) { nodep->v3error("Can't find definition of task/function: "<prettyName()); } nodep->taskp(taskp); nodep->packagep(packageFor(taskp)); + if (taskp->castTask() && nodep->castFuncRef()) nodep->v3error("Illegal call of a task as a function: "<prettyName()); } } nodep->iterateChildren(*this); diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 3eaa5876d..7e4ae71d0 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -380,7 +380,10 @@ private: UINFO(9, " pin "<unlinkFrBack(); // Relinked to assignment below // - if (portp->isInout()) { + if ((portp->isInout()||portp->isOutput()) && pinp->castConst()) { + pinp->v3error("Function/task output connected to constant instead of variable: "+portp->prettyName()); + } + else if (portp->isInout()) { if (AstVarRef* varrefp = pinp->castVarRef()) { // Connect to this exact variable AstVarScope* localVscp = varrefp->varScopep(); if (!localVscp) varrefp->v3fatalSrc("Null var scope"); @@ -390,9 +393,6 @@ private: pinp->v3warn(E_TASKNSVAR,"Unsupported: Function/task input argument is not simple variable"); } } - else if (portp->isOutput() && outvscp) { - refp->v3error("Outputs not allowed in function declarations"); - } else if (portp->isOutput()) { // Make output variables // Correct lvalue; we didn't know when we linked @@ -456,7 +456,7 @@ private: tempp->stmtsp()->unlinkFrBackWithNext(); tempp->deleteTree(); tempp=NULL; } // - if (debug()>=9) { beginp->dumpTree(cout,"-iotask: "); } + if (debug()>=9) { beginp->dumpTreeAndNext(cout,"-iotask: "); } return beginp; } @@ -481,7 +481,10 @@ private: } else { UINFO(9, " Port "<isInout()) { + if ((portp->isInout()||portp->isOutput()) && pinp->castConst()) { + pinp->v3error("Function/task output connected to constant instead of variable: "+portp->prettyName()); + } + else if (portp->isInout()) { if (pinp->castVarRef()) { // Connect to this exact variable } else { @@ -536,7 +539,7 @@ private: ccallp->addArgsp(new AstVarRef(refp->fileline(), outvscp, true)); } - if (debug()>=9) { beginp->dumpTree(cout,"-nitask: "); } + if (debug()>=9) { beginp->dumpTreeAndNext(cout,"-nitask: "); } return beginp; } @@ -1011,40 +1014,22 @@ private: nodep->iterateChildren(*this); m_scopep = NULL; } - virtual void visit(AstTaskRef* nodep, AstNUser*) { - iterateIntoFTask(nodep->taskp()); // First, do hierarchical funcs - UINFO(4," Task REF "<=9) { nodep->dumpTree(cout,"-inltask:"); } - // Create cloned statements - string namePrefix = "__Vtask_"+nodep->taskp()->shortName()+"__"+cvtToStr(m_modNCalls++); - AstNode* beginp; - if (m_statep->ftaskNoInline(nodep->taskp())) { - beginp = createNonInlinedFTask(nodep, namePrefix, NULL); - } else { - beginp = createInlinedFTask(nodep, namePrefix, NULL); - } - // Replace the ref - nodep->replaceWith(beginp); - nodep->deleteTree(); nodep=NULL; - } - virtual void visit(AstFuncRef* nodep, AstNUser*) { - UINFO(4," Func REF "<=9) { nodep->dumpTree(cout,"-preref:"); } - // First, do hierarchical funcs - AstNodeFTask* funcp = nodep->taskp(); - if (!funcp) nodep->v3fatalSrc("unlinked"); - if (!funcp->isFunction()) nodep->v3fatalSrc("func reference to non-function"); - if (!m_scopep) nodep->v3fatalSrc("func ref not under scope"); - // Inline func refs in the function - iterateIntoFTask(funcp); - // Create output variable - string namePrefix = "__Vfunc_"+nodep->taskp()->shortName()+"__"+cvtToStr(m_modNCalls++); - AstVarScope* outvscp = createVarScope (funcp->fvarp()->castVar(), - namePrefix+"__Vfuncout"); - // Create cloned statements - if (debug()>=9) { nodep->taskp()->dumpTree(cout,"-oldfunc:"); } + virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) { if (!nodep->taskp()) nodep->v3fatalSrc("Unlinked?"); - + iterateIntoFTask(nodep->taskp()); // First, do hierarchical funcs + UINFO(4," FTask REF "<=9) { nodep->dumpTree(cout,"-inlfunc:"); } + if (!m_scopep) nodep->v3fatalSrc("func ref not under scope"); + string namePrefix = ((nodep->castFuncRef()?"__Vfunc_":"__Vtask_") + +nodep->taskp()->shortName()+"__"+cvtToStr(m_modNCalls++)); + // Create output variable + AstVarScope* outvscp = NULL; + if (nodep->taskp()->isFunction()) { + // Not that it's a FUNCREF, but that we're calling a function (perhaps as a task) + outvscp = createVarScope (nodep->taskp()->fvarp()->castVar(), + namePrefix+"__Vfuncout"); + } + // Create cloned statements AstNode* beginp; if (m_statep->ftaskNoInline(nodep->taskp())) { // This may share VarScope's with a public task, if any. Yuk. @@ -1053,13 +1038,20 @@ private: beginp = createInlinedFTask(nodep, namePrefix, outvscp); } // Replace the ref - AstVarRef* outrefp = new AstVarRef (nodep->fileline(), outvscp, false); - nodep->replaceWith(outrefp); - // Insert new statements - insertBeforeStmt(nodep, beginp); + if (nodep->castFuncRef()) { + if (!nodep->taskp()->isFunction()) nodep->v3fatalSrc("func reference to non-function"); + AstVarRef* outrefp = new AstVarRef (nodep->fileline(), outvscp, false); + nodep->replaceWith(outrefp); + // Insert new statements + insertBeforeStmt(nodep, beginp); + } else { + // outvscp maybe non-NULL if calling a function in a taskref, + // but if so we want to simply ignore the function result + nodep->replaceWith(beginp); + } // Cleanup nodep->deleteTree(); nodep=NULL; - UINFO(4," Func REF Done.\n"); + UINFO(4," FTask REF Done.\n"); } virtual void visit(AstNodeFTask* nodep, AstNUser*) { UINFO(4," Inline "< ["--lint-only"], + fails=>1, + expect=> +q{%Error: t/t_func_task_bad.v:\d+: Illegal call of a task as a function: task_as_func +%Error: Exiting due to.*}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_func_task_bad.v b/test_regress/t/t_func_task_bad.v new file mode 100644 index 000000000..c1623fd41 --- /dev/null +++ b/test_regress/t/t_func_task_bad.v @@ -0,0 +1,16 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2011 by Wilson Snyder. + +module t (/*AUTOARG*/); + + initial begin + if (task_as_func(1'b0)) $stop; + end + + task task_as_func; + input ign; + endtask + +endmodule diff --git a/test_regress/t/t_func_tie_bad.pl b/test_regress/t/t_func_tie_bad.pl new file mode 100755 index 000000000..23ee4055b --- /dev/null +++ b/test_regress/t/t_func_tie_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2011 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. + +compile ( + v_flags2 => ["--lint-only"], + fails=>1, + expect=> +q{%Error: t/t_func_tie_bad.v:\d+: Function/task output connected to constant instead of variable: b +%Error: Exiting due to.*}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_func_tie_bad.v b/test_regress/t/t_func_tie_bad.v new file mode 100644 index 000000000..8ca74c2a6 --- /dev/null +++ b/test_regress/t/t_func_tie_bad.v @@ -0,0 +1,19 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2011 by Wilson Snyder. + +module t (/*AUTOARG*/); + + initial begin + func(0, 1'b1); + end + + function automatic int func + ( + input int a, + output bit b ); + return 0; + endfunction + +endmodule