blob: 18262a7e9925b488af6524fe70aa37d995d478bf [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 ULL 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 GF180ULL 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("GF180ULL 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("GF180ULL 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
lvpwell = polygons(204, 0 ).merged
dualgate = polygons(55, 0).merged
dualgate_2 = polygons(144, 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
v5_xtor = polygons(112, 1 ).merged
#======================================================================================================
#--------------------------------------- LAYER DERIVATIONS --------------------------------------------
#======================================================================================================
tgate = poly2 & comp
thin_gate = tgate.not(dualgate_2).not(v5_xtor)
thick_gate = tgate.and(dualgate_2).not(dualgate)
diode_ull = nplus.and(comp).inside(lvpwell)
diode_1p8 = diode_ull.not(dualgate).not(dualgate_2).not(v5_xtor)
diode_3p3 = diode_ull.and(dualgate).not(dualgate_2).not(v5_xtor)
diode_6p0 = diode_ull.not(dualgate).and(dualgate_2).not(v5_xtor)
diode = diode_1p8.or(diode_3p3).or(diode_6p0)
# === 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 --------------------------------------------------------
#=========================================================================================================================
logger.info('Starting GF180ULL 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)
# Rule ANT.2_thin: Diode filtering for ANT.2 [thin gate] , MF = 2
logger.info('Executing rule ANT.2_thin')
antenna_check(thin_gate,perimeter_only(metal1,0.54.um), 400,[diode,800]).output('ANT.2_thin','ANT.2_thin: Maximum ratio of Metal1 perimeter area to related thin gate oxide area is 400')
# Rule ANT.2_thick: Diode filtering for ANT.2 [thick gate] , MF = 15
logger.info('Executing rule ANT.2_thick')
antenna_check(thick_gate,perimeter_only(metal1,0.54.um), 400,[diode,6000]).output('ANT.2_thick','ANT.2_thick: Maximum ratio of Metal1 perimeter area to related thick gate oxide area is 400')
#========================================
#----------------- VIA1 -----------------
#========================================
connect(metal1, via1 )
# Rule ANT.9_thin: Diode filtering for ANT.9 [thin gate]
logger.info('Executing rule ANT.9_thin')
antenna_check(thin_gate,via1, 20,[diode,40]).output('ANT.9_thin','ANT.9_thin: Maximum ratio of Via1 area to related thin gate oxide area is 20')
# Rule ANT.9_thick: Diode filtering for ANT.9 [thick gate]
logger.info('Executing rule ANT.9_thick')
antenna_check(thick_gate,via1, 20,[diode,300]).output('ANT.9_thick','ANT.9_thick: Maximum ratio of Via1 area to related thick gate oxide area is 20')
#========================================
#---------------- METAL2 ----------------
#========================================
connect(via1, metal2 )
# Rule ANT.3_thin: Diode filtering for ANT.3 [thin gate]
logger.info('Executing rule ANT.3_thin')
antenna_check(thin_gate,perimeter_only(metal2,0.54.um), 400,[diode,800]).output('ANT.3_thin','ANT.3_thin: Maximum ratio of Metal2 perimeter area to related gate oxide area is 400')
# Rule ANT.3_thick: Diode filtering for ANT.3 [thick gate]
logger.info('Executing rule ANT.3_thick')
antenna_check(thick_gate,perimeter_only(metal2,0.54.um), 400,[diode,6000]).output('ANT.3_thick','ANT.3_thick: Maximum ratio of Metal2 perimeter area to related gate oxide area is 400')
#========================================
#----------------- VIA2 -----------------
#========================================
connect(metal2, via2 )
# Rule ANT.10_thin: Diode filtering for ANT.10 [thin gate]
logger.info('Executing rule ANT.10_thin')
antenna_check(thin_gate,via2, 20,[diode,40]).output('ANT.10_thin','ANT.10_thin: Maximum ratio of Via2 area to related thin gate oxide area is 20')
# Rule ANT.10_thick: Diode filtering for ANT.10 [thick gate]
logger.info('Executing rule ANT.10_thick')
antenna_check(thick_gate,via2, 20,[diode,300]).output('ANT.10_thick','ANT.10_thick: Maximum ratio of Via2 area to related thick gate oxide area is 20')
#========================================
#---------------- METAL3 ----------------
#========================================
connect(via2, metal3 )
# Rule ANT.4_thin: Diode filtering for ANT.4 [thin gate]
logger.info('Executing rule ANT.4_thin')
antenna_check(thin_gate,perimeter_only(metal3,0.54.um), 400,[diode,800]).output('ANT.4_thin','ANT.4_thin: Maximum ratio of Metal3 perimeter area to related gate oxide area is 400')
# Rule ANT.4_thick: Diode filtering for ANT.4 [thick gate]
logger.info('Executing rule ANT.4_thick')
antenna_check(thick_gate,perimeter_only(metal3,0.54.um), 400,[diode,6000]).output('ANT.4_thick','ANT.4_thick: Maximum ratio of Metal3 perimeter area to related gate oxide area is 400')
#========================
#----- MIM OPTION A -----
#========================
if MIM_OPTION == 'A'
connect(metal3, fusetop )
# Rule ANT.14_M3_MIMA: Maximum ratio of each of the metal3 layer perimeter area to related MIM area is 400
logger.info('Executing rule ANT.14_M3_MIMA')
antenna_check(fusetop,perimeter_only(metal3,0.54.um), 400,[diode,6000]).output('ANT.14_M3_MIMA','ANT.14_M3_MIMA: Maximum ratio of each of the metal3 layer perimeter area to related MIM area is 400')
# Rule ANT.15_V2_MIMA: Maximum ratio of each of Via2 area to related MIM area is 20
logger.info('Executing rule ANT.15_V2_MIMA')
antenna_check(fusetop, via2, 20,[diode,300]).output('ANT.15_V2_MIMA','ANT.15_V2_MIMA: Maximum ratio of each of Via2 area to related MIM area is 20')
end
#========================================
#----------------- VIA3 -----------------
#========================================
connect(metal3, via3 )
# Rule ANT.11_thin: Diode filtering for ANT.11 [thin gate]
logger.info('Executing rule ANT.11_thin')
antenna_check(thin_gate,via3, 20,[diode,40]).output('ANT.11_thin','ANT.11_thin: Maximum ratio of Via3 area to related thin gate oxide area is 20')
# Rule ANT.11_thick: Diode filtering for ANT.11 [thick gate]
logger.info('Executing rule ANT.11_thick')
antenna_check(thick_gate,via3, 20,[diode,300]).output('ANT.11_thick','ANT.11_thick: Maximum ratio of Via3 area to related thick gate oxide area is 20')
#========================
#----- MIM OPTION A -----
#========================
if MIM_OPTION == 'A'
# Rule ANT.15_V3_MIMA: Maximum ratio of each of Via2 area to related MIM area is 20
logger.info('Executing rule ANT.15_V3_MIMA')
antenna_check(fusetop, via3, 20,[diode,300]).output('ANT.15_V3_MIMA','ANT.15_V3_MIMA: Maximum ratio of each of Via3 area to related MIM area is 20')
end
#========================================
#---------------- METAL4 ----------------
#========================================
connect(via3, metal4 )
# Rule ANT.5_thin: Diode filtering for ANT.5 [thin gate]
logger.info('Executing rule ANT.5_thin')
antenna_check(thin_gate,perimeter_only(metal4,0.54.um), 400,[diode,800]).output('ANT.5_thin','ANT.5_thin: Maximum ratio of Metal4 perimeter area to related gate oxide area is 400')
# Rule ANT.5_thick: Diode filtering for ANT.5 [thick gate]
logger.info('Executing rule ANT.5_thick')
antenna_check(thick_gate,perimeter_only(metal4,0.54.um), 400,[diode,6000]).output('ANT.5_thick','ANT.5_thick: Maximum ratio of Metal4 perimeter area to related gate oxide area is 400')
#========================
#----- MIM OPTION A -----
#========================
if MIM_OPTION == 'A'
# Rule ANT.14_M4_MIMA: Maximum ratio of each of the metal3 layer perimeter area to related MIM area is 400
logger.info('Executing rule ANT.15_V3_MIMA')
antenna_check(fusetop,perimeter_only(metal4,0.54.um), 400,[diode,6000]).output('ANT.14_M4_MIMA','ANT.14_M4_MIMA: Maximum ratio of each of the metal4 layer perimeter area to related MIM area is 400')
end
#========================================
#----------------- VIA4 -----------------
#========================================
connect(metal4, via4 )
# Rule ANT.12_thin: Diode filtering for ANT.12 [thin gate]
logger.info('Executing rule ANT.12_thin')
antenna_check(thin_gate,via4, 20,[diode,40]).output('ANT.12_thin','ANT.12_thin: Maximum ratio of Via4 area to related thin gate oxide area is 20')
# Rule ANT.12_thick: Diode filtering for ANT.12 [thick gate]
logger.info('Executing rule ANT.12_thick')
antenna_check(thick_gate,via4, 20,[diode,300]).output('ANT.12_thick','ANT.12_thick: Maximum ratio of Via4 area to related thick gate oxide area is 20')
#========================
#----- MIM OPTION A -----
#========================
if MIM_OPTION == 'A'
# Rule ANT.15_V4_MIMA: Maximum ratio of each of Via2 area to related MIM area is 20
logger.info('Executing rule ANT.15_V4_MIMA')
antenna_check(fusetop, via4, 20,[diode,300]).output('ANT.15_V4_MIMA','ANT.15_V4_MIMA: Maximum ratio of each of Via4 area to related MIM area is 20')
end
#========================================
#---------------- METAL5 ----------------
#========================================
connect(via4, metal5 )
# Rule ANT.6_thin: Diode filtering for ANT.6 [thin gate]
logger.info('Executing rule ANT.6_thin')
antenna_check(thin_gate,perimeter_only(metal5,0.54.um), 400,[diode,800]).output('ANT.6_thin','ANT.6_thin: Maximum ratio of Metal5 perimeter area to related gate oxide area is 400')
# Rule ANT.6_thick: Diode filtering for ANT.6 [thick gate]
logger.info('Executing rule ANT.6_thick')
antenna_check(thick_gate,perimeter_only(metal5,0.54.um), 400,[diode,6000]).output('ANT.6_thick','ANT.6_thick: Maximum ratio of Metal5 perimeter area to related gate oxide area is 400')
#========================
#----- MIM OPTION A -----
#========================
if MIM_OPTION == 'A'
# Rule ANT.14_M5_MIMA: Maximum ratio of each of the metal3 layer perimeter area to related MIM area is 400
logger.info('Executing rule ANT.14_M5_MIMA')
antenna_check(fusetop,perimeter_only(metal5,0.54.um), 400,[diode,6000]).output('ANT.14_M5_MIMA','ANT.14_M5_MIMA: Maximum ratio of each of the metal5 layer perimeter area to related MIM area is 400')
end
#========================================
#----------------- VIA5 -----------------
#========================================
connect(metal5, via5 )
# Rule ANT.13_thin: Diode filtering for ANT.13 [thin gate]
logger.info('Executing rule ANT.13_thin')
antenna_check(thin_gate,via5, 20,[diode,40]).output('ANT.13_thin','ANT.13_thin: Maximum ratio of Via5 area to related thin gate oxide area is 20')
# Rule ANT.13_thick: Diode filtering for ANT.13 [thick gate]
logger.info('Executing rule ANT.13_thick')
antenna_check(thick_gate,via5, 20,[diode,300]).output('ANT.13_thick','ANT.13_thick: Maximum ratio of Via5 area to related thick gate oxide area is 20')
#========================
#----- MIM OPTION A -----
#========================
if MIM_OPTION == 'A'
# Rule ANT.15_V5_MIMA: Maximum ratio of each of Via2 area to related MIM area is 20
logger.info('Executing rule ANT.15_V5_MIMA')
antenna_check(fusetop, via5, 20,[diode,300]).output('ANT.15_V5_MIMA','ANT.15_V5_MIMA: Maximum ratio of each of Via5 area to related MIM area is 20')
end
#========================================
#--------------- METALTOP ---------------
#========================================
connect(via5, metaltop)
# Rule ANT.7_thin: Diode filtering for ANT.7 [thin gate]
logger.info('Executing rule ANT.7_thin')
antenna_check(thin_gate,perimeter_only(metaltop,met_top_thick), 400,[diode,800]).output('ANT.7_thin','ANT.7_thin: Maximum ratio of Metaltop perimeter area to related gate oxide area is 400')
# Rule ANT.7_thick: Diode filtering for ANT.7 [thick gate]
logger.info('Executing rule ANT.7_thick')
antenna_check(thick_gate,perimeter_only(metaltop,met_top_thick), 400,[diode,6000]).output('ANT.7_thick','ANT.7_thick: Maximum ratio of Metaltop perimeter area to related gate oxide area is 400')
#========================
#----- MIM OPTION A -----
#========================
if MIM_OPTION == 'A'
# Rule ANT.14_MT_MIMA: Maximum ratio of each of the metal3 layer perimeter area to related MIM area is 400
logger.info('Executing rule ANT.14_MT_MIMA')
antenna_check(fusetop,perimeter_only(metaltop,met_top_thick), 400,[diode,6000]).output('ANT.14_MT_MIMA','ANT.14_MT_MIMA: Maximum ratio of each of the Metaltop layer perimeter area to related MIM area is 400')
end
#========================
#----- MIM OPTION B -----
#========================
if MIM_OPTION == 'B'
connect(metaltop, fusetop )
# Rule ANT.14_MT_MIMB: Maximum ratio of each of the metal3 layer perimeter area to related MIM area is 400
logger.info('Executing rule ANT.14_MT_MIMB')
antenna_check(fusetop,perimeter_only(metaltop,met_top_thick), 400,[diode,6000]).output('ANT.14_MT_MIMB','ANT.14_MT_MIMB: Maximum ratio of each of the metaltop layer perimeter area to related MIM area is 400')
end
exec_end_time = Time.now
run_time = exec_end_time - exec_start_time
logger.info('DRC Total Run time %f seconds' % [run_time])
#===================================
#--------------- END ---------------
#===================================