Coverage for pyEDAA/OutputFilter/Xilinx/SynthesizeDesign.py: 82%

428 statements  

« prev     ^ index     » next       coverage.py v7.14.1, created at 2026-06-05 22:59 +0000

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

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

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

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

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

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

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

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

9# Authors: # 

10# Patrick Lehmann # 

11# # 

12# License: # 

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

14# Copyright 2025-2026 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 re import compile as re_compile 

33from typing import ClassVar, Dict, Generator, Type, Optional as Nullable, Any, Union 

34 

35from pyTooling.Common import getFullyQualifiedName 

36from pyTooling.Decorators import export, readonly 

37from pyTooling.MetaClasses import ExtendedType, abstractmethod 

38 

39from pyEDAA.OutputFilter.Xilinx.Exception import NotPresentException 

40from pyEDAA.OutputFilter.Xilinx.Common import VHDLAssertionMessage, Line, LineKind, VivadoInfoMessage, VHDLReportMessage, VivadoMessage 

41from pyEDAA.OutputFilter.Xilinx.Common2 import BaseParser 

42 

43TIME_MEMORY_PATTERN = re_compile(r"""Time \(s\): cpu = (\d{2}:\d{2}:\d{2}) ; elapsed = (\d{2}:\d{2}:\d{2}) . Memory \(MB\): peak = (\d+\.\d+) ; gain = (\d+\.\d+)""") 

44 

45 

46@export 

47class SubSectionNotPresentException(NotPresentException): 

48 pass 

49 

50 

51@export 

52class BaseSection(metaclass=ExtendedType, mixin=True): 

53 @abstractmethod 

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

55 pass 

56 

57 @abstractmethod 

58 def _SectionFinish(self, line: Line) -> Generator[Line, Line, None]: 

59 pass 

60 

61 @abstractmethod 

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

63 pass 

64 

65 

66@export 

67class Section(BaseParser, BaseSection): 

68 """ 

69 Base-class for sections within log outputs from *synthesize design*. 

70 """ 

71 # _NAME: ClassVar[str] 

72 # _START: ClassVar[str] 

73 # _FINISH: ClassVar[str] 

74 

75 _command: "Command" #: Reference to the command (parent). 

76 _duration: float #: Duration synthesis spent in processing a synthesis step logged in this log output section. 

77 

78 def __init__(self, command: "Command") -> None: 

79 """ 

80 Initialized a section. 

81 

82 :param command: Reference to the parent TCL command. 

83 """ 

84 super().__init__() #command._processor) 

85 

86 self._command = command 

87 self._duration = 0.0 

88 

89 @readonly 

90 def Duration(self) -> float: 

91 """ 

92 Read-only property to access the duration synthesis spent in processing a synthesis step logged in this log output 

93 section. 

94 

95 :returns: Synthesis step duration in seconds. 

96 """ 

97 return self._duration 

98 

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

100 line._kind = LineKind.SectionStart 

101 

102 line = yield line 

103 if line.StartsWith("----"): 103 ↛ 106line 103 didn't jump to line 106 because the condition on line 103 was always true

104 line._kind = LineKind.SectionStart | LineKind.SectionDelimiter 

105 else: 

106 line._kind |= LineKind.ProcessorError 

107 

108 nextLine = yield line 

109 return nextLine 

110 

111 def _SectionFinish(self, line: Line, skipDashes: bool = False) -> Generator[Line, Line, None]: 

112 if not skipDashes: 

113 if line.StartsWith("----"): 113 ↛ 116line 113 didn't jump to line 116 because the condition on line 113 was always true

114 line._kind = LineKind.SectionEnd | LineKind.SectionDelimiter 

115 else: 

116 line._kind |= LineKind.ProcessorError 

117 

118 line = yield line 

119 

120 if line.StartsWith(self._FINISH): 120 ↛ 123line 120 didn't jump to line 123 because the condition on line 120 was always true

121 line._kind = LineKind.SectionEnd 

122 else: 

123 line._kind |= LineKind.ProcessorError 

124 

125 line = yield line 

126 if line.StartsWith("----"): 126 ↛ 129line 126 didn't jump to line 129 because the condition on line 126 was always true

