介绍
功能覆盖、激励生成和运行管理是当今功能验证的三大相互关联的任务。其中,功能覆盖率可以说是最重要的,主要是因为覆盖率收敛是tape的主要标准。覆盖率衡量标准提供了关键的反馈。如图1所示,覆盖率模型应包括端到端功能覆盖、主要接口的事务覆盖、关键RTL结构的结构覆盖和基本代码覆盖。
基于断言的方法有助于发现bug,反馈回归环境的质量。这种方法不仅可以由验证实现,设计可以通过以断言的形式描述他们对设计内部操作的深入行为来提供check。
断言和功能覆盖实际上是同一枚硬币的两面。两者都在寄存器传输水平(RTL)设计中提供详细的观察点。
指南
遵循指南可以使设计更容易。首先,将断言放在RTL代码中,以便它们可以与RTL代码一起管理、更新和重复使用。接下来,通过适当的注释将断言与RTL分开;一些公司建议将ifdef/endif放在断言周围,以便将它们排除在实现流程中的工具之外。
断言不必复杂。事实上,根据我的经验,简单的断言通常和复杂的断言一样有用,包括捕捉复杂的bug。在接下来的部分中,我将探索如何将SystemVerilog 断言属性和覆盖属性置于在设计上。
首先,用于表示特殊信息的寄存器应遵守预定义的合法值(gray_code、odd_parity、even_parity、one-hot)。例如,下面的寄存器声明要求bus_state是one_hot编码的,int_mask中的单个位是相互排斥的,hdl_cmd将只具有合法值。设计或者验证可以捕获它们,以确保它们被功能验证所涵盖。
接下来,当寄存器用作计数器时,它们应该相应地存在概念(最小、最大、范围、值、递减、递增、上溢出、下溢出等)。例如,在下面的寄存器声明中,我们希望确保hdr_adr在1到26的范围内。对于bus_cnt,它不应该下溢和溢出。对于计数器来说,了解他们是否达到了高水位可能很有趣。验证团队可以进行更多的覆盖分析,但需要知道这些计数器的位置,这些指针通常可以在覆盖属性中找到。
接下来,当寄存器用作计数器时,它们应该相应地运行(即与最小、最大、范围、值、递减、增量、增量、下流、溢出等的所有参数一致)。例如,在下面的寄存器声明中,我们希望确保hdr_adr在1到26的范围内。对于bus_cnt,它不应该下溢和上溢。对于计数器来说,了解他们是否达到了高水位也可能很有趣。验证团队可以进行更多的覆盖率分析。
此外,重要的控制寄存器(状态、地址和状态)应正确复位,并且不应具有X或Z状态。
在RTL开发期间定期进行检查。例如,在下面的示例中,当断言cmd_write时,将发生DMA传输。然而,用户没有检查cmd_ready。他假设当cmd_write被采样时,命令处理已经准备就绪。
下面的第一个断言属性有助于确保在断言cmd_write时,信号cmd_ready为真。第二个断言属性确保xdma传输将在cmd_write之后发生。另一个覆盖率属性可以评估成功的DMA传输。
当综合指令与case语句一起使用时,确保假设对指定的case语句成立,并报告任何潜在的仿真/综合不匹配。对于full_case指令,至少有一个case项为真,对于parall_case指令,最多有一个case项为真。例如,在下面的示例中,带有“X”赋值的默认分支用于帮助综合优化。永远不应该达到它。可以添加断言属性来检查此场景。然后,可以使用仿真和形式验证来验证它永远不会被执行。与此同时,我们可以有一个覆盖率属性,可以获取一些关键但罕见的条件。我们希望确保它们已经通过仿真进行了检查和覆盖。
有时候,只有一个分支变量应该是真。例如,在下面的示例中,应始终断言其中一个信号(s0、s1或s2)。我们可以用one_hot属性来验证这一点。同样,覆盖属性可用于捕获控制信号上的临界值变化,例如当pkg_type从`CTRL更改为3'b111时。控制语句为定义这些覆盖属性提供了一个特别好的位置,因为所有控制信号和参数都在本地可用。
当设计团队集成所有SoC模块进行芯片级仿真时,这些模块通常无法相互通信。为了及早发现这些模块间通信问题,添加了协议监视器来检查片上总线和标准接口。在仿真过程中,协议监视器确保模块与其外部接口正确通信。通过收集统计数据和覆盖信息,这些监视器衡量验证环境的有效性。
随着模块的复杂性增加,内部通信方案也越来越复杂。断言对于验证这些模块内接口很有用。
覆盖率和数据流统计对内部接口和外部接口一样重要。此类信息证实了通过接口的数据流,并突出了任何潜在的“瓶颈”。
例如,在下面的数据传输波形中,我想确保数据有效信号断言足够长的时间(两到四个周期),并且当断言有效时数据总线是稳定的。
接下来,在下面的握手数据传输波形中,我想确保数据有效信号的断言时间足够长,以便在断言有效时数据总线是稳定的,并且每个有效的断言后都有一个ack。
计算资源、系统片上总线、互连、buffer和存储器是逻辑结构,通常由仲裁和复杂的控制逻辑共享和控制。在为设计创建验证环境时,团队倾向于首先关注整体规格。相反,它们不会强调这些资源控制逻辑的边界情况。我看到许多回归环境在这些关键场景提供的覆盖率非常低。因此,有问题的场景没有被发现,包括重新流片成本高昂的故障。
在仲裁资源共享的控制器中,根据优先级、权重或credit方案生成request和grant信号。我想确保仲裁方案正确,资源(总线、互连、内存)一次只由一个master处理,并在再次分配之前取消分配。最好用参考模型方法检查这种类型的结构。可以利用Accellera OVL库中的仲裁检查器。预定义的仲裁包括优先权、公平或轮训、FIFO和LRU。
ovl_arbiter检查器可以在RTL代码中实例化。它确保不应在没有请求的情况下发放grant,并且在一个周期内只声明一项grant,并在请求后[min_cks:max_cks]指定的时间窗口内grant。除了检查仲裁方案外,仲裁员checker还有一套全面的cover point和cover group,如cover_req_granted、cover_req_aborted、time_to_grant、concurrent_requests等。还可以添加额外的断言属性,以确保request和grant信号表现良好。例如,仲裁checker假设请求将保留,直到它被grant。我们可以为每个通道生成断言属性,如下所示。
总线桥、dma控制器和路由器等数据传输设备将数据包从一个接口传输到另一个接口。在系统级仿真环境中,数据完整性错误不容易观察到。只有当损坏的数据到达scoreboard时,它们才会被检测到,或者在仿真结束时被标记为丢失。使用断言属性,可以沿着数据传输路径检查它们。它们不应该丢失或损坏,如有必要,我们还可以确保它们遵循先入先出规格,没有任何更改。与其手动创建数据完整性断言,不如利用Accellera OVL库中的fifo断言检查器。fifo检查器确保模块中事务通过模块的数据传输不会损坏。对于具有多个输入和输出端口的模块,例如N-to-M总线矩阵,可以使用OVL多端口fifo检查器。同样,fifo检查器还有一套全面的cover point和cover group,如cover_enqueues、cover_dequeues、cover_fifo_full、cover_fifo_empty、cover_simultaneous_enq_deq等。它们可用于评估设备的数据流。也可以添加其他断言属性。
出于验证目的,我们将有限状态机(FSM)分为两类:接口FSM和计算FSM。接口FSM使用具有明确timing要求的I/O信号。接口FSM的例子有总线控制器、握手FSM等。计算FSM不涉及具有明确定义的timing要求的信号。重要的是不要根据FSM的RTL编写属性。如果设计师误解了需求或在编写RTL时犯了错误,FSM将是错误的。
通常,接口FSM的规范来自协议文档和波形图。断言属性应来自原始规范。他们将确保FSM在时间段内正确采样输入信号,并在输出时序规范内断言响应信号。通常,计算FSM的规范来自控制流图,这在工程文档和标准规范中很常见。为了提高性能和/或简化实现,流程图可能会被划分、扁平化、重新管道化成多个FSM。我们可以捕获具有断言属性的流程图行为创建了一个“可执行”规范。
断言属性可用于捕获流程图中的控制决策、状态跳变和操作序列。在下面的示例中,流程图来自原始规范。
结论
在覆盖率驱动的验证方法中,捕获错误和衡量进度的能力同样重要。幸运的是可以利用用断言捕获错误以及在设计中提供深入的结构覆盖。通过使用覆盖属性和断言库,你可以以很少的增量努力完成这项工作。
最好的建议:在为设计开发断言时考虑覆盖范围。这是在回归环境中实现全面的错误检测能力和结构覆盖率的第一步。
审核编辑:刘清
全部0条评论
快来发表一下你的评论吧 !