体系结构论文(九十一):BugGen: A Self-Correcting Multi-Agent LLM Pipeline for Realistic RTL Bug Synthesis
BugGen: A Self-Correcting Multi-Agent LLM Pipeline for Realistic RTL Bug Synthesis
其实这篇文章挺有意思的。
这篇文章提出了一个用多智能体 LLM 自动生成 RTL 真实功能 bug 的框架 BugGen。它的核心目标不是“修 bug”,而是批量制造真实、可检测、可用于验证和机器学习训练的 RTL bug 数据集,从而提升硬件验证、调试和 failure triage 的效率。
- 解决问题
- 硬件验证越来越复杂,人工插入 bug 太慢、太贵,而且容易带偏见。
- 现有自动化方法(如随机 mutation)虽然能插 bug,但很多 bug 很“假”、很浅、没语义,不像工程师真实会犯的错。
- 而 ML-based debug / triage 又很依赖大量带标签、可触发失败的 bug 数据,所以作者想解决“如何自动生成真实 RTL bug 数据集”这个问题。
- 核心思路
- 作者提出了一个叫 BugGen 的框架:一个自纠错的多智能体 LLM pipeline。
- 它拆成多个 agent 协同工作:
- 先把大 RTL 模块切分成有功能意义的区域;
- 再选哪个区域更适合插 bug;
- 再选插哪一类 bug;
- 再真正生成 mutation;
- 最后编译、跑回归测试,看这个 bug 是否真的能触发 failure。
- 如果失败,它会回滚并重试,所以这是一个闭环系统,而不是一次性生成。
- 文章亮点
- Module Splitter:先把大模块切成逻辑区域,避免 RTL 太长超出 LLM 上下文,同时让 bug 分布更均匀。比如把 FSM、控制逻辑、接口逻辑等拆成 mutation target regions。
- Class-based Mutation Paradigm:作者不是让 LLM 随便乱改,而是预定义 bug 类型,让它按类别插 bug,例如:
- missing assignment
- logic bug
- wrong assignment
- loop modification
- FSM transition error 等。
- 共享 mutation cache:系统会记住之前尝试过什么 mutation、成没成功,从而避免重复,并逐步学会哪些区域、哪些 bug 类型更有效。
- 闭环验证:生成完 bug 以后,不只检查语法,还要真正编译并跑 regression;只有能触发测试失败的 bug,才算“功能上有效”。
- 实验
- 作者在 5 个 OpenTitan IP block 上做实验,包括 AES、I2C、OTP、ROM、USB control 等。
- 总共生成了 500 个 unique bug scenarios,一共 1000 个 mutations。
- 使用的 LLM 是 GPT-4o Mini。
- 每个 bug scenario 默认包含 2 个 mutation,这样既保证复杂度,又不至于验证太慢。
- 结果
- BugGen 生成的 bug 中,94.2% 最终是功能上有效的,也就是既语法正确,又能在回归中触发失败。
- 首次尝试成功率是 56.4%,说明很多 bug 一次就能成功,但系统也依赖自纠错和重试机制。
- 总吞吐量达到 17.7 个有效 bug / 小时,作者说这比人工专家插 bug 快很多。
- 它还找出了 104 个原本 OpenTitan regression 没测出来的 bug,也就是能暴露 testbench blind spots。
- 跟工业工具 Certitude 比较时,BugGen 的语法正确率更高,还能发现更多 testbench 漏洞,bug 也更复杂、更有功能意义。
- 这篇文章最有价值的地方
- 它证明了:LLM 不只是能写 RTL,也能“有控制地制造 RTL bug”。
- 而且它制造是更接近真实工程错误的 bug。
- 这让它有两个价值:
- 给 ML 调试/triage 提供高质量训练数据;
- 反过来检测 验证环境的盲区,看看 testbench 哪些 bug 根本抓不住。
一、INTRO
1. 硬件验证的根本问题
- 芯片规模大(billions of transistors)
- 验证占开发时间 > 50%
- regression 中 failure 很多,但难 debug
- 硬件复杂度↑ → 验证成本爆炸
- ML debugging 需要大量 bug 数据
- 但现有 bug 数据来源:
- 人工 → 慢、贵、有偏见
- 自动 mutation → 不真实
2. ML-based debugging 的依赖
- ML 可以帮助 debug
- 但前提是:需要大量 diverse + labeled bug
问题:
- legacy bug → 偏旧、分布不均
- 会导致:
- overfitting
- 泛化差
结论:必须生成新的、真实的 bug
3. 现有 bug 插入方法的问题
(1)人工
- 慢
- 覆盖有限
(2)自动 mutation(关键批判点)
- constrained-random mutation
- 结果:
- trivial(太简单)
- implausible(不真实)
本质问题:没有语义理解,只是“语法级改动”
传统方法
1. 它们怎么做
- 预定义 mutation:
- operator inversion
- control path change
- 然后:
- 插 bug
- 跑测试
- 看能不能检测到
2. 问题(重点)
- 无语义(no semantics)
- 无上下文(no context)
- 模板化(template-based)
3. 后果
- bug 太简单
- 不像工程师犯的错
-
dataset 有偏:容易检测的 bug 太多、真实复杂 bug 太少
4. 对 ML 的影响
- 训练出来的 debug 模型:
- 只会简单 case
- 不会复杂 root-cause
结论:传统 mutation = “垃圾数据生成器”
LLMs in Verification
1. LLM 的能力
- syntax fluency(语法)
- logical reasoning(逻辑)
- functional intuition(功能理解)
关键:这些能力正好就是“造真实 bug”所需要的
2. 现有工作启发
- VeriGen
- 用 LLM 生成 RTL
- 但会产生错误代码(bug)
insight:LLM 天然就会犯“像人一样的错”
- AutoCkt
- 引入 self-correction loop
insight:LLM 可以自我修正 → 形成闭环
既然 LLM 能写代码 + 会犯错 + 能自我修复
那就可以有控制地生成 bug
普通 mutation
通常是这种思路:
- 把
==改成!=- 把
+改成-- 把某个条件取反
- 删一条赋值
这类改动的特点是:
- 局部
- 机械
- 不理解上下文
- 很多时候只是“语法变了”,但不像工程师真实会犯的错
semantic mutation
它会考虑:
- 这段 RTL 的功能是什么
- 这个变量/状态/条件在设计里扮演什么角色
- 哪种改错方式更像真实设计人员在实现控制逻辑、时序逻辑、FSM、边界条件时会犯的错误
举个直观例子
假设原代码是:
if (req && ready)
grant <= 1'b1;普通 mutation 可能是
if (req || ready)
grant <= 1'b1;或者
if (req && ready)
grant <= 1'b0;semantic mutation 可能是
它先理解这段逻辑是在做 握手控制,于是产生更像真实 bug 的错误,比如:
- 漏掉
readyif (req)
grant <= 1'b1;
- 在错误的周期更新
grant- 没有在某个异常状态下清零
grant- 只在部分 FSM state 中处理
grant- 把
grant的产生条件和另一个 pipeline stage 搞混这些 bug 的共同点是:
- 和模块功能强相关
- 会影响行为
- 更接近真实工程错误
二、方法

