Source code for pyVHDLModel.Concurrent

# ==================================================================================================================== #
#             __     ___   _ ____  _     __  __           _      _                                                     #
#   _ __  _   \ \   / / | | |  _ \| |   |  \/  | ___   __| | ___| |                                                    #
#  | '_ \| | | \ \ / /| |_| | | | | |   | |\/| |/ _ \ / _` |/ _ \ |                                                    #
#  | |_) | |_| |\ V / |  _  | |_| | |___| |  | | (_) | (_| |  __/ |                                                    #
#  | .__/ \__, | \_/  |_| |_|____/|_____|_|  |_|\___/ \__,_|\___|_|                                                    #
#  |_|    |___/                                                                                                        #
# ==================================================================================================================== #
# Authors:                                                                                                             #
#   Patrick Lehmann                                                                                                    #
#                                                                                                                      #
# License:                                                                                                             #
# ==================================================================================================================== #
# Copyright 2017-2023 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                                                                                  #
# ==================================================================================================================== #
#
"""
This module contains parts of an abstract document language model for VHDL.

Concurrent defines all concurrent statements used in entities, architectures, generates and block statements.
"""
from typing                  import List, Dict, Union, Iterable, Generator, Optional as Nullable

from pyTooling.Decorators    import export
from pyTooling.MetaClasses   import ExtendedType

from pyVHDLModel.Base        import ModelEntity, LabeledEntityMixin, DocumentedEntityMixin, Range, BaseChoice, BaseCase, IfBranchMixin
from pyVHDLModel.Base        import ElsifBranchMixin, ElseBranchMixin, AssertStatementMixin, BlockStatementMixin, WaveformElement
from pyVHDLModel.Regions     import ConcurrentDeclarationRegionMixin
from pyVHDLModel.Namespace   import Namespace
from pyVHDLModel.Name        import Name
from pyVHDLModel.Symbol      import ComponentInstantiationSymbol, EntityInstantiationSymbol, ArchitectureSymbol, ConfigurationInstantiationSymbol
from pyVHDLModel.Expression  import BaseExpression, QualifiedExpression, FunctionCall, TypeConversion, Literal
from pyVHDLModel.Association import AssociationItem, ParameterAssociationItem
from pyVHDLModel.Interface   import PortInterfaceItemMixin
from pyVHDLModel.Common      import Statement, ProcedureCallMixin, SignalAssignmentMixin
from pyVHDLModel.Sequential  import SequentialStatement, SequentialStatementsMixin, SequentialDeclarationsMixin


ExpressionUnion = Union[
	BaseExpression,
	QualifiedExpression,
	FunctionCall,
	TypeConversion,
	# ConstantOrSymbol,     TODO: ObjectSymbol
	Literal,
]


[docs] @export class ConcurrentStatement(Statement): """A base-class for all concurrent statements."""
[docs] @export class ConcurrentStatementsMixin(metaclass=ExtendedType, mixin=True): """ A mixin-class for all language constructs supporting concurrent statements. .. seealso:: .. todo:: concurrent declaration region """ _statements: List[ConcurrentStatement] _instantiations: Dict[str, 'Instantiation'] # TODO: add another instantiation class level for entity/configuration/component inst. _blocks: Dict[str, 'ConcurrentBlockStatement'] _generates: Dict[str, 'GenerateStatement'] _hierarchy: Dict[str, Union['ConcurrentBlockStatement', 'GenerateStatement']]
[docs] def __init__(self, statements: Iterable[ConcurrentStatement] = None): self._statements = [] self._instantiations = {} self._blocks = {} self._generates = {} self._hierarchy = {} if statements is not None: for statement in statements: self._statements.append(statement) statement._parent = self
@property def Statements(self) -> List[ConcurrentStatement]: return self._statements def IterateInstantiations(self) -> Generator['Instantiation', None, None]: for instance in self._instantiations.values(): yield instance for block in self._blocks.values(): yield from block.IterateInstantiations() for generate in self._generates.values(): yield from generate.IterateInstantiations() # TODO: move into _init__ def IndexStatements(self): for statement in self._statements: if isinstance(statement, (EntityInstantiation, ComponentInstantiation, ConfigurationInstantiation)): self._instantiations[statement.NormalizedLabel] = statement elif isinstance(statement, (ForGenerateStatement, IfGenerateStatement, CaseGenerateStatement)): self._generates[statement.NormalizedLabel] = statement statement.IndexStatement() elif isinstance(statement, ConcurrentBlockStatement): self._hierarchy[statement.NormalizedLabel] = statement statement.IndexStatements()
[docs] @export class Instantiation(ConcurrentStatement): """ A base-class for all (component) instantiations. """ _genericAssociations: List[AssociationItem] _portAssociations: List[AssociationItem]
[docs] def __init__(self, label: str, genericAssociations: Iterable[AssociationItem] = None, portAssociations: Iterable[AssociationItem] = None): super().__init__(label) # TODO: extract to mixin self._genericAssociations = [] if genericAssociations is not None: for association in genericAssociations: self._genericAssociations.append(association) association._parent = self # TODO: extract to mixin self._portAssociations = [] if portAssociations is not None: for association in portAssociations: self._portAssociations.append(association) association._parent = self
@property def GenericAssociations(self) -> List[AssociationItem]: return self._genericAssociations @property def PortAssociations(self) -> List[AssociationItem]: return self._portAssociations
[docs] @export class ComponentInstantiation(Instantiation): """ Represents a component instantiation by referring to a component name. .. admonition:: Example .. code-block:: VHDL inst : component Counter; """ _component: ComponentInstantiationSymbol
[docs] def __init__(self, label: str, componentSymbol: ComponentInstantiationSymbol, genericAssociations: Iterable[AssociationItem] = None, portAssociations: Iterable[AssociationItem] = None): super().__init__(label, genericAssociations, portAssociations) self._component = componentSymbol componentSymbol._parent = self
@property def Component(self) -> ComponentInstantiationSymbol: return self._component
[docs] @export class EntityInstantiation(Instantiation): """ Represents an entity instantiation by referring to an entity name with optional architecture name. .. admonition:: Example .. code-block:: VHDL inst : entity work. Counter; """ _entity: EntityInstantiationSymbol _architecture: ArchitectureSymbol
[docs] def __init__(self, label: str, entitySymbol: EntityInstantiationSymbol, architectureSymbol: ArchitectureSymbol = None, genericAssociations: Iterable[AssociationItem] = None, portAssociations: Iterable[AssociationItem] = None): super().__init__(label, genericAssociations, portAssociations) self._entity = entitySymbol entitySymbol._parent = self self._architecture = architectureSymbol if architectureSymbol is not None: architectureSymbol._parent = self
@property def Entity(self) -> EntityInstantiationSymbol: return self._entity @property def Architecture(self) -> ArchitectureSymbol: return self._architecture
[docs] @export class ConfigurationInstantiation(Instantiation): """ Represents a configuration instantiation by referring to a configuration name. .. admonition:: Example .. code-block:: VHDL inst : configuration Counter; """ _configuration: ConfigurationInstantiationSymbol
[docs] def __init__(self, label: str, configurationSymbol: ConfigurationInstantiationSymbol, genericAssociations: Iterable[AssociationItem] = None, portAssociations: Iterable[AssociationItem] = None): super().__init__(label, genericAssociations, portAssociations) self._configuration = configurationSymbol configurationSymbol._parent = self
@property def Configuration(self) -> ConfigurationInstantiationSymbol: return self._configuration
[docs] @export class ProcessStatement(ConcurrentStatement, SequentialDeclarationsMixin, SequentialStatementsMixin, DocumentedEntityMixin): """ Represents a process statement with sensitivity list, sequential declaration region and sequential statements. .. admonition:: Example .. code-block:: VHDL proc: process(Clock) -- sequential declarations begin -- sequential statements end process; """ _sensitivityList: List[Name] # TODO: implement a SignalSymbol
[docs] def __init__( self, label: str = None, declaredItems: Iterable = None, statements: Iterable[SequentialStatement] = None, sensitivityList: Iterable[Name] = None, documentation: str = None ): super().__init__(label) SequentialDeclarationsMixin.__init__(self, declaredItems) SequentialStatementsMixin.__init__(self, statements) DocumentedEntityMixin.__init__(self, documentation) if sensitivityList is None: self._sensitivityList = None else: self._sensitivityList = [] # TODO: convert to dict for signalSymbol in sensitivityList: self._sensitivityList.append(signalSymbol)
# signalSymbol._parent = self # FIXME: currently str are provided @property def SensitivityList(self) -> List[Name]: return self._sensitivityList
[docs] @export class ConcurrentProcedureCall(ConcurrentStatement, ProcedureCallMixin):
[docs] def __init__(self, label: str, procedureName: Name, parameterMappings: Iterable[ParameterAssociationItem] = None): super().__init__(label) ProcedureCallMixin.__init__(self, procedureName, parameterMappings)
[docs] @export class ConcurrentBlockStatement(ConcurrentStatement, BlockStatementMixin, LabeledEntityMixin, ConcurrentDeclarationRegionMixin, ConcurrentStatementsMixin, DocumentedEntityMixin): _portItems: List[PortInterfaceItemMixin]
[docs] def __init__( self, label: str, portItems: Iterable[PortInterfaceItemMixin] = None, declaredItems: Iterable = None, statements: Iterable['ConcurrentStatement'] = None, documentation: str = None ): super().__init__(label) BlockStatementMixin.__init__(self) LabeledEntityMixin.__init__(self, label) ConcurrentDeclarationRegionMixin.__init__(self, declaredItems) ConcurrentStatementsMixin.__init__(self, statements) DocumentedEntityMixin.__init__(self, documentation) # TODO: extract to mixin self._portItems = [] if portItems is not None: for item in portItems: self._portItems.append(item) item._parent = self
@property def PortItems(self) -> List[PortInterfaceItemMixin]: return self._portItems
[docs] @export class GenerateBranch(ModelEntity, ConcurrentDeclarationRegionMixin, ConcurrentStatementsMixin): """ A base-class for all branches in a generate statements. .. seealso:: * :class:`If-generate branch <pyVHDLModel.Concurrent.IfGenerateBranch>` * :class:`Elsif-generate branch <pyVHDLModel.Concurrent.ElsifGenerateBranch>` * :class:`Else-generate branch <pyVHDLModel.Concurrent.ElseGenerateBranch>` """ _alternativeLabel: Nullable[str] _normalizedAlternativeLabel: Nullable[str] _namespace: Namespace
[docs] def __init__(self, declaredItems: Iterable = None, statements: Iterable[ConcurrentStatement] = None, alternativeLabel: str = None): super().__init__() ConcurrentDeclarationRegionMixin.__init__(self, declaredItems) ConcurrentStatementsMixin.__init__(self, statements) self._alternativeLabel = alternativeLabel self._normalizedAlternativeLabel = alternativeLabel.lower() if alternativeLabel is not None else None self._namespace = Namespace(self._normalizedAlternativeLabel)
@property def AlternativeLabel(self) -> Nullable[str]: return self._alternativeLabel @property def NormalizedAlternativeLabel(self) -> Nullable[str]: return self._normalizedAlternativeLabel
[docs] @export class IfGenerateBranch(GenerateBranch, IfBranchMixin): """ Represents if-generate branch in a generate statement with a concurrent declaration region and concurrent statements. .. admonition:: Example .. code-block:: VHDL gen: if condition generate -- concurrent declarations begin -- concurrent statements elsif condition generate -- ... else generate -- ... end generate; """
[docs] def __init__(self, condition: ExpressionUnion, declaredItems: Iterable = None, statements: Iterable[ConcurrentStatement] = None, alternativeLabel: str = None): super().__init__(declaredItems, statements, alternativeLabel) IfBranchMixin.__init__(self, condition)
[docs] @export class ElsifGenerateBranch(GenerateBranch, ElsifBranchMixin): """ Represents elsif-generate branch in a generate statement with a concurrent declaration region and concurrent statements. .. admonition:: Example .. code-block:: VHDL gen: if condition generate -- ... elsif condition generate -- concurrent declarations begin -- concurrent statements else generate -- ... end generate; """
[docs] def __init__(self, condition: ExpressionUnion, declaredItems: Iterable = None, statements: Iterable[ConcurrentStatement] = None, alternativeLabel: str = None): super().__init__(declaredItems, statements, alternativeLabel) ElsifBranchMixin.__init__(self, condition)
[docs] @export class ElseGenerateBranch(GenerateBranch, ElseBranchMixin): """ Represents else-generate branch in a generate statement with a concurrent declaration region and concurrent statements. .. admonition:: Example .. code-block:: VHDL gen: if condition generate -- ... elsif condition generate -- ... else generate -- concurrent declarations begin -- concurrent statements end generate; """
[docs] def __init__(self, declaredItems: Iterable = None, statements: Iterable[ConcurrentStatement] = None, alternativeLabel: str = None): super().__init__(declaredItems, statements, alternativeLabel) ElseBranchMixin.__init__(self)
[docs] @export class GenerateStatement(ConcurrentStatement): """ A base-class for all generate statements. .. seealso:: * :class:`If...generate statement <pyVHDLModel.Concurrent.IfGenerateStatement>` * :class:`Case...generate statement <pyVHDLModel.Concurrent.CaseGenerateStatement>` * :class:`For...generate statement <pyVHDLModel.Concurrent.ForGenerateStatement>` """ _namespace: Namespace
[docs] def __init__(self, label: str = None): super().__init__(label) self._namespace = Namespace(self._normalizedLabel)
# @mustoverride def IterateInstantiations(self) -> Generator[Instantiation, None, None]: raise NotImplementedError() # @mustoverride def IndexStatement(self) -> None: raise NotImplementedError()
[docs] @export class IfGenerateStatement(GenerateStatement): """ Represents an if...generate statement. .. admonition:: Example .. code-block:: VHDL gen: if condition generate -- ... elsif condition generate -- ... else generate -- ... end generate; .. seealso:: * :class:`Generate branch <pyVHDLModel.Concurrent.GenerateBranch>` base-class * :class:`If-generate branch <pyVHDLModel.Concurrent.IfGenerateBranch>` * :class:`Elsif-generate branch <pyVHDLModel.Concurrent.ElsifGenerateBranch>` * :class:`Else-generate branch <pyVHDLModel.Concurrent.ElseGenerateBranch>` """ _ifBranch: IfGenerateBranch _elsifBranches: List[ElsifGenerateBranch] _elseBranch: Nullable[ElseGenerateBranch]
[docs] def __init__(self, label: str, ifBranch: IfGenerateBranch, elsifBranches: Iterable[ElsifGenerateBranch] = None, elseBranch: ElseGenerateBranch = None): super().__init__(label) self._ifBranch = ifBranch ifBranch._parent = self self._elsifBranches = [] if elsifBranches is not None: for branch in elsifBranches: self._elsifBranches.append(branch) branch._parent = self if elseBranch is not None: self._elseBranch = elseBranch elseBranch._parent = self else: self._elseBranch = None
@property def IfBranch(self) -> IfGenerateBranch: return self._ifBranch @property def ElsifBranches(self) -> List[ElsifGenerateBranch]: return self._elsifBranches @property def ElseBranch(self) -> Nullable[ElseGenerateBranch]: return self._elseBranch def IterateInstantiations(self) -> Generator[Instantiation, None, None]: yield from self._ifBranch.IterateInstantiations() for branch in self._elsifBranches: yield from branch.IterateInstantiations() if self._elseBranch is not None: yield from self._ifBranch.IterateInstantiations() def IndexStatement(self) -> None: self._ifBranch.IndexStatements() for branch in self._elsifBranches: branch.IndexStatements() if self._elseBranch is not None: self._elseBranch.IndexStatements()
[docs] @export class ConcurrentChoice(BaseChoice): """A base-class for all concurrent choices (in case...generate statements)."""
[docs] @export class IndexedGenerateChoice(ConcurrentChoice): _expression: ExpressionUnion
[docs] def __init__(self, expression: ExpressionUnion): super().__init__() self._expression = expression expression._parent = self
@property def Expression(self) -> ExpressionUnion: return self._expression
[docs] def __str__(self) -> str: return str(self._expression)
[docs] @export class RangedGenerateChoice(ConcurrentChoice): _range: 'Range'
[docs] def __init__(self, rng: 'Range'): super().__init__() self._range = rng rng._parent = self
@property def Range(self) -> 'Range': return self._range
[docs] def __str__(self) -> str: return str(self._range)
[docs] @export class ConcurrentCase(BaseCase, LabeledEntityMixin, ConcurrentDeclarationRegionMixin, ConcurrentStatementsMixin):
[docs] def __init__(self, declaredItems: Iterable = None, statements: Iterable[ConcurrentStatement] = None, alternativeLabel: str = None): super().__init__() LabeledEntityMixin.__init__(self, alternativeLabel) ConcurrentDeclarationRegionMixin.__init__(self, declaredItems) ConcurrentStatementsMixin.__init__(self, statements)
[docs] @export class GenerateCase(ConcurrentCase): _choices: List[ConcurrentChoice]
[docs] def __init__(self, choices: Iterable[ConcurrentChoice], declaredItems: Iterable = None, statements: Iterable[ConcurrentStatement] = None, alternativeLabel: str = None): super().__init__(declaredItems, statements, alternativeLabel) # TODO: move to parent or grandparent self._choices = [] if choices is not None: for choice in choices: self._choices.append(choice) choice._parent = self
# TODO: move to parent or grandparent @property def Choices(self) -> List[ConcurrentChoice]: return self._choices
[docs] def __str__(self) -> str: return "when {choices} =>".format(choices=" | ".join(str(c) for c in self._choices))
[docs] @export class OthersGenerateCase(ConcurrentCase):
[docs] def __str__(self) -> str: return "when others =>"
[docs] @export class CaseGenerateStatement(GenerateStatement): """ Represents a case...generate statement. .. admonition:: Example .. code-block:: VHDL gen: case selector generate case choice1 => -- ... case choice2 => -- ... case others => -- ... end generate; """ _expression: ExpressionUnion _cases: List[GenerateCase]
[docs] def __init__(self, label: str, expression: ExpressionUnion, cases: Iterable[ConcurrentCase]): super().__init__(label) self._expression = expression expression._parent = self # TODO: create a mixin for things with cases self._cases = [] if cases is not None: for case in cases: self._cases.append(case) case._parent = self
@property def SelectExpression(self) -> ExpressionUnion: return self._expression @property def Cases(self) -> List[GenerateCase]: return self._cases def IterateInstantiations(self) -> Generator[Instantiation, None, None]: for case in self._cases: yield from case.IterateInstantiations() def IndexStatement(self): for case in self._cases: case.IndexStatements()
[docs] @export class ForGenerateStatement(GenerateStatement, ConcurrentDeclarationRegionMixin, ConcurrentStatementsMixin): """ Represents a for...generate statement. .. admonition:: Example .. code-block:: VHDL gen: for i in 0 to 3 generate -- ... end generate; """ _loopIndex: str _range: Range
[docs] def __init__(self, label: str, loopIndex: str, rng: Range, declaredItems: Iterable = None, statements: Iterable[ConcurrentStatement] = None): super().__init__(label) ConcurrentDeclarationRegionMixin.__init__(self, declaredItems) ConcurrentStatementsMixin.__init__(self, statements) self._loopIndex = loopIndex self._range = rng rng._parent = self
@property def LoopIndex(self) -> str: return self._loopIndex @property def Range(self) -> Range: return self._range # IndexDeclaredItems = ConcurrentStatements.IndexDeclaredItems def IndexStatement(self) -> None: self.IndexStatements() def IndexStatements(self) -> None: super().IndexStatements() def IterateInstantiations(self) -> Generator[Instantiation, None, None]: return ConcurrentStatementsMixin.IterateInstantiations(self)
[docs] @export class ConcurrentSignalAssignment(ConcurrentStatement, SignalAssignmentMixin): """ A base-class for concurrent signal assignments. .. seealso:: * :class:`~pyVHDLModel.Concurrent.ConcurrentSimpleSignalAssignment` * :class:`~pyVHDLModel.Concurrent.ConcurrentSelectedSignalAssignment` * :class:`~pyVHDLModel.Concurrent.ConcurrentConditionalSignalAssignment` """
[docs] def __init__(self, label: str, target: Name): super().__init__(label) SignalAssignmentMixin.__init__(self, target)
[docs] @export class ConcurrentSimpleSignalAssignment(ConcurrentSignalAssignment): _waveform: List[WaveformElement]
[docs] def __init__(self, label: str, target: Name, waveform: Iterable[WaveformElement]): super().__init__(label, target) # TODO: extract to mixin self._waveform = [] if waveform is not None: for waveformElement in waveform: self._waveform.append(waveformElement) waveformElement._parent = self
@property def Waveform(self) -> List[WaveformElement]: return self._waveform
[docs] @export class ConcurrentSelectedSignalAssignment(ConcurrentSignalAssignment):
[docs] def __init__(self, label: str, target: Name, expression: ExpressionUnion): super().__init__(label, target)
[docs] @export class ConcurrentConditionalSignalAssignment(ConcurrentSignalAssignment):
[docs] def __init__(self, label: str, target: Name, expression: ExpressionUnion): super().__init__(label, target)
[docs] @export class ConcurrentAssertStatement(ConcurrentStatement, AssertStatementMixin):
[docs] def __init__(self, condition: ExpressionUnion, message: ExpressionUnion, severity: ExpressionUnion = None, label: str = None): super().__init__(label) AssertStatementMixin.__init__(self, condition, message, severity)