| #!/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}!") |