Source code for pyVHDLModel

# ==================================================================================================================== #
#             __     ___   _ ____  _     __  __           _      _                                                     #
#   _ __  _   \ \   / / | | |  _ \| |   |  \/  | ___   __| | ___| |                                                    #
#  | '_ \| | | \ \ / /| |_| | | | | |   | |\/| |/ _ \ / _` |/ _ \ |                                                    #
#  | |_) | |_| |\ V / |  _  | |_| | |___| |  | | (_) | (_| |  __/ |                                                    #
#  | .__/ \__, | \_/  |_| |_|____/|_____|_|  |_|\___/ \__,_|\___|_|                                                    #
#  |_|    |___/                                                                                                        #
# ==================================================================================================================== #
# Authors:                                                                                                             #
#   Patrick Lehmann                                                                                                    #
#                                                                                                                      #
# License:                                                                                                             #
# ==================================================================================================================== #
# Copyright 2017-2024 Patrick Lehmann - Boetzingen, Germany                                                            #
# Copyright 2016-2017 Patrick Lehmann - Dresden, Germany                                                               #
#                                                                                                                      #
# Licensed under the Apache License, Version 2.0 (the "License");                                                      #
# you may not use this file except in compliance with the License.                                                     #
# You may obtain a copy of the License at                                                                              #
#                                                                                                                      #
#   http://www.apache.org/licenses/LICENSE-2.0                                                                         #
#                                                                                                                      #
# Unless required by applicable law or agreed to in writing, software                                                  #
# distributed under the License is distributed on an "AS IS" BASIS,                                                    #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.                                             #
# See the License for the specific language governing permissions and                                                  #
# limitations under the License.                                                                                       #
#                                                                                                                      #
# SPDX-License-Identifier: Apache-2.0                                                                                  #
# ==================================================================================================================== #
#
"""
**An abstract VHDL language model.**

This package provides a unified abstract language model for VHDL. Projects reading from source files can derive own
classes and implement additional logic to create a concrete language model for their tools.

Projects consuming pre-processed VHDL data (parsed, analyzed or elaborated) can build higher level features and services
on such a model, while supporting multiple frontends.

.. admonition:: Copyright Information

   :copyright: Copyright 2017-2024 Patrick Lehmann - Bötzingen, Germany
   :copyright: Copyright 2016-2017 Patrick Lehmann - Dresden, Germany
   :license: Apache License, Version 2.0
"""
__author__ =    "Patrick Lehmann"
__email__ =     "Paebbels@gmail.com"
__copyright__ = "2016-2024, Patrick Lehmann"
__license__ =   "Apache License, Version 2.0"
__version__ =   "0.29.2"


from enum                      import unique, Enum, Flag, auto
from pathlib                   import Path
from sys                       import version_info

from typing                    import Union, Dict, cast, List, Generator, Optional as Nullable

from pyTooling.Common          import getFullyQualifiedName
from pyTooling.Decorators      import export, readonly
from pyTooling.Graph           import Graph, Vertex, Edge

from pyVHDLModel.Exception     import VHDLModelException
from pyVHDLModel.Exception     import LibraryExistsInDesignError, LibraryRegisteredToForeignDesignError, LibraryNotRegisteredError, EntityExistsInLibraryError
from pyVHDLModel.Exception     import ArchitectureExistsInLibraryError, PackageExistsInLibraryError, PackageBodyExistsError, ConfigurationExistsInLibraryError
from pyVHDLModel.Exception     import ContextExistsInLibraryError, ReferencedLibraryNotExistingError
from pyVHDLModel.Base          import ModelEntity, NamedEntityMixin, MultipleNamedEntityMixin, DocumentedEntityMixin
from pyVHDLModel.Expression    import UnaryExpression, BinaryExpression, TernaryExpression
from pyVHDLModel.Namespace     import Namespace
from pyVHDLModel.Object        import Obj, Signal, Constant, DeferredConstant
from pyVHDLModel.Symbol        import PackageReferenceSymbol, AllPackageMembersReferenceSymbol, PackageMemberReferenceSymbol, SimpleObjectOrFunctionCallSymbol
from pyVHDLModel.Concurrent    import EntityInstantiation, ComponentInstantiation, ConfigurationInstantiation
from pyVHDLModel.DesignUnit    import DesignUnit, PrimaryUnit, Architecture, PackageBody, Context, Entity, Configuration, Package
from pyVHDLModel.PSLModel      import VerificationUnit, VerificationProperty, VerificationMode
from pyVHDLModel.Instantiation import PackageInstantiation
from pyVHDLModel.Type          import IntegerType, PhysicalType, ArrayType, RecordType


