diff --git a/src/V3LinkJump.cpp b/src/V3LinkJump.cpp index 566060394..3b02c867a 100644 --- a/src/V3LinkJump.cpp +++ b/src/V3LinkJump.cpp @@ -52,6 +52,7 @@ private: AstNodeFTask* m_ftaskp; // Current function/task AstWhile* m_loopp; // Current loop bool m_loopInc; // In loop increment + bool m_inFork; // Under fork int m_modRepeatNum; // Repeat counter BlockStack m_blockStack; // All begin blocks above current node @@ -136,9 +137,14 @@ private: } virtual void visit(AstNodeBlock* nodep) VL_OVERRIDE { UINFO(8, " " << nodep << endl); + bool oldFork = m_inFork; m_blockStack.push_back(nodep); - iterateChildren(nodep); + { + m_inFork = m_inFork || VN_IS(nodep, Fork); + iterateChildren(nodep); + } m_blockStack.pop_back(); + m_inFork = oldFork; } virtual void visit(AstRepeat* nodep) VL_OVERRIDE { // So later optimizations don't need to deal with them, @@ -185,7 +191,11 @@ private: virtual void visit(AstReturn* nodep) VL_OVERRIDE { iterateChildren(nodep); AstFunc* funcp = VN_CAST(m_ftaskp, Func); - if (!m_ftaskp) { + if (m_inFork) { + nodep->v3error("Return isn't legal under fork (IEEE 1800-2017 9.2.3)"); + VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); + return; + } else if (!m_ftaskp) { nodep->v3error("Return isn't underneath a task or function"); } else if (funcp && !nodep->lhsp()) { nodep->v3error("Return underneath a function should have return value"); @@ -268,6 +278,7 @@ public: explicit LinkJumpVisitor(AstNetlist* nodep) { m_modp = NULL; m_ftaskp = NULL; + m_inFork = false; m_loopp = NULL; m_loopInc = false; m_modRepeatNum = 0; diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 51051876e..ed78d7546 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -490,17 +490,6 @@ private: } iterateChildren(nodep); } - virtual void visit(AstFork* nodep) VL_OVERRIDE { - if (v3Global.opt.bboxUnsup()) { - AstBegin* newp - = new AstBegin(nodep->fileline(), nodep->name(), nodep->stmtsp()->unlinkFrBack()); - nodep->replaceWith(newp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); - } else { - nodep->v3error("Unsupported: fork statements"); - // TBD might support only normal join, if so complain about other join flavors - } - } virtual void visit(AstCase* nodep) VL_OVERRIDE { V3Config::applyCase(nodep); cleanFileline(nodep); diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 699020441..b57fe02c7 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -552,6 +552,23 @@ private: nodep->v3warn(STMTDLY, "Unsupported: Ignoring delay on this delayed statement."); VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); } + virtual void visit(AstFork* nodep) VL_OVERRIDE { + if (VN_IS(m_ftaskp, Func) && !nodep->joinType().joinNone()) { + nodep->v3error("Only fork .. join_none is legal in functions. " + "(IEEE 1800-2017 13.4.4)"); + VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); + return; + } + if (v3Global.opt.bboxUnsup()) { + AstBegin* newp + = new AstBegin(nodep->fileline(), nodep->name(), nodep->stmtsp()->unlinkFrBack()); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } else { + nodep->v3error("Unsupported: fork statements"); + // TBD might support only normal join, if so complain about other join flavors + } + } virtual void visit(AstToLowerN* nodep) VL_OVERRIDE { if (m_vup->prelim()) { iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH); diff --git a/test_regress/t/t_fork.out b/test_regress/t/t_fork.out index 1f9b98a83..5d76dd536 100644 --- a/test_regress/t/t_fork.out +++ b/test_regress/t/t_fork.out @@ -1,4 +1,5 @@ %Error: t/t_fork.v:10:14: Unsupported: fork statements + : ... In instance t 10 | fork : fblk | ^~~~ %Error: Exiting due to diff --git a/test_regress/t/t_fork_func2_bad.out b/test_regress/t/t_fork_func2_bad.out new file mode 100644 index 000000000..16cdd6242 --- /dev/null +++ b/test_regress/t/t_fork_func2_bad.out @@ -0,0 +1,5 @@ +%Error: t/t_fork_func2_bad.v:10:7: Only fork .. join_none is legal in functions. (IEEE 1800-2017 13.4.4) + : ... In instance t + 10 | fork + | ^~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_fork_func2_bad.pl b/test_regress/t/t_fork_func2_bad.pl new file mode 100755 index 000000000..2f077ff56 --- /dev/null +++ b/test_regress/t/t_fork_func2_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_fork_func2_bad.v b/test_regress/t/t_fork_func2_bad.v new file mode 100644 index 000000000..c777a5c58 --- /dev/null +++ b/test_regress/t/t_fork_func2_bad.v @@ -0,0 +1,21 @@ +// 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; + fork + ; + join_any // Illegal 13.4.4 + endfunction + + int i; + + initial begin + i = f(); + end + +endmodule diff --git a/test_regress/t/t_fork_func_bad.out b/test_regress/t/t_fork_func_bad.out new file mode 100644 index 000000000..0fdf968a9 --- /dev/null +++ b/test_regress/t/t_fork_func_bad.out @@ -0,0 +1,4 @@ +%Error: t/t_fork_func_bad.v:11:10: Return isn't legal under fork (IEEE 1800-2017 9.2.3) + 11 | return 0; + | ^~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_fork_func_bad.pl b/test_regress/t/t_fork_func_bad.pl new file mode 100755 index 000000000..2f077ff56 --- /dev/null +++ b/test_regress/t/t_fork_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_fork_func_bad.v b/test_regress/t/t_fork_func_bad.v new file mode 100644 index 000000000..c4a67a6f1 --- /dev/null +++ b/test_regress/t/t_fork_func_bad.v @@ -0,0 +1,21 @@ +// 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; + fork + return 0; // Illegal 9.3.2 + join_none + endfunction + + int i; + + initial begin + i = f(); + end + +endmodule