aboutsummaryrefslogtreecommitdiffstats
path: root/testsuite/pyunit/dom
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 /testsuite/pyunit/dom
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
Diffstat (limited to 'testsuite/pyunit/dom')
-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.vhdl57
-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
19 files changed, 1058 insertions, 71 deletions
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/dom/examples/SimpleEntity.vhdl b/testsuite/pyunit/dom/examples/SimpleEntity.vhdl
new file mode 100644
index 000000000..8acc3ddb5
--- /dev/null
+++ b/testsuite/pyunit/dom/examples/SimpleEntity.vhdl
@@ -0,0 +1,57 @@
+-- Author: Patrick Lehmann
+--
+-- 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;
+
+-- Generic modulo N counter
+--
+-- This component implements a generic modulo N counter with synchronous reset
+-- and enable. It generates a wrap-around strobe signal when it roles from
+-- MODULO-1 back to zero.
+--
+-- .. hint::
+--
+-- A modulo N counter counts binary from zero to N-1.
+--
+-- This component uses VHDL-2008 features like readback of ``out`` ports.
+entity Counter is
+ generic (
+ MODULO : positive; -- Modulo value.
+ BITS : natural := log2(MODULO) -- Number of expected output bits.
+ );
+ port (
+ Clock : in std_logic; -- Component clock
+ Reset : in std_logic; -- Component reset (synchronous)
+ Enable : in std_logic; -- Component enable (synchronous)
+
+ Value : out unsigned(BITS - 1 downto 0); -- Current counter value
+ WrapAround : out std_logic -- Strobe output on change from MODULO-1 to zero
+ );
+end entity;
+
+
+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)
+ 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/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;