| #!/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 |