SystemVerilog中的callback机制

“randomize()”是systemverilog中的一个带有callback的内建方法。randomize方法通过在randomize()前后分别调用pre_randomize()和post_randomize()去实现callback。而验证人员往往为了最大可能性的提高验证平台的可重用性,会在验证环境中增加callback机制,从而为验证环境的使用人员提供了一个接口,可以实现对于传输的激励进行一些修改而不对原验证环境产生任何影响。本文将通过示例与大家一起探讨SystemVerilog回调机制的原理。

Callback机制是SystemVerilog面向对象特性实现的一种由程序开发者预留一个callback函数/任务接口(hook),程序使用者通过该接口实现对程序开发者开发的验证环境进行重用的一种机制,一种广义callback机制的结构示意图如下:

object_callback是一个类,其中定义了两个虚方法pre_callbackpost_callback,这两个虚方法中不包含任何内容,此处是预留给用户进行重载修改的接口方法,当用户不对object_callback进行派生时,因为pre_callbackpost_callback是空的,不会执行任何操作。验证环境的用户可以通过对object_callback进行派生后,在派生类中对pre_callbackpost_callback进行重写实现自己期望的功能逻辑而不需要对验证环境中的object_callback进行任何修改。在对pre_callbackpost_callback进行重写后,再次执行object_callback时就会执行修改后的pre_callbackpost_callback的行为。

那么如何使用SystemVerilogOOP特性构建callback机制呢?下面我们通过示例逐步实现callback

【第一步】创建回调基类 

SystemVerilog中,抽象类对于后续的扩展类除了提供可重用或覆盖的现有功能之外,抽象类对于定义扩展类的约定(即扩展类必须实现特定功能)也很有用。回调基类cbb之所以使用抽象类,因为实际使用中,将会有多个不同的子类将派生自回调基类。在回调基类中定义了回调任务(pre_fcallbackpost_fcallback),定义的回调任务(pre_fcallbackpost_fcallback)均为虚方法,并且任务体均为空,之所以定义为虚方法是为了后续扩展回调基类后,通过句柄引用时可以任务进行重载,而之所以在这里没有使用纯虚方法,是因为派生自抽象类的派生类如果要实例化必须要实现所有父类中的纯虚方法,然而实际使用时,不一定在派生类中对所有的函数(任务)进行重写。

【第二步】插入回调基类 

示例中,我们要在driver中插入回调类。首先在driver中声明类型为cbb(回调基类)的队列cbb_pool[$],用于后续存放回调基类或者其派生类。17行到19行,调用队列cbb_pool中成员的回调方法pre_fcallback22行到24行调用队列cbb_pool中成员的回调方法post_fcallback,因为在没有对回调基类进行扩展,并且也没有回调基类派生类压入队列cbb_pool中,即cbb_pool为空,所以foreach循环不会执行。后续将派生类压入队列后,当环境运行时,因为cbb_pool不为空,就会执行对应的回调方法(pre_fcallbackpost_fcallback)。此处一般为验证环境开发人员提供给验证环境用户的回调方法的入口hook

【第三部】派生回调基类 

原回调基类进行扩展,在扩展类中对回调基类中需要重写的方法进行重写,可以按照用户的需要实现特定的行为。一般情况下,该扩展类为验证环境用户根据实际情况开发。示例中分别对回调基类中的虚方法进行了重写。

【第四部】使用回调机制 

23行创建了派生类ecbb的对象,第24行将创建的对象压入driver中声明的回调基类队列cbb_pool中(这里注意,第22行到25行之所以使用begin...end主要是这里需要声明一个新的局部变量pecbb,可参考《硅心思见:【111】局部变量声明不能太随意》)。当后续程序调用driver中的方法run时,其中的cbb_pool因为不为空,就会执行此时压入队列中的pecbb,而pecbb指向的对象中方法pre_fcallbackpost_fcallback均被重写,所以此时就会执行重写后的pre_fcallbackpost_fcallback。整个过程中,验证环境的用户不需要对原有验证环境进行修改,即可在数据的传输过程中实现特定的功能。至此,一个简单的回调机制的实现就完成了。

【注意】上述示例其他代码见文末附图。

回调机制其实是使用SystemVerilog OOP实现的一种验证环境开发者向验证环境使用者提供的模块内部接口hook,是一种重要的重用机制,也是UVM中的一种重要机制,其在UVM中的实现过程与本文示例相同,但是UVM实现的过程相当复杂,但基本原理与本文示例基本相同,使用的基本操作流程也基本一样,在UVM中针对验证环境的开发者和使用者,需要分别完成以下几步以实现回调机制。此处参考《UVM实战》

【验证环境开发人员】

定义一个A类;

声明一个A_pool,用于指明该pool被哪个类使用;

typedef uvm_callbacks #(my_driver,A) A_pool;

在要预留callback方法接口的类中调用uvm_register_cb宏;

在要调用callback方法接口的方法中,使用uvm_do_callbacks宏;

【验证环境使用人员】

A类派生一个类,在派生类中定义好pre_tran

在测试用例的connect_phase(或者其他phase中,但是一定要在验证环境开发步骤第4步中使用此回调方法的phase之前)将从A派生的类实例化,并将其加入A_pool中;

【本文callback示例中剩余代码如下】

// 待测设计,为一个空壳


// env,包含driver以及一些task


// generator产生数据

// interface

// package,包含环境里所有的代码

// 传输的数据包

全部评论

相关推荐

rbjjj:太杂了吧,同学,项目似乎都没深度,都是api调度耶,分层架构思想没有体现出来了,前端没有前端优化前端工程化体现,后端微服务以及分层架构没体现以及数据安全也没体现,核心再改改,注重于计算机网络,工程化,底层原理吧
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务