Verilogではノンブロッキング代入とブロッキング代入を適切に使いわける必要がある.
本記事では,ノンブロッキング代入とブロッキング代入について説明する.
ノンブロッキング代入とブロッキング代入
Verilogでは(<=)で代入するノンブロッキング代入と(=)で代入するブロッキング代入の2種類がある.
一般的な説明としては…
ブロッキング代入はC言語などのプログラムと同様でコードに書かれた順番で演算が進んでいく.
一方で,ノンブロッキング代入はコードに書かれている順序には関係なく計算される.
しかし,より重要なのは論理合成後に生成される実際の回路との対応だ.
実際の回路との対応を考えれば,ブロッキング代入はalways文外でノンブロッキング代入はalways文内で使用するのが正しいと判断できる.
これらを表にまとめた.
使用法 | 回路的意味 | |
---|---|---|
ノンブロッキング代入 | always 文内 | フリップフロップへの代入 |
ブロッキング代入 | always 文外 assignを使用 | 配線接続 |
フリップフロップは順序回路で前の状態を保存する役割だったが,値を更新するタイミングが必要でこれにクロックが必要である.
always文内では,クロックに同期した論理が記述されるために,必ずフリップフロップ(Verilogではreg)にノンブロッキング代入(<=)で代入するのが正しい.
ノンブロッキング代入がフリップフロップへの代入というイメージが付いていれば,always文内にassignやブロッキング代入(=)があるのはおかしいと気づけるだろう.
それは,assignやブロッキング代入(=)はただの配線接続であるのでクロックに同期している必要はなく,always文の外に記述するのが正しい.
4入力ANDの例
次の2つのモジュール(module1, module2)を比較してみる.
module1は一部ブロッキング代入で記述し,module2は全てノンブロッキング代入で記述した.
module module1 (
input clk_i,
input a_i,
input b_i,
input c_i,
input d_i,
output z_o
);
reg z_r;
wire ab, cd;
assign ab = a_i & b_i;
assign cd = c_i & d_i;
assign z_o = z_r;
always @(posedge clk_i) begin
z_r <= ab & cd;
end
endmodule
module module2 (
input clk_i,
input a_i,
input b_i,
input c_i,
input d_i,
output z_o
);
reg z_r, ab_r, cd_r;
assign z_o = z_r;
always @(posedge clk_i) begin
ab_r <= a_i & b_i
cd_r <= c_i & d_i
z_r <= ab_r & cd_r;
end
endmodule
上記の2つの回路の違いがどうなるかは次に示している.
module1はシンプルな4入力ANDとなるが,module2はフリップフロップが間に挿入されるので2クロック遅れて結果が出力される回路となる.
同じ論理でも書き方によって回路は全く違うものになるので要注意である.
まとめ
Verilogでは(<=)で代入するノンブロッキング代入と(=)で代入するブロッキング代入の2種類がある.
使用法と回路的な意味は次のようになる.
使用法 | 回路的意味 | |
---|---|---|
ノンブロッキング代入 | always 文内 | フリップフロップへの代入 |
ブロッキング代入 | always 文外 assignを使用 | 配線接続 |
Verilogは,同じ論理でも書き方によって回路は全く違うものになるので,ノンブロッキング代入とブロッキング代入を心から理解し適切に使いわける必要がある.
コメント