这篇文章研究的是:

能不能用一个 agent,把硬件模块级 functional verification 从头到尾自动做下来。

作者提出的系统叫 `UCAgent`。它想解决的不是 assertion generation、coverage closure、testbench generation 这些单独子任务,而是:

从规格理解、环境搭建、coverage 建模、testcase 生成、执行与分析,一路串起来做 end-to-end verification。

为此,作者提出了三个核心机制:

1. 用纯 Python verification environment 替代让 LLM 去写大量 SystemVerilog/UVM。
2. 用一个 31-stage 的细粒度工作流,把复杂 verification 拆成很多可检查的小步骤。
3. 用 `VCLM`(Verification Consistency Labeling Mechanism)维持 specification、coverage model、testcase 三者之间的一致性和可追踪性。

这篇文章的主张很明确:

1. LLM 不是完全不能做 verification。
2. 但如果直接让它一把生成 SV/UVM 验证环境,稳定性会很差。
3. 需要通过语言迁移、工作流拆解、checker 约束和一致性标签,把问题改造成 LLM 更容易做的形式。

一. Introduction 

为什么功能验证这么难

Introduction 一开始先重新定义 functional verification:它的本质是确认硬件实现是否正确满足设计规格。作者强调,随着硬件设计复杂度指数增长,验证已经变成时间、人工和可靠性上的“瓶颈”。

这里有几个信息点:

  • 验证现在消耗了很大比例的项目周期;
  • 验证工程师的需求远高于设计工程师;
  • 连设计人员自己也要花很多时间协助验证;
  • 即便投入很多人力,first-silicon success 仍不高,逻辑/功能错误依然是重 spin 的主要来源。

这段的逻辑是:
投入很大 → 但结果仍不理想 → 所以需要新的自动化范式。

传统方法为什么“不够用了”

作者接着说,行业长期依赖的还是:

  • constrained random verification
  • formal verification
  • hardware emulation

但这些方法本质上只是“维持平衡”,没有真正缩小“设计复杂度增长”和“验证能力增长”之间的差距。

这里不是说传统方法没用,而是说:

  • 它们仍然重要;
  • 但靠它们单打独斗,已经越来越难覆盖现代设计的复杂性;
  • 所以大家自然会开始关注 AI / LLM 驱动的验证自动化。

现有 LLM 验证研究

工业界和学术界都在做,但 mostly 只做局部

作者指出,Synopsys、Cadence、Siemens 等 EDA 厂商都在把 AI 引入验证流程,典型方向包括:

  • assertion generation
  • coverage closure
  • debug

学术界也在做:

  • assertion generation
  • automated testbench generation
  • coverage improvement

但作者认为,这些工作多数都只是优化验证流程中的一个局部阶段,而不是把整个验证过程自动串起来。
也就是说,人还是那个 orchestration 的核心,并没有真正实现“end-to-end autonomous verification”。

现有端到端尝试,被分成两大类

作者把已有的 LLM 自动验证工作分成两类:

第一类:SystemVerilog / UVM-based

这些方法的共同点是:仍然围绕传统验证语言和验证框架做自动化,比如自动生成 UVM testbench、分多 agent 做规格解析、测试规划、代码生成等。

第二类:Python-based

它采用纯 Python 生成策略,尝试实现 end-to-end RTL 自动验证。

作者这样分类,其实是在给自己的工作铺垫:
UCAgent 明显站在 Python-based 这一侧,但又想比 PRO-V 做得更完整。


 三个核心挑战

一个真正的端到端自动验证系统到底会死在哪些地方。

Challenge 1:LLM 生成 Verilog/SystemVerilog 验证代码不够可靠

作者的判断是:
LLM 在 Python 上通常表现不错,但在 Verilog/SystemVerilog 上明显更差。原因有两层。

第一层:训练数据太少

作者引用 The Stack v2 的数据说,Python 数据量极大,而 Verilog 和 SystemVerilog 的数据量小得多。于是模型对 HDL 的掌握天然更弱。

第二层:语言本身难

