SV环境构建篇之三:接口
在认识了DUT ctrl_regs的接口定义以及如何进行例化以后,我们接下来就需要考虑如何在testbench中给ctrl_regs添加需要的激励。从下面这张图可以看到,ctrl_regs在MCDF的集成中需要与多个模块进行连接,这些模块包括有:
-
外部的时钟复位模块(Clock & Reset)
-
外部的控制模块(Controller)
-
内部的Slaves、FIFOs、Arbiter以及Formatter

如果要完成充分的验证,我们就需要对上述的连接关系给予激励。在发生激励之前,我们采用接口(interface)进行stimulator与DUT的连接。
interface的基本作用是对各个模块做清晰有序地连接,因此interface可以看做一捆智能的集束线(collector)。如果将interface作为一个路由器(router),那么意味着只要同interface的接口类型一致,多个模块都可以使用这个interface,将其与interface进行连接也不需要担心信号的驱动方向、连接性问题。可见,interface不但可以方便多个模块之间的连线,也能将DUT同testbench的连接隔离开来。对于DUT同testbench隔离的好处,我们将会在后续部分关于stimulator、monitor的实现中进一步介绍。
那么有了interface,我们应该如何声明这样的接口,而且应该需要几个接口呢?下面是常见的两种实现方式:
interface连接方式1

该连接方式只定义了一个interface: regs_if,而且将所有需要同ctrl_regs相连接的信号均定义在regs_if中且与ctrl_regs在testbench中进行连接。
interface连接方式2

该方式则定义了三个interface: regs_cf_if、regs_ini_if和regs_rsp_if。该三个interface的功能划分更加明确:
-
regs_cr_if:时钟和复位的接口,用来供给ctrl_regs和其它两个接口。
-
regs_ini_if:ctrl_regs读写接口,也由于该接口模拟了集成以后外部控制器的作用,我们将其称之为initiator(发起端)接口,即该接口主动发起读写请求。
-
regs_rsp_if:ctrl_regs配置和状态反馈接口,该接口时为了能够及时响应ctrl_regs在相应寄存器经过读写以后对所对应模块的功能配置或者状态返回。我们也将其称之为responsor(响应端)接口。
那么这两种方式从实现方式来看,方式2看起来需要做更多接口的定义,而且似乎将一件连接环境的事情变得更复杂了,是这样的吗?从实现的工作量来看,方式2确实会引入更多的工作,但从日后ctrl_regs的testbench在更高层级的集成复用来看,现在按照ctrl_regs边界信号进行有效的划分会对日后的工作提供更多的方便,这一点也会在以后的篇章关于《SV的系统集成篇》中得到体现。
那么,下面是关于上述三个interface的定义:


在上述interface定义中我们需要注意以下几点:
-
interface可以定义input/output/inout端口,或者如果这些接口对不同连接模块的方向不相同时,可以将这些端口定义在interface实体中,这样的信号定义本身没有方向。
-
我们建议将interface上信号数据类型定义为logic,而非wire或者reg。这么做是因为SV的logic类型本身扩展了传统的reg类型,使得其也可以像wire进行连线。值得注意的一点是,唯一不能使用logic变量的地方是含有多驱动(multi-drive)的场景,这时候你必须使用连线类型,例如wire。
-
此外,我们需要再次强调,interface中的信号如果用来同DUT相连接,那么应该必须是四值逻辑即logic/reg/wire等,而不应该是二值逻辑bit/int/byte等。这么做的考虑是确保在今后的stimulator到DUT的驱动场景或者DUT到monitor的数据采集场景中,硬件部分的'X'或者'Z'信号不会被缺省转换以致丢失。
-
interface也可以定义parameter来方便扩展复用。
在实现了interface的端口定义之后,我们进一步深入interface的其它应用。首先,我们提到了regs_cr_if的功能是提供时钟和复位信号的,这里我们可以在regs_cr_if中产生时钟和复位信号。

从上面的例子可以看到,interface也可以包含过程语句(always和initial)以及连续赋值语句,这对更高层级的建模和testbench应用都有好处。从上面的regs_cr_if中可以看到通过两个简单的initial过程语句可以在interface内部产生出时钟和复位信号。
接下来我们看三个interface与DUT的实际连接关系:

interface本身既需要同DUT连接, 也需要同stimulator和monitor连接,那么对于不同对象来讲,连接的信号方向也是不相同的。考虑到interface中声明了的信号自身没有方向,这就使得同一个信号可能会连错或者反向驱动的问题。
interface为了限制不同对象对其信号的访问权限和方向,通过modport来做进一步的声明来确立信号应该连接的方向。这里,我们以regs_ini_if为例:

在regs_ini_if实体中,进一步定义了3个modport:dut,stim和mon。它们分别用来作为DUT,stimulator和mon的“插座”,这样一方面澄清了各个对象可以连接的interface信号,也通过限制的方向避免了反向驱动的问题。如果形象地来理解modport的作用,可以将interface作为一个插排,而各个modport作为针对不同对象的插槽,这使得针对更复杂的连线问题可以得到简化。

如果regs_ini_if通过modport来进一步约束信号的连接,那么上面的代码实例对于DUT的连接就转换为下面的部分:

可以看到,除了时钟和复位信号意外,其它信号与ini_if和rsp_if内部信号连接时需要再进一步通过modport dut来连接。与之前的点对点连接方式比较,modport可以使所有相关的信号集中在同一个地方描述,减少出错的概率,但也需要额外地对这些不同的信号进行分类集合。
在介绍完interface主要的使用情况以后,我们下一节将介绍testbench的“外包装”——program(程序块),来看一看program与module的比较,以及它们之间可能存在的竞争问题。
浙公网安备 33010602011771号