今天跟大家分享的內(nèi)容很重要,也是我們調(diào)試FPGA經(jīng)驗(yàn)的總結(jié)。隨著FPGA對(duì)時(shí)序和性能的要求越來越高,高頻率、大位寬的設(shè)計(jì)越來越多。在調(diào)試這些FPGA樣機(jī)時(shí),需要從寫代碼時(shí)就要小心謹(jǐn)慎,否則寫出來的代碼可能無法滿足時(shí)序要求。另外,最近跟網(wǎng)友聊天時(shí),有談到公眾號(hào)壽命的問題,我覺得網(wǎng)絡(luò)交換FPGA公眾號(hào)應(yīng)該在這方面有優(yōu)勢(shì),作為高校里從事FPGA開發(fā)的老師,又有興趣做公眾號(hào)的維護(hù),不會(huì)遇到其他公眾號(hào)做著做著就停更的問題,我們的公眾號(hào)也許將陪伴你十年甚至幾十年。同時(shí),也請(qǐng)大家放心,我們今后每篇文章都將用心的去總結(jié)歸納,確保篇篇都是干貨!新的一年開始了,希望在新的一年里,繼續(xù)給大家分享平時(shí)遇到的FPGA調(diào)試中遇到的問題及經(jīng)驗(yàn),一起進(jìn)步,一起努力,加油!
問題一:沒有對(duì)設(shè)計(jì)進(jìn)行全面的約束導(dǎo)致綜合結(jié)果異常,比如沒有設(shè)置異步時(shí)鐘分組,綜合器對(duì)異步時(shí)鐘路徑進(jìn)行靜態(tài)時(shí)序分析導(dǎo)致誤報(bào)時(shí)序違例。
約束文件包括三類,建議用戶應(yīng)該將這三類約束文件分開寫在三個(gè)xdc/sdc文件中。
第一類是物理約束,它主要對(duì)設(shè)計(jì)頂層的輸入輸出引腳的分配約束、電平標(biāo)準(zhǔn)的約束,
如下圖所示:在quartus環(huán)境下,對(duì)pcie_rstn和pcie_refclk的電平標(biāo)準(zhǔn)和管腳進(jìn)行了約束。
如下圖所示:在vivado環(huán)境下,對(duì)rst_n和sys_clk_PCIe_p的電平標(biāo)準(zhǔn)和管教進(jìn)行了約束。
第二類是調(diào)試約束,用戶在使用ila調(diào)試時(shí),Vivado會(huì)自動(dòng)生成相關(guān)ila的調(diào)試約束。 如下圖所示,這是Vivado自動(dòng)生成的相關(guān)ila的調(diào)試約束。
第三類是時(shí)序約束,這類約束的種類最多,它包括時(shí)鐘周期約束、輸入輸出延遲約束、跨時(shí)鐘域路徑約束、多周期路徑約束、偽路徑約束等。 時(shí)鐘周期約束:用戶需要將設(shè)計(jì)中的所有時(shí)鐘進(jìn)行約束后,綜合器才能進(jìn)行合理的靜態(tài)時(shí)序分析。一個(gè)設(shè)計(jì)中的時(shí)鐘主要分為兩類:主時(shí)鐘和生成時(shí)鐘。主時(shí)鐘包括由全局時(shí)鐘引腳接入的時(shí)鐘、高速收發(fā)器的輸出時(shí)鐘。生成時(shí)鐘包括由MMCM/PLL產(chǎn)生的時(shí)鐘、用戶邏輯分頻產(chǎn)生的時(shí)鐘,建議用戶不要使用后者,因?yàn)樗ǔJ怯山M合邏輯或觸發(fā)器生成的時(shí)鐘,這種時(shí)鐘的歪斜、抖動(dòng)、驅(qū)動(dòng)能力都很差。對(duì)時(shí)鐘進(jìn)行約束時(shí),主要針對(duì)時(shí)鐘的頻率、占空比、抖動(dòng)、不確定性等參數(shù)進(jìn)行約束。 全局時(shí)鐘引腳接入的時(shí)鐘約束舉例: 如下圖所示,在quatus環(huán)境下,對(duì)全局時(shí)鐘引腳接入的時(shí)鐘pcie_refclk進(jìn)行了約束,因?yàn)檎伎毡仁?0%,抖動(dòng)和不確定性也采用默認(rèn)值,所以圖中只對(duì)頻率進(jìn)行了約束。
如下圖所示,在vivado環(huán)境下,對(duì)全局時(shí)鐘引腳接入的時(shí)鐘sys_clk_PCIe_p進(jìn)行了約束,因?yàn)檎伎毡仁?0%,抖動(dòng)和不確定性也采用默認(rèn)值,所以圖中只對(duì)頻率進(jìn)行了約束。
高速收發(fā)器的輸出時(shí)鐘約束舉例:由于高速收發(fā)器通常是例化IP核來使用的,所以這種約束通常是IP核自帶的。 如下圖所示,在vivado環(huán)境下,PCIE IP核中對(duì)高速收發(fā)器的輸出時(shí)鐘進(jìn)行約束。
MMCM/PLL生成時(shí)鐘約束舉例: 如下圖所示,在quatus環(huán)境下,在sdc中加入以下命令,quatus會(huì)對(duì)所有PLL產(chǎn)生的時(shí)鐘進(jìn)行了約束。因?yàn)橛脩糁灰獙?duì)PLL的輸入時(shí)鐘(通常情況下是主時(shí)鐘)進(jìn)行了約束,在sdc中加入以下命令后,quatus能夠根據(jù)輸入時(shí)鐘和輸出時(shí)鐘的關(guān)系自動(dòng)推斷出PLL的輸出時(shí)鐘的時(shí)鐘周期、占空比、相位關(guān)系等。
如下圖所示,在vivado環(huán)境下,用戶對(duì)PCIE IP核中的MMCM的輸出時(shí)鐘進(jìn)行重命名,用戶只要確保對(duì)MMCM的輸入時(shí)鐘(通常情況下是主時(shí)鐘)進(jìn)行了約束,Vivado會(huì)自動(dòng)能夠根據(jù)輸入時(shí)鐘和輸出時(shí)鐘的關(guān)系自動(dòng)推斷出PLL的輸出時(shí)鐘的時(shí)鐘周期、占空比、相位關(guān)系等。
跨時(shí)鐘域約束:在介紹跨時(shí)鐘域之前,先介紹兩個(gè)概念:同步時(shí)鐘和異步時(shí)鐘。同步時(shí)鐘:當(dāng)兩個(gè)時(shí)鐘間的相位是固定的,則可以稱這兩個(gè)時(shí)鐘為同步時(shí)鐘。一般同源,如由同一個(gè)MMCM/PLL產(chǎn)生的兩個(gè)時(shí)鐘可以稱為同步時(shí)鐘。異步時(shí)鐘:無法判定兩個(gè)時(shí)鐘間相位時(shí),則可以稱這兩個(gè)時(shí)鐘為異步時(shí)鐘。兩個(gè)來自不同晶振的時(shí)鐘,一定是異步時(shí)鐘。通常情況下設(shè)計(jì)中不同的主時(shí)鐘肯定是異步時(shí)鐘。由不同的MMCM/PLL產(chǎn)生的兩個(gè)輸出時(shí)鐘即使頻率相同,但是由于相位關(guān)系不確定,所以也屬于異步時(shí)鐘。 用戶想要進(jìn)行跨時(shí)鐘域的約束,首先需要對(duì)設(shè)計(jì)中的所有時(shí)鐘進(jìn)行異步時(shí)鐘分組。若用戶沒有設(shè)置異步時(shí)鐘分組,綜合器在綜合時(shí)會(huì)認(rèn)為所有的時(shí)鐘都是相關(guān)的,從而對(duì)某些源時(shí)鐘與目的時(shí)鐘屬于異步時(shí)鐘關(guān)系的路徑進(jìn)行了靜態(tài)時(shí)序分析,由于源時(shí)鐘與目的時(shí)鐘的相位關(guān)系不確定,所以該路徑的建立時(shí)間或保持時(shí)間必定是存在違例的。若用戶設(shè)置了異步時(shí)鐘分組,Vivado在時(shí)序分析時(shí),當(dāng)源時(shí)鐘和目的時(shí)鐘屬于同一個(gè)時(shí)鐘組時(shí),才會(huì)分析此時(shí)序路徑;而源時(shí)鐘和目的時(shí)鐘屬于不同時(shí)鐘組時(shí),則會(huì)略過此時(shí)序路徑的分析。 那么如何進(jìn)行時(shí)鐘的異步分組呢?首先要按照上面提到同步時(shí)鐘和異步時(shí)鐘的概念對(duì)設(shè)計(jì)中的所有時(shí)鐘進(jìn)行分類,屬于異步時(shí)鐘關(guān)系的時(shí)鐘必定要?jiǎng)澐衷诓煌姆纸M中,屬于同步時(shí)鐘關(guān)系的時(shí)鐘可以分在同一個(gè)分組也可以分在不同的分組中,如何劃分要看具體情況而定。 如下圖所示,在quatus環(huán)境下,對(duì)時(shí)鐘進(jìn)行異步時(shí)鐘分組的劃分,圖中主要有3類時(shí)鐘, 由全局時(shí)鐘引腳輸入的pcie_refclk,PCIE IP核中的MMCM輸出的時(shí)鐘(圖中用通配符*表示) Flash_pll輸出的兩個(gè)不同頻率的時(shí)鐘outclk0和outclk1。首先要確定全局時(shí)鐘引腳輸入的時(shí)鐘和PCIE IP核中的MMCM輸出的時(shí)鐘以及Flash_pll輸出的兩個(gè)不同頻率的時(shí)鐘屬于異步時(shí)鐘關(guān)系,它們必須要?jiǎng)澐衷诓煌姆纸M中。但是,F(xiàn)lash_pll輸出的兩個(gè)不同頻率的時(shí)鐘outclk0和outclk1如何進(jìn)行劃分呢?首先,考慮一下設(shè)計(jì)中,outclk0和outclk1之間有沒有進(jìn)行數(shù)據(jù)交互,如果沒有數(shù)據(jù)交互,那么就將這兩個(gè)時(shí)鐘劃分在同一個(gè)時(shí)鐘分組即可,圖中就屬于這種情況。如果有數(shù)據(jù)交互,可以分為以下三種方案進(jìn)行操作: 1.將這兩個(gè)時(shí)鐘劃分在不同的時(shí)鐘分組,用戶在邏輯中進(jìn)行了跨時(shí)鐘域處理。(推薦使用) 2.將這個(gè)時(shí)鐘劃分在相同的時(shí)鐘分組,用戶在邏輯中進(jìn)行了跨時(shí)鐘域處理,在xdc/sdc中添加set_flase_path(偽路徑約束)禁止綜合器對(duì)跨時(shí)鐘域路徑(通常是雙觸發(fā)器同步的跨時(shí)鐘路徑)進(jìn)行靜態(tài)時(shí)序分析。 3.將這個(gè)時(shí)鐘劃分在相同的時(shí)鐘分組,用戶邏輯中不需要進(jìn)行跨時(shí)鐘域處理,由后端保證時(shí)序。
偽路徑約束:偽路徑約束主要用于以下情況:1.上文提到的對(duì)通過雙觸發(fā)器同步的跨時(shí)鐘域路徑設(shè)置偽路徑。2.異步復(fù)位路徑
在vivado環(huán)境下,通過以下指令將異步復(fù)位路徑sys_rst_n 設(shè)置為偽路徑
set_false_path-from [get_ports sys_rst_n]
在quatus環(huán)境下,通過以下指令將異步復(fù)位路徑pcie_rstn 設(shè)置為偽路徑
set_false_path-from [get_ports pcie_rstn] -to *
判斷條件過長問題
問題二:一個(gè)always塊的判斷條件中的部分變量或賦值語句中的部分被賦值變量是直接由組合邏輯產(chǎn)生的。當(dāng)組合邏輯不是特別長時(shí)或FPGA的資源利用率比較低時(shí),這種時(shí)序問題很可能會(huì)被綜合器優(yōu)化處理掉。但是當(dāng)組合邏輯鏈路過長時(shí),尤其是大位寬的寄存器進(jìn)行邏輯運(yùn)算生成了較長的組合邏輯鏈路時(shí),這種代碼風(fēng)格導(dǎo)致的時(shí)序問題就會(huì)比較明顯,最終導(dǎo)致always塊的輸入信號(hào)的延時(shí)變大,建立時(shí)間違例。
有時(shí)序問題的代碼如下圖所示,req_start_addr_reg信號(hào)和PC_LAST_ADDR信號(hào)屬于位寬較大的寄存器,圖中有三個(gè)典型問題需要注意。
第一個(gè)需要注意的問題:PC_LAST_ADDR信號(hào)是一個(gè)組合邏輯鏈路的輸出信號(hào),該組合邏輯鏈路是由邏輯運(yùn)算導(dǎo)致的。錯(cuò)誤的地方在于PC_LAST_ADDR信號(hào)直接被當(dāng)做always塊的輸入信號(hào)使用,導(dǎo)致always塊的輸入信號(hào)的延時(shí)變大,建立時(shí)間違例。正確的處理方式應(yīng)該是將PC_LAST_ADDR信號(hào)打一拍后,再將打一拍后的輸出信號(hào)作為always塊的輸入信號(hào)使用。
第二個(gè)需要注意的問題:在always塊的第三個(gè)和第四個(gè)的判斷條件中都是先進(jìn)行了邏輯運(yùn)算后再進(jìn)行邏輯判斷的。這個(gè)問題的本質(zhì)和第一個(gè)問題相同,都是將組合邏輯的輸出信號(hào)直接作為always塊的輸入信號(hào)使用,導(dǎo)致always塊的輸入信號(hào)的延時(shí)變大,建立時(shí)間違例。正確的處理方式應(yīng)該是將組合邏輯單獨(dú)拎出來,然后將組合邏輯的輸出結(jié)果打一拍后,再將打一拍后的輸出信號(hào)作為always塊的輸入信號(hào)使用。而且在always塊的第三個(gè)和第四個(gè)的判斷條件中使用了三段式狀態(tài)機(jī)的n_state作為了判斷條件,原因同上。正確的處理方式應(yīng)該盡量使用c_state作為判斷條件。
第三個(gè)需要注意的問題:在always塊的第四個(gè)賦值語句中,將兩個(gè)信號(hào)進(jìn)行邏輯運(yùn)算后進(jìn)行賦值操作。這個(gè)問題的本質(zhì)和第一個(gè)問題相同,都是將組合邏輯的輸出信號(hào)直接作為always塊的輸入信號(hào)使用,導(dǎo)致always塊的輸入信號(hào)的延時(shí)變大,建立時(shí)間違例。正確的處理方式應(yīng)該是將組合邏輯單獨(dú)拎出來,然后將組合邏輯的輸出結(jié)果打一拍后,再將打一拍后的輸出信號(hào)作為always塊的輸入信號(hào)使用。 修改之后的代碼如下圖所示:
總結(jié):在編寫代碼時(shí),應(yīng)該注意以下三點(diǎn): 1.應(yīng)該盡量保證每一個(gè)always塊的判斷條件簡潔(判斷條件中盡量只進(jìn)行邏輯判斷,盡量避免邏輯運(yùn)算) 2.應(yīng)該盡量保證每一個(gè)always塊的判斷條件中的每一個(gè)變量都是直接來源于某個(gè)always塊輸出信號(hào),盡量避免將組合邏輯的輸出直接作為某個(gè)always塊的判斷條件的一部分,這樣就可以保證每一個(gè)always塊的輸入信號(hào)的延時(shí)比較固定,有利于時(shí)序收斂。 3.應(yīng)該盡量保證每一個(gè)always塊的賦值語句中的被賦值變量都是直接來源于某個(gè)always塊輸出信號(hào),盡量避免將組合邏輯的輸出直接作為某個(gè)always塊的賦值語句中的一部分,這樣就可以保證每一個(gè)always塊的輸入信號(hào)的延時(shí)比較固定,有利于時(shí)序收斂。
if else嵌套層數(shù)過多
問題三:always塊中的if…else…嵌套層數(shù)過多導(dǎo)致綜合問題 有時(shí)序問題的代碼如下圖所示,always塊中嵌套了三層if…else…,正確的處理方式應(yīng)該盡量減少always塊中if…else…的嵌套層數(shù)。
修改之后的代碼如下圖所示,
總結(jié):在編寫代碼時(shí),應(yīng)該盡量減少always塊中的if…else…嵌套層數(shù).
邏輯信號(hào)扇出過大
問題四:部分用戶邏輯信號(hào)扇出過大,導(dǎo)致驅(qū)動(dòng)能力不足。
有時(shí)序問題的代碼如下圖所示,圖中三個(gè)always塊產(chǎn)生了一組RAM的寫信號(hào),這組信號(hào)作為55個(gè)always塊的輸入信號(hào),也就是說該信號(hào)驅(qū)動(dòng)了55個(gè)always塊,普通的信號(hào)的扇出能力一般在15-20左右。這組信號(hào)作為普通的用戶邏輯,如果采用加BUFG的方式來增加驅(qū)動(dòng)能力,這樣不僅浪費(fèi)BUFG的資源,而且BUFG會(huì)給信號(hào)加入極大的延時(shí),這種延時(shí)對(duì)于有些高速設(shè)計(jì)來說也許是不可接受的,一般只有全局復(fù)位信號(hào)才會(huì)使用BUFG增加驅(qū)動(dòng)能力。所以對(duì)于這種用戶邏輯信號(hào),推薦采用復(fù)制寄存器的方式解決驅(qū)動(dòng)能力不夠的問題。
修改之后的代碼如下圖所示:將原來的一組信號(hào),復(fù)制了兩份,總共三組信號(hào),且三組信號(hào)的邏輯相同,每組信號(hào)驅(qū)動(dòng)的always塊的個(gè)數(shù)變成了原來的1/3。但是同時(shí)需要注意的問題是,這種復(fù)制的寄存器有極大的可能會(huì)被綜合器當(dāng)作等效寄存器優(yōu)化掉,為了防止綜合器多管閑事,在quatus下需要在聲明被復(fù)制的寄存器前面加上(* noprune *)告知綜合器此寄存器不需要優(yōu)化,在vivado下需要在聲明被復(fù)制的寄存器前面加上(* keep =“true”*)告知綜合器此寄存器不需要優(yōu)化。
總結(jié):在編寫代碼時(shí),需要注意信號(hào)驅(qū)動(dòng)能力與扇出的問題,對(duì)扇出大的用戶邏輯信號(hào)進(jìn)行寄存器復(fù)制解決驅(qū)動(dòng)能力不足的問題。對(duì)于全局復(fù)位信號(hào),使用加BUFG解決驅(qū)動(dòng)能力不足的問題。
數(shù)據(jù)選擇器過大
問題五:用戶需要使用大型的數(shù)據(jù)選擇器(8選1以上的選擇器)時(shí),如果直接使用組合邏輯的case語句實(shí)現(xiàn)大型數(shù)據(jù)選擇器,可能會(huì)導(dǎo)致以下問題:綜合器綜合速度變慢,邏輯資源占用率變大,數(shù)據(jù)選擇器的相關(guān)信號(hào)時(shí)序違例會(huì)很大,數(shù)據(jù)選擇器的輸出結(jié)果也會(huì)極不穩(wěn)定。
有時(shí)序問題的部分代碼如下圖所示:用戶需要一個(gè)128選1的數(shù)據(jù)選擇器,圖中直接使用了一個(gè)組合邏輯的case語句實(shí)現(xiàn)了128選1。正確的處理方式應(yīng)該是將一個(gè)128選1的選擇器,分為3級(jí),第一級(jí)使用了16個(gè)8選1,第二級(jí)使用了2個(gè)8選1,第三級(jí)使用了1個(gè)2選1,總共消耗3個(gè)時(shí)鐘,選出最終的輸出結(jié)果,注意每一級(jí)的輸出結(jié)果都需要打一拍后再輸入到下一級(jí)進(jìn)行選擇。
修改之后的部分代碼如下圖所示,
總結(jié):大型數(shù)據(jù)選擇器不能直接使用組合邏輯的case語句實(shí)現(xiàn),在對(duì)選擇器的延時(shí)要求不是很高的情況下,最好將大型數(shù)據(jù)選擇器進(jìn)行分級(jí)選擇的處理。
大位寬RAM數(shù)據(jù)總線約束
問題六:高速設(shè)計(jì)中,RAM的輸出或寄存器的位寬太寬時(shí)(64bit以上),可能會(huì)出現(xiàn)在某個(gè)時(shí)鐘的上升沿時(shí),寄存器的某些bit由于布線導(dǎo)致路徑時(shí)延不一致,不能與其他bit的數(shù)據(jù)在同一個(gè)時(shí)鐘上升沿到達(dá),導(dǎo)致用戶采樣到數(shù)據(jù)出現(xiàn)錯(cuò)誤或者采樣到亞穩(wěn)態(tài)。所以,用戶要使用某個(gè)數(shù)據(jù)位寬很寬的寄存器時(shí),無論這個(gè)寄存器數(shù)據(jù)來源于FIFO還是來源于用戶邏輯,建議先將該寄存器打拍,然后使用打拍后的數(shù)據(jù),這樣更有利于時(shí)序收斂。 但如果從RAM里面輸出的大位寬的數(shù)據(jù)總線經(jīng)過打拍后仍然不穩(wěn)定又該怎么辦呢?筆者在實(shí)際調(diào)試過程中發(fā)現(xiàn),采用對(duì)使用大位寬總線RAM的時(shí)鐘信號(hào)進(jìn)行約束的方法非常有效。具體實(shí)現(xiàn)跟FPGA外圍管腳時(shí)鐘信號(hào)約束的方法一樣,比如下圖中在vivado工具中可以對(duì)設(shè)計(jì)中內(nèi)部某個(gè)用到大位寬的RAM的時(shí)鐘進(jìn)行創(chuàng)建即可。
總結(jié):大位寬的數(shù)據(jù)總線需要保持?jǐn)?shù)據(jù)傳輸過程中時(shí)延的一致性,盡可能的多采用時(shí)序邏輯,同時(shí)對(duì)于大位寬RAM的時(shí)鐘要進(jìn)行約束。
審核編輯 :李倩
-
FPGA
+關(guān)注
關(guān)注
1626文章
21671瀏覽量
601918 -
收發(fā)器
+關(guān)注
關(guān)注
10文章
3399瀏覽量
105865 -
Vivado
+關(guān)注
關(guān)注
19文章
808瀏覽量
66332
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論