本文如果有錯,歡迎留言更正;此外,轉載請標明出處 http://www.cnblogs.com/IClearner/ ,作者:IC_learner
對進行時序路徑、工作環境、設計規則等進行約束完成之后,DC就可以進行綜合、優化時序了,DC的優化步驟將在下面進行講解。然而,當普通模式下不能進行優化的,就需要我們進行編寫腳本來改進DC的優化來達到時序要求。理論部分以邏輯綜合為主,不涉及物理庫信息。在實戰部分,我們將在DC的拓撲模式下進行。(本文主要參考虞希清的《專用集成電路設計實用教程》來寫的總結整理與實驗拓展)主要內容有:
·DC的邏輯綜合及優化過程
·時序優化及方法
·實戰
1.DC的綜合優化階段
我們使用compile命令就可以讓DC進行綜合優化我們的設計了,這里是使用普通模式,在拓撲模式下,不支持compile命令,而是使用compile_ultra命令。電路綜合優化包括三個階段,在這三個階段,都對設計作優化,如下圖所示:
主要包括:第一階段的結構級的優化(Architectural-Level Optimization)、第二階段的邏輯級優化(Logic-Level Optimization)、最后階段的門級優化(Gate-Level Optimization)。
(1)結構級的優化(Architectural-Level Optimization)
結構級優化包括的內容如下:
①設計結構的選擇(Implementation Selection):
在DesignWare中選擇最合適的結構或算法實現電路的功能。
②數據通路的優化(Data-path Optimization):
選擇CSA等算法優化數據通路的設計。
③共享共同的子表達式(Sharing Common Subexpressions):
也就是多個表達式/等式中,有共同的表達式,進行共享,舉例如下:
有等式:
SUM1<=A+B+C;
SUM2<=A+B+D;
SUM3<= A+B+E;
很容易看出,上面的等式中有共同的表達式A+B,那么代碼子表達式A+B可以被共用,原等式可改為:
Temp=A+B;
SUM1<=Temp+C;
SUM2<= Temp+D;
SUM3<=Temp+E;
這種方法可以把比較器的數目減少,共享共同的子表達式。
④資源共享(Resource Sharing):
對於下面的代碼:
DC中經過資源共享之后,就會得到綜合出僅用一個加法器和兩個多路傳輸器的設計,如下圖所示,從而節省資源:
算術運算資源共享的默認策略是約束驅動的。我們也可以指示DC使用面積優化的策略。即將變量hlo_resource_allocation設置為area,如下所示:
set hlo_resource_allocation area
如果不希望資源共享,可以將即將變量hlo_resource_allocation設置為none,這時候,我們還是要進行算術運算的資源共享,那么我們必須在RTL代碼中寫出相應的代碼,如下所示:
⑤重新排序運算符號(Reordering Operators):
RTL代碼包含有電路的拓撲結構。HDL編譯器從左到右解析表示式。括號的優先級更高。DC中DesignWare以這個次序作為排序的開始。
例如:表達式SUM<= A*B+C*D+E+F+G,在DC中的綜合的結構如下圖所示:
電路的總延遲等於一個乘法器的延遲加上4個加法器的延遲。為了使電路的延遲減少,我們可以改變表達式的次序或用括號強制電路用不同的拓撲結構。如:
這時得到的綜合結構為:
電路的總延遲等於一個乘法器的延遲加上2個加法器的延遲,比原來的電路少了2個加法器的延遲。
(2)邏輯級優化(Logic-Level Optimization)
邏輯優化的內容如下:
做完結構的優化后,電路的功能以GTECH的器件來表示。在邏輯級優化的過程中,可以作結構(Structuring)優化和展(開)平(Flattening)優化。
①結構優化:
結構(Structuring)優化用共用子表達式來減少邏輯,這種方式既可用作速度優化又可用作面積優化。結構優化是DC默認的邏輯級優化策略。結構優化在作邏輯優化時,在電路中加入中間變量和邏輯結構。DC作結構優化時,尋找設計中的共用子表達式。例如,對於下面的電路,優化前為:
做完結構優化后,電路和功能表達式為:
值得一提的是邏輯級的結構優化中共用子表達式和前面結構級的共用子表達式是不同的,邏輯級的結構優化指門級電路的共用子表達式,結構級的是算術電路的共用子表達式。邏輯級結構優化並不會改變設計的層次,用下面的命令設置結構優化:
set_structure true
②展平優化:
展平優化把組合邏輯路徑減少為兩級,變為乘積之和(sum-of-products,簡稱SOP)的電路,即先與(and)后或(or)的電路,如下圖所示:
這種優化主要用作速度的優化,電路的面積可能會很大。用下面的命令設置展平優化:
set_flatten true -effort low | medium | high(low 、 medium、high其中一個就可以了)
命令選項“-effort”后的默認值為low,對大部分設計來說,默認值都能收到好的效果。如果電路不易展平,優化就停止。如果把選項“-effort”后的值設為medium, DC將花更多的CPU時間來努力展平設計。如果把選項“-effort”后的值設為high,展平的進程將繼續直到完成。這時,可能要花很多時間進行展平優化。
結構(Structuring)優化和展平(Flattening)優化的比較:
(3)門級優化(Gate-Level Optimization)
門級優化時,Design Compiler開始映射,完成實現門級電路。主要有以下內容:
映射的優化過程包括4個階段:
階段1:延遲優化、階段2:設計規則修整、階段3:以時序為代價的設計規則修整、階段4:面積優化。
如果我們在設計上加入了面積的約束,Design Compiler在最后階段(階段4)將努力地去減少設計的面積。門級優化時需要映射組合功能和時序功能:
組合功能的映射的過程為:DC從目標庫中選擇組合單元組成設計,該設計能滿足時間和面積的要求,如下圖所示:
時序功能的映射的過程為:DC從目標庫中選擇時序單元組成設計,該設計能滿足時間和面積的要求,為了提高速度和減少面積,DC會選擇比較復雜的時序單元,如下所示:
設計規則修整的介紹如下:工藝庫中包括廠商為每個單元指定的設計規則。設計規則有:max_capacitance,max_transition和max_fanout。映射過程中,DC會檢查電路是否滿足設計規則的約束,如有違反之處.DC會通過插入緩沖器( buffers)和修改單元的驅動能力(resizes cells)進行設計規則的修整。修正設計規則的步驟如下所示:
DC進行進行優化的時候,如果下面的條件之一都滿足了:
①所有的約束都滿足了;②用戶中斷;③Design Compiler到了綜合結果收益遞減的階段,即再綜合下去對結果也不能有多大的改善。
這時DC就會進行中斷優化,停止綜合。
(4)其他的優化情況(需要加上一定的綜合選項開關)
比如一個寄存器驅動多個寄存器時,可能會違反設計規則,DC會把就驅動寄存器進行復用,同時把被驅動的進行分割,如下圖所示:
(使用DC的拓撲模式,加上 -timing選項才能自動地使用上面的這種寄存器復制的優化)
當你的設計中出現多次例化的情況時,也就是下面的情況:
在這種情況下,DC在編譯時,會復制每個例化的模塊。每個模塊對應一個拷貝,並且有一個獨一無二的名字。這樣DC可以根據每個模塊本身特有的環境做優化和映射,如下圖所示((模塊名字唯一化)):
在DC里,我們可以用uniquify命令為設計中的每一個模塊產生一個名字唯一的拷貝。DC在為設計做綜合(compile)時,也會自動地為每一個模塊產生一個唯一的有名字的拷貝。變量uniquify_naming_style可以用來控制多次例化子模塊每個拷貝的命名方式。其詳細的使用方法可以在DC'中用“man uniquify_naming_style”來查看。
2.時序優化及方法
DC綜合之后,我們查看詳細的報告,如果沒有違規,設計既能滿足時間和面積的要求又不違犯設計規則,那么綜合完成。可以把門級網表和設計約束等交給后端(backend)工具做布局(placement )、時鍾樹綜合(clock tree synthesis)和布線(route)等工作,產生GDSII文件。如果設計不能滿足時間和面積的要求或違犯設計規則等,就要分析問題所在,判斷問題的大小,然后采取適當的措施解決問題。問題往往是時序的問題,發生時序違規時可以采取相應的措施,如下圖所示:
(1)當違規得比較嚴重時,也就是時序的違規(timing violation)在時鍾周期的25%以上時,就需要重新修改RTL代碼了。
(2)時序違規在25%以下,有下面的時序優化方法:
①使用compile_ultra命令(在拓撲模式下運行)
compile_ultra跟compile一樣,是進行編譯的命令。compile_ultra命令適用於時序要求比較嚴格,高性能的設計。使用該命令可以得到更好的延遲質量( delay QoR ),特別適用於高性能的算術電路優化。該命令非常容易使用,它自動設置所有所需的選項和變量。下面是這個命令的一些介紹:
compile_ultra命令包含了以時間為中心的優化算法,在編輯過程中使用的算法有:A以時間為驅動的高級優化(Timing driven high-level optimization);B為算術運算選擇適當的宏單元結構;C從DesignWare庫中選擇最好的數據通路實現電路;D映射寬扇入(Wide-fanin)門以減少邏輯級數;E積極進取地使用邏輯復制進行負載隔離;F在關鍵路徑自動取消層次划分(Auto-ungrouping of hierarchies)。
compile_ultra命令支持DFT流程,此外compile_ultra命令非常簡單易用,它的開關選項有:
部分解釋如下所示:
-scan :做可測試(DFT)編輯;
-no_autoungroup :關掉自動取消划分特性;
-no_boundary_optimization :不作邊界優化;
-no_uniquify : 加速含多次例化模塊的設計的運行時間
-area_high_effort_script : 面積優化
-timinq_high_effort_script : 時序優化
上面的開關部分說明如下所示:
·使用compile_ultra命令時,如使用下面變量的設置,所有的DesignWare層次自動地被取消:
set compile_ultra_ungroup_dw true (默認值為true)
也就是說,你調用的一個加法器和一個乘法器,本來他們是以IP核的形式,或者說是以模塊的形式進行綜合的,但是設置了上面那么變量之后,綜合后那個模塊的界面就沒有了,你不知道哪些門電路是加法器的,哪些是乘法器的。
使用compile_ultra命令時,使用下面的變量設置,如果設計中有一些模塊的規模小於或等於變量的值,模塊層次被自動取消:
set compile_auto_ungroup_delay_num_cells 100(默認值=500)
也就是說,假設你有一個模塊A是一個小的乘法器,並且調用了模塊B,一個模塊B是一個小的加法器,使用沒有設置這條命令的情況綜合,那么我們可以看到模塊A中乘法器對應的門電路是哪些,同樣也可以看到模塊B的加法器是由哪些門電路構成的,模塊A和模塊B之間有層次、有界限;當設置上面的那條命令之后,我們就看不到模塊A或者模塊B之間的層次關系了,也看不到乘法器是由哪些門電路構成,或者說你看到了某一個與門,但是你並不知道它是構成乘法器的還是構成加法器的。
為了使設計的結果最優化,我們建議將compile_ultra命令和DesignWare library一起使用。
·邊界優化是指在編輯(又叫綜合)時,Design Compiler會對傳輸常數、沒有連接的引腳和補碼(complement)信息進行優化,如下圖所示:
也就是說,邊界優化會把邊界引腳一些固定的電平、固定的邏輯進行優化。
此外,在DC Ultra(或者DC的拓撲模式下)中,我們可以用Behavioral ReTiming(簡稱BRT)技術,對門級網表的時序進行優化,也可以對寄存器的面積進行優化。BRT通過對門級網表進行管道傳遞(pipeline)(或者稱之為流水線),使設計的傳輸量(throughput)更快。BRT有兩個命令:
optimize_registers :適用於包含寄存器的門級網表(不是compile_ultra的開關選項)。
pipeline_design :適用於純組合電路的門級網表。
對於寄存器的的優化,舉例如下,對於下面的電路,既包含有組合邏輯電路又包含有寄存器:
后級的寄存器與寄存器之間的時序路徑延遲為10. 2 ns,而時鍾周期為10 ns,因此,這條路徑時序違規。但是前級的寄存器與寄存器之間的時序路徑延遲為7. 5 ns,有時間的冗余。使用optimize_registers命令,可以將后級的部分組合邏輯移到前級,使所有的寄存器與寄存器之間的時序路徑延遲都小於時鍾周期,滿足寄存器建立時間的要求。optimize_registers命令首先對時序做優化,然后對面積作優化。優化后,在模塊的入/輸出邊界,電路的功能保持不變。該命令只對門級網表作優化。
除了單獨使用這個命令之外,還可以在編譯的時候往往加上選項-retime(這個好像只有compile_ultra才有這個開關選項)。-retime選項的功能也就是:當有一個路徑不滿足,而相鄰的路徑滿足要求時,DC會進行路徑間的邏輯遷移,以同時滿足兩條路徑的要求,這也叫adaptive retiming,如下圖所示:
對於純組合邏輯的流水線(管道)優化,舉例如下,對於純組合邏輯電路進行優化如下所示:
左邊電路,是一個純組合電路,它的路徑延遲為23. 0 ns。對這個電路進行管道傳遞優化后,得到右邊所示的電路。顯然,電路的傳輸量(throughput)加快了。需要注意的是,在使用這個命令時,需要在RTL設計中把寄存器預置好,否則DC不知道這些寄存器是怎么來的。
②使用compile -scan -inc 命令
-inc 是使用增量編譯。這條命令就是進行支持可測性設計的增量編譯。使用增量編輯時,DC只作門級優化,這時,設計不會回到GTECH,如下圖所示:
③使用自定義路徑組合關鍵范圍
在介紹這種優化方法之前,先來了解一下路徑分組與延時。
·路徑分組:
DC為了便於分析電路的時間,時序路徑又被分組。路徑按照控制它們終點的時鍾進行分組。如果路徑不被時鍾控制,這些路徑被歸類於默認(Default)的路徑組。我們可以用report_path_group命令來報告當前設計中的路徑分組情況。例如,對於下面的電路,我們來看一下路徑及分組情況:
根據上圖可以知道,圖中共有5個終點(四個寄存器和一個輸出)。時鍾CLK1控制3個終點,在CLK1的控制下有8條路徑。時鍾CLK2控制一個終點,在CLK2的控制下有3條路徑。輸出端口為一終點,它不受任何時鍾控制,其起點為第二級寄存器的時鍾引腳,在它的控制下只有一條路徑,這條路徑被歸類於默認的路徑組。因此,本設計中共有12條路徑和3個路徑組。該3個路徑組分別為CLKI,CLK2和默認(Default )路徑組。
·路徑的延時:
在計算路徑的延遲時,Design Compiler把每一條路徑分成時間弧((timine arcs),如下圖所示:
DC就是通過時間弧來計算路徑延時。因為時間弧描述單元或/和連線的時序特性。單元的時間弧由工藝庫定義,包括單元的延遲和時序檢查(如寄存器的setup/hold檢查,clk->q的延遲等);連線的時間弧由網表定義。在上面電路中,時間弧有連線的延遲,單元的延遲和寄存器的clk -> q延遲。單元延遲常用非線性模型計算;連線延遲在版圖前用線負載模型計算;RC寄生參數的分配用操作條件中的“Tree-type”屬性決定;工作條件又決定制程、電壓和溫度對連線及單元延遲的影響。
此外,路徑的延遲與起點的邊沿有關,如下圖所示:
假設連線延遲為0,如果起點為上升沿,則該條路徑的延遲等於1. 5 ns。如果起點為下降沿,則該條路徑的延遲等於2. 0 ns。由此可見,單元的時間弧是邊沿敏感的。Design Compiler說明了每一條路徑延遲的邊沿敏感性。還有需要強調的是Design Compiler默認的行為是假設寄存器之間的最大延遲約束為:TCLK - FF21ibSetup,即數據從發送邊沿到接收邊沿的最大延遲時間要小於一個時鍾周期,如下圖所示:
Design Compiler中,常用report_timing命令來報告設計的時序是否滿足目標。執行report_timing命令時,DC做4個步驟:
·把設計分解成單獨的時間組;
·每條路徑計算兩次延遲,一次起點為上升沿,另一次起點為下降沿;
·在每個路徑組里找出關鍵路徑(critical path),即延遲最大的路徑;
·顯示每個時間組的時間報告。
關於怎么閱讀時序報告,我們后面進行介紹。
DC的默認行為是對關鍵路徑作優化。當它不能為關鍵路徑找到一個更好的優化解決方案時,綜合過程就停止。DC不會對次關鍵路徑(Sub-critical paths)作進一步的優化。因此,如果關鍵路徑不能滿足時序的要求,違反時間的約束,次關鍵路徑也不會被優化,它們僅僅被映射到工藝庫,如下圖所示:
對於下面的電路,假設加設計約束后,所有的路徑屬於同樣的時鍾組,也就是只有一個路徑組:
如果組合電路部分的優化不能滿足時序要求,並且關鍵路徑在組合電路里,根據DC的默認行為,組合電路中關鍵路徑的優化將會阻礙了與它屬於相同時鍾組的寄存器和寄存器之間路徑的優化。防止出現這種情況可用下面兩種方法:自定義路徑組和設置關鍵范圍。
·自定義路徑組(User-Defined Path Group):
綜合時,工具只對一個路徑組的最差(延時最長)的路徑作獨立的優化,但並不阻礙另外自定義路徑組的路徑優化。產生自定義路徑組也可以幫助綜合器在做時序分析時采用各自擊破(divide-and-conquer)的策略,因為report_timing命令分別報告每個時序路徑組的時序路徑。這樣可以幫助我們對設計的某個區域進行孤立,對優化作更多的控制,並分析出問題所在,如下圖所示的:
產生自定義路徑組的命令如下所示:
#Avoid getting stuck on one path in the reg-reg group
group_path -name INPUTS -from [all_inputs]
group_path -name OUTPUTS -to [all_outputs]
group_path -name COMBO -from [all_inputs] -to [all_outputs]
上面的命令產生三個自定義的路徑組,加上原有的路徑組,即寄存器到寄存器的路徑組(因為受CLK控制,默認的是CLK的路徑組),現在有4個路徑組。組合電路的路徑,屬於“COMBO”組,由於該路徑組的起點是輸入端,在執行“group_path -name INPUTS -from [all_inputs]”命令后,命令中用了選項“-from [all_inputs]",它們原先屬於“INPUTS”組。在執行“group_path -name OUTPUTS -to [all_outputs]”命令后,組合電路的路徑不會被移到“OUTPUTS”組,因為開關選項‘'-from”的優先級高於選項”-to”,因此組合電路的路徑還是留在“INPUTS”路徑組。但是由於“group_path -name COMBO -from [all_inputs] -to [all-outputs]”命令中同時使用了開關選項“-from”和“-to" ,組合電路路徑的起點和終點同時滿足要求,因此它們最終歸屬於“COMBO”組。DC以這種方式工作來防止由於命令次序的改變而使結果不同。我們可以用report_path_group命令來得到設計中時序路徑組的情況。
產生自定義的路徑組后,路徑優化如下圖所示,此時,寄存器和寄存器之間的路徑可以得到優化:
DC可以指定權重進行優化,當某些路徑的時序比較差的時候,可以通過指定權重,着重優化該路徑。權重最高5,其次是2,默認是1;因此最差的要設置5;如下圖所示,下面的命令就是着重優化CLK這個路徑組:
·關鍵范圍(Critical Range):
DC默認只對一個路徑組內的關鍵路徑進行時序優化,但是我們可以設置DC在關鍵路徑的延時下面某個延時值之內的路徑進行優化,因此我們可以使用下面的命令設置關鍵范圍:set_critical_range 2 [current_design]
使用上面的命令之后,DC會對在關鍵路徑2ns的范圍內的所有路徑作優化,解決相關次關鍵路徑的時序問題可能也可以幫助關鍵路徑的優化。時序優化的示意圖如下所示:
如果在執行set_critical_range命令后,優化時使關鍵路徑時序變差,DC將不改進次關鍵路徑的時序。我們建議關鍵范圍的值不要超過關鍵路徑總值的10%。
·自定義路徑組+關鍵范圍
這是將自定義路徑組合關鍵范圍結合起來,也就是在每一個路徑組用指定的關鍵范圍來設置設計的關鍵范圍,命令如下所示:
group_path -name CLK1 -critical_range 0.3
group_path -name CLK2 -critical_range 0.1
group_path -name INPUTS -from [all_inputs] -critical_range 0
同時使用自定義時序路徑組和關鍵范圍,會使DC運行時間加長,並且需要使用計算機的很多內存。但這種方法值得一試,因為DC默認地只在每個路徑組優化關鍵路徑。如果在一條路徑上關鍵路徑不能滿足時間,它不會嘗試其他的方法對該時序路徑組的其他路徑做優化。如果能使DC對更多的路徑做優化,它可能在對設計的其他部分做更好的優化。在數據通路的設計中,很多時序路徑是相互關聯的,對次關鍵路徑的優化可能會改進關鍵路徑的時序。設置關鍵范圍后.即使DC不能減少設計中的最差負數冗余(Worst NegativeSlack,我也不知道這是什么東西),它也會減少設計中總的負數冗余(Total Negative Slack) 。
下面是自定義路徑組和關鍵范圍的主要區別:
自定義路徑組: 用戶自定義路徑組后,如果設計的總性能有改善,DC允許以犧牲一個路徑組的路徑時序(時序變差)為代價,而使另一個路徑組的路徑時序有改善。在設計中加入一個路徑組可能會使時序最差的路徑時序變得更差。
關鍵范圍: 關鍵范圍不允許因為改進次關鍵路徑的時序而使同一個路徑組的關鍵路徑時序變得更差。如果設計中有多個路徑組,我們只對其中的一個路徑組設置了關鍵范圍,而不是對整個設計中的所有路徑組都設置了關鍵范圍,DC只會並行地對幾條路徑優化,運行時間不會增加很多。
④重新划分模塊(Repartition Block)
模塊的划分是在設計一開始就進行的,但是由於我們是注重DC這個工具的使用,因此放在這里講解。
·層次結構與模塊划分:
層次結構在IC設計中廣泛使用。現代的IC設計中,幾乎沒有不用層次結構進行設計的。一些大的設計,其邏輯層次可能多達十幾層。SoC設計中一般包括設計的再使用和知識產權IP核。SoC設計中包括了多個層次的電路。層次化的IC設計趨勢如下所示:
SoC設計由一些模塊組成,如下圖所示:
同樣,圖中已綜合邏輯電路(例如RISC_CORE),一般也由一些子模塊組成。對於設計復雜規模又大的電路,我們需要對它進行划分(Partitioning),然后對划分后比較簡單規模又小的電路作處理(如綜合)。這時,由於電路小,處理和分析比較方便簡單。容易較快地達到要求。再把已處理好的小電路集成為原來的大電路,如下圖所示:
理想情況下,所有的划分應該在寫HDL代碼前已經計划好。
·初始的划分由HDL定義好.
·初始的划分可以用Desige Compiler進行修改.
做划分的原因很多,下面是其中的幾個原因:
·不同的功能塊(如Memory,uP,ADC,Codec、控制器等等);
·設計大小和復雜度(模塊處理時間適中,設計大小一般設為一個晚上的運行時間,白天進行人工處理和調試,晚上機器運行,第二天上午檢查運行結果);
·方便設計的團隊管理項目(每個設計工程師負責一個或幾個模塊);
·設計再使用(設計中使用IP);
·滿足物理約束(如用FPGA先做工程樣品—Engineering Sample;大的設計可能需要放入多個FPGA芯片才能實現)。
·等等。
划分模塊關系到時序,時序不好的情況下,可以進行重新划分模塊,因此就要求我們在划分模塊的時候,對設計進行合適的划分。
可用例化(instantiation)定義設計的層次結構和模塊(hierarchical structure and blocks)。 VHDL的entity和Verilog的module的陳述(statements)定義了新的層次模塊,即例化一個entity或module產生一級新的層次結構。如果設計中,我們用符號(+,一,*,/,…)來標示算術運算電路,可能會產生一級新的層次結構。VHDL語言中的Process和Verilog語言中的Always陳述並不能產生一級新的層次。設計時,為了得到最優的電路,我們需要對整個電路作層次結構的設計,對整個設計進行划分,使每個模塊以及整個電路的綜合結果能滿足我們的目標。
例如下面的設計中:
有3個模塊:A,B和C。它們各自有輸入和輸出端口。由於DC在對整個電路做綜合時,必須保留每個模塊的端口。因此,邏輯綜合不能穿越模塊邊界,相鄰模塊的組合邏輯也不能合並。從寄存器A到寄存器C的路徑的延時較長,這部分的電路面積較大。 如果我們對設計的划分作出修改,相關的組合電路組合到一個模塊,原來模塊A,B和C中的組合電路沒有了層次的分隔,綜合工具中對組合電路優化的技術現在能得到充分的使用。這時,電路的面積比原來要小,從寄存器A到寄存器C的路徑的延時也短了。修改如下圖所示:
如果我們對設計的划分作另一種修改,如下所示,我們將得到最好的划分:
這里的修改將相關的組合電路組合到一個模塊,原來模塊A,B和C中的組合電路沒有了層次的分隔,綜合工具中對組合電路優化的技術能得到充分的使用。並且,由於組合電路和寄存器的數據輸入端相連,綜合工具在對時序電路進行優化時,可以選擇一個更復雜的觸發器((JK,T,Muxed和Clock-enabled等),把一部分組合電路吸收集成到觸發器里。從而使電路的面積更小,從寄存器A到寄存器C的路徑的延時更短。
對於一般的設計,好的模塊划分如下圖所示:
在這樣的划分下,模塊的輸出邊界是寄存器的輸出端。由於組合電路之間沒有邊界,其輸出連接到寄存器的數據輸入端,我們可以充分利用綜合工具對組合電路和時序電路的優化技術,得到最優的結果,同時也簡化了設計的約束。圖中每個模塊除時鍾端口外的所有輸入端口延時是相同的,等於寄存器的時鍾引腳CLK到輸出引腳Q的延時。這使得時序約束更為方便,這一點在前面的時序路徑約束中有說過。
上面是推薦的模塊划分模式,下面就來說一下哪些是要避免的模塊划分方式。
作模塊划分時,應盡量避免使用膠合邏輯(Glue Logic),膠合邏輯如下圖所示:
膠合邏輯是連接到模塊的組合邏輯。圖中,頂層的與非門(HAND gate)僅僅是個例化的單元,由於膠合邏輯不能被其他模塊吸收,優化受到了限制。如果采用由底向上(bottom up)的策略,我們需要在頂層做額外的編譯(compile)。避免使用膠合邏輯(Glue Logic)的划分如下所示:
膠合邏輯可以和其他邏輯一起優化,頂層設計也只是結構化的網表。不需要再做編譯。
·模塊划分的修改
第一次的模塊划分可能存在時序違規,可能需要重新划分模塊,這里就來介紹一下模塊划分的修改問題。我們知道,設計越大,計算機對設計作綜合時所需要的資源越多,運行時間就越長。Design Compiler軟件本身對設計的規模大小並沒有限制。我們在對設計做編譯時,需要考慮划分模塊規模的大小應與現有的計算機中央處理器(CPU)和內存資源相匹配。盡量避免下面划分不當情況:
模塊太小:由於人工划分的模塊邊界,使得優化受到限制,綜合的結果可能不是最優的。
模塊太大:做編輯所需的運行時間可能會太長,由於要求設計的周期短,我們不能等太久。
一般來說,根據現有的計算機資源和綜合軟件的運算速度,按我們所期望的周轉時間(turnaround time),把模塊划分的規模定為大約400 ~800K門。對設計作綜合時,比較合理的運行時間為一個晚上。白天我們對電路進行設計和修改,寫出編譯的腳本。下班前,用腳本把設計輸人到DC,對設計作綜合優化,第二天早上回來檢查結果。
作划分時,要把核心邏輯(Core Logic) 、 I/0 Pads、時鍾產生電路、異步電路和JTAG(Joint Test Action Group)電路分開,把它們放到不同的模塊里。頂層設計至少划分為3層的層次結構:頂層(Top-level)、中間層(Mid-level)、核心功能(Functional Core),如下圖所示:
使用這種划分方式是因為:I/O pad單元與工藝相關、分頻時鍾產生電路是不可測試(Untestable)的、JTAG電路與工藝相關、異步電路的設計、約束和綜合與同步電路不同,所以也放在與核心功能不同的模塊里。
這里主要介紹同步電路的設計與綜合。 為了使電路的綜合結果最優化,綜合的運行時間適中,我們需要對設計作合適的划分。如果現有的划分不能滿足要求,我們要對划分進行修改。我們可以修改RTL原代碼對划分作修改,也可以用DC的命令對划分作修改。下面介紹在DC里用命令修改划分。
DC以兩種方法修改划分:自動修改划分和手動修改划分。
自動修改划分:
綜合過程中DC需透明地修改划分。在DC中如使用命令:
compile -auto_ungroup area | delay (面積和延時之中選一個)
DC在綜合時將自動取消(去掉)小的模塊分區。取消模塊分區由變量(前面也有提及到這些命令):
compile_auto_ungroup_delay_num_cells
compile_auto_ungroup_area_num_cells
來控制。兩個變量的預設默認值分別為500和30。我們也可以用set命令把它們設置為我們希望的任何數值。我們可用report_auto_ungroup命令來報告編輯時取消了那些分區。如在DC中使用命令:
compile -ungroup_all
DC在綜合時將自動取消所有的模塊分區或層次結構。此時,設計將只有頂層一層的電路。該命令不能取消附加了dont_touch屬性的模塊分區。
手工修改划分:
手動修改划分是指用戶用命令指示所有的修改。使用“group”和“ungroup”命令修改設計里的划分,如下圖所示:
group命令產生新的層次模塊,效果如下圖所示:
ungroup命令取消一個或所有的模塊分區,效果如下圖所示:
如要在當前設計中取消所有的層次結構,可以使用下面的命令:
ungroup -all -flatten
ungroup命令用選項“-simple_names”將得到原來的非層次的單元名U2 and U3
ungroup U23 -simple_names
得到的效果如下圖所示:
最后,為了防止再次划分模塊,這里總結一下模塊划分的策略:
·不要通過層次邊界分離組合電路。
·把寄存器的輸出作為划分的邊界。
·模塊的規模大小適中,運行時間合理。
·把核心邏輯(Core Logic) ,Pads、時鍾產生電路、異步電路和JTAG電路分開到不同的模塊。
這樣划分好處是:結果更好——設計小又快、簡化綜合過程——簡化約束和腳本、編譯速度更快一一更快周轉時間(turnaround)。
下面是實戰環節
3、實戰
在本次實戰里面,我們主要根據給出的原理圖和綜合規范,實踐DC的綜合優化技術,在拓撲模式下進行,因此還有可能涉及一些物理設計的內容,我們一步一步來進行吧。
設計原理圖:
(頂層模塊示意圖:)
(子模塊示意圖一:)
(子模塊示意圖二:)
(子模塊示意圖三:)
綜合規范:
(可用資源說明:)
(設計和約束文件說明:)
(布局規划說明:)
(設計規范:)
首先我們來簡單分析一下這個綜合規范:
可用資源規范:也就是通過運行那個腳本來查看你的電腦有多少可用用來綜合的核心,這里我們跳過,不用理他。
設計和約束文件說明:告訴我們設計的RTL文件和名字,以及告訴我們約束的位置和名字,RTL文件和名字以及時序環境等約束都我們不需要改。
布局規划說明:由於我們使用的是拓撲模式下的綜合,這個布局規划提供給了我們物理的約束信息。
設計規范說明:其實這個是綜合的規范說明,告訴你需要在綜合過程中,要對哪些模塊進行怎么樣的處理,從而達到某種要求,這里面的10條規范我們后面在時間過程中都會介紹。
·設置.synopsys_dc.setup啟動文件,配置DC的啟動環境
(跟前面一樣,不進行具體描述)
·進行編寫設計約束文件,由於這里一方面沒有給出時序和環境屬性等方面設計規范,一方面給出了相關的設計約束文件,因此我們不需要進行撰寫了,我來看一下吧:
時序和環境屬性的約束:
從上到下依次是:清除以前的約束、時鍾的約束、輸入端口延時的約束、輸入端口環境屬性的約束、輸出端口延時約束、輸出端口環境屬性的約束。
布局規划中,包含的物理信息,對於了相應地物理約束,如下所示:
約束都給我們准備好了,我們就可以啟動DC了
·啟動DC,進行讀入設計前的檢查
(這里跟之前的章節一樣,不再陳述)
·為formality創建文件,以便retiming轉化可以捕捉到相應地文件,總之就是形式驗證要用到,命令如下:
set_svf STOTO.svf
·讀入設計和檢查設計
(很前面的章節已經,這里不再陳述)
·執行時序約束,查看約束是否滿足,同時執行非默認的物理約束:
source STOTO.con
check_timing
source STOTO.pcon
report_clock
·根據設計規范,應用不同的優化命令:
-->根據1和2,IO約束是保守值,能夠更改,還有就是最終的設計要滿足寄存器到寄存器之間的路徑,因此,我們可以進行路徑分組,並且更關注時鍾那一組,也就是寄存器到寄存器那一組,優化的命令如下所示:
group_path -name clk -critical 0.21 -weight 5
group_path -name INPUTS -from [all_inputs]
group_path -name OUTPUTS -to [all_output]
group_path -name COMBO -from [all_inputs] -to [all_output]
然后我們可以查看時候進行了設置:
report_path_group,得到結果如下:
-->根據3,INPUT模塊的結構需要保護;根據4,PIPELINE模塊需要進行register_timing,也就是純的流水線,因此也不能被打散,因此需要設置:
set_ungroup [get_designs "PIPELINE INPUT"] false
設置之后我們需要查看是否設置正確(設置正確會返回false )
get_attribute [get_designs "PIPELINE INPUT"] ungroup
如下圖所示:
ungroup是取消層次的依次,設置為true就是要進行取消層次結構;因此我們要設置為false
-->根據6,I_DONT_PIPELINE模塊的寄存器不能被流水線移動,根據前面的講解,我們可以這樣約束:
set_dont_retime [get_cells I_MIDDLE/I_DONT_PIPELINE] true
然后檢查是不是約束成功,或者約束對了:
get_attribute [get_cells I_MIDDLE/I_DONT_PIPELINE] dont_retime
如下圖所示,返回應為true:
-->根據要求4,需要進行pipelined,於是我們可以啟用register_timing,約束如下所示:
set_optimize_registers true -design PIPELINE
-->根據要求5,雖然PIPELINE進行了pipelined,也就是進行了寄存器retiming,但是輸出寄存器不能動,也就是保持原來的寄存器,因此需要約束:
set_dont_retime [get_cells I_MIDDLE/I_PIPELINE/z_reg*] true
然后檢查一下是否正確:
-->保存在綜合之前保存一下我們的設計:
write -f ddc -hier -out unmapped/STOTO.ddc
·進行綜合:
根據要求8:設計是時序關鍵的,因此我們要在綜合的時候加上-timing選項;根據要求10:要執行掃描插入,因此要加上-scan選項,看預加上掃描鏈綜合后是否有違規;根據要求7、9以及前面的要求,我們可以加上-retiming選項優化進行寄存器、組合邏輯等的優化;綜合使用的命令如下所示:
compile_ultra -scan -timing -retime
·綜合后檢查與處理:
-->綜合完成之后,我們可以查查看我們用了哪些特性(這一步可以忽略):
(這些特性都是大把大把地燒錢啊)
-->查看哪些模塊是否被打散,即驗證與約束的是否一致:
可以知道:MIDDLE, OUTPUT, DONT_PIPELINE, GLUE, ARITH and RANDOM這些模塊都被打散了; 沒有被打散的,也就是保存了模塊結構的只有下面的這三個設計:STOTO, PIPELINE, INPUT
我們從GUI中也可以看到:
只有頂層設計STOTO和子模塊PIPELINE, INPUT的邊框被保存下來了,其他的都被打散了,也就是找不到模塊的邊界了。
-->查看是否有約束違規:
這里我們通過重定義的形式,把生成的時序報告保存到文件中:
redirect -tee -file rc_compile_ultra.rpt {report_constraint -all}
(本實驗中,有時序違規)
-->查看時序報告:
redirect -tee -file rt_compile_ultra.rpt {report_timing}
下面我們就來看看這個這個時序報告的一部分吧:
從上面的報告我們可以知道,雖然一些模塊被打散了,但是模塊的例化明還在,我們可以通過例化名來找到原件所在的模塊,方便我們查看延時不合理時提供定位;這也就是模塊例化名字唯一化的一個好處。
-->保存設計:
write -f ddc -hier -out mapped/STOTO.ddc
綜合完成了,此外我們為formality進行停止記錄數據(總之就是形式驗證要做得事):
set_svf -off
·查看寄存器是否被移動等操作,也就是查看優化技術的結果細節(有興趣的可以仔細看下,深入了解)
前面我們進行了各種retiming、pipeline的優化,有一些寄存器被移動了,有些組合邏輯被分割了,我們現在就來看看那些被移動,一方面是純粹的查看進行了解一些優化技術,另一方面是看看是否存在約束與預期不符合的情況。
-->查看在PIPELINE設計中被register retiming技術移動過的寄存器 :
get_cells -hier *r_REG*_S
通過返回值(即返回寄存器的名字)的路徑,我們可以知道PIPELINE中的流水線寄存器被移動過了:
(retiming中被移動過的流水線寄存器的名字以 clkname_r_REG*_S*結束,*是通配符),再結合我們我們的原理圖,我們可以知道,是z1_reg被移動了(一位后綴名是z1跟s1):
-->我們還可以查看例化的名字原來的模塊名字,如下所示:
查看原來的I_IN模塊:
report_cell -nosplit I_IN:
-->在第1點中我們說只是通過名字中的1來說移動的是z1_reg,這顯然是不夠充分,可以通過下面來驗證z_reg是否被移動過:
get_cells -hier *z_reg*
有返回值,說明這個寄存器存在,沒有被移動過(移動過之后就被換了例化名字):
然后我們來查看一下z1_reg,可以看到找不到對象,說明被移動了:
-->查看其它的被retiming移動都的觸發器(retiming中,被移動過的卻不是流水線中的寄存器的被命名為R_* ):
上面是INPUT模塊中被retiming移動的寄存器,我們可以查看該模塊是否有不被移動的寄存器:
get_cells I_IN/*_reg*
有返回值,說明是存在有不被移動的寄存器的。
-->通過下面的命令:
report_timing -from I_MIDDLE/I_PIPELINE/z_reg*/*
可以知道PIPELINE模塊是寄存輸出的(因為有返回報告值)
優化的實戰部分都這里就結束了,最后,DC的優化命令有很多,不懂的可以通過man命令查看。最后感嘆一下,總共碼了一萬兩千多子,加上一堆圖,這應該是本系列最長的一篇博文吧。