pyEDAA.OutputFilter 0.2.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (21) hide show
  1. {pyedaa_outputfilter-0.2.0 → pyedaa_outputfilter-0.3.0}/PKG-INFO +21 -21
  2. {pyedaa_outputfilter-0.2.0 → pyedaa_outputfilter-0.3.0}/README.md +1 -1
  3. {pyedaa_outputfilter-0.2.0 → pyedaa_outputfilter-0.3.0}/pyEDAA/OutputFilter/CLI/Vivado.py +56 -43
  4. pyedaa_outputfilter-0.3.0/pyEDAA/OutputFilter/Xilinx/Commands.py +285 -0
  5. pyedaa_outputfilter-0.2.0/pyEDAA/OutputFilter/Xilinx/__init__.py → pyedaa_outputfilter-0.3.0/pyEDAA/OutputFilter/Xilinx/Common.py +79 -302
  6. pyedaa_outputfilter-0.3.0/pyEDAA/OutputFilter/Xilinx/Common2.py +179 -0
  7. pyedaa_outputfilter-0.3.0/pyEDAA/OutputFilter/Xilinx/Exception.py +59 -0
  8. pyedaa_outputfilter-0.2.0/pyEDAA/OutputFilter/Xilinx/Synthesis.py → pyedaa_outputfilter-0.3.0/pyEDAA/OutputFilter/Xilinx/SynthesizeDesign.py +154 -229
  9. pyedaa_outputfilter-0.3.0/pyEDAA/OutputFilter/Xilinx/__init__.py +209 -0
  10. {pyedaa_outputfilter-0.2.0 → pyedaa_outputfilter-0.3.0}/pyEDAA/OutputFilter/__init__.py +1 -1
  11. {pyedaa_outputfilter-0.2.0 → pyedaa_outputfilter-0.3.0}/pyEDAA.OutputFilter.egg-info/PKG-INFO +21 -21
  12. {pyedaa_outputfilter-0.2.0 → pyedaa_outputfilter-0.3.0}/pyEDAA.OutputFilter.egg-info/SOURCES.txt +5 -1
  13. {pyedaa_outputfilter-0.2.0 → pyedaa_outputfilter-0.3.0}/LICENSE.md +0 -0
  14. {pyedaa_outputfilter-0.2.0 → pyedaa_outputfilter-0.3.0}/pyEDAA/OutputFilter/CLI/__init__.py +0 -0
  15. {pyedaa_outputfilter-0.2.0 → pyedaa_outputfilter-0.3.0}/pyEDAA.OutputFilter.egg-info/dependency_links.txt +0 -0
  16. {pyedaa_outputfilter-0.2.0 → pyedaa_outputfilter-0.3.0}/pyEDAA.OutputFilter.egg-info/entry_points.txt +0 -0
  17. {pyedaa_outputfilter-0.2.0 → pyedaa_outputfilter-0.3.0}/pyEDAA.OutputFilter.egg-info/requires.txt +19 -19
  18. {pyedaa_outputfilter-0.2.0 → pyedaa_outputfilter-0.3.0}/pyEDAA.OutputFilter.egg-info/top_level.txt +0 -0
  19. {pyedaa_outputfilter-0.2.0 → pyedaa_outputfilter-0.3.0}/pyproject.toml +0 -0
  20. {pyedaa_outputfilter-0.2.0 → pyedaa_outputfilter-0.3.0}/setup.cfg +0 -0
  21. {pyedaa_outputfilter-0.2.0 → pyedaa_outputfilter-0.3.0}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyEDAA.OutputFilter
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Post-processing of EDA Tool outputs (log files).
5
5
  Home-page: https://GitHub.com/edaa-org/pyEDAA.OutputFilter
6
6
  Author: Patrick Lehmann
@@ -27,45 +27,45 @@ Description-Content-Type: text/markdown
27
27
  License-File: LICENSE.md
28
28
  Requires-Dist: pyTooling[terminal]~=8.5
29
29
  Provides-Extra: doc
30
- Requires-Dist: sphinx_design~=0.6.1; extra == "doc"
31
30
  Requires-Dist: pyTooling[terminal]~=8.5; extra == "doc"
32
31
  Requires-Dist: docutils_stubs~=0.0.22; extra == "doc"
33
- Requires-Dist: sphinx_rtd_theme~=3.0; extra == "doc"
34
- Requires-Dist: sphinxcontrib-mermaid~=1.0; extra == "doc"
35
32
  Requires-Dist: sphinx_autodoc_typehints~=3.2; extra == "doc"
