代入文は、次の3種類があります。Assignment継続代入文の左辺は、下のように制限があります。type6.1手続き代入文BAは、次の2種類があります。;一方NBAも全く同じ記述形式です。;ところが、意味が全然ちがいます。stage2;ところで、2)3)は、次と等価です。2)`ところで、2)`は次と等価です。temp;//代入を実施する。temp;//代入を実施する。stage4;が後に続いているとするとこれらは、Cと同じく順番に代入動作が行われます。シフトレジスタ的な動作をさせようとすると順番を意識して書かなければいけません。4)は、RHS(右辺)の値を求めますが、すぐには、LHS(左辺)には代入されません。RHSを求めた値は、イベントキュ-(NBA専用)に入ります。この後にRHSが変わったとしてもNBAキューで保持している値は不変です。イベントキNBAキュ-は、同時刻イベントでも最後に配置されますので、BAより先に代入がおこることはありません。5)は、RHSの値を求めた後、#10時間後にNBAされます。6)は、RHSの値を求めた後、@(a)イベント後にNBAされます。この動作により記述の順番依存性がなくなります。stage2;と書いても同じシフトレジスタ動作になります。BAでは、まったく違う動作になってしまうのとは対象的です。実用上、FFの記述は、全てNBAを使います。組み合わせ回路をAlwaysで記述するときは、BAを使うと覚えてください。この辺の動作を肌で感じるのは、Veritakで、Step動作させてEditor上で値を表示させてみるとわかります。BAは、代入を実施するとすぐにLHS=RHSとなりますが、NBAは、代入を実施してもLHSは元のLHS値のままです。時刻が変わった後に初めてRHS値が変わったことがわかるでしょう。(実際には、時刻が変わる直前に代入が行われる。)なお、いい忘れましたが、手続き代入文のLHSは、reg型でないといけません。reg型は、reg、real,realtime,integer,timeのどれかで宣言されたtypeです。;綺羅星のごとくoptionが並んでいますが、実際によく使う記述は、次のような記述です。継続代入文では、簡単な組み合わせ回路の記述に使います。こちらのほうは<=はな=しかありません。w1=r1[3:2];なお、継続代入文のLHSは、Net宣言されていないといけません。reg型は、左辺に置けません。手続き型との違いは、regの場合は、最後に代入されている値を記憶するのに対し、Net型は、継続的にドライブされている必要があります。組み合わせ回路しか記述できません。物理的には、”線”の意味に捉えてよいかと思います。w1に実態はありません。あるのは、r1[3:2]への参照です。HW上存在しませんし、シミュレータ上でもメモリを占有していません。a&bという右辺は、アンド回路ロジックという実態を持ちますがLHSはその参照でしかありません。従って特殊な文を除いてNetの値を明示的に設定することはできません。継続的代入文のRHSのすべての信号は、その変化をモニタしています。変化したらすぐに再計算してLHSに値を設定するためです。大部分のVerilogシミュレータの内部インプリメンテーションでは、Netと手続き構文と二つの違うエンジンを持っています。スレッド駆動型エンジン(C言語型)と、NET駆動型テーブルルックアップ方式(従来の回路シミュレータ)による方式です。Veritakもそうなっています。筆者がVerilogを覚えたの2年間、納得できない現象がありました。次のソースを見てください。最初の$displayで、q=1は文句ないところですが、pは0でしょうかそれとも1でしょうか?答えは、全部のVerilogシミュレータで、xになるはずです。q=1になったところで、インバート動作で、0にならないのでしょうか?また、#0の後、どうして0になるのでしょうか?その答えは、同時刻のイベントのキューイングの仕方にあります。前の章で述べた通り、q=1となってもスレッドの実行は継続しています。#0になって初めて、制御が他のイベントの伝播に振り分けられます。伝播イベントより$displayの方が早かったためにこのような現象になります。従って継続代入文のモニタをするときは、注意が必要です。ところで、最後の$strobeではどうなるでしょうか?答えは、1になる筈です。いうのは、q<=0が効いて、同時刻の終わりでq=0となり、そのイベントが伝わってp=1になります。$strobeは、NBAよりも後のもう同時刻のイベントがなくなって次の時刻に行こうとする直前の最終値をモニタするのがVerilogの仕様ですので同時刻の最終値であるp=1が得られたという訳です。同時刻のキューイングはこのように複雑ですので、別項でもう一度整理してみたいと思います。DelayVerilogでは、様々な、Delayの指定形態がありますので、ここでまとめて見てみたいと思います。下記はサンプルソースからです。alwaysの中から見ていきましょう。#10;ba1=a+b;に分解されます。(Always/Initial中、左側にDelayがあるのは、全部、この形に分解できます。)#10単位時間経つまでba1=a+b;は、実行されません。従って、Alwaysの頭に戻るのは、#10単位時間たった後です。その間に、a,b信号に変化があったとしても、@待ちにはなっていないので、検出されません。a+b;は、temp=a+b;#10;ba2=temp;に分解されます。@(a,b)で、変化があったら、その内容をtempに一旦Saveされますが、#10単位時間待てになりますので、次の文には#10単位時間進みません。従って、この間@(a,b)のところに進めないので、入力変化を検出することができないのは、上と同じです。a+b;は、a+bを即評価します。評価した値をa+b=>cとでもしておきましょう。cの値は、#10単位時間後に、nb1<=c;とするイベントをイベントキューに貯めこみます。LHSの評価は、即行われますが、代入予約だけが、現在時間に行われ、次の文に休むことなく進みます。次の文は、@(a,b)なので、ここでまた、a,bの変化を検出するまで待て、になり、別のスレッドの実行に移ります。従って、a,bの検出変化出来ない期間は、なかったことに注意してください。上の二つが#10単位時間、変化を検出できないのとは対称的です。このことは、a,bの全ての変化は、#10単位時間遅れることを意味します。Lineと同じ動作となります。Delayと呼んでいます。Delay)があります。Delayは、オプションです。)慣性遅延は、ロジックででるハザードなどを無視させるのに実際的に用いられます。これを、Verilogでは、Wire構文で実現できます。変化してから#10単位時間後にcwにその結果が現れることを意味しています。言葉ですと、なかなかイメージがつかみにくいので、実際にシミュレータで、様子を確認してみるのがよいでしょう。Delayとは別物です。Delayになります。イナーシャディレイになります。そのほかにゲートのディレイ構文もあります。ブロックされずに実行順にキューイングされる。a<=temp_c;の動作となる。時間、bw=>#(8+7)時間の遅延時間になります。endmoduleイベントの始まりはなんでしょうか?手続き構文代入文がトリガとなります。構文の再計算をTriggerします。//illegalendと同じことです。これは、別プロセスと考えることもできます。イベント制御文や、時間制御文に出会わないと、そのプロセス(スレッド)は継続されました。従って、$dispalyが、wireの値を即反映しなかったことも説明ができます。シミュレータの視点からも、動作的にもその方が高速です。Veritakの初期Versionは、変化を受けて、即再計算していました。a=1,b=1..というように、変化があったぞ!と、Triggerをかけておいて、別プロセスで、変化が落ち着いた後、まとめて再計算をしてほうが高速なことは、明らかです。(特に算術演算系)従って、一部のシミュレータを除いて、後者のアルゴリズムになっています。これらのイベントは、全て、下図の一番上のActiveイベントになります。Activeイベント内の実行順序は、実装依存になっています。「wire計算即行う/後で行う」のどちらでもよいことになります。Eventつまり#0に行きます。Eventの最後に行われます。Eventに戻ることに注意してください。Sutherland氏の記述指針を見ると#0の記述は、お勧めしていません。(とりあえず、スレッドの順番をSKIPする意味はあるのですが、状況を複雑にするだけなので、意味がないということなのでしょう。)大事なことは、<=は、その後に実行されることです。すべてのActiveイベントが尽きた後に予約された、(スケジュールされた)<=が実行されます。全ての予約イベントが実行された後、、またActiveイベントが生まれれば、また、一番上から実行されます。イベントがなければ、さらに下に行き、$monitor、や、$strobeが実行されます。このとき、もう上に戻る事はありません。同時刻の最終確定値が得られる訳です。VeritakのWaveformViewは、この最終値を表示しています。