Report error on function call output tied to constant.
Fix internal error on functions called as SV tasks.
This commit is contained in:
parent
e26a75c59d
commit
e5de759236
4
Changes
4
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]
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
Loading…
Reference in New Issue