第十章高级接口

在第4章中,您学习了如何将设计和测试工作台与接口连接起来。这些物理接口代表真实信号,类似于Verilog-1995中连接端口的电线。测试工作台通过端口静态地连接到这些接口。然而,对于许多设计,测试台需要动态地连接到设计。

例如,在一个网络交换机中,一个单一的驱动类可以连接到许多接口,每个接口对应于DUT的每个输入通道。你不需要为每个通道编写唯一的驱动程序——相反,你需要编写一个通用的驱动程序,实例化它N次,并让它连接到N个物理接口。在SystemVerilog中,可以通过使用虚拟接口来实现这一点,虚拟接口仅仅是物理接口的句柄或指针。虚拟接口更好的名称是“ref接口”。

您可能需要编写一个附加到您的设计的几种不同配置的测试平台。在另一个例子中,芯片可以具有多种配置。在一个,引脚可能驱动一个USB总线,然而在另一个相同的引脚可能驱动一个I2C串行总线。同样,您可以使用一个虚拟接口,这样您就可以在运行时决定在您的测试台中运行哪些驱动程序。

SystemVerilog接口不仅仅是信号——您可以在其中放入可执行代码。这可能包括读取和写入接口的例程、在接口内部运行代码的初始化和总是阻塞,以及不断检查信号状态的断言。但是,不要把testbench代码放在一个接口中。如SystemVerilog LRM所述,程序块是专门为构建测试平台而创建的,包括在反应区域中调度它们的执行。

10.1. 与ATM路由器的虚拟接口

虚拟接口最常见的用途是允许testbench中的对象使用通用句柄而不是实际名称引用复制接口中的项。虚拟接口是唯一能够将对象的动态世界与模块和接口的静态世界连接起来的机制。

10.1.1 只有物理接口的测试平台

第4章展示了如何建立一个接口来连接4x4 ATM路由器到一个测试工作台。示例10.1和10.2展示了接收和发送方向的ATM接口。

示例10.1 Rx接口与时钟块

带时钟块的10.2 Tx接口示例

这些接口可以在示例10.3中所示的程序块中使用。这个过程代码是用接口名(如Rx0和Tx0)硬编码的。注意,在这些示例中,top模块没有将时钟传递给testbench;相反,测试与接口中的时钟块同步,从而允许您在更高的抽象级别上工作。

示例10.3使用物理接口的Testbench

图10.1显示了测试台通过虚拟接口与设计通信。

Testbench

d0

处方 Tx

m0

d1

d2

4 x4 ATM

路由器

m1

平方米

d3

m3

图10.1带接口的路由器和测试台

顶级模块必须连接一系列接口才能在样例10.6中使用testbench。示例10.4中的模块实例化了一个接口数组,并将这个数组传递给testbench。因为DUT是用四个RX和四个TX接口编写的,所以需要将各个接口数组元素传递到DUT实例中。

示例10.4带有接口数组的顶级模块

10.1.2 带有虚拟接口的测试平台

一种好的OOP技术是创建一个使用句柄来引用对象的类,而不是使用硬编码的对象名称。在这种情况下,您可以创建单个驱动程序类和单个监视器类,让它们对数据的句柄进行操作,然后在运行时传递句柄。

与示例10.3一样,示例10.5中的程序块仍然将4个Rx和4个Tx接口作为端口传递,但它创建了一个虚拟接口数组vRx和vTx。这些现在可以传递到驱动程序和监视器的构造函数中。

示例10.5使用虚拟接口的Testbench

您也可以跳过虚拟接口数组变量,在端口列表中创建一个数组。这些接口被传递给构造函数,如示例10.6所示。

示例10.6使用虚拟接口的Testbench

示例10.7中的任务monitor::receive_cell与示例10.3中的任务receive_cell0相似,不同之处是它使用了虚拟接口名称Tx而不是物理接口Tx0。

示例10.7使用虚拟接口的监视类

在创建一个testbench时,一个常见的错误是在虚拟接口声明中忽略modport名称。示例10.5中的程序声明了Tx_if。TB Tx0在端口列表中,所以它只能将Tx0分配给用TB modport声明的虚拟接口。请参阅示例10.7中虚拟接口Tx的声明。

10.1.3 连接Testbench到端口列表中的接口

这本书展示了连接到DUT的端口列表中的接口的测试。这种风格对于总是使用端口中的信号连接模块的Verilog用户来说很舒服。示例10.8是顶级模块,也称为测试工具,它使用端口列表中的接口连接DUT和测试。

示例10.8使用端口列表中的接口测试线束

示例10.9显示了端口列表中带有接口的程序块。

示例10.9使用端口列表中的接口进行测试