127 line._kind = LineKind.SectionEnd | LineKind.SectionDelimiter 

128 else: 

129 line._kind |= LineKind.ProcessorError 

130 

131 nextLine = yield line 

132 return nextLine 

133 

134 # @mustoverride 

135 # def ParseLine(self, lineNumber: int, line: str) -> ProcessingState: 

136 # if len(line) == 0: 

137 # return ProcessingState.EmptyLine 

138 # elif line.startswith("----"): 

139 # return ProcessingState.DelimiterLine 

140 # elif line.startswith(self._START): 

141 # return ProcessingState.Skipped 

142 # elif line.startswith(self._FINISH): 

143 # l = line[len(self._FINISH):] 

144 # if (match := TIME_MEMORY_PATTERN.match(l)) is not None: 

145 # # cpuParts = match[1].split(":") 

146 # elapsedParts = match[2].split(":") 

147 # # peakMemory = float(match[3]) 

148 # # gainMemory = float(match[4]) 

149 # self._duration = int(elapsedParts[0]) * 3600 + int(elapsedParts[1]) * 60 + int(elapsedParts[2]) 

150 # 

151 # return ProcessingState.Skipped | ProcessingState.Last 

152 # elif line.startswith("Start") or line.startswith("Starting"): 

153 # print(f"ERROR: didn't find finish\n {line}") 

154 # return ProcessingState.Reprocess 

155 # 

156 # return ProcessingState.Skipped 

157 

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

159 line = yield from self._SectionStart(line) 

160 

161 while True: 

162 if line._kind is LineKind.Empty: 162 ↛ 163line 162 didn't jump to line 163 because the condition on line 162 was never true

163 line = yield line 

164 continue 

165 elif line.StartsWith("----"): 

166 line._kind = LineKind.SectionEnd | LineKind.SectionDelimiter 

167 break 

168 elif isinstance(line, VivadoMessage): 

169 self._AddMessage(line) 

170 else: 

171 line._kind = LineKind.Verbose 

172 

173 line = yield line 

174 

175 # line = yield line 

176 nextLine = yield from self._SectionFinish(line) 

177 return nextLine 

178 

179 

180@export 

181class SubSection(BaseParser, BaseSection): 

182 """ 

183 Base-class for subsections within log outputs from *synthesize design*. 

184 """ 

185 # _NAME: ClassVar[str] 

186 

187 _section: Section #: Reference to the section (parent). 

188 

189 def __init__(self, section: Section) -> None: 

190 """ 

191 Initialized a subsection. 

192 

193 :param section: Reference to the parent section. 

194 """ 

195 super().__init__() 

196 self._section = section 

197 

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

199 line._kind = LineKind.SubSectionStart 

200 

201 line = yield line 

202 if line.StartsWith("----"): 202 ↛ 205line 202 didn't jump to line 205 because the condition on line 202 was always true

203 line._kind = LineKind.SubSectionStart | LineKind.SubSectionDelimiter 

204 else: 

205 line._kind |= LineKind.ProcessorError 

206 

207 nextLine = yield line 

208 return nextLine 

209 

210 def _SectionFinish(self, line: Line) -> Generator[Line, Line, None]: 

211 if line.StartsWith("----"): 211 ↛ 214line 211 didn't jump to line 214 because the condition on line 211 was always true

212 line._kind = LineKind.SubSectionEnd | LineKind.SubSectionDelimiter 

213 else: 

214 line._kind |= LineKind.ProcessorError 

215 

216 line = yield line 

217 if line.StartsWith(self._FINISH): 217 ↛ 220line 217 didn't jump to line 220 because the condition on line 217 was always true

218 line._kind = LineKind.SubSectionEnd 

219 else: 

220 line._kind |= LineKind.ProcessorError 

221 

222 line = yield line 

223 if line.StartsWith("----"): 223 ↛ 226line 223 didn't jump to line 226 because the condition on line 223 was always true

224 line._kind = LineKind.SubSectionEnd | LineKind.SubSectionDelimiter 

225 else: 

226 line._kind |= LineKind.ProcessorError 

