SystemVerilog是对Verilog的扩展,其中汲取了很多面向对象语言的特性,当然也具有OOP的三大特性:封装、继承和多态。但是其中的继承目前只支持单继承,这种继承关系类似于Java中的继承关系。但是有时候子类需要具有多个父类的特性,类似于C++的多继承,那么这种“多继承”的效果在SystemVerilog中该如何实现呢?有的人可能觉得可以采用多层继承的方法实现,即不断地extends子类,但是这种方法随着继承层次的增多,各种父子类之间的关系将会变得非常复杂,就在这个时候,也就是大概2012年的时候,IEEE1800-2012中增加了一个新的特性,即interface class横空出世,通过接口类实现想要被继承的方法的声明,然后在需要使用该方法的实现类中实现这些接口类的方法,从而可以在同一个实现类中,可以同时实现多个不同接口类中的方法,但是这并不是我们理解的多重继承,应该算作一种多重实现。
可能会有人说,这么厉害的SystemVerilog的特性,有没有用在UVM中?很遗憾的是,这哥们生不逢时,2012年的时候UVM已经修修补补很多年了,库里的实现基本上也就没有interface class啥事了,所以,这个比较厉害的特性在目前发布的UVM中就没有出现(不信你可以在库里头grep下)。但是后生可畏,以后UVM会不会把这个特性加进去,也说不定,毕竟UVM还在缝缝补补。下面,我们主要介绍了解下接口类(interface class)到底是个啥?
接口类是一个抽象的类,其中只能包含pure virtual方法(即方法原型的声明)、类型声明和参数声明,不能包含constraint块、covergroup和其他类的定义,其中的pure virtual方法的实现是在其实现类中完成,因为其可以有多个实现类,所以其中的pure virtual会有多种不同的实现。
在SystemVerilog中,一个类可以通过关键字“implements”实现一个或者多个接口类,如下示例。
【示例】
【仿真结果】
示例中,定义了两个接口类animal和flyable,分别包含的pure virtual方法有eat()、sleep()、和fly()。实现类bird通过关键字implements表明要实现animal和flyable中的pure virtual方法,在类bird中对接口类中的pure virtual方法进行了实现,同时需要注意,此时实现类中实现的方法需要与接口类中的方法原型完全一致(除了不用加pure这个关键字以外),并且在实现类中,该方法必须是virtual方法。另外,示例中,接口类不能直接通过new()方法创建,但是可以声明句柄。在示例中,分别声明了三个句柄,分别是接口类句柄f和a,以及实现类句柄b。实现类句柄指向创建好的对象之后,可以通过实现类句柄调用实现类中所有接口类的方法。虽然此时接口类句柄可以指向实现类句柄指向的对象,但是此时接口类句柄只能调用该接口类中声明的方法,并不能调用实现类中实现的其他接口类的方法。
通过这个示例可以看到,bird在方法上实现了同时对于两个接口类方法的实现,而接口类则类似于定义了一种接口协议类型,这样可以保证所有实现该接口的类都能按照同样的接口协议实现各自的方法。同时,通过示例可以看到,所有的调用和指向关系都可以在仿真运行之后动态的建立,相较于一些验证结构中连接关系必须在仿真运行之前确定更加灵活。
上面示例中一个实现类实现了两个接口,同样的,一个接口类也可以对应多个实现类,如下例所示。
【示例】
【仿真结果】
示例中,有两个接口类PutImp和GetImp,这两个接口类中的pure virtual方法在类fifo1和fifo2中分别实现。monitor将数据分别发送给f1和f2指向的对象,然后对f1和f2指向对象收到的数据进行比较,并且可以看到f1和f2调用的方法原型是相同的,即相同的接口被不同的实现类实现。
参考上述示例中接口类的用法,我们可以知道在SystemVerilog中可以使用接口类实现“多重继承”的效果,为了实现这样的效果,我们只需要定义接口类,在接口类中包含我们需要实现的方法的原型,然后通过实现类实现这些接口类中的方法即可。
下面是一个不错的关于SystemVerilog接口类的文档(SystemVerilog Interface Classes – MoreUseful Than You Thought),有很多公众号的都转发过其中的内容,下面以附件的形式提供给大家,需要的朋友自行下载。