blob: d315884106eecaa695fa528b4fbf4f0ad49ac1a6 [file] [log] [blame]
###############################################################################################
# Copyright 2022 GlobalFoundries PDK Authors
#
# Licensed under the Apache License, Version 2.0 (the 'License');
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an 'AS IS' BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
################################################################################################
if FEOL
#================================================
#---------------------NPLUS----------------------
#================================================
# Rule NP.1: min. nplus width is 0.4µm
logger.info('Executing rule NP.1')
np1_l1 = nplus.width(0.4.um, euclidian).polygons(0.001)
np1_l1.output('NP.1', 'NP.1 : min. nplus width : 0.4µm')
np1_l1.forget
# Rule NP.2: min. nplus spacing is 0.4µm
logger.info('Executing rule NP.2')
np2_l1 = nplus.space(0.4.um, euclidian).polygons(0.001)
np2_l1.output('NP.2', 'NP.2 : min. nplus spacing : 0.4µm')
np2_l1.forget
# Rule NP.3a: Space to PCOMP for PCOMP Inside Nwell. is 0.16µm
logger.info('Executing rule NP.3a')
np3a_l1 = nplus.separation(pcomp.inside(nwell), 0.16.um, euclidian).polygons(0.001)
np3a_l1.output('NP.3a', 'NP.3a : Space to PCOMP for PCOMP Inside Nwell. : 0.16µm')
np3a_l1.forget
np_3b = pcomp.edges.not(nwell.sized(0.429.um))
# Rule NP.3b: Space to PCOMP for PCOMP space to Nwell >= 0.43um (outside Nwell). is 0.08µm
logger.info('Executing rule NP.3b')
np3b_l1 = nplus.outside(nwell).edges.separation(np_3b, 0.08.um, euclidian).polygons
np3b_l1.output('NP.3b', 'NP.3b : Space to PCOMP for PCOMP space to Nwell >= 0.43um. : 0.08µm')
np3b_l1.forget
np_3b.forget
np_3c = pcomp.edges.and(nwell.sized(0.429.um))
# Rule NP.3c: Space to PCOMP for PCOMP space to Nwell < 0.43um (outside Nwell). is 0.16µm
logger.info('Executing rule NP.3c')
np3c_l1 = nplus.outside(nwell).edges.separation(np_3c, 0.16.um, euclidian).polygons
np3c_l1.output('NP.3c', 'NP.3c : Space to PCOMP for PCOMP space to Nwell < 0.43um. : 0.16µm')
np3c_l1.forget
np_3c.forget
# Rule NP.3d: Min/max space to a butted PCOMP.
logger.info('Executing rule NP.3d')
np3d_l1 = nplus.not_outside(pcomp)
np3d_l1.output('NP.3d', 'NP.3d : Min/max space to a butted PCOMP.')
np3d_l1.forget
# Rule NP.3e: Space to related PCOMP edge adjacent to a butting edge.
logger.info('Executing rule NP.3e')
np3e_l1 = nplus.not_outside(pcomp)
np3e_l1.output('NP.3e', 'NP.3e : Space to related PCOMP edge adjacent to a butting edge.')
np3e_l1.forget
# Rule NP.4a: Space to related P-channel gate at a butting edge parallel to gate. is 0.32µm
logger.info('Executing rule NP.4a')
np4a_l1 = nplus.edges.and(pcomp.edges).separation(pgate.edges, 0.32.um, projection).polygons(0.001)
np4a_l1.output('NP.4a', 'NP.4a : Space to related P-channel gate at a butting edge parallel to gate. : 0.32µm')
np4a_l1.forget
np_4b_poly = poly2.edges.interacting(pgate.edges.not(pcomp.edges)).centers(0, 0.99).and(pgate.sized(0.32.um))
# Rule NP.4b: Within 0.32um of channel, space to P-channel gate extension perpendicular to the direction of Poly2. is 0.22um
logger.info('Executing rule NP.4b')
np4b_l1 = nplus.interacting(nplus.edges.separation(np_4b_poly, 0.22.um, projection).polygons(0.001))
np4b_l1.output('NP.4b', 'NP.4b : Within 0.32um of channel, space to P-channel gate extension perpendicular to the direction of Poly2. : 0.22um')
np4b_l1.forget
np_4b_poly.forget
# Rule NP.5a: Overlap of N-channel gate. is 0.23µm
logger.info('Executing rule NP.5a')
np5a_l1 = nplus.enclosing(ngate, 0.23.um, euclidian).polygons(0.001)
np5a_l2 = ngate.not_outside(nplus).not(nplus)
np5a_l = np5a_l1.or(np5a_l2)
np5a_l.output('NP.5a', 'NP.5a : Overlap of N-channel gate. : 0.23µm')
np5a_l1.forget
np5a_l2.forget
np5a_l.forget
# Rule NP.5b: Extension beyond COMP for the COMP outside Nwell. is 0.16µm
logger.info('Executing rule NP.5b')
np5b_l1 = nplus.outside(nwell).edges.not(pplus).enclosing(comp.edges, 0.16.um, euclidian).polygons(0.001)
np5b_l1.output('NP.5b', 'NP.5b : Extension beyond COMP for the COMP outside Nwell. : 0.16µm')
np5b_l1.forget
np_5c_background = nplus.not_outside(nwell).edges
np_5c_extend = nwell.not(nwell.sized(-0.429.um))
np_5c_foreground = ncomp.not_outside(nwell).edges.not(pplus.edges).and(np_5c_extend)
# Rule NP.5c: Extension beyond COMP: inside Nwell: For Nwell overlap of Nplus < 0.43um. is 0.16µm
logger.info('Executing rule NP.5c')
np5c_l1 = np_5c_background.enclosing(np_5c_foreground, 0.16.um, projection).polygons(0.001)
np5c_l1.output('NP.5c', 'NP.5c : Extension beyond COMP: inside Nwell: For Nwell overlap of Nplus < 0.43um. : 0.16µm')
np5c_l1.forget
np_5c_background.forget
np_5c_extend.forget
np_5c_foreground.forget
np_5d_background = nplus.not_outside(nwell).edges.not(pplus.edges)
np_5d_extend = nwell.sized(-0.429.um)
np_5d_foreground = ncomp.not_outside(nwell).edges.not(pplus.edges).and(np_5d_extend)
# Rule NP.5d: Extension beyond COMP: inside Nwell: For Nwell overlap of Nplus >= 0.43um. is 0.02µm
logger.info('Executing rule NP.5d')
np5d_l1 = np_5d_background.enclosing(np_5d_foreground, 0.02.um, euclidian).polygons(0.001)
np5d_l1.output('NP.5d', 'NP.5d : Extension beyond COMP: inside Nwell: For Nwell overlap of Nplus >= 0.43um. : 0.02µm')
np5d_l1.forget
np_5d_background.forget
np_5d_extend.forget
np_5d_foreground.forget
# Rule NP.6: Overlap with NCOMP butted to PCOMP. is 0.22µm
logger.info('Executing rule NP.6')
np6_l1 = comp.interacting(nplus).enclosing(pcomp.interacting(nplus), 0.22.um, projection).polygons
np6_l1.output('NP.6', 'NP.6 : Overlap with NCOMP butted to PCOMP. : 0.22µm')
np6_l1.forget
# Rule NP.7: Space to unrelated unsalicided Poly2. is 0.18µm
logger.info('Executing rule NP.7')
np7_l1 = nplus.separation(poly2.and(sab), 0.18.um, euclidian).polygons(0.001)
np7_l1.output('NP.7', 'NP.7 : Space to unrelated unsalicided Poly2. : 0.18µm')
np7_l1.forget
# Rule NP.8a: Minimum Nplus area (um2). is 0.35µm²
logger.info('Executing rule NP.8a')
np8a_l1 = nplus.with_area(nil, 0.35.um)
np8a_l1.output('NP.8a', 'NP.8a : Minimum Nplus area (um2). : 0.35µm²')
np8a_l1.forget
# Rule NP.8b: Minimum area enclosed by Nplus (um2). is 0.35µm²
logger.info('Executing rule NP.8b')
np8b_l1 = nplus.holes.with_area(nil, 0.35.um)
np8b_l1.output('NP.8b', 'NP.8b : Minimum area enclosed by Nplus (um2). : 0.35µm²')
np8b_l1.forget
# Rule NP.9: Overlap of unsalicided Poly2. is 0.18µm
logger.info('Executing rule NP.9')
np9_l1 = nplus.enclosing(poly2.and(sab), 0.18.um, euclidian).polygons(0.001)
np9_l2 = poly2.and(sab).not_outside(nplus).not(nplus)
np9_l = np9_l1.or(np9_l2)
np9_l.output('NP.9', 'NP.9 : Overlap of unsalicided Poly2. : 0.18µm')
np9_l1.forget
np9_l2.forget
np9_l.forget
# Rule NP.10: Overlap of unsalicided COMP. is 0.18µm
logger.info('Executing rule NP.10')
np10_l1 = nplus.enclosing(comp.and(sab), 0.18.um, euclidian).polygons(0.001)
np10_l1.output('NP.10', 'NP.10 : Overlap of unsalicided COMP. : 0.18µm')
np10_l1.forget
# Rule NP.11: Butting Nplus and PCOMP is forbidden within 0.43um of Nwell edge.
logger.info('Executing rule NP.11')
np11_l1 = nplus.interacting(nplus.edges.and(pcomp.edges).and(nwell.sized(0.429.um)))
np11_l1.output('NP.11', 'NP.11 : Butting Nplus and PCOMP is forbidden within 0.43um of Nwell edge.')
np11_l1.forget
# Rule NP.12: Overlap with P-channel poly2 gate extension is forbidden within 0.32um of P-channel gate.
logger.info('Executing rule NP.12')
np12_l1 = nplus.interacting(nplus.edges.separation(pgate.edges.and(pcomp.edges), 0.32.um, euclidian).polygons(0.001))
np12_l1.output('NP.12', 'NP.12 : Overlap with P-channel poly2 gate extension is forbidden within 0.32um of P-channel gate.')
np12_l1.forget
end #FEOL