IP核的使用之FIFO(Vivado)

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

IP核的使用之FIFO(Vivado)

一、引言

在开始介绍FIFO IP核之前,我们先设想这么一个实际场景:FPGA内部有个16位计数器,以50MHz的频率计数,此时,我们希望随机截取计数器连续256个计数周期的值发到电脑上进行分析处理。用串口发送到电脑上。(数据产生速率大于数据使用速率),此时需要使用存储器先将这256个数据存储起来,再由串口慢慢发送到电脑。这时就引出了FIFO的使用场景即数据产生和使用速率不匹配。

二、FIFO IP核及相关内容扫盲

1.FIFO 简介

FIFO(First In First Out),即先进先出。FPGA 或者 ASIC 中使用到的 FIFO 一般指的是对数据的存储具有先进先出特性的一个缓存器,常被用于数据的缓存或者高速异步数据的交互。它与普通存储器的区别是没有外部读写地址线,这样使用起来相对简单,但缺点就是只能顺序写入数据,顺序的读出数据,其数据地址由内部读写指针自动加 1 完成,不能像普通存储器那样可以由地址线决定读取或写入某个指定的地址。

2.FIFO 结构

FIFO 从读写时钟上来分有两类结构:单时钟 FIFO(同步 FIFO - SCFIFO)双时钟 FIFO(异步FIFO - DCFIFO)单时钟 FIFO 具有一个时钟(读写共用一个时钟)输入,因此所有输入信号的读取都是在这个时钟的上升沿进行的,所有输出信号的变化也是在这个时钟信号的上升沿的控制下进行的,即单时钟 FIFO 的所有输入输出信号都是同步这个时钟信号的。而在双时钟 FIFO结构中,写端口和读端口分别有独立的时钟,所有与写相关的信号都是同步于写时钟 wr_clk的,所有与读相关的信号都是同步于读时钟 rd_clk 的。下面图是双时钟 FIFO 的整体框图和内部实现的框图,有单独的模块对读写时钟域进行同步处理
vivado fifo ip核使用,IP核,tcp/ip,fpga开发,网络协议
关于 FIFO 各个端口的详细功能解释可参考 Xilinx FIFO IP 手册。

3.FIFO 应用场景

(1) 单时钟 FIFO(同步 FIFO - SCFIFO)
**单时钟 FIFO 常用于片内数据交互。**例如,在 FPGA 的控制下从外部传感器读取到的一连串传感器数据,首先被写入 FIFO 中,然后再以 UART 串口波特率将数据依次发送出去。由于传感器的单次读取数据可能很快,但并不是时刻都需要采集数据,例如某传感器使用SPI 接口的协议,FPGA 以 2M 的 SPI 数据速率从该传感器中读取 20 个数据,然后以 9600的波特率通过串口发送出去。因为 2M 的数据速率远高于串口 9600 的波特率,因此需要将从传感器中采集到的数据首先用 FIFO 缓存起来,然后再以串口的数据速率缓慢发送出去。这里,由于传感器数据的读取和串口数据的发送都是可以同步于同一个时钟的,因此可以使用单时钟结构的 FIFO 来实现此功能。
(2) 双时钟 FIFO(异步FIFO - DCFIFO)
双时钟 FIFO 的一个典型应用就是异步数据的收发,所谓异步数据是指数据的发送端和接收端分别使用不同的时钟域。使用双时钟 FIFO 能够将不同时钟域中的数据同步到所需的时钟域系统中。例如,在一个高速数据采集系统中,实现将高速 ADC 采集的数据通过千兆以太网发送到 PC 机。ADC 的采样时钟(CLK1)由外部专用锁相环芯片产生,则高速 ADC 采样得到的数据就是同步于该 CLK1 时钟信号,在 FPGA 内部,如果 FPGA 工作时钟(CLK2)是由独立的时钟芯片加片上锁相环产生的,则 CLK1 和 CLK2就是两个不同域的时钟,他们的频率和相位没有必然的联系,假如 CLK1 为 65M,CLK2 为 125M,那么就不能使用 125M的数据来直接采集 65M 速率的数据,因为两者数据速率不匹配,在采集过程中会出现包括亚稳态问题在内的一系列问题,所以这里就可以使用一个具备双时钟结构的 FIFO 来进行异步数据的收发。如下图为使用 FIFO 进行异步数据收发的简易系统框图。
vivado fifo ip核使用,IP核,tcp/ip,fpga开发,网络协议
在此系统中,由于 ADC 的数据位宽为 8 位,基于 UDP 协议的以太网发送模块所需的数据也是 8 位,因此使用的是读写数据宽度相同的双时钟 FIFO 结构。假如 CLK1 的频率为20M,ADC 的数据位宽为 16 位,则可以使用读写数据位宽不同的双时钟 FIFO,在实现异步时钟域数据收发的同时,实现数据位宽的转换。通过设置双时钟 FIFO 的写入位宽为 16位,读取位宽为 8 位,则可以实现将 16 位的 ADC 数据转换为以太网支持的 8 位发送数据,然后通过以太网发送到 PC 机。

