Xilinx約束學習筆記(二)—— 定義時鐘

NeverCode 發表於 2021-08-24

2. 定義時鐘

2.1 關於時鐘

為了獲得最佳精度路徑覆蓋資訊,必須正確定義時鐘。

  • 時鐘要定義在時鐘樹的根 pin 或 port 上,稱為 source point。
  • 時鐘的邊緣應該由週期和波形進行組合描述。
  • 週期使用納秒做為單位進行定義。它對應于波形重複的時間。
  • 波形是一系列的上升沿和下降沿絕對時間列表,單位為納秒,並且所有時間在一個時鐘週期內。列表必須包含偶數個值。第一個值始終對應於第一個上升邊緣。如果沒有指定波形,波形的預設佔空比為 50%,相移為 0。

2.1.1 傳播時鐘

週期和波形屬性只展現出了時鐘的理想特性。當時鍾進入 FPGA 並通過時鐘樹傳播時,時鐘邊沿被延緩,並受噪聲和硬體行為引影響。這些特性稱為時鐘網路延遲和時鐘不確定性。時鐘的不確定性包括:

  • 時鐘抖動(clock jitter)
  • 相位錯誤
  • 使用者指定新增的不確定性

預設情況下,Vivado 在做時序分析時,始終將時鐘視為傳播時鐘,即非理想時鐘,以此提供準確的餘量值,其中包括時鐘樹插入延遲和不確定性。

2.1.2 專用硬體資源

FPGA 有大量專用的時鐘管腳,這個管腳可以專門用來做時鐘的輸入。FPGA 內部包含有 MMCM、PLL 和 BUR 之類的時鐘資源。

2.2 基準時鐘(Primary Clock)

基準時鐘是通過 FPGA 輸入埠或千兆收發器輸出引腳(例如,恢復時鐘)進入設計的時鐘。基準時鐘只能通過 create_clock 指令進行定義。(為什麼是千兆收發器?下面的話應該可以解釋,7 系列的 GT 恢復時鐘不能自動推導,必須手動定義。而 US 和 USP 系列的可以自動推導,不需要人為定義)

Primary clocks must be defined on a gigabit transceiver output only for Xilinx® 7 series FPGAs. For UltraScale and UltraScale+™ devices, the timer automatically derives clocks on the GT output ports.

基準時鐘必須附加到網表物件。該網表物件代表設計中的所有時鐘邊沿起點,並且是時鐘樹上向下遊傳播的起點。換句話說,基準時鐘的源點定義了零時間點,這個點被 Vivado 用來計算餘量方程時,作為時鐘延遲和不確定性的零起點。Vivado 會忽略來自定義基準時鐘點上游單元的所有時鐘樹延遲。如果基準時鐘錯誤的定義在了路徑中間的引腳上,則只有部分延遲用於時序分析。
這可能會引起問題,因為時鐘之間的偏斜和餘量值會變得不準確。

2.2.1 基準時鐘示例

image-20210823215132300

# 週期 10ns, 來源於外部,通過 sysclk 埠輸入,佔空比 50%,相位為 0。
create_clock -period 10 [get_ports sysclk]

# 週期 10ns, 來源於外部,通過 ClkIn 埠輸入,佔空比 25%,相位為 90。
create_clock -name devclk -period 10 -waveform {2.5 5} [get_ports ClkIn]

image-20210823215303233

# GT 的恢復時鐘無法自動推導時,需要手動約束。Vivado 在計算餘量時,會從RXOUTCLK開始。
create_clock -name rxclk -period 3.33 [get_pins gt0/RXOUTCLK]

image-20210823220104689

# 對於差分時鐘,時鐘必須定義在 P 端上,N 端上不能有定義。如果 P 和 N 各自定義一次,會導致軟體認為是非同步路徑。
create_clock -name sysclk -period 3.33 [get_ports SYS_CLK_clk_p]

2.3 虛擬時鐘(Virtual Clocks)

