当约束随机测试模式生成成为验证设计的实际标准方法时,参考模型就变得必不可少,以检查设计是否产生正确的输出。这些参考模型通常分布在多个模型中,例如检查器、记分板和断言器。
另一个需要创建的模型是覆盖率模型。之所以需要它,是因为必须知道生成的测试是否真正有效,并能测试出之前未测试过的设计方面。初始模型的生成定义了设计中需要确保得到测试的重要方面。覆盖点和覆盖组被定义,尽管它们实际上并不对应于被模拟和检查的功能,但它们被认为是足够好的替代指标。在我个人看来,这是业界做出的一个错误决定,而且代价非常高昂。
在讨论交叉问题之前,你无法与任何验证人员进行讨论。他们会很快指出,如果你定义了一组覆盖点,那么你也需要考虑这些覆盖点的交叉问题,很快你就会陷入一个棘手的问题。最后一点确实如此,因为大多数实际设计中的状态总数是无法遍历所有状态的,因此永远无法进行完全验证。但是——这是一个重要的“但是”——你根本不需要这样做。
代码覆盖率有很多种,例如行覆盖率、切换覆盖率、决策覆盖率和分支覆盖率等等。不胜枚举,但我认为有一种覆盖率非常重要,却常常被忽略——路径覆盖率。路径覆盖率之所以常常被忽略,是因为如果它以展开的形式使用,也会变得难以处理。它并不包含设计在代码中可能遵循的所有路径,而是包含了设计实现的全部功能。但是——这里还有另一个重要的“但是”——这种程度的难处理程度要小得多。
这两者交汇之处在于对“唯一硬件”概念的定义。如果一个硬件经过测试并证明有效,那么它在任何情况下都始终有效,除非其中包含仅在特定条件下才会运行的其他硬件。正是这句话的后半部分让所有人望而却步,不敢尝试使用掩体交叉。然而,如果一开始就没有一个“唯一硬件”,那么这一切都是徒劳。即便如此,你仍然需要购买另一个模拟器。
让我们举一个非常简单的例子,请原谅它的简单。它应该能传达重要的信息。这个概念可以通过抽象来扩展。假设 RTL 代码中有一条语句:如果 a > 42,则执行 'x',否则执行 'y'。我们还假设运算符 '>' 已经过形式化验证,因此我们知道它总是有效的,并且其中没有隐藏任何特殊的代码片段。现在我们可以看一下这个条件语句。该语句总共有两条路径,它们都会导致执行 'x' 或 'y'。要完全验证该条件语句,需要两个值,或者如果您还想考虑到软件工程师总是会出错的情况,则可能需要三个值。这些值是 41、42 和 43。
希望目前还没有人提出异议,但如果您有异议,请告诉我原因。我还假设合成工具运行正常,不会引入任何错误。
如果我们现在用一个寄存器组(比如包含 16 个寄存器)替换寄存器“a”,那么我们可能需要确保当源数据来自这些寄存器中的任何一个时,该行代码仍然有效。这样一来,我们就验证了将正确数据导向操作员的路径和多路复用器。接下来是第一个有争议的部分。如果我们复制这段代码并将其放置在其他地方,需要验证什么呢?我们需要知道操作员是否确实是同一个操作员,如果是,它应该也使用完全相同的硬件进行多路复用和数据传输。没有必要重新进行所有原始验证,只需验证所走的路径以及每条路径中执行的代码即可,因为没有涉及任何独特的硬件。其中不可能隐藏任何错误。
如果我们在代码路径中添加一个输出寄存器,甚至将结果写入同一个寄存器组,同样的道理也适用。一旦我们验证了第一条语句总是能将结果写入正确的寄存器,那么只要没有使用特殊的硬件,就没有必要对每条语句都进行同样的验证。这当然也不意味着为了保证代码覆盖率,我们需要遍历输入寄存器、输出寄存器以及代码中存在的每个运算符及其所有实例。
覆盖率完全缺乏对唯一硬件的概念。虽然我使用的例子很简单,但这个概念应该是可扩展的。路径覆盖率可以帮助我们找到唯一代码,并可以利用这一点来减少需要执行的大量交叉验证。虽然无法完全做到这一点,因为路径覆盖率在某些方面实际上与形式化覆盖相同,即覆盖所有可能的输入和输入序列,但它不必探索所有路径。它仅用于排除冗余情况,这些冗余情况很容易识别,从而减轻验证负担。
我总觉得我肯定漏掉了什么,因为我倡导这件事已经快30年了,但没有人认同我的观点,也没有人为此采取任何行动。
来源:编译自semiengineering
参考链接
https://semiengineering.com/the-verification-conundrum/
本文转自:半导体行业观察,转载此文目的在于传递更多信息,版权归原作者所有。如不支持转载,请联系小编demi@eetrend.com删除。