首页 / 资讯中心 / 文章详情

FPGA工程创建全流程:从Verilog到Vivado比特流下载实战

FPGA工程创建全流程:从Verilog到Vivado比特流下载实战 ★ FEATURED ARTICLE
又到一篇笔记。第九篇我不打算继续推 Verilog 语法而是想聊聊怎么把一个写好的.v文件真正变成一个能跑在 FPGA 上的设计。不少读者私信问过类似的问题功能仿真明明通过了但怎么才能点亮板子上的 LED答案就在这里——基于 Vivado 的 FPGA 工程创建。这篇笔记会从软件安装一直讲到生成比特流并下载到开发板同时把约束文件、仿真、工程组织这些容易出错的细节一并过一遍。适合已经写过一些 Verilog、但还没完整跑通 FPGA 工程流程的朋友也适合刚从 Icarus Verilog 转到 Vivado 的人按顺序操作基本不会迷路。1. 为什么我把“创建工程”单开一篇工具链的思维转变很多人在学习 Verilog 的初期是在 Icarus Verilog、Modelsim 或者别的轻量仿真工具里做验证。写一个模块写一个 testbench编译、跑仿真、看波形这一套顺手之后突然切到 Vivado 会很不适应。因为 Vivado 不只是“仿真器”它是一整套 FPGA 设计套件涵盖综合、实现、时序分析、比特流生成乃至板级调试。它的工程概念比单纯一个源码文件复杂得多所以需要一个专门的操作流程这就是这篇笔记存在的意义。1.1 从仿真器到完整设计流程的跨越在 Icarus 里你的世界里只有 RTL 代码和 testbench在 Vivado 里设计文件、约束文件、IP 核、仿真文件和组织脚本构成了一个工程。综合Synthesis会把 Verilog 代码映射成 LUT、触发器、DSP、BRAM 这些实际资源实现Implementation负责将这些资源布局布线到 FPGA 内部最后一步 Generate Bitstream 生成一个比特流文件把它通过 JTAG 下载到板子上硬件才会真正按你的逻辑运行。这个思维转变很关键。功能仿真通过不等于硬件能跑。仿真器是基于理想时序的抽象模型而真实 FPGA 有布线延迟、时钟偏斜、建立保持时间约束、IO 标准要求。所以工程创建不仅仅是一个“新建文件夹”的动作更是一个引入完整设计流的过程。1.2 Vivado 工程到底管理了什么一个 Vivado 工程不是一个单个文件而是一个目录树。默认情况下会生成.xpr工程文件、src源文件目录、sim仿真目录、constrs约束目录以及runs综合实现目录。工程文件记录了你添加了哪些源文件哪个是顶层目标器件是什么使用了哪些 IP 核约束文件的优先级等等。你以后修改代码、换板子、重跑综合都是基于这个.xpr文件来组织的。所以工程创建的规范性直接影响后续开发的效率。我见过不少朋友把几十个.v文件直接拖进一个文件夹用include乱飞最后在综合报告里根本看不懂哪个模块被例化了几次。工程创建时如果能把目录和文件角色规划清楚后面会非常省心。1.3 GUI 与 Tcl 脚本各解决什么问题创建工程有两种方式图形界面GUI和 Tcl 脚本。初学者推荐从 GUI 入手因为能直观看到每个选项的作用。等你重复创建过三次以上工程就会意识到脚本化的必要性——写一个create_project.tcl以后每次重建工程只要source一下五分钟恢复全部环境。这篇笔记以 GUI 流程为主线但在最后一节会补一个脚本化创建的思路。两者并不互斥我日常是先用 GUI 弄清楚选项再沉淀成脚本。2. Vivado 版本选择和安装这些细节容易翻车我写这篇笔记时的最新版本已经到了 Vivado 2025.1不过 2023.1 之后的版本菜单结构基本一致大家不必追求最新。重点在于版本满足你需要用的 FPGA 型号以及安装时别踩那几个经典坑。2.1 免费许可证够用吗AMD/Xilinx 官方提供免费的 WebPACK 许可证适用于大多数中小容量的艺术器件Artix、Kintex 部分型号和一些单芯片 Zynq 器件。对于学习用的 Artix-7 XC7A35T、XC7A100T、Zynq-7020 这类芯片完全够用。工程创建时如果提示没有 License一般是因为你选了 Enterprise 版本禁止的器件或者 License 没有配置好。解决方法是先确认自己在 Project Part 里选的芯片再去 License Manager 看一下本机 WebPACK 状态。不需要也没必要折腾网上那种来路不明的授权补丁官方免费版已经覆盖了绝大多数学习场景。2.2 磁盘、内存和路径的硬性要求这是我想放到前面说的一点因为不少人是装到一半才后悔的。Vivado 完整版安装包大约 100GB/解压后占用 70GB 左右空间即使只安装核心工具也会接近 30GB。内存方面8GB 只能算入门综合稍微大一点的图像处理模块16GB 以上会更舒适。磁盘建议用固态硬盘综合和实现的中间产物写入非常频繁。路径问题是这篇系列笔记里最容易被忽略的“第一坑”工程路径、安装路径千万不要放在包含中文、空格或特殊字符的目录下。Vivado 的 GUI 在某些中文路径下会诡异闪退Tcl 命令报错甚至生成比特流失败。我见过有人把工程放在D:\学习资料\FPGA实验\新建文件夹1结果综合到一半直接崩溃。稳定做法是建立一个类似D:\fpga_workspace\project1的纯英文路径所有工程统一管理。2.3 安装过程中的小插曲安装 Vivado 时到组件选择页面默认会勾选“Vivado HL WebPACK”、“Vivado HL System Edition”等一堆选项。不要全勾除非你的磁盘真的很大。对于最常用的 RTL 开发只需要勾选Vivado、Vivado HL WebPACK相关内容以及Hardware Manager调试和下载需要用到。SDK 可以后面单独装安装时可以先不勾选。另外安装过程中可能会弹窗提示WinPcap安装失败这个组件主要用于以太网调试和远程连接不影响正常 JTAG 下载跳过即可。网上总有人问这个错误其实不需要处理。还有一个老生常谈的问题Vivado 怎么改中文。官方界面没有完整中文网上所谓的汉化包基本都不靠谱而且改了之后很容易出现信息缺失、报错定位困难。我的建议是直接接受英文环境Vivado 的报错关键词本来就是英文这样遇到问题也方便复制粘贴去搜索。3. 从 Create Project 到目标器件新建工程的完整路径这一节是纯操作步骤我尽量把每一步的界面选项讲清楚并且告诉你为什么这么选。3.1 工程名称和位置的规范习惯双击 Vivado在欢迎界面点Create Project或者菜单File New Project进入向导。第一步写 Project Name我建议尽量用能表达工程内容的名字例如uart_rx_demo而不是test1、project_final。工程路径选到一个专门放置工程的目录比如D:/vivado_prj。注意不能勾选Create project subdirectory以外的那些杂项除非你想把工程文件拆开。这个路径本身会成为工程根目录后面所有源文件、子目录都围绕它组织。3.2 Project TypeRTL Project 还是别的向导会让你选择 Project Type常见选项有RTL Project、Post-synthesis Project、I/O Planning Project等。初学者选默认的RTL Project并且建议勾选下面的Do not specify sources at this time先不添加源文件。这样有一个干净的工程骨架后续用 Add Sources 逐步添加文件避免向导过程中误选文件。如果你是憋着一股劲想一次建完整可以现场添加但我的经验是工程骨架干净一点后面好改。3.3 Part Selection目标器件的选择到了 Part 选择界面有两种模式一种是直接选择芯片型号另一种是按开发板选择 Board。如果你用的是开发板可以直接在 Board 页里搜板的品牌但因为 Board 文件可能需要额外安装很多时候大家找不到就转到 Part 页手动选。以常见的学习板为例如果是 Basys3 或者 EGO1芯片大概率是 Artix-7 XC7A35T-1CPG236C如果是 ZedBoard那就是 Zynq-7045 或类似型号。选中对应型号时界面会显示资源用量LUT、Flip-Flop、Block RAM、DSP、IO 数量你可以大致评估自己的设计规模是否放得下。注意不要选错封装例如 CSG324 和 CPG236 的引脚数量不同后续约束文件会完全对不上。3.4 默认 Summary 和空工程的样子最后一步会列出一个 Summary点击 Finish 后会看到 Vivado 主界面左侧是 Flow Navigator中间是设计源文件和工程总览下方会出现 Tcl Console。一个刚创建的空工程Sources面板只有一个主工程项没有任何设计源。这时候不要急着写代码先设置好工程属性右键工程名选Settings在General里确认 Top Module 是自动还是手动在Simulation里设置仿真器的编译选项。这些设置后面也会经常用到。4. 设计源文件组织RTL、Testbench 和 IP 怎么放才算规范新建了一个空工程之后接下来要把代码文件导入进去。这一步如果随随便便后面的仿真、综合和团队协作都会变扭。4.1 添加 Verilog 文件与目录约定在 Sources 面板中点加号选择Add or create design sources。你既可以从磁盘导入现成的.v文件也可以在工程里直接创建新文件。这里有个建议在工程目录下提前建好rtl、sim、constrs三个子目录分别放置设计代码、仿真代码、约束文件。Vivado 虽然不会强制让你这样做但参考工程维护经验这是最直观的分类方式。比如你做一个 SPI ADC 采集模块rtl/spi_adc.v、sim/tb_spi_adc.v、constrs/pin_adc.xdc一目了然。后续如果扩展成图像处理、UART 传输也只需要按模块再建子目录。4.2 小心顶层设置Set as Top一个工程允许有多个.v文件但必须指定一个顶层模块Top Module。Vivado 默认会自动推导顶层但如果你文件里存在多个模块或者一个文件里定义了多个 module自动推导可能出错。正确做法是在Sources面板选中自己设计的顶层模块右键选择Set as Top。这个动作很基础但很多人忘了导致综合时选错入口报出一堆“模块未定义”的错误。另外命名规范最好统一。顶层命名不要再用top这种泛名直接用功能名例如spi_adc_top。测试模块则统一加上tb_前缀这样在 Sources 面板里一眼就能和设计文件分开。4.3 添加 IP 核的入口和文件管理如果你的设计需要 PLL/MMCM 产生时钟、BRAM 做数据缓存、FIFO 跨时钟域直接在 Sources 面板点加号选择Add or create IP。Vivado 会打开 IP Catalog搜索例如Clocking Wizard、FIFO Generator、Block Memory Generator。添加后 IP 会以.xci文件形式出现在工程中综合时会被自动处理成网表。这里要注意IP 核的实例化名和配置文件最好放在一个独立目录例如ip/不要跟 RTL 代码混在一起。否则一旦需要重新生成 IP散落的文件很难清理。4.4 仿真文件与综合文件分离的重要性Vivado 会默认把 testbench 和 RTL 源文件混着显示但仿真和综合是两套文件集合。在Sources面板顶部有三个页签Design Sources、Constraints、Simulation Sources。仿真文件应出现在 Simulation Sources 下面并且可以直接右键点Run Simulation触发行为仿真。如果把 testbench 混在设计源里综合时会把不可综合的initial、#10之类语法也包进去综合直接报错。我见过太多这种低级错误本质上是文件分类没有做干净。规范做法是RTL 文件只在 Design Sources带tb_前缀的文件只加到 Simulation Sources约束文件只放 Constraints 下这是工程创建的核心纪律。5. XDC 约束文件和引脚规划不结束最后的自由意志Verilog 代码告诉 FPGA 逻辑怎么连但如果没有 XDC 约束文件FPGA 芯片并不知道clk信号要连接封装上的哪个引脚。约束文件是 FPGA 工程里“最后一公里”。5.1 为什么要物理约束和时序约束XDC (Xilinx Design Constraints) 文件包含物理约束引脚位置、IO 标准和时序约束时钟周期、输入输出延迟。物理约束让sys_clk这个信号映射到板上的晶振引脚让led[0]映射到 LED 对应的引脚时序约束告诉工具时钟频率是多少工具在布局布线时才能判断路径是否收敛。没有 XDC就算综合成功实现也可能因为找不到引脚而失败没有时钟约束时序分析就是个空壳。5.2 用 I/O Planning 快速生成 XDC手工记引脚编号容易出错特别是开发板上有几十个引脚的时候。推荐先用 GUI 辅助在窗口顶部选Layout I/O Planning或者在 Flow Navigator 中找到Open Elaborated Design后点击I/O Planning。打开后可以看到所有 IO 引脚在旁边的引脚分配表里双击信号名从下拉表格中选择要绑定的封装引脚和 IO 标准。完成引脚分配后点击保存图标Vivado 会生成一个默认的 XDC 文件并自动加入工程。这比手写set_property PACKAGE_PIN更直观。对于最简单的实验板点灯工程XDC 内容基本是两三行set_property PACKAGE_PIN P17 [get_ports {clk}] set_property IOSTANDARD LVCMOS33 [get_ports {clk}] set_property PACKAGE_PIN M14 [get_ports {led[0]}] set_property IOSTANDARD LVCMOS33 [get_ports {led[0]}]引脚编号一定要查你自己的板卡原理图千万不能照抄网上别人的板子。同一颗芯片的不同封装引脚号完全不一样。IO 标准也要匹配板卡 bank 电压别把 1.8V 的 bank 插 LVCMOS33那样轻则采不到信号重则可能损伤芯片。5.3 手写 XDC 的常见坑我见过不少手写 XDC 的教程但最容易出错的地方是端口名不匹配。get_ports里的名字必须跟顶层模块的端口名一致少一个字母都会导致错误。其次是通配符的误用比如get_ports led[*]这种写法有时能对有时会失效建议尽量把每根引脚写清楚。还有一个经典问题是把 FPGA 厂商内部信号当成普通端口约束了比如不同 bank 的时钟输入引脚的专用资源标记CLOCK_DEDICATED_ROUTE如果你手写 XDC 去约束不存在的端口布局时就会报错。5.4 时钟约束create_clock 与“跑起来的时序”时钟约束是 XDC 里比较关键的部分用create_clock定义时钟源。比如开发板用的是 100MHz 晶振引脚接到了 FPGA 的 E3那么至少要有create_clock -period 10.000 -name sys_clk [get_ports clk]period 是纳秒单位100MHz 对应 10ns。写完这条约束之后综合工具就会以 100MHz 为目标做时序收敛。如果你设计里用了 PLL 产生内部时钟工具会通过内部时钟资源自动推导新时钟约束不需要你再手动 create但最好检查一下报告。很多朋友在生成比特流失败后看日志看到Timing constraint not met一脸茫然。其实原因就是写了 create_clock但实际逻辑延迟太大布线后的路径达不到 100MHz。这时要么降低时钟频率约束要么优化 RTL 代码。这是工程创建时就要建立起来的意识XDC 不仅是一个“引脚映射表”它还是你与 Vivado 沟通性能目标的合同。6. 综合、实现、生成比特流第一次跑通完整流程这一步是整个 FPGA 工程创建流程的高潮但我先给你打个预防针第一次跑通很少是一遍过的。碰到报错不要慌按报告逐层查。6.1 三步流程分别做了什么Flow Navigator 中依次有三个按钮Run Synthesis、Run Implementation、Generate Bitstream。直接点最后一个按钮工具会自动帮你跑前两步。但我建议初学者分步跑因为你需要在每步之后翻阅报告。综合负责把 Verilog 转换成器件原语网表。如果你用了不支持的语法到这里就会报错。综合完成后可以打开Synthesis Report看看资源利用率、预估功耗、扇出最高的信号。重点看 Utilization 里有没有变成 999%、LUT 数量超不超。如果是这样不是你工程创建错了就是设计规模评估失误或者综合策略太激进。实现负责布局布线把网表放到 FPGA 物理结构上并满足时序约束。这一步通常最耗时。实现完成后打开Implementation Report里面不仅有资源利用率还有详细的时序路径表格。如果出现Slack为负数说明时序违例。这时你先不要急着调整 XDC而是去查看是哪条路径超了是组合逻辑链太长还是跨时钟域没处理好。6.2 生成比特流失败的最常见原因与排查顺序“生成比特流失败”这几乎是每个 FPGA 新手都遇到过的问题。我遇到过的原因按出现频率排序是这样的实现后时序尚未收敛但工具默认把比特流生成和时序检查挂钩失败就会停在write_bitstream步骤。解决方法是先回到 Implementation重新看时序报告必要时在Settings Implementation Bitstream里关闭-no_timing_driven我一般不建议改这个选项硬生成一个不收敛的比特流硬件跑起来就是半随机。引脚冲突或未分配引脚。设计里有 IO 信号没有在 XDC 中约束实现会报unplaced pins错误。排查方法是在I/O Planning界面里看所有端口是否都有绿色引脚标记。器件资源不足。BRAM、DSP、LUT 超了实现阶段会在映射时报错这种只能精简设计或者换更大器件。工程路径或文件路径存在中文空格导致某个中间文件生成失败。这属于上一节说的工程规范问题重新换个纯英文目录基本就解决。查看报错时我习惯先看 Messages 窗口的红色ERROR再点开 Details 跳到具体源码行。很多看起来骇人的大段日志其实关键信息只有一行。别去瞎搜“vivado生成比特流失败”先学会自己定位报告的summary部分比急着复制错误码更有用。6.3 连接开发板并下载到 FPGA比特流生成成功后会生成后缀为.bit的文件。接下来点击 Flow Navigator 下面的Open Hardware Manager点击Open target选择你的 JTAG 连接方式。自动化一般会检测到开发板上的 FPGA 芯片然后Program Device选择你刚生成的比特流文件。下载成功后板子上的 LED 或数码管就能看到效果了。如果下载不成功先检查 JTAG 驱动是否安装开发板电源是否打开或者换根 USB 线试一下。这些步骤听起来琐碎但调试过程中我最常遇到的下载失败基本都和安全连接有关。7. 仿真不止 Run Simulation行为、综合后与实现后的三层递进在工程创建完成之后仿真其实是验证环节。但 Vivado 的仿真功能和其他工具有不少差别值得单独说清楚。7.1 添加 Testbench 并启动 xsim在 Sources 面板的 Simulation Sources 里右键点Add sources把带有tb_前缀的 Verilog 文件加进来。然后选中仿真顶层右键点Run Simulation Run Behavioral SimulationVivado 会启动 xsim 仿真器并打开波形窗口。注意第一次打开仿真可能速度会很慢因为工具会做一遍预处理。启动后如果看不到波形检查测试里是否给时钟加了forever #5 clk ~clk;给复位信号加了足够宽的脉冲模块的实例名是否和 tb 中的线程一致。7.2 设置仿真时间与波形观察默认仿真时间是 1000ns如果你的 testbench 逻辑比较长可能只跑了一小部分。在波形窗口的Simulation菜单里点Run for...输入2000 ns之类的时长或者用Restart重新开始然后再跑。观察波形时可以点击信号右键Radix切换为十六进制或二进制显示这样比一堆电平高低直观很多。如果你仿真一个 UART 接收 RX 模块txd波形里的串行字节流需要配合radix才能看清。7.3 行为仿真和时序仿真的区别在哪Vivado 提供三种仿真层级Behavioral行为仿真、Post-Synthesis综合后仿真、Post-Implementation实现后仿真。行为仿真只验证逻辑功能延时不真实综合后和实现后仿真会加入门级延迟和布线延迟更接近真实硬件。它们的作用场景不同刚写完逻辑快速跑行为仿真找功能 bug综合实现后再跑一次后仿真看看有没有因为时序导致的问题。对于学习型工程行为仿真已经覆盖大部分问题后仿真耗时较长等你有心排查顽疾时再用。7.4 顺手说说 Icarus 与 Vivado 之间的工程差异不少人的入门工具是 Icarus Verilog GTKWave它启动快适合单文件小模块。但 Vivado 的 xsim 在 IP 核支持和后仿真方面更全它能自动处理 VHDL/Verilog 混合仿真也能直接例化工程里的 IP。所以从 Icarus 转过来的人不需要每次都新建独立测试工程直接在同一个 Vivado 工程里挂 testbench 即可。唯一的适应成本是 Vivado 的仿真工程本身也是工程的一部分文件位置和编译顺序都跟着工程走不能像 Icarus 那样一句命令行就全部搞定。8. 工程组织中的好习惯清理重跑、版本管理和脚本化前面七节把“新建工程—加代码—写约束—仿真—下载”这条主线讲完了。最后一节想聊一些容易被忽略、但真正决定长期效率的工程习惯。8.1 哪些目录可以删哪些不能删Vivado 工程目录里常有一堆.cache、.hw、.runs、.gen之类的自动生成目录。这些文件占地方且经常在版本管理里弄脏提交记录很多人会问“工程怎么清理”。我通常只删.cache和.runs下生成的临时缓存但不会删.xpr文件本身也不会随便删src、constrs、sim这三个自有目录。如果你要彻底清空中间结果重跑最保险的方法是关闭 Vivado手动删除工程目录中除了.xpr、src、constrs、sim、ip之外的文件夹再重新打开工程让工具重新综合实现。也可以使用菜单里的Project Clean但这仅清理运行产物。这种操作在修改顶层端口名、换芯片型号时需要用到。8.2 用 Git 管源码不管理生成物FPGA 工程不像纯软件工程runs目录动辄几百 MB没有必要整体纳入 Git 管理。我的经验是保留.xpr、src/、constrs/、sim/、ip/和*.tcl脚本文件忽略*.runs、*.cache、*.hw、*.gen、*.jou、*.log这些自动生成文件。这样你和同事或未来的自己共享时克隆下来后打开源码工程重新综合时间和磁盘都会很省。.gitignore的另一个好处是避免大量冲突合并每个工程刷新的中间文件各不相关没有版本控制价值。8.3 Tcl 一键创建工程把整个流程脚本化当你想再创建一个结构相同的工程时完全可以不点 GUI。Vivado 在 Tcl Console 里支持create_project、add_files、add_files -fileset constrs等命令。还可以通过write_project_tcl把当前工程导出成一个 Tcl 脚本以后再重建时source ./project.tcl就能恢复工程结构。举个例子一个极简脚本create_project project_led ./project_led -part xc7a35tcpg236-1 add_files -norecurse ./rtl/led_top.v add_files -fileset constrs_1 -norecurse ./constrs/pin.xdc set_property top led_top [current_fileset] update_compile_order -fileset sources_1这样创建工程就不再依赖鼠标也能在批量化、多版本复现时保持一致性。我觉得这是每个 FPGA 开发者迟早会主动拥抱的工作方式但前提是把 GUI 流程跑熟。8.4 沉淀一套自己的模板工程最后分享一个经验当工程创建流程稳定下来后可以做一个自己的“空模板工程”里面包含基本的时钟约束、LED/按键/开关的 XDC 引脚约束、一个能跑通的 top 模块和最小 testbench。以后任何新板子的功能验证直接拷贝这个模板工程再按需改引脚和顶层内容就行。很多 FPGA 工程师都会维护这么一套模板而不是每次从 Create Project 开始一步步点因为新建工程向导再熟练也要几分钟还容易在选择器件或路径时出错。工程创建这件事乍看只是一个“向导”实际上它是你从纯语法学习进入硬件设计工作流的第一个分水岭。工具链的规范程度、约束文件的意识、目录与版本管理的良好习惯都会从这里开始影响你后面的每一个项目。这篇笔记没有讲什么高级算法就是把我自己在经历过若干次工程崩溃、报错和重删重建设后总结出的一些硬经验写下来。希望你在第一次尝试“基于 Vivado 的 FPGA 工程创建”时能比我当年少几次折腾。
阅读完成 · 觉得有帮助?
咨询建站