本文将解释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()几乎不做任何事(只有两个高亮块之间的代码将保留)。
我希望这篇文章能够帮助你理解字段宏。