文章目录
前言
2023.3.6 加油接着学
2023.3.12 植树节
一、callback机制
在父类定义方法时,预留回调函数入口,使得在继承的子类中填充回调函数,就可以完成对父类方法的修改。
预留回调函数入口,定义回调类和类中函数,例化及添加回调类的实例
1、用途
- 提高验证平台的可重用性:如post_randomize、pre_body、post_body等函数
- 用于构建异常的测试用例(之前的factory机制也可以用来构建)
2、callback机制的原理
使用时只要从A派生一个类并将其实例化,然后重新定义其pre_tran函数。把实例A放到A_pool
。假设这个类称为A_pool,意思就是专门存放A或者A的派生类的一个池子。UVM约定会执行这个池子中所有实例的pre_tran函数/任务。
task my_driver::main_phase();
…
while(1) begin
seq_item_port.get_next_item(req);
A.pre_tran(req);
…
end
endtask
3、callback机制的使用
对于VIP的开发者:
- 定义一个A类;
- 声明一个A_pool类;
- 在要预留callback函数/任务接口的类中调用
uvm_register_cb
宏; - 在要调用callback函数/任务接口的函数/任务中,使用
uvm_do_callbacks
宏。
对于VIP的使用者:
首先从A派生一个类,然后在测试用例中将my_callback实例化,并将其加入A_pool中(是在case层次的connect_phase完成这个任务)。
class my_callback extends A;
virtual task pre_tran(my_driver drv, ref my_transaction tr);
`uvm_info("my_callback", "this is pre_tran task", UVM_MEDIUM)
endtask
`uvm_object_utils(my_callback)
endclass
function void my_case0::connect_phase(uvm_phase phase);
my_callback my_cb;
super.connect_phase(phase);
my_cb = my_callback::type_id::create("my_cb");
A_pool::add(env.i_agt.drv, my_cb);
endfunction
4、子类继承父类的callback机制
应用场景:前后两次项目,大部分代码都相同,只是去修改某个组件,例如my_driver。
首先,使用uvm_set_super_type宏,把子类和父类关联在一起;然后在main_phase中调用uvm_do_callbacks宏时,其第一个参数是my_driver而不是new_driver,即调用方式与在my_driver中一样。
class new_driver extends my_driver;
`uvm_component_utils(new_driver)
`uvm_set_super_type(new_driver, my_driver)
…
endclass
task new_driver::main_phase(uvm_phase phase);
…
while(1) begin
seq_item_port.get_next_item(req);
`uvm_info("new_driver", "this is new driver", UVM_MEDIUM)
`uvm_do_callbacks(my_driver, A, pre_tran(this, req))
drive_one_pkt(req);
seq_item_port.item_done();
end
endtask
在my_agent中实例化此new_driver
function void my_agent::build_phase(uvm_phase phase);
super.build_phase(phase);
if (is_active == UVM_ACTIVE) begin
sqr = my_sequencer::type_id::create("sqr", this);
drv = new_driver::type_id::create("drv", this);
end
mon = my_monitor::type_id::create("mon", this);
endfunction
5、使用callback函数/任务实现所有sequence
6、举例
定义回调函数类,绑定回调函数类和组件,插入回调函数
`uvm_register_cb(comp1,cb1) //绑定
`uvm_do_callbacks(comp1,cb1,do_trans(d)) //插入
`uvm_callbacks #(comp1)::add(c1,m_cb1) //添加
call_back
是按照顺序执行的
uvm_do_callbacks(T, CB, METHOD)
:会循环执行和该对象结对的回调函数类的方法
顶层声明例化两个回调函数类,并添加回调函数
uvm_callbacks #(T, CB)
:类的静态方法add(comp, cb1)来添加成对的object和cb对象
7、完整举例
// Developer Code
class my_seq_item extends uvm_sequence_item;
rand logic [7:0] addr;
rand logic [7:0] data;
constraint addr_range_cn {
addr inside { [10:20]};
}
constraint data_range_cn {
data inside { [100:200]};
}
`uvm_object_utils_begin (my_seq_item)
`uvm_field_int (addr, UVM_ALL_ON| UVM_DEC)
`uvm_field_int (data, UVM_ALL_ON| UVM_DEC)
`uvm_object_utils_end
function new (string name="my_seq_item");
super.new (name);
endfunction : new
virtual function string convert2string ();
convert2string = $sformatf ("addr=%0d, data=%0d", addr, data);
endfunction : convert2string
endclass : my_seq_item
class my_sequencer extends uvm_sequencer # (my_seq_item);
`uvm_component_utils (my_sequencer)
function new (string name="my_sequencer", uvm_component parent=null);
super.new (name, parent);
endfunction : new
endclass : my_sequencer
typedef class my_driver;
class driver_cb extends uvm_callback;
`uvm_object_utils (driver_cb)
function new (string name="driver_cb");
super.new (name);
endfunction : new
// callback method shall be virtual.
virtual task inject_err (my_driver drv, my_seq_item tr);
endtask : inject_err
endclass : driver_cb
class my_driver extends uvm_driver # (my_seq_item);
`uvm_component_utils (my_driver)
// Register Callback
`uvm_register_cb (my_driver,driver_cb)
function new (string name="my_driver", uvm_component parent=null);
super.new (name, parent);
endfunction : new
function void build_phase (uvm_phase phase);
super.build_phase (phase);
endfunction : build_phase
virtual task inject_err (my_seq_item tr);
`uvm_do_callbacks (my_driver, driver_cb, inject_err (this,tr))
endtask : inject_err
task run_phase (uvm_phase phase);
forever
begin
#5;
seq_item_port.get_next_item (req);
inject_err (req);
`uvm_info (get_name (),
$sformatf ("After passing throguh callback in driver my_seq_item= %s",
req.convert2string ()), UVM_LOW);
#5;
seq_item_port.item_done ();
end
endtask : run_phase
endclass : my_driver
// End User Code
class my_seq extends uvm_sequence # (my_seq_item);
`uvm_object_utils (my_seq)
function new (string name="my_seq");
super.new (name);
endfunction : new
task body ();
`uvm_create (req)
if (!req.randomize ())
begin
`uvm_fatal (get_name (), $sformatf ("Randomization failed"))
end
`uvm_info (get_name (),
$sformatf ("After randomizating in my_seq my_seq_item= %s",
req.convert2string ()), UVM_LOW)
`uvm_send (req)
endtask : body
endclass : my_seq
class my_dri_cb extends driver_cb;
`uvm_object_utils (my_dri_cb)
static bit drop = 1;
function new (string name="my_dri_cb");
super.new (name);
endfunction : new
task inject_err (my_driver drv, my_seq_item tr);
tr.addr = tr.addr + 10;
tr.data = tr.data + 10;
endtask : inject_err
endclass : my_dri_cb
typedef uvm_callbacks # (my_driver,driver_cb) bus_driver_cbs_t;
class my_test extends uvm_test;
`uvm_component_utils (my_test)
my_sequencer sqr;
my_driver drv;
my_dri_cb cb;
function new (string name="my_test", uvm_component parent=null);
super.new (name, parent);
endfunction : new
function void build_phase (uvm_phase phase);
super.build_phase (phase);
sqr = my_sequencer :: type_id :: create ("sqr", this);
drv = my_driver :: type_id :: create ("drv", this);
cb = my_dri_cb :: type_id :: create ("cb");
endfunction : build_phase
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
drv.seq_item_port.connect(sqr.seq_item_export);
endfunction: connect_phase
task run_phase(uvm_phase phase);
my_seq seq;
phase.raise_objection(this);
#5;
seq = my_seq::type_id::create("seq");
seq.start(sqr);
#50;
bus_driver_cbs_t::add(drv, cb);
`uvm_info(get_name(), "----------------------Added Callback----------------------", UVM_LOW)
seq = my_seq::type_id::create("seq");
seq.start(sqr);
bus_driver_cbs_t::delete(drv, cb);
`uvm_info(get_name(), "----------------------Deleted Callback--------------------", UVM_LOW)
#50;
seq = my_seq::type_id::create("seq");
seq.start(sqr);
phase.drop_objection(this);
endtask
endclass
module top();
`include "uvm_macros.svh"
import uvm_pkg::*;
initial begin
run_test("my_test");
end
endmodule: top
二、UVM中一些可重用性的地方
1、factory机制
:把一些操作写成可重载的函数/任务,这样代码在验证环境中只要写一次,其他地方要用的话就对它去重载。
2、sequence
:把实现单个功能的部分做成一个个小的sequence
3、参数化类
:如设置总线位宽为参数,参数化的类方便修改从而产生不同的类
提高复用率,减少代码量
4、寄存器模型
的重用
5、call back机制