一、FIFO簡介
FIFO是英文First In First Out 的縮寫,是一種先進(jìn)先出的數(shù)據(jù)緩存器,它與普通存儲器的區(qū)別是沒有外部讀寫地址線,這樣使用起來非常簡單,但缺點(diǎn)就是只能順序?qū)懭霐?shù)據(jù),順序的讀出數(shù)據(jù),其數(shù)據(jù)地址由內(nèi)部讀寫指針自動(dòng)加1完成,不能像普通存儲器那樣可以由地址線決定讀取或?qū)懭肽硞€(gè)指定的地址。
用途1:
異步FIFO讀寫分別采用相互異步的不同時(shí)鐘。在現(xiàn)代集成電路芯片中,隨著設(shè)計(jì)規(guī)模的不斷擴(kuò)大,一個(gè)系統(tǒng)中往往含有數(shù)個(gè)時(shí)鐘,多時(shí)鐘域帶來的一個(gè)問題就是,如何設(shè)計(jì)異步時(shí)鐘之間的接口電路。異步FIFO是這個(gè)問題的一種簡便、快捷的解決方案,使用異步FIFO可以在兩個(gè)不同時(shí)鐘系統(tǒng)之間快速而方便地傳輸實(shí)時(shí)數(shù)據(jù)。
用途2:
對于不同寬度的數(shù)據(jù)接口也可以用FIFO,例如單片機(jī)位8位數(shù)據(jù)輸出,而DSP可能是16位數(shù)據(jù)輸入,在單片機(jī)與DSP連接時(shí)就可以使用FIFO來達(dá)到數(shù)據(jù)匹配的目的。
二、分類
同步FIFO是指讀時(shí)鐘和寫時(shí)鐘為同一個(gè)時(shí)鐘,在時(shí)鐘沿來臨時(shí)同時(shí)發(fā)生讀寫操作;
異步FIFO是指讀寫時(shí)鐘不一致,讀寫時(shí)鐘是互相獨(dú)立的。
三、FIFO的常見參數(shù)
FIFO的寬度:即FIFO一次讀寫操作的數(shù)據(jù)位;
FIFO的深度:指的是FIFO可以存儲多少個(gè)N位的數(shù)據(jù)(如果寬度為N)。
滿標(biāo)志:FIFO已滿或?qū)⒁獫M時(shí)由FIFO的狀態(tài)電路送出的一個(gè)信號,以阻止FIFO的寫操作繼續(xù)向FIFO中寫數(shù)據(jù)而造成溢出(overflow)。
空標(biāo)志:FIFO已空或?qū)⒁諘r(shí)由FIFO的狀態(tài)電路送出的一個(gè)信號,以阻止FIFO的讀操作繼續(xù)從FIFO中讀出數(shù)據(jù)而造成無效數(shù)據(jù)的讀出(underflow)。
讀時(shí)鐘:讀操作所遵循的時(shí)鐘,在每個(gè)時(shí)鐘沿來臨時(shí)讀數(shù)據(jù)。
寫時(shí)鐘:寫操作所遵循的時(shí)鐘,在每個(gè)時(shí)鐘沿來臨時(shí)寫數(shù)據(jù)。
===============================分 隔 符 ==============================
讀寫指針的工作原理
讀指針:總是指向下一個(gè)將要被寫入的單元,復(fù)位時(shí),指向第1個(gè)單元(編號為0)。
寫指針:總是指向當(dāng)前要被讀出的數(shù)據(jù),復(fù)位時(shí),指向第1個(gè)單元(編號為0)
FIFO的“空”/“滿”檢測
FIFO設(shè)計(jì)的關(guān)鍵:產(chǎn)生可靠的FIFO讀寫指針和生成FIFO“空”/“滿”狀態(tài)標(biāo)志。
當(dāng)讀寫指針相等時(shí),表明FIFO為空,這種情況發(fā)生在復(fù)位操作時(shí),或者當(dāng)讀指針讀出FIFO中最后一個(gè)字后,追趕上了寫指針時(shí),如下圖所示:

