| # Copyright 2022 GlobalFoundries 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 |
| # |
| # http://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. |
| |
| """Run GlobalFoundries 180nm IC LVS. |
| |
| Usage: |
| run_lvs.py (--help| -h) |
| run_lvs.py (--design=<layout_path>) (--net=<netlist_path>) (--gf180ic=<combined_options>) [--thr=<thr>] [--run_mode=<run_mode>] [--lvs_sub=<sub_name>] [--no_net_names] [--set_spice_comments] [--set_scale] [--set_verbose] [--set_schematic_simplify] [--set_net_only] [--set_top_lvl_pins] [--set_combine] [--set_purge] [--set_purge_nets] |
| |
| Options: |
| --help -h Print this help message. |
| --design=<layout_path> The input GDS file path. |
| --net=<netlist_path> The input netlist file path. |
| --gf180ic=<combined_options> Select combined options of metal_top, mim_option, and metal_level. Allowed values (A, B, C). |
| gf180ic=A: Select metal_top=30K mim_option=A metal_level=3LM poly_res=1K, and mim_cap=2 |
| gf180ic=B: Select metal_top=11K mim_option=B metal_level=4LM poly_res=1K, and mim_cap=2 |
| gf180ic=C: Select metal_top=9K mim_option=B metal_level=5LM poly_res=1K, and mim_cap=2 |
| --thr=<thr> Number of cores to be used by LVS checker |
| --run_mode=<run_mode> Select klayout mode Allowed modes (flat , deep, tiling). [default: deep] |
| --lvs_sub=<sub_name> Assign the substrate name used in design. |
| --no_net_names Discard net names in extracted netlist. |
| --set_spice_comments Set netlist comments in extracted netlist. |
| --set_scale Set scale of 1e6 in extracted netlist. |
| --set_verbose Set verbose mode. |
| --set_schematic_simplify Set schematic simplification in input netlist. |
| --set_net_only Set netlist object creation only in extracted netlist. |
| --set_top_lvl_pins Set top level pins only in extracted netlist. |
| --set_combine Set netlist combine only in extracted netlist. |
| --set_purge Set netlist purge all only in extracted netlist. |
| --set_purge_nets Set netlist purge nets only in extracted netlist. |
| """ |
| |
| from docopt import docopt |
| import os |
| import logging |
| |
| from subprocess import check_call |
| |
| |
| def main(): |
| |
| # Switches used in run |
| switches = "" |
| |
| if args["--run_mode"] in ["flat", "deep", "tiling"]: |
| switches = switches + f'-rd run_mode={args["--run_mode"]} ' |
| else: |
| logging.error("Allowed klayout modes are (flat , deep , tiling) only") |
| exit() |
| |
| if args["--gf180ic"] == "A": |
| switches = ( |
| switches |
| + "-rd metal_top=30K -rd mim_option=A -rd metal_level=3LM -rd poly_res=1K -rd mim_cap=2 " |
| ) |
| elif args["--gf180ic"] == "B": |
| switches = ( |
| switches |
| + "-rd metal_top=11K -rd mim_option=B -rd metal_level=4LM -rd poly_res=1K -rd mim_cap=2 " |
| ) |
| elif args["--gf180ic"] == "C": |
| switches = ( |
| switches |
| + "-rd metal_top=9K -rd mim_option=B -rd metal_level=5LM -rd poly_res=1K -rd mim_cap=2 " |
| ) |
| else: |
| print("gf180ic switch allowed values are (A , B, C) only") |
| exit() |
| |
| switches = ( |
| switches + "-rd spice_net_names=false " |
| if args["--no_net_names"] |
| else switches + "-rd spice_net_names=true " |
| ) |
| |
| switches = ( |
| switches + "-rd spice_comments=true " |
| if args["--set_spice_comments"] |
| else switches + "-rd spice_comments=false " |
| ) |
| |
| switches = ( |
| switches + "-rd scale=true " |
| if args["--set_scale"] |
| else switches + "-rd scale=false " |
| ) |
| |
| switches = ( |
| switches + "-rd verbose=true " |
| if args["--set_verbose"] |
| else switches + "-rd verbose=false " |
| ) |
| |
| switches = ( |
| switches + "-rd schematic_simplify=true " |
| if args["--set_schematic_simplify"] |
| else switches + "-rd schematic_simplify=false " |
| ) |
| |
| switches = ( |
| switches + "-rd net_only=true " |
| if args["--set_net_only"] |
| else switches + "-rd net_only=false " |
| ) |
| |
| switches = ( |
| switches + "-rd top_lvl_pins=true " |
| if args["--set_top_lvl_pins"] |
| else switches + "-rd top_lvl_pins=false " |
| ) |
| |
| switches = ( |
| switches + "-rd combine=true " |
| if args["--set_combine"] |
| else switches + "-rd combine=false " |
| ) |
| |
| switches = ( |
| switches + "-rd purge=true " |
| if args["--set_purge"] |
| else switches + "-rd purge=false " |
| ) |
| |
| switches = ( |
| switches + "-rd purge_nets=true " |
| if args["--set_purge_nets"] |
| else switches + "-rd purge_nets=false " |
| ) |
| |
| switches = ( |
| switches + f'-rd lvs_sub={args["--lvs_sub"]} ' |
| if args["--lvs_sub"] |
| else switches |
| ) |
| |
| # Generate databases |
| if args["--design"]: |
| path = args["--design"] |
| if args["--design"]: |
| file_name = args["--net"].split(".") |
| else: |
| print( |
| "The script must be given a netlist file or a path to be able to run LVS" |
| ) |
| exit() |
| check_call( |
| f"klayout -b -r {run_lvs_full_path}/gf180ic.lvs -rd input={path} -rd report={file_name[0]}.lyrdb -rd schematic={args['--net']} -rd target_netlist=extracted_netlist_{file_name[0]}.cir -rd thr={workers_count} {switches}", |
| shell=True, |
| ) |
| |
| else: |
| print("The script must be given a layout file or a path to be able to run LVS") |
| exit() |
| |
| |
| if __name__ == "__main__": |
| |
| logging.basicConfig( |
| level=logging.DEBUG, |
| format="%(asctime)s | %(levelname)-7s | %(message)s", |
| datefmt="%d-%b-%Y %H:%M:%S", |
| ) |
| |
| # Args |
| args = docopt(__doc__, version="LVS Checker: 0.1") |
| workers_count = os.cpu_count() * 2 if args["--thr"] is None else int(args["--thr"]) |
| |
| run_lvs_full_path = os.path.dirname(os.path.abspath(__file__)) |
| |
| # ========= Checking Klayout version ========= |
| klayout_v_ = os.popen("klayout -v").read() |
| klayout_v_ = klayout_v_.split("\n")[0] |
| klayout_v = int(klayout_v_.split(".")[-1]) |
| |
| if klayout_v < 8: |
| logging.warning( |
| "Using this klayout version has not been assesed in this development. Limits are unknown" |
| ) |
| logging.info(f"Your version is: {klayout_v_}") |
| logging.info("Prerequisites at a minimum: KLayout 0.27.8") |
| |
| # Calling main function |
| main() |