blob: 9408778703cb8f65c7635657443742687ed46af8 [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
# Error message, if failed
def get_cov_summary_table(cov_report_txt, tool):
try:
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)
err_msg = "Unsupported tool for cov extraction: {}".format(tool)
return None, None, err_msg
except Exception as e:
err_msg = "Exception occurred: {}".format(str(e))
return None, None, err_msg
# 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'
# metric.
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 [metrics, values], cov_total, None
# If we reached here, then we were unable to extract the coverage.
err_msg = "ParseError: coverage data not found!"
return None, None, err_msg
# 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, None
# If we reached here, then we were unable to extract the coverage.
err_msg = "ParseError: coverage data not found!"
return None, None, err_msg