在线咨询
eetop公众号 创芯大讲堂 创芯人才网
切换到宽版

EETOP 创芯网论坛 (原名:电子顶级开发网)

手机号码,快捷登录

手机号码,快捷登录

找回密码

  登录   注册  

快捷导航
搜帖子
查看: 3038|回复: 3

[原创] uvm_callback讨论

[复制链接]
发表于 2015-10-9 20:35:18 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?注册

x
uvm中的很多思想来源软件工程,callback机制就是其中的一个。
但是callback究竟在uvm环境中究竟有多大的作用?有多少场景可以用到它?
或者说最好是用它而不是用别的手段来达到相同的目的?
对此我持怀疑态度!

在对callback机制的介绍中,使用的最多的两个例子是改变driver的行为,加一些delay,注入一些error,等等;
另外一个例子就是使用它来收集coverage。

就上面这个增强driver功能这个例子,我觉得有一些常规的方法来实现相同的功能,毫无疑问,那就是继承加上factory的overwrite功能。
那些用callback和用继承+factory的优缺点是什么呢?

用继承+factory的优点是最容易想到的也是最直观的;
但是它有一个致命的缺点:会引起组合爆炸(设计模式中的提法)。
举例来说:
class driver ;
   task run();
      pre_do();
      xxx;
      mid_do();
      xxx;
      post_do();   
   endtask
endclass
其中的pre_do,mid_do,post_do都是callback的方法。这些callback方法一般默认都是是空的。
如果我需要一个修改pre_do的driver,我会写:
class  pre_driver extends driver; 然后重新改写pre_do方法;
如果我需要一个修改post_do的driver,我会写:
class  post_driver extends driver; 然后重新改写post_do方法;
........
如果我需要一个修改mid_do和post_do的driver,我会写:
class  mid_post_driver extends driver; 然后重新改写mid_do和post_do方法;
........
然后在testcase里使用factory的overwrite用pre_driver, post_driver......替换环境里的正常的driver。
很明显,需要3个callback点的driver,它最多有可能需要7个xxx_driver派生类来应对各种可能的组合。
如果是4个callback点,那将是4+6+4+1=15种派生可能;
如果是5个callback点,那将是5+10+10+4+1=30种派生可能;
........
对于callback较多的情况,用继承+factory overwrite的方式显然是不可取的。

但是对于我们的uvm验证环境来说,有多少情形会出现比较多的callback需求点呢?
至少我目前还没有遇到过,请有此经历的同仁也发表一下你们的看法。
 楼主| 发表于 2015-10-9 20:58:29 | 显示全部楼层
至于uvm中的callback核心机制,本身来说没有什么特别复杂的地方。
要使用uvm callback的功能,说实话我觉得操作起来并不是很爽,步骤也不算少,涉及的宏也不算少。
但是我们可以自己写一个简化版的callback来理解它的基本机制,如下:

typedef class callback ;

/////callbacks类可以看作是一个装类型T的callback的容器
class callbacks#(type T=callback) ;
    static local callbacks#(T) _m_inst ; ////对一个类型T,只需要一个容器即可
    static local T _next [$] = {}; ////容器的物理载体
    local int index ; ////用来遍历容器,在uvm callback中有对应的类似机制,叫做iterator
   
    static function callbacks#(T) get();
        if(!_m_inst) _m_inst = new ;
        return _m_inst ;
    endfunction

    local function new();
        reset_index() ;
    endfunction

    /////提供给用户的接口,加入自己希望的callback,在testcase中使用
    static function void add(T cb);
        _next.push_back(cb);
    endfunction

    //////这两个方法用来遍历容器中的callback
    function T get_next();
        return _next[index++] ;
    endfunction

    function void reset_index();
        index = 0 ;
    endfunction
endclass


/////这个宏用来简化打算使用callback的class的一些申明
`define callback_registry(T) \
        local callbacks#(T) hook = callbacks#(T)::get() ; \
        local T each ;

/////这个宏用来简化callback的使用,在uvm中有类似的宏做类似的事情
`define do_callback(T,METHOD) \
        each = hook.get_next() ;\
        while(each)begin \
            each.METHOD ; \
            each = hook.get_next() ;\
        end \
        hook.reset_index();

//////打算使用callback的类
class driver ;
   
    `callback_registry(callback)
   
    function void run();
        `do_callback(callback,pre_do)
        $display("call driver's run()...");
        `do_callback(callback,post_do)
    endfunction

endclass


//////用户定义的callback类及其界面
class callback ;
    virtual function void pre_do();
    endfunction
   
    virtual function void post_do();
    endfunction
endclass


/////下面几个真正用来扩展功能的callback派生类
/////注意,有几个callback点就只需要几个派生类,而不再需要各种组合了!
class pre_callback extends callback;
    function void pre_do();
        $display("call pre_callback's pre_do()...");
    endfunction
endclass


class post_callback extends callback;
    function void post_do();
        $display("call post_callback's post_do()...");
    endfunction
endclass


/////testcase类
class testcase ;
    driver drv ;

    function new();
        drv = new ;
    endfunction

    /////本testcase需要扩展pre_do和post_do
    virtual function build();
        pre_callback pre_cb = new() ;
        post_callback post_cb = new() ;
        callbacks#(callback)::add(pre_cb) ;
        callbacks#(callback)::add(post_cb) ;
    endfunction

    function void run();
        drv.run();
    endfunction
endclass


////两外一个testcase类
class testcase2 extends testcase ;
      /////本testcase只需要扩展post_do
  virtual function build();
        post_callback post_cb  = new();
        callbacks#(callback)::add(post_cb) ;
    endfunction
endclass


个人结论:
callback点的设置需要个人的项目经验、项目需求、项目成熟度来决定,没有特定的公式可以套用;
在不是必须的情况下还是使用继承+factory overwrite比较容易和直观。
 楼主| 发表于 2015-10-9 21:04:54 | 显示全部楼层
在uvm的callback机制中,说起来我觉得算是使用了两个软件工程中的设计模式,bridge模式和iterator模式。
另外,虽然模版技术是一项强大的技术,而C++中的模版技术早已发展成为一个流派;有些标准甚至非常依赖模版技术,比如SystemC。
但是我觉得对模版类的过度使用会使代码变得难以理解。
发表于 2015-10-14 21:48:06 | 显示全部楼层
有幸读了楼主关于uvm phase的文章,不错。改天和楼主讨论下systemc相关,希望指点下
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

站长推荐 上一条 /2 下一条

×

小黑屋| 手机版| 关于我们| 联系我们| 在线咨询| 隐私声明| EETOP 创芯网
( 京ICP备:10050787号 京公网安备:11010502037710 )

GMT+8, 2024-12-22 14:50 , Processed in 0.036614 second(s), 10 queries , Gzip On, Redis On.

eetop公众号 创芯大讲堂 创芯人才网
快速回复 返回顶部 返回列表