FPGA Asynchronous FIFO設計思路異步
將一個多位寬,且在不停變化的數據從一個時鐘域傳遞到另外一個時鐘域是比較困難的。spa
同步FIFO的指針比較好肯定,當FIFO counter達到上限值時候,FIFO爲滿,當FIFO counter爲0時,FIFO爲空。設計
異步FIFO有writer pointer 和 read pointer兩個指針,writer pointer 老是指向下一個要被寫入的位置,read pointer 老是指向下一個將被讀出的數據。沒有必要使用這樣一種機制:接受端的用戶邏輯先給一個時鐘週期到FIFO,使得指針指向將要讀出的數,而後接收端在用一個時鐘週期來鎖存讀出的數據。指針
怎樣斷定FIFO的空滿,當寫指針追上讀指針時候,FIFO爲滿,當讀指針追上寫指針時候,FIFO爲空,既然當FIFO爲空和滿的時候,都是讀指針和寫指針相等,那該怎麼判斷空滿呢,在讀寫指針前面多加一位,當讀寫指針走過FIFO最後一個地址的時,並從頭再來,這個時候最高位進行翻轉,其餘地址位進行清零處理。若是,讀寫指針最高位相同,說明他們翻轉的次數相同,這種狀況只有讀在寫指針的後面,快要空。若是讀寫指針最高位不一樣,說明他們翻轉的次數不一樣,這種只能是寫指針在讀指針的後面,快要滿。code
`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模型,並不能拿來綜合和使用。(待續................)blog