| ################################################################################################ |
| # 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 |
| |
| #=============================================== |
| #------------------Poly2------------------------ |
| #=============================================== |
| |
| |
| logger.info('Starting POLY2 derivations') |
| |
| poly2_lv = poly2.not_interacting(v5_xtor).not_interacting(dualgate_2) |
| poly2_mv = poly2.overlapping(dualgate_2) |
| poly_pl_lv = poly2_lv.not(otp_mk) |
| poly_pl_mv = poly2_mv.not(otp_mk) |
| |
| # Rule PL.1_LV: Interconnect Width is 0.18µm |
| logger.info('Executing rule PL.1_LV') |
| pl1_l1 = poly2.outside(sramcore).not_interacting(v5_xtor).not_interacting(dualgate_2).width(0.18.um, euclidian).polygons(0.001) |
| pl1_l1.output('PL.1_LV', 'PL.1_LV : Interconnect Width : 0.18µm') |
| pl1_l1.forget |
| |
| # Rule PL.1_MV: Interconnect Width (outside PLFUSE). is 0.2µm |
| logger.info('Executing rule PL.1_5V') |
| pl1_l1 = poly2.outside(sramcore).not_interacting(dualgate).overlapping(dualgate_2).width(0.2.um, euclidian).polygons(0.001) |
| pl1_l1.output('PL.1_MV', 'PL.1_MV : Interconnect Width : 0.2µm') |
| pl1_l1.forget |
| |
| # Rule PL.2a_LV_1.8V: Gate Width (Channel Length). is 0.18µm |
| logger.info('Executing rule PL.2a_LV_1.8V') |
| pl2a_1p8_l1 = tgate.not_interacting(dualgate.or(dualgate_2)).not(otp_mk).width(0.18.um, euclidian).polygons(0.001) |
| pl2a_1p8_l1.output('PL.2a_LV_1.8V', 'PL.2a_LV_1.8V : Gate Width (Channel Length). : 0.18µm') |
| pl2a_1p8_l1.forget |
| |
| # Rule PL.2a_LV_3.3V: Gate Width (Channel Length). is 0.35µm for NMOS and 0.30 for PMOS |
| logger.info('Executing rule PL.2a_LV_3.3V') |
| pl2a_3p3_l1 = ngate.overlapping(dualgate).not_interacting(dualgate_2).not(otp_mk).width(0.35.um, euclidian).polygons(0.001) |
| pl2a_3p3_l2 = pgate.overlapping(dualgate).not_interacting(dualgate_2).not(otp_mk).width(0.30.um, euclidian).polygons(0.001) |
| pl2a_3p3_l = pl2a_3p3_l1.or(pl2a_3p3_l2) |
| pl2a_3p3_l.output('PL.2a_LV_3.3V', 'PL.2a_LV_3.3V : Gate Width (Channel Length). is 0.35µm for NMOS and 0.30 for PMOS') |
| pl2a_3p3_l1.forget |
| pl2a_3p3_l2.forget |
| pl2a_3p3_l.forget |
| |
| # Rule PL.2a_MV_5V: Gate Width (Channel Length). is 0.5µm |
| logger.info('Executing rule PL.2a_MV_5V') |
| pl2a_5p0_l1 = tgate.not_interacting(dualgate).overlapping(dualgate_2).overlapping(v5_xtor).not(otp_mk).width(0.5.um, euclidian).polygons(0.001) |
| pl2a_5p0_l1.output('PL.2a_MV_5V', 'PL.2a_MV_5V : Gate Width (Channel Length). : 0.5µm') |
| pl2a_5p0_l1.forget |
| |
| # Rule PL.2a_MV_6V: Gate Width (Channel Length). is 0.6µm |
| logger.info('Executing rule PL.2a_MV_6V') |
| pl2a_6p0_l1 = tgate.not_interacting(dualgate.or(v5_xtor) ).overlapping(dualgate_2).not(otp_mk).width(0.6.um, euclidian).polygons(0.001) |
| pl2a_6p0_l1.output('PL.2a_MV_6V', 'PL.2a_MV_6V : Gate Width (Channel Length). : 0.6µm') |
| pl2a_6p0_l1.forget |
| |
| # Rule PL.2b_LV_3.3V : Gate width for OTP cell area (identified by OTP_MK). 0.27 for PMOS |
| logger.info('Executing rule PL.2b_LV_3.3V') |
| pl2b_3p3_l1 = pgate.overlapping(dualgate).not_interacting(dualgate_2).interacting(otp_mk).width(0.27.um, euclidian).polygons(0.001) |
| pl2b_3p3_l1.output('PL.2b_LV_3.3V','PL.2b_LV_3.3V : Gate width for OTP cell area (identified by OTP_MK). 0.27 for PMOS') |
| pl2b_3p3_l1.forget |
| |
| # Rule PL.3ai_LV: Space on COMP. is 0.25µm |
| logger.info('Executing rule PL.3ai_LV') |
| pl3ai_l1 = (tgate).not(otp_mk).not_interacting(dualgate_2).space(0.25.um, euclidian).polygons(0.001) |
| pl3ai_l1.output('PL.3ai_LV', 'PL.3ai_LV : Space on COMP : 0.25µm') |
| pl3ai_l1.forget |
| |
| # Rule PL.3ai_MV: Space on COMP. is 0.4µm |
| logger.info('Executing rule PL.3ai_MV') |
| pl3ai_l1 = (tgate).not(otp_mk).not_interacting(dualgate).overlapping(dualgate_2).space(0.4.um, euclidian).polygons(0.001) |
| pl3ai_l1.output('PL.3ai_MV', 'PL.3ai_MV : Space on COMP : 0.4µm') |
| pl3ai_l1.forget |
| |
| |
| # Rule PL.3aii_LV: Space on Field. is 0.25µm |
| logger.info('Executing rule PL.3aii_LV') |
| pl3aii_l1 = (poly2.not(comp)).outside(sramcore).not_interacting(dualgate_2).not(otp_mk).space(0.25.um, euclidian).polygons(0.001) |
| pl3aii_l1.output('PL.3aii_LV', 'PL.3aii_LV : Space on Field. : 0.25µm') |
| pl3aii_l1.forget |
| |
| # Rule PL.3aii_MV: Space on Field. is 0.25µm |
| logger.info('Executing rule PL.3aii_LV') |
| pl3aii_l1 = (poly2.not(comp)).outside(sramcore).not_interacting(dualgate).overlapping(dualgate_2).not(otp_mk).space(0.25.um, euclidian).polygons(0.001) |
| pl3aii_l1.output('PL.3aii_MV', 'PL.3aii_MV : Space on Field. : 0.25µm') |
| pl3aii_l1.forget |
| |
| # Rule PL.4_LV: Extension beyond COMP to form Poly2 end cap. is 0.22µm |
| logger.info('Executing rule PL.4_LV') |
| comp_pl = comp.not(otp_mk) |
| pl4_l1 = comp_pl.enclosed(poly_pl_lv, 0.22.um, euclidian) |
| pl4_l1.output('PL.4_LV', 'PL.4_LV : Extension beyond COMP to form Poly2 end cap. : 0.22µm') |
| pl4_l1.forget |
| |
| # Rule PL.4_MV: Extension beyond COMP to form Poly2 end cap. is 0.22µm |
| logger.info('Executing rule PL.4_MV') |
| pl4_l1 = comp_pl.enclosed(poly_pl_mv, 0.22.um, euclidian) |
| pl4_l1.output('PL.4_MV', 'PL.4_MV : Extension beyond COMP to form Poly2 end cap. : 0.22µm') |
| pl4_l1.forget |
| |
| poly_pl = poly2.not(otp_mk) |
| comp_pl = comp.not(otp_mk) |
| # Rule PL.5a_LV: Space from field Poly2 to unrelated COMP Spacer from field Poly2 to Guard-ring. is 0.1µm |
| logger.info('Executing rule PL.5a_LV') |
| pl5a_l1 = poly_pl.not_interacting(dualgate_2).separation(comp_pl.not_interacting(poly_pl), 0.1.um, euclidian).polygons(0.001) |
| pl5a_l1.output('PL.5a_LV', 'PL.5a_LV : Space from field Poly2 to unrelated COMP Spacer from field Poly2 to Guard-ring. : 0.1µm') |
| pl5a_l1.forget |
| |
| # Rule PL.5a_MV: Space from field Poly2 to unrelated COMP Spacer from field Poly2 to Guard-ring. is 0.3µm |
| logger.info('Executing rule PL.5a_MV') |
| pl5a_l1 = poly_pl.not_interacting(dualgate).overlapping(dualgate_2).outside(sramcore).separation(comp_pl.not_interacting(poly_pl), 0.3.um, euclidian).polygons(0.001) |
| pl5a_l1.output('PL.5a_MV', 'PL.5a_MV : Space from field Poly2 to unrelated COMP Spacer from field Poly2 to Guard-ring. : 0.3µm') |
| pl5a_l1.forget |
| |
| # Rule PL.5b_LV: Space from field Poly2 to related COMP. is 0.1µm |
| logger.info('Executing rule PL.5b_LV') |
| pl5b_l1 = poly_pl.outside(sramcore).not_interacting(dualgate_2).separation(comp_pl.interacting(poly_pl), 0.1.um, euclidian).polygons(0.001) |
| pl5b_l1.output('PL.5b_LV', 'PL.5b_LV : Space from field Poly2 to related COMP. : 0.1µm') |
| pl5b_l1.forget |
| |
| # Rule PL.5b_MV: Space from field Poly2 to related COMP. is 0.3µm |
| logger.info('Executing rule PL.5b_MV') |
| pl5b_l1 = poly_pl.outside(sramcore).not_interacting(dualgate).overlapping(dualgate_2).outside(sramcore).separation(comp_pl.interacting(poly_pl), 0.3.um, euclidian).polygons(0.001) |
| pl5b_l1.output('PL.5b_MV', 'PL.5b_MV : Space from field Poly2 to related COMP. : 0.3µm') |
| pl5b_l1.forget |
| poly_pl.forget |
| comp_pl.forget |
| |
| poly_90deg = tgate.corners(90.0).sized(0.1) |
| # Rule PL.6: 90 degree bends on the COMP are not allowed. |
| logger.info('Executing rule PL.6') |
| pl6_l1 = poly_90deg.inside(comp) |
| pl6_l1.output('PL.6', 'PL.6 : 90 degree bends on the COMP are not allowed.') |
| pl6_l1.forget |
| |
| # Rule PL.7_LV_1.8V: 45 degree bent gate width is 0.2µm |
| logger.info('Executing rule PL.7_LV_1.8V') |
| nom_e1 = tgate.not_interacting(dualgate.or(dualgate_2)).edges.inside_part(comp).with_angle(45) |
| nom_e2 = tgate.not_interacting(dualgate.or(dualgate_2)).edges.inside_part(comp).with_angle(-45) |
| pl7_edges_nom = nom_e1.or(nom_e2) |
| pl7_l1 = pl7_edges_nom.width(0.2.um, euclidian) |
| pl7_l1.output('PL.7_LV_1.8V', 'PL.7_LV_1.8V : 45 degree bent gate width : 0.2µm') |
| pl7_l1.forget |
| nom_e1.forget |
| nom_e2.forget |
| pl7_edges_nom.forget |
| |
| # Rule PL.7_LV_3.3V: 45 degree bent gate width is 0.4µm |
| logger.info('Executing rule PL.7_LV_3.3V') |
| nom_e1 = tgate.overlapping(dualgate).not_interacting(dualgate_2).edges.inside_part(comp).with_angle(45) |
| nom_e2 = tgate.overlapping(dualgate).not_interacting(dualgate_2).edges.inside_part(comp).with_angle(-45) |
| pl7_edges_nom = nom_e1.or(nom_e2) |
| pl7_l1 = pl7_edges_nom.width(0.4.um, euclidian) |
| pl7_l1.output('PL.7_LV_3.3V', 'PL.7_LV_3.3V : 45 degree bent gate width : 0.4µm') |
| pl7_l1.forget |
| nom_e1.forget |
| nom_e2.forget |
| pl7_edges_nom.forget |
| |
| # Rule PL.7_MV: 45 degree bent gate width is 0.7µm |
| logger.info('Executing rule PL.7_MV') |
| thick_e1 = tgate.not_interacting(dualgate).overlapping(dualgate_2).edges.inside_part(comp).with_angle(25, 65) |
| thick_e2 = tgate.not_interacting(dualgate).overlapping(dualgate_2).edges.inside_part(comp).with_angle(-65, -25) |
| pl7_edges_thick = thick_e1.or(thick_e2) |
| pl7_l2 = pl7_edges_thick.width(0.7.um, euclidian) |
| pl7_l2.output('PL.7_MV', 'PL.7_MV : 45 degree bent gate width : 0.7µm') |
| pl7_l2.forget |
| thick_e1.forget |
| thick_e2.forget |
| pl7_edges_thick.forget |
| |
| # Rule PL.9: V5_Xtor must enclose 5V device. |
| logger.info('Executing rule PL.9') |
| pl9_l1 = v5_xtor.not_inside(dualgate_2.or(otp_mk)) |
| pl9_l1.output('PL.9', 'PL.9 : V5_Xtor must enclose 5V device.') |
| pl9_l1.forget |
| |
| # Rule PL.10 : Minimum DNWELL overlap of Poly2 is 0.5µm |
| logger.info('Executing rule PL.10') |
| pl10_l1 = dnwell.enclosing(poly2,0.5.um).polygons(0.001) |
| pl10_l2 = poly2.not_outside(dnwell).not_inside(dnwell) |
| pl10_l = pl10_l1.or(pl10_l2) |
| pl10_l.output('PL.10','PL.10 : Minimum DNWELL overlap of Poly2 is 0.5µm ') |
| pl10_l1.forget |
| pl10_l2.forget |
| pl10_l.forget |
| |
| # Rule PL.11: Poly2 interconnect connecting LV and MV areas (area inside and outside DV2/Dualgate) are not allowed. They shall be done though metal lines only. |
| logger.info('Executing rule PL.11') |
| pl11_l1 = poly2.interacting(poly2.not(v5_xtor).not(dualgate.or(dualgate_2))).interacting(poly2.and(dualgate.or(dualgate_2))) |
| pl11_l1.output('PL.11', 'PL.11 : Poly2 interconnect connecting LV and MV areas (area inside and outside DV2/Dualgate) are not allowed. They shall be done though metal lines only.') |
| pl11_l1.forget |
| |
| # Rule PL.12: V5_Xtor enclose 5V Comp. |
| logger.info('Executing rule PL.12') |
| pl12_l1 = comp.interacting(v5_xtor).not(v5_xtor) |
| pl12_l1.output('PL.12', 'PL.12 : V5_Xtor enclose 5V Comp.') |
| pl12_l1.forget |
| |
| end #FEOL |