FPGA自学笔记--VIVADO FIFO IP核控制和使用

本文主要学习在VIVADO软件中如何生成所需要的FIFO IP核,以及相关的配置定义,并搭建tb对生成的IP读写控制时序进行仿真和测试。主要学习小梅哥的笔记整理而成。

FIFO(First In First Out,先进先出)是一种具有先进先出特性的缓冲存储结构,在 FPGA 或 ASIC 设计中常用于数据缓存和高速异步数据交互。与普通存储器相比,FIFO 没有外部读写地址线,读写操作依赖内部读写指针自动递增,简化了使用,但只能顺序写入和顺序读出,无法像普通存储器那样通过地址线随机访问指定位置。

本文重点介绍 FIFO 的基本原理,并以双时钟 FIFO 为例,说明 FIFO IP 的生成流程及其基本使用方法。

一、FIFO结构与应用场景

从读写时钟角度来看,FIFO 可分为两种结构:单时钟 FIFO(同步 FIFO)和双时钟 FIFO(异步 FIFO)。

  • 单时钟 FIFO:读写共用同一个时钟,所有输入信号的采样与输出信号的更新都在该时钟的上升沿完成,因此所有输入输出操作都与这一时钟保持同步。

  • 双时钟 FIFO :读端和写端各自使用独立的时钟,写相关信号仅与写时钟 wr_clk 同步,读相关信号则仅与读时钟 rd_clk 同步,实现跨时钟域的数据传输。

单时钟 FIFO 常用于片内同步数据的传输与缓存。

例如,FPGA 在控制外部传感器时,可以先以 2 MHz 的 SPI 速率快速读取 20 个数据,再通过 UART 以 9600 bps 的波特率依次发送。由于传感器读取速度远高于串口发送速度,需先将数据写入 FIFO 进行缓存,然后按串口速率慢速输出。读取与发送均可依赖同一时钟,因此适合采用单时钟结构的 FIFO。

双时钟 FIFO 则用于不同步时钟域之间的数据交换。

典型场景是高速采集系统:高速 ADC 以外部锁相环产生的 CLK1 采样,而 FPGA 内部运行在独立的 CLK2(如 125 MHz)。两者频率和相位互不关联,无法直接用 125 MHz 时钟采集 65 MHz 的数据,否则会产生速率不匹配及亚稳态等问题。借助双时钟 FIFO,可在写端同步于 CLK1、读端同步于 CLK2,实现跨时钟域的安全数据传输。

二、FIFO的常见参数和实现方式

FIFO 的常见关键参数包括:

  • 宽度:一次读写操作的数据位数。

  • 深度:可存储的 N 位数据的数量(若宽度为 N)。

  • 满标志:当 FIFO 已满或接近满时输出,用于禁止继续写入以避免溢出。

  • 空标志:当 FIFO 已空或接近空时输出,用于禁止继续读取以防读到无效数据。

  • 读时钟:控制读操作的时钟信号,每个有效沿触发一次读取。

  • 写时钟:控制写操作的时钟信号,每个有效沿触发一次写入。

实现 FIFO 的主要方式有三种:

  1. 自行编写逻辑:用户根据实际需求手动设计 FIFO 电路,适用于功能要求较特殊的场合。

  2. 采用第三方开源 IP 核:直接使用源码形式的开源 FIFO,实现速度快,并可在源码基础上做定制修改,以满足个性化需求。

  3. 使用 Xilinx Vivado 自带的免费 FIFO IP:Vivado 提供可视化配置界面,可轻松设置参数和结构,并针对不同系列器件做优化,功能齐全且稳定,系统设计中通常优先推荐这种方式。

三、FIFO IP配置流程

在IP库中找到FIFO

IP Location 设置中,可以更改生成的 IP 存放路径。此处保持默认路径,仅将 IP 名称修改为 fifo

在 IP 配置界面中,将接口类型设为 Native 。根据所用资源和读写时钟是否一致,FIFO 类型有多种可选。此示例中创建的是读写时钟独立 且使用嵌入式 Block RAM 资源的 FIFO,因此选择 Independent Clocks Block RAM

将读写数据位宽都设置为 8 bit (实际应用中读写位宽可不同),数据深度配置为 256 words 。需要注意的是,虽然界面上设置为 256,但生成的 FIFO 实际有效深度只有 255。最终以工具显示的实际深度为准,这与 FIFO IP 的内部实现有关,无需深入探究,使用时留意即可。

Read Mode 设置中有两种可选模式:

  • Standard FIFO:只有在读使能信号有效后,数据才会输出。

  • First Word Fall Through (FWFT) :当前数据会提前出现在数据线上,读使能到来时,下一个数据立即送出。本例选择 Standard FIFO 模式。


在 Output Register 勾选并选择 Embedded Register,也可以选择 Fabric Register ,或者两个寄存器都选加上,多加一个输出 寄存器,输出就会多延迟一个时钟周期出来。

此处可保持默认选项,勾选 复位管脚复位同步 以及 Enable Safety Circuit

  • 复位:重置数据输出和内部读写指针计数,复位后读写指针清零。

  • 复位同步:将异步复位信号分别在读时钟域和写时钟域内先做同步,再执行各自的复位操作。

  • Safety Circuit :通过额外逻辑提高复位可靠性。启用后会多出 wr_rst_busyrd_rst_busy 两个信号,分别表示写/读时钟域处于复位忙状态。

