??作者簡(jiǎn)介:
小瑞同學(xué)
,一個(gè)努力精進(jìn)的FPGA和通信學(xué)習(xí)者。
??個(gè)人主頁(yè):小瑞同學(xué)的博客主頁(yè)
??個(gè)人信條:越努力,越幸運(yùn)!
?日期:2023.12.3
??來(lái)源:自學(xué)經(jīng)歷
??文章內(nèi)容概述:介紹了異步FIFO的基本工作原理和深度計(jì)算,通過(guò)仿真觀察了其讀寫(xiě)過(guò)程。
連載系列:FPGA中FIFO的應(yīng)用
完整工程已上傳至CSDN:下載鏈接
- 同步FIFO設(shè)計(jì)
- 異步FIFO設(shè)計(jì)
- Vivado FIFO IP核的調(diào)用
1.異步FIFO簡(jiǎn)介
1.1 概述
??異步FIFO是指讀寫(xiě)受兩個(gè)不同的時(shí)鐘控制,一般用于數(shù)據(jù)的跨時(shí)鐘域傳遞以及不同數(shù)據(jù)寬度的數(shù)據(jù)接口。對(duì)于單bit信號(hào)跨時(shí)鐘域可以使用簡(jiǎn)單的打拍進(jìn)行同步,而對(duì)于多bit信號(hào)的跨時(shí)鐘域傳遞,就需要使用異步FIFO了。
1.2 主要參數(shù)
??異步FIFO的主要參數(shù)和同步FIFO基本相同,主要的區(qū)別的是異步FIFO有讀時(shí)鐘rd_clk和寫(xiě)時(shí)鐘wr_clk兩個(gè)時(shí)鐘。
參數(shù) | 意義 |
---|---|
讀時(shí)鐘 | —— |
寫(xiě)時(shí)鐘 | —— |
FIFO的寬度 | FIFO一次讀寫(xiě)的數(shù)據(jù)位寬 |
FIFO的深度 | FIFO中存儲(chǔ)的數(shù)據(jù)個(gè)數(shù) |
空標(biāo)志 | FIFO已空時(shí)發(fā)出空信號(hào),以阻止讀操作繼續(xù)讀取無(wú)效數(shù)據(jù) |
滿標(biāo)志 | FIFO已滿時(shí)發(fā)出滿信號(hào),以阻止寫(xiě)操作繼續(xù)向FIFO中寫(xiě)數(shù)據(jù)而導(dǎo)致FIFO溢出 |
2.空滿判斷
2.1 高位擴(kuò)展法
??異步FIFO的設(shè)計(jì)難點(diǎn)在于空滿標(biāo)志的判斷,由于其讀寫(xiě)時(shí)鐘不同,無(wú)法用上篇文章提到的的計(jì)數(shù)器法進(jìn)行判斷。
??這里我們采用高位擴(kuò)展法,高位擴(kuò)展法就是將讀寫(xiě)地址變量擴(kuò)展出一個(gè)最高位作為判斷位,判斷位和地址組成讀指針變量rd_ptr和寫(xiě)指針變量wr_ptr,對(duì)于二進(jìn)制地址數(shù)據(jù),判斷方法如下:
- 對(duì)于空標(biāo)志,rd_ptr和wr_ptr所經(jīng)過(guò)的路徑相同,反應(yīng)在變量數(shù)值上就是 rd_ptr=wr_ptr ;
- 對(duì)于滿標(biāo)志,wr_ptr需要比rd_ptr多走一圈,反應(yīng)在變量數(shù)值上就是rd_ptr和wr_ptr的最高位不同,而其它位相同 。
2.2 空滿標(biāo)志的時(shí)鐘域同步
??由于讀寫(xiě)過(guò)程由不同時(shí)鐘控制,所以在比較讀寫(xiě)指針前需要先對(duì)其進(jìn)行時(shí)鐘域同步。但是這里存在一個(gè)問(wèn)題,如果直接使用二進(jìn)制數(shù)據(jù)進(jìn)行同步的話,會(huì)出現(xiàn)多位數(shù)據(jù)同時(shí)跳變,這樣就增大了出錯(cuò)的概率。格雷碼可以很好的解決這個(gè)問(wèn)題,相鄰的兩個(gè)格雷碼之間只有1位不同,所以在同步之前我們先將二進(jìn)制數(shù)據(jù)轉(zhuǎn)化為格雷碼。
2.3 二進(jìn)制數(shù)和格雷碼之間的轉(zhuǎn)換
四位二進(jìn)制數(shù)和格雷碼的對(duì)應(yīng)關(guān)系如下圖所示。
具體的轉(zhuǎn)化公式如下:
格雷碼轉(zhuǎn)二進(jìn)制:
二進(jìn)制轉(zhuǎn)格雷碼:
我們將二進(jìn)制地址指針轉(zhuǎn)化為對(duì)應(yīng)的格雷碼wr_gray和rd_gray,然后進(jìn)行時(shí)鐘同步:
- 在寫(xiě)時(shí)鐘上升沿,將rd_gray打兩拍延時(shí)得到rd_gray_d2。
- 在讀時(shí)鐘上升沿,將wr_gray打兩拍延時(shí)得到wr_gray_d2。
在轉(zhuǎn)化為格雷碼后,空滿標(biāo)志的判斷標(biāo)準(zhǔn)將不同于二進(jìn)制:
- 空標(biāo)志:rd_gray==wr_gray_d2。
- 滿標(biāo)志:wr_gray和rd_gray_d2的最高位和次高位相反,而其它各位相等。
例如:對(duì)于深度為8的FIFO,其地址寬度為3,當(dāng)rd_ptr的二進(jìn)制數(shù)為0001時(shí),如果是滿狀態(tài)的話wr_ptr應(yīng)該為1001,參考上表,對(duì)應(yīng)的格雷碼分別為0001和1101,即最高位和次高位相反,其它各位相等。
3.異步FIFO的深度計(jì)算
??在跨時(shí)鐘域數(shù)據(jù)傳遞用到異步FIFO時(shí),往往需要計(jì)算FIFO的理論最小深度,而實(shí)際FIFO深度通常要大于計(jì)算值。
??現(xiàn)考慮這樣的場(chǎng)景,假設(shè)模塊A以一定的時(shí)鐘頻率不間斷地向FIFO中寫(xiě)數(shù)據(jù),而模塊B以慢于A的時(shí)鐘頻率不間斷地從FIFO中讀取數(shù)據(jù),如果系統(tǒng)一直工作,那么FIFO中的數(shù)據(jù)會(huì)越累積越多,需要FIFO的深度就是無(wú)窮大的,這并不現(xiàn)實(shí)。所以只有在突發(fā)傳輸過(guò)程中討論FIFO的深度才有意義。要確定FIFO的深度,就要計(jì)算出在突發(fā)讀寫(xiě)這段時(shí)間內(nèi)有多少數(shù)據(jù)沒(méi)有被讀走。
突發(fā)傳輸:短時(shí)間內(nèi)進(jìn)行相對(duì)高帶寬的數(shù)據(jù)傳輸
這里舉一個(gè)簡(jiǎn)單的題:
問(wèn):一個(gè)8bit位寬的FIFO,輸入時(shí)鐘是100MHz,輸出時(shí)鐘是50MHz,設(shè)計(jì)一個(gè)讀寫(xiě)包文的緩存是2Kbit,兩個(gè)包文間的發(fā)送時(shí)間間隔足夠大,求異步FIFO的最小讀寫(xiě)深度。
答:
- 發(fā)送包文的突發(fā)長(zhǎng)度是 250 B y t e 250Byte 250Byte,每個(gè)地址存取1個(gè) B y t e Byte Byte
- 輸入時(shí)鐘周期為 10 n s 10ns 10ns,輸出時(shí)鐘周期為 20 n s 20ns 20ns
- 前一模塊發(fā)送包文,寫(xiě)入FIFO所用的時(shí)間為 2000 / 8 ? 10 = 2500 n s 2000/8*10=2500 ns 2000/8?10=2500ns
- 在這段時(shí)間內(nèi),后一模塊接收包文,從FIFO中讀出讀取的數(shù)據(jù)量為 2500 / 20 = 125 B y t e 2500/20=125Byte 2500/20=125Byte
- 異步FIFO理論最小深度為 250 B y t e ? 125 B y t e = 125 B y t e 250Byte-125Byte=125Byte 250Byte?125Byte=125Byte
有關(guān)FIFO深度計(jì)算更細(xì)致的講解,可參考該文章:FIFO深度計(jì)算
4.verilog代碼
module FIFO_asyn
#(parameter FIFO_WIDTH=8,
parameter FIFO_DEPTH=16)
(
input wclk ,
input rclk ,
input wr_rstn,
input rd_rstn,
input wr_en ,
input rd_en ,
input [FIFO_WIDTH-1:0] din ,
output empty ,
output full ,
output reg [FIFO_WIDTH-1:0] dout
);
localparam ADDR_LEN=$clog2(FIFO_DEPTH);
localparam PTR_LEN=ADDR_LEN+1;
//讀寫(xiě)地址
wire [ADDR_LEN-1:0] wr_addr;
wire [ADDR_LEN-1:0] rd_addr;
//讀寫(xiě)指針
reg [PTR_LEN-1:0] wr_ptr;
reg [PTR_LEN-1:0] rd_ptr;
//讀寫(xiě)指針對(duì)應(yīng)的格雷碼
wire [PTR_LEN-1:0] wr_gray;
wire [PTR_LEN-1:0] rd_gray;
//打拍寄存器變量
reg [PTR_LEN-1:0] wr_gray_d1;
reg [PTR_LEN-1:0] wr_gray_d2;
reg [PTR_LEN-1:0] rd_gray_d1;
reg [PTR_LEN-1:0] rd_gray_d2;
//FIFO
reg [FIFO_WIDTH-1:0] fifo [0:FIFO_DEPTH-1];
//讀寫(xiě)指針為1bit判斷位和讀寫(xiě)地址的拼接
assign wr_addr=wr_ptr[ADDR_LEN-1:0];
assign rd_addr=rd_ptr[ADDR_LEN-1:0];
//二進(jìn)制轉(zhuǎn)格雷碼
assign wr_gray=(wr_ptr>>1)^wr_ptr;
assign rd_gray=(rd_ptr>>1)^rd_ptr;
//空滿判斷
assign empty=(wr_gray_d2==rd_gray) ? 1'b1:1'b0;
assign full=(wr_gray=={~rd_gray_d2[PTR_LEN-1:PTR_LEN-2],rd_gray_d2[PTR_LEN-3:0]})? 1'b1: 1'b0;
//寫(xiě)FIFO
always@(posedge wclk or negedge wr_rstn)begin
if(!wr_rstn)begin
wr_ptr<='b0;
end
else if(wr_en&&!full)begin
fifo[wr_addr]<=din;
wr_ptr<=wr_ptr+1'b1;
end
else begin
wr_ptr<=wr_ptr;
end
end
//讀FIFO
always@(posedge rclk or negedge rd_rstn)begin
if(!rd_rstn)begin
rd_ptr<='b0;
dout<='b0;
end
else if(rd_en&&!empty)begin
dout<=fifo[rd_addr];
rd_ptr<=rd_ptr+1'b1;
end
else begin
rd_ptr<=rd_ptr;
dout<=dout;
end
end
//將寫(xiě)指針同步到讀時(shí)鐘域
always@(posedge rclk or negedge rd_rstn)begin
if(!rd_rstn)begin
wr_gray_d1<='b0;
wr_gray_d2<='b0;
end
else begin
wr_gray_d1<=wr_gray;
wr_gray_d2<=wr_gray_d1;
end
end
//將讀指針同步到寫(xiě)時(shí)鐘域
always@(posedge wclk or negedge wr_rstn)begin
if(!wr_rstn)begin
rd_gray_d1<='b0;
rd_gray_d2<='b0;
end
else begin
rd_gray_d1<=rd_gray;
rd_gray_d2<=rd_gray_d1;
end
end
endmodule
5.仿真分析
5.1 參考testbench文件
`timescale 1ns / 1ps
module tb();
parameter FIFO_WIDTH=8;
reg wclk;
reg rclk;
reg rstn;
reg wr_en;
reg rd_en;
reg [FIFO_WIDTH-1:0] din;
wire empty;
wire full;
wire [FIFO_WIDTH-1:0] dout;
initial begin
wclk=1'b0;
rclk=1'b0;
rstn=1'b0;
wr_en=1'b0;
rd_en=1'b0;
din='b0;
#15;
rstn=1'b1;
repeat(16)wr_only;
repeat(16)rd_only;
repeat(5)wr_rd;
#30;
wr_en=1'b0;
rd_en=1'b0;
$stop;
end
always #10 wclk=~wclk;
always #20 rclk=~rclk;
//只寫(xiě)的任務(wù)
task wr_only;
begin
@(negedge wclk)begin
wr_en=1'b1;
rd_en=1'b0;
din={$random}%(2^FIFO_WIDTH);//生成0~2^FIFO_WIDTH-1的隨機(jī)數(shù)
end
end
endtask
//只讀的任務(wù)
task rd_only;
begin
@(negedge rclk)begin
rd_en=1'b1;
wr_en=1'b0;
end
end
endtask
//讀寫(xiě)的任務(wù)
task wr_rd;
begin
@(negedge rclk)begin
rd_en=1'b1;
end
@(negedge wclk)begin
wr_en=1'b1;
din={$random}%(2^FIFO_WIDTH);
end
end
endtask
FIFO_asyn FIFO_asyn_u
(
. wclk (wclk),
. rclk (rclk),
. wr_rstn (rstn),
. rd_rstn (rstn),
. wr_en (wr_en),
. rd_en (rd_en),
. din (din),
. empty (empty),
. full (full),
. dout (dout)
);
endmodule
5.2 仿真結(jié)果
可以看到,讀寫(xiě)過(guò)程都按照各自的時(shí)鐘頻率進(jìn)行,空滿標(biāo)志可以正確產(chǎn)生。
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-772327.html
??如果覺(jué)得文章對(duì)你有所幫助的話,別忘了點(diǎn)個(gè)收藏和贊哦~
??更多優(yōu)質(zhì)內(nèi)容可瀏覽本人主頁(yè)??,期待再次與你相遇!
????????????小瑞同學(xué)的博客主頁(yè)????????????文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-772327.html
到了這里,關(guān)于FPGA中FIFO的應(yīng)用(二)——異步FIFO設(shè)計(jì)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!