首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

SystemVerilog|UVM|Sequence这份干货太干了

Sequence可在测试用例中被用来构造不同的测试场景,可以说是UVM验证中非常重要甚至最为重要的一部分。开发并应用好sequence,可以极大地提高测试用例的开发效率和质量。

前面两篇文章已经介绍了sequence item的基本构造,以及driver和sequencer的握手机制和使用模型。本文将继续关注sequence这一主题,介绍sequence的基础内容。

本文内容包括sequence的重要成员变量和方法,怎么写sequence,sequence如何被启动,文章最后会告诉你为什么不要用default sequence。

01 Sequence重要成员和方法

uvm_sequence派生自uvm_sequence_item,它有一个重要的任务方法body()和两个重要的成员变量m_sequencer和p_sequencer后面会介绍。

body()

任务方法body()是sequence作为测试序列的主体部分,我们需要在body()方法中定义该sequence的功能和行为。

其实在body()方法的前后,分别还有pre_body()和post_body()可能会被调用。只不过大多数时候,定义在pre_body()或者post_body()方法中功能都可以直接写到body()方法中,此外,这两个方法是否被调用还取决于sequence的启动方式或参数,具有不确定性。所以,就算在成熟的UVM Testbench中也很少见对pre_body()或者post_body()方法的重写。

m_sequencer

接下来是m_sequencer成员。m_sequencer是一个指向与当前sequence“绑定”的sequencer的句柄。Sequence基本的工作流程是通过sequencer将sequence_item发送给driver,那么自然需要有一个sequencer与之关联,而m_sequencer正是关联sequence和sequencer的纽带。

除此之外,m_sequencer可以被用来访问UVM component层次结构中的其他资源或者配置信息等。但有一点需要注意,m_sequencer的类型是uvm_sequencer_base,而我们通常绑定给sequence的sequencer是uvm_sequencer_base的子类,所以,当该句柄引用子类对象时,可引用的资源将受到限制。

p_sequencer

为了解决上面提到的资源引用问题,UVM又搞了一个p_sequencer的句柄,用户可以通过宏`uvm_declare_p_sequencer来创建。

p_sequencer的类型是我们绑定给sequence的sequencer的实际类型,它会通过$cast函数去引用到m_sequencer引用的对象,这样一来,我们就可以通过p_sequencer去引用实际sequencer中的资源了。

02 怎么写Sequence

Sequence的基本结构如下图所示,主要包含五个部分:对宏的调用,sequence_item的声明,成员变量声明,构造函数,最后是在body中定义sequence的主要逻辑功能。

该示例代码不针对其他sequence的嵌套,以及virtual sequence的使用。关于对sequence的嵌套,仲裁,以及virtual sequence的使用,会在后续文章中专门介绍。

在有些代码实现中会在pre_body()中raise objection,在post_body()中drop objection。但本文不建议这么做,在Sequence中不要直接对objection进行控制,我们可以将对objection的控制统一放到测试用例顶层的位置,方便维护和调试。

另外,UVM类库还提供了uvm_do、uvm_do_with、uvm_do_pri、uvm_do_pri_with等宏用来“自动”实例化、随机化和发送sequence item。不过我仍然觉得start_item()和finish_item()已经足够简单和直观了,那些宏在编译阶段实际上也是展开成对start_item()和finish_item()的调用。

03 怎么启动Sequence

结论:Sequence启动可以用start()方法,也可以用uvm_do宏,还可以用default_sequence。但建议用start(),不建议用default_sequence。

start()方法的原型如上图所示,总共有四个参数。其中用的最多的是第一个参数sequencer,用来指定sequence运行在哪个sequencer上面。第二个参数parent_sequence,如果不指定,则表示当前sequence为根sequence;如果指定了父sequence,则sequence在运行的过程中会去调用上级sequence的pre_do(),mid_do()和post_do()函数。第三个参数是当前sequence的优先级,在多sequence的情况下会有用。第四个参数call_pre_post,默认值为1,表示sequence在运行过程中会调用pre_body()和post_body()任务。

再来看uvm_do宏,展开之后最终还是调用的start函数。区别在于有两个参数设置,parent_sequence参数配置成了this,call_pre_post参数配置成了0。uvm_do更多的是用在一个父sequence对子sequence的启动上:父sequence的do函数会被执行,同时不需要执行子sequence的pre_body()和post_body()。

之所以建议用start(),是因为宏尽管便利,但会隐藏掉一些必要的信息,比如不了解uvm_do宏展开的工程师,他就不知道pre_body()和post_body()为什么不会被执行;而如果用start(),一方面不需要关心所谓的父或子sequence的关系,可以很明确的通过配置参数来达到想要的执行内容。

04 Default_sequence

最后谈一下default_sequence的启动方式。这种启动方式来自OVM,通过将某个sequence配置为default_sequence,可以使得该sequence在仿真开始之后被自动启动。

之所以不建议用default_sequence,大致有这么一些原因:设置default_sequence是在connect_phase或者build_phase中完成,这就意味着将测试用例跟Testbench的构建混在了一起,在环境架构上不干净;使用default_sequence隐藏了太多信息,比如用户并不是很明确sequence在哪个时候被启动,甚至不知道是不是被其他同事配置了default_sequence,一旦出问题很难调试;无法在同一个sequencer上启动其他sequence,而这个需求又是经常存在的。

如果非要使用default_sequence,请重读上面一段话。

参考资料

[1] Accellera Systems Initiative. "Universal Verification Methodology (UVM) 1.2 Class Reference" (2014).

[2] Accellera Systems Initiative. "Universal Verification Methodology (UVM) 1.2 User's Guide" (2015).

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20230402A000PZ00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券