路科验证的个人空间 https://blog.eetop.cn/1561828 [收藏] [复制] [分享] [RSS]

空间首页 动态 记录 日志 相册 主题 分享 留言板 个人资料

日志

UVM寄存器篇八:寄存器模型的场景应用(终)

已有 3916 次阅读| 2018-5-20 13:48 |个人分类:验证系统思想|系统分类:芯片设计

如何检查寄存器模型

在了解了寄存器模型的常规方法之后,我们需要考虑如何利用这些方法来检查寄存器、以及协助检查硬件设计的逻辑和数据比对。要知道,在软件实现硬件驱动和固件层时,也会实现类似寄存器模型镜像值的方法,即在寄存器配置的底层函数中,同时也声明一些全局的影子寄存器(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寄存器模型来看,除了测试寄存器本身,我们还需要考虑在不同的配置模式下,设计的数据处理、仲裁等功能是否正确,所以我们需要安置功能覆盖率covergroup在寄存器模型中。由于寄存器描述文件的结构化,我们可以通过扩充寄存器模型生成器(register model generator)的功能,使得其生成的寄存器模型也可以自动包含各个寄存器域的功能覆盖率采集。UVM的寄存器模型已经内置了一些方法用来使能对应的covergroup,同时在调用read()或者read()方法时,会自动调用covergroup::sample()的方法来完成收集收据。接下来我们就给出两种可供选择的方式,来实现寄存器功能覆盖率收集。


内部自动收集模式

如果寄存器模型生成器可以一并生成covergroup和对应的方法,我们就可以考虑是否例化这些covergroup、以及何时收集这些数据。从例码中摘出的ctrl_reg寄存器扩充的定义部分来看,value_cg是用来收集寄存器中所有的域(包含reserved只读区域),而要例化value_cg、以及何时采集数据,我们需要在实现的过程中考虑下面几点:

  • 由于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()是供用户外部调用的方法,在一些特定的事件触发时,例如中断、复位等场景,用户可以在外部通过监听具体事件来主动调用该方法,即ctrl_reg::sampel_values()。

  • 在sample_values()方法中,可以通过get_coverage()方法来判断是否允许进行覆盖率采样。用户可能容易将has_coverage()与get_coverage()等方法混淆,就这两个方法而言,前者指的是是否具备对应的covergroup,后者指的是是否允许使用对应的covergroup进行采样。UVM将方法设计的如此多样(或者说别出心裁),在这儿我们要体会它的良苦用心,即对是否例化、以及是否采样做双重的管理,以此来尽量降低由于覆盖率采样对验证环境运行效率的负面影响。与这些方法类属的方法还包括有set_coverage()和include_coverage(),读者可以参考源代码或者类手册。




借助于寄存器描述文件的良好格式,寄存器模型生成器都可以通过模板的形式来生成可以控制例化和采样的寄存器模型。如果用户自己在开发寄存器模型生成器时,也可以考虑是否通过上述参考的变量形式来控制,或者在生成时导入一些特定的编译导向(compiler directive),例如`ifndef的语句块来判断是否需要将寄存器的covergroup进行编译。这些方法的目的都是为了更灵活的选择是否需要例化并采样数据,以此来保证仿真性能。


事件触发外部收集模式

自动收集覆盖率的形式,不够灵活,而且不是很贴合实际场景。不灵活的地方在于,它默认会采样所有的域,包括那些保留域(reserved field),又或者对某一个域,为2位时,它会自动分配bin_0、bin_1、bin_2和bin_3来对应4个可能的值,殊不知可能val_3是违法的(illeagal bin),又或者采样上述的状态寄存器中的域fifo_avail[7:0],那么是否要采集从0到63的所有可能值才能保证此域的完备性呢?另外,不贴合实际场景的地方在于,它不够“智能”,无法组合出更有意义的运用场景,例如在实际场景下,我们需要考虑3个通道是否同时使能、同时关闭、又或者有的使能有的关闭这种组合情形?3个通道在使能时,是否考虑到了不同优先级、相同优先级、又或者两个通道相同优先级、一个通道不同优先级的情况?例如这种组合的场景,我们更应该在后期测试时考虑是否覆盖到。因此,路桑建议,更贴合实际的、可作为覆盖率验收标准的covergroup定义还当采取自定义的形式,一方面来限定感兴趣的域和值、一方面来指定感兴趣的采样事件,即在合适的事件、来触发采样,通过这种方式,最后可以形成寄存器功能覆盖率验证完备性的签收标准。


下面,我们就着之前的例码,自定义一个覆盖率类,其中嵌入了对应的covergroup,以及指定的采样事件。这段例码中,定义了类mcdf_coverage,继承于uvm_subscriber,这么做的便利在于先听准备了一副“耳朵”,用来订阅从其它地方传来的信息。这里的信息稍后来自于mcdf_bus_monitor,来接信息的方式也将通过mcdf_bus_monitor的uvm_analysis_port,发往mcdf_coverage的uvm_analysis_export。在mcdf_coverage::reg_value_cg的覆盖率定义中,不但指定了对各个寄存器感兴趣的域和值范围,也将各个相关的coverpoint进行cross组合,构成更复杂的场景实现要求。在覆盖率的采集事件中,我们就利用了mcdf_bus_monitor监听到的前门访问读写事件来作为触发事件,对数据进行采样。当然,这种采样的方式也可以扩展,通过内置其它的可同步的组件,例如uvm_event对中断等特殊事件进行寄存器采样。




在了解了寄存器描述文件、如何生成和集成寄存器,也掌握了寄存器模型的常规方法、了解如何完成寄存器测试和功能覆盖率收集之后,本书关于UVM的章节就结束了。下一章,我们将进入UVM的高级话题之一《验证平台自动化篇》。


谢谢你对路科验证的关注,也欢迎你分享和转发真正的技术价值,你的支持是我们保持前行的动力。



点赞

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 注册

  • 关注TA
  • 加好友
  • 联系TA
  • 0

    周排名
  • 0

    月排名
  • 0

    总排名
  • 0

    关注
  • 253

    粉丝
  • 25

    好友
  • 33

    获赞
  • 45

    评论
  • 访问数
关闭

站长推荐 上一条 /1 下一条

小黑屋| 关于我们| 联系我们| 在线咨询| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-4-26 03:34 , Processed in 0.013220 second(s), 12 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
返回顶部