From be2775f11dd13d6dcfd3268cf08c4b2d1579a069 Mon Sep 17 00:00:00 2001 From: Patrick Lehmann Date: Sat, 14 Jan 2023 17:05:04 +0100 Subject: [PATCH 01/16] Simplified CI workflow. --- .github/workflows/Pipeline.yml | 188 ++++++++++++++++----------------- 1 file changed, 94 insertions(+), 94 deletions(-) diff --git a/.github/workflows/Pipeline.yml b/.github/workflows/Pipeline.yml index 5d2c17d..dcbea3f 100644 --- a/.github/workflows/Pipeline.yml +++ b/.github/workflows/Pipeline.yml @@ -13,44 +13,44 @@ jobs: with: name: VHDLDomain - UnitTesting: - uses: pyTooling/Actions/.github/workflows/UnitTesting.yml@dev - needs: - - Params - with: - jobs: ${{ needs.Params.outputs.python_jobs }} - artifact: ${{ fromJson(needs.Params.outputs.artifact_names).unittesting_xml }} - - Coverage: - uses: pyTooling/Actions/.github/workflows/CoverageCollection.yml@dev - needs: - - Params - with: - python_version: ${{ needs.Params.outputs.python_version }} - artifact: ${{ fromJson(needs.Params.outputs.artifact_names).codecoverage_html }} - secrets: - codacy_token: ${{ secrets.CODACY_PROJECT_TOKEN }} - - StaticTypeCheck: - uses: pyTooling/Actions/.github/workflows/StaticTypeCheck.yml@dev - needs: - - Params - with: - python_version: ${{ needs.Params.outputs.python_version }} - requirements: '-r tests/requirements.txt' - commands: mypy --html-report htmlmypy -p VHDLDomain - html_artifact: ${{ fromJson(needs.Params.outputs.artifact_names).statictyping_html }} - - PublishTestResults: - uses: pyTooling/Actions/.github/workflows/PublishTestResults.yml@dev - needs: - - UnitTesting +# UnitTesting: +# uses: pyTooling/Actions/.github/workflows/UnitTesting.yml@dev +# needs: +# - Params +# with: +# jobs: ${{ needs.Params.outputs.python_jobs }} +# artifact: ${{ fromJson(needs.Params.outputs.artifact_names).unittesting_xml }} +# +# Coverage: +# uses: pyTooling/Actions/.github/workflows/CoverageCollection.yml@dev +# needs: +# - Params +# with: +# python_version: ${{ needs.Params.outputs.python_version }} +# artifact: ${{ fromJson(needs.Params.outputs.artifact_names).codecoverage_html }} +# secrets: +# codacy_token: ${{ secrets.CODACY_PROJECT_TOKEN }} +# +# StaticTypeCheck: +# uses: pyTooling/Actions/.github/workflows/StaticTypeCheck.yml@dev +# needs: +# - Params +# with: +# python_version: ${{ needs.Params.outputs.python_version }} +# requirements: '-r tests/requirements.txt' +# commands: mypy --html-report htmlmypy -p VHDLDomain +# html_artifact: ${{ fromJson(needs.Params.outputs.artifact_names).statictyping_html }} +# +# PublishTestResults: +# uses: pyTooling/Actions/.github/workflows/PublishTestResults.yml@dev +# needs: +# - UnitTesting Package: uses: pyTooling/Actions/.github/workflows/Package.yml@dev needs: - Params - - Coverage +# - Coverage with: python_version: ${{ needs.Params.outputs.python_version }} artifact: ${{ fromJson(needs.Params.outputs.artifact_names).package_all }} @@ -59,9 +59,9 @@ jobs: uses: pyTooling/Actions/.github/workflows/Release.yml@dev if: startsWith(github.ref, 'refs/tags') needs: - - UnitTesting - - Coverage - - StaticTypeCheck +# - UnitTesting +# - Coverage +# - StaticTypeCheck - Package PublishOnPyPI: @@ -78,61 +78,61 @@ jobs: secrets: PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} - VerifyDocs: - needs: - - Params - name: 👍 Verify example snippets using Python ${{ needs.Params.outputs.python_version }} - runs-on: ubuntu-latest - - steps: - - name: ⏬ Checkout repository - uses: actions/checkout@v3 - - - name: ⚙ Setup GHDL - uses: ghdl/setup-ghdl-ci@master - - - name: 🐍 Setup Python - uses: actions/setup-python@v4 - with: - python-version: "3.10" -# python-version: ${{ needs.Params.outputs.python_version }} - - - name: 🐍 Install dependencies - run: | - pip3 install --disable-pip-version-check git+https://github.com/ghdl/ghdl.git@$(ghdl version hash) - - - name: ✂ Extract code snippet from README - shell: python - run: | - from pathlib import Path - import re - - ROOT = Path('.') - - with (ROOT / 'README.md').open('r') as rptr: - content = rptr.read() - - m = re.search(r"```py(thon)?(?P.*?)```", content, re.MULTILINE|re.DOTALL) - - if m is None: - raise Exception("Regular expression did not find the example in the README!") - - with (ROOT / 'tests/docs/example.py').open('w') as wptr: - wptr.write(m["code"]) - -# - name: Print example.py -# run: cat tests/docs/example.py - - - name: ☑ Run example snippet - working-directory: tests/docs - run: | - python3 example.py +# VerifyDocs: +# needs: +# - Params +# name: 👍 Verify example snippets using Python ${{ needs.Params.outputs.python_version }} +# runs-on: ubuntu-latest +# +# steps: +# - name: ⏬ Checkout repository +# uses: actions/checkout@v3 +# +# - name: ⚙ Setup GHDL +# uses: ghdl/setup-ghdl-ci@master +# +# - name: 🐍 Setup Python +# uses: actions/setup-python@v4 +# with: +# python-version: "3.10" +## python-version: ${{ needs.Params.outputs.python_version }} +# +# - name: 🐍 Install dependencies +# run: | +# pip3 install --disable-pip-version-check git+https://github.com/ghdl/ghdl.git@$(ghdl version hash) +# +# - name: ✂ Extract code snippet from README +# shell: python +# run: | +# from pathlib import Path +# import re +# +# ROOT = Path('.') +# +# with (ROOT / 'README.md').open('r') as rptr: +# content = rptr.read() +# +# m = re.search(r"```py(thon)?(?P.*?)```", content, re.MULTILINE|re.DOTALL) +# +# if m is None: +# raise Exception("Regular expression did not find the example in the README!") +# +# with (ROOT / 'tests/docs/example.py').open('w') as wptr: +# wptr.write(m["code"]) +# +## - name: Print example.py +## run: cat tests/docs/example.py +# +# - name: ☑ Run example snippet +# working-directory: tests/docs +# run: | +# python3 example.py BuildTheDocs: uses: pyTooling/Actions/.github/workflows/BuildTheDocs.yml@dev needs: - Params - - VerifyDocs +# - VerifyDocs with: artifact: ${{ fromJson(needs.Params.outputs.artifact_names).documentation_html }} @@ -141,23 +141,23 @@ jobs: needs: - Params - BuildTheDocs - - Coverage - - StaticTypeCheck +# - Coverage +# - StaticTypeCheck with: doc: ${{ fromJson(needs.Params.outputs.artifact_names).documentation_html }} - coverage: ${{ fromJson(needs.Params.outputs.artifact_names).codecoverage_html }} - typing: ${{ fromJson(needs.Params.outputs.artifact_names).statictyping_html }} +# coverage: ${{ fromJson(needs.Params.outputs.artifact_names).codecoverage_html }} +# typing: ${{ fromJson(needs.Params.outputs.artifact_names).statictyping_html }} ArtifactCleanUp: uses: pyTooling/Actions/.github/workflows/ArtifactCleanUp.yml@dev needs: - Params - - UnitTesting - - Coverage - - StaticTypeCheck +# - UnitTesting +# - Coverage +# - StaticTypeCheck - BuildTheDocs - PublishToGitHubPages - - PublishTestResults +# - PublishTestResults with: package: ${{ fromJson(needs.Params.outputs.artifact_names).package_all }} remaining: | From 60d268e320960cd33c24fb352d8e7d1704e32800 Mon Sep 17 00:00:00 2001 From: Patrick Lehmann Date: Tue, 17 Jan 2023 01:24:07 +0100 Subject: [PATCH 02/16] Some improvements. --- VHDLDomain/Index.py | 48 +++++++++++++++++++++++++++++++++++++--- VHDLDomain/__init__.py | 47 ++++++++++++++++++++++++++++++++++++++- VHDLDomain/vhdldomain.py | 31 -------------------------- doc/Directives/index.rst | 4 ++++ doc/Indices/index.rst | 4 ++++ doc/Roles/index.rst | 4 ++++ doc/StopWatch/index.rst | 9 ++++++++ doc/index.rst | 20 ++++++++++++++--- doc/vhdl-compindex.rst | 2 ++ doc/vhdl-packindex.rst | 2 ++ doc/vhdl-subindex.rst | 2 ++ doc/vhdl-typeindex.rst | 2 ++ 12 files changed, 137 insertions(+), 38 deletions(-) delete mode 100644 VHDLDomain/vhdldomain.py create mode 100644 doc/Directives/index.rst create mode 100644 doc/Indices/index.rst create mode 100644 doc/Roles/index.rst create mode 100644 doc/StopWatch/index.rst create mode 100644 doc/vhdl-compindex.rst create mode 100644 doc/vhdl-packindex.rst create mode 100644 doc/vhdl-subindex.rst create mode 100644 doc/vhdl-typeindex.rst diff --git a/VHDLDomain/Index.py b/VHDLDomain/Index.py index 4f2f160..eb22202 100644 --- a/VHDLDomain/Index.py +++ b/VHDLDomain/Index.py @@ -1,41 +1,78 @@ from typing import Iterable, Optional as Nullable, List, Tuple +from pyTooling.Decorators import export from sphinx.domains import Index, IndexEntry +@export class ComponentIndex(Index): - name = "componentindex" + """ + An index for VHDL components. + """ + + name = "compindex" localname = "Component Index" shortname = "Components" def generate(self, docnames: Iterable[str] = None) -> Tuple[List[Tuple[str, List[IndexEntry]]], bool]: result: List[Tuple[str, List[IndexEntry]]] = [] + entry = ("Counter", 0, "lib_Utilities/Counter", "lib_Utilities-Counter", "lib_Utilities/Counter", "", "A generic counter.") + group = ("C", [entry]) + + result.append(group) + return result, True + +@export class PackageIndex(Index): - name = "packageindex" + """ + An index for VHDL packages. + """ + + name = "packindex" localname = "Package Index" shortname = "Packages" def generate(self, docnames: Iterable[str] = None) -> Tuple[List[Tuple[str, List[IndexEntry]]], bool]: result: List[Tuple[str, List[IndexEntry]]] = [] + entry = ("Utilities", 0, "lib_Utilities/Utilities", "lib_Utilities-Utilities", "lib_Utilities/Utilities", "", "A collection of utilities.") + group = ("U", [entry]) + + result.append(group) + return result, True +@export class SubprogramIndex(Index): - name = "subprogramindex" + """ + An index for VHDL functions or procedures. + """ + + name = "subindex" localname = "Subprogram Index" shortname = "Subprograms" def generate(self, docnames: Iterable[str] = None) -> Tuple[List[Tuple[str, List[IndexEntry]]], bool]: result: List[Tuple[str, List[IndexEntry]]] = [] + entry = ("binary2onehot", 0, "lib_Utilities/binary2onehot", "lib_Utilities-binary2onehot", "lib_Utilities/binary2onehot", "", "Conversion from binary to onehot code.") + group = ("B", [entry]) + + result.append(group) + return result, True +@export class TypeIndex(Index): + """ + An index for types and subtypes in VHDL. + """ + name = "typeindex" localname = "Type Index" shortname = "Types" @@ -43,4 +80,9 @@ class TypeIndex(Index): def generate(self, docnames: Iterable[str] = None) -> Tuple[List[Tuple[str, List[IndexEntry]]], bool]: result: List[Tuple[str, List[IndexEntry]]] = [] + entry = ("BCD", 0, "lib_Utilities/BCD", "lib_Utilities-BCD", "lib_Utilities/BCD", "", "Binary coded decimal.") + group = ("B", [entry]) + + result.append(group) + return result, True diff --git a/VHDLDomain/__init__.py b/VHDLDomain/__init__.py index 176174b..bab1d47 100644 --- a/VHDLDomain/__init__.py +++ b/VHDLDomain/__init__.py @@ -44,6 +44,9 @@ __license__ = "Apache License, Version 2.0" __version__ = "0.1.0" +from pathlib import Path + +from pyGHDL.dom.NonStandard import Design, Document from sphinx.application import Sphinx from sphinx.domains import Domain @@ -68,6 +71,48 @@ def setup(sphinxApplication: Sphinx): sphinxApplication.add_domain(VHDLDomain) # sphinxApplication.add_config_value('vhdl_autodoc_source_path', '.', 'env', [str]) + _packageFiles = ( + ("lib_Utilities", Path("Utilities.pkg.vhdl")), + ("lib_Utilities", Path("Utilities.ctx.vhdl")), + ("lib_StopWatch", Path("StopWatch.pkg.vhdl")), + ("lib_StopWatch", Path("StopWatch.ctx.vhdl")), + ) + _encoderFiles = _packageFiles + ( + ("lib_StopWatch", Path("seg7_Encoder.vhdl")), + ("lib_StopWatch", Path("toplevel.Encoder.vhdl")), + ) + _displayFiles = _packageFiles + ( + ("lib_StopWatch", Path("Counter.vhdl")), + ("lib_StopWatch", Path("seg7_Encoder.vhdl")), + ("lib_StopWatch", Path("seg7_Display.vhdl")), + ("lib_StopWatch", Path("seg7_Display.cfg.vhdl")), + ("lib_StopWatch", Path("toplevel.Display.vhdl")), + ) + _stopwatchFiles = _packageFiles + ( + ("lib_Utilities", Path("Counter.vhdl")), + ("lib_StopWatch", Path("seg7_Encoder.vhdl")), + ("lib_StopWatch", Path("seg7_Display.vhdl")), + ("lib_StopWatch", Path("seg7_Display.cfg.vhdl")), + ("lib_StopWatch", Path("StopWatch.vhdl")), + ("lib_Utilities", Path("sync_Bits.vhdl")), + ("lib_Utilities", Path("Debouncer.vhdl")), + ("lib_StopWatch", Path("toplevel.StopWatch.vhdl")), + ) + + print("=" * 40) + print(Path.cwd()) + design = Design() + design.LoadDefaultLibraries() + designRoot = (Path.cwd() / "../examples/StopWatch").resolve() + for libraryName, file in _stopwatchFiles: + document = Document(designRoot / file) + design.AddDocument(document, design.GetLibrary(libraryName)) + print("-" * 40) + design.Analyze() + print("=" * 40) + return { - "version": "0.1" + "version": __version__, + 'parallel_read_safe': False, + 'parallel_write_safe': False, } diff --git a/VHDLDomain/vhdldomain.py b/VHDLDomain/vhdldomain.py deleted file mode 100644 index a2d773c..0000000 --- a/VHDLDomain/vhdldomain.py +++ /dev/null @@ -1,31 +0,0 @@ -# ==================================================================================================================== # -# __ ___ _ ____ _ ____ _ # -# \ \ / / | | | _ \| | | _ \ ___ _ __ ___ __ _(_)_ __ # -# \ \ / /| |_| | | | | | | | | |/ _ \| '_ ` _ \ / _` | | '_ \ # -# \ V / | _ | |_| | |___| |_| | (_) | | | | | | (_| | | | | | # -# \_/ |_| |_|____/|_____|____/ \___/|_| |_| |_|\__,_|_|_| |_| # -# # -# ==================================================================================================================== # -# Authors: # -# Patrick Lehmann # -# # -# License: # -# ==================================================================================================================== # -# Copyright 2017-2023 Patrick Lehmann - Boetzingen, Germany # -# Copyright 2016-2017 Patrick Lehmann - Dresden, Germany # -# # -# Licensed under the Apache License, Version 2.0 (the "License"); # -# you may not use this file except in compliance with the License. # -# You may obtain a copy of the License at # -# # -# http://www.apache.org/licenses/LICENSE-2.0 # -# # -# Unless required by applicable law or agreed to in writing, software # -# distributed under the License is distributed on an "AS IS" BASIS, # -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # -# See the License for the specific language governing permissions and # -# limitations under the License. # -# # -# SPDX-License-Identifier: Apache-2.0 # -# ==================================================================================================================== # -# diff --git a/doc/Directives/index.rst b/doc/Directives/index.rst new file mode 100644 index 0000000..33e7a00 --- /dev/null +++ b/doc/Directives/index.rst @@ -0,0 +1,4 @@ +.. _Directives: + +Directives +########## diff --git a/doc/Indices/index.rst b/doc/Indices/index.rst new file mode 100644 index 0000000..3d9e7e1 --- /dev/null +++ b/doc/Indices/index.rst @@ -0,0 +1,4 @@ +.. _Indices: + +Indices +####### diff --git a/doc/Roles/index.rst b/doc/Roles/index.rst new file mode 100644 index 0000000..ce8efe7 --- /dev/null +++ b/doc/Roles/index.rst @@ -0,0 +1,4 @@ +.. _Roles: + +Roles +##### diff --git a/doc/StopWatch/index.rst b/doc/StopWatch/index.rst new file mode 100644 index 0000000..de92551 --- /dev/null +++ b/doc/StopWatch/index.rst @@ -0,0 +1,9 @@ +.. _EX/StopWatch: + +StopWatch +######### + +:ref:`vhdl-compindex` +:ref:`vhdl-packindex` +:ref:`vhdl-subindex` +:ref:`vhdl-typeindex` diff --git a/doc/index.rst b/doc/index.rst index 6018d4f..d1104a4 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -122,10 +122,23 @@ License :caption: Main Documentation :hidden: - LanguageModel/index - Analyze/index - DataStructure/index + Directives/index + Roles/index + Indices/index +.. raw:: latex + + \part{Examples} + +.. toctree:: + :caption: Examples + :hidden: + + StopWatch/index + Components + Packages + Subprograms + Types .. raw:: latex @@ -143,6 +156,7 @@ License .. raw:: latex + \part{Appendix} .. toctree:: diff --git a/doc/vhdl-compindex.rst b/doc/vhdl-compindex.rst new file mode 100644 index 0000000..19b047b --- /dev/null +++ b/doc/vhdl-compindex.rst @@ -0,0 +1,2 @@ +Component Index +############### diff --git a/doc/vhdl-packindex.rst b/doc/vhdl-packindex.rst new file mode 100644 index 0000000..26a6a0e --- /dev/null +++ b/doc/vhdl-packindex.rst @@ -0,0 +1,2 @@ +Package Index +############# diff --git a/doc/vhdl-subindex.rst b/doc/vhdl-subindex.rst new file mode 100644 index 0000000..a8dbe25 --- /dev/null +++ b/doc/vhdl-subindex.rst @@ -0,0 +1,2 @@ +Subprogram Index +################ diff --git a/doc/vhdl-typeindex.rst b/doc/vhdl-typeindex.rst new file mode 100644 index 0000000..c976bb9 --- /dev/null +++ b/doc/vhdl-typeindex.rst @@ -0,0 +1,2 @@ +Type Index +########## From 7c69684becef25129f70cddc68820ac46fea9bb5 Mon Sep 17 00:00:00 2001 From: Patrick Lehmann Date: Tue, 17 Jan 2023 01:24:21 +0100 Subject: [PATCH 03/16] Added example design "StopWatch". --- examples/StopWatch/Counter.vhdl | 45 ++++++ examples/StopWatch/Debouncer.vhdl | 74 ++++++++++ examples/StopWatch/README.md | 15 ++ examples/StopWatch/StopWatch.ctx.vhdl | 11 ++ examples/StopWatch/StopWatch.pkg.vhdl | 50 +++++++ examples/StopWatch/StopWatch.vhdl | 129 ++++++++++++++++++ examples/StopWatch/Utilities.ctx.vhdl | 12 ++ examples/StopWatch/Utilities.pkg.vhdl | 115 ++++++++++++++++ examples/StopWatch/seg7_Display.cfg.vhdl | 16 +++ examples/StopWatch/seg7_Display.vhdl | 92 +++++++++++++ examples/StopWatch/seg7_Encoder.vhdl | 42 ++++++ examples/StopWatch/sync_Bits.vhdl | 37 +++++ examples/StopWatch/toplevel.StopWatch.tb.vhdl | 59 ++++++++ examples/StopWatch/toplevel.StopWatch.vhdl | 120 ++++++++++++++++ 14 files changed, 817 insertions(+) create mode 100644 examples/StopWatch/Counter.vhdl create mode 100644 examples/StopWatch/Debouncer.vhdl create mode 100644 examples/StopWatch/README.md create mode 100644 examples/StopWatch/StopWatch.ctx.vhdl create mode 100644 examples/StopWatch/StopWatch.pkg.vhdl create mode 100644 examples/StopWatch/StopWatch.vhdl create mode 100644 examples/StopWatch/Utilities.ctx.vhdl create mode 100644 examples/StopWatch/Utilities.pkg.vhdl create mode 100644 examples/StopWatch/seg7_Display.cfg.vhdl create mode 100644 examples/StopWatch/seg7_Display.vhdl create mode 100644 examples/StopWatch/seg7_Encoder.vhdl create mode 100644 examples/StopWatch/sync_Bits.vhdl create mode 100644 examples/StopWatch/toplevel.StopWatch.tb.vhdl create mode 100644 examples/StopWatch/toplevel.StopWatch.vhdl diff --git a/examples/StopWatch/Counter.vhdl b/examples/StopWatch/Counter.vhdl new file mode 100644 index 0000000..b26a0fa --- /dev/null +++ b/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_pkg.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/examples/StopWatch/Debouncer.vhdl b/examples/StopWatch/Debouncer.vhdl new file mode 100644 index 0000000..2c4a013 --- /dev/null +++ b/examples/StopWatch/Debouncer.vhdl @@ -0,0 +1,74 @@ +-- 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; + +context work.Utilities_ctx; + + +entity Debouncer is + generic ( + CLOCK_PERIOD : time := 10 ns; + DEBOUNCE_TIME : time := 3 ms; + + BITS : positive; + INPUT_SYNC : boolean := true + ); + 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); + + signal Input_sync : Input'subtype; +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); + + genSync: if INPUT_SYNC generate + sync: entity work.sync_Bits + generic map ( + BITS => BITS + ) + port map ( + Clock => Clock, + Input => Input, + Output => Input_sync + ); + else generate + Input_sync <= Input; + end generate; + + 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/examples/StopWatch/README.md b/examples/StopWatch/README.md new file mode 100644 index 0000000..97fa026 --- /dev/null +++ b/examples/StopWatch/README.md @@ -0,0 +1,15 @@ +# StopWatch + +This is the project solution used in PLC2's 5-days class [**Professional VHDL**](https://www.plc2.com/en/training/detail/professional-vhdl). +It develops step by step a stop watch running on a **Digilent Nexys4 DDR** board +(new name *Nexys A7*). + +See https://github.com/PLC2/Solution-StopWatch for more details. + + +# License + +Licensed under [MIT License](LICENSE.md). + +--------------- +SPDX-License-Identifier: MIT diff --git a/examples/StopWatch/StopWatch.ctx.vhdl b/examples/StopWatch/StopWatch.ctx.vhdl new file mode 100644 index 0000000..dc89d5b --- /dev/null +++ b/examples/StopWatch/StopWatch.ctx.vhdl @@ -0,0 +1,11 @@ +-- Author: Patrick Lehmann +-- License: MIT +-- +-- undocumented +-- +context StopWatch_ctx is + library lib_Utilities; + context lib_Utilities.Utilities_ctx; + + use work.StopWatch_pkg.all; +end context; diff --git a/examples/StopWatch/StopWatch.pkg.vhdl b/examples/StopWatch/StopWatch.pkg.vhdl new file mode 100644 index 0000000..3755e45 --- /dev/null +++ b/examples/StopWatch/StopWatch.pkg.vhdl @@ -0,0 +1,50 @@ +-- 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 with stop watch specific types. +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; + + -- Encoder that translates from 4-bit binary (BCD) to 7-segment code. + -- + -- In addition, an optional dot input is supported. + component seg7_Encoder is + port ( + BCDValue : in T_BCD; + Dot : in std_logic := '0'; + + Seg7Code : out std_logic_vector(7 downto 0) + ); + end component; + + component 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 component; +end package; diff --git a/examples/StopWatch/StopWatch.vhdl b/examples/StopWatch/StopWatch.vhdl new file mode 100644 index 0000000..87a1478 --- /dev/null +++ b/examples/StopWatch/StopWatch.vhdl @@ -0,0 +1,129 @@ +-- 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_Utilities; +use lib_Utilities.Utilities_pkg.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 rtl 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 lib_Utilities.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 lib_Utilities.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/examples/StopWatch/Utilities.ctx.vhdl b/examples/StopWatch/Utilities.ctx.vhdl new file mode 100644 index 0000000..0506820 --- /dev/null +++ b/examples/StopWatch/Utilities.ctx.vhdl @@ -0,0 +1,12 @@ +-- Author: Patrick Lehmann +-- License: MIT +-- +-- undocumented +-- +context Utilities_ctx is + library IEEE; + use IEEE.std_logic_1164.all, + IEEE.numeric_std.all; + + use work.Utilities_pkg.all; +end context; diff --git a/examples/StopWatch/Utilities.pkg.vhdl b/examples/StopWatch/Utilities.pkg.vhdl new file mode 100644 index 0000000..6231261 --- /dev/null +++ b/examples/StopWatch/Utilities.pkg.vhdl @@ -0,0 +1,115 @@ +-- 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; + + +-- Useful utility functions and types. +package Utilities_pkg 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; + + component 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 component; +end package; + + +package body Utilities_pkg 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/examples/StopWatch/seg7_Display.cfg.vhdl b/examples/StopWatch/seg7_Display.cfg.vhdl new file mode 100644 index 0000000..63d0c5e --- /dev/null +++ b/examples/StopWatch/seg7_Display.cfg.vhdl @@ -0,0 +1,16 @@ +-- Author: Patrick Lehmann +-- License: MIT +-- +-- A generic counter module used in the StopWatch example. +-- +context work.StopWatch_ctx; + + +-- Encoder that translates from 4-bit binary (BCD) to 7-segment code. +configuration seg7_Display_cfg of seg7_Display is + for rtl + for enc : seg7_Encoder + use entity work.seg7_Encoder(rtl); + end for; + end for; +end configuration; diff --git a/examples/StopWatch/seg7_Display.vhdl b/examples/StopWatch/seg7_Display.vhdl new file mode 100644 index 0000000..6ed4eca --- /dev/null +++ b/examples/StopWatch/seg7_Display.vhdl @@ -0,0 +1,92 @@ +-- 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_Utilities; +use lib_Utilities.Utilities_pkg.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: component seg7_Encoder + port map ( + BCDValue => Digit, + Dot => Dot, + + Seg7Code => Seg7_Segments + ); + + + Seg7_Selects <= bin2onehot(Digit_Select, DIGITS); +end architecture; diff --git a/examples/StopWatch/seg7_Encoder.vhdl b/examples/StopWatch/seg7_Encoder.vhdl new file mode 100644 index 0000000..88074c8 --- /dev/null +++ b/examples/StopWatch/seg7_Encoder.vhdl @@ -0,0 +1,42 @@ +-- Author: Patrick Lehmann +-- License: MIT +-- +-- A generic counter module used in the StopWatch example. +-- +context work.StopWatch_ctx; + + +-- Encoder that translates from 4-bit binary (BCD) to 7-segment code. +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/examples/StopWatch/sync_Bits.vhdl b/examples/StopWatch/sync_Bits.vhdl new file mode 100644 index 0000000..499305e --- /dev/null +++ b/examples/StopWatch/sync_Bits.vhdl @@ -0,0 +1,37 @@ +-- Author: Patrick Lehmann +-- License: MIT +-- +-- A generic multi-FF synchronizer. +-- +library ieee; +use ieee.std_logic_1164.all; + + +-- Multi-stage FF synchronizer +entity sync_Bits is + generic ( + BITS : positive := 1; + STAGES : positive range 2 to 5 := 3 + ); + port ( + Clock : in std_logic; + + Input : in std_logic_vector(BITS - 1 downto 0); + output : in std_logic_vector(BITS - 1 downto 0) + ); +end entity; + + +architecture rtl of sync_Bits is + +begin + gen : for i in Input'range generate + signal meta : std_logic := '0'; + signal ffs : std_logic_vector(STAGES - 1 downto 1) := (others => '0'); + begin + meta <= Input(i) when rising_edge(Clock); + ffs <= (ffs(ffs'left downto 1) & meta) when rising_edge(Clock); + + Output(i) <= ffs(ffs'left); + end generate; +end architecture; diff --git a/examples/StopWatch/toplevel.StopWatch.tb.vhdl b/examples/StopWatch/toplevel.StopWatch.tb.vhdl new file mode 100644 index 0000000..87cd758 --- /dev/null +++ b/examples/StopWatch/toplevel.StopWatch.tb.vhdl @@ -0,0 +1,59 @@ +-- 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_Utilities; +use lib_Utilities.Utilities_pkg.all; + +use work.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/examples/StopWatch/toplevel.StopWatch.vhdl b/examples/StopWatch/toplevel.StopWatch.vhdl new file mode 100644 index 0000000..d23d75b --- /dev/null +++ b/examples/StopWatch/toplevel.StopWatch.vhdl @@ -0,0 +1,120 @@ +-- 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_Utilities; +use lib_Utilities.Utilities_pkg.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: component 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: /* configuration */ seg7_Display--_cfg + 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; From 695993b4cca5355378e606605746f12d132d01eb Mon Sep 17 00:00:00 2001 From: Patrick Lehmann Date: Tue, 17 Jan 2023 01:37:12 +0100 Subject: [PATCH 04/16] Not nice, but a first output is printed. --- VHDLDomain/Index.py | 19 +++++++++++++++++-- VHDLDomain/__init__.py | 4 +++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/VHDLDomain/Index.py b/VHDLDomain/Index.py index eb22202..6b14101 100644 --- a/VHDLDomain/Index.py +++ b/VHDLDomain/Index.py @@ -1,9 +1,15 @@ from typing import Iterable, Optional as Nullable, List, Tuple +from pyGHDL.dom.NonStandard import Design from pyTooling.Decorators import export +from pyVHDLModel import DesignUnitKind from sphinx.domains import Index, IndexEntry +class DUMMY: + VAR = None + + @export class ComponentIndex(Index): """ @@ -17,8 +23,17 @@ class ComponentIndex(Index): def generate(self, docnames: Iterable[str] = None) -> Tuple[List[Tuple[str, List[IndexEntry]]], bool]: result: List[Tuple[str, List[IndexEntry]]] = [] - entry = ("Counter", 0, "lib_Utilities/Counter", "lib_Utilities-Counter", "lib_Utilities/Counter", "", "A generic counter.") - group = ("C", [entry]) + entries = [] + + design: Design = DUMMY.VAR + for entity in design.IterateDesignUnits(DesignUnitKind.Entity): + entryName = entity.Identifier + entryKind = 0 + document = f"{entity.Library.Identifier}/{entity.Identifier}" + link = f"{entity.Library.Identifier}-{entity.Identifier}" + entries.append((entryName, entryKind, document, link, document, "", entity.Documentation)) + + group = ("C", entries) result.append(group) diff --git a/VHDLDomain/__init__.py b/VHDLDomain/__init__.py index bab1d47..fa7a9f7 100644 --- a/VHDLDomain/__init__.py +++ b/VHDLDomain/__init__.py @@ -50,7 +50,7 @@ from sphinx.application import Sphinx from sphinx.domains import Domain -from VHDLDomain.Index import ComponentIndex, PackageIndex, SubprogramIndex, TypeIndex +from VHDLDomain.Index import ComponentIndex, PackageIndex, SubprogramIndex, TypeIndex, DUMMY class VHDLDomain(Domain): @@ -109,6 +109,8 @@ def setup(sphinxApplication: Sphinx): design.AddDocument(document, design.GetLibrary(libraryName)) print("-" * 40) design.Analyze() + + DUMMY.VAR = design print("=" * 40) return { From 9e47df68b324d754048ec5d35077ad86fe1a77b5 Mon Sep 17 00:00:00 2001 From: Patrick Lehmann Date: Sun, 22 Jan 2023 21:04:48 +0100 Subject: [PATCH 05/16] Some updates. --- VHDLDomain/Directive.py | 180 ++++++++++++++++++++++++++++++++ VHDLDomain/Index.py | 59 +++++++---- VHDLDomain/Role.py | 121 +++++++++++++++++++++ VHDLDomain/__init__.py | 81 ++++++++++++-- examples/StopWatch/Counter.vhdl | 19 ++++ 5 files changed, 432 insertions(+), 28 deletions(-) create mode 100644 VHDLDomain/Directive.py create mode 100644 VHDLDomain/Role.py diff --git a/VHDLDomain/Directive.py b/VHDLDomain/Directive.py new file mode 100644 index 0000000..ed58e23 --- /dev/null +++ b/VHDLDomain/Directive.py @@ -0,0 +1,180 @@ +from typing import List + +from docutils import nodes +from pyTooling.Decorators import export +from sphinx.directives import ObjectDescription + + +@export +class BaseDirective(ObjectDescription): + has_content: bool = False + """ + A boolean; ``True`` if content is allowed. + + Client code must handle the case where content is required but not supplied (an empty content list will be supplied). + """ + + required_arguments = 0 + """Number of required directive arguments.""" + + optional_arguments = 0 + """Number of optional arguments after the required arguments.""" + + final_argument_whitespace = False + """A boolean, indicating if the final argument may contain whitespace.""" + + option_spec = None + """ + Mapping of option names to validator functions. + + A dictionary, mapping known option names to conversion functions such as :py:class:`int` or :py:class:`float` + (default: {}, no options). Several conversion functions are defined in the ``directives/__init__.py`` module. + + Option conversion functions take a single parameter, the option argument (a string or :py:class:`None`), validate it + and/or convert it to the appropriate form. Conversion functions may raise :py:exc:`ValueError` and + :py:exc:`TypeError` exceptions. + """ + + +@export +class DescribeDesign(BaseDirective): + """ + This directive will be replaced by the description of a VHDL design. + """ + + has_content = False + required_arguments = 0 + optional_arguments = 0 + + def run(self) -> List: + paragraph = nodes.paragraph(text="Describe design") + + return [paragraph] + + +@export +class DescribeLibrary(BaseDirective): + """ + This directive will be replaced by the description of a VHDL library. + """ + + has_content = False + required_arguments = 0 + optional_arguments = 0 + + def run(self) -> List: + paragraph = nodes.paragraph(text="Describe library") + + return [paragraph] + + +@export +class DescribeDocument(BaseDirective): + """ + This directive will be replaced by the description of a VHDL document. + """ + + has_content = False + required_arguments = 0 + optional_arguments = 0 + + def run(self) -> List: + paragraph = nodes.paragraph(text="Describe document") + + return [paragraph] + + +@export +class DescribeContext(BaseDirective): + """ + This directive will be replaced by the description of a VHDL context. + """ + + has_content = False + required_arguments = 0 + optional_arguments = 0 + + def run(self) -> List: + paragraph = nodes.paragraph(text="Describe context") + + return [paragraph] + + +@export +class DescribeEntity(BaseDirective): + """ + This directive will be replaced by the description of a VHDL entity. + """ + + has_content = False + required_arguments = 0 + optional_arguments = 0 + + def run(self) -> List: + paragraph = nodes.paragraph(text="Describe entity") + + return [paragraph] + + +@export +class DescribeArchitecture(BaseDirective): + """ + This directive will be replaced by the description of a VHDL architecture. + """ + + has_content = False + required_arguments = 0 + optional_arguments = 0 + + def run(self) -> List: + paragraph = nodes.paragraph(text="Describe architecture") + + return [paragraph] + + +@export +class DescribePackage(BaseDirective): + """ + This directive will be replaced by the description of a VHDL package. + """ + + has_content = False + required_arguments = 0 + optional_arguments = 0 + + def run(self) -> List: + paragraph = nodes.paragraph(text="Describe package") + + return [paragraph] + + +@export +class DescribePackageBody(BaseDirective): + """ + This directive will be replaced by the description of a VHDL package body. + """ + + has_content = False + required_arguments = 0 + optional_arguments = 0 + + def run(self) -> List: + paragraph = nodes.paragraph(text="Describe package body") + + return [paragraph] + + +@export +class DescribeConfiguration(BaseDirective): + """ + This directive will be replaced by the description of a VHDL configuration. + """ + + has_content = False + required_arguments = 0 + optional_arguments = 0 + + def run(self) -> List: + paragraph = nodes.paragraph(text="Describe configuration") + + return [paragraph] diff --git a/VHDLDomain/Index.py b/VHDLDomain/Index.py index 6b14101..053d982 100644 --- a/VHDLDomain/Index.py +++ b/VHDLDomain/Index.py @@ -6,12 +6,13 @@ from sphinx.domains import Index, IndexEntry -class DUMMY: - VAR = None +@export +class BaseIndex(Index): + pass @export -class ComponentIndex(Index): +class ComponentIndex(BaseIndex): """ An index for VHDL components. """ @@ -23,25 +24,31 @@ class ComponentIndex(Index): def generate(self, docnames: Iterable[str] = None) -> Tuple[List[Tuple[str, List[IndexEntry]]], bool]: result: List[Tuple[str, List[IndexEntry]]] = [] - entries = [] - design: Design = DUMMY.VAR - for entity in design.IterateDesignUnits(DesignUnitKind.Entity): - entryName = entity.Identifier - entryKind = 0 - document = f"{entity.Library.Identifier}/{entity.Identifier}" - link = f"{entity.Library.Identifier}-{entity.Identifier}" - entries.append((entryName, entryKind, document, link, document, "", entity.Documentation)) - - group = ("C", entries) - - result.append(group) + for library in design.Libraries.values(): + entries = [] + for entity in library.Entities.values(): + entryName = entity.Identifier + entryKind = 0 if len(entity.Architectures) == 1 else 1 + document = f"{entity.Library.Identifier}/{entity.Identifier}" + link = f"{entity.Library.Identifier}-{entity.Identifier}" + entries.append((entryName, entryKind, document, link, document, "", entity.Documentation)) + if entryKind == 1: + for architecture in entity.Architectures.values(): + architectureName = architecture.Identifier + architectureKind = 2 + doc = f"{entity.Library.Identifier}/{entity.Identifier}-{architecture.Identifier}" + lnk = f"{entity.Library.Identifier}-{entity.Identifier}-{architecture.Identifier}" + entries.append((architectureName, architectureKind, doc, lnk, doc, "", architecture.Documentation)) + + group = (library.Identifier, entries) + result.append(group) return result, True @export -class PackageIndex(Index): +class PackageIndex(BaseIndex): """ An index for VHDL packages. """ @@ -53,16 +60,24 @@ class PackageIndex(Index): def generate(self, docnames: Iterable[str] = None) -> Tuple[List[Tuple[str, List[IndexEntry]]], bool]: result: List[Tuple[str, List[IndexEntry]]] = [] - entry = ("Utilities", 0, "lib_Utilities/Utilities", "lib_Utilities-Utilities", "lib_Utilities/Utilities", "", "A collection of utilities.") - group = ("U", [entry]) - - result.append(group) + design: Design = DUMMY.VAR + for library in design.Libraries.values(): + entries = [] + for package in library.Packages.values(): + entryName = package.Identifier + entryKind = 0 + document = f"{package.Library.Identifier}/{package.Identifier}" + link = f"{package.Library.Identifier}-{package.Identifier}" + entries.append((entryName, entryKind, document, link, document, "", package.Documentation)) + + group = (library.Identifier, entries) + result.append(group) return result, True @export -class SubprogramIndex(Index): +class SubprogramIndex(BaseIndex): """ An index for VHDL functions or procedures. """ @@ -83,7 +98,7 @@ def generate(self, docnames: Iterable[str] = None) -> Tuple[List[Tuple[str, List @export -class TypeIndex(Index): +class TypeIndex(BaseIndex): """ An index for types and subtypes in VHDL. """ diff --git a/VHDLDomain/Role.py b/VHDLDomain/Role.py new file mode 100644 index 0000000..6457d92 --- /dev/null +++ b/VHDLDomain/Role.py @@ -0,0 +1,121 @@ +from pyTooling.Decorators import export +from sphinx.roles import XRefRole + + +@export +class DesignRole(XRefRole): + """ + This role will reference a VHDL design. + """ + + +@export +class LibraryRole(XRefRole): + """ + This role will reference a VHDL library. + """ + + +@export +class DocumentRole(XRefRole): + """ + This role will reference a VHDL document. + """ + + +@export +class ContextRole(XRefRole): + """ + This role will reference a context. + """ + + +@export +class EntityRole(XRefRole): + """ + This role will reference a entity. + """ + + +@export +class ArchitectureRole(XRefRole): + """ + This role will reference an architecture. + """ + + +@export +class ComponentRole(XRefRole): + """ + This role will reference a component. + """ + + +@export +class PackageRole(XRefRole): + """ + This role will reference a package. + """ + + +@export +class PackageBodyRole(XRefRole): + """ + This role will reference a package body. + """ + + +@export +class ConfigurationRole(XRefRole): + """ + This role will reference a configuration. + """ + + +@export +class TypeRole(XRefRole): + """ + This role will reference a type. + """ + + +@export +class FunctionRole(XRefRole): + """ + This role will reference a function. + """ + + +@export +class ProcedureRole(XRefRole): + """ + This role will reference a procedure. + """ + + +@export +class ConstantRole(XRefRole): + """ + This role will reference a constant. + """ + + +@export +class GenericRole(XRefRole): + """ + This role will reference a generic. + """ + + +@export +class PortRole(XRefRole): + """ + This role will reference a port. + """ + + +@export +class ParameterRole(XRefRole): + """ + This role will reference a parameter. + """ diff --git a/VHDLDomain/__init__.py b/VHDLDomain/__init__.py index fa7a9f7..36b57b0 100644 --- a/VHDLDomain/__init__.py +++ b/VHDLDomain/__init__.py @@ -45,31 +45,100 @@ __version__ = "0.1.0" from pathlib import Path +from typing import Dict, Tuple, Any, Optional as Nullable +from docutils import nodes from pyGHDL.dom.NonStandard import Design, Document +from sphinx.addnodes import pending_xref from sphinx.application import Sphinx from sphinx.domains import Domain +from VHDLDomain.Directive import DescribeDesign, DescribeLibrary, DescribeDocument, DescribeEntity, DescribeArchitecture +from VHDLDomain.Directive import DescribePackage, DescribePackageBody, DescribeConfiguration, DescribeContext from VHDLDomain.Index import ComponentIndex, PackageIndex, SubprogramIndex, TypeIndex, DUMMY +from VHDLDomain.Role import DesignRole, LibraryRole, DocumentRole, ContextRole, EntityRole, ArchitectureRole, PackageRole, PackageBodyRole, ConfigurationRole class VHDLDomain(Domain): - name = "vhdl" - label = "VHDL" - initial_data = {} - directives = {} - roles = {} + name = "vhdl" #: The name of this domain + label = "VHDL" #: The label of this domain + + dependencies = [ + ] #: A list of other extensions this domain depends on. + + directives = { + # "describedesign": DescribeDesign, + "describelibrary": DescribeLibrary, + # "describedocument": DescribeDocument, + # "describecontext": DescribeContext, + "describeentity": DescribeEntity, + # "describearchitecture": DescribeArchitecture, + # "describepackage": DescribePackage, + # "describepackagebody": DescribePackageBody, + # "describeconfiguration": DescribeConfiguration, + } #: A dictionary of all directives in this domain. + + roles = { + # "design": DesignRole, + # "lib": LibraryRole, + # "doc": DocumentRole, + # "ctx": ContextRole, + "ent": EntityRole, + # "arch": ArchitectureRole, + # "pack": PackageRole, + # "packbody": PackageBodyRole, + # "config": ConfigurationRole, + } #: A dictionary of all roles in this domain. + indices = { ComponentIndex, PackageIndex, SubprogramIndex, TypeIndex + } #: A dictionary of all indices in this domain. + + configValues: Dict[str, Tuple[Any, str, Any]] = { + "designs": ({}, "env", Dict), + } #: A dictionary of all configuration values used by this domain. + + initial_data = { } + @staticmethod + def ReadDesigns(app: Sphinx, docname: str, source: str) -> None: + print(f"Callback: source-read -> ReadDesigns") + print(docname) +# print(source) + + callbacks = { + "source-read": ReadDesigns + } #: A dictionary of all callbacks used by this domain. + + def resolve_xref( + self, + env: 'BuildEnvironment', + fromdocname: str, + builder: 'Builder', + typ: str, + target: str, + node: pending_xref, + contnode: nodes.Element + ) -> Nullable[nodes.Element]: + raise NotImplementedError() + def setup(sphinxApplication: Sphinx): + """ + Extension setup function registering the VHDL domain in Sphinx. + + :param sphinxApplication: The Sphinx application. + :return: Dictionary containing the extension version and some properties. + """ sphinxApplication.add_domain(VHDLDomain) - # sphinxApplication.add_config_value('vhdl_autodoc_source_path', '.', 'env', [str]) + for eventName, callback in VHDLDomain.callbacks.items(): + sphinxApplication.connect(eventName, callback) + for configName, (configDefault, configRebuilt, configTypes) in VHDLDomain.configValues.items(): + sphinxApplication.add_config_value(f"{VHDLDomain.name}_{configName}", configDefault, configRebuilt, configTypes) _packageFiles = ( ("lib_Utilities", Path("Utilities.pkg.vhdl")), diff --git a/examples/StopWatch/Counter.vhdl b/examples/StopWatch/Counter.vhdl index b26a0fa..fe7aeb2 100644 --- a/examples/StopWatch/Counter.vhdl +++ b/examples/StopWatch/Counter.vhdl @@ -43,3 +43,22 @@ begin Value <= resize(CounterValue, BITS); WrapAround <= Enable when (CounterValue = MODULO - 1) else '0'; end architecture; + + +architecture sim 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; From bb2257716ee1483032d5c7eb994a769065a9e250 Mon Sep 17 00:00:00 2001 From: Patrick Lehmann Date: Mon, 23 Jan 2023 02:35:42 +0100 Subject: [PATCH 06/16] Added project dependency in PyCharm. --- .idea/VHDLDomain.iml | 1 + doc/Configuration/index.rst | 0 2 files changed, 1 insertion(+) create mode 100644 doc/Configuration/index.rst diff --git a/.idea/VHDLDomain.iml b/.idea/VHDLDomain.iml index d13f6da..72f95c6 100644 --- a/.idea/VHDLDomain.iml +++ b/.idea/VHDLDomain.iml @@ -9,6 +9,7 @@ +