36
- Requires-Dist: sphinx-copybutton>=0.5.2; extra == "doc"
33
+ Requires-Dist: sphinxcontrib-autoprogram~=0.1; extra == "doc"
37
34
  Requires-Dist: sphinx~=8.2; extra == "doc"
38
- Requires-Dist: sphinx_reports~=0.9; extra == "doc"
35
+ Requires-Dist: sphinx_design~=0.6.1; extra == "doc"
36
+ Requires-Dist: sphinxcontrib-mermaid~=1.0; extra == "doc"
39
37
  Requires-Dist: autoapi>=2.0.1; extra == "doc"
38
+ Requires-Dist: sphinx-copybutton>=0.5.2; extra == "doc"
39
+ Requires-Dist: sphinx_reports~=0.9; extra == "doc"
40
+ Requires-Dist: sphinx_rtd_theme~=3.0; extra == "doc"
40
41
  Requires-Dist: docutils~=0.21; extra == "doc"
41
- Requires-Dist: sphinxcontrib-autoprogram~=0.1; extra == "doc"
42
42
  Provides-Extra: test
43
43
  Requires-Dist: pyTooling[terminal]~=8.5; extra == "test"
44
+ Requires-Dist: pytest~=8.4; extra == "test"
44
45
  Requires-Dist: typing_extensions~=4.14; extra == "test"
46
+ Requires-Dist: mypy~=1.16; extra == "test"
45
47
  Requires-Dist: pytest-cov~=6.2; extra == "test"
46
- Requires-Dist: pytest~=8.4; extra == "test"
47
48
  Requires-Dist: Coverage~=7.9; extra == "test"
48
49
  Requires-Dist: lxml~=5.4; extra == "test"
49
- Requires-Dist: mypy~=1.16; extra == "test"
50
50
  Provides-Extra: all
51
- Requires-Dist: sphinx_design~=0.6.1; extra == "all"
52
51
  Requires-Dist: pyTooling[terminal]~=8.5; extra == "all"
52
+ Requires-Dist: pytest~=8.4; extra == "all"
53
+ Requires-Dist: Coverage~=7.9; extra == "all"
53
54
  Requires-Dist: docutils_stubs~=0.0.22; extra == "all"
54
- Requires-Dist: sphinxcontrib-mermaid~=1.0; extra == "all"
55
- Requires-Dist: sphinx_rtd_theme~=3.0; extra == "all"
56
55
  Requires-Dist: sphinx_autodoc_typehints~=3.2; extra == "all"
57
- Requires-Dist: sphinx-copybutton>=0.5.2; extra == "all"
56
+ Requires-Dist: sphinxcontrib-autoprogram~=0.1; extra == "all"
58
57
  Requires-Dist: sphinx~=8.2; extra == "all"
59
- Requires-Dist: typing_extensions~=4.14; extra == "all"
60
- Requires-Dist: sphinx_reports~=0.9; extra == "all"
61
- Requires-Dist: pytest-cov~=6.2; extra == "all"
62
- Requires-Dist: pytest~=8.4; extra == "all"
63
- Requires-Dist: Coverage~=7.9; extra == "all"
64
58
  Requires-Dist: lxml~=5.4; extra == "all"
59
+ Requires-Dist: typing_extensions~=4.14; extra == "all"
60
+ Requires-Dist: sphinx_design~=0.6.1; extra == "all"
61
+ Requires-Dist: sphinxcontrib-mermaid~=1.0; extra == "all"
65
62
  Requires-Dist: autoapi>=2.0.1; extra == "all"
66
- Requires-Dist: docutils~=0.21; extra == "all"
67
- Requires-Dist: sphinxcontrib-autoprogram~=0.1; extra == "all"
63
+ Requires-Dist: sphinx-copybutton>=0.5.2; extra == "all"
64
+ Requires-Dist: sphinx_reports~=0.9; extra == "all"
65
+ Requires-Dist: sphinx_rtd_theme~=3.0; extra == "all"
68
66
  Requires-Dist: mypy~=1.16; extra == "all"
67
+ Requires-Dist: docutils~=0.21; extra == "all"
68
+ Requires-Dist: pytest-cov~=6.2; extra == "all"
69
69
  Dynamic: author
70
70
  Dynamic: author-email
