blob: d05b243387995a965d5a1968738c93acb1277c2b [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.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.2c : Max. Space for well tap guard ring contacts for High Voltage LDMOS is 11µm
hv_ring = ntap.join(ptap).and(ldmos_xtor)
hv_ring_con = contact.and(hv_ring)
co2c_l1 = hv_ring_con.not_interacting(hv_ring_con.space(11.um).polygons(0.001))
co2c_l1.output('CO.2c','CO.2c : Max. Space for well tap guard ring contacts for High Voltage LDMOS is 11µm')
co2c_l1.forget
hv_ring.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.not(mvsd).not(mvpsd).enclosing(contact.outside(sramcore), 0.1.um, euclidian).polygons(0.001)
co4_l2 = contact.outside(sramcore).not_outside(comp.not(mvsd).not(mvpsd)).not(comp.not(mvsd).not(mvpsd))
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.6a: (i) Metal1 (< 0.34um) end-of-line overlap. is 0.06µm.
## (Applies to all < 0.34µm wide metal lines,
## excluding metal branches shorter than 0.24µm.)
logger.info('Executing rule CO.6a')
cont_6a_cond = metal1.width(0.34.um + 1.dbu).with_length(0.24.um, nil, both)
cont_6a_cond_edge1 = cont_6a_cond.first_edges
cont_6a_cond_edge2 = cont_6a_cond.second_edges
cont_6a_eol = metal1.edges.with_length(nil, 0.34.um).interacting(cont_6a_cond_edge1).interacting(cont_6a_cond_edge2)
.not(cont_6a_cond_edge1).not(cont_6a_cond_edge2)
cont_6a_l1 = contact.edges.enclosed(cont_6a_eol, 0.06.um, projection)
cont_6a_l1.output('CO.6a', 'CO.6a : (i) Metal1 (< 0.34um) end-of-line overlap contact
(Applies to all < 0.34µm wide metal lines,
excluding metal branches shorter than 0.24µm) : 0.06µm')
cont_6a_l1.forget
cont_6a_cond.forget
cont_6a_eol.forget
cont_6a_cond.forget
cont_6a_cond_edge1.forget
cont_6a_cond_edge2.forget
# Rule CO.6b: Min. Metal1 enclose Contact by sides (a, b, c, d) [Outside Not Allowed] are (0.005,0.06,0.005,0.06) or (0,04,0.04,0.04,0.04)
logger.info('Executing rule CO.6b')
co6b_l1 = contact.enclosed(metal1, 0.04.um).polygons(0.001)
co6b_l2 = contact.enclosed(metal1, 0.06.um).polygons(0.001)
co6b_l3 = contact.enclosed(metal1, 0.005.um).polygons(0.001)
co6b_l = co6b_l1.join(co6b_l2.interacting(co6b_l3))
co6b_l.output('CO.6b','CO.6b : Min. Metal1 enclose Contact by sides (a, b, c, d) [Outside Not Allowed] are (0.005,0.06,0.005,0.06) or (0,04,0.04,0.04,0.04)')
co6b_l1.forget
co6b_l2.forget
co6b_l3.forget
co6b_l.forget
# rule CO.6c is not a DRC check
# Rule CO.7a : Space from COMP contact to Poly2 on COMP. is 0.16µm
logger.info('Executing rule CO.7a')
co7a_l1 = contact.not_outside(comp).separation(tgate, 0.16.um, euclidian).polygons(0.001)
co7a_l1.output('CO.7a', 'CO.7a : Space from COMP contact to Poly2 on COMP. : 0.16µm')
co7a_l1.forget
# Rule CO.7b : Min. COMP contact space to Poly2 on COMP for drain side of asymmetric HVNMOS/HVPMOS is 0.7/0.6 um
logger.info('Executing rule CO.7b')
co7b_l1 = contact.not_outside(comp.interacting(hvnddd)).separation(tgate.interacting(hvnddd), 0.7.um, euclidian).polygons(0.001)
co7b_l2 = contact.not_outside(comp.interacting(hvpddd)).separation(tgate.interacting(hvpddd), 0.6.um, euclidian).polygons(0.001)
co7b_l = co7b_l1.or(co7b_l2)
co7b_l.output('CO.7b', 'CO.7b : Space from COMP contact to Poly2 on COMP.Min. COMP contact space to Poly2 on COMP for drain side of asymmetric HVNMOS/HVPMOS: 0.7/0.6 um')
co7b_l.forget
co7b_l1.forget
co7b_l2.forget
# Rule CO.7c : Min. COMP contact space to Poly2 on COMP for source side of asymmetric HVNMOS and HVPMOS is 0.16 um
logger.info('Executing rule CO.7c')
co7c_l1 = contact.not_outside(comp.not(hvnddd.or(hvpddd))).separation(tgate.interacting(hvnddd.or(hvpddd)), 0.16.um, euclidian).polygons(0.001)
co7c_l1.output('CO.7c', 'CO.7c : Min. COMP contact space to Poly2 on COMP for source side of asymmetric HVNMOS and HVPMOS : 0.16µm')
co7c_l1.forget
# Rule CO.8: Space from Poly2 contact to COMP. is 0.2µm
logger.info('Executing rule CO.8')
co8_l1 = contact.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.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_inside(comp.or(poly2))
co11_l1.output('CO.11', 'CO.11 : Contact on field oxide is forbidden.')
co11_l1.forget
n_source = (ncomp.not(poly2).interacting(pcomp).interacting(poly2))
p_source = (pcomp.not(poly2).interacting(ncomp).interacting(poly2))
p_tap = (pcomp.not_interacting(poly2).interacting(ncomp))
n_tap = (ncomp.not_interacting(poly2).interacting(pcomp))
# Rule CO.12: Butted source NCOMP overlap with contact is 0.16 µm
logger.info('Executing rule CO.12')
co12_l1 = n_source.overlap(contact,0.16.um).polygons(0.001)
co12_l1.output('CO.12','CO.12: Butted source NCOMP overlap with contact is 0.16 µm')
co12_l1.forget
# Rule CO.13 : Butted source PCOMP overlap with contact is 0.16 µm
co13_l1 = p_source.overlap(contact,0.16.um).polygons(0.001)
co13_l1.output('CO.13','CO.13 : Butted source PCOMP overlap with contact is 0.16 µm')
co13_l1.forget
# Rule CO.14a : Min Pbody width, with contact is 0.42 µm
co14a_l1 = p_tap.interacting(contact).width(0.42.um).polygons(0.001)
co14a_l1.output('CO.14a',' CO.14a : Min Pbody width, with contact is 0.42 µm')
co14a_l1.forget
# Rule CO.14b : There must be at least one row of contact inside P-Body
co14b_l1 = p_tap.not_interacting(contact.inside(p_tap))
co14b_l1.output('CO.14b','CO.14b : There must be at least one row of contact inside P-Body')
co14b_l1.forget
# Rule CO.14c : Min Pbody contact enclosure by butted PCOMP is 0.1 µm
co14c_l1 = p_tap.enclosing(contact.inside(p_tap),0.1.um).polygons(0.001)
co14c_l1.output('CO.14c','CO.14c : Min Pbody contact enclosure by butted PCOMP is 0.1 µm')
co14c_l1.forget
# Rule CO.15a : Min Nbody width, with contact is 0.42 µm
co15a_l1 = n_tap.interacting(contact).width(0.42.um).polygons(0.001)
co15a_l1.output('CO.15a','CO.15a : Min Nbody width, with contact is 0.42 µm')
co15a_l1.forget
# Rule CO.15b : There must be at least one row of contact inside N-Body
co15b_l1 = n_tap.not_interacting(contact.inside(n_tap))
co15b_l1.output('CO.15b','CO.15b : There must be at least one row of contact inside N-Body')
co15b_l1.forget
# Rule CO.15c : Min Nbody contact enclosure by butted NCOMP is 0.1 µm
co15c_l1 = n_tap.enclosing(contact.inside(n_tap),0.1.um).polygons(0.001)
co15c_l1.output('CO.15c','CO.15c : Min Nbody contact enclosure by butted NCOMP is 0.1 µm')
co15c_l1.forget
end #FEOL