uvm Register Access Methods(16)

时间:2020-04-15
本文章向大家介绍uvm Register Access Methods(16),主要包括uvm Register Access Methods(16)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

转载:

译文:https://blog.csdn.net/zhajio/article/details/80731435

原文:http://cluelogic.com/2013/02/uvm-tutorial-for-candy-lovers-register-access-methods/

UVM的寄存器抽象层(RAL)提供了几种访问寄存器的方法。 这篇文章将解释寄存器访问方法的工作原理。 在Register Abstraction中,我们介绍了RAL的概述并解释了如何定义寄存器。 在这篇文章中,我们将介绍如何访问寄存器。

uvm_reg_field的属性

在深入了解寄存器访问方法之前,让我们看看如何存储寄存器值。 如寄存器抽象中所示,uvm_reg_field是表示寄存器的位的最低寄存器抽象层。 uvm_reg_field使用多个属性来存储各种寄存器字段值:

  • m_reset [“HARD”]存储硬重置值(hard reset)。 请注意,m_reset是一种带有一种重置键的关联数组。
  • m_mirrored存储我们在待测试设计(DUT)中所认为应该存储的值。
  • m_desired存储我们想要设置给DUT的值。
  • value将要采样的值存储在功能覆盖率中,或者当该字段被随机化时将value约束。

请注意,在这些属性中,只有值属性是公共的。 其他属性是本地的,因此我们无法直接从类外访问它们。 稍后我们将向您介绍如何使用寄存器访问方法访问这些本地属性。

  

                                               uvm_reg_field的属性

configure()

我们在创建uvm_reg_field后执行的第一件事是配置它。在寄存器抽象中,我们如下配置flavor字段。请注意,在Register Abstraction中,我们将flavor字段定义为“WO”(只写),但我们在此将其定义为“RW”(读/写),以使该字段更通用。

flavor = uvm_reg_field::type_id::create( "flavor" );
flavor.configure( .parent                 ( this ),
                  .size                   ( 3    ),
                  .lsb_pos                ( 0    ),
                  .access                 ( "RW" ),
                  .volatile               ( 0    ),
                  .reset                  ( 0    ),
                  .has_reset              ( 1    ),
                  .is_rand                ( 1    ),
                  .individually_accessible( 0    ) );

如果has_reset参数为1,则复位参数的值将被视为“HARD”复位值。如果has_reset值为0,则复位值将被忽略。复位值应与DUT的复位状态相匹配。如果您想在配置后修改复位值,可以使用set_reset()方法。

flavor.set_reset( .value( 0 ), .kind( "HARD" ) ); // kind == "HARD" by default

                                               configure()和set_reset()方法如何工作

reset()

如果m_reset [kind]存在,reset()方法将重置寄存器字段的属性。默认类型是“HARD”。如果m_reset [kind]不存在,则reset()方法不执行任何操作。请注意,reset()方法不会复位DUT中的寄存器。它只复位寄存器字段对象的属性。

flavor.reset( .kind( "HARD" ) ); // kind == "HARD" by default

                                 reset()方法如何工作

set()

set()方法设置寄存器字段的期望值。 set()方法不会将值设置为DUT中的寄存器的值。它只将值设置为m_desired和寄存器字段对象的值属性。要真正将值设置为DUT中的寄存器,请使用write()或update()方法。这些方法将在稍后解释。

flavor.set( .value( 1 ) );

get()

get()方法获取寄存器字段的期望值。 get()方法不会从DUT中的寄存器获取值。它只获取m_desired属性的值。要实际从DUT获取值,请使用read()或mirror()方法。这些方法将在稍后解释。与get()方法类似,还有两个getter访问本地属性。 get_reset()检索m_reset [kind]属性的值,而get_mirrored_value()方法检索m_mirrored属性的值。

uvm_reg_data_t desired_value  = flavor.get();
uvm_reg_data_t reset_value    = flavor.get_reset( .kind( "HARD" ) ); // kind == "HARD" by default
uvm_reg_data_t mirrored_value = flavor.get_mirrored_value();

randomize()

randomize()方法是一个SystemVerilog方法。它随机化一个寄存器字段对象的值属性。随机化后,post_randomize()方法将value属性的值复制到m_desired属性。请注意,如果value属性的rand_mode为OFF,则pre_randomize()方法会将m_desired的值复制到value属性。

assert( flavor.randomize() );

write()

write()方法实际上向DUT写入一个值。

uvm_status_e status; 
flavor.write( .status( status ), .value( 1 ) );

write()方法涉及多个步骤。

  1. 创建与写入操作对应的uvm_reg_item对象。
  2. uvm_reg_adapter将写入操作转换为相应的总线事务。
  3. uvm_driver执行到DUT的总线事务。
  4. uvm_monitor捕获总线事务。
  5. uvm_reg_predictor要求uvm_reg_adapter将总线事务转换为相应的寄存器操作。
  6. 寄存器操作转换为uvm_reg_item。
  7. uvm_reg_item用于更新值,m_mirrored和m_desired属性。

