FPGA 专家 36:自动化测试——让硬件像软件一样持续回归
本文是
fpga/专家层第 39 篇。仿真加速与覆盖率见 进阶 24,CI 流程建设见 专家 46,JTAG 自动化通道见 专家 27。
一、FPGA 测试金字塔

▲ 上板 BIST/冒烟/性能(少、慢、真)
│ 子系统协同仿真(AXI VIP/BFM)
│ 模块级仿真(多 seed 随机+断言+覆盖率,快、多)
└──────────────────────────────► 反馈速度
原则:能在仿真证伪的不上板。二、仿真回归工程

- pytest/cocotb/Makefile 组织用例;自检 TB + 参考模型,失败即红;
- 回归矩阵:器件/参数/seed;功能覆盖率补洞;波形+日志+git hash 自动归档;
- flaky 治理:固定 seed、禁真实时间假设。
三、板级自检 BIST

上电/命令 ─► BIST 控制器 ─┬─ SerDes PRBS 误码
├─ DDR march/图案
├─ 算法 golden vector
├─ 时钟/温度/电压
└─ 接口回环/对发
结果 ─► 状态寄存器/LED/UART/网络 ─► 夹具/MES 绑定序列号铁律:BIST 不能依赖被测对象自身。
四、远程 Lab + 硬件 CI

git push → lint/CDC → 仿真回归 → 综合(资源/警告) → 实现(时序门槛)
→ 调度器选板(PDU 上电/JTAG-over-ETH/串口网管)
→ 刷 commit 关联比特流 → BIST+冒烟 → 结果回 PR板卡池管理:健康心跳、占用锁、自动发现、失败硬下电、比特流版本寄存器。
五、失败治理
区分物理(接触/供电/老化→监控与下线)、测试(固定延时→改状态同步)、真随机(CDC/误码→统计压力);归档 commit+比特流+全量日志+ILA+环境快照保证可重放。
六、测试基础设施工程:让一条失败能在十分钟内定位
自动化测试的价值不仅是“自动跑”,更是失败的可诊断性。一条回归失败,如果需要资深工程师花半天翻波形才能定位,那么测试再多也无法支撑高频迭代——团队会倾向于忽略红灯。测试基础设施工程的目标,是让绝大多数失败在十分钟内由提交者自己定位到模块、场景和原因,这要求在测试组织、日志、归档、环境管理上做扎实的工程投入。
测试用例的组织原则是分层、正交、可选择。单元级用例只验一个模块的一个性质(某个 FIFO 的满空行为、某个 CRC 的已知向量),毫秒级跑完、失败即指向该模块;子系统用例验多模块协同(AXI 主设备经互联访问多个从设备),秒级;系统/端到端用例跑完整业务流,慢但少。用例之间不得共享可变状态(每个用例独立复位、独立随机种子、独立目录),否则一个用例改状态会导致后面的用例随机失败。用 Python(pytest/cocotb)或 Makefile 把用例组织成可按标签选择(只跑冒烟、只跑某模块、只跑长回归),让开发者本地跑快速子集、CI 跑全量,反馈时间分层。参数化用例(同一测试逻辑跑不同数据宽度、不同 FIFO 深度、不同 seed)用同一套代码覆盖配置矩阵,避免复制粘贴导致的维护灾难。
自检(self-checking)是底线:测试台必须自带参考模型和期望,自己判 pass/fail,绝不依赖人看波形。每笔事务即时比对、发现第一个失配就打印“时间、期望值、实际值、事务序号、相关输入历史”,然后在安全点结束(不是立刻结束,要让 pipeline 排空、把后续相关日志打出来)。记分板(scoreboard)、覆盖率收集器、协议监视器(monitor 把管脚事务翻译成人类可读的“读地址 X 返回 Y”)是标准组件,应做成复用库。随机测试必须可复现:种子显式打印并写入归档,给定种子 + 代码版本必须能重放同一激励;带随机性的用例失败后,归档里第一件事就是能拿到复现命令。
日志与波形归档策略要按失败成本分层。全程波形文件巨大且写盘慢,不能每用例都全量 dump。成熟做法是:常规运行只存结构化文本日志(事务流水、断言、状态转移),波形用环形缓冲(只保留最近 N 个事务/时间窗在内存),一旦失败才把环形缓冲落盘——这正好覆盖“失败前发生了什么”,文件小而精准;对疑难用例再单独开全波形。归档目录以“用例名 + seed + git hash + 时间戳”命名,内含日志、波形、综合/时序报告、配置参数、标准输出,保留策略按磁盘配额滚动。这样 CI 红了,打开归档就能复现,而不是找当时跑测试的人要环境。
环境与依赖管理决定回归是否可信。仿真器版本、IP 版本、工具链、环境变量、第三方库必须固定并可一键搭建(容器或脚本化环境),避免“我本地过了”的版本漂移;测试数据(输入文件、golden 向量)纳入版本库或制品库,不允许散落在个人机器;CI 的每次运行记录完整环境指纹。对 FPGA,还要管理器件型号/速度等级/器件版本(stepping)、板卡序列号、比特流版本这些硬件维度。时间相关用例禁止用墙钟 sleep 做判断(机器忙慢时必 flaky),全部改用“轮询硬件状态位 + 超时”的确定性同步。
可诊断性还要覆盖‘测试本身错了’和‘环境错了’。失败要分类:RTL 缺陷(有稳定失配)、测试台缺陷(参考模型或检查器错)、环境缺陷(板卡掉线、许可证耗尽、磁盘满)。后两类不应报成产品 bug,CI 框架要能识别基础设施错误(连接失败、烧录失败)并重试或标记为 infra-error,避免噪声淹没真实信号。长期统计各类失败和 flaky 率,本身就是衡量测试体系健康度的指标:一个 flaky 率很高的回归集会被团队忽略,比没有测试更危险,因为它制造了虚假的安全感。
七、约束随机验证与覆盖率闭环:从“测了很多”到“知道没测到什么”

