1978 - GDSII 版圖格式:把整顆晶片裝進一個檔案#
案件摘要#
1978 年,Calma 公司為其 GDS(Graphic Data System)數位化系統推出 GDSII Stream Format—— 一種記錄式二進位格式,把版圖的層次結構(library / cell / boundary / path / sref)壓進單一檔案。 GDSII 在 1980 年代成為版圖交換的事實標準,至今仍是 tape-out 交棒給晶圓廠的統一語言。
前因 -- 為什麼會有這個案子#
- 版圖資料各說各話:1970 年代的 CAD 系統(Calma、Applicon、Auto-trol)各有私有的內部格式,設計公司與 mask house 之間交換版圖得靠磁帶「翻譯」,錯一個座標就整批報廢。
- 數位化儀器需要統一輸出:Calma 的 GDS 數位化工作站(digitizer)把圖紙上的版圖轉成向量資料;要讓下游(製版機、光繪機、各家 CAD)讀得懂,必須有一個中立、可串流(stream)的格式——GDSII 由此誕生,「stream」意即資料以連續記錄(record)依序寫入磁帶。
- 層次化是唯一的救星:一顆晶片的版圖由大量重複的單元(cell)構成——RAM 位元、標準閘、IO pad。若每個 instance 都展開成實際幾何,檔案大小為 \(O(\text{geometry})\) ;若用層次引用(sref / array),只需 \(O(\text{instances})\) :
一個 100 圖形的 RAM 位元被引用 10 萬次,層次化描述就省下約 100 倍的儲存量。 - 關鍵推理:Calma 選擇「記錄式二進位 + 層次引用」而非純文字展開——磁帶空間與讀取速度都撐不住展開式描述,層次化結構同時解決儲存、傳輸與顯示三個問題。
線索與推理 -- 數學式、程式、理論#
1. 案件現場:GDSII 的資料結構#
GDSII 檔案是一棵樹:library 底下掛 cell,cell 底下掛元素(element):
| 元素 | 意義 | 內容 |
|---|---|---|
| LIBRARY / BGNLIB | 檔案庫 | 名稱、時間戳 |
| STRUCTURE / BGNSTR | 單元(cell) | 名稱、時間戳 |
| BOUNDARY | 多邊形版圖 | LAYER、DATATYPE、XY 座標 |
| PATH | 走線(有寬度的線段) | LAYER、WIDTH、XY |
| SREF | 單元引用(instance) | SNAME、座標(可旋轉/鏡射) |
| AREF | 陣列引用 | SNAME、行列數、間距 |
| TEXT | 文字標註 | TEXTTYPE、字串 |
| ENDSTR / ENDLIB | 結尾記錄 | — |
層次引用 SREF/AREF 是 GDSII 的靈魂:單元只定義一次,被引用任意次。
2. 記錄式二進位格式:length + type + payload#
每筆記錄的開頭是 4 個位元組:
- length:含 4 位元組 header 在內的總長度(big-endian)。
- record type:如 0x00 HEADER、0x01 BGNLIB、0x05 BGNSTR、0x08 BOUNDARY、0x0C SREF、0x11 TEXT。
- data type:0x00 無資料、0x01 位元陣列、0x02 2-byte 整數、0x03 4-byte 整數、0x06 ASCII 字串、0x05 8-byte 實數。
- 座標系:GDSII 座標是有號整數,以 database unit(如 1 nm)為刻度;user unit(如 1 μm)透過 UNITS 記錄換算: \(\text{座標值} = \text{物理長度} / \text{db unit}\) 。例如 1.5 μm 線寬、db unit = 1 nm,座標值即 1500。
3. 層次化壓縮率的數學#
設晶片含 \(N\) 個 instance,每個 cell 平均 \(g\) 個圖形(polygon):
- 展開式(flatten):檔案大小 \(S_{\text{flat}} \approx N \cdot g \cdot s\) ,其中 \(s\) 為單一圖形的描述成本(8 個座標 × 4 bytes ≈ 32 B)。
- 層次化(hierarchical): \(S_{\text{hier}} \approx (N + M \cdot g) \cdot s'\) ,其中 \(M\) 為不同 cell 的種類數、 \(s'\) 為含引用開銷的成本。當 \(N \gg M\) (重複率高)時:
DRAM、SRAM、快閃記憶體的 \(N/M\) 比可達數千以上——這就是為什麼 GDSII 存得下整顆晶片。 - 代價:下游工具(DRC、mask writer)往往需要 flatten 後的幾何才能正確處理;flatten 之後檔案又爆回 \(O(\text{geometry})\) ,於是 quadtree / clip(空間切割)登場。
4. Quadtree 與 clip:處理超大版圖#
先進製程的 flatten 版圖動輒數百 GB,記憶體裝不下。解法是把版圖切成 tile(瓷磚),每個 tile 建一棵 quadtree:
- quadtree:把矩形遞迴四分,直到每個節點的圖形數低於門檻;查詢「點 \((x,y)\) 上有什麼圖形」為 \(O(\log n)\) ,區域查詢為 \(O(\sqrt{n} + k)\) 。
- clip:把跨越多個 tile 的圖形在 tile 邊界切開(clipping),每個 tile 可獨立處理(平行化、分散式運算)——mask data preparation(MDP)的工具(如 fracturing、shot assignment)都建立在此架構上。
- 層次化 DRC:現代工具更進一步——不 flatten,直接在層次結構上做 DRC,只處理「每種 cell 一次」再複製結果;這是 1990s hierarchical verification 的核心思想。
- 時間戳與可重現性:每個 BGNLIB/BGNSTR 記錄都帶修改與存取時間;儘管沒有實際功能意義,卻讓「同一份版圖經過誰的手」有跡可循——EDA 偵探追溯 tape-out 歷史時的第一條線索。
5. GDSII 的 UNITS 記錄與精度換算#
GDSII 用 UNITS 記錄存兩個實數: \(\text{db unit in user units}\) 與 \(\text{db unit in meters}\) ,例如 \((0.001, 1\times10^{-9})\) 表示 1 user unit = 1 μm、1 db unit = 1 nm。所有座標都是有號整數乘以 db unit,因此精度由製程決定:0.35 μm 世代用 1 nm 足夠,EUV 世代圖形邊界需 0.1 nm 以下精度,UNITS 的選擇直接影響檔案大小與 mask writer 的解析成本。
6. 事實標準的誕生與接班#
- 1980s 事實標準:Calma GDSII 因「中立 + 可串流 + 層次化」被各家 CAD 與 mask house 採用;即便 Calma 公司本身(1981 年被 GE 收購)消逝,格式卻活了下來。
- OASIS(2004, SEMI P39):GDSII 的二進位編碼冗餘(每個座標 4 bytes、每筆記錄 4 bytes header)在先進製程的巨型版圖上吃不消;SEMI 推出 OASIS,用變動長度整數(variable-length integer)與重複壓縮,檔案可小 10 倍以上。
- GDSII 仍是 tape-out 標準:儘管 OASIS 更優,GDSII 因相容性與工具支援度,至今仍是 foundry 交棒的首選格式——「舊但不死」的經典案例。
- 格式演進的偵探筆記:從 GDS(1974)→ GDSII(1978)→ OASIS(2004),三代的演化主軸都是「更大的版圖逼出更緊的編碼」;判斷一個格式能否存活,看的不是技術優劣,而是生態系的慣性。
7. Python 實作:迷你 GDSII 記錄解析器#
import struct
RECORDS = {0x00: "HEADER", 0x01: "BGNLIB", 0x02: "LIBNAME", 0x04: "UNITS",
0x05: "BGNSTR", 0x06: "STRNAME", 0x08: "BOUNDARY", 0x0D: "LAYER",
0x0E: "DATATYPE", 0x10: "XY", 0x11: "ENDEL", 0x07: "ENDSTR"}
def parse_records(data):
"""逐筆解析 GDSII stream:4-byte header (length, type, datatype) + payload"""
out, i = [], 0
while i < len(data):
length, rtype, dtype = struct.unpack('>HBB', data[i:i+4])
payload = data[i+4:i+length]
name = RECORDS.get(rtype, f"0x{rtype:02X}")
if rtype == 0x10 and len(payload) >= 8: # XY:成對 4-byte 座標
pts = [struct.unpack('>ii', payload[j:j+8]) for j in range(0, len(payload) - 7, 8)]
out.append((name, pts))
elif rtype in (0x0D, 0x0E): # LAYER / DATATYPE
out.append((name, struct.unpack('>H', payload)[0]))
else:
out.append((name, payload))
i += length
return out
def mini_boundary(layer, datatype, pts, db_unit_nm=1):
"""組一筆 BOUNDARY 記錄鏈:座標以 db unit 為刻度"""
xy = b''.join(struct.pack('>ii', int(x / db_unit_nm), int(y / db_unit_nm)) for x, y in pts)
recs = [(0x08, 0x00, b''), (0x0D, 0x02, struct.pack('>H', layer)),
(0x0E, 0x02, struct.pack('>H', datatype)), (0x10, 0x03, xy), (0x11, 0x00, b'')]
return b''.join(struct.pack('>HBB', 4 + len(p), t, d) + p for t, d, p in recs)
blob = mini_boundary(layer=1, datatype=0, pts=[(0, 0), (1500, 0), (1500, 800), (0, 800), (0, 0)])
print([r for r in parse_records(blob)])
# [('BOUNDARY', b''), ('LAYER', 1), ('DATATYPE', 0), ('XY', [(0, 0), (1500, 0), (1500, 800), (0, 800), (0, 0)]), ('ENDEL', b'')]
解析結果顯示:一個 1.5 μm × 0.8 μm 的長方形(db unit = 1 nm)被存成 LAYER=1、DATATYPE=0、五個座標點的 BOUNDARY 記錄鏈——GDSII 的全部祕密就在這 4-byte header 與層次引用之間。
結案 -- 後果與影響#
- tape-out 的統一語言:設計公司把 GDSII 交給晶圓廠,晶圓廠以此為 mask data preparation(MDP)起點——fracturing、shot assignment、OPC 全部從 GDSII 出發。
- EDA 工具間的互換格式:Cadence Virtuoso、Synopsys ICC、Siemens Calibre、開源的 KLayout 與 gdspy,全都讀寫 GDSII;版圖在工具之間流通不再需要「翻譯」。
- 後進製程的檔案爆炸:28 nm 世代 GDSII 約數十 GB,7 nm 以下破百 GB——OASIS 的壓縮與分散式 MDP(如 tiling + 雲端運算)正是為了治這個病。
- 層次化設計的催化劑:SREF/AREF 引用讓「設計一次、引用千萬次」可行,直接影響後來的 hierarchical verification 與 hierarchical routing 思想。
- OASIS 接班但 GDSII 不死:2004 年 SEMI P39(OASIS)以更小的檔案接班,但 GDSII 因相容性至今仍是 tape-out 事實標準——一個 1978 年的格式,服役近半世紀。
關鍵人物與文檔#
- Calma 公司:GDS 數位化工作站與 GDSII Stream Format(1978)的發明者;公司本身後被 GE(1981)、Valid(1988)輾轉收購,格式卻成為產業遺產。
- SEMI:OASIS 標準(SEMI P39, 2004)的制定單位,GDSII 的接班者。
- KLayout / gdspy / gdstk:開源社群的 GDSII 讀寫工具,讓這個 1978 年的格式在 Python 時代繼續被使用。
- Calma, GDSII Stream Format Manual, 1978(作業系統內部文件,後被業界廣泛流傳)。
- SEMI P39(OASIS)標準文件與 KLayout 官方文件:GDS→GDSII→OASIS 格式演進的第一手比較資料。