第一章 验证指南

有些人认为我们缺乏描述完美世界的编程语言……

(《黑客帝国》,1999)

想象一下,你被指派给某人盖一所房子。你应该从哪里开始呢?你从选择门窗开始,选择油漆和地毯的颜色,还是选择浴室设备?当然不是!首先,你必须考虑业主将如何使用空间,以及他们的预算,这样你就可以决定建造什么类型的房子。你应该考虑的问题是:他们喜欢烹饪,想要一个高端厨房,还是更喜欢在家庭影院看电影,吃外卖披萨?他们想要一间家庭办公室还是一间额外的卧室?还是他们的预算限制了他们在一个更普通的房子?

在开始学习SystemVerilog语言的细节之前,您需要了解您计划如何验证特定的设计,以及这如何影响testbench结构。就像所有的房子都有厨房、卧室和浴室一样,所有的测试工作台都有一些共同的刺激产生和反应检查结构。本章介绍了一组指导方针和编码风格,用于设计和构建满足您特定需求的测试平台。这些技术使用了SystemVerilog (VMM)、Bergeron等人(2006)的验证方法手册中显示的一些相同的概念,但没有基类。其他方法,如UVM和OVM,都有相同的概念。

作为一个验证工程师,你可以学到的最重要的原则是:“bug是好的。“不要羞于发现下一个漏洞,不要在每次发现漏洞时犹豫地敲响警钟,更重要的是,要始终跟踪发现的每个漏洞的细节。整个项目团队都假定设计中存在bug,因此在tape-out之前发现的每个bug都会减少一个最终落入客户手中的bug。在设计周期的每一个阶段,如规格说明、编码、合成、制造,修复错误的成本会增加10倍,所以要尽早并经常找到这些错误。你需要尽可能地扭曲和折磨设计现在就提取所有可能的bug,尽管它们仍然很容易修复。不要让设计师偷走所有的荣耀——没有你的工艺和狡猾,设计可能永远不会成功!本书假设您已经了解Verilog语言,并且希望学习Verilog硬件验证语言(HVL)系统。HVL的一些典型特征将其与硬件描述语言区分开来,例如

Verilog或VHDL是:

  • Constrained-random刺激一代

  • 功能覆盖

  • 更高级的结构,特别是面向对象的编程和事务级建模

  • 多线程和进程间通信(IPC)

  • 支持HDL类型,如Verilog的4状态值

  • 与事件模拟器紧密集成,以控制设计

还有许多其他有用的特性,但是这些特性允许您在更高的抽象级别上创建testbench,而不是使用HDL或编程语言(如C)所能实现的。

1.1 验证过程

核实的目的是什么?如果你的回答是“寻找bug”,你只说对了一部分。硬件设计的目标是根据设计规范创建一个执行特定任务的设备,如DVD播放器、网络路由器或雷达信号处理器。作为验证工程师,你的目的是确保设备能够成功地完成这项任务——也就是说,设计是对规格的准确描述。当存在差异时,就会出现bug。设备在其原始用途之外的使用行为不是你的责任,尽管你想知道这些界限在哪里。

验证过程与设计创建过程并行。设计者阅读一个块的硬件规范,解释人类语言描述,并以机器可读的形式(通常是RTL代码)创建相应的逻辑。为此,他或她需要理解输入格式、转换函数和输出格式。这种解释总是含糊不清,可能是由于原始文件中的含糊不清、缺少细节或描述相互矛盾。作为一个验证工程师,您还必须阅读硬件规范,创建验证计划,然后按照它来构建测试,显示RTL代码正确地实现了特性。因此,作为一个验证工程师,你不仅要理解设计和它的意图,而且,你必须考虑所有的角落测试用例,设计者可能没有想到。通过让多个人员执行相同的解释,您已经为设计过程增加了冗余。作为验证工程师,您的工作是阅读相同的硬件规范,并对它们的含义做出独立的评估。然后您的测试将测试RTL,以显示它与您的解释相匹配。

1.1.1 不同水平的测试

在设计中潜伏着什么类型的bug ?最容易检测的是块级别,即由单个人创建的模块。ALU是否正确地将两个数字相加?是否每个总线事务都成功完成了?所有的包都通过网络交换机的一部分了吗?编写定向测试来发现这些bug几乎是微不足道的,因为它们完全包含在设计块中。

