Coverage for pyEDAA/OutputFilter/Xilinx/PlaceDesign.py: 89%

482 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, Dict, Tuple 

33 

34from pyTooling.Decorators import export 

35 

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

37from pyEDAA.OutputFilter.Xilinx.Common2 import Task, Phase, SubPhase, SubSubPhase, SubSubSubPhase 

38 

39 

40@export 

41class Phase11_PlacerInitializationNetlistSorting(SubPhase): 

42 _START: ClassVar[str] = "Phase 1.1 Placer Initialization Netlist Sorting" 

43 _FINISH: ClassVar[str] = "Phase 1.1 Placer Initialization Netlist Sorting | Checksum:" 

44 _TIME: ClassVar[str] = "Time (s):" 

45 

46 

47@export 

48class Phase12_IOPlacement_ClockPlacement_BuildPlacerDevice(SubPhase): 

49 _START: ClassVar[str] = "Phase 1.2 IO Placement/ Clock Placement/ Build Placer Device" 

50 _FINISH: ClassVar[str] = "Phase 1.2 IO Placement/ Clock Placement/ Build Placer Device | Checksum:" 

51 _TIME: ClassVar[str] = "Time (s):" 

52 

53 

54@export 

55class Phase13_BuildPlacerNetlistModel(SubPhase): 

56 _START: ClassVar[str] = "Phase 1.3 Build Placer Netlist Model" 

57 _FINISH: ClassVar[str] = "Phase 1.3 Build Placer Netlist Model | Checksum:" 

58 _TIME: ClassVar[str] = "Time (s):" 

59 

60 

61@export 

62class Phase14_ConstrainClocks_Macros(SubPhase): 

63 _START: ClassVar[str] = "Phase 1.4 Constrain Clocks/Macros" 

64 _FINISH: ClassVar[str] = "Phase 1.4 Constrain Clocks/Macros | Checksum:" 

65 _TIME: ClassVar[str] = "Time (s):" 

66 

67 

68@export 

69class Phase1_PlacerInitialization(Phase): 

70 _START: ClassVar[str] = "Phase 1 Placer Initialization" 

71 _FINISH: ClassVar[str] = "Phase 1 Placer Initialization | Checksum:" 

72 _TIME: ClassVar[str] = "Time (s):" 

73 _FINAL: ClassVar[str] = None 

74 

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

76 Phase11_PlacerInitializationNetlistSorting, 

77 Phase12_IOPlacement_ClockPlacement_BuildPlacerDevice, 

78 Phase13_BuildPlacerNetlistModel, 

79 Phase14_ConstrainClocks_Macros 

80 ) 

81 

82 _subphases: Dict[Type[SubPhase], SubPhase] 

83 

84 def __init__(self, phase: Phase): 

85 super().__init__(phase) 

86 

87 self._subphases = {p: p(self) for p in self._PARSERS} 

88 

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

90 line = yield from self._PhaseStart(line) 

91 

92 activeParsers: List[Phase] = list(self._subphases.values()) 

93 

94 while True: 

95 while True: 

96 if line._kind is LineKind.Empty: 

97 line = yield line 

98 continue 

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

100 self._AddMessage(line) 

101 elif line.StartsWith("Phase 1."): 

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

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

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

105 break 

106 else: 

107 raise Exception(f"Unknown subphase: {line!r}") 

108 break 

109 elif line.StartsWith(self._FINISH): 

110 nextLine = yield from self._PhaseFinish(line) 

111 return nextLine 

112 

113 line = yield line 

114 

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

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

117 # line = yield task.send(line) 

118 # break 

119 

120 if isinstance(line, VivadoMessage): 

121 self._AddMessage(line) 

122 

123 try: 

124 line = yield phase.send(line) 

125 except StopIteration as ex: 

126 activeParsers.remove(parser) 

127 line = ex.value 

128 break 

129 

130 

131@export 

132class Phase21_Floorplanning(SubPhase): 

133 _START: ClassVar[str] = "Phase 2.1 Floorplanning" 

134 _FINISH: ClassVar[str] = "Phase 2.1 Floorplanning | Checksum:" 

135 _TIME: ClassVar[str] = "Time (s):" 

136 

137 

138@export 

139class Phase22_UpdateTimingBeforeSLRPathOpt(SubPhase): 

140 _START: ClassVar[str] = "Phase 2.2 Update Timing before SLR Path Opt" 

141 _FINISH: ClassVar[str] = "Phase 2.2 Update Timing before SLR Path Opt | Checksum:" 

