1. 程式人生 > >用Quartus II Timequest Timing Analyzer進行時序分析 :例項講解

用Quartus II Timequest Timing Analyzer進行時序分析 :例項講解

一,概述

用Altera的話來講,timequest timing analyzer是一個功能強大的,ASIC-style的時序分析工具。採用工業標準--SDC(synopsys design contraints)--的約束、分析和報告方法來驗證你的設計是否滿足時序設計的要求。在使用者的角度,從我使用TimeQuest的經驗看,它與IC設計中經常用到的比如prime time,time craft等STA軟體是比較類似的。用過prime time或time craft的朋友是非常容易上手的。

在這一系列的文章裡,我將會拿一個DAC7512控制器的verilog設計作為例子,詳細講解如何使用TimeQuest進行時序設計和分析。

二,TimeQuest的基本操作流程

做為altera FPGA開發流程中的一個組成部分,TimeQuest執行從驗證約束到時序模擬的所有工作。Altera推薦使用下面的流程來完成TimeQuest的操作。

clip_image001

1. 建立專案並加入相關設計檔案

 不管做什麼事情,都需要有一個目標或者說物件。我們用TimeQuest做時序分析,當然也需要一個物件,這個物件實際上就是我們的設計。所以首先是要建立一個Quartus II的專案,並把所有需要的設計檔案都加入到專案中去。需要注意的一點是,這裡的設計檔案,不僅僅包含邏輯設計相關的檔案,也包含已經存在的時序約束檔案,當然,需要以synopsys Design Constraints(.sdc)的格式存在的。

2. 對專案進行預編譯(initial compilation)

    專案建立以後,如果從來沒有對專案進行過編譯的話,就需要對專案進行預編譯。這裡的預編譯是對應於全編譯(full compilation)來講的,我們可以理解為預編譯是對專案進行部分的編譯,而全編譯是對專案進行完整的編譯。做預編譯的目的是為了生成一個initial design database,然後我們可以根據這個database用Timequest採用互動的模式生成時序約束。實際上,對於小的設計,編譯時間並不是很長的話,完全可以不去區分預編譯和全編譯,需要編譯的時候,直接做全編譯就可以了,做全編譯的話,可以生成一個post-fit的database,完全可以給TimeQuest使用。

3. 向設計中新增時序約束

     在用TimeQuest做時序分析之前,必須要指定出對時序的要求,也就是我們通常所說的時序約束。這些約束包括時鐘,時序例外(timing exceptions)和輸入/輸出延時等。

    預設情況下,Quartus II 軟體會給所有沒有被下約束的時鐘都設定為1GHz。沒有任何的時序例外,也就是說所有的timing path都按1T去check。所有的輸入/輸出的延遲都按0來計算。這顯然不符合絕大多數設計的時序要求,所以有必要根據設計的特性,新增必要的時序約束。

    如上所述,時序約束主要包括三類:時鐘,時序例外和輸入/輸出延遲。其中時鐘和輸入/輸出延遲可以認為是在某種程度上增強時序設計的要求。而時序例外可以認為是在某種程度上降低時序設計的要求。比如說,僅僅設定一個時鐘的頻率為100MHz的話,這個時鐘域裡所有timing path都需要能工作在100MHz下。這顯然是增強了時序設計的要求。可是如果在這個時鐘域下面,有部分timing path是不需要做1T的check的,那麼就可以通過新增時序例外來避免對這些timing path做1T的check,即降低了時序設計的要求。

    在用TimeQuest做時序分析時,如果非常熟悉設計的構架和對時序的要求,又比較熟悉sdc的相關命令,那麼可以直接在sdc檔案裡輸入時序約束的命令。而通常情況下,可以利用TimeQuest GUI提供的設定時序約束的嚮導新增時序約束。不過要注意的是,用嚮導生成的時序約束,並不會被直接寫到sdc檔案裡,所以如果要儲存這些時序約束,必須在TimeQuest用write sdc的命令來儲存所生成的時序約束。

4. 執行完整的編譯

    在設定好時序約束以後,就需要對整個設計進行完整的編譯。在編譯過程中,軟體會優化設計的邏輯、佈局佈線等來儘可能滿足所有的時序約束。

    如果沒有新增時序約束,那麼軟體在編譯的時候,會按照預設的時序約束對設計進行優化,對於絕大多數的設計,都會報出來時序的問題,但因為預設的時序約束與設計本身的要求在絕大多數情況下,都是不同的,所以這些時序的問題也並不是設計本身的問題,並沒有太多的參考價值,而且很多初學者也不會注意到這個問題。這樣就把設計中很多潛在的時序問題給隱藏起來了,最終帶來的可能就是系統執行的不穩定,甚至是完全不能執行。

