# Basic DRC deck for the Optical I/O 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. Notebook 1 draws a 220 nm silicon core on # a 90 nm slab, a TiN heater, and a single metal layer. # # Read about DRC scripts in the User Manual under "Design Rule Check (DRC)" # http://klayout.de/doc/manual/drc_basic.html source($gdsfile) report("Optical I/O DRC", $resultsfile) # Layers, as notebook 1 numbered them: LayerSi = input(1, 0) LayerSlab = input(2, 0) LayerP = input(3, 0) LayerN = input(4, 0) LayerPpp = input(5, 0) LayerNpp = input(6, 0) LayerGe = input(7, 0) LayerContact = input(10, 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 123 nm modulator coupler. LayerSi.width(0.15 - tol, angle_limit(80)).output("Si_width", "Si minimum feature size violation; min 150 nm") LayerSi.space(0.12 - tol, angle_limit(80)).output("Si_space", "Si minimum space violation; min 120 nm") # The slab is a 90 nm etch, so it resolves less finely than the core LayerSlab.width(0.3 - tol, angle_limit(80)).output("Slab_width", "Slab minimum feature size violation; min 300 nm") LayerSlab.space(0.3 - tol, angle_limit(80)).output("Slab_space", "Slab minimum space violation; min 300 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") # Implants are drawn as sectors microns across LayerP.width(0.5 - tol, angle_limit(80)).output("P_width", "P doping minimum feature size violation; min 500 nm") LayerN.width(0.5 - tol, angle_limit(80)).output("N_width", "N doping minimum feature size violation; min 500 nm") LayerPpp.width(0.5 - tol, angle_limit(80)).output("Ppp_width", "P++ doping minimum feature size violation; min 500 nm") LayerNpp.width(0.5 - tol, angle_limit(80)).output("Npp_width", "N++ doping minimum feature size violation; min 500 nm") # TiN heater. The 1.2 um loop is cut by a 600 nm slot, so the narrowest drawn # heater feature is the 300 nm arm either side of that cut. 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 wherever a cell places a 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 LayerContact.width(1.0 - tol, angle_limit(70)).output("Contact_width", "Contact minimum feature size violation; min 1 um") LayerContact.space(1.0 - tol).output("Contact_space", "Contact minimum space violation; min 1 um") # Vias, drawn square at the metal width LayerVia.width(1.0 - tol, angle_limit(70)).output("Via_width", "Via minimum feature size violation; min 1 um") 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") # minimum inclusion rules: LayerM1.enclosing(LayerPadOpen, 2.5 - tol).output("M1_PadOpen_enclosure", "M1-PadOpen minimum enclosure violation; min 2.5 um") # A contact can land on the core or on the slab, so the check is against both LayerSilicon = LayerSi | LayerSlab LayerContact.not_inside(LayerSilicon).output("Contact_on_Si", "Contact must land on silicon, not on oxide") # An ohmic contact needs heavy implant under it, not bare silicon LayerOhmic = LayerPpp | LayerNpp LayerContact.not_inside(LayerOhmic).output("Contact_on_ohmic", "Contact must land on p++ or n++") LayerVia.not_inside(LayerM1).output("Via_in_M1", "Via must be covered by M1")