陳書祺,占薇,劉益巧,徐龍潔,陳鑫
(南京航空航天大學電子信息工程學院,江蘇 南京 211106)
高層次綜合工具大部分都采用C/C++作為輸入并輸出寄存器傳輸級代碼,從而極大地降低了硬件編程門檻并縮短了開發時間,HLS 系統還提供了各種優化方法使得開發人員可以從高級語言層面對硬件結構進行優化,部分還提供了視圖以方便對每個時鐘周期的電路行為進行分析,進一步提高了生成RTL 的性能[1]。
文獻[2]顯示,現階段高層次綜合工具已經可以應用于中、高復雜度的應用系統,并且相較于傳統基于寄存器傳輸級(RTL)的技術路線,開發周期減少約60%,且最高工作速度提升了一倍。但是,現階段大部分已報道的高層次綜合工具主要是賽靈思公司開發的Vivado HLS 開發工具[3-4]。由于賽靈思公司是老牌的FPGA 芯片制造商,且Vivado HLS 開發工具源于FPGA 的設計工具EDA,因此Vivado HLS 開發工具主要被硬件開發工程師所熟悉。
因為MATLAB 具有運算能力強、語法簡單易于學習掌握、應用范圍廣等特點,廣泛被算法開發工程師所應用。雖然MATLAB 也具有高層次綜合工具功能,但經檢索發現,國內幾乎沒有報道使用MATLAB 作為高層次綜合工具,僅有少部分人嘗試Simulink 結合HDL Coder 來完成FPGA 的快速設計[5-6]。國外雖然存在使用HDL Coder 來轉化代碼的個別案例,但此方法并未被大量采用[7]。此外,所有已發表文獻僅僅將MATLAB 作為工程的一種實現方式,而未對其進行評估。
因此,本文研究了基于MATLAB 高層次綜合方法,并探究其設計效率。首先,本文研究了MATLAB的高層次綜合方法,總結了一些必要的MATLAB 代碼設計風格。隨后,建立了一套行之有效的MATLAB 的高層次綜合方法,并確定了作為評估對象的電路類型和設計方法。最后,本文將同樣的算法邏輯,在Vivado 和MATLAB 中分別實現,并對編寫的模塊進行功能性仿真以及時序仿真,并對仿真數據進行性能比較和評估。最終結果顯示,在簡單電路模塊的構建上,與Verilog 搭建電路相比,用MATLAB 進行設計,功耗減少程度在-5%~10%區間內波動,面積使用量增加約5%,時序減少程度則是-14%~17%不等,主要由于各項數據之間的平衡,某項性能的提升會以另一項性能的降低為代價。這表明高層次綜合已經足夠成熟,并且在特定場合可以在面積,資源利用上實現突破。
HDL Coder 是MathWorks 推出的一款工具,它支持從MATLAB 代碼自動生成HDL 代碼,允許工程師用MATLAB 語言實現FPGA 和ASIC 設計。同時發布的還有HDL Verifier,該產品包含用于測試的FPGA 硬件在環功能。這兩款產品使得MathWorks可提供利用MATLAB 和Simulink 進行HDL 代碼生成和驗證的能力[8]。
本文使用的MATLAB 版本為R2019b,HDL Coder 設計流程圖如圖1 所示。在新建的腳本文件中以function 的形式確定模塊的功能,同時明確模塊的輸入和輸出。接著,編寫testbench 測試文件,規定模塊輸入和輸出數據的類型和大小。在命令行窗口中輸入hdlcoder,在彈出的MATLAB HDL Coder Project 窗口中設置工程名稱以及存放位置。然后在HDL Code Generation 中添加前文提到的function和testbench,最后在workflow advisor 的HDL Code Generation 步驟中,設置語言為Verilog。在HDL Verification 上右擊選擇運行到選定任務,無報錯即可得到轉換的Verilog 代碼。

