第一章 FPGA時序約束分享02_時鐘約束
作者:潘文明
上一篇《FPGA時序約束分享01_約束四大步驟》一文中,介紹了時序約束的四大步驟。
?
? ?上圖是四大步驟,并且每個步驟都分別展開了各種情況,后續(xù)可以參考對照,分別添加時序約束。本文講述上圖中的第1點:時鐘約束。
? ?時鐘約束分三種情況:輸入時鐘、PLL等衍生時鐘以及自己分頻的時鐘。而其中輸入時鐘又可再分三種,第一種是輸入管腳是CLK的,第二種是差分時鐘,最后一種是GT或?恢復(fù)的一個時鐘。下面分別展開描述。
?
第1節(jié) 輸入時鐘
?
? ?輸入時鐘根據(jù)管腳情況,有三種三種,第一種是輸入管腳是CLK的,第二種是差分時鐘,最后一種是GT或?恢復(fù)的一個時鐘。
?
? 1.1 輸入管腳CLK
? ? 時鐘直接從管腳輸入,如上圖所示。這種是最常見的一個情況,包括明德?lián)P的MP603、MP801學(xué)習板,其時鐘都是由外部的晶振產(chǎn)生,然后直接輸入管腳進來的,這種情況的生成時鐘約束是最簡單的,其格式如下:
? ?create_clock -name SysClk -period 10 -waveform {0 5} [get_ports Clk]
? ?create_clock是生成約束約束命令。
? ?name后面表示給這個時鐘命名,這里命名為SysClk,您可以命為其他您所想要的名字,即使跟代碼中的時鐘名不同,都是可以的。
? ?period后面表示約定該時鐘的周期,默認單位為納秒。
? ?waveform后面表示該時鐘在一個周期內(nèi)的上升沿和下降沿時間點。{0 5}表示時鐘在第0時刻上升,在第5時鐘下降。通過這個,設(shè)置了時鐘的占空比。
? ?get_ports這里指定了約束的對象,即對應(yīng)代碼中的哪個信號,get_ports Clk,表示這個時鐘就是代碼或上圖中的Clk。
? 這個時鐘約束是最常用的,只要參照這種格式生成晚就可以了。
?
?
? ?假設(shè)說該時鐘輸入后經(jīng)過了一個內(nèi)部的PLL或者MMCM(時鐘管理單元)后,再作為工作時鐘,此種情況下,仍然是要對Clk約束,其約束方法跟前面是一樣的。注意,這里說的是約束上面的時鐘Clk,而不是MMCM的輸出時鐘。
?
1.2 差分時鐘
差分時鐘是指通過管腳的P端和N端共同進來的,通常應(yīng)該到高頻或者精度 很高的場合,例如明德?lián)P的MP802、MP5620,以及各種核心板,基本上外面都有差分晶振,有差分時鐘的輸入。
如果是差分時鐘,又是如何約束呢?
注意下,差分信號在芯片上,肯定是占用了兩個管腳位置,但在代碼中不一定。在XILINX的頂層接口代碼中,差分時鐘會對應(yīng)兩個接口信號,分別 P端和N端;而對于ALTERA,頂層接口信號只有一個,不用區(qū)分出P端和N端,在管腳定義時,再來區(qū)分出P和N。
對于ALTERA的差分時鐘約束,其與單端輸入約束方法完全一樣。
對于XILINX的差分時鐘約束,只需要約束P端就可以了,即:
create_clock -name SysClk -period 10 -waveform {0 5} [get_ports Clk_p]
?
1.3 GT或恢復(fù)的時鐘
?
?
第三種是GT或恢復(fù)的時鐘,即使用了高速收發(fā)器的情形,最常見的就是光纖接口了。
在高速收發(fā)器管腳中,是沒有時鐘的,時鐘已經(jīng)嵌入到數(shù)據(jù)里面。接收的時候,我們使用高速收發(fā)器如GTX、GTY IP核接收數(shù)據(jù),并且從數(shù)據(jù)時提取出時鐘。這個恢復(fù)出來的時鐘就是此種情形,例如上圖中的GT模塊,就是FPGA內(nèi)部使用的一個IP核,其輸出了時鐘TXCLK。
在這種情況下,我們需要約束這個恢復(fù)出來的時鐘。按前面方式,同樣也是使用create_clock,定義時鐘周期、占空比等,但約束對象需要注意一下,不是通過get_ports,而是通過get_pins找到對象,該對象是恢復(fù)出的時鐘,如上圖中的GT/TXOUTCLK,即:
? ? create_clock -name txClk -period 6.667-waveform {0 5} [get_pins GT/TXOUTCLK]
? ?上面產(chǎn)生了一個名為txClk的約束,其對象為GT/TXOUTCLK,周期為6.667,即133M。
? ?對于get_ports和get_pins的區(qū)別,可以簡單認為,get_ports是FPGA頂層的接口,該接口是要連到FPGA芯片管腳上的;get_pins是模塊內(nèi)的輸出管腳。如果大家不清楚是用哪個,可以使用工具,工具會提醒您怎么找出這個信號來的。
? ?注意上面找到的是GT/TXOUTCLK,而不是圖中的TXCLK。這是因為TXCLK是例化的信號,有時候是找不出來的。這個時候,需要設(shè)計者找到GT模塊,再仔細辨識出時鐘信號是哪個,非??简炘O(shè)計師的經(jīng)驗。
?
第2節(jié) PLL等衍生時鐘
?
? ?上圖是時鐘Clk經(jīng)過內(nèi)部的MMCM時鐘管理單元,該時鐘管理單元在此基礎(chǔ)上倍頻或者分頻等,產(chǎn)生輸出時鐘CLKOUT0,該時鐘用于驅(qū)動REGA和REGB。在前面的介紹里,我們知道需要對Clk進行約束,使用的是create_clock命令。那么上圖中的CLKOUT0要不要約束呢?
? ?對于PLL和MMCM,一般VIVIDAO、ISE和QUARTUS工具是可以推導(dǎo)出該時鐘約束的,因為我們在生成IP核的時候,已經(jīng)設(shè)置了該時鐘的輸入和輸出 時鐘頻率、相位等信息,通過這些信息,工具就可以推導(dǎo)出時鐘約束。
? ?因此,對于XILINX可以不用約束PLL和MMCM產(chǎn)生的時鐘;對于ALTERA,也可以自動推導(dǎo)的,但需要添加如下命令,才會自動推導(dǎo):
derive_pll_clocks
? ?雖然工具可以自動推導(dǎo)PLL和MMCM產(chǎn)生的時鐘約束,但是其約束時鐘名是不受設(shè)計師控制或預(yù)見的。這會帶來什么問題呢?
? ?我們產(chǎn)生時鐘約束后,通常還會在基于此時鐘產(chǎn)生其他約束,例如下面是input delay的約束:
set_input_delay -clock sysclk -max 4 [get_ports ain]
? ?上面是input delay的約束,對象是ain,但注意看,-clock后面的sysclk是時鐘約束產(chǎn)生的時鐘名(注意是約束名,不是代碼中的時鐘信號),這說明input delay約束時,是依賴時鐘約束名的。
? ?如果由工具自動推導(dǎo)PLL和MMCM產(chǎn)生時鐘約束,那么名字就不知道,或者雖然知道了,但可能稍微改下代碼名稱又變了。這樣會導(dǎo)致依賴于此名字的其他約束,會存在失效而不知道的風險。
? ?因此,明德?lián)P建議對PLL和MMCM產(chǎn)生時鐘添加約束,確定時鐘名。
?
例如上面的電路,添加如下約束
create_clcok –name clk_200 –period 5 [get_ports Clk]
create_generated_clock ?-name my_clk [get_pins MMCM/CLKOUT0] \
????????????????????????????????????????????????????????????????????????????????????-source [get_pins MMCM/CLKIN]\
?????????????????????????????????????????????????? ??????????????????????????????? -master_clock clk_200
首先通過create_clock命令對輸入管腳Clk約束,周期為5,命名為Clk_200。然后通過create_geneated_clock對MMCM產(chǎn)生的CLKOUT0約束,命名為my_clk;約束對象為MMCM/CLKOUT0;通過-source表明來源于MMCM/CLKIN,即MMCM的輸入管腳;通過-master_clock表明其主時鐘是clk_200。
通過上面方法,就可以確定MMCM的時鐘名,已經(jīng)固定為my_clk,不會再變了。前面提及的input delay約束,就會變?yōu)槿缦拢?/span>
set_input_delay -clock my_clk -max 4 [get_ports ain]
?
第3節(jié) 自己分頻的時鐘
?
?
第三種就是自己分頻的時鐘。如上圖所示,CLK1經(jīng)過一個D觸發(fā)器,通過該觸發(fā)器二分頻產(chǎn)生了時鐘CLK2。
首先說明,明德?lián)P不推薦使用此方法來產(chǎn)生時鐘,我們建議全部使用PLL等來產(chǎn)生時鐘。如果確實要用到分頻時鐘時,那就要記得做時鐘約束。這種情況下要怎么進行約束呢?下面是推薦的約束方法。
?
?
?
create_clcok –name CLK1 –period 5 [get_ports CKP1]
create_generated_clock ?-name CLK2 [get_pins REGA/Q] \
???????????????????????????????????????-source [get_ports CKP1] –divide_by 2
?
首先通過create_clock產(chǎn)生對管腳CKP1的時鐘約束,周期定為5,名字為CLK1。
然后通過create_generated_clock產(chǎn)生二分頻后的時鐘約束,對象是REGA/Q,即D觸發(fā)器的輸出信號;然后要指示該時鐘來自于CKP1,通過-source來指定;最后還要說明頻率,通過-divide_by來說明幾分頻,-divide_by 2是表示二分頻,即CKP1時鐘的一半頻率。
注意的是,一定要通過-divide_by來指定頻率,因為工具無法從您的代碼中推導(dǎo)出頻率的。
強烈建議,分頻時鐘一定要約束,經(jīng)驗之談,沒有約束的話,時鐘是不穩(wěn)定的,會產(chǎn)生莫名其妙的問題的,這方面我們已經(jīng)吃過虧的。
?
第4節(jié) 總結(jié)與建議
好了,我們在這里再總結(jié)一下。
首先,本文將時鐘約束分了好幾種情況,制成了一個表。您可以根據(jù)實際情況,對照步驟表,從而制定自己需要在我約束。
其次,注意一下約束的優(yōu)先級。
自定義約束覆蓋工具推導(dǎo)的約束。前面講過,有些約束工具是可以推導(dǎo)出來的。如果自己又定義了該對象的約束,那么這個約束將覆蓋工具推導(dǎo)出來的約束,即定義的約束有效,推導(dǎo)出來的約束無效。
后定義的約束覆蓋先定義的約束。例如,在開始的時候定義了一個對CLK的約束,定義為100M,后面又有一個對CLK的約束,定義為200M,那么以哪個為準呢?那就以后面的為準,約束為200M。
但有時候需要對多個約束同時有效,即多個約束共存,那么可以在約束后面加上-add,以此表明不要覆蓋前面約束,而是共同有效。
?
下一篇文章,我們將具體探討“input delays約束”的內(nèi)容,講解各種情況下的時序約束方法。需要更多更詳細的資料,可以找作者了解。
審核編輯:湯梓紅
評論