142 _TIME: ClassVar[str] = "Time (s):" 

143 

144 

145@export 

146class Phase23_PostProcessingInFloorplanning(SubPhase): 

147 _START: ClassVar[str] = "Phase 2.3 Post-Processing in Floorplanning" 

148 _FINISH: ClassVar[str] = "Phase 2.3 Post-Processing in Floorplanning | Checksum:" 

149 _TIME: ClassVar[str] = "Time (s):" 

150 

151 

152@export 

153class Phase24_GlobalPlacePhase1(SubPhase): 

154 _START: ClassVar[str] = "Phase 2.4 Global Place Phase1" 

155 _FINISH: ClassVar[str] = "Phase 2.4 Global Place Phase1 | Checksum:" 

156 _TIME: ClassVar[str] = "Time (s):" 

157 

158 

159@export 

160class Phase251_UpdateTimingBeforePhysicalSynthesis(SubSubPhase): 

161 _START: ClassVar[str] = "Phase 2.5.1 UpdateTiming Before Physical Synthesis" 

162 _FINISH: ClassVar[str] = "Phase 2.5.1 UpdateTiming Before Physical Synthesis | Checksum:" 

163 _TIME: ClassVar[str] = "Time (s):" 

164 

165 

166@export 

167class Phase252_PhysicalSynthesisInPlacer(SubSubPhase): 

168 _START: ClassVar[str] = "Phase 2.5.2 Physical Synthesis In Placer" 

169 _FINISH: ClassVar[str] = "Phase 2.5.2 Physical Synthesis In Placer | Checksum:" 

170 _TIME: ClassVar[str] = "Time (s):" 

171 

172 

173@export 

174class Phase25_GlobalPlacePhase2(SubPhase): 

175 _START: ClassVar[str] = "Phase 2.5 Global Place Phase2" 

176 _FINISH: ClassVar[str] = "Phase 2.5 Global Place Phase2 | Checksum:" 

177 _TIME: ClassVar[str] = "Time (s):" 

178 

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

180 Phase251_UpdateTimingBeforePhysicalSynthesis, 

181 Phase252_PhysicalSynthesisInPlacer 

182 ) 

183 

184 _subsubphases: Dict[Type[SubSubPhase], SubSubPhase] 

185 

186 def __init__(self, subphase: SubPhase): 

187 super().__init__(subphase) 

188 

189 self._subsubphases = {p: p(self) for p in self._PARSERS} 

190 

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

192 line = yield from self._SubPhaseStart(line) 

193 

194 activeParsers: List[Phase] = list(self._subsubphases.values()) 

195 

196 while True: 

197 while True: 

198 if line._kind is LineKind.Empty: 

199 line = yield line 

200 continue 

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

202 self._AddMessage(line) 

203 elif line.StartsWith("Phase 2.5."): 

204 for parser in activeParsers: # type: SubSubPhase 204 ↛ 209line 204 didn't jump to line 209 because the loop on line 204 didn't complete

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

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

207 break 

208 else: 

209 raise Exception(f"Unknown subsubphase: {line!r}") 

210 break 

211 elif line.StartsWith(self._FINISH): 211 ↛ 215line 211 didn't jump to line 215 because the condition on line 211 was always true

212 nextLine = yield from self._SubPhaseFinish(line) 

213 return nextLine 

214 

215 line = yield line 

216 

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

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

219 # line = yield task.send(line) 

220 # break 

221 

222 if isinstance(line, VivadoMessage): 

223 self._AddMessage(line) 

224 

225 try: 

226 line = yield phase.send(line) 

227 except StopIteration as ex: 

228 activeParsers.remove(parser) 

229 line = ex.value 

230 break 

231 

232 

233@export 

234class Phase2_GlobalPlacement(Phase): 

235 _START: ClassVar[str] = "Phase 2 Global Placement" 

236 _FINISH: ClassVar[str] = "Phase 2 Global Placement | Checksum:" 

237 _TIME: ClassVar[str] = "Time (s):" 

238 _FINAL: ClassVar[str] = None 

239 

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

241 Phase21_Floorplanning, 

242 Phase22_UpdateTimingBeforeSLRPathOpt, 

243 Phase23_PostProcessingInFloorplanning, 

244 Phase24_GlobalPlacePhase1, 

245 Phase25_GlobalPlacePhase2 

246 ) 

247 

248 _subphases: Dict[Type[SubPhase], SubPhase] 

249 