即使不考虑数据量,SystemVerilog 验证代码本身也更难:

  • 语法复杂;
  • 时序和并发语义强;
  • 容易出现语法正确但语义不一致的问题。

所以作者的一个重要判断是:
如果让 LLM 大量直接生成 SV/UVM 验证代码,那么系统稳定性天花板会很低。

这就是为什么他们后面改用 Python。


Challenge 2:复杂端到端验证流程很难靠 LLM 稳定完成

作者认为,功能验证不是一次性生成一个文件,而是一个很长的流程,要处理:

  • 规格文档
  • 设计代码
  • 验证代码
  • 仿真日志
  • 测试报告

这些信息量非常大,很容易超出 LLM 的有效处理能力。于是会出现:

  • hallucination
  • context rot
  • instruction following 变弱

作者又把这个挑战拆成两个更具体的问题。

(1)信息丢失和错误累积

验证阶段之间是强依赖的。
如果前面规格分析少理解了一条约束,或者 coverage model 有一个命名错了,后面的 testcase、coverage 报告、bug 分析都会被带偏。

所以作者的观点是:
必须在每个阶段结束后进行自动检查,而不能等到最后统一发现问题。

(2)简单 workflow 无法适应不同模块

有些模块简单,比如 FIFO、算术单元,LLM 直接生成输入输出检查也许还行。
但有些模块交互复杂,比如 bus crossbar,需要 mock、复杂依赖、严格时序和接口约束。这个时候,如果 workflow 太粗糙,就会生成接口不匹配、行为错误的验证实现。

这里的重点是:
验证流程不能只有一个统一粗模板,而要能根据 DUT 复杂性配置。


Challenge 3:整个验证闭环里最难的是“一致性”

这是这篇文章最有辨识度的点。

作者认为,一个健壮的功能验证流程,必须在以下三个东西之间建立严格 traceability:

  • functional specification
  • coverage model
  • testcase implementation

换句话说:

  • 规格里提取出来的每个功能点;
  • 覆盖模型里的 covergroup / coverpoint;
  • 测试里真正执行到的检查点;

三者必须是一一对应、可追踪的。

作者把这种“验证目标、实现方式和最终结果之间的语义闭环”定义为 Verification Consistency

这是非常重要的一个概念。因为很多自动化工作虽然生成了测试,也跑出了覆盖率,但你很难证明:

  • 这个 coverage 到底是不是对应原始 spec;
  • 有没有凭空 hallucinate 出不存在的功能点;
  • 有没有 spec 里的重要 feature 没被真正覆盖到。

Figure 1 是整段引言里最关键的例子。它直观地说明了“一致性断裂”是怎么发生的。

图里的原始规格

左边 UART Spec 中说的是:

  • bit0: Data Ready
  • bit1: Overrun Error
  • bit2: Parity Error
  • bit3: Framing Error
  • 没有 Underrun Error

中间的 feature list

LLM 在中间把这个功能总结成:

  • UART Receiver Error Detection
  • Overrun Error
  • Parity Error
  • Framing Error

到这一步看起来还没太大问题。

右边 coverage model 出问题了

到了 coverage model 阶段,LLM 把:

  • overrun 改成了 overflow
  • 又额外加了一个 underrun

这就出现了两种典型错误:

  1. Naming inconsistency
    原始规格里的术语被偷偷替换了,虽然看上去意思接近,但已经不再严格一致。
  2. Hallucination
    LLM 凭空加了规格里根本没有的场景。

作者借这个例子说明:
如果没有专门的机制去维护一致性,那么最后 coverage model 虽然“像那么回事”,但它和真实设计意图已经脱节了,验证结果也就不再可信。


现有方法的不足

在引言后半部分,作者对几个代表性方法做了一个对比性批评:

  • PRO-V:没有 functional coverage model,因此没法建立“spec → coverage”的完整 traceability;
  • UVM²:主要依赖 prompt 限制,没有显式机制确保跨阶段输出严格一致;
  • MAVF:虽然建立了 test point 和 testcase 的 cross-reference matrix,但没有覆盖整个端到端流程的一致性机制。

