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ではこの仕様が「普通に」許されています。
階層参照の解決ルール
参照は以下の順で解決されます:
-
現在のモジュール 内で探す
- 例:
instance.signal
- 例:
-
親モジュール に遡って探す
- 兄弟モジュールのインスタンスも参照できる
-
さらに上位モジュール まで再帰的に探索
コード例
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