异步FIFO原理及使用

可编程逻辑

1364人已加入

描述

可以先配合异步FIFO基础知识食用

fifo

Part.1

第一块Binary Logic:判断二进制Pointer什么时候+1,生成ptr_bin_next信号

assign wptr_bin_next = wptr_bin + (winc & (!wfull));

Part.2

第二块Gray Logic:由Binary Pointer生成Gary Pointer,其实这里根据经典AFIFO论文[1]里应该是用新的wptr_bin_next生成wptr_gray_next,这样wptr_bin和wptr_gray可以同步更新。(这里为了Pass牛客网的测试案例,需要将wptr_bin_next改为 wptr_bin生成,这样格雷码指针会比二进制指针慢一拍)

assign wptr_gray_next = wptr_bin_next ^ (wptr_bin_next >> 1);

新态逻辑写完后赋值给Reg变量

{wptr_bin,wptr_gray} <= {wptr_bin_next, wptr_gray_next};

Part.3

第三块Empty Logic:将wptr_gray在read时钟域打2拍,做空判断

assign rempty =  rptr_gray == wptr_gray_rr2;

Part.4

第四块Full Logic:将rptr_gray在write时钟域打2拍,做满判断

assign wfull = wptr_gray == {~rptr_gray_wr2[ADDR_WIDTH:ADDR_WIDTH-1], rptr_gray_wr2[ADDR_WIDTH-2:0]};

Part.5

第五块Full Logic:例化RAM,addr为ptr_bin次高位到最低位

最后添加一点点细节,形成完整代码

`timescale 1ns/1ns

/***************************************RAM*****************************************/
module dual_port_RAM #(parameter DEPTH = 16,
                       parameter WIDTH = 8)(
     input wclk
    ,input wenc
    ,input [$clog2(DEPTH)-1:0] waddr  //深度对2取对数,得到地址的位宽。
    ,input [WIDTH-1:0] wdata        //数据写入
    ,input rclk
    ,input renc
    ,input [$clog2(DEPTH)-1:0] raddr  //深度对2取对数,得到地址的位宽。
    ,output reg [WIDTH-1:0] rdata       //数据输出
);

reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1];

always @(posedge wclk) begin
    if(wenc)
        RAM_MEM[waddr] <= wdata;
end 

always @(posedge rclk) begin
    if(renc)
        rdata <= RAM_MEM[raddr];
end 

endmodule  

/***************************************AFIFO*****************************************/
module asyn_fifo#(
    parameter   WIDTH = 8,
    parameter   DEPTH = 16
)(
    input                   wclk    , 
    input                   rclk    ,   
    input                   wrstn   ,
    input                   rrstn   ,
    input                   winc    ,
    input                   rinc    ,
    input       [WIDTH-1:0] wdata   ,

    output wire             wfull   ,
    output wire             rempty  ,
    output wire [WIDTH-1:0] rdata
);
    parameter ADDR_WIDTH = $clog2(DEPTH);
/***************************************Bin Logic*****************************************/
    reg [ADDR_WIDTH:0] wptr_bin;
    reg [ADDR_WIDTH:0] rptr_bin;
    wire [ADDR_WIDTH:0] wptr_bin_next;
    wire [ADDR_WIDTH:0] rptr_bin_next;

    assign wptr_bin_next = wptr_bin + (winc & (!wfull));
    assign rptr_bin_next = rptr_bin + (rinc & (!rempty));

/***************************************Gray Logic*****************************************/
    reg [ADDR_WIDTH:0] wptr_gray;
    reg [ADDR_WIDTH:0] rptr_gray;
    wire [ADDR_WIDTH:0] wptr_gray_next;
    wire [ADDR_WIDTH:0] rptr_gray_next;

    assign wptr_gray_next = wptr_bin_next ^ (wptr_bin_next >> 1);
    assign rptr_gray_next = rptr_bin_next ^ (rptr_bin_next >> 1);

    always @ (posedge wclk or negedge wrstn) begin
        if (!wrstn) begin
            {wptr_bin,wptr_gray} <= 'd0;
        end
        else
            {wptr_bin,wptr_gray} <= {wptr_bin_next, wptr_gray_next};
    end

    always @ (posedge rclk or negedge rrstn) begin
        if (!rrstn) begin
            {rptr_bin,rptr_gray} <= 'd0;
        end
        else
            {rptr_bin,rptr_gray} <= {rptr_bin_next, rptr_gray_next};
    end
/***************************************Full Logic*****************************************/
    reg [ADDR_WIDTH:0] rptr_gray_wr,rptr_gray_wr2;

    always @ (posedge wclk or negedge wrstn) begin
        if (!wrstn) begin
            {rptr_gray_wr,rptr_gray_wr2} <= 'd0;
        end
        else
            {rptr_gray_wr2,rptr_gray_wr} <= {rptr_gray_wr,rptr_gray};
    end

    assign wfull = wptr_gray == {~rptr_gray_wr2[ADDR_WIDTH:ADDR_WIDTH-1], rptr_gray_wr2[ADDR_WIDTH-2:0]};
/***************************************Empty Logic*****************************************/
    reg [ADDR_WIDTH:0] wptr_gray_rr,wptr_gray_rr2;

    always @ (posedge rclk or negedge rrstn) begin
        if (!rrstn) begin
            {wptr_gray_rr2,wptr_gray_rr} <= 'd0;
        end
        else
            {wptr_gray_rr2,wptr_gray_rr} <= {wptr_gray_rr,wptr_gray};
    end

    assign rempty =  rptr_gray == wptr_gray_rr2;
/***************************************Dual RAM*****************************************/
    wire wenc, renc;
    wire [ADDR_WIDTH-1:0] raddr, waddr;

    assign wenc = winc & !wfull;
    assign renc = rinc & !rempty;

    assign raddr = rptr_bin[ADDR_WIDTH-1:0];
    assign waddr = wptr_bin[ADDR_WIDTH-1:0];

    dual_port_RAM #(.DEPTH(DEPTH), .WIDTH(WIDTH)) 
                u_dual_port_RAM (
                .wclk(wclk), 
                .rclk(rclk), 
                .wenc(wenc), 
                .renc(renc),
                .raddr(raddr),
                .waddr(waddr),
                .wdata(wdata),
                .rdata(rdata)
                );
/***************************************AFIFO*****************************************/    
endmodule

编辑:黄飞

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分