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

321 statements  

« prev     ^ index     » next       coverage.py v7.14.3, created at 2026-06-26 23:00 +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, Optional as Nullable 

34 

35from pyTooling.Decorators import export, readonly 

36 

37from pyEDAA.OutputFilter.Xilinx import Section, SubSection, SectionWithChildren 

38from pyEDAA.OutputFilter.Xilinx import VHDLAssertionMessage, VivadoLine, LineKind, VivadoInfoMessage, VHDLReportMessage, VivadoMessage 

39 

40 

41__all__ = ["TIME_MEMORY_PATTERN"] 

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 RTLElaboration(Section): 

48 """ 

49 *RTL Elaboration* section. 

50 

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

52 """ 

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

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

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

56 _DUPLICATES: ClassVar[bool] = False 

57 

58 def Generator(self, line: VivadoLine) -> Generator[VivadoLine, VivadoLine, VivadoLine]: 

59 line = yield from self._SectionStart(line) 

60 

61 while True: 

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

63 line = yield line 

64 continue 

65 elif isinstance(line, VivadoInfoMessage): 

66 if line._toolID == 8: 

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

68 newLine = VHDLAssertionMessage.Convert(line) 

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

70 pass 

71 else: 

72 line = newLine 

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

74 newLine = VHDLReportMessage.Convert(line) 

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

76 pass 

77 else: 

78 line = newLine 

79 

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

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

82 break 

83 elif isinstance(line, VivadoMessage): 

84 self._AddMessage(line) 

85 else: 

86 line._kind = LineKind.Verbose 

87 

88 line = yield line 

89 

90 # line = yield line 

91 nextLine = yield from self._SectionFinish(line) 

92 return nextLine 

93 

94 

95@export 

96class HandlingCustomAttributes(Section): 

97 """ 

98 *Handling Custom Attributes* section. 

99 

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

101 """ 

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

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

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

105 _DUPLICATES: ClassVar[bool] = True 

106 

107 

108@export 

109class ConstraintValidation(Section): 

110 """ 

111 *Constraint Validation* section. 

112 

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

114 """ 

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

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

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

118 _DUPLICATES: ClassVar[bool] = False 

119 

120 

121@export 

122class LoadingPart(Section): 

123 """ 

124 *Loading Part and Timing Information* section. 

125 

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

127 """ 

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

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

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

131 _DUPLICATES: ClassVar[bool] = False 

132 

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

134 

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

136 """ 

137 Initializes the section for loading the device information. 

138 

139 :param command: Reference to the TCL command. 

140 """ 

141 super().__init__(command) 

142 

143 self._part = None 

144 

145 @readonly 

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

147 """ 

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

149 

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

151 """ 

152 return self._part 

153 

154 def Generator(self, line: VivadoLine) -> Generator[VivadoLine, VivadoLine, VivadoLine]: 

155 line = yield from self._SectionStart(line) 

156 

157 while True: 

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

159 line = yield line 

160 continue 

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

162 line._kind = LineKind.Normal 

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

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

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

166 break 

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

168 self._AddMessage(line) 

169 else: 

170 line._kind = LineKind.Verbose 

171 

172 line = yield line 

173 

174 nextLine = yield from self._SectionFinish(line) 

175 return nextLine 

176 

177 

178@export 

179class ApplySetPropertyXDCConstraints(Section): 

180 """ 

181 *Applying 'set_property' XDC Constraints* section. 

182 

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

184 """ 

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

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

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

188 _DUPLICATES: ClassVar[bool] = False 

189 

190 

191@export 

192class RTLComponentStatistics(Section): 

193 """ 

194 *RTL Component Statistics* section. 

195 

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

197 """ 

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

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

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

201 _DUPLICATES: ClassVar[bool] = False 

202 

203 def Generator(self, line: VivadoLine) -> Generator[VivadoLine, VivadoLine, VivadoLine]: 

204 line = yield from self._SectionStart(line) 

205 

206 while True: 

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

208 line = yield line 

209 continue 

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

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

212 break 

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

214 self._AddMessage(line) 

215 else: 

216 line._kind = LineKind.Verbose 

217 

218 line = yield line 

219 

220 nextLine = yield from self._SectionFinish(line) 

221 return nextLine 

222 

223 

224@export 

225class RTLHierarchicalComponentStatistics(Section): 

