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

204 statements  

« prev     ^ index     » next       coverage.py v7.14.1, created at 2026-06-12 23:17 +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 Exception as ex: # pragma: no cover 

50 osvvmContext.RaiseException(ex) 

51""" 

52from pathlib import Path 

53from typing import Optional as Nullable 

54 

55from pyTooling.Decorators import export 

56from pyTooling.Common import getFullyQualifiedName 

57from pyVHDLModel import VHDLVersion 

58 

59from pyEDAA.OSVVM import OSVVMException 

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

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

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

63 

64 

65@export 

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

67 """ 

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

69 

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

71 

72 :param name: Name of the build. 

73 :returns: The option's unique ID. 

74 """ 

75 try: 

76 buildName = OSVVM_BuildName(name) 

77 return osvvmContext.AddOption(buildName) 

78 

79 except Exception as ex: # pragma: no cover 

80 osvvmContext.RaiseException(ex) 

81 

82 

83@export 

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

85 """ 

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

87 

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

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

90 

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

92 

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

94 

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

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

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

98 

99 .. rubric:: inferring the build name: 

100 

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

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

103 

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

105 file. 

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

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

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

109 

110 .. seealso:: 

111 

112 * :func:`BuildName` 

113 * :func:`include` 

114 * :func:`ChangeWorkingDirectory` 

115 """ 

116 try: 

117 file = Path(file) 

118 buildName = None 

119 

120 # Preserve current directory 

121 currentDirectory = osvvmContext._currentDirectory 

122 

123 for optionID in options: 

124 try: 

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

126 except KeyError as e: # pragma: no cover 

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

128 ex.__cause__ = e 

129 osvvmContext.RaiseException(ex) 

130 

131 if isinstance(option, OSVVM_BuildName): 

132 buildName = option.Name 

133 else: # pragma: no cover 

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

135 ex.__cause__ = TypeError() 

136 osvvmContext.LastException = ex 

137 raise ex 

138 

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

140 if buildName is None: 

141 buildName = file.stem 

142 

143 osvvmContext.BeginBuild(buildName) 

144 includeFile = osvvmContext.IncludeFile(file) 

145 osvvmContext.EvaluateFile(includeFile) 

146 osvvmContext.EndBuild() 

147 

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

149 osvvmContext._currentDirectory = currentDirectory 

150 

151 except Exception as ex: # pragma: no cover 

152 osvvmContext.RaiseException(ex) 

153 

154 

155@export 

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

157 """ 

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

159 

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

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

162 

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

164 

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

166 

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

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

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

170 

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

172 file. 

173 

174 .. seealso:: 

175 

176 * :func:`build` 

177 * :func:`ChangeWorkingDirectory` 

178 """ 

179 try: 

180 # Preserve current directory 

181 currentDirectory = osvvmContext._currentDirectory 

182 

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

184 osvvmContext.EvaluateFile(includeFile) 

185 

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

187 osvvmContext._currentDirectory = currentDirectory 

188 

189 except Exception as ex: # pragma: no cover 

190 osvvmContext.RaiseException(ex) 

191 

192 

193@export 

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

195 """ 

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

197 

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

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

200 

201 .. hint:: 

202 

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

204 

205 .. caution:: 

206 

207 Parameter `libraryPath` is not yet implemented. 

208 

209 :param libraryName: Name of the VHDL library. 

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

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

212 

213 .. seealso:: 

214 

215 * :func:`LinkLibrary` 

216 * :func:`LinkLibraryDirectory` 

217 """ 

218 try: 

219 if libraryPath is not None: 

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

221 

222 osvvmContext.SetLibrary(libraryName) 

223 

224 except Exception as ex: # pragma: no cover 

225 osvvmContext.RaiseException(ex) 

226 

227 

228@export 

229def NoNullRangeWarning() -> int: 

230 """ 

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

232 

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

234 

235 :returns: The option's unique ID. 

236 """ 

237 try: 

238 option = OSVVM_NoNullRangeWarning() 

239 return osvvmContext.AddOption(option) 

240 

241 except Exception as ex: # pragma: no cover 

242 osvvmContext.RaiseException(ex) 

243 

244 

245@export 

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

247 """ 

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

249 

250 Analyze an HDL source file. 

251 

252 .. rubric:: Supported options: 

253 

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

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

256 

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

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

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

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

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

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

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

264 

265 .. seealso:: 

266 

267 * :func:`NoNullRangeWarning` 

268 * :func:`SetCoverageAnalyzeEnable` 

269 * :func:`ConstraintFile` 

