FEATURED · 精选文章

AI生成Verilog如何摆脱“巨型代码块”?HiVeGen层次化生成解析

发布时间 / 2026/9/8 14:57:28
来源 / 创域科博编辑部
栏目 / 资讯中心
AI生成Verilog如何摆脱“巨型代码块”?HiVeGen层次化生成解析 刚接触用AI写Verilog的时候估计不少人和我有同样的感受明明只是要一个小功能模块大模型经常甩给你一个两三百行的module要是让它“写一个完整的Cache”或者“实现一个支持AXI的UART”它恨不得把整个芯片塞进一个文件里。更夸张的是这些生成结果里所有状态机、计数器、接口逻辑全部堆在一个always块中甚至把寄存器堆、FIFO、仲裁逻辑全部硬塞进同一个module的端口列表里review的时候血压直接拉满。这种现象在ICLAD 2025 的 Best Paper 中被正式摆上了台面。这篇获奖论文叫 HiVeGenHierarchical Verilog Generation专门研究了“AI生成Verilog为什么总是一片平铺的大代码块”这个问题并给出了一套层次化生成方案。我花了一晚上精读这篇论文结合自己平时用AI写RTL、做验证的经验今天把这篇文章的核心逻辑拆给各位硬件工程师听。这不仅是论文内容梳理更是一次关于“怎么让大模型更好地辅助硬件设计”的方法论翻新。1. 先把问题说清楚AI为什么总爱“一锅端”1.1 大模型写RTL的“职业病”从哪来先说结论这还真不能全怪大模型。很多人以为AI写代码的逻辑和资深工程师一样先搭架构、再分模块、逐层例化最后再做集成。但实际上的工作方式完全不同大模型本质上是一个逐token生成文本的自回归模型它对你输入的prompt的响应是在概率空间里一步一步“猜”下一个字符。这种机制决定了它有几个致命倾向。第一个倾向是追求连续完整性。自回归模型在生成代码时会倾向于输出一段从头到尾中间不断裂的连续文本。你让它写一个“包含FIFO、状态机和数据通路的完整UART模块”它的训练数据告诉大家最安全、最符合用户表面期待的答案就是把FIFO、状态机、波特率发生器、数据通路全部糅合在一个module里面线性输出。如果它中途停下来告诉你“建议分成三个模块你分别生成”反而会让多数用户觉得“这AI不行写不完整”。第二个倾向是训练数据的分布偏差。大模型预训练时喂进去的Verilog语料很大一部分来自GitHub等公开仓库里的零散RTL文件。这些文件里占多数的是独立的module比如某个IP的单一文件、某个算法模块的单文件实现。真正来自大型芯片项目的多层级目录结构、几十个子模块互连的工程化代码反而不容易被完整采集。模型学习的统计规律自然偏向“一个文件一个module”的简单形态。第三个倾向是对硬件设计方法学的理解缺失。软件代码里一个函数长一点、一个类里代码多一点虽然不优雅但勉强还能跑。硬件代码的复杂度则完全不同一个巨型module意味着综合工具要花更长时间做逻辑优化和面积映射验证时功能覆盖率难以收敛后端布局布线时timing和congestion问题一抓一大把。可大模型没有做过芯片流片它在生成时并不会考虑这些下游代价。1.2 “巨型代码块”在真实项目中到底有多要命我见过不少同学直接用AI生成一个大模块然后拿去综合最后被各种工具问题折磨。这里我把巨型代码块的危害分成五个层面逐一说明。可读性与维护性层面一个1000行的module意味着至少五六百行的端口定义和信号声明两三组不同的状态机逻辑叠在一起。你review代码时光滚滚动条就要花十分钟。最难受的是AI还喜欢复制粘贴式命名state_next1、state_next2、data_buffer_1、data_buffer_2我甚至见过AI生成同一个信号的三种不同名称然后互相驱动的“名场面”。这种代码在代码评审时根本没法治只能让写的人自己回去反思。综合与实现层面综合工具处理大模块时通常会把这个模块当作一个整体来做逻辑优化。模块内部的逻辑层级越深、控制流越复杂综合工具收敛到目标频率所需的时间就越长。一个巨型组合逻辑块意味着关键路径的优化空间被限制在单个模块内部工具很难跨模块边界做合理的重定时和优化。验证与调试层面模块拆分的本质其实是一种“验证边界”。如果所有逻辑都在一个module里你只能靠顶层的testbench直接拉内部信号来调试。但商用EDA工具在正式验证流程中更倾向于用断言和属性检查这些检查如果全部集中在顶层一旦数据路径出了问题定位效率非常低。层次化设计能让你在子模块级别就锁定bug范围这比从顶层往下逐层深挖快得多。复用与迭代层面芯片设计里最值钱的资产是可复用的IP。如果AI生成的整个设计是一个不可分割的大模块那下次你想在一个新项目里复用它的一部分功能只能做移植手术把需要的逻辑从大module里抠出来再改端口。抠逻辑的时候又容易引入接口不匹配和跨模块信号依赖的坑整个过程费时费力。版本管理与协同层面多人协作时分割代码是基本操作。一个module一个文件每个人改自己的文件merge时的冲突概率低。而一个巨型module占了整个工程的核心文件多人同时改同一个文件每一次merge都是一场冲突大战。这种痛苦经历过的人自然懂。2. HiVeGen 到底在做什么核心思路拆解2.1 一句话理解这篇论文HiVeGen的核心主张其实非常朴素让AI像工程师一样先拆模块再分别实现最后做集成。它不是对大模型本身做改造而是设计了一套“生成策略”或者说“编排流程”让现有的LLM能够产出结构良好的层次化Verilog代码。论文的比测基线也很有意思直接把AI生成一个大模块和AI按层次化流程生成的结果做了对比发现层次化流程不仅让代码结构更好而且在编译通过率、仿真正确性、可读性评分这些维度上全面占优。这个结论符合一线工程师的直觉层次化是硬件设计的常识AI生成策略也应该继承这个常识而不是让常识迁就AI的原始输出习惯。2.2 三个台阶的生成流程按照论文的思路HiVeGen把生成过程分成了三个递进阶段我用自己的话复述一下。第一阶段是设计分解。拿到用户的自然语言设计需求后会让大模型先生成一个“微架构级别的设计方案描述”。这里要求模型以文本形式列出整个设计需要哪些子模块例如一个通信IP可能需要“发送端FIFO”“接收端FIFO”“链路层状态机”“CRC校验模块”“寄存器配置模块”等。同时还要说明每个子模块的职责边界和它们之间的数据流、控制流关系。这一阶段不生成任何RTL代码纯粹是在架构层面做规划。第二阶段是子模块逐个生成。按照第一阶段列出的模块清单依次为每个子模块单独生成Verilog代码。由于每个子模块的功能都被限制在较小的范围内生成结果相对短小逻辑也更清晰。这里还有一层细节是子模块的端口定义需要在前一阶段就确定。也就是说在架构描述阶段HiVeGen会要求大模型一并输出“端口接口列表”包括信号的位宽、方向、协议含义这样在生成每个子模块时端口定义和模块间互联已经有了统一协定。第三阶段是顶层集成。当所有子模块代码都生成完毕后再让大模型生成一个顶层module把这些子模块像搭积木一样例化起来完成信号连接。这个顶层模块通常非常薄主要负责例化、连线和一些必要的跨模块信号转换。除了生成流程本身HiVeGen还加入了自动检查和修复机制。每生成一步都用编译器做语法检查用仿真器做基础冒烟测试如果出现编译错误或端口不匹配会带着错误信息回喂给大模型让它自行修复。这个“生成-检查-修复”的闭环也是论文强调的一个重要设计。2.3 为什么层次化生成有实际收益论文的实验数据我不在此逐条罗列但从实操角度来说这套方案的收益是显而易见的。首先是问题边界可控。当生成一个子模块的代码出错时报错信息能精确指向这个模块修复时也只需要针对这个模块重新生成或者在这个模块的代码上进行小范围修改不需要让大模型重新生成整个大设计。从工程成本角度看这种精细化的容错方式效率高得多。其次是契合人的介入方式。现在的AI辅助EDA流程里工程师不可能完全当甩手掌柜。在层次化流程的每个阶段人都可以在关键节点进行干涉比如调整模块划分方式、指定某些模块采用特定的握手协议、修改接口位宽等。这种干涉比在巨型代码块里做外科手术式的修改要轻松得多而且不影响整体设计进度。第三是验证能够分层进行。子模块可以有自己的独立testbench顶层又有顶层集成测试。如果子模块验证充分顶层集成时遇到的接线错误定位范围和概率都会更小。论文中特别强调验证效率的大幅提升是层次化生成最大的隐性收益这我深表赞同。3. 论文关键技术细节精读3.1 模块拆分的粒度控制HiVeGen这套流程里最考验大模型能力的就是模块拆分的质量。模块拆得太粗每个子模块本身还是很大的代码块没有真正解决可维护性问题模块拆得太细又会让顶层例化关系变得碎而深接口数量爆炸反而增加集成的复杂度。论文里给出的经验是把模块粒度控制在单模块代码量不超过200行左右一个设计拆成5到10个子模块。这个区间兼顾了代码可读性和集成成本。我自己的实操经验也与这个结论相符追求单个module短小时状态机、计数器、数据通路分开每块逻辑都很好理解但如果拆到更多比如每个寄存器组都要一个文件那光文件切换和维护模块之间的依赖关系就够你喝一壶的。另外论文提到在分解模块时会显式要求大模型标注每个模块的类型归属比如“control logic”“datapath”“memory interface”这样的分类标签。这个做法的好处在于后续生成代码时模型能够根据模块类型自动匹配对应的代码风格模板。控制逻辑用状态机写法数据通路用并行赋值写法存储交互用握手时序写法生成质量会有明显提升。3.2 自顶向下分解与自底向上生成的结合HiVeGen的流程表面上看是自顶向下的先有架构再拆模块最后集成。但论文特别强调在生成环节使用了一种“自底向上验证”的策略这个细节很容易被略读。具体来说模块生成的顺序不是随机的。HiVeGen会先处理那些没有依赖关系的“叶子模块”比如CRC计算、FIFO存储体、波特率分频器等基础模块。这些模块生成后你就能立刻做编译检查和单独的仿真验证确认没问题后再向上处理依赖这些底层模块的逻辑模块。最上面的顶层模块是最后才生成的。这样做的好处非常明显你在每一层都有经过验证的可靠基础。越往上构建时底层出现错误的概率越低排查范围越小。这就像盖房子时先确保地基和每一层楼板的质量过关而不是等整栋楼都搭完了再发现问题那时候整改的代价就太大了。3.3 验证与合法性检查的工程化设计HiVeGen中让我觉得最务实的地方是它对验证资源的利用策略。它不追求用现代的UVM或formal验证方案而是用直接的编译加仿真冒烟测试来筛选生成结果。每次生成完代码会跑一次快速的语法检查和功能仿真。仿真激励也不复杂通常是一个简单的testbench喂入几组典型输入查看关键输出是否与预期一致。如果通过进入下一阶段如果没有通过把编译器和仿真器的报错信息连同当前代码一起打包回喂给大模型让它务必“根据以下错误信息进行修改”。这个“错误反馈回路”其实非常关键。很多人在实际中使用AI写Verilog的时候如果生成的代码仿真不过往往选择重新生成一个新的版本但重新生成可能引入新的问题。HiVeGen的这种迭代修复方式更像是在真实项目中“debug一版代码”而不是反复推倒重来收敛速度要快得多。需要注意的一个细节是迭代修改的次数并不是无限制的。一旦反复修改多次仍然无法通过基本检查论文的策略是回到模块拆分阶段重新考虑模块划分和接口定义。这是因为反复报错往往说明接口定义或模块职责划分本身存在不合理之处单纯的代码修复解决不了根本问题。这种“向上回退”的思路工程上非常实用。3.4 与其他AI硬件生成方法的对比近几年用LLM生成RTL的论文和工具并不少但大多数集中在“如何提升单次生成代码的语法正确率”或者“如何通过更长的上下文来直接生成更大的模块”。HiVeGen的视角更偏向设计方法学传统方法prompt工程 代码补全 语法修复上下文扩展方法把整个设计规格和所有模块代码全部塞进一个巨大上下文让模型一把梭生成全部代码HiVeGen方法把生成过程拆成“架构设计-模块生成-顶层集成”三个阶段每个阶段的上下文都相对独立用验证反馈来串联HiVeGen的优势在于对上下文窗口的要求更低不需要为了生成一个大设计而无限扩展上下文长度对出错后的修复成本也更低可以在子模块级别完成调试。这其实切中了算力受限场景下的实用需求不是每个用户都拥有可以处理超大上下文的模型但几乎所有用户都能运行一个中等长度上下文的模型来分步生成。当然论文也坦承了局限性比如对于接口协议非常严格的设计场景自动生成的子模块互连可能存在隐藏的时序或协议风险单纯靠编译和仿真检查未必能发现所有问题。这意味着HiVeGen在可综合级别的简单设计上表现最好但对于带严格工程约束的高速接口类设计仍然需要资深工程师的深度介入。4. 实操视角没有HiVeGen工程师怎么用AI写出可维护RTL读论文的本质在于吸收方法论而不是期待论文给出一套开箱即用的工具。HiVeGen目前主要还是一个研究性质的工作但它提出的思路完全可以落到日常工作中。这里分享我自己的实践心得。4.1 提示词层面先把“模块划分”逼出来想让AI按层次化方式生成代码最简单的一步就是在prompt里强制要求模块划分。我平时会让AI先回答三件事后再写任何代码这个设计可以拆成哪几个功能子模块每个模块分别做什么子模块之间的接口信号有哪些各自的位宽和方向顶层模块的例化关系是怎样的如果AI直接开始生成代码我就会中断它明确告知“先输出设计拆分方案不要写代码”。大多数支持多轮对话的模型都能理解这个约束。这一步强制了“先设计再编码”的流程从源头降低了巨型代码块出现的概率。4.2 用AI生成空白模块骨架而不是直接生成实现这里分享一个我自己常用的方法让AI先生成每个子模块的module声明和输入输出端口定义但内部逻辑留空。把这些骨架代码集中起来review确认模块划分和端口定义都合理后再让AI逐个子模块去填充内部实现逻辑。这个方法的妙处在于它把“接口设计”和“逻辑实现”变成了两个独立的检查节点。接口设计阶段的错误在你开始写内部实现之前就被抓住成本极低。而且每个子模块的实现是相对独立的任务上下文更精简模型生成的质量会更高也不会出现模块之间信号命名不一致的问题。4.3 用“伪代码 引脚表”替代纯自然语言描述如果想让AI生成更符合你预期的接口建议别只扔给它一句文字描述。你可以在prompt里加上精确定义的接口表格包括信号名、方向、位宽、功能备注。这能让大模型在生成时严格遵守接口规范而不是自己脑补一套接口然后在顶层集成时对不上号。举个例子我想让AI生成一个双端口RAM模块我会这样写请生成一个同步双端口RAM模块端口定义如下 - clk: input, 1bit, 时钟信号 - rst_n: input, 1bit, 异步复位低有效 - wr_en: input, 1bit, 写使能 - wr_addr: input, 8bit, 写地址 - wr_data: input, 32bit, 写数据 - rd_en: input, 1bit, 读使能 - rd_addr: input, 8bit, 读地址 - rd_data: output, 32bit, 读数据这种带有明确引脚定义的prompt生成结果基本不需要改接口可以直接用。4.4 生成后的自动检查清单不管用哪种方式让AI写代码我建议生成结果后别急着仿真先做一个基础的静态检查我自己常用这份清单模块名是否与文件名一致有没有多个module堆在同一个文件里是否有未声明的信号或者声明了但没有driver的信号是否存在多个always块不小心对同一个reg变量赋值的问题时钟复位是否统一有没有在组合逻辑always块里出现时钟信号端口位宽与连接信号的位宽是否匹配有没有在顶层例化时出现位宽不匹配的warning这些检查项不一定需要用lint工具来做肉眼加文本编辑器搜索也能完成。它们的意义在于把AI代码里最常见的问题在早期就拦截下来避免带病进入仿真和综合流程。5. 常见问题与排查技巧实录5.1 模块拆得太碎反而更难维护有朋友反馈看了HiVeGen的介绍后尝试把小模块拆到极致结果发现设计拆成十来个小模块每个模块只有二三十行接口信号满天飞顶层例化代码比之前大模块里实现功能的代码还长。这种情况就属于模块拆分粒度过细。模块拆分的判断标准应该是一个模块最好包含一组完整的、可独立验证的功能语义。比如FIFO是一个整体CRC校验是一个整体状态机控制器是一个整体。如果一个模块只能完成“把信号A赋值给信号B再打一拍”这种事那它不具备独立验证的意义应该合并到调用它的模块里去。记住层次化的目的是改善可读性和验证效率不是单纯地“把代码变短”。5.2 AI生成子模块时端口定义不一致这个坑我踩过好几次。AI生成两个子模块时明明架构设计阶段指定的接口信号是同一个但在生成不同子模块时它会擅自改名或者改变位宽。A模块的输出叫tx_dataB模块的输入却被写成了rx_data位宽也从8位变成了16位。应对方式有两个层面。第一个层面是把端口表写进每个子模块的prompt里明确告诉模型这里必须严格按照指定接口输出不要修改信号名和位宽。第二个层面是在顶层集成了之后写一段自动检查脚本解析所有例化语句确保所有连接信号的位宽对齐。有些经验丰富的工程师会直接在JSON里定义整个设计的接口然后让AI从JSON里读取接口信息这样一致性会好很多。5.3 仿真能过但综合不过的类型问题AI生成的代码做个简单的仿真测试很容易通过但一旦拿到综合工具里就疯狂报错。常见的情况有两类一类是不可综合的语法比如initial块里给reg赋值、循环次数无法确定、使用了不支持的延时控制另一类是敏感列表不完整或者在组合逻辑always块里不小心嵌入了时序逻辑描述。我的经验是让AI生成代码时在prompt里加一句话“请确保生成的代码是可综合的不要使用initial、delay、fork join等不可综合语法”能减少一半以上的综合错误。同时每一层模块在完成静态检查后尽量用综合工具做一次快速的“语法综合检查”不需要跑到布局布线只用elaborate阶段跑一遍确认没有不可综合的语法结构就行。5.4 仿真失败时别忙着重新生成前面提到HiVeGen的错误反馈机制换言之就是迭代修复而不是重新生成。这个策略我特别认同。在实践中如果第一次生成的代码仿真失败直接把报错信息和波形信息回喂给大模型让它修改当前代码通常比让它重新写一遍有效得多。原因在于重新生成时模型会重新做概率抽样语法结构、模块划分思路、状态机编码方式都可能完全不同修复了旧bug又可能引入新bug。而基于当前代码迭代修改相当于在局部搜索空间内做优化稳定性高很多。我建议把AI当作“第一个版本的作者”而不是“最终的实现者”。它写完的代码经过你的修改后回喂给它它能够在这个基础上继续优化这种交互方式更高效。5.5 完全放手让AI写大型设计仍然不现实最后说一个比较清醒的认知。尽管HiVeGen提出了很好的流程优化但以当前大模型的代码生成能力和上下文理解能力完全放手让AI独立完成一个大型芯片设计仍然不现实。复杂设计里的微架构规划尤其是涉及多核缓存一致性、低功耗状态切换、时钟域交叉策略等高级主题时大模型的理解深度仍然不够。所以我更倾向把AI定位成**“高效的初级工程师”“全知的技术顾问”**。它可以帮你把80%的常规RTL写掉可以给出初级方案可以帮你在系统verilog和UVM中搭建验证环境但架构决策、关键时序约束、协议设计这些核心工作需要资深工程师来把关。HiVeGen的价值在于它让“AI生成代码-工程师审查修改”这条协作链路的边界更加清晰模块化生成给了人更多控制节点也让审查难度大幅降低。6. 在真实项目中用AI写RTL的一点体会读了这篇论文之后我在自己手头的一个小IP设计里尝试了HiVeGen式的流程先用AI做设计拆分确认模块清单再逐个模块去生成最后让AI完成顶层集成。整体下来最大的感受不是“AI变聪明了”而是我作为工程师能控制的地方变多了。之前用AI写RTL总有一种“代码失控感”生成结果像一块沉重的毛坯砖头你只能要么接受、要么推翻重来。现在改用模块化流程每一步的产出物都很轻可审查、可修改、可回退整个过程变得像和一个初级的、速度快到离谱的工程师协作一样顺手。如果你现在手头也面临类似的问题不用非等工具落地完全可以先把这套流程用起来。下次再让AI生成Verilog的时候记得先说一句话“先给我模块划分方案再逐模块生成代码最后做顶层集成。”这句话的价值可能比换一个大模型还实在。
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