226 """ 

227 *RTL Hierarchical Component Statistics* section. 

228 

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

230 """ 

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

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

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

234 _DUPLICATES: ClassVar[bool] = False 

235 

236 

237@export 

238class PartResourceSummary(Section): 

239 """ 

240 *Part Resource Summary* section. 

241 

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

243 """ 

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

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

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

247 _DUPLICATES: ClassVar[bool] = False 

248 

249 

250@export 

251class CrossBoundaryAndAreaOptimization(Section): 

252 """ 

253 *Cross Boundary and Area Optimization* section. 

254 

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

256 """ 

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

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

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

260 _DUPLICATES: ClassVar[bool] = False 

261 

262 

263@export 

264class ROM_RAM_DSP_SR_Retiming(Section): 

265 """ 

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

267 

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

269 """ 

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

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

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

273 _DUPLICATES: ClassVar[bool] = True 

274 

275 

276@export 

277class ApplyingXDCTimingConstraints(Section): 

278 """ 

279 *Applying XDC Timing Constraints* section. 

280 

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

282 """ 

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

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

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

286 _DUPLICATES: ClassVar[bool] = False 

287 

288 

289@export 

290class TimingOptimization(Section): 

291 """ 

292 *Timing Optimization* section. 

293 

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

295 """ 

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

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

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

299 _DUPLICATES: ClassVar[bool] = False 

300 

301 

302@export 

303class TechnologyMapping(Section): 

304 """ 

305 *Technology Mapping* section. 

306 

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

308 """ 

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

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

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

312 _DUPLICATES: ClassVar[bool] = False 

313 

314 

315@export 

316class FlatteningBeforeIOInsertion(SubSection): 

317 """ 

318 *Flattening Before IO Insertion* subsection. 

319 

320 Used by section :class:`IOInsertion`. 

321 """ 

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

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

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

325 _DUPLICATES: ClassVar[bool] = False 

326 

327 

328@export 

329class FinalNetlistCleanup(SubSection): 

330 """ 

331 *Final Netlist Cleanup* subsection. 

332 

333 Used by section :class:`IOInsertion`. 

334 """ 

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

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

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

338 _DUPLICATES: ClassVar[bool] = False 

339 

340 

341@export 

342class IOInsertion(SectionWithChildren): 

343 """ 

344 *IO Insertion* section. 

345 

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

347 """ 

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

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

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

351 _DUPLICATES: ClassVar[bool] = False 

352 

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

354 def Generator(self, line: VivadoLine) -> Generator[VivadoLine, VivadoLine, VivadoLine]: 

355 line = yield from self._SectionStart(line) 

356 

357 while True: 

358 while True: 

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

360 line = yield line 

361 continue 

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

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

364 elif line.StartsWith("Start "): 

365 if line == FlatteningBeforeIOInsertion._START: 

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

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

368 break 

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

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

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

372 break 

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

374 self._AddMessage(line) 

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

376 break 

377 else: 

378 line._kind |= LineKind.ProcessorError 

379 

380 line = yield line 

381 

382 if line.StartsWith(self._FINISH): 

383 break 

384 

385 while True: 

386 if line.StartsWith(subsection._FINISH): 

387 line = yield parser.send(line) 

388 line = yield parser.send(line) 

389 

390 subsection = None 

391 parser = None 

392 break 

393 

394 line = parser.send(line) 

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

396 self._AddMessage(line) 

397 

398 line = yield line 

399 

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

401 return nextLine 

402 

403 

404@export 

405class RenamingGeneratedInstances(Section): 

406 """ 

407 *Renaming Generated Instances* section. 

408 

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

410 """ 

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

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

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

414 _DUPLICATES: ClassVar[bool] = False 

415 

416 

417@export 

418class RebuildingUserHierarchy(Section): 

419 """ 

420 *Rebuilding User Hierarchy* section. 

421 

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

423 """ 

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

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

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

427 _DUPLICATES: ClassVar[bool] = False 

428 

429 

430@export 

431class RenamingGeneratedPorts(Section): 

432 """ 

433 *Renaming Generated Ports* section. 

434 

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

436 """ 

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

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

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

440 _DUPLICATES: ClassVar[bool] = False 

441 

442 

443@export 

444class RenamingGeneratedNets(Section): 

445 """ 

446 *Renaming Generated Nets* section. 

447 

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

449 """ 

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

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

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