在块水平之后,下一个寻找差异的地方是块之间的边界。这就是所谓的集成阶段。当两个或更多的设计师阅读相同的描述却有不同的解释时,有趣的问题就出现了。对于一个给定的协议,什么信号会在什么时候改变?第一个设计器使用规范的一个视图构建总线驱动程序,而第二个设计器使用稍微不同的视图构建接收器。你的工作是找到逻辑上有争议的领域,甚至可能帮助调和这两种不同的观点。

为了模拟单个设计块,您需要创建从周围所有块产生刺激的测试——这是一项困难的工作。好处是这些低级别模拟运行得非常快。然而,您可能会在设计和测试工作台中都发现bug,因为后者需要大量代码来从丢失的块中提供刺激。当您开始集成设计模块时,它们可以相互刺激,从而减少您的工作量。这些多块模拟可能会发现更多的错误,但它们也运行得更慢。在更高的级别上,分析行为以确定错误的根本原因会花费更多的时间。

在被测设计(DUT)的最高水平上,对整个系统进行测试,但仿真性能大大降低。您的测试应该努力让所有块并发地执行感兴趣的活动。所有的I/O端口都处于活动状态,处理器正在处理数据,缓存正在被填满。有了这些操作,数据对齐和计时错误肯定会发生。

在这个级别上,您可以运行复杂的测试,这些测试让DUT并发执行多个操作,从而使尽可能多的块处于活动状态。如果MP3播放器正在播放音乐,而用户试图从主机上下载新的音乐,会发生什么情况?然后,在下载过程中,用户按下播放器上的几个按钮?你知道,当真正的设备被使用时,有人会做所有这些,所以为什么不在它建成之前试用一下呢?这种测试将决定一个产品是容易使用还是反复锁定。

验证DUT正确执行其指定的功能之后,您需要了解在出现错误时它是如何工作的。设计能否处理部分事务,或数据或控件字段损坏的事务?仅仅试图列举出所有可能的问题是困难的,更不用说确定设计应该如何从这些问题中恢复。错误注入和处理可能是验证中最具挑战性的部分。

当您转移到系统级的验证时,挑战也转移到更高的级别。在块级别,您可以显示单个单元正确地流经ATM路由器的块,但在系统级别,您可能必须考虑如果存在不同优先级的流会发生什么情况。接下来选择哪个单元格在最高级别上并不总是很明显。您可能必须分析来自数千个单元格的统计数据,以查看聚合行为是否正确。

最后一点:你永远无法证明没有bug留下,所以你需要不断地想出新的验证策略。

1.1.2 验证计划

验证计划来源于硬件规范,并包含需要执行哪些特性和要使用的技术的描述。这些步骤可能包括定向或随机测试、断言、软硬件协同验证、仿真、形式证明和验证IP的使用。关于验证的更完整的讨论见Bergeron(2006)。

1.2 验证方法手册

您手中的这本书借鉴了VMM,它植根于由Janick Bergeron和Qualis Design的其他人开发的方法论中。他们从行业标准的实践开始,并根据他们在许多项目中的经验来完善它们。VMM的技术最初是为与OpenVera语言一起使用而开发的,并在2005年为SystemVerilog进行了扩展。VMM及其前身,用于Vera的参考验证方法(RVM),已经成功地用于验证广泛的硬件设计,从网络设备到处理器。新的方法,如OVM和UVM,使用了许多类似的思想。这本书是基于许多相同的概念,所有这些方法,虽然大大简化。

这本书是SystemVerilog语言的用户指南。它描述了许多语言结构,并为选择最适合您需要的语言提供了指导方针。如果你是验证的新手,对面向对象编程(OOP)缺乏经验,或者不熟悉约束随机测试(CRT),这本书可以告诉你选择正确的路径。一旦熟悉了它们,您就会发现UVM和VMM是很容易的一步。

那么,为什么这本书没有教你UVM或VMM呢?像任何先进的工具一样,这些方法是为有经验的用户而设计的,并且擅长解决困难的问题。您是否负责验证一个拥有许多通信协议、复杂错误处理和IP库的1亿门设计?如果是这样,那么UVM或VMM是合适的工具。然而,如果您正在使用单一协议处理较小的模块,则可能不需要如此健壮的方法。记住,你的街区是一个更大系统的一部分;符合UVM或vmm的代码在项目期间和以后的设计中都可以重用。验证的成本超出了您当前的项目。

UVM和VMM有一组用于数据和环境的基类,以及用于管理日志文件和进程间通信的实用程序,等等。这本书是SystemVerilog的简介,展示了涉及这些类和实用程序的技术和技巧,让您深入了解它们的构造。

1.3 基本的Testbench功能

