blob: bacc633c8d735f806124b3555c3d96449321865f [file] [log] [blame]
#!/usr/bin/env python3
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
"""
This script provides common DV simulation specific utilities.
"""
import re
from collections import OrderedDict
# Capture the summary results as a list of lists.
# The text coverage report is passed as input to the function, in addition to
# the tool used. The tool returns a 2D list if the coverage report file was read
# and the coverage was extracted successfully. It returns a tuple of:
# List of metrics and values
# Final coverage total
#
# Raises the appropriate exception if the coverage summary extraction fails.
def get_cov_summary_table(cov_report_txt, tool):
with open(cov_report_txt, 'r') as f:
if tool == 'xcelium':
return xcelium_cov_summary_table(f)
if tool == 'vcs':
return vcs_cov_summary_table(f)
raise NotImplementedError(f"{tool} is unsupported for cov extraction.")
# Same desc as above, but specific to Xcelium and takes an opened input stream.
def xcelium_cov_summary_table(buf):
for line in buf:
if "name" in line:
# Strip the line and remove the unwanted "* Covered" string.
metrics = line.strip().replace("* Covered", "").split()
# Change first item to 'Score'.
metrics[0] = 'Score'
# Gather the list of metrics.
items = OrderedDict()
for metric in metrics:
items[metric] = {}
items[metric]['covered'] = 0
items[metric]['total'] = 0
# Next line is a separator.
line = buf.readline()
# Subsequent lines are coverage items to be aggregated.
for line in buf:
line = re.sub(r"%\s+\(", "%(", line)
values = line.strip().split()
for i, value in enumerate(values):
value = value.strip()
m = re.search(r"\((\d+)/(\d+).*\)", value)
if m:
items[metrics[i]]['covered'] += int(m.group(1))
items[metrics[i]]['total'] += int(m.group(2))
items['Score']['covered'] += int(m.group(1))
items['Score']['total'] += int(m.group(2))
# Capture the percentages and the aggregate.
values = []
cov_total = None
for metric in items.keys():
if items[metric]['total'] == 0:
values.append("-- %")
else:
value = items[metric]['covered'] / items[metric][
'total'] * 100
value = "{0:.2f} %".format(round(value, 2))
values.append(value)
if metric == 'Score':
cov_total = value
return [items.keys(), values], cov_total
# If we reached here, then we were unable to extract the coverage.
raise SyntaxError(f"Coverage data not found in {buf.name}!")
# Same desc as above, but specific to VCS and takes an opened input stream.
def vcs_cov_summary_table(buf):
for line in buf:
match = re.match("total coverage summary", line, re.IGNORECASE)
if match:
# Metrics on the next line.
line = buf.readline().strip()
metrics = line.split()
# Values on the next.
line = buf.readline().strip()
# Pretty up the values - add % sign for ease of post
# processing.
values = []
for val in line.split():
val += " %"
values.append(val)
# first row is coverage total
cov_total = values[0]
return [metrics, values], cov_total
# If we reached here, then we were unable to extract the coverage.
raise SyntaxError(f"Coverage data not found in {buf.name}!")