UVM糖果爱好者教程 - 14. 字段宏(Field Macros)

本文将解释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()几乎不做任何事(只有两个高亮块之间的代码将保留)。

我希望这篇文章能够帮助你理解字段宏。

猜你喜欢

转载自blog.csdn.net/zhajio/article/details/80704889