测试台的目的是确定DUT的正确性。这可以通过以下步骤完成。

  • 产生刺激

  • 刺激DUT

  • 捕获的响应

  • 检查正确性

  • 根据总体的验证目标来衡量进展

有些步骤由testbench自动完成,而其他步骤则由您手动确定。您选择的方法决定了如何执行上述步骤。

1.4 直接测试

传统上,当面临验证设计正确性的任务时,您可能会使用定向测试。使用这种方法,您可以查看硬件规范,并编写一个带有测试列表的验证计划,每个测试都集中于一组相关特性。有了这个计划,您可以编写在DUT中实践这些特性的刺激向量。然后用这些矢量模拟DUT,并手动检查生成的日志文件和波形,以确保设计符合您的预期。一旦测试正常工作,您就可以在验证计划中进行检查,然后进行下一个测试。

这种渐进的方法可以取得稳定的进展,这总是受到希望看到项目取得进展的经理们的欢迎。它还能产生几乎立竿见影的效果,因为当你在指导创建每个刺激载体时,几乎不需要什么基础设施。给定充足的时间和人员,直接测试足以验证许多设计。

图1.1显示了定向测试如何增量地覆盖验证计划中的特性。每个测试都针对一组非常特定的设计元素。如果您有足够的时间,您可以编写整个验证计划100%覆盖所需的所有测试。

如果您没有必要的时间或资源来执行定向测试方法,该怎么办?正如你所看到的,虽然你可能总是在前进,但斜率是不变的。当设计复杂度翻倍时,完成它需要的时间也翻倍,或者需要两倍的人来实现它。

图1.1有方向性的测试进度随时间的变化

这两种情况都不可取。为了达到100%覆盖率的目标,您需要一种能够更快地发现bug的方法。蛮力不起作用;如果您试图验证32位加法器的输入的每个组合,您的模拟将仍然运行多年后的项目应该已经发货。

图1.2显示了被定向测试用例覆盖的总体设计空间和特性。在这个领域中有许多功能,其中一些有bug。您需要编写覆盖所有特性的测试,并找到bug。

图1.2定向测试覆盖率

1.5 方法论基础

这本书采用了以下原则。

  • Constrained-random刺激

  • 功能覆盖

  • 使用事务处理器的分层测试工作台

  • 用于所有测试的公共测试台架

  • 特定于测试用例的代码与testbench分离

所有这些原则都是相互关联的。随机刺激对于复杂的设计是至关重要的。定向测试会发现你预期在设计中出现的bug,而随机测试则会发现你从未预料到的bug。当使用随机刺激时,您需要功能覆盖来测量验证过程。此外,一旦你开始使用自动生成的刺激,你就需要一种自动的方法来预测结果——通常是记分板或参考模型。构建testbench基础设施,包括自我预测,需要大量的工作。一个分层的测试台通过将问题分解成可管理的部分来帮助您控制复杂性。事务处理程序为构建这些部分提供了一个有用的模式。通过适当的计划,您可以构建一个testbench基础设施,它可以被所有的测试共享,并且不需要不断地修改。你只需要留下“挂钩”,让测试执行某些操作,如塑造刺激和注入干扰。相反,特定于单个测试的代码必须与测试工作台分离,以防止使基础设施复杂化。

构建这种风格的测试平台比传统的定向测试平台需要更长的时间——特别是自检部分。因此,在运行第一个测试之前可能会有很大的延迟。这种差距会让经理感到恐慌,所以把这种努力作为你日程的一部分吧。在图1.3中,你可以看到第一次随机测试运行前的初始延迟。

图1.3随时间变化的约束随机测试进度与定向测试进度

虽然这一前期工作似乎令人生畏,但回报却很高。您创建的每个随机测试都共享这个公共测试工作台,而不是从头编写每个测试的定向测试。每个随机测试都包含几十行代码,以在特定方向约束刺激,并导致任何所需的异常,如创建协议违背。结果是,您的单个受限随机测试平台现在比许多定向测试平台更快地找到bug。

当发现速度开始下降时,您可以创建新的随机约束来探索新的区域。最后几个bug可能只能通过定向测试找到,但是绝大多数的bug可以通过随机测试找到。如果您创建了一个随机测试平台,您总是可以将其约束为创建的定向测试,但是定向测试平台永远不会变成一个真正的随机测试平台。

1.6 Constrained-Random刺激

