From 8d516ea4b413b43ac5b346c56080b7e0a2a26adb Mon Sep 17 00:00:00 2001 From: Patrick Lehmann Date: Mon, 4 Oct 2021 02:49:45 +0200 Subject: [PATCH 01/34] Bumped version to v0.1.1. --- doc/conf.py | 2 +- pyEDAA/ProjectModel/__init__.py | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index f1d75cc0..3f82ec9d 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -37,7 +37,7 @@ def _LatestTagName(): # The full version, including alpha/beta/rc tags version = "0.1" # The short X.Y version. -release = "0.1.0" # The full version, including alpha/beta/rc tags. +release = "0.1.1" # The full version, including alpha/beta/rc tags. try: if _IsUnderGitControl: latestTagName = _LatestTagName()[1:] # remove prefix "v" diff --git a/pyEDAA/ProjectModel/__init__.py b/pyEDAA/ProjectModel/__init__.py index e2e981c5..5e2fabf5 100644 --- a/pyEDAA/ProjectModel/__init__.py +++ b/pyEDAA/ProjectModel/__init__.py @@ -39,7 +39,7 @@ from pydecor import export -__version__ = "0.1.0" +__version__ = "0.1.1" class FileType(type): diff --git a/setup.py b/setup.py index eef6bd8c..c4e269de 100644 --- a/setup.py +++ b/setup.py @@ -40,7 +40,7 @@ gitHubNamespace = "edaa-org" projectName = "ProjectModel" projectNameWithPrefix = "pyEDAA." + projectName -version = "0.1.0" +version = "0.1.1" # Read README for upload to PyPI readmeFile = Path("README.md") From 9a4ece018a58a40717bfd26a092e58f0d6ace094 Mon Sep 17 00:00:00 2001 From: Patrick Lehmann Date: Mon, 4 Oct 2021 03:09:13 +0200 Subject: [PATCH 02/34] Fixed some shields in README. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 554410cc..72cfffb4 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -[![Sourcecode on GitHub](https://img.shields.io/badge/edaa-org-pyEDAA.ProjectModel-323131.svg?logo=github&longCache=true)](https://github.com/edaa-org/pyEDAA.ProjectModel) -[![Sourcecode License](https://img.shields.io/pypi/l/pyEDAA.ProjectModel?logo=GitHub&label=code%20license)](LICENSE.md) +[![Sourcecode on GitHub](https://img.shields.io/badge/edaa--org-pyEDAA.ProjectModel-323131.svg?logo=github&longCache=true)](https://github.com/edaa-org/pyEDAA.ProjectModel) +[![Sourcecode License](https://img.shields.io/pypi/l/pyEDAA.ProjectModel?logo=Github&label=code%20license)](LICENSE.md) [![GitHub tag (latest SemVer incl. pre-release)](https://img.shields.io/github/v/tag/edaa-org/pyEDAA.ProjectModel?logo=GitHub&include_prereleases)](https://github.com/edaa-org/pyEDAA.ProjectModel/tags) [![GitHub release (latest SemVer incl. including pre-releases)](https://img.shields.io/github/v/release/edaa-org/pyEDAA.ProjectModel?logo=GitHub&include_prereleases)](https://github.com/edaa-org/pyEDAA.ProjectModel/releases/latest) [![GitHub release date](https://img.shields.io/github/release-date/edaa-org/pyEDAA.ProjectModel?logo=GitHub&)](https://github.com/edaa-org/pyEDAA.ProjectModel/releases) From f9c6c5db54dd695c56ff80beae2d4677564c684f Mon Sep 17 00:00:00 2001 From: Patrick Lehmann Date: Mon, 4 Oct 2021 20:32:21 +0200 Subject: [PATCH 03/34] Test code snippet in README. --- .github/workflows/Pipeline.yml | 53 ++++++++++++++++++++++++++++++++-- README.md | 4 +++ tests/docs/.gitempty | 0 3 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 tests/docs/.gitempty diff --git a/.github/workflows/Pipeline.yml b/.github/workflows/Pipeline.yml index b9396674..c80c46a1 100644 --- a/.github/workflows/Pipeline.yml +++ b/.github/workflows/Pipeline.yml @@ -282,12 +282,61 @@ jobs: run: | twine upload dist/* + VerifyDocs: + name: 👍 Verify example snippets using Python 3.9 + runs-on: ubuntu-latest + + env: + PYTHON: 3.9 + outputs: + python: ${{ env.PYTHON }} + + steps: + - name: ⏬ Checkout repository + uses: actions/checkout@v2 + + - name: 🐍 Setup Python + uses: actions/setup-python@v2 + with: + python-version: ${{ env.PYTHON }} + + - name: 🐍 Install dependencies + run: | + pip3 install . + + - 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: name: 📓 Run BuildTheDocs and publish to GH-Pages runs-on: ubuntu-latest + needs: + - VerifyDocs -# needs: -# - VerifyDocs env: ARTIFACT: pyEDAA-ProjectModel-documentation outputs: diff --git a/README.md b/README.md index 72cfffb4..e4d28e7b 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,10 @@ fileset = FileSet("uart", Path("src/uart"), design=design) for vhdlFilePath in fileset.ResolvedPath.glob("*.vhdl"): vhdlFile = VHDLSourceFile(vhdlFilePath) fileset.AddFile(vhdlFile) + +print(f"All VHDL files in {project.Name}:") +#for file in project.Designs["design"].Files(fileType=VHDLSourceFile): +# print(f" {file.Path}") ``` diff --git a/tests/docs/.gitempty b/tests/docs/.gitempty new file mode 100644 index 00000000..e69de29b From df57ab219e14c5998b6dee270ec06ee4bdbb9bd3 Mon Sep 17 00:00:00 2001 From: Patrick Lehmann Date: Tue, 5 Oct 2021 07:21:08 +0200 Subject: [PATCH 04/34] Improved API. --- README.md | 4 ++-- pyEDAA/ProjectModel/__init__.py | 19 +++++++++++++++++++ tests/project/designA/file_A1.vhdl | 0 tests/project/designA/file_A2.vhdl | 0 tests/project/designA/file_A3.v | 0 tests/project/designB/file_B1.vhdl | 0 tests/project/lib/file1.vhdl | 0 tests/unit/Design.py | 8 +++++--- tests/unit/FileSet.py | 6 ++++-- tests/unit/Project.py | 2 +- 10 files changed, 31 insertions(+), 8 deletions(-) create mode 100644 tests/project/designA/file_A1.vhdl create mode 100644 tests/project/designA/file_A2.vhdl create mode 100644 tests/project/designA/file_A3.v create mode 100644 tests/project/designB/file_B1.vhdl create mode 100644 tests/project/lib/file1.vhdl diff --git a/README.md b/README.md index e4d28e7b..968a8fc4 100644 --- a/README.md +++ b/README.md @@ -46,8 +46,8 @@ for vhdlFilePath in fileset.ResolvedPath.glob("*.vhdl"): fileset.AddFile(vhdlFile) print(f"All VHDL files in {project.Name}:") -#for file in project.Designs["design"].Files(fileType=VHDLSourceFile): -# print(f" {file.Path}") +for file in project["design"].Files(fileType=VHDLSourceFile): + print(f" {file.Path}") ``` diff --git a/pyEDAA/ProjectModel/__init__.py b/pyEDAA/ProjectModel/__init__.py index 5e2fabf5..33ae31bb 100644 --- a/pyEDAA/ProjectModel/__init__.py +++ b/pyEDAA/ProjectModel/__init__.py @@ -638,6 +638,9 @@ def SVVersion(self) -> SystemVerilogVersion: def SVVersion(self, value: SystemVerilogVersion) -> None: self._svVersion = value + def __str__(self): + return self._name + @export class VHDLLibrary: @@ -718,6 +721,9 @@ def VHDLVersion(self) -> VHDLVersion: def VHDLVersion(self, value: VHDLVersion) -> None: self._vhdlVersion = value + def __str__(self): + return self._name + @export class Design: @@ -755,6 +761,8 @@ def __init__( ): self._name = name self._project = project + if project is not None: + project._designs[name] = self self._directory = directory self._fileSets = {} self._defaultFileSet = FileSet("default", project=project, design=self) @@ -814,6 +822,8 @@ def DefaultFileSet(self, value: Union[str, FileSet]) -> None: else: raise ValueError("Unsupported parameter type for 'value'.") + def __getitem__(self, name: str): + return self._fileSets[name] # TODO: return generator with another method @property @@ -909,6 +919,9 @@ def AddFiles(self, files: Iterable[File]) -> None: for file in files: self.AddFile(file) + def __str__(self): + return self._name + @export class Project: @@ -961,6 +974,9 @@ def ResolvedPath(self) -> Path: else: return path.relative_to(Path.cwd()) + def __getitem__(self, name: str): + return self._designs[name] + # TODO: return generator with another method @property def Designs(self) -> Dict[str, Design]: @@ -992,3 +1008,6 @@ def SVVersion(self) -> SystemVerilogVersion: @SVVersion.setter def SVVersion(self, value: SystemVerilogVersion) -> None: self._svVersion = value + + def __str__(self): + return self._name diff --git a/tests/project/designA/file_A1.vhdl b/tests/project/designA/file_A1.vhdl new file mode 100644 index 00000000..e69de29b diff --git a/tests/project/designA/file_A2.vhdl b/tests/project/designA/file_A2.vhdl new file mode 100644 index 00000000..e69de29b diff --git a/tests/project/designA/file_A3.v b/tests/project/designA/file_A3.v new file mode 100644 index 00000000..e69de29b diff --git a/tests/project/designB/file_B1.vhdl b/tests/project/designB/file_B1.vhdl new file mode 100644 index 00000000..e69de29b diff --git a/tests/project/lib/file1.vhdl b/tests/project/lib/file1.vhdl new file mode 100644 index 00000000..e69de29b diff --git a/tests/unit/Design.py b/tests/unit/Design.py index 18a85b46..d1478c35 100644 --- a/tests/unit/Design.py +++ b/tests/unit/Design.py @@ -59,9 +59,11 @@ def test_Design(self): def test_WithProject(self): project = Project("project") - design = Design("design", project=project) + designName = "design" + design = Design(designName, project=project) self.assertIs(project, design.Project) + self.assertIs(design, project[designName]) def test_WithVersions(self): vhdlVersion = VHDLVersion.VHDL2019 @@ -93,8 +95,8 @@ def test_SetDirectoryLater(self): self.assertIs(directory, design.Directory) def test_ResolveDirectory(self): - projectDirectoryPath = Path.cwd() / "temp/project" - designDirectory = "design" + projectDirectoryPath = Path.cwd() / "project" + designDirectory = "designA" project = Project("project", projectDirectoryPath) design = Design("design", Path(designDirectory), project=project) diff --git a/tests/unit/FileSet.py b/tests/unit/FileSet.py index bfe329b6..4fd62330 100644 --- a/tests/unit/FileSet.py +++ b/tests/unit/FileSet.py @@ -56,11 +56,13 @@ def test_FileSet(self): def test_WithDesign(self): design = Design("design") - fileset = FileSet("fileset", design=design) + filesetName = "fileset" + fileset = FileSet(filesetName, design=design) self.assertIsNotNone(fileset) - self.assertEqual("fileset", fileset.Name) + self.assertEqual(filesetName, fileset.Name) self.assertIs(design, fileset.Design) + self.assertIs(fileset, design[filesetName]) self.assertEqual(0, len(fileset._files)) def test_WithProject(self): diff --git a/tests/unit/Project.py b/tests/unit/Project.py index d193b3e9..cff023b1 100644 --- a/tests/unit/Project.py +++ b/tests/unit/Project.py @@ -57,7 +57,7 @@ def test_Project(self): self.assertIsNone(project.SVVersion) # now assign a root directory and check it - rootDirectoryPath = Path.cwd() / "temp/project" + rootDirectoryPath = Path.cwd() / "project" rootDirectory = rootDirectoryPath.as_posix() project.RootDirectory = rootDirectoryPath self.assertIs(rootDirectoryPath, project.RootDirectory) From 35c921240f63d988c0bc87c309ed6a3f36f9a295 Mon Sep 17 00:00:00 2001 From: Patrick Lehmann Date: Tue, 5 Oct 2021 07:31:20 +0200 Subject: [PATCH 05/34] Improved example in README. --- README.md | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 968a8fc4..299d4a27 100644 --- a/README.md +++ b/README.md @@ -31,22 +31,26 @@ ## Examples - ```python from pathlib import Path from pyEDAA.ProjectModel import Project, Design, FileSet, VHDLSourceFile -projectPath = Path("temp/project") -project = Project("project", rootDirectory=projectPath) -design = Design("design", project=project) -fileset = FileSet("uart", Path("src/uart"), design=design) +print(f"Current working directory: {Path.cwd()}") +projectDirectory = Path.cwd() / "../project" +print(f"Project directory: {projectDirectory!s} - {projectDirectory.exists()}") + +project = Project("myProject", rootDirectory=projectDirectory) +designA = Design("designA", project=project, directory=Path("designA")) +designAFileset = FileSet("srcA", design=designA) +for vhdlFilePath in designAFileset.ResolvedPath.glob("*.vhdl"): + designAFileset.AddFile(VHDLSourceFile(vhdlFilePath)) -for vhdlFilePath in fileset.ResolvedPath.glob("*.vhdl"): - vhdlFile = VHDLSourceFile(vhdlFilePath) - fileset.AddFile(vhdlFile) +libFileset = FileSet("lib", Path("../lib"), design=designA) +for vhdlFilePath in libFileset.ResolvedPath.glob("*.vhdl"): + libFileset.AddFile(VHDLSourceFile(vhdlFilePath)) -print(f"All VHDL files in {project.Name}:") -for file in project["design"].Files(fileType=VHDLSourceFile): +print(f"All VHDL files in {designA.Name}:") +for file in designA.Files(fileType=VHDLSourceFile): print(f" {file.Path}") ``` From 7525e0f7a888fc5eb8dc14a211fdeaa38dfce115 Mon Sep 17 00:00:00 2001 From: Patrick Lehmann Date: Tue, 5 Oct 2021 23:45:20 +0200 Subject: [PATCH 06/34] Fixed resolved path methods on Windows. --- pyEDAA/ProjectModel/__init__.py | 19 +++++++++++++++---- tests/unit/File.py | 11 +++++++++++ tests/unit/FileSet.py | 14 +++++++------- tests/unit/Project.py | 7 +++++++ 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/pyEDAA/ProjectModel/__init__.py b/pyEDAA/ProjectModel/__init__.py index 33ae31bb..e32b8f24 100644 --- a/pyEDAA/ProjectModel/__init__.py +++ b/pyEDAA/ProjectModel/__init__.py @@ -136,8 +136,12 @@ def ResolvedPath(self) -> Path: if self._path.is_absolute(): return self._path.resolve() elif self._fileSet is not None: - path = (self._fileSet.ResolvedPath / self._directory).resolve() - return path.relative_to(Path.cwd()) + path = (self._fileSet.ResolvedPath / self._path).resolve() + + if path.is_absolute(): + return path + else: + return path.relative_to(Path.cwd()) else: # TODO: message and exception type raise Exception("") @@ -534,7 +538,10 @@ def ResolvedPath(self) -> Path: raise Exception("") directory = (directory / self._directory).resolve() - return directory.relative_to(Path.cwd()) + if directory.is_absolute(): + return directory + else: + return directory.relative_to(Path.cwd()) @property def Parent(self) -> Nullable['FileSet']: @@ -798,7 +805,11 @@ def ResolvedPath(self) -> Path: return self._directory.resolve() elif self._project is not None: path = (self._project.ResolvedPath / self._directory).resolve() - return path.relative_to(Path.cwd()) + + if path.is_absolute(): + return path + else: + return path.relative_to(Path.cwd()) else: # TODO: message and exception type raise Exception("") diff --git a/tests/unit/File.py b/tests/unit/File.py index 440455cd..2ab2b983 100644 --- a/tests/unit/File.py +++ b/tests/unit/File.py @@ -114,3 +114,14 @@ def test_SetDesignWithProjectLater(self): self.assertIs(project, file.Project) self.assertIs(design, file.Design) + + def test_ResolveDirectory(self): + projectDirectoryPath = Path.cwd() / "project" + designDirectory = "designA" + filePath = "file_A1.vhdl" + + project = Project("project", projectDirectoryPath) + design = Design("design", Path(designDirectory), project=project) + file = File(Path(filePath), design=design) + + self.assertEqual(f"{projectDirectoryPath.as_posix()}/{designDirectory}/{filePath}", file.ResolvedPath.as_posix()) diff --git a/tests/unit/FileSet.py b/tests/unit/FileSet.py index 4fd62330..27d35b8e 100644 --- a/tests/unit/FileSet.py +++ b/tests/unit/FileSet.py @@ -99,15 +99,15 @@ def test_SetDirectoryLater(self): self.assertIs(path, fileset.Directory) def test_ResolveDirectory(self): - projectPath = Path("temp/project") - designPath = Path("design") - filesetPath = Path("fileset") + projectDirectoryPath = Path.cwd() / "project" + designDirectory = "designA" + filesetDirectoy = "fileset" - project = Project("project", projectPath) - design = Design("design", directory=designPath, project=project) - fileset = FileSet("fileset", directory=filesetPath, design=design) + project = Project("project", projectDirectoryPath) + design = Design("design", directory=Path(designDirectory), project=project) + fileset = FileSet("fileset", directory=Path(filesetDirectoy), design=design) - self.assertEqual(projectPath / designPath / filesetPath, fileset.ResolvedPath) + self.assertEqual(f"{projectDirectoryPath.as_posix()}/{designDirectory}/{filesetDirectoy}", fileset.ResolvedPath.as_posix()) def test_SetProjectLater(self): project = Project("project") diff --git a/tests/unit/Project.py b/tests/unit/Project.py index cff023b1..d0a1cbcb 100644 --- a/tests/unit/Project.py +++ b/tests/unit/Project.py @@ -98,3 +98,10 @@ def test_SetVersionsLater(self): self.assertEqual(vhdlVersion, project.VHDLVersion) self.assertEqual(verilogVersion, project.VerilogVersion) self.assertEqual(svVersion, project.SVVersion) + + def test_ResolveDirectory(self): + projectDirectoryPath = Path.cwd() / "project" + + project = Project("project", projectDirectoryPath) + + self.assertEqual(projectDirectoryPath.as_posix(), project.ResolvedPath.as_posix()) From 875aa06c85e38d6763814b424fc497d90342d1f4 Mon Sep 17 00:00:00 2001 From: Patrick Lehmann Date: Wed, 6 Oct 2021 07:18:43 +0200 Subject: [PATCH 07/34] Fixed Codacy ID for shields. Fixes #5. --- README.md | 4 ++-- doc/shields.inc | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 299d4a27..daa0e960 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ [![GitHub release date](https://img.shields.io/github/release-date/edaa-org/pyEDAA.ProjectModel?logo=GitHub&)](https://github.com/edaa-org/pyEDAA.ProjectModel/releases) [![Dependent repos (via libraries.io)](https://img.shields.io/librariesio/dependent-repos/pypi/pyEDAA.ProjectModel?logo=GitHub)](https://github.com/edaa-org/pyEDAA.ProjectModel/network/dependents) [![GitHub Workflow - Build and Test Status](https://img.shields.io/github/workflow/status/edaa-org/pyEDAA.ProjectModel/Test%20and%20Coverage?label=build%20and%20test&logo=GitHub%20Actions&logoColor=FFFFFF)](https://github.com/edaa-org/pyEDAA.ProjectModel/actions?query=workflow%3A%22Test+and+Coverage%22) -[![Codacy - Quality](https://img.shields.io/codacy/grade/2286426d2b11417e90010427b7fed8e7?logo=Codacy)](https://www.codacy.com/manual/edaa-org/pyEDAA.ProjectModel) -[![Codacy - Coverage](https://img.shields.io/codacy/coverage/2286426d2b11417e90010427b7fed8e7?logo=Codacy)](https://www.codacy.com/manual/edaa-org/pyEDAA.ProjectModel) +[![Codacy - Quality](https://img.shields.io/codacy/grade/c2635df20fa840bc85639ca2fa1d9cb4?logo=Codacy)](https://www.codacy.com/manual/edaa-org/pyEDAA.ProjectModel) +[![Codacy - Coverage](https://img.shields.io/codacy/coverage/c2635df20fa840bc85639ca2fa1d9cb4?logo=Codacy)](https://www.codacy.com/manual/edaa-org/pyEDAA.ProjectModel) [![Codecov - Branch Coverage](https://img.shields.io/codecov/c/github/edaa-org/pyEDAA.ProjectModel?logo=Codecov)](https://codecov.io/gh/edaa-org/pyEDAA.ProjectModel) [![Libraries.io SourceRank](https://img.shields.io/librariesio/sourcerank/pypi/pyEDAA.ProjectModel)](https://libraries.io/github/edaa-org/pyEDAA.ProjectModel/sourcerank) [![GitHub Workflow Release Status](https://img.shields.io/github/workflow/status/edaa-org/pyEDAA.ProjectModel/Release?label=release&logo=GitHub%20Actions&logoColor=FFFFFF)](https://github.com/edaa-org/pyEDAA.ProjectModel/actions?query=workflow%3A%22Release%22) diff --git a/doc/shields.inc b/doc/shields.inc index 5361ca9a..2098bec9 100644 --- a/doc/shields.inc +++ b/doc/shields.inc @@ -74,21 +74,21 @@ :target: https://github.com/edaa-org/pyEDAA.ProjectModel/actions?query=workflow%3A%22Test+and+Coverage%22 .. # Codacy - quality -.. |SHIELD:svg:ProjectModel-codacy-quality| image:: https://img.shields.io/codacy/grade/2286426d2b11417e90010427b7fed8e7?logo=codacy +.. |SHIELD:svg:ProjectModel-codacy-quality| image:: https://img.shields.io/codacy/grade/c2635df20fa840bc85639ca2fa1d9cb4?logo=codacy :alt: Codacy - Quality :height: 22 :target: https://www.codacy.com/manual/edaa-org/pyEDAA.ProjectModel -.. |SHIELD:png:ProjectModel-codacy-quality| image:: https://raster.shields.io/codacy/grade/2286426d2b11417e90010427b7fed8e7?logo=codacy +.. |SHIELD:png:ProjectModel-codacy-quality| image:: https://raster.shields.io/codacy/grade/c2635df20fa840bc85639ca2fa1d9cb4?logo=codacy :alt: Codacy - Quality :height: 22 :target: https://www.codacy.com/manual/edaa-org/pyEDAA.ProjectModel .. # Codacy - coverage -.. |SHIELD:svg:ProjectModel-codacy-coverage| image:: https://img.shields.io/codacy/coverage/2286426d2b11417e90010427b7fed8e7?logo=codacy +.. |SHIELD:svg:ProjectModel-codacy-coverage| image:: https://img.shields.io/codacy/coverage/c2635df20fa840bc85639ca2fa1d9cb4?logo=codacy :alt: Codacy - Line Coverage :height: 22 :target: https://www.codacy.com/manual/edaa-org/pyEDAA.ProjectModel -.. |SHIELD:png:ProjectModel-codacy-coverage| image:: https://raster.shields.io/codacy/coverage/2286426d2b11417e90010427b7fed8e7?logo=codacy +.. |SHIELD:png:ProjectModel-codacy-coverage| image:: https://raster.shields.io/codacy/coverage/c2635df20fa840bc85639ca2fa1d9cb4?logo=codacy :alt: Codacy - Line Coverage :height: 22 :target: https://www.codacy.com/manual/edaa-org/pyEDAA.ProjectModel From 4527f4eafb3f39213fcb81c98463a9fbd9791700 Mon Sep 17 00:00:00 2001 From: Patrick Lehmann Date: Mon, 11 Oct 2021 01:42:31 +0200 Subject: [PATCH 08/34] Add files to default filesets when project or design is specified. --- pyEDAA/ProjectModel/__init__.py | 26 ++++++++++++++++++++------ tests/unit/File.py | 17 +++++++++++++++++ tests/unit/Project.py | 3 ++- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/pyEDAA/ProjectModel/__init__.py b/pyEDAA/ProjectModel/__init__.py index e32b8f24..2dc53e51 100644 --- a/pyEDAA/ProjectModel/__init__.py +++ b/pyEDAA/ProjectModel/__init__.py @@ -88,6 +88,7 @@ class File(metaclass=FileType): """ _path: Path + _fileType: 'FileType' _project: Nullable['Project'] _design: Nullable['Design'] _fileSet: Nullable['FileSet'] @@ -154,6 +155,9 @@ def Project(self) -> Nullable['Project']: def Project(self, value: 'Project') -> None: self._project = value + if self._fileSet is None: + self._project.DefaultDesign.DefaultFileSet.AddFile(self) + @property def Design(self) -> Nullable['Design']: return self._design @@ -161,6 +165,10 @@ def Design(self) -> Nullable['Design']: @Design.setter def Design(self, value: 'Design') -> None: self._design = value + + if self._fileSet is None: + self._design.DefaultFileSet.AddFile(self) + if self._project is None: self._project = value._project elif self._project is not value._project: @@ -943,12 +951,13 @@ class Project: :arg rootDirectory: Base-path to the project. """ - _name: str - _rootDirectory: Nullable[Path] - _designs: Dict[str, Design] - _vhdlVersion: VHDLVersion - _verilogVersion: VerilogVersion - _svVersion: SystemVerilogVersion + _name: str + _rootDirectory: Nullable[Path] + _designs: Dict[str, Design] + _defaultDesign: Design + _vhdlVersion: VHDLVersion + _verilogVersion: VerilogVersion + _svVersion: SystemVerilogVersion def __init__( self, @@ -961,6 +970,7 @@ def __init__( self._name = name self._rootDirectory = rootDirectory self._designs = {} + self._defaultDesign = Design("default", project=self) self._vhdlVersion = vhdlVersion self._verilogVersion = verilogVersion self._svVersion = svVersion @@ -993,6 +1003,10 @@ def __getitem__(self, name: str): def Designs(self) -> Dict[str, Design]: return self._designs + @property + def DefaultDesign(self) -> Design: + return self._defaultDesign + @property def VHDLVersion(self) -> VHDLVersion: # TODO: check for None and return exception diff --git a/tests/unit/File.py b/tests/unit/File.py index 2ab2b983..5c572db9 100644 --- a/tests/unit/File.py +++ b/tests/unit/File.py @@ -115,6 +115,23 @@ def test_SetDesignWithProjectLater(self): self.assertIs(project, file.Project) self.assertIs(design, file.Design) + files = [f for f in design.DefaultFileSet.Files()] + self.assertEqual(1, len(files)) + self.assertIs(file, files[0]) + + def test_SetFileSetLater(self): + path = Path("example.vhdl") + fileset = FileSet("fileset") + file = File(path) + + file.FileSet = fileset + + self.assertIs(fileset, file.FileSet) + + files = [f for f in fileset.Files()] + self.assertEqual(1, len(files)) + self.assertIs(file, files[0]) + def test_ResolveDirectory(self): projectDirectoryPath = Path.cwd() / "project" designDirectory = "designA" diff --git a/tests/unit/Project.py b/tests/unit/Project.py index d0a1cbcb..f619fa3a 100644 --- a/tests/unit/Project.py +++ b/tests/unit/Project.py @@ -51,7 +51,8 @@ def test_Project(self): self.assertIsNotNone(project) self.assertEqual(project.Name, "project") self.assertEqual(Path("."), project.RootDirectory) - self.assertEqual(0, len(project.Designs)) + self.assertEqual(1, len(project.Designs)) + # todo: test for "default" design self.assertIsNone(project.VHDLVersion) self.assertIsNone(project.VerilogVersion) self.assertIsNone(project.SVVersion) From 3abca47e93ad369f366c0e316c0648f82947cc35 Mon Sep 17 00:00:00 2001 From: Patrick Lehmann Date: Mon, 11 Oct 2021 01:42:45 +0200 Subject: [PATCH 09/34] Enabled Python 3.10 --- .github/workflows/Pipeline.yml | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/.github/workflows/Pipeline.yml b/.github/workflows/Pipeline.yml index c80c46a1..8f64b3c3 100644 --- a/.github/workflows/Pipeline.yml +++ b/.github/workflows/Pipeline.yml @@ -15,10 +15,11 @@ jobs: fail-fast: false matrix: include: -# - {python: 3.6, icon: 🔴} - - {python: 3.7, icon: 🟠} - - {python: 3.8, icon: 🟡} - - {python: 3.9, icon: 🟢} +# - {python: "3.6", icon: 🔴} # until 23.12.2021 + - {python: "3.7", icon: 🟠} # until 27.06.2023 + - {python: "3.8", icon: 🟡} # until Oct. 2024 + - {python: "3.9", icon: 🟢} # until Oct. 2025 + - {python: "3.10", icon: 🟢} # until Oct. 2026 env: PYTHON: ${{ matrix.python }} @@ -44,11 +45,11 @@ jobs: python -m pytest -rA tests/unit Coverage: - name: 📈 Collect Coverage Data using Python 3.9 + name: 📈 Collect Coverage Data using Python 3.10 runs-on: ubuntu-latest env: - PYTHON: 3.9 + PYTHON: "3.10" ARTIFACT: pyEDAA-ProjectModel-coverage-html outputs: python: ${{ env.PYTHON }} @@ -106,11 +107,11 @@ jobs: retention-days: 1 StaticTypeCheck: - name: 📈 Check Static Typing using Python 3.9 + name: 📈 Check Static Typing using Python 3.10 runs-on: ubuntu-latest env: - PYTHON: 3.9 + PYTHON: "3.10" ARTIFACT: pyEDAA-ProjectModel-typing-html outputs: python: ${{ env.PYTHON }} @@ -283,11 +284,11 @@ jobs: twine upload dist/* VerifyDocs: - name: 👍 Verify example snippets using Python 3.9 + name: 👍 Verify example snippets using Python 3.10 runs-on: ubuntu-latest env: - PYTHON: 3.9 + PYTHON: "3.10" outputs: python: ${{ env.PYTHON }} From d0e2cc99b574a4b72f9f134812fd952f94e904c3 Mon Sep 17 00:00:00 2001 From: Patrick Lehmann Date: Mon, 11 Oct 2021 21:57:39 +0200 Subject: [PATCH 10/34] Added method structure for XPR parsing. --- pyEDAA/ProjectModel/Xilinx/Vivado.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/pyEDAA/ProjectModel/Xilinx/Vivado.py b/pyEDAA/ProjectModel/Xilinx/Vivado.py index 0c807cde..4c96003a 100644 --- a/pyEDAA/ProjectModel/Xilinx/Vivado.py +++ b/pyEDAA/ProjectModel/Xilinx/Vivado.py @@ -31,13 +31,30 @@ # from pydecor import export -from pyEDAA.ProjectModel import ConstraintFile, ProjectFile, XMLFile, XMLContent, SDCContent +from pyEDAA.ProjectModel import ConstraintFile, ProjectFile, XMLFile, XMLContent, SDCContent, Project @export class VivadoProjectFile(ProjectFile, XMLContent): """A Vivado project file (``*.xpr``).""" + _xprProject: Project + + def Parse(self): + pass + + def _ParseRootElement(self): + pass + + def _ParseFileSets(self): + pass + + def _ParseFile(self): + pass + + def _ParseVHDLFile(self): + pass + @export class XDCConstraintFile(ConstraintFile, SDCContent): From 4a38c281576cd4ae2f586888d66e5a2ada34115f Mon Sep 17 00:00:00 2001 From: Stefan Unrein Date: Mon, 11 Oct 2021 23:48:53 +0200 Subject: [PATCH 11/34] fill Vivado xpr Parser Class --- pyEDAA/ProjectModel/Xilinx/Vivado.py | 79 ++++++++++++++++++++++++---- tests/unit/VivadoProject.py | 56 ++++++++++++++++++++ 2 files changed, 125 insertions(+), 10 deletions(-) create mode 100644 tests/unit/VivadoProject.py diff --git a/pyEDAA/ProjectModel/Xilinx/Vivado.py b/pyEDAA/ProjectModel/Xilinx/Vivado.py index 4c96003a..6b791576 100644 --- a/pyEDAA/ProjectModel/Xilinx/Vivado.py +++ b/pyEDAA/ProjectModel/Xilinx/Vivado.py @@ -29,9 +29,14 @@ # SPDX-License-Identifier: Apache-2.0 # ============================================================================ # +from pathlib import Path + +from lxml import etree +from pyVHDLModel import VHDLVersion from pydecor import export -from pyEDAA.ProjectModel import ConstraintFile, ProjectFile, XMLFile, XMLContent, SDCContent, Project +from pyEDAA.ProjectModel import ConstraintFile, ProjectFile, XMLFile, XMLContent, SDCContent, Project, FileSet, \ + VHDLSourceFile, File, VerilogSourceFile @export @@ -41,19 +46,73 @@ class VivadoProjectFile(ProjectFile, XMLContent): _xprProject: Project def Parse(self): - pass + if not self._path.exists(): + raise Exception("File not found!") + + try: + with self._path.open(encoding="utf-8") as fileHandle: + content = fileHandle.read() + content = bytes(bytearray(content, encoding='utf-8')) + except OSError: + raise Exception("Couldn't open '{0!s}'.".format(self._path)) + + XMLParser = etree.XMLParser(remove_blank_text=True, encoding='utf-8') + root = etree.XML(content, XMLParser) + rootTag = etree.QName(root.tag) + + self._xprProject = Project(self._path.stem, rootDirectory=self._path.parent) + self._ParseRootElement(root) + + def _ParseRootElement(self, root): + filesetsNode = root.find('FileSets') + for filesetNode in filesetsNode: + self._ParseFileSet(filesetNode) + + + def _ParseFileSet(self, filesetNode): + filesetName = filesetNode.get('Name') + fileset = FileSet(filesetName, design=self._xprProject.DefaultDesign) + + for fileNode in filesetNode: + if fileNode.tag == 'File': + self._ParseFile(fileNode, fileset) + + def _ParseFile(self, fileNode, fileset): + filePath = Path(fileNode.get('Path')) + if filePath.suffix in ('.vhd', '.vhdl'): + self._ParseVHDLFile(fileNode, filePath, fileset) + elif filePath.suffix == '.xdc': + self._ParseXDCFile(fileNode, filePath, fileset) + elif filePath.suffix == '.v': + self._ParseVerilogFile(fileNode, filePath, fileset) + elif filePath.suffix == '.xci': + self._ParseXCIFile(fileNode, filePath, fileset) + else: + self._ParseDefaultFile(fileNode, filePath, fileset) + + + def _ParseVHDLFile(self, fileNode, path, fileset): + vhdlFile = VHDLSourceFile(Path(*path.parts[1:])) + fileset.AddFile(vhdlFile) + + if fileNode[0].tag == 'FileInfo': + if fileNode[0].get('SFType') == 'VHDL2008': + vhdlFile.VHDLVersion = VHDLVersion.VHDL2008 + else: + vhdlFile.VHDLVersion = VHDLVersion.VHDL93 + + def _ParseDefaultFile(self, _, path, fileset): + File(Path(*path.parts[1:]), fileSet=fileset) - def _ParseRootElement(self): - pass + def _ParseXDCFile(self, _, path, fileset): + XDCConstraintFile(Path(*path.parts[1:]), fileSet=fileset) - def _ParseFileSets(self): - pass + def _ParseVerilogFile(self, _, path, fileset): + VerilogSourceFile(Path(*path.parts[1:]), fileSet=fileset) - def _ParseFile(self): - pass + def _ParseXCIFile(self, _, path, fileset): + IPCoreInstantiationFile(Path(*path.parts[1:]), fileSet=fileset) - def _ParseVHDLFile(self): - pass @export diff --git a/tests/unit/VivadoProject.py b/tests/unit/VivadoProject.py new file mode 100644 index 00000000..aa970843 --- /dev/null +++ b/tests/unit/VivadoProject.py @@ -0,0 +1,56 @@ +# ============================================================================= +# _____ ____ _ _ +# _ __ _ _| ____| _ \ / \ / \ +# | '_ \| | | | _| | | | |/ _ \ / _ \ +# | |_) | |_| | |___| |_| / ___ \ / ___ \ +# | .__/ \__, |_____|____/_/ \_\/_/ \_\ +# |_| |___/ +# ============================================================================== +# Authors: Patrick Lehmann +# +# Python unittest: Instantiation tests for the project model. +# +# License: +# ============================================================================== +# Copyright 2021-2021 Patrick Lehmann - Boetzingen, 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 +# ============================================================================== +# +from pathlib import Path +from unittest import TestCase + +from pyVHDLModel import VHDLVersion +from pySVModel import VerilogVersion, SystemVerilogVersion + +from pyEDAA.ProjectModel import FileSet, VHDLSourceFile, VHDLLibrary, VerilogSourceFile, SystemVerilogSourceFile, FileTypes +from pyEDAA.ProjectModel.Xilinx.Vivado import VivadoProjectFile + +if __name__ == "__main__": # pragma: no cover + print("ERROR: you called a testcase declaration file as an executable module.") + print("Use: 'python -m unitest '") + exit(1) + + +class FileSets(TestCase): + def test_Parsing(self): + print(Path.cwd()) + path = Path('../../example/RootComplex/project/PCIe_SubSystem.xpr') + + file = VivadoProjectFile(path) + + file.Parse() + print('...') + From 5436545df8efe0ad8fdd7d27897f85937b787fa3 Mon Sep 17 00:00:00 2001 From: Patrick Lehmann Date: Tue, 12 Oct 2021 23:01:54 +0200 Subject: [PATCH 12/34] Added StopWatch Vivado example. --- tests/VivadoProject/StopWatch/LICENSE.md | 21 + tests/VivadoProject/StopWatch/README.md | 12 + .../StopWatch/project/StopWatch.xpr | 479 ++++++++++++++++++ .../StopWatch/sim/toplevel_tb.gtkw | 55 ++ .../StopWatch/sim/toplevel_tb.wcfg | 53 ++ .../VivadoProject/StopWatch/src/Counter.vhdl | 40 ++ .../StopWatch/src/Debouncer.vhdl | 53 ++ .../StopWatch/src/StopWatch.pkg.vhdl | 16 + .../StopWatch/src/StopWatch.vhdl | 122 +++++ .../StopWatch/src/Utilities.pkg.vhdl | 120 +++++ .../StopWatch/src/seg7_Display.vhdl | 77 +++ .../StopWatch/src/seg7_Encoder.vhdl | 47 ++ .../StopWatch/src/toplevel.Display.vhdl | 60 +++ .../StopWatch/src/toplevel.Encoder.vhdl | 37 ++ .../StopWatch/src/toplevel.StopWatch.vhdl | 113 +++++ .../StopWatch/tb/toplevel.StopWatch.tb.vhdl | 53 ++ tests/VivadoProject/StopWatch/xdc/Button.xdc | 3 + tests/VivadoProject/StopWatch/xdc/Clock.xdc | 3 + tests/VivadoProject/StopWatch/xdc/Display.xdc | 21 + tests/VivadoProject/StopWatch/xdc/Reset.xdc | 3 + .../StopWatch/xdc/Switch03-00.xdc | 6 + .../StopWatch/xdc/Switch15-04.xdc | 14 + 22 files changed, 1408 insertions(+) create mode 100644 tests/VivadoProject/StopWatch/LICENSE.md create mode 100644 tests/VivadoProject/StopWatch/README.md create mode 100644 tests/VivadoProject/StopWatch/project/StopWatch.xpr create mode 100644 tests/VivadoProject/StopWatch/sim/toplevel_tb.gtkw create mode 100644 tests/VivadoProject/StopWatch/sim/toplevel_tb.wcfg create mode 100644 tests/VivadoProject/StopWatch/src/Counter.vhdl create mode 100644 tests/VivadoProject/StopWatch/src/Debouncer.vhdl create mode 100644 tests/VivadoProject/StopWatch/src/StopWatch.pkg.vhdl create mode 100644 tests/VivadoProject/StopWatch/src/StopWatch.vhdl create mode 100644 tests/VivadoProject/StopWatch/src/Utilities.pkg.vhdl create mode 100644 tests/VivadoProject/StopWatch/src/seg7_Display.vhdl create mode 100644 tests/VivadoProject/StopWatch/src/seg7_Encoder.vhdl create mode 100644 tests/VivadoProject/StopWatch/src/toplevel.Display.vhdl create mode 100644 tests/VivadoProject/StopWatch/src/toplevel.Encoder.vhdl create mode 100644 tests/VivadoProject/StopWatch/src/toplevel.StopWatch.vhdl create mode 100644 tests/VivadoProject/StopWatch/tb/toplevel.StopWatch.tb.vhdl create mode 100644 tests/VivadoProject/StopWatch/xdc/Button.xdc create mode 100644 tests/VivadoProject/StopWatch/xdc/Clock.xdc create mode 100644 tests/VivadoProject/StopWatch/xdc/Display.xdc create mode 100644 tests/VivadoProject/StopWatch/xdc/Reset.xdc create mode 100644 tests/VivadoProject/StopWatch/xdc/Switch03-00.xdc create mode 100644 tests/VivadoProject/StopWatch/xdc/Switch15-04.xdc diff --git a/tests/VivadoProject/StopWatch/LICENSE.md b/tests/VivadoProject/StopWatch/LICENSE.md new file mode 100644 index 00000000..94e779e5 --- /dev/null +++ b/tests/VivadoProject/StopWatch/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 PLC2 GmbH + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/tests/VivadoProject/StopWatch/README.md b/tests/VivadoProject/StopWatch/README.md new file mode 100644 index 00000000..e6ee9329 --- /dev/null +++ b/tests/VivadoProject/StopWatch/README.md @@ -0,0 +1,12 @@ +# VHDL StopWatch Example from PLC2 + +The VHDL StopWatch Vivado project is the solution to the **Professional VHDL** 5-days class offered by PLC2. + + + +# License + +Licensed under [MIT License](LICENSE.md). + +--------------- +SPDX-License-Identifier: MIT diff --git a/tests/VivadoProject/StopWatch/project/StopWatch.xpr b/tests/VivadoProject/StopWatch/project/StopWatch.xpr new file mode 100644 index 00000000..cb04cd7c --- /dev/null +++ b/tests/VivadoProject/StopWatch/project/StopWatch.xpr @@ -0,0 +1,479 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + default_dashboard + + + diff --git a/tests/VivadoProject/StopWatch/sim/toplevel_tb.gtkw b/tests/VivadoProject/StopWatch/sim/toplevel_tb.gtkw new file mode 100644 index 00000000..e908a447 --- /dev/null +++ b/tests/VivadoProject/StopWatch/sim/toplevel_tb.gtkw @@ -0,0 +1,55 @@ +[*] +[*] GTKWave Analyzer v3.3.88 (w)1999-2018 BSI +[*] Sun Oct 14 10:46:47 2018 +[*] +[dumpfile] "C:\Training\Solutions\StopWatch\toplevel_tb.ghw" +[dumpfile_mtime] "Sun Oct 14 10:45:02 2018" +[dumpfile_size] 67424942 +[savefile] "C:\Training\Solutions\StopWatch\toplevel_tb.gtkw" +[timestart] 0 +[size] 2048 1048 +[pos] -1 -1 +*-41.719524 10040000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +[treeopen] top. +[treeopen] top.toplevel_tb. +[treeopen] top.toplevel_tb.dut. +[sst_width] 197 +[signals_width] 142 +[sst_expanded] 1 +[sst_vpaned_height] 311 +@28 +top.toplevel_tb.stopsimulation +top.toplevel_tb.clock +top.toplevel_tb.reset +top.toplevel_tb.startbutton +@200 +-StopWatch +@28 +top.toplevel_tb.dut.start +top.toplevel_tb.dut.reset +@420 +top.toplevel_tb.dut.sw.state +@200 +-Digits +@c00022 +#{top.toplevel_tb.dut.digits[0][3:0]} top.toplevel_tb.dut.digits[0][3] top.toplevel_tb.dut.digits[0][2] top.toplevel_tb.dut.digits[0][1] top.toplevel_tb.dut.digits[0][0] +@28 +top.toplevel_tb.dut.digits[0][3] +top.toplevel_tb.dut.digits[0][2] +top.toplevel_tb.dut.digits[0][1] +top.toplevel_tb.dut.digits[0][0] +@1401200 +-group_end +@22 +#{top.toplevel_tb.dut.digits[1][3:0]} top.toplevel_tb.dut.digits[1][3] top.toplevel_tb.dut.digits[1][2] top.toplevel_tb.dut.digits[1][1] top.toplevel_tb.dut.digits[1][0] +#{top.toplevel_tb.dut.digits[2][3:0]} top.toplevel_tb.dut.digits[2][3] top.toplevel_tb.dut.digits[2][2] top.toplevel_tb.dut.digits[2][1] top.toplevel_tb.dut.digits[2][0] +#{top.toplevel_tb.dut.digits[3][3:0]} top.toplevel_tb.dut.digits[3][3] top.toplevel_tb.dut.digits[3][2] top.toplevel_tb.dut.digits[3][1] top.toplevel_tb.dut.digits[3][0] +#{top.toplevel_tb.dut.digits[4][3:0]} top.toplevel_tb.dut.digits[4][3] top.toplevel_tb.dut.digits[4][2] top.toplevel_tb.dut.digits[4][1] top.toplevel_tb.dut.digits[4][0] +#{top.toplevel_tb.dut.digits[5][3:0]} top.toplevel_tb.dut.digits[5][3] top.toplevel_tb.dut.digits[5][2] top.toplevel_tb.dut.digits[5][1] top.toplevel_tb.dut.digits[5][0] +@201 +-Outputs +@22 +#{top.toplevel_tb.dut.cathode[7:0]} top.toplevel_tb.dut.cathode[7] top.toplevel_tb.dut.cathode[6] top.toplevel_tb.dut.cathode[5] top.toplevel_tb.dut.cathode[4] top.toplevel_tb.dut.cathode[3] top.toplevel_tb.dut.cathode[2] top.toplevel_tb.dut.cathode[1] top.toplevel_tb.dut.cathode[0] +#{top.toplevel_tb.dut.anode[5:0]} top.toplevel_tb.dut.anode[5] top.toplevel_tb.dut.anode[4] top.toplevel_tb.dut.anode[3] top.toplevel_tb.dut.anode[2] top.toplevel_tb.dut.anode[1] top.toplevel_tb.dut.anode[0] +[pattern_trace] 1 +[pattern_trace] 0 diff --git a/tests/VivadoProject/StopWatch/sim/toplevel_tb.wcfg b/tests/VivadoProject/StopWatch/sim/toplevel_tb.wcfg new file mode 100644 index 00000000..b2dac266 --- /dev/null +++ b/tests/VivadoProject/StopWatch/sim/toplevel_tb.wcfg @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + StopSimulation + StopSimulation + + + Clock + Clock + + + Reset + Reset + + + StartButton + StartButton + + + Input[1:0] + Input[1:0] + + + Output[1:0] + Output[1:0] + + + DigitValues[5:0][3:0] + DigitValues[5:0][3:0] + + + diff --git a/tests/VivadoProject/StopWatch/src/Counter.vhdl b/tests/VivadoProject/StopWatch/src/Counter.vhdl new file mode 100644 index 00000000..24fce3b6 --- /dev/null +++ b/tests/VivadoProject/StopWatch/src/Counter.vhdl @@ -0,0 +1,40 @@ +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/tests/VivadoProject/StopWatch/src/Debouncer.vhdl b/tests/VivadoProject/StopWatch/src/Debouncer.vhdl new file mode 100644 index 00000000..23e987f1 --- /dev/null +++ b/tests/VivadoProject/StopWatch/src/Debouncer.vhdl @@ -0,0 +1,53 @@ +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; + +use work.Utilities.all; + + +entity Debouncer is + generic ( + CLOCK_FREQ : freq := 100 MHz; + 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 := TimingToCycles(ite(IS_SIMULATION, 1 us, DEBOUNCE_TIME), CLOCK_FREQ); + constant DEBOUNCE_COUNTER_BITS : positive := log2(DEBOUNCE_COUNTER_MAX); + +begin + assert false report "CLOCK_FREQ: " & freq'image(CLOCK_FREQ); + 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/tests/VivadoProject/StopWatch/src/StopWatch.pkg.vhdl b/tests/VivadoProject/StopWatch/src/StopWatch.pkg.vhdl new file mode 100644 index 00000000..2b7c73c7 --- /dev/null +++ b/tests/VivadoProject/StopWatch/src/StopWatch.pkg.vhdl @@ -0,0 +1,16 @@ +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/tests/VivadoProject/StopWatch/src/StopWatch.vhdl b/tests/VivadoProject/StopWatch/src/StopWatch.vhdl new file mode 100644 index 00000000..a0da6375 --- /dev/null +++ b/tests/VivadoProject/StopWatch/src/StopWatch.vhdl @@ -0,0 +1,122 @@ +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_FREQ : freq := 100 MHz; + + 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 => TimingToCycles(ite(IS_SIMULATION, 100 ns, TIMEBASE), CLOCK_FREQ), + 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'element'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/tests/VivadoProject/StopWatch/src/Utilities.pkg.vhdl b/tests/VivadoProject/StopWatch/src/Utilities.pkg.vhdl new file mode 100644 index 00000000..c1e1194f --- /dev/null +++ b/tests/VivadoProject/StopWatch/src/Utilities.pkg.vhdl @@ -0,0 +1,120 @@ +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; +use IEEE.math_real.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 : time; ElseValue : time) return time; + + 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; + + function TimingToCycles(Timing : time; Clock_Period : time) return natural; + function TimingToCycles(Timing : time; Clock_Frequency: freq) 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 : time; ElseValue : time) return time 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; + + function to_time(f : freq) return time is + function div(a : freq; b : freq) return real is + begin + return real(a / 1 Hz) / real(b / 1 Hz); + end function; + begin + return div(1000 MHz, f) * 1 ns; + end function; + + function TimingToCycles(Timing : time; Clock_Period : time) return natural is + function div(a : time; b : time) return real is + begin + return real(a / 1 fs) / real(b / 1 fs); + end function; + begin + return natural(ceil(div(Timing, Clock_Period))); + end; + + function TimingToCycles(Timing : time; Clock_Frequency : freq) return natural is + begin + return TimingToCycles(Timing, to_time(Clock_Frequency)); + end function; +end package body; diff --git a/tests/VivadoProject/StopWatch/src/seg7_Display.vhdl b/tests/VivadoProject/StopWatch/src/seg7_Display.vhdl new file mode 100644 index 00000000..e1d6ae97 --- /dev/null +++ b/tests/VivadoProject/StopWatch/src/seg7_Display.vhdl @@ -0,0 +1,77 @@ +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_FREQ : freq := 100 MHz; + REFRESH_RATE : time := 1000 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 := TimingToCycles(REFRESH_RATE, CLOCK_FREQ); -- * ite(IS_SIMULATION, 1_000, 1)); + + signal Timebase_Tick : std_logic; + signal Digit_Select : unsigned(log2(DIGITS) - 1 downto 0); + + signal Digit : T_BCD; + signal Dot : std_logic; +begin + -- refresh rate + cnt1khZ: entity work.Counter + generic map ( + MODULO => TIMEBASE_COUNTER_MAX + ) + port map ( + Clock => Clock, + Reset => '0', + Enable => '1', + Value => open, + WrapAround => Timebase_Tick + ); + + -- counter to select digits (time multiplexing) + cntDigitSelect: entity work.Counter + generic map ( + MODULO => DIGITS, + BITS => Digit_Select'length + ) + port map ( + Clock => Clock, + Reset => '0', + Enable => Timebase_Tick, + Value => Digit_Select, + WrapAround => open + ); + + -- 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/tests/VivadoProject/StopWatch/src/seg7_Encoder.vhdl b/tests/VivadoProject/StopWatch/src/seg7_Encoder.vhdl new file mode 100644 index 00000000..8d5631f9 --- /dev/null +++ b/tests/VivadoProject/StopWatch/src/seg7_Encoder.vhdl @@ -0,0 +1,47 @@ +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 x"A" => temp := "1110111"; -- + when x"B" => temp := "1111100"; -- + when x"C" => temp := "0111001"; -- + when x"D" => temp := "0111110"; -- + when x"E" => temp := "1111001"; -- + when x"F" => temp := "1110001"; -- + when others => temp := "XXXXXXX"; -- + end case; + + Seg7Code <= Dot & temp; + end process; +end architecture; diff --git a/tests/VivadoProject/StopWatch/src/toplevel.Display.vhdl b/tests/VivadoProject/StopWatch/src/toplevel.Display.vhdl new file mode 100644 index 00000000..73016aa5 --- /dev/null +++ b/tests/VivadoProject/StopWatch/src/toplevel.Display.vhdl @@ -0,0 +1,60 @@ +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_FREQ : freq := 100 MHz + ); + 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_FREQ => CLOCK_FREQ, + 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 when rising_edge(NexysA7_SystemClock); + NexysA7_GPIO_Seg7_Anode_n <= not ((NexysA7_GPIO_Seg7_Anode_n'high downto Anode'length => '0') & Anode) when rising_edge(NexysA7_SystemClock); +end architecture; diff --git a/tests/VivadoProject/StopWatch/src/toplevel.Encoder.vhdl b/tests/VivadoProject/StopWatch/src/toplevel.Encoder.vhdl new file mode 100644 index 00000000..83dcc7ce --- /dev/null +++ b/tests/VivadoProject/StopWatch/src/toplevel.Encoder.vhdl @@ -0,0 +1,37 @@ +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/tests/VivadoProject/StopWatch/src/toplevel.StopWatch.vhdl b/tests/VivadoProject/StopWatch/src/toplevel.StopWatch.vhdl new file mode 100644 index 00000000..2ec9806c --- /dev/null +++ b/tests/VivadoProject/StopWatch/src/toplevel.StopWatch.vhdl @@ -0,0 +1,113 @@ +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_FREQ : freq := 100 MHz + ); + 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_FREQ => CLOCK_FREQ, + 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_FREQ => CLOCK_FREQ, + + 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_FREQ => CLOCK_FREQ, + 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 when rising_edge(NexysA7_SystemClock); + NexysA7_GPIO_Seg7_Anode_n <= not ((NexysA7_GPIO_Seg7_Anode_n'high downto Anode'length => '0') & Anode) when rising_edge(NexysA7_SystemClock); +end architecture; diff --git a/tests/VivadoProject/StopWatch/tb/toplevel.StopWatch.tb.vhdl b/tests/VivadoProject/StopWatch/tb/toplevel.StopWatch.tb.vhdl new file mode 100644 index 00000000..39951993 --- /dev/null +++ b/tests/VivadoProject/StopWatch/tb/toplevel.StopWatch.tb.vhdl @@ -0,0 +1,53 @@ +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/tests/VivadoProject/StopWatch/xdc/Button.xdc b/tests/VivadoProject/StopWatch/xdc/Button.xdc new file mode 100644 index 00000000..e075ad0d --- /dev/null +++ b/tests/VivadoProject/StopWatch/xdc/Button.xdc @@ -0,0 +1,3 @@ +set_property PACKAGE_PIN M18 [ get_ports NexysA7_GPIO_Button[0] ] +set_property IOSTANDARD LVCMOS33 [ get_ports -regexp {NexysA7_GPIO_Button\[\d+\]} ] ; # set I/O standard +set_false_path -from [ get_ports -regexp {NexysA7_GPIO_Button\[\d+\]} ] ; # Ignore timings on async I/O pins diff --git a/tests/VivadoProject/StopWatch/xdc/Clock.xdc b/tests/VivadoProject/StopWatch/xdc/Clock.xdc new file mode 100644 index 00000000..012d8e9e --- /dev/null +++ b/tests/VivadoProject/StopWatch/xdc/Clock.xdc @@ -0,0 +1,3 @@ +set_property PACKAGE_PIN E3 [ get_ports NexysA7_SystemClock ] +set_property IOSTANDARD LVCMOS33 [ get_ports NexysA7_SystemClock ] ; # set I/O standard +create_clock -name PIN_SystemClock_100MHz -period 10.000 [ get_ports NexysA7_SystemClock ] ; # specify a 100 MHz clock diff --git a/tests/VivadoProject/StopWatch/xdc/Display.xdc b/tests/VivadoProject/StopWatch/xdc/Display.xdc new file mode 100644 index 00000000..c7f2f1a4 --- /dev/null +++ b/tests/VivadoProject/StopWatch/xdc/Display.xdc @@ -0,0 +1,21 @@ +set_property PACKAGE_PIN T10 [ get_ports NexysA7_GPIO_Seg7_Cathode_n[0] ] +set_property PACKAGE_PIN R10 [ get_ports NexysA7_GPIO_Seg7_Cathode_n[1] ] +set_property PACKAGE_PIN K16 [ get_ports NexysA7_GPIO_Seg7_Cathode_n[2] ] +set_property PACKAGE_PIN K13 [ get_ports NexysA7_GPIO_Seg7_Cathode_n[3] ] +set_property PACKAGE_PIN P15 [ get_ports NexysA7_GPIO_Seg7_Cathode_n[4] ] +set_property PACKAGE_PIN T11 [ get_ports NexysA7_GPIO_Seg7_Cathode_n[5] ] +set_property PACKAGE_PIN L18 [ get_ports NexysA7_GPIO_Seg7_Cathode_n[6] ] +set_property PACKAGE_PIN H15 [ get_ports NexysA7_GPIO_Seg7_Cathode_n[7] ] +set_property IOSTANDARD LVCMOS33 [ get_ports -regexp {NexysA7_GPIO_Seg7_Cathode_n\[\d+\]} ] ; # set I/O standard +set_false_path -to [ get_ports -regexp {NexysA7_GPIO_Seg7_Cathode_n\[\d+\]} ] ; # Ignore timings on async I/O pins + +set_property PACKAGE_PIN J17 [ get_ports NexysA7_GPIO_Seg7_Anode_n[0] ] +set_property PACKAGE_PIN J18 [ get_ports NexysA7_GPIO_Seg7_Anode_n[1] ] +set_property PACKAGE_PIN T9 [ get_ports NexysA7_GPIO_Seg7_Anode_n[2] ] +set_property PACKAGE_PIN J14 [ get_ports NexysA7_GPIO_Seg7_Anode_n[3] ] +set_property PACKAGE_PIN P14 [ get_ports NexysA7_GPIO_Seg7_Anode_n[4] ] +set_property PACKAGE_PIN T14 [ get_ports NexysA7_GPIO_Seg7_Anode_n[5] ] +set_property PACKAGE_PIN K2 [ get_ports NexysA7_GPIO_Seg7_Anode_n[6] ] +set_property PACKAGE_PIN U13 [ get_ports NexysA7_GPIO_Seg7_Anode_n[7] ] +set_property IOSTANDARD LVCMOS33 [ get_ports -regexp {NexysA7_GPIO_Seg7_Anode_n\[\d+\]} ] ; # set I/O standard +set_false_path -to [ get_ports -regexp {NexysA7_GPIO_Seg7_Anode_n\[\d+\]} ] ; # Ignore timings on async I/O pins diff --git a/tests/VivadoProject/StopWatch/xdc/Reset.xdc b/tests/VivadoProject/StopWatch/xdc/Reset.xdc new file mode 100644 index 00000000..42e0c3d7 --- /dev/null +++ b/tests/VivadoProject/StopWatch/xdc/Reset.xdc @@ -0,0 +1,3 @@ +set_property PACKAGE_PIN C12 [ get_ports NexysA7_GPIO_Button_Reset_n ] +set_property IOSTANDARD LVCMOS33 [ get_ports NexysA7_GPIO_Button_Reset_n ] ; # set I/O standard +set_false_path -from [ get_ports NexysA7_GPIO_Button_Reset_n ] ; # Ignore timings on async I/O pins diff --git a/tests/VivadoProject/StopWatch/xdc/Switch03-00.xdc b/tests/VivadoProject/StopWatch/xdc/Switch03-00.xdc new file mode 100644 index 00000000..239d8724 --- /dev/null +++ b/tests/VivadoProject/StopWatch/xdc/Switch03-00.xdc @@ -0,0 +1,6 @@ +set_property PACKAGE_PIN J15 [ get_ports NexysA7_GPIO_Switch[0] ] +set_property PACKAGE_PIN L16 [ get_ports NexysA7_GPIO_Switch[1] ] +set_property PACKAGE_PIN M13 [ get_ports NexysA7_GPIO_Switch[2] ] +set_property PACKAGE_PIN R15 [ get_ports NexysA7_GPIO_Switch[3] ] +set_property IOSTANDARD LVCMOS33 [ get_ports -regexp {NexysA7_GPIO_Switch\[\d+\]} ] ; # set I/O standard +set_false_path -from [ get_ports -regexp {NexysA7_GPIO_Switch\[\d+\]} ] ; # Ignore timings on async I/O pins diff --git a/tests/VivadoProject/StopWatch/xdc/Switch15-04.xdc b/tests/VivadoProject/StopWatch/xdc/Switch15-04.xdc new file mode 100644 index 00000000..5ae0156b --- /dev/null +++ b/tests/VivadoProject/StopWatch/xdc/Switch15-04.xdc @@ -0,0 +1,14 @@ +set_property PACKAGE_PIN R17 [ get_ports NexysA7_GPIO_Switch[4] ] +set_property PACKAGE_PIN T18 [ get_ports NexysA7_GPIO_Switch[5] ] +set_property PACKAGE_PIN U18 [ get_ports NexysA7_GPIO_Switch[6] ] +set_property PACKAGE_PIN R13 [ get_ports NexysA7_GPIO_Switch[7] ] +set_property PACKAGE_PIN T8 [ get_ports NexysA7_GPIO_Switch[8] ] +set_property PACKAGE_PIN U8 [ get_ports NexysA7_GPIO_Switch[9] ] +set_property PACKAGE_PIN R16 [ get_ports NexysA7_GPIO_Switch[10] ] +set_property PACKAGE_PIN T13 [ get_ports NexysA7_GPIO_Switch[11] ] +set_property PACKAGE_PIN H6 [ get_ports NexysA7_GPIO_Switch[12] ] +set_property PACKAGE_PIN U12 [ get_ports NexysA7_GPIO_Switch[13] ] +set_property PACKAGE_PIN U11 [ get_ports NexysA7_GPIO_Switch[14] ] +set_property PACKAGE_PIN V10 [ get_ports NexysA7_GPIO_Switch[15] ] +set_property IOSTANDARD LVCMOS33 [ get_ports -regexp {NexysA7_GPIO_Switch\[\d+\]} ] ; # set I/O standard +set_false_path -from [ get_ports -regexp {NexysA7_GPIO_Switch\[\d+\]} ] ; # Ignore timings on async I/O pins From 48ef3c3d94305b0672d9d62f6d3b6377a5fca4cc Mon Sep 17 00:00:00 2001 From: Patrick Lehmann Date: Tue, 12 Oct 2021 23:25:03 +0200 Subject: [PATCH 13/34] Use "StopWatch.xpr" example file. --- pyEDAA/ProjectModel/Xilinx/Vivado.py | 4 ++++ tests/unit/VivadoProject.py | 15 +++------------ 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/pyEDAA/ProjectModel/Xilinx/Vivado.py b/pyEDAA/ProjectModel/Xilinx/Vivado.py index 6b791576..d3b006b6 100644 --- a/pyEDAA/ProjectModel/Xilinx/Vivado.py +++ b/pyEDAA/ProjectModel/Xilinx/Vivado.py @@ -45,6 +45,10 @@ class VivadoProjectFile(ProjectFile, XMLContent): _xprProject: Project + @property + def ProjectModel(self) -> Project: + return self._xprProject + def Parse(self): if not self._path.exists(): raise Exception("File not found!") diff --git a/tests/unit/VivadoProject.py b/tests/unit/VivadoProject.py index aa970843..4d7933ed 100644 --- a/tests/unit/VivadoProject.py +++ b/tests/unit/VivadoProject.py @@ -32,10 +32,6 @@ from pathlib import Path from unittest import TestCase -from pyVHDLModel import VHDLVersion -from pySVModel import VerilogVersion, SystemVerilogVersion - -from pyEDAA.ProjectModel import FileSet, VHDLSourceFile, VHDLLibrary, VerilogSourceFile, SystemVerilogSourceFile, FileTypes from pyEDAA.ProjectModel.Xilinx.Vivado import VivadoProjectFile if __name__ == "__main__": # pragma: no cover @@ -46,11 +42,6 @@ class FileSets(TestCase): def test_Parsing(self): - print(Path.cwd()) - path = Path('../../example/RootComplex/project/PCIe_SubSystem.xpr') - - file = VivadoProjectFile(path) - - file.Parse() - print('...') - + xprPath = Path('VivadoProject/StopWatch/project/StopWatch.xpr') + xprFile = VivadoProjectFile(xprPath) + xprFile.Parse() From 6814c0561ed2e87dc3314e7b74973fc72b015318 Mon Sep 17 00:00:00 2001 From: Patrick Lehmann Date: Tue, 12 Oct 2021 23:41:14 +0200 Subject: [PATCH 14/34] Added pretty printing for testing. --- tests/unit/VivadoProject.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/unit/VivadoProject.py b/tests/unit/VivadoProject.py index 4d7933ed..6a2213d7 100644 --- a/tests/unit/VivadoProject.py +++ b/tests/unit/VivadoProject.py @@ -42,6 +42,17 @@ class FileSets(TestCase): def test_Parsing(self): - xprPath = Path('VivadoProject/StopWatch/project/StopWatch.xpr') + xprPath = Path.cwd() / "tests/VivadoProject/StopWatch/project/StopWatch.xpr" + print() + print(f"{xprPath}") xprFile = VivadoProjectFile(xprPath) xprFile.Parse() + + project = xprFile.ProjectModel + print(f"Project: {project.Name}") + for designName, design in project.Designs.items(): + print(f" Design: {designName}") + for fileSetName, fileSet in design.FileSets.items(): + print(f" FileSet: {fileSetName}") + for file in fileSet.Files(): + print(f" {file.ResolvedPath}") From 6ff2079d57193cbaeaf92019220438c47829d1a5 Mon Sep 17 00:00:00 2001 From: Stefan Unrein Date: Fri, 15 Oct 2021 21:07:17 +0200 Subject: [PATCH 15/34] remove unused rootTag --- pyEDAA/ProjectModel/Xilinx/Vivado.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pyEDAA/ProjectModel/Xilinx/Vivado.py b/pyEDAA/ProjectModel/Xilinx/Vivado.py index 6b791576..4ba9f88f 100644 --- a/pyEDAA/ProjectModel/Xilinx/Vivado.py +++ b/pyEDAA/ProjectModel/Xilinx/Vivado.py @@ -58,7 +58,6 @@ def Parse(self): XMLParser = etree.XMLParser(remove_blank_text=True, encoding='utf-8') root = etree.XML(content, XMLParser) - rootTag = etree.QName(root.tag) self._xprProject = Project(self._path.stem, rootDirectory=self._path.parent) self._ParseRootElement(root) From 3d355f3b93384aea1f5f7fc84a639ff49593bf6f Mon Sep 17 00:00:00 2001 From: Stefan Unrein Date: Fri, 15 Oct 2021 21:14:11 +0200 Subject: [PATCH 16/34] fix filepath to test --- tests/unit/VivadoProject.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/VivadoProject.py b/tests/unit/VivadoProject.py index 6a2213d7..7ec876ea 100644 --- a/tests/unit/VivadoProject.py +++ b/tests/unit/VivadoProject.py @@ -42,7 +42,7 @@ class FileSets(TestCase): def test_Parsing(self): - xprPath = Path.cwd() / "tests/VivadoProject/StopWatch/project/StopWatch.xpr" + xprPath = Path.cwd() / "VivadoProject/StopWatch/project/StopWatch.xpr" print() print(f"{xprPath}") xprFile = VivadoProjectFile(xprPath) From fb54aefe16452500de7f6aec037fc8a22c8b55a7 Mon Sep 17 00:00:00 2001 From: Stefan Unrein Date: Fri, 15 Oct 2021 21:48:59 +0200 Subject: [PATCH 17/34] add some files without vhdl 2008 --- .../StopWatch/project/StopWatch.xpr | 28 ++++++++----------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/tests/VivadoProject/StopWatch/project/StopWatch.xpr b/tests/VivadoProject/StopWatch/project/StopWatch.xpr index cb04cd7c..a3731397 100644 --- a/tests/VivadoProject/StopWatch/project/StopWatch.xpr +++ b/tests/VivadoProject/StopWatch/project/StopWatch.xpr @@ -3,7 +3,7 @@ - +