WeiLin

Logo

End of Best.

View My GitHub

> Home
> Back

vlog_day20:异步FIFO

by WeiLin

推荐2个讲解异步FIFO不错的博客: 地址1, 地址2

1.关于写满读空怎么判断:当什么都不写时rd_ptr==wr_ptr,当写满时rd_ptr也等于wr_ptr,所以有两个解决办法:

2.关于格雷码同步:将写时钟域的写指针同步到读时钟域,将同步后的写指针与读时钟域的读指针进行比较产生读空信号;将读时钟域的读指针同步到写时钟域,将同步后的读指针与写时钟域的写指针进行比较产生写满信号;而同步后的读指针或写指针会延时两个时钟,所以会造成假满和假空的状态,这会导致满空趋于保守,但是保守并不等于错误。

3.二进制码转换成二进制格雷码:其法则是保留二进制码的最高位作为格雷码的最高位,而次高位格雷码为二进制码的高位与次高位相异或,而格雷码其余各位与次高位的求法相类似。这样就可以实现二进制到格雷码的转换了,总结就是移位并且异或,verilog代码实现就一句: assign graydata = (bindata » 1) ^ bindata;

4.FIFO深度:通过读写频率,突发速率,突发长度进而确定FIFO的最小深度。要理解“背靠背“突发。可以参看这篇博客.

//异步FIFO
module asunc_fifo#(
    parameter FIFO_DEATH=16,
    parameter FIFO_WIDTH=8
)(
    input clk1,//写时钟
    input rst1,
    input we,//写使能
    input [FIFO_WIDTH-1:0]din,

    input clk2,//读时钟
    input rst2,
    input re,//读使能
    output reg [FIFO_WIDTH-1:0]dout,

    output full,
    output empty
);

localparam ADDR_WIDTH=$clog2(FIFO_DEATH);

reg [FIFO_WIDTH-1:0] RAM [FIFO_DEATH-1:0];

reg [ADDR_WIDTH:0] w_ptr;//需要多1位
always@(posedge clk1 or posedge rst1)begin
    if(rst1)
        w_ptr<=0;
    else begin
        if(we && !full)begin
            RAM[w_ptr]<=din;
            w_ptr<=w_ptr+1;
        end
        else
            w_ptr<=w_ptr;
    end
end

reg [ADDR_WIDTH:0] r_ptr;//需要多1位
always@(posedge clk2 or posedge rst2)begin
    if(rst2)
        r_ptr<=0;
    else begin
        if(re && !empty)begin
            dout<=RAM[r_ptr];
            r_ptr<=r_ptr+1;
        end
        else
            r_ptr<=r_ptr;
    end
end
////////指针同步/////////
reg [ADDR_WIDTH:0] w_ptr_g;//gray写指针
bin2gray #(ADDR_WIDTH+1) bg1(w_ptr,w_ptr_g);

reg [ADDR_WIDTH:0] w_ptr_g1;//两级同步器中间值
reg [ADDR_WIDTH:0] w_ptr_s;//同步后的写指针
always@(posedge clk1 or posedge rst1)begin
    if(rst1)begin
        w_ptr_g1<=0;
        w_ptr_s<=0;
    end 
    else begin
        w_ptr_g1<=w_ptr_g;
        w_ptr_s<=w_ptr_g1;
    end
end


reg [ADDR_WIDTH:0] r_ptr_g;//gray读指针
bin2gray #(ADDR_WIDTH+1) bg2(r_ptr,r_ptr_g);

reg [ADDR_WIDTH:0] r_ptr_g1;//两级同步器中间值
reg [ADDR_WIDTH:0] r_ptr_s;//同步后的读指针
always@(posedge clk2 or posedge rst2)begin
    if(rst1)begin
        r_ptr_g1<=0;
        r_ptr_s<=0;
    end 
    else begin
        r_ptr_g1<=r_ptr_g;
        r_ptr_s<=r_ptr_g1;
    end
end
////////空满判断////////
assign full=((!w_ptr_g[ADDR_WIDTH-:2]==r_ptr_s[ADDR_WIDTH-:2])&&(w_ptr_g[ADDR_WIDTH-2:0]==r_ptr_s[ADDR_WIDTH-2:0]))?1:0;
assign empty=(r_ptr_g==w_ptr_s)?1:0;

endmodule
tags: verilog