227 

228 nextLine = yield line 

229 return nextLine 

230 

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

232 line = yield from self._SectionStart(line) 

233 

234 while True: 

235 if line._kind is LineKind.Empty: 235 ↛ 236line 235 didn't jump to line 236 because the condition on line 235 was never true

236 line = yield line 

237 continue 

238 elif line.StartsWith("----"): 238 ↛ 241line 238 didn't jump to line 241 because the condition on line 238 was always true

239 line._kind = LineKind.SubSectionEnd | LineKind.SubSectionDelimiter 

240 break 

241 elif isinstance(line, VivadoMessage): 

242 self._AddMessage(line) 

243 else: 

244 line._kind = LineKind.Verbose 

245 

246 line = yield line 

247 

248 nextLine = yield from self._SectionFinish(line) 

249 return nextLine 

250 

251 

252@export 

253class SectionWithChildren(Section): 

254 """ 

255 Base-class for sections with subsections. 

256 """ 

257 _subsections: Dict[Type[SubSection], SubSection] 

258 

259 def __init__(self, command: "Command") -> None: 

260 super().__init__(command) 

261 

262 self._subsections = {} 

263 

264 def __contains__(self, key: Any) -> bool: 

265 if not issubclass(key, SubSection): 265 ↛ 266line 265 didn't jump to line 266 because the condition on line 265 was never true

266 ex = TypeError(f"Parameter 'item' is not a SubSection.") 

267 ex.add_note(f"Got type '{getFullyQualifiedName(key)}'.") 

268 raise ex 

269 

270 return key in self._subsections 

271 

272 def __getitem__(self, item: Type[SubSection]) -> SubSection: 

273 try: 

274 return self._sections[item] 

275 except KeyError as ex: 

276 raise SubSectionNotPresentException(f"SubSection '{item._NAME}' not present in '{self._parent._parent.logfile}'.") from ex 

277 

278 

279@export 

280class RTLElaboration(Section): 

281 """ 

282 *RTL Elaboration* section. 

283 

284 Used by Vivado command :class:`~pyEDAA.OutputFilter.Xilinx.Commands.SynthesizeDesign`. 

285 """ 

286 _NAME: ClassVar[str] = "RTL Elaboration" 

287 _START: ClassVar[str] = "Starting RTL Elaboration : " 

288 _FINISH: ClassVar[str] = "Finished RTL Elaboration : " 

289 

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

291 line = yield from self._SectionStart(line) 

292 

293 while True: 

294 if line._kind is LineKind.Empty: 294 ↛ 295line 294 didn't jump to line 295 because the condition on line 294 was never true

295 line = yield line 

296 continue 

297 elif isinstance(line, VivadoInfoMessage): 

298 if line._toolID == 8: 

299 if line._messageKindID == 63: # VHDL assert statement 

300 newLine = VHDLAssertionMessage.Convert(line) 

301 if newLine is None: 301 ↛ 302line 301 didn't jump to line 302 because the condition on line 301 was never true

302 pass 

303 else: 

304 line = newLine 

305 elif line._messageKindID == 6031: # VHDL report statement 

306 newLine = VHDLReportMessage.Convert(line) 

307 if newLine is None: 307 ↛ 308line 307 didn't jump to line 308 because the condition on line 307 was never true

308 pass 

309 else: 

310 line = newLine 

311 

312 if line.StartsWith("----"): 

313 line._kind = LineKind.SectionEnd | LineKind.SectionDelimiter 

314 break 

315 elif isinstance(line, VivadoMessage): 

316 self._AddMessage(line) 

317 else: 

318 line._kind = LineKind.Verbose 

319 

320 line = yield line 

321 

322 # line = yield line 

323 nextLine = yield from self._SectionFinish(line) 

324 return nextLine 

325 

326 

327@export 

328class HandlingCustomAttributes(Section): 

329 """ 

330 *Handling Custom Attributes* section. 

331 

332 Used by Vivado command :class:`~pyEDAA.OutputFilter.Xilinx.Commands.SynthesizeDesign`. 

333 """ 

334 _NAME: ClassVar[str] = "Handling Custom Attributes" 

