使用背景:DUT有一组控制端口,通过控制端口,配置DUT中的寄存器,DUT可以根据寄存器的值来改变行为,这组控制端口称为寄存器配置总线。
我们需要在参考模型中读取寄存器的值,然后在参考模型对该值输出的transaction做寄存器相同的操作。问题在于如何在参考模型中读取一个寄存器的值?
初步设想通过bus_driver向总线发送读指令,并给出要读的寄存器地址。需要启动一个sequence,该sequence发送transaction给bus_driver。
那么就需要考虑两个问题:
1、如何在参考模型的控制下启动sequence读取寄存器?
2、sequence读取的寄存器的值如何传递给参考模型?
这个过程可以用寄存器模型来实现,启动sequence和读取结果返回这些操作都将由寄存器模型自动完成。
没有rgm之前,只能通过启动sequence进行前门访问读取寄存器,在scoreboard中难以控制。
而有了rgm之后,scoreboard只与寄存器模型打交道,发送读指令和获取读操作的返回值都可以由寄存器模型完成。可以在任何耗时的phase中使用rgm进行前门/后门访问获取寄存器的值;也可以在不耗时phase中进行后门访问来读取寄存器的值。

基本概念
uvm_reg_field(药丸):寄存器的域,是rgm中最小的单位。
uvm_reg(小瓶子):寄存器,比reg_field高一个级别,一个寄存器中最少包含一个域。
uvm_reg_block(大箱子):在块中可以加入很多寄存器,也可以加入其他块,一个rgm最少包含一个块。
uvm_reg_map:寄存器在加入rgm时都有地址,reg_map用于存放这些地址,并将其转换为可以访问的物理地址,寄存器存入rgm的地址都是偏移地址,基地址+偏移地址=绝对地址。当rgm使用前门访问的方式实现读/写操作时,reg_map就会将偏移地址转换为绝对地址,启动读/写sequence,并将读/写的结果返回。
简单的寄存器模型
只有一个寄存器的rgm
从uvm_reg中派生出一个reg类,在reg类中rand声明uvm_reg_field。每个派生自uvm_reg的类都有一个build函数,这个build不同于component的build_phase(),它不会自动执行也不会构建树形结构(rgm是object),必须要手工调用,但是功能是一样的,就是在其中将所有的uvm_reg_field进行实例化,然后通过configure函数进行配置。
然后在new函数中传递寄存器的总位数,总位数一般与系统总线宽度一致。

定义好uvm_reg寄存器后,在uvm_reg_block块派生的类中对其实例化,同之前一样,定义build函数,声明例化,配置,手动调用寄存器的build函数,在这里需要注意的是一个uvm_reg_block中一定要对应一个uvm_reg_map,一般用系统声明好的default_map即可,别忘记将寄存器加入到default_map中,使用add_reg函数,因为uvm_reg_map需要存储所有寄存器的地址,因此必须将实例化的寄存器加入到default_map中,否则无法进行前门访问。
总结一下建模过程:
1. 声明各个寄存器,并对寄存器中各个域进行build和configure。
2. 在uvm_reg_block中声明各个寄存器,添加uvm_reg_map。
3. 在uvm_reg_block的build函数中例化配置并调用各个寄存器的build函数。
4. uvm_reg_map 例化,并将各个寄存器加入到uvm_reg_map中。
5. lock_model,防止外部的修改。


文章详细介绍了如何在参考模型中读取和操作寄存器,包括通过寄存器模型实现前门和后门访问,以及如何启动sequence读取寄存器值。此外,还讨论了DPI-VPI接口在后门访问中的应用,以及寄存器模型的层次化和复杂情况下的构建方法。
4409

被折叠的 条评论
为什么被折叠?



