| ||
mem与reg的联系和差别
UVM寄存器模型也可以用来对存储建模。uvm_mem类可以用来模拟RW(读写)、RO(只读)和WO(只写)类型的存储,并且可以配置其模型的数据宽度和地址范围。而uvm_mem不同于uvm_reg的地方在于,考虑到物理存储一旦映射到uvm_mem会带来更大的资源消耗,因此uvm_mem并不支持预测和影子存储(shadow storage)功能,即没有预期值和期望值。uvm_mem可以提供的功能就是利用自带的存储访问方法去访问硬件存储,相比于直接利用硬件总线UVC进行访问,这么做的好处在于:
类似于寄存器模型访问寄存器,利用存储模型访问硬件存储便于维护和复用。
在访问过程中,可以利用模型的地址范围来测试硬件的地址范围是否全部覆盖。
由于uvm_mem也同时提供前门访问和后门访问,这使得存储测试可以考虑现在先期通过后门访问预先加载存储内容,而后通过前门访问读取存储内容,继而做数据比对,这样做不但节省时间,同时也在测试方式上保持了前后一致性(即只需要选择后门访问还是前门访问)。这种方式与传统的测试方式,即利用系统函数或者仿真器函数实现存储加载,要在UVM的测试框架中更为统一。
与uvm_reg相比,uvm_mem不但拥有常规的访问方法read()、write()、peek()和poke(),也提供了burst_read()和burst_write()。之所以额外提供这两种方法,不但是为了更高速地通过物理总线BURST方式连续方法存储,也是为了尽可能贴合实际访问存储中的场景。要实现BURST访问形式,需要考虑下面这些因素:
目前挂载的总线UVC是否支持BURST形式访问,例如APB不能支持BURST访问模式。
与read()、write()方法相比,burst_read()和burst_write()的参数列表中的一项uvm_reg_data_t value[]采用的是数组形式,不再是单一变量,即表示用户可以传递多个数据。而在后台,这些数据首先需要装载到uvm_reg_item对象中,装载时value数组可以直接写入,另外两个成员需要分别指定为element_kind = UVM_MEM,kind = UVM_BURST_READ。
在adapter实现中,也需要考虑到存储模型BURST访问的情形,即需要考虑到四种访问类型(uvm_access_e)下的转换,即UVM_READ、UVM_WRITE、UVM_BURST_READ和UVM_BURST_WRITE。对于UVM_READ和UVM_WRITE的桥接,已经在寄存器模型访问中实现,而UVM_BURST_READ和UVM_BURST_WRITE的转换,往往需要考虑写入的数据长度和,例如长度是否是4、8、16或者其它。譬如AHB总线,支持连续4个、8个、16个数据的读写(INCR4、INCR8、INCR16),但是如果数据长度不是这些固定长度时,adapter还需要自己处理来实现INCR的连续访问方式。
此外,还需要考虑不同总线的其它控制参数,例如AHB支持WRAP模式,AXI支持out-of-order模式等,如果想要将更多的总线控制封装在adapter的桥接功能里,需要将更多的配置作为扩展配置,在调用访问方法时,一并传入到参数uvm_object extension。待传入后,adapter将可以在桥接方法中抽取出额外的配置,作为选择更准确的协议访问的限定依据。
对于更为复杂的BURST形式,如果需要实现更多的协议配置要求,那么路桑推荐直接在总线UVC层面去驱动。这样做的灵活性更大,且更能充分全面的测试存储接口的协议层完备性。因此,verifier在为存储模型访问实现adapter方法时,需要考虑的是,uvm_mem层面的方法应该尽量便捷、必要的参数少,以便于使用和维护;而另外一方面,如果要首先测试存储接口,则应该在总线UVC的层面上更充分的完成验证。
内建(built-in)sequences
不少有经验的UVM用户可能会忽略UVM针对寄存器模型内建的一些sequence,实际上如果可以将这些自建的序列作为验证项目一开始的健康检查必选项的话,这对于整个项目的平稳运行会有不小的贡献。这是因为在项目一开始的阶段,设计内部的逻辑还不稳定,对于verifier而言,如果想要同步跟上设计的进度,可以展开验证的部分无外乎是系统控制信号(时钟、复位、电源)和寄存器的验证。在早期时,寄存器模型的验证可以为后期各个功能点验证打下良好的基础。比如,通过内建的寄存器或者存储序列可以实现完善的寄存器复位值检查,又比如检查读写寄存器的读写功能是否正常等。
不过有一些寄存器即便可以测试,也建议将其作为例外而过滤出去,例如一些重要的系统控制信号(时钟、复位、电源),当写入某些值以后,会使得系统全部或者局部复位、时钟也可能被关闭,这就可能阻碍寄存器的下一步检查。所以UVM提供了一些特殊域,用来禁止一些sequence检查这些寄存器或者存储。接下来,我们来浏览整理出来的寄存器和存储相关的自建sequence。
寄存器模型内建序列
存储模型内建序列
接下来我们给出一段例码,继之前MCDF测试寄存器的例子,用来演示如何利用内建序列完成寄存器测试一开始的健康检查。下面的例码分别添加了uvm_reg_hw_reset_seq、uvm_reg_bit_bash_seq和uvm_reg_access_seq来测试寄存器模型,从代码的整洁性来看,用户并不需要额外再添加什么,这种使用方式非常方便,且又能完成寄存器的大规模集成测试。
对于一些寄存器,如果像将其排除在某些内建序列测试范围之外,用户可以额外添加上面列表中提到的“禁止域名”。由于uvm_reg_block和uvm_reg均是uvm_object类而不是uvm_component类,所以可以使用uvm_resource_db来配置“禁止域名”。下面的代码摘自mcdf_rgm::build()方法,这相当于寄存器模型在自己的建立阶段设定了一些属性,当然,uvm_resource_db的配置也可以在更高层指定,只不过考虑到uvm_resource_db不具备层次化的覆盖属性,我们建议只在一个地方进行“禁止域名”的配置。
下一节我们将进入本章的最后一部分《寄存器模型的场景应用》,即考虑寄存器模型在集成中的功能检查和覆盖率采集。
谢谢你对路科验证的关注,也欢迎你分享和转发真正的技术价值,你的支持是我们保持前行的动力。