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