Coverage for pyEDAA / OSVVM / Project / Procedures.py: 88%

204 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-03-13 22:31 +0000

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

2# _____ ____ _ _ ___ ______ ____ ____ __ # 

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

4# | '_ \| | | | _| | | | |/ _ \ / _ \ | | | \___ \\ \ / / \ \ / /| |\/| | # 

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

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

7# |_| |___/ # 

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

9# Authors: # 

10# Patrick Lehmann # 

11# # 

12# License: # 

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

14# Copyright 2025-2026 Patrick Lehmann - Boetzingen, Germany # 

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""" 

32This module implements OSVVM's TCL procedures (used in OSVVM's ``*.pro`` files) as Python functions. 

33 

34These functions are then registered at the :class:`TCL processor <pyEDAA.OSVVM.Project.TCL.OsvvmProFileProcessor>`, so 

35procedure calls within TCL code get "redirected" to these Python functions. Each Python function has access to a global 

36variable :data:`~pyEDAA.OSVVM.Project.osvvmContext` to preserve its state or modify the context. 

37 

38.. important:: 

39 

40 For passing Python exceptions through the TCL layer back into Python, every function in the module MUST follow the 

41 following scheme: 

42 

43 .. code-block:: Python 

44 

45 def myTclProcedure(....) -> ...: 

46 try: 

47 # do something 

48 

49 except OSVVMException as ex: # pragma: no cover 

50 raise ex 

51 except Exception as ex: # pragma: no cover 

52 osvvmContext.RaiseException(ex) 

53""" 

54from pathlib import Path 

55from typing import Optional as Nullable 

56 

57from pyTooling.Decorators import export 

58from pyTooling.Common import getFullyQualifiedName 

59from pyVHDLModel import VHDLVersion 

60 

61from pyEDAA.OSVVM import OSVVMException 

62from pyEDAA.OSVVM.Project import osvvmContext, VHDLSourceFile, GenericValue, ConstraintFile as OSVVM_ConstraintFile 

63from pyEDAA.OSVVM.Project import XDCConstraintFile, ScopeToRef as OSVVM_ScopeToRef, ScopeToCell as OSVVM_ScopeToCell 

64from pyEDAA.OSVVM.Project import BuildName as OSVVM_BuildName, NoNullRangeWarning as OSVVM_NoNullRangeWarning 

65 

66 

67@export 

68def BuildName(name: str) -> int: 

69 """ 

70 This function implements the behavior of OSVVM's ``BuildName`` procedure. 

71 

72 Create and register a :class:`~pyEDAA.OSVVM.Project.BuildName` option and return the options unique ID. 

73 

74 :param name: Name of the build. 

75 :returns: The option's unique ID. 

76 """ 

77 try: 

78 buildName = OSVVM_BuildName(name) 

79 return osvvmContext.AddOption(buildName) 

80 except OSVVMException as ex: # pragma: no cover 

81 raise ex 

82 except Exception as ex: # pragma: no cover 

83 osvvmContext.RaiseException(ex) 

84 

85 

86@export 

87def build(file: str, *options: int) -> None: 

88 """ 

89 This function implements the behavior of OSVVM's ``build`` procedure. 

90 

91 The current directory of the currently active context is preserved while the referenced ``*.pro`` file is processed. 

92 After processing that file, the context's current directory is restored. 

93 

94 The referenced file gets appended to a list of included files maintained by the context. 

95 

96 .. rubric:: pro-file discovery algorithm: 

97 

98 1. If the path explicitly references a ``*.pro`` file, this file is used. 

99 2. If the path references a directory, it checks implicitly for a ``build.pro`` file, otherwise 

100 3. it checks implicitly for a ``<path>.pro`` file, named like the directories name. 

101 

102 .. rubric:: inferring the build name: 

103 

104 1. The option :class:`~pyEDAA.OSVVM.Project.BuildName` was gives (indirectly via option ID) as parameter. 

105 2. It's derived from the current directory name. 

106 

107 :param file: Explicit path to a ``*.pro`` file or a directory containing an implicitly searched ``*.pro`` 

108 file. 

109 :param options: Optional, list of option IDs. 

110 :raises OSVVMException: If parameter 'options' contains unknown option IDS. 

111 :raises OSVVMException: If parameter 'options' contains an option not of type :class:`~pyEDAA.OSVVM.Project.BuildName`. 

112 

113 .. seealso:: 

114 

115 * :func:`BuildName` 

116 * :func:`include` 

117 * :func:`ChangeWorkingDirectory` 

118 """ 

