天天看點

[轉]TimeQuest限制外設之詭異的Create Generated Clocks用法

轉自:http://www.cnblogs.com/shengansong/archive/2012/05/17/2505830.html

最近在altera FPGA裡設計一個外設的驅動子產品,子產品本身邏輯很簡單如下圖所示,但是子產品和外設之間的時序限制問題搞的很頭疼,今天先講講總結的一些Timequest下外設限制方法,特别是那毫無使用者體驗而言的Create Generated Clocks用法。

[轉]TimeQuest限制外設之詭異的Create Generated Clocks用法

要讓外設正确接收FPGA發出的資料,需要dout和clkout滿足外設的建立保持時間,如下圖所示。

[轉]TimeQuest限制外設之詭異的Create Generated Clocks用法

時序分析是基于源reg的Tco、目的reg的Tsu,源reg到目的reg的Tdelay路徑延遲以及到兩個reg的clk skew計算出來的,現在Timequest不知道外設接收reg和時鐘輸入端的延遲參數,無法分析,還需分若幹步配置:

1.使用Create Clocks建立系統時鐘sysclk

create_clock -name {sysclk} -period 20.000 -waveform { 0.000 10.000 } [get_ports {sysclk}]

Timequset裡的所有時鐘都需要手動設定,首先設定系統時鐘,後面的時鐘都要基于這個時鐘才能生成。

2.使用Create Generated Clocks建立輸出時鐘clkout

外設的時鐘源于FPGA的輸出port clkout,如果不建立時鐘,timequest隻會把clkout當作一個普通的輸出引腳,時序分析器認為目的reg缺少驅動時鐘,無法分析。Timequest中将通過倍頻、分頻或者移相等生成的時鐘都歸為Generated Clocks,你可以使用Create Clocks建立試一下,不會提示建立失敗,但是在最後的時序分析裡不會加入clkout的clock network delay,Timequest沒有你想象的那麼智能,知道clkout是從一個分頻子產品輸出,自動加入子產品延遲分析,它不知道這些。是以還是使用Create Generated Clocks來建立吧,先填寫源時鐘sysclk,再填寫生成時鐘和源時鐘的關系,2分頻,最後指定target 生成時鐘到clkout引腳,這三個步驟看似沒問題,結果卻是建立失敗,提示找不到sysclk到clkout之間的路徑,如下所示。

Warning: No paths exist between clock target "clk_out" of clock "clkout" and its clock source. Assuming zero source clock latency.

但是sysclk到clkout明明是有路徑的啊,之間的邏輯也很簡單,就是一個二分頻關系,bdf圖如下所示。

[轉]TimeQuest限制外設之詭異的Create Generated Clocks用法

clk_div子產品的代碼如下:

reg clk_div;

always @(posedge clk or negedge rset_n)

begin

    if(!rset_n)

        clk_div <= 0;

    else

        clk_div <= ~clk_div;

end

嘗試了很多方法都無效,最終實驗成功了一種自認為很别扭的方法,“曲線救國”分兩步走:

首先Create Generated Clocks 從引腳sysclk 到 寄存器clk_div

create_generated_clock -name {clk_div_r} -source [get_ports {sysclk}] -divide_by 2 -master_clock {sysclk} [get_registers {clk_div:inst4|clk_div}]

再Create Generated Clocks 從寄存器clk_div到輸出引腳clk_out 

create_generated_clock -name {clkout} -source [get_registers {clk_div:inst4|clk_div}] -master_clock {clk_div_r} [get_ports {clk_out}]

這才把clk_out設定為和sysclk關聯的輸出時鐘。

3. 用set output delay 設定基于clkout時鐘的輸出dout延遲。

set_output_delay -add_delay  -clock [get_clocks {clkout}]  5.000 [get_ports {dout}],這句話在源reg和目的reg之間搭建起一座橋梁,實作兩個作用:

1.告訴分析工具,clkout是目的reg的驅動時鐘(但是前提是clkout需要被Timequest認為是個時鐘),dout是目的reg的資料源,分析工具才能計算出路徑的clk skew(clkout的clock network delay - sysclk的clock network delay);

2.告訴了分析工具外設reg的建立時間Tsu和路徑延遲Tdelay,這兩個參數之和其實就是輸出延遲,分别源于外設資料手冊和PCB闆的走線延遲。

4.設定set max delay和set min delay