定向测试只能验证工程师想到的场景,而真实 bug 藏在没想到的组合里。约束随机验证(CRV)的思路是:用约束描述合法输入空间,让生成器自动产生大量合法且多样的激励,用功能覆盖率回答“设计的哪些行为被真正 exercised 过”,再用覆盖率驱动的反馈定向补洞。这套从 SystemVerilog 约束随机/覆盖率到 cocotb + Python 的方法论,是把验证从“体力劳动”变成“可度量工程”的关键,FPGA 项目即便不用全套 UVM,也应吸收其核心纪律。
激励建模分两层:数据字段约束(每个包/事务各字段的取值域、合法性关系,比如 length 字段必须和实际负载一致、类型枚举按权重分布)和场景/序列约束(连续事务之间的关系:背靠背、间隔随机、反向读写交错、满负荷突发、错误注入)。约束要分层——基础约束保证永远合法(不产生协议不允许的事务),测试用例在其上叠加场景约束(这次专门打满 FIFO、专门发非法长度),错误激励单独走“允许非法”的约束并期待 DUT 正确拒绝。纯均匀随机往往大量重复常见场景、几乎不碰边界,因此要对边界值、罕见状态(FIFO 将满将空、计数器回绕、背靠背最大包)加权,让随机有方向地涌向易错区。
参考模型与检查器在随机环境下更关键:因为没人能预知第 3724 个随机事务的正确输出,必须有一个与 RTL 独立实现的模型(软件功能模型、事务级参考、或已知性质的不变量检查器)实时判定。检查分两类——数据检查(每个响应的内容对不对,经 scoreboard 与期望比对)和协议/性质检查(不管数据是什么都必须成立的不变量:valid/ready 握手不能丢事务、FIFO 先入先出、计数器不回退、状态机不进非法态),后者用断言(SVA/仿真断言)表达最有效,一处违反立即抓到现场。好的验证环境里,断言像网一样铺满接口和关键不变量,随机流量在网里跑,任何违反立刻现形。
覆盖率分两种,回答不同问题。代码/翻转覆盖率(工具自动统计哪些行、哪些信号值、哪些状态/翻转被触发)回答“RTL 的哪些角落没被碰到”,但覆盖了代码不代表验证了意图(一行错误代码也可能被执行)。**功能覆盖率(covergroup/覆盖点/交叉覆盖)**由验证者定义,回答“规格里的重要场景组合是否都发生过”:如“各种包长 × 各种队列深度 × 背压有无 × 是否跨越缓存块边界”的交叉。交叉覆盖是发现组合盲区的利器——单独看包长覆盖了、背压也覆盖了,但“最长包 + 最深背压 + 边界未对齐”这个致命组合可能从未发生。覆盖率目标不是盲目追求 100%(有些组合不可达),而是对每个未覆盖/未达标点分析原因:不可达就合理排除(waiver 并说明),可达却没测到就加约束/定向用例。
覆盖率驱动验证(CDG)的闭环:跑一批随机种子→收集功能和代码覆盖率→看覆盖率报告找洞→加新约束或定向序列定向打洞→再跑,直到覆盖率收敛、找不到新 bug(覆盖率曲线和 bug 发现曲线都趋平)。回归库要多 seed 滚动:同一随机测试每次 CI 用不同 seed(同时归档固定 seed 的基线),随时间积累覆盖的空间远超固定用例。覆盖率数据本身也进趋势管理——覆盖率不应倒退(重构把某路径变成不可达要显式确认)。形式验证在这里互补:对难以靠随机命中的深边界(如特定计数器值 + 特定状态 + 特定错误),用形式工具直接证明性质在所有可达状态成立或给出反例,随机管“常见大海”、形式管“证明角落”。
对资源受限的 FPGA 团队,落地 CRV 不必全套重器:用 cocotb/Python 写带权重的随机事务生成器和 scoreboard、用仿真器的覆盖率开关收集翻转/条件覆盖、用一个简单表格手工维护关键场景覆盖矩阵、对关键握手用断言,就能获得这套方法论八成的收益。最重要的思维转变是:验证完成度的判据从“我写了多少用例”变成“规格定义的行为空间被覆盖了多少、还有哪些洞”,并且这个数字是自动测量、持续可见的。
八、板级 BIST 与量产夹具:把健康检查设计进芯片
仿真覆盖功能,但产品在现场面对的是真实 SerDes、真实 DDR、真实温度电压和老化。板级自检(BIST, Built-In Self-Test)把“验证设备是否健康”的能力做进 FPGA 本身,使板子在产线夹具、上电现场、远程机房里无需外接仪表或专家即可自证健康,并给出可定位的故障码。它既是量产测试手段,也是现场运维和远程 CI 的基础。
BIST 控制器是一段独立于业务功能的硬件状态机,上电后或收到命令后顺序执行一组测试并汇总结果。典型测试项:①SerDes/收发器:内部环回(near-end PMA loopback、远端 PCS loopback)下发 PRBS 图案,统计误码率/误码计数,覆盖串行链路、均衡和时钟恢复;外部环回还能覆盖板级通道和光模块。②DDR/外部存储:march 算法(按特定顺序对每个地址写读 0/1/棋盘/行走图案)检测固定故障、相邻位耦合、地址解码错误,再加随机图案和长时间压力,很多 FPGA 自带 DDR 控制器提供校准与校验状态可读。③算法核/数据通路:灌入 golden vector(已知输入和期望输出),比对结果,覆盖业务逻辑;含 DSP/BRAM 的通路用已知答案验证运算和存储完好。④时钟/电源/温度:读 XADC/系统监控的电压、片上温度、PLL lock 状态,与门限比较。⑤板级接口:UART/SPI/I2C/以太网环回、与对侧板/夹具互发、LED/继电器自检。⑥存储与配置:Flash/SD/eMMC 读写校验、配置 CRC、比特流版本寄存器(见 20 比特流烧录与四方版本一致 manifest/门禁)。
BIST 设计的铁律是不能依赖被测对象自身:测 DDR 的代码不能放在待验证的 DDR 里执行(要在 BRAM/OCM)、测 SerDes 的结果通道不能复用正在被测的那条链路(用独立低速管理口/JTAG)、测试控制器的时钟和复位要独立于被测时钟资源;否则某一项故障会让自检本身跑不起来或给出假结果。BIST 还要能在不同温度电压点重复触发(配合温度箱和电压拉偏做 corner 验证),测试覆盖和入口/出口条件明确,测试结束后设备干净回到正常工作态(环回要解除、PRBS 要清、控制器复位业务通路)。
结果上报与故障码要支持多种消费方式:LED/数码管给出粗粒度阶段/错误码(产线工人和无外壳场景用)、UART 打印详细文本、经 JTAG/管理控制器读出寄存器、或经网络上报。给每类故障一个稳定编码(如 DDR 位 3 march 失败、通道 2 误码超限、核心电压低于下限),产线 MES 系统把序列号 + BIST 结果绑定存档,维修时直接定位到通道/器件而非整板报废。BIST 结果应包含版本、时间、温度电压快照,使故障数据可做批次分析(某批次某通道早期失效 → 来料或焊接问题)。
**量产夹具(fixture)**把 BIST 接到自动化产线:夹具提供电源(程控电压、可拉偏)、激励(GPIO 脉冲、继电器环接外部接口、参考时钟)、负载和测量(万用表/示波器经 SCPI 程控读取电平、电流),一台测试站运行脚本——扫描条码、烧录正确比特流(含版本绑定)、触发 BIST、采集结果和电流功耗、与限值比较、写 MES、按 pass/fail 分流。FPGA 在这里的独特价值是高速接口可以自测(普通 MCU 测不了 10G/25G SerDes),夹具主要负责外部环回路径、电源和最终的电气确认。边界扫描(JTAG boundary scan)可与 BIST 互补做管脚焊接/连通性测试。
在研发流程中,BIST 不应是量产前才补的“测试部门的事”:它在 bring-up 阶段就是最好的最小验证(一块新板先跑 BIST 确认器件健康再调试业务)、在远程 Lab 和硬件 CI 里是每次烧录后的自动健康门禁(见 专家 46)、在现场是远程诊断和 RMA 判据。因此架构早期就要预留 BIST 控制器、环回 mux、测试入口和状态寄存器,把“可自测”作为系统需求写进规格。一块不能自证健康的板,在规模部署后会吃掉大量本可避免的现场支持成本。
九、远程 Lab:把稀缺板卡变成可排队的共享资源
真实 FPGA 板卡昂贵、稀缺、依赖物理环境(线缆、仪表、对端设备),而团队中需要用板的人越来越多,靠“板子在谁桌上、谁占着”管理必然造成大量闲置和争抢。远程 Lab 的目标是把板卡资源化、池化:任何人或 CI 都能通过网络独占借用一块状态明确的板子、自动烧录、跑测试、收日志、释放,全程不必物理接触。
一块可远程使用的板卡需要四类设备网络化。①电源控制:智能 PDU/网络排插或板载载板的使能信号,实现远程上下电和硬复位——板卡挂死、配置控制器失联时,断电重启是最可靠的恢复手段,这是远程 Lab 的刚需而非可选。②配置/调试通道:JTAG 经 JTAG-over-Ethernet 网关或带网口的下载服务器共享;UART/USB 转串口服务器(serial console);部分平台支持远程刷新和复位。③业务 IO:以太网本就是网络可达;光口/特殊接口可能需要在板卡上架时接好环回、对端设备或程控交换矩阵(能远程把某板的光口连到另一块板或仪表)。④观测:板卡上方的网络摄像头/IP KVM 看 LED 和屏幕、网络连接的示波器/逻辑分析仪/功耗仪在需要时抓取,环境(温度箱)也可程控。
板卡池管理系统是核心软件:每块板(或每个槽位)跑一个 agent,周期性上报心跳(在线/占用/健康)、板卡型号、当前比特流版本、连接的对端资源;中央调度器维护资源清单和锁,用户或 CI 提交“需要某型号板 + 某对端拓扑”的请求,排队分配、授予带租期(lease)的独占锁——租期内别人不可用,租期到期或任务结束自动释放,防止“占而不用”和“任务挂死永久锁板”。烧录前,调度器自动获取与 commit 绑定的比特流制品、远程断电/上电、烧录、等待 BIST 通过,再把控制台和操作权限交给任务。整个借用过程脚本化:一条命令完成“借板→烧录→跑我的测试→取回所有日志→释放”。
环境与镜像的确定性决定远程测试是否可信。板卡是有物理状态的:上一个用户可能改了 Flash 内容、拨了开关、留下了未释放的对端配置。因此每次租借开始应执行标准化的“清场”流程:硬下电再上电、重烧指定比特流、跑 BIST、把可程控的开关/交换矩阵恢复到已知拓扑、清空日志;任务结束回收时同样复位。这样每个任务拿到的都是“已知良好且干净”的板,避免“前任残留”导致的诡异失败。物理拓扑(谁连谁、环回还是直连)要在资源数据库里显式建模,分配请求按拓扑匹配,不能假设线缆一直没被动过——定期用 BIST/链路发现核对物理连接。
健康管理借鉴服务器运维:为每块板维护健康档案(上电时长、BIST 历史、误码趋势、温度、失败任务率),自动下线疑似故障板(连续 BIST 失败、反复掉线),常见耗材(SD 卡/eMMC、风扇、光模块、连接器)按寿命预警;接触不良等问题在高频插拔的共享环境里特别多,线缆和连接器状态也要纳入巡检。板卡支持远程带外管理(不依赖业务 FPGA 是否活着的独立管理 MCU/BMC)能显著提升“挂死也能救”的比例,否则只能等人去现场断电。把远程 Lab 与 专家 46 的硬件 CI 接起来,板池就同时服务人和流水线:白天人借用调试,夜间 CI 批量跑回归和多板拓扑测试,利用率远高于专人专板。
十、硬件 CI 流水线:从 push 到板上绿灯
把 FPGA 开发接入持续集成,意味着每次代码提交都自动经过一条从静态质量到真实硬件的流水线验证,问题在引入当天被拦下,而不是在集成周集中爆炸。与软件 CI 相比,硬件 CI 多了耗时数十分钟到数小时的综合实现、昂贵且并发有限的板卡资源、以及物理失败的治理,需要专门设计阶段、门禁和调度。
典型流水线的阶段(每阶段失败即停并精准报告):①lint/风格/规范:秒级到分钟级,HDL lint、命名/编码规范、禁止结构检查、接口一致性。②CDC/RDC 与结构检查:跨时钟域、跨复位域、X 传播风险、综合前就可确定的结构问题(见 专家 38)。③仿真回归:单元 + 子系统 + 多 seed 随机,带覆盖率收集,分钟级反馈;可并行分片压缩墙钟时间。④综合:得到 LUT/FF/BRAM/URAM/DSP 占用、警告分类、初步时序和频率预估,资源增长与新增严重警告触发门禁。⑤实现(布局布线):完整 place&route + 静态时序分析,时序必须在目标频率收敛(多时钟域各自收敛),这是硬红线;产出比特流和报告。⑥板级阶段:向远程 Lab 调度器申请板卡(资源池可能排队,用独立的下游 stage,避免占着流水线等板),硬复位→烧录→BIST→冒烟用例(链路训练、DDR 压力、算法 golden vector、端到端性能计数)→回收日志/串口/功耗/温度→释放板卡。⑦制品归档:比特流与软件、报告、版本元数据(git hash、工具版本、IP 版本)作为不可变制品入库,供部署追溯(呼应 20 比特流烧录与四方版本一致 manifest/门禁)。
门禁分硬红线与趋势告警。硬红线:时序违例、CDC 错误、功能仿真失败、BIST 失败、资源超片——直接红灯,阻止合并。趋势/阈值告警:资源占用周环比增长超过设定比例、新增警告、覆盖率下降、综合时长异常、功耗逼近限值——不一定阻断但在 PR 上提示,防止温水煮青蛙。性能类指标(吞吐、延迟直方图、误码率)也应在板级阶段自动测量并与基线对比,显著退化即报警。每个门禁的判据必须是机器可读的数字,而非“看一眼报告”。
调度与经济性:综合实现昂贵,可设计“轻流水线每次提交都跑(lint+仿真),重流水线(综合+板测)在合并前或每日夜间全量跑”,并在结果页清楚标注每个比特流验证到了哪一层;板卡阶段是异步的——PR 提交后排队进板池,完成后把结果回写 PR 检查项。缓存能省大量时间:未变化的 IP/模块用增量综合或缓存网表、第三方 IP 固定版本预构建,但缓存要与工具版本/参数绑定,防止脏缓存。流水线配置本身(脚本、约束、容器镜像)进版本库并走 review,避免“CI 神秘脚本”无人敢改。
结果可观测与失败治理:每次运行有唯一 ID,关联 commit、作者、所有日志、波形环形缓冲、板卡序列号、环境版本;失败按类型归因(RTL/环境/板卡/flaky),有看板统计成功率、时长、队列等待、板卡健康。flaky 用例按正文的分类治理:物理类(板卡/接触)自动重试到健康板并降低该板可信度,测试类(固定 sleep、未等校准)改成状态同步,真随机类(CDC/误码)改成统计阈值测试。流水线还应强制“构建可复现”的纪律:同一 commit + 同一工具版本产出的比特流可重复,现场任何版本都能在 CI 里重新精确构建。当“时序不过不能合并、板上 BIST 不过不能发布”成为由机器执行的默认规则,FPGA 项目才获得软件团队早已习惯的集成节奏。
结果可观测与失败治理:每次运行有唯一 ID,关联 commit、作者、所有日志、波形环形缓冲、板卡序列号、环境版本;失败按类型归因(RTL/环境/板卡/flaky),有看板统计成功率、时长、队列等待、板卡健康。flaky 用例按正文的分类治理:物理类(板卡/接触)自动重试到健康板并降低该板可信度,测试类(固定 sleep、未等校准)改成状态同步,真随机类(CDC/误码)改成统计阈值测试。流水线还应强制“构建可复现”的纪律:同一 commit + 同一工具版本产出的比特流可重复,现场任何版本都能在 CI 里重新精确构建。当“时序不过不能合并、板上 BIST 不过不能发布”成为由机器执行的默认规则,FPGA 项目才获得软件团队早已习惯的集成节奏。
指标与持续改进:自动化体系本身要用数据运营——回归总时长、失败率、flaky 率、仿真覆盖率趋势、板卡平均排队时间和利用率、从提交到全绿的前置时间。这些数字告诉团队瓶颈在计算资源、板卡数量还是用例质量:若前置时间太长导致开发者绕过 CI,再严格的门禁也会失效。定期删除长期无效的用例、合并冗余配置、把最慢的高价值测试保留在夜间而把快速子集留给提交,是让体系长期被信任而不是被绕过的关键。自动化测试的终态不是“跑了很多测试”,而是“任何人在任何时刻都敢基于绿灯合并,且绿灯与现场可靠性之间有可验证的相关性”。
总结
FPGA 自动化 = 仿真金字塔承担功能回归、BIST 承担真实硬件健康、远程板池+网络电源/JTAG 把板子变成 CI 资源;时序和物理层是上板测试不可替代的理由,可重放的失败归档是硬件回归可信的底线。