119 try: 

120 file = Path(file) 

121 buildName = None 

122 

123 # Preserve current directory 

124 currentDirectory = osvvmContext._currentDirectory 

125 

126 for optionID in options: 

127 try: 

128 option = osvvmContext._options[int(optionID)] 

129 except KeyError as e: # pragma: no cover 

130 ex = OSVVMException(f"Option {optionID} not found in option dictionary.") 

131 ex.__cause__ = e 

132 osvvmContext.RaiseException(ex) 

133 

134 if isinstance(option, OSVVM_BuildName): 

135 buildName = option.Name 

136 else: # pragma: no cover 

137 ex = OSVVMException(f"Option {optionID} is not a BuildName.") 

138 ex.__cause__ = TypeError() 

139 osvvmContext.LastException = ex 

140 raise ex 

141 

142 # If no build name was specified, derive a name from *.pro file. 

143 if buildName is None: 

144 buildName = file.stem 

145 

146 osvvmContext.BeginBuild(buildName) 

147 includeFile = osvvmContext.IncludeFile(file) 

148 osvvmContext.EvaluateFile(includeFile) 

149 osvvmContext.EndBuild() 

150 

151 # Restore current directory after recursively evaluating *.pro files. 

152 osvvmContext._currentDirectory = currentDirectory 

153 

154 except OSVVMException as ex: # pragma: no cover 

155 raise ex 

156 except Exception as ex: # pragma: no cover 

157 osvvmContext.RaiseException(ex) 

158 

159 

160@export 

161def include(file: str) -> None: 

162 """ 

163 This function implements the behavior of OSVVM's ``include`` procedure. 

164 

165 The current directory of the currently active context is preserved while the referenced ``*.pro`` file is processed. 

166 After processing that file, the context's current directory is restored. 

167 

168 The referenced file gets appended to a list of included files maintained by the context. 

169 

170 .. rubric:: pro-file discovery algorithm: 

171 

172 1. If the path explicitly references a ``*.pro`` file, this file is used. 

173 2. If the path references a directory, it checks implicitly for a ``build.pro`` file, otherwise 

174 3. it checks implicitly for a ``<path>.pro`` file, named like the directories name. 

175 

176 :param file: Explicit path to a ``*.pro`` file or a directory containing an implicitly searched ``*.pro`` 

177 file. 

178 

179 .. seealso:: 

180 

181 * :func:`build` 

182 * :func:`ChangeWorkingDirectory` 

183 """ 

184 try: 

185 # Preserve current directory 

186 currentDirectory = osvvmContext._currentDirectory 

187 

188 includeFile = osvvmContext.IncludeFile(Path(file)) 

189 osvvmContext.EvaluateFile(includeFile) 

190 

191 # Restore current directory after recursively evaluating *.pro files. 

192 osvvmContext._currentDirectory = currentDirectory 

193 

194 except OSVVMException as ex: # pragma: no cover 

195 raise ex 

196 except Exception as ex: # pragma: no cover 

197 osvvmContext.RaiseException(ex) 

198 

199 

200@export 

201def library(libraryName: str, libraryPath: Nullable[str] = None) -> None: 

202 """ 

203 This function implements the behavior of OSVVM's ``library`` procedure. 

204 

205 It sets the currently active VHDL library to the specified VHDL library. If no VHDL library with that name exist, a 

206 new VHDL library is created and set as active VHDL library. 

207 

208 .. hint:: 

209 

210 All following ``analyze`` calls will use this library as the VHDL source file's VHDL library. 

211 

212 .. caution:: 

213 

214 Parameter `libraryPath` is not yet implemented. 

215 

216 :param libraryName: Name of the VHDL library. 

217 :param libraryPath: Optional, path where to create that VHDL library. 

218 :raises NotImplementedError: When parameter 'libraryPath' is not None. 

219 

220 .. seealso:: 

221 

222 * :func:`LinkLibrary` 

223 * :func:`LinkLibraryDirectory` 

224 """ 

