FPGA — FIFO学习笔记

这篇具有很好参考价值的文章主要介绍了FPGA — FIFO学习笔记。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

使用软件: Vivado
参考文档:FIFO Generator v13.2

基础知识

FIFO(Fist In Fist Out),即为先进先出,常被用于数据的缓存或高速异步数据的交互,与普通存储器区别是没有外部读写地址线,使用简单,缺点是只能顺序写入数据,顺序的读出数据,其数据地址由内部读写指针自动加1完成,不能像普通存储器那样由地址线决定读取或写入某个指定的地址。

1. FIFO 结构

FIFO从读写时钟上看,分为两类:
(1)单时钟FIFO(同步FIFO)
	读写共用一个时钟,即所有输入输出信号的变化都是由一个时钟信号控制。
(2)双时钟FIFO(异步FIFO)
	读写各由一个时钟信号控制,写时钟:wr_clk,读时钟:rd_clk。

双时钟FIFO的整体框图和内部结构如下所示:
fifio学习,FPGA,fpga开发,学习
fifio学习,FPGA,fpga开发,学习

2. 应用场景

场景一

需求:
FPGA内部有个16位计数器,以50MHz频率计数,此时,希望随机截取计数器连续256个计数周期的值发到电脑上进行分析处理。
用串口发送到电脑上。(数据产生速率大于数据消费速率)
解决:
需要用存储器先将256个数据存储起来,再由串口慢慢发送到电脑。
对于FIFO来说,写入的数据是16位,读出的数据可能是16位或者8位

场景二

需求:
任意脉冲信号发生器:由电脑通过串口发送256个14位(16)的数据到FPGA,FPGA再把这256个数据,以50MHz的输出速率送给DAC,产生脉冲信号
问题:数据的产生速率小于数据消费速率
解决:
电脑发送速率最大为115200,小于FPGA发送的速率,需要FPGA将256个数据完全接收到并存储后,再一次性送给DAC输出
对于FIFO来说,写入的数据可能是16位(UART收到2个8位数据后,拼接起来一起写入)或者8位,读出的数据是16位

3. FIFO 常见参数

 FIFO 的宽度:即 FIFO一次读写操作的数据位;
 FIFO 的深度:指的是 FIFO可以存储多少个 N 位的数据(如果宽度为 N)。
 满标志:FIFO已满或将要满时由 FIFO的状态电路送出的一个信号,以阻止FIFO的写操作继续向FIFO 中写数据而造成溢出。
 空标志:FIFO 已空或将要空时由 FIFO 的状态电路送出的一个信号,以阻止FIFO的读操作继续从 FIFO 中读出数据而造成无效数据的读出。
 读时钟:读操作所遵循的时钟,在每个时钟沿来临时读数据。

FIFO IP核的使用及仿真

双时钟 FIFO IP的配置

在Vivado软件的左侧项目管理栏下找到[IP Catalog],鼠标单击,在右边搜索框输入fifo搜索,选择[Memories&Storage Elements]下的[FIFO Generator],双击进入FIFO设置界面。
fifio学习,FPGA,fpga开发,学习

在Basic栏下进行配置

修改IP名字,为fifo,如下图所示

  1. 接口类型分为3种,一般选择Native类型
    (1)Native:能够配置时钟域,用于写入和读取操作。
    (2)AXI Memory Mapped:AXI指定写入通道和读取通道。
    (3)AXI Stream:适合非基于地址的点对点应用,与使用此接口的其他IP进行连接。(如AXI4版本的DSP功能、FFT、DDS和FIR编译器等)
    具体介绍看官方文档:FIFO Generator v13.2
  2. 创建一个独立的读写时钟,使用嵌入式Block RAM资源的FIFO,选择Independent Clocks Block RAM
    fifio学习,FPGA,fpga开发,学习

对引脚进行配置

1. Read Mode选择Standard FIFO
对于Standard FIFO,在给了读数据使能后,数据才出来
对于First Word Fall Through,当前数据提前到了数据读数据线还是那个,在读使能到来后,下一个数据汇到数据线上,可以结合下面时序图来看:
Standard FIFO时序图:
fifio学习,FPGA,fpga开发,学习
First Word Fall Through时序图:
fifio学习,FPGA,fpga开发,学习

