問題:
隨著NI的FPGA產(chǎn)品的廣泛使用,很多同事和客戶都碰到了一些FPGA編程時遇到的問題。由于FPGA不能實時調(diào)試,每次修改一點代碼之后都要編譯很長時間之后才能看到修改的效果,所以,我們希望盡量在FPGA編寫代碼時就將更多的問題考慮到位。本文針對項目過程中碰到的一些實際問題進(jìn)行闡述,希望可以為大家在FPGA編程過程中提供一些幫助。
項目描述:該項目是一個實時頻譜監(jiān)測、流盤以及跳頻信號檢測的需求。具體參數(shù)是IQ速率為100MHz,流盤5分鐘(要做類似Reference Trigger的效果,即按下按鈕之前的一分鐘和按下按鈕之后的四分鐘信號一起流盤),檢測跳頻信號的時間點和相應(yīng)的頻點,其中跳頻信號的參數(shù)是:突發(fā)性,每次持續(xù)1ms~20ms,跳頻信號在每個頻點上的持續(xù)時間是1us~20us,跳頻頻率70000/s,每個頻點上的信號帶寬是5MHz;使用的硬件是5792+7966.其中與FPGA相關(guān)的部分就是數(shù)據(jù)采集和跳頻信號的檢測。對于數(shù)據(jù)采集部分,5792有專門的采集范例可以供大家參考,而跳頻信號的檢測算法是將數(shù)據(jù)每隔128個點做一次FFT(100M的采樣率,對于1us的跳頻信號持續(xù)時間,對應(yīng)為100個時域采樣點)。做出的FFT結(jié)果如果超過閾值,則將FFT結(jié)果的序號回傳給上位機進(jìn)行保存。
解答:
一、DMA傳輸?shù)乃俾?/h2>
對于PXIe-7966R,官網(wǎng)上標(biāo)定的DMA的傳輸速率為800MB/s,理論上可以完全滿足項目中的400MB/s的傳輸速率要求。但實際測試過程中,傳輸?shù)乃俾式咏偸沁_(dá)不到400MB,這直接影響了信號的實時采集和流盤。經(jīng)了解,F(xiàn)PGA的DMA BenchMark與FIFO的數(shù)據(jù)位寬、總線帶寬以及DMA控制器的速率都有一定關(guān)系。見下圖:
注:上圖中PXIe系統(tǒng)下,F(xiàn)PGA的時鐘使用的是200MHz的時鐘。而PXI系統(tǒng)下,F(xiàn)PGA的時鐘使用的是160M (U8 和U16),133M(U32和U64)。
注:上圖中使用的機箱是PXIe-1075,使用的控制器是PXIe-8130.
通過觀察上述PXIe和PXI板卡的速率統(tǒng)計,可以看到:
對于PXI板卡,在 U8場景下,F(xiàn)PGA每秒鐘產(chǎn)生160MB的數(shù)據(jù),U16場景下FPGA每秒產(chǎn)生320MB的數(shù)據(jù)。眾所周知,PCI總線的傳輸帶寬為133MB/s,那為什么上圖中U8情況下的速率才33MB/s,U16情況下的速率才66MB/s呢?這是因為PCI總線的傳輸模式是并行傳輸,總線位寬和時鐘頻譜分別是32位和33M(一般的desktop都是這樣的配置),也就是說每個時鐘周期傳輸32個比特的數(shù)據(jù)。因此,如果傳輸?shù)氖荱8或者U16的數(shù)據(jù)類型,那么相當(dāng)于每個傳輸周期浪費了3/4或者1/2的位寬。因此,U8情況下每次只能傳輸一個字節(jié),結(jié)合33MHz的時鐘頻率,使得DMA 的Benchmark只有33MB/s。U16的情況下的DMA速率為66M也是可以理解的。而U32以及U64的情況下,只能達(dá)到133M的極限速率。
對于PXIe板卡,F(xiàn)PGA讀寫 FIFO的時鐘固定為200MHz,因此,如果FIFO的數(shù)據(jù)類型是U8,那么每秒鐘FPGA端就產(chǎn)生200MB的數(shù)據(jù);如果FIFO的數(shù)據(jù)類型是U16,那么每秒鐘FPGA端就產(chǎn)生400MB的數(shù)據(jù)量。這些數(shù)據(jù)量遠(yuǎn)小于1075機箱的單槽帶寬(PCIe Gen 1 ×4,1GB/s),因此,總的DMA Benchmark 就等于FPGA端產(chǎn)生數(shù)據(jù)的速率。如果FIFO的數(shù)據(jù)類型為U32,那么FPGA產(chǎn)生數(shù)據(jù)的速率就達(dá)到了800MB,這幾乎1075機箱的單槽傳輸極限,因此U32場景下DMA的BenchMark接近800MB/s。繼續(xù)增加FPGA端FIFO的位寬,在200MHz的時鐘頻率下FPGA每秒鐘產(chǎn)生1.6GB的數(shù)據(jù),但這時PCIe總線的傳輸速率不可能再大幅提升,因此,U64情況下DMA的Benchmark 還是在800MB左右,所以我們很容易得出DMA的傳輸速率限制為總線的單槽傳輸帶寬。
實測1085+8135環(huán)境下的DMA速率
為了驗證此種情況(U64,200M時鐘)下DMA的傳輸速率限制確實為總線的單槽傳輸帶寬,我們有理由假設(shè),如果使用1085機箱(單槽傳輸速率為4GB/s),DMA的傳輸速率應(yīng)該可以達(dá)到1.6GB/s。因此,我又搭建了相關(guān)的系統(tǒng)對1085機箱下的7966 DMA速率進(jìn)行測試:
硬件環(huán)境:PXIe-8135+PXIe-1085+PXIe-7966
測試方法:在7966中以200M的時鐘不斷將U64數(shù)據(jù)寫入到FIFO中,F(xiàn)IFO大小2048;上位機中對FIFO進(jìn)行全速讀?。ň彌_區(qū)中有多少點讀多少點),上位機緩沖區(qū)設(shè)置為200M;
測試結(jié)果:DMA速率900MB/s左右.修改上位機中FIFO的緩沖區(qū)大小,DMA速率沒有出現(xiàn)大的波動,依然在900MB/s。觀察CPU占用率在18~20%,每次循環(huán)查看緩沖區(qū)中的點數(shù)10000點不到,說明上位機的讀取速率完全不是瓶頸。
分析結(jié)果可以發(fā)現(xiàn):此時系統(tǒng)總線的單槽帶寬已經(jīng)不是限制因素,上位機的讀取速率也完全可以跟上。DMA傳輸鏈路上的瓶頸,除了FPGA產(chǎn)生數(shù)據(jù)的速率、總線傳輸帶寬、上位機的讀取速率之外,還有一點是我們之前沒有考慮到的——就是DMA控制器的速率。在我們實際測試的這種場景下,DMA控制器的速率成了DMA鏈路傳輸速率受限的主要原因。這個結(jié)果與官網(wǎng)上說7966的DMA傳輸速率為800MB/s以上是相互吻合的。
總結(jié):
i) PXI總線的帶寬比較低,目前支持PXI總線的FlexRIO只有較老的795x系列,這種情況下限制DMA傳輸速率的主要是總線帶寬;
ii) PXIe 總線的帶寬比較高,不同機箱的單槽傳輸帶寬各有不同,因此,對DMA傳輸速率上限有一定的影響;
iii) FPGA端在一定的時鐘頻率下,如果希望提升數(shù)據(jù)率,可以使用更寬的數(shù)據(jù)位寬;
iv) DMA控制器的速率是板卡本身硬件上對DMA速率的限制——7966的DMA速率為800M以上,7975的DMA速率可以達(dá)到1.6GB/s;
當(dāng)然, DMA的傳輸性能的影響因素,比如上下行的影響。上圖中給出的數(shù)據(jù)中,對于7965的上下行DMA速率相差不大,但對于7954的上下行DMA速率相差很大。對于這一點,還需要更加深入地研究。本文不再深入討論。
二、 FPGA與上位機的握手
FPGA中FIFO的使用使得FPGA端和上位機端在很多時候都可以異步操作。上位機中沒有有效的數(shù)據(jù)傳遞到FPGA端,F(xiàn)PGA端就不會進(jìn)行有效的計算并傳輸無效的數(shù)據(jù)。但在有些情況下,F(xiàn)PGA端與上位機端需要進(jìn)行握手的操作。比如:一個項目需要通過Adapter端口進(jìn)行數(shù)據(jù)采集,然后將數(shù)據(jù)傳回到上位機。這種情況下,如果FPGA先于上位機開始執(zhí)行,那么FPGA采集到的端口數(shù)據(jù)會迅速地填滿FIFO(此時上位機還沒有準(zhǔn)備好去讀取FIFO的數(shù)據(jù))導(dǎo)致后續(xù)的數(shù)據(jù)無法保存到FIFO中(寫入超時)。而當(dāng)上位機開始讀取FIFO時,會發(fā)現(xiàn)FIFO的前一段數(shù)據(jù)(數(shù)據(jù)的長度與FPGA端配置的FIFO大小有關(guān))與后續(xù)的數(shù)據(jù)是非連續(xù)的。為了避免類似的問題,需要在FPGA與上位機之間握手。
通常用于FPGA程序與Host程序同步的方法是使用一個握手控件。在FPGA的主程序之前,使用一個while循環(huán),條件接線端鏈接著布爾控件。在上位機中,當(dāng)一切準(zhǔn)備就緒時(對FPGA的初始化以及其他初始化工作),可以為FPGA的Start控件賦上真值,這樣,F(xiàn)PGA與Host端的數(shù)據(jù)傳輸就同步了,這是非常容易實現(xiàn)的方法。代碼如下:
另一種方法是使用FPGA中提供的中斷。在FPGA端需要等待上位機的數(shù)據(jù)或者等待上位機做好接收數(shù)據(jù)的準(zhǔn)備時,產(chǎn)生一個中斷。該中斷會阻塞程序直到該中斷被確認(rèn)。當(dāng)上位機中準(zhǔn)備好向FPGA傳輸數(shù)據(jù)或者接收來自FPGA的數(shù)據(jù)時,上位機可以對中斷進(jìn)行確認(rèn)。代碼如下:
三、FIFO的使用
1) 使用場景:
該項目需要在回放時對信號進(jìn)行精細(xì)的分析。尤其是有一個跳頻信號,跳頻的頻帶寬度為70MHz,跳頻信號本身的帶寬為5MHz,跳頻信號的持續(xù)時間為1us~20us,跳頻信號以突發(fā)的模式出現(xiàn)。需求是以較快的速率分析出信號文件中所有的頻率點以及各個跳頻信號所處的時間點。其實分析的原理不難,只需要對信號以足夠精細(xì)的時間分辨率(1us)做FFT,判斷該段信號是否有功率大于閾值的點就可以了。
在項目初期,曾經(jīng)嘗試過直接在上位機中做FFT,判斷閾值,找到頻點以及對應(yīng)的時間點。但經(jīng)過測試,上位機端進(jìn)行數(shù)據(jù)處理的瓶頸在于大的數(shù)據(jù)塊的分割。本程序中的數(shù)據(jù)源是存在磁盤陣列中的數(shù)據(jù)文件,從磁盤陣列中讀取文件本身的速率可以達(dá)到非常高,500MB以上,但達(dá)到此速率的前提就是每次讀取一個大的數(shù)據(jù)塊(幾兆到幾十兆字節(jié)),否則,讀取速率無法達(dá)到理想值;但這種情況下,就需要在程序中對大塊的數(shù)據(jù)進(jìn)行分割,然后進(jìn)行FFT。雖然測試時已經(jīng)開通了多個流水線進(jìn)行數(shù)據(jù)分割,但速率依然達(dá)不到要求。整個系統(tǒng)的最高處理速率只有40~50MB/s,這對于120G(流盤5分鐘)的跳頻信號分析顯然是不能滿足要求的(分析5分鐘的數(shù)據(jù)需要花將近1個小時的時間)。
基于這個原因,本程序?qū)FT的操作放在FPGA中完成。上位機中將大塊的數(shù)據(jù)傳輸?shù)紽PGA中,F(xiàn)PGA天然的單點操作特性使得不需要進(jìn)行大數(shù)據(jù)分割就可以完成小點數(shù)的FFT操作。由于N點時域信號做完FFT之后數(shù)據(jù)量沒有減小,不能將FFT結(jié)果直接傳回到上位機中進(jìn)行閾值檢測,所以FFT結(jié)果的閾值比較也在FPGA端進(jìn)行單點比較,并將超過閾值的頻點的索引值傳回到上位機。
最終,F(xiàn)PGA端以400MB/s的速率對信號進(jìn)行處理。
2) 初始化和配置:
每次在程序重新運行時,系統(tǒng)會對所有FIFO進(jìn)行初始化,清除原有的數(shù)據(jù)。在上位機中對FIFO進(jìn)行讀取之前,要首先對FIFO進(jìn)行開始操作,否則,雖然最終能讀出數(shù)據(jù),但前期會出現(xiàn)數(shù)據(jù)的丟失。當(dāng)然,也可以通過編程的方式對FIFO進(jìn)行初始化:使用FIFO的調(diào)用節(jié)點,先開始FIFO,再停止FIFO,再開始FIFO,就能完成FIFO的初始化并使FIFO處于就緒的狀態(tài)。不過這種編程方法來初始化FIFO的操作不常用。
FPGA與Host端通常采用DMA的方式進(jìn)行數(shù)據(jù)傳輸,數(shù)據(jù)在DMA控制器的作用下從FPGA傳輸?shù)缴衔粰C的緩沖區(qū)中,LabVIEW從緩沖區(qū)讀取到應(yīng)用程序內(nèi)部;在從上位機往下位機傳輸數(shù)據(jù)時,LabVIEW將數(shù)據(jù)從應(yīng)用程序內(nèi)部寫入到緩沖區(qū)中,然后DMA控制器通過總線從緩沖區(qū)獲取數(shù)據(jù)。在配置時,一方面需要配FPGA端的FIFO大小,這是通過窗口配置的方式來實現(xiàn)的。FIFO本身的大小在一定程度上可以減低數(shù)據(jù)覆蓋的危險,但FIFO設(shè)置的過大,會占用太多FPGA的資源,且是沒有必要的;另一方面需要配置上位機端用于DMA FIFO的緩沖區(qū)大小。一般,緩沖區(qū)的大小為每次讀取的數(shù)據(jù)塊大小的5~10倍左右。
3) FIFO讀取和寫入超時的利用:
參考FFT Co-processor范例,當(dāng)FIFO中沒有有效數(shù)據(jù)時,讀取操作會發(fā)生超時,這時,不將無效數(shù)據(jù)寫入到下一級的FIFO;在下一次定時循環(huán)時繼續(xù)讀?。划?dāng)寫入FIFO時發(fā)生超時,說明被寫入的FIFO中已沒有足夠的空間存入新的數(shù)據(jù),這時,下一次定時循環(huán)時,依然向FIFO中寫入上一次循環(huán)的數(shù)據(jù)。當(dāng)然,使用這種方式來進(jìn)行數(shù)據(jù)傳輸時,F(xiàn)IFO讀取和寫入的數(shù)據(jù)都不會發(fā)生異常,但如果該流程中包含Host與FPGA之間的數(shù)據(jù)傳輸,則會影響FPGA執(zhí)行的速率:I)Host端發(fā)送數(shù)據(jù)不夠快,則FPGA中總是無法得到有效數(shù)據(jù),導(dǎo)致FPGA處理流程受限于數(shù)據(jù)源;II)Host端接收數(shù)據(jù)不夠快,則FPGA無法將FPGA-to-Host FIFO中的數(shù)據(jù)快速清空,進(jìn)而影響FPGA從Host端取數(shù)據(jù)的速率。因此,在使用FPGA處理并向上位機傳輸數(shù)據(jù)的時候,上位機要以FPGA處理速率相當(dāng)?shù)乃俾驶蛘咭员M可能快的速率讀取數(shù)據(jù)。推薦的方式如下:
很多時候,從FPGA中讀取出來的數(shù)據(jù)需要直接流盤到磁盤陣列中。在高速流盤時對每次寫入文件的數(shù)據(jù)塊大小有要求——必須是扇區(qū)大小的整數(shù)倍,這種情況下,怎么進(jìn)行讀取呢?
當(dāng)然,很多函數(shù)本身就自帶輸入就緒、輸入有效和輸出就緒、輸出有效這些端口,可以將這些端口與FIFO讀取和寫入超時端口結(jié)合起來,保證讀取或者寫入數(shù)據(jù)的有效性。如下:
四線制的握手交互:上圖中展示的已經(jīng)是一種四線制的握手方式,完成了三個模塊之間的交互。我們可以把這種交互分成左右兩部分來查看,每一部分分別都是兩線制的控制回環(huán)。首先來看左側(cè)部分:讀取FIFO IN時,如果發(fā)生超時,那么它輸出的數(shù)據(jù)就是無效的,可以將這個端口與下一個模塊的“輸入有效”端口相連,來告知下一個模塊這個必要的信息,對于無效數(shù)據(jù),該模塊應(yīng)該丟棄;而如果第二個模塊準(zhǔn)備好接收下一個數(shù)據(jù)之后,第二個模塊也將該信號反饋給第一個模塊,告知第一個模塊可以輸出新的數(shù)據(jù),否則,第一個模塊不應(yīng)該輸出新的數(shù)據(jù);這就構(gòu)成了一個控制回環(huán)。再來看右側(cè)部分:第三個模塊如果準(zhǔn)備好了接收新的數(shù)據(jù),需要將這個信息告知第二個模塊(連接到第二個模塊的“輸出就緒”端口),這時第二個模塊就可以輸出新的數(shù)據(jù)了,否則第二個模塊不應(yīng)該輸出有效數(shù)據(jù);而當(dāng)?shù)诙€模塊輸出了有效的數(shù)據(jù),那么第三個模塊就應(yīng)該接收數(shù)據(jù),否則忽略。這又構(gòu)成了一個控制回環(huán)。按照這樣的思路,可以進(jìn)行多級級聯(lián),完成多線制的握手。
四、FPGA中的數(shù)據(jù)類型轉(zhuǎn)換
FPGA中的很多運算都用整型或者定點數(shù)完成,這其中會經(jīng)常碰到數(shù)據(jù)轉(zhuǎn)換的問題。比如,前端Adaptor采集到的信號的位寬是14,如果在FPGA中對數(shù)據(jù)進(jìn)行FFT運算,就需要將整型數(shù)據(jù)轉(zhuǎn)換成定點數(shù);很多時候,在將整型數(shù)轉(zhuǎn)換成定點數(shù)時,有客戶會問:我的整數(shù)位數(shù)應(yīng)該設(shè)置為多少呢?其實在數(shù)據(jù)轉(zhuǎn)換時,首先要搞清楚整條鏈路上數(shù)據(jù)轉(zhuǎn)換的步驟。前端的Adaptor在進(jìn)行AD采樣時,將數(shù)據(jù)轉(zhuǎn)換從DBL的模擬量量化成N位的整數(shù)。在量化的過程中,有一個量程的概念。比如量程為±M,那么轉(zhuǎn)換成將以±M作為歸一化的參考值。假設(shè)實際的模擬值為A,則A采樣值量化的方法如下:
量化值=A/M×2^((N-1))
之所以乘以2^((N-1)),是將最高位作為符號位進(jìn)行處理。進(jìn)一步,在FPGA端,將I16的數(shù)據(jù)轉(zhuǎn)換成定點數(shù),道理是一樣的。在轉(zhuǎn)換成定點數(shù)時需要設(shè)置整數(shù)位數(shù),這個整數(shù)位數(shù)就是在FPGA中進(jìn)行定點轉(zhuǎn)換時的量程。當(dāng)然,這里的量程表示的范圍與AD量化時的量程有可能是不匹配的,導(dǎo)致轉(zhuǎn)換之后的定點數(shù)與采樣之前的信號實際值是不一致的,但是沒有關(guān)系,只要牢記轉(zhuǎn)換過程中的相對關(guān)系,可以基于相對的轉(zhuǎn)換值進(jìn)行計算。在將數(shù)據(jù)傳遞到上位機之后,如果要獲取絕對的數(shù)值,則可以按照轉(zhuǎn)換過程中的相對關(guān)系進(jìn)行還原,即進(jìn)行增益補償。
另一種可能出現(xiàn)的轉(zhuǎn)換就是:如果DMA接收到的數(shù)據(jù)是64位,其中包含兩個樣值,而后續(xù)處理是以32位的Sample為單位的,這就需要將64位FIFO中取出的數(shù)據(jù)轉(zhuǎn)換成32位的數(shù)據(jù),然后寫入后續(xù)的FIFO中。前文有提到過,DMA的最高傳輸速率是基于64位數(shù)據(jù)位寬的,所以,很多時候,為了追求Host與FPGA之間的高速數(shù)據(jù)傳輸,F(xiàn)PGA從Host端接收的是64位數(shù)據(jù)。本程序就涉及到將64位數(shù)據(jù)寫入32位的FIFO。具體實現(xiàn)的方法是取出一個64位數(shù)據(jù)之后,拆分成高位和低位兩部分。定時循環(huán)每隔兩個循環(huán)讀取一個數(shù)據(jù),但每次循環(huán)都要向32位FIFO中寫入數(shù)據(jù)。有人可能認(rèn)為,這是很簡單的事兒?。褐灰靡粋€奇偶判斷,奇數(shù)循環(huán)時寫入高位,偶數(shù)循環(huán)時寫入低位不就行了?但測試發(fā)現(xiàn),在一個循環(huán)內(nèi)部,不能出現(xiàn)多個FIFO寫入,否則,編譯器會提示無法決定數(shù)據(jù)源。另外,這種方法本身也是不可靠的,如果奇數(shù)循環(huán)在寫入高位時出現(xiàn)了超時,那么在下一個循環(huán)(即偶數(shù)循環(huán)),應(yīng)該重新寫入高位數(shù)據(jù)。同理,如果偶數(shù)循環(huán)寫入時發(fā)生了超時,那么在下一個循環(huán)(即奇數(shù)循環(huán))應(yīng)該重新寫入低位數(shù)據(jù)。最終,如下方法是經(jīng)過測試的既有可靠性而在編程上又非常簡便的方法:
五、FPGA編程時的普通循環(huán)和單周期定時循環(huán)
在說循環(huán)之前,我們首先來看一下FPGA在對代碼編譯到硬件上時會做什么樣的操作。默認(rèn)情況下,LabVIEW需要確保程序在頂層時鐘下能編譯成功。在編程時,我們常常對數(shù)據(jù)進(jìn)行多種聯(lián)結(jié)在一起的運算操作,如下所示。這些聯(lián)結(jié)在一起的運算使得聯(lián)合路徑較長并導(dǎo)致總的時鐘速率降低?;谶@樣的原因,LabVIEW會在如下代碼的各運算函數(shù)之間增加寄存器,來拆分關(guān)鍵路徑的長度,確保程序可以在頂層時鐘下執(zhí)行。每個寄存器的執(zhí)行都需要一個tick,那么以下這段代碼的執(zhí)行之間就是3個ticks。
While循環(huán)和For循環(huán)都可以用來執(zhí)行重復(fù)的計算操作。這一點,與上位機中的功能是完全一致的。通常,我們會將一些操作放在循環(huán)中進(jìn)行持續(xù)的處理。那么上述代碼在循環(huán)中的執(zhí)行時序如下:
循環(huán)中每一個函數(shù)都在預(yù)留的硬件資源中等待上一個函數(shù)給出有效的輸出。因此,每次循環(huán)的執(zhí)行都需要三個時鐘周期。上圖中顯示的還是一些簡單的運算,例如乘法、加法、邏輯比較等。如果程序中用到了一些多周期的數(shù)值運算函數(shù),比如商與余數(shù)、倒數(shù)、平方根、除法等,那么一個循環(huán)執(zhí)行的時間將會更長??偨Y(jié)來說,一個普通的while或者for循環(huán)執(zhí)行的速率依賴于頂層時鐘以及一行代碼最多有多少個運算。
基于上述的原理,很多時候,普通的while循環(huán)或者for循環(huán)并不能滿足實際的需求。即使將頂層時鐘提升,也是有上限的。這種情況下,可以使用單周期定時循環(huán)(SCTL)來實現(xiàn)功能。在單周期定時循環(huán)中,程序員可以控制聯(lián)合路徑的長度,因為程序不再自動在函數(shù)之間增加寄存器,而使用到的反饋節(jié)點以及移位寄存器在硬件上都使用觸發(fā)器來實現(xiàn)。另外,單周期定時循環(huán)可以使用的時鐘頻率更加豐富。基于這些原因,單周期定時循環(huán)的效率接近HDL語言。同樣將之前所述的代碼放入到單周期定時循環(huán)中。
我們來看一下這段代碼在普通的循環(huán)中和在單周期定時循環(huán)中的執(zhí)行效率。
可以看見,普通的循環(huán)由于 有系統(tǒng)自動添加的寄存器的效果,每個時鐘周期執(zhí)行一個運算函數(shù),而單周期定時循環(huán)可以在一個時鐘周期內(nèi)執(zhí)行循環(huán)內(nèi)的所有代碼。當(dāng)然,如果循環(huán)內(nèi)的代碼無法在一個時鐘周期內(nèi)完成,那么,程序在編譯時就會報出定時錯誤。這種情況下,需要修改代碼,減少關(guān)鍵路徑所占用的時間。
六、FPGA編程時的流水線使用
如上所述,如果單周期定時循環(huán)內(nèi)部代碼執(zhí)行所需的時間超出了定時時鐘限定的范圍,比如100MHz的時鐘限定了單周期定時循環(huán)每次執(zhí)行的時間為10ns,那么程序在編譯過程中就會報出定時錯誤。消除這種錯誤的方法就是減少關(guān)鍵路徑所占用的時間(關(guān)鍵路徑是代碼中需要時間最長的一條代碼路徑)。那如何消除?使用流水線。
流水線的編程方法就是人為地在關(guān)鍵路徑(最長執(zhí)行時延的路徑)中插入一些寄存器。這些寄存器可以將聯(lián)合的路徑拆分開,這一點與普通循環(huán)中系統(tǒng)自動添加的寄存器的作用是一致的。但在普通循環(huán)中,每個時鐘周期只執(zhí)行一個函數(shù),后續(xù)的函數(shù)雖然占用著硬件的資源,但由于沒有接收到前端的有效數(shù)據(jù)所以不會開始執(zhí)行。因此,整個循環(huán)的代碼的執(zhí)行時間是幾乎函數(shù)個數(shù)的總和。但是,既然各個函數(shù)都有各自預(yù)留的硬件資源,那為什么不能讓所有的函數(shù)在同一時間并行執(zhí)行呢?這就是流水線的含義。而在單周期定時循環(huán)內(nèi)部,在每個時鐘周期內(nèi),每一個流水線節(jié)點都從各自的起始點開始執(zhí)行。
上圖分別展示了普通的循環(huán)、普通的單周期定時循環(huán)以及具有流水線的單周期定時循環(huán)對于同一個程序的執(zhí)行流程。對于流水線的單周期定時循環(huán),前兩個周期的輸出數(shù)據(jù)是無效的,從第三個周期開始輸出了第一個有效的數(shù)據(jù),此后每個周期都會輸出一個有效的數(shù)據(jù)。所以,帶流水線的單周期定時循環(huán)的執(zhí)行效果只是會引入一定的輸出數(shù)據(jù)時延,其他方面沒有任何不同。而帶流水線的單周期定時循環(huán),由于使用了人為加入的反饋節(jié)點或者移位寄存器,將原來的關(guān)鍵路徑拆分成了好幾個部分,因此,一方面不容易在編譯時出現(xiàn)定時錯誤,另一方面由于縮短了關(guān)鍵路徑使得可以使用更高的時鐘頻率。具體編程時,請在時延和最高可達(dá)的時鐘頻率之間做一個權(quán)衡。
一些簡單的流水線編程技例子如下:
評論
查看更多