reg_field的读写函数
首先明确,reg_field的读写函数的意思是下面介绍的函数是用于读写软件寄存器模型中reg_field的值的,并非读写硬件DUT的寄存器,切记。
set():设置m_desired
set()函数修改的是寄存器模型中调用该函数的uvm_reg_field的m_desired(期望值),并且根据configure()时配置的m_access(访问类型)来给m_desired赋值(函数中case…endcase中间的内容),同时将value值更新为最新的m_desired值。使用get()函数可以获取m_desired
注意这里修改的仅仅是寄存器模型中的m_desired和value值,并不涉及任何与dut相关的寄存器值的修改。
图解:
randomize:随机化value
在reg_field中并未定义randomize函数,相反定义了其前后回调函数来对randomize()前后的行为进行一定的约束,我们知道randomize()实际是对value值做的随机,在randomize()前会自动调用pre_randomize()将m_desired的值赋给了value,这样如果rand_mode被设置为0,那么value值就使用了m_desired。而post_randomize()则是将随机后的value值更到m_desired中。
由此我们可以总结:
若允许value随机化,那么randomize()相当于随机化了m_desired,从效果上看randomize()功能类似于set()了一个随机的值。
若禁止value随机化,则调用randomize前后,m_desired不会改变
图解如下:
寄存器模型的reg_field读写DUT寄存器的函数
下面介绍reg_field的write和read函数,不涉及前/后门访问、mirror和update。因为寄存器模型可以分为三个层次:block、reg、field,前后门是针对reg级别而言的,即field只实现最基本的write/read函数,没有前后门一说(个人理解,不一定对);而mirror和update是针对reg和block的,field没有这两个函数(这个说法不太准确,实际中field包含一个mirror但是确实没有update,而且field.mirror会直接调用它所在reg的mirror,如下图,所以也可以认为field没有mirror)
write():将data写入DUT对应寄存器
- 创建与写入操作对应的uvm_reg_item对象(将write()的参数赋值给uvm_reg_item对象成员),调用uvm_reg_field::do_write(),在该函数中又会调用uvm_reg_item::do_write()
- 调用uvm_reg_field::do_write()判断是否存在adapter,存在则调用do_bus_write()
- do_bus_write()会取reg_item部分值组成结构体reg_bus_op,调用adapter.reg2bus()将reg_bus_op转换为相应的总线事务item:bus_req。
- do_bus_write()将bus_req挂载到sqr上,并启动item发送
- uvm_driver 通过sqr来get到bus_req并取出其中的data等值,通过接口发送到DUT
对于predict,分两种:显式预测和隐式预测(自动预测):
隐式(自动):若设置了隐式预测,则在uvm_reg_field::do_write()的最后会自动调用do_predicte()来更新m_desired、m_mirror和value。
显式预测:必须例化reg_predictor,与monitor连接来实时检测总线事务,具体的更新过程如下:
- uvm_monitor捕获接口总线上的data\cmd\address等变化,赋值给item:bus_rsp,并发送给predictor
- uvm_reg_predictor要求uvm_reg_adapter将总线事务bus_rsp转换为相应的寄存器操作reg_bus_op(结构体)。
- 寄存器操作reg_bus_op转换为uvm_reg_item。
- 调用do_predict(),将uvm_reg_item用于更新m_mirrored和m_desired。
注:自动预测中do_predict()是由uvm_reg_field::do_write()调用;显式预测中,do_predict()有predictor.write()调用,这个write跟寄存器模型的write没有任何关系,predictor之所以有一个write函数是因为predictor与monitor之间通过TML端口通信,predictor作为IMP端口,内部必须实现write函数供monitor调用。
图解如下:下图采用显式预测
read():从指定DUT寄存器读数据
与write()方法类似,只多了一条将读取的data返回的路线,不再详述
- 创建与读操作对应的uvm_reg_item对象。
- uvm_reg_adapter将读取操作转换为相应的总线事务。
- uvm_driver执行到DUT的总线事务。
- uvm_reg_apapter将读取数据的总线事务转换为寄存器操作。
- read()方法将读取值返回给调用者。
- 同时,uvm_monitor捕获总线事务。
- uvm_reg_predictor要求uvm_reg_adapter将总线事务转换为相应的寄存器操作。
- 寄存器操作转换为uvm_reg_item。
- uvm_reg_item用于更新值,m_mirrored和m_desired属性。
请注意,如果在配置寄存器字段时individually_accessible
参数为0,则会读取包含字段的整个寄存器。在这种情况下,也会为其他字段更新m_mirrored值。
图解: