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
以下参考