异步FIFO

接着上一个章节,继续介绍FIFO。异步FIFO读/写指针在不同的时钟域产生,如何根据异步指针信号对FIFO的空/满状态进行正确的判断则成为重点。
二进制指针由地址位和状态位组成,地址位随相应的操作递增,指针由内存的以后w位置返回到初始位置时状态位取反。
eg:当读指针从0111到1000变化时,指针的所有位都发生了变换,如果写指针刚好在读指针变换时采样,写得到的读指针有可能是从0000到1111的任意数值。
为了能够在不同时钟域内直接同步指针,可采用格雷码的编码方式,也就是指针每次移动只变化一位,这样就避免额由于指针多位同时变化而无法直接同步的问题。
异步FIFO的FPGA实现,先以在读时钟域下产生状态为例,分为以下几个步骤:
1.将写指针(二进制)转化为格雷码
2.将写指针(格雷码)通过跨时钟转换到读时钟域
3.将写格雷码指针转换为写二进制指针
4.写指针与读指针通过二进制进行比较产生状态
代码如下,写时钟域的状态产生同理而言

// Current read pointer               
always @(posedge clkb or posedge arstb  )
    if (arstb  )
        cur_rptr <= {C_AW+1{1'b0}};
    else
        cur_rptr <= next_rptr;   

// Change binary read pointer to gray code 
generate
//    genvar i;
    for (i=0;i<C_AW+1;i=i+1)
        begin :RBIN2GRAY_GEN
            wire   m;
            assign m = (i == C_AW) ? 1'b0 : cur_rptr[(i+1)%(C_AW+1)]; 
            always @(posedge clkb or posedge arstb  )
                if (arstb  )
                    gray_rptr[i] <= 1'b0;
                else
                    gray_rptr[i] <= cur_rptr[i] ^ m;  
        end
endgenerate              

// Write pointer to Read clock domain
always @(posedge clkb or posedge arstb)        
    if (arstb  )
        begin
            gray_awptr <= {C_AW+1{1'b0}};
            gray_swptr <= {C_AW+1{1'b0}};
        end
    else
        begin
            gray_awptr <= gray_wptr   ;
            gray_swptr <= gray_awptr  ;
        end    

// Convert the Gray pointer to binary                      
generate 
//    genvar i;
    for (i=0;i<C_AW+1;i=i+1)
        begin :WGRAY2BIN_GEN
            always @(posedge clkb or posedge arstb)
                if (arstb  )
                    bin_wptr[i] <= 1'b0;
                else
                    bin_wptr[i] <= ^gray_swptr[C_AW:i];
        end
endgenerate

// empty flag
always @(posedge clkb or posedge arstb)
    if (arstb  )
        rempty  <= 1'b1;
    else      
        rempty  <= (next_rptr == bin_wptr);//(rdiff == 0);

// almost empty flag        
always @(posedge clkb or posedge arstb)
    if (arstb  )         
        arempty <= 1'b1;
    else
        arempty <= (rdiff < (C_HAE + 1));  

always @(posedge clkb or posedge arstb)
    if (arstb  )
        rleft  <= {C_AW+1{1'b0}};
    else
        rleft  <= rdiff       ;       

always @(posedge clkb or posedge arstb)
    if (arstb  )   
        uflw   <= 1'b0;
    else
        uflw   <= rempty & re;      
### 异步FIFO的工作原理 异步FIFO(First In First Out)是一种用于在不同时钟域之间传输数据的缓冲结构。其核心原理是通过两个独立的时钟域分别控制数据的取操作,从而实现数据的异步传输。在异步FIFO中,入操作由时钟控制,而取操作由时钟控制。这种设计允许数据在不同时钟频率相位的情况下进行传输,适用于多时钟域系统中的数据同步问题[^3]。 #### 1. **空满标志的判断** 由于异步FIFO指针指针处于不同的时钟域,直接进行比较会导致跨时钟域的问题。因此,需要对指针指针进行同步处理后再进行比较,以消除亚稳态的影响。通常采用多级寄存器(如两级D触发器)对指针进行同步处理,同时将指针转换为格雷码(Gray Code)以减少同步过程中可能出现的错误[^5]。 #### 2. **指针的表示** 在同步FIFO中,FIFO的空满状态通常通过地址减去地址来判断。然而,在异步FIFO中,由于指针处于不同的时钟域,这种直接相减的方式不再适用。因此,需要采用额外的同步机制来确保指针的比较是可靠的[^2]。 #### 3. **复位机制** 异步FIFO支持在过程中发生复位操作。例如,在过程中发生复位时,数据FIFO满标志位会被清空;在过程中发生复位时,数据FIFO空标志位会被清空。这种机制确保了FIFO在复位后仍能继续正常工作[^1]。 --- ### 异步FIFO的实现方法 #### 1. **Verilog实现** 异步FIFO的实现通常包括以下几个关键模块: - **控制模块**:负责将数据FIFO,并更新指针。 - **控制模块**:负责从FIFO取数据,并更新指针。 - **空满标志生成模块**:通过比较同步后的指针,生成FIFO的空满标志。 - **同步模块**:对指针进行同步处理,以消除跨时钟域的亚稳态问题。 以下是一个简单的异步FIFO的Verilog代码框架: ```verilog module async_fifo #( parameter DATA_WIDTH = 8, parameter ADDR_WIDTH = 4 ) ( input wr_clk, input wr_rst_n, input rd_clk, input rd_rst_n, input wr_en, input [DATA_WIDTH-1:0] din, output reg [DATA_WIDTH-1:0] dout, output full, output empty ); // FIFO存储器 reg [DATA_WIDTH-1:0] fifo_mem [0:(1<<ADDR_WIDTH)-1]; // 指针指针 reg [ADDR_WIDTH:0] wr_ptr; reg [ADDR_WIDTH:0] rd_ptr; // 同步后的指针 wire [ADDR_WIDTH:0] sync_wr_ptr; wire [ADDR_WIDTH:0] sync_rd_ptr; // 同步逻辑 sync_block_wr sync_wr ( .clk(wr_clk), .rst_n(wr_rst_n), .data_in(rd_ptr), .data_out(sync_rd_ptr) ); sync_block_rd sync_rd ( .clk(rd_clk), .rst_n(rd_rst_n), .data_in(wr_ptr), .data_out(sync_wr_ptr) ); // 空满标志生成逻辑 assign full = (wr_ptr == {~sync_rd_ptr[ADDR_WIDTH:ADDR_WIDTH-1], sync_rd_ptr[ADDR_WIDTH-2:0]} && wr_ptr[ADDR_WIDTH] != sync_rd_ptr[ADDR_WIDTH]); assign empty = (wr_ptr == sync_rd_ptr); // 操作 always @(posedge wr_clk or negedge wr_rst_n) begin if (!wr_rst_n) begin wr_ptr <= 0; end else if (wr_en && !full) begin fifo_mem[wr_ptr[ADDR_WIDTH-1:0]] <= din; wr_ptr <= wr_ptr + 1; end end // 操作 always @(posedge rd_clk or negedge rd_rst_n) begin if (!rd_rst_n) begin rd_ptr <= 0; dout <= 0; end else begin if (!empty) begin dout <= fifo_mem[rd_ptr[ADDR_WIDTH-1:0]]; rd_ptr <= rd_ptr + 1; end end end endmodule // 同步模块 module sync_block_wr ( input clk, input rst_n, input [ADDR_WIDTH:0] data_in, output reg [ADDR_WIDTH:0] data_out ); always @(posedge clk or negedge rst_n) begin if (!rst_n) begin data_out <= 0; end else begin data_out <= data_in; end end endmodule ``` #### 2. **同步处理** 为了消除亚稳态,异步FIFO通常采用多级寄存器对跨时钟域信号进行同步处理。例如,在时钟域中对指针进行同步,或在时钟域中对指针进行同步。这种同步机制可以有效减少由于时钟异步导致的不稳定状态。 --- ### 异步FIFO的应用场景 异步FIFO广泛应用于需要在不同时钟域之间传输数据的场景,主要包括以下几个方面: 1. **多时钟域系统**:在现代集成电路设计中,系统通常包含多个时钟域。异步FIFO可以作为不同时钟域之间的数据缓冲,确保数据的可靠传输[^3]。 2. **数据流处理**:在数据流处理系统中,异步FIFO可以用于缓存数据,以应对数据速率不匹配的问题。例如,在高速ADC(模数转换器)低速处理器之间的数据传输中,异步FIFO可以有效缓解数据速率差异[^1]。 3. **通信接口**:在通信系统中,异步FIFO常用于串行通信接口(如UART、SPI等)中,用于缓冲发送接收的数据,避免数据丢失或溢出。 4. **图像处理**:在图像处理系统中,异步FIFO可以用于缓冲图像数据,以应对不同模块之间的处理速度差异。例如,在图像采集图像处理模块之间,异步FIFO可以确保数据的连续传输[^4]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值