UVM糖果爱好者教程 - 24.通过后门访问寄存器

这篇文章将增加对寄存器抽象中定义的寄存器的后门访问。 通过附加几行代码,您可以通过后门访问寄存器。

DUT

我们使用与寄存器抽象中定义的相同的DUT(jelly_bean_taster)。 被测设备有两个寄存器,如下所示。


                                            DUT 寄存器

DUT将寄存器的每个字段定义为reg(第4至8行)。

module jelly_bean_taster( jelly_bean_if.slave_mp jb_if );
  import jelly_bean_pkg::*;
 
  reg [1:0] taste;  // TASTE  register
  reg [2:0] flavor; // RECIPE register
  reg [1:0] color;
  reg       sugar_free;
  reg       sour;
 
  reg [1:0] command;
 
  initial begin
    flavor     = 0;
    color      = 0;
    sugar_free = 0;
    sour       = 0;
    command    = 0;
    taste      = 0;
  end
 
  always @ ( posedge jb_if.clk ) begin
    if ( jb_if.command == JB_WRITE ) begin
      flavor     < = jb_if.flavor;
      color      <= jb_if.color;
      sugar_free <= jb_if.sugar_free;
      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_taster

Testbench

top测试平台将jelly_bean_taster实例化为dut(第6行)。

module top;
  import uvm_pkg::*;
 
  reg clk;
  jelly_bean_if     jb_if( clk );
  jelly_bean_taster dut( jb_if ); // DUT
 
  initial begin // clock
    clk = 1;
    forever #5ns clk = ! clk;
  end
 
  initial begin // waveform
    $dumpfile( "dump.vcd" );
    $dumpvars( 0, top );
  end
 
  initial begin
    uvm_config_db#( virtual jelly_bean_if )::set( .cntxt( null ),
                                                  .inst_name( "uvm_test_top*" ),
                                                  .field_name( "jb_if" ),
                                                  .value( jb_if ) );
    run_test();
  end
endmodule: top

Register Block

要通过后门访问DUT寄存器,我们需要通知寄存器块关于其对应的HDL路径(第27行)。 在我们的例子中,寄存器块对应的层次HDL路径是“top.dut”。

class jelly_bean_reg_block extends uvm_reg_block;
  `uvm_object_utils( jelly_bean_reg_block )
 
  rand jelly_bean_recipe_reg jb_recipe_reg;
  rand jelly_bean_taste_reg  jb_taste_reg;
  uvm_reg_map                reg_map;
 
  function new( string name = "jelly_bean_reg_block" );
    super.new( .name( name ), .has_coverage( UVM_NO_COVERAGE ) );
  endfunction: new
 
  virtual function void build();
    jb_recipe_reg = jelly_bean_recipe_reg::type_id::create( "jb_recipe_reg" );
    jb_recipe_reg.configure( .blk_parent( this ) );
    jb_recipe_reg.build();
 
    jb_taste_reg = jelly_bean_taste_reg::type_id::create( "jb_taste_reg" );
    jb_taste_reg.configure( .blk_parent( this ) );
    jb_taste_reg.build();
 
    reg_map = create_map( .name( "reg_map" ), .base_addr( 8'h00 ), 
                          .n_bytes( 1 ), .endian( UVM_LITTLE_ENDIAN ) );
    reg_map.add_reg( .rg( jb_recipe_reg ), .offset( 8'h00 ), .rights( "WO" ) );
    reg_map.add_reg( .rg( jb_taste_reg  ), .offset( 8'h01 ), .rights( "RO" ) );
 
    // for back-door access
    add_hdl_path( .path( "top.dut" ) );
 
    lock_model(); // finalize the address mapping
  endfunction: build
endclass: jelly_bean_reg_block

Registers

我们还需要通知每个寄存器抽象类有关寄存器字段的HDL路径(第31行)。 在我们的例子中,taste寄存器字段对应于DUT中的taste寄存器。

class jelly_bean_taste_reg extends uvm_reg;
  `uvm_object_utils( jelly_bean_taste_reg )
 
  rand uvm_reg_field taste;
 
  //----------------------------------------------------------------------------
  // Function: new
  //----------------------------------------------------------------------------
 
  function new( string name = "jelly_bean_taste_reg" );
     super.new( .name( name ), .n_bits( 2 ), .has_coverage( UVM_NO_COVERAGE ) );
  endfunction: new
 
  //----------------------------------------------------------------------------
  // Function: build
  //----------------------------------------------------------------------------
 
  virtual function void build();
    taste = uvm_reg_field::type_id::create( "taste" );
    taste.configure( .parent                 ( this ), 
                     .size                   ( 2    ), 
                     .lsb_pos                ( 0    ), 
                     .access                 ( "RO" ), 
                     .volatile               ( 1    ),
                     .reset                  ( 0    ), 
                     .has_reset              ( 1    ), 
                     .is_rand                ( 0    ), 
                     .individually_accessible( 0    ) );
 
    // for back-door access
    add_hdl_path_slice( .name( "taste" ), .offset( 0 ), .size( 2 ) );
  endfunction: build
