FPGA基礎學習(12) -- 多週期路徑約束

在我實際涉及的項目中,基本沒有遇到多週期路徑約束的情況,所以之前關注的不多,爲了鞏固基本知識,藉此梳理這個約束。

1. 目的

目的就是說什麼時候需要用到多週期約束?

Vivado、TimeQuest等時序引擎默認是按照單週期關係分析數據關係的,即數據在發起沿發送,在捕獲被捕獲,發起沿和捕獲沿相差一個週期。

但是很多情況是,數據路徑邏輯較爲複雜,導致延時較大,使得數據無法在一個時鐘週期內穩定下來, 或者數據可以在一個時鐘週期內穩定下來,但是在數據發送幾個週期之後才使用;在這些情況中,設計者的意圖都是使數據的有效期從發起沿爲起始直至數個週期之後的捕獲沿,這樣的意圖無法被時序分析工具猜度出來,必須由設計者在時序約束中指明;否則時序分析工具會按照單週期路徑檢查的方式執行,往往會誤報出時序違規;

說白了,就是根據用於設計需求,改變原有的時序檢查機制,從而避免非真實的時序違例或者時序過緊導致的資源浪費。

2. 單週期時序檢查

如上圖所示,爲時序引擎默認的單週期檢查機制。確定建立時間路徑和保持時間路徑規則如下:

  • 建立時間路徑

以第一個發送沿爲基準(current launch),再向後尋找距此發送沿最近的一個捕獲沿(current capture),並將兩者的setup定爲1個週期。

  • 保持時間路徑

每確定一個建立路徑,都會檢查兩個保持時間路徑:1)確保當前發送沿推出的數據不被上一個捕獲沿給捕獲,即hold1;2)確保下一個發送沿推出的數據不被當前捕獲沿給捕獲,即hold2。對這描述,爲了便於分析記憶,簡而言之,1)previous capture與current launch 構成一組檢查;2)current capture與next launch 構成一組檢查。

對於兩條保持時間的檢查,時序報告最終只會給出裕量最小的一條。此外,還需要記住:一旦確定建立時間路徑,保持時間路徑會自動根據規則做調整。

3. 使用方法

對於多週期路徑的約束語法,就一條指令:set_multicycle_path

set_multicycle_path [-setup|-hold] [-start|-end]

[-from ] [-to ] [-through <pins|cells|nets>]

參數名稱 含義
-setup 表示建立時間所需要的時鐘週期個數
-hold 表示分析保持時間時,相較於默認的捕獲沿,實際捕獲沿偏差的時鐘週期個數
-start 表示以目的端時鐘作爲時鐘週期計數基準
-end 表示以源端時鐘作爲時鐘週期的計數基準

在默認的情況下,set_multicycle_path

  • 對建立時間的分析是設置目的時鐘爲多週期,即-setup 與-end 搭配使用;
  • 對保持時間的分析是設置源時鐘爲多週期,即-hold與-start搭配使用;

注意,上述是默認情況,-end和-start可以省略。根據場景不同會有所不同,並且數週期個數是往前還是往後也會不同,下面會介紹。

知道了命令參數的含義,結合第2節中的路徑規則的文字描述,那麼默認檢查機制就應該是下面的表達:

set_multicycle_path 1 -setup -end -from [get_clocks s_clk] -to [get_clocks d_clk]
set_multicycle_path 0 -hold -start -from [get_clocks s_clk] -to [get_clocks d_clk]

實際上這個約束的意義,就是使引擎按照設計者的邏輯來重新定義路徑分析的規則。如果沒有深刻理解多週期路徑,是不知道怎麼使用的。爲什麼有的時候只需要setup,有的時候又需要setup和hold,怎麼加-start和-end又不清楚。所以結合文檔給出的4中案例來加深對多週期路徑的理解,並且學會約束語句的使用。

4. 案例

4.1 同一時鐘域

在同一時鐘域下,有的時候,我們希望第一個發送沿推出數據,經過N各週期才被被第二個寄存器的捕獲沿給捕獲。最常見的就是,時鐘使能控制數據捕獲的情形。

如上圖所示,假設使能信號週期爲驅動時鐘的2倍,顯然如果按照默認的規則進行時序檢查,就會發生錯誤。

