一:概述
都说EDA工具很难(芯片设计不可缺少的工具),目前我国正在举国之力来发展它(因为之前我国一直没在这个领域做基础研究,一直是使用者,所以,被美国拉开了很大的差距)。那它到底难在哪里?大家经常能看到的和理解的是芯片的工艺很难,大规模的集成电路很难,实际上,芯片最终要使用,是需要EDA工具来辅助的,大规模集成电路的设计,不可能是手工绘制电路,包括一些测试工作,也依赖于EDA工具。
对于一款手机,我们验证它的好坏,首先是它的CPU,GPU,无非是跑分,拆机,测试。我们要探寻EDA软件的难点,自然也可以通过它的测试过程来一探究竟。并且,作为一个曾经的外行,通过测试来了解一款产品,是最佳路径。今天,我们尝试从测试的角度,来看看一款EDA软件到底是如何组成的。
对于一款FPGA的EDA工具,它的核心功能是辅助完成 电路编程,编译,优化,映射,布局,布线,生成位流,烧录到芯片,在线调试,最终得到用户需要的电路设计。
要测试一款EDA工具,和传统软件的测试有所不同,一般包括三个方面:
- 普通的软件测试: 面向软件的功能,这和普通电脑软件测试基本一致。
- 位流验证:这个对于普通软件,基本上是不存在的。它实际上验证芯片的硬件设计是否合理,我们理解就是芯片的各个组件需要有预期的功能,可以在没有得到实际芯片前,通过位流的方式来验证。我们不可能在芯片完全生产后,才来测试所有的功能。
- 上板测试:芯片样片或批量片存在的情况下,实际放到demo板,对软件进行测试。
对于软件本身的测试包括,单元测试,集成测试。按测试的点不同,又分为 GUI测试,功能测试,性能测试,压力测试,这些和普通软件相同,但对于EDA还多了一个形式化验证,后面我们再详细解释它的作用和必要性。
对于位流验证,实际上就是仿真验证,它不依赖硬件,采用仿真工具来验证硬件的基础设计的准确性。仿真非常重要,对于硬件产品它是必须的,因为不可能实际使用硬件来完成大规模的测试。
最后就是上板测试了,我们需要实际的下载器,Demo板,芯片,完成真实的应用场景的测试。它作为软件发布的最后一道防线。
接下来,我们就围绕这三方面的测试来展开详细讲解。
二:软件测试
2.1 单元测试(白盒冒烟)
单元测试,大家都知道是什么,也就是白盒测试。这主要是通过编程对模块级的代码进行测试。在EDA工具厂家,大多是由开发人员自行完成。因为涉及复杂的算法,性能,这些工作,合适由开发人员在开发过程中完成。这不是今天要讲的重点,略过不谈了。单元测试非常重要,需要有良好习惯和较强能力的人来把控哪些地方需要单元测试。这是代码的第一关。
EDA工具,我们按模块,一般会分为 架构,建模,综合,布局,布线,时序,功耗,位流,下载,GUI等……。这些模块首先会在各自的领域和内部完成自有的模块测试。一般会有一个集成模块(通过是GUI)进行一些集成单元测试(主要针对flow进行完整的测试)。
单元测试采用的框架,因为EDA软件大多采用C++编写,所以,一般会使用GoogleTest,这个不用多说。
对于冒烟测试的时机,我们希望是相关模块在提交代码前完成自测。但是,这不一定能得到保证。为了整体的工程质量有一定保证。我们会选择一些关键的主流程的单元测试用例,在提交代码的门禁处,做一个整体的冒烟。如果有问题,不允许代码提交。注意:这是针对所有代码提交都要冒烟。当然,我们也欢迎各模块将合理的自测加入门禁,可以不断补充本模块需要冒烟的用例,这样,在指定模块进行提交时,我们会进行指定模块的冒烟用例的检查。
以上的测试,并不是EDA软件的特有的,所有软件都通用。
2.2 GUI测试
对于GUI测试,我们必须要单独拿出来说,因为它相对比较简单,但又有一定的特殊性。
我们先来看看GUI测试一般会涉及到哪些功能
- IDE——整个IDE的界面。这里主要关注编程界面,各种输出视图。一般我们会采用 checksum方式,通过比较图像来查看是否有异常。也就是采用 自动化测试,工具有很多,比如 QT的自动化测试工具。当然,这需要软件相对稳定,并且需要人工录制脚本。
- Flow——指整个EDA的关键Flow的验证。从综合,优化,映射,布局,布线,时序报告,生成位流的整个过程。
- Project Manager——工程管理,这是非常重要的功能。这包括了和工程管理相关的一些高级功能,比如 Hierachy parser,property order,grouping support……这可能更多需要手工测试,当然,也可以录制一些脚本来自动化的完成。
- Time constraint——对于时序约束生成和报告的验证。
- Pythsical constraint——对于各种物理约束的设置和验证,比如:fence, io package等的使用和验证。
- Configuation —— 就是烧录的过程,这里主要是需要对加密,RSA,CRC算法等进行必要的测试。
- Debug——这个主要是要对 探针,在线分析工具等调试工具进行测试和验证,这要看EDA工具具体提供了哪些debug工具,这个也非常关键,因为客户是必须要使用的。
- Simulation——如果EDA自带仿真工具,需要对仿真功能进行完成测试,如果只是集成三方工具,那就对集成部分进行测试。
- Chip 查看工具——这里一般指的是chip view,floorplan 工具,这个很难自动化测试,一般需要手工进行验证,因为相应的设计和效果与器件强相关,当然,也可以针对每种器件做一些checksum的校验。
- IP Catelog —— 这里主要针对 IP的 导入,参数定义,生成过程进行测试验证。这个很容易做成自动化测试,来保证生成过程和相关界面的正确性。
- 电路图显示——这个一般有几种视图,一种是原始RTL的原理图,一种是综合没有map的原理图,还有就是map后的原理图。原理图一般是只支持查看的,还有一些场景还支持修改,那就更加复杂。
- 安装包——对于最终的安装包,也需要进行不同环境的测试,看是否预期的步骤和效果。
- License——一般EDA工具会提供License控制,会有单机版和浮动版之分,并且会控制有效期,并发数量。这些需要进行相应的测试和验证。
- 消息,日志——不同情况下的不同类型的消息输出,以及不同级别的日志输出。
这里肯定没有列全,但比较核心的功能就是这些了,每款EDA工具必然有自已特有的功能,上述是比较常见的功能。
对于GUI测试,我们必须要做到自动化,自动化工具。有很多标准工具可以用,比如:QT的自动化工具(这个比较贵Squish),也可以采用国内的产品,比如:CukeTest。
EDA工具一般是桌面程序,会在Windows,Linux上运行(一般不用去支持MacOS),也可能会跑在国产的操作系统上。所以,如果使用cuke test,在国内的某些操作系统(信创)的项目上,还会有一些优势。
当然,前提是软件的界面已经相对稳定,
- 我们可以录制脚本,添加检查点,断言,或者比较图像来完成测试。
- 对于经常可能位置有变更的程序,可以根据使用的语言进行元素获取,增强脚本的适应性。
- 提供机器人随机测试,这个需要抓取界面上的按纽什么的,模拟一些操作。随机测试程序的健状性。
GUI自动化,往往会做为交付客户版本前的版本出口测试。
注意:GUI 测试本来也包括外观设计的测试,但一般是在开发早期,由美工设计人员来完成。
2.3:Flow集成测试
集成测试,我们一般需要定义一个小小的框架,方便快速配置不同的EDA集成和功能测试。
2.3.1:测试框架
主要是将测试时用到的参数全部抽象出来,用shell脚本或者python来解析,完成测试的框架定义。通过这个测试框架,来进行不同的参数配置,通过输入不同的测试用例,形成不同的功能测试。
下面,看看需要建立如何的参数:
1:测试运行的环境。这实际上在其它几种测试下也得提供,因为测试是非常耗资源的,一般不可能在单机上运行,一般会使用公司的集群资源,但为了协调资源,一般会做一些资源配置。
一般我们推荐在使用HPC时,采用 LSF 的 bsub来运行测试,所以,最好是将运行指令进行封装,由大家统一调用,也方便统一分配资源。
如果HPC的queue是公用的,可能还需要指定一下,目前使用哪个 queue。指定一下使用的资源细节,比如:线程数,最大内存等……
2:需要有一个控制Flow的配置。我们一般需要提供几种标准的流程。
place_route_sdc:包括 布局+布线+约束部分
place_route_without_sdc:只处理布局+布线
place_route_pipeline:处理 布局+布线后面的所有流程。
可能还会有一些别的组合,可以视需要来提前配置和供选择。
可以按需求组合成多种流程,供测试各种场景调用。这种配置往往是为了简单流程,按最节省资源的流程来达成需要测试的效果(不要浪费不必要的时间和资源,高效完成测试)。
3:对于测试用例集需要进行管理,一般是设定一个测试集的目录,实际执行时循环执行。因为我们一般情况是批量测试。对于测试用例 ,一般会分为小,中,大规模的不同scale 的 case。
4:指定输出结果存放的目录,方便统一解析和查看。
5:注意可能还需要设置一些基础的环境变量,主要是EDA运行时所需,以及使用的EDA的不同版本。因为有时测试需要不同的EDA输出版本(比如:为内存检查所准备,为客户测试所准备)。对于运行环境的选择,实际上是CI/CD平台的某一个输出环境的选择。
6:运行的参数设置。EDA运行时,一般会有很多参数,为了设定不同的综合/实现的策略,在测试前需要严格指定。一般会提供一个基础的公共参数策略,然后在自行根据情况做调整。
7:芯片的选择,这个别忘了,不过,如果测试的框架是针对某款芯片的,就可以写死了。否则,必须指定好芯片的架构,系列。一般指的是一种特定的架构,可唯一标识的名称。
8:最后,为了保证不会死循环,还可以设定一下运行的超时时间,单一用例或者整体的时长。
其它,看看还有什么测试中可以抽象出来作为参数的,都可以加到框架中。
框架的执行很简单:
就是利用定义的lfow和参数,采用准备好的环境和资源,参数,循环执行指定好的示例,而对于示例的结果进行解析,输出,完成测试。不同的示例和参数形成不同的功能测试。具体什么功能,采用什么样的示例,采用什么样的参数和流程,下面会介绍一些典型的场景。
针对业务功能的测试,单元测试是站在技术维度,而业务功能测试,会站在客户的角度。
2.3.2:基础功能测试
选取一些例子,进行一些分类,进行特定的测试,如下:
集成示例的分类:
- 应用测试(Application Test):验证工具在特定应用场景下的表现。
- 规模测试(Scale Test):验证工具在大规模设计中的处理能力。
- 特性测试(Feature Test):验证工具的各个特性和功能模块。
- 最大时钟频率测试(Fmax Test):测试设计可达到的最高时钟频率。
- 多时钟测试(MultClk Test):验证多时钟域设计的稳定性。
- 宏单元测试(Macro Test):验证FPGA中的宏单元或IP核的正确性。
- 验证测试(Validation Test):验证设计是否符合需求和规格。
- 连接测试(Connection Test):检查设计中各模块之间的连接是否正确。
- 功能测试(Function Test):确保设计的功能符合预期。
集成测试的结果如下:
1:flow过程是否成功
Synthesis ,Map,Place,Route,Sta,Bitgen,整体流程 P/F
2:器件使用率(这个和芯片的架构有关,看使用到哪些器件)
Luts ,FF,IO,Carrys,DSP,BRAM,EMRAM,BUFG 等……
3:重要技术指标
SysPeakMemory:峰值内存占用。可以判断是否合理。
PeakMemory:可以计算某个step的内存占用。
cpuRuntime:cpu消耗的时间
wallRuntime:cpu + i/o 的时间
sysRuntime:cpu + i/o + 其它操作 的总时间。
gpWL:Global Place & Route Wire Length,全局布局 使用的线长,越短说明越优化。
dpWL:Detail Place & Route Wire Length,局部布局 使用的线长。
dpWins:Detail Place & Route Wins,布线中成功的次数。
node_Init:节点初始化规模
congested_init:初始拥塞的情况
node_final:最终模块连接的节点数。
congested_final:最终拥塞的区块个数。
numIters:迭代次数。
routeWL:布线总长度。
NumWiresUsed:使用信号线数量。
WNS: worst negative slack,最严重的时序负值。
TNS: total negative slack,总的负值和。
WHS:worst hold slack,hold 时序的最差值。
THS: total hold slack 总的hold slack 总值。
Fmax_geomean: 几何最大时钟频率
Fmax_wgeomean:加权的几何最大时钟频率,对于路径加权(重要程度)
FmaxRatiocaps_geomean: 表示设计的几何平均Fmax比率(与时钟约束的比率),用于衡量设计在特定时钟约束下能达到的最大频率与理论最大频率的比值。
FmaxRatioCaps_wgeomean:表示设计的加权几何平均Fmax比率,与设计的时钟约束进行对比,考虑权重影响,衡量设计在多个时钟域下的频率表现。
minFmax: 表示设计中最小的最大时钟频率。这通常用于衡量设计中时序性能最差的路径,表示该路径能承受的最大时钟频率。
minFmaxRatioCaps:表示设计中最小的Fmax比率,即设计中最差时钟路径的最大时钟频率与约束的比率。
max_logic_level: 表示设计中最深的逻辑层级,即信号通过多个逻辑单元的最长路径。较高的逻辑层级意味着信号传播的延迟较大,可能影响时序。
logic_level_wmean:表示设计中加权平均的逻辑层级,即根据各个路径的长度和复杂度计算出的加权平均值。它反映了设计的整体逻辑复杂性。
2.3.3:DRC测试
为什么功能测试之后,我们马上要提DRC测试?
DRC 不仅仅指物理/时序约束,它的的测试范围更广,覆盖了物理规则、时序规则以及架构规则等方面,不完全依赖物理和时序约束,但会结合它们来进行更具体的检查。
- Blackbox 检查,查看有没有不被当前Device支持的Inst,是否正常可用的Primitve。
-
BRAM(FIFO) cascade in相关port没有连接vcc(1)。
-
SFTR32的Q31端口是否与一个SFTR16连接。
-
BUFG或BUFGCE的I端口不能没有驱动,O端口不能不连接net
-
net不能存在多个驱动
-
基于part信息检测资源使用是否超出限制
-
检测当前的top module是否为空(没有inst,没有net),如果为空则不合法
-
检查对于PLL的必要配置信息(PLL上DI端口的每一bit都需要有驱动)
-
ISERDES/OSERDES前的IOB不应该被约束到UIO Site上
-
约束到同一个fence的instances占用的SLAB类资源总和不超过在floorplan上该fence指定区域所包含的资源
-
作用在同一个IO的多个set_port -packagePin不能在位置上产生冲突
-
检查FF的control信号是否悬空
-
XGT:XGT从SRAM加载时,检查XGT bin文件是否存在
DDR:检查DDR bin文件是否存在
BRAM:BRAM INIT使能,且从文件读取时,检查文件是否存在
-
是否达成约定的时钟频率,添加时序约束
类似的DRC规则还有很多,具体要看你的芯片的架构定义。
测试方法:DRC都是可以做成自动化的回归测试,不断补充用例。
2.3.4:PhyConstr物理约束
测试physical constraint的功能正确性,需要使用 tcl 来编写各种物理约束,然后对示例进行执行后,查看相应的约束是否生效。
典型的例子:
-
lock_inst -site
lock_inst -site -elem
-
lock_pin
-
set_port -packagePin
-
package pin禁用测试
-
package pin&IOstd测试
上述命令的正常运行,异常执行,组合执行的用例,具体就不细述了。总之,一方面要验证命令本身执行不出错,然后还要验证达到了约束的实际效果。这些都是可以自动化测试的。
2.3.5:fence 测试
fence测试实际上也是physical constraint,只是它针对的场景不同,一般是对内部逻辑单元的使用进行设计,它是为了干预实现,节约资源,优化布线的一种手段。
常见的用例有:
- fence 约束的语法验证,
- fence 之间有无冲突,重叠
- 一个inst被绑定到多个fence
- 通配符,正则式绑定inst
- 各种不同inst的测试
- lock 和 fence 同时使用的问题
- ……
情况太多,这里不再一一罗列,原则是尽可能覆盖所有场景,由于很多操作是需要基于GUI的,所以,有些用例可能不适合自动化,需要手工配合。
2.3.5:Timing constraint 测试
对于时序约束的功能正确性进行测试
典型的用例包括:
- create_clock
- set_input_delay
- set_output_delay
- create_generated_clock
- set_clock_groups
- set_false_path
- set_multicycle_path
- set_min_delay
- set_max_delay
- report_timing
- ……
主要针对这些指令的不同参数和场景进行用例设计。通过report输出,验证功能是否正确。
大部分用例是可以自动化回归的,对于复杂路径,性能相关,异步处理时,可能需要人工辅助回归测试。
2.3.6:tcl 命令测试
我们会用tcl定义很多EDA工具的命令,这些命令被大量使用,必须要优先进行测试。
tcl命令大致会分为如下几类:
- Design 相关——create,save,close design,set param,get_xx_place,get_xx_route,save_io_assignment,write_netlist……
- RTL 相关 —— read_postsyn_netlist,read_postmap_netlist,……
- Netlist 相关 —— get_ports,get_pins,get_cells,get_clocks,……
- Flow相关——xxx_Synth,xxx_map,xxx_opt,xxx_place,xxx_route,xxx_bitstream,xxx_extmem,……
这些都是完全可以自动化的。
2.3.7:consistency一致性测试
程序运行的一致性是很重要的,否则,客户无法使用工具进行开发,你可以想象,同样的条件,每次输出的结果不一致,你如何保证你的设计正确可用,不可能每一次的修改都要全量回归。
一般采用三种方式来进行一致性测试
- checksum 测试——将flow的各阶段拆开,对于每一步的输出进行checksum,运行N次,比较每次运行结果是否一致。
- netlist 测试——将每个阶段的子文件取出进行比较,查看阶段子文件内容一致。
- dcp 测试——使用save_design -bin参数,生成二进制格式的和文本格式的文件,多次生成,比较是否正常和一致。
这些测试都是可以完全自动化执行的。
2.3.8:Synthesis Atribute 测试
在代码中,可以设置属性,影响综合的过程,这些属性对于编程非常重要,它往往是进行优化的关键,必须要保证执行正常。
这里举例一些比较重要属性。
- black_box:Synthesis工具将不编译或优化的模块。
- disable_fsm:禁用状态机,也就是不要对fsm进行优化。
-
max_fanout:设定fanout的限制
-
no_opt:阻止inst被优化或者更改
-
no_buff:阻止buffer的生成
属性很多,但都是可以自动化测试的,因为目标很明确,可以比较综合后的效果是否符合预期。
2.3.9:Device 测试
对芯片资源的能力进行测试(主要是Luts资源),IO Package约束的结果进行测试。
芯片资源能力,可以根据芯片已有的LUTS总数和预期使用的最大比率,设计用例,看是否可以达成。当然,也可以对不能达成的用例进行反向验证。
IO 测试时,可以通过正常配置查看效果,或者配置不正常,查看DRC是否拦截来验证。
这些基本都可以自动化测试完成。
2.3.10:Primitive Simulation 行为仿真
针对所有Primitive,做行为仿真,具体要看Primitive的功能,按它的功能进行用例设计和激励设计。这个一般是用手工来完成。需要查看波形,是否符合预期。
2.3.11:Verilog/VHDL/System Verilog 测试
一般包括两种测试:
- 语法测试——选择典型语法对应的示例进行测试,没啥可说的。
- VHDL 例化测试——一般会用VHDL来进行Primitive定义,可以对它进行例化,并综合,确保primitive_name、input、output name以及param可选项都正常运行,跑完综合,看有无错误。
2.3.12:Primitive 连接关系测试
我们上面只对Primitive本身进行了测试,但很多应用是多个Primitive配合才能运行的情况,而且连接有固定的方式。我们可以使用一些样例来测试,是否按预期进行了正常的连接。
这个相对复杂,可以逐渐追加用例,另外,在做整体功能测试时,实际上已经对此进行一些测试。
2.3.13:Timing 测试
通过模拟不同的时间约束条件来测试系统的性能和响应,使用的例子仍然可以使用flow的例子,但需要跟进timing相对的参数。
如下,给出一些标准的指标:
PathNum / Total PathNum Setup:
PathNum / Total PathNum Hold:
Runtime:
Setup Wns:
Setup TNS:
Hold Wns:
Hold TNS:
2.3.14:OOC模式测试
对于一些单独综合和联合综合的情况,需要做测试。
2.4 性能测试
FPGA本身的性能主要是关注PPA。这里并不对PPA进行深入的探究,只站到EDA软件的角度,探讨指标如何进行防止劣化,不关注实际的技术问题。防劣化的方法当然就只有是QoR了。
2.4.1:QoR测试
对于QoR分为自身的不同版本的指标比较(与历史版本),和同行产品指标的比较。对于国外产品,一般会选择vivado,国内产品更多会选择pango。
对于指标,包括主要step 的 cpu_runtime, wall_runtime, peak_memory。
step 包括:synthesis, map,place,route,sta,bitgen……
比较重要的指标:(上面其实已经讲过了,这里再强调一次)
Max_logic_Level | 设计中最长的逻辑级数(最长路径) | 定位最关键的逻辑路径 |
logic_level_wmean | 加权平均逻辑级数 | 衡量全局逻辑深度 |
fmax_geomean | 几何平均最大时钟频率 | 评估整体时钟频率性能 |
fmax_wgeomean | 加权几何平均最大时钟频率 | 强调关键时钟域性能 |
minFMax | 设计中最小的最大时钟频率 | 定位性能瓶颈,关键优化目标 |
FMaxRatioCap_ wgeomean | 加权几何平均的 Fmax 比率上限 | 衡量实际性能与目标性能的差距 |
meanFMaxRatioCap | Fmax 比率的算术平均值 | 快速评估设计整体性能 |
Runtime | 工具运行时间 | 衡量工具效率和设计复杂度 |
这些值肯定是不够的,但在产品初期,上述值是比较能代码基础质量的指标。
QoR代表了产品的成熟度,做得好的,会将QoR放到发版的质量评审流程中,一旦有质量劣化,将不允许发版。
2.4.2:内存测试
内存使用,对软件非常重要,不要存在不合理的内容申请和释放,非常重要。一般我们采取两种方法来进行测试:
-
Asan 测试:这是在程序编译时,添加特殊开关,以保证程序运行时,可以跟踪内存使用情况,随时监控内容的使用。
-
Vargrind 测试:这是使用工具来分析分存使用情况。
具体如何使用,只句话是讲不清楚的,这里就略过了。
2.4.3 压力/并发测试
EDA工具的使用,一般是针对单个设计进行处理,并不会存在大量的并发压力。如果存在并发使用,更多也是不同进程的使用。不过,如果单机有设计多个flow并行执行,那就需要测试一下并行的能力或逻辑正确性。一般来说,这不是重点,往往出现问题,更多是HPC时,I/O和网络出现问题。
2.5:IP测试
我们把IP单独拿出说,主要是指的随着EDA带出的标准IP,而不是用户设计的IP。标准IP又分为Macro IP 和 Soft IP,Macro IP又分为基础Primitive 封装 IP 和 三方组件的封装IP。
注意:用户自定义IP,不在这里考虑,会在功能测试中进行测试。
2.5.1:基础 Macro IP(简单)
包括:BRAM,EMRAM,PLL/CLK,FIFO,DSP,DLRAM 等……
因为Macro IP 是针对Primitive的简单封装,所以,不需要再对Primitive的内置功能进行测试,更多需要对封装的接口进行简单测试。
1:支持正常使用时的Flow运行。
2:支持RTL设计时的仿真。
3:支持综合后的网表仿真。
2.5.2:专项定制 Macro IP(复杂)
XGT,PCIe,UIO/SIO DDR 等复杂IP,这些 IP的验证就很难了,如果是自研的,那光是这些IP的测试就非常复杂,如果是外采,那就简单一点,只需要配合测试的它的逻辑,前仿和后仿。
2.5.3:Soft IP
一些较复杂的IP,比如:Debug IP(探针和调试工具)
这个要根据实际功能来看需要测试些什么,这里就不详述了。
2.6:跨平台/兼容性测试
这个要看本身是支持哪些操作系统 ,一般是要支持windows,linux(centos,redhat,ubunbu……)
这个也不详细介绍了,和其它软件的跨平台,兼容性测试一样的。
二:位流验证
EDA工具输出的东东,能否真实在硬件上可用,不可能都到实际硬件上运行,这时,就需要通过位流验证来保证了。提到位流验证前,需要先了解位流验证平台。
2.1:原理
不讲太复杂的东西,简单说明一下这个平台如何工作的?
1:首先,准备好你的FPGA的EDA软件(准备好Flow tcl)。给出你的所有Primitve的仿真库。
2:选择你要测试的设计用例(需要有一定的代表性噢),用 flow 生成仿真用的门级网表文件,输出用例的route结果,输出最终的bitstream。
3:开始对要测试的用例,编写一个参考模型(也是另外一种实现方案)。
4:使用第2步生成的route文件,找出你的用例的输入,输出IO,并定义相应的变量,按照你的IO Primitive的写法。
5:编写激励(测试)程序。
6:针对 DUT 的 Ref模型进行仿真,验证两者输出是否一致,如果一致,说明位流测试正常。
2.2:Device support 测试
对于EDA工具,我们前面已经讲了太多的功能测试,但是,我们设计出来的电路,是否能满足预期。我们首先要保证我们提供给用户的每一个器件的功能是符合预期的,也就是单个tile的功能是完全正常的。所以,我们需要针对单Tile,多Tile,fullchip做位流验证。方法就是使用上面的位流验证平台。
2.2.1:单tile
对于每一种Tile做单独的测试,比如:CLB(LUT,CLA,DFF,SFTR……),CMT,IO,DSP,BRAM,EMRAM……
也包括Tile内部的连接信号路由的验证。
我们以CLB为例,主要还是用例设计的问题:
对于CLB,里面主要涉及不同的LUT,DFF,CLA,SFTR,需要设计一系列的用例,去覆盖相关的器件使用。
- A & B , A | B 可以验证 LUT2的使用情况。
- INIT=0 IS_C_INVERTED = 0 IS_CLR_INVERTED=1 可以验证 DFFCE 的功能
- 1bit加,1bit 减 可以验证CLA功能
- wclk极性不反转 验证 SFTR32
- 将INIT、IC_C_INVERTED、IS_PRE(CLR/R/S/)_INVERTED的值进行随机,inst约束到FFA0 验证 LPQCE
我们再以DSP为例,选择合适的用例(针对DSPX48)
- (A+D)*B+C,均不打拍
- (A+D)*(A+D)+C,乘法器选择两个pre_add
- (A+D)*B+C,a,b,c,d均打一拍,预加器和乘法器不打拍
- (A+D)*B+C+carry_in,均不打拍
2.2.2:多tile
需要验证 Tile间路由的正确性,在多个tile分配资源,全局信号,时钟可以正常共享,跨tile的优化结果符合预期。
需要构造如下用例:
- 长路径信号传输:
- Tile间级联:多个tile之间的逻辑级联(比如:多级加法器)
- Tile内外通信:在不同Tile实现的模块之间进行通信(如:FIFO,AXI总线)
2.2.3:Fullchip 测试
对于全局资源(如:时钟,全局线)的使用进行验证。关注边界行为(I/O引脚,DDR,PCIe)。
需要构建的用例 :
- 设计一条覆盖尽可能多Tile的信号路径,从一个边界Tile传播到对角线另一侧。
- 在设计中启动全局时钟。
- 包含外部接口(I/O,DDR,PCIe)在设计中。
三:形式化验证
我还是把形式化验证单独拿了出来,因为它太特殊了,很多人都很难理解它的作用和必要性。实际上我也是基本上不懂,也没做过,只是把一些理论的东西列出来,完全没有实战的经验。也不清楚,它对于芯片EDA工具测试的必要性有多强?
3.1:概念
UVM主要是针对输出进行校验,可以理解为随机仿真,没有办法做到解空间的全覆盖,对于极端状态(边界)难以完全覆盖。
那如何做到更好的解空间覆盖呢?可以采用形式化验证。
形式化验证:从数学完备地证明和验证电路的实现方案是否确实实现了电路设计所描述的功能。
具体方法:二元决策图,计算树逻辑,Petri网,形式等效验证,符号模型检验,SAT。
对于芯片测试,它是一个很好的补充,它更像是静态测试,属于UVM的补充。
如果从工具层面上看,常用的工具是 Formality。
3.2:Formality
什么时候需要形式化验证?是在网表发生变化时,因为我们今天讲的是芯片,数字电路设计主要是通过verilog,而 formality刚好是支持verilog的工具。
以FPGA开发为例,我们可以认为 RTL 设计是 Reference design(golden design),我们认为是正确的设计。而 Implementation design 是经过修改的,待验证的设计。
我们要做的是,比较处理后的设计在功能上是否没有变化。
比较的原理,将设计变成多个锥,进行分别比较。
主要的流程:
形式化验证的速度较慢,需要很长时间。
3.3:示例
Formality 可用于验证综合后网表、布局布线后网表与原始 RTL 的逻辑一致性,帮助快速发现工具链中的功能错误。主要应用环节包括综合验证、布局布线验证、时序约束验证和部分重配置验证。通过自动化流程和详细报告,形式化验证是确保工具链逻辑正确性和等价性的重要手段。
举例一个设计中的模块:Adder
module Adder(input [3:0] a, input [3:0] b, output [3:0] sum);
assign sum = a + b;
endmodule
我们的目标是,确保综合后的门级网表与RTL定义的逻辑功能一致。
set_reference -vlog rtl/Adder.v
set_implementation -vlog netlist/Adder.mapped.v
match
verify
report verify
如何使用形式化验证来作为测试的补充,没啥好的经验。
四:上板测试
最后,在有条件的情况,我们希望能做上板测试。并且,有一些功能是强依赖上板测试的。比如:位流的烧录,在线Debug的功能。
4.1:在线烧录(download)
这部分的功能,类似GUI 功能测试的做法,需要对烧录的所有配置参数进行测试,对于速度,稳定性进行不同的测试。这要看我们提供多少种接口,多少种协议,按照相应的spec进行有针对性的测试。
4.2:在线调试(Debug)
这也是要看我们提供了哪些功能。一般常见的功能有,探针跟踪,在线分析仪,鹰眼跟踪数据。
这些都是要看具体的功能,对于使用层面,算是类似GUI的集成功能测试。对于本身的实现,可能需要针对相应的IP做测试(前面有章节已提到)。
4.3:其它
其它一些和环境,实际物理器件相关的测试,一般会在生产测试部门配合完成。按理也应该给出一些相关的测试报告。后面有机会,在讲解芯片的生产测试时,再仔细展开。
五:市场部验证
软件在软件部门评测无问题后,交到市场部,市场部一般还会做一次验收。
他们会关注软件的稳定性,关键性能,运行的一致性,客户用例的达成度……
好了,罗列了太多内容了,暂时就这么多了,有空再补充。