虽然您希望模拟器生成刺激,但您不想要完全随机的值。您可以使用SystemVerilog语言来描述刺激的格式(“地址是32位;操作码是ADD, SUB或STORE;长度< 32字节”),模拟器选择满足约束的值。约束随机值成为相关刺激将在第6章中讨论。这些值被发送到设计中,也被发送到预测结果应该是什么的高级模型中。将设计的实际输出与预测输出进行了比较。

图1.4显示了约束随机测试在整个设计空间的覆盖范围。首先,请注意随机测试通常比定向测试覆盖更广的空间。这个额外的覆盖范围可能会与其他测试重叠,或者可能会探索您没有预料到的新领域。如果这些新区域发现了一个bug,那么你就很幸运了!如果新的区域是不合法的,你需要编写更多的约束来防止随机生成产生非法的设计功能。最后,您可能仍然需要编写一些定向测试,以找到任何其他约束随机测试所不覆盖的案例。

图1.5显示了实现完全覆盖的路径。从左上角的基本约束随机测试开始。用许多不同的种子运行它们。

图1.4约束随机测试覆盖率

约束的随机测试

导演

很多次跑步,不同的种子

添加约束

导演testcase

最少的代码修改

功能覆盖

图1.5覆盖收敛

当您查看功能覆盖率报告时,请找到覆盖率中存在缺口的漏洞。然后,可以通过使用新的约束,或者向DUT中注入错误或延迟,进行最小的代码更改。把大部分时间花在这个外部循环上,只为随机测试不太可能达到的少数特性编写定向测试。

1.7 你应该随机化什么?

当您考虑对设计的刺激因素进行随机化时,您可能首先选择数据字段。这些值是最容易创建的-只需调用$random()。问题是,这种选择在漏洞发现方面的回报非常低。随机数据发现的主要错误类型是数据路径错误,可能是位级错误。您需要找到控制逻辑中的错误,这是最棘手问题的根源。

广义地考虑所有的设计输入,例如下面的内容。

  • 设备配置

  • 环境配置

  • 输入数据

  • 协议异常

  • 错误和违规

  • 延迟

这些将在第1.7.1到1.7.4节中讨论。

1.7.1 设备与环境配置

在测试RTL设计时遗漏bug最常见的原因是什么?没有尝试足够多的不同配置。大多数测试只是在重新设置后使用设计,或者应用一组固定的初始化向量将其置于已知状态。这就像在PC安装完之后测试它的操作系统,但是没有安装任何应用程序。当然,性能很好,没有任何崩溃。

在真实的环境中,DUT的配置随着使用时间的延长而变得更加随机。例如,我帮助一家公司验证了一个有2000个输入通道和12个输出通道的时分多路复用开关。验证工程师说:“这些通道可以映射到另一边的各种配置。每个输入可以作为单个通道使用,也可以进一步划分为多个通道。棘手的是,尽管在大多数情况下使用了一些标准的分解方法,但任何分解组合都是合法的,留下了大量可能的客户配置。”

为了测试这个设备,工程师必须编写几十行直接的测试平台代码来配置每个通道。因此,她永远无法尝试使用超过几个频道的配置。我们一起编写了一个测试平台随机的参数为一个单一的通道,然后把它放在一个循环来配置所有的开关的通道。现在她有信心她的测试将发现配置相关的错误,这些错误在以前可能会被忽略。

在现实世界中,您的设备在一个包含其他组件的环境中运行。在验证DUT时,它连接到一个模拟此环境的测试平台。您应该随机化整个环境配置,包括模拟的长度、设备的数量以及它们的配置方式。当然,您需要创建约束来确保配置是合法的。

在Synopsys的另一个客户示例中,一家公司创建了一个I/O开关芯片,将多个PCI总线连接到内部内存总线。在模拟开始时,他们随机选择了PCI总线的数量(1-4)、每个总线上的设备数量(1-8)以及每个设备的参数(主或从、CSR地址等)。他们使用功能覆盖来跟踪测试的组合,这样他们就可以确定他们已经覆盖了几乎所有可能的组合。

其他环境参数包括测试长度、错误注入速率和延迟模式。更多的例子见Bergeron(2006)。

1.7.2 输入数据

当您阅读有关随机刺激的内容时,您可能会想到处理一个事务,例如总线写入或ATM单元格,并用随机值填充数据字段。实际上,只要您像第5章和第8章中所示的那样仔细准备事务类,这种方法就相当简单。您需要预测任何分层协议和错误注入,以及计分板和功能覆盖。

1.7.3 协议异常、错误和违反

没有什么比电脑或手机等设备上锁更令人沮丧的了。很多时候,唯一的解决办法就是关闭它,然后重新启动。很有可能在产品内部有一个逻辑,经历了某种错误条件,它不能恢复,从而阻止了设备的正确工作。