225 try: 

226 if libraryPath is not None: 

227 raise NotImplementedError(f"Optional parameter 'libraryPath' not yet supported.") 

228 

229 osvvmContext.SetLibrary(libraryName) 

230 

231 except OSVVMException as ex: # pragma: no cover 

232 raise ex 

233 except Exception as ex: # pragma: no cover 

234 osvvmContext.RaiseException(ex) 

235 

236 

237@export 

238def NoNullRangeWarning() -> int: 

239 """ 

240 This function implements the behavior of OSVVM's ``NoNullRangeWarning`` procedure. 

241 

242 Create and register a :class:`~pyEDAA.OSVVM.Project.NoNullRangeWarning` option and return the options unique ID. 

243 

244 :returns: The option's unique ID. 

245 """ 

246 try: 

247 option = OSVVM_NoNullRangeWarning() 

248 return osvvmContext.AddOption(option) 

249 except OSVVMException as ex: # pragma: no cover 

250 raise ex 

251 except Exception as ex: # pragma: no cover 

252 osvvmContext.RaiseException(ex) 

253 

254 

255@export 

256def analyze(file: str, *options: int) -> None: 

257 """ 

258 This function implements the behavior of OSVVM's ``analyze`` procedure. 

259 

260 Analyze an HDL source file. 

261 

262 .. rubric:: Supported options: 

263 

264 * :func:`NoNullRangeWarning` - disable null-range warnings when analyzing. 

265 * :func:`ConstraintFile` - associated constraint file 

266 

267 :param file: Path of the VHDL source file. 

268 :param options: Optional, list of option IDs. 

269 :raises OSVVMException: When the referenced source file doesn't exist. 

270 :raises OSVVMException: When the referenced source file isn't an ``*.vhd`` or ``*.vhdl`` file. 

271 :raises OSVVMException: When parameter 'options' contains an unknown option ID. 

272 :raises OSVVMException: When referenced option is not a :class:`~pyEDAA.OSVVM.Project.NoNullRangeWarning` or 

273 :class:`~pyEDAA.OSVVM.Project.ConstraintFile`. 

274 

275 .. seealso:: 

276 

277 * :func:`NoNullRangeWarning` 

278 * :func:`SetCoverageAnalyzeEnable` 

279 * :func:`ConstraintFile` 

280 """ 

281 try: 

282 file = Path(file) 

283 fullPath = (osvvmContext._currentDirectory / file).resolve() 

284 

285 noNullRangeWarning = None 

286 associatedConstraintFiles = [] 

287 for optionID in options: 

288 try: 

289 option = osvvmContext._options[int(optionID)] 

290 except KeyError as ex: # pragma: no cover 

291 osvvmContext.RaiseException(OSVVMException(f"Option {optionID} not found in option dictionary."), ex) 

292 

293 if isinstance(option, OSVVM_NoNullRangeWarning): 293 ↛ 294line 293 didn't jump to line 294 because the condition on line 293 was never true

294 noNullRangeWarning = True 

295 elif isinstance(option, OSVVM_ConstraintFile): 

296 associatedConstraintFiles.append(XDCConstraintFile( 

297 option.Path, 

298 option.ScopeToRef, 

299 option.ScopeToCell 

300 )) 

301 else: # pragma: no cover 

302 ex = TypeError(f"Option {optionID} is not a NoNullRangeWarning or ConstraintFile.") 

303 ex.add_note(f"Got type '{getFullyQualifiedName(option)}'.") 

304 osvvmContext.RaiseException(OSVVMException(f"Dereferenced option ID is not a NoNullRangeWarning or ConstraintFile object"), ex) 

305 

306 if not fullPath.exists(): # pragma: no cover 

307 osvvmContext.RaiseException(OSVVMException(f"Path '{fullPath}' can't be analyzed."), FileNotFoundError(fullPath)) 

308 

309 if fullPath.suffix in (".vhd", ".vhdl"): 

