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