近来在学习Xlinx的FIFO IP核,根据自己学习中遇到的一些问题以及解决的办法总结了自己学到的一些知识,作为自己的学习笔记,当然也作为一些初学者查阅的笔记。
FIFO无非就是一个输入输出的中间存储,一般用于不同时钟域之间的数据传输,下面主要介绍一下他的各个参数的作用以及设置。
prog_full:写FIFO将要满的时候,这个数值与你设置的数据相关,达到你设置的数据和以上时,此信号就会被拉高;
prog_empty:读FIFO将要空的时候,这个数值与你设置的数据相关,达到你设置的数据和以下时,此信号就会被拉高;
这两个信号是在status flag – programmable flag里面设置,如下图:
Rst:复位信号
wr_clk:写时钟
rd_clk:读时钟
din:输入的数据
wr_en:写使能
rd_en:读使能
dout:输出的数据
full:写入全满时的信号;
wr_rst_busy:写准备完成的标志,准备完成才能开写,也就是位0才能写入;
rd_rst_busy:读准备完成的标志,准备完成才能开读,也就是位0才能读取;
almost_full:写入全满前一个的信号,高有效,如果为高电平,在写一个数据FIFO将全满;
almost_empty:读出全空前一个的信号,高有效,如果为高电平,在读一个数据FIFO将全空;
wr_ack:写确认,表示前一个的写请求得到处理成功;
overflow:上溢标志,可选,表示前一个写的请求没有完成,因为已经写满,在写完之后会出现;
valid:有效的,可选,表示在输出总线DOUT上面有可用的数据;
underflow:下溢标志,可选,表示前一个读的请求没有完成,因为已经读空,在读完之后会出现;
empty:FIFO全空时的信号;
rd_data_count:计数器,表示FIFO里面有多少数据可以读;
wr_data_count:计数器,表示FIFO里面已经写多少数据;
测试代码tb如下:
`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;
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 wr_rst_busy;
wire rd_rst_busy;
wire prog_full; // output wire prog_full
wire prog_empty; // output wire prog_empty
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;
#(`WR_CLK_PERIOD*8+1);
rst = 1'b0;
@(negedge wr_rst_busy);
//write data
while(full == 1'b0)
begin
@(posedge wr_clk);
#1;
wr_en = 1'b1;
din = din + 1'b1;
end
//多写一个数据,看overflow的变化
din = 8'hff;
@(posedge wr_clk);
wr_en = 1'b0;
wait(rd_rst_busy == 1'b0);
#2000;
while(empty == 1'b0)
begin
@(posedge rd_clk);
#1;
rd_en = 1'b1;
end
//多给一个读使能,看underflow的变化
@(posedge rd_clk);
rd_en = 1'b0;
#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
fifo_generator_0 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
.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
.wr_rst_busy(wr_rst_busy), // output wire wr_rst_busy
.rd_rst_busy(rd_rst_busy), // output wire rd_rst_busy
.prog_full(prog_full), // output wire prog_full
.prog_empty(prog_empty) // output wire prog_empty
);
endmodule
时序的分析我就不分析了,大家可以结合test_bench波形自己分析:
整体波形如下:
写入的波形放大:
读出的波形放大: