# Basic DRC deck for the LiDAR SOI technology of this series # # Written to follow the SiEPIC EBeam PDK deck that ships with the PhotonForge DRC # guide, so the structure and the idioms are ones a reader will meet again: # https://docs.flexcompute.com/projects/photonforge/en/latest/guides/SiEPIC_EBeam.drc # # The numbers are this technology's own: a single full etch of 220 nm silicon, a TiN # heater, one routing metal, germanium detectors. # # Read about DRC scripts in the User Manual under "Design Rule Check (DRC)" # http://klayout.de/doc/manual/drc_basic.html source($gdsfile) report("LiDAR DRC", $resultsfile) # Layers, as the technology page numbered them LayerSi = input(1, 0) LayerSiPartial = input(2, 0) LayerGe = input(7, 0) LayerContact = input(10, 0) LayerGeContact = input(11, 0) LayerHeater = input(12, 0) LayerVia = input(13, 0) LayerM1 = input(14, 0) LayerPadOpen = input(15, 0) LayerFloorPlan = input(99, 0) ################# # non-physical checks ################# # Nothing may sit outside the chip area the floor plan marks out LayerSi.outside(LayerFloorPlan).output("Boundary", "Si outside the floor plan") LayerM1.outside(LayerFloorPlan).output("Boundary_M1", "M1 outside the floor plan") ################# # physical checks ################# tol = 1e-3 # users typically shoot for exactly the min features # for curves, this leads to lots of false errors. # Silicon. The narrowest line drawn is the 180 nm edge coupler tip and the # tightest gap is the 200 nm tap coupler. The antenna teeth are on the partial # etch layer and have their own rules below. LayerSi.width(0.15 - tol, angle_limit(80)).output("Si_width", "Si minimum feature size violation; min 150 nm") LayerSi.space(0.15 - tol, angle_limit(80)).output("Si_space", "Si minimum space violation; min 150 nm") # Partial-etch teeth: 100 to 200 nm wide, half a grating period apart LayerSiPartial.width(0.1 - tol, angle_limit(80)).output("SiPartial_width", "Partial etch minimum feature size violation; min 100 nm") LayerSiPartial.space(0.1 - tol, angle_limit(80)).output("SiPartial_space", "Partial etch minimum space violation; min 100 nm") # Germanium is grown on a silicon seed and is drawn microns wide LayerGe.width(1.0 - tol, angle_limit(80)).output("Ge_width", "Ge minimum feature size violation; min 1 um") LayerGe.space(1.0 - tol, angle_limit(80)).output("Ge_space", "Ge minimum space violation; min 1 um") # TiN heater, drawn 1 um wide over every phase shifter LayerHeater.width(0.3 - tol, angle_limit(70)).output("Heater_width", "Heater minimum feature size violation; min 300 nm") LayerHeater.space(0.3 - tol).output("Heater_space", "Heater minimum space violation; min 300 nm") # Metal, drawn at 3 um for every trace and terminal LayerM1.width(1.0 - tol, angle_limit(70)).output("M1_width", "M1 minimum feature size violation; min 1 um") LayerM1.space(1.0 - tol).output("M1_space", "M1 minimum space violation; min 1 um") # Contact plugs down to the silicon and to the germanium LayerContact.width(0.5 - tol, angle_limit(70)).output("Contact_width", "Contact minimum feature size violation; min 500 nm") LayerGeContact.width(0.5 - tol, angle_limit(70)).output("GeContact_width", "Ge contact minimum feature size violation; min 500 nm") # Vias from the heater up to the metal, drawn 0.8 x 3 um on each heater end LayerVia.width(0.5 - tol, angle_limit(70)).output("Via_width", "Via minimum feature size violation; min 500 nm") LayerVia.space(1.0 - tol).output("Via_space", "Via minimum space violation; min 1 um") # Pad openings in the passivation LayerPadOpen.width(10.0 - tol).output("PadOpen_width", "Pad opening minimum feature size violation; min 10 um") LayerPadOpen.space(10.0 - tol).output("PadOpen_space", "Pad opening minimum space violation; min 10 um") ################# # cross-layer checks ################# LayerM1.enclosing(LayerPadOpen, 2.5 - tol).output("M1_PadOpen_enclosure", "M1-PadOpen minimum enclosure violation; min 2.5 um") LayerContact.not_inside(LayerSi).output("Contact_on_Si", "Contact must land on silicon, not on oxide") LayerGeContact.not_inside(LayerGe).output("GeContact_on_Ge", "Ge contact must land on germanium") LayerVia.not_inside(LayerHeater).output("Via_on_heater", "Via must land on the heater") LayerVia.not_inside(LayerM1).output("Via_in_M1", "Via must be covered by M1") # Metal half a micron above a heater is a heat sink and changes its efficiency, so the # only metal allowed over a heater is the landing on its via LayerM1.and(LayerHeater).not_inside(LayerVia.sized(1.5)).output("M1_over_heater", "M1 over a heater away from its via")