n generator task in which there is a for loop with 1000 repetitions.
n model task in which there is a forever loop.
n driver task in which there is a forever loop.
I knew how to develop 1 generator, 1 driver, and 1 model but I don’t know how can develop n of these.
How should do this job whit fork-join?
In reply to Moein75:
It would help if you were more specific about your usage of the tasks.
If your n==2, show us the code.
Tasks are called and automatic tasks are dynamically created and destroyed when done.
Objects can be created at elaboration time with the generate endgenerate statement.
That is why I am not clear about your question. What is your usage?
Ben Cohen Ben@systemverilog.us
Link to the list of papers and books that I wrote, many are now donated.
In reply to Moein75:
The issue of using a fork join_any for each group of the loop variable i is taht it joins just that group (e.g., group 0, but not group1)
Can you do something like this where done is a common variable to the t_master task
and any forked task return a 1 to done.
The return end the t_master task
automatic task run(inout bit done); // example of one task
....
done=1;
endtask
automatic task t_master(int v);
bit done;
for (int i = 1; i<=v; i=i+1) begin
fork
// NEED THE FOLLOWING as explained below
automatic int j = i; // Updated 6/27/
gen[j].run(done); //
drv[j].run(done);
model[j].run(done);
join_any
end
wait(done);
return;
endtask
// For v==2, the for loop will create
fork
gen[0].run(done);
drv[0].run(done);
model[0].run(done);
join_any
fork
gen[1].run(done);
drv[1].run(done);
model[1].run(done);
join_any
wait(done); return;
// since any task sets the done to 1, the t_master will end.
This assumes the size of the gen/model/drv are all the same, and that int j is delcared with an automatic lifetime (It would be if this code is inside a class method or a task with an explicit automatic lifetime. You also need to come up with a mechanism for when the test ends.
The most basic fundamentals of the UVM takes care of these issues trivially.
Thank you, if use an automatic variable and replace join_any with join_none, your solution gives my desire output.
If use join_any, gen[1] runs after gen[0].
Dave,
Why is the following code NOT producing an error?
1800 9.3.2 Parallel blocks states
Variables declared in the block_item_declaration of a fork-join block shall be initialized to their initialization value expression whenever execution enters their scope and before any processes are spawned. 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.
module test;
initial begin
for(int i = 0; i < 16; i++)
begin
fork
//automatic int index =i ;
send(i); // am within a fork-join-any
// "i" is referring to formal argument "j" of function send
// "j" is a formal where actual is passed by reference
// All simulators give the same results
// Am I misunderstanding 1800?
join_any
end
wait fork;
end
function automatic void send( ref int j);
$display("driving %0d %t" , j, $realtime);
endfunction
endmodule
// Sim
# driving 0 0
# driving 1 0
# driving 2 0
...
# driving 15 0
# exit
You may be confusing the terms “refers to” with “a reference argument”.
The term “refers to” is a mention of an identifier in the source text, referring to something declared in another place. In the code
send(i), The variable i is referred to inside the fork/join_any, and was declared outside the fork. ‘i’ is not a formal argument.
A “formal argument passed by reference” is an indirection. The formal argument identifier becomes a symbolic reference to the actual identifier. And the reference is unidirectional and only active for the duration of the task/function call. Formal j is a reference to actual i, but actual i is not a reference to j. That’s because there is no variable j.
Dave,
Thanks for the clarification.
I understand the need for the **automatic int index =i ; **
But I fail to understand what the 1800 statement (copied below) has to do as a rational
for the need of automatic int k = j;
1800: 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. These variables are useful in processes spawned by looping constructs to store unique, per-iteration data. For example:
initial
for( int j = 1; j <= 3; ++j )
fork
automatic int k = j; // local copy, k, for each value of j
#k $write( "%0d", k );
begin automatic int m = j; // the value of m is undetermined
...
end join_none
Also, can you give an example where a compiler would provide a violation of th2 1800 statement?
I also tried the 1800 example, but I saw no violation of the value of “m”
module test;
initial begin
for(int i = 0; i < 16; i++)
begin
fork
automatic int index =i ;
send(index);
begin
automatic int m = i; // the value of m is undetermined
send(m);
end
join_any
end
wait fork;
end
function automatic void send( ref int j);
j=j+2;
$display("driving %0d %t" , j, $realtime);
endfunction
endmodule
// sim
driving 2 0
driving 3 0
driving 3 0
driving 4 0
driving 4 0
driving 5 0
driving 5 0
..,
driving 16 0
driving 17 0
driving 17 0
driving 18 0
The example from the LRM you show is about the sentence before the two sentences you quoted, and last sentence. It is not trying to explain the restriction in the first sentence.
The issue with arguments passed by reference is dealing with the end of life of a variable with an automatic lifetime. The life of an automatic variable begins when entering the procedural block (begin/fork, task/function) containing its declaration. Normally its life ends when exiting that block, but gets extended by any fork block enclosed within its scope. Calling a task or function procedure does not make that procedure an enclosing scope.
An contrived illegal example would be:
module top;
task automatic t1;
int i1=4;
t2(i1);
#1 return; // i1's lifetime ends when this task returns at time 1
endtask
task t2(ref int arg);
fork
while(arg>0) #1 $display($time, arg--);
join_none
endtask
initial fork t1; t1; join
endmodule
The problem with this code when calling t2, the lifetime of arg needs to exist for the duration of the while loop., but it disappears when t2 exits.