[验证百花筒] 聊聊模块级寄存器模型如何复用到系统级
1. 引言
这篇文章主要应某位粉丝的要求写的,主要从应用角度讲解如何把模块级的寄存器模型复用到系统级,就不去细究UVM源码的实现原理了,所以就没有放在[UVM源代码分析]的专栏里。
寄存器模型有个很基础的概念,就是寄存器模型本身是与接口协议无关的,它只跟spec定义的寄存器地址位宽、读写属性、默认值相关,所以同样一套寄存器模型可以用在多种接口实现上,接口的类型主要体现在uvm_reg_adapter的实现上。所以我们在做SOC开发时,模块级的寄存器实现可能是通过apb或者mdio等串口进行访问的,但是到了系统级的访问接口有可能就换成了AHB或者AXI等高速接口,但是对于寄存器模型本身而言不需要做任何的修改可以直接复用,只需要把对应的adapter换掉即可。
本文以ahb2apb_adapter的环境为例,介绍下sub_system的环境中,如何将模块级的两个子环境spi和uart的模块级寄存器模型复用到sub_system中。
2. 验证环境背景介绍
本sub_system验证环境分别包含了3个模块级的验证环境,分别spi、uart和ahb2apb_bridge,其中spi和uart定义了自己模块的寄存器,需要使用寄存器模型,ahp2apb_bridge模块只做接口ahb到apb的转换,没有定义寄存器,不需要寄存器模型。
2.1 模块级验证环境
图1-图3分别为三个模块级验证环境的框图。
图1 spi验证环境
图2 uart验证环境
图3 ahb2apb_bridge验证环境
如此一来我们在spi和uart这两个模块级的验证环境中就需要使用到各自的寄存器模型,并且相应的adapter为apb_adapter。对应的模块级验证环境包含的文件package分别如图4-图5所示。
图4 spi验证环境package
图5 uart验证环境package
这里我们把模块级验证环境需要复用的内容打包成独立的package文件,这样在顶层要复用的时候直接将对应的package文件编译了之后再import即可,这样方便进行文件版本的升级维护和统一管理。testcase相关的内容(从uvm_test继承的包括test_base等文件)无法直接复用,因而没有放在env_pkg中。
两个模块级验证环境中寄存器模型都是直接放在env_pkg中进行编译的,而adapter由于是与接口直接相关的,所以打包到了对应的接口package中,本例中的两个模块级环境都是通过apb接口访问寄存器的,所以相应的adapter就放在了apb_pkg中,apb_pkg中就包含了apb相关的vip代码以及寄存器适配器模块apb_adapter,如图6所示。
图6 apb_pkg内容
2.2 模块级验证环境到系统级的复用
模块级spi和uart的寄存器接口apb到了系统级变成了内部接口,从ahb2apb_bridge模块输出,ahb2apb_bridge模块根据ahb接口访问的地址决定选中哪一个spb_slave进行访问,也就是说spi和uart这两个apb_slave模块在模块级时,寄存器地址都是从0开始排布,但是到了系统级各自又加上了一个系统级地址空间的基地址,这个由系统架构设计时决定,因而spi和uart寄存器的地址由分别有module_base_addr+offset_addr决定,offset_addr就是模块级定义的寄存器地址。本例中我们给spi分配的基地址为32’h0000,给uart分配的基地址为32’h1000,这在我们产生系统级寄存器模型的时候会使用到,系统级寄存器模型如图7所示。
图7 系统级寄存器模型
可以看到系统级寄存器模型中通过include宏将模块级定义的两个寄存器模型复制过来,分别例化到了一个新定义的寄存器模型中,这个新定义的寄存器模型就是系统级顶层寄存器模型,顶层寄存器模型并不会定义新的寄存器,而只是作为存放模块级寄存器模型的一个容器,并且将模块级寄存器的base_address分别作为submap添加到顶层寄存器模型的default_map中。这样我们在系统级验证环境中只需要仿照模块级验证环境创建寄存器模型一样创建顶层寄存器模型,模块级寄存器模型也会在调用顶层寄存器模型的build()函数时被创建。我们通过hierarchy调用的方式访问模块级寄存器模型时,寄存器接口地址会自动转化为对应寄存器的base_addr+offset_addr去访问对应的总线接口,系统级寄存器创建的代码示例如图8所示。
图8 系统级验证环境寄存器模型的使用代码实例
可以看到模块级除了使用adapter由apb_adapter换成了ahb_adapter,其他代码几乎一模一样。
还可以在顶层的virtual_sequencer中分别定义模块级验证环境的寄存器模型句柄然后在connect_phase分别连接到对应的寄存器模型,这样在virtual_sequence中通过p_sequencer引用寄存器模型时就可以少一个层次。
sub_system集成模块级验证环境时的package如图9所示,仅供参考。这里可以看到模块级的相关代码直接通过package import进来了,在编译时确保相关需要import的package提前编译好,这样其实模块级的寄存器模型就已经提前编译好了,图7中include的两个寄存器模型也可以不需要了,为了防止重复编译的问题,我们一定要养成良好的编程习惯,在class定义的文件前面要加上 ifndef ...
define … ,最后加上`endif 这段宏定义。
图9 系统级验证环境package文件
如此一来,我们便换成了模块级寄存器模型到系统级的复用。
3. 总结
本文以代码示例介绍了UVM中模块级寄存器模型到系统级复用的方法,其实本质上就是将原来定义的寄存器模型例化在一个顶层寄存器模型中,将原来模块级验证环境build_phase创建寄存器模型的代码搬到顶层寄存器模型的build()函数中,通过add_submap将模块级寄存器的基地址添加到顶层寄存器模型的default_map中即可。使用方法跟模块级寄存器没什么太大的区别,其实本文不仅仅介绍了寄存器模型从模块级到系统级的复用方法,还提到了整个模块级的验证环境到系统级的复用思路,那就是以package的形式打包相关需要复用的代码,这一点大家自己去领悟吧,如果有需要的话,后面我可以再以同样的项目为例,介绍下整个验证环境的复用思路以及在进行模块级环境验证时如何提前规划好验证代码的复用思路。