問題
下記サンプルコードのようにuvm_componentの派生クラスの中でNested classを定義したところ、uvm_infoの部分でコンパイルエラーとなってしまったのでその原因と対策を調べてみました。
import uvm_pkg::*;
`include "uvm_macros.svh"
class Outer extends uvm_component;
`uvm_component_utils(Outer)
class Inner;
function void print_message(uvm_component caller);
`uvm_info(caller.get_type_name(), "Test", UVM_MEDIUM)
// `uvm_info_context(caller.get_type_name(), "Test", UVM_MEDIUM, caller)
endfunction
endclass
function new(string name, uvm_component parent);
Inner inner;
super.new(name, parent);
inner = new();
inner.print_message(this);
endfunction
endclass
program top;
initial begin
Outer outer;
outer = Outer::type_id::create("top", null);
end
endprogram
Error-[IRPCM] Illegal reference to parent class method
testbench.sv, 9
"uvm_report_enabled"
The method call resolves to a non-static task/function
'uvm_report_object::uvm_report_enabled' of an ancestor class. Such
references to non-static method are not allowed.
Please declare the method as static.
解決方法
uvm_info()ではなくuvm_info_context()を使いましょう。
上記コードでuvm_info()をコメントアウトし、下の行のuvm_info_context()のコメントアウトを戻すと動作するようになります。
同様にuvm_warning()はuvm_warning_context(),
uvm_error()はuvm_errro_context(), uvm_fatal()にはuvm_fatal_context()でそれぞれ置き換えることができます。
説明
エラーメッセージからも推測できますがuvm_info()のマクロは内部でuvm_report_enabled()を呼んでいます。uvm_componentの派生クラスであれば、親クラスのuvm_report_objectの中で定義されたuvm_report_enabled()が継承されて、結局自分が持っているuvm_report_enabled()が呼ばれることになります。
一方上記のNested classの場合はInnerの中にはuvm_report_enabled()が定義されていないので、この定義を探しに行き、uvm_report_object::uvm_report_enabled()を見つけてしまいます。エラーメッセージの通りこの関数はstaticではありませんのそのまま呼び出すことはできずコンパイルエラーとなります。
uvm_info_context()はuvm_report_object内の関数ではなく、uvm_package内の関数を使用します。こちらはnew()しないでも使用できるのでコンパイルエラーにはなりません。追加の引数としてcontextを渡さなければならないので、本例ではOuterのインスタンスを渡しています。外側のインスタンスを渡すのが難しい場合はuvm_root::get()でルートのインスタンスを渡してしまっても構いません。この場合uvm_componentの階層によるMessage制御が効かなくなるなどの機能の制限があります。
余談ですがuvm_objectやmoduleからuvm_info()を使う場合は(uvm_report_object内で定義されているものではなく)uvm_packageの中で定義されている関数が呼ばれます。このため上記のような問題は起きません。