endclass: jelly_bean_taste_reg

我们也将HDL路径设置为RECIPE寄存器(第66至69行)。在这种情况下,我们添加四个HDL路径(每个DUT寄存器一个路径)。

class jelly_bean_recipe_reg extends uvm_reg;
  `uvm_object_utils( jelly_bean_recipe_reg )
 
  rand uvm_reg_field flavor;
  rand uvm_reg_field color;
  rand uvm_reg_field sugar_free;
  rand uvm_reg_field sour;
 
  constraint flavor_color_con {
    flavor.value != NO_FLAVOR;
    flavor.value == APPLE     -> color.value != BLUE;
    flavor.value == BLUEBERRY -> color.value == BLUE;
    flavor.value < = CHOCOLATE;
  }
 
  function new( string name = "jelly_bean_recipe_reg" );
    super.new( .name( name ), .n_bits( 7 ), .has_coverage( UVM_NO_COVERAGE ) );
  endfunction: new
 
  virtual function void build();
    flavor = uvm_reg_field::type_id::create( "flavor" );
    flavor.configure( .parent                 ( this ), 
                      .size                   ( 3    ), 
                      .lsb_pos                ( 0    ), 
                      .access                 ( "WO" ), 
                      .volatile               ( 0    ),
                      .reset                  ( 0    ), 
                      .has_reset              ( 1    ), 
                      .is_rand                ( 1    ), 
                      .individually_accessible( 0    ) );
 
    color = uvm_reg_field::type_id::create( "color" );
    color.configure( .parent                 ( this ), 
                     .size                   ( 2    ), 
                     .lsb_pos                ( 3    ), 
                     .access                 ( "WO" ), 
                     .volatile               ( 0    ),
                     .reset                  ( 0    ), 
                     .has_reset              ( 1    ), 
                     .is_rand                ( 1    ), 
                     .individually_accessible( 0    ) );
 
    sugar_free = uvm_reg_field::type_id::create( "sugar_free" );
    sugar_free.configure( .parent                 ( this ), 
                          .size                   ( 1    ), 
                          .lsb_pos                ( 5    ), 
                          .access                 ( "WO" ), 
                          .volatile               ( 0    ),
                          .reset                  ( 0    ), 
                          .has_reset              ( 1    ), 
                          .is_rand                ( 1    ), 
                          .individually_accessible( 0    ) );
 
    sour = uvm_reg_field::type_id::create( "sour" );
    sour.configure( .parent                 ( this ), 
                    .size                   ( 1    ), 
                    .lsb_pos                ( 6    ), 
                    .access                 ( "WO" ), 
                    .volatile               ( 0    ),
                    .reset                  ( 0    ), 
                    .has_reset              ( 1    ), 
                    .is_rand                ( 1    ), 
                    .individually_accessible( 0    ) );
 
    // for back-door access
    add_hdl_path_slice( .name( "flavor"     ), .offset( 0 ), .size( 3 ) );
    add_hdl_path_slice( .name( "color"      ), .offset( 3 ), .size( 2 ) );
    add_hdl_path_slice( .name( "sugar_free" ), .offset( 5 ), .size( 1 ) );
    add_hdl_path_slice( .name( "sour"       ), .offset( 6 ), .size( 1 ) );
  endfunction: build
endclass: jelly_bean_recipe_reg

这就是你需要的一切。我们来测试后门。

Register Sequence

这个序列演示了通过后门访问寄存器的几种方法。作为进修人员,我们首先通过前门访问寄存器。

  1. 第24行使用uvm_reg_sequence类的write_reg任务写入RECIPE寄存器。
  2. 第27行使用uvm_reg_sequence类的read_reg任务从TASTE寄存器中读取。

然后,我们用三种不同的方式通过后门写RECIPE寄存器。

  1. 第32行使用uvm_reg_sequence类的poke_reg任务。
  2. 第36行使用带有UVM_BACKDOOR选项的uvm_reg_sequence类的write_reg任务。
  3. 第41行使用uvm_reg类的写入任务和UVM_BACKDOOR选项。

同样,我们通过三种不同的方式通过后门读取TASTE寄存器。

  1. 第46行使用uvm_reg_sequence类的peek_reg任务。
  2. 第49行使用uvm_reg_sequence类的read_reg任务和UVM_BACKDOOR选项。
  3. 第52行使用带有UVM_BACKDOOR选项的uvm_reg类的读取任务。
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_reg_block jb_reg_block;
    flavor_e             flavor;
    color_e              color;
    bit                  sugar_free;
    bit                  sour;
    uvm_status_e         status;
    uvm_reg_data_t       value;
 
    $cast( jb_reg_block, model );
    flavor     = APPLE;
    color      = GREEN;
    sugar_free = 0;
    sour       = 1;
 
    // front-door write
    write_reg( jb_reg_block.jb_recipe_reg, status, { sour, sugar_free, color, flavor } ); 
 
    // front-door read
    read_reg( jb_reg_block.jb_taste_reg, status, value );
    #20ns ;
 
    // back-door writes
    flavor = BLUEBERRY;
    poke_reg( jb_reg_block.jb_recipe_reg, status, { sour, sugar_free, color, flavor } ); 
    #10ns ;
 
    flavor = BUBBLE_GUM;
    write_reg( jb_reg_block.jb_recipe_reg, status, { sour, sugar_free, color, flavor },
               UVM_BACKDOOR ); 
    #10ns ;
 
    flavor = CHOCOLATE;
    jb_reg_block.jb_recipe_reg.write( status, { sour, sugar_free, color, flavor },
                                      UVM_BACKDOOR, .parent( this ) );
    #10ns ;
 
    // back-door reads
    peek_reg( jb_reg_block.jb_taste_reg, status, value );
    assert( value == YUMMY );
 
    read_reg( jb_reg_block.jb_taste_reg, status, value, UVM_BACKDOOR );
    assert( value == YUMMY );
 
    jb_reg_block.jb_taste_reg.read( status, value, UVM_BACKDOOR, .parent( this ) );
    assert( value == YUMMY );
    #10ns ;
  endtask: body
 
endclass: jelly_bean_reg_sequence

Simulation

这是一个带注释的波形。前门访问使用jb_if,而后门访问则直接更新DUT的寄存器值。请注意,即使DUT应该对YUCKY响应酸味和巧克力的组合,后门仍然不会更新DUT的taste字段。这是因为DUT会响应jb_if上的值更新taste字段,但不会响应内部RECIPE寄存器值。



猜你喜欢

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