# OpenROAD 使用心得 本次project1藉由OpenROAD-Project中的**OpenROAD-flow-scripts**(ORFS)項目來觀察IC design flow是如何藉由EDA(Electronic Design Automation)實現。 OpenROAD Flow is a full RTL-to-GDS flow built entirely on open-source tools. The project aims for automated, no-human-in-the-loop digital circuit design with 24-hour turnaround time.(本段節錄自document) - 目前只理解部分內容,並沒有全部參透,所以介紹的內容並不完全。 ## Resource ### offical site https://theopenroadproject.org ### github https://github.com/The-OpenROAD-Project/OpenROAD-flow-scripts --- ## How to Install 我使用wsl2原生gui支援的設置搭配官方網站安裝教學(採用*locally install* on ubuntu20.04) ### wsl2 support GUI https://learn.microsoft.com/zh-tw/windows/wsl/tutorials/gui-apps ### ORFS local installation https://openroad-flow-scripts.readthedocs.io/en/latest/user/BuildLocally.html --- ## 項目結構 主要從**flow**這個目錄下開始觀察。 ![](https://hackmd.io/_uploads/Hy1mg22Rh.png) ### design ![](https://hackmd.io/_uploads/Bk7gWn3R2.png) design中有各個PDK,各PDK之下還有幾個檔案,例如本次以gcd(Greatest Common Divisor)該項目舉例,而每個項目的HDL source code也都在design下的src目錄之下。 >PDK(Process Design Kit):例如design下的gf180意指GlobalFoundries 180nm --- - $config.mk$ ![](https://hackmd.io/_uploads/B1sxQnhAn.png) 只是一些簡單的環境設置,真正要的重要資訊大多不在這裡,其中我們可以透過*VERILOG_FILES*那條去得知我們的HDL source code在哪 - $constraint.sdc$ ![](https://hackmd.io/_uploads/HkplV2hR2.png) .sdc檔,全名為Synopsys design constraints,如其名是對電路的時序、面積、功耗有一定的約束,是設計前的基本規範,由使用者定義,而此檔案內的都是本來就有提供的預設值。 - $rules-base.json$ 該晶片的應有的執行後數據標準,以用於$Metric$比對,如果數值出來較該檔案中紀錄的數值更差,需要重新執行或評估。 - $metadata-base-ok.json$ run完之後的數值紀錄。 ### logs ![](https://hackmd.io/_uploads/rJou5hnCh.png) 在$make$後我們可以看到一些相關的**過程紀錄**,它會很貼心的把每個階段都分類得很清楚,可以依需求去找相對應的檔案觀察。 ### result ![](https://hackmd.io/_uploads/BygH6ph0n.png) 如果跑完會有相對應的資料夾產生:PDK下的晶片項目中的base和base下的result檔案,例如經歷floorplan處理後會有.odb和.sdc。與logs不同的是它在每個被分隔成小階段的結果外還會有整個大階段跑完的結果,例如2_1到2_6後還會有一個2_floorplan.*檔案。 ### script ![](https://hackmd.io/_uploads/SJx3RThRh.png) 自動化執行所需要的腳本檔案,也就是最重要的部分,真的去執行這些各階段任務的檔案內容,若是想要了解是如何運作的,實際上除了用$Makefile$去觀察flow外,看tcl才會知道詳細的執行過程。 --- ## OpenROAD Flow (EDA flow) ![figure1.](https://hackmd.io/_uploads/BJGMkRnA3.png) [figure1.] ![figure2.](https://hackmd.io/_uploads/SkydkGC0h.png) [figure2.] (節錄自OpenROAD-flow-scripts github & openROAD github) 該**OpenROAD FLOW(EDA FLOW)**實際運作內容我們可以透過flow目錄下的**Makefile**來了解 ![](https://hackmd.io/_uploads/HkrylR30h.png) 可以選擇其中一個來執行,利用#(comment)來控制 如前面所說我們使用規模較小的gcd(也就是default)來做觀察 (一開始安裝步驟中的Verify Installation所make的就是默認的gcd,而make gui_final顯示的也是gcd項目最後layout圖的樣子) --- ### STEP1. Synthesis ![](https://hackmd.io/_uploads/HkEm-CnR3.png) ![](https://hackmd.io/_uploads/BkG_ZCnCn.png) 可以看到該step會產生的目標為*1_synth.v和1_synth.sdc*,但.sdc是由剛剛所說的/OpenROAD-flow-scripts/flow/designs/nangate45/gcd/constraint.sdc所複製過來的,用於之後的step所用。 - 自動化部份透過*synth.tcl*來執行,其中會記錄各種log紀錄檔。 - 使用yosys將RTL code(*.v)轉換成gate-level netlist >RTL 描述的是高層次的硬體行為和date flow(data stream),而 gate-level netlist 描述的是具體的數位邏輯閘和連接。後者更接近於實際硬體的結構。 從register-transfer-level code轉成gate-level code ![](https://hackmd.io/_uploads/B1voH1a02.png) ![](https://hackmd.io/_uploads/S1TpSkT0h.png) ``` $yosys $read_verilog 1_synth.v $show ``` 原本想用show指令觀察netlist但卻毫無反應,排查問題失敗 後來嘗試直接在yosys裡面合成就可以看到了。 ``` $yosys $read_verilog gcd.v $synth $select gcd $show ``` ![](https://hackmd.io/_uploads/HJan7yT03.png) [figure. 1_synth.v netlist] 最後在這步驟來看一下晶片布局半成品圖 ``` $make gui_synth ``` ![](https://hackmd.io/_uploads/SkAing0A2.png) ![](https://hackmd.io/_uploads/Syt0hlCC2.png) 一片黑,很好,這應該是我們所要的 大概要等到第一個place動作出來我們才會可以看到有基本的圖 --- ### STEP2. Floorplan ![](https://hackmd.io/_uploads/BktXxMA0h.png) 如同前面一樣先觀察一下輸出檔案和它的依賴關係是什麼。 > .odb ODB++(Open Data Base)is a proprietary CAD-to-CAM data exchange format used in the design and manufacture of electronic devices. Its purpose is to exchange printed circuit board design information between design and manufacturing and between design tools from different EDA/ECAD vendors. reference : [wiki](https://en.wikipedia.org/wiki/ODB%2B%2B) 白話來說,大概就是macro/block等手工、半手工設計過的一些元件的擺放資訊、size大小...等等重要資訊紀錄,後續會隨著各流程而陸續增加更多資訊。 *之後有一段code是避開依賴性檢查,makefile有強大的依賴性這個特性,但對於這個project來說依賴性不一定是必須的,因為追求模組化可以使其各個階段分開執行或分別利用,但在我們make的過程中它執行時還是有相依的,每個步驟都會input前一個步驟的output,只是我們還是需要避開依賴性檢查以達到最好的利用(無圖搭配)。* #### step.2.1 Translate verilog to obd ![](https://hackmd.io/_uploads/rkqz_UyyT.png) 如同剛剛所述,將前一階段輸出的.v檔轉成.odb檔 #### step.2.2 IO Placement (random) ![](https://hackmd.io/_uploads/HkppTUJy6.png) 根據PPA(Power, Performance, Area)擺放IO 註解上寫random我猜測可能是某種並不需要正規擺放的擺放方式 但我們已經可以看到有元件顯示在gui上了(最外圈),正是剛剛擺放上去的IO pin ![](https://hackmd.io/_uploads/ryi4aIkyT.png) #### step.2.3 Timing Driven Mixed Sized Placement ![](https://hackmd.io/_uploads/B1S21wyJT.png) ![](https://hackmd.io/_uploads/ryi4aIkyT.png) 擺放後沒有元件顯示,猜測可能是gcd規模太小 後來陸續換了幾個觀察,即使是nangate45/tinyRocket也沒有看到有元件擺放 #### step.2.4 Macro Placement 根據設計經驗,macro盡量在core四周擺放。對於儲存單元來說有port很方便,但同時也功耗很大 這樣也利於接電方便供電,並且可以防止這些元件過多的pin對其他單元的layout造成影響。 ![](https://hackmd.io/_uploads/HybGAP1Ja.png) ![](https://hackmd.io/_uploads/BksAavkka.png) 這邊因為gcd沒有變化繼續看nangate45/tinyRocket ![](https://hackmd.io/_uploads/HJTmk_1k6.png) 這裡終於可以看到有個name為blockage(阻礙區)的macro被擺進來,用於預設位置。 --- #### step.2.5 Tapcell and Welltie insertion Tap cell是為了防止CMOS設計中的latch-up。 >Latch-up/閂鎖效應:指的是在積體電路中的電源和地線之間形成的短路/低阻抗路徑,導致高電流通過並損壞集成電路。它是由PNP和NPN電晶體之間的相互作用引起。這些結構類似於可控矽(SCR)。它們形成一個正反饋環路,通過短路電源線和地線,最終導致通過高電流,甚至可能永久損壞元件。 ![](https://hackmd.io/_uploads/SyIt4_yJT.png) 這次換回gcd繼續觀察,畢竟不可能不需要這個元件。 ![](https://hackmd.io/_uploads/ryALr_kyT.png) --- #### step.2.6 PDN generation ![](https://hackmd.io/_uploads/B1b3H_kka.png) 這個步驟是擺上VSS和VDD以利電源供應,顧名思義Power Delivery Network。 ![](https://hackmd.io/_uploads/ByTN8uyJ6.png) 通過gui右側的資訊可以得知 Row是VSS和VDD平行交錯擺放,以利元件擺放時上下都能接到供電跟導地 再來看到colume是一條左VSS和右VDD貫穿上下 - 總結一下Floorplan大概就是 : 1. 確定晶片尺寸和位置 2. IO,角落PAD位置(還沒有filler) 3. macro和blockage的擺放 4. VSS,VDD的分布 --- ### STEP3. Placement Placement跟floorplann很像,但這時是擺std cell/standard cells(標準元件/標準單元),所謂標準就像是已有的library中的元件,是指那些通用已設計好的cell,還是跟前一步驟所擺放手工元件有所區別的,但兩者主要的目標都是要對delay、總面積以及interconnect cost作最佳化。 正因為關係到最佳化,所以這個步驟中可能會基於幾個因素去衡量如何進行placement 1. Timing Driven 顧名思義就是指base on Timing Driven的placement。 2. Congestion Driven 在place過程中EDA tool會用global route來估算繞線的情況,所以就會考慮到壅塞的問題,以此去進行place的最佳化。 3. Power Optimization 功耗是理所當然會考慮的。 Floorplan跟Placement白話點理解可以想成先打底再去細放。 --- #### step.3.1 Global placement without placed IOs, timing-driven, and routability-driven. ![](https://hackmd.io/_uploads/HyxSnhb16.png) 進行全域佈局(Global placement)但忽略了IO port,在這個階段主要是將元件**大致**放置在其合適位置,同時有考慮到timing-driven和routability-driven。 ![](https://hackmd.io/_uploads/HyEyp2b1p.png) ![](https://hackmd.io/_uploads/Hylh63hWJp.png) 所以我們看到凌亂的擺放方式是正常的,畢竟只是大致擺放,後續會再進行最佳化。 --- #### step.3.2 IO placement (non-random) ![](https://hackmd.io/_uploads/Sy4XTnWyT.png) 這邊我們可以看到步驟名為non-random,跟前面floorplan有所區別 其中一定會有限制條件或是規則,這點顯示在*IO_CONSTRANINTS*這個文件的引用上。 而openROAD程式碼有更新過,現在都用do-step和do-copy去使整體code方面更加模組化 ![](https://hackmd.io/_uploads/ryWkwpZ1p.png) 所以這邊新增了echo方便觀察 可以得知這裡用的.tcl是*flow/scripts/io_placement.tcl* 而先前floorplan沒有產生相對應的def檔案,應該是包含在.odb了 ![](https://hackmd.io/_uploads/SJInK6-J6.png) 進入else後這個gcd項目沒有*IO_CONSTRAINTS*,所以繼續往下執行再用puts去trace的結果是*IO_PLACE_H=metal5, IO_PLACE_V=metal6*,對應下圖。 ![](https://hackmd.io/_uploads/BJKQo6-yT.png) ![](https://hackmd.io/_uploads/SJTBs6Zyp.png) 實際透過gui會看到port各自對應其layer(正方形那個)。 ![](https://hackmd.io/_uploads/BycD0hWk6.png) 如上是這個3.2step整體圖。 --- #### step.3.3 Global placement with placed IOs, timing-driven, and routability-driven. ![](https://hackmd.io/_uploads/BkAj8A-kp.png) 與3.1不同的是**with** placed IOs. 有了IO port正確的擺放之後方能讓剛剛雜亂的cell正式佈局 ![](https://hackmd.io/_uploads/ByJ5vAb1T.png) 但白色網格無從觀察是什麼。 --- #### step.3.4 Resizing & Buffering - Resizing 依照需求調整gate大小,舉凡可能會考慮: 1. 體積占用比 2. timing 3. power consume - Buffering/ buffer insertion 增加緩衝區主要是為了改善信號完整性,信號有可能會衰減或失真,buffer可以幫助維持信號完整。 ![](https://hackmd.io/_uploads/ry26HlMJ6.png) ![](https://hackmd.io/_uploads/BJAWLlf1a.png) 不過因為name,佈局位置、size都改變了,有點難觀察出before跟after。 --- #### step.3.5 Detail placement 光看標題有些含糊,我們從makefile開始觀察 ![](https://hackmd.io/_uploads/Sy64Klzka.png) 接下來一樣去找到相對應的.tcl,也就是detail_place.tcl ![](https://hackmd.io/_uploads/ByMYYxzya.png) 可以看到中間第10行有句:detailed_placement 也是沒頭沒尾的,所以拿去google會發現它是屬於openDP支援的command: [detailed_placement](https://github.com/The-OpenROAD-Project/OpenROAD/blob/ef5421b408f17fa3556a48824c5b26590ecd9169/src/dpl/README.md) 簡單來說就是會進行一些合法化之類的最佳化,例如 1. 元件重疊:避免所有元件/單元不會在同平面重疊。 2. 網格對齊:元件要放在預先定義好的網格上,確保對齊。 (前面step3.3還搞不太清楚地那個白色網格) 3. 邊界限制:保持元件都被限制在晶片的物理邊界內。 4. ...e.t.c. ![](https://hackmd.io/_uploads/ryHwcgfy6.png) 本張小結論:基於PPA做各種Placement的最佳化。 --- ### STEP4. CTS Clock Tree Synthesis(時鐘樹綜合)主要是為了確保時鐘信號能在最短的時間內傳遞到其驅動的所有DFF(Data Filp Flop)。 對於時鐘樹綜合,主要關注以下三個指標,並希望能盡量最佳化: 1. Low Latency 希望每個時鐘信號能在最短的時間內到達它所驅動的各個sink(也就是DFF)。 2. Low Clock Skew 偏斜是指同一clock信號到達不同DFF的時間差。理想情況下是希望所有DFF同時接收到訊號,但由於實際layout、阻抗等因素的影響,會難以達成。 3. Long Common Path 希望每個時鐘信號的共同路徑能盡量長,這有助於進一步降低clock skew,從而提高整體的性能,這是因為在共同路徑下幾乎承受的同樣的環境條件,也就是傳輸訊號的速度會幾乎相同,所以這條共同的路徑越長越好。 ![](https://hackmd.io/_uploads/BkNPhgGyp.png) #### step.4.1 Run tritonCTS ![](https://hackmd.io/_uploads/HyVdZbMya.png) 在cts.tcl這段中可以看到它在裡面直接call tritonCTS的*clock_tree_synthesis*和設置相關的參數。 ![](https://hackmd.io/_uploads/S1LufbzkT.png) 老實說這裡感覺太複雜,在有限的時間內沒有得到什麼有用的觀察。 --- #### step.4.2 Filler cell insertion ![](https://hackmd.io/_uploads/B14EM-fJT.png) 由fiilcel.tcl實現,以提高整體可靠性跟改善性能。 ![](https://hackmd.io/_uploads/rkdaMZzya.png) 直接放大可以看到filler都就位了。 --- ### STEP5. Routing ![](https://hackmd.io/_uploads/BkJy6bzka.png) 如同前面的結構,熟悉的寫法 #### step.5.1 global route 那就直接看第一個tcl: global_route.tcl ![](https://hackmd.io/_uploads/H104abMyp.png) 前面第九行這個判斷式是判斷有沒有要用[fastroute](https://github.com/The-OpenROAD-Project-Attic/FastRoute) 然後重點是24行的[global_route](https://openroad.readthedocs.io/en/latest/main/src/grt/README.html) 1. 在這階段它會布局但不會走線,也就是說先無視地形連連看(想像成打草稿) 2. 實際走線還要搭配它生成的route.guide(指導各種routing時該如何穿梭於layer) 3. 最後如果沒有輸入相關的參數,它默認是會壅塞迭代20次,每5次產生一個.drc(Design Rules Check)檔案以供參考。變相來說是提供了一個能讓使用者能夠動態地指定額外的route參數。 ![](https://hackmd.io/_uploads/S1HnrMMka.png) 我把全部圈選起來,雖然不太清楚,但還是可以看到route是挺隨心所欲的。 --- #### step.5.2 detail route detail_route.tcl部分段落如下圖所示 ![](https://hackmd.io/_uploads/SJKeOGGyp.png) [detail_route](https://openroad.readthedocs.io/en/latest/main/src/grt/README.html)透過topology algo去實現最佳化。 ![](https://hackmd.io/_uploads/SkEq_GM1p.png) 執行完之後就可以看到完全體了! --- ### STEP.6 Finish ![](https://hackmd.io/_uploads/BJSLVym1a.png) 最後FINISH依賴於: - *.log* - *.v* - *.sdc* - *GDS_FNAL_FILE* 而*elapsed*會透過$genlapsedtime.py$在*log*目錄下產生對應的*.json*檔案去紀錄處理時間 ![](https://hackmd.io/_uploads/ryF-vJmJa.png)   這裡根據*$(USE_FILL)*決定是否進行*density_fill*的填充步驟;否則,它會直接複製 5_route.odb 到 6_1_fill.odb,意味著不進行填充。   density_fill也就是去做Dummy Metal的增加,晶圓廠對金屬密度有一定的規定,以防止在晶片製造中的蝕刻階段會過度蝕刻而導致影響性能,所以才要增加金屬密度。 ![](https://hackmd.io/_uploads/SJDVY17ka.png) mock測試中如如果有一些很難產生的檔案對象,例如上圖所提到的resize、CTS等等,它們都很耗時,所以若在具體測試時我們可以直接利用已有的檔案來加速模擬測試。可以看到上述都是*copy*指令。 ![](https://hackmd.io/_uploads/H1K19k71a.png) 目標一樣是GDSII,這裡使用klayout去整合包裝好的Macros,也就是IP整合。 ![](https://hackmd.io/_uploads/SylmiyXJ6.png) ![](https://hackmd.io/_uploads/BySusk7yT.png) 最後在這階段與上個merge不同的是這是針對GDS檔案之間的合併。 - DRC (Design Rule Check) 用來檢查佈局是否符合製程技術的規則。這包括規則如金屬層寬度、空間、孔徑大小等。 - CDL (Circuit Description Language) 主要用於描述模擬Netlist,通常是要用於傳遞netlist訊息給相關的simulator,如 SPICE(Simulation Program with Integrated Circuit Emphasis .cdl檔案用於LVS(Layout Versus Schematic)檢查。 - LVS (Layout Versus Schematic) cdl檔案(代表netlist)會與GDS檔案(代表佈局)進行比對,以確認它們等效。 也就這段中的*GDS_FINAL_FILE*和(OBJECTS_DIR)/6_final_concat.cdl來比較。 再來整段finish終於結束了!用*make gui_final*看一次。 ![](https://hackmd.io/_uploads/BJ41JlQk6.png) --- ## 心得   這次將這門最後的作業前移當作第一個作業我覺得是一個非常好的決定,比起一步一步看到後面,不如先用一個好上手的porject來摸摸看,而起初在觀察時因為缺少大量背景知識的情況下困步難行,後來慢慢進入軌道後發現各個執行階段的知識量都各可以拿出來做一門領域研究,而openROAD flow script是很入門款的project,所以很多內容其實跟正規的流程還是有不太一樣的地方,但模組化的設計以及code撰寫還是很值得借鏡的。 過程中幾乎每個章節都要找資料來看一下,畢竟是很陌生的領域,在最後做完報告還是覺得只是很粗略的晃過整個flow,只能有限度的了解一些樣貌,但我相信先做完這份作業後會對後續的作業也會有很大的幫助。