如果在设计中添加新的接口会发生什么?示例10.10中的测试工具声明了新总线,并将其放入端口列表中。

示例10.10 Top模块,在测试的端口列表中有第二个接口

现在,您必须更改示例10.9中的测试,以在端口列表中包含另一个接口,以提供示例10.11中的测试。

示例10.11使用端口列表中的两个接口进行测试

向您的设计添加一个新的接口意味着您需要编辑所有现有的测试,以便它们可以插入到测试工具中。你怎样才能避免这项额外的工作呢?避免端口连接!

10.1.4 将测试连接到使用XMR的接口

您的测试需要连接到harness中的物理接口,因此使用交叉模块引用(XMR)和程序块中的虚拟接口,如示例10.12所示。您必须使用虚拟接口,这样才能在顶层模块中为它分配物理接口。

示例10.12使用虚拟接口和XMR测试

程序连接到示例10.13中所示的测试束。

示例10.13测试端口列表中没有接口的线束

VMM等方法推荐使用这种方法,以使测试代码更具可重用性。如果您向您的设计中添加一个新的接口,如示例10.14所示,那么测试管理将发生变化,但是现有的测试不必改变。

示例10.14使用第二个接口测试线束

样例10.14中的管理与样例10.12中的不知道新接口的测试以及样例10.15中的知道新接口的测试一起工作。

示例10.15使用两个虚拟接口和XMRs进行测试

有些方法有一个规则,使测试和利用之间的连接比传统端口稍微复杂一些,但这意味着即使设计发生变化,您也不必修改现有的测试。本书中的例子使用了端口列表中接口的简单风格,但您应该决定测试重用是否重要到足以改变您的编码风格。

10.2. 连接到多个设计配置

验证设计的一个常见挑战是它可能有几种配置。您可以为每个配置创建一个单独的测试平台,但是当您探索每个替代方案时,这可能会导致组合爆炸。相反,您可以使用虚拟接口动态连接到可选接口。

10.2.1 网的设计

示例10.16是由一个简单的复制组件,一个8位计数器构建的。这类似于DUT, DUT有一个设备,如网络芯片或处理器,在mesh配置中重复实例化。关键思想是,顶层模块创建一个接口和计数器数组。现在,testbench可以将其虚拟接口阵列连接到物理接口。

示例10.16显示了计数器接口X_if的代码。如果代码使用$monitor打印信号值,那么当信号发生变化时就会显示这些值。相反,always块等待直到时钟块改变,然后用$strobe在时间槽的末尾打印信号的值。结果是您现在在更高的抽象级别上工作,看到的是一个周期一个周期的值,而不是单个事件。

示例10.16 8位计数器接口

示例10.17中显示了一个简单的计数器。

示例10.17使用X_if接口的计数器模型

示例10.18中的顶级模块使用generate语句进行实例化

NUM_XI接口和计数器,但只有一个测试台。

示例10.18顶级模块,包含一个虚拟接口数组

在示例10.19中,testbench中的关键行是本地虚拟接口数组vxi被分配到指向顶层模块top.xi中的物理接口数组的地方。(注意,这个例子采用了一些捷径

第8章的建议。为了简化示例10.18,环境类已经与测试合并,而生成器、代理和驱动程序层已经压缩到驱动程序中。)

测试台假设至少有一个计数器,因此至少有一个X接口。如果设计的计数器为零,则必须使用动态数组来保存虚拟接口,因为固定大小的数组的大小不能为零。接口的实际数量作为参数从顶级模块传递。

样例10.19使用虚拟接口Counter testbench

当然,在这个简单的例子中,您可以直接将接口传递到驱动程序的构造函数中,而不是单独创建一个变量。

在示例10.20中,驱动程序类使用单个虚拟接口来驱动和采样计数器的信号。

示例10.20使用虚拟接口的驱动程序类

  1. 使用类型定义和虚拟接口

    您可以通过替换" virtual X_if "来减少输入量,并确保始终使用正确的mod- port。TB”,使用接口、测试工作台和驱动程序的类型定义,如示例10.21到10.23所示。

    示例10.21带有类型定义的接口

示例10.22 Testbench为虚拟接口使用typedef

示例10.23为虚拟接口使用typedef的驱动程序

10.2.2 使用端口传递虚拟接口阵列

前面的示例使用跨模块引用(XMR)传递虚拟接口数组。另一种方法是在端口中传递数组。由于顶部模块中的数组是静态的,所以只需要引用一次,因此XMR样式比使用通常用于传递更改值的端口更有意义。

示例10.24使用一个全局参数定义X个接口的数量。下面是top模块的一个片段。

使用虚拟接口数组的示例10.24 Testbench

