故事是這樣子的,無論是數位、類比還是微波電路,在晶片的最後一步,都要進行所謂的 signoff 流程,進行最終的檢查看看設計有沒有問題等等。

一般的 Signoff 流程至少包括兩個:DRC 和 LVS,有些還會加上之前提過的 RC extraction (PEX) + Post-layout simulation,以及跟 LVS 整合的 ERC。

這段稱為 Physical Verification 或 Verification,同樣的三家大廠都會推自己的解決方案:

就我個人所知(至少快十年前的資訊),在這個領域,業界標準是 Mentor 的 Calibre ,在一線的晶圓廠下線,晶圓廠開始生產前的最後一步檢查也是用 Calibre 去跑。
即便 Synopsys/Cadence 的工具也一直在進步,讓檢查速度更快、消除掉假錯、減少漏過的真錯,但結果還是以 Calibre 做標竿,沒能取代掉 Calibre 最後一線的地位;箇中理由自然也很好懂,如果有錯誤沒檢查到,一片幾百萬的光罩你要負責嗎?

也因此,到目前為止,個人用過的工具就只有 Calibre ,沒用過 IC Validator 和 Assura,下面的整理就以 Calibre 為主。

DRC

DRC 為 Design Rule Check 的簡稱,主要是在晶圓製造的時候,有些狀況會做不出來或導致良率下降, 用各金屬層的連線舉例是最常見的,檢查諸如:

  • 線寬是不是會太寬、太窄,太寬了一大坨金屬會影響晶片的平坦度、太窄了線可能做不出來直接斷掉
  • 線距會不會太近,太近了線會短路
  • 金層層和 Via 間有沒有足夠的空間,讓 Via 長不整齊也能連接

當然 DRC 不止這些,還有像:

  • 密度規則,例如以 100x100 um2 的區間,金屬密度是否太高或太低,密度太高會長不好,太低沒足夠支撐晶片可能會垮掉
  • 天線規則,連接到電晶體的金屬面積會不會太大

諸如此類,都是為了晶片製作過程中,數百道的曝光、蝕刻、金屬沉積的製程誤差導致短路或開路, 造成晶片無法正常工作浪費沙子
當然,這年頭一顆晶片上塞的電晶體數量動輒用十億為單位,可能一層金屬就有幾十億到幾百億個矩形 需要檢查彼此間的關係,要如何又快又正確的檢查就是難中之難了。

另一方面,先進製程也帶來更多的規則與更多的金屬層,例如古早味的 180nm 製程可能只有五層金屬,DRC 文件幾百頁左右;40 nm 製程就膨脹到千頁,個位數 nm 的先進製程會多多少規則可想而知。
也因此 DRC 其實非常浪費算力,就算是幾百核心平行跑,按下 enter 之後可能幾個小時才得到結果也是稀鬆平常。

DRC 怎麼跑

首先,晶圓廠一定會提供他們的 DRC 規則檔,以下就稱它為 DRC.rule 吧。
檔案內容可以分為四個部分,注意會改動的只有第一部分的設定,其餘除非你是寫 DRC 規則的那位不然千萬別亂動,這篇文章也不會深入那些細節,有機會我再寫為說明:

  • 設定
  • 圖層定義
  • 圖層運算
  • 規則檢查

設定

設定參考如下,需要改的就關於輸入的部分,你的 layout 檔、top cell 名字跟格式(一般都 GDSII 也不用改):

LAYOUT PATH "layout/CHIP.gds"
LAYOUT PRIMARY "top_cell"
LAYOUT SYSTEM GDSII

DRC MAXIMUM RESULTS 1000
DRC RESULTS DATABASE "DRC.db" ASCII
DRC SUMMARY REPORT "DRC.rep" HIER

PRECISION 1000
RESOLUTION 5

FLAG SKEW YES
FLAG OFFGRID YES
FLAG ACUTE YES
FLAG NONSIMPLE YES

執行

就這樣,有什麼就跑什麼,DRC 通常包含整體規則和密度檢查;ANTENNA 則是單獨的天線規則檢查。
加上 hier 和 turbo 選項讓它用階層式與多核心模式來加速。

calibre -drc -hier -turbo DRC.cmd
calibre -drc -hier -turbo ANTENNA.cmd

DRC 報告怎麼看

依照上面的設定會生成兩種輸出:

  1. DRC.db 這類 ASCII 格式,可以在 INNOVUS, Virtuoso 等進行匯入,在 Layout 上檢視有哪些錯誤。
  2. DRC.rep 則是文字格式,可以用文字編輯器打開它。

DRC.rep 會有幾個區段:
ORIGINAL LAYER STATISTICS
統計 calibre 從你的 layout 中,擷取出多少你定義的 LAYERw,這裡可以注意一下數量,例如我的結果:

LAYER M1 …… TOTAL Original Geometry Count = 881136

一般在全數位的 DRC,如果沒有一次過,原因大多只有一個:

匯出 gds 檔的時候圖層沒選對。

M1 應該是 LAYER 100 但你選錯設定,INNOVUS 把它對應到 87,那 Calibre 在擷取 M1 時就會一個 Count 都沒有。

RULECHECK RESULTS STATISTICS
這裡就是重中之重了,會列出每條規則的結果:

RULECHECK M1.A  …… TOTAL Result Count = 0
RULECHECK M1.B  …… TOTAL Result Count = 0
RULECHECK M1.C  …… TOTAL Result Count = 0

DRC 規則數量眾多,還會有一些錯誤是可允許的假錯,為了避免眼花漏掉不是 0 的數字,可以用 vim 輸入 /= [^0] 直接搜尋檔案中結果不是 0 的規則。

我後來是直接寫 python script,直接幫我 grep 某路徑下所有的 .rep 檔。

import os
import re

def grep_non_zero_lines(directory):
    # Regular expression to match the lines with non-zero values
    pattern = re.compile(r'RULECHECK.*?TOTAL Result Count = (?!0)')

    for root, dirs, files in os.walk(directory):
        for file in files:
            if file.endswith(".rep"):
                with open(os.path.join(root, file), 'r') as f:
                    for line in f:
                        if pattern.search(line):
                            print(f"{file}: {line.strip()}")

if __name__ == "__main__":
    grep_non_zero_lines("result")

LVS

LVS 是指 Layout Versus Schematic,也就是說 APR 軟體寫出的 Layout ,以及另外一套設計本身的示意圖 schematic,兩者進行比對是否相同。

一般來說單純的數位電路,用 ICC2 INNOVUS 這類工具從 verilog 幫你畫出來的,LVS 應該都是直接 pass 的等級,工具出錯的機會很低的。
但倘若你是類比、射頻或客製化等等,LVS 就會是個讓你頭大的東西了,網路上也不乏各種教你怎麼看 LVS 錯誤的文章;如果我哪一年想不開回去手繪 layout 再來寫文教大家。

數位電路的 LVS 背後的流程如下圖所示: LVS flowchart

  1. 從 APR 軟體中匯出的 layout,結合用到的 hard macro 與 Standard cell 成為最終的 layout CHIP.gds
  2. Calibre 會讀入 layout,萃取出內部的 device,轉為 LAYOUT.spi 的 spice 連線表
  3. 同樣從 APR 軟體中匯出帶 power/ground 的 verilog 檔
  4. 利用工具 v2lvs 將 verilog 檔結合 hard macro spice、standard cell spice,輸出 source.spi
  5. Calibre 比較 source.spi 與 layout.spi 兩者是否相符

hard macro spice 和 standard cell spice 當然也是晶圓廠提供,一般會叫 .cdl 檔。

比較時 calibre 其實是在比較兩個 spice 檔是不是同構的,不過執行 LVS 時必須在 Layout 上用 text 標上 top cell 的 Port,LVS 會用這些作為線索往下進行比較,頂層單元的節點是已知可 match 的,所以跟實際的 Graph isomorphism problem 還是稍不一樣。
與 DRC 一樣,現今電路動輒幾億幾十億顆電晶體的時候,光是把幾 GB 的 layout 讀入、從中萃取所有的元件與走線再進行比較,實務上是不會到 DRC 這麼久,但也是一項耗費算力亟待加速的工程。

LVS 設定

與 DRC 相同,修改輸入的部分,這次會有 source 和 layout 兩組輸入,修改檔名、top cell 名跟格式:

SOURCE PATH "SORUCE.spi"
SOURCE PRIMARY "top_cell"
SOURCE SYSTEM SPICE

LAYOUT PATH "CHIP.gds"
LAYOUT PRIMARY "top_cell"
LAYOUT SYSTEM GDSII

LVS REPORT "lvs.rep"