5. 驗證時序

    當完成編譯以後,我們就可以用TimeQuest來驗證時序了。在時序分析的過程中,TimeQuest會分析設計中所有的timing path,計算每一條timing path的延時,檢查每一條timing path是否滿足時序約束,最後按照positive slack或negative slack來報告時序分析的結果。其中negative slack就表示對應的timing path不滿足時序約束的要求(timing violation)。

    如果遇到有不滿足時序要求的情況,則可以根據對應的時序報告分析設計,確定如何優化設計使之滿足時序約束。時序約束有任何變化的話,都需要重新編譯設計。這個反覆的過程可以讓我們解決設計中的時序問題。

三,DAC7512控制器

    DAC7512是一個具有三線序列介面的DAC。我們基於FPGA用Verilog語言實現了一個簡單的DAC7512的控制器。下面是控制器的結構圖:

clip_image002

    DAC7512控制器由三個模組組成,PLL用來生成控制器所要的時鐘C0(25MHz)和C1(50MHz),其lock訊號用來做為控制器的非同步reset。da_data模組生成要送往DAC7512的資料,其中DA_DATA為資料,DA_DATA_EN為資料有效訊號,該模組使用C0時鐘,整個屬於C0時鐘域。DAC7512模組用於將DA_DATA轉換成符合DAC7512介面標準的序列資料並送給DAC7512,要用到C1(50MHz)和DA_SCLK(C1二分頻,25MHz)兩個時鐘。

    DAC7512控制器一共有四個輸入輸出埠。CLK_IN為PLL的基準時鐘,為25MHz。DA_DIN,DA_SCLK和DA_SYNC為三線串列埠,都為輸出埠。

    由於C0,C1是由同一個PLL輸出的,DA_SCLK是由C1經二分頻得到的,三者之間是同步的,處於同一個clock group中。

    DAC7512模組的詳細設計資料可參照本部落格中 “FPGA設計中DAC7512控制的Verilog實現” 的文章。不過要注意一點的是,在序列總線上,DA_DIN是在DA_SCLK的下降沿有效的。把DA_DIN設計為C1時鐘域的訊號,並控制其值只在DA_SCLK為高電平的時候發生變化。這樣可以把DA_DIN與DA_SCLK之間的時序要求轉換為DA_DIN在C1時鐘域的時序要求,細節我們會在下面介紹。

四,用TimeQuest對DAC7512控制器進行時序分析 

 在對某個物件下時序約束的時候,首先要能正確識別它,TimeQuest會對設計中各組成部分根據屬性進行歸類,我們在下時序約束的時候,可以通過命令查詢對應類別的某個物件。

     TimeQuest對設計中各組成部分的歸類主要有cells,pins,nets和ports幾種。暫存器,閘電路等為cells;設計的輸入輸出埠為ports;暫存器,閘電路等的輸入輸出引腳為pins;ports和pins之間的連線為nets。具體可以參照下圖(此圖出自Altera Time Quest的使用說明)。

clip_image002

      下面我們按照本文第二部分用TimeQuest做時序分析的基本操作流程所描述的流程對DAC7512控制器進行時序分析。

       建立和預編譯專案的部分相對簡單,涉及到的也只是QuartusII的一些基本操作,這裡我們就不再做具體的敘述。主要介紹如何向專案中新增時序約束和如何進行時序驗證。首先建立一個名稱與專案top層名字一致的sdc檔案,然後按照下面的步驟新增時序約束。

1. 建立時鐘

     新增時序約束的第一步就是建立時鐘。為了確保STA結果的準確性,必須定義設計中所有的時鐘,並指定時鐘所有相關引數。TimeQuest支援下面的時鐘型別:

a) 基準時鐘(Base clocks)

b) 虛擬時鐘(Virtual clocks)

c) 多頻率時鐘(Multifrequency clocks)

d) 生成時鐘(Generated clocks)

我們在新增時序約束的時候,首先建立時鐘的原因是後面其它的時序約束都要參考相關的時鐘的。

