做了快十年的FPGA开发,近一半时间在跟军用电子产品的项目打交道。这些年被问到频率最高的问题,不是某一段Verilog怎么写,也不是某个接口的时序怎么收敛,而是一个看起来有点笨、却很难一句话答清的问题:FPGA到底算硬件,还是算软件?这个问题一旦落到型号项目里,就会变成一连串更绕不开的麻烦:要不要按软件流程评审?要不要做配置管理?测试记录要怎么写?交付的时候除了bit文件,还要交哪些文档?GJB 9764-2020标准下的FPGA软件研制,本质上就是回答这些“差不多先生”式的问题。这篇规范解读与工程实践指南,就是把我这些年落地这条标准时踩过的坑、拆过的条款、总结出的步骤,原原本本写出来。不管你是刚入门FPGA的新人,还是在做军用或高可靠项目的熟手,里面涉及的FPGA开发、时序约束、板级验证、配置管理方法,都应该能直接用上。
1. 为什么FPGA需要单独一套“软件测试规矩”
1.1 FPGA在装备研制里的角色已经悄悄变了
早期FPGA在板卡上的角色很简单,做地址译码、接口转换、控制逻辑,规模不大,错了也好查。但现在再看,一个综合化电子设备里,FPGA可能同时在承担多路高速图像采集、信号预处理、协议解析、大容量缓存管理、甚至部分安全逻辑。在这种复杂度下,“上板试试看,不行再改”的开发方式已经完全行不通了。
举个实际例子,我遇到过一个项目,FPGA要同时控制一片高速ADC和一片DAC,还带一个外部配置芯片的加载时序。功能仿真时一切正常,可是把bit流传到板子上之后,系统工作几分钟就偶发一次数据错乱。查了三天,最后定位到问题不在数据通路,而在外部器件对上电时序的要求极其苛刻,而我的设计里根本没有把“上电顺序”当作一条需求来管理。这种问题,单靠“功能对不对”的测试思路很难发现,必须靠一套能把时序、接口、异常行为、边界条件都纳入管理的规矩,才能提前暴露出来。
这恰恰是GJB 9764-2020这类标准的发力点。它不是教你怎么写HDL代码,而是告诉一个FPGA项目组:你该有哪些评审环节,该留下哪些可追踪的记录,该用什么方法去证明这个FPGA设计在交付之前已经达到可信状态。对于从事军工、航天、高可靠电子设备的人说,这套规矩不是负担,反而是保护自己的手段。
1.2 传统软件测试方法套不到FPGA上
做惯了MCU软件的人,刚开始接触FPGA测试时通常很不适应。传统软件测试的本质是:给一个处理器执行一串指令,观察寄存器和存储器的输出,所有行为是顺序化的,出错了可以打日志、打断点。FPGA不一样,它是硬件并行的逻辑电路,同一时刻可能有几十个模块在同时工作,数据通道、状态机、时钟树交织在一起,没有“CPU暂停”这种说法。
很多通用软件测试工具可以做的内容,比如“插桩覆盖率统计”“运行时动态断点”,在FPGA工程里很难直接搬,即使搬了也会因为资源占用过多而导致被测电路失真。反过来,FPGA里真正要紧的问题,比如跨时钟域采样亚稳态、组合逻辑环、未约束路径、布局布线后的时序余量不足,传统软件测试方法一条都覆盖不到。
所以,真正适配FPGA的测试活动,必须是仿真、静态时序分析、代码走查、上板动态验证、故障注入等手段的组合。GJB 9764-2020的价值,就是把这一整套组合用一个可执行、可检查的框架约束起来。如果你所在的团队还在把FPGA当硬件器件对待,没有单独建立一套软件测试记录,那早晚会在某个集成测试阶段翻车。
1.3 标准解决的核心矛盾:设计灵活性和可信度要求
FPGA和ASIC比起来,最大的优势是灵活,可以改设计,可以重新下载配置,开发周期短。但这个灵活性也带来一个麻烦:因为修改成本低,许多人就丧失了“一次做对”的约束意识,经常是一边改代码一边测,最后的电路行为究竟符合哪一版需求,谁也说不清。
而军用软件领域讲究什么呢?讲究可追溯、可验证、可复现。一次投板流片前,任何回路里某个信号电平错误都可能造成重大损失,必须给出令人信服的证据链。GJB 9764-2020瞄准的就是这对矛盾:如何在设计迭代快、综合工具黑盒化、交付物是不可读的配置文件的前提下,把“可信”这两个字落实成具体的工作产物。
我理解这套标准的本质,是逼着团队回答三个问题:第一,你的FPGA软件要做什么,边界在哪里,是否写清楚了;第二,你怎么证明实现是符合需求的,仿真、静态分析、上板验证各覆盖了什么;第三,你交付出去之后,问题能不能复现,历史版本还能不能追溯。能回答好这三问,FPGA软件项目就成功了一大半。
2. 我按落地需要把GJB 9764-2020拆成四个层面
拿到标准原文的第一感觉是,条目真多,而且很多表述是通用性条款,直接照做容易变成形式主义。我自己的习惯是,先把标准内容按工程执行的角度重新组织,不做逐条背诵,而是想清楚每个要求对应到项目里的哪个动作、由谁做、产出什么记录。
这不是标准原文的章节结构,而是我个人理解出来的工作框架,具体项目仍要以当时受控的有效版本为准。
2.1 管理与流程层面
这一层解决的是“人、事、节点”的问题。FPGA设计不能做一步看一步,必须像软件项目一样有策划、有评审、有风险跟踪。
我在团队里通常会要求先输出一份FPGA软件研制策划或软件开发计划,里面明确几个基本要素:项目用到的FPGA芯片型号、开发工具及版本、第三方IP清单、团队分工、关键里程碑、每个阶段的评审方式、问题报告的流转路径。不要小看这份策划,它最大的作用不是给领导看,而是让项目组内部在开工前对齐预期,避免后期“我以为你测过了,你以为我测过了”的情况发生。
流程层面还涉及一个常见争议:FPGA软件要不要引入独立测试人员。如果团队规模允许,我强烈建议让没有参与RTL编码的人承担系统级仿真和上板验证。哪怕只有交叉验收这种程度,也能挡掉不少“设计者盲区”。比如你自己写的状态机,怎么走都觉得合理,因为每一步都是你设计的思路,但另一个人拿着需求文档来测,反而更容易发现遗漏的分支。标准里对这种独立性虽有不同细度要求,但背后的风险控制逻辑是一样的。
2.2 技术实现层面
技术层面只干一件事:把“需求怎么变成电路”这件事讲清楚,并且保证实现过程可控。
输出物一般包括三类:软件需求规格说明、软件设计说明、源代码及其配套脚本与约束文件。写设计说明的时候,不要只贴代码,要讲清楚每个模块的接口时序、状态转移、数据位宽、异常处理方式,还包括一些工具层面的工程设置,比如综合策略、布局布线种子、时序约束文件版本等。这些信息在后续排错和维护时价值极大。
源码工程的管理里,很多人忽略的是脚本和约束文件。一个FPGA工程最终生成bit流,靠的不只是VHDL或者Verilog源码,约束文件(XDC/SDC/QSF)、IP定制文件、Makefile或Tcl脚本、甚至综合策略中的某个随机种子,都会影响最终结果。这些都应该纳入配置管理,不能只在个人电脑里存着一份“能跑的工程”。我在项目评审时发现过不少次,开发人员换台机器重新跑综合,结果时序结果变了,但查遍代码没有任何改动,最后才意识到是综合种子和工程版本没锁住。
2.3 测试与验证层面
测试层面是整个标准里我最看重的一块,也是最容易做形式化的一块。测试活动不能简化成“跑一遍仿真、上板烧一把、看灯亮不亮”,而应该是一系列有依据、有判决、有记录的动作。
我通常把FPGA软件验证拆成四层:静态分析层,包括代码走查、Lint检查、跨时钟域检查,目标是去除代码隐患;动态仿真层,包括模块级仿真和系统级仿真,目标是验证功能逻辑;静态时序分析层,包括综合后和布局布线后的时序报告检查,目标是保证时序收敛;板级验证层,包括配置烧录、寄存器读写、主功能跑测、异常拉偏测试,目标是验证真实环境下的行为。
每一层都要有对应的计划、说明、报告和问题单。我不是说所有项目都要做全套,但至少要在测试计划里明确:哪些做、哪些不做、为什么不做,这是一种工程判断,而不是拍脑袋省略。
2.4 交付与记录层面
交付和记录是FPGA项目最容易翻车的环节。很多团队交付的时候,只提供一个bit文件和一个“说明.txt”,然后拍胸脯说设计没问题。真正符合规范的做法,是交付一套可以重建整个研制过程的基础信息。
我建议每个FPGA项目至少具备以下交付物:受控的源码工程和版本列表;经评审的需求和设计文档;测试计划、测试用例、测试报告;覆盖率统计结果或者阈值确认记录;时序收敛报告和例外路径说明;配置管理记录和问题追踪清单;最终比特流的校验值以及对应工程的完整标识。
这些记录不是越厚越好,但一定要让一个没有参加过这个项目的人,拿到资料后能复现整个验证过程。这个可复现性的底线,才是规范真正要求的“硬指标”。没有这些,程序跑得再欢,也只能算是一个“基于经验的侥幸成功”。
3. 需求阶段必须堵住两个漏洞:接口定义和复位/时钟策略
3.1 接口协议:从时序图到可验证的约束
很多FPGA项目在需求阶段就埋了雷,最常见的是接口定义停留在“大概这个样子”的程度。比如模块说明里写着“在数据准备好信号拉高后等待一小段时间再发送数据”,这种话在设计和仿真阶段根本没有办法形成断言,等到联调时才发现两边理解不一致。
我自己的习惯是,所有外部接口都必须有三样东西:接口信号方向和数据位宽的完整列表、接口时序图而且必须标注时钟周期数、异常或超时行为描述。以一次QSPI Flash的读操作为例,需求里不能只写“从Flash读数据”,至少要有:时钟频率、片选信号有效时序、指令码与地址位宽、等待周期数、读数据在哪个沿有效、超时后状态机如何处理、CRC校验失败怎么办。
这些内容确认得越早,后面的仿真测试用例就越有据可依。我把测试用例和需求条目做了双向追踪矩阵,每一条需求都有对应的正向用例和反向用例,反向用例专门覆盖边界的错误行为。比如接口需求规定“收到非法命令字时,系统应在1个时钟周期内回复错误标志且不触发任何写操作”,那就必须有用例去踩这个分支。很多项目功能仿真的覆盖率高,但异常分支覆盖率很差,就是因为需求层面对异常行为根本没有定义。
3.2 复位与时钟:FPGA亚稳态问题的源头管理
FPGA设计中有一个最容易被新手忽略、也最容易在项目后期造成致命事故的话题,就是复位和时钟策略。热词里出现的“FPGA复位信号亚稳态”,几乎是每次评审必被翻开的老账。
工程上常见的错误是直接使用外部按钮产生异步复位,再不加处理地连到所有寄存器的复位端。异步复位释放如果离时钟上升沿太近,就会导致一部分寄存器比另一部分寄存器早退出复位一个周期,状态机里的状态寄存器可能从非法状态开始工作。你说它是什么大问题?多数情况下不是,系统可能抖动一下又能跑,但在军用高可靠环境里,“可能”这两个字就是不可接受的。
我推荐的做法是采用异步复位、同步释放的复位桥电路。也就是说,外部复位信号到来时可以立即影响全局复位,但释放时通过两级同步器由时钟把它们统一放行,确保所有寄存器在同一拍退出复位状态。这个逻辑就算在综合工具里加了复位相关的优化选项,也应该在RTL级别显式实现,而不是指望工具默认处理。
时钟策略同样要在需求阶段定清楚。单时钟域还是多时钟域?有没有时钟分频、倍频、动态切换?不同时钟域之间有哪些信号需要跨越?这些都会直接影响编码和测试策略。跨时钟域信号如果没有做两级同步,或者使用异步FIFO时格雷码处理不当,上板之后表现出来的就是“随机偶发错误”,极难定位。这一类问题在仿真中往往看得很清楚,前提是仿真环境里要把异步时钟关系建出来并且跑足够多的随机相位回归。
4. 编码与静态检查:用工具把问题挡在综合之前
4.1 综合不报错,不等于电路正确
很多刚入门的FPGA开发人员有个错觉,认为只要综合通过、时序没什么大红,代码就算写完了。实际上,综合工具比你想象中“宽容”得多,它只负责把你的RTL描述翻译成电路,至于这个电路是不是你想要的那个行为,它不保证,也保证不了。
最常见的就是组合逻辑里漏写else。假设有一段这样的代码:
always @(*) begin if (sel == 1'b1) data_out = data_a; end这段代码综合不会报错,但视频电路里会综合出一个锁存器。看起来差别不大,可是在FPGA里,这种隐性锁存器会带来时序收敛麻烦,也容易产生毛刺,甚至在资源报告中造成误导。静态检查工具里有一类规则就是专门抓这种“incomplete assignment”的。规范要求的代码走查,重点之一就是把这些“工具不报错但行为不对”的模式挑出来。
状态机也一样。如果你定义了三个状态,case语句里只写了三个分支,没有default,综合器可能会在非法状态下兜圈回不来。正确做法是给状态寄存器加默认状态,并在仿真里专门设计非法状态注入用例,确认它能回到安全状态。这些动作听起来繁琐,但都能在综合之前兜住问题。
4.2 静态检查的具体项目清单
在实际落地时,我一般会把静态检查项整理成一张清单,交给工具自动扫描,同时人工重点查看工具无法理解的语义问题。这张清单大致包含以下内容:
- 未使用信号、悬空输入、重复驱动或多驱动信号;
- 组合逻辑环和组合反馈回路;
- if/case分支是否完整,是否存在隐性锁存器;
- 状态机是否存在不可达或非法状态回复路径;
- 跨时钟域信号是否经过正确同步,有没有CDC路径遗漏;
- 复位信号的处理方式是否统一,是否存在未复位寄存器;
- 位宽不匹配和截位风险,尤其是乘法器、累加器、图像处理通路中的定点数运算;
- 异步信号直接参与组合逻辑或作为时钟使用的情况;
- 时钟门控和时钟切换是否有保护逻辑;
- 第三IP输出信号有无做必要的上电初始化和错误处理。
这套清单的价值,不只是产生一份检查报告,而是把团队内部长期踩坑的经验固化成了规则。我见过不少团队,第一年项目出了问题很紧张,第二年就忘了,第三年又在同一个坑里栽倒。把规则写进静态检查库和代码评审检查单,才能让组织记忆真正沉淀下来。
4.3 关于工具置信度的现实建议
FPGA开发工具链是黑盒,这是客观事实。你写了一段RTL,工具综合成什么样,布局布线时走了哪些路径,没多少人能完全控制。GJB 9764-2020背后的风险管理逻辑告诉我们,越依赖工具,就越要评估工具本身的可信度。
实际工程里有两个维度:一是工具版本要锁死,二是工具规则和编译选项要有记录。工具升级后综合结果差异大,这是普遍现象,不一定是新版工具更差,但你必须知道差异在哪里。所以我们会在交付资料里写明使用的是哪个厂商、哪个版本、哪个补丁,以及综合种子和布局布线策略的配置。这样万一后续需要回溯,才能复现当时的时序结果。
另外,如果项目中使用了没有被鉴定过的第三方IP,或者自定义的综合流程,就需要额外验证来补偿置信度缺口。比如一个外部提供的DDR控制器IP,我无法审查它内部每个逻辑单元,但我会把它当做一个相对独立的模块,在系统级仿真里覆盖它的初始化时序、唤醒时序、刷新行为、错误状态等多个场景,并在测试记录里注明该项验证的目的和局限性。坦白地承认“哪些我证明了、哪些没有”,本身就是一种负责任的做法。
5. 仿真做到什么程度才叫通过:覆盖率、断言与可复现性
5.1 覆盖率不是越高越好,而是要有方向
谈到仿真验证,最常见的考核指标是代码覆盖率。很多人误以为语句覆盖率、分支覆盖率跑到95%以上,就说明测试充分了。这是很大的误会。代码覆盖率只能告诉你“哪些代码被执行过”,不能告诉你“这次执行是否符合预期”。一个功能错误的仿真,同样可以把代码覆盖到100%。
我采取的策略是联合使用代码覆盖率和功能覆盖率。功能覆盖率不是工具自动收集的,而是从需求分析出来,像人工设计的检查点。比如一个通信接口模块,字节序、帧格式、超时重传、错误FCS、缓冲区溢出后是否会丢弃,这些场景必须单独设计用例并勾选确认。每一条功能覆盖点都对应需求文档里的一条内容,最终汇总成一张“需求/覆盖/结论”的对应表,作为仿真通过的评判依据。这就是测试可审计性的核心。
覆盖率的方向感比数字更重要。我们曾经在图像处理模块里为了保证定点数运算精度,专门针对中间计算位宽设计了边界值用例:全零输入、最大正值、最小负值、交替变化模式,以及渐近接近溢出阈值的序列。这些用例覆盖到的不是代码行,而是算法行为。跑完之后再对比MATLAB参考模型,误差完全在可接受范围内,我们才敢说这块定点处理逻辑验证到位了。
5.2 断言:把“协议正确”变成机器可查的条件
仿真最忌讳的是对着波形图“目测正确”。人眼在波形上盯了一个小时,基本就麻木了,很容易放过一个本该被判错的边沿。因此,我要求测试平台里必须有自动化断言,最好使用SVA等断言语言来描述时序协议。
比如,我们可以针对请求和应答之间的关系写一条断言:
property req_resp_timing; @(posedge clk) $rose(req) |-> ##[1:3] $rose(ack); endproperty意思是,每当req拉高,ack必须在一个到三个时钟周期内拉高。一旦超过三个周期,仿真直接报错。这样,无论是功能回归、随机激励测试,还是系统级长时间仿真,都能自动捕获协议违规。断言是真真正正的“机器可查条件”,比任何测试报告里的“人工检查通过”都可靠得多。
有些人觉得写断言浪费时间,但实际上断言的成本在长期维护里能换回数倍回报。尤其是在做FPGA图像处理或者总线协议适配的时候,接口时序复杂且频繁迭代,没有断言约束,改一处逻辑很可能就悄悄破坏了对面的时序假设。有了断言,回归测试一旦跑出一个红色报错,你瞬间就知道是什么被打断了,而不用像侦探一样去翻波形。
5.3 仿真环境本身要纳入配置管理
仿真可复现性经常被忽略。很多项目的仿真结果是“仅此一次”的:某个随机种子跑出的波形过了,下一次换一台机器跑就报错,根本原因是什么没人知道。规范的测试流程要求,仿真验证环境本身就是一种软件配置项,必须记录下来。
我们组的做法是,把仿真脚本、Testbench源码、随机种子、工具版本、IP版本、编译参数全部放进受控目录,并且在每一次仿真回归结束后,记录关键输出日志的校验值。这样,任何一次测试结果,别人拿到之后都能原样复现,而不必依赖“当时那台电脑”。
特别是当验证涉及随机激励时,固定随机种子就格外重要。如果不固定种子,可能你今天跑功能全对,明天换了种子就报一个超时,而你根本不知道是这个种子触发了边界,还是昨天修复的代码被引进了回归。种子不一致,整个验证过程就没有可追溯性,测试报告里写的“通过”也就缺少依据。用控制器更有把握的一点,是把固定种子当成回归配置线的一部分,而不是随用随改。
6. 从综合到上板:时序、布局布线和在线调试的配合
6.1 综合、布局、布线到底是三步还是两个阶段
很多开发者在刚接触FPGA工具链时,对“布局”和“布线”这两个词容易混着用。其实这两个步骤解决的问题完全不同,我先用一个小类比解释:综合解决的是“逻辑上有什么”,布局解决的是“这些门放在哪里”,布线解决的是“怎么连起来”。
布局阶段,工具会把综合出来的寄存器和查找表分配到FPGA内部的实际物理位置上。这一步决定了资源的物理距离,也决定了时钟区域、DSP单元、块内存的布置是否合理。布线阶段,工具则根据布局结果,用可编程开关构造实际互连,把每个模块打通。布线结果直接决定了每条路径的延迟,也就是最终时序是否满足约束。
在工程实践中,布局和布线是强耦合的迭代关系,没有绝对的先后。比如布线完发现某一阶路径时序违规,工具可能会重新布局,把相关逻辑拉近,再重新布线。这也是为什么我们反复强调时序收敛要靠合理的代码结构、充分的物理约束和足够的时序余量,而指望工具像魔法一样把所有整理干净,不现实。
对于图像处理这类数据流密集的FPGA应用,布局布线是否合理,还会影响功耗和引脚锁存。设计中如果注意把同一数据通路上的运算单元放在同一时钟区域,布线的局部拥塞会明显减少。这个心得听上去很虚,但我在做多点位视频拼接项目时,仅仅调整了一个计算模块的物理位置约束,就把原本不收敛的路径全部变成了正余量。
6.2 时序约束与“偶发错误”的排查思路
FPGA上板后表现成“偶发错误”的问题,十有八九可以追溯到三类原因:跨时钟域亚稳态、IO时序约束偏差、异步信号处理不当。而这些问题在静态时序分析报告里不一定直接暴露,因为STA检查的是你声明的约束路径,如果某条路径本来就没被约束,工具根本不会去看它。
比如外部输入信号没有经过同步就直接进入内部逻辑,就可能产生亚稳态。同步器本身也存在“平均故障间隔时间(MTBF)”指标,如果时钟频率很高、信号翻转频繁,MTBF可能会低到几小时,表现为系统隔一段时间随机错误一次。我们曾经排查过一个故障,现象是设备运行几个小时之后偶尔出现一帧图像花屏,最后定位就是对外部同步信号只打了一拍,没有采用跨时钟域的正确处理。这类问题在做随机长时间回归测试时最容易暴露,靠“跑一次看一次”很难发现规律。
如果你在排查一个偶发问题时,一定要保留逻辑分析仪的采样数据。Vivado里有ILA,Quartus里有SignalTap,这些在线调试核可以挂在目标信号上,用真实时钟连续采样,把错误发生时前后的波形保存下来。把波形文件和时序报告、仿真波形放在一起对比,往往能快速定位是时序问题还是逻辑问题。这一步做完,再回到仿真里去构造复现用例,修复后重新跑回归,才能确认问题真正解决,而不是在板子上“碰巧躲过”。
6.3 上板验证的设计:从JTAG回读到在线逻辑分析仪
板级验证不能只是烧个bit流,看几个指示灯,然后紧张地等着是否出错。为了支撑标准要求,最好在系统设计阶段就给FPGA预留自测试和观测接口。至少包括三种:JTAG链可以用来做边界扫描和配置下载;在线逻辑分析仪核用来观测内部信号;寄存器读写接口用来让处理器或者上位机对FPGA内部状态进行控制和回读。
这些调试逻辑有时会占据不少资源,所以在交付之前,我强烈建议做一次“调试逻辑清理”:把为排错插入的ILA核、计数器、导出寄存器删掉或临时禁用,重新综合布局布线,然后运行一轮完整的回归验证。为什么要多此一举呢?因为清理调试逻辑后会改变布局,时序行为会发生变化,甚至可能因为引脚分配精简而有细微差别。不重新验证过,等于交付了一个没跑过的新版本。
还有一类验证容易被忽略,就是配置Bit流本身。上电加载是FPGA系统的第一道关口,外部配置器件、时钟源、配置引脚电平、模式选择都可能出问题。我们会在板级验证用例里专门设计:配置完成后去读取配置状态寄存器、回读Bit流并校验CRC、模拟配置失败后是否进入差错处理流程。这些看似基础的内容,恰恰是军用和民用高可靠场景下最容易提心吊胆的一环。只有把上电时的一致性都纳入计划,才算得上完整的板级验证。
7. FPGA工程管理里的隐性成本和踩坑记录
7.1 工具版本变更带来的“玄学”问题
FPGA工具链的更新速度非常快,供应商每年都会发布新版本,而且很多项目立项时为了省事,直接就装了最新版。这种做法的麻烦,通常不是立刻显现的,而是半年后当你需要复现一个旧版本结果时,发现那台机器上已经找不到当时的工具环境了。
有一次我们做回归对比测试,想把一个老工程从旧版本工具迁移到新版本,结果综合后的寄存器数量变了,关键路径延迟也不同。代码一行没动,只是升级了工具版本,就带来了这么大的影响。后来我们总结经验,在项目策划阶段就明确指定工具版本,而且在版本变更时走正式的更改流程,先做小范围对比验证,评估差异在可接受范围内,才允许全工程切换。对于军工项目来说,这种“工程可复现性”不完全依赖人记性,而是要依靠配置管理工具的强制手段才能持续维系。
更要提醒的一点是,综合工具里的随机种子并不“随机”,它决定了工具探索解空间的方向。不同种子对应的布局布线结果不同,可能其中一个能满足时序,另一个就不满足。在最终确认交付版本时,我们会在固定约束条件下保存当时使用的种子,并且在测试记录里把这个参数写清楚。否则,后续任何人重跑一遍,哪怕工程一样,结果也可能对不上,这在评审时非常麻烦。
7.2 第三方IP的审查边界
现在的FPGA设计几乎离不开IP核。PCIe、DDR、MIPI、Ethernet这类高速接口,自己从头写既不经济也不安全,大概率直接使用厂商或第三方供应商提供的IP。但第三方IP同时也是一个黑盒,它内部到底怎么实现,有没有隐藏缺陷,你通常看不到。
所以我在审核第三方IP时,不会因为它是知名厂商就放松验证,而是把IP的外部行为看成一个待测对象,重点做集成边界检查。具体来说,包括:IP的时钟和复位要求是否全部满足;配置寄存器默认值是否与手册一致;上电初始化和热复位流程是否完整;异常输入条件下IP是否会产生错误的控制信号;IP在配置错误时是否有状态位可以查询。这些用例不出来,就不算完成了IP验证。
还要保留IP供应商的版本证明和授权文件。项目到后期做过一次外部严厉检查,问“DDR控制器的版本为什么是这个版本,和时序分析报告是否一致”,要是没有证据根本回答不了。保留这些信息,不只是合规需要,更是为了在IP供应商发布补丁或安全通告时,你能判断当前工程是否受影响。这种“供应链意识”,是FPGA软件工程管理里很容易被低估的能力。
7.3 测试记录与文档的“可复现性”底线
关于测试记录,我想说一个很多人不爱听的观点:记录写得再少,也不能少到让后来人无法判断这次测试到底干过什么。我看到过不少测试报告,只有“功能测试通过”“指标满足要求”这样的结论,既没有测试环境描述,也没有用例编号,更不用说被测试的代码版本。这种报告写多了,人就会麻掉,最后连自己都信了“测试通过了”这句话。
一个最低限度可用的测试记录,至少应该包含:被测工程版本号或SVN/Git版本标识;开发工具的厂商、版本和关键参数;测试用例与需求条目的对应关系表;每次仿真的随机种子和日志摘要;上板验证的软硬件环境和操作步骤;问题单列表及其关闭情况。有了这些,哪怕项目结束半年后有人提出一个故障,也能快速回溯,而不是从零开始重新猜。
在实际项目里,我倾向于把“需求到测试用例的追踪矩阵”放在配置管理工具里维护,每次需求变更就同步更新矩阵,测试用例执行结果也回填到这个矩阵中。这样做的好处是,评审的时候不是看一堆打印稿,而是面对一份动态、可查询的证据链。虽然前期建立这种表格要多花一点时间,但它在项目每个阶段都会省下大量“解释来龙去脉”的时间。到最后交付,资料不是“写出来”的,而是项目过程中自然而然沉淀下来的,这才是规范落地的真正状态。
如果整个项目只能先落地一件事,我的建议就是先搭起这条“需求到测试用例”的追踪链。我在很多团队里发现,大家不是不愿意写文档,而是不知道写什么才不算形式主义。其实答案很简单:把需求的每一个条目,从设计、编码、仿真、上板一路追踪到你验证过它的证据上,这条链完整了,GJB 9764-2020里的管理要求、测试要求、文档要求自然就推动了。坚持这种做法几年以后,你会发现自己对FPGA项目的掌握程度,已经远超“代码能跑就行”的阶段,而是进入“每一步都有底气”的状态。