如何防止这种情况发生在正在构建的硬件上?如果在实际的硬件中可能出现错误,您应该尝试模拟它。看看所有可能发生的错误。如果总线事务未完成会发生什么?如果遇到无效操作?设计规范是否说明两个信号是相互排斥的?同时驱动它们,并确保设备继续正常运行。

正如您试图用格式不良的命令触发硬件一样,您也应该尝试捕捉这些事件。例如,相互回忆

独家的信号。您应该添加检查器代码来查找这些违规行为。当发生这种情况时,您的代码至少应该打印一条警告消息,最好生成一个错误并结束测试。花几个小时跟踪代码,试图找到故障的根源,这是令人沮丧的,特别是当您可以通过一个简单的断言在源代码附近捕获故障时。参见Vijayaraghavan[2005],了解更多关于在测试平台和设计代码中编写断言的指导方针。只要确保您可以禁用在出现错误时停止模拟的代码,这样您就可以轻松地测试错误处理。

1.7.4 延迟和同步

您的测试平台应该以多快的速度发送刺激?您应该选择随机的延迟来帮助捕获协议bug。具有最短延迟的测试很容易编写,但不会创建所有可能的刺激组合。当选择实际的延迟时,围绕边界条件的微妙bug往往会被揭示出来。

一个区块可以正确地处理来自单一界面的所有可能的刺激排列,但当事务流入多个输入时,可能会出现微妙的错误。试着协调不同的司机,使他们能够以不同的时间速率交流。如果输入以可能最快的速度到达,但输出被限制回较慢的速度,那该怎么办?如果刺激同时到达多个输入点会怎样?如果是交错的,有不同的延迟呢?使用功能覆盖(将在第9章中讨论)来度量随机生成的组合。

1.7.5 并行随机测试

如何运行测试?定向测试有一个测试平台,它产生一组独特的刺激和反应向量。为了改变刺激,你需要改变测试。一个随机测试由testbench代码和一个随机种子组成。如果你做同样的测试50次,每次都用一种独特的种子,你会得到50种不同的刺激。使用多种种子可以扩大测试的覆盖范围,并扩展工作。

您需要为每个模拟选择一个唯一的种子。有些人使用一天中的时间,但这仍然会导致重复。如果您正在使用跨CPU场的批处理队列系统,并告诉它在午夜启动10个作业,该怎么办?多个作业可以在不同的计算机上同时启动,因此将获得相同的随机种子并运行相同的刺激。您应该在种子中加入处理器名称。如果您的CPU场包括多处理器机器,那么您可以使用相同的种子让两个作业在午夜开始运行,因此您还应该添加进程ID。现在所有作业都有唯一的种子。

你需要计划如何组织你的文件来处理多个模拟。每个作业都创建一组输出文件,比如日志文件和功能覆盖率数据。您可以在不同的目录中运行每个作业,或者尝试为每个文件指定唯一的名称。最简单的方法是将随机种子值附加到目录名。

1.8 功能覆盖

第1.6节和第1.7节展示了如何创建能够随机穿越整个可能输入空间的刺激。使用这种方法,您的测试工作台经常访问一些区域,但是要到达所有可能的状态需要花费太长时间。即使给予无限的模拟时间,无法到达的状态也永远不会被访问。为了核对验证计划中的项目,您需要度量已验证的内容。

度量和使用功能覆盖率的过程由几个步骤组成。首先,向测试台中添加代码,以监视进入设备的刺激及其反应和响应,以确定执行了哪些功能。运行几个模拟,每个模拟使用不同的种子。接下来,将这些模拟的结果合并到一个报告中。最后,你需要分析结果,并决定如何创造新的刺激,以达到未经测试的条件和逻辑。第9章描述SystemVerilog中的功能覆盖。

1.8.1 从功能覆盖到刺激的反馈

随机测试使用反馈进行发展。初始测试可以使用许多不同的种子运行,从而创建许多惟一的输入序列。最终,即使使用了新的种子,测试也不太可能产生能够到达设计空间的刺激。随着功能覆盖逐渐接近其极限,您需要更改测试,以找到新的方法来达到设计的未覆盖区域。这就是所谓的“覆盖驱动验证”,如图1.6所示。

图1.6有反馈和没有反馈的测试进度