同樣的,如果是成熟製程與老練的晶圓廠,後續 LVS 高機率是不需要改動的,遇到 LVS error 再詳加研究即可。

比較可能會動到的有下面這些,就先列一下:

LAYOUT CASE         YES
SOURCE CASE         YES
LVS COMPARE CASE    NO  //YES

三個 case 確保所有的名字是否保留大小寫,以我的狀況,在 LVS.rule 裡面萃取的 device 名字叫 nmos;但 晶圓廠的 .cdl 中引入的 device 叫 NMOS;LVS COMPARE CASE YES 就會出現 LVS 錯誤。

LVS POWER NAME "VDD"
LVS GROUND NAME "GND"

定義電源與接地的名字,如果你有多組電源就會需要這樣處理,另外接地有些人會用 VSS,也可以在此修改。

LAYER M1 100
LAYER M2 100
LAYER MTOP 500
TEXT LAYER 550
port layer text 550
ATTACH 550 MTOP

這邊要注意的就是圖層了,跟 DRC 一樣,如果匯出的圖層錯了,那整個 LVS 鐵定會出錯。 上面的範例意思如下:

  • 500 層是最頂層的 top metal
  • 550 層是文字
  • 指定 550 層為識別 top cell PORT 用的文字層
  • 550 層的文字釘在 500 的 top metal 層上

如果你的 APR 工具沒有寫出 port text 的話,可以在 LVS.rule 內加上 .include "ports.txt" ,並填入下列的範例內容,自行標示各 port 的位置。

# ports.txt
# LAYOUT TEXT <port name> <x-coord> <y-coord> <layer> <cell name>
LAYOUT TEXT "clk"   55.0  990.9 550 top_cell
LAYOUT TEXT "rst_n" 155.0 990.9 550 top_cell

hardmacro spice 檔

執行 v2lvs 前,先要準備好 hard macro 相關的檔案,這邊只憑印象說明記憶體要怎麼處理。
第一是 verilog 檔,使用跟 APR 時一樣的 除了 header 之外其他都移除的 .v 檔。
另一個是 library 檔,使用 spice 的 subckt 語法,要告訴 spice 我們有 hardmacro 這個子電路, 內部因為是黑盒子所以留白就好。

module hardmacro (clk, cen, wen, addr, i_data, o_data)
  input clk;
  input cen;
  input wen;
  input [1:0] addr;
  input [7:0] i_data;
  output [7:0] o_data;
endmodule

上述的 verilog (容我稍微減少 port 寬度)就會需要一個如下的 subckt 宣告:

.SUBCKT hardmacro clk cen wen addr[0] addr[1]
i_data[0] i_data[1] i_data[2] i_data[3] i_data[4] i_data[5] i_data[6] i_data[7]
o_data[0] o_data[1] o_data[2] o_data[3] o_data[4] o_data[5] o_data[6] o_data[7]
.ENDS hardmacro

因為 array port 都需要展開,所以我也是寫一個 python script 來處理這個問題,要 parse verilog 來自動生也不是不行,只是有點殺雞用牛刀。

# Usage gen.py addr 2 i_data 8 i_data 8
import sys

def main():
    args = sys.argv[1:]
    if len(args) % 2 != 0:
        print("Arguments must come in pairs: <name> <num>")
        return

    for i in range(0, len(args), 2):
        name = args[i]
        num = int(args[i+1])
        lines = [f"{name}[{j}]" for j in range(num)]
        print("\n".join(lines))

if __name__ == "__main__":
    main()

v2lvs

實際執行,使用 v2lvs 將你 INNOVUS 寫出的 CHIP_pg.v 檔轉成 netlist spice 檔。

v2lvs -b -s xxx.cdl -v CHIP_pg.v -v hardmacro.v -l hardmacro.l \
-s1 VDD -s0 VSS -o SOURCE.spi

有任何的 .cdl 檔就用 -s 匯入,它會變成 SOURCE.spi 的 .INCLUDE 並一起進行 LVS。
-b 這個選項至關重要,如果你在 synthesis 時沒有設定 define_name_rules,design compiler 輸出的 .syn.v 會有反斜線的名字,這些會混淆 v2lvs 的判斷造成後續的 lvs 的錯誤。
-s1 VDD 和 -s0 VSS 會設定 VDD 與 VSS 為 spice 的全域變數,請填入你的電源接地名稱。

