Source code for pyEDAA.OutputFilter.Xilinx.RouteDesign

# ==================================================================================================================== #
#               _____ ____    _        _      ___        _               _   _____ _ _ _                               #
#   _ __  _   _| ____|  _ \  / \      / \    / _ \ _   _| |_ _ __  _   _| |_|  ___(_) | |_ ___ _ __                    #
#  | '_ \| | | |  _| | | | |/ _ \    / _ \  | | | | | | | __| '_ \| | | | __| |_  | | | __/ _ \ '__|                   #
#  | |_) | |_| | |___| |_| / ___ \  / ___ \ | |_| | |_| | |_| |_) | |_| | |_|  _| | | | ||  __/ |                      #
#  | .__/ \__, |_____|____/_/   \_\/_/   \_(_)___/ \__,_|\__| .__/ \__,_|\__|_|   |_|_|\__\___|_|                      #
#  |_|    |___/                                             |_|                                                        #
# ==================================================================================================================== #
# 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


[docs] @export class Phase1_BuildRTDesign(Phase): _START: ClassVar[str] = "Phase 1 Build RT Design" _FINISH: ClassVar[str] = "Phase 1 Build RT Design | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase21_FixTopologyConstraints(SubPhase): _START: ClassVar[str] = "Phase 2.1 Fix Topology Constraints" _FINISH: ClassVar[str] = "Phase 2.1 Fix Topology Constraints | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase22_PreRouteCleanup(SubPhase): _START: ClassVar[str] = "Phase 2.2 Pre Route Cleanup" _FINISH: ClassVar[str] = "Phase 2.2 Pre Route Cleanup | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase23_UpdateTiming(SubPhase): _START: ClassVar[str] = "Phase 2.3 Update Timing" _FINISH: ClassVar[str] = "Phase 2.3 Update Timing | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase24_SoftConstraintPins_FastBudgeting(SubPhase): _START: ClassVar[str] = "Phase 2.4 Soft Constraint Pins - Fast Budgeting" _FINISH: ClassVar[str] = "Phase 2.4 Soft Constraint Pins - Fast Budgeting | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase2_RouterInitialization(Phase): _START: ClassVar[str] = "Phase 2 Router Initialization" _FINISH: ClassVar[str] = "Phase 2 Router Initialization | Checksum:" _TIME: ClassVar[str] = "Time (s):" _PARSERS: ClassVar[Tuple[Type[Phase], ...]] = ( Phase21_FixTopologyConstraints, Phase22_PreRouteCleanup, Phase23_UpdateTiming, Phase24_SoftConstraintPins_FastBudgeting ) _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: SubPhase 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 Phase3_GlobalRouting(Phase): _START: ClassVar[str] = "Phase 3 Global Routing" _FINISH: ClassVar[str] = "Phase 3 Global Routing | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase41_InitialNetRoutingPass(SubPhase): _START: ClassVar[str] = "Phase 4.1 Initial Net Routing Pass" _FINISH: ClassVar[str] = "Phase 4.1 Initial Net Routing Pass | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase4_InitialRouting(Phase): _START: ClassVar[str] = "Phase 4 Initial Routing" _FINISH: ClassVar[str] = "Phase 4 Initial Routing | Checksum:" _TIME: ClassVar[str] = "Time (s):" _PARSERS: ClassVar[Tuple[Type[Phase], ...]] = ( Phase41_InitialNetRoutingPass, ) _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 4."): for parser in activeParsers: # type: SubPhase 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 Phase51_GlobalIteration0(SubPhase): _START: ClassVar[str] = "Phase 5.1 Global Iteration 0" _FINISH: ClassVar[str] = "Phase 5.1 Global Iteration 0 | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase52_GlobalIteration1(SubPhase): _START: ClassVar[str] = "Phase 5.2 Global Iteration 1" _FINISH: ClassVar[str] = "Phase 5.2 Global Iteration 1 | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase5_RipUpAndReroute(Phase): _START: ClassVar[str] = "Phase 5 Rip-up And Reroute" _FINISH: ClassVar[str] = "Phase 5 Rip-up And Reroute | Checksum:" _TIME: ClassVar[str] = "Time (s):" _PARSERS: ClassVar[Tuple[Type[Phase], ...]] = ( Phase51_GlobalIteration0, Phase52_GlobalIteration1 ) _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 5."): for parser in activeParsers: # type: SubPhase 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 Phase61_DelayCleanUp(SubPhase): _START: ClassVar[str] = "Phase 6.1 Delay CleanUp" _FINISH: ClassVar[str] = "Phase 6.1 Delay CleanUp | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase62_ClockSkewOptimization(SubPhase): _START: ClassVar[str] = "Phase 6.2 Clock Skew Optimization" _FINISH: ClassVar[str] = "Phase 6.2 Clock Skew Optimization | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase6_DelayAndSkewOptimization(Phase): _START: ClassVar[str] = "Phase 6 Delay and Skew Optimization" _FINISH: ClassVar[str] = "Phase 6 Delay and Skew Optimization | Checksum:" _TIME: ClassVar[str] = "Time (s):" _PARSERS: ClassVar[Tuple[Type[Phase], ...]] = ( Phase61_DelayCleanUp, Phase62_ClockSkewOptimization ) _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 6."): for parser in activeParsers: # type: SubPhase 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 Phase71_HoldFixIter(SubPhase): _START: ClassVar[str] = "Phase 7.1 Hold Fix Iter" _FINISH: ClassVar[str] = "Phase 7.1 Hold Fix Iter | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase7_PostHoldFix(Phase): _START: ClassVar[str] = "Phase 7 Post Hold Fix" _FINISH: ClassVar[str] = "Phase 7 Post Hold Fix | Checksum:" _TIME: ClassVar[str] = "Time (s):" _PARSERS: ClassVar[Tuple[Type[Phase], ...]] = ( Phase71_HoldFixIter, ) _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 7."): for parser in activeParsers: # type: SubPhase 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 Phase8_RouteFinalize(Phase): _START: ClassVar[str] = "Phase 8 Route finalize" _FINISH: ClassVar[str] = "Phase 8 Route finalize | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase9_VerifyingRoutedNets(Phase): _START: ClassVar[str] = "Phase 9 Verifying routed nets" _FINISH: ClassVar[str] = "Phase 9 Verifying routed nets | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase10_DepositingRoutes(Phase): _START: ClassVar[str] = "Phase 10 Depositing Routes" _FINISH: ClassVar[str] = "Phase 10 Depositing Routes | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase11_PostProcessRouting(Phase): _START: ClassVar[str] = "Phase 11 Post Process Routing" _FINISH: ClassVar[str] = "Phase 11 Post Process Routing | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase12_PostRouterTiming(Phase): _START: ClassVar[str] = "Phase 12 Post Router Timing" _FINISH: ClassVar[str] = "Phase 12 Post Router Timing | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class Phase13_PostRouteEventProcessing(Phase): _START: ClassVar[str] = "Phase 13 Post-Route Event Processing" _FINISH: ClassVar[str] = "Phase 13 Post-Route Event Processing | Checksum:" _TIME: ClassVar[str] = "Time (s):"
[docs] @export class RoutingTask(Task): _START: ClassVar[str] = "Starting Routing Task" _FINISH: ClassVar[str] = "Ending Routing Task" _PARSERS: ClassVar[Tuple[Type[Phase], ...]] = ( Phase1_BuildRTDesign, Phase2_RouterInitialization, Phase3_GlobalRouting, Phase4_InitialRouting, Phase5_RipUpAndReroute, Phase6_DelayAndSkewOptimization, Phase7_PostHoldFix, Phase8_RouteFinalize, Phase9_VerifyingRoutedNets, Phase10_DepositingRoutes, Phase11_PostProcessRouting, Phase12_PostRouterTiming, Phase13_PostRouteEventProcessing ) 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