鐘域設(shè)計(jì)全解析:從亞穩(wěn)態(tài)到異步FIFO的工程實(shí)踐)
1. 跨時(shí)鐘域?yàn)槭裁词菙?shù)字設(shè)計(jì)的“鬼門關(guān)”做數(shù)字設(shè)計(jì)這些年我見過太多功能仿真正常、上板就隨機(jī)出錯(cuò)的模塊最后定位下來十有八九和跨時(shí)鐘域CDC有關(guān)。只要設(shè)計(jì)里同時(shí)存在兩個(gè)以上異步時(shí)鐘域信號(hào)從一個(gè)時(shí)鐘域傳到另一個(gè)時(shí)鐘域時(shí)“零延遲瞬間跳變”的抽象模型就不成立了必須面對(duì)真實(shí)觸發(fā)器建立/保持時(shí)間、亞穩(wěn)態(tài)、多bit一致性問題。這一節(jié)先把根子上的原因說清楚后面講單bit、多bit處理方法才有依據(jù)。1.1 亞穩(wěn)態(tài)是CDC問題的根因任何觸發(fā)器都有一個(gè)采樣窗口由建立時(shí)間setup time和保持時(shí)間hold time共同決定。數(shù)據(jù)在時(shí)鐘沿到來之前和之后的一段窗口內(nèi)必須保持穩(wěn)定否則觸發(fā)器輸出可能停在一個(gè)既不是高電平也不是低電平的中間狀態(tài)這就是亞穩(wěn)態(tài)。亞穩(wěn)態(tài)不是模擬噪聲那種隨機(jī)小擾動(dòng)而是數(shù)字電路里真實(shí)存在的中間邏輯電平它會(huì)在門電路中被逐漸收斂到合法電平但收斂所需時(shí)間沒有上限。亞穩(wěn)態(tài)之所以危險(xiǎn)核心在于兩個(gè)點(diǎn)一是它可能超過一個(gè)時(shí)鐘周期才穩(wěn)定二是它可能對(duì)后續(xù)兩個(gè)不同路徑產(chǎn)生不同的邏輯解讀。前者會(huì)導(dǎo)致下一級(jí)觸發(fā)器再次采樣到非法電平后者會(huì)導(dǎo)致同一個(gè)亞穩(wěn)態(tài)信號(hào)在扇出到不同寄存器時(shí)被解讀成不同值。這也是為什么單bit同步器至少要兩級(jí)寄存器本質(zhì)上不是要“消掉”亞穩(wěn)態(tài)而是給輸出足夠的時(shí)間收斂降低亞穩(wěn)態(tài)傳播概率。MTBF平均無故障時(shí)間這個(gè)概念經(jīng)常被拿來做定量估算當(dāng)亞穩(wěn)態(tài)剩余時(shí)間超過一個(gè)目標(biāo)時(shí)鐘周期時(shí)后續(xù)觸發(fā)器再次采到亞穩(wěn)態(tài)的概率已經(jīng)低到可以用MTBF來衡量通常做得好的同步器MTBF都在幾十年甚至幾百年以上所以兩級(jí)足夠再往后加級(jí)數(shù)收益甚微。1.2 時(shí)鐘域劃分和失效場(chǎng)景比想象得多正常設(shè)計(jì)里異步時(shí)鐘域出現(xiàn)的場(chǎng)景大概這么幾類不同晶振產(chǎn)生的獨(dú)立時(shí)鐘PLL/MMCM分頻后不同相位的時(shí)鐘通常歸為同源時(shí)鐘還有電源域或復(fù)位域切換。最容易被忽視的是“同頻不同相”的兩個(gè)時(shí)鐘它們相位差固定但不確定綜合時(shí)無法用靜態(tài)時(shí)序分析去約束實(shí)際采樣位置可能貼近建立時(shí)間窗口風(fēng)險(xiǎn)一點(diǎn)不比完全異步小。還有一種隱藏場(chǎng)景是門控時(shí)鐘clock gating使能信號(hào)切來切去導(dǎo)致某些寄存器在特定時(shí)間段內(nèi)收不到時(shí)鐘沿?cái)?shù)據(jù)變化的時(shí)間點(diǎn)變成不可控這種跨時(shí)鐘域問題很難通過打拍完全解決。失效的表現(xiàn)也多種多樣同步后電平出現(xiàn)毛刺單bit脈沖被漏采多bit數(shù)據(jù)總線出現(xiàn)一個(gè)周期的“臟值”甚至FIFO讀寫指針碰撞。理解了這些表現(xiàn)再回頭去查“打拍”和“異步FIFO”的原理就會(huì)有更直接的體感??鐣r(shí)鐘域的終極目標(biāo)只有一個(gè)讓采到的數(shù)據(jù)要么是舊值要么是新值的完整表達(dá)絕不能是中間狀態(tài)或混合值。這里要特別強(qiáng)調(diào)很多人以為“跨時(shí)鐘域處理 打兩拍”就完事了這是個(gè)非常危險(xiǎn)的誤解。打兩拍只是最簡(jiǎn)單場(chǎng)景里的基本功真正工程上需要根據(jù)信號(hào)類型、傳輸方向、頻率關(guān)系、吞吐需求來做決策。2. 單bit信號(hào)跨時(shí)鐘域基礎(chǔ)但坑最多的傳輸場(chǎng)景單bit信號(hào)在跨時(shí)鐘域處理里屬于“看起來簡(jiǎn)單、實(shí)際門道多”的類型。一個(gè)布爾信號(hào)從A時(shí)鐘域到B時(shí)鐘域處理方式取決于它在A域里到底是什么形態(tài)持續(xù)電平信號(hào)還是一個(gè)只在某個(gè)周期拉高的脈沖。形態(tài)不同方案完全不同。下面把三種常見場(chǎng)景拆開講這也是我在多個(gè)項(xiàng)目里反復(fù)改版后總結(jié)出來的分類法。2.1 持續(xù)電平信號(hào)兩級(jí)同步器的正宗用法持續(xù)電平信號(hào)比如狀態(tài)標(biāo)志位、模式配置、使能信號(hào)在源時(shí)鐘域會(huì)維持多個(gè)目標(biāo)時(shí)鐘周期不變這是兩級(jí)同步器使用的前提。兩級(jí)同步器結(jié)構(gòu)很簡(jiǎn)單目標(biāo)時(shí)鐘域連續(xù)用兩個(gè)觸發(fā)器采源信號(hào)第一個(gè)觸發(fā)器輸出的亞穩(wěn)態(tài)信號(hào)經(jīng)過第二個(gè)觸發(fā)器后亞穩(wěn)態(tài)繼續(xù)傳播的概率極大降低。實(shí)際項(xiàng)目中我一般會(huì)盡量打三拍但不建議無腦打更多拍原因前面說過MTBF收益已經(jīng)飽和了。三拍更多是針對(duì)后端布局里同步器兩個(gè)寄存器物理距離太遠(yuǎn)、路徑延遲異常的情況留余量。能用兩級(jí)同步器的前提是源信號(hào)在目標(biāo)時(shí)鐘域采樣沿附近的變化頻率足夠低確保同步器第一級(jí)觸發(fā)器的輸入建立時(shí)間大概率不被違反。怎么定量判斷如果源信號(hào)翻轉(zhuǎn)間隔遠(yuǎn)大于目標(biāo)時(shí)鐘周期至少2-3倍以上基本安全。如果每次翻轉(zhuǎn)間隔接近目標(biāo)時(shí)鐘周期就不該繼續(xù)用打拍方式得轉(zhuǎn)握手或異步FIFO。很多同學(xué)寫代碼時(shí)不去確認(rèn)這個(gè)前提結(jié)果同步器第一級(jí)寄存器經(jīng)常采到接近建立時(shí)間窗口的信號(hào)亞穩(wěn)態(tài)概率飆升最終表現(xiàn)為系統(tǒng)運(yùn)行幾小時(shí)偶發(fā)一次死機(jī)這種故障最難排查。要注意的是同步器必須用目標(biāo)時(shí)鐘域的干凈時(shí)鐘驅(qū)動(dòng)寄存器的復(fù)位也要認(rèn)真處理。如果是異步復(fù)位復(fù)位信號(hào)本身要同步釋放如果是同步復(fù)位復(fù)位拉低時(shí)同步器寄存器復(fù)位復(fù)位釋放后還是要先同步進(jìn)來的數(shù)據(jù)這里經(jīng)常有人踩復(fù)位時(shí)序的坑后面第四部分細(xì)說。另外同步器的命名規(guī)范也很重要我習(xí)慣用sync_stage1、sync_stage2這種后綴方便CDC工具和代碼評(píng)審一眼定位。2.2 單bit脈沖信號(hào)的跨域不能直接打兩拍源時(shí)鐘域的脈沖信號(hào)寬度通常只有源時(shí)鐘一個(gè)周期到目標(biāo)時(shí)鐘域后如果目標(biāo)時(shí)鐘頻率較低很可能漏采如果目標(biāo)時(shí)鐘頻率較高連續(xù)采到同一個(gè)脈沖的高電平會(huì)把它當(dāng)成多個(gè)脈沖這在計(jì)數(shù)器或者中斷觸發(fā)邏輯里會(huì)直接造成邏輯錯(cuò)誤。所以脈沖跨域的思路不是簡(jiǎn)單打拍而是“先把脈沖變成電平”。經(jīng)典方案是脈沖同步器源域把輸入脈沖轉(zhuǎn)成電平翻轉(zhuǎn)信號(hào)例如每次脈沖翻轉(zhuǎn)一次輸出然后用兩級(jí)同步器把翻轉(zhuǎn)信號(hào)同步到目標(biāo)域再在目標(biāo)域檢測(cè)翻轉(zhuǎn)沿上升沿或下降沿檢測(cè)到沿就還原出一個(gè)目標(biāo)域脈沖。這個(gè)方案天然適合“源域是慢時(shí)鐘、目標(biāo)域是快時(shí)鐘”的場(chǎng)景。如果目標(biāo)域比源域慢單個(gè)輸入脈沖在經(jīng)過電平翻轉(zhuǎn)同步后目標(biāo)域檢測(cè)沿時(shí)可能已經(jīng)錯(cuò)過多個(gè)周期嗎不會(huì)因?yàn)殡娖椒D(zhuǎn)保持到下一個(gè)輸入脈沖到來才再次翻轉(zhuǎn)目標(biāo)域只要采樣到翻轉(zhuǎn)沿就一定能還原脈沖只是延遲不定。但是如果源域連續(xù)兩個(gè)脈沖間隔很短在目標(biāo)域看來兩個(gè)翻轉(zhuǎn)沿相鄰很近能否分辨取決于目標(biāo)域時(shí)鐘能否以大于2倍脈沖密度的頻率采樣。工程上這種方案適合低速率事件型信號(hào)比如中斷請(qǐng)求、觸發(fā)命令。高吞吐的脈沖流就別用這個(gè)了。我再補(bǔ)充一個(gè)常見實(shí)現(xiàn)細(xì)節(jié)電平翻轉(zhuǎn)信號(hào)最好在源域用專門的觸發(fā)器輸出不要在組合邏輯之后直接翻轉(zhuǎn)否則翻轉(zhuǎn)瞬間毛刺會(huì)直接影響后續(xù)同步邏輯這一點(diǎn)在FPGA上尤其明顯LUT輸出毛刺被同步器第一級(jí)采到后也會(huì)產(chǎn)生亞穩(wěn)態(tài)。2.3 快時(shí)鐘域到慢時(shí)鐘域的單bit傳輸握手更穩(wěn)妥當(dāng)源域時(shí)鐘比目標(biāo)域快一個(gè)脈沖在源域只有一個(gè)周期寬目標(biāo)域采樣周期比脈沖長(zhǎng)很多即使脈沖同步器能捕捉翻轉(zhuǎn)也會(huì)遇到“兩個(gè)連續(xù)脈沖間隔小于目標(biāo)域采樣周期”的瓶頸。此時(shí)單bit已經(jīng)不夠必須引入反饋路徑做握手協(xié)議源域拉起請(qǐng)求信號(hào)req目標(biāo)域兩級(jí)同步req采樣后回送ack源域再同步ack之后才撤下req。這本質(zhì)上是把單bit變成了“請(qǐng)求-應(yīng)答”狀態(tài)機(jī)。握手協(xié)議的優(yōu)點(diǎn)是可靠缺點(diǎn)是延遲大、吞吐低適合偶發(fā)的慢速控制命令不適合高頻數(shù)據(jù)流。實(shí)現(xiàn)時(shí)要小心狀態(tài)機(jī)的死鎖req必須等待ack回來再撤撤掉后目標(biāo)域檢測(cè)到req下落也要清掉ack這樣才能處理下一次請(qǐng)求。如果兩邊的時(shí)鐘域偶然出現(xiàn)復(fù)位錯(cuò)位很容易卡死在滿狀態(tài)所以握手協(xié)議里必須加超時(shí)保護(hù)或者復(fù)位釋放順序保證。我一般會(huì)寫一個(gè)簡(jiǎn)單的狀態(tài)機(jī)源域狀態(tài)IDLE→REQ_SET→WAIT_ACK→REQ_CLR→WAIT_ACK_CLR目標(biāo)域?qū)?yīng)IDLE→WAIT_REQ→DATA_LATCH→ACK_SET→WAIT_REQ_CLR→ACK_CLR兩邊都對(duì)兩級(jí)同步后的信號(hào)做沿判斷邏輯上非常清晰。到這里單bit部分就三種持續(xù)電平用打拍慢到快的脈沖用脈沖同步器快到慢且密集的脈沖用握手。這個(gè)分類是我在實(shí)際項(xiàng)目中反復(fù)修改后總結(jié)出來的比籠統(tǒng)說“打兩拍脈沖同步”要實(shí)用得多。3. 多bit信號(hào)跨時(shí)鐘域分門別類看方案別亂打拍多bit跨時(shí)鐘域是很多人的知識(shí)盲區(qū)。一個(gè)8位計(jì)數(shù)器從快時(shí)鐘域傳到慢時(shí)鐘域如果直接把每個(gè)bit都打兩拍同步問題極大每個(gè)bit相對(duì)時(shí)鐘沿的延遲不同采樣窗口不同甚至?xí)霈F(xiàn)某個(gè)bit采樣到新值、另一個(gè)bit還停在舊值的狀態(tài)導(dǎo)致組合出來的數(shù)值既不是舊值也不是新值而是亂七八糟的中間值。比如4位計(jì)數(shù)器從0111變到1000理論上只是1但如果低三位先變成000最高位還沒變目標(biāo)域會(huì)采到0000或0111之外的數(shù)值當(dāng)場(chǎng)數(shù)據(jù)撕裂。所以要正確處理多bit信號(hào)必須按信號(hào)類型選方案而不是無腦打拍。下面把工程里常見的幾類情況分別講清楚。3.1 多bit數(shù)據(jù)流異步FIFO幾乎是標(biāo)準(zhǔn)答案當(dāng)我們要跨時(shí)鐘域傳輸連續(xù)不斷的多bit數(shù)據(jù)流比如圖像像素、ADC采樣序列、網(wǎng)絡(luò)包異步FIFO是幾乎繞不開的方案。讀寫兩端各自用本地時(shí)鐘數(shù)據(jù)寫入FIFO存儲(chǔ)陣列讀端按自己的時(shí)機(jī)讀出。關(guān)鍵在于讀寫指針的比較不能直接放在兩個(gè)時(shí)鐘域下進(jìn)行——它本身也是多bit信號(hào)也會(huì)遇到撕裂問題。異步FIFO真正成熟的做法是讓寫指針轉(zhuǎn)換成格雷碼后同步到讀時(shí)鐘域讀指針轉(zhuǎn)換成格雷碼后同步到寫時(shí)鐘域再用兩級(jí)同步后的格雷碼指針做滿/空比較。格雷碼的妙處在于相鄰計(jì)數(shù)值之間只有一位變化把多bit不一致問題轉(zhuǎn)化為單bit異步問題同步后讀到的指針最多是“超前/滯后一個(gè)計(jì)數(shù)值”的狀態(tài)不會(huì)出現(xiàn)亂碼。二進(jìn)制轉(zhuǎn)格雷碼的公式就一行g(shù)ray (bin 1) ^ bin。但這里有個(gè)容易漏掉的坑就是FIFO深度必須是2的冪次才能保證格雷碼的循環(huán)對(duì)稱性如果深度不是2的冪指針回繞時(shí)會(huì)打破格雷碼相鄰條件空滿判斷直接失效。需要提醒的是滿空判斷有細(xì)節(jié)寫滿判斷要拿讀指針的格雷碼同步到寫時(shí)鐘域后和寫指針比較而且讀指針要“打兩拍”所以寫滿信號(hào)天然是保守的可能晚幾個(gè)周期才拉高好處是絕不會(huì)漏掉真正的滿讀空同理。深度設(shè)計(jì)要根據(jù)讀寫頻差、突發(fā)長(zhǎng)度算一般至少比突發(fā)長(zhǎng)度多兩級(jí)比如寫時(shí)鐘100MHz、讀時(shí)鐘80MHz、突發(fā)長(zhǎng)度64拍那深度至少64幾級(jí)余量通常取128。這里還要考慮讀寫頻率比極端情況比如讀端只偶爾讀一次寫端連續(xù)寫就需要更深的FIFO否則直接溢出。只有幾個(gè)深度的小FIFO直接等內(nèi)部雙口RAM實(shí)現(xiàn)也很常見但不建議自己寫滿空拉起邏輯直接調(diào)IP核更穩(wěn)。3.2 多bit寄存器配置握手式同步寧慢勿亂如果說異步FIFO解決的是“數(shù)據(jù)流”那么多bit寄存器配置比如配置字、寄存器地址、查找表數(shù)據(jù)就是“低速突發(fā)”場(chǎng)景特點(diǎn)是數(shù)量不多、需要正確性優(yōu)先級(jí)極高、延遲無所謂。這種情況下握手協(xié)議是合適選擇源域先準(zhǔn)備好數(shù)據(jù)拉req目標(biāo)域同步req到本地采樣數(shù)據(jù)回ack源域同步ack后知道數(shù)據(jù)已經(jīng)被安全采到再撤req完成一次傳輸。四階段握手里信號(hào)變化的過程容易出錯(cuò)req和ack都存在多拍延遲源域撤req后目標(biāo)域必須看到req下落再撤ack否則可能出現(xiàn)重復(fù)采數(shù)。具體實(shí)現(xiàn)可以用狀態(tài)機(jī)也可以把數(shù)據(jù)保持到ack回來之前都別變。我習(xí)慣在源域?qū)懸粋€(gè)簡(jiǎn)單的“先放數(shù)據(jù)、再拉req、等ack、撤req”的狀態(tài)機(jī)目標(biāo)域則用“看到req、鎖存數(shù)據(jù)、拉ack、等req下落、撤ack”的狀態(tài)機(jī)兩邊都對(duì)兩級(jí)同步后的信號(hào)做沿判斷。寫代碼時(shí)要注意目標(biāo)域鎖存數(shù)據(jù)必須在拉高ack之前完成因?yàn)樵从蚩吹絘ck之后可能立刻改變數(shù)據(jù)內(nèi)容如果ack拉高和數(shù)據(jù)采樣在同一個(gè)組合邏輯塊里容易產(chǎn)生采樣窗口違例。這種握手方式吞吐確實(shí)低但跨時(shí)鐘域的寄存器配置本來就不是高吞吐場(chǎng)景正確性遠(yuǎn)大于速度。有些同學(xué)想優(yōu)化成“一次握手傳多個(gè)數(shù)據(jù)”那不如直接上同步FIFO別自己造復(fù)雜協(xié)議。實(shí)際項(xiàng)目中如果配置數(shù)據(jù)來自CPU總線通常還會(huì)給握手模塊加一個(gè)超時(shí)計(jì)數(shù)器防止CPU寫操作因?yàn)楫惒竭壿嬁ㄋ蓝鴴炱疬@個(gè)保護(hù)邏輯很便宜但能讓系統(tǒng)在異常復(fù)位時(shí)自動(dòng)恢復(fù)。3.3 受控?cái)?shù)據(jù)和近似單調(diào)信號(hào)MUX同步與格雷碼的巧用除了連續(xù)數(shù)據(jù)流和突發(fā)配置還有兩種多bit場(chǎng)景值得單獨(dú)說。第一種是“源域變化頻率低、且允許目標(biāo)域在某些周期內(nèi)保持舊值”的信號(hào)比如視頻處理中的分辨率配置、增益系數(shù)等??梢杂肕UX同步多路選擇器法把多個(gè)bit送到目標(biāo)域后不直接采樣而是通過一組選擇信號(hào)通常是同步過的使能信號(hào)來控制目標(biāo)寄存器何時(shí)鎖存數(shù)據(jù)。本質(zhì)上是“先同步一個(gè)單bit使能再采樣多bit數(shù)據(jù)”——只要使能信號(hào)能表明數(shù)據(jù)已穩(wěn)定數(shù)據(jù)本身就可以是組合邏輯供給。注意使能和數(shù)據(jù)之間必須滿足目標(biāo)時(shí)鐘的建立保持關(guān)系通常把數(shù)據(jù)提前一拍擺好再拉使能。舉例來說源域在t0更新數(shù)據(jù)t1拉高valid目標(biāo)域同步valid到本地后產(chǎn)生lock信號(hào)此時(shí)數(shù)據(jù)總線早就穩(wěn)定了鎖存就不會(huì)出錯(cuò)。如果數(shù)據(jù)更新緊貼著valid拉高就必須在源域先把數(shù)據(jù)寄存一拍再讓valid跟隨寄存器輸出保證目標(biāo)域看到valid時(shí)數(shù)據(jù)已經(jīng)穩(wěn)定了至少一個(gè)源域時(shí)鐘周期。第二種是“單調(diào)連續(xù)變化”的多bit信號(hào)比如FIFO指針、旋轉(zhuǎn)角度編碼、伽馬校正表地址。如果變化時(shí)嚴(yán)格單調(diào)可以用格雷碼直接跨域原理和異步FIFO指針一樣。不是所有計(jì)數(shù)器都適合轉(zhuǎn)格雷碼只有相鄰值之間單bit翻轉(zhuǎn)才可行如果值會(huì)跳躍變化就必須考慮握手或FIFO。這里有個(gè)誤區(qū)很多人以為只要把多bit轉(zhuǎn)成格雷碼就可以直接打拍同步實(shí)際還要考慮變化速率。如果連續(xù)兩個(gè)計(jì)數(shù)值之間的間隔小于目標(biāo)時(shí)鐘周期即使格雷碼只有1bit變化那1bit也會(huì)有漏采風(fēng)險(xiǎn)。所以轉(zhuǎn)格雷碼跨域的前提是值變化的頻率必須遠(yuǎn)低于目標(biāo)時(shí)鐘頻率否則依然要加同步FIFO。4. 工程實(shí)踐中的坑與經(jīng)驗(yàn)理論講完說說實(shí)際項(xiàng)目里我踩過、看過別人踩的坑。CDC最大的問題不是方案不會(huì)選而是“細(xì)節(jié)摧毀一切”下面這些點(diǎn)每一條都對(duì)應(yīng)過一次真實(shí)的故障定位。每次做設(shè)計(jì)評(píng)審我都會(huì)把這幾條當(dāng)成檢查清單逐項(xiàng)過一遍能攔下很多后期問題。4.1 同步器打拍并不是“能打幾拍就打幾拍”很多人為了心里踏實(shí)把同步器打了五六拍美其名曰“超級(jí)多拍同步”其實(shí)從MTBF角度來說兩拍之后亞穩(wěn)態(tài)傳播概率已經(jīng)低到和單粒子翻轉(zhuǎn)同等量級(jí)再多打拍收益極低反而增加了數(shù)據(jù)在目標(biāo)域的延遲也容易讓綜合時(shí)序變差。真正應(yīng)該關(guān)注的是同步器第一級(jí)寄存器的輸入Fmax是否滿足以及與后端布局的物理距離。如果同步器兩個(gè)寄存器離得太遠(yuǎn)中間走線延遲過大第一級(jí)輸出的亞穩(wěn)態(tài)信號(hào)在到達(dá)第二級(jí)時(shí)可能還沒收斂等于同步器失效。所以后端約束里最好給同步器寄存器組加set_false_path或?qū)iT的placement約束把兩個(gè)寄存器放在相鄰的slice里。如果條件允許打開綜合工具的跨時(shí)鐘域分析報(bào)告看MTBF和同步器建議比手動(dòng)加寄存器靠譜得多。另外同步器之間不要插組合邏輯比如sync_q2 sync_q1;中間再加個(gè)與門這等于破壞了兩級(jí)寄存器的亞穩(wěn)態(tài)收斂鏈路會(huì)讓蹺蹺板效應(yīng)失控。我看過有人為了省寄存器用assign sync_q2 sync_q1 en;這種寫法在CDC工具里會(huì)直接報(bào)錯(cuò)但在普通仿真里完全看不出來等到芯片回來后才會(huì)偶發(fā)故障非???。4.2 異步FIFO的空滿標(biāo)志存在“虛報(bào)警”要習(xí)慣保守設(shè)計(jì)異步FIFO的空滿標(biāo)志本來就是異步邏輯生成的目標(biāo)域看到它時(shí)可能已經(jīng)滯后了幾個(gè)時(shí)鐘周期所以“滿”標(biāo)志晚拉高沒關(guān)系關(guān)鍵是它不能提前拉高——否則會(huì)誤判寫入失敗。同理“空”標(biāo)志也不能提前拉低。格雷碼比較時(shí)如果要判斷“即將滿/即將空”需要在格雷碼里額外做并行判斷那個(gè)邏輯極其容易寫錯(cuò)最好直接使用成熟IP核而不是自己寫滿空生成電路。自己手寫過一次仿真跑了幾千次都沒問題上板后寫滿標(biāo)志偶發(fā)提前一個(gè)周期拉高導(dǎo)致寫端丟掉一拍數(shù)據(jù)定位了兩天才發(fā)現(xiàn)是格雷碼比較時(shí)把滿和即將滿兩個(gè)條件寫成了或關(guān)系這個(gè)錯(cuò)誤在非邊界情況下永遠(yuǎn)不觸發(fā)。項(xiàng)目里遇到一個(gè)典型案例我們自研的異步FIFO在空標(biāo)志置位后讀端立即停止讀但由于空標(biāo)志晚了兩拍實(shí)際上FIFO里還有一個(gè)有效數(shù)據(jù)沒有被讀走導(dǎo)致下游數(shù)據(jù)流卡死。排查了半天最后發(fā)現(xiàn)是讀指針同步路徑多個(gè)寄存器的物理位置距離太遠(yuǎn)等效采樣延遲增大空標(biāo)志拉高時(shí)間比預(yù)期晚。解決辦法是給空標(biāo)志多打一拍同時(shí)讀端看到空后再等一拍徹底繞開“晚空”問題。這個(gè)教訓(xùn)讓我后來設(shè)計(jì)所有異步FIFO的讀控制邏輯時(shí)都把空標(biāo)志當(dāng)成“建議性信號(hào)”而不是“精確信號(hào)”來處理。4.3 復(fù)位、時(shí)鐘門控和CDC交織在一起時(shí)最要命跨時(shí)鐘域從來不是只有“數(shù)據(jù)”要處理復(fù)位同樣會(huì)跨時(shí)鐘域而且時(shí)鐘門控clock gating會(huì)讓某些寄存器在特定時(shí)間段內(nèi)收不到時(shí)鐘沿。異步復(fù)位信號(hào)如果不經(jīng)過同步就釋放極有可能在目標(biāo)時(shí)鐘的有效沿附近撤走等于給目標(biāo)域寄存器引入一個(gè)亞穩(wěn)態(tài)復(fù)位輕則數(shù)據(jù)錯(cuò)位重則狀態(tài)機(jī)跑飛。標(biāo)準(zhǔn)做法是“異步復(fù)位、同步釋放”復(fù)位輸入先用目標(biāo)時(shí)鐘域兩級(jí)同步器同步再作為寄存器的異步復(fù)位端確保復(fù)位撤銷只發(fā)生在目標(biāo)時(shí)鐘域時(shí)鐘沿附近。同步釋放模塊建議做成一個(gè)小IP不要在每個(gè)模塊里重復(fù)寫否則很容易出現(xiàn)某些模塊寫對(duì)、某些模塊寫漏的情況。除此以外時(shí)鐘門控的使能信號(hào)如果來自另一個(gè)時(shí)鐘域也要先同步使能否則門控打開瞬間時(shí)鐘沿跳變位置不可控會(huì)讓同步器第一級(jí)采到半個(gè)周期信號(hào)。實(shí)際項(xiàng)目里我們遇到過一個(gè)uart模塊的接收時(shí)鐘門控使能來自CPU總線的異步信號(hào)CPU配置完使能后立刻進(jìn)入中斷uart偶爾會(huì)漏掉第一個(gè)起始位。后來在使能路徑上加兩級(jí)同步器再讓門控在同步后的使能穩(wěn)定后再打開問題才消失。門控和復(fù)位的組合拳是跨時(shí)鐘域里最容易被忽略的暗坑。4.4 CDC驗(yàn)證要靠約束工具定向用例三者配合功能仿真很難暴露亞穩(wěn)態(tài)導(dǎo)致的時(shí)序問題因?yàn)榉抡嫫骰灸J(rèn)所有觸發(fā)器的clk-to-q延遲為0。所以工程上要三管齊下首先在SDC約束文件里把異步時(shí)鐘域明確的set_clock_groups -asynchronous寫清楚杜絕綜合工具在這條路徑上白做時(shí)序收斂其次用CDC lint工具比如Questa CDC、SpyGlass、或者綜合器的CDC報(bào)告把未同步的跨域路徑全部列出來最后在仿真里用定向用例模擬最惡劣情況故意把源數(shù)據(jù)在目標(biāo)時(shí)鐘沿附近反復(fù)翻轉(zhuǎn)觀察同步后是否出現(xiàn)錯(cuò)誤。我一般會(huì)寫一個(gè)隨機(jī)抖動(dòng)的testbench給跨域信號(hào)加0到1個(gè)目標(biāo)時(shí)鐘周期的隨機(jī)延遲跑長(zhǎng)時(shí)間回歸很多同步器時(shí)序問題能在這種仿真中暴露出來。這三個(gè)環(huán)節(jié)里最容易被忽視的是約束。很多團(tuán)隊(duì)后端綜合時(shí)不寫set_clock_groups工具會(huì)自動(dòng)把異步時(shí)鐘域當(dāng)同步路徑去檢查時(shí)序結(jié)果報(bào)出大量violation要么后端硬著頭皮修到很累要么干脆例外導(dǎo)致真正的CDC問題被掩蓋。正確的做法是前端設(shè)計(jì)最早就把這些約束寫清楚并搭配lint工具做卡關(guān)而不是等后端報(bào)警才回來改。另外別忘了在仿真里對(duì)異步FIFO的跨域指針做隨機(jī)延遲注入只測(cè)功能通不通是不行的要測(cè)極端頻差下的滿空行為。5. 從項(xiàng)目實(shí)戰(zhàn)中沉淀的跨時(shí)鐘域決策清單最后分享一個(gè)實(shí)戰(zhàn)中可抄作業(yè)的決策清單也是我在評(píng)審各種設(shè)計(jì)時(shí)反復(fù)用的套路。這個(gè)表每隔一段時(shí)間就會(huì)更新一次但分類骨架一直沒變。5.1 一張場(chǎng)景-方案對(duì)照表信號(hào)類型典型場(chǎng)景推薦方案關(guān)鍵注意點(diǎn)單bit持續(xù)電平狀態(tài)標(biāo)志、模式配置兩級(jí)/三級(jí)同步器源信號(hào)翻轉(zhuǎn)間隔要遠(yuǎn)大于目標(biāo)時(shí)鐘周期單bit慢時(shí)鐘脈沖中斷請(qǐng)求、觸發(fā)命令脈沖同步器電平翻轉(zhuǎn)沿檢測(cè)連續(xù)脈沖間隔必須能被目標(biāo)時(shí)鐘分辨單bit快時(shí)鐘密集脈沖高速位脈沖握手協(xié)議注意req/ack時(shí)序避免死鎖多bit數(shù)據(jù)流圖像、網(wǎng)絡(luò)數(shù)據(jù)異步FIFO格雷碼指針、滿空保守判斷多bit低頻配置寄存器配置握手協(xié)議數(shù)據(jù)穩(wěn)定后再拉req多bit受控?cái)?shù)據(jù)增益系數(shù)、慢變參數(shù)MUX同步使能信號(hào)必須同步單調(diào)連續(xù)多bitFIFO指針、計(jì)數(shù)器格雷碼跨域只能用于相鄰值單bit翻轉(zhuǎn)這張表基本覆蓋了95%的跨時(shí)鐘域場(chǎng)景剩下的“數(shù)據(jù)總線FIFO握手混合”場(chǎng)景其實(shí)也是組合拳打法數(shù)據(jù)放FIFO、控制信號(hào)握手。不要試圖用一個(gè)通用方案解決所有問題每種方案都有它的代價(jià)選型時(shí)把延遲、吞吐、面積、復(fù)雜度都列出來對(duì)比比從網(wǎng)上隨便抄一個(gè)同步器電路靠譜得多。5.2 設(shè)計(jì)規(guī)范上的三點(diǎn)硬性要求我現(xiàn)在審代碼時(shí)跨時(shí)鐘域相關(guān)會(huì)盯三件事一是所有跨域寄存器必須成組命名比如sync_前綴確保后續(xù)靜態(tài)檢查一眼能識(shí)別二是任何跨域路徑旁邊必須加上異步約束注釋否則后端工具無法自動(dòng)判斷三是涉及異步FIFO的設(shè)計(jì)必須附上讀寫指針的格雷碼轉(zhuǎn)換代碼獨(dú)立模塊禁止在主邏輯里手寫格雷碼轉(zhuǎn)換因?yàn)槭謱懞苋菀茁┑簟岸M(jìn)制到格雷碼再跨域再解碼回二進(jìn)制”的完整鏈條。我見過一個(gè)項(xiàng)目在主邏輯里直接對(duì)二進(jìn)制指針打拍結(jié)果上板后FIFO隔一段時(shí)間就丟一個(gè)數(shù)據(jù)查了三天最后發(fā)現(xiàn)指針比較邏輯里把同步后的格雷碼直接當(dāng)成二進(jìn)制用等于完全沒做轉(zhuǎn)換。還要補(bǔ)充一點(diǎn)跨時(shí)鐘域模塊的仿真用例必須在有GLS門級(jí)仿真階段回歸一遍。RTL仿真里同步器行為太理想門級(jí)仿真加入了真實(shí)的clk-to-q延遲和門延遲往往能暴露出跨時(shí)鐘域路徑上的布局延遲問題。雖然門級(jí)仿真跑得很慢但跨時(shí)鐘域相關(guān)測(cè)試向量一定要保留到GLS階段這個(gè)步驟不能省。這不是形式主義而是這些命名和模塊邊界能讓CDC工具、代碼審查和后續(xù)維護(hù)節(jié)省大量時(shí)間。我見過很多項(xiàng)目在原型驗(yàn)證階段僥幸通過一到量產(chǎn)測(cè)試就開始偶發(fā)fail最后追根溯源全是跨時(shí)鐘域細(xì)節(jié)沒遵守規(guī)范代價(jià)非常慘痛。如果團(tuán)隊(duì)里沒有專職的CDC專家那至少要讓每個(gè)寫跨時(shí)鐘域邏輯的設(shè)計(jì)師熟讀這份清單比事后排查高效得多。5.3 一個(gè)收尾的小建議跨時(shí)鐘域的方法本身并不復(fù)雜真正難得是每次動(dòng)手前先問自己三個(gè)問題這個(gè)信號(hào)是什么形態(tài)它在兩個(gè)時(shí)鐘域之間的頻率關(guān)系如何系統(tǒng)允許的最大延遲多大把這三個(gè)問題想清楚方案基本就有了。千萬不要先寫代碼再回頭“補(bǔ)”同步器那是最容易埋雷的路徑。我個(gè)人的習(xí)慣是在微架構(gòu)文檔里就先把所有跨時(shí)鐘域信號(hào)列成一張表寫清楚形態(tài)、頻率、方案、余量后面編碼和驗(yàn)證只是執(zhí)行。這樣設(shè)計(jì)評(píng)審時(shí)清楚驗(yàn)證人員也知道該往哪個(gè)方向打用例整個(gè)項(xiàng)目的返工率能降一大截。最后再分享一個(gè)小經(jīng)驗(yàn)每次調(diào)試跨時(shí)鐘域問題先把工具的所有CDC報(bào)錯(cuò)信息逐條過完再動(dòng)手九成以上問題在工具報(bào)告里就能看出線索比直接看波形大海撈針高效得多。