SystemVerilogではfor文を使ってforkの並列プロセスを複数実行する事ができる。その際、forのindex変数をfork内に直接渡すのではなく、automaticで定義した変数に一旦渡す。
module for_fork_test();
initial begin
int val[] = '{0,1,2,3,4,5};
foreach(val[i])
fork
automatic int auto_i = i; // <====== This is necessary!!!!
begin
#(10*auto_i);
$display("time %2t: process %0d finsihed, val = %0d", $time, auto_i, val[auto_i]);
end
join_none
wait fork;
end
endmodule
time 0: process 0 finished, val = 0
time 10: process 1 finished, val = 1
time 20: process 2 finished, val = 2
time 30: process 3 finished, val = 3
time 40: process 4 finished, val = 4
time 50: process 5 finished, val = 5
automaticの変数を介さず直接渡すと。。。
module for_fork_test();
initial begin
int val[] = '{0,1,2,3,4,5,6};
for(int i=0; i<6; i++)
fork
begin
#(10*i);
$display("time %2t, process %0d : val = %0d", $time, i, val[i]);
end
join_none
wait fork;
end
endmodule
time 60: process 6 finished, val = 6
time 60: process 6 finished, val = 6
time 60: process 6 finished, val = 6
time 60: process 6 finished, val = 6
time 60: process 6 finished, val = 6
time 60: process 6 finished, val = 6
と、この様にforkの各プロセスの実行がfor文が回り終わってi=6となった後にスケジュールされる為、その時点でのi=6が参照されて、みんな同じ実行をしてしまう。
fork/join_noneでプロセス分岐した後、wait forkで全てのforkプロセスの終了を待つようにしているが、これは少し注意が必要。wait forkは同一のプロセス或いはそこからforkで分岐した子プロセス以下すべてのforkプロセスの終了を待つ。したがって、以下の様に他にforkがある場合にはそのプロセスの終了も待ってしまう。
module for_fork_test();
initial begin
int val[] = '{0,1,2,3,4,5};
fork : first_fork
forever #1000 $display("Hello!!");
join_none
//---------------------------------
foreach(val[i])
fork : second_fork
automatic int auto_i = i;
begin
#(10*auto_i);
$display("time %2t: process %0d finsihed, val = %0d", $time, auto_i, val[auto_i]);
end
join_none
wait fork; // <==== wait for both end of first_fork and second_fork!!!!
//---------------------------------
end
endmodule
この様にforeach文で分岐させたsecond_forkのラベルを付けたfork/join_noneプロセスの終了を待ちたいのに、first_forkのラベルを付けた別のfork/join_noneプロセスの終了も待ってしまう。この例の様にそのプロセスがずっと終わらないプロセスだとwait_forの先に進まない。
この様な場合どうすればよいかと言うと、wait forkとそれで待ちたいforkのみを別途ダミーのfork/joinで囲って、ひとまとまりのプロセスとして区別し、wait forkが効く範囲を限定する。wait forkが効く範囲は前述のとおり、同一プロセスとその子プロセス以下なので。
module for_fork_test();
initial begin
int val[] = '{0,1,2,3,4,5};
fork : first_fork
forever #1000 $display("Hello!!");
join_none
fork : guard_fork
begin //---------------------------------
foreach(val[i])
fork : second_fork
automatic int auto_i = i;
begin
#(10*auto_i);
$display("time %2t: process %0d finsihed, val = %0d", $time, auto_i, val[auto_i]);
end
join_none
wait fork; // <==== wait for end of second_fork
end //---------------------------------
join
end
endmodule
以下参考