diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 7418df2fa..4cff5c4b8 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -102,7 +102,7 @@ private: bool m_doShort; // Remove expressions that short circuit bool m_doV; // Verilog, not C++ conversion 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 AstArraySel* m_selp; // Current select AstNode* m_scopep; // Current scope @@ -2114,11 +2114,11 @@ private: iterateChildren(nodep); } virtual void visit(AstWhile* nodep) VL_OVERRIDE { - bool oldHasJumpGo = m_hasJumpGo; - m_hasJumpGo = false; + bool oldHasJumpDelay = m_hasJumpDelay; + m_hasJumpDelay = false; { iterateChildren(nodep); } - bool thisWhileHasJumpGo = m_hasJumpGo; - m_hasJumpGo = thisWhileHasJumpGo || oldHasJumpGo; + bool thisWhileHasJumpDelay = m_hasJumpDelay; + m_hasJumpDelay = thisWhileHasJumpDelay || oldHasJumpDelay; if (m_doNConst) { if (nodep->condp()->isZero()) { UINFO(4, "WHILE(0) => nop " << nodep << endl); @@ -2129,7 +2129,7 @@ private: } VL_DO_DANGLING(nodep->deleteTree(), nodep); } else if (nodep->condp()->isNeqZero()) { - if (!thisWhileHasJumpGo) { + if (!thisWhileHasJumpDelay) { nodep->v3warn(INFINITELOOP, "Infinite loop (condition always true)"); nodep->fileline()->modifyWarnOff(V3ErrorCode::INFINITELOOP, true); // Complain just once @@ -2161,9 +2161,13 @@ private: //----- // Jump elimination + virtual void visit(AstDelay* nodep) VL_OVERRIDE { + iterateChildren(nodep); + m_hasJumpDelay = true; + } virtual void visit(AstJumpGo* nodep) VL_OVERRIDE { iterateChildren(nodep); - m_hasJumpGo = true; + m_hasJumpDelay = true; if (m_doExpensive) { // If last statement in a jump label we have JumpLabel(...., JumpGo) // 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_doV = false; m_doGenerate = false; // Inside generate conditionals - m_hasJumpGo = false; + m_hasJumpDelay = false; m_warn = false; m_wremove = true; // Overridden in visitors m_modp = NULL; diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 2d5a4d94a..51a9922db 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -189,8 +189,8 @@ private: bool m_paramsOnly; // Computing parameter value; limit operation AstRange* m_cellRangep; // Range for arrayed instantiations, NULL for normal instantiations AstNodeFTask* m_ftaskp; // Current function/task + AstNodeProcedure* m_procedurep; // Current final/always AstFunc* m_funcp; // Current function - AstInitial* m_initialp; // Current initial block AstAttrOf* m_attrp; // Current attribute bool m_doGenerate; // Do errors later inside generate statement int m_dtTables; // Number of created data type tables @@ -539,6 +539,17 @@ private: } } 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."); VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); } @@ -1661,7 +1672,8 @@ private: // if (debug() >= 9) nodep->dumpTree(cout, " VRout "); if (nodep->lvalue() && nodep->varp()->direction() == VDirection::CONSTREF) { 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 // Move this to a property of the AstInitial block nodep->v3error("Assigning to const variable: " << nodep->prettyNameQ()); @@ -3763,11 +3775,11 @@ private: processFTaskRefArgs(nodep); nodep->didWidth(true); } - virtual void visit(AstInitial* nodep) VL_OVERRIDE { + virtual void visit(AstNodeProcedure* nodep) VL_OVERRIDE { assertAtStatement(nodep); - m_initialp = nodep; + m_procedurep = nodep; userIterateChildren(nodep, NULL); - m_initialp = NULL; + m_procedurep = NULL; } virtual void visit(AstNetlist* nodep) VL_OVERRIDE { // Iterate modules backwards, in bottom-up order. That's faster @@ -5227,8 +5239,8 @@ public: m_paramsOnly = paramsOnly; m_cellRangep = NULL; m_ftaskp = NULL; + m_procedurep = NULL; m_funcp = NULL; - m_initialp = NULL; m_attrp = NULL; m_doGenerate = doGenerate; m_dtTables = 0; diff --git a/test_regress/t/t_timing_func_bad.out b/test_regress/t/t_timing_func_bad.out new file mode 100644 index 000000000..681f70631 --- /dev/null +++ b/test_regress/t/t_timing_func_bad.out @@ -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 diff --git a/test_regress/t/t_timing_func_bad.pl b/test_regress/t/t_timing_func_bad.pl new file mode 100755 index 000000000..2f077ff56 --- /dev/null +++ b/test_regress/t/t_timing_func_bad.pl @@ -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; diff --git a/test_regress/t/t_timing_func_bad.v b/test_regress/t/t_timing_func_bad.v new file mode 100644 index 000000000..aa7ceddfc --- /dev/null +++ b/test_regress/t/t_timing_func_bad.v @@ -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