| #!/usr/bin/env python3 |
| # Copyright 2020 The Skywater 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. |
| |
| import argparse |
| import os |
| import re |
| import subprocess |
| import json |
| from collections import defaultdict |
| from pathlib import Path |
| from common import lib_extract_from_path, version_extract_from_path, convert_libname |
| |
| sourcetodests = defaultdict(list) |
| |
| Copyright_header = ('# Copyright 2020 The Skywater PDK Authors\n' |
| '#\n' |
| '# Licensed under the Apache License, Version 2.0 (the "License");\n' |
| '# you may not use this file except in compliance with the License.\n' |
| '# You may obtain a copy of the License at\n' |
| '#\n' |
| '# https://www.apache.org/licenses/LICENSE-2.0\n' |
| '#\n' |
| '# Unless required by applicable law or agreed to in writing, software\n' |
| '# distributed under the License is distributed on an "AS IS" BASIS,\n' |
| '# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n' |
| '# See the License for the specific language governing permissions and\n' |
| '# limitations under the License.\n' |
| '\n') |
| |
| def remap_path(old_path, input_dir, output_dir, lib_name, new_lib_name): |
| """ |
| >>> remap_path('Dokumenty/SkyWater/skywater-src-nda/scs8hd/V0.0.1/lef/scs8hd.lef', 'Dokumenty/SkyWater/skywater-src-nda' ,'output', 'scs8hd', 'sky130_fd_sc_hd') |
| 'output/skywater-pdk/libraries/sky130_fd_sc_hd/V0.0.1/sky130_fd_sc_hd.lef' |
| >>> remap_path('Dokumenty/SkyWater/skywater-src-nda/s8iom0s8/V0.1.0/lef/s8iom0s8.lef', 'Dokumenty/SkyWater/skywater-src-nda' ,'output', 's8iom0s8', 'sky130_fd_io') |
| 'output/skywater-pdk/libraries/sky130_fd_io/V0.1.0/sky130_fd_io.lef' |
| >>> remap_path('Dokumenty/SkyWater/skywater-src-nda/s8fmlt/V0.1.0/lef/s8fmlt__16k_sys.lef', 'Dokumenty/SkyWater/skywater-src-nda' ,'output', 's8fmlt', 'sky130_fd_fmlt') |
| 'output/skywater-pdk/libraries/sky130_fd_fmlt/V0.1.0/sky130_fd_fmlt__16k_sys.lef' |
| """ |
| parent_dir = str(input_dir).split("/")[-1] |
| output_dir = str(output_dir) |
| |
| index = old_path.find(parent_dir) + len(parent_dir) |
| |
| target_dir, target_file = os.path.split(old_path[index:]) |
| if len(target_file.split('.')[0]) > len(lib_name): |
| target_file = target_file[:len(lib_name)] + '_' + target_file[len(lib_name)+1:] |
| new_path = output_dir +"/skywater-pdk/libraries" + target_dir.replace("/lef","") + "/" + target_file |
| |
| assert lib_name != None and new_lib_name != None |
| new_path = new_path.replace(lib_name, new_lib_name) |
| |
| return new_path |
| |
| def rewrite_lef(lef_file, out_file): |
| lef_file = os.path.abspath(lef_file) |
| p = subprocess.Popen(['lefrw', '-o', out_file , lef_file], stdout=subprocess.PIPE, stderr=subprocess.PIPE) |
| stdout , stderr = p.communicate() |
| ret = p.wait() |
| if stderr != b'': |
| print(stderr) |
| return ret |
| |
| def change_naming(contents, libi, new_lib_name): |
| assert new_lib_name != None |
| contents = contents.replace(lib + '_', new_lib_name + '__') |
| |
| return contents, new_lib_name |
| |
| def main(lef_file, lib_name, new_lib_name, out_file=None): |
| |
| rewrite_lef(lef_file, 'temp.lef') |
| with open('temp.lef') as in_f: |
| contents = in_f.read() |
| out, _ = change_naming(contents, lib_name, new_lib_name) |
| out = re.sub(r"Parsed [0-9]* number of lines!![\n]", "", out) |
| out = re.sub(r"MACRO\s+CLASS\s+[A-Z ]*[\n]", "", out) |
| out = re.sub(r"DIVIDER (?P<div>.) ;", "DIVIDERCHAR \"\g<div>\" ;", out) |
| out.replace(Copyright_header, '') |
| out = Copyright_header + out |
| |
| if out_file is not None: |
| dest_dir = os.path.split(out_file)[0] |
| if not os.path.isdir(dest_dir): |
| os.makedirs(dest_dir) |
| with open(out_file, 'w') as out_f: |
| out_f.write(out) |
| else: |
| pass |
| print(">>> Output:\n"+"_"*60+ "\n" + out) |
| |
| if __name__ == "__main__": |
| import doctest |
| fails, _ = doctest.testmod() |
| if fails>0: |
| exit() |
| parser = argparse.ArgumentParser() |
| parser.add_argument( |
| "input", |
| help="The path to the source directory/file", |
| type=Path) |
| parser.add_argument( |
| "output", |
| help="The path to the output directory", |
| type=Path) |
| parser.add_argument( |
| "sourcetodests", |
| help="output file mapping input to output", |
| type=Path) |
| args = parser.parse_args() |
| if not os.path.isdir(args.input): |
| lib = lib_extract_from_path(args.input) |
| new_lib = convert_libname(lib) |
| debug = True |
| main(str(args.input), lib, new_lib) |
| else: |
| files = sorted(args.input.rglob('*.lef')) |
| for f in files: |
| f = str(f) |
| if '/s8/' in f or 's8iom0s8' in f or 'sram' in f or 'osu130' in f or 's8iom0s8' in f or 's8fmlt' in f: |
| continue |
| |
| print(f) |
| lib = lib_extract_from_path(f) |
| print(lib) |
| new_lib = convert_libname(lib) |
| out_f = remap_path(f, args.input, args.output, lib, new_lib) |
| sourcetodests[f].append(out_f) |
| main(f, lib, new_lib, out_f) |
| os.remove('temp.lef') |
| with open(args.sourcetodests, 'w') as srctodest: |
| json.dump(sourcetodests, srctodest, indent=2) |
| |