UVM_CALLBACK
是一种基于回调函数的设计模式,允许用户在特定事件发生时插入自定义的行为。UVM提供了uvm_callback
类作为基类,用户可以通过继承该类来定义自己的回调行为。采用uvm_callback
基类,用户可以在不更改原始代码的情况下轻松插入调试代码或者功能代码。
实际使用时,大概有以下几种场景会用到callback:
(1)异常测试激励,需要在正常激励的基础上,随机插入一些额外的错误激励或者延迟;
(2)监控driver发送的事务是否符合预期;
(3)捕获monitor接收的数据并分析是否合理;
举例:
以第一种使用场景为例,现有如下具体场景:APB寄存器配置接口的验证,环境中已有组件apb_driver可以发送常规激励,但无法发送psel为低,paddr超范围等异常激励。
需求:不改动driver基本逻辑,不额外增加seq,不force接口,需要在每一笔apb激励驱动前,随机插入一些异常激励。
解决方案:采用callback成为了最佳解决方案。
具体实现步骤如下:
(1)定义callback类,完成pre_transmit task;
class my_apb_driver_callback extends uvm_callback;
`uvm_object_utils(my_apb_driver_callback)
// 回调任务
virtual task pre_transmit(apb_driver drv, apb_pkt pkt);
bit add_en;
int add_cycl;
`uvm_info("MY_APB_DRV_CALLBACK", "Pre-transmit callback executed", UVM_LOW)
if(`PLUS_ARG.plus_psel_low_mode == 1)begin
add_en = $urandom_range(0,1);
add_cycl = $urandom_range(1,6);
if(rand_en == 1)begin //随机插入
repeat(add_cycl)begin //插入数量随机
drv.delay_n_apb_cyc(1);
drv.vif.psel <= 0;
drv.vif.penable <= $urandom_rang(0,1);
drv.vif.pwrite <= $urandom_rang(0,1);
drv.vif.pwdata <= $urandom_rang(0,'hffff_ffff);
drv.vif.paddr <= $urandom_rang(0,'hffff_ffff);
end
end
end
endtask
virtual task post_transmit(apb_driver drv, apb_pkt pkt);
`uvm_info("MY_APB_DRV_CALLBACK", "Post-transmit callback executed", UVM_LOW)
endtask
function new(string name = "my_apb_driver_callback");
super.new(name);
endfunction
endclass
(2)在dirver组件中注册回调,调用回调;
class my_apb_driver extends uvm_driver #(apb_pkt pkt);
`uvm_component_utils(my_apb_driver)
// 注册回调
`uvm_register_cb(my_apb_driver, my_apb_driver_callback)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req);
// 调用回调方法
`uvm_do_callbacks(my_apb_driver, my_apb_driver_callback, pre_transmit(this,req))
// 执行主要功能
drive_transaction(req);
// 调用回调方法
`uvm_do_callbacks(my_apb_driver, my_apb_driver_callback, post_transmit(this,req))
seq_item_port.item_done();
end
endtask
virtual task drive_transaction(my_transaction tr);
// 驱动事务的逻辑
endtask
endclass
(3)在agent组件中inst回调,并将回调和对应driver连接;
class my_apb_agent extends uvm_agent;
`uvm_component_utils(my_apb_agent)
my_apb_driver drv;
my_apb_driver_callback cb;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
drv = my_apb_driver::type_id::create("drv", this);
// 创建回调实例
cb = my_apb_driver_callback::type_id::create("cb");
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
// 将回调实例添加到driver中
uvm_callbacks#(my_apb_driver, my_apb_driver_callback)::add(drv, cb);
endfunction
endclass
仿真效果:
按照如上方式调用callback,将会在正常的apb激励发送前,随机插入数量不等的psel为低的apb激励: