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
   end // always @ *
 
endmodule: jelly_bean_partnership

Partner

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;
   end
 
   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;
      end
   end
 
   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;
   end
 
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" ) );
      jb_reg_blocks[0].build();
      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" ) );
      jb_reg_blocks[1].build();
      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_partnership_reg_block.build();
      jb_recipe_reg = jb_partnership_reg_block.jb_reg_blocks[1].jb_recipe_reg; // shorthand
      jb_recipe_reg.clear_hdl_path();
      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.

Modeljb_partnership_reg_blockjb_reg_block[1]jb_recipe_reg
Pathtop.dutpartnercolor_and_flavor
Pathtop.dutpartnerextra.sugar_free
Pathtop.dutpartnerextra.sour

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

Modeljb_partnership_reg_blockjb_reg_block[1]jb_taste_reg
Pathtop.dutpartnertaste

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

Modeljb_partnership_reg_blockjb_reg_block[0]jb_recipe_reg
Pathtop.duttasterflavor
Pathtop.duttastercolor
Pathtop.duttastersugar_free
Pathtop.duttastersour
Modeljb_partnership_reg_blockjb_reg_block[0]jb_taste_reg
Pathtop.duttastertaste

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

Simulation

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: 
 jb_partnership_reg_block.jb_reg_blocks[1].jb_recipe_reg=0x53
# KERNEL: UVM_INFO @ 20: reporter [RegModel] Wrote register via DPI backdoor: 
 jb_partnership_reg_block.jb_reg_blocks[1].jb_recipe_reg=0x4c

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值