UVM通信篇之七(终):同步通信元件(下)
本文转自:http://www.eetop.cn/blog/html/28/1561828-5940104.html
uvm_callback应用
除了UVM提供新的类方便组件之间的同步之外,另外一种同步方式回调函数(callback)也方便了类的封装复用。读者们可以试想一下,在通常情况下,如果得到了一个封闭的包,其中的类如果有些成员方法需要修改,或者需要扩展新的方法时,应该怎么做呢?如果这个包是外来的,那么它的维护方首先不建议我们去修改这个类的本身。如果我们通过类的继承来实现这一要求,又无法进一步在该包的环境中用新的子类替换原来的父类。那么,UVM的覆盖机制(override)就可以帮到忙。除了覆盖机制,还有callback也可以为用户提供可以自定义的处理方法。这就使得,如果用户不需要添加新的方法,而是想延展之前的方法,那么就不需要通过继承类的方式,而只需要通过在后期自定义callback方法来实现。
在之前《核心基类》中我们已经谈过,uvm_object本身就提供了丰富的callback方法供用户们自己定义:
-
copy()和do_copy()
-
print()和do_print()
-
compare()和do_compare()
-
pack()和do_pack()
-
unpack()和do_unpack()
-
record()和do_record()
默认情况下,这些回调函数do_xxx是定义为空的,所以譬如用户执行了copy()函数,那么它会在执行末尾再执行do_copy()函数。所以,do_copy()就是copy()的回调函数。通过在copy()的执行尾端,来勾住(hook)下一个callback函数do_copy()。如果用户自定义了这些回调函数,那么就可以执行扩展后的方法。
那么,这种普通的回调函数定义就足够了,为什么还要专门定义一个uvm_callback类呢?可以说,通过这个新添加的类,使得回调都有了顺序和继承性。关于顺序和继承性的实现,又是通过两个相关的类uvm_callback_iter和uvm_callbacks #(T, CB)来实现的。接下来,我们依然给出一个实例来说明在uvm_callback的帮助下,回调函数可以玩出什么新的花样。
输出结果:
UVM_INFO @ 0: reporter [RNTST] Running test test1...
UVM_INFO @ 0: uvm_test_top.env.c1 [RUN] proceeding data 100
UVM_INFO @ 0: reporter [CB] cb1 executed with data 200
UVM_INFO @ 0: reporter [CB] cb2 executed with data 300
如果读者已经理解了回调函数本身的“钩子”属性,那么从上面这个例子可以看到,uvm_callback类使得钩子属性变得更加容易控制和继承。在这里例子中,有下面一些需要读者注意的地方:
-
callback可以通过继承的方式来满足用户更多的定制,例如上面的c2继承于cb1。
-
为了保证调用callback的组件类型T与callback类型CB保持匹配,建议用户在T中声明T与CB的匹配,该声明可以通过宏`uvm_register_cb(T, CB)来实现。用户养成了注册的习惯之后,如果以后一旦调用的T与CB不匹配,那么在检查完匹配注册表之后系统会打印warning信息,提示用户调用的潜在问题。
-
uvm_callback实现了回调函数执行的层次性,因此在实现方面,不再是在T的方法中直接呼叫某一个回调方法,而是通过宏`uvm_do_callbacks(T, CB, METHOD)来实现。该宏最直观的作用在于会循环执行已经与该对象结对的uvm_callback中的方法。此外,还有一个宏`uvm_do_callbacks_exit_on(T, CB, METHOD, VAL)可以进一步控制执行回调函数的层次,简单来讲,回调函数会一直执行,直到返回值与给入的VAL值相同就立刻返回,这一点使得回调方法执行顺序上面有了更多的选择。
-
有了`uvm_do_callbacks宏还不够,需要注意的是,在执行回调方法时,依赖的是已经例化的uvm_callback对象。所以,最后一步,需要例化uvm_callback对象,上面的例子中分别例化了cb1和cb2。最后,通过“结对子”的方式,通过uvm_callbacks #(T, CB)的静态方法add()来添加成对的uvm_object对象和uvm_callback对象。
从这个例子可以看到,uvm_callback的灵活性不但在于可以利用继承性的优点,实现用户的自定义内容,还在于回调函数不再固定依赖于某一些固定的程序,而是通过对象(uvm_object)和对象(uvm_callback)的绑定实现了精细化的回调函数指定。从最后的执行顺序来看,也证明了通过uvm_callbacks #(T, CB)::add()方法的简便性。
到这里,我们本章《UVM通信篇》已经就TLM通信模式、TLM1和TLM2的通信应用和组件之间的同步方式给出了详细的说明,希望读者可以利用这些便捷的类构建UVM环境中的快车道。