当我们之前实现“do”钩子时,我们定义了convert2string函数,但是我们没有定义我们自己的do_print函数。这是因为convert2string非常灵活且重量轻,因为它不需要提供打印格式的所谓打印策略。但是如果您定义了自己的do_print,则可以立即享受预定义的打印格式。您也可以创建自己的格式。本文展示了如何使用do_print。
定义do_print
定义do_print本身并不是很困难。但在这之前,我们先看看我们之前定义的convert2string函数。如您所见,convert2string函数定义了要打印的变量以及如何操作。
class jelly_bean_transaction extends uvm_sequence_item;
virtual function string convert2string();
string s = super.convert2string();
s = { s, $psprintf( "\nname : %s", get_name() ) };
s = { s, $psprintf( "\nflavor : %s", flavor.name() ) };
s = { s, $psprintf( "\ncolor : %s", color.name() ) };
s = { s, $psprintf( "\nsugar_free: %b", sugar_free ) };
s = { s, $psprintf( "\nsour : %b", sour ) };
s = { s, $psprintf( "\ntaste : %s", taste.name() ) };
return s;
endfunction: convert2string
// ...
endclass: jelly_bean_transaction
与convert2string不同,通常do_print本身并不定义打印格式。相反,它会将格式委托给打印策略对象(printer)。以下是我们对do_print的定义。 uvm_printer类提供了以各种格式打印uvm_objects的接口(第1行)。在do_print函数中,我们仅使用uvm_printer类的函数(第3到第8行)列出要打印的变量。
严格地说,您可以在不使用uvm_printer的情况下定义do_print,但如果这样做,则无法使用uvm_printer的子类中定义的打印机格式。
virtual function void do_print( uvm_printer printer );
super.do_print( printer );
printer.print_string( "name", get_name() );
printer.print_string( "flavor", flavor.name() );
printer.print_string( "color", color.name() );
printer.print_field_int( "sugar_free", sugar_free, .size( 1 ) );
printer.print_field_int( "sour", sour, .size( 1 ) );
printer.print_string( "taste", taste.name() );
endfunction: do_print
使用do_print
uvm_object的print和sprint函数调用do_print。让我们在我们的果冻豆记分板中调用sprint。为方便起见,UVM预先定义了三个打印策略(uvm_default_table_printer,uvm_default_tree_printer和uvm_default_line_printer;第5至7行)。如果您未指定打印策略,则会使用默认设置为uvm_default_table_printer的uvm_default_printer(第4行)。为了比较,我们也在第3行调用convert2string。
class jelly_bean_sb_subscriber extends uvm_subscriber#( jelly_bean_transaction );
function void write( jelly_bean_transaction t );
`uvm_info( get_name(), { "using convert2string", t.convert2string() }, UVM_LOW )
`uvm_info( get_name(), { "using uvm_default_printer\n", t.sprint() }, UVM_LOW ) // use uvm_default_printer
`uvm_info( get_name(), { "using uvm_default_table_printer\n", t.sprint( uvm_default_table_printer ) }, UVM_LOW )
`uvm_info( get_name(), { "using uvm_default_tree_printer\n", t.sprint( uvm_default_tree_printer ) }, UVM_LOW )
`uvm_info( get_name(), { "using uvm_default_line_printer\n", t.sprint( uvm_default_line_printer ) }, UVM_LOW )
endfunction: write
// ...
endclass: jelly_bean_sb_subscriber
让我们看看每个输出。运行仿真之后,您应该看到如下所示的内容:
convert2string的输出
这是我们的老朋友。我们看到在该函数中指定的输出。
UVM_INFO env.svh(134) @ 185: uvm_test_top.jb_env.jb_sb [jb_sb] using convert2string
name : jb_tx
flavor : BUBBLE_GUM
color : RED
sugar_free: 1
sour : 1
taste : YUMMY
使用uvm_default_printer输出
如果我们不指定打印策略,这是输出。正如我们前面提到的那样,使用了uvm_default_printer,默认情况下它被设置为uvm_default_table_printer。
UVM_INFO env.svh(136) @ 185: uvm_test_top.jb_env.jb_sb [jb_sb] using uvm_default_printer
-----------------------------------------------------------------
Name Type Size Value
-----------------------------------------------------------------
jb_tx sugar_free_jelly_bean_transaction - @861
name string 5 jb_tx
flavor string 10 BUBBLE_GUM
color string 3 RED
sugar_free integral 1 'h1
sour integral 1 'h1
taste string 5 YUMMY
-----------------------------------------------------------------
使用uvm_default_table_printer输出
该输出与上述完全相同。
UVM_INFO env.svh(138) @ 185: uvm_test_top.jb_env.jb_sb [jb_sb] using uvm_default_table_printer
-----------------------------------------------------------------
Name Type Size Value
-----------------------------------------------------------------
jb_tx sugar_free_jelly_bean_transaction - @861
name string 5 jb_tx
flavor string 10 BUBBLE_GUM
color string 3 RED
sugar_free integral 1 'h1
sour integral 1 'h1
taste string 5 YUMMY
-----------------------------------------------------------------
使用uvm_default_tree_printer输出
uvm_default_tree_printer以树形式输出对象。
UVM_INFO env.svh(140) @ 185: uvm_test_top.jb_env.jb_sb [jb_sb] using uvm_default_tree_printer
jb_tx: (sugar_free_jelly_bean_transaction@861) {
name: jb_tx
flavor: BUBBLE_GUM
color: RED
sugar_free: 'h1
sour: 'h1
taste: YUMMY
}
使用uvm_default_line_printer输出
uvm_default_line_printer输出与uvm_default_tree_printer相同的信息,但在一行中。
UVM_INFO env.svh(142) @ 185: uvm_test_top.jb_env.jb_sb [jb_sb] using uvm_default_line_printer
jb_tx: (sugar_free_jelly_bean_transaction@861) { name: jb_tx flavor: BUBBLE_GUM color: RED sugar_free: 'h1 sour: 'h1 taste: YUMMY }
定义我们自己的打印策略
如果预定义的格式不能满足您的需求,您可以创建自己的打印策略。作为一个例子,我们将创建一个打印JSON格式的uvm_object的策略。我们的目标是打印一个像这样的jelly_bean_transaction:
{
"jb_tx": {
"name": "jb_tx",
"flavor": "BUBBLE_GUM",
"color": "RED",
"sugar_free": "'h1",
"sour": "'h1",
"taste": "YUMMY"
}
}
对于那些不熟悉JSON的人,请看这个链接。
要创建您自己的打印策略,您需要扩展uvm_printer类并定义emit函数。要打印的信息存储在保存变量名称,大小,值等的uvm_printer_row_info结构(第16行)的数组(m_rows)中。第31行打印名称 - 值对,如“flavor”:“BUBBLE_GUM”。我不会逐行解释实现,因为大多数其他行处理细节格式。我必须提到的一点是,printer设置是在knobs中定义的(uvm_printer_knobs类的一个对象)。我们使用第18行的其中一个设置(缩进;用定义缩进的空格数量)。
class json_printer extends uvm_printer;
function new();
super.new();
endfunction: new
virtual function string emit();
string s;
string comma = "";
string space = { 100 { " " } };
string indent;
int next_level;
s = "{\n"; // begin JSON
foreach ( m_rows[i] ) begin
uvm_printer_row_info row = m_rows[i];
indent = space.substr( 1, ( row.level + 1 ) * knobs.indent );
s = { s, comma, indent };
if ( i == m_rows.size() - 1 ) begin // last row
next_level = 0;
end else begin // not last row
next_level = m_rows[ i + 1 ].level;
if ( row.level < next_level ) begin // next level is deepr
s = { s, "\"", row.name, "\": {\n" }; // begin nested JSON object
comma = "";
continue;
end
end
s = { s, "\"", row.name, "\": \"", row.val, "\"" }; // name-value pair
comma = ",\n";
if ( next_level < row.level ) begin // next level is shallower
for ( int l = row.level; l > next_level; l-- ) begin
indent = space.substr( 1, l * knobs.indent );
s = { s, "\n", indent, "}" }; // end nested JSON object
end
end
end // foreach ( m_rows[i] )
emit = { s, "\n}" }; // end JSON
m_rows.delete();
endfunction: emit
endclass: json_printer
要使用新的打印策略,我们创建它(第6行),并在我们称为sprint(第10行)时传递它。
class jelly_bean_sb_subscriber extends uvm_subscriber#( jelly_bean_transaction );
json_printer json_p;
virtual function void build_phase( uvm_phase phase );
super.build_phase( phase );
json_p = new;
endfunction: build_phase
function void write( jelly_bean_transaction t );
`uvm_info( get_name(), { "using json_printer\n", t.sprint( json_p ) }, UVM_LOW )
endfunction: write
// ...
endclass: jelly_bean_sb_subscriber
运行时应该会看到类似这样的内容:
UVM_INFO env.svh(144) @ 185: uvm_test_top.jb_env.jb_sb [jb_sb] using json_printer
{
"jb_tx": {
"name": "jb_tx",
"flavor": "BUBBLE_GUM",
"color": "RED",
"sugar_free": "'h1",
"sour": "'h1",
"taste": "YUMMY"
}
}
为了您的参考,这些是我们在本文中使用的类和结构。
UVM printer类
您可以在EDA Playground上查看并运行代码。