UVM: callback机制 uvm_callback和uvm_callbacks

callback机制

callback机制提高代码的可重用性,还用于构建异常的测试用例。
广义的callback机制有post_randomize(),pre_body(),post_body(), pre_do(), mid_do()等,它们提供了额外的接口给用户。

原理

以在driver中提供callback函数接口为例,在发送transaction之前或之后需要对transaction进行处理,于是建立preSend()和postSend()任务,而不同的测试用例希望preSend或postSend进行不同的处理,所以这两个任务不能是Driver类的方法,这样毫无重用性可言,每搭建一个测试用例就需要新的Driver。
解决办法是建立一个新的专门服务callback机制的类,将preSend()和postSend()放在该类中,之后在Driver中实例化该类,通过层次化引用的方法调用preSend和postSend,这样就将两个任务和Driver分离开,不同的测试用例只需要重新定义不同的callback类,不需重新定义Driver。
这样还有一个问题,每一个测试用例需要不同的preSend()和postSend()也就是不同的callback类,如果将这些类都放在Driver中实例化的话,也丧失了可重复性,而且Driver也不知道运行测试用例时需要调用哪个callback类的任务。
解决思想时将callback类放在对应的测试用例中实例化,然后让Driver调用所有实例化了的对象的preSend()和postSend()任务,这样callback类只会在需要时被实例化,之后Driver只会使用实例化了的callback。方法是先定义一个基类,里面定义两个空的虚拟方法preSend()和postSend(),再创建一个以这个基类为元素的数组(该数组需要时全局的),之后所有的callback类都是这个基类的扩展。在测试用例中,每实例化一个callback类,就将该对象的句柄放入数组中(是一个子类赋给父类的过程),之后在Driver中,会遍历该数组的所有元素(每个元素其实都是一个句柄而已),通过层次化引用方式调用每个元素的preSend()和postSend()方法。

callback机制使用方式

  1. 先定义一个基类
class Driver_callback extends uvm_callback;

endclass : Driver_callback 

然后在基类中定义所需要的callback方法,方法必须是虚拟的(将在子类中重载)在基类中定义所需要的callback方法,方法必须是虚拟的(将在子类中重载)

virtual task pre_send(); endtask
virtual task post_send(); endtask
  1. 在Driver中使用uvm_register_cb宏来注册上面定义的基类
class Driver extends uvm_component;

`uvm_component_utils(Driver)

`uvm_register_cb(Driver,Driver_callback)

function new (string name, uvm_component parent=null);
super.new(name,parent);
endfunction

endclass

之后在Driver中调用定义好的callback方法,preSend()和postSend()分别在发送前后调用。使用uvm_do_callbacks宏。这个宏函数有三个参数,第一个参数必须是Driver类名字,这个类会调用callback方法,第二个必须是使用的callback基类的名字,表示这个基类含有callback方法,第三个是所要调用的callback方法名字(如果有参数需要带上参数)

virtual task run();

repeat(2) begin
`uvm_do_callbacks(Driver,Driver_callback,pre_send())
$display(" Driver: Started Driving the packet ...... %d",$time);
// Logic to drive the packet goes hear
// let's consider that it takes 40 time units to drive a packet.
#40;
$display(" Driver: Finished Driving the packet ...... %d",$time);
`uvm_do_callbacks(Driver,Driver_callback,post_send())
end
endtask
  1. 使用callback机制构建测试用例:
    首先扩展基类,重载callback方法
class Custom_Driver_callbacks_1 extends Driver_callback;

function new (string name = "Driver_callback");
super.new(name);
endfunction

virtual task pre_send();
$display("CB_1:pre_send: Delaying the packet driving by 20 time units. %d",$time);
#20;
endtask

virtual task post_send();
$display("CB_1:post_send: Just a message from post send callback method \n");
endtask

endclass
  1. 添加callback实例到uvm_callback_pool中
    然后再testcase中实例化该类,并使用uvm_callbacks类的静态方法add将该类添加到“池子”里。注意uvm_callbacks使用时也有两个参数,第一个是Driver的类名字,第二个是callback基类名字。add方法也有两个参数,第一个是Driver在验证环境中的实例路径,指定是哪个Driver使用的,第二个就是扩展callback类实例的名字。也就是说前面的参数都是使用类的名字,只有在add方法这里使用的是实例名
module test;

initial begin
Driver drvr;
Custom_Driver_callbacks_1 cb_1;
drvr = new("drvr");
cb_1 = new("cb_1");
uvm_callbacks #(Driver,Driver_callback)::add(drvr,cb_1);
uvm_callbacks #(Driver,Driver_callback)::display();
run_test();
end

endmodule

以上就是使用callback机制构建测试用例的基本方法,运行测试用例时,`uvm_do_callbacks宏会检测到添加到uvm_callbacks中的扩展callback类实例,然后调用其preSend()或者postSend()方法。

如果添加了多个扩展类

其它部分不变,只是增加一个callback扩展类,并使用add方法添加到池子里

module test;

initial begin
Driver drvr;
Custom_Driver_callbacks_1 cb_1;
Custom_Driver_callbacks_2 cb_2;
drvr = new("drvr");
cb_1 = new("cb_1");
cb_2 = new("cb_2");
uvm_callbacks #(Driver,Driver_callback)::add(drvr,cb_1);
uvm_callbacks #(Driver,Driver_callback)::add(drvr,cb_2);
uvm_callbacks #(Driver,Driver_callback)::display();
run_test();
end

endmodule

如上所示,那么在运行这个testcase时,这个两个扩展callback类的preSend()和postSend()方法都会被调用,那么是哪个先被执行哪个后执行呢?答案是cb_1的先执行,cb_2的后执行,原因是调用add方法添加cb_1的代码在前,添加cb_2在后,Driver中按照这个顺序执行
因此改变多个callback方法的执行顺序就是需要改变调用add方法的顺序。

uvm_callback和uvm_callbacks

上面提到callback基类的定义是从uvm_callback类扩展而来的,而注册callback实例的add静态方法则是uvm_callbacks类的方法。它们的用处决定了它们区别,uvm_callbacks是更为复杂些。

`uvm_callbacks
uvm_callback

https://verificationacademy.com/verification-methodology-reference/uvm/docs_1.2/html/files/base/uvm_callback-svh.html
http://testbench.in/UT_15_UVM_CALLBACK.html

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值