| #!/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 json |
| import os |
| import re |
| import sys |
| from collections import defaultdict |
| from common import lib_extract_from_name, lib_extract_from_path |
| from pathlib import Path |
| |
| debug = True |
| debug_print = lambda x: print(x) if debug else 0 |
| |
| 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 create_file(module, header , main_cell_dir, lib_name): |
| """ |
| >>> create_file('MACRO sky130_fd_io__smth END sky130_fd_io__smth', '', 'output/skywater-pdk/libraries/sky130_fd_io/V0.1.0/cells', 'sky130_fd_io') |
| 'output/skywater-pdk/libraries/sky130_fd_io/V0.1.0/cells/smth/sky130_fd_io__smth.lef' |
| """ |
| global debug |
| re_modname = re.compile(rf'{lib_name}\w*') |
| full_name = re_modname.search(module)[0] |
| module = module.replace(Copyright_header, '') |
| header = header.replace(Copyright_header, '') |
| module = Copyright_header + header + module + '[\n]END LIBRARY' |
| mod_name = full_name.replace(lib_name + '__', '') |
| # remove strenght spec from mod |
| mod_name = re.sub(r'_[0-9][0-9]?$', '', mod_name) |
| path = main_cell_dir + '/' + mod_name |
| # write file |
| file_path = path + '/' + full_name + '.lef' |
| if debug: |
| pass |
| else: |
| if not os.path.isdir(path): |
| os.makedirs(path) |
| with open(file_path, 'w') as f_out: |
| f_out.write(module) |
| return file_path |
| |
| |
| def main(input_file): |
| global sourcetodests |
| with open(input_file, 'r') as in_f: |
| contents = in_f.read() |
| main_cell_dir = "/".join(input_file.split("/")[:-1])+ "/cells" |
| lib = lib_extract_from_path(input_file) |
| |
| header_end_index = contents.find('MACRO') |
| header = contents[:header_end_index] |
| cell_search = re.findall(rf'(?s)MACRO {lib}\w*?[\n].*?END {lib}\w*', contents) |
| if cell_search is not None: |
| for cell in cell_search: |
| out_f = create_file(cell, header, main_cell_dir, lib) |
| print('\t' + out_f) |
| sourcetodests[f].append(out_f) |
| else: |
| sys.exit(f"Cannot find a single module deifinition in file {input_file}.") |
| #remove source file |
| os.remove(input_file) |
| |
| |
| if __name__ == "__main__": |
| import doctest |
| fails, _ = doctest.testmod() |
| if fails != 0: |
| exit() |
| else: |
| print("Tests Passed") |
| parser = argparse.ArgumentParser() |
| parser.add_argument( |
| "input", |
| help="The path to the source directory", |
| type=Path) |
| parser.add_argument( |
| "sourcetodests", |
| help="Output file mapping input to output", |
| type=Path) |
| debug = False |
| args = parser.parse_args() |
| files = sorted(args.input.rglob('sky130_fd_sc_*.lef')) |
| for f in files: |
| f = str(f) |
| print(f) |
| main(f) |
| with open(args.sourcetodests, 'w') as srctodest: |
| json.dump(sourcetodests, srctodest, indent=2) |
| |
| |
| |