UVM——寄存器应用场景

本文介绍了UVM如何应用于寄存器的检查和功能覆盖率描述,包括寄存器检查的不同方法,如从前门和后门读写,以及如何在寄存器模型中实现覆盖率自动收集和外部事件触发收集。强调了寄存器模型在验证硬件设计和配合scoreboard检查DUT功能的重要性,同时讨论了自定义覆盖率类以满足实际验证需求。
摘要由CSDN通过智能技术生成

寄存器应用场景

在了解了寄存器模型的常规方法之后,我们需要考虑如何利用这些方法来检查寄存器、以及协助检查硬件设计逻辑和比对数据。在软件实现硬件驱动和固件层时,也会实现类似寄存器模型镜像值的方法,即在寄存器配置的底层函数中,同时也声明一些全局的影子寄存器(shadow register) 。这些影子寄存器的功能就是暂存当时写入寄存器的值,而在后期使用时,如果这些寄存器是非易失的non-volatile),那么便可以省略读取寄存器的步骤,转而使用影子寄存器的值。这么做的好处在于响应更迅速,而不再通过若干个时钟周期的总线发起请求和等待响应,但另外一方面这么做的前提同我们测试寄存器模型的目的是一样的,即寄存器的写入值可以准确地反映到硬件中的寄存器。
利用寄存器模型的另外一个场景是,在对硬件数据通路做数据比对时,需要及时地知道当时的硬件配置状况,而利用寄存器模型的镜像值可以实现实时读取,而不需要从前门访问。相对的,后门访问也可以在零时刻内完成,只是这么做会省略检查寄存器的步骤,即假设寄存器模型的镜像值同硬件中的寄存器真实值保持一致,而这一假设存在验证风险。所以只有这么做,才能为后期软件开发时使用影子寄存器扫清可能的硬件缺陷。寄存器模型不但可以用来检查硬件寄存器,也可以用来配合scoreboard实时检查DUT的功能。

寄存器检查

用来检查寄存器时,我们总结出下面几种可行的方式:
- 从前门写,并且从前门读。这种方式最为常见,但无法检查地址是否正确映射。
- 从前门写,再从后门读。即利用write()实现前门写,再使用read()或者peek()从后门读。
- 从后门写,再从前门读。即利用write()或者poke()从后门写,再利用read()从前门读。
- 对于一些状态寄存器(硬件自身信号会驱动更新其实际值),先用peek()来获取(并且会调用predict()方法来更新镜像值),再调用mirror()方法来从前门访问并且与之前更新的镜像值比较。
上面的这些方法,在寄存器模型的内建序列中都已经实现。与内建序列相比,自建序列可以更灵活,更贴近需求,但需要消耗更多的人力;内建序列使用简单,是全自动化的方式,但考虑到一些特殊的寄存器,在使用内建序列测试前,用户需要对一些寄存器设定“禁止域名”来将其排除在特定的寄存器检查范围以外。
在配合scoreboard实施检查DUT的功能时,需要注意:
- 无论是将寄存器模型通过config_db进行层次化配置,还是间接通过封装在配置对象(configuration object)中的寄存器模型句柄,都需要scoreboard可以索引到寄存器模型。
- 在读取寄存器或者寄存器域的值时,用户需要加以区分。不少初学者默认uvm_reg类中应该对应有类似value的成员来表征其对应硬件寄存器的值,然而并没有。
- uvm_reg并不是寄存器模型的最小切分单元,uvm_reg_field才是。
- uvm_reg可以理解为uvm_reg_field的容器,一个uvm_reg可以包含多个顺序排列的uvm_reg_field。
- 在取值时,用户可以使用uvm_reg_field的成员value直接访问,但更建议使用uvm_reg类和uvm_reg_field类都具备的接口函数get_mirrored_value()。

功能覆盖率描述

在测试寄存器以及设计的某些功能配置模式时,我们也需要统计测试过的配置情况。就MCDF寄存器模型来看,除了测试寄存器本身,我们还需要考虑在不同的配置下,设计的数据处理、仲裁等功能是否正确,所以我们需要放置功能覆盖率在寄存器模型中。由于寄存器描述文件的结构化,我们可以通过扩充寄存器模型生成器的功能,使得生成的寄存器模型也可以自动包含各个寄存器域的功能覆盖率。UVM的寄存器模型已经内置了一些方法用来使能对应的covergroup,同时在调用write()或者read()方法时,会自动调用covergroup::sample()来完成功能覆盖率收集。

覆盖率自动收集模式

如果寄存器模型生成器可以一并生成covergroup和对应的方法,我们就可以考虑是否例化这些covergroup、以及何时收集这些数据。从示例中摘出的ctrl_reg寄存器扩充的定义部分来看,value_cg是用来收集寄存器中所有的域(包含reserved只读区域)。由于covergroup在此模式下可以自动生成,并且在使能的情况下,可以在每次read()write()方法后调用。从例化时的内存消耗、以及每次采集时的内存消耗,从上百个寄存器内置的covergroup联动的情况出发,是否例化、是否使能采样数据都需要考虑。在验证前期,可以不例化covergroup,保证更好的资源利用:在验证后期需要采集功能覆盖率时,再考虑例化、使能采样。
在ctrl_reg的构建函数中,通过has_coverage()来判断是否需要例化的。该方法会查询成员ctrl_reg::m_has_cover,是否具备特定的覆盖率类型,而该成员在例化时,已经赋予了初值UVM_CVR_ALL,即包含所有覆盖率类型,因此,value_cg可以例化。
在新扩充的sample()和sample_values()两个方法时:
- sample()可以理解为read()write()方法的回调函数,用户需要填充该方法,使得可以保证自动采样数据。
- sample_values()是供用户外部调用的方法,在一些特定事件触发时,例如中断、复位等场景,用户可以在外部通过监听具体事件来调用该方法。
sample_values()方法中,可以通过get_coverage()方法来判断是否允许进行覆盖率采样。用户可能容易将has_coverage()get_coverage()等方法混淆,就这两个方法而言,前者指是否具备对应的covergroup,后者指是否允许使用对应的covergroup进行采样。

//实例
class ctrl_reg extends uvm_reg;
	'uvm_object_utils(ctrl_reg)
	uvm_reg_field reserved;
	rand uvm_reg_field pkt_len;
	rand uvm_reg_field prio_level;
	rand uvm_reg_field chnl_en;
	covergroup value_cg;
		option.per_instance = 1;
		reserved: coverpoint reserved.value[25:0];
		pkt_len: coverpoint pkt_len.value[2: 0];
		prio_level: coverpoint prio_level.value[1:0];
		chnl_en: coverpoint chnl__en.value[0:0];
	endgroup
	function new(string name = "ctrl_reg");
		super.new
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值