一、原理介绍
FIFO即First in, First out。代表着先进的数据先出,后进的数据后出。FIFO实在RAM的基础上增加了许多功能,主要分为读和写两部分。与RAM最大的不同时,FIFO没有地址线,不能够随机的速写数据。这样的好处就是不用频繁的控制地址线。
FIFO典型的结构如下:
虽然看不到地址线,但是在FIFO内部实际是有地址线的。读写过程如下图所示:
向FIFO中写入一个数据,写地址加1。向FIFO中读出一个数据,读地址加1。可以将FIFO想象成一个水池,写数据和读数据分别对应着注水和抽水。当注水速度快时,水池会满。当抽水速度快时,水池会空。
根据读写时钟,可以分为同步FIFO和异步FIFO。同步FIFO,读写使用同一个时钟。异步FIFO,读写使用不同的时钟。
2、FIFO的端口和时序
FIFO常用的端口如图所示:
标准的FIFO写时序如图所示:
可以看出,写数据需要写使能有效,并且FIFO没有写满才能够在写时钟上升沿时候将数据写入。
标准的FIFO读时序如图所示:
可以看出,读数据需要写读能有效,并且FIFO不为空才能够在读时钟上升沿时候将数据读出。注意:当读使能有效时候,需要延后一个时钟周期,才能够将数据读出。而FWFT模式则是使能有效时,有效数据已经在数据线上准备好了,不会再延后一个周期。如下图所示:
二、测试程序
/* 写FIFO状态机 */
localparam W_IDLE = 1 ;
localparam W_FIFO = 2 ;
reg[2:0] write_state;
reg[2:0] next_write_state;
always@(posedge wr_clk or negedge fifo_rst_n)
begin
if(!fifo_rst_n)
write_state <= W_IDLE;
else
write_state <= next_write_state;
end
always@(*)
begin
case(write_state)
W_IDLE:
begin
if(wcnt == 8'd79) //复位后等待一定时间,safety
circuit模式下的最慢时钟60个周期
next_write_state <= W_FIFO;
else
next_write_state <= W_IDLE;
end
W_FIFO:
next_write_state <= W_FIFO; //一直在写FIFO状态
default:
next_write_state <= W_IDLE;
endcase
end
//在IDLE状态下,也就是复位之后,计数器计数
always@(posedge wr_clk or negedge fifo_rst_n)
begin
if(!fifo_rst_n)
wcnt <= 8'd0;
else if (write_state == W_IDLE)
wcnt <= wcnt + 1'b1 ;
else
wcnt <= 8'd0;
end
写使能:
assign wr_en = (write_state == W_FIFO) ? ~full : 1'b0;
/* 读FIFO状态机 */
localparam R_IDLE = 1 ;
localparam R_FIFO = 2 ;
reg[2:0] read_state;
reg[2:0] next_read_state;
///产生FIFO读的数据
always@(posedge rd_clk or negedge fifo_rst_n)
begin
if(!fifo_rst_n)
read_state <= R_IDLE;
else
read_state <= next_read_state;
end
always@(*)
begin
case(read_state)
R_IDLE:
begin
if (rcnt == 8'd59) //复位后等待一定时间,
safety circuit模式下的最慢时钟60个周期
next_read_state <= R_FIFO;
else
next_read_state <= R_IDLE;
end
R_FIFO:
next_read_state <= R_FIFO ; //一直在读FIFO状态
default:
next_read_state <= R_IDLE;
endcase
end
//在IDLE状态下,也就是复位之后,计数器计数
always@(posedge rd_clk or negedge fifo_rst_n)
begin
if(!fifo_rst_n)
rcnt <= 8'd0;
else if (write_state == W_IDLE)
rcnt <= rcnt + 1'b1 ;
else
rcnt <= 8'd0;
end
读使能:
assign rd_en = (read_state == R_FIFO) ? ~empty : 1'b0;
|