ARTICLE DETAIL

资讯详情

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

FPGA网表生成与交付:ISE、Vivado、Quartus黑盒实战指南

FPGA网表生成与交付:ISE、Vivado、Quartus黑盒实战指南 1. 先搞清楚网表文件在三个工具里的位置做 FPGA 项目ISE、Vivado、Quartus 这三套工具里的网表文件几乎每个交付阶段都会碰到。你可能有源码但客户只要一个能集成进去的黑盒或者团队里综合和实现分给两个人做中间就需要一份稳定的网表再或者你想保护自己的 IP不想把 Verilog 直接交出去。这些场景都绕不开网表。可网表这东西三个工具的叫法、格式、生成方式、使用方法都不一样新手第一次接触很容易被 NGC、EDN、DCP、EDF、QXP、VQM 这些后缀绕晕。我写这篇东西就是把我自己从 ISE 老工程、Vivado 新流程、Quartus 项目里折腾网表的经验摊开讲一遍尽量让你看完能直接下手而不是只记住几个名词。网表不是万能钥匙它更像一份“半成品图纸”。源码是设计意图综合之后变成与门、触发器、RAM、DSP、IO 缓冲这些厂商原语的连接关系这份连接关系就是网表。它已经丢掉了大部分人类可读的逻辑结构但还没有变成最终烧进芯片的比特流。ISE、Vivado、Quartus 分别属于不同厂商和不同时代它们的网表格式、原语库、约束体系都有差异所以你不能指望把 Quartus 生成的东西直接丢给 Vivado 用也不能随便把 ISE 的 NGC 当成 Vivado 的 DCP 来读。先把边界搞清楚后面操作才不容易翻车。1.1 网表不是源码也不是比特流我习惯把 FPGA 流程拆成四层RTL 源码、综合网表、实现后网表、比特流。RTL 源码最灵活能改参数、能加条件编译、能跨平台综合网表是工具把 RTL 翻译成厂商原语后的结果里面能看到 LUT、FF、BRAM、DSP48 之类的实例但看不到原来的 always 块实现后网表又进一步包含了布局布线信息和具体器件、具体管脚、具体时序强相关比特流则是最终配置芯片的数据基本不可读也不适合当交付物。网表处在中间层所以它既有“可交付”的一面也有“绑工具、绑器件、绑版本”的一面。很多人第一次生成网表是为了给仿真用结果拿到的是综合后仿真模型不是可综合网表也有人想给客户一个黑盒却把带布局信息的网表交出去客户换一个器件就完全用不了。这两种情况我都见过。判断标准很简单如果你希望对方还能继续综合、布局、布线那就给综合后网表如果你只是让对方做功能仿真那就给仿真网表如果你希望对方直接复用你的实现结果那才考虑实现后网表或分区网表。三者别混。还有一点网表里的端口名、实例名、参数名非常关键。RTL 阶段你可以用generate生成一堆名字综合后这些名字可能被工具改写、打平、优化掉。如果交付时没有保留层次对方拿到的网表可能连顶层端口都对不上。我的习惯是凡是要交付网表的模块综合时尽量保留层次关键模块加keep_hierarchy或等价属性端口顺序和方向在文档里写死别让接收方靠猜。1.2 ISE、Vivado、Quartus 的网表家族盘点先看一张速查表把常见后缀和用途对上号。不同版本工具有细微差异但大方向不会差太多。工具常见网表/中间文件典型扩展名主要用途跨工具可用性ISENGC 综合输出、EDIF 网表、NGD/NCD.ngc、.edn/.edf、.ngd、.ncdISE 内部实现、黑盒交付、仿真同厂商有限跨厂商基本不行VivadoDCP 检查点、EDIF、Verilog/VHDL 网表.dcp、.edf、.v/.vhd工程恢复、黑盒交付、仿真、层次化DCP 绑版本EDIF 可读但原语受限QuartusQXP 分区、VQM、仿真网表.qxp、.vqm、.vo/.vho团队分区、第三方综合导入、仿真QXP 绑 Quartus 版本VQM 绑 Quartus 原语ISE 的 NGC 是 XST 综合后的二进制网表里面通常还打包了约束信息所以用 NGC 时不要再重复加同一份约束。EDN 或 EDF 是更“纯”的 EDIF 网表适合交给别人读。Vivado 的 DCP 是 checkpoint不只是网表还包含设计状态、约束、器件信息所以它最方便恢复工程但也最挑版本。Quartus 的 QXP 是设计分区导出文件做增量编译和团队分工很好用VQM 则是 Quartus 映射网表常见于第三方综合工具输出给 Quartus 的场景不是拿来跨到 Xilinx 的。这里要提醒一句EDIF 虽然名字看起来通用但通用的是文件语法不是原语库。一个 EDIF 里如果全是 Xilinx 的 LUT6、FDRE、DSP48E1拿到 Quartus 里就是不认识。反过来也一样。所以“EDIF 可以跨工具”这句话只对了一半真正能不能用要看网表里引用了哪家的库。1.3 什么时候该用网表交付什么时候别偷懒网表交付最典型的场景是 IP 保护。你开发了一个算法模块或者接口控制器不想把源码给客户但客户又要在自己的顶层里例化。这时候给综合后网表加黑盒桩文件是最常见的做法。另一个场景是团队分工综合工程师先把大模块综合成 DCP 或 QXP实现工程师拿网表继续布局布线避免每次都从头综合。还有就是快速集成第三方 IP 只给网表你需要在工程里读进来配上约束再和自己的逻辑连接。但网表不是所有时候都合适。如果对方需要改参数、改位宽、加调试逻辑给网表就是给自己找麻烦如果对方器件不同、工具版本不同网表很可能不可用如果设计里用了大量厂商 IP 核网表交付还要把 IP 的网表、约束、仿真模型一起打包漏一个就链接失败。我一般的判断是只有接口稳定、参数固定、工具和器件明确、接收方只需要集成不需要修改时才用网表交付。否则宁可给源码加密或者通过正规授权方式交付也别硬塞网表。2. ISE 生成网表从 XST 到 NGC/EDN 的老派流程ISE 这套工具现在看起来老但很多老项目、老器件、老代码还在用。它的网表流程和 Vivado 差别很大生成方式更依赖 XST 选项工程管理也更“手工”。如果你手里有 ISE 14.7 之类的环境下面这套流程基本能跑通。注意安装和授权走正规渠道这里只聊工程内的网表操作。2.1 用 Project Navigator 导出综合网表在 ISE 里新建工程选好器件、综合工具选 XST把源码和约束加进去。综合之前先打开 Process Properties找到 Synthesis Options 里的输出选项。XST 可以生成 NGC也可以额外写出 EDIF 网表、Verilog 或 VHDL 仿真模型。常见的几个开关是Write Edif Netlist、Write Verilog、Write VHDL。如果你要交付黑盒勾上 EDIF 输出如果你还要给对方仿真勾上 Verilog 或 VHDL。综合跑完后在工程目录下能看到类似top.ngc、top.edn、top.v的文件。这里有个细节ISE 的 NGC 默认会包含约束和部分综合信息适合自己工程继续实现EDN 更接近纯网表适合交付。不要同时把 NGC 和 EDN 加入同一个工程来代表同一个模块否则很容易出现重复定义。我的做法是自己用 NGC交付用 EDN仿真模型单独放一个目录文档里写清楚每个文件的用途。2.2 XST 命令行和批处理脚本怎么写图形界面适合第一次跑但批量生成网表还是命令行稳。XST 可以直接吃脚本文件下面是一个裁剪过的模板具体参数名请按你安装的 ISE 版本核对。xst -intstyle ise -ifn top.xst -ofn top.syrtop.xst里面大致是这样run -ifn top.prj -ifmt mixed -ofn top.ngc -ofmt NGC -write_edif yes -write_verilog yes -write_vhdl notop.prj里列出所有 Verilog/VHDL 源文件和包含路径。综合完之后top.ngc、top.edn、top.v会出现在输出目录。批处理里再调用ngdbuild、map、par继续实现。这样做的好处是可重复网表生成不依赖鼠标点选版本管理也方便。注意事项命令行里的-ofmt决定输出格式NGC 和 EDIF 不是一回事-write_edif yes才会额外写 EDIF如果工程里有 IP 核XST 命令行还要把 IP 的网表或仿真文件加进top.prj否则综合时会报黑盒未定义。2.3 黑盒例化和网表使用ISE 里使用网表黑盒通常是在顶层源码中声明一个空模块端口和网表一致然后在工程里把 EDN 或 NGC 添加为源文件。综合时ISE 会把这个空模块当成黑盒链接时用网表填充。UCF 约束里要给出黑盒模块内部关键路径的时钟约束否则时序分析会不完整。如果网表是 NGC可能已经带了约束这时要避免重复约束冲突。一个常见的坑是端口方向写反。黑盒桩文件里input、output、inout必须和网表完全一致位宽也要一致。ISE 不会像 Vivado 那样给出特别友好的提示很多时候就是链接失败或者实现阶段报错。我的习惯是生成网表后先用ngdbuild单独跑一遍确认网表能读进来再放进完整工程。2.4 ISE 网表踩坑清单NGC 和 EDN 别同时代表同一个模块选一种。黑盒桩文件端口必须和网表一致名字、方向、位宽都不能错。网表里可能已经包含约束UCF 里重复约束会冲突。器件型号要一致不同器件的原语可能不兼容。ISE 版本差异会影响 NGC 读取交付时注明工具版本。综合时尽量保留层次否则网表里的实例名可能被优化掉。如果模块里有未连接端口综合可能优化掉交付前要确认。仿真网表不等于综合网表别拿top.v去当黑盒。3. Vivado 生成网表DCP 是主力EDIF 是桥梁Vivado 的网表流程比 ISE 清晰很多核心就是 DCP。DCP 不只是网表它是一个检查点里面包含当前设计状态、约束、器件信息甚至包括综合或实现后的结果。你可以把 DCP 理解成“存档”打开之后继续跑实现、写报告、做调试。EDIF 则是更传统的纯网表适合交付黑盒。两者用途不同别混着用。3.1 综合后 DCP 与后实现 DCP 的差别综合后 DCP 是在synth_design之后write_checkpoint得到的。它包含综合后的逻辑网表、约束和器件信息还没有布局布线。后实现 DCP 是在place_design、route_design之后写出的包含布局布线结果可以用来做时序分析、功耗分析、增量实现甚至可以直接生成比特流。如果你只是想让别人继续实现给综合后 DCP如果你想复用实现结果给后实现 DCP如果你只是想让别人读网表做黑盒EDIF 更轻。DCP 和 Vivado 版本绑定很紧。用 2022.2 生成的 DCP拿到 2020.1 里可能打不开跨大版本更危险。交付时一定要写清楚 Vivado 版本、器件型号、是否包含约束。我的经验是DCP 适合团队内部同版本协作跨团队交付优先给 EDIF 加仿真模型或者直接给源码让对方重新综合。3.2 Tcl 生成 EDIF、Verilog/VHDL 网表下面是一段常用的 Vivado Tcl假设顶层是top器件是xc7a100tcsg324-1源文件在src目录。read_verilog [glob ./src/*.v] read_xdc ./src/top.xdc synth_design -top top -part xc7a100tcsg324-1 write_checkpoint -force ./output/top_post_synth.dcp write_edif -force ./output/top_post_synth.edf write_verilog -force -mode funcsim ./output/top_funcsim.v write_vhdl -force -mode funcsim ./output/top_funcsim.vhdwrite_checkpoint写出综合后 DCP后面可以open_checkpoint继续实现。write_edif写出 EDIF 网表适合交付黑盒。write_verilog和write_vhdl的-mode funcsim生成功能仿真网表-mode timesim生成时序仿真网表。注意仿真网表通常是给仿真器用的不是拿来综合的。如果你要生成综合桩文件可以用write_verilog -mode synth_stub之类的模式具体模式名以版本为准。后实现网表可以这样写open_checkpoint ./output/top_post_synth.dcp opt_design place_design route_design write_checkpoint -force ./output/top_post_route.dcp write_edif -force ./output/top_post_route.edf后实现 EDIF 仍然不包含布局布线信息只是逻辑网表。想要保留布局结果还是用 DCP。如果你要交付某个子模块的 DCP可以用write_checkpoint -cell指定层次但前提是该层次没有被打平综合时最好保留层次。3.3 在 Vivado 工程里使用网表黑盒使用 EDIF 黑盒时顶层 RTL 里要有一个和网表端口一致的桩模块。可以在模块前加黑盒属性(* black_box true *) module core ( input wire clk, input wire rst_n, input wire [31:0] din, output wire [31:0] dout ); endmodule然后在 Tcl 里先读桩文件再读 EDIF最后链接read_verilog ./src/top.v read_verilog ./src/core_stub.v read_edif ./ip/core.edf read_xdc ./src/top.xdc link_design -top top -part xc7a100tcsg324-1 opt_design place_design route_design write_bitstream -force ./output/top.bit如果是 DCP 层次化流程可以用read_checkpoint -cell u_core ./ip/core_post_synth.dcp但要注意 DCP 里的顶层名、端口、器件要和当前工程匹配。用 DCP 的时候通常不需要再读 EDIF也不要重复读同一个模块的源码否则会报重复定义或黑盒冲突。3.4 Vivado 网表常见报错与处理Vivado 的报错信息相对清楚但有些问题还是容易卡人。比如Unresolved black box通常是桩文件没读、端口不匹配、或者 EDIF 没读进来Part mismatch是网表器件和当前工程器件不一致Cell not found是层次化路径写错DCP version mismatch是版本不兼容。排查顺序我一般是先看端口再看顶层名再看器件再看版本最后看约束。端口和顶层名的问题占了一多半。还有一个常见问题是时钟约束。黑盒网表内部如果有寄存器顶层 XDC 必须给出时钟否则时序分析会认为没有时钟实现结果可能很差。如果网表本身就是后实现 DCP约束可能已经在里面重复加 XDC 反而会冲突。交付文档里最好写清楚网表是否自带约束顶层需要补哪些时钟和 IO 约束。4. Quartus 生成网表QXP、VQM 和仿真网表别混用Quartus 的网表生态和 Xilinx 那边不太一样。它最常用来做团队协作的是 QXP 分区文件最常和第三方综合工具打交道的是 VQM最容易让人误解的是 EDA Netlist Writer 生成的仿真网表。很多人把.vo当成可综合网表结果导入后报一堆错其实就是用途搞错了。4.1 QXP 导出与导入的完整流程QXP 是 Quartus 的设计分区导出文件。它可以把某个层次模块单独综合或适配后导出让上层工程直接导入使用。图形界面流程大致是先确保要导出的模块保留了层次在 Assignments 菜单里打开 Design Partitions Window新建或指定分区设置分区类型为 Post Synthesis 或 Post Fit然后通过 Project 菜单导出设计分区保存为.qxp。导入时在顶层工程里例化一个黑盒模块端口和 QXP 一致再通过 Project 菜单导入设计分区指定对应实例。QXP 的好处是团队可以并行开发底层模块先固化顶层不用每次重新综合。坏处是版本绑定强Quartus 版本、器件型号、顶层名、端口名有一个不对就可能导入失败。我一般会把 QXP 和一份端口说明、约束说明、工具版本号放在同一个交付目录里接收方按文档操作别自己猜。4.2 VQM 和 EDA Netlist Writer 的用途VQM 是 Quartus Mapping 网表常见于 Synplify、Precision 等第三方综合工具输出给 Quartus 的场景。Quartus 可以读取 VQM 作为设计文件然后继续映射、布局、布线。它不是给 Xilinx 工具用的也不是通用交换格式。如果你手里只有 Quartus想把自己的设计导出成 VQM 给别人一般不是为了跨工具而是为了配合特定综合流程。EDA Netlist Writer 生成的是仿真网表通常是.vo或.vho配合 ModelSim 等仿真器做功能仿真或时序仿真。它不能拿来综合因为里面包含厂商原语和仿真模型有些结构综合器不认识。很多人看到.vo是 Verilog 文件就以为可以当源码用这是典型的误区。仿真网表要配合仿真库使用缺了库文件连编译都过不了。4.3 命令行 quartus_eda 生成仿真网表Quartus 的命令行工具比较多生成仿真网表常用quartus_eda。下面是一个示意命令具体参数以你的 Quartus 版本为准quartus_eda top --simulation --toolmentor --formatverilog --output_directorysim有时候也可以先跑quartus_map综合再跑quartus_eda输出网表。图形界面里对应的是 Processing 菜单下的 Generate Simulator Netlist。我的建议是第一次用图形界面生成然后把生成的命令记录到脚本里后面批量跑。这样既不容易写错参数也方便版本管理。如果你要生成 QXP命令行也有对应工具但不同版本差异较大。稳妥做法是在图形界面里操作一次然后在 Quartus 的 Tcl Console 里查看它自动生成的命令再复制到脚本中。别硬背命令工具版本一换就容易踩坑。4.4 Quartus 网表使用的注意点QXP 和源码不要同时代表同一个模块否则重复定义。分区类型要选对Post Synthesis 和 Post Fit 的复用程度不同。导入 QXP 时实例名、端口名、器件型号、Quartus 版本都要匹配。仿真网表.vo/.vho不能当可综合源码用。VQM 是 Quartus 生态内的映射网表不要指望跨到 Vivado。黑盒模块的端口方向、位宽、时钟域要在文档里写清楚。如果 QXP 内部有时钟顶层 SDC 要补时钟约束或者确认 QXP 自带约束。资源报告和时序报告要一起交付否则接收方不知道网表的真实状态。5. 跨工具迁移和常见问题速查5.1 三个工具的网表能不能互相吃这是问得最多的问题。我的结论很直接同厂商内部有限可用跨厂商基本不可行。ISE 的 EDIF 理论上可以被 Vivado 读取但里面的 Xilinx 原语、约束、IP 可能不兼容尤其是老器件原语和新器件原语差异很大。Vivado 的 DCP 不能给 ISE也不能给 Quartus。Quartus 的 QXP 只能在 Quartus 里用VQM 也绑 Quartus 原语。跨厂商迁移最靠谱的方式是拿源码重新综合或者让原开发者提供对应工具的网表版本。如果你非要在 Xilinx 内部迁移比如从 ISE 到 Vivado建议先拿一个小模块试。用 Vivado 的read_edif读入 ISE 生成的 EDIF补上黑盒桩和约束看能否链接、综合、实现。能跑通再考虑大模块。别一上来就迁移整个工程容易陷在报错里出不来。5.2 常见问题速查表现象可能原因处理思路黑盒未解析桩文件缺失、端口不匹配、网表未读入先核对端口和顶层名再确认 read_edif/read_checkpoint 顺序器件不匹配网表器件和当前工程器件不同换对应器件网表或重新综合版本打不开 DCP/QXP工具版本不一致用原版本打开或让对方导出 EDIF/仿真模型时序不收敛黑盒内部无时钟约束顶层补 XDC/SDC确认网表是否自带约束重复定义源码和网表同时存在二选一黑盒只留桩文件仿真编译失败缺厂商仿真库编译对应仿真库确认.vo/.vho用途资源报告异常网表被优化或层次打平综合时保留层次检查 keep 属性导入后行为不对端口方向或位宽错误对照端口文档逐位核对5.3 我踩过的几个坑和排查顺序第一个坑是端口顺序。Verilog 例化可以用位置关联也可以用名字关联。网表交付时最好强制用名字关联否则端口顺序一变就全错。第二个坑是顶层名。Vivado 的 DCP 和 Quartus 的 QXP 都对顶层名敏感交付文档里必须写清楚网表顶层叫什么别让接收方猜。第三个坑是约束重复。NGC 和 DCP 可能自带约束你再加一份同样的时钟约束工具可能报冲突或者直接忽略时序结果就不对了。我的排查顺序通常是先看端口和顶层名再看器件和工具版本再看约束最后看网表内容。大部分问题在前两步就能定位。如果前两步都没问题再用工具的报告看黑盒是否真的被链接进来有没有被优化掉。别一上来就怀疑工具坏了网表问题九成是接口和版本问题。6. 网表交付工程化目录、版本和复现记录6.1 交付包里应该放什么一个靠谱的网表交付包绝不只是丢一个.edf或.qxp。我一般会放这些内容网表文件本身、对应的仿真模型、端口说明文档、约束文件或约束说明、工具版本和器件型号、资源与时序报告、一个最小测试用例、README。端口说明里要写清楚每个端口的名字、方向、位宽、时钟域、复位极性。约束说明里要写清楚顶层需要补哪些时钟、输入输出延迟、虚假路径。最小测试用例能让接收方快速验证网表能不能链接、能不能跑通。如果是 DCP 或 QXP还要注明是否包含约束、是否包含布局布线、能否继续实现。别让接收方拿到后自己试半天。交付文档写得越清楚后面扯皮越少。6.2 版本兼容与归档策略DCP、QXP、NGC 这些格式和工具版本绑定很强。我的做法是交付时把工具版本号写进文件名和文档比如top_vivado2022.2_xc7a100t.edf、core_quartus18.1_ep4ce10.qxp。同时保留生成网表的脚本和源码 tag万一网表有问题还能回到源码重新生成。归档时把网表、脚本、报告、文档放在同一个目录别散落在不同磁盘。如果团队内部用 Git 管理网表文件通常比较大不建议直接塞进普通仓库。可以放制品库或者用 Git LFS。更重要的是网表不是源码不能只看 diff 判断变化。每次重新生成网表都要记录对应的源码提交号、工具版本、综合选项。否则过几个月你根本不知道这份网表是从哪来的。6.3 一份可复现的网表实验模板我常用下面这种目录结构ISE、Vivado、Quartus 都可以套project/ src/ # 源码或桩文件 xdc/ # 约束 scripts/ # 生成网表的 Tcl/Bat 脚本 output/ # 网表、DCP、QXP、报告 sim/ # 仿真模型和测试用例 doc/ # 端口说明、版本说明、READMEVivado 里用scripts/build_netlist.tcl一键生成 DCP 和 EDIFISE 里用scripts/run_xst.bat跑 XSTQuartus 里用图形界面生成一次再把命令记到scripts/export_qxp.tcl。每次生成后把output目录归档附上doc/release_note.md。这样别人拿到交付包能复现也能验证。最后分享一个我自己的习惯网表交付前一定用一个空顶层工程实际链接一遍。别只在原工程里综合通过就认为没问题。空顶层只例化黑盒补最少的约束跑一遍综合或实现。如果能过说明端口和网表基本没问题如果过不了问题一定在交付包本身而不是接收方的工程。这个步骤花不了多少时间但能省掉后面大量的沟通成本。
返回列表