示例10.25显示了使用虚拟接口的测试平台。它创建了一个虚拟接口数组,这样就可以将它们传递到驱动程序类的构造函数中,或者直接从端口传递接口。

样例10.25 Testbench通过带端口的虚拟接口

10.3. 参数化接口和虚拟接口

10.2节中的例子显示了一个8位计数器和匹配总线。如果你想改变柜台的宽度怎么办?Verilog-1995允许您参数化模块,并且系统Verilog通过参数化接口和虚拟接口扩展了这个概念。

首先,使用参数更新计数器(最初在示例10.17中显示)。这只需要更改前几行。样例10.26现在也将接口的编号作为参数传入。

示例10.26使用X_if接口的参数化计数器模型

接下来,示例10.27将位宽参数添加到示例10.16中的接口。

示例10.27 8位计数器的参数化接口

示例10.28显示了传递到testbench的参数。

示例10.28使用虚拟接口数组的参数化顶层模块

最后是testbench模块和驱动程序类,如示例10.29和10.30所示。这些虚拟接口必须参数化。的语法

这有点棘手,特别是当你有modport的时候。首先,从示例10.19更新的testbench。注意参数是如何在类型名和modport之间传递的。

样例10.29使用虚拟接口的参数化计数器testbench

示例10.30使用虚拟接口的驱动程序类

10.4. 接口中的过程代码

正如一个类既包含变量又包含例程一样,一个接口也可以包含例程、断言、初始块和always块等代码。回想一下,接口包括两个块之间通信的信号和功能。因此,总线的接口块可以包含信号和执行命令(如读或写)的例程。这些例程的内部工作对外部块是隐藏的,允许您推迟实际的实现。对这些例程的访问是使用modport语句控制的,就像信号一样。一个任务或函数被导入到modport中,这样它就可以被任何使用modport的block看到。

这些例程可以被设计和测试工作台使用。这种方法

确保两者使用相同的协议,消除测试工作台错误的共同来源。然而,并不是所有的合成工具都能处理接口中的例程。

在设计团队和测试团队之间共享代码的一个问题是,设计团队和验证团队之间的独立性丧失了。如果只有一个人实现了两部分的接口协议,谁来检查它?

您可以在接口中使用断言来验证协议。断言可以检查非法的组合,例如违反协议和未知值。它们可以显示状态信息并立即停止模拟,以便您可以轻松调试问题。当好的事务发生时,也可以触发断言。功能覆盖代码使用这种类型的断言来触发覆盖平均信息的收集。

10.4.1 并行协议接口

在创建系统时,您可能不知道是选择并行协议还是串行协议。示例10.31中的接口有两个任务,initiatorSend和targetRcv,它们使用接口信号在两个块之间发送事务。它通过两个8位总线并行地发送地址和数据。

示例10.31接口与任务并行协议

10.4.2 串行协议接口

示例10.32中的接口实现了发送和接收地址和数据值的串行接口。它具有与示例10.31相同的接口和例程名称,因此您可以在这两者之间进行交换,而不必更改任何设计或testbench代码。

示例10.32串行协议任务接口

10.4.3 接口代码的限制

接口中的任务对于RTL来说很好,因为RTL的功能是严格定义的。然而,对于任何类型的验证IP来说,这些任务都不是一个好的选择。接口及其代码不能基于配置进行扩展、重载或动态实例化。接口不能有私有数据。验证需要的任何代码

最大的灵活性和可配置性,因此应该使用在程序块中运行的类。

10.5. 结论

SystemVerilog中的接口构造提供了一种强大的技术,可以将块之间通信的连接性、计时和功能组合在一起。在本章中,您看到了如何创建一个连接到包含多个接口的许多不同设计配置的单个测试台。您的信号层代码可以在运行时通过虚拟接口连接到数量可变的物理接口。此外,接口可以有驱动信号和断言检查协议的例程,但将测试放在程序块中,而不是接口中。

在许多方面,接口可以类似于具有指针、封装和抽象的类。这使您可以创建一个接口,在比Verilog的传统端口和连接更高的级别上为系统建模。只需记住将testbench保存在program块中。

10.6. 练习

  1. 如注释所示,完成以下代码。

  1. 使用练习1的解决方案,按照注释的指示完成下面的代码。

  1. 修改下面的程序声明以使用跨模块引用(XMR)。假设包含接口的顶层模块名为top。

修改下面程序测试的实例化以使用跨模块引用(XMR)。

  1. 将解决方案扩展到练习3,创建NUM_RISC_BUS环境并创建NUM_RISC_BUS接口。

  2. 将解决方案扩展到练习3,为虚拟接口使用typedef。

  3. 修改下面的接口以使用一个参数ADDRESS_WIDTH。缺省情况下,寻址空间支持256个字。

results matching ""

    No results matching ""