Coverage for pyEDAA/OutputFilter/Xilinx/PhysicalOptimizeDesign.py: 90%

65 statements  

« prev     ^ index     » next       coverage.py v7.9.2, created at 2025-07-16 06:19 +0000

1# ==================================================================================================================== # 

2# _____ ____ _ _ ___ _ _ _____ _ _ _ # 

3# _ __ _ _| ____| _ \ / \ / \ / _ \ _ _| |_ _ __ _ _| |_| ___(_) | |_ ___ _ __ # 

4# | '_ \| | | | _| | | | |/ _ \ / _ \ | | | | | | | __| '_ \| | | | __| |_ | | | __/ _ \ '__| # 

5# | |_) | |_| | |___| |_| / ___ \ / ___ \ | |_| | |_| | |_| |_) | |_| | |_| _| | | | || __/ | # 

6# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)___/ \__,_|\__| .__/ \__,_|\__|_| |_|_|\__\___|_| # 

7# |_| |___/ |_| # 

8# ==================================================================================================================== # 

9# Authors: # 

10# Patrick Lehmann # 

11# # 

12# License: # 

13# ==================================================================================================================== # 

14# Copyright 2025-2025 Electronic Design Automation Abstraction (EDA²) # 

15# # 

16# Licensed under the Apache License, Version 2.0 (the "License"); # 

17# you may not use this file except in compliance with the License. # 

18# You may obtain a copy of the License at # 

19# # 

20# http://www.apache.org/licenses/LICENSE-2.0 # 

21# # 

22# Unless required by applicable law or agreed to in writing, software # 

23# distributed under the License is distributed on an "AS IS" BASIS, # 

24# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # 

25# See the License for the specific language governing permissions and # 

26# limitations under the License. # 

27# # 

28# SPDX-License-Identifier: Apache-2.0 # 

29# ==================================================================================================================== # 

30# 

31"""A filtering anc classification processor for AMD/Xilinx Vivado Synthesis outputs.""" 

32from typing import Generator, ClassVar, List, Type, Tuple 

33 

34from pyTooling.Decorators import export 

35 

36from pyEDAA.OutputFilter.Xilinx import Line, VivadoMessage, LineKind 

37from pyEDAA.OutputFilter.Xilinx.Common2 import Task, Phase 

38 

39 

40@export 

41class InitialUpdateTimingTask(Task): 

42 _NAME: ClassVar[str] = "Initial Update Timing Task" 

43 _START: ClassVar[str] = "Starting Initial Update Timing Task" 

44 _FINISH: ClassVar[str] = None 

45 

46 

47@export 

48class Phase1_PlacerInitialization(Phase): 

49 _START: ClassVar[str] = "Phase 1 Physical Synthesis Initialization" 

50 _FINISH: ClassVar[str] = "Phase 1 Physical Synthesis Initialization | Checksum:" 

51 

52 

53@export 

54class Phase2_DSPRegisterOptimization(Phase): 

55 _START: ClassVar[str] = "Phase 2 DSP Register Optimization" 

56 _FINISH: ClassVar[str] = "Phase 2 DSP Register Optimization | Checksum:" 

57 

58 

59@export 

60class Phase3_CriticalPathOptimization(Phase): 

61 _START: ClassVar[str] = "Phase 3 Critical Path Optimization" 

62 _FINISH: ClassVar[str] = "Phase 3 Critical Path Optimization | Checksum:" 

63 

64 

65@export 

66class Phase4_CriticalPathOptimization(Phase): 

67 _START: ClassVar[str] = "Phase 4 Critical Path Optimization" 

68 _FINISH: ClassVar[str] = "Phase 4 Critical Path Optimization | Checksum:" 

69 

70 

71@export 

72class PhysicalSynthesisTask(Task): 

73 _NAME: ClassVar[str] = "Physical Synthesis Task" 

74 _START: ClassVar[str] = "Starting Physical Synthesis Task" 

75 _FINISH: ClassVar[str] = "Ending Physical Synthesis Task" 

76 

77 _PARSERS: ClassVar[Tuple[Type[Phase], ...]] = ( 

78 Phase1_PlacerInitialization, 

79 Phase2_DSPRegisterOptimization, 

80 Phase3_CriticalPathOptimization, 

81 Phase4_CriticalPathOptimization 

82 ) 

83 

84 def Generator(self, line: Line) -> Generator[Line, Line, Line]: 

85 line = yield from self._TaskStart(line) 

86 

87 activeParsers: List[Phase] = list(self._phases.values()) 

88 

89 while True: 

90 while True: 

91 if line._kind is LineKind.Empty: 

92 line = yield line 

93 continue 

94 elif isinstance(line, VivadoMessage): 

95 self._AddMessage(line) 

96 elif line.StartsWith("Phase "): 

97 for parser in activeParsers: # type: Phase 97 ↛ 102line 97 didn't jump to line 102 because the loop on line 97 didn't complete

98 if line.StartsWith(parser._START): 98 ↛ 97line 98 didn't jump to line 97 because the condition on line 98 was always true

99 line = yield next(phase := parser.Generator(line)) 

100 break 

101 else: 

102 raise Exception(f"Unknown phase: {line!r}") 

103 break 

104 elif line.StartsWith("Ending"): 

105 nextLine = yield from self._TaskFinish(line) 

106 return nextLine 

107 elif line.StartsWith(self._TIME): 107 ↛ 108line 107 didn't jump to line 108 because the condition on line 107 was never true

108 line._kind = LineKind.TaskTime 

109 nextLine = yield line 

110 return nextLine 

111 

112 line = yield line 

113 

114 while phase is not None: 114 ↛ 89line 114 didn't jump to line 89 because the condition on line 114 was always true

115 # if line.StartsWith("Ending"): 

116 # line = yield task.send(line) 

117 # break 

118 

119 if isinstance(line, VivadoMessage): 

120 self._AddMessage(line) 

121 

122 try: 

123 line = yield phase.send(line) 

124 except StopIteration as ex: 

125 activeParsers.remove(parser) 

126 line = ex.value 

127 break