这段的潜台词是:
现有工作也许能做自动生成,但还不能真正构成完整、闭环、可验证的自动验证系统


UCAgent 在引言里提出的三大对应解法

在 Figure 1 之后,作者正式提出 UCAgent 的解决思路。

改语言载体——把验证实现转到 Python

作者用 Picker 把 DUT 转成 Python 包 PyDUT,再用 Toffee 引导 LLM 在 Python 中搭建 testbench 和 testcase。

本质逻辑是:

  • HDL 验证代码难生成;
  • Python 更符合 LLM 的能力边界;
  • 所以不要硬让 LLM 在自己不擅长的地方作战。

这不是简单的“换个语言写代码”,而是重新设计 LLM 参与验证的接口层

改流程组织——31-stage 细粒度 workflow

作者把验证流程拆成 31 个细阶段,每一阶段都要经过 checker 校验。这样可以:

  • 降低单步任务复杂度;
  • 阻止错误跨阶段扩散;
  • 让系统在失败时可以局部修复,而不是整条链重来。

这一点非常像把“大任务 agent”改造成“可验证的阶段化 pipeline”。

改一致性维护方式——VCLM

VCLM 通过层级标签,让 spec、coverage、testcase 三者共享同一套显式标识。这样:

  • 每个功能组
  • 每个功能点
  • 每个检查点

都可以跨阶段被 checker 自动追踪。

也就是说,作者不再只依赖 prompt 说“请保持一致”,而是把一致性变成machine-checkable constraint

二、方法

(Figure 2)其实是整篇文章最核心的总览图之一。它想说明:
UCAgent 不是单靠一个 LLM 在自由发挥,而是由三个机制共同约束和支撑。

图里可以拆成四个层次来看。

输入层:Spec 和 DUT

左边的 Task Inputs 是:

  • Spec
  • DUT

也就是说,这个系统的起点不是“让模型凭空想”,而是让它基于:

  • 设计规格文档
  • 被测硬件模块

来完成验证任务。

中间核心:LLM

中间是 LLM,它负责贯穿多个阶段地产生工件,包括:

  • verify components
  • coverage model
  • test cases

但这里的 LLM 并不是裸奔的,它上下左右都被机制包住了。

下方机制一:Python Verification Environment

LLM 的输出不是 UVM/SV testbench,而是进入 Python Verification Environment
也就是:

  • DUT 经 Picker 变成 PyDUT
  • LLM 基于 Toffee 和 Python 抽象构建验证组件、覆盖模型和测试。

这相当于给 LLM 换了一套“更适合它工作的操作系统”。

上方机制二 + 右侧机制三

上方是 Verification Workflow,表示 LLM 不会一次性把所有东西生成完,而是按阶段推进:

  1. Analyse Spec
  2. Insert Mock
  3. Build Coverage Model
  4. Build TestCases

这些阶段结果都会被 Checkers 检查,如果失败,会形成 Error Feedback 回到 LLM,让它修正。

右下角是 Artifacts + VCLM,表示 feature list、coverage model、test cases 这些工件之间不能各写各的,而要通过 FG / FC / CK 标签建立一致性。checker 还会进一步做 label checking。


2.1 Python Verification Environment 


为什么不让 LLM 直接写 SystemVerilog,而要让它生成 Python?

2.1.1 作者的根本判断:HDL 是 LLM 的短板

作者一上来就明确说,之所以建立纯 Python 验证环境,是为了绕开 hardware description language 数据稀缺 这个瓶颈。
他们认为当前 LLM 驱动验证的主要限制之一,就是 LLM 不能稳定地产生高质量 SystemVerilog 验证代码

这背后的逻辑是:

  • SV 在工业里当然是标准;
  • 但 LLM 在 SV 上学得不够好;
  • Python 才是 LLM 更擅长的语言。

注意这里作者不是在说“Python 更专业”,而是在说:
如果目标是让 LLM 稳定完成自动验证,那么应该把工作语言设计成更符合模型能力边界的形式。


2.1.2 Picker 和 Toffee 各干什么