2. 读写数据位宽均设置为 8bits(实际根据需要可以设置读写数据位宽不一样),数据深度为 256words。
这里修改数据位宽及深度。需要注意的是设置数据后面有实际深度,这里虽然我们配置的是 256,但实际 FIFO 只有 255 的深度,这个是需要注意的,最终配置深度以后面实际深度为准,这个可能和 FIFO IP 内部设计有关,在仿真的时候可以看出来。
fifio学习,FPGA,fpga开发,学习
从下图中可以看到,在蓝线的位置,rd_clk为上升沿,检测到rd_en为1,隔了一个时钟周期,在黄线的位置,dout有了第一个有效输出值:01
fifio学习,FPGA,fpga开发,学习

3. 勾选[Output Register]
后面选择[Embedded Register]会使输出多一个寄存器,输出就会多延迟一个时钟周期出来,如果选择[Embedded Reg AND Fabric Reg]的话,输出会延迟2个时钟周期,从后面仿真图中可以看出。
fifio学习,FPGA,fpga开发,学习
4. 初始化设置

(1)这里可以保持默认的勾选复位管脚、复位同步和使能 Safety Circuit,这里的复位是对数据输出以及内部读写指针计数等进行复位,复位后,读写指针清零。
这里的复位同步功能是对异步输入的复位信号分别在读写时钟域内先进行同步后再进行读写的各自复位。
使用Safety Circuit 可以认为是一种更加可靠模式,内部通过额外的逻辑电路让 FIFO 复位的更加可靠,勾选 Enable Safety Circuit 后 fifo 模块的管脚会多出 wr_rst_busy 和 rd_rst_busy 两个信号输出,这两个信号分别表示的是写/读时钟域复位忙信号(为 1 表示忙,处于复位中,为0表示复位完),所以每次给一个异步复位信号对 FIFO 进行复位时,需要等到 wr_rst_busy 从1 变为 0 后才能对 FIFO 进行写数据操作(在 FIFO 非满情况下,这个是任何写操作时候都需要满足的),在 wr_rst_busy 为 1 时进行写是不允许的
同样的要等到 rd_rst_busy 从 1 变为 0 后才能对 FIFO 进行读操作,在rd_rst_busy 为 1 时进行读是不允许的,这些是我们在使用 IP 过程需要注意的地方,有关具体时序波形可以到看后面仿真。
(2)Full Flag Reset Value:设置在复位时,满信号处于什么值,这里保持默认的1,也就是复位时认为是满,禁止写入。
 Dout Reset Value:设置复位时,FIFO 输出处于什么值,保持默认。
 Read Latency:这里会根据前面设置自动更新,前面我们设置输出加上一个寄存器,这里就变为了 2,不加寄存器的情况下是 1,加两个寄存器就是 3。
fifio学习,FPGA,fpga开发,学习

Status Flags 状态标志设置

状态输出信号的设置,包括将空和将满信号,读写端口握手信号,这里根据实际情况进行选择,这里作为实验演示就都勾选上,便于后面看波形。这里读写端口握手信号都勾选上后,会看到 FIFO 输出管脚会多出一些信号。
fifio学习,FPGA,fpga开发,学习
 wr_ack:写操作响应信号,当向 FIFO 写入数据时,如果正确写入到 FIFO了,会输出高电平表示数据已成功写入。
 overflow:上溢出标识信号,表示 FIFO 数据满情况下继续往 FIFO 里写数据,该信号会拉高标志向上溢出。
 valid:读数据输出数据有效信号,在进行读操作时,valid 信号伴随数据输出而拉高,高电平表示输出数据有效,用户逻辑可以根据该信号对读出的数据做后续进一步的处理使用。
 underflow:下溢出标识信号,表示 FIFO 数据空情况下继续对 FIFO 进行读操作,该信号会拉高标志向下溢出。
空满信号产生的数据个数的阈值设置,Programmable Full Type 和 Programmable Empty Type有多种类型可以选择。默认是No Programmable Full Threshold和No Programmable Empty Threshold,默认情况下设置值依次为 253,252,2,3。

