体系结构论文(九十七):Spec2RTL-Agent: Automated Hardware Code Generation from Complex Specifications Using LLM
Spec2RTL-Agent: Automated Hardware Code Generation from Complex Specifications Using LLM Agent Systems 【英伟达25年报告】这篇文章在做什么这篇文章要解决的问题能不能让一个由大语言模型驱动的 agent 系统直接读“真实的、很长的、很乱的、还带图表和公式的硬件规范文档”然后自动生成可综合的硬件实现硬件设计里真正难的往往不是“写几行 RTL 语法”而是把一篇几十页的规范文档真正吃透。规范里会混着自然语言说明、表格、状态流程、数学定义、接口约束、边界条件很多信息并不是一句 prompt 就能说清楚的。过去很多“LLM 写 RTL”的工作常见套路是给模型一段已经被人整理好的简短需求让它补一个模块或者虽然用了 LLM但前面的“读文档、拆任务、发现错误、回头修设计”还是依赖人来做。换句话说以前很多工作只是把“编码”这一步部分自动化了而不是把“从规范到实现”整条链路自动化。这篇文章的价值就在这里。它不是再做一个“给定描述生成 Verilog”的小 benchmark而是试图回答一个更贴近真实工程的问题如果输入不是干净 prompt而是一份真实规范文档LLM 到底能不能像工程师一样先理解、再拆解、再逐步实现、再定位错误、再回头修作者给出的答案不是“单个大模型一步到位”而是一个多 agent 协作框架 Spec2RTL-Agent。它把整个流程拆成四个阶段理解与推理、渐进式编码与 prompt 优化、自适应反思、最后做 HLS 兼容优化并转 RTL。这个思路本身比“直接让模型写 RTL”更像工程系统而不是一次性 demo。一、方向背景先建立几个基础概念。1. 规范文档是什么真实硬件不是从一句“请帮我写 AES”开始的而是从规范文档开始。比如 AES、DSS、HMAC 这种标准算法规范文档里会写清楚输入输出格式、轮函数、变换规则、数学表达、边界条件、流程顺序。工程师真正做的是把这些文档翻译成可以验证、可以综合、可以落地的实现。2. 为什么 LLM 在这里容易失效普通代码生成任务里模型常常面对的是一个明确函数签名加几句需求描述。但规范到 RTL 有几个额外难点- 文档很长超出单次稳定推理的舒适区。- 信息是多模态的文字、图、表、公式都可能携带关键约束。- 真正实现不是一个函数而是一串互相依赖的子功能。- 后面出错时错误来源可能在前面不一定在当前正在写的那段代码。- 即使功能大体对了代码格式也未必能被综合工具接受。作者在论文里把这些问题明确成三个挑战理解与推理、多模块代码生成、错误检测与纠正。这三个挑战的划分是合理的因为它对应了真实工程里最耗人的三类工作读规范、组织实现、调试回溯。文章核心思路作者并没有让模型直接从规范文档吐出最终 RTL而是故意走了一条更绕、但更稳的路- 先把长文档变成结构化理解结果- 再把整体任务拆成多个子功能- 每个子功能不是直接写 C 或 RTL而是按“伪代码 - Python - C”逐级生成- 每一步都配 verifier 去检查- 如果测试失败不急着认为当前函数写错了而是让 reflection 模块分析错误可能来自哪里- 全部子功能完成后再把 C 改写成适配 Stratus HLS 的形式最后转 RTL这个设计背后的核心判断很明确当前 LLM 对复杂硬件任务的弱点不只是语法生成能力不够而是“在长上下文、多依赖、多轮修复的工程流程里不稳定”。所以作者不是强行榨干一个模型而是通过流程设计去补模型短板。图 1 是这篇文章最重要的定位图。它把已有工作和自己的方法放在同一条硬件实现流程上比较。这个图表达的核心意思不是“我们精度更高”而是“我们自动化覆盖面更完整”。图里把硬件实现流程拆成几个阶段理解、架构/规划、编码、反思修正、最后实现。作者认为以前的方法大致有两类- 一类只自动化编码不自动化理解和反思。也就是你先把问题整理好模型再帮你写。- 另一类只在局部环节引入自动化比如让模型协助 debug、协助 coding但并没有覆盖从原始规范到最终实现的整条链路。作者想强调的是Spec2RTL-Agent 要覆盖的是“理解 编码 反思”三块而不是只覆盖中间一小段。这张图的意义在于它把论文贡献从“某个模块设计”提升成了“流程闭环设计”。这篇文章的亮点首先是系统流程完整性而不是某个局部算法有多新。但也要客观看这张图是作者自己的抽象方式带有一定“按自己框架定义优势”的成分。因为很多前作也并不是完全不做理解而是把理解工作交给人类或隐式包含在 prompt 工程里。作者这里把“是否显式自动化”作为边界逻辑上成立但也有一定“口径优势”。问题定义为什么“真实规范文档”是个难输入图 2 画的是目标输入长什么样。它展示的不是某个具体算法细节而是一类典型规范文档的样子页数长、结构复杂、混有图、表、公式而且信息组织方式并不天然适合 LLM 直接消费。这张图其实是在替整篇文章立论。因为如果输入只是几句清楚的功能描述那 Spec2RTL-Agent 的很多设计都显得过重但如果输入真的是图 2 这种文档那作者提出的“先摘要、再拆解、再补信息、再编码”的层层处理就有必要了。问题定义和挑战划分在 preliminary 部分作者把任务定义为输入是未经人工简化的原始规范文档输出是满足规范要求的、功能正确的 RTL 实现而且希望人类只在少数高层指导场景下介入。这个任务定义是清楚的而且比很多“LLM for RTL”论文更贴近真实工程。但它也隐含了几个非常关键的限制- 作者的“自动化”不是完全零人工而是尽量少人工。- 作者的“正确”主要还是功能正确不是全栈工程指标全优。- 作者最终虽然声称生成 RTL但中间实质路线是“规范 - C - HLS - RTL”并不是直接生成高质量手写式 RTL。这点很关键因为它会影响你怎么评价这篇文章。严格说这篇文章更准确的定位应该是“从复杂规范到可 HLS 的实现自动化”而不是“直接替代硬件工程师写工业级 RTL”。二、方法这张图里有四个大模块1. Iterative Understanding and Reasoning Module2. Progressive Coding and Prompt Optimization Module3. Adaptive Reflection Module4. Code Optimization and Conversion Module图 3 的重点不是模块名字而是它们之间的数据流和回路关系。先从左到右看- 规范文档先进入理解与推理模块- 被拆成多个 sub-function并为每个 sub-function 生成结构化说明- 这些说明再驱动后面的逐个实现- 每个子功能要经过伪代码、Python、C几层生成- verifier 决定通过还是失败- 一旦失败不是简单重试而是触发 analysis agent 和 reflection agent 去判断问题源头- 最后经过 code optimizer 适配 HLS再输出 RTL如果把它和软件工程里的 agent 系统类比你可以把前半部分看成“需求分析 任务拆分”中间看成“分阶段代码生成”后半部分看成“错误定位 回滚修复”。这也是它相比单模型直接生成更像“工程系统”的地方。理解与推理模块这个模块包含三步summarization、decomposition、information augmentation。1. Summarization先减负不让后面的 agent 直接啃整篇长文档作者先让一个 Summarization Agent 为文档每个 section 做摘要。这个思路很朴素但很必要。因为如果每个后续 agent 都要反复读取整篇规范不仅 token 成本高而且很容易在长上下文里丢失重点。这里你可以把它理解成“先做读书笔记”。工程师读标准文档时也很少每次都从第一页重新通读而是会先提炼出关键段落和约束项。不过这里也有一个风险摘要本身会丢信息。如果前面总结错了后面所有子功能都可能沿着错误理解继续走。作者后面引入 verifier就是在试图减轻这个问题但这个风险本质上并没有被彻底消除。2. Decomposition把整体功能拆成可实现的子功能Decomposer Agent 负责把目标实现拆成多个 sub-function。这个设计非常符合硬件工程现实因为很多算法模块天然不是一个函数写完而是由多个变换、控制步骤、子模块拼起来。例如 AES 不会是一个“黑盒大函数”而会涉及 SubBytes、ShiftRows、MixColumns、AddRoundKey 等若干功能块。把任务拆开后每一步更短、更清楚也更方便验证。这一步的真正作用不只是“方便编码”更是“限定上下文边界”。模型每次只需要关心当前子功能和必要上下文而不是背着整篇文档做超长生成。3. Information Augmentation把每个子功能补充成结构化字典这是理解模块里我认为最重要的一步也是这篇文章比较像样的设计点。作者没有只输出一个子功能名字列表而是进一步让 Description Agent 给每个子功能整理出一个结构化 dictionary其中包括- 输入- 输出- 功能说明- 实现步骤- 文档引用位置然后再由 Verifier 审核这个 dictionary。这一招很关键因为它相当于把“散落在原始文档里的知识”压缩成“后续编码 agent 可直接消费的半结构化中间表示”。换句话说作者不是让 coder 自己去猜规范而是先给 coder 准备一份类似“设计说明单”。图 4 给了 AES cipher 函数里几个子功能的信息字典示例比如 MixColumns、AddRoundKey 等。每个框里都列出 description、inputs、outputs、steps、reference。例如 AddRoundKey 的字典会明确写- 它做的是 state 和 round key 的异或- 输入是 state array 和 round key- 输出是 XOR 后的 state array- 关键步骤是什么- 对应规范位置在哪作者先让系统给每个子任务写一张“做题卡”把这个函数是什么、吃什么、吐什么、按什么步骤做、证据在哪全都列出来。这样后面写代码时就不是凭空生成而是照着“任务说明书”来写。从研究角度看这个设计是有道理的因为很多生成错误并不是语言模型不会写语法而是前面输入定义不清、接口没说全、实现步骤漏了。图 4 这种中间表示恰恰是在补这个短板。但也要指出这个字典本质上仍然是自然语言结构化不是严格可执行规格也不是形式化语义。它提高了清晰度但没有从根本上消除歧义。渐进式编码模块为什么作者坚持“伪代码 - Python - C”这一部分是论文方法中最有争议、但也最有现实感的设计之一。作者认为让模型直接从说明写最终低层实现稳定性不够所以采用逐层细化- 先生成伪代码- 再生成 Python- 再生成 C每一层都由 coder 生成再由 verifier 检查。这个想法背后的逻辑是LLM 通常更擅长先生成高层、语义更清楚的表示再把它逐渐落到更具体的代码上。高层表示相当于思维脚手架可以减少底层实现时跑偏。可以类比写作文- 直接写最终稿容易逻辑乱- 先列提纲再写草稿再润色定稿会更稳这里伪代码就是提纲Python 是较清晰的草稿C 是更接近综合实现的定稿。这个思路不是空想因为在复杂任务里“先高层、后低层”的确常常比一步到底更稳。尤其是在硬件算法实现里先用 Python 明确数据流、接口和功能再转向 C/HLS确实更符合很多工程团队的验证习惯。但必须说这也是这篇论文最容易被质疑的地方之一它并没有真正解决“从规范直接到 RTL”的最难一步而是通过引入多层中间表示把问题转成一个较长的、流程化的生成任务。它提升了可控性但代价是流程更长、token 更多、工程成本更高。prompt optimization如果说 progressive coding 是“分层生成”那 prompt optimization 就是“把失败教训显式沉淀下来”。作者观察到coder 和 verifier 反复拉扯会越来越费 token于是专门加了一个 Prompt Optimizer Agent读取当前子功能的实现日志分析失败原因再把经验写回 prompt。图 5 是这个机制最直观的展示。它拿 AddRoundKey 这个子功能举例- 初始 prompt 很短只是让 Python coder 按说明生成目标子函数- 优化后的 prompt 明显更具体强调要注意输入输出格式、参数是否已经在前文定义、shape 是否匹配等问题这张图说明了一件很重要的事很多错误不是“模型完全不会这个算法”而是“当前 prompt 没有把关键约束钉死”。例如 AddRoundKey 这种操作概念上并不复杂但它经常会在接口维度、数组形状、参数格式上出问题。这个设计是实用的也解释了为什么作者的方法比 naive coding 迭代次数更少。但它也说明系统仍然高度依赖 prompt 工程。换句话说这篇文章不是证明“模型已经天然理解复杂规范”而是证明“把流程、角色和反馈设计好之后系统可以更稳定地逼近正确实现”。自适应反思模块这部分是整篇论文最像 agent 系统的地方很多生成系统所谓“反思”其实就是失败了重试一下。这篇文章比那种简单做法前进了一步因为它不只是重试而是试图判断错误源头在哪。作者把 adaptive reflection 分两步1. Analysis Agent 回顾整个生成轨迹总结当前已经完成了什么并提出可能的错误来源。2. Reflection Agent 根据这些信息从四种动作里选一个- 指令错了回到理解模块改 instruction- 前面子功能错了回去改之前的 sub-function- 当前子功能错了重写当前实现- 实在不清楚请求人类介入这套设计的关键价值在于它承认复杂多模块生成的错误不一定局部化。比如现在测试在当前模块挂了不代表就是当前模块写错可能是之前某个函数接口定义错了错误一直传到现在才暴露。这一点非常像真实调试程序在 B 函数炸了不等于 bug 一定在 B可能是 A 提前把输入结构弄坏了。从系统设计角度这个 reflection 模块使得论文不再只是“多 agent 并行分工”而是有了真正的回溯逻辑所以它比很多把多个 agent 排成流水线的工作更像一套闭环系统。但要客观说这里分析与反思 agent 的决策仍然是基于语言推断不是严格 program analysis。它能提高排错效率但并不能保证错误归因一定正确。图 6 展示了需要人类介入的两类典型场景这张图我认为是全文最诚实、也最有信息量的图之一。第一类场景是规范本身描述就不够准确或者有歧义。此时 agent 即使“理解能力再强”也无法凭空知道作者真实意图只能向人类提问。第二类场景是测试不够强导致系统虽然知道“前面某处可能有问题”但无法进一步定位到具体哪个子功能。图里展示的例子就涉及 key expansion 和 AddRoundKey 的 shape mismatch以及对一些前序函数缺少足够测试支撑的问题。这张图很重要因为它说明作者并没有把系统吹成“完全自主设计硬件”。相反它明确承认了两类当前 agent 系统很难彻底跨越的边界- 规范歧义- 验证信号不足这两个问题其实非常本质。前者不是模型能力单独能解决的因为输入信息本身不充分后者则说明再聪明的 agent如果缺少高质量测试也可能只能做模糊排查。这张图对应的结论应该是Spec2RTL-Agent 把人工介入压缩到了更少、更高价值的环节但并没有消灭人类在歧义消解和高级 debug 中的作用。为什么作者要走 HLS而不是直接出 RTL代码优化与转换模块里作者最终不是直接输出 Verilog而是先生成适配 Stratus HLS 的 C再交给 HLS 工具转成 RTL。这一步非常现实也非常值得谨慎评价。为什么现实因为直接生成工业上可靠的 RTL比生成语义正确的高层实现难得多。HLS 提供了一个折中方案先保证功能逻辑再借工具链转硬件表示。对研究原型来说这样更容易打通流程。为什么要谨慎因为这也意味着论文的“RTL generation”其实带有明显的 HLS 路线属性。它并不是在证明模型能稳定产出高质量、人工工程风格的 hand-written RTL而是在证明模型能生成足够好的 HLS 输入再借商业工具完成 RTL 转换。这会直接影响你对文章贡献的判断- 如果你的问题是“能不能从复杂规范自动得到一个能工作的硬件实现流程”这篇文章是有意义的。- 如果你的问题是“能不能替代资深 RTL 工程师直接产出工业质量 RTL”那这篇文章距离那个目标还很远。三、实验实验使用了三个 NIST/FIPS 规范文档- AES- DSS- HMAC这三个任务的共同特点是都是标准化、规范文档长、算法明确、公开实现可验证比较适合做“从规范到实现”的原型评测。这组 benchmark 的选择是合理的但也有明显边界- 它们都是算法/密码学导向模块- 更偏数据通路和标准流程- 不代表复杂片上系统、控制密集设计、协议协商、多时钟域等更难的真实硬件所以这篇论文的实验能证明“这个路线在标准算法规范上可行”但不能直接外推到“任意复杂芯片模块都行”。表 1 比较了六种方法- Human- Single-Shot- W/o Understand- Naive Coding- W/o Reflection- Spec2RTL-Agent评价指标有三个- Correct是否功能正确- # Intervention需要多少次人工介入- # Coding平均每个子功能需要多少次生成/修订先看 Correct- Single-Shot 是 0/3- W/o Understand 是 2/3- 其余几个方法和完整系统都是 3/3这个结果说明了两件事。第一单次直接生成在这种任务上基本不可用。因为输入文档本来就远超“一次 prompt”能稳定处理的复杂度。第二完整系统的优势不主要体现在“能不能做对”而体现在“做对时要花多少人工和多少轮次”。因为 Naive Coding 和 W/o Reflection 也能做到 3/3只是代价更大。再看 # Intervention- W/o Understand18.67- Naive Coding9.00- W/o Reflection6.33- Spec2RTL-Agent4.33这个趋势很有说服力。它说明完整系统不是靠某一个模块突然神奇提升而是每个模块都在减少人工兜底压力。尤其理解模块去掉之后人工介入暴涨这和前面图 4 的信息字典设计形成了呼应。再看 # Coding- W/o Understand15.53- Naive Coding17.46- W/o Reflection13.20- Spec2RTL-Agent9.11这说明完整系统不仅少求人而且能少走弯路。换句话说好的任务理解、好的 prompt 优化、以及带回溯的反思机制确实在减少无效编码迭代。表 2 给了 AES、DSS、HMAC 三个文档各自的结果。人工介入次数大致是- AES4- DSS6- HMAC3平均编码迭代次数大致在 8.5 到 9.5 之间。这说明系统在三个任务上的工作量水平相对稳定没有出现“一个例子特别好、其他全崩”的情况。这对于原型系统来说是正面信号。但这个表也暴露出一个很现实的问题即便是完整系统每个子功能平均仍然要接近 10 次左右的生成/修订。这说明它并不是“高效率的一次成型系统”而是“通过多轮迭代换稳定性”的系统。作者自己在结论里也承认了这一点。Spec2RTL-Agent 的进步方向是减少人力而不是已经把 token 成本和交互成本压得很低。做得好的地方。第一它的研究问题选得对。相比很多只在 toy prompt 上比正确率的 RTL 生成论文这篇文章把问题推进到了“真实规范文档 - 自动实现”这个更接近工业价值的层面。第二它的方法设计是成体系的。理解、拆解、结构化说明、分层编码、prompt 优化、回溯反思、HLS 适配这些部分是连成一条逻辑链的不是几个 agent 名词拼盘。第三它最强的贡献其实是流程工程而不是单点模型技巧。它展示了一种很可能对后续工作有启发的范式当基础模型还不够稳时可以通过更像工程流程的 agent system 去抬高实际可用性。第四它没有完全回避失败场景。图 6 这种“人类仍需要出现”的展示反而增强了论文可信度。问题和局限。第一benchmark 太小。只有 AES、DSS、HMAC 三个任务这远远不够支撑很强的泛化结论。第二任务类型偏窄。它们主要是标准算法规范并不代表复杂 SoC 子系统、总线协议、控制逻辑、异常处理、多模块时序交互这些更难场景。第三最终路线依赖 HLS。严格说这篇文章证明的是“复杂规范到 HLS-compatible C 再到 RTL 的自动化可行性”而不是“直接工业级 RTL 自动化已经成熟”。第四效率并不高。平均每个子功能接近 10 次编码修订本质上仍然是一个高 token、高流程长度的系统。第五系统对 verifier 和测试质量很敏感。图 6 已经说明测试不足时 reflection 虽然能猜到错误大概在哪但仍可能无法完成闭环。第六它的很多能力其实建立在 prompt 设计与 agent orchestration 之上而不是更强的底层形式化理解。因此它的上限和稳定性仍会受到模型波动影响。Spec2RTL-Agent 是一篇方向很对、系统设计比较完整、比很多同类工作更接近真实工程流程的论文。它最重要的贡献是证明面对复杂规范文档单次生成不行但通过“理解-拆解-分层编码-反思回溯-HLS 转换”的 agent 化流程自动化程度可以明显推进人类负担也确实能下降。但这篇文章离“成熟工业方案”还有明显距离。它的实验规模小、任务类型集中、效率一般、验证依赖较强、最终也没有摆脱 HLS 路线。把它看成一篇很有启发性的早期系统论文是合适的