blob: 274f9740c8cca6f1f3a019291ca82d82eda15bdd [file] [log] [blame] [edit]
#!/usr/bin/env python3
# adapted from openroad
import re
import sys
import os
import argparse # argument parsing
# Parse and validate arguments
# ==============================================================================
parser = argparse.ArgumentParser(
description='Adds padding to the right of all macros in a lef file')
parser.add_argument('--right', '-r', required=False, type=float,
default='0',
help='Padding on the right in SITE widths')
parser.add_argument('--left', '-l', required=False, type=float,
default='0',
help='Padding on the left in SITE widths')
parser.add_argument('--top', '-t', required=False, type=float,
default='0',
help='Padding on the top in SITE heights')
parser.add_argument('--bottom', '-b', required=False, type=float,
default='0',
help='Padding on the bottom in SITE heights')
parser.add_argument('--site', '-s', required=False,
default='0',
help='Lef SITE')
parser.add_argument('--exclude', '-e', required=False,
default='ENDCAPTIE* CNRCAP* INCNR* TBCAP* FILL* WELLTAP* tsmc65lp_* gf14_* fakeram45_*',
help='exclude')
parser.add_argument('--inputLef', '-i', required=True,
help='Input LEF')
parser.add_argument('--outputLef', '-o', required=True,
help='Output LEF')
args = parser.parse_args()
REGEXNUM = "-?\d+\.?\d*"
def replace_size(match):
m = match.groups()
newWidth = float(m[0]) + right_padding + left_padding
newHeight = float(m[1]) + top_padding + bottom_padding
return "SIZE " + '{0:g}'.format(newWidth) + " BY " + '{0:g}'.format(newHeight)
def replace_rect(match):
m = match.groups()
pt1 = '{0:g}'.format(float(m[0]) + left_padding) + " " + '{0:g}'.format(float(m[1]) + bottom_padding)
pt2 = '{0:g}'.format(float(m[2]) + left_padding) + " " + '{0:g}'.format(float(m[3]) + bottom_padding)
return "RECT " + pt1 + " " + pt2
def replace_rectMask(match):
m = match.groups()
pt1 = '{0:g}'.format(float(m[0]) + left_padding) + " " + '{0:g}'.format(float(m[1]) + bottom_padding)
pt2 = '{0:g}'.format(float(m[2]) + left_padding) + " " + '{0:g}'.format(float(m[3]) + bottom_padding)
return "RECT MASK " + str(m[0]) + " " + pt1 + " " + pt2
# Function used by re.sub
def replace_pad(match):
m = match.groups()
skip = 0
# Check if it's a MACRO to be skipped
for pattern in args.exclude.split():
if re.match(pattern, m[0]):
print('Skipping LEF padding for MACRO ', m[0])
return match.group()
returnString = match.group()
# Pad SIZE
sizePattern = r"SIZE\s+(" + REGEXNUM + r")\s+BY\s+(" + REGEXNUM + r")"
returnString = re.sub(sizePattern, replace_size, returnString, 0, re.M | re.DOTALL)
# Pad RECTs
rectPattern = r"RECT\s+(" + REGEXNUM + r")\s+(" + REGEXNUM + r")\s+(" + REGEXNUM + r")\s+(" + REGEXNUM + r")"
returnString = re.sub(rectPattern, replace_rect, returnString, 0, re.M | re.DOTALL)
# Pad RECT MASKs
rectMastPattern = r"^RECT\s+MASK\s+(" + REGEXNUM + r")\s+(" + REGEXNUM + r")\s+(" + REGEXNUM + r")\s+(" + REGEXNUM + r")"
returnString = re.sub(rectMastPattern, replace_rectMask, returnString, 0, re.M | re.DOTALL)
return returnString
print(os.path.basename(__file__),": Padding technology lef file")
# Read input file
f = open(args.inputLef)
content = f.read()
f.close()
# Find SITE width
sitePattern = r"^SITE\s+" + args.site + r".*SIZE\s+(" + REGEXNUM + r")\s+BY\s+(" + REGEXNUM + r").*END\s+" + args.site
m = re.search(sitePattern, content, re.M | re.DOTALL)
if m:
site_width = float(m.group(1))
site_height = float(m.group(2))
right_padding = float(args.right) * site_width
left_padding = float(args.left) * site_width
top_padding = float(args.top) * site_height
bottom_padding = float(args.bottom) * site_height
else:
raise ValueError("Error: Pattern search for SITE size failed")
print("Derived SITE width (microns): " + str(site_width))
print("Derived SITE height (microns): " + str(site_height))
print("Right cell padding (microns): " + str(right_padding))
print("Left cell padding (microns): " + str(left_padding))
print("Top cell padding (microns): " + str(top_padding))
print("Bottom cell padding (microns): " + str(bottom_padding))
# Perform substitution on every macro
pattern = r"^MACRO\s+(\S+).*?^END\s\S+"
result, count = re.subn(pattern, replace_pad, content, 0, re.M | re.DOTALL)
# Write output file
f = open(args.outputLef, "w")
f.write(result)
f.close()
# Check
if count < 1:
print("WARNING: Replacement pattern not found")
# sys.exit(1)
print(os.path.basename(__file__),": Finished")