> 技术文档 > VIVADO FIFO (同步和异步) IP 核详细使用配置步骤_vivado fifo ip核使用

VIVADO FIFO (同步和异步) IP 核详细使用配置步骤_vivado fifo ip核使用


VIVADO FIFO (同步和异步) IP 核详细使用配置步骤

目录

前言

一、同步FIFO的使用

1、配置

2、仿真

二、异步FIFO的使用

1、配置

2、仿真


前言

        在系统设计中,利用FIFO(first in first out)进行数据处理是再普遍不过的应用了,使用FIFO实现不同域时钟的数据同步,总线位宽调整,数据缓存等。本文以xilinx vivado中的FIFO IP 核为例,详细介绍其配置步骤,并给出详细的仿真,本文包含同步和异步(不同时钟)FIFO的详细使用步骤。


提示:以下是本篇文章正文内容,转载请附上原文链接

一、同步FIFO的使用

1、配置

         在IP Catalog 界面搜索FIFO并双击FIFO Generator开始配置IP 核。对IP核命名,不妨取test_synchronous_fifo(同步FIFO的测试)。

首先,配置Basic界面:

Interface Type 保持默认即可,一般不选AXI接口。

FIFO Implementation 选用什么资源生成FIFO,这里选择 Common Clock Block RAM,即用块RAM资源生成一个同步FIFO。

该界面下面显示的是在选定方式生成的FIFO具有的特点。

然后,配置Native Ports界面:

Read Mode 默认选Standard FIFO,First FIFO Fall Through 会在没有读的时候就在读端口放置第一个数据,如手册中的下图所示,只要写入一个数据 D1 后,在rd_en为低电平的时候,dout就会变成D1且valid一直拉高。大家可以根据自己的需求选择对应的读模式。

Data Port Parameters 用来配置读写的深度和数据位宽,这里示例配置4bit宽度,16的深度。

!!!要留意一下配置的深度和实际的深度,手册中提及了选择不同实现方式(Basic 界面)实际深度与配置的深度是有差异的,实际深度才是可以使用的深度。

ECC,Output... 是IP核纠错,输出端加寄存器的功能,在配置时其实不用管,不用勾选任何东西。

Initialization 勾选复位,类型选择同步复位,Full Flags Reset Value 是复位时满标志的默认电平,Dout Reset Value 是复位时默认的读端口输出。

再然后,配置Status Flags界面:

Optional Flags中的Almost Full Flag是快要写满标志,即再写一个数据就满了的提示, Almost Empty Flag是快要读空标志,即再读一个数据就空了的提示。

Write Acknowledge 是写数据的标志,如果勾选高电平有效,则其拉高表示数据被写入。

Overflow 是溢出标志,如果满了,继续写数据是写不了的,溢出了。

valid Flag 读数据时输出数据有效的标志。

Underflow Flag 下溢标志,如果选择高电平有效,也就是读空了继续读该标志就会拉高。

Programmable Flags 是自定义一个数据写多少个就算满的标志信号和数据还剩多少个就算空的标志信号,可以在IP核界面配置固定的值,也可以引入两个输入端口由程序编程设置。需要用到该功能的可自行配置。

此处,按下图配置届时仿真可观察这些信号。

最后,配置Data Counts界面:

可以勾选Data Count,指示FIFO中还有多少个数据。由于此时是同步FIFO,所以只有一个Data Count。

至此,同步 FIFO 配置完成,下面进行仿真。

2、仿真

        创建一个名为 tb_synchronous_fifo 的 testbench 文件,测试以上配置的FIFO。

