BugGen: A Self-Correcting Multi-Agent LLM Pipeline for Realistic RTL Bug Synthesis

其实这篇文章挺有意思的。

这篇文章提出了一个用多智能体 LLM 自动生成 RTL 真实功能 bug 的框架 BugGen。它的核心目标不是“修 bug”,而是批量制造真实、可检测、可用于验证和机器学习训练的 RTL bug 数据集,从而提升硬件验证、调试和 failure triage 的效率。

  1. 解决问题
    • 硬件验证越来越复杂,人工插入 bug 太慢、太贵,而且容易带偏见。
    • 现有自动化方法(如随机 mutation)虽然能插 bug,但很多 bug 很“假”、很浅、没语义,不像工程师真实会犯的错。
    • 而 ML-based debug / triage 又很依赖大量带标签、可触发失败的 bug 数据,所以作者想解决“如何自动生成真实 RTL bug 数据集”这个问题。
  2. 核心思路
    • 作者提出了一个叫 BugGen 的框架:一个自纠错的多智能体 LLM pipeline
    • 它拆成多个 agent 协同工作:
      • 先把大 RTL 模块切分成有功能意义的区域;
      • 再选哪个区域更适合插 bug;
      • 再选插哪一类 bug;
      • 再真正生成 mutation;
      • 最后编译、跑回归测试,看这个 bug 是否真的能触发 failure。
    • 如果失败,它会回滚并重试,所以这是一个闭环系统,而不是一次性生成。
  3. 文章亮点
    • 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,才算“功能上有效”。
  4. 实验
    • 作者在 5 个 OpenTitan IP block 上做实验,包括 AES、I2C、OTP、ROM、USB control 等。
    • 总共生成了 500 个 unique bug scenarios,一共 1000 个 mutations
    • 使用的 LLM 是 GPT-4o Mini
    • 每个 bug scenario 默认包含 2 个 mutation,这样既保证复杂度,又不至于验证太慢。
  5. 结果
    • BugGen 生成的 bug 中,94.2% 最终是功能上有效的,也就是既语法正确,又能在回归中触发失败。
    • 首次尝试成功率是 56.4%,说明很多 bug 一次就能成功,但系统也依赖自纠错和重试机制。
    • 总吞吐量达到 17.7 个有效 bug / 小时,作者说这比人工专家插 bug 快很多。
    • 它还找出了 104 个原本 OpenTitan regression 没测出来的 bug,也就是能暴露 testbench blind spots。
    • 跟工业工具 Certitude 比较时,BugGen 的语法正确率更高,还能发现更多 testbench 漏洞,bug 也更复杂、更有功能意义。
  6. 这篇文章最有价值的地方
    • 它证明了: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 的错误,比如:

  • 漏掉 ready

if (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 概括为三步:

  1. 把 module 切成一组 region
  2. 往这些 region 里迭代插 bug
  3. 验证这些 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 块可能还没结束
  • 一个 caseif-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:

  1. surface coverage:优先之前被尝试较少的 region,保证 bug 分布广
  2. success rates:优先历史上更容易生成“语法合法 + 功能可检测”bug 的 region
  3. 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 完成。

它拿到三类输入:

  1. mutation index:允许哪些 bug classes
  2. selected region 的 RTL code
  3. 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
  • 结果来自并行化运行后的完整缓存结果

作者在看:

  1. 这些 bug 质量怎么样
  2. 生成过程 是不是自动化
  3. 代价 高不高
  4. bug 分布得均不均匀
  5. 系统 会不会学习
  6. 这些 bug 对 ML debug 有没有实际帮助

A. Accuracy

这篇文章的“准确性”不是传统 classification accuracy,而是生成成功率
作者把它拆成两层:

  • functional accuracy
  • syntactic accuracy

1. Functional Accuracy

作者定义 functional accuracy 为,一个 bug scenario 同时满足:

  • unique
  • syntactically valid
  • functionally detectable

也就是说,一个 bug 只有在下面三关都过了才算成功:

  1. 不重复
  2. 代码合法能编
  3. 能在 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

作者说系统可无缝扩到大型工业设计,主要靠两点:

  1. module splitter 把大 RTL 切成可处理 region
  2. 支持 inter-designintra-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 不是“好看但没用”的样本,而是能真正训练模型。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