Verilog posedgeとノンブロッキングの代入タイミング

Verilogコードでは、ある時刻tにおいて変数xが変化するとき、時刻tでの処理に使われるxが時刻t-δか、t+δか、どちらを想定したものなのか混乱が生じやすい。そのためにノンブロッキング代入があるらしいが。今回、その点について検証した。

次の二点がわかった。
1. @(posedge ck) ブロックではckは1であること
2. (@posedge ck)ブロック内にck2 <= ~ckがあっても、他の処理に使うck2はまだ代入前であること

つまり、@(posedge ck)ブロック中ではckのみ1への移行が済んでおり、他のものはまだckの立ち上がり前の値だ。

以下に検証を記した。



1. について


always @(posedge ck) begin
    if(ck) begin
        //do something
    end
end


このコードだと、if(ck)は常に1を返す

2の場合

ck2にノンブロッキング代入をしておく。

clk_test.v


module clk_test(
    output reg y
    );
    reg clk;
    reg clk2;
    
    initial begin
    clk = 0;
    forever #25 clk = ~clk;
    end
    
    always @(posedge clk) begin
        clk2 <= ~clk;
    end
    
    always @(posedge clk) begin
        y <= clk2 ? 1'b1 : 1'b0;
    end
    
endmodule

clk_test_tp.v

module clk_test_tp;
    wire y;
    clk_test clk_test(y);
    initial $monitor($stime, "y=%b", y);
endmodule



clkの立ち上がるたびに

clk2 <= ~ clk
if(clk2)

という代入と判定の2つが起こっている。ノンブロッキング代入では、最初に右辺を評価していき、最後に行われるのでif(clk2)の中のclk2はまだ~clkが代入されていない。

見ての通り、yは0を返している。

ck周期は50nsecです。

時刻 0 nsec
ckが0になる
ck2はまだ不定

時刻 25nsec
ckが立ち上がり1になる
ck2は、不定であったが、この立ち上がり時に、~clkが評価される。
if'(clk2)はまだ不定のままなのでyには値が入らない
そして、clk2 <= ~clkのノンブロッキング代入が終わり、clk2には1が入る。

時刻 50nsec
ckが立ち下がる。clk2とyは1と不定値のまま

時刻 75nsec
ckが二度目の立ち上がり。
clk2の右辺の~clk (~0 すなわち 1)が評価される。
if(clk2)が通過しyに1が入る
clk2のノンブロッキング代入が終わり、clk2に引き続き1が入る。

補足

2のclk_test.v中で、clk2の代入をブロッキング代入にすると、つまり
clk2 = ~clk;
とすると、この代入は評価時に実行される。なので、@(posedge clk)ブロック中のif(clk2)のclk2は既に~clkが実行された値が入る。



そして、clk2 <= ^clkのノンブロッキング代入はそのままにし、yをブロッキング代入
y = clk2 ? 1'b1: 1'b0:
にすると

やはり、clk2への代入より、こちらが先に行われている。





結論

@(posedge ck)ブロックではckのみ1への代入が終わっており、他のノンブロッキング代入はは全てひとしく未処理である。

この記事もおかしいところがあるかもしれないので、気付いた方は指摘願いたい。

コメント

人気の投稿