250 def __init__(self, phase: Phase): 

251 super().__init__(phase) 

252 

253 self._subphases = {p: p(self) for p in self._PARSERS} 

254 

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

256 line = yield from self._PhaseStart(line) 

257 

258 activeParsers: List[Phase] = list(self._subphases.values()) 

259 

260 while True: 

261 while True: 

262 if line._kind is LineKind.Empty: 

263 line = yield line 

264 continue 

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

266 self._AddMessage(line) 

267 elif line.StartsWith("Phase 2."): 

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

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

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

271 break 

272 else: 

273 raise Exception(f"Unknown subphase: {line!r}") 

274 break 

275 elif line.StartsWith(self._FINISH): 275 ↛ 279line 275 didn't jump to line 279 because the condition on line 275 was always true

276 nextLine = yield from self._PhaseFinish(line) 

277 return nextLine 

278 

279 line = yield line 

280 

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

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

283 # line = yield task.send(line) 

284 # break 

285 

286 if isinstance(line, VivadoMessage): 

287 self._AddMessage(line) 

288 

289 try: 

290 line = yield phase.send(line) 

291 except StopIteration as ex: 

292 activeParsers.remove(parser) 

293 line = ex.value 

294 break 

295 

296 

297@export 

298class Phase31_CommitMultiColumnMacros(SubPhase): 

299 _START: ClassVar[str] = "Phase 3.1 Commit Multi Column Macros" 

300 _FINISH: ClassVar[str] = "Phase 3.1 Commit Multi Column Macros | Checksum:" 

301 _TIME: ClassVar[str] = "Time (s):" 

302 

303 

304@export 

305class Phase32_CommitMostMacrosLUTRAMs(SubPhase): 

306 _START: ClassVar[str] = "Phase 3.2 Commit Most Macros & LUTRAMs" 

307 _FINISH: ClassVar[str] = "Phase 3.2 Commit Most Macros & LUTRAMs | Checksum:" 

308 _TIME: ClassVar[str] = "Time (s):" 

309 

310 

311@export 

312class Phase33_AreaSwapOptimization(SubPhase): 

313 _START: ClassVar[str] = "Phase 3.3 Area Swap Optimization" 

314 _FINISH: ClassVar[str] = "Phase 3.3 Area Swap Optimization | Checksum:" 

315 _TIME: ClassVar[str] = "Time (s):" 

316 

317 

318@export 

319class Phase34_PipelineRegisterOptimization(SubPhase): 

320 _START: ClassVar[str] = "Phase 3.4 Pipeline Register Optimization" 

321 _FINISH: ClassVar[str] = "Phase 3.4 Pipeline Register Optimization | Checksum:" 

322 _TIME: ClassVar[str] = "Time (s):" 

323 

324 

325@export 

326class Phase35_FastOptimization(SubPhase): 

327 _START: ClassVar[str] = "Phase 3.5 Fast Optimization" 

328 _FINISH: ClassVar[str] = "Phase 3.5 Fast Optimization | Checksum:" 

329 _TIME: ClassVar[str] = "Time (s):" 

330 

331 

332@export 

333class Phase36_SmallShapeDetailPlacement(SubPhase): 

334 _START: ClassVar[str] = "Phase 3.6 Small Shape Detail Placement" 

335 _FINISH: ClassVar[str] = "Phase 3.6 Small Shape Detail Placement | Checksum:" 

336 _TIME: ClassVar[str] = "Time (s):" 

337 

338 

339@export 

340class Phase37_ReassignLUTPins(SubPhase): 

341 _START: ClassVar[str] = "Phase 3.7 Re-assign LUT pins" 

342 _FINISH: ClassVar[str] = "Phase 3.7 Re-assign LUT pins | Checksum:" 

343 _TIME: ClassVar[str] = "Time (s):" 

344 

345 

346@export 

347class Phase38_PipelineRegisterOptimization(SubPhase): 

348 _START: ClassVar[str] = "Phase 3.8 Pipeline Register Optimization" 

349 _FINISH: ClassVar[str] = "Phase 3.8 Pipeline Register Optimization | Checksum:" 

350 _TIME: ClassVar[str] = "Time (s):" 

351 

352 

353@export 

354class Phase39_FastOptimization(SubPhase): 

355 _START: ClassVar[str] = "Phase 3.9 Fast Optimization" 

356 _FINISH: ClassVar[str] = "Phase 3.9 Fast Optimization | Checksum:" 

357 _TIME: ClassVar[str] = "Time (s):" 

