降龙十八掌 system verilog

回调函数概念:在上面的类比中,“制作身份证”是一个首先被执行的主函数(main ),填写信息表中取送方式一栏就是向主函数注册回调函数( a),而“邮寄”和“本人来取”其实就是被注册的回调函数( ),主函数在结束之前会调用回调函数,这个调用的地方叫做回调函数的hook 。回调函数的接口通常是预先定义好的,比如CC总不能给主函数注册一个“由民警配送到我家”的回调函数吧 。
SV的步骤
1、在需要回调的地方预留入口;(类似、)
2、定义回调的类及其内部的回调函数;( class; task;)
3、例化和添加回调类的实例;(回调类 xx=new(); 添加到1的地方)
// 第一步:添加回调函数和hooktypedef enum {OKAY, EXOKAY, SLVERR, DECERR} resp_type;class slave_driver;resp_type resp;// 这个就是回调函数,一般声明称virtual,方便override// 在使用的时候是直接继承该类并重载定义回调函数 virtual task update_resp; endtasktask send_response;std::randomize(resp) with {resp == OKAY;}; update_resp();// 这行代码就是回调函数的hookendtaskendclass// 第二步:使用回调数class err_inject extends slave_driver;// 在子类中重新定义回调函数的实现 virtual task update resp;$display("Injecting SLVERR"); resp = SLVERR;endtask endclass// 第三步:使用回调数program error_test;slave env env;err_inject err_driver;initial begin// 例化环境组件 env =new();err driver =new();// 用err_driver覆盖slave_driverenv.slv_driver = err_driver();// 仿真开始 env.run(); endendprogram
UVM的
参考白皮书P288的9.1.4小节
的开发者:
1、定义一个A类:class A;回调函数要添加(以便使用者重载)
如: task ( , reftr)
2、声明类:#(,A) ;
第一个参数::这个将会被这个类使用;
第二个参数:A:这是一个A类型的pool;
3、在要预留函数|任务接口的类中调用宏:
class xxx123 extend uvm_driver #(transaction);// 在主函数中注册回调函数`uvm_register_cb(xxx123,A)
4、在调用函数或任务接口的函数或任务中,使用宏来调用回调函数;
task xxx123::main_phase(uvm_phase phase)//.........`uvm_do_callback(xxx123,A,pre_tran(parameters))//........endtask
使用者:需要实现具体的函数
1、从A中派生一个类ex_A,并重载回调函数;
2、在测试用例这一层的中(要求就是在上面步骤4中使用回调函数之前的phase即可):把ex_A类实例化并加入到中 。(::add(xx.a,my_cb))参考白皮书P290 代码清单9-13
下面是:芯片学堂给出的一个实例
// 第一步:添加和引用回调函数,回调基类定义和hook分开 class driver_callback extends uvm_callback;uvm object utils(driver callback)function new(string name = "driver_callback");super.new(name); endfunction// 定义回调函数virtual task pre drive;endtask virtual task post_drive; endtask endclass// 回调函数在使用之前,需要先被注册到回调hook的object当中//注册的时候可以使用UVM提供的宏来完成,并且在object中加hook class driver extends uvm_component;`uvm_component_utils(driver)// 这里就是对回调函数的注册,将回调基类和驱动类型关联起来`uvm_register_cb(driver, driver_callback)function new(string name, uvm_component parent);super.new(name,parent);endfunctiontask run_phase(uvm phase phase);//这里就是对两个回调函数的hook,实际上是从回调函数资源池里面找函数执行// 函数索引是驱动类型+回调类型+回调函数名`uvm_do_callbacks(driver, driver_callback, pre_drive()); drive_pkt();`uvm_do_callbacks(driver, driver_callback, post_drive()); endtasktask drive pkt();`uvm_info("DRIVER", "Inside drive_pkt method", UVM_LOW); endtask endclass// 第二步:实现回调函数// 在上面SystemVerilog的例子中,实现回调函数是要继承整个driver// 在UVM这个例子中,回调函数的声明和hook是分开的,因此在实现回调函数的时候// 只要继承callback类就可以了class user callback extends driver callback:`uvm_object utils(user callback)function new(string name = "user_callback")super.new(name); endfunctiontask pre_drive;uvm_info("USER_CALLBACK", "Inside pre_drive method", UVM_LOW); endtasktask post drive;uvm_info( "USER_CALLBACK", "Inside post_drive method", UVM_LOW) endtask endclass// 第三步:使用回调函数// 在UVM这个例子中,因为回调函数跟hook是分开的,在使用的时候也需要单独例化//在SystemVerilog实现的例子中,则是只要例化driver就可以,这是个区别 class user callback_test extends basic_test;// 声明用户实现后的回调类user_callback callback_1;uvm_component_utils(user_callback_test)function new(string name = "user_callback_test", uvm_component parent);super.new(name,parent); endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);// 回调类实例化callback 1 = user callback::type id::create("callback 1", this);// 给env的driver的回调函数资源池里添加回调对象uvm callback #(driver, driver callback)::add(env.drv, callback_1);endfunctionendclass