270 """ 

271 try: 

272 file = Path(file) 

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

274 

275 noNullRangeWarning = None 

276 associatedConstraintFiles = [] 

277 for optionID in options: 

278 try: 

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

280 except KeyError as ex: # pragma: no cover 

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

282 

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

284 noNullRangeWarning = True 

285 elif isinstance(option, OSVVM_ConstraintFile): 

286 associatedConstraintFiles.append(XDCConstraintFile( 

287 option.Path, 

288 option.ScopeToRef, 

289 option.ScopeToCell 

290 )) 

291 else: # pragma: no cover 

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

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

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

295 

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

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

298 

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

300 vhdlFile = VHDLSourceFile( 

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

302 noNullRangeWarning=noNullRangeWarning, 

303 associatedFiles=associatedConstraintFiles 

304 ) 

305 osvvmContext.AddVHDLFile(vhdlFile) 

306 else: # pragma: no cover 

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

308 

309 except Exception as ex: # pragma: no cover 

310 osvvmContext.RaiseException(ex) 

311 

312 

313@export 

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

315 """ 

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

317 

318 Simulate a given toplevel entity or configuration name. 

319 

320 .. rubric:: Supported options: 

321 

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

323 

324 :param toplevelName: Name of the toplevel. 

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

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

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

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

329 

330 .. seealso:: 

331 

332 * :func:`generic` 

333 * :func:`RunTest` 

334 """ 

335 try: 

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

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

338 

339 testcase = osvvmContext.SetTestcaseToplevel(toplevelName) 

340 for optionID in options: 

341 try: 

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

343 except KeyError as ex: # pragma: no cover 

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

345 

346 if isinstance(option, GenericValue): 

347 testcase.AddGeneric(option) 

348 else: # pragma: no cover 

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

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

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

352 

353 except Exception as ex: # pragma: no cover 

354 osvvmContext.RaiseException(ex) 

355 

356 

357@export 

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

359 """ 

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

361 

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

363 

364 :param name: Name of the generic. 

365 :param value: Value of the generic. 

366 :returns: The option's unique ID. 

367 """ 

368 try: 

369 genericValue = GenericValue(name, value) 

370 return osvvmContext.AddOption(genericValue) 

371 

372 except Exception as ex: # pragma: no cover 

373 osvvmContext.RaiseException(ex) 

374 

375 

376@export 

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

378 """ 

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

380 

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

382 

383 :param name: Name of the OSVVM testsuite. 

384 """ 

385 try: 

386 osvvmContext.SetTestsuite(name) 

387 

388 except Exception as ex: # pragma: no cover 

389 osvvmContext.RaiseException(ex) 

390 

391 

392@export 

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

394 """ 

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

396 

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

398 

399 :param name: Name of the OSVVM testcase. 

400 """ 

401 try: 

402 osvvmContext.AddTestcase(name) 

403 

404 except Exception as ex: # pragma: no cover 

405 osvvmContext.RaiseException(ex) 

406 

407 

408@export 

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

410 """ 

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

412 

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

414 

415 .. rubric:: Supported options: 

416 

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

418 

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

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

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

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

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

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

425 

426 .. seealso:: 

427 

428 * :func:`generic` 

429 * :func:`simulate` 

430 """ 

431 try: 

432 file = Path(file) 

433 testName = file.stem 

434 

435 # Analyze file 

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

437 

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

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

440 

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

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

443 osvvmContext.AddVHDLFile(vhdlFile) 

444 else: # pragma: no cover 

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

446 

447 # Add testcase 

448 testcase = osvvmContext.AddTestcase(testName) 

449 testcase.SetToplevel(testName) 

450 for optionID in options: 

451 try: 

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

453 except KeyError as ex: # pragma: no cover 

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

455 

456 if isinstance(option, GenericValue): 

457 testcase.AddGeneric(option) 

458 else: # pragma: no cover 

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

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

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

462 

463 except Exception as ex: # pragma: no cover 

464 osvvmContext.RaiseException(ex) 

465 

466 

467@export 

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

469 """ 

470 Not implemented by pyEDAA.OSVVM. 

471 """ 

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

473 

474 

475@export 

476def LinkLibraryDirectory(libraryDirectory: str): 

477 """ 

478 Not implemented by pyEDAA.OSVVM. 

479 """ 

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

481 

482 

483@export 

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

485 """ 

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

487 

488 Set the used VHDL language revision. 

489 

490 .. hint:: 

491 

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

493 

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

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

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

497 

498 .. seealso:: 

499 

500 * :func:`GetVHDLVersion` 

501 """ 

502 try: 

503 try: 

504 value = int(value) 

505 except ValueError as e: # pragma: no cover 

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

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

508 osvvmContext.RaiseException(ex, e) 

509 

510 match value: 

511 case 1987: 

512 osvvmContext.VHDLVersion = VHDLVersion.VHDL87 

513 case 1993: 

514 osvvmContext.VHDLVersion = VHDLVersion.VHDL93 

515 case 2002: 

516 osvvmContext.VHDLVersion = VHDLVersion.VHDL2002 

517 case 2008: 

518 osvvmContext.VHDLVersion = VHDLVersion.VHDL2008 

519 case 2019: 

520 osvvmContext.VHDLVersion = VHDLVersion.VHDL2019 

521 case _: # pragma: no cover 

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

523 

524 except Exception as ex: # pragma: no cover 

525 osvvmContext.RaiseException(ex) 

526 

527 

528@export 

529def GetVHDLVersion() -> int: 

530 """ 

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

