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
« 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.
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 Exception as ex: # pragma: no cover
50 osvvmContext.RaiseException(ex)
51"""
52from pathlib import Path
53from typing import Optional as Nullable
55from pyTooling.Decorators import export
56from pyTooling.Common import getFullyQualifiedName
57from pyVHDLModel import VHDLVersion
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
65@export
66def BuildName(name: str) -> int:
67 """
68 This function implements the behavior of OSVVM's ``BuildName`` procedure.
70 Create and register a :class:`~pyEDAA.OSVVM.Project.BuildName` option and return the options unique ID.
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)
79 except Exception as ex: # pragma: no cover
80 osvvmContext.RaiseException(ex)
83@export
84def build(file: str, *options: int) -> None:
85 """
86 This function implements the behavior of OSVVM's ``build`` procedure.
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.
91 The referenced file gets appended to a list of included files maintained by the context.
93 .. rubric:: pro-file discovery algorithm:
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.
99 .. rubric:: inferring the build name:
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.
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`.
110 .. seealso::
112 * :func:`BuildName`
113 * :func:`include`
114 * :func:`ChangeWorkingDirectory`
115 """
116 try:
117 file = Path(file)
118 buildName = None
120 # Preserve current directory
121 currentDirectory = osvvmContext._currentDirectory
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)
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
139 # If no build name was specified, derive a name from *.pro file.
140 if buildName is None:
141 buildName = file.stem
143 osvvmContext.BeginBuild(buildName)
144 includeFile = osvvmContext.IncludeFile(file)
145 osvvmContext.EvaluateFile(includeFile)
146 osvvmContext.EndBuild()
148 # Restore current directory after recursively evaluating *.pro files.
149 osvvmContext._currentDirectory = currentDirectory
151 except Exception as ex: # pragma: no cover
152 osvvmContext.RaiseException(ex)
155@export
156def include(file: str) -> None:
157 """
158 This function implements the behavior of OSVVM's ``include`` procedure.
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.
163 The referenced file gets appended to a list of included files maintained by the context.
165 .. rubric:: pro-file discovery algorithm:
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.
171 :param file: Explicit path to a ``*.pro`` file or a directory containing an implicitly searched ``*.pro``
172 file.
174 .. seealso::
176 * :func:`build`
177 * :func:`ChangeWorkingDirectory`
178 """
179 try:
180 # Preserve current directory
181 currentDirectory = osvvmContext._currentDirectory
183 includeFile = osvvmContext.IncludeFile(Path(file))
184 osvvmContext.EvaluateFile(includeFile)
186 # Restore current directory after recursively evaluating *.pro files.
187 osvvmContext._currentDirectory = currentDirectory
189 except Exception as ex: # pragma: no cover
190 osvvmContext.RaiseException(ex)
193@export
194def library(libraryName: str, libraryPath: Nullable[str] = None) -> None:
195 """
196 This function implements the behavior of OSVVM's ``library`` procedure.
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.
201 .. hint::
203 All following ``analyze`` calls will use this library as the VHDL source file's VHDL library.
205 .. caution::
207 Parameter `libraryPath` is not yet implemented.
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.
213 .. seealso::
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.")
222 osvvmContext.SetLibrary(libraryName)
224 except Exception as ex: # pragma: no cover
225 osvvmContext.RaiseException(ex)
228@export
229def NoNullRangeWarning() -> int:
230 """
231 This function implements the behavior of OSVVM's ``NoNullRangeWarning`` procedure.
233 Create and register a :class:`~pyEDAA.OSVVM.Project.NoNullRangeWarning` option and return the options unique ID.
235 :returns: The option's unique ID.
236 """
237 try:
238 option = OSVVM_NoNullRangeWarning()
239 return osvvmContext.AddOption(option)
241 except Exception as ex: # pragma: no cover
242 osvvmContext.RaiseException(ex)
245@export
246def analyze(file: str, *options: int) -> None:
247 """
248 This function implements the behavior of OSVVM's ``analyze`` procedure.
250 Analyze an HDL source file.
252 .. rubric:: Supported options:
254 * :func:`NoNullRangeWarning` - disable null-range warnings when analyzing.
255 * :func:`ConstraintFile` - associated constraint file
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`.
265 .. seealso::
267 * :func:`NoNullRangeWarning`
268 * :func:`SetCoverageAnalyzeEnable`
269 * :func:`ConstraintFile`
270 """
271 try:
272 file = Path(file)
273 fullPath = (osvvmContext._currentDirectory / file).resolve()
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)
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)
296 if not fullPath.exists(): # pragma: no cover
297 osvvmContext.RaiseException(OSVVMException(f"Path '{fullPath}' can't be analyzed."), FileNotFoundError(fullPath))
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)."))
309 except Exception as ex: # pragma: no cover
310 osvvmContext.RaiseException(ex)
313@export
314def simulate(toplevelName: str, *options: int) -> None:
315 """
316 This function implements the behavior of OSVVM's ``simulate`` procedure.
318 Simulate a given toplevel entity or configuration name.
320 .. rubric:: Supported options:
322 * :func:`generic` - specify generic values.
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`.
330 .. seealso::
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.")
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)
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)
353 except Exception as ex: # pragma: no cover
354 osvvmContext.RaiseException(ex)
357@export
358def generic(name: str, value: str) -> int:
359 """
360 This function implements the behavior of OSVVM's ``generic`` procedure.
362 Create and register a :class:`~pyEDAA.OSVVM.Project.GenericValue` option and return the options unique ID.
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)
372 except Exception as ex: # pragma: no cover
373 osvvmContext.RaiseException(ex)
376@export
377def TestSuite(name: str) -> None:
378 """
379 This function implements the behavior of OSVVM's ``TestSuite`` procedure.
381 Set or create the currently active :class:`~pyEDAA.OSVVM.Project.Testsuite`.
383 :param name: Name of the OSVVM testsuite.
384 """
385 try:
386 osvvmContext.SetTestsuite(name)
388 except Exception as ex: # pragma: no cover
389 osvvmContext.RaiseException(ex)
392@export
393def TestName(name: str) -> None:
394 """
395 This function implements the behavior of OSVVM's ``TestName`` procedure.
397 Create a new :class:`~pyEDAA.OSVVM.Project.Testcase`.
399 :param name: Name of the OSVVM testcase.
400 """
401 try:
402 osvvmContext.AddTestcase(name)
404 except Exception as ex: # pragma: no cover
405 osvvmContext.RaiseException(ex)
408@export
409def RunTest(file: str, *options: int) -> None:
410 """
411 This function implements the behavior of OSVVM's ``RunTest`` procedure.
413 Simulate a given toplevel entity or configuration name. Infer testcase name from filename.
415 .. rubric:: Supported options:
417 * :func:`generic` - specify generic values.
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`.
426 .. seealso::
428 * :func:`generic`
429 * :func:`simulate`
430 """
431 try:
432 file = Path(file)
433 testName = file.stem
435 # Analyze file
436 fullPath = (osvvmContext._currentDirectory / file).resolve()
438 if not fullPath.exists(): # pragma: no cover
439 osvvmContext.RaiseException(OSVVMException(f"Path '{fullPath}' can't be analyzed."), FileNotFoundError(fullPath))
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)."))
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)
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)
463 except Exception as ex: # pragma: no cover
464 osvvmContext.RaiseException(ex)
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."))
475@export
476def LinkLibraryDirectory(libraryDirectory: str):
477 """
478 Not implemented by pyEDAA.OSVVM.
479 """
480 osvvmContext.RaiseException(NotImplementedError(f"Procedure 'LinkLibraryDirectory' is not implemented."))
483@export
484def SetVHDLVersion(value: str) -> None:
485 """
486 This function implements the behavior of OSVVM's ``SetVHDLVersion`` procedure.
488 Set the used VHDL language revision.
490 .. hint::
492 All following ``analyze`` calls will use this VHDL revision.
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.
498 .. seealso::
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)
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}'."))
524 except Exception as ex: # pragma: no cover
525 osvvmContext.RaiseException(ex)
528@export
529def GetVHDLVersion() -> int:
530 """
531 This function implements the behavior of OSVVM's ``GetVHDLVersion`` procedure.
533 Returns the currently set VHDL language revision.
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.
538 .. seealso::
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}'."))
556 except Exception as ex: # pragma: no cover
557 osvvmContext.RaiseException(ex)
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."))
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."))
576@export
577def FileExists(file: str) -> bool:
578 """
579 This function implements the behavior of OSVVM's ``FileExists`` procedure.
581 Check if the given file exists.
583 :param file: File name.
584 :returns: True, if file exists, otherwise False.
585 :raises ValueError: When parameter 'file' is empty.
587 .. seealso::
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.")
595 return (osvvmContext._currentDirectory / file).is_file()
597 except Exception as ex: # pragma: no cover
598 osvvmContext.RaiseException(ex)
601@export
602def DirectoryExists(directory: str) -> bool:
603 """
604 This function implements the behavior of OSVVM's ``DirectoryExists`` procedure.
606 Check if the given directory exists.
608 :param directory: Directory name.
609 :returns: True, if directory exists, otherwise False.
610 :raises ValueError: When parameter 'directory' is empty.
612 .. seealso::
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.")
620 return (osvvmContext._currentDirectory / directory).is_dir()
622 except Exception as ex: # pragma: no cover
623 osvvmContext.RaiseException(ex)
626@export
627def ChangeWorkingDirectory(directory: str) -> None:
628 """
629 This function implements the behavior of OSVVM's ``ChangeWorkingDirectory`` procedure.
631 Change the current directory (virtual working directory) to the given directory.
633 :param directory: Directory name.
634 :raises ValueError: When parameter 'directory' is empty.
635 :raises OSVVMException: When the referenced directory doesn't exist.
637 .. seealso::
639 * :func:`build`
640 * :func:`include`
641 """
642 try:
643 if directory == "":
644 raise ValueError(f"Parameter 'directory' is empty.")
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))
650 except Exception as ex: # pragma: no cover
651 osvvmContext.RaiseException(ex)
654@export
655def FindOsvvmSettingsDirectory(*args) -> str:
656 """
657 .. todo::
659 Needs documentation.
660 """
661 return osvvmContext.CurrentDirectory.as_posix()
664@export
665def CreateOsvvmScriptSettingsPkg(*args) -> None:
666 """
667 Not implemented by pyEDAA.OSVVM.
668 """
669 osvvmContext.RaiseException(NotImplementedError(f"Procedure 'CreateOsvvmScriptSettingsPkg' is not implemented."))
672@export
673def noop(*args) -> None:
674 """
675 A no-operation dummy procedure accepting any positional arguments.
677 :param args: Any arguments
678 """
681@export
682def ConstraintFile(file: str, *options: int) -> int:
683 """
684 This function implements the behavior of pyEDAA's ``ConstraintFile`` procedure.
686 Create and register a :class:`~pyEDAA.OSVVM.Project.ConstraintFile` option and return the options unique ID.
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()
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)
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)
717 if not fullPath.exists(): # pragma: no cover
718 osvvmContext.RaiseException(OSVVMException(f"Constraint file '{fullPath}' can't be found."), FileNotFoundError(fullPath))
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)."))
723 constraint = OSVVM_ConstraintFile(Path(file), **properties)
724 return osvvmContext.AddOption(constraint)
726 except Exception as ex: # pragma: no cover
727 osvvmContext.RaiseException(ex)
730@export
731def ScopeToRef(refName: str) -> int:
732 """
733 This function implements the behavior of pyEDAA's ``ScopeToRef`` procedure.
735 Create and register a :class:`~pyEDAA.OSVVM.Project.ScopeToRef` option and return the options unique ID.
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.")
745 ref = OSVVM_ScopeToRef(refName)
746 return osvvmContext.AddOption(ref)
748 except Exception as ex: # pragma: no cover
749 osvvmContext.RaiseException(ex)
752@export
753def ScopeToCell(cellName: str) -> int:
754 """
755 This function implements the behavior of pyEDAA's ``ScopeToCell`` procedure.
757 Create and register a :class:`~pyEDAA.OSVVM.Project.ScopeToCell` option and return the options unique ID.
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.")
767 ref = OSVVM_ScopeToCell(cellName)
768 return osvvmContext.AddOption(ref)
770 except Exception as ex: # pragma: no cover
771 osvvmContext.RaiseException(ex)