UVM Tutorial for Candy Lovers – 15. “Do” Hooks

This post will explain user-definable do_* hook functions. In Field Macros, we saw that the standard data methods, such as copy() and compare(), called the user-definable hook functions, such as do_copy() and do_compare(). I will define these hook functions in this post.

Jelly Bean Transaction Class with “do” Functions

Let’s add the “do” functions to the jelly_bean_transaction class.

do_copy

The do_copy() method is called by the copy() method. The do_copy() method is used to copy all the properties of a jelly_bean_transaction object (lines 10 to 14). Note that we have to cast a uvm_object (rhs) to a jelly_bean_transaction (that) in order to access the properties of the jelly_bean_transaction object (line 4). We must call the super.do_copy() to copy the properties defined in the super class (line 9).

   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

The do_compare() method is called by the compare() method. The do_compare() is used to compare each property of the jelly_bean_transaction object. The do_compare() returns 1 if the comparison succeeds, and returns 0 if the comparison fails (lines 6 to 11). Note that we have to cast a uvm_object (rhs) to a jelly_bean_transaction (that) again in order to access the properties of the jelly_bean_transaction object (line 4). We must call the super.do_compare() to compare the properties of the super class (line 6). The uvm_comparer argument provides a policy object for doing comparisons, but we do not use it.

   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

The do_pack() method is called by the pack()pack_bytes(), and pack_ints() methods. The do_pack() is used to pack each propery of the jelly_bean_transaction object using a uvm_packer policy object. Please see Register Abstraction for how each property is packed. The packer determines how the packing should be done. We must call the super.do_pack() to pack the properties of the super class (line 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

The do_unpack() method is called by the unpack()unpack_bytes(), and unpack_ints() methods. The do_unpack() is used to unpack each property of the jelly_bean_transaction object using a uvm_packer policy object. The packer determines how the unpacking should be done. We must call the super.do_unpack() to unpack the properties of the super class (line 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

The convert2string() method is called by the user to provide object information in the form of a string. The convert2string() is used to convert each property of the jelly_bean_transaction object into a string. We should call the super.convert2string() to convert the properties of the super class into the string (line 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

Let’s test the “do” hooks. We will define the run_phase() task of the jelly_bean_test class as follows.

  1. Create three jelly_bean_transactions; jb_tx1jb_tx2 and jb_tx3 (lines 11 to 13).
  2. Randomize the jb_tx1 (line 14).
  3. Copy the properties of the jb_tx1 to jb_tx2 (line 18).
  4. Copy the properties of the jb_tx1 to jb_tx3, but using the pack() and unpack() methods instead of calling the copy() method (lines 24 and 25).
  5. Now the jb_tx1jb_tx2, and jb_tx3 should have the same property values. Verify it using the compare() method (lines 29 to 39).
  6. Print the properties of the jb_tx1jb_tx2, and jb_tx3 using the convert2string() method to visually verify the property values (lines 43 to 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

You might have noticed that we created a uvm_packer object (jb_packer) on line 22 and set its big_endian property to 0 (line 23). We used this packer when we pack and unpack the jelly_bean_transaction (lines 24 and 25). This is to make sure we pack each property value in little endian as we did in Register Abstraction. If you just want to pack and unpack and don’t care about the bitstream representation, you don’t have to create the uvm_packer object. If you don’t specify the uvm_packer, the global uvm_default_packer policy will be used, of which the value of big_endian is 1. The following diagram shows how the value of big_endian affects the bitstream representation. The m_bits is a property of the uvm_packer and it represents the packed bitstream in the form of a bit array.

Pack in little endian and in big endian

                                                                 Pack in little endian and in big endian

Simulation

Here is a simulation result. As you see, all three jelly_bean_transactions have same property values.

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

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页