虛擬時鐘是一種沒有物理連線到設計中任何網表元素的時鐘。虛擬時鐘是通過 create_clock 指令定義的,但無需指定源物件。虛擬時鐘通常用於指定輸入和輸出延遲約束:

# 建立時鐘,但不指定時鐘源
create_clock -name clk_virt -period 10

2.4 衍生時鐘(Generated Clocks)

2.4.1 關於衍生時鐘

衍生時鐘產生於 FPGA 設計內部,通常由 MMCM 或使用者邏輯產生。衍生時鐘有一個關聯的主時鐘(master clock),指令 create_generated_clock 需要指定一個主時鐘,它可以是基準時鐘或者是另一個衍生時鐘。衍生時鐘屬性直接源自其主時鐘,定義衍生時鐘時,不是指定它們的週期或波形,而是描述如何轉換主時鐘到衍生時鐘。衍生時鐘和主時鐘之間的關係可以是以下任何一種:

  • 簡單的分頻
  • 簡單的倍頻
  • 分頻和倍頻的組合,用來得到一個非整數比的分頻。
  • 移相或反相
  • 改變佔空比
  • 所有上面的組合

為了計算衍生時鐘的延遲,工具會跟蹤衍生時鐘的源引腳和主時鐘的源引腳之間的時序路徑和組合路徑。在某些情況下,可能需要僅跟蹤組合路徑以計算生成的時鐘延遲。可以使用 -combinational 行選項執行此操作。

2.4.2 使用者自定義的衍生時鐘

2.4.2.1 示例1:簡單的2分頻

image-20210823224136595

create_clock -name clkin -period 10 [get_ports clkin]

# Option 1: master clock source is the primary clock source point
create_generated_clock -name clkdiv2 -source [get_ports clkin] -divide_by 2 [get_pins REGA/Q]

# Option 2: master clock source is the REGA clock pin
create_generated_clock -name clkdiv2 -source [get_pins REGA/C] -divide_by 2 [get_pins REGA/Q]

2.4.2.2 示例2:使用 -edge 選項進行2分頻

可以不使用 -divide_by 選項,而是使用 -edges 選項直接基於主時鐘邊沿描述衍生時鐘波形。該引數是一組主時鐘邊沿的序號,用來標記衍生時鐘的跳變沿的位置。從衍生時鐘的上升沿開始描述。

# waveform specified with -edges instead of -divide_by
create_generated_clock -name clkdiv2 -source [get_pins REGA/C] -edges {1 3 5} [get_pins REGA/Q]

2.4.2.3 示例3:使用 -edge 和 -edge_shift 選項改變佔空比和相位

當需要做移相時,可以使用 -edge_shift 選項。衍生時鐘的每個邊沿都可以單獨的進行正向或負向移相。-edge_shift 選項 不能和以下選項同時使用:

  • -divide_by
  • -multiply_by
  • -invert

假設主時鐘 clkin 的週期為 10 ns,佔空比為 50% 。clkin 輸入到 mmcm0 後,衍生出一個時鐘,其佔空比為 25%,移相 90 度。衍生時鐘定義基於主時鐘的第 1、2 和 3 邊沿。這些邊沿跳變分別發生在 0ns、5ns 和 10ns 上。要獲得所需的波形,將第一和第三邊沿移動 2.5ns。

image-20210823225527551

create_clock -name clkin -period 10 [get_ports clkin]
# First rising edge:   0ns + 2.5ns = 2.5ns
# Falling edge:        5ns + 0ns   = 5ns
# Second rising edge: 10ns + 2.5ns = 12.5ns
create_generated_clock -name clkshift -source [get_pins mmcm0/CLKIN] -edges {1 2 3} \
    -edge_shift {2.5 0 2.5} [get_pins mmcm0/CLKOUT]

注意: -edge_shift 的值可以為正數,也可以為負數。

