JOVANA
Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

時脈樹合成

到現在為止,你的單元已經擺在佈局上的真實位置上了,但它們都還在等同一樣東西:心跳。時脈必須在幾乎完全相同的一瞬間抵達數百萬個正反器——而單單一條線是做不到這件事的。這篇指南講的就是工具如何長出一棵活的緩衝器樹,把這一拍準時、同時地送到每一個角落,以及為什麼哪怕只是把它做偏了一點點,都會悄悄地從你辛辛苦苦平衡好的每一份時序預算裡偷走時間。

一個時脈,數百萬個正反器

想像一個體育場裡觀眾在做人浪。如果所有人都在完全相同的一瞬間站起來,你根本看不到什麼人浪——你看到的會是一個乾淨俐落、整齊劃一的動作。這種「瞬間處處同步」的爆發,正是晶片裡時脈應該做到的樣子:單單一拍,在同一時刻抵達每一個正反器,讓它們一起發射、一起擷取資料。一個現代的模組裡可以裝下數百萬個正反器,而在每一個時脈邊緣上,它們當中的每一個都需要這一拍。

比人浪更貼切的畫面是草坪灑水器。你希望水同時澆到每一株植物上——花圃角落裡的那株,不該比水龍頭旁邊那些晚整整一秒才被淋到。要是真晚了,整個花園就會長得參差不齊。時脈幹的是同一件活兒:它必須把自己的邊緣噴灑到茫茫一片正反器上,噴得足夠均勻,以至於對邏輯而言,它們全都是同時聽到這一拍的。

為什麼時脈不能只是一條線

最顯而易見的辦法恰恰是錯的:從時脈源拉出一條粗線,然後把每個正反器都從這條線上掛出去。它會失敗,原因有兩個,而且兩個都是純粹的物理。第一是扇出。一個時脈接腳要去驅動數百萬個正反器輸入,就像一個人想同時推一千個鞦韆——這個源頭根本提供不出足夠的電流,去把那麼多電晶體閘極乾脆俐落地翻轉過來。那條本該像懸崖一樣陡峭的邊緣,會變成一段懶洋洋、軟塌塌的斜坡,而緩慢的邊緣會讓正反器變得不可靠。

第二個原因更陰險,那就是RC 延遲。每條導線都有電阻(R)和電容(C),讓訊號沿著一條導線傳過去,與其說像啪地一下打開電燈開關,不如說更像讓水沖過一條又長又細的軟管——遠端的反應明顯比近端晚。所以,就算一條線*真能*驅動一切,緊挨著時脈源的那個正反器,也會比模組對角另一頭的那個正反器早得多地聽到這一拍。這單單一條線送出的並不是一拍同步的節奏;它把這一拍在整個晶片上抹開、糊掉了。這種「糊開」是有名字的,而它正是整篇指南要對付的敵人。

# A wire's delay grows roughly with the SQUARE of its length:
#   t_delay  ~  R_per_um * C_per_um * length^2
#
# Double a clock wire's length and you ~quadruple its delay.
# That is why a single source wire smears the clock edge across
# the die instead of delivering it everywhere at once.
埃爾莫爾(Elmore)延遲的直覺:沒有緩衝的長線,代價漲得飛快。線長之所以比你想的更要命,是因為你要充電的電阻和電容都隨線長一起增長。

歪斜與插入延遲

有兩個數描述了一個真實的時脈是怎麼到達的,這兩個你都得知道。第一個是插入延遲(也叫時脈延遲,clock latency):這一拍從時脈源一路走到某個正反器的時脈接腳,要花多長時間。如果源在時刻零產生一個邊緣,而某個特定正反器在 320 皮秒之後才看到它,那麼這個正反器的插入延遲就是 320 ps。有一部分延遲是躲不掉的——訊號總得在實體上走到那兒——而它本身並不有害,因為發射正反器和擷取正反器搭的是同一班「被延遲了的時脈」。

那個*確實*有害的數,是歪斜(skew):所有端點之間到達時間的離散程度。正式地寫出來是:

# Skew = how UNEVEN the clock arrival is across all endpoints
skew = t_arrival_max - t_arrival_min

# Insertion delay (latency) = source -> one flop's clock pin
#   e.g. flop A hears the edge at 300 ps  (latency_A = 300 ps)
#        flop B hears the edge at 345 ps  (latency_B = 345 ps)
#   skew between A and B = 345 - 300 = 45 ps
插入延遲說的是這一拍到得有多晚;歪斜說的是這份「晚」在各個正反器之間差了多少。CTS 對付的是歪斜,而不是插入延遲。

接下來是從業者真正在意的那一點,它跟時序預算直接掛鉤。回想一下前端軌道裡講過的建立時間約束:時脈週期必須容得下 `t_clk-to-q + t_logic + t_setup`,再用時脈歪斜去調整。當發射正反器和擷取正反器在略有差異的時刻聽到邊緣時,這點不一致會直接落進裕量的等式裡。讓擷取時脈到得*更晚*的那種歪斜,會給一條建立時間路徑塞進一點額外的時間——但它是從下一級那裡來的,於是反過來咬你的保持時間檢查。失控的歪斜就是不確定性,而不確定性就是從每一份預算裡被扣掉的皮秒。這正是為什麼 CTS 幾乎把追求低而均衡的歪斜擺在所有事情之上。

緩衝器與 H 樹

