同步与异步FIFO

FIFO

一、同步FIFO设计

二、异步FIFO设计

        异步FIFO主要用于跨时钟域的多bit数据传输,常常与RAM结合使用,本文的例子中,结合双端口RAM实现了深度为16的8bit数据传输,难点在于各个信号之间的逻辑与模块划分。FIFO产生读写有效使能信号,重点在于空满信号的判断与地址的有效增减。

写FIFO

读FIFO

双口RAM

信号

定义

信号

定义

信号

定义

Input

wr_clk

写时钟

Input

rd_clk

读时钟

Input

wr_clk

写时钟

wr_rstn

写复位

rd_rstn

读复位

rd_clk

读时钟

wr_en

写使能

rd_en

读使能

ram_wen

写使能

rd_wr_gray

读地址格雷码

wr_rd_gray

写地址格雷码

ram_ren

读使能

Output

wr_addr

写地址

Output

rd_addr

读地址

wr_addr

写地址

wr_full

写满信号

rd_empty

读空信号

rd_addr

读地址

ram_wen

RAM写使能

ram_ren

RAM读使能

wr_data_in [DATA_WIDTH-1

: 0]

输入数据

wr_rd_gray

写地址格雷码

rd_wr_gray

读地址格雷码

Output

rd_data_out [DATA_WIDTH-1

: 0]

输出数据

        异步FIFO的空满判断有很多方法,但其中不变的一个点是,利用格雷码减少亚稳态发生的概率,在这个基础上可以得到,将二进制地址转换成格雷码后,满信号基于写时钟域来判断,此时同步过来的读地址信号有一定的延迟,即可能已经读出来三个数据了,但是指针显示只读了一个数据,而写地址指针无延时,造成实际上还没满,但是满信号有效的现象,假满只是导致部分资源的浪费,不会造成逻辑错误,是可以接收的方式;同时,空的判断也是如此,基于读时钟域进行判断,将同步过来的写地址格雷码进行比较,同样会出现假满,但不影响逻辑功能。

        判断空和满时直接根据转成格雷码后的地址指针进行比较,可以发现格雷码与二进制码相比优点是相邻位变换bit为1,且格雷码是镜像对称的,判断为空时即两个格雷码值相等,判断为满时,最高位的格雷码值相反,后位相等。还有的方法有讲格雷码再转成二进制码后再进行比较来得到空满信号,另外,空满信号的判断方法还可以是将格雷码转换为二进制后,设置full_limit和empty_limit,我用的方法中limit的值相当于0。-->(verilog)一步步带你手写异步FIFO - 知乎

二进制码

格雷码

000

000

001

001

010

011

011

010

100

110

101

111

110

101

111

100

Debug总结

    • 信号理解不到位,对各个模块之间相同信号的输入输出关系理解有误,如address信号相较于FIFO读写模块来讲是输出,对RAM来讲是输入信号;
    • FIFO只是产生地址有效增减和空满判断,RAM只要根据地址指针读取对应数据;
    • FIFO深度的计算、FIFO与RAM的区别,异步FIFO对于跨时钟域的贡献;

写FIFO代码

module fifo_wr #(
    parameter    DATA_WIDTH  = 'd8,            // FIFO DATA WIDTH
    parameter   DATA_DEEPTH = 'd16            // FIFO DATA DEEPTH
    )(
    input                             wr_rstn,
    input                             wr_clk,             
    input                             wr_en,                        
    input [$clog2(DATA_DEEPTH):0]    rd_gray,

    output[$clog2(DATA_DEEPTH):0]    wr_rd_gray,            
    output                            wr_full,
    output                            ram_wen,
    output[$clog2(DATA_DEEPTH)-1:0]    wr_addr                
);
    reg [$clog2(DATA_DEEPTH):0]        wr_ptr;
    reg    [$clog2(DATA_DEEPTH):0]        wr_gray;
    reg    [$clog2(DATA_DEEPTH):0]        rd_gray1;
    reg [$clog2(DATA_DEEPTH):0]        rd_gray2;


// read's gray signal CDC
    always @(posedge wr_clk or negedge wr_rstn) begin
        if(~wr_rstn) begin
            rd_gray1 <= 0;
            rd_gray2 <= 0;
        end else begin
            rd_gray1 <= rd_gray;
            rd_gray2 <= rd_gray1;
        end
    end

//binary to gray
    always @(posedge wr_clk or negedge wr_rstn) begin
        if(~wr_rstn) begin
            wr_gray <= 0;
        end else begin
            wr_gray <= wr_ptr ^ (wr_ptr >> 1);
        end
    end

    // generate wr_rd_gray signal
    assign wr_rd_gray = wr_gray;

// generate full signal
    assign wr_full = {~rd_gray2[$clog2(DATA_DEEPTH)],~rd_gray2[$clog2(DATA_DEEPTH)-1],rd_gray2[$clog2(DATA_DEEPTH)-2:0]} == wr_gray ? 1 : 0 ;


// generate ram_in signal
    assign ram_wen = wr_en && (~wr_full);