使用时需注意:

  • 只有当 wr_rst_busy 由 1 变为 0 后,且 FIFO 未满,才能开始写操作;wr_rst_busy 为 1 时禁止写入。

  • 只有当 rd_rst_busy 由 1 变为 0 后才能开始读操作;rd_rst_busy 为 1 时禁止读取。

状态输出信号可按实际需求选择。为了便于实验观察波形,此处将空、将满以及读写端握手相关信号全部勾选。勾选后,FIFO 的输出端口会增加以下常见信号:

  • wr_ack:写入响应,当数据成功写入 FIFO 时输出高电平,表示写操作已完成。

  • overflow:上溢出标志,当 FIFO 已满仍继续写入时,该信号拉高提示溢出。

  • valid:读数据有效指示,在读操作时伴随数据输出拉高,高电平表示输出数据有效,可据此触发后续处理。

  • underflow:下溢出标志,当 FIFO 已空仍继续读出时,该信号拉高提示下溢。

空满信号的触发阈值可通过 Programmable Full TypeProgrammable Empty Type 设置。默认配置为 No Programmable Full ThresholdNo Programmable Empty Threshold,对应默认阈值依次为 253、252、2、3。

其逻辑可简单理解为:

  • Full 信号:当 FIFO 内数据量 ≥ 253 时置 1;在 full 为 1 的情况下,如果数据量降至 ≤ 252,full 信号恢复为 0。

  • Empty 信号:当 FIFO 内数据量从 0 增加到 ≥ 3 时,empty 信号变为 0;在 empty 为 0 的情况下,如果数据量降至 ≤ 2,empty 信号恢复为 1。

由此可见,full 和 empty 信号并非在 FIFO 完全写满或完全读空时才改变状态,而是预留了一定余量以提高系统稳定性。

以上默认设置是可修改的,通过 Programmable Full TypeProgrammable Empty Type 可以选择不同模式进行配置。以 Programmable Full Type 为例:

  • Single Programmable Full Threshold Constant :仅可设置 Assert ValueNegate Value 保持默认不可改。

  • Multiple Programmable Full Threshold ConstantAssert ValueNegate Value 均可自定义设置。

  • Single Programmable Full Threshold Input PortAssert Value 可通过输入端口动态设置,Negate Value 保持默认不可改,此时 FIFO 会多出一个输入端口 prog_full_thresh 用于输入阈值。

FIFO 提供数据量计数信号输出:

  • Write Data Count:同步于写时钟,表示 FIFO 内当前已写入的数据数量。

  • Read Data Count:同步于读时钟,表示 FIFO 内当前可读的数据数量。

计数信号的位宽可根据实际需求设置,此处保持默认 8 位

完成上述设置后,可在 Summary 栏查看配置总结,内容包括存储器类型、数据位宽 8 bit 、实际深度 255 以及已选择的状态信号等信息。

点击OK,再点击generate,生成IP ing。

四、FIFO IP 例化

在生成的IP source中,有IP的例化模板。

复制代码
fifo your_instance_name (
  .rst(rst),                      // input wire rst
  .wr_clk(wr_clk),                // input wire wr_clk
  .rd_clk(rd_clk),                // input wire rd_clk
  .din(din),                      // input wire [7 : 0] din
  .wr_en(wr_en),                  // input wire wr_en
  .rd_en(rd_en),                  // input wire rd_en
  .dout(dout),                    // output wire [7 : 0] dout
  .full(full),                    // output wire full
  .almost_full(almost_full),      // output wire almost_full
  .wr_ack(wr_ack),                // output wire wr_ack
  .overflow(overflow),            // output wire overflow
  .empty(empty),                  // output wire empty
  .valid(valid),                  // output wire valid
  .underflow(underflow),          // output wire underflow
  .rd_data_count(rd_data_count),  // output wire [7 : 0] rd_data_count
  .wr_data_count(wr_data_count),  // output wire [7 : 0] wr_data_count
  .wr_rst_busy(wr_rst_busy),      // output wire wr_rst_busy
  .rd_rst_busy(rd_rst_busy)      // output wire rd_rst_busy
);
相关推荐
丝斯20111 天前
AI学习笔记整理(42)——NLP之大规模预训练模型Transformer
人工智能·笔记·学习
凉、介1 天前
深入 QEMU Guest Agent:虚拟机内外通信的隐形纽带
c语言·笔记·学习·嵌入式·虚拟化
njsgcs1 天前
SIMA2 论文阅读 Google 任务设定器、智能体、奖励模型
人工智能·笔记
3有青年1 天前
Altera FPGA操作系统支持的情况分析
fpga开发
云半S一1 天前
pytest的学习过程
经验分享·笔记·学习·pytest
AI视觉网奇1 天前
ue5.7 配置 audio2face
笔记·ue5
国科安芯1 天前
卫星通讯导航FPGA供电单元DCDC芯片ASP4644S2B可靠性分析
单片机·嵌入式硬件·fpga开发·架构·安全性测试
崎岖Qiu1 天前
【OS笔记35】:文件系统的使用、实现与管理
笔记·操作系统·存储管理·文件系统·os
曦月逸霜1 天前
离散数学-学习笔记(持续更新中~)
笔记·学习·离散数学
hunter14501 天前
windows server AD域与CA部署证书
笔记