异步FIFO(格雷码实现)
一、FIFIO简介
FIFO是一种现先进先出的数据缓冲器,特点是没有外部的读写地址。由于没有外部的地址信号,所以只能顺序的读写,而不能跳读。FIFO的读写是根据满和空信号设计写使能和读使能来写/读FIFO,当FIFO满的时候不可以往里面写、当FIFO空的时候不能读数据。读FIFO时,内部的读指针自动的加一,当写FIFO时写指针自动的加一。
二、异步FIFO的用途
1、使用异步FIFO可以在两个不同的时钟域之间快速而方便的传输数据,起到跨时钟域处理的作用。经常用于处理跨时钟域的问题。
2、对于不同宽度的数据接口也可以采用FIFO进行缓冲,如8位输入,16位输出。(注:本文只简介输入输出位宽相同的情况)
三、FIFO的常见参数
wfull: 满标志, 表示FIFO已经满,不能再写入数据。
rempty:空标志,表示FIFO已经空,不能再读取数据。
wclk: 写时钟
rclk: 读时钟
winc: 写使能
rinc: 读使能
wdata:写数据
rdata: 读数据
wrst_n: 写复位
rrst_n:读复位
四、FIFO满空标志的产生
FIFO设计的关键是如何产生可靠的读写指针和满空信号。
判空:读指针追上写指针的时候,两者相等,为空。
判空和使用二进制一样,只需判断读写指针是否完全相同即可。
判满:写指针追上读指针的时候,两者相等,为满。
图中使用格雷码,最高位是辅助判断是否空满(实际深度为8)。如:当写指针为1000,读指针为0100,则写指针超过读指针一圈,写满状态。因此判断其是否写满,需判断高两位是否相反,剩下的是否相同。
五、异步FIFO的模块图
六、异步FIFO实现代码
module afifo
#(
parameter WSIZE = 8,
parameter DSIZE = 16
)
(
input [WSIZE - 1:0]wdata,
input wclk,
input winc,
input wrst_n,
input rclk,
input rinc,
input rrst_n,
output wfull,
output rempty,
output [WSIZE - 1:0]data
);
reg [WSIZE - 1:0] mem [0:DSIZE - 1];
wire [3:0] waddr;
wire [3:0] raddr;
reg [4:0] wptr;
reg [4:0] rptr;
reg rempty_val;
reg wfull_val;
assign data = mem [raddr];
always @(posedge wclk) begin
if(winc && !wfull)begin
mem[waddr] <= wdata;
end
end
reg [4:0]wbin;
always @(posedge wclk or negedge wrst_n) begin
if(!wrst_n)begin
wbin <= 5'b0;
end
else if(winc && !wfull) begin
wbin <= wbin + 1'b1;
end
end
assign waddr = wbin[3:0];
reg [4:0]wgray;
always @(posedge wclk or negedge wrst_n) begin
if (!wrst_n) begin
wgray <= 5'b0;
end
else begin
wgray <= (wbin >> 1) ^ wbin;
end
end
always @(posedge wclk or negedge wrst_n) begin
if (!wrst_n) begin
wptr <= 5'b0;
end
else begin
wptr <= wgray;
end
end
reg [4:0]wptr_1;
reg [4:0]wptr_2;
always @(posedge wclk or negedge wrst_n) begin
if(!wrst_n)begin
{wptr_2 , wptr_1} <= 10'd0;
end
else begin
{wptr_2 , wptr_1} <= {wptr_1 , rptr};
end
end
assign wfull = {~wptr_2[4:3],wptr_2[2:0]} == wgray;
reg [4:0]rbin;
always @(posedge rclk or negedge rrst_n) begin
if (!rrst_n) begin
rbin <= 5'b0;
end
else if(rinc && !rempty) begin
rbin <= rbin + 1'b1;
end
end
assign raddr = rbin[3:0];
reg [4:0]rgray;
always @(posedge rclk or negedge rrst_n) begin
if(!rrst_n)begin
rgray <= 5'b0;
end
else begin
rgray <= (rbin >> 1) ^ rbin;
end
end
always @(posedge rclk or negedge rrst_n) begin
if(!rrst_n)begin
rptr <= 5'b0;
end
else begin
rptr <= rgray;
end
end
reg [4:0]rptr_1;
reg [4:0]rptr_2;
always @(posedge rclk or negedge rrst_n) begin
if(!rrst_n)begin
{rptr_2 , rptr_1} <= 10'd0;
end
else begin
{rptr_2 , rptr_1} <= {rptr_1 , wptr};
end
end
assign rempty = rptr_2 == rgray;
endmodule
tb文件
`timescale 1ns / 1ps
module tb_afifo(
);
reg wclk;
reg [7:0]wdata;
reg winc;
reg wrst_n;
reg rclk;
reg rrst_n;
reg rinc;
wire wfull;
wire rempty;
wire [7:0]data;
integer i = 0;
localparam CYCLE = 20;
localparam CYCLE1 = 40;
initial begin
wclk = 0;
forever
#(CYCLE/2)
wclk = ~wclk;
end
initial begin
rclk = 0;
forever
#(CYCLE1/2)
rclk = ~rclk;
end
initial begin
wrst_n = 1;
#2;
wrst_n = 0;
#(CYCLE*3);
wrst_n = 1;
end
initial begin
rrst_n = 1;
#2
rrst_n = 0;
#(CYCLE*3);
rrst_n = 1;
end
always@(posedge wclk or negedge wrst_n)begin
if(!wrst_n)begin
i <= 0;
end
else if(!wfull)begin
i <= i+1;
end
else begin
i <= i;
end
end
afifo u_afifo(
.wclk (wclk),
.wdata (wdata),
.winc (winc),
.wrst_n (wrst_n),
.rclk (rclk),
.rrst_n (rrst_n),
.rinc (rinc),
.wfull (wfull),
.rempty (rempty),
.data (data)
);
always @(posedge wclk or negedge wrst_n)begin
if(wrst_n==1'b0)begin
i <= 0;
end
else if(!wfull)begin
i = i+1;
end
else begin
i <= i;
end
end
always @(rempty or rrst_n)begin
if(rrst_n==1'b0)begin
rinc = 1'b0;
end
else if(!rempty)begin
rinc = 1'b1;
end
else
rinc = 1'b0;
end
always@(wfull or wrst_n)begin
if(wrst_n)
winc = 1'b0;
else if(!wfull)
winc = 1'b1;
else
winc = 1'b0;
end
always@(*)begin
if(!wfull)
wdata= i;
else
wdata = 0;
end
endmodule
七、异步FIFO仿真效果
参考文献:
C.E. Cummings, Simulation and Synthesis Techniques for Asynchronous FIFO Design, SNUG 2002 .User Papers, 2002.