UVMの`uvm_info等のメッセージ出力マクロは、特に何も指定しなくてもそれを実行したファイル名と行番号、シミュレーション時間などが表示されて便利なのですが、個人的には以下のような不満点があります。
- ファイル名がフルパスで表示されるので、メッセージの一行がとても長くなり見づらい
- 出力メッセージの縦方向のインデントを揃えようと思ってもソースコードの行番号と時刻の文字幅が変わってしまうために揃わない
例えば以下のような感じです。
UVM_INFO proj_dir/test_dir/testbench.sv(68) @ 0.000 ns: uvm_test_top [my_test_c] First
UVM_INFO proj_dir/test_dir/testbench.sv(70) @ 10.000 ns: uvm_test_top [my_test_c] Second
UVM_INFO proj_dir/test_dir/testbench.sv(120) @ 10.000 ns: uvm_test_top [my_test_c] Third
UVMにはメッセージ出力のフォーマットを変更する仕組みがありますので、これを利用して以下のような表示にしてみたいと思います。
UVM_INFO testbench.sv( 68) @ 0.000 ns: uvm_test_top [my_test_c] First
UVM_INFO testbench.sv( 70) @ 10.000 ns: uvm_test_top [my_test_c] Second
UVM_INFO testbench.sv( 120) @ 10.000 ns: uvm_test_top [my_test_c] Third
手順
- UVM 1.1dの場合はuvm_report_serverをextendsして、1.2の場合はuvm_default_report_serverをextendsして派生クラスを作る。このクラスでcompose_messageというfunctionをオーバーライドする。これが出力メッセージの文字列を生成するfunctionとなる
- 上記で作成したクラスをnew()したのちuvm_report_server::set_server(my_report_server_c)で使用するように設定する
compose_messageの中身は、UVMのソースコードの該当部分をコピーしてきて、必要な部分を書き換えるのがよいでしょう。
今回の目的の場合、ポイントは以下の通り。
- compose_message内で取得できるファイル名はフルパスです。自分でここからディレクトリ名を削除した文字列を取り出す必要があります
- ソースコードの行番号を固定幅にします。フォーマット指定子の"%4d"で最小幅を4文字に指定できます
- UVMの時間の縦方向が揃わないのは、オリジナルのUVMコードで時間を文字列に変換する時に%0tを使用しているせいです。これを%tに変更すれば揃うようになります。なお%tでの出力フォーマットは$timeformatで決まります。これについては時間表示のフォーマッティングで説明しています。
さて、実際のコードを紹介します。上記の手順は同じなのですが、実際のコードはUVM 1.1dと1.2でかなり異なりますので、別々に紹介します。
UVM 1.1dの場合
import uvm_pkg::*;
`include "uvm_macros.svh"
class my_report_server_c extends uvm_report_server;
static function string get_filename_wo_directory(string fullname);
const byte delimiter = "/";
string stripped_name;
stripped_name = fullname;
for (int i = fullname.len() - 1; i >= 0; i--) begin
if (fullname[i] == delimiter) begin
stripped_name = fullname.substr(i + 1, fullname.len() - 1);
break;
end
end
return stripped_name;
endfunction
virtual function string compose_message(uvm_severity severity,
string name,
string id,
string message,
string filename,
int line);
uvm_severity_type sv;
string time_str;
string line_str;
sv = uvm_severity_type'(severity);
$swrite(time_str, "%t", $realtime);
filename = get_filename_wo_directory(filename);
$swrite(line_str, "%4d", line);
return {sv.name(), " ", filename, "(", line_str, ")", " @ ", time_str, ": ", name, " [", id, "] ", message};
endfunction
endclass
class my_test_c extends uvm_test;
`uvm_component_utils(my_test_c)
function new(string name, uvm_component parent);
my_report_server_c my_report_server;
super.new(name, parent);
my_report_server = new();
uvm_report_server::set_server(my_report_server);
endfunction
virtual task run_phase(uvm_phase phase);
phase.raise_objection(this);
repeat (3) begin
`uvm_info(get_type_name(), "Bra", UVM_NONE)
#30ns ;
`uvm_info(get_type_name(), "Bra Bra", UVM_NONE)
#30ns ;
end
phase.drop_objection(this);
endtask
endclass
module top();
initial begin
$timeformat(-9, 3, " ns", 12);
run_test("my_test_c");
end
endmodule
EDA playgroundのこちらにサンプルコードがあります。
ただしEDA playgroundではシミュレーションのファイルがルートディレクトリに配置されるイメージになっているため、ファイル名表示をフルパスからファイル名だけに変更する効果を見ることができません。
UVM 1.2の場合
import uvm_pkg::*;
`include "uvm_macros.svh"
class my_report_server_c extends uvm_default_report_server;
static function string get_filename_wo_directory(string fullname);
const byte delimiter = "/";
string stripped_name;
stripped_name = fullname;
for (int i = fullname.len() - 1; i >= 0; i--) begin
if (fullname[i] == delimiter) begin
stripped_name = fullname.substr(i + 1, fullname.len() - 1);
break;
end
end
return stripped_name;
endfunction
virtual function string compose_report_message(uvm_report_message report_message,
string report_object_name = "");
string sev_string;
uvm_severity l_severity;
uvm_verbosity l_verbosity;
string filename_line_string;
string time_str;
// string line_str;
string context_str;
string verbosity_str;
string terminator_str;
string msg_body_str;
uvm_report_message_element_container el_container;
string prefix;
uvm_report_handler l_report_handler;
l_severity = report_message.get_severity();
sev_string = l_severity.name();
$swrite(filename_line_string, "%s(%4d)", get_filename_wo_directory(report_message.get_filename()), report_message.get_line());
$swrite(time_str, "%t", $time);
if (report_message.get_context() != "")
context_str = {"@@", report_message.get_context()};
if (show_verbosity) begin
if ($cast(l_verbosity, report_message.get_verbosity()))
verbosity_str = l_verbosity.name();
else
verbosity_str.itoa(report_message.get_verbosity());
verbosity_str = {"(", verbosity_str, ")"};
end
if (show_terminator)
terminator_str = {" -",sev_string};
el_container = report_message.get_element_container();
if (el_container.size() == 0)
msg_body_str = report_message.get_message();
else begin
prefix = uvm_default_printer.knobs.prefix;
uvm_default_printer.knobs.prefix = " +";
msg_body_str = {report_message.get_message(), "\n", el_container.sprint()};
uvm_default_printer.knobs.prefix = prefix;
end
if (report_object_name == "") begin
l_report_handler = report_message.get_report_handler();
report_object_name = l_report_handler.get_full_name();
end
compose_report_message = {sev_string, verbosity_str, " ", filename_line_string, "@ ",
time_str, ": ", report_object_name, context_str,
" [", report_message.get_id(), "] ", msg_body_str, terminator_str};
endfunction
endclass
class my_test_c extends uvm_test;
`uvm_component_utils(my_test_c)
function new(string name, uvm_component parent);
my_report_server_c my_report_server;
super.new(name, parent);
my_report_server = new();
uvm_report_server::set_server(my_report_server);
endfunction
virtual task run_phase(uvm_phase phase);
phase.raise_objection(this);
repeat (3) begin
`uvm_info(get_type_name(), "Bra", UVM_NONE)
#30ns ;
`uvm_info(get_type_name(), "Bra Bra", UVM_NONE)
#30ns ;
end
phase.drop_objection(this);
endtask
endclass
module top();
initial begin
$timeformat(-9, 3, " ns", 12);
run_test("my_test_c");
end
endmodule
EDA playgroundのこちらにサンプルコードがあります。
ただしEDA playgroundではシミュレーションのファイルがルートディレクトリに配置されるイメージになっているため、ファイル名表示をフルパスからファイル名だけに変更する効果を見ることができません。
参考文献
Accellera, "6.4 UVM Report Server", [Universal Verification Methodology (UVM) 1.2 Class Reference]
(https://www.accellera.org/images/downloads/standards/uvm/UVM_Class_Reference_Manual_1.2.pdf), pp.70-80.
Accellera, "6.3 UVM Report Server", [Universal Verification Methodology (UVM) 1.1 Class Reference]
(https://www.accellera.org/images/downloads/standards/uvm/UVM_1.1_Class_Reference_Final_06062011.pdf), pp.61-65.