Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
200 changes: 191 additions & 9 deletions pyEDAA/OutputFilter/Xilinx/Commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
from pyEDAA.OutputFilter.Xilinx import VivadoTclCommand
from pyEDAA.OutputFilter.Xilinx.Exception import ProcessorException
from pyEDAA.OutputFilter.Xilinx.Common import Line, LineKind, VivadoMessage, VHDLReportMessage
from pyEDAA.OutputFilter.Xilinx.Common2 import Parser, UnknownSection, UnknownTask
from pyEDAA.OutputFilter.Xilinx.Common2 import Parser, UnknownSection, UnknownTask, Task
from pyEDAA.OutputFilter.Xilinx.SynthesizeDesign import Section, RTLElaboration, HandlingCustomAttributes
from pyEDAA.OutputFilter.Xilinx.SynthesizeDesign import ConstraintValidation, LoadingPart, ApplySetProperty
from pyEDAA.OutputFilter.Xilinx.SynthesizeDesign import RTLComponentStatistics, RTLHierarchicalComponentStatistics
Expand All @@ -52,7 +52,7 @@
from pyEDAA.OutputFilter.Xilinx.SynthesizeDesign import RenamingGeneratedInstances, RebuildingUserHierarchy
from pyEDAA.OutputFilter.Xilinx.SynthesizeDesign import RenamingGeneratedPorts, RenamingGeneratedNets
from pyEDAA.OutputFilter.Xilinx.SynthesizeDesign import WritingSynthesisReport
from pyEDAA.OutputFilter.Xilinx.OptimizeDesign import Task, DRCTask, CacheTimingInformationTask, LogicOptimizationTask
from pyEDAA.OutputFilter.Xilinx.OptimizeDesign import DRCTask, CacheTimingInformationTask, LogicOptimizationTask
from pyEDAA.OutputFilter.Xilinx.OptimizeDesign import PowerOptimizationTask, FinalCleanupTask, NetlistObfuscationTask
from pyEDAA.OutputFilter.Xilinx.PlaceDesign import PlacerTask
from pyEDAA.OutputFilter.Xilinx.PhysicalOptimizeDesign import PhysicalSynthesisTask, InitialUpdateTimingTask
Expand Down Expand Up @@ -96,11 +96,52 @@ class ROM_RAM_DSP_SR_Retiming3(ROM_RAM_DSP_SR_Retiming):

@export
class Command(Parser):
"""
This parser parses outputs from Vivado TCL commands.

Depending on the command's output (and how it's implemented), they use different subcategories.

.. rubric:: Command subcategories

* :class:`CommandWithSections`
* :class:`CommandWithtasks`

.. rubric:: Supported commands

* :class:`SynthesizeDesign`
* :class:`LinkDesign`
* :class:`OptimizeDesign`
* :class:`PlaceDesign`
* :class:`PhysicalOptimizeDesign`
* :class:`RouteDesign`
* :class:`WriteBitstream`
* :class:`ReportDRC`
* :class:`ReportMethodology`
* :class:`ReportPower`

.. rubric:: Example

.. code-block::

[...]
Command: synth_design -top system_top -part xc7z015clg485-2
Starting synth_design
[...]
"""

# _TCL_COMMAND: ClassVar[str]

def _CommandStart(self, line: Line) -> Generator[Line, Line, Line]:
"""
A generator accepting a line containing the expected Vivado TCL command.

When the generator exits, the returned line is the successor line to the line containing the Vivado TCL command.

:param line: The first line for the generator to process.
:returns: A generator processing Vivado output log lines.
"""
if not (isinstance(line, VivadoTclCommand) and line._command == self._TCL_COMMAND):
raise ProcessorException()
raise ProcessorException() # FIXME: add exception message

nextLine = yield line
return nextLine
Expand Down Expand Up @@ -145,6 +186,27 @@ def __str__(self) -> str:

@export
class CommandWithSections(Command):
"""
A Vivado command writing sections into the output log.

.. rubric:: Example

.. code-block::

[...]
---------------------------------------------------------------------------------
Starting RTL Elaboration : Time (s): cpu = 00:00:03 ; elapsed = 00:00:03 . Memory (MB): peak = 847.230 ; gain = 176.500
---------------------------------------------------------------------------------
INFO: [Synth 8-638] synthesizing module 'system_top' [C:/Users/tgomes/git/2019_1/src/system_top_PE1.vhd:257]
[...]
[...]
[...]
---------------------------------------------------------------------------------
Finished RTL Elaboration : Time (s): cpu = 00:00:04 ; elapsed = 00:00:04 . Memory (MB): peak = 917.641 ; gain = 246.910
---------------------------------------------------------------------------------
[...]
"""

