|  | #!/usr/bin/python3 | 
|  | # SPDX-FileCopyrightText: 2020 Efabless Corporation | 
|  | # | 
|  | # 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. | 
|  | # SPDX-License-Identifier: Apache-2.0 | 
|  |  | 
|  | # | 
|  | #--------------------------------------------------------- | 
|  | # 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: | 
|  | 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)) | 
|  |  |