335 _START: ClassVar[str] = "Start Handling Custom Attributes" 

336 _FINISH: ClassVar[str] = "Finished Handling Custom Attributes : " 

337 

338 

339@export 

340class ConstraintValidation(Section): 

341 """ 

342 *Constraint Validation* section. 

343 

344 Used by Vivado command :class:`~pyEDAA.OutputFilter.Xilinx.Commands.SynthesizeDesign`. 

345 """ 

346 _NAME: ClassVar[str] = "Constraint Validation" 

347 _START: ClassVar[str] = "Finished RTL Optimization Phase 1" 

348 _FINISH: ClassVar[str] = "Finished Constraint Validation : " 

349 

350 

351@export 

352class LoadingPart(Section): 

353 """ 

354 *Loading Part and Timing Information* section. 

355 

356 Used by Vivado command :class:`~pyEDAA.OutputFilter.Xilinx.Commands.SynthesizeDesign`. 

357 """ 

358 _NAME: ClassVar[str] = "Loading Part and Timing Information" 

359 _START: ClassVar[str] = "Start Loading Part and Timing Information" 

360 _FINISH: ClassVar[str] = "Finished Loading Part and Timing Information : " 

361 

362 _part: Nullable[str] #: Part name of the device this design was synthesized for. 

363 

364 def __init__(self, command: "Command") -> None: 

365 """ 

366 Initializes the section for loading the device information. 

367 

368 :param command: Reference to the TCL command. 

369 """ 

370 super().__init__(command) 

371 

372 self._part = None 

373 

374 @readonly 

375 def Part(self) -> Nullable[str]: 

376 """ 

377 Read-only property to access the used device's part name. 

378 

379 :returns: Part name of the device this design was synthesized for. 

380 """ 

381 return self._part 

382 

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

384 line = yield from self._SectionStart(line) 

385 

386 while True: 

387 if line._kind is LineKind.Empty: 387 ↛ 388line 387 didn't jump to line 388 because the condition on line 387 was never true

388 line = yield line 

389 continue 

390 elif line.StartsWith("Loading part: "): 

391 line._kind = LineKind.Normal 

392 self._part = line._message[14:].strip() 

393 elif line.StartsWith("----"): 

394 line._kind = LineKind.SectionEnd | LineKind.SectionDelimiter 

395 break 

396 elif isinstance(line, VivadoMessage): 396 ↛ 399line 396 didn't jump to line 399 because the condition on line 396 was always true

397 self._AddMessage(line) 

398 else: 

399 line._kind = LineKind.Verbose 

400 

401 line = yield line 

402 

403 nextLine = yield from self._SectionFinish(line) 

404 return nextLine 

405 

406@export 

407class ApplySetProperty(Section): 

408 """ 

409 *Applying 'set_property' XDC Constraints* section. 

410 

411 Used by Vivado command :class:`~pyEDAA.OutputFilter.Xilinx.Commands.SynthesizeDesign`. 

412 """ 

413 _NAME: ClassVar[str] = "Applying 'set_property' XDC Constraints" 

414 _START: ClassVar[str] = "Start Applying 'set_property' XDC Constraints" 

415 _FINISH: ClassVar[str] = "Finished applying 'set_property' XDC Constraints : " 

416 

417 

418@export 

419class RTLComponentStatistics(Section): 

420 """ 

421 *RTL Component Statistics* section. 

422 

423 Used by Vivado command :class:`~pyEDAA.OutputFilter.Xilinx.Commands.SynthesizeDesign`. 

424 """ 

425 _NAME: ClassVar[str] = "RTL Component Statistics" 

426 _START: ClassVar[str] = "Start RTL Component Statistics" 

427 _FINISH: ClassVar[str] = "Finished RTL Component Statistics" 

428 

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

430 line = yield from self._SectionStart(line) 

431 

432 while True: 

433 if line._kind is LineKind.Empty: 433 ↛ 434line 433 didn't jump to line 434 because the condition on line 433 was never true

434 line = yield line 

435 continue 

436 elif line.StartsWith("----"): 

437 line._kind = LineKind.SectionEnd | LineKind.SectionDelimiter 