358 

359 

360@export 

361class Phase3_DetailPlacement(Phase): 

362 _START: ClassVar[str] = "Phase 3 Detail Placement" 

363 _FINISH: ClassVar[str] = "Phase 3 Detail Placement | Checksum:" 

364 _TIME: ClassVar[str] = "Time (s):" 

365 _FINAL: ClassVar[str] = None 

366 

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

368 Phase31_CommitMultiColumnMacros, 

369 Phase32_CommitMostMacrosLUTRAMs, 

370 Phase33_AreaSwapOptimization, 

371 Phase34_PipelineRegisterOptimization, 

372 Phase35_FastOptimization, 

373 Phase36_SmallShapeDetailPlacement, 

374 Phase37_ReassignLUTPins, 

375 Phase38_PipelineRegisterOptimization, 

376 Phase39_FastOptimization 

377 ) 

378 

379 _subphases: Dict[Type[SubPhase], SubPhase] 

380 

381 def __init__(self, phase: Phase): 

382 super().__init__(phase) 

383 

384 self._subphases = {p: p(self) for p in self._PARSERS} 

385 

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

387 line = yield from self._PhaseStart(line) 

388 

389 activeParsers: List[Phase] = list(self._subphases.values()) 

390 

391 while True: 

392 while True: 

393 if line._kind is LineKind.Empty: 

394 line = yield line 

395 continue 

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

397 self._AddMessage(line) 

398 elif line.StartsWith("Phase 3."): 

399 for parser in activeParsers: # type: Section 399 ↛ 404line 399 didn't jump to line 404 because the loop on line 399 didn't complete

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

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

402 break 

403 else: 

404 raise Exception(f"Unknown subphase: {line!r}") 

405 break 

406 elif line.StartsWith(self._FINISH): 406 ↛ 410line 406 didn't jump to line 410 because the condition on line 406 was always true

407 nextLine = yield from self._PhaseFinish(line) 

408 return nextLine 

409 

410 line = yield line 

411 

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

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

414 # line = yield task.send(line) 

415 # break 

416 

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

418 self._AddMessage(line) 

419 

420 try: 

421 line = yield phase.send(line) 

422 except StopIteration as ex: 

423 activeParsers.remove(parser) 

424 line = ex.value 

425 break 

426 

427 

428@export 

429class Phase4111_BUFGInsertion(SubSubSubPhase): 

430 _START: ClassVar[str] = "Phase 4.1.1.1 BUFG Insertion" 

431 _FINISH: ClassVar[str] = "Phase 4.1.1.1 BUFG Insertion | Checksum:" 

432 _TIME: ClassVar[str] = "Time (s):" 

433 

434 

435@export 

436class Phase4112_PostPlacementTimingOptimization(SubSubSubPhase): 

437 _START: ClassVar[str] = "Phase 4.1.1.2 Post Placement Timing Optimization" 

438 _FINISH: ClassVar[str] = "Phase 4.1.1.2 Post Placement Timing Optimization | Checksum:" 

439 _TIME: ClassVar[str] = "Time (s):" 

440 

441 

442@export 

443class Phase411_PostPlacementOptimization(SubSubPhase): 

444 _START: ClassVar[str] = "Phase 4.1.1 Post Placement Optimization" 

445 _FINISH: ClassVar[str] = None # Phase 4.1.1 Post Placement Optimization | Checksum:" 

446 _TIME: ClassVar[str] = "Time (s):" 

447 

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

449 Phase4111_BUFGInsertion, 

450 Phase4112_PostPlacementTimingOptimization 

451 ) 

452 

453 _subsubsubphases: Dict[Type[SubSubSubPhase], SubSubSubPhase] 

454 

455 def __init__(self, subsubphase: SubSubPhase): 

456 super().__init__(subsubphase) 

457 

458 self._subsubsubphases = {p: p(self) for p in self._PARSERS} 

459 

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

461 line = yield from self._SubSubPhaseStart(line) 

462 

463 activeParsers: List[Phase] = list(self._subsubsubphases.values()) 

464 

465 while True: 

466 while True: 

467 if line._kind is LineKind.Empty: 

468 line = yield line 

469 continue 

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

471 self._AddMessage(line) 

472 elif line.StartsWith("Phase 4.1.1."): 

473 for parser in activeParsers: # type: SubSubSubPhase 473 ↛ 478line 473 didn't jump to line 478 because the loop on line 473 didn't complete

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

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

476 break 

477 else: 

