1.首先介绍使用xilinx fifo 原语优势:
在设计或大或小的工程时,尤其是视频项目,往往会使用许多异步fifo作为数据缓存,xilinx fifo使用需要调用IP设置开发,较为麻烦,而且过多fifo命名也会导致重复或则不便于修改,因此需要寻找一种便捷管理方法。
xilinx内部提供了一种fifo原语,用户可以通过原理例化,参数匹配即可完成在线自定义FIFO深度以及引出需要的信号,灵活性可谓是得到大幅度提升。
2.XMP fifo使用:
首先在例化模板内找到:
上图所示,async为异步FIFO,suync为同步fifo。
以异步fifo为例,本设计更改异步fifo原语后将其自定义,后续只需对该头文件例化后即可作为FIFO ip使用,更改后的fifo.v代码如下所示:
`timescale 1ns / 1ps
//
// Company: Nuist
// Engineer: jia yu chen
//
// Create Date: 2023/05/16 13:00:18
// Design Name:
// Module Name: async_fifo
// Project Name: async_fifo
// Target Devices:
// Tool Versions:
// Description:
//
module async_fifo #(
parameter integer FIFO_TYPES = 0 ,//‘0’fwft,‘1’为标准fifo延迟一个时钟,需要更改模式
parameter integer FIFO_WRITE_DEPTH = 2048 ,//fifo写深度
parameter integer READ_DATA_WIDTH = 32 ,//读数据位宽
parameter integer WRITE_DATA_WIDTH = 32 ,//写数据位宽
parameter integer PROG_EMPTY_THRESH = 10 ,
parameter integer PROG_FULL_THRESH = 10 ,
parameter integer WR_WIDTH = 10 ,
parameter integer RD_WIDTH = 10
)
(
input wire fifo_rst ,
input wire wr_clk ,
input wire wr_en ,
input wire [WRITE_DATA_WIDTH-1:0] wr_data ,
input wire rd_clk ,
input wire rd_en ,
output wire [READ_DATA_WIDTH-1:0] rd_data ,
output wire [WR_WIDTH-1:0] wr_data_count ,
output wire [RD_WIDTH-1:0] rd_data_count ,
output wire empty ,
output wire full ,
output wire prog_empty ,
output wire prog_full
);
function integer clogb2 (input integer bit_depth);
begin
for(clogb2=0; bit_depth>0; clogb2=clogb2+1)
bit_depth = bit_depth >> 1;
end
endfunction
localparam FIFO_READ_LATENCY = FIFO_TYPES; //fifo读写延迟值
localparam RD_DATA_COUNT_WIDTH = clogb2( WRITE_DATA_WIDTH*FIFO_WRITE_DEPTH/WRITE_DATA_WIDTH-1)+1 ; //读侧fifo计数器位宽.总容量÷读位宽-1求位宽 + 1
localparam WR_DATA_COUNT_WIDTH = clogb2(FIFO_WRITE_DEPTH-1)+1 ; //写侧fifo计数器位宽,用写侧深度-1求位宽即可
// localparam TYPE = FIFO_TYPES? "std" :"fwft" ;//模式先入先出或者标准
xpm_fifo_async #(
.CDC_SYNC_STAGES(2), // DECIMAL
.DOUT_RESET_VALUE("0"), // String
.ECC_MODE("no_ecc"), //string; "no_ecc" or "en_ecc";
.FIFO_MEMORY_TYPE("auto"), //string; "auto", "block", or "distributed";
.FIFO_READ_LATENCY(FIFO_READ_LATENCY), // 读延时
.FIFO_WRITE_DEPTH(FIFO_WRITE_DEPTH), //integer 写fifo深度
.FULL_RESET_VALUE(0), // positive integer; 0 or 1
.PROG_EMPTY_THRESH(PROG_EMPTY_THRESH), // fifo快空水线
.PROG_FULL_THRESH(PROG_FULL_THRESH), //fifo快满水线
.RD_DATA_COUNT_WIDTH(RD_DATA_COUNT_WIDTH), //读侧fifo计数器位宽
.READ_DATA_WIDTH(READ_DATA_WIDTH), // fifo读侧读数据位宽
.READ_MODE("fwft"), //string; "std" or "fwft";先入先出或者标准模式
.RELATED_CLOCKS(0), //positive integer; 0 or 1
.SIM_ASSERT_CHK(0), // DECIMAL; 0=disable simulation messages, 1=enable simulation messages
.USE_ADV_FEATURES("0707"), //string; "0000" to "1F1F";
.WAKEUP_TIME(0), // positive integer; 0 or 2;
.WRITE_DATA_WIDTH(WRITE_DATA_WIDTH), //integer 写数据位宽
.WR_DATA_COUNT_WIDTH(WR_DATA_COUNT_WIDTH) //integer 写数据计数器位宽
)
xpm_fifo_async_inst (
.almost_empty(), // 1-bit output: Almost Empty : When asserted, this signal indicates that
.almost_full(), // 1-bit output: Almost Full: When asserted, this signal indicates that
.data_valid(), // 1-bit output: Read Data Valid: When asserted, this signal indicates
.dbiterr(), // 1-bit output: Double Bit Error: Indicates that the ECC decoder detected
.dout(rd_data), // READ_DATA_WIDTH-bit output: Read Data: The output data bus is driven
.empty(empty), // 1-bit output: Empty Flag: When asserted, this signal indicates that the
.full(full), // 1-bit output: Full Flag: When asserted, this signal indicates that the
.overflow(), // 1-bit output: Overflow: This signal indicates that a write request
.prog_empty(prog_empty), // 1-bit output: Programmable Empty: This signal is asserted when the
.prog_full(prog_full), // 1-bit output: Programmable Full: This signal is asserted when the
.rd_data_count(rd_data_count), // RD_DATA_COUNT_WIDTH-bit output: Read Data Count: This bus indicates the
.rd_rst_busy(), // 1-bit output: Read Reset Busy: Active-High indicator that the FIFO read
.sbiterr(), // 1-bit output: Single Bit Error: Indicates that the ECC decoder detected
.underflow(), // 1-bit output: Underflow: Indicates that the read request (rd_en) during
.wr_ack(), // 1-bit output: Write Acknowledge: This signal indicates that a write
.wr_data_count(wr_data_count), // WR_DATA_COUNT_WIDTH-bit output: Write Data Count: This bus indicates
.wr_rst_busy(), // 1-bit output: Write Reset Busy: Active-High indicator that the FIFO
.din(wr_data), // WRITE_DATA_WIDTH-bit input: Write Data: The input data bus used when
.injectdbiterr(1'b0), // 1-bit input: Double Bit Error Injection: Injects a double bit error if
.injectsbiterr(1'b0), // 1-bit input: Single Bit Error Injection: Injects a single bit error if
.rd_clk(rd_clk), // 1-bit input: Read clock: Used for read operation. rd_clk must be a free
.rd_en(rd_en), // 1-bit input: Read Enable: If the FIFO is not empty, asserting this
.rst(fifo_rst), // 1-bit input: Reset: Must be synchronous to wr_clk. The clock(s) can be
.sleep(1'b0), // 1-bit input: Dynamic power saving: If sleep is High, the memory/fifo
.wr_clk(wr_clk), // 1-bit input: Write clock: Used for write operation. wr_clk must be a
.wr_en(wr_en) // 1-bit input: Write Enable: If the FIFO is not full, asserting this
);
endmodule
3.新建仿真tb文件对该模块仿真,仿真代码如下所示:
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2023/05/16 14:15:52
// Design Name:
// Module Name: async_fifo_tb
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module async_fifo_tb(
);
reg wr_clk ;//100m
reg rd_clk ;//50m
reg wr_en = 0;
wire [31:0] wr_data ;
reg [15:0] cnt1 = 16'd0;
reg rd_en = 0 ;
wire [15:0] rd_data ;
assign wr_data = {cnt1,cnt1};
initial begin
wr_clk = 1'b0;
rd_clk = 1'b0;
end
always # 10 wr_clk = ~wr_clk ;
always # 5 rd_clk = ~rd_clk ;
always@(posedge wr_clk)begin
if(32'd50<cnt1 & cnt1<32'd550)begin
wr_en <= 1'b1;
end
else begin
wr_en <= 1'b0;
end
end
always@(posedge wr_clk)begin
cnt1 <= cnt1+1'b1;
end
reg [31:0] cnt = 32'd0;
always@(posedge rd_clk)begin
if(32'd500<cnt&cnt<32'd1500)begin
rd_en <= 1'b1;
end
else begin
rd_en <= 1'b0;
end
end
always@(posedge rd_clk)begin
cnt <= cnt+1'b1;
end
async_fifo #(
. FIFO_TYPES (0 ) ,//‘0’fwft,‘1’为标准fifo延迟一个时钟,需要更改模式
. FIFO_WRITE_DEPTH (2048 ) ,//fifo写深度
. READ_DATA_WIDTH (16 ) ,//读数据位宽
. WRITE_DATA_WIDTH (32 ) ,//写数据位宽
. PROG_EMPTY_THRESH (10 ) ,
. PROG_FULL_THRESH (10 ) ,
. WR_WIDTH (12) ,
. RD_WIDTH (12)
)async_fifo_inst
(
.fifo_rst (1'b0) ,
.wr_clk (wr_clk) ,
.wr_en (wr_en) ,
.wr_data (wr_data) ,
.rd_clk (rd_clk) ,
.rd_en (rd_en) ,
.rd_data (rd_data) ,
.wr_data_count () ,
.rd_data_count () ,
.empty () ,
.full () ,
.prog_empty () ,
.prog_full ()
);
endmodule
50M时钟下一次写数据开始第一个:(写入的为32位数据,wrdata = {cnt1,cnt1})
50M时钟下一次写数据的最后一个:
100M时钟下一次读出的数据16位数据开始:
从上可以开出,连续读两个一样的数据,因为写是一次写了两个一样的16bit数据。
100M时钟下一次读出的数据16位数据结束:
由此验证完毕,输入输出异步FIFO没有出错。