请注意,如果在配置寄存器字段时个别可访问参数为0,则包含该字段的整个寄存器会被写入,因为该字段不可单独访问。在这种情况下,m_mirrored值将用作其他字段的写入值。

read()

read()方法实际上从DUT中读取一个寄存器值。

uvm_status_e   status;
uvm_reg_data_t value;
 
flavor.read( .status( status ), .value( value ) );

与write()方法类似,read()方法涉及多个步骤。

  1. 创建与读操作对应的uvm_reg_item对象。
  2. uvm_reg_adapter将读取操作转换为相应的总线事务。
  3. uvm_driver执行到DUT的总线事务。
  4. uvm_reg_apapter将读取数据的总线事务转换为寄存器操作。
  5. read()方法将读取值返回给调用者。
  6. 同时,uvm_monitor捕获总线事务。
  7. uvm_reg_predictor要求uvm_reg_adapter将总线事务转换为相应的寄存器操作。
  8. 寄存器操作转换为uvm_reg_item。
  9. uvm_reg_item用于更新值,m_mirrored和m_desired属性。

请注意,如果在配置寄存器字段时individually_accessible 参数为0,则会读取包含字段的整个寄存器。在这种情况下,也会为其他字段更新m_mirrored值。

update()

update()方法实际上是向DUT写入一个寄存器值。 update()方法属于uvm_reg类。 uvm_reg_field类没有update()方法。

uvm_status_e status;
 
jb_recipe_reg.update( .status( status ) );

write()方法和update()方法之间的区别是:

  • write()方法将一个值作为其参数,而update()方法使用m_desired属性的值作为要写入的值。
  • 只有当m_mirrored和m_desired不相等时,update()方法才写入该值。

update()方法在内部调用write(.value(m_desired))。因此,更新后,m_mirrored的值也会更新。

mirror()

mirror()方法实际上是从DUT读取一个寄存器。

uvm_status_e status;
 
flavor.mirror( .status( status ), .check( UVM_CHECK ) );

read()方法和mirror()方法之间的区别是:

  • read()方法返回寄存器值给调用者,而mirror()方法不返回寄存器值。 mirror()方法只更新m_mirrored属性的值。
  • 如果check参数的值为UVM_CHECK,则mirror()方法将读取值与m_desired进行比较。请注意,UVM类库文档指出,它将读取值与镜像值进行比较,但如果您查看uvm-1.1c代码库的uvm_reg.svh的第2,944行,它实际上会与所需的值进行比较,而不是针对镜像值。

2014年4月11日:uvm-1.1d代码库已纠正此问题。mirror()将读取值与镜像值进行比较。如果您对此修复感兴趣,请参阅uvm_reg.svh的第2,951行。)

关于检查的另一个警告是,如果在配置寄存器字段时将volatile参数设置为1,则即使将check参数设置为UVM_CHECK,也不会检查寄存器字段。这是因为我们无法确定性地预测寄存器字段的值,因为它可能在DUT中被更改(易失性)。

mirror()方法在内部调用do_read()方法。这是与read()方法内部调用的相同方法。因此,除m_mirrored属性外,mirror()方法还会更新值和m_desired属性。

predict()

predict()方法更新镜像值。

flavor.predict( .value( 1 ) );

predict()方法也会更新值和m_desired属性。

Summary

下表总结了每种方法如何更新寄存器字段对象的属性。

Methodm_reset
["HARD"]
valuem_desiredm_mirroredDUT
configure
(.reset(val),
.has_reset(1))
set the value of val        
set_reset(val) set the value of val        
reset()   copy the value of m_reset
["HARD"]
copy the value of m_reset
["HARD"]
copy the value of m_reset
["HARD"]
 
set(val)   set the value of val set the value of val    
get_reset() return the value of m_reset
["HARD"]
       
get()     return the value of m_desired    
get_mirrored_value()       return the value of m_mirrored  
randomize()   randomize copy the value of value    
write(.value(val))   set the value of val set the value of val set the value of val write the value of val
read(.value(val))   set the read value set the read value set the read value read the register
update()   set the value of m_desired set the value of m_desired set the value of m_desired write the value of m_desired
mirror()   set the read value set the read value set the read value read the register
predict
(.value(val))
  set the value of val set the value of val set the value of val

在这篇文章中,我们只介绍了所谓的前门访问。我们将在单独的帖子中介绍后门访问。我希望本教程能帮助您理解寄存器的访问方法。

 原文中有一些QA可以加深理解。

原文地址:https://www.cnblogs.com/zhiminyu/p/12706990.html