blob: 0281f6ec4f03a77e28c0e48a9bdf911de1312c3e [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.
#=======================================================================================================================
#----------------------------------------- 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 ---------------
#===================================