如果您的测试工作台足够聪明,可以为您完成这些工作,那会怎样呢?在以前的工作中,我编写了一个测试,该测试为处理器生成每个总线事务,并在每个周期中额外触发每个总线终止程序(成功、奇偶校验错误、重试)。这是在HVLs之前,所以我编写了一套很长的定向测试,并花了几天时间排列终止代码,以便在适当的周期触发。经过大量的手分析,我宣布成功- 100%的覆盖率。然后处理器的时间发生了轻微的变化!现在我必须重新分析测试,改变刺激因素。

更高效的测试策略使用随机事务和终止器。你运行的时间越长,覆盖率就越高。作为奖励,即使设计的时间改变了,测试也可以足够灵活地创造有效的刺激。你可以通过添加一个反馈循环来实现这一点,该循环着眼于到目前为止所创造的刺激(生成了所有的写周期吗?),然后改变约束权重(将写权重降为0)。这种改进将极大地减少实现完全覆盖所需的时间,很少有人工干预。

然而,这不是一个典型的情况,因为从功能覆盖到刺激的琐碎反馈。在真实的设计中,你应该如何改变刺激来达到理想的设计状态?这需要深入的设计知识和强大的形式化技术。没有简单的答案,所以动态反馈很少用于受限随机刺激。相反,您需要手动分析功能覆盖率报告,并更改您的随机约束。

反馈被用于形式分析工具,如麦哲伦(Synopsys 2003)。它分析一个设计,以找到所有唯一的、可到达的状态。然后它运行一个简短的模拟来查看访问了多少个状态。最后,它从状态机搜索到设计输入,计算达到任何剩余状态所需的刺激,然后麦哲伦将其应用到DUT。

1.9 Testbench组件

在模拟中,测试台包覆被测单元,就像一个硬件测试器连接到一个物理芯片,如图1.7所示。测试台和测试人员都提供刺激并捕获响应。它们之间的区别是,您的testbench需要在广泛的抽象级别上工作,创建事务和序列,这些事务和序列最终被转换为位向量。测试人员只是在位级上工作。

图1.7试验台设计环境

什么会进入这个testbench块?它由许多总线功能模型(BFM)组成,你可以把它们看作是测试平台组件——对DUT来说,它们看起来像真实的组件,但它们是测试平台的一部分,而不是RTL设计。如果实际设备连接到AMBA、USB、PCI和SPI总线,则必须在测试台上构建能够产生刺激并检查响应的等效组件,如图1.8所示。这些不是详细的、可综合的模型,而是遵循协议并执行得更快的高级事务处理程序。另一方面,如果你是使用fpga或仿真进行原型设计,BFMs确实需要是可合成的。

图1.8试验台组件

1.10 分层Testbench

任何现代验证方法的关键概念都是分层的testbench。虽然这个过程可能看起来使测试工作台更复杂,但它实际上有助于将代码分成可以单独开发的更小的部分,从而使您的任务更容易。不要试图编写一个可以随机生成所有类型刺激的例程,包括合法的和非法的,以及用多层协议注入错误。这个例行程序很快就会变得复杂和不可维护。此外,一种分层的方法允许重用和封装验证IP (VIP),这是面向对象的概念。

1.10.1 一个平面Testbench

当您第一次学习Verilog并开始编写测试时,它们可能看起来像示例1.1中的底层代码,该代码进行了简化的APB (AMBA外围总线)编写。(VHDL用户可能也写过类似的代码)。

样本1.1驱动APB引脚

在编写了几天这样的代码之后,您可能会意识到它非常重复,因此您为总线编写等常见操作创建了任务,如示例1.2所示。

例1.2一个驱动APB引脚的任务

现在您的测试平台变得更简单了,如示例1.3所示

示例1.3低级Verilog测试

通过采取常见操作(如重置、总线读取和写入)并将它们放入例程中,您将变得更有效率,犯的错误也更少。物理层和命令层的创建是分层测试工作台的第一步。

1.10.2 信号层和命令层

图1.9显示了测试台的底层。

图1.9信号层和命令层

底部是包含被测设计和连接到测试台的信号层。

再上一层是命令层。DUT的输入由运行单个命令的驱动程序驱动,例如总线读或写。DUT的输出驱动接受信号转换的监视器,并将它们组合成命令。断言也跨越命令/信号层,因为它们查看单个信号,也跨越整个命令进行更改。

1.10.3 功能层

图1.10显示了添加了功能层的testbench,该层向下提供给命令层。代理块(在VMM中称为事务处理程序)接收更高级别的事务,如DMA读或写,并将它们分解为单独的命令或事务。这些命令也被发送到预测事务结果的记分牌。该检查器将来自监视器的命令与记分板上的命令进行比较。