2.4.2.4 示例4:同時使用 -divide_by 和 -multiply_by

Vivado 允許同時指定 -divide_by-multiply_by,這是對 SDC 的擴充套件。雖然這對於手動定義 MMCM 或 PLL 生成的時鐘特別方便,但是 Xilinx 建議讓軟體自動建立這些約束。如果手動定義了約束,必須確認約束的設定和鎖相環本身的配置是相匹配的。

# 假設 MMCM 生成的時脈頻率為原主時鐘的 4/3。
create_generated_clock -name clk43 -source [get_pins mmcm0/CLKIN] -multiply_by 4 \
    -divide_by 3 [get_pins mmcm0/CLKOUT]

2.4.2.5 示例5:追蹤主時鐘的組合邏輯路徑

在此示例中,假設主時鐘同時驅動基於暫存器的時2分頻器和時鐘多路複用器,時鐘多路複用器可從選擇主時鐘或2分頻時鐘。在此方案中,從主時鐘到生成的時鐘有兩條路徑,即時序邏輯路徑和組合邏輯路徑。我們希望在多路複用器輸出上建立一個衍生時鐘,該輸出反映了從主時鐘到多路複用器的組合路徑的延遲。這可以通過使用 -combinational 選項完成的:

image-20210824095944630

create_generated_clock -name clkout -source [get_pins mmcm0/CLKIN] -combinational [get_pins MUX/O]

2.4.2.6 示例6:由 ODDR 驅動的轉發時鐘

在此示例中,由 ODDR 單元驅動的輸出埠上建立轉發時鐘。轉發時鐘參考驅動 ODDR/CLKDIV 引腳的主時鐘,並且與主時鐘(-divide_by 1) 具有相同的週期。

image-20210824100521913

create_generated_clock -name ck_vsf_clk_2 -source [get_pins ODDRE1_vsfclk2_inst/CLKDIV] -divide_by 1 [get_ports vsf_clk_2]

2.4.3 自動推匯出的衍生時鐘

自動推導的時鐘也稱為自動生成時鐘。Vivado 會自動在 CMB( Clock Modifying Blocks)的輸出引腳上建立這些約束,前提是相關的主時鐘已經定義。

  • Xilinx 7 系列的 CMB 可以是:
    • MMCM*/ PLL*
    • BUFR
    • PHASER*
  • Xilinx UltraScale 系列的 CMB 可以是:
  • MMCM* / PLL*
  • BUFG_GT / BUFGCE_DIV
  • GT* _COMMON / GT*_CHANNEL / IBUFDS_GTE3
  • BITSLICE_CONTROL / RX*_BITSLICE
  • ISERDESE3