71
71
  Dynamic: classifier
@@ -127,7 +127,7 @@ Dynamic: summary
127
127
 
128
128
  ```python
129
129
  from pathlib import Path
130
- from pyEDAA.OutputFilter.Xilinx.Synthesis import Processor
130
+ from pyEDAA.OutputFilter.Xilinx.SynthesizeDesign import Processor
131
131
 
132
132
  logfile = Path("tests/data/Stopwatch/toplevel.vds")
133
133
  processor = Processor(logfile)
@@ -44,7 +44,7 @@
44
44
 
45
45
  ```python
46
46
  from pathlib import Path
47
- from pyEDAA.OutputFilter.Xilinx.Synthesis import Processor
47
+ from pyEDAA.OutputFilter.Xilinx.SynthesizeDesign import Processor
48
48
 
49
49
  logfile = Path("tests/data/Stopwatch/toplevel.vds")
50
50
  processor = Processor(logfile)
@@ -38,13 +38,16 @@ from pyTooling.Attributes.ArgParse import CommandHandler
38
38
  from pyTooling.Attributes.ArgParse.Flag import LongFlag
39
39
  from pyTooling.Attributes.ArgParse.ValuedFlag import LongValuedFlag
40
40
 
41
- from pyEDAA.OutputFilter.Xilinx import Preamble, LineKind, Line
42
- from pyEDAA.OutputFilter.Xilinx.Synthesis import WritingSynthesisReport, Processor, LoadingPart
41
+ from pyEDAA.OutputFilter.Xilinx import Document, ProcessorException, SynthesizeDesign
42
+ from pyEDAA.OutputFilter.Xilinx.Common import LineKind, Line
43
+ from pyEDAA.OutputFilter.Xilinx.Common2 import Preamble
44
+ from pyEDAA.OutputFilter.Xilinx.SynthesizeDesign import WritingSynthesisReport, LoadingPart
45
+
43
46
 
44
47
 
45
48
  class VivadoHandlers(metaclass=ExtendedType, mixin=True):
46
- @CommandHandler("vivado-synth", help="Parse AMD/Xilinx Vivado Synthesis log files.", description="Parse AMD/Xilinx Vivado Synthesis log files.")
47
- @LongValuedFlag("--file", dest="logfile", metaName='Synthesis Log', help="Synthesis log file (*.vds).")
49
+ @CommandHandler("vivado", help="Parse AMD/Xilinx Vivado log files.", description="Parse AMD/Xilinx Vivado log files.")
50
+ @LongValuedFlag("--file", dest="logfile", metaName='Log file', help="Log file (*.vds|*.vdi).")
48
51
  @LongFlag("--colored", dest="colored", help="Render logfile with colored lines.")
49
52
  @LongFlag("--summary", dest="summary", help="Print a summary.")
50
53
  @LongFlag("--info", dest="info", help="Print info messages.")
@@ -53,8 +56,8 @@ class VivadoHandlers(metaclass=ExtendedType, mixin=True):
53
56
  @LongFlag("--error", dest="error", help="Print error messages.")
54
57
  @LongFlag("--influxdb", dest="influxdb", help="Write statistics as InfluxDB line protocol file (*.line).")
55
58
  # @LongValuedFlag("--file", dest="logfile", metaName='Synthesis Log', help="Synthesis log file (*.vds).")
56
- def HandleVivadoSynthesis(self, args: Namespace) -> None:
57
- """Handle program calls with command ``vivado-synth``."""
59
+ def HandleVivado(self, args: Namespace) -> None:
60
+ """Handle program calls with command ``vivado``."""
58
61
  self._PrintHeadline()
59
62
 
60
63
  returnCode = 0
@@ -64,13 +67,13 @@ class VivadoHandlers(metaclass=ExtendedType, mixin=True):
64
67
 
65
68
  logfile = Path(args.logfile)
66
69
  if not logfile.exists():
67
- self.WriteError(f"Vivado synthesis log file '{logfile}' doesn't exist.")
70
+ self.WriteError(f"Vivado log file '{logfile}' doesn't exist.")
68
71
  returnCode = 4
69
72
 
70
73
  if returnCode != 0:
71
74
  self.Exit(returnCode)
72
75
 
73
- processor = Processor(logfile)
76
+ processor = Document(logfile)
74
77
  processor.Parse()
75
78
 
76
79
  if args.colored:
