刚听到“用AI写RTL”这句话的时候,我第一反应是终于可以不用自己手敲verilog了。可真等自己在项目里跑了一轮下来,我才明白那句话背后的意思——第一批用AI写RTL的人,快被折腾疯了。芯片设计行业里,RTL是硬件描述语言的核心,是芯片逻辑设计的源头,AI在通用代码领域可以写出看起来像模像样的软件代码,可一旦到了RTL这里,画风就完全不一样了。
我身边好几个做数字IC设计的同事都说会拿AI辅助写点模块,但问起来几乎人人都有被坑过的经历,有人把状态机写到死锁,有人综合出来组合逻辑环,还有人因为复位风格不对导致DFT插复位失败。这些坑单看都不大,但每一个都实实在在地吃掉了一到两天的时间。这篇博文就是记录我从“AI好厉害”到“AI把我折腾疯了”再到“终于摸索出一套能用的工作流”的全过程,涉及的RTL基础、AI协作思路、时序和复位那些让人头疼的细节,我都会尽量讲透,希望能帮正在尝试或者准备尝试用AI写RTL的同仁少走点弯路。
1. 为什么RTL不是AI的舒适区——先搞清楚问题在哪
1.1 RTL和普通代码,差的不只是语言
AI写普通软件代码之所以看着很厉害,是因为软件世界里的规则相对统一,函数调用、循环、异常处理这些东西有大量公开资料可以学习。RTL则完全是另一个世界,它描述的是硬件电路,是真正在硅片上并行跑起来的东西。
我第一次让AI写一个简单的FIFO时,它给出的代码语法完全正确,用always块也像模像样,乍一看毫无问题。但真正放进综合工具里,问题立刻暴露出来——某个信号在组合逻辑路径上生成了一个本不存在的锁存器,这个锁存器在综合时会产生警告甚至报错。软件代码里你写个if不加else可能只是逻辑不完整,RTL里不加else就会综合出锁存器,这是硬件设计独有的坑。AI在训练时看过无数RTL代码,但它并不会真正理解“这段代码会被综合工具转换成门级网表”这件事,它只是在模仿文本模式。
更关键的是,RTL设计讲究并行和时序。软件里的语句是顺序执行的,RTL里每个always块并行触发,信号赋值还分阻塞赋值和非阻塞赋值。AI经常把这两种赋值混用,写出在仿真里没问题、一到综合就行为异常的代码。这种错误不是语法错误,而是语义层面和硬件实现层面的偏差,LLM再强大也难以靠训练数据彻底规避。
1.2 AI写RTL时最典型的“幻觉”
通用AI圈子里很爱提“幻觉”这个词,就是模型一本正经地编造看似合理实际错误的内容。在RTL领域,这种幻觉会以极其隐蔽的方式出现。
我自己遇到最多的第一类幻觉是状态机编造状态。让AI生成一个简单的UART接收状态机,它会给每个状态编一个华丽的命名,甚至画出一套带多个嵌套分支的转移逻辑,看起来结构很清晰,但你仔细检查就会发现其中两个状态根本不可能到达,还有一条转移路径在同一时钟周期内同时改变了两个状态寄存器的值,这在真实硬件里是要闹出大事的。仿真也许能跑通某几条路径,一到覆盖率统计的时候,你会发现那些所谓的“保护状态”永远进不去,可代码里又确实写了一大堆逻辑,白白浪费面积和功耗。
第二类幻觉是跨时钟域处理。AI非常喜欢在两个不同时钟域的模块之间直接打拍同步,却完全不考虑信号本身是不是脉冲信号、需不需要握手、CDC结构符不符合项目规范。它甚至会在同一段代码里混用posedge clk_a和posedge clk_b的触发逻辑,这在RTL静态检查里直接就是违规。真实芯片设计里,跨时钟域处理是重中之重,如果只是打两拍就能解决,那CDC工程师早就失业了。
第三类幻觉是“自我感动式”的注释和断言。AI会生成大量看起来专业感十足的注释,比如“此处防止亚稳态传播”,但代码里根本没有做任何防止亚稳态的处理。它还会写一些断言,看起来像模像样,实际触发条件写错,永远不可能失败。如果你把这些断言当成验证依据,那你的验证环境就是一个定时炸弹。
1.3 可综合性、DFT和规范,是绕不过去的三道坎
RTL不是写给人看的,是写给综合工具、仿真工具和其他工程师看的。这里面有三个绕不过去的坎,AI如果没有被明确约束,几乎必然踩中。
第一道坎是可综合性。可综合RTL是指综合工具能把它映射成标准单元网表的代码风格,像always @(*)里不能有initial,循环次数必须是编译期可确定的,不能用动态内存分配。AI经常写一些在仿真库能跑、但综合工具完全不认的代码,比如用fork和join来模拟并行行为,这在SystemVerilog测试平台里是合法的,但如果在可综合模块里出现,综合工具直接翻脸。
第二道坎是DFT。DFT即可测试性设计,芯片流片之后要靠扫描链和复位设计来测试制造缺陷。这里特别要强调“插复位”这个问题。DFT工具通常需要RTL里有清晰可控的复位策略,但AI生成复位逻辑时经常犯两种错:一种是复位信号只在部分触发器的敏感列表里出现,导致DFT工具没办法把整条扫描链统一复位;另一种是复位电平定义和项目规范相反,比如项目规定高电平复位,AI按照训练数据里的主流写法给了低电平复位,然后整个DFT流程的约束脚本全部作废。网上还有一个热搜词叫“DFT插复位怎么改RTL”,说明这个问题已经成了普遍痛点,我在后面专门展开讲。
第三道坎是公司和团队的代码规范。芯片公司几乎都有自己的RTL编码规范,包括信号命名、时钟命名、复位风格、状态机写法、寄存表结构等等。AI在训练数据里学的是互联网上各种来源的混合风格,和公司规范天然冲突。除非你把规范完整喂给它,否则它产出的代码必然是“野蛮生长”的。越是大型SoC项目,这种规范冲突带来的返工成本越高,因为每个模块都要人工再审一遍,等于AI帮你写的活儿,你用两倍时间检查。
2. 被AI折腾的三大名场面
2.1 综合出来一个组合逻辑环
我印象最深的一次事故,是在一个总线桥接模块里。当时我用AI生成了一段ARBITER逻辑处理多主机访问,输入的需求描述写得比较长,AI给出了一段非常工整的always @(*)代码,每个分支都覆盖到,没有锁存器风险,仿真也通过了。
真正发现问题是在综合后的形式验证阶段。工具报了一个组合逻辑环,定位到这段ARBITER的反相路径上——一个信号通过两级组合逻辑反过来影响了自己的输入。在RTL仿真里,这种环因为延迟设置原因可能表现正常,但实际电路里它就是一个振荡源,轻则功能紊乱,重则芯片电流异常。
排查了很久才找到根因:AI在处理同一个内层判断条件时,同时使用了两个命名不同但逻辑等价的中间信号,一个是我让它加的req_priority,另一个是它自己从上下文推断出的req_level,两个信号组合起来形成了一个互相依赖的环。如果是我自己写代码,绝不可能给同一个逻辑起两个名字,但AI在生成代码时根本不记得前几十行里它自己定义过哪个信号,于是又“创造”了一个新名字。这让我彻底意识到:用AI写RTL,必须做严格的代码审查,尤其是组合逻辑里的信号依赖关系。
2.2 时序约束:AI完全不理解的“玄学”
时序约束对AI来说就是玄学。RTL代码本身没有“频率”这个概念,让AI去写一个高速接口模块,它会默认按照最理想的情况来写组合逻辑的级数,完全不管路径延迟是否满足时钟周期。
我让AI优化过一段数据通路,目标是5GHz,AI给出一版看起来很精简的组合逻辑链,用的全是行为级描述。放进综合工具里一跑,时序报告显示关键路径差了整整0.2ns。为什么?因为AI把三段独立的判断逻辑串联成了一条长组合链,没有考虑插入流水寄存器。这根本怪不了AI,它并不知道综合库里的门延迟是多少,也不会主动想到跨周期打拍。
这里必须强调一个核心观点:时序收敛不是AI能替你解决的,它甚至不能在RTL层面给你提供靠谱的预判。RTL设计者自己心里必须清楚组合逻辑到寄存器的延迟预算,该拆的流水段要拆,该并行的判断要并行。AI能帮你写代码,但写出来的组合深度需要你自己心中有数。很多新人以为AI能“一键优化时序”,这是最危险的误解。
2.3 复位策略:DFT插不进去的经典事故
“DFT插复位怎么改RTL”这个热搜词精准描述了我们组踩过的大坑。项目里有一个模块需要做扫描链插入,我们用AI生成了模块的所有复位逻辑。AI不负众望地给出了一套漂亮的复位管理代码,每个触发器都接了异步复位端,看起来非常规范。
但当DFT工具真正开始插扫描链的时候,问题来了。工具要求扫描单元在测试模式下能够通过复位端口统一初始化,可AI生成的代码里,部分寄存器的复位信号是经过组合逻辑处理后的衍生复位,并不直接来自顶层复位端口。DFT工具在分析时发现这些寄存器的复位不可控,直接把整条扫描链的报告标红,表示无法满足复位要求。
改起来更是噩梦。你必须在RTL层面把复位策略统一,所有触发器要么都用同步复位,要么都用异步复位,而且还是同一个复位网络,不能有的模块用异步、有的复位用同步。同时,复位信号必须是可测试的,测试模式下要能绕过功能复位,直接由外部引脚控制。AI不具备这种全局视角,它只会按照训练样本里最常见的风格去写,不会主动考虑DFT约束。那次事故花了团队里一位工程师三天时间,改了一百多处代码,从此以后我们定下规矩:复位和时钟相关的RTL,AI一个字都不能碰。
3. 硬核实践:把AI当结对工程师,而不是自动生成器
3.1 整个工作流长什么样
踩过足够多的坑之后,我总结出一条核心原则:别把AI当自动生成器,把它当结对工程师。结对工程师不会直接甩给你一坨代码就完事,他会先问需求、给方案、写代码、自测,然后等你评审。AI在你给的上下文足够充分时,也能表现出类似的行为,前提是你得建一套工作流。
我现在的工作流大致分五步:第一步,用RAG知识库把项目规范喂给AI,包括公司RTL编码规范、复位规则、CDC规则、低功耗相关约束等。第二步,把模块需求写成结构化的提示词,明确信号接口、时钟域、复位极性、时序要求、DDL功能描述。第三步,让AI生成RTL代码,并明确要求在关键位置加注释说明设计意图,但代码风格必须符合规范模板。第四步,把AI生成的代码放进我们的回归测试环境里跑一遍,包括Lint、仿真、形式化验证。第五步,人工评审,重点检查时钟复位、跨时钟域、状态机可达性和组合逻辑环路。
这套流程下来,AI并没有让我工作量减半,但让我把精力从“敲代码”重新分配到“定规范和查问题”上,这才是一个工程师真正的价值所在。
3.2 提示词工程:把RTL规范灌给AI
给AI写提示词和给人类工程师写设计文档是两回事。人类工程师有默会知识,你说“按照规范来写”他就懂了,AI不懂,你必须把它能查到的一切都写进上下文里。
我常用的一段提示词模板是这样的,分享给大家参考:
你是资深数字IC设计工程师,现在要设计一个[模块名]模块。 接口规范: - 模块名:xxx - 时钟:clk_a(500MHz),clk_b(250MHz),异步关系 - 复位:por_rst_n,异步低电平复位,必须直接连到每个触发器的复位端,不允许衍生复位 - 信号列表:请按下面表格实现 功能要求: - 描述数据通路、控制状态机、错误处理逻辑 - 状态机必须完整定义所有状态和转移条件,不允许不可达状态 - 跨时钟域处使用标准两级同步器,不允许在组合逻辑中直接本地跨时钟 可综合要求: - 只使用可综合的Verilog/SystemVerilog子集 - 禁止initial、fork/join、动态数组、delay语句 - always中敏感列表必须完整 - 组合逻辑中每个分支都必须有默认赋值,禁止锁存器 - 非阻塞赋值用于时序逻辑,阻塞赋值用于组合逻辑 输出要求: - 给出完整编码,按项目命名规范命名所有信号 - 在每个模块上方用注释说明设计意图 - 注释用中文,控制在合理长度这段提示词我每次都会微调,但核心不变:接口、复位、时钟域、可综合子集、输出规范。按理说把这些都写清楚,AI生成的代码质量会高很多,但依然不能掉以轻心,因为AI可能在不显眼的地方偷偷用了一个没声明的信号,或者在状态机里漏掉了某个转移条件。
3.3 验证环节不能省:仿真、Lint、CDC至少留两样
有些朋友问,是不是提示词写好了、AI生成的代码直接能过仿真,就可以省掉验证流程?我的答案是绝对不行。
仿真只能验证特定激励下的行为,覆盖率再高也不能保证所有场景。AI代码最危险的往往是那些看似合理的角落逻辑,你自己写代码时天然会规避很多无效路径,但AI不会,它把每一种可能的分支都写得满满当当,看起来防御性强,实际上很多分支根本不会触发。
所以我现在对AI生成的RTL,至少会过Lint和仿真回归两项。Lint能抓到信号悬空、位宽不匹配、状态机不完备、时钟域交叉等结构性问题。仿真回归能验证基础功能。如果项目有CDC验证和形式化验证工具,那更好,特别是形式化验证可以直接证明状态机的可达性和死锁性质,这是AI代码最需要被“照顾”的弱点。
我们这个行业里有个隐形成本叫“验证的沉默成本”。AI生成的代码会让验证工作量比预期增加不少,因为你不知道它会在哪个角落埋雷。你必须在验证环节投入足够多,提前把雷挖出来,而不是等到tapeout前的仿真阶段才崩溃。
3.4 我踩坑后整理的AI写RTL协作清单
经过几个月的磨合,我总结了一份协作清单,现在团队里新来的同学我都会让他们先看一遍:
- 严格限定AI只负责小型、独立、功能清晰的模块,复杂模块拆成子模块再交给AI。
- 时钟和复位相关的RTL一律人工编写,AI只做辅助审查。
- 状态机、FIFO、跨时钟域等经典结构,必须人工评审状态转移表。
- 所有AI生成的代码必须过Lint和仿真回归,不允许跳过。
- 如果AI给出了“看似高级”的写法,比如复杂的宏定义或者多层嵌套,优先怀疑它的可综合性。
- 每次让AI改代码前,先保存当前能通过测试的版本,不要让它直接在前一版上打补丁。
- 提示词里永远写一句:如果某个功能你不敢确定可综合,请直接说明并保持简单实现。
这份清单不一定适合所有团队,但它至少能帮你规避70%的AI写RTL翻车事故。剩下的30%,就是那些绕不开的“人肉debug”时间。
4. 三个月团队实测:哪些活能交给AI,哪些千万别碰
4.1 真的好用的场景
虽然开篇说了那么多坑,但AI写RTL并不是一无是处。三个月的团队实测下来,有几个场景AI确实能稳定提高效率。
第一个是寄存器配置类代码。比如SPI配置寄存器、AXI-Lite寄存器堆、中断状态寄存器这类代码,结构固定、命名规律、位域定义清晰,AI只要拿到一张寄存器表,就能生成结构基本正确的RTL。这类代码人工写起来繁琐且容易出错,AI反而是强项。
第二个是粘合逻辑和简单转换。比如字节序转换、位宽转换、CRC计算模块、简单的编解码逻辑,这些模块功能独立、边界清晰,AI生成质量不错,稍微检查就能用。
第三个是生成测试平台和激励。SystemVerilog的UVM环境里,给AI明确要求和接口定义,它写出来的driver、monitor、sequence往往比很多初级工程师写得还规整。这部分不涉及可综合问题,验证本来就是用仿真软件跑,AI的“幻觉”危害小很多,即便错了也容易在仿真中暴露。
第四个是代码注释和文档转换。AI把一段原本没有注释的RTL解释清楚,并按照公司模板生成模块级文档,这个能力非常实用,至少能帮我们省出半天时间。
4.2 千万别碰的场景
反过来,有几类场景我们明确禁止使用AI生成RTL。
第一,时钟树和复位树相关代码。时钟门控、复位同步器、异步复位同步释放电路,这类代码直接影响芯片的可靠性和DFT,必须由资深工程师逐行手写。原因前面已经讲了,AI不懂全局复位策略,更不懂DFT要求。
第二,复杂状态机和协议控制。比如AXI协议的主从状态机、DDR控制器的命令调度状态机,这类模块的状态存在大量时序交互和异常处理,AI生成的状态图看着完整,实际可达性分析很容易出问题。一旦流片回来才发现状态机BUG,代价是以百万美元计的。
第三,和时序预算紧密相关的数据通路。比如高速SerDes的收发数据通路、CPU流水线控制逻辑,这些地方的关键路径延迟必须靠人工精心设计,AI生成的组合逻辑深度完全不可控,很可能直接让时序收敛失败。
第四,低功耗相关的isolate、retention、level shifter控制逻辑。这些逻辑牵扯UPF文件、ISO单元、电源域切换,AI不仅不懂这些,还会生成一些“看起来像低功耗”的伪代码。
4.3 RTL评审清单:AI代码过检必查项
不管AI在哪个场景帮了忙,评审这关绝对不能省。我列了一个AI代码过检必查项,每个细项都是踩坑换来的:
| 检查项 | 具体内容 | 后果 |
|---|---|---|
| 复位连接 | 每个触发器复位端是否正确连接,是否有衍生复位 | DFT失败、复位不可控 |
| 敏感列表 | always块敏感列表是否完整,是否包含多余信号 | 仿真与综合不一致 |
| 阻塞/非阻塞赋值 | 时序逻辑是否全用非阻塞,组合逻辑是否全用阻塞 | 仿真行为异常、综合警告 |
| 组合逻辑闭环 | 是否存在信号不经过寄存器自己影响自己的路径 | 综合出振荡环 |
| 位宽匹配 | 所有运算和赋值是否做了位宽对齐扩展 | 数据截断或符号错误 |
| 状态机完备性 | 是否有默认状态、是否可到达所有状态、是否有死锁 | 功能异常、覆盖率难收敛 |
| 跨时钟域结构 | 是否使用标准同步器/异步FIFO | 亚稳态风险 |
| 可综合性 | 是否有initial、fork/join、delay、动态数组等 | 综合直接失败 |
| 命名规范 | 信号名、模块名、前缀是否符合团队规范 | 可读性差、集成困难 |
| 覆盖率空点 | 是否存在永远无法触发的分支 | 验证效率低、隐藏风险 |
这张表我打印出来贴在工位上,每次评审AI代码时一键对照。老实说,一开始每次都能查出好几个问题,现在随着提示词优化,问题数量在逐步下降,但依然没有一次是“零问题”直接通过的。
5. 常见问题与排查实录
5.1 AI为什么总爱写满触发器
有朋友吐槽,AI生成一个简单的计数器,结果给它写了一个32位宽的计数器,每拍都判断是否等于某个值再置零,功能没错,但面积和功耗白白翻了一倍。这是AI非常典型的“过设计”倾向。
原因在于训练数据里大量的工程师会采用“通用性强”的写法,把计数位宽留得很宽,把判断条件写成全量比较。AI学到了这种保守风格,但它不理解你的场景只需要一个4位计数器,每16拍翻转一次。面对这种情况,我的建议是在提示词里明确写出位宽和计数目标,甚至给出计数行为的伪代码,让AI照着实现,而不是自由发挥。
5.2 状态机死锁怎么定位
AI写的状态机多了之后,最容易遇到的就是死锁。现象是仿真跑到某一拍之后,某个状态就再也不变了,而看起来代码里的转移条件似乎都有覆盖。
定位方法我推荐两步走。第一步,用形式化验证工具做可达性分析,直接列出每个状态在约束条件下是否可达、是否存在所有状态都无法跳出的死区。没有形式化工具的话,就用最笨的办法,在仿真里把状态寄存器的值拉出来,遍历所有跳转条件,逐个排除。第二步,检查状态机的默认分支,AI经常把默认状态设成一个“保留状态”,但实际上永远无法跳转到正常流程,这就是死锁陷阱。
说到底,状态机的本质是一个反馈系统,任何一步转移到你没想到的死区,系统就再也回不来了。AI生成的代码尤其容易出现这种情况,因为它总是想把所有防御性分支都画满,结果反而把系统复杂化。
5.3 一次完整的AI开发RTL复盘
这里以一个具体的项目做一次完全复盘。项目需求是做一个AHB到APB桥的最低配模块,我把它交给AI,从结果来看整体可用,但经历了三轮返工。
第一轮,AI生成的代码综合后报Latch warning,原因是在组合逻辑里没有给某个分支赋默认值。第二轮,仿真通过但Lint报跨时钟域违规,原来AI在桥接模块里插入了一个多余的异步FIFO,而我们项目这个桥根本不需要跨时钟域处理,我要求的跨时钟域保护被它“贴心”地扩张了。第三轮,形式化验证发现状态机存在一个不可达的保护状态,于是把状态数砍掉,最终才得到一版能用的RTL。
整个过程大概花费了半天时间,但如果我们没有完整验证流程,可能直接就把不可达状态带进下个阶段了。所以我的结论是:AI写RTL的效率红利真实存在,但前提是团队必须有足够的验证能力和评审能力。如果你所在的团队连仿真环境都不完善,那我不建议你让AI参与RTL开发,否则你就是在给自己埋雷。
5.4 我的安全边界建议
最后说一说安全边界。我个人的建议是,AI可以成为RTL工程师的加速器,但绝不能成为设计决策者。时钟、复位、DFT、跨时钟域、低功耗这些关系到芯片能否点亮、量产良率的领域,必须保留人工把控。模块级的小型功能、寄存器配置、测试平台生成、文档注释这些领域,可以大胆交给AI并配合评审闭环。
不少同行会问:“那AI以后会不会取代RTL工程师?”我的看法是,它先能把状态机写得不死锁、把复位风格统一、把组合逻辑环问题解决掉再说。在那之前,它折腾我们,我们也折腾它,这个过程本身就是行业技术更好用的预演。说到底,所有这一轮轮的折腾,都是为了让AI在芯片设计里真正落地的那天,我们已经有足够经验去驾驭它。