ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Vivado IP核操作顺序:先Generate后Create Wrapper

Vivado IP核操作顺序:先Generate后Create Wrapper 很多刚接触Xilinx FPGA开发的朋友在Vivado里折腾IP核比如PLL、FIFO、Block RAM的时候十有八九会被两个按钮搞懵一个是Create HDL Wrapper一个是Generate Output Products。弹窗一个接一个也不知道先点谁往往鼠标飞快点下去结果后面综合时报一堆莫名其妙的错。这个问题我在带新人时被问过无数次也亲眼见过有人因为顺序搞反浪费了整整一个下午去排查一个根本不该存在的问题。先说结论标准操作顺序是先执行 Generate Output Products然后执行 Create HDL Wrapper。但只知道这个结论远远不够。你要是弄不明白这两个动作背后的逻辑换个工程、换个IP、或者遇到一次非标准流程照样会踩坑。这篇文章我把这两个步骤掰开揉碎讲清楚包括它们各自干了什么、为什么顺序不能乱、不同选项该怎么选、报错了怎么排查看完你就能彻底摆脱对这两个按钮的恐惧感。1. 先搞明白这两个按钮到底是干嘛的很多教程会直接告诉你“先Generate再Create”但从来不说为什么。我见过不少工程师每做一个工程都机械地点Yes点得多了就麻木了。等哪天真需要手动处理IP相关文件时才发现自己完全不知道Vivado在背后做了什么。1.1 Create HDL Wrapper 和它的历史包袱不知道你有没有注意过这个按钮的名字里有一个非常“复古”的词Wrapper。这个词直译叫“包装器”本质上体现了一种非常经典的软件设计思想——封装。Xilinx的IP核从RTL级别看它就是一大堆复杂的逻辑电路可能有几十个模块几百个连线。如果你在顶层设计里直接把这个IP核拖进来用那你的顶层代码会被一大堆IP内部引脚占用而且很难看清楚模块之间的关系。Create HDL Wrapper做了什么它是给IP核包了一层“壳”生成一个顶层的HDL文件通常是VHDL或Verilog这个文件里只暴露IP对外提供的端口比如时钟输入、复位输入、数据输入输出而把IP内部的所有内容都隐藏起来。这个“壳”文件生成之后你在自己的工程里看到的就是一个干干净净的模块直接例化它就行了。可能有人会问既然IP核自己已经有一个例化模板为什么还要专门生成一个Wrapper这是因为IP核本身是以.xci文件Xilinx Core Instance形式存在的它不是Verilog文件。综合工具不能直接拿.xci去做综合它需要有一个实实在在的HDL文件来描述这个IP例化后的样子。Create HDL Wrapper就是把这个“HDL描述文件”自动生成出来省得你手动去抄端口连接。值得留意的是Vivado里这个Wrapper生成的时候会提供一个选项——是生成一份允许编辑的Wrapper文件Let me edit it还是生成一份只读的Wrapper文件Copy generated wrapper to allow edit不同版本提示不太一样。新手建议全部选默认的“自动管理”方式让Vivado自己来维护这个Wrapper的同步更新后面要修改IP配置时它会自动更新端口。1.2 Generating Output Products 到底“生成”了什么Generate Output Products这个按钮翻译成中文其实不是特别直观。它直译过来是“生成输出产物”。什么“输出”什么“产物”对新手来说太抽象了。说穿了它生成的是让这个IP能在整个FPGA设计流程中正常工作所需要的一切配套文件。这些配套文件包括但不限于综合阶段需要的网表文件如果是加密IP没有网表你根本无法综合、约束文件比如IP内部某些异步时钟域的约束、IO延迟约束、仿真模型用于功能仿真和时序仿真的行为级描述、以及Memory初始化文件等。你可以这样理解Create HDL Wrapper生成的是IP的“额头”“身体轮廓”——就是长什么样、有哪些对外接口而Generate Output Products生成的是IP的“血肉筋骨”——真正让这个IP跑起来需要的内部实现细节。从流程上看Generate Output Products做的事情是把.xci描述的IP核转换为综合和仿真工具能够直接使用的文件集合。它是IP配置与后续实现流程之间的桥梁。没有这个步骤后面综合的时候Vivado根本不知道这个IP实际上该怎么实现想跑通流程更是天方夜谭。1.3 一个贯穿全文的地基这两个步骤在Vivado里管什么在Vivado的工程结构下每个IP核实例在Sources面板里都是一个独立节点。右键点击这个节点能看到的菜单里就有Create HDL Wrapper和Generate Output Products。有一个特别容易忽略但很重要的机制Vivado对IP核采用的是“惰性生成”策略。也就是说你改完IP配置点OK之后Vivado并不会立即为你生成所有配套文件它会先把配置保存到.xci文件里然后等你操作或者等到综合前检查时才触发实际生成。这就是为什么很多时候你修改完IP配置直接点综合Vivado会先卡在那儿跑很久跑一段“Update IP”的任务——因为它在贴心且固执地替你补做Generate Output Products和Create HDL Wrapper。这里就是第一个知识的“地基”这两步本质上都是让IP从配置状态进入可用状态的必须环节只是生成的对象不同。2. 到底该先用谁为什么——拆开聊聊背后的逻辑好现在回到最核心的问题。既然这两步都是生成配套的那为什么先Generate再Create我来说说如果顺序错了会发生什么。2.1 VIVADO里的隐藏流程Wrapper自动更新我先说一个很多老手都踩过的事实Create HDL Wrapper这个操作其实不依赖于Generate Output Products的产出物。你就算不生成产物直接右键点Create HDL WrapperVivado照样能给你生成一个.v文件。所以表面上看好像谁先谁后都行Vivado不会拒绝你。但问题出在另一方面。Generate Output Products生成的文件列表里有一种文件叫仿真模型。这个仿真模型是根据IP配置动态生成的描述了IP在仿真环境中的行为。而这个仿真模型是需要被Wrapper引用或者说需要和Wrapper相匹配的。Create HDL Wrapper生成的顶层模块端口定义并不是固定的它会参考IP核的配置信息。但如果此时Output Products里那个仿真模型还没生成Vivado生成的Wrapper可能就会基于旧的IP配置来定义端口。一旦后期IP配置更新或者Wrapper与仿真模型之间出现端口不匹配你在仿真时就会出现悬空连接、端口数量对不上、编译报错等一系列让人抓狂的问题。2.2 从文件依赖的角度看Generate的先决性再往深一层说Generate Output Products不仅是提供仿真模型它还提供综合阶段必须用到的网表和约束文件。比如你需要对这款FPGA做引脚分配IO Planning或者实现内部的时钟约束这些约束的某些部分是从IP核的Output Products中继承而来的。如果你先创建了Wrapper那么你在工程里看到一个结构完整、接口丰富的模块但你去查它底层依赖的网表文件或约束文件时发现它们还不存在或者版本不对。这种感觉就像你拿到了一本书的目录打开正文却是白纸整个工程的状态处于“半损坏”状态。经验之谈在Vivado的官方文档UG903和UG949里对IP的集成流程给出过一个推荐顺序就是先generate output products再generate wrapper。虽然Vivado的自动化流程在大多数时候可以容忍顺序错误但它会在点击综合时偷偷地花大量时间重新做一遍生成动作。这绝不是没事找事而是因为Vivado自己的依赖系统非常敏感它发现IP的核心产物.dcp网表文件未生成时会强制调度相关进程这也是为什么很多新手的工程综合特别慢因为你在不知不觉当中让Vivado重复做了很多底层操作。2.3 一个真实的顺序错误案例我有个前同事刚上手FPGA时在一个工程里集成了两个DDR控制器IP赶时间直接点了Create HDL WrapperWrapper文件生成得倒是挺快。但紧接着他打开顶层模块准备连信号发现IP例化的端口与他预期的完全不匹配——少了一些DDR的物理接口。他以为是自己IP配置有问题把IP删了重建了一次重新Create Wrapper还是一样。折腾一小时后才发现原来是他Generate Output Products里的某个版级约束XDC在生成过程中报了一个warning导致Output Products没有完整生成Wrapper里的顶层接口就是从缺失状态生成的。后来他把Generate Output Products完整跑通再右键IP核重新刷新Refresh IP删掉旧的Wrapper重新Create端口立刻就正常了。这个案例想告诉你的是把操作顺序固定下来能帮你把“变量”控制到最少出问题时排查路径会清晰得多。先Generate后Create这看似简单的规则其实就是帮你规避一整套由文件依赖混乱引发的隐性错误。2.4 顺带一提IP核的复位、时钟与Wrapper的金科玉律在Wrapper生成之后你在修改IP配置时Vivado通常会提示你“Wrapper需要更新以匹配新配置”问你是否允许Vivado自动更新Wrapper。如果你选的是Read-only模式Automatic那你不需要手动改任何代码但如果你选的是允许编辑的User Mode那每次改IP参数Vivado只会弹窗提示却不会帮你自动改代码。你得手动处理端口变化。在实操中我强烈推荐新手都用“Automatic”自动模式等以后真正需要定制Wrapper内部逻辑时比如在IP周围加寄存器、做信号级联再切换成手动模式并且切之前记得备份。3. 实操拆解用最稳妥的顺序一步步点完不迷路理论聊清楚之后我们来看现场实操。假设你已经在一个Vivado工程里添加好了IP核比如添加一个Clocking Wizard或者Block Memory Generator现在Sources面板里能看到这个IP的黄色图标。接下来按我的步骤操作每一步我都会解释为什么要这么做以及界面里那些选项到底该怎么选。3.1 第一步在IP核上右键先选Generate Output Products在Sources窗口里对着IP核右键选择Generate Output Products。Vivado会弹出一个对话框里面有Synthesis Options和Simulation Options两个下拉菜单。Synthesis Options这里值得多说两句。它默认是Global也叫Global Synthesis。选了GlobalIP会和你顶层工程一起综合综合工具能看到IP内部的RTL细节有时能做一些跨模块优化。另一种是Out Of ContextOOC字面意思叫“上下文外”综合即把IP核单独拎出来综合成独立的网表.dcp文件然后在顶层综合时直接调用这个网表不再重复综合IP内部RTL。对于大多数复杂的IP我都推荐用Out Of Context。原因有三条第一综合时间大幅度缩短IP不需要每次顶层综合都跑一遍第二工程结构清晰每个IP的时序约束互不干扰第三对小型IP来说Global可能会受到顶层约束文件的影响导致莫名其妙的时序问题OOC则天然隔离这些干扰。代价是你修改IP配置后需要多一个步骤——重新Generate Output Products。Simulation Options保持默认的Instantiation即可大多数情况下它生成的都是行为级仿真模型足够用了。如果你想在某些性能分析场景下获得更高的仿真精度可以换成Timing或Structural但会牺牲仿真速度新手阶段不需要折腾。选好之后点GenerateVivado底部进度条跑完后会有一个Write Interface之类的辅助任务不用管等它结束就行。这时你可以去工程目录下看到IP名_sim_netlist、IP名_stub.v、IP名.dcp等文件已经落盘说明Output Products正常工作。3.2 第二步右键再选Create HDL Wrapper确认Generate Output Products的进度条显示为绿色对钩后回到Sources窗口再次右键IP核选择Create HDL Wrapper。此时会弹出一个选项Let me edit it允许用户手动编辑Wrapper文件Copy generated wrapper to allow edit同样是允许编辑但复制了一份AutomaticVivado全自动管理Wrapper内容用户无法编辑。不同版本里显示的措辞不尽相同有的是单选“Allow edit”有的会直接弹框问你要不要自动管理。新手一律选Automatic。选了Automatic后Vivado会生成一个名为top_name_wrapper.v的文件在Sources面板里出现于Design Sources下。这个Wrapper文件的核心内容是把IP核重新例化了一遍然后暴露出一堆输入输出端口。值得留意的是如果IP核的配置里使用了类似AXI接口或者原生接口控制信号Wrapper上同样会暴露相应的总线端口例如S_AXI_*、DDR_*等。对于新手此刻最需要做的就是不要手动去改这个Wrapper文件内部的任何内容。3.3 第三步检查Wrapper端口匹配顶层连接生成完Wrapper后打开这个.v文件对照IP规格手册逐一核对端口名。正常来说端口命名非常规范。比如Clocking Wizard会生成CLK_IN1_D、CLK_OUT1、CLK_OUT2这类端口Block Memory Generator会生成addra、dina、douta等标准端口名。为什么要把这一步专门拎出来说因为经常有人在这里犯低级错误。Wrapper检查环节后面非常重要的一步是在顶层文件里例化这个Wrapper。有人图省事直接在顶层里例化IP核本身而不是例化Wrapper这种写法虽然有时也能通过综合老版本Vivado会允许但会绕开Vivado的IP管理机制导致后续IP更新时端口不一致的问题。正确的做法是顶层里永远引用Wrapper生成的模块名而不是xci的模块名。3.4 第四步更新IP配置后别忘重新生成整套文件实际开发中IP配置不会一步到位你可能会因为时钟频率不对、FIFO深度不够等原因双击IP核重新打开了配置界面改完参数后点OK。这个时候请记得Vivado没有帮你自动Generate Output Products也没有自动Create Wrapper。它的IP更新机制只会把变化标记下来。此时我建议的流程是先在底部Tcl Console里执行reset_project如果工程已经综合过可选然后重新右键执行Generate Output Products再执行Create HDL Wrapper如果弹出提示问是否更新Wrapper选择自动更新即可。如果工程比较大IP数量多一个个右键太累了也可以在Tcl Console里批量执行。比如foreach ip [get_ips] { generate_target all [get_files $ip.xci] create_hdl_wrapper -files [get_files $ip.xci] }这个命令会把所有IP的Output Products和Wrapper一并刷新适合大批量处理。不过批处理之前记得先保存工程避免误操作。4. 从GUI到脚本深入理解生成动作的底层逻辑很多人觉得Vivado的GUI好用但它掩盖了太多实现细节。你越是依赖点击越难理解系统在背后干了什么。所以这一节我想带大家把这两个步骤从文件系统层面“扒开看”理解了这些以后遇到报错你自己就能判断出大概问题出在哪一层。4.1 Output Products到底产出了哪些文件一个典型的IP经过Generate Output Products之后在工程目录的Project.gen/sources_1/ip/IP_Name/下会出现一堆子文件夹。常见的有synth/综合产物目录包含.dcp网表文件OOC综合后的结果。这是后续实现和处理的基础。sim/仿真产物目录包含.v行为模型、glbl.v全局复位/时钟模型等。constraints/IP相关的约束文件各种时序例外、管脚约束等。example_design/IP推荐的例化模板部分IP有。docs/IP规格文档、端口说明很多IP自带很有用。这些文件不是随便生成的。当你修改IP核参数后这些目录里的文件可能有部分失效。Vivado会通过一个叫“底层的target管理”机制去判断哪些文件需要重新生成。这也是为什么每次Generate Output Products实际上并不是全部重新生成而是增量更新。如果你的工程莫名多出一堆无用的旧文件不要慌那是Vivado没有完全清理的中间产物手工删除工程目录后重新生成时它会做一次全量生成。4.2 OOC综合与Wrapper的深度绑定在Vivado的OOC综合模式下每个IP核是独立综合的。独立综合完成后会生成一个IP_Name.dcp文件。这个.dcp文件里面包含了综合后的网表、时序约束等。这里有个非常关键的点Wrapper生成的端口声明必须与这个.dcp中的顶层端口完全一致。因为后续的实现阶段工具会读取Wrapper的.dcp以及每个IP子模块的.dcp然后进行装配。如果你顺序乱了端口声明和实际网表不一致EDA工具在装配时就会直接报错错误信息往往是“Port ... does not exist on instance ...”或者“pin mismatch”。这种错误光看表面很难发现原因因为它不会直接告诉你“你Generate的顺序不对”。你只能靠经验去排查或者回到“先把Output Products完整生成再重新Create Wrapper”这条底线上。这也是我为什么反复强调顺序的重要原因——它不只是开发习惯问题是文件系统层面的装配依赖。4.3 不生成Output Products直接综合会怎样我再模拟一个场景你新建工程添加IP没Generate Output Products没Create HDL Wrapper直接点击Run Synthesis。Vivado在综合启动时会自动执行两个任务它会先调用IP的生成器把Output Products生成默认会使用Global或OOC模式然后再综合顶层设计。也就是说Vivado会在综合前自动帮你做掉这两个步骤。但是自动触发时系统不会弹出选项它会用默认配置。如果你的工程里设置的是Global综合模式那么IP会和你的顶层一起综合用户的约束文件可能会导致某些IP内部时序出现意外变化。很多人在这一步遇到的莫名其妙的问题尤其是“IP怎么综合出来结果不对”往往就是因为原理上默认的Global模式把IP和你自己的逻辑搅和在一起产生了一些复杂的综合调度行为。所以规范的操作流程其实是为了让你对工程有更精确的控制权而不是让Vivado自动帮你做决定。工程越复杂自动化越容易在不可预期的地方织出一团乱麻。5. 高频报错现场这些炸在脸上过的错今天一并收拾了这一节我整理几个我亲手排查过的高频报错。如果你正在被这些问题折磨按下面的思路走大概率能快速脱身。5.1 错误一Portxxdoes not exist on instanceyy这个报错通常出现在综合或实现阶段。字面意思是某个顶层模块例化了一个子模块但子模块里没有你连的那个端口。遇到这种报错尤其是IP相关的例化第一反应不是去改顶层代码而是检查Wrapper是否过期。具体操作是右键IP核先Get Output Products跑一遍如果看到有进度条跑动说明之前确实没生成完整然后再删掉旧Wrapper重新Create HDL Wrapper。重新生成后打开新的Wrapper文件对比一下端口变化。多数情况下端口不匹配是因为IP配置升级后Wrapper没更新造成的。5.2 错误二[Synth 8-3331] designxxhas unconnected portyy这个报错更容易误导人。它说的是在设计综合时发现某些端口没有连接。常见场景是你创建了Wrapper但Wrapper里有一大把output端口悬空Vivado会给warning但如果是input端口悬空某些配置下会升级为错误。原因在于Wrapper生成的端口是根据IP自动决定的。比如Clocking Wizard如果你没有启用某些输出时钟那这些端口就不会出现在Wrapper里。但在手动修改Wrapper时你可能保留了它们或者反过来你在Wrapper里手写了一段例化但把端口名拼错了导致例化时匹配不上整个端口被当成未连接处理。排除方法重新生成Wrapper不改任何代码直接跑一次综合。如果错误消失说明是你改动Wrapper时引入了问题如果错误还在检查IP配置中哪些接口使能了但没连。5.3 错误三ERROR: [IP_Flow 19-3664] Failed to generate IPxx这是Generate Output Products阶段最常见的错误之一。报错原因五花八门大体分三类IP版本与当前Vivado版本不兼容、系统盘空间不足、以及IP被其他进程占用比如你开着另一个Vivado工程正在读写同一个IP目录。处理思路最简单粗暴的方法是先在Tcl Console里运行ipx::infer_user_parameters然后再重新Generate如果还不行就直接把工程里这个IP从Sources里Remove掉重新从IP Catalog里添加一遍重新生成。虽然慢但有效。更彻底的做法是删除工程目录下Project.gen、Project.cache文件夹后重新打开工程再Generate。注意删.cache目录后Vivado首次打开工程会重建大量缓存耗时较长但可以解决一些顽固的生成失败问题。5.4 错误四仿真时报glbl模块缺失新手用Xilinx IP做仿真时经常会在仿真日志里看到找不到glbl模块的报错。原因在于很多全局资源如GTP、IDELAYCTRL、STARTUP等在仿真时需要glbl.v这个全局模块作为仿真基础。这个glbl.v文件通常位于Vivado安装目录下的data/verilog/src/glbl.v。解决办法是在仿真设置里将仿真库中的glbl.v文件也加入仿真文件列表。或者如果你用的是Vivado自带的仿真器xsim那么需要在仿真设置-xsim.simulate.runtime中指定glbl。注意顺序问题要先编译glbl再编译你的设计文件。大多数情况下Vivado的自动编译脚本会帮你处理但如果你手动修改过仿真文件列表就容易漏掉它。5.5 错误五综合OOC模式时报缺少约束文件这通常是IP的约束文件没有生成。去工程目录里找找IP_Name.xdc是否存在。如果不存在先检查IP有没有被正确配置生成Output Products时不要勾选“Skip constraints generation”新版Vivado有类似选项。如果你是自己在Tcl里手动调用生成请检查命令参数是否遗漏了约束生成部分。反正在这一块我始终给新人的建议就是日常开发中永远不要手动拷贝或编辑IP相关的输出文件。所有更新全部通过Vivado右键操作或脚本命令完成。只有这样才能保证文件依赖链一致从根上避开大部分认知盲区导致的报错。6. 关于这两个步骤你还应该知道的几个小诀窍最后分享一些我自己工作时积累的小习惯不算高深但能让你后续开发顺畅很多。第一个小诀窍养成看Tcl Console的习惯。每次你点Generate Output Products或Create HDL WrapperVivado都会在Tcl Console打印出它实际执行的命令。你不需要懂所有Tcl语法但只要扫一眼就能看到生成用了多少秒、有没有warning、输出文件路径在哪。这些信息对于排查问题非常有价值。多看几遍你就能逐渐理解Vivado的输出规律。第二个小诀窍IP核的Version不要随便升级。很多人觉得IP核是个独立小模块升级一下不会有问题。但IP版本升级往往会改变端口名、仿真模型甚至内部网表结构。升级后如果不重新Generate Output Products并重新Create Wrapper报错是大概率事件。所以在你没有充分理由的情况下不要随意升级IP版本。尤其在多人协作中一个成员升级了IP另一个成员因为版本不统一导致打开工程就一屏报错这种场景我见过太多次了。第三个小诀窍使用Vivado的Batch Mode和脚本化构建。如果你不是只做小工程而是持续维护一个中等以上规模的工程强烈建议你把IP生成、综合、实现的流程做成一个Tcl脚本。比如open_project ./my_project.xpr upgrade_ip [get_ips] generate_target all [get_ips] create_hdl_wrapper -files [get_files my_ip.xci] launch_runs synth_1 -jobs 4 wait_on_run synth_1这样做的好处是你不会遗忘任何一个IP的更新版本可控性会大幅提高。而且回归测试或者换机器跑工程时脚本执行效率和稳定性远高于GUI逐一点击。第四个诀窍谨慎修改由Vivado自动生成的Wrapper文件内容。如果你非要修改比如想往Wrapper里加一些辅助逻辑建议先复制一份再改名命名为xxx_wrapper_custom.v然后手动例化。这样既保留Vivado自动生成文件的原貌又能实现定制需求避免每次生成时和Vivado打架。7. 写在最后的几个关键提醒前面已经说得比较多了但有几条实操原则值得最后再重复一遍因为它们是很多人血和泪换来的经验。原则一永远不要低估这两个步骤的“副作用”。很多新人认为“生成Output Products”就是把IP的RTL代码复制一份出来点一下就完了。实际上这一步会触发大量的内部检查和文件生成任务包括IP的时序约束、仿真模型、OOC综合初始化等。如果你电脑性能一般这一步卡个几分钟都是正常的千万别以为界面“卡死”了就去强制关闭Vivado。耐心等待右下角的进度条一定会给你回应的。原则二如果工程变得异常优先怀疑IP生成状态。这句话百试百灵。当一个之前正常编译的工程突然出现各种诡异错误而且你最近刚动过IP相关配置那么90%以上的概率是IP的生成状态出了问题。解决办法不是去改顶层代码而是回到IP核依次执行Generate Output Products和Create HDL Wrapper再重新Run Synthesis。很多时候问题自己就好了。因为IP生成状态决定了后续所有流程的输入外部逻辑改错了只会影响具体功能不会导致这么多低级错误同时爆发。原则三尽量让Wrapper保持“自动管理”状态。手动改Wrapper是给高手准备的“自定义”能力对于新手这个文件应该被视作“系统生成”能不动就不要动。自动状态下Wrapper内容更新和IP配置是同步的维护成本为零。手动状态下每次IP配置 변경你都要同步处理Wrapper里的端口容易遗漏且难以专注在顶层设计逻辑上。我在带FPGA工程师的这几年里发现一个规律很多看起来特别“玄学”的问题本质上都是因为对工具链的底层依赖关系缺乏概念。这两个按钮Vivado已经帮你安排得明明白白了只是它没有耐心告诉你每个按钮背后的为什么。等你把这两步的机制彻底吃透后面再遇到IP相关的任何报错心里都会有一个非常清晰的排查地图不再慌慌张张地删工程重来了。希望这篇分享对你有帮助。踩坑不可怕关键是踩完一个坑能真正搞明白这个坑到底是谁挖的、为什么挖、下次怎么绕开它。FPGA开发就是这样经验都是一次次综合报错堆出来的你自己趟过一遍比别人讲十遍都管用。
返回列表