🧐

Verilogにおける階層参照まとめ

に公開

Verilogにおける階層参照は柔軟ですが、その自由度ゆえに構文解析を難しくする要素にもなっています。特に 上位参照 (Upwards Name Reference) が許されている点は、Verilog独自の特徴です。

Verilogの名前空間は「論理的にはツリー構造を持っているが、実質的にはどこからでも参照可能な巨大グローバル空間」として動作しています。この柔軟な階層参照機構により、Verilogでは任意の階層からオブジェクトにアクセス可能になりますが、一方で可読性や保守性を損なう場合もあるため、利用には注意が必要です。

また、これはテスト/Behavior記述には使えますが、通常は合成はできない記述であることにもご注意ください。


モジュールのインスタンス階層構造

Verilog HDLは「モジュール」を基本単位として設計されます。モジュールは他のモジュールをインスタンス化でき、これにより階層的な構造を形成します。

ソースに書かれていても他からインスタンス化されないモジュールは トップレベルモジュール となります。トップは複数存在でき、結果的に複数の階層ツリーが形成される場合もあります。

コード例

module top1;
    module_a instance_a();  // module_aをインスタンス化
endmodule

module top2;
    module_b instance_b();  // module_bをインスタンス化
endmodule

module module_a;
    module_c instance_c();  // module_cをさらに下位に
endmodule

module module_b;
    module_c instance_c0();
    module_c instance_c1();
endmodule

module module_c;
endmodule

階層図


インスタンス階層名と名前空間

Verilogでは、階層をピリオド(.)でつないだ インスタンス階層名 によって、階層内のオブジェクトを一意に参照できます。

  • モジュール
  • タスク / 関数
  • 名前付きブロック (begin-end, fork-join)

これらはそれぞれ新しい 名前空間 (name space) を導入します。

コード例:階層名参照

module top;
    sub u1();
    initial begin
        // 下位モジュール(u1)の変数aを参照
        $display("a = %b", u1.a);
    end
endmodule

module sub;
    reg a;
endmodule

各識別子は階層パスを持つ

Verilogのすべての識別子は「一意の階層パス」を持ちます。これは、モジュール・タスク・関数・名前付きブロックなどが形成するツリー構造によって定義されます。

コード例:名前付きブロック

module top;
    initial begin : init_block
        integer i;
        $display("This block name is %m"); // %m で現在の階層パスを表示
    end
endmodule

実行時、top.init_block のように完全な階層名が確認できます。


Generateによる識別子

generate 文を使うと、ループ展開されたブロックやインスタンスも階層名に含まれます。

コード例

module top;
    genvar i;
    generate
        for (i = 0; i < 2; i = i + 1) begin : gen_block
            sub u();
        end
    endgenerate
endmodule

module sub;
endmodule

この場合のインスタンス階層名は以下のようになります:

  • top.gen_block[0].u
  • top.gen_block[1].u

上位参照 (Upwards Name Referencing)

Verilogの特徴として、下位モジュールから上位モジュールの変数や要素にアクセスできます。

コード例

module top;
    reg clk;
    sub u1();
endmodule

module sub;
    always @(posedge top.clk) begin
        $display("posedge clk detected");
    end
endmodule

このように、sub モジュールから top.clk を直接参照できます。
ソフトウェア言語では名前空間の上方参照は禁止されているのが一般的で、スコープ境界は強いカプセル化の壁となることが多いですが、Verilogではこの仕様が「普通に」許されています。


階層参照の解決ルール

参照は以下の順で解決されます:

  1. 現在のモジュール 内で探す

    • 例: instance.signal
  2. 親モジュール に遡って探す

    • 兄弟モジュールのインスタンスも参照できる
  3. さらに上位モジュール まで再帰的に探索

コード例

module top;
    reg top_var = 1'b0;

    // 下位モジュールを2つインスタンス
    child c1();
    child c2();

    // 上位にタスクと関数を定義
    task top_task;
        $display("%m: called top_task");
    endtask

    function int top_func;
        top_func = 42;
    endfunction
endmodule


module child;
    reg local_var = 1'b0;

    // 子モジュールにもタスクと関数を定義
    task local_task;
        $display("%m: called local_task");
    endtask

    function int local_func;
        local_func = 99;
    endfunction

    initial begin : init_block
        // 1. 下位参照(自分の中)
        $display("%m: local_var = %b", local_var);
        local_task();
        $display("%m: local_func() = %0d", local_func());

        // 2. 上位参照(親モジュール top の変数・タスク・関数)
        $display("%m: top_var = %b", top.top_var);
        top.top_task();
        $display("%m: top_func() = %0d", top.top_func());

        // 3. 兄弟参照(同じ親の別インスタンスの変数・タスク・関数)
        $display("%m: brother's local_var = %b", top.c2.local_var);
        top.c2.local_task();
        $display("%m: brother's local_func() = %0d", top.c2.local_func());
    end
endmodule

まとめ

  • Verilogではモジュール階層ごとに インスタンス階層名 を持つ
  • generate や名前付きブロックも階層パスに含まれる
  • 上位参照 (Upwards Name Referencing) により、下位から上位モジュールの要素を参照できる

この柔軟な機構は強力である一方で、設計の複雑化やデバッグの困難さを招く可能性があるため、利用には慎重な検討が必要です。

Discussion