1. 从 783 道 Verilog 考题说起:AI 写硬件代码的真实水位
硬件圈最近有个话题热度一直没降下来:大模型到底能不能写 RTL。软件那边 Copilot 已经帮人补全了几十亿行代码,但硬件描述语言这边,情况一直很微妙。NVIDIA 放出的 CVDP(Comprehensive Verilog Design Problems)基准,把这件事从"感觉能用"拉到了"拿数据说话"的层面——783 道 Verilog 考题,覆盖从组合逻辑到复杂时序、从语法填空到完整模块设计,直接给各路 AI 模型做了一次摸底考试。
我自己是从业多年的 RTL 设计工程师,日常写 Verilog 和 SystemVerilog,也一直在试各种 AI 辅助工具。看到这个基准的第一反应是:终于有人把评测做得像样了。之前大家测 AI 写 Verilog,要么拿几个玩具例子(比如写个计数器、写个状态机),要么就是让模型解释一段代码,根本测不出真实工程能力。CVDP 这套题不一样,它把硬件设计里那些真正让人头疼的东西——时序约束、复位策略、位宽匹配、跨时钟域处理——都塞进了考题里。
这篇文章我想聊的不是"AI 行不行"这种二元结论,而是把 CVDP 这个基准拆开看:它到底考了什么、怎么考的、AI 在哪些题型上翻车、哪些题型上表现超出预期,以及这些结果对一线 RTL 工程师意味着什么。如果你正在用 AI 辅助写 Verilog,或者正在评估要不要把 AI 引入硬件开发流程,这篇应该能给你一些实在的参考。
先说结论方向:AI 在 Verilog 上的表现,呈现出非常明显的"两极分化"。语法层面的事情它做得相当好,但一旦涉及设计意图理解、时序推理、边界条件处理,翻车率就上来了。这个分化不是随机的,背后有清晰的原因,后面会逐层拆解。
2. CVDP 基准到底考什么:783 道题的分类逻辑
2.1 为什么硬件代码评测比软件代码评测难做
软件代码评测相对好做,因为软件有明确的输入输出,跑一遍测试用例就知道对不对。硬件代码不一样,Verilog 写出来是描述电路的,它的"正确性"至少包含三个层面:功能正确、时序正确、可综合。功能正确只是最低要求,一段 Verilog 功能仿真过了,综合出来可能是锁存器一堆、时序违例、面积爆炸。更麻烦的是,很多硬件设计问题在仿真阶段根本暴露不出来,要等到综合、布局布线、甚至流片之后才炸。
CVDP 的设计者显然清楚这一点。783 道题不是随便凑的,它按难度和题型做了分层。我梳理了一下,大致可以分成这么几类:
| 题型类别 | 占比估算 | 典型考察点 | AI 表现趋势 |
|---|---|---|---|
| 语法与基础结构 | 约 20% | 模块声明、端口定义、赋值语句 | 较好 |
| 组合逻辑设计 | 约 25% | 多路选择、编码器、算术运算 | 中等偏上 |
| 时序逻辑设计 | 约 30% | 计数器、状态机、移位寄存器 | 中等 |
| 复杂模块设计 | 约 15% | FIFO、仲裁器、协议接口 | 偏弱 |
| 调试与修复 | 约 10% | 找 bug、改时序、修位宽 | 波动大 |
这个分类不是官方给的,是我根据公开的题目样本和评测报告反推的。核心逻辑是:越靠近"翻译人类意图"的题,AI 越容易翻车;越靠近"模式匹配"的题,AI 越稳。
2.2 题目难度的三个梯度
CVDP 的题目难度大致分三档,这个分档方式很值得说道。
第一档是"单点知识"题。比如给你一个不完整的模块,让你补一个 always 块,或者让你把一段二进制转格雷码的组合逻辑写出来。这类题的特点是:答案空间小,正确写法基本唯一,AI 只要见过类似模式就能写对。我实测过,这类题主流大模型的通过率能到 70% 以上。
第二档是"多知识点组合"题。比如让你设计一个带使能、带复位、带溢出标志的计数器,或者写一个支持优先级仲裁的 arbiter。这类题需要模型同时处理多个约束,任何一个约束理解错就全错。通过率明显下降,大概在 40% 到 60% 之间波动。
第三档是"设计意图推理"题。这类题最狠,它不直接告诉你"写一个 FIFO",而是给一段描述或者一个不完整的接口,让你推断出设计意图再实现。比如"设计一个模块,输入是两个时钟域的信号,输出要保证不丢失数据"——这里面的坑太多了:要不要做同步、用几级触发器、空满标志怎么产生、深度怎么定。这类题 AI 的通过率经常掉到 30% 以下。
这里有个关键认知:AI 写 Verilog 的能力,不是一条平滑的曲线,而是断崖式的。简单题它做得比新手快,但复杂题它可能比新手还危险,因为新手知道自己不会,AI 会一本正经地给你一段看起来对、实际有坑的代码。
2.3 评测方式:不只是"跑通就行"
CVDP 的评测不是简单的"仿真过了就算对"。据我了解,它的评分维度至少包括:
- 功能正确性:用 testbench 跑仿真,看输出是否符合预期。
- 可综合性:检查代码是否包含不可综合的构造,比如延时语句、initial 块里的复杂逻辑。
- 时序合理性:看是否引入了不必要的锁存器、是否有组合环路。
- 代码质量:命名规范、注释、模块化程度。
这个多维评分很关键。因为 AI 很容易写出"仿真能过但综合会炸"的代码。比如它可能在一个组合 always 块里漏了 else 分支,仿真时恰好没触发那个条件所以过了,但综合出来就是一个锁存器。CVDP 把这类问题单独拎出来扣分,说明评测设计者是懂行的。
3. AI 在 Verilog 上的真实表现:哪些题稳,哪些题崩
3.1 语法层面:AI 确实比人快
先说好消息。在纯语法和基础结构层面,AI 的表现相当能打。我拿几个典型场景测过:
场景一:模块框架生成。你告诉 AI"写一个 8 位宽、带同步复位、带写使能的寄存器模块",它基本能一次写对。端口方向、位宽声明、always 块敏感列表,这些它都记得住。新手写这个经常犯的错——比如把reg和wire搞混、敏感列表漏信号——AI 反而很少犯。
场景二:常见逻辑翻译。比如"把二进制转成格雷码",AI 能直接写出assign gray = bin ^ (bin >> 1);。这个转换用组合逻辑而不是时序逻辑,原因在于格雷码转换是纯组合函数,当前输出只取决于当前输入,不需要存储状态。AI 对这类经典模式掌握得很好。
场景三:测试平台搭建。让 AI 写一个简单的 testbench,生成时钟、给激励、打印结果,它做得又快又规范。这部分确实能省不少时间。
但这里有个陷阱:AI 写语法正确的代码,不代表它理解这段代码在硬件上意味着什么。我见过 AI 写出这样的代码:
always @(posedge clk) begin if (enable) data_out <= data_in; end这段代码语法没问题,但它隐含了一个设计决策:enable 为低时输出保持。如果设计意图是"enable 为低时输出清零",那这段代码就是错的。AI 不会问你"enable 为低时你想怎样",它会默认选一个它见过的常见写法。这就是"模式匹配"和"设计理解"的区别。
3.2 时序逻辑:翻车的重灾区
时序逻辑是 AI 表现明显下滑的地方。我分析了一下 CVDP 里时序题的失败案例,问题主要集中在几个方面。
复位策略混乱。同步复位还是异步复位,这是硬件设计的基本决策。AI 经常混用,比如在一个模块里,有的触发器用同步复位,有的用异步复位,综合出来复位树会出问题。更隐蔽的是复位值的处理:AI 有时会给复位值赋一个非零值,但没考虑这个值在后续逻辑里是否合理。
时钟域处理草率。只要题目涉及多时钟域,AI 的出错率就飙升。它知道要用两级触发器做同步,但经常忘记:同步器只能用于单比特信号,多比特信号要用握手或者异步 FIFO。我见过 AI 直接把一个多比特计数器用两级触发器同步过去,这在硬件上是灾难——各位到达时间不同,会采到中间态。
状态机设计不完整。让 AI 写状态机,它通常能写出状态转移,但经常漏掉:默认状态处理、非法状态恢复、输出寄存。比如一个三段式状态机,它可能只写两段,把状态转移和输出混在一起,导致输出有毛刺。
// AI 常写的"看起来对"的状态机 always @(posedge clk) begin case (state) IDLE: if (start) state <= RUN; RUN: if (done) state <= IDLE; endcase end // 问题:没有 default 分支,综合可能产生锁存器 // 问题:没有复位,上电状态不确定3.3 复杂模块:AI 的"想象力"不够
到了 FIFO、仲裁器、协议接口这个层级,AI 的表现就更不稳定了。核心问题不是它不会写代码,而是它不会做设计权衡。
以异步 FIFO 为例。一个合格的异步 FIFO 设计,需要处理:读写指针的格雷码转换、空满标志的跨时钟域同步、深度的选择。AI 通常能写出主体结构,但在细节上经常出问题:
- 空满标志的判断条件写错,导致要么提前报满(浪费空间),要么晚报满(覆盖数据)。
- 格雷码转换只做了一半,读写指针一个用格雷码一个用二进制。
- 深度不是 2 的幂,导致格雷码回绕判断失效。
这些问题的共同点是:它们不是语法问题,而是设计经验问题。AI 没有在真实项目里被这些坑坑过,所以它不知道这些地方容易出错。
3.4 调试与修复:表现最不稳定
CVDP 里有一类题是给一段有 bug 的 Verilog,让 AI 找出来并修复。这类题 AI 的表现波动极大。
简单的 bug,比如位宽不匹配、敏感列表漏信号,AI 找得挺准。但稍微复杂一点的,比如"这段代码在特定输入序列下会死锁",AI 就经常找不到,或者找到了但改错了地方。
我自己的经验是:让 AI 调试 Verilog,它更像一个"语法检查器"而不是"逻辑分析器"。它能发现代码层面的问题,但发现不了设计层面的问题。比如一个跨时钟域的信号没有同步,AI 可能不会主动指出来,因为从语法上看那段代码完全合法。
4. 把 AI 用对:一线 RTL 工程师的实操方法
4.1 什么任务适合交给 AI
基于 CVDP 的结果和我自己的实践,我把 AI 能干的活分成三档:
放心交给 AI 的:
- 模块框架和端口声明生成
- 常见组合逻辑翻译(编解码、算术、多路选择)
- 测试平台搭建和激励生成
- 代码格式化和注释补全
- 简单 bug 的语法层面排查
需要人工审核的:
- 时序逻辑设计(复位、时钟域、状态机)
- 中等复杂度模块(计数器、移位寄存器、简单协议)
- 代码综合结果检查
不建议直接用的:
- 复杂模块架构设计(FIFO、仲裁器、DMA)
- 跨时钟域方案设计
- 时序约束和综合策略
- 任何涉及设计权衡的决策
这个分档不是绝对的,取决于你的经验水平。如果你本身是资深工程师,AI 写的时序逻辑你能一眼看出问题,那可以多用一些。如果你是新手,AI 写的复杂模块你根本判断不了对错,那就别用。
4.2 提示词怎么写才能让 AI 少犯错
跟 AI 要 Verilog 代码,提示词的质量直接决定输出质量。我总结了一个"四要素"模板:
- 接口定义:明确端口名、方向、位宽。
- 时序要求:时钟频率、复位类型、是否有使能。
- 功能描述:用状态转移或者数据流的方式描述行为。
- 约束条件:可综合性要求、面积/速度偏好、编码风格。
举个例子,不要这样问:
"帮我写一个 FIFO"
要这样问:
"写一个同步 FIFO,深度 16,位宽 8 位。端口:clk、rst_n(异步低有效复位)、wr_en、rd_en、data_in[7:0]、data_out[7:0]、full、empty。要求:满时忽略写、空时忽略读,空满标志用组合逻辑输出。代码要可综合,不要用 initial 块。"
后一种问法,AI 的输出质量会高很多。因为你把设计决策都替它做了,它只需要做翻译工作,而翻译正是它擅长的。
4.3 一个真实的辅助设计流程
我现在的工作流大致是这样的:
第一步:让 AI 生成框架。把接口和基本结构描述清楚,让 AI 写出模块骨架和端口声明。这一步基本不用改。
第二步:自己写核心逻辑。时序逻辑、状态机、跨时钟域处理,这些我自己写。不是因为 AI 写不了,而是因为我自己写更快,而且不用花时间检查 AI 的错。
第三步:让 AI 写测试平台。这是 AI 最省时间的地方。给它模块接口,让它生成激励和检查逻辑,我再改改就能用。
第四步:让 AI 做代码审查。把我写好的代码丢给 AI,问它"这段代码有没有可综合性问题、有没有位宽不匹配、有没有锁存器风险"。它经常能发现一些我疏忽的小问题。
第五步:综合和时序检查自己做。这部分 AI 帮不上忙,得靠工具和经验。
这个流程下来,AI 大概能帮我省 20% 到 30% 的时间,主要集中在框架搭建和测试平台这两块。核心设计还是自己来。
5. 常见问题与排查技巧实录
5.1 AI 写的 Verilog 高频问题速查表
| 问题现象 | 根本原因 | 排查方法 | 修复方式 |
|---|---|---|---|
| 综合出锁存器 | 组合 always 块分支不全 | 检查 if/case 是否有 else/default | 补全分支或改用时序逻辑 |
| 仿真过但上板不对 | 复位策略不一致 | 检查所有触发器的复位类型 | 统一复位策略 |
| 跨时钟域数据错乱 | 多比特信号直接同步 | 检查是否有跨时钟域信号 | 改用握手或异步 FIFO |
| 状态机跑飞 | 缺少默认状态处理 | 检查 case 是否有 default | 加 default 回到 IDLE |
| 位宽不匹配警告 | 赋值两侧位宽不一致 | 看综合警告 | 显式位宽转换 |
| 时序违例 | 组合逻辑路径太长 | 看时序报告 | 插入流水线寄存器 |
5.2 几个我踩过的坑
坑一:AI 的"默认正确"陷阱。有一次我让 AI 写一个带使能的计数器,它默认写成了"使能无效时保持"。但我的设计意图是"使能无效时清零"。这个差异在仿真时没暴露,因为我的测试激励恰好没覆盖使能无效的情况。后来上板才发现。教训是:AI 不会问你的设计意图,它只会选一个常见写法。所有涉及"默认行为"的地方,都要明确告诉它。
坑二:AI 对复位值的处理。AI 经常给复位值赋一些"看起来合理"的数,比如把地址寄存器复位成 0,把数据寄存器复位成 0。但有些设计里,复位值是有讲究的。比如一个 FIFO 的读指针和写指针,复位值必须相等,否则空满标志会错。AI 有时会给它们赋不同的值。这个必须人工检查。
坑三:AI 写的 testbench 太"温柔"。AI 生成的测试激励通常只覆盖正常路径,不覆盖边界条件。比如测一个计数器,它只测正常计数,不测溢出、不测复位中途生效、不测使能跳变。我现在的做法是:让 AI 生成基础 testbench,然后自己加边界用例。
坑四:AI 对"可综合"的理解有偏差。有些构造在仿真时能用,但综合工具不支持。比如#10延时、initial块里的复杂逻辑、while循环。AI 有时会写出这些,因为它训练数据里仿真代码比综合代码多。拿到 AI 的代码,第一件事是检查有没有这些不可综合的构造。
5.3 怎么判断 AI 写的代码能不能用
我总结了一个"三查"原则:
一查语法和可综合性。跑一遍 lint 工具,看有没有警告。重点看:锁存器推断、位宽不匹配、不可综合构造。
二查时序逻辑。人工检查所有 always 块:复位策略是否统一、敏感列表是否完整、是否有组合环路。
三查边界条件。自己写几个边界测试用例:复位中途生效、使能跳变、计数器溢出、FIFO 满/空。这些是 AI 最容易漏的地方。
这三查做完,基本能过滤掉 80% 的问题。剩下的 20% 需要靠仿真和上板验证。
6. 这件事对 RTL 工程师意味着什么
6.1 短期:AI 是加速器,不是替代者
从 CVDP 的结果看,AI 在 Verilog 上的能力,大致相当于一个"熟练的初级工程师"——语法熟、常见模式熟,但设计经验和判断力不足。它能帮你写框架、写测试、查语法,但核心设计决策还得自己来。
这个定位其实挺合理的。硬件设计和软件开发不一样,软件出 bug 可以热修复,硬件出 bug 要重新流片,成本差好几个数量级。所以硬件行业对 AI 的容错率天然更低。AI 在软件领域可以"先跑起来再修",在硬件领域不行,必须"一次做对"。
6.2 中期:工作流会变,但核心能力不变
AI 的介入会改变 RTL 工程师的工作方式。以前你可能花 30% 时间写框架和测试,现在这部分可以交给 AI,你专注于核心设计。但核心能力——时序推理、架构设计、权衡决策——这些 AI 替代不了,反而会变得更值钱。
因为当 AI 能写基础代码时,区分工程师水平的就不是"能不能写出代码",而是"能不能判断代码对不对、能不能设计出正确的架构"。这跟软件领域发生的事一样:Copilot 普及后,会写 CRUD 的人不值钱了,会做架构设计的人更值钱了。
6.3 长期:AI 和 EDA 工具的融合
我个人的判断是,AI 写 Verilog 这件事,最终不会以"聊天窗口"的形式存在,而是会融入 EDA 工具链。想象一下:综合工具内置 AI,能自动识别代码里的时序问题并给出修复建议;仿真工具内置 AI,能自动生成覆盖率驱动的测试激励;布局布线工具内置 AI,能根据设计意图优化约束。
这个方向已经在发生了。一些 EDA 厂商已经在做 AI 辅助的综合和验证。CVDP 这样的基准,本质上是在为这个方向做技术储备——先搞清楚 AI 在 Verilog 上的能力边界,再决定怎么把它集成到工具里。
6.4 给不同阶段工程师的建议
新手:可以用 AI 学语法和常见模式,但不要用它替代理解。AI 写的代码,你要能逐行解释为什么这么写。如果解释不了,说明你还没学会。
中级:用 AI 加速重复性工作,把省下来的时间花在架构设计和时序分析上。这两个能力是往上走的关键。
资深:用 AI 做代码审查和测试生成,但核心设计自己把关。同时关注 AI 和 EDA 工具融合的趋势,这可能是下一个效率提升点。
最后分享一个我自己的小习惯:每次 AI 给我一段 Verilog,我都会问自己一个问题——"如果这段代码上板出问题,最可能是什么原因?"这个习惯逼着我去检查那些 AI 容易忽略的地方:复位、时钟域、边界条件。用了大半年,确实帮我避开了不少坑。AI 是个好工具,但硬件设计这件事,最终还是要靠工程师的判断力兜底。