FIFO的使用非常廣泛,一般用于不同時(shí)鐘域之間的數(shù)據(jù)傳輸名扛,比如FIFO的一端是AD數(shù)據(jù)采集,另一端是計(jì)算機(jī)的PCI總線茧痒,假設(shè)其AD采集的速率為16位100K SPS肮韧,那么每秒的數(shù)據(jù)量為100K×16bit=1.6Mbps,而PCI總線的速度為33MHz,總線寬度32bit,其最大傳輸速率為33*32=1056Mbps,在兩個(gè)不同的時(shí)鐘域間就可以采用FIFO來(lái)作為數(shù)據(jù)緩沖旺订。另外對(duì)于不同寬度的數(shù)據(jù)接口也可以用FIFO弄企,例如單片機(jī)位8位數(shù)據(jù)輸出,而DSP可能是16位數(shù)據(jù)輸入区拳,在單片機(jī)與DSP連接時(shí)就可以使用FIFO來(lái)達(dá)到數(shù)據(jù)匹配的目的拘领。
本文就講通過(guò)ISE軟件生成一個(gè)FIFO,并對(duì)其進(jìn)行一些操作以求更加了解FIFO中各個(gè)信號(hào)的作用以及控制方法(有些簡(jiǎn)單步驟將省略不提)樱调。
在這步中院究,由于現(xiàn)在做的不是soc工程,選擇Native.
Next后本涕,需選擇時(shí)鐘和存儲(chǔ)器類(lèi)型业汰。1,時(shí)鐘菩颖,由FIFO的作用可知大部分都是讀寫(xiě)不同步的样漆,這里我們也選擇異步模式,即讀寫(xiě)的時(shí)鐘不同晦闰。2放祟,存儲(chǔ)器類(lèi)型鳍怨,這里主要是block RAM和distribute RAM之間的區(qū)別。簡(jiǎn)而言之跪妥,block RAM是FPGA中定制的ram資源鞋喇,而distribute RAM則是由LUT構(gòu)成的RAM資源。由此區(qū)別表明眉撵,當(dāng)FIFO較大時(shí)應(yīng)選擇block RAM侦香,當(dāng)FIFO較小時(shí),選擇distribute RAM.另外一個(gè)很重要的就是block RAM支持讀寫(xiě)不同寬度纽疟,而distribute不支持罐韩。在這里為了更全面的了解FIFO,選擇block RAM以擁有非對(duì)稱方向速率的特性污朽。
讀模式有兩種選擇散吵,一般選擇標(biāo)準(zhǔn)模式,至于First-Word Fall-Fhrough的含義請(qǐng)查看FIFO手冊(cè)蟆肆。寫(xiě)數(shù)據(jù)寬度定義為8位矾睦,寫(xiě)深度定義為256.讀寬度定義為4位,而讀深度將根據(jù)以上幾個(gè)參數(shù)自動(dòng)計(jì)算炎功。但我們需要注意的是顷锰,在data port parameters處,有actual write depth和actual read depth,他們都比我們?cè)O(shè)置的要小亡问,其意義以及原因?qū)⒃诶讨姓f(shuō)明官紫。
之后便是添加信號(hào),信號(hào)越多越難操作州藕,但同時(shí)也能讓我們更加準(zhǔn)確的控制FIFO束世,這里為了更好的了解FIFO,把所有能選的信號(hào)都選上床玻。
接下來(lái)是復(fù)位信號(hào)以及可編程信號(hào)的配置毁涉。雖然在block RAM和distribute RAM中,復(fù)位信號(hào)不是必需的锈死,但根據(jù)習(xí)慣贫堰,還是啟用rst端口,且配置成同步復(fù)位待牵,即整個(gè)FIFO共用一個(gè)復(fù)位信號(hào)其屏,而不是讀寫(xiě)不同的復(fù)位。至于編程信號(hào)缨该,看選項(xiàng)就很容易理解了偎行。配置如圖,F(xiàn)IFO中數(shù)據(jù)達(dá)到200時(shí),programmable full有效蛤袒,數(shù)據(jù)為10時(shí)熄云,programmable empty有效。
之后是寫(xiě)計(jì)數(shù)和讀計(jì)數(shù)妙真,都使之有效缴允,由于寫(xiě)深度是256,讀深度是512.因此寫(xiě)計(jì)數(shù)器的寬度定義為8珍德,讀計(jì)數(shù)器的狂度定義為9.其實(shí)不一定計(jì)數(shù)器一定要比深度大练般,當(dāng)計(jì)數(shù)器計(jì)數(shù)最大值小于數(shù)據(jù)深度時(shí),例如數(shù)據(jù)深度為512菱阵,而計(jì)數(shù)器大小為256踢俄,則每?jī)蓚€(gè)數(shù)據(jù)計(jì)數(shù)器計(jì)數(shù)一次缩功。
最后可以看到我們配置的FIFO信息如下(注意幾個(gè)關(guān)鍵信息)晴及,最后生成IP就好了。
通過(guò)點(diǎn)擊View HDL Instantiation Template,我們可以看到所有需要例化的信號(hào)嫡锌,以及格式虑稼。
在該FIFO例程中,首先是將1-255寫(xiě)入FIFO中势木,此時(shí)不讀取蛛倦,觀察各個(gè)信號(hào),然后再?gòu)腇IFO中讀出FIFO中存儲(chǔ)的數(shù)據(jù)啦桌,此時(shí)不再寫(xiě)入溯壶,觀察各信號(hào)。
代碼如下:
module FIFO_top(
input clk,rst,
output wire [3:0] dout
);
wire clk_50M_wire;
wire [7:0] din_wire;
wire valid,wr_ack;
wire overflow,underflow;
wire almost_empty,almost_full;
wire [8:0] rd_data_count;
wire [7:0] wr_data_count;
wire prog_full,prog_empty;
wire wr_en,rd_en;
wire full,empty;
///////////////////////////////////////////////////
//二分頻電路
//100M為讀時(shí)鐘甫男,50M為寫(xiě)時(shí)鐘
reg clk_50M;
assign clk_50M_wire = clk_50M ;
always @(posedge clk or posedge rst) begin
if (rst) clk_50M<=0;
else clk_50M<=~clk_50M;
end
///////////////////////////////////////////////
////////////////////////////////////////////////
reg [2:0] cnt;
assign wr_en =(full==0 && rd_en==0 && cnt==5)?1:0 ;//非滿時(shí)寫(xiě)且改,且滿后就不再寫(xiě)了,即便之后數(shù)據(jù)被讀取導(dǎo)致非滿
assign rd_en = (empty==0 && wr_en==0)?1:0 ;//寫(xiě)時(shí)不讀取板驳,寫(xiě)完再讀取
reg [7:0] din;
assign din_wire = din ;
always @(posedge clk_50M or posedge rst) begin
if (rst) begin
din<=1;
end
else begin
if(wr_en) din<=din+1;
else din<=din;
end
end
always @ (posedge clk_50M or posedge rst)
if(rst) cnt<=0;
else begin
if(cnt==3'd5) cnt<=cnt;
else cnt<=cnt+1;
end
FIFO FIFO (
.rst(rst), // input rst
.wr_clk(clk_50M_wire), // input wr_clk 50M
.rd_clk(clk), // input rd_cFIFOlk 100M
.din(din_wire), // input [7 : 0] din
.wr_en(wr_en), // input wr_en
.rd_en(rd_en), // input rd_en
.dout(dout), // output [3 : 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
.rd_data_count(rd_data_count), // output [8 : 0] rd_data_count
.wr_data_count(wr_data_count), // output [7 : 0] wr_data_count
.prog_full(prog_full), // output prog_full 200
.prog_empty(prog_empty) // output prog_empty 10
);
endmodule
1又跛,復(fù)位信號(hào)rst: 由結(jié)果可知,其為高電平有效若治,且復(fù)位后其他信號(hào)的初始值是可以在產(chǎn)生FIFO中配置的慨蓝,之前配置為0;很重要的一點(diǎn)是端幼,復(fù)位后的幾個(gè)寫(xiě)周期內(nèi)(2,3個(gè)周期)是無(wú)法進(jìn)行寫(xiě)操作的礼烈,所以在本例程中,復(fù)位一段時(shí)間后再拉高wr_en以確保首先寫(xiě)入的是1.
2婆跑,寫(xiě)使能信號(hào)wr_en與寫(xiě)響應(yīng)信號(hào)wr_ack:關(guān)于該信號(hào)济丘,很重要的一點(diǎn)是,寫(xiě)入的值是wr_en拉高時(shí)的值;還是說(shuō)當(dāng)wr_en拉高后摹迷,下一周期才能進(jìn)行寫(xiě)操作疟赊?如果是前者,由波形所示峡碉,寫(xiě)入的第一個(gè)值應(yīng)該是1近哟;如果是后者,寫(xiě)入的應(yīng)該是2鲫寄。這就需要根據(jù)讀取的第一個(gè)值來(lái)判斷了吉执。而經(jīng)查看,讀取的第一個(gè)值為1地来,也就是說(shuō)戳玫,只要wr_en拉高,立馬就進(jìn)行寫(xiě)操作未斑。
從下圖還能明白wr_ack的工作模式咕宿,即寫(xiě)入成功時(shí),wr_ack將在下一周期拉高蜡秽。也就是說(shuō)府阀,wr_ack反映的是上一周期的寫(xiě)操作。
3芽突,讀使能信號(hào)rd_en與讀響應(yīng)信號(hào)valid:在讀操作中试浙,第一個(gè)讀取的數(shù)據(jù)應(yīng)該是0,第二個(gè)是1(原因之后解釋?zhuān)┠觥S刹ㄐ慰芍锇停?dāng)rd_en有效的那個(gè)上升沿,并沒(méi)有進(jìn)行讀操作挟秤,而是在下一個(gè)周期才真正讀取了數(shù)據(jù)壹哺,同時(shí)valid被拉高,這是與寫(xiě)操作所不同的地方煞聪。
4斗躏,寫(xiě)計(jì)數(shù)wr_data_count和rd_data_count:因?yàn)閷?xiě)數(shù)據(jù)會(huì)有256個(gè),讀數(shù)據(jù)會(huì)有512個(gè)昔脯,一旦count的大小不夠啄糙,count從一開(kāi)始就會(huì)失效,成為高阻態(tài)云稚,所以應(yīng)該給wr_data_count設(shè)置成8位隧饼,rd_data_count設(shè)置成9位。當(dāng)把wr_data_count設(shè)置成7位静陈,rd_data_count設(shè)置成8位時(shí)燕雁,結(jié)果見(jiàn)圖诞丽。
正常設(shè)置時(shí),即wr_data_count設(shè)置成8位拐格,rd_data_count設(shè)置成9位僧免。
在寫(xiě)的過(guò)程中,可以看到捏浊,wr_data_count正常計(jì)數(shù)懂衩,每次加一,但是其值滯后2個(gè)周期金踪。而由于讀操作是每次4位浊洞,寫(xiě)操作是每次8位,即每次寫(xiě)操作都意味著需要讀兩次才能讀出數(shù)據(jù)胡岔,所以每次寫(xiě)操作法希,rd_data_count都是加2。
在讀過(guò)程中靶瘸,rd_data_count是每次減1苫亦。同理,wr_data_count則是每2次讀操作才減1奕锌。
對(duì)于這兩個(gè)信號(hào)著觉,也有不太正常的地方村生。如下圖惊暴,當(dāng)進(jìn)行了讀操作的時(shí)候,wr_data_count依舊保持在255不變趁桃,rd_data_count則在505和504之間切換辽话,且其最大值不是預(yù)期的510.
可能的原因在于wr_data_count是屬于寫(xiě)時(shí)鐘域的,讀操作進(jìn)行后需要一段時(shí)間才能反映到寫(xiě)時(shí)鐘域的各個(gè)參數(shù)卫病,這在之后的empty等信號(hào)也可以得出類(lèi)似結(jié)論油啤。
至于rd_data_count應(yīng)該是受讀操作以及full或者wr_data_count等信號(hào)的共同影響,導(dǎo)致其在505和504之間不停變換蟀苛。
官方文檔也提到說(shuō)益咬,wr_data_count以及rd_data_count是大概的,不是非常準(zhǔn)確帜平。
5幽告,prog_full;almost_full;full:Prog_full在之前的設(shè)置中是200,該值是根據(jù)wr_data_count判定的裆甩,即當(dāng)wr_data_count為200時(shí)冗锁,prog_full置一。但是由于wr_data_count滯后2個(gè)周期嗤栓,所以真正寫(xiě)入到FIFO中的值應(yīng)該有202個(gè)了冻河。
full以及almost_full由圖可知箍邮,在數(shù)據(jù)數(shù)滿足要求后的下一個(gè)周期被拉高。而且當(dāng)讀操作進(jìn)行后叨叙,這兩個(gè)信號(hào)并不是立刻被拉低锭弊,和之前所提到的一樣,這兩個(gè)信號(hào)屬于寫(xiě)時(shí)鐘域擂错,讀操作反映到這兩個(gè)信號(hào)上需要一定的時(shí)間
6廷蓉,prog_empty;almost_empty;empty:
Prog_empty之前設(shè)置的是10,由波形圖知马昙,其信號(hào)還是比較準(zhǔn)確的桃犬。
Almost_empty以及empty則提早了一個(gè)周期被拉高
也可以看到,當(dāng)寫(xiě)操作進(jìn)行時(shí)行楞,empty等信號(hào)也不是立刻變低的攒暇,其原因也應(yīng)該是屬于不同時(shí)鐘域。
7子房,underflow;overflow: 改動(dòng)程序形用,使寫(xiě)信號(hào)一直有效,可以看到當(dāng)full變高后的下一周期因?yàn)槔^續(xù)進(jìn)行寫(xiě)操作证杭,使得overflow也被拉高田度。
再改動(dòng)程序,寫(xiě)操作一段時(shí)間后解愤,讀信號(hào)一直有效镇饺。可以看到當(dāng)empty有效后送讲,繼續(xù)讀操作奸笤,underflow將在下一周期被拉高。
8哼鬓,關(guān)于FIFO實(shí)際讀寫(xiě)深度的問(wèn)題:在之前的設(shè)置中可以看到监右,我們?cè)驹O(shè)置的寫(xiě)深度是256,讀深度是512异希;但是邊上顯示的實(shí)際讀寫(xiě)深度分別是255,510.從結(jié)果中我們也可以看到:當(dāng)寫(xiě)到255時(shí)(數(shù)據(jù)是1~255)健盒,full被拉高。讀數(shù)據(jù)以及讀數(shù)據(jù)深度是根據(jù)寫(xiě)數(shù)據(jù)和寫(xiě)深度來(lái)的称簿,自然也就是510了扣癣。也就是說(shuō)實(shí)際寫(xiě)深度會(huì)比設(shè)置的小1,這是在工程中需要注意的地方予跌。
9搏色,關(guān)于讀寫(xiě)不對(duì)稱的問(wèn)題:所謂的讀寫(xiě)不對(duì)稱,即讀寫(xiě)的位大小以及讀寫(xiě)速率不一樣券册。在本例程中频轿,寫(xiě)入的數(shù)據(jù)是8位的垂涯,而讀出的數(shù)據(jù)是4位的。那么讀操作的時(shí)候是怎么樣一個(gè)讀出法呢航邢?在寫(xiě)操作中耕赘,我們是順序?qū)懭?~255的。通過(guò)觀察讀數(shù)據(jù)可知膳殷,讀出的數(shù)據(jù)為:0,1,0,2,0,3……這就說(shuō)明當(dāng)讀寫(xiě)非對(duì)稱時(shí)操骡,是先讀取數(shù)據(jù)的高位的。
10赚窃,關(guān)于FIFO的深度計(jì)算問(wèn)題:在很多筆試面試中册招,都會(huì)問(wèn)的FIFO的深度計(jì)算問(wèn)題。因此勒极,了解這方面也是很有必要的是掰。
網(wǎng)上有很多關(guān)于這方面的公式,在此就不做討論了辱匿。其實(shí)很簡(jiǎn)單键痛,只要先計(jì)算單位時(shí)間內(nèi)讀寫(xiě)數(shù)據(jù)量的差值,然后乘以持續(xù)時(shí)間匾七,就是FIFO的最小深度了絮短。但是這里還需要注意幾點(diǎn):
1,背靠背問(wèn)題昨忆,假設(shè)寫(xiě)數(shù)據(jù)100個(gè)wr_clk內(nèi)寫(xiě)入80個(gè)數(shù)據(jù)丁频,這時(shí)就需要考慮最壞的情況,就是前20個(gè)時(shí)鐘不寫(xiě)入扔嵌,接著80個(gè)時(shí)鐘寫(xiě)入限府,再后來(lái)的80個(gè)時(shí)鐘繼續(xù)寫(xiě)入夺颤,最后的20個(gè)時(shí)鐘不寫(xiě)入痢缎。這樣寫(xiě)入數(shù)據(jù)最集中的情況就有160個(gè)時(shí)鐘寫(xiě)入160個(gè)數(shù)據(jù)了。
2世澜,需要留有深度裕量独旷,即實(shí)際的深度會(huì)比設(shè)置的小,因此應(yīng)該多設(shè)置點(diǎn)FIFO深度寥裂,以避免丟失數(shù)據(jù)嵌洼。