传统 mutation 太机械,人工插 bug 太慢,所以作者需要一个方法来回答:
- 怎样让 LLM 生成真实的 RTL bug?
- 怎样保证这些 bug 不是乱改,而是语法正确、功能可检测?
- 怎样让这个过程 自动化、规模化、可持续改进?
作者对自己方法的定位
作者给了几个关键词:
- agentic:不是单模型一次性输出,而是多个专门 agent 分工协作
- self-correcting:错了会回滚重试
- learning-based:会记住历史尝试,后面更会选
- modular / design-agnostic / HDL language-agnostic:想强调它不依赖某个特定设计,也不绑定某个 HDL 语言
这说明它不是一个“prompt hack”,而是一个系统工程化 pipeline。
Overview
作者把整个 bug generation pipeline 概括为三步:
- 把 module 切成一组 region
- 往这些 region 里迭代插 bug
- 验证这些 bug 是否 unique、语法合法、功能可检测
为什么不能直接把整个 RTL 丢给 LLM
作者这里的判断很关键:
大 RTL module 不能直接让 LLM 整体处理。
原因有两个:
- context window 限制
- 会引入偏差和不稳定输出
这其实非常符合 RTL 场景:
- 一个真实 SoC 模块可能几千行
- 逻辑高度嵌套
- FSM、控制逻辑、接口逻辑、寄存器路径交织在一起
如果整块扔给 LLM,它容易:
- 看不全
- 忽略细节
- 在无关区域乱改
- 或者生成“表面合理、实际不通”的修改
Module Splitter
给 bug 生成先做“程序切片 + 功能分区”。
作者提出一个核心中间表示:
Mutation Target Regions, MTRs
它表示:
- 一个 module 中,逻辑上相对独立
- 功能上有意义
- 适合注入 bug 的局部区域
论文举的例子包括:
- finite state machine
- control logic
- memory-mapped interfaces
也就是说,MTR 不是随便按“每 50 行切一块”,而是按功能语义切。
为什么 MTR 很重要
(1)解决上下文窗口问题
模块太大,LLM吃不下;切成 region 后,每次只看一块。
(2)提高 bug 的功能相关性
如果 region 本身就是 FSM 或控制逻辑,那在里面插 bug,更可能影响架构级行为,而不是只改到无关紧要的辅助逻辑。
(3)让 bug 分布更均匀
如果不切分,LLM 往往会总盯着少数明显区域动手。
切成 MTR 后,系统可以有意识地在不同 region 之间分配 bug。
作者说系统支持两种模式:
- 工程师显式指定 MTR
- 如果没指定,就用 module splitter agent 自动切分
自动切分是怎么做的
(1)输入是什么
module splitter 拿到的是:
- RTL code
- 一组 general guidelines,用来帮助它定义 region 时不要把逻辑依赖拆坏
(2)小模块:一次切完
如果模块本身足够小,能放进上下文窗口,splitter 就直接一次处理整个 module,输出完整 regions。
(3)大模块:迭代式切分
如果模块很大,就采用 iterative, context-aware approach。
这是一个很有意思的设计:
- 每次给 agent 一个固定大小的 chunk
- 再额外给下一块的 5 行辅助行(auxiliary lines)
- 让 agent 判断当前 chunk 末尾的 region 是不是“还没结束”
这里的思想很像:
- 编译器处理跨块结构时要看 lookahead
- 文本分段时要避免把一个完整语义结构砍成两半
(4)为什么要看“后面 5 行”
因为 Verilog/SystemVerilog 的逻辑块可能跨 chunk 边界:
- 一个
always块可能还没结束 - 一个
case或if-else链可能没闭合 - 一个表达式或语句组可能在下个 chunk 才完整
所以系统要判断:
当前最后一个 region 是真的完整,还是只是“看起来像结束,实际还依赖下一块”?
如果检测到依赖,就不把最后一块 region 输出,而是留到下一轮连着处理;否则就正常保留。
region synopsis
对于每个 region,splitter 还要生成一个简短说明,作者叫它:
region synopsis
这个 synopsis 的作用非常大,因为后面的 region selector 并不总是直接看整块代码,它会利用这些 synopsis 来理解:
- 这个 region 是做什么的
- 它的功能角色是什么
- 适不适合某类 bug
所以 splitter 的输出不是只有“region 边界”,而是一个带注释的功能划分结果。
Module Splitter 本质上在做三件事:
- 把超大 RTL 变成 LLM 可处理的粒度
- 按功能而不是按文本长度切块
- 为后续 bug 选择阶段提供“语义索引”
作者如何定义“什么叫一个 bug”
1. mutation 的定义
作者说:
- 一个 mutation 是对一行或多行连续 Verilog 代码做的、语法合法的修改
- 例如:
- 改条件
- 改 loop 行为
- 改 FSM transition 等
这里有两个点要抓住:
第一,它强调 syntactically valid
也就是 mutation 至少先要像“可编译代码”,不是瞎改。
第二,它允许 one or more consecutive lines
说明它不是只做单 token/operator 替换,而可以是更大粒度的局部代码重写。
2. bug scenario 的定义
作者又引入了比 mutation 更高一层的概念:
bug scenario
它指的是:
- 在同一个 module 里
- 同时插入多个功能相关的 mutations
- 把它们作为一个整体来评估
这很关键。因为现实中的 bug 很多不是单行错,而是:
- 某处条件漏了
- 另一处配套状态更新也错了
- 两个地方合起来才形成完整的功能偏差
如果只允许单点 mutation,生成出来的 bug 往往太“玩具化”。
3. 为什么需要“class-based”
作者认为 LLM 有两个天然问题:
- stochasticity:随机性
- knowledge deficits:知识缺口
所以不能完全放任它自由发挥。
需要在 自动化 和 控制性 之间找平衡,于是提出:
multi-step, agentic, class-based mutation paradigm
这里“class-based”的意思是:
先预定义若干 bug class,让生成过程受控地在这些类别中选,而不是无约束生成。
4. Mutation Index:bug 类别字典
作者设计了一个 mutation index,里面列出所有可用的 mutation class,以及每个 class 的简短功能描述。
注意这不是详细代码模板,而是高层功能描述:
- 这个 mutation 类别想模拟什么错
- 期望改变什么功能行为
作者还说:
- baseline index 可以扩展
- 后续可以加更复杂的 mutation types,不用大改系统
5. Mutation Specification:类别背后的详细说明
每个 mutation class 都配一个由 verification engineer 编写的 mutation specification,里面会详细说明它的功能意图,并给出语法示例。
也就是说:
- index 是“类目表”
- specification 是“具体插 bug 的设计说明书”
这让系统具备:
- 人可以定义 bug 风格
- LLM 负责具体实例化
- 但不会完全脱离验证工程师的需求
6. Shared Mutation Cache
作者还维护一个 shared mutation cache,记录之前所有尝试过的 mutation 及其评估结果。
这个 cache 的作用包括:
- 避免重复 mutation
- 优先沿用成功率更高的策略
- 随着运行积累形成动态 rulebook
这一节其实是在建立一个受控的 bug 语义空间:
- 不是随机改代码
- 不是自由生成 bug
- 而是在“预定义类别 + 工程师规范 + 历史反馈”约束下生成
Mutation Pipeline
这一部分是操作层面最核心的内容。
作者说完整 pipeline 包含三个 LLM agent 驱动步骤,再加后续评估。
图里也画得很清楚:
先 Choose Region,再 Choose Mutation,最后 Inject Mutation,然后 Insert and Test。
Step 1: Select Region(选在哪插)
由 region selector agent 完成。
作者说它根据三个原则选 region:
- surface coverage:优先之前被尝试较少的 region,保证 bug 分布广
- success rates:优先历史上更容易生成“语法合法 + 功能可检测”bug 的 region
- uniqueness:优先更可能产生不同于已有 bug 的区域,提高数据集多样性
这三个目标其实互相牵制:
- 只看 success,会总盯着容易成功的 region
- 只看 coverage,会去一些很难插出有效 bug 的地方
- 只看 uniqueness,又可能产出太离谱的改法
region selector 的输入
作者给了三类输入:
(1)Module partition
包括:
- 所有 region 的 synopsis
- 每个 region 已经插过多少 mutation
agent 要利用这些信息去找: - 既能触发有趣 end-behavior
- 又覆盖更广区域的地方
(2)Mutation attempt history
包括:
- 各 region 的整体成功率
- 各类 mutation 在每个 region 的分布。agent 要避免总去那些经常产出 undetectable bug 的 region。
(3)Mutation index
结合 history,优先去那些欠覆盖的 mutation classes 更可能奏效的 region。
输出是什么
region selector 不只是输出一个 region,还会输出:
- rationale(为什么选它)
- proposed mutation class(建议的 bug 类别)
作者特别说明,后者不会被强制直接使用,但它有助于后续 deliberate reasoning。
这很像一个 agent 先做高层规划,再交给下游 agent 细化。
Step 2: Select Mutation(选插什么 bug)
由 mutation selector agent 完成。
它拿到三类输入:
- mutation index:允许哪些 bug classes
- selected region 的 RTL code
- region-specific mutation history:该 region 过去每次尝试成功还是失败
它要输出两个关键决策:
- 选哪个 mutation class
- 选哪个 target block / target line(s) 去插入
对于单行 mutation:
- 选 1 行
对于多行 mutation:
- 可以选 1 到 4 行范围
此外还会生成一个 tentative insertion plan,帮助后续注入 agent 进行更细化执行。
这一步是在做:
“region 内的局部策略选择”Step 1 决定“在哪个功能区域搞事”,
Step 2 决定“在这个区域里用哪种 bug、动哪几行”。
Step 3: Inject Mutation(真正改代码)
由 mutation injector agent 完成。
pipeline 会把以下信息给 injector:
- 根据所选 mutation class 提取出的详细 mutation specification
- 被选中的 target block
- full RTL code of the region,让它能结合周围上下文改写
注意:它不是只拿目标行,而是拿整个 region 的代码。这是为了避免出现“改了这行但和上下文不协调”的问题。
injector 生成:
- mutated block
- mutation summary:解释这个 bug 的功能意图是什么
然后这个 mutated block 会被插回原设计中。
为什么还要 summary
因为系统不仅想生成 bug,还想:
- 记录这次到底改了什么
- 后续进入 history / cache
- 为未来 agent 提供可解释经验
这使 cache 更像“带语义说明的 bug 日志”。
Step 4: Evaluate(评估是否成功)
这一步不是单个 agent,而是整个系统的 validator 部分。
作者说:
Step 1–3 会按每个 bug scenario 所需 mutation 数反复执行。
也就是说,如果你设定一个 scenario 要 2 个 related mutations:
- 选一次 region + mutation + inject
- 再来一次
- 最后把两处改动作为一个整体评估
先做 uniqueness 检查
每次 mutation 完成后,先和 shared mutation cache 比较,看是不是重复。
如果冗余,就回到 Step 1 重来。
这保证:
- 数据集不会灌满近似重复样本
- 每个生成结果都尽量新
再做 compilation 检查
接着编译设计:
- 编译失败 → 至少有一个 mutation 在语法或结构上不合法
- 对应 mutation entry 标为 failed attempt
这一步对应“syntactic correctness”。
编译通过后,再跑 simulation / regression
如果 compilation 成功,就进入 simulator 做 functional evaluation。
作者说明他们使用的是:
- OpenTitan 现有 test suite
- 并通过不同 random seeds 重跑,以扩大输入覆盖
怎么判定成功
如果插入的 bug scenario:
- 编译成功
- 并且触发至少一个 test case failure
则认为这次 mutation 成功,因为它造成了真实偏离预期行为。
否则标为失败:
- 要么没编过
- 要么编过了但根本没触发可检测 bug
不管成功失败,都会写入共享历史
作者特别强调:
无论结果如何,所有尝试都会被加入 design-agnostic shared mutation cache。
这很重要,因为它不是只从成功样本学习,失败样本同样有信息价值:
- 哪些 region 经常无效
- 哪类 mutation 容易编译失败
- 哪些组合更可能被 testbench 检出
Step 5: Repeat / Rollback(失败就回滚重来)
如果评估成功,就带着更新后的 history 进入下一个 bug scenario。
如果不成功,就把本轮 mutation rollback,然后重试当前 bug scenario。
从系统设计角度看,这个方法实际上分成四层。
第一层:表示层
用 MTR + region synopsis + mutation classes 来表示问题。
作用:
把原始 RTL 组织成更适合 reasoning 的结构化对象
第二层:决策层
两个 selector agent:
region selector:做全局选择
mutation selector:做局部策略选择
作用:
降低端到端生成难度
把复杂决策拆成可解释的子决策
第三层:执行层
mutation injector 真正改 RTL。
作用:
将“bug 类别 + target block + context”实例化成具体代码改动
第四层:闭环控制层
validator + cache + rollback
作用:
语法验证
功能验证
去重
历史积累
失败回滚
它不是直接“生成 bug”,而是“搜索 bug”
整个 pipeline 更像一个受约束搜索过程:
- 搜索空间:region × mutation class × target block × local rewrite
- 约束:
- 不重复
- 能编译
- 能被 regression 检测
- 反馈:
- 历史成功率
- 分布均衡
- 多样性
所以从算法味道上看,它不是简单 generation,更接近:
heuristic-guided, feedback-driven search over bug space它把“真实 bug”拆成了两个标准
作者心中的“好 bug”至少满足两个维度:
- syntactically valid
- functionally detectable
这和普通代码生成不一样。
这里不是“生成正确代码”,而是“生成会稳定制造错误行为的合法代码”。
三、评估
实验基于:
- 5 个 OpenTitan 设计
- 500 个 unique、detectable 的 bug scenarios
- 总共 1000 个 mutations
- 结果来自并行化运行后的完整缓存结果
作者在看:
- 这些 bug 质量怎么样
- 生成过程 是不是自动化
- 代价 高不高
- bug 分布得均不均匀
- 系统 会不会学习
- 这些 bug 对 ML debug 有没有实际帮助
A. Accuracy
这篇文章的“准确性”不是传统 classification accuracy,而是生成成功率。
作者把它拆成两层:
- functional accuracy
- syntactic accuracy
1. Functional Accuracy
作者定义 functional accuracy 为,一个 bug scenario 同时满足:
- unique
- syntactically valid
- functionally detectable
也就是说,一个 bug 只有在下面三关都过了才算成功:
- 不重复
- 代码合法能编
- 能在 regression 里触发 failure

Across all 5 designs:
- overall functional accuracy = 94.2%
- 最多允许 two retries
- first-attempt functional accuracy = 56.4%
94.2% 表示
- 在允许最多两次重试后
- 几乎所有最终生成的 bug scenario 都能通过语法验证和功能验证
56.4%说明:
- 超过一半的 bug scenario 第一次就成功
- 不需要 rollback / revision
Figure 2 给的是不同 mutation type 上,首次/第二次/第三次成功的堆叠结果。
它想说明的不是某一种 bug class 最强,而是:
- 多数类型下都能保持较高最终成功率
- 首次成功占比已经不低
- 后续 retry 主要在补齐少数第一次失败的 case
Syntactic Accuracy
作者说,在某些应用场景中,functionally undetected bug 不再算失败,而是 testbench blind spot 的信号。
所以这时只看:
- 这个 bug 是否 syntactically valid
如果目标是:
- 压测 verification suite
- 挖 testbench 漏洞
那一个“编得过,但没测出来”的 bug 也很有价值。
Table II 显示 first-attempt mutation 的总体:
- syntactic accuracy ≈ 64%
同时:104 个 mutation 是“语法有效但没被 OpenTitan regression 检出来”,约占所有插入 bug 的 10%。
(1)Detected表示:bug 编译通过并且被 regression 检出来了
(2)Syntax Failure表示:这次 mutation 语法/结构不合法/编译阶段就挂了
(3)Undetected表示:bug 是合法的但 regression 没发现
这在传统“只看成功率”的思路里会被算失败,但作者把它解释为:verification blind spots
尤其 AES Cipher Control 有 72 个 undetected,明显高于其他设计,说明这个设计的测试基础设施在某些区域可能覆盖不足。
跟 Certitude 对比说明了什么
作者又在一个 MESI comparison design 上,把 BugGen 跟 Synopsys Certitude 比。