310 vhdlFile = VHDLSourceFile( 

311 fullPath.relative_to(osvvmContext._workingDirectory, walk_up=True), 

312 noNullRangeWarning=noNullRangeWarning, 

313 associatedFiles=associatedConstraintFiles 

314 ) 

315 osvvmContext.AddVHDLFile(vhdlFile) 

316 else: # pragma: no cover 

317 osvvmContext.RaiseException(OSVVMException(f"Path '{fullPath}' is no VHDL file (*.vhd, *.vhdl).")) 

318 

319 except OSVVMException as ex: # pragma: no cover 

320 raise ex 

321 except Exception as ex: # pragma: no cover 

322 osvvmContext.RaiseException(ex) 

323 

324 

325@export 

326def simulate(toplevelName: str, *options: int) -> None: 

327 """ 

328 This function implements the behavior of OSVVM's ``simulate`` procedure. 

329 

330 Simulate a given toplevel entity or configuration name. 

331 

332 .. rubric:: Supported options: 

333 

334 * :func:`generic` - specify generic values. 

335 

336 :param toplevelName: Name of the toplevel. 

337 :param options: Optional, list of option IDs. 

338 :raises ValueError: When parameter 'toplevelName' is empty. 

339 :raises OSVVMException: When parameter 'options' contains an unknown option ID. 

340 :raises OSVVMException: When referenced option is not a :class:`~pyEDAA.OSVVM.Project.GenericValue`. 

341 

342 .. seealso:: 

343 

344 * :func:`generic` 

345 * :func:`RunTest` 

346 """ 

347 try: 

348 if toplevelName == "": 348 ↛ 349line 348 didn't jump to line 349 because the condition on line 348 was never true

349 raise ValueError(f"Parameter 'toplevelName' is empty.") 

350 

351 testcase = osvvmContext.SetTestcaseToplevel(toplevelName) 

352 for optionID in options: 

353 try: 

354 option = osvvmContext._options[int(optionID)] 

355 except KeyError as ex: # pragma: no cover 

356 osvvmContext.RaiseException(OSVVMException(f"Option {optionID} not found in option dictionary."), ex) 

357 

358 if isinstance(option, GenericValue): 

359 testcase.AddGeneric(option) 

360 else: # pragma: no cover 

361 ex = TypeError(f"Option {optionID} is not a GenericValue.") 

362 ex.add_note(f"Got type '{getFullyQualifiedName(option)}'.") 

363 osvvmContext.RaiseException(OSVVMException(f"Dereferenced option ID is not a GenericValue object"), ex) 

364 

365 except OSVVMException as ex: # pragma: no cover 

366 raise ex 

367 except Exception as ex: # pragma: no cover 

368 osvvmContext.RaiseException(ex) 

369 

370 

371@export 

372def generic(name: str, value: str) -> int: 

373 """ 

374 This function implements the behavior of OSVVM's ``generic`` procedure. 

375 

376 Create and register a :class:`~pyEDAA.OSVVM.Project.GenericValue` option and return the options unique ID. 

377 

378 :param name: Name of the generic. 

379 :param value: Value of the generic. 

380 :returns: The option's unique ID. 

381 """ 

382 try: 

383 genericValue = GenericValue(name, value) 

384 return osvvmContext.AddOption(genericValue) 

385 except OSVVMException as ex: # pragma: no cover 

386 raise ex 

387 except Exception as ex: # pragma: no cover 

388 osvvmContext.RaiseException(ex) 

389 

390 

391@export 

392def TestSuite(name: str) -> None: 

393 """ 

394 This function implements the behavior of OSVVM's ``TestSuite`` procedure. 

395 

396 Set or create the currently active :class:`~pyEDAA.OSVVM.Project.Testsuite`. 

397 

398 :param name: Name of the OSVVM testsuite. 

399 """ 

400 try: 

401 osvvmContext.SetTestsuite(name) 

402 except OSVVMException as ex: # pragma: no cover 

403 raise ex 

404 except Exception as ex: # pragma: no cover 

405 osvvmContext.RaiseException(ex) 

406 

407 

408@export 

409def TestName(name: str) -> None: 

