行业随笔【5】: 2026-04-20
一次全自动生成2000行RTL的实验,以及它暴露出的结构性问题
引言
AI生成RTL早就不是什么新鲜的事了,但是当上个月我真正看到Claude.ai在网页端,在没有仿真器的情况下,全自动地一次性完成RTL编写,甚至预测仿真结果的时候,我意识到全自动生成RTL的时代已经不可避免地到来了,甚至有一点行业快完蛋的焦虑感。
于是我做了个实验,我一行代码不写,只使用prompt指导AI使用仿真器完成设计,花了大约一周完成了一个大约2000行的协议控制器,最终完成其与一个商业级的IP的对接,构建成SoC系统。中间AI犯了很多错,包括但不限于:
• 状态机跳转条件,对FIFO的空满状态的判断出错
• 喜欢给我写兜底方案,导致错误藏得极深
• 不按最优路径实现,喜欢大面积重构
• 对于时序的理解不到位,无法正确实现信号的先后等待关系
• 写出不可综合的写法
这里我暂且不想长篇谈论如何使用什么Skill或者上下文管理手段作为workaround规避这些问题,我在想AI for RTL design真正在技术层面还有哪些问题,哪些是上下文管理之外,我们应该在架构上思考的问题。
序列生成器遇上并发电路
首先,我们简单回顾一下Transformer的本质,其基本原理是一个从左到右的序列生成器——它学到的全部是"前面的token如何决定后面的token"。这种机制天然适用于从前到后串行执行的代码。
而我们的RTL不是这样。RTL描述的是一张时序电路,一个时钟沿来了,几百个甚至上千个always块会在同一瞬间用旧值算新值,然后并行提交。这是并发,不是顺序。
那么回到RTL的生成和开发中,想象这样一个场景。你有一段RTL代码,里面十几个always 块,你把它们的顺序前后调换一下,或者干脆拆到两个文件里,语义完全不变——综合器不care,仿真器也不在乎。
但在AI眼里这样是有区别的,它必须在生成时对这些块做先后决断,因为它只能沿着token序列一路往下写。它可能无法准确判断一个always到底写在前面好,还是写在后面好,只能按照它已经学习到的范式,选择概率最大的那个生成。它没有办法同时追踪太多信号的来源和先后关系。
每多并行追踪一个信号,它的上下文空间和生成速度都会受到挤压。从数学上看,这其实是状态空间的问题。N个并发FSM的联合状态空间是指数级的,而LLM没有显式的状态存储。那么它每生成一个token都要从上下文里隐式重建整个系统的状态。一旦token超过它能关注的上限,AI的能力就会显著下降。
还有一层更隐蔽的问题:时序。RTL背后潜藏着一层时序约束:像Setup/Hold、CDC、亚稳态这些时序概念,说的都是信号在某个时钟沿前后必须满足的稳定关系。
这些约束不是从代码的语义能直接推断出来的,它是物理世界在数字设计中的一层隐含规则。大模型没有clock cycle的概念,它只有token position。如果不把这些约束作为显式的规则喂给它,它就只能靠训练语料里见过的写法去猜,猜中了是运气,猜不中就是一个语法完全正确但时序上埋了雷的设计。
说到底,如果想让一个大语言模型真正理解一段RTL在运行时发生了什么,它需要在脑子里跑一个事件驱动的仿真器:同时追踪数百个信号的变化、触发、传播。这件事对注意力机制的要求是远超它能力边界的。它可以写出看起来对的代码,但它并不真的知道这段代码跑起来会发生什么。
仿真能跑不代表能综合
这个问题出在语言本身。Verilog和SystemVerilog这种RTL语言,从设计之初就不是"语义安全"的语言,仿真器无法在编译或者语法检查层面进行详尽的安全检测。
它把两件性质完全不同的东西绑在同一套语法里:一套是可综合的RTL子集;另一套专用于仿真器的testbench写法。这门语言里能安全用于综合的部分,其实只是整个语法的很小一个子集。
问题在于,大模型训练的时候不会显式区分哪段代码是Design、哪段是Testbench。它看到的就是一锅乱炖的Verilog。你让它写一个RTL模块,它可能顺手就用上fork/join、用上延时、用上force这些不可综合的语法特性。
这些特性在语法层面一个错都没有,仿真也能跑通,但送去综合就会出问题。意外latch、多驱动、无意引入的优先级编码器,这些问题每一种都不会在语法检查阶段报错,只会在后端流程中悄悄浮出来。
这就是一道隐形的断层。仿真能跑,说明功能逻辑在行为级是通的;但综合能不能通,取决于你的代码是否落在可综合子集内,有没有引入latch或者组合环路;而综合通了之后,时序能不能收敛,又是另一个维度的事情:它关乎微架构选择、流水级数和关键路径上的逻辑深度。
这三层之间每一层都有自己的规则,前一层通过不代表后一层没问题。传统上工程师依赖Spyglass这类EDA Lint工具做额外的静态检查来守住这些边界,但大模型自身并不具备这套完整的Lint能力,它在生成时并不知道自己正在越过哪一道线。
用软件语料教不出硬件思维
大语言模型要学会写RTL,得有足够的语料在训练阶段让它见过各种写法。可工业级的RTL代码几乎全是私有的。Intel、AMD、NVIDIA、Apple、Qualcomm的RTL没一家开源,作为工程师,大家手里的代码都是公司资产,不可能上传到任何公开平台。工程师圈子内的交流大部分是口头的,偶尔做文档汇报也不会贴原始代码进去。哪怕是技术分享,公开出来的内容粒度其实都相当有限。
所以公开能得到的Verilog语料,绝大多数来自OpenCores、GitHub上的学生项目和少数开源IP。Verilog连GitHub Octoverse报告的前50语言榜都排不进去。标记为Verilog和SystemVerilog的仓库加起来大约6500个,GitHub总仓库数超过4亿,占比连0.1%都不到。
当然我们也看到,开源生态在逐步完善,可用的RTL语料确实在增长。但即便HDL语料在训练数据中的占比提升两个数量级、达到10%左右,这个问题依然解决不了。剩下90%以上的高层语言代码,在训练阶段已经深度塑造了模型的推理框架。大量软件语言训练出来的能力,向RTL的迁移并不完整,甚至可以说两者之间存在很大的范式差异。模型在处理RTL时,其底层的推理模式仍然是顺序的、有副作用的、基于函数调用的,这不是靠补充数据就能纠正的。
同一个Prompt,两次不同的代码
大语言模型有一个工程上绕不开的性质——同一个输入给它两次,生成出来的代码可能不一样。信号命名会变,代码结构会变,实现细节也会变。即使把Temperature调到0,这种不确定性也不能完全消除,因为浮点的非确定性、GPU的并行调度、batching策略这些底层机制都会引入概率波动。
不可复现性首先摧毁的是调试过程中的经验沉淀机制。工程中排查问题的基本链条是"复现→定位→修复→验证",如果你让AI重新生成一遍,代码变了,bug也消失了——不是修好了,是碰巧走了另一条采样路径。你没有办法对一个不可复现的错误做根因分析。人类工程师踩过坑之后认知就留下了,不占工作记忆,不需要每次重新加载。AI没有这个机制,每次生成都是独立采样,教训必须显式写进Context,而Context本身是有限的。
更深层的问题在于,LLM本质上是生成模型,不是编辑模型,它没有"保留"这个概念。工程师在指导AI修改时,往往只能给出模糊的意图,很少会把修改范围显式锁定到具体的代码区间。你说"最小改动"、"不要重构",这些只是提示词层面的软约束,AI无法严格遵循,只能在自己生成的几个候选方案之间做概率比较。结果就是你让它改一个跳转条件,它可能顺手把周围几个always块的写法也重构了。你做diff的时候,分不清哪些变化是你的意图、哪些是采样漂移。一旦代码被重构,下游锚定在代码结构上的Lint Waiver、SDC约束、CDC报告全部需要重新审视。另外如果代码的增量验证做不了,那么Testcase的Regression只能全量重跑。每一次AI辅助的修改都要付出这个代价的话,维护效率不是被提升了,而是被拖下去了。
AI写得越好,验证越难
生成侧的问题先讲到这里。接下来聊聊验证。
前面讲不可复现性的时候已经提到,AI每一次修改都可能导致regression全量重跑。一个自然的想法是:让AI也帮忙写验证环境,用生成对冲生成。这个思路方向上没错,但在展开之前,有一件事值得先想清楚。
我们讨论的前提是AI生成RTL的能力在变强,代码产出在变多。但代码产出变多本身,就意味着需要被验证的对象在膨胀。审查成本跟着代码量线性上涨,而bug的发现效率并不会同步上涨,甚至可能下降。因为模型写出来的代码风格一致、语法干净,你反而更容易对它产生信任,更容易漏掉藏在"看起来没问题"下面的逻辑错误。换句话说,AI写RTL的能力越强,验证这件事反而可能变得更难。
那让AI来写testcase呢?问题在于AI的训练数据里绝大部分是正确代码和正确解释,不是错误分析。它对"错"的理解基于统计——常见的错它能覆盖,罕见的错它根本没见过。可真正难的硬件bug藏在分布的尾部:几个低概率事件同时触发、特定reset时序下的corner case、某种CDC条件下的亚稳态传播。模型的生成机制决定了它天然往统计中心靠拢,而不是往分布的边缘走。即使调大采样温度,代价是它会编出大量不存在的假场景,工程师在假case里淘真Bug,效率反而更低。
那走形式验证呢?这里有一个根本性的障碍。举个例子,你跟AI说"帮我写一个FIFO":同步还是异步?位宽多少?深度多少?满标志是寄存器输出还是组合输出?空读和满写怎么处理?一旦你把这些模糊性一个一个填进去,把需求精确到机器可检查的程度,你会发现那份spec的长度已经和RTL本身差不多了。这不是压缩,是等长翻译。信息总量没变,你只是换了一个地方写。所以"用自然语言描述设计、AI自动生成RTL"这条路,在真正复杂的定制设计上走不通:你最后写的那份spec,就是RTL换了层皮。
但这个推理反过来恰好指向了一个可行的方向:SVA。如果说完整的自然语言spec等价于RTL,那一条assertion只钉住设计空间里一条性质,信息量远小于整个设计,这恰恰是LLM擅长处理的粒度。事实上,LLM生成SVA目前已经是学界和工业界进展最快的方向之一:最新的研究在语法正确率和功能正确率上都已经突破90%,甚至有团队用LLM生成的SVA在开源RISC-V核心中发现了人工审查遗漏的真实bug。
另外,对于标准化程度高的接口,例如AXI、PCIe这类协议,AI只凭很少的额外信息就能生成高质量的assertion,因为训练语料里这类pattern足够丰富。但如果是公司内部的自定协议,没有充分的文档和范例,AI目前还是无从下手。总的来说,SVA生成是当前AI介入验证最现实的切入点,但它能覆盖的范围仍然受限于语料的丰富程度。
可预见的未来,人还是主agent
回到开头说的那个实验。一周时间、2000行控制器代码、零行手写——听起来很诱人,但过程中踩过的每一个坑,其实都在验证上面说的这些结构性问题。那么经历过这些之后,到底该怎么跟AI协作写RTL?我先说说这段实践下来,对AI能力边界的一个基本判断。
AI目前擅长的,是那些有golden model的事情——有一个清晰的、结构化的参考,能让生成的代码在一个有监督的闭环里被自动对照、自动验证。标准协议是典型例子,AXI、APB这类spec极度稳定,大家写的第一版实现长得都差不多,AI跟着pattern走就能写出来。体系结构建模、高层行为级代码也属于这个区间,因为它们的正确性可以被独立的reference model验证。
而业务驱动的产品化代码就是另一回事。这类代码的spec本身是流动的,跟着客户需求走、跟着产品定义走,里面全是trade-off。为什么选3级流水、为什么buffer深度是16、为什么仲裁策略是weighted round-robin——这些几乎从来不会写在spec里,它们在架构师脑子里、在项目会议的口头讨论里、在几年积累的设计直觉里。AI拿到spec看不到这些,只能按最标准的pattern去写,产出的东西功能可能对,但实现路径十有八九不是你想要的。AMS和模拟部分的行为建模就更不用说了,对连续域的抽象思考,AI实在力有不逮。
说了这么多不行的,那在它确实能介入的区间里,怎么搭一个可用的工作框架?
首先,基座模型的能力是地基。我试过把某国产厂商吹得很猛的M2.7模型接上Claude Code和iverilog,提供完整的仿真和编译环境,让它写一个SPI存储器模型。这是一个复杂度很低的任务,结果磕磕绊绊一个多小时,反复陷在自己制造的bug里绕不出来。而同样的任务交给Claude Opus 4.6,它在网页端没有任何仿真器辅助的条件下,五分钟一次通过,编译仿真都没问题。工具链、RAG、Harness这些东西是缰绳,但如果马本身跑不动,再精致的缰绳也拉不出结果。
但光有模型也远远不够。人是主agent,这个位置让不出来。架构怎么拆分、PPA在功耗和性能之间取什么平衡点、哪些模块值得投入验证资源去做深度覆盖、跨模块集成时哪些隐含假设需要对齐,这些决策依赖的是对产品定位的理解、对系统上下文的把握、对"够不够好"的风险判断,因此没法交给AI。人自顶向下拆解到叶子模块的粒度,再让AI动手写——这是AI辅助设计,不是一段prompt进去AI全自动交付。哪怕给再完善的约束,在未来几年的能力框架下,fully generated RTL都不太现实。
在这个前提下,怎么让AI发挥最大价值?核心是在模型外面搭够支撑。我目前的实践里大致分这么几层:
RAG,提供背景上下文——让模型能检索到项目里已有的代码、信号定义、接口文档,知道自己在给什么样的系统写代码,而不是凭空生成。
MCP工具链,接仿真器、lint、波形查看器,让模型写完代码之后能跑、能看结果、能据此debug。没有这层闭环,所有生成都是盲写。
Skills,可复用的操作手册——告诉模型怎么做一件具体的事,比如怎么结构化地写一个状态机、怎么组织testbench、怎么跑某个特定的lint流程。它编码的是领域操作经验。
项目约束文档,类似CLAUDE.md这类东西——编码规范、命名规则、禁用的语法特性、模块间的接口契约。如果说skills是"怎么做",这一层是"什么能做、什么不能做",是项目级的工程纪律。
Harness engineering,最外面一层治理——管的不是模型怎么生成,而是生成之后怎么验收:哪些文件可以动、改完必须跑哪些检查、不通过就打回重来。
这几层是叠加关系,不是选配关系。只搭其中一两层,效果都立不住。
回头看这篇讨论的几个问题,架构错配、语言陷阱、数据困境、不可复现、验证的分布错位,它们不是某个模型的能力不足,而是写在LLM的架构、Verilog的语言特性和整个行业的数据结构里的结构性约束。这些不会因为下一代模型参数翻倍就自动消失。
但话说回来,今天的Transformer也不是AI的终极形态。如果出现一个真正能做事件驱动推理的架构,或者有人用形式化中间表示彻底绕开Verilog的语言陷阱,上面这些约束可能一夜之间就不成立了。
这个行业的护城河从来不是某种具体技能,而是对系统的理解深度和工程判断力。模型在变强,边界在收窄,这是事实。认清今天的边界在哪里,在边界内把工具链搭好,同时不要赌这些边界永远不会被突破,也许这才是在这个时代做数字IC工程师应该有的姿态。
先记到这里,有机会我们单独抽一篇文章的篇幅聊聊AI for RTL design的最佳实践。
晚安,祝各位的流片一切顺利
。
— END —
夜雨聆风