當(dāng)讀寫指針再次相等時(shí),表明FIFO為滿,這種情況發(fā)生在,當(dāng)寫指針轉(zhuǎn)了一圈,折回來(wrapped around)又追上了讀指針,如下圖:

為了區(qū)分到底是滿狀態(tài)還是空狀態(tài),可以采用以下方法:
方法1:在指針中添加一個(gè)額外的位(extra bit),當(dāng)寫指針增加并越過最后一個(gè)FIFO地址時(shí),就將寫指針這個(gè)未用的MSB加1,其它位回零。對讀指針也進(jìn)行同樣的操作。此時(shí),對于深度為2n的FIFO,需要的讀/寫指針位寬為(n+1)位,如對于深度為8的FIFO,需要采用4bit的計(jì)數(shù)器,0000~1000、1001~1111,MSB作為折回標(biāo)志位,而低3位作為地址指針。
如果兩個(gè)指針的MSB不同,說明寫指針比讀指針多折回了一次;如r_addr=0000,而w_addr = 1000,為滿。
如果兩個(gè)指針的MSB相同,則說明兩個(gè)指針折回的次數(shù)相等。其余位相等,說明FIFO為空;
3.二進(jìn)制FIFO指針的考慮
將一個(gè)二進(jìn)制的計(jì)數(shù)值從一個(gè)時(shí)鐘域同步到另一個(gè)時(shí)鐘域的時(shí)候很容易出現(xiàn)問題,因?yàn)椴捎枚M(jìn)制計(jì)數(shù)器時(shí)所有位都可能同時(shí)變化,在同一個(gè)時(shí)鐘沿同步多個(gè)信號的變化會產(chǎn)生亞穩(wěn)態(tài)問題。而使用格雷碼只有一位變化,因此在兩個(gè)時(shí)鐘域間同步多個(gè)位不會產(chǎn)生問題。所以需要一個(gè)二進(jìn)制到gray碼的轉(zhuǎn)換電路,將地址值轉(zhuǎn)換為相應(yīng)的gray碼,然后將該gray碼同步到另一個(gè)時(shí)鐘域進(jìn)行對比,作為空滿狀態(tài)的檢測。

4.
使用gray碼進(jìn)行對比,如何判斷“空”與“滿”
使用gray碼解決了一個(gè)問題,但同時(shí)也帶來另一個(gè)問題,即在格雷碼域如何判斷空與滿。
對于“空”的判斷依然依據(jù)二者完全相等(包括MSB);
而對于“滿”的判斷,如下圖,由于gray碼除了MSB外,具有鏡像對稱的特點(diǎn),當(dāng)讀指針指向7,寫指針指向8時(shí),除了MSB,其余位皆相同,不能說它為滿。因此不能單純的只檢測最高位了,在gray碼上判斷為滿必須同時(shí)滿足以下3條:
wptr和同步過來的rptr的MSB不相等,因?yàn)閣ptr必須比rptr多折回一次。
wptr與rptr的次高位不相等,如上圖位置7和位置15,轉(zhuǎn)化為二進(jìn)制對應(yīng)的是0111和1111,MSB不同說明多折回一次,111相同代表同一位置。
剩下的其余位完全相等。

5.總體實(shí)現(xiàn)
系統(tǒng)的總體框圖如下:

