#!ENV_PATH python3 # #--------------------------------------------------------- # LVS failure check # # This is a Python script that parses the comp.json # output from netgen and reports on the number of # errors in the top-level netlist. # #--------------------------------------------------------- # Written by Tim Edwards # efabless, inc. # Pulled from qflow GUI as standalone script Aug 20, 2018 #--------------------------------------------------------- import os import re import sys import json import argparse def count_LVS_failures(filename): with open(filename, 'r') as cfile: lvsdata = json.load(cfile) # Count errors in the JSON file failures = 0 devfail = 0 netfail = 0 pinfail = 0 propfail = 0 netdiff = 0 devdiff = 0 ncells = len(lvsdata) for c in range(0, ncells): cellrec = lvsdata[c] if c == ncells - 1: topcell = True else: topcell = False # Most errors must only be counted for the top cell, because individual # failing cells are flattened and the matching attempted again on the # flattened netlist. if topcell: if 'devices' in cellrec: devices = cellrec['devices'] devlist = [val for pair in zip(devices[0], devices[1]) for val in pair] devpair = list(devlist[p:p + 2] for p in range(0, len(devlist), 2)) for dev in devpair: c1dev = dev[0] c2dev = dev[1] diffdevs = abs(c1dev[1] - c2dev[1]) failures += diffdevs devdiff += diffdevs if 'nets' in cellrec: nets = cellrec['nets'] diffnets = abs(nets[0] - nets[1]) failures += diffnets netdiff += diffnets if 'badnets' in cellrec: badnets = cellrec['badnets'] failures += len(badnets) netfail += len(badnets) if 'badelements' in cellrec: badelements = cellrec['badelements'] failures += len(badelements) devfail += len(badelements) if 'pins' in cellrec: pins = cellrec['pins'] pinlist = [val for pair in zip(pins[0], pins[1]) for val in pair] pinpair = list(pinlist[p:p + 2] for p in range(0, len(pinlist), 2)) for pin in pinpair: # Avoid flagging global vs. local names, e.g., "gnd" vs. "gnd!," # and ignore case when comparing pins. pin0 = re.sub('!$', '', pin[0].lower()) pin1 = re.sub('!$', '', pin[1].lower()) if pin0 != pin1: # The text "(no pin)" indicates a missing pin that can be # ignored because the pin in the other netlist is a no-connect if pin0 != '(no pin)' and pin1 != '(no pin)': failures += 1 pinfail += 1 # Property errors must be counted for every cell if 'properties' in cellrec: properties = cellrec['properties'] failures += len(properties) propfail += len(properties) return [failures, netfail, devfail, pinfail, propfail, netdiff, devdiff] if __name__ == '__main__': parser = argparse.ArgumentParser(description='Parses netgen lvs') parser.add_argument('--file', '-f', required=True) args = parser.parse_args() failures = count_LVS_failures(args.file) total = failures[0] if total > 0: failed = True print('LVS reports:') print(' net count difference = ' + str(failures[5])) print(' device count difference = ' + str(failures[6])) print(' unmatched nets = ' + str(failures[1])) print(' unmatched devices = ' + str(failures[2])) print(' unmatched pins = ' + str(failures[3])) print(' property failures = ' + str(failures[4])) else: print('LVS reports no net, device, pin, or property mismatches.') print('') print('Total errors = ' + str(total))