fifo的使用方式有很多種且方法靈活,這里不再做贅述??梢詤⒖紉ilinx?pg057文檔及中研院總結的”fifo的使用”文檔。本文檔只推薦一種常用的native接口的fifo使用的建議方式,以滿足大多數的應用場景。
1?Fifo的定制
- 通常情況選擇independent clock模式,這樣讀寫時鐘是否同源都可以支持,便于后期維護修改。
- 根據所需深度選擇distributed ram 與 blockram類型,原則上小的fifo建議使用distributed?ram類型以節(jié)省block?ram資源。
- 選擇Standard 或FWFT模式,選擇StandardFIFO ,默認為1clk延遲,FWFT無延時。當block?ram類型時,可以選擇添加output?registers,在復雜布線情況下應該有助于布線結果,當然此時為2clk延遲。
- 使能resetpin,使能 reset?synchronization,Full flags reset value值為1。
- 如果采用Prog_full信號反壓寫信號,需要根據鏈路延遲合理設置fullthreshold。
- 根據需要使能wr_data_cnt 和 rd_data_cnt。
2?fifo的復位
- 采用讀寫時鐘中的慢速時鐘產生至少8clk的復位信號進行fifo復位 , 若采用快時鐘產生,保證產生寬度滿足以上條件亦可。
- 復位完成后至少等待60個慢時鐘周期再進行讀寫操作,嚴格來講需要等待full信號拉低才可以(異步復位模式,Full flags reset value值為1)。此處以附帶safetycircuit為例,若不帶safety?circuit,時間要比這個短,但在視頻幀結構應用中,只要復位的時機合理,都可以保證此要求。
- 復位過程中嚴禁讀寫操作。
- 通常在視頻幀結構處理中,采用視頻vs的后沿構造,并滿足以上需求。
- 復位過程時鐘必須是穩(wěn)定的。
3?fifo的讀寫控制邏輯
通常fifo的寫使能和寫數據由fifo的前后讀寫速度或progfull決定,保證fifo不應該被寫溢出,且要保證在復位時刻寫使能為0。
通常可以采用非空信號作為讀使能(RST拉起來后empty也會拉高,可以保證復位時無讀使能)。
也可以采用rd_data_cnt構造讀使能。
也可以由獨立的時序構造讀使能,只要能從fifo的讀寫帶寬上保證讀使能來的時候fifo中一定由足夠的數據即可。
建議對滿寫overflow和和空讀underflow進行監(jiān)測。
4?example
4.1?Example1
該用例可以應用于數據需要跨時鐘域傳輸時,讀端時鐘速率大于等于寫端時鐘,或者是讀端時鐘速率略小于寫端時鐘速率,但可以利用數據流的行間隔時間以及合理的fifo深度,保證所有寫入的數據均能夠及時讀出而不被新寫入的數據覆蓋。
此種應用時,fifo的復位可以是上電一次合理時間的復位,若是視頻流,建議在視頻垂直逆程通過vs的沿構造合理的周期性復位。
reg [9:0] vs_dly;
always @ (posedge wr_clk)
begin
vs_d0 <= vs;
vs_d1 <= vs_d0;
vs_d2 <= vs_d1;
end
assign vs_pos = vs_d1 && (!vs_d2);
always @ (posedge wr_clk)
begin
vs_dly <= {vs_dly[8:0],vs_pos};
end
always @ (posedge wr_clk)
begin
fifo_rst <= |vs_dly[9:0];
end
AsyFifo_Std_64x36 inst_RxFifo(
.rst ( fifo_rst ),
.wr_clk ( wr_clk ), // 27M~165M
.rd_clk ( rx_clk ), // 162.5M
.din ( wr_dat[35:0] ),
.wr_en ( wr_en ), // video in en
.rd_en ( rd_en ),
.dout ( rd_dat[35:0] ),
.full ( full ),
.empty ( empty ),
.valid ( )
);
assign rd_en =~empty;
always @ (posedge RxClk)
begin
rd_en_d1 <= rd_en ;
fifo_rx_vld <= rd_en_d1;
fifo_rd_dat[35:0] <= rd_dat[35:0];
end
4.2?Example2
本用例采用prog_full信號反壓寫端數據流,從而保證fifo的讀寫的速率匹配。通常可用在fifo前端的數據已經在一個緩存中,并且可以隨時訪問。這樣可以通過這個機制跨到fifo的讀時鐘域下。這里需要根據鏈路的延遲合理時鐘progfull的閾值。
assign rd_ram_en = ~prog_full;
always@(posedge wr_clk)
begin
rd_ram_en_d1 <= rd_ram_en;
wr_en <= rd_ram_en_d1;
wr_dat <= rd_ram_dat;
end
AsyFifo_Std_64x36 RxFifo(
.rst ( fifo_rst ),
.wr_clk ( wr_clk ),
.rd_clk ( rd_clk ),
.din ( wr_dat[35:0] ),
.wr_en ( wr_en ),
.rd_en ( ~empty),
.dout ( rd_dat[35:0] ),
.full ( ),
.empty ( empty ),
.valid ( rx_vld ),
.prog_full( prog_full)
);
always @(posedge rd_clk)
begin
vin_de_out <= rx_vld;
vin_data_out <= rd_dat;
end
4.2?Example3
該用例是典型的通過判斷fifo中數據量構造讀取fifo的邏輯,寫端數據流可以不間斷的寫入fifo。所以需要保證fifo的讀取速率能夠大于寫入速率。
通常如果有多路異步數據流需要同步到同一處理時鐘域的時候,可以采用此種方式,只需保證讀時鐘大于寫時鐘即可。
讀取fifo的使能信號還可以作為所有這路數據流后續(xù)所有處理邏輯的clock enable信號,以達到減少動態(tài)功耗的目的。
當然如果不采用ce的方式,也可以用讀使能與上數據流中的嵌入的de,構造出新的數據使能信號。(寫使能的機制能夠保證所有數據能從fifo中讀出)
assign wr_en = (fifo_rst || full) ? 0 : 1;
always@(posedge proc_clk)
begin
if(rd_dat_cnt >= 8) // 根據fifo深度合理設置即可
rd_set <= 1'b1;
else
rd_set <= 1'b0;
end
always@(posedge proc_clk)
begin
if(rd_dat_cnt<=4)// 根據fifo深度合理設置即可
rd_clear <= 1'b1;
else
rd_clear <= 1'b0;
end
always@(posedge proc_clk)
begin
if(rd_set)
rd_en <= 1'b1;
else if(rd_clear)
rd_en <= 1'b0;
else
rd_en <= rd_en;
end
AsyFifo_Std_64x24 inst_RxFifo(
.rst (fifo_rst ),
.wr_clk ( video_in_clk), //27M~165M
.rd_clk ( proc_clk ), //200M
.din ( {video_in_de,video_in_data[23:0]} ),
.wr_en ( wr_en ),
.rd_en ( rd_en ),
.dout ( rd_dat[24:0] ),
.full ( full ),
.empty ( ),
.rd_data_count(rd_dat_cnt)
);
always @(posedge proc_clk)
begin
if(rd_en)
begin
vin_de_out <= rd_dat[24];
vin_data_out <= rd_dat[23:0];
end
end
assign clk_ce = rd_en;
or
always @(posedge proc_clk)
begin
vin_de_out <= rd_dat[24] && rd_en;
vin_data_out <= rd_dat[23:0];
end