Verilog ノンブロッキング代入の検証 test of non-blocking assignment

ノンブロッキング代入の変数代入のタイミングを検証するため、簡単なコードを書いて検証した。



昨夏、ブログを始めて以来、珍しく研究に関する記事だ。

ノンブロッキング代入


問題

non_blocking.v 中の

hoge <= {ck, vari}

に入るvariは、一つ前の行の右辺のvariなのか、左辺のvariなのかを確認した。
下記の二つのファイルを作ってみた。下のファイルはシミュレーション用だ。

ソースコード

**** non_blocking.v
`timescale 1ns / 1ps
module non_blocking(
    input            ck,
    output reg       vari, // Not declaring a width is interpreted as a bit.
    output reg [1:0] hoge
    );
    initial vari <= 0;
    always @(posedge ck) begin
        vari <= ~vari;
        hoge <= {ck, vari};
    end    
endmodule


**** non_blocking_tp.v


`timescale 1ns / 1ps
module non_blocking_tp;
    reg ck;
    wire vari;
    wire [1:0] hoge;
    parameter STEP = 100; // 100nsec
 
    non_blocking non_blocking(ck, vari, hoge);
    initial begin
        ck = 0;
        forever #(STEP/2) ck = ~ck;
    end
 
    initial $monitor($stime, "ck=%b, var = %b, hoge=%b", ck, vari, hoge);

endmodule


non_blocking.v 中の

        vari <= ~vari;
        hoge <= {ck, vari};

で、hogeの1bit目に入るものが、vari <= ~vari の左辺のvariなのか、右辺のvariなのかを確認した。ちなみに、hogeの2bit目にはck (クロック) を入れてある。クロックの立ち上がり時にhoge[1] = ckが処理されるはずであるが、ckの立ち上がり時というのが、立ち上がる直前か、直後なのかよくわからなかったためだ。説明によくある、クロックの立ち上がり同時のクロックの値というのは、正直よくわからなかった。それでは、ステップ関数のx=0での値を聞かれているみたいだった。

シミュレーション結果


Vivado Simulator 2014.1
Time resolution is 1 ps
         0ck=0, var = 0, hoge=xx
        50ck=1, var = 1, hoge=10
       100ck=0, var = 1, hoge=10
       150ck=1, var = 0, hoge=11
       200ck=0, var = 0, hoge=11
       250ck=1, var = 1, hoge=10
       300ck=0, var = 1, hoge=10
       350ck=1, var = 0, hoge=11
       400ck=0, var = 0, hoge=11
       450ck=1, var = 1, hoge=10
       500ck=0, var = 1, hoge=10
       550ck=1, var = 0, hoge=11
       600ck=0, var = 0, hoge=11
       650ck=1, var = 1, hoge=10
       700ck=0, var = 1, hoge=10
       750ck=1, var = 0, hoge=11
       800ck=0, var = 0, hoge=11
       850ck=1, var = 1, hoge=10
       900ck=0, var = 1, hoge=10
       950ck=1, var = 0, hoge=11
      1000ck=0, var = 0, hoge=11
xsim: Time (s): cpu = 00:00:05 ; elapsed = 00:00:07 . Memory (MB): peak = 1135.855 ; gain = 0.000
INFO: [Vivado 12-1395] XSim completed. Design snapshot 'non_blocking_tp_behav' loaded.
launch_xsim: Time (s): cpu = 00:00:06 ; elapsed = 00:00:09 . Memory (MB): peak = 1135.855 ; gain = 0.000




図を見るとわかるように、vari と hogeが逆位相になっている。これは、hogeに代入されたvarは、

vari <= ~vari

の右辺のvariだったことがわかる。また、 non_blocking.v 中で vari をinitialとノンブロッキング代入で、 non_blocking_tp.v 中で ckをinitial とブロッキング代入によって初期化していることに注意。

クロックについては、hoge[1]がひたすら1であることからわかるように、クロックの立ち上がり posedge から無限微小時間δ秒後に hoge[1] <= ck が代入されていると思った方がいいらしい。

wireとreg、ブロッキング代入とノンブロッキング代入の使い分け

この使い分けが難しい。variとhogeはnon_blocking.vではregだが、一方でnon_blocking_tp.vではwireとして扱われている。初期化もvariはノンブロッキング代入で、ckはブロッキング代入だ。これは、ckの方がbegin endで挟まれているからだろうと推察される。また、assignを使うタイミングもよくわからない。

小林優『入門Verilog HDL記述』, CQ出版社, P.124には次の説明がある。


ブロッキング代入は通常の逐次処理で、ノンブロッキング代入では、まず右辺を全て処理してから左辺の処理に入るらしい。

コメント

人気の投稿