如果一條線送不出這一拍,那你就搭一張分發網路——而其中的竅門,是讓從源到每一個正反器的每一條路徑都花掉一樣多的時間。教科書上的理想是 H 樹。想像字母 H。時脈從那道橫樑的正中央進來;橫樑分岔到兩個端點;在每個端點上你再畫一個更小的、轉了向的 H;每一個這樣的 H 又再分岔成更小的 H。因為這套幾何是對稱的,從中心到這個碎形裡每一片葉子的線長都完全相同——於是到每一片葉子的延遲都完全相同,歪斜便朝著零塌縮過去。這就是那台被設計成讓角落裡的植物和水龍頭旁的植物在同一瞬間都得到水的灑水器。

對稱解決的是距離,但它解決不了驅動能力——這就輪到時脈緩衝器登場了。在每一個分岔點上,工具都會插入一個緩衝器:一個小小的放大器,把那條正在變弱的邊緣接過來,重新「蓋章」成一條嶄新、銳利的邊緣,再去驅動下一組分支。把它想成一場接力賽,而不是一個跑得精疲力竭的選手從頭跑到尾——每個緩衝器都是一名接過接力棒的、體力充沛的新選手。這些緩衝器還會重新平衡延遲:如果某條分支天生快了一點點,工具可以把它的線拉長,或者加一個緩衝器去故意把它放慢,把每一片葉子都拽回到彼此一致。一棵做完的時脈樹,就是從樹根到葉子層層散開的好幾這樣的緩衝器。

# A clock-tree spec the CTS engine works to honor (vendor-neutral):
create_clock -name CLK -period 1.0 [get_ports clk]   ;# 1.0 ns = 1 GHz beat

set_clock_uncertainty 0.05 [get_clocks CLK]          ;# 50 ps budget reserved for skew+jitter
set_clock_transition  0.08 [get_clocks CLK]          ;# keep clock edges sharp (<= 80 ps)

# CTS targets, conceptually:
#   max_skew      <= 30 ps
#   max_latency   <= 350 ps   (insertion delay budget)
#   max_tree_depth: a handful of buffer levels root -> leaf
你用 create_clock 宣告這一拍;你用 clock uncertainty(時脈不確定度)從週期裡預留出一小塊給歪斜和抖動;接著 CTS 長出緩衝器樹,去命中你設定的歪斜、延遲和轉換(transition)目標。

為什麼 CTS 在佈局之後才跑

這裡有個值得停下來想一想的問題:為什麼時脈樹合成是第步,排在佈局之後、繞線之前?為什麼不先把時脈建好呢?因為你沒法去平衡那些你根本量不出來的延遲,而在你知道正反器到底在哪兒之前,你又量不出延遲。歪斜是幾何的屬性——是距離和線長——所以工具得先有佈局上真實的單元位置,才能決定緩衝器放在哪裡、每條分支的線該畫多長。想在佈局之前就把時脈樹搭起來,就好比花園還沒種下去,你就想規劃好灑水管要怎麼鋪。

  1. 先做佈局規劃:把晶粒、巨集單元、I/O 和電源網格定下來——這是後面整條流程賴以存在的、固定的地貌。
  2. 把每一個標準單元,連同所有正反器,都擺放到合法的位置上。現在工具就確切地知道每一個時脈端點坐落在哪兒了。
  3. CTS:把鄰近的正反器聚成簇,長出那棵平衡的緩衝器樹,並插入時脈緩衝器去命中歪斜和延遲目標——用的正是佈局剛剛敲定的真實距離。
  4. 然後繞著這張此刻已固定下來的時脈網路去繞線訊號線。完事之後要重新檢查時序,因為真正繞出來的線帶著真實的 RC,那是紙面估算之前只能猜個大概的東西。

這個先後次序之所以要緊,還有一個更深的原因:建起時脈樹會改變整個時序的地貌。在 CTS 之前,時序工具假定的是一個*理想*時脈——零歪斜,處處同時到達——好讓它們能專心把邏輯擺好。而真實的樹一旦存在,每個正反器真正的時脈到達時刻就被鎖定了,工具於是切換到傳播(propagated)時脈模式:它在計算裕量時,現在用的是真實的插入延遲和歪斜。先佈局,好讓那棵樹是誠實的;建起那棵樹,好讓時序變得誠實;然後再繞線,並對著這份誠實的時序去做簽核。

瞥一眼有用歪斜

整篇指南我們都把歪斜當成敵人——而百分之九十五的時候它確實是。但這裡有個把劇本翻過來的高階技巧:有用歪斜(useful skew)(也叫有意歪斜,或時脈歪斜調度)。它的想法是,與其逼著每個正反器都在完全相同的一瞬間聽到這一拍,不如*故意*把時脈稍微晚一點點送到某些擷取正反器去——好給它們待接收的資料多騰出幾皮秒的到達時間。

把它想成挪動一個截止期限,而不是把活兒幹得更快。假設有一條路徑,它的建立時間檢查差了 20 ps——它就是沒法及時把資料送到擷取正反器。工具不必去重新設計邏輯,而可以把*那個正反器的*時脈邊緣延後,比方說 25 ps。現在資料有截到那個更晚的邊緣為止的時間可以慢慢到,於是這條路徑就通過了。這裡有個坑——而且永遠都有個坑——就是同一個正反器又是下一級的*發射*正反器,所以延後它的時脈,是靠從下一條路徑那裡偷時間,來給這條路徑借時間(同時它會收緊下一級的保持時間裕量)。有用歪斜就是跨著時脈去借時間,而工具會把整條鏈平衡好,讓這些借來借去最終能軋平。

把鏡頭拉遠,CTS 就是一句話:把這一拍在每個角落同時送到,然後只在划算的地方才有意去掰彎這條規矩。 把樹平衡好,你那數百萬個正反器就會步調一致地齊步前進;做砸了,你就悄無聲息地給晶片上每一份時序預算都課了稅。如今時脈已經分發到位、單元也已經擺好,這個設計終於可以迎接導線了——那就是接下來的繞線