本文将解释UVM字段宏(`uvm_field_ *)如何工作。 在事务和序列中,我们使用UVM字段宏来自动实现jelly_bean_transaction的标准数据方法,如copy(),compare()和pack()。
`uvm_object_utils_begin(jelly_bean_transaction)
`uvm_field_enum(flavor_e, flavor, UVM_ALL_ON)
`uvm_field_enum(color_e, color, UVM_ALL_ON)
`uvm_field_int (sugar_free, UVM_ALL_ON)
`uvm_field_int (sour, UVM_ALL_ON)
`uvm_field_enum(taste_e, taste, UVM_ALL_ON)
`uvm_object_utils_end
以下伪代码显示了如何扩展这些字段宏。
// Assuming UVM_NO_DEPRECATED is defined.
// Consequently assuming UVM_NO_REGISTERED_CONVERTER is defined.
// Assuming UVM_OBJECT_MUST_HAVE_CONSTRUCTOR is defined.
class jelly_bean_transaction extends uvm_sequence_item;
// `uvm_object_utils_begin(T) is expanded as follows
// |
// +--> `m_uvm_object_registry_internal(T,T)
// |
// V
typedef uvm_object_registry#( jelly_bean_transaction,
"jelly_bean_transaction" ) type_id;
static function type_id get_type();
return type_id::get();
endfunction
virtual function uvm_object_wrapper get_object_type();
return type_id::get();
endfunction
// |
// +--> `m_uvm_object_create_func(T)
// |
// V
function uvm_object create( string name = "" );
jelly_bean_transaction tmp;
if ( name == "" ) tmp = new();
else tmp = new( name );
return tmp;
endfunction
// |
// +--> `m_uvm_get_type_name_func(T)
// |
// V
const static string type_name = "jelly_bean_transaction";
virtual function string get_type_name();
return type_name;
endfunction
// |
// +--> `uvm_field_utils_begin(T)
function void __m_uvm_field_automation( uvm_object tmp_data__,
int what__,
string str__ );
begin
jelly_bean_transaction local_data__; // Used for copy and compare
typedef jelly_bean_transaction ___local_type____;
string string_aa_key; // Used for associative array lookups
uvm_object __current_scopes[$];
if ( what__ inside { UVM_SETINT, UVM_SETSTR, UVM_SETOBJ } ) begin
if ( __m_uvm_status_container.m_do_cycle_check( this ) ) begin
return;
end else
__current_scopes=__m_uvm_status_container.m_uvm_cycle_scopes;
end
super.__m_uvm_field_automation( tmp_data__, what__, str__ );
// Type is verified by uvm_object::compare()
if ( tmp_data__ != null )
// Allow objects in same hierarchy to be copied/compared
if ( ! $cast( local_data__, tmp_data__ ) ) return;
// `uvm_field_enum(flavor_e, flavor, UVM_ALL_ON) is expanded as follows
// |
// V
begin
case ( what__ )
UVM_CHECK_FIELDS:
__m_uvm_status_container.do_field_check( "flavor", this );
UVM_COPY: begin
if ( local_data__ == null ) return;
if ( ! ( UVM_ALL_ON & UVM_NOCOPY ) )
flavor = local_data__.flavor;
end
UVM_COMPARE: begin
if ( local_data__ == null ) return;
if ( ! ( UVM_ALL_ON & UVM_NOCOMPARE ) ) begin
if ( flavor !== local_data__.flavor ) begin
__m_uvm_status_container.scope.set_arg( "flavor" );
$swrite( __m_uvm_status_container.stringv,
"lhs = %0s : rhs = %0s",
flavor.name(), local_data__.flavor.name() );
__m_uvm_status_container.comparer.print_msg
( __m_uvm_status_container.stringv );
if ( __m_uvm_status_container.comparer.result &&
( __m_uvm_status_container.comparer.show_max < =
__m_uvm_status_container.comparer.result ) )
return;
end
end
end
UVM_PACK:
if ( ! ( UVM_ALL_ON & UVM_NOPACK ) ) begin
__m_uvm_status_container.packer.pack_field
( flavor, $bits( flavor ) );
end
UVM_UNPACK:
if ( ! ( UVM_ALL_ON & UVM_NOPACK ) ) begin
flavor = flavor_e'
( __m_uvm_status_container.packer.unpack_field_int
( $bits( flavor ) ) );
end
UVM_RECORD:
`m_uvm_record_string( flavor, flavor.name(), UVM_ALL_ON )
UVM_PRINT:
if ( ! ( UVM_ALL_ON & UVM_NOPRINT ) ) begin
__m_uvm_status_container.printer.print_generic
( "flavor", "flavor_e", $bits( flavor ), flavor.name() );
end
UVM_SETINT: begin
__m_uvm_status_container.scope.set_arg( "flavor" );
if ( uvm_is_match( str__,
__m_uvm_status_container.scope.get())) begin
if ( UVM_ALL_ON & UVM_READONLY ) begin
uvm_report_warning
( "RDONLY",
$sformatf( "Readonly argument match %s is ignored",
__m_uvm_status_container.get_full_scope_arg()),
UVM_NONE);
end else begin
if ( __m_uvm_status_container.print_matches )
uvm_report_info
( "STRMTC",
{ "set_int()", ": Matched string ", str__,
" to field ",
__m_uvm_status_container.get_full_scope_arg() },
UVM_LOW );
flavor = flavor_e'
( uvm_object::__m_uvm_status_container.bitstream );
__m_uvm_status_container.status = 1;
end // else: !if( UVM_ALL_ON & UVM_READONLY )
end // if ( uvm_is_match( str__,...
end // case: UVM_SETINT
endcase // case ( what__ )
end
// `uvm_field_enum(color_e, color, UVM_ALL_ON) is expanded as follows
// |
// V
begin
case ( what__ )
UVM_CHECK_FIELDS:
__m_uvm_status_container.do_field_check( "color", this );
UVM_COPY: begin
if ( local_data__ == null ) return;
if ( ! ( UVM_ALL_ON & UVM_NOCOPY ) )
color = local_data__.color;
end
UVM_COMPARE: begin
if ( local_data__ == null ) return;
if ( ! ( UVM_ALL_ON & UVM_NOCOMPARE ) ) begin
if ( color !== local_data__.color ) begin
__m_uvm_status_container.scope.set_arg( "color" );
$swrite( __m_uvm_status_container.stringv,
"lhs = %0s : rhs = %0s",
color.name(), local_data__.color.name() );
__m_uvm_status_container.comparer.print_msg
( __m_uvm_status_container.stringv );
if ( __m_uvm_status_container.comparer.result &&
( __m_uvm_status_container.comparer.show_max <=
__m_uvm_status_container.comparer.result ) )
return;
end
end
end
UVM_PACK:
if ( ! ( UVM_ALL_ON & UVM_NOPACK ) ) begin
__m_uvm_status_container.packer.pack_field
( color, $bits( color ) );
end
UVM_UNPACK:
if ( ! ( UVM_ALL_ON & UVM_NOPACK ) ) begin
color = color_e'
( __m_uvm_status_container.packer.unpack_field_int
( $bits( color ) ) );
end
UVM_RECORD:
`m_uvm_record_string( color, color.name(), UVM_ALL_ON )
UVM_PRINT:
if ( ! ( UVM_ALL_ON & UVM_NOPRINT ) ) begin
__m_uvm_status_container.printer.print_generic
( "color", "color_e", $bits( color ), color.name() );
end
UVM_SETINT: begin
__m_uvm_status_container.scope.set_arg( "color" );
if ( uvm_is_match( str__,
__m_uvm_status_container.scope.get())) begin
if ( UVM_ALL_ON & UVM_READONLY ) begin
uvm_report_warning
( "RDONLY",
$sformatf( "Readonly argument match %s is ignored",
__m_uvm_status_container.get_full_scope_arg()),
UVM_NONE);
end else begin
if ( __m_uvm_status_container.print_matches )
uvm_report_info
( "STRMTC",
{ "set_int()", ": Matched string ", str__,
" to field ",
__m_uvm_status_container.get_full_scope_arg() },
UVM_LOW );
color = color_e'
( uvm_object::__m_uvm_status_container.bitstream );
__m_uvm_status_container.status = 1;
end // else: !if( UVM_ALL_ON & UVM_READONLY )
end // if ( uvm_is_match( str__,...
end // case: UVM_SETINT
endcase // case ( what__ )
end
// `uvm_field_int(sugar_free, UVM_ALL_ON) is expanded as follows
// |
// V
begin
case ( what__ )
UVM_CHECK_FIELDS: begin
__m_uvm_status_container.do_field_check( "sugar_free", this );
end
UVM_COPY: begin
if ( local_data__ == null ) return;
if ( !( UVM_ALL_ON & UVM_NOCOPY ) )
sugar_free = local_data__.sugar_free;
end
UVM_COMPARE: begin
if ( local_data__ == null ) return;
if ( ! ( UVM_ALL_ON & UVM_NOCOMPARE ) ) begin
if ( sugar_free !== local_data__.sugar_free ) begin
void'( __m_uvm_status_container.comparer.compare_field
( "sugar_free", sugar_free,
local_data__.sugar_free, $bits( sugar_free )));
if ( __m_uvm_status_container.comparer.result &&
( __m_uvm_status_container.comparer.show_max <=
__m_uvm_status_container.comparer.result ) )
return;
end
end // if ( ! ( UVM_ALL_ON & UVM_NOCOMPARE ) )
end // case: UVM_COMPARE
UVM_PACK:
if ( !( UVM_ALL_ON & UVM_NOPACK ) ) begin
if ( $bits( sugar_free ) <= 64 )
__m_uvm_status_container.packer.pack_field_int
( sugar_free, $bits( sugar_free ) );
else
__m_uvm_status_container.packer.pack_field
( sugar_free, $bits( sugar_free ) );
end
UVM_UNPACK:
if ( !( UVM_ALL_ON & UVM_NOPACK ) ) begin
if ( $bits( sugar_free ) <= 64 )
sugar_free = __m_uvm_status_container.packer.unpack_field_int
( $bits( sugar_free ) );
else
sugar_free = __m_uvm_status_container.packer.unpack_field
( $bits( sugar_free ) );
end
UVM_RECORD:
`m_uvm_record_int( sugar_free, UVM_ALL_ON )
UVM_PRINT:
if ( !( UVM_ALL_ON & UVM_NOPRINT ) ) begin
__m_uvm_status_container.printer.print_int
( "sugar_free", sugar_free, $bits( sugar_free ),
uvm_radix_enum'( UVM_ALL_ON & UVM_RADIX ) );
end
UVM_SETINT: begin
bit matched;
__m_uvm_status_container.scope.set_arg( "sugar_free" );
matched = uvm_is_match( str__,
__m_uvm_status_container.scope.get());
if ( matched ) begin
if ( UVM_ALL_ON & UVM_READONLY ) begin
uvm_report_warning
( "RDONLY",
$sformatf( "Readonly argument match %s is ignored",
__m_uvm_status_container.get_full_scope_arg()),
UVM_NONE );
end else begin
if ( __m_uvm_status_container.print_matches )
uvm_report_info
( "STRMTC",
{ "set_int()", ": Matched string ", str__,
" to field ",
__m_uvm_status_container.get_full_scope_arg() },
UVM_LOW );
sugar_free = uvm_object::__m_uvm_status_container.bitstream;
uvm_object::__m_uvm_status_container.status = 1;
end // else: !if( UVM_ALL_ON & UVM_READONLY )
end // if ( matched )
__m_uvm_status_container.scope.unset_arg( "sugar_free" );
end // case: UVM_SETINT
endcase // case (what__)
end
// `uvm_field_int(sour, UVM_ALL_ON) is expanded as follows
// |
// V
begin
case ( what__ )
UVM_CHECK_FIELDS: begin
__m_uvm_status_container.do_field_check( "sour", this );
end
UVM_COPY: begin
if ( local_data__ == null ) return;
if ( !( UVM_ALL_ON & UVM_NOCOPY ) )
sour = local_data__.sour;
end
UVM_COMPARE: begin
if ( local_data__ == null ) return;
if ( ! ( UVM_ALL_ON & UVM_NOCOMPARE ) ) begin
if ( sour !== local_data__.sour ) begin
void'( __m_uvm_status_container.comparer.compare_field
( "sour", sour,
local_data__.sour, $bits( sour )));
if ( __m_uvm_status_container.comparer.result &&
( __m_uvm_status_container.comparer.show_max <=
__m_uvm_status_container.comparer.result ) )
return;
end
end // if ( ! ( UVM_ALL_ON & UVM_NOCOMPARE ) )
end // case: UVM_COMPARE
UVM_PACK:
if ( !( UVM_ALL_ON & UVM_NOPACK ) ) begin
if ( $bits( sour ) <= 64 )
__m_uvm_status_container.packer.pack_field_int
( sour, $bits( sour ) );
else
__m_uvm_status_container.packer.pack_field
( sour, $bits( sour ) );
end
UVM_UNPACK:
if ( !( UVM_ALL_ON & UVM_NOPACK ) ) begin
if ( $bits( sour ) <= 64 )
sour = __m_uvm_status_container.packer.unpack_field_int
( $bits( sour ) );
else
sour = __m_uvm_status_container.packer.unpack_field
( $bits( sour ) );
end
UVM_RECORD:
`m_uvm_record_int( sour, UVM_ALL_ON )
UVM_PRINT:
if ( !( UVM_ALL_ON & UVM_NOPRINT ) ) begin
__m_uvm_status_container.printer.print_int
( "sour", sour, $bits( sour ),
uvm_radix_enum'( UVM_ALL_ON & UVM_RADIX ) );
end
UVM_SETINT: begin
bit matched;
__m_uvm_status_container.scope.set_arg( "sour" );
matched = uvm_is_match( str__,
__m_uvm_status_container.scope.get());
if ( matched ) begin
if ( UVM_ALL_ON & UVM_READONLY ) begin
uvm_report_warning
( "RDONLY",
$sformatf( "Readonly argument match %s is ignored",
__m_uvm_status_container.get_full_scope_arg()),
UVM_NONE );
end else begin
if ( __m_uvm_status_container.print_matches )
uvm_report_info
( "STRMTC",
{ "set_int()", ": Matched string ", str__,
" to field ",
__m_uvm_status_container.get_full_scope_arg() },
UVM_LOW );
sour = uvm_object::__m_uvm_status_container.bitstream;
uvm_object::__m_uvm_status_container.status = 1;
end // else: !if( UVM_ALL_ON & UVM_READONLY )
end // if ( matched )
__m_uvm_status_container.scope.unset_arg( "sour" );
end // case: UVM_SETINT
endcase // case (what__)
end
// `uvm_field_enum(taste_e, taste, UVM_ALL_ON) is expanded as follows
// |
// V
begin
case ( what__ )
UVM_CHECK_FIELDS:
__m_uvm_status_container.do_field_check( "taste", this );
UVM_COPY: begin
if ( local_data__ == null ) return;
if ( ! ( UVM_ALL_ON & UVM_NOCOPY ) )
taste = local_data__.taste;
end
UVM_COMPARE: begin
if ( local_data__ == null ) return;
if ( ! ( UVM_ALL_ON & UVM_NOCOMPARE ) ) begin
if ( taste !== local_data__.taste ) begin
__m_uvm_status_container.scope.set_arg( "taste" );
$swrite( __m_uvm_status_container.stringv,
"lhs = %0s : rhs = %0s",
taste.name(), local_data__.taste.name() );
__m_uvm_status_container.comparer.print_msg
( __m_uvm_status_container.stringv );
if ( __m_uvm_status_container.comparer.result &&
( __m_uvm_status_container.comparer.show_max <=
__m_uvm_status_container.comparer.result ) )
return;
end
end
end
UVM_PACK:
if ( ! ( UVM_ALL_ON & UVM_NOPACK ) ) begin
__m_uvm_status_container.packer.pack_field
( taste, $bits( taste ) );
end
UVM_UNPACK:
if ( ! ( UVM_ALL_ON & UVM_NOPACK ) ) begin
taste = taste_e'
( __m_uvm_status_container.packer.unpack_field_int
( $bits( taste ) ) );
end
UVM_RECORD:
`m_uvm_record_string( taste, taste.name(), UVM_ALL_ON )
UVM_PRINT:
if ( ! ( UVM_ALL_ON & UVM_NOPRINT ) ) begin
__m_uvm_status_container.printer.print_generic
( "taste", "taste_e", $bits( taste ), taste.name() );
end
UVM_SETINT: begin
__m_uvm_status_container.scope.set_arg( "taste" );
if ( uvm_is_match( str__,
__m_uvm_status_container.scope.get())) begin
if ( UVM_ALL_ON & UVM_READONLY ) begin
uvm_report_warning
( "RDONLY",
$sformatf( "Readonly argument match %s is ignored",
__m_uvm_status_container.get_full_scope_arg()),
UVM_NONE);
end else begin
if ( __m_uvm_status_container.print_matches )
uvm_report_info
( "STRMTC",
{ "set_int()", ": Matched string ", str__,
" to field ",
__m_uvm_status_container.get_full_scope_arg() },
UVM_LOW );
taste = taste_e'
( uvm_object::__m_uvm_status_container.bitstream );
__m_uvm_status_container.status = 1;
end // else: !if( UVM_ALL_ON & UVM_READONLY )
end // if ( uvm_is_match( str__,...
end // case: UVM_SETINT
endcase // case ( what__ )
end
// `uvm_object_utils_end is expanded as follows
// |
// V
end
endfunction // __m_uvm_field_automation
endclass: jelly_bean_transaction
哇!多长的代码!每个字段宏被扩展到大约80行代码。您不需要完全理解代码,但基本上代码会执行以下操作:
- uvm_object_utils_begin()宏创建一个名为__m_uvm_field_automation的虚拟函数(第一个突出显示的黄色代码块,第50行)。
- 每个`uvm_field_ *宏都会创建一个case语句(第二个高亮块,第79-146行),并根据传递给__m_uvm_field_automation()函数的what__参数的值执行复制,比较和打包的功能。
然后__m_uvm_field_automation()在uvm_object类中使用。正如您看到下图所示,uvm_object :: copy()将使用UVM_COPY调用__m_uvm_field_automation()作为what__的值。同样,uvm_object :: compare()使用UVM_COMPARE调用__m_uvm_field_automation()。
uvm_object类的一些标准数据方法
现在你可能会认为这些字段宏很方便但效率不高。为了更高效和更灵活的实现,我们可以使用用户可定义的do _ *()钩子。如上所示,uvm_object在调用__m_uvm_field_automation()之后调用do _ *()钩子。例如,uvm_object :: copy()在调用__m_uvm_field_automation()之后调用do_copy(),而uvm_object :: compare()在调用__m_uvm_field_automation()之后调用do_compare()。默认情况下,这些do _ *()方法是空的。我将在下一篇文章中解释关于do _ *()方法的更多细节。如果没有使用字段宏,__m_uvm_field_automation()几乎不做任何事(只有两个高亮块之间的代码将保留)。
我希望这篇文章能够帮助你理解字段宏。