一、FIFO簡(jiǎn)介
FIFO是英文First In First Out 的縮寫(xiě),是一種先進(jìn)先出的數(shù)據(jù)緩存器,它與普通存儲(chǔ)器的區(qū)別是沒(méi)有外部讀寫(xiě)地址線,這樣使用起來(lái)非常簡(jiǎn)單,但缺點(diǎn)就是只能順序?qū)懭霐?shù)據(jù),順序的讀出數(shù)據(jù),其數(shù)據(jù)地址由內(nèi)部讀寫(xiě)指針自動(dòng)加1完成,不能像普通存儲(chǔ)器那樣可以由地址線決定讀取或?qū)懭肽硞€(gè)指定的地址。
用途1:
異步FIFO讀寫(xiě)分別采用相互異步的不同時(shí)鐘。在現(xiàn)代集成電路芯片中,隨著設(shè)計(jì)規(guī)模的不斷擴(kuò)大,一個(gè)系統(tǒng)中往往含有數(shù)個(gè)時(shí)鐘,多時(shí)鐘域帶來(lái)的一個(gè)問(wèn)題就是,如何設(shè)計(jì)異步時(shí)鐘之間的接口電路。異步FIFO是這個(gè)問(wèn)題的一種簡(jiǎn)便、快捷的解決方案,使用異步FIFO可以在兩個(gè)不同時(shí)鐘系統(tǒng)之間快速而方便地傳輸實(shí)時(shí)數(shù)據(jù)。
用途2:
對(duì)于不同寬度的數(shù)據(jù)接口也可以用FIFO,例如單片機(jī)位8位數(shù)據(jù)輸出,而DSP可能是16位數(shù)據(jù)輸入,在單片機(jī)與DSP連接時(shí)就可以使用FIFO來(lái)達(dá)到數(shù)據(jù)匹配的目的。
二、分類(lèi)
同步FIFO是指讀時(shí)鐘和寫(xiě)時(shí)鐘為同一個(gè)時(shí)鐘,在時(shí)鐘沿來(lái)臨時(shí)同時(shí)發(fā)生讀寫(xiě)操作;
異步FIFO是指讀寫(xiě)時(shí)鐘不一致,讀寫(xiě)時(shí)鐘是互相獨(dú)立的。
三、FIFO的常見(jiàn)參數(shù)
FIFO的寬度:即FIFO一次讀寫(xiě)操作的數(shù)據(jù)位;
FIFO的深度:指的是FIFO可以存儲(chǔ)多少個(gè)N位的數(shù)據(jù)(如果寬度為N)。
滿標(biāo)志:FIFO已滿或?qū)⒁獫M時(shí)由FIFO的狀態(tài)電路送出的一個(gè)信號(hào),以阻止FIFO的寫(xiě)操作繼續(xù)向FIFO中寫(xiě)數(shù)據(jù)而造成溢出(overflow)。
空標(biāo)志:FIFO已空或?qū)⒁諘r(shí)由FIFO的狀態(tài)電路送出的一個(gè)信號(hào),以阻止FIFO的讀操作繼續(xù)從FIFO中讀出數(shù)據(jù)而造成無(wú)效數(shù)據(jù)的讀出(underflow)。
讀時(shí)鐘:讀操作所遵循的時(shí)鐘,在每個(gè)時(shí)鐘沿來(lái)臨時(shí)讀數(shù)據(jù)。
寫(xiě)時(shí)鐘:寫(xiě)操作所遵循的時(shí)鐘,在每個(gè)時(shí)鐘沿來(lái)臨時(shí)寫(xiě)數(shù)據(jù)。
===============================分 隔 符 ==============================
讀寫(xiě)指針的工作原理
讀指針:總是指向下一個(gè)將要被寫(xiě)入的單元,復(fù)位時(shí),指向第1個(gè)單元(編號(hào)為0)。
寫(xiě)指針:總是指向當(dāng)前要被讀出的數(shù)據(jù),復(fù)位時(shí),指向第1個(gè)單元(編號(hào)為0)
FIFO的“空”/“滿”檢測(cè)
FIFO設(shè)計(jì)的關(guān)鍵:產(chǎn)生可靠的FIFO讀寫(xiě)指針和生成FIFO“空”/“滿”狀態(tài)標(biāo)志。
當(dāng)讀寫(xiě)指針相等時(shí),表明FIFO為空,這種情況發(fā)生在復(fù)位操作時(shí),或者當(dāng)讀指針讀出FIFO中最后一個(gè)字后,追趕上了寫(xiě)指針時(shí),如下圖所示:
當(dāng)讀寫(xiě)指針再次相等時(shí),表明FIFO為滿,這種情況發(fā)生在,當(dāng)寫(xiě)指針轉(zhuǎn)了一圈,折回來(lái)(wrapped around)又追上了讀指針,如下圖:
為了區(qū)分到底是滿狀態(tài)還是空狀態(tài),可以采用以下方法:
方法1:在指針中添加一個(gè)額外的位(extra bit),當(dāng)寫(xiě)指針增加并越過(guò)最后一個(gè)FIFO地址時(shí),就將寫(xiě)指針這個(gè)未用的MSB加1,其它位回零。對(duì)讀指針也進(jìn)行同樣的操作。此時(shí),對(duì)于深度為2n的FIFO,需要的讀/寫(xiě)指針位寬為(n+1)位,如對(duì)于深度為8的FIFO,需要采用4bit的計(jì)數(shù)器,0000~1000、1001~1111,MSB作為折回標(biāo)志位,而低3位作為地址指針。
如果兩個(gè)指針的MSB不同,說(shuō)明寫(xiě)指針比讀指針多折回了一次;如r_addr=0000,而w_addr = 1000,為滿。
如果兩個(gè)指針的MSB相同,則說(shuō)明兩個(gè)指針折回的次數(shù)相等。其余位相等,說(shuō)明FIFO為空;
3.二進(jìn)制FIFO指針的考慮
將一個(gè)二進(jìn)制的計(jì)數(shù)值從一個(gè)時(shí)鐘域同步到另一個(gè)時(shí)鐘域的時(shí)候很容易出現(xiàn)問(wèn)題,因?yàn)椴捎枚M(jìn)制計(jì)數(shù)器時(shí)所有位都可能同時(shí)變化,在同一個(gè)時(shí)鐘沿同步多個(gè)信號(hào)的變化會(huì)產(chǎn)生亞穩(wěn)態(tài)問(wèn)題。而使用格雷碼只有一位變化,因此在兩個(gè)時(shí)鐘域間同步多個(gè)位不會(huì)產(chǎn)生問(wèn)題。所以需要一個(gè)二進(jìn)制到gray碼的轉(zhuǎn)換電路,將地址值轉(zhuǎn)換為相應(yīng)的gray碼,然后將該gray碼同步到另一個(gè)時(shí)鐘域進(jìn)行對(duì)比,作為空滿狀態(tài)的檢測(cè)。
4.
使用gray碼進(jìn)行對(duì)比,如何判斷“空”與“滿”
使用gray碼解決了一個(gè)問(wèn)題,但同時(shí)也帶來(lái)另一個(gè)問(wèn)題,即在格雷碼域如何判斷空與滿。
對(duì)于“空”的判斷依然依據(jù)二者完全相等(包括MSB);
而對(duì)于“滿”的判斷,如下圖,由于gray碼除了MSB外,具有鏡像對(duì)稱的特點(diǎn),當(dāng)讀指針指向7,寫(xiě)指針指向8時(shí),除了MSB,其余位皆相同,不能說(shuō)它為滿。因此不能單純的只檢測(cè)最高位了,在gray碼上判斷為滿必須同時(shí)滿足以下3條:
wptr和同步過(guò)來(lái)的rptr的MSB不相等,因?yàn)閣ptr必須比rptr多折回一次。
wptr與rptr的次高位不相等,如上圖位置7和位置15,轉(zhuǎn)化為二進(jìn)制對(duì)應(yīng)的是0111和1111,MSB不同說(shuō)明多折回一次,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, //寫(xiě)請(qǐng)求信號(hào),寫(xiě)時(shí)鐘,寫(xiě)復(fù)位 input rinc, rclk, rrst_n, //讀請(qǐng)求信號(hào),讀時(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 *************************************************************/ /*在檢測(cè)“滿”或“空”狀態(tài)之前,需要將指針同步到其它時(shí)鐘域時(shí),使用格雷碼,可以降低同步過(guò)程中亞穩(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)讀指針和同步過(guò)來(lái)的寫(xiě)指針完全相等時(shí)(包括MSB),說(shuō)明二者折回次數(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)志在寫(xiě)時(shí)鐘域產(chǎn)生,因此比較安全的做法是將讀指針同步到寫(xiě)時(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核,為安全起見(jiàn)推薦使用IP核定制FIFO,本文的目的只是作為思路參考。
審核編輯:郭婷
-
芯片
+關(guān)注
關(guān)注
459文章
51988瀏覽量
434231 -
存儲(chǔ)器
+關(guān)注
關(guān)注
38文章
7617瀏覽量
166063 -
fifo
+關(guān)注
關(guān)注
3文章
397瀏覽量
44523
原文標(biāo)題:異步FIFO的FPGA實(shí)現(xiàn)
文章出處:【微信號(hào):zhuyandz,微信公眾號(hào):FPGA之家】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
異步串行接口有哪些,異步串行接口為何需要波特率
總線接口的類(lèi)型與選擇指南
計(jì)算機(jī)接口位于什么之間
scsi接口是什么之間的接口
pcm1794能否支持異步時(shí)鐘模式?
隔離式調(diào)制器與MCU之間的數(shù)字接口的時(shí)鐘邊沿延遲補(bǔ)償

記一次JSF異步調(diào)用引起的接口可用率降低

開(kāi)源芯片系列講座第22期:異步電路機(jī)制為RISC-V處理器賦能

怎么判斷同步清零和異步清零
異步置零和同步置零的區(qū)別在哪里
同步電路和異步電路怎么判斷正負(fù)極
同步電路和異步電路的優(yōu)缺點(diǎn)
同步電路和異步電路的優(yōu)缺點(diǎn)有哪些
直播預(yù)告 |開(kāi)源芯片系列講座第22期:異步電路機(jī)制為RISC-V處理器賦能

評(píng)論