测试驱动硬件开发:是对是错?

关于硬件设计有许多观点,其中更为人们所认可的一条是,越早发现错误越好。然而,在传统的“先设计后验证”流程中,开始纠错之前,错误有充分的时间嵌入设计中。其实不必如此。

我们可以借鉴软件领域的一项技术——测试驱动开发 (TDD) ,通过局部修改设计流程来解决这个问题(图1)。在 TDD 中,你需要在编写代码之前为每个代码单元开发测试工具。

这样的顺序调整听起来似乎没有什么意义。但是越来越多的设计团队发现 TDD 带来了巨大的变化:缩短了设计时间,提高了质量,并使他们能够更好地应对漏洞和功能安全等新问题。

“图
图 1.TDD 可以缩短设计周期,通过微小的调整提高质量。

TDD 定义

那么 TDD 是什么呢?它是一种基于单元测试概念的迭代设计方法。在单元测试中,开发人员无需一次性测试整个功能代码块,而是将其分割成单元并进行单独测试,然后再将其集成到该代码块中。那么单元又什么?划分过程需要算法,但更具艺术性。你想定义的单元要有少量输入和输出数据,独立于输入数据(尤其是独立于其他单元的状态)并具备最低限度内部状态的明确功能。

换而言之,定义的单元要易于测试,同时确保单元的数量不会失控。

TDD 的创新在于,你可以在编写代码之前根据需求来定义单元(图 2)。然后,在为单元编写代码之前,再次根据需求和软件架构直接为其编写测试工具。检查测试时,可以对整个代码块的现有代码(如果有)进行测试。由于你还没有编写新代码,所以该模块当然无法通过新的测试。

“图
图 2.TDD 迭代从需求角度出发

现在,你可以为单元编写代码,应用测试工具并进行迭代,直到该单元成功通过测试。因为你定义单元的目的是便于测试,所以运行时间应该很短,并且关键在于,诊断一个错误的时间应该远远低于代码块或系统级错误诊断。在正确定义的单元内非常的简单。在代码单元通过测试之后,将其添加到块中并开始继续处理,为下一个需求单元编写测试工具。

但是为什么要先编写测试,后编写要测试的代码呢? 这是否只是软件人员在故作姿态,故意使用一种虚张声势的怪异方法?经验表明,事实并非如此。先编写测试工具解决了测试中的一个主要问题:开发人员通常会在编写测试和编写(或审查)代码时犯同样的错误。“TDD 要求开发人员从用户的角度去思考,而不是程序员,”XtremeEDA 首席技术专家 Neil Johnson 表示。一直以来 ,他都提倡硬件开发人员采用 TDD。归根结底,你需要根据原始需求来进行测试,而不是自己对代码结构的理解。

另外,还有一点不太明显,TDD 可以引导程序员先专注于所需要的结构和代码块的整体软件架构,然后在深入编写代码。这本身就具有诸多好处。

但功能验证专家 Brian Bailey 发现,测试优先的方法背后有一个更大的问题。TDD 对于设计需求有另外的独立见解:只需运行单元测试即可将其与实施代码进行比较。这种双轨流程不仅可以捕获编码错误,还可以找出对需求的错误解读,甚至需求文档中含糊不清的表述——这些问题在设计流程的后期可能很难诊断。

但它对于硬件有效吗?

你可能会说,好吧,这适用于软件人员。但我们做的是硬件设计。TDD 对我们有什么用?

在一个往往过度承诺设计自动化的世界里,需要保持合理的谨慎。Bailey 说:“如果只是把软件概念转移到硬件上,就会出问题。

软件在调试完成时就基本完工了。

但硬件设计还必须经过合成、安排布线、测试插入、布局……仍然有很大可能性出问题。”

但是在证明设计的功能正确性方面,可以直接应用 TDD。“将某些软件技术用于硬件确实会非常糟糕,”约翰逊表示同意。

“但无论用 C 语言编写程序,用 System Verilog 描述系统,还是用 Verilog 描述结构,TDD 的工作原理都是完全一样的。”

在功能层面,对于硬件设计来说 TDD 概念并不新鲜。“断言功能在某种程度上是 TDD 的一种形式,”Bailey 指出。如果遵循最佳实践,那么就像在 TDD 流程中一样,可以根据需求编写断言功能。但是在硬件设计中探索 TDD 的一个挑战是,在功能设计的标签下可能隐藏着几个截然不同的抽象级别。

许多团队首先用 C 语言或者 Python、 Java 等更现代的语言将需求解释为行为模型。在 TDD 流程中,该模型需要使用自身语言的测试工具。

还有一些团队可能直接从需求出发进入系统 Verilog,在这种情况下,他们可能会在通用验证方法 (UVM) 框架内开发单元测试。“但是有很多设计师从来没有写过行为代码,”Johnson 说。“他们直接从需求文档到 RTL。所以我们看到一些设计师同时使用 TDD 和 Verilog。”

他表示,为硬件描述语言生成行为测试确实需要谨慎一些。毕竟,Verilog 代码中会有更多细节,这远远超过描述单元内功能行为所需的详细程度。在编写的单元测试中可以有意识地提高抽象级别可能有所帮助,例如将该单元视为一组函数,而不是一堆内嵌代码。“你可以创建自己的测试 API,”Johnson 说。

即使设计从 C 语言开始,最终也会达到寄存器传输级别 (RTL)。如果单元测试可以应用于每一个抽象级别,而不是源自一种语言,然后再手工转换成其它语言,那么它将非常有价值。这是 Accellera Portable Stimulus (PS) 规范工作组的目标:定义一种可以一次性指定行为的语言,并使用该规范通过物理原型来激励行为模型以及各种级别的实施(图3)。PS 并不依赖于 TDD,但它一定有助于 TDD。