478 raise Exception(f"Unknown subsubsubphase: {line!r}") 

479 break 

480 elif line.StartsWith(self._TIME): 

481 line._kind = LineKind.SubSubPhaseTime 

482 nextLine = yield line 

483 return nextLine 

484 

485 line = yield line 

486 

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

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

489 # line = yield task.send(line) 

490 # break 

491 

492 if isinstance(line, VivadoMessage): 

493 self._AddMessage(line) 

494 

495 try: 

496 line = yield phase.send(line) 

497 except StopIteration as ex: 

498 activeParsers.remove(parser) 

499 line = ex.value 

500 break 

501 

502 

503@export 

504class Phase41_PostCommitOptimization(SubPhase): 

505 _START: ClassVar[str] = "Phase 4.1 Post Commit Optimization" 

506 _FINISH: ClassVar[str] = "Phase 4.1 Post Commit Optimization | Checksum:" 

507 _TIME: ClassVar[str] = "Time (s):" 

508 

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

510 Phase411_PostPlacementOptimization, 

511 ) 

512 

513 _subsubphases: Dict[Type[SubSubPhase], SubSubPhase] 

514 

515 def __init__(self, subphase: SubPhase): 

516 super().__init__(subphase) 

517 

518 self._subsubphases = {p: p(self) for p in self._PARSERS} 

519 

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

521 line = yield from self._SubPhaseStart(line) 

522 

523 activeParsers: List[Phase] = list(self._subsubphases.values()) 

524 

525 while True: 

526 while True: 

527 if line._kind is LineKind.Empty: 

528 line = yield line 

529 continue 

530 elif isinstance(line, VivadoMessage): 

531 self._AddMessage(line) 

532 elif line.StartsWith("Phase 4.1."): 

533 for parser in activeParsers: # type: SubSubPhase 533 ↛ 538line 533 didn't jump to line 538 because the loop on line 533 didn't complete

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

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

536 break 

537 else: 

538 raise Exception(f"Unknown subsubphase: {line!r}") 

539 break 

540 elif line.StartsWith(self._FINISH): 540 ↛ 544line 540 didn't jump to line 544 because the condition on line 540 was always true

541 nextLine = yield from self._SubPhaseFinish(line) 

542 return nextLine 

543 

544 line = yield line 

545 

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

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

548 # line = yield task.send(line) 

549 # break 

550 

551 if isinstance(line, VivadoMessage): 

552 self._AddMessage(line) 

553 

554 try: 

555 line = yield phase.send(line) 

556 except StopIteration as ex: 

557 activeParsers.remove(parser) 

558 line = ex.value 

559 break 

560 

561 

562@export 

563class Phase42_PostPlacementCleanup(SubPhase): 

564 _START: ClassVar[str] = "Phase 4.2 Post Placement Cleanup" 

565 _FINISH: ClassVar[str] = "Phase 4.2 Post Placement Cleanup | Checksum:" 

566 _TIME: ClassVar[str] = "Time (s):" 

567 

568 

569@export 

570class Phase431_PrintEstimatedCongestion(SubSubPhase): 

571 _START: ClassVar[str] = "Phase 4.3.1 Print Estimated Congestion" 

572 _FINISH: ClassVar[str] = "Phase 4.3.1 Print Estimated Congestion | Checksum:" 

573 _TIME: ClassVar[str] = "Time (s):" 

574 

575 

576@export 

577class Phase43_PlacerReporting(SubPhase): 

578 _START: ClassVar[str] = "Phase 4.3 Placer Reporting" 

579 _FINISH: ClassVar[str] = "Phase 4.3 Placer Reporting | Checksum:" 

580 _TIME: ClassVar[str] = "Time (s):" 

581 

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

583 Phase431_PrintEstimatedCongestion, 

584 ) 

585 

586 _subsubphases: Dict[Type[SubSubPhase], SubSubPhase] 

587 

588 def __init__(self, subphase: SubPhase): 

589 super().__init__(subphase) 

590 

591 self._subsubphases = {p: p(self) for p in self._PARSERS} 

592 

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

594 line = yield from self._SubPhaseStart(line) 

595 

596 activeParsers: List[Phase] = list(self._subsubphases.values()) 

597 

598 while True: 

599 while True: 

600 if line._kind is LineKind.Empty: 

601 line = yield line 

602 continue 

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

604 self._AddMessage(line) 

605 elif line.StartsWith("Phase 4.3."): 

