Hi,
system verilog lrm 1800-212 makes following statement on page 176:
“Within a fork-join_any or fork-join_none block, it shall be illegal to refer to formal arguments
passed by reference other than in the initialization value expressions of variables declared in a
block_item_declaration of the fork.”
I am not clear why this restriction should be there. Can someone explain with an example.
also if I have an automatic function foo, which spawns a task tsk1, using fork-join_none and task is passed a local variable of the function by reference. Task modifies a the local variable at 10ns. But since function executes in 0 time, the variable will not exist. Will this result in run-time error?
thanks,
-sunil
In reply to dave_59:
In reply to puranik.sunil@tcs.com:
The problem when passing a variable by reference is that the code inside the function or task knows nothing about the lifetime of the argument being passed, it only know the location where it exists.
Hi Dave,
thanks for the explanation.
Now if the task tsk1 in my question has a parameter prm_out of the type output and this parameter is passed the local variable inside automatic function. Task writes to it at 10 ns. But it will not exist at 10 ns and this will also result in “accessing a variable that no longer exists.” So does this restriction apply to output parameters in addition to reference parameters also? Or the output parameter is simply copied on stack by called function/task and calling function in this case does not read it from stack since calling function no longer exists along with its variables. So output parameter is simply destroyed with stack?
Is this understanding correct?
regards,
-sunil
In reply to puranik.sunil@tcs.com:
I believe what you are asking is this:
module top;
function automatic foo;
bit local_prm;
fork
begin : forked
tsk1(local_prm);
$display("local_prm %b exists till this process ends %t",local_prm, $time);
end
join_none
endfunction
task automatic tsk1(output bit prm_out); // ref bit prm_out also allowed
#10 prm_out = 1;
endtask
initial foo();
endmodule
This is allowed because:
The lifetime of a fork-join block (see 9.3.2) shall encompass the execution of all processes spawned by the
block. The lifetime of a scope enclosing any fork-join block includes the lifetime of the fork-join block.
Solocal_prm remains active while the process forked is active even after foo() returns. And it doesn’t matter if prm_out gets passed by reference or not. So it’s a little more complex than just a call stack determining the lifetime of an automatic.
But let’s go back to your original post and modify this example
module top;
function automatic foo;
bit prm;
fork
begin : forked
tsk1(prm);
$display("prm %b exists till this process ends %t",prm, $time);
end
join_none
endfunction
task automatic tsk1(ref bit prm_out);
#10 prm_out = 1;
fork
tsk2(prm_out);
join_none
endtask
task automatic tsk2(ref bit prm_out); // this is illegal
#10 prm_out = 0;
endtask
initial foo;
endmodule
For this to work, the compiler would need to know the lifetime of prm goes beyond the lifetime of the forked process. Generally, it’s not a good idea to have to look inside the task you are calling in determining the behavior of code outside the task call.
[i]In reply to [url=https://verificationacademy.com/forums/
Hi Dave,
thanks for the detailed reply.
The LRM statement below applies only to fork-join. Does it apply to fork-join_none or fork-join_any also? In example 1 which you have given, you have used a fork-join_none block.
regards,
-sunil
In reply to puranik.sunil@tcs.com:
Section 9.3.2 refers to all of the
fork constructs. When “fork-join” is used without being highlighted as syntax, like
fork join, it refers to all the parallel
fork constructs.
In reply to puranik.sunil@tcs.com:
- The compiler just needs to associate a particular scope, or set of scopes with an automatic variable that need to exit before deallocating that variable.
- The compiler just needs to know that the ‘forked’ scope has to finish before it deallocates prm.
- There is no problem when using fork/join to spawn tsk2. That is because the ‘forked’ scope will not end until after the call to tsk1 returns.