74ls390设计任意进制计数器_异步FIFO:设计原理及Verliog源码
1.? 異步FIFO的概念
異步FIFO為讀取與寫入采用不同的時鐘,使用異步FIFO用于在不同的時鐘域傳輸數據,主要用于跨時鐘域傳輸多bit數據。
2.? 異步FIFO的設計難點
同步異步信號,避免亞穩態數據的危害
設計合適的FIFO指針,判斷FIFO滿或者空狀態。3.? 同步FIFO的指針
同步FIFO有一個計數器用于計數存儲的數目和讀取的數目。當FIFO只有寫操作沒有讀操作計數值增加,當FIFO只有讀操作沒有寫操作的時候計數值減小,當沒有讀寫操作或者同時在進行讀寫操作的時候計數值保持不變。當計數器的計數值達到FIFO的總長度的時候FIFO滿,當計數值為0的時候那么FIFO空。
但是在異步FIFO設計中無法使用一個計數器來統計FIFO的數據的個數,因為兩個異步的時鐘需要去控制同一個計數器。因此在設計異步FIFO時候需要比較FIFO的讀寫指針位置。4.? 異步FIFO的指針
異步FIFO的寫指針總是指向下一個要被寫入的地址,當復位或者清空時候讀寫指針都指向FIFO緩沖區的0地址。同樣的讀指針總是指向當前FIFO中要被讀出的數據所在的地址,當清空或者復位是指針指向0,當發生一次讀操作時讀指針所指的地址的數據被取出,然后指針地址增加。
FIFO空的標志發生時是當讀的指針和寫的指針相等時。當讀寫指針復位到0的時候如清空FIFO等操作的時候,或者是當讀的指針趕上了寫指針。
FIFO滿的標志也是當讀指針和寫指針相等的時候。當寫指針已經環繞一周,然后追上讀指針的時候。因此就存在一個問題當讀寫指針相等的時候如何判斷是讀空還是寫滿。
為了區分是讀空還是寫滿,一種設計的方式是給讀寫指針添加一個額外的位。當寫指針增加了以后超過了FIFO的存儲空間的最后的地址,這時候指針自加就會使得額外添加的最高位翻轉。同樣的讀指針也會進行相同的操作。因此當兩個最高位是不同的時候就可以判斷是寫指針已經環繞追上了讀指針,那么FIFO是處于寫滿狀態,如果最高位是相同的那么是讀指針追趕上了寫指針,FIFO處于讀空狀態。
圖1 添加MSB用于區分寫滿與讀空5.? 讀寫指針計數器設計
對于一個二進制計數器,當他的計數值從一個時鐘域同步到另外一個時鐘域的時候是危險的,因為可能存在n-bits數據同時變化的情況,如7計數到8對應的二進制是0111計數到1000,那么對應的所有的位均發生變化。
一種通用的解決FIFO計數器的問題的方法是使用格雷碼進行計數,格雷碼對于相鄰的兩個計數值只允許一個位發生變化。因此就解決了欲在同一個時鐘邊沿同步多個bits的問題。6.? 格雷碼計數器問題引入
考慮4位和3位的格雷碼計數器如圖 2。通過對二進制碼的分析可以得出對于4位格雷碼上半部分與下半部分是最高位反向其余位關于中點鏡像。為了將4位的格雷碼轉化為3位的格雷碼,同時使得最高位為附加位,用于區分寫滿與讀空。我們希望4位格雷碼的低3位重復第一部分的低3位,而不是關于中點的鏡像。如果直接將下半部分的低3位格雷碼編碼改為上半部分的低3位一樣的編碼那么就不是真格雷碼應為從7到8以及15到0時候會出現兩bits發生變化。而真格雷碼應該是在相鄰的兩個計數之間只有一個位發生變化。
圖2 四位格雷碼7.? 格雷碼計數器設計
格雷碼計數器是不存在奇數長度的,因此設計出來的額FIFO的深度就是? 。 二進制計數器咋每次自加都會檢測是否為滿或者空狀態,從而保證不會出現溢出或者下溢。
在圖 3所示的格雷碼計數器中二進制計數器的低(n-1)位可以直接作為FIFO存儲單元的地址指針,將二進制數轉化為格雷碼傳輸給另外一個時鐘域。
圖 3格雷碼計數器8.? 格雷碼轉二進制與二進制轉格雷碼
二進制B[n:0]轉化為格雷碼G[n:0]
G[n] = B[n]?????????????????????? //保留最高位作為格雷碼的最高位
G[n-1:0] = B[n-1:0]^B[n:1]? //次高位格雷碼為二進制碼的高位與次高位相異或其余類似
格雷碼G[n:0]轉化為二進制B[n:0]
B[n] = G[n]??????????????????????? //保留最高位作為二進制碼的最高位
B[n-1:0] = G[n-1:0]^B[n:1]? //次高位格雷碼為二進制碼的高位與次高位相異或其余類似
9.? FIFO實現
將地址指針轉化為格雷碼以后對于相鄰的兩個地址只有一個位數據發生變化,因此可以使用觸發器來同步異步時鐘的數據。? 圖4 FIFO結構框圖10.滿和空信號的生成
讀空信號是在讀時鐘域生成的,從而保證能夠實時的沒有延遲的確定讀空。當讀空發生時是讀指針追趕上寫指針,兩個指針值相同(包括擴展的最高位)。此時其格雷碼也是相同的,因此設計相對簡單。
在FIFO設計中寫滿信號是在寫時鐘域生成的,從而保證能夠實時的沒有延遲的確定寫滿。當寫指針追趕上讀指針的時候發生,此時兩個指針的二進制計數器的低(n-1)位相同最高位不同。但是由于擴展了格雷碼,而對于n位格雷碼其(n-1)位是關于中間值鏡像對稱的。
圖 5 有擴展位的格雷碼編碼
考慮圖 5對于3位的格雷碼地址添加一個附加位用于區分寫滿與讀空成為4位的格雷碼編碼。當FIFO空時即讀指針趕上寫指針,此時兩個格雷碼完全相同(包括擴展位)。當FIFO寫滿時候需要考慮如下3個條件
1.? 寫指針的格雷碼與同步到寫時鐘域的讀指針格雷碼的最高位不同
2.? 寫指針的格雷碼與同步到寫時鐘域的讀指針格雷碼的次高位不相等
3.? 寫指針的格雷碼與同步到寫時鐘域的讀指針格雷碼的其余位都相等11.不同的時鐘速率同步的深入思考
當異步FIFO來同步兩個不同的時鐘域的時候,顯然兩個時鐘的速度是不一樣的,考慮當一個快的時鐘域的信號同步到慢的時鐘域的時候可能會存在計數值跳躍,因為在慢的時鐘域的一個周期快的時鐘域的計數值可能已經增加了多次了,因此就會導致如下的兩個問題:
1. ?在同步格雷碼的時候如果格雷碼的值增加了2個然而只采樣了一次就會出現多個位的數據發生變化,這種情況下會導致多bit數據同步問題嗎?
?? 答案是否定的。在同步多bit數據的時候當多個數據位在同步上升沿變化時會出現問題。但是對于快的時鐘域的寫指針的格雷碼在一個時鐘周期只改變一位,因此在慢的時鐘域周圍最多只會有一個位發生變化。
2. ?在慢的時鐘域一個周期里面快的時鐘域的計數器可能已經增加了幾個計數值了,那么會存在快的時鐘域的已經從滿狀態增加到(滿+1)的狀態,而沒能檢測出滿嗎?
?? 答案是否定的,應為滿狀態是在寫時鐘域產生的,如果寫的時鐘比讀取的時鐘快,當寫指針趕上從讀時鐘域同步過來的讀指針后,滿狀態會馬上置位,因此就不會出現溢出。
滿與空狀態能夠準確的被置位,但是標志位清除有一定的延遲。
當我們在寫時鐘域產生FIFO滿的狀態,當寫指針追趕上讀指針的時候馬上產生滿標志,此時當讀指針增長了以后FIFO就不再滿了,但是寫時鐘域不能馬上檢測到讀指針已經增加了,需要經過兩個時鐘周期,使得讀指針的數據同步到寫時鐘域以后才能夠清空滿狀態。這樣能夠保證FIFO不會溢出,相同的讀FIFO也存在這樣的問題。
Verilog源碼:
/*異步fifo 參考文獻? Simulation and SynthesisTechniques for Asynchronous FIFO Design*/
module async_fifo(
?????? rst_n???????? ,
?????? fifo_wr_clk?? ,
?????? fifo_wr_en,
?????? r_fifo_full?? ,
?????? fifo_wr_data,
?????? fifo_rd_clk?? ,
?????? fifo_rd_en,
?????? fifo_rd_data,
?????? r_fifo_empty?
//???? fifo_wr_err,
//???? fifo_rd_err
??? );
?????? input rst_n????????? ;
?????? inputfifo_wr_en? ;
?????? input? [15:0]fifo_wr_data;
?????? inputfifo_rd_en? ;
?????? inputfifo_rd_clk;
?????? inputfifo_wr_clk;
?????? output regr_fifo_full?? ;
?????? output[15:0]fifo_rd_data;
?????? output regr_fifo_empty? ;
//???? output regfifo_wr_err;
//???? output regfifo_rd_err;
?????? reg[9:0]?rdaddress; //RAM地址為9位地址 擴展一位用于同步
?????? reg[9:0]?wraddress;
?????? wire?? [9:0]? gray_rdaddress;
?????? wire?? [9:0]? gray_wraddress;
?????? /*同步寄存器*/
?????? reg[9:0] sync_w2r_r1,sync_w2r_r2;
?????? reg[9:0] sync_r2w_r1,sync_r2w_r2;
?????? wirefifo_empty;
?????? wirefifo_full;
?????? /*二進制轉化為格雷碼計數器*/
?????? assigngray_rdaddress = (rdaddress >>1) ^ rdaddress;//(({1'b0,rdaddress[9:1]}) ^rdaddress);
?????? /*二進制轉化為格雷碼計數器*/
?????? assigngray_wraddress = (({1'b0,wraddress[9:1]}) ^ wraddress);
?????? assignfifo_empty = (gray_rdaddress == sync_w2r_r2);
?????? assignfifo_full = (gray_wraddress == {~sync_r2w_r2[9:8],sync_r2w_r2[7:0]});
//????
//???? assignfifo_wr_err = (w_fifo_full && fifo_wr_en);
//???? assignfifo_rd_err = (fifo_empty && fifo_rd_en);
?????? ram? ram(
?????????? .data????? (fifo_wr_data???? ),
?????????? .rdaddress(rdaddress[8:0]),
?????????? .rdclock?? (fifo_rd_clk? ),
?????????? .wraddress(wraddress[8:0]),
?????????? .wrclock?? (fifo_wr_clk? ),
?????????? .wren????? (fifo_wr_en?? ),
?????????? .q???????? (fifo_rd_data)
?????????? );?
?????? /*在讀時鐘域同步FIFO空 sync_w2r_r2 為同步的寫指針地址延遲兩拍 非實際 寫指針值 但是確保不會發生未寫入數據就讀取*/
?????? always@(posedgefifo_rd_clk or negedge rst_n)
?????? if(!rst_n)
?????????? r_fifo_empty<= 1'b1;
?????? else
?????????? r_fifo_empty<= fifo_empty;
?????????? /*在寫時鐘域判斷FIFO滿 sync_r2w_r2 實際延遲兩個節拍可能存在非滿判斷為滿 但不會導致覆蓋*/
?????? always@(posedgefifo_wr_clk or negedge rst_n)
?????? if(!rst_n)
?????????? r_fifo_full<= 1'b1;
?????? else ?????????????????????????????
?????????? r_fifo_full<= fifo_full;//格雷碼判斷追及問題???????
?????? /*讀數據地址生成*/
?????? always@(posedgefifo_rd_clk or negedge rst_n)
?????? if(!rst_n)
?????????? rdaddress<= 10'b0;
?????? elseif(fifo_rd_en && ~fifo_empty)begin
?????????? rdaddress<= rdaddress + 1'b1;
?????? end
?????? /*寫數據地址生成*/
?????? always@(posedgefifo_wr_clk or negedge rst_n)
?????? if(!rst_n)
?????????? wraddress<= 10'b0;
?????? elseif(fifo_wr_en && ~r_fifo_full)begin
?????????? wraddress<= wraddress + 1'b1;
?????? end
?????? /*同步讀地址到寫時鐘域*/
?????? always@(posedgefifo_wr_clk or negedge rst_n)
?????? if(!rst_n)begin
?????????? sync_r2w_r1<= 10'd0;
?????????? sync_r2w_r2<= 10'd0;
?????? end elsebegin
?????????? sync_r2w_r1<= gray_rdaddress;
?????????? sync_r2w_r2<= sync_r2w_r1;????
?????? end
?????? /*同步寫地址到讀時鐘域, 同步以后 存在延遲兩個節拍*/
?????? always@(posedgefifo_rd_clk or negedge rst_n)
?????? if(!rst_n)begin
?????????? sync_w2r_r1<= 10'd0;
?????????? sync_w2r_r2<= 10'd0;
?????? end elsebegin
?????????? sync_w2r_r1<= gray_wraddress ;
??? ?????? sync_w2r_r2 <= sync_w2r_r1;????
?????? end
endmodule
轉載自:
https://blog.csdn.net/u014070258/article/details/90052281
侵刪。
總結
以上是生活随笔為你收集整理的74ls390设计任意进制计数器_异步FIFO:设计原理及Verliog源码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 现在常州驾照考下来大概多久,费用多少
- 下一篇: stc15w404as引脚图_STC15