// refresh write address
    always @(posedge wr_clk or negedge wr_rstn) begin
        if(~wr_rstn) begin
            wr_ptr <= 0; 
        end else if(ram_wen)begin
            wr_ptr <= wr_ptr + 'd1;
        end
    end

    assign wr_addr = wr_ptr[$clog2(DATA_DEEPTH)-1:0];

    

endmodule : fifo_wr

读FIFO

module fifo_rd #(
    parameter    DATA_WIDTH  = 'd8,            // FIFO DATA WIDTH
    parameter   DATA_DEEPTH = 'd16            // FIFO DATA DEEPTH
    )(
    input                             rd_rstn,
    input                             rd_clk,             
    input                             rd_en,                        
    input [$clog2(DATA_DEEPTH):0]    wr_gray,

    output[$clog2(DATA_DEEPTH):0]    rd_wr_gray,            
    output                            rd_empty,
    output                            ram_ren,
    output[$clog2(DATA_DEEPTH)-1:0]    rd_addr
);

    reg [$clog2(DATA_DEEPTH):0]        rd_ptr;
    reg    [$clog2(DATA_DEEPTH):0]        rd_gray;
    reg    [$clog2(DATA_DEEPTH):0]        wr_gray1;
    reg [$clog2(DATA_DEEPTH):0]        wr_gray2;

//    reg [DATA_WIDTH-1:0]            ram_buffer_reg[$clog2(DATA_DEEPTH)-1:0];

// read's gray signal CDC
    always @(posedge rd_clk or negedge rd_rstn) begin
        if(~rd_rstn) begin
            wr_gray1 <= 0;
            wr_gray2 <= 0;
        end else begin
            wr_gray1 <= wr_gray;
            wr_gray2 <= wr_gray1;
        end
    end

//binary to gray
    
    always @(posedge rd_clk or negedge rd_rstn) begin
        if(~rd_rstn) begin
            rd_gray <= 0;
        end else begin
            rd_gray <= rd_ptr ^ (rd_ptr >> 1);
        end
    end
    assign    rd_wr_gray = rd_gray;

// generate wr_rd_gray signal
//    assign  wr_rd_gray = wr_gray;

// generate empty signal
    assign rd_empty = (wr_gray2 == rd_gray) ? 1 : 0;     

// generate ram_ren signal
    assign ram_ren = rd_en && (~rd_empty);

// refresh read address
    always @(posedge rd_clk or negedge rd_rstn) begin
        if(~rd_rstn) begin
            rd_ptr <= 0;
        end 
        else if(ram_ren)begin
            rd_ptr <= rd_ptr + 'd1;
        end
    end

    assign rd_addr = rd_ptr[$clog2(DATA_DEEPTH)-1:0];


endmodule : fifo_rd

顶层模块

module afifo_top#(
    parameter    DATA_WIDTH  = 'd8,            // FIFO DATA WIDTH
    parameter   DATA_DEEPTH = 'd16            // FIFO DATA DEEPTH
    )(
    input                             wr_rstn,        //
    input                             wr_clk,         //    
    input                             wr_en,             //         
    input [DATA_WIDTH-1:0]            wr_data_in,        //1        //
    output[$clog2(DATA_DEEPTH):0]    wr_rd_gray,            
    output                            wr_full,
    output                            ram_wen,
    output[$clog2(DATA_DEEPTH)-1:0]    wr_addr,
    input                             rd_rstn,        //
    input                             rd_clk,         //    
    input                             rd_en,             //         
    output[$clog2(DATA_DEEPTH):0]    rd_wr_gray,            
    output                            rd_empty,
    output                            ram_ren,
    output[DATA_WIDTH-1:0]            rd_data_out,        //2
    output[$clog2(DATA_DEEPTH)-1:0]    rd_addr
);
    
    reg [DATA_WIDTH-1:0]            ram_buffer_reg[DATA_DEEPTH-1:0];
//    reg [DATA_WIDTH-1:0]            ram_buffer_reg2[$clog2(DATA_DEEPTH)-1:0];
    integer i;
    reg [DATA_WIDTH-1:0]            rd_data_out_reg;

    always @(posedge wr_clk or negedge wr_rstn) begin
        if(~wr_rstn) begin
            for(i = 0 ; i < DATA_DEEPTH ; i = i + 1) begin
                ram_buffer_reg[i] <= 0;
            end
        end else if(ram_wen)begin
            ram_buffer_reg[wr_addr] <= wr_data_in;
        end
    end

    always @(posedge rd_clk or negedge rd_rstn) begin
        if(~rd_rstn) begin
            rd_data_out_reg <= 0;
        end else if(ram_ren) begin
            rd_data_out_reg <= ram_buffer_reg[rd_addr];
        end
    end

    assign rd_data_out = rd_data_out_reg;




//example the write module
    fifo_wr #(
        .DATA_WIDTH (DATA_WIDTH ),                // FIFO DATA WIDTH
        .DATA_DEEPTH(DATA_DEEPTH)                // FIFO DATA DEEPTH
    )
    my_fifo_wr(
        .wr_rstn        (wr_rstn    ),
         .wr_clk         (wr_clk     ),
         .wr_en          (wr_en      ),
         .wr_addr        (wr_addr    ),
         .rd_gray        (rd_wr_gray ),
         .wr_rd_gray     (wr_rd_gray ),
         .wr_full        (wr_full    ),
         .ram_wen         (ram_wen    )
        );

