Report error on function call output tied to constant.

Fix internal error on functions called as SV tasks.
This commit is contained in:
Wilson Snyder 2011-02-14 19:25:30 -05:00
parent e26a75c59d
commit e5de759236
8 changed files with 129 additions and 45 deletions

View File

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

View File

@ -500,6 +500,7 @@ private:
if (!taskp) { nodep->v3error("Can't find definition of task/function: "<<nodep->prettyName()); }
nodep->taskp(taskp);
nodep->packagep(packageFor(taskp));
if (taskp->castTask() && nodep->castFuncRef()) nodep->v3error("Illegal call of a task as a function: "<<nodep->prettyName());
}
}
nodep->iterateChildren(*this);

View File

@ -380,7 +380,10 @@ private:
UINFO(9, " pin "<<pinp<<endl);
pinp->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 "<<portp<<endl);
UINFO(9, " pin "<<pinp<<endl);
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 (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 "<<nodep<<endl);
if (debug()>=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 "<<nodep<<endl);
if (debug()>=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 "<<nodep<<endl);
if (debug()>=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 "<<nodep<<endl);

View File

@ -47,6 +47,14 @@ module t;
nil();
if (n !== 10) $stop;
// Functions called as tasks
rglobal = 32'h4;
if (inc_and_return(32'h2) != 32'h6) $stop;
if (rglobal !== 32'h6) $stop;
rglobal = 32'h6;
inc_and_return(32'h3);
if (rglobal !== 32'h9) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
@ -133,4 +141,10 @@ module t;
toint = fa + 32'h1;
endfunction
function [31:0] inc_and_return;
input [31:0] inc;
rglobal = rglobal + inc;
return rglobal;
endfunction
endmodule

View File

@ -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_task_bad.v:\d+: Illegal call of a task as a function: task_as_func
%Error: Exiting due to.*},
);
ok(1);
1;

View File

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

View File

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

View File

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