如果不需要更嚴苛的限制,不設定這兩個參數也可以。經過前三步,時序分析器已經知道了源reg和目的reg的時鐘頻率,系統會預設使用時鐘頻率分析,既最大延遲為時鐘周期Tclk,最小延遲為0。這裡的set max delay限制Tco和clk skew為了滿足外設的建立時間,使(Tclk + clk skew)-(Tco+Tdelay) > Tsu,set min delay 限制Tco和clk skew滿足外設的保持時間,(Tco+Tdelay) - clk skew > Th。

5.設定多周期限制

由于本例的特殊性,源時鐘是目的時鐘的兩倍,需要多時鐘限制設定,由篇幅所限,下次再細講。

最後可以在Report Timing的Registers to Outputs的setup和hold裡看到時序餘量分析了。

回顧限制的整個過程,最鬧心的就是第二步Create Generated Clocks了,可能一直受altera裡的pll設定影響,隻要設定源時鐘,填好輸出輸入時鐘關系,pll就可以用了,到了Timequest裡的生成時鐘設定,我也想當然的認為,clkout是由sysclk生成變化而來,源裡面隻要填sysclk,關系填好就肯定沒問題了,但是結果并非這麼簡單。

再回到第二步,再嘗試從sysclk直接Create Generated Clocks指定到輸出時鐘clkout,發現除了找不到sysclk和clkout之間的路徑之外還有一個警告

Warning: Node: clk_div:inst|clk_div was determined to be a clock but was found without an associated clock assignment。

警告clk_div被設定為了時鐘,但是沒有指定關聯的源時鐘即沒指定clk_div是由哪個時鐘生成的,從這個警告推理:我設定的Generated 時鐘是clkout,而clkout是由clk_div驅動的,是以Timequest也将clk_div認為是一個時鐘路徑node,但是我隻告訴了Timequest clkout的源時鐘是sysclk,而沒有告訴它clk_div的源時鐘是哪個,是以建立失敗,雖然從程式顯而易見源也是sysclk,看來我高估了TimeQuest的智商,按照上述的“兩步走”方案,第一步就是告知clk_div的源時鐘是sysclk,第二步再生成基于clk_div的clkout就ok了

推測Timequest中對Creat Generated Clocks分析過程是這樣的:從最終的target Clock端口往回分析,尋找這個時鐘路徑上的net寄存器,看其是否有關聯時鐘,如果有,看是否已經指定了,如果指定了則繼續反向分析直到源時鐘,如果沒有則提示建立失敗。為了驗證這個推測,再級聯一個分頻子產品clk_div如下圖所示。

[轉]TimeQuest限制外設之詭異的Create Generated Clocks用法

此時該如何建立基于sysclk的輸出時鐘clk_out呢,從clk_out管腳傳回分析,clk_out由ints5|clk_div驅動,ints5|clk_div的關聯時鐘是inst4|clk_div,inst4|clk_div的關聯時鐘是sysclk,是以要分三步建立:

首先建立基于sysclk的inst4|clk_div。

create_generated_clock -name {clk_div_r} -source [get_ports {sysclk}] -divide_by 2 -master_clock {sysclk} [get_registers {clk_div:inst4|clk_div}] 

再建立基于inst4|clk_div的inst5|clk_div。

create_generated_clock -name {clk_div_rr} -source [get_registers {clk_div:inst4|clk_div}] -divide_by 2 -master_clock {clk_div_r} [get_registers {clk_div:inst5|clk_div}] 

最後建立基于inst5|clk_div的clk_out。

create_generated_clock -name {clkout} -source [get_registers {clk_div:inst5|clk_div}] -master_clock {clk_div_rr} [get_ports {clk_out}] 

驗證結果,少了上述任何一步都無法得到正确的輸出時鐘,比如用Create clk 建立inst4|clk_div 取代第一步,雖然也可以生成clk_out,但最終的輸出延遲會減小。

多數工程中,使用分頻子產品輸出時鐘的做法并不多,更多的是使用pll,我又嘗試了下使用PLL産生一個外部時鐘,PLL的源為sysclk,仍然無法直接Create Generated Clocks從sysclk到clk_out,而是首先derive_pll_clocks将所有的PLL輸出都設為時鐘,再Create Generated Clocks從PLL的時鐘輸出寄存器到clk_out才可以。

繼續閱讀