圖1 HDL Coder 設計流程圖
在function 的編寫過程中,由于目前并沒有較完整的代碼風格,編寫者大多依靠經驗,我們在嘗試的過程中發現了一些可以遵循的規律。具體地來說,我們發現通過編寫function 和testbench 從MATLAB 函數中生成Verilog 代碼時,MATLAB 代碼風格對轉化結果起至關重要的作用,相同邏輯用不合適的語法描述時可能會得到不理想的結果甚至引起報錯。我們探究了不同數據類型、輸入、結構語句及MATLAB 中函數對生成結果的影響。結果如下:
從數據類型角度分析:
(1)轉化的Verilog 代碼的輸入輸出均為wire類型;
(2)function 中input 與output 的數據類型以及長度大小由testbench 決定,而在MATLAB 中設置為不同的數據類型如logical,double,uint8 等不影響轉化結果,但不可設置為string,否則fixed-point conversion 階段將不支持;
(3)HDL Coder 不支持2D 矩陣作為function 的輸入,1×n或n×1 矩陣是唯一可以轉化的矩陣,轉化后變為n個寄存器,寄存器長度相同且由矩陣中最大的數值決定。在HDL 程序中由寄存器組作為中間變量進行操作。且轉化所得的寄存器組完全一致;且輸入輸出矩陣n的大小必須通過testbench 固定,不支持動態矩陣。
從語法角度分析:
(1)MATLAB 中的switch 語句轉化為Verilog 中的case 語句,elseif 語句轉化為if 語句,while 語句不支持轉化,建議使用for 語句;
(2)較高級的數學函數不支持轉化,已知的有log2(n),dec2bin(),imread()等。
為了更好地研究MATLAB 高層次綜合方法的設計效率,本文擬對數據通路的典型電路,具體包括加法器,比較器,數據選擇器,乘法器四種電路進行設計。
算術邏輯單元(ALU)不僅能完成算術運算也能完成邏輯運算,是微處理器芯片中的一個十分重要的部件[9]。但是所有基本算術運算(加、減、乘、除)最終都可歸結為加法運算,所以加法運算的實現顯得尤為重要[10]。
本文采用四位加法器對比設計,考慮到帶有進位的加法器設計,采用的方法為手工擴展輸入一位,執行常規加法,截取和的最高位作為進位。
在MATLAB 的腳本文件中,編寫代碼得到兩個輸入相加的和,再把和分為進位以及非進位部分,如圖2(a)所示,再編寫測試文件,由于MATLAB HDL Coder 的特殊性,需要在激勵文件中通過給輸入輸出賦值,來達到約束位數的作用,如針對此加法器,x1 和x2 的賦值區間在[8,15]時,轉化生成的Verilog 代碼中的輸入為4 位2 進制。同理,如果賦值區間為[16,31],得到的轉化代碼中input 的位數也就為5 位。因此如圖2(b)中,給x1 和x2 賦值為15,使得約束加法器的輸入為4 位2 進制,就可以得到相同原理的四位加法器模塊。

圖2 基于HDL Coder 的加法器代碼
在數字電路中,數值比較器的輸入是要進行比較的兩個二進制數,輸出是比較的結果[11],是一種比較常見且很常用的邏輯模塊。
本文采用最基本的32 位比較器,即輸入的數均為字長為一個字節的無符號整型數,通過比較大小輸出相應的結果值。輸出三個值x、y、z初始均為0,若a>b,則x變為1;若a=b,則y變為1;若a<b,則z變為1。
在腳本文件中新建function comp_1,如圖3,在此函數中,編寫基本比較器的邏輯,即當a>b時,x=1,y=0,z=0;即當a=b時,x=0,y=1,z=0;即當a<b時,x=0,y=0,z=1。整個函數通過三個if 結構來完成。

圖3 比較器代碼
數據選擇器(也稱多路選擇器)是一種多輸入、單輸出的組合邏輯電路,在地址端的控制下將多個輸入信號中的一個從輸出端輸出[12]。數據選擇器屬于組合邏輯電路,他的基本功能是在數據傳輸過程中完成多路數據到一路數據的有序轉換,還可代替繁多的邏輯門實現組合邏輯函數,從而使電路簡化[13],因此也是個十分重要的模塊。
本文選用的是四位四選一數據選擇器,通過判斷輸入的值來選擇哪個通路的數據被輸出。
如圖4,在MATLAB 的腳本文件中通過case 結構實現,當a 的取值分別為00、01、10、11 時,輸出端out 將分別輸出in0,in1,in2,in3 的數據。

圖4 數據選擇器代碼
在各類處理器中,乘法器有著不可或缺的地位。高性能的乘法器是提高中央處理器運算速度的關鍵。在常見的FPGA 芯片上都不會搭載多位乘法器模塊,需要我們進行設計來實現,所以研究FPGA 的數字乘法器是有著非常重要的意義。在乘法器設計上,以位移相乘法和booth 算法居多[14]。本文主要研究采用位移相乘法的乘法器模塊。
本文研究基本的16 位乘法器模塊,算法為從乘數的最末尾開始依次與被乘數相乘,并將乘得的結果依次左移再相加求和。
如圖5 所示,在MATLAB 的腳本文件中,編寫代碼得到兩個輸入相乘的積。

