VerilogHDLが実行される順序

[] [] []


理合成と違ってシミュレーションには文を実行する順序があるので、最初にこれを説明する。特に注意しなければならないのは、並行に実行される文同士でどちらが先に実行されるかによって結果が変わってしまう(レーシングracingという)書き方を絶対にしないことである。もしレーシングが起きる記述が内在していると、シミュレータを変更したり、文の順序を入れ替えたときに、シミュレーション結果が合わなくなる恐れがある。

Verilogのモジュールの中は、かならずinitialalwaysで始まる複数の文をくくったブロック(または1個の文)で書かれている。その実行順序の規則は次のとおりである。

(1) 普通のシミュレータはモジュールの先頭から順に実行するが、initialalwaysのブロック同士の実行順序は言語仕様上不確定である。(つまり並列に実行されるイメージ)

(2) initialブロックは1回だけ、alwaysブロックは無限に繰り返し実行される

(3) ブロックはbegin-endでくくられ、この中の文は上から順に実行する(fork-joinでくくるブロックもあるが、ややこしくなるのでここでは触れない)

(3) 遅延(#)かイベント待ち(@)があると、その条件が成立するまで次の文の実行を保留する

  例) #(10) ;  10単位時間後に文を実行する。 @(posedge clk) ; 信号clk0→1に変化したら文を実行する。

(4) 実行する文がなくなるか、または$finishまで来たらそこで終了する

  initial文だけしかなければ$finishがなくても終了するが、alwaysがあるとどこかに$finishを書いておかないと終了しないことに注意。

例えば次の記述は、右の欄にしめす順に実行される

module(input clk);

 

always

    begin

    @(posedge clk)1

    @(posedge clk)2

    end

 

always

    begin

    @(posedge clk)3

    end

 

initial

    begin

    4

    @(posedge clk)5

    @(posedge clk)6

    @(posedge clk)7

    #10 $finish;

    end

 

initial

    begin

  【8

    end

 

endmodule

 

実行順序:

(4】【7)

clk立ち上がりエッジ

(1】【3】【5)

clk立ち上がりエッジ

(2】【3】【6)

clk立ち上がりエッジ

(1】【3】【7)

10単位時間後

終了

注:()内の実行順序は不確定である

例えば、論理合成向けのRTL記述はすべて次のように書いてあるので、シミュレーションではclkの立ち上がり毎に各alwaysbegin-end内が繰り返し実行されることになる

always @(posedge clk)

    begin

    ...

    end

◇◇

initial,alwaysブロック同士の実行順序は不確定と言ったが、他ブロックの変数を自ブロックで代入することはあるので、代入結果がブロック同士の実行順序依存しないようにノンブロッキング代入というものがある。

ブロッキング代入(=)は現在の右辺の値を計算したらすぐ左辺に代入する

ノンブロッキング代入(=>)は、現在の全always,initial文の右辺を計算した後に、左辺に代入する

例えば次の記述で現在a=1,b=2とするとクロック立ち上がり後、ブロッキング代入ではb=ac=bの実行順序に依存してb=1,c=2になるのかb=c=1になるのか不確定だが、ノンブロッキング代入ではb=1,c=2に確定する。

×// ブロッキング代入

always @(posedge clk)

    begin

    b = a;

    end

always @(posedge clk)

    begin

    c = b;

    end

// ノンブロッキング代入

always @(posedge clk)

    begin

    b <= a;

    end

always @(posedge clk)

    begin

    c <= b;

    end


[] [] []