aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortgingold <tgingold@users.noreply.github.com>2022-12-24 08:56:55 +0100
committerGitHub <noreply@github.com>2022-12-24 08:56:55 +0100
commit26bb3c572eaffafafd8de8ef09b8acc34f91656f (patch)
tree2d70696f4f8bb78f9a4fda7a6d596775fdf080cc
parent8845f761ed2299e595afd5eee2444fed7fb79639 (diff)
parent5d9897770cb16494c6379cce85ed5935532c0cd1 (diff)
downloadghdl-26bb3c572eaffafafd8de8ef09b8acc34f91656f.tar.gz
ghdl-26bb3c572eaffafafd8de8ef09b8acc34f91656f.tar.bz2
ghdl-26bb3c572eaffafafd8de8ef09b8acc34f91656f.zip
Merge pull request #2265 from Paebbels/paebbels/DOM-with-documentation
pyGHDL.dom with Documentation
-rw-r--r--.github/workflows/Test.yml10
-rw-r--r--pyGHDL/dom/Attribute.py17
-rw-r--r--pyGHDL/dom/DesignUnit.py109
-rw-r--r--pyGHDL/dom/InterfaceItem.py168
-rw-r--r--pyGHDL/dom/Misc.py16
-rw-r--r--pyGHDL/dom/NonStandard.py37
-rw-r--r--pyGHDL/dom/Object.py124
-rw-r--r--pyGHDL/dom/Subprogram.py16
-rw-r--r--pyGHDL/dom/Symbol.py24
-rw-r--r--pyGHDL/dom/Type.py25
-rw-r--r--pyGHDL/dom/_Translate.py55
-rw-r--r--pyGHDL/dom/_Utils.py16
-rw-r--r--pyGHDL/dom/__init__.py2
-rw-r--r--pyGHDL/dom/formatting/prettyprint.py6
-rw-r--r--pyGHDL/dom/requirements.txt2
-rw-r--r--testsuite/pyunit/SimplePackage.vhdl13
-rw-r--r--testsuite/pyunit/dom/Expressions.py10
-rw-r--r--testsuite/pyunit/dom/Literals.py10
-rw-r--r--testsuite/pyunit/dom/Sanity.py7
-rw-r--r--testsuite/pyunit/dom/Simple.py (renamed from testsuite/pyunit/dom/SimpleEntity.py)76
-rw-r--r--testsuite/pyunit/dom/SimplePackage.py63
-rw-r--r--testsuite/pyunit/dom/StopWatch.py109
-rw-r--r--testsuite/pyunit/dom/examples/SimpleEntity.vhdl (renamed from testsuite/pyunit/SimpleEntity.vhdl)4
-rw-r--r--testsuite/pyunit/dom/examples/SimplePackage.vhdl28
-rw-r--r--testsuite/pyunit/dom/examples/StopWatch/Counter.vhdl45
-rw-r--r--testsuite/pyunit/dom/examples/StopWatch/Debouncer.vhdl58
-rw-r--r--testsuite/pyunit/dom/examples/StopWatch/StopWatch.pkg.vhdl21
-rw-r--r--testsuite/pyunit/dom/examples/StopWatch/StopWatch.vhdl127
-rw-r--r--testsuite/pyunit/dom/examples/StopWatch/Utilities.pkg.vhdl99
-rw-r--r--testsuite/pyunit/dom/examples/StopWatch/seg7_Display.vhdl90
-rw-r--r--testsuite/pyunit/dom/examples/StopWatch/seg7_Encoder.vhdl46
-rw-r--r--testsuite/pyunit/dom/examples/StopWatch/toplevel.Display.vhdl65
-rw-r--r--testsuite/pyunit/dom/examples/StopWatch/toplevel.Encoder.vhdl42
-rw-r--r--testsuite/pyunit/dom/examples/StopWatch/toplevel.StopWatch.tb.vhdl58
-rw-r--r--testsuite/pyunit/dom/examples/StopWatch/toplevel.StopWatch.vhdl118
-rw-r--r--testsuite/pyunit/libghdl/Initialize.py10
36 files changed, 1331 insertions, 395 deletions
diff --git a/.github/workflows/Test.yml b/.github/workflows/Test.yml
index 70b0bb8b5..03e8935de 100644
--- a/.github/workflows/Test.yml
+++ b/.github/workflows/Test.yml
@@ -101,8 +101,7 @@ jobs:
run: |
sudo apt update -qq
sudo apt install -y gnat
- python -m pip install --upgrade pip
- python -m pip install black wheel pyTooling
+ python -m pip install --disable-pip-version-check black wheel pyTooling
- name: '🚧 Update Python bindings'
run: ./scripts/update_py_bindings.sh
@@ -583,9 +582,8 @@ jobs:
- name: '🐍 Install pyGHDL'
run: |
- python -m pip install --upgrade pip
- python -m pip install wheel (& ls *.whl)
- python -m pip install -r testsuite/requirements.txt
+ python -m pip install --disable-pip-version-check wheel (& ls *.whl)
+ python -m pip install --disable-pip-version-check -r testsuite/requirements.txt
- name: '🚦 Test pyGHDL entrypoints'
run: |
@@ -692,7 +690,7 @@ jobs:
- name: '🛠 Install package and 🐍 Python dependencies'
run: |
pacman --noconfirm -U artifact/mingw-w64-*-ghdl-llvm-*.zst
- pip3 install -r testsuite/requirements.txt
+ pip3 install --disable-pip-version-check -r testsuite/requirements.txt
- name: '🚦 Run tests to generate coverage report'
run: PYTHONPATH=$(pwd) python3 -m pytest -rA --cov=.. --cov-config=.coveragerc testsuite/pyunit
diff --git a/pyGHDL/dom/Attribute.py b/pyGHDL/dom/Attribute.py
index 86be400ac..ccd3ecf47 100644
--- a/pyGHDL/dom/Attribute.py
+++ b/pyGHDL/dom/Attribute.py
@@ -13,7 +13,7 @@
#
# License:
# ============================================================================
-# Copyright (C) 2019-2021 Tristan Gingold
+# Copyright (C) 2019-2022 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
@@ -46,7 +46,7 @@ from pyGHDL.libghdl._types import Iir
from pyGHDL.libghdl.vhdl import nodes
from pyGHDL.libghdl.vhdl.tokens import Tok
from pyGHDL.dom import DOMMixin, Position, DOMException, Expression
-from pyGHDL.dom._Utils import GetNameOfNode, GetIirKindOfNode
+from pyGHDL.dom._Utils import GetNameOfNode, GetIirKindOfNode, GetDocumentationOfNode
from pyGHDL.dom._Translate import GetNameFromNode, GetExpressionFromNode
from pyGHDL.dom.Names import SimpleName
from pyGHDL.dom.Symbol import SimpleSubtypeSymbol
@@ -54,18 +54,19 @@ from pyGHDL.dom.Symbol import SimpleSubtypeSymbol
@export
class Attribute(VHDLModel_Attribute, DOMMixin):
- def __init__(self, node: Iir, identifier: str, subtype: SubtypeOrSymbol):
- super().__init__(identifier, subtype)
+ def __init__(self, node: Iir, identifier: str, subtype: SubtypeOrSymbol, documentation: str = None):
+ super().__init__(identifier, subtype, documentation)
DOMMixin.__init__(self, node)
@classmethod
def parse(cls, attributeNode: Iir) -> "Attribute":
name = GetNameOfNode(attributeNode)
+ documentation = GetDocumentationOfNode(attributeNode)
subtypeMark = nodes.Get_Type_Mark(attributeNode)
subtypeName = GetNameOfNode(subtypeMark)
subtype = SimpleSubtypeSymbol(subtypeMark, subtypeName)
- return cls(attributeNode, name, subtype)
+ return cls(attributeNode, name, subtype, documentation)
_TOKEN_TRANSLATION = {
@@ -102,14 +103,16 @@ class AttributeSpecification(VHDLModel_AttributeSpecification, DOMMixin):
attribute: Name,
entityClass: EntityClass,
expression: Expression,
+ documentation: str = None,
):
- super().__init__(identifiers, attribute, entityClass, expression)
+ super().__init__(identifiers, attribute, entityClass, expression, documentation)
DOMMixin.__init__(self, node)
@classmethod
def parse(cls, attributeNode: Iir) -> "AttributeSpecification":
attributeDesignator = nodes.Get_Attribute_Designator(attributeNode)
attributeName = GetNameFromNode(attributeDesignator)
+ documentation = GetDocumentationOfNode(attributeNode)
names = []
entityNameList = nodes.Get_Entity_Name_List(attributeNode)
@@ -136,4 +139,4 @@ class AttributeSpecification(VHDLModel_AttributeSpecification, DOMMixin):
expression = GetExpressionFromNode(nodes.Get_Expression(attributeNode))
- return cls(attributeNode, names, attributeName, entityClass, expression)
+ return cls(attributeNode, names, attributeName, entityClass, expression, documentation)
diff --git a/pyGHDL/dom/DesignUnit.py b/pyGHDL/dom/DesignUnit.py
index f45cb8340..eebf888bc 100644
--- a/pyGHDL/dom/DesignUnit.py
+++ b/pyGHDL/dom/DesignUnit.py
@@ -13,7 +13,7 @@
#
# License:
# ============================================================================
-# Copyright (C) 2019-2021 Tristan Gingold
+# Copyright (C) 2019-2022 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
@@ -43,11 +43,15 @@ from typing import Iterable
from pyTooling.Decorators import export
-from pyVHDLModel import ContextUnion, EntityOrSymbol
-from pyVHDLModel.SyntaxModel import (
+from pyVHDLModel import (
+ ContextUnion as VHDLModel_ContextUnion,
+ EntityOrSymbol as VHDLModel_EntityOrSymbol,
LibraryClause as VHDLModel_LibraryClause,
UseClause as VHDLModel_UseClause,
ContextReference as VHDLModel_ContextReference,
+ Name,
+)
+from pyVHDLModel.SyntaxModel import (
Entity as VHDLModel_Entity,
Architecture as VHDLModel_Architecture,
Package as VHDLModel_Package,
@@ -58,15 +62,16 @@ from pyVHDLModel.SyntaxModel import (
Component as VHDLModel_Component,
GenericInterfaceItem,
PortInterfaceItem,
- Name,
ConcurrentStatement,
+ PackageReferenceSymbol,
+ ContextReferenceSymbol,
)
from pyGHDL.libghdl import utils
from pyGHDL.libghdl._types import Iir
from pyGHDL.libghdl.vhdl import nodes
from pyGHDL.dom import DOMMixin, Position, DOMException
-from pyGHDL.dom._Utils import GetNameOfNode
+from pyGHDL.dom._Utils import GetNameOfNode, GetDocumentationOfNode
from pyGHDL.dom._Translate import (
GetGenericsFromChainedNodes,
GetPortsFromChainedNodes,
@@ -82,41 +87,41 @@ __all__ = []
@export
class LibraryClause(VHDLModel_LibraryClause, DOMMixin):
- def __init__(self, libraryNode: Iir, names: Iterable[Name]):
- super().__init__(names)
+ def __init__(self, libraryNode: Iir, symbols: Iterable[Name]):
+ super().__init__(symbols)
DOMMixin.__init__(self, libraryNode)
@export
class UseClause(VHDLModel_UseClause, DOMMixin):
- def __init__(self, useNode: Iir, names: Iterable[Name]):
- super().__init__(names)
+ def __init__(self, useNode: Iir, symbols: Iterable[Name]):
+ super().__init__(symbols)
DOMMixin.__init__(self, useNode)
@classmethod
def parse(cls, useNode: Iir):
from pyGHDL.dom._Translate import GetNameFromNode
- uses = [GetNameFromNode(nodes.Get_Selected_Name(useNode))]
+ uses = [PackageReferenceSymbol(GetNameFromNode(nodes.Get_Selected_Name(useNode)))]
for use in utils.chain_iter(nodes.Get_Use_Clause_Chain(useNode)):
- uses.append(GetNameFromNode(nodes.Get_Selected_Name(use)))
+ uses.append(PackageReferenceSymbol(GetNameFromNode(nodes.Get_Selected_Name(use))))
return cls(useNode, uses)
@export
class ContextReference(VHDLModel_ContextReference, DOMMixin):
- def __init__(self, contextNode: Iir, names: Iterable[Name]):
- super().__init__(names)
+ def __init__(self, contextNode: Iir, symbols: Iterable[Name]):
+ super().__init__(symbols)
DOMMixin.__init__(self, contextNode)
@classmethod
def parse(cls, contextNode: Iir):
from pyGHDL.dom._Translate import GetNameFromNode
- contexts = [GetNameFromNode(nodes.Get_Selected_Name(contextNode))]
+ contexts = [ContextReferenceSymbol(GetNameFromNode(nodes.Get_Selected_Name(contextNode)))]
for context in utils.chain_iter(nodes.Get_Context_Reference_Chain(contextNode)):
- contexts.append(GetNameFromNode(nodes.Get_Selected_Name(context)))
+ contexts.append(ContextReferenceSymbol(GetNameFromNode(nodes.Get_Selected_Name(context))))
return cls(contextNode, contexts)
@@ -127,18 +132,20 @@ class Entity(VHDLModel_Entity, DOMMixin):
self,
node: Iir,
identifier: str,
- contextItems: Iterable[ContextUnion] = None,
+ contextItems: Iterable[VHDLModel_ContextUnion] = None,
genericItems: Iterable[GenericInterfaceItem] = None,
portItems: Iterable[PortInterfaceItem] = None,
declaredItems: Iterable = None,
statements: Iterable["ConcurrentStatement"] = None,
+ documentation: str = None,
):
- super().__init__(identifier, contextItems, genericItems, portItems, declaredItems, statements)
+ super().__init__(identifier, contextItems, genericItems, portItems, declaredItems, statements, documentation)
DOMMixin.__init__(self, node)
@classmethod
- def parse(cls, entityNode: Iir, contextItems: Iterable[ContextUnion]):
+ def parse(cls, entityNode: Iir, contextItems: Iterable[VHDLModel_ContextUnion]):
name = GetNameOfNode(entityNode)
+ documentation = GetDocumentationOfNode(entityNode)
generics = GetGenericsFromChainedNodes(nodes.Get_Generic_Chain(entityNode))
ports = GetPortsFromChainedNodes(nodes.Get_Port_Chain(entityNode))
declaredItems = GetDeclaredItemsFromChainedNodes(nodes.Get_Declaration_Chain(entityNode), "entity", name)
@@ -148,7 +155,7 @@ class Entity(VHDLModel_Entity, DOMMixin):
# FIXME: read use clauses
- return cls(entityNode, name, contextItems, generics, ports, declaredItems, statements)
+ return cls(entityNode, name, contextItems, generics, ports, declaredItems, statements, documentation)
@export
@@ -157,20 +164,22 @@ class Architecture(VHDLModel_Architecture, DOMMixin):
self,
node: Iir,
identifier: str,
- entity: EntityOrSymbol,
- contextItems: Iterable[ContextUnion] = None,
+ entity: VHDLModel_EntityOrSymbol,
+ contextItems: Iterable[VHDLModel_ContextUnion] = None,
declaredItems: Iterable = None,
statements: Iterable["ConcurrentStatement"] = None,
+ documentation: str = None,
):
- super().__init__(identifier, entity, contextItems, declaredItems, statements)
+ super().__init__(identifier, entity, contextItems, declaredItems, statements, documentation)
DOMMixin.__init__(self, node)
@classmethod
- def parse(cls, architectureNode: Iir, contextItems: Iterable[ContextUnion]):
+ def parse(cls, architectureNode: Iir, contextItems: Iterable[VHDLModel_ContextUnion]):
name = GetNameOfNode(architectureNode)
+ documentation = GetDocumentationOfNode(architectureNode)
entityNameNode = nodes.Get_Entity_Name(architectureNode)
entityName = GetNameOfNode(entityNameNode)
- entity = EntitySymbol(entityNameNode, SimpleName(entityNameNode, entityName))
+ entitySymbol = EntitySymbol(entityNameNode, SimpleName(entityNameNode, entityName))
declaredItems = GetDeclaredItemsFromChainedNodes(
nodes.Get_Declaration_Chain(architectureNode), "architecture", name
)
@@ -180,7 +189,7 @@ class Architecture(VHDLModel_Architecture, DOMMixin):
# FIXME: read use clauses
- return cls(architectureNode, name, entity, contextItems, declaredItems, statements)
+ return cls(architectureNode, name, entitySymbol, contextItems, declaredItems, statements, documentation)
@export
@@ -191,17 +200,19 @@ class Component(VHDLModel_Component, DOMMixin):
identifier: str,
genericItems: Iterable[GenericInterfaceItem] = None,
portItems: Iterable[PortInterfaceItem] = None,
+ documentation: str = None,
):
- super().__init__(identifier, genericItems, portItems)
+ super().__init__(identifier, genericItems, portItems, documentation)
DOMMixin.__init__(self, node)
@classmethod
def parse(cls, componentNode: Iir):
name = GetNameOfNode(componentNode)
+ documentation = GetDocumentationOfNode(componentNode)
generics = GetGenericsFromChainedNodes(nodes.Get_Generic_Chain(componentNode))
ports = GetPortsFromChainedNodes(nodes.Get_Port_Chain(componentNode))
- return cls(componentNode, name, generics, ports)
+ return cls(componentNode, name, generics, ports, documentation)
@export
@@ -210,16 +221,18 @@ class Package(VHDLModel_Package, DOMMixin):
self,
node: Iir,
identifier: str,
- contextItems: Iterable[ContextUnion] = None,
+ contextItems: Iterable[VHDLModel_ContextUnion] = None,
genericItems: Iterable[GenericInterfaceItem] = None,
declaredItems: Iterable = None,
+ documentation: str = None,
):
- super().__init__(identifier, contextItems, genericItems, declaredItems)
+ super().__init__(identifier, contextItems, genericItems, declaredItems, documentation)
DOMMixin.__init__(self, node)
@classmethod
- def parse(cls, packageNode: Iir, contextItems: Iterable[ContextUnion]):
+ def parse(cls, packageNode: Iir, contextItems: Iterable[VHDLModel_ContextUnion]):
name = GetNameOfNode(packageNode)
+ documentation = GetDocumentationOfNode(packageNode)
packageHeader = nodes.Get_Package_Header(packageNode)
if packageHeader is not nodes.Null_Iir:
@@ -231,7 +244,7 @@ class Package(VHDLModel_Package, DOMMixin):
# FIXME: read use clauses
- return cls(packageNode, name, contextItems, generics, declaredItems)
+ return cls(packageNode, name, contextItems, generics, declaredItems, documentation)
@export
@@ -240,20 +253,22 @@ class PackageBody(VHDLModel_PackageBody, DOMMixin):
self,
node: Iir,
identifier: str,
- contextItems: Iterable[ContextUnion] = None,
+ contextItems: Iterable[VHDLModel_ContextUnion] = None,
declaredItems: Iterable = None,
+ documentation: str = None,
):
- super().__init__(identifier, contextItems, declaredItems)
+ super().__init__(identifier, contextItems, declaredItems, documentation)
DOMMixin.__init__(self, node)
@classmethod
- def parse(cls, packageBodyNode: Iir, contextItems: Iterable[ContextUnion]):
+ def parse(cls, packageBodyNode: Iir, contextItems: Iterable[VHDLModel_ContextUnion]):
name = GetNameOfNode(packageBodyNode)
+ documentation = GetDocumentationOfNode(packageBodyNode)
declaredItems = GetDeclaredItemsFromChainedNodes(nodes.Get_Declaration_Chain(packageBodyNode), "package", name)
# FIXME: read use clauses
- return cls(packageBodyNode, name, contextItems, declaredItems)
+ return cls(packageBodyNode, name, contextItems, declaredItems, documentation)
@export
@@ -264,13 +279,15 @@ class PackageInstantiation(VHDLModel_PackageInstantiation, DOMMixin):
identifier: str,
uninstantiatedPackageName: Name,
# genericItems: List[GenericInterfaceItem] = None,
+ documentation: str = None,
):
- super().__init__(identifier, uninstantiatedPackageName)
+ super().__init__(identifier, uninstantiatedPackageName, documentation)
DOMMixin.__init__(self, node)
@classmethod
def parse(cls, packageNode: Iir):
name = GetNameOfNode(packageNode)
+ documentation = GetDocumentationOfNode(packageNode)
uninstantiatedPackageName = nodes.Get_Uninstantiated_Package_Name(packageNode)
# FIXME: read use clauses (does it apply here too?)
@@ -278,7 +295,7 @@ class PackageInstantiation(VHDLModel_PackageInstantiation, DOMMixin):
# FIXME: read generic map
# genericAssociations = GetGenericMapAspect(nodes.Get_Generic_Map_Aspect_Chain(instantiationNode))
- return cls(packageNode, name, uninstantiatedPackageName)
+ return cls(packageNode, name, uninstantiatedPackageName, documentation)
@export
@@ -289,8 +306,9 @@ class Context(VHDLModel_Context, DOMMixin):
identifier: str,
libraryReferences: Iterable[LibraryClause] = None,
packageReferences: Iterable[UseClause] = None,
+ documentation: str = None,
):
- super().__init__(identifier, libraryReferences, packageReferences)
+ super().__init__(identifier, libraryReferences, packageReferences, documentation)
DOMMixin.__init__(self, node)
@classmethod
@@ -298,6 +316,7 @@ class Context(VHDLModel_Context, DOMMixin):
from pyGHDL.dom._Utils import GetIirKindOfNode
name = GetNameOfNode(contextNode)
+ documentation = GetDocumentationOfNode(contextNode)
items = []
names = []
@@ -316,25 +335,21 @@ class Context(VHDLModel_Context, DOMMixin):
pos = Position.parse(item)
raise DOMException(f"Unknown context item kind '{kind.name}' in context at line {pos.Line}.")
- return cls(contextNode, name, items)
+ return cls(contextNode, name, items, documentation)
@export
class Configuration(VHDLModel_Configuration, DOMMixin):
- def __init__(
- self,
- node: Iir,
- identifier: str,
- contextItems: Iterable[Context] = None,
- ):
- super().__init__(identifier, contextItems)
+ def __init__(self, node: Iir, identifier: str, contextItems: Iterable[Context] = None, documentation: str = None):
+ super().__init__(identifier, contextItems, documentation)
DOMMixin.__init__(self, node)
@classmethod
def parse(cls, configurationNode: Iir, contextItems: Iterable[Context]):
name = GetNameOfNode(configurationNode)
+ documentation = GetDocumentationOfNode(configurationNode)
# FIXME: read use clauses
# FIXME: read specifications
- return cls(configurationNode, name, contextItems)
+ return cls(configurationNode, name, contextItems, documentation)
diff --git a/pyGHDL/dom/InterfaceItem.py b/pyGHDL/dom/InterfaceItem.py
index 66a8fe37b..aa63f3094 100644
--- a/pyGHDL/dom/InterfaceItem.py
+++ b/pyGHDL/dom/InterfaceItem.py
@@ -13,7 +13,7 @@
#
# License:
# ============================================================================
-# Copyright (C) 2019-2021 Tristan Gingold
+# Copyright (C) 2019-2022 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
@@ -30,7 +30,7 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
# ============================================================================
-from typing import List
+from typing import List, Iterable
from pyTooling.Decorators import export
@@ -53,7 +53,7 @@ from pyVHDLModel.SyntaxModel import (
from pyGHDL.libghdl._types import Iir
from pyGHDL.libghdl.vhdl import nodes
from pyGHDL.dom import DOMMixin
-from pyGHDL.dom._Utils import GetNameOfNode, GetModeOfNode
+from pyGHDL.dom._Utils import GetNameOfNode, GetModeOfNode, GetDocumentationOfNode
from pyGHDL.dom._Translate import GetSubtypeIndicationFromNode, GetExpressionFromNode
@@ -69,95 +69,80 @@ class GenericConstantInterfaceItem(VHDLModel_GenericConstantInterfaceItem, DOMMi
mode: Mode,
subtype: SubtypeOrSymbol,
defaultExpression: ExpressionUnion,
+ documentation: str = None,
):
- super().__init__(identifiers, mode, subtype, defaultExpression)
+ super().__init__(identifiers, mode, subtype, defaultExpression, documentation)
DOMMixin.__init__(self, node)
@classmethod
- def parse(cls, genericNode: Iir) -> "GenericConstantInterfaceItem":
+ def parse(cls, genericNode: Iir, furtherIdentifiers: Iterable[str] = None) -> "GenericConstantInterfaceItem":
name = GetNameOfNode(genericNode)
+ documentation = GetDocumentationOfNode(genericNode)
+ identifiers = [name]
+ if furtherIdentifiers is not None:
+ identifiers.extend(furtherIdentifiers)
mode = GetModeOfNode(genericNode)
subtypeIndication = GetSubtypeIndicationFromNode(genericNode, "generic", name)
default = nodes.Get_Default_Value(genericNode)
value = GetExpressionFromNode(default) if default else None
- return cls(
- genericNode,
- [
- name,
- ],
- mode,
- subtypeIndication,
- value,
- )
+ return cls(genericNode, identifiers, mode, subtypeIndication, value, documentation)
@export
class GenericTypeInterfaceItem(VHDLModel_GenericTypeInterfaceItem, DOMMixin):
- def __init__(
- self,
- node: Iir,
- identifier: str,
- ):
- super().__init__(identifier)
+ def __init__(self, node: Iir, identifier: str, documentation: str = None):
+ super().__init__(identifier, documentation)
DOMMixin.__init__(self, node)
@classmethod
def parse(cls, genericNode: Iir) -> "GenericTypeInterfaceItem":
name = GetNameOfNode(genericNode)
+ documentation = GetDocumentationOfNode(genericNode)
- return cls(genericNode, name)
+ return cls(genericNode, name, documentation)
@export
class GenericPackageInterfaceItem(VHDLModel_GenericPackageInterfaceItem, DOMMixin):
- def __init__(
- self,
- node: Iir,
- name: str,
- ):
- super().__init__(name)
+ def __init__(self, node: Iir, name: str, documentation: str = None):
+ super().__init__(name, documentation)
DOMMixin.__init__(self, node)
@classmethod
def parse(cls, genericNode: Iir) -> "GenericPackageInterfaceItem":
name = GetNameOfNode(genericNode)
+ documentation = GetDocumentationOfNode(genericNode)
- return cls(genericNode, name)
+ return cls(genericNode, name, documentation)
@export
class GenericProcedureInterfaceItem(VHDLModel_GenericProcedureInterfaceItem, DOMMixin):
- def __init__(
- self,
- node: Iir,
- identifier: str,
- ):
- super().__init__(identifier)
+ def __init__(self, node: Iir, identifier: str, documentation: str = None):
+ super().__init__(identifier, documentation)
DOMMixin.__init__(self, node)
@classmethod
def parse(cls, genericNode: Iir) -> "GenericProcedureInterfaceItem":
name = GetNameOfNode(genericNode)
+ documentation = GetDocumentationOfNode(genericNode)
- return cls(genericNode, name)
+ return cls(genericNode, name, documentation)
@export
class GenericFunctionInterfaceItem(VHDLModel_GenericFunctionInterfaceItem, DOMMixin):
- def __init__(
- self,
- node: Iir,
- identifier: str,
- ):
- super().__init__(identifier)
+ def __init__(self, node: Iir, identifier: str, documentation: str = None):
+ super().__init__(identifier, documentation)
DOMMixin.__init__(self, node)
@classmethod
def parse(cls, genericNode: Iir) -> "GenericFunctionInterfaceItem":
name = GetNameOfNode(genericNode)
+ documentation = GetDocumentationOfNode(genericNode)
- return cls(genericNode, name)
+ return cls(genericNode, name, documentation)
@export
@@ -169,28 +154,25 @@ class PortSignalInterfaceItem(VHDLModel_PortSignalInterfaceItem, DOMMixin):
mode: Mode,
subtype: SubtypeOrSymbol,
defaultExpression: ExpressionUnion = None,
+ documentation: str = None,
):
- super().__init__(identifiers, mode, subtype, defaultExpression)
+ super().__init__(identifiers, mode, subtype, defaultExpression, documentation)
DOMMixin.__init__(self, node)
@classmethod
- def parse(cls, portNode: Iir) -> "PortSignalInterfaceItem":
+ def parse(cls, portNode: Iir, furtherIdentifiers: Iterable[str] = None) -> "PortSignalInterfaceItem":
name = GetNameOfNode(portNode)
+ documentation = GetDocumentationOfNode(portNode)
+ identifiers = [name]
+ if furtherIdentifiers is not None:
+ identifiers.extend(furtherIdentifiers)
mode = GetModeOfNode(portNode)
subtypeIndication = GetSubtypeIndicationFromNode(portNode, "port", name)
defaultValue = nodes.Get_Default_Value(portNode)
value = GetExpressionFromNode(defaultValue) if defaultValue != nodes.Null_Iir else None
- return cls(
- portNode,
- [
- name,
- ],
- mode,
- subtypeIndication,
- value,
- )
+ return cls(portNode, identifiers, mode, subtypeIndication, value, documentation)
@export
@@ -202,28 +184,25 @@ class ParameterConstantInterfaceItem(VHDLModel_ParameterConstantInterfaceItem, D
mode: Mode,
subtype: SubtypeOrSymbol,
defaultExpression: ExpressionUnion = None,
+ documentation: str = None,
):
- super().__init__(identifiers, mode, subtype, defaultExpression)
+ super().__init__(identifiers, mode, subtype, defaultExpression, documentation)
DOMMixin.__init__(self, node)
@classmethod
- def parse(cls, parameterNode: Iir) -> "ParameterConstantInterfaceItem":
+ def parse(cls, parameterNode: Iir, furtherIdentifiers: Iterable[str] = None) -> "ParameterConstantInterfaceItem":
name = GetNameOfNode(parameterNode)
+ documentation = GetDocumentationOfNode(parameterNode)
+ identifiers = [name]
+ if furtherIdentifiers is not None:
+ identifiers.extend(furtherIdentifiers)
mode = GetModeOfNode(parameterNode)
subtypeIndication = GetSubtypeIndicationFromNode(parameterNode, "parameter", name)
defaultValue = nodes.Get_Default_Value(parameterNode)
value = GetExpressionFromNode(defaultValue) if defaultValue != nodes.Null_Iir else None
- return cls(
- parameterNode,
- [
- name,
- ],
- mode,
- subtypeIndication,
- value,
- )
+ return cls(parameterNode, identifiers, mode, subtypeIndication, value, documentation)
@export
@@ -235,28 +214,25 @@ class ParameterVariableInterfaceItem(VHDLModel_ParameterVariableInterfaceItem, D
mode: Mode,
subtype: SubtypeOrSymbol,
defaultExpression: ExpressionUnion = None,
+ documentation: str = None,
):
- super().__init__(identifiers, mode, subtype, defaultExpression)
+ super().__init__(identifiers, mode, subtype, defaultExpression, documentation)
DOMMixin.__init__(self, node)
@classmethod
- def parse(cls, parameterNode: Iir) -> "ParameterVariableInterfaceItem":
+ def parse(cls, parameterNode: Iir, furtherIdentifiers: Iterable[str] = None) -> "ParameterVariableInterfaceItem":
name = GetNameOfNode(parameterNode)
+ documentation = GetDocumentationOfNode(parameterNode)
+ identifiers = [name]
+ if furtherIdentifiers is not None:
+ identifiers.extend(furtherIdentifiers)
mode = GetModeOfNode(parameterNode)
subtypeIndication = GetSubtypeIndicationFromNode(parameterNode, "parameter", name)
defaultValue = nodes.Get_Default_Value(parameterNode)
value = GetExpressionFromNode(defaultValue) if defaultValue != nodes.Null_Iir else None
- return cls(
- parameterNode,
- [
- name,
- ],
- mode,
- subtypeIndication,
- value,
- )
+ return cls(parameterNode, identifiers, mode, subtypeIndication, value, documentation)
@export
@@ -268,50 +244,40 @@ class ParameterSignalInterfaceItem(VHDLModel_ParameterSignalInterfaceItem, DOMMi
mode: Mode,
subtype: SubtypeOrSymbol,
defaultExpression: ExpressionUnion = None,
+ documentation: str = None,
):
- super().__init__(identifiers, mode, subtype, defaultExpression)
+ super().__init__(identifiers, mode, subtype, defaultExpression, documentation)
DOMMixin.__init__(self, node)
@classmethod
- def parse(cls, parameterNode: Iir) -> "ParameterSignalInterfaceItem":
+ def parse(cls, parameterNode: Iir, furtherIdentifiers: Iterable[str] = None) -> "ParameterSignalInterfaceItem":
name = GetNameOfNode(parameterNode)
+ documentation = GetDocumentationOfNode(parameterNode)
+ identifiers = [name]
+ if furtherIdentifiers is not None:
+ identifiers.extend(furtherIdentifiers)
mode = GetModeOfNode(parameterNode)
subtypeIndication = GetSubtypeIndicationFromNode(parameterNode, "parameter", name)
defaultValue = nodes.Get_Default_Value(parameterNode)
value = GetExpressionFromNode(defaultValue) if defaultValue != nodes.Null_Iir else None
- return cls(
- parameterNode,
- [
- name,
- ],
- mode,
- subtypeIndication,
- value,
- )
+ return cls(parameterNode, identifiers, mode, subtypeIndication, value, documentation)
@export
class ParameterFileInterfaceItem(VHDLModel_ParameterFileInterfaceItem, DOMMixin):
- def __init__(
- self,
- node: Iir,
- identifiers: List[str],
- subtype: SubtypeOrSymbol,
- ):
- super().__init__(identifiers, subtype)
+ def __init__(self, node: Iir, identifiers: List[str], subtype: SubtypeOrSymbol, documentation: str = None):
+ super().__init__(identifiers, subtype, documentation)
DOMMixin.__init__(self, node)
@classmethod
- def parse(cls, parameterNode: Iir) -> "ParameterFileInterfaceItem":
+ def parse(cls, parameterNode: Iir, furtherIdentifiers: Iterable[str] = None) -> "ParameterFileInterfaceItem":
name = GetNameOfNode(parameterNode)
+ documentation = GetDocumentationOfNode(parameterNode)
+ identifiers = [name]
+ if furtherIdentifiers is not None:
+ identifiers.extend(furtherIdentifiers)
subtypeIndication = GetSubtypeIndicationFromNode(parameterNode, "parameter", name)
- return cls(
- parameterNode,
- [
- name,
- ],
- subtypeIndication,
- )
+ return cls(parameterNode, identifiers, subtypeIndication, documentation)
diff --git a/pyGHDL/dom/Misc.py b/pyGHDL/dom/Misc.py
index d6fc08524..8f85db222 100644
--- a/pyGHDL/dom/Misc.py
+++ b/pyGHDL/dom/Misc.py
@@ -13,7 +13,7 @@
#
# License:
# ============================================================================
-# Copyright (C) 2019-2021 Tristan Gingold
+# Copyright (C) 2019-2022 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
@@ -42,22 +42,22 @@ from pyVHDLModel.SyntaxModel import (
)
from pyGHDL.libghdl._types import Iir
from pyGHDL.dom import DOMMixin
-from pyGHDL.dom._Utils import GetNameOfNode
-
+from pyGHDL.dom._Utils import GetNameOfNode, GetDocumentationOfNode
__all__ = []
@export
class Alias(VHDLModel_Alias, DOMMixin):
- def __init__(self, node: Iir, aliasName: str):
- super().__init__(aliasName)
+ def __init__(self, node: Iir, aliasName: str, documentation: str = None):
+ super().__init__(aliasName, documentation)
DOMMixin.__init__(self, node)
@classmethod
- def parse(cls, node: Iir):
- aliasName = GetNameOfNode(node)
+ def parse(cls, aliasNode: Iir):
+ aliasName = GetNameOfNode(aliasNode)
+ documentation = GetDocumentationOfNode(aliasNode)
# FIXME: add an implementation
- return cls(node, aliasName)
+ return cls(aliasNode, aliasName)
diff --git a/pyGHDL/dom/NonStandard.py b/pyGHDL/dom/NonStandard.py
index c55786d54..14f5e1eac 100644
--- a/pyGHDL/dom/NonStandard.py
+++ b/pyGHDL/dom/NonStandard.py
@@ -13,7 +13,7 @@
#
# License:
# ============================================================================
-# Copyright (C) 2019-2021 Tristan Gingold
+# Copyright (C) 2019-2022 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
@@ -42,11 +42,11 @@ from typing import Any
from pyTooling.Decorators import export
-from pyGHDL.dom.Names import SimpleName
from pyVHDLModel.SyntaxModel import (
Design as VHDLModel_Design,
Library as VHDLModel_Library,
Document as VHDLModel_Document,
+ LibraryReferenceSymbol,
)
from pyGHDL.libghdl import (
@@ -61,9 +61,12 @@ from pyGHDL.libghdl import (
utils,
files_map_editor,
)
-from pyGHDL.libghdl.vhdl import nodes, sem_lib, parse
+from pyGHDL.libghdl.flags import Flag_Gather_Comments
+from pyGHDL.libghdl.vhdl import nodes, sem_lib
+from pyGHDL.libghdl.vhdl.parse import Flag_Parse_Parenthesis
from pyGHDL.dom import DOMException, Position
-from pyGHDL.dom._Utils import GetIirKindOfNode, CheckForErrors, GetNameOfNode
+from pyGHDL.dom._Utils import GetIirKindOfNode, CheckForErrors, GetNameOfNode, GetDocumentationOfNode
+from pyGHDL.dom.Names import SimpleName
from pyGHDL.dom.DesignUnit import (
Entity,
Architecture,
@@ -100,7 +103,8 @@ class Design(VHDLModel_Design):
libghdl_set_option("--std=08")
libghdl_set_option("--ams")
- parse.Flag_Parse_Parenthesis.value = True
+ Flag_Gather_Comments.value = True
+ Flag_Parse_Parenthesis.value = True
# Finish initialization. This will load the standard package.
if libghdl_analyze_init_status() != 0:
@@ -167,6 +171,7 @@ class Document(VHDLModel_Document):
def translate(self):
firstUnit = nodes.Get_First_Design_Unit(self.__ghdlFile)
+ self._documentation = GetDocumentationOfNode(firstUnit)
for unit in utils.chain_iter(firstUnit):
libraryUnit = nodes.Get_Library_Unit(unit)
@@ -179,7 +184,7 @@ class Document(VHDLModel_Document):
for item in utils.chain_iter(context):
itemKind = GetIirKindOfNode(item)
if itemKind is nodes.Iir_Kind.Library_Clause:
- contextNames.append(SimpleName(item, GetNameOfNode(item)))
+ contextNames.append(LibraryReferenceSymbol(SimpleName(item, GetNameOfNode(item))))
if nodes.Get_Has_Identifier_List(item):
continue
@@ -197,43 +202,43 @@ class Document(VHDLModel_Document):
if nodeKind == nodes.Iir_Kind.Entity_Declaration:
entity = Entity.parse(libraryUnit, contextItems)
- self.Entities.append(entity)
+ self._AddEntity(entity)
elif nodeKind == nodes.Iir_Kind.Architecture_Body:
architecture = Architecture.parse(libraryUnit, contextItems)
- self.Architectures.append(architecture)
+ self._AddArchitecture(architecture)
elif nodeKind == nodes.Iir_Kind.Package_Declaration:
package = Package.parse(libraryUnit, contextItems)
- self.Packages.append(package)
+ self._AddPackage(package)
elif nodeKind == nodes.Iir_Kind.Package_Body:
packageBody = PackageBody.parse(libraryUnit, contextItems)
- self.PackageBodies.append(packageBody)
+ self._AddPackageBody(packageBody)
elif nodeKind == nodes.Iir_Kind.Package_Instantiation_Declaration:
package = PackageInstantiation.parse(libraryUnit)
- self.Packages.append(package)
+ self._AddPackage(package)
elif nodeKind == nodes.Iir_Kind.Context_Declaration:
context = Context.parse(libraryUnit)
- self.Contexts.append(context)
+ self._AddContext(context)
elif nodeKind == nodes.Iir_Kind.Configuration_Declaration:
configuration = Configuration.parse(libraryUnit, contextItems)
- self.Configurations.append(configuration)
+ self._AddConfiguration(configuration)
elif nodeKind == nodes.Iir_Kind.Vunit_Declaration:
vunit = VerificationUnit.parse(libraryUnit)
- self.VerificationUnits.append(vunit)
+ self._AddVerificationUnit(vunit)
elif nodeKind == nodes.Iir_Kind.Vprop_Declaration:
vprop = VerificationProperty.parse(libraryUnit)
- self.VerificationProperties.append(vprop)
+ self._AddVerificationProperty(vprop)
elif nodeKind == nodes.Iir_Kind.Vmode_Declaration:
vmod = VerificationMode.parse(libraryUnit)
- self.VerificationModes.append(vmod)
+ self._AddVerificationMode(vmod)
else:
raise DOMException(f"Unknown design unit kind '{nodeKind.name}'.")
diff --git a/pyGHDL/dom/Object.py b/pyGHDL/dom/Object.py
index 6d3472a6f..1079eae4a 100644
--- a/pyGHDL/dom/Object.py
+++ b/pyGHDL/dom/Object.py
@@ -13,7 +13,7 @@
#
# License:
# ============================================================================
-# Copyright (C) 2019-2021 Tristan Gingold
+# Copyright (C) 2019-2022 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
@@ -30,7 +30,7 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
# ============================================================================
-from typing import Union, List
+from typing import Union, List, Iterable
from pyTooling.Decorators import export
@@ -48,7 +48,7 @@ from pyVHDLModel.SyntaxModel import (
from pyGHDL.libghdl._types import Iir
from pyGHDL.libghdl.vhdl import nodes
from pyGHDL.dom import DOMMixin
-from pyGHDL.dom._Utils import GetNameOfNode
+from pyGHDL.dom._Utils import GetNameOfNode, GetDocumentationOfNode
__all__ = []
@@ -61,61 +61,53 @@ class Constant(VHDLModel_Constant, DOMMixin):
identifiers: List[str],
subtype: SubtypeOrSymbol,
defaultExpression: ExpressionUnion,
+ documentation: str = None,
):
- super().__init__(identifiers, subtype, defaultExpression)
+ super().__init__(identifiers, subtype, defaultExpression, documentation)
DOMMixin.__init__(self, node)
@classmethod
- def parse(cls, constantNode: Iir) -> Union["Constant", "DeferredConstant"]:
+ def parse(
+ cls, constantNode: Iir, furtherIdentifiers: Iterable[str] = None
+ ) -> Union["Constant", "DeferredConstant"]:
from pyGHDL.dom._Translate import (
GetSubtypeIndicationFromNode,
GetExpressionFromNode,
)
name = GetNameOfNode(constantNode)
+ documentation = GetDocumentationOfNode(constantNode)
+ identifiers = [name]
+ if furtherIdentifiers is not None:
+ identifiers.extend(furtherIdentifiers)
subtypeIndication = GetSubtypeIndicationFromNode(constantNode, "constant", name)
defaultValue = nodes.Get_Default_Value(constantNode)
if defaultValue != nodes.Null_Iir:
defaultExpression = GetExpressionFromNode(defaultValue)
- return cls(
- constantNode,
- [
- name,
- ],
- subtypeIndication,
- defaultExpression,
- )
+ return cls(constantNode, identifiers, subtypeIndication, defaultExpression, documentation)
else:
- return DeferredConstant(
- constantNode,
- [
- name,
- ],
- subtypeIndication,
- )
+ return DeferredConstant(constantNode, identifiers, subtypeIndication, documentation)
@export
class DeferredConstant(VHDLModel_DeferredConstant, DOMMixin):
- def __init__(self, node: Iir, identifiers: List[str], subtype: SubtypeOrSymbol):
- super().__init__(identifiers, subtype)
+ def __init__(self, node: Iir, identifiers: List[str], subtype: SubtypeOrSymbol, documentation: str = None):
+ super().__init__(identifiers, subtype, documentation)
DOMMixin.__init__(self, node)
@classmethod
- def parse(cls, constantNode: Iir) -> "DeferredConstant":
+ def parse(cls, constantNode: Iir, furtherIdentifiers: Iterable[str] = None) -> "DeferredConstant":
from pyGHDL.dom._Translate import GetSubtypeIndicationFromNode
name = GetNameOfNode(constantNode)
+ documentation = GetDocumentationOfNode(constantNode)
+ identifiers = [name]
+ if furtherIdentifiers is not None:
+ identifiers.extend(furtherIdentifiers)
subtypeIndication = GetSubtypeIndicationFromNode(constantNode, "deferred constant", name)
- return cls(
- constantNode,
- [
- name,
- ],
- subtypeIndication,
- )
+ return cls(constantNode, identifiers, subtypeIndication, documentation)
@export
@@ -126,54 +118,50 @@ class Variable(VHDLModel_Variable, DOMMixin):
identifiers: List[str],
subtype: SubtypeOrSymbol,
defaultExpression: ExpressionUnion,
+ documentation: str = None,
):
- super().__init__(identifiers, subtype, defaultExpression)
+ super().__init__(identifiers, subtype, defaultExpression, documentation)
DOMMixin.__init__(self, node)
@classmethod
- def parse(cls, variableNode: Iir) -> "Variable":
+ def parse(cls, variableNode: Iir, furtherIdentifiers: Iterable[str] = None) -> "Variable":
from pyGHDL.dom._Translate import (
GetSubtypeIndicationFromNode,
GetExpressionFromNode,
)
name = GetNameOfNode(variableNode)
+ documentation = GetDocumentationOfNode(variableNode)
+ identifiers = [name]
+ if furtherIdentifiers is not None:
+ identifiers.extend(furtherIdentifiers)
subtypeIndication = GetSubtypeIndicationFromNode(variableNode, "variable", name)
defaultValue = nodes.Get_Default_Value(variableNode)
defaultExpression = None
if defaultValue != nodes.Null_Iir:
defaultExpression = GetExpressionFromNode(defaultValue)
- return cls(
- variableNode,
- [
- name,
- ],
- subtypeIndication,
- defaultExpression,
- )
+ return cls(variableNode, identifiers, subtypeIndication, defaultExpression, documentation)
@export
class SharedVariable(VHDLModel_SharedVariable, DOMMixin):
- def __init__(self, node: Iir, identifiers: List[str], subtype: SubtypeOrSymbol):
- super().__init__(identifiers, subtype)
+ def __init__(self, node: Iir, identifiers: List[str], subtype: SubtypeOrSymbol, documentation: str = None):
+ super().__init__(identifiers, subtype, documentation)
DOMMixin.__init__(self, node)
@classmethod
- def parse(cls, variableNode: Iir) -> "SharedVariable":
+ def parse(cls, variableNode: Iir, furtherIdentifiers: Iterable[str] = None) -> "SharedVariable":
from pyGHDL.dom._Translate import GetSubtypeIndicationFromNode
name = GetNameOfNode(variableNode)
+ documentation = GetDocumentationOfNode(variableNode)
+ identifiers = [name]
+ if furtherIdentifiers is not None:
+ identifiers.extend(furtherIdentifiers)
subtypeIndication = GetSubtypeIndicationFromNode(variableNode, "variable", name)
- return cls(
- variableNode,
- [
- name,
- ],
- subtypeIndication,
- )
+ return cls(variableNode, identifiers, subtypeIndication, documentation)
@export
@@ -184,51 +172,47 @@ class Signal(VHDLModel_Signal, DOMMixin):
identifiers: List[str],
subtype: SubtypeOrSymbol,
defaultExpression: ExpressionUnion,
+ documentation: str = None,
):
- super().__init__(identifiers, subtype, defaultExpression)
+ super().__init__(identifiers, subtype, defaultExpression, documentation)
DOMMixin.__init__(self, node)
@classmethod
- def parse(cls, signalNode: Iir) -> "Signal":
+ def parse(cls, signalNode: Iir, furtherIdentifiers: Iterable[str] = None) -> "Signal":
from pyGHDL.dom._Translate import (
GetSubtypeIndicationFromNode,
GetExpressionFromNode,
)
name = GetNameOfNode(signalNode)
+ documentation = GetDocumentationOfNode(signalNode)
+ identifiers = [name]
+ if furtherIdentifiers is not None:
+ identifiers.extend(furtherIdentifiers)
subtypeIndication = GetSubtypeIndicationFromNode(signalNode, "signal", name)
default = nodes.Get_Default_Value(signalNode)
defaultExpression = GetExpressionFromNode(default) if default else None
- return cls(
- signalNode,
- [
- name,
- ],
- subtypeIndication,
- defaultExpression,
- )
+ return cls(signalNode, identifiers, subtypeIndication, defaultExpression, documentation)
@export
class File(VHDLModel_File, DOMMixin):
- def __init__(self, node: Iir, identifiers: List[str], subtype: SubtypeOrSymbol):
- super().__init__(identifiers, subtype)
+ def __init__(self, node: Iir, identifiers: List[str], subtype: SubtypeOrSymbol, documentation: str = None):
+ super().__init__(identifiers, subtype, documentation)
DOMMixin.__init__(self, node)
@classmethod
- def parse(cls, fileNode: Iir) -> "File":
+ def parse(cls, fileNode: Iir, furtherIdentifiers: Iterable[str] = None) -> "File":
from pyGHDL.dom._Translate import GetSubtypeIndicationFromNode
name = GetNameOfNode(fileNode)
+ documentation = GetDocumentationOfNode(fileNode)
+ identifiers = [name]
+ if furtherIdentifiers is not None:
+ identifiers.extend(furtherIdentifiers)
subtypeIndication = GetSubtypeIndicationFromNode(fileNode, "file", name)
# FIXME: handle file open stuff
- return cls(
- fileNode,
- [
- name,
- ],
- subtypeIndication,
- )
+ return cls(fileNode, identifiers, subtypeIndication, documentation)
diff --git a/pyGHDL/dom/Subprogram.py b/pyGHDL/dom/Subprogram.py
index 2e9c0116f..46ce92707 100644
--- a/pyGHDL/dom/Subprogram.py
+++ b/pyGHDL/dom/Subprogram.py
@@ -13,7 +13,7 @@
#
# License:
# ============================================================================
-# Copyright (C) 2019-2021 Tristan Gingold
+# Copyright (C) 2019-2022 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
@@ -44,7 +44,7 @@ from pyVHDLModel.SyntaxModel import (
from pyGHDL.libghdl._types import Iir
from pyGHDL.libghdl.vhdl import nodes
from pyGHDL.dom import DOMMixin
-from pyGHDL.dom._Utils import GetNameOfNode
+from pyGHDL.dom._Utils import GetNameOfNode, GetDocumentationOfNode
from pyGHDL.dom.Symbol import SimpleSubtypeSymbol
@@ -57,8 +57,9 @@ class Function(VHDLModel_Function, DOMMixin):
returnType: SubtypeOrSymbol,
genericItems: List[GenericInterfaceItem] = None,
parameterItems: List[ParameterInterfaceItem] = None,
+ documentation: str = None,
):
- super().__init__(functionName)
+ super().__init__(functionName, documentation)
DOMMixin.__init__(self, node)
# TODO: move to model
@@ -74,6 +75,7 @@ class Function(VHDLModel_Function, DOMMixin):
)
functionName = GetNameOfNode(functionNode)
+ documentation = GetDocumentationOfNode(functionNode)
generics = GetGenericsFromChainedNodes(nodes.Get_Generic_Chain(functionNode))
parameters = GetParameterFromChainedNodes(nodes.Get_Interface_Declaration_Chain(functionNode))
@@ -82,7 +84,7 @@ class Function(VHDLModel_Function, DOMMixin):
returnTypeName = GetNameOfNode(returnType)
returnTypeSymbol = SimpleSubtypeSymbol(returnType, returnTypeName)
- return cls(functionNode, functionName, returnTypeSymbol, generics, parameters)
+ return cls(functionNode, functionName, returnTypeSymbol, generics, parameters, documentation)
@export
@@ -93,8 +95,9 @@ class Procedure(VHDLModel_Procedure, DOMMixin):
procedureName: str,
genericItems: List[GenericInterfaceItem] = None,
parameterItems: List[ParameterInterfaceItem] = None,
+ documentation: str = None,
):
- super().__init__(procedureName)
+ super().__init__(procedureName, documentation)
DOMMixin.__init__(self, node)
# TODO: move to model
@@ -109,8 +112,9 @@ class Procedure(VHDLModel_Procedure, DOMMixin):
)
procedureName = GetNameOfNode(procedureNode)
+ documentation = GetDocumentationOfNode(procedureNode)
generics = GetGenericsFromChainedNodes(nodes.Get_Generic_Chain(procedureNode))
parameters = GetParameterFromChainedNodes(nodes.Get_Interface_Declaration_Chain(procedureNode))
- return cls(procedureNode, procedureName, generics, parameters)
+ return cls(procedureNode, procedureName, generics, parameters, documentation)
diff --git a/pyGHDL/dom/Symbol.py b/pyGHDL/dom/Symbol.py
index c5ed39ba3..0dd0fefa9 100644
--- a/pyGHDL/dom/Symbol.py
+++ b/pyGHDL/dom/Symbol.py
@@ -32,10 +32,13 @@
# ============================================================================
from typing import List, Iterator
-from pyTooling.Decorators import export
+from pyTooling.Decorators import export, InheritDocString
+from pyGHDL.dom.Names import SimpleName
from pyVHDLModel.SyntaxModel import (
EntitySymbol as VHDLModel_EntitySymbol,
+ ArchitectureSymbol as VHDLModel_ArchitectureSymbol,
+ PackageSymbol as VHDLModel_PackageSymbol,
SimpleSubtypeSymbol as VHDLModel_SimpleSubtypeSymbol,
ConstrainedScalarSubtypeSymbol as VHDLModel_ConstrainedScalarSubtypeSymbol,
ConstrainedCompositeSubtypeSymbol as VHDLModel_ConstrainedCompositeSubtypeSymbol,
@@ -54,12 +57,29 @@ __all__ = []
@export
class EntitySymbol(VHDLModel_EntitySymbol, DOMMixin):
- def __init__(self, node: Iir, entityName: Name):
+ @InheritDocString(VHDLModel_EntitySymbol)
+ def __init__(self, node: Iir, entityName: SimpleName):
super().__init__(entityName)
DOMMixin.__init__(self, node)
@export
+class ArchitectureSymbol(VHDLModel_ArchitectureSymbol, DOMMixin):
+ @InheritDocString(VHDLModel_ArchitectureSymbol)
+ def __init__(self, node: Iir, architectureName: SimpleName):
+ super().__init__(architectureName)
+ DOMMixin.__init__(self, node)
+
+
+@export
+class PackageSymbol(VHDLModel_PackageSymbol, DOMMixin):
+ @InheritDocString(VHDLModel_PackageSymbol)
+ def __init__(self, node: Iir, packageName: SimpleName):
+ super().__init__(packageName)
+ DOMMixin.__init__(self, node)
+
+
+@export
class SimpleSubtypeSymbol(VHDLModel_SimpleSubtypeSymbol, DOMMixin):
def __init__(self, node: Iir, subtypeName: Name):
if isinstance(subtypeName, (List, Iterator)):
diff --git a/pyGHDL/dom/Type.py b/pyGHDL/dom/Type.py
index b0f2d1311..2b71ccc3c 100644
--- a/pyGHDL/dom/Type.py
+++ b/pyGHDL/dom/Type.py
@@ -13,7 +13,7 @@
#
# License:
# ============================================================================
-# Copyright (C) 2019-2021 Tristan Gingold
+# Copyright (C) 2019-2022 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
@@ -30,7 +30,7 @@
#
# SPDX-License-Identifier: GPL-2.0-or-later
# ============================================================================
-from typing import List, Union, Iterator, Tuple
+from typing import List, Union, Iterator, Tuple, Iterable
from pyTooling.Decorators import export
@@ -185,20 +185,18 @@ class RecordTypeElement(VHDLModel_RecordTypeElement, DOMMixin):
DOMMixin.__init__(self, node)
@classmethod
- def parse(cls, elementDeclarationNode: Iir) -> "RecordTypeElement":
+ def parse(cls, elementDeclarationNode: Iir, furtherIdentifiers: Iterable[str] = None) -> "RecordTypeElement":
from pyGHDL.dom._Utils import GetNameOfNode
from pyGHDL.dom._Translate import GetSubtypeIndicationFromNode
elementName = GetNameOfNode(elementDeclarationNode)
elementType = GetSubtypeIndicationFromNode(elementDeclarationNode, "record element", elementName)
- return cls(
- elementDeclarationNode,
- [
- elementName,
- ],
- elementType,
- )
+ identifiers = [elementName]
+ if furtherIdentifiers is not None:
+ identifiers.extend(furtherIdentifiers)
+
+ return cls(elementDeclarationNode, identifiers, elementType)
@export
@@ -214,13 +212,12 @@ class RecordType(VHDLModel_RecordType, DOMMixin):
elements = []
elementDeclarations = nodes.Get_Elements_Declaration_List(typeDefinitionNode)
+ furtherIdentifiers = []
elementCount = flists.Flast(elementDeclarations) + 1
index = 0
while index < elementCount:
elementDeclaration = flists.Get_Nth_Element(elementDeclarations, index)
- element = RecordTypeElement.parse(elementDeclaration)
-
# Lookahead for elements with multiple identifiers at once
if nodes.Get_Has_Identifier_List(elementDeclaration):
index += 1
@@ -228,7 +225,7 @@ class RecordType(VHDLModel_RecordType, DOMMixin):
nextNode: Iir = flists.Get_Nth_Element(elementDeclarations, index)
# Consecutive identifiers are found, if the subtype indication is Null
if nodes.Get_Subtype_Indication(nextNode) == nodes.Null_Iir:
- element.Identifiers.append(GetNameOfNode(nextNode))
+ furtherIdentifiers.append(GetNameOfNode(nextNode))
else:
break
index += 1
@@ -239,7 +236,9 @@ class RecordType(VHDLModel_RecordType, DOMMixin):
else:
index += 1
+ element = RecordTypeElement.parse(elementDeclaration, furtherIdentifiers)
elements.append(element)
+ furtherIdentifiers.clear()
return cls(typeDefinitionNode, typeName, elements)
diff --git a/pyGHDL/dom/_Translate.py b/pyGHDL/dom/_Translate.py
index a125abfe5..b3a48769b 100644
--- a/pyGHDL/dom/_Translate.py
+++ b/pyGHDL/dom/_Translate.py
@@ -464,13 +464,14 @@ def GetGenericsFromChainedNodes(
GenericFunctionInterfaceItem,
)
+ furtherIdentifiers = []
generic = nodeChain
while generic != nodes.Null_Iir:
kind = GetIirKindOfNode(generic)
if kind == nodes.Iir_Kind.Interface_Constant_Declaration:
from pyGHDL.dom.InterfaceItem import GenericConstantInterfaceItem
- genericConstant = GenericConstantInterfaceItem.parse(generic)
+ parseNode = generic
# Lookahead for generics with multiple identifiers at once
if nodes.Get_Has_Identifier_List(generic):
@@ -478,7 +479,7 @@ def GetGenericsFromChainedNodes(
for nextGeneric in utils.chain_iter(nextNode):
# Consecutive identifiers are found, if the subtype indication is Null
if nodes.Get_Subtype_Indication(nextGeneric) == nodes.Null_Iir:
- genericConstant.Identifiers.append(GetNameOfNode(nextGeneric))
+ furtherIdentifiers.append(GetNameOfNode(nextGeneric))
else:
generic = nextGeneric
break
@@ -492,7 +493,8 @@ def GetGenericsFromChainedNodes(
else:
generic = nodes.Get_Chain(generic)
- yield genericConstant
+ yield GenericConstantInterfaceItem.parse(parseNode, furtherIdentifiers)
+ furtherIdentifiers.clear()
continue
else:
if kind == nodes.Iir_Kind.Interface_Type_Declaration:
@@ -517,13 +519,14 @@ def GetPortsFromChainedNodes(
nodeChain: Iir,
) -> Generator[PortInterfaceItem, None, None]:
+ furtherIdentifiers = []
port = nodeChain
while port != nodes.Null_Iir:
kind = GetIirKindOfNode(port)
if kind == nodes.Iir_Kind.Interface_Signal_Declaration:
from pyGHDL.dom.InterfaceItem import PortSignalInterfaceItem
- portSignal = PortSignalInterfaceItem.parse(port)
+ portToParse = port
# Lookahead for ports with multiple identifiers at once
if nodes.Get_Has_Identifier_List(port):
@@ -531,7 +534,7 @@ def GetPortsFromChainedNodes(
for nextPort in utils.chain_iter(nextNode):
# Consecutive identifiers are found, if the subtype indication is Null
if nodes.Get_Subtype_Indication(nextPort) == nodes.Null_Iir:
- portSignal.Identifiers.append(GetNameOfNode(nextPort))
+ furtherIdentifiers.append(GetNameOfNode(nextPort))
else:
port = nextPort
break
@@ -545,7 +548,8 @@ def GetPortsFromChainedNodes(
else:
port = nodes.Get_Chain(port)
- yield portSignal
+ yield PortSignalInterfaceItem.parse(portToParse, furtherIdentifiers)
+ furtherIdentifiers.clear()
continue
else:
position = Position.parse(port)
@@ -559,25 +563,30 @@ def GetParameterFromChainedNodes(
nodeChain: Iir,
) -> Generator[ParameterInterfaceItem, None, None]:
+ identifiers = []
parameter = nodeChain
while parameter != nodes.Null_Iir:
kind = GetIirKindOfNode(parameter)
if kind == nodes.Iir_Kind.Interface_Constant_Declaration:
from pyGHDL.dom.InterfaceItem import ParameterConstantInterfaceItem
- param = ParameterConstantInterfaceItem.parse(parameter)
+ parseMethod = ParameterConstantInterfaceItem.parse
+ parseNode = parameter
elif kind == nodes.Iir_Kind.Interface_Variable_Declaration:
from pyGHDL.dom.InterfaceItem import ParameterVariableInterfaceItem
- param = ParameterVariableInterfaceItem.parse(parameter)
+ parseMethod = ParameterVariableInterfaceItem.parse
+ parseNode = parameter
elif kind == nodes.Iir_Kind.Interface_Signal_Declaration:
from pyGHDL.dom.InterfaceItem import ParameterSignalInterfaceItem
- param = ParameterSignalInterfaceItem.parse(parameter)
+ parseMethod = ParameterSignalInterfaceItem.parse
+ parseNode = parameter
elif kind == nodes.Iir_Kind.Interface_File_Declaration:
from pyGHDL.dom.InterfaceItem import ParameterFileInterfaceItem
- param = ParameterFileInterfaceItem.parse(parameter)
+ parseMethod = ParameterFileInterfaceItem.parse
+ parseNode = parameter
else:
position = Position.parse(parameter)
raise DOMException(
@@ -590,7 +599,7 @@ def GetParameterFromChainedNodes(
for nextParameter in utils.chain_iter(nextNode):
# Consecutive identifiers are found, if the subtype indication is Null
if nodes.Get_Subtype_Indication(nextParameter) == nodes.Null_Iir:
- param.Identifiers.append(GetNameOfNode(nextParameter))
+ identifiers.append(GetNameOfNode(nextParameter))
else:
parameter = nextParameter
break
@@ -604,7 +613,7 @@ def GetParameterFromChainedNodes(
else:
parameter = nodes.Get_Chain(parameter)
- yield param
+ yield parseMethod(parseNode, identifiers)
def GetMapAspect(mapAspect: Iir, cls: Type, entity: str) -> Generator[AssociationItem, None, None]:
@@ -650,6 +659,7 @@ def GetParameterMapAspect(
def GetDeclaredItemsFromChainedNodes(nodeChain: Iir, entity: str, name: str) -> Generator[ModelEntity, None, None]:
+ furtherIdentifiers = []
item = nodeChain
lastKind = None
while item != nodes.Null_Iir:
@@ -657,23 +667,27 @@ def GetDeclaredItemsFromChainedNodes(nodeChain: Iir, entity: str, name: str) ->
if kind == nodes.Iir_Kind.Constant_Declaration:
from pyGHDL.dom.Object import Constant
- obj = Constant.parse(item)
-
+ objectParseMethod = Constant.parse
+ objectItem = item
elif kind == nodes.Iir_Kind.Variable_Declaration:
from pyGHDL.dom.Object import SharedVariable
if nodes.Get_Shared_Flag(item):
- obj = SharedVariable.parse(item)
+ objectParseMethod = SharedVariable.parse
+ objectItem = item
else:
- obj = Variable.parse(item)
+ objectParseMethod = Variable.parse
+ objectItem = item
elif kind == nodes.Iir_Kind.Signal_Declaration:
from pyGHDL.dom.Object import Signal
- obj = Signal.parse(item)
+ objectParseMethod = Signal.parse
+ objectItem = item
elif kind == nodes.Iir_Kind.File_Declaration:
from pyGHDL.dom.Object import File
- obj = File.parse(item)
+ objectParseMethod = File.parse
+ objectItem = item
else:
if kind == nodes.Iir_Kind.Type_Declaration:
yield GetTypeFromNode(item)
@@ -782,7 +796,7 @@ def GetDeclaredItemsFromChainedNodes(nodeChain: Iir, entity: str, name: str) ->
for nextItem in utils.chain_iter(nextNode):
# Consecutive identifiers are found, if the subtype indication is Null
if nodes.Get_Subtype_Indication(nextItem) == nodes.Null_Iir:
- obj.Identifiers.append(GetNameOfNode(nextItem))
+ furtherIdentifiers.append(GetNameOfNode(nextItem))
else:
item = nextItem
break
@@ -796,7 +810,8 @@ def GetDeclaredItemsFromChainedNodes(nodeChain: Iir, entity: str, name: str) ->
else:
item = nodes.Get_Chain(item)
- yield obj
+ yield objectParseMethod(objectItem, furtherIdentifiers)
+ furtherIdentifiers.clear()
def GetConcurrentStatementsFromChainedNodes(
diff --git a/pyGHDL/dom/_Utils.py b/pyGHDL/dom/_Utils.py
index 0349a11ef..10053db6e 100644
--- a/pyGHDL/dom/_Utils.py
+++ b/pyGHDL/dom/_Utils.py
@@ -13,7 +13,7 @@
#
# License:
# ============================================================================
-# Copyright (C) 2019-2021 Tristan Gingold
+# Copyright (C) 2019-2022 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
@@ -34,7 +34,7 @@ from pyTooling.Decorators import export
from pyVHDLModel.SyntaxModel import Mode
-from pyGHDL.libghdl import LibGHDLException, name_table, errorout_memory
+from pyGHDL.libghdl import LibGHDLException, name_table, errorout_memory, files_map, file_comments
from pyGHDL.libghdl._types import Iir
from pyGHDL.libghdl.vhdl import nodes, utils
from pyGHDL.libghdl.vhdl.nodes import Null_Iir
@@ -88,6 +88,18 @@ def GetNameOfNode(node: Iir) -> str:
@export
+def GetDocumentationOfNode(node: Iir) -> str:
+ file = files_map.Location_To_File(nodes.Get_Location(node))
+ idx = file_comments.Find_First_Comment(file, node)
+ documentation = []
+ while idx != file_comments.No_Comment_Index:
+ documentation.append(file_comments.Get_Comment(file, idx))
+ idx = file_comments.Get_Next_Comment(file, idx)
+
+ return "\n".join(documentation)
+
+
+@export
def GetModeOfNode(node: Iir) -> Mode:
"""Return the mode of a :obj:`node`."""
if node == Null_Iir:
diff --git a/pyGHDL/dom/__init__.py b/pyGHDL/dom/__init__.py
index e9eb89240..12caccc1b 100644
--- a/pyGHDL/dom/__init__.py
+++ b/pyGHDL/dom/__init__.py
@@ -39,8 +39,6 @@ from pyGHDL.libghdl import files_map, name_table
from pyGHDL.libghdl._types import Iir
from pyGHDL.libghdl.vhdl import nodes
-__all__ = []
-
@export
class Position:
diff --git a/pyGHDL/dom/formatting/prettyprint.py b/pyGHDL/dom/formatting/prettyprint.py
index aa9c90c34..b5397610a 100644
--- a/pyGHDL/dom/formatting/prettyprint.py
+++ b/pyGHDL/dom/formatting/prettyprint.py
@@ -47,7 +47,7 @@ from pyGHDL.dom.Concurrent import (
)
from pyVHDLModel.SyntaxModel import (
GenericInterfaceItem,
- NamedEntity,
+ NamedEntityMixin,
PortInterfaceItem,
WithDefaultExpressionMixin,
Function,
@@ -301,7 +301,7 @@ class PrettyPrint:
return buffer
- def formatGeneric(self, generic: Union[NamedEntity, GenericInterfaceItem], level: int = 0) -> StringBuffer:
+ def formatGeneric(self, generic: Union[NamedEntityMixin, GenericInterfaceItem], level: int = 0) -> StringBuffer:
if isinstance(generic, GenericConstantInterfaceItem):
return self.formatGenericConstant(generic, level)
elif isinstance(generic, GenericTypeInterfaceItem):
@@ -311,7 +311,7 @@ class PrettyPrint:
f"Unhandled generic kind '{generic.__class__.__name__}' for generic '{generic.Identifiers[0]}'."
)
- def formatPort(self, port: Union[NamedEntity, PortInterfaceItem], level: int = 0) -> StringBuffer:
+ def formatPort(self, port: Union[NamedEntityMixin, PortInterfaceItem], level: int = 0) -> StringBuffer:
if isinstance(port, PortSignalInterfaceItem):
return self.formatPortSignal(port, level)
else:
diff --git a/pyGHDL/dom/requirements.txt b/pyGHDL/dom/requirements.txt
index 943757e92..6b540d7b7 100644
--- a/pyGHDL/dom/requirements.txt
+++ b/pyGHDL/dom/requirements.txt
@@ -1,4 +1,4 @@
-r ../libghdl/requirements.txt
-pyVHDLModel==0.14.4
+pyVHDLModel==0.18.0
#https://github.com/VHDL/pyVHDLModel/archive/dev.zip#pyVHDLModel
diff --git a/testsuite/pyunit/SimplePackage.vhdl b/testsuite/pyunit/SimplePackage.vhdl
deleted file mode 100644
index 0571e7060..000000000
--- a/testsuite/pyunit/SimplePackage.vhdl
+++ /dev/null
@@ -1,13 +0,0 @@
-library ieee;
-use ieee.std_logic_1164.all;
-use ieee.numeric_std.all;
-
-package pack_1 is
- constant const_1 : boolean := false;
-
-end package;
-
-package body pack_1 is
- constant const_1 : boolean := true;
-
-end package body;
diff --git a/testsuite/pyunit/dom/Expressions.py b/testsuite/pyunit/dom/Expressions.py
index 113e541ac..4b2e47507 100644
--- a/testsuite/pyunit/dom/Expressions.py
+++ b/testsuite/pyunit/dom/Expressions.py
@@ -34,6 +34,7 @@ import ctypes
from inspect import currentframe
from pathlib import Path
from textwrap import dedent
+from typing import TypeVar, Dict
from unittest import TestCase
@@ -51,6 +52,13 @@ if __name__ == "__main__":
exit(1)
+_DictKey = TypeVar("_DictKey")
+_DictValue = TypeVar("_DictValue")
+
+def firstValue(d: Dict[_DictKey, _DictValue]) -> _DictValue:
+ return next(iter(d.values()))
+
+
class Expressions(TestCase):
_root = Path(__file__).resolve().parent.parent
_design = Design()
@@ -69,7 +77,7 @@ class Expressions(TestCase):
self._design.Documents.append(document)
# Traverse already to default value expression
- package: Package = document.Packages[0]
+ package: Package = firstValue(document.Packages)
item: Constant = package.DeclaredItems[0]
default: Expression = item.DefaultExpression
diff --git a/testsuite/pyunit/dom/Literals.py b/testsuite/pyunit/dom/Literals.py
index debd401e3..9f53a6cc6 100644
--- a/testsuite/pyunit/dom/Literals.py
+++ b/testsuite/pyunit/dom/Literals.py
@@ -32,6 +32,7 @@
# ============================================================================
from pathlib import Path
from textwrap import dedent
+from typing import TypeVar, Dict
from unittest import TestCase
from pyVHDLModel.SyntaxModel import ExpressionUnion
@@ -49,6 +50,13 @@ if __name__ == "__main__":
exit(1)
+_DictKey = TypeVar("_DictKey")
+_DictValue = TypeVar("_DictValue")
+
+def firstValue(d: Dict[_DictKey, _DictValue]) -> _DictValue:
+ return next(iter(d.values()))
+
+
class Literals(TestCase):
_root = Path(__file__).resolve().parent.parent
_design = Design()
@@ -67,7 +75,7 @@ class Literals(TestCase):
self._design.Documents.append(document)
# Traverse already to default value expression
- package: Package = document.Packages[0]
+ package: Package = firstValue(document.Packages)
item: Constant = package.DeclaredItems[0]
default: ExpressionUnion = item.DefaultExpression
diff --git a/testsuite/pyunit/dom/Sanity.py b/testsuite/pyunit/dom/Sanity.py
index ff5151fb3..54cb4103b 100644
--- a/testsuite/pyunit/dom/Sanity.py
+++ b/testsuite/pyunit/dom/Sanity.py
@@ -50,10 +50,11 @@ _SANITY_TESTS_ROOT = _TESTSUITE_ROOT / "sanity"
design = Design()
-@mark.parametrize("file", [str(f.relative_to(_TESTSUITE_ROOT)) for f in _SANITY_TESTS_ROOT.glob("**/*.vhdl")])
-def test_AllVHDLSources(file):
+@mark.parametrize("parameters", [f"{i}:{f.relative_to(_TESTSUITE_ROOT)}" for i, f in enumerate(_SANITY_TESTS_ROOT.glob("**/*.vhdl"))])
+def test_AllVHDLSources(parameters):
+ id, file = parameters.split(":")
filePath = _TESTSUITE_ROOT / file
- lib = design.GetLibrary("sanity")
+ lib = design.GetLibrary(f"sanity_{id}")
document = Document(filePath)
design.AddDocument(document, lib)
diff --git a/testsuite/pyunit/dom/SimpleEntity.py b/testsuite/pyunit/dom/Simple.py
index 7e19c2d17..82dd8579e 100644
--- a/testsuite/pyunit/dom/SimpleEntity.py
+++ b/testsuite/pyunit/dom/Simple.py
@@ -31,6 +31,7 @@
# SPDX-License-Identifier: GPL-2.0-or-later
# ============================================================================
from pathlib import Path
+from typing import TypeVar, Dict
from unittest import TestCase
from pyGHDL.dom.NonStandard import Design, Document
@@ -42,9 +43,16 @@ if __name__ == "__main__":
exit(1)
+_DictKey = TypeVar("_DictKey")
+_DictValue = TypeVar("_DictValue")
+
+def firstValue(d: Dict[_DictKey, _DictValue]) -> _DictValue:
+ return next(iter(d.values()))
+
+
class SimpleEntity(TestCase):
_root = Path(__file__).resolve().parent.parent
- _filename: Path = _root / "SimpleEntity.vhdl"
+ _filename: Path = _root / "dom/examples/SimpleEntity.vhdl"
def test_Design(self):
design = Design()
@@ -60,6 +68,9 @@ class SimpleEntity(TestCase):
design.Documents.append(document)
self.assertEqual(1, len(design.Documents))
+ print()
+ print(document.Documentation)
+ self.assertEqual(4, len(document.Documentation.splitlines()))
def test_Entity(self):
design = Design()
@@ -67,7 +78,12 @@ class SimpleEntity(TestCase):
design.Documents.append(document)
self.assertEqual(1, len(design.Documents[0].Entities))
- self.assertEqual("Counter", design.Documents[0].Entities[0].Identifier)
+
+ entity = firstValue(design.Documents[0].Entities)
+ self.assertEqual("Counter", entity.Identifier)
+ print()
+ print(entity.Documentation)
+ self.assertEqual(11, len(entity.Documentation.splitlines()))
def test_Architecture(self):
design = Design()
@@ -75,4 +91,58 @@ class SimpleEntity(TestCase):
design.Documents.append(document)
self.assertEqual(1, len(design.Documents[0].Architectures))
- self.assertEqual("rtl", design.Documents[0].Architectures[0].Identifier)
+
+ architecture = firstValue(firstValue(design.Documents[0].Architectures))
+ self.assertEqual("rtl", architecture.Identifier)
+ print()
+ print(architecture.Documentation)
+ self.assertEqual(1, len(architecture.Documentation.splitlines()))
+
+
+class SimplePackage(TestCase):
+ _root = Path(__file__).resolve().parent.parent
+ _filename: Path = _root / "dom/examples/SimplePackage.vhdl"
+
+ def test_Design(self):
+ design = Design()
+
+ self.assertIsNotNone(design)
+
+ # def test_Library(self):
+ # library = Library()
+
+ def test_Document(self):
+ design = Design()
+ document = Document(self._filename)
+ design.Documents.append(document)
+
+ self.assertEqual(1, len(design.Documents))
+ print()
+ print(document.Documentation)
+ self.assertEqual(4, len(document.Documentation.splitlines()))
+
+ def test_Package(self):
+ design = Design()
+ document = Document(self._filename)
+ design.Documents.append(document)
+
+ self.assertEqual(1, len(design.Documents[0].Packages))
+
+ package = firstValue(design.Documents[0].Packages)
+ self.assertEqual("utilities", package.Identifier)
+ print()
+ print(package.Documentation)
+ self.assertEqual(1, len(package.Documentation.splitlines()))
+
+ def test_PackageBody(self):
+ design = Design()
+ document = Document(self._filename)
+ design.Documents.append(document)
+
+ self.assertEqual(1, len(design.Documents[0].PackageBodies))
+
+ packageBodies = firstValue(design.Documents[0].PackageBodies)
+ self.assertEqual("utilities", packageBodies.Identifier)
+ print()
+ print(packageBodies.Documentation)
+ self.assertEqual(0, len(packageBodies.Documentation.splitlines()))
diff --git a/testsuite/pyunit/dom/SimplePackage.py b/testsuite/pyunit/dom/SimplePackage.py
deleted file mode 100644
index 9c62db4a1..000000000
--- a/testsuite/pyunit/dom/SimplePackage.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# =============================================================================
-# ____ _ _ ____ _ _
-# _ __ _ _ / ___| | | | _ \| | __| | ___ _ __ ___
-# | '_ \| | | | | _| |_| | | | | | / _` |/ _ \| '_ ` _ \
-# | |_) | |_| | |_| | _ | |_| | |___ | (_| | (_) | | | | | |
-# | .__/ \__, |\____|_| |_|____/|_____(_)__,_|\___/|_| |_| |_|
-# |_| |___/
-# =============================================================================
-# Authors:
-# Patrick Lehmann
-#
-# Testsuite: Check libghdl IIR translation with a simple package.
-#
-# 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 pathlib import Path
-from unittest import TestCase
-
-from pyGHDL.dom.NonStandard import Design, Document
-
-
-if __name__ == "__main__":
- print("ERROR: you called a testcase declaration file as an executable module.")
- print("Use: 'python -m unitest <testcase module>'")
- exit(1)
-
-
-class SimplePackage(TestCase):
- _root = Path(__file__).resolve().parent.parent
- _filename: Path = _root / "SimplePackage.vhdl"
-
- def test_Package(self):
- design = Design()
- document = Document(self._filename)
- design.Documents.append(document)
-
- self.assertEqual(1, len(design.Documents[0].Packages))
- self.assertEqual("pack_1", design.Documents[0].Packages[0].Identifier)
-
- def test_PackageBody(self):
- design = Design()
- document = Document(self._filename)
- design.Documents.append(document)
-
- self.assertEqual(1, len(design.Documents[0].PackageBodies))
- self.assertEqual("pack_1", design.Documents[0].PackageBodies[0].Identifier)
diff --git a/testsuite/pyunit/dom/StopWatch.py b/testsuite/pyunit/dom/StopWatch.py
new file mode 100644
index 000000000..37b8293de
--- /dev/null
+++ b/testsuite/pyunit/dom/StopWatch.py
@@ -0,0 +1,109 @@
+# =============================================================================
+# ____ _ _ ____ _ _
+# _ __ _ _ / ___| | | | _ \| | __| | ___ _ __ ___
+# | '_ \| | | | | _| |_| | | | | | / _` |/ _ \| '_ ` _ \
+# | |_) | |_| | |_| | _ | |_| | |___ | (_| | (_) | | | | | |
+# | .__/ \__, |\____|_| |_|____/|_____(_)__,_|\___/|_| |_| |_|
+# |_| |___/
+# =============================================================================
+# Authors:
+# Patrick Lehmann
+#
+# Testsuite: Check libghdl IIR translation with a simple package.
+#
+# 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 pathlib import Path
+from unittest import TestCase
+
+from pyGHDL.dom.NonStandard import Design, Document
+
+
+if __name__ == "__main__":
+ print("ERROR: you called a testcase declaration file as an executable module.")
+ print("Use: 'python -m unitest <testcase module>'")
+ exit(1)
+
+
+class Designs(TestCase):
+ _root = Path(__file__).resolve().parent.parent
+ _sourceDirectory: Path = _root / "dom/examples/StopWatch"
+
+ _packageFiles = (
+ Path("Utilities.pkg.vhdl"),
+ Path("StopWatch.pkg.vhdl"),
+ )
+ _encoderFiles = _packageFiles + (
+ Path("seg7_Encoder.vhdl"),
+ Path("toplevel.Encoder.vhdl"),
+ )
+ _displayFiles = _packageFiles + (
+ Path("Counter.vhdl"),
+ Path("seg7_Encoder.vhdl"),
+ Path("seg7_Display.vhdl"),
+ Path("toplevel.Display.vhdl"),
+ )
+ _stopwatchFiles = _packageFiles + (
+ Path("Counter.vhdl"),
+ Path("seg7_Encoder.vhdl"),
+ Path("seg7_Display.vhdl"),
+ Path("StopWatch.vhdl"),
+ Path("Debouncer.vhdl"),
+ Path("toplevel.StopWatch.vhdl"),
+ )
+
+
+class Display(Designs):
+ def test_Encoder(self):
+ design = Design()
+ for file in self._encoderFiles:
+ document = Document(self._sourceDirectory / file)
+ design.Documents.append(document)
+
+ self.assertEqual(len(self._encoderFiles), len(design.Documents))
+
+ def test_Display(self):
+ design = Design()
+ for file in self._displayFiles:
+ document = Document(self._sourceDirectory / file)
+ design.Documents.append(document)
+
+ self.assertEqual(len(self._displayFiles), len(design.Documents))
+
+ def test_StopWatch(self):
+ design = Design()
+ for file in self._stopwatchFiles:
+ document = Document(self._sourceDirectory / file)
+ design.Documents.append(document)
+
+ self.assertEqual(len(self._stopwatchFiles), len(design.Documents))
+
+
+class CompileOrder(Designs):
+ def test_Encoder(self):
+ design = Design()
+ design.LoadStdLibrary()
+ design.LoadIEEELibrary()
+ library = design.GetLibrary("lib_StopWatch")
+ for file in self._encoderFiles:
+ document = Document(self._sourceDirectory / file)
+ design.AddDocument(document, library)
+
+ design.Analyze()
diff --git a/testsuite/pyunit/SimpleEntity.vhdl b/testsuite/pyunit/dom/examples/SimpleEntity.vhdl
index bdeae47e1..8acc3ddb5 100644
--- a/testsuite/pyunit/SimpleEntity.vhdl
+++ b/testsuite/pyunit/dom/examples/SimpleEntity.vhdl
@@ -35,8 +35,10 @@ entity Counter is
end entity;
--- Synthesizable and simulatable variant of a generic counter.
architecture rtl of Counter is
+ -- Synthesizable and simulatable variant of a generic counter.
+
+ -- Internal counter value
signal CounterValue : unsigned(log2(MODULO) - 1 downto 0) := (others => '0');
begin
process (Clock)
diff --git a/testsuite/pyunit/dom/examples/SimplePackage.vhdl b/testsuite/pyunit/dom/examples/SimplePackage.vhdl
new file mode 100644
index 000000000..04df1c521
--- /dev/null
+++ b/testsuite/pyunit/dom/examples/SimplePackage.vhdl
@@ -0,0 +1,28 @@
+-- Author: Patrick Lehmann
+--
+-- A collection of utility types and functions.
+--
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.numeric_std.all;
+
+-- Utility package
+package utilities is
+ -- Deferred constant to distinguish simulation from synthesis.
+ constant IS_SIMULATION : boolean;
+
+end package;
+
+package body utilities is
+ function simulation return boolean is
+ variable result : boolean := false;
+ begin
+ -- synthesis translate off
+ result := true;
+ -- synthesis translate on
+ return result;
+ end function;
+
+ constant IS_SIMULATION : boolean := simulation;
+
+end package body;
diff --git a/testsuite/pyunit/dom/examples/StopWatch/Counter.vhdl b/testsuite/pyunit/dom/examples/StopWatch/Counter.vhdl
new file mode 100644
index 000000000..3ef284b98
--- /dev/null
+++ b/testsuite/pyunit/dom/examples/StopWatch/Counter.vhdl
@@ -0,0 +1,45 @@
+-- Author: Patrick Lehmann
+-- License: MIT
+--
+-- A generic counter module used in the StopWatch example.
+--
+library IEEE;
+use IEEE.std_logic_1164.all;
+use IEEE.numeric_std.all;
+
+use work.Utilities.all;
+
+
+entity Counter is
+ generic (
+ MODULO : positive;
+ BITS : natural := log2(MODULO)
+ );
+ port (
+ Clock : in std_logic;
+ Reset : in std_logic;
+ Enable : in std_logic;
+
+ Value : out unsigned(BITS - 1 downto 0);
+ WrapAround : out std_logic
+ );
+end entity;
+
+
+architecture rtl of Counter is
+ signal CounterValue : unsigned(log2(MODULO) - 1 downto 0) := (others => '0');
+begin
+ process (Clock)
+ begin
+ if rising_edge(Clock) then
+ if ((Reset or WrapAround) = '1') then
+ CounterValue <= (others => '0');
+ elsif (Enable = '1') then
+ CounterValue <= CounterValue + 1;
+ end if;
+ end if;
+ end process;
+
+ Value <= resize(CounterValue, BITS);
+ WrapAround <= Enable when (CounterValue = MODULO - 1) else '0';
+end architecture;
diff --git a/testsuite/pyunit/dom/examples/StopWatch/Debouncer.vhdl b/testsuite/pyunit/dom/examples/StopWatch/Debouncer.vhdl
new file mode 100644
index 000000000..18207c7f1
--- /dev/null
+++ b/testsuite/pyunit/dom/examples/StopWatch/Debouncer.vhdl
@@ -0,0 +1,58 @@
+-- Author: Patrick Lehmann
+-- License: MIT
+--
+-- A generic counter module used in the StopWatch example.
+--
+library IEEE;
+use IEEE.std_logic_1164.all;
+use IEEE.numeric_std.all;
+
+use work.Utilities.all;
+
+
+entity Debouncer is
+ generic (
+ CLOCK_PERIOD : time := 10 ns;
+ DEBOUNCE_TIME : time := 3 ms;
+
+ BITS : positive
+ );
+ port (
+ Clock : in std_logic;
+
+ Input : in std_logic_vector(BITS - 1 downto 0);
+ Output : out std_logic_vector(BITS - 1 downto 0) := (others => '0')
+ );
+end entity;
+
+architecture rtl of Debouncer is
+ constant DEBOUNCE_COUNTER_MAX : positive := DEBOUNCE_TIME / (CLOCK_PERIOD* ite(IS_SIMULATION, 20, 1));
+ constant DEBOUNCE_COUNTER_BITS : positive := log2(DEBOUNCE_COUNTER_MAX);
+
+begin
+ assert false report "CLOCK_PERIOD: " & time'image(CLOCK_PERIOD);
+ assert false report "DEBOUNCE_TIME: " & time'image(DEBOUNCE_TIME);
+ --assert false report "DEBOUNCE_COUNTER_MAX: " & to_string(10 ns);
+ --assert false report "INTEGER'high: " & integer'image(integer'high);
+
+ genBits: for i in Input'range generate
+ signal DebounceCounter : signed(DEBOUNCE_COUNTER_BITS downto 0) := to_signed(DEBOUNCE_COUNTER_MAX - 3, DEBOUNCE_COUNTER_BITS + 1);
+ begin
+ process (Clock)
+ begin
+ if rising_edge(Clock) then
+ -- restart counter, whenever Input(i) was unstable within DEBOUNCE_TIME_MS
+ if (Input(i) /= Output(i)) then
+ DebounceCounter <= DebounceCounter - 1;
+ else
+ DebounceCounter <= to_signed(DEBOUNCE_COUNTER_MAX - 3, DebounceCounter'length);
+ end if;
+
+ -- latch input bit, if input was stable for DEBOUNCE_TIME_MS
+ if (DebounceCounter(DebounceCounter'high) = '1') then
+ Output(i) <= Input(i);
+ end if;
+ end if;
+ end process;
+ end generate;
+end architecture;
diff --git a/testsuite/pyunit/dom/examples/StopWatch/StopWatch.pkg.vhdl b/testsuite/pyunit/dom/examples/StopWatch/StopWatch.pkg.vhdl
new file mode 100644
index 000000000..3bcafdd6d
--- /dev/null
+++ b/testsuite/pyunit/dom/examples/StopWatch/StopWatch.pkg.vhdl
@@ -0,0 +1,21 @@
+-- Author: Patrick Lehmann
+-- License: MIT
+--
+-- A generic counter module used in the StopWatch example.
+--
+library IEEE;
+use IEEE.std_logic_1164.all;
+use IEEE.numeric_std.all;
+
+
+package StopWatch_pkg is
+ subtype T_BCD is unsigned(3 downto 0);
+ type T_BCD_Vector is array(natural range <>) of T_BCD;
+
+ type T_DIGIT_CONFIGURATION is record
+ Modulo : positive;
+ Dot : std_logic;
+ end record;
+
+ type T_STOPWATCH_CONFIGURATION is array(natural range <>) of T_DIGIT_CONFIGURATION;
+end package;
diff --git a/testsuite/pyunit/dom/examples/StopWatch/StopWatch.vhdl b/testsuite/pyunit/dom/examples/StopWatch/StopWatch.vhdl
new file mode 100644
index 000000000..c7c9068ab
--- /dev/null
+++ b/testsuite/pyunit/dom/examples/StopWatch/StopWatch.vhdl
@@ -0,0 +1,127 @@
+-- Author: Patrick Lehmann
+-- License: MIT
+--
+-- A generic counter module used in the StopWatch example.
+--
+library IEEE;
+use IEEE.std_logic_1164.all;
+use IEEE.numeric_std.all;
+
+use work.Utilities.all;
+use work.StopWatch_pkg.all;
+
+
+entity Stopwatch is
+ generic (
+ CLOCK_PERIOD : time := 10 ns;
+
+ TIMEBASE : time;
+ CONFIG : T_STOPWATCH_CONFIGURATION
+ );
+ port (
+ Clock : in std_logic;
+ Reset : in std_logic;
+
+ Start : in std_logic;
+
+ Digits : out T_BCD_Vector(CONFIG'length - 1 downto 0);
+ Dots : out std_logic_vector(CONFIG'length - 1 downto 0)
+ );
+end entity;
+
+
+architecture trl of Stopwatch is
+ type T_STATE is (ST_RESET, ST_IDLE, ST_COUNTING, ST_PAUSE);
+
+ signal State : T_STATE := ST_IDLE;
+ signal NextState : T_STATE;
+
+ signal FSM_Reset : std_logic;
+ signal FSM_Enable : std_logic;
+
+ signal Tick : std_logic;
+ signal Overflows : std_logic_vector(CONFIG'length downto 0);
+
+
+begin
+ process(Clock)
+ begin
+ if rising_edge(Clock) then
+ if (Reset = '1') then
+ State <= ST_RESET;
+ else
+ State <= NextState;
+ end if;
+ end if;
+ end process;
+
+ process(State, Start)
+ begin
+ NextState <= State;
+
+ FSM_Reset <= '0';
+ FSM_Enable <= '0';
+
+ case State is
+ when ST_RESET =>
+ FSM_Reset <= '1';
+ NextState <= ST_IDLE;
+
+ when ST_IDLE =>
+ if (Start = '1') then
+ NextState <= ST_COUNTING;
+ end if;
+
+ when ST_COUNTING =>
+ FSM_Enable <= '1';
+
+ if (Start = '1') then
+ NextState <= ST_PAUSE;
+ end if;
+
+ when ST_PAUSE =>
+ if (Start = '1') then
+ NextState <= ST_COUNTING;
+ end if;
+
+ when others =>
+ NextState <= ST_RESET;
+
+ end case;
+ end process;
+
+ TimeBaseCnt: entity work.Counter
+ generic map (
+ MODULO => TIMEBASE / (CLOCK_PERIOD * ite(IS_SIMULATION, 100, 1)),
+ BITS => 0
+ )
+ port map (
+ Clock => Clock,
+ Reset => FSM_Reset,
+ Enable => FSM_Enable,
+
+ Value => open,
+ WrapAround => Tick
+ );
+
+ Overflows(0) <= Tick;
+
+ genDigits: for i in CONFIG'range generate
+ cnt: entity work.Counter
+ generic map (
+ MODULO => CONFIG(i).Modulo,
+ BITS => Digits(i)'length
+ )
+ port map (
+ Clock => Clock,
+ Reset => FSM_Reset,
+ Enable => Overflows(i),
+
+ Value => Digits(i),
+ WrapAround => Overflows(i + 1)
+ );
+
+ Dots(i) <= CONFIG(i).Dot;
+ end generate;
+
+end architecture;
diff --git a/testsuite/pyunit/dom/examples/StopWatch/Utilities.pkg.vhdl b/testsuite/pyunit/dom/examples/StopWatch/Utilities.pkg.vhdl
new file mode 100644
index 000000000..8daf39614
--- /dev/null
+++ b/testsuite/pyunit/dom/examples/StopWatch/Utilities.pkg.vhdl
@@ -0,0 +1,99 @@
+-- Author: Patrick Lehmann
+-- License: MIT
+--
+-- A generic counter module used in the StopWatch example.
+--
+library IEEE;
+use IEEE.std_logic_1164.all;
+use IEEE.numeric_std.all;
+
+
+package Utilities is
+ type freq is range integer'low to integer'high units
+ Hz;
+ kHz = 1000 Hz;
+ MHz = 1000 kHz;
+ GHz = 1000 MHz;
+ THz = 1000 GHz;
+ end units;
+
+ -- deferred constant
+ constant IS_SIMULATION : boolean;
+
+ function ite(condition : boolean; ThenValue : integer; ElseValue : integer) return integer;
+
+ function log2(Value : positive) return positive;
+
+ function bin2onehot(binary : std_logic_vector; bits : natural := 0) return std_logic_vector;
+ function bin2onehot(binary : unsigned; bits : natural := 0) return std_logic_vector;
+
+ function to_index(value : unsigned; max : positive) return natural;
+ function to_index(value : natural; max : positive) return natural;
+end package;
+
+
+package body Utilities is
+ function simulation return boolean is
+ variable result : boolean := FALSE;
+ begin
+ -- synthesis translate_off
+ result := TRUE;
+ -- synthesis translate_on
+ return result;
+ end function;
+
+ -- deferred constant initialization
+ constant IS_SIMULATION : boolean := simulation;
+
+ function ite(condition : boolean; ThenValue : integer; ElseValue : integer) return integer is
+ begin
+ if condition then
+ return ThenValue;
+ else
+ return ElseValue;
+ end if;
+ end function;
+
+ function log2(Value : positive) return positive is
+ variable twosPower : natural := 1;
+ variable result : natural := 0;
+ begin
+ while (twosPower < Value) loop
+ twosPower := twosPower * 2;
+ result := result + 1;
+ end loop;
+ return result;
+ end function;
+
+ function bin2onehot(binary : std_logic_vector; bits : natural := 0) return std_logic_vector is
+ begin
+ return bin2onehot(unsigned(binary), bits);
+ end function;
+
+ function bin2onehot(binary : unsigned; bits : natural := 0) return std_logic_vector is
+ variable result : std_logic_vector(2**binary'length - 1 downto 0) := (others => '0');
+ begin
+ result(to_integer(binary)) := '1';
+
+ if (bits = 0) then
+ return result;
+ else
+ return result(bits - 1 downto 0);
+ end if;
+ end function;
+
+ function to_index(value : unsigned; max : positive) return natural is
+ begin
+ return to_index(to_integer(value), max);
+ end function;
+
+ function to_index(value : natural; max : positive) return natural is
+ begin
+ if (value <= max) then
+ return value;
+ else
+ return max;
+ end if;
+ -- return minimum(value, max);
+ end function;
+end package body;
diff --git a/testsuite/pyunit/dom/examples/StopWatch/seg7_Display.vhdl b/testsuite/pyunit/dom/examples/StopWatch/seg7_Display.vhdl
new file mode 100644
index 000000000..c3771ba68
--- /dev/null
+++ b/testsuite/pyunit/dom/examples/StopWatch/seg7_Display.vhdl
@@ -0,0 +1,90 @@
+-- Author: Patrick Lehmann
+-- License: MIT
+--
+-- A generic counter module used in the StopWatch example.
+--
+library IEEE;
+use IEEE.std_logic_1164.all;
+use IEEE.numeric_std.all;
+
+use work.Utilities.all;
+use work.StopWatch_pkg.all;
+
+
+entity seg7_Display is
+ generic (
+ CLOCK_PERIOD : time := 10 ns;
+ REFRESH_RATE : time := 200 us;
+ DIGITS : positive
+ );
+ port (
+ Clock : in std_logic;
+
+ DigitValues : in T_BCD_Vector(DIGITS - 1 downto 0);
+ DotValues : in std_logic_vector(DIGITS - 1 downto 0) := (others => '0');
+
+ Seg7_Segments : out std_logic_vector(7 downto 0);
+ Seg7_Selects : out std_logic_vector(DIGITS - 1 downto 0)
+ );
+end entity;
+
+
+architecture rtl of seg7_Display is
+ constant TIMEBASE_COUNTER_MAX : positive := REFRESH_RATE / (CLOCK_PERIOD * ite(IS_SIMULATION, 1_000, 1));
+
+ signal Timebase_Counter : unsigned(log2(TIMEBASE_COUNTER_MAX) - 1 downto 0) := (others => '0');
+ signal Timebase_Tick : std_logic;
+
+ signal Digit_Select : unsigned(log2(DIGITS) - 1 downto 0) := (others => '0');
+ signal Digit_Select_ov : std_logic;
+
+ signal Digit : T_BCD;
+ signal Dot : std_logic;
+begin
+ -- refresh rate
+ process(Clock)
+ begin
+ if rising_edge(Clock) then
+ if (Timebase_Tick = '1') then
+ Timebase_Counter <= (others => '0');
+ else
+ Timebase_Counter <= Timebase_Counter + 1;
+ end if;
+ end if;
+ end process;
+
+ Timebase_Tick <= '1' when (Timebase_Counter = TIMEBASE_COUNTER_MAX - 1) else '0';
+
+
+ -- counter to select digits (time multiplexing)
+ process(Clock)
+ begin
+ if rising_edge(Clock) then
+ if (Timebase_Tick = '1') then
+ if (Digit_Select_ov = '1') then
+ Digit_Select <= (others => '0'); -- to_unsigned(5, Digit_Select'length);
+ else
+ Digit_Select <= Digit_Select + 1;
+ end if;
+ end if;
+ end if;
+ end process;
+
+ Digit_Select_ov <= '1' when (Digit_Select = DIGITS - 1) else '0';
+
+ -- multiplexer
+ Digit <= DigitValues(to_index(Digit_Select, DigitValues'high));
+ Dot <= DotValues(to_index(Digit_Select, DotValues'high));
+
+ -- 7-segment encoder
+ enc: entity work.seg7_Encoder
+ port map (
+ BCDValue => Digit,
+ Dot => Dot,
+
+ Seg7Code => Seg7_Segments
+ );
+
+
+ Seg7_Selects <= bin2onehot(Digit_Select, DIGITS);
+end architecture;
diff --git a/testsuite/pyunit/dom/examples/StopWatch/seg7_Encoder.vhdl b/testsuite/pyunit/dom/examples/StopWatch/seg7_Encoder.vhdl
new file mode 100644
index 000000000..e4c731ff9
--- /dev/null
+++ b/testsuite/pyunit/dom/examples/StopWatch/seg7_Encoder.vhdl
@@ -0,0 +1,46 @@
+-- Author: Patrick Lehmann
+-- License: MIT
+--
+-- A generic counter module used in the StopWatch example.
+--
+library IEEE;
+use IEEE.std_logic_1164.all;
+use IEEE.numeric_std.all;
+
+use work.Utilities.all;
+use work.StopWatch_pkg.all;
+
+
+entity seg7_Encoder is
+ port (
+ BCDValue : in T_BCD;
+ Dot : in std_logic := '0';
+
+ Seg7Code : out std_logic_vector(7 downto 0)
+ );
+end entity;
+
+
+architecture rtl of seg7_Encoder is
+
+begin
+ process(BCDValue, Dot)
+ variable temp : std_logic_vector(6 downto 0);
+ begin
+ case BCDValue is -- segments: GFEDCBA -- Segment Pos. Index Pos.
+ when x"0" => temp := "0111111"; --
+ when x"1" => temp := "0000110"; --
+ when x"2" => temp := "1011011"; -- AAA 000
+ when x"3" => temp := "1001111"; -- F B 5 1
+ when x"4" => temp := "1100110"; -- F B 5 1
+ when x"5" => temp := "1101101"; -- GGG 666
+ when x"6" => temp := "1111101"; -- E C 4 2
+ when x"7" => temp := "0000111"; -- E C 4 2
+ when x"8" => temp := "1111111"; -- DDD DOT 333 7
+ when x"9" => temp := "1101111"; --
+ when others => temp := "XXXXXXX"; --
+ end case;
+
+ Seg7Code <= Dot & temp;
+ end process;
+end architecture;
diff --git a/testsuite/pyunit/dom/examples/StopWatch/toplevel.Display.vhdl b/testsuite/pyunit/dom/examples/StopWatch/toplevel.Display.vhdl
new file mode 100644
index 000000000..67228a5ac
--- /dev/null
+++ b/testsuite/pyunit/dom/examples/StopWatch/toplevel.Display.vhdl
@@ -0,0 +1,65 @@
+-- Author: Patrick Lehmann
+-- License: MIT
+--
+-- A generic counter module used in the StopWatch example.
+--
+library IEEE;
+use IEEE.std_logic_1164.all;
+use IEEE.numeric_std.all;
+
+use work.Utilities.all;
+use work.StopWatch_pkg.all;
+
+
+entity toplevel is
+ generic (
+ constant CLOCK_PERIOD : time := 10 ns
+ );
+ port (
+ NexysA7_SystemClock : in std_logic;
+
+ NexysA7_GPIO_Switch : in std_logic_vector(15 downto 0);
+
+ NexysA7_GPIO_Seg7_Cathode_n : out std_logic_vector(7 downto 0);
+ NexysA7_GPIO_Seg7_Anode_n : out std_logic_vector(7 downto 0)
+ );
+end entity;
+
+
+architecture rtl of toplevel is
+ signal Digits : T_BCD_Vector(5 downto 0);
+
+ signal Cathode : std_logic_vector(7 downto 0);
+ signal Anode : std_logic_vector(Digits'range);
+
+begin
+ -- connect switches to first 4 digits
+ genDigits: for i in 0 to 3 generate
+ Digits(i) <= unsigned(NexysA7_GPIO_Switch(i * 4 + 3 downto i * 4));
+ end generate;
+
+ -- do arithmetic calculations on next 2 digits
+ Digits(4) <= Digits(1) + Digits(0);
+ Digits(5) <= Digits(3) - Digits(2);
+
+
+ -- 7-segment display
+ display: entity work.seg7_Display
+ generic map (
+ CLOCK_PERIOD => CLOCK_PERIOD,
+ DIGITS => Digits'length
+ )
+ port map (
+ Clock => NexysA7_SystemClock,
+
+ DigitValues => Digits,
+ DotValues => 6d"16",
+
+ Seg7_Segments => Cathode,
+ Seg7_Selects => Anode
+ );
+
+ -- convert low-active outputs
+ NexysA7_GPIO_Seg7_Cathode_n <= not Cathode;
+ NexysA7_GPIO_Seg7_Anode_n <= not ((NexysA7_GPIO_Seg7_Anode_n'high downto Anode'length => '0') & Anode);
+end architecture;
diff --git a/testsuite/pyunit/dom/examples/StopWatch/toplevel.Encoder.vhdl b/testsuite/pyunit/dom/examples/StopWatch/toplevel.Encoder.vhdl
new file mode 100644
index 000000000..7775a6eb6
--- /dev/null
+++ b/testsuite/pyunit/dom/examples/StopWatch/toplevel.Encoder.vhdl
@@ -0,0 +1,42 @@
+-- Author: Patrick Lehmann
+-- License: MIT
+--
+-- A generic counter module used in the StopWatch example.
+--
+library IEEE;
+use IEEE.std_logic_1164.all;
+use IEEE.numeric_std.all;
+
+use work.Utilities.all;
+use work.StopWatch_pkg.all;
+
+
+entity toplevel is
+ port (
+ NexysA7_GPIO_Switch : in std_logic_vector(3 downto 0);
+
+ NexysA7_GPIO_Seg7_Cathode_n : out std_logic_vector(7 downto 0);
+ NexysA7_GPIO_Seg7_Anode_n : out std_logic_vector(7 downto 0)
+ );
+end entity;
+
+
+architecture rtl of toplevel is
+ signal Cathode : std_logic_vector(7 downto 0);
+ signal Anode : std_logic_vector(7 downto 0);
+
+begin
+
+ -- 7-segment encoder
+ encoder: entity work.seg7_Encoder
+ port map (
+ BCDValue => unsigned(NexysA7_GPIO_Switch),
+ Dot => '1',
+
+ Seg7Code => Cathode
+ );
+
+ -- convert low-active outputs
+ NexysA7_GPIO_Seg7_Cathode_n <= not Cathode;
+ NexysA7_GPIO_Seg7_Anode_n <= not x"01";
+end architecture;
diff --git a/testsuite/pyunit/dom/examples/StopWatch/toplevel.StopWatch.tb.vhdl b/testsuite/pyunit/dom/examples/StopWatch/toplevel.StopWatch.tb.vhdl
new file mode 100644
index 000000000..a334475c4
--- /dev/null
+++ b/testsuite/pyunit/dom/examples/StopWatch/toplevel.StopWatch.tb.vhdl
@@ -0,0 +1,58 @@
+-- Author: Patrick Lehmann
+-- License: MIT
+--
+-- A generic counter module used in the StopWatch example.
+--
+library IEEE;
+use IEEE.std_logic_1164.all;
+use IEEE.numeric_std.all;
+
+library lib_StopWatch;
+use lib_StopWatch.Utilities.all;
+use lib_StopWatch.StopWatch_pkg.all;
+
+
+entity toplevel_tb is
+end entity;
+
+
+architecture tb of toplevel_tb is
+ constant CLOCK_PERIOD : time := 10 ns;
+
+ signal StopSimulation : std_logic := '0';
+ signal Clock : std_logic := '1';
+ signal Reset : std_logic := '1';
+
+ signal StartButton : std_logic := '0';
+
+begin
+ StopSimulation <= '1' after 30 ms;
+
+ Clock <= (Clock xnor StopSimulation) after CLOCK_PERIOD / 2;
+ Reset <= '0' after 2 us,
+ '1' after 3 us,
+ '0' after 20 ms,
+ '1' after 20 ms + 2 us;
+ StartButton <= '1' after 10 us,
+ '0' after 15 us,
+ '1' after 10 ms,
+ '0' after 10 ms + 1 us,
+ '1' after 12 ms,
+ '0' after 12 ms + 2 us,
+ '1' after 22 ms,
+ '0' after 22 ms + 2 us;
+
+ DUT: entity lib_StopWatch.toplevel
+ generic map (
+ CLOCK_PERIOD_NS => CLOCK_PERIOD / 1 ns
+ )
+ port map (
+ Clock => Clock,
+ Reset_n => Reset,
+
+ Button(0) => StartButton,
+ Seg7_Cathode_n => open,
+ Seg7_Anode_n => open
+ );
+
+end architecture;
diff --git a/testsuite/pyunit/dom/examples/StopWatch/toplevel.StopWatch.vhdl b/testsuite/pyunit/dom/examples/StopWatch/toplevel.StopWatch.vhdl
new file mode 100644
index 000000000..1c8547446
--- /dev/null
+++ b/testsuite/pyunit/dom/examples/StopWatch/toplevel.StopWatch.vhdl
@@ -0,0 +1,118 @@
+-- Author: Patrick Lehmann
+-- License: MIT
+--
+-- A generic counter module used in the StopWatch example.
+--
+library IEEE;
+use IEEE.std_logic_1164.all;
+use IEEE.numeric_std.all;
+
+use work.Utilities.all;
+use work.StopWatch_pkg.all;
+
+
+entity toplevel is
+ generic (
+ constant CLOCK_PERIOD : time := 10 ns
+ );
+ port (
+ NexysA7_SystemClock : in std_logic;
+ NexysA7_GPIO_Button_Reset_n : in std_logic;
+
+ NexysA7_GPIO_Button : in std_logic_vector(0 downto 0);
+ NexysA7_GPIO_Seg7_Cathode_n : out std_logic_vector(7 downto 0);
+ NexysA7_GPIO_Seg7_Anode_n : out std_logic_vector(7 downto 0)
+ );
+end entity;
+
+
+architecture rtl of toplevel is
+ constant STOPWATCH_CONFIGURATION : T_STOPWATCH_CONFIGURATION := (
+ 0 => (Modulo => 10, Dot => '0'),
+ 1 => (Modulo => 10, Dot => '0'),
+ 2 => (Modulo => 10, Dot => '0'),
+ 3 => (Modulo => 6, Dot => '0'),
+ 4 => (Modulo => 10, Dot => '0'),
+ 5 => (Modulo => 6, Dot => '0')
+ );
+
+ signal Board_Reset : std_logic;
+
+ signal Deb_Reset : std_logic;
+ signal Deb_Start : std_logic;
+ signal Deb_Start_d : std_logic := '0';
+ signal Deb_Start_re : std_logic;
+
+ signal Reset : std_logic;
+ signal Start : std_logic;
+
+
+ signal Digits : T_BCD_Vector(STOPWATCH_CONFIGURATION'length - 1 downto 0);
+
+ signal Cathode : std_logic_vector(7 downto 0);
+ signal Anode : std_logic_vector(Digits'range);
+
+begin
+ -- convert from low-active inputs
+ Board_Reset <= not NexysA7_GPIO_Button_Reset_n;
+
+ -- Debounce input signals
+ deb: entity work.Debouncer
+ generic map (
+ CLOCK_PERIOD => CLOCK_PERIOD,
+ BITS => 2
+ )
+ port map (
+ Clock => NexysA7_SystemClock,
+
+ Input(0) => Board_Reset,
+ Input(1) => NexysA7_GPIO_Button(0),
+ Output(0) => Deb_Reset,
+ Output(1) => Deb_Start
+ );
+
+ Reset <= Deb_Reset;
+
+ -- Rising edge detection
+ Deb_Start_d <= Deb_Start when rising_edge(NexysA7_SystemClock);
+ Deb_Start_re <= not Deb_Start_d and Deb_Start;
+
+ -- renaming
+ Start <= Deb_Start_re;
+
+ -- Stopwatch
+ sw: entity work.Stopwatch
+ generic map (
+ CLOCK_PERIOD => CLOCK_PERIOD,
+
+ TIMEBASE => 10 ms,
+ CONFIG => STOPWATCH_CONFIGURATION
+ )
+ port map (
+ Clock => NexysA7_SystemClock,
+ Reset => Reset,
+
+ Start => Start,
+
+ Digits => Digits
+ );
+
+ -- 7-segment display
+ display: entity work.seg7_Display
+ generic map (
+ CLOCK_PERIOD => CLOCK_PERIOD,
+ DIGITS => Digits'length
+ )
+ port map (
+ Clock => NexysA7_SystemClock,
+
+ DigitValues => Digits,
+
+ Seg7_Segments => Cathode,
+ Seg7_Selects => Anode
+ );
+
+ -- convert to low-active outputs
+ NexysA7_GPIO_Seg7_Cathode_n <= not Cathode;
+ NexysA7_GPIO_Seg7_Anode_n <= not ((NexysA7_GPIO_Seg7_Anode_n'high downto Anode'length => '0') & Anode);
+end architecture;
diff --git a/testsuite/pyunit/libghdl/Initialize.py b/testsuite/pyunit/libghdl/Initialize.py
index 7e3ace869..299b6321e 100644
--- a/testsuite/pyunit/libghdl/Initialize.py
+++ b/testsuite/pyunit/libghdl/Initialize.py
@@ -14,7 +14,7 @@ if __name__ == "__main__":
class Instantiate(TestCase):
_root = Path(__file__).resolve().parent.parent
- _filename: Path = _root / "SimpleEntity.vhdl"
+ _filename: Path = _root / "dom/examples/SimpleEntity.vhdl"
@staticmethod
def getIdentifier(node):
@@ -39,7 +39,7 @@ class Instantiate(TestCase):
file_id = name_table.Get_Identifier(str(self._filename))
sfe = files_map.Read_Source_File(name_table.Null_Identifier, file_id)
if sfe == files_map.No_Source_File_Entry:
- self.fail("Cannot read file '{!s}'".format(self._filename))
+ self.fail(f"Cannot read file '{self._filename}'")
# Parse
file = sem_lib.Load_File(sfe)
@@ -54,7 +54,7 @@ class Instantiate(TestCase):
self.assertEqual(
"counter",
entityName,
- "expected entity name 'counter', got '{}'".format(entityName),
+ f"expected entity name 'counter', got '{entityName}'",
)
elif nodes.Get_Kind(libraryUnit) == nodes.Iir_Kind.Architecture_Body:
@@ -62,9 +62,7 @@ class Instantiate(TestCase):
self.assertEqual(
"rtl",
architectureName,
- "expected architecture name 'rtl', got '{}'".format(
- architectureName
- ),
+ f"expected architecture name 'rtl', got '{architectureName}'"
)
else: