| ################################################################################################ |
| # 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 BEOL |
| |
| #================================================ |
| #--------------------METALTOP-------------------- |
| #================================================ |
| |
| if METAL_TOP == '6K' |
| logger.info('MetalTop thickness 6k section') |
| |
| # Rule MT.1: min. metaltop width is 0.36µm |
| logger.info('Executing rule MT.1') |
| mt1_l1 = top_metal.width(0.36.um, euclidian).polygons(0.001) |
| mt1_l1.output('MT.1', 'MT.1 : min. metaltop width : 0.36µm') |
| mt1_l1.forget |
| |
| # Rule MT.2a: min. metaltop spacing is 0.38µm |
| logger.info('Executing rule MT.2a') |
| mt2a_l1 = top_metal.space(0.38.um, euclidian).polygons(0.001) |
| mt2a_l1.output('MT.2a', 'MT.2a : min. metaltop spacing : 0.38µm') |
| mt2a_l1.forget |
| |
| # Rule MT.2b: Space to wide metal top (length & width > 10um) is 0.6µm |
| logger.info('Executing rule MT.2b') |
| wide_top_metal = top_metal.not_interacting(top_metal.edges.with_length(nil, 10.um)) |
| mt2b_l1 = top_metal.separation(wide_top_metal, 0.5.um, euclidian) |
| mt2b_l1.output('MT.2b', 'MT.2b : Space to wide metal top (length & width > 10um) : 0.6µm') |
| mt2b_l1.forget |
| wide_top_metal.forget |
| |
| # Rule MT.4: Minimum MetalTop area is 0.1444µm² |
| logger.info('Executing rule MT.4') |
| mt4_l1 = top_metal.with_area(nil, 0.1444.um) |
| mt4_l1.output('MT.4', 'MT.4 : Minimum MetalTop area : 0.1444µm²') |
| mt4_l1.forget |
| |
| elsif (METAL_TOP == '8K' or METAL_TOP == '9K') |
| logger.info('MetalTop thickness 8k/9k section') |
| |
| # Rule MT.1: min. metaltop width is 0.44µm |
| logger.info('Executing rule MT.1') |
| mt1_l1 = top_metal.width(0.44.um, euclidian).polygons(0.001) |
| mt1_l1.output('MT.1', 'MT.1 : min. metaltop width : 0.44µm') |
| mt1_l1.forget |
| |
| # Rule MT.2a: min. metaltop spacing is 0.46µm |
| logger.info('Executing rule MT.2a') |
| mt2a_l1 = top_metal.space(0.46.um, euclidian).polygons(0.001) |
| mt2a_l1.output('MT.2a', 'MT.2a : min. metaltop spacing : 0.46µm') |
| mt2a_l1.forget |
| |
| # Rule MT.2b: Space to wide metal top (length & width > 10um) is 0.6µm |
| logger.info('Executing rule MT.2b') |
| wide_top_metal = top_metal.not_interacting(top_metal.edges.with_length(nil, 10.um)) |
| mt2b_l1 = top_metal.separation(wide_top_metal, 0.6.um, euclidian) |
| mt2b_l1.output('MT.2b', 'MT.2b : Space to wide metal top (length & width > 10um) : 0.6µm') |
| mt2b_l1.forget |
| wide_top_metal.forget |
| |
| # Rule MT.4: Minimum MetalTop area is 0.5625µm² |
| logger.info('Executing rule MT.4') |
| mt4_l1 = top_metal.with_area(nil, 0.5625.um) |
| mt4_l1.output('MT.4', 'MT.4 : Minimum MetalTop area : 0.5625µm²') |
| mt4_l1.forget |
| |
| elsif METAL_TOP == '30K' |
| logger.info('MetalTop thickness 30K section') |
| |
| # Rule MT30.1: Min. thick MetalTop width. is 1.8µm |
| logger.info('Executing rule MT30.1') |
| mt301_l1 = top_metal.width(1.8.um, euclidian).polygons(0.001) |
| mt301_l1.output('MT30.1', 'MT30.1 : Min. thick MetalTop width. : 1.8µm') |
| mt301_l1.forget |
| |
| # Rule MT30.2a: Minimum space between thick MetalTop. is 1.8µm |
| logger.info('Executing rule MT30.2a') |
| mt302a_l1 = top_metal.space(1.8.um, euclidian).polygons(0.001) |
| mt302a_l1.output('MT30.2a', 'MT30.2a : Minimum space between thick MetalTop. : 1.8µm') |
| mt302a_l1.forget |
| |
| # Rule MT30.2b: Minimum space between wide (length & width > 30um) MetalTop is 1.8µm |
| logger.info('Executing rule MT30.2b') |
| mt302b_wide = top_metal.interacting(top_metal.edges.with_length(nil, 30.um)) |
| mt302b_l1 = top_metal.separation(mt302b_wide, 1.8.um, euclidian).polygons(0.001) |
| mt302b_l1.output('MT30.2b', 'MT30.2b : Minimum space between wide (length & width > 30um) MetalTop : 1.8µm') |
| mt302b_l1.forget |
| mt302b_wide.forget |
| |
| # Rule MT30.3: The separation of two corners should satisfy the minimum spacing. is 1.8µm |
| logger.info('Executing rule MT30.3') |
| mt303_l1 = top_metal.space(1.8.um, euclidian).polygons(0.001) |
| mt303_l1.output('MT30.3', 'MT30.3 : The separation of two corners should satisfy the minimum spacing. : 1.8µm') |
| mt303_l1.forget |
| |
| # Rule MT30.4: The separation of single metal line from a any degree metal line should satisfy the minimum spacing. is 1.8µm |
| logger.info('Executing rule MT30.4') |
| mt304_l1 = top_metal.space(1.8.um, euclidian).polygons(0.001) |
| mt304_l1.output('MT30.4', 'MT30.4 : The separation of single metal line from a any degree metal line should satisfy the minimum spacing. : 1.8µm') |
| mt304_l1.forget |
| |
| # Rule MT30.5: Minimum thick MetalTop enclose underlying via (for example: via5 for 6LM case) [Outside Not Allowed]. |
| logger.info('Executing rule MT30.5') |
| mt305_l1 = top_metal.enclosing(top_via, 0.12.um, euclidian).polygons(0.001).or(top_via.not_inside(top_metal)) |
| mt305_l1.output('MT30.5', 'MT30.5 : Minimum thick MetalTop enclose underlying via (for example: via5 for 6LM case) [Outside Not Allowed].') |
| mt305_l1.forget |
| |
| mt30p6_cond = top_metal.drc(width < 2.5.um) |
| mt30p6_eol = top_metal.edges.with_length(nil, 2.5.um).interacting(mt30p6_cond.first_edges).interacting(mt30p6_cond.second_edges).not(mt30p6_cond.first_edges).not(mt30p6_cond.second_edges) |
| # Rule MT30.6: Thick MetalTop end-of-line overlap1 (width <2.5um, length>1.8um) of underlying via (for example: via5 for 6LM case). is 0.25 um |
| logger.info('Executing rule MT30.6') |
| mt306_l1 = mt30p6_eol.enclosing(top_via.edges,0.25.um, projection).polygons(0.001).or(top_via.not_inside(top_metal)) |
| mt306_l1.output('MT30.6', 'MT30.6 :Thick MetalTop end-of-line overlap1 (width <2.5um, length>1.8um) of underlying via (for example: via5 for 6LM case).: 0.25 um') |
| mt306_l1.forget |
| mt30p6_cond.forget |
| mt30p6_eol.forget |
| |
| # Rule MT30.8: There shall be minimum 2X2 array of vias |
| ## (top vias) at one location connecting to 3um thick top metal. |
| logger.info('Executing rule MT30.8') |
| mt308_egde_length = 0.26 * 1 + 1 * 0.26 |
| top_via_not_seal_ring = top_via.not(guard_ring_mk) |
| metal_top_intersections = top_metal.and(topmin1_metal).not(guard_ring_mk).interacting(top_via_not_seal_ring) |
| mt308_l1 = metal_top_intersections.interacting(top_via_not_seal_ring, 1, 3) |
| mt308_poss_l2 = metal_top_intersections.interacting(top_via_not_seal_ring, 4..nil) |
| mt308_poss_via = top_via_not_seal_ring.interacting(mt308_poss_l2) |
| mt308_poss_via_over_under = mt308_poss_via.sized(0.16, 'square_limit').merged.sized(-0.16, 'square_limit') |
| mt308_all = mt308_poss_via_over_under.with_bbox_min(mt308_egde_length..nil) |
| mt308_loc_exc = mt308_all.width(mt308_egde_length, |
| projection_limits(mt308_egde_length..1000 * mt308_egde_length)).polygons |
| mt308_loc = mt308_all.not_interacting(mt308_loc_exc) |
| mt308_l2 = mt308_poss_l2.not_interacting(mt308_loc) |
| mt308_l = mt308_l1.join(mt308_l2) |
| mt308_l.output('MT30.8', 'MT30.8 : There shall be minimum 2X2 array of vias |
| (top vias) at one location connecting to 3um thick top metal.') |
| top_via_not_seal_ring.forget |
| metal_top_intersections.forget |
| mt308_l1.forget |
| mt308_poss_l2.forget |
| mt308_poss_via.forget |
| mt308_poss_via_over_under.forget |
| mt308_all.forget |
| mt308_loc_exc.forget |
| mt308_loc.forget |
| mt308_l2.forget |
| mt308_l.forget |
| |
| elsif METAL_TOP == '20K' or METAL_TOP == '25K' |
| logger.info('MetalTop thickness 20k/25k section') |
| |
| # Rule MTK.1: Min. thick MetalTop width. is 1.5µm |
| logger.info('Executing rule MTK.1') |
| mtk1_l1 = top_metal.width(1.5.um).polygons(0.001) |
| mtk1_l1.output('MTK.1', 'MTK.1 : Min. thick MetalTop width. : 1.5µm') |
| mtk1_l1.forget |
| |
| # Rule MTK.2a: Minimum space between thick MetalTop. is 1.5µm |
| logger.info('Executing rule MTK.2a') |
| mtk2a_l1 = top_metal.space(1.5.um).polygons(0.001) |
| mtk2a_l1.output('MTK.2a', 'MTK.2a : Minimum space between thick MetalTop. : 1.5µm') |
| mtk2a_l1.forget |
| |
| wide_mt = top_metal.interacting(top_metal.edges.with_length(30.um,nil)) |
| # Rule MTK.2b: Minimum space between wide (length & width > 30um) MetalTop is 1.5µm |
| logger.info('Executing rule MTK.2b') |
| mtk2b_l1 = wide_mt.separation(top_metal.not(wide_mt),1.5.um).polygons(0.001) |
| mtk2b_l1.output('MTK.2b', 'MTK.2b : Minimum space between wide (length & width > 30um) MetalTop : 1.5µm') |
| mtk2b_l1.forget |
| |
| # Rule MTK.2c: The separation of two corners should satisfy the minimum spacing. is 1.5µm |
| logger.info('Executing rule MTK.2c') |
| mtk2c_l1 = top_metal.space(1.5.um).polygons(0.001) |
| mtk2c_l1.output('MTK.2c', 'MTK.2c : The separation of two corners should satisfy the minimum spacing. : 1.5µm') |
| mtk2c_l1.forget |
| |
| # Rule MTK.2d: The separation of single metal line from a any degree metal line should satisfy the minimum spacing. is 1.5µm |
| logger.info('Executing rule MTK.2d') |
| mtk2d_l1 = top_metal.space(1.5.um, euclidian).polygons(0.001) |
| mtk2d_l1.output('MTK.2d', 'MTK.2d : The separation of single metal line from a any degree metal line should satisfy the minimum spacing. : 1.5µm') |
| mtk2d_l1.forget |
| |
| # Rule MTK.7 : MetalTop must not be electrically floating |
| logger.info('Executing rule MTK.7') |
| mtk7_l1 = top_metal.not_interacting(top_via.inside(topmin1_metal)) |
| mtk7_l1.output('MTK.7','MTK.7 : MetalTop must not be electrically floating') |
| mtk7_l1.forget |
| |
| mtk9_via = top_via.sized(0.18.um).sized(-0.18.um).with_bbox_min(0.78.um , nil).extents.inside(top_metal) |
| mtk9_mask = mtk9_via.size(1).not(top_via).with_holes(4, nil) |
| mtk9_slct_via = top_via.interacting(mtk9_mask) |
| # Rule MTK.9: There shall be minimum 2X2 array of vias (top vias) at one location connecting to thick top metal. |
| logger.info('Executing rule MTK.9') |
| mtk9_l1 = topmin1_metal.not_interacting(mtk9_slct_via) |
| mtk9_l1.output('MTK.9', 'MTK.9 : There shall be minimum 2X2 array of vias (top vias) at one location connecting to thick top metal.') |
| mtk9_l1.forget |
| mtk9_via.forget |
| mtk9_mask.forget |
| mtk9_slct_via.forget |
| end #METAL_TOP |
| |
| end #BEOL |