438 break 

439 elif isinstance(line, VivadoMessage): 439 ↛ 440line 439 didn't jump to line 440 because the condition on line 439 was never true

440 self._AddMessage(line) 

441 else: 

442 line._kind = LineKind.Verbose 

443 

444 line = yield line 

445 

446 nextLine = yield from self._SectionFinish(line) 

447 return nextLine 

448 

449 

450@export 

451class RTLHierarchicalComponentStatistics(Section): 

452 """ 

453 *RTL Hierarchical Component Statistics* section. 

454 

455 Used by Vivado command :class:`~pyEDAA.OutputFilter.Xilinx.Commands.SynthesizeDesign`. 

456 """ 

457 _NAME: ClassVar[str] = "RTL Hierarchical Component Statistics" 

458 _START: ClassVar[str] = "Start RTL Hierarchical Component Statistics" 

459 _FINISH: ClassVar[str] = "Finished RTL Hierarchical Component Statistics" 

460 

461 

462@export 

463class PartResourceSummary(Section): 

464 """ 

465 *Part Resource Summary* section. 

466 

467 Used by Vivado command :class:`~pyEDAA.OutputFilter.Xilinx.Commands.SynthesizeDesign`. 

468 """ 

469 _NAME: ClassVar[str] = "Part Resource Summary" 

470 _START: ClassVar[str] = "Start Part Resource Summary" 

471 _FINISH: ClassVar[str] = "Finished Part Resource Summary" 

472 

473 

474@export 

475class CrossBoundaryAndAreaOptimization(Section): 

476 """ 

477 *Cross Boundary and Area Optimization* section. 

478 

479 Used by Vivado command :class:`~pyEDAA.OutputFilter.Xilinx.Commands.SynthesizeDesign`. 

480 """ 

481 _NAME: ClassVar[str] = "Cross Boundary and Area Optimization" 

482 _START: ClassVar[str] = "Start Cross Boundary and Area Optimization" 

483 _FINISH: ClassVar[str] = "Finished Cross Boundary and Area Optimization : " 

484 

485 

486@export 

487class ROM_RAM_DSP_SR_Retiming(Section): 

488 """ 

489 *ROM, RAM, DSP, Shift Register and Retiming Reporting* section. 

490 

491 Used by Vivado command :class:`~pyEDAA.OutputFilter.Xilinx.Commands.SynthesizeDesign`. 

492 """ 

493 _NAME: ClassVar[str] = "ROM, RAM, DSP, Shift Register and Retiming Reporting" 

494 _START: ClassVar[str] = "Start ROM, RAM, DSP, Shift Register and Retiming Reporting" 

495 _FINISH: ClassVar[str] = "Finished ROM, RAM, DSP, Shift Register and Retiming Reporting" 

496 

497 

498@export 

499class ApplyingXDCTimingConstraints(Section): 

500 """ 

501 *Applying XDC Timing Constraints* section. 

502 

503 Used by Vivado command :class:`~pyEDAA.OutputFilter.Xilinx.Commands.SynthesizeDesign`. 

504 """ 

505 _NAME: ClassVar[str] = "Applying XDC Timing Constraints" 

506 _START: ClassVar[str] = "Start Applying XDC Timing Constraints" 

507 _FINISH: ClassVar[str] = "Finished Applying XDC Timing Constraints : " 

508 

509 

510@export 

511class TimingOptimization(Section): 

512 """ 

513 *Timing Optimization* section. 

514 

515 Used by Vivado command :class:`~pyEDAA.OutputFilter.Xilinx.Commands.SynthesizeDesign`. 

516 """ 

517 _NAME: ClassVar[str] = "Timing Optimization" 

518 _START: ClassVar[str] = "Start Timing Optimization" 

519 _FINISH: ClassVar[str] = "Finished Timing Optimization : " 

520 

521 

522@export 

523class TechnologyMapping(Section): 

524 """ 

525 *Technology Mapping* section. 

526 

527 Used by Vivado command :class:`~pyEDAA.OutputFilter.Xilinx.Commands.SynthesizeDesign`. 

528 """ 