410 """ 

411 This function implements the behavior of OSVVM's ``TestName`` procedure. 

412 

413 Create a new :class:`~pyEDAA.OSVVM.Project.Testcase`. 

414 

415 :param name: Name of the OSVVM testcase. 

416 """ 

417 try: 

418 osvvmContext.AddTestcase(name) 

419 except OSVVMException as ex: # pragma: no cover 

420 raise ex 

421 except Exception as ex: # pragma: no cover 

422 osvvmContext.RaiseException(ex) 

423 

424 

425@export 

426def RunTest(file: str, *options: int) -> None: 

427 """ 

428 This function implements the behavior of OSVVM's ``RunTest`` procedure. 

429 

430 Simulate a given toplevel entity or configuration name. Infer testcase name from filename. 

431 

432 .. rubric:: Supported options: 

433 

434 * :func:`generic` - specify generic values. 

435 

436 :param file: Path of the VHDL source file containing the toplevel. 

437 :param options: Optional, list of option IDs. 

438 :raises OSVVMException: When the referenced source file doesn't exist. 

439 :raises OSVVMException: When the referenced source file isn't an ``*.vhd`` or ``*.vhdl`` file. 

440 :raises OSVVMException: When parameter 'options' contains an unknown option ID. 

441 :raises OSVVMException: When referenced option is not a :class:`~pyEDAA.OSVVM.Project.GenericValue`. 

442 

443 .. seealso:: 

444 

445 * :func:`generic` 

446 * :func:`simulate` 

447 """ 

448 try: 

449 file = Path(file) 

450 testName = file.stem 

451 

452 # Analyze file 

453 fullPath = (osvvmContext._currentDirectory / file).resolve() 

454 

455 if not fullPath.exists(): # pragma: no cover 

456 osvvmContext.RaiseException(OSVVMException(f"Path '{fullPath}' can't be analyzed."), FileNotFoundError(fullPath)) 

457 

458 if fullPath.suffix in (".vhd", ".vhdl"): 

459 vhdlFile = VHDLSourceFile(fullPath.relative_to(osvvmContext._workingDirectory, walk_up=True)) 

460 osvvmContext.AddVHDLFile(vhdlFile) 

461 else: # pragma: no cover 

462 osvvmContext.RaiseException(OSVVMException(f"Path '{fullPath}' is no VHDL file (*.vhd, *.vhdl).")) 

463 

464 # Add testcase 

465 testcase = osvvmContext.AddTestcase(testName) 

466 testcase.SetToplevel(testName) 

467 for optionID in options: 

468 try: 

469 option = osvvmContext._options[int(optionID)] 

470 except KeyError as ex: # pragma: no cover 

471 osvvmContext.RaiseException(OSVVMException(f"Option {optionID} not found in option dictionary."), ex) 

472 

473 if isinstance(option, GenericValue): 

474 testcase.AddGeneric(option) 

475 else: # pragma: no cover 

476 ex = TypeError(f"Option {optionID} is not a GenericValue.") 

477 ex.add_note(f"Got type '{getFullyQualifiedName(option)}'.") 

478 osvvmContext.RaiseException(OSVVMException(f"Dereferenced option ID is not a GenericValue object"), ex) 

479 

480 except OSVVMException as ex: # pragma: no cover 

481 raise ex 

482 except Exception as ex: # pragma: no cover 

483 osvvmContext.RaiseException(ex) 

484 

485 

486@export 

487def LinkLibrary(libraryName: str, libraryPath: Nullable[str] = None): 

488 """ 

489 Not implemented by pyEDAA.OSVVM. 

490 """ 

491 osvvmContext.RaiseException(NotImplementedError(f"Procedure 'LinkLibrary' is not implemented.")) 

492 

493 

494@export 

495def LinkLibraryDirectory(libraryDirectory: str): 

496 """ 

497 Not implemented by pyEDAA.OSVVM. 

498 """ 

499 osvvmContext.RaiseException(NotImplementedError(f"Procedure 'LinkLibraryDirectory' is not implemented.")) 

500 

501 

502@export 

503def SetVHDLVersion(value: str) -> None: 

