文章目录
1. 寄存器模型概览
一些简单的脚本可以保住我们生成寄存器模型。
- 寄存器模型的优点?
- 发送激励;利用RAL可以对DUT寄存器做测试;完成寄存器读写的覆盖
- DUT中所有的寄存器都要在软件中实现,这里的map包括寄存器的地址信息。
- 这里的Reg initiator好像是adapter
- 如何抽象出层次化的寄存器列表
- 如何通过寄存器模型访问DUT寄存器
1.1 寄存器中心化管理方式
- 寄存器信息是一个高度格式化的东西,中心管理形成单一权威的寄存器解释,可减低出错可能。
- 寄存器描述文件可以抽取生成.doc文件,便于阅读
1.2 uvm_reg相关概念
- uvm_reg_field的有效位通常是rand,定义后需要创建,并config赋予其特性
- 问题:寄存器模型的随机化最终随机的是寄存器各个域,为啥要随机化?
- 这里有一个函数是build,不是build_phase,只有component才会有phase的概念。寄存器模型是object。这里只是功能相似,所以也叫build。
- 第二个参数为位宽、第三为起始位,第四属性,第五复位值
- 构建好了uvm_reg后,使用uvm_reg_block做集成,首先定义了各个通道的ctrl_reg/stat_reg以及uvm_reg_map,然后在build_phase中对各个寄存器再次build,这里会调用之前定义寄存器class时候的build函数对寄存器中各个寄存器域,同时还有configure,是为了指明寄存器的父类。
- 这里必须手动调用寄存器的build函数,可见当寄存器多了时候这种方法很容易出错,因此常用脚本生成寄存器模型。
- uvm_reg_block还对map进行了创建,明确寄存器组的基地址('h0),偏移地址,大小端访问。
- 添加寄存器,最后锁定寄存器模型(不允许外部访问改变,只能通过寄存器预测做改变)
1.3 寄存器建模
- 可见寄存器模型有三个优势 :
- 生成测试序列,可读复用强
- DUT寄存器覆盖率
- 寄存器模型检查
2. 寄存器模型集成
2.1 总线UVC实现
- 可以看到这里用到了run_phase,一般driver和monitor仿真时始终在运行,根据其他component的举手放手决定是否结束。不需要自己举手。
- monitor要从virtual_interface上面监控总线的行为。analysis_port将读到的trans写入通往uvm_predictor的fifo
- 这里使用analysis_port写trans时候用fork join_none,是因为在写trans到fifo的时候不希望错过再次的读写命令。
- 接下来是driver:
- driver是一个参数类,这里没有指定参数,因此需要先定义一个tmp,其类型是sequence_item,若声明了类型参数可以直接使用,那就是声明的trans类型。
- 父类的句柄要转到子类中。
2.2 adapter实现
- 到目前为止,上图中的寄存器模型和DUT已经实现,bus agent也有了。还剩下adapter和predictor。
- 在无adapter时,DUT寄存器访问是外挂一个sequence,通过sqr/driver将一个trans发送到DUT
- 现在通过寄存器模型,借助adapter,将uvm_reg_item的trans映射为bus_seq_item的trans,再对DUT进行读写访问(图中包含bus_seq_item的箭头应该是双向的)
- reg2bus、bus2reg是预定义的两个函数,我们必须实现。
- 既然是既定的方法,那函数声明要一字不差。
- reg2bus是子类的句柄返回,子类句柄变为父类句柄,隐转换。
- bus2reg是父类的句柄用cast显式转为子类句柄,之后就可以访问子类对象并赋值给rw对象
2.3 adapter集成
- if(!uvm_config_db#(mcdf_rgm)::get(this,"",“rgm”,rgm))begin是为了检测看顶层有没有给我们传递一个寄存器模型,没有就创建,若有就使用顶层传递来的rgm即可(一般是有,在test里面例化了rgm,然后传递进environment)
- rgm.build,创建reg并config
- connect_phase中,将存储了各个寄存器信息的map与adapter相关联,adapter又和agent.sequencer相关联。三者之间通信是双向的。
- 在验证时,我们不仅要对DUT的寄存器进行读写,也要使得软件中寄存器模型中的寄存器值和DUT中的保持一致(DUT中寄存器值也要映射或者说预测到寄存器模型中),然后参考模型才可以根据寄存器模型中寄存器值采取相应的动作模拟DUT的行为。
- predictor拿到monitor检测到的bus_trans,同时又有adapter的句柄,那么predictor就可以调用adapter的bus2reg函数转化为reg_item从而更新寄存器模型中reg值。
- 当然没有predictor也可以更新寄存器模型中reg值,即上面代码中的set_auto_predict,当模型向DUT发送寄存器访问时自动更新模型中的值而不去依赖从总线中检测到的trans,也不依赖monitor。(往往不使用,预测不准:1、未必通过总线成功写入DUT寄存器;2、除了向DUT写入,还会读取其中状态REG,那就没法做自动预测)通常实际例化一个predictor。
2.4 寄存器模型访问方式
- 后面访问优势:速度快,不消耗时间。是仿真器提供的便利。
2.4.1 前门访问
- 方式1:uvm_reg自带的读写方法,通过寄存器模型.寄存器名.读写方法 对DUT进行读写寄存器。
- 方式2:借助uvm_reg_sequence(必须继承于它),使用read_reg/write_reg
2.4.2 后门访问
- peek默认是后门访问读,poke默认是后门访问写
2.4.3 前后门访问区别
- 若几个寄存器直接有时序关系,那后门访问可能会扰乱时序。