UVM糖果爱好者教程 - 9.寄存器抽象

本文将解释如何使用UVM寄存器抽象层(RAL)来生成寄存器事务。下图显示了用于这篇文章的验证平台。 除此之外,jelly_bean_reg_block,jelly_bean_reg_adapter和jelly_bean_reg_predictor是用于寄存器抽象的类。

      

                          Verification Platform

下图显示了RAL相关类的图。 标准UVM类以粉色显示,而 jelly-bean类以浅蓝色显示。 该图看起来乱糟糟一团,但要请放轻松,我会逐一解释每个 jelly-bean类。

                                              Diagram of the Jelly-Bean-Register Related Classes

Register Definitions

在之前的文章中,DUT没有可访问的寄存器。我们将添加容纳 jelly-bean食谱信息和味道的寄存器。我们还将一个命令输入端口添加到DUT中,以便我们可以向寄存器写入果冻配方并阅读它的味道。下图显示了DUT的寄存器定义。

                                             DUT Registers

DUT的源代码(jelly_bean_taster)如下所示。当命令输入为WRITE时,flavor,color,sugar_free和sour输入端口的值被写入RECIPE寄存器(第22至25行)。当命令输入为READ时,TASTE寄存器被读出并且味道输出相应地被驱动(第27行)。

module jelly_bean_taster( jelly_bean_if.slave_mp jb_slave_if );
   import jelly_bean_pkg::*;
 
   reg [2:0] flavor;
   reg [1:0] color;
   reg       sugar_free;
   reg       sour;
   reg [1:0] command;
   reg [1:0] taste;
 
   initial begin
      flavor     = 0;
      color      = 0;
      sugar_free = 0;
      sour       = 0;
      command    = 0;
      taste      = 0;
   end
 
   always @ ( posedge jb_slave_if.clk ) begin
      if ( jb_slave_if.command == jelly_bean_types::WRITE ) begin
         flavor     < = jb_slave_if.flavor;
         color      <= jb_slave_if.color;
         sugar_free <= jb_slave_if.sugar_free;
         sour       <= jb_slave_if.sour;
      end else if ( jb_slave_if.command == jelly_bean_types::READ ) begin
         jb_slave_if.taste <= taste;
      end
   end
 
   always @ ( posedge jb_slave_if.clk ) begin
      if ( jb_slave_if.flavor == jelly_bean_types::CHOCOLATE &&
           jb_slave_if.sour ) begin
         taste <= jelly_bean_types::YUCKY;
      end else if ( jb_slave_if.flavor != jelly_bean_types::NO_FLAVOR ) begin
         taste <= jelly_bean_types::YUMMY;
      end
   end
endmodule: jelly_bean_taster

Register Model

RECIPE寄存器的模型是通过扩展uvm_reg类来定义的。寄存器的每个字段定义为一个uvm_reg_field(第4至7行)。这些字段在构建函数中配置。请注意build方法是为了方便而使用的。不要将它与uvm_component的build_phase混淆,因为uvm_reg不是uvm_component。

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 != jelly_bean_types::NO_FLAVOR;
      flavor.value == jelly_bean_types::APPLE
                   -> color.value != jelly_bean_types::BLUE;
      flavor.value == jelly_bean_types::BLUEBERRY
                   -> color.value == jelly_bean_types::BLUE;
      flavor.value < = jelly_bean_types::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    ) );
   endfunction: build
endclass: jelly_bean_recipe_reg

TASTE寄存器的模型被类似地定义。

class jelly_bean_taste_reg extends uvm_reg;
   `uvm_object_utils( jelly_bean_taste_reg )
 
   rand uvm_reg_field taste;
 
   function new( string name = "jelly_bean_taste_reg" );
      super.new( .name( name ), .n_bits( 2 ), .has_coverage( UVM_NO_COVERAGE ) );
   endfunction: new
 
   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                ( 1    ),
                       .individually_accessible( 1    ) );
   endfunction: build
endclass: jelly_bean_taste_reg

Register Block

jelly_bean_reg_block包含上面创建的两个寄存器并定义一个寄存器映射。

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" ) );
      lock_model(); // finalize the address mapping
   endfunction: build
 
endclass: jelly_bean_reg_block

Register Adapter

jelly_bean_reg_adapter类提供了两个函数来在uvm_reg_bus_op和jelly_bean_transaction之间进行转换。 reg2bus函数将uvm_reg_bus_op转换为jelly_bean_transaction,而bus2reg函数将jelly_bean_transaction转换回uvm_reg_bus_op。

uvm_reg_adapter是一个uvm_object,而不是uvm_component。

高级主题:即使uvm_sequence是uvm_sequence_item,也不能让reg2bus()函数创建uvm_sequence并将其返回。这是因为当读取/写入寄存器时,uvm_reg_map调用uvm_sequence_base :: start_item()传递由reg2bus()返回的对象,但start_item()不指向uvm_sequence。这将导致致命的错误。有关更多详细信息,请参阅寄存器访问方法。

class jelly_bean_reg_adapter extends uvm_reg_adapter;
   `uvm_object_utils( jelly_bean_reg_adapter )
 
   function new( string name = "" );
      super.new( name );
      supports_byte_enable = 0;
      provides_responses   = 0;
   endfunction: new
 
   virtual function uvm_sequence_item reg2bus( const ref uvm_reg_bus_op rw );
      jelly_bean_transaction jb_tx
        = jelly_bean_transaction::type_id::create("jb_tx");
 
      if ( rw.kind == UVM_READ )       jb_tx.command = jelly_bean_types::READ;
      else if ( rw.kind == UVM_WRITE ) jb_tx.command = jelly_bean_types::WRITE;
      else                             jb_tx.command = jelly_bean_types::NO_OP;
      if ( rw.kind == UVM_WRITE )
        { jb_tx.sour, jb_tx.sugar_free, jb_tx.color, jb_tx.flavor } = rw.data;
      return jb_tx;
   endfunction: reg2bus
 
   virtual function void bus2reg( uvm_sequence_item bus_item,
                                  ref uvm_reg_bus_op rw );
      jelly_bean_transaction jb_tx;
 
      if ( ! $cast( jb_tx, bus_item ) ) begin
         `uvm_fatal( get_name(),
                     "bus_item is not of the jelly_bean_transaction type." )
         return;
      end
 
      rw.kind = ( jb_tx.command == jelly_bean_types::READ ) ? UVM_READ : UVM_WRITE;
      if ( jb_tx.command == jelly_bean_types::READ )
        rw.data = jb_tx.taste;
      else if ( jb_tx.command == jelly_bean_types::WRITE )
        rw.data = { jb_tx.sour, jb_tx.sugar_free, jb_tx.color, jb_tx.flavor };
      rw.status = UVM_IS_OK;
   endfunction: bus2reg
 
endclass: jelly_bean_reg_adapter

Register Predictor

寄存器预测器根据观察到的总线事务更新寄存器模型的值。由于果冻豆寄存器预测器不涉及任何类型的扩展功能,因此使用uvm_reg_predictor。

typedef uvm_reg_predictor#( jelly_bean_transaction ) jelly_bean_reg_predictor;

Agent

jelly_bean_agent实例化jelly_bean_reg_adapter(第35行)。

class jelly_bean_agent extends uvm_agent;
   `uvm_component_utils( jelly_bean_agent )
 
   uvm_analysis_port#( jelly_bean_transaction ) jb_ap;
 
   jelly_bean_agent_config jb_agent_cfg;
   jelly_bean_sequencer    jb_seqr;
   jelly_bean_driver       jb_drvr;
   jelly_bean_monitor      jb_mon;
   jelly_bean_reg_adapter  jb_reg_adapter;
 
   function new( string name, uvm_component parent );
      super.new( name, parent );
   endfunction: new
 
   function void build_phase( uvm_phase phase );
      super.build_phase( phase );
 
      if ( ! uvm_config_db#( jelly_bean_agent_config )::get( .cntxt( this ),
                                                             .inst_name ( "" ),
                                                             .field_name( "jb_agent_cfg" ),
                                                             .value( jb_agent_cfg ))) begin
         `uvm_error( "jelly_bean_agent", "jb_agent_cfg not found" )
      end
 
      jb_ap = new( .name( "jb_ap" ), .parent( this ) );
      if ( jb_agent_cfg.active == UVM_ACTIVE ) begin
         jb_seqr = jelly_bean_sequencer::type_id::create( .name( "jb_seqr" ),
                                                          .parent( this ) );
         jb_drvr = jelly_bean_driver::type_id::create( .name( "jb_drvr" ),
                                                       .parent( this ) );
      end
      jb_mon = jelly_bean_monitor::type_id::create( .name( "jb_mon" ),
                                                    .parent( this ) );
      jb_reg_adapter = jelly_bean_reg_adapter::type_id::create( .name( "jb_reg_adapter" ) );
   endfunction: build_phase
 
   function void connect_phase( uvm_phase phase );
      super.connect_phase( phase );
 
      jb_mon.jb_if = jb_agent_cfg.jb_if;
      if ( jb_agent_cfg.active == UVM_ACTIVE ) begin
         jb_drvr.seq_item_port.connect( jb_seqr.seq_item_export );
         jb_drvr.jb_if = jb_agent_cfg.jb_if;
      end
      jb_mon.jb_ap.connect( jb_ap );
   endfunction: connect_phase
endclass: jelly_bean_agent

Environment Configuration

jelly_bean_env_config具有jelly_bean_reg_block的句柄,以便jelly_bean_env可以访问寄存器模型。

class jelly_bean_env_config extends uvm_object;
   `uvm_object_utils( jelly_bean_env_config )
 
   bit has_jb_agent = 1;
   bit has_jb_sb    = 1;
 
   jelly_bean_agent_config jb_agent_cfg;
   jelly_bean_reg_block    jb_reg_block;
 
   function new( string name = "" );
      super.new( name );
   endfunction: new
