22 UVM Callbacks

回调用于改变组件或对象的行为而不修改其代码。请参阅SystemVerilog callback - VLSI Verify以更好地理解。UVM 中的phasing机制就是回调的一个简单示例

1 UVM Callback Usage

  1. 允许即插即用机制以建立可重用的验证环境。
  2. 基于钩子方法(hook method)调用,执行用户自定义的代码,而不是空的回调方法。这带来了组件或对象的各种风格。
  3. 回调可用于在组件中引入错误或延迟。

2 UVM Callback Macros

下面仅提及广泛使用的回调宏:

3 UVM Callback Classes

UVM 回调为其实现提供了一组类。

4 UVM Callback Methods

uvm_callback 方法可以使用范围解析运算符来调用,因为它们是静态方法。

例如: uvm_callbacks#(T, CB)::add(obj,cb);

其中:

T :使用用户定义回调的对象类型,它必须从 uvm_object 派生。

CB :用户自定义回调类型

obj : 使用用户定义回调函数的对象句柄

cb :用户定义回调对象

uvm_callbacks、uvm_callback_iter 和 uvm_callback 类还有许多其他方法,这里不讨论,常用方法和宏在上一节中介绍。 

5 Steps to implement uvm_callback

1. 创建一个派生自uvm_callback类的用户自定义callback类。

class driver_cb extends uvm_callback;

2. 添加一个空的回调方法。

virtual task modify_pkt();
endtask

driver_cb回调类代码:

class driver_cb extends uvm_callback;
  `uvm_object_utils(driver_cb)
  
  function new(string name = "driver_cb");
    super.new(name);
  endfunction
  
  virtual task modify_pkt();
  endtask  
endclass

3  基于上面用户定义的类来派生一个类并实现回调方法。

class derived_cb extends driver_cb;
  `uvm_object_utils(derived_cb)
  
  function new(string name = "derived_cb");
    super.new(name);
  endfunction
  
  task modify_pkt; // callback method implementation
    `uvm_info(get_full_name(),"Inside modify_pkt method: Injecting error pkt",UVM_LOW);
    std::randomize(pkt) with {pkt inside {BAD_ERR1, BAD_ERR2};};
  endtask
endclass

4  在调用回调的组件/component或对象/object中使用`uvm_register_cb注册用户定义的回调方法(在下面的示例中,它是在驱动程序组件中注册的)。

`uvm_register_cb(driver,driver_cb)

如果未使用`uvm_register_cb,则会发出警告。

例如:

UVM_WARNING @ 0: reporter [CBUNREG] Callback drvd_cb cannot be registered with object (*) because callback type derived_cb is not registered with object type uvm_object

5 使用`uvm_do_callbacks宏在所需组件或对象中放置回调挂钩,即调用回调方法

`uvm_do_callbacks(driver,driver_cb,modify_pkt());

Driver component code:

typedef enum {GOOD, BAD_ERR1, BAD_ERR2} pkt_type;
class driver extends uvm_component;
  `uvm_component_utils(driver)
  `uvm_register_cb(driver,driver_cb) // callback registration
  
  function new(string name = "driver", uvm_component parent = null);
    super.new(name,parent);
  endfunction
  
  task run_phase(uvm_phase phase); 
    super.run_phase(phase);
    drive();
    `uvm_do_callbacks(driver,driver_cb,modify_pkt()); // callback hook
  endtask
  
  task drive();
    `uvm_info(get_full_name(),"Inside drive method",UVM_LOW);
    std::randomize(pkt) with {pkt == GOOD;};
  endtask
endclass

 Output:

1. 当base_test执行时,(Run options: +UVM_TESTNAME=base_test)

class base_test extends uvm_test;
  `uvm_component_utils(base_test)
  env env_o;
  
  function new(string name = "base_test", uvm_component parent = null);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    env_o = env::type_id::create("env_o", this);
  endfunction
endclass

会产生一个GOOD包。

UVM_INFO @ 0: reporter [RNTST] Running test base_test...
UVM_INFO driver.sv(17) @ 0: uvm_test_top.env_o.drv [uvm_test_top.env_o.drv] Inside drive method
UVM_INFO driver.sv(13) @ 0: uvm_test_top.env_o.drv [uvm_test_top.env_o.drv] Driven pkt is GOOD

2. 当err_test执行时: (Run options: +UVM_TESTNAME=err_test)

class err_test extends base_test;
  derived_cb drvd_cb;
  `uvm_component_utils(err_test)
  
  function new(string name = "err_test", uvm_component parent = null);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    drvd_cb = derived_cb::type_id::create("drvd_cb", this);
    uvm_callbacks#(driver, driver_cb)::add(env_o.drv, drvd_cb);
  endfunction
endclass

使用UVM callback,产生了一个error包,如下:

VM_INFO @ 0: reporter [RNTST] Running test err_test...
UVM_INFO driver.sv(17) @ 0: uvm_test_top.env_o.drv [uvm_test_top.env_o.drv] Inside drive method
UVM_INFO callbacks.sv(20) @ 0: reporter [drvd_cb] Inside modify_pkt method: Injecting error pkt
UVM_INFO driver.sv(13) @ 0: uvm_test_top.env_o.drv [uvm_test_top.env_o.drv] Driven pkt is BAD_ERR2

6 UVM callback in uvm_sequence

uvm_sequence中实现回调函数的步骤与上面的步骤相同。

请注意,`uvm_do_obj_callbacks宏被用作带有associated sequencer的回调钩子/callback hook。

`uvm_do_obj_callbacks(sequencer,seq_cb,l_seqr,modify_pkt(req));

6.1 UVM callback in uvm_sequence example

class base_seq extends uvm_sequence #(seq_item);
  seq_item req;
  sequencer l_seqr; // Provided sequencer hierarchy from base_test before starting the sequence.
  `uvm_object_utils(base_seq)
  
  function new (string name = "base_seq");
    super.new(name);
  endfunction

  task body();
    `uvm_info(get_type_name(), "Base seq: Inside Body", UVM_LOW);
    req = seq_item::type_id::create("req");
    wait_for_grant();
    assert(req.randomize());
    `uvm_do_obj_callbacks(sequencer,seq_cb,l_seqr,modify_pkt(req));
    send_request(req);
    wait_for_item_done();
  endtask
endclass

Output:

1 当base_test执行时,(Run options: +UVM_TESTNAME=base_test)

class base_test extends uvm_test;
  env env_o;
  base_seq bseq;

  `uvm_component_utils(base_test)
  
  function new(string name = "base_test", uvm_component parent = null);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    env_o = env::type_id::create("env_o", this);
  endfunction
 
  task run_phase(uvm_phase phase);
    phase.raise_objection(this);
    bseq = base_seq::type_id::create("bseq");
    bseq.l_seqr = env_o.agt.seqr;
    bseq.start(env_o.agt.seqr);
    phase.drop_objection(this);
  endtask
endclass

产生一个GOOD包:

UVM_INFO @ 0: reporter [RNTST] Running test base_test...
UVM_INFO sequences.sv(11) @ 0: uvm_test_top.env_o.agt.seqr@@bseq [base_seq] Base seq: Inside Body
UVM_INFO driver.sv(15) @ 0: uvm_test_top.env_o.agt.drv [uvm_test_top.env_o.agt.drv] Driving pkt =
------------------------------
Name    Type      Size  Value
------------------------------
req     seq_item  -     @578 
 addr  integral  16    'he157
 data  integral  16    'h96b
 pkt   pkt_type  32    GOOD 
------------------------------

UVM_INFO /apps/vcsmx/vcs/Q-2020.03-SP1-1//etc/uvm-1.2/src/base/uvm_objection.svh(1276) @ 50: reporter [TEST_DONE] 'run' phase is ready to proceed to the 'extract' phase

2 当err_test执行时:+UVM_TESTNAME=err_test

class err_test extends base_test;
  derived_seq_cb drvd_seq;
  `uvm_component_utils(err_test)
  
  function new(string name = "err_test", uvm_component parent = null);
    super.new(name, parent);
  endfunction
  
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    drvd_seq = derived_seq_cb::type_id::create("drvd_seq", this);
  endfunction
  
  function void end_of_elaboration();
    super.end_of_elaboration();
    uvm_callbacks#(sequencer, seq_cb)::add(env_o.agt.seqr,drvd_seq);
  endfunction : end_of_elaboration
endclass

使用UVM callback,产生一个error 包,如下:

 

UVM_INFO @ 0: reporter [RNTST] Running test err_test...
UVM_INFO sequences.sv(11) @ 0: uvm_test_top.env_o.agt.seqr@@bseq [base_seq] Base seq: Inside Body
UVM_INFO callbacks.sv(20) @ 0: reporter [drvd_seq] Inside modify_pkt method: Injecting error in the seq item
--------------------------------
Name    Type      Size  Value  
--------------------------------
req     seq_item  -     @580   
 addr  integral  16    'hffff 
 data  integral  16    'h96b  
 pkt   pkt_type  32    BAD_ERR1
--------------------------------
UVM_INFO driver.sv(15) @ 0: uvm_test_top.env_o.agt.drv [uvm_test_top.env_o.agt.drv] Driving pkt =
--------------------------------
Name    Type      Size  Value  
--------------------------------
req     seq_item  -     @580   
 addr  integral  16    'hffff 
 data  integral  16    'h96b  
 pkt   pkt_type  32    BAD_ERR1
--------------------------------

UVM_INFO /apps/vcsmx/vcs/Q-2020.03-SP1-1//etc/uvm-1.2/src/base/uvm_objection.svh(1276) @ 50: reporter [TEST_DONE] 'run' phase is ready to proceed to the 'extract' phase

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值