| #!/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") |