會說謊的節拍器
想像一支由十億位樂手組成的管弦樂團。指揮舉起指揮棒,在落拍那一刻,每位樂手都應該同時奏響。在同步晶片裡,時脈就是那根指揮棒,正反器則是樂手。在第三階我們計算餘裕時,假設發射正反器與捕捉正反器在完全相同的那一皮秒感受到落拍。這個假設是個方便的謊言。
落拍不會瞬間傳送。它以一個邊緣離開時脈接腳,一條接一條地對導線充放電,並穿過一長串緩衝器,才抵達任一個正反器。藏在 20 平方毫米晶粒角落的正反器,可能比靠近時脈源的正反器晚 80–150 ps 才看到上升邊緣。*同一個*時脈邊緣抵達兩個不同正反器的時間差,就是時脈偏斜。
clk pin ──▶[buf]──▶[buf]──▶[buf]──┬──▶ FF_A (launch) edge @ t = 110 ps
│
└──▶[buf]──▶ FF_B (capture) edge @ t = 165 ps
skew(A→B) = T_capture_clk − T_launch_clk = 165 − 110 = +55 ps
(capture clock arrives LATER than launch clock → positive skew)正偏斜對建立有利、對保持不利
這裡有個美妙的不對稱性,讓整個主題值得一篇專文。當捕捉時脈比發射時脈*晚*到——正偏斜——資料便獲得額外的時間在被取樣前抵達。正偏斜實際上把截止期限往後推。這對建立(setup)檢查是純粹的禮物。
SETUP (must arrive BEFORE the next capture edge):
slack_setup = T_clk + skew − T_cq − T_logic − T_setup
^^^^
positive skew ADDS to the budget ✓ easier
HOLD (must NOT change too soon after the SAME capture edge):
slack_hold = T_cq + T_logic − T_hold − skew
^^^^
positive skew SUBTRACTS from the budget ✗ harder為什麼保持往反方向擺?保持問的是不同的問題。它不關乎*下一個*邊緣,而是關乎*同一個*邊緣。在邊緣 N 發射的新資料,不可以衝過邏輯、破壞捕捉正反器正試圖在同一個邊緣 N 抓取的值。如果捕捉時脈遲到(正偏斜),捕捉正反器的窗口便向未來*更久地*敞開——剛發射的資料就有更多時間溜進去把它弄壞。所以救了建立的那件事,正是毀了保持的那件事。
時脈樹合成:打造指揮棒
如果偏斜是保持的敵人、又是建立靠不住的朋友,直覺的反應便是:讓偏斜處處為零。把邊緣在同一瞬間送達全部一百萬個正反器。嘗試做到這件事的步驟,就是時脈樹合成(clock tree synthesis),簡稱 CTS,在實體實作流程中緊接著佈局之後執行。
你無法用一個緩衝器驅動一百萬個正反器——負載電容會把斜率壓垮,邊緣會以糊成一團的斜坡抵達。因此 CTS 長出一棵*樹*:時脈根節點分支到幾個緩衝器,每個再分到更多,一路向下分支或許 10 到 18 層,直到葉節點正是正反器的時脈接腳。其工藝在於讓每一條從根到葉的路徑花費*相同*的延遲,使所有葉節點一起看到邊緣。
┌─[buf]─┬─▶ FF
┌─[buf]──┤ └─▶ FF
│ └─[buf]─┬─▶ FF
clk root ─[buf] └─▶ FF
│ ┌─[buf]─┬─▶ FF
└─[buf]──┤ └─▶ FF
└─[buf]─┴─▶ FF
Goal: every root→leaf path = equal delay → skew ≈ 0
Knobs: balanced fanout, matched wire length, buffer sizing,
shielding, sometimes an H-tree or clock mesh for the spine- 依地理位置將正反器分群,讓鄰近的葉節點共用一條分支。
- 建構樹狀結構,插入並調整時脈緩衝器尺寸以平衡路徑延遲。
- 平衡——微調繞線迂迴與緩衝器強度,使所有葉節點落在嚴格的偏斜目標內。
- 為功耗與訊號完整性最佳化:時脈每個週期都翻轉,時脈樹往往佔總動態功耗的 30–40%;要為它遮蔽以防串擾,並留意其斜率。
時脈不確定性:你預留的餘裕
即使做完一次漂亮的 CTS,你也無法保證工具裡量到的偏斜正是矽晶實際交付的值。緩衝器會隨製程、電壓與溫度而變動。時脈源本身會晃動。串擾會推擠邊緣。因此 STA 拒絕把整個預算押在一個標稱值上——它撥出一塊刻意的緩衝墊,稱為時脈不確定性(clock uncertainty)。
set_clock_uncertainty -setup 0.12 [get_clocks clk] # ps reserved for setup set_clock_uncertainty -hold 0.04 [get_clocks clk] # ps reserved for hold # what it folds in: # • clock JITTER from the PLL / source (cycle-to-cycle wander) # • estimated SKEW before the tree is built (pre-CTS guess) # • a safety pad for OCV / crosstalk / margin # effect on the check: # slack_setup = (T_clk − uncertainty_setup) + skew − T_cq − T_logic − T_setup
注意建立與保持拿到的是*不同*的不確定性值,這並非偶然。建立的不確定性把抖動(只在整個時脈週期上才有影響)連同餘裕一併打包;保持的不確定性通常小得多,因為保持檢查發生在單一邊緣之內,週期抖動大致互相抵消。在流程早期、樹尚未存在時,不確定性還夾帶著對樹最終偏斜的一個*猜測*——而一旦 CTS 給了你一棵真實的傳播樹,你便縮減不確定性,只留下抖動與真正的餘裕。
有用偏斜:化臭蟲為工具
現在來談那個把工具操作員與工程師區分開來的轉折。整篇我們都在奮力把偏斜弄成*零*。但記得那個不對稱性:正偏斜*幫助*建立。如果有一條頑固的路徑在建立上差了 30 ps,而它所饋入的下一條路徑卻有 200 ps 的餘裕可揮霍呢?與其把樹弄平,你可以刻意延後那個共用正反器的時脈——把更多時間交給失敗的路徑,由那個寬裕鄰居的盈餘來支付。這種刻意的、外科手術般的偏斜,就是有用偏斜(useful skew)。
Before useful skew (zero-skew tree):
FFa ──[ tight logic ]──▶ FFb ──[ loose logic ]──▶ FFc
setup slack: setup slack:
−30 ps ✗ +200 ps ✓✓
Apply +40 ps of useful skew to FFb's clock (delay it):
• path FFa→FFb : capture clock (FFb) now LATER → setup slack −30 +40 = +10 ps ✓
• path FFb→FFc : launch clock (FFb) now LATER → setup slack +200 −40 = +160 ps ✓
• borrow 40 ps from the loose stage to rescue the tight one — net win現代時序工具會把這件事自動納入 CTS。最佳化器把每個正反器的插入延遲當成一個*變數*,而非固定目標,並求解出一組微小偏斜,使整個設計中最差的負餘裕最大化——這是一個橫跨整棵時脈樹的有用偏斜編列問題。做得好,它能為你買到數十皮秒,並在完全不動邏輯的情況下削掉一整個時序角點。
綜合起來:一幅收尾的圖像
退一步看,時脈網路講述了一個連貫的故事。時脈不是理想的指揮棒,而是一棵帶有延遲與失配的實體樹。偏斜就是那份失配——它施惠於建立、索取於保持。CTS 建構並平衡這棵樹,使偏斜維持微小、斜率維持鋭利。時脈不確定性是我們為無法預測的晃動誠實預留的餘裕。而有用偏斜,是我們不再把偏斜當成純粹的誤差、開始刻意動用它的那一刻,把餘裕移到最需要的地方。
下次你讀時序報告,看到 `clock network delay (propagated)` 與每條路徑的 `clock skew` 欄位時,你會確切知道它們的意思,以及每一個各往哪個方向撥動你的餘裕。在第五階,我們將徹底離開標稱的世界:真實晶片不會只跑在單一電壓、單一溫度或單一製程——我們將遇見晶片內變異,以及決定這顆零件能否真正出貨的多角點、多模式簽核。