位信號(hào)的CDC處理:同步釋放原則與復(fù)位樹架構(gòu)解析)
異步復(fù)位信號(hào)在跨時(shí)鐘域CDC中的處理原則做了十幾年數(shù)字IC和FPGA設(shè)計(jì)我最早明白異步復(fù)位有風(fēng)險(xiǎn)是在一個(gè)多時(shí)鐘域項(xiàng)目里翻車之后。仿真全綠上板之后偶爾抓拍數(shù)據(jù)錯(cuò)幾個(gè)bit查了半天才發(fā)現(xiàn)是復(fù)位釋放瞬間和時(shí)鐘上升沿撞在了一起某一片寄存器的輸出端直接出現(xiàn)了在0和1之間抖動(dòng)的電平。當(dāng)時(shí)第一反應(yīng)是電源噪聲后來用示波器加邏輯分析儀定位最終確定是異步復(fù)位信號(hào)的釋放沿沒有和目的時(shí)鐘對(duì)齊。這類問題在CDC跨時(shí)鐘域場景里特別隱蔽因?yàn)閺?fù)位信號(hào)的扇出面極大一個(gè)點(diǎn)出問題整條數(shù)據(jù)鏈路的寄存器都可能被污染。這篇文章就圍繞異步復(fù)位信號(hào)在CDC中的處理原則展開把標(biāo)準(zhǔn)做法、架構(gòu)選型、驗(yàn)證手段和實(shí)際踩坑都梳理一遍希望對(duì)正在做多時(shí)鐘域設(shè)計(jì)的同行有幫助。1. 異步復(fù)位為什么是CDC里的“隱形殺手”1.1 從一次X態(tài)故障說起那次故障讓我對(duì)“復(fù)位”這兩個(gè)字有了新的認(rèn)識(shí)。項(xiàng)目里的系統(tǒng)有四個(gè)時(shí)鐘域復(fù)位源是片外的上電復(fù)位信號(hào)直接連到了各個(gè)時(shí)鐘域的觸發(fā)器異步復(fù)位端。板子運(yùn)行起來偶發(fā)性地出現(xiàn)寄存器輸出為X態(tài)隨后數(shù)據(jù)鏈路錯(cuò)誤。最初懷疑跨時(shí)鐘域的數(shù)據(jù)同步有漏洞把SpyGlass CDC的report翻了一遍數(shù)據(jù)路徑的檢查都是干凈的。后來定位到出錯(cuò)的寄存器發(fā)現(xiàn)它們都有一個(gè)共同點(diǎn)復(fù)位釋放沿和各自的時(shí)鐘上升沿距離太近違反了庫單元的recovery時(shí)間。這類問題在仿真里很難抓因?yàn)榉抡婕?lì)里的復(fù)位信號(hào)通常離時(shí)鐘沿有固定的相位關(guān)系比如復(fù)位釋放都安排在時(shí)鐘沿之后幾納秒大家習(xí)慣性地認(rèn)為“這樣就安全了”??蓪?shí)際場景里外部復(fù)位信號(hào)和片內(nèi)時(shí)鐘的相位關(guān)系是任意的。復(fù)位信號(hào)本身異步于每個(gè)時(shí)鐘域它在任意時(shí)刻釋放都可能在某個(gè)時(shí)鐘域里撞擊到關(guān)鍵沿。當(dāng)復(fù)位釋放沿落在觸發(fā)器的建立/保持窗口內(nèi)觸發(fā)器輸出不是干凈的復(fù)位值也不是正常功能值而是亞穩(wěn)態(tài)或者不確定狀態(tài)。1.2 recovery/removal時(shí)間——兩個(gè)被低估的時(shí)序窗口很多人對(duì)setup/hold time很熟但對(duì)recovery/removal time就模糊了。其實(shí)這兩組參數(shù)是一一對(duì)應(yīng)的關(guān)系。setup/hold描述的是數(shù)據(jù)信號(hào)相對(duì)于時(shí)鐘沿的約束而recovery/removal描述的是異步控制信號(hào)比如異步復(fù)位、異步置位相對(duì)于時(shí)鐘沿的約束。recovery time恢復(fù)時(shí)間在時(shí)鐘有效沿到來之前異步復(fù)位信號(hào)必須已經(jīng)穩(wěn)定釋放的最短時(shí)間。如果復(fù)位釋放太晚時(shí)鐘沿到達(dá)時(shí)復(fù)位還沒完全釋放觸發(fā)器可能看不到正確的D端數(shù)據(jù)。removal time移除時(shí)間在時(shí)鐘有效沿之后異步復(fù)位信號(hào)必須繼續(xù)保持有效狀態(tài)的最短時(shí)間。如果復(fù)位釋放得太早復(fù)位脈沖的高電平寬度不足可能導(dǎo)致觸發(fā)器來不及可靠退出復(fù)位狀態(tài)。這兩者合起來構(gòu)成了一個(gè)對(duì)異步復(fù)位信號(hào)釋放沿的“禁忌窗口”。異步復(fù)位信號(hào)一旦被觸發(fā)它可以在任意時(shí)刻生效并快速把輸出拉回復(fù)位值這一點(diǎn)不受時(shí)鐘約束但釋放時(shí)刻如果落進(jìn)這個(gè)禁忌窗口觸發(fā)器的輸出狀態(tài)就無法預(yù)測。在實(shí)際電路里這個(gè)窗口通常是幾個(gè)百皮秒到幾個(gè)納秒看起來很小但只要釋放沿和時(shí)鐘沿的相位差恰好落進(jìn)去故障就是真實(shí)存在的。更麻煩的是復(fù)位信號(hào)通常接在成千上萬個(gè)觸發(fā)器上扇出路徑長短不一不同寄存器的釋放沿到達(dá)時(shí)間也不同只要有一個(gè)寄存器掉進(jìn)禁忌窗口整條鏈路就可能被污染。1.3 復(fù)位信號(hào)也要當(dāng)成CDC信號(hào)來對(duì)待很多工程師做CDC檢查時(shí)只關(guān)注數(shù)據(jù)路徑比如一個(gè)模塊的輸出直接送到另一個(gè)時(shí)鐘域中間有沒有同步器、有沒有握手協(xié)議。但復(fù)位信號(hào)本質(zhì)上也是一種跨時(shí)鐘域信號(hào)。復(fù)位源所在的時(shí)間域和目標(biāo)時(shí)鐘域之間沒有確定的相位關(guān)系它就符合CDC信號(hào)的定義。只是我們通常不把它叫“數(shù)據(jù)CDC”而叫“復(fù)位CDC”。這帶來一個(gè)思維轉(zhuǎn)變你不能因?yàn)閺?fù)位信號(hào)是“全局的”“異步的”就覺得它天然安全。恰恰相反正因?yàn)樗钱惒降牟疟仨氂脤iT的機(jī)制把它“馴服”。數(shù)據(jù)信號(hào)的CDC處理常用兩級(jí)同步器、異步FIFO、握手協(xié)議解決的問題是“數(shù)據(jù)內(nèi)容不能丟、不能錯(cuò)”復(fù)位信號(hào)的CDC處理解決的是“釋放沿必須對(duì)齊到目的時(shí)鐘且不能落入時(shí)序禁忌窗口”。兩者都是同步概念但手法不同不能混用。還有一種情況是需要特別小心的復(fù)位信號(hào)從另一個(gè)時(shí)鐘域產(chǎn)生比如軟件控制下的軟復(fù)位信號(hào)它本身在某個(gè)時(shí)鐘域里是同步信號(hào)但到了目標(biāo)時(shí)鐘域之后又變成了異步信號(hào)。這種信號(hào)不能直接當(dāng)作復(fù)位源使用應(yīng)該先按照CDC數(shù)據(jù)通道的方式把軟復(fù)位信號(hào)安全傳遞到目標(biāo)時(shí)鐘域再在目標(biāo)時(shí)鐘域內(nèi)做異步復(fù)位的同步釋放。換句話說復(fù)位信號(hào)的源頭到目標(biāo)寄存器之間每一個(gè)跨域邊界都要專門處理。2. 標(biāo)準(zhǔn)解法異步置位、同步釋放2.1 兩級(jí)寄存器的電路結(jié)構(gòu)與工作時(shí)序業(yè)界對(duì)異步復(fù)位信號(hào)的標(biāo)準(zhǔn)處理原則四個(gè)字就能概括異步置位、同步釋放。英文常寫作Asynchronous Assert, Synchronous Deassert。意思是復(fù)位信號(hào)有效的那個(gè)沿進(jìn)入復(fù)位狀態(tài)可以完全異步地發(fā)生不需要任何同步但復(fù)位信號(hào)釋放的那個(gè)沿退出復(fù)位狀態(tài)必須與目標(biāo)時(shí)鐘對(duì)齊。典型的實(shí)現(xiàn)是一個(gè)兩級(jí)復(fù)位同步器結(jié)構(gòu)不復(fù)雜第一級(jí)觸發(fā)器的D端接高電平針對(duì)低有效復(fù)位接1。第二級(jí)觸發(fā)器的D端接第一級(jí)的Q端。兩個(gè)觸發(fā)器的異步復(fù)位端都直接接原始異步復(fù)位信號(hào)。兩個(gè)觸發(fā)器使用同一個(gè)目標(biāo)時(shí)鐘域時(shí)鐘。第二級(jí)觸發(fā)器的Q端輸出就是同步釋放后的復(fù)位信號(hào)。時(shí)序上可以這樣理解原始復(fù)位信號(hào)拉低的那一刻兩級(jí)觸發(fā)器都立即進(jìn)入復(fù)位狀態(tài)輸出為0整個(gè)時(shí)鐘域被復(fù)位。原始復(fù)位信號(hào)釋放拉高后第一級(jí)觸發(fā)器要等到目標(biāo)時(shí)鐘的第一個(gè)有效沿到來因?yàn)樗腄端是1所以輸出變1第二級(jí)觸發(fā)器要再等一個(gè)時(shí)鐘周期才能看到第一級(jí)的1并輸出變1。這樣一來復(fù)位釋放沿就從“任意時(shí)刻”變成了“目標(biāo)時(shí)鐘沿加clk-to-q延時(shí)”的確定性事件下游所有觸發(fā)器的recovery/removal時(shí)序都有了保障。實(shí)際代碼大概是這個(gè)思路module reset_synchronizer ( input wire clk, input wire rst_n, // 原始異步復(fù)位低有效 output wire rst_sync_n ); reg rst_n_sync1; reg rst_n_sync2; always (posedge clk or negedge rst_n) begin if (!rst_n) begin rst_n_sync1 1b0; end else begin rst_n_sync1 1b1; end end always (posedge clk or negedge rst_n) begin if (!rst_n) begin rst_n_sync2 1b0; end else begin rst_n_sync2 rst_n_sync1; end end assign rst_sync_n rst_n_sync2; endmodule需要注意這個(gè)模塊輸出的是一根“內(nèi)部時(shí)鐘域的復(fù)位信號(hào)”它的有效沿拉低仍然是異步的釋放沿拉高已經(jīng)被同步到了clk。下游的目標(biāo)寄存器它們的異步復(fù)位端接到的就應(yīng)該是這根信號(hào)而不是原始復(fù)位信號(hào)。未同步的原始復(fù)位信號(hào)只能連接到各時(shí)鐘域自己的復(fù)位同步器輸入端不要再直接接到其他寄存器上。2.2 為什么兩級(jí)夠用什么情況下要上三級(jí)有不少人問為什么一定是兩級(jí)一級(jí)不行嗎一級(jí)同步器的問題在于原始異步復(fù)位信號(hào)釋放沿落到第一級(jí)觸發(fā)器的recovery/removal窗口時(shí)它輸出狀態(tài)可能進(jìn)入亞穩(wěn)態(tài)。如果這個(gè)亞穩(wěn)態(tài)信號(hào)直接作為整個(gè)時(shí)鐘域的復(fù)位使用亞穩(wěn)態(tài)可能傳播到所有寄存器。兩級(jí)結(jié)構(gòu)里第一級(jí)即使亞穩(wěn)態(tài)也有整整一個(gè)時(shí)鐘周期來收斂第二級(jí)看到的輸入通常已經(jīng)穩(wěn)定到0或1它自己的輸出就能可靠地對(duì)齊到時(shí)鐘沿。這是典型的MTBF平均無故障時(shí)間考量。兩級(jí)是絕大多數(shù)場景下的起步配置。如果復(fù)位信號(hào)需要驅(qū)動(dòng)的寄存器特別多、復(fù)位網(wǎng)絡(luò)特別長或者目標(biāo)時(shí)鐘頻率很高、時(shí)鐘抖動(dòng)較大有些團(tuán)隊(duì)會(huì)加一級(jí)變成三級(jí)同步器。第三級(jí)的作用是額外提供一個(gè)時(shí)鐘周期的穩(wěn)定余量代價(jià)是多一個(gè)時(shí)鐘周期的復(fù)位釋放延遲。我在高性能項(xiàng)目里見過三級(jí)但大多數(shù)SoC設(shè)計(jì)用兩級(jí)就夠了。需要注意的是增加級(jí)數(shù)并不會(huì)改善“扇出過大”的問題。同步器只是把釋放沿對(duì)齊到時(shí)鐘它不能替代復(fù)位樹設(shè)計(jì)。如果復(fù)位扇出成百上千個(gè)觸發(fā)器你必須考慮復(fù)位緩沖樹的平衡否則每個(gè)觸發(fā)器的釋放沿到達(dá)時(shí)間會(huì)有差異部分寄存器照樣可能落在禁忌窗口里。這個(gè)問題后面專門展開。2.3 低有效復(fù)位和高有效復(fù)位的統(tǒng)一處理標(biāo)準(zhǔn)單元庫里的異步復(fù)位端可能低有效也可能高有效。低有效的情況最常見代碼里通常叫rst_n同步器里的邏輯用上面那套寫法即可。如果復(fù)位端是高有效對(duì)應(yīng)rst同步器也能做對(duì)稱處理第一級(jí)D端接0。兩級(jí)觸發(fā)器的異步置位端接原始高有效復(fù)位信號(hào)。釋放時(shí)第一級(jí)在時(shí)鐘沿后變0第二級(jí)跟隨后變0。庫單元如果只提供低有效異步復(fù)位端而系統(tǒng)復(fù)位源是高有效可以在同步器輸出端加一個(gè)反相器或者把高有效復(fù)位信號(hào)反相后再進(jìn)同步器。原則是把“異步有效沿”和“同步釋放沿”對(duì)應(yīng)到正確的電平極性上不要讓信號(hào)經(jīng)過組合邏輯后再大范圍扇出。還有一點(diǎn)容易忽略同步器輸出的復(fù)位信號(hào)必須保持它作為“異步復(fù)位端驅(qū)動(dòng)”的屬性。也就是說下游寄存器看到的是一個(gè)電平型復(fù)位它的有效沿是即時(shí)的釋放沿是對(duì)齊過的。你不能因?yàn)檫@個(gè)信號(hào)邏輯上像“普通電平”就把它又當(dāng)成使能信號(hào)去接D端邏輯。這種誤用會(huì)導(dǎo)致復(fù)位行為在時(shí)序上出現(xiàn)不可控的延遲。3. 集中式還是分布式復(fù)位樹的架構(gòu)權(quán)衡3.1 集中式同步器適合什么場景復(fù)位同步器放哪里是一個(gè)架構(gòu)決策。最簡單的方式是全芯片只放一個(gè)復(fù)位同步器它的輸出通過全局復(fù)位樹分發(fā)到所有寄存器。這個(gè)方案的優(yōu)點(diǎn)是資源少、邏輯簡單只要一個(gè)同步器工作正確全局復(fù)位邏輯看上去就是統(tǒng)一的。但它有兩個(gè)很明顯的隱患。第一個(gè)是復(fù)位樹延遲。同步器輸出到不同位置寄存器的路徑長度差異很大如果復(fù)位樹沒有仔細(xì)平衡同一個(gè)釋放沿到達(dá)近端寄存器和遠(yuǎn)端寄存器的時(shí)刻可能差好幾個(gè)納秒。對(duì)于高速時(shí)鐘這個(gè)差異完全可能超過時(shí)鐘偏斜的容忍度導(dǎo)致一部分寄存器已經(jīng)退出復(fù)位另一部分還在復(fù)位態(tài)甚至有一小部分寄存器的釋放沿和本地時(shí)鐘沿卡在禁忌窗口里。第二個(gè)隱患是時(shí)鐘和復(fù)位的偏斜耦合。集中式同步器距離各個(gè)目標(biāo)寄存器遠(yuǎn)等效于把“復(fù)位偏斜”疊加到“時(shí)鐘偏斜”上時(shí)序收斂難度呈指數(shù)上升。所以集中式復(fù)位同步器只適合寄存器規(guī)模小、時(shí)鐘頻率低、復(fù)位樹延遲遠(yuǎn)小于時(shí)鐘周期的設(shè)計(jì)比如一些低速控制模塊。多時(shí)鐘域大型SoC上直接用一個(gè)全局同步器后段物理實(shí)現(xiàn)會(huì)很痛苦。3.2 分布式同步器每個(gè)時(shí)鐘域各放一個(gè)更穩(wěn)妥的做法是分布式復(fù)位同步器。每個(gè)時(shí)鐘域都放一個(gè)獨(dú)立的同步器原始異步復(fù)位信號(hào)同時(shí)接到所有同步器的異步復(fù)位端每個(gè)同步器的輸出只驅(qū)動(dòng)自己所在時(shí)鐘域內(nèi)的復(fù)位樹。這樣做的好處有三個(gè)層次。第一每個(gè)時(shí)鐘域的釋放沿都對(duì)齊到本域時(shí)鐘和別的時(shí)鐘域沒有相位關(guān)系天然避開了“多域釋放沿必須一致”的偽需求。第二同步器輸出到域內(nèi)寄存器的距離被壓縮得很短復(fù)位樹延遲可控時(shí)鐘和復(fù)位的偏斜可以并做一體收斂。第三某個(gè)域的復(fù)位邏輯出了問題影響范圍被限制在該域內(nèi)不會(huì)擴(kuò)散成全局事故。代價(jià)是原始異步復(fù)位信號(hào)需要廣播到每一個(gè)同步器。有人會(huì)擔(dān)心原始復(fù)位信號(hào)的到達(dá)時(shí)間不一致會(huì)不會(huì)造成各域復(fù)位釋放時(shí)間不同這個(gè)問題其實(shí)不用太糾結(jié)。因?yàn)槊總€(gè)同步器都做了異步置位、同步釋放原始復(fù)位信號(hào)到達(dá)時(shí)間的那點(diǎn)差異只會(huì)影響第一級(jí)同步器的“異步置位時(shí)刻”而釋放時(shí)刻永遠(yuǎn)對(duì)齊到各自時(shí)鐘。你能確定的只是所有域都會(huì)在一個(gè)相對(duì)晚的時(shí)間點(diǎn)之后完成釋放但每個(gè)域具體哪個(gè)周期釋放由各自時(shí)鐘決定。這在多數(shù)系統(tǒng)里是允許的。如果業(yè)務(wù)上要求多個(gè)時(shí)鐘域在同一個(gè)時(shí)刻一起退出復(fù)位那就要做多域復(fù)位釋放對(duì)齊電路屬于特殊需求不能用分布式同步器天然實(shí)現(xiàn)。3.3 “釋放沿對(duì)齊”背后的時(shí)鐘樹代價(jià)把復(fù)位同步器分布在各個(gè)時(shí)鐘域之后很多人忽略了另一件事復(fù)位釋放沿對(duì)齊到時(shí)鐘沿這個(gè)“對(duì)齊”隱含了時(shí)鐘樹和復(fù)位樹必須聯(lián)合作戰(zhàn)。說得直白一點(diǎn)同步器輸出到目標(biāo)寄存器的復(fù)位路徑和時(shí)鐘到目標(biāo)寄存器的時(shí)鐘路徑最終都在同一個(gè)觸發(fā)器的異步復(fù)位端匯合。復(fù)位釋放沿必須在時(shí)鐘沿的recovery/removal窗口之外這就要求復(fù)位樹和時(shí)鐘樹的偏差被壓縮到很小。后段實(shí)現(xiàn)里復(fù)位樹往往會(huì)被綜合工具當(dāng)成普通的high-fanout信號(hào)自動(dòng)插入很多buffer。如果沒有額外的約束這些buffer的位置和延遲是不受控的。我的建議是在做物理實(shí)現(xiàn)時(shí)把復(fù)位同步器的輸出節(jié)點(diǎn)設(shè)置成balance屬性讓工具把復(fù)位樹當(dāng)成高優(yōu)先級(jí)網(wǎng)絡(luò)處理并且讓復(fù)位樹和時(shí)鐘樹共用類似的布局密度約束。另外復(fù)位信號(hào)在布局階段如果和時(shí)鐘路徑繞了遠(yuǎn)路釋放沿的偏斜會(huì)很難收斂。時(shí)序分析時(shí)也要對(duì)復(fù)位釋放路徑做相應(yīng)的檢查。有些團(tuán)隊(duì)用SDC約束里create_generated_clock或者set_false_path來處理復(fù)位這是不嚴(yán)謹(jǐn)?shù)?。?fù)位釋放路徑不是false path它在recovery/removal分析里是真實(shí)存在的路徑。要做的是在這個(gè)路徑上設(shè)置max_delay約束復(fù)位樹從同步器輸出到目的寄存器的延遲上限幫助工具收斂。4. 多時(shí)鐘域與低功耗場景下的額外講究4.1 全局復(fù)位與局部復(fù)位的配合多時(shí)鐘域系統(tǒng)里除了上電時(shí)的全局復(fù)位往往還有各種局部復(fù)位比如某個(gè)子系統(tǒng)的軟復(fù)位、調(diào)試復(fù)位、低功耗喚醒復(fù)位。這些局部復(fù)位不能隨意“扔”到異步復(fù)位端上。我的處理習(xí)慣是先把全局復(fù)位和局部復(fù)位合并成一棵復(fù)位樹再把它接入該時(shí)鐘域的復(fù)位同步器。合并時(shí)要非常小心不要用組合邏輯把多個(gè)復(fù)位信號(hào)直接或起來就完事。復(fù)位信號(hào)和普通控制信號(hào)不同它的有效沿要求接近零延遲傳播組合邏輯引入的毛刺和延遲都可能讓部分觸發(fā)器誤復(fù)位。更安全的做法是用一個(gè)專門的復(fù)位控制器模塊把全局復(fù)位、軟復(fù)位請(qǐng)求、低功耗狀態(tài)機(jī)的退出復(fù)位等統(tǒng)一處理成干凈的同步復(fù)位請(qǐng)求信號(hào)然后再進(jìn)入復(fù)位同步器。軟復(fù)位請(qǐng)求跨時(shí)鐘域的部分要按標(biāo)準(zhǔn)CDC流程走。比如軟復(fù)位寄存器在CPU時(shí)鐘域目標(biāo)模塊在高速接口時(shí)鐘域你就需要做一次跨時(shí)鐘域的脈沖或電平同步防止請(qǐng)求信號(hào)在目標(biāo)域里被當(dāng)成毛刺。這樣做的成本不大但能省掉很多事后排查X態(tài)的精力。4.2 時(shí)鐘門控期間復(fù)位還能不能同步釋放低功耗設(shè)計(jì)里目標(biāo)時(shí)鐘域可能被門控關(guān)閉。此時(shí)如果原始復(fù)位信號(hào)釋放復(fù)位同步器沒有時(shí)鐘沿可以采樣第一級(jí)和第二級(jí)的輸出會(huì)保持復(fù)位狀態(tài)等時(shí)鐘重新開啟后第一個(gè)有效時(shí)鐘沿才開始釋放過程。這個(gè)行為其實(shí)是安全的但它帶來一個(gè)時(shí)序上的不確定性時(shí)鐘恢復(fù)的時(shí)刻和復(fù)位釋放之間可能存在一段“等待窗口”。在等待窗口內(nèi)域內(nèi)寄存器保持復(fù)位態(tài)域外看到的是不確定的中間狀態(tài)。很多人踩過的坑是時(shí)鐘門控打開后的第一個(gè)時(shí)鐘沿正好和復(fù)位釋放沿非常接近。雖然兩級(jí)同步器能吸收這個(gè)風(fēng)險(xiǎn)但物理實(shí)現(xiàn)和工具分析上它往往被當(dāng)成復(fù)雜的邊界條件。我建議在UPF低功耗流程里把時(shí)鐘開啟和復(fù)位釋放的順序約束起來比如要求時(shí)鐘穩(wěn)定運(yùn)行至少一個(gè)周期后復(fù)位同步器才允許開始釋放。這樣既符合時(shí)序收斂的直覺也能減少后段優(yōu)化時(shí)的麻煩。另外不要在復(fù)位釋放臨界點(diǎn)同時(shí)關(guān)斷時(shí)鐘。復(fù)位釋放本來已經(jīng)對(duì)齊到某個(gè)時(shí)鐘沿如果這個(gè)沿被門控吃掉釋放動(dòng)作被拖延到下一個(gè)不確定的沿下游模塊的行為就完全難以預(yù)測。所以時(shí)鐘門控單元的控制信號(hào)和復(fù)位同步器輸出之間我總是會(huì)加嚴(yán)格的時(shí)序約束寧可讓復(fù)位晚一點(diǎn)釋放也不讓時(shí)鐘在釋放窗口里抖。4.3 復(fù)位脈沖寬度太窄等于沒復(fù)位異步復(fù)位信號(hào)的有效寬度必須足夠?qū)掃@是設(shè)計(jì)中容易糊弄的地方。復(fù)位有效沿可以異步發(fā)生但是它必須持續(xù)足夠時(shí)間讓所有目標(biāo)觸發(fā)器都進(jìn)入確定的復(fù)位狀態(tài)。對(duì)于兩級(jí)復(fù)位同步器來說原始復(fù)位信號(hào)的有效寬度至少要保證兩級(jí)觸發(fā)器都完成異步置位并且在釋放前有穩(wěn)定的時(shí)間。更嚴(yán)格的經(jīng)驗(yàn)值是復(fù)位有效寬度至少覆蓋目標(biāo)時(shí)鐘域最慢時(shí)鐘的2到3個(gè)周期。如果復(fù)位控制器發(fā)出的復(fù)位脈沖太窄比如只有幾個(gè)納秒就可能出現(xiàn)這樣一種尷尬情況靠近復(fù)位源的同步器已經(jīng)復(fù)位遠(yuǎn)端寄存器還沒來得及收到有效的復(fù)位電平脈沖就消失了。結(jié)果整個(gè)復(fù)位操作形同虛設(shè)。為了避免這個(gè)問題復(fù)位控制器里可以加一個(gè)最小脈寬擴(kuò)展電路用計(jì)數(shù)器把復(fù)位有效時(shí)間延長到幾百甚至幾千個(gè)時(shí)鐘周期。反正復(fù)位期間邏輯不工作寧長勿短。同理對(duì)外部輸入的異步復(fù)位信號(hào)片內(nèi)最好用專門的復(fù)位輸入的毛刺濾波器先濾除窄毛刺再做復(fù)位同步。不要把外部復(fù)位直接接到同步器甚至直接接到寄存器外部輸入信號(hào)的邊沿質(zhì)量和脈寬你是無法保證的。5. 用工具和斷言把復(fù)位問題攔在流片前5.1 CDC工具查什么結(jié)構(gòu)檢查與恢復(fù)時(shí)間違例現(xiàn)在主流CDC工具比如Cadence SpyGlass CDC、Synopsys Questa CDC、Siemens Meridian CDC都對(duì)復(fù)位信號(hào)有專門的檢查。你不要只看數(shù)據(jù)路徑的CDC報(bào)告復(fù)位相關(guān)的檢查項(xiàng)要單獨(dú)過一遍。工具一般會(huì)做兩類檢查。第一類是結(jié)構(gòu)檢查確認(rèn)每個(gè)時(shí)鐘域的復(fù)位信號(hào)是否經(jīng)過了標(biāo)準(zhǔn)的復(fù)位同步器結(jié)構(gòu)。如果你把原始異步復(fù)位信號(hào)直接接到某個(gè)普通觸發(fā)器的異步復(fù)位端又沒有同步釋放工具會(huì)報(bào)出類似“async reset deassert unsynchronized”的violation。第二類是恢復(fù)時(shí)間檢查工具會(huì)分析復(fù)位釋放沿和各時(shí)鐘沿的相對(duì)相位評(píng)估是否違反recovery/removal時(shí)間。有個(gè)容易忽略的點(diǎn)CDC工具默認(rèn)的復(fù)位同步器識(shí)別規(guī)則可能要求你按照特定模板編寫代碼。如果你用了“兩個(gè)獨(dú)立always塊分別描述兩級(jí)觸發(fā)器”這種常見寫法工具大概率能識(shí)別如果你把兩級(jí)觸發(fā)器寫在一個(gè)always塊里或者把D端邏輯搞得很復(fù)雜工具可能就認(rèn)不出來最后要么誤報(bào)要么漏報(bào)。我的經(jīng)驗(yàn)是寫復(fù)位同步器模塊時(shí)保持極簡只做同步功能不要混雜其他邏輯。這樣工具識(shí)別率最高后續(xù)審查也最省事。5.2 仿真斷言怎么寫、X態(tài)怎么追仿真階段復(fù)位問題最容易偽裝成“偶發(fā)現(xiàn)象”。因?yàn)閺?fù)位釋放沿和時(shí)鐘沿的相位關(guān)系在普通行為仿真里可能永遠(yuǎn)撞不上除非你用隨機(jī)延遲或者后仿真的真實(shí)時(shí)序。我有兩個(gè)習(xí)慣。第一在頂層測試平臺(tái)里給復(fù)位釋放加隨機(jī)抖動(dòng)。每次測試用例開始前用系統(tǒng)函數(shù)把復(fù)位釋放時(shí)刻在一定范圍內(nèi)隨機(jī)化多跑上百個(gè)種子能有效暴露復(fù)位釋放和時(shí)鐘沿競爭的問題。第二在復(fù)位相關(guān)信號(hào)上做斷言檢查??梢栽趶?fù)位同步器輸出端加一條SVA斷言要求復(fù)位釋放沿和時(shí)鐘上升沿之間的間隔不小于recovery time。如果后端時(shí)序仿真里跑出這條斷言失敗幾乎可以直接定位到復(fù)位路徑的物理實(shí)現(xiàn)問題。追查X態(tài)時(shí)也有技巧。當(dāng)仿真出現(xiàn)X態(tài)不要只盯著數(shù)據(jù)路徑找先檢查復(fù)位信號(hào)的波形??纯磸?fù)位釋放沿的位置和所有相關(guān)時(shí)鐘沿的位置把它們放在同一個(gè)時(shí)間坐標(biāo)下對(duì)比。如果復(fù)位釋放沿距離某個(gè)時(shí)鐘沿非常近而X態(tài)恰好出現(xiàn)在那一拍附近八成就是復(fù)位時(shí)序問題。再結(jié)合CDC工具報(bào)告基本能確認(rèn)根因。5.3 收斂流程從回歸到signoff把復(fù)位CDC問題納入signoff流程是我個(gè)人覺得最重要的一步。很多團(tuán)隊(duì)的CDC signoff checklist里只寫了數(shù)據(jù)同步器檢查復(fù)位檢查是附帶的甚至有人根本沒意識(shí)到要查。實(shí)際上復(fù)位網(wǎng)絡(luò)的高扇出特性決定了它比普通數(shù)據(jù)路徑更值得花時(shí)間做形式化檢查。我的收斂流程大致是這樣RTL階段先用SpyGlass跑一遍復(fù)位CDC檢查把所有異步復(fù)位釋放未同步的violation清零然后綜合后拿網(wǎng)表再跑一次重點(diǎn)看recovery/removal違例最后后端布局完成后用STA和CDC工具交叉驗(yàn)證復(fù)位樹的延遲和釋放沿對(duì)齊情況。任何一步有違例都要回到RTL或約束層面解決不允許帶著未關(guān)閉的復(fù)位CDC違例進(jìn)signoff。這里尤其要提醒不要在復(fù)位釋放路徑上盲目設(shè)set_false_path來“消除”違例。你是把這個(gè)約束加上了報(bào)告干凈了但芯片里的物理時(shí)序它不認(rèn)約束它只認(rèn)實(shí)際的邊沿關(guān)系。很多芯片流片后偶發(fā)復(fù)位問題回頭看代碼往往就是一根set_false_path把復(fù)位路徑的檢查給屏蔽了。這個(gè)教訓(xùn)我在多個(gè)項(xiàng)目里反復(fù)遇到真的不值得再踩。6. 幾個(gè)容易翻車的邊緣場景6.1 復(fù)位信號(hào)被組合邏輯“加工”后接異步端有人會(huì)把復(fù)位同步器輸出和某個(gè)控制信號(hào)做邏輯與比如“在上電初始化完成之前模塊保持復(fù)位”然后把這個(gè)組合信號(hào)接到寄存器的異步復(fù)位端。這種做法的風(fēng)險(xiǎn)在于組合邏輯的延遲和毛刺會(huì)破壞復(fù)位釋放沿的對(duì)齊甚至可能產(chǎn)生一個(gè)非常窄的“復(fù)位毛刺”導(dǎo)致某個(gè)寄存器在正常運(yùn)行中突然被異步復(fù)位一拍。異步復(fù)位端對(duì)毛刺極其敏感你必須保證驅(qū)動(dòng)它的信號(hào)是干凈的電平信號(hào)而不是組合邏輯瞬態(tài)的結(jié)果。如果確實(shí)需要根據(jù)某個(gè)條件延長復(fù)位應(yīng)該把這個(gè)條件也放進(jìn)復(fù)位控制器由控制器重新生成一個(gè)干凈的復(fù)位請(qǐng)求再走一遍同步器。所有寄存器只允許看到同步器輸出或者復(fù)位樹上的緩沖信號(hào)中間不能再有任何組合邏輯。6.2 同步器輸出又被當(dāng)數(shù)據(jù)用復(fù)位同步器的輸出是一根經(jīng)過同步的復(fù)位信號(hào)它本身也連接到很多寄存器的異步復(fù)位端。但有些工程師會(huì)順便把它當(dāng)作一個(gè)普通狀態(tài)信號(hào)比如“復(fù)位釋放完成標(biāo)志”送給另一個(gè)時(shí)鐘域的邏輯或者軟件。這個(gè)用法的問題在于它的釋放沿雖然和本時(shí)鐘域?qū)R了但到了另一個(gè)時(shí)鐘域它又成了異步信號(hào)直接使用依然存在CDC風(fēng)險(xiǎn)。如果軟件或者其他硬件需要知道“復(fù)位已經(jīng)釋放”正確的做法是用一個(gè)獨(dú)立的跨時(shí)鐘域握手信號(hào)把釋放狀態(tài)安全地傳遞過去。更隱蔽的變體是有人把復(fù)位同步器輸出的釋放沿當(dāng)作一個(gè)事件用來觸發(fā)某些寄存器的初始化賦值。這樣做會(huì)把復(fù)位釋放對(duì)齊的時(shí)序和功能邏輯的時(shí)序攪在一起任何時(shí)序微小的偏差都會(huì)變成功能錯(cuò)誤。復(fù)位釋放是全局行為功能事件的觸發(fā)要用功能信號(hào)不要復(fù)用復(fù)位路徑。6.3 復(fù)位源本身帶毛刺或來自另一個(gè)時(shí)鐘域最后一個(gè)常見翻車點(diǎn)是復(fù)位源本身不干凈。外部引腳進(jìn)來的復(fù)位信號(hào)先經(jīng)過輸入緩沖如果不加濾波外部環(huán)境的抖動(dòng)可能產(chǎn)生幾個(gè)窄毛刺。這些毛刺被當(dāng)成異步復(fù)位有效沿就會(huì)導(dǎo)致寄存器復(fù)位狀態(tài)被隨機(jī)修改。處理辦法是在復(fù)位輸入路徑上放置專門的毛刺濾波器或者用低頻采樣邏輯把外部復(fù)位先采幾拍確認(rèn)其穩(wěn)定有效后再往內(nèi)部復(fù)位樹送。對(duì)于來自另一個(gè)時(shí)鐘域的復(fù)位源也一定要先做跨時(shí)鐘域數(shù)據(jù)同步再進(jìn)入復(fù)位同步器不能想當(dāng)然地認(rèn)為異步復(fù)位端能“容忍”一切異步輸入。掃描測試模式下也要額外注意。掃描使能期間異步復(fù)位信號(hào)如果仍然有效會(huì)導(dǎo)致掃描移位數(shù)據(jù)被破壞或者產(chǎn)生不可預(yù)測的行為。多數(shù)設(shè)計(jì)里會(huì)用測試復(fù)位信號(hào)在調(diào)試模式下接管異步復(fù)位或者通過測試控制邏輯屏蔽功能復(fù)位。這一點(diǎn)在后端DFT階段通常會(huì)被查出來但如果你的RTL里沒有預(yù)留測試復(fù)位接口后期改起來會(huì)很痛苦。我自己的習(xí)慣是在每個(gè)項(xiàng)目開始時(shí)就把復(fù)位CDC檢查寫進(jìn)RTL評(píng)審的必查清單里并且在代碼規(guī)范中強(qiáng)制所有異步復(fù)位必須通過復(fù)位同步器模塊接入。一開始大家覺得多此一舉后來遇到幾個(gè)因?yàn)閺?fù)位釋放沒對(duì)齊導(dǎo)致的偶發(fā)bug所有人都默認(rèn)了這條規(guī)矩。異步復(fù)位信號(hào)看起來簡單但在跨時(shí)鐘域場景里它往往是仿真最看不到、上板最折磨人的那類問題。先把原則定下來把電路結(jié)構(gòu)寫對(duì)再靠工具和斷言兜底整個(gè)系統(tǒng)才算真正穩(wěn)定。