圖5 乘法器代碼
此次對比測試中,我們選擇FPGA 板卡型號為xc7k325tffg900-2。仿真的過程中,我們分別將直接編寫的Verilog 代碼與MATLAB 轉化后生成的Verilog 代碼使用Vivado 進行仿真。
單個模塊差異過小,如功耗差異出現在小數點后3位以上,造成無法比較。為了解決這個問題,我們將兩份代碼進行處理,處理的方法即在新建的頂層模塊中使用generate 語句,生成函數名為<模塊名>bit[0].f1到<模塊名>bit[999].f1 的1 000 個相同的該模塊,這樣可以便捷地實現1 000 個相同功能模塊的并行,使得兩份代碼在增加功耗的同時消除錯誤影響。
同時,1 000 個輸出的末端可能出現“線與”的問題,此問題主要體現在造成了電路末端信號的冒險與競爭,在妨礙正常波形輸出(產生毛刺等錯誤)的同時還增加了不確定的功耗,導致兩者的對比結果不準確,乃至導致結論錯誤。因此,為了避免這一問題,我們在每個模塊的末端增加數據選擇器,并且在輸出的每一位bit 處使用或門得到正確的輸出。這樣雖然增加了功耗,但是每個模塊的增加功耗相同。因此,差異不會改變,最終也就可以正確地得出所有結論。
在Vivado 中編寫每個頂層模塊的testbench,其中在每個激勵文件中,利用random 函數每過30 ns隨機生成給定范圍內的激勵信號,使得仿真生成的saif 向量文件輔助測試功耗有較高的可信度。
將代碼改寫后,我們先將工程進行綜合以及實現,對代碼進行布局布線之后才能獲得準確的功耗以及資源利用情況。在做完實現之后,根據官方提供的手冊ug997 進行時序仿真,來生成saif 向量文件,這個向量文件用以獲得置信水平為high 的功耗報告。這樣通過對兩份代碼的仿真,分別獲得溫度、功耗,時序,原理圖,資源等數據,并且確保了置信水平為high。
我們通過對比兩種代碼的功耗,資源,原理圖,時序等(如表1),發現了以下的結論:Verilog 編寫在復雜電路中總體更優,但高級語言的HDL 各項數據也較為接近,在簡單電路中表現甚至更為優秀,具體的數據差異體現在功耗、時間、面積的相互轉換上,即一項性能的提升會帶來另一項性能的降低。

表1 四種基本運算模塊的性能對比
我們采用式(1)來計算MATLAB HLS 的性能改進程度:

該公式僅用于計算功耗、IO、LUT,對于WNS 則不需要公式前的負號。計算所得的百分比若為正則表示性能的提升,為負則表示性能的下降。
由表可知,使用MATLAB HLS,在加法器的設計上功耗優化了11.50%,面積優化了2.11%,時延優化了16.12%,再者,數據選擇器設計功耗優化了0.96%,時延快2.39%,但面積多出來0.92%;比較器的優勢主要集中在功耗上,優化28.96%。由此看來,在簡單電路的構建上,MATLAB 高層次綜合與Verilog 搭建電路相比,性能指標的差異主要集中在功耗、時間和面積的相互轉化上。但針對復雜電路如乘法器電路,功耗、面積以及時延皆不如Verilog編寫的代碼,具體的差距分別為0.09%,9.29%和11.43%。可見,高級語言的HLS 在復雜電路的轉化和優化上還有很長的路要走。
在此基礎上,繼續測試了不同位寬下MATLAB HLS 和Verilog 直接編寫代碼的性能對比。當位寬為4 位、8 位、16 位、32 位依次增長時,兩種設計方式的功耗、LUT 呈現上升的趨勢,WNS 呈現下降的趨勢,這也是意料之內的結果。
在上述設計的基礎上進行不同位寬下的性能對比,我們仍然采用式(1)來計算功耗、LUT 和WNS的性能改進程度,其中以加法器的不同位寬性能對比為例,計算功耗、LUT 使用以及WNS 的性能提升百分比,如圖6 所示,位寬為4 位時MATLAB HLS全面占優,而位寬為8 位時,僅速度優于直接編寫的代碼,在16 位加法器中則為面積占優,最后32 位加法器只有面積劣于Verilog 直接編寫的代碼。隨著位數的增加,性能的差異沒有一成不變,而是體現在功耗、時間、面積的相互轉換上。如圖7 所示,數據選擇器也是同理。

圖6 加法器不同位寬性能對比

圖7 數據選擇器不同位寬性能對比
但對于乘法器這種復雜電路來說,如圖8 所示,僅在4 位和8 位電路相對簡單時,MATLAB HLS 在速度上稍占優勢,隨著位數的增加,電路復雜度的提升,在16 位和32 位時性能全面處于劣勢,但劣勢不是很大,32 位時功耗和面積分別低3.39%和0.88%,也就是說MATLAB HLS 在復雜電路的轉化上還有一定的提升空間,但Verilog 直接編寫代碼的優勢也不明顯。折線圖依然可以體現功耗、時間、面積性能的相互轉換。

圖8 乘法器不同位寬性能對比
本文研究了基于MATLAB 的高層次綜合方法,并用該方法完成了加法器、比較器、四選一數據選擇器、乘法器這些運算模塊的設計。在與傳統的RTL級設計的功能與時序仿真對比中,得知使用MATLAB 進行高層次綜合的設計功耗減少程度在-5%~10%區間內波動,面積使用量約增加5%,時序減少程度則是-14%~17%不等,主要為各項數據之間的平衡。評估結果顯示,現階段使用高級語言如MATLAB 進行高層次綜合的設計已經成為了可能,在性能差距可以接受的前提下,MATLAB 高層次綜合已經足夠成熟,并且在特定場合可以在面積,資源利用上實現突破。