blob: 4871b5ec3fd5d7ec64d9e8385517f13ad77245b5 [file] [log] [blame]
#!/usr/bin/env python3
#
#--------------------------------------------------------------------
# make_minmax_techlef.py --
#
# From a nominal technology LEF file, create the corresponding
# technology files for the minimum and maximum process corners.
# Currently this only considers the change in layer and via
# resistance, not parasitic capacitance.
#
# Usage:
#
# make_minmax_techlef.py -variant=sky130A|sky130B
# -library=hd|hs|lp|ls|ms|hdll|hvl
# [-ef_format]
#
# Given the PDK variant and library name, finds the technology
# LEF file in the staging area with the nominal corner values,
# and creates two additional technology LEF files for the
# minimum and maximum corners.
#--------------------------------------------------------------------
import os
import re
import sys
options = []
arguments = []
for item in sys.argv[1:]:
if item.find('-', 0) == 0:
options.append(item[1:])
else:
arguments.append(item)
variant = 'sky130A'
lib = 'hd'
tlefpath = variant + '/libs.ref/sky130_fd_sc_' + lib + '/techlef'
if len(options) > 0:
for option in options:
if option.startswith('variant'):
variant = option.split('=')[1]
elif option.startswith('library'):
lib = option.split('=')[1]
tlefpath = variant + '/libs.ref/sky130_fd_sc_' + lib + '/techlef'
for option in options:
if option == 'ef_format':
tlefpath = variant + '/libs.ref/techLEF/sky130_fd_sc_' + lib
elif len(arguments) > 0:
tlefpath = arguments[0]
tlefbase = 'sky130_fd_sc_' + lib + '__'
tlefnom = tlefbase + 'nom.tlef'
resrex1 = re.compile('^[ \t]*RESISTANCE RPERSQ')
resrex2 = re.compile('^[ \t]*RESISTANCE')
layerrex = re.compile('^[ \t]*LAYER ([^ \t\n]+)')
# Resistance values, by layer
rnom = {}
rmin = {}
rmax = {}
# Nominal values are for reference only; they're not used in the code below
rnom['li1'] = '12.8'
rnom['mcon'] = '9.3'
rnom['met1'] = '0.125'
rnom['via'] = '4.5'
rnom['met2'] = '0.125'
rnom['via2'] = '3.41'
rnom['met3'] = '0.047'
rnom['via3'] = '3.41'
rnom['met4'] = '0.047'
rnom['via4'] = '0.38'
rnom['met5'] = '0.0285'
rmin['li1'] = '9.2'
rmin['mcon'] = '1.6'
rmin['met1'] = '0.105'
rmin['via'] = '2.0'
rmin['met2'] = '0.105'
rmin['via2'] = '0.5'
rmin['met3'] = '0.038'
rmin['via3'] = '0.5'
rmin['met4'] = '0.038'
rmin['via4'] = '0.012'
rmin['met5'] = '0.0212'
rmax['li1'] = '17.0'
rmax['mcon'] = '23.0'
rmax['met1'] = '0.145'
rmax['via'] = '15.0'
rmax['met2'] = '0.145'
rmax['via2'] = '8.0'
rmax['met3'] = '0.056'
rmax['via3'] = '8.0'
rmax['met4'] = '0.056'
rmax['via4'] = '0.891'
rmax['met5'] = '0.0358'
if variant == 'sky130B':
rnom['via'] = '9.0'
rmin['via'] = '4.0'
rmax['via'] = '30.0'
#--------------------------------------------------------------------
infile_name = tlefpath + '/' + tlefnom
print('Creating minimum and maximum corner variants of ' + infile_name)
if not os.path.exists(infile_name):
print('Error: Cannot find file ' + infile_name)
sys.exit(1)
for corner in ['min', 'max']:
tleffile = tlefbase + corner + '.tlef'
outfile_name = tlefpath + '/' + tleffile
infile = open(infile_name, 'r')
outfile = open(outfile_name, 'w')
curlayer = None
value = None
for line in infile:
rmatch1 = resrex1.match(line)
rmatch2 = resrex2.match(line)
lmatch = layerrex.match(line)
if lmatch:
curlayer = lmatch.group(1)
if curlayer in rnom:
if corner == 'min':
value = rmin[curlayer]
else:
value = rmax[curlayer]
else:
value = None
outfile.write(line)
elif value and rmatch1:
outfile.write(' RESISTANCE RPERSQ ' + value + ' ;\n')
elif value and rmatch2:
outfile.write(' RESISTANCE ' + value + ' ;\n')
else:
outfile.write(line)
infile.close()
outfile.close()