IC 後端執行專家
2026年5月1日9 分鐘閱讀
Signoff 方法論

PrimeTime 寫出來的 Conditional WIDTH SDF 不對?平行 Constraint Arc 合併陷阱

當同一 pin 上有兩條 sdf_cond 不同的平行 min_pulse_width——例如 eFuse STROBE 在讀模式與燒寫模式下——PrimeTime 會把兩條 COND WIDTH 都寫成同一對 (min::max) 合併值。修法只有一個變數,但它必須在 link_design 之前 set;對所有依賴 restore_session 的人都是個大坑。

背景

01問題出處

TSMC 28nm SoC 上的 eFuse hard macro。Vendor lib 在 STROBE pin 上定義了兩條 min_pulse_width——讀模式約 142 ns,燒寫模式約 11000 ns——只能透過 sdf_cond 字串(check_read_start 與 check_pgm_start)區分。PrimeTime 完整 signoff 後寫出的 SDF 內,STROBE 上的兩條 COND WIDTH 都掛了同一對 (min::max):142.4570 :: 11000.0000。

乍看之下這個輸出沒什麼錯——數字確實出現過。但它是錯的:兩個值來自不同的 condition。PrimeTime 把讀模式的 pulse width 與燒寫模式的 pulse width 合併成一對 bounding (min::max),然後把同一對複製到該 pin 上每一條 COND WIDTH。

Gate-level 模擬讀進這份 SDF 後,STROBE 上每一個 WIDTH 檢查——不論電路當下處於讀或燒寫模式——都會被拿錯誤的上界去比對。輕則模擬期間出現假違例,重則真實違例被遮掉。無論哪種,這份 SDF 都已經不是 lib 的忠實反映。

02現象

Lib 裡兩條平行 min_pulse_width 對應 SDF 裡兩條 COND WIDTH,但兩條的數值在條件之間互相串了,沒有保持各自獨立。

PrimeTime 實際寫出
(WIDTH (COND check_read_start (posedge STROBE)) (142.4570::11000.0000));check_pgm_start 那一行也是同樣的 (142.4570::11000.0000)。讀模式與燒寫模式雙雙繼承了合併的 bounding pair。
Lib 真實描述
min_pulse_width with when : '!PD*!CSB*!PGENB*LOAD*!PS' 的 constraint_high 是 142.45701;when : '!PD*!CSB*!PGENB*!LOAD*PS' 的 constraint_high 是 11000.00002。兩條彼此互斥的 condition,各自綁定一組功能態。
正確的 SDF 應該是
每一條 COND 行只承載自己的值:check_read_start 應該是 (142.457::142.457),check_pgm_start 應該是 (11000.000::11000.000)。pair 的 min/max 兩側是該條件的 corner 範圍,永遠不該跨條件混用。
為什麼這很重要
Gate-level 模擬器是按 SDF 字面意義跑的。COND 行上一個合併的 (min::max) 不是 corner pair——是憑空捏造。WIDTH 違例要嘛在燒寫模擬讀到讀模式那一行時錯誤觸發,要嘛因為上界太鬆而被遮蓋。
Liberty

03Liberty 真正記錄的東西

兩條互斥 when 的平行 min_pulse_width——是任何含模式 pin 的 IP 都會用到的標準寫法。

  • 模式 Pin 驅動條件

    PD、CSB、PGENB、LOAD、PS——eFuse 上五個模式 pin。每一條 min_pulse_width 的 when 字串都對應一個唯一的功能態。

  • sdf_cond 是輸出標籤

    每一條 min_pulse_width 帶一個 sdf_cond 字串,SDF writer 應原樣寫進 COND 子句。這是 SDF 唯一能用來辨識「這個值屬於哪個功能態」的握把。

  • 互斥是 Lib 規則

    Library Compiler 對於 when 不互斥的多條 min_pulse_width 會發警告。Lib 乾淨的話,任何真實矽片狀態下都只有一條 constraint 是 active。

  • constraint_high 是高脈衝最小寬度

    min_pulse_width () { constraint_high : N; } 設定高脈衝的最小寬度。這個案例兩條值差了約 80 倍——讀模式 142 ns vs 燒寫模式 11 us。

04根因:平行 Constraint Arc 在 link 階段被合併

PrimeTime 預設會把平行 constraint arc 以 bounding 形式儲存。同一個 endpoint 上的兩條 min_pulse_width 並不會以兩個獨立值留存到 link_design 之後——它們在 bundled arc 上塌成單一對 (min, max)。write_sdf 隨後從同一對合併值產出兩條 COND 行。

Bounding 合併是個優化
現代 PrimeTime 把平行 constraint arc 視作一個分析物件,存 bounding 值。對絕大多數 STA 任務,這樣更快、結果同樣保守——因為最壞 constraint 主導。
對 SDF 來說是有損的
兩個獨立值一旦變成單一 bounding pair,per-condition 資訊就丟了。COND 標籤還在 arc 上,但每個標籤現在指向同一對數字。
舊版 PrimeTime 不會這樣做
Synopsys 文件描述另一行為時用了「matches the default behavior of older PrimeTime releases」——這個合併是後加的優化,配套提供一個相容開關讓你關掉。
在 link 階段一次決定
是否合併是在 link_design 建 timing graph、決定平行 arc 怎麼存的時候一次定型的。link 之後資料結構就鎖死了。
PrimeTime 變數