_sections: Dict[Type[Section], Section]

_PARSERS: ClassVar[Tuple[Type[Section], ...]] = dict()
Expand All @@ -156,6 +218,11 @@ def __init__(self, processor: "Processor") -> None:

@readonly
def Sections(self) -> Dict[Type[Section], Section]:
"""
Read-only property to access a dictionary of found sections within the TCL command's output.

:returns: A dictionary of found :class:`~pyEDAA.OutputFilter.Xilinx.SynthesizeDesign.Section`s.
"""
return self._sections

def __getitem__(self, key: Type[Section]) -> Section:
Expand All @@ -164,6 +231,21 @@ def __getitem__(self, key: Type[Section]) -> Section:

@export
class CommandWithTasks(Command):
"""
A Vivado command writing tasks into the output log.

.. rubric:: Example

.. code-block::

[...]
Starting Cache Timing Information Task
INFO: [Timing 38-35] 79-Done setting XDC timing constraints.
[...]
[...]
Ending Cache Timing Information Task | Checksum: 19fe8cb97
[...]
"""
_tasks: Dict[Type[Task], Task]

def __init__(self, processor: "Processor") -> None:
Expand All @@ -173,6 +255,11 @@ def __init__(self, processor: "Processor") -> None:

@readonly
def Tasks(self) -> Dict[Type[Task], Task]:
"""
Read-only property to access a dictionary of found tasks within the TCL command's output.

:returns: A dictionary of found :class:`~pyEDAA.OutputFilter.Xilinx.Common2.Task`s.
"""
return self._tasks

def __getitem__(self, key: Type[Task]) -> Task:
Expand All @@ -181,6 +268,9 @@ def __getitem__(self, key: Type[Task]) -> Task:

@export
class SynthesizeDesign(CommandWithSections):
"""
A Vivado command output parser for ``synth_design``.
"""
_TCL_COMMAND: ClassVar[str] = "synth_design"
_PARSERS: ClassVar[Tuple[Type[Section], ...]] = (
RTLElaboration,
Expand Down Expand Up @@ -211,32 +301,84 @@ class SynthesizeDesign(CommandWithSections):

@readonly
def HasLatches(self) -> bool:
"""
Read-only property returning if synthesis inferred latches into the design.

Latch detection is based on:

* Vivado message ``synth 8-327``
* Cells of lind ``LD`` listed in the *Cell Usage* report.

:returns: True, if the design contains latches.
"""
if (8 in self._messagesByID) and (327 in self._messagesByID[8]):
return True

return "LD" in self._sections[WritingSynthesisReport]._cells

@readonly
def Latches(self) -> Iterator[VivadoMessage]:
try:
yield from iter(self._messagesByID[8][327])
except KeyError:
yield from ()
def Latches(self) -> List[VivadoMessage]:
"""
Read-only property to access a list of Vivado output messages for inferred latches.

:returns: A list of Vivado messages for interred latches.

.. note::

This returns ``[Synth 8-327]`` messages.

.. code-block::

WARNING: [Synth 8-327] inferring latch for variable 'Q_reg'
"""
if 8 in self._messagesByID:
if 327 in (synthMessages := self._messagesByID[8]):
return [message for message in synthMessages[327]]

return []

@readonly
def HasBlackboxes(self) -> bool:
"""
Read-only property returning if the design contains black-boxes.

:returns: True, if the design contains black-boxes.
"""
return len(self._sections[WritingSynthesisReport]._blackboxes) > 0

@readonly
def Blackboxes(self) -> Dict[str, int]:
"""
Read-only property to access the dictionary of found blackbox statistics.

:returns: The dictionary of found blackbox statistics.
"""
return self._sections[WritingSynthesisReport]._blackboxes

@readonly
def Cells(self) -> Dict[str, int]:
"""
Read-only property to access the dictionary of synthesized cell statistics.

:returns: The dictionary of used cell statistics.
"""
return self._sections[WritingSynthesisReport]._cells

@readonly
def VHDLReportMessages(self) -> List[VHDLReportMessage]:
"""
Read-only property to access a list of Vivado output messages generated by VHDL report statement.

:returns: A list of VHDL report statement outputs.

.. note::

This returns ``[Synth 8-6031]`` messages.

.. code-block::

INFO: [Synth 8-6031] RTL report: "TimingToCycles(time, freq): period=10.000000 ns -- 0.000000 fs" [C:/[...]/StopWatch/src/Utilities.pkg.vhdl:118]
"""
if 8 in self._messagesByID:
if 6031 in (synthMessages := self._messagesByID[8]):
return [message for message in synthMessages[6031]]
Expand All @@ -245,6 +387,19 @@ def VHDLReportMessages(self) -> List[VHDLReportMessage]:

@readonly
def VHDLAssertMessages(self) -> List[VHDLReportMessage]:
"""
Read-only property to access a list of Vivado output messages generated by VHDL assert statement.

:returns: A list of VHDL assert statement outputs.

.. note::

This returns ``[Synth 8-63]`` messages.

.. code-block::

INFO: [Synth 8-63] RTL assertion: "CLOCK_FREQ: 100.000000 ns" [C:/[...]/StopWatch/src/Debouncer.vhdl:28]
"""
if 8 in self._messagesByID:
if 63 in (synthMessages := self._messagesByID[8]):
return [message for message in synthMessages[63]]
Expand All @@ -259,7 +414,7 @@ def __getitem__(self, item: Type[Parser]) -> Union[_PARSERS]:

def SectionDetector(self, line: Line) -> Generator[Union[Line, ProcessorException], Line, None]:
if not (isinstance(line, VivadoTclCommand) and line._command == self._TCL_COMMAND):
raise ProcessorException()
raise ProcessorException() # FIXME: add exception message

activeParsers: List[Parser] = list(self._sections.values())

Expand Down Expand Up @@ -338,6 +493,9 @@ def SectionDetector(self, line: Line) -> Generator[Union[Line, ProcessorExceptio

@export
class LinkDesign(Command):
"""
A Vivado command output parser for ``link_design``.
"""
_TCL_COMMAND: ClassVar[str] = "link_design"
_TIME: ClassVar[str] = "Time (s):"

Expand Down Expand Up @@ -435,6 +593,9 @@ def SectionDetector(self, line: Line) -> Generator[Union[Line, ProcessorExceptio

@export
class OptimizeDesign(CommandWithTasks):
"""
A Vivado command output parser for ``opt_design``.
"""
_TCL_COMMAND: ClassVar[str] = "opt_design"
_TIME: ClassVar[str] = None

Expand Down Expand Up @@ -510,6 +671,9 @@ def SectionDetector(self, line: Line) -> Generator[Union[Line, ProcessorExceptio

@export
class PlaceDesign(CommandWithTasks):
"""
A Vivado command output parser for ``place_design``.
"""
_TCL_COMMAND: ClassVar[str] = "place_design"
_TIME: ClassVar[str] = None

Expand Down Expand Up @@ -580,6 +744,9 @@ def SectionDetector(self, line: Line) -> Generator[Union[Line, ProcessorExceptio

@export
class PhysicalOptimizeDesign(CommandWithTasks):
"""
A Vivado command output parser for ``phy_opt_design``.
"""
_TCL_COMMAND: ClassVar[str] = "phys_opt_design"
_TIME: ClassVar[str] = None

Expand Down Expand Up @@ -651,6 +818,9 @@ def SectionDetector(self, line: Line) -> Generator[Union[Line, ProcessorExceptio

@export
class RouteDesign(CommandWithTasks):
"""
A Vivado command output parser for ``route_design``.
"""
_TCL_COMMAND: ClassVar[str] = "route_design"
_TIME: ClassVar[str] = "Time (s):"

Expand Down Expand Up @@ -721,23 +891,35 @@ def SectionDetector(self, line: Line) -> Generator[Union[Line, ProcessorExceptio

@export
class WriteBitstream(Command):
"""
A Vivado command output parser for ``write_bitstream``.
"""
_TCL_COMMAND: ClassVar[str] = "write_bitstream"
_TIME: ClassVar[str] = "Time (s):"


@export
class ReportDRC(Command):
"""
A Vivado command output parser for ``report_drc``.
"""
_TCL_COMMAND: ClassVar[str] = "report_drc"
_TIME: ClassVar[str] = None


@export
class ReportMethodology(Command):
"""
A Vivado command output parser for ``report_methodology``.
"""
_TCL_COMMAND: ClassVar[str] = "report_methodology"
_TIME: ClassVar[str] = None


@export
class ReportPower(Command):
"""
A Vivado command output parser for ``report_power``.
"""
_TCL_COMMAND: ClassVar[str] = "report_power"
_TIME: ClassVar[str] = None
Loading
Loading