453 _DUPLICATES: ClassVar[bool] = False 

454 

455 

456@export 

457class WritingSynthesisReport(Section): 

458 """ 

459 *Writing Synthesis Report* section. 

460 

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

462 """ 

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

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

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

466 _DUPLICATES: ClassVar[bool] = False 

467 

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

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

470 

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

472 super().__init__(command) 

473 

474 self._blackboxes = {} 

475 self._cells = {} 

476 

477 @readonly 

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

479 """ 

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

481 

482 :returns: The dictionary of used cell statistics. 

483 """ 

484 return self._cells 

485 

486 @readonly 

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

488 """ 

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

490 

491 :returns: The dictionary of found blackbox statistics. 

492 """ 

493 return self._blackboxes 

494 

495 def _BlackboxesGenerator(self, line: VivadoLine) -> Generator[VivadoLine, VivadoLine, VivadoLine]: 

496 """ 

497 A parser parsing the blackboxes table. 

498 

499 :param line: First line to process. 

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

501 

502 .. rubric:: Example 

503 

504 .. code-block:: 

505 

506 Report BlackBoxes: 

507 +------+----------------------------------+----------+ 

508 | |BlackBox name |Instances | 

509 +------+----------------------------------+----------+ 

510 |1 |name | 1| 

511 |[...] |[...] | [...]| 

512 +------+----------------------------------+----------+ 

513 """ 

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

515 line._kind = LineKind.TableFrame 

516 else: 

517 line._kind = LineKind.ProcessorError 

518 

519 line = yield line 

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

521 line._kind = LineKind.TableHeader 

522 else: 

523 line._kind = LineKind.ProcessorError 

524 

525 line = yield line 

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

527 line._kind = LineKind.TableFrame 

528 else: 

529 line._kind = LineKind.ProcessorError 

530 

531 line = yield line 

532 while True: 

533 if line.StartsWith("|"): 

534 line._kind = LineKind.TableRow 

535 

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

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

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

539 line._kind = LineKind.TableFrame 

540 break 

541 else: 

542 line._kind = LineKind.ProcessorError 

543 

544 line = yield line 

545 

546 nextLine = yield line 

547 return nextLine 

548 

549 def _CellGenerator(self, line: VivadoLine) -> Generator[VivadoLine, VivadoLine, VivadoLine]: 

550 """ 

551 A parser parsing the cell statistic table. 

552 

553 :param line: First line to process. 

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

555 

556 .. rubric:: Example 

557 

558 .. code-block:: 

559 

560 Report Cell Usage: 

561 +------+----------------------------------+------+ 

562 | |Cell |Count | 

563 +------+----------------------------------+------+ 

564 |1 |name | 1| 

565 |[...] |[...] | [...]| 

566 +------+----------------------------------+------+ 

567 """ 

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

569 line._kind = LineKind.TableFrame 

570 else: 

571 line._kind = LineKind.ProcessorError 

572 

573 line = yield line 

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

575 line._kind = LineKind.TableHeader 

576 else: 

577 line._kind = LineKind.ProcessorError 

578 

579 line = yield line 

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

581 line._kind = LineKind.TableFrame 

582 else: 

583 line._kind = LineKind.ProcessorError 

584 

585 line = yield line 

586 while True: 

587 if line.StartsWith("|"): 

588 line._kind = LineKind.TableRow 

589 

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

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

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

593 line._kind = LineKind.TableFrame 

594 break 

595 else: 

596 line._kind = LineKind.ProcessorError 

597 

598 line = yield line 

599 

600 nextLine = yield line 

601 return nextLine 

602 

603 def Generator(self, line: VivadoLine) -> Generator[VivadoLine, VivadoLine, VivadoLine]: 

604 line = yield from self._SectionStart(line) 

605 

606 while True: 

607 if line._kind is LineKind.Empty: 

608 line = yield line 

609 continue 

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

611 line._kind = LineKind.ParagraphHeadline 

612 line = yield line 

613 line = yield from self._BlackboxesGenerator(line) 

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

615 line._kind = LineKind.ParagraphHeadline 

616 line = yield line 

617 line = yield from self._CellGenerator(line) 

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

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

620 break 

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

622 self._AddMessage(line) 

623 else: 

624 line._kind = LineKind.Verbose 

625 line = yield line 

626 

627 nextLine = yield from self._SectionFinish(line) 

628 return nextLine