一、概述
1.1 验证的目的和方法
验证的目的
- 原始描述是否正确?(代码)
- 逻辑功能是否正确?(功能)
- 时序及其相关性能指标是否正确?(时序、速度、噪声)
- 是否完全符合物理设计规则?(工艺)
- 功耗、可测性、可靠性、可制造性是否满足要求?(其他)
验证的方法
- 软件验证:也叫软件模拟(simulation),基于EDA工具,易行,有效性取决于EDA工具和设计师的经验
- 硬件验证:也叫硬件仿真(emulation),基于FPGA或其他硬件仿真器,速度比软件仿真快,有效性介于软件验证和流片验证之间
- 流片验证:基于样片及测试,最真实,代价高昂
1.2 验证的要求
- 不同的设计层次或设计阶段,采用不同的仿真验证工具(管、门、RTL、逻辑、系统,数字、模拟、混合,时序、逻辑、功耗等)
- 所有功能与性能指标都要通过仿真验证
- 仿真验证必须考虑最差情况(Worst、Typical、Best)
- 验证必须考虑仿真精度与计算效率的折衷
1.3 验证的分类
- 功能验证(动态验证或功能仿真)
- 方法:施加外部输入激励到所设计的电路模型,判断它所产生的输出响应是否符合预期功能,主要用于验证电路功能
- 特点:最接近电路实际工作场景,但难以找到完全的激励来覆盖电路的所有功能,而且耗费时间,对于规模大的电路尤其如此
- 类型:电路仿真,逻辑仿真
- 时序验证(静态验证)
- 方法:分析电路所有路径的时序,或者将待验证的电路与参考电路进行对照比较,主要用于验证电路性能指标,限于数字逻辑电路
- 特点:无需输入激励信号,速度快,但无法验证电路功能,准确性较低
- 类型:静态时序分析,形式验证(等效性检查)
- 物理验证
- 方法:检查版图是否符合预定的设计规则,是否与电路一致
- 特点:同时需要版图和电路数据,物理设计完成后进行
- 类型:DRC,ERC,LVS
1.4 FPGA设计验证流程
二、动态仿真
2.1 动态仿真流程
在进行动态仿真时,我们需要像仿真工具输入激励描述和电路描述,并给出相应的控制命令。其中,激励描述指的是根据电路功能要求设计尽可能全面或有充分代表性的激励信号,电路描述指的是将用户对电路的描述转换成EDA工具可识别的形式(如逻辑表达式、网表、等效电路)。控制命令表示设置初始值、仿真时间、过程控制、中断、观察仿真状态等。
2.2 电路仿真与逻辑仿真
2.2.1 电路仿真
电路级仿真(多用于模拟电路)
- 用于仿真晶体管级的电路,精确性高,功能全面
- SPICE:电路模拟的事实标准,已衍生出Spectre、HSPICE、PSPICE、OrCAD、Workbench等多种版本
- NanoSim:Synopsys公司开发,可用于几百万门、0.13μm以下节点、模拟/数字/混合信号电路设计验证
这里我们选取一种有代表性的电路仿真进行介绍:SPICE仿真。
2.2.2 逻辑仿真
逻辑级仿真(只用于数字电路)
- 行为级仿真:验证模型、算法和行为等抽象程度较高的内容,一般不考虑具体的实现方式,仿真语言可以是HDL或C等高级语言,仿真环境可以使用MATLAB、SPW、COSSAP等
- RTL级仿真:验证RTL级代码,一般不考虑实际器件的延时,用HDL编写仿真激励,仿真工具有Synopsys的VSS、Cadence的NC-Sim等
- 门级仿真:pre-layout前仿真经过综合的门级网表,post-layout后仿真布局布线后的网表,都需使用器件与互连的延时信息(包含在SDF文件中)
同样,我们选取一个有代表性的例子:四位数值比较器
2.3 基于事件&基于周期的仿真
基于事件的仿真(Event-based simulation)
- 输入状态一旦发生变化(事件发生)就会计算得到输出响应,看是否满足要求
- 既能验证逻辑,也能验证时序
- 既可用于同步系统,也可用于异步系统
- 电路规模和输入向量复杂(可仿4~28种输入状态)时,仿真时间很长
- 适合对功能块和关键局部进行仿真,目前多数动态仿真工具基于这种方法
基于周期的仿真(Cycle-based simulation)
- 每个时钟周期结束时计算电路的输入-输出稳态响应,看是否满足要求
- 只能验证逻辑,不能验证时序,故必须与静态验证工具配合应用
- 只能验证同步系统,不能验证异步系统
- 仿真速度远高于基于事件的仿真(快10~100倍)
- 适合对超大规模复杂数字电路(如微处理器、浮点处理器、系统芯片等)进行仿真,以及作了少量修改后的验证
2.4 激励生成&响应分析
如何生成激励?
- 编制测试向量:对大规模芯片而言编制工作量巨大,要穷尽所有情况的话仿真时间很长(16位以上的微处理器已不可能实现穷尽测试)。测试向量可采用HDL、波形、事务和设计约束等方法建立。
- 随机测试或最坏情况测试:若设计规模过大使得激励无法覆盖所有的边界条件,可采用随机化的激励数据来验证,可在有限的时间和人力条件下覆盖到更多的边界条件。也可采用最坏情况下的测试,但会增大设计难度和实现成本。
- 借鉴已有数据:借鉴类似芯片的测试向量,如1GHz主频CPU的验证可借鉴500MHz主频CPU的历史数据。
如何分析响应?
- 肉眼观察(Eyeballing):靠人工判断验证结果的准确性,对大规模芯片而言工作量巨大,待观测信号数较多时难以分析它们之间的交互过程。
- 与基准(Golden)文件比较:必须有基准文件,可以是前次仿真的结果,也可以是不同抽象层次(行为级、RTL级、门级)的仿真结果。
- 协议检查(Protocol monitors):对必须满足标准协议的接口(如PCI、AMBA总线接口等)进行协议符合性测试,协议常需使用抽象程度更高的验证语言来表征。
2.5 基于事务与基于断言
事务(Transaction):也称交易,是针对设计对象所作的一次数据或控制的传输,例如对存储器的一次读取或者改写,不同单元之间通过总线进行的一次报文数据发送。
基于事务的验证(Transaction-based Verification):将复杂的激励单元或向量组合抽象成事务模型(也叫事务器(transactor)或事务验证模块),如将对存储器或总线的读/写操作转换为寻址和数据信号。事务模型可以用抽象程度更高的硬件验证语言(如行为级HDL、C++、System C)来编写,从而大大提高了激励产生以及整个验证的效率。
- 可插入电路内部的任何关键点,需要内部结构信息(属于白盒验证)。
- 插入断言不应影响设计结构与行为。在RTL代码中插入断言不应影响综合结果,可将插入断言看成是综合的注释。
- 与需全芯片、全时测试的动态仿真相比,断言验证显著提高了可观察性和验证效率,缩短了验证时间。
2.6 如何评估仿真验证质量
- 代码覆盖率(Code Coverage):验证过程中执行过的代码在所有代码中占有的比例。100%的代码覆盖率只代表每一行代码都在仿真中执行过,并不意味着功能没有错误代码覆盖率的范围:RTL编码的模块、路径、语句、条件分支、条件表达式的覆盖率,寄存器的触发覆盖率,每位信号的翻转覆盖率,状态机的状态受访、状态跳变、状态互访的覆盖率等。
- 功能覆盖率(Functional Coverage):仿真测试到的功能在设计实现所有功能中所占的比例。100%的功能覆盖率只能确保对设计者事先列出的所有功能(可能有缺项)都进行了验证。
- 插入缺陷覆盖率(Fault Insertion Coverage):有意识地在设计中插入缺项(Bug),然后检查该Bug是否能在验证过程中检测到,从而可有效地衡量测试用例的质量。显然,我们不可能在设计中插入所有可能发生的Bug,而只能随机地插入有限个Bug。
三、小结
在现代集成电路设计中,验证所占工作量超过70%。验证要求真实而完备,它决定了设计的成败与成本。本文主要介绍了什么是验证,为什么我们需要验证,芯片验证大体上可以分成动态验证、静态验证和物理验证,本文又着重介绍了动态验证的内容。