多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Vivado IP核管理实战:添加、生成与封装全攻略

Vivado IP核管理实战:添加、生成与封装全攻略 做FPGA开发的人几乎每天都得跟IP文件打交道。不管是调一个FIFO、挂一颗DDR、拉一个FFT还是把别人工程里的某个IP搬到新工程第一步永远是围绕“IP”这个词转。Vivado里项目管理最基础和最高频的操作其实就是两件事把现有的IP文件正确加进工程以及把需要的IP按自己的参数生成出来。这篇东西我就按实际干活时的操作顺序把添加IP和生成IP的全过程、背后的原理、常见的坑一次说完。适合刚用Vivado建工程、被文件结构搞得一头雾水的萌新也适合已经在多个工程之间反复搬运IP、想弄清楚为什么有时候IP会“红标”的熟练工。1. 先搞懂IP文件到底是什么再动手很多人习惯拿到一个Vivado工程直接双击打开就干活但一遇到IP相关的报错就抓瞎。我建议先花几分钟把IP文件的性质搞清楚后面所有操作都会顺手得多。1.1 Vivado里常见IP文件都有哪些在Vivado工程里一颗IP出现的时候通常不只是一个文件而是一堆文件的组合。最核心的是.xci文件它是整个IP的“身份证”全称是 XML Component Interface本质是一个XML格式的文本文件。里面记录了IP类型、版本、定制参数、接口配置、地址映射等信息。你双击它在文本编辑器里打开能看到一堆component、parameters、interfaces标签这些就是Vivado恢复一颗IP状态的依据。另一个常见的是.xcix这是Vivado对xci文件打包压缩后的产物可以理解成xci的“压缩包版”通常用于在 IP Catalog 中作为库文件或者在不同工程间分发。如果你拿到一个.xcix文件不需要解压它直接用Vivado的 Add IP 功能添加或者把它拷贝到工程目录下再添加Vivado会自己解包并生成对应的xci。在IP生成输出结果之后还会出现.dcp文件这是Vivado综合后的网表文件。对于加密IP或者没有源码的IPVivado通过OOC综合生成dcp然后工程顶层在布局布线时直接读取这个网表而不是重新综合IP内部逻辑。这就是为什么IP生成之后不能随便删除output_product目录里的dcp删了会导致后续综合失败。另外sim子目录下会有.v/.vhd仿真模型文件Synthesis子目录下有IP的约束文件_ooc.xdc。所以你在工程里看到XX IP的时候Sources窗口里真正挂载的是.xci而它在磁盘上实际占据一个独立文件夹通常是在工程目录下的ip_lib或者项目的.srcs/sources_1/ip/xxx之类的位置。理解了这个文件结构添加和迁移IP时就不会害怕报错。1.2 Vivado管理IP的机制为什么不是直接例化代码有人会有疑问我就写个FIFO一两百行代码也能搞定为什么非要用IP核原因是层次化设计考虑。Vivado的IP核不是给你一堆可以随便改的源码它是一套经过验证的封闭模块。我们用IP其实是在用三家东西定制参数后的接口逻辑、厂商提供的功能和时序保证、以及一套自动化的文件生成机制。IP生成的时候Vivado会做一次Out-of-Context (OOC)综合。简单说就是先把IP单独拿出来当成一个独立的“小工程”综合一遍生成综合后的网表dcp再把网表交给顶层工程做布局布线。这样做最大的好处是IP内部时序在生成阶段已经约束好了顶层工程每次改代码不需要把内部那些复杂的IP逻辑重新综合一遍省时间同时IP内部的关键路径优化也更稳定。所以当你添加一个IP文件不只是往工程里塞一段代码而是把一套“参数网表生成流程约束仿真模型OOC综合配置”的完整依赖关系交给了Vivado。之后的“生成IP”操作就是让Vivado根据xci里记录的参数帮你把这套依赖全部编译出来。明白这一点你就知道为什么新加到工程的IP必须先右键点 Generate Output Products否则综合会报找不到XPM/网表之类的错。2. 添加现有IP文件的几种具体做法2.1 从IP Catalog创建一颗新IP这是最常用的入口。在Vivado工程界面左侧的 Flow Navigator 里点开 IP Catalog会看到一个巨大的搜索栏和分类列表。比如我要加一个AXI4-Stream Data FIFO直接在搜索框输入“FIFO”列出的结果会包含好几个名字类似的IP注意区分是普通FIFO还是带AXI接口的。双击选中IP弹出Customize IP配置窗口里面有一堆参数常见的是数据宽度、深度、读写时钟模式、复位类型、是否使能握手信号等等。这个窗口配置完要点 OK但这时候IP还没有真正“生成”它只是被加入工程。Sources窗口里会出现一个IP源文件图标和普通文件不同同时会带一个类似“IP核”的小符号。这时候你再看工程目录新生成了一个以该IP命名的文件夹里面已经有一个xci文件了。这个阶段相当于只有设计文档没有综合产物。接下来必须进行生成。2.2 把已有的xci文件塞进当前工程很多时候你手里是别人给的.xci文件或者是从另一个工程复制出来的整个IP文件夹。添加方式很简单菜单栏选File-Add Sources选择Add or create IP sources然后在对话框里点Add Directories或Add Files把xci文件选进来。也可以直接在Sources窗口的空白处右键选择Add Sources。选完以后Vivado会提示你“IP已经存在于其他目录是否复制到当前工程”之类的问题这里的建议是如果希望工程能整体拷贝分发就选复制如果是临时引用就选不复制。但注意不复制会带来路径依赖问题Vivado会在xci里记录绝对路径一旦整个工程挪到别的电脑或目录就可能找不到关联文件。我个人的习惯是在一个项目刚起步时就把所有IP统一放到工程的ip目录下所有添加进来的IP都选择复制从源头避免掉路径问题。2.3 跨工程/跨版本迁移Copy工程和IP时最容易踩的雷从别人那边拿整个工程打开后经常会遇到IP状态显示“Out of date”或者“Unsupported”。如果只是通过复制粘贴的方式把某个IP的文件夹拷过来而没有同步拷贝.xci和.ip_user_files那么重新添加时会提示缺少IP定义文件甚至弹出的定制窗口里所有参数都变成默认值。那是因为参数全记录在xci里xci丢了就等于把配置信息丢了。还有一种常见情况是版本不同。比如对方的工程是Vivado 2020.1你本地装的是2022.2打开工程后IP Catalog里会有大量IP显示为黄色感叹号或红色标记。这时候可以在Report-Report IP Status里看到哪些IP需要升级。通常的做法是对IP右键选择 “Upgrade IP”。但升级IP并不是无脑点升级后参数虽然基本保留但端口时序约束可能需要重新检查尤其是DDR控制器这类复杂IP升级后必须重新看一遍接口时序。迁移时我建议带着整个IP目录一起拷不要只拿xci。一个IP在磁盘上的典型结构是IP名文件夹下包含xxx.xci、xxx.xcix可选、xxx_ip_user_files或者.ip_user_files、synth、sim等子目录。只拷xci当然能添加但拷贝后需要重新运行 Generate Output Products等于让Vivado重新生成一遍综合网表白等十几分钟。带着整个文件夹一起搬如果目录结构一致Vivado能直接识别已经生成的产物省掉重新生成的等待时间。3. 生成IP时那些绕不开的关键配置3.1 Customize IP不是随便点几个参数以最常用的Block Memory Generator为例。定制窗口里分好几页第一页选Memory Type比如Single Port RAM、True Dual Port RAM、Simple Dual Port RAM等第二页选数据位宽和深度数据位宽决定你的数据总线是多少bit深度决定地址位宽地址位宽 log2(深度)。还有一个很关键的“Operating Mode”叫“Read First / Write First / No Change”这个决定了同地址读写时输出的行为仿真和实际波形不一样时多半是这里选错。还要注意右下角有个 “Component Name” 输入框默认是IP前缀加一串字符最好改成易于识别的名字比如blk_mem_128x32但注意只能包含字母、数字和下划线不能有连字符、不能以数字开头。这个组件名会作为xci文件名和顶层模块名工程里所有用到这个IP的模块引用名都跟着它走。如果后面对这个名字不满意改xci文件名是没有用的应该在IP编辑器里重新配置并保存。时钟设置也要小心。很多IP可以选择是单时钟还是双时钟比如异步FIFO必须是读写两个时钟域。这里要理解“时钟频率”对综合的影响IP定制窗口里的频率主要用来约束内部时序它不是刨出来的功能而是一个时序约束值。不要把频率设得太低或太高设太低会导致时序条线宽松但实际硬件工作不稳设太高则会让布局布线花大力气去优化可能反而频繁出现页面报错——时序约束不是“标一下最高能跑多快”的意思而是“我承诺这个模块在这个频率下能工作”。3.2 Generate Output Products到底生成了什么在Sources窗口里选中IP右键菜单里第一个就是 Generate Output Products...。点开会让你选择生成范围Synthesis和Simulation是必选的这两个不用纠结都勾上。关键是下面还有一个选项叫 “Generate synthesis and analysis products using”默认是Out-of-context synthesis per IP也就是前面说的OOC综合推荐保持默认。如果你为了节省时间选了Global synthesisVivado会把IP放到顶层一起综合省IP单独综合的时间但以后每次顶层改动这个IP也会跟着重新综合整体时间反而更长。生成过程中会在底部的Messages窗口打印大量信息如果你用的是实实在在的工程而只是试验可以切到 Log 标签页看综合过程。完成后IP目录下会新增synth、sim、ip_user_files等目录。重点看synth目录里面的.dcp文件和.stub文件。stub是供顶层仿真用的“空壳”模块里面只有端口声明没有逻辑实现仿真时用stub就好不会拖慢仿真速度。此外Vivado还会自动生成一个叫XX_ip_clock_converter.xdc之类的约束文件这些约束在综合时自动纳入。当你的工程综合时报错说“IP xxx 缺失约束”多半就是Generate Output Products没跑完或者产物不完整。3.3 用Tcl脚本批量添加和生成IPGUI操作适合单个或少量IP但是当你需要在一个脚本化流程里添加一大批IP时就必须用Tcl命令。我在自动化构建的流程里用到的几个常用命令很简单# 在指定位置创建IP create_ip -name blk_mem_gen -vendor xilinx.com -library ip -version 8.4 -module_name my_mem # 设置IP参数以Block Memory Generator为例 set_property -dict [list \ CONFIG.Memory_Type {True_Dual_Port_RAM} \ CONFIG.Write_Width_A {32} \ CONFIG.Write_Depth_A {1024} \ CONFIG.Write_Width_B {32} \ CONFIG.Write_Depth_B {1024} \ ] [get_ips my_mem] # 生成产物 generate_target {synthesis simulation} [get_ips my_mem] # 编译IP到OOC综合完成 synth_ip [get_ips my_mem]用脚本创建IP的好处是可重复几个工程里都用同一套脚本保证IP参数完全一致。要注意的是create_ip执行的时候会把IP直接加进顶层工程后续generate_target和synth_ip会按顺序生成对应文件。这个流程在CI自动构建里能省掉大量人工点击。3.4 IP编辑器的保存和更新IP定制好参数生成过一次之后如果想修改参数直接双击Sources里的xci会重新打开IP编辑器修改完点 OK 后Vivado会提示你“IP已经被修改是否需要重新生成输出产物”。点 YesVivado会重新生成并替换旧的dcp。注意这一步修改的是xci本身你自己的RTL代码里如果没有同步修改例化接口综合时就会报端口不匹配的错。在多人协作的开发模式里经常有人把IP参数改了以后忘记重新生成产物直接打包工程发给下一个同事结果对方综合时一直报IP端口不匹配排查半天最后发现只是忘了点Generate Output Products。这件事我踩过不止一次后来形成习惯只要改过IP参数第一件事就是跑一次 Report IP Status看到某个IP是黄色“Out of date”状态就右键Check/Reload并重新生成。4. 把自己写的RTL封装成一个可复用的IP不只厂商有IP我们自己写好的模块也可以封装成IP放进项目或者团队内部库下次像调Xilinx官方IP一样直接用。这一步对提升复用效率帮助很大。4.1 什么时候值得把代码打包成IP不是所有模块都有必要封装成IP。如果你的模块只是这个工程用一次那封装纯粹是给自己添麻烦。一般在下面几种场景我会打包公司/团队内部有统一接口标准比如全部走AXI4-Lite总线封装成IP后规范接口风格。模块要在两个以上项目中复用封装后参数化调配不需要每次复制源码再改。要给客户或合作方交付一个“黑盒”模块不希望对方看到内部RTL封装成IP后可以选择只输出网表保护代码知识产权。4.2 Create and Package New IP 的完整流程在Vivado里选择Tools-Create and Package New IP向导会问两个问题你要打包的是当前工程里的模块还是创建带AXI接口的新IP。如果只是把现有源码模块打包选“Package current project”或“Package a specified directory”。这里最常用的其实是创建AXI外设选“Create a new AXI4 peripheral”然后它会让你填IP名称、接口类型AXI4、AXI4-Lite、AXI4-Stream、接口模式Slave/Master以及寄存器数量。指定完接口Vivado会自动生成一套带AXI总线接口的骨架代码里面包含了寄存器读写逻辑的模板。接下来在IP编辑器的File Groups和Ports and Interfaces选项卡里添加你自己写的RTL文件或者把生成的骨架改造成真正的功能逻辑。确认后点 Review and Package填版本号、厂商信息、描述就能把IP打包到指定目录。打包完成后这个IP会出现在你的IP Catalog的User Repository分类下。想要在另一个工程里使用需要在IP Settings-Repository里添加打包目录然后回到IP Catalog搜索就能看到了。这里有个坑如果打包时选了加密或只输出网表生成的IP在综合时可能会额外要求一个“用于仿真的行为模型”否则仿真直接黑盒化容易误判。4.3 打包模板和参数化设计真正靠谱的封装IP一定要做参数化。比如我封装过自己的SPI Master模块对外暴露SPI_CPOL、SPI_CPHA、SPI_FREQ_DIV等参数。在打包时Vivado里需要把这些参数从RTL里的parameter或generic提取到IP定制界面里。具体在IP编辑器里点击Customization Parameters把端口和参数映射到GUI控件上设置好默认值、类型、显示名称。之后在别的工程双击该IP就能像官方IP一样像填表单一样填参数Vivado会根据参数生成不同实例。参数化封装做好之后整个团队的使用成本会大幅降低。同事不需要看懂你的Verilog只需要知道SPI_CPOL选0还是选1就能得到正确配置的IP。5. 高频报错和排错思路5.1 IP状态异常Out of date / Unsupported / Upgradable这是工程里最常见的三种状态。Out of date表示IP定义有改动但产物没有重新生成最简单的处理是选中IP后右键Generate Output Products。Unsupported通常是当前Vivado版本不支持该IP版本这个基本只能升级IP版本或者切换到对应版本的Vivado。Upgradable状态表示当前IP可以升级到新版本但升级后要注意工程内其他逻辑是否依赖旧版的端口时序行为。每次打开别人工程出现一堆黄色图标时别急着点“Upgrade All”。我曾经在一个老项目里点了自动升级所有IP结果几十个IP全被升级然后顶层模块的例化端口全部对不上花了整整一天修连接关系。正确做法是先确认当前Vivado版本和原工程版本差多少如果只是小版本差异可以先不升级IP直接将xci作为源文件添加很多时候不需要升级也能用。除非报错明确提示IP版本不兼容否则保持现状最省心。5.2 仿真找不到IP模型或编译不过添加IP之后如果你用的仿真语言是Verilog生成时会同时产生一个ip_sim_netlist.v或者支持行为仿真的模型文件。仿真报错里常见的Xilinx IP module not found大概率是因为generate_target simulation没有执行或者IP的仿真模型路径没有被正确包含。处理方法是菜单栏Simulation-Simulation Settings在Verilog Compiler的Include Directories里手动加上生成目录或者重新右键Generate Output Products勾上Simulation。在用Vivado自带仿真器时通常只要重新生成就能解决但如果你用的是ModelSim/Questa等第三方仿真器还要把IP的仿真库编译到对应目录否则会报“无法打开库文件”。这个问题在混合语言仿真中更常见——若干IP是VHDL另一些是Verilog编译顺序不对直接出几百条错误。5.3 生成比特流失败错误提示在IP内部综合没问题但又到Implementation时报失败错误提示指向某个IP内部的路径。这通常和IP的OOC综合有关。一个常见做法是右键IP选择Reset Output Products后重新生成。另一个常见原因是IP的约束与顶层约束冲突比如你的顶层set_property PACKAGE_PIN或者时钟约束与IP内部xdc冲突在Implementation阶段报出约束重叠。定位这种问题我的建议是先看地址和时钟约束。错误日志里如果提到“constraint from IP xxx”和“constraint from your top”,十有八九是顶层XDC里对同一个时钟或管脚写了重复约束。打开 Implementation 的Report Clock Interaction看一下跨时钟域路径确认IP输入时钟是不是在顶层被create_clock重新定义了但频率和IP里配置不一致。频率不一致是最隐蔽的坑IP内部按100MHz综合顶层却给它50MHz的约束现实中能跑100MHz的IP被当成50MHz去布线时序垮掉基本是意料之中。5.4 license相关异常和文件缺失IP是分授权类型的比如部分付费IP没有加载对应的License时IP Catalog会标注“License Required”或者完全搜不到。如果IP已经存在但打开报License错误首先要确认Vivado的License设置里是否包含了对应IP的授权其次看是不是在安装Vivado基础版时漏装了支持该IP的组件。这种情况在有些机器上重装一次License服务就能解决但也确实遇到过License管理器服务本身没开导致所有IP都无法定制。另外使用.xcix打包的第三方IP有时缺少必要的依赖文件比如多个xcix之间相互引用只添加一个会报“找不到xxx IP”。遇到这种情况备份整个IP库目录然后用Tools-IP Settings添加Repository不要把单个文件散着添加。5.5 提高生成速度的两个习惯IP数量多了以后每次生成Output Products都非常吃时间。我在工程开始阶段会把所有需要的IP先在草稿工程里生成好再把工程里的IP目录整体复制到正式工程目录。Vivado打开正式工程时因为已经存在产物文件会直接使用已有的dcp不再重新综合。另外推荐打开Settings-General确认“On IP Modification”和“Generate Output Products Automatically”被勾上。这样每次修改IP参数保存后Vivado自动重新生成避免忘了重新生成而惦记。如果只是改了一两个IP参数没必要全部重新生成。可以在Tcl Console里只对修改过的IP执行generate_target -force {synthesis simulation} [get_ips my_modified_ip] reset_target all [get_ips my_modified_ip] synth_ip [get_ips my_modified_ip]reset_target会清除旧的生成结果再执行synth_ip只综合这一颗IP。实测下来对于大型工程能省掉接近一半的等待时间。6. 一个小习惯省掉大半IP管理烦恼最后说一个我自己的项目管理习惯。每次建新工程我第一批操作里一定包含在工程根目录手动创建ip_lib文件夹然后在Settings-IP-Repository里把它加进去。以后从IP Catalog创建的所有自定义IP都默认存到这个统一目录而不是散落在项目各处的临时目录里。这样一来无论换电脑还是拉分支整个ip_lib可以作为一个独立的库随工程可控版本管理别人拿到工程后也不会出现满屏幕找不到IP文件的红叹号。还有一个小技巧在Vivado的 Sources 窗口里IP和普通源文件混在一起的时候可以使用分组视图。点击窗口右上角的排列图标按Source File Properties分组能看到IP的状态、语言、类型排查起来比一个个点开快很多。按上面的方式去操作添加现有IP文件、生成IP、封装自定义IP这些事基本不会出大乱子。遇到问题的时候先别急着重装Vivado先看IP的状态是Out of date还是Unsupported再决定是重新生成还是升级。细心管好你的IP库工程越复杂省的时间越明显。
返回列表