[docs] @export @unique class VHDLVersion(Enum): """ An enumeration for all possible version numbers for VHDL and VHDL-AMS. A version can be given as integer or string and is represented as a unified enumeration value. This enumeration supports compare operators. """ Any = -1 #: Any VHDL87 = 87 #: VHDL-1987 VHDL93 = 93 #: VHDL-1993 AMS93 = 1993 #: VHDL-AMS-1993 AMS99 = 1999 #: VHDL-AMS-1999 VHDL2000 = 2000 #: VHDL-2000 VHDL2002 = 2002 #: VHDL-2002 VHDL2008 = 2008 #: VHDL-2008 AMS2017 = 2017 #: VHDL-AMS-2017 VHDL2019 = 2019 #: VHDL-2019 Latest = 10000 #: Latest VHDL (2019) __VERSION_MAPPINGS__: Dict[Union[int, str], Enum] = { -1: Any, 87: VHDL87, 93: VHDL93, # 93: AMS93, 99: AMS99, 0: VHDL2000, 2: VHDL2002, 8: VHDL2008, 17: AMS2017, 19: VHDL2019, 1987: VHDL87, # 1993: VHDL93, 1993: AMS93, 1999: AMS99, 2000: VHDL2000, 2002: VHDL2002, 2008: VHDL2008, 2017: AMS2017, 2019: VHDL2019, 10000: Latest, "Any": Any, "87": VHDL87, "93": VHDL93, # "93": AMS93, "99": AMS99, "00": VHDL2000, "02": VHDL2002, "08": VHDL2008, "17": AMS2017, "19": VHDL2019, "1987": VHDL87, # "1993": VHDL93, "1993": AMS93, "1999": AMS99, "2000": VHDL2000, "2002": VHDL2002, "2008": VHDL2008, "2017": AMS2017, "2019": VHDL2019, "Latest": Latest, } #: Dictionary of VHDL and VHDL-AMS year codes variants as integer and strings for mapping to unique enum values.
[docs] def __init__(self, *_) -> None: """Patch the embedded MAP dictionary""" for k, v in self.__class__.__VERSION_MAPPINGS__.items(): if (not isinstance(v, self.__class__)) and (v == self.value): self.__class__.__VERSION_MAPPINGS__[k] = self
[docs] @classmethod def Parse(cls, value: Union[int, str]) -> "VHDLVersion": """ Parses a VHDL or VHDL-AMS year code as integer or string to an enum value. :param value: VHDL/VHDL-AMS year code. :returns: Enumeration value. :raises ValueError: If the year code is not recognized. """ try: return cls.__VERSION_MAPPINGS__[value] except KeyError: raise ValueError(f"Value '{value!s}' cannot be parsed to member of {cls.__name__}.")
[docs] def __lt__(self, other: Any) -> bool: """ Compare two VHDL/VHDL-AMS versions if the version is less than the second operand. :param other: Parameter to compare against. :returns: True if version is less than the second operand. :raises TypeError: If parameter ``other`` is not of type :class:`VHDLVersion`. """ if isinstance(other, VHDLVersion): return self.value < other.value else: raise TypeError("Second operand is not of type 'VHDLVersion'.")
[docs] def __le__(self, other: Any) -> bool: """ Compare two VHDL/VHDL-AMS versions if the version is less or equal than the second operand. :param other: Parameter to compare against. :returns: True if version is less or equal than the second operand. :raises TypeError: If parameter ``other`` is not of type :class:`VHDLVersion`. """ if isinstance(other, VHDLVersion): return self.value <= other.value else: raise TypeError("Second operand is not of type 'VHDLVersion'.")
[docs] def __gt__(self, other: Any) -> bool: """ Compare two VHDL/VHDL-AMS versions if the version is greater than the second operand. :param other: Parameter to compare against. :returns: True if version is greater than the second operand. :raises TypeError: If parameter ``other`` is not of type :class:`VHDLVersion`. """ if isinstance(other, VHDLVersion): return self.value > other.value else: raise TypeError("Second operand is not of type 'VHDLVersion'.")
[docs] def __ge__(self, other: Any) -> bool: """ Compare two VHDL/VHDL-AMS versions if the version is greater or equal than the second operand. :param other: Parameter to compare against. :returns: True if version is greater or equal than the second operand. :raises TypeError: If parameter ``other`` is not of type :class:`VHDLVersion`. """ if isinstance(other, VHDLVersion): return self.value >= other.value else: raise TypeError("Second operand is not of type 'VHDLVersion'.")
[docs] def __ne__(self, other: Any) -> bool: """ Compare two VHDL/VHDL-AMS versions if the version is unequal to the second operand. :param other: Parameter to compare against. :returns: True if version is unequal to the second operand. :raises TypeError: If parameter ``other`` is not of type :class:`VHDLVersion`. """ if isinstance(other, VHDLVersion): return self.value != other.value else: raise TypeError("Second operand is not of type 'VHDLVersion'.")
[docs] def __eq__(self, other: Any) -> bool: """ Compare two VHDL/VHDL-AMS versions if the version is equal to the second operand. :param other: Parameter to compare against. :returns: True if version is equal to the second operand. :raises TypeError: If parameter ``other`` is not of type :class:`VHDLVersion`. """ if isinstance(other, VHDLVersion): if (self is self.__class__.Any) or (other is self.__class__.Any): return True else: return self.value == other.value else: raise TypeError("Second operand is not of type 'VHDLVersion'.")
@readonly def IsVHDL(self) -> bool: """ Checks if the version is a VHDL (not VHDL-AMS) version. :returns: True if version is a VHDL version. """ return self in (self.VHDL87, self.VHDL93, self.VHDL2002, self.VHDL2008, self.VHDL2019) @readonly def IsAMS(self) -> bool: """ Checks if the version is a VHDL-AMS (not VHDL) version. :returns: True if version is a VHDL-AMS version. """ return self in (self.AMS93, self.AMS99, self.AMS2017)
[docs] def __str__(self) -> str: """ Formats the VHDL version to pattern ``VHDL'xx`` or in case of VHDL-AMS to ``VHDL-AMS'xx``. :return: Formatted VHDL/VHDL-AMS version. """ if self.value == self.Any.value: return "VHDL'Any" elif self.value == self.Latest.value: return "VHDL'Latest" year = str(self.value)[-2:] if self.IsVHDL: return f"VHDL'{year}" else: return f"VHDL-AMS'{year}"
[docs] def __repr__(self) -> str: """ Formats the VHDL/VHDL-AMS version to pattern ``xxxx``. :return: Formatted VHDL/VHDL-AMS version. """ if self.value == self.Any.value: return "Any" elif self.value == self.Latest.value: return "Latest" else: return str(self.value)
[docs] @export @unique class ObjectClass(Enum): """ An ``ObjectClass`` is an enumeration and represents an object's class (``constant``, ``signal``, ...). In case no *object class* is defined, ``Default`` is used, so the *object class* is inferred from context. """ Default = 0 #: Object class not defined, thus it's context dependent. Constant = 1 #: Constant Variable = 2 #: Variable Signal = 3 #: Signal File = 4 #: File Type = 5 #: Type # FIXME: Package? Procedure = 6 #: Procedure Function = 7 #: Function
[docs] def __str__(self) -> str: """ Formats the object class. :return: Formatted object class. """ return ("", "constant", "variable", "signal", "file", "type", "procedure", "function")[cast(int, self.value)] # TODO: check performance
[docs] @export @unique class DesignUnitKind(Flag): """ A ``DesignUnitKind`` is an enumeration and represents the kind of design unit (``Entity``, ``Architecture``, ...). """ Context = auto() #: Context Package = auto() #: Package PackageBody = auto() #: Package Body Entity = auto() #: Entity Architecture = auto() #: Architecture Configuration = auto() #: Configuration Primary = Context | Configuration | Entity | Package #: List of primary design units. Secondary = PackageBody | Architecture #: List of secondary design units. WithContext = Configuration | Package | Entity | PackageBody | Architecture #: List of design units with a context. WithDeclaredItems = Package | Entity | PackageBody | Architecture #: List of design units having a declaration region. All = Primary | Secondary #: List of all design units.
[docs] @export @unique class DependencyGraphVertexKind(Flag): """ A ``DependencyGraphVertexKind`` is an enumeration and represents the kind of vertex in the dependency graph. """ Document = auto() #: A document (VHDL source file). Library = auto() #: A VHDL library. Context = auto() #: A context design unit. Package = auto() #: A package design unit. PackageBody = auto() #: A package body design unit. Entity = auto() #: A entity design unit. Architecture = auto() #: A architecture design unit. Component = auto() #: A VHDL component. Configuration = auto() #: A configuration design unit.
[docs] @export @unique class DependencyGraphEdgeKind(Flag): """ A ``DependencyGraphEdgeKind`` is an enumeration and represents the kind of edge in the dependency graph. """ Document = auto() Library = auto() Context = auto() Package = auto() Entity = auto() # Architecture = auto() Configuration = auto() Component = auto() DeclaredIn = auto() Order = auto() Reference = auto() Implementation = auto() Instantiation = auto() SourceFile = Document | DeclaredIn CompileOrder = Document | Order LibraryClause = Library | Reference UseClause = Package | Reference ContextReference = Context | Reference EntityImplementation = Entity | Implementation PackageImplementation = Package | Implementation EntityInstantiation = Entity | Instantiation ComponentInstantiation = Component | Instantiation ConfigurationInstantiation = Configuration | Instantiation
[docs] @export @unique class ObjectGraphVertexKind(Flag): """ A ``ObjectGraphVertexKind`` is an enumeration and represents the kind of vertex in the object graph. """ Type = auto() Subtype = auto() Constant = auto() DeferredConstant = auto() Variable = auto() Signal = auto() File = auto() Alias = auto()
[docs] @export @unique class ObjectGraphEdgeKind(Flag): """ A ``ObjectGraphEdgeKind`` is an enumeration and represents the kind of edge in the object graph. """ BaseType = auto() Subtype = auto() ReferenceInExpression = auto()
[docs] @export class Design(ModelEntity): """ A ``Design`` represents set of VHDL libraries as well as all loaded and analysed source files (see :class:`~pyVHDLModel.Document`). It's the root of this code document-object-model (CodeDOM). It contains at least one VHDL library (see :class:`~pyVHDLModel.Library`). When the design is analysed (see :meth:`Analyze`), multiple graph data structures will be created and populated with vertices and edges. As a first result, the design's compile order and hierarchy can be iterated. As a second result, the design's *top-level* is identified and referenced from the design (see :attr:`TopLevel`). The *design* contains references to the following graphs: * :attr:`DependencyGraph` * :attr:`CompileOrderGraph` * :attr:`HierarchyGraph` * :attr:`ObjectGraph` """ _name: Nullable[str] #: Name of the design _libraries: Dict[str, 'Library'] #: List of all libraries defined for a design. _documents: List['Document'] #: List of all documents loaded for a design. _dependencyGraph: Graph[None, None, None, None, None, None, None, None, str, DesignUnit, None, None, None, None, None, None, None, None, None, None, None, None, None] #: The graph of all dependencies in the designs. _compileOrderGraph: Graph[None, None, None, None, None, None, None, None, None, 'Document', None, None, None, None, None, None, None, None, None, None, None, None, None] #: A graph derived from dependency graph containing the order of documents for compilation. _hierarchyGraph: Graph[None, None, None, None, None, None, None, None, str, DesignUnit, None, None, None, None, None, None, None, None, None, None, None, None, None] #: A graph derived from dependency graph containing the design hierarchy. _objectGraph: Graph[None, None, None, None, None, None, None, None, str, Obj, None, None, None, None, None, None, None, None, None, None, None, None, None] #: The graph of all types and objects in the design. _toplevel: Union[Entity, Configuration] #: When computed, the toplevel design unit is cached in this field.
[docs] def __init__(self, name: Nullable[str] = None) -> None: """ Initializes a VHDL design. :param name: Name of the design. """ super().__init__() self._name = name self._libraries = {} self._documents = [] self._compileOrderGraph = Graph() self._dependencyGraph = Graph() self._hierarchyGraph = Graph() self._objectGraph = Graph() self._toplevel = None
@readonly def Libraries(self) -> Dict[str, 'Library']: """ Read-only property to access the dictionary of library names and VHDL libraries (:attr:`_libraries`). :returns: A dictionary of library names and VHDL libraries. """ return self._libraries @readonly def Documents(self) -> List['Document']: """ Read-only property to access the list of all documents (VHDL source files) loaded for this design (:attr:`_documents`). :returns: A list of all documents. """ return self._documents @readonly def CompileOrderGraph(self) -> Graph: """ Read-only property to access the compile-order graph (:attr:`_compileOrderGraph`). :returns: Reference to the compile-order graph. """ return self._compileOrderGraph @readonly def DependencyGraph(self) -> Graph: """ Read-only property to access the dependency graph (:attr:`_dependencyGraph`). :returns: Reference to the dependency graph. """ return self._dependencyGraph @readonly def HierarchyGraph(self) -> Graph: """ Read-only property to access the hierarchy graph (:attr:`_hierarchyGraph`). :returns: Reference to the hierarchy graph. """ return self._hierarchyGraph @readonly def ObjectGraph(self) -> Graph: """ Read-only property to access the object graph (:attr:`_objectGraph`). :returns: Reference to the object graph. """ return self._objectGraph @readonly def TopLevel(self) -> Union[Entity, Configuration]: """ Read-only property to access the design's *top-level* (:attr:`_toplevel`). When called the first time, the hierarchy graph is checked for its root elements. When there is only one root element in the graph, a new field ``toplevel`` is added to :attr:`_hierarchyGraph` referencing that single element. In addition, the result is cached in :attr:`_toplevel`. :returns: Reference to the design's *top-level*. :raises VHDLModelException: If the hierarchy graph is not yet computed from dependency graph. :raises VHDLModelException: If there is more than one *top-level*. """ # Check for cached result if self._toplevel is not None: return self._toplevel if self._hierarchyGraph.EdgeCount == 0: raise VHDLModelException(f"Hierarchy is not yet computed from dependency graph.") roots = tuple(self._hierarchyGraph.IterateRoots()) if len(roots) == 1: toplevel = roots[0] self._hierarchyGraph["toplevel"] = toplevel self._toplevel = toplevel.Value return toplevel.Value else: raise VHDLModelException(f"Found more than one toplevel: {', '.join(roots)}")
[docs] def LoadStdLibrary(self) -> 'Library': """ Load the predefined VHDL library ``std`` into the design. This will create a virtual source code file ``std.vhdl`` and register VHDL design units of library ``std`` to that file. :returns: The library object of library ``std``. """ from pyVHDLModel.STD import Std doc = Document(Path("std.vhdl"), parent=self) library = Std() for designUnit in library.IterateDesignUnits(): doc._AddDesignUnit(designUnit) self.AddLibrary(library) return library
[docs] def LoadIEEELibrary(self) -> 'Library': """ Load the predefined VHDL library ``ieee`` into the design. This will create a virtual source code file ``ieee.vhdl`` and register VHDL design units of library ``ieee`` to that file. :returns: The library object of library ``ieee``. """ from pyVHDLModel.IEEE import Ieee doc = Document(Path("ieee.vhdl"), parent=self) library = Ieee() for designUnit in library.IterateDesignUnits(): doc._AddDesignUnit(designUnit) self.AddLibrary(library) return library
[docs] def AddLibrary(self, library: 'Library') -> None: """ Add a VHDL library to the design. Ensure the libraries name doesn't collide with existing libraries in the design. |br| If ok, set the libraries parent reference to the design. :param library: Library object to loaded. :raises LibraryExistsInDesignError: If the library already exists in the design. :raises LibraryRegisteredToForeignDesignError: If library is already used by a different design. """ libraryIdentifier = library.NormalizedIdentifier if libraryIdentifier in self._libraries: raise LibraryExistsInDesignError(library) if library._parent is not None: raise LibraryRegisteredToForeignDesignError(library) self._libraries[libraryIdentifier] = library library._parent = self
[docs] def GetLibrary(self, libraryName: str) -> 'Library': """ Return an (existing) VHDL library object of name ``libraryName``. If the requested VHDL library doesn't exist, a new VHDL library with that name will be created. :param libraryName: Name of the requested VHDL library. :returns: The VHDL library object. """ libraryIdentifier = libraryName.lower() try: return self._libraries[libraryIdentifier] except KeyError: lib = Library(libraryName, parent=self) self._libraries[libraryIdentifier] = lib lib._parent = self return lib
# TODO: allow overloaded parameter library to be str?
[docs] def AddDocument(self, document: 'Document', library: 'Library') -> None: """ Add a document (VHDL source file) to the design and register all embedded design units to the given VHDL library. .. rubric:: Algorithm 1. Iterate all entities in the document 1. Check if entity name might exist in target library. 2. Add entity to library and update library membership. 2. Iterate all architectures in the document 1. Check if architecture name might exist in target library. 2. Add architecture to library and update library membership. 3. Iterate all packages in the document 1. Check if package name might exist in target library. 2. Add package to library and update library membership. 4. Iterate all package bodies in the document 1. Check if package body name might exist in target library. 2. Add package body to library and update library membership. 5. Iterate all configurations in the document 1. Check if configuration name might exist in target library. 2. Add configuration to library and update library membership. 6. Iterate all contexts in the document 1. Check if context name might exist in target library. 2. Add context to library and update library membership. :param document: The VHDL source code file. :param library: The VHDL library used to register the embedded design units to. :raises LibraryNotRegisteredError: If the given VHDL library is not a library in the design. :raises EntityExistsInLibraryError: If the processed entity's name is already existing in the VHDL library. :raises ArchitectureExistsInLibraryError: If the processed architecture's name is already existing in the VHDL library. :raises PackageExistsInLibraryError: If the processed package's name is already existing in the VHDL library. :raises PackageBodyExistsError: If the processed package body's name is already existing in the VHDL library. :raises ConfigurationExistsInLibraryError: If the processed configuration's name is already existing in the VHDL library. :raises ContextExistsInLibraryError: If the processed context's name is already existing in the VHDL library. """ # FIXME: this checks for the library name, but not the object # should the libraries parent be checked too? if library._normalizedIdentifier not in self._libraries: raise LibraryNotRegisteredError(library) self._documents.append(document) document._parent = self for entityIdentifier, entity in document._entities.items(): if entityIdentifier in library._entities: raise EntityExistsInLibraryError(entity, library) library._entities[entityIdentifier] = entity entity.Library = library for entityIdentifier, architectures in document._architectures.items(): try: architecturesPerEntity = library._architectures[entityIdentifier] for architectureIdentifier, architecture in architectures.items(): if architectureIdentifier in architecturesPerEntity: raise ArchitectureExistsInLibraryError(architecture, library._entities[entityIdentifier], library) architecturesPerEntity[architectureIdentifier] = architecture architecture.Library = library except KeyError: architecturesPerEntity = document._architectures[entityIdentifier].copy() library._architectures[entityIdentifier] = architecturesPerEntity for architecture in architecturesPerEntity.values(): architecture.Library = library for packageIdentifier, package in document._packages.items(): if packageIdentifier in library._packages: raise PackageExistsInLibraryError(package, library) library._packages[packageIdentifier] = package package.Library = library for packageBodyIdentifier, packageBody in document._packageBodies.items(): if packageBodyIdentifier in library._packageBodies: raise PackageBodyExistsError(packageBody, library) library._packageBodies[packageBodyIdentifier] = packageBody packageBody.Library = library for configurationIdentifier, configuration in document._configurations.items(): if configurationIdentifier in library._configurations: raise ConfigurationExistsInLibraryError(configuration, library) library._configurations[configurationIdentifier] = configuration configuration.Library = library for contextIdentifier, context in document._contexts.items(): if contextIdentifier in library._contexts: raise ContextExistsInLibraryError(context, library) library._contexts[contextIdentifier] = context context.Library = library
[docs] def IterateDesignUnits(self, filter: DesignUnitKind = DesignUnitKind.All) -> Generator[DesignUnit, None, None]: """ Iterate all design units in the design. A union of :class:`DesignUnitKind` values can be given to filter the returned result for suitable design units. .. rubric:: Algorithm 1. Iterate all VHDL libraries. 1. Iterate all contexts in that library. 2. Iterate all packages in that library. 3. Iterate all package bodies in that library. 4. Iterate all entites in that library. 5. Iterate all architectures in that library. 6. Iterate all configurations in that library. :param filter: An enumeration with possibly multiple flags to filter the returned design units. :returns: A generator to iterate all matched design units in the design. .. seealso:: :meth:`pyVHDLModel.Library.IterateDesignUnits` Iterate all design units in the library. :meth:`pyVHDLModel.Document.IterateDesignUnits` Iterate all design units in the document. """ for library in self._libraries.values(): yield from library.IterateDesignUnits(filter)
[docs] def Analyze(self) -> None: """ Analyze the whole design. .. rubric:: Algorithm 1. Analyze dependencies of design units. |br| This will also yield the design hierarchy and the compiler order. 2. Analyze dependencies of types and objects. .. seealso:: :meth:`AnalyzeDependencies` Analyze the dependencies of design units. :meth:`AnalyzeObjects` Analyze the dependencies of types and objects. """ self.AnalyzeDependencies() self.AnalyzeObjects()
[docs] def AnalyzeDependencies(self) -> None: """ Analyze the dependencies of design units. .. rubric:: Algorithm 1. Create all vertices of the dependency graph by iterating all design units in all libraries. |br| |rarr| :meth:`CreateDependencyGraph` 2. Create the compile order graph. |br| |rarr| :meth:`CreateCompileOrderGraph` 3. Index all packages. |br| |rarr| :meth:`IndexPackages` 4. Index all architectures. |br| |rarr| :meth:`IndexArchitectures` 5. Link all contexts |br| |rarr| :meth:`LinkContexts` 6. Link all architectures. |br| |rarr| :meth:`LinkArchitectures` 7. Link all package bodies. |br| |rarr| :meth:`LinkPackageBodies` 8. Link all library references. |br| |rarr| :meth:`LinkLibraryReferences` 9. Link all package references. |br| |rarr| :meth:`LinkPackageReferences` 10. Link all context references. |br| |rarr| :meth:`LinkContextReferences` 11. Link all components. |br| |rarr| :meth:`LinkComponents` 12. Link all instantiations. |br| |rarr| :meth:`LinkInstantiations` 13. Create the hierarchy graph. |br| |rarr| :meth:`CreateHierarchyGraph` 14. Compute the compile order. |br| |rarr| :meth:`ComputeCompileOrder` """ self.CreateDependencyGraph() self.CreateCompileOrderGraph() self.IndexPackages() self.IndexArchitectures() self.LinkContexts() self.LinkArchitectures() self.LinkPackageBodies() self.LinkLibraryReferences() self.LinkPackageReferences() self.LinkContextReferences() self.LinkComponents() self.LinkInstantiations() self.CreateHierarchyGraph() self.ComputeCompileOrder()
[docs] def AnalyzeObjects(self) -> None: """ Analyze the dependencies of types and objects. .. rubric:: Algorithm 1. Index all entities. |br| |rarr| :meth:`IndexEntities` 2. Index all package bodies. |br| |rarr| :meth:`IndexPackageBodies` 3. Import objects. |br| |rarr| :meth:`ImportObjects` 4. Create the type and object graph. |br| |rarr| :meth:`CreateTypeAndObjectGraph` """ self.IndexEntities() self.IndexPackageBodies() self.ImportObjects() self.CreateTypeAndObjectGraph()
[docs] def CreateDependencyGraph(self) -> None: """ Create all vertices of the dependency graph by iterating all design units in all libraries. This method will purely create a sea of vertices without any linking between vertices. The edges will be created later by other methods. |br| See :meth:`AnalyzeDependencies` for these methods and their algorithmic order. Each vertex has the following properties: * The vertex' ID is the design unit's identifier. * The vertex' value references the design unit. * A key-value-pair called ``kind`` denotes the vertex's kind as an enumeration value of type :class:`DependencyGraphVertexKind`. * A key-value-pair called ``predefined`` denotes if the referenced design unit is a predefined language entity. .. rubric:: Algorithm 1. Iterate all libraries in the design. * Create a vertex for that library and reference the library by the vertex' value field. |br| In return, set the library's :attr:`~pyVHDLModel.Library._dependencyVertex` field to reference the created vertex. 1. Iterate all contexts in that library. * Create a vertex for that context and reference the context by the vertex' value field. |br| In return, set the context's :attr:`~pyVHDLModel.DesignUnit.Context._dependencyVertex` field to reference the created vertex. 2. Iterate all packages in that library. * Create a vertex for that package and reference the package by the vertex' value field. |br| In return, set the package's :attr:`~pyVHDLModel.DesignUnit.Package._dependencyVertex` field to reference the created vertex. 3. Iterate all package bodies in that library. * Create a vertex for that package body and reference the package body by the vertex' value field. |br| In return, set the package body's :attr:`~pyVHDLModel.DesignUnit.PackageBody._dependencyVertex` field to reference the created vertex. 4. Iterate all entities in that library. * Create a vertex for that entity and reference the entity by the vertex' value field. |br| In return, set the entity's :attr:`~pyVHDLModel.DesignUnit.Entity._dependencyVertex` field to reference the created vertex. 5. Iterate all architectures in that library. * Create a vertex for that architecture and reference the architecture by the vertex' value field. |br| In return, set the architecture's :attr:`~pyVHDLModel.DesignUnit.Architecture._dependencyVertex` field to reference the created vertex. 6. Iterate all configurations in that library. * Create a vertex for that configuration and reference the configuration by the vertex' value field. |br| In return, set the configuration's :attr:`~pyVHDLModel.DesignUnit.Configuration._dependencyVertex` field to reference the created vertex. """ predefinedLibraries = ("std", "ieee") for libraryIdentifier, library in self._libraries.items(): dependencyVertex = Vertex(vertexID=f"{libraryIdentifier}", value=library, graph=self._dependencyGraph) dependencyVertex["kind"] = DependencyGraphVertexKind.Library dependencyVertex["predefined"] = libraryIdentifier in predefinedLibraries library._dependencyVertex = dependencyVertex for contextIdentifier, context in library._contexts.items(): dependencyVertex = Vertex(vertexID=f"{libraryIdentifier}.{contextIdentifier}", value=context, graph=self._dependencyGraph) dependencyVertex["kind"] = DependencyGraphVertexKind.Context dependencyVertex["predefined"] = context._parent._normalizedIdentifier in predefinedLibraries context._dependencyVertex = dependencyVertex for packageIdentifier, package in library._packages.items(): dependencyVertex = Vertex(vertexID=f"{libraryIdentifier}.{packageIdentifier}", value=package, graph=self._dependencyGraph) dependencyVertex["kind"] = DependencyGraphVertexKind.Package dependencyVertex["predefined"] = package._parent._normalizedIdentifier in predefinedLibraries package._dependencyVertex = dependencyVertex for packageBodyIdentifier, packageBody in library._packageBodies.items(): dependencyVertex = Vertex(vertexID=f"{libraryIdentifier}.{packageBodyIdentifier}(body)", value=packageBody, graph=self._dependencyGraph) dependencyVertex["kind"] = DependencyGraphVertexKind.PackageBody dependencyVertex["predefined"] = packageBody._parent._normalizedIdentifier in predefinedLibraries packageBody._dependencyVertex = dependencyVertex for entityIdentifier, entity in library._entities.items(): dependencyVertex = Vertex(vertexID=f"{libraryIdentifier}.{entityIdentifier}", value=entity, graph=self._dependencyGraph) dependencyVertex["kind"] = DependencyGraphVertexKind.Entity dependencyVertex["predefined"] = entity._parent._normalizedIdentifier in predefinedLibraries entity._dependencyVertex = dependencyVertex for entityIdentifier, architectures in library._architectures.items(): for architectureIdentifier, architecture in architectures.items(): dependencyVertex = Vertex(vertexID=f"{libraryIdentifier}.{entityIdentifier}({architectureIdentifier})", value=architecture, graph=self._dependencyGraph) dependencyVertex["kind"] = DependencyGraphVertexKind.Architecture dependencyVertex["predefined"] = architecture._parent._normalizedIdentifier in predefinedLibraries architecture._dependencyVertex = dependencyVertex for configurationIdentifier, configuration in library._configurations.items(): dependencyVertex = Vertex(vertexID=f"{libraryIdentifier}.{configurationIdentifier}", value=configuration, graph=self._dependencyGraph) dependencyVertex["kind"] = DependencyGraphVertexKind.Configuration dependencyVertex["predefined"] = configuration._parent._normalizedIdentifier in predefinedLibraries configuration._dependencyVertex = dependencyVertex
[docs] def CreateCompileOrderGraph(self) -> None: """ Create a compile-order graph with bidirectional references to the dependency graph. Add vertices representing a document (VHDL source file) to the dependency graph. Each "document" vertex in dependency graph is copied into the compile-order graph and bidirectionally referenced. In addition, each vertex of a corresponding design unit in a document is linked to the vertex representing that document to express the design unit in document relationship. Each added vertex has the following properties: * The vertex' ID is the document's filename. * The vertex' value references the document. * A key-value-pair called ``kind`` denotes the vertex's kind as an enumeration value of type :class:`DependencyGraphVertexKind`. * A key-value-pair called ``predefined`` does not exist. .. rubric:: Algorithm 1. Iterate all documents in the design. * Create a vertex for that document and reference the document by the vertex' value field. |br| In return, set the documents's :attr:`~pyVHDLModel.Document._dependencyVertex` field to reference the created vertex. * Copy the vertex from dependency graph to compile-order graph and link both vertices bidirectionally. |br| In addition, set the documents's :attr:`~pyVHDLModel.Document._dependencyVertex` field to reference the copied vertex. * Add a key-value-pair called ``compileOrderVertex`` to the dependency graph's vertex. * Add a key-value-pair called ``dependencyVertex`` to the compiler-order graph's vertex. 1. Iterate the documents design units and create an edge from the design unit's corresponding dependency vertex to the documents corresponding dependency vertex. This expresses a "design unit is located in document" relation. * Add a key-value-pair called `kind`` denoting the edge's kind as an enumeration value of type :class:`DependencyGraphEdgeKind`. """ for document in self._documents: dependencyVertex = Vertex(vertexID=document.Path.name, value=document, graph=self._dependencyGraph) dependencyVertex["kind"] = DependencyGraphVertexKind.Document document._dependencyVertex = dependencyVertex compilerOrderVertex = dependencyVertex.Copy( self._compileOrderGraph, copyDict=True, linkingKeyToOriginalVertex="dependencyVertex", linkingKeyFromOriginalVertex="compileOrderVertex" ) document._compileOrderVertex = compilerOrderVertex for designUnit in document._designUnits: edge = dependencyVertex.EdgeFromVertex(designUnit._dependencyVertex) edge["kind"] = DependencyGraphEdgeKind.SourceFile
def ImportObjects(self) -> None: def _ImportObjects(package: Package) -> None: for referencedLibrary in package._referencedPackages.values(): for referencedPackage in referencedLibrary.values(): for declaredItem in referencedPackage._declaredItems: if isinstance(declaredItem, MultipleNamedEntityMixin): for normalizedIdentifier in declaredItem._normalizedIdentifiers: package._namespace._elements[normalizedIdentifier] = declaredItem elif isinstance(declaredItem, NamedEntityMixin): package._namespace._elements[declaredItem._normalizedIdentifier] = declaredItem else: raise VHDLModelException(f"Unexpected declared item.") for libraryName in ("std", "ieee"): for package in self.GetLibrary(libraryName).IterateDesignUnits(filter=DesignUnitKind.Package): # type: Package _ImportObjects(package) for document in self.IterateDocumentsInCompileOrder(): for package in document.IterateDesignUnits(filter=DesignUnitKind.Package): # type: Package _ImportObjects(package) def CreateTypeAndObjectGraph(self) -> None: def _HandlePackage(package) -> None: packagePrefix = f"{package.Library.NormalizedIdentifier}.{package.NormalizedIdentifier}" for deferredConstant in package._deferredConstants.values(): print(f"Deferred Constant: {deferredConstant}") deferredConstantVertex = Vertex( vertexID=f"{packagePrefix}.{deferredConstant.NormalizedIdentifiers[0]}", value=deferredConstant, graph=self._objectGraph ) deferredConstantVertex["kind"] = ObjectGraphVertexKind.DeferredConstant deferredConstant._objectVertex = deferredConstantVertex for constant in package._constants.values(): print(f"Constant: {constant}") constantVertex = Vertex( vertexID=f"{packagePrefix}.{constant.NormalizedIdentifiers[0]}", value=constant, graph=self._objectGraph ) constantVertex["kind"] = ObjectGraphVertexKind.Constant constant._objectVertex = constantVertex for type in package._types.values(): print(f"Type: {type}") typeVertex = Vertex( vertexID=f"{packagePrefix}.{type.NormalizedIdentifier}", value=type, graph=self._objectGraph ) typeVertex["kind"] = ObjectGraphVertexKind.Type type._objectVertex = typeVertex for subtype in package._subtypes.values(): print(f"Subtype: {subtype}") subtypeVertex = Vertex( vertexID=f"{packagePrefix}.{subtype.NormalizedIdentifier}", value=subtype, graph=self._objectGraph ) subtypeVertex["kind"] = ObjectGraphVertexKind.Subtype subtype._objectVertex = subtypeVertex for function in package._functions.values(): print(f"Function: {function}") functionVertex = Vertex( vertexID=f"{packagePrefix}.{function.NormalizedIdentifier}", value=function, graph=self._objectGraph ) functionVertex["kind"] = ObjectGraphVertexKind.Function function._objectVertex = functionVertex for procedure in package._procedures.values(): print(f"Procedure: {procedure}") procedureVertex = Vertex( vertexID=f"{packagePrefix}.{procedure.NormalizedIdentifier}", value=procedure, graph=self._objectGraph ) procedureVertex["kind"] = ObjectGraphVertexKind.Function procedure._objectVertex = procedureVertex for signal in package._signals.values(): print(f"Signal: {signal}") signalVertex = Vertex( vertexID=f"{packagePrefix}.{signal.NormalizedIdentifiers[0]}", value=signal, graph=self._objectGraph ) signalVertex["kind"] = ObjectGraphVertexKind.Signal signal._objectVertex = signalVertex def _LinkSymbolsInExpression(expression, namespace: Namespace, typeVertex: Vertex): if isinstance(expression, UnaryExpression): _LinkSymbolsInExpression(expression.Operand, namespace, typeVertex) elif isinstance(expression, BinaryExpression): _LinkSymbolsInExpression(expression.LeftOperand, namespace, typeVertex) _LinkSymbolsInExpression(expression.RightOperand, namespace, typeVertex) elif isinstance(expression, TernaryExpression): pass elif isinstance(expression, SimpleObjectOrFunctionCallSymbol): obj = namespace.FindObject(expression) expression._reference = obj edge = obj._objectVertex.EdgeToVertex(typeVertex) edge["kind"] = ObjectGraphEdgeKind.ReferenceInExpression else: pass def _LinkItems(package: Package): for item in package._declaredItems: if isinstance(item, Constant): print(f"constant: {item}") elif isinstance(item, DeferredConstant): print(f"deferred constant: {item}") elif isinstance(item, Signal): print(f"signal: {item}") elif isinstance(item, IntegerType): typeNode = item._objectVertex _LinkSymbolsInExpression(item.Range.LeftBound, package._namespace, typeNode) _LinkSymbolsInExpression(item.Range.RightBound, package._namespace, typeNode) # elif isinstance(item, FloatingType): # print(f"signal: {item}") elif isinstance(item, PhysicalType): typeNode = item._objectVertex _LinkSymbolsInExpression(item.Range.LeftBound, package._namespace, typeNode) _LinkSymbolsInExpression(item.Range.RightBound, package._namespace, typeNode) elif isinstance(item, ArrayType): # Resolve dimensions for dimension in item._dimensions: subtype = package._namespace.FindSubtype(dimension) dimension._reference = subtype edge = item._objectVertex.EdgeToVertex(subtype._objectVertex) edge["kind"] = ObjectGraphEdgeKind.Subtype # Resolve element subtype subtype = package._namespace.FindSubtype(item._elementType) item._elementType._reference = subtype edge = item._objectVertex.EdgeToVertex(subtype._objectVertex) edge["kind"] = ObjectGraphEdgeKind.Subtype elif isinstance(item, RecordType): # Resolve each elements subtype for element in item._elements: subtype = package._namespace.FindSubtype(element._subtype) element._subtype._reference = subtype edge = item._objectVertex.EdgeToVertex(subtype._objectVertex) edge["kind"] = ObjectGraphEdgeKind.Subtype else: print(f"not handled: {item}") for libraryName in ("std", "ieee"): for package in self.GetLibrary(libraryName).IterateDesignUnits(filter=DesignUnitKind.Package): # type: Package _HandlePackage(package) _LinkItems(package) for document in self.IterateDocumentsInCompileOrder(): for package in document.IterateDesignUnits(filter=DesignUnitKind.Package): # type: Package _HandlePackage(package) _LinkItems(package)
[docs] def LinkContexts(self) -> None: """ Resolves and links all items (library clauses, use clauses and nested context references) in contexts. It iterates all contexts in the design. Therefore, the library of the context is used as the working library. By default, the working library is implicitly referenced in :data:`_referencedLibraries`. In addition, a new empty dictionary is created in :data:`_referencedPackages` and :data:`_referencedContexts` for that working library. At first, all library clauses are resolved (a library clause my have multiple library reference symbols). For each referenced library an entry in :data:`_referencedLibraries` is generated and new empty dictionaries in :data:`_referencedPackages` and :data:`_referencedContexts` for that working library. In addition, a vertex in the dependency graph is added for that relationship. At second, all use clauses are resolved (a use clause my have multiple package member reference symbols). For each referenced package, """ for context in self.IterateDesignUnits(DesignUnitKind.Context): # type: Context # Create entries in _referenced*** for the current working library under its real name. workingLibrary: Library = context.Library libraryNormalizedIdentifier = workingLibrary._normalizedIdentifier context._referencedLibraries[libraryNormalizedIdentifier] = self._libraries[libraryNormalizedIdentifier] context._referencedPackages[libraryNormalizedIdentifier] = {} context._referencedContexts[libraryNormalizedIdentifier] = {} # Process all library clauses for libraryReference in context._libraryReferences: # A library clause can have multiple comma-separated references for libraryName in libraryReference.Symbols: libraryNormalizedIdentifier = libraryName.Name._normalizedIdentifier try: library = self._libraries[libraryNormalizedIdentifier] except KeyError: raise ReferencedLibraryNotExistingError(context, libraryName) # TODO: add position to these messages libraryName.Library = library context._referencedLibraries[libraryNormalizedIdentifier] = library context._referencedPackages[libraryNormalizedIdentifier] = {} context._referencedContexts[libraryNormalizedIdentifier] = {} # TODO: warn duplicate library reference dependency = context._dependencyVertex.EdgeToVertex(library._dependencyVertex, edgeValue=libraryReference) dependency["kind"] = DependencyGraphEdgeKind.LibraryClause # Process all use clauses for packageReference in context.PackageReferences: # A use clause can have multiple comma-separated references for symbol in packageReference.Symbols: # type: PackageReferenceSymbol packageName = symbol.Name.Prefix libraryName = packageName.Prefix libraryNormalizedIdentifier = libraryName._normalizedIdentifier packageNormalizedIdentifier = packageName._normalizedIdentifier # In case work is used, resolve to the real library name. if libraryNormalizedIdentifier == "work": library: Library = context._parent libraryNormalizedIdentifier = library._normalizedIdentifier elif libraryNormalizedIdentifier not in context._referencedLibraries: # TODO: This check doesn't trigger if it's the working library. raise VHDLModelException(f"Use clause references library '{libraryName._identifier}', which was not referenced by a library clause.") else: library = self._libraries[libraryNormalizedIdentifier] try: package = library._packages[packageNormalizedIdentifier] except KeyError: raise VHDLModelException(f"Package '{packageName._identifier}' not found in {'working ' if libraryName._normalizedIdentifier == 'work' else ''}library '{library._identifier}'.") symbol.Package = package # TODO: warn duplicate package reference context._referencedPackages[libraryNormalizedIdentifier][packageNormalizedIdentifier] = package dependency = context._dependencyVertex.EdgeToVertex(package._dependencyVertex, edgeValue=packageReference) dependency["kind"] = DependencyGraphEdgeKind.UseClause # TODO: update the namespace with visible members if isinstance(symbol, AllPackageMembersReferenceSymbol): pass elif isinstance(symbol, PackageMemberReferenceSymbol): raise NotImplementedError() else: raise VHDLModelException()
[docs] def LinkArchitectures(self) -> None: """ Link all architectures to corresponding entities in all libraries. .. rubric:: Algorithm 1. Iterate all libraries: 1. Iterate all architecture groups (grouped per entity symbol's name). |rarr| :meth:`pyVHDLModel.Library.LinkArchitectures` * Check if entity symbol's name exists as an entity in this library. 1. For each architecture in the same architecture group: * Add architecture to entities architecture dictionary :attr:`pyVHDLModel.DesignUnit.Entity._architectures`. * Assign found entity to architecture's entity symbol :attr:`pyVHDLModel.DesignUnit.Architecture._entity` * Set parent namespace of architecture's namespace to the entitie's namespace. * Add an edge in the dependency graph from the architecture's corresponding dependency vertex to the entity's corresponding dependency vertex. .. seealso:: :meth:`LinkPackageBodies` Link all package bodies to corresponding packages in all libraries. """ for library in self._libraries.values(): library.LinkArchitectures()
[docs] def LinkPackageBodies(self) -> None: """ Link all package bodies to corresponding packages in all libraries. .. rubric:: Algorithm 1. Iterate all libraries: 1. Iterate all package bodies. |rarr| :meth:`pyVHDLModel.Library.LinkPackageBodies` * Check if package body symbol's name exists as a package in this library. * Add package body to package :attr:`pyVHDLModel.DesignUnit.Package._packageBody`. * Assign found package to package body's package symbol :attr:`pyVHDLModel.DesignUnit.PackageBody._package` * Set parent namespace of package body's namespace to the package's namespace. * Add an edge in the dependency graph from the package body's corresponding dependency vertex to the package's corresponding dependency vertex. .. seealso:: :meth:`LinkArchitectures` Link all architectures to corresponding entities in all libraries. """ for library in self._libraries.values(): library.LinkPackageBodies()
def LinkLibraryReferences(self) -> None: DEFAULT_LIBRARIES = ("std",) for designUnit in self.IterateDesignUnits(DesignUnitKind.WithContext): # All primary units supporting a context, have at least one library implicitly referenced if isinstance(designUnit, PrimaryUnit): for libraryIdentifier in DEFAULT_LIBRARIES: referencedLibrary = self._libraries[libraryIdentifier] designUnit._referencedLibraries[libraryIdentifier] = referencedLibrary designUnit._referencedPackages[libraryIdentifier] = {} designUnit._referencedContexts[libraryIdentifier] = {} # TODO: catch KeyError on self._libraries[libName] # TODO: warn duplicate library reference dependency = designUnit._dependencyVertex.EdgeToVertex(referencedLibrary._dependencyVertex) dependency["kind"] = DependencyGraphEdgeKind.LibraryClause workingLibrary: Library = designUnit.Library libraryIdentifier = workingLibrary.NormalizedIdentifier referencedLibrary = self._libraries[libraryIdentifier] designUnit._referencedLibraries[libraryIdentifier] = referencedLibrary designUnit._referencedPackages[libraryIdentifier] = {} designUnit._referencedContexts[libraryIdentifier] = {} dependency = designUnit._dependencyVertex.EdgeToVertex(referencedLibrary._dependencyVertex) dependency["kind"] = DependencyGraphEdgeKind.LibraryClause # All secondary units inherit referenced libraries from their primary units. else: if isinstance(designUnit, Architecture): referencedLibraries = designUnit.Entity.Entity._referencedLibraries elif isinstance(designUnit, PackageBody): referencedLibraries = designUnit.Package.Package._referencedLibraries else: raise VHDLModelException() for libraryIdentifier, library in referencedLibraries.items(): designUnit._referencedLibraries[libraryIdentifier] = library for libraryReference in designUnit._libraryReferences: # A library clause can have multiple comma-separated references for librarySymbol in libraryReference.Symbols: libraryIdentifier = librarySymbol.Name.NormalizedIdentifier try: library = self._libraries[libraryIdentifier] except KeyError: ex = VHDLModelException(f"Library '{librarySymbol.Name.Identifier}' referenced by library clause of design unit '{designUnit.Identifier}' doesn't exist in design.") ex.add_note(f"""Known libraries: '{"', '".join(library for library in self._libraries)}'""") raise ex librarySymbol.Library = library designUnit._referencedLibraries[libraryIdentifier] = library designUnit._referencedPackages[libraryIdentifier] = {} designUnit._referencedContexts[libraryIdentifier] = {} # TODO: warn duplicate library reference dependency = designUnit._dependencyVertex.EdgeToVertex(library._dependencyVertex, edgeValue=libraryReference) dependency["kind"] = DependencyGraphEdgeKind.LibraryClause def LinkPackageReferences(self) -> None: DEFAULT_PACKAGES = ( ("std", ("standard",)), ) for designUnit in self.IterateDesignUnits(DesignUnitKind.WithContext): # All primary units supporting a context, have at least one package implicitly referenced if isinstance(designUnit, PrimaryUnit): if designUnit.Library.NormalizedIdentifier != "std" and \ designUnit.NormalizedIdentifier != "standard": for lib in DEFAULT_PACKAGES: if lib[0] not in designUnit._referencedLibraries: raise VHDLModelException() for pack in lib[1]: referencedPackage = self._libraries[lib[0]]._packages[pack] designUnit._referencedPackages[lib[0]][pack] = referencedPackage # TODO: catch KeyError on self._libraries[lib[0]]._packages[pack] # TODO: warn duplicate package reference dependency = designUnit._dependencyVertex.EdgeToVertex(referencedPackage._dependencyVertex) dependency["kind"] = DependencyGraphEdgeKind.UseClause # All secondary units inherit referenced packages from their primary units. else: if isinstance(designUnit, Architecture): referencedPackages = designUnit.Entity.Entity._referencedPackages elif isinstance(designUnit, PackageBody): referencedPackages = designUnit.Package.Package._referencedPackages else: raise VHDLModelException() for packageIdentifier, package in referencedPackages.items(): designUnit._referencedPackages[packageIdentifier] = package for packageReference in designUnit.PackageReferences: # A use clause can have multiple comma-separated references for packageMemberSymbol in packageReference.Symbols: packageName = packageMemberSymbol.Name.Prefix libraryName = packageName.Prefix libraryIdentifier = libraryName.NormalizedIdentifier packageIdentifier = packageName.NormalizedIdentifier # In case work is used, resolve to the real library name. if libraryIdentifier == "work": library: Library = designUnit.Library libraryIdentifier = library.NormalizedIdentifier elif libraryIdentifier not in designUnit._referencedLibraries: # TODO: This check doesn't trigger if it's the working library. raise VHDLModelException(f"Use clause references library '{libraryName.Identifier}', which was not referenced by a library clause.") else: library = self._libraries[libraryIdentifier] try: package = library._packages[packageIdentifier] except KeyError: ex = VHDLModelException(f"Package '{packageName.Identifier}' not found in {'working ' if libraryName.NormalizedIdentifier == 'work' else ''}library '{library.Identifier}'.") ex.add_note(f"Caused in design unit '{designUnit}' in file '{designUnit.Document}'.") raise ex packageMemberSymbol.Package = package # TODO: warn duplicate package reference designUnit._referencedPackages[libraryIdentifier][packageIdentifier] = package dependency = designUnit._dependencyVertex.EdgeToVertex(package._dependencyVertex, edgeValue=packageReference) dependency["kind"] = DependencyGraphEdgeKind.UseClause # TODO: update the namespace with visible members if isinstance(packageMemberSymbol, AllPackageMembersReferenceSymbol): for componentIdentifier, component in package._components.items(): designUnit._namespace._elements[componentIdentifier] = component elif isinstance(packageMemberSymbol, PackageMemberReferenceSymbol): raise NotImplementedError() else: raise VHDLModelException() def LinkContextReferences(self) -> None: for designUnit in self.IterateDesignUnits(): for contextReference in designUnit._contextReferences: # A context reference can have multiple comma-separated references for contextSymbol in contextReference.Symbols: libraryName = contextSymbol.Name.Prefix libraryIdentifier = libraryName.NormalizedIdentifier contextIdentifier = contextSymbol.Name.NormalizedIdentifier # In case work is used, resolve to the real library name. if libraryIdentifier == "work": referencedLibrary = designUnit.Library libraryIdentifier = referencedLibrary.NormalizedIdentifier elif libraryIdentifier not in designUnit._referencedLibraries: # TODO: This check doesn't trigger if it's the working library. raise VHDLModelException(f"Context reference references library '{libraryName.Identifier}', which was not referenced by a library clause.") else: referencedLibrary = self._libraries[libraryIdentifier] try: referencedContext = referencedLibrary._contexts[contextIdentifier] except KeyError: raise VHDLModelException(f"Context '{contextSymbol.Name.Identifier}' not found in {'working ' if libraryName.NormalizedIdentifier == 'work' else ''}library '{referencedLibrary.Identifier}'.") contextSymbol.Package = referencedContext # TODO: warn duplicate referencedContext reference designUnit._referencedContexts[libraryIdentifier][contextIdentifier] = referencedContext dependency = designUnit._dependencyVertex.EdgeToVertex(referencedContext._dependencyVertex, edgeValue=contextReference) dependency["kind"] = DependencyGraphEdgeKind.ContextReference for vertex in self._dependencyGraph.IterateTopologically(): if vertex["kind"] is DependencyGraphVertexKind.Context: context: Context = vertex.Value for designUnitVertex in vertex.IteratePredecessorVertices(): designUnit: DesignUnit = designUnitVertex.Value for libraryIdentifier, library in context._referencedLibraries.items(): # if libraryIdentifier in designUnit._referencedLibraries: # raise VHDLModelException(f"Referenced library '{library.Identifier}' already exists in references for design unit '{designUnit.Identifier}'.") designUnit._referencedLibraries[libraryIdentifier] = library designUnit._referencedPackages[libraryIdentifier] = {} for libraryIdentifier, packages in context._referencedPackages.items(): for packageIdentifier, package in packages.items(): if packageIdentifier in designUnit._referencedPackages: raise VHDLModelException(f"Referenced package '{package.Identifier}' already exists in references for design unit '{designUnit.Identifier}'.") designUnit._referencedPackages[libraryIdentifier][packageIdentifier] = package def LinkComponents(self) -> None: for package in self.IterateDesignUnits(DesignUnitKind.Package): # type: Package library = package._parent for component in package._components.values(): try: entity = library._entities[component.NormalizedIdentifier] except KeyError: print(f"Entity '{component.Identifier}' not found for component '{component.Identifier}' in library '{library.Identifier}'.") component.Entity = entity # QUESTION: Add link in dependency graph as dashed line from component to entity? # Currently, component has no _dependencyVertex field def LinkInstantiations(self) -> None: for architecture in self.IterateDesignUnits(DesignUnitKind.Architecture): # type: Architecture for instance in architecture.IterateInstantiations(): if isinstance(instance, EntityInstantiation): libraryName = instance.Entity.Name.Prefix libraryIdentifier = libraryName.Identifier normalizedLibraryIdentifier = libraryName.NormalizedIdentifier if normalizedLibraryIdentifier == "work": libraryIdentifier = architecture.Library.Identifier normalizedLibraryIdentifier = architecture.Library.NormalizedIdentifier elif normalizedLibraryIdentifier not in architecture._referencedLibraries: ex = VHDLModelException(f"Referenced library '{libraryIdentifier}' in direct entity instantiation '{instance.Label}: entity {instance.Entity.Prefix.Identifier}.{instance.Entity.Identifier}' not found in architecture '{architecture!r}'.") ex.add_note(f"Add a library reference to the architecture or entity using a library clause like: 'library {libraryIdentifier};'.") raise ex try: library = self._libraries[normalizedLibraryIdentifier] except KeyError: ex = VHDLModelException(f"Referenced library '{libraryIdentifier}' in direct entity instantiation '{instance.Label}: entity {instance.Entity.Prefix.Identifier}.{instance.Entity.Identifier}' not found in design.") ex.add_note(f"No design units were parsed into library '{libraryIdentifier}'. Thus it doesn't exist in design.") raise ex try: entity = library._entities[instance.Entity.Name.NormalizedIdentifier] except KeyError: ex = VHDLModelException(f"Referenced entity '{instance.Entity.Name.Identifier}' in direct entity instantiation '{instance.Label}: entity {instance.Entity.Name.Prefix.Identifier}.{instance.Entity.Name.Identifier}' not found in {'working ' if instance.Entity.Name.Prefix.NormalizedIdentifier == 'work' else ''}library '{libraryIdentifier}'.") libs = [library.Identifier for library in self._libraries.values() for entityIdentifier in library._entities.keys() if entityIdentifier == instance.Entity.Name.NormalizedIdentifier] if libs: ex.add_note(f"Found entity '{instance.Entity!s}' in other libraries: {', '.join(libs)}") raise ex instance.Entity.Entity = entity dependency = architecture._dependencyVertex.EdgeToVertex(entity._dependencyVertex, edgeValue=instance) dependency["kind"] = DependencyGraphEdgeKind.EntityInstantiation elif isinstance(instance, ComponentInstantiation): component = architecture._namespace.FindComponent(instance.Component) instance.Component.Component = component dependency = architecture._dependencyVertex.EdgeToVertex(component.Entity._dependencyVertex, edgeValue=instance) dependency["kind"] = DependencyGraphEdgeKind.ComponentInstantiation elif isinstance(instance, ConfigurationInstantiation): # pass print(instance.Label, instance.Configuration)
[docs] def IndexPackages(self) -> None: """ Index all declared items in all packages in all libraries. .. rubric:: Algorithm 1. Iterate all libraries: 1. Iterate all packages |br| |rarr| :meth:`pyVHDLModel.Library.IndexPackages` * Index all declared items in that package. |br| |rarr| :meth:`pyVHDLModel.DesignUnit.Package.IndexDeclaredItems` .. seealso:: :meth:`IndexPackageBodies` Index all declared items in all package bodies in all libraries. :meth:`IndexEntities` Index all declared items in all entities in all libraries. :meth:`IndexArchitectures` Index all declared items in all architectures in all libraries. """ for library in self._libraries.values(): library.IndexPackages()
[docs] def IndexPackageBodies(self) -> None: """ Index all declared items in all packages in all libraries. .. rubric:: Algorithm 1. Iterate all libraries: 1. Iterate all packages |br| |rarr| :meth:`pyVHDLModel.Library.IndexPackageBodies` * Index all declared items in that package body. |br| |rarr| :meth:`pyVHDLModel.DesignUnit.PackageBody.IndexDeclaredItems` .. seealso:: :meth:`IndexPackages` Index all declared items in all packages in all libraries. :meth:`IndexEntities` Index all declared items in all entities in all libraries. :meth:`IndexArchitectures` Index all declared items in all architectures in all libraries. """ for library in self._libraries.values(): library.IndexPackageBodies()
[docs] def IndexEntities(self) -> None: """ Index all declared items in all packages in all libraries. .. rubric:: Algorithm 1. Iterate all libraries: 1. Iterate all packages |br| |rarr| :meth:`pyVHDLModel.Library.IndexEntities` * Index all declared items in that entity. |br| |rarr| :meth:`pyVHDLModel.DesignUnit.Entity.IndexDeclaredItems` .. seealso:: :meth:`IndexPackages` Index all declared items in all packages in all libraries. :meth:`IndexPackageBodies` Index all declared items in all package bodies in all libraries. :meth:`IndexArchitectures` Index all declared items in all architectures in all libraries. """ for library in self._libraries.values(): library.IndexEntities()
[docs] def IndexArchitectures(self) -> None: """ Index all declared items in all packages in all libraries. .. rubric:: Algorithm 1. Iterate all libraries: 1. Iterate all packages |br| |rarr| :meth:`pyVHDLModel.Library.IndexArchitectures` * Index all declared items in that architecture. |br| |rarr| :meth:`pyVHDLModel.DesignUnit.Architecture.IndexDeclaredItems` .. seealso:: :meth:`IndexPackages` Index all declared items in all packages in all libraries. :meth:`IndexPackageBodies` Index all declared items in all package bodies in all libraries. :meth:`IndexEntities` Index all declared items in all entities in all libraries. """ for library in self._libraries.values(): library.IndexArchitectures()
[docs] def CreateHierarchyGraph(self) -> None: """ Create the hierarchy graph from dependency graph. .. rubric:: Algorithm 1. Iterate all vertices corresponding to entities and architectures in the dependency graph: * Copy these vertices to the hierarchy graph and create a bidirectional linking. |br| In addition, set the referenced design unit's :attr:`~pyVHDLModel.Document._hierarchyVertex` field to reference the copied vertex. * Add a key-value-pair called ``hierarchyVertex`` to the dependency graph's vertex. * Add a key-value-pair called ``dependencyVertex`` to the hierarchy graph's vertex. 2. Iterate all architectures ... .. todo:: Design::CreateHierarchyGraph describe algorithm 1. Iterate all outbound edges .. todo:: Design::CreateHierarchyGraph describe algorithm """ # Copy all entity and architecture vertices from dependency graph to hierarchy graph and double-link them entityArchitectureFilter = lambda v: v["kind"] in DependencyGraphVertexKind.Entity | DependencyGraphVertexKind.Architecture for vertex in self._dependencyGraph.IterateVertices(predicate=entityArchitectureFilter): hierarchyVertex = vertex.Copy(self._hierarchyGraph, copyDict=True, linkingKeyToOriginalVertex="dependencyVertex", linkingKeyFromOriginalVertex="hierarchyVertex") vertex.Value._hierarchyVertex = hierarchyVertex # Copy implementation edges from for hierarchyArchitectureVertex in self._hierarchyGraph.IterateVertices(predicate=lambda v: v["kind"] is DependencyGraphVertexKind.Architecture): for dependencyEdge in hierarchyArchitectureVertex["dependencyVertex"].IterateOutboundEdges(): kind: DependencyGraphEdgeKind = dependencyEdge["kind"] if DependencyGraphEdgeKind.Implementation in kind: hierarchyDestinationVertex = dependencyEdge.Destination["hierarchyVertex"] newEdge = hierarchyArchitectureVertex.EdgeFromVertex(hierarchyDestinationVertex) elif DependencyGraphEdgeKind.Instantiation in kind: hierarchyDestinationVertex = dependencyEdge.Destination["hierarchyVertex"] # FIXME: avoid parallel edges, to graph can be converted to a tree until "real" hierarchy is computed (unrole generics and blocks) if hierarchyArchitectureVertex.HasEdgeToDestination(hierarchyDestinationVertex): continue newEdge = hierarchyArchitectureVertex.EdgeToVertex(hierarchyDestinationVertex) else: continue newEdge["kind"] = kind
def ComputeCompileOrder(self) -> None: def predicate(edge: Edge) -> bool: return ( DependencyGraphEdgeKind.Implementation in edge["kind"] or DependencyGraphEdgeKind.Instantiation in edge["kind"] or DependencyGraphEdgeKind.UseClause in edge["kind"] or DependencyGraphEdgeKind.ContextReference in edge["kind"] ) and edge.Destination["predefined"] is False for edge in self._dependencyGraph.IterateEdges(predicate=predicate): sourceDocument: Document = edge.Source.Value.Document destinationDocument: Document = edge.Destination.Value.Document sourceVertex = sourceDocument._compileOrderVertex destinationVertex = destinationDocument._compileOrderVertex # Don't add self-edges if sourceVertex is destinationVertex: continue # Don't add parallel edges elif sourceVertex.HasEdgeToDestination(destinationVertex): continue e = sourceVertex.EdgeToVertex(destinationVertex) e["kind"] = DependencyGraphEdgeKind.CompileOrder e = sourceVertex["dependencyVertex"].EdgeToVertex(destinationVertex["dependencyVertex"]) e["kind"] = DependencyGraphEdgeKind.CompileOrder
[docs] def IterateDocumentsInCompileOrder(self) -> Generator['Document', None, None]: """ Iterate all document in compile-order. .. rubric:: Algorithm * Check if compile-order graph was populated with vertices and its vertices are linked by edges. 1. Iterate compile-order graph in topological order. |br| :meth:`pyTooling.Graph.Graph.IterateTopologically` * yield the compiler-order vertex' referenced document. :returns: A generator to iterate all documents in compile-order in the design. :raises VHDLModelException: If compile-order was not computed. .. seealso:: .. todo:: missing text :meth:`pyVHDLModel.Design.ComputeCompileOrder` """ if self._compileOrderGraph.EdgeCount < self._compileOrderGraph.VertexCount - 1: raise VHDLModelException(f"Compile order is not yet computed from dependency graph.") for compileOrderNode in self._compileOrderGraph.IterateTopologically(): yield compileOrderNode.Value
def GetUnusedDesignUnits(self) -> List[DesignUnit]: raise NotImplementedError()
[docs] def __repr__(self) -> str: """ Formats a representation of the design. **Format:** ``Document: 'my_design'`` :returns: String representation of the design. """ return f"Design: {self._name}"
__str__ = __repr__
[docs] @export class Library(ModelEntity, NamedEntityMixin): """A ``Library`` represents a VHDL library. It contains all *primary* and *secondary* design units.""" _contexts: Dict[str, Context] #: Dictionary of all contexts defined in a library. _configurations: Dict[str, Configuration] #: Dictionary of all configurations defined in a library. _entities: Dict[str, Entity] #: Dictionary of all entities defined in a library. _architectures: Dict[str, Dict[str, Architecture]] #: Dictionary of all architectures defined in a library. _packages: Dict[str, Package] #: Dictionary of all packages defined in a library. _packageBodies: Dict[str, PackageBody] #: Dictionary of all package bodies defined in a library. _dependencyVertex: Vertex[None, None, str, Union['Library', DesignUnit], None, None, None, None, None, None, None, None, None, None, None, None, None] #: Reference to the vertex in the dependency graph representing the library. |br| This reference is set by :meth:`~pyVHDLModel.Design.CreateDependencyGraph`.
[docs] def __init__(self, identifier: str, parent: ModelEntity = None) -> None: super().__init__(parent) NamedEntityMixin.__init__(self, identifier) self._contexts = {} self._configurations = {} self._entities = {} self._architectures = {} self._packages = {} self._packageBodies = {} self._dependencyVertex = None
@readonly def Contexts(self) -> Dict[str, Context]: """Returns a list of all context declarations declared in this library.""" return self._contexts @readonly def Configurations(self) -> Dict[str, Configuration]: """Returns a list of all configuration declarations declared in this library.""" return self._configurations @readonly def Entities(self) -> Dict[str, Entity]: """Returns a list of all entity declarations declared in this library.""" return self._entities @readonly def Architectures(self) -> Dict[str, Dict[str, Architecture]]: """Returns a list of all architectures declarations declared in this library.""" return self._architectures @readonly def Packages(self) -> Dict[str, Package]: """Returns a list of all package declarations declared in this library.""" return self._packages @readonly def PackageBodies(self) -> Dict[str, PackageBody]: """Returns a list of all package body declarations declared in this library.""" return self._packageBodies @readonly def DependencyVertex(self) -> Vertex: """ Read-only property to access the corresponding dependency vertex (:attr:`_dependencyVertex`). The dependency vertex references this library by its value field. :returns: The corresponding dependency vertex. """ return self._dependencyVertex
[docs] def IterateDesignUnits(self, filter: DesignUnitKind = DesignUnitKind.All) -> Generator[DesignUnit, None, None]: """ Iterate all design units in the library. A union of :class:`DesignUnitKind` values can be given to filter the returned result for suitable design units. .. rubric:: Algorithm 1. Iterate all contexts in that library. 2. Iterate all packages in that library. 3. Iterate all package bodies in that library. 4. Iterate all entites in that library. 5. Iterate all architectures in that library. 6. Iterate all configurations in that library. :param filter: An enumeration with possibly multiple flags to filter the returned design units. :returns: A generator to iterate all matched design units in the library. .. seealso:: :meth:`pyVHDLModel.Design.IterateDesignUnits` Iterate all design units in the design. :meth:`pyVHDLModel.Document.IterateDesignUnits` Iterate all design units in the document. """ if DesignUnitKind.Context in filter: for context in self._contexts.values(): yield context if DesignUnitKind.Package in filter: for package in self._packages.values(): yield package if DesignUnitKind.PackageBody in filter: for packageBody in self._packageBodies.values(): yield packageBody if DesignUnitKind.Entity in filter: for entity in self._entities.values(): yield entity if DesignUnitKind.Architecture in filter: for architectures in self._architectures.values(): for architecture in architectures.values(): yield architecture if DesignUnitKind.Configuration in filter: for configuration in self._configurations.values(): yield configuration
# for verificationProperty in self._verificationUnits.values(): # yield verificationProperty # for verificationUnit in self._verificationProperties.values(): # yield entity # for verificationMode in self._verificationModes.values(): # yield verificationMode
[docs] def LinkArchitectures(self) -> None: """ Link all architectures to corresponding entities. .. rubric:: Algorithm 1. Iterate all architecture groups (grouped per entity symbol's name). * Check if entity symbol's name exists as an entity in this library. 1. For each architecture in the same architecture group: * Add architecture to entities architecture dictionary :attr:`pyVHDLModel.DesignUnit.Entity._architectures`. * Assign found entity to architecture's entity symbol :attr:`pyVHDLModel.DesignUnit.Architecture._entity` * Set parent namespace of architecture's namespace to the entitie's namespace. * Add an edge in the dependency graph from the architecture's corresponding dependency vertex to the entity's corresponding dependency vertex. :raises VHDLModelException: If entity name doesn't exist. :raises VHDLModelException: If architecture name already exists for entity. .. seealso:: :meth:`LinkPackageBodies` Link all package bodies to corresponding packages. """ for entityName, architecturesPerEntity in self._architectures.items(): if entityName not in self._entities: architectureNames = "', '".join(architecturesPerEntity.keys()) raise VHDLModelException(f"Entity '{entityName}' referenced by architecture(s) '{architectureNames}' doesn't exist in library '{self._identifier}'.") # TODO: search in other libraries to find that entity. # TODO: add code position entity = self._entities[entityName] for architecture in architecturesPerEntity.values(): if architecture._normalizedIdentifier in entity._architectures: raise VHDLModelException(f"Architecture '{architecture._identifier}' already exists for entity '{entity._identifier}'.") # TODO: add code position of existing and current entity._architectures[architecture._normalizedIdentifier] = architecture architecture._entity.Entity = entity architecture._namespace._parentNamespace = entity._namespace # add "architecture -> entity" relation in dependency graph dependency = architecture._dependencyVertex.EdgeToVertex(entity._dependencyVertex) dependency["kind"] = DependencyGraphEdgeKind.EntityImplementation
[docs] def LinkPackageBodies(self) -> None: """ Link all package bodies to corresponding packages. .. rubric:: Algorithm 1. Iterate all package bodies. * Check if package body symbol's name exists as a package in this library. * Add package body to package :attr:`pyVHDLModel.DesignUnit.Package._packageBody`. * Assign found package to package body's package symbol :attr:`pyVHDLModel.DesignUnit.PackageBody._package` * Set parent namespace of package body's namespace to the package's namespace. * Add an edge in the dependency graph from the package body's corresponding dependency vertex to the package's corresponding dependency vertex. :raises VHDLModelException: If package name doesn't exist. .. seealso:: :meth:`LinkArchitectures` Link all architectures to corresponding entities. """ for packageBodyName, packageBody in self._packageBodies.items(): if packageBodyName not in self._packages: raise VHDLModelException(f"Package '{packageBodyName}' referenced by package body '{packageBodyName}' doesn't exist in library '{self._identifier}'.") package = self._packages[packageBodyName] package._packageBody = packageBody # TODO: add warning if package had already a body, which is now replaced packageBody._package.Package = package packageBody._namespace._parentNamespace = package._namespace # add "package body -> package" relation in dependency graph dependency = packageBody._dependencyVertex.EdgeToVertex(package._dependencyVertex) dependency["kind"] = DependencyGraphEdgeKind.PackageImplementation
[docs] def IndexPackages(self) -> None: """ Index declared items in all packages. .. rubric:: Algorithm 1. Iterate all packages: * Index all declared items. |br| |rarr| :meth:`pyVHDLModel.DesignUnit.Package.IndexDeclaredItems` .. seealso:: :meth:`IndexPackageBodies` Index all declared items in a package body. :meth:`IndexEntities` Index all declared items in an entity. :meth:`IndexArchitectures` Index all declared items in an architecture. """ for package in self._packages.values(): if isinstance(package, Package): package.IndexDeclaredItems()
[docs] def IndexPackageBodies(self) -> None: """ Index declared items in all package bodies. .. rubric:: Algorithm 1. Iterate all package bodies: * Index all declared items. |br| |rarr| :meth:`pyVHDLModel.DesignUnit.PackageBody.IndexDeclaredItems` .. seealso:: :meth:`IndexPackages` Index all declared items in a package. :meth:`IndexEntities` Index all declared items in an entity. :meth:`IndexArchitectures` Index all declared items in an architecture. """ for packageBody in self._packageBodies.values(): packageBody.IndexDeclaredItems()
[docs] def IndexEntities(self) -> None: """ Index declared items in all entities. .. rubric:: Algorithm 1. Iterate all entities: * Index all declared items. |br| |rarr| :meth:`pyVHDLModel.DesignUnit.Entity.IndexDeclaredItems` .. seealso:: :meth:`IndexPackages` Index all declared items in a package. :meth:`IndexPackageBodies` Index all declared items in a package body. :meth:`IndexArchitectures` Index all declared items in an architecture. """ for entity in self._entities.values(): entity.IndexDeclaredItems()
[docs] def IndexArchitectures(self) -> None: """ Index declared items in all architectures. .. rubric:: Algorithm 1. Iterate all architectures: * Index all declared items. |br| |rarr| :meth:`pyVHDLModel.DesignUnit.Architecture.IndexDeclaredItems` .. seealso:: :meth:`IndexPackages` Index all declared items in a package. :meth:`IndexPackageBodies` Index all declared items in a package body. :meth:`IndexEntities` Index all declared items in an entity. """ for architectures in self._architectures.values(): for architecture in architectures.values(): architecture.IndexDeclaredItems() architecture.IndexStatements()
[docs] def __repr__(self) -> str: """ Formats a representation of the library. **Format:** ``Library: 'my_library'`` :returns: String representation of the library. """ return f"Library: '{self._identifier}'"
__str__ = __repr__
[docs] @export class Document(ModelEntity, DocumentedEntityMixin): """A ``Document`` represents a sourcefile. It contains *primary* and *secondary* design units.""" _path: Path #: path to the document. ``None`` if virtual document. _designUnits: List[DesignUnit] #: List of all design units defined in a document. _contexts: Dict[str, Context] #: Dictionary of all contexts defined in a document. _configurations: Dict[str, Configuration] #: Dictionary of all configurations defined in a document. _entities: Dict[str, Entity] #: Dictionary of all entities defined in a document. _architectures: Dict[str, Dict[str, Architecture]] #: Dictionary of all architectures defined in a document. _packages: Dict[str, Package] #: Dictionary of all packages defined in a document. _packageBodies: Dict[str, PackageBody] #: Dictionary of all package bodies defined in a document. _verificationUnits: Dict[str, VerificationUnit] #: Dictionary of all PSL verification units defined in a document. _verificationProperties: Dict[str, VerificationProperty] #: Dictionary of all PSL verification properties defined in a document. _verificationModes: Dict[str, VerificationMode] #: Dictionary of all PSL verification modes defined in a document. _dependencyVertex: Vertex[None, None, None, 'Document', None, None, None, None, None, None, None, None, None, None, None, None, None] #: Reference to the vertex in the dependency graph representing the document. |br| This reference is set by :meth:`~pyVHDLModel.Design.CreateCompileOrderGraph`. _compileOrderVertex: Vertex[None, None, None, 'Document', None, None, None, None, None, None, None, None, None, None, None, None, None] #: Reference to the vertex in the compile-order graph representing the document. |br| This reference is set by :meth:`~pyVHDLModel.Design.CreateCompileOrderGraph`.
[docs] def __init__(self, path: Path, documentation: Nullable[str] = None, parent: ModelEntity = None) -> None: super().__init__(parent) DocumentedEntityMixin.__init__(self, documentation) self._path = path self._designUnits = [] self._contexts = {} self._configurations = {} self._entities = {} self._architectures = {} self._packages = {} self._packageBodies = {} self._verificationUnits = {} self._verificationProperties = {} self._verificationModes = {} self._dependencyVertex = None self._compileOrderVertex = None
[docs] def _AddEntity(self, item: Entity) -> None: """ Add an entity to the document's lists of design units. :param item: Entity object to be added to the document. :raises TypeError: If parameter 'item' is not of type :class:`~pyVHDLModel.DesignUnits.Entity`. :raises VHDLModelException: If entity name already exists in document. """ if not isinstance(item, Entity): ex = TypeError(f"Parameter 'item' is not of type 'Entity'.") if version_info >= (3, 11): # pragma: no cover ex.add_note(f"Got type '{getFullyQualifiedName(item)}'.") raise ex identifier = item._normalizedIdentifier if identifier in self._entities: # TODO: use a more specific exception raise VHDLModelException(f"An entity '{item._identifier}' already exists in this document.") self._entities[identifier] = item self._designUnits.append(item) item._document = self
[docs] def _AddArchitecture(self, item: Architecture) -> None: """ Add an architecture to the document's lists of design units. :param item: Architecture object to be added to the document. :raises TypeError: If parameter 'item' is not of type :class:`~pyVHDLModel.DesignUnits.Architecture`. :raises VHDLModelException: If architecture name already exists for the referenced entity name in document. """ if not isinstance(item, Architecture): ex = TypeError(f"Parameter 'item' is not of type 'Architecture'.") if version_info >= (3, 11): # pragma: no cover ex.add_note(f"Got type '{getFullyQualifiedName(item)}'.") raise ex entity = item._entity.Name entityIdentifier = entity._normalizedIdentifier try: architectures = self._architectures[entityIdentifier] if item._normalizedIdentifier in architectures: # TODO: use a more specific exception # FIXME: this is allowed and should be a warning or a strict mode. raise VHDLModelException(f"An architecture '{item._identifier}' for entity '{entity._identifier}' already exists in this document.") architectures[item.Identifier] = item except KeyError: self._architectures[entityIdentifier] = {item._identifier: item} self._designUnits.append(item) item._document = self
[docs] def _AddPackage(self, item: Package) -> None: """ Add a package to the document's lists of design units. :param item: Package object to be added to the document. :raises TypeError: If parameter 'item' is not of type :class:`~pyVHDLModel.DesignUnits.Package`. :raises VHDLModelException: If package name already exists in document. """ if not isinstance(item, (Package, PackageInstantiation)): ex = TypeError(f"Parameter 'item' is not of type 'Package' or 'PackageInstantiation'.") if version_info >= (3, 11): # pragma: no cover ex.add_note(f"Got type '{getFullyQualifiedName(item)}'.") raise ex identifier = item._normalizedIdentifier if identifier in self._packages: # TODO: use a more specific exception raise VHDLModelException(f"A package '{item._identifier}' already exists in this document.") self._packages[identifier] = item self._designUnits.append(item) item._document = self
[docs] def _AddPackageBody(self, item: PackageBody) -> None: """ Add a package body to the document's lists of design units. :param item: Package body object to be added to the document. :raises TypeError: If parameter 'item' is not of type :class:`~pyVHDLModel.DesignUnits.PackageBody`. :raises VHDLModelException: If package body name already exists in document. """ if not isinstance(item, PackageBody): ex = TypeError(f"Parameter 'item' is not of type 'PackageBody'.") if version_info >= (3, 11): # pragma: no cover ex.add_note(f"Got type '{getFullyQualifiedName(item)}'.") raise ex identifier = item._normalizedIdentifier if identifier in self._packageBodies: # TODO: use a more specific exception raise VHDLModelException(f"A package body '{item._identifier}' already exists in this document.") self._packageBodies[identifier] = item self._designUnits.append(item) item._document = self
[docs] def _AddContext(self, item: Context) -> None: """ Add a context to the document's lists of design units. :param item: Context object to be added to the document. :raises TypeError: If parameter 'item' is not of type :class:`~pyVHDLModel.DesignUnits.Context`. :raises VHDLModelException: If context name already exists in document. """ if not isinstance(item, Context): ex = TypeError(f"Parameter 'item' is not of type 'Context'.") if version_info >= (3, 11): # pragma: no cover ex.add_note(f"Got type '{getFullyQualifiedName(item)}'.") raise ex identifier = item._normalizedIdentifier if identifier in self._contexts: # TODO: use a more specific exception raise VHDLModelException(f"A context '{item._identifier}' already exists in this document.") self._contexts[identifier] = item self._designUnits.append(item) item._document = self
[docs] def _AddConfiguration(self, item: Configuration) -> None: """ Add a configuration to the document's lists of design units. :param item: Configuration object to be added to the document. :raises TypeError: If parameter 'item' is not of type :class:`~pyVHDLModel.DesignUnits.Configuration`. :raises VHDLModelException: If configuration name already exists in document. """ if not isinstance(item, Configuration): ex = TypeError(f"Parameter 'item' is not of type 'Configuration'.") if version_info >= (3, 11): # pragma: no cover ex.add_note(f"Got type '{getFullyQualifiedName(item)}'.") raise ex identifier = item._normalizedIdentifier if identifier in self._configurations: # TODO: use a more specific exception raise VHDLModelException(f"A configuration '{item._identifier}' already exists in this document.") self._configurations[identifier] = item self._designUnits.append(item) item._document = self
def _AddVerificationUnit(self, item: VerificationUnit) -> None: if not isinstance(item, VerificationUnit): ex = TypeError(f"Parameter 'item' is not of type 'VerificationUnit'.") if version_info >= (3, 11): # pragma: no cover ex.add_note(f"Got type '{getFullyQualifiedName(item)}'.") raise ex identifier = item._normalizedIdentifier if identifier in self._verificationUnits: raise ValueError(f"A verification unit '{item._identifier}' already exists in this document.") self._verificationUnits[identifier] = item self._designUnits.append(item) item._document = self def _AddVerificationProperty(self, item: VerificationProperty) -> None: if not isinstance(item, VerificationProperty): ex = TypeError(f"Parameter 'item' is not of type 'VerificationProperty'.") if version_info >= (3, 11): # pragma: no cover ex.add_note(f"Got type '{getFullyQualifiedName(item)}'.") raise ex identifier = item.NormalizedIdentifier if identifier in self._verificationProperties: raise ValueError(f"A verification property '{item.Identifier}' already exists in this document.") self._verificationProperties[identifier] = item self._designUnits.append(item) item._document = self def _AddVerificationMode(self, item: VerificationMode) -> None: if not isinstance(item, VerificationMode): ex = TypeError(f"Parameter 'item' is not of type 'VerificationMode'.") if version_info >= (3, 11): # pragma: no cover ex.add_note(f"Got type '{getFullyQualifiedName(item)}'.") raise ex identifier = item.NormalizedIdentifier if identifier in self._verificationModes: raise ValueError(f"A verification mode '{item.Identifier}' already exists in this document.") self._verificationModes[identifier] = item self._designUnits.append(item) item._document = self
[docs] def _AddDesignUnit(self, item: DesignUnit) -> None: """ Add a design unit to the document's lists of design units. :param item: Configuration object to be added to the document. :raises TypeError: If parameter 'item' is not of type :class:`~pyVHDLModel.DesignUnits.DesignUnit`. :raises ValueError: If parameter 'item' is an unknown :class:`~pyVHDLModel.DesignUnits.DesignUnit`. :raises VHDLModelException: If configuration name already exists in document. """ if not isinstance(item, DesignUnit): ex = TypeError(f"Parameter 'item' is not of type 'DesignUnit'.") if version_info >= (3, 11): # pragma: no cover ex.add_note(f"Got type '{getFullyQualifiedName(item)}'.") raise ex if isinstance(item, Entity): self._AddEntity(item) elif isinstance(item, Architecture): self._AddArchitecture(item) elif isinstance(item, Package): self._AddPackage(item) elif isinstance(item, PackageBody): self._AddPackageBody(item) elif isinstance(item, Context): self._AddContext(item) elif isinstance(item, Configuration): self._AddConfiguration(item) elif isinstance(item, VerificationUnit): self._AddVerificationUnit(item) elif isinstance(item, VerificationProperty): self._AddVerificationProperty(item) elif isinstance(item, VerificationMode): self._AddVerificationMode(item) else: ex = ValueError(f"Parameter 'item' is an unknown 'DesignUnit'.") if version_info >= (3, 11): # pragma: no cover ex.add_note(f"Got type '{getFullyQualifiedName(item)}'.") raise ex
@readonly def Path(self) -> Path: """ Read-only property to access the document's path (:attr:`_path`). :returns: The path of this document. """ return self._path @readonly def DesignUnits(self) -> List[DesignUnit]: """ Read-only property to access a list of all design units declarations found in this document (:attr:`_designUnits`). :returns: List of all design units. """ return self._designUnits @readonly def Contexts(self) -> Dict[str, Context]: """ Read-only property to access a list of all context declarations found in this document (:attr:`_contexts`). :returns: List of all contexts. """ return self._contexts @readonly def Configurations(self) -> Dict[str, Configuration]: """ Read-only property to access a list of all configuration declarations found in this document (:attr:`_configurations`). :returns: List of all configurations. """ return self._configurations @readonly def Entities(self) -> Dict[str, Entity]: """ Read-only property to access a list of all entity declarations found in this document (:attr:`_entities`). :returns: List of all entities. """ return self._entities @readonly def Architectures(self) -> Dict[str, Dict[str, Architecture]]: """ Read-only property to access a list of all architecture declarations found in this document (:attr:`_architectures`). :returns: List of all architectures. """ return self._architectures @readonly def Packages(self) -> Dict[str, Package]: """ Read-only property to access a list of all package declarations found in this document (:attr:`_packages`). :returns: List of all packages. """ return self._packages @readonly def PackageBodies(self) -> Dict[str, PackageBody]: """ Read-only property to access a list of all package body declarations found in this document (:attr:`_packageBodies`). :returns: List of all package bodies. """ return self._packageBodies @readonly def VerificationUnits(self) -> Dict[str, VerificationUnit]: """ Read-only property to access a list of all verification unit declarations found in this document (:attr:`_verificationUnits`). :returns: List of all verification units. """ return self._verificationUnits @readonly def VerificationProperties(self) -> Dict[str, VerificationProperty]: """ Read-only property to access a list of all verification properties declarations found in this document (:attr:`_verificationProperties`). :returns: List of all verification properties. """ return self._verificationProperties @readonly def VerificationModes(self) -> Dict[str, VerificationMode]: """ Read-only property to access a list of all verification modes declarations found in this document (:attr:`_verificationModes`). :returns: List of all verification modes. """ return self._verificationModes @readonly def CompileOrderVertex(self) -> Vertex[None, None, None, 'Document', None, None, None, None, None, None, None, None, None, None, None, None, None]: """ Read-only property to access the corresponding compile-order vertex (:attr:`_compileOrderVertex`). The compile-order vertex references this document by its value field. :returns: The corresponding compile-order vertex. """ return self._compileOrderVertex
[docs] def IterateDesignUnits(self, filter: DesignUnitKind = DesignUnitKind.All) -> Generator[DesignUnit, None, None]: """ Iterate all design units in the document. A union of :class:`DesignUnitKind` values can be given to filter the returned result for suitable design units. .. rubric:: Algorithm * If contexts are selected in the filter: 1. Iterate all contexts in that library. * If packages are selected in the filter: 1. Iterate all packages in that library. * If package bodies are selected in the filter: 1. Iterate all package bodies in that library. * If entites are selected in the filter: 1. Iterate all entites in that library. * If architectures are selected in the filter: 1. Iterate all architectures in that library. * If configurations are selected in the filter: 1. Iterate all configurations in that library. :param filter: An enumeration with possibly multiple flags to filter the returned design units. :returns: A generator to iterate all matched design units in the document. .. seealso:: :meth:`pyVHDLModel.Design.IterateDesignUnits` Iterate all design units in the design. :meth:`pyVHDLModel.Library.IterateDesignUnits` Iterate all design units in the library. """ if DesignUnitKind.Context in filter: for context in self._contexts.values(): yield context if DesignUnitKind.Package in filter: for package in self._packages.values(): yield package if DesignUnitKind.PackageBody in filter: for packageBody in self._packageBodies.values(): yield packageBody if DesignUnitKind.Entity in filter: for entity in self._entities.values(): yield entity if DesignUnitKind.Architecture in filter: for architectures in self._architectures.values(): for architecture in architectures.values(): yield architecture if DesignUnitKind.Configuration in filter: for configuration in self._configurations.values(): yield configuration
# for verificationProperty in self._verificationUnits.values(): # yield verificationProperty # for verificationUnit in self._verificationProperties.values(): # yield entity # for verificationMode in self._verificationModes.values(): # yield verificationMode
[docs] def __repr__(self) -> str: """ Formats a representation of the document. **Format:** ``Document: 'path/to/file.vhdl'`` :returns: String representation of the document. """ return f"Document: '{self._path}'"
__str__ = __repr__