- BugGen 产生 36 个 undetected bugs
- Certitude 只有 2 个
- BugGen 还有 超过两倍的 syntactic accuracy
Table III 中,两个值分别是:
- 第一值:BugGen
- 第二值:Certitude
作者的解读是:
- 如果一个 bug 合法、真实、但 testbench 抓不住
- 那它更能说明 blind spot 被暴露了
所以:
- Certitude 更多是在制造“容易被测出来的模板化 bug”
- BugGen 更容易生成“真实但不显眼”的 bug
B. Autonomy
作者这里的论证相对直接。
结论是:
- pipeline 一旦启动
- 不需要人工介入
- module partitioning、mutation insertion、evaluation、caching、rollback 全部自动完成
换句话说
- engineer 不需要逐条看代码挑 region
- 不需要手动改 bug
- 不需要手动判定失败
- 不需要手动回滚
C. Efficiency
这部分作者把耗时拆得很细。把:
- LLM 生成时间
- syntax correction 时间
- simulation / validation 时间
分开看。

1. 原始吞吐表现
作者说:
- bug generation(LLM portion)约 16 秒 / bug scenario
- validation(simulation and detection)平均 6.4 分钟 / bug scenario
这说明一个很关键的事实:
真正的瓶颈不是 LLM,而是仿真验证。
这点和硬件验证的常识非常一致:
- 文本生成很快
- compile 也还行
- 真正贵的是 simulation regression
2. Correctable overhead
为了剥离“系统自身的额外开销”,作者又定义了两个时间:
- first-attempt generation time = 10.3 秒
- average syntax correction time = 26.7 秒
这里:
- first-attempt generation:第一次生成初始 mutation 的时间
- syntax correction:编译失败后 rollback + regenerate 的额外时间
作者的结论是:
除去 simulation 时间,correctable overhead 相对较低。
3. 每个设计的速度

