svunit:将敏捷方法引入功能验证
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类图和脚本输出示例。