在DV中,我们可以使用factory,override机制来实现方法的重载,继而修改现有类的方法和属性。想象一下下面的一个应用场景,driver从sequencer拿到transaction,需要根据一些条件进行一些特殊处理才可以驱动到interface上,而现有的环境没有做这方面的处理。这个时候我们可以重载这个类,修改这个方法(用户的角度),但是TB开发人员(有时候不是用户),比如VIP开发的时候,开发人员可能无法穷经所有的情况,或者锁着项目的迭代,出现了一些新的特性,在TB中使用回调函数变成了一种可选项,这里我们介绍一下uvm_callback是怎么使用的,以及内部的机理是什么。
回调函数基本的3个步骤,
(1)注册
(2)添加
(3)调用
class mycb extends uvm_callback;virtual function void do_processing();endfunction
endclass
class my_comp extends uvm_component;`uvm_register_cb(my_comp,mycb);task run_phase(uvm_phase phase);`uvm_do_callacks(my_comp,mycb,do_processing());endtask
enclass
在上述代码中,`uvm_register_cb(my_comp,mycb)起到的是注册是作用。
define uvm_register_cb(T,CB) \
static local bit m_rigister_cb_``CB=uvm_callbacks#(T,CB)::m_register_pair(`"T`",`"CB`");
展开这个`uvm_register_cb(my_comp,mycb)
m_register_cb_mycb=uvm_callbacks#(my_comp,mycb)::m_register_pair("my_comp","mycb");
首先先明确一下继承关系
uvm_callbacks_base //基类
uvm_typed_callback#(T)//子类
uvm_callbacks#(T,CB) //子子类
m_register_pair方法做了下面几件工作
(1)创建父类uvm_typed_callback#(my_comp),创建父父类uvm_callbacks_base,创建本身uvm_callbacks#(my_comp,mycb)(2)创建uvm_callbacks#(my_comp,uvm_callback),uvm_typed_callback#(my_comp)句柄指向uvm_callbacks#(my_comp,uvm_callback)这个对象。
(3)typeid_map[uvm_typeid#(comp)]=uvm_callbacks#(my_comp,uvm_callback)type_map[uvm_callbacks_base]=uvm_typeid#(my_comp)
(4) uvm_callbacks#(my_comp,uvm_callback).m_this_type.push_back(uvm_callbacks#(my_comp,mycb))
(5)uvm_callbacks#(my_comp,mycb).m_regoster=1 //标志注册完成
//说明:
变量m_this_type是队列 uvm_callbacks_base m_this_type[$]
上述完成了注册类型的任务
下一步就是添加:添加的是句柄
class my_env extends uvm_env;my_comp comp_inst;mycb cb_inst;virtual function build_phase(uvm_phase phase);super.build_hase(phase);comp_inst=my_comp::type_id::create("comp_inst",this);cb_inst= mycb::tyep_id::create("cb_inst");uvm_callbacks#(my_comp)::add(comp_inst,cb_inst);endfunction
endclass
add 方法做了下面几件事情
(1)判断 参数uvm_callback CB 这个参数时候为null,是的话报错退出
(2)uvm_callbacks#(my_comp,uvm_callback).check_registration(comp_inst,cb_inst);(2-1) cb_inst必须是uvm_callback的子类或者本身句柄(2-2) comp_inst必须是my_comp的子类或者本身句柄
(3)uvm_pool#(uvm_object,uvm_queue#(uvm_callback)) m_pool[comp_inst].push_back(cb_inst)
总结下来就是uvm_callbacks#(my_comp)::add的作用是向全局的pool中存放comp_inst 以及cb_inst整个pair
最后一个步骤是调用
`uvm_do_callbacks#(my_comp,mycb,do_processing());
这样就会去调用mycb::do_processing()的方法。