作者提到两个关键工具:

  • Picker:把 Verilog/SystemVerilog 的 DUT 转成 Python package,也就是 PyDUT
  • Toffee:基于 Picker 之上,提供更高层的 Python 验证抽象。

你可以这样理解:

  • Picker 负责“把 RTL 暴露成 Python 可操作对象”
  • Toffee 负责“把 testbench 编写提升到更高层”

所以这个体系不是让 Python 取代仿真器,而是让 Python 成为控制、驱动、检查 RTL 的上层接口语言


2.1.3 解决了什么问题

作者特别强调,这种基础设施会把很多低层硬件交互细节抽象掉,比如:

  • 时钟控制
  • 仿真调度细节
  • delta-cycle 等时序细节依赖

这带来的直接收益是:

  1. LLM 不用直接处理太底层的硬件验证细节
  2. testbench/testcase 更容易生成
  3. 更适合通过少量 in-context learning 驱动硬件

这一步其实非常关键。因为如果让 LLM 直接面对完整的 SV/UVM 语义和事件调度,任务难度会陡增。
作者这里本质上是在做一层 verification abstraction layer


2.1.4 这一小节最后一句很重要

作者最后说,LLM 通过 Toffee 与 PyDUT 交互来构建 testbench 和 testcase,而整个执行过程又受到:

  • fine-grained workflow
  • stage-specific checkers
  • VCLM

三者共同约束,从而保证:

  • syntactic correctness
  • 与设计规格的严格对齐。

这说明 Python 环境本身不是完整解决方案,只是三大机制中的第一块地基。


2.2 The Verification Workflow

完整工作流图。它把整个验证过程拆成四大块:

  1. Requirement Analysis
  2. Verification Infrastructure Construction
  3. Coverage and Verification Interface Construction
  4. Testcase Development and Execution

虚线框表示有些阶段默认可跳过。作者强调这是一个可配置 workflow,不是僵硬固定模板。


Requirement Analysis

这一列主要在做“理解任务”的工作,包含:

  • Requirement Analysis and Planning
  • DUT Function Understanding
  • Functional Specification Analysis
  • DUT Function Grouping
  • Function Point Definition
  • Check Point Design

这一步的本质不是写代码,而是把规格转成结构化验证目标。
也就是回答:

  • DUT 有哪些功能块?
  • 每个功能块有哪些功能点?
  • 每个功能点需要哪些检查点?

你可以把它理解成:
把自然语言规格,转成后续 coverage 和 testcase 可以消费的验证语义骨架。

这也是后面 VCLM 的起点。


Verification Infrastructure Construction

这一列是最“验证工程化”的部分,主要是把测试环境真正搭出来,包括:

这部分意思很明确:

先把 DUT 包起来

不是直接拿 RTL 裸跑,而是先包装成可操作的 wrapper / fixture / bundle 接口。

 必要时引入 mock

如果 DUT 依赖外部组件,或者交互太复杂,单纯对 DUT 本身施激励不够,那就要生成 mock。
这正是作者前面引言里说的:复杂模块需要更复杂的环境建模,不能套一个简单模板。

先验证环境本身

环境不是搭完就默认对,还要做:

  • mock functional test
  • basic fixture evaluation
  • 必要时 human check

这说明作者并不把“环境代码生成”视作理所当然成功,而是把它也纳入被验证对象。

Coverage and Verification Interface Construction

Coverage group / point 的作用

前面 requirement analysis 得到的是概念上的功能点;
这里要把这些功能点变成:

  • 可执行 coverage model
  • 可调用检查接口
  • 后面 testcase 能实际触发和打点的结构

Basic API 的意义

这相当于先构造一些基础验证原语,例如:

  • 某个接口怎么驱动
  • 某个功能怎么调用
  • 某类状态怎么检查

这会降低后续 testcase 直接生成的复杂度。

换句话说,这一列是在做:
从验证目标建模,过渡到验证执行接口建模。

Testcase Development and Execution

这说明 testcase 并不是一次性生成完事,而是个迭代闭环过程。

先做模板

