1)摘自【正點原子】領航者ZYNQ之HLS 開發指南
2)實驗平臺:正點原子領航者ZYNQ開發板
3)平臺購買地址:https://item.taobao.com/item.htm?&id=606160108761
4)全套實驗源碼+手冊+視頻下載:http://www.openedv.com/docs/boards/fpga/zdyz_linhanz.html
5)對正點原子FPGA感興趣的同學可以加群討論:876744900
6)正點原子資料更新和新品發布,請加正點原子公眾號:正點原子
關注方法:微信→添加好友→公眾號→輸入:正點原子
第三章按鍵控制LED實驗
在第一章節我們通過LED閃爍實驗學習了如何通過HLS來生成一個帶有輸出接口的IP核。在本章我們通過按鍵控制LED實驗,來學習如何使用Vivado HLS工具生成一個帶有輸入和輸出接口的IP核,並學習Vivado HLS工具仿真平臺的使用,以及在Vivado中對綜合結果進行驗證的流程。
本章包括以下幾個部分:
33.1簡介
3.2實驗任務
3.3HLS設計
3.4IP驗證
3.5下載驗證
3.1簡介
在使用Vivado HLS工具進行設計的時候,如果設計完成之後發現功能不正確,然後確定問題產生的原因是非常耗時的。為了提高效率,我們使用測試平臺在設計完成之後驗證C函數在功能上是否正確。
Vivado HLS工具的輸入和輸出如下圖所示:
圖 3.1.1 vivado hls工具的輸入和輸出
從圖中可以看出在Vivado HLS的設計流程中,設計的輸入包括C/C++設計、Testbench(測試集)編寫以及Constraints(約束)/directives(指令)的添加。Vivado HLS最主要的輸出結果是以VHDL/Verilog語言描述的RTL實現,並打包成IP模塊的形式以方便Xilinx設計工具使用,如System Generator等。
我們可以使用C testbench在綜合之前對C函數進行仿真,驗證函數的輸出的正確性,這一過程被稱之為C仿真,對應於圖中的「C Simulation」。它還可以在綜合之後對綜合得到的RTL設計進行仿真,這一仿真過程同樣是使用C testbench進行的,這一過程被稱為C/RTL協同仿真,對應於圖中的「RTL Simulation」。
3.2實驗任務
本章的實驗任務是使用領航者底板上的 PL_KEY0 和 PL_KEY1 按鍵來控制底板上的 PL_LED0 和 PL_LED1 兩個 LED。沒有按鍵按下時,兩個 LED 保持常亮;如果按鍵 0 按下,則PL_LED0熄滅;如果 按鍵 1 按下,則PL_LED1熄滅。要求使用C語言完成設計,然後綜合得到RTL級實現並進行驗證。
3.3HLS設計
我們在電腦中的「F:\ZYNQ\High_Level_Synthesis」目錄下新建一個名為key_led的文件夾,作為本次實驗的工程目錄。然後打開Vivado HLS工具,創建一個新的工程。設置工程名為「key_led_hls」,選擇工程路徑為剛剛創建的文件夾。需要注意的是,工程名以及路徑只能由英文字母、數字和下劃線組成,不能包含中文、空格以及其他特殊字符。如下圖所示:
圖 3.3.1 工程配置界面
設置好工程名及路徑之後,點擊「Next」,進入如下界面:
圖 3.3.2 設置頂層函數
工程創建完成後,在工程面板中的「source」目錄上點擊右鍵,然後在打開的列表中選擇「New File」新建源文件,如下圖所示;
圖 3.3.3 新建源文件
然後在彈出的對話框中輸入源文件的名稱「key_led.c」,如圖 2.3.11所示。源文件默認的保存路徑為HLS工程目錄,為方便源文件的管理,我們在工程目錄下新建一個名為「src」的文件下,將源文件保存在src目錄下。
圖 3.3.4 輸入源文件名
我們在圖 3.3.4中輸入的源文件的後綴名為「.c」,即使用C語言進行設計。如果使用C++語言進行設計,那麼後綴名需要設置為「.cpp」。設置好文件名和路徑之後,點擊「保存」。
在創建了源文件之後,在Vivado HLS工程面板中的Source目錄下可以看到我們新建的源文件:key_led.c,同時信息面板自動打開了該文件的編輯界面,我們可以在裡面輸入C代碼。如下圖所示:
圖 3.3.5 新建的源文件
在圖1.3.5中箭頭所指示的位置輸入本次實驗的原始碼:
在代碼的第1行,包含了一個名為「key_led.h」的頭文件,這個是我們自己創建的頭文件。「key_led.h」的創建方式和「key_led.c」的創建方式相同。創建此頭文件的目的是為了函數聲明,以便在測試文件中引入此頭文件,從而在測試文件中可以調用我們所編寫的函數。在代碼的第3行,我們在定義函數參數類型時,使用了「uint2」這種數據類型,它表示2位無符號整數。
在代碼的第5行到代碼的第6行,#pragma為HLS優化指令,它表示led和key使用的是ap_none協議。在代碼的第7行ap_ctrl_none表明沒有添加包級別的協議,而是完全在埠接口級別用埠級別協議來做控制。在代碼的第9行我們定義了一個key_value變量來寄存按鍵的值。
在第11行到第25行我們根據按鍵的不同值,來控制LED的狀態。這是一個switch case語句。它根據不同的按鍵key的狀態來切換LED的數值。比如:當兩個按鍵的值是3(二進位11),表示沒有按鍵按下,則給LED賦值為3(二進位11),從而點亮兩個LED。
頭文件「key_led.h」的代碼如下:
在代碼的第1行我們引入了「ap_cint.h」的頭文件來包含任意精度數據類型。在代碼的第3行到第4行表示如果沒有定義「key_led.h」頭文件則定義這個頭文件,這樣可以避免頭文件的重複定義。在代碼第6行,我們聲明了按鍵控制LED函數,從而在測試文件中可以調用此函數。
在工程面板中的「Test Bench」目錄上點擊右鍵,然後在打開的列表中選擇「New File」新建測試文件, 在彈出的對話框中輸入測試文件的名稱「key_led_tb.c」,如圖1.3.6所示。測試文件的保存路徑為src目錄。
圖 3.3.6 新建測試文件
在測試文件中編寫如下代碼:
在測試文件中,我們通過調用按鍵控制函數,並給按鍵賦不同的值,來實現按鍵控制的仿真。
代碼輸入完成後,按快捷鍵Ctrl+S保存。然後點擊工具欄中向右的綠色三角形對C代碼進行綜合,如下圖所示:
圖 3.3.7 運行C綜合
綜合完成後,會自動打開綜合結果(solution)的報告,如下圖所示:
圖 3.3.8 綜合報告
在圖1.3.8所示的綜合報告中,給出了設計的性能評估、資源評估以及接口等信息。本次實驗中,我們重點關注綜合工具為我們生成的兩個接口,分別為 「key」、「led」。 從接口信息中,我們可以看到按鍵key的C語言類型是變量,在RTL級別中被映射為輸入埠。led的C語言類型是指針,在RTL級別中被映射為輸出埠。
這是因為HLS規定了協議、埠類型和方向之間的相關性,在Vivado HLS開發過程中,考慮C/C++函數參數的類型是很重要的。Vivado HLS規定可以傳入/傳出C/C++函數的值有四種不同的數據類型,分別是:變量、指針、數組和引用。這也就是說,一種特定的參數類型只對應於有限的幾種協議。比如,傳入一個數組作為形參輸入,能使用的協議就只有:ap_hs、ap_memory、bram、 ap_fifo、ap_bus、axis 和 m_axi,其中 ap_memory 是默認的。參數類型對應支持的接口協議如下圖所示:
圖 3.3.9 參數類型和接口協議的對應圖
本實驗中,我們規定接口所使用的協議為ap_none。圖中的「D」表示「default」,表示Vivado HLS工具默認綜合出來的接口。「S」表示「support」,表示Vivado HLS工具支持綜合出來的接口。從圖中我們可以看出,使用ap_none時,當變量作為形參時,接口只能被綜合成輸入而不能被綜合成輸出,當指針變量作為形參時,接口可以被綜合成輸入、輸出和雙向埠。本節實驗中,我們定義按鍵key的類型為變量,led的類型指針,從而實現了將按鍵key作為輸入接口,led作為輸出接口。
下面我們進行仿真,來測試HLS設計是否滿足要求。點擊工具欄中的仿真按鈕,進入仿真,如下圖所示:
圖 3.3.10 運行C仿真
彈出仿真配置界面,我們在配置界面中啟動C調試器,並清除編譯殘留文件。設置如下圖所示:
圖 3.3.11 C調試器配置界面
點擊「OK」按鈕,打開C調試器,在C調試器工具欄中點擊單步調試按鈕,如下圖所示:
圖 3.3.12 單步調試
執行單步調試,在右側變量觀察窗口中可以看到當按鍵值key為1的時候,*LED值變為了1。如下圖所示:
圖 3.3.13 變量觀察窗口
繼續執行單步調試,可以看到當按鍵值key為2的時候,*led的值變為了2。當按鍵值key為3的時候,*led的值變為了3。這意味著我們已經可以通過按鍵來控制LED的狀態,至此仿真設計完成,通過仿真我們驗證了HLS設計的正確性。下面我們將設計打包成IP模塊,以供Vivado開發套件中的其他工具(如IP集成器)使用。
在工具欄中點擊黃色的「田」字按鈕,導出RTL,如下圖所示:
圖 3.3.14 導出RTL
在彈出的對話框中保持默認設置,直接點擊「OK」,如下圖所示:
圖 3.3.15 將設計導出成IP
設計導出完成後,HLS設計部分就結束了,我們在HLS工程目錄下可以找到導出的IP核,如下圖紅色方框所示:
圖 3.3.16導出得到的IP
我們到計算機工程目錄所指向的文件夾中同樣可以看到以ZIP壓縮文件形式存在的IP核,如下圖所示:
圖 3.3.17 文件夾中的IP核
HLS設計結束之後,我們將在Vivado中對導出的IP核進行驗證。
3.4IP驗證
在IP驗證環節,我們會使用Vivado工具的IP集成器將生成的IP核添加到Block Design中,然後完成設計後將程序下載到領航者開發板上進行驗證。
我們在《領航者ZYNQ之嵌入式開發指南》第一章「Hello World實驗」中詳細介紹了如何使用Vivado創建工程,以及如何使用IP集成器(IP INTEGRATOR)創建Block Design。如果大家對這一部分內容不熟悉的話,一定要先按照《領航者ZYNQ之嵌入式開發指南》中第一章的描述,把這一流程完整的操作一遍,然後才能進行本章的IP驗證環節。
在本次實驗中,我們創建一個名為「key_led_ip_test」的Vivado工程。為了方便工程管理,我們將Vivado工程的目錄與HLS工程目錄保持一致,如下圖所示:
圖 3.4.1 創建Vivado工程
Vivado工程創建完成之後,本次實驗的工程目錄如下圖所示:
圖 3.4.2 按鍵控制LED實驗工程目錄
圖 3.4.2中,以「_hls」結尾的文件夾為Vivado HLS工程,以「_ip_test」結尾的是用於IP驗證的Vivado工程。
工程創建完成後,需要先將HLS設計過程中導出的IP核拷貝到Vivado工程目錄下。我們在Vivado工程目錄下新建一個名為「ip_repo」的文件夾,然後將圖 3.3.17中的壓縮包拷貝到該文件夾中並解壓,解壓完成後如下圖所示:
圖 3.4.3 拷貝並解壓IP
接下來在Vivado中將該IP添加到工程的IP庫中。添加IP核完成之後,創建一個名為「system」的Block Design。在設計中添加key_led IP核,最終完成的設計如下圖所示:
圖 3.4.4 完成後的Block Design
到這裡我們的Block Design就設計完成了,在Diagram窗口空白處右擊,然後選擇「Validate Design」驗證設計。驗證完成後彈出對話框提示「Validation Successful」表明設計無誤,點擊「OK」確認。最後按快捷鍵「Ctrl + S」保存設計。
接下來在Source窗口中右鍵點擊Block Design設計文件「system.bd」,然後依次執行「Generate Output Products」和「Create HDL Wrapper」。
然後我們還要為設計創建約束文件navigator.xdc,並在文件中添加以下管腳約束信息:
最後在左側Flow Navigator導航欄中找到PROGRAM AND DEBUG,點擊該選項中的「Generate Bitstream」,對設計進行綜合、實現、並生成Bitstream文件。
3.5下載驗證
連接開發板的電源和下載器,並打開電源開關。在工程編譯之後,將生成的bit文件下載到開發板中。下載完成之後,底板上兩個 PL LED 處於點亮狀態。然後按下 PL_KEY0,可以看到PL LED 0熄滅;按下PL_KEY1,可以看到PLLED1熄滅。如下圖所示:
圖 3.5.1 按鍵控制LED實驗現象