🤔
Verilog/SystemVerilogでのbegin-end,fork-joinの違い
VerilogとSystemVerilogの間にはbegin-end (sequential block) と fork-join (parallel block) に文法上の違いがあります。SystemVerilog では追加仕様があり、より柔軟な記述が可能です。
無名ブロックでのスコープ生成
Verilog では 名前付き の begin-end / fork-join ブロックのみがスコープを生成します。
そのため、無名ブロックに変数を宣言するとコンパイルエラーになります。
// 名前付きのbegin-end,fork-joinブロックのみ、
// モジュールやタスク内部の階層的なスコープとして機能します。
// これにより、ブロック内で宣言されたローカル変数を一意に識別できます。
module verilog_example;
initial begin
integer i; // OK: 宣言可能
begin : blk1
integer j; // OK: 名前付きブロックは新しいスコープを持つ
end
begin
integer k; // ERROR: 無名ブロックでは新しいスコープを作らない
end
end
endmodule
SystemVerilog では 無名ブロックでも変数宣言を含む場合、新しいスコープが作られます。
// 名前の付けられていないbegin-end/fork-jonブロックに対しても、
// そのブロックが直接、変数宣言や型宣言などのブロックアイテム宣言を含んでいる場合にのみ、
// 新しい階層スコープを作成します。
// このスコープ内で宣言された要素は外部から参照できる階層名をもたないため、
// ブロック外部から参照できません。
module sv_example;
initial begin
begin
int a = 10; // OK: 無名ブロック内でもスコープが生成される
$display("a = %0d", a);
end
// 外部から a にアクセスできない (スコープが切れる)
// $display("a = %0d", a); // コンパイルエラー
end
endmodule
名前つきブロックのブロック後名前記述
SystemVerilog では、名前付きブロックにおいて ブロックの終了部分にも名前を記述できます。
これにより begin-end, fork-join の対応を明示でき、ミスを防ぐことが可能です。
module block_name_check;
initial begin : my_block
int x = 42;
$display("x = %0d", x);
end : my_block // ← ブロック名を再度書ける
endmodule
join_any, join_none の追加
Verilog では fork-joinブロックは常にjoinキーワードで終了し、親プロセスはブロック内のすべての並列プロセスが完了するまで実行をブロックしました。
module verilog_fork;
initial begin
fork
#10 $display("Task A done");
#20 $display("Task B done");
join
$display("All tasks finished");
end
endmodule
出力例:
#10: Task A done
#20: Task B done
#20: All tasks finished
SystemVerilogでfork-joinブロックに類する新しいブロック終了キーワードのjoin_anyとjoin_noneが追加されました。
fork-join_any
親プロセスは、fork-join_anyブロック内で生成された並列プロセスのいずれか1つが完了した時点で、自身の実行を再開します。
module sv_fork_any;
initial begin
fork
#10 $display("Task A done");
#20 $display("Task B done");
join_any
$display("At least one task finished");
end
endmodule
出力例:
#10: Task A done
#10: At least one task finished
#20: Task B done
fork-join_none
親プロセスは、fork-join_noneブロック内で生成されたすべての並列プロセスと並行して実行を続行します。
module sv_fork_none;
initial begin
fork
#10 $display("Task A done");
#20 $display("Task B done");
join_none
$display("Parent continues immediately");
#30 $display("Simulation end");
end
endmodule
出力例:
#0 : Parent continues immediately
#10: Task A done
#20: Task B done
#30: Simulation end
Discussion