4.FIFO 常见参数

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

5.实现 FIFO 的方法

使用 FIFO 实现用户功能设计主要有三种实现方式。

第一种为用户根据需求自己编写 FIFO 逻辑,当对于 FIFO 的功能有特殊需求时,可以使用此种方式实现。
第二种方式为使用第三方提供的开源 IP 核,此种 IP 核以源码的形式提供,能够快速的应用到用户系统中,当用户对 FIFO 功能有特殊需求时,可以在此源码的基础上进行修改,以适应自己的系统需求。
第三种方式为使用 Xilinx Vivado 软件提供的免费 FIFO IP 核,此种方式下,Xilinx Vivado软件为用户提供了友好的图形化界面方便用户对 FIFO 的各种参数和结构进行配置,生成的 FIFO IP 核针对 Xilinx 不同系列的器件,还可以实现结构上的优化。由于该FIFO IP 核已经提供了大部分设计所需的所有功能,因此在系统设计中,推荐使用该 FIFO IP 核进行系统设计。

三、双时钟 FIFO(异步FIFO - DCFIFO)配置

打开 Vivado 软件,新建一个以名为 fifo_ip 的工程,然后在 Vivado 软件窗口左侧找到 IP Catalog 并 点 击, 在 右边 的 IP Catalog 窗 口 搜索 fifo , 在 下 面 搜 索 的结 果 中 找 到 Memories&Storage Elements 下 FIFO 中的 FIFO Generator 并双击。
vivado fifo ip核使用,IP核,tcp/ip,fpga开发,网络协议
进入到 FIFO 的设置界面
vivado fifo ip核使用,IP核,tcp/ip,fpga开发,网络协议
在 IP Location 可以修改 IP 生成的路径,这里保持默认路径,修改 IP 名称为 dcfifo。在 IP 设置界面对接口类型设置为 Native(常规接口),FIFO 类型上根据使用的资源以及读写时钟是否相同分为多种,这里创建一个独立读写时钟,使用嵌入式 Block RAM 资源的 FIFO,选择 Independent Clocks Block RAM(表示为异步FIFO,用的块RAM资源)
vivado fifo ip核使用,IP核,tcp/ip,fpga开发,网络协议
写数据位宽均设置为 8bits(实际根据需要可以设置读写数据位宽不一样),数据深度为 256words。这里修改数据位宽及深度。需要注意的是设置数据后面有实际深度,这里虽然我们配置的是 256,但实际 FIFO 只有 255 的深度,这个是需要注意的,最终配置深度以后面实际深度为准,这个可能和 FIFO IP 内部设计有关,不过多讲解,实际使用时注意就行。
vivado fifo ip核使用,IP核,tcp/ip,fpga开发,网络协议
上面 Read Mode 有两种类型可选,Standard FIFO 是在给了读数据使能后,数据才出来,而 First Word Fall Through 模式是,当前数据提前已经到数据读数据线上,在读使能到来后,下一个数据会到数据线上,可以结合下面的时序图进行理解。这里选择 Standard FIFO 类型。
vivado fifo ip核使用,IP核,tcp/ip,fpga开发,网络协议
关于 ECC 这里不做讲解,需要了解的可以查看手册,在 Output Register 勾选并选择 Embedded Register,也可以选择 Fabric Register,或者两个寄存器都选加上,多加一个输出寄存器,输出就会多延迟一个时钟周期出来。
vivado fifo ip核使用,IP核,tcp/ip,fpga开发,网络协议
这里可以保持默认的勾选复位管脚、复位同步和使能 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 过程需要注意的地方,有关具体时序波形可以到看后面仿真。
vivado fifo ip核使用,IP核,tcp/ip,fpga开发,网络协议
手册中还有提到一点,就是异步复位信号持续时间需要多长的问题,理论上 1 个较小的时钟周期(读写时钟周期中较小的那个,这里说的是周期较小的,也就是频率高的那个的)就行,实际使用推荐至少保持有 3 个或着设置同步级数个周期。这里提到的同步级数就是在 IP 设置的第一个界面中的 Synchronization Stages,这个只有在选择独立时钟 FIFO 类型时才会有这个设置,在相同时钟 FIFO 类型下是没有这个设置的。
vivado fifo ip核使用,IP核,tcp/ip,fpga开发,网络协议
①Full Flag Reset Value:设置在复位时,满信号处于什么值,这里保持默认的 1,也就是复位时认为是满,禁止写入。
②Dout Reset Value:设置复位时,FIFO 输出处于什么值,保持默认。
③Read Latency:这里会根据前面设置自动更新,前面我们设置输出加上一个寄存器,这里就变为了 2,不加寄存器的情况下是 1,加两个寄存器就是 3
vivado fifo ip核使用,IP核,tcp/ip,fpga开发,网络协议
状态输出信号的设置,包括将空和将满信号,读写端口握手信号,这里根据实际情况进行选择,这里作为实验演示就都勾选上,便于后面看波形。这里读写端口握手信号都勾选上后,会看到 FIFO 输出管脚会多出一些信号。
①wr_ack:写操作响应信号,当向 FIFO 写入数据时,如果正确写入到 FIFO 了,会输出
高电平表示数据已成功写入。
②overflow:上溢出标识信号,表示 FIFO 数据满情况下继续往 FIFO 里写数据,该信号会
拉高标志向上溢出。
③valid:读数据输出数据有效信号,在进行读操作时,valid 信号伴随数据输出而拉高,高
电平表示输出数据有效,用户逻辑可以根据该信号对读出的数据做后续进一步的处理使
用。
④underflow:下溢出标识信号,表示 FIFO 数据空情况下继续对 FIFO 进行读操作,该信
号会拉高标志向下溢出。
vivado fifo ip核使用,IP核,tcp/ip,fpga开发,网络协议
空满信号产生的数据个数的阈值设置,Programmable Full Type 和 Programmable Empty Type有多种类型可以选择。默认是No Programmable Full Threshold和No Programmable Empty Threshold,默认情况下设置值依次为 253,252,2,3。简单描述下就是当数据大于等于 253时,full 信号置 1,在 full 为 1 情况下,fifo 内数据量减小到 252 以下(包括 252)时,full 变为 0。同理对与空信号,当 FIFO 内数据量从 0 增加到 3(或大于 3)时,empty 信号变为 0,在 empty 为 0 的情况下,当 FIFO 数据量减少到 2(包括 2)时,empty 变为高。从这里可以看出,full 信号并不是在 FIFO 完全写满才置 1,留有一定的余量,同样 empty 也是一样,并非在 FIFO 完全读空才置 1。
vivado fifo ip核使用,IP核,tcp/ip,fpga开发,网络协议
当然这里只是默认设置,里面的值我们是可以更改设置的,通过 Programmable Full Type 和 Programmable Empty Type 选择不同设置模式可以进行设置,下面以 Programmable Full Type 设置为例做简单的介绍:
①Single Programmable Full Threshold Constant:仅对 Assert Value 值可进行设置,Negate Value 不可设置,保持默认。
②Multiple Programmable Full Threshold Constant:Assert Value 和 Negate Value 均可设置。
③Single Programmable Full Threshold Input Port:Assert Value 可由输入端口进行设置,Negate Value 不可设置,保持默认,这种情况下 FIFO 会多出一个输入端口prog_full_thresh。
vivado fifo ip核使用,IP核,tcp/ip,fpga开发,网络协议
④Multiple Programmable Full Threshold Input Port:Assert Value 和 Negate Value 均可由输入端口进行设置。这种情况下FIFO会多出两个输入端口分别为 prog_full_thresh_assert[7:0]和 prog_full_thresh_negate[7:0],用于设置 Assert Value 和 Negate Value。
vivado fifo ip核使用,IP核,tcp/ip,fpga开发,网络协议
FIFO 数据量计数信号输出,Write Data Count 和 Read Data Count 分别同步与写时钟和读时钟。位宽可以根据实际进行设置,这里保持默认位宽 8。
vivado fifo ip核使用,IP核,tcp/ip,fpga开发,网络协议
以上设置完后,可以在 Summary 一栏看到前面一些设置的总结,里面信息包括存储器类型,数据位宽 8bit,深度 255 以及一些状态信号的选择等信息。
vivado fifo ip核使用,IP核,tcp/ip,fpga开发,网络协议
点击界面左下角 OK,弹出Generate,生成FIFO IP核。