05關鍵變數:timing_parallel_constraint_arcs_compatibility

整個行為由一個 application 變數控制。預設值 false。要拿到 per-condition 的 SDF,把它設成 true。

  1. 01
    預設是 false
    PrimeTime 預設 timing_parallel_constraint_arcs_compatibility = false。平行 constraint arc 在 link 階段被合併為 bounding pair——這就是 SDF 現象的源頭。
  2. 02
    set 為 true 即關閉合併
    set timing_parallel_constraint_arcs_compatibility true 告訴 PrimeTime 完整保留所有平行 constraint arc 數值。每個 sdf_cond 在 link、update_timing、write_sdf 全程保持自己的 constraint_high。
  3. 03
    必須在 link_design 之前 set
    Synopsys man page 寫得很清楚:「This variable must be set before the link_design command is run.」link_design 才是決定平行 arc 儲存方式的時刻。link 之後再 set 沒有任何作用。
  4. 04
    相容性提示
    變數命名與描述都暗示「不合併」是舊版預設。如果某個老腳本不設這個變數也能寫出正確 SDF,幾乎肯定當年跑在合併還沒預設啟用的舊版 PrimeTime 上。

06順序陷阱:restore_session 救不了

團隊在這個問題上最容易燒掉一個下午的方式,就是把變數設在錯誤的時機。PrimeTime session 存的是 link 之後的 timing graph,而不是 application 變數狀態;任何會影響 link 行為的變數都得在「原始建 session」的 shell 裡設,而非「restore session」的 shell。

restore_session 還原的是已 link 完的資料庫
save_session 凍結的是 post-link timing graph。restore_session 再把它讀回來。等你拿到 restored session 時,link_design 已經發生過了——用的是當時 session 建立時 timing_parallel_constraint_arcs_compatibility 的值。
restore 之後再 set 對 SDF 等於沒設
你 echo 它、printvar 它、再次 write_sdf——都不會重新觸發 bounding 決策。Arc 已經以合併形式儲存了。
Resave 也救不回來
把變數設好、把已合併的 graph save_session、之後 restore——這只是把錯誤狀態固化進新的 session 檔。修復必須發生在 link_design 之前。
DMSA / Multi-Scenario 每個 worker 都要設
分散式流程裡,每個 scenario worker 都會自己跑一次 link_design。變數必須在每個 worker 的啟動腳本裡、link 之前就在——可以放共用 setup script,或在 scenario 啟用前用 set_distributed_variables 派發。
跨工具行為

07PT vs Tempus:相關的 Conditional Pulse-Width 差異

同一個 eFuse 設置還會在 PrimeTime 報違例、Tempus 不報。是另一個問題,但結構同源:兩家對「未明確 case_analysis 時 conditional min_pulse_width 該怎麼處理」採用了不同預設。

在同一個 STROBE pin 上,PrimeTime 會用燒寫模式的 11000 ns 去比對 SoC 在功能讀模式下實際 ~114 ns 的 STROBE 脈衝,slack 報 -10886 ns。Tempus 在同樣的資料庫上不報任何東西。

PrimeTime 並不會去解 conditional min_pulse_width 的 when 表達式。它無法判斷 PD、CSB、PGENB、LOAD、PS 是否被約束在「check_pgm_start 不可達」的狀態。沒有對這些模式 pin 顯式 set_case_analysis,兩條 conditional 都會保持 active,而最壞那條主導違例。

Tempus 似乎對未解 conditional pulse-width 用了不同預設——更接近「條件不可達就不報」。兩種行為都不算錯,只是對同一個歧義輸入採用了不同預設。在 PrimeTime 裡的修法是用 set_case_analysis 鎖住模式 pin,讓燒寫模式 constraint 自動失效;或直接用 set_disable_timing 對應 timing arc 把它關掉。

08修復腳本

一份乾淨可重複的 PrimeTime 流程,產出 per-condition SDF 並避免模式相依的假違例。對任何用了 conditional 平行約束的 IP——eFuse、OTP、自訂類比 wrapper、含 mode-dependent min_pulse_width 或 min_period 的東西——都當清單用。

先設相容性變數
在所有 read 或 link 命令之前:set timing_parallel_constraint_arcs_compatibility true 與 set sdf_enable_cond_start_end true。後者確保 SDF writer 認 lib 提供的 sdf_cond_start / sdf_cond_end。
Read 與 Link 在同一個 session 內完成
Read library、read netlist、link_design 全在同一個 shell。除非你能確定那個 session 是在變數已為 true 的條件下建立的,否則不要從 saved session 起步。
套用模式 case_analysis
Functional scenario 上鎖模式 pin,每個 scenario 只有一條 conditional 為 active:set_case_analysis 0 PD/CSB/PS、set_case_analysis 1 LOAD/PGENB。用 report_case_analysis 驗證。
用 SDF 3.0 寫出
write_sdf -version 3.0 out.sdf。SDF 2.1 對 conditional WIDTH 構造支援有限——只要 sdf_cond 重要,就用 3.0。
在 write_sdf 之後存 session
需要可恢復檢查點時,最後再 save_session。後續 restore 出來的 session 會繼承正確儲存的 arc。同時在專案 README 註明:這個 session 是在相容性變數啟用下建立的。
驗證

