svunit:将敏捷方法引入功能验证

SNUG San Jose 2009 2009 22 页

svunit:将敏捷方法引入功能验证

会议: SNUG San Jose 2009 作者: Bryan Morris, Rob Saxe (XtremeEDA, Ottawa, Canada) 页数: 22 源文件: SNUG_2009_SanJose_Agile_svunit_paper.pdf


摘要

敏捷方法 Agile Methodology是软件工程中使用的一种高度纪律化的方法论。敏捷方法论中适用于ASIC 专用集成电路/FPGA功能验证 Functional Verification的一个方面,特别是在使用面向对象范式创建验证环境时尤为重要,那就是TDD 测试驱动开发(Test Driven Development)。该过程鼓励为系统中定义的每个关键类创建单独的单元测试 Unit Test。本文描述了在创建功能验证环境时使用SystemVerilog单元测试框架的价值。应用这一敏捷方面可能有助于提高质量和生产力。本文还介绍了使用模型、为SystemVerilog创建的单元测试框架(称为svunit)的设计,以及其使用的具体示例。


第4页 — 1. 引言

敏捷方法 Agile Methodology是一种成熟的软件开发方法论,它提供了一种语言无关的方式来开发软件,能够适应变化的用户需求,并以小型增量步骤交付可工作的代码。

敏捷编程包含的关键过程包括: - 结对编程:两名开发人员共同开发一个软件单元 - 测试驱动开发:在代码之前实现测试 - 持续集成:在小的、明确定义的间隔内构建和测试代码 - 重构:以更好的方式重组代码以提高质量或满足新需求 - 小版本发布:交付工作代码并从小增量改进中获得用户反馈

许多硬件工程师认识到ASIC 专用集成电路/FPGA功能验证 Functional Verification环境的开发与开发复杂软件程序非常相似。虽然敏捷方法论的许多方面可以应用于功能验证环境的开发,但我们认为最容易采纳的一个方面是"测试驱动开发"。

TDD 测试驱动开发引入了验证组件开发的转变:工程师在编写类本身之前先创建验证类行为的单元测试。随着需求的变更,重构后的单元测试可以验证变更不会破坏预期行为。编写类的单元测试还有一个有益的副作用——类的使用模型在实现之前就被清晰地定义和理解。TDD还以可工作的示例形式为类的用户提供了文档。

关于采用此方法论的关键观察是,这是一种设计技术,而非测试技术。


第6页 — 2. 方法论

2.1 使用模型

svunit测试框架包含三个核心基类:

svunit_testcase:单元测试基类。派生类需定义三个任务: - setup():初始化测试条件 - run_test():运行所需的测试 - teardown():清理单元测试

svunit_testsuite:测试套件基类。派生类负责创建测试案例对象并使用add_testcase()添加到套件中。

svunit_testrunner:测试运行器基类。迭代每个测试套件(进而迭代每个单元测试),直至环境中所有单元测试运行完毕。

2.2 svunit设计

svunit框架由以下基类组成,打包为svunit_pkg: - svunit_defines.svh:类型、定义和宏(FAIL_IF/FAIL_UNLESS/INFO/ERROR) - svunit_testcase.sv:单元测试基类 - svunit_testsuite.sv:测试套件基类 - svunit_testrunner.sv:测试运行器基类

2.3 脚本

提供了Perl脚本以简化采用: - create_unit_test.pl:从现有类文件创建关联的单元测试文件,自动生成test_任务模板 - create_testsuite.pl:从_unit_test.sv文件创建测试套件模板 - create_testrunner.pl:从_testsuite.sv文件创建测试运行器模板 - create_svunit.pl:综合前三者,用于已有环境的批量创建

2.4 集成建议

新类:创建类头文件(仅定义)→ 使用脚本生成单元测试模板 → 实现测试 → 聚合为测试套件 → 聚合到测试运行器

已有类:可采用增量方法(按需添加单元测试)或全量方法(一次性为所有函数生成单元测试)

运行时机(优先级排序): 1. 代码提交前必须运行全部测试套件 2. 集成到源码控制系统提交序列中 3. 集成到"消毒剂"脚本中 4. 回归前手动运行 5. 通过cron任务定期运行


第14页 — 2.5 示例

示例1:从零开始

创建packet.sv的类头文件后,运行:

# create_unit_test.pl packet.sv

生成packet_unit_test.sv,包含setup()run_test()teardown()任务以及test_calc_parity()test_calc_crc()任务。填充测试代码:

test_calc_parity();
   INFO("Running packet::calc_parity");
   FAIL_UNLESS(my_packet.calc_parity(8'h00) == 1'b0);
   FAIL_UNLESS(my_packet.calc_parity(8'hff) == 1'b0);
   FAIL_UNLESS(my_packet.calc_parity(8'ha8) == 1'b0);
endtask

创建测试套件:# create_testsuite.pl –out packet_testsuite.sv

创建测试运行器:# create_testrunner.pl –out testrunner.sv -r

编译运行:

# vcs +incdir+../svunit_base+../env/utils+../env/atm \
      –sverilog –ntb_opts dtm \
      ../svunit_base/svunit_pkg \
      ../env/atm/atm_pkg.sv \
      ../env/packet/packet_pkg.sv \
      ../env/testrunner_pkg.sv \
      ../env/svunit_top.sv

示例2:已有环境

# create_svunit.pl –r –i

脚本以交互方式遍历所有目录,找到SystemVerilog文件,为每个类创建单元测试,按子目录分组测试套件,最后汇总到testrunner.sv中。


第20页 — 2.6 局限性

单元测试的有效性取决于编写方式。建议投入时间规划单元测试——理解函数接口、使用方式和最佳测试方法。可以引入随机化以增加测试有效性。

2.7 案例研究

作者尚未在验证环境开发中使用此框架,正在内部研发项目中探索采纳方式。期待随着验证工程师对敏捷方法论的认知增加,验证框架有效性的案例研究将浮现。


第21页 — 3. 结论

随着DUT复杂性的增加,验证环境中每个组件的质量必须极高。十多年前,软件开发经历了类似功能验证工程师近年来所经历的演变。作为回应,软件社区开发了敏捷方法 Agile Methodology

随着功能验证团队规模的增长,确保子团队之间交付的组件坚如磐石至关重要。本文中概述的TDD 测试驱动开发技术提供了一个框架,可为系统中的每个关键类轻松创建单元测试。我们为SystemVerilog语言开发了这样的框架,允许用户快速创建单元测试的支架,将多个单元测试聚合为测试套件,并使用测试运行器执行单元测试并报告通过/失败。

在SystemVerilog中引入TDD提供了一种技术,通过在初始实现之前强制执行某些分析来有效提高代码质量,并确保每个组件在变更时按预期工作。

参考文献

[1] http://en.wikipedia.org/wiki/Agile_programming
[2] http://en.wikipedia.org/wiki/Unit_test
[3] http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks
[4] http://www.junit.org/
[5] http://sourceforge.net/projects/cppunit/
[6] http://pyunit.sourceforge.net/
[7] http://www.naturaldocs.org/
[8] http://www.vmmcentral.org/
[9] http://www.ovmworld.org/


图片索引

本文共 6 张图片(图1-6),展示svunit类图和脚本输出示例。