From 8c0f8e0ad95c53beac983546550222117c6a639c Mon Sep 17 00:00:00 2001 From: Patrick Lehmann Date: Tue, 17 Aug 2021 20:14:13 +0200 Subject: Handle associations. --- pyGHDL/dom/Concurrent.py | 142 ++++++++++++++++++++++++++++++++++-------- pyGHDL/dom/DesignUnit.py | 1 + pyGHDL/dom/_Translate.py | 46 +++++++++++++- testsuite/pyunit/Current.vhdl | 20 ++++-- 4 files changed, 177 insertions(+), 32 deletions(-) diff --git a/pyGHDL/dom/Concurrent.py b/pyGHDL/dom/Concurrent.py index f4681dbf9..2910e596c 100644 --- a/pyGHDL/dom/Concurrent.py +++ b/pyGHDL/dom/Concurrent.py @@ -36,6 +36,9 @@ from pydecor import export from pyGHDL.dom.Range import Range from pyVHDLModel.SyntaxModel import ( + GenericAssociationItem as VHDLModel_GenericAssociationItem, + PortAssociationItem as VHDLModel_PortAssociationItem, + ParameterAssociationItem as VHDLModel_ParameterAssociationItem, ComponentInstantiation as VHDLModel_ComponentInstantiation, EntityInstantiation as VHDLModel_EntityInstantiation, ConfigurationInstantiation as VHDLModel_ConfigurationInstantiation, @@ -60,6 +63,7 @@ from pyVHDLModel.SyntaxModel import ( Expression, ConcurrentChoice, ConcurrentCase, + AssociationItem, ) from pyGHDL.libghdl import Iir, utils @@ -68,24 +72,65 @@ from pyGHDL.dom import DOMMixin, DOMException, Position from pyGHDL.dom._Utils import GetNameOfNode +@export +class GenericAssociationItem(VHDLModel_GenericAssociationItem, DOMMixin): + def __init__(self, associationNode: Iir, actual: Expression, formal: Name = None): + super().__init__(actual, formal) + DOMMixin.__init__(self, associationNode) + + +@export +class PortAssociationItem(VHDLModel_PortAssociationItem, DOMMixin): + def __init__(self, associationNode: Iir, actual: Expression, formal: Name = None): + super().__init__(actual, formal) + DOMMixin.__init__(self, associationNode) + + +@export +class ParameterAssociationItem(VHDLModel_ParameterAssociationItem, DOMMixin): + def __init__(self, associationNode: Iir, actual: Expression, formal: Name = None): + super().__init__(actual, formal) + DOMMixin.__init__(self, associationNode) + + @export class ComponentInstantiation(VHDLModel_ComponentInstantiation, DOMMixin): - def __init__(self, instantiationNode: Iir, label: str, componentName: Name): - super().__init__(label, componentName) + def __init__( + self, + instantiationNode: Iir, + label: str, + componentName: Name, + genericAssociations: Iterable[AssociationItem] = None, + portAssociations: Iterable[AssociationItem] = None, + ): + super().__init__(label, componentName, genericAssociations, portAssociations) DOMMixin.__init__(self, instantiationNode) @classmethod def parse( cls, instantiationNode: Iir, instantiatedUnit: Iir, label: str ) -> "ComponentInstantiation": - from pyGHDL.dom._Translate import GetNameFromNode + from pyGHDL.dom._Translate import ( + GetNameFromNode, + GetGenericMapAspect, + GetPortMapAspect, + ) componentName = GetNameFromNode(instantiatedUnit) + genericAssociations = GetGenericMapAspect( + nodes.Get_Generic_Map_Aspect_Chain(instantiationNode) + ) + portAssociations = GetPortMapAspect( + nodes.Get_Port_Map_Aspect_Chain(instantiationNode) + ) - # TODO: get mapped generics - # TODO: get mapped ports - - return cls(instantiationNode, label, componentName) + return cls( + instantiationNode, + label, + componentName, + genericAssociations, + portAssociations, + ) @export @@ -96,15 +141,23 @@ class EntityInstantiation(VHDLModel_EntityInstantiation, DOMMixin): label: str, entityName: Name, architectureName: Name = None, + genericAssociations: Iterable[AssociationItem] = None, + portAssociations: Iterable[AssociationItem] = None, ): - super().__init__(label, entityName, architectureName) + super().__init__( + label, entityName, architectureName, genericAssociations, portAssociations + ) DOMMixin.__init__(self, instantiationNode) @classmethod def parse( cls, instantiationNode: Iir, instantiatedUnit: Iir, label: str ) -> "EntityInstantiation": - from pyGHDL.dom._Translate import GetNameFromNode + from pyGHDL.dom._Translate import ( + GetNameFromNode, + GetGenericMapAspect, + GetPortMapAspect, + ) entityId = nodes.Get_Entity_Name(instantiatedUnit) entityName = GetNameFromNode(entityId) @@ -114,31 +167,65 @@ class EntityInstantiation(VHDLModel_EntityInstantiation, DOMMixin): if architectureId != nodes.Null_Iir: architectureName = GetNameOfNode(architectureId) - # TODO: get mapped generics - # TODO: get mapped ports + genericAssociations = GetGenericMapAspect( + nodes.Get_Generic_Map_Aspect_Chain(instantiationNode) + ) + portAssociations = GetPortMapAspect( + nodes.Get_Port_Map_Aspect_Chain(instantiationNode) + ) - return cls(instantiationNode, label, entityName, architectureName) + return cls( + instantiationNode, + label, + entityName, + architectureName, + genericAssociations, + portAssociations, + ) @export class ConfigurationInstantiation(VHDLModel_ConfigurationInstantiation, DOMMixin): - def __init__(self, instantiationNode: Iir, label: str, configurationName: Name): - super().__init__(label, configurationName) + def __init__( + self, + instantiationNode: Iir, + label: str, + configurationName: Name, + genericAssociations: Iterable[AssociationItem] = None, + portAssociations: Iterable[AssociationItem] = None, + ): + super().__init__( + label, configurationName, genericAssociations, portAssociations + ) DOMMixin.__init__(self, instantiationNode) @classmethod def parse( cls, instantiationNode: Iir, instantiatedUnit: Iir, label: str ) -> "ConfigurationInstantiation": - from pyGHDL.dom._Translate import GetNameFromNode + from pyGHDL.dom._Translate import ( + GetNameFromNode, + GetGenericMapAspect, + GetPortMapAspect, + ) configurationId = nodes.Get_Configuration_Name(instantiatedUnit) configurationName = GetNameFromNode(configurationId) - # TODO: get mapped generics - # TODO: get mapped ports + genericAssociations = GetGenericMapAspect( + nodes.Get_Generic_Map_Aspect_Chain(instantiationNode) + ) + portAssociations = GetPortMapAspect( + nodes.Get_Port_Map_Aspect_Chain(instantiationNode) + ) - return cls(instantiationNode, label, configurationName) + return cls( + instantiationNode, + label, + configurationName, + genericAssociations, + portAssociations, + ) @export @@ -160,6 +247,9 @@ class ConcurrentBlockStatement(VHDLModel_ConcurrentBlockStatement, DOMMixin): GetConcurrentStatementsFromChainedNodes, ) + # genericAssociations = GetGenericMapAspect(nodes.Get_Generic_Map_Aspect_Chain(instantiationNode)) + # portAssociations = GetPortMapAspect(nodes.Get_Port_Map_Aspect_Chain(instantiationNode)) + declaredItems = GetDeclaredItemsFromChainedNodes( nodes.Get_Declaration_Chain(blockNode), "block", label ) @@ -678,15 +768,15 @@ class ConcurrentProcedureCall(VHDLModel_ConcurrentProcedureCall, DOMMixin): DOMMixin.__init__(self, callNode) @classmethod - def parse(cls, callNode: Iir, label: str) -> "ConcurrentProcedureCall": - from pyGHDL.dom._Translate import GetNameFromNode + def parse(cls, concurrentCallNode: Iir, label: str) -> "ConcurrentProcedureCall": + from pyGHDL.dom._Translate import GetNameFromNode, GetParameterMapAspect - call = nodes.Get_Procedure_Call(callNode) - prefix = nodes.Get_Prefix(call) + callNode = nodes.Get_Procedure_Call(concurrentCallNode) + prefix = nodes.Get_Prefix(callNode) procedureName = GetNameFromNode(prefix) + parameterAssociations = GetParameterMapAspect( + nodes.Get_Parameter_Association_Chain(callNode) + ) - # TODO: parameter mappings - parameterMappings = [] - - return cls(callNode, label, procedureName, parameterMappings) + return cls(concurrentCallNode, label, procedureName, parameterAssociations) diff --git a/pyGHDL/dom/DesignUnit.py b/pyGHDL/dom/DesignUnit.py index 7f4d8e964..5db6c1613 100644 --- a/pyGHDL/dom/DesignUnit.py +++ b/pyGHDL/dom/DesignUnit.py @@ -291,6 +291,7 @@ class PackageInstantiation(VHDLModel_PackageInstantiation, DOMMixin): # FIXME: read use clauses (does it apply here too?) # FIXME: read generics # FIXME: read generic map + # genericAssociations = GetGenericMapAspect(nodes.Get_Generic_Map_Aspect_Chain(instantiationNode)) return cls(packageNode, name, uninstantiatedPackageName) diff --git a/pyGHDL/dom/_Translate.py b/pyGHDL/dom/_Translate.py index 133d9386f..e7e862039 100644 --- a/pyGHDL/dom/_Translate.py +++ b/pyGHDL/dom/_Translate.py @@ -30,7 +30,7 @@ # # SPDX-License-Identifier: GPL-2.0-or-later # ============================================================================ -from typing import List, Generator +from typing import List, Generator, Type from pydecor import export @@ -56,6 +56,7 @@ from pyVHDLModel.SyntaxModel import ( Name, ConcurrentStatement, SequentialStatement, + AssociationItem, ) from pyGHDL.libghdl import utils, name_table @@ -159,6 +160,9 @@ from pyGHDL.dom.Concurrent import ( CaseGenerateStatement, ConcurrentSimpleSignalAssignment, ConcurrentProcedureCall, + GenericAssociationItem, + PortAssociationItem, + ParameterAssociationItem, ) from pyGHDL.dom.Subprogram import Function, Procedure from pyGHDL.dom.Misc import Alias @@ -654,6 +658,46 @@ def GetParameterFromChainedNodes( yield param +def GetMapAspect( + mapAspect: Iir, cls: Type, entity: str +) -> Generator[AssociationItem, None, None]: + for generic in utils.chain_iter(mapAspect): + kind = GetIirKindOfNode(generic) + if kind is nodes.Iir_Kind.Association_Element_By_Expression: + formalNode = nodes.Get_Formal(generic) + if formalNode is nodes.Null_Iir: + formal = None + else: + formal = GetNameFromNode(formalNode) + + actual = GetExpressionFromNode(nodes.Get_Actual(generic)) + + yield cls(generic, actual, formal) + else: + pos = Position.parse(generic) + raise DOMException( + "Unknown association kind '{kind}' in {entity} map at line {line}.".format( + kind=kind.name, entity=entity, line=pos.Line + ) + ) + + +def GetGenericMapAspect( + genericMapAspect: Iir, +) -> Generator[AssociationItem, None, None]: + return GetMapAspect(genericMapAspect, GenericAssociationItem, "generic") + + +def GetPortMapAspect(portMapAspect: Iir) -> Generator[AssociationItem, None, None]: + return GetMapAspect(portMapAspect, PortAssociationItem, "port") + + +def GetParameterMapAspect( + parameterMapAspect: Iir, +) -> Generator[AssociationItem, None, None]: + return GetMapAspect(parameterMapAspect, ParameterAssociationItem, "parameter") + + def GetDeclaredItemsFromChainedNodes( nodeChain: Iir, entity: str, name: str ) -> Generator[ModelEntity, None, None]: diff --git a/testsuite/pyunit/Current.vhdl b/testsuite/pyunit/Current.vhdl index 1f802af47..81887ae7f 100644 --- a/testsuite/pyunit/Current.vhdl +++ b/testsuite/pyunit/Current.vhdl @@ -136,20 +136,29 @@ begin inst1: entity work.counter1(rtl) generic map ( - BITS => 8 + BITS1 => 8 ) port map ( - clk => Clock + clk1 => Clock ); inst2: component counter2 + generic map ( + BITS2 => 8, + value2 + ) port map ( - clk => Clock + clk2 => Clock, + enable2 ); inst3: configuration counter3 + generic map ( + BITS3 => 8 + ) port map ( - clk => Clock + clk3 => Clock, + control(0) => battery and emergency ); blk: block @@ -215,7 +224,8 @@ begin end block; end generate; - call: OtherDummy; + call: CallDummy; + called: CalledDummy(25); ende: std.env.stop; end architecture behav; -- cgit v1.2.3