Verilog階層参照スコープのマスター:モジュールとブロックでの名前衝突回避
ほとんどのプログラミング言語には、コードの特定セクションが変数やメソッドにどの程度見えるかを定義するスコープという特徴的な機能があります。スコープは、同じ名前空間内の異なるオブジェクト名間の衝突を避けるための名前空間を定義します。
Verilogは、モジュール、関数、タスク、名前付きブロック、generateブロックに新しいスコープを定義します。
module tb;
reg signal;
// 同じスコープ内で既存の名前で
// 別の変数を宣言することはできない
reg signal; // エラー
// しかし、'signal'という名前は
// 異なるスコープに属するタスク内で再利用可能
task display();
reg signal = 1;
$display("signal = %0b", signal);
endtask
endmodule
識別子(信号名など)は、与えられたスコープ内で1種類のアイテムのみを宣言するために使用できます。つまり、同じスコープ内で異なるまたは同じデータ型の2つの変数が同じ名前を持つことはできず、タスクと変数が同じ名前を持つことも、ネットとゲートインスタンスが同じ名前を持つこともできません。
Verilogのすべての識別子には一意の階層パス名があり、各モジュールインスタンス、タスク、関数、名前付きbegin endまたはfork joinブロックが新しいレベルまたはスコープを定義します。
階層参照の例
module tb;
// 異なるモジュールの2つのインスタンスを作成
A uA();
B uB();
// 信号を宣言し、シミュレーション開始から10nsで
// 値を表示する名前付きブロックを作成
initial begin : TB_INITIAL
reg signal;
#10 $display("signal=%0d", signal);
end
// このinitialブロックから階層参照を使って
// 他のスコープにアクセスしてみる
initial begin
TB_INITIAL.signal = 0;
uA.display();
uB.B_INITIAL.B_INITIAL_BLOCK1.b_signal_1 = 1;
uB.B_INITIAL.B_INITIAL_BLOCK2.b_signal_2 = 0;
end
endmodule
module A;
task display();
$display("Hello, this is A");
endtask
endmodule
module B;
initial begin : B_INITIAL
#50;
begin : B_INITIAL_BLOCK1
reg b_signal_1;
#10 $display("signal_1=%0d", b_signal_1);
end
#50;
begin : B_INITIAL_BLOCK2
reg b_signal_2;
#10 $display("signal_2=%0d", b_signal_2);
end
end
endmodule
xcelium> run Hello, this is A TB signal=0 signal_1=1 signal_2=0 xmsim: *W,RNQUIE: Simulation is complete.
上方向名前参照
下位のモジュールは、階層でその上にあるモジュールのアイテムを参照できます。例えば、TB_INITIALブロックのsignalは、モジュールAのdisplayタスクから見えます。
module A;
task display();
$display("Hello, this is A");
// 上方向参照、TB_INITIALはこのモジュールから見える
#5 TB_INITIAL.signal = 1;
endtask
endmodule
モジュールAによる上方向参照での変更により、TB signalが0ではなく1になります。
xcelium> run Hello, this is A TB signal=1 signal_1=1 signal_2=0 xmsim: *W,RNQUIE: Simulation is complete.
複数のネストされたモジュールを持つ別の例では、リーフノードが上方向階層参照を通じて上位ノードのメンバに直接アクセスできます。
module tb;
A a();
function display();
$display("Hello, this is TB");
endfunction
endmodule
module A;
B b();
function display();
$display("Hello, this is A");
endfunction
endmodule
module B;
C c();
function display();
$display("Hello, this is B");
endfunction
endmodule
module C;
D d();
function display();
$display("Hello, this is C");
endfunction
endmodule
module D;
initial begin
a.display(); // または A.display()
b.display(); // または B.display()
c.display(); // または C.display()
a.b.c.display();
end
endmodule
xcelium> run Hello, this is A Hello, this is B Hello, this is C Hello, this is C xmsim: *W,RNQUIE: Simulation is complete.
コンパイラがb.display()を見つけると、
- 現在のスコープ(モジュールD内)でbが定義されているか確認。存在しない場合、囲むスコープで名前を探し、モジュールスコープに達するまで上方向に移動。それでも見つからない場合、次のステップへ。
- 親モジュールの最外側スコープで探し、見つからなければ階層をさらに上に遡る。
Verilog
- Verilogマスター:デジタル回路設計のための完全チュートリアル
- Verilog連結マスター:実践ガイド
- Verilogエッセンシャル:簡潔な概要
- Verilog代入文の理解:種類、構文、ベストプラクティス
- Verilogブロッキング代入とノンブロッキング代入:違いを徹底解説
- Verilog関数のマスター:効率的なRTL設計のために
- Verilogタスクの理解:関数との違い、構文、使用法
- Verilog階層参照スコープのマスター:モジュールとブロックでの名前衝突回避
- Verilogクロックジェネレータ:設計と実装ガイド
- Verilog表示タスクのマスター:効率的なデバッグとログ出力
- Verilog数学関数のマスター:効率的なハードウェア設計のために