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
« 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.
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.
38.. important::
40 For passing Python exceptions through the TCL layer back into Python, every function in the module MUST follow the
41 following scheme:
43 .. code-block:: Python
45 def myTclProcedure(....) -> ...:
46 try:
47 # do something
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
57from pyTooling.Decorators import export
58from pyTooling.Common import getFullyQualifiedName
59from pyVHDLModel import VHDLVersion
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
67@export
68def BuildName(name: str) -> int:
69 """
70 This function implements the behavior of OSVVM's ``BuildName`` procedure.
72 Create and register a :class:`~pyEDAA.OSVVM.Project.BuildName` option and return the options unique ID.
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)
86@export
87def build(file: str, *options: int) -> None:
88 """
89 This function implements the behavior of OSVVM's ``build`` procedure.
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.
94 The referenced file gets appended to a list of included files maintained by the context.
96 .. rubric:: pro-file discovery algorithm:
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.
102 .. rubric:: inferring the build name:
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.
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`.
113 .. seealso::
115 * :func:`BuildName`
116 * :func:`include`
117 * :func:`ChangeWorkingDirectory`
118 """
119 try:
120 file = Path(file)
121 buildName = None
123 # Preserve current directory
124 currentDirectory = osvvmContext._currentDirectory
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)
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
142 # If no build name was specified, derive a name from *.pro file.
143 if buildName is None:
144 buildName = file.stem
146 osvvmContext.BeginBuild(buildName)
147 includeFile = osvvmContext.IncludeFile(file)
148 osvvmContext.EvaluateFile(includeFile)
149 osvvmContext.EndBuild()
151 # Restore current directory after recursively evaluating *.pro files.
152 osvvmContext._currentDirectory = currentDirectory
154 except OSVVMException as ex: # pragma: no cover
155 raise ex
156 except Exception as ex: # pragma: no cover
157 osvvmContext.RaiseException(ex)
160@export
161def include(file: str) -> None:
162 """
163 This function implements the behavior of OSVVM's ``include`` procedure.
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.
168 The referenced file gets appended to a list of included files maintained by the context.
170 .. rubric:: pro-file discovery algorithm:
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.
176 :param file: Explicit path to a ``*.pro`` file or a directory containing an implicitly searched ``*.pro``
177 file.
179 .. seealso::
181 * :func:`build`
182 * :func:`ChangeWorkingDirectory`
183 """
184 try:
185 # Preserve current directory
186 currentDirectory = osvvmContext._currentDirectory
188 includeFile = osvvmContext.IncludeFile(Path(file))
189 osvvmContext.EvaluateFile(includeFile)
191 # Restore current directory after recursively evaluating *.pro files.
192 osvvmContext._currentDirectory = currentDirectory
194 except OSVVMException as ex: # pragma: no cover
195 raise ex
196 except Exception as ex: # pragma: no cover
197 osvvmContext.RaiseException(ex)
200@export
201def library(libraryName: str, libraryPath: Nullable[str] = None) -> None:
202 """
203 This function implements the behavior of OSVVM's ``library`` procedure.
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.
208 .. hint::
210 All following ``analyze`` calls will use this library as the VHDL source file's VHDL library.
212 .. caution::
214 Parameter `libraryPath` is not yet implemented.
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.
220 .. seealso::
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.")
229 osvvmContext.SetLibrary(libraryName)
231 except OSVVMException as ex: # pragma: no cover
232 raise ex
233 except Exception as ex: # pragma: no cover
234 osvvmContext.RaiseException(ex)
237@export
238def NoNullRangeWarning() -> int:
239 """
240 This function implements the behavior of OSVVM's ``NoNullRangeWarning`` procedure.
242 Create and register a :class:`~pyEDAA.OSVVM.Project.NoNullRangeWarning` option and return the options unique ID.
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)
255@export
256def analyze(file: str, *options: int) -> None:
257 """
258 This function implements the behavior of OSVVM's ``analyze`` procedure.
260 Analyze an HDL source file.
262 .. rubric:: Supported options:
264 * :func:`NoNullRangeWarning` - disable null-range warnings when analyzing.
265 * :func:`ConstraintFile` - associated constraint file
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`.
275 .. seealso::
277 * :func:`NoNullRangeWarning`
278 * :func:`SetCoverageAnalyzeEnable`
279 * :func:`ConstraintFile`
280 """
281 try:
282 file = Path(file)
283 fullPath = (osvvmContext._currentDirectory / file).resolve()
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)
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)
306 if not fullPath.exists(): # pragma: no cover
307 osvvmContext.RaiseException(OSVVMException(f"Path '{fullPath}' can't be analyzed."), FileNotFoundError(fullPath))
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)."))
319 except OSVVMException as ex: # pragma: no cover
320 raise ex
321 except Exception as ex: # pragma: no cover
322 osvvmContext.RaiseException(ex)
325@export
326def simulate(toplevelName: str, *options: int) -> None:
327 """
328 This function implements the behavior of OSVVM's ``simulate`` procedure.
330 Simulate a given toplevel entity or configuration name.
332 .. rubric:: Supported options:
334 * :func:`generic` - specify generic values.
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`.
342 .. seealso::
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.")
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)
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)
365 except OSVVMException as ex: # pragma: no cover
366 raise ex
367 except Exception as ex: # pragma: no cover
368 osvvmContext.RaiseException(ex)
371@export
372def generic(name: str, value: str) -> int:
373 """
374 This function implements the behavior of OSVVM's ``generic`` procedure.
376 Create and register a :class:`~pyEDAA.OSVVM.Project.GenericValue` option and return the options unique ID.
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)
391@export
392def TestSuite(name: str) -> None:
393 """
394 This function implements the behavior of OSVVM's ``TestSuite`` procedure.
396 Set or create the currently active :class:`~pyEDAA.OSVVM.Project.Testsuite`.
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)
408@export
409def TestName(name: str) -> None:
410 """
411 This function implements the behavior of OSVVM's ``TestName`` procedure.
413 Create a new :class:`~pyEDAA.OSVVM.Project.Testcase`.
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)
425@export
426def RunTest(file: str, *options: int) -> None:
427 """
428 This function implements the behavior of OSVVM's ``RunTest`` procedure.
430 Simulate a given toplevel entity or configuration name. Infer testcase name from filename.
432 .. rubric:: Supported options:
434 * :func:`generic` - specify generic values.
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`.
443 .. seealso::
445 * :func:`generic`
446 * :func:`simulate`
447 """
448 try:
449 file = Path(file)
450 testName = file.stem
452 # Analyze file
453 fullPath = (osvvmContext._currentDirectory / file).resolve()
455 if not fullPath.exists(): # pragma: no cover
456 osvvmContext.RaiseException(OSVVMException(f"Path '{fullPath}' can't be analyzed."), FileNotFoundError(fullPath))
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)."))
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)
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)
480 except OSVVMException as ex: # pragma: no cover
481 raise ex
482 except Exception as ex: # pragma: no cover
483 osvvmContext.RaiseException(ex)
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."))
494@export
495def LinkLibraryDirectory(libraryDirectory: str):
496 """
497 Not implemented by pyEDAA.OSVVM.
498 """
499 osvvmContext.RaiseException(NotImplementedError(f"Procedure 'LinkLibraryDirectory' is not implemented."))
502@export
503def SetVHDLVersion(value: str) -> None:
504 """
505 This function implements the behavior of OSVVM's ``SetVHDLVersion`` procedure.
507 Set the used VHDL language revision.
509 .. hint::
511 All following ``analyze`` calls will use this VHDL revision.
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.
517 .. seealso::
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)
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}'."))
543 except OSVVMException as ex: # pragma: no cover
544 raise ex
545 except Exception as ex: # pragma: no cover
546 osvvmContext.RaiseException(ex)
549@export
550def GetVHDLVersion() -> int:
551 """
552 This function implements the behavior of OSVVM's ``GetVHDLVersion`` procedure.
554 Returns the currently set VHDL language revision.
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.
559 .. seealso::
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}'."))
577 except OSVVMException as ex: # pragma: no cover
578 raise ex
579 except Exception as ex: # pragma: no cover
580 osvvmContext.RaiseException(ex)
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."))
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."))
599@export
600def FileExists(file: str) -> bool:
601 """
602 This function implements the behavior of OSVVM's ``FileExists`` procedure.
604 Check if the given file exists.
606 :param file: File name.
607 :returns: True, if file exists, otherwise False.
608 :raises ValueError: When parameter 'file' is empty.
610 .. seealso::
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.")
618 return (osvvmContext._currentDirectory / file).is_file()
620 except OSVVMException as ex: # pragma: no cover
621 raise ex
622 except Exception as ex: # pragma: no cover
623 osvvmContext.RaiseException(ex)
626@export
627def DirectoryExists(directory: str) -> bool:
628 """
629 This function implements the behavior of OSVVM's ``DirectoryExists`` procedure.
631 Check if the given directory exists.
633 :param directory: Directory name.
634 :returns: True, if directory exists, otherwise False.
635 :raises ValueError: When parameter 'directory' is empty.
637 .. seealso::
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.")
645 return (osvvmContext._currentDirectory / directory).is_dir()
647 except OSVVMException as ex: # pragma: no cover
648 raise ex
649 except Exception as ex: # pragma: no cover
650 osvvmContext.RaiseException(ex)
653@export
654def ChangeWorkingDirectory(directory: str) -> None:
655 """
656 This function implements the behavior of OSVVM's ``ChangeWorkingDirectory`` procedure.
658 Change the current directory (virtual working directory) to the given directory.
660 :param directory: Directory name.
661 :raises ValueError: When parameter 'directory' is empty.
662 :raises OSVVMException: When the referenced directory doesn't exist.
664 .. seealso::
666 * :func:`build`
667 * :func:`include`
668 """
669 try:
670 if directory == "":
671 raise ValueError(f"Parameter 'directory' is empty.")
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))
677 except OSVVMException as ex: # pragma: no cover
678 raise ex
679 except Exception as ex: # pragma: no cover
680 osvvmContext.RaiseException(ex)
683@export
684def FindOsvvmSettingsDirectory(*args) -> None:
685 """
686 Not implemented by pyEDAA.OSVVM.
687 """
688 osvvmContext.RaiseException(NotImplementedError(f"Procedure 'FindOsvvmSettingsDirectory' is not implemented."))
691@export
692def CreateOsvvmScriptSettingsPkg(*args) -> None:
693 """
694 Not implemented by pyEDAA.OSVVM.
695 """
696 osvvmContext.RaiseException(NotImplementedError(f"Procedure 'CreateOsvvmScriptSettingsPkg' is not implemented."))
699@export
700def noop(*args) -> None:
701 """
702 A no-operation dummy procedure accepting any positional arguments.
704 :param args: Any arguments
705 """
708@export
709def ConstraintFile(file: str, *options: int) -> int:
710 """
711 This function implements the behavior of pyEDAA's ``ConstraintFile`` procedure.
713 Create and register a :class:`~pyEDAA.OSVVM.Project.ConstraintFile` option and return the options unique ID.
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()
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)
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)
744 if not fullPath.exists(): # pragma: no cover
745 osvvmContext.RaiseException(OSVVMException(f"Constraint file '{fullPath}' can't be found."), FileNotFoundError(fullPath))
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)."))
750 constraint = OSVVM_ConstraintFile(Path(file), **properties)
751 return osvvmContext.AddOption(constraint)
753 except OSVVMException as ex: # pragma: no cover
754 raise ex
755 except Exception as ex: # pragma: no cover
756 osvvmContext.RaiseException(ex)
759@export
760def ScopeToRef(refName: str) -> int:
761 """
762 This function implements the behavior of pyEDAA's ``ScopeToRef`` procedure.
764 Create and register a :class:`~pyEDAA.OSVVM.Project.ScopeToRef` option and return the options unique ID.
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.")
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)
782@export
783def ScopeToCell(cellName: str) -> int:
784 """
785 This function implements the behavior of pyEDAA's ``ScopeToCell`` procedure.
787 Create and register a :class:`~pyEDAA.OSVVM.Project.ScopeToCell` option and return the options unique ID.
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.")
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)