ARTICLE DETAIL

资讯详情

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

FPGA EDA三工具网表生成与复用:ISE、Vivado、Quartus

FPGA EDA三工具网表生成与复用:ISE、Vivado、Quartus ISE、Vivado、Quartus 这三套 EDA 工具我前后用了十来年从早期的 Spartan-3 一直到现在的 UltraScale 和 Agilex项目里踩过最多的坑不是时序收敛也不是引脚分配而是网表文件这一块——生成不难难的是怎么把它塞回另一个工程还能正常跑起来。很多同行第一次做只给网表不给源码的交付往往卡在黑盒报错、端口对不上、器件不匹配这几个地方折腾一整天都很正常。这篇把三个工具的网表文件生成与使用一次性讲透什么是网表、为什么工程里需要它、ISE 怎么出 NGC 和 EDIF、Vivado 怎么用 write_edif 加 synth_stub、Quartus 怎么搞 VQM 和 QXP 分区以及跨工具迁移时那些没人写在手册里的细节。不管你是刚接触 FPGA 的学生还是接手了别人工程要维护的老手都能从里面挑到能直接抄的步骤。1. 网表文件到底是什么为什么项目里绕不开它1.1 网表是结构描述跟源码不是一回事先说清楚概念。我们平时写的 Verilog/VHDL 是行为描述工具需要经过综合Synthesis这一步把它翻译成由查找表、触发器、进位链、块存储、DSP 单元以及它们之间的连线组成的结构描述这个结构描述就是网表。它描述的是有哪些元件、谁连到谁不再有 always 块、不有 if-else只有实例化关系和端口连接。这个区别很关键。源码可以拿到任何工具里综合网表不行——它已经绑定到具体工艺库了。Xilinx 的网表里是 LUT6、FDRE、RAMB36E1 这些原语Altera/Intel 的网表里是 LUT4、DFF、M9K、M20K两者根本不通用。所以你会发现网表文件的第一个用途天然就是锁死在某个器件系列上。我第一次接触网表是因为一个老项目客户只给了 .ngc 文件和一份端口说明没有源码。当时我以为是加密文件后来才明白这就是综合后的结构描述用它可以直接跳过一次综合编译时间从四十多分钟压到几分钟。从那时起我就习惯把稳定的模块固化成网表来复用。网表还有个容易被忽略的特点它是有版本属性的。同是 Xilinx 的 NGCISE 14.2 生成的拿到 14.7 里用大部分时候没问题但 Vivado 生成的 EDIF 拿到 ISE 里基本一定失败因为两者的原语库和命名规则都变了。1.2 三类网表文件用途完全不同初学者最容易搞混的一点网表文件其实分两大类一类给实现布局布线用一类给仿真用两者绝对不能互换。用途典型文件面向对象能否用来做布局布线实现用网表NGC、EDIF/EDN、VQM、DCP、QXP实现工具可以仿真用网表_synthesis.v、.vo、.vho、funcsim.v仿真器不可以交付用桩文件synth_stub.v、black box 声明综合工具不可以仅提供端口实现用网表里包含原语绑定只能被对应工具的对应器件库识别仿真用网表里调用的是仿真库模型unisims_ver、altera_mf 这类必须有对应的仿真库编译好才能跑桩文件stub只声明端口不包含任何逻辑它的唯一作用是在顶层综合时告诉工具这个模块存在端口长这样真身由网表文件顶上。很多人第一次用 Vivado 的 synth_stub 时以为它没用因为打开一看是空模块其实它不是给仿真看的是给综合器看的。没有它顶层实例化一个黑盒模块综合阶段就会报端口不存在的错误。1.3 我在项目里用网表解决的三个实际问题第一个是编译时间。一个包含 DDR 控制器和 PCIe 的大工程全流程综合加实现可能要一小时以上。把 DDR 控制器和部分固定逻辑固化成网表只改上层逻辑重新编译时间能压到十几分钟。这在需要反复迭代的调试阶段收益非常直观。第二个是交付与保护。给客户或者合作方交付模块时不希望给出源码就给网表加桩文件。对方能正常例化、能跑通时序但看不到内部实现。这里要说一句网表不是绝对安全的逆向网表在专业工具下是可以还原出部分逻辑结构的只是成本较高对一般的商业保护够用了。第三个是团队并行。两个人做同一个工程的不同模块各自综合成网表后在顶层焊起来避免了所有人的代码都塞在一个工程里、每次都要整体编译的麻烦。Quartus 的分区Partition和 Vivado 的 OOC 综合本质上都是在做这件事。2. ISE 生成与使用网表NGC 与 EDIF 两条路线2.1 用 XST 综合出 NGC从工程设置到文件落地ISE 的网表载体首选 NGC。NGC 文件是 XST 综合后的产物里面包含综合网表和一部分时序约束文件体积不大一个中等规模的模块通常几百 KB。在 ISE 里生成 NGC 的流程是把要固化的模块设为综合顶层右键模块Set as Top Module然后双击 Synthesize - XST 运行综合。综合完成后在工程目录下ISE 14.7 里通常是工程名/工程名.ngc或工程名/implementation/下能找到对应的 .ngc 文件。这里有个细节值得注意ISE 生成的 NGC 默认带时序约束如果综合时工程里有对应的 UCF部分约束会被写进 NGC。所以固化前最好单独建一个临时工程只放目标模块和一个干净的 UCF避免把顶层工程的约束误带进来。我踩过一次这个坑——固化出来的模块带着顶层时钟的周期约束放回新工程后时序报告里莫名其妙多了一堆约束排查了很久才发现是 NGC 里夹带的。如果想生成仿真模型在 Synthesize - XST 上右键Process Properties 里把Generate Post-Synthesis Simulation Model勾上综合后会输出模块名_synthesis.v或.vhd。这个文件用来做综合后仿真需要配合 unisims_ver 库和 glbl 模块。2.2 从 NGC 转 EDIF以及命令行脚本化有些场景必须用 EDIF比如对方工具链只吃 EDIF 格式或者需要做版本比对。ISE 提供了两条路。第一条是用 XST 直接输出。在 Process Properties 里找到Other XST Command Line Options填上-write_edif 模块名.edn。综合完成后会生成 EDIF 文件。注意这个选项要配合-i之类的路径参数使用路径最好写绝对路径否则容易输出到奇怪的目录里。第二条是用 ngc2edif 工具转换命令很简单ngc2edif my_mod.ngc my_mod.edn这个工具在 ISE 安装目录的 bin 下Windows 里是ngc2edif.exe。转换出来的 .edn 文件可以直接被 ngdbuild 识别。要批量做的话用 XST 的脚本模式更省事。写一个.xst文件set -top my_mod set -part xc7a35t-1fgg484 set -write_edif my_mod.edn set -write_ngc my_mod.ngc run然后命令行执行xst -ifn my_mod.xst -ofn my_mod.syr。这样一套流程可以塞进批处理或者 Makefile适合每天深夜自动跑一次的场合。注意XST 的-part参数必须和实际目标器件完全一致包括速度等级和封装。器件写错生成的网表拿到目标板上会直接报原语不匹配。2.3 ISE 引用 NGC 的工程设置与最容易翻车的地方把 NGC 用起来比生成它更容易出错。ISE 里正确的步骤是这样把 .ngc 文件 Add Source 到工程里。右键这个文件Source Properties把Association设成 NoneUnassociated。从工程中移除对应的 HDL 源文件或者把它的 Association 也设为 None杜绝重复定义。确认调用它的上层模块是当前综合/实现顶层。为什么必须做第二步和第三步因为 ISE 是用文件名匹配模块名的。ngdbuild 在展开设计时遇到一个实例化的模块名my_mod会先去搜索目录找my_mod.ngc找到就直接用它找不到才去找 HDL 源码。如果 HDL 源码还在工程里两个定义同时存在ngdbuild 会报模块重复定义的错误具体报错信息通常是ERROR:NgdBuild:604 - logical block xxx with type yyy could not be resolved或者Multiple driver。还有一个常被忽略的点NGC 的文件名必须等于模块名。你把文件重命名成my_module_v2.ngc但里面顶层模块还叫my_modngdbuild 是找不到的因为 ISE 按文件名去匹配。这个规则和 Vivado、Quartus 都不一样一定要记住。如果 NGC 文件不在工程目录下还要在 Translate 的 Process Properties 里加搜索路径。找到Search Directories对应-sd参数把 NGC 所在目录填进去多个目录用分号或者换行分隔。我一般倾向于直接复制到工程目录少配一个参数就少一个出错点。3. Vivado 生成与使用网表write_edif、synth_stub 与 DCP3.1 OOC 综合是前提不然写出来的网表不干净Vivado 里做网表第一步不是 write_edif而是把模块设成独立综合Out-of-Context简称 OOC。这个步骤的意义在于让这个模块脱离顶层环境单独综合得到的网表是干净的、可复用的如果不做 OOC直接把整个设计的综合结果写出来里面会混进顶层的信息复用价值很低。在 GUI 里选好模块后右键会看到Set as Out-of-Context Module之类的选项在 Sources 窗口的 Hierarchy 页里右键模块下的综合设置。在 Tcl 里更直接create_fileset -blockset -define_from my_mod ./my_mod_ooc add_files -fileset my_mod_ooc -norecurse ./rtl/my_mod.v set_property top my_mod [get_filesets my_mod_ooc] launch_runs my_mod_ooc_synth -jobs 8 wait_on_run my_mod_ooc_synthOOC 综合完成后这个模块会生成独立的 DCP工程顶层综合时会直接调用它不再重新综合。这一步本身就能节省大量编译时间即使你不打算把网表交给别人也值得做。需要提醒的是OOC 综合时模块的端口会被自动插入 IOBUF 或者被推断成端口缓冲这会影响时序。所以在 OOC 综合设置里最好把-mode out_of_context打开让工具不要给顶层端口插 IO 缓冲。这个选项不加出来的网表直接给顶层用会出现端口类型冲突的报错。3.2 write_edif 与 write_verilog -mode synth_stub 的配合使用Vivado 生成对外交付的网表标准动作是两条命令open_run my_mod_ooc_synth write_edif -force ./netlist/my_mod.edif write_verilog -force -mode synth_stub ./netlist/my_mod_stub.v第一条写出 EDIF 网表第二条写出桩文件。桩文件的内容就是一个只有端口声明的空模块module my_mod ( input wire clk, input wire rst_n, input wire [31:0] din, output wire [31:0] dout ); endmodule有人会疑惑既然 EDIF 里有完整信息为什么还要单独给桩文件原因在于综合阶段。Vivado 在综合顶层时需要知道被例化模块的端口方向、位宽、是否有时钟约束。这些信息 EDIF 里当然有但综合器在解析阶段并不会去读 EDIF它只解析 HDL。所以桩文件的作用是在综合阶段占个位让端口校验通过到实现阶段再用 EDIF 顶替逻辑。使用时的关键是三个文件同时处理# 加入网表和桩 add_files -fileset sources_1 -norecurse ./netlist/my_mod.edif add_files -fileset sources_1 -norecurse ./netlist/my_mod_stub.v # 把原始 HDL 停用避免重复定义 set_property IS_ENABLED FALSE [get_files ./rtl/my_mod.v]如果原 HDL 文件留在工程里且处于启用状态Vivado 会同时看到 HDL 定义和 EDIF 定义综合阶段报[Synth 8-2286] duplicate declaration或者实现阶段报黑盒未解析。把原文件 disable 掉是最省心的做法比从工程里删除文件更安全因为路径信息还在将来想恢复回到源码也方便。还有一个安全模式参数值得知道如果你的设计里包含加密 IP 或者某些厂商 IP直接 write_edif 可能报错或者导出不全加上-security_mode all可以把这些内容一起写出去write_edif -security_mode all -force ./netlist/my_mod.edif这个参数在交付包含 IP 的网表时很关键不加的话对方工程里会报一堆黑盒未解析。3.3 DCP 才是 Vivado 内部复用的首选EDIF 主要用于对外交付这里要说一个很多人不知道的取舍。在 Vivado 内部做模块复用时DCPDesign Checkpoint比 EDIF 好用太多write_checkpoint -force ./netlist/my_mod_synth.dcpDCP 里包含综合网表、约束、器件信息、参数设置而且读取速度快不需要桩文件配合。用法也简单GUI 里 Add Sources 选 Design Checkpoints 就行Tcl 里add_files -fileset sources_1 ./netlist/my_mod_synth.dcp那为什么还要用 EDIF因为 EDIF 是通用格式可以被第三方工具读取虽然原语还是 Xilinx 的而且在只允许传递网表、不允许传递约束的场合更合适。DCP 会把约束一并带过去有些约束是内部的交给对方可能会冲突。我的习惯是自己工程内部复用一律用 DCP对外交付用 EDIF 加桩文件。顺便说下 Vivado 生成仿真网表的命令跟上面完全不是一回事write_verilog -mode funcsim -force ./sim/my_mod_funcsim.vfuncsim 输出的是功能仿真模型里面调用 unisims_ver 和 secureip 库配合 glbl.v 一起仿真。这个文件不能拿去做实现我之前见过有人把它加进综合工程里报了一屏幕原语未定义就是典型的误用。4. Quartus 生成与使用网表VQM、EDIF 与 QXP 分区4.1 quartus_eda 生成 VQM/EDIFGUI 与命令行两种走法Quartus 的网表体系和 Xilinx 那套差别不小。它最常用的实现用网表是VQMVerilog Quartus Mapping File也就是 Verilog 格式的工艺映射网表另外它也能输出 EDIF但 EDIF 在 Quartus 内部用得不
返回列表