Verilog ノンブロッキング代入とブロッキング代入

verilog_nonblocking-eyecatch verilog

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は,同じ論理でも書き方によって回路は全く違うものになるので,ノンブロッキング代入とブロッキング代入を心から理解し適切に使いわける必要がある.

コメント

タイトルとURLをコピーしました