这篇文章将解释用户可定义的do_ *钩子函数。 在Field Macros中,我们看到标准数据方法(如copy()和compare())提供了用户可定义的钩子函数,如do_copy()和do_compare()。 我将在这篇文章中定义这些钩子函数。
具有“do”功能的Jelly Bean事务类。
让我们将“do”函数添加到jelly_bean_transaction类。
do_copy
do_copy()方法由copy()方法调用。 do_copy()方法用于复制jelly_bean_transaction对象的所有属性(第10至14行)。 请注意,我们必须将uvm_object(rhs)转换为jelly_bean_transaction(that)以访问jelly_bean_transaction对象(第4行)的属性。 我们必须调用super.do_copy()来复制在超类中定义的属性。
virtual function void do_copy( uvm_object rhs );
jelly_bean_transaction that;
if ( ! $cast( that, rhs ) ) begin
`uvm_error( get_name(), "rhs is not a jelly_bean_transaction" )
return;
end
super.do_copy( rhs );
this.flavor = that.flavor;
this.color = that.color;
this.sugar_free = that.sugar_free;
this.sour = that.sour;
this.taste = that.taste;
endfunction: do_copy
do_compare
do_compare()方法由compare()方法调用。 do_compare()用于比较jelly_bean_transaction对象的每个属性。如果比较成功,则do_compare()将返回1,如果比较失败,则返回0(第6至11行)。请注意,为了访问jelly_bean_transaction对象的属性(第4行),我们必须再次将uvm_object(rhs)转换为jelly_bean_transaction(that)。我们必须调用super.do_compare()来比较超类的属性(第6行)。 uvm_comparer参数提供了用于比较的策略对象,但我们不使用它。
virtual function bit do_compare( uvm_object rhs, uvm_comparer comparer );
jelly_bean_transaction that;
if ( ! $cast( that, rhs ) ) return 0;
return ( super.do_compare( rhs, comparer ) &&
this.flavor == that.flavor &&
this.color == that.color &&
this.sugar_free == that.sugar_free &&
this.sour == that.sour &&
this.taste == that.taste );
endfunction: do_compare
do_pack
do_pack()方法由pack(),pack_bytes()和pack_ints()方法调用。 do_pack()用于使用uvm_packer策略对象打包jelly_bean_transaction对象的每个属性。请参阅寄存器抽象了解每个属性是如何打包的。打包器决定如何包装。我们必须调用super.do_pack()来打包超类的属性(第5行)。
virtual function void do_pack( uvm_packer packer );
bit R1; // reserved bit
bit [5:0] R6; // reserved bits
super.do_pack( packer );
packer.pack_field_int( .value( flavor ), .size( 3 ) );
packer.pack_field_int( .value( color ), .size( 2 ) );
packer.pack_field_int( .value( sugar_free ), .size( 1 ) );
packer.pack_field_int( .value( sour ), .size( 1 ) );
packer.pack_field_int( .value( R1 ), .size( 1 ) );
packer.pack_field_int( .value( taste ), .size( 2 ) );
packer.pack_field_int( .value( R6 ), .size( 6 ) );
endfunction: do_pack
do_unpack
do_unpack()方法由unpack(),unpack_bytes()和unpack_ints()方法调用。 do_unpack()用于使用uvm_packer策略对象解压jelly_bean_transaction对象的每个属性。分包器决定了拆包应该如何完成。我们必须调用super.do_unpack()来解压超级类的属性(第5行)。
virtual function void do_unpack( uvm_packer packer );
bit R1; // reserved bit
bit [5:0] R6; // reserved bits
super.do_unpack( packer );
flavor = flavor_e'( packer.unpack_field_int( .size( 3 ) ) );
color = color_e '( packer.unpack_field_int( .size( 2 ) ) );
sugar_free = packer.unpack_field_int( .size( 1 ) );
sour = packer.unpack_field_int( .size( 1 ) );
R1 = packer.unpack_field_int( .size( 1 ) );
taste = taste_e '( packer.unpack_field_int( .size( 2 ) ) );
R6 = packer.unpack_field_int( .size( 6 ) );
endfunction: do_unpack
convert2string
convert2string()方法由用户调用以提供字符串形式的对象信息。 convert2string()用于将jelly_bean_transaction对象的每个属性转换为一个字符串。我们应该调用super.convert2string()将超类的属性转换为字符串(第2行)。
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
Test the“do”Hooks我们来测试一下“do”钩子。我们将如下定义jelly_bean_test类的run_phase()任务。
- 创建三个jelly_bean_transactions;对象jb_tx1,jb_tx2和jb_tx3(第11至13行)。
- 随机化jb_tx1(第14行)。
- 将jb_tx1的属性复制到jb_tx2(第18行)。
- 将jb_tx1的属性复制到jb_tx3,但使用pack()和unpack()方法而不是调用copy()方法(第24和25行)。
- 现在jb_tx1,jb_tx2和jb_tx3应该具有相同的属性值。使用compare()方法验证它(第29到39行)。
- 使用convert2string()方法打印jb_tx1,jb_tx2和jb_tx3的属性以直观地验证属性值(第43至45行)。
task run_phase( uvm_phase phase );
jelly_bean_transaction jb_tx1;
jelly_bean_transaction jb_tx2;
jelly_bean_transaction jb_tx3;
uvm_packer jb_packer;
bit bitstream[];
int num_bits;
phase.raise_objection( .obj( this ) );
jb_tx1 = jelly_bean_transaction::type_id::create( "jb_tx1" );
jb_tx2 = jelly_bean_transaction::type_id::create( "jb_tx2" );
jb_tx3 = jelly_bean_transaction::type_id::create( "jb_tx3" );
assert( jb_tx1.randomize() );
// copy jb_tx1 to jb_tx2
jb_tx2.copy( jb_tx1 );
// create jb_tx3 by packing and unpacking jb_tx1
jb_packer = new;
jb_packer.big_endian = 0;
num_bits = jb_tx1.pack ( bitstream, jb_packer );
num_bits = jb_tx3.unpack( bitstream, jb_packer );
// check if jb_tx1, jb_tx2 and jb_tx3 have the same properties
if ( jb_tx1.compare( jb_tx2 ) ) begin
`uvm_info( get_name(), "jb_tx1 and jb_tx2 matched", UVM_NONE )
end else begin
`uvm_error( get_name(), "jb_tx1 and jb_tx2 mismatched" )
end
if ( jb_tx2.compare( jb_tx3 ) ) begin
`uvm_info( get_name(), "jb_tx2 and jb_tx3 matched", UVM_NONE )
end else begin
`uvm_error( get_name(), "jb_tx2 and jb_tx3 mismatched" )
end
// print each object
`uvm_info( get_name(), jb_tx1.convert2string(), UVM_NONE )
`uvm_info( get_name(), jb_tx2.convert2string(), UVM_NONE )
`uvm_info( get_name(), jb_tx3.convert2string(), UVM_NONE )
phase.drop_objection( .obj( this ) );
endtask: run_phase
您可能已经注意到我们在第22行创建了一个uvm_packer对象(jb_packer),并将它的big_endian属性设置为0(第23行)。我们在打包和解压jelly_bean_transaction(第24行和第25行)时使用了此打包器。这是为了确保我们将每个属性值打包成小端数,正如我们在寄存器抽象中所做的那样。如果您只想打包并解压缩并且不关心比特流表示,则不必创建uvm_packer对象。如果未指定uvm_packer,则将使用全局uvm_default_packer策略,其中big_endian的值为1.下图显示big_endian的值如何影响比特流表示形式。 m_bits是uvm_packer的一个属性,它以位数组( bit array)的形式表示打包比特流。
Simulation
这是一个仿真结果。如您所见,所有三个jelly_bean_transactions都具有相同的属性值。
UVM_INFO jb15.sv(589) @ 0: uvm_test_top [uvm_test_top] jb_tx1 and jb_tx2 matched
UVM_INFO jb15.sv(595) @ 0: uvm_test_top [uvm_test_top] jb_tx2 and jb_tx3 matched
UVM_INFO jb15.sv(602) @ 0: uvm_test_top [uvm_test_top]
name : jb_tx1
flavor : CHOCOLATE
color : RED
sugar_free: 1
sour : 0
taste : UNKNOWN
UVM_INFO jb15.sv(603) @ 0: uvm_test_top [uvm_test_top]
name : jb_tx2
flavor : CHOCOLATE
color : RED
sugar_free: 1
sour : 0
taste : UNKNOWN
UVM_INFO jb15.sv(604) @ 0: uvm_test_top [uvm_test_top]
name : jb_tx3
flavor : CHOCOLATE
color : RED
sugar_free: 1
sour : 0
taste : UNKNOWN
我希望这篇教程能帮助你理解“do”钩子函数。
|