From f01acb5c2e875acac9e9a1347b251099378b7eba Mon Sep 17 00:00:00 2001 From: Matt Liberty Date: Wed, 2 Feb 2022 16:44:10 -0800 Subject: [PATCH] Add scripts/pdk-linker.py for ORFS/OL integration and ioplacer update (#897) * Add scripts/pdk-linker.py for ORFS/OL integration Signed-off-by: Matt Liberty * Add *~ to .gitignore Signed-off-by: Matt Liberty * Update ioplacer.tcl to use proper tcl commands Also allow skipping the calls Signed-off-by: Matt Liberty * black format pdk-linker.py Signed-off-by: Matt Liberty --- .gitignore | 5 +- scripts/openroad/ioplacer.tcl | 18 ++++-- scripts/pdk-linker.py | 105 ++++++++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+), 7 deletions(-) create mode 100755 scripts/pdk-linker.py diff --git a/.gitignore b/.gitignore index eb4d0843..fb97f5b5 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,10 @@ tags .vim -# Flow Artefacts +# emacs backup files +*~ + +# Flow Artifacts dummy.guide lefRWarning.log run.param diff --git a/scripts/openroad/ioplacer.tcl b/scripts/openroad/ioplacer.tcl index aa16089c..baf15b66 100755 --- a/scripts/openroad/ioplacer.tcl +++ b/scripts/openroad/ioplacer.tcl @@ -27,14 +27,20 @@ if {[catch {read_def $::env(CURRENT_DEF)} errmsg]} { exit 1 } -set_pin_length -hor_length $::env(FP_IO_HLENGTH) \ - -ver_length $::env(FP_IO_VLENGTH) +if {$::env(FP_IO_HLENGTH) != "" && $::env(FP_IO_HLENGTH) != ""} { + set_pin_length -hor_length $::env(FP_IO_HLENGTH) \ + -ver_length $::env(FP_IO_VLENGTH) +} -set_pin_length_extension -hor_extension $::env(FP_IO_HEXTEND) \ - -ver_extension $::env(FP_IO_VEXTEND) +if {$::env(FP_IO_HLENGTH) != "" && $::env(FP_IO_HLENGTH) != ""} { + set_pin_length_extension -hor_extension $::env(FP_IO_HEXTEND) \ + -ver_extension $::env(FP_IO_VEXTEND) +} -set_pin_thick_multiplier -hor_multiplier $::env(FP_IO_HTHICKNESS_MULT) \ - -ver_multiplier $::env(FP_IO_VTHICKNESS_MULT) +if {$::env(FP_IO_HLENGTH) != "" && $::env(FP_IO_HLENGTH) != ""} { + set_pin_thick_multiplier -hor_multiplier $::env(FP_IO_HTHICKNESS_MULT) \ + -ver_multiplier $::env(FP_IO_VTHICKNESS_MULT) +} set arg_list [list] if { $::env(FP_IO_MODE) == 1 } { diff --git a/scripts/pdk-linker.py b/scripts/pdk-linker.py new file mode 100755 index 00000000..d9a0782a --- /dev/null +++ b/scripts/pdk-linker.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 + +############################################################################### +## BSD 3-Clause License +## +## Copyright (c) 2022, The Regents of the University of California +## All rights reserved. +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions are met: +## +## * Redistributions of source code must retain the above copyright notice, this +## list of conditions and the following disclaimer. +## +## * Redistributions in binary form must reproduce the above copyright notice, +## this list of conditions and the following disclaimer in the documentation +## and/or other materials provided with the distribution. +## +## * Neither the name of the copyright holder nor the names of its +## contributors may be used to endorse or promote products derived from +## this software without specific prior written permission. +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +## AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +## ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +## LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +## INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +## CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +## ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +## POSSIBILITY OF SUCH DAMAGE. + +# The purpose of this script is to build a symbolic link farm from a +# source PDK according to a JSON mapping file. This is to adapt a PDK +# from a vendor into the form expected by OpenLane without actually +# modifying the source PDK. This is in opposition to the open_pdks +# approach which modifies the vendor PDK to fit. + +# This is a transitional tool. Eventually OpenLane scripts will use +# the mapping file to directly access the files without needing the +# link farm. This will free OL from any dependency on PDK organization. + +import argparse +import glob +import json +import os + +parser = argparse.ArgumentParser( + description="""Builds a link farm from in according to """ +) +parser.add_argument("-s", "--source", required=True) +parser.add_argument("-d", "--destination", required=True) +parser.add_argument("-m", "--mappings", required=True) +parser.add_argument("-v", "--verbose", action="store_true") + +args = parser.parse_args() + + +def link_files(source_path, destination_path): + """Create a link from source_path to destination path unless + one already exists. If it exists but is different then the + arguments imply an exception is raised.""" + + destination_dir = os.path.dirname(destination_path) + if not os.path.isdir(destination_dir): + os.makedirs(destination_dir) + if os.path.exists(destination_path): + if ( + os.path.islink(destination_path) + and os.path.realpath(destination_path) == source_path + ): + if args.verbose: + print(f" Skip {source_path} -> {destination_path}") + return + else: + raise Exception(f"File {destination_path} already exists") + os.symlink(source_path, destination_path) + if args.verbose: + print(f" Link {source_path} -> {destination_path}") + + +with open(args.mappings) as f: + mappings = json.load(f) + +if not os.path.isdir(args.source): + raise Exception(f"{args.source} is not a directory") + +source = os.path.abspath(f"{args.source}") +destination = os.path.abspath(f"{args.destination}") + +for category, mapping in mappings.items(): + print(f"Linking {category}") + pdk = mapping["pdk"] + openlane = mapping["openlane"] + for pattern in mapping["files"]: + pattern = f"{source}/{pdk}/{pattern}" + paths = glob.glob(pattern) + if len(paths) == 0: + raise Exception(f"No matches for {pattern}") + for source_path in paths: + file_name = os.path.basename(source_path) + destination_path = f"{destination}/{openlane}/{file_name}" + link_files(source_path, destination_path)