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