# OpenRoad ###### M11107415 張育瑋 ###### CAD PA6 by 劉一宇教授 20230104 ## 官方資源 ### 官方網站 https://theopenroadproject.org/ ### github https://github.com/The-OpenROAD-Project ## 安裝步驟 ### WSL 在win11設定wsl並安裝Ubuntu的最新版 先以系統管理員身分開啟cmd或powershell 如果是第一次使用wsl,輸入以下指令,系統會更新,並且需要在安裝後重新開機 wsl --install 如果不是第一次使用wsl,輸入以下指令可以直接安裝Ubuntu,系統預設是22.04版 wsl --install -d Ubuntu 安裝完成後要設定自己的帳號及密碼 若想使用圖形化介面,win11有內建的資料夾,直接開啟即可,或也可以使用moboxterm開啟WSL的Ubuntu也非常便利。 ### OpenROAD 下載OpenROAD flow scripts git clone --recursive https://github.com/The-OpenROAD-Project/OpenROAD-flow-scripts 安裝OpenROAD相依性套件(需要一段時間) cd ~/OpenRoad-flow-script/tools/OpenROAD/ sudo ./etc/Dependencyinstaller.sh -dev 編譯OpenROAD (需要執行一段時間安裝,如果遇到錯誤可以google查詢錯誤訊息,安裝缺少的套件) 返回OpenROAD-flow-scripts主目錄 cd ~/OpenROAD-flow-scripts 開始編譯 ./build_openroad.sh --local 驗證OpenROAD是否正確編譯完成 環境參數設定 source ./setup_env.sh 確認yosys及openroad可以執行並出現help說明 yosys -help openroad -help ### klayout 下載klayout wget http://www.klayout.org/downlaods/Ubuntu-22/klayout_0.28.2-1_amd64.deb 這裡下載的版本和參考影片中的不同,原因是因為我們的Ubuntu是22.04版,所以需要安裝Ubuntu22的klayout,才不會出現錯誤 接著是安裝klayout相依性套件 sudo apt install libqt5designer5 libqt5multimedia5 libqt5multimediawidgets5 libqt5xmlpatterns5 libruby3.0 這裡一樣因為Ubuntu22的關係,所以安裝的libruby是和影片不同的3.0版本 安裝Klayout sudo dpkg -i klayout_0.28.2-1_amd64.deb 最後開啟Klayout klayout ### 參考影片教學: https://www.youtube.com/watch?v=c7raQWp73j4&ab_channel=Yi-YuLiu%28%E5%8A%89%E4%B8%80%E5%AE%87%29 --- ## OpenROAD-flow-script/flow基本介紹 ### 初次使用 + **makeFile**:使用OpenROAD最核心的部分,若只要執行default的部分可以直接打make即可執行。 + makeFile中最上面有許多design初始是被註解的狀態,可以將想執行的design解註解就可以看到自動運行後的結果,預設的design是nangate45的gcd + 可以在make後面跟隨指令呼叫不同的效果,如加gui_final可以用gui顯示全部完成後的電路 ### 檔案介紹 + **results** 裡面會顯示每個分項步驟的結果,結構如下圖所示 ![](https://i.imgur.com/0D1bsGX.png) + **designs** + ![](https://i.imgur.com/ELSLaEF.png) 每個以design命名的資料夾裡面會包含design用來執行的config.mk檔,在執行一個design時就是執行config.mk來進行,裡面有紀錄每個design相關的設定值還有要依序執行的檔案(他就是一個script)。 下圖是nangate45/gcd的config.mk檔範例 ![](https://i.imgur.com/NChnRSS.png) + 另外如果要真正的找到verilog source code原始檔,會在這個src資料夾中 ![](https://i.imgur.com/aliz42y.png) + **script** 裡面存放了各個步驟會用到的tcl檔,當makeFile開始執行整個flow,就會依序進來抓需要的tcl檔 ### gui可視化界面小技巧 #### 搜尋某類型的元件 在使用OpenROAD的GUI介面時,可以直接用ctrl + F 叫出此視窗,然後打上想要搜尋的元件類別,程式就會直接幫忙找出所有該元件 ![](https://i.imgur.com/6ynlvWG.png) 例如要找所有的net,就可以在輸入欄打*,然後把type選到net,就可以顯示所有的net,如下圖所示 ![](https://i.imgur.com/aGrlXQS.png) 如果要搜尋所有的clk訊號則可以打clk*,type一樣選net,就可以顯示如下圖 ![](https://i.imgur.com/c3sYFmv.png) --- ## EDA flow介紹 以下的介紹主要會根據OpenROAD makeFile中的順序及分類介紹,並再做額外的延伸 且舉例部分皆以nangate45的gcd為主 ### 1. Synthesis 使用yosys(based on ABC)進行 + 主要是將RTL code轉換成gate level的net list 下圖是原本RTL code的樣子 ![](https://i.imgur.com/gEmWCBL.png) 進行完synthesis後會變成下圖gate level的樣子 ![](https://i.imgur.com/VhSUiwc.png) + 產生的結果檔 ![](https://i.imgur.com/eW2wkgV.png) + **sdc**格式介紹 全名是Synopsys design constraints,內容規範電路的時序、面積、功耗等。 ### 2. Floorplan #### 1. Translate verilog to odb 將verilog格式轉成odb格式,方便OpenROAD讀取和使用 因為還沒有做任何擺置,所以初始的影像是空白的 ![](https://i.imgur.com/kylTEDa.png) 如果想進一步了解odb格式請參考: 1. https://en.wikipedia.org/wiki/ODB%2B%2B 2. https://fileinfo.com/extension/odb #### 2. IO Placement (random) 進行IO的隨機擺放,結果如下圖所示 ![](https://i.imgur.com/woaTkU0.png) #### 3. Timing Driven Mixed Sized Placement 由於在nangate45/gcd中沒有macro,因此此階段會看到如下的空白顯示 ![](https://i.imgur.com/woaTkU0.png) 因此這裡我們使用nangate45/tinyRocket來觀察變化,如下圖所示,可以看出在這邊已經先直接把macro和cell都擺進來了 ![](https://i.imgur.com/CacaAYs.png) #### 4. Macro Placement nangate45/gcd在此階段一樣是沒有變化 ![](https://i.imgur.com/woaTkU0.png) 而從nangate45/tinyRocket可以看出macro已經進行了palcement,並且周圍有虛線的Blockage範圍,目的是要讓其他元件離該macro有一定的距離 ![](https://i.imgur.com/K7OYBsR.png) #### 5. Tapcell and Welltie insertion 此步驟加入了Tapcell和Welltie,如下圖所示。由於nangate45/gcd已經看得出差別,故接下來的例子我們都繼續從nangate45/gcd的角度出發觀察變化。 ![](https://i.imgur.com/qPVKVrU.png) Tap cell 詳細資訊如下 ![](https://i.imgur.com/0foEMQY.png) + **Tap cell(well tap cell)** 相關知識如下: 1. https://teamvlsi.com/2020/08/well-tap-cell-in-asic-design.html + about **Latch-up** 1. https://en.wikipedia.org/wiki/Latch-up 2. https://www.newton.com.tw/wiki/%E9%96%82%E9%8E%96%E6%95%88%E6%87%89/9391913 #### 6. PDN generation 接著佈上VDD線和VSS線如下所示,以藍色線段表示 ![](https://i.imgur.com/7C8QT21.png) 奇數排及右邊的導線是連通的VDD ![](https://i.imgur.com/ux75kI5.png) 偶數排及左邊的導線是連通的VSS ![](https://i.imgur.com/6BAZBgv.png) **PDN(power delivery network)** 相關知識如下 1. 簡單來說就是**供電網路** 2. https://semiengineering.com/knowledge_centers/low-power/low-power-design/power-delivery-network-pdn/ ### 3. Place #### 1. Global placement without placed IOs, timing-driven, and routability-driven 在不考慮IOs、timing和繞線的前提下先對instance進行第一次global placement ![](https://i.imgur.com/O4ZGbog.png) #### 2. IO placement (non-random) 接著進行IO placement,這部會根據剛剛進行完的GP結果,以instance擺放位置為基礎,對pin進行位置的調整,以符合最佳的擺放結果 ![](https://i.imgur.com/Rqmshtu.png) #### 3. Global placement with placed IOs, timing-driven, and routability-driven. 在上一步擺完IO之後,就可以進行繞線、timing的考慮了,因此此步驟就是在考慮這些與IO相連因素的前提底下再進行一次global placement ![](https://i.imgur.com/6OUxOx7.png) #### 4. Resizing & Buffering 接著進行Resizing和Buffering,相關的功能和進行的原因如下所示 **resizing** 對某些電路進行resizing(如電晶體),可以使他滿足timing constraints,還有提升電路的performance。 **Buffering** Buffering包含在某些電路中加入buffer gates減輕附載,還有透過減少電容或電阻等元件的寄生特性影響程度來改善信號完整度(signal integrity) ![](https://i.imgur.com/e8sAGJR.png) 做以上行為是為了符合.sdc檔案定義的timing、power規定 #### 5. Detail placement 在這個步驟直接進行了legalization和detail placement,使電路符合constrains並減少HPWL ![](https://i.imgur.com/3F74k8y.png) ### 4. CTS **Clock tree synthesis(CTS)** 是數位電路設計和實現中重要的一步,因為它在將clock信號分佈到電路的不同部分中起著關鍵作用。clock信號用於同步電路中不同元件的操作,並且對電路的正常運作至關重要。clock tree必須精心設計,以滿足電路的performance和reliability要求,例如low skew,low jitter和fast clock period。 詳細介紹請見 1. https://ithelp.ithome.com.tw/articles/10286131?sc=rss.qu #### 1. Run TritonCTS 使用TritonCTS進行CTS-award的調整,如下圖所示,紅框框出的cell就是經過CTS調整的cell範例(和上圖detail placement完的圖進行比較) ![](https://i.imgur.com/5FjqxDh.png) 另一個可以看出明顯變化的是clock (觀察方法:用ctrl + F叫出Find視窗,並打ckl*,搜尋net就可) 下面第一張圖是剛做完place,尚未開始做cts的clk分布,可以看到完全就是直接連到clk pin,沒有任何的支狀分布 ![](https://i.imgur.com/sHsk082.png) 第二章圖則是有進行完CTS之後的樣子,可以看到clock tree的分布已經平衡非常多了 ![](https://i.imgur.com/Ej1uFxp.png) 值得注意的是,可以看到上圖中有五個H形狀instance,那是在clock tree的連接處新加入的clock buffer,用於增強驅動能力以及漸少時間落差,在下圖中可以看到clock buffer的詳細資訊 ![](https://i.imgur.com/X23t7tH.png) clock buffer相關資訊請參考 1. https://blog.csdn.net/icxiaoge/article/details/79995681 #### 2. Filler cell insertion 進行完此步驟後可以發現在圖中有許多filler cells被填入 ![](https://i.imgur.com/1p1rAgz.png) **Filler cell insertion**可以提高數位電路的性能和可靠性。他會將filler cells放入電路中,以優化clock tree的性能。 作用: 1. 減少clock tree中的filler cells和jitter。 2. 提高clock tree的功率效率。filler cells可以使clock tree增加電容,降低時鐘樹的功耗。 ### 5. Routing #### 1. Run global route 在完成CTS之後,就進到global route的部分,可以看到下圖是完成global route之後的連線關係 ![](https://i.imgur.com/tkx2sjb.png) #### 2. Run detailed route 在完成global routing之後,就會進到detail routing的部分,下圖是完成繞線之後的樣子,以及用顏色區分layer的顯示結果 ![](https://i.imgur.com/jrAcgoL.png) ![](https://i.imgur.com/hwkdggy.png) + routing flow 參考(以icc為例): https://blog.csdn.net/weixin_46752319/article/details/107564592 ### 6.Finishing 最後是finish的部分,可以看到下圖就已經是完成finishing後最終的樣子了,但這還不是真正可以給別人讀得懂的格式因此需要做一些最後的處理和轉檔。 ![](https://i.imgur.com/t3JkGWE.png) 下圖是finish在makefile部分中的截圖,可以看出他所讀入的檔案是 ![](https://i.imgur.com/Pq62dv7.png) --- ## Place分項介紹 ### makeFile Place區塊原始碼 # ============================================================================== # ____ _ _ ____ _____ # | _ \| | / \ / ___| ____| # | |_) | | / _ \| | | _| # | __/| |___ / ___ \ |___| |___ # |_| |_____/_/ \_\____|_____| # place: $(RESULTS_DIR)/3_place.odb \ $(RESULTS_DIR)/3_place.sdc # ============================================================================== # STEP 1: Global placement without placed IOs, timing-driven, and routability-driven. #------------------------------------------------------------------------------- $(RESULTS_DIR)/3_1_place_gp_skip_io.odb: $(RESULTS_DIR)/2_floorplan.odb $(RESULTS_DIR)/2_floorplan.sdc $(LIB_FILES) ($(TIME_CMD) $(OPENROAD_CMD) $(SCRIPTS_DIR)/global_place_skip_io.tcl -metrics $(LOG_DIR)/3_1_place_gp_skip_io.json) 2>&1 | tee $(LOG_DIR)/3_1_place_gp_skip_io.log # STEP 2: IO placement (non-random) #------------------------------------------------------------------------------- $(RESULTS_DIR)/3_2_place_iop.odb: $(RESULTS_DIR)/3_1_place_gp_skip_io.odb $(IO_CONSTRAINTS) ifndef IS_CHIP ($(TIME_CMD) $(OPENROAD_CMD) $(SCRIPTS_DIR)/io_placement.tcl -metrics $(LOG_DIR)/3_2_place_iop.json) 2>&1 | tee $(LOG_DIR)/3_2_place_iop.log else cp $< $@ endif # STEP 3: Global placement with placed IOs, timing-driven, and routability-driven. #------------------------------------------------------------------------------- $(RESULTS_DIR)/3_3_place_gp.odb: $(RESULTS_DIR)/3_2_place_iop.odb $(RESULTS_DIR)/2_floorplan.sdc $(LIB_FILES) ($(TIME_CMD) $(OPENROAD_CMD) $(SCRIPTS_DIR)/global_place.tcl -metrics $(LOG_DIR)/3_3_place_gp.json) 2>&1 | tee $(LOG_DIR)/3_3_place_gp.log # STEP 4: Resizing & Buffering #------------------------------------------------------------------------------- $(RESULTS_DIR)/3_4_place_resized.odb: $(RESULTS_DIR)/3_3_place_gp.odb $(RESULTS_DIR)/2_floorplan.sdc ($(TIME_CMD) $(OPENROAD_CMD) $(SCRIPTS_DIR)/resize.tcl -metrics $(LOG_DIR)/3_4_resizer.json) 2>&1 | tee $(LOG_DIR)/3_4_resizer.log clean_resize: rm -f $(RESULTS_DIR)/3_4_place_resized.odb # STEP 5: Detail placement #------------------------------------------------------------------------------- $(RESULTS_DIR)/3_5_place_dp.odb: $(RESULTS_DIR)/3_4_place_resized.odb ($(TIME_CMD) $(OPENROAD_CMD) $(SCRIPTS_DIR)/detail_place.tcl -metrics $(LOG_DIR)/3_5_opendp.json) 2>&1 | tee $(LOG_DIR)/3_5_opendp.log $(RESULTS_DIR)/3_place.odb: $(RESULTS_DIR)/3_5_place_dp.odb cp $< $@ $(RESULTS_DIR)/3_place.sdc: $(RESULTS_DIR)/2_floorplan.sdc cp $< $@ # Clean Targets #------------------------------------------------------------------------------- clean_place: rm -f $(RESULTS_DIR)/3_*place*.odb rm -f $(RESULTS_DIR)/3_place.sdc rm -f $(REPORTS_DIR)/3_* rm -f $(LOG_DIR)/3_* ### 分段介紹 ### 1. Global placement without placed IOs, timing-driven, and routability-driven #### 原始碼 我們先來看看這段程式碼和他所做的事情 $(RESULTS_DIR)/3_1_place_gp_skip_io.odb: $(RESULTS_DIR)/2_floorplan.odb $(RESULTS_DIR)/2_floorplan.sdc $(LIB_FILES) ($(TIME_CMD) $(OPENROAD_CMD) $(SCRIPTS_DIR)/global_place_skip_io.tcl -metrics $(LOG_DIR)/3_1_place_gp_skip_io.json) 2>&1 | tee $(LOG_DIR)/3_1_place_gp_skip_io.log 這段程式碼執行名為 global_place_skip_io.tcl 的 Tcl 腳本,並將腳本的輸出和錯誤信息重定向到 log_dir 目錄中的 3_1_place_gp_skip_io.log 文件中。此外,腳本的運行時間將被記錄在同目錄中的 3_1_place_gp_skip_io.log 文件中。腳本的運行結果將被保存到 results_dir 目錄中的 3_1_place_gp_skip_io.odb 文件中。 接著我們就再仔細研究一下global_place_skip_io.tcl做了什麼 #### global_place_skip_io.tcl 首先載入上一段floorplan的結果檔2_floorplan.odb和2_floorplan.sdc source $::env(SCRIPTS_DIR)/load.tcl load_design 2_floorplan.odb 2_floorplan.sdc "Starting global placement" 接著檢查top down IO Constraints是否已經存在,如果已經存在就可以跳過global_place_skip_io這段,直接進行下一個部分 if {[info exists ::env(FLOORPLAN_DEF)] || ([info exists ::env(HAS_IO_CONSTRAINTS)] && $::env(HAS_IO_CONSTRAINTS) != 0)} { puts "Has top down IO Constraints. Skip global placement without IOs" } else { + **top down IO Constraints**解釋 "Top down IO Constraints" refers to the practice of placing input/output terminals at the top of the placement process and considering their positions as the primary factor in placement. This method allows the placement process to more accurately follow the position constraints of the input/output terminals and can reduce problems caused by the misplacement of input/output terminals. To use a placement process with "Top down IO Constraints", it is usually necessary to set the position constraints of the input/output terminals in the design before performing the placement process. This ensures that the placement process can properly consider the positions of the input/output terminals. 如果沒有現有的top down IO Constraints,則開始進行核心部分。 此處會先檢查PLACE_DENSITY的lower bound,然後設定place_density相關變數 # check the lower boundary of the PLACE_DENSITY and add PLACE_DENSITY_LB_ADDON if it exists if {[info exist ::env(PLACE_DENSITY_LB_ADDON)]} { set place_density_lb [gpl::get_global_placement_uniform_density \ -pad_left $::env(CELL_PAD_IN_SITES_GLOBAL_PLACEMENT) \ -pad_right $::env(CELL_PAD_IN_SITES_GLOBAL_PLACEMENT)] set place_density [expr $place_density_lb + $::env(PLACE_DENSITY_LB_ADDON) + 0.01] if {$place_density > 1.0} { set place_density 1.0 } } else { set place_density $::env(PLACE_DENSITY) } 接著進行global_placement,並檢查GLOBAL_PLACEMENT_ARGS矩陣是否有內容,有的話就一樣做為命令跟在後面。 ```bash if { 0 != [llength [array get ::env GLOBAL_PLACEMENT_ARGS]] } { global_placement -skip_io -density $place_density \ -pad_left $::env(CELL_PAD_IN_SITES_GLOBAL_PLACEMENT) \ -pad_right $::env(CELL_PAD_IN_SITES_GLOBAL_PLACEMENT) \ {*}$::env(GLOBAL_PLACEMENT_ARGS) } else { global_placement -skip_io -density $place_density \ -pad_left $::env(CELL_PAD_IN_SITES_GLOBAL_PLACEMENT) \ -pad_right $::env(CELL_PAD_IN_SITES_GLOBAL_PLACEMENT) } } ``` + 命令解釋 + -skip_io:忽略io + -density:給予密度參數 + pad_right & pad_left:指定在global placement過程中保留的區域。 + {*}$::env(GLOBAL_PLACEMENT_ARGS)解釋: + {*} 字符串是一種特殊的擴展。它允許在命令行中傳遞數組的所有元素作為命令的參數。因此,這句話的意思是將名為 GLOBAL_PLACEMENT_ARGS 的數組中的所有元素作為 global_placement 命令的參數。 + 例如,假設 GLOBAL_PLACEMENT_ARGS 數組的值為 {-seed 123 -timing_driven},則這句話將會被解釋為: global_placement -skip_io -density $place_density \ -pad_left $::env(CELL_PAD_IN_SITES_GLOBAL_PLACEMENT) \ -pad_right $::env(CELL_PAD_IN_SITES_GLOBAL_PLACEMENT) \ -seed 123 -timing_driven 最後,腳本使用 write_db 命令將global placement結果保存到 3_1_place_gp_skip_io.odb 中。 if {![info exists save_checkpoint] || $save_checkpoint} { write_db $::env(RESULTS_DIR)/3_1_place_gp_skip_io.odb } ### 2. IO placement (non-random) #### 原始碼 $(RESULTS_DIR)/3_2_place_iop.odb: $(RESULTS_DIR)/3_1_place_gp_skip_io.odb $(IO_CONSTRAINTS) ifndef IS_CHIP ($(TIME_CMD) $(OPENROAD_CMD) $(SCRIPTS_DIR)/io_placement.tcl -metrics $(LOG_DIR)/3_2_place_iop.json) 2>&1 | tee $(LOG_DIR)/3_2_place_iop.log else cp $< $@ endif 這段 Tcl 程式碼有兩個主要部分: 1. 建立目標文件: $(RESULTS_DIR)/3_2_place_iop.odb。 2. 建立依賴文件列表: $(RESULTS_DIR)/3_1_place_gp_skip_io.odb 和 $(IO_CONSTRAINTS)。 程式碼的主體部分是一個帶有 ifndef 和 else 分支的 if 語句。ifndef 分支檢查變量 IS_CHIP 是否未定義。如果是這樣,則執行 io_placement.tcl 腳本。否則,將依賴文件 $(RESULTS_DIR)/3_1_place_gp_skip_io.odb 複製到目標文件 $(RESULTS_DIR)/3_2_place_iop.odb 中。 而IS_CHIP的定義要往上找到floorplan的部分,如下圖所示 ![](https://i.imgur.com/HF5Ru0i.png) 這段 Tcl 程式碼使用 ifneq 命令檢查變量 FOOTPRINT 和 FOOTPRINT_TCL 是否未定義。如果任一變量未定義,則定義變量 IS_CHIP。 #### io_placement.tcl 首先一樣載入load.tcl,並用其load_design命令載入上一個步驟完成的.odb檔 source $::env(SCRIPTS_DIR)/load.tcl load_design 3_1_place_gp_skip_io.odb 2_floorplan.sdc "Starting io placement" 接著如果發現已經有FLOORPLAN_DEF檔案,就跳過IO palcement階段,否則進行IO placement if {[info exists ::env(FLOORPLAN_DEF)]} { puts "Skipping IO placement as DEF file was used to initialize floorplan." } else { 進行IO placement時第一步先讀入IO_CONSTRAINTS if {[info exists ::env(IO_CONSTRAINTS)]} { source $::env(IO_CONSTRAINTS) } 接著用place_pins指令進行pin placement,作法類似剛剛的global_placement步驟,後面一樣跟了相關命令,包含給予定義垂直層或水平層的hor_layer、ver_layer命令,和其他跟隨命令 place_pins -hor_layer $::env(IO_PLACER_H) \ -ver_layer $::env(IO_PLACER_V) \ {*}$::env(PLACE_PINS_ARGS) } 最後一樣進行存檔 if {![info exists save_checkpoint] || $save_checkpoint} { write_db $::env(RESULTS_DIR)/3_2_place_iop.odb } ### 3. Global placement with placed IOs, timing-driven, and routability-driven #### 原始碼 $(RESULTS_DIR)/3_3_place_gp.odb: $(RESULTS_DIR)/3_2_place_iop.odb $(RESULTS_DIR)/2_floorplan.sdc $(LIB_FILES) ($(TIME_CMD) $(OPENROAD_CMD) $(SCRIPTS_DIR)/global_place.tcl -metrics $(LOG_DIR)/3_3_place_gp.json) 2>&1 | tee $(LOG_DIR)/3_3_place_gp.log 一樣讀入上一步的檔案並呼叫本段落的腳本global_place.tcl #### global_place.tcl 首先一樣讀入檔案,在此和先前的tcl不同的是有先用set_dont_use設定不要使用的cell utl::set_metrics_stage "globalplace__{}" source $::env(SCRIPTS_DIR)/load.tcl load_design 3_2_place_iop.odb 2_floorplan.sdc "Starting global placement" set_dont_use $::env(DONT_USE_CELLS) 接著設定fastroute layer相關事項,如果已經存在FASTROUTE_TCL檔案,則直接使用,否則使用else中的命令進行 # set fastroute layer reduction if {[info exist env(FASTROUTE_TCL)]} { source $env(FASTROUTE_TCL) } else { set_global_routing_layer_adjustment $env(MIN_ROUTING_LAYER)-$env(MAX_ROUTING_LAYER) 0.5 set_routing_layers -signal $env(MIN_ROUTING_LAYER)-$env(MAX_ROUTING_LAYER) set_macro_extension 2 } + FastRoute 相關介紹: https://openroad.readthedocs.io/en/latest/main/src/grt/README.html 然後進行和global_place_skip_io一樣的place_density設定 # check the lower boundary of the PLACE_DENSITY and add PLACE_DENSITY_LB_ADDON if it exists if {[info exist ::env(PLACE_DENSITY_LB_ADDON)]} { set place_density_lb [gpl::get_global_placement_uniform_density \ -pad_left $::env(CELL_PAD_IN_SITES_GLOBAL_PLACEMENT) \ -pad_right $::env(CELL_PAD_IN_SITES_GLOBAL_PLACEMENT)] set place_density [expr $place_density_lb + ((1.0 - $place_density_lb) * $::env(PLACE_DENSITY_LB_ADDON)) + 0.01] if {$place_density > 1.0} { utl::error FLW 24 "Place density exceeds 1.0 (current PLACE_DENSITY_LB_ADDON = $::env(PLACE_DENSITY_LB_ADDON)). Please check if the value of PLACE_DENSITY_LB_ADDON is between 0 and 0.99." } } else { set place_density $::env(PLACE_DENSITY) } 下一步進行global_placement_args的設定,根據此design是要以GPL_ROUTABILITY_DRIVEN的方式進行還是要以GPL_TIMING_DRIVEN的方式進行。 set global_placement_args "" if {$::env(GPL_ROUTABILITY_DRIVEN)} { append global_placement_args " -routability_driven" } if {$::env(GPL_TIMING_DRIVEN)} { append global_placement_args " -timing_driven" } 再來也是global_place_skip_io中有出現過的部分,使用global_placement命令進行global placement if { 0 != [llength [array get ::env GLOBAL_PLACEMENT_ARGS]] } { global_placement -density $place_density \ -pad_left $::env(CELL_PAD_IN_SITES_GLOBAL_PLACEMENT) \ -pad_right $::env(CELL_PAD_IN_SITES_GLOBAL_PLACEMENT) \ {*}$global_placement_args \ {*}$::env(GLOBAL_PLACEMENT_ARGS) } else { global_placement -density $place_density \ -pad_left $::env(CELL_PAD_IN_SITES_GLOBAL_PLACEMENT) \ -pad_right $::env(CELL_PAD_IN_SITES_GLOBAL_PLACEMENT) \ {*}$global_placement_args } 下面這段是使用estimate_parasitics指令計算placement的寄生效應,並進行儲存 estimate_parasitics -placement source $::env(SCRIPTS_DIR)/report_metrics.tcl report_metrics "global place" false false if {![info exists save_checkpoint] || $save_checkpoint} { write_db $::env(RESULTS_DIR)/3_3_place_gp.odb } ### 4. Resizing & Buffering #### 原始碼 $(RESULTS_DIR)/3_4_place_resized.odb: $(RESULTS_DIR)/3_3_place_gp.odb $(RESULTS_DIR)/2_floorplan.sdc ($(TIME_CMD) $(OPENROAD_CMD) $(SCRIPTS_DIR)/resize.tcl -metrics $(LOG_DIR)/3_4_resizer.json) 2>&1 | tee $(LOG_DIR)/3_4_resizer.log clean_resize: rm -f $(RESULTS_DIR)/3_4_place_resized.odb 此部分使用resize.tcl進行,並定義了clean_resize清除指令 #### resize.tcl 首先一樣進行初始設定 utl::set_metrics_stage "placeopt__{}" source $::env(SCRIPTS_DIR)/load.tcl load_design 3_3_place_gp.odb 2_floorplan.sdc "Starting resizer" 定義print_banner這個指令 proc print_banner {header} { puts "\n==========================================================================" puts "$header" puts "--------------------------------------------------------------------------" } 在tcl語言中proc可以定義一個function,詳細用法可以參考以下網站: http://vaplab.ee.ncu.edu.tw/chinese/pcchang/course2004b/comsp/network/3.4.htm 接著計算寄生電容 estimate_parasitics -placement 接下來這段是對utl中的metrics_stages_進行push和pop,把需要的狀態"placeopt__{}pre_opt"存進metrics_stages_,再執行report_metrics.tcl,做metric的回報,並最後再把它pop掉 utl::push_metrics_stage "placeopt__{}__pre_opt" source $::env(SCRIPTS_DIR)/report_metrics.tcl report_metrics "resizer pre" false false utl::pop_metrics_stage 印出instance_count和pin_count print_banner "instance_count" puts [sta::network_leaf_instance_count] print_banner "pin_count" puts [sta::network_leaf_pin_count] puts "" 設定DONT_USE_CELLS set_dont_use $::env(DONT_USE_CELLS) 如果這個designs是chip-level的話,不要加入buffer # Do not buffer chip-level designs if {![info exists ::env(FOOTPRINT)]} { puts "Perform port buffering..." buffer_ports } puts "Perform buffer insertion..." repair_design 上面區塊中的buffer_ports和repair_design詳細用法與功能可以參考: https://github.com/The-OpenROAD-Project/OpenROAD/tree/master/src/rsz 用TIE_SEPARATION設定tie_separation,沒有則設成0 if { [info exists env(TIE_SEPARATION)] } { set tie_separation $env(TIE_SEPARATION) } else { set tie_separation 0 } 然後對tie cell分別進行repair # Repair tie lo fanout puts "Repair tie lo fanout..." set tielo_cell_name [lindex $env(TIELO_CELL_AND_PORT) 0] set tielo_lib_name [get_name [get_property [lindex [get_lib_cell $tielo_cell_name] 0] library]] set tielo_pin $tielo_lib_name/$tielo_cell_name/[lindex $env(TIELO_CELL_AND_PORT) 1] repair_tie_fanout -separation $tie_separation $tielo_pin # Repair tie hi fanout puts "Repair tie hi fanout..." set tiehi_cell_name [lindex $env(TIEHI_CELL_AND_PORT) 0] set tiehi_lib_name [get_name [get_property [lindex [get_lib_cell $tiehi_cell_name] 0] library]] set tiehi_pin $tiehi_lib_name/$tiehi_cell_name/[lindex $env(TIEHI_CELL_AND_PORT) 1] repair_tie_fanout -separation $tie_separation $tiehi_pin + **tie cell** 介紹: + https://teamvlsi.com/2021/08/tie-cells-in-physical-design.html + about **Electrostatic discharge(ESD) problem**: + https://en.wikipedia.org/wiki/Electrostatic_discharge + https://www.edaboard.com/threads/how-tie-hi-tie-low-cells-work-on-esd-problem.63856/ 最後進行report和存檔 # hold violations are not repaired until after CTS # post report print_banner "report_floating_nets" report_floating_nets source $::env(SCRIPTS_DIR)/report_metrics.tcl report_metrics "resizer" true false print_banner "instance_count" puts [sta::network_leaf_instance_count] print_banner "pin_count" puts [sta::network_leaf_pin_count] puts "" if {![info exists save_checkpoint] || $save_checkpoint} { write_db $::env(RESULTS_DIR)/3_4_place_resized.odb } ### 5. Detail placement #### 原始碼 ($(TIME_CMD) $(OPENROAD_CMD) $(SCRIPTS_DIR)/detail_place.tcl -metrics $(LOG_DIR)/3_5_opendp.json) 2>&1 | tee $(LOG_DIR)/3_5_opendp.log $(RESULTS_DIR)/3_place.odb: $(RESULTS_DIR)/3_5_place_dp.odb cp $< $@ $(RESULTS_DIR)/3_place.sdc: $(RESULTS_DIR)/2_floorplan.sdc cp $< $@ 使用detail_place.tcl處理詳細的細節,並結果儲存在RESULTS_DIR底下 #### detail_place.tcl 首先一樣設定metrics_stage並讀入上一步的檔案 utl::set_metrics_stage "detailedplace__{}" source $::env(SCRIPTS_DIR)/load.tcl load_design 3_4_place_resized.odb 2_floorplan.sdc "Starting detailed placement" source $::env(PLATFORM_DIR)/setRC.tcl 設定placement_padding set_placement_padding -global \ -left $::env(CELL_PAD_IN_SITES_DETAIL_PLACEMENT) \ -right $::env(CELL_PAD_IN_SITES_DETAIL_PLACEMENT) 進行detail placement detailed_placement 指令細節詳見 https://github.com/The-OpenROAD-Project/OpenROAD/blob/ef5421b408f17fa3556a48824c5b26590ecd9169/src/dpl/README.md 接著執行**improve_placement** if {[info exists ::env(ENABLE_DPO)] && $::env(ENABLE_DPO)} { if {[info exist ::env(DPO_MAX_DISPLACEMENT)]} { improve_placement -max_displacement $::env(DPO_MAX_DISPLACEMENT) } else { improve_placement } } 指令細節詳見 1. https://github.com/The-OpenROAD-Project/OpenROAD/blob/32620a14a9c4ae342e1691250405719f5b5bcee4/src/dpo/src/Optdp.tcl 然後執行**optimize_mirroring**,過程是以y軸鏡像翻轉instance以降低total wirelength (HPWL) optimize_mirroring 指令細節詳見 1. https://github.com/The-OpenROAD-Project/OpenROAD/blob/ef5421b408f17fa3556a48824c5b26590ecd9169/src/dpl/README.md 2. https://github.com/The-OpenROAD-Project/OpenROAD/blob/53841647e23d364a7552d95136a9da387fb7a16d/src/dpl/src/Opendp.tcl 接著用**check_placement**檢查整個place是否合法 utl::info FLW 12 "Placement violations [check_placement -verbose]." 指令細節詳見 1. https://github.com/The-OpenROAD-Project/OpenROAD/blob/e38cd4158ee826ed2d0b2968767ba7f9a09d9415/src/rsz/README.md 2. https://github.com/The-OpenROAD-Project/OpenROAD/blob/53841647e23d364a7552d95136a9da387fb7a16d/src/dpl/src/Opendp.tcl 再來用estimate_parasitics計算RC parasitics estimate_parasitics -placement 指令細節詳見 1. https://github.com/The-OpenROAD-Project/OpenROAD/blob/0cc6cb1bbdfb547a3f1be87908cdabe52f205401/src/grt/README.md 2. https://github.com/The-OpenROAD-Project/OpenROAD/blob/e38cd4158ee826ed2d0b2968767ba7f9a09d9415/src/rsz/README.md 最後,就一如往常的存檔和report,place的部分就全部完成了 source $::env(SCRIPTS_DIR)/report_metrics.tcl report_metrics "detailed place" true false if {![info exists save_checkpoint] || $save_checkpoint} { write_db $::env(RESULTS_DIR)/3_5_place_dp.odb } ### 想進一步了解place相關細節請參考 #### global placement 部分 https://openroad.readthedocs.io/en/latest/main/src/gpl/README.html #### global placement tcl commands https://openroad.readthedocs.io/en/latest/main/src/gpl/doc/TclCommands.html #### pin placement https://openroad.readthedocs.io/en/latest/main/src/ppl/README.html #### detail placement 1. https://github.com/The-OpenROAD-Project/OpenROAD/tree/master/src/dpl 2. https://dl.acm.org/doi/10.1145/3299874.3318012 --- ## RePlAce 在place的過程使用了許多的演算法,如global placement中的RePLAce、detail placement中使用的OpenDP等,而這次我們主要嘗試使用RePLAce進行操作和深入研究 ### 官方參考資料 #### GitHub https://github.com/The-OpenROAD-Project/RePlAce #### 說明文件 https://openroad.readthedocs.io/en/latest/main/src/gpl/README.html #### 相關paper https://ieeexplore.ieee.org/abstract/document/8418790 ### 參數調整 在global placement當中有許多可以調整的參數,詳細的使用說明如下 #### 參數介紹 global_placement [-skip_initial_place] [-incremental] [-bin_grid_count grid_count] [-density density] [-init_density_penalty init_density_penalty] [-init_wirelength_coef init_wirelength_coef] [-min_phi_coef min_phi_coef] [-max_phi_coef max_phi_coef] [-overflow overflow] [-initial_place_max_iter max_iter] [-initial_place_max_fanout max_fanout] [-verbose_level verbose_level] + **Flow Control** + **skip_initial_place** : Skip the initial placement (BiCGSTAB solving) before Nesterov placement. IP improves HPWL by ~5% on large designs. Equal to '-initial_place_max_iter 0' + **incremental** : Enable the incremental global placement. Users would need to tune other parameters (e.g. init_density_penalty) with pre-placed solutions. + **Tuning Parameters** + **bin_grid_count** : Set bin grid's counts. Default: Defined by internal algorithm. [64,128,256,512,..., int] + **density** : Set target density. Default: 0.70 [0-1, float] + **init_density_penalty** : Set initial density penalty. Default: 8e-5 [1e-6 - 1e6, float] + **init_wire_lengthcoef** : Set initial wirelength coefficient. Default: 0.25 [unlimited, float] + **min_phi_coef** : Set pcof_min(µ_k Lower Bound). Default: 0.95 [0.95-1.05, float] + **max_phi_coef** : Set pcof_max(µ_k Upper Bound). Default: 1.05 [1.00-1.20, float] + **overflow** : Set target overflow for termination condition. Default: 0.1 [0-1, float] + **initial_place_max_iter** : Set maximum iterations in initial place. Default: 20 [0-, int] + **initial_place_max_fanout** : Set net escape condition in initial place when 'fanout >= initial_place_max_fanout'. Default: 200 [1-, int] #### 調整結果 本次調整的參數有density和routability driven 或是 timing driven兩種 ##### density 下兩張圖上面是nangate45/tinyRocket在density設成0.3時跑出來placement without io的樣子(3-1),下面則是density設成0.5時的樣子。 ![](https://i.imgur.com/xVuyppR.png) ![](https://i.imgur.com/DAPxTSP.jpg) 可以看到density設成0.5時很明顯擺放的比0.3的結果更密,這是因為density代表的是該design中每個bin可以擺多少密度的cell,而0.5相較0.3更密集,所以cell會更傾向留在原本的bin當中,而相對不會擴散的這麼全面。 ##### routability driven & timing driven routability driven ![](https://i.imgur.com/poQaHqE.png) timing driven ![](https://i.imgur.com/gOvMQhd.png) 從上兩張圖可以看出許多cell擺放位置都不同,但因為design並不大,所以差異其實沒有到非常明顯。 ## 心得 這次對OpenROAD進行研究的這個PA,是我本堂課裡面最喜歡也覺得收穫最多的PA ,因為本身是EDA相關實驗室,所以一直都有接觸physical design相關的paper或是研究、甚至是演算法,但通常一項研究都只會針對某個專項進行研究,可能是global placement、也可能是legalization過程中的某個優化,但總是很少能全面的對整個EDA flow進行了解,畢竟網路上的資訊通常也是分成一個細項一個細項,難以串聯。 所以這次可以對OpenROAD進行整體的觀察和實作,其實我非常開心,可以了解到流程中的每一個細節,並且知道哪些事情儘管是研究上比較少被拿出來討論,但仍然重要的步驟。也可以看出要完成一整個晶片的製造和layout,根本不是單純顧好place、或是繞線就可以解決的事,finishing、Buffering、setup也都是重要的步驟、缺一不可。 而這樣的一份專題作業其實和CAD課程中所要教導的東西也是不謀而合,在學完了整條的EDA flow後,最後可以以實務的方式把整個flow都跑一遍,甚至改變裡面的變數,了解其中的用意,也真的是難能可貴的經驗,非常謝謝老師和老師實驗室的團隊花了這份心力來給我們進入OpenROAD世界的引導,讓我可以以無痛的方式對OpenROAD進行探索與研究,這次的經驗時數寶貴,讓我受益良多