电子说
Testbench是几乎所有做动态仿真验证的工程师都要面对的问题,可能是需要设计,或者开发,又或者是维护,总有很多事情要在这上面折腾。Testbench可以很简单,也可以很复杂。
在面对具体的验证对象的时候,如何利用我们手头的工具,比如SV/UVM/Python等,去搭建一个简洁高效的、可维护性和可重用性强的testbench,是一个非常重要且值得讨论的问题,甚至不同的工程师就能总结出自己的一套经验法则。
本文将从架构(Architecture)、实现(Implementation)、维护(Maintenance)这三个方面着手,讨论设计和构建testbench通常需要考虑的问题,不涉及编程实操,不涉及验证计划。
01 Architecture
Testbench架构定义很大程度影响着仿真程序的执行效率。这里的讨论将分三个小点展开:验证环境本身结构,层次化测试激励,以及配置信息的传播。
最简单的验证环境,或者说验证环境的一般雏形,包括driver、monitor、sequencer、model、checker、scoreboard等这么一些组件,连接关系也很简单。然而在实际工程项目中,特别是到了系统集成级,由于验证对象很庞大,验证环境的组件数量往往成倍数增加,连接关系和控制关系也会变得更加复杂。
层次化的测试激励来源于我们对测试场景的定义和对激励控制的需求。一般来说,测试场景定义得越抽象,测试激励的层次就会相应地增加,对测试激励的控制也会更加复杂。举个例子,假设我们想要测试CHI NoC中HN对某一种transaction的响应行为,那么只需要启动让RN agent直接发出transaction的sequence即可;某天我们想要测试HN处理不同hazard(多笔请求产生冲突)的行为,那么我们可以通过封装多个base sequence来实现该目的。
配置信息的传播在testbench架构中很重要。配置信息一般包括对DUT参数或者宏定义的配置、验证环境组件的开关配置、测试激励权重的配置等等。配置信息使得当前验证环境可以被有效复用,可以覆盖到更多的测试场景。通常我们可以通过分享config对象句柄的方式来传递配置信息。
02 Implementation
在实现上要考虑的问题会比较杂,这里举几个常见的主题:数据结构的定义,建模和检查方式,覆盖率收集,以及仿真的启动和结束。
数据结构的定义应当完整,并提供足够的方法使其能够被高效操作。数据结构容易直接想到的就是sequence_item的定义,决定了数据在testbench各组件中游走的包格式。除此之外,需要定义config对象的数据结构,自定义的建模方式可能需要一种新的数据类型等等。
建模和检查方式强依赖于验证计划。大白话是,确定需要覆盖的测试点和覆盖方法,对此再分门别类定义checker,根据checker所需要的信息定义建模方式。这里的建模指的是在testbench中实现DUT中某个模块的功能,或者记录DUT状态信息,使得检查测试结果时有理有据。
覆盖率是芯片项目验收的关键技术指标,收集覆盖率就变成testbench必要的功能。定义覆盖点的位置以及收集覆盖率的方式都比较灵活,如果没有统一规划和管理,容易让同一个testbench中收集覆盖率变得分散而不好管理。
仿真的启动和结束主要为了实现这两部分功能:测试用例开始前的初始化和仿真结束时的状态检查。仿真验证不代表一上来就给验证对象灌激励,除了要处理好复位、上电流程之外,通常还要其他初始化工作,比如将某些接口tie成固定值、初始化控制寄存器的值、加载memory的内容等等。仿真结束时,除了要确保DUT已经完成对测试激励的完整响应,还需要检查DUT以及testbench自身的一些状态是否符合预期。
03 Maintenance
在项目迭代中通常会复用到前项目的验证环境,这就导致testbench的维护工作需要做得比较长远,否则容易积重难返,最后谁也不敢做出更新或者改进。Testbench的维护有这么几个重要的主题:验证环境的集成,工程目录结构,各类脚本管理,以及相关文档的整理。
验证环境的集成指的是将底层验证环境的向上复用,这种操作在实际项目中非常常见,也是提高验证效率和节约人力的好方法。当testbench需要被集成复用,需要提前沟通好双方的需求和配置方式。
工程目录结构一般要遵守项目管理的统一安排,使得环境在需要维护时检索效率比较高。否则,当验证环境变得非常庞大之后,在一个结构混乱的工程目录中找文件会非常麻烦,所以不要随意存放文件。
环境脚本虽然不作为testbench本身的一部分,却是维护验证环境的必要工具。这里的脚本主要的工作有文本处理、自动化生成文件、提交仿真任务等内容,当需求发生变化,相应的脚本也就需要更新和维护。
审核编辑:刘清
全部0条评论
快来发表一下你的评论吧 !