“图
图 3.Portable Stimulus 将允许通过单次捕获行为意图来激励许多不同的抽象级别。

质疑的声音

伴随着这些承诺,TDD 可能会产生很多问题,尤其是在硬件领域,设计和验证在传统意义上是各自独立的专业,并严格以串行的次序执行。例如,TDD 仅仅是验证工程师试图进入设计领域的一种尝试吗?Bailey 的回答是否定的。“TDD 和 PS 两者的目标是创建并驾齐驱、同等重要的需求视图:一个定义行为,另一个定义实施。”在测试设计和逻辑设计过程中不太可能犯同样的错误,因为它们的任务截然不同。通过这种方式,TDD 几乎可以比肩两个并行作业的独立设计团队:这是一种被证明具有优势的方法,但是对于大多数项目来说,还是太昂贵了。这里没有冗余作业,因为无论如何都要必须创建设计和相应的测试,但质量的改进则大部分来自于冗余。

但是,即使没有单独的验证团队,TDD 的测试优先方法也倾向于将设计人员的注意力首先集中在需求上,然后才会投入到复杂的实施中。Johnson 表示,要想知道你是否真正理解一个要求,最可靠的方法就是试着为它写一个测试。

但是对设计、测试、版本控制、跟踪和构建进行这种划分(批评人士可能会称之为“割裂”)不会成为管理的噩梦吗? 如果没有自动化,是的,有这种可能。结果,许多平台似乎都提供了 TDD 流程自动化。即便如此,这种方法是否还是会影响项目进度?

可能不会,也可能会。长期使用 TDD 的两个软件团队和使用 TDD 的硬件团队都声称,它通常会缩短整个项目周期,有时效果非常显著。这是由于在单元测试中找出了大部分错误,在这个阶段更容易隔离和诊断。只要有一些这样的错误保留到系统集成阶段,就可能会破坏系统验证计划。

然而,有一个不可否认的问题。测试优先的方法在开始编写代码之前进行了一些非编码活动,并且通过交叉测试开发和编码降低了当前编写待测试代码的速度。如果您的上司比较传统,每周都用代码行数或功能覆盖率等指标衡量工作进度,那么就可能会严重误解项目的进展速度。这可能会导致设计团队产生不必要的摩擦。

还有更严重的反对意见,与许多软件项目不同的是,大多数硬件设计包含大量重复利用的知识产权 (IP)——来自第三方的许可,来自开源,或是以前的项目。由于这个 IP 应该已经被验证过了,所以这似乎限制了将 TDD 应用于新编写的系统中相对较小部分的功能设计。

但是,Baily 和 Johnson 一致认为,在 IP 重复利用方面,TDD 也有一个重要作用。在 IP 重复利用中,最常见的失败原因之一是滥用:以未经测试或意想不到的方式使用 IP 块。可以从系统需求出发生成测试,用于验证 IP 块实际上是否会按照您的假设运行。即使无法为了创建单元测试而访问 IP 的行为模型,也可能做到这一点。您可以根据需求单元编写测试,然后对整个 IP 的加密模型进行黑盒测试,而不是测试单个模型代码单元。

这个想法有一些有趣的拓展。Bailey 指出,功能验证中有一个至关重要但又往往被忽略的步骤,即证明 IP 块没有执行非预期的功能。“需求单元通常与您使用的 IP 的结构并不完全匹配,”Bailey 解释说。“这可能会导致 IP 中仍然存在您不使用或根本不知道的功能。如果不慎将其激活,就会造成严重破坏。”通过将 TDD 单元测试与活动监视功能相结合,您可以识别在您的用例中未启用的 IP 代码区域或者可能在不恰当时间被激活的单元,然后将其删除或禁用。这可能是使设计获得功能安全认证的关键步骤。

另一个想法进一步拓展了这个概念。系统中的一些 IP 可能是芯片的形式,而不是设计文件。芯片经常会附带不准确或不正确的数据表,而且没有可执行的模型。通过使用 TDD 生成测试和硬件测试设备开发工具包,对于验证您对该芯片操作的理解非常有帮助,特别是在初始化、休眠/唤醒以及其他的序列中。

最后一个问题目前还没有好的答案。计时怎么处理?在合成之前设置时间限制,这与 TDD 在编码之前创建测试工具的方式非常相似。没有相似之处吗?

答案是否定的。TDD 适用于功能领域,在本质上不计时。但是……做类比的问题在于,Bailey 说,尽管 TDD 可以从系统需求得出功能测试,但目前还没有已知方法能够通过系统性能需求得出时间限制。后者是用最低数据速率和功能延迟来表述的。但是基于 CPU 的系统充满不确定性,一个函数的完成时间和它的硬件构成的内部路径延迟之间几乎没有什么关系。即便使用具有确定性的硬件,这种关系也可能非常复杂。因此,计时问题仍然毫无头绪。

许多硬件设计团队的经验表明,TDD 确实是一种重要的方法论发展方向。它需要大量的个人重新定位,极大地受益于使用一个专业化平台,而且对于大多数设计师来说,初次体验可能会有些陌生。但是,它能够将测试重点聚焦在系统需求上,而且能够在设计流程前期隔离错误,这使它现在足以成为一个非常有效的方法。

本文转载自:Altera - SDJ
转载地址:http://systemdesign.altera.com.cn/test-driven-hardware-development-true-...
声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有,如涉及侵权,请联系小编邮箱:cathy@eetrend.com 进行处理。

最新文章