Source code for pyEDAA.OutputFilter.Xilinx.PlaceDesign

# ==================================================================================================================== #
#               _____ ____    _        _      ___        _               _   _____ _ _ _                               #
#   _ __  _   _| ____|  _ \  / \      / \    / _ \ _   _| |_ _ __  _   _| |_|  ___(_) | |_ ___ _ __                    #
#  | '_ \| | | |  _| | | | |/ _ \    / _ \  | | | | | | | __| '_ \| | | | __| |_  | | | __/ _ \ '__|                   #
#  | |_) | |_| | |___| |_| / ___ \  / ___ \ | |_| | |_| | |_| |_) | |_| | |_|  _| | | | ||  __/ |                      #
#  | .__/ \__, |_____|____/_/   \_\/_/   \_(_)___/ \__,_|\__| .__/ \__,_|\__|_|   |_|_|\__\___|_|                      #
#  |_|    |___/                                             |_|                                                        #
# ==================================================================================================================== #
# Authors:                                                                                                             #
#   Patrick Lehmann                                                                                                    #
#                                                                                                                      #
# License:                                                                                                             #
# ==================================================================================================================== #
# Copyright 2025-2025 Electronic Design Automation Abstraction (EDA²)                                                  #
#                                                                                                                      #
# Licensed under the Apache License, Version 2.0 (the "License");                                                      #
# you may not use this file except in compliance with the License.                                                     #
# You may obtain a copy of the License at                                                                              #
#                                                                                                                      #
#   http://www.apache.org/licenses/LICENSE-2.0                                                                         #
#                                                                                                                      #
# Unless required by applicable law or agreed to in writing, software                                                  #
# distributed under the License is distributed on an "AS IS" BASIS,                                                    #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.                                             #
# See the License for the specific language governing permissions and                                                  #
# limitations under the License.                                                                                       #
#                                                                                                                      #
# SPDX-License-Identifier: Apache-2.0                                                                                  #
# ==================================================================================================================== #
#
"""A filtering anc classification processor for AMD/Xilinx Vivado Synthesis outputs."""
from typing import Generator, ClassVar, List, Type, Dict, Tuple

from pyTooling.Decorators  import export

from pyEDAA.OutputFilter.Xilinx           import Line, VivadoMessage, LineKind
from pyEDAA.OutputFilter.Xilinx.Common2   import Task, Phase, SubPhase, SubSubPhase, SubSubSubPhase


