Quartus Ⅱ呼叫FIFO IP核方法實現求和(Mega Wizard)

Handat發表於2024-07-11

摘要:本次實驗學習記錄主題為“FIFO_IP核實現算術求和”,主要內容是上位機透過串列埠向FPGA傳送一定規格的數字矩陣,FPGA對矩陣處理,按規定邏輯實現求和運算,將結果返回串列埠轉發至上位機。

晶片型號:cyclone Ⅳ EP4CE10F17C8

平臺工具:Quartus II 15.0 (64-bit)、Modelsim SE-64 10.4

最終框圖:

image


【FIFO IP核概述及呼叫】

FIFO(First In First Out,先入先出) IP核作為資料緩衝區,能臨時儲存從資料來源接收的資料,直到資料被其他處理單元再次讀取。FIFO IP核通常用於多位元資料的跨時鐘域處理以及前後頻寬不同步情況,平衡資料來源和處理單元之間的速度差異,同時減少因速率不匹配而導致的等待時間或資料丟失。

FIFO IP核支援同步(SCFIFO)和非同步(DCFIFO)操作模式,在同步模式下,讀寫操作在同一時鐘域下進行。其支援可配置的引數(如資料寬度、深度等,調整以適應不同的需求。針對不同模式的選擇,需要考慮方面包括時鐘源、存取位寬和深度、以及一系列輔助設計的標誌訊號和操作訊號。

下圖為Quartus Ⅱ構建IP核能產生的全部介面,同步模式下,除了基本的外介面如資料位、時鐘、寫標誌和讀標誌、計數位usedw外,還有清零操作(同步sclr/非同步aclr)、滿/近滿/空/近空/校檢eccstatus訊號。而非同步模式下,對於入棧和出棧輔助設計的分為了兩批,具體結構如下圖。

image

訪問IP Catalog:在Quartus Ⅱ的選單欄中,點選“Tools”選項,然後選擇“IP Catalog”或者“MegaWizard Plug-In Manager”,開啟“fifo”選項即可。FIFO配置流程分為三部分:parameter settings、EDA和summary。如下圖的配置介面,在其左上可以實時看到配置產生的介面,左下角看到FIFO在FPGA所產生的資源消耗。

image

在配置完基本引數後,FIFO還支援功能等設定趨向,rdreq讀取驅動:訊號作為請求,資料滯後一個時鐘週期輸出;訊號作為確認,資料同時輸出。儲存方式和最大深度選擇自動匹配即可。FIFO效能支援最大速度和最小消耗資源空間兩種,可根據具體工程需求選定。黃色方框內是上級檢測和下級檢測保護電路,即儲存棧滿和棧空情況下的繼續操作保護,最小面是儲存空間位置選擇,這裡預設選定內部儲存塊即可。

image

非同步模式下,還需配置速度和穩定性的最佳化方式,一是保持最低延遲,但需要同步時鐘,沒有亞穩態保護,佔用資源空間最小,提供良好效能;二是具備兩個同步階段和良好的亞穩態保護,資源空間消耗中等;三是提高最佳的亞穩態保護,具有三個或更多同步階段。

image

【IP核的同步、非同步呼叫及模擬驗證】

首先,構建一個同步FIFO_IP核,具體配置如下:

almost_empty_value = 20,	//近空閾值
almost_full_value = 220,	//近滿閾值
intended_device_family = "Cyclone IV E",	//FPGA IP核型號
lpm_numwords = 256,			//FIFO深度
lpm_showahead = "OFF",		//rdreq模式選擇
lpm_type = "scfifo",		//FIFO工作模式(同步,單時鐘模式)
lpm_width = 8,				//時鐘源同步下,進入FIFO位寬
lpm_widthu = 8,				//計數位寬

IP的直接呼叫inst.v模組檔案即可,例項化應用後,透過一個簡單的錄入核/退出核模擬(如下兩圖)。可以看到,程式啟動,持續向核內寫入256個8bit資料,模擬設定,寫入週期是讀入週期的四倍。

計數到20時,退出近空閾值,近空訊號拉低;計數到220,達到近滿閾值,近滿訊號拉高,等到寫入完畢(這裡計數單元usedw_sig溢位,顯示8'h00),滿訊號拉高。下一週期,讀標誌拉高,讀取一個8bit資料後,滿訊號拉低,持續讀取完畢。

image

構建一個非同步混合FIFO_IP核,具體配置如下:

add_usedw_msb_bit = "ON",	//為計數位擴充一位,避免溢位
intended_device_family = "Cyclone IV E",	//FPGA IP核型號
lpm_numwords = 256,			//FIFO深度
lpm_showahead = "OFF",		//rdreq模式選擇
lpm_type = "dcfifo_mixed_widths",	//混合非同步fifo模式,意思是錄入核和退出核位寬不一致
lpm_width = 8,				//錄入核位寬
lpm_widthu = 9,				//計數位寬+1 = 9
lpm_widthu_r = 8,			//讀取退出核位寬
lpm_width_r = 16,			//讀取退出核計數位寬

非同步模式,需要關注時序上的同步(打了兩拍),50MHz的寫時鐘wrclk,25MHz的讀時鐘rdclk。這裡由於寫位寬和讀位寬的不同,要區別寫計數和讀計數的計數方式。

image

【呼叫FIFO實現求和運算】

呼叫Quartus Ⅱ的IP核實現普通求和運算(便於Sobel演算法FPGA學習),左邊是求和模組的框圖,需要複用兩個相同位寬及深度的FIFO IP核,以m x n(5x4)矩陣為例,先對上三行求運算後,持續向下降一行運算,形成一個新的矩陣(m-2) x n形式。

image

FPGA運算:pi_data持續接入資料,先將第一、二行資料分佈存入FIFO 1核和2核內,在第三行資料開始,同步讀取兩核一個資料,並對其作求和運算,透過po_data輸出。求和的同時,將FIFO 2核內資料寫入1核(1、2核此時為空),即第二行充當原先的第一行。第三行寫入2核,第四行持續運算.......

時序圖如下,pi_flagpi_data是串列埠rx模組接收上位機處理後的資料,錄入此fifo_disp模組。矩陣的列和行計數器cnt_rowcnt_rol作為的順序標誌,方便確認求和準備。dout_flag條件(wr_en2)&&(rd_en),標誌建立用於1核資料再次寫入。借入標誌訊號sum_flag,觸發求和po_data=data_out1+data_out2+pi_data

image

對應的各訊號時序條件處理,程式碼如下:

always@(posedge sys_clk or negedge sys_rst)begin	//dispose cnt_row counter
    if(!sys_rst)	cnt_row <=  8'd0;
    else    if((cnt_row == CNT_ROW_MAX)&&(pi_flag))	cnt_row <=  8'd0;
    else    if(pi_flag)	cnt_row <=  cnt_row + 1'b1;
end

always@(posedge sys_clk or negedge sys_rst)begin	//dispose cnt_col counter
    if(!sys_rst)	cnt_col <=  8'd0;
    else    if((cnt_col == CNT_COL_MAX)&&(pi_flag)&&(cnt_row == CNT_ROW_MAX))
        cnt_col <=  8'd0;
    else    if((cnt_row == CNT_ROW_MAX)&&(pi_flag))cnt_col <=  cnt_col + 1'b1;
end

always@(posedge sys_clk or negedge sys_rst)begin	//dispose wr_en1 drive
    if(!sys_rst)	wr_en1  <=  1'b0;
    else    if((cnt_col == 8'd0) && (pi_flag))	wr_en1  <=  1'b1;
    else	wr_en1  <=  dout_flag;
end

always@(posedge sys_clk or negedge sys_rst)begin	//dispose data_in1 sequence
    if(!sys_rst)	data_in1  <=  8'd0;
    else    if((pi_flag)&&(cnt_col == 8'd0))	data_in1  <=  pi_data;
    else    if(dout_flag == 1'b1)	data_in1  <=  data_out2;
    else	data_in1  <=  data_in1;
end

always@(posedge sys_clk or negedge sys_rst)begin	//dispose wr_en2 drive
    if(!sys_rst)	wr_en2  <=  1'b0;
    else    if((cnt_col >= 8'd1)&&(cnt_col <= CNT_COL_MAX - 1'b1)&&(pi_flag))
        wr_en2  <=  1'b1;
    else	wr_en2  <=  1'b0;
end

always@(posedge sys_clk or negedge sys_rst)begin	//dispose data_in2 sequence
    if(!sys_rst)	data_in2  <=  8'b0;
    else    if((pi_flag)&&(cnt_col >= 8'd1)&&(cnt_col <= (CNT_COL_MAX - 1'b1)))
        data_in2  <=  pi_data;
    else	data_in2  <=  data_in2;
end

always@(posedge sys_clk or negedge sys_rst)begin	//dispose rd_en drive
    if(!sys_rst)	 rd_en <=  1'b0;
    else    if((pi_flag)&&(cnt_col >= 8'd2)&&(cnt_col <= CNT_COL_MAX)) rd_en <=  1'b1;
    else	rd_en <=  1'b0;
end

always@(posedge sys_clk or negedge sys_rst)begin	//dispose dout_flag sequence
    if(!sys_rst)	dout_flag <=  0;
    else    if((wr_en2)&&(rd_en))	dout_flag <=  1'b1;
    else	dout_flag <=  1'b0;
end

always@(posedge sys_clk or negedge sys_rst)begin	//dispose sum_flag sequence
    if(!sys_rst)	sum_flag <=  1'b0;
    else    if(rd_en)	sum_flag <=  1'b1;
    else    sum_flag <=  1'b0;
end

always@(posedge sys_clk or negedge sys_rst)begin	//dispose po_data result
    if(!sys_rst)	po_data  <=  8'b0;
    else    if(sum_flag)	po_data  <=  data_out1 + data_out2 + pi_data;
    else	po_data  <=  po_data;
end

always@(posedge sys_clk or negedge sys_rst)begin	//dispose po_flag sequence
    if(!sys_rst)	po_flag <=  1'b0;
    else 	po_flag <=  sum_flag;
end

模擬分析:很明顯,模擬圖與上面的時序圖一致,tx、rx模組在之前的實驗經過模擬驗證了。

image

最後,將程式下載至開發板,得到的資料與模擬結果一樣,簡單做了兩次測試,結果都正確。

image

文獻參考:

[1] FIFO求和實驗 野火FPGA Verilog開發實戰指南——基於Altera EP4CE10 征途Pro開發板 文件 (embedfire.com);

[2] 掰開揉碎講 FIFO(同步FIFO和非同步FIFO) - Doreen的FPGA自留地 - 部落格園 (cnblogs.com)


本篇文章中使用的Verilog程式模組,若有需見網頁左欄Gitee倉庫連結:https://gitee.com/silly-big-head/little-mouse-funnyhouse/tree/FPGA-Verilog/

相關文章