简单描述下就是当数据大于等于 253时,prog_full 信号置 1,在 prog_full 为 1 情况下,fifo 内数据量减小到 252 以下(包括 252)时,prog_full变为 0。

同理对与空信号,当 FIFO 内数据量从0增加到 3(或大于 3)时,prog_empty 信号变为0,在 prog_empty 为 0 的情况下,当 FIFO 数据量减少到 2(包括 2)时,prog_empty 变为高。

从这里可以看出,prog_full 信号并不是在 FIFO 完全写满才置 1,留有一定的余量,同样 prog_empty 也是一样,并非在 FIFO 完全读空才置 1。

fifio学习,FPGA,fpga开发,学习

Data Counts设置

FIFO 数据量计数信号输出,Write Data Count 和 Read Data Count 分别同步与写时钟和读时钟。位宽可以根据实际进行设置,这里保持默认位宽 8。
fifio学习,FPGA,fpga开发,学习

以上设置完后,可以在 Summary 一栏看到前面一些设置的总结,里面信息包括存储器类型,数据位宽 8bit,深度 255 以及一些状态信号的选择等信息。
fifio学习,FPGA,fpga开发,学习
点击界面左下角 OK,弹出界面 Generate,生成IP即可。

仿真验证

仿真代码:

`timescale 1ns / 1ps
//
// Create Date: 2022/10/26 20:42:41
// Design Name: 
// Module Name: sim_fifo_ip
// Revision 0.01 - File Created
// Additional Comments:
// 
//

/*
The computer sends data to FPGA at 20MHz and FPGA sends data to DAC at 50MHz    
*/
`define WR_CYCLE 40  //write cycle is 40 ns  = 25MHz
`define RD_CYCLE 20  //write cycle is 20 ns  =50MHz
module sim_fifo_ip();
reg wr_clk=0,rd_clk=0;
reg[9:0] cnt1=0;
reg[7:0] din=8'b00000000;
reg wr_en=0,rd_en=0,rst=1;
wire[7:0] dout,rd_data_count,wr_data_count;
wire full,almost_full,wr_ack,overflow,empty,almost_empty,valid,underflow,prog_full,prog_empty,wr_rst_busy,rd_rst_busy;
always #(`WR_CYCLE/2)  wr_clk=~wr_clk;
always #(`RD_CYCLE/2)  rd_clk=~rd_clk;

initial begin
#(`WR_CYCLE*8+1);
rst=0;
@(negedge wr_rst_busy);

//write data
while(full==0)
begin
    @(posedge wr_clk);
    #1;
    wr_en=1;
    din=din+1'b1;
end

