UVM Tutorial for Candy Lovers – 29. Backdoor HDL Path

Our jelly-bean tasting business became very successful, so we decided to expand our business into partnership with another jelly-bean taster. During the process of the merger, however, we found that the partner had slightly different register structure than ours. We want to access the partner’s registers through the back door without modifying the register model we already have. But, how do we specify the HDL paths?

Partnership (DUT)

This is how the new DUT (jelly_bean_partnership) looks.

                                                                            Partnership module (DUT)

The partnership module includes our old jelly_bean_taster as well as the new jelly_bean_partner. We also added a new signal called taster_id, which selects either taster or partner, to the jelly_bean_if.

module jelly_bean_partnership( jelly_bean_if.slave_mp jb_if );
   import jelly_bean_pkg::*;
   jelly_bean_if jb_if0( jb_if.clk );
   jelly_bean_if jb_if1( jb_if.clk );
   jelly_bean_taster  taster ( jb_if0 );
   jelly_bean_partner partner( jb_if1 );
   always @* begin
      jb_if0.flavor     = jb_if.flavor;
      jb_if1.flavor     = jb_if.flavor;
      jb_if0.color      = jb_if.color;
      jb_if1.color      = jb_if.color;
      jb_if0.sugar_free = jb_if.sugar_free;
      jb_if1.sugar_free = jb_if.sugar_free;
      jb_if0.sour       = jb_if.sour;
      jb_if1.sour       = jb_if.sour;
      if ( jb_if.taster_id == 0 ) begin
	 jb_if0.command = jb_if.command;
	 jb_if1.command = NO_OP;
	 jb_if.taste    = jb_if0.taste;
      end else begin
	 jb_if0.command = NO_OP;
	 jb_if1.command = jb_if.command;
	 jb_if.taste    = jb_if1.taste;
   end // always @ *
endmodule: jelly_bean_partnership


The partner module does jelly-bean tasting in a similar way as the jelly_bean_taster. It has the equivalent registers as the jelly_bean_taster, but its structure is different. In particular:

  • The partner has one 5-bit consolidated color_and_flavor register (line 5).
  • The sour and sugar_free registers are within another module instance called extra (lines 37 and 38).
module jelly_bean_partner( jelly_bean_if.slave_mp jb_if );
   import jelly_bean_pkg::*;
   reg [1:0] taste;
   reg [4:0] color_and_flavor;
   reg [1:0] command;
   jelly_bean_extra extra();
   initial begin
      color_and_flavor = 0;
      extra.sugar_free = 0;
      extra.sour       = 0;
      command          = 0;
      taste            = 0;
   always @ ( posedge jb_if.clk ) begin
      command < = jb_if.command;
      if ( jb_if.command == JB_WRITE ) begin
	 color_and_flavor <= { jb_if.color, jb_if.flavor };
	 extra.sugar_free <= jb_if.sugar_free;
	 extra.sour       <= jb_if.sour;
      end else if ( jb_if.command == JB_READ ) begin
	 jb_if.taste <= #2ns taste;
   always @ ( posedge jb_if.clk ) begin
      if ( jb_if.flavor == CHOCOLATE && jb_if.sour ) taste <= YUCKY;
      else if ( jb_if.flavor != NO_FLAVOR )          taste <= YUMMY;
endmodule: jelly_bean_partner
module jelly_bean_extra;
   reg sugar_free;
   reg sour;
endmodule: jelly_bean_extra

Register Model

The top-level register block (jelly_bean_partnership_reg_block) instantiates two jelly_bean_reg_blocks we created before; one (jb_reg_blocks[0]) for the taster and the other (jb_reg_block[1]) for the partner.

                                                                                    Top-level register model

Then we set the HDL path of the jb_reg_blocks[0] to be "taster" (line 16), which matches the instance name of the jelly_bean_taster in the jelly_bean_partnership module (see the line 7 of the jelly_bean_partnership above). Similarly, we set the HDL path of the jb_reg_blocks[1] to be "partner" (line 21), which matches the instance name of the jelly_bean_partner in the jelly_bean_partnership module (see the line 8 of the jelly_bean_partnership above).