endclass: jelly_bean_env_config

Enviroment

jelly_bean_env实例化jelly_bean_agent和jelly_bean_reg_predictor(第28至31行),然后连接与寄存器相关的对象:

首先,在connect_phase()中,set_sequencer()函数将果冻豆序列器和寄存器适配器与寄存器映射关联(第45和46行)。必须在基于uvm_reg_sequence开始序列之前调用set_sequencer()。寄存器块可能有多个寄存器映射。

其次,寄存器映射和寄存器适配器与寄存器预测器相关联(第49和50行)。寄存器预测器将使用寄存器映射和寄存器适配器将jelly_bean_transaction转换回寄存器操作。

最后,寄存器预测器连接到代理以订阅来自代理的jelly_bean_transactions(第51行)。

class jelly_bean_env extends uvm_env;
   `uvm_component_utils( jelly_bean_env )
 
   jelly_bean_env_config    jb_env_cfg;
   jelly_bean_agent         jb_agent;
   jelly_bean_fc_subscriber jb_fc_sub;
   jelly_bean_scoreboard    jb_sb;
   jelly_bean_reg_predictor jb_reg_predictor;
 
   function new( string name, uvm_component parent );
      super.new( name, parent );
   endfunction: new
 
   function void build_phase( uvm_phase phase );
      super.build_phase( phase );
      if ( ! uvm_config_db#( jelly_bean_env_config )::get
           ( .cntxt( this ),
             .inst_name( "" ),
             .field_name( "jb_env_cfg" ),
             .value( jb_env_cfg ) ) ) begin
         `uvm_fatal( get_name(), "jb_env_cfg not found" )
      end
 
      uvm_config_db#( jelly_bean_agent_config )::set( .cntxt( this ),
                                                      .inst_name( "jb_agent*" ),
                                                      .field_name( "jb_agent_cfg" ),
                                                      .value( jb_env_cfg.jb_agent_cfg ) );
      jb_agent = jelly_bean_agent::type_id::create( .name( "jb_agent" ),
                                                    .parent( this ) );
      jb_reg_predictor = jelly_bean_reg_predictor::type_id::create( .name( "jb_reg_predictor" ),
                                                                    .parent( this ) );
      if ( jb_env_cfg.has_jb_sb ) begin
         jb_sb = jelly_bean_scoreboard::type_id::create( .name( "jb_sb" ),
                                                         .parent( this ) );
      end
      jb_fc_sub = jelly_bean_fc_subscriber::type_id::create( .name( "jb_fc_sub" ),
                                                             .parent( this ) );
    endfunction: build_phase
 
   function void connect_phase( uvm_phase phase );
      super.connect_phase( phase );
      jb_agent.jb_ap.connect( jb_fc_sub.analysis_export );
      jb_agent.jb_ap.connect( jb_sb.jb_analysis_export );
      if ( jb_env_cfg.jb_reg_block.get_parent() == null ) begin // if the top-level env
         jb_env_cfg.jb_reg_block.reg_map.set_sequencer( .sequencer( jb_agent.jb_seqr ),
                                                        .adapter( jb_agent.jb_reg_adapter ) );
      end
      jb_env_cfg.jb_reg_block.reg_map.set_auto_predict( .on( 0 ) );
      jb_reg_predictor.map     = jb_env_cfg.jb_reg_block.reg_map;
      jb_reg_predictor.adapter = jb_agent.jb_reg_adapter;
      jb_agent.jb_ap.connect( jb_reg_predictor.bus_in );
   endfunction: connect_phase
 