如果使用者定義的時鐘(主時鐘或衍生時鐘)也在同一網列表物件(即在同一定義點(pin 或 net)上定義,Vivado 則不會自動建立衍生時鐘。

2.4.3.1 自動衍生時鐘示例

以下自動衍生時鐘示例是由 MMCM 生成的時鐘。 主時鐘 clkin 驅動 MMCME2 例項 clkip/mmcm0 的輸入 CLKIN。自動生成的時鐘的名稱是 cpuClk,其定義點是 clkip/mmcm0/CLKOUT。

image-20210824104151371

使用 get_clocks -of_objects <pin/port/net> 命令在不知道其名稱的情況下查詢自動生成的時鐘。這使的約束或指令碼相對通用,不用關心時鐘名稱是否有改動。

2.4.3.2 本地網名

如果 CMB 例項位於設計層次結構內,則生成的時鐘名稱將使用本地網名(即沒有父單元名的名稱)。例如,對於名稱為 clkip/cpuClk 的層次網線:

  • 父單元名稱為 clkip 。
  • 生成的時鐘名稱為 cpuClk。

2.4.3.3 名稱衝突

如果兩個自動生成的時鐘之間的名稱有衝突,Vivado 會新增獨有的字尾來區分它們,例如:

  • usrclk
  • usrclk_1
  • usrclk_2

強制修改衍生時鐘的名稱:

  • 在 RTL 中選擇獨特且相關的網名。
  • 使用 create_generated_clock 強制使用指定的名稱。

2.4.4 重新命名自動衍生時鐘

可以對工具自動建立的衍生時鐘進行重新命名。重新命名通過使用 create_generated_clock 指令和有限的引數完成。

create_generated_clock -name new_name [-source master_pin] [-master_clock master_clk] source_object

必須指定的引數有新生成的時鐘名稱和生成時鐘的源物件。生成時鐘的源物件是建立衍生時鐘的物件(CMB 的輸出引腳、UltraScale GT 的輸出引腳等)。只有當多個時鐘通過源引腳傳播時,才能使用源和主引數,以消除任何模糊性。當有多個時鐘通過源物件傳播時,必須指定 -source-master 引數,以消除任何不明確的地方。

注意:如果有 -edges / -edge_shift / -divide_by / -multiply_by / -combinational / -duty_cycle / -invert 選項傳遞到create_generated_clock 指令,則自動生成衍生時鐘不會被重新命名,相反會重新定義一個新的衍生時鐘。

注意:使用 OOC 模式的模組在綜合時,模組被當做黑盒,模組內部引腳和時鐘名稱不可訪問。在這種情況下,用於綜合的頂層 XDC 約束不能指定時鐘名稱或重新命名模組內生成的自動衍生時鐘。可以使用一些查詢指令引用相關目標,如 get_clocks -of_objects [get_pins <OOC_MODULE_OUTPUT_CLOCK_PORT>]。用於實現的 XDC 約束沒有此限制。

重新命名的限制:

  • 自動衍生時鐘只能在其源引腳上重新命名,例如在 CMB(PLL、MMCM. .. ) 的輸出處。自動衍生時鐘不能在 BUFG 的輸出上重新命名,即便時鐘是通過它傳播的。
  • 無法重新命名基準時鐘或使用者定義衍生時鐘。只有自動衍生時鐘才能使用此機制進行重新命名。
  • source_object 必須匹配建立自動衍生時鐘的物件。
  • 如果工具無法重新命名衍生時鐘,則會返回錯誤。重新命名完成時,主時鐘也必須存在。
  • 自動衍生時鐘可以在 XDC 內的任何時間重新命名,即使已被某些時序約束引用。

2.5 時鐘組(Clock Groups)

2.5.1 關於時鐘組

預設情況下,Vivado 會對設計中所有時鐘之間的路徑進行時序收斂,除非使用了時鐘組或偽路徑進行約束。set_clock_groups 指令會讓 Vivado 不對時鐘組之間的路徑進行時序分析,而同一組內的時鐘之間的仍會進行時序收斂。與 set_false_path 約束不同,兩個時鐘之間的兩個方向的路徑都會被忽略。

可以多次使用 -group 選項指定多個時鐘組。如果組中的時鐘在設計中都不存在,則組將變為空。set_clock_groups 約束至少需要兩組,並且都不為空組時才有效。如果只有一個組有效,其他組都為空時,set_clock_groups 約束不會生效,並返回錯誤訊息。

使用原理圖檢視器(Schematic Viewer)或時鐘網路報告(Clock Networks Report)檢視視覺化時鐘樹的拓撲,確定哪些時鐘不能一起進行收斂。您還可以使用時鐘互動報告來(Clock Interactions Report)檢視兩個時鐘之間的現有約束,並確定它們是有相同的主時鐘(即它們具有已知的相位關係),或者判斷出週期沒有公倍數的時鐘(Unexpandable)。

謹慎!忽略兩個時鐘之間的時序分析並不意味著它們之間的路徑將在硬體上能正常工作。為了防止亞穩態,必須確認這些路徑是否具有適當的同步電路或非同步資料傳輸協議。

2.5.2 時鐘分類

  • 同步時鐘
    當兩個時鐘的相對相位關係是已知的,它們就是是同步時鐘。通常它們的時鐘樹源頭來自網列表中的同一根,它們的週期有公倍數。例如,衍生時鐘和他的主時鐘的週期比率為 2,這兩個時鐘是同步的。因為它們有相同時鐘源點,並且週期為2倍關係。它們可以安全地一起進行時序收斂。

  • 非同步時鐘
    當無法確定兩個時鐘的相對相位關係時,這兩個時鐘就是非同步的。例如,由板上兩個獨立晶振生成的時鐘,通過不同輸入埠進入 FPGA,這兩個時鐘就是非同步的。如果它們是由板上的同一晶振生成的,這兩個就不是非同步時鐘。在大多數情況下,基準時鐘可以被視為非同步時鐘。

  • 不可擴充套件的時鐘(Unexpandable Clocks)
    當時序引擎在 1000 個週期中無法找到兩個時鐘週期的公倍數時,則認為兩個時鐘無法擴充套件。在這種情況下,在時序分析時會使用 1000 週期中最小的相位關係,但時序引擎無法保證這是最差的情況。通常這兩個時鐘之間的週期比比較奇怪的情況。例如,兩個時鐘 clk0 和 clk1,由相同主時鐘的兩個 MMCM 生成,clk0 週期為 5.12 ns,clk1 週期為 6.66 ns。他們的上升沿在 1000 個週期內沒有對齊的時候,時序引擎會取最差的情況 0.01 ns 做時序收斂。與非同步時鐘一樣,餘量計算會正常進行,但其值是不可信的。因此,無可擴充套件的時鐘經常被處理為非同步時鐘,必須用處理非同步時鐘相同的方式對待這兩個時鐘,包括其約束和非同步電路。

2.5.3 非同步時鐘組

非同步時鐘和不可擴充套件時鐘不能被時序收斂。使用 set_clock_groups 指令可以在時序分析時忽略它們之間的時序路徑。

注意set_clock_groups 比普通的時序例外的優先順序要高,如果需要約束和報告非同步時鐘間的路徑,那就不能使用 set_clock_groups ,只能使用時序例外。

2.5.3.1 非同步時鐘組示例

  • 基準時鐘 clk0 定義在輸入管腳上,並連線到了 MMCM。MMCM 生成了 usrclk 和 itfclk 兩個時鐘 。
  • 另一個基準時鐘 clk1 定義在了 GTP 輸出的恢復時鐘上,並連線到了另一個 MMCM。此 MMCM 生成了 gtclkrx 和 gtclktx 兩個時鐘。

使用 -asynchronous 選項建立非同步時鐘組。

set_clock_groups -name async_clk0_clk1 -asynchronous -group {clk0 usrclk itfclk} \    -group {clk1 gtclkrx gtclktx}

如果衍生時鐘的名稱無法事先得知,可以使用 get_clocks -include_generated_clocks 動態獲取。所以上面的約束也可以寫成如下方式,其移植性更強。

set_clock_groups -name async_clk0_clk1 -asynchronous \    -group [get_clocks -include_generated_clocks clk0] \    -group [get_clocks -include_generated_clocks clk1]

注意:上面的約束中,非同步是指組與組之間非同步,組內各時鐘仍會進行時序分析和收斂。

2.5.4 獨佔時鐘組(Exclusive Clock Groups)

有些設計擁有多種操作模式,在不同的模式下需要使用不同的時鐘。時鐘之間的選擇通常使用時鐘多路複用器完成,如 BUFGMUX 和 BUFGCTRL 或 LUT(儘量不使用LUT做時鐘選擇)。由於這些單元是組合邏輯,所這些時鐘都通過同一個時鐘樹傳播。這些時鐘會同時報告中呈現,但在硬體方面是不可能的,同一時刻只會有一個時鐘。這種不會同時工作的時鐘稱作獨佔時鐘。

2.5.4.1 獨佔時鐘組示例

獨佔時鐘使用 set_clock_groups-logically_exclusive-physically_exclusive 選項進行定義。在 Vivado 中,這兩個選項的意義是相同的,任意使用一個即可。

假設一個 MMCM 輸出了 clk0 和 clk1,這兩個時鐘連線到了一個 BUFGMUX(例項名為clkmux),輸出 clkmux 驅動時鐘樹。預設情況下,Vivado 會分析 clk0 和 clk1 之間的路徑,即便兩個時鐘驅動同一個時鐘樹,並且兩個時鐘不可能同時使用。必須使用如下約束停止分析兩個時鐘之間的路徑。

set_clock_groups -name exclusive_clk0_clk1 -physically_exclusive -group clk0 -group clk1

2.6 時鐘延遲、抖動和不確定性

除了定義時鐘波形外,還必須指定與操作條件和環境相關的可預測變化和隨機變化。

2.6.1 時鐘延遲

時鐘在 PCB 板上和 FPGA 內部傳播後,時鐘沿會經過一段延時後到達目的地。此延時通常有:

  • 源延時(通常在時鐘源點之前,在 FPGA 裝置外部)。
  • 網路延時。

網路延時(也稱為插入延時),其延時值要麼是自動估算(pre-route design),要麼是精確計算(post-route design)。

Xilinx FPGA 使用 set_clock_latency 指令主要是用來指定器件外部的延時。

# Minimum source latency value for clock sysClk (for both Slow and Fast corners)set_clock_latency -source -early 0.2 [get_clocks sysClk]# Maximum source latency value for clock sysClk (for both Slow and Fast corners)set_clock_latency -source -late 0.5 [get_clocks sysClk]

2.6.2 時鐘不確定性

2.6.2.1 時鐘抖動

對於 ASIC 裝置,時鐘抖動通常表示在時鐘不確定性特徵中。然而,對於 FPGA 來說,抖動特性是可以預知的。它們可以通過時序分析引擎自動計算,也可以單獨指定。

  • 輸入抖動(Input Jitter)
    輸入抖動是連續時鐘邊緣與理想時鐘到達時間的差別。輸入抖動是一個絕對值,表示時鐘邊緣兩側的變化。使用 set_input_jitter 指令單獨指定每個基準時鐘的輸入抖動。衍生時鐘上的輸入抖動無法直接指定,Vivado 時序引擎會自動從主時鐘繼承的抖動到衍生時鐘。

    • 對於由 MMCM 或 PLL 生成的時鐘,輸入抖動被計算的不同的抖動替換。
    • 對於由組合邏輯或時序邏輯生成的時鐘,生成時鐘抖動與其主時鐘抖動相同。

    以下命令在通過輸入埠 clkin 傳播的基準時鐘上設定 +/-100 ps 抖動:

    set_input_jitter [get_clocks -of_objects [get_ports clkin]] 0.1
    
  • 系統拉動(System Jitter)
    系統抖動是由於電源噪聲、板噪聲或系統的任何額外抖動而導致的整體抖動。使用 set_system_jitter 指令只為整個設計設定一個值,即針對所有時鐘。

2.6.2.2 附加時鐘不確定性

使用 set_clock_uncertainty 指令定義不同角落、延時或特定時鐘關係所需的額外時鐘不確定性。這一種方便為設計增加額外餘量的方法。

無論約束的順序如何,時鐘相互間的不確定性總是優先於簡單的時鐘不確定性。在下示例中,雖然時鐘 clk1 上最後定義了 1.0 ns 的簡單時鐘不確定性,但從時鐘 clk1 到時鐘 clk2 的計時路徑受到 2.0 ns 時鐘不確定性的限制。

set_clock_uncertainty 2.0 -from [get_clocks clk1] -to [get_clocks clk2]set_clock_uncertainty 1.0 [get_clocks clk1]