首先,修改建立時間路徑,使用語句

set_multicycle_path 2 -setup -from [get_pins data0_reg/C] -to [get_pins data1_reg/D]

表示以目的時鐘爲基準,往前數,第2個沿作爲捕獲沿

根據默認規則,保持路徑會自動調整,如圖AFTER。顯然這個時候的捕獲沿的確定是不合適的,會導致保持時序過緊(實現工具會通過增加數據延遲的方式,來優化時序,從而導致資源浪費,功耗增加)。所以增加修改hold規則語句:

set_multicycle_path 1 -hold -end -from [get_pins data0_reg/C] \
-to [get_pins data1_reg/D]

表示以目的時鐘爲基準,相較於默認的捕獲沿,往後數1個週期的沿作爲實際的捕獲沿

綜上,得到最終的路徑關係,如下圖所示:

同理,針對setup延遲5個週期的情況,修改setup規則:

set_multicycle_path 5 -setup -from [get_pins data0_reg/C] -to [get_pins data1_reg/D]

隨着hold關係的自動變化,得到如下圖所示的情形。

修改hold規則,約束語句如下:

set_multicycle_path 4 -hold -end -from [get_pins data0_reg/C] -to [get_pins data1_reg/D]

表示以目的時鐘爲基準,相較於默認的捕獲沿,往後數4個週期的沿作爲實際的捕獲沿,如下圖所示

還有一種修改hold的方式,將-end改爲-start,對應的關係如下圖所示。

那麼上面兩種情況有什麼區別?實際上,是一樣的,因爲兩時鐘爲同一時鐘域。所以針對同一時鐘域,可以不考慮基準,即約束語句可以忽略-end或-start。但是設計者一定要心裏清楚。

針對同一時鐘域的多週期路徑,一般語句可表示爲:

set_multicycle_path N -setup -from [get_pins data0_reg/C] -to [get_pins data1_reg/D]
set_multicycle_path N-1 -hold -from [get_pins data0_reg/C] -to [get_pins data1_reg/D]

4.2 兩時鐘同一週期,但有相移

對於發送和捕獲的兩時鐘是同週期,但存在相移。有兩種情況:clk2較clk1,正相移;clk2較clk1,負相移。


4.2.1 正相移

如下圖所示,clk2較clk1偏移+0.3ns。根據默認的檢查規則,建立和保持路徑已經在圖中表示出來。

可見,數據要在0.3ns之內滿足建立時間,這太緊了。反之,數據給的保持時間卻是-3.7ns,對於時序檢查又太寬鬆。先對建立時間放寬一些,使捕獲沿往後沿一個週期,約束如下:

set_multicycle_path 2 -setup -from [get_clocks CLK1] -to [get_clocks CLK2]

隨着建立路徑的修改,自動判斷新的保持路徑,如上圖所示。此時不需要在對保持路徑進行調整了,所以這種情況只需要修改建立路徑規則即可

4.2.2 負相移

如下圖所示,clk2較clk1偏移-0.3ns。可見,此時的建立路徑和保持路徑即不太緊又不太鬆,可不進行多週期約束。


綜上,對於同週期不同相位的兩時鐘分析,必須要考慮相移方向和相移量。對於負相移,也不是絕對的不用添加約束,如果負相移量太大,實際上就可視爲正相移,同樣需要添加約束。所以視情況而定。

4.3 從慢時鐘到快時鐘

假設捕獲時鐘爲發送時鐘頻率的3倍,默認的檢測機制如上圖所示。在實際設計中,捕獲寄存器肯定需要一個使能信號,才能合理捕獲數據,這個時候會用到多週期路徑約束。同樣先修改建立路徑規則:

set_multicycle_path 3 -setup -from [get_clocks CLK1] -to [get_clocks CLK2]

隨着建立路徑的修改,自動判斷新的保持路徑,如上圖所示。這個時候的保持路徑檢查,會導致消耗過多的資源,增加面積,增加功耗,所以對保持路徑進行修改:

set_multicycle_path 2 -hold -end -from [get_clocks CLK1] -to [get_clocks CLK2]