532 

533 Returns the currently set VHDL language revision. 

534 

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

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

537 

538 .. seealso:: 

539 

540 * :func:`SetVHDLVersion` 

541 """ 

542 try: 

543 if osvvmContext.VHDLVersion is VHDLVersion.VHDL87: 

544 return 1987 

545 elif osvvmContext.VHDLVersion is VHDLVersion.VHDL93: 

546 return 1993 

547 elif osvvmContext.VHDLVersion is VHDLVersion.VHDL2002: 

548 return 2002 

549 elif osvvmContext.VHDLVersion is VHDLVersion.VHDL2008: 

550 return 2008 

551 elif osvvmContext.VHDLVersion is VHDLVersion.VHDL2019: 

552 return 2019 

553 else: # pragma: no cover 

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

555 

556 except Exception as ex: # pragma: no cover 

557 osvvmContext.RaiseException(ex) 

558 

559 

560@export 

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

562 """ 

563 Not implemented by pyEDAA.OSVVM. 

564 """ 

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

566 

567 

568@export 

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

570 """ 

571 Not implemented by pyEDAA.OSVVM. 

572 """ 

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

574 

575 

576@export 

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

578 """ 

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

580 

581 Check if the given file exists. 

582 

583 :param file: File name. 

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

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

586 

587 .. seealso:: 

588 

589 * :func:`DirectoryExists` 

590 """ 

591 try: 

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

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

594 

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

596 

597 except Exception as ex: # pragma: no cover 

598 osvvmContext.RaiseException(ex) 

599 

600 

601@export 

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

603 """ 

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

605 

606 Check if the given directory exists. 

607 

608 :param directory: Directory name. 

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

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

611 

612 .. seealso:: 

613 

614 * :func:`FileExists` 

615 """ 

616 try: 

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

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

619 

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

621 

622 except Exception as ex: # pragma: no cover 

623 osvvmContext.RaiseException(ex) 

624 

625 

626@export 

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

628 """ 

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

630 

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

632 

633 :param directory: Directory name. 

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

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

636 

637 .. seealso:: 

638 

639 * :func:`build` 

640 * :func:`include` 

641 """ 

642 try: 

643 if directory == "": 

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

645 

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

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

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

649 

650 except Exception as ex: # pragma: no cover 

651 osvvmContext.RaiseException(ex) 

652 

653 

654@export 

655def FindOsvvmSettingsDirectory(*args) -> str: 

656 """ 

657 .. todo:: 

658 

659 Needs documentation. 

660 """ 

661 return osvvmContext.CurrentDirectory.as_posix() 

662 

663 

664@export 

665def CreateOsvvmScriptSettingsPkg(*args) -> None: 

666 """ 

667 Not implemented by pyEDAA.OSVVM. 

668 """ 

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

670 

671 

672@export 

673def noop(*args) -> None: 

674 """ 

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

676 

677 :param args: Any arguments 

678 """ 

679 

680 

681@export 

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

683 """ 

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

685 

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

687 

688 :param file: Path to the constraint file. 

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

690 :returns: The option's unique ID. 

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

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

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

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

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

696 """ 

697 try: 

698 file = Path(file) 

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

700 

701 properties = {} 

702 for optionID in options: 

703 try: 

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

705 except KeyError as ex: # pragma: no cover 

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

707 

708 if isinstance(option, OSVVM_ScopeToRef): 

709 properties["scopeToRef"] = option.Reference 

710 elif isinstance(option, OSVVM_ScopeToCell): 

711 properties["scopeToCell"] = option.Cell 

712 else: # pragma: no cover 

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

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

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

716 

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

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

719 

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

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

722 

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

724 return osvvmContext.AddOption(constraint) 

725 

726 except Exception as ex: # pragma: no cover 

727 osvvmContext.RaiseException(ex) 

728 

729 

730@export 

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

732 """ 

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

734 

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

736 

737 :param refName: Reference name. 

738 :returns: The option's unique ID. 

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

740 """ 

741 try: 

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

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

744 

745 ref = OSVVM_ScopeToRef(refName) 

746 return osvvmContext.AddOption(ref) 

747 

748 except Exception as ex: # pragma: no cover 

749 osvvmContext.RaiseException(ex) 

750 

751 

752@export 

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

754 """ 

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

756 

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

758 

759 :param cellName: Cell name. 

760 :returns: The option's unique ID. 

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

762 """ 

763 try: 

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

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

766 

767 ref = OSVVM_ScopeToCell(cellName) 

768 return osvvmContext.AddOption(ref) 

769 

770 except Exception as ex: # pragma: no cover 

771 osvvmContext.RaiseException(ex)