先有 testcase template,再实例化具体测试。

跑起来再分析

不是“写出来就行”,还要执行并分析结果。

覆盖率驱动补充

如果 line coverage 不够,就继续增强 testcase。

 还能做随机 testcase

说明这个流程并不局限于 directed tests,也支持进一步向随机测试扩展。

作者认为功能验证必须通过 structured workflow 来管理复杂性。
它把整个生命周期拆成多个相对独立、输入输出明确、结果可检查的阶段。

比如:

  • specification analysis 必须输出有精确 label 结构的文档
  • coverage modeling 必须输出可执行 covergroup
  • testcase generation 必须产出能通过特定检查的仿真代码。

也就是说,这个工作流不是“为了画图好看”,而是为了把每一步都变成deterministic deliverable

这是 agent 能稳定工作的关键。


Checker 在这里的真正角色是什么

作者这里对 checker 的定义很值得注意:

checker mechanism encodes expert quality criteria into executable constraint logic.

这句话意思是:

checker 不是简单判个 pass/fail,而是把验证专家对每个阶段产物的质量要求,写成机器可以执行的约束逻辑。

因此,一旦某阶段输出不达标:

  • checker 会返回具体错误信息
  • LLM 根据这些 error message 自我修正
  • 再重新尝试这一阶段

所以 checker 的作用相当于:

  • 局部裁判
  • 阶段闸门
  • 自动反馈器

这也是为什么作者说这个系统能抑制错误累积。


为什么是 31-stage

作者说,这个 31-stage 架构是通过基于 checker 反馈的经验式 refinement 得到的。
他们观察哪些任务容易失败,就继续细分这些任务,最后收敛到一个更细粒度的工作流。

  • 工作流设计本身也是实验结果的一部分;
  • 作者不是先验地知道“31 是最优”,而是通过失败统计和任务重构逐步打磨出来的。

这是一种很典型的系统工程论文思路。


2.3 VCLM 

这一节是整个方法里最有辨识度的部分。

作者说,为了解决多阶段之间 verification consistency 难以维持的问题,他们提出 Verification Consistency Labeling Mechanism (VCLM)
VCLM 建立了三层标签:

  • FG
  • FC
  • CK

并要求 LLM 在三个关键阶段都持续使用这些标签:

  1. functional specification analysis
  2. coverage model construction
  3. testcase implementation

VCLM 的本质是“把隐式语义变成显式约束”

作者明确说,VCLM 的作用是把原本隐式的设计依赖关系,转化成 structured, machine-checkable data

以前你只能通过 prompt 说:

  • 请保持 coverage model 和 specification 一致;
  • 请让 testcase 覆盖这些功能点。

但 prompt 只是自然语言要求,LLM 很容易:

  • 改名
  • 漏项
  • 幻觉出不存在的点

而现在通过标签机制:

  • 规格里的功能点有明确 ID
  • coverage model 必须复用这些 ID
  • testcase 也必须引用这些 ID
  • checker 自动核对这些 ID 是否对应正确

于是“保持一致”就从一个软要求,变成了一个硬约束。


VCLM 是怎样和 checker 联动的

作者说,stage-specific checker 会系统性地提取这些标签,验证跨阶段一致性。
如果某个工件:

  • 没有带上必须的标签
  • 带了错误标签
  • 和前一阶段标签不匹配

checker 就会拒绝该输出,并返回明确错误 trace 给 LLM,触发立即自我修正。


为什么“不能只靠 prompt”

作者明确说,只靠自然语言提示,比如“ensure the coverage model is consistent with the specification”,对于复杂硬件设计来说是不可靠的。

这句话其实是在批评很多 LLM 系统论文常见的问题:

  • 过度依赖 prompt engineering;
  • 缺乏显式结构约束;
  • 输出看似合理,实际很难保证可追踪性。

三、部署

Figure 6 用一个 vector floating-point addition module 展示了 VCLM-enabled workflow。

流程很直观:

