Source code for hwtBuildsystem.vivado.logParser.synthesis

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

from itertools import islice
import re


[docs] class VivadoSynthesisLogParser(): RE_TABLE_HEADER = re.compile(r"^\d+(\.\d+)*\.?\s+(\S+[^\n]*)") RE_TABLE_TOP_LINE = re.compile(r"^\+(-*\+)+") RE_SECTION_NAME_UNDERLINE = re.compile(r"^-+") def __init__(self, text: str): self.lines = text.split("\n") self.tables = {} def _parseTableSize(self, headerLine): offset = 1 # 0 is table boundary columns = [] for column in headerLine.split("+")[1:-1]: c_width = len(column) columns.append((offset, offset + c_width)) offset += c_width + 1 # +1 for table | return columns def _parseTableColumns(self, line, columnSizes): return [line[x[0]: x[1]].strip() for x in columnSizes]
[docs] def indexByRowNameColumnName(self, table, rowName, columnName): c_i = table[0].index(columnName) for row in islice(table, 1, None): if row[0] == rowName: return row[c_i] raise KeyError("The row with such a name not found", rowName)
[docs] def parse(self): table_name = None table_content = None table_column_size = None for line in self.lines: if table_name: if not line and table_content: assert table_name not in self.tables, table_name self.tables[table_name] = table_content table_name = None table_content = None table_column_size = None else: m_table_top_line = self.RE_TABLE_TOP_LINE.match(line) if m_table_top_line: if table_column_size is None: table_column_size = self._parseTableSize(line) continue if line and table_content is None: m_underline = self.RE_SECTION_NAME_UNDERLINE.match(line) if m_underline: table_content = [] continue else: # false detection table_name = None elif line: assert table_column_size, line table_content.append(self._parseTableColumns(line, table_column_size)) else: m = self.RE_TABLE_HEADER.match(line) if m: table_name = m.group(2)
[docs] def getBasicResourceReport(self): """ A small report function which extracts the most important values from the tables contained in a report. """ i = self.indexByRowNameColumnName isUSp = False isVersalAndAfter = False if "Slice Logic" in self.tables: Slice_Logic = self.tables["Slice Logic"] lut = int(i(Slice_Logic, "Slice LUTs*", "Used")) elif "CLB Logic" in self.tables: # ultrascaleplus Netlist_Logic = self.tables["CLB Logic" ] lut = int(i(Netlist_Logic, "CLB LUTs*", "Used")) isUSp = True Slice_Logic = Netlist_Logic elif "Netlist Logic" in self.tables: # versal and newer Netlist_Logic = self.tables["Netlist Logic"] lut = int(i(Netlist_Logic, "CLB LUTs*", "Used")) isVersalAndAfter = True Slice_Logic = Netlist_Logic ff = int(i(Slice_Logic, "Register as Flip Flop", "Used")) latch = int(i(Slice_Logic, "Register as Latch", "Used")) if isVersalAndAfter or isUSp: BLOCKRAM = self.tables["BLOCKRAM"] bram = float(i(BLOCKRAM, "Block RAM Tile", "Used")) else: Memory = self.tables["Memory"] bram = float(i(Memory, "Block RAM Tile", "Used")) if isVersalAndAfter: ARITHMETIC = self.tables["ARITHMETIC"] dsp = int(i(ARITHMETIC, "DSP Slices", "Used")) elif isUSp: ARITHMETIC = self.tables["ARITHMETIC"] dsp = int(i(ARITHMETIC, "DSPs", "Used")) else: DSP = self.tables["DSP"] dsp = int(i(DSP, "DSPs", "Used")) return { "lut": lut, "ff": ff, "latch": latch, 'bram': bram, 'uram': 0, 'dsp': dsp, }
if __name__ == "__main__": with open("../examples/tmp/ExampleTop0/ExampleTop0.runs/synth_1/ExampleTop0_utilization_synth.rpt") as f: rp = VivadoSynthesisLogParser(f.read()) rp.parse() for table_name, table in rp.tables.items(): print(table_name) for x in table: print(x) print(rp.getBasicResourceReport())