FPGA Asynchronous FIFO设计思路
将一个多位宽,且在不停变化的数据从一个时钟域传递到另一个时钟域是比较困难的。
同步FIFO的指针比较好确定,当FIFO counter达到上限值时候,FIFO为满,当FIFO counter为0时,FIFO为空。
异步FIFO有writer pointer 和 read pointer两个指针,writer pointer 总是指向下一个要被写入的位置,read pointer 总是指向下一个将被读出的数据。没有必要使用这样一种机制:接受端的用户逻辑先给一个时钟周期到FIFO,使得指针指向将要读出的数,然后接收端在用一个时钟周期来锁存读出的数据。
怎样判定FIFO的空满,当写指针追上读指针时候,FIFO为满,当读指针追上写指针时候,FIFO为空,既然当FIFO为空和满的时候,都是读指针和写指针相等,那该怎么判断空满呢,在读写指针前面多加一位,当读写指针走过FIFO最后一个地址的时,并从头再来,这个时候最高位进行翻转,其他地址位进行清零处理。如果,读写指针最高位相同,说明他们翻转的次数相同,这种情况只有读在写指针的后面,快要空。如果读写指针最高位不同,说明他们翻转的次数不同,这种只能是写指针在读指针的后面,快要满。
`timescale 1ns / 1ps ////////////////////////////////////////////////////////////////////////////////// // Company: // Engineer: chensimin // // Create Date: 2018/10/24 17:31:22 // Design Name: // Module Name: beh_fifo // Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // ////////////////////////////////////////////////////////////////////////////////// module beh_fifo #( parameter ASIZE = 4, parameter DSIZE = 8 ) ( input wire wclk, input wire wrst_n, input wire winc, input wire [DSIZE-1 : 0] wdata, output wire wfull, output wire rempty, input wire rclk, input wire rrst_n, input wire rinc, output wire [DSIZE-1 : 0] rdata ); //-------------------------------------------------------------- //写一个数据,指针加一 parameter MEMDEPTH = 1 << ASIZE; reg [ASIZE : 0] wptr; reg [DSIZE-1 : 0] ex_mem [0 : MEMDEPTH-1]; always @(posedge wclk or negedge wrst_n) begin if(!wrst_n) wptr <= 0; else if(winc && !wfull) begin ex_mem[wptr[ASIZE-1 : 0]] <= wdata; wptr <= wptr + 1; end end //-------------------------------------------------------------- //将rptr读指针,同步到wclk时钟域,打了三拍 reg [ASIZE : 0] wrptr3; reg [ASIZE : 0] wrptr2; reg [ASIZE : 0] wrptr1; always @(posedge wclk or negedge wrst_n) begin if(!wrst_n) {wrptr3, wrptr2, wrptr1} <= 0; else {wrptr3, wrptr2, wrptr1} <= {wrptr2, wrptr1, rptr}; end //-------------------------------------------------------------- //读指针加一 reg [ASIZE : 0] rptr; always @(posedge rclk or negedge rrst_n) begin if(!rrst_n) rptr <= 0; else if(rinc && !rempty) rptr <= rptr + 1; end //-------------------------------------------------------------- //将写指针同步到读指针时钟域 reg [ASIZE : 0] rwptr3; reg [ASIZE : 0] rwptr2; reg [ASIZE : 0] rwptr1; always @(posedge rclk or negedge rrst_n) begin if(!rrst_n) {rwptr3, rwptr2, rwptr1} <= 0; else {rwptr3, rwptr2, rwptr1} <= {rwptr2, rwptr1, wptr}; end //-------------------------------------------------------------- assign rdata = ex_mem[rptr[ASIZE-1 : 0]]; assign rempty = (rptr == rwptr3); assign wfull = (( wptr[ASIZE-1:0] == wrptr3[ASIZE-1:0] ) && ( wptr[ASIZE] != wrptr3[ASIZE] )); endmodule
以上只是一个很粗糙的FIFO模型,并不能拿来综合和使用。(待续................)