@@ -94,98 +97,108 @@ class VivadoHandlers(metaclass=ExtendedType, mixin=True):
94
97
  self.WriteNormal(f" {message}")
95
98
 
96
99
  if args.influxdb:
100
+ synthesizeDesign = processor[SynthesizeDesign]
97
101
  influxString = "vivado_synthesis_overview"
98
- influxString += f",version={processor[Preamble].ToolVersion}"
102
+ influxString += f",version={processor.Preamble.ToolVersion}"
99
103
  influxString += f",branch=main"
100
104
  influxString += f",design=Stopwatch"
101
105
  influxString += " "
102
106
  influxString += f"processing_duration={processor.Duration:.3f}"
103
- influxString += f",synthesis_duration={processor[WritingSynthesisReport].Duration:.1f}"
107
+ influxString += f",synthesis_duration={synthesizeDesign[WritingSynthesisReport].Duration:.1f}"
104
108
  influxString += f",info_count={len(processor.InfoMessages)}u"
105
109
  influxString += f",warning_count={len(processor.WarningMessages)}u"
106
110
  influxString += f",critical_count={len(processor.CriticalWarningMessages)}u"
107
111
  influxString += f",error_count={len(processor.ErrorMessages)}u"
108
- influxString += f",blackbox_count={len(processor[WritingSynthesisReport].Blackboxes)}u"
112
+ influxString += f",blackbox_count={len(synthesizeDesign[WritingSynthesisReport].Blackboxes)}u"
109
113
  influxString += "\n"
110
114
  influxString += "vivado_synthesis_cells"
111
- influxString += f",version={processor[Preamble].ToolVersion}"
115
+ influxString += f",version={processor.Preamble.ToolVersion}"
112
116
  influxString += f",branch=main"
113
117
  influxString += f",design=Stopwatch"
114
118
  influxString += " "
115
- influxString += ",".join(f"{cellName}={cellCount}" for cellName, cellCount in processor[WritingSynthesisReport].Cells.items() if not cellName.endswith("_bbox"))
119
+ influxString += ",".join(f"{cellName}={cellCount}" for cellName, cellCount in synthesizeDesign[WritingSynthesisReport].Cells.items() if not cellName.endswith("_bbox"))
116
120
 
117
121
  self.WriteNormal(influxString)
118
122
 
119
123
  if args.summary:
124
+ synthesizeDesign : SynthesizeDesign = processor[SynthesizeDesign]
120
125
  self.WriteNormal("Summary:")
121
- self.WriteNormal(f" Tool version: {processor[Preamble].ToolVersion}")
122
- self.WriteNormal(f" Started at: {processor[Preamble].StartDatetime}")
126
+ self.WriteNormal(f" Tool version: {processor.Preamble.ToolVersion}")
127
+ self.WriteNormal(f" Started at: {processor.Preamble.StartDatetime}")
123
128
  self.WriteNormal(f" Processing duration: {processor.Duration:.3f} s")
124
129
  self.WriteNormal(f" Info: {len(processor.InfoMessages)}")
125
130
  self.WriteNormal(f" Warning: {len(processor.WarningMessages)}")
126
131
  self.WriteNormal(f" Critical Warning: {len(processor.CriticalWarningMessages)}")
127
132
  self.WriteNormal(f" Error: {len(processor.ErrorMessages)}")
128
- self.WriteNormal(f" Part: {processor[LoadingPart].Part}")
133
+ self.WriteNormal(f" Part: {synthesizeDesign[LoadingPart].Part}")
129
134
 
130
135
  self.WriteNormal("Policies:")
131
- self.WriteNormal(f" Latches: {'found' if processor.HasLatches else '----'}")
132
- if processor.HasLatches:
136
+ self.WriteNormal(f" Latches: {'found' if synthesizeDesign.HasLatches else '----'}")
137
+ if synthesizeDesign.HasLatches:
133
138
  for cellName in ("LD", ):
134
139
  try:
135
- self.WriteNormal(f" {cellName}: {processor.Cells[cellName]}")
140
+ self.WriteNormal(f" {cellName}: {synthesizeDesign.Cells[cellName]}")
136
141
  except KeyError:
137
142
  pass
138
- for latch in processor.Latches:
143
+ for latch in synthesizeDesign.Latches:
139
144
  self.WriteNormal(f" {latch}")