504 """ 

505 This function implements the behavior of OSVVM's ``SetVHDLVersion`` procedure. 

506 

507 Set the used VHDL language revision. 

508 

509 .. hint:: 

510 

511 All following ``analyze`` calls will use this VHDL revision. 

512 

513 :param value: The VHDL language revision's release year. 

514 :raises ValueError: When parameter 'value' is not an integer value. 

515 :raises OSVVMException: When parameter 'value' is not a known VHDL revision's release year. 

516 

517 .. seealso:: 

518 

519 * :func:`GetVHDLVersion` 

520 """ 

521 try: 

522 try: 

523 value = int(value) 

524 except ValueError as e: # pragma: no cover 

525 ex = ValueError(f"Parameter 'value' is not an integer value.") 

526 ex.add_note(f"Got '{value}'.") 

527 osvvmContext.RaiseException(ex, e) 

528 

529 match value: 

530 case 1987: 

531 osvvmContext.VHDLVersion = VHDLVersion.VHDL87 

532 case 1993: 

533 osvvmContext.VHDLVersion = VHDLVersion.VHDL93 

534 case 2002: 

535 osvvmContext.VHDLVersion = VHDLVersion.VHDL2002 

536 case 2008: 

537 osvvmContext.VHDLVersion = VHDLVersion.VHDL2008 

538 case 2019: 

539 osvvmContext.VHDLVersion = VHDLVersion.VHDL2019 

540 case _: # pragma: no cover 

541 osvvmContext.RaiseException(OSVVMException(f"Unsupported VHDL version '{value}'.")) 

542 

543 except OSVVMException as ex: # pragma: no cover 

544 raise ex 

545 except Exception as ex: # pragma: no cover 

546 osvvmContext.RaiseException(ex) 

547 

548 

549@export 

550def GetVHDLVersion() -> int: 

551 """ 

552 This function implements the behavior of OSVVM's ``GetVHDLVersion`` procedure. 

553 

554 Returns the currently set VHDL language revision. 

555 

556 :returns: The VHDL language revision's release year. 

557 :raises OSVVMException: When the currently set VHDL language revision is unknown in this decoding function. 

558 

559 .. seealso:: 

560 

561 * :func:`SetVHDLVersion` 

562 """ 

563 try: 

564 if osvvmContext.VHDLVersion is VHDLVersion.VHDL87: 

565 return 1987 

566 elif osvvmContext.VHDLVersion is VHDLVersion.VHDL93: 

567 return 1993 

568 elif osvvmContext.VHDLVersion is VHDLVersion.VHDL2002: 

569 return 2002 

570 elif osvvmContext.VHDLVersion is VHDLVersion.VHDL2008: 

571 return 2008 

572 elif osvvmContext.VHDLVersion is VHDLVersion.VHDL2019: 

573 return 2019 

574 else: # pragma: no cover 

575 osvvmContext.RaiseException(OSVVMException(f"Unsupported VHDL version '{osvvmContext.VHDLVersion}'.")) 

576 

577 except OSVVMException as ex: # pragma: no cover 

578 raise ex 

579 except Exception as ex: # pragma: no cover 

580 osvvmContext.RaiseException(ex) 

581 

582 

583@export 

584def SetCoverageAnalyzeEnable(value: bool) -> None: 

585 """ 

586 Not implemented by pyEDAA.OSVVM. 

587 """ 

588 osvvmContext.RaiseException(NotImplementedError(f"Procedure 'SetCoverageAnalyzeEnable' is not implemented.")) 

589 

590 

591@export 

592def SetCoverageSimulateEnable(value: bool) -> None: 

593 """ 

594 Not implemented by pyEDAA.OSVVM. 

595 """ 

596 osvvmContext.RaiseException(NotImplementedError(f"Procedure 'SetCoverageSimulateEnable' is not implemented.")) 

597 

598 

599@export 

600def FileExists(file: str) -> bool: 

601 """ 

602 This function implements the behavior of OSVVM's ``FileExists`` procedure. 

603 

604 Check if the given file exists. 

605 

606 :param file: File name. 

607 :returns: True, if file exists, otherwise False. 

608 :raises ValueError: When parameter 'file' is empty. 

609 

610 .. seealso:: 

611 

612 * :func:`DirectoryExists` 

613 """ 