基準時鐘:

     基準時鐘是輸入到FPGA中的原始輸入時鐘。與PLLs輸出的時鐘不同,基準時鐘一般是由片外晶振產生的。定義基準時鐘的原因是其他生成時鐘和時序約束通常都以基準時鐘為參照。

    很明顯,在DAC7512控制器中,CLK_IN是基準時鐘。我們用下面的命令來建立這個基準時鐘:

create_clock -name CLK_IN -period 40 -waveform {0 20} [get_ports {CLK_IN}]

    其中,create_clock是建立時鐘的命令,後面是命令的各種選項。其中-name CLK_IN選項給出了時鐘的名字,即CLK_IN。-period 40給出了時鐘的週期,即40ns。-waveform {0 20}給出了時鐘的佔空比,即50/50。最後的[get_ports {CLK_IN}] 是巢狀的tcl命令,給出了CLK_IN對應的port,實際上也就是CLK_IN的輸入引腳。

    在sdc檔案裡新增上述命令後,在quartusII裡編譯設計,然後通過tools –> TimeQuest Time Aanlyzer命令開啟TimeQuest。在TimeQuest的Tasks視窗,找到Report Clocks,雙擊之,TimeQuest就會在右邊主視窗給出設計中已成功新增的時鐘資訊。如下圖所示,可以看到CLK_IN,其型別為基準時鐘,週期為40ns,頻率為25MHz,targets項為CLK_IN,即表示這個時鐘是連線在CLK_IN埠上的。這說明上面create_clock的命令已經在設計中正確建立了時鐘CLK_IN。

