mirror of
https://github.com/The-OpenROAD-Project/OpenLane.git
synced 2026-05-29 00:23:55 +08:00
~ Avoid using `/dev/null` for writing DEF files (it tries to create a temp file and fail) ~ PDK now has a default value of sky130A even outside the Makefile ~ PDK_ROOT now set automatically if Volare is installed ~ Upgrade to a newer version of OpenLane 2, which in turns uses `nix-eda` ~ Format nix packages using Alejandra ~ OpenROAD scripts now read liberty files before database files (they are linked together when the database is read) ~ Update Readme to remove Colab and add banner directing people to OpenLane 2
133 lines
4.7 KiB
Python
Executable File
133 lines
4.7 KiB
Python
Executable File
#!/usr/bin/python3
|
|
# Copyright 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.
|
|
|
|
#
|
|
# ---------------------------------------------------------
|
|
# 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 re
|
|
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))
|