前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >UVM(十三)之callback

UVM(十三)之callback

作者头像
瓜大三哥
发布2018-02-26 15:05:58
2.3K0
发布2018-02-26 15:05:58
举报
文章被收录于专栏:瓜大三哥瓜大三哥

在UVM验证平台中,callback的最大用处就是提高验证平台的复用性。很多情况下,我们期望在一个项目中开发的验证平台能够用于另一个项目。但是,通常来说,完全复用是非常难实现的,两个不同的项目之间或多或少有一些差异。如果把两个项目不同的地方使用callback来做,而把相同的地方写成一个完整的env,这样复用时,env可以完全的复用,只要改变相关的callback即可。

1. callback简介

先来看一个最贱的callback函数。前面介绍过的mac_trransaction为例:

这个transaction的最后一个字段是crc校验信息,这个信息必须在整个transaction的数据都固定之后才能计算出来。

执行前两句之后,tr中的crc字段的值是一个随机的值,我们要把其设置成真正的反正这个transaction数据的crc信息,需要在randomize()之后调用一个calc_crc,calc_crc是一个自定义的函数。

这个调用calc_crc的过程有点繁琐,因为每次randomize之后都要调用一次,如果有一次,忘记调用了,这很可能会成为验证平台的一个隐患,非常隐蔽,不容易发现。我们期望有一种方法,能够在randomize之后自动调用calc_crc函数。randomize是systemverilog提供的一个函数,同时systemverilog还提供了一个post_randomize()函数,当randomize之后,系统会自动调用post_randomize函数,像如上的三句话,执行时实际上如下:

其中tr.post_randomize是自动调用的,所以如果能够定义post_randomize函数,在其中执行calc_crc函数,那么就可以达到我们的目的了:

像上面的post_randomize就是systemverilog提供的一个callback函数。这也是最简单的callback函数。

2. callback:让一切丰富多彩

世界是丰富多彩的,而程序又是固定的。程序的设计者不是程序的使用者,所以作为程序的使用者来说,总是希望能够程序的设计者提供一些接口来满足自己的应用需求。作为这两者之间的一个协调,callback就出现了。如上面所示的例子,如果systemverilog的设计者一意孤行,他将会只提供randomize函数,此函数执行完成之后就完成任务了,不坐任何事情。幸运的是,他听取了用户的意见,加入了一个post_randomize的callback函数,这样可以让用户实现各自的想法。

3. UVM中的callback

上面讲述了一个最简单的callback,那是systemverilog中自带的callback。考虑下面这个callback:

假设这是一个VIP中的driver,考虑如何实现这个pre_tran这个callback呢?它应该是mii_driver的一个函数(任务)。如果按照上面的post_randomize的经验,那么我们应该从mii_driver派生出一个类来,然后重写pre_tran这个函数(任务)。这种想法是行不通的,因为这是一个完整的VIP,我们虽然从mii_driver派生了一个类,但是这个VIP中正常运行时使用的依然是mii_driver,而不是它的派生类。所以pre_tran从来不会运行。

为了解决这个问题,UVM中新引入了一个类:

这样的话,就可以避免把mii_driver重新定义一次,我们只需要重新定义A的pre_tran就可以了。重新派生A的代价是要远小于mii_driver的。

在使用的时候,我们只要从A派生一个类,然后把这个类实例化,重新定义其pre_tran函数,于是callback的目的就达到了。看起来一切顺利,但是忽略了一点。因为我们从A派生了一个类,把它实例化,但是作为mii_driver来说,怎么知道A派生了一个类呢?又怎么知道A实例化了呢?为了应付这个问题,UVM中又引入了一个类,假设这个类称为A_pool,意思就是专门存放A或者A的派生类的一个池子。我们约定会执行这个池子中所有实例的pre_tran函数(任务),即:

这样在使用的时候,只要从A派生一个类,把其实例化,并加入到A_pool中,那么系统运行到上面的foreach(A_pool[i]) 语句时,会知道加入了一个实例,于是就会调用pre_tran函数(任务)。有了A和A_pool,真正的callback就可以实现了。UVM中的callback机制就是类似,不过其代码实现非常复杂。

4. pre_tran功能的具体实现

要真正的pre_tran,首先要定义好类A:

这里要注意的是A类一定要从uvm_callback派生,另外还需要定义一个pre_tran的任务,此任务的类型一定要virtual的,因为从A派生的类需要重载这个任务。

接下来定义好一个A_pool类:

typedef uvm_callback#(mii_driver,A) A_pool;

A_pool的定义相当简单,只需要一个typedef语句即可。另外,在这个生命中除了要指明这是一个A类型的池子之外,还要指明这个池子将会用于哪个类。在本例中,mii_driver将会使用这个池子,所以要把这个池子声明为mii_driver专用的。之后,在mii_driver中要做如下声明:

这个声明与A_pool的类似,要指明mii_driver和A。在mii_driver的main_phase中调用pre_tran时并不如上面指示的那么简单,而是调用了一个宏来实现:

uvm_do_callback宏的第一个参数是调用pre_tran的类的名字,这里自然是mii_driver,第二个参数是哪个类具有pre_tran,这里是A,第三个参数是调用的哪个函数(任务),这里是pre_tran,在指明pre_tran时,要顺便给出pre_tran的参数。

其次,在base_test中把my_callback实例化:

my_callback的实例化是在connect_phase中完成的,实例化完成后需要把my_cb加入到A_pool中。同时,在加入的时候,要指定是给哪个mii_driver使用的。因为很可能整个base_test中例化了多个mii_env,所以要把mii_driver的路径作为add函数的第一个参数。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-11-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 瓜大三哥 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 在UVM验证平台中,callback的最大用处就是提高验证平台的复用性。很多情况下,我们期望在一个项目中开发的验证平台能够用于另一个项目。但是,通常来说,完全复用是非常难实现的,两个不同的项目之间或多或少有一些差异。如果把两个项目不同的地方使用callback来做,而把相同的地方写成一个完整的env,这样复用时,env可以完全的复用,只要改变相关的callback即可。
    • 1. callback简介
      • 2. callback:让一切丰富多彩
        • 3. UVM中的callback
          • 4. pre_tran功能的具体实现
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档