529 _NAME: ClassVar[str] = "Technology Mapping" 

530 _START: ClassVar[str] = "Start Technology Mapping" 

531 _FINISH: ClassVar[str] = "Finished Technology Mapping : " 

532 

533 

534@export 

535class FlatteningBeforeIOInsertion(SubSection): 

536 """ 

537 *Flattening Before IO Insertion* subsection. 

538 

539 Used by section :class:`IOInsertion`. 

540 """ 

541 _NAME: ClassVar[str] = "Flattening Before IO Insertion" 

542 _START: ClassVar[str] = "Start Flattening Before IO Insertion" 

543 _FINISH: ClassVar[str] = "Finished Flattening Before IO Insertion" 

544 

545 

546@export 

547class FinalNetlistCleanup(SubSection): 

548 """ 

549 *Final Netlist Cleanup* subsection. 

550 

551 Used by section :class:`IOInsertion`. 

552 """ 

553 _NAME: ClassVar[str] = "Final Netlist Cleanup" 

554 _START: ClassVar[str] = "Start Final Netlist Cleanup" 

555 _FINISH: ClassVar[str] = "Finished Final Netlist Cleanup" 

556 

557 

558@export 

559class IOInsertion(SectionWithChildren): 

560 """ 

561 *IO Insertion* section. 

562 

563 Used by Vivado command :class:`~pyEDAA.OutputFilter.Xilinx.Commands.SynthesizeDesign`. 

564 """ 

565 _NAME: ClassVar[str] = "IO Insertion" 

566 _START: ClassVar[str] = "Start IO Insertion" 

567 _FINISH: ClassVar[str] = "Finished IO Insertion : " 

568 

569 # TODO: generalize, use _PARSERS and move to SectionWithChildren 

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

571 line = yield from self._SectionStart(line) 

572 

573 while True: 

574 while True: 

575 if line._kind is LineKind.Empty: 575 ↛ 576line 575 didn't jump to line 576 because the condition on line 575 was never true

576 line = yield line 

577 continue 

578 elif line.StartsWith("----"): 

579 line._kind = LineKind.SubSectionStart | LineKind.SubSectionDelimiter 

580 elif line.StartsWith("Start "): 

581 if line == FlatteningBeforeIOInsertion._START: 

582 self._subsections[FlatteningBeforeIOInsertion] = (subsection := FlatteningBeforeIOInsertion(self)) 

583 line = yield next(parser := subsection.Generator(line)) 

584 break 

585 elif line == FinalNetlistCleanup._START: 585 ↛ 596line 585 didn't jump to line 596 because the condition on line 585 was always true

586 self._subsections[FinalNetlistCleanup] = (subsection := FinalNetlistCleanup(self)) 

587 line = yield next(parser := subsection.Generator(line)) 

588 break 

589 elif isinstance(line, VivadoMessage): 589 ↛ 590line 589 didn't jump to line 590 because the condition on line 589 was never true

590 self._AddMessage(line) 

591 elif line.StartsWith("Finished "): 591 ↛ 594line 591 didn't jump to line 594 because the condition on line 591 was always true

592 break 

593 else: 

594 line._kind |= LineKind.ProcessorError 

595 

596 line = yield line 

597 

598 if line.StartsWith(self._FINISH): 

599 break 

600 

601 while True: 

602 if line.StartsWith(subsection._FINISH): 

603 line = yield parser.send(line) 

604 line = yield parser.send(line) 

605 

606 subsection = None 

607 parser = None 

608 break 

609 

610 line = parser.send(line) 

611 if isinstance(line, VivadoMessage): 611 ↛ 612line 611 didn't jump to line 612 because the condition on line 611 was never true

612 self._AddMessage(line) 

613 

614 line = yield line 

615 

616 nextLine = yield from self._SectionFinish(line, True) 

617 return nextLine 

618 

619 

620@export 

621class RenamingGeneratedInstances(Section): 

622 """ 

623 *Renaming Generated Instances* section. 

624 

625 Used by Vivado command :class:`~pyEDAA.OutputFilter.Xilinx.Commands.SynthesizeDesign`. 

626 """ 

