芯片Bug记录跟踪Markdown模板:现象、定位、根因、回归四段式
更新时间:2026-10-29。本篇是「集成电路大类 · 芯片设计」入门层的一篇模板文。仿真里抓到一个 bug 只是开始,把它记下来、跟到底、防复发才算闭环。很多团队的 bug 单写得像聊天截图——只有一句「FIFO 满了但标志没拉高」,三个月后谁也复现不了。本文给出一份可直接复制的 Markdown 缺陷单模板,按「现象 → 定位 → 根因 → 回归」四段组织,配状态流转与优先级分级,文末以「FIFO 满标志晚一拍」为例做完整示范。
本文要回答的问题
- 一份能闭环的芯片 bug 记录至少要写清哪四段,缺了哪段会导致什么后果?
- 模板的每个槽位具体写什么、不该写什么?
- bug 单的状态怎么流转(open/analyzing/fixed/closed/regression-added),卡在哪最常见?
- 优先级怎么分级,时序类与显示类 bug 为什么不该同级?
- 拿「FIFO 满标志晚一拍」套模板,填出来长什么样?
先给整篇的骨架图:一个 bug 从被发现到永不复发要走的四个站点和五个状态。
读这张卡抓一点:回归不是可选项而是第四站。只修不入库的修复,等于给下一个项目留定时炸弹——同类缺陷在复用模块上的复发率出了名的高。模板里「用例入库」是关闭 bug 单的硬前置。
一、模板名称与使用场景
这份模板叫「RTL 缺陷单(Markdown 版)」,适用于三类场景:
- 仿真验证抓到的功能 bug:scoreboard 比对失败、断言触发,需要记录波形与复现路径。同步 FIFO Verilog 实现与回归实测 里「跑回归发现标志位异常」就是标准入口。
- 评审或 lint 发现的设计隐患:还没走到仿真但已确认是问题,先开单跟踪,避免人脑管理。
- 跨模块复用时的遗留风险:IP 搬到新项目,环境变了,老 bug 单就是现成的风险清单。
它不替代 Jira 那类正式系统,定位是跟代码仓库同生共死的轻量记录:放仓库 docs/bugs/ 目录,修 bug 的 commit 引用单号,git log 即把改动和原因对上。
二、完整可复制的模板文本
下面这段直接复制到 docs/bugs/BUG-<模块名>-<三位编号>.md 就能用,尖括号是待填槽位:
# BUG-<模块>-<编号>:<一句话标题(模块 + 异常行为 + 触发条件)>
- 状态:open # open / analyzing / fixed / closed / regression-added
- 优先级:P? # P0 致命 / P1 严重 / P2 一般 / P3 轻微
- 发现人 / 日期:<名字> / <YYYY-MM-DD>
- 责任人:<名字>
- 相关提交:发现版本 <commit> ;修复版本 <commit>
## 1. 现象
- 期望行为:<按规格书或设计意图,信号应在什么时刻取什么值>
- 实际行为:<异常值、错拍、丢数,一句话说清>
- 复现命令:<一条命令能跑出故障,如 make sim TEST=fifo_full SEQ=bad_seq>
- 环境:<仿真器及版本 / 随机种子 seed / 回归用例名>
### 波形摘录
<关键信号在故障时刻的取值,贴图或用文字表格:信号名 / 时刻 / 期望 / 实际>
### 日志摘录
<报错原文 3-10 行,含时间戳、断言名或 scoreboard 比对信息>
## 2. 定位
- 最小复现:<删减后的最小 testbench / 最小时钟数 / 触发序列>
- 二分记录:<排除了哪些模块、缩小到哪个 always 块或哪条赋值>
- 可疑代码:<文件:行号 + 代码行>
## 3. 根因
- 缺陷分类:<时序拍序错 / 边界条件漏 / 位宽不匹配 / 状态机漏分支 / 复位不完整 / 接口协议误读 / 规格书歧义>
- 根因陈述:<为什么错,不是"改了什么"而是"设计意图哪里没落实到代码">
- 影响面:<仅本用例 / 本模块所有满边界场景 / 复用本模块的其他系统>
## 4. 回归
- 修复说明:<改动文件与思路,关联修复 commit>
- 修复验证:<重跑原用例通过 + 跑相邻边界用例通过>
- 回归用例入库:新增用例 <用例名> 已加入回归清单 <清单文件路径>
- 关闭条件核对:[ ] 原用例通过 [ ] 相邻用例通过 [ ] 回归用例已入库 [ ] 单号已在修复 commit message 引用模板故意只设四个二级小节——再多就没人愿意填。下面逐槽位给填写要点。
三、槽位填写要点与注意事项
现象段是地基。 最常见的烂写法是只贴一屏日志、不写期望行为,三个月后没人知道哪行是错。「期望 vs 实际」必须成对出现,差值就是 bug 的签名。波形只贴故障时刻前后各两拍,全波形路径放「环境」槽位。
复现命令必须是一条能跑的命令,随机测试把 seed 写死——「只有 seed=42 能复现」是有价值的定位信息。
定位段的二分记录防止重复劳动:把「已排除 X,因为 Y」记下来,接手的人不用从头怀疑。
根因段是灵魂也最常被跳过。 只写「把 full 改成打一拍」是改法不是根因;根因是「设计意图要求满标志与写指针同拍更新,代码却把比较结果组合输出跨了一拍」。七类归口长期积累,团队最高频的缺陷类别就是下一份检查单的输入——bug 单由此变成组织记忆,系统讲法见 回归缺陷分诊与复盘方法。
回归段的入库是硬门槛:「修复验证」只证明今天好了,「用例入库」保证它不会悄悄回来。修复 commit message 引用单号(如 closes BUG-FIFO-003),形成反向索引。
四、状态流转与优先级分级
状态只有五个,流转规则如下:
| 状态 | 含义 | 进入条件 | 离开去向 |
|---|---|---|---|
| open | 已记录现象,未开始定位 | 发现即建单 | analyzing |
| analyzing | 正在定位根因 | 有人认领责任人 | fixed(或退回 open 补充现象) |
| fixed | 代码已改,待回归验证 | 修复 commit 合入 | closed |
| closed | 原用例与相邻用例均通过 | 回归核对四项全勾 | regression-added |
| regression-added | 防复发用例已入库,最终态 | 用例名与清单路径填齐 | (终态,不再动) |
最常见的卡点在 analyzing:现象段太差、定位无从下手,单一躺几个月。把「现象不合格不许进 analyzing」当纪律执行,卡壳率立刻下降。另一个坑是 fixed 直接关闭——没入库的修复会在复用时复发,FIFO 标志位与上溢验证要点 讨论的边界场景复发就属这类。
优先级分四级,按「对硅片行为的实际危害」定级,不按「发现时的吓人程度」:
| 级别 | 定义 | 例子 | 处置时限 |
|---|---|---|---|
| P0 | 功能错误,硅后无法绕过 | 状态机死锁、数据通路算错 | 当天,阻塞 tape-out |
| P1 | 边界条件出错,特定场景丢错数 | FIFO 满标志晚一拍、CDC 亚稳态 | 本周 |
| P2 | 性能或资源损失,功能正确 | 仲裁器饿死低优先级、多打一拍 | 下个里程碑 |
| P3 | 代码卫生与可读性 | 未用信号、命名歧义 | 随提交顺手清 |
时序拍序错、边界条件漏两类根因默认至少 P1 起步——「仿真过了不等于没问题」,危害有潜伏性。统计类异常不丢数,别随手打 P1 稀释优先级信号。
五、摘录示范:FIFO 满标志晚一拍
拿一个真实感最强的例子套模板——同步 FIFO 的 full 标志在写满后不拉高、下一拍才拉高,导致上游多写一拍、数据溢出(这类 bug 的验证视角见 FIFO 溢出导致测试平台丢数据的排查,本文只展示记录形态):
# BUG-FIFO-003:sync_fifo 满标志晚一拍,满边界多写入一拍数据
- 状态:regression-added
- 优先级:P1
- 发现人 / 日期:zhang / 2026-10-22
- 责任人:li
- 相关提交:发现版本 a41c9e2 ;修复版本 b77d30f
## 1. 现象
- 期望行为:DEPTH=16 的 FIFO 在第 16 个写使能拍,`full` 应与写指针回卷同拍拉高。
- 实际行为:`full` 在第 17 拍才拉高,第 16 拍时上游依据 full=0 又写入一拍,溢出覆盖最旧数据。
- 复现命令:make sim TEST=sync_fifo SEQ=fill_to_full
- 环境:Icarus Verilog 13.0 / seed=42 / 用例 tc_fifo_fill_full
### 波形摘录
| 信号 | 第 15 拍 | 第 16 拍(故障) | 期望 |
|------|----------|------------------|------|
| wr_en | 1 | 1 | — |
| wptr_bin | 14 | 15 | 15 |
| full | 0 | 0(实际) | 1 |
### 日志摘录
[ns=320] SCOREBOARD ERROR: expected 0x1A, got 0x09 (oldest entry overwritten)
Assertion 'no_overflow_when_full' failed at ns=340
## 2. 定位
- 最小复现:testbench 只留连续写 17 拍,10 行激励即复现。
- 二分记录:排除读侧逻辑(wr_en 恒定 1、rd_en 恒定 0 仍复现);排除格雷码转换(直接看二进制指针差异仍在);缩小到 full 生成组合块。
- 可疑代码:sync_fifo.v:47 assign full = (wptr_bin == DEPTH-1);
## 3. 根因
- 缺陷分类:边界条件漏 + 时序拍序错
- 根因陈述:设计意图是「写指针指向最后一格时即满」,但代码把 full 写成 wptr_bin==DEPTH-1 的即时比较——该比较在写入本拍结束后才成立,等效满标志晚一拍。正确写法应预判下一拍指针值。
- 影响面:本模块所有「连续写至满」场景;复用本 FIFO 的 UART 缓冲同样受影响。
## 4. 回归
- 修复说明:full 改为对下一拍指针预判 assign full = (wptr_bin_next == DEPTH-1) && wr_en 的同拍逻辑,见 b77d30f。
- 修复验证:tc_fifo_fill_full 通过;相邻用例 tc_fifo_empty、tc_fifo_almost_full 通过。
- 回归用例入库:新增 tc_fifo_fill_full_boundary 已加入 regression/list.f
- 关闭条件核对:[x] 原用例通过 [x] 相邻用例通过 [x] 回归用例已入库 [x] 单号已引用这份示范故意把「波形摘录」压成三行四列的小表——bug 单里的波形只贴关键拍,全量波形归档后在环境槽位指路径。注意根因陈述写「设计意图哪里没落实」,修复说明才写「改了什么」,两段分工不要混。
六、修改示范:适配到自己的项目
模板不是教条,三个最常见的裁剪动作:
- 加槽位:形式验证团队把「现象」加「反例(counterexample)长度」槽;混合信号团队把波形拆成数字与模拟两个槽。原则是「每个新槽位都曾被真实 bug 证明缺它会丢信息」。
- 减槽位:单人 FPGA 小项目可砍「责任人」和二分记录,但根因分类与回归入库不许砍——这两段是模板的复利所在。
- 改状态:有评审流程的团队在 fixed 与 closed 之间加 reviewing;带硅后阶段的加 silicon-verified。状态加一,流转表的进入条件就要同步补一句。
裁剪完检查:任意一个状态卡住的单,是否都能从记录里回答「差什么才能往前走」?答得上,模板就合身。
这一篇在知识体系里的位置
- 设计基础:FIFO 与仲裁器设计基础(本文示例 bug 所在的模块背景);
- 验证实操:FIFO 标志位与上溢验证要点、FIFO 溢出丢数据排查(怎么抓到这类 bug,本文讲抓到之后怎么记);
- 方法论:回归缺陷分诊与复盘方法(bug 单积累成组织记忆的下一步)。
总结
芯片 Bug 记录的核心是四段闭环:现象段写清期望与实际的差值、定位段留二分排除痕迹、根因段按七类归口陈述设计意图缺口、回归段强制用例入库;配 open→analyzing→fixed→closed→regression-added 五态流转和 P0–P3 按硅后危害分级,模板放进仓库 docs/bugs/ 与代码同生共死,bug 就从一次性事故变成可检索的组织记忆。