1. 在 specification 阶段,功能点被标成类似 `<FG-ARITHMETIC>`, `<FC-VFADD>`, `<CK-FP32>` 这样的标签。
2. 到 coverage modeling 阶段,这些标签必须原样复用到 CoverGroup、CoverPoint、Bin。
3. 到 testcase 阶段,测试函数也必须声明自己覆盖哪些 check point。
4. checker 在阶段之间做 cross-reference。

这张图的意义是把 VCLM 从抽象概念变成了可执行机制。

它不是“加几个注释”,而是整个 workflow 的跨阶段语义锚点。

Figure 4 讲的是实现总览,主要包括四个模块:

1. Agent Middleware
2. Workflow Management Module
3. Stage Validation Module
4. Verification Execution Environment

这里最关键的是分层:

1. Middleware 负责 LLM、上下文、工具调用。
2. Workflow manager 决定现在在哪个阶段、下一个阶段是什么。
3. Validation module 负责 checker 和 VCLM。
4. Execution environment 真正跑仿真和测试。

Figure 5 则更细地展示了 workflow management module,包括 YAML 配置、StageManager、checker gating 等。

这两张图说明作者很重视“系统可控性”。不是单纯让 agent 自由发挥,而是:

1. 明确阶段边界。
2. 明确通过条件。
3. 明确失败回路。

这对 verification 任务尤其重要。

四、实验

作者测试了五个模块,包括:

1. UART-16550
2. ALU754
3. IntegerDivider
4. ICache-WayLookup
5. PageTableWalker

其中前几个规模和结构差异明显,而 `PageTableWalker` 已经是很大的设计。

作者用默认 automated workflow 跑这些模块,并比较 Claude-Sonnet-4.5、GPT-5、Qwen3-Coder-Plus 等模型。

这说明实验不是单一模块 demo,而是有一定横向覆盖。

Figure 7 分四块展示:

1. Runtime
2. Code coverage
3. Coverage bins count
4. Functional coverage

从结果看:

1. IntegerDivider 的 functional coverage 可以到 100%。
2. UART 和 ALU754 的 functional coverage 多数也在 86% 以上。
3. UCAgent 在不同模块上能达到最高 98.5% code coverage 和 100% functional coverage。

这对一篇 end-to-end verification agent 论文来说已经是比较扎实的结果。

但图里也显示不同模型风格不同:

1. Claude-Sonnet-4.5 覆盖更高、更细。
2. GPT-5 更稳定。
3. Qwen3-Coder-Plus 更快,但覆盖较低。

这种差异说明 UCAgent 不是“屏蔽了底层模型差异”,而是提供了一个能把不同模型能力放大的流程。

Figure 8 把流程拆成三个大阶段来看:

1. Component generation
2. Coverage-model generation
3. Testcase generation

结果非常有启发性:

1. Component generation 相对稳定,耗时中等,失败少。
2. Coverage-model generation 最快、失败率也最低。
3. Testcase generation 是最难、最慢、失败最多的阶段。

它说明:

verification 自动化里最难的,还是把抽象 intent 落成真正有效的测试刺激。

文章还指出:

1. Claude 在 testcase generation 上试错很多,但最终 coverage 最好。
2. GPT-5更平衡、更稳。
3. Qwen 更快,但因为功能分解更粗,后续 testcase 难度低一些,最终 coverage 也更低。

这让 Figure 8 不只是“耗时图”,而是帮助理解模型行为差异。

 Case studies

文章给了三个 case study。

第一,`IntegerDivider`。

Qwen3-Coder-Plus 在 RISC-V 特定边界行为上失败,说明即使有 workflow,模型本身的 domain knowledge 仍然限制 verification completeness。

workflow 能兜住很多过程错误,但兜不住模型对某些领域知识根本不懂。

第二,`LaneFAdd`。

UCAgent 找出了三个之前未发现的边界条件 bug,并且借助 VCLM 把失败追踪回具体 function/check point。

第三,`PageTableWalker`。

这个模块太大,默认 workflow 跑不完,最后需要 human-in-the-loop,8 小时内达成预期结果。

1. UCAgent 对模块级任务有效。
2. 但超大规模设计还不能完全自动化。


 

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