614 try: 

615 if file == "": 615 ↛ 616line 615 didn't jump to line 616 because the condition on line 615 was never true

616 raise ValueError(f"Parameter 'file' is empty.") 

617 

618 return (osvvmContext._currentDirectory / file).is_file() 

619 

620 except OSVVMException as ex: # pragma: no cover 

621 raise ex 

622 except Exception as ex: # pragma: no cover 

623 osvvmContext.RaiseException(ex) 

624 

625 

626@export 

627def DirectoryExists(directory: str) -> bool: 

628 """ 

629 This function implements the behavior of OSVVM's ``DirectoryExists`` procedure. 

630 

631 Check if the given directory exists. 

632 

633 :param directory: Directory name. 

634 :returns: True, if directory exists, otherwise False. 

635 :raises ValueError: When parameter 'directory' is empty. 

636 

637 .. seealso:: 

638 

639 * :func:`FileExists` 

640 """ 

641 try: 

642 if directory == "": 642 ↛ 643line 642 didn't jump to line 643 because the condition on line 642 was never true

643 raise ValueError(f"Parameter 'directory' is empty.") 

644 

645 return (osvvmContext._currentDirectory / directory).is_dir() 

646 

647 except OSVVMException as ex: # pragma: no cover 

648 raise ex 

649 except Exception as ex: # pragma: no cover 

650 osvvmContext.RaiseException(ex) 

651 

652 

653@export 

654def ChangeWorkingDirectory(directory: str) -> None: 

655 """ 

656 This function implements the behavior of OSVVM's ``ChangeWorkingDirectory`` procedure. 

657 

658 Change the current directory (virtual working directory) to the given directory. 

659 

660 :param directory: Directory name. 

661 :raises ValueError: When parameter 'directory' is empty. 

662 :raises OSVVMException: When the referenced directory doesn't exist. 

663 

664 .. seealso:: 

665 

666 * :func:`build` 

667 * :func:`include` 

668 """ 

669 try: 

670 if directory == "": 

671 raise ValueError(f"Parameter 'directory' is empty.") 

672 

673 osvvmContext._currentDirectory = (newDirectory := osvvmContext._currentDirectory / directory) 

674 if not newDirectory.is_dir(): # pragma: no cover 

675 osvvmContext.RaiseException(OSVVMException(f"Directory '{newDirectory}' doesn't exist."), NotADirectoryError(newDirectory)) 

676 

677 except OSVVMException as ex: # pragma: no cover 

678 raise ex 

679 except Exception as ex: # pragma: no cover 

680 osvvmContext.RaiseException(ex) 

681 

682 

683@export 

684def FindOsvvmSettingsDirectory(*args) -> None: 

685 """ 

686 Not implemented by pyEDAA.OSVVM. 

687 """ 

688 osvvmContext.RaiseException(NotImplementedError(f"Procedure 'FindOsvvmSettingsDirectory' is not implemented.")) 

689 

690 

691@export 

692def CreateOsvvmScriptSettingsPkg(*args) -> None: 

693 """ 

694 Not implemented by pyEDAA.OSVVM. 

695 """ 

696 osvvmContext.RaiseException(NotImplementedError(f"Procedure 'CreateOsvvmScriptSettingsPkg' is not implemented.")) 

697 

698 

699@export 

700def noop(*args) -> None: 

701 """ 

702 A no-operation dummy procedure accepting any positional arguments. 

703 

704 :param args: Any arguments 

705 """ 

706 

707 

708@export 

709def ConstraintFile(file: str, *options: int) -> int: 

710 """ 

711 This function implements the behavior of pyEDAA's ``ConstraintFile`` procedure. 

712 

713 Create and register a :class:`~pyEDAA.OSVVM.Project.ConstraintFile` option and return the options unique ID. 

714 

715 :param file: Path to the constraint file. 

716 :param options: Optional, list of option IDs. 

717 :returns: The option's unique ID. 

718 :raises OSVVMException: When parameter 'options' contains an unknown option ID. 

719 :raises OSVVMException: When referenced option is not a :class:`~pyEDAA.OSVVM.Project.ScopeToRef` or 

720 :class:`~pyEDAA.OSVVM.Project.ScopeToCell`. 

721 :raises OSVVMException: When the referenced constraint file doesn't exist. 

722 :raises OSVVMException: When the referenced constraint file isn't an ``*.sdc`` or ``*.xdc`` file. 

723 """ 

