次の例題は、ブロッキング代入とノンブロッキング代入の動作の違いを調べろ、というもの。
「=」がブロッキング代入で、「<=」がノンブロッキング代入。小なりイコール、ではない (;´Д`)
ブロッキング代入とノンブロッキング代入
ブロッキング代入「=」は、上から順番に実行される。ノンブロッキング代入「<=」は、同時に実行される。
組み合わせ回路では、信号は各ゲートを順にとおってくる。順序回路では、クロックがはいると一斉に信号が走る。だからあれよ、シフトレジスタで、クロックがはいると各段のデータが一斉にシフトする、って。ノンブロッキングって、そんな感じ。
回路記述
ブロッキング代入の回路と、ノンブロッキング代入の回路を用意しました。
違いは、7~9 行目。
たとえば、D=1、X=0、Y=0、Z=0 としたとき、ブロッキング代入では、
X = D = 1 → Y = X = 1 → Z = Y = 1
と、すべて 1 になる。
対して、ノンブロッキング代入では並列に処理するので、
X <= D = 1 Y <= X = 0 Z <= Y = 0
となり、Y、Z の値は変化しない。
テストベンチ
- module DFF_TEST;
- reg CLK, D;
- wire X, Y, Z;
- parameter CYCLE = 10;
- integer i;
- DFF DFF(CLK, D, X, Y, Z);
- always begin
- CLK = 0; #(CYCLE/2);
- CLK = 1; #(CYCLE/2);
- end
- initial begin
- for(i=0; i<3; i=i+1) begin
- D = 0; #(CYCLE*5);
- D = 1; #(CYCLE*3);
- end
- D = 0; #(CYCLE*3);
- $finish;
- end
- initial begin
- $dumpfile("dff_test.vcd");
- $dumpvars(0, DFF_TEST);
- end
- endmodule
D を印加する部分を for() 文にしてみました。まぁ、これぐらいの処理はべたに書いたほうがよいと思います。ここは、お勉強。
シミュレーション結果
ブロッキング代入
ブロッキング代入では、入力 D にしたがって、全部の出力が変化します。
回路にすると、こんな感じかな。あ、これ論理合成とかじゃなくて、自分で考えただけだから、間違ってるかも。
ノンブロッキング代入
ノンブロッキング代入では、クロックにしたがって一斉に信号が動くので、出力がシフトレジスタのようになります。
シフトレジスタだから、こんな回路。
D=1、X=0 とすると、クロックが入って回路の遅延時間後に X=1 になる。クロックが入ったときはまだ X=0 なので、2段目の入力は 0。つぎのクロックのときには X=1 になっている。
シフトレジスタの動作のしくみですね。
どちらの代入を使う?
むずかしいことは言わない。
- 混ぜて使わない
- 組み合わせ回路 (assign) では「=」ブロッキング代入
- 順序回路 (always) では「<=」ノンブロッキング代入
- テストベンチでは「=」ブロッキング代入
それだけを守ってれば、よさそう。