執行 lvs

直接執行就好,-spice 只是指定 calibre 把從 layout 中萃取出來的 spice 檔寫出來。
我的經驗是這幾乎沒什麼用,LVS 的本質就是電腦做圖學的比較,這是人腦不擅長的領域, 數位電路動輒幾十萬幾百萬個元件,既然電腦都解不出來了,怎麼會覺得人腦看一看可以看出問題在哪?

calibre -lvs -spice LAYOUT.spi -hier LVS.cmd  

LVS 錯誤了怎麼辦

兩手一攤
嚴格來說這是個大哉問,LVS 對的方法只有一種,出錯的方法卻有百百種,我也不是每種都遇過。 在學校做類比遇到的錯誤,現在已經沒印象也無法截圖說明。
現在我們只談數位電路,一樣的說詞:從工具出來的高機率不會出錯,不要急著開始用肉眼對 LAYOUT.spi 跟 SOURCE.spi,或是在 APR 軟體上翻來覆去的,先懷疑是否有設定沒弄對。

以下是我統整(猜測)數位電路最常出錯的原因:

1. 圖層沒設對

這點重複很多次不多講了,從 APR 軟體匯出的圖層跟 DRC LVS 設定一定要對起來,對不起來直接 GG。

2. Port 沒設對

請檢視 LVS.rep 的 Top cell 的 Port 節,下方的 Port 數量一定要對得上,在 report 找 Initial Correspondence Points 也能找到初始的 port list,請確認你的 port 都有找到。

******************************************************************
                             INFORMATION AND WARNINGS
******************************************************************
                Matched  Matched  Unmatched  Unmatched  Component
                 Layout   Source     Layout     Source  Type
                -------  -------  ---------  ---------  ---------
   Ports:            20       20          0          0

3. 大小寫比較設定

上面敘述過了,這個好像意外容易踩到,我建議是 source, layout 都要用 CASE YES,Compare 則看晶圓廠的檔案而定。

4. v2lvs -b

上面也敘述過了,我 v2lvs 沒設定 -b 的話會出現 Naming Error:

******************************************************************
                               INCORRECT OBJECTS
******************************************************************
  LEGEND:
-------
  ne  = Naming Error (same layout name found in source
      circuit, but object was matched otherwise).

其他 Error message 包括有 Net 對不起來:

*******************************************************************
                             INFORMATION AND WARNINGS
*******************************************************************
                Matched  Matched  Unmatched  Unmatched  Component
                 Layout   Source     Layout     Source       Type
                -------  -------  ---------  ---------  ---------
   Ports:            19       19          0          0
   Nets:          57080    57079          0          0

實際檢視 layout,會看到有一條線在 source.spi 那邊,名字多一條反斜線而被算成同一條,但在 layout 上是被兩個 inverter 給切割開的。
這個問題過去我都是自行合成,會設定 design compiler 的 define_name_rules 避掉這個問題, 這次第一次用別人合成的檔案做 layout 就踩到了,我個人懷疑用 Naming Error 找到所有的文章都是在討論這個錯誤。

LVS 報告怎麼看

LVS 報告倒是沒什麼好看,如果覺得 lvs.rep 開頭的 warning 太多,可以使用 vim 開檔搜尋,一秒來到結果的位置:

vim +/OVERALL lvs.rep

所以希望大家都能輕鬆過 LVS,只要 LVS.rep 裡面出現這個笑臉就沒問題啦 =b。 LVS pass

Makefile

又到文章最後面的 Makefile 時間,以下是我執行 DRC 與 LVS 時使用的 Makefile。
drc 和 antenna 會有下面的 watch,是因為 DRC 一般花的時間都很久,用 watch 配 ls 監視結果資料夾有沒有產生輸出檔案,這樣就可以把視窗開著放一邊去做其他事 (X) 看動畫 (O)。

drc: FORCE
  calibre -drc -hier -turbo_all DRC.rule
  # watch "ls -lh calibre_result/"

antenna: FORCE
  calibre -drc -hier -turbo_all ANTENNA.rule
  # watch "ls -lh calibre_result/"

v2lvs: CHIP_pg.v
  v2lvs -b -s TECH.cdl -v $< -s1 VDD -s0 GND -o SOURCE.spi

lvs: FORCE
  calibre -lvs -spice LAYOUT.spi -hier LVS.cmd