From 626c0f7e667567038ba53d3f154ba1aaadf60f49 Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Thu, 6 Jun 2019 13:44:47 +0200 Subject: [PATCH 1/3] An utility script that helps to find missing segbits for PIPs Signed-off-by: Maciej Kurc --- utils/find_missing_segbits.py | 221 ++++++++++++++++++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100755 utils/find_missing_segbits.py diff --git a/utils/find_missing_segbits.py b/utils/find_missing_segbits.py new file mode 100755 index 00000000..db49578c --- /dev/null +++ b/utils/find_missing_segbits.py @@ -0,0 +1,221 @@ +#!/usr/bin/env python3 +""" +This script allows to find missing segbits in the database. + +For each tile the script loads its 'tile_type_*.json' file and looks for all +non-pseudo pips there. Next it loads corresponding 'segbits_*.db' file (if found) +and checks if those pips are listed there. + +Missing segbits for pips are reported as well as missing segbit files. +""" +import logging +import json +import argparse +import os +import re + +# ============================================================================= + + +def read_pips_from_tile(tile_file): + """ + Loads pip definition from a tile type JSON file and returns non-pseudo + PIP name strings. Names are formatted as . + """ + + with open(tile_file, "r") as fp: + root = json.load(fp) + pips = root["pips"] + + pip_names = [] + for pip in pips.values(): + if int(pip["is_pseudo"]) == 0: + pip_names.append( + "{}.{}".format(pip["dst_wire"], pip["src_wire"])) + + return pip_names + + +def read_ppips(ppips_file): + """ + Loads and parses ppips_*.db file. Returns a dict indexed by PIP name which + contains their types ("always", "default" or "hint") + """ + ppips = {} + + with open(ppips_file, "r") as fp: + for line in fp.readlines(): + line = line.split() + if len(line) == 2: + full_pip_name = line[0].split(".") + pip_name = ".".join(full_pip_name[1:]) + ppips[pip_name] = line[1] + + return ppips + + +def read_segbits(segbits_file): + """ + Loads and parses segbits_*.db file. Returns only segbit names. + """ + segbits = [] + + with open(segbits_file, "r") as fp: + for line in fp.readlines(): + line = line.split() + if len(line) > 1: + fields = line[0].split(".") + segbit = ".".join(fields[1:]) + segbits.append(segbit) + + return segbits + + +# ============================================================================= + + +def main(): + """ + The main + """ + + # Parse arguments + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument( + "--db-root", type=str, required=True, help="Database root") + parser.add_argument( + "--verbose", type=int, default=0, help="Verbosity level 0-5") + parser.add_argument( + "--skip-tiles", + type=str, + nargs="*", + default=[], + help="Tile type name regex list for tile types to skip") + parser.add_argument( + "--incl-tiles", + type=str, + nargs="*", + default=[], + help="Tile type name regex list for tile types to include") + + args = parser.parse_args() + + logging.basicConfig(level=50 - args.verbose * 10, format="%(message)s") + + # List files in DB root + files = os.listdir(args.db_root) + + # List tile types + tile_types = [] + for file in files: + match = re.match("^tile_type_(\w+).json$", file) + if match: + tile_types.append(match.group(1)) + + tile_types.sort() + + # Look for missing bits + for tile_type in tile_types: + + # Check if we should include this tile + do_skip = len(args.incl_tiles) > 0 + for pattern in args.incl_tiles: + if re.match(pattern, tile_type): + do_skip = False + break + + # Check if we should skip this tile + for pattern in args.skip_tiles: + if re.match(pattern, tile_type): + do_skip = True + break + + if do_skip: + continue + + logging.critical(tile_type) + + # DB file names + tile_file = os.path.join( + args.db_root, "tile_type_{}.json".format(tile_type.upper())) + ppips_file = os.path.join( + args.db_root, "ppips_{}.db".format(tile_type.lower())) + segbits_file = os.path.join( + args.db_root, "segbits_{}.db".format(tile_type.lower())) + + # Load pips + pips = read_pips_from_tile(tile_file) + + # Load ppips (if any) + if os.path.isfile(ppips_file): + ppips = read_ppips(ppips_file) + else: + ppips = {} + + # Load segbits (if any) + if os.path.isfile(segbits_file): + segbits = read_segbits(segbits_file) + else: + segbits = [] + + # There are non-pseudo pips in this tile + if len(pips): + missing_bits = 0 + known_bits = 0 + + # Build a list of pips to check. If a pip is listed in the ppips + # file and it is not "default" then make it a pseudo one + pips_to_check = [] + for pip in pips: + if pip in ppips.keys() and ppips[pip] != "default": + continue + pips_to_check.append(pip) + + # Missing segbits file + if len(segbits) == 0: + missing_bits = len(pips_to_check) + logging.critical(" MISSING: no segbits file!") + + # Segbits file present + else: + + # Check pips + for pip in pips_to_check: + if pip not in segbits: + + # A "default" pip + if pip in ppips.keys() and ppips[pip] == "default": + missing_bits += 1 + logging.error( + " WARNING: no bits for pip '{}' which defaults to VCC_WIRE" + .format(pip)) + + # A regular pip + else: + missing_bits += 1 + logging.error( + " MISSING: no bits for pip '{}'".format(pip)) + + # The pip has segbits + else: + known_bits += 1 + + # Report missing bit count + if missing_bits > 0: + logging.critical( + " MISSING: no bits for {}/{} pips!".format( + missing_bits, missing_bits + known_bits)) + else: + logging.critical(" OK: no missing bits") + + # No pips + else: + logging.warning(" OK: no pips") + + +# ============================================================================= + +if __name__ == "__main__": + main() From 53db46b2d5af1d6f35edaa2a7998f014ad18f8f2 Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Fri, 7 Jun 2019 11:26:05 +0200 Subject: [PATCH 2/3] Updated exit and input args handling Signed-off-by: Maciej Kurc --- utils/find_missing_segbits.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/utils/find_missing_segbits.py b/utils/find_missing_segbits.py index db49578c..44a8f569 100755 --- a/utils/find_missing_segbits.py +++ b/utils/find_missing_segbits.py @@ -8,6 +8,7 @@ and checks if those pips are listed there. Missing segbits for pips are reported as well as missing segbit files. """ +import sys import logging import json import argparse @@ -74,7 +75,7 @@ def read_segbits(segbits_file): # ============================================================================= -def main(): +def main(argv): """ The main """ @@ -100,7 +101,7 @@ def main(): default=[], help="Tile type name regex list for tile types to include") - args = parser.parse_args() + args = parser.parse_args(argv[1:]) logging.basicConfig(level=50 - args.verbose * 10, format="%(message)s") @@ -214,8 +215,10 @@ def main(): else: logging.warning(" OK: no pips") + return 0 + # ============================================================================= if __name__ == "__main__": - main() + sys.exit(main(sys.argv)) From 1eae588d60f2b4ab0ac2f1f1417ad42af6805331 Mon Sep 17 00:00:00 2001 From: Maciej Kurc Date: Tue, 11 Jun 2019 12:44:35 +0200 Subject: [PATCH 3/3] Added reporting presence of missing bits via exit code Signed-off-by: Maciej Kurc --- utils/find_missing_segbits.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/utils/find_missing_segbits.py b/utils/find_missing_segbits.py index 44a8f569..f4ad3d62 100755 --- a/utils/find_missing_segbits.py +++ b/utils/find_missing_segbits.py @@ -80,6 +80,8 @@ def main(argv): The main """ + exitcode = 0 + # Parse arguments parser = argparse.ArgumentParser( description=__doc__, @@ -178,6 +180,7 @@ def main(argv): if len(segbits) == 0: missing_bits = len(pips_to_check) logging.critical(" MISSING: no segbits file!") + exitcode = -1 # Segbits file present else: @@ -192,12 +195,14 @@ def main(argv): logging.error( " WARNING: no bits for pip '{}' which defaults to VCC_WIRE" .format(pip)) + exitcode = -1 # A regular pip else: missing_bits += 1 logging.error( " MISSING: no bits for pip '{}'".format(pip)) + exitcode = -1 # The pip has segbits else: @@ -208,6 +213,7 @@ def main(argv): logging.critical( " MISSING: no bits for {}/{} pips!".format( missing_bits, missing_bits + known_bits)) + exitcode = -1 else: logging.critical(" OK: no missing bits") @@ -215,7 +221,7 @@ def main(argv): else: logging.warning(" OK: no pips") - return 0 + return exitcode # =============================================================================