140
- self.WriteNormal(f" Blackboxes: {'found' if processor.HasBlackboxes else '----'}")
141
- if processor.HasBlackboxes:
142
- for bbox in processor[WritingSynthesisReport].Blackboxes:
145
+ self.WriteNormal(f" Blackboxes: {'found' if synthesizeDesign.HasBlackboxes else '----'}")
146
+ if synthesizeDesign.HasBlackboxes:
147
+ for bbox in synthesizeDesign.Blackboxes:
143
148
  self.WriteNormal(f" {bbox}")
144
149
 
145
- self.WriteNormal(f"VHDL report statements ({len(processor.VHDLReportMessages)}):")
146
- for message in processor.VHDLReportMessages:
150
+ self.WriteNormal(f"VHDL report statements ({len(synthesizeDesign.VHDLReportMessages)}):")
151
+ for message in synthesizeDesign.VHDLReportMessages:
147
152
  self.WriteNormal(f" {message}")
148
- self.WriteNormal(f"VHDL assert statements ({len(processor.VHDLAssertMessages)}):")
149
- for message in processor.VHDLAssertMessages:
153
+ self.WriteNormal(f"VHDL assert statements ({len(synthesizeDesign.VHDLAssertMessages)}):")
154
+ for message in synthesizeDesign.VHDLAssertMessages:
150
155
  self.WriteNormal(f" {message}")
151
156
 
152
- self.WriteNormal(f"Cells: {len(processor.Cells)}")
153
- for cell, count in processor.Cells.items():
157
+ self.WriteNormal(f"Cells: {len(synthesizeDesign.Cells)}")
158
+ for cell, count in synthesizeDesign.Cells.items():
154
159
  self.WriteNormal(f" {cell}: {count}")
155
160
 
156
161
  self.ExitOnPreviousErrors()
157
162
 
158
163
  def ColoredOutput(self, lines: Iterable[Line]) -> None:
159
164
  for i, line in enumerate(lines, start=1):
160
- if line.Kind is LineKind.Normal:
165
+ message = str(line).replace("{", "{{").replace("}", "}}")
166
+ if isinstance(line, ProcessorException):
167
+ print(f"{i:4}: {{RED}}EXCEPTION:{{NOCOLOR}} {message}".format(**self.Foreground))
168
+ elif line.Kind is LineKind.Normal:
161
169
  print(f"{i:4}: {line.Message}")
162
170
  elif LineKind.Message in line.Kind:
163
171
  if line.Kind is LineKind.InfoMessage:
164
- print(f"{i:4}: {{BLUE}}{line}{{NOCOLOR}}".format(**self.Foreground))
172
+ print(f"{i:4}: {{BLUE}}{message}{{NOCOLOR}}".format(**self.Foreground))
165
173
  elif line.Kind is LineKind.WarningMessage:
166
- print(f"{i:4}: {{YELLOW}}{line}{{NOCOLOR}}".format(**self.Foreground))
174
+ print(f"{i:4}: {{YELLOW}}{message}{{NOCOLOR}}".format(**self.Foreground))
167
175
  elif line.Kind is LineKind.CriticalWarningMessage:
168
- print(f"{i:4}: {{MAGENTA}}{line}{{NOCOLOR}}".format(**self.Foreground))
176
+ print(f"{i:4}: {{MAGENTA}}{message}{{NOCOLOR}}".format(**self.Foreground))
169
177
  elif line.Kind is LineKind.ErrorMessage:
170
- print(f"{i:4}: {{RED}}{line}{{NOCOLOR}}".format(**self.Foreground))
171
- elif LineKind.Command in line.Kind:
172
- print(f"{i:4}: {{CYAN}}{line}{{NOCOLOR}}".format(**self.Foreground))
178
+ print(f"{i:4}: {{RED}}{message}{{NOCOLOR}}".format(**self.Foreground))
179
+ elif LineKind.TclCommand in line.Kind:
180
+ print(f"{i:4}: {{CYAN}}{message}{{NOCOLOR}}".format(**self.Foreground))
173
181
  elif (LineKind.Start in line.Kind) or (LineKind.End in line.Kind):
174
- print(f"{i:4}: {{DARK_CYAN}}{line}{{NOCOLOR}}".format(**self.Foreground))
182
+ if LineKind.Phase in line.Kind:
183
+ print(f"{i:4}: {{YELLOW}}{message}{{NOCOLOR}}".format(**self.Foreground))
184
+ else:
185
+ print(f"{i:4}: {{DARK_CYAN}}{message}{{NOCOLOR}}".format(**self.Foreground))
175
186
  elif line.Kind is LineKind.ParagraphHeadline:
176
- print(f"{i:4}: {{DARK_YELLOW}}{line}{{NOCOLOR}}".format(**self.Foreground))
187
+ print(f"{i:4}: {{DARK_YELLOW}}{message}{{NOCOLOR}}".format(**self.Foreground))
177
188
  elif LineKind.Table in line.Kind:
178
- print(f"{i:4}: {{WHITE}}{line}{{NOCOLOR}}".format(**self.Foreground))
189
+ print(f"{i:4}: {{WHITE}}{message}{{NOCOLOR}}".format(**self.Foreground))
179
190
  elif LineKind.Delimiter in line.Kind:
180
- print(f"{i:4}: {{GRAY}}{line}{{NOCOLOR}}".format(**self.Foreground))
191
+ print(f"{i:4}: {{GRAY}}{message}{{NOCOLOR}}".format(**self.Foreground))
181
192
  elif LineKind.Verbose in line.Kind:
182
- print(f"{i:4}: {{DARK_GRAY}}{line}{{NOCOLOR}}".format(**self.Foreground))
193
+ print(f"{i:4}: {{DARK_GRAY}}{message}{{NOCOLOR}}".format(**self.Foreground))
194
+ elif LineKind.Success in line.Kind:
195
+ print(f"{i:4}: {{GREEN}}{message}{{NOCOLOR}}".format(**self.Foreground))
183
196
  elif line.Kind is LineKind.Empty:
184
197
  print(f"{i:4}:")
185
198
  elif line.Kind is LineKind.ProcessorError:
186
- print(f"{i:4}: {{RED}}{line}{{NOCOLOR}}".format(**self.Foreground))
199
+ print(f"{i:4}: {{RED}}{message}{{NOCOLOR}}".format(**self.Foreground))
187
200
  elif line.Kind is LineKind.Unprocessed:
188
- print(f"{i:4}: {{DARK_RED}}{line}{{NOCOLOR}}".format(**self.Foreground))
201
+ print(f"{i:4}: {{DARK_RED}}{message}{{NOCOLOR}}".format(**self.Foreground))
189
202
  else:
190
203
  print(f"{i:4}: Unknown LineKind '{line._kind}' for line {line._lineNumber}.")
191
204
  print(line)
@@ -0,0 +1,285 @@
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
+ """Basic classes for outputs from AMD/Xilinx Vivado."""
32
+ from typing import ClassVar, Generator, Union, List, Type, Dict, Iterator, Any
33
+
34
+ from pyTooling.Decorators import export, readonly
35
+
36
+ from pyEDAA.OutputFilter.Xilinx import VivadoTclCommand
37
+ from pyEDAA.OutputFilter.Xilinx.Exception import ProcessorException
38
+ from pyEDAA.OutputFilter.Xilinx.Common import Line, LineKind, VivadoMessage, VHDLReportMessage
39
+ from pyEDAA.OutputFilter.Xilinx.Common2 import Parser
40
+ from pyEDAA.OutputFilter.Xilinx.SynthesizeDesign import Section, RTLElaboration, HandlingCustomAttributes
41
+ from pyEDAA.OutputFilter.Xilinx.SynthesizeDesign import ConstraintValidation, LoadingPart, ApplySetProperty
42
+ from pyEDAA.OutputFilter.Xilinx.SynthesizeDesign import RTLComponentStatistics, PartResourceSummary
43
+ from pyEDAA.OutputFilter.Xilinx.SynthesizeDesign import CrossBoundaryAndAreaOptimization, ROM_RAM_DSP_SR_Retiming
44
+ from pyEDAA.OutputFilter.Xilinx.SynthesizeDesign import ApplyingXDCTimingConstraints, TimingOptimization
45
+ from pyEDAA.OutputFilter.Xilinx.SynthesizeDesign import TechnologyMapping, IOInsertion, FlatteningBeforeIOInsertion
46
+ from pyEDAA.OutputFilter.Xilinx.SynthesizeDesign import FinalNetlistCleanup, RenamingGeneratedInstances
47
+ from pyEDAA.OutputFilter.Xilinx.SynthesizeDesign import RebuildingUserHierarchy, RenamingGeneratedPorts
48
+ from pyEDAA.OutputFilter.Xilinx.SynthesizeDesign import RenamingGeneratedNets, WritingSynthesisReport
49
+
50
+
51
+ @export
52
+ class NotPresentException(ProcessorException):
53
+ pass
54
+
55
+
56
+ @export
57
+ class SectionNotPresentException(NotPresentException):
58
+ pass
59
+
60
+
61
+ @export
62
+ class HandlingCustomAttributes1(HandlingCustomAttributes):
63
+ pass
64
+
65
+
66
+ @export
67
+ class HandlingCustomAttributes2(HandlingCustomAttributes):
68
+ pass
69
+
70
+
71
+ @export
72
+ class ROM_RAM_DSP_SR_Retiming1(ROM_RAM_DSP_SR_Retiming):
73
+ pass
74
+
75
+
76
+ @export
77
+ class ROM_RAM_DSP_SR_Retiming2(ROM_RAM_DSP_SR_Retiming):
78
+ pass
79
+
80
+
81
+ @export
82
+ class ROM_RAM_DSP_SR_Retiming3(ROM_RAM_DSP_SR_Retiming):
83
+ pass
84
+
85
+
86
+ @export
87
+ class Command(Parser):
88
+ # _TCL_COMMAND: ClassVar[str]
89
+ pass
90
+
91
+
92
+ @export
93
+ class SynthesizeDesign(Command):
94
+ _TCL_COMMAND: ClassVar[str] = "synth_design"
95
+ _PARSERS: ClassVar[List[Type[Section]]] = (
96
+ RTLElaboration,
97
+ HandlingCustomAttributes1,
98
+ ConstraintValidation,
99
+ LoadingPart,
100
+ ApplySetProperty,
101
+ RTLComponentStatistics,
102
+ PartResourceSummary,
103
+ CrossBoundaryAndAreaOptimization,
104
+ ROM_RAM_DSP_SR_Retiming1,
105
+ ApplyingXDCTimingConstraints,
106
+ TimingOptimization,
107
+ ROM_RAM_DSP_SR_Retiming2,
108
+ TechnologyMapping,
109
+ IOInsertion,
110
+ FlatteningBeforeIOInsertion,
111
+ FinalNetlistCleanup,
112
+ RenamingGeneratedInstances,
113
+ RebuildingUserHierarchy,
114
+ RenamingGeneratedPorts,
115
+ HandlingCustomAttributes2,
116
+ RenamingGeneratedNets,
117
+ ROM_RAM_DSP_SR_Retiming3,
118
+ WritingSynthesisReport,
119
+ )
120
+
121
+ _sections: Dict[Type[Section], Section]
122
+
123
+ def __init__(self, processor: "Processor") -> None:
124
+ super().__init__(processor)
125
+
126
+ self._sections = {p: p(self) for p in self._PARSERS}
127
+
128
+ @readonly
129
+ def HasLatches(self) -> bool:
130
+ if (8 in self._messagesByID) and (327 in self._messagesByID[8]):
131
+ return True
132
+
133
+ return "LD" in self._sections[WritingSynthesisReport]._cells
134
+
135
+ @readonly
136
+ def Latches(self) -> Iterator[VivadoMessage]:
137
+ try:
138
+ yield from iter(self._messagesByID[8][327])
139
+ except KeyError:
140
+ yield from ()
141
+
142
+ @readonly
143
+ def HasBlackboxes(self) -> bool:
144
+ return len(self._sections[WritingSynthesisReport]._blackboxes) > 0
145
+
146
+ @readonly
147
+ def Blackboxes(self) -> Dict[str, int]:
148
+ return self._sections[WritingSynthesisReport]._blackboxes
149
+
150
+ @readonly
151
+ def Cells(self) -> Dict[str, int]:
152
+ return self._sections[WritingSynthesisReport]._cells
153
+
154
+ @readonly
155
+ def VHDLReportMessages(self) -> List[VHDLReportMessage]:
156
+ if 8 in self._messagesByID:
157
+ if 6031 in (synthMessages := self._messagesByID[8]):
158
+ return [message for message in synthMessages[6031]]
159
+
160
+ return []
161
+
162
+ @readonly
163
+ def VHDLAssertMessages(self) -> List[VHDLReportMessage]:
164
+ if 8 in self._messagesByID:
165
+ if 63 in (synthMessages := self._messagesByID[8]):
166
+ return [message for message in synthMessages[63]]
167
+
168
+ return []
169
+
170
+ def __getitem__(self, item: Type[Parser]) -> Union[_PARSERS]:
171
+ try:
172
+ return self._sections[item]
173
+ except KeyError as ex:
174
+ raise SectionNotPresentException(F"Section '{item._NAME}' not present in '{self._parent.logfile}'.") from ex
175
+
176
+ def SectionDetector(self, line: Line) -> Generator[Union[Line, ProcessorException], Line, None]:
177
+ # parser: Section = firstValue(self._sections)
178
+ activeParsers: List[Parser] = list(self._sections.values())
179
+
180
+ rtlElaboration = self._sections[RTLElaboration]
181
+ # constraintValidation = self._sections[ConstraintValidation]
182
+
183
+ if not (isinstance(line, VivadoTclCommand) and line._command == self._TCL_COMMAND):
184
+ raise ProcessorException()
185
+
186
+ line = yield line
187
+ if line == "Starting synth_design":
188
+ line._kind = LineKind.Verbose
189
+ else:
190
+ raise ProcessorException()
191
+
192
+ line = yield line
193
+
194
+ while True:
195
+ while True:
196
+ if line.StartsWith("Start "):
197
+ for parser in activeParsers: # type: Section
198
+ if line.StartsWith(parser._START):
199
+ line = next(section := parser.Generator(line))
200
+ line._previousLine._kind = LineKind.SectionStart | LineKind.SectionDelimiter
201
+ break
202
+ else:
203
+ raise Exception(f"Unknown section: {line}")
204
+ break
205
+ elif line.StartsWith("Starting "):
206
+ if line.StartsWith(rtlElaboration._START):
207
+ parser = rtlElaboration
208
+ line = next(section := parser.Generator(line))
209
+ line._previousLine._kind = LineKind.SectionStart | LineKind.SectionDelimiter
210
+ break
211
+ elif line.StartsWith(self._TCL_COMMAND):
212
+ if line[len(self._TCL_COMMAND) + 1:].startswith("completed successfully"):
213
+ line._kind |= LineKind.Success
214
+
215
+ line = yield line
216
+ if line.StartsWith(self._TCL_COMMAND + ":"):
217
+ line._kind |= LineKind.Last
218
+ else:
219
+ pass
220
+
221
+ lastLine = yield line
222
+ return lastLine
223
+ elif line.StartsWith("Finished RTL Optimization Phase"):
224
+ line._kind = LineKind.PhaseEnd
225
+ line._previousLine._kind = LineKind.PhaseEnd | LineKind.PhaseDelimiter
226
+ elif line.StartsWith("----"):
227
+ if LineKind.Phase in line._previousLine._kind:
228
+ line._kind = LineKind.PhaseEnd | LineKind.PhaseDelimiter
229
+ elif not isinstance(line, VivadoMessage):
230
+ pass
231
+ # line._kind = LineKind.Unprocessed
232
+
233
+ line = yield line
234
+
235
+ line = yield line
236
+
237
+ while True:
238
+ if line.StartsWith("Finished"):
239
+ l = line[9:]
240
+ if not (l.startswith("Flattening") or l.startswith("Final")):
241
+ line = yield section.send(line)
242
+ break
243
+
244
+ if isinstance(line, VivadoMessage):
245
+ self._AddMessage(line)
246
+
247
+ line = yield section.send(line)
248
+
249
+ line = yield section.send(line)
250
+
251
+ activeParsers.remove(parser)
252
+
253
+
254
+ @export
255
+ class LinkDesign(Command):
256
+ _TCL_COMMAND: ClassVar[str] = "link_design"
257
+
258
+
259
+ @export
260
+ class OptimizeDesign(Command):
261
+ _TCL_COMMAND: ClassVar[str] = "opt_design"
262
+
263
+
264
+ @export
265
+ class PlaceDesign(Command):
266
+ _TCL_COMMAND: ClassVar[str] = "place_design"
267
+
268
+
269
+ @export
270
+ class PhysicalOptimizationDesign(Command):
271
+ _TCL_COMMAND: ClassVar[str] = "phys_opt_design"
272
+
273
+
274
+ @export
275
+ class PhysicalOptimizationDesign(Command):
276
+ _TCL_COMMAND: ClassVar[str] = "route_design"
277
+
278
+
279
+ @export
280
+ class WriteBitstream(Command):
281
+ _TCL_COMMAND: ClassVar[str] = "write_bitstream"
282
+
283
+ # report_drc
284
+ # report_methodology
285
+ # report_power