图1.10添加功能层的测试台架

1.10.4 层的场景

功能层由场景层的generator驱动,如图1.11所示。什么是情景?请记住,作为一名验证工程师,你的工作是确保该设备完成其预期任务。一个示例设备是MP3播放器,它可以同时从其存储中播放音乐,从主机下载新音乐,并响应用户的输入,例如调整音量和音轨控制。每一个操作都是一个场景。下载一个音乐文件需要几个步骤,比如控制寄存器的读写设置操作,多路DMA写入传输歌曲,然后再进行另一组读写操作。测试工作台的场景层使用参数(如跟踪大小和内存位置)的约束随机值编排所有这些步骤。

图1.11添加场景层的测试台架

testbench环境中的区块(在图1.11中的虚线内)是在开发开始时编写的。在项目期间,它们可能会发展,您可能会添加功能,但是这些块不应该因单个测试而改变。这是通过在代码中留下“钩子”来实现的,这样测试就可以改变这些块的行为,而不必重写它们。您可以使用工厂模式(第8.2节)和回调(第8.7节)创建这些钩子。

1.10.5 测试层和功能覆盖

现在你在测试台的顶部,在测试层,如图1.12所示。在DUT块之间发生的设计错误很难发现,因为它们涉及到多个人员阅读和解释多个规范。

这个最高层次的测试是指挥:他不演奏任何乐器,而是引导别人的努力。测试包含创建刺激的约束条件。

功能覆盖度量在完成验证计划需求过程中的所有测试的进度。功能覆盖代码在项目中发生变化随着各种标准的完成。这段代码经常被修改,因此它不是环境的一部分。

您可以在一个受限随机环境中创建一个定向测试。只需将一段定向测试代码插入到随机序列的中间,或者将两段代码并行放置。定向代码执行你想要的工作,但是随机的“背景噪音”可能会导致一个bug变得可见,也许是在一个你从未考虑过的块中。

图1.12所有层的完整测试台架

您的测试台中需要所有这些层吗?答案取决于你的DUT是什么样的。一个复杂的设计需要一个复杂的测试平台。您总是需要测试层。对于简单的设计,场景层可能非常简单,您可以将其与代理合并。在评估测试设计的工作量时,不要计算门的数量;数一数设计师的数量。每当您向团队中添加另一个人时,您就增加了对规范的不同解释的机会。典型的硬件团队需要为每个设计师配备两个以上的验证工程师。

你可能需要更多的层。如果你的DUT有几个协议层,每个都应该在testbench环境中有自己的层。例如,如果您有用IP包装并以以太网数据包发送的TCP流量,请考虑使用三个单独的层进行生成和检查。更好的是,使用现有的验证组件。

关于图1.12的最后一点说明。它显示了块之间的一些可能的连接,但您的测试工作台可能有不同的设置。测试可能需要深入到驱动层以强制产生物理错误。这里所描述的只是指导方针——让你的需求指导你所创造的东西。

1.11 构建分层测试平台

现在是时候看看前面的图并学习如何将组件映射到SystemVerilog结构中了。

1.11.1 创建简单的驱动程序

首先,仔细看看其中一个街区,司机。

图1.13驱动器连接

如图1.13所示的驱动程序接收代理的命令。驱动程序可能会注入错误或增加延迟。然后,它将命令分解为单独的信号更改,如总线请求和握手。这种testbench块的通用术语是“事务处理器”,其核心是一个循环。示例1.4中显示了事务处理程序的示例代码。

示例1.4基本事务处理代码

第五章介绍了基本的面向对象编程以及如何创建一个对象,该对象包含事务处理程序的程序和数据。事务处理程序的另一个例子是代理。它可以将一个复杂的事务(如DMA)分解为多个总线命令。同样在第5章,您将看到如何构建一个包含数据和例程组成命令的对象。这些对象是使用SystemVerilog邮箱在事务器之间发送的。在第7章中,您将了解在不同层之间交换数据和同步事务的许多方法。

1.12 模拟环境阶段

到目前为止,您已经了解了环境的组成部分。这些部件什么时候执行?您需要清楚地定义协调测试工作台的阶段,以便项目的所有代码一起工作。三个主要阶段是构建、运行和总结。每个步骤都分为更小的步骤。这三个阶段是UVM和VMM许多阶段的一个子集。

