前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SystemVerilog中的callback(回调)

SystemVerilog中的callback(回调)

作者头像
数字IC小站
发布2020-06-30 16:05:56
2.5K0
发布2020-06-30 16:05:56
举报
文章被收录于专栏:数字IC小站数字IC小站

在第二次systemverilog实验中,我看到有同学用到了callback函数,今天就是简单讲讲这个方法。


1、什么是callback

callback是SystemVerilog学习者的主要困惑点之一。许多人在许多论坛上都提出了相同的问题,但答案似乎并不能尽如人意。

我们可以将数据成员传递给任何函数。现在考虑一种情况,将一个函数(例如func1)作为数据成员传递给另一个函数(例如func2),并且得到所谓的callback。之所以称为callback,是因为函数func2现在可以在其代码函数func1中的任何地方调用。

如下图所示:

这个是一个基类,其中:

  • temp是一个方法
  • 方法temp中的一些语句还调用了方法callback_1和callback_2,在这其中的两个方法都是虚方法,并不含有任何逻辑。
  • 用户可以在派生类中将所需逻辑添加到方法callback_1和callback_2,不需要更改方法temp。

例如,“randomize”是systemverilog中的一个带有callback的内建方法。randomize方法通过在randomize()前后分别调用pre_randomize()和post_randomize()去实现callback。

方法将按照下面提到的顺序执行,

  • pre_randomize();
  • randomize();
  • pre_randomize();

2、如何实现callback

实现systemverilog中callback的一种方式如下:

  • 编写一个方法,并且其中调用了其他的虚方法
  • 编写被调用的虚方法,此方法中一般不含有任何逻辑

3、如何使用callback

方法如下:

  • 派生类并且实现callback方法,重写虚方法的内容
  • 通过派生类覆盖基类

4、使用范例

代码语言:javascript
复制
class abc_transactor;
virtual task pre_send(); endtask
virtual task post_send(); endtask

task xyz();
  // Some code here
  this.pre_send();
  // Some more code here
  this.post_send();
  // And some more code here
endtask : xyz
endclass : abc_transactor

class my_abc_transactor extend abc_transactor;
virtual task pre_send();
  ...     // This function is implemented here
endtask

virtual task post_send();
  ...     // This function is implemented here
endtask

endclass : my_abc_transactor

上述代码中,基类含有3个task,其中2个task声明为virtual并且没有任何逻辑,但是这2个task都被另外的task xyz()调用,而xyz()是已经有逻辑代码了的,在这其中,这2个virtual task就被称为callback class。

my_abc_transactor派生自abc_transactor类,并且实现了基类中没有添加任何逻辑的task,这样我们可以直接把需要执行的代码添加到virtual task中而不需要对其进行修改。


还是不懂?那么看个实例:

上图实现的是一个slaver driver,用来对master进行反馈。

其中包括以下组件:

  • slave_driver - Normal driver to drive response
    • 响应类型为 OKAY, EXOKAY, SLVERR, DECERR
    • slave_driver 被限制为始终发送OKAY响应以查看回调用法差异
  • slave_env -在其中创建了slave_driver的环境
  • basic_test - 发送正常响应
  • error_test - 具有回调方法的测试用例,用于生成错误响应
  • err_inject - 扩展的驱动程序类,用于实现回调方法

首先,编写slave_driver,并在其中添加空方法,放置挂钩以进行回调,在此示例中,由于需要在响应生成后立即对其进行更改,因此最好在调用randomize方法之后放置回调挂钩:

代码语言:javascript
复制
typedef enum {OKAY, EXOKAY, SLVERR, DECERR} resp_type;
 
class slave_driver;
  resp_type resp;
   
  //callback hook
  virtual task update_resp; 
  endtask
   
  //send response task
  task send_response;
    std::randomize(resp) with { resp == OKAY;};
    update_resp();//hook
  endtask
endclass

实现callback,首先派生类,完善virtual task:

代码语言:javascript
复制
class err_inject extends slave_driver;
  virtual task update_resp;
    $display("Injecting SLVERR");
    resp = SLVERR;
  endtask
endclass

使用callback,生成error_test:

代码语言:javascript
复制
program error_test;
  slave_env  env;
  err_inject err_driver;
   
  initial begin
    //Create env
    env = new();
    err_driver = new();
    //Overriding slave_driver by error_driver
    env.slv_driver = err_driver;
     
    //Calling run of env
    env.run();
  end
endprogram

其中slave_env如下:

代码语言:javascript
复制
class slave_env;
  slave_driver slv_driver;
  
  function new();
    slv_driver = new();
  endfunction
  
  //run task to call driver logic
  task run;
    
    repeat(2) begin //{
      slv_driver.send_response();
      $display("Slave generated response is %s",slv_driver.resp.name());
    end //}
  endtask
  
endclass

此外,还添加basic_test如下,以便进行比对:

代码语言:javascript
复制
program basic_test;
  slave_env env;
  
  initial begin
    //Create env
    env = new();
    
    //Calling run of env
    env.run();
  end
endprogram 

在Synopsys VCS 2019.06下进行仿真

  • 当执行basic_test时,输出如下:
  • 当执行error_test时,输出如下:

可见,我们通过调用改变派生类中的virtual task中的内容,可以实现我们特定的内容。可以在不改变现有环境的情况下就实现错误的注入,因此好处如下:

  • 易于向现有逻辑添加其他功能
  • 使组件可重用,扩展类的功能

你点亮的每个在看,我都认真当成了喜欢、看完记得点亮在看哦~

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

本文分享自 数字IC小站 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档