鐘資源全解析:從PLL到BUFG,搞定時(shí)序收斂)
做FPGA設(shè)計(jì)的人總有一天會被“時(shí)鐘資源”這四個(gè)字卡住。尤其是當(dāng)你把工程從仿真搬到板子上發(fā)現(xiàn)時(shí)序收斂不了、采樣老出錯(cuò)、PLL怎么都鎖不上翻來覆去排查半天根子往往就在時(shí)鐘資源的規(guī)劃和使用上。這篇文章想圍繞FPGA時(shí)鐘資源這個(gè)主題把時(shí)鐘網(wǎng)絡(luò)、時(shí)鐘管理模塊、時(shí)鐘約束、時(shí)序質(zhì)量這些事從頭到尾捋一遍聊清楚它們是什么、為什么重要、怎么用、怎么避坑。適合正準(zhǔn)備開始做時(shí)序收斂的FPGA開發(fā)者也適合被“時(shí)鐘偏斜”“BUFG不夠用”“時(shí)鐘域亂跳”折磨過但沒時(shí)間翻手冊的工程師。1. 先把時(shí)鐘資源家族認(rèn)全FPGA里面負(fù)責(zé)時(shí)鐘的硬件資源不是一個(gè)東西而是一整套體系。很多人只聽說過“PLL”以為時(shí)鐘資源就是PLL其實(shí)PLL只是其中一個(gè)環(huán)節(jié)。真正重要的是后面那棵“時(shí)鐘樹”以及連接時(shí)鐘進(jìn)入FPGA的專用引腳。這套體系可以粗略分成三大類全局時(shí)鐘網(wǎng)絡(luò)、區(qū)域時(shí)鐘與IO時(shí)鐘、時(shí)鐘管理模塊。每一類管的事不一樣用錯(cuò)了后面的時(shí)序報(bào)告就會給你顏色看。1.1 全局時(shí)鐘網(wǎng)絡(luò)芯片里的“城市主干道”全局時(shí)鐘網(wǎng)絡(luò)也就是常說的長線時(shí)鐘資源是FPGA里最穩(wěn)定、覆蓋范圍最大、偏斜最小的時(shí)鐘通路。你可以把它理解成一座城市的環(huán)形主干道所有關(guān)鍵街區(qū)都能快速到達(dá)而且紅綠燈設(shè)置得很均勻。普通邏輯互連資源則是小巷子走通能通但每條巷子的長度、彎道都不一樣信號到達(dá)時(shí)間自然千差萬別。時(shí)鐘信號如果走在普通互連上每個(gè)寄存器收到的時(shí)鐘邊沿會有明顯差異這就是偏斜。全局時(shí)鐘網(wǎng)絡(luò)從專門的時(shí)鐘引腳進(jìn)入FPGA后會經(jīng)由全局緩沖器再分往整個(gè)芯片。這個(gè)緩沖器就是BUFG——GA緩沖器。BUFG的延遲通常是固定的而且網(wǎng)絡(luò)內(nèi)部做了負(fù)載均衡所以芯片左上角寄存器和右下角寄存器收到同一個(gè)時(shí)鐘邊沿的時(shí)間差可以壓得很低只有幾百皮秒甚至更低。它對全局的高扇出信號特別友好所以不只是時(shí)鐘復(fù)位信號、高扇出的控制使能信號也經(jīng)常借用全局時(shí)鐘網(wǎng)絡(luò)來驅(qū)動(dòng)。我見過不少剛上手的工程師FPGA里明明有全局時(shí)鐘網(wǎng)絡(luò)因?yàn)椴皇煜ぶ苯影褍?nèi)部邏輯產(chǎn)生的一個(gè)信號當(dāng)“時(shí)鐘”接到寄存器時(shí)鐘端結(jié)果工具也不吭聲最后就是時(shí)序報(bào)告一堆違例跑起來偶發(fā)出錯(cuò)。記住一個(gè)原則真正決定系統(tǒng)節(jié)拍的時(shí)鐘特別是外部引腳進(jìn)來的參考時(shí)鐘一定要想辦法接到BUFG讓工具把它放到全局時(shí)鐘布線上。1.2 區(qū)域時(shí)鐘與IO時(shí)鐘特定范圍內(nèi)的專用通道不是所有信號都需要滿芯片范圍內(nèi)都拉一條低偏斜時(shí)鐘線。器件大了以后全局時(shí)鐘網(wǎng)絡(luò)覆蓋的路徑更長占用資源也多。為了兼顧靈活和效率FPGA內(nèi)部還會劃分為多個(gè)時(shí)鐘區(qū)域每個(gè)區(qū)域有獨(dú)立的區(qū)域時(shí)鐘緩沖器一般叫BUFH之類。區(qū)域時(shí)鐘只能驅(qū)動(dòng)本區(qū)域的邏輯延遲更短、資源開銷更小適用于那些只影響一小片局部的同步邏輯。還有一類是專門為輸入輸出寄存器準(zhǔn)備的IO時(shí)鐘它有著更強(qiáng)的驅(qū)動(dòng)能力和特殊的加速路徑用來做高速源同步接口的采集時(shí)鐘。比如你接一塊外部ADC數(shù)據(jù)線帶一個(gè)隨路時(shí)鐘DCODCO進(jìn)來后通常不應(yīng)該直接送全局時(shí)鐘網(wǎng)絡(luò)繞一圈而是就近接到區(qū)域時(shí)鐘或者IO時(shí)鐘鏈路這樣數(shù)據(jù)引腳和時(shí)鐘引腳之間的走線延遲關(guān)系更容易控制采樣窗口更好。這里需要特別留意區(qū)域時(shí)鐘不是“隨便一個(gè)普通IO都能進(jìn)”的你得用器件手冊上標(biāo)明的專用時(shí)鐘引腳區(qū)域。換句話說外部時(shí)鐘信號進(jìn)入FPGA的位置是有講究的。如果你的PCB原理圖上時(shí)鐘信號接到了普通數(shù)據(jù)引腳上就算邏輯上能功能仿真通過實(shí)際時(shí)序也大概率做不好甚至工具直接提示這條路徑?jīng)]有足夠的時(shí)鐘布線資源。1.3 時(shí)鐘管理模塊給時(shí)鐘做“整形”和變頻接下來是大家最熟悉的時(shí)鐘管理模塊PLL是鎖相環(huán)MMCM是混合模式時(shí)鐘管理器很多中高端FPGA上配的是MMCM早期器件則常用DCM這類延遲鎖定環(huán)。功能上它們差不多對外部輸入時(shí)鐘做倍頻、分頻、相移、占空比調(diào)整有的還能把輸入的差分時(shí)鐘轉(zhuǎn)成單端時(shí)鐘順便過濾一部分抖動(dòng)。PLL內(nèi)部的VCO壓控振蕩器工作范圍是有講究的。比如一個(gè)輸入時(shí)鐘是50MHz邏輯需要200MHz看起來倍頻系數(shù)是4就夠了。但很多器件PLL要求VCO頻率在某個(gè)范圍內(nèi)比如400MHz到800MHz那你不能在200MHz頻率點(diǎn)直接讓VCO停住而是要讓VCO先跑到中段頻率比如600MHz再分頻三次得到200MHz。配置工具通常會自動(dòng)算但理解這個(gè)機(jī)制很重要否則你換一顆器件PLL配置評估就會報(bào)“頻率超出范圍”或者“找不到合適的VCO頻率”。PLL輸出的時(shí)鐘如果是要發(fā)給全芯片邏輯用的一般還需要再過一級BUFG才能真正到全局網(wǎng)絡(luò)。很多工程軟件會自動(dòng)幫你插入這級緩沖但如果你的工程里手動(dòng)例化了PLL又沒合理設(shè)置時(shí)鐘資源屬性就可能會出現(xiàn)“PLL輸出時(shí)鐘沒有到全局布線資源上”這種隱蔽問題表現(xiàn)為時(shí)序分析里局部路徑偏斜特別大。所以看資源報(bào)告時(shí)不光要看PLL鎖沒鎖上還要看它的輸出到底走了哪一類時(shí)鐘布線。2. 時(shí)鐘方案怎么選不是越“高級”越好拿到一個(gè)項(xiàng)目需求外部時(shí)鐘頻率多少、需要產(chǎn)生幾路內(nèi)部時(shí)鐘、每路時(shí)鐘要用在哪里這些信息直接決定你選哪類資源。別看到一個(gè)“全局時(shí)鐘網(wǎng)絡(luò)”就覺得什么都往上放也別覺得PLL萬能。合理的方案往往是把不同種類的資源組合起來用。2.1 從使用場景倒推資源選擇我習(xí)慣把FPGA里的時(shí)鐘需求分成四類每類對應(yīng)一種默認(rèn)資源主時(shí)鐘也就是系統(tǒng)同步邏輯的節(jié)拍通常來自外部晶振或參考時(shí)鐘頻率比較高扇出非常大所有寄存器都用它。這種一定要走全局時(shí)鐘網(wǎng)絡(luò)。如果主時(shí)鐘頻率由PLL產(chǎn)生那PLL輸出再配一級全局緩沖就是最常見的標(biāo)準(zhǔn)結(jié)構(gòu)。局部功能模塊的時(shí)鐘比如某個(gè)接口模塊內(nèi)部用到的同步時(shí)鐘只影響模塊內(nèi)幾百個(gè)寄存器用一個(gè)區(qū)域時(shí)鐘就夠了。區(qū)域時(shí)鐘延遲更短而且不占用寶貴的主時(shí)鐘通路。高速源同步接口的采集時(shí)鐘比如DDR接口或者高速ADC/DAC數(shù)據(jù)流帶隨路時(shí)鐘這種時(shí)鐘往往直接送到IO時(shí)鐘入口讓數(shù)據(jù)和時(shí)鐘在IO寄存器處保持精確相位關(guān)系。把這種慢速使用的時(shí)鐘繞進(jìn)全局網(wǎng)絡(luò)反而會增加采樣不確定性。特殊用途的時(shí)鐘比如調(diào)試時(shí)用的觸發(fā)器信號、外部輸入中斷脈沖扇出不大對偏斜不那么敏感如果直接拿普通互連資源驅(qū)動(dòng)也不算致命。但需要注意任何作為“異步事件”的信號本來就不應(yīng)該出現(xiàn)在時(shí)鐘路徑上更合適的是當(dāng)成普通數(shù)據(jù)做同步。為方便對比我把常見資源、覆蓋范圍和典型用途整理成了下面這張表資源類型覆蓋范圍延遲與偏斜特點(diǎn)最典型用途全局時(shí)鐘網(wǎng)絡(luò)整個(gè)芯片延遲固定偏斜極低系統(tǒng)主時(shí)鐘、全局復(fù)位區(qū)域時(shí)鐘單個(gè)或相鄰時(shí)鐘區(qū)域延遲短局部偏斜低局部模塊時(shí)鐘IO時(shí)鐘IO寄存器周邊與數(shù)據(jù)引腳時(shí)序緊密對齊DDR接口、源同步采集PLL/MMCM頻率變換與相位調(diào)整鎖定后輸出穩(wěn)定倍頻、分頻、相移這里有一點(diǎn)要注意區(qū)域時(shí)鐘和IO時(shí)鐘的可用數(shù)量、連接關(guān)系與具體器件強(qiáng)相關(guān)同一個(gè)工程換器件型號時(shí)鐘方案很可能要重新審核。2.2 時(shí)鐘樹規(guī)劃的提前量畫板前就要想時(shí)鐘方案的規(guī)劃最忌諱在PCB畫完、甚至貼片完才做。外部時(shí)鐘信號進(jìn)入FPGA用的是專用時(shí)鐘引腳不同位置的引腳對應(yīng)到不同的全局時(shí)鐘入口、區(qū)域時(shí)鐘區(qū)域。如果你把外部時(shí)鐘隨便接了一個(gè)普通引腳后期就算內(nèi)部邏輯想給它接BUFG也很難布線因?yàn)槟憷@不開管腳本身的位置約束。我自己吃過一次虧。某個(gè)小項(xiàng)目里原理圖把外部時(shí)鐘接到了一個(gè)全能IO功能是可以的但布局布線跑到全局時(shí)鐘網(wǎng)絡(luò)延遲偏大區(qū)域時(shí)鐘資源又進(jìn)不去。當(dāng)時(shí)改了一版PCB多花了兩周。所以現(xiàn)在做方案我一定會提前確認(rèn)外部時(shí)鐘引腳是否可直達(dá)全局緩沖差分時(shí)鐘是否走了專用差分對復(fù)位按鍵信號要不要上全局網(wǎng)絡(luò)這些在FPGA管腳分配階段就要定好。另一個(gè)提前量是PLL輸入和輸出的數(shù)量。FPGA的時(shí)鐘管理模塊不是很多每個(gè)PLL能接的參考時(shí)鐘也有限。如果一個(gè)模塊接了多個(gè)PLL而每個(gè)PLL又都在做不同頻率變換那么規(guī)劃時(shí)就要核對功耗和資源余量。尤其是多路視頻或通信項(xiàng)目動(dòng)輒需要五六組內(nèi)部時(shí)鐘可能要做PLL級聯(lián)先用一路主PLL產(chǎn)生基頻再分配給第二級PLL或分頻器。2.3 別輕易使用門控時(shí)鐘寫RTL時(shí)很容易圖省事把某個(gè)使能信號和時(shí)鐘做一個(gè)與門得到一個(gè)“只在使能時(shí)跳變的時(shí)鐘”然后把門控時(shí)鐘接到寄存器上。這種糊口式寫法在仿真階段完全沒問題甚至看起來功耗還低因?yàn)椴还ぷ鲿r(shí)時(shí)鐘不翻轉(zhuǎn)。但在FPGA實(shí)現(xiàn)階段門控時(shí)鐘會帶來兩類非常麻煩的問題。第一是毛刺風(fēng)險(xiǎn)。與門的兩個(gè)輸入如果存在競爭冒險(xiǎn)輸出時(shí)鐘上可能蹦出窄脈沖如果這個(gè)窄脈沖正好被寄存器采到數(shù)據(jù)就可能寫壞。第二是靜時(shí)序分析困難。工具默認(rèn)把時(shí)鐘當(dāng)作周期信號來推導(dǎo)約束你的門控時(shí)鐘讓時(shí)序分析器很難定義時(shí)鐘邊沿要么你得寫復(fù)雜的約束要么干脆標(biāo)記成虛假路徑收斂質(zhì)量大打折扣。推薦的做法是保留時(shí)鐘一直翻轉(zhuǎn)用時(shí)鐘使能信號配合寄存器。比如一個(gè)計(jì)數(shù)器只有在數(shù)據(jù)有效的周期才計(jì)數(shù)就讓使能信號進(jìn)到時(shí)鐘域內(nèi)同步后再控制計(jì)數(shù)器而不是在時(shí)鐘路徑上插入門控。這幾乎可以省掉一大類“偶發(fā)數(shù)據(jù)錯(cuò)誤”。除非你有極強(qiáng)的低功耗設(shè)計(jì)需求且對毛刺做過專門分析否則盡量不要直接門控時(shí)鐘。3. 實(shí)操把時(shí)鐘資源真正用起來講完理論說說在工程里怎么把時(shí)鐘資源配置出來。我以一個(gè)真實(shí)的工程片段為例外部提供50MHz晶振系統(tǒng)邏輯需要200MHz的主時(shí)鐘另外一路接口需要75MHz參考時(shí)鐘還有一路外部ADC需要50MHz、相位滯后90度的采樣時(shí)鐘。3.1 從50MHz晶振到三組輸出時(shí)鐘先算頻率方案。主流FPGA里配置PLL時(shí)輸入50MHz要得到200MHz單純倍頻系數(shù)是4。但許多PLL的VCO范圍有下限比如最低400MHz那VCO就不能直接鎖在200MHz點(diǎn)。這時(shí)要讓VCO在600MHz附近工作再通過分頻器得到200MHz。75MHz可以由600MHz除以8得到50MHz帶90度相移則是在600MHz分頻配相移后得到。整個(gè)配置界面里會要求你填入輸入時(shí)鐘、輸出時(shí)鐘頻率、相移數(shù)值工具自動(dòng)給出M、D、O乘數(shù)分頻關(guān)系。實(shí)操時(shí)我一般會先把VCO頻率挑在器件標(biāo)稱范圍的中段附近這樣留有余量對溫度變化更穩(wěn)。配置完成后工具會生成一個(gè)時(shí)鐘模塊的IP核接口大致長這樣clk_gen u_clk_gen ( .clk_in (clk_in_50m), .clk_out_200m (clk_200m), .clk_out_75m (clk_75m), .clk_out_50m_90(clk_50m_90), .locked (pll_locked) );這里clk_in_50m是從專用時(shí)鐘引腳進(jìn)來的外部時(shí)鐘信號locked是PLL鎖定指示復(fù)位邏輯一定要等它拉高后再釋放不然早期時(shí)鐘還沒穩(wěn)定寄存器可能被寫入未知狀態(tài)。有一點(diǎn)值得提醒如果只是借用某個(gè)廠商工程向?qū)傻腎P接口名可能略有差異但關(guān)鍵信號基本都長這樣。真正需要關(guān)心的是例化后綜合的資源報(bào)告看你生成了幾個(gè)PLL、幾個(gè)全局緩沖。如果工具報(bào)了“全局時(shí)鐘緩沖不足”往往不是真的不夠用而是你把這個(gè)IP例化了很多份每份都帶一個(gè)全局緩沖。3.2 時(shí)鐘約束書寫讓時(shí)序分析器知道你的時(shí)鐘長什么樣有了時(shí)鐘網(wǎng)絡(luò)還要在時(shí)序約束里把你“希望工具認(rèn)為的時(shí)鐘”告訴它。常見工具支持SDC約束最基礎(chǔ)的就是創(chuàng)建時(shí)鐘。以外部100MHz輸入為例create_clock -name sys_clk -period 10.000 [get_ports clk_in_100m]period 10.000表示時(shí)鐘周期10納秒也就是100MHz。這條約束告訴時(shí)序分析器從clk_in_100m引腳進(jìn)來的信號是系統(tǒng)主時(shí)鐘周期10ns。PLL內(nèi)部生成的時(shí)鐘工具會根據(jù)IP配置自動(dòng)往后推衍不需要你手動(dòng)再定義只要時(shí)鐘源被正確約束了就行。實(shí)際項(xiàng)目里我通常還會跟上時(shí)鐘不確定度約束set_clock_uncertainty -setup 0.150 -hold 0.050 [get_clocks sys_clk]setup不確定度設(shè)得比hold大是因?yàn)樗瑫r(shí)鐘抖動(dòng)、板級噪聲、PLL相位噪聲等影響而hold相對更偏靜態(tài)。不確定度設(shè)置需要根據(jù)硬件質(zhì)量來別拍腦袋設(shè)太大余量太大容易把自己逼進(jìn)“時(shí)序永遠(yuǎn)收斂不了”的死胡同設(shè)太小又會讓工具盲樂觀板子上跑起來就可能翻車。另外要提到跨時(shí)鐘域約束。如果你有多個(gè)主時(shí)鐘而且彼此之間沒有確定相位關(guān)系就要用時(shí)鐘分組把它們設(shè)為“異步”的set_clock_groups -asynchronous \ -group [get_clocks sys_clk] \ -group [get_clocks pcie_refclk]這段約束的意思是兩個(gè)時(shí)鐘域之間的路徑時(shí)序分析器不需要檢查因?yàn)樵O(shè)計(jì)里已經(jīng)有跨時(shí)鐘域同步策略了。沒有這條約束工具默認(rèn)去約束兩個(gè)異步時(shí)鐘之間的路徑會產(chǎn)生大量假違例。3.3 手動(dòng)插入BUFG的時(shí)機(jī)與方法多數(shù)情況下工具會在綜合和布局布線階段自動(dòng)插入全局緩沖不需要你手動(dòng)干預(yù)。但有幾類場景需要手動(dòng)指定比如復(fù)位的同步釋放邏輯你想確保復(fù)位釋放沿在全芯片內(nèi)基本同時(shí)到達(dá)又比如某個(gè)內(nèi)部生成的時(shí)鐘你想強(qiáng)制它上全局網(wǎng)絡(luò)再比如從GTP/Serdes恢復(fù)出來的時(shí)鐘跨時(shí)鐘域之前希望先走一遍全局緩沖整形。手動(dòng)指定的一般方法是設(shè)置網(wǎng)絡(luò)屬性。以復(fù)位網(wǎng)絡(luò)為例可以在綜合工具里把復(fù)位網(wǎng)絡(luò)指定為全局緩沖set_property CLOCK_BUFFER_TYPE BUFG [get_nets rst_sync]注意這里的屬性名只是示意不同工具可能叫法不同但思路一致命名一個(gè)高扇出的網(wǎng)把它分配到全局時(shí)鐘緩沖器。手動(dòng)指定時(shí)我會先查一下網(wǎng)絡(luò)扇出如果扇出不到幾百個(gè)觸發(fā)器根本沒必要上BUFG用了反而浪費(fèi)全局時(shí)鐘資源。某些低端FPGA上全局緩沖數(shù)量少一個(gè)核心模塊用一個(gè)別每個(gè)復(fù)位都搞一個(gè)全局緩沖否則后續(xù)工程擴(kuò)展時(shí)資源會卡脖子。4. 時(shí)鐘質(zhì)量與時(shí)序收斂的關(guān)系時(shí)鐘資源選好、配好之后接下來的問題就是怎么去衡量這套時(shí)鐘系統(tǒng)到底好不好。很多工程師覺得PLL能鎖定、輸出頻率夠了就行直到時(shí)序分析報(bào)告里出現(xiàn)“clock skew”特別大的路徑才醒悟。時(shí)序收斂這件事本質(zhì)上就是和時(shí)鐘的偏斜、抖動(dòng)、延遲賽跑。4.1 偏斜、抖動(dòng)和延遲一個(gè)一個(gè)算明白延遲latency好理解時(shí)鐘從源頭到寄存器時(shí)鐘端的傳輸時(shí)間。偏斜skew是同一個(gè)時(shí)鐘到達(dá)兩個(gè)不同寄存器時(shí)鐘端的時(shí)間差。抖動(dòng)jitter是時(shí)鐘邊沿在時(shí)間軸上的不確定性PLL的抖動(dòng)通常比外部晶振直接進(jìn)來要小但也不是零。假設(shè)一條數(shù)據(jù)路徑時(shí)鐘周期10ns寄存器輸出延遲Tco是2ns組合邏輯延遲5ns建立時(shí)間0.5ns。如果不考慮偏斜時(shí)序余量是10-2-5-0.5等于2.5ns還挺寬裕。但如果這時(shí)時(shí)鐘偏斜是1.5ns余量直接被吃掉大半變成1ns偏斜到2.5ns余量只剩0超過2.5ns時(shí)序就violate了。這就是為什么全局時(shí)鐘網(wǎng)絡(luò)如此重要。普通邏輯繞線傳時(shí)鐘不同位置的走線長度差異可能是3納秒級別這足以讓一個(gè)本可以收時(shí)序的設(shè)計(jì)徹底崩潰。而全局時(shí)鐘網(wǎng)絡(luò)把偏斜壓到幾百皮秒反而讓數(shù)據(jù)路徑有了足夠的設(shè)計(jì)空間。jitter的影響則體現(xiàn)在時(shí)序余量計(jì)算里通常歸到時(shí)鐘不確定度里。一個(gè)非常臟的參考時(shí)鐘哪怕FPGA內(nèi)部PLL嘗試去過濾輸出jitter也可能達(dá)到幾百個(gè)皮秒如果通信接口本來就只有0.5ns的建立余量那必然是偶發(fā)錯(cuò)誤不斷。這種問題單純加大約束余量沒有意義要從源頭換晶振或者加一個(gè)干凈的時(shí)鐘緩沖器。4.2 同源時(shí)鐘與異步時(shí)鐘域先識別再處理做多時(shí)鐘設(shè)計(jì)時(shí)最大的坑不是“有多個(gè)時(shí)鐘”而是“不知道哪些時(shí)鐘是相關(guān)的”。兩個(gè)時(shí)鐘如果來自同一個(gè)PLL它們的相位關(guān)系是確定的工具可以推導(dǎo)出它們之間的路徑時(shí)序這種叫同步相關(guān)時(shí)鐘。比如PLL輸出的200MHz和75MHz如果都鎖定在同一個(gè)VCO上它們邊沿之間是有固定相位關(guān)系的??鐣r(shí)鐘域時(shí)可以直接用打拍同步來處理。但如果是兩個(gè)完全獨(dú)立的外部時(shí)鐘源比如一路來自板載晶振另一路來自PCIe參考時(shí)鐘源二者之間頻率和相位都沒有確定性關(guān)系這兩個(gè)時(shí)鐘域之間就必須用異步FIFO、握手同步再加回環(huán)測試等手段。這類時(shí)鐘之間要記得在約束里做異步分組否則時(shí)序分析器會去分析一堆不存在的路徑產(chǎn)生好幾千條假違例你修三天三夜也修不完。我遇到過最隱蔽的情況設(shè)計(jì)里兩個(gè)PLL的輸入來自同一個(gè)50MHz晶振但由于每個(gè)PLL內(nèi)部VCO相噪特性不同兩個(gè)PLL輸出之間并不嚴(yán)格同相它們不是完全同步的時(shí)鐘。從名字上看一個(gè)叫clk_pll_a一個(gè)叫clk_pll_b低級工程師可能想當(dāng)然認(rèn)為它們相關(guān)。處理這類問題我會直接打開時(shí)鐘樹報(bào)告看兩個(gè)時(shí)鐘的根節(jié)點(diǎn)是否同源、是否經(jīng)過同一個(gè)PLL共用的VCO而不是看名字長不長得像。4.3 復(fù)位與時(shí)鐘的配合細(xì)節(jié)時(shí)鐘資源的問題是“時(shí)鐘本身”但復(fù)位和時(shí)鐘的配合也經(jīng)常出幺蛾子。最常見的錯(cuò)誤是把復(fù)位信號直接接到寄存器異步復(fù)位端而復(fù)位釋放時(shí)刻沒有和時(shí)鐘對齊。舉個(gè)例子PLL鎖定后locked信號拉高你把這個(gè)信號直接拿來作為寄存器異步復(fù)位釋放時(shí)候看起來沒問題但locked信號本身既不是同步信號也未必和主時(shí)鐘邊沿對齊。如果恰好某個(gè)寄存器在復(fù)位釋放的瞬間時(shí)鐘邊沿到來它可能被寫入一個(gè)半穩(wěn)定狀態(tài)后面所有邏輯全亂。解決方式是用同步復(fù)位釋放電路reg rst_n_meta, rst_n_sync; always (posedge clk_200m or negedge global_rst_n) begin if (!global_rst_n) begin rst_n_meta 1b0; rst_n_sync 1b0; end else begin rst_n_meta pll_locked; rst_n_sync rst_n_meta; end end assign rst_n rst_n_sync;這樣就把PLL鎖定信號同步到主時(shí)鐘域再釋放復(fù)位。這類電路看起來簡單但很多人不做導(dǎo)致上板后偶發(fā)啟動(dòng)失敗。經(jīng)驗(yàn)是任何標(biāo)記為“異步復(fù)位同步釋放”的電路都要放在主時(shí)鐘域里仔細(xì)驗(yàn)證并且不要讓復(fù)位信號走普通邏輯資源到處漂必要時(shí)加一級BUFG。5. 常見問題排查時(shí)鐘相關(guān)的坑我基本都踩過最后聊幾個(gè)我在實(shí)際項(xiàng)目里反復(fù)見過的問題每個(gè)都伴隨過不少調(diào)試工時(shí)。整理成可檢索的形式希望對你有直接幫助。5.1 “BUFG不夠用”到底該怎么解報(bào)錯(cuò)信息可能是“全局時(shí)鐘緩沖資源不足”或者“無法分配時(shí)鐘網(wǎng)絡(luò)資源”。遇到這個(gè)先別急著刪PLL或換器件我通常按以下順序排查。先檢查是不是同一個(gè)時(shí)鐘被例化成了多個(gè)網(wǎng)絡(luò)尤其是多個(gè)PLL輸出同一頻率同一相位時(shí)工具可能給它們各分配了一個(gè)全局緩沖。正確的做法是讓它們合并或者主動(dòng)指定其中一個(gè)作為主時(shí)鐘網(wǎng)絡(luò)其他模塊直接借用。再檢查是不是復(fù)位網(wǎng)絡(luò)占了太多BUFG很多組件各自綜合一套復(fù)位同步邏輯每套都會嘗試用BUFG??梢园阉凶幽K的復(fù)位邏輯收斂到一個(gè)總復(fù)位模塊全系統(tǒng)共用一條全局復(fù)位網(wǎng)絡(luò)。最后檢查有沒有超大扇出的低優(yōu)先級信號也被自動(dòng)全局化了可以通過綜合選項(xiàng)里把全局緩沖插入閾值調(diào)大讓工具只在扇出超過一定數(shù)量時(shí)才使用全局緩沖。如果這三步都做完還缺緩沖那才需要考慮改用區(qū)域時(shí)鐘把不影響全局時(shí)序的局部時(shí)鐘挪到區(qū)域時(shí)鐘網(wǎng)絡(luò)。大部分情況下“不夠用”不是真不夠用而是資源分配不合理。5.2 PLL鎖不住或輸出時(shí)鐘不穩(wěn)PLL鎖定失敗首先要確認(rèn)參考輸入時(shí)鐘確實(shí)到了PLL引腳。示波器鉤不到FPGA內(nèi)部就看PLL的配置寄存器有沒有讀到locked信號拉高。如果locked一直拉不高看硬件輸入晶振是否起振、電平幅度是否滿足VMIN/VMAX、是不是誤把差分輸入接成了單端。再看配置輸入頻率是否在PLL允許范圍里輸出頻率計(jì)算是否超出了VCO范圍。有一種比較隱蔽的原因PLL的輸入?yún)⒖紩r(shí)鐘本身不穩(wěn)定。比如時(shí)鐘信號經(jīng)過了普通IO引腳再繞到PLL或者前端有沒做好的分頻器導(dǎo)致時(shí)鐘邊沿抖動(dòng)特別大PLL反復(fù)處于鎖定和失鎖狀態(tài)。排查時(shí)可以用一個(gè)已知干凈的外部信號做替換驗(yàn)證。如果換了干凈時(shí)鐘就能鎖定問題就在前端硬件而不是PLL配置。輸出時(shí)鐘不穩(wěn)還有一種表現(xiàn)是鎖定時(shí)序報(bào)告里顯示PLL輸出jitter很大。這個(gè)要么是參考源不干凈要么是配置里選的帶寬模式不對。低帶寬模式對輸入jitter過濾更好但鎖定時(shí)間更長高帶寬模式鎖定快但對輸入噪聲敏感。溫度變化劇烈的環(huán)境中調(diào)試優(yōu)先考慮低帶寬模式。5.3 時(shí)序報(bào)告里偏斜大得離譜布局布線后如果某一組時(shí)序路徑slack很緊打開時(shí)序報(bào)告看到clock skew那一列數(shù)值特別夸張多半是時(shí)鐘路徑走了“歪路”。常見原因有時(shí)鐘源沒進(jìn)專用時(shí)鐘引腳PLL輸出沒有接到全局緩沖局部邏輯處于一個(gè)離全局時(shí)鐘入口很遠(yuǎn)的區(qū)域時(shí)鐘繞了大半個(gè)芯片才到達(dá)。修復(fù)思路就是回到第2章講的資源規(guī)劃第一條是確認(rèn)觸發(fā)器陣列都放在離各自時(shí)鐘源較近的時(shí)鐘區(qū)域不要讓PLL在芯片左下角而一百個(gè)關(guān)鍵觸發(fā)器在右上角。第二條是確認(rèn)路徑上的時(shí)鐘有沒有真正使用全局網(wǎng)絡(luò)可以打開時(shí)鐘布線報(bào)告看一下時(shí)鐘網(wǎng)絡(luò)用的布線類型。第三條就是加約束在綜合階段把關(guān)鍵時(shí)鐘明確指定到某個(gè)全局緩沖不要完全依賴工具自動(dòng)選擇。5.4 現(xiàn)場避坑清單速查現(xiàn)象可能原因優(yōu)先排查動(dòng)作時(shí)鐘上出現(xiàn)毛刺門控時(shí)鐘或組合邏輯時(shí)鐘改成時(shí)鐘使能禁止組合邏輯輸出直接驅(qū)動(dòng)時(shí)鐘端仿真通過上電偶發(fā)錯(cuò)亂復(fù)位釋放太早locked未同步增加異步復(fù)位同步釋放電路等locked穩(wěn)定后再釋放BUFG資源不足高扇出信號各自上全局緩沖合并同頻同相時(shí)鐘復(fù)位網(wǎng)絡(luò)收斂到一條全局網(wǎng)絡(luò)PLL鎖定失敗輸入頻率范圍越界或參考時(shí)鐘抖動(dòng)核對輸入頻率可達(dá)性換干凈時(shí)鐘源時(shí)序報(bào)告出現(xiàn)大量違例時(shí)鐘域兩個(gè)異步時(shí)鐘域沒做時(shí)鐘分組增加set_clock_groups -asynchronous約束溫度一高就出錯(cuò)時(shí)鐘不確定度余量過小增加setup/hold不確定度檢查晶振溫度漂移這份清單不是萬能的但能覆蓋多數(shù)時(shí)鐘資源相關(guān)的低頻但麻煩的故障。排查時(shí)鐘問題最重要的是保持“先看時(shí)鐘再看邏輯”的順序。一個(gè)信號出問題如果我確認(rèn)它所在時(shí)鐘域和時(shí)鐘樹質(zhì)量沒問題那多半是邏輯問題如果時(shí)鐘樹本身就偏斜大、抖動(dòng)高那再怎么改邏輯都只是打補(bǔ)丁。最后自留地。我做時(shí)鐘資源規(guī)劃多年最大的體會是“規(guī)劃永遠(yuǎn)比修補(bǔ)省錢”。畫板之前花一天把時(shí)鐘引腳、PLL資源、全局緩沖數(shù)量核對清楚比后期為了把一個(gè)時(shí)鐘引到某個(gè)區(qū)域而重新布板要省幾周時(shí)間。另一個(gè)習(xí)慣是每次改動(dòng)時(shí)鐘樹或PLL配置后我不只跑增量實(shí)現(xiàn)而是從頭跑一遍嚴(yán)格完整的時(shí)序分析因?yàn)闀r(shí)鐘改動(dòng)會影響全芯片的每一個(gè)寄存器的時(shí)序關(guān)系。希望這篇能幫你少踩幾個(gè)坑把調(diào)試精力留給真正值得調(diào)的功能邏輯。