| |
| # 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. |
| |
| #======================================================================================================================= |
| #----------------------------------------- GF 0.18 um IC DRC RULE DECK ------------------------------------------------ |
| #======================================================================================================================= |
| require 'time' |
| require 'logger' |
| require 'etc' |
| |
| exec_start_time = Time.now |
| |
| logger = Logger.new($stdout) |
| |
| logger.formatter = proc do |_severity, datetime, _progname, msg| |
| "#{datetime}: Memory Usage (" + `pmap #{Process.pid} | tail -1`[10, 40].strip + ") : #{msg} |
| " |
| end |
| |
| |
| #================================================ |
| #----------------- FILE SETUP ------------------- |
| #================================================ |
| logger.info("Starting running GF180IC Klayout DRC runset on #{$input}") |
| logger.info("Ruby Version for klayout: #{RUBY_VERSION}") |
| |
| if $input |
| if $topcell |
| source($input, $topcell) |
| else |
| source($input) |
| end |
| end |
| |
| logger.info('Loading database to memory is complete.') |
| |
| if $report |
| logger.info("GF180IC Klayout antenna DRC runset output at: #{$report}") |
| report('GF180 ANTENNA DRC Run Report at', $report) |
| else |
| layout_dir = Pathname.new(RBA::CellView.active.filename).parent.realpath |
| report_path = layout_dir.join('gf180_drc.lyrdb').to_s |
| logger.info("GF180IC Klayout antenna DRC runset output at default location: #{report_path}") |
| report('GF180 ANTENNA DRC Run Report at', report_path) |
| end |
| |
| #======================================================================================= |
| #------------------------------------- SWITCHES ---------------------------------------- |
| #======================================================================================= |
| |
| logger.info('Evaluate switches.') |
| |
| # threads |
| if $thr |
| threads($thr) |
| else |
| thr ||= Etc.nprocessors |
| threads(thr) |
| end |
| |
| logger.info("Number of threads to use #{$thr}") |
| |
| #=== PRINT DETAILS === |
| logger.info("Verbose mode: #{$verbose}") |
| if $verbose == 'true' |
| verbose(true) |
| else |
| verbose(false) |
| end |
| |
| # === TILING MODE === |
| case $run_mode |
| when 'tiling' |
| tiles(500.um) |
| tile_borders(10.um) |
| logger.info('Tiling mode is enabled.') |
| |
| when 'deep' |
| #=== HIER MODE === |
| deep |
| logger.info('deep mode is enabled.') |
| else |
| #=== FLAT MODE === |
| flat |
| logger.info('flat mode is enabled.') |
| end |
| |
| #====================================================================================================== |
| #--------------------------------------- LAYER DEFINITIONS -------------------------------------------- |
| #====================================================================================================== |
| |
| comp = polygons(22, 0).merged |
| dualgate = polygons(55, 0).merged |
| poly2 = polygons(30, 0).merged |
| nplus = polygons(32, 0).merged |
| pplus = polygons(31, 0).merged |
| contact = polygons(33, 0).merged |
| metal1 = polygons(34, 0).merged |
| via1 = polygons(35, 0).merged |
| metal2 = polygons(36, 0).merged |
| via2 = polygons(38, 0).merged |
| metal3 = polygons(42, 0).merged |
| via3 = polygons(40, 0).merged |
| metal4 = polygons(46, 0).merged |
| via4 = polygons(41, 0).merged |
| metal5 = polygons(81, 0).merged |
| via5 = polygons(82, 0).merged |
| metaltop = polygons(53, 0).merged |
| fusetop = polygons(75, 0).merged |
| |
| #====================================================================================================== |
| #--------------------------------------- LAYER DERIVATIONS -------------------------------------------- |
| #====================================================================================================== |
| |
| tgate = poly2 & comp |
| thin_gate = tgate.not(dualgate) |
| thick_gate = tgate.and(dualgate) |
| diode = nplus & comp |
| |
| # === LAYOUT EXTENT === |
| CHIP = extent.sized(0.0) |
| |
| #======================================================================================= |
| #------------------------------------- SWITCHES ---------------------------------------- |
| #======================================================================================= |
| |
| logger.info('Evaluate switches.') |
| |
| if $mim_option |
| MIM_OPTION = $mim_option |
| else |
| MIM_OPTION = false |
| end |
| |
| logger.info('MIM Option selected %s' % [MIM_OPTION]) |
| |
| # METAL_TOP |
| if $metal_top |
| METAL_TOP = $metal_top |
| else |
| METAL_TOP = '9K' |
| end |
| |
| logger.info('METAL_TOP Selected is %s' % [METAL_TOP]) |
| |
| if METAL_TOP == '6K' |
| met_top_thick = 0.69.um |
| |
| elsif METAL_TOP == '9K' |
| met_top_thick = 0.99.um |
| |
| elsif METAL_TOP == '11K' |
| met_top_thick = 1.19.um |
| |
| elsif METAL_TOP == '30K' |
| met_top_thick = 3.035.um |
| |
| end #METAL_TOP |
| |
| if $metal_level |
| METAL_LEVEL = $metal_level |
| else |
| METAL_LEVEL = '6LM' |
| end |
| |
| logger.info('METAL_STACK Selected is %s' % [METAL_LEVEL]) |
| |
| if METAL_LEVEL == '6LM' |
| top_via = via5 |
| topmin1_via = via4 |
| top_metal = metaltop |
| topmin1_metal = metal5 |
| elsif METAL_LEVEL == '5LM' |
| top_via = via4 |
| topmin1_via = via3 |
| top_metal = metal5 |
| topmin1_metal = metal4 |
| elsif METAL_LEVEL == '4LM' |
| top_via = via3 |
| topmin1_via = via2 |
| top_metal = metal4 |
| topmin1_metal = metal3 |
| elsif METAL_LEVEL == '3LM' |
| top_via = via2 |
| topmin1_via = via1 |
| top_metal = metal3 |
| topmin1_metal = metal2 |
| elsif METAL_LEVEL == '2LM' |
| top_via = via1 |
| topmin1_via = via1 |
| top_metal = metal2 |
| topmin1_metal = metal1 |
| end #METAL_LEVEL |
| |
| #========================================================================================================================= |
| #---------------------------------------------------- MAIN RUNSET -------------------------------------------------------- |
| #========================================================================================================================= |
| |
| diode_filter_factor = 1000 |
| |
| logger.info('Starting GF180IC ANTENNA DRC rules.') |
| |
| #======================================== |
| #----------------- POLY ----------------- |
| #======================================== |
| connect(poly2,tgate ) |
| connect(poly2,thin_gate ) |
| connect(poly2,thick_gate) |
| # Rule ANT.1: Maximum ratio of Poly2 perimeter area to related gate oxide area is 200 |
| logger.info('Executing rule ANT.1') |
| antenna_check(tgate,perimeter_only(poly2,0.2.um), 200).output('ANT.1','ANT.1: Maximum ratio of Poly2 perimeter area to related gate oxide area is 200') |
| |
| #======================================== |
| #--------------- CONTACT ---------------- |
| #======================================== |
| connect(poly2,contact) |
| connect(diode,contact) |
| # Rule ANT.8: Maximum ratio of contact area to related gate oxide area is 10 |
| logger.info('Executing rule ANT.8') |
| antenna_check(tgate, contact, 10).output('ANT.8','ANT.8: Maximum ratio of contact area to related gate oxide area is 10') |
| |
| #======================================== |
| #---------------- METAL1 ---------------- |
| #======================================== |
| connect(contact,metal1) |
| # Case (a): Connection to COMP is not present: Flag error (No diode) [Default] |
| # Rule ANT.2: Maximum ratio of Metal1 perimeter area to related gate oxide area is 400 |
| logger.info('Executing rule ANT.2') |
| antenna_check(thin_gate,perimeter_only(metal1,0.54.um), 400,[diode,400*diode_filter_factor]).output('ANT.2','ANT.2: Maximum ratio of Metal1 perimeter area to related thin gate oxide area is 400') |
| |
| #======================================== |
| #----------------- VIA1 ----------------- |
| #======================================== |
| connect(metal1, via1 ) |
| |
| # Case (a): Connection to COMP is not present: Flag error (No diode) [Default] |
| # Rule ANT.9: Maximum ratio of Via1 area to related gate oxide area is 20 |
| logger.info('Executing rule ANT.9') |
| antenna_check(thin_gate,via1, 20,[diode,20*diode_filter_factor]).output('ANT.9','ANT.9: Maximum ratio of Via1 area to related thin gate oxide area is 20') |
| |
| #======================================== |
| #---------------- METAL2 ---------------- |
| #======================================== |
| connect(via1, metal2 ) |
| |
| # Case (a): Connection to COMP is not present: Flag error (No diode) [Default] |
| # Rule ANT.3: Maximum ratio of Metal2 perimeter area to related gate oxide area is 400 |
| logger.info('Executing rule ANT.3') |
| antenna_check(thin_gate,perimeter_only(metal2,0.54.um), 400,[diode,400*diode_filter_factor]).output('ANT.3','ANT.3: Maximum ratio of Metal2 perimeter area to related gate oxide area is 400') |
| |
| #======================================== |
| #----------------- VIA2 ----------------- |
| #======================================== |
| connect(metal2, via2 ) |
| |
| # Case (a): Connection to COMP is not present: Flag error (No diode) [Default] |
| # Rule ANT.10: Maximum ratio of Via2 area to related gate oxide area is 20 |
| logger.info('Executing rule ANT.10') |
| antenna_check(thin_gate,via2, 20,[diode,20*diode_filter_factor]).output('ANT.10','ANT.10: Maximum ratio of Via2 area to related thin gate oxide area is 20') |
| |
| #======================================== |
| #---------------- METAL3 ---------------- |
| #======================================== |
| connect(via2, metal3 ) |
| |
| # Case (a): Connection to COMP is not present: Flag error (No diode) [Default] |
| # Rule ANT.4: Maximum ratio of Metal3 perimeter area to related gate oxide area is 400 |
| logger.info('Executing rule ANT.4') |
| antenna_check(thin_gate,perimeter_only(metal3,0.54.um), 400,[diode,400*diode_filter_factor]).output('ANT.4','ANT.4: Maximum ratio of Metal3 perimeter area to related gate oxide area is 400') |
| |
| #======================================== |
| #----------------- VIA3 ----------------- |
| #======================================== |
| connect(metal3, via3 ) |
| |
| # Case (a): Connection to COMP is not present: Flag error (No diode) [Default] |
| # Rule ANT.11: Maximum ratio of Via3 area to related gate oxide area is 20 |
| logger.info('Executing rule ANT.11') |
| antenna_check(thin_gate,via3, 20,[diode,20*diode_filter_factor]).output('ANT.11','ANT.11: Maximum ratio of Via3 area to related thin gate oxide area is 20') |
| |
| #======================================== |
| #---------------- METAL4 ---------------- |
| #======================================== |
| connect(via3, metal4 ) |
| |
| # Rule ANT.5: Maximum ratio of Metal4 perimeter area to related gate oxide area is 400 |
| logger.info('Executing rule ANT.5') |
| antenna_check(thin_gate,perimeter_only(metal4,0.54.um), 400,[diode,400*diode_filter_factor]).output('ANT.5','ANT.5: Maximum ratio of Metal4 perimeter area to related gate oxide area is 400') |
| |
| #======================================== |
| #----------------- VIA4 ----------------- |
| #======================================== |
| connect(metal4, via4 ) |
| |
| # Case (a): Connection to COMP is not present: Flag error (No diode) [Default] |
| # Rule ANT.12: Maximum ratio of Via4 area to related gate oxide area is 20 |
| logger.info('Executing rule ANT.12') |
| antenna_check(thin_gate,via4, 20,[diode,20*diode_filter_factor]).output('ANT.12','ANT.12: Maximum ratio of Via4 area to related thin gate oxide area is 20') |
| |
| #======================================== |
| #---------------- METAL5 ---------------- |
| #======================================== |
| connect(via4, metal5 ) |
| |
| # Rule ANT.6: Maximum ratio of Metal5 perimeter area to related gate oxide area is 400 |
| logger.info('Executing rule ANT.6') |
| antenna_check(thin_gate,perimeter_only(metal5,0.54.um), 400,[diode,400*diode_filter_factor]).output('ANT.6','ANT.6: Maximum ratio of Metal5 perimeter area to related gate oxide area is 400') |
| |
| #======================================== |
| #----------------- VIA5 ----------------- |
| #======================================== |
| connect(metal5, via5 ) |
| # Case (a): Connection to COMP is not present: Flag error (No diode) [Default] |
| # Rule ANT.13: Maximum ratio of Via5 area to related gate oxide area is 20 |
| logger.info('Executing rule ANT.13') |
| antenna_check(thin_gate,via5, 20,[diode,20*diode_filter_factor]).output('ANT.13','ANT.13: Maximum ratio of Via5 area to related thin gate oxide area is 20') |
| |
| #======================================== |
| #--------------- METALTOP --------------- |
| #======================================== |
| connect(via5, metaltop) |
| |
| # Rule ANT.7: Maximum ratio of MetalTop perimeter area to related gate oxide area is 400 |
| logger.info('Executing rule ANT.7') |
| antenna_check(thin_gate,perimeter_only(metaltop,met_top_thick), 400,[diode,400*diode_filter_factor]).output('ANT.7','ANT.7: Maximum ratio of Metaltop perimeter area to related gate oxide area is 400') |
| |
| exec_end_time = Time.now |
| run_time = exec_end_time - exec_start_time |
| logger.info('DRC Total Run time %f seconds' % [run_time]) |
| |
| #=================================== |
| #--------------- END --------------- |
| #=================================== |