四、双时钟 FIFO(异步FIFO - DCFIFO)仿真验证

1.测试代码:

`timescale 1ns / 1ns
`define WR_CLK_PERIOD 10
`define  RD_CLK_PERIOD 30

module dcfifo_tb();

 reg rst;
 reg wr_clk;
 reg rd_clk;
 reg [7:0]din;
 reg wr_en;
 reg rd_en; 
 reg [7:0] prog_full_thresh_assert;
 reg [7:0] prog_full_thresh_negate;
 wire [7:0]dout;
 wire full;
 wire almost_full;
 wire wr_ack;
 wire overflow;
 wire empty;
 wire almost_empty;
 wire valid;
 wire underflow;
 wire [7:0]rd_data_count;
 wire [7:0]wr_data_count;
 wire prog_full;
 wire wr_rst_busy;
 wire rd_rst_busy;


dcfifo dcfifo_inst (
  .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
  .prog_full_thresh_assert(prog_full_thresh_assert),  // input wire [7 : 0] prog_full_thresh_assert
  .prog_full_thresh_negate(prog_full_thresh_negate),  // input wire [7 : 0] prog_full_thresh_negate
  .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
  .wr_rst_busy(wr_rst_busy),                          // output wire wr_rst_busy
  .rd_rst_busy(rd_rst_busy)                          // output wire rd_rst_busy
);

 initial wr_clk = 1;
 always #(`WR_CLK_PERIOD/2) wr_clk = ~wr_clk;
 initial rd_clk = 1;
 always #(`RD_CLK_PERIOD/2) rd_clk = ~rd_clk;

 initial begin
     rst = 1'b1;
     wr_en = 1'b0;
     rd_en = 1'b0;
     din = 8'hff;
     prog_full_thresh_assert = 8'd0;
     prog_full_thresh_negate = 8'd0;
     
     #(`WR_CLK_PERIOD*3+1);
     rst = 1'b0;
     prog_full_thresh_assert = 8'd253;
     prog_full_thresh_negate = 8'd252;
     
     @(negedge wr_rst_busy); 
     //write data
     while(full == 1'b0)
         begin
             @(posedge wr_clk);
             #1; 
             wr_en = 1'b1;
             din = din - 1'b1;
         end
     wr_en = 1'b0;
     
     wait(rd_rst_busy == 1'b0);
     
     while(empty == 1'b0)
         begin 
             @(posedge rd_clk);
             #1;
             rd_en = 1'b1;
         end
     rd_en = 1'b0;
     
     //reset
     #200;
     rst = 1'b1;
     #(`WR_CLK_PERIOD*3+1);
     rst = 1'b0;
     @(negedge wr_rst_busy);
     wait(rd_rst_busy == 1'b0);
     
     #2000;
     $stop;

end
endmodule

2、仿真结果

vivado fifo ip核使用,IP核,tcp/ip,fpga开发,网络协议

五、单时钟 FIFO(同步FIFO - SCFIFO)仿真验证

选 FIFO 的类型,以及使用什么资源来实现。选择“Common Clock Block RAM”使用块 RAM 来实现同步 FIFO;其中 Common Clock 表示是同步 FIFO,Block RAM 表示的是块 RAM 资源。
vivado fifo ip核使用,IP核,tcp/ip,fpga开发,网络协议
其余设置可参考上文。

参考视频:
小梅哥:FIFO模型与应用场景详解文章来源地址https://www.toymoban.com/news/detail-802045.html

到了这里,关于IP核的使用之FIFO(Vivado)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • vivado IP核:ILA、时钟、RAM、FIFO

    vivado工具集成了逻辑分析仪,ILA IP核用于替换外部的逻辑分析仪,添加探针来监控内部信号波形变化。 1)IP Catalog 2)搜索栏可搜索IP核,如创建FIFO、RAM等。 3)搜索并选择。 4)设置ILA各项参数。    5) 设置好IP核参数后点ok。 6)打开ila_0.evo。 7) 复制ila例化模板。 8)在

    2023年04月21日
    浏览(44)
  • FPGA零基础学习之Vivado-FIFO使用教程

    本系列将带来FPGA的系统性学习,从最基本的数字电路基础开始,最详细操作步骤,最直白的言语描述,手把手的“傻瓜式”讲解,让电子、信息、通信类专业学生、初入职场小白及打算进阶提升的职业开发者都可以有系统性学习的机会。 系统性的掌握技术开发以及相关要求

    2024年02月20日
    浏览(40)
  • FIFO(一) —— Quartus中FIFO IP核的学习与modelsim仿真

    1、 FIFO:(First In First Out),是有先进先出特性的缓存器,常被用于数据的缓存或者高速异步数据的交互。 2、 FIFO与普通存储器的区别在于:它没有外部读写地址线(其数据地址由内部读写指针自动加 1 完成),操作简单但不能指定某一地址。 3、主要包含两种:单时钟FIF

    2024年02月08日
    浏览(49)
  • 【Vivado】clock ip核的使用

    ​ Clock在时序逻辑的设计中是不可或缺的,同时对于Clock的编写和优化也能体现一个FPGA工程师的技术水平,Clock的分频,倍频在设计项目时都有可能用到,对于分频,可以通过代码的方式进行实现,而倍频,就要用到我们今天的主角——Clock IP核。熟练使用Clock IP核是学习FPG

    2024年01月16日
    浏览(58)
  • 【Vivado】ram ip核的使用

    ​ ram 的英文全称是 Random Access Memory,即随机存取存储器, 它可以随时把数据写入任一指定地址的存储单元,也可以随时从任一指定地址中读出数据, 其读写速度是由时钟频率决定的。 ram 主要用来存放程序及程序执行过程中产生的中间数据、 运算结果等。 ​ rom为只读存储

    2024年02月02日
    浏览(35)
  • Vivado中VIO IP核的使用

      Vivado中的VIO(Virtual Input/Output) IP核是一种用于调试和测试FPGA设计的IP核。它允许设计者通过使用JTAG接口读取和写入FPGA内部的寄存器,从而检查设计的运行状态并修改其行为。VIO IP核提供了一个简单易用的接口,使得用户可以轻松地与FPGA内部寄存器进行交互。通过使用

    2024年02月06日
    浏览(87)
  • Vivado PLL锁相环 IP核的使用

    本文纯属学习笔记,使用的FPGA是Xilinx的XC7A35TFGG484-1,使用Vivado调用PLL IP核来实现倍频效果,使50Mhz的晶振时钟源倍频到100Mhz、200Mhz和400Mhz。 Clocking Options 1.MMCM与PLL相比,PLL的时钟质量更高,所以对时钟质量要求较高的时候需要选择PLL,但是一般可以不用纠结。 2.修改Input Fre

    2024年02月08日
    浏览(40)
  • vivado DDS IP核的使用及仿真

    参考:https://blog.csdn.net/weixin_45303812/article/details/123704440 新人第一次写文档,有错误的地方请大佬指点。 文档:Xilinx官网搜DDS Configuration 可配置参数 : 1.Configuration Options,有如下三种模式 Phase Generator and SIN/COS LUT (DDS): 相位和sin和cos的数据都是IP核自己产生 Phase Generator only:

    2023年04月15日
    浏览(47)
  • 如何使用Synplify综合vivado带IP核的工程

    下面的说法来自网上: 综合时间更好,综合出来所使用的逻辑更少 综合的时序更好 在IC设计中,使用Synplify综合+Vivado组合比较多。synplify 用于生成网表,然后将网表倒入FPGA中,进行布局布线等操作。 Libero集成开发环境中Synplify应用与提高-Microsemi(Actel) FPGA开发工具——周

    2024年02月11日
    浏览(51)
  • FPGA 学习分享-- 04 FIFO核的使用(2)

    写在前面: 博主耗费了四天!!!完成了FIFO核的第二部分。 在这个部分,博主遇到了很多问题,对着代码不停修改,询问学长和老师,好在终于没有报错,可以向大家交作业了!当然,我会在本文详细的帮助大家学习FIFO核的代码编写,带着大家剖析每个部分,尽可能地通俗

    2024年02月03日
    浏览(41)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包