这张表最关键是最后一行
作者强调的主指标是:
- 17.72 unique, detectable, meaningful bug scenarios / hour
这表示在并行运行条件下,整体吞吐远高于人工验证工程师。
这个系统本质上是非常适合并行的:
- 不同 design 可以并行
- 同一 design 的不同 module 理论上也可并行
- 限制主要来自 simulation resource,而不是 agent 本身
所以作者想传达的是:
这是一个天然适合大规模部署的 bug factory。
D. Coverage
作者把 coverage 分成两部分:
- uniqueness
- spread
1. Uniqueness:不重复
这个比较直观。
系统通过 mutation cache 自动比较,保证没有重复 mutation。
所以 uniqueness 是系统设计直接保证的。
2. Spread:分布是不是均匀
Spread 指:
- bug 是否均匀分布在设计中功能上有意义的区域
作者用人工标注的 MTR 来做评估,但注意:
- 实验时 pipeline 并没有使用这些 engineer-provided MTR
- 它只用了自己的 module splitter
- 人工 MTR 只是拿来做“独立评测标准”
这点非常重要,因为它表明:
不是“先给答案再评分”,而是拿独立人工划分标准来检验系统切分和投放是不是合理。
3. Spread score 怎么算
作者先定义每个 MTR 的相对密度:

然后归一化成概率分布
,
再算归一化熵:

得到一个 0 到 1 的分数:
- 0:全部集中到一个 MTR
- 1:在所有 MTR 上完美均匀分布
两个核心结论:
(1)95.87% mutations 落在人工认为有功能意义的 MTR 内
这说明系统很少把 bug 浪费在无意义代码区域。
(2)spread score 平均 0.726
说明虽然不是“理想均匀”,但已经有不错的分布均衡性,不是只盯某几个 obvious region 下手。
在 MESI 模块上:
- BugGen 在 spread 和 MTR targeting 上都优于 Certitude
- 平均:
- Spread Score: 0.8146 vs 0.7085
- Mutations in MTRs: 94.42% vs 40.52%
这很有说服力,因为它说明:
- BugGen 更会往“有功能意义”的位置插 bug
- Certitude 更像在到处做模板化语法扰动
E. Adaptability
这部分是作者想突出“learning-based”属性。
他们说系统可以通过 shared mutation cache 从过去尝试中学习,并对陌生设计动态适应。
1. 这个学习不是再训练模型
注意这不是 finetune,也不是 online SGD。
它的“学习”是:
- 基于 in-context learning
- 基于 shared mutation cache
- 在同一次运行过程中逐步积累经验
也就是说:
- 哪些 region 容易成功
- 哪些 mutation 类在某类模块上更靠谱
- 哪些尝试常失败
这些经验会反过来影响后续选择。
Figure 4 展示 first-time validation accuracy over time。
作者说它呈现总体上升趋势,说明随着 cache 增长,系统会逐渐减少失败并更好泛化到不同设计。
它不是 static pipeline,而是能靠运行经验不断改善。
这对陌生设计尤其关键,因为实验开始时:
- mutation cache 是空的
- 没有人工提供 MTR
- 系统对设计是“stranger”状态
所以如果后面 accuracy 还能上升,就说明系统有真实适应性。
F. Scalability / Extensibility
截图里正文标题写到 F 和 G;前面总述用 extensibility 这个词。作者这里实际想表达两层:
- scalability:能不能扩到更大设计、更多并行
- extensibility / downstream utility:能不能扩展到别的任务上
1. Scalability
作者说系统可无缝扩到大型工业设计,主要靠两点:
- module splitter 把大 RTL 切成可处理 region
- 支持 inter-design 和 intra-design parallelism
本质上:
- 大设计的问题通过 region abstraction 解决
- 大规模吞吐通过并行解决
所以它的扩展瓶颈更多是:
- 仿真资源
- 可并行设计/模块数量
而不是 agent 生成能力本身。
2. Downstream Evaluation with ML-based Triage
作者用生成出来的 bug scenarios 去训练一套 ML-based triage 模型。
训练数据是:
- bug scenario 对应的 labeled failure waveform data
- 4 个 OpenTitan 设计
- 每个设计大约 80–120 unique bugs
Table VII:训练出来的 triage 准确率

这不是在证明 triage 模型本身多厉害,而是在反向证明:
- BugGen 生成的数据 足够真实
- 标签 足够有用
- 能支撑下游 ML debug / failure classification 任务
这些 bug 不是“好看但没用”的样本,而是能真正训练模型。
更多推荐







所有评论(0)