時序優化學習筆記
1.適當進行邏輯複製以優化設計速度(減少扇出)
邏輯複製是指當某個訊號扇出比較大時,會造成該訊號到各個目的邏輯節點的路徑變得過長,從而成為設計中的關鍵路徑,為了解決這個問題,可以通過在書寫程式碼時對該訊號進行復制,已達到分擔該訊號扇出過多的目的。
例如: assign a=b &c; 而在程式碼中多處用到a,可以改寫為如下
assign a1=b&c;
assign a2=b&c;
在程式碼中使用a1 a2來分擔a,從而減小了a的扇出,縮短佈線延時
2.通過減少關鍵路徑上的組合邏輯級數來優化時序
FPGA邏輯設計中時序路徑上的組合邏輯都會給路徑增加延時,從而影響設計效能的往往只有幾條關鍵的路徑而已,所以可以通過減少關鍵路徑上的組合邏輯單元數來減小該路徑上的延時,從而達到優化的目的。關鍵路徑重組是常用技術,多用於關鍵路徑由多個路徑組合而成的場合,而且這些被組合的路徑之間又可以重組互相之間的相互順序。
上圖紅色部分所示,這行程式碼需要在一個週期內完成加法,判斷大小和與三個操作,組合邏輯的級數太大,成為了關鍵路徑,
對於時序有一定的改善作用。
3. 適當地較少資料的位寬。
比如在上面程式碼中如果tx_cnt最大不超過2048,則可以將
signal tx_cnt: (15 downto 0) std_logic_vector ; 改為
signal tx_cnt: (10 downto 0) std_logic_vector ;
4. 充分利用二進位制的優勢,比如
通過判斷計數器的暫存器counter的最高位來進行狀態的跳轉。
5. ddr3的前後通常有RAM作為資料的快取,如果ram離ddr3的路徑太長,容易導致時序變差。
解決辦法有:
A,將塊ram變成分散式ram,因為塊ram是在fpga中是固定位置。
B, 多打幾拍,相當於在路徑中間設定幾個加油站。
STA(Static Timing Analysis,即靜態時序分析)在實際FPGA設計過程中的重要性是不言而喻的,其作用是:
1. 幫助分析和驗證一個FPGA設計的時序是否符合要求;
2. 指導fitter(佈線綜合器)佈局佈線出符合要求的結果;
啟動沿:資料被launch的時鐘邊沿;也就是說,每一個啟動沿,一般都會產生一個新的資料!
鎖存沿:資料被latch的時鐘邊沿;也就是說,每一個鎖存沿,都會有一個新的資料被儲存!
對於如上圖所示的級聯的暫存器電路而言(忽略上一級觸發器輸出到下一級觸發器輸入之間的邏輯關係),一般藍色的上升沿作為第一個觸發器的啟動沿,而紅色的上升沿(一般都是緊跟著啟動沿後的有效邊沿)。所以說:藍色的啟動沿之後由REG1輸出有效資料,並在紅色的邊沿被鎖存進REG2並輸出到下級。
上述的鎖存沿會將資料儲存下來,但是必須要滿足一定的條件:
建立時間Tsu:在時鐘有效沿之前,資料必須保持穩定的最小時間;
保持時間Th:在時鐘有效沿之後,資料必須保持穩定的最小時間;
這就相當於一個視窗時間,在有效邊沿的視窗時間內,資料必須保持穩定;這裡的時鐘訊號時序和資料訊號時序,都是暫存器實際感受到的時序;什麼事實際感受到的,下面會繼續分析;
1.3 資料到達時間(DAT:data arrival time)
所有的訊號在FPGA內部傳播都會有延時,包括時鐘訊號、資料訊號(實際上不該如此可以的區分這兩種訊號,在一定條件下,這兩個訊號可能可以相互轉換,這個是題外話了),也就是說,從訊號的發出點到訊號的接收點,會存在一個延時,這個延時可能是因為FPGA內部空間分佈所致,也有可能是因為組合邏輯造成,這裡不再深究;
正如上圖所示,在計算資料到達時間時,一般都會存在3個延時:
1. Tclk1:時鐘訊號從起點(一般是PLL輸出或者時鐘輸入引腳)到達啟動暫存器(或說啟動觸發器)的相應clk埠所耗的時間;假如CLK是由PLL發出的時鐘訊號(稱之為源時鐘),這個訊號經過FPGA內部的“連線”最終來到了REG1(啟動觸發器)的clk端,所以此時在REG的clk1處也會有周期性的時鐘訊號REG1.CLK(如圖所示);可以看到,此時的CLK(源時鐘)和REG1.CLK實際上有個(相位差)時間差,這個時間差就是Tclk1;
2. Tco:啟動暫存器內部延時,是暫存器REG1感受到有效的上升沿後,到資料真正從從REG1的Q輸出之間延時;請注意:上述所謂的有效的上升沿,就是REG1.CLK,而不是CLK;所以實際的有效資料輸出的時序如上圖的REG1.Q;
3. Tdata:資料從上級暫存器輸出Q(經過所有其他組合邏輯以及FPGA內部走線)到下級暫存器的資料輸入D之間的延時;如圖所示,資料從從REG1的Q流向了REG2的D,所以REG2.D實際感受到的資料時序是REG2.D;
假如將上圖中的launch Edge作為時間0點,將一些列的延時累加,所得結果稱之為資料到達時間,DAT:
DAT=啟動沿+Tclk1+Tco+Tdata;
分析方法同上,需要計算資料建立時間,也需要兩個延時:
1. Tclk2,不同於上述的Tclk1,這個延時是時鐘從起點(一般是PLL或者時鐘輸入引腳)到鎖存觸發器之間的延時;如上圖所示,REG2實際感受到的時鐘來自於其本身的clk引腳,而不是源時鐘CLK,他們之間存在一個延時,即Tclk2;所以REG2實際感受到的時鐘,實際上是上圖的REG2.CLK;
2. Tsu:上面分析過了,每一個數據被鎖存都要滿足建立時間和保持時間,Tsu就是建立時間,也就是在REG2實際感受到Latch Edge時,資料如果需要被正確鎖存,就必須提前Tsu的時間來到REG2的D;
綜合時鐘走線延時Tclk2以及Tsu,我們得到了資料建立時間DRTsu:
DRTsu=鎖存沿+Tclk2-Tsu。也就是說在DRTsu時刻之前,資料必須已經有效且穩定
即DRTh=鎖存沿+Tclk2+Th;也就是說,資料在DRTh時間之前必須保持住不變;
如上圖所示,在0時刻(Launch edge),源時鐘CLK說,“啊,我要產生一個新的資料”,但是這個命令(啟動沿)並沒有馬上傳達到REG1,而是有個延時Tclk1。所以在Tclk1時刻,REG1終於聽到了(感受到了有效的時鐘上升沿,就是啟動沿)老大的命令,就開始準備,他憋了一會兒,又延時了Tco,終於產生了資料(REG1.Q上有了valid data);這個有效資料也是慢吞吞的來到了他的終點,又浪費了Tdata。最終在Tclk1+Tco+Tdata時間後,REG2得到了這個資料;別以為REG2得到這個資料就完事了,REG2也是個傲嬌的娃,怎麼個傲嬌法,下面繼續分析;老大CLK在0時刻傳送了啟動沿之後,休息了一個時鐘週期,在Latch edge時突然想起來,剛才讓REG1發出的資料,REG2要接受啊,不然就浪費了,於是乎他又對REG2下達了命令,新資料要來了,準備好接受!但是這個命令也不是馬上就到了REG2的耳中,而是經過了Tclk2的時間。等到REG2接收到命令後(實際感受到了有效的Latch Edge),他就看看自己家門口沒有資料已經來了(檢查REG2.D是否有資料),同時要看看這個資料是不是符合他的胃口的(滿足鎖存的條件),他要求資料必須在他接收到老大命令的時候已經等了Tsu時間(資料建立時間),由要求這個資料在他家門口不能早退,必要再保持Th時間(資料保持),如果都滿足了,REG2就開心的接受了這個資料,反之,他就會覺得,REG1準備的資料太懶惰了(沒有提前Tsu時間到達),又或者性子太急(沒有多逗留th),一概不收!
所以這裡涉及到兩個要求,第一個就是建立時間裕量:
正如上圖所示Setup Slack=DRTsu-DAT。
如果Setup Slack為正,則說明資料在規定的時間內達到了目標。反之,則認為資料並沒有在規定的時間達到目標,此時REG2鎖存的資料很有可能是亞穩態;
如上所述,hold slack = DAT – DRTh
如果為正,則認為資料在被鎖存的時候有足夠多的穩定時間,是有效的。反之則認為資料有誤或者資料可能是亞穩態;
小結:
理解了上面的7個概念,就明白了:如果時鐘頻率過快或者資料延時太大,都會導致錯誤的時序。在FPGA內部暫存器到內部暫存器之間,所有的延時都是建立在時序模型上的,如slow和fast,這些模型從兩個極端工作情況來分析FPGA能否正常工作;只要滿足這兩個工況,則FPGA在其他環境下都能滿足時序!
現有一塊ADC連線到FPGA上,需要在FPGA上實現高速資料的讀取,那麼第一步自然就是完成可靠的硬體連線,其中需要注意的是:
1. 注意訊號的完整性,儘可能的避免邊沿退化;這兩區分兩個概念:
i. 高速訊號,指的是訊號翻轉,由高電平到低電平或者反之所耗得時間非常小;可能一個1MHz的TTL訊號或者LVDS訊號,只要邊沿足夠陡,那也算是高速訊號!
ii. 高頻訊號,一般指的是週期性訊號的週期時間足夠小;
iii. 也就是說高速訊號不一定是高頻的;數字訊號一般都是高速訊號,所以必須要保證其邊沿的完整性,如果邊沿發生退化或者變形,那麼將相當於加入了額外的時序上的偏差;
2. 保持時鐘訊號和資料訊號路徑等長,不管是單端還是差分訊號,需要用繞線等形式迫使兩類線幾乎等長;這個在之前的時序分析中非常重要,如果真的不能夠做到等長,甚至差的還挺多的,也必須提前獲得該差值,並將則合成時間差,在後面的時序分析中將會有用;
保證以上兩點後,就可以著手時序的分析了,那麼首先我們會得到目標器件ADC的時序,如下圖所示:
從上圖中我們首先得到幾個資訊:
1. 這是個同步時序,由兩類訊號組成,時鐘訊號DCO和資料訊號FCO以及D(忽略它們是差分訊號,下面的分析會把它畫成單端訊號,簡化好畫一點)
2. 這是個DDR訊號,DDR指的是資料是同步於時鍾訊號的上升、下降邊沿,所以該類同步訊號需要引入虛擬時鐘概念,後面繼續介紹;
3. 訊號是不是邊沿對齊,而是偏移了90度!也就是說DCO邊沿翻轉後,資料訊號沒有第一時間翻轉,而是延後了四分之一個週期,這是高速訊號慣用的伎倆,後面會發現,這個延時讓時序更好分析;
將FCO訊號和D訊號的實際意義扔一邊,在設計者看來,他們都僅僅是資料而已,將上面的時序圖簡化成下圖:
可以看到,實際上所有的資料訊號都是同步於DCO的邊沿,但是並不是對齊的,而是相差了90度,同時還是個DDR系統(上下邊沿都是Launch Edge)
一般來說DDR系統會引入一個虛擬時鐘的概念,就是說DCO是實際存在的時鐘,設計和虛構出一個2倍頻的DCOX2時鐘,並將其相移180度以後,我們重新得到了下圖:
引入虛擬時鐘後,我們重新規劃Launch Edge,將其規劃到DCOX2-Shift180的上升沿,其所對應的的Latch Edge仍然還是在DCO上。
到目前為止,我們已經很清楚的規劃了ADC的時鐘和資料輸出的關係,至於如何用SDC語言描述,見下文;接下來就要考慮到這些訊號實際上是各自經過PCB走線後來到FPGA的引腳,從FPGA引腳由進入到FPGA內部,然後又經過各自的FPGA內部走線延時以後來到了他們目標的暫存器,如下圖所示:
從上圖可以獲知:
1. ADC內部看起來有一個源時鐘,這個源時鐘我們不用管怎麼產生,它分成了兩路,其中一路經過倍頻+移相後觸發了ADC上的REG0(就是說其上升沿作為Launch Edge),另一路直接輸出到ADC引腳DCO;
2. 資料由REG0產生後輸出至ADC引腳D,經過一個延時後來到FPGA的相應輸入引腳D`,與此同時,DCO引腳也經由PCB來到了FPGA的輸入引腳DCO`;
3. 這兩個訊號進入FPGA後,都各自分成了兩路,分別經過各自的延時來到其目標:
a) DCO`引腳輸入後,進過TCLK2,來到了REG1的clk引腳
b) DCO`引腳輸入後,進過TCLK3,來到了REG2的clk引腳
c) D`引腳輸入後,進過Tdata2,來到了REG1的D引腳
d) D`引腳輸入後,進過Tdata3,來到了REG2的D引腳
4. REG1和REG2有所區別,一個是上升沿觸發,一個是下降沿觸發(clk前加了個小圈圈),這是因為latch edge本來就是上升沿又有下降沿的;後期實際上也可以給DCO`也引入虛擬時鐘,這裡不表;
5. 不管是REG1還是REG2,想要鎖存latch資料就必須滿足建立時間和保持時間,這個在下文的圖中也有所體現;
說了那麼多,都不如實際的時序圖來的實際,下面放圖:
上圖由三個顏色的時序,分別是:
1. 紫色代表DAT,也就是資料到達時間,它由Tco(圖中沒有體現,可以參考手冊)、Tdata1和Tdata2三者構成,是不是和我們的DAT定義不一樣?公式是死的,只需要理解其意思就可以。和公式相比少了Tclk(源時鐘到REG0的clk的延時),是因為我們不需要考慮這個延時,我們是根據ADC資料手冊的時序圖反推回裡面的結構圖,所以所有延時在反推的過程中已經都被體現或者被摺合!
2. 綠色夥同棕色線,表達出兩個意思DRTsu和DRTh,分別代表資料建立所需時間和資料保持所需時間;
3. 將兩者按照定義做減法,就能夠得到建立時間裕量和保持時間裕量!
如上圖所示,棕色線所劃分的時間窗中,REG1.D已經是新的資料,而且在這個時間窗內並沒有變化,所以就同時滿足了建立時間裕量大於0和保持時間裕量大於0兩個關係,這樣的時序是穩定的!
但是這個只是圖示而已,所有的Tdata1、2、3以及Tclk1、2、3都是我們目前假設的,在實際進行約束時,那些量時需要設計者提前設定,而那些量是自動生成的那?答案是:
1. Tdata1和Tclk1是由PCB實際佈線所決定的,如果能夠按照等長佈線規則,就能夠讓兩者相互抵消;
2. DCO和DCOX2-shift180的時序是由器件決定的;
3. Tdata2、3,Tclk2、3是FPGA在佈線時自動產生的!
所以說這裡我們只需要告訴FPGA,DCO`和D`之間的時序關係就可以了,要獲得這兩者之間的時序關係,我們就必須獲得DCO和D之間的原始關係,以及他們是如何被佈線延時變成DCO`和D`的;如何去描述上面所說的這種關係呢?利用SDC檔案!
也就是說SDC檔案就是要準確的告訴FPGA,所有輸入(輸出先不管)訊號在進入FPGA時會是個什麼樣子,然後根據這個資訊,FPGA會自動佈線,使得REG1和REG2能夠獲得正確的資料;如果萬一SDC檔案所描述的時序關係非常的惡劣,將會導致不管FPGA怎麼優化佈線和佈局,都不能夠實現正確時時序時,就會輸出報錯,這個在以後的文章TimeQuest TA中會有詳細的分析;那麼接下來就開始寫SDC檔案吧;
#設定各種延時常數
#這裡假設ADC片上的延時都為0
set ADC_CLKs_max 0
set ADC_CLKs_min 0
Set ADC_CLKd_max 0
set ADC_CLKd_min 0
# 同時根據ADC手冊去設定Launch edge到有效資料之間的延時,這裡假設他為X
set ADC_tCO_max X
set ADC_tCO_min X
#這裡設定時鐘訊號和資料訊號在PCB板上的延時差,即使是等長佈線,我們也要可以給
#定兩個值,這樣可以給FPGA佈線更多的壓力,使得後期佈線會往一個最理想的方向進行,
#分別是
set ADC_BD_min XX
set ADC_BD_max XX
#設定兩個時鐘,第一個時鐘為DCO,它會從FPGA的DCO引腳輸入
#另一個時鐘是虛擬時鐘,根據設定,它是DCO的兩倍頻,而且有180度的相移
#這兩個時鐘之間是同步的,一個是很是存在的,另一個是虛擬的!
create_clock -name DCO-period 5-waveform {1.25 3.75} [get_ports {DCO}]
create_clock -name DCO_virtual-period 2.5 -waveform {0 1.25}
#最後將所有的資料引腳同步到DCO_virtual的上升沿,根據上面的延時常數設定輸入延時和
#輸出延時,這條語句非常關鍵,它告訴FPGA所有的輸入訊號,在進入FPGA之前,相對於
#時鐘存在怎麼樣的關係!
set_input_delay -clock DCO_virtual -max [expr $ADC_CLKs_max + $ADC_tCO_max + $ADC_BD_max - $ADC_CLKd_min] [get_ports {D*}]
set_input_delay -clock DCO_virtual -min [expr $ADC_CLKs_min + $ADC_tCO_min + $ADC_BD_min - $ADC_CLKd_max] [get_ports {}D*}]
SDC檔案解釋
1. 藍色底部分代表定義一些延時引數,這些延時引數都是根據實際的PCB佈線或者是ADC的書籍引數來設定的
2. 綠色底部分設定同步時鐘,如果有必要的話還要設定虛擬時鐘;
3. 紫色底部分將所有的輸入訊號同步到時鐘,在這裡這個時鐘是虛擬時鐘,因為我們假設虛擬時鐘的上升沿是launch edge,這裡其實可以也可以同步到DCO上,但就要設定下降沿同步,會顯得比較麻煩;但是一樣都是可以實現的!
通過上面的語句,FPGA就知道了,這些屬於訊號之間的關係:D和DCO之間的關係,D和DCOX2-shift180(就是DCO_Virtual)之間關係;
對自己的設計的實現方式越瞭解,對自己的設計的時序要求越瞭解,對目標器件的資源分佈和結構越瞭解,對EDA工具執行約束的效果越瞭解,那麼對設計的時序約束目標就會越清晰,相應地,設計的時序收斂過程就會更可控。 riple
從最近一段時間工作和學習的成果中,我總結了如下幾種進行時序約束的方法。按照從易到難的順序排列如下: riple
0. 核心頻率約束
這是最基本的,所以標號為0。 riple
1. 核心頻率約束+時序例外約束
時序例外約束包括FalsePath、MulticyclePath、MaxDelay、MinDelay。但這還不是最完整的時序約束。如果僅有這些約束的話,說明設計者的思路還侷限在FPGA晶片內部。 riple
2. 核心頻率約束+時序例外約束+I/O約束
I/O約束包括引腳分配位置、空閒引腳驅動方式、外部走線延時(InputDelay、OutputDelay)、上下拉電阻、驅動電流強度等。加入I/O約束後的時序約束,才是完整的時序約束。FPGA作為PCB上的一個器件,是整個PCB系統時序收斂的一部分。FPGA作為PCB設計的一部分,是需要PCB設計工程師像對待所有COTS器件一樣,閱讀並分析其I/O Timing Diagram的。FPGA不同於COTS器件之處在於,其I/O Timing是可以在設計後期在一定範圍內調整的;雖然如此,最好還是在PCB設計前期給與充分的考慮並歸入設計文件。 riple
正因為FPGA的I/O Timing會在設計期間發生變化,所以準確地對其進行約束是保證設計穩定可控的重要因素。許多在FPGA重新編譯後,FPGA對外部器件的操作出現不穩定的問題都有可能是由此引起的。 riple
3. 核心頻率約束+時序例外約束+I/O約束+Post-fit Netlist
引入Post-fit Netlist的過程是從一次成功的時序收斂結果開始,把特定的一組邏輯在FPGA上實現的佈局位置和佈線結果固定下來,保證這一佈局佈線結果可以在新的編譯中重現,相應地,這一組邏輯的時序收斂結果也就得到了保證。由於有了EDA工具的有力支援,雖然是精確到門級的細粒度約束,設計者只須進行一系列設定操作即可,不需要關心佈局和佈線的具體資訊。 riple
4. 核心頻率約束+時序例外約束+I/O約束+LogicLock
LogicLock是FPGA器件內部的佈局約束。LogicLock的約束是粗粒度的,只規定設計頂層模組或子模組可以調整的佈局位置和大小。成功的LogicLock需要設計者對可能的時序收斂目標作出預計,考慮特定邏輯資源(引腳、儲存器、DSP)與LogicLock Region的位置關係對時序的影響,並可以參考上一次時序成功收斂的結果。這一權衡和規劃FPGA底層物理佈局的過程就是FloorPlanning。LogicLock給了設計者對佈局位置和範圍更多的控制權,可以有效地向EDA工具傳遞設計者的設計意圖,避免EDA工具由於缺乏佈局優先順序資訊而盲目優化非關鍵路徑。由於模組在每一次編譯中的佈局位置變化被限定在了最優的固定範圍內,時序收斂結果的可重現性也就更高。 riple
5. 核心頻率約束+時序例外約束+I/O約束+暫存器佈局約束
暫存器佈局約束是精確到暫存器或LE一級的細粒度佈局約束。設計者通過對設計施加精準的控制來獲得可靠的時序收斂結果。對設計中的每一個暫存器手工進行佈局位置約束並保證時序收斂是一項浩大的工程,這標誌著設計者能夠完全控制設計的物理實現。這是一個理想目標,是不可能在有限的時間內完成的。通常的做法是設計者對設計的區域性進行暫存器佈局約束並通過實際執行佈局佈線工具來獲得時序收斂的資訊,通過數次迭代逼近預期的時序目標。 riple
不久前我看到過一個這樣的設計:一個子模組的每一個暫存器都得到了具體的佈局位置約束。該模組的時序收斂也就相應地在每一次重新編譯的過程中得到了保證。經過分析,這一子模組的設計和約束最初是在原理圖中進行的,在達到時序收斂目標後該設計被轉換為HDL語言描述,相應的約束也儲存到了配置檔案中。 riple
6. 核心頻率約束+時序例外約束+I/O約束+特定路徑延時約束
好的時序約束應該是“引導型”的,而不應該是“強制型”的。通過給出設計中關鍵路徑的時序延遲範圍,把具體而微的工作留給EDA工具在該約束的限定範圍內自由實現。這也是一個理想目標,需要設計者對每一條時序路徑都做到心中有數,需要設計者分清哪些路徑是可以通過核心頻率和簡單的時序例外約束就可以收斂的,哪些路徑是必須制定MaxDelay和MinDelay的,一條也不能遺漏。設定路徑延時約束就是間接地設定佈局佈線約束,但是比上述3、4、5的方法更靈活,而且不失其準確性。通過時序約束而不是顯式的佈局和網表約束來達到時序收斂才是時序約束的真諦。 riple
記得有網友說過“好的時序是設計出來的,不是約束出來的”,我一直把這句話作為自己進行邏輯設計和時序約束的指導。好的約束必須以好的設計為前提。沒有好的設計,在約束上下再大的功夫也是沒有意義的。不過,通過正確的約束也可以檢查設計的優劣,通過時序分析報告可以檢查出設計上時序考慮不周的地方,從而加以修改。通過幾次“分析—修改—分析”的迭代也可以達到完善設計的目標。應該說,設計是約束的根本,約束是設計的保證,二者是相輔相成的關係。
除錯flash,ddr3 ,sdram,跨時鐘域,邊緣閃紅點打拍走PIO, fifo溢位導致影象閃點
除錯中遇到的bug主要份兩類
1, 邏輯或者時序的問題(邏輯上的問題比較好解決,主要是時序和資源的問題,優化資源和時序)
2, pcb硬體的問題(電源的問題,serdes的p,n管腳接反了,sdramd的ba管腳沒接)