blob: 2c87af2b6e906283d86d923a11d29d4d06c70c35 [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
#================================================
#--------------------CONTACT---------------------
#================================================
logger.info('Starting CONTACT derivations')
main_contact = contact.not(sramcore)
# Rule CO.1: Min/max contact size. is 0.22µm
logger.info('Executing rule CO.1')
co1_l1 = contact.outside(sramcore).edges.without_length(0.22.um).extended(0, 0, 0.001, 0.001)
co1_l1.output('CO.1', 'CO.1 : Min/max contact size. : 0.22µm')
co1_l1.forget
# Rule CO.2a: min. contact spacing is 0.25µm
logger.info('Executing rule CO.2a')
co2a_l1 = contact.space(0.25.um, euclidian).polygons(0.001)
co2a_l1.output('CO.2a', 'CO.2a : min. contact spacing : 0.25µm')
co2a_l1.forget
# Rule CO.2b: Space in 4x4 or larger contact array. is 0.28µm
logger.info('Executing rule CO.2b')
# Array to be filterd
## array_length = 3 * exact_size + 3 * min_space
co2b_egde_length = 0.22 * 3 + 3 * 0.28
poss_4_4_contact = contact.sized(0.16, 'square_limit').merged.sized(-0.16, 'square_limit')
co_4x4_all = poss_4_4_contact.with_bbox_min(co2b_egde_length..nil).interacting(contact, 16..nil)
co_4x4_loc_exc = co_4x4_all.width(co2b_egde_length,
projection_limits(co2b_egde_length..1000 * co2b_egde_length)).polygons
co_4x4_loc = co_4x4_all.not_interacting(co_4x4_loc_exc)
selected_co = contact.interacting(co_4x4_loc)
co2b_l1 = selected_co.space(0.28.um, euclidian)
co2b_l1.output('CO.2b', 'CO.2b : Space in 4x4 or larger contact array. : 0.28µm')
poss_4_4_contact.forget
co_4x4_all.forget
co_4x4_loc_exc.forget
selected_co.forget
co2b_l1.forget
# Rule CO.3: Poly2 overlap of contact. is 0.07µm
logger.info('Executing rule CO.3')
co3_l1 = main_contact.enclosed(poly2, 0.07.um, euclidian).polygons(0.001)
co3_l2 = main_contact.not_outside(poly2).not(poly2)
co3_l = co3_l1.or(co3_l2)
co3_l.output('CO.3', 'CO.3 : Poly2 overlap of contact. : 0.07µm')
co3_l.forget
co3_l1.forget
co3_l2.forget
# Rule CO.3: Poly2 overlap of contact. is 0.1µm
logger.info('Executing rule CO.3')
co3_l1 = poly2.enclosing(contact.outside(sramcore), 0.1.um, euclidian).polygons(0.001)
co3_l2 = contact.outside(sramcore).not_outside(poly2).not(poly2)
co3_l = co3_l1.or(co3_l2)
co3_l.output('CO.3', 'CO.3 : Poly2 overlap of contact. : 0.1µm')
co3_l1.forget
co3_l2.forget
co3_l.forget
# Rule CO.4: COMP overlap of contact. is 0.1µm
logger.info('Executing rule CO.4')
co4_l1 = comp.enclosing(contact.outside(sramcore), 0.1.um, euclidian).polygons(0.001)
co4_l2 = contact.outside(sramcore).not_outside(comp).not(comp)
co4_l = co4_l1.or(co4_l2)
co4_l.output('CO.4', 'CO.4 : COMP overlap of contact. : 0.1µm')
co4_l1.forget
co4_l2.forget
co4_l.forget
# Rule CO.5a: Nplus overlap of contact on COMP is 0.1µm
logger.info('Executing rule CO.5a')
co5a_l1 = ncomp.enclosing(contact, 0.1.um, euclidian).polygons(0.001)
co5a_l2 = contact.not_outside(ncomp).not(ncomp)
co5a_l = co5a_l1.or(co5a_l2)
co5a_l.output('CO.5a', 'CO.5a : Nplus overlap of contact on COMP : 0.1µm')
co5a_l1.forget
co5a_l2.forget
co5a_l.forget
# Rule CO.5b: Pplus overlap of contact on COMP is 0.1µm
logger.info('Executing rule CO.5b')
co5b_l1 = pcomp.enclosing(contact, 0.1.um, euclidian).polygons(0.001)
co5b_l2 = contact.not_outside(pcomp).not(pcomp)
co5b_l = co5b_l1.or(co5b_l2)
co5b_l.output('CO.5b', 'CO.5b : Pplus overlap of contact on COMP : 0.1µm')
co5b_l1.forget
co5b_l2.forget
co5b_l.forget
# Rule CO.6: Metal1 overlap of contact.
logger.info('Executing rule CO.6')
co6_l1 = metal1.enclosing(contact, 0.005.um, euclidian).polygons(0.001).or(contact.not(metal1))
co6_l1.output('CO.6', 'CO.6 : Metal1 overlap of contact.')
co6_l1.forget
cop6a_cond = metal1.drc( width <= 0.34.um).with_length(0.24.um,nil,both)
cop6a_eol = metal1.edges.with_length(nil, 0.34.um).interacting(cop6a_cond.first_edges).interacting(cop6a_cond.second_edges).not(cop6a_cond.first_edges).not(cop6a_cond.second_edges)
# Rule CO.6a: (i) Metal1 (< 0.34um) end-of-line overlap. is 0.06µm
logger.info('Executing rule CO.6a')
co6a_l1 = cop6a_eol.enclosing(contact.edges,0.06.um, projection).polygons(0.001)
co6a_l1.output('CO.6a', 'CO.6a : (i) Metal1 (< 0.34um) end-of-line overlap. : 0.06µm')
co6a_l1.forget
cop6a_cond.forget
cop6a_eol.forget
co_6b_1 = contact.edges.interacting(contact.drc(enclosed(metal1, projection) < 0.04.um).edges.centers(0, 0.5))
co_6b_2 = contact.edges.interacting(contact.drc(0.04.um <= enclosed(metal1, projection) < 0.06.um).centers(0, 0.5))
co_6b_3 = co_6b_1.extended(0, 0, 0, 0.001, joined).corners(90)
# Rule CO.6b: (ii) If Metal1 overlaps contact by < 0.04um on one side, adjacent metal1 edges overlap is 0.06µm
logger.info('Executing rule CO.6b')
co6b_l1 = co_6b_2.not_in(co_6b_1).interacting(co_6b_1).or(co_6b_1.interacting(co_6b_3)).not(sramcore).enclosed(metal1.outside(sramcore).edges, 0.06.um).polygons(0.001)
co6b_l1.output('CO.6b', 'CO.6b : (ii) If Metal1 overlaps contact by < 0.04um on one side, adjacent metal1 edges overlap : 0.06µm')
co6b_l1.forget
co_6b_1.forget
co_6b_2.forget
co_6b_3.forget
# rule CO.6c is not a DRC check
# Rule CO.7: Space from COMP contact to Poly2 on COMP. is 0.16µm
logger.info('Executing rule CO.7')
co7_l1 = contact.outside(sramcore).not_outside(comp).separation(tgate, 0.16.um, euclidian).polygons(0.001)
co7_l1.output('CO.7', 'CO.7 : Space from COMP contact to Poly2 on COMP. : 0.16µm')
co7_l1.forget
# Rule CO.8: Space from Poly2 contact to COMP. is 0.2µm
logger.info('Executing rule CO.8')
co8_l1 = contact.outside(sramcore).not_outside(poly2).separation(comp, 0.2.um, euclidian).polygons(0.001)
co8_l1.output('CO.8', 'CO.8 : Space from Poly2 contact to COMP. : 0.2µm')
co8_l1.forget
# Rule CO.9: Contact on NCOMP to PCOMP butting edge is forbidden (contact must not straddle butting edge).
logger.info('Executing rule CO.9')
co9_l1 = contact.interacting(ncomp.edges.and(pcomp.edges))
co9_l1.output('CO.9', 'CO.9 : Contact on NCOMP to PCOMP butting edge is forbidden (contact must not straddle butting edge).')
co9_l1.forget
# Rule CO.10: Contact on Poly2 gate over COMP is forbidden.
logger.info('Executing rule CO.10')
co10_l1 = contact.not_outside(tgate)
co10_l1.output('CO.10', 'CO.10 : Contact on Poly2 gate over COMP is forbidden.')
co10_l1.forget
# Rule CO.11: Contact on field oxide is forbidden.
logger.info('Executing rule CO.11')
co11_l1 = contact.not(comp.or(poly2))
co11_l1.output('CO.11', 'CO.11 : Contact on field oxide is forbidden.')
co11_l1.forget
end #FEOL