FIFO-IP核的配置
下面操作是以异步FIFO为例,且读模式为首字先出模式FWFT。

配置界面1

1、模块命名
首先给FIFO模块起名,要做到见名知意。

2、接口类型
接口类型,选择不同的接口类型,那么FIFO的信号线是不同的,也就是说接口类型不同,信号线的功能也不一样,我们的读写操作所使用的信号线不同。我们默认选择Native本地接口。


3、FIFO类型
FIFO类型选取,有同步FIFO和异步FIFO。

Block RAM称为块RAM、嵌入式RAM,它是一个电路,专门用于存储数据的。其电路是在FPGA内部,一块BRAM大小为36Kbit,由两个小的RAM(18Kbit)组成。在FPGA内部资源里有很多BRM资源。它是按块使用的,比如我们位宽是64bit,深度为65536,那么就要消耗64*65535 / (36*1024) ≈ 113.8,需要114个BRAM。那如果消耗了113.1个,那么还是消耗114个BRAM。
总结:(1)FPGA越贵,BRAM资源越多
(2)BRAM的数量,需要根据我们选择芯片信号,去查看手册得知。
(3)每一个BRAM的容量大小为36Kbit,每一块BRAM是由两个小的RAM(18Kbit)组成。
(4)有时候使用存储类的IP核,可能消耗的是BRAM资源,主要看我们选择是BRAM还是DRAM。
(5)消耗BRAM计算公式:位宽*深度 bit / 36Kbit,若存在小数,则结果要+1。
Distributed RAM称为分布式RAM,它消耗的只能是FPGA内部的CLB(可配置逻辑块)中的SLILCM中的LUT(查找表)资源, 可在UG474手册中12页查到。SLILCM的资源要少于SLILCL,在FPGA中比较分散。

FIFO/ROM/RAM-IP核如何选择RAM类型:
BRAM:尽量选择这个,数据量大、较为重要的数据、时钟频率高。是因为它是一个电路 ,专门用于存储数据,适用于时钟频率快的情况。
DRAM:数据量小、不太重要的数据、时钟频率低。是因为它消耗的只能是FPGA内部的CLB(可配置逻辑块)中的SLILCM中的LUT(查找表)资源,而SLILCM的资源在FPGA中比较分散,在读写数据时这个时延相对来说比较大,适用于时钟频率慢的情况。
Bulitin FIFO:在FPGA内部是一个专门的电路,适用于高速的数据缓存的情况。
这里选择异步FIFO的BRAM类型。

配置界面2

1、读模式选择
设置读模式,分别是标准FIFO和首字先出模式。
标准FIFO:读使能rden和读数据之间会有一拍的延迟,也就是1个时钟的潜伏期(1 Clock Latency)
首字先出模式(FWFT) :读使能rden和读数据之间无延迟,也就是0个潜伏期(0 Clock Latency)
2、数据端口的参数
然后再设置读写位宽,以及深度。
异步FIFO可以解决的问题:(1)数据位宽不匹配问题(跨位宽),FIFO作为数据缓存器(同步FIFO也可以),但是需要注意的是读位宽最大只能是写位宽的8倍。(2)跨时域问题

3、输出寄存器
读使能rden和读数据之间的Clock Latency有三种情况:
0拍:FWFT,用在读使能rden和读数据间的时序是对齐的。
1拍:Standard,正常情况下都使用这个。
2拍:Standard + Output Registers,当时钟频率>=200Mhz或者我们的工程所用资源超过了FPGA芯片内部资源的70%,推荐使用2拍延迟

4、复位引脚
FIFO的复位信号rst高电平有效,在复位时rst信号高电平持续时间需要长一些,而且复位结束以后还需要等一会时间。如下图所示:来自PG057手册P128。在这段时间内读写数据都是无效的,也就是说在复位操作这段时间内不可以读写数据。

配置界面3

prog_full和prog_empty可作为反馈机制引脚,控制往FIFO里写数据模块,FIFO快满时不能写,FIFO读空时快点写。
配置界面4

假设写数据位宽位8bit,读数据位宽16bit。
写用量信号wr_data_count:代表FIFO中有多少个8bit数据。
读用量信号rd_data_count:代表FIFO中有多少个16bit数据。
配置界面5
最后检查一下配置是否正确,然后点击OK,即完成FIFO-IP核的配置。

仿真代码
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2023/05/17 09:16:36
// Design Name:
// Module Name: FWFT_FIFO_TB
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module FWFT_FIFO_TB(
);
reg fifo_clk;
reg [15:0] fifo_wrdata;
reg fifo_wren;
reg fifo_rden;
reg rst_n;
initial begin
fifo_clk = 1'b0;
rst_n = 1'b0;
#300.1
rst_n = 1'b1;
end
always #10 fifo_clk = ~fifo_clk;
reg [15:0]work_cnt;
always @ (posedge fifo_clk or negedge rst_n)
begin
if(~rst_n)
begin
work_cnt <= 16'd0;
end
else if(work_cnt == 16'd1000)
begin
work_cnt <= work_cnt;
end
else
begin
work_cnt <= work_cnt + 1'b1;
end
end
always @ (posedge fifo_clk or negedge rst_n)
begin
if(~rst_n)
begin
fifo_wrdata <= 16'd0;
fifo_wren <= 1'b0;
end
else if((work_cnt >= 100) && (work_cnt <= 199))//写了100个随机数据
begin
fifo_wrdata <= {$random} %3000;
fifo_wren <= 1'b1;
end
else
begin
fifo_wren <= 1'b0;
fifo_wrdata <= 16'd0;
end
end
always @ (posedge fifo_clk or negedge rst_n)
begin
if(~rst_n)
begin
fifo_rden <= 1'b0;
end
else if((work_cnt >= 200) && (work_cnt <= 299))
begin
fifo_rden <= 1'b1;
end
else
begin
fifo_rden <= 1'b0;
end
end
wire fifo_full;
wire fifo_empty;
wire [15:0]fifo_dataout;
wire [10:0] fifo_data_count;//表示FIFO内部已经存在的数据量
wire [10:0] wr_data_count;
//异步FIFO测试
FWFT_FIFO FWFT_FIFO (
.wr_clk(fifo_clk), // input wire wr_clk
.rd_clk(fifo_clk), // input wire rd_clk
.din(fifo_wrdata), // input wire [15 : 0] din
.wr_en(fifo_wren), // input wire wr_en
.rd_en(fifo_rden), // input wire rd_en
.dout(fifo_dataout), // output wire [15 : 0] dout
.full(fifo_full), // output wire full
.empty(fifo_empty), // output wire empty
.rd_data_count(fifo_data_count), // output wire [10 : 0] rd_data_count
.wr_data_count(wr_data_count) // output wire [10 : 0] wr_data_count
);
endmodule
仿真验证

由于使用的首字先出模式,会在写数据时,将第一个数据放在读数据端口上,以此来实现的0拍的延迟。所以才会导致上面这种情况。但是不影响后续读数据时序。

