前言
芯片验证是为了发现芯片中的错误而执行的过程,它是一个破坏性的过程。完备的验证激励可以更有效地发现芯片错误,进而缩短验证周期。合格的验证激励必须能产生所有可能的验证场景(完备性),包括合法和非法的场景,并保持最大的可扩展性和可控性。
激励构造一直都是芯片验证的一大难点。本文将从完备性、可拓展性和可控性三方面展开阐述如何系统地思考和构建验证激励。
-
完备性
完备性可以从接口类型、内部结构和激励审查三方面分析。分析接口类型是为了从待测模块与其它模块的交互信号上提取出验证场景。分析内部结构是为了从待测模块内部实现细节上来调整激励,使激励多产生可能发现错误的场景。激励审查用于查缺补漏,从自己、他人以及项目等各个环节上对激励进行完善。
-
-
接口类型
-
对于待测设计的输入输出接口,可以通过接口类型进行划分,根据接口类型的特性构造对应的验证组件来产生激励。常见接口类型有:
- 系统控制接口:主要是时钟、复位、电源开关、时钟门控、时钟分频等,这类信号行为都会有详细的规定,遵循实际集成关系做控制即可。例如:时钟和复位的时序,多个时钟是不是同步关系,多个复位信号是否可以单独控制等。
- 标准总线接口:行业公开的标准总线协议,例如AMBA系列协议。这类协议通常有现成的验证IP,只需配置它们来产生预期的场景。
- 非标准总线接口:公司内部定义的接口,或者根据模块功能需求定义的接口。这类接口需要从相邻设计了解各信号的准确信息。
- 其它接口:DFT等。通常来说,这类接口与验证关系不是很大,只需要把它们接固定值即可。
在对接口类型进行分析要产生的激励时,可以先从单一接口类型进行分析,然后再看多个接口交互上有什么需要重点关注。关于如何进行测试点分解,可以看这个系列视频《芯片验证分享系列总结及PPT分享》。
-
-
-
单一接口类型
-
-
单一接口类型分析可以按基本颗粒、高级颗粒和非法行为顺序进行。
- 基本颗粒:基本颗粒面向信号层,提供基本颗粒生成方法。
- 每根信号:信号来源和功能、使能极性、脉冲有效或电平有效、时序、信号的取值范围和格式等。
- 信号之间:不同信号之间的关系,是否存在握手和时序关系,无关信号是否处理成随机值还是固定值等。
- 高级颗粒:高级颗粒面向场景层,它封装了多个基本颗粒,较少考虑底层信号。
- 序列:传输包的序列有哪些。
- 密度:传输包的密度分布有哪些。
- 非法行为:用于验证待测设计的鲁棒性,出现非法行为,待测设计是否可以正常处理。
- 数值:信号值可能出现哪些非预期的值。
- 行为:信号时序、协议等行为可能出现哪些异常行为。
-
-
-
多个接口交互
-
-
对于具有多个接口的待测设计,我们也需要考虑接口之间可能存在的交互或同步,以及接口之间是否使用共同资源。比如,为了测试两个接口相同地址hazard,可以让这两个接口共享一个地址产生器。
不同接口对应不同的验证组件,组件之间的协调有用多种方式:
- 中心统筹式:通过集中式控制、分配和协调,在上层将任务分解成每个接口组件的任务,并统一分派给各个接口组件去执行,进而产生不同的激励组合场景。比如UVM中的virtual sequence角色。
- 分布事件驱动式:每个接口组件有自己的控制权,各个组件直接进行交互。比如使用SystemVerilog中的event、mailbox、semaphore和全部变量等方式实现通信交互。
- 混合式:上述两种方式并存。这需要根据具体场景来使用。
-
-
内部结构
-
激励设计除了看接口信号外,还需要结合待测设计的内部结构和功能去分析,调整激励约束,从而有更大的概率产生有效场景。
可以沿着控制流(control flow)方向去分析待测设计的内部结构和功能,具体以下几个地方需要重点关注:
- 触发功能点:触发内部某个功能的激励序列有哪些,比如Prefetch、flow-control、address hazard等。触发内部某个功能的敏感值有哪些,比如ALU、内部错误(cache ecc error, slave error, etc)、barrier、exclusive monitor、address hazard等。
- 触发资源瓶颈和争抢:如何触发内部资源瓶颈和争抢。比如FIFO空满、Buffer空满、多请求源仲裁、数字运算上下溢等。
-
-
激励审查
-
审查(Review)环节对完善激励起着至关重要的作用,可以提高激励质量,并减少漏验特性、无效激励的概率,对个人成长也有很大帮助。
建议以下这些审查方式都要进行:
- 个人审查:由自己进行,对照历史错误清单进行,举一反三,避免犯类似错误。
- 同组审查:由组内更有经验的人进行,对激励完备性、设计结构、假设、代码实现进行检查。
- 跨组审查:由待测模块的设计人员进行,对激励完备性、设计顾虑、易错特性、局限性和各种激励假设进行检查。
-
可扩展性
可扩展性也包括可复用性。为了处理验证周期缩短、待测RTL规格频繁变动等各种情况,我们需要在设计激励时提前构思如何让激励更容易扩展。基于此,我们可以从模块化和层次化方面去思考。
-
-
模块化
-
模块化需要将设计输入输出信号划分为不同的接口类型,并创建出对应的接口验证组件,确保各个组件之间的独立性,各个组件才会最大程度地不受其它组件的制约。并定义好模块之间的交互方式,这样一个模块的改动对其它模块的影响就很小,而且模块也更容易的复用到其它地方。例如,如果有两组相同接口,则应该引入两个组件分别控制,而非建立一个组件却拥有两套接口,这样后期维护起来会很麻烦的。
另外把常见的功能封装成公共库,这样在多个地方都可以直接使用,如果功能需要改动,只需要改动一处代码即可。在写代码时,多留一些后门(callback),方便实现多样化的激励和后期增加新功能。
-
-
层次化
-
层次化需要将激励抽象出各个层次,越高的抽象层次越不关注底层的时序,而是更重视验证场景构造。这样底层信号时序或功能的改动也不容易影响到上层的激励,而且上层的激励说不定也可以复用到其它地方。
以UVM为例,uvm_driver应只关心接口驱动,负责把收到的uvm_sequence_item内容直接驱动到接口信号;uvm_sequence负责场景的构造,当然uvm_sequence也可以继续分层,更上层的uvm_sequence产生更宏观的验证场景,然后逐层分解成小的场景。
-
可控性
可控性用于表征是否容易控制激励产生预期的验证场景。比如验证ECC模块功能时,在最开始时,我们需要不注入任何ECC错误的激励,侧重于验证ECC模块功能是否正常。随后才会打开ECC注错激励,验证ECC模块是否可以检查出来。这需要提供一些方式可以控制是否打开ECC注错激励。基于此,我们可以从局部和全局方面去思考。
-
-
局部
-
可控性局部的意思是验证激励可以单独控制局部激励的行为,通常来说面向单个接口验证组件。这层控制的特点是偏向于接口,可以细致到控制接口每根信号的行为。
比如,待测对象有两个ECC模块,我们可以控制其中一个有ECC注错,另一个没有。
-
-
全局
-
可控性全局的意思是验证激励可以一同控制所有激励的行为,通常来说面向一个验证环境中的所有接口验证组件。这层控制的特点是偏向于特性,是把所有局部控制参数整合起来,提供和验证特性相关的控制参数。
比如,待测对象有两个ECC模块,我们可以同时控制两个都有ECC注错,或都没有等。又或者待测对象的某个特性还未开发完成,我们可以控制不让所有激励发出与未完成特性相关的场景。
总结
综上所述,激励设计可以按照“完备性->可拓展性->可控性”方向去分析。在完备性中,可以按照“接口类型->内部结构->激励审查”方向去分析。在可拓展性中,可以按照“模块化->层次化”方向去分析。在可控性中,可以按照“局部->全局”方向去分析。
另外很重要的一点是:要经常对验证结果进行复盘分析,并优化激励。
总得思维导图如下: