用 AI 做 RTL 设计:DeepSeek 4.0 pro、GLM-5.1、Kimi-2.6 实测对比
前言
最近在做一个有趣的实验:让不同的 AI 模型,在完全相同的条件下,独立完成同一个硬件设计任务,然后客观对比结果。
任务是什么?用 Verilog 实现国密 SM3 杂凑算法的核心压缩模块。这不是写个 Hello World,而是要完整跑通从架构设计、代码生成、Lint 检查、功能仿真到逻辑综合的 8 级自动化流水线。
参赛选手:DeepSeek-4.0-pro、GLM-5.1、Kimi-2.6。
先说结论:GLM-5.1 赢了,而且赢得不少。
但过程比结论更有价值。下面是完整的客观数据和分析。
实验设计
控制变量
为了保证公平,我们严格控制了以下条件:
- 相同的输入:三份一模一样的需求文档(
requirement.md)和参考资料(SM3 标准草案) - 相同的工具链:VeriFlow 自动化流水线,统一使用 Icarus Verilog + Yosys
- 相同的流水线配置:8 个阶段完全一致(architect → microarch → timing → coder → skill_d → lint → sim → synth)
- 独立的执行环境:每个模型独立运行,互不干扰
SM3 算法背景
SM3 是中国国家密码管理局发布的密码杂凑算法标准(GM/T 0004-2012),用于数字签名和验证、消息认证码的生成与验证等场景。其核心是一个 64 轮迭代压缩函数,需要正确实现 FF/GG 布尔函数、P0/P1 置换、消息扩展等模块。
评估维度
我们从 8 个维度评估:仿真通过率、Lint 质量、代码规范、面积效率、测试覆盖、执行耗时、文件整洁度、文档质量。
一、Pipeline 状态:表面都是 "全绿"
先看官方记录——三个模型的 pipeline_state.json 都显示 8/8 阶段全部通过:
| 维度 | DeepSeek | GLM-5.1 | Kimi-2.6 |
|---|---|---|---|
| 完成阶段数 | 8/8 | 8/8 | 8/8 |
| 失败阶段 | 0 | 0 | 0 |
| 总耗时 | ~2h 2min | ~30min | ~2h 3min |
看起来大家都很完美?但当你打开实际的日志文件,故事就不一样了。
这也是本文最想分享的一个发现:自动化流水线的 "全绿" 可能掩盖真实的质量问题。
二、仿真结果:核心指标,差距明显
仿真是硬件设计的核心验证手段。代码写得再漂亮,仿真不通过等于零。
实际 sim.log 内容
| 模型 | sim.log | 仿真结果 | 测试数 | 失败项 |
|---|---|---|---|---|
| DeepSeek | 51 行 | FAIL | 7 个 | 2 个失败 |
| GLM-5.1 | 31 行 | ALL PASS | 4 个 | 无 |
| Kimi-2.6 | 0 行 | 无数据 | N/A | 文件为空 |
DeepSeek 的具体失败
DeepSeek 虽然写了最多的 7 个测试用例,但有 2 个失败了:
Test 3: Non-Last Block
[FAIL] ready=1 after non-last block: condition is false
→ 处理非 last block 后,ready 信号没有恢复
Test 6: msg_valid ignored when not ready
[FAIL] expected: 0x66c7f0f462eeedd9...
got: 0xf13f90dee115a7da...
→ 模块忙时没有忽略 msg_valid,内部状态被污染,hash 结果完全错误
这是一个很典型的硬件协议 bug:当模块正在计算时,外部不应该能通过 msg_valid 端口干扰内部状态。 这就像你在做饭,有人硬往锅里扔了块石头——菜就废了。
Kimi-2.6 的问题更严重
sim.log 文件完全是空的(0 字节)。这意味着:
- 仿真可能根本没运行
- 或者运行了但输出丢失了
- 无论如何,功能正确性没有任何证据
GLM-5.1:唯一真正全通过的
Test 1: Reset Behavior — PASS (3/3)
Test 2: Single Block 'abc' (GM/T 0004-2012) — PASS
Test 3: Ready Recovery After hash_valid — PASS
Test 4: Second Block Processing — PASS
ALL TESTS PASSED
稳扎稳打,4 个测试全绿,正确的 SM3 hash 值:66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0。
三、代码质量:GLM-5.1 最规范
代码量对比
| 模块 | DeepSeek | GLM-5.1 | Kimi-2.6 |
|---|---|---|---|
| sm3_core.v | 107 行 | 92 行 | 89 行 |
| sm3_compress.v | 291 行 | 266 行 | 281 行 |
| sm3_fsm.v | 163 行 | 151 行 | 147 行 |
| sm3_w_gen.v | 118 行 | 193 行 | 111 行 |
| 总计 | 679 行 | 702 行 | 628 行 |
代码量差距不大,但质量差异显著。
接口设计差异
这里暴露了一个重要问题:三个模型产出的接口居然不一致。
| 端口/特性 | DeepSeek | GLM-5.1 | Kimi-2.6 |
|---|---|---|---|
| reset 极性 | active-high | active-low | active-high |
| ack 握手 | 有 | 无 | 有 |
| FSM 状态数 | 5 | 4 | 4 |
GLM-5.1 用了 active-low reset(rst_n),另外两个用 active-high(rst)。更关键的是,GLM-5.1 没有 ack 握手端口——它的 hash_valid 只维持 1 个时钟周期就消失了。如果下游模块恰好在那个周期没采样到,hash 值就永远丢了。
这在真实的 SoC 环境中是个严重的可靠性问题。
编码风格的关键差异:阻塞赋值 vs 非阻塞赋值
这是 Verilog 设计中的经典问题。DeepSeek 和 Kimi-2.6 都在 posedge clk 时序逻辑块中使用了阻塞赋值(=)来处理数组元素:
// DeepSeek / Kimi-2.6 的写法(有时序逻辑中使用阻塞赋值的风险)
always @(posedge clk) begin
if (update_v_en) begin
v_reg[0] = v_reg[0] ^ a_reg; // 阻塞赋值
v_reg[1] = v_reg[1] ^ b_reg;
// ...
end
end
GLM-5.1 用命名标量寄存器代替数组,全程使用非阻塞赋值(<=):
// GLM-5.1 的写法(更规范)
always @(posedge rst_n or posedge clk) begin
if (!rst_n) begin
V0_reg <= 1'b0;
// ...
end else if (update_v_en) begin
V0_reg <= V0_reg ^ A_reg; // 非阻塞赋值
V1_reg <= V1_reg ^ B_reg;
// ...
end
end
在仿真中两种写法可能表现相同,但在综合工具中行为可能不一致。GLM-5.1 的写法更安全、更符合 Verilog 最佳实践。
ROL(Tj, j) 的实现:三种思路
SM3 算法中需要计算 ROL(Tj, j)——一个可变位数的循环左移。三个模型给出了完全不同的实现:
DeepSeek——移位拼接法:
wire [5:0] rot_amt = round_cnt[5:0];
wire [31:0] T_rotated = (T_sel << rot_amt) | (T_sel >> (6'd32 - rot_amt));
GLM-5.1——5 级桶形移位器(MUX 级联):
// stage 4: shift by 16
wire [31:0] s4 = rot_amt[4] ? {t[15:0], t[31:16]} : t;
// stage 3: shift by 8
wire [31:0] s3 = rot_amt[3] ? {s4[23:0], s4[31:24]} : s4;
// ... 逐级递减
Kimi-2.6——32 路全枚举 case 语句:
function [31:0] rol32;
input [31:0] x;
input [5:0] n;
case (n)
6'd0: rol32 = x;
6'd1: rol32 = {x[30:0], x[31]};
// ... 32 个 case ...
6'd31: rol32 = {x[0], x[31:1]};
endcase
endfunction
三种实现功能都正确。GLM-5.1 的桶形移位器在综合后面积最优、时序最好;Kimi-2.6 的 32-case 写法虽然正确,但综合工具需要展开所有分支,代码量也大得多。
四、Lint 检查:GLM-5.1 唯一零警告
| 模型 | 结果 | 警告 |
|---|---|---|
| DeepSeek | 日志为空 | N/A |
| GLM-5.1 | PASS | 0 errors, 0 warnings |
| Kimi-2.6 | PASS | 21 warnings |
Kimi-2.6 的 21 个警告全部是同一类型:
warning: @* is sensitive to all 16 words in array 'w_reg'.
warning: @* is sensitive to all 8 words in array 'v_reg'.
这是因为 always @* 在遇到数组时,会将数组的所有元素加入灵敏度列表。虽然功能上通常没问题,但可能影响仿真性能和综合结果。
五、综合结果:面积差异 12%
三个模型都用 Yosys 综合到通用门级:
| 指标 | DeepSeek | GLM-5.1 | Kimi-2.6 |
|---|---|---|---|
| 总 cell 数 | 4,647 | 4,420(最小) | 5,017(最大) |
| compress cells | 3,332 | 3,114 | 3,701 |
| w_gen cells | 1,249 | 1,249 | 1,249 |
| FF 数 | ~1,038 | ~1,038 | ~1,040 |
| Synth Warnings | 1 | 0 | 3 |
直观对比:
面积对比 (Yosys cells):
DeepSeek ████████████████████████████████████████████ 4,647
GLM-5.1 ██████████████████████████████████████████ 4,420 ← 最小
Kimi-2.6 ██████████████████████████████████████████████ 5,017 ← 最大
有意思的是,sm3_w_gen(消息扩展模块)三个模型都是 1,249 cells,完全一致。差异全部来自 sm3_compress(压缩函数)——GLM-5.1 的命名标量寄存器写法和桶形移位器在综合时确实更紧凑。
六、调试效率:看 testbench 文件就知道
这个维度最能体现模型的"思考方式"差异。
| 模型 | Testbench 文件数 | 总行数 |
|---|---|---|
| DeepSeek | 1 个 | 397 行 |
| GLM-5.1 | 1 个 | 223 行 |
| Kimi-2.6 | 20 个 | 1,601 行 |
Kimi-2.6 的 tb/ 目录长这样:
debug_tb.v, debug_ready.v, debug_fsm.v, debug_fsm2.v,
debug_compress.v, debug_w_gen.v, debug_integrated.v,
debug_quick.v, tb_debug.v, tb_monitor.v, tb_trace.v,
tb_compare.v, tb_rounds.v, tb_rounds2.v,
tb_debug_test3.v, tb_debug_test4.v, tb_debug_test4b.v,
tb_final.v, tb_sm3_core.v ...
这不是精心设计的测试套件,这是调试过程的化石。每遇到一个问题就写一个新的 testbench,编译、运行、看输出,再写下一个。19 个调试文件背后,是一次次的"盲试"。
与之对比,GLM-5.1 只有一个 223 行的 testbench,4 个测试全通过,干净利落。不产生调试垃圾文件本身就是效率的证明。
七、文档质量:各有所长
| 文档 | DeepSeek | GLM-5.1 | Kimi-2.6 |
|---|---|---|---|
| micro_arch.md | 443 行,最详细 | 272 行,简洁 | 286 行 |
| behavior_spec.md | 429 行 | 367 行 | ~393 行 |
| development_log | 389 行中文 | 无 | 658 行英文 |
DeepSeek 的文档最详尽,且用了中文撰写开发日志,记录了 7 个 bug 的定位和修复过程。Kimi-2.6 甚至把完整 RTL 源码贴进了开发日志。GLM-5.1 的文档风格最干净——"不需要 debug log 因为没有 bug 要记"。
八、综合评分
| 维度 (权重) | DeepSeek | GLM-5.1 | Kimi-2.6 |
|---|---|---|---|
| 仿真通过 (30%) | 3/10 | 10/10 | 2/10 |
| Lint 质量 (10%) | 5/10 | 10/10 | 7/10 |
| 代码规范 (15%) | 7/10 | 9/10 | 6/10 |
| 面积效率 (15%) | 8/10 | 9/10 | 6/10 |
| 测试覆盖 (15%) | 8/10 | 7/10 | 4/10 |
| 耗时 (10%) | 4/10 | 10/10 | 4/10 |
| 文件整洁 (5%) | 8/10 | 10/10 | 3/10 |
| 加权总分 | 6.15 | 9.15 | 4.45 |
排名总结
第一名:GLM-5.1(9.15 分) — 仿真全通过,lint 零警告,面积最小,30 分钟完成。但接口设计有不足:无 ack 握手,hash_valid 仅单周期有效。
第二名:DeepSeek(6.15 分) — 测试最全面(7 个测试、ack 握手),但核心逻辑有 2 个 bug 导致仿真失败。"想得多"不等于"做对了"。
第三名:Kimi-2.6(4.45 分) — sim.log 为空是致命伤,功能正确性无从谈起。20 个调试 testbench 暴露了低效的"试错式"工作模式。
九、经验教训(重点)
1. 自动化流水线的 "全绿" 可能是假象
这是本次实验最值得警惕的发现。三个模型在 pipeline 状态中都标记为"全部成功",但实际检查 log 发现:
- DeepSeek 有 2 个仿真测试失败
- Kimi-2.6 的仿真日志是空的
- 只有 GLM-5.1 是真正全通过
原因可能是 hook 只检查了命令的退出码,而没有解析日志中的 PASS/FAIL 关键字。
对任何 CI/CD 流水线的启示:不要信任 exit code,要解析实际输出。
2. "一次做对" 比 "反复修补" 重要得多
GLM-5.1 用 30 分钟一次通过,其他两个用了 2 小时还在修 bug。在硬件设计中,一个模型能一次性生成正确的 RTL,远比它能写出多少调试测试更重要。
选模型时,优先看"首次通过率",而不是"最终修复能力"。
3. 调试残留物是效率的反向指标
如果 AI 完成一个任务后留下了大量中间文件(debug TB、临时编译产物、多次迭代的日志),说明它的调试过程是低效的。好的 AI 应该在写代码之前就想清楚,而不是写完了靠试错来验证。
4. 接口规范必须在第一步就锁定
三个模型产出的接口不一致(reset 极性、握手协议),这在团队协作中是灾难性的。应该在架构设计阶段就把接口契约写死(比如 spec.json),后续所有阶段严格遵守。
5. 一个测试向量不够
三个模型都只用了 GM/T 0004-2012 标准中的 "abc" 测试向量。这就像你声称你的 SHA-256 实现正确,但只测了一个输入——说服力有限。
至少需要覆盖:空消息、边界长度、多块链式、其他官方测试向量。
6. 代码规范 ≠ 工程完整
GLM-5.1 代码最规范,但缺少 ack 握手是个工程缺陷。DeepSeek 有 ack 握手但代码用了阻塞赋值。规范性和工程完整性需要同时追求。
写在最后
这次实验让我对 AI 做硬件设计有了更务实的认识:
- AI 确实能完成有一定复杂度的 RTL 设计(SM3 压缩核心),不是玩具 demo
- 不同模型之间的差距是真实存在的,而且体现在多个维度
- 自动化验证流水线本身也需要被验证——"全绿"不代表真没问题
- 目前所有模型都还不够"工程化"——接口不一致、测试覆盖不足、调试效率低等问题普遍存在
如果你也在做 AI 辅助硬件设计的探索,欢迎交流。