endclass: jelly_bean_env

Base Test

基本测试实例化jelly_bean_reg_block(第16和17行)并将其句柄存储在jelly_bean_env_config(第19和20行)中。

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_reg_block    jb_reg_block;
 
   function new( string name, uvm_component parent );
      super.new( name, parent );
   endfunction: new
 
   function void build_phase(uvm_phase phase);
      super.build_phase(phase);
 
      jb_reg_block = jelly_bean_reg_block::type_id::create( "jb_reg_block" );
      jb_reg_block.build();
 
      jb_env_cfg = jelly_bean_env_config::type_id::create( "jb_env_cfg" );
      jb_env_cfg.jb_reg_block = jb_reg_block;
 
      jb_agent_cfg = jelly_bean_agent_config::type_id::create( "jb_agent_cfg" );
 
      if ( ! uvm_config_db#( virtual jelly_bean_if )::get( .cntxt( this ),
                                                           .inst_name( "" ),
                                                           .field_name( "jb_if" ),
                                                           .value( jb_agent_cfg.jb_if ))) begin
         `uvm_error( "jelly_bean_test", "jb_if not found" )
      end
 
      jb_env_cfg.jb_agent_cfg = jb_agent_cfg;
 
      uvm_config_db#(jelly_bean_env_config)::set( .cntxt( null ),
                                                  .inst_name( "*" ),
                                                  .field_name( "jb_env_cfg" ),
                                                  .value( jb_env_cfg ) );
      jb_env = jelly_bean_env::type_id::create( .name( "jb_env" ),
                                                .parent( this ) );
   endfunction: build_phase
 
   virtual function void start_of_simulation_phase( uvm_phase phase );
      super.start_of_simulation_phase( phase );
      uvm_top.print_topology();
   endfunction: start_of_simulation_phase
 
endclass: jelly_bean_base_test

Sequence without Register Abstraction

我们现在已经创建了所有组件,并且我们准备创建一个寄存器序列。但在这之前,我们先创建一个“常规”序列,而不使用寄存器抽象,以便进行比较。 jelly_bean_sequence是生成sour-green-apple jelly_bean的序列。该序列的主体创建一个jelly_bean_transaction,驱动程序将使用它驱动引脚。
class jelly_bean_sequence extends uvm_sequence#( jelly_bean_transaction );
   `uvm_object_utils( jelly_bean_sequence )
 
   function new( string name = "" );
      super.new( name );
   endfunction: new
 
   task body();
      jelly_bean_transaction jb_tx;
      jb_tx = jelly_bean_transaction::type_id::create( .name( "jb_tx" ),
                                                       .contxt( get_full_name()));
      start_item( jb_tx );
      jb_tx.flavor     = jelly_bean_types::APPLE;
      jb_tx.color      = jelly_bean_types::GREEN;
      jb_tx.sugar_free = 0;
      jb_tx.sour       = 1;
      finish_item(jb_tx);
   endtask: body
