blob: 32aece979a1aa21b022a75f7674ab7ab68984b2c [file] [log] [blame]
# Copyright 2020-2021 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.
# The only purpose of this file is to create a wrapper around report.py and config.py and make them usable by flow.tcl
import os
import click
import utils.utils as utils
from report.report import Report
from report.get_file_name import get_name
from config.config import ConfigHandler
@click.command()
@click.option("--design", "-d", required=True, help="Design Path")
@click.option("--design_name", "-n", required=True, help="Design Name")
@click.option("--tag", "-t", required=True, help="Run Tag")
@click.option(
"--run_path",
"-r",
default=None,
help="Run Path [Optional, otherwise derived from tag]",
)
@click.option("--output_file", "-o", required=True, help="Output Final Summary Report")
@click.option(
"--man_report", "-m", default="/dev/null", help="Output Manufacturability Reports"
)
def cli(design, design_name, tag, run_path, output_file, man_report):
"""
Creates manufacturability and metric summary reports for a given design and OpenLane run.
"""
# Extracting Configurations
params = ConfigHandler.get_config(design, tag, run_path)
# Extracting Report
report = Report(design, tag, design_name, params, run_path).get_report()
# Write into file
with open(output_file, "w") as f:
f.write(Report.get_header() + "," + ConfigHandler.get_header())
f.write("\n")
f.write(report)
# Adding Extra Attributes computed from configs and reported statistics
utils.add_computed_statistics(output_file)
# Tracking Magic DRC, LVS, Antenna Logs:
run_path = run_path or utils.get_run_path(design, tag)
_, magic_antenna_report = get_name(
os.path.join(run_path, "reports", "routing"), "antenna_violators.rpt"
)
_, arc_antenna_report = get_name(
os.path.join(run_path, "reports", "signoff"), "antenna.rpt"
)
_, magic_drc_report = get_name(
os.path.join(run_path, "reports", "signoff"), "drc.rpt"
)
_, lvs_report = get_name(
os.path.join(run_path, "logs", "signoff"), f"{design_name}.lvs.lef.log"
)
printArr = []
printArr.append("Design Name: " + design_name)
printArr.append("Run Directory: " + str(run_path))
splitLine = "----------------------------------------"
# Summarizing Magic DRC
drcVioDict = dict()
cnt = 0
if os.path.exists(magic_drc_report):
drcFileOpener = open(magic_drc_report)
if drcFileOpener.mode == "r":
drcContent = drcFileOpener.read()
drcFileOpener.close()
# design name
# violation message
# list of violations
# Total Count:
printArr.append(splitLine)
printArr.append("\nMagic DRC Summary:")
printArr.append("Source: " + str(magic_drc_report))
if drcContent is not None:
drcSections = drcContent.split(splitLine)
if len(drcSections) > 2:
for i in range(1, len(drcSections) - 1, 2):
drcVioDict[drcSections[i]] = len(drcSections[i + 1].split("\n")) - 2
for key in drcVioDict:
val = drcVioDict[key]
cnt += val
printArr.append(
'Violation Message "'
+ str(key.strip())
+ ' "found '
+ str(val)
+ " Times."
)
printArr.append("Total Magic DRC violations is " + str(cnt))
else:
printArr.append("Source not found.")
# Summarizing LVS
printArr.append(splitLine)
printArr.append("\nLVS Summary:")
printArr.append("Source: " + str(lvs_report))
if os.path.exists(lvs_report):
lvsFileOpener = open(lvs_report)
if lvsFileOpener.mode == "r":
lvsContent = lvsFileOpener.read()
lvsFileOpener.close()
flag = False
for line in lvsContent.split("\n"):
if line.find("Total errors =") != -1:
flag = True
printArr.append(line)
elif line.find("net") != -1:
printArr.append(line)
if not flag:
printArr.append("Design is LVS clean.")
else:
printArr.append("Source not found.")
# Summarizing Antennas
printArr.append(splitLine)
printArr.append("\nAntenna Summary:")
if os.path.exists(arc_antenna_report):
printArr.append("Source: " + str(arc_antenna_report))
antFileOpener = open(arc_antenna_report)
if antFileOpener.mode == "r":
antContent = antFileOpener.read().split("\n")[-5:]
antFileOpener.close()
for line in antContent:
if line.find("violated:") != -1:
printArr.append(line)
elif os.path.exists(magic_antenna_report):
printArr.append("Source: " + str(magic_antenna_report))
antFileOpener = open(magic_antenna_report)
if antFileOpener.mode == "r":
antContent = antFileOpener.read().split("\n")
antFileOpener.close()
tot_cnt = 0
for ant in antContent:
if len(str(ant).strip()):
tot_cnt += 1
printArr.append("Number of pins violated: " + str(tot_cnt))
else:
printArr.append("No antenna report found.")
# write into file
with open(man_report, "w") as f:
f.write("\n".join(printArr))
if __name__ == "__main__":
cli()