雖然與數(shù)學(xué)庫的原始計算相比,算法的速度有了明顯的改善,但客戶需要的是速度快得多的實現(xiàn)。不過前文所述的最后一步給我們提供了一種能夠輕松轉(zhuǎn)向硬件實現(xiàn)的方法。
這種實現(xiàn)方法需要某些用于拆分 xi值的運(yùn)算。要在硬件中做到這一點,只需將所需的位進(jìn)行連接即可。然后我們需要三個表;我們使用以我們的PC模型計算出的預(yù)定義值推導(dǎo)出ROM,然后將其轉(zhuǎn)入IP的VHDL代碼中。該IP能夠一次讀取所有三個表,從而能夠再度節(jié)省時間。最后,我們需要進(jìn)行一次浮點MUL和一次浮點ADD運(yùn)算。
對于該任務(wù),我們發(fā)現(xiàn)用于浮點運(yùn)算的CORE GeneratorTM模塊非常適合。
?
?
圖 3 — 無流水線功能的加速器 IP
我們使用一些Slice和乘法器,對這些硬件模塊中的兩個進(jìn)行例化。兩個內(nèi)核都要求4到5個周期的延遲,以匹配我們設(shè)計的時序要求。延遲在此不是什么問題,我們將在下面的步驟中進(jìn)行討論。
我們將最終的IP以MicroBlaze的快速單工鏈路 (FSL) IP 的形式進(jìn)行實現(xiàn)。對時序的第一次估算結(jié)果表明:
? 將數(shù)據(jù)從MicroBlaze傳輸?shù)紽SL總線需用一個時鐘周期
? 將數(shù)據(jù)從FSL總線傳輸至FSL IP(當(dāng)正弦計算的自變量從FSL總線讀出時,將立即從BRAM讀取數(shù)據(jù),因而無需時鐘周期)需用一個時鐘周期
? 完成MUL運(yùn)算 (cos(x)*sin(d)) 需用四個時鐘周期
? 將方程的結(jié)果存儲到寄存器中需用一個時鐘周期
? 完成ADD運(yùn)算需用四個時鐘周期
? 將數(shù)據(jù)發(fā)送回FSL總線需用一個時鐘周期
? MicroBlaze從FSL IP讀取數(shù)據(jù)需用一個時鐘周期。
請注意,在沒有使用任何額外流水線(我們將在下一步驟中討論這一點)的情況下,自變量數(shù)據(jù)在整個過程中必須保持穩(wěn)定。這就意味著MicroBlaze僅能請求一次正弦計算,且必須讀取該值,然后至少要等上13個時鐘周期,才能請求下一次計算。
因此,我們估計進(jìn)行該實現(xiàn)需要13個時鐘周期。當(dāng)然,要處理軟件上的函數(shù)調(diào)用以及某些其他運(yùn)算,還需要更多的時鐘周期。
我們簡單地把一些標(biāo)準(zhǔn)時鐘組合在一起,不到一天就實現(xiàn)了該IP,隨即在硬件中對該算法進(jìn)行測量。整個算法(軟硬件混合)耗用了360個時鐘周期(包括所有的函數(shù)調(diào)用)。雖然這已是顯著的進(jìn)步,但是仍不足以充分滿足客戶的需求。
在我們的加速器IP處理所有數(shù)據(jù)之前,我們使用一個SRL16來延遲信號的寫入。
雖然該算法現(xiàn)在可與我們的MicroBlaze并行運(yùn)行,但它每次只能計算一個值。
步驟六:添加流水線和適配客戶代碼
設(shè)計到了這一步,我們就可以開始向我們的內(nèi)核添加流水線。浮點ADD和浮點MUL的CORE Generator模塊已采用流水線實現(xiàn),因而我們在此無需再做什么。第一個版本的算法要求自變量保持恒定,直至計算完成。在開始新計算之前(自變量數(shù)據(jù)到達(dá)FSL IP內(nèi)部),立刻讀取兩個BRAM并執(zhí)行浮點MUL。運(yùn)算的結(jié)果在數(shù)個時鐘周期后生效。
我們的 sin(xi) 的自變量 xi 是一個20位寬的整數(shù),它分為 x 和 d 兩個部分。因此,我們必須對自變量 xi的MSB部分 x 進(jìn)行幾個時鐘周期的延遲,以讀取 BRAM 的內(nèi)容,存儲自變量xi,并將其與MUL運(yùn)算的結(jié)果相匹配。
我們?yōu)槲覀兊?0位寬數(shù)值使用了少量SRL16元件(總共 10 個),共占用了10個LUT(但由于Spartan-6具有LUT組合功能,如果采用該器件較寬的LUT6結(jié)構(gòu),則僅需 5 個 LUT 即可)。
最后的工作量相當(dāng)小。在圖4中已對增加的SRL16x10位用紅圈進(jìn)行了標(biāo)注。
?
?
圖 4:帶流水線的加速器內(nèi)核
然后我們使用EDK向?qū)硇薷奈覀兊腇SL總線FIFO,以便存儲多個值(我們確定能夠存儲8個值就足以達(dá)到我們的目的,但可根據(jù)需要輕松增加更多)。
這就意味著我們的客戶甚至在請求第一個結(jié)果之前即能獲得多達(dá)8個值。這足以滿足我們客戶當(dāng)前的需求,但如果想請求更多正弦值的話,則可以輕松將FIFO緩沖參數(shù)擴(kuò)展為較大的值。
我們在與客戶討論這種新的方案時,發(fā)現(xiàn)可將正弦計算進(jìn)一步劃分為兩個部分:
1. 請求正弦計算(fslput 運(yùn)算)
2. 請求正弦計算的結(jié)果(fslget運(yùn)算)
由于我們在運(yùn)算中有一個固定時延,所以如果這兩個運(yùn)算依次銜接、緊密地按順序執(zhí)行,那么MicroBlaze將停頓,并等待FSL IP完成對請求的處理。如果能夠?qū)⑦@兩組運(yùn)算分開(這在客戶的算法中是可以的),那么我們即可進(jìn)一步提
升運(yùn)算的總體速度。通過增加流水線, 在MicroBlaze上執(zhí)行的最終代碼如下:
putfsl(arg1,fsl1_id);
putfsl(arg2,fsl1_id);
putfsl(arg3,fsl1_id);
putfsl(arg4,fsl1_id);
putfsl(arg5,fsl1_id);
putfsl(arg6,fsl1_id);
putfsl(arg7,fsl1_id);
putfsl(arg8,fsl1_id);
...
getfsl(result1,fsl1_id);
getfsl(result2,fsl1_id);
getfsl(result3,fsl1_id);
getfsl(result4,fsl1_id);
getfsl(result5,fsl1_id);
getfsl(result6,fsl1_id);
getfsl(result7,fsl1_id);
getfsl(result8,fsl1_id);
這給我們帶來了顯著的優(yōu)勢。內(nèi)核不僅可完全實現(xiàn)流水線功能,而且還能夠?qū)⒄矣嬎愕膬蓚€調(diào)用分開。IP核的時延依然存在,但不再明顯。MicroBlaze也不再發(fā)生停頓和等待未完成的IP計算的情況,從而提高了整體性能。
客戶同意對代碼進(jìn)行相應(yīng)調(diào)整,這對客戶來說只是小量工作。通過使用C語言的宏命令取代函數(shù)調(diào)用,我們就能夠把所有要求的調(diào)用插入代碼庫中。
?
?
圖 5 - EDK為FSL總線實現(xiàn)了深度為 8 的 FIFO 以提升流水線的性能
最終實現(xiàn)的算法一次計算只需要四個時鐘周期。處理的總體時延不再明顯,而被調(diào)用的劃分以及結(jié)果請求所隱藏。另外,整體IP需要一些額外的BRAM(需為我們的三個表增加六個BRAM)和一定數(shù)量的乘法器或DSP Slice以及一些其他Slice。
但結(jié)果非常令人吃驚。我們的MicroBlaze現(xiàn)在就能夠如同超高端處理器內(nèi)核一樣運(yùn)行,而且其運(yùn)行頻率仍然相當(dāng)?shù)停ìF(xiàn)在比原來的正弦計算約快9,600 倍)。
步驟七:進(jìn)一步優(yōu)化?
當(dāng)我們達(dá)到這種實現(xiàn)水平時,我們的客戶對結(jié)果感到非常滿意,并且我們也完成了加速器IP方面的工作。速度和精度都非常不錯。
當(dāng)然,還有一項最終優(yōu)化需要完成。如果我們在d值非常小的情況下對sin(d) 值進(jìn)行考察,算法還可以進(jìn)一步完善:
sin(d) = ~d
若d值小于2*π/1024,即小于0.0061359,那么總體誤差則小于 1E-8(針對有 1,024 個值的表)。
我們算法的最后步驟將為:
sin(x+d) = sin(x) + cos(x) * d
這樣只會存在非常小的額外誤差,但我們可以去掉第三個表。當(dāng)然,我們必須保留 fadd 和 fmul運(yùn)算器。雖然我們還可以通過其他方式來計算浮點值的正弦值,但這種方案充分顯示了增添硬件加速器的強(qiáng)大功能。我們的開發(fā)經(jīng)歷表明,你們無需為了將含有浮點計算的算法在硬件中實現(xiàn)而擔(dān)心。
評論
查看更多