//write a data again
//多写2个数据:
@(posedge wr_clk);
din=2;
@(posedge wr_clk);
@(posedge wr_clk);
din=3;
@(posedge wr_clk);
@(posedge wr_clk);
wr_en=0;
@(posedge rd_clk);
//enable read
wait(wr_rst_busy==1'b0);
#2000;
while(empty==0)
begin
    @(posedge rd_clk)
    begin
        #1;
        rd_en=1;
    end
end
//多读一个数据看看变化
@(posedge rd_clk);
rd_en=0;//读使能置零

//reset,观察复位时间
    #200;
    rst   = 1'b1;
    #(`WR_CYCLE*3+1);
    rst = 1'b0;
    @(negedge wr_rst_busy);
    wait(rd_rst_busy == 1'b0);
    #2000;
$stop;

end

fifo fifo_testbench(
  .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
  .almost_empty(almost_empty),    // output wire almost_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
  .prog_full(prog_full),          // output wire prog_full
  .prog_empty(prog_empty),        // output wire prog_empty
  .wr_rst_busy(wr_rst_busy),      // output wire wr_rst_busy
  .rd_rst_busy(rd_rst_busy)      // output wire rd_rst_busy
);
endmodule

为了测试仿真编写测试激励文件,添加并新建仿真文件命名为 sim_fifo_ip.v。
上面创建的FIFO 是独立时钟,首先分别产生写时钟信号 wr_clk 和读时钟信号 rd_clk,周期时间值通过宏定义 define 分别设置为 40ns 和 20ns。

fifio学习,FPGA,fpga开发,学习
仿真中首先是产生一段时间的复位信号(高电平复位),等到写复位忙信号 wr_rst_busy 从 1 变为 0(等待 wr_rst_busy 下降沿),说明写复位已经做完,

fifio学习,FPGA,fpga开发,学习
然后通过一个 while 循环在 FIFO 没有满的情况下,一直往 FIFO 里写入数据,数据值从 254 递减,为了让仿真波形更加贴合实际,写使能信号在时钟上升沿之后延时 1ns 给高电平,这样能更加清晰看到 FIFO 各信号之间的关系。在 FIFO 写满之后将写使能置 0,停止写入数据。

fifio学习,FPGA,fpga开发,学习
然后多写入两个数据,看看仿真结果。

读操作类似,前面进行过一次复位操作,所以先确保读复位忙信号rd_rst_busy 已经为 0,然后在 fifo 为非空的情况下进行读数据操作,直到 FIFO读空就停止进行读操作。然后多读一个数据,看看仿真情况。
之后又对复位进行一次测试,等复位完后延时一段时间就停止仿真。

仿真结果及分析

  1. 仿真一开始进行了一段时间的复位(rst 拉高大概 8 个写时钟周期),这个时候 FIFO 就进入到 FIFO 操作,之后 wr_rst_busy 和 rd_rst_busy 也先后被拉高,说明读写都进入到复位过程,复位期间 full 和 almost_full 信号会变为高电平。这里复位期间 full 为高为低是之前在IP 配置过程中进行设置的,默认是复位时 full 为高,因为复位情况下是不允许进行写操作的,full 为高可以避免写入数据,如果有特殊要求也可以将这里设置为 0.
    fifio学习,FPGA,fpga开发,学习

  2. 在蓝线处开始写入数据,但是在其下一个上升沿中wr_ack才变为1,表示写入成功,再下一个上升沿显示wr_data_count=1,表示写入数据的数量;
    fifio学习,FPGA,fpga开发,学习

  3. 写复位完成后,接下来是在非满情况下进行写数据操作,直到 FIFO 的 full 信号被拉高就停止写操作。多写一个‘2’,则overflow置1,表示溢出,此时数字‘2’不会被写入FIFO中。almost_full是提前一个计数值(253-1),出现高电平.
    fifio学习,FPGA,fpga开发,学习

  4. 从波形上可以看到,读出数据和对应的数据 valid 信号延迟读使能一个时钟周期出来。之所以延迟一个时钟周期出来,与前面 IP 配置选择增加一个输出寄存器是一致的。

  5. rd_data_count 信号的变化延迟读使能一个周期出现,该信号同步于读端口时钟(wr_data_count 信号是同步于写端口时钟)。
    fifio学习,FPGA,fpga开发,学习

  6. FIFO 空信号标识信号 empty 是在rd_data_count计数值为 2 的时候变为高电平,与前面 IP 配置是一致的。从波形上可以看到 almost_empty提前一个 wr_data_count 计数值变为高电平(这里 2+1=3)
    underflow 信号是 FIFO 读溢出标志信号,从读数据的波形看到 FIFO 读空后,未再进行读数据操作,没出现读溢出,所以 underflow 信号一直为低电平,如果此时再对 FIFO 进行一次读数据操作,underflow 信号就会变为高电平。
    fifio学习,FPGA,fpga开发,学习

  7. 在仿真最后又对 FIFO 进行了一次复位,等复位完成后过了 2000ns 就停止仿真。
    fifio学习,FPGA,fpga开发,学习文章来源地址https://www.toymoban.com/news/detail-595870.html

到了这里,关于FPGA — FIFO学习笔记的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • FPGA原理与结构(12)——FIFO IP核原理学习

    系列文章目录:FPGA原理与结构(0)——目录与传送门         FIFO是英文First-In-First-Out的缩写,是一种先入先出的数据缓冲器,与一般的存储器的区别在于没有地址线, 使用起来简单,缺点是只能顺序读写数据,其数据地址由内部读写指针自动加1完成,不能像普通存储器

    2024年02月08日
    浏览(36)
  • FPGA学习笔记-1 FPGA原理与开发流程

    注:笔记主要参考: B站 正点原子 教学视频“正点原子手把手教你学FPGA-基于达芬奇Pro开发板 Artix-7 XC7A35T/XC7A100T”。 小梅哥爱漂流 教学视频“【零基础轻松学习FPGA】小梅哥Xilinx FPGA基础入门到项目应用培训教程”。 B站搬运 “特权同学2020版《深入浅出玩转FPGA视频教程》

    2024年02月05日
    浏览(37)
  • FPGA之FIFO详解,初识FIFO

           在篇博客里引入FIFO IP核的概念,FIFO是FPGA中最常用的IP核,经常用在接口模块、串并转换、协议处理、数据缓存等很多场合,所以活学活用这个IP核对于后期项目开发很重要,并且灵活掌握FIFO,也是一名合格的FPGA工程师的一项基本功。        FIFO顾名思义就是First

    2024年01月20日
    浏览(36)
  • FPGA FIFO基本介绍(FIFO Geneerator(13.2))

    软件:vivado 2020.2  参考文献: 文档xilinx官网pg057-fifo-generator文档下载链接官网https://docs.xilinx.com/v/u/en-US/pg057-fifo-generatorhttps://docs.xilinx.com/v/u/en-US/pg057-fifo-generator https://docs.xilinx.com/v/u/en-US/pg057-fifo-generator 原官网免费文档已被上传为付费文档,笔者上传的免费文档未过审核。

    2024年01月25日
    浏览(33)
  • FPGA中FIFO的应用(二)——异步FIFO设计

    ⭐️作者简介: 小瑞同学 ,一个努力精进的 FPGA 和通信学习者。 🍎个人主页:小瑞同学的博客主页 🌻个人信条:越努力,越幸运! ⏰日期:2023.12.3 🔍来源:自学经历 📖文章内容概述:介绍了 异步FIFO 的基本工作原理和深度计算,通过仿真观察了其读写过程。 连载系列

    2024年02月03日
    浏览(31)
  • FPGA——FIFO

    FIFO FIFO(First In First Out,即先入先出),是一种数据缓冲器,用来实现数据先入先出的读写方式。FIFO 根据读写时钟是否相同,分为 SCFIFO(single-clock FIFO)和 DCFIFO(duabl-clock FIFO),SCFIFO 的读写为同一时钟,应用在同步时钟系统中;DCFIFO 的读写时钟不同,应用在异步时钟系统

    2024年02月05日
    浏览(27)
  • 【LabVIEW FPGA入门】FIFO

            要在 FPGA VI 的不同部分之间或 FPGA 目标中的 VI 之间传输缓冲数据,可使用 FIFO。FIFO 是一种先进先出的缓冲器,第一个写入内存的数据项就是第一个从内存中读取和删除的数据项,类似于队列。         FPGA FIFO 的功能类似于一个固定长度的队列,可将多个数据

    2024年03月27日
    浏览(36)
  • 【FPGA】UART串口通信---基于FIFO

    我们在上一章完成了UART串口通信的收发模块,这一章我们将FIFO引入进来,使用FIFO进行缓存数据,来连接串口通信的收发模块 FIFO即First In First Out,是一种先进先出数据存储、缓冲器,我们知道一般的存储器是用外部的读写地址来进行读写,而FIFO这种存储器的结构并不需要外

    2023年04月14日
    浏览(73)
  • FPGA中FIFO的应用(三)——Vivado FIFO IP核的调用

    ⭐️作者简介: 小瑞同学 ,一个努力精进的 FPGA 和通信学习者。 🍎个人主页:小瑞同学的博客主页 🌻个人信条:越努力,越幸运! ⏰日期:2023.12.6 🔍来源:自学经历 📖文章内容概述:简单介绍了 FIFO IP核 常用参数的配置,通过仿真分析了异步IP的 读写数据 过程。 连载

    2024年01月18日
    浏览(32)
  • 【FPGA IP系列】FIFO深度计算详解

    FIFO(First In First Out)是一种先进先出的存储结构,经常被用来在FPGA设计中进行数据缓存或者匹配传输速率。 FIFO的一个关键参数是其深度,也就是FIFO能够存储的数据条数,深度设计的合理,可以防止数据溢出,也可以节省FPGA资源的消耗。 影响FIFO深度计算的主要因素包括: FIF

    2024年02月06日
    浏览(43)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包