注意,這種情況和同週期時鐘的多週期路徑約束有相似的地方。但是此時-hold一定要增加-end,表示以目的時鐘爲基準,較默認路徑,往回數2個週期作爲捕獲沿

綜上,對於慢時鐘到快時鐘的情況,一般約束如下:

set_multicycle_path N -setup -from [get_pins data0_reg/C] -to [get_pins data1_reg/D]
set_multicycle_path N-1 -hold -end -from [get_pins data0_reg/C] -to [get_pins data1_reg/D]

4.4 從快時鐘到慢時鐘

如上圖所示,clk1是clk2頻率的3倍。原本默認檢查規則,滿足setup檢查的有3條路徑(有兩條是紅線補充),因爲最終時序報告只會給出最苛刻的一條,所以只保留黑色這條setup路徑。

針對這種情況,需要同時修改建立路徑和保持路徑:

set_multicycle_path 3 -setup -start -from [get_clocks CLK1] -to [get_clocks CLK2]
set_multicycle_path 2 -hold -from [get_clocks CLK1] -to [get_clocks CLK2]

分析這兩條約束語句:首先,-setup必須搭配-start,因爲必須要以源時鐘爲基準,再往後數;

然後,根據默認規則,保持路徑自動調整爲紅色的路徑;最後,約束hold,因爲hold默認搭配-start,所以以源時鐘爲基準,往前數了2個時鐘沿。

綜上,對於快時鐘到慢時鐘的情況,一般約束如下:

set_multicycle_path N -setup -start -from [get_clocks CLK1] -to [get_clocks CLK2]
set_multicycle_path N-1 -hold -from [get_clocks CLK1] -to [get_clocks CLK2]

綜上所有案例,可總結到下圖中:

5. 補充說明

  1. 關於setup 和hold 搭配start和end之後,是往前數還是往後數週期個數

一開始被高老師的《vivado從此開始》中有關多週期路徑約束講述的一點誤導了,在對-hold參數描述時,是這樣寫的

-hold 表示分析保持時間時,相對於默認的捕獲沿實際捕獲沿應回調的時鐘週期個數

“回調”二字我理解偏了,以爲有關hold,不論-start還是-end都往回數週期,結果始終分析不出正確的結果。最後細讀UG903,纔看到下面一圖。

所以,不論是setup還是hold,都可能往前數或者往後數,看具體搭配的是-start還是-end

  1. 時序過鬆、過緊?資源又過渡消耗?

對於多週期路徑約束的使用,我們無非就是要解決由於默認的規則導致時序誤判。但是什麼時候覺得過鬆或者過緊呢?實際上要深刻理解時序分析原理之後,靈活應用於多週期路徑分析。

如下圖所示,默認的檢查規則:

建立時間和保持時間裕量計算公式如下:

setup slack = (current latch edge - current launch edge ) + Tskew - (Tdelay + Tco + Tsu)
= T + Tskew - (Tdelay + Tco + Tsu)
hold slack = Tdelay + Tco - (Th + previous latch edge - current launch edge)
= Tdelay + Tco - Th

以4.1節兩時鐘是同一時鐘域的情況舉例,建立路徑延後1個週期,如下圖所示:

代入公式得到:

setup slack = (current latch edge - current launch edge ) + Tskew - (Tdelay + Tco + Tsu)
= 2*T + Tskew - (Tdelay + Tco + Tsu)
hold slack = Tdelay + Tco - (Th + previout latch edge - current launch edge)
= Tdelay+Tco - (T+Th)

可見,建立時間裕量增加了(多加了一個週期T),而保持時間裕量減少了(多減了一個週期T),這就導致保持時間過緊,實現的過程中需要儘可能增加Tdelay,這樣又會導致資源過度消耗,所以需要調整保持時間。

另一種情況,4.2.1 正相移那節中,如果hold路徑爲負-3.7ns,根據公式,我的理解是保持裕量增加太多(減掉一個負數),導致時序太寬鬆。定性的理解就是,由於上一個捕獲沿在當前發送沿的左邊(正相移導致),所以當前推送的數據,不太可能被上一個捕獲沿所捕獲。

參考文獻

  1. 換位思考多週期約束

  2. Vivado使用技巧(19):多週期路徑
  3. 《Vivado從此開始》
  4. 《UG903》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章