[docs] @export class Phase11_PlacerInitializationNetlistSorting(SubPhase): _START: ClassVar[str] = "Phase 1.1 Placer Initialization Netlist Sorting" _FINISH: ClassVar[str] = "Phase 1.1 Placer Initialization Netlist Sorting | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase12_IOPlacement_ClockPlacement_BuildPlacerDevice(SubPhase): _START: ClassVar[str] = "Phase 1.2 IO Placement/ Clock Placement/ Build Placer Device" _FINISH: ClassVar[str] = "Phase 1.2 IO Placement/ Clock Placement/ Build Placer Device | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase13_BuildPlacerNetlistModel(SubPhase): _START: ClassVar[str] = "Phase 1.3 Build Placer Netlist Model" _FINISH: ClassVar[str] = "Phase 1.3 Build Placer Netlist Model | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase14_ConstrainClocks_Macros(SubPhase): _START: ClassVar[str] = "Phase 1.4 Constrain Clocks/Macros" _FINISH: ClassVar[str] = "Phase 1.4 Constrain Clocks/Macros | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase1_PlacerInitialization(Phase): _START: ClassVar[str] = "Phase 1 Placer Initialization" _FINISH: ClassVar[str] = "Phase 1 Placer Initialization | Checksum:" _TIME: ClassVar[str] = "Time (s):" _FINAL: ClassVar[str] = None _PARSERS: ClassVar[Tuple[Type[Phase], ...]] = ( Phase11_PlacerInitializationNetlistSorting, Phase12_IOPlacement_ClockPlacement_BuildPlacerDevice, Phase13_BuildPlacerNetlistModel, Phase14_ConstrainClocks_Macros ) _subphases: Dict[Type[SubPhase], SubPhase]
[docs] def __init__(self, phase: Phase): super().__init__(phase) self._subphases = {p: p(self) for p in self._PARSERS}
def Generator(self, line: Line) -> Generator[Line, Line, Line]: line = yield from self._PhaseStart(line) activeParsers: List[Phase] = list(self._subphases.values()) while True: while True: if line._kind is LineKind.Empty: line = yield line continue elif isinstance(line, VivadoMessage): self._AddMessage(line) elif line.StartsWith("Phase 1."): for parser in activeParsers: # type: Section if line.StartsWith(parser._START): line = yield next(phase := parser.Generator(line)) break else: raise Exception(f"Unknown subphase: {line!r}") break elif line.StartsWith(self._FINISH): nextLine = yield from self._PhaseFinish(line) return nextLine line = yield line while phase is not None: # if line.StartsWith("Ending"): # line = yield task.send(line) # break if isinstance(line, VivadoMessage): self._AddMessage(line) try: line = yield phase.send(line) except StopIteration as ex: activeParsers.remove(parser) line = ex.value break
[docs] @export class Phase21_Floorplanning(SubPhase): _START: ClassVar[str] = "Phase 2.1 Floorplanning" _FINISH: ClassVar[str] = "Phase 2.1 Floorplanning | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase22_UpdateTimingBeforeSLRPathOpt(SubPhase): _START: ClassVar[str] = "Phase 2.2 Update Timing before SLR Path Opt" _FINISH: ClassVar[str] = "Phase 2.2 Update Timing before SLR Path Opt | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase23_PostProcessingInFloorplanning(SubPhase): _START: ClassVar[str] = "Phase 2.3 Post-Processing in Floorplanning" _FINISH: ClassVar[str] = "Phase 2.3 Post-Processing in Floorplanning | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase24_GlobalPlacePhase1(SubPhase): _START: ClassVar[str] = "Phase 2.4 Global Place Phase1" _FINISH: ClassVar[str] = "Phase 2.4 Global Place Phase1 | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase251_UpdateTimingBeforePhysicalSynthesis(SubSubPhase): _START: ClassVar[str] = "Phase 2.5.1 UpdateTiming Before Physical Synthesis" _FINISH: ClassVar[str] = "Phase 2.5.1 UpdateTiming Before Physical Synthesis | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase252_PhysicalSynthesisInPlacer(SubSubPhase): _START: ClassVar[str] = "Phase 2.5.2 Physical Synthesis In Placer" _FINISH: ClassVar[str] = "Phase 2.5.2 Physical Synthesis In Placer | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase25_GlobalPlacePhase2(SubPhase): _START: ClassVar[str] = "Phase 2.5 Global Place Phase2" _FINISH: ClassVar[str] = "Phase 2.5 Global Place Phase2 | Checksum:" _TIME: ClassVar[str] = "Time (s):" _PARSERS: ClassVar[Tuple[Type[Phase], ...]] = ( Phase251_UpdateTimingBeforePhysicalSynthesis, Phase252_PhysicalSynthesisInPlacer ) _subsubphases: Dict[Type[SubSubPhase], SubSubPhase]
[docs] def __init__(self, subphase: SubPhase): super().__init__(subphase) self._subsubphases = {p: p(self) for p in self._PARSERS}
def Generator(self, line: Line) -> Generator[Line, Line, Line]: line = yield from self._SubPhaseStart(line) activeParsers: List[Phase] = list(self._subsubphases.values()) while True: while True: if line._kind is LineKind.Empty: line = yield line continue elif isinstance(line, VivadoMessage): self._AddMessage(line) elif line.StartsWith("Phase 2.5."): for parser in activeParsers: # type: SubSubPhase if line.StartsWith(parser._START): line = yield next(phase := parser.Generator(line)) break else: raise Exception(f"Unknown subsubphase: {line!r}") break elif line.StartsWith(self._FINISH): nextLine = yield from self._SubPhaseFinish(line) return nextLine line = yield line while phase is not None: # if line.StartsWith("Ending"): # line = yield task.send(line) # break if isinstance(line, VivadoMessage): self._AddMessage(line) try: line = yield phase.send(line) except StopIteration as ex: activeParsers.remove(parser) line = ex.value break
[docs] @export class Phase2_GlobalPlacement(Phase): _START: ClassVar[str] = "Phase 2 Global Placement" _FINISH: ClassVar[str] = "Phase 2 Global Placement | Checksum:" _TIME: ClassVar[str] = "Time (s):" _FINAL: ClassVar[str] = None _PARSERS: ClassVar[Tuple[Type[Phase], ...]] = ( Phase21_Floorplanning, Phase22_UpdateTimingBeforeSLRPathOpt, Phase23_PostProcessingInFloorplanning, Phase24_GlobalPlacePhase1, Phase25_GlobalPlacePhase2 ) _subphases: Dict[Type[SubPhase], SubPhase]
[docs] def __init__(self, phase: Phase): super().__init__(phase) self._subphases = {p: p(self) for p in self._PARSERS}
def Generator(self, line: Line) -> Generator[Line, Line, Line]: line = yield from self._PhaseStart(line) activeParsers: List[Phase] = list(self._subphases.values()) while True: while True: if line._kind is LineKind.Empty: line = yield line continue elif isinstance(line, VivadoMessage): self._AddMessage(line) elif line.StartsWith("Phase 2."): for parser in activeParsers: # type: Phase if line.StartsWith(parser._START): line = yield next(phase := parser.Generator(line)) break else: raise Exception(f"Unknown subphase: {line!r}") break elif line.StartsWith(self._FINISH): nextLine = yield from self._PhaseFinish(line) return nextLine line = yield line while phase is not None: # if line.StartsWith("Ending"): # line = yield task.send(line) # break if isinstance(line, VivadoMessage): self._AddMessage(line) try: line = yield phase.send(line) except StopIteration as ex: activeParsers.remove(parser) line = ex.value break
[docs] @export class Phase31_CommitMultiColumnMacros(SubPhase): _START: ClassVar[str] = "Phase 3.1 Commit Multi Column Macros" _FINISH: ClassVar[str] = "Phase 3.1 Commit Multi Column Macros | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase32_CommitMostMacrosLUTRAMs(SubPhase): _START: ClassVar[str] = "Phase 3.2 Commit Most Macros & LUTRAMs" _FINISH: ClassVar[str] = "Phase 3.2 Commit Most Macros & LUTRAMs | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase33_AreaSwapOptimization(SubPhase): _START: ClassVar[str] = "Phase 3.3 Area Swap Optimization" _FINISH: ClassVar[str] = "Phase 3.3 Area Swap Optimization | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase34_PipelineRegisterOptimization(SubPhase): _START: ClassVar[str] = "Phase 3.4 Pipeline Register Optimization" _FINISH: ClassVar[str] = "Phase 3.4 Pipeline Register Optimization | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase35_FastOptimization(SubPhase): _START: ClassVar[str] = "Phase 3.5 Fast Optimization" _FINISH: ClassVar[str] = "Phase 3.5 Fast Optimization | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase36_SmallShapeDetailPlacement(SubPhase): _START: ClassVar[str] = "Phase 3.6 Small Shape Detail Placement" _FINISH: ClassVar[str] = "Phase 3.6 Small Shape Detail Placement | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase37_ReassignLUTPins(SubPhase): _START: ClassVar[str] = "Phase 3.7 Re-assign LUT pins" _FINISH: ClassVar[str] = "Phase 3.7 Re-assign LUT pins | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase38_PipelineRegisterOptimization(SubPhase): _START: ClassVar[str] = "Phase 3.8 Pipeline Register Optimization" _FINISH: ClassVar[str] = "Phase 3.8 Pipeline Register Optimization | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase39_FastOptimization(SubPhase): _START: ClassVar[str] = "Phase 3.9 Fast Optimization" _FINISH: ClassVar[str] = "Phase 3.9 Fast Optimization | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase3_DetailPlacement(Phase): _START: ClassVar[str] = "Phase 3 Detail Placement" _FINISH: ClassVar[str] = "Phase 3 Detail Placement | Checksum:" _TIME: ClassVar[str] = "Time (s):" _FINAL: ClassVar[str] = None _PARSERS: ClassVar[Tuple[Type[Phase], ...]] = ( Phase31_CommitMultiColumnMacros, Phase32_CommitMostMacrosLUTRAMs, Phase33_AreaSwapOptimization, Phase34_PipelineRegisterOptimization, Phase35_FastOptimization, Phase36_SmallShapeDetailPlacement, Phase37_ReassignLUTPins, Phase38_PipelineRegisterOptimization, Phase39_FastOptimization ) _subphases: Dict[Type[SubPhase], SubPhase]
[docs] def __init__(self, phase: Phase): super().__init__(phase) self._subphases = {p: p(self) for p in self._PARSERS}
def Generator(self, line: Line) -> Generator[Line, Line, Line]: line = yield from self._PhaseStart(line) activeParsers: List[Phase] = list(self._subphases.values()) while True: while True: if line._kind is LineKind.Empty: line = yield line continue elif isinstance(line, VivadoMessage): self._AddMessage(line) elif line.StartsWith("Phase 3."): for parser in activeParsers: # type: Section if line.StartsWith(parser._START): line = yield next(phase := parser.Generator(line)) break else: raise Exception(f"Unknown subphase: {line!r}") break elif line.StartsWith(self._FINISH): nextLine = yield from self._PhaseFinish(line) return nextLine line = yield line while phase is not None: # if line.StartsWith("Ending"): # line = yield task.send(line) # break if isinstance(line, VivadoMessage): self._AddMessage(line) try: line = yield phase.send(line) except StopIteration as ex: activeParsers.remove(parser) line = ex.value break
[docs] @export class Phase4111_BUFGInsertion(SubSubSubPhase): _START: ClassVar[str] = "Phase 4.1.1.1 BUFG Insertion" _FINISH: ClassVar[str] = "Phase 4.1.1.1 BUFG Insertion | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase4112_PostPlacementTimingOptimization(SubSubSubPhase): _START: ClassVar[str] = "Phase 4.1.1.2 Post Placement Timing Optimization" _FINISH: ClassVar[str] = "Phase 4.1.1.2 Post Placement Timing Optimization | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase411_PostPlacementOptimization(SubSubPhase): _START: ClassVar[str] = "Phase 4.1.1 Post Placement Optimization" _FINISH: ClassVar[str] = None # Phase 4.1.1 Post Placement Optimization | Checksum:" _TIME: ClassVar[str] = "Time (s):" _PARSERS: ClassVar[Tuple[Type[Phase], ...]] = ( Phase4111_BUFGInsertion, Phase4112_PostPlacementTimingOptimization ) _subsubsubphases: Dict[Type[SubSubSubPhase], SubSubSubPhase]
[docs] def __init__(self, subsubphase: SubSubPhase): super().__init__(subsubphase) self._subsubsubphases = {p: p(self) for p in self._PARSERS}
def Generator(self, line: Line) -> Generator[Line, Line, Line]: line = yield from self._SubSubPhaseStart(line) activeParsers: List[Phase] = list(self._subsubsubphases.values()) while True: while True: if line._kind is LineKind.Empty: line = yield line continue elif isinstance(line, VivadoMessage): self._AddMessage(line) elif line.StartsWith("Phase 4.1.1."): for parser in activeParsers: # type: SubSubSubPhase if line.StartsWith(parser._START): line = yield next(phase := parser.Generator(line)) break else: raise Exception(f"Unknown subsubsubphase: {line!r}") break elif line.StartsWith(self._TIME): line._kind = LineKind.SubSubPhaseTime nextLine = yield line return nextLine line = yield line while phase is not None: # if line.StartsWith("Ending"): # line = yield task.send(line) # break if isinstance(line, VivadoMessage): self._AddMessage(line) try: line = yield phase.send(line) except StopIteration as ex: activeParsers.remove(parser) line = ex.value break
[docs] @export class Phase41_PostCommitOptimization(SubPhase): _START: ClassVar[str] = "Phase 4.1 Post Commit Optimization" _FINISH: ClassVar[str] = "Phase 4.1 Post Commit Optimization | Checksum:" _TIME: ClassVar[str] = "Time (s):" _PARSERS: ClassVar[Tuple[Type[Phase], ...]] = ( Phase411_PostPlacementOptimization, ) _subsubphases: Dict[Type[SubSubPhase], SubSubPhase]
[docs] def __init__(self, subphase: SubPhase): super().__init__(subphase) self._subsubphases = {p: p(self) for p in self._PARSERS}
def Generator(self, line: Line) -> Generator[Line, Line, Line]: line = yield from self._SubPhaseStart(line) activeParsers: List[Phase] = list(self._subsubphases.values()) while True: while True: if line._kind is LineKind.Empty: line = yield line continue elif isinstance(line, VivadoMessage): self._AddMessage(line) elif line.StartsWith("Phase 4.1."): for parser in activeParsers: # type: SubSubPhase if line.StartsWith(parser._START): line = yield next(phase := parser.Generator(line)) break else: raise Exception(f"Unknown subsubphase: {line!r}") break elif line.StartsWith(self._FINISH): nextLine = yield from self._SubPhaseFinish(line) return nextLine line = yield line while phase is not None: # if line.StartsWith("Ending"): # line = yield task.send(line) # break if isinstance(line, VivadoMessage): self._AddMessage(line) try: line = yield phase.send(line) except StopIteration as ex: activeParsers.remove(parser) line = ex.value break
[docs] @export class Phase42_PostPlacementCleanup(SubPhase): _START: ClassVar[str] = "Phase 4.2 Post Placement Cleanup" _FINISH: ClassVar[str] = "Phase 4.2 Post Placement Cleanup | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase431_PrintEstimatedCongestion(SubSubPhase): _START: ClassVar[str] = "Phase 4.3.1 Print Estimated Congestion" _FINISH: ClassVar[str] = "Phase 4.3.1 Print Estimated Congestion | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase43_PlacerReporting(SubPhase): _START: ClassVar[str] = "Phase 4.3 Placer Reporting" _FINISH: ClassVar[str] = "Phase 4.3 Placer Reporting | Checksum:" _TIME: ClassVar[str] = "Time (s):" _PARSERS: ClassVar[Tuple[Type[Phase], ...]] = ( Phase431_PrintEstimatedCongestion, ) _subsubphases: Dict[Type[SubSubPhase], SubSubPhase]
[docs] def __init__(self, subphase: SubPhase): super().__init__(subphase) self._subsubphases = {p: p(self) for p in self._PARSERS}
def Generator(self, line: Line) -> Generator[Line, Line, Line]: line = yield from self._SubPhaseStart(line) activeParsers: List[Phase] = list(self._subsubphases.values()) while True: while True: if line._kind is LineKind.Empty: line = yield line continue elif isinstance(line, VivadoMessage): self._AddMessage(line) elif line.StartsWith("Phase 4.3."): for parser in activeParsers: # type: SubSubPhase if line.StartsWith(parser._START): line = yield next(phase := parser.Generator(line)) break else: raise Exception(f"Unknown subsubphase: {line!r}") break elif line.StartsWith(self._FINISH): nextLine = yield from self._SubPhaseFinish(line) return nextLine line = yield line while phase is not None: # if line.StartsWith("Ending"): # line = yield task.send(line) # break if isinstance(line, VivadoMessage): self._AddMessage(line) try: line = yield phase.send(line) except StopIteration as ex: activeParsers.remove(parser) line = ex.value break
[docs] @export class Phase44_FinalPlacementCleanup(SubPhase): _START: ClassVar[str] = "Phase 4.4 Final Placement Cleanup" _FINISH: ClassVar[str] = "Time (s):" _TIME: ClassVar[str] = None
[docs] @export class Phase4_PostPlacementOptimizationAndCleanUp(Phase): _START: ClassVar[str] = "Phase 4 Post Placement Optimization and Clean-Up" _FINISH: ClassVar[str] = "Phase 4 Post Placement Optimization and Clean-Up | Checksum:" _TIME: ClassVar[str] = "Time (s):" _FINAL: ClassVar[str] = None _PARSERS: ClassVar[Tuple[Type[Phase], ...]] = ( Phase41_PostCommitOptimization, Phase42_PostPlacementCleanup, Phase43_PlacerReporting, Phase44_FinalPlacementCleanup ) _subphases: Dict[Type[SubPhase], SubPhase]
[docs] def __init__(self, phase: Phase): super().__init__(phase) self._subphases = {p: p(self) for p in self._PARSERS}
def Generator(self, line: Line) -> Generator[Line, Line, Line]: line = yield from self._PhaseStart(line) activeParsers: List[Phase] = list(self._subphases.values()) while True: while True: if isinstance(line, VivadoMessage): self._AddMessage(line) elif line.StartsWith("Phase 4."): for parser in activeParsers: # type: Section if line.StartsWith(parser._START): line = yield next(phase := parser.Generator(line)) break else: raise Exception(f"Unknown subphase: {line!r}") break elif line.StartsWith(self._FINISH): nextLine = yield from self._PhaseFinish(line) return nextLine line = yield line while phase is not None: # if line.StartsWith("Ending"): # line = yield task.send(line) # break if isinstance(line, VivadoMessage): self._AddMessage(line) try: line = yield phase.send(line) except StopIteration as ex: activeParsers.remove(parser) line = ex.value break
[docs] @export class PlacerTask(Task): _START: ClassVar[str] = "Starting Placer Task" _FINISH: ClassVar[str] = "Ending Placer Task" _PARSERS: ClassVar[Tuple[Type[Phase], ...]] = ( Phase1_PlacerInitialization, Phase2_GlobalPlacement, Phase3_DetailPlacement, Phase4_PostPlacementOptimizationAndCleanUp ) def Generator(self, line: Line) -> Generator[Line, Line, Line]: line = yield from self._TaskStart(line) activeParsers: List[Phase] = list(self._phases.values()) while True: while True: if isinstance(line, VivadoMessage): self._AddMessage(line) elif line.StartsWith("Phase "): for parser in activeParsers: # type: Section if line.StartsWith(parser._START): line = yield next(phase := parser.Generator(line)) break else: raise Exception(f"Unknown phase: {line!r}") break elif line.StartsWith("Ending"): nextLine = yield from self._TaskFinish(line) return nextLine elif line.StartsWith(self._TIME): line._kind = LineKind.TaskTime nextLine = yield line return nextLine line = yield line while phase is not None: # if line.StartsWith("Ending"): # line = yield task.send(line) # break if isinstance(line, VivadoMessage): self._AddMessage(line) try: line = yield phase.send(line) except StopIteration as ex: activeParsers.remove(parser) line = ex.value break