class jelly_bean_partnership_reg_block extends uvm_reg_block;
   `uvm_object_utils( jelly_bean_partnership_reg_block )
   rand jelly_bean_reg_block jb_reg_blocks[2];
   uvm_reg_map               reg_map;
   function new( string name = "jelly_bean_partnership_reg_block" );
      super.new( .name( name ), .has_coverage( UVM_NO_COVERAGE ) );
   endfunction: new
   virtual function void build();
      reg_map = create_map( .name( "reg_map" ), .base_addr( 8'h00 ), 
                            .n_bytes( 1 ), .endian( UVM_LITTLE_ENDIAN ) );
      jb_reg_blocks[0] = jelly_bean_reg_block::type_id::create( "jb_reg_blocks[0]" );
      jb_reg_blocks[0].configure( .parent( this ), .hdl_path( "taster" ) );
      reg_map.add_submap( .child_map( jb_reg_blocks[0].reg_map ), .offset( 0 ) );
      jb_reg_blocks[1] = jelly_bean_reg_block::type_id::create( "jb_reg_blocks[1]" );
      jb_reg_blocks[1].configure( .parent( this ), .hdl_path( "partner" ) );
      reg_map.add_submap( .child_map( jb_reg_blocks[1].reg_map ), .offset( 2 ) );
   endfunction: build
endclass: jelly_bean_partnership_reg_block

Setting HDL Paths

Now we are ready to instantiate the top-level register model. Firstly, we set the HDL path of the top-level register block to be "top.dut" (line 18 of jelly_bean_base_test below) assuming we have the following top-level test-bench .

module top;
  import uvm_pkg::*;
  reg clk;
  jelly_bean_if          jb_if( clk );
  jelly_bean_partnership dut( jb_if ); // DUT
  // ... omit ...
endmodule: top

Then, we set the HDL path slices to the partner’s recipe register (lines 22 to 24). Note that we cleared the HDL path of the jb_recipe_reg on the line 21 before setting the slices. This is because the reused jelly_bean_recipe_reg already has HDL path slices, which do not match the HDL paths of the partner (If you are interested, please see the lines 66 to 69 of the jelly_bean_recipe_reg in Register Access through the Back Door.).

class jelly_bean_base_test extends uvm_test;
   `uvm_component_utils( jelly_bean_base_test )
   jelly_bean_env                   jb_env;
   jelly_bean_env_config            jb_env_cfg;
   jelly_bean_agent_config          jb_agent_cfg;
   jelly_bean_partnership_reg_block jb_partnership_reg_block;
   function new( string name, uvm_component parent );
      super.new( name, parent );
   endfunction: new
   function void build_phase( uvm_phase phase );
      jelly_bean_recipe_reg jb_recipe_reg;
      super.build_phase( phase );
      jb_partnership_reg_block = jelly_bean_partnership_reg_block::type_id::create( "jb_partnership_reg_block" );
      jb_partnership_reg_block.configure( .hdl_path( "top.dut" ) );
      jb_recipe_reg = jb_partnership_reg_block.jb_reg_blocks[1].jb_recipe_reg; // shorthand
      jb_recipe_reg.add_hdl_path_slice( .name( "color_and_flavor" ), .offset( 0 ), .size( 5 ) );
      jb_recipe_reg.add_hdl_path_slice( .name( "extra.sugar_free" ), .offset( 5 ), .size( 1 ) );
      jb_recipe_reg.add_hdl_path_slice( .name( "extra.sour"       ), .offset( 6 ), .size( 1 ) );
      jb_partnership_reg_block.lock_model(); // finalize the address mapping
   // ... omit ...
endclass: jelly_bean_base_test

The following table summarizes the overall HDL paths we have defined for the partner’s recipe register.


The partner’s taste register uses the same HDL path (taste) we had already defined in the jelly_bean_taste_reg.


FYI, the following tables summarize the overall HDL paths we have for the taster.


Register Sequence

Let’s verify the HDL paths using the following sequence. We have three backdoor writes in the sequence (highlighted).

class jelly_bean_reg_sequence extends uvm_reg_sequence;
   `uvm_object_utils( jelly_bean_reg_sequence )
   function new( string name = "" );
      super.new( name );
   endfunction: new
   virtual   task body();
      jelly_bean_partnership_reg_block jb_partnership_reg_block;
      jelly_bean_reg_block             partner_reg_block;
      flavor_e                         flavor;
      color_e                          color;
      bit                              sugar_free;
      bit                              sour;
      uvm_status_e                     status;
      uvm_reg_data_t                   value;
      $cast( jb_partnership_reg_block, model );
      partner_reg_block = jb_partnership_reg_block.jb_reg_blocks[1]; // shorthand
      sugar_free = 0;
      sour       = 1;
      // back-door writes
      flavor = BLUEBERRY;
      color  = BLUE;
      poke_reg( partner_reg_block.jb_recipe_reg, status, 
                { sour, sugar_free, color, flavor } ); // 'h5A
      #10ns ;
      flavor = BUBBLE_GUM;
      color  = GREEN;
      write_reg( partner_reg_block.jb_recipe_reg, status, 
                 { sour, sugar_free, color, flavor }, UVM_BACKDOOR ); // 'h53
      #10ns ;
      flavor = CHOCOLATE;
      color  = RED;
      partner_reg_block.jb_recipe_reg.write( status, 
        { sour, sugar_free, color, flavor }, UVM_BACKDOOR, .parent( this ) ); // 'h4C
      #10ns ;
   endtask: body
endclass: jelly_bean_reg_sequence


When you run a simulation, you should see the result like this:

# KERNEL: UVM_INFO /home/build/vlib1/vlib/uvm-1.2/src/reg/uvm_reg.svh(2820) @ 0:
 reporter [RegModel] Poked register "jb_partnership_reg_block.jb_reg_blocks[1].jb_recipe_reg": 'h000000000000005a
# KERNEL: UVM_INFO @ 10: reporter [RegModel] Wrote register via DPI backdoor: 
# KERNEL: UVM_INFO @ 20: reporter [RegModel] Wrote register via DPI backdoor: 

I hope this article helped you to clarify the HDL path.

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