606 for parser in activeParsers: # type: SubSubPhase 606 ↛ 611line 606 didn't jump to line 611 because the loop on line 606 didn't complete

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

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

609 break 

610 else: 

611 raise Exception(f"Unknown subsubphase: {line!r}") 

612 break 

613 elif line.StartsWith(self._FINISH): 613 ↛ 617line 613 didn't jump to line 617 because the condition on line 613 was always true

614 nextLine = yield from self._SubPhaseFinish(line) 

615 return nextLine 

616 

617 line = yield line 

618 

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

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

621 # line = yield task.send(line) 

622 # break 

623 

624 if isinstance(line, VivadoMessage): 

625 self._AddMessage(line) 

626 

627 try: 

628 line = yield phase.send(line) 

629 except StopIteration as ex: 

630 activeParsers.remove(parser) 

631 line = ex.value 

632 break 

633 

634 

635@export 

636class Phase44_FinalPlacementCleanup(SubPhase): 

637 _START: ClassVar[str] = "Phase 4.4 Final Placement Cleanup" 

638 _FINISH: ClassVar[str] = "Time (s):" 

639 _TIME: ClassVar[str] = None 

640 

641 

642@export 

643class Phase4_PostPlacementOptimizationAndCleanUp(Phase): 

644 _START: ClassVar[str] = "Phase 4 Post Placement Optimization and Clean-Up" 

645 _FINISH: ClassVar[str] = "Phase 4 Post Placement Optimization and Clean-Up | Checksum:" 

646 _TIME: ClassVar[str] = "Time (s):" 

647 _FINAL: ClassVar[str] = None 

648 

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

650 Phase41_PostCommitOptimization, 

651 Phase42_PostPlacementCleanup, 

652 Phase43_PlacerReporting, 

653 Phase44_FinalPlacementCleanup 

654 ) 

655 

656 _subphases: Dict[Type[SubPhase], SubPhase] 

657 

658 def __init__(self, phase: Phase): 

659 super().__init__(phase) 

660 

661 self._subphases = {p: p(self) for p in self._PARSERS} 

662 

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

664 line = yield from self._PhaseStart(line) 

665 

666 activeParsers: List[Phase] = list(self._subphases.values()) 

667 

668 while True: 

669 while True: 

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

671 self._AddMessage(line) 

672 elif line.StartsWith("Phase 4."): 

673 for parser in activeParsers: # type: Section 673 ↛ 678line 673 didn't jump to line 678 because the loop on line 673 didn't complete

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

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

676 break 

677 else: 

678 raise Exception(f"Unknown subphase: {line!r}") 

679 break 

680 elif line.StartsWith(self._FINISH): 

681 nextLine = yield from self._PhaseFinish(line) 

682 return nextLine 

683 

684 line = yield line 

685 

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

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

688 # line = yield task.send(line) 

689 # break 

690 

691 if isinstance(line, VivadoMessage): 

692 self._AddMessage(line) 

693 

694 try: 

695 line = yield phase.send(line) 

696 except StopIteration as ex: 

697 activeParsers.remove(parser) 

698 line = ex.value 

699 break 

700 

701 

702@export 

703class PlacerTask(Task): 

704 _START: ClassVar[str] = "Starting Placer Task" 

705 _FINISH: ClassVar[str] = "Ending Placer Task" 

706 

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

708 Phase1_PlacerInitialization, 

709 Phase2_GlobalPlacement, 

710 Phase3_DetailPlacement, 

711 Phase4_PostPlacementOptimizationAndCleanUp 

712 ) 

713 

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

715 line = yield from self._TaskStart(line) 

716 

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

718 

719 while True: 

720 while True: 

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

722 self._AddMessage(line) 

723 elif line.StartsWith("Phase "): 

724 for parser in activeParsers: # type: Section 724 ↛ 729line 724 didn't jump to line 729 because the loop on line 724 didn't complete

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

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

727 break 

728 else: 

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

730 break 

731 elif line.StartsWith("Ending"): 

732 nextLine = yield from self._TaskFinish(line) 

733 return nextLine 

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

735 line._kind = LineKind.TaskTime 

736 nextLine = yield line 

737 return nextLine 

738 

739 line = yield line 

740 

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

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

743 # line = yield task.send(line) 

744 # break 

745 

746 if isinstance(line, VivadoMessage): 

747 self._AddMessage(line) 

748 

749 try: 

750 line = yield phase.send(line) 

751 except StopIteration as ex: 

752 activeParsers.remove(parser) 

753 line = ex.value 

754 break