時鐘周期約束
時鐘周期約束,顧名思義,就是我們對時鐘的周期進行約束,這個約束是我們用的最多的約束了,也是最重要的約束。
下面我們講一些Vivado中時鐘約束指令。
1. Create_clock
在Vivado中使用create_clock來創(chuàng)建時鐘周期約束。使用方法為:
create_clock -name-period -waveform { } [get_ports ]
這里的時鐘必須是主時鐘primary clock,主時鐘通常有兩種情形:一種是時鐘由外部時鐘源提供,通過時鐘引腳進入FPGA,該時鐘引腳綁定的時鐘為主時鐘:另一種是高速收發(fā)器(GT)的時鐘RXOUTCLK或TXOUTCLK。對于7系列FPGA,需要對GT的這兩個時鐘手工約束:對于UltraScale FPGA,只需對GT的輸入時鐘約束即可,Vivado會自動對這兩個時鐘約束。
如何確定主時鐘是時鐘周期約束的關(guān)鍵,除了根據(jù)主時鐘的兩種情形判斷之外,還可以借助Tcl腳本判斷。
在vivado自帶的example project里面,打開CPU(HDL)的工程,如下圖所示。
把工程的xdc文件中,create_clock的幾項都注釋掉。這里解釋下端口(Port)和管腳(Pin)。get_ports獲取的是FPGA的IO端口,get_pins獲取的是FPGA內(nèi)部子模塊的Pin,具體的我們在第14講的Tcl命令中會講到。
再Open Synthesized Design或者Open Implementation Design,并通過以下兩種方式查看主時鐘。
? 方式一
運行tcl指令report_clock_networks -name mainclock,顯示結(jié)果如下:
? 方式二
運行tcl指令check_timing -override_defaults no_clock,顯示結(jié)果如下:
Vivado中的tcl命令行相當(dāng)好用,有很多的功能,大家可以開始習(xí)慣用起來了。
對于高速收發(fā)器的時鐘,我們也以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]
當(dāng)系統(tǒng)中有多個主時鐘,且這幾個主時鐘之間存在確定的相位關(guān)系時,需要用到-waveform參數(shù)。如果有兩個主時鐘,如下圖所示。
則時鐘約束為:
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]
約束中的數(shù)字的單位默認是ns,若不寫wavefrom參數(shù),則默認是占空比為50%且第一個上升沿出現(xiàn)在0時刻。使用report_clocks指令可以查看約束是否生效。還是上面的CPU的例子,把約束都還原到最初的狀態(tài)。執(zhí)行report_clocks后,如下所示,我們只列出其中幾項內(nèi)容。
Clock Report Clock 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。這樣既會增加內(nèi)存開銷,也會延長編譯時間。
2. create_generated_clock
其使用方法為:
create_generated_clock -name/ -source / -multiply_by / -divide_by / -master_clock /
從名字就能看出來,這個是約束我們在FPGA內(nèi)部產(chǎn)生的衍生時鐘, 所以參數(shù)在中有個-source,就是指定這個時鐘是從哪里來的,這個時鐘叫做master clock,是指上級時鐘,區(qū)別于primary clock。
它可以是我們上面講的primary clock,也可以是其他的衍生時鐘。該命令不是設(shè)定周期或波形,而是描述時鐘電路如何對上級時鐘進行轉(zhuǎn)換。
這種轉(zhuǎn)換可以是下面的關(guān)系:
-簡單的頻率分頻
-簡單的頻率倍頻
-頻率倍頻與分頻的組合,獲得一個非整數(shù)的比例,通常由MMCM或PLL完成
-相移或波形反相
-占空比改變
-上述所有關(guān)系的組合
衍生時鐘又分兩種情況:
① Vivado自動推導(dǎo)的衍生時鐘
② 用戶自定義的衍生時鐘
首先來看第一種,如果使用PLL或者MMCM,則Vivado會自動推導(dǎo)出一個約束。大家可以打開Vivado中有個叫wavegen的工程,在這個工程中,輸入時鐘經(jīng)過PLL輸出了2個時鐘,如下圖所示。
但在xdc文件中,并未對這2個輸出時鐘進行約束,只對輸入的時鐘進行了約束,若我們使用report_clocks指令,則會看到:
注:有三個約束是因為PLL會自動輸出一個反饋時鐘
自動推導(dǎo)的好處在于當(dāng)MMCM/PLL/BUFR的配置改變而影響到輸出時鐘的頻率和相位時,用戶無需改寫約束,Vivado仍然可以自動推導(dǎo)出正確的頻率/相位信息。劣勢在于,用戶并不清楚自動推導(dǎo)出的衍生鐘的名字,當(dāng)設(shè)計層次改變時,衍生鐘的名字也有可能改變。但由于該衍生時鐘的約束并非我們自定義的,因此可能會沒有關(guān)注到它名字的改變,當(dāng)我們使用者這些衍生時鐘進行別的約束時,就會出現(xiàn)錯誤。
解決辦法是用戶自己手動寫出自動推導(dǎo)的衍生時鐘的名字,也僅僅寫出名字即可,其余的不寫。如下所示。
create_generated_clock -name/ -source
這一步很容易會被提示critical warning,其實有個很簡單的方法,就是name和source都按照vivado中生成的來。具體我們到后面的例子中會講到。
3. set_clock_groups
使用方法為:
set_clock_groups -asynchronous -group-group set_clock_groups -physically_exclusive -group -group
這個約束常用的方法有三種,第一種用法是當(dāng)兩個主時鐘是異步關(guān)系時,使用asynchronous來指定。這個在我們平時用的還是比較多的,一般稍微大點的工程,都會出現(xiàn)至少兩個主時鐘,而且這兩個時鐘之間并沒有任何的相位關(guān)系,這時就要指定:
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
第二種用法是當(dāng)我們需要驗證同一個時鐘端口在不同時鐘頻率下能否獲得時序收斂時使用。比如有兩個異步主時鐘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
第三種用法就是當(dāng)我們使用BUFGMUX時,會有兩個輸入時鐘,但只會有一個時鐘被使用。比如MMCM輸入100MHz時鐘,兩個輸出分別為50MHz和200MHz,這兩個時鐘進入了BUFGMUX,如下圖所示。
在這種情況下,我們需要設(shè)置的時序約束如下:
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]]
4. 創(chuàng)建虛擬時鐘
虛擬時鐘通常用于設(shè)定對輸入和輸出的延遲約束,這個約束其實是屬于IO約束中的延遲約束,之所以放到這里來講,是因為虛擬時鐘的創(chuàng)建,用到了本章節(jié)講的一些理論。虛擬時鐘和前面講的延遲約束的使用場景不太相同。顧名思義,虛擬時鐘,就是沒有與之綁定的物理管腳。
虛擬時鐘主要用于以下三個場景:
? 外部IO的參考時鐘并不是設(shè)計中的時鐘
? FPGA I/O路徑參考時鐘來源于內(nèi)部衍生時鐘,但與主時鐘的頻率關(guān)系并不是整數(shù)倍
? 針對I/O指定不同的jitter和latency
簡而言之,之所以要創(chuàng)建虛擬時鐘,對于輸入來說,是因為輸入到FPGA數(shù)據(jù)的捕獲時鐘是FPGA內(nèi)部產(chǎn)生的,與主時鐘頻率不同;或者PCB上有Clock Buffer導(dǎo)致時鐘延遲不同。對于輸出來說,下游器件只接收到FPGA發(fā)送過去的數(shù)據(jù),并沒有隨路時鐘,用自己內(nèi)部的時鐘去捕獲數(shù)據(jù)。
如下圖所示,在FPGA的A和B端口分別有兩個輸入,其中捕獲A端口的時鐘是主時鐘,而捕獲B端口的時鐘是MMCM輸出的衍生時鐘,而且該衍生時鐘與主時鐘的頻率不是整數(shù)倍關(guān)系。
這種情況下時序約束如下:
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]
可以看到,創(chuàng)建虛擬時鐘用的也是create_clock約束,但后面并沒有加get_ports參數(shù),因此被稱為虛擬時鐘。
再舉個輸出的例子,我們常用的UART和SPI,當(dāng)FPGA通過串口向下游器件發(fā)送數(shù)據(jù)時,僅僅發(fā)過去了uart_tx這個數(shù)據(jù),下游器件通過自己內(nèi)部的時鐘去捕獲uart_tx上的數(shù)據(jù),這就需要通過虛擬時鐘來約束;而當(dāng)FPGA通過SPI向下游器件發(fā)送數(shù)據(jù)時,會發(fā)送sclk/sda/csn三個信號,其中sclk就是sda的隨路時鐘,下游器件通過sclk去捕獲sda的數(shù)據(jù),而不是用自己內(nèi)部的時鐘,這是就不需要虛擬時鐘,直接使用set_output_delay即可。
注意,虛擬時鐘必須在約束I/O延遲之前被定義。
5. 最大最小延遲約束
顧名思義,就是設(shè)置路徑的max/min delay,主要應(yīng)用場景有兩個:
? 輸入管腳的信號經(jīng)過組合邏輯后直接輸出到管腳
? 異步電路之間的最大最小延遲
設(shè)置方式為:
set_max_delay[-datapath_only] [-from ][-to ][-through ] set_min_delay [-from ] [-to ][-through ]
max/min delay的約束平時用的相對少一些,因為在跨異步時鐘域時,我們往往會設(shè)置asynchronous或者false_path。對于異步時鐘,我們一般都會通過設(shè)計來保證時序能夠收斂,而不是通過時序約束來保證。
-
FPGA
+關(guān)注
關(guān)注
1629文章
21736瀏覽量
603315 -
時序約束
+關(guān)注
關(guān)注
1文章
115瀏覽量
13425 -
Vivado
+關(guān)注
關(guān)注
19文章
812瀏覽量
66523
發(fā)布評論請先 登錄
相關(guān)推薦
評論