构建阶段分为以下几个步骤:

  • 生成配置:随机化DUT和周围环境的配置。

  • 构建环境:根据配置分配和连接testbench组件。testbench组件只存在于testbench中,与使用RTL代码构建的设计中的物理组件相反。例如,如果配置选择了三个总线驱动程序,testbench将在这个步骤中分配和初始化它们。

  • 重置DUT。

  • 配置DUT:根据第一步生成的配置,加载DUT命令寄存器。

运行阶段是测试实际运行的阶段。它有以下步骤:

  • 启动环境:运行测试工作台组件,如BFMs和刺激生成器。

  • 运行测试:开始测试,然后等待它完成。判断一个定向测试何时完成是很容易的,但是这样做对于一个随机测试来说可能很复杂。您可以使用testbench层作为指南。从顶层开始,等待一层从上一层(如果有的话)耗尽所有的输入,等待当前层变为空闲,然后等待下一个较低的层。您还应该使用超时检查器来确保DUT或testbench不会锁定。

总结阶段有两个步骤:

  • 清扫:在最低层完成后,您需要等待最终的事务从DUT中清空。

  • 报告:一旦DUT空闲,清理测试台中丢失的数据。有时记分牌上保存着从未公开的交易,可能是因为它们被DUT丢弃了。有了这些信息,您可以创建关于测试是通过还是失败的最终报告。如果失败,请确保删除所有功能覆盖结果,因为它们可能不正确。

如图1.12所示,测试启动环境,环境依次运行每个步骤。更多细节可在第8章中找到。

1.13 最大代码重用

为了验证具有数百个特性的复杂设备,你必须编写数百个定向测试。如果使用受限随机刺激,就会编写更少的测试。相反,真正的工作是构建testbench,它包含所有较低的testbench层:场景、功能、命令和信号。所有测试都使用这个测试平台代码,所以它仍然是通用的。

这些指导方针似乎是在推荐一个过于复杂的测试平台,但是请记住,您在测试平台中放入的每一行都可以在每个测试中删除一行。如果您知道您将创建几十个测试,那么创建一个更复杂的测试平台将有很高的回报。当你读第八章的时候要记住这一点。

1.14 Testbench性能

如果这是您第一次看到这种方法,那么与直接测试相比,您可能会对它的工作方式感到不安。一个常见的反对意见是testbench的性能。定向测试通常在几秒钟内模拟,而约束随机测试将在状态空间中徘徊几分钟甚至几小时。这个论证的问题是它忽略了一个真正的验证瓶颈:您创建测试所需的时间。您可以在一天内手工制作一个定向测试,然后在一到两天内调试它,手工验证结果。与您个人投入的时间相比,实际的模拟运行时间显得微不足道。

创建约束随机测试需要几个步骤。第一步也是最重要的一步是构建分层测试平台,包括自检部分。这项工作的好处是由所有测试共享的,因此值得付出努力。第二步是创建特定于验证计划中的目标的刺激。您可能会制造随机的约束,或者以迂回的方式注入错误或违反协议。构建其中一个可能比进行几个定向测试需要更多的时间,但回报将会更高。一个尝试不同协议变体的受限随机测试比在相同时间内创建的少量定向测试更有价值。

约束随机测试的第三个步骤是功能覆盖。这个任务从创建一个强大的验证计划开始,该计划有明确的目标,可以很容易地衡量。接下来,您需要创建SystemVerilog代码,该代码将检测添加到环境中并收集数据。最后,您必须分析结果,以确定您是否达到了目标,以及,如果没有,您应该如何修改测试。

1.15 结论

电子设计的复杂性不断增长,需要一个现代的、系统的、自动化的方法来创建测试工作台。随着项目从规范的每个步骤到RTL编码、gate合成、制造,最后到用户手中,修复bug的成本会增长十倍。定向测试一次只测试一种功能,不能产生设备在现实世界中会受到的复杂刺激和配置。为了产生健壮的设计,您必须使用受限的随机刺激与功能覆盖相结合,以创建尽可能广泛的刺激范围。

1.16 练习

  1. 编写算术逻辑单元(ALU)的验证计划:

    • 异步主动高输入复位

    • 输入时钟

    • 4位符号输入,A和B

    • 在输入时钟的正边缘注册的5位有符号输出C。

    • 4操作码

      • Add: A + B

      • Sub: A−B

      • 位操作转化:

      • 减少或:B

  2. 块级测试的优点和缺点是什么?为什么?

  3. 在系统级进行测试的优点和缺点是什么?为什么?

  4. 定向测试的优点和缺点是什么?为什么?

  5. 受限随机测试的优点和缺点是什么?为什么?

results matching ""

    No results matching ""