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
);
相关推荐
小二·2 小时前
前端笔记:HTML output标签介绍及用法
javascript·笔记·html5
杰尼君3 小时前
STM32CubeMX笔记(11)-- AD模块使用
笔记·stm32·嵌入式硬件
_JinHao3 小时前
Cesium Viewer对象详解——Cesium基础笔记(快速入门)
前端·javascript·笔记·3d·webgl
xxy.c8 小时前
基于IMX6ULL的时钟,定时器(EPIT,GPT)
单片机·嵌入式硬件·fpga开发
sz-lcw9 小时前
MySQL知识笔记
笔记·mysql·adb
古译汉书9 小时前
嵌入式铁头山羊STM32-各章节详细笔记-查阅传送门
数据结构·笔记·stm32·单片机·嵌入式硬件·个人开发
2301_8000509912 小时前
DNS 服务器
linux·运维·笔记
汇能感知12 小时前
光谱相机的未来趋势
经验分享·笔记·科技
风已经起了15 小时前
FPGA学习笔记——图像处理之对比度调节(直方图均衡化)
图像处理·笔记·学习·fpga开发·fpga