Callback机制

 Callback 机制


       在UVM 验证平台中,callback 机制的最大用处就是提高验证平台的可重用性。很多情况下,验证人员期望在一个项目中开发的验证平台能够用于另外一个项目。但是,通常来说,完全的重用是比较难实现的,两个不同的项目之间或多或少会有一些差异。如果把两个项目不同的地方使用 callback 函数来做,而把相同的地方写成一个完整的 env,这样重用时,只要改变相关的 callback 函数 env 可完全的重用。


除了提高可重用性外,callback 机制还用于构建异常的测试用例。只是在 UVM 中,构建异常的测试用例有很多种方式,如factory 机制的重载callback 机制只是其中的一种


post_randomize 函数是 SystemVerilog 提供的广义的 callback 函数。UVM也为用户提供了广义的 callback函数/任务: pre_body 和post _body,除此之外还有pre_ do、mid_ do、post_do。 

callback 机制制的使用

作为 VIP的开发者应该做的事情

class A extends uvm_callback;
  virtual task pre_tran (my_driver drv, ref my_transaction tr);
  endtask
endclass

A类一定要从 uvm_callback 派生,另外还需要定义一个pre_tran 的任务,此任务的类型一定要是 virtual 的,因为从A 派生的类需要重载这个任务

       接下来声明一个A_pool类:

 typedef uvm_callbacks# (my_driver, A) A_pool;

A pool 的声明相当简单,只需要一个 typeder语句即可。另外,在这个声明中除了变指明这是一个A类型的池子外,还要指明这个池子将会被哪个类使用。

如果my.driver 使用这个池子,需要将此池子声明为 my_driver专用的。之后,在 my_driver中要做如下声明:

 typedef class A;

 class my_driver extends uvm_driverf (my_transaction);
   'uvm_component_utils(my driver)
   'uvm_register_cb(my_driver,A)
endclass

这个声明与A_pool的类似,要指明 my_driver和A。在my_driver的 main_phase 中调用pre_tran 时需调用一个宏来实现:

task my_driver::main_phase (uvm_phase phase);
   while(1) begin
   seq_item_port.get_next_item(req);
   'uvm do callbacks (my_driver, A, pre_tran(this, reg))
   drive_one_pkt(req);
   seq_item_port.item done ();
endclass

uvm_do_callbacks宏的第一个参数是调用pre_tran 的类的名字,这里自然是my_driver,第二个参数是哪个类具有 pre tran,这里是A,第三个参数是调用的是函数/任务,这里是 pre_tran,在指明是 pre_tran 时,要顺便给出 pre_tran 的参数。

作为使用 VIP 的用户来说,需要做如下事情:
首先从 A 派生一个类:

class my_callback extends A;
    'uvm_object_utils(my_callback)
    
    virtual task pre_tran(my_driver drv, ref my_transaction tr);
      'uvm_info("my_callback","this is pre_tran task",UVM_MEDIUM)
    endtask
     
 endclass


其次,在测试用例中将 my_callback 实例化,并将其加人 A_pool中:

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


my_callback 的实例化是在 connect_phase 中完成的,实例化完成后需要将 my_cb 加人A_pool中。同时,在加人时需要指定是给哪个my_driver 使用的。因为很可能整个 base_test中实例化了多个my_env,从而有多个my_driver 的实例,所以要将my_driver 的路径作为add函数的第一个参数。至此,一个简单的 callback 机制示例就完成了。这个示例几乎涵盖 UVM 中所有可能用到的 callback 机制的知识,大部分 callback 机制的使用都与这个例子相似。
总结一下,对于 VIP 的开发者来说,预留一个 callback 函数/任务接口时需要做以下几步:
1.定义一个A类。
2.声明一个A _pool类。
3.在要预留 callback 函数/任务接口的类中调用uvm_register_cb 宏。
4.在要调用 callback 函数/任务接口的函数/任务中,使用uvm _do _callbacks宏。
对于 VIP 的使用者来说,需要做如下几步:
1.从A派生一个类,在这个类中定义好 pre _tran。

2.在测试用例的 connect_phase 中将从 A类派生的类实例化。并将其加人入 A_pool中.


类继承父类的 callback 机制


由于一个 callback 池(即A_pool)在声明的时候指明了这个池子只能装用于 my_driver 的 callback,那么怎样才能使原来的 callback 函数/任务能够用于 new_driver 中呢?
这就涉及到了子类继承父类的 callback 函数/任务问题。

my_driver 使用上节中的定义,在此基础上派生新的类 new_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) ;

   'uvm_info("new_driver", "this is new driver", UVM_MEDIUM)
    seq_item_port.get_next_item(req);
  
    while(l) begin
     'uvm_do_callbacks (my_driver, A, pre_tran(this, req))
      drive_one_pkt(req);
      seq_item_port.item_done();
    end
endtask

 这里使用了uvm_set_super_type宏,它把子类和父类关联在一起。其第一个参数是子类,第二个参数是父类。在 main phase 中调用uvm_do_callbacks 宏时,其第一个参数是my_driver,而不是new_driver,即调用方式与在 my_driver 中一样。
在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

使用callback 函数/任务来实现所有的测试用例

       其实完全可以不用sequence,只用 callback 函数/任务就可以实现所有的测试用例。假设A类定义如下:

class A extends uvm_callback;
    
   my_transaction tr;

   virtual function bit gen_tran();
......
   endfunction


 virtual task run (my_driver drv, uvm_phase phase);
     
     phase.raise_objection (drv);

    drv.vif.data <= 8'b0;
    drv.vif.valid <= 1'b0;
    while(!drv.vif.rst_n)
      @(posedge drv.vif.clk);

    while(gen_tran()) begin
    
      drv.drive_one_pkt(tr);

    end

    phase.drop_objection(drv);

  endtask

endclass

在my_driver 的 main_phase 中,去掉所有其他代码,只调用A的 run():

task my_driver: :main_phase (uvm_phase phase) ;
   
    'uvm_do_callbacks (my_driver, A, run(this, phase))

endtask

在建立新的测试用例时,只需要从A 派生一个类,并重载 gen_tran 函数:

class my_callback extends A;
     int pkt num = 0;

     'uvm object_utils (my_callback)

virtual function  bit gen_tran();
   ‘uvm_info("my_callback","gen_tran","UVM_MEDIUM")
     tr = new("tr");
     assert(tr.randomize());
     pkt_num++;
     return 1;
   end
  else
     return 0;
endfunction

endclass


在这种情况下,新建测试用例相当于重载 gen_tran。如果不满足要求,还可以将A类run 任务重载。在这个示例中完全丢弃了 sequence 机制,在 A类的run任务中进行控制 objection,激励产生在gen_tran 中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值