vivado
阅读信息
约 3314 个字 11 分钟 本页总访问量:加载中... 次
注意
本文由AI生成。
未完待续。
编译流程
网表是什么?
网表(netlist)是一种描述电路结构的文件或数据,它记录了电路中有哪些逻辑单元(门电路、寄存器、加法器、乘法器、存储块等)以及这些单元之间的连接关系。可以理解为电路的“清单”和“连接图”。
综合(synthesis)完成后,源代码就被转换成网表,这时候电路已经从抽象的 Verilog/VHDL 变成了门级描述,但还没有对应到芯片上具体的物理位置。
比如:
- 元件部分:列出电路中所有用到的逻辑块。
- 网络部分:说明哪些逻辑块的输出连到哪些输入。
它的作用是作为综合和实现之间的桥梁,让实现阶段(implementation)能根据这个电路结构去做布局和布线。
Synthesis 是什么?
Synthesis(综合) 是 FPGA/ASIC 设计流程中的一个关键步骤。它的作用是把你写的 硬件描述语言(HDL,比如 Verilog/VHDL)代码 转换成一个 逻辑电路网表(netlist)。
通俗地说,就是把“抽象的代码”翻译成“由门电路、触发器、算术单元组成的硬件结构”。
主要过程包括:
- 解析 HDL 代码:检查语法和语义。
- 逻辑推导与优化:把高级的行为描述(如
if-else
,算术运算)转换为基本的逻辑单元,同时尝试优化,减少面积或提高速度。 - 映射到器件库:根据目标 FPGA 芯片的资源,把逻辑功能实现成该芯片能提供的基本单元,比如 LUT(查找表)、FF(触发器)、DSP 块、RAM 块等。
- 生成网表:输出一个门级电路清单,供后续 implementation(实现:布局布线) 使用。
举个例子,你写了 Verilog:
Verilog | |
---|---|
综合之后,工具会把它变成:
- 两个 AND 门
- 一个 OR 门
- 以及这些门之间的连线关系
也就是我之前给你演示的网表。
一句话总结:Synthesis 就是把 HDL 源代码转换成逻辑电路(网表)的过程,是从“代码”到“电路”的桥梁。
Implementation 是什么?
Implementation(实现) 是 FPGA 设计流程中继 Synthesis(综合) 之后的一步。
综合完成后,你得到的只是一个逻辑电路的网表(知道有哪些门电路、寄存器,以及它们之间怎么连接),但这个电路还没有放到 FPGA 芯片的实际资源上。Implementation 的任务就是把这些逻辑真正“安置”到芯片内部。
主要步骤包括:
- Opt Design(优化设计):对综合出来的网表再做一些逻辑优化。
- Placement(布局):决定每个逻辑单元放到 FPGA 芯片上的哪个具体位置(比如哪一个 LUT、哪一个寄存器)。
- Routing(布线):为单元之间的连接分配芯片内部的连线路径。
- 时序检查:确认电路能满足你的时钟频率要求,不会因为布线延迟过大而出错。
完成 Implementation 之后,你就得到一个完整的、和芯片资源绑定的电路设计结果,这时才能进一步生成 Bitstream(比特流文件 .bit),烧录到 FPGA 里运行。
可以这么理解:
- Synthesis → 把 HDL 代码翻译成“电路图”
- Implementation → 把“电路图”放到“芯片”上,并连好线
- Bitstream → 把结果转成机器能直接加载的配置文件
Bitstream 是什么?
Bitstream(比特流文件,通常是 .bit
或 .bin
) 是 FPGA 开发流程的最后产物。
它的本质是:一串二进制数据,里面记录了 FPGA 芯片中每个可编程资源(查找表 LUT、触发器 FF、布线开关、I/O 配置等)的具体配置状态。
FPGA 是一种 可重构硬件,出厂时内部都是“空白的开关矩阵”。只有把 bitstream 下载进去,它才知道:
- 哪些 LUT 实现什么逻辑函数
- 哪些寄存器存放数据
- 哪些线要连通
- 哪些引脚作为输入/输出,以及电平标准
整个设计经过 Synthesis(综合)→ Implementation(实现) 后,Vivado 就会根据布局布线的结果生成这个 bitstream 文件。然后你通过下载线(如 JTAG、USB)把 bitstream 烧录到 FPGA 上,芯片就能按你设计的电路来工作。
一句话总结:Bitstream 就是把你的 HDL 代码和电路设计“翻译”成 FPGA 能理解的二进制配置文件,是让芯片变成你电路的关键步骤。
IP 核封装
IP 核是什么?
IP 核(Intellectual Property Core,知识产权核)是一段经过封装、可以直接复用的硬件模块(逻辑电路设计),可以在不同项目中重复使用。
.xml 文件是什么?
在 Vivado 封装 IP 核的过程中,会生成一个 .xml
文件,这个文件的作用主要是描述和管理 IP 核的元信息。
.xml 文件记录这个 IP 的名称、版本号、参数、接口类型等信息,Vivado 可以根据这个文件知道如何识别和加载你的 IP。
如果你的 IP 核有可调参数(比如计数器宽度、时钟频率等),.xml
会保存这些参数的默认值和可选范围。
当你在 Vivado 的 IP Integrator 里拖拽 IP 时,软件读取 .xml
文件来显示 IP 的接口、端口和参数选项。
Example of .xml file
怎么生成网表文件?
Text Only | |
---|---|
write_verilog
:让 Vivado 导出 Verilog 格式的文件。-
-mode synth_stub
:表示导出的是 stub 文件(空端口文件)。 -
Stub 文件只有模块名和端口定义,没有具体实现逻辑。
-
主要用于在其他工程里调用这个 IP 时作为“占位符”。
-
E:/FPGA/ip/MUX2T1_5.v
:指定生成的文件路径和文件名。
这一句的效果:生成一个 空壳 Verilog 文件,里面只有 module MUX2T1_5(...)
的端口定义,供你在其他地方引用。
Text Only | |
---|---|
write_edif
:让 Vivado 把设计导出为 EDIF(Electronic Design Interchange Format) 文件。E:/FPGA/ip/MUX2T1_5.edf
:指定生成的文件路径和名字。
这一句的效果:生成一个 EDIF 格式的网表文件,里面是逻辑电路结构(门级连接),供后续工具或者其他项目使用。
所以总结一下:
- 第一条命令导出 空壳 Verilog 接口文件,只保留端口定义。
- 第二条命令导出 网表文件(.edf),保留逻辑实现。
这两步经常配合用:上层工程用 stub 文件识别端口,真正的功能由 EDIF 网表来实现。
调用 IP 核原理
你问的这个问题,其实就是 Vivado 调用 IP 核(Intellectual Property Core) 的内部原理,我帮你详细拆开讲一讲:
1. IP 核本质
在 Vivado 里,一个 IP 核其实就是一个“已经实现好的模块封装”,里面可能是:
- 源代码(Verilog/VHDL),或者
- 网表文件(EDIF .edf / DCP .dcp),甚至
- 加密后的黑盒逻辑。
它对外只暴露接口(端口),对内隐藏了具体实现。这样你在工程中使用时,就像调用普通模块一样。
2. 文件组成
当你创建/生成一个 IP 核时,Vivado 会生成一堆文件:
.xml
文件:描述这个 IP 的参数、接口特征等(元数据)。.tcl
脚本:配合 Vivado 的 XGUI 界面使用,根据用户在 GUI 中的参数配置动态生成或更新 IP。.edf
/.dcp
文件:设计的网表或已实现的设计快照,是真正的逻辑实现。- stub 文件(.v 或 .vhdl):只有端口声明的“空模块”,让综合器知道接口定义。
3. 调用流程
当你在 Vivado 工程里“调用”一个 IP 核时,内部会发生这些事情:
-
解析 XML 描述 Vivado 会读取
.xml
文件,知道这个 IP 有哪些参数(比如位宽、复位信号极性)、有哪些输入输出端口。 -
执行 Tcl 脚本 Tcl 脚本会根据用户的配置(你在 GUI 或 Tcl Console 里选择的参数),自动生成相应的工程文件,比如:
-
生成/复制 stub 文件(空接口)
- 复制
.edf
或.dcp
文件到工程目录下 -
更新工程的
.xci
或.xco
文件(IP 配置文件) -
引入网表 在综合和实现阶段,Vivado 会自动把对应的
.edf
或.dcp
加载进来,作为逻辑实现。因为 stub 文件只有端口,真正的逻辑是从网表来的。 -
实例化使用 在你的 HDL 代码里,只需要
U1: ip_core (...)
这样的实例化调用。综合器会发现这是个 stub,然后在 Implementation 阶段用对应的网表替换进去。
4. 一个类比
可以把 IP 核想成:
- stub 文件 → 产品说明书(告诉你接口长什么样)
- .xml + Tcl → 装配指南(告诉 Vivado 怎么把这东西装进工程)
- .edf/.dcp → 真正的零件(逻辑实现)
当你“调用”一个 IP 时,Vivado 并不是重新生成逻辑,而是 根据 xml 特征 + Tcl 脚本,把现成的网表复制到你的工程里,并让综合/实现阶段识别并链接。
5. 总结
调用 IP 核的原理就是:
- GUI 参数配置 → Tcl 脚本解析 → 根据 xml 描述生成接口文件(stub)
- 同时把网表(edf/dcp)加入工程
- 综合阶段看见 stub,知道这是个黑盒
- 实现阶段用网表替换黑盒 → 完整逻辑嵌入工程
I/O Buffer是什么?
在 FPGA 设计中,I/O Buffer(输入输出缓冲器)是一种特殊的硬件单元,用于连接 FPGA 内部逻辑与外部引脚,确保信号可以安全、可靠地进出芯片。
IBUF(输入缓冲器)把外部信号传入 FPGA 内部逻辑,提供电平匹配、噪声滤波和逻辑信号稳定性。OBUF(输出缓冲器)把 FPGA 内部逻辑信号驱动到外部引脚,提供足够的驱动能力,保证信号可以传输到外部电路。IOBUF(双向缓冲器)用于既能输入又能输出的引脚,内部逻辑通过控制信号决定当前是输入模式还是输出模式。
I/O Buffer 的作用是:匹配 FPGA 内部逻辑电平与外部接口电平,保证信号能安全传输;提供足够的驱动能力,应对外部负载和线路特性;防止 FPGA 内部信号直接暴露给外部电路,从而保护芯片。
举例来说,如果有一个 FPGA 输入引脚 A 和输出引脚 Y,输入时信号先经过 IBUF 进入内部逻辑,输出时内部逻辑信号先经过 OBUF 再驱动外部引脚。如果是双向引脚,可以用 IOBUF 控制方向。
在 Vivado 中,默认情况下,综合顶层模块时会自动在顶层 I/O 上插入 I/O Buffer。如果选择 out_of_context 综合,模块内部不会插入 I/O Buffer,因为顶层 I/O 由调用工程统一管理。
一句话总结:I/O Buffer 是 FPGA 内部逻辑和外部引脚之间的桥梁,确保信号可靠、安全地传入或传出芯片。
out-of-context是什么?
在 Vivado 中,当你对某个模块进行综合时,可以设置一个选项叫 out_of_context
,意思是让这个模块 独立于顶层工程进行综合。
通常,综合会考虑模块的整个上下文,包括顶层模块的输入输出和连接情况,同时会自动在顶层 I/O 引脚处插入 I/O 缓冲器(如 IBUF
、OBUF
或 IOBUF
),确保信号能正确驱动 FPGA 外部接口。但是有些情况下,你只想对某个子模块本身进行逻辑综合,不想把它的顶层 I/O 包含进来,这时就可以使用 out_of_context
。
使用 out_of_context
有几个效果:
-
不生成顶层 I/O 缓冲器
-
模块内部逻辑会被综合成门级网表,但顶层输入输出不会自动加上 I/O buffer。
-
这样生成的网表只包含内部逻辑,外部接口留空或当作黑盒处理。
-
加快综合速度
-
因为不需要处理顶层连接和 I/O 分配,Vivado 只关注模块内部逻辑。
-
对大型工程或 IP 封装尤其有用,可以独立生成网表。
-
方便模块复用
-
模块可以作为独立的逻辑块导出(比如
.edf
或.dcp
文件),供其他工程或顶层模块引用。 - 你在顶层工程中再实例化时,顶层 I/O 会根据实际需要加上缓冲器。
导出网表文件时设置OOC,不插入任何I/O Buffer:
启用 out_of_context
后,Vivado 把这个模块当作 独立的子工程或黑盒 来综合,只生成模块内部逻辑,不管它外面怎么连接,也不生成任何 I/O buffer。这样可以方便 IP 核封装、模块复用和分块综合。
在导出网表文件时设置 OOC(out_of_context),让模块不加入任何 I/O Buffer,是因为此时你只想生成模块内部的逻辑网表,而不关心它在顶层工程的引脚连接。
OOC 模式下,Vivado 会把模块当作一个独立子模块或黑盒来综合,只关注模块内部的逻辑功能,不生成顶层 I/O 相关的缓冲器。这样做有几个好处:
- 可以独立综合模块,提高综合速度,不受顶层引脚约束影响。
- 生成的网表更通用,便于在其他工程中复用,顶层 I/O 由调用工程统一处理。
- 避免在生成的网表里固定 I/O 连接,保留接口灵活性,使模块更像一个可重用的 IP 核。
简单来说,设置 OOC 并不加 I/O Buffer,是为了让导出的网表只包含内部逻辑,而顶层 I/O 由最终工程来决定,保证复用性和灵活性。
网表示例
好的,我用一个最简单的电路:
1
也就是有两个与门,结果再进一个或门。
如果写成 Verilog,大概是这样:
综合之后,工具会生成一个网表(netlist)。 网表格式有很多种(EDIF、Verilog netlist 等),这里我给你展示一个简单的、接近“清单+连线”的描述:
解释一下:
U1, U2, U3
是实例化的门电路。AND2
、OR2
表示两输入的与门、或门。n1
和n2
是综合过程中生成的中间网络。