724 try: 

725 file = Path(file) 

726 fullPath = (osvvmContext._currentDirectory / file).resolve() 

727 

728 properties = {} 

729 for optionID in options: 

730 try: 

731 option = osvvmContext._options[int(optionID)] 

732 except KeyError as ex: # pragma: no cover 

733 osvvmContext.RaiseException(OSVVMException(f"Option {optionID} not found in option dictionary."), ex) 

734 

735 if isinstance(option, OSVVM_ScopeToRef): 

736 properties["scopeToRef"] = option.Reference 

737 elif isinstance(option, OSVVM_ScopeToCell): 

738 properties["scopeToCell"] = option.Cell 

739 else: # pragma: no cover 

740 ex = TypeError(f"Option {optionID} is not a ScopeToRef or ScopeToCell.") 

741 ex.add_note(f"Got type '{getFullyQualifiedName(option)}'.") 

742 osvvmContext.RaiseException(OSVVMException(f"Dereferenced option ID is not a ScopeToRef or ScopeToCell object"), ex) 

743 

744 if not fullPath.exists(): # pragma: no cover 

745 osvvmContext.RaiseException(OSVVMException(f"Constraint file '{fullPath}' can't be found."), FileNotFoundError(fullPath)) 

746 

747 if not fullPath.suffix in (".sdc", ".xdc"): 747 ↛ 748line 747 didn't jump to line 748 because the condition on line 747 was never true

748 osvvmContext.RaiseException(OSVVMException(f"Path '{fullPath}' is no constraint file (*.sdc, *.xdc).")) 

749 

750 constraint = OSVVM_ConstraintFile(Path(file), **properties) 

751 return osvvmContext.AddOption(constraint) 

752 

753 except OSVVMException as ex: # pragma: no cover 

754 raise ex 

755 except Exception as ex: # pragma: no cover 

756 osvvmContext.RaiseException(ex) 

757 

758 

759@export 

760def ScopeToRef(refName: str) -> int: 

761 """ 

762 This function implements the behavior of pyEDAA's ``ScopeToRef`` procedure. 

763 

764 Create and register a :class:`~pyEDAA.OSVVM.Project.ScopeToRef` option and return the options unique ID. 

765 

766 :param refName: Reference name. 

767 :returns: The option's unique ID. 

768 :raises ValueError: When parameter 'refName' is empty. 

769 """ 

770 try: 

771 if refName == "": 771 ↛ 772line 771 didn't jump to line 772 because the condition on line 771 was never true

772 raise ValueError("Parameter 'refName' is a empty string.") 

773 

774 ref = OSVVM_ScopeToRef(refName) 

775 return osvvmContext.AddOption(ref) 

776 except OSVVMException as ex: # pragma: no cover 

777 raise ex 

778 except Exception as ex: # pragma: no cover 

779 osvvmContext.RaiseException(ex) 

780 

781 

782@export 

783def ScopeToCell(cellName: str) -> int: 

784 """ 

785 This function implements the behavior of pyEDAA's ``ScopeToCell`` procedure. 

786 

787 Create and register a :class:`~pyEDAA.OSVVM.Project.ScopeToCell` option and return the options unique ID. 

788 

789 :param cellName: Cell name. 

790 :returns: The option's unique ID. 

791 :raises ValueError: When parameter 'cellName' is empty. 

792 """ 

793 try: 

794 if cellName == "": 794 ↛ 795line 794 didn't jump to line 795 because the condition on line 794 was never true

795 raise ValueError("Parameter 'cellName' is a empty string.") 

796 

797 ref = OSVVM_ScopeToCell(cellName) 

798 return osvvmContext.AddOption(ref) 

799 except OSVVMException as ex: # pragma: no cover 

800 raise ex 

801 except Exception as ex: # pragma: no cover 

802 osvvmContext.RaiseException(ex)