11. 階層構造

11.1 SCOPE

x.y.a とか、ドットでつながった表現を見たことがあると思います。なにを単位としているかというと次の4つのいずかです。

(Verilog2001 generate を後で説明しますが、Named blockの扱いになります。)

Modules
Tasks
Functions
Named blocks


階層アクセスするには、名前がついていないといけません。これらは、言語仕様で皆、名前がついています。(名前のないモジュールや、タスク、ファンクションはありませんね。) begin end も次のようにすれば、名前付になります。これをNamed Blockといいます。

これを、VeritakのSCOPE TREE VIEWで見ると下のようになります。



今回は、モジュールの中の階層アクセスでしたが、モジュール階層をまたいでも、同様です。
ところで、識別子の探索は、どのように行われるでしょうか?本例の場合、WIDTHと、bは、複数の階層にあります。
アルゴリズムは、

という具合になっています。実は、シミュレータの中の管理単位は、SCOPEになっています。SCOPEは、インスタンス化された後のUnique表現(ただひとつしか存在しない)です。インスタンス化されるとモジュールは、複数の実体を持ちえます。それは、複数のSCOPEになっているということです。ハードウェアは、究極のオブジェクト指向になっているということなんですね。

11.2 generate
 generateは、Altera,Xilinx共に合成でのサポートはされていないようです。FPGA関係もいずれ合成サポートはされると思います。

 genvarは、genarate用の特別インデックス変数です。0以上の整数として使い、ZX、負数はエラーです。generateの外、内にあってもいいのですが、module内にないといけません。また、SCOPEの概念を持たない(SCOPE生成前なので)で階層表現は、無効です。


実行結果です。


上記は、generate forの例です。genvar宣言 iは、for loopのインデックスとしての意味を持ちます。
このときSCOPEが生成されることに注意してください。SCOPEが生成されるためには、名前が必要です。なので、begin:名前 が必ずつきます。
一番目のLOOPは、

assign bin[0]=^gray[11:0];
assign bin[1]=^gray[11:1];
assign bin[2]=^gray[11:2];
assign bin[3]=^gray[11:3];
.......
assign bin[11]=^gray[11:11];

と等価です。こう書いてもいいのですが、同じようなことをずらずらと書きたくない!という人はgenerateを使うといいでしょう。
2番めも同じですね

always @* bin[0]=^gray[11:0];
always @* bin[1]=^gray[11:1];
always @* bin[2]=^gray[11:2];
always @* bin[3]=^gray[11:3];
........
always @* bin[11]=^gray[11:11];

実際、シミュレータのなかでは、上記のように展開しています。このとき、genvarは、消えています。genvarは、展開するためのインデックスに過ぎないということです。
次の例は、リップルアダーです。任意ビットの加算器がコンパクトに書ける、という例です。ただし、こういうのを書くのは、ライブラリ担当者だけでしょう。設計資産として保存するには、パラメタライズできることが必要です。そういう面では重宝するかもしれません。


実行結果です。



もし、dut1のfor loopが

だと、t1,t2,t3は、内側ループですから、bit SCOPEの下に信号が配置され
bit[0]、bit[1]、、bit[7] SCOPEの下に信号t1,t2,t3が来ます。


次は、最初の例のdut1をさらに for loopでインスタンス化した例です。

このSCOPEは、

になります。
次の例は、for loopのNestingです。

このSCOPEは、

になります。



次は、generate if else の例です。Verilog2001LRMでは、generate if は、のスコープの取り扱いに不明確な点があります。Veritakでは、3.23Eから、IEEE1800-2005仕様に変更しています。
 次例で見ていきましょう。generate if 文の最初の方はラベルが書いてありません。一方else文の方にはラベルが書いてあります。IEEE1800-2005の仕様では、generate 構文でラベルがないものは、コンパイラが生成する内部ラベルを使うことになっています。当然、Vendor間では内部ラベルは変わります。(また、Xilinxのツールでは、ラベルがないと単純にエラーとしているようです。) 



if文を生かすインスタンス化では、

        select 
                #(.WIDTH(WIDTH),.inv_type(0))
                         dut(.d0(d0),.d1(d1),.dout(dout));

次のように内部ラベル(Implicit Scope0 これはVeritakUniqueな名前です)が生成されます。


一方else文を生かすインスタンス化では、

select 
                #(.WIDTH(WIDTH),.inv_type(1))
                         dut(.d0(d0),.d1(d1),.dout(dout));

このときのSCOPEは、


となります。このような仕様の変更があったので、regで書くところをwireで置き換える、あるいは、別なtaskやfunctionを呼ぶ、みたいなことは出来なくなりました。

また、Verilog2001では、generate if文のラベルはあってもなくてもよいのですが、for文ではLRM上必須です。
しかしIEEE1800-2005では、これもなくてもよいことになっています。ラベルがない場合は、必ず暗黙ラベルがついてしまう(VCD出力とか、Vendor依存になってしまう)ので、ラベルを明示しておいた方がよいでしょう。

次の例は、generate if文とfor文を駆使したパイプラインレジスタの例です。幅と深さをインスタンス化の際に自由に指定できますので、強力にライブラリ化を促進します。
generate は、知的な「条件コンパイル」です。色々書いてあっても、実行時もしくは論理合成時に残るのは、アクティブにされる記述だけです。


下のScope Viewで、一番目のレジスタのスコープがif_label, 2番目以降のスコープがelse_labelになっているのが分かります。




task や、functionもgenerate下に置けますが、for loopの下には置けません。

それからgenerate case というのもあります。これも想像される通りですが、ここで、注意するべきは、generate が評価されるときに定数でなくてはいけないということです。parameter はオーバライドがありますが、オーバライド後の値で評価されます。


verilog のgenerateは、VHDLのそれより強力になってしまいました。使い方は難しいと思いますし、使わないと書けないというものでもありません。どちらかというとライブラリ向きだと思います。

11.3 ANSI スタイルポートリスト
 2001になって、ANSI−Cスタイルのリストが可能になりました。
下は、色々なスタイルで、書いてみたものです。
パラメータの名前による結合が可能になった他、ポートリスト中にポートタイプが入れられるようになりました。
これによって、短く書けますのでお勧めです。ただし、1995スタイル、2001スタイルは統一して使うようにしましょう。


テストベンチ用途では、初期化付きも可能なので、さらに短く書けます。勿論これは、reg等のvariable typeのみに限定されます。

ANSI Cスタイルと呼ぶのなぜ?
昔C言語が出始めの頃(K&Rの時代)、C言語のポートリストスタイルは、Verilog1995みたいに別々に書く感じでした。その後ANSIでC言語の標準化の際に、今のC言語スタイルになったのです。Verilog言語が設計された当時は、まだK&Rの時代だったのです。