09如何驗證輸出正確

三個檢查確認修復生效、SDF 忠實。

  • 1. 確認變數在 link_design 之前 active

    set 之後立刻 printvar timing_parallel_constraint_arcs_compatibility,link_design 之前再 print 一次。用 report_app_var -only_non_default 抽查整體 override 集合。

  • 2. 驗證 sdf_cond 在 lib 中保留下來

    Link 之後查詢:foreach_in_collection a [get_lib_timing_arcs -of [get_lib_pins '*/STROBE']] { echo "[get_attribute $a sdf_cond] [get_attribute $a when]" }。sdf_cond 為空表示 .db 編譯時沒保留字串——要從原始 .lib 重編。

  • 3. 對 SDF Per-Condition Diff

    Write_sdf 之後 grep 該 pin,確認每一條 COND WIDTH 行的 (X::X) 中 X 等於該 when 對應的 constraint_high。如果同一 pin 上兩條行還共享同一對 (min::max),表示合併發生了——回頭檢查變數是否真的在 link 之前設好。

10其他會影響的設定

這個變數不孤立工作。幾個鄰居設定會強化、遮蔽、或覆蓋它的效果。

timing_reduce_parallel_cell_arcs 是另一回事
容易混淆。timing_reduce_parallel_cell_arcs 管的是平行 cell delay arc(預設 true),不是 constraint arc。調它不會改變 conditional WIDTH SDF 輸出。Advanced waveform 模式下會自動把它改 false 並印 PTE-112——和 conditional constraint 陷阱無關。
set_min_pulse_width 會覆蓋 Liberty
使用者在 pin 上 set_min_pulse_width 會替換掉所有 lib 端 conditional constraint。這時相容性變數無事可做。當 override 用很實用,當意外屏蔽真實燒寫模式需求時很危險。
對非作用模式 arc 用 set_disable_timing
比 case_analysis 更外科手術的替代:直接對 get_timing_arcs 對應 collection 用 set_disable_timing 關掉非作用 conditional timing arc。用 report_disable_timing 確認只關了燒寫模式 constraint arc。
Lib 編譯品質
如果 .db 是被一個簡化版 Library Compiler 編出來、沒保留 sdf_cond,PrimeTime 任何變數都救不回來。lib_timing_arc 查詢回來 sdf_cond 為空時,務必從原始 .lib 重編。

11為什麼這個 pattern 在不同專案重複出現

Conditional min_pulse_width 與 min_period constraint 出現在所有有模式 pin 的 IP——eFuse、OTP、MTP、有模式控制的 PLL、某些 ADC 取樣時鐘。Library 編碼是標準的,signoff 失效模式也是標準的。

預設關閉的相容性開關最容易漏
改變數值含義但預設走「現代、更快」路徑的變數,是跨專案漂移最常見的源頭。把它釘進專案級別的 setup 腳本。
Session restore 隱藏了操作順序
save_session 是給跑報告的工程師用的生產力工具——它凍結資料庫。任何會影響資料庫如何被建立的設定,都得在 save 之前生效,而非 restore 之後。
跨工具預設不同不是 bug
PrimeTime 與 Tempus 在沒有顯式 case_analysis 時對 conditional pulse-width 行為不一致。把這種不一致當成兩家工具同時要求你「把模式 constraint 寫得更明確」,不要當成工具品質差異。
Gate-Level Sim 對 SDF 完全字面信任
Gate-level 模擬器照 SDF 數字跑,不會去和 lib 對照。一個合併的 COND 值對模擬不可見,但會在下游製造數小時的假 debug。

12結語

現代 signoff 的工程風險,多半已不在數學裡,而在工具預設與 lib 編碼如何互動。Conditional min_pulse_width / SDF 這個案子是個乾淨的例子:一個變數、一條順序規則、一個 lib 慣例——一個能順利通過完整 STA signoff、卻以靜默損壞形式落到 gate-level 模擬裡的失效模式。

如果你的專案用了 eFuse、OTP,或任何含模式相依 pulse-width constraint 的 IP,請審查交給 gate-level 模擬的 SDF。看同一 pin 上多條 COND WIDTH 行是否共享相同 (min::max)——這就是這個陷阱的指紋,而修法只是放在對的檔案裡的一行 TCL。

遇到一個 SDF 或 signoff 異常解釋不通?

我們在 PrimeTime 變數、lib 編譯、工具預設差異裡花了不少時間。把現象丟過來——我們會告訴你這是設置問題、工具 bug,或 lib 在藏什麼。

References

  1. [1]
  2. [2]
  3. [3]