caravel/scripts/count_lvs.py

121 lines
4.1 KiB
Python
Raw Normal View History

2021-12-01 13:03:45 -06:00
#!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))