clip_image004

       實際上對於create_clock命令,我們可以通過quartus II的幫助系統(http://quartushelp.altera.com/current/),查詢它的語法。在QuartusII的幫助裡,可以查詢到:

Syntax

create_clock [-h | -help] [-long_help] [-add] [-name<clock_name>] -period <value> [-waveform <edge_list>] [<targets>]

    另外,幫助系統裡有很詳盡的關於該命令的描述,並且給出了各種使用的範例。不僅僅是這一個命令,所有的命令都可以在幫助系統裡找到。如果看到一個陌生的命令,或者不知道命令該如何使用,那麼最好的辦法就是在幫助系統裡查詢該命令。

PLL時鐘:

     上面我們建立了基準時鐘。下面我們建立PLL輸出的時鐘。

     在Altera的FPGA中,PLL電路是通過ALTPLL的IP庫被新增到設計中的。下圖是一個典型的ALTPLL的結構圖。

clip_image005

        從圖上可以看到,當我們選定了基準時鐘和PLL的引數以後,PLL的輸出c0和c1的引數就隨之確定了。所以在QuartusII環境下,可以通過一個簡單的命令讓軟體自動生成PLL輸出的時鐘的時序約束。

derive_pll_clocks

     這個命令會自動建立PLL輸出的C0和C1的相關時序約束。同樣的,在sdc檔案裡新增該命令,然後編譯,在TimeQuest裡檢視時鐘資訊。如下圖所示,derive_pll_clocks在系統裡添加了兩個時鐘,PLL1|altpll_component|auto_generated|pll1|clk[0]和PLL1|altpll_component|auto_generated|pll1|clk[1]。可以看出,時鐘是按“PLL層次結構+時鐘埠名字”的規則命名的。時鐘的型別為created clock,週期頻率是在PLL裡設定好的。duty_cycle為50/50。Clock source為PLL1|altpll_component|auto_generated|pll1|inclk[0],實際上就是我們之前定義的CLK_IN。

clip_image007

       用derive_pll_clocks命令建立PLL相關的時鐘很是方便,但不好的地方就是,時鐘的命名太過複雜,我們在新增與此時鐘相關的時序約束時,就必須用這種名字很長的時鐘,容易出錯,且可讀性也差。所以建議還是採用create_generated_clock命令來建立PLL的時鐘。

       create_generated_clock命令的語法如下,可以從quartusII的幫助系統裡找到每個引數的詳細解釋。

Syntax

create_generated_clock [-h | -help] [-long_help] [-add] [-divide_by <factor>] [-duty_cycle <percent>] [-edge_shift<shift_list>] [-edges <edge_list>] [-invert] [-master_clock<clock>] [-multiply_by <factor>] [-name <clock_name>] [-offset<time>] [-phase <degrees>] -source <clock_source> [<targets>]

      可以用下面的命令來建立PLL的兩個時鐘C0和C1。我們把時鐘命名為CLK25M和CLK50M,source clock為CLK_IN。

create_generated_clock -name CLK25M -source CLK_IN -duty_cycle 50.000 -multiply_by 1 -master_clock {CLK_IN} [get_pins {PLL1|altpll_component|auto_generated|pll1|clk[0]}]

create_generated_clock -name CLK50M -source CLK_IN -duty_cycle 50.000 -multiply_by 2 -master_clock {CLK_IN} [get_pins {PLL1|altpll_component|auto_generated|pll1|clk[1]}]

      用這兩個命令建立的時鐘與derive_pll_clocks命令建立的時鐘的本質是一樣的,只是給時鐘定義了不同的名字。當然我們也可以用derive_pll_clocks中對時鐘的命名方式來使用create_generated_clock命令。

    同樣的,可以按照上面的方法,在TimeQuest裡檢視建立時鐘的結果,如下圖所示。

clip_image009

       到此為止,我們建立了PLL的基準時鐘以及PLL輸出的兩個時鐘CLK25M和CLK50M。

DA_SCLK時鐘:

       在TimeQuest的Tasks窗口裡,選擇Report Unconstrained Paths命令,TimeQuest會報告出所有需要下約束但實際並沒有約束的情況。在Report裡的Unconstrained Path列表下,我們可以檢視這個報告。雙擊Clock Status Summary,就可以在主視窗看到所有時鐘的情況。見下圖,很明顯,軟體辨識出DAC7512模組下的DA_SCLK為時鐘訊號,但是我們並沒有對該時鐘新增約束,所以用紅色將這個時鐘顯示了出來。下一步我們就來建立這個時鐘。

clip_image011

        DA_SCLK是用CLK50M通過二分頻電路得到的。所以其source clock為CLK50M。但是,我們在使用create_generated_clock命令建立該時鐘的時候,在-source的引數裡,卻不能直接使用CLK50M,而必須使用CLK50M所對應的pin,即PLL1|altpll_component|auto_generated|pll1|clk[1]。 這主要是因為-source引數只支援pins,ports和registers。

       DA_SCLK是由CLK50M通過二分頻電路生成的,其程式碼如下:

reg DA_SCLK;

always @(posedge CLK50M or negedge RESET)

begin

if(~RESET)

DA_SCLK <= 1'b0;

else

DA_SCLK <= ~DA_SCLK;

end

     可以看到,本質上DA_SCLK為一個暫存器的輸出,所以使用get_registers命令獲取DA_SCLK。DA_SCLK是由CLK50M經二分頻電路生成的,所以-divide_by的引數應該是2。

      綜上所述,用下面的命令建立DA_SCLK:

create_generated_clock -name DA_SCLK -divide_by 2 -source [get_pins {PLL1|altpll_component|auto_generated|pll1|clk[1]}] [get_registers {DAC7512:DAC7512|DA_SCLK} ]

     到此為止,DAC7512控制器中所有4個時鐘都建立好了。如下圖所示:

clip_image013

      我們再看TimeQuest中Unconstrained Paths中clock Status Summary,就會發現,所有的時鐘都已經被添加了約束。

clip_image015

上面已經把DAC7512控制器中所有的時鐘都建立好了。下面我們再額外討論一下關於時鐘屬性方面的一些問題和在做時序分析時的處理方法。

     對於具有單一時鐘的系統,設計和時序分析都相對簡單。但是現在很多設計都有多個甚至幾十個時鐘乃至更多的時鐘。比如說DAC7512控制器,在設計中用到的時鐘實際上是有3個,CLK25M,CLK50M和DA_SCLK。在對多時鐘設計進行時序分析的時候,我們首先要搞清楚各時鐘之間的關係。

     當設計中有多個時鐘時,時鐘之間可能存在三種關係,分別是同步,非同步和互斥。

     如果兩個或者多個時鐘具有相同的source和固定的相位差,那麼這些時鐘是同步時鐘。在DAC7512的控制器裡,CLK25M,CLK50M和DA_SCLK的source都是CLK_IN,所以可以認為他們三個是同步的。

     如果兩個或者多個時鐘之間沒有任何關係,則稱之為非同步時鐘。比如說CLKA來源於晶振A,而CLKB來源於其他系統的輸入,CLKA和CLKB就為非同步時鐘。對於非同步時鐘來講,兩個時鐘域的時鐘沿有可能在任意時刻出現,相互之間不會有任何關係。如果一條timing path的起始點是在CLKA,而終點在CLKB,即這條timing path跨越了CLKA和CLKB兩個時鐘域,那麼STA軟體是不會對該timing path做分析的。實際上這等同於在這兩個時鐘之間設定了一條false path。

     如果兩個時鐘不會相互作用,那麼稱這兩個時鐘為互斥的。舉個例子來講,PCIE GEN2可以工作在GEN1和GEN2兩種模式,在GEN1模式下,時鐘為125MHz,在GEN2的模式下,時鐘為250MHz,但在某一個特定時間裡,時鐘只可能為125MHz或者250MHz,這兩個頻率的時鐘不會共存,相互之間也不會有相互作用。

    下圖給出了時鐘的三種關係的例子。

clip_image002

     做時序分析時,在建立好所有的時鐘後,需要定義這些時鐘之間的關係。我們可以把同步時鐘放到一個group中,然後在定義時鐘之間的關係時,可以使用group來定義。在預設情況下,TimeQuest認為設計中所有的時鐘都是同步的,並把所有的時鐘都放在同一個group裡。如果設計中有非同步時鐘,就需要用命令把非同步時鐘分組並定義出來。

     在TimeQuest裡,我們用set_clock_groups來定義時鐘的group。下面是命令的語法,更詳細的說明請參照quartusII的幫助系統。

Syntax

set_clock_groups [-h | -help] [-long_help] [-asynchronous] [-exclusive] -group <names> [-logically_exclusive] [-physically_exclusive]

     在DAC7512控制器裡,CLK25M,CLK50M和DA_SCLK三個時鐘是同步時鐘。預設情況下,它們已經被軟體放到了同一個group裡,所以我們不需要對其做任何的處理。

    但假設CLK25M屬於一個group,而CLK50M和DA_SCLK屬於另外一個group,我們就要用set_clock_groups命令把二者設為非同步時鐘,命令如下:

set_clock_groups -asynchronous -group {CLK25M} -group {CLK50M DA_SCLK}

     我們對比一下把CLK25M設定為CLK50M的非同步時鐘前後TimeQuest對時序分析的處理情況來看這個命令的作用。下面是在新增這個命令前後TimeQuest中Report clock transfer的結果。

在沒有新增這個命令前,軟體預設三個時鐘都是同步時鐘,所以會分析並報告出三個時鐘之間所有的timing path。

clip_image004

       在新增這個命令以後,軟體認為CLK25M和CLK50M/DA_SCLK是非同步時鐘,所以就直接將CLK25M和CLK50M/DA_SCLK之間的timing path設為false path。不再做更多的分析。

clip_image006

        那如果我們假設CLK25M和CLK50M是互斥時鐘的話,又會是什麼情況呢?用下面的命令將CLK25M和CLK50M設為互斥時鐘:

set_clock_groups -exclusive -group {CLK25M} -group {CLK50M}

       還是看TimeQuest中Report clock transfer的結果,可以發現CLK25M和CLK50M之間的timing path都被設定為false path了。

clip_image008

     再看一下關於Clock uncertainty的知識

     簡單的說,Clock uncertainty是指時鐘邊沿實際到達時間與理論到達時間之間的差異和變化。在做時序分析的時候,是需要加上clock uncertainty來計算timing path的延時的。Clock uncertainty的大小是比較難確定的,在ASIC設計中,clock uncertainty的值往往要根據所使用的工藝,以往專案的經驗等各種因素來決定。但在FPGA的設計中,我們能參考的資料不多,特別是對於PLL輸出的時鐘,因為我們對PLL本身的引數並不是非常的瞭解,所以很難給出合適的clock uncertainty的值。

     在FPGA設計中定義PLL的時候,我們要定義參考時鐘的精度,這會直接影響到PLL輸出時鐘的clock uncertainty的值。如下圖所示,25.000MHz即為輸入基準時鐘的精度。

clip_image009

      有了輸入時鐘的精度,TimeQuest會根據PLL本身的屬性,自動計算出各輸出時鐘的uncertainty值。如果要在設計中由軟體加入clock uncertainty的值,可以使用下面的命令:

derive_clock_uncertainty

     除非你對系統的時鐘有充分的理解並確切知道時鐘的屬性,否則不建議使用set_clock_uncertainty命令直接定義FPGA中各時鐘的uncertainty屬性。推薦使用derive_clock_uncertainty命令由軟體自動計算並新增。