endclass: jelly_bean_sequence

Sequence Using Register Abstraction

jelly_bean_reg_sequence是另一种产生sour-green-apple jelly_bean的序列,但是使用了寄存器抽象。该序列从uvm_reg_sequence类扩展,以便我们可以使用诸如write_reg()和read_reg()之类的便利功能。序列的主体将一个配方(第23行)写入RECIPE寄存器,然后从TASTE寄存器(第24行)回读其味道。请注意,我们不会在序列中创建jelly_bean_transaction。注册适配器将把注册操作转换成相应的jelly_bean_transactions。
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;
      jelly_bean_types::flavor_e flavor;
      jelly_bean_types::color_e  color;
      bit                        sugar_free;
      bit                        sour;
      uvm_status_e               status;
      uvm_reg_data_t             value;
 
      $cast( jb_reg_block, model );
      flavor     = jelly_bean_types::APPLE;
      color      = jelly_bean_types::GREEN;
      sugar_free = 0;
      sour       = 1;
 
      write_reg( jb_reg_block.jb_recipe_reg, status, { sour, sugar_free, color, flavor } );
      read_reg ( jb_reg_block.jb_taste_reg,  status, value );
   endtask: body
 
endclass: jelly_bean_reg_sequence

Register Test

jelly_bean_reg_test创建一个我们刚刚创建的jelly_bean_reg_sequence并启动序列(第12行至第15行)。

class jelly_bean_reg_test extends jelly_bean_base_test;
   `uvm_component_utils( jelly_bean_reg_test )
 
   function new( string name, uvm_component parent );
      super.new( name, parent );
   endfunction: new
 
   task main_phase( uvm_phase phase );
      jelly_bean_reg_sequence jb_reg_seq;
 
      phase.raise_objection( .obj( this ) );
      jb_reg_seq = jelly_bean_reg_sequence::type_id::create( .name( "jb_reg_seq" ),
                                                             .contxt( get_full_name()));
      jb_reg_seq.model = jb_reg_block;
      jb_reg_seq.start( .sequencer( jb_env.jb_agent.jb_seqr ) );
 
      #100ns;
      phase.drop_objection( .obj( this ) );
 
   endtask: main_phase
endclass: jelly_bean_reg_test

Simulation

我们来看一个仿真结果。仿真成功地生成了一个 sour-green苹果,并从DUT读回它的味道。

UVM_INFO jb3.sv(727) @ 30: uvm_test_top.jb_env.jb_sb [jelly_bean_scoreboard] You have a good sense of taste.
---------------------------------------------------------
Name          Type                         Size  Value
---------------------------------------------------------
jb_tx         jelly_bean_transaction       -     @7929
  flavor      jelly_bean_types::flavor_e   3     APPLE
  color       jelly_bean_types::color_e    2     GREEN
  sugar_free  integral                     1     'h0
  sour        integral                     1     'h1
  command     jelly_bean_types::command_e  2     WRITE
  taste       jelly_bean_types::taste_e    2     NO_TASTE
---------------------------------------------------------
 
UVM_INFO jb3.sv(727) @ 60: uvm_test_top.jb_env.jb_sb [jelly_bean_scoreboard] You have a good sense of taste.
----------------------------------------------------------
Name          Type                         Size  Value
----------------------------------------------------------
jb_tx         jelly_bean_transaction       -     @7928
  flavor      jelly_bean_types::flavor_e   3     NO_FLAVOR
  color       jelly_bean_types::color_e    2     NO_COLOR
  sugar_free  integral                     1     'h0
  sour        integral                     1     'h0
  command     jelly_bean_types::command_e  2     READ
  taste       jelly_bean_types::taste_e    2     YUMMY
----------------------------------------------------------

我希望本教程能帮助你理解UVM寄存器抽象。

  

您可以在EDA Playground上查看并运行代码。

阅读更多
文章标签: UVM systemverilog
个人分类: system verilog UVM
所属专栏: UVM糖果爱好者教程
上一篇用于Windows的便携式控制台模拟器Cmder
下一篇python从pdf文件中提取文本,并自动翻译
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