diff --git a/elaborate.cc b/elaborate.cc index 123d0f378..3010ae2db 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -2977,6 +2977,9 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const return tmp; } + if (type != NetBlock::SEQU) + des->fork_enter(); + for (unsigned idx = 0 ; idx < list_.size() ; idx += 1) { assert(list_[idx]); @@ -3018,6 +3021,9 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const cur->append(tmp); } + if (type != NetBlock::SEQU) + des->fork_exit(); + // Update flags in parent scope. if (!nscope->is_const_func()) scope->is_const_func(false); @@ -5763,23 +5769,27 @@ NetProc* PRepeat::elaborate(Design*des, NetScope*scope) const NetProc* PReturn::elaborate(Design*des, NetScope*scope) const { NetScope*target = scope; + + if (des->is_in_fork()) { + cerr << get_fileline() << ": error: " + << "Return statement is not allowed within fork-join block." << endl; + des->errors += 1; + return 0; + } + for (;;) { if (target == 0) { cerr << get_fileline() << ": error: " - << "Return statement is not in a function." << endl; + << "Return statement is not in a function or task." + << endl; des->errors += 1; return 0; } if (target->type() == NetScope::FUNC) break; - - if (target->type() == NetScope::TASK) { - cerr << get_fileline() << ": error: " - << "Cannot \"return\" from tasks." << endl; - des->errors += 1; - return 0; - } + if (target->type() == NetScope::TASK) + break; if (target->type()==NetScope::BEGIN_END) { target = target->parent(); @@ -5791,6 +5801,19 @@ NetProc* PReturn::elaborate(Design*des, NetScope*scope) const des->errors += 1; return 0; } + + if (target->type() == NetScope::TASK) { + if (expr_) { + cerr << get_fileline() << ": error: " + << "A value cannot be returned from a task." << endl; + des->errors += 1; + return 0; + } + NetDisable *disa = new NetDisable(target, true); + disa->set_line(*this); + return disa; + } + ivl_assert(*this, target->type() == NetScope::FUNC); if (target->func_def()->is_void()) { diff --git a/ivtest/ivltests/task_return1.v b/ivtest/ivltests/task_return1.v new file mode 100644 index 000000000..ae96bffba --- /dev/null +++ b/ivtest/ivltests/task_return1.v @@ -0,0 +1,31 @@ +// Check that it is possible to exit from a task using the return statement with +// affecting other concurrently running instances of the same task. + +module test; + + task automatic t(input integer a, output integer b); + if (a == 0) begin + b = 1; + return; + end + #10 + b = 100; + endtask + + integer b1; + integer b2; + + initial begin + fork + t(0, b1); + t(1, b2); + join + + if (b1 == 1 && b2 == 100) begin + $display("PASSED"); + end else begin + $display("FAILED b1=%0d, b2=%0d", b1, b2); + end + end + +endmodule diff --git a/ivtest/ivltests/task_return2.v b/ivtest/ivltests/task_return2.v new file mode 100644 index 000000000..d82c8fc64 --- /dev/null +++ b/ivtest/ivltests/task_return2.v @@ -0,0 +1,22 @@ +// Check that it is possible to return from a named sub-block of a task using a +// `return` statement. + +module test; + + task t(input integer a); + begin : subblock + if (a == 1) begin : condition + return; + end + end + $display("FAILED"); + $finish; + endtask + + initial begin + t(1); + #10 + $display("PASSED"); + end + +endmodule diff --git a/ivtest/ivltests/task_return_fail1.v b/ivtest/ivltests/task_return_fail1.v new file mode 100644 index 000000000..044116e16 --- /dev/null +++ b/ivtest/ivltests/task_return_fail1.v @@ -0,0 +1,15 @@ +// Check that using a return value when using the return statement in a task +// results in an error. + +module test; + + task t; + return 10; // This is an error, tasks can not have return values. + endtask + + initial begin + t(); + $display("FAILED"); + end + +endmodule diff --git a/ivtest/ivltests/task_return_fail2.v b/ivtest/ivltests/task_return_fail2.v new file mode 100644 index 000000000..a6b6ac37e --- /dev/null +++ b/ivtest/ivltests/task_return_fail2.v @@ -0,0 +1,18 @@ +// Check that using a return statment inside a parallel block in a task results +// in an error. + +module test; + + task t; + fork + // This is an error it is not possible to return from inside a parallel block + return; + join + endtask + + initial begin + t(); + $display("FAILED"); + end + +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index beecf80b2..31e20b9e1 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -38,3 +38,7 @@ sv_array_cassign7 vvp_tests/sv_array_cassign7.json sv_foreach9 vvp_tests/sv_foreach9.json sv_foreach10 vvp_tests/sv_foreach10.json sdf_header vvp_tests/sdf_header.json +task_return1 vvp_tests/task_return1.json +task_return2 vvp_tests/task_return2.json +task_return_fail1 vvp_tests/task_return_fail1.json +task_return_fail2 vvp_tests/task_return_fail2.json diff --git a/ivtest/vvp_tests/task_return1.json b/ivtest/vvp_tests/task_return1.json new file mode 100644 index 000000000..d6fcc1d2c --- /dev/null +++ b/ivtest/vvp_tests/task_return1.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "task_return1.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/task_return2.json b/ivtest/vvp_tests/task_return2.json new file mode 100644 index 000000000..1bac64c1d --- /dev/null +++ b/ivtest/vvp_tests/task_return2.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "task_return2.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/task_return_fail1.json b/ivtest/vvp_tests/task_return_fail1.json new file mode 100644 index 000000000..3511d078c --- /dev/null +++ b/ivtest/vvp_tests/task_return_fail1.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "task_return_fail1.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/ivtest/vvp_tests/task_return_fail2.json b/ivtest/vvp_tests/task_return_fail2.json new file mode 100644 index 000000000..0ea73f5b4 --- /dev/null +++ b/ivtest/vvp_tests/task_return_fail2.json @@ -0,0 +1,5 @@ +{ + "type" : "CE", + "source" : "task_return_fail2.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/netlist.h b/netlist.h index 3e1f48a9a..811604355 100644 --- a/netlist.h +++ b/netlist.h @@ -5124,6 +5124,12 @@ class Design { // detected. It prevents code being emitted. unsigned errors; + void fork_enter() { in_fork++; }; + void fork_exit() { in_fork--; }; + bool is_in_fork() { return in_fork != 0; } + + unsigned int in_fork = 0; + private: NetScope* find_scope_(NetScope*, const hname_t&name, NetScope::TYPE type = NetScope::MODULE) const;