system verilog:call back机制的理解

什么是callback?它有什么作用呢?

引用自《UVM实战》第九章 UVM中代码的重用性:验证人员希望在在一个项目中开发的验证平台能够用于另一个项目,但是,完全重用是很难实现的,不同项目多少存在差异。但是,将两个项目不同的地方使用callback函数来做,而将相同的地方写成一个完整的env,重用时只要改变callback函数env就可以完全重用。

上代码来说明什么是callback

参考硅芯思见,很不错的博主
代码架构如下:

  • cbb是callback函数的基类(这个类是一个虚类或者说是抽象类,可以被扩展不能被实例化,只有扩展类中所有虚方法都有实体时,才能被实例化。将实例化的callback类的句柄写入 driver 组件的callback_pool中,相当于一个池子,放各种不同的被扩展的callback类。
  • ecbb重载了cbb中的pre post方法
  • env中实例化了 generator 和 driver 两个组件,作为可以复用的模块,generator 将 transaction 的句柄通过 mailbox 送给了driver
  • driver 组件中会有相应的地方从callback_pool中取出callback类并调用方法,这些地方成为hook(鱼钩)。
env
interface
mailbox
drive
generator
cbb
ecbb
DUT

code:
top_tb.sv

`timescale 1ns / 1ps
module test(input [7 : 0] data, input [1 : 0] addr);
endmodule

interface bitf(input bit clk, input bit rst_n);
    bit [7 : 0] data;
    bit [1 : 0] addr;
endinterface

package tpkg;
    `include "transaction.sv"
    `include "cbb.sv"
    `include "ecbb.sv"
    `include "driver.sv"
    `include "generator.sv"
    `include "enviroment.sv"
endpackage

module top_tb;
    import tpkg::*;
    bit clk;
    bit rst_n;
    initial begin
        clk = 1'b0;
        forever #1 clk = ~clk;
    end

    initial begin
        rst_n = 1'b0;
        #10 rst_n = 1'b1;
    end

    bitf itf(clk, rst_n);
    enviroment env;

    initial begin
        env = new(itf, 1);
        env.wait_opt();
        env.gend('h10);
        begin
            ecbb pecbb = new();//类的实例化必须紧挨begin,否则编译错误
            env.drv.cbb_pool.push_back(pecbb);
		end
		begin
            ecbb pecbb1 = new();
            env.drv.cbb_pool.push_back(pecbb1);
        end
        env.sim();
        repeat(10) @(posedge clk);
        $stop;
    end
    test u_dut(itf.data, itf.addr);

`ifdef FSDB
initial begin
	$fsdbDumpfile("top.fsdb");
	$fsdbDumpvars;
    	$fsdbDumpMDA();
end
`endif
endmodule

cbb.sv

virtual class cbb;

virtual task pre_fcallback(ref transaction tr, ref bit drop);
endtask

virtual task fcallback(ref transaction tr);
    $display("fcallback between pre and post");
endtask

virtual task post_fcallback(ref transaction tr);
endtask
endclass

ecbb.sv

class ecbb extends cbb;
    virtual task pre_fcallback(ref transaction tr, ref bit drop);
    $display("hello pre");
    $display(tr);
    endtask

    virtual task post_fcallback(ref transaction tr);
        $display("hello post");
        tr.data = ~tr.data;
        tr.addr = ~tr.addr;
        $display(tr);
    endtask
endclass

transaction.sv

class transaction;
    rand bit [7 : 0] data;
    rand bit [1 : 0] addr;
endclass

generator.sv

class generator;
    transaction tr;
    mailbox mbx;

    function new(mailbox mbx);
        this.mbx = mbx;
    endfunction

    task send(input int len);
        $display("generator start sending!");
        for (int i = 0; i < len; i++)begin
        tr = new();
        assert(tr.randomize());
        mbx.put(tr);
        $display("new data is %h", tr.data);
        $display("new addr is %h", tr.addr);
    end
    $display("generator end sending!");
    endtask
endclass

driver.sv

class driver;
    cbb cbb_pool[$];
    mailbox mbx;
    transaction tr;
    bit drop;
    virtual bitf itf;

    function new(mailbox mbx, virtual bitf itf, input int drop);
        this.mbx = mbx;
        this.itf = itf;
        this.drop = drop;
    endfunction

    task run();
        while(mbx.num())begin
            mbx.get(tr);
            foreach(cbb_pool[i])begin//hook
                cbb_pool[i].pre_fcallback(tr, drop);
            end
            if(!drop) continue;
            send(tr);
            foreach(cbb_pool[i])begin//hook
                cbb_pool[i].post_fcallback(tr);
            end
        end
    endtask

    task send(transaction tr);
        @(posedge itf.clk);
        this.itf.data = tr.data;
        this.itf.addr = tr.addr;
    endtask
endclass

enviroment.sv

class enviroment;
    generator gen;
    driver drv;
    mailbox mbx;
    virtual bitf itf;

    function new(virtual bitf itf, input int drop);
        this.itf = itf;
        mbx = new();
        gen = new(mbx);
        drv = new(mbx, itf, drop);
    endfunction

    task wait_opt();
        @(posedge itf.rst_n);
    endtask

    task gend(input int len);
        gen.send(len);
    endtask
    
    task sim();
        drv.run();
    endtask
endclass

make后的结果:(部分)
在这里插入图片描述

从程序回到书本,我们再深化对callback的认识

将systemverilog开发过程视为项目A,那么用户使用开发就是项目B,A的开发者预料到了B可能会在env.driver.send()函数的前后完成一些别的事情,因此在此函数的前后添加了callback的hook,B如A所料,扩展了callback类,重载了函数,并注册了扩展类(将callback扩展类的句柄放入callback_pool中,等待hook处的调用)。

UVM中的callback机制

以上代码其实已经实现了callback机制基于systemverilog的简单开发。那么UVM中如何开发callback机制如何作为用户使用开发过的callback机制呢

  1. 首先如何去开发一个callback机制?
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值