Add lint check for bad delay locations.
This commit is contained in:
parent
ee1b20e1cd
commit
ca77a93214
|
|
@ -102,7 +102,7 @@ private:
|
||||||
bool m_doShort; // Remove expressions that short circuit
|
bool m_doShort; // Remove expressions that short circuit
|
||||||
bool m_doV; // Verilog, not C++ conversion
|
bool m_doV; // Verilog, not C++ conversion
|
||||||
bool m_doGenerate; // Postpone width checking inside generate
|
bool m_doGenerate; // Postpone width checking inside generate
|
||||||
bool m_hasJumpGo; // JumpGo under this while
|
bool m_hasJumpDelay; // JumpGo or Delay under this while
|
||||||
AstNodeModule* m_modp; // Current module
|
AstNodeModule* m_modp; // Current module
|
||||||
AstArraySel* m_selp; // Current select
|
AstArraySel* m_selp; // Current select
|
||||||
AstNode* m_scopep; // Current scope
|
AstNode* m_scopep; // Current scope
|
||||||
|
|
@ -2114,11 +2114,11 @@ private:
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
}
|
}
|
||||||
virtual void visit(AstWhile* nodep) VL_OVERRIDE {
|
virtual void visit(AstWhile* nodep) VL_OVERRIDE {
|
||||||
bool oldHasJumpGo = m_hasJumpGo;
|
bool oldHasJumpDelay = m_hasJumpDelay;
|
||||||
m_hasJumpGo = false;
|
m_hasJumpDelay = false;
|
||||||
{ iterateChildren(nodep); }
|
{ iterateChildren(nodep); }
|
||||||
bool thisWhileHasJumpGo = m_hasJumpGo;
|
bool thisWhileHasJumpDelay = m_hasJumpDelay;
|
||||||
m_hasJumpGo = thisWhileHasJumpGo || oldHasJumpGo;
|
m_hasJumpDelay = thisWhileHasJumpDelay || oldHasJumpDelay;
|
||||||
if (m_doNConst) {
|
if (m_doNConst) {
|
||||||
if (nodep->condp()->isZero()) {
|
if (nodep->condp()->isZero()) {
|
||||||
UINFO(4, "WHILE(0) => nop " << nodep << endl);
|
UINFO(4, "WHILE(0) => nop " << nodep << endl);
|
||||||
|
|
@ -2129,7 +2129,7 @@ private:
|
||||||
}
|
}
|
||||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||||
} else if (nodep->condp()->isNeqZero()) {
|
} else if (nodep->condp()->isNeqZero()) {
|
||||||
if (!thisWhileHasJumpGo) {
|
if (!thisWhileHasJumpDelay) {
|
||||||
nodep->v3warn(INFINITELOOP, "Infinite loop (condition always true)");
|
nodep->v3warn(INFINITELOOP, "Infinite loop (condition always true)");
|
||||||
nodep->fileline()->modifyWarnOff(V3ErrorCode::INFINITELOOP,
|
nodep->fileline()->modifyWarnOff(V3ErrorCode::INFINITELOOP,
|
||||||
true); // Complain just once
|
true); // Complain just once
|
||||||
|
|
@ -2161,9 +2161,13 @@ private:
|
||||||
//-----
|
//-----
|
||||||
// Jump elimination
|
// Jump elimination
|
||||||
|
|
||||||
|
virtual void visit(AstDelay* nodep) VL_OVERRIDE {
|
||||||
|
iterateChildren(nodep);
|
||||||
|
m_hasJumpDelay = true;
|
||||||
|
}
|
||||||
virtual void visit(AstJumpGo* nodep) VL_OVERRIDE {
|
virtual void visit(AstJumpGo* nodep) VL_OVERRIDE {
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
m_hasJumpGo = true;
|
m_hasJumpDelay = true;
|
||||||
if (m_doExpensive) {
|
if (m_doExpensive) {
|
||||||
// If last statement in a jump label we have JumpLabel(...., JumpGo)
|
// If last statement in a jump label we have JumpLabel(...., JumpGo)
|
||||||
// Often caused by "return" in a Verilog function. The Go is pointless, remove.
|
// Often caused by "return" in a Verilog function. The Go is pointless, remove.
|
||||||
|
|
@ -2566,7 +2570,7 @@ public:
|
||||||
m_doShort = true; // Presently always done
|
m_doShort = true; // Presently always done
|
||||||
m_doV = false;
|
m_doV = false;
|
||||||
m_doGenerate = false; // Inside generate conditionals
|
m_doGenerate = false; // Inside generate conditionals
|
||||||
m_hasJumpGo = false;
|
m_hasJumpDelay = false;
|
||||||
m_warn = false;
|
m_warn = false;
|
||||||
m_wremove = true; // Overridden in visitors
|
m_wremove = true; // Overridden in visitors
|
||||||
m_modp = NULL;
|
m_modp = NULL;
|
||||||
|
|
|
||||||
|
|
@ -189,8 +189,8 @@ private:
|
||||||
bool m_paramsOnly; // Computing parameter value; limit operation
|
bool m_paramsOnly; // Computing parameter value; limit operation
|
||||||
AstRange* m_cellRangep; // Range for arrayed instantiations, NULL for normal instantiations
|
AstRange* m_cellRangep; // Range for arrayed instantiations, NULL for normal instantiations
|
||||||
AstNodeFTask* m_ftaskp; // Current function/task
|
AstNodeFTask* m_ftaskp; // Current function/task
|
||||||
|
AstNodeProcedure* m_procedurep; // Current final/always
|
||||||
AstFunc* m_funcp; // Current function
|
AstFunc* m_funcp; // Current function
|
||||||
AstInitial* m_initialp; // Current initial block
|
|
||||||
AstAttrOf* m_attrp; // Current attribute
|
AstAttrOf* m_attrp; // Current attribute
|
||||||
bool m_doGenerate; // Do errors later inside generate statement
|
bool m_doGenerate; // Do errors later inside generate statement
|
||||||
int m_dtTables; // Number of created data type tables
|
int m_dtTables; // Number of created data type tables
|
||||||
|
|
@ -539,6 +539,17 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void visit(AstDelay* nodep) VL_OVERRIDE {
|
virtual void visit(AstDelay* nodep) VL_OVERRIDE {
|
||||||
|
if (VN_IS(m_procedurep, Final)) {
|
||||||
|
nodep->v3error("Delays are not legal in final blocks. IEEE 1800-2017 9.2.3");
|
||||||
|
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (VN_IS(m_ftaskp, Func)) {
|
||||||
|
nodep->v3error("Delays are not legal in functions. Suggest use a task. "
|
||||||
|
"IEEE 1800-2017 13.4.4");
|
||||||
|
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||||
|
return;
|
||||||
|
}
|
||||||
nodep->v3warn(STMTDLY, "Unsupported: Ignoring delay on this delayed statement.");
|
nodep->v3warn(STMTDLY, "Unsupported: Ignoring delay on this delayed statement.");
|
||||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||||
}
|
}
|
||||||
|
|
@ -1661,7 +1672,8 @@ private:
|
||||||
// if (debug() >= 9) nodep->dumpTree(cout, " VRout ");
|
// if (debug() >= 9) nodep->dumpTree(cout, " VRout ");
|
||||||
if (nodep->lvalue() && nodep->varp()->direction() == VDirection::CONSTREF) {
|
if (nodep->lvalue() && nodep->varp()->direction() == VDirection::CONSTREF) {
|
||||||
nodep->v3error("Assigning to const ref variable: " << nodep->prettyNameQ());
|
nodep->v3error("Assigning to const ref variable: " << nodep->prettyNameQ());
|
||||||
} else if (nodep->lvalue() && nodep->varp()->isConst() && !m_paramsOnly && !m_initialp) {
|
} else if (nodep->lvalue() && nodep->varp()->isConst() && !m_paramsOnly
|
||||||
|
&& !VN_IS(m_procedurep, Initial)) {
|
||||||
// Too loose, but need to allow our generated first assignment
|
// Too loose, but need to allow our generated first assignment
|
||||||
// Move this to a property of the AstInitial block
|
// Move this to a property of the AstInitial block
|
||||||
nodep->v3error("Assigning to const variable: " << nodep->prettyNameQ());
|
nodep->v3error("Assigning to const variable: " << nodep->prettyNameQ());
|
||||||
|
|
@ -3763,11 +3775,11 @@ private:
|
||||||
processFTaskRefArgs(nodep);
|
processFTaskRefArgs(nodep);
|
||||||
nodep->didWidth(true);
|
nodep->didWidth(true);
|
||||||
}
|
}
|
||||||
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
|
virtual void visit(AstNodeProcedure* nodep) VL_OVERRIDE {
|
||||||
assertAtStatement(nodep);
|
assertAtStatement(nodep);
|
||||||
m_initialp = nodep;
|
m_procedurep = nodep;
|
||||||
userIterateChildren(nodep, NULL);
|
userIterateChildren(nodep, NULL);
|
||||||
m_initialp = NULL;
|
m_procedurep = NULL;
|
||||||
}
|
}
|
||||||
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
virtual void visit(AstNetlist* nodep) VL_OVERRIDE {
|
||||||
// Iterate modules backwards, in bottom-up order. That's faster
|
// Iterate modules backwards, in bottom-up order. That's faster
|
||||||
|
|
@ -5227,8 +5239,8 @@ public:
|
||||||
m_paramsOnly = paramsOnly;
|
m_paramsOnly = paramsOnly;
|
||||||
m_cellRangep = NULL;
|
m_cellRangep = NULL;
|
||||||
m_ftaskp = NULL;
|
m_ftaskp = NULL;
|
||||||
|
m_procedurep = NULL;
|
||||||
m_funcp = NULL;
|
m_funcp = NULL;
|
||||||
m_initialp = NULL;
|
|
||||||
m_attrp = NULL;
|
m_attrp = NULL;
|
||||||
m_doGenerate = doGenerate;
|
m_doGenerate = doGenerate;
|
||||||
m_dtTables = 0;
|
m_dtTables = 0;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
%Error: t/t_timing_func_bad.v:10:8: Delays are not legal in functions. Suggest use a task. IEEE 1800-2017 13.4.4
|
||||||
|
: ... In instance t
|
||||||
|
10 | #1 $stop;
|
||||||
|
| ^
|
||||||
|
%Error: t/t_timing_func_bad.v:23:8: Delays are not legal in final blocks. IEEE 1800-2017 9.2.3
|
||||||
|
: ... In instance t
|
||||||
|
23 | #1;
|
||||||
|
| ^
|
||||||
|
%Error: Exiting due to
|
||||||
|
|
@ -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 2019 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);
|
||||||
|
|
||||||
|
compile(
|
||||||
|
verilator_flags2 => ['--lint-only'],
|
||||||
|
fails => 1,
|
||||||
|
expect_filename => $Self->{golden_filename},
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2020 by Wilson Snyder.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
module t(/*AUTOARG*/);
|
||||||
|
|
||||||
|
function int f;
|
||||||
|
#1 $stop;
|
||||||
|
f = 0;
|
||||||
|
endfunction
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
i = f();
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
final begin
|
||||||
|
#1;
|
||||||
|
$stop;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
Loading…
Reference in New Issue