`timescale 1ns / 1ps//////////////////////////////////////////////////////////////////////////////////// Company: // Engineer: // // Create Date: 2025/01/15 11:36:36// Design Name: // Module Name: tb_synchronous_fifo// Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision:// Revision 0.01 - File Created// Additional Comments:// //////////////////////////////////////////////////////////////////////////////////module tb_synchronous_fifo();parameter PERIOD = 2;reg clk=1;reg rst_n=0;reg [3 : 0] din=0;reg wr_en=0;reg rd_en=0;wire [3 : 0] dout;wire full;wire almost_full;wire wr_ack;wire overflow;wire empty;wire almost_empty;wire valid;wire underflow;wire [3 : 0] data_count;initialbegin forever #(PERIOD/2) clk=~clk;endinitialbegin #(PERIOD*5) rst_n = 1;endreg [4:0] cnt;always @(posedge clk or negedge rst_n)begin if(!rst_n) begin wr_en<=0; cnt<=0; end else if(cnt<16) begin cnt<=cnt+1; wr_en<=1; din<=din+1; end else begin wr_en<=0; endendalways @(posedge clk or negedge rst_n)begin if(!rst_n) begin rd_en<=0; end else if(cnt==16) begin rd_en<=1; endendtest_synchronous_fifo u_test_synchronous_fifo ( .clk(clk),  // input wire clk .srst(!rst_n), // input wire srst ip核本身是高电平复位 .din(din),  // input wire [3 : 0] din .wr_en(wr_en), // input wire wr_en .rd_en(rd_en), // input wire rd_en .dout(dout),  // output wire [3 : 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 .data_count(data_count) // output wire [3 : 0] data_count);endmodule

        从以上结果可以看出写入16个数据,读出16个数据,谁先写入就先被读出。大家可自行观察其他信号的变化是否和自己理解的一致。

        上面配置FIFO的深度只有16,如果写入数据个数大于16,数据能写进去吗?答案是写不进去,并不是我们理解的满了再进就会将最开始进的挤出去。VIVADO FIFO IP就是这样这样设置的,没有办法改变,那么如果某些场景下需要这种满了再进就会将最开始进的挤出去的这种功能,光调用IP还无法实现。

        例如,将上面代码中的 else if(cnt<16)  和 else if(cnt==16) 两句代码中的16改成20再仿真,结果如下,分析结果可以得出,满了继续写不会将最开始写的挤出去,而是直接忽视掉再写的数据。

二、异步FIFO的使用

1、配置

        在IP Catalog 界面搜索FIFO并双击FIFO Generator开始配置IP 核。对IP核命名,不妨取test_asynchronous_fifo(异步FIFO的测试)。

首先,配置Basic界面:

Interface Type 保持默认即可,一般不选AXI接口。

FIFO Implementation 选用什么资源生成FIFO,这里选择 Independent Clocks Block RAM,即用块RAM资源生成一个异步FIFO。

相比于同步FIFO,多了synchronization Stages的配置,这个相当于写时钟域里面的数据经过多少个时钟周期同步到读时钟区域,可以理解成延时打拍同步。

该界面下面显示的是在选定方式生成的FIFO具有的特点。

然后,配置Native Ports界面:

Read Mode 同步FIFO配置有介绍,此处默认选Standard FIFO。

Data Port Parameters 用来配置读写的深度和数据位宽,这里示例配置4bit宽度,16的深度。

!!!要留意一下配置的深度和实际的深度,手册中提及了选择不同实现方式(Basic 界面)实际深度与配置的深度是有差异的,实际深度才是可以使用的深度。异步FIFO此时实际可使用的深度就比我们配置的少了一个。

ECC,Output... 是IP核自己纠错,输出端加寄存器的功能,在配置时其实不用管,不用勾选任何东西。

Initialization 勾选复位,Reset Type 固定了只能异步复位,是相对于整个IP而言。Full Flags Reset Value 是复位后满标志的默认电平,Dout Reset Value 是复位后默认的读端口输出。

相比于同步FIFO,多了Enable Reset Synchronization,该选项是读写时钟域分开来看时,在各自的时钟域里面使用同步复位。Enable Safety Circuit 手册说是一个保护电路,默认勾选即可,不用过多纠结。

Full Flags Reset Value 是复位时满标志默认电平,Dout Reset Value 是复位时默认读端口输出。

再然后,配置Status Flags界面:

同步FIFO配置界面已一 一说明。此处,按下图配置届时仿真可观察这些信号。

最后,配置Data Counts界面:

Data Count,指示FIFO中还有多少个数据。由于此时是异步FIFO,所以读写各有一个Data Count。

至此,异步 FIFO 配置完成,下面进行仿真。

2、仿真

        创建一个名为 tb_asynchronous_fifo 的 testbench 文件,测试以上配置的异步FIFO。

`timescale 1ns / 1ps//////////////////////////////////////////////////////////////////////////////////// Company: // Engineer: // // Create Date: 2025/01/15 12:20:08// Design Name: // Module Name: tb_asynchronous_fifo// Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision:// Revision 0.01 - File Created// Additional Comments:// //////////////////////////////////////////////////////////////////////////////////module tb_asynchronous_fifo();parameter PERIOD = 2;reg rst_n=0;reg wr_clk=1;reg rd_clk=1;reg [3 : 0] din=0;reg wr_en=0;reg rd_en=0;wire [3 : 0] dout;wire full;wire almost_full;wire wr_ack;wire overflow;wire empty;wire almost_empty;wire valid;wire underflow;wire [3 : 0] rd_data_count;wire [3 : 0] wr_data_count;wire wr_rst_busy;wire rd_rst_busy;initialbegin forever #(PERIOD/2) wr_clk=~wr_clk;endinitialbegin forever #(PERIOD) rd_clk=~rd_clk;endinitialbegin #(PERIOD*5) rst_n = 1;endreg flag=0;initialbegin #(PERIOD*28) flag = 1; #(PERIOD) flag = 0;endreg [4:0] cnt;always @(posedge wr_clk or negedge rst_n)begin if(!rst_n) begin wr_en<=0; cnt<=0; end else if(flag) begin cnt<=cnt+1; wr_en<=1; din<=din+1; end else if(1<=cnt&&cnt<16) begin cnt<=cnt+1; wr_en<=1; din<=din+1; end else begin wr_en<=0; endendalways @(posedge rd_clk or negedge rst_n)begin if(!rst_n) begin rd_en<=0; end else if(cnt==16) begin rd_en<=1; endendtest_asynchronous_fifo u_test_asynchronous_fifo ( .rst(!rst_n),  // input wire rst .wr_clk(wr_clk), // input wire wr_clk .rd_clk(rd_clk), // input wire rd_clk .din(din),// input wire [3 : 0] din .wr_en(wr_en),  // input wire wr_en .rd_en(rd_en),  // input wire rd_en .dout(dout),  // output wire [3 : 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 [3 : 0] rd_data_count .wr_data_count(wr_data_count), // output wire [3 : 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);endmodule

观察上面的仿真结果,第一,复位时满信号为1,与我们IP配置界面相吻合;第二,因为本身实际容量只有15个数据,我们写16个数据,溢出了一个,图中overflow拉高了一个电平,与同步FIFO一样,写满了就写不进去了;第三,图中两条黄色线之间相差4个读时钟周期,就是我们前面配置提到的延迟打拍保证时钟区域同步,那明明前面配置的是2,为什么这里为4呢?这是因为下图中的数字2造成的,2+2=4。

接下来将IP配置界面的同步拍数改为3,那么仿真图中两条黄色线之间则会有5个读时钟周期,以保证数据同步到读时钟域,如下面仿真图所示。

至此,本文结束。说明一下,如果自己想设置写到一定数量就有满标志提示,还剩多少个就有空标志提示,就需要去配置Status Flags界面的Programmable Flags。