//example the read module
    fifo_rd#(
        .DATA_WIDTH (DATA_WIDTH ),                // FIFO DATA WIDTH
        .DATA_DEEPTH(DATA_DEEPTH)                // FIFO DATA DEEPTH
    )
    my_fifo_rd(
        .rd_rstn        (rd_rstn    ),
        .rd_clk         (rd_clk     ),   
        .rd_en          (rd_en      ),     
        .rd_addr        (rd_addr    ),
        .wr_gray        (wr_rd_gray ),
        .rd_wr_gray     (rd_wr_gray ),
        .rd_empty       (rd_empty   ),
        .ram_ren        (ram_ren    )
        );

//example the RAM module
 /*    ram    #(
        .DATA_WIDTH (DATA_WIDTH ),                // FIFO DATA WIDTH
        .DATA_DEEPTH(DATA_DEEPTH)                // FIFO DATA DEEPTH
    )
    my_ram(
        .ram_wclk(wr_clk),
        .ram_rclk(rd_clk),
        .ram_wen(ram_wen),
        .ram_ren(ram_ren),
        .wr_data(wr_data_in),
        .wr_addr(wr_addr),
        .rd_addr(rd_addr),
        .rd_data(rd_data_out)
        );
*/
endmodule : afifo_top

仿真代码

`timescale 1ns/1ns
module afifo_top_tb #(
    parameter    DATA_WIDTH  = 'd8,            // FIFO DATA WIDTH
    parameter   DATA_DEEPTH = 'd16            // FIFO DATA DEEPTH
    )();
    reg                             wr_rstn;        //
    reg                             wr_clk;         //    
    reg                             wr_en;             //         
    reg [DATA_WIDTH-1:0]            wr_data_in;        //1
    wire[$clog2(DATA_DEEPTH)-1:0]    wr_addr;        //
    wire[$clog2(DATA_DEEPTH):0]        wr_rd_gray;            
    wire                            wr_full;
    wire                            ram_wen; 
    reg                             rd_rstn;        //
    reg                             rd_clk;         //    
    reg                             rd_en;             //         
    wire[$clog2(DATA_DEEPTH)-1:0]    rd_addr;
    wire[$clog2(DATA_DEEPTH):0]        rd_wr_gray;            
    wire                            rd_empty;
    wire                            ram_ren;
    wire[DATA_WIDTH-1:0]            rd_data_out;    //2


    always #5     wr_clk = ~wr_clk;
    always #15     rd_clk = ~rd_clk;
    initial begin
         #10      rd_rstn = 0;
                 wr_rstn = 0;
                 wr_clk  = 0;
                 rd_clk  = 0;
                 wr_en   = 0;
                 rd_en   = 0;
         #20     rd_rstn = 1;
                  wr_rstn = 1;
 
         #5      wr_data_in = 8'b1000_0000;
                  wr_en = 1;
         #10     wr_data_in = 8'b1000_0001;
         #10     wr_data_in = 8'b1000_0010;
         #10     wr_data_in = 8'b1000_0011;
         #10     wr_data_in = 8'b1000_0100;
         #10     wr_data_in = 8'b1000_0101;
         #10     wr_data_in = 8'b1000_0110;
         #10     wr_data_in = 8'b1000_0111;
         #10     wr_data_in = 8'b1000_1000;
         #10     wr_data_in = 8'b1000_1001;
         #10     wr_data_in = 8'b1000_1010;
         #10     wr_data_in = 8'b1000_1011;
         #10     wr_data_in = 8'b1000_1100;
         #10     wr_data_in = 8'b1000_1101;
         #10     wr_data_in = 8'b1000_1110;
         #10     wr_data_in = 8'b1000_1111;
         #10         wr_en = 0;
         #10     wr_data_in = 8'b1111_1111;
         #10     rd_en = 1;
         #480     rd_en = 0;
     end


 // example the top module
     afifo_top#(
        .DATA_WIDTH (DATA_WIDTH ),                // FIFO DATA WIDTH
        .DATA_DEEPTH(DATA_DEEPTH)                // FIFO DATA DEEPTH
    )
    my_afifo_top(
    .wr_rstn    (wr_rstn    ),    
    .wr_clk        (wr_clk        ),    
    .wr_en        (wr_en        ),     
    .wr_addr    (wr_addr    ),
    .wr_data_in (wr_data_in ),    
    .wr_rd_gray    (wr_rd_gray    ),
    .wr_full    (wr_full    ),
    .ram_wen    (ram_wen    ),
    .rd_rstn    (rd_rstn    ),    
    .rd_clk        (rd_clk        ),     
    .rd_en        (rd_en        ),             
    .rd_addr    (rd_addr    ),
    .rd_wr_gray    (rd_wr_gray    ),    
    .rd_empty    (rd_empty    ),
    .ram_ren    (ram_ren    ),
    .rd_data_out(rd_data_out)    
    );

endmodule : afifo_top_tb

仿真波形图

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值