blob: e6d0bf3028c9498e79a6538fb72c21e1fa76ac11 [file] [log] [blame]
# 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()