diff options
Diffstat (limited to 'pyGHDL/dom/Sequential.py')
-rw-r--r-- | pyGHDL/dom/Sequential.py | 388 |
1 files changed, 388 insertions, 0 deletions
diff --git a/pyGHDL/dom/Sequential.py b/pyGHDL/dom/Sequential.py new file mode 100644 index 000000000..896b09544 --- /dev/null +++ b/pyGHDL/dom/Sequential.py @@ -0,0 +1,388 @@ +# ============================================================================= +# ____ _ _ ____ _ _ +# _ __ _ _ / ___| | | | _ \| | __| | ___ _ __ ___ +# | '_ \| | | | | _| |_| | | | | | / _` |/ _ \| '_ ` _ \ +# | |_) | |_| | |_| | _ | |_| | |___ | (_| | (_) | | | | | | +# | .__/ \__, |\____|_| |_|____/|_____(_)__,_|\___/|_| |_| |_| +# |_| |___/ +# ============================================================================= +# Authors: +# Patrick Lehmann +# +# Package module: DOM: Sequential statements. +# +# License: +# ============================================================================ +# Copyright (C) 2019-2021 Tristan Gingold +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <gnu.org/licenses>. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ============================================================================ +from typing import Iterable + +from pydecor import export + +from pyGHDL.dom.Concurrent import WaveformElement # TODO: move out from concurrent? +from pyGHDL.dom.Range import Range +from pyVHDLModel.SyntaxModel import ( + IfBranch as VHDLModel_IfBranch, + ElsifBranch as VHDLModel_ElsifBranch, + ElseBranch as VHDLModel_ElseBranch, + IfStatement as VHDLModel_IfStatement, + IndexedChoice as VHDLModel_IndexedChoice, + RangedChoice as VHDLModel_RangedChoice, + OthersCase as VHDLModel_OthersCase, + Case as VHDLModel_Case, + CaseStatement as VHDLModel_CaseStatement, + ForLoopStatement as VHDLModel_ForLoopStatement, + SequentialSimpleSignalAssignment as VHDLModel_SequentialSimpleSignalAssignment, + SequentialProcedureCall as VHDLModel_SequentialProcedureCall, + Name, + SequentialStatement, + Expression, + SequentialChoice, SequentialCase, +) + + +from pyGHDL.libghdl import Iir, utils +from pyGHDL.libghdl.vhdl import nodes +from pyGHDL.dom import DOMMixin +from pyGHDL.dom._Utils import GetNameOfNode + + +@export +class IfBranch(VHDLModel_IfBranch): + def __init__( + self, + branchNode: Iir, + condition: Expression, + statements: Iterable[SequentialStatement] = None, + ): + super().__init__(condition, statements) + DOMMixin.__init__(self, branchNode) + + @classmethod + def parse(cls, generateNode: Iir, label: str) -> "IfBranch": + from pyGHDL.dom._Translate import ( + GetSequentialStatementsFromChainedNodes, + GetExpressionFromNode, + ) + + condition = GetExpressionFromNode(nodes.Get_Condition(generateNode)) + body = nodes.Get_Generate_Statement_Body(generateNode) + + statementChain = nodes.Get_Sequential_Statement_Chain(body) + statements = GetSequentialStatementsFromChainedNodes( + statementChain, "if branch", label + ) + + return cls(generateNode, condition, statements) + + +@export +class ElsifBranch(VHDLModel_ElsifBranch): + def __init__( + self, + branchNode: Iir, + condition: Expression, + statements: Iterable[SequentialStatement] = None, + ): + super().__init__(condition, statements) + DOMMixin.__init__(self, branchNode) + + @classmethod + def parse(cls, generateNode: Iir, condition: Iir, label: str) -> "ElsifBranch": + from pyGHDL.dom._Translate import ( + GetSequentialStatementsFromChainedNodes, + GetExpressionFromNode, + ) + + condition = GetExpressionFromNode(condition) + body = nodes.Get_Generate_Statement_Body(generateNode) + + statementChain = nodes.Get_Sequential_Statement_Chain(body) + statements = GetSequentialStatementsFromChainedNodes( + statementChain, "elsif branch", label + ) + + return cls(generateNode, condition, statements) + + +@export +class ElseBranch(VHDLModel_ElseBranch): + def __init__( + self, + branchNode: Iir, + statements: Iterable[SequentialStatement] = None, + ): + super().__init__(statements) + DOMMixin.__init__(self, branchNode) + + @classmethod + def parse(cls, generateNode: Iir, label: str) -> "ElseBranch": + from pyGHDL.dom._Translate import ( + GetSequentialStatementsFromChainedNodes, + ) + + body = nodes.Get_Generate_Statement_Body(generateNode) + + statementChain = nodes.Get_Sequential_Statement_Chain(body) + statements = GetSequentialStatementsFromChainedNodes( + statementChain, "else branch", label + ) + + return cls(generateNode, statements) + + +@export +class IfStatement(VHDLModel_IfStatement, DOMMixin): + def __init__( + self, + generateNode: Iir, + ifBranch: IfBranch, + elsifBranches: Iterable[ElsifBranch] = None, + elseBranch: ElseBranch = None, + label: str = None, + ): + super().__init__(ifBranch, elsifBranches, elseBranch, label) + DOMMixin.__init__(self, generateNode) + + @classmethod + def parse(cls, generateNode: Iir, label: str) -> "IfStatement": + ifBranch = IfBranch.parse(generateNode, label) + elsifBranches = [] + elseBranch = None + # WORKAROUND: Python 3.8 syntax + # elseClause = generateNode + # while (elseClause := nodes.Get_Generate_Else_Clause(elseClause)) != nodes.Null_Iir: + elseClause = nodes.Get_Generate_Else_Clause(generateNode) + while elseClause != nodes.Null_Iir: + condition = nodes.Get_Condition(elseClause) + if condition != nodes.Null_Iir: + elsifBranches.append(ElsifBranch.parse(elseClause, condition, label)) + else: + elseBranch = ElseBranch.parse(elseClause, label) + break + + elseClause = nodes.Get_Generate_Else_Clause(elseClause) + + return cls(generateNode, ifBranch, elsifBranches, elseBranch, label) + + +@export +class IndexedChoice(VHDLModel_IndexedChoice, DOMMixin): + def __init__(self, node: Iir, expression: Expression): + super().__init__(expression) + DOMMixin.__init__(self, node) + + +@export +class RangedChoice(VHDLModel_RangedChoice, DOMMixin): + def __init__(self, node: Iir, rng: Range): + super().__init__(rng) + DOMMixin.__init__(self, node) + + +@export +class Case(VHDLModel_Case, DOMMixin): + def __init__(self, node: Iir, choices: Iterable[SequentialChoice], statements: Iterable[SequentialStatement]): + super().__init__(choices, statements) + DOMMixin.__init__(self, node) + + @classmethod + def parse(cls, caseNode: Iir, label: str) -> "Case": + from pyGHDL.dom._Translate import ( + GetSequentialStatementsFromChainedNodes, + ) + + body = nodes.Get_Generate_Statement_Body(caseNode) + + statementChain = nodes.Get_Sequential_Statement_Chain(body) + statements = GetSequentialStatementsFromChainedNodes( + statementChain, "case", label + ) + + choices = [] + + return cls(caseNode, choices, statements) + + +@export +class OthersCase(VHDLModel_OthersCase, DOMMixin): + def __init__( + self, + caseNode: Iir, + statements: Iterable[SequentialStatement] = None, + ): + super().__init__(statements) + DOMMixin.__init__(self, caseNode) + + @classmethod + def parse(cls, caseNode: Iir) -> "OthersCase": + from pyGHDL.dom._Translate import ( + GetDeclaredItemsFromChainedNodes, + GetSequentialStatementsFromChainedNodes, + ) + + # body = nodes.Get_Generate_Statement_Body(caseNode) + # + # statementChain = nodes.Get_Sequential_Statement_Chain(body) + # statements = GetStatementsFromChainedNodes( + # statementChain, "else branch", alternativeLabel + # ) + + # return cls(caseNode, declaredItems, statements, alternativeLabel) + return cls(caseNode, [], [], "") + + +@export +class CaseStatement(VHDLModel_CaseStatement, DOMMixin): + def __init__( + self, generateNode: Iir, label: str, expression: Expression, cases: Iterable[SequentialCase] + ): + super().__init__(expression, cases, label) + DOMMixin.__init__(self, generateNode) + + @classmethod + def parse(cls, generateNode: Iir, label: str) -> "CaseStatement": + from pyGHDL.dom._Translate import ( + GetExpressionFromNode, + GetIirKindOfNode, + GetRangeFromNode, + ) + + # TODO: get choices + + expression = GetExpressionFromNode(nodes.Get_Expression(generateNode)) + + cases = [] + choices = [] + alternatives = nodes.Get_Case_Statement_Alternative_Chain(generateNode) + for alternative in utils.chain_iter(alternatives): + choiceKind = GetIirKindOfNode(alternative) + + if choiceKind in ( + nodes.Iir_Kind.Choice_By_Name, + nodes.Iir_Kind.Choice_By_Expression, + ): + choiceExpression = GetExpressionFromNode( + nodes.Get_Choice_Expression(alternative) + ) + choices.append(IndexedChoice(alternative, choiceExpression)) + cases.append(Case(alternative, choices)) + choices = [] + elif choiceKind is nodes.Iir_Kind.Choice_By_Range: + rng = GetRangeFromNode(nodes.Get_Choice_Range(alternative)) + choices.append(RangedChoice(alternative, rng)) + cases.append(Case(alternative, choices)) + choices = [] + elif choiceKind is nodes.Iir_Kind.Choice_By_Others: + cases.append(OthersCase.parse(alternative)) + else: + print(choiceKind) + + return cls(generateNode, label, expression, cases) + + +@export +class ForLoopStatement(VHDLModel_ForLoopStatement, DOMMixin): + def __init__( + self, + generateNode: Iir, + loopIndex: str, + range: Range, + statements: Iterable[SequentialStatement] = None, + label: str = None, + ): + super().__init__(loopIndex, range, statements, label) + DOMMixin.__init__(self, generateNode) + + @classmethod + def parse(cls, generateNode: Iir, label: str) -> "ForLoopStatement": + from pyGHDL.dom._Translate import ( + GetSequentialStatementsFromChainedNodes, + GetRangeFromNode, + ) + + spec = nodes.Get_Parameter_Specification(generateNode) + loopIndex = GetNameOfNode(spec) + rng = GetRangeFromNode(nodes.Get_Discrete_Range(spec)) + + body = nodes.Get_Generate_Statement_Body(generateNode) + + statementChain = nodes.Get_Sequential_Statement_Chain(body) + statements = GetSequentialStatementsFromChainedNodes( + statementChain, "for", label + ) + + return cls(generateNode, loopIndex, rng, statements, label) + + +@export +class SequentialSimpleSignalAssignment( + VHDLModel_SequentialSimpleSignalAssignment, DOMMixin +): + def __init__( + self, + assignmentNode: Iir, + target: Name, + waveform: Iterable[WaveformElement], + label: str = None, + ): + super().__init__(target, waveform, label) + DOMMixin.__init__(self, assignmentNode) + + @classmethod + def parse( + cls, assignmentNode: Iir, label: str = None + ) -> "SequentialSimpleSignalAssignment": + from pyGHDL.dom._Translate import GetNameFromNode + + target = nodes.Get_Target(assignmentNode) + targetName = GetNameFromNode(target) + + waveform = nodes.Get_Waveform_Chain(assignmentNode) + + # TODO: translate waveforms to series of "expressions". + expression = [None] + + return cls(assignmentNode, targetName, expression, label) + + +@export +class SequentialProcedureCall(VHDLModel_SequentialProcedureCall, DOMMixin): + def __init__( + self, + callNode: Iir, + label: str, + procedureName: Name, + parameterMappings: Iterable, + ): + super().__init__(label, procedureName, parameterMappings) + DOMMixin.__init__(self, callNode) + + @classmethod + def parse(cls, callNode: Iir, label: str) -> "SequentialProcedureCall": + from pyGHDL.dom._Translate import GetNameFromNode, GetIirKindOfNode + + call = nodes.Get_Procedure_Call(callNode) + prefix = nodes.Get_Prefix(call) + + procedureName = GetNameFromNode(prefix) + + # TODO: parameter mappings + parameterMappings = [] + + return cls(callNode, label, procedureName, parameterMappings) |