1)頂層模塊
moduleAsyncFIFO
#(parameter ASIZE = 4, //地址位寬 parameter DSIZE = 8) //數(shù)據(jù)位寬 ( input [DSIZE-1:0] wdata, input winc, wclk, wrst_n, //寫請求信號,寫時(shí)鐘,寫復(fù)位 input rinc, rclk, rrst_n, //讀請求信號,讀時(shí)鐘,讀復(fù)位 output [DSIZE-1:0] rdata, output wfull, output rempty ); wire [ASIZE-1:0] waddr, raddr; wire [ASIZE:0] wptr, rptr, wq2_rptr, rq2_wptr; /************************************************************ * In order to perform FIFO full and FIFO empty tests using * this FIFO style, the read and write pointers must be * passed to the opposite clock domain for pointer comparison *************************************************************/ /*在檢測“滿”或“空”狀態(tài)之前,需要將指針同步到其它時(shí)鐘域時(shí),使用格雷碼,可以降低同步過程中亞穩(wěn)態(tài)出現(xiàn)的概率*/ sync_r2w I1_sync_r2w( .wq2_rptr(wq2_rptr), .rptr(rptr), .wclk(wclk), .wrst_n(wrst_n)); sync_w2r I2_sync_w2r ( .rq2_wptr(rq2_wptr), .wptr(wptr), .rclk(rclk), .rrst_n(rrst_n)); /* * DualRAM */ DualRAM #(DSIZE, ASIZE) I3_DualRAM( .rdata(rdata), .wdata(wdata), .waddr(waddr), .raddr(raddr), .wclken(winc), .wclk(wclk)); /* * 空、滿比較邏輯 */ rptr_empty #(ASIZE) I4_rptr_empty( .rempty(rempty), .raddr(raddr), .rptr(rptr), .rq2_wptr(rq2_wptr), .rinc(rinc), .rclk(rclk), .rrst_n(rrst_n)); wptr_full #(ASIZE) I5_wptr_full( .wfull(wfull), .waddr(waddr), .wptr(wptr), .wq2_rptr(wq2_rptr), .winc(winc), .wclk(wclk), .wrst_n(wrst_n)); endmodule
2)DualRAM模塊
module DualRAM #( parameter DATA_SIZE = 8, // 數(shù)據(jù)位寬 parameter ADDR_SIZE = 4 // 地址位寬 ) ( input wclken,wclk, input [ADDR_SIZE-1:0] raddr, //RAM read address input [ADDR_SIZE-1:0] waddr, //RAM write address input [DATA_SIZE-1:0] wdata, //data input output [DATA_SIZE-1:0] rdata //data output ); localparam RAM_DEPTH = 1 << ADDR_SIZE; //RAM深度 = 2^ADDR_WIDTH reg [DATA_SIZE-1:0] Mem[RAM_DEPTH-1:0]; always@(posedge wclk) begin if(wclken) Mem[waddr] <= wdata; end assign rdata = Mem[raddr]; endmodule
3)同步模塊
module sync_r2w #(parameter ADDRSIZE = 4) ( output reg [ADDRSIZE:0] wq2_rptr, input [ADDRSIZE:0] rptr, input wclk, wrst_n ); reg [ADDRSIZE:0] wq1_rptr; always @(posedge wclk or negedge wrst_n) if (!wrst_n) {wq2_rptr,wq1_rptr} <= 0; else {wq2_rptr,wq1_rptr} <= {wq1_rptr,rptr}; endmodule
4)同步模塊2
module sync_w2r #(parameter ADDRSIZE = 4) ( output reg [ADDRSIZE:0] rq2_wptr, input [ADDRSIZE:0] wptr, input rclk, rrst_n ); reg [ADDRSIZE:0] rq1_wptr; always @(posedge rclk or negedge rrst_n) if (!rrst_n) {rq2_wptr,rq1_wptr} <= 0; else {rq2_wptr,rq1_wptr} <= {rq1_wptr,wptr}; endmodule
5)空判斷邏輯
module rptr_empty #(parameter ADDRSIZE = 4) ( output reg rempty, output [ADDRSIZE-1:0] raddr, output reg [ADDRSIZE :0] rptr, input [ADDRSIZE :0] rq2_wptr, input rinc, rclk, rrst_n); reg [ADDRSIZE:0] rbin; wire [ADDRSIZE:0] rgraynext, rbinnext; wire rempty_val; //------------------- // GRAYSTYLE2 pointer: gray碼讀地址指針 //------------------- always @(posedge rclk or negedge rrst_n) if (!rrst_n) begin rbin <= 0; rptr <= 0; end else begin rbin <= rbinnext ; rptr <= rgraynext; end // gray碼計(jì)數(shù)邏輯 assign rbinnext = !rempty ? (rbin + rinc) : rbin; assign rgraynext = (rbinnext>>1) ^ rbinnext; //二進(jìn)制到gray碼的轉(zhuǎn)換 assign raddr = rbin[ADDRSIZE-1:0]; //--------------------------------------------------------------- // FIFO empty when the next rptr == synchronized wptr or on reset //--------------------------------------------------------------- /* * 讀指針是一個(gè)n位的gray碼計(jì)數(shù)器,比FIFO尋址所需的位寬大一位 * 當(dāng)讀指針和同步過來的寫指針完全相等時(shí)(包括MSB),說明二者折回次數(shù)一致,FIFO為空 * */ assign rempty_val = (rgraynext == rq2_wptr); always @(posedge rclk or negedge rrst_n) if (!rrst_n) rempty <= 1'b1; else rempty <= rempty_val; endmodule
6)滿判斷邏輯
module wptr_full #( parameter ADDRSIZE = 4 ) ( output reg wfull, output [ADDRSIZE-1:0] waddr, output reg [ADDRSIZE :0] wptr, input [ADDRSIZE :0] wq2_rptr, input winc, wclk, wrst_n); reg [ADDRSIZE:0] wbin; wire [ADDRSIZE:0] wgraynext, wbinnext; wire wfull_val; // GRAYSTYLE2 pointer always @(posedge wclk or negedge wrst_n) if (!wrst_n) begin wbin <= 0; wptr <= 0; end else begin wbin <= wbinnext; wptr <= wgraynext; end //gray 碼計(jì)數(shù)邏輯 assign wbinnext = !wfull ? wbin + winc : wbin; assign wgraynext = (wbinnext>>1) ^ wbinnext; assign waddr = wbin[ADDRSIZE-1:0]; /*由于滿標(biāo)志在寫時(shí)鐘域產(chǎn)生,因此比較安全的做法是將讀指針同步到寫時(shí)鐘域*/ /**/ //------------------------------------------------------------------ // Simplified version of the three necessary full-tests: // assign wfull_val=((wgnext[ADDRSIZE] !=wq2_rptr[ADDRSIZE] ) && // (wgnext[ADDRSIZE-1] !=wq2_rptr[ADDRSIZE-1]) && // (wgnext[ADDRSIZE-2:0]==wq2_rptr[ADDRSIZE-2:0])); //------------------------------------------------------------------ assign wfull_val = (wgraynext=={~wq2_rptr[ADDRSIZE:ADDRSIZE-1], wq2_rptr[ADDRSIZE-2:0]}); always @(posedge wclk or negedge wrst_n) if (!wrst_n) wfull <= 1'b0; else wfull <= wfull_val; endmodule
P.S : 在quartus中有異步FIFO IP核,為安全起見推薦使用IP核定制FIFO,本文的目的只是作為思路參考。
審核編輯:郭婷
-
芯片
+關(guān)注
關(guān)注
463文章
54010瀏覽量
466089 -
存儲器
+關(guān)注
關(guān)注
39文章
7739瀏覽量
171676 -
fifo
+關(guān)注
關(guān)注
3文章
407瀏覽量
45748
原文標(biāo)題:異步FIFO的FPGA實(shí)現(xiàn)
文章出處:【微信號:zhuyandz,微信公眾號:FPGA之家】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
探索LMK1C110xA系列:高性能低噪聲異步LVCMOS時(shí)鐘緩沖器
單片機(jī)中的串口通訊串行同步通信與串行異步通信
嵌入式接口通識知識之Ethernet接口
嵌入式接口通識知識之UART接口
瑞薩RA系列FSP庫開發(fā)實(shí)戰(zhàn)指南(29)CGC(時(shí)鐘生成電路)時(shí)鐘控制
ADC和FPGA之間LVDS接口設(shè)計(jì)需要考慮的因素
AMD FPGA異步模式與同步模式的對比
USB串口芯片GP232RL替代FT232RL/uart 接口
電容在時(shí)鐘電路中的應(yīng)用有哪些
時(shí)鐘電路的組成與設(shè)計(jì)要點(diǎn)介紹
時(shí)鐘電路與晶振電路兩者的區(qū)別有哪些
中國集成電路大全 接口集成電路
AD9576雙通道PLL、異步時(shí)鐘發(fā)生器技術(shù)手冊
接口電路防護(hù)設(shè)計(jì)要點(diǎn)解析
如何設(shè)計(jì)異步時(shí)鐘之間的接口電路
評論