Xilinx IP核之FIFO
文章目錄
- 背景
- 1、FIFO的介紹
- 2、IP核的配置
- 3、同步FIFO工程實(shí)例
- 4、異步FIFO
- 1、讀寫指針的概念
- 2、FIFO滿空標(biāo)志的產(chǎn)生
- 3、如何判斷讀寫指針相等時(shí)候,為空還是為滿呢?
- 4、異步時(shí)鐘域下如何判斷是空還是滿?
- 5、使用格雷碼來表示指針
- 5、FIFO深度的計(jì)算(跨時(shí)鐘域處理問題研究)
背景
目前關(guān)于FIFO,我還沒有實(shí)戰(zhàn)用到,不過這個(gè)也是一名FPGA工程師必須要掌握的,這里來惡補(bǔ)一下,以方便以后哪天萬一用到,況且最近筆試、面試,FIFO都會(huì)被問到。
1、FIFO的介紹
FIFO(FIRST Input First Output) 即先進(jìn)先出隊(duì)列,在計(jì)算機(jī)中先進(jìn)先出隊(duì)列是一種傳統(tǒng)的按序執(zhí)行方法,先進(jìn)入的指令先完成并引退,跟著才執(zhí)行第二條指令。
FIFO一般用于不同時(shí)鐘域之間的數(shù)據(jù)傳輸,比如FIFO的一端是采樣速率比較慢的一個(gè)接口,另一端是擦癢速度比較快的一個(gè)接口,如果我們直接將這兩個(gè)接口相連接,那么就會(huì)出現(xiàn)各種問題。如何解決呢?我們就可以在這兩個(gè)不同的時(shí)鐘域之間采用FIFO來作為數(shù)據(jù)緩沖。
另外對(duì)于不同寬度的數(shù)據(jù)接口,也可以用FIFO,比如一端的接口輸出數(shù)據(jù)是8位,而另一端輸出數(shù)據(jù)可能是16位,我們就可以在這兩個(gè)不同寬度的數(shù)據(jù)接口中使用FIFO來達(dá)到數(shù)據(jù)匹配。
這里以同步FIFO IP核為例進(jìn)行講解。(注意:同步FIFO的讀寫時(shí)鐘是同一個(gè)時(shí)鐘)
FIFO一般用于不同時(shí)鐘域之間的數(shù)據(jù)傳輸,比如FIFO的一端時(shí)AD數(shù)據(jù)采集,另一端時(shí)計(jì)算機(jī)的PCI總線,假設(shè)其AD采集的速率為16位 100K SPS,那么每秒的數(shù)據(jù)量為100K×16bit=1.6Mbps,而PCI總線的速度為33MHz,總線寬度32bit,其最大傳輸速率為1056Mbps,在兩個(gè)不同的時(shí)鐘域間就可以采用FIFO來作為數(shù)據(jù)緩沖。另外對(duì)于不同寬度的數(shù)據(jù)接口也可以用FIFO,例如單片機(jī)位8位數(shù)據(jù)輸出,而DSP可能是16位數(shù)據(jù)輸入,在單片機(jī)與DSP連接時(shí)就可以使用FIFO來達(dá)到數(shù)據(jù)匹配的目的。
滿標(biāo)志:FIFO已滿或?qū)⒁獫M時(shí)由FIFO的狀態(tài)電路送出的一個(gè)信號(hào),以阻止FIFO的寫操作繼續(xù)向FIFO中寫數(shù)據(jù)而造成溢出(overflow)。
空標(biāo)志:FIFO已空或?qū)⒁諘r(shí)由FIFO的狀態(tài)電路送出的一個(gè)信號(hào),以阻止FIFO的讀操作繼續(xù)從FIFO中讀出數(shù)據(jù)而造成無效數(shù)據(jù)的讀出(underflow)。
讀時(shí)鐘:讀操作所遵循的時(shí)鐘,在每個(gè)時(shí)鐘沿來臨時(shí)讀數(shù)據(jù)。
寫時(shí)鐘:寫操作所遵循的時(shí)鐘,在每個(gè)時(shí)鐘沿來臨時(shí)寫數(shù)據(jù)。
讀指針:指向下一個(gè)讀出地址。讀完后自動(dòng)加1。
寫指針:指向下一個(gè)要寫入的地址的,寫完自動(dòng)加1。
讀寫指針其實(shí)就是讀寫的地址,只不過這個(gè)地址不能任意選擇,而是連續(xù)的。
2、IP核的配置
從配置的第二個(gè)界面,我們可以看到支持的類型;
前三個(gè)代表使用共同的時(shí)鐘,后面三個(gè)代表使用獨(dú)立的讀寫時(shí)鐘。
上面第三個(gè)頁面,有兩個(gè)標(biāo)簽需要我們配置:“Read ”模式和端口參數(shù)
在read mode中:standard FIFO(標(biāo)準(zhǔn)FIFO):FIFO的讀數(shù)據(jù)延遲讀請求一個(gè)時(shí)鐘周期輸出;
First word fall through:FIFO的讀數(shù)據(jù)在讀請求的同一個(gè)時(shí)鐘周期內(nèi)輸出。
另外,可以設(shè)置讀取深度和讀取寬度;
在optional flags欄中:
Almost FULL flag (幾乎滿了標(biāo)志位):表示FIFO里存的數(shù)據(jù)還差一個(gè)就滿了;
Almost Empty Flag(幾乎空了標(biāo)志位):表示FIFO里面存的數(shù)據(jù)只剩一個(gè)了;
W rite Port Handshaking 欄中:
write Acknowledga Flag:表示一次成功的寫操作標(biāo)志位;
Overflow Flag:表示一次無效的寫操作標(biāo)志位(溢出了)
在“Read Port Handshaking”欄中;
“valid flag”表示該端口的數(shù)據(jù)是有效的;
“underflow flag”表示一次無效的讀操作標(biāo)志位
在這個(gè)頁面中,有七個(gè)標(biāo)簽徐雅我們配置。
“Reset Pin”:給FIFO IP核設(shè)置一個(gè)復(fù)數(shù)引腳。
Synchrnous Reset(同步復(fù)位):復(fù)位信號(hào)在時(shí)鐘的上升呀且復(fù)位信號(hào)為低電平時(shí)有效;
Asynchronous Reset(異步復(fù)位):復(fù)位信號(hào)在復(fù)位信號(hào)的下降沿時(shí)有效。
“Full Flags Reset Value”設(shè)置全部標(biāo)志位信號(hào)的復(fù)位值
“Use Dout Reset Value”:設(shè)置讀端口數(shù)據(jù)的復(fù)位值,默認(rèn)為0;
最終形成FIFO的詳細(xì)報(bào)告單
另外,我們可以看到,其實(shí)FIFO IP核和我們的RAM IP核使用方法是差不多的,在RAM IP核中我們需要寫使能、寫數(shù)據(jù)、讀使能、讀數(shù)據(jù)以及時(shí)鐘和地址,在我們的FIFO IP核中,我們則需要寫使能、寫數(shù)據(jù)、讀使能、讀數(shù)據(jù)、時(shí)鐘、空表示、滿表示、以及數(shù)據(jù)計(jì)數(shù)等等,如果我們?nèi)サ暨@些標(biāo)志信號(hào),我么你可以看到我們的FIFO IP 核剩下的信號(hào)是和RAM IP核一樣的,唯一不同的是我們的RAM IP核讀寫操作需要地址,我們的 FIFO核就不需要使用地址,只要使能信號(hào)打開,時(shí)鐘到來,數(shù)據(jù)就可以讀出和寫入,比我們的RAM IP核使用起來簡單。
3、同步FIFO工程實(shí)例
下面我以計(jì)數(shù)器產(chǎn)生數(shù)據(jù)寫入,只需要控制wr_en和re_en即可
`timescale 1ns / 1ns // module FIFO_top( input clk, input rst, output [7:0] dout, // output [7 : 0] dout output full, // output full output almost_full, // output almost_full output wr_ack, // output wr_ack output overflow, // output overflow output empty, // output empty output almost_empty, // output almost_empty output valid, // output valid output underflow, // output underflow output [4:0]data_count // output [4 : 0] data_count); reg [7:0] timecnt=0; reg [7:0] din=0; wire wr_en; wire rd_en; reg wr_en_reg=0; reg rd_en_reg=0;always @ (posedge clk or negedge rst) beginif(!rst)din<=0;elsedin<=timecnt; endalways @ (posedge clk or negedge rst) beginif(!rst)timecnt<=0;else if(timecnt==8'd69)timecnt<=1'b0;elsetimecnt<=timecnt+1; end//用于產(chǎn)生FIFO IP核的寫使能信號(hào) //組合電路,用于產(chǎn)生寫使能信號(hào) always @ (posedge clk or negedge rst) begin if(!rst)beginwr_en_reg<=0;rd_en_reg<=0;end elsebeginwr_en_reg <=(timecnt>=8'd4&&timecnt<=8'd35)?1'b1:1'b0;rd_en_reg <=(timecnt>=8'd38&&timecnt<=8'd69)?1'b1:1'b0;end end assign wr_en=wr_en_reg; assign rd_en=rd_en_reg; FIFO_IP FIFO_IP_inst (.clk(clk), // input clk.rst(rst), // input rst.din(din), // input [7 : 0] din.wr_en(wr_en), // input wr_en.rd_en(rd_en), // input rd_en.dout(dout), // output [7 : 0] dout.full(full), // output full.almost_full(almost_full), // output almost_full.wr_ack(wr_ack), // output wr_ack.overflow(overflow), // output overflow.empty(empty), // output empty.almost_empty(almost_empty), // output almost_empty.valid(valid), // output valid.underflow(underflow), // output underflow.data_count(data_count) // output [4 : 0] data_count );endmodule
從上圖中可以看到雖然已經(jīng)開啟了寫使能,但是在復(fù)位后,需要4個(gè)時(shí)鐘的恢復(fù)時(shí)間,即使寫了,寫沒寫進(jìn)去。
然后data_count會(huì)延遲一個(gè)周期,empty也是延遲一個(gè)周期。所以寫進(jìn)去的數(shù)開始應(yīng)該是4.
但是如果沒復(fù)位,直接打開write寫使能,是只需要一個(gè)時(shí)鐘的;
從上圖,可以看出第一次讀取數(shù)據(jù)是4,并且在輸出4的同時(shí),data_count也計(jì)數(shù)為31(原本為32(即0,0就是32(因?yàn)橹挥?個(gè)bit位寬)))
full拉低,almost full在被讀走一個(gè)數(shù)據(jù)后拉低;
工程鏈接:
以上是同步FIFO,也就是讀寫使用的是一個(gè)時(shí)鐘
下面介紹異步FIFO,也就是讀寫非一個(gè)時(shí)鐘
4、異步FIFO
1、讀寫指針的概念
- 讀指針:
總是指向下一個(gè)將要被寫入的單元,復(fù)位時(shí)指向第一個(gè)單元。 - 寫指針:
總是指向當(dāng)前要被讀出的數(shù)據(jù),復(fù)位時(shí)指向第一個(gè)單元。
也就是說,復(fù)位時(shí)讀寫指針都指向第一個(gè)單元。并且向FIFO寫入一個(gè)數(shù)據(jù),寫指針加1。從FIFO中讀出一個(gè)數(shù)據(jù),都指針加1。
FIFO設(shè)計(jì)的關(guān)鍵是如何產(chǎn)生可靠的讀寫指針和滿空信號(hào)。FIFO讀寫指針的工作原理如上第四點(diǎn)所述。
2、FIFO滿空標(biāo)志的產(chǎn)生
那么剩下的就是要討論如何產(chǎn)生FIFO的滿空信號(hào)了。FIFO什么時(shí)候?yàn)榭漳?#xff1f;我們來思考一下,假設(shè)我從第一個(gè)單元寫入數(shù)據(jù),那么寫指針從地址0—>1,讀指針不變,此時(shí)FIFO中有一個(gè)數(shù)據(jù)。接著我把這個(gè)數(shù)據(jù)讀出來,讀指針從0—>1。此時(shí)寫指針為1,讀指針也為1,FIFO中沒有數(shù)據(jù)了,因此FIFO為空。從中可以發(fā)現(xiàn),判斷FIFO為空很簡單,只要讀寫指針相等就是空。但是事情好像也沒那么簡單,再想一下,假設(shè)一開始就復(fù)位,讀寫指針都在0地址,然后一直王FIFO中寫入數(shù)據(jù),當(dāng)寫滿FIFO的時(shí)候,寫指針剛好轉(zhuǎn)了一圈回到了0地址,此時(shí)讀寫指針也相等,但是這時(shí)候FIFO是滿的。因此得到下面的判空和判滿條件。
判空:讀指針追上寫指針的時(shí)候,兩者相等,為空。
判滿:寫指針追上讀指針的時(shí)候,兩者相等,為滿。
突然發(fā)現(xiàn)兩者相等的話不是空就是滿,區(qū)別就是誰追上誰而已了。那么如何來區(qū)別是誰追上誰呢?
3、如何判斷讀寫指針相等時(shí)候,為空還是為滿呢?
答案就是在表示讀寫指針的數(shù)據(jù)位寬上再加1位來區(qū)分是滿還是空。比如FIFO的深度位8,那么需要3位二進(jìn)制數(shù)來表地址,則需要再最高之前再加一位,變成4位。一開始讀寫都是0000,FIFO為空。當(dāng)寫指針增加并越過最后一個(gè)存儲(chǔ)單元的時(shí)候,就將這個(gè)最高位取反,變成1000。這時(shí)是寫地址追上了讀地址,FIFO為滿。同理,當(dāng)讀地址越過最后一個(gè)存儲(chǔ)單元的時(shí)候把讀地址的最高位也取反。可以看到,當(dāng)最高位相同,并且剩下的位也相同的時(shí)候FIFO為空;
4、異步時(shí)鐘域下如何判斷是空還是滿?
上述已經(jīng)解釋了如何按斷FIFO的滿空,是根據(jù)地址是否相等的方法,就是深度比如有8位,那么指針應(yīng)該有4位
如果讀的指針等于寫的指針(同時(shí)讀同時(shí)寫),那么二者相等,為空。
如果讀的指針為0000,寫的指針為1000,那么寫追上讀。此時(shí)為滿。
如果寫的指針為0000,讀的指針為1000,那么讀追上寫,此時(shí)為空。
-----------------------我是分界符-----------------------------
但是在上述問題中,讀寫時(shí)鐘需要一致同步,才能判斷。如果是在不同的時(shí)鐘域下,顯然需要將讀寫指針進(jìn)行同步化才可以進(jìn)行判斷。具體就是在判斷空的時(shí)候,需要將寫地址同步到讀時(shí)鐘域下進(jìn)行判斷。同理,在進(jìn)行判斷滿的時(shí)候需要將讀時(shí)鐘域下的讀指針同步到寫時(shí)鐘域進(jìn)行判斷。
5、使用格雷碼來表示指針
其實(shí)在讀時(shí)鐘域中讀指針的增加仍然是自然二進(jìn)制,同理,在寫時(shí)鐘域中寫地址的增加也是按照自然二進(jìn)制變化的。但是在將讀指針發(fā)送到寫時(shí)鐘域下進(jìn)行同步時(shí),如果仍然采用自然二進(jìn)制,那么就會(huì)面臨地址同時(shí)有多位變化的情況,這樣會(huì)容易引起亞穩(wěn)態(tài)或者毛刺。
5、FIFO深度的計(jì)算(跨時(shí)鐘域處理問題研究)
總結(jié)
以上是生活随笔為你收集整理的Xilinx IP核之FIFO的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 5、C语言面试笔试--数据组织--数组
- 下一篇: 汇顶科技真题-IC