提示:文章寫完后,目錄可以自動生成,如何生成可參考右邊的幫助文檔
目錄
前言
一、Create_clock
前言
時鐘周期約束,就是對時鐘進行約束。
一、Create_clock
create_clock?-name?<name>?-period?<period>?-waveform?{<rise_time>?<fall_time>}?[get_ports?<input_port>]
<name>是時鐘名字
<period>是時鐘周期,單位ns
<rise_time>上升沿時刻
<fall_time>下降沿時刻
這里的時鐘必須是主時鐘,有兩種情況:由外部時鐘源提供,另一種是高速收發器的時鐘,RXOUTCLK或TXOUTCLK。對于7系列FPGA,需要對GT的這兩個時鐘手工約束:對于UltraScale FPGA,只需對GT的輸入時鐘約束即可,Vivado會自動對這兩個時鐘約束。
端口(port)的管腳(pin)的區別。
端口是FPGA的IO端口,對應的XDC命令,get_ports。
管腳是FPGA內部的子模塊的Pin,對應的是get_pins。
除了上面的時鐘外,還有其他的辦法確定時鐘是不是主時鐘,用Tcl腳本。
在Open Synthesized Design
或者Open Implementation Design
,并通過以下兩種方式查看主時鐘。
方式一:
運行tcl指令report_clock_networks -name mainclock
方式二:
運行tcl指令check_timing -override_defaults no_clock
對于高速收發器的時鐘,我們也以Vivado中的CPU example工程為例,看下Xilinx官方是怎么約束的。
#?Define?the?clocks?for?the?GTX?blocks
create_clock?-name?gt0_txusrclk_i?-period?12.8?[get_pins?mgtEngine/ROCKETIO_WRAPPER_TILE_i/gt0_ROCKETIO_WRAPPER_TILE_i/gtxe2_i/TXOUTCLK]
create_clock?-name?gt2_txusrclk_i?-period?12.8?[get_pins?mgtEngine/ROCKETIO_WRAPPER_TILE_i/gt2_ROCKETIO_WRAPPER_TILE_i/gtxe2_i/TXOUTCLK]
create_clock?-name?gt4_txusrclk_i?-period?12.8?[get_pins?mgtEngine/ROCKETIO_WRAPPER_TILE_i/gt4_ROCKETIO_WRAPPER_TILE_i/gtxe2_i/TXOUTCLK]
create_clock?-name?gt6_txusrclk_i?-period?12.8?[get_pins?mgtEngine/ROCKETIO_WRAPPER_TILE_i/gt6_ROCKETIO_WRAPPER_TILE_i/gtxe2_i/TXOUTCLK]
當系統中有多個主時鐘,且這幾個主時鐘之間存在確定的相位關系時,需要用到-waveform
參數。如果有兩個主時鐘,如下圖所示。
對應的時鐘約束為:
create_clock?-name?clk0?-period?10.0?-waveform?{0?5}?[get_ports?clk0]
create_clock?-name?clk1?-period?8.0?-waveform?{2?8}?[get_ports?clk1]
這里應該是指高電平的持續時間,周期是10,0到5ns是高電平。
周期是8ns,高電平時間是2到8ns。
約束中的數字的單位默認是ns,若不寫wavefrom
參數,則默認是占空比為50%且第一個上升沿出現在0時刻。使用report_clocks
指令可以查看約束是否生效。還是上面的CPU的例子,把約束都還原到最初的狀態。執行report_clocks
后,如下所示,我們只列出其中幾項內容。
Clock?ReportClock???????????Period(ns)??Waveform(ns)????Attributes??Sources
sysClk??????????10.000??????{0.000?5.000}???P???????????{sysClk}
gt0_txusrclk_i??12.800??????{0.000?6.400}???P???????????{mgtEngine/ROCKETIO_WRAPPER_TILE_i/gt0_ROCKETIO_WRAPPER_TILE_i/gtxe2_i/TXOUTCLK}
...====================================================
Generated?Clocks
====================================================Generated?Clock???:?clkfbout
Master?Source?????:?clkgen/mmcm_adv_inst/CLKIN1
Master?Clock??????:?sysClk
Multiply?By???????:?1
Generated?Sources?:?{clkgen/mmcm_adv_inst/CLKFBOUT}Generated?Clock???:?cpuClk_4
Master?Source?????:?clkgen/mmcm_adv_inst/CLKIN1
Master?Clock??????:?sysClk
Edges?????????????:?{1?2?3}
Edge?Shifts(ns)???:?{0.000?5.000?10.000}
Generated?Sources?:?{clkgen/mmcm_adv_inst/CLKOUT0}
一般來講,我們的輸入時鐘都是差分的,此時我們只對P端進行約束即可。如果同時約束了P端和N端,通過report_clock_interaction
命令可以看到提示unsafe。這樣既會增加內存開銷,也會延長編譯時間。
二、create_generated_clock
create_generated_clock?-name?<generated_clock_name>?\-source?<master_clock_source_pin_or_port>?\-multiply_by?<mult_factor>?\-divide_by?<div_factor>?\-master_clock?<master_clk>?\<pin_or_port>
-name 時鐘的名字
-source產生該時鐘的源時鐘
-multiply_by源時鐘的多少倍頻
-divide_by源時鐘的多少分頻
這個是約束FPGA內部的衍生時鐘,所以有個-source,這個時鐘叫做Master clokc,指的是上級時鐘,為生成時鐘提供時鐘的時鐘,和primary clock是不同的。這個master clock可以是主時鐘也可以是其他的衍生時鐘,沒有主時鐘那么多限制。
這個命令不是設定周期或波形,而是描述電路如何對上級時鐘進行轉換。
這種轉換可以是:
-
簡單的頻率分頻
-
簡單的頻率倍頻
-
頻率倍頻與分頻的組合,獲得一個非整數的比例,通常由MMCM或PLL完成
-
相移或波形反相
-
占空比改變
-
上述所有關系的組合
衍生時鐘有兩種情況。vivado自動推導的衍生時鐘,用戶自定義的衍生時鐘,自定義的就是上面的。
首先來看第一種,如果使用PLL或者MMCM,則Vivado會自動推導出一個約束。大家可以打開Vivado中有個叫wavegen
的工程,在這個工程中,輸入時鐘經過PLL輸出了2個時鐘,如下圖所示。
但在xdc文件中,并未對這2個輸出時鐘進行約束,只對輸入的時鐘進行了約束,若我們使用report_clocks
指令,則會看到:
有三個約束是因為PLL會自動輸出一個反饋時鐘。
自動推導的好處在于當MMCM/PLL/BUFR的配置改變而影響到輸出時鐘的頻率和相位時,用戶無需改寫約束,Vivado仍然可以自動推導出正確的頻率/相位信息。劣勢在于,用戶并不清楚自動推導出的衍生鐘的名字,當設計層次改變時,衍生鐘的名字也有可能改變。但由于該衍生時鐘的約束并非我們自定義的,因此可能會沒有關注到它名字的改變,當我們使用這些衍生時鐘進行別的約束時,就會出現錯誤。
就是名字要取好,不要重復了。
解決辦法是用戶自己手動寫出自動推導的衍生時鐘的名字,也僅僅寫出名字即可,其余的不寫。如下所示。
create_generated_clock?-name?<generated_clock_name>?\-source?<master_clock_source_pin_or_port>
這一步很容易會被提示critical warning,其實有個很簡單的方法,就是name和source都按照vivado中生成的來。
三、set_clock_groups
使用方法是:
set_clock_groups?-asynchronous?-group?<clock_name_1>?-group?<clock_name_2>set_clock_groups?-physically_exclusive??-group?<clock_name_1>?-group?<clock_name_2>
這個約束常用的方法有三種,第一種用法是當兩個主時鐘是異步關系時,使用asynchronous
來指定。這個在我們平時用的還是比較多的,一般稍微大點的工程,都會出現至少兩個主時鐘,而且這兩個時鐘之間并沒有任何的相位關系,這時就要指定:
create_clock?-period?10?-name?clk1?[get_ports?clk1]
create_clock?-period?8?-name?clk2?[get_ports?clk2]
set_clock_groups?-asynchronous?-group?clk1?-group?clk2
第二種用法是當我們需要驗證同一個時鐘端口在不同時鐘頻率下能否獲得時序收斂時使用。比如有兩個異步主時鐘clk1和clk2,需要驗證在clk2頻率為100MHz,clk1頻率分別為50MHz、100MHz和200MHz下的時序收斂情況,我們就可以這樣寫。
create_clock?-name?clk1A?-period?20.0?[get_ports?clk1]
create_clock?-name?clk1B?-period?10.0?[get_ports?clk1]?-add
create_clock?-name?clk1C?-period?5.0??[get_ports?clk1]?-add?
create_clock?-name?clk2?-period?10.0?[get_ports?clk2]
set_clock_groups?-physically_exclusive?-group?clk1A?-group?clk1B?-group?clk1C
set_clock_groups?-asynchronous?-group?"clk1A?clk1B?clk1C"?-group?clk2
第三種用法就是當我們使用BUFGMUX時,會有兩個輸入時鐘,但只會有一個時鐘被使用。比如MMCM輸入100MHz時鐘,兩個輸出分別為50MHz和200MHz,這兩個時鐘進入了BUFGMUX,如下圖所示。
set_clock_groups?-logically_exclusive?\
-group?[get_clocks?-of?[get_pins?inst_mmcm/inst/mmcm_adv_inst/CLKOUT0]]?\
-group?[get_clocks?-of?[get_pins?inst_mmcm/inst/mmcm_adv_inst/CLKOUT1]]
四、創建虛擬時鐘
虛擬時鐘用于設定輸入和輸出的延遲約束。
這個約束其實是屬于IO約束中的延遲約束。
虛擬時鐘,就是沒有與之綁定的物理管腳。
虛擬時鐘主要用于以下三個場景:
-
外部IO的參考時鐘并不是設計中的時鐘
-
FPGA I/O路徑參考時鐘來源于內部衍生時鐘,但與主時鐘的頻率關系并不是整數倍
-
針對I/O指定不同的jitter和latency
如下圖所示,在FPGA的A和B端口分別有兩個輸入,其中捕獲A端口的時鐘是主時鐘,而捕獲B端口的時鐘是MMCM輸出的衍生時鐘,而且該衍生時鐘與主時鐘的頻率不是整數倍關系。
create_clock?-name?sysclk?-period?10?[get_ports?clkin]
create_clock?-name?virclk?-period?6.4
set_input_delay?2?-clock?sysclk?[get_ports?A]
set_input_delay?2?-clock?virclk?[get_ports?B]
可以看到,創建虛擬時鐘用的也是create_clock
約束,但后面并沒有加get_ports
參數,因此被稱為虛擬時鐘。
再舉個輸出的例子,我們常用的UART和SPI,當FPGA通過串口向下游器件發送數據時,僅僅發過去了uart_tx這個數據,下游器件通過自己內部的時鐘去捕獲uart_tx上的數據,這就需要通過虛擬時鐘來約束;而當FPGA通過SPI向下游器件發送數據時,會發送sclk/sda/csn三個信號,其中sclk就是sda的隨路時鐘,下游器件通過sclk去捕獲sda的數據,而不是用自己內部的時鐘,這是就不需要虛擬時鐘,直接使用set_output_delay
即可。
注意,虛擬時鐘必須在約束I/O延遲之前被定義。
五、最大最小延遲約束
就是設置路徑的max/min delay,主要應用場景有兩個:
-
輸入管腳的信號經過組合邏輯后直接輸出到管腳
-
異步電路之間的最大最小延遲
設置方式為:
set_max_delay?<delay>?[-datapath_only]?[-from?<node_list>][-to?<node_list>][-through?<node_list>]
set_min_delay?<delay>?[-from?<node_list>]?[-to?<node_list>][-through?<node_list>]
-form有效的起始節點包含:時鐘,input(input)端口,或時序單元(寄存器,RAM)的時鐘引腳.
-to有效的終止節點包含:時鐘,output(inout)端口或時序單元的數據端口.
-through有效的節點包含:引腳,端口,線網.
max/min delay的約束平時用的相對少一些,因為在跨異步時鐘域時,我們往往會設置asynchronous
或者false_path
。對于異步時鐘,我們一般都會通過設計來保證時序能夠收斂,而不是通過時序約束來保證。