627 _NAME: ClassVar[str] = "Renaming Generated Instances" 

628 _START: ClassVar[str] = "Start Renaming Generated Instances" 

629 _FINISH: ClassVar[str] = "Finished Renaming Generated Instances : " 

630 

631 

632@export 

633class RebuildingUserHierarchy(Section): 

634 """ 

635 *Rebuilding User Hierarchy* section. 

636 

637 Used by Vivado command :class:`~pyEDAA.OutputFilter.Xilinx.Commands.SynthesizeDesign`. 

638 """ 

639 _NAME: ClassVar[str] = "Rebuilding User Hierarchy" 

640 _START: ClassVar[str] = "Start Rebuilding User Hierarchy" 

641 _FINISH: ClassVar[str] = "Finished Rebuilding User Hierarchy : " 

642 

643 

644@export 

645class RenamingGeneratedPorts(Section): 

646 """ 

647 *Renaming Generated Ports* section. 

648 

649 Used by Vivado command :class:`~pyEDAA.OutputFilter.Xilinx.Commands.SynthesizeDesign`. 

650 """ 

651 _NAME: ClassVar[str] = "Renaming Generated Ports" 

652 _START: ClassVar[str] = "Start Renaming Generated Ports" 

653 _FINISH: ClassVar[str] = "Finished Renaming Generated Ports : " 

654 

655 

656@export 

657class RenamingGeneratedNets(Section): 

658 """ 

659 *Renaming Generated Nets* section. 

660 

661 Used by Vivado command :class:`~pyEDAA.OutputFilter.Xilinx.Commands.SynthesizeDesign`. 

662 """ 

663 _NAME: ClassVar[str] = "Renaming Generated Nets" 

664 _START: ClassVar[str] = "Start Renaming Generated Nets" 

665 _FINISH: ClassVar[str] = "Finished Renaming Generated Nets : " 

666 

667 

668@export 

669class WritingSynthesisReport(Section): 

670 """ 

671 *Writing Synthesis Report* section. 

672 

673 Used by Vivado command :class:`~pyEDAA.OutputFilter.Xilinx.Commands.SynthesizeDesign`. 

674 """ 

675 _NAME: ClassVar[str] = "Writing Synthesis Report" 

676 _START: ClassVar[str] = "Start Writing Synthesis Report" 

677 _FINISH: ClassVar[str] = "Finished Writing Synthesis Report : " 

678 

679 _blackboxes: Dict[str, int] #: Blackbox statistics: blackbox name -> count 

680 _cells: Dict[str, int] #: Cell statistics: cell name -> count 

681 

682 def __init__(self, command: "Command") -> None: 

683 super().__init__(command) 

684 

685 self._blackboxes = {} 

686 self._cells = {} 

687 

688 @readonly 

689 def Cells(self) -> Dict[str, int]: 

690 """ 

691 Read-only property to access the dictionary of synthesized cell statistics. 

692 

693 :returns: The dictionary of used cell statistics. 

694 """ 

695 return self._cells 

696 

697 @readonly 

698 def Blackboxes(self) -> Dict[str, int]: 

699 """ 

700 Read-only property to access the dictionary of found blackbox statistics. 

701 

702 :returns: The dictionary of found blackbox statistics. 

703 """ 

704 return self._blackboxes 

705 

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

707 """ 

708 A parser parsing the blackboxes table. 

709 

710 :param line: First line to process. 

711 :returns: A generator to process multiple lines containing a table of blackboxes. 

712 

713 .. rubric:: Example 

714 

715 .. code-block:: 

716 

717 Report BlackBoxes: 

718 +------+----------------------------------+----------+ 

719 | |BlackBox name |Instances | 

720 +------+----------------------------------+----------+ 

721 |1 |name | 1| 

722 |[...] |[...] | [...]| 

723 +------+----------------------------------+----------+ 

724 """ 

725 if line.StartsWith("+-"): 725 ↛ 728line 725 didn't jump to line 728 because the condition on line 725 was always true

726 line._kind = LineKind.TableFrame 

727 else: 

728 line._kind = LineKind.ProcessorError 

729 

730 line = yield line 

731 if line.StartsWith("| "): 731 ↛ 734line 731 didn't jump to line 734 because the condition on line 731 was always true

732 line._kind = LineKind.TableHeader 

733 else: 

734 line._kind = LineKind.ProcessorError 

735 

736 line = yield line 

737 if line.StartsWith("+-"): 737 ↛ 740line 737 didn't jump to line 740 because the condition on line 737 was always true

738 line._kind = LineKind.TableFrame 

739 else: 

740 line._kind = LineKind.ProcessorError 

741 

742 line = yield line 

743 while True: 

744 if line.StartsWith("|"): 

745 line._kind = LineKind.TableRow 

746 

747 columns = line._message.strip("|").split("|") 

748 self._blackboxes[columns[1].strip()] = int(columns[2].strip()) 

749 elif line.StartsWith("+-"): 749 ↛ 753line 749 didn't jump to line 753 because the condition on line 749 was always true

750 line._kind = LineKind.TableFrame 

751 break 

752 else: 

753 line._kind = LineKind.ProcessorError 

754 

755 line = yield line 

756 

757 nextLine = yield line 

758 return nextLine 

759 

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

761 """ 

762 A parser parsing the cell statistic table. 

763 

764 :param line: First line to process. 

765 :returns: A generator to process multiple lines containing a table of cell statistics. 

766 

767 .. rubric:: Example 

768 

769 .. code-block:: 

770 

771 Report Cell Usage: 

772 +------+----------------------------------+------+ 

773 | |Cell |Count | 

774 +------+----------------------------------+------+ 

775 |1 |name | 1| 

776 |[...] |[...] | [...]| 

777 +------+----------------------------------+------+ 

778 """ 

779 if line.StartsWith("+-"): 779 ↛ 782line 779 didn't jump to line 782 because the condition on line 779 was always true

780 line._kind = LineKind.TableFrame 

781 else: 

782 line._kind = LineKind.ProcessorError 

783 

784 line = yield line 

785 if line.StartsWith("| "): 785 ↛ 788line 785 didn't jump to line 788 because the condition on line 785 was always true

786 line._kind = LineKind.TableHeader 

787 else: 

788 line._kind = LineKind.ProcessorError 

789 

790 line = yield line 

791 if line.StartsWith("+-"): 791 ↛ 794line 791 didn't jump to line 794 because the condition on line 791 was always true

792 line._kind = LineKind.TableFrame 

793 else: 

794 line._kind = LineKind.ProcessorError 

795 

796 line = yield line 

797 while True: 

798 if line.StartsWith("|"): 

799 line._kind = LineKind.TableRow 

800 

801 columns = line._message.strip("|").split("|") 

802 self._cells[columns[1].strip()] = int(columns[2].strip()) 

803 elif line.StartsWith("+-"): 803 ↛ 807line 803 didn't jump to line 807 because the condition on line 803 was always true

804 line._kind = LineKind.TableFrame 

805 break 

806 else: 

807 line._kind = LineKind.ProcessorError 

808 

809 line = yield line 

810 

811 nextLine = yield line 

812 return nextLine 

813 

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

815 line = yield from self._SectionStart(line) 

816 

817 while True: 

818 if line._kind is LineKind.Empty: 

819 line = yield line 

820 continue 

821 elif line.StartsWith("Report BlackBoxes:"): 

822 line._kind = LineKind.ParagraphHeadline 

823 line = yield line 

824 line = yield from self._BlackboxesGenerator(line) 

825 elif line.StartsWith("Report Cell Usage:"): 

826 line._kind = LineKind.ParagraphHeadline 

827 line = yield line 

828 line = yield from self._CellGenerator(line) 

829 elif line.StartsWith("----"): 

830 line._kind = LineKind.SectionEnd | LineKind.SectionDelimiter 

831 break 

832 elif isinstance(line, VivadoMessage): 832 ↛ 833line 832 didn't jump to line 833 because the condition on line 832 was never true

833 self._AddMessage(line) 

834 else: 

835 line._kind = LineKind.Verbose 

836 line = yield line 

837 

838 nextLine = yield from self._SectionFinish(line) 

839 return nextLine