ChangeLog¶
+Upcoming Release¶
+-
+
tbd
+
01.09.2021¶
+pyEDAA.ProjectModel was split from pyIPCMI (v1.1.6) as an independent Python package.
+diff --git a/.buildinfo b/.buildinfo new file mode 100644 index 00000000..ccea200f --- /dev/null +++ b/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 7133a5af6d992ad8f5e8918c0e42bbf0 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/ChangeLog/index.html b/ChangeLog/index.html new file mode 100644 index 00000000..012f963c --- /dev/null +++ b/ChangeLog/index.html @@ -0,0 +1,147 @@ + + +
+ + + ++ | + |
---|---|
+ | + |
Package |
+Version |
+License |
+Dependencies |
+
---|---|---|---|
+ | ≥5.0.0 |
++ | None |
+
+ | ≥0.27.1 |
++ | + | +
+ | ≥0.3.1 |
++ | + | +
+ | ≥0.1.0 |
++ | + | +
Additional Python packages needed for testing, code coverage collection and static type checking. These packages are +only needed for developers or on a CI server, thus sub-dependencies are not evaluated further.
+Manually Installing Test Requirements
+Use the tests/requirements.txt
file to install all dependencies via pip3
. The file will recursively install
+the mandatory dependencies too.
pip3 install -U -r tests/requirements.txt
+
Dependency List
+Package |
+Version |
+License |
+Dependencies |
+
---|---|---|---|
+ | ≥7.4.0 |
++ | Not yet evaluated. |
+
+ | ≥4.1.0 |
++ | Not yet evaluated. |
+
+ | ≥7.3 |
++ | Not yet evaluated. |
+
+ | ≥1.5 |
++ | Not yet evaluated. |
+
+ | ≥4.7.1 |
++ | Not yet evaluated. |
+
+ | ≥4.9 |
++ | Not yet evaluated. |
+
Additional Python packages needed for documentation generation. These packages are only needed for developers or on a +CI server, thus sub-dependencies are not evaluated further.
+Manually Installing Documentation Requirements
+Use the doc/requirements.txt
file to install all dependencies via pip3
. The file will recursively install
+the mandatory dependencies too.
pip3 install -U -r doc/requirements.txt
+
Dependency List
+Package |
+Version |
+License |
+Dependencies |
+
---|---|---|---|
+ | ≥5.0.0 |
++ | None |
+
+ | ≥5.3.0 |
++ | Not yet evaluated. |
+
+ | ≥0.5.2 |
++ | Not yet evaluated. |
+
+ | ≥0.0.6 |
++ | Not yet evaluated. |
+
+ | ≥1.19.5 |
++ | Not yet evaluated. |
+
Additional Python packages needed for installation package generation. These packages are only needed for developers or +on a CI server, thus sub-dependencies are not evaluated further.
+Manually Installing Packaging Requirements
+Use the build/requirements.txt
file to install all dependencies via pip3
. The file will recursively
+install the mandatory dependencies too.
pip3 install -U -r build/requirements.txt
+
Dependency List
+Package |
+Version |
+License |
+Dependencies |
+
---|---|---|---|
+ | ≥5.0.0 |
++ | None |
+
+ | ≥0.40.0 |
++ | Not yet evaluated. |
+
Additional Python packages needed for publishing the generated installation package to e.g, PyPI or any equivalent +services. These packages are only needed for maintainers or on a CI server, thus sub-dependencies are not evaluated +further.
+Manually Installing Publishing Requirements
+Use the dist/requirements.txt
file to install all dependencies via pip3
. The file will recursively
+install the mandatory dependencies too.
pip3 install -U -r dist/requirements.txt
+
Dependency List
+Package |
+Version |
+License |
+Dependencies |
+
---|---|---|---|
+ | ≥0.40.0 |
++ | Not yet evaluated. |
+
+ | ≥4.0.2 |
++ | Not yet evaluated. |
+
Note
+This is a local copy of the Creative Commons - Attribution 4.0 International (CC BY 4.0).
+Attention
+This CC BY 4.0 license applies only to the documentation of this project.
+Creative Commons Corporation (“Creative Commons”) is not a law firm and does not +provide legal services or legal advice. Distribution of Creative Commons public +licenses does not create a lawyer-client or other relationship. Creative Commons +makes its licenses and related information available on an “as-is” basis. +Creative Commons gives no warranties regarding its licenses, any material +licensed under their terms and conditions, or any related information. Creative +Commons disclaims all liability for damages resulting from their use to the +fullest extent possible.
+ +Creative Commons Attribution 4.0 International Public License
+By exercising the Licensed Rights (defined below), You accept and agree to be +bound by the terms and conditions of this Creative Commons Attribution 4.0 +International Public License (“Public License”). To the extent this Public +License may be interpreted as a contract, You are granted the Licensed Rights +in consideration of Your acceptance of these terms and conditions, and the +Licensor grants You such rights in consideration of benefits the Licensor +receives from making the Licensed Material available under these terms and +conditions.
+Adapted Material means material subject to Copyright and Similar +Rights that is derived from or based upon the Licensed Material and in +which the Licensed Material is translated, altered, arranged, transformed, or +otherwise modified in a manner requiring permission under the Copyright and +Similar Rights held by the Licensor. For purposes of this Public License, +where the Licensed Material is a musical work, performance, or sound +recording, Adapted Material is always produced where the Licensed Material +is synched in timed relation with a moving image.
Adapter’s License means the license You apply to Your Copyright and +Similar Rights in Your contributions to Adapted Material in accordance with +the terms and conditions of this Public License.
Copyright and Similar Rights means copyright and/or similar rights +closely related to copyright including, without limitation, performance, +broadcast, sound recording, and Sui Generis Database Rights, without regard +to how the rights are labeled or categorized. For purposes of this Public +License, the rights specified in Section 2(b)(1)-(2) are not Copyright and +Similar Rights.
Effective Technological Measures means those measures that, in the +absence of proper authority, may not be circumvented under laws fulfilling +obligations under Article 11 of the WIPO Copyright Treaty adopted on +December 20, 1996, and/or similar international agreements.
Exceptions and Limitations means fair use, fair dealing, and/or any +other exception or limitation to Copyright and Similar Rights that applies to +Your use of the Licensed Material.
Licensed Material means the artistic or literary work, database, or +other material to which the Licensor applied this Public License.
Licensed Rights means the rights granted to You subject to the terms +and conditions of this Public License, which are limited to all Copyright and +Similar Rights that apply to Your use of the Licensed Material and that the +Licensor has authority to license.
Licensor means the individual(s) or entity(ies) granting rights under +this Public License.
Share means to provide material to the public by any means or process +that requires permission under the Licensed Rights, such as reproduction, +public display, public performance, distribution, dissemination, +communication, or importation, and to make material available to the public +including in ways that members of the public may access the material from a +place and at a time individually chosen by them.
Sui Generis Database Rights means rights other than copyright +resulting from Directive 96/9/EC of the European Parliament and of the +Council of 11 March 1996 on the legal protection of databases, as amended +and/or succeeded, as well as other essentially equivalent rights anywhere +in the world.
You means the individual or entity exercising the Licensed Rights +under this Public License. Your has a corresponding meaning.
License grant.
+Subject to the terms and conditions of this Public License, the Licensor +hereby grants You a worldwide, royalty-free, non-sublicensable, +non-exclusive, irrevocable license to exercise the Licensed Rights in the +Licensed Material to:
++++
+- +
reproduce and Share the Licensed Material, in whole or in part; and
- +
produce, reproduce, and Share Adapted Material.
Exceptions and Limitations. For the avoidance of doubt, where +Exceptions and Limitations apply to Your use, this Public License does not +apply, and You do not need to comply with its terms and conditions.
Term. The term of this Public License is specified in Section 6(a).
Media and formats; technical modifications allowed. The Licensor +authorizes You to exercise the Licensed Rights in all media and formats +whether now known or hereafter created, and to make technical +modifications necessary to do so. The Licensor waives and/or agrees not to +assert any right or authority to forbid You from making technical +modifications necessary to exercise the Licensed Rights, including +technical modifications necessary to circumvent Effective Technological +Measures. For purposes of this Public License, simply making modifications +authorized by this Section 2(a)(4) never produces Adapted Material.
Downstream recipients.
++++
+- +
Offer from the Licensor – Licensed Material. Every recipient of +the Licensed Material automatically receives an offer from the +Licensor to exercise the Licensed Rights under the terms and +conditions of this Public License.
- +
No downstream restrictions. You may not offer or impose any +additional or different terms or conditions on, or apply any Effective +Technological Measures to, the Licensed Material if doing so restricts +exercise of the Licensed Rights by any recipient of the Licensed +Material.
No endorsement. Nothing in this Public License constitutes or may +be construed as permission to assert or imply that You are, or that Your +use of the Licensed Material is, connected with, or sponsored, endorsed, +or granted official status by, the Licensor or others designated to +receive attribution as provided in Section 3(a)(1)(A)(i).
Other rights.
+Moral rights, such as the right of integrity, are not licensed under this +Public License, nor are publicity, privacy, and/or other similar +personality rights; however, to the extent possible, the Licensor waives +and/or agrees not to assert any such rights held by the Licensor to the +limited extent necessary to allow You to exercise the Licensed Rights, but +not otherwise.
Patent and trademark rights are not licensed under this Public License.
To the extent possible, the Licensor waives any right to collect royalties +from You for the exercise of the Licensed Rights, whether directly or +through a collecting society under any voluntary or waivable statutory or +compulsory licensing scheme. In all other cases the Licensor expressly +reserves any right to collect such royalties.
Your exercise of the Licensed Rights is expressly made subject to the following conditions.
+Attribution.
+If You Share the Licensed Material (including in modified form), You must:
++++
+- +
retain the following if it is supplied by the Licensor with the +Licensed Material:
+++
+- +
identification of the creator(s) of the Licensed Material and any +others designated to receive attribution, in any reasonable manner +requested by the Licensor (including by pseudonym if designated);
- +
a copyright notice;
- +
a notice that refers to this Public License;
- +
a notice that refers to the disclaimer of warranties;
- +
a URI or hyperlink to the Licensed Material to the extent reasonably +practicable;
+
+- +
indicate if You modified the Licensed Material and retain an +indication of any previous modifications; and
- +
indicate the Licensed Material is licensed under this Public License, +and include the text of, or the URI or hyperlink to, this Public +License.
You may satisfy the conditions in Section 3(a)(1) in any reasonable manner +based on the medium, means, and context in which You Share the Licensed +Material. For example, it may be reasonable to satisfy the conditions by +providing a URI or hyperlink to a resource that includes the required +information.
If requested by the Licensor, You must remove any of the information +required by Section 3(a)(1)(A) to the extent reasonably practicable.
If You Share Adapted Material You produce, the Adapter’s License You apply +must not prevent recipients of the Adapted Material from complying with +this Public License.
Where the Licensed Rights include Sui Generis Database Rights that apply to Your +use of the Licensed Material:
+for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, +reuse, reproduce, and Share all or a substantial portion of the contents of +the database;
if You include all or a substantial portion of the database contents in a +database in which You have Sui Generis Database Rights, then the database +in which You have Sui Generis Database Rights (but not its individual +contents) is Adapted Material; and
You must comply with the conditions in Section 3(a) if You Share all or a +substantial portion of the contents of the database.
For the avoidance of doubt, this Section 4 supplements and does not replace +Your obligations under this Public License where the Licensed Rights include +other Copyright and Similar Rights.
+Unless otherwise separately undertaken by the Licensor, to the extent +possible, the Licensor offers the Licensed Material as-is and as-available, +and makes no representations or warranties of any kind concerning the +Licensed Material, whether express, implied, statutory, or other. This +includes, without limitation, warranties of title, merchantability, +fitness for a particular purpose, non-infringement, absence of latent or +other defects, accuracy, or the presence or absence of errors, whether or +not known or discoverable. Where disclaimers of warranties are not allowed +in full or in part, this disclaimer may not apply to You.
To the extent possible, in no event will the Licensor be liable to You +on any legal theory (including, without limitation, negligence) or +otherwise for any direct, special, indirect, incidental, consequential, +punitive, exemplary, or other losses, costs, expenses, or damages arising +out of this Public License or use of the Licensed Material, even if the +Licensor has been advised of the possibility of such losses, costs, expenses, +or damages. Where a limitation of liability is not allowed in full or in +part, this limitation may not apply to You.
The disclaimer of warranties and limitation of liability provided above +shall be interpreted in a manner that, to the extent possible, most +closely approximates an absolute disclaimer and waiver of all liability.
This Public License applies for the term of the Copyright and Similar Rights +licensed here. However, if You fail to comply with this Public License, then +Your rights under this Public License terminate automatically.
Where Your right to use the Licensed Material has terminated under +Section 6(a), it reinstates:
+automatically as of the date the violation is cured, provided it is cured +within 30 days of Your discovery of the violation; or
upon express reinstatement by the Licensor.
For the avoidance of doubt, this Section 6(b) does not affect any right the +Licensor may have to seek remedies for Your violations of this Public License.
+For the avoidance of doubt, the Licensor may also offer the Licensed Material +under separate terms or conditions or stop distributing the Licensed Material +at any time; however, doing so will not terminate this Public License.
Sections 1, 5, 6, 7, and 8 survive termination of this Public License.
The Licensor shall not be bound by any additional or different terms or +conditions communicated by You unless expressly agreed.
Any arrangements, understandings, or agreements regarding the Licensed +Material not stated herein are separate from and independent of the terms +and conditions of this Public License.
For the avoidance of doubt, this Public License does not, and shall not be +interpreted to, reduce, limit, restrict, or impose conditions on any use of +the Licensed Material that could lawfully be made without permission under +this Public License.
To the extent possible, if any provision of this Public License is deemed +unenforceable, it shall be automatically reformed to the minimum extent +necessary to make it enforceable. If the provision cannot be reformed, it +shall be severed from this Public License without affecting the +enforceability of the remaining terms and conditions.
No term or condition of this Public License will be waived and no failure to +comply consented to unless expressly agreed to by the Licensor.
Nothing in this Public License constitutes or may be interpreted as a +limitation upon, or waiver of, any privileges and immunities that apply to +the Licensor or You, including from the legal processes of any jurisdiction +or authority.
Creative Commons is not a party to its public licenses. Notwithstanding, +Creative Commons may elect to apply one of its public licenses to material it +publishes and in those instances will be considered the “Licensor.” Except for +the limited purpose of indicating that material is shared under a Creative +Commons public license or as otherwise permitted by the Creative Commons +policies published at creativecommons.org/policies, +Creative Commons does not authorize the use of the trademark “Creative Commons” +or any other trademark or logo of Creative Commons without its prior written +consent including, without limitation, in connection with any unauthorized +modifications to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For the +avoidance of doubt, this paragraph does not form part of the public licenses.
+Creative Commons may be contacted at creativecommons.org
+Design Goal
+TBD
+Language Reference Manual is the name given to IEEE Standard documents defining Hardware Description Languages:
+ +An ancestor class for other derived classes.
+A representation of a physical file.
+A group of files.
+If no fileset is specified, the pre-existing fileset named default
is used to group files.
A namespace in VHDL to group and organize VHDL design units (entity, package, configuration, context).
+A …
+A …
+Note
+Python ≥3.7 is required for this package due to problems with meta classes and
+__getattr__
in Python 3.6.
pip3 install pyEDAA.ProjectModel
+
pip3 install -U pyEDAA.ProjectModel
+
pip3 uninstall pyEDAA.ProjectModel
+
pip3 install .
+
setup.py
(legacy)¶See sections above on how to use PIP.
+setup.py
¶setup.py install
+
Note
+This is a local copy of the Apache License Version 2.0.
+Attention
+This Apache License, 2.0 applies to all source and configuration files of project, except documentation.
+Version 2.0, January 2004
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+“License” shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
+“Licensor” shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
+“Legal Entity” shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that +entity. For the purposes of this definition, “control” means (i) the power, direct or indirect, to cause the direction or management of such entity, whether +by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
+“You” (or “Your”) shall mean an individual or Legal Entity exercising permissions granted by this License.
+“Source” form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and +configuration files.
+“Object” form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object +code, generated documentation, and conversions to other media types.
+“Work” shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is +included in or attached to the work (an example is provided in the Appendix below).
+“Derivative Works” shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
+“Contribution” shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative +Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to +submit on behalf of the copyright owner. For the purposes of this definition, “submitted” means any form of electronic, verbal, or written communication +sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue +tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is +conspicuously marked or otherwise designated in writing by the copyright owner as “Not a Contribution.”
+“Contributor” shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work.
+Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form.
+Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such +license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of +their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim +or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then +any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
+You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions:
+You must give any other recipients of the Work or Derivative Works a copy of this License; and
You must cause any modified files to carry prominent notices stating that You changed the files; and
You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source +form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
If the Work includes a “NOTICE” text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the +Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE +file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, +alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise +complies with the conditions stated in this License.
+Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any +separate license agreement you may have executed with Licensor regarding such Contributions.
+This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable +and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
+Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an “AS IS” BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, +MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and +assume any risks associated with Your exercise of permissions under this License.
+In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or +consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages +for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been +advised of the possibility of such damages.
+While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other +liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole +responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
+Appendix: How to apply the Apache License to your work
+To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets “[]” replaced with your own identifying +information. (Don’t include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or +class name and description of purpose be included on the same “printed page” as the copyright notice for easier identification within third-party archives.
+Copyright [yyyy] [name of copyright owner]
+
+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.
+
Generic description of an EDA design.
+Todo
+Write documentation.
+Class Relationship
+Design
¶@export
+class Design:
+ _name: str
+ _project: Nullable['Project']
+ _directory: Nullable[Path]
+ _fileSets: Dict[str, FileSet]
+ _defaultFileSet: Nullable[FileSet]
+ _vhdlLibraries: Dict[str, VHDLLibrary]
+ _vhdlVersion: VHDLVersion
+ _verilogVersion: VerilogVersion
+ _svVersion: SystemVerilogVersion
+ _externalVHDLLibraries: List
+
+ def __init__(
+ self,
+ name: str,
+ directory: Path = Path("."),
+ project: 'Project' = None,
+ vhdlVersion: VHDLVersion = None,
+ verilogVersion: VerilogVersion = None,
+ svVersion: SystemVerilogVersion = None
+ ):
+
+ @property
+ def Name(self) -> str:
+
+ @property
+ def Project(self) -> Nullable['Project']:
+ @Project.setter
+ def Project(self, value: 'Project') -> None:
+
+ @property
+ def Directory(self) -> Path:
+ @Directory.setter
+ def Directory(self, value: Path) -> None:
+
+ @property
+ def ResolvedPath(self) -> Path:
+
+ @property
+ def DefaultFileSet(self) -> FileSet:
+ @DefaultFileSet.setter
+ def DefaultFileSet(self, value: Union[str, FileSet]) -> None:
+
+ @property
+ def FileSets(self) -> Dict[str, FileSet]:
+
+ def Files(self, fileType: FileType = FileTypes.Any, fileSet: Union[str, FileSet] = None) -> Generator[File, None, None]:
+
+ @property
+ def VHDLLibraries(self) -> List[VHDLLibrary]:
+
+ @property
+ def VHDLVersion(self) -> VHDLVersion:
+ @VHDLVersion.setter
+ def VHDLVersion(self, value: VHDLVersion) -> None:
+
+ @property
+ def VerilogVersion(self) -> VerilogVersion:
+ @VerilogVersion.setter
+ def VerilogVersion(self, value: VerilogVersion) -> None:
+
+ @property
+ def SVVersion(self) -> SystemVerilogVersion:
+ @SVVersion.setter
+ def SVVersion(self, value: SystemVerilogVersion) -> None:
+
+ @property
+ def ExternalVHDLLibraries(self) -> List:
+
+ def AddFileSet(self, fileSet: FileSet) -> None:
+
+ def AddFileSets(self, fileSets: Iterable[FileSet]) -> None:
+
+ def AddFile(self, file: File) -> None:
+
+ def AddFiles(self, files: Iterable[File]) -> None:
+
Generic description of a file in EDA design.
+Todo
+Write documentation.
+Class Relationship
+File
¶@export
+class File(metaclass=FileType):
+ _path: Path
+ _project: Nullable['Project']
+ _design: Nullable['Design']
+ _fileSet: Nullable['FileSet']
+
+ def __init__(
+ self,
+ path: Path,
+ project: 'Project' = None,
+ design: 'Design' = None,
+ fileSet: 'FileSet' = None
+ ):
+
+ @property
+ def FileType(self) -> 'FileType':
+
+ @property
+ def Path(self) -> Path:
+
+ @property
+ def ResolvedPath(self) -> Path:
+
+ @property
+ def Project(self) -> Nullable['Project']:
+ @Project.setter
+ def Project(self, value: 'Project') -> None:
+
+ @property
+ def Design(self) -> Nullable['Design']:
+ @Design.setter
+ def Design(self, value: 'Design') -> None:
+
+ @property
+ def FileSet(self) -> Nullable['FileSet']:
+ @FileSet.setter
+ def FileSet(self, value: 'FileSet') -> None:
+
Generic description of an EDA file set (group of files).
+Todo
+Write documentation.
+Class Relationship
+FileSet
¶@export
+class FileSet:
+ _name: str
+ _project: Nullable['Project']
+ _design: Nullable['Design']
+ _directory: Nullable[Path]
+ _parent: Nullable['FileSet']
+ _fileSets: Dict[str, 'FileSet']
+ _files: List[File]
+
+ _vhdlLibrary: 'VHDLLibrary'
+ _vhdlVersion: VHDLVersion
+ _verilogVersion: VerilogVersion
+ _svVersion: SystemVerilogVersion
+
+ def __init__(
+ self,
+ name: str,
+ directory: Path = Path("."),
+ project: 'Project' = None,
+ design: 'Design' = None,
+ parent: Nullable['FileSet'] = None,
+ vhdlLibrary: Union[str, 'VHDLLibrary'] = None,
+ vhdlVersion: VHDLVersion = None,
+ verilogVersion: VerilogVersion = None,
+ svVersion: SystemVerilogVersion = None
+ ):
+
+ @property
+ def Name(self) -> str:
+
+ @property
+ def Project(self) -> Nullable['Project']:
+ @Project.setter
+ def Project(self, value: 'Project') -> None:
+
+ @property
+ def Design(self) -> Nullable['Design']:
+ @Design.setter
+ def Design(self, value: 'Design') -> None:
+
+ @property
+ def Directory(self) -> Path:
+ @Directory.setter
+ def Directory(self, value: Path) -> None:
+
+ @property
+ def ResolvedPath(self) -> Path:
+
+ @property
+ def Parent(self) -> Nullable['FileSet']:
+ @Parent.setter
+ def Parent(self, value: 'FileSet') -> None:
+
+ @property
+ def FileSets(self) -> Dict[str, 'FileSet']:
+
+ def Files(self, fileType: FileType = FileTypes.Any, fileSet: Union[str, 'FileSet'] = None) -> Generator[File, None, None]:
+
+ def AddFile(self, file: File) -> None:
+
+ def AddFiles(self, files: Iterable[File]) -> None:
+
+ @property
+ def VHDLLibrary(self) -> 'VHDLLibrary':
+ @VHDLLibrary.setter
+ def VHDLLibrary(self, value: 'VHDLLibrary') -> None:
+
+ @property
+ def VHDLVersion(self) -> VHDLVersion:
+ @VHDLVersion.setter
+ def VHDLVersion(self, value: VHDLVersion) -> None:
+
+ @property
+ def VerilogVersion(self) -> VerilogVersion:
+ @VerilogVersion.setter
+ def VerilogVersion(self, value: VerilogVersion) -> None:
+
+ @property
+ def SVVersion(self) -> SystemVerilogVersion:
+ @SVVersion.setter
+ def SVVersion(self, value: SystemVerilogVersion) -> None:
+
Generic description of an EDA project.
+Todo
+Write documentation.
+Class Relationship
+Project
¶@export
+class Project:
+ _name: str
+ _rootDirectory: Nullable[Path]
+ _designs: Dict[str, Design]
+ _vhdlVersion: VHDLVersion
+ _verilogVersion: VerilogVersion
+ _svVersion: SystemVerilogVersion
+
+ def __init__(
+ self,
+ name: str,
+ rootDirectory: Path = Path("."),
+ vhdlVersion: VHDLVersion = None,
+ verilogVersion: VerilogVersion = None,
+ svVersion: SystemVerilogVersion = None
+ ):
+
+ @property
+ def Name(self) -> str:
+
+ @property
+ def RootDirectory(self) -> Path:
+ @RootDirectory.setter
+ def RootDirectory(self, value: Path) -> None:
+
+ @property
+ def ResolvedPath(self) -> Path:
+
+ @property
+ def Designs(self) -> Dict[str, Design]:
+
+ @property
+ def VHDLVersion(self) -> VHDLVersion:
+ @VHDLVersion.setter
+ def VHDLVersion(self, value: VHDLVersion) -> None:
+
+ @property
+ def VerilogVersion(self) -> VerilogVersion:
+ @VerilogVersion.setter
+ def VerilogVersion(self, value: VerilogVersion) -> None:
+
+ @property
+ def SVVersion(self) -> SystemVerilogVersion:
+ @SVVersion.setter
+ def SVVersion(self, value: SystemVerilogVersion) -> None:
+
Generic description of a VHDL library (group of VHDL files containing VHDL primary units).
+Todo
+Write documentation.
+Class Relationship
+VHDLLibrary
¶@export
+class VHDLLibrary:
+ _name: str
+ _project: Nullable['Project']
+ _design: Nullable['Design']
+ _files: List[File]
+ _vhdlVersion: VHDLVersion
+
+ def __init__(
+ self,
+ name: str,
+ project: 'Project' = None,
+ design: 'Design' = None,
+ vhdlVersion: VHDLVersion = None
+ ):
+
+ @property
+ def Name(self) -> str:
+
+ @property
+ def Project(self) -> Nullable['Project']:
+ @Project.setter
+ def Project(self, value: 'Project'):
+
+ @property
+ def Design(self) -> Nullable['Design']:
+ @Design.setter
+ def Design(self, value: 'Design'):
+
+ @property
+ def Files(self) -> Generator[File, None, None]:
+
+ @property
+ def VHDLVersion(self) -> VHDLVersion:
+ @VHDLVersion.setter
+ def VHDLVersion(self, value: VHDLVersion) -> None:
+
Design Goal
+Clearly named classes that model the semantics of an EDA project.
Child objects shall have a reference to their parent.
Overall Hierarchy
+An EDA project contains one or multiple variants of a EDA design. +A design then has at least one but usually multiple file sets to group source files and apply settings or attributes to that group.
+Elements of the Project Model
+
+# ==================================================================================================================== #
+# _____ ____ _ _ ____ _ _ __ __ _ _ #
+# _ __ _ _| ____| _ \ / \ / \ | _ \ _ __ ___ (_) ___ ___| |_| \/ | ___ __| | ___| | #
+# | '_ \| | | | _| | | | |/ _ \ / _ \ | |_) | '__/ _ \| |/ _ \/ __| __| |\/| |/ _ \ / _` |/ _ \ | #
+# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| __/| | | (_) | | __/ (__| |_| | | | (_) | (_| | __/ | #
+# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_| |_| \___// |\___|\___|\__|_| |_|\___/ \__,_|\___|_| #
+# |_| |___/ |__/ #
+# ==================================================================================================================== #
+# Authors: #
+# Patrick Lehmann #
+# #
+# License: #
+# ==================================================================================================================== #
+# Copyright 2017-2023 Patrick Lehmann - Boetzingen, Germany #
+# Copyright 2014-2016 Technische Universität Dresden - Germany, Chair of VLSI-Design, Diagnostics and Architecture #
+# #
+# 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 #
+# ==================================================================================================================== #
+#
+"""An abstract model of EDA tool projects."""
+__author__ = "Patrick Lehmann"
+__email__ = "Paebbels@gmail.com"
+__copyright__ = "2014-2023, Patrick Lehmann, Unai Martinez-Corral"
+__license__ = "Apache License, Version 2.0"
+__version__ = "0.5.0"
+__keywords__ = ["eda project", "model", "abstract", "xilinx", "vivado", "osvvm", "file set", "file group", "test bench", "test harness"]
+
+from os.path import relpath as path_relpath
+from pathlib import Path as pathlib_Path
+from typing import Dict, Union, Optional as Nullable, List, Iterable, Generator, Tuple, Any as typing_Any, Type, Set, Any
+
+from pyTooling.Decorators import export
+from pyTooling.MetaClasses import ExtendedType
+from pyTooling.Graph import Graph, Vertex
+from pySVModel import SystemVerilogVersion
+from pyVHDLModel import VHDLVersion
+from pySystemRDLModel import SystemRDLVersion
+
+
+
+[docs]
+@export
+class Attribute(metaclass=ExtendedType):
+ KEY: str
+ VALUE_TYPE: typing_Any
+
+ @staticmethod
+ def resolve(obj: typing_Any, key: Type['Attribute']):
+ if isinstance(obj, File):
+ return obj._fileSet[key]
+ elif isinstance(obj, FileSet):
+ return obj._design[key]
+ elif isinstance(obj, Design):
+ return obj._project[key]
+ else:
+ raise Exception("Resolution error")
+
+
+
+
+[docs]
+@export
+class FileType(ExtendedType):
+ """
+ A :term:`meta-class` to construct *FileType* classes.
+
+ Modifications done by this meta-class:
+ * Register all classes of type :class:`FileType` or derived variants in a class field :attr:`FileType.FileTypes` in this meta-class.
+ """
+
+ FileTypes: Dict[str, 'FileType'] = {} #: Dictionary of all classes of type :class:`FileType` or derived variants
+ Any: 'FileType'
+
+
+[docs]
+ def __init__(cls, name: str, bases: Tuple[type, ...], dictionary: Dict[str, typing_Any], **kwargs):
+ super().__init__(name, bases, dictionary, **kwargs)
+ cls.Any = cls
+
+
+
+[docs]
+ def __new__(cls, className, baseClasses, classMembers: Dict, *args, **kwargs):
+ fileType = super().__new__(cls, className, baseClasses, classMembers, *args, **kwargs)
+ cls.FileTypes[className] = fileType
+ return fileType
+
+
+ def __getattr__(cls, item) -> 'FileType':
+ if item[:2] != "__" and item[-2:] != "__":
+ return cls.FileTypes[item]
+ else:
+ return super().__getattribute__(item)
+
+ def __contains__(cls, item) -> bool:
+ return issubclass(item, cls)
+
+
+
+@export
+class File(metaclass=FileType, slots=True):
+ """
+ A :term:`File` represents a file in a design. This :term:`base-class` is used
+ for all derived file classes.
+
+ A file can be created standalone and later associated to a fileset, design and
+ project. Or a fileset, design and/or project can be associated immediately
+ while creating a file.
+
+ :arg path: Relative or absolute path to the file.
+ :arg project: Project the file is associated with.
+ :arg design: Design the file is associated with.
+ :arg fileSet: Fileset the file is associated with.
+ """
+
+ _path: pathlib_Path
+ _fileType: 'FileType'
+ _project: Nullable['Project']
+ _design: Nullable['Design']
+ _fileSet: Nullable['FileSet']
+ _attributes: Dict[Type[Attribute], typing_Any]
+
+ def __init__(
+ self,
+ path: pathlib_Path,
+ project: 'Project' = None,
+ design: 'Design' = None,
+ fileSet: 'FileSet' = None
+ ):
+ self._fileType = getattr(FileTypes, self.__class__.__name__)
+ self._path = path
+ if project is not None:
+ self._project = project
+ self._design = design
+ if fileSet is not None:
+ self.FileSet = fileSet
+ elif design is not None:
+ self._project = design._project
+ self._design = design
+ self.FileSet = design.DefaultFileSet if fileSet is None else fileSet
+ elif fileSet is not None:
+ design = fileSet._design
+ if design is not None:
+ self._project = design._project
+ else:
+ self._project = None
+ self._design = design
+ self.FileSet = fileSet
+ else:
+ self._project = None
+ self._design = None
+ self._fileSet = None
+
+ self._attributes = {}
+ self._registerAttributes()
+
+ def _registerAttributes(self):
+ pass
+
+ @property
+ def FileType(self) -> 'FileType':
+ """Read-only property to return the file type of this file."""
+ return self._fileType
+
+ @property
+ def Path(self) -> pathlib_Path:
+ """Read-only property returning the path of this file."""
+ return self._path
+
+ # TODO: setter?
+
+ @property
+ def ResolvedPath(self) -> pathlib_Path:
+ """Read-only property returning the resolved path of this file."""
+ if self._path.is_absolute():
+ return self._path.resolve()
+ elif self._fileSet is not None:
+ path = (self._fileSet.ResolvedPath / self._path).resolve()
+
+ if path.is_absolute():
+ return path
+ else:
+ # WORKAROUND: https://stackoverflow.com/questions/67452690/pathlib-path-relative-to-vs-os-path-relpath
+ return pathlib_Path(path_relpath(path, pathlib_Path.cwd()))
+ else:
+ # TODO: message and exception type
+ raise Exception("")
+
+ @property
+ def Project(self) -> Nullable['Project']:
+ """Property setting or returning the project this file is used in."""
+ return self._project
+
+ @Project.setter
+ 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']:
+ """Property setting or returning the design this file is used in."""
+ return self._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:
+ raise Exception("The design's project is not identical to the already assigned project.")
+
+ @property
+ def FileSet(self) -> Nullable['FileSet']:
+ """Property setting or returning the fileset this file is used in."""
+ return self._fileSet
+
+ @FileSet.setter
+ def FileSet(self, value: 'FileSet') -> None:
+ self._fileSet = value
+ value._files.append(self)
+
+ def Validate(self):
+ """Validate this file."""
+ if self._path is None:
+ raise Exception("Validation: File has no path.")
+ try:
+ path = self.ResolvedPath
+ except Exception as ex:
+ raise Exception(f"Validation: File '{self._path}' could not compute resolved path.") from ex
+ if not path.exists():
+ raise Exception(f"Validation: File '{self._path}' (={path}) does not exist.")
+ if not path.is_file():
+ raise Exception(f"Validation: File '{self._path}' (={path}) is not a file.")
+
+ if self._fileSet is None:
+ raise Exception(f"Validation: File '{self._path}' has no fileset.")
+ if self._design is None:
+ raise Exception(f"Validation: File '{self._path}' has no design.")
+ if self._project is None:
+ raise Exception(f"Validation: File '{self._path}' has no project.")
+
+ def __len__(self) -> int:
+ """
+ Returns number of attributes set on this file.
+
+ :returns: The number if attributes set on this file.
+ """
+ return len(self._attributes)
+
+ def __getitem__(self, key: Type[Attribute]) -> Any:
+ """Index access for returning attributes on this file.
+
+ :param key: The attribute type.
+ :returns: The attribute's value.
+ :raises TypeError: When parameter 'key' is not a subclass of Attribute.
+ """
+ if not issubclass(key, Attribute):
+ raise TypeError("Parameter 'key' is not an 'Attribute'.")
+
+ try:
+ return self._attributes[key]
+ except KeyError:
+ return key.resolve(self, key)
+
+ def __setitem__(self, key: Type[Attribute], value: typing_Any) -> None:
+ """
+ Index access for adding or setting attributes on this file.
+
+ :param key: The attribute type.
+ :param value: The attributes value.
+ :raises TypeError: When parameter 'key' is not a subclass of Attribute.
+ """
+ if not issubclass(key, Attribute):
+ raise TypeError("Parameter 'key' is not an 'Attribute'.")
+
+ self._attributes[key] = value
+
+ def __delitem__(self, key: Type[Attribute]) -> None:
+ """
+ Index access for deleting attributes on this file.
+
+ :param key: The attribute type.
+ """
+ if not issubclass(key, Attribute):
+ raise TypeError("Parameter 'key' is not an 'Attribute'.")
+
+ del self._attributes[key]
+
+ def __str__(self) -> str:
+ return f"{self._path}"
+
+
+FileTypes = File
+
+
+
+[docs]
+@export
+class HumanReadableContent(metaclass=ExtendedType, mixin=True):
+ """A file type representing human-readable contents."""
+
+
+
+
+[docs]
+@export
+class XMLContent(HumanReadableContent, mixin=True):
+ """A file type representing XML contents."""
+
+
+
+
+[docs]
+@export
+class YAMLContent(HumanReadableContent, mixin=True):
+ """A file type representing YAML contents."""
+
+
+
+
+[docs]
+@export
+class JSONContent(HumanReadableContent, mixin=True):
+ """A file type representing JSON contents."""
+
+
+
+
+[docs]
+@export
+class INIContent(HumanReadableContent, mixin=True):
+ """A file type representing INI contents."""
+
+
+
+
+[docs]
+@export
+class TOMLContent(HumanReadableContent, mixin=True):
+ """A file type representing TOML contents."""
+
+
+
+
+[docs]
+@export
+class TCLContent(HumanReadableContent, mixin=True):
+ """A file type representing content in TCL code."""
+
+
+
+
+[docs]
+@export
+class SDCContent(TCLContent, mixin=True):
+ """A file type representing contents as Synopsys Design Constraints (SDC)."""
+
+
+
+
+[docs]
+@export
+class PythonContent(HumanReadableContent, mixin=True):
+ """A file type representing contents as Python source code."""
+
+
+
+@export
+class TextFile(File, HumanReadableContent):
+ """A text file (``*.txt``)."""
+
+
+@export
+class LogFile(File, HumanReadableContent):
+ """A log file (``*.log``)."""
+
+
+@export
+class XMLFile(File, XMLContent):
+ """An XML file (``*.xml``)."""
+
+
+@export
+class SourceFile(File):
+ """Base-class of all source files."""
+
+
+@export
+class HDLSourceFile(SourceFile):
+ """Base-class of all HDL source files."""
+
+
+@export
+class RDLSourceFile(SourceFile):
+ """Base-class of all RDL source files."""
+
+
+@export
+class NetlistFile(SourceFile):
+ """Base-class of all netlist source files."""
+
+
+@export
+class EDIFNetlistFile(NetlistFile):
+ """Netlist file in EDIF (Electronic Design Interchange Format)."""
+
+
+@export
+class TCLSourceFile(SourceFile, TCLContent):
+ """A TCL source file."""
+
+
+@export
+class VHDLSourceFile(HDLSourceFile, HumanReadableContent):
+ """
+ A VHDL source file (of any language version).
+
+ :arg path: Relative or absolute path to the file.
+ :arg vhdlLibrary: VHDLLibrary this VHDL source file is associated wih.
+ :arg vhdlVersion: VHDLVersion this VHDL source file is associated wih.
+ :arg project: Project the file is associated with.
+ :arg design: Design the file is associated with.
+ :arg fileSet: Fileset the file is associated with.
+ """
+
+ _vhdlLibrary: Nullable['VHDLLibrary']
+ _vhdlVersion: VHDLVersion
+
+ def __init__(self, path: pathlib_Path, vhdlLibrary: Union[str, 'VHDLLibrary'] = None, vhdlVersion: VHDLVersion = None, project: 'Project' = None, design: 'Design' = None, fileSet: 'FileSet' = None):
+ super().__init__(path, project, design, fileSet)
+
+ if isinstance(vhdlLibrary, str):
+ if design is not None:
+ try:
+ vhdlLibrary = design.VHDLLibraries[vhdlLibrary]
+ except KeyError as ex:
+ raise Exception(f"VHDL library '{vhdlLibrary}' not found in design '{design.Name}'.") from ex
+ elif project is not None:
+ try:
+ vhdlLibrary = project.DefaultDesign.VHDLLibraries[vhdlLibrary]
+ except KeyError as ex:
+ raise Exception(f"VHDL library '{vhdlLibrary}' not found in default design '{project.DefaultDesign.Name}'.") from ex
+ else:
+ raise Exception(f"Can't lookup VHDL library because neither 'project' nor 'design' is given as a parameter.")
+ elif isinstance(vhdlLibrary, VHDLLibrary):
+ self._vhdlLibrary = vhdlLibrary
+ vhdlLibrary.AddFile(self)
+ elif vhdlLibrary is None:
+ self._vhdlLibrary = None
+ else:
+ raise TypeError(f"Parameter 'vhdlLibrary' is neither a 'str' nor 'VHDLibrary'.")
+
+ self._vhdlVersion = vhdlVersion
+
+ def Validate(self) -> None:
+ """Validate this VHDL source file."""
+ super().Validate()
+
+ try:
+ _ = self.VHDLLibrary
+ except Exception as ex:
+ raise Exception(f"Validation: VHDLSourceFile '{self._path}' (={self.ResolvedPath}) has no VHDLLibrary assigned.") from ex
+ try:
+ _ = self.VHDLVersion
+ except Exception as ex:
+ raise Exception(f"Validation: VHDLSourceFile '{self._path}' (={self.ResolvedPath}) has no VHDLVersion assigned.") from ex
+
+ @property
+ def VHDLLibrary(self) -> 'VHDLLibrary':
+ """Property setting or returning the VHDL library this VHDL source file is used in."""
+ if self._vhdlLibrary is not None:
+ return self._vhdlLibrary
+ elif self._fileSet is not None:
+ return self._fileSet.VHDLLibrary
+ else:
+ raise Exception("VHDLLibrary was neither set locally nor globally.")
+
+ @VHDLLibrary.setter
+ def VHDLLibrary(self, value: 'VHDLLibrary') -> None:
+ self._vhdlLibrary = value
+ value._files.append(self)
+
+ @property
+ def VHDLVersion(self) -> VHDLVersion:
+ """Property setting or returning the VHDL version this VHDL source file is used in."""
+ if self._vhdlVersion is not None:
+ return self._vhdlVersion
+ elif self._fileSet is not None:
+ return self._fileSet.VHDLVersion
+ else:
+ raise Exception("VHDLVersion was neither set locally nor globally.")
+
+ @VHDLVersion.setter
+ def VHDLVersion(self, value: VHDLVersion) -> None:
+ self._vhdlVersion = value
+
+ def __repr__(self) -> str:
+ return f"<VHDL file: '{self.ResolvedPath}'; lib: '{self.VHDLLibrary}'; version: {self.VHDLVersion}>"
+
+
+class VerilogMixIn(metaclass=ExtendedType, mixin=True):
+ @property
+ def VerilogVersion(self) -> SystemVerilogVersion:
+ """Property setting or returning the Verilog version this Verilog source file is used in."""
+ if self._version is not None:
+ return self._version
+ elif self._fileSet is not None:
+ return self._fileSet.VerilogVersion
+ else:
+ raise Exception("VerilogVersion was neither set locally nor globally.")
+
+ @VerilogVersion.setter
+ def VerilogVersion(self, value: SystemVerilogVersion) -> None:
+ self._version = value
+
+
+class SystemVerilogMixIn(metaclass=ExtendedType, mixin=True):
+ @property
+ def SVVersion(self) -> SystemVerilogVersion:
+ """Property setting or returning the SystemVerilog version this SystemVerilog source file is used in."""
+ if self._version is not None:
+ return self._version
+ elif self._fileSet is not None:
+ return self._fileSet.SVVersion
+ else:
+ raise Exception("SVVersion was neither set locally nor globally.")
+
+ @SVVersion.setter
+ def SVVersion(self, value: SystemVerilogVersion) -> None:
+ self._version = value
+
+
+@export
+class VerilogBaseFile(HDLSourceFile, HumanReadableContent):
+ _version: SystemVerilogVersion
+
+ def __init__(self, path: pathlib_Path, version: SystemVerilogVersion = None, project: 'Project' = None, design: 'Design' = None, fileSet: 'FileSet' = None):
+ super().__init__(path, project, design, fileSet)
+
+ self._version = version
+
+
+@export
+class VerilogSourceFile(VerilogBaseFile, VerilogMixIn):
+ """A Verilog source file (of any language version)."""
+
+
+@export
+class VerilogHeaderFile(VerilogBaseFile, VerilogMixIn):
+ """A Verilog header file (of any language version)."""
+
+
+@export
+class SystemVerilogBaseFile(VerilogBaseFile):
+ ...
+
+
+@export
+class SystemVerilogSourceFile(SystemVerilogBaseFile, SystemVerilogMixIn):
+ """A SystemVerilog source file (of any language version)."""
+
+
+@export
+class SystemVerilogHeaderFile(SystemVerilogBaseFile, SystemVerilogMixIn):
+ """A SystemVerilog header file (of any language version)."""
+
+
+@export
+class SystemRDLSourceFile(RDLSourceFile, HumanReadableContent):
+ """A SystemRDL source file (of any language version)."""
+
+ _srdlVersion: SystemRDLVersion
+
+ def __init__(self, path: pathlib_Path, srdlVersion: SystemRDLVersion = None, project: 'Project' = None, design: 'Design' = None, fileSet: 'FileSet' = None):
+ super().__init__(path, project, design, fileSet)
+
+ self._srdlVersion = srdlVersion
+
+ @property
+ def SystemRDLVersion(self) -> SystemRDLVersion:
+ """Property setting or returning the SystemRDL version this SystemRDL source file is used in."""
+ if self._srdlVersion is not None:
+ return self._srdlVersion
+ elif self._fileSet is not None:
+ return self._fileSet.SRDLVersion
+ else:
+ raise Exception("SRDLVersion was neither set locally nor globally.")
+
+ @SystemRDLVersion.setter
+ def SystemRDLVersion(self, value: SystemRDLVersion) -> None:
+ self._srdlVersion = value
+
+
+@export
+class PythonSourceFile(SourceFile, PythonContent):
+ """A Python source file."""
+
+
+# TODO: move to a Cocotb module
+@export
+class CocotbPythonFile(PythonSourceFile):
+ """A Python source file used by Cocotb."""
+
+
+@export
+class ConstraintFile(File, HumanReadableContent):
+ """Base-class of all constraint files."""
+
+
+@export
+class ProjectFile(File):
+ """Base-class of all tool-specific project files."""
+
+
+@export
+class CSourceFile(SourceFile):
+ """Base-class of all ANSI-C source files."""
+
+
+@export
+class CppSourceFile(SourceFile):
+ """Base-class of all ANSI-C++ source files."""
+
+
+@export
+class SettingFile(File):
+ """Base-class of all tool-specific setting files."""
+
+
+@export
+class SimulationAnalysisFile(File):
+ """Base-class of all tool-specific analysis files."""
+
+
+@export
+class SimulationElaborationFile(File):
+ """Base-class of all tool-specific elaboration files."""
+
+
+@export
+class SimulationStartFile(File):
+ """Base-class of all tool-specific simulation start-up files."""
+
+
+@export
+class SimulationRunFile(File):
+ """Base-class of all tool-specific simulation run (execution) files."""
+
+
+@export
+class WaveformConfigFile(File):
+ """Base-class of all tool-specific waveform configuration files."""
+
+
+@export
+class WaveformDatabaseFile(File):
+ """Base-class of all tool-specific waveform database files."""
+
+
+@export
+class WaveformExchangeFile(File):
+ """Base-class of all tool-independent waveform exchange files."""
+
+
+
+[docs]
+@export
+class FileSet(metaclass=ExtendedType, slots=True):
+ """
+ A :term:`FileSet` represents a group of files. Filesets can have sub-filesets.
+
+ The order of insertion is preserved. A fileset can be created standalone and
+ later associated to another fileset, design and/or project. Or a fileset,
+ design and/or project can be associated immediately while creating the
+ fileset.
+
+ :arg name: Name of this fileset.
+ :arg topLevel: Name of the fileset's toplevel.
+ :arg directory: Path of this fileset (absolute or relative to a parent fileset or design).
+ :arg project: Project the file is associated with.
+ :arg design: Design the file is associated with.
+ :arg parent: Parent fileset if this fileset is nested.
+ :arg vhdlLibrary: Default VHDL library for files in this fileset, if not specified for the file itself.
+ :arg vhdlVersion: Default VHDL version for files in this fileset, if not specified for the file itself.
+ :arg verilogVersion: Default Verilog version for files in this fileset, if not specified for the file itself.
+ :arg svVersion: Default SystemVerilog version for files in this fileset, if not specified for the file itself.
+ :arg srdlVersion: Default SystemRDL version for files in this fileset, if not specified for the file itself.
+ """
+
+ _name: str
+ _topLevel: Nullable[str]
+ _project: Nullable['Project']
+ _design: Nullable['Design']
+ _directory: pathlib_Path
+ _parent: Nullable['FileSet']
+ _fileSets: Dict[str, 'FileSet']
+ _files: List[File]
+ _set: Set
+ _attributes: Dict[Type[Attribute], typing_Any]
+ _vhdlLibraries: Dict[str, 'VHDLLibrary']
+ _vhdlLibrary: 'VHDLLibrary'
+ _vhdlVersion: VHDLVersion
+ _verilogVersion: SystemVerilogVersion
+ _svVersion: SystemVerilogVersion
+ _srdlVersion: SystemRDLVersion
+
+
+[docs]
+ def __init__(
+ self,
+ name: str,
+ topLevel: str = None,
+ directory: pathlib_Path = pathlib_Path("."),
+ project: 'Project' = None,
+ design: 'Design' = None,
+ parent: Nullable['FileSet'] = None,
+ vhdlLibrary: Union[str, 'VHDLLibrary'] = None,
+ vhdlVersion: VHDLVersion = None,
+ verilogVersion: SystemVerilogVersion = None,
+ svVersion: SystemVerilogVersion = None,
+ srdlVersion: SystemRDLVersion = None
+ ):
+ self._name = name
+ self._topLevel = topLevel
+ if project is not None:
+ self._project = project
+ self._design = design if design is not None else project.DefaultDesign
+
+ elif design is not None:
+ self._project = design._project
+ self._design = design
+ else:
+ self._project = None
+ self._design = None
+ self._directory = directory
+ self._parent = parent
+ self._fileSets = {}
+ self._files = []
+ self._set = set()
+
+ if design is not None:
+ design._fileSets[name] = self
+
+ self._attributes = {}
+ self._vhdlLibraries = {}
+
+ # TODO: handle if vhdlLibrary is a string
+ self._vhdlLibrary = vhdlLibrary
+ self._vhdlVersion = vhdlVersion
+ self._verilogVersion = verilogVersion
+ self._svVersion = svVersion
+ self._srdlVersion = srdlVersion
+
+
+ @property
+ def Name(self) -> str:
+ """Property setting or returning the fileset's name."""
+ return self._name
+
+ @Name.setter
+ def Name(self, value: str) -> None:
+ self._name = value
+
+ @property
+ def TopLevel(self) -> str:
+ """Property setting or returning the fileset's toplevel."""
+ return self._topLevel
+
+ @TopLevel.setter
+ def TopLevel(self, value: str) -> None:
+ self._topLevel = value
+
+ @property
+ def Project(self) -> Nullable['Project']:
+ """Property setting or returning the project this fileset is used in."""
+ return self._project
+
+ @Project.setter
+ def Project(self, value: 'Project') -> None:
+ self._project = value
+
+ @property
+ def Design(self) -> Nullable['Design']:
+ """Property setting or returning the design this fileset is used in."""
+ if self._design is not None:
+ return self._design
+ elif self._parent is not None:
+ return self._parent.Design
+ else:
+ return None
+ # TODO: raise exception instead
+ # QUESTION: how to handle if design and parent is set?
+
+ @Design.setter
+ def Design(self, value: 'Design') -> None:
+ self._design = value
+ if self._project is None:
+ self._project = value._project
+ elif self._project is not value._project:
+ raise Exception("The design's project is not identical to the already assigned project.")
+
+ @property
+ def Directory(self) -> pathlib_Path:
+ """Property setting or returning the directory this fileset is located in."""
+ return self._directory
+
+ @Directory.setter
+ def Directory(self, value: pathlib_Path) -> None:
+ self._directory = value
+
+ @property
+ def ResolvedPath(self) -> pathlib_Path:
+ """Read-only property returning the resolved path of this fileset."""
+ if self._directory.is_absolute():
+ return self._directory.resolve()
+ else:
+ if self._parent is not None:
+ directory = self._parent.ResolvedPath
+ elif self._design is not None:
+ directory = self._design.ResolvedPath
+ elif self._project is not None:
+ directory = self._project.ResolvedPath
+ else:
+ # TODO: message and exception type
+ raise Exception("")
+
+ directory = (directory / self._directory).resolve()
+ if directory.is_absolute():
+ return directory
+ else:
+ # WORKAROUND: https://stackoverflow.com/questions/67452690/pathlib-path-relative-to-vs-os-path-relpath
+ return pathlib_Path(path_relpath(directory, pathlib_Path.cwd()))
+
+ @property
+ def Parent(self) -> Nullable['FileSet']:
+ """Property setting or returning the parent fileset this fileset is used in."""
+ return self._parent
+
+ @Parent.setter
+ def Parent(self, value: 'FileSet') -> None:
+ self._parent = value
+ value._fileSets[self._name] = self
+ # TODO: check it it already exists
+ # QUESTION: make an Add fileset method?
+
+ @property
+ def FileSets(self) -> Dict[str, 'FileSet']:
+ """Read-only property returning the dictionary of sub-filesets."""
+ return self._fileSets
+
+
+[docs]
+ def Files(self, fileType: FileType = FileTypes.Any, fileSet: Union[bool, str, 'FileSet'] = None) -> Generator[File, None, None]:
+ """
+ Method returning the files of this fileset.
+
+ :arg fileType: A filter for file types. Default: ``Any``.
+ :arg fileSet: Specifies how to handle sub-filesets.
+ """
+ if fileSet is False:
+ for file in self._files:
+ if file.FileType in fileType:
+ yield file
+ elif fileSet is None:
+ for fileSet in self._fileSets.values():
+ for file in fileSet.Files(fileType):
+ yield file
+ for file in self._files:
+ if file.FileType in fileType:
+ yield file
+ else:
+ if isinstance(fileSet, str):
+ fileSetName = fileSet
+ try:
+ fileSet = self._fileSets[fileSetName]
+ except KeyError as ex:
+ raise Exception(f"Fileset {fileSetName} not bound to fileset {self.Name}.") from ex
+ elif not isinstance(fileSet, FileSet):
+ raise TypeError("Parameter 'fileSet' is not of type 'str' or 'FileSet' nor value 'None'.")
+
+ for file in fileSet.Files(fileType):
+ yield file
+
+
+
+[docs]
+ def AddFileSet(self, fileSet: "FileSet") -> None:
+ """
+ Method to add a single sub-fileset to this fileset.
+
+ :arg fileSet: A fileset to add to this fileset as sub-fileset.
+ """
+ if not isinstance(fileSet, FileSet):
+ raise ValueError("Parameter 'fileSet' is not of type ProjectModel.FileSet.")
+ elif fileSet in self._fileSets:
+ raise Exception("Sub-fileset already contains this fileset.")
+ elif fileSet.Name in self._fileSets.keys():
+ raise Exception(f"Fileset already contains a sub-fileset named '{fileSet.Name}'.")
+
+ self._fileSets[fileSet.Name] = fileSet
+ fileSet._parent = self
+
+
+
+[docs]
+ def AddFileSets(self, fileSets: Iterable["FileSet"]) -> None:
+ """
+ Method to add a multiple sub-filesets to this fileset.
+
+ :arg fileSets: An iterable of filesets to add each to the fileset.
+ """
+ for fileSet in fileSets:
+ self.AddFileSet(fileSet)
+
+
+ @property
+ def FileSetCount(self) -> int:
+ """Returns number of file sets excl. sub-filesets."""
+ return len(self._fileSets)
+
+ @property
+ def TotalFileSetCount(self) -> int:
+ """Returns number of file sets incl. sub-filesets."""
+ fileSetCount = len(self._fileSets)
+ for fileSet in self._fileSets.values():
+ fileSetCount += fileSet.TotalFileSetCount
+
+ return fileSetCount
+
+
+[docs]
+ def AddFile(self, file: File) -> None:
+ """
+ Method to add a single file to this fileset.
+
+ :arg file: A file to add to this fileset.
+ """
+ if not isinstance(file, File):
+ raise TypeError("Parameter 'file' is not of type ProjectModel.File.")
+ elif file._fileSet is not None:
+ ex = ValueError(f"File '{file.Path!s}' is already part of fileset '{file.FileSet.Name}'.")
+ ex.add_note(f"A file can't be assigned to another fileset.")
+ raise ex
+ elif file in self._set:
+ ex = ValueError(f"File '{file.Path!s}' is already part of this fileset.")
+ ex.add_note(f"A file can't be added twice to a fileset.")
+ raise ex
+
+ self._files.append(file)
+ self._set.add(file)
+ file._fileSet = self
+
+
+
+[docs]
+ def AddFiles(self, files: Iterable[File]) -> None:
+ """
+ Method to add a multiple files to this fileset.
+
+ :arg files: An iterable of files to add each to the fileset.
+ """
+ for file in files:
+ self.AddFile(file)
+
+
+ @property
+ def FileCount(self) -> int:
+ """Returns number of files excl. sub-filesets."""
+ return len(self._files)
+
+ @property
+ def TotalFileCount(self) -> int:
+ """Returns number of files incl. the files in sub-filesets."""
+ fileCount = len(self._files)
+ for fileSet in self._fileSets.values():
+ fileCount += fileSet.FileCount
+
+ return fileCount
+
+
+[docs]
+ def Validate(self) -> None:
+ """Validate this fileset."""
+ if self._name is None or self._name == "":
+ raise Exception("Validation: FileSet has no name.")
+
+ if self._directory is None:
+ raise Exception(f"Validation: FileSet '{self._name}' has no directory.")
+ try:
+ path = self.ResolvedPath
+ except Exception as ex:
+ raise Exception(f"Validation: FileSet '{self._name}' could not compute resolved path.") from ex
+ if not path.exists():
+ raise Exception(f"Validation: FileSet '{self._name}'s directory '{path}' does not exist.")
+ if not path.is_dir():
+ raise Exception(f"Validation: FileSet '{self._name}'s directory '{path}' is not a directory.")
+
+ if self._design is None:
+ raise Exception(f"Validation: FileSet '{self._directory}' has no design.")
+ if self._project is None:
+ raise Exception(f"Validation: FileSet '{self._directory}' has no project.")
+
+ for fileSet in self._fileSets.values():
+ fileSet.Validate()
+ for file in self._files:
+ file.Validate()
+
+
+ def GetOrCreateVHDLLibrary(self, name) -> 'VHDLLibrary':
+ if name in self._vhdlLibraries:
+ return self._vhdlLibraries[name]
+ elif name in self._design._vhdlLibraries:
+ library = self._design._vhdlLibraries[name]
+ self._vhdlLibraries[name] = library
+ return library
+ else:
+ library = VHDLLibrary(name, design=self._design, vhdlVersion=self._vhdlVersion)
+ self._vhdlLibraries[name] = library
+ return library
+
+ @property
+ def VHDLLibrary(self) -> 'VHDLLibrary':
+ """Property setting or returning the VHDL library of this fileset."""
+ if self._vhdlLibrary is not None:
+ return self._vhdlLibrary
+ elif self._parent is not None:
+ return self._parent.VHDLLibrary
+ elif self._design is not None:
+ return self._design.VHDLLibrary
+ else:
+ raise Exception("VHDLLibrary was neither set locally nor globally.")
+
+ @VHDLLibrary.setter
+ def VHDLLibrary(self, value: 'VHDLLibrary') -> None:
+ self._vhdlLibrary = value
+
+ @property
+ def VHDLVersion(self) -> VHDLVersion:
+ """Property setting or returning the VHDL version of this fileset."""
+ if self._vhdlVersion is not None:
+ return self._vhdlVersion
+ elif self._parent is not None:
+ return self._parent.VHDLVersion
+ elif self._design is not None:
+ return self._design.VHDLVersion
+ else:
+ raise Exception("VHDLVersion was neither set locally nor globally.")
+
+ @VHDLVersion.setter
+ def VHDLVersion(self, value: VHDLVersion) -> None:
+ self._vhdlVersion = value
+
+ @property
+ def VerilogVersion(self) -> SystemVerilogVersion:
+ """Property setting or returning the Verilog version of this fileset."""
+ if self._verilogVersion is not None:
+ return self._verilogVersion
+ elif self._parent is not None:
+ return self._parent.VerilogVersion
+ elif self._design is not None:
+ return self._design.VerilogVersion
+ else:
+ raise Exception("VerilogVersion was neither set locally nor globally.")
+
+ @VerilogVersion.setter
+ def VerilogVersion(self, value: SystemVerilogVersion) -> None:
+ self._verilogVersion = value
+
+ @property
+ def SVVersion(self) -> SystemVerilogVersion:
+ """Property setting or returning the SystemVerilog version of this fileset."""
+ if self._svVersion is not None:
+ return self._svVersion
+ elif self._parent is not None:
+ return self._parent.SVVersion
+ elif self._design is not None:
+ return self._design.SVVersion
+ else:
+ raise Exception("SVVersion was neither set locally nor globally.")
+
+ @SVVersion.setter
+ def SVVersion(self, value: SystemVerilogVersion) -> None:
+ self._svVersion = value
+
+ @property
+ def SRDLVersion(self) -> SystemRDLVersion:
+ if self._srdlVersion is not None:
+ return self._srdlVersion
+ elif self._parent is not None:
+ return self._parent.SRDLVersion
+ elif self._design is not None:
+ return self._design.SRDLVersion
+ else:
+ raise Exception("SRDLVersion was neither set locally nor globally.")
+
+ @SRDLVersion.setter
+ def SRDLVersion(self, value: SystemRDLVersion) -> None:
+ self._srdlVersion = value
+
+
+[docs]
+ def __len__(self) -> int:
+ """
+ Returns number of attributes set on this fileset.
+
+ :returns: The number if attributes set on this fileset.
+ """
+ return len(self._attributes)
+
+
+
+[docs]
+ def __getitem__(self, key: Type[Attribute]) -> Any:
+ """Index access for returning attributes on this fileset.
+
+ :param key: The attribute type.
+ :returns: The attribute's value.
+ :raises TypeError: When parameter 'key' is not a subclass of Attribute.
+ """
+ if not issubclass(key, Attribute):
+ raise TypeError("Parameter 'key' is not an 'Attribute'.")
+
+ try:
+ return self._attributes[key]
+ except KeyError:
+ return key.resolve(self, key)
+
+
+
+[docs]
+ def __setitem__(self, key: Type[Attribute], value: typing_Any) -> None:
+ """
+ Index access for adding or setting attributes on this fileset.
+
+ :param key: The attribute type.
+ :param value: The attributes value.
+ :raises TypeError: When parameter 'key' is not a subclass of Attribute.
+ """
+ if not issubclass(key, Attribute):
+ raise TypeError("Parameter 'key' is not an 'Attribute'.")
+
+ self._attributes[key] = value
+
+
+
+[docs]
+ def __delitem__(self, key: Type[Attribute]) -> None:
+ """
+ Index access for deleting attributes on this fileset.
+
+ :param key: The attribute type.
+ """
+ if not issubclass(key, Attribute):
+ raise TypeError("Parameter 'key' is not an 'Attribute'.")
+
+ del self._attributes[key]
+
+
+
+
+
+
+
+
+[docs]
+@export
+class VHDLLibrary(metaclass=ExtendedType, slots=True):
+ """
+ A :term:`VHDLLibrary` represents a group of VHDL source files compiled into the same VHDL library.
+
+ :arg name: The VHDL libraries' name.
+ :arg project: Project the VHDL library is associated with.
+ :arg design: Design the VHDL library is associated with.
+ :arg vhdlVersion: Default VHDL version for files in this VHDL library, if not specified for the file itself.
+ """
+
+ _name: str
+ _project: Nullable['Project']
+ _design: Nullable['Design']
+ _files: List[File]
+ _vhdlVersion: VHDLVersion
+
+ _dependencyNode: Vertex
+
+
+[docs]
+ def __init__(
+ self,
+ name: str,
+ project: 'Project' = None,
+ design: 'Design' = None,
+ vhdlVersion: VHDLVersion = None
+ ):
+ self._name = name
+ if project is not None:
+ self._project = project
+ self._design = project._defaultDesign if design is None else design
+ self._dependencyNode = Vertex(value=self, graph=self._design._vhdlLibraryDependencyGraph)
+
+ if name in self._design._vhdlLibraries:
+ raise Exception(f"Library '{name}' already in design '{self._design.Name}'.")
+ else:
+ self._design._vhdlLibraries[name] = self
+
+ elif design is not None:
+ self._project = design._project
+ self._design = design
+ self._dependencyNode = Vertex(value=self, graph=design._vhdlLibraryDependencyGraph)
+
+ if name in design._vhdlLibraries:
+ raise Exception(f"Library '{name}' already in design '{design.Name}'.")
+ else:
+ design._vhdlLibraries[name] = self
+
+ else:
+ self._project = None
+ self._design = None
+ self._dependencyNode = None
+
+ self._files = []
+ self._vhdlVersion = vhdlVersion
+
+
+ @property
+ def Name(self) -> str:
+ return self._name
+
+ @property
+ def Project(self) -> Nullable['Project']:
+ """Property setting or returning the project this VHDL library is used in."""
+ return self._project
+
+ @Project.setter
+ def Project(self, value: 'Project') -> None:
+ if not isinstance(value, Project):
+ raise TypeError("Parameter 'value' is not of type 'Project'.")
+
+ if value is None:
+ # TODO: unlink VHDLLibrary from project
+ self._project = None
+ else:
+ self._project = value
+ if self._design is None:
+ self._design = value._defaultDesign
+
+ @property
+ def Design(self) -> Nullable['Design']:
+ """Property setting or returning the design this VHDL library is used in."""
+ return self._design
+
+ @Design.setter
+ def Design(self, value: 'Design') -> None:
+ if not isinstance(value, Design):
+ raise TypeError("Parameter 'value' is not of type 'Design'.")
+
+ if value is None:
+ # TODO: unlink VHDLLibrary from design
+ self._design = None
+ else:
+ if self._design is None:
+ self._design = value
+ self._dependencyNode = Vertex(value=self, graph=self._design._vhdlLibraryDependencyGraph)
+ elif self._design is not value:
+ # TODO: move VHDLLibrary to other design
+ # TODO: create new vertex in dependency graph and remove vertex from old graph
+ self._design = value
+ else:
+ pass
+
+ if self._project is None:
+ self._project = value._project
+ elif self._project is not value._project:
+ raise Exception("The design's project is not identical to the already assigned project.")
+
+ @property
+ def Files(self) -> Generator[File, None, None]:
+ """Read-only property to return all files in this VHDL library."""
+ for file in self._files:
+ yield file
+
+ @property
+ def VHDLVersion(self) -> VHDLVersion:
+ """Property setting or returning the VHDL version of this VHDL library."""
+ if self._vhdlVersion is not None:
+ return self._vhdlVersion
+ elif self._design is not None:
+ return self._design.VHDLVersion
+ else:
+ raise Exception("VHDLVersion is not set on VHDLLibrary nor parent object.")
+
+ @VHDLVersion.setter
+ def VHDLVersion(self, value: VHDLVersion) -> None:
+ self._vhdlVersion = value
+
+ def AddDependency(self, library: 'VHDLLibrary') -> None:
+ library.parent = self
+
+ def AddFile(self, vhdlFile: VHDLSourceFile) -> None:
+ if not isinstance(vhdlFile, VHDLSourceFile):
+ raise TypeError(f"Parameter 'vhdlFile' is not a 'VHDLSourceFile'.")
+
+ self._files.append(vhdlFile)
+
+ def AddFiles(self, vhdlFiles: Iterable[VHDLSourceFile]) -> None:
+ for vhdlFile in vhdlFiles:
+ if not isinstance(vhdlFile, VHDLSourceFile):
+ raise TypeError(f"Item '{vhdlFile}' in parameter 'vhdlFiles' is not a 'VHDLSourceFile'.")
+
+ self._files.append(vhdlFile)
+
+ @property
+ def FileCount(self) -> int:
+ """Returns number of files."""
+ return len(self._files)
+
+
+[docs]
+ def __len__(self) -> int:
+ """
+ Returns number of attributes set on this VHDL library.
+
+ :returns: The number if attributes set on this VHDL library.
+ """
+ return len(self._attributes)
+
+
+
+[docs]
+ def __getitem__(self, key: Type[Attribute]) -> Any:
+ """Index access for returning attributes on this VHDL library.
+
+ :param key: The attribute type.
+ :returns: The attribute's value.
+ :raises TypeError: When parameter 'key' is not a subclass of Attribute.
+ """
+ if not issubclass(key, Attribute):
+ raise TypeError("Parameter 'key' is not an 'Attribute'.")
+
+ try:
+ return self._attributes[key]
+ except KeyError:
+ return key.resolve(self, key)
+
+
+
+[docs]
+ def __setitem__(self, key: Type[Attribute], value: typing_Any) -> None:
+ """
+ Index access for adding or setting attributes on this VHDL library.
+
+ :param key: The attribute type.
+ :param value: The attributes value.
+ :raises TypeError: When parameter 'key' is not a subclass of Attribute.
+ """
+ if not issubclass(key, Attribute):
+ raise TypeError("Parameter 'key' is not an 'Attribute'.")
+
+ self._attributes[key] = value
+
+
+
+[docs]
+ def __delitem__(self, key: Type[Attribute]) -> None:
+ """
+ Index access for deleting attributes on this VHDL library.
+
+ :param key: The attribute type.
+ """
+ if not issubclass(key, Attribute):
+ raise TypeError("Parameter 'key' is not an 'Attribute'.")
+
+ del self._attributes[key]
+
+
+
+
+
+
+
+
+[docs]
+@export
+class Design(metaclass=ExtendedType, slots=True):
+ """
+ A :term:`Design` represents a group of filesets and the source files therein.
+
+ Each design contains at least one fileset - the :term:`default fileset`. For
+ designs with VHDL source files, a independent `VHDLLibraries` overlay structure
+ exists.
+
+ :arg name: The design's name.
+ :arg topLevel: Name of the design's toplevel.
+ :arg directory: Path of this design (absolute or relative to the project).
+ :arg project: Project the design is associated with.
+ :arg vhdlVersion: Default VHDL version for files in this design, if not specified for the file itself.
+ :arg verilogVersion: Default Verilog version for files in this design, if not specified for the file itself.
+ :arg svVersion: Default SystemVerilog version for files in this design, if not specified for the file itself.
+ :arg srdlVersion: Default SystemRDL version for files in this fileset, if not specified for the file itself.
+ """
+
+ _name: str
+ _topLevel: Nullable[str]
+ _project: Nullable['Project']
+ _directory: pathlib_Path
+ _fileSets: Dict[str, FileSet]
+ _defaultFileSet: Nullable[FileSet]
+ _attributes: Dict[Type[Attribute], typing_Any]
+
+ _vhdlLibraries: Dict[str, VHDLLibrary]
+ _vhdlVersion: VHDLVersion
+ _verilogVersion: SystemVerilogVersion
+ _svVersion: SystemVerilogVersion
+ _srdlVersion: SystemRDLVersion
+ _externalVHDLLibraries: List
+
+ _vhdlLibraryDependencyGraph: Graph
+ _fileDependencyGraph: Graph
+
+
+[docs]
+ def __init__(
+ self,
+ name: str,
+ topLevel: str = None,
+ directory: pathlib_Path = pathlib_Path("."),
+ project: 'Project' = None,
+ vhdlVersion: VHDLVersion = None,
+ verilogVersion: SystemVerilogVersion = None,
+ svVersion: SystemVerilogVersion = None,
+ srdlVersion: SystemRDLVersion = None
+ ):
+ self._name = name
+ self._topLevel = topLevel
+ 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)
+ self._attributes = {}
+ self._vhdlLibraries = {}
+ self._vhdlVersion = vhdlVersion
+ self._verilogVersion = verilogVersion
+ self._svVersion = svVersion
+ self._srdlVersion = srdlVersion
+ self._externalVHDLLibraries = []
+
+ self._vhdlLibraryDependencyGraph = Graph()
+ self._fileDependencyGraph = Graph()
+
+
+ @property
+ def Name(self) -> str:
+ """Property setting or returning the design's name."""
+ return self._name
+
+ @Name.setter
+ def Name(self, value: str) -> None:
+ self._name = value
+
+ @property
+ def TopLevel(self) -> str:
+ """Property setting or returning the fileset's toplevel."""
+ return self._topLevel
+
+ @TopLevel.setter
+ def TopLevel(self, value: str) -> None:
+ self._topLevel = value
+
+ @property
+ def Project(self) -> Nullable['Project']:
+ """Property setting or returning the project this design is used in."""
+ return self._project
+
+ @Project.setter
+ def Project(self, value: 'Project') -> None:
+ self._project = value
+
+ @property
+ def Directory(self) -> pathlib_Path:
+ """Property setting or returning the directory this design is located in."""
+ return self._directory
+
+ @Directory.setter
+ def Directory(self, value: pathlib_Path) -> None:
+ self._directory = value
+
+ @property
+ def ResolvedPath(self) -> pathlib_Path:
+ """Read-only property returning the resolved path of this fileset."""
+ if self._directory.is_absolute():
+ return self._directory.resolve()
+ elif self._project is not None:
+ path = (self._project.ResolvedPath / self._directory).resolve()
+
+ if path.is_absolute():
+ return path
+ else:
+ # WORKAROUND: https://stackoverflow.com/questions/67452690/pathlib-path-relative-to-vs-os-path-relpath
+ return pathlib_Path(path_relpath(path, pathlib_Path.cwd()))
+ else:
+ # TODO: message and exception type
+ raise Exception("")
+
+ @property
+ def DefaultFileSet(self) -> FileSet:
+ """Property setting or returning the default fileset of this design."""
+ return self._defaultFileSet
+
+ @DefaultFileSet.setter
+ def DefaultFileSet(self, value: Union[str, FileSet]) -> None:
+ if isinstance(value, str):
+ if value not in self._fileSets.keys():
+ raise Exception(f"Fileset '{value}' is not in this design.")
+
+ self._defaultFileSet = self._fileSets[value]
+ elif isinstance(value, FileSet):
+ if value not in self.FileSets:
+ raise Exception(f"Fileset '{value}' is not associated to this design.")
+
+ self._defaultFileSet = value
+ else:
+ raise ValueError("Unsupported parameter type for 'value'.")
+
+ # TODO: return generator with another method
+ @property
+ def FileSets(self) -> Dict[str, FileSet]:
+ """Read-only property returning the dictionary of filesets."""
+ return self._fileSets
+
+
+[docs]
+ def Files(self, fileType: FileType = FileTypes.Any, fileSet: Union[str, FileSet] = None) -> Generator[File, None, None]:
+ """
+ Method returning the files of this design.
+
+ :arg fileType: A filter for file types. Default: ``Any``.
+ :arg fileSet: Specifies if all files from all filesets (``fileSet=None``) are files from a single fileset are returned.
+ """
+ if fileSet is None:
+ for fileSet in self._fileSets.values():
+ for file in fileSet.Files(fileType):
+ yield file
+ else:
+ if isinstance(fileSet, str):
+ try:
+ fileSet = self._fileSets[fileSet]
+ except KeyError as ex:
+ raise Exception(f"Fileset {fileSet.Name} not bound to design {self.Name}.") from ex
+ elif not isinstance(fileSet, FileSet):
+ raise TypeError("Parameter 'fileSet' is not of type 'str' or 'FileSet' nor value 'None'.")
+
+ for file in fileSet.Files(fileType):
+ yield file
+
+
+
+[docs]
+ def Validate(self) -> None:
+ """Validate this design."""
+ if self._name is None or self._name == "":
+ raise Exception("Validation: Design has no name.")
+
+ if self._directory is None:
+ raise Exception(f"Validation: Design '{self._name}' has no directory.")
+ try:
+ path = self.ResolvedPath
+ except Exception as ex:
+ raise Exception(f"Validation: Design '{self._name}' could not compute resolved path.") from ex
+ if not path.exists():
+ raise Exception(f"Validation: Design '{self._name}'s directory '{path}' does not exist.")
+ if not path.is_dir():
+ raise Exception(f"Validation: Design '{self._name}'s directory '{path}' is not a directory.")
+
+ if len(self._fileSets) == 0:
+ raise Exception(f"Validation: Design '{self._name}' has no fileset.")
+ try:
+ if self._defaultFileSet is not self._fileSets[self._defaultFileSet.Name]:
+ raise Exception(f"Validation: Design '{self._name}'s default fileset is the same as listed in filesets.")
+ except KeyError as ex:
+ raise Exception(f"Validation: Design '{self._name}'s default fileset is not in list of filesets.") from ex
+ if self._project is None:
+ raise Exception(f"Validation: Design '{self._path}' has no project.")
+
+ for fileSet in self._fileSets.values():
+ fileSet.Validate()
+
+
+ @property
+ def VHDLLibraries(self) -> Dict[str, VHDLLibrary]:
+ return self._vhdlLibraries
+
+ @property
+ def VHDLVersion(self) -> VHDLVersion:
+ if self._vhdlVersion is not None:
+ return self._vhdlVersion
+ elif self._project is not None:
+ return self._project.VHDLVersion
+ else:
+ raise Exception("VHDLVersion was neither set locally nor globally.")
+
+ @VHDLVersion.setter
+ def VHDLVersion(self, value: VHDLVersion) -> None:
+ self._vhdlVersion = value
+
+ @property
+ def VerilogVersion(self) -> SystemVerilogVersion:
+ if self._verilogVersion is not None:
+ return self._verilogVersion
+ elif self._project is not None:
+ return self._project.VerilogVersion
+ else:
+ raise Exception("VerilogVersion was neither set locally nor globally.")
+
+ @VerilogVersion.setter
+ def VerilogVersion(self, value: SystemVerilogVersion) -> None:
+ self._verilogVersion = value
+
+ @property
+ def SVVersion(self) -> SystemVerilogVersion:
+ if self._svVersion is not None:
+ return self._svVersion
+ elif self._project is not None:
+ return self._project.SVVersion
+ else:
+ raise Exception("SVVersion was neither set locally nor globally.")
+
+ @SVVersion.setter
+ def SVVersion(self, value: SystemVerilogVersion) -> None:
+ self._svVersion = value
+
+ @property
+ def SRDLVersion(self) -> SystemRDLVersion:
+ if self._srdlVersion is not None:
+ return self._srdlVersion
+ elif self._project is not None:
+ return self._project.SRDLVersion
+ else:
+ raise Exception("SRDLVersion was neither set locally nor globally.")
+
+ @SRDLVersion.setter
+ def SRDLVersion(self, value: SystemRDLVersion) -> None:
+ self._srdlVersion = value
+
+ @property
+ def ExternalVHDLLibraries(self) -> List:
+ return self._externalVHDLLibraries
+
+ def AddFileSet(self, fileSet: FileSet) -> None:
+ if not isinstance(fileSet, FileSet):
+ raise ValueError("Parameter 'fileSet' is not of type ProjectModel.FileSet.")
+ elif fileSet in self._fileSets:
+ raise Exception("Design already contains this fileset.")
+ elif fileSet.Name in self._fileSets.keys():
+ raise Exception(f"Design already contains a fileset named '{fileSet.Name}'.")
+
+ self._fileSets[fileSet.Name] = fileSet
+ fileSet.Design = self
+ fileSet._parent = self
+
+ def AddFileSets(self, fileSets: Iterable[FileSet]) -> None:
+ for fileSet in fileSets:
+ self.AddFileSet(fileSet)
+
+ @property
+ def FileSetCount(self) -> int:
+ """Returns number of file sets excl. sub-filesets."""
+ return len(self._fileSets)
+
+ @property
+ def TotalFileSetCount(self) -> int:
+ """Returns number of file sets incl. sub-filesets."""
+ fileSetCount = len(self._fileSets)
+ for fileSet in self._fileSets.values():
+ fileSetCount += fileSet.TotalFileSetCount
+
+ return fileSetCount
+
+ def AddFile(self, file: File) -> None:
+ if file.FileSet is None:
+ self._defaultFileSet.AddFile(file)
+ else:
+ raise ValueError(f"File '{file.Path!s}' is already part of fileset '{file.FileSet.Name}' and can't be assigned via Design to a default fileset.")
+
+ def AddFiles(self, files: Iterable[File]) -> None:
+ for file in files:
+ self.AddFile(file)
+
+ def AddVHDLLibrary(self, vhdlLibrary: VHDLLibrary) -> None:
+ if vhdlLibrary.Name in self._vhdlLibraries:
+ if self._vhdlLibraries[vhdlLibrary.Name] is vhdlLibrary:
+ raise Exception(f"The VHDLLibrary '{vhdlLibrary.Name}' was already added to the design.")
+ else:
+ raise Exception(f"A VHDLLibrary with same name ('{vhdlLibrary.Name}') already exists for this design.")
+
+
+
+[docs]
+ def __len__(self) -> int:
+ """
+ Returns number of attributes set on this design.
+
+ :returns: The number if attributes set on this design.
+ """
+ return len(self._attributes)
+
+
+
+[docs]
+ def __getitem__(self, key: Type[Attribute]) -> Any:
+ """Index access for returning attributes on this design.
+
+ :param key: The attribute type.
+ :returns: The attribute's value.
+ :raises TypeError: When parameter 'key' is not a subclass of Attribute.
+ """
+ if not issubclass(key, Attribute):
+ raise TypeError("Parameter 'key' is not an 'Attribute'.")
+
+ try:
+ return self._attributes[key]
+ except KeyError:
+ return key.resolve(self, key)
+
+
+
+[docs]
+ def __setitem__(self, key: Type[Attribute], value: typing_Any) -> None:
+ """
+ Index access for adding or setting attributes on this design.
+
+ :param key: The attribute type.
+ :param value: The attributes value.
+ :raises TypeError: When parameter 'key' is not a subclass of Attribute.
+ """
+ if not issubclass(key, Attribute):
+ raise TypeError("Parameter 'key' is not an 'Attribute'.")
+
+ self._attributes[key] = value
+
+
+
+[docs]
+ def __delitem__(self, key: Type[Attribute]) -> None:
+ """
+ Index access for deleting attributes on this design.
+
+ :param key: The attribute type.
+ """
+ if not issubclass(key, Attribute):
+ raise TypeError("Parameter 'key' is not an 'Attribute'.")
+
+ del self._attributes[key]
+
+
+
+
+
+
+
+
+[docs]
+@export
+class Project(metaclass=ExtendedType, slots=True):
+ """
+ A :term:`Project` represents a group of designs and the source files therein.
+
+ :arg name: The project's name.
+ :arg rootDirectory: Base-path to the project.
+ :arg vhdlVersion: Default VHDL version for files in this project, if not specified for the file itself.
+ :arg verilogVersion: Default Verilog version for files in this project, if not specified for the file itself.
+ :arg svVersion: Default SystemVerilog version for files in this project, if not specified for the file itself.
+ """
+
+ _name: str
+ _rootDirectory: pathlib_Path
+ _designs: Dict[str, Design]
+ _defaultDesign: Design
+ _attributes: Dict[Type[Attribute], typing_Any]
+
+ _vhdlVersion: VHDLVersion
+ _verilogVersion: SystemVerilogVersion
+ _svVersion: SystemVerilogVersion
+ _srdlVersion: SystemRDLVersion
+
+
+[docs]
+ def __init__(
+ self,
+ name: str,
+ rootDirectory: pathlib_Path = pathlib_Path("."),
+ vhdlVersion: VHDLVersion = None,
+ verilogVersion: SystemVerilogVersion = None,
+ svVersion: SystemVerilogVersion = None
+ ):
+ self._name = name
+ self._rootDirectory = rootDirectory
+ self._designs = {}
+ self._defaultDesign = Design("default", project=self)
+ self._attributes = {}
+ self._vhdlVersion = vhdlVersion
+ self._verilogVersion = verilogVersion
+ self._svVersion = svVersion
+
+
+ @property
+ def Name(self) -> str:
+ """Property setting or returning the project's name."""
+ return self._name
+
+ @property
+ def RootDirectory(self) -> pathlib_Path:
+ """Property setting or returning the root directory this project is located in."""
+ return self._rootDirectory
+
+ @RootDirectory.setter
+ def RootDirectory(self, value: pathlib_Path) -> None:
+ self._rootDirectory = value
+
+ @property
+ def ResolvedPath(self) -> pathlib_Path:
+ """Read-only property returning the resolved path of this fileset."""
+ path = self._rootDirectory.resolve()
+ if self._rootDirectory.is_absolute():
+ return path
+ else:
+ # WORKAROUND: https://stackoverflow.com/questions/67452690/pathlib-path-relative-to-vs-os-path-relpath
+ return pathlib_Path(path_relpath(path, pathlib_Path.cwd()))
+
+ # TODO: return generator with another method
+ @property
+ def Designs(self) -> Dict[str, Design]:
+ return self._designs
+
+ @property
+ def DefaultDesign(self) -> Design:
+ return self._defaultDesign
+
+
+[docs]
+ def Validate(self) -> None:
+ """Validate this project."""
+ if self._name is None or self._name == "":
+ raise Exception("Validation: Project has no name.")
+
+ if self._rootDirectory is None:
+ raise Exception(f"Validation: Project '{self._name}' has no root directory.")
+ try:
+ path = self.ResolvedPath
+ except Exception as ex:
+ raise Exception(f"Validation: Project '{self._name}' could not compute resolved path.") from ex
+ if not path.exists():
+ raise Exception(f"Validation: Project '{self._name}'s directory '{path}' does not exist.")
+ if not path.is_dir():
+ raise Exception(f"Validation: Project '{self._name}'s directory '{path}' is not a directory.")
+
+ if len(self._designs) == 0:
+ raise Exception(f"Validation: Project '{self._name}' has no design.")
+ try:
+ if self._defaultDesign is not self._designs[self._defaultDesign.Name]:
+ raise Exception(f"Validation: Project '{self._name}'s default design is the same as listed in designs.")
+ except KeyError as ex:
+ raise Exception(f"Validation: Project '{self._name}'s default design is not in list of designs.") from ex
+
+ for design in self._designs.values():
+ design.Validate()
+
+
+ @property
+ def DesignCount(self) -> int:
+ """Returns number of designs."""
+ return len(self._designs)
+
+ @property
+ def VHDLVersion(self) -> VHDLVersion:
+ # TODO: check for None and return exception
+ return self._vhdlVersion
+
+ @VHDLVersion.setter
+ def VHDLVersion(self, value: VHDLVersion) -> None:
+ self._vhdlVersion = value
+
+ @property
+ def VerilogVersion(self) -> SystemVerilogVersion:
+ # TODO: check for None and return exception
+ return self._verilogVersion
+
+ @VerilogVersion.setter
+ def VerilogVersion(self, value: SystemVerilogVersion) -> None:
+ self._verilogVersion = value
+
+ @property
+ def SVVersion(self) -> SystemVerilogVersion:
+ # TODO: check for None and return exception
+ return self._svVersion
+
+ @SVVersion.setter
+ def SVVersion(self, value: SystemVerilogVersion) -> None:
+ self._svVersion = value
+
+ @property
+ def SRDLVersion(self) -> SystemRDLVersion:
+ # TODO: check for None and return exception
+ return self._srdlVersion
+
+ @SRDLVersion.setter
+ def SRDLVersion(self, value: SystemRDLVersion) -> None:
+ self._srdlVersion = value
+
+
+[docs]
+ def __len__(self) -> int:
+ """
+ Returns number of attributes set on this project.
+
+ :returns: The number if attributes set on this project.
+ """
+ return len(self._attributes)
+
+
+
+[docs]
+ def __getitem__(self, key: Type[Attribute]) -> Any:
+ """Index access for returning attributes on this project.
+
+ :param key: The attribute type.
+ :returns: The attribute's value.
+ :raises TypeError: When parameter 'key' is not a subclass of Attribute.
+ """
+ if not issubclass(key, Attribute):
+ raise TypeError("Parameter 'key' is not an 'Attribute'.")
+
+ try:
+ return self._attributes[key]
+ except KeyError:
+ return key.resolve(self, key)
+
+
+
+[docs]
+ def __setitem__(self, key: Type[Attribute], value: typing_Any) -> None:
+ """
+ Index access for adding or setting attributes on this project.
+
+ :param key: The attribute type.
+ :param value: The attributes value.
+ :raises TypeError: When parameter 'key' is not a subclass of Attribute.
+ """
+ if not issubclass(key, Attribute):
+ raise TypeError("Parameter 'key' is not an 'Attribute'.")
+
+ self._attributes[key] = value
+
+
+
+[docs]
+ def __delitem__(self, key: Type[Attribute]) -> None:
+ """
+ Index access for deleting attributes on this project.
+
+ :param key: The attribute type.
+ """
+ if not issubclass(key, Attribute):
+ raise TypeError("Parameter 'key' is not an 'Attribute'.")
+
+ del self._attributes[key]
+
+
+
+
+
+
+# ==================================================================================================================== #
+# _____ ____ _ _ ____ _ _ __ __ _ _ #
+# _ __ _ _| ____| _ \ / \ / \ | _ \ _ __ ___ (_) ___ ___| |_| \/ | ___ __| | ___| | #
+# | '_ \| | | | _| | | | |/ _ \ / _ \ | |_) | '__/ _ \| |/ _ \/ __| __| |\/| |/ _ \ / _` |/ _ \ | #
+# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| __/| | | (_) | | __/ (__| |_| | | | (_) | (_| | __/ | #
+# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_| |_| \___// |\___|\___|\__|_| |_|\___/ \__,_|\___|_| #
+# |_| |___/ |__/ #
+# ==================================================================================================================== #
+# Authors: #
+# Patrick Lehmann #
+# #
+# License: #
+# ==================================================================================================================== #
+# Copyright 2017-2023 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 #
+# ==================================================================================================================== #
+#
+"""A set of common attributes to store meta information on ProjectModel entities (project, design, fileset, file, ...)."""
+from typing import Dict
+from pyTooling.Decorators import export
+
+from pyEDAA.ProjectModel import Attribute
+
+
+
+[docs]
+@export
+class KeyValueAttribute(Attribute):
+ KEY = "ID"
+
+ _keyValuePairs: Dict[str, str]
+
+
+
+
+ def __getitem__(self, item: str) -> str:
+ return self._keyValuePairs[item]
+
+ def __setitem__(self, key: str, value: str) -> None:
+ self._keyValuePairs[key] = value
+
+
+# ==================================================================================================================== #
+# _____ ____ _ _ ____ _ _ __ __ _ _ #
+# _ __ _ _| ____| _ \ / \ / \ | _ \ _ __ ___ (_) ___ ___| |_| \/ | ___ __| | ___| | #
+# | '_ \| | | | _| | | | |/ _ \ / _ \ | |_) | '__/ _ \| |/ _ \/ __| __| |\/| |/ _ \ / _` |/ _ \ | #
+# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| __/| | | (_) | | __/ (__| |_| | | | (_) | (_| | __/ | #
+# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_| |_| \___// |\___|\___|\__|_| |_|\___/ \__,_|\___|_| #
+# |_| |___/ |__/ #
+# ==================================================================================================================== #
+# Authors: #
+# Patrick Lehmann #
+# #
+# License: #
+# ==================================================================================================================== #
+# Copyright 2017-2023 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 #
+# ==================================================================================================================== #
+#
+"""Specific file types and attributes for Xilinx Vivado."""
+from pathlib import Path
+from typing import Iterable
+
+from xml.dom import minidom, Node
+
+from pyTooling.MetaClasses import ExtendedType
+from pyVHDLModel import VHDLVersion
+from pyTooling.Decorators import export
+
+from pyEDAA.ProjectModel import ProjectFile, XMLFile, XMLContent, SDCContent, Project, FileSet, Attribute, Design
+from pyEDAA.ProjectModel import File as Model_File
+from pyEDAA.ProjectModel import ConstraintFile as Model_ConstraintFile
+from pyEDAA.ProjectModel import VerilogSourceFile as Model_VerilogSourceFile
+from pyEDAA.ProjectModel import VHDLSourceFile as Model_VHDLSourceFile
+
+
+
+
+
+
+@export
+class File(Model_File):
+ pass
+
+
+class VivadoFileMixIn(metaclass=ExtendedType, mixin=True):
+ def _registerAttributes(self):
+ self._attributes[UsedInAttribute] = []
+
+
+@export
+class ConstraintFile(Model_ConstraintFile, VivadoFileMixIn):
+ def _registerAttributes(self):
+ super()._registerAttributes()
+ VivadoFileMixIn._registerAttributes(self)
+
+
+@export
+class VerilogSourceFile(Model_VerilogSourceFile):
+ def _registerAttributes(self):
+ super()._registerAttributes()
+ VivadoFileMixIn._registerAttributes(self)
+
+
+@export
+class VHDLSourceFile(Model_VHDLSourceFile):
+ def _registerAttributes(self):
+ super()._registerAttributes()
+ VivadoFileMixIn._registerAttributes(self)
+
+
+@export
+class VivadoProjectFile(ProjectFile, XMLContent):
+ """A Vivado project file (``*.xpr``)."""
+
+ _xprProject: Project
+
+ def __init__(
+ self,
+ path: Path,
+ project: Project = None,
+ design: Design = None,
+ fileSet: FileSet = None
+ ):
+ super().__init__(path, project, design, fileSet)
+
+ self._xprProject = None
+
+ @property
+ def ProjectModel(self) -> Project:
+ return self._xprProject
+
+ def Parse(self):
+ if not self._path.exists():
+ raise Exception(f"Vivado project file '{self._path!s}' not found.") from FileNotFoundError(f"File '{self._path!s}' not found.")
+
+ try:
+ root = minidom.parse(str(self._path)).documentElement
+ except Exception as ex:
+ raise Exception(f"Couldn't open '{self._path!s}'.") from ex
+
+ self._xprProject = Project(self._path.stem, rootDirectory=self._path.parent)
+ self._ParseRootElement(root)
+
+ def _ParseRootElement(self, root):
+ for rootNode in root.childNodes:
+ if rootNode.nodeName == "FileSets":
+ self._ParseFileSets(rootNode)
+ break
+
+ def _ParseFileSets(self, filesetsNode):
+ for fileSetsNode in filesetsNode.childNodes:
+ if fileSetsNode.nodeType == Node.ELEMENT_NODE and fileSetsNode.tagName == "FileSet":
+ self._ParseFileSet(fileSetsNode)
+
+ def _ParseFileSet(self, filesetNode):
+ filesetName = filesetNode.getAttribute("Name")
+ fileset = FileSet(filesetName, design=self._xprProject.DefaultDesign)
+
+ for fileNode in filesetNode.childNodes:
+ if fileNode.nodeType == Node.ELEMENT_NODE:
+ if fileNode.tagName == "File":
+ self._ParseFile(fileNode, fileset)
+ elif fileNode.nodeType == Node.ELEMENT_NODE and fileNode.tagName == "Config":
+ self._ParseFileSetConfig(fileNode, fileset)
+
+ def _ParseFile(self, fileNode, fileset):
+ croppedPath = fileNode.getAttribute("Path").replace("$PPRDIR/", "")
+ filePath = Path(croppedPath)
+ 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)
+ fileset.AddFile(vhdlFile)
+ usedInAttr = vhdlFile[UsedInAttribute]
+
+ for childNode in fileNode.childNodes:
+ if childNode.nodeType == Node.ELEMENT_NODE and childNode.tagName == "FileInfo":
+ if childNode.getAttribute("SFType") == "VHDL2008":
+ vhdlFile.VHDLVersion = VHDLVersion.VHDL2008
+ else:
+ vhdlFile.VHDLVersion = VHDLVersion.VHDL93
+
+ for fileAttribute in childNode.childNodes:
+ if fileAttribute.nodeType == Node.ELEMENT_NODE and fileAttribute.tagName == "Attr":
+ if fileAttribute.getAttribute("Name") == "Library":
+ libraryName = fileAttribute.getAttribute("Val")
+ vhdlFile.VHDLLibrary = fileset.GetOrCreateVHDLLibrary(libraryName)
+ elif fileAttribute.getAttribute("Val") == "UsedIn":
+ usedInAttr.append(fileAttribute.getAttribute("Val"))
+
+ def _ParseDefaultFile(self, _, path, fileset):
+ File(path, fileSet=fileset)
+
+ def _ParseXDCFile(self, _, path, fileset):
+ XDCConstraintFile(path, fileSet=fileset)
+
+ def _ParseVerilogFile(self, _, path, fileset):
+ VerilogSourceFile(path, fileSet=fileset)
+
+ def _ParseXCIFile(self, _, path, fileset):
+ IPCoreInstantiationFile(path, fileSet=fileset)
+
+ def _ParseFileSetConfig(self, fileNode, fileset):
+ for option in fileNode.childNodes:
+ if option.nodeType == Node.ELEMENT_NODE and option.tagName == "Option":
+ if option.getAttribute("Name") == "TopModule":
+ fileset.TopLevel = option.getAttribute("Val")
+
+
+@export
+class XDCConstraintFile(ConstraintFile, SDCContent):
+ """A Vivado constraint file (Xilinx Design Constraints; ``*.xdc``)."""
+
+
+@export
+class IPCoreDescriptionFile(XMLFile):
+ pass
+
+
+@export
+class IPCoreInstantiationFile(XMLFile):
+ """A Vivado IP core instantiation file (Xilinx IPCore Instance; ``*.xci``)."""
+
' + + '' + + _("Hide Search Matches") + + "
" + ) + ); + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords: () => { + document + .querySelectorAll("#searchbox .highlight-link") + .forEach((el) => el.remove()); + document + .querySelectorAll("span.highlighted") + .forEach((el) => el.classList.remove("highlighted")); + localStorage.removeItem("sphinx_highlight_terms") + }, + + initEscapeListener: () => { + // only install a listener if it is really needed + if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS) return; + + document.addEventListener("keydown", (event) => { + // bail for input elements + if (BLACKLISTED_KEY_CONTROL_ELEMENTS.has(document.activeElement.tagName)) return; + // bail with special keys + if (event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) return; + if (DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS && (event.key === "Escape")) { + SphinxHighlight.hideSearchWords(); + event.preventDefault(); + } + }); + }, +}; + +_ready(() => { + /* Do not call highlightSearchWords() when we are on the search page. + * It will highlight words from the *previous* search query. + */ + if (typeof Search === "undefined") SphinxHighlight.highlightSearchWords(); + SphinxHighlight.initEscapeListener(); +}); diff --git a/coverage/coverage_html.js b/coverage/coverage_html.js new file mode 100644 index 00000000..59348828 --- /dev/null +++ b/coverage/coverage_html.js @@ -0,0 +1,624 @@ +// Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +// For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt + +// Coverage.py HTML report browser code. +/*jslint browser: true, sloppy: true, vars: true, plusplus: true, maxerr: 50, indent: 4 */ +/*global coverage: true, document, window, $ */ + +coverage = {}; + +// General helpers +function debounce(callback, wait) { + let timeoutId = null; + return function(...args) { + clearTimeout(timeoutId); + timeoutId = setTimeout(() => { + callback.apply(this, args); + }, wait); + }; +}; + +function checkVisible(element) { + const rect = element.getBoundingClientRect(); + const viewBottom = Math.max(document.documentElement.clientHeight, window.innerHeight); + const viewTop = 30; + return !(rect.bottom < viewTop || rect.top >= viewBottom); +} + +function on_click(sel, fn) { + const elt = document.querySelector(sel); + if (elt) { + elt.addEventListener("click", fn); + } +} + +// Helpers for table sorting +function getCellValue(row, column = 0) { + const cell = row.cells[column] // nosemgrep: eslint.detect-object-injection + if (cell.childElementCount == 1) { + const child = cell.firstElementChild + if (child instanceof HTMLTimeElement && child.dateTime) { + return child.dateTime + } else if (child instanceof HTMLDataElement && child.value) { + return child.value + } + } + return cell.innerText || cell.textContent; +} + +function rowComparator(rowA, rowB, column = 0) { + let valueA = getCellValue(rowA, column); + let valueB = getCellValue(rowB, column); + if (!isNaN(valueA) && !isNaN(valueB)) { + return valueA - valueB + } + return valueA.localeCompare(valueB, undefined, {numeric: true}); +} + +function sortColumn(th) { + // Get the current sorting direction of the selected header, + // clear state on other headers and then set the new sorting direction + const currentSortOrder = th.getAttribute("aria-sort"); + [...th.parentElement.cells].forEach(header => header.setAttribute("aria-sort", "none")); + if (currentSortOrder === "none") { + th.setAttribute("aria-sort", th.dataset.defaultSortOrder || "ascending"); + } else { + th.setAttribute("aria-sort", currentSortOrder === "ascending" ? "descending" : "ascending"); + } + + const column = [...th.parentElement.cells].indexOf(th) + + // Sort all rows and afterwards append them in order to move them in the DOM + Array.from(th.closest("table").querySelectorAll("tbody tr")) + .sort((rowA, rowB) => rowComparator(rowA, rowB, column) * (th.getAttribute("aria-sort") === "ascending" ? 1 : -1)) + .forEach(tr => tr.parentElement.appendChild(tr) ); +} + +// Find all the elements with data-shortcut attribute, and use them to assign a shortcut key. +coverage.assign_shortkeys = function () { + document.querySelectorAll("[data-shortcut]").forEach(element => { + document.addEventListener("keypress", event => { + if (event.target.tagName.toLowerCase() === "input") { + return; // ignore keypress from search filter + } + if (event.key === element.dataset.shortcut) { + element.click(); + } + }); + }); +}; + +// Create the events for the filter box. +coverage.wire_up_filter = function () { + // Cache elements. + const table = document.querySelector("table.index"); + const table_body_rows = table.querySelectorAll("tbody tr"); + const no_rows = document.getElementById("no_rows"); + + // Observe filter keyevents. + document.getElementById("filter").addEventListener("input", debounce(event => { + // Keep running total of each metric, first index contains number of shown rows + const totals = new Array(table.rows[0].cells.length).fill(0); + // Accumulate the percentage as fraction + totals[totals.length - 1] = { "numer": 0, "denom": 0 }; // nosemgrep: eslint.detect-object-injection + + // Hide / show elements. + table_body_rows.forEach(row => { + if (!row.cells[0].textContent.includes(event.target.value)) { + // hide + row.classList.add("hidden"); + return; + } + + // show + row.classList.remove("hidden"); + totals[0]++; + + for (let column = 1; column < totals.length; column++) { + // Accumulate dynamic totals + cell = row.cells[column] // nosemgrep: eslint.detect-object-injection + if (column === totals.length - 1) { + // Last column contains percentage + const [numer, denom] = cell.dataset.ratio.split(" "); + totals[column]["numer"] += parseInt(numer, 10); // nosemgrep: eslint.detect-object-injection + totals[column]["denom"] += parseInt(denom, 10); // nosemgrep: eslint.detect-object-injection + } else { + totals[column] += parseInt(cell.textContent, 10); // nosemgrep: eslint.detect-object-injection + } + } + }); + + // Show placeholder if no rows will be displayed. + if (!totals[0]) { + // Show placeholder, hide table. + no_rows.style.display = "block"; + table.style.display = "none"; + return; + } + + // Hide placeholder, show table. + no_rows.style.display = null; + table.style.display = null; + + const footer = table.tFoot.rows[0]; + // Calculate new dynamic sum values based on visible rows. + for (let column = 1; column < totals.length; column++) { + // Get footer cell element. + const cell = footer.cells[column]; // nosemgrep: eslint.detect-object-injection + + // Set value into dynamic footer cell element. + if (column === totals.length - 1) { + // Percentage column uses the numerator and denominator, + // and adapts to the number of decimal places. + const match = /\.([0-9]+)/.exec(cell.textContent); + const places = match ? match[1].length : 0; + const { numer, denom } = totals[column]; // nosemgrep: eslint.detect-object-injection + cell.dataset.ratio = `${numer} ${denom}`; + // Check denom to prevent NaN if filtered files contain no statements + cell.textContent = denom + ? `${(numer * 100 / denom).toFixed(places)}%` + : `${(100).toFixed(places)}%`; + } else { + cell.textContent = totals[column]; // nosemgrep: eslint.detect-object-injection + } + } + })); + + // Trigger change event on setup, to force filter on page refresh + // (filter value may still be present). + document.getElementById("filter").dispatchEvent(new Event("input")); +}; + +coverage.INDEX_SORT_STORAGE = "COVERAGE_INDEX_SORT_2"; + +// Loaded on index.html +coverage.index_ready = function () { + coverage.assign_shortkeys(); + coverage.wire_up_filter(); + document.querySelectorAll("[data-sortable] th[aria-sort]").forEach( + th => th.addEventListener("click", e => sortColumn(e.target)) + ); + + // Look for a localStorage item containing previous sort settings: + const stored_list = localStorage.getItem(coverage.INDEX_SORT_STORAGE); + + if (stored_list) { + const {column, direction} = JSON.parse(stored_list); + const th = document.querySelector("[data-sortable]").tHead.rows[0].cells[column]; // nosemgrep: eslint.detect-object-injection + th.setAttribute("aria-sort", direction === "ascending" ? "descending" : "ascending"); + th.click() + } + + // Watch for page unload events so we can save the final sort settings: + window.addEventListener("unload", function () { + const th = document.querySelector('[data-sortable] th[aria-sort="ascending"], [data-sortable] [aria-sort="descending"]'); + if (!th) { + return; + } + localStorage.setItem(coverage.INDEX_SORT_STORAGE, JSON.stringify({ + column: [...th.parentElement.cells].indexOf(th), + direction: th.getAttribute("aria-sort"), + })); + }); + + on_click(".button_prev_file", coverage.to_prev_file); + on_click(".button_next_file", coverage.to_next_file); + + on_click(".button_show_hide_help", coverage.show_hide_help); +}; + +// -- pyfile stuff -- + +coverage.LINE_FILTERS_STORAGE = "COVERAGE_LINE_FILTERS"; + +coverage.pyfile_ready = function () { + // If we're directed to a particular line number, highlight the line. + var frag = location.hash; + if (frag.length > 2 && frag[1] === "t") { + document.querySelector(frag).closest(".n").classList.add("highlight"); + coverage.set_sel(parseInt(frag.substr(2), 10)); + } else { + coverage.set_sel(0); + } + + on_click(".button_toggle_run", coverage.toggle_lines); + on_click(".button_toggle_mis", coverage.toggle_lines); + on_click(".button_toggle_exc", coverage.toggle_lines); + on_click(".button_toggle_par", coverage.toggle_lines); + + on_click(".button_next_chunk", coverage.to_next_chunk_nicely); + on_click(".button_prev_chunk", coverage.to_prev_chunk_nicely); + on_click(".button_top_of_page", coverage.to_top); + on_click(".button_first_chunk", coverage.to_first_chunk); + + on_click(".button_prev_file", coverage.to_prev_file); + on_click(".button_next_file", coverage.to_next_file); + on_click(".button_to_index", coverage.to_index); + + on_click(".button_show_hide_help", coverage.show_hide_help); + + coverage.filters = undefined; + try { + coverage.filters = localStorage.getItem(coverage.LINE_FILTERS_STORAGE); + } catch(err) {} + + if (coverage.filters) { + coverage.filters = JSON.parse(coverage.filters); + } + else { + coverage.filters = {run: false, exc: true, mis: true, par: true}; + } + + for (cls in coverage.filters) { + coverage.set_line_visibilty(cls, coverage.filters[cls]); // nosemgrep: eslint.detect-object-injection + } + + coverage.assign_shortkeys(); + coverage.init_scroll_markers(); + coverage.wire_up_sticky_header(); + + document.querySelectorAll("[id^=ctxs]").forEach( + cbox => cbox.addEventListener("click", coverage.expand_contexts) + ); + + // Rebuild scroll markers when the window height changes. + window.addEventListener("resize", coverage.build_scroll_markers); +}; + +coverage.toggle_lines = function (event) { + const btn = event.target.closest("button"); + const category = btn.value + const show = !btn.classList.contains("show_" + category); + coverage.set_line_visibilty(category, show); + coverage.build_scroll_markers(); + coverage.filters[category] = show; + try { + localStorage.setItem(coverage.LINE_FILTERS_STORAGE, JSON.stringify(coverage.filters)); + } catch(err) {} +}; + +coverage.set_line_visibilty = function (category, should_show) { + const cls = "show_" + category; + const btn = document.querySelector(".button_toggle_" + category); + if (btn) { + if (should_show) { + document.querySelectorAll("#source ." + category).forEach(e => e.classList.add(cls)); + btn.classList.add(cls); + } + else { + document.querySelectorAll("#source ." + category).forEach(e => e.classList.remove(cls)); + btn.classList.remove(cls); + } + } +}; + +// Return the nth line div. +coverage.line_elt = function (n) { + return document.getElementById("t" + n)?.closest("p"); +}; + +// Set the selection. b and e are line numbers. +coverage.set_sel = function (b, e) { + // The first line selected. + coverage.sel_begin = b; + // The next line not selected. + coverage.sel_end = (e === undefined) ? b+1 : e; +}; + +coverage.to_top = function () { + coverage.set_sel(0, 1); + coverage.scroll_window(0); +}; + +coverage.to_first_chunk = function () { + coverage.set_sel(0, 1); + coverage.to_next_chunk(); +}; + +coverage.to_prev_file = function () { + window.location = document.getElementById("prevFileLink").href; +} + +coverage.to_next_file = function () { + window.location = document.getElementById("nextFileLink").href; +} + +coverage.to_index = function () { + location.href = document.getElementById("indexLink").href; +} + +coverage.show_hide_help = function () { + const helpCheck = document.getElementById("help_panel_state") + helpCheck.checked = !helpCheck.checked; +} + +// Return a string indicating what kind of chunk this line belongs to, +// or null if not a chunk. +coverage.chunk_indicator = function (line_elt) { + const classes = line_elt?.className; + if (!classes) { + return null; + } + const match = classes.match(/\bshow_\w+\b/); + if (!match) { + return null; + } + return match[0]; +}; + +coverage.to_next_chunk = function () { + const c = coverage; + + // Find the start of the next colored chunk. + var probe = c.sel_end; + var chunk_indicator, probe_line; + while (true) { + probe_line = c.line_elt(probe); + if (!probe_line) { + return; + } + chunk_indicator = c.chunk_indicator(probe_line); + if (chunk_indicator) { + break; + } + probe++; + } + + // There's a next chunk, `probe` points to it. + var begin = probe; + + // Find the end of this chunk. + var next_indicator = chunk_indicator; + while (next_indicator === chunk_indicator) { + probe++; + probe_line = c.line_elt(probe); + next_indicator = c.chunk_indicator(probe_line); + } + c.set_sel(begin, probe); + c.show_selection(); +}; + +coverage.to_prev_chunk = function () { + const c = coverage; + + // Find the end of the prev colored chunk. + var probe = c.sel_begin-1; + var probe_line = c.line_elt(probe); + if (!probe_line) { + return; + } + var chunk_indicator = c.chunk_indicator(probe_line); + while (probe > 1 && !chunk_indicator) { + probe--; + probe_line = c.line_elt(probe); + if (!probe_line) { + return; + } + chunk_indicator = c.chunk_indicator(probe_line); + } + + // There's a prev chunk, `probe` points to its last line. + var end = probe+1; + + // Find the beginning of this chunk. + var prev_indicator = chunk_indicator; + while (prev_indicator === chunk_indicator) { + probe--; + if (probe <= 0) { + return; + } + probe_line = c.line_elt(probe); + prev_indicator = c.chunk_indicator(probe_line); + } + c.set_sel(probe+1, end); + c.show_selection(); +}; + +// Returns 0, 1, or 2: how many of the two ends of the selection are on +// the screen right now? +coverage.selection_ends_on_screen = function () { + if (coverage.sel_begin === 0) { + return 0; + } + + const begin = coverage.line_elt(coverage.sel_begin); + const end = coverage.line_elt(coverage.sel_end-1); + + return ( + (checkVisible(begin) ? 1 : 0) + + (checkVisible(end) ? 1 : 0) + ); +}; + +coverage.to_next_chunk_nicely = function () { + if (coverage.selection_ends_on_screen() === 0) { + // The selection is entirely off the screen: + // Set the top line on the screen as selection. + + // This will select the top-left of the viewport + // As this is most likely the span with the line number we take the parent + const line = document.elementFromPoint(0, 0).parentElement; + if (line.parentElement !== document.getElementById("source")) { + // The element is not a source line but the header or similar + coverage.select_line_or_chunk(1); + } else { + // We extract the line number from the id + coverage.select_line_or_chunk(parseInt(line.id.substring(1), 10)); + } + } + coverage.to_next_chunk(); +}; + +coverage.to_prev_chunk_nicely = function () { + if (coverage.selection_ends_on_screen() === 0) { + // The selection is entirely off the screen: + // Set the lowest line on the screen as selection. + + // This will select the bottom-left of the viewport + // As this is most likely the span with the line number we take the parent + const line = document.elementFromPoint(document.documentElement.clientHeight-1, 0).parentElement; + if (line.parentElement !== document.getElementById("source")) { + // The element is not a source line but the header or similar + coverage.select_line_or_chunk(coverage.lines_len); + } else { + // We extract the line number from the id + coverage.select_line_or_chunk(parseInt(line.id.substring(1), 10)); + } + } + coverage.to_prev_chunk(); +}; + +// Select line number lineno, or if it is in a colored chunk, select the +// entire chunk +coverage.select_line_or_chunk = function (lineno) { + var c = coverage; + var probe_line = c.line_elt(lineno); + if (!probe_line) { + return; + } + var the_indicator = c.chunk_indicator(probe_line); + if (the_indicator) { + // The line is in a highlighted chunk. + // Search backward for the first line. + var probe = lineno; + var indicator = the_indicator; + while (probe > 0 && indicator === the_indicator) { + probe--; + probe_line = c.line_elt(probe); + if (!probe_line) { + break; + } + indicator = c.chunk_indicator(probe_line); + } + var begin = probe + 1; + + // Search forward for the last line. + probe = lineno; + indicator = the_indicator; + while (indicator === the_indicator) { + probe++; + probe_line = c.line_elt(probe); + indicator = c.chunk_indicator(probe_line); + } + + coverage.set_sel(begin, probe); + } + else { + coverage.set_sel(lineno); + } +}; + +coverage.show_selection = function () { + // Highlight the lines in the chunk + document.querySelectorAll("#source .highlight").forEach(e => e.classList.remove("highlight")); + for (let probe = coverage.sel_begin; probe < coverage.sel_end; probe++) { + coverage.line_elt(probe).querySelector(".n").classList.add("highlight"); + } + + coverage.scroll_to_selection(); +}; + +coverage.scroll_to_selection = function () { + // Scroll the page if the chunk isn't fully visible. + if (coverage.selection_ends_on_screen() < 2) { + const element = coverage.line_elt(coverage.sel_begin); + coverage.scroll_window(element.offsetTop - 60); + } +}; + +coverage.scroll_window = function (to_pos) { + window.scroll({top: to_pos, behavior: "smooth"}); +}; + +coverage.init_scroll_markers = function () { + // Init some variables + coverage.lines_len = document.querySelectorAll("#source > p").length; + + // Build html + coverage.build_scroll_markers(); +}; + +coverage.build_scroll_markers = function () { + const temp_scroll_marker = document.getElementById("scroll_marker") + if (temp_scroll_marker) temp_scroll_marker.remove(); + // Don't build markers if the window has no scroll bar. + if (document.body.scrollHeight <= window.innerHeight) { + return; + } + + const marker_scale = window.innerHeight / document.body.scrollHeight; + const line_height = Math.min(Math.max(3, window.innerHeight / coverage.lines_len), 10); + + let previous_line = -99, last_mark, last_top; + + const scroll_marker = document.createElement("div"); + scroll_marker.id = "scroll_marker"; + document.getElementById("source").querySelectorAll( + "p.show_run, p.show_mis, p.show_exc, p.show_exc, p.show_par" + ).forEach(element => { + const line_top = Math.floor(element.offsetTop * marker_scale); + const line_number = parseInt(element.querySelector(".n a").id.substr(1)); + + if (line_number === previous_line + 1) { + // If this solid missed block just make previous mark higher. + last_mark.style.height = `${line_top + line_height - last_top}px`; + } else { + // Add colored line in scroll_marker block. + last_mark = document.createElement("div"); + last_mark.id = `m${line_number}`; + last_mark.classList.add("marker"); + last_mark.style.height = `${line_height}px`; + last_mark.style.top = `${line_top}px`; + scroll_marker.append(last_mark); + last_top = line_top; + } + + previous_line = line_number; + }); + + // Append last to prevent layout calculation + document.body.append(scroll_marker); +}; + +coverage.wire_up_sticky_header = function () { + const header = document.querySelector("header"); + const header_bottom = ( + header.querySelector(".content h2").getBoundingClientRect().top - + header.getBoundingClientRect().top + ); + + function updateHeader() { + if (window.scrollY > header_bottom) { + header.classList.add("sticky"); + } else { + header.classList.remove("sticky"); + } + } + + window.addEventListener("scroll", updateHeader); + updateHeader(); +}; + +coverage.expand_contexts = function (e) { + var ctxs = e.target.parentNode.querySelector(".ctxs"); + + if (!ctxs.classList.contains("expanded")) { + var ctxs_text = ctxs.textContent; + var width = Number(ctxs_text[0]); + ctxs.textContent = ""; + for (var i = 1; i < ctxs_text.length; i += width) { + key = ctxs_text.substring(i, i + width).trim(); + ctxs.appendChild(document.createTextNode(contexts[key])); + ctxs.appendChild(document.createElement("br")); + } + ctxs.classList.add("expanded"); + } +}; + +document.addEventListener("DOMContentLoaded", () => { + if (document.body.classList.contains("indexfile")) { + coverage.index_ready(); + } else { + coverage.pyfile_ready(); + } +}); diff --git a/coverage/d_bb657af29d23493a_Attributes_py.html b/coverage/d_bb657af29d23493a_Attributes_py.html new file mode 100644 index 00000000..81cedfe0 --- /dev/null +++ b/coverage/d_bb657af29d23493a_Attributes_py.html @@ -0,0 +1,152 @@ + + + + ++ « prev + ^ index + » next + + coverage.py v7.3.0, + created at 2023-08-24 21:52 +0000 +
+ +1# ==================================================================================================================== #
+2# _____ ____ _ _ ____ _ _ __ __ _ _ #
+3# _ __ _ _| ____| _ \ / \ / \ | _ \ _ __ ___ (_) ___ ___| |_| \/ | ___ __| | ___| | #
+4# | '_ \| | | | _| | | | |/ _ \ / _ \ | |_) | '__/ _ \| |/ _ \/ __| __| |\/| |/ _ \ / _` |/ _ \ | #
+5# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| __/| | | (_) | | __/ (__| |_| | | | (_) | (_| | __/ | #
+6# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_| |_| \___// |\___|\___|\__|_| |_|\___/ \__,_|\___|_| #
+7# |_| |___/ |__/ #
+8# ==================================================================================================================== #
+9# Authors: #
+10# Patrick Lehmann #
+11# #
+12# License: #
+13# ==================================================================================================================== #
+14# Copyright 2017-2023 Patrick Lehmann - Boetzingen, Germany #
+15# #
+16# Licensed under the Apache License, Version 2.0 (the "License"); #
+17# you may not use this file except in compliance with the License. #
+18# You may obtain a copy of the License at #
+19# #
+20# http://www.apache.org/licenses/LICENSE-2.0 #
+21# #
+22# Unless required by applicable law or agreed to in writing, software #
+23# distributed under the License is distributed on an "AS IS" BASIS, #
+24# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
+25# See the License for the specific language governing permissions and #
+26# limitations under the License. #
+27# #
+28# SPDX-License-Identifier: Apache-2.0 #
+29# ==================================================================================================================== #
+30#
+31"""A set of common attributes to store meta information on ProjectModel entities (project, design, fileset, file, ...)."""
+32from typing import Dict
+33from pyTooling.Decorators import export
+ +35from pyEDAA.ProjectModel import Attribute
+ + +38@export
+39class KeyValueAttribute(Attribute):
+40 KEY = "ID"
+ +42 _keyValuePairs: Dict[str, str]
+ +44 def __init__(self):
+45 super().__init__()
+ +47 self._keyValuePairs = {}
+ +49 def __getitem__(self, item: str) -> str:
+50 return self._keyValuePairs[item]
+ +52 def __setitem__(self, key: str, value: str) -> None:
+53 self._keyValuePairs[key] = value
++ « prev + ^ index + » next + + coverage.py v7.3.0, + created at 2023-08-24 21:52 +0000 +
+ +1# ==================================================================================================================== #
+2# _____ ____ _ _ ____ _ _ __ __ _ _ #
+3# _ __ _ _| ____| _ \ / \ / \ | _ \ _ __ ___ (_) ___ ___| |_| \/ | ___ __| | ___| | #
+4# | '_ \| | | | _| | | | |/ _ \ / _ \ | |_) | '__/ _ \| |/ _ \/ __| __| |\/| |/ _ \ / _` |/ _ \ | #
+5# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| __/| | | (_) | | __/ (__| |_| | | | (_) | (_| | __/ | #
+6# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_| |_| \___// |\___|\___|\__|_| |_|\___/ \__,_|\___|_| #
+7# |_| |___/ |__/ #
+8# ==================================================================================================================== #
+9# Authors: #
+10# Patrick Lehmann #
+11# #
+12# License: #
+13# ==================================================================================================================== #
+14# Copyright 2017-2023 Patrick Lehmann - Boetzingen, Germany #
+15# Copyright 2014-2016 Technische Universität Dresden - Germany, Chair of VLSI-Design, Diagnostics and Architecture #
+16# #
+17# Licensed under the Apache License, Version 2.0 (the "License"); #
+18# you may not use this file except in compliance with the License. #
+19# You may obtain a copy of the License at #
+20# #
+21# http://www.apache.org/licenses/LICENSE-2.0 #
+22# #
+23# Unless required by applicable law or agreed to in writing, software #
+24# distributed under the License is distributed on an "AS IS" BASIS, #
+25# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
+26# See the License for the specific language governing permissions and #
+27# limitations under the License. #
+28# #
+29# SPDX-License-Identifier: Apache-2.0 #
+30# ==================================================================================================================== #
+31#
+32"""An abstract model of EDA tool projects."""
+33__author__ = "Patrick Lehmann"
+34__email__ = "Paebbels@gmail.com"
+35__copyright__ = "2014-2023, Patrick Lehmann, Unai Martinez-Corral"
+36__license__ = "Apache License, Version 2.0"
+37__version__ = "0.5.0"
+38__keywords__ = ["eda project", "model", "abstract", "xilinx", "vivado", "osvvm", "file set", "file group", "test bench", "test harness"]
+ +40from os.path import relpath as path_relpath
+41from pathlib import Path as pathlib_Path
+42from typing import Dict, Union, Optional as Nullable, List, Iterable, Generator, Tuple, Any as typing_Any, Type, Set, Any
+ +44from pyTooling.Decorators import export
+45from pyTooling.MetaClasses import ExtendedType
+46from pyTooling.Graph import Graph, Vertex
+47from pySVModel import SystemVerilogVersion
+48from pyVHDLModel import VHDLVersion
+49from pySystemRDLModel import SystemRDLVersion
+ + +52@export
+53class Attribute(metaclass=ExtendedType):
+54 KEY: str
+55 VALUE_TYPE: typing_Any
+ +57 @staticmethod
+58 def resolve(obj: typing_Any, key: Type['Attribute']):
+59 if isinstance(obj, File): 59 ↛ 61line 59 didn't jump to line 61, because the condition on line 59 was never false
+60 return obj._fileSet[key]
+61 elif isinstance(obj, FileSet):
+62 return obj._design[key]
+63 elif isinstance(obj, Design):
+64 return obj._project[key]
+65 else:
+66 raise Exception("Resolution error")
+ + +69@export
+70class FileType(ExtendedType):
+71 """
+72 A :term:`meta-class` to construct *FileType* classes.
+ +74 Modifications done by this meta-class:
+75 * Register all classes of type :class:`FileType` or derived variants in a class field :attr:`FileType.FileTypes` in this meta-class.
+76 """
+ +78 FileTypes: Dict[str, 'FileType'] = {} #: Dictionary of all classes of type :class:`FileType` or derived variants
+79 Any: 'FileType'
+ +81 def __init__(cls, name: str, bases: Tuple[type, ...], dictionary: Dict[str, typing_Any], **kwargs):
+82 super().__init__(name, bases, dictionary, **kwargs)
+83 cls.Any = cls
+ +85 def __new__(cls, className, baseClasses, classMembers: Dict, *args, **kwargs):
+86 fileType = super().__new__(cls, className, baseClasses, classMembers, *args, **kwargs)
+87 cls.FileTypes[className] = fileType
+88 return fileType
+ +90 def __getattr__(cls, item) -> 'FileType':
+91 if item[:2] != "__" and item[-2:] != "__":
+92 return cls.FileTypes[item]
+93 else:
+94 return super().__getattribute__(item)
+ +96 def __contains__(cls, item) -> bool:
+97 return issubclass(item, cls)
+ + +100@export
+101class File(metaclass=FileType, slots=True):
+102 """
+103 A :term:`File` represents a file in a design. This :term:`base-class` is used
+104 for all derived file classes.
+ +106 A file can be created standalone and later associated to a fileset, design and
+107 project. Or a fileset, design and/or project can be associated immediately
+108 while creating a file.
+ +110 :arg path: Relative or absolute path to the file.
+111 :arg project: Project the file is associated with.
+112 :arg design: Design the file is associated with.
+113 :arg fileSet: Fileset the file is associated with.
+114 """
+ +116 _path: pathlib_Path
+117 _fileType: 'FileType'
+118 _project: Nullable['Project']
+119 _design: Nullable['Design']
+120 _fileSet: Nullable['FileSet']
+121 _attributes: Dict[Type[Attribute], typing_Any]
+ +123 def __init__(
+124 self,
+125 path: pathlib_Path,
+126 project: 'Project' = None,
+127 design: 'Design' = None,
+128 fileSet: 'FileSet' = None
+129 ):
+130 self._fileType = getattr(FileTypes, self.__class__.__name__)
+131 self._path = path
+132 if project is not None:
+133 self._project = project
+134 self._design = design
+135 if fileSet is not None: 135 ↛ 136line 135 didn't jump to line 136, because the condition on line 135 was never true
+136 self.FileSet = fileSet
+137 elif design is not None:
+138 self._project = design._project
+139 self._design = design
+140 self.FileSet = design.DefaultFileSet if fileSet is None else fileSet
+141 elif fileSet is not None:
+142 design = fileSet._design
+143 if design is not None:
+144 self._project = design._project
+145 else:
+146 self._project = None
+147 self._design = design
+148 self.FileSet = fileSet
+149 else:
+150 self._project = None
+151 self._design = None
+152 self._fileSet = None
+ +154 self._attributes = {}
+155 self._registerAttributes()
+ +157 def _registerAttributes(self):
+158 pass
+ +160 @property
+161 def FileType(self) -> 'FileType':
+162 """Read-only property to return the file type of this file."""
+163 return self._fileType
+ +165 @property
+166 def Path(self) -> pathlib_Path:
+167 """Read-only property returning the path of this file."""
+168 return self._path
+ +170 # TODO: setter?
+ +172 @property
+173 def ResolvedPath(self) -> pathlib_Path:
+174 """Read-only property returning the resolved path of this file."""
+175 if self._path.is_absolute(): 175 ↛ 176line 175 didn't jump to line 176, because the condition on line 175 was never true
+176 return self._path.resolve()
+177 elif self._fileSet is not None: 177 ↛ 187line 177 didn't jump to line 187, because the condition on line 177 was never false
+178 path = (self._fileSet.ResolvedPath / self._path).resolve()
+ +180 if path.is_absolute(): 180 ↛ 184line 180 didn't jump to line 184, because the condition on line 180 was never false
+181 return path
+182 else:
+183 # WORKAROUND: https://stackoverflow.com/questions/67452690/pathlib-path-relative-to-vs-os-path-relpath
+184 return pathlib_Path(path_relpath(path, pathlib_Path.cwd()))
+185 else:
+186 # TODO: message and exception type
+187 raise Exception("")
+ +189 @property
+190 def Project(self) -> Nullable['Project']:
+191 """Property setting or returning the project this file is used in."""
+192 return self._project
+ +194 @Project.setter
+195 def Project(self, value: 'Project') -> None:
+196 self._project = value
+ +198 if self._fileSet is None: 198 ↛ exitline 198 didn't return from function 'Project', because the condition on line 198 was never false
+199 self._project.DefaultDesign.DefaultFileSet.AddFile(self)
+ +201 @property
+202 def Design(self) -> Nullable['Design']:
+203 """Property setting or returning the design this file is used in."""
+204 return self._design
+ +206 @Design.setter
+207 def Design(self, value: 'Design') -> None:
+208 self._design = value
+ +210 if self._fileSet is None: 210 ↛ 213line 210 didn't jump to line 213, because the condition on line 210 was never false
+211 self._design.DefaultFileSet.AddFile(self)
+ +213 if self._project is None: 213 ↛ 215line 213 didn't jump to line 215, because the condition on line 213 was never false
+214 self._project = value._project
+215 elif self._project is not value._project:
+216 raise Exception("The design's project is not identical to the already assigned project.")
+ +218 @property
+219 def FileSet(self) -> Nullable['FileSet']:
+220 """Property setting or returning the fileset this file is used in."""
+221 return self._fileSet
+ +223 @FileSet.setter
+224 def FileSet(self, value: 'FileSet') -> None:
+225 self._fileSet = value
+226 value._files.append(self)
+ +228 def Validate(self):
+229 """Validate this file."""
+230 if self._path is None: 230 ↛ 231line 230 didn't jump to line 231, because the condition on line 230 was never true
+231 raise Exception("Validation: File has no path.")
+232 try:
+233 path = self.ResolvedPath
+234 except Exception as ex:
+235 raise Exception(f"Validation: File '{self._path}' could not compute resolved path.") from ex
+236 if not path.exists(): 236 ↛ 237line 236 didn't jump to line 237, because the condition on line 236 was never true
+237 raise Exception(f"Validation: File '{self._path}' (={path}) does not exist.")
+238 if not path.is_file(): 238 ↛ 239line 238 didn't jump to line 239, because the condition on line 238 was never true
+239 raise Exception(f"Validation: File '{self._path}' (={path}) is not a file.")
+ +241 if self._fileSet is None: 241 ↛ 242line 241 didn't jump to line 242, because the condition on line 241 was never true
+242 raise Exception(f"Validation: File '{self._path}' has no fileset.")
+243 if self._design is None: 243 ↛ 244line 243 didn't jump to line 244, because the condition on line 243 was never true
+244 raise Exception(f"Validation: File '{self._path}' has no design.")
+245 if self._project is None: 245 ↛ 246line 245 didn't jump to line 246, because the condition on line 245 was never true
+246 raise Exception(f"Validation: File '{self._path}' has no project.")
+ +248 def __len__(self) -> int:
+249 """
+250 Returns number of attributes set on this file.
+ +252 :returns: The number if attributes set on this file.
+253 """
+254 return len(self._attributes)
+ +256 def __getitem__(self, key: Type[Attribute]) -> Any:
+257 """Index access for returning attributes on this file.
+ +259 :param key: The attribute type.
+260 :returns: The attribute's value.
+261 :raises TypeError: When parameter 'key' is not a subclass of Attribute.
+262 """
+263 if not issubclass(key, Attribute): 263 ↛ 264line 263 didn't jump to line 264, because the condition on line 263 was never true
+264 raise TypeError("Parameter 'key' is not an 'Attribute'.")
+ +266 try:
+267 return self._attributes[key]
+268 except KeyError:
+269 return key.resolve(self, key)
+ +271 def __setitem__(self, key: Type[Attribute], value: typing_Any) -> None:
+272 """
+273 Index access for adding or setting attributes on this file.
+ +275 :param key: The attribute type.
+276 :param value: The attributes value.
+277 :raises TypeError: When parameter 'key' is not a subclass of Attribute.
+278 """
+279 if not issubclass(key, Attribute): 279 ↛ 280line 279 didn't jump to line 280, because the condition on line 279 was never true
+280 raise TypeError("Parameter 'key' is not an 'Attribute'.")
+ +282 self._attributes[key] = value
+ +284 def __delitem__(self, key: Type[Attribute]) -> None:
+285 """
+286 Index access for deleting attributes on this file.
+ +288 :param key: The attribute type.
+289 """
+290 if not issubclass(key, Attribute):
+291 raise TypeError("Parameter 'key' is not an 'Attribute'.")
+ +293 del self._attributes[key]
+ +295 def __str__(self) -> str:
+296 return f"{self._path}"
+ + +299FileTypes = File
+ + +302@export
+303class HumanReadableContent(metaclass=ExtendedType, mixin=True):
+304 """A file type representing human-readable contents."""
+ + +307@export
+308class XMLContent(HumanReadableContent, mixin=True):
+309 """A file type representing XML contents."""
+ + +312@export
+313class YAMLContent(HumanReadableContent, mixin=True):
+314 """A file type representing YAML contents."""
+ + +317@export
+318class JSONContent(HumanReadableContent, mixin=True):
+319 """A file type representing JSON contents."""
+ + +322@export
+323class INIContent(HumanReadableContent, mixin=True):
+324 """A file type representing INI contents."""
+ + +327@export
+328class TOMLContent(HumanReadableContent, mixin=True):
+329 """A file type representing TOML contents."""
+ + +332@export
+333class TCLContent(HumanReadableContent, mixin=True):
+334 """A file type representing content in TCL code."""
+ + +337@export
+338class SDCContent(TCLContent, mixin=True):
+339 """A file type representing contents as Synopsys Design Constraints (SDC)."""
+ + +342@export
+343class PythonContent(HumanReadableContent, mixin=True):
+344 """A file type representing contents as Python source code."""
+ + +347@export
+348class TextFile(File, HumanReadableContent):
+349 """A text file (``*.txt``)."""
+ + +352@export
+353class LogFile(File, HumanReadableContent):
+354 """A log file (``*.log``)."""
+ + +357@export
+358class XMLFile(File, XMLContent):
+359 """An XML file (``*.xml``)."""
+ + +362@export
+363class SourceFile(File):
+364 """Base-class of all source files."""
+ + +367@export
+368class HDLSourceFile(SourceFile):
+369 """Base-class of all HDL source files."""
+ + +372@export
+373class RDLSourceFile(SourceFile):
+374 """Base-class of all RDL source files."""
+ + +377@export
+378class NetlistFile(SourceFile):
+379 """Base-class of all netlist source files."""
+ + +382@export
+383class EDIFNetlistFile(NetlistFile):
+384 """Netlist file in EDIF (Electronic Design Interchange Format)."""
+ + +387@export
+388class TCLSourceFile(SourceFile, TCLContent):
+389 """A TCL source file."""
+ + +392@export
+393class VHDLSourceFile(HDLSourceFile, HumanReadableContent):
+394 """
+395 A VHDL source file (of any language version).
+ +397 :arg path: Relative or absolute path to the file.
+398 :arg vhdlLibrary: VHDLLibrary this VHDL source file is associated wih.
+399 :arg vhdlVersion: VHDLVersion this VHDL source file is associated wih.
+400 :arg project: Project the file is associated with.
+401 :arg design: Design the file is associated with.
+402 :arg fileSet: Fileset the file is associated with.
+403 """
+ +405 _vhdlLibrary: Nullable['VHDLLibrary']
+406 _vhdlVersion: VHDLVersion
+ +408 def __init__(self, path: pathlib_Path, vhdlLibrary: Union[str, 'VHDLLibrary'] = None, vhdlVersion: VHDLVersion = None, project: 'Project' = None, design: 'Design' = None, fileSet: 'FileSet' = None):
+409 super().__init__(path, project, design, fileSet)
+ +411 if isinstance(vhdlLibrary, str): 411 ↛ 412line 411 didn't jump to line 412, because the condition on line 411 was never true
+412 if design is not None:
+413 try:
+414 vhdlLibrary = design.VHDLLibraries[vhdlLibrary]
+415 except KeyError as ex:
+416 raise Exception(f"VHDL library '{vhdlLibrary}' not found in design '{design.Name}'.") from ex
+417 elif project is not None:
+418 try:
+419 vhdlLibrary = project.DefaultDesign.VHDLLibraries[vhdlLibrary]
+420 except KeyError as ex:
+421 raise Exception(f"VHDL library '{vhdlLibrary}' not found in default design '{project.DefaultDesign.Name}'.") from ex
+422 else:
+423 raise Exception(f"Can't lookup VHDL library because neither 'project' nor 'design' is given as a parameter.")
+424 elif isinstance(vhdlLibrary, VHDLLibrary):
+425 self._vhdlLibrary = vhdlLibrary
+426 vhdlLibrary.AddFile(self)
+427 elif vhdlLibrary is None: 427 ↛ 430line 427 didn't jump to line 430, because the condition on line 427 was never false
+428 self._vhdlLibrary = None
+429 else:
+430 raise TypeError(f"Parameter 'vhdlLibrary' is neither a 'str' nor 'VHDLibrary'.")
+ +432 self._vhdlVersion = vhdlVersion
+ +434 def Validate(self) -> None:
+435 """Validate this VHDL source file."""
+436 super().Validate()
+ +438 try:
+439 _ = self.VHDLLibrary
+440 except Exception as ex:
+441 raise Exception(f"Validation: VHDLSourceFile '{self._path}' (={self.ResolvedPath}) has no VHDLLibrary assigned.") from ex
+442 try:
+443 _ = self.VHDLVersion
+444 except Exception as ex:
+445 raise Exception(f"Validation: VHDLSourceFile '{self._path}' (={self.ResolvedPath}) has no VHDLVersion assigned.") from ex
+ +447 @property
+448 def VHDLLibrary(self) -> 'VHDLLibrary':
+449 """Property setting or returning the VHDL library this VHDL source file is used in."""
+450 if self._vhdlLibrary is not None:
+451 return self._vhdlLibrary
+452 elif self._fileSet is not None:
+453 return self._fileSet.VHDLLibrary
+454 else:
+455 raise Exception("VHDLLibrary was neither set locally nor globally.")
+ +457 @VHDLLibrary.setter
+458 def VHDLLibrary(self, value: 'VHDLLibrary') -> None:
+459 self._vhdlLibrary = value
+460 value._files.append(self)
+ +462 @property
+463 def VHDLVersion(self) -> VHDLVersion:
+464 """Property setting or returning the VHDL version this VHDL source file is used in."""
+465 if self._vhdlVersion is not None:
+466 return self._vhdlVersion
+467 elif self._fileSet is not None:
+468 return self._fileSet.VHDLVersion
+469 else:
+470 raise Exception("VHDLVersion was neither set locally nor globally.")
+ +472 @VHDLVersion.setter
+473 def VHDLVersion(self, value: VHDLVersion) -> None:
+474 self._vhdlVersion = value
+ +476 def __repr__(self) -> str:
+477 return f"<VHDL file: '{self.ResolvedPath}'; lib: '{self.VHDLLibrary}'; version: {self.VHDLVersion}>"
+ + +480class VerilogMixIn(metaclass=ExtendedType, mixin=True):
+481 @property
+482 def VerilogVersion(self) -> SystemVerilogVersion:
+483 """Property setting or returning the Verilog version this Verilog source file is used in."""
+484 if self._version is not None:
+485 return self._version
+486 elif self._fileSet is not None:
+487 return self._fileSet.VerilogVersion
+488 else:
+489 raise Exception("VerilogVersion was neither set locally nor globally.")
+ +491 @VerilogVersion.setter
+492 def VerilogVersion(self, value: SystemVerilogVersion) -> None:
+493 self._version = value
+ + +496class SystemVerilogMixIn(metaclass=ExtendedType, mixin=True):
+497 @property
+498 def SVVersion(self) -> SystemVerilogVersion:
+499 """Property setting or returning the SystemVerilog version this SystemVerilog source file is used in."""
+500 if self._version is not None:
+501 return self._version
+502 elif self._fileSet is not None:
+503 return self._fileSet.SVVersion
+504 else:
+505 raise Exception("SVVersion was neither set locally nor globally.")
+ +507 @SVVersion.setter
+508 def SVVersion(self, value: SystemVerilogVersion) -> None:
+509 self._version = value
+ + +512@export
+513class VerilogBaseFile(HDLSourceFile, HumanReadableContent):
+514 _version: SystemVerilogVersion
+ +516 def __init__(self, path: pathlib_Path, version: SystemVerilogVersion = None, project: 'Project' = None, design: 'Design' = None, fileSet: 'FileSet' = None):
+517 super().__init__(path, project, design, fileSet)
+ +519 self._version = version
+ + +522@export
+523class VerilogSourceFile(VerilogBaseFile, VerilogMixIn):
+524 """A Verilog source file (of any language version)."""
+ + +527@export
+528class VerilogHeaderFile(VerilogBaseFile, VerilogMixIn):
+529 """A Verilog header file (of any language version)."""
+ + +532@export
+533class SystemVerilogBaseFile(VerilogBaseFile):
+534 ...
+ + +537@export
+538class SystemVerilogSourceFile(SystemVerilogBaseFile, SystemVerilogMixIn):
+539 """A SystemVerilog source file (of any language version)."""
+ + +542@export
+543class SystemVerilogHeaderFile(SystemVerilogBaseFile, SystemVerilogMixIn):
+544 """A SystemVerilog header file (of any language version)."""
+ + +547@export
+548class SystemRDLSourceFile(RDLSourceFile, HumanReadableContent):
+549 """A SystemRDL source file (of any language version)."""
+ +551 _srdlVersion: SystemRDLVersion
+ +553 def __init__(self, path: pathlib_Path, srdlVersion: SystemRDLVersion = None, project: 'Project' = None, design: 'Design' = None, fileSet: 'FileSet' = None):
+554 super().__init__(path, project, design, fileSet)
+ +556 self._srdlVersion = srdlVersion
+ +558 @property
+559 def SystemRDLVersion(self) -> SystemRDLVersion:
+560 """Property setting or returning the SystemRDL version this SystemRDL source file is used in."""
+561 if self._srdlVersion is not None:
+562 return self._srdlVersion
+563 elif self._fileSet is not None:
+564 return self._fileSet.SRDLVersion
+565 else:
+566 raise Exception("SRDLVersion was neither set locally nor globally.")
+ +568 @SystemRDLVersion.setter
+569 def SystemRDLVersion(self, value: SystemRDLVersion) -> None:
+570 self._srdlVersion = value
+ + +573@export
+574class PythonSourceFile(SourceFile, PythonContent):
+575 """A Python source file."""
+ + +578# TODO: move to a Cocotb module
+579@export
+580class CocotbPythonFile(PythonSourceFile):
+581 """A Python source file used by Cocotb."""
+ + +584@export
+585class ConstraintFile(File, HumanReadableContent):
+586 """Base-class of all constraint files."""
+ + +589@export
+590class ProjectFile(File):
+591 """Base-class of all tool-specific project files."""
+ + +594@export
+595class CSourceFile(SourceFile):
+596 """Base-class of all ANSI-C source files."""
+ + +599@export
+600class CppSourceFile(SourceFile):
+601 """Base-class of all ANSI-C++ source files."""
+ + +604@export
+605class SettingFile(File):
+606 """Base-class of all tool-specific setting files."""
+ + +609@export
+610class SimulationAnalysisFile(File):
+611 """Base-class of all tool-specific analysis files."""
+ + +614@export
+615class SimulationElaborationFile(File):
+616 """Base-class of all tool-specific elaboration files."""
+ + +619@export
+620class SimulationStartFile(File):
+621 """Base-class of all tool-specific simulation start-up files."""
+ + +624@export
+625class SimulationRunFile(File):
+626 """Base-class of all tool-specific simulation run (execution) files."""
+ + +629@export
+630class WaveformConfigFile(File):
+631 """Base-class of all tool-specific waveform configuration files."""
+ + +634@export
+635class WaveformDatabaseFile(File):
+636 """Base-class of all tool-specific waveform database files."""
+ + +639@export
+640class WaveformExchangeFile(File):
+641 """Base-class of all tool-independent waveform exchange files."""
+ + +644@export
+645class FileSet(metaclass=ExtendedType, slots=True):
+646 """
+647 A :term:`FileSet` represents a group of files. Filesets can have sub-filesets.
+ +649 The order of insertion is preserved. A fileset can be created standalone and
+650 later associated to another fileset, design and/or project. Or a fileset,
+651 design and/or project can be associated immediately while creating the
+652 fileset.
+ +654 :arg name: Name of this fileset.
+655 :arg topLevel: Name of the fileset's toplevel.
+656 :arg directory: Path of this fileset (absolute or relative to a parent fileset or design).
+657 :arg project: Project the file is associated with.
+658 :arg design: Design the file is associated with.
+659 :arg parent: Parent fileset if this fileset is nested.
+660 :arg vhdlLibrary: Default VHDL library for files in this fileset, if not specified for the file itself.
+661 :arg vhdlVersion: Default VHDL version for files in this fileset, if not specified for the file itself.
+662 :arg verilogVersion: Default Verilog version for files in this fileset, if not specified for the file itself.
+663 :arg svVersion: Default SystemVerilog version for files in this fileset, if not specified for the file itself.
+664 :arg srdlVersion: Default SystemRDL version for files in this fileset, if not specified for the file itself.
+665 """
+ +667 _name: str
+668 _topLevel: Nullable[str]
+669 _project: Nullable['Project']
+670 _design: Nullable['Design']
+671 _directory: pathlib_Path
+672 _parent: Nullable['FileSet']
+673 _fileSets: Dict[str, 'FileSet']
+674 _files: List[File]
+675 _set: Set
+676 _attributes: Dict[Type[Attribute], typing_Any]
+677 _vhdlLibraries: Dict[str, 'VHDLLibrary']
+678 _vhdlLibrary: 'VHDLLibrary'
+679 _vhdlVersion: VHDLVersion
+680 _verilogVersion: SystemVerilogVersion
+681 _svVersion: SystemVerilogVersion
+682 _srdlVersion: SystemRDLVersion
+ +684 def __init__(
+685 self,
+686 name: str,
+687 topLevel: str = None,
+688 directory: pathlib_Path = pathlib_Path("."),
+689 project: 'Project' = None,
+690 design: 'Design' = None,
+691 parent: Nullable['FileSet'] = None,
+692 vhdlLibrary: Union[str, 'VHDLLibrary'] = None,
+693 vhdlVersion: VHDLVersion = None,
+694 verilogVersion: SystemVerilogVersion = None,
+695 svVersion: SystemVerilogVersion = None,
+696 srdlVersion: SystemRDLVersion = None
+697 ):
+698 self._name = name
+699 self._topLevel = topLevel
+700 if project is not None:
+701 self._project = project
+702 self._design = design if design is not None else project.DefaultDesign
+ +704 elif design is not None:
+705 self._project = design._project
+706 self._design = design
+707 else:
+708 self._project = None
+709 self._design = None
+710 self._directory = directory
+711 self._parent = parent
+712 self._fileSets = {}
+713 self._files = []
+714 self._set = set()
+ +716 if design is not None:
+717 design._fileSets[name] = self
+ +719 self._attributes = {}
+720 self._vhdlLibraries = {}
+ +722 # TODO: handle if vhdlLibrary is a string
+723 self._vhdlLibrary = vhdlLibrary
+724 self._vhdlVersion = vhdlVersion
+725 self._verilogVersion = verilogVersion
+726 self._svVersion = svVersion
+727 self._srdlVersion = srdlVersion
+ +729 @property
+730 def Name(self) -> str:
+731 """Property setting or returning the fileset's name."""
+732 return self._name
+ +734 @Name.setter
+735 def Name(self, value: str) -> None:
+736 self._name = value
+ +738 @property
+739 def TopLevel(self) -> str:
+740 """Property setting or returning the fileset's toplevel."""
+741 return self._topLevel
+ +743 @TopLevel.setter
+744 def TopLevel(self, value: str) -> None:
+745 self._topLevel = value
+ +747 @property
+748 def Project(self) -> Nullable['Project']:
+749 """Property setting or returning the project this fileset is used in."""
+750 return self._project
+ +752 @Project.setter
+753 def Project(self, value: 'Project') -> None:
+754 self._project = value
+ +756 @property
+757 def Design(self) -> Nullable['Design']:
+758 """Property setting or returning the design this fileset is used in."""
+759 if self._design is not None:
+760 return self._design
+761 elif self._parent is not None: 761 ↛ 762line 761 didn't jump to line 762, because the condition on line 761 was never true
+762 return self._parent.Design
+763 else:
+764 return None
+765 # TODO: raise exception instead
+766 # QUESTION: how to handle if design and parent is set?
+ +768 @Design.setter
+769 def Design(self, value: 'Design') -> None:
+770 self._design = value
+771 if self._project is None: 771 ↛ 773line 771 didn't jump to line 773, because the condition on line 771 was never false
+772 self._project = value._project
+773 elif self._project is not value._project:
+774 raise Exception("The design's project is not identical to the already assigned project.")
+ +776 @property
+777 def Directory(self) -> pathlib_Path:
+778 """Property setting or returning the directory this fileset is located in."""
+779 return self._directory
+ +781 @Directory.setter
+782 def Directory(self, value: pathlib_Path) -> None:
+783 self._directory = value
+ +785 @property
+786 def ResolvedPath(self) -> pathlib_Path:
+787 """Read-only property returning the resolved path of this fileset."""
+788 if self._directory.is_absolute(): 788 ↛ 789line 788 didn't jump to line 789, because the condition on line 788 was never true
+789 return self._directory.resolve()
+790 else:
+791 if self._parent is not None: 791 ↛ 792line 791 didn't jump to line 792, because the condition on line 791 was never true
+792 directory = self._parent.ResolvedPath
+793 elif self._design is not None: 793 ↛ 795line 793 didn't jump to line 795, because the condition on line 793 was never false
+794 directory = self._design.ResolvedPath
+795 elif self._project is not None:
+796 directory = self._project.ResolvedPath
+797 else:
+798 # TODO: message and exception type
+799 raise Exception("")
+ +801 directory = (directory / self._directory).resolve()
+802 if directory.is_absolute(): 802 ↛ 806line 802 didn't jump to line 806, because the condition on line 802 was never false
+803 return directory
+804 else:
+805 # WORKAROUND: https://stackoverflow.com/questions/67452690/pathlib-path-relative-to-vs-os-path-relpath
+806 return pathlib_Path(path_relpath(directory, pathlib_Path.cwd()))
+ +808 @property
+809 def Parent(self) -> Nullable['FileSet']:
+810 """Property setting or returning the parent fileset this fileset is used in."""
+811 return self._parent
+ +813 @Parent.setter
+814 def Parent(self, value: 'FileSet') -> None:
+815 self._parent = value
+816 value._fileSets[self._name] = self
+817 # TODO: check it it already exists
+818 # QUESTION: make an Add fileset method?
+ +820 @property
+821 def FileSets(self) -> Dict[str, 'FileSet']:
+822 """Read-only property returning the dictionary of sub-filesets."""
+823 return self._fileSets
+ +825 def Files(self, fileType: FileType = FileTypes.Any, fileSet: Union[bool, str, 'FileSet'] = None) -> Generator[File, None, None]:
+826 """
+827 Method returning the files of this fileset.
+ +829 :arg fileType: A filter for file types. Default: ``Any``.
+830 :arg fileSet: Specifies how to handle sub-filesets.
+831 """
+832 if fileSet is False: 832 ↛ 833line 832 didn't jump to line 833, because the condition on line 832 was never true
+833 for file in self._files:
+834 if file.FileType in fileType:
+835 yield file
+836 elif fileSet is None: 836 ↛ 844line 836 didn't jump to line 844, because the condition on line 836 was never false
+837 for fileSet in self._fileSets.values(): 837 ↛ 838line 837 didn't jump to line 838, because the loop on line 837 never started
+838 for file in fileSet.Files(fileType):
+839 yield file
+840 for file in self._files:
+841 if file.FileType in fileType:
+842 yield file
+843 else:
+844 if isinstance(fileSet, str):
+845 fileSetName = fileSet
+846 try:
+847 fileSet = self._fileSets[fileSetName]
+848 except KeyError as ex:
+849 raise Exception(f"Fileset {fileSetName} not bound to fileset {self.Name}.") from ex
+850 elif not isinstance(fileSet, FileSet):
+851 raise TypeError("Parameter 'fileSet' is not of type 'str' or 'FileSet' nor value 'None'.")
+ +853 for file in fileSet.Files(fileType):
+854 yield file
+ +856 def AddFileSet(self, fileSet: "FileSet") -> None:
+857 """
+858 Method to add a single sub-fileset to this fileset.
+ +860 :arg fileSet: A fileset to add to this fileset as sub-fileset.
+861 """
+862 if not isinstance(fileSet, FileSet): 862 ↛ 863line 862 didn't jump to line 863, because the condition on line 862 was never true
+863 raise ValueError("Parameter 'fileSet' is not of type ProjectModel.FileSet.")
+864 elif fileSet in self._fileSets: 864 ↛ 865line 864 didn't jump to line 865, because the condition on line 864 was never true
+865 raise Exception("Sub-fileset already contains this fileset.")
+866 elif fileSet.Name in self._fileSets.keys(): 866 ↛ 867line 866 didn't jump to line 867, because the condition on line 866 was never true
+867 raise Exception(f"Fileset already contains a sub-fileset named '{fileSet.Name}'.")
+ +869 self._fileSets[fileSet.Name] = fileSet
+870 fileSet._parent = self
+ +872 def AddFileSets(self, fileSets: Iterable["FileSet"]) -> None:
+873 """
+874 Method to add a multiple sub-filesets to this fileset.
+ +876 :arg fileSets: An iterable of filesets to add each to the fileset.
+877 """
+878 for fileSet in fileSets:
+879 self.AddFileSet(fileSet)
+ +881 @property
+882 def FileSetCount(self) -> int:
+883 """Returns number of file sets excl. sub-filesets."""
+884 return len(self._fileSets)
+ +886 @property
+887 def TotalFileSetCount(self) -> int:
+888 """Returns number of file sets incl. sub-filesets."""
+889 fileSetCount = len(self._fileSets)
+890 for fileSet in self._fileSets.values():
+891 fileSetCount += fileSet.TotalFileSetCount
+ +893 return fileSetCount
+ +895 def AddFile(self, file: File) -> None:
+896 """
+897 Method to add a single file to this fileset.
+ +899 :arg file: A file to add to this fileset.
+900 """
+901 if not isinstance(file, File):
+902 raise TypeError("Parameter 'file' is not of type ProjectModel.File.")
+903 elif file._fileSet is not None:
+904 ex = ValueError(f"File '{file.Path!s}' is already part of fileset '{file.FileSet.Name}'.")
+905 ex.add_note(f"A file can't be assigned to another fileset.")
+906 raise ex
+907 elif file in self._set: 907 ↛ 908line 907 didn't jump to line 908, because the condition on line 907 was never true
+908 ex = ValueError(f"File '{file.Path!s}' is already part of this fileset.")
+909 ex.add_note(f"A file can't be added twice to a fileset.")
+910 raise ex
+ +912 self._files.append(file)
+913 self._set.add(file)
+914 file._fileSet = self
+ +916 def AddFiles(self, files: Iterable[File]) -> None:
+917 """
+918 Method to add a multiple files to this fileset.
+ +920 :arg files: An iterable of files to add each to the fileset.
+921 """
+922 for file in files:
+923 self.AddFile(file)
+ +925 @property
+926 def FileCount(self) -> int:
+927 """Returns number of files excl. sub-filesets."""
+928 return len(self._files)
+ +930 @property
+931 def TotalFileCount(self) -> int:
+932 """Returns number of files incl. the files in sub-filesets."""
+933 fileCount = len(self._files)
+934 for fileSet in self._fileSets.values():
+935 fileCount += fileSet.FileCount
+ +937 return fileCount
+ +939 def Validate(self) -> None:
+940 """Validate this fileset."""
+941 if self._name is None or self._name == "": 941 ↛ 942line 941 didn't jump to line 942, because the condition on line 941 was never true
+942 raise Exception("Validation: FileSet has no name.")
+ +944 if self._directory is None: 944 ↛ 945line 944 didn't jump to line 945, because the condition on line 944 was never true
+945 raise Exception(f"Validation: FileSet '{self._name}' has no directory.")
+946 try:
+947 path = self.ResolvedPath
+948 except Exception as ex:
+949 raise Exception(f"Validation: FileSet '{self._name}' could not compute resolved path.") from ex
+950 if not path.exists(): 950 ↛ 951line 950 didn't jump to line 951, because the condition on line 950 was never true
+951 raise Exception(f"Validation: FileSet '{self._name}'s directory '{path}' does not exist.")
+952 if not path.is_dir(): 952 ↛ 953line 952 didn't jump to line 953, because the condition on line 952 was never true
+953 raise Exception(f"Validation: FileSet '{self._name}'s directory '{path}' is not a directory.")
+ +955 if self._design is None: 955 ↛ 956line 955 didn't jump to line 956, because the condition on line 955 was never true
+956 raise Exception(f"Validation: FileSet '{self._directory}' has no design.")
+957 if self._project is None: 957 ↛ 958line 957 didn't jump to line 958, because the condition on line 957 was never true
+958 raise Exception(f"Validation: FileSet '{self._directory}' has no project.")
+ +960 for fileSet in self._fileSets.values(): 960 ↛ 961line 960 didn't jump to line 961, because the loop on line 960 never started
+961 fileSet.Validate()
+962 for file in self._files: 962 ↛ 963line 962 didn't jump to line 963, because the loop on line 962 never started
+963 file.Validate()
+ +965 def GetOrCreateVHDLLibrary(self, name) -> 'VHDLLibrary':
+966 if name in self._vhdlLibraries:
+967 return self._vhdlLibraries[name]
+968 elif name in self._design._vhdlLibraries:
+969 library = self._design._vhdlLibraries[name]
+970 self._vhdlLibraries[name] = library
+971 return library
+972 else:
+973 library = VHDLLibrary(name, design=self._design, vhdlVersion=self._vhdlVersion)
+974 self._vhdlLibraries[name] = library
+975 return library
+ +977 @property
+978 def VHDLLibrary(self) -> 'VHDLLibrary':
+979 """Property setting or returning the VHDL library of this fileset."""
+980 if self._vhdlLibrary is not None:
+981 return self._vhdlLibrary
+982 elif self._parent is not None: 982 ↛ 984line 982 didn't jump to line 984, because the condition on line 982 was never false
+983 return self._parent.VHDLLibrary
+984 elif self._design is not None:
+985 return self._design.VHDLLibrary
+986 else:
+987 raise Exception("VHDLLibrary was neither set locally nor globally.")
+ +989 @VHDLLibrary.setter
+990 def VHDLLibrary(self, value: 'VHDLLibrary') -> None:
+991 self._vhdlLibrary = value
+ +993 @property
+994 def VHDLVersion(self) -> VHDLVersion:
+995 """Property setting or returning the VHDL version of this fileset."""
+996 if self._vhdlVersion is not None:
+997 return self._vhdlVersion
+998 elif self._parent is not None:
+999 return self._parent.VHDLVersion
+1000 elif self._design is not None: 1000 ↛ 1003line 1000 didn't jump to line 1003, because the condition on line 1000 was never false
+1001 return self._design.VHDLVersion
+1002 else:
+1003 raise Exception("VHDLVersion was neither set locally nor globally.")
+ +1005 @VHDLVersion.setter
+1006 def VHDLVersion(self, value: VHDLVersion) -> None:
+1007 self._vhdlVersion = value
+ +1009 @property
+1010 def VerilogVersion(self) -> SystemVerilogVersion:
+1011 """Property setting or returning the Verilog version of this fileset."""
+1012 if self._verilogVersion is not None:
+1013 return self._verilogVersion
+1014 elif self._parent is not None:
+1015 return self._parent.VerilogVersion
+1016 elif self._design is not None: 1016 ↛ 1019line 1016 didn't jump to line 1019, because the condition on line 1016 was never false
+1017 return self._design.VerilogVersion
+1018 else:
+1019 raise Exception("VerilogVersion was neither set locally nor globally.")
+ +1021 @VerilogVersion.setter
+1022 def VerilogVersion(self, value: SystemVerilogVersion) -> None:
+1023 self._verilogVersion = value
+ +1025 @property
+1026 def SVVersion(self) -> SystemVerilogVersion:
+1027 """Property setting or returning the SystemVerilog version of this fileset."""
+1028 if self._svVersion is not None:
+1029 return self._svVersion
+1030 elif self._parent is not None:
+1031 return self._parent.SVVersion
+1032 elif self._design is not None: 1032 ↛ 1035line 1032 didn't jump to line 1035, because the condition on line 1032 was never false
+1033 return self._design.SVVersion
+1034 else:
+1035 raise Exception("SVVersion was neither set locally nor globally.")
+ +1037 @SVVersion.setter
+1038 def SVVersion(self, value: SystemVerilogVersion) -> None:
+1039 self._svVersion = value
+ +1041 @property
+1042 def SRDLVersion(self) -> SystemRDLVersion:
+1043 if self._srdlVersion is not None:
+1044 return self._srdlVersion
+1045 elif self._parent is not None:
+1046 return self._parent.SRDLVersion
+1047 elif self._design is not None:
+1048 return self._design.SRDLVersion
+1049 else:
+1050 raise Exception("SRDLVersion was neither set locally nor globally.")
+ +1052 @SRDLVersion.setter
+1053 def SRDLVersion(self, value: SystemRDLVersion) -> None:
+1054 self._srdlVersion = value
+ +1056 def __len__(self) -> int:
+1057 """
+1058 Returns number of attributes set on this fileset.
+ +1060 :returns: The number if attributes set on this fileset.
+1061 """
+1062 return len(self._attributes)
+ +1064 def __getitem__(self, key: Type[Attribute]) -> Any:
+1065 """Index access for returning attributes on this fileset.
+ +1067 :param key: The attribute type.
+1068 :returns: The attribute's value.
+1069 :raises TypeError: When parameter 'key' is not a subclass of Attribute.
+1070 """
+1071 if not issubclass(key, Attribute): 1071 ↛ 1072line 1071 didn't jump to line 1072, because the condition on line 1071 was never true
+1072 raise TypeError("Parameter 'key' is not an 'Attribute'.")
+ +1074 try:
+1075 return self._attributes[key]
+1076 except KeyError:
+1077 return key.resolve(self, key)
+ +1079 def __setitem__(self, key: Type[Attribute], value: typing_Any) -> None:
+1080 """
+1081 Index access for adding or setting attributes on this fileset.
+ +1083 :param key: The attribute type.
+1084 :param value: The attributes value.
+1085 :raises TypeError: When parameter 'key' is not a subclass of Attribute.
+1086 """
+1087 if not issubclass(key, Attribute): 1087 ↛ 1088line 1087 didn't jump to line 1088, because the condition on line 1087 was never true
+1088 raise TypeError("Parameter 'key' is not an 'Attribute'.")
+ +1090 self._attributes[key] = value
+ +1092 def __delitem__(self, key: Type[Attribute]) -> None:
+1093 """
+1094 Index access for deleting attributes on this fileset.
+ +1096 :param key: The attribute type.
+1097 """
+1098 if not issubclass(key, Attribute): 1098 ↛ 1099line 1098 didn't jump to line 1099, because the condition on line 1098 was never true
+1099 raise TypeError("Parameter 'key' is not an 'Attribute'.")
+ +1101 del self._attributes[key]
+ +1103 def __str__(self) -> str:
+1104 """Returns the fileset's name."""
+1105 return self._name
+ + +1108@export
+1109class VHDLLibrary(metaclass=ExtendedType, slots=True):
+1110 """
+1111 A :term:`VHDLLibrary` represents a group of VHDL source files compiled into the same VHDL library.
+ +1113 :arg name: The VHDL libraries' name.
+1114 :arg project: Project the VHDL library is associated with.
+1115 :arg design: Design the VHDL library is associated with.
+1116 :arg vhdlVersion: Default VHDL version for files in this VHDL library, if not specified for the file itself.
+1117 """
+ +1119 _name: str
+1120 _project: Nullable['Project']
+1121 _design: Nullable['Design']
+1122 _files: List[File]
+1123 _vhdlVersion: VHDLVersion
+ +1125 _dependencyNode: Vertex
+ +1127 def __init__(
+1128 self,
+1129 name: str,
+1130 project: 'Project' = None,
+1131 design: 'Design' = None,
+1132 vhdlVersion: VHDLVersion = None
+1133 ):
+1134 self._name = name
+1135 if project is not None:
+1136 self._project = project
+1137 self._design = project._defaultDesign if design is None else design
+1138 self._dependencyNode = Vertex(value=self, graph=self._design._vhdlLibraryDependencyGraph)
+ +1140 if name in self._design._vhdlLibraries: 1140 ↛ 1141line 1140 didn't jump to line 1141, because the condition on line 1140 was never true
+1141 raise Exception(f"Library '{name}' already in design '{self._design.Name}'.")
+1142 else:
+1143 self._design._vhdlLibraries[name] = self
+ +1145 elif design is not None:
+1146 self._project = design._project
+1147 self._design = design
+1148 self._dependencyNode = Vertex(value=self, graph=design._vhdlLibraryDependencyGraph)
+ +1150 if name in design._vhdlLibraries: 1150 ↛ 1151line 1150 didn't jump to line 1151, because the condition on line 1150 was never true
+1151 raise Exception(f"Library '{name}' already in design '{design.Name}'.")
+1152 else:
+1153 design._vhdlLibraries[name] = self
+ +1155 else:
+1156 self._project = None
+1157 self._design = None
+1158 self._dependencyNode = None
+ +1160 self._files = []
+1161 self._vhdlVersion = vhdlVersion
+ +1163 @property
+1164 def Name(self) -> str:
+1165 return self._name
+ +1167 @property
+1168 def Project(self) -> Nullable['Project']:
+1169 """Property setting or returning the project this VHDL library is used in."""
+1170 return self._project
+ +1172 @Project.setter
+1173 def Project(self, value: 'Project') -> None:
+1174 if not isinstance(value, Project): 1174 ↛ 1175line 1174 didn't jump to line 1175, because the condition on line 1174 was never true
+1175 raise TypeError("Parameter 'value' is not of type 'Project'.")
+ +1177 if value is None: 1177 ↛ 1179line 1177 didn't jump to line 1179, because the condition on line 1177 was never true
+1178 # TODO: unlink VHDLLibrary from project
+1179 self._project = None
+1180 else:
+1181 self._project = value
+1182 if self._design is None: 1182 ↛ exitline 1182 didn't return from function 'Project', because the condition on line 1182 was never false
+1183 self._design = value._defaultDesign
+ +1185 @property
+1186 def Design(self) -> Nullable['Design']:
+1187 """Property setting or returning the design this VHDL library is used in."""
+1188 return self._design
+ +1190 @Design.setter
+1191 def Design(self, value: 'Design') -> None:
+1192 if not isinstance(value, Design):
+1193 raise TypeError("Parameter 'value' is not of type 'Design'.")
+ +1195 if value is None:
+1196 # TODO: unlink VHDLLibrary from design
+1197 self._design = None
+1198 else:
+1199 if self._design is None:
+1200 self._design = value
+1201 self._dependencyNode = Vertex(value=self, graph=self._design._vhdlLibraryDependencyGraph)
+1202 elif self._design is not value:
+1203 # TODO: move VHDLLibrary to other design
+1204 # TODO: create new vertex in dependency graph and remove vertex from old graph
+1205 self._design = value
+1206 else:
+1207 pass
+ +1209 if self._project is None:
+1210 self._project = value._project
+1211 elif self._project is not value._project:
+1212 raise Exception("The design's project is not identical to the already assigned project.")
+ +1214 @property
+1215 def Files(self) -> Generator[File, None, None]:
+1216 """Read-only property to return all files in this VHDL library."""
+1217 for file in self._files:
+1218 yield file
+ +1220 @property
+1221 def VHDLVersion(self) -> VHDLVersion:
+1222 """Property setting or returning the VHDL version of this VHDL library."""
+1223 if self._vhdlVersion is not None:
+1224 return self._vhdlVersion
+1225 elif self._design is not None: 1225 ↛ 1228line 1225 didn't jump to line 1228, because the condition on line 1225 was never false
+1226 return self._design.VHDLVersion
+1227 else:
+1228 raise Exception("VHDLVersion is not set on VHDLLibrary nor parent object.")
+ +1230 @VHDLVersion.setter
+1231 def VHDLVersion(self, value: VHDLVersion) -> None:
+1232 self._vhdlVersion = value
+ +1234 def AddDependency(self, library: 'VHDLLibrary') -> None:
+1235 library.parent = self
+ +1237 def AddFile(self, vhdlFile: VHDLSourceFile) -> None:
+1238 if not isinstance(vhdlFile, VHDLSourceFile): 1238 ↛ 1239line 1238 didn't jump to line 1239, because the condition on line 1238 was never true
+1239 raise TypeError(f"Parameter 'vhdlFile' is not a 'VHDLSourceFile'.")
+ +1241 self._files.append(vhdlFile)
+ +1243 def AddFiles(self, vhdlFiles: Iterable[VHDLSourceFile]) -> None:
+1244 for vhdlFile in vhdlFiles:
+1245 if not isinstance(vhdlFile, VHDLSourceFile):
+1246 raise TypeError(f"Item '{vhdlFile}' in parameter 'vhdlFiles' is not a 'VHDLSourceFile'.")
+ +1248 self._files.append(vhdlFile)
+ +1250 @property
+1251 def FileCount(self) -> int:
+1252 """Returns number of files."""
+1253 return len(self._files)
+ +1255 def __len__(self) -> int:
+1256 """
+1257 Returns number of attributes set on this VHDL library.
+ +1259 :returns: The number if attributes set on this VHDL library.
+1260 """
+1261 return len(self._attributes)
+ +1263 def __getitem__(self, key: Type[Attribute]) -> Any:
+1264 """Index access for returning attributes on this VHDL library.
+ +1266 :param key: The attribute type.
+1267 :returns: The attribute's value.
+1268 :raises TypeError: When parameter 'key' is not a subclass of Attribute.
+1269 """
+1270 if not issubclass(key, Attribute):
+1271 raise TypeError("Parameter 'key' is not an 'Attribute'.")
+ +1273 try:
+1274 return self._attributes[key]
+1275 except KeyError:
+1276 return key.resolve(self, key)
+ +1278 def __setitem__(self, key: Type[Attribute], value: typing_Any) -> None:
+1279 """
+1280 Index access for adding or setting attributes on this VHDL library.
+ +1282 :param key: The attribute type.
+1283 :param value: The attributes value.
+1284 :raises TypeError: When parameter 'key' is not a subclass of Attribute.
+1285 """
+1286 if not issubclass(key, Attribute):
+1287 raise TypeError("Parameter 'key' is not an 'Attribute'.")
+ +1289 self._attributes[key] = value
+ +1291 def __delitem__(self, key: Type[Attribute]) -> None:
+1292 """
+1293 Index access for deleting attributes on this VHDL library.
+ +1295 :param key: The attribute type.
+1296 """
+1297 if not issubclass(key, Attribute):
+1298 raise TypeError("Parameter 'key' is not an 'Attribute'.")
+ +1300 del self._attributes[key]
+ +1302 def __str__(self) -> str:
+1303 """Returns the VHDL library's name."""
+1304 return self._name
+ + +1307@export
+1308class Design(metaclass=ExtendedType, slots=True):
+1309 """
+1310 A :term:`Design` represents a group of filesets and the source files therein.
+ +1312 Each design contains at least one fileset - the :term:`default fileset`. For
+1313 designs with VHDL source files, a independent `VHDLLibraries` overlay structure
+1314 exists.
+ +1316 :arg name: The design's name.
+1317 :arg topLevel: Name of the design's toplevel.
+1318 :arg directory: Path of this design (absolute or relative to the project).
+1319 :arg project: Project the design is associated with.
+1320 :arg vhdlVersion: Default VHDL version for files in this design, if not specified for the file itself.
+1321 :arg verilogVersion: Default Verilog version for files in this design, if not specified for the file itself.
+1322 :arg svVersion: Default SystemVerilog version for files in this design, if not specified for the file itself.
+1323 :arg srdlVersion: Default SystemRDL version for files in this fileset, if not specified for the file itself.
+1324 """
+ +1326 _name: str
+1327 _topLevel: Nullable[str]
+1328 _project: Nullable['Project']
+1329 _directory: pathlib_Path
+1330 _fileSets: Dict[str, FileSet]
+1331 _defaultFileSet: Nullable[FileSet]
+1332 _attributes: Dict[Type[Attribute], typing_Any]
+ +1334 _vhdlLibraries: Dict[str, VHDLLibrary]
+1335 _vhdlVersion: VHDLVersion
+1336 _verilogVersion: SystemVerilogVersion
+1337 _svVersion: SystemVerilogVersion
+1338 _srdlVersion: SystemRDLVersion
+1339 _externalVHDLLibraries: List
+ +1341 _vhdlLibraryDependencyGraph: Graph
+1342 _fileDependencyGraph: Graph
+ +1344 def __init__(
+1345 self,
+1346 name: str,
+1347 topLevel: str = None,
+1348 directory: pathlib_Path = pathlib_Path("."),
+1349 project: 'Project' = None,
+1350 vhdlVersion: VHDLVersion = None,
+1351 verilogVersion: SystemVerilogVersion = None,
+1352 svVersion: SystemVerilogVersion = None,
+1353 srdlVersion: SystemRDLVersion = None
+1354 ):
+1355 self._name = name
+1356 self._topLevel = topLevel
+1357 self._project = project
+1358 if project is not None:
+1359 project._designs[name] = self
+1360 self._directory = directory
+1361 self._fileSets = {}
+1362 self._defaultFileSet = FileSet("default", project=project, design=self)
+1363 self._attributes = {}
+1364 self._vhdlLibraries = {}
+1365 self._vhdlVersion = vhdlVersion
+1366 self._verilogVersion = verilogVersion
+1367 self._svVersion = svVersion
+1368 self._srdlVersion = srdlVersion
+1369 self._externalVHDLLibraries = []
+ +1371 self._vhdlLibraryDependencyGraph = Graph()
+1372 self._fileDependencyGraph = Graph()
+ +1374 @property
+1375 def Name(self) -> str:
+1376 """Property setting or returning the design's name."""
+1377 return self._name
+ +1379 @Name.setter
+1380 def Name(self, value: str) -> None:
+1381 self._name = value
+ +1383 @property
+1384 def TopLevel(self) -> str:
+1385 """Property setting or returning the fileset's toplevel."""
+1386 return self._topLevel
+ +1388 @TopLevel.setter
+1389 def TopLevel(self, value: str) -> None:
+1390 self._topLevel = value
+ +1392 @property
+1393 def Project(self) -> Nullable['Project']:
+1394 """Property setting or returning the project this design is used in."""
+1395 return self._project
+ +1397 @Project.setter
+1398 def Project(self, value: 'Project') -> None:
+1399 self._project = value
+ +1401 @property
+1402 def Directory(self) -> pathlib_Path:
+1403 """Property setting or returning the directory this design is located in."""
+1404 return self._directory
+ +1406 @Directory.setter
+1407 def Directory(self, value: pathlib_Path) -> None:
+1408 self._directory = value
+ +1410 @property
+1411 def ResolvedPath(self) -> pathlib_Path:
+1412 """Read-only property returning the resolved path of this fileset."""
+1413 if self._directory.is_absolute(): 1413 ↛ 1414line 1413 didn't jump to line 1414, because the condition on line 1413 was never true
+1414 return self._directory.resolve()
+1415 elif self._project is not None: 1415 ↛ 1425line 1415 didn't jump to line 1425, because the condition on line 1415 was never false
+1416 path = (self._project.ResolvedPath / self._directory).resolve()
+ +1418 if path.is_absolute(): 1418 ↛ 1422line 1418 didn't jump to line 1422, because the condition on line 1418 was never false
+1419 return path
+1420 else:
+1421 # WORKAROUND: https://stackoverflow.com/questions/67452690/pathlib-path-relative-to-vs-os-path-relpath
+1422 return pathlib_Path(path_relpath(path, pathlib_Path.cwd()))
+1423 else:
+1424 # TODO: message and exception type
+1425 raise Exception("")
+ +1427 @property
+1428 def DefaultFileSet(self) -> FileSet:
+1429 """Property setting or returning the default fileset of this design."""
+1430 return self._defaultFileSet
+ +1432 @DefaultFileSet.setter
+1433 def DefaultFileSet(self, value: Union[str, FileSet]) -> None:
+1434 if isinstance(value, str):
+1435 if value not in self._fileSets.keys():
+1436 raise Exception(f"Fileset '{value}' is not in this design.")
+ +1438 self._defaultFileSet = self._fileSets[value]
+1439 elif isinstance(value, FileSet):
+1440 if value not in self.FileSets:
+1441 raise Exception(f"Fileset '{value}' is not associated to this design.")
+ +1443 self._defaultFileSet = value
+1444 else:
+1445 raise ValueError("Unsupported parameter type for 'value'.")
+ +1447 # TODO: return generator with another method
+1448 @property
+1449 def FileSets(self) -> Dict[str, FileSet]:
+1450 """Read-only property returning the dictionary of filesets."""
+1451 return self._fileSets
+ +1453 def Files(self, fileType: FileType = FileTypes.Any, fileSet: Union[str, FileSet] = None) -> Generator[File, None, None]:
+1454 """
+1455 Method returning the files of this design.
+ +1457 :arg fileType: A filter for file types. Default: ``Any``.
+1458 :arg fileSet: Specifies if all files from all filesets (``fileSet=None``) are files from a single fileset are returned.
+1459 """
+1460 if fileSet is None:
+1461 for fileSet in self._fileSets.values():
+1462 for file in fileSet.Files(fileType):
+1463 yield file
+1464 else:
+1465 if isinstance(fileSet, str): 1465 ↛ 1470line 1465 didn't jump to line 1470, because the condition on line 1465 was never false
+1466 try:
+1467 fileSet = self._fileSets[fileSet]
+1468 except KeyError as ex:
+1469 raise Exception(f"Fileset {fileSet.Name} not bound to design {self.Name}.") from ex
+1470 elif not isinstance(fileSet, FileSet):
+1471 raise TypeError("Parameter 'fileSet' is not of type 'str' or 'FileSet' nor value 'None'.")
+ +1473 for file in fileSet.Files(fileType):
+1474 yield file
+ +1476 def Validate(self) -> None:
+1477 """Validate this design."""
+1478 if self._name is None or self._name == "": 1478 ↛ 1479line 1478 didn't jump to line 1479, because the condition on line 1478 was never true
+1479 raise Exception("Validation: Design has no name.")
+ +1481 if self._directory is None: 1481 ↛ 1482line 1481 didn't jump to line 1482, because the condition on line 1481 was never true
+1482 raise Exception(f"Validation: Design '{self._name}' has no directory.")
+1483 try:
+1484 path = self.ResolvedPath
+1485 except Exception as ex:
+1486 raise Exception(f"Validation: Design '{self._name}' could not compute resolved path.") from ex
+1487 if not path.exists(): 1487 ↛ 1488line 1487 didn't jump to line 1488, because the condition on line 1487 was never true
+1488 raise Exception(f"Validation: Design '{self._name}'s directory '{path}' does not exist.")
+1489 if not path.is_dir(): 1489 ↛ 1490line 1489 didn't jump to line 1490, because the condition on line 1489 was never true
+1490 raise Exception(f"Validation: Design '{self._name}'s directory '{path}' is not a directory.")
+ +1492 if len(self._fileSets) == 0: 1492 ↛ 1493line 1492 didn't jump to line 1493, because the condition on line 1492 was never true
+1493 raise Exception(f"Validation: Design '{self._name}' has no fileset.")
+1494 try:
+1495 if self._defaultFileSet is not self._fileSets[self._defaultFileSet.Name]: 1495 ↛ 1496line 1495 didn't jump to line 1496, because the condition on line 1495 was never true
+1496 raise Exception(f"Validation: Design '{self._name}'s default fileset is the same as listed in filesets.")
+1497 except KeyError as ex:
+1498 raise Exception(f"Validation: Design '{self._name}'s default fileset is not in list of filesets.") from ex
+1499 if self._project is None: 1499 ↛ 1500line 1499 didn't jump to line 1500, because the condition on line 1499 was never true
+1500 raise Exception(f"Validation: Design '{self._path}' has no project.")
+ +1502 for fileSet in self._fileSets.values():
+1503 fileSet.Validate()
+ +1505 @property
+1506 def VHDLLibraries(self) -> Dict[str, VHDLLibrary]:
+1507 return self._vhdlLibraries
+ +1509 @property
+1510 def VHDLVersion(self) -> VHDLVersion:
+1511 if self._vhdlVersion is not None:
+1512 return self._vhdlVersion
+1513 elif self._project is not None: 1513 ↛ 1516line 1513 didn't jump to line 1516, because the condition on line 1513 was never false
+1514 return self._project.VHDLVersion
+1515 else:
+1516 raise Exception("VHDLVersion was neither set locally nor globally.")
+ +1518 @VHDLVersion.setter
+1519 def VHDLVersion(self, value: VHDLVersion) -> None:
+1520 self._vhdlVersion = value
+ +1522 @property
+1523 def VerilogVersion(self) -> SystemVerilogVersion:
+1524 if self._verilogVersion is not None:
+1525 return self._verilogVersion
+1526 elif self._project is not None: 1526 ↛ 1529line 1526 didn't jump to line 1529, because the condition on line 1526 was never false
+1527 return self._project.VerilogVersion
+1528 else:
+1529 raise Exception("VerilogVersion was neither set locally nor globally.")
+ +1531 @VerilogVersion.setter
+1532 def VerilogVersion(self, value: SystemVerilogVersion) -> None:
+1533 self._verilogVersion = value
+ +1535 @property
+1536 def SVVersion(self) -> SystemVerilogVersion:
+1537 if self._svVersion is not None:
+1538 return self._svVersion
+1539 elif self._project is not None: 1539 ↛ 1542line 1539 didn't jump to line 1542, because the condition on line 1539 was never false
+1540 return self._project.SVVersion
+1541 else:
+1542 raise Exception("SVVersion was neither set locally nor globally.")
+ +1544 @SVVersion.setter
+1545 def SVVersion(self, value: SystemVerilogVersion) -> None:
+1546 self._svVersion = value
+ +1548 @property
+1549 def SRDLVersion(self) -> SystemRDLVersion:
+1550 if self._srdlVersion is not None:
+1551 return self._srdlVersion
+1552 elif self._project is not None:
+1553 return self._project.SRDLVersion
+1554 else:
+1555 raise Exception("SRDLVersion was neither set locally nor globally.")
+ +1557 @SRDLVersion.setter
+1558 def SRDLVersion(self, value: SystemRDLVersion) -> None:
+1559 self._srdlVersion = value
+ +1561 @property
+1562 def ExternalVHDLLibraries(self) -> List:
+1563 return self._externalVHDLLibraries
+ +1565 def AddFileSet(self, fileSet: FileSet) -> None:
+1566 if not isinstance(fileSet, FileSet):
+1567 raise ValueError("Parameter 'fileSet' is not of type ProjectModel.FileSet.")
+1568 elif fileSet in self._fileSets:
+1569 raise Exception("Design already contains this fileset.")
+1570 elif fileSet.Name in self._fileSets.keys():
+1571 raise Exception(f"Design already contains a fileset named '{fileSet.Name}'.")
+ +1573 self._fileSets[fileSet.Name] = fileSet
+1574 fileSet.Design = self
+1575 fileSet._parent = self
+ +1577 def AddFileSets(self, fileSets: Iterable[FileSet]) -> None:
+1578 for fileSet in fileSets:
+1579 self.AddFileSet(fileSet)
+ +1581 @property
+1582 def FileSetCount(self) -> int:
+1583 """Returns number of file sets excl. sub-filesets."""
+1584 return len(self._fileSets)
+ +1586 @property
+1587 def TotalFileSetCount(self) -> int:
+1588 """Returns number of file sets incl. sub-filesets."""
+1589 fileSetCount = len(self._fileSets)
+1590 for fileSet in self._fileSets.values():
+1591 fileSetCount += fileSet.TotalFileSetCount
+ +1593 return fileSetCount
+ +1595 def AddFile(self, file: File) -> None:
+1596 if file.FileSet is None: 1596 ↛ 1599line 1596 didn't jump to line 1599, because the condition on line 1596 was never false
+1597 self._defaultFileSet.AddFile(file)
+1598 else:
+1599 raise ValueError(f"File '{file.Path!s}' is already part of fileset '{file.FileSet.Name}' and can't be assigned via Design to a default fileset.")
+ +1601 def AddFiles(self, files: Iterable[File]) -> None:
+1602 for file in files:
+1603 self.AddFile(file)
+ +1605 def AddVHDLLibrary(self, vhdlLibrary: VHDLLibrary) -> None:
+1606 if vhdlLibrary.Name in self._vhdlLibraries:
+1607 if self._vhdlLibraries[vhdlLibrary.Name] is vhdlLibrary:
+1608 raise Exception(f"The VHDLLibrary '{vhdlLibrary.Name}' was already added to the design.")
+1609 else:
+1610 raise Exception(f"A VHDLLibrary with same name ('{vhdlLibrary.Name}') already exists for this design.")
+ + +1613 def __len__(self) -> int:
+1614 """
+1615 Returns number of attributes set on this design.
+ +1617 :returns: The number if attributes set on this design.
+1618 """
+1619 return len(self._attributes)
+ +1621 def __getitem__(self, key: Type[Attribute]) -> Any:
+1622 """Index access for returning attributes on this design.
+ +1624 :param key: The attribute type.
+1625 :returns: The attribute's value.
+1626 :raises TypeError: When parameter 'key' is not a subclass of Attribute.
+1627 """
+1628 if not issubclass(key, Attribute):
+1629 raise TypeError("Parameter 'key' is not an 'Attribute'.")
+ +1631 try:
+1632 return self._attributes[key]
+1633 except KeyError:
+1634 return key.resolve(self, key)
+ +1636 def __setitem__(self, key: Type[Attribute], value: typing_Any) -> None:
+1637 """
+1638 Index access for adding or setting attributes on this design.
+ +1640 :param key: The attribute type.
+1641 :param value: The attributes value.
+1642 :raises TypeError: When parameter 'key' is not a subclass of Attribute.
+1643 """
+1644 if not issubclass(key, Attribute):
+1645 raise TypeError("Parameter 'key' is not an 'Attribute'.")
+ +1647 self._attributes[key] = value
+ +1649 def __delitem__(self, key: Type[Attribute]) -> None:
+1650 """
+1651 Index access for deleting attributes on this design.
+ +1653 :param key: The attribute type.
+1654 """
+1655 if not issubclass(key, Attribute):
+1656 raise TypeError("Parameter 'key' is not an 'Attribute'.")
+ +1658 del self._attributes[key]
+ +1660 def __str__(self) -> str:
+1661 return self._name
+ + +1664@export
+1665class Project(metaclass=ExtendedType, slots=True):
+1666 """
+1667 A :term:`Project` represents a group of designs and the source files therein.
+ +1669 :arg name: The project's name.
+1670 :arg rootDirectory: Base-path to the project.
+1671 :arg vhdlVersion: Default VHDL version for files in this project, if not specified for the file itself.
+1672 :arg verilogVersion: Default Verilog version for files in this project, if not specified for the file itself.
+1673 :arg svVersion: Default SystemVerilog version for files in this project, if not specified for the file itself.
+1674 """
+ +1676 _name: str
+1677 _rootDirectory: pathlib_Path
+1678 _designs: Dict[str, Design]
+1679 _defaultDesign: Design
+1680 _attributes: Dict[Type[Attribute], typing_Any]
+ +1682 _vhdlVersion: VHDLVersion
+1683 _verilogVersion: SystemVerilogVersion
+1684 _svVersion: SystemVerilogVersion
+1685 _srdlVersion: SystemRDLVersion
+ +1687 def __init__(
+1688 self,
+1689 name: str,
+1690 rootDirectory: pathlib_Path = pathlib_Path("."),
+1691 vhdlVersion: VHDLVersion = None,
+1692 verilogVersion: SystemVerilogVersion = None,
+1693 svVersion: SystemVerilogVersion = None
+1694 ):
+1695 self._name = name
+1696 self._rootDirectory = rootDirectory
+1697 self._designs = {}
+1698 self._defaultDesign = Design("default", project=self)
+1699 self._attributes = {}
+1700 self._vhdlVersion = vhdlVersion
+1701 self._verilogVersion = verilogVersion
+1702 self._svVersion = svVersion
+ +1704 @property
+1705 def Name(self) -> str:
+1706 """Property setting or returning the project's name."""
+1707 return self._name
+ +1709 @property
+1710 def RootDirectory(self) -> pathlib_Path:
+1711 """Property setting or returning the root directory this project is located in."""
+1712 return self._rootDirectory
+ +1714 @RootDirectory.setter
+1715 def RootDirectory(self, value: pathlib_Path) -> None:
+1716 self._rootDirectory = value
+ +1718 @property
+1719 def ResolvedPath(self) -> pathlib_Path:
+1720 """Read-only property returning the resolved path of this fileset."""
+1721 path = self._rootDirectory.resolve()
+1722 if self._rootDirectory.is_absolute():
+1723 return path
+1724 else:
+1725 # WORKAROUND: https://stackoverflow.com/questions/67452690/pathlib-path-relative-to-vs-os-path-relpath
+1726 return pathlib_Path(path_relpath(path, pathlib_Path.cwd()))
+ +1728 # TODO: return generator with another method
+1729 @property
+1730 def Designs(self) -> Dict[str, Design]:
+1731 return self._designs
+ +1733 @property
+1734 def DefaultDesign(self) -> Design:
+1735 return self._defaultDesign
+ +1737 def Validate(self) -> None:
+1738 """Validate this project."""
+1739 if self._name is None or self._name == "": 1739 ↛ 1740line 1739 didn't jump to line 1740, because the condition on line 1739 was never true
+1740 raise Exception("Validation: Project has no name.")
+ +1742 if self._rootDirectory is None: 1742 ↛ 1743line 1742 didn't jump to line 1743, because the condition on line 1742 was never true
+1743 raise Exception(f"Validation: Project '{self._name}' has no root directory.")
+1744 try:
+1745 path = self.ResolvedPath
+1746 except Exception as ex:
+1747 raise Exception(f"Validation: Project '{self._name}' could not compute resolved path.") from ex
+1748 if not path.exists(): 1748 ↛ 1749line 1748 didn't jump to line 1749, because the condition on line 1748 was never true
+1749 raise Exception(f"Validation: Project '{self._name}'s directory '{path}' does not exist.")
+1750 if not path.is_dir(): 1750 ↛ 1751line 1750 didn't jump to line 1751, because the condition on line 1750 was never true
+1751 raise Exception(f"Validation: Project '{self._name}'s directory '{path}' is not a directory.")
+ +1753 if len(self._designs) == 0: 1753 ↛ 1754line 1753 didn't jump to line 1754, because the condition on line 1753 was never true
+1754 raise Exception(f"Validation: Project '{self._name}' has no design.")
+1755 try:
+1756 if self._defaultDesign is not self._designs[self._defaultDesign.Name]: 1756 ↛ 1757line 1756 didn't jump to line 1757, because the condition on line 1756 was never true
+1757 raise Exception(f"Validation: Project '{self._name}'s default design is the same as listed in designs.")
+1758 except KeyError as ex:
+1759 raise Exception(f"Validation: Project '{self._name}'s default design is not in list of designs.") from ex
+ +1761 for design in self._designs.values():
+1762 design.Validate()
+ +1764 @property
+1765 def DesignCount(self) -> int:
+1766 """Returns number of designs."""
+1767 return len(self._designs)
+ +1769 @property
+1770 def VHDLVersion(self) -> VHDLVersion:
+1771 # TODO: check for None and return exception
+1772 return self._vhdlVersion
+ +1774 @VHDLVersion.setter
+1775 def VHDLVersion(self, value: VHDLVersion) -> None:
+1776 self._vhdlVersion = value
+ +1778 @property
+1779 def VerilogVersion(self) -> SystemVerilogVersion:
+1780 # TODO: check for None and return exception
+1781 return self._verilogVersion
+ +1783 @VerilogVersion.setter
+1784 def VerilogVersion(self, value: SystemVerilogVersion) -> None:
+1785 self._verilogVersion = value
+ +1787 @property
+1788 def SVVersion(self) -> SystemVerilogVersion:
+1789 # TODO: check for None and return exception
+1790 return self._svVersion
+ +1792 @SVVersion.setter
+1793 def SVVersion(self, value: SystemVerilogVersion) -> None:
+1794 self._svVersion = value
+ +1796 @property
+1797 def SRDLVersion(self) -> SystemRDLVersion:
+1798 # TODO: check for None and return exception
+1799 return self._srdlVersion
+ +1801 @SRDLVersion.setter
+1802 def SRDLVersion(self, value: SystemRDLVersion) -> None:
+1803 self._srdlVersion = value
+ +1805 def __len__(self) -> int:
+1806 """
+1807 Returns number of attributes set on this project.
+ +1809 :returns: The number if attributes set on this project.
+1810 """
+1811 return len(self._attributes)
+ +1813 def __getitem__(self, key: Type[Attribute]) -> Any:
+1814 """Index access for returning attributes on this project.
+ +1816 :param key: The attribute type.
+1817 :returns: The attribute's value.
+1818 :raises TypeError: When parameter 'key' is not a subclass of Attribute.
+1819 """
+1820 if not issubclass(key, Attribute):
+1821 raise TypeError("Parameter 'key' is not an 'Attribute'.")
+ +1823 try:
+1824 return self._attributes[key]
+1825 except KeyError:
+1826 return key.resolve(self, key)
+ +1828 def __setitem__(self, key: Type[Attribute], value: typing_Any) -> None:
+1829 """
+1830 Index access for adding or setting attributes on this project.
+ +1832 :param key: The attribute type.
+1833 :param value: The attributes value.
+1834 :raises TypeError: When parameter 'key' is not a subclass of Attribute.
+1835 """
+1836 if not issubclass(key, Attribute):
+1837 raise TypeError("Parameter 'key' is not an 'Attribute'.")
+ +1839 self._attributes[key] = value
+ +1841 def __delitem__(self, key: Type[Attribute]) -> None:
+1842 """
+1843 Index access for deleting attributes on this project.
+ +1845 :param key: The attribute type.
+1846 """
+1847 if not issubclass(key, Attribute):
+1848 raise TypeError("Parameter 'key' is not an 'Attribute'.")
+ +1850 del self._attributes[key]
+ +1852 def __str__(self) -> str:
+1853 return self._name
++ « prev + ^ index + » next + + coverage.py v7.3.0, + created at 2023-08-24 21:52 +0000 +
+ +1# ==================================================================================================================== #
+2# _____ ____ _ _ ____ _ _ __ __ _ _ #
+3# _ __ _ _| ____| _ \ / \ / \ | _ \ _ __ ___ (_) ___ ___| |_| \/ | ___ __| | ___| | #
+4# | '_ \| | | | _| | | | |/ _ \ / _ \ | |_) | '__/ _ \| |/ _ \/ __| __| |\/| |/ _ \ / _` |/ _ \ | #
+5# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| __/| | | (_) | | __/ (__| |_| | | | (_) | (_| | __/ | #
+6# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_| |_| \___// |\___|\___|\__|_| |_|\___/ \__,_|\___|_| #
+7# |_| |___/ |__/ #
+8# ==================================================================================================================== #
+9# Authors: #
+10# Patrick Lehmann #
+11# #
+12# License: #
+13# ==================================================================================================================== #
+14# Copyright 2017-2023 Patrick Lehmann - Boetzingen, Germany #
+15# #
+16# Licensed under the Apache License, Version 2.0 (the "License"); #
+17# you may not use this file except in compliance with the License. #
+18# You may obtain a copy of the License at #
+19# #
+20# http://www.apache.org/licenses/LICENSE-2.0 #
+21# #
+22# Unless required by applicable law or agreed to in writing, software #
+23# distributed under the License is distributed on an "AS IS" BASIS, #
+24# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
+25# See the License for the specific language governing permissions and #
+26# limitations under the License. #
+27# #
+28# SPDX-License-Identifier: Apache-2.0 #
+29# ==================================================================================================================== #
+30#
+31"""Specific file types and attributes for Xilinx Vivado."""
+32from pathlib import Path
+33from typing import Iterable
+ +35from xml.dom import minidom, Node
+ +37from pyTooling.MetaClasses import ExtendedType
+38from pyVHDLModel import VHDLVersion
+39from pyTooling.Decorators import export
+ +41from pyEDAA.ProjectModel import ProjectFile, XMLFile, XMLContent, SDCContent, Project, FileSet, Attribute, Design
+42from pyEDAA.ProjectModel import File as Model_File
+43from pyEDAA.ProjectModel import ConstraintFile as Model_ConstraintFile
+44from pyEDAA.ProjectModel import VerilogSourceFile as Model_VerilogSourceFile
+45from pyEDAA.ProjectModel import VHDLSourceFile as Model_VHDLSourceFile
+ + +48@export
+49class UsedInAttribute(Attribute):
+50 KEY = "UsedIn"
+51 VALUE_TYPE = Iterable[str]
+ + +54@export
+55class File(Model_File):
+56 pass
+ + +59class VivadoFileMixIn(metaclass=ExtendedType, mixin=True):
+60 def _registerAttributes(self):
+61 self._attributes[UsedInAttribute] = []
+ + +64@export
+65class ConstraintFile(Model_ConstraintFile, VivadoFileMixIn):
+66 def _registerAttributes(self):
+67 super()._registerAttributes()
+68 VivadoFileMixIn._registerAttributes(self)
+ + +71@export
+72class VerilogSourceFile(Model_VerilogSourceFile):
+73 def _registerAttributes(self):
+74 super()._registerAttributes()
+75 VivadoFileMixIn._registerAttributes(self)
+ + +78@export
+79class VHDLSourceFile(Model_VHDLSourceFile):
+80 def _registerAttributes(self):
+81 super()._registerAttributes()
+82 VivadoFileMixIn._registerAttributes(self)
+ + +85@export
+86class VivadoProjectFile(ProjectFile, XMLContent):
+87 """A Vivado project file (``*.xpr``)."""
+ +89 _xprProject: Project
+ +91 def __init__(
+92 self,
+93 path: Path,
+94 project: Project = None,
+95 design: Design = None,
+96 fileSet: FileSet = None
+97 ):
+98 super().__init__(path, project, design, fileSet)
+ +100 self._xprProject = None
+ +102 @property
+103 def ProjectModel(self) -> Project:
+104 return self._xprProject
+ +106 def Parse(self):
+107 if not self._path.exists(): 107 ↛ 108line 107 didn't jump to line 108, because the condition on line 107 was never true
+108 raise Exception(f"Vivado project file '{self._path!s}' not found.") from FileNotFoundError(f"File '{self._path!s}' not found.")
+ +110 try:
+111 root = minidom.parse(str(self._path)).documentElement
+112 except Exception as ex:
+113 raise Exception(f"Couldn't open '{self._path!s}'.") from ex
+ +115 self._xprProject = Project(self._path.stem, rootDirectory=self._path.parent)
+116 self._ParseRootElement(root)
+ +118 def _ParseRootElement(self, root):
+119 for rootNode in root.childNodes: 119 ↛ exitline 119 didn't return from function '_ParseRootElement', because the loop on line 119 didn't complete
+120 if rootNode.nodeName == "FileSets":
+121 self._ParseFileSets(rootNode)
+122 break
+ +124 def _ParseFileSets(self, filesetsNode):
+125 for fileSetsNode in filesetsNode.childNodes:
+126 if fileSetsNode.nodeType == Node.ELEMENT_NODE and fileSetsNode.tagName == "FileSet":
+127 self._ParseFileSet(fileSetsNode)
+ +129 def _ParseFileSet(self, filesetNode):
+130 filesetName = filesetNode.getAttribute("Name")
+131 fileset = FileSet(filesetName, design=self._xprProject.DefaultDesign)
+ +133 for fileNode in filesetNode.childNodes:
+134 if fileNode.nodeType == Node.ELEMENT_NODE:
+135 if fileNode.tagName == "File":
+136 self._ParseFile(fileNode, fileset)
+137 elif fileNode.nodeType == Node.ELEMENT_NODE and fileNode.tagName == "Config":
+138 self._ParseFileSetConfig(fileNode, fileset)
+ +140 def _ParseFile(self, fileNode, fileset):
+141 croppedPath = fileNode.getAttribute("Path").replace("$PPRDIR/", "")
+142 filePath = Path(croppedPath)
+143 if filePath.suffix in (".vhd", ".vhdl"):
+144 self._ParseVHDLFile(fileNode, filePath, fileset)
+145 elif filePath.suffix == ".xdc": 145 ↛ 147line 145 didn't jump to line 147, because the condition on line 145 was never false
+146 self._ParseXDCFile(fileNode, filePath, fileset)
+147 elif filePath.suffix == ".v":
+148 self._ParseVerilogFile(fileNode, filePath, fileset)
+149 elif filePath.suffix == ".xci":
+150 self._ParseXCIFile(fileNode, filePath, fileset)
+151 else:
+152 self._ParseDefaultFile(fileNode, filePath, fileset)
+ +154 def _ParseVHDLFile(self, fileNode, path, fileset):
+155 vhdlFile = VHDLSourceFile(path)
+156 fileset.AddFile(vhdlFile)
+157 usedInAttr = vhdlFile[UsedInAttribute]
+ +159 for childNode in fileNode.childNodes:
+160 if childNode.nodeType == Node.ELEMENT_NODE and childNode.tagName == "FileInfo":
+161 if childNode.getAttribute("SFType") == "VHDL2008":
+162 vhdlFile.VHDLVersion = VHDLVersion.VHDL2008
+163 else:
+164 vhdlFile.VHDLVersion = VHDLVersion.VHDL93
+ +166 for fileAttribute in childNode.childNodes:
+167 if fileAttribute.nodeType == Node.ELEMENT_NODE and fileAttribute.tagName == "Attr":
+168 if fileAttribute.getAttribute("Name") == "Library":
+169 libraryName = fileAttribute.getAttribute("Val")
+170 vhdlFile.VHDLLibrary = fileset.GetOrCreateVHDLLibrary(libraryName)
+171 elif fileAttribute.getAttribute("Val") == "UsedIn": 171 ↛ 172line 171 didn't jump to line 172, because the condition on line 171 was never true
+172 usedInAttr.append(fileAttribute.getAttribute("Val"))
+ +174 def _ParseDefaultFile(self, _, path, fileset):
+175 File(path, fileSet=fileset)
+ +177 def _ParseXDCFile(self, _, path, fileset):
+178 XDCConstraintFile(path, fileSet=fileset)
+ +180 def _ParseVerilogFile(self, _, path, fileset):
+181 VerilogSourceFile(path, fileSet=fileset)
+ +183 def _ParseXCIFile(self, _, path, fileset):
+184 IPCoreInstantiationFile(path, fileSet=fileset)
+ +186 def _ParseFileSetConfig(self, fileNode, fileset):
+187 for option in fileNode.childNodes:
+188 if option.nodeType == Node.ELEMENT_NODE and option.tagName == "Option":
+189 if option.getAttribute("Name") == "TopModule":
+190 fileset.TopLevel = option.getAttribute("Val")
+ + +193@export
+194class XDCConstraintFile(ConstraintFile, SDCContent):
+195 """A Vivado constraint file (Xilinx Design Constraints; ``*.xdc``)."""
+ + +198@export
+199class IPCoreDescriptionFile(XMLFile):
+200 pass
+ + +203@export
+204class IPCoreInstantiationFile(XMLFile):
+205 """A Vivado IP core instantiation file (Xilinx IPCore Instance; ``*.xci``)."""
++ « prev + ^ index + » next + + coverage.py v7.3.0, + created at 2023-08-24 21:52 +0000 +
+ +1# ==================================================================================================================== #
+2# _____ ____ _ _ ____ _ _ __ __ _ _ #
+3# _ __ _ _| ____| _ \ / \ / \ | _ \ _ __ ___ (_) ___ ___| |_| \/ | ___ __| | ___| | #
+4# | '_ \| | | | _| | | | |/ _ \ / _ \ | |_) | '__/ _ \| |/ _ \/ __| __| |\/| |/ _ \ / _` |/ _ \ | #
+5# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| __/| | | (_) | | __/ (__| |_| | | | (_) | (_| | __/ | #
+6# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_| |_| \___// |\___|\___|\__|_| |_|\___/ \__,_|\___|_| #
+7# |_| |___/ |__/ #
+8# ==================================================================================================================== #
+9# Authors: #
+10# Patrick Lehmann #
+11# #
+12# License: #
+13# ==================================================================================================================== #
+14# Copyright 2017-2023 Patrick Lehmann - Boetzingen, Germany #
+15# #
+16# Licensed under the Apache License, Version 2.0 (the "License"); #
+17# you may not use this file except in compliance with the License. #
+18# You may obtain a copy of the License at #
+19# #
+20# http://www.apache.org/licenses/LICENSE-2.0 #
+21# #
+22# Unless required by applicable law or agreed to in writing, software #
+23# distributed under the License is distributed on an "AS IS" BASIS, #
+24# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
+25# See the License for the specific language governing permissions and #
+26# limitations under the License. #
+27# #
+28# SPDX-License-Identifier: Apache-2.0 #
+29# ==================================================================================================================== #
+30#
+31"""A vendor specific package for Xilinx."""
++ coverage.py v7.3.0, + created at 2023-08-24 21:52 +0000 +
+Module | +statements | +missing | +excluded | +branches | +partial | +coverage | +
---|---|---|---|---|---|---|
pyEDAA/ProjectModel/Attributes.py | +15 | +0 | +0 | +2 | +0 | +100% | +
pyEDAA/ProjectModel/Xilinx/Vivado.py | +121 | +14 | +0 | +66 | +4 | +88% | +
pyEDAA/ProjectModel/Xilinx/__init__.py | +1 | +0 | +0 | +0 | +0 | +100% | +
pyEDAA/ProjectModel/__init__.py | +1064 | +271 | +0 | +638 | +74 | +73% | +
Total | +1201 | +285 | +0 | +706 | +78 | +75% | +
+ No items found using the specified filter. +
++ | + |
|
+
+ | + |
+ | + |
+ |
+ |
+ |
+ |
|
+
+ |
|
+
|
+
+ | + |
+ | + |
+ | + |
+ |
+ | + |
+ |
+ |
An abstract model of HDL design projects and EDA tooling.
+This package provides a unified abstract project model for HDL designs and EDA tools. +Third-party frameworks can derive own classes and implement additional logic to create a concrete project model for +their tools.
+Frameworks consuming this model can build higher level features and services on top of such a model, while supporting +multiple input sources.
+Describing HDL projects for open source simulation and synthesis tools: +GHDL, +Icarus Verilog, +Verilator, +Yosys, +Verilog to Routing (VTR), +nextpnr, +etc.
Managing IP cores and projects with pyIPCMI.
*.xpr
and *.pro
Files¶Xilinx Vivado’s *.xpr
and OSVVM’s *.pro
files can now be read.
Filesets can be nested.
The dataset can be validated.
Patrick Lehmann (Maintainer)
Unai Martinez-Corral (Maintainer)
This Python package (source code) is licensed under Apache License 2.0.
+The accompanying documentation is licensed under Creative Commons - Attribution 4.0 (CC-BY 4.0).
This document was generated on 24.Aug 2023 - 21:52.
++ p | ||
+ |
+ pyEDAA | + |
+ |
+ pyEDAA.ProjectModel | + |
+ |
+ pyEDAA.ProjectModel.Altera | + |
+ |
+ pyEDAA.ProjectModel.Altera.Quartus | + |
+ |
+ pyEDAA.ProjectModel.Attributes | + |
+ |
+ pyEDAA.ProjectModel.GHDL | + |
+ |
+ pyEDAA.ProjectModel.Intel | + |
+ |
+ pyEDAA.ProjectModel.Intel.QuartusPrime | + |
+ |
+ pyEDAA.ProjectModel.MentorGraphics | + |
+ |
+ pyEDAA.ProjectModel.MentorGraphics.ModelSim | + |
+ |
+ pyEDAA.ProjectModel.MentorGraphics.QuestaSim | + |
+ |
+ pyEDAA.ProjectModel.OSVVM | + |
+ |
+ pyEDAA.ProjectModel.Verilog | + |
+ |
+ pyEDAA.ProjectModel.VHDL | + |
+ |
+ pyEDAA.ProjectModel.Xilinx | + |
+ |
+ pyEDAA.ProjectModel.Xilinx.ISE | + |
+ |
+ pyEDAA.ProjectModel.Xilinx.Vivado | + |
Reference of all packages and modules:
+pyEDAA.ProjectModel
pyEDAA.ProjectModel.Altera
+pyEDAA.ProjectModel.Attributes
+pyEDAA.ProjectModel.GHDL
pyEDAA.ProjectModel.Intel
+pyEDAA.ProjectModel.MentorGraphics
+pyEDAA.ProjectModel.OSVVM
pyEDAA.ProjectModel.VHDL
pyEDAA.ProjectModel.Verilog
pyEDAA.ProjectModel.Xilinx
+Attribute
FileType
FileType.FileTypes
FileType.__init__()
FileType.__new__()
FileType.__base__
FileType.__call__()
FileType.__delattr__()
FileType.__dir__()
FileType.__getattribute__()
FileType.__instancecheck__()
FileType.__or__()
FileType.__prepare__()
FileType.__repr__()
FileType.__ror__()
FileType.__setattr__()
FileType.__sizeof__()
FileType.__subclasscheck__()
FileType.__subclasses__()
FileType.__text_signature__
FileType._checkForAbstractMethods()
FileType._iterateBaseClassPaths()
FileType._wrapNewMethodIfAbstract()
FileType._wrapNewMethodIfSingleton()
FileType.mro()
HumanReadableContent
XMLContent
YAMLContent
JSONContent
INIContent
TOMLContent
TCLContent
SDCContent
PythonContent
FileSet
FileSet.__init__()
FileSet.Name
FileSet.TopLevel
FileSet.Project
FileSet.Design
FileSet.Directory
FileSet.ResolvedPath
FileSet.Parent
FileSet.FileSets
FileSet.Files()
FileSet.AddFileSet()
FileSet.AddFileSets()
FileSet.FileSetCount
FileSet.TotalFileSetCount
FileSet.AddFile()
FileSet.AddFiles()
FileSet.FileCount
FileSet.TotalFileCount
FileSet.Validate()
FileSet.VHDLLibrary
FileSet.VHDLVersion
FileSet.VerilogVersion
FileSet.SVVersion
FileSet.__len__()
FileSet.__getitem__()
FileSet.__setitem__()
FileSet.__delitem__()
FileSet.__str__()
VHDLLibrary
+Design
Design.__init__()
Design.Name
Design.TopLevel
Design.Project
Design.Directory
Design.ResolvedPath
Design.DefaultFileSet
Design.FileSets
Design.Files()
Design.Validate()
Design.FileSetCount
Design.TotalFileSetCount
Design.__len__()
Design.__getitem__()
Design.__setitem__()
Design.__delitem__()
Design.__str__()
Project
+pyEDAA.ProjectModel.Altera.Quartus
¶Classes
+QuartusProjectFile
:
+A Quartus project file (*.qpf
).
SDCConstraintFile
:
+A Quartus constraint file (Synopsys Design Constraints; *.sdc
).
pyEDAA.ProjectModel.Altera
¶Submodules
+ +pyEDAA.ProjectModel.GHDL
¶Classes
+GHDLWaveformFile
:
+GHDL’s waveform file (*.ghw
) supporting VHDL and Verilog simulation results.
pyEDAA.ProjectModel.Intel.QuartusPrime
¶Classes
+QuartusProjectFile
:
+A Quartus project file (*.qpf
).
SDCConstraintFile
:
+A Quartus constraint file (Synopsys Design Constraints; *.sdc
).
pyEDAA.ProjectModel.Intel
¶Submodules
+ +pyEDAA.ProjectModel.MentorGraphics.ModelSim
¶Classes
+ModelSimProjectFile
:
+Base-class of all tool-specific project files.
ModelSimINIFile
:
+Base-class of all tool-specific setting files.
WaveDoFile
:
+Base-class of all tool-specific waveform configuration files.
pyEDAA.ProjectModel.MentorGraphics.QuestaSim
¶Classes
+ModelSimProjectFile
:
+Base-class of all tool-specific project files.
ModelSimINIFile
:
+Base-class of all tool-specific setting files.
WaveDoFile
:
+Base-class of all tool-specific waveform configuration files.
pyEDAA.ProjectModel.MentorGraphics
¶Submodules
+ +pyEDAA.ProjectModel.OSVVM
¶Classes
+OSVVMProjectFile
:
+An OSVVM project file (*.pro
).
pyEDAA.ProjectModel.VHDL
¶pyEDAA.ProjectModel.Verilog
¶Classes
+ValueChangeDumpFile
:
+Verilog’s waveform file (*.vcd
) for exchanging value changes as defined by IEEE Std. 1364.
pyEDAA.ProjectModel.Xilinx.ISE
¶Classes
+ISEProjectFile
:
+Base-class of all tool-specific project files.
UCFConstraintFile
:
+Base-class of all constraint files.
pyEDAA.ProjectModel.Xilinx.Vivado
¶Classes
+UsedInAttribute
:
+Undocumented.
File
:
+A File represents a file in a design. This base-class is used
ConstraintFile
:
+Base-class of all constraint files.
VerilogSourceFile
:
+A Verilog source file (of any language version).
VHDLSourceFile
:
+A VHDL source file (of any language version).
VivadoProjectFile
:
+A Vivado project file (*.xpr
).
XDCConstraintFile
:
+A Vivado constraint file (Xilinx Design Constraints; *.xdc
).
IPCoreDescriptionFile
:
+An XML file (*.xml
).
IPCoreInstantiationFile
:
+A Vivado IP core instantiation file (Xilinx IPCore Instance; *.xci
).
pyEDAA.ProjectModel.Xilinx
¶Submodules
+ +pyEDAA.ProjectModel
¶Submodules
+Classes
+Attribute
:
+Undocumented.
FileType
:
+A meta-class to construct FileType classes.
File
:
+A File represents a file in a design. This base-class is used
HumanReadableContent
:
+A file type representing human-readable contents.
XMLContent
:
+A file type representing XML contents.
YAMLContent
:
+A file type representing YAML contents.
JSONContent
:
+A file type representing JSON contents.
INIContent
:
+A file type representing INI contents.
TOMLContent
:
+A file type representing TOML contents.
TCLContent
:
+A file type representing content in TCL code.
SDCContent
:
+A file type representing contents as Synopsys Design Constraints (SDC).
PythonContent
:
+A file type representing contents as Python source code.
TextFile
:
+A text file (*.txt
).
LogFile
:
+A log file (*.log
).
XMLFile
:
+An XML file (*.xml
).
SourceFile
:
+Base-class of all source files.
HDLSourceFile
:
+Base-class of all HDL source files.
RDLSourceFile
:
+Base-class of all RDL source files.
NetlistFile
:
+Base-class of all netlist source files.
EDIFNetlistFile
:
+Netlist file in EDIF (Electronic Design Interchange Format).
TCLSourceFile
:
+A TCL source file.
VHDLSourceFile
:
+A VHDL source file (of any language version).
VerilogBaseFile
:
+Base-class of all HDL source files.
VerilogSourceFile
:
+A Verilog source file (of any language version).
VerilogHeaderFile
:
+A Verilog header file (of any language version).
SystemVerilogBaseFile
:
+Base-class of all HDL source files.
SystemVerilogSourceFile
:
+A SystemVerilog source file (of any language version).
SystemVerilogHeaderFile
:
+A SystemVerilog header file (of any language version).
SystemRDLSourceFile
:
+A SystemRDL source file (of any language version).
PythonSourceFile
:
+A Python source file.
CocotbPythonFile
:
+A Python source file used by Cocotb.
ConstraintFile
:
+Base-class of all constraint files.
ProjectFile
:
+Base-class of all tool-specific project files.
CSourceFile
:
+Base-class of all ANSI-C source files.
CppSourceFile
:
+Base-class of all ANSI-C++ source files.
SettingFile
:
+Base-class of all tool-specific setting files.
SimulationAnalysisFile
:
+Base-class of all tool-specific analysis files.
SimulationElaborationFile
:
+Base-class of all tool-specific elaboration files.
SimulationStartFile
:
+Base-class of all tool-specific simulation start-up files.
SimulationRunFile
:
+Base-class of all tool-specific simulation run (execution) files.
WaveformConfigFile
:
+Base-class of all tool-specific waveform configuration files.
WaveformDatabaseFile
:
+Base-class of all tool-specific waveform database files.
WaveformExchangeFile
:
+Base-class of all tool-independent waveform exchange files.
FileSet
:
+A FileSet represents a group of files. Filesets can have sub-filesets.
VHDLLibrary
:
+A VHDLLibrary represents a group of VHDL source files compiled into the same VHDL library.
Design
:
+A Design represents a group of filesets and the source files therein.
Project
:
+A Project represents a group of designs and the source files therein.
A meta-class to construct FileType classes.
+Modifications done by this meta-class:
+* Register all classes of type FileType
or derived variants in a class field FileType.FileTypes
in this meta-class.
Inheritance
+ +classMembers (Dict) –
+Dict
[str
, FileType
] = {'CSourceFile': <class 'pyEDAA.ProjectModel.CSourceFile'>, 'CocotbPythonFile': <class 'pyEDAA.ProjectModel.CocotbPythonFile'>, 'ConstraintFile': <class 'pyEDAA.ProjectModel.Xilinx.Vivado.ConstraintFile'>, 'CppSourceFile': <class 'pyEDAA.ProjectModel.CppSourceFile'>, 'EDIFNetlistFile': <class 'pyEDAA.ProjectModel.EDIFNetlistFile'>, 'File': <class 'pyEDAA.ProjectModel.Xilinx.Vivado.File'>, 'GHDLWaveformFile': <class 'pyEDAA.ProjectModel.GHDL.GHDLWaveformFile'>, 'HDLSourceFile': <class 'pyEDAA.ProjectModel.HDLSourceFile'>, 'IPCoreDescriptionFile': <class 'pyEDAA.ProjectModel.Xilinx.Vivado.IPCoreDescriptionFile'>, 'IPCoreInstantiationFile': <class 'pyEDAA.ProjectModel.Xilinx.Vivado.IPCoreInstantiationFile'>, 'ISEProjectFile': <class 'pyEDAA.ProjectModel.Xilinx.ISE.ISEProjectFile'>, 'LogFile': <class 'pyEDAA.ProjectModel.LogFile'>, 'ModelSimINIFile': <class 'pyEDAA.ProjectModel.MentorGraphics.QuestaSim.ModelSimINIFile'>, 'ModelSimProjectFile': <class 'pyEDAA.ProjectModel.MentorGraphics.QuestaSim.ModelSimProjectFile'>, 'NetlistFile': <class 'pyEDAA.ProjectModel.NetlistFile'>, 'OSVVMProjectFile': <class 'pyEDAA.ProjectModel.OSVVM.OSVVMProjectFile'>, 'ProjectFile': <class 'pyEDAA.ProjectModel.ProjectFile'>, 'PythonSourceFile': <class 'pyEDAA.ProjectModel.PythonSourceFile'>, 'QuartusProjectFile': <class 'pyEDAA.ProjectModel.Intel.QuartusPrime.QuartusProjectFile'>, 'RDLSourceFile': <class 'pyEDAA.ProjectModel.RDLSourceFile'>, 'SDCConstraintFile': <class 'pyEDAA.ProjectModel.Intel.QuartusPrime.SDCConstraintFile'>, 'SettingFile': <class 'pyEDAA.ProjectModel.SettingFile'>, 'SimulationAnalysisFile': <class 'pyEDAA.ProjectModel.SimulationAnalysisFile'>, 'SimulationElaborationFile': <class 'pyEDAA.ProjectModel.SimulationElaborationFile'>, 'SimulationRunFile': <class 'pyEDAA.ProjectModel.SimulationRunFile'>, 'SimulationStartFile': <class 'pyEDAA.ProjectModel.SimulationStartFile'>, 'SourceFile': <class 'pyEDAA.ProjectModel.SourceFile'>, 'SystemRDLSourceFile': <class 'pyEDAA.ProjectModel.SystemRDLSourceFile'>, 'SystemVerilogBaseFile': <class 'pyEDAA.ProjectModel.SystemVerilogBaseFile'>, 'SystemVerilogHeaderFile': <class 'pyEDAA.ProjectModel.SystemVerilogHeaderFile'>, 'SystemVerilogSourceFile': <class 'pyEDAA.ProjectModel.SystemVerilogSourceFile'>, 'TCLSourceFile': <class 'pyEDAA.ProjectModel.TCLSourceFile'>, 'TextFile': <class 'pyEDAA.ProjectModel.TextFile'>, 'UCFConstraintFile': <class 'pyEDAA.ProjectModel.Xilinx.ISE.UCFConstraintFile'>, 'VHDLSourceFile': <class 'pyEDAA.ProjectModel.Xilinx.Vivado.VHDLSourceFile'>, 'ValueChangeDumpFile': <class 'pyEDAA.ProjectModel.Verilog.ValueChangeDumpFile'>, 'VerilogBaseFile': <class 'pyEDAA.ProjectModel.VerilogBaseFile'>, 'VerilogHeaderFile': <class 'pyEDAA.ProjectModel.VerilogHeaderFile'>, 'VerilogSourceFile': <class 'pyEDAA.ProjectModel.Xilinx.Vivado.VerilogSourceFile'>, 'VivadoProjectFile': <class 'pyEDAA.ProjectModel.Xilinx.Vivado.VivadoProjectFile'>, 'WaveDoFile': <class 'pyEDAA.ProjectModel.MentorGraphics.QuestaSim.WaveDoFile'>, 'WaveformConfigFile': <class 'pyEDAA.ProjectModel.WaveformConfigFile'>, 'WaveformDatabaseFile': <class 'pyEDAA.ProjectModel.WaveformDatabaseFile'>, 'WaveformExchangeFile': <class 'pyEDAA.ProjectModel.WaveformExchangeFile'>, 'XDCConstraintFile': <class 'pyEDAA.ProjectModel.Xilinx.Vivado.XDCConstraintFile'>, 'XMLFile': <class 'pyEDAA.ProjectModel.XMLFile'>}¶Dictionary of all classes of type FileType
or derived variants
Construct a new class using this meta-class.
+className – The name of the class to construct.
baseClasses – The tuple of base-classes the class is derived from.
members – The dictionary of members for the constructed class.
slots – If true, store object attributes in __slots__ instead of __dict__
.
mixin – If true, make the class a Mixin-Class.
+If false, create slots if slots
is true.
+If none, preserve behavior of primary base-class.
singleton – If true, make the class a Singleton.
classMembers (Dict) –
The new class.
+AttributeError – If base-class has no ‘__slots__’ attribute.
AttributeError – If slot already exists in base-class.
alias of ExtendedType
Call self as a function.
+Implement delattr(self, name).
+Specialized __dir__ implementation for types.
+Return getattr(self, name).
+Check if an object is an instance.
+Return self|value.
+used to create the namespace for the class statement
+ +Return repr(self).
+Return value|self.
+Implement setattr(self, name, value).
+Return memory consumption of the type object.
+Check if a class is a subclass.
+Return a list of immediate subclasses.
+Check if the current class contains abstract methods and return a tuple of them.
+These abstract methods might be inherited from any base-class. If there are inherited abstract methods, check if +they are now implemented (overridden) by the current class that’s right now constructed.
+ +Return a generator to iterate all possible inheritance paths for a given list of base-classes.
+An inheritance path is expressed as a tuple of base-classes from current base-class (left-most item) to
+object
(right-most item).
If the class has abstract methods, replace the _new__
method, so it raises an exception.
newClass – The newly constructed class for further modifications.
+True
, if the class is abstract.
AbstractClassError – If the class is abstract and can’t be instantiated.
+If a class is a singleton, wrap the _new__
method, so it returns a cached object, if a first object was created.
Only the first object creation initializes the object.
+This implementation is threadsafe.
+ +Return a type’s method resolution order.
+A file type representing human-readable contents.
+Inheritance
+ +A file type representing XML contents.
+Inheritance
+ +A file type representing YAML contents.
+Inheritance
+ +A file type representing JSON contents.
+Inheritance
+ +A file type representing INI contents.
+Inheritance
+ +A file type representing TOML contents.
+Inheritance
+ +A file type representing content in TCL code.
+Inheritance
+ +A file type representing contents as Synopsys Design Constraints (SDC).
+Inheritance
+ +A file type representing contents as Python source code.
+Inheritance
+ +A FileSet represents a group of files. Filesets can have sub-filesets.
+The order of insertion is preserved. A fileset can be created standalone and +later associated to another fileset, design and/or project. Or a fileset, +design and/or project can be associated immediately while creating the +fileset.
+name (str
) – Name of this fileset.
topLevel (str
) – Name of the fileset’s toplevel.
directory (Path
) – Path of this fileset (absolute or relative to a parent fileset or design).
project (Project
) – Project the file is associated with.
design (Design
) – Design the file is associated with.
parent (Optional
[FileSet
]) – Parent fileset if this fileset is nested.
vhdlLibrary (Union
[str
, VHDLLibrary
]) – Default VHDL library for files in this fileset, if not specified for the file itself.
vhdlVersion (VHDLVersion
) – Default VHDL version for files in this fileset, if not specified for the file itself.
verilogVersion (SystemVerilogVersion
) – Default Verilog version for files in this fileset, if not specified for the file itself.
svVersion (SystemVerilogVersion
) – Default SystemVerilog version for files in this fileset, if not specified for the file itself.
srdlVersion (SystemRDLVersion
) – Default SystemRDL version for files in this fileset, if not specified for the file itself.
name –
topLevel –
directory –
project –
design –
parent –
vhdlLibrary –
vhdlVersion –
verilogVersion –
svVersion –
srdlVersion –
Inheritance
+ +Property setting or returning the project this fileset is used in.
+Property setting or returning the design this fileset is used in.
+Property setting or returning the directory this fileset is located in.
+Property setting or returning the parent fileset this fileset is used in.
+Read-only property returning the dictionary of sub-filesets.
+Method returning the files of this fileset.
+ +Method to add a single file to this fileset.
+file (File
) – A file to add to this fileset.
file –
Property setting or returning the VHDL library of this fileset.
+Property setting or returning the VHDL version of this fileset.
+Property setting or returning the Verilog version of this fileset.
+Property setting or returning the SystemVerilog version of this fileset.
+Returns number of attributes set on this fileset.
+The number if attributes set on this fileset.
+Index access for adding or setting attributes on this fileset.
+ +A VHDLLibrary represents a group of VHDL source files compiled into the same VHDL library.
+name (str
) – The VHDL libraries’ name.
project (Project
) – Project the VHDL library is associated with.
design (Design
) – Design the VHDL library is associated with.
vhdlVersion (VHDLVersion
) – Default VHDL version for files in this VHDL library, if not specified for the file itself.
name –
project –
design –
vhdlVersion –
Inheritance
+ + + +Property setting or returning the project this VHDL library is used in.
+Property setting or returning the design this VHDL library is used in.
+Read-only property to return all files in this VHDL library.
+Property setting or returning the VHDL version of this VHDL library.
+Returns number of attributes set on this VHDL library.
+The number if attributes set on this VHDL library.
+Index access for adding or setting attributes on this VHDL library.
+ +A Design represents a group of filesets and the source files therein.
+Each design contains at least one fileset - the default fileset. For +designs with VHDL source files, a independent VHDLLibraries overlay structure +exists.
+name (str
) – The design’s name.
topLevel (str
) – Name of the design’s toplevel.
directory (Path
) – Path of this design (absolute or relative to the project).
project (Project
) – Project the design is associated with.
vhdlVersion (VHDLVersion
) – Default VHDL version for files in this design, if not specified for the file itself.
verilogVersion (SystemVerilogVersion
) – Default Verilog version for files in this design, if not specified for the file itself.
svVersion (SystemVerilogVersion
) – Default SystemVerilog version for files in this design, if not specified for the file itself.
srdlVersion (SystemRDLVersion
) – Default SystemRDL version for files in this fileset, if not specified for the file itself.
name –
topLevel –
directory –
project –
vhdlVersion –
verilogVersion –
svVersion –
srdlVersion –
Inheritance
+ +Property setting or returning the project this design is used in.
+Property setting or returning the directory this design is located in.
+Property setting or returning the default fileset of this design.
+Read-only property returning the dictionary of filesets.
+Method returning the files of this design.
+ +Returns number of attributes set on this design.
+The number if attributes set on this design.
+Index access for adding or setting attributes on this design.
+ +A Project represents a group of designs and the source files therein.
+name (str
) – The project’s name.
rootDirectory (Path
) – Base-path to the project.
vhdlVersion (VHDLVersion
) – Default VHDL version for files in this project, if not specified for the file itself.
verilogVersion (SystemVerilogVersion
) – Default Verilog version for files in this project, if not specified for the file itself.
svVersion (SystemVerilogVersion
) – Default SystemVerilog version for files in this project, if not specified for the file itself.
name –
rootDirectory –
vhdlVersion –
verilogVersion –
svVersion –
Inheritance
+ +Property setting or returning the root directory this project is located in.
+Returns number of attributes set on this project.
+The number if attributes set on this project.
+Index access for adding or setting attributes on this project.
+ +pyEDAA.ProjectModel
", "pyEDAA.ProjectModel.Altera
", "pyEDAA.ProjectModel.Altera.Quartus
", "pyEDAA.ProjectModel.Attributes
", "pyEDAA.ProjectModel.GHDL
", "pyEDAA.ProjectModel.Intel
", "pyEDAA.ProjectModel.Intel.QuartusPrime
", "pyEDAA.ProjectModel.MentorGraphics
", "pyEDAA.ProjectModel.MentorGraphics.ModelSim
", "pyEDAA.ProjectModel.MentorGraphics.QuestaSim
", "pyEDAA.ProjectModel.OSVVM
", "pyEDAA.ProjectModel.VHDL
", "pyEDAA.ProjectModel.Verilog
", "pyEDAA.ProjectModel.Xilinx
", "pyEDAA.ProjectModel.Xilinx.ISE
", "pyEDAA.ProjectModel.Xilinx.Vivado
", "Static Type Checking Report"], "terms": {"\u00bd": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u00bc": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u215b": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u00be": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u215c": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u215d": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u215e": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "_": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u00b5": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u03c9": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u00aa": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u00ba": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u00b9": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u00b2": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u00b3": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u212c": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u2145": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u212d": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u2102": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u2146": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u03dd": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u2130": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u2147": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u2131": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u02c7": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u210f": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u210b": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u2111": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u2148": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u2110": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u2124": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u2112": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u2133": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u2115": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u2134": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u210c": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u2119": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u210d": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u211a": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u211c": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u211b": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u211d": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u03f5": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u03d5": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u03c5": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u03b5": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u03f0": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u03c6": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u03d6": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u03f1": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u03c2": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u03d1": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "\u2128": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34], "tbd": [0, 3], "pyedaa": [0, 5, 17], "projectmodel": [0, 5, 17], "wa": [0, 6, 15, 18], "split": 0, "from": [0, 2, 6, 18], "pyipcmi": 0, "v1": 0, "1": [0, 1, 4], "6": [0, 1, 5], "an": [0, 2, 4, 6, 7, 9, 10, 12, 15, 18, 28, 33], "independ": [0, 2, 18], "python": [0, 1, 5, 15, 18], "packag": [0, 4, 5, 15, 17], "librari": [1, 12, 18], "io": 1, "requir": [1, 2, 5, 6], "version": [1, 6, 18, 33], "licens": 1, "pytool": [1, 18], "5": 1, "0": [1, 15], "apach": [1, 15], "2": [1, 15], "none": [1, 7, 8, 9, 10, 11, 18], "pyvhdlmodel": 1, "27": 1, "pysvmodel": 1, "3": [1, 5], "pysystemrdlmodel": 1, "addit": [1, 2, 15], "need": [1, 2], "code": [1, 6, 15, 18], "collect": [1, 2], "static": [1, 18], "These": [1, 18], "ar": [1, 2, 6, 18], "develop": 1, "thu": 1, "sub": [1, 18], "evalu": 1, "further": [1, 18], "manual": [1, 4], "instal": 1, "us": [1, 4, 6, 18, 33], "txt": [1, 18], "file": [1, 4, 6, 7, 9, 11, 12, 17, 18, 20, 22, 24, 26, 27, 28, 30, 32, 33], "all": [1, 2, 6, 17, 18, 26, 27, 32, 33], "via": 1, "pip3": [1, 5], "The": [1, 2, 6, 18], "recurs": 1, "mandatori": 1, "too": 1, "u": [1, 5], "r": 1, "list": [1, 6, 7, 9, 11, 18], "pytest": [1, 13], "7": [1, 5], "4": [1, 15], "mit": 1, "Not": [1, 6], "yet": 1, "cov": 1, "mypi": [1, 34], "extens": 1, "psf": 1, "lxml": 1, "9": [1, 2], "bsd": 1, "claus": 1, "gener": [1, 6, 7, 8, 9, 10, 11, 13, 15, 18, 34], "doc": 1, "sphinx_btd_them": 1, "sphinx_fontawesom": 1, "gpl": 1, "sphinx_autodoc_typehint": 1, "19": 1, "build": [1, 15], "wheel": 1, "40": 1, "e": 1, "g": 1, "pypi": [1, 15], "ani": [1, 2, 6, 7, 9, 18, 33], "equival": [1, 2], "servic": [1, 2, 6, 15], "maintain": [1, 15], "dist": 1, "twine": 1, "thi": [2, 5, 6, 15, 18, 33], "i": [2, 4, 5, 6, 15, 18, 33], "local": [2, 6], "copi": [2, 6], "cc": [2, 15], "BY": [2, 15], "appli": [2, 6, 12], "onli": [2, 6, 18], "document": [2, 4, 6, 7, 8, 9, 10, 11], "project": [2, 4, 6, 7, 8, 9, 11, 15, 17, 18, 20, 24, 26, 27, 28, 32, 33], "corpor": 2, "law": [2, 6], "firm": 2, "doe": [2, 6], "provid": [2, 6, 15], "legal": [2, 6], "advic": 2, "distribut": [2, 6], "creat": [2, 15, 18], "lawyer": 2, "client": 2, "relationship": [2, 7, 8, 9, 10, 11], "make": [2, 6, 18], "its": [2, 6], "relat": 2, "inform": [2, 6], "avail": [2, 6], "basi": [2, 6], "give": [2, 6], "regard": [2, 6], "materi": 2, "under": [2, 6, 15], "damag": [2, 6], "result": [2, 6, 22], "fullest": 2, "extent": 2, "possibl": [2, 6, 18], "standard": [2, 4], "set": [2, 9, 12, 18, 26, 27], "creator": 2, "holder": 2, "mai": [2, 6], "share": [2, 6], "origin": [2, 6], "work": [2, 6], "authorship": [2, 6], "subject": [2, 6], "copyright": 2, "certain": 2, "specifi": [2, 4, 18], "below": [2, 6], "follow": [2, 6], "consider": 2, "purpos": [2, 6], "exhaust": 2, "do": [2, 6], "form": [2, 6], "part": [2, 6], "our": 2, "licensor": [2, 6], "intend": 2, "those": [2, 6], "author": [2, 6], "permiss": [2, 6], "wai": 2, "otherwis": [2, 6], "restrict": 2, "irrevoc": [2, 6], "should": [2, 6], "read": [2, 18], "understand": 2, "thei": [2, 18], "choos": [2, 6], "befor": 2, "also": [2, 6], "secur": 2, "necessari": 2, "so": [2, 18], "can": [2, 15, 18], "reus": 2, "expect": 2, "clearli": [2, 12], "mark": [2, 6], "includ": [2, 6], "except": [2, 6, 18], "more": [2, 6, 15], "By": 2, "one": [2, 6, 12, 18], "grant": 2, "If": [2, 4, 6, 18], "": [2, 6, 15, 18, 22, 30], "reason": [2, 6], "exampl": [2, 6], "becaus": 2, "applic": [2, 6], "regul": 2, "ha": [2, 6, 12, 15, 18], "still": 2, "have": [2, 6, 12, 18], "A": [2, 4, 6, 12, 18, 20, 24, 33], "special": [2, 6, 18], "request": 2, "ask": 2, "chang": [2, 6, 30], "describ": [2, 6, 15], "although": 2, "you": [2, 6], "encourag": 2, "respect": 2, "where": [2, 6], "exercis": [2, 6], "defin": [2, 4, 6, 30], "accept": 2, "agre": [2, 6], "bound": 2, "To": [2, 6], "contract": [2, 6], "your": [2, 6], "benefit": 2, "receiv": [2, 6], "adapt": 2, "mean": [2, 6], "similar": 2, "deriv": [2, 4, 6, 15, 18], "base": [2, 4, 6, 18, 26, 27, 32, 33], "upon": 2, "which": [2, 6], "translat": [2, 6], "alter": 2, "arrang": 2, "transform": [2, 6], "modifi": [2, 6], "manner": 2, "held": 2, "For": [2, 6, 18], "music": 2, "perform": [2, 6], "sound": 2, "record": 2, "alwai": 2, "produc": 2, "synch": 2, "time": 2, "move": 2, "imag": 2, "contribut": 2, "accord": 2, "close": 2, "without": [2, 6], "broadcast": 2, "how": [2, 5, 6, 18], "label": 2, "categor": 2, "b": 2, "effect": 2, "technolog": 2, "measur": 2, "absenc": 2, "proper": 2, "circumv": 2, "fulfil": 2, "oblig": [2, 6], "articl": 2, "11": 2, "wipo": 2, "treati": 2, "adopt": 2, "decemb": 2, "20": 2, "1996": 2, "agreement": [2, 6], "fair": 2, "deal": 2, "artist": 2, "literari": 2, "individu": [2, 6], "entiti": [2, 4, 6], "process": 2, "reproduct": [2, 6], "displai": [2, 6], "dissemin": 2, "commun": [2, 6], "import": [2, 6], "member": [2, 18], "access": [2, 18], "place": [2, 6], "chosen": 2, "them": [2, 18], "than": 2, "direct": [2, 6], "96": 2, "ec": 2, "european": 2, "parliament": 2, "council": 2, "march": 2, "protect": 2, "amend": 2, "succeed": 2, "well": 2, "essenti": 2, "anywher": 2, "world": 2, "correspond": 2, "herebi": [2, 6], "worldwid": [2, 6], "royalti": [2, 6], "free": [2, 6], "non": [2, 6], "sublicens": [2, 6], "exclus": [2, 6], "reproduc": [2, 6], "whole": [2, 6], "avoid": 2, "doubt": 2, "compli": [2, 6], "media": [2, 6], "format": [2, 6, 18], "technic": 2, "modif": [2, 6, 18], "allow": [2, 18], "whether": [2, 6], "now": [2, 15, 18], "known": 2, "hereaft": 2, "waiv": 2, "assert": [2, 6], "forbid": 2, "simpli": 2, "never": 2, "downstream": 2, "recipi": [2, 6], "offer": [2, 6], "everi": 2, "automat": 2, "No": 2, "impos": 2, "differ": [2, 6], "endors": 2, "noth": [2, 6], "constitut": [2, 6], "constru": [2, 6], "impli": [2, 6], "connect": 2, "sponsor": 2, "offici": 2, "statu": 2, "design": [2, 3, 4, 6, 8, 9, 10, 11, 12, 15, 17, 18, 20, 24, 33], "moral": 2, "integr": [2, 15], "nor": 2, "privaci": 2, "person": 2, "howev": [2, 6], "patent": 2, "trademark": 2, "directli": 2, "through": [2, 6], "societi": 2, "voluntari": 2, "waivabl": 2, "statutori": 2, "compulsori": 2, "scheme": 2, "In": [2, 6], "case": 2, "expressli": 2, "reserv": 2, "made": [2, 6], "must": [2, 6], "retain": [2, 6], "suppli": 2, "identif": [2, 6], "pseudonym": 2, "notic": [2, 6], "refer": [2, 4, 12], "uri": 2, "hyperlink": 2, "practic": 2, "indic": [2, 6], "previou": 2, "text": [2, 6, 18], "satisfi": 2, "medium": [2, 6], "context": [2, 4], "resourc": 2, "remov": 2, "prevent": 2, "extract": 2, "substanti": 2, "portion": 2, "content": [2, 6, 18], "supplement": 2, "replac": [2, 6, 18], "unless": [2, 6], "separ": [2, 6], "undertaken": 2, "represent": [2, 4], "kind": [2, 6], "concern": 2, "express": [2, 6, 18], "titl": [2, 6], "merchant": [2, 6], "fit": [2, 6], "particular": [2, 6], "infring": [2, 6], "latent": 2, "defect": 2, "accuraci": 2, "presenc": 2, "error": 2, "discover": 2, "full": 2, "event": [2, 6], "liabl": [2, 6], "theori": [2, 6], "neglig": [2, 6], "indirect": [2, 6], "incident": [2, 6], "consequenti": [2, 6], "punit": 2, "exemplari": 2, "loss": [2, 6], "cost": 2, "expens": 2, "aris": [2, 6], "out": [2, 6], "even": [2, 6], "been": [2, 6, 15], "advis": [2, 6], "abov": [2, 5, 6], "shall": [2, 6, 12], "most": [2, 18], "approxim": 2, "absolut": [2, 18], "waiver": 2, "here": 2, "fail": 2, "reinstat": 2, "date": [2, 6], "violat": 2, "cure": 2, "within": [2, 6], "30": 2, "dai": 2, "discoveri": 2, "affect": 2, "seek": 2, "remedi": 2, "stop": 2, "surviv": 2, "state": [2, 6], "herein": [2, 6], "reduc": 2, "could": 2, "lawfulli": 2, "provis": 2, "deem": 2, "unenforc": 2, "reform": 2, "minimum": 2, "enforc": 2, "cannot": [2, 6], "sever": 2, "remain": [2, 6], "failur": [2, 6], "consent": 2, "privileg": 2, "immun": 2, "jurisdict": 2, "parti": [2, 6, 15], "notwithstand": [2, 6], "elect": 2, "publish": 2, "instanc": [2, 18, 33], "consid": 2, "permit": 2, "polici": 2, "creativecommon": 2, "org": [2, 6], "logo": 2, "prior": 2, "written": [2, 6], "unauthor": 2, "paragraph": 2, "contact": 2, "goal": [3, 12], "lrm": 4, "languag": [4, 6, 18, 33], "name": [4, 6, 7, 9, 10, 11, 12, 17, 18], "given": [4, 18], "ieee": [4, 30], "hardwar": 4, "descript": [4, 6, 7, 8, 9, 10, 11], "vhdl": [4, 12, 17, 18, 22, 33], "revis": [4, 6], "1076": 4, "2019": 4, "2008": 4, "aka": 4, "iec": 4, "61691": 4, "2011": 4, "2002": 4, "ed": 4, "2004": [4, 6], "10": 4, "2000": 4, "1993": 4, "1987": 4, "verilog": [4, 15, 17, 18, 22, 33], "tbc": 4, "system": [4, 6], "class": [4, 5, 6, 12, 15, 18, 20, 21, 22, 24, 26, 27, 28, 30, 32, 33], "ancestor": 4, "other": [4, 6], "physic": 4, "fileset": [4, 7, 8, 12, 15, 17, 18], "group": [4, 9, 11, 12, 18], "default": [4, 18], "pre": 4, "exist": [4, 18], "vhdllibrari": [4, 7, 9, 17, 18], "namespac": [4, 15, 18], "organ": 4, "unit": [4, 11], "configur": [4, 6, 18, 26, 27], "due": 5, "problem": 5, "meta": [5, 18], "__getattr__": 5, "see": [5, 6], "section": [5, 6], "sourc": [6, 12, 15, 18, 21, 33], "januari": 6, "term": 6, "AND": 6, "condit": 6, "FOR": 6, "owner": 6, "union": [6, 7, 9, 18], "act": 6, "control": 6, "common": [6, 15], "power": 6, "caus": 6, "manag": [6, 15], "ii": 6, "ownership": 6, "fifti": 6, "percent": 6, "50": 6, "outstand": 6, "iii": 6, "benefici": 6, "prefer": 6, "softwar": 6, "object": [6, 12, 18], "mechan": 6, "compil": [6, 18], "convers": 6, "type": [6, 18], "attach": 6, "appendix": 6, "editori": 6, "annot": 6, "elabor": [6, 18], "repres": [6, 18, 33], "mere": 6, "link": 6, "bind": 6, "interfac": 6, "thereof": 6, "intention": 6, "submit": 6, "inclus": 6, "behalf": 6, "electron": [6, 18], "verbal": 6, "sent": 6, "mail": 6, "issu": 6, "track": 6, "discuss": 6, "improv": 6, "exclud": 6, "conspicu": 6, "write": [6, 7, 8, 9, 10, 11], "contributor": 6, "whom": 6, "subsequ": 6, "incorpor": 6, "each": [6, 18], "perpetu": 6, "charg": 6, "prepar": 6, "publicli": 6, "sell": 6, "transfer": 6, "claim": 6, "necessarili": 6, "alon": 6, "combin": 6, "institut": 6, "litig": 6, "against": 6, "cross": 6, "counterclaim": 6, "lawsuit": 6, "alleg": 6, "contributori": 6, "termin": 6, "meet": 6, "carri": 6, "promin": 6, "attribut": [6, 12, 15, 17, 18, 33], "pertain": 6, "readabl": [6, 18], "contain": [6, 11, 12, 18], "least": [6, 12, 18], "along": 6, "wherev": 6, "third": [6, 15], "normal": 6, "appear": 6, "add": [6, 18], "own": [6, 15], "alongsid": 6, "addendum": 6, "statement": [6, 18], "explicitli": 6, "supersed": 6, "execut": [6, 18], "trade": 6, "product": 6, "customari": 6, "AS": 6, "OR": 6, "OF": 6, "either": 6, "sole": 6, "respons": 6, "determin": 6, "appropri": 6, "assum": 6, "risk": 6, "associ": [6, 18], "tort": 6, "deliber": 6, "grossli": 6, "charact": 6, "inabl": 6, "goodwil": 6, "stoppag": 6, "comput": 6, "malfunct": 6, "commerci": 6, "while": [6, 15, 18], "fee": 6, "support": [6, 15, 22], "indemn": 6, "right": [6, 18], "consist": 6, "indemnifi": 6, "defend": 6, "hold": 6, "harmless": 6, "incur": 6, "boilerpl": 6, "field": [6, 18], "enclos": 6, "bracket": 6, "identifi": 6, "don": 6, "t": [6, 18], "comment": 6, "syntax": 6, "we": 6, "recommend": 6, "same": [6, 18], "print": 6, "page": 6, "easier": 6, "archiv": 6, "yyyi": 6, "complianc": 6, "obtain": 6, "http": 6, "www": 6, "specif": [6, 18, 26, 27, 32], "govern": 6, "eda": [7, 8, 9, 10, 12, 15], "export": [7, 8, 9, 10, 11], "_name": [7, 9, 10, 11], "str": [7, 9, 10, 11, 18], "_project": [7, 8, 9, 11], "nullabl": [7, 8, 9, 10, 11], "_directori": [7, 9], "path": [7, 8, 9, 10, 18], "_fileset": [7, 8, 9], "dict": [7, 9, 10, 18], "_defaultfileset": 7, "_vhdllibrari": [7, 9], "_vhdlversion": [7, 9, 10, 11], "vhdlversion": [7, 9, 10, 11, 17, 18], "_verilogvers": [7, 9, 10], "verilogvers": [7, 9, 10, 17, 18], "_svversion": [7, 9, 10], "systemverilogvers": [7, 9, 10, 18], "_externalvhdllibrari": 7, "def": [7, 8, 9, 10, 11], "__init__": [7, 8, 9, 10, 11, 17, 18, 21], "self": [7, 8, 9, 10, 11, 18], "directori": [7, 9, 17, 18], "svversion": [7, 9, 10, 17, 18], "properti": [7, 8, 9, 10, 11, 18], "setter": [7, 8, 9, 10, 11], "valu": [7, 8, 9, 10, 11, 18, 30], "resolvedpath": [7, 8, 9, 10, 17, 18], "defaultfileset": [7, 17, 18], "filetyp": [7, 8, 9, 17, 18], "externalvhdllibrari": 7, "addfileset": [7, 17, 18], "iter": [7, 9, 18], "addfil": [7, 9, 17, 18], "metaclass": [8, 18], "_path": 8, "_design": [8, 9, 10, 11], "_parent": 9, "_file": [9, 11], "parent": [9, 12, 17, 18], "_rootdirectori": 10, "rootdirectori": [10, 17, 18], "primari": [11, 18], "semant": 12, "child": 12, "overal": 12, "hierarchi": 12, "multipl": [12, 15, 18], "variant": [12, 18], "usual": 12, "element": 12, "placehold": [13, 34], "abstract": [15, 18], "model": 15, "hdl": [15, 18], "tool": [15, 18, 26, 27, 32], "unifi": 15, "framework": 15, "implement": [15, 18], "logic": 15, "concret": 15, "consum": 15, "higher": 15, "level": 15, "featur": 15, "top": 15, "input": 15, "open": 15, "simul": [15, 18, 22], "synthesi": 15, "ghdl": [15, 17, 18], "icaru": 15, "veril": 15, "yosi": 15, "rout": 15, "vtr": 15, "nextpnr": 15, "etc": 15, "ip": [15, 33], "core": [15, 33], "xilinx": [15, 17, 18], "vivado": [15, 17, 18, 31], "osvvm": [15, 17, 18], "nest": [15, 18], "dataset": 15, "valid": [15, 17, 18], "becam": 15, "first": [15, 18], "citizen": 15, "eda\u00b2": 15, "got": 15, "patrick": 15, "lehmann": 15, "unai": 15, "martinez": 15, "corral": 15, "accompani": 15, "creativ": 15, "24": 15, "aug": 15, "2023": 15, "21": 15, "52": 15, "modul": 17, "altera": [17, 18], "quartu": [17, 18, 19, 24], "keyvalueattribut": [17, 18, 21], "intel": [17, 18], "quartusprim": [17, 18, 23], "mentorgraph": [17, 18], "modelsim": [17, 18, 25], "questasim": [17, 18, 25], "ISE": [17, 18, 31], "usedinattribut": [17, 18, 31, 33], "__new__": [17, 18], "__base__": [17, 18], "__call__": [17, 18], "__delattr__": [17, 18], "__dir__": [17, 18], "__getattribute__": [17, 18], "__instancecheck__": [17, 18], "__or__": [17, 18], "__prepare__": [17, 18], "__repr__": [17, 18], "__ror__": [17, 18], "__setattr__": [17, 18], "__sizeof__": [17, 18], "__subclasscheck__": [17, 18], "__subclasses__": [17, 18], "__text_signature__": [17, 18], "_checkforabstractmethod": [17, 18], "_iteratebaseclasspath": [17, 18], "_wrapnewmethodifabstract": [17, 18], "_wrapnewmethodifsingleton": [17, 18], "mro": [17, 18], "humanreadablecont": [17, 18], "xmlcontent": [17, 18], "yamlcont": [17, 18], "jsoncont": [17, 18], "inicont": [17, 18], "tomlcont": [17, 18], "tclcontent": [17, 18], "sdccontent": [17, 18], "pythoncont": [17, 18], "toplevel": [17, 18], "filesetcount": [17, 18], "totalfilesetcount": [17, 18], "filecount": [17, 18], "totalfilecount": [17, 18], "__len__": [17, 18], "__getitem__": [17, 18], "__setitem__": [17, 18], "__delitem__": [17, 18], "__str__": [17, 18], "designcount": [17, 18], "submodul": [18, 19, 23, 25, 31], "undocu": [18, 21, 33], "construct": 18, "human": 18, "xml": [18, 33], "yaml": 18, "json": 18, "ini": 18, "toml": 18, "tcl": 18, "synopsi": [18, 20, 24], "constraint": [18, 20, 24, 32, 33], "sdc": [18, 20, 24], "textfil": 18, "logfil": 18, "log": 18, "xmlfile": 18, "sourcefil": 18, "hdlsourcefil": 18, "rdlsourcefil": 18, "rdl": 18, "netlistfil": 18, "netlist": 18, "edifnetlistfil": 18, "edif": 18, "interchang": 18, "tclsourcefil": 18, "vhdlsourcefil": [18, 33], "verilogbasefil": 18, "verilogsourcefil": [18, 33], "verilogheaderfil": 18, "header": 18, "systemverilogbasefil": 18, "systemverilogsourcefil": 18, "systemverilog": 18, "systemverilogheaderfil": 18, "systemrdlsourcefil": 18, "systemrdl": 18, "pythonsourcefil": 18, "cocotbpythonfil": 18, "cocotb": 18, "constraintfil": [18, 33], "projectfil": 18, "csourcefil": 18, "ansi": 18, "c": 18, "cppsourcefil": 18, "settingfil": 18, "simulationanalysisfil": 18, "analysi": 18, "simulationelaborationfil": 18, "simulationstartfil": 18, "start": 18, "up": 18, "simulationrunfil": 18, "run": 18, "waveformconfigfil": 18, "waveform": [18, 22, 26, 27, 30], "waveformdatabasefil": 18, "databas": 18, "waveformexchangefil": 18, "exchang": [18, 30], "therein": 18, "inherit": [18, 21, 33], "dictionari": 18, "kwarg": 18, "done": 18, "regist": 18, "extendedtyp": 18, "paramet": 18, "classmemb": 18, "ghdlwaveformfil": [18, 22], "ipcoredescriptionfil": [18, 33], "ipcoreinstantiationfil": [18, 33], "iseprojectfil": [18, 32], "modelsiminifil": [18, 26, 27], "modelsimprojectfil": [18, 26, 27], "osvvmprojectfil": [18, 28], "quartusprojectfil": [18, 20, 24], "sdcconstraintfil": [18, 20, 24], "ucfconstraintfil": [18, 32], "valuechangedumpfil": [18, 30], "vivadoprojectfil": [18, 33], "wavedofil": [18, 26, 27], "xdcconstraintfil": [18, 33], "tupl": 18, "cl": 18, "classnam": 18, "baseclass": 18, "arg": 18, "new": 18, "slot": 18, "true": 18, "store": 18, "__slots__": 18, "instead": 18, "__dict__": 18, "mixin": 18, "fals": 18, "preserv": 18, "behavior": 18, "singleton": 18, "return": 18, "rais": 18, "attributeerror": 18, "alreadi": 18, "alia": 18, "call": 18, "function": 18, "delattr": 18, "getattr": 18, "check": 18, "classmethod": 18, "bool": 18, "repr": 18, "setattr": 18, "memori": 18, "consumpt": 18, "subclass": 18, "immedi": 18, "current": 18, "method": 18, "might": 18, "overridden": 18, "callabl": 18, "left": 18, "item": 18, "newclass": 18, "_new__": 18, "newli": 18, "abstractclasserror": 18, "instanti": [18, 33], "wrap": 18, "cach": 18, "creation": 18, "initi": 18, "threadsaf": 18, "singl": 18, "resolut": 18, "order": 18, "posixpath": 18, "srdlversion": 18, "insert": 18, "standalon": 18, "later": 18, "anoth": 18, "Or": 18, "rel": 18, "option": 18, "itself": 18, "systemrdlvers": 18, "locat": 18, "resolv": 18, "filter": 18, "handl": 18, "int": 18, "number": 18, "excl": 18, "incl": 18, "kei": 18, "index": 18, "typeerror": 18, "when": 18, "ad": 18, "delet": 18, "overlai": 18, "structur": 18, "root": 18, "qpf": [20, 24], "ghw": 22, "pro": 28, "vcd": 30, "std": 30, "1364": 30, "xpr": 33, "xdc": 33, "ipcor": 33, "xci": 33}, "objects": {"pyEDAA": [[18, 0, 0, "-", "ProjectModel"]], "pyEDAA.ProjectModel": [[19, 0, 0, "-", "Altera"], [18, 1, 1, "", "Attribute"], [21, 0, 0, "-", "Attributes"], [18, 1, 1, "", "Design"], [18, 1, 1, "", "FileSet"], [18, 1, 1, "", "FileType"], [22, 0, 0, "-", "GHDL"], [18, 1, 1, "", "HumanReadableContent"], [18, 1, 1, "", "INIContent"], [23, 0, 0, "-", "Intel"], [18, 1, 1, "", "JSONContent"], [25, 0, 0, "-", "MentorGraphics"], [28, 0, 0, "-", "OSVVM"], [18, 1, 1, "", "Project"], [18, 1, 1, "", "PythonContent"], [18, 1, 1, "", "SDCContent"], [18, 1, 1, "", "TCLContent"], [18, 1, 1, "", "TOMLContent"], [29, 0, 0, "-", "VHDL"], [18, 1, 1, "", "VHDLLibrary"], [30, 0, 0, "-", "Verilog"], [18, 1, 1, "", "XMLContent"], [31, 0, 0, "-", "Xilinx"], [18, 1, 1, "", "YAMLContent"]], "pyEDAA.ProjectModel.Altera": [[20, 0, 0, "-", "Quartus"]], "pyEDAA.ProjectModel.Attributes": [[21, 1, 1, "", "KeyValueAttribute"]], "pyEDAA.ProjectModel.Attributes.KeyValueAttribute": [[21, 2, 1, "", "__init__"]], "pyEDAA.ProjectModel.Design": [[18, 3, 1, "", "DefaultFileSet"], [18, 3, 1, "", "Directory"], [18, 3, 1, "", "FileSetCount"], [18, 3, 1, "", "FileSets"], [18, 2, 1, "", "Files"], [18, 3, 1, "", "Name"], [18, 3, 1, "", "Project"], [18, 3, 1, "", "ResolvedPath"], [18, 3, 1, "", "TopLevel"], [18, 3, 1, "", "TotalFileSetCount"], [18, 2, 1, "", "Validate"], [18, 2, 1, "", "__delitem__"], [18, 2, 1, "", "__getitem__"], [18, 2, 1, "", "__init__"], [18, 2, 1, "", "__len__"], [18, 2, 1, "", "__setitem__"], [18, 2, 1, "", "__str__"]], "pyEDAA.ProjectModel.FileSet": [[18, 2, 1, "", "AddFile"], [18, 2, 1, "", "AddFileSet"], [18, 2, 1, "", "AddFileSets"], [18, 2, 1, "", "AddFiles"], [18, 3, 1, "", "Design"], [18, 3, 1, "", "Directory"], [18, 3, 1, "", "FileCount"], [18, 3, 1, "", "FileSetCount"], [18, 3, 1, "", "FileSets"], [18, 2, 1, "", "Files"], [18, 3, 1, "", "Name"], [18, 3, 1, "", "Parent"], [18, 3, 1, "", "Project"], [18, 3, 1, "", "ResolvedPath"], [18, 3, 1, "", "SVVersion"], [18, 3, 1, "", "TopLevel"], [18, 3, 1, "", "TotalFileCount"], [18, 3, 1, "", "TotalFileSetCount"], [18, 3, 1, "", "VHDLLibrary"], [18, 3, 1, "", "VHDLVersion"], [18, 2, 1, "", "Validate"], [18, 3, 1, "", "VerilogVersion"], [18, 2, 1, "", "__delitem__"], [18, 2, 1, "", "__getitem__"], [18, 2, 1, "", "__init__"], [18, 2, 1, "", "__len__"], [18, 2, 1, "", "__setitem__"], [18, 2, 1, "", "__str__"]], "pyEDAA.ProjectModel.FileType": [[18, 4, 1, "", "FileTypes"], [18, 4, 1, "", "__base__"], [18, 2, 1, "", "__call__"], [18, 2, 1, "", "__delattr__"], [18, 2, 1, "", "__dir__"], [18, 2, 1, "", "__getattribute__"], [18, 2, 1, "", "__init__"], [18, 2, 1, "", "__instancecheck__"], [18, 2, 1, "", "__new__"], [18, 2, 1, "", "__or__"], [18, 2, 1, "", "__prepare__"], [18, 2, 1, "", "__repr__"], [18, 2, 1, "", "__ror__"], [18, 2, 1, "", "__setattr__"], [18, 2, 1, "", "__sizeof__"], [18, 2, 1, "", "__subclasscheck__"], [18, 2, 1, "", "__subclasses__"], [18, 4, 1, "", "__text_signature__"], [18, 2, 1, "", "_checkForAbstractMethods"], [18, 2, 1, "", "_iterateBaseClassPaths"], [18, 2, 1, "", "_wrapNewMethodIfAbstract"], [18, 2, 1, "", "_wrapNewMethodIfSingleton"], [18, 2, 1, "", "mro"]], "pyEDAA.ProjectModel.Intel": [[24, 0, 0, "-", "QuartusPrime"]], "pyEDAA.ProjectModel.MentorGraphics": [[26, 0, 0, "-", "ModelSim"], [27, 0, 0, "-", "QuestaSim"]], "pyEDAA.ProjectModel.Project": [[18, 3, 1, "", "DesignCount"], [18, 3, 1, "", "Name"], [18, 3, 1, "", "ResolvedPath"], [18, 3, 1, "", "RootDirectory"], [18, 2, 1, "", "Validate"], [18, 2, 1, "", "__delitem__"], [18, 2, 1, "", "__getitem__"], [18, 2, 1, "", "__init__"], [18, 2, 1, "", "__len__"], [18, 2, 1, "", "__setitem__"], [18, 2, 1, "", "__str__"]], "pyEDAA.ProjectModel.VHDLLibrary": [[18, 3, 1, "", "Design"], [18, 3, 1, "", "FileCount"], [18, 3, 1, "", "Files"], [18, 3, 1, "", "Project"], [18, 3, 1, "", "VHDLVersion"], [18, 2, 1, "", "__delitem__"], [18, 2, 1, "", "__getitem__"], [18, 2, 1, "", "__init__"], [18, 2, 1, "", "__len__"], [18, 2, 1, "", "__setitem__"], [18, 2, 1, "", "__str__"]], "pyEDAA.ProjectModel.Xilinx": [[32, 0, 0, "-", "ISE"], [33, 0, 0, "-", "Vivado"]], "pyEDAA.ProjectModel.Xilinx.Vivado": [[33, 1, 1, "", "UsedInAttribute"]]}, "objtypes": {"0": "py:module", "1": "py:class", "2": "py:method", "3": "py:property", "4": "py:attribute"}, "objnames": {"0": ["py", "module", "Python module"], "1": ["py", "class", "Python class"], "2": ["py", "method", "Python method"], "3": ["py", "property", "Python property"], "4": ["py", "attribute", "Python attribute"]}, "titleterms": {"changelog": 0, "upcom": 0, "releas": 0, "01": 0, "09": 0, "2021": [0, 15], "depend": 1, "pyedaa": [1, 15, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33], "projectmodel": [1, 15, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33], "packag": 1, "unit": 1, "test": 1, "coverag": [1, 13], "type": [1, 3, 34], "check": [1, 34], "option": 1, "sphinx": 1, "document": [1, 15], "publish": 1, "ci": 1, "server": 1, "onli": 1, "creativ": 2, "common": 2, "attribut": [2, 21], "4": [2, 6], "0": [2, 6], "intern": 2, "us": [2, 5, 15], "public": 2, "licens": [2, 6, 15], "section": 2, "1": [2, 6], "definit": [2, 6, 7, 8, 9, 10, 11], "2": [2, 6], "scope": 2, "3": [2, 6], "condit": 2, "sui": 2, "generi": 2, "databas": 2, "right": 2, "5": [2, 6], "disclaim": [2, 6], "warranti": [2, 6], "limit": [2, 6], "liabil": [2, 6], "6": [2, 6], "term": 2, "termin": 2, "7": [2, 6], "other": 2, "8": [2, 6], "interpret": 2, "file": [3, 8, 15], "content": 3, "overal": 3, "hierarchi": 3, "glossari": 4, "instal": 5, "updat": 5, "pip": 5, "from": [5, 15], "pypi": 5, "uninstal": 5, "local": 5, "directori": 5, "setup": 5, "py": 5, "legaci": 5, "apach": 6, "grant": 6, "copyright": 6, "patent": 6, "redistribut": 6, "submiss": 6, "contribut": 6, "trademark": 6, "9": 6, "accept": 6, "addit": 6, "design": 7, "todo": [7, 8, 9, 10, 11], "condens": [7, 8, 9, 10, 11], "class": [7, 8, 9, 10, 11, 17], "fileset": 9, "project": [10, 12], "vhdl": [11, 29], "librari": 11, "vhdllibrari": 11, "model": 12, "report": [13, 34], "index": [14, 16], "The": 15, "main": 15, "goal": 15, "case": 15, "new": 15, "oct": 15, "read": 15, "xpr": 15, "pro": 15, "sep": 15, "extract": 15, "pyipcmi": 15, "contributor": 15, "modul": 16, "python": 17, "refer": 17, "altera": [19, 20], "quartu": 20, "ghdl": 22, "intel": [23, 24], "quartusprim": 24, "mentorgraph": [25, 26, 27], "modelsim": 26, "questasim": 27, "osvvm": 28, "verilog": 30, "xilinx": [31, 32, 33], "ISE": 32, "vivado": 33, "static": 34}, "envversion": {"sphinx.domains.c": 3, "sphinx.domains.changeset": 1, "sphinx.domains.citation": 1, "sphinx.domains.cpp": 9, "sphinx.domains.index": 1, "sphinx.domains.javascript": 3, "sphinx.domains.math": 2, "sphinx.domains.python": 4, "sphinx.domains.rst": 2, "sphinx.domains.std": 2, "sphinx.ext.intersphinx": 1, "sphinx.ext.todo": 2, "sphinx.ext.viewcode": 1, "sphinx": 60}, "alltitles": {"ChangeLog": [[0, "changelog"]], "Upcoming Release": [[0, "upcoming-release"]], "01.09.2021": [[0, "id1"]], "Dependency": [[1, "dependency"]], "pyEDAA.ProjectModel Package": [[1, "pyedaa-projectmodel-package"]], "Unit Testing / Coverage / Type Checking (Optional)": [[1, "unit-testing-coverage-type-checking-optional"]], "Sphinx Documentation (Optional)": [[1, "sphinx-documentation-optional"]], "Packaging (Optional)": [[1, "packaging-optional"]], "Publishing (CI-Server only)": [[1, "publishing-ci-server-only"]], "Creative Commons Attribution 4.0 International": [[2, "creative-commons-attribution-4-0-international"]], "Using Creative Commons Public Licenses": [[2, null]], "Section 1 \u2013 Definitions.": [[2, "section-1-definitions"]], "Section 2 \u2013 Scope.": [[2, "section-2-scope"]], "Section 3 \u2013 License Conditions.": [[2, "section-3-license-conditions"]], "Section 4 \u2013 Sui Generis Database Rights.": [[2, "section-4-sui-generis-database-rights"]], "Section 5 \u2013 Disclaimer of Warranties and Limitation of Liability.": [[2, "section-5-disclaimer-of-warranties-and-limitation-of-liability"]], "Section 6 \u2013 Term and Termination.": [[2, "section-6-term-and-termination"]], "Section 7 \u2013 Other Terms and Conditions.": [[2, "section-7-other-terms-and-conditions"]], "Section 8 \u2013 Interpretation.": [[2, "section-8-interpretation"]], "File Types": [[3, "file-types"]], "Content Types": [[3, "content-types"]], "Overall Hierarchy": [[3, "overall-hierarchy"]], "Glossary": [[4, "glossary"]], "Installation/Updates": [[5, "installation-updates"]], "Using PIP": [[5, "using-pip"]], "Installation from PyPI using PIP": [[5, "installation-from-pypi-using-pip"]], "Updating from PyPI using PIP": [[5, "updating-from-pypi-using-pip"]], "Uninstallation using PIP": [[5, "uninstallation-using-pip"]], "Installation from local directory using PIP": [[5, "installation-from-local-directory-using-pip"]], "Using setup.py (legacy)": [[5, "using-setup-py-legacy"]], "Installation using setup.py": [[5, "installation-using-setup-py"]], "Apache License 2.0": [[6, "apache-license-2-0"]], "1. Definitions.": [[6, "definitions"]], "2. Grant of Copyright License.": [[6, "grant-of-copyright-license"]], "3. Grant of Patent License.": [[6, "grant-of-patent-license"]], "4. Redistribution.": [[6, "redistribution"]], "5. Submission of Contributions.": [[6, "submission-of-contributions"]], "6. Trademarks.": [[6, "trademarks"]], "7. Disclaimer of Warranty.": [[6, "disclaimer-of-warranty"]], "8. Limitation of Liability.": [[6, "limitation-of-liability"]], "9. Accepting Warranty or Additional Liability.": [[6, "accepting-warranty-or-additional-liability"]], "Design": [[7, "design"]], "Todo": [[7, "id1"], [8, "id1"], [9, "id1"], [10, "id1"], [11, "id1"]], "Condensed definition of class Design": [[7, "condensed-definition-of-class-design"]], "File": [[8, "file"]], "Condensed definition of class File": [[8, "condensed-definition-of-class-file"]], "FileSet": [[9, "fileset"]], "Condensed definition of class FileSet": [[9, "condensed-definition-of-class-fileset"]], "Project": [[10, "project"]], "Condensed definition of class Project": [[10, "condensed-definition-of-class-project"]], "VHDL Library": [[11, "vhdl-library"]], "Condensed definition of class VHDLLibrary": [[11, "condensed-definition-of-class-vhdllibrary"]], "Project Model": [[12, "project-model"]], "Coverage Report": [[13, "coverage-report"]], "Index": [[14, "index"]], "The pyEDAA.ProjectModel Documentation": [[15, "the-pyedaa-projectmodel-documentation"]], "Main Goals": [[15, "main-goals"]], "Use Cases": [[15, "use-cases"]], "News": [[15, "news"]], "Oct. 2021 - Reading *.xpr and *.pro Files": [[15, "oct-2021-reading-xpr-and-pro-files"]], "Sep. 2021 - Extracted ProjectModel from pyIPCMI": [[15, "sep-2021-extracted-projectmodel-from-pyipcmi"]], "Contributors": [[15, "contributors"]], "License": [[15, "license"]], "Module Index": [[16, "module-index"]], "Python Class Reference": [[17, "python-class-reference"]], "pyEDAA.ProjectModel": [[18, "pyedaa-projectmodel"]], "pyEDAA.ProjectModel.Altera": [[19, "pyedaa-projectmodel-altera"]], "pyEDAA.ProjectModel.Altera.Quartus": [[20, "pyedaa-projectmodel-altera-quartus"]], "pyEDAA.ProjectModel.Attributes": [[21, "pyedaa-projectmodel-attributes"]], "pyEDAA.ProjectModel.GHDL": [[22, "pyedaa-projectmodel-ghdl"]], "pyEDAA.ProjectModel.Intel": [[23, "pyedaa-projectmodel-intel"]], "pyEDAA.ProjectModel.Intel.QuartusPrime": [[24, "pyedaa-projectmodel-intel-quartusprime"]], "pyEDAA.ProjectModel.MentorGraphics": [[25, "pyedaa-projectmodel-mentorgraphics"]], "pyEDAA.ProjectModel.MentorGraphics.ModelSim": [[26, "pyedaa-projectmodel-mentorgraphics-modelsim"]], "pyEDAA.ProjectModel.MentorGraphics.QuestaSim": [[27, "pyedaa-projectmodel-mentorgraphics-questasim"]], "pyEDAA.ProjectModel.OSVVM": [[28, "pyedaa-projectmodel-osvvm"]], "pyEDAA.ProjectModel.VHDL": [[29, "pyedaa-projectmodel-vhdl"]], "pyEDAA.ProjectModel.Verilog": [[30, "pyedaa-projectmodel-verilog"]], "pyEDAA.ProjectModel.Xilinx": [[31, "pyedaa-projectmodel-xilinx"]], "pyEDAA.ProjectModel.Xilinx.ISE": [[32, "pyedaa-projectmodel-xilinx-ise"]], "pyEDAA.ProjectModel.Xilinx.Vivado": [[33, "pyedaa-projectmodel-xilinx-vivado"]], "Static Type Checking Report": [[34, "static-type-checking-report"]]}, "indexentries": {"default fileset": [[4, "term-Default-fileset"]], "design": [[4, "term-Design"]], "file": [[4, "term-File"]], "fileset": [[4, "term-FileSet"]], "lrm": [[4, "term-LRM"]], "project": [[4, "term-Project"]], "vhdllibrary": [[4, "term-VHDLLibrary"]], "base-class": [[4, "term-base-class"]], "addfile() (pyedaa.projectmodel.fileset method)": [[18, "pyEDAA.ProjectModel.FileSet.AddFile"]], "addfileset() (pyedaa.projectmodel.fileset method)": [[18, "pyEDAA.ProjectModel.FileSet.AddFileSet"]], "addfilesets() (pyedaa.projectmodel.fileset method)": [[18, "pyEDAA.ProjectModel.FileSet.AddFileSets"]], "addfiles() (pyedaa.projectmodel.fileset method)": [[18, "pyEDAA.ProjectModel.FileSet.AddFiles"]], "attribute (class in pyedaa.projectmodel)": [[18, "pyEDAA.ProjectModel.Attribute"]], "defaultfileset (pyedaa.projectmodel.design property)": [[18, "pyEDAA.ProjectModel.Design.DefaultFileSet"]], "design (class in pyedaa.projectmodel)": [[18, "pyEDAA.ProjectModel.Design"]], "design (pyedaa.projectmodel.fileset property)": [[18, "pyEDAA.ProjectModel.FileSet.Design"]], "design (pyedaa.projectmodel.vhdllibrary property)": [[18, "pyEDAA.ProjectModel.VHDLLibrary.Design"]], "designcount (pyedaa.projectmodel.project property)": [[18, "pyEDAA.ProjectModel.Project.DesignCount"]], "directory (pyedaa.projectmodel.design property)": [[18, "pyEDAA.ProjectModel.Design.Directory"]], "directory (pyedaa.projectmodel.fileset property)": [[18, "pyEDAA.ProjectModel.FileSet.Directory"]], "filecount (pyedaa.projectmodel.fileset property)": [[18, "pyEDAA.ProjectModel.FileSet.FileCount"]], "filecount (pyedaa.projectmodel.vhdllibrary property)": [[18, "pyEDAA.ProjectModel.VHDLLibrary.FileCount"]], "fileset (class in pyedaa.projectmodel)": [[18, "pyEDAA.ProjectModel.FileSet"]], "filesetcount (pyedaa.projectmodel.design property)": [[18, "pyEDAA.ProjectModel.Design.FileSetCount"]], "filesetcount (pyedaa.projectmodel.fileset property)": [[18, "pyEDAA.ProjectModel.FileSet.FileSetCount"]], "filesets (pyedaa.projectmodel.design property)": [[18, "pyEDAA.ProjectModel.Design.FileSets"]], "filesets (pyedaa.projectmodel.fileset property)": [[18, "pyEDAA.ProjectModel.FileSet.FileSets"]], "filetype (class in pyedaa.projectmodel)": [[18, "pyEDAA.ProjectModel.FileType"]], "filetypes (pyedaa.projectmodel.filetype attribute)": [[18, "pyEDAA.ProjectModel.FileType.FileTypes"]], "files (pyedaa.projectmodel.vhdllibrary property)": [[18, "pyEDAA.ProjectModel.VHDLLibrary.Files"]], "files() (pyedaa.projectmodel.design method)": [[18, "pyEDAA.ProjectModel.Design.Files"]], "files() (pyedaa.projectmodel.fileset method)": [[18, "pyEDAA.ProjectModel.FileSet.Files"]], "humanreadablecontent (class in pyedaa.projectmodel)": [[18, "pyEDAA.ProjectModel.HumanReadableContent"]], "inicontent (class in pyedaa.projectmodel)": [[18, "pyEDAA.ProjectModel.INIContent"]], "jsoncontent (class in pyedaa.projectmodel)": [[18, "pyEDAA.ProjectModel.JSONContent"]], "name (pyedaa.projectmodel.design property)": [[18, "pyEDAA.ProjectModel.Design.Name"]], "name (pyedaa.projectmodel.fileset property)": [[18, "pyEDAA.ProjectModel.FileSet.Name"]], "name (pyedaa.projectmodel.project property)": [[18, "pyEDAA.ProjectModel.Project.Name"]], "parent (pyedaa.projectmodel.fileset property)": [[18, "pyEDAA.ProjectModel.FileSet.Parent"]], "project (class in pyedaa.projectmodel)": [[18, "pyEDAA.ProjectModel.Project"]], "project (pyedaa.projectmodel.design property)": [[18, "pyEDAA.ProjectModel.Design.Project"]], "project (pyedaa.projectmodel.fileset property)": [[18, "pyEDAA.ProjectModel.FileSet.Project"]], "project (pyedaa.projectmodel.vhdllibrary property)": [[18, "pyEDAA.ProjectModel.VHDLLibrary.Project"]], "pythoncontent (class in pyedaa.projectmodel)": [[18, "pyEDAA.ProjectModel.PythonContent"]], "resolvedpath (pyedaa.projectmodel.design property)": [[18, "pyEDAA.ProjectModel.Design.ResolvedPath"]], "resolvedpath (pyedaa.projectmodel.fileset property)": [[18, "pyEDAA.ProjectModel.FileSet.ResolvedPath"]], "resolvedpath (pyedaa.projectmodel.project property)": [[18, "pyEDAA.ProjectModel.Project.ResolvedPath"]], "rootdirectory (pyedaa.projectmodel.project property)": [[18, "pyEDAA.ProjectModel.Project.RootDirectory"]], "sdccontent (class in pyedaa.projectmodel)": [[18, "pyEDAA.ProjectModel.SDCContent"]], "svversion (pyedaa.projectmodel.fileset property)": [[18, "pyEDAA.ProjectModel.FileSet.SVVersion"]], "tclcontent (class in pyedaa.projectmodel)": [[18, "pyEDAA.ProjectModel.TCLContent"]], "tomlcontent (class in pyedaa.projectmodel)": [[18, "pyEDAA.ProjectModel.TOMLContent"]], "toplevel (pyedaa.projectmodel.design property)": [[18, "pyEDAA.ProjectModel.Design.TopLevel"]], "toplevel (pyedaa.projectmodel.fileset property)": [[18, "pyEDAA.ProjectModel.FileSet.TopLevel"]], "totalfilecount (pyedaa.projectmodel.fileset property)": [[18, "pyEDAA.ProjectModel.FileSet.TotalFileCount"]], "totalfilesetcount (pyedaa.projectmodel.design property)": [[18, "pyEDAA.ProjectModel.Design.TotalFileSetCount"]], "totalfilesetcount (pyedaa.projectmodel.fileset property)": [[18, "pyEDAA.ProjectModel.FileSet.TotalFileSetCount"]], "vhdllibrary (class in pyedaa.projectmodel)": [[18, "pyEDAA.ProjectModel.VHDLLibrary"]], "vhdllibrary (pyedaa.projectmodel.fileset property)": [[18, "pyEDAA.ProjectModel.FileSet.VHDLLibrary"]], "vhdlversion (pyedaa.projectmodel.fileset property)": [[18, "pyEDAA.ProjectModel.FileSet.VHDLVersion"]], "vhdlversion (pyedaa.projectmodel.vhdllibrary property)": [[18, "pyEDAA.ProjectModel.VHDLLibrary.VHDLVersion"]], "validate() (pyedaa.projectmodel.design method)": [[18, "pyEDAA.ProjectModel.Design.Validate"]], "validate() (pyedaa.projectmodel.fileset method)": [[18, "pyEDAA.ProjectModel.FileSet.Validate"]], "validate() (pyedaa.projectmodel.project method)": [[18, "pyEDAA.ProjectModel.Project.Validate"]], "verilogversion (pyedaa.projectmodel.fileset property)": [[18, "pyEDAA.ProjectModel.FileSet.VerilogVersion"]], "xmlcontent (class in pyedaa.projectmodel)": [[18, "pyEDAA.ProjectModel.XMLContent"]], "yamlcontent (class in pyedaa.projectmodel)": [[18, "pyEDAA.ProjectModel.YAMLContent"]], "__base__ (pyedaa.projectmodel.filetype attribute)": [[18, "pyEDAA.ProjectModel.FileType.__base__"]], "__call__() (pyedaa.projectmodel.filetype method)": [[18, "pyEDAA.ProjectModel.FileType.__call__"]], "__delattr__() (pyedaa.projectmodel.filetype method)": [[18, "pyEDAA.ProjectModel.FileType.__delattr__"]], "__delitem__() (pyedaa.projectmodel.design method)": [[18, "pyEDAA.ProjectModel.Design.__delitem__"]], "__delitem__() (pyedaa.projectmodel.fileset method)": [[18, "pyEDAA.ProjectModel.FileSet.__delitem__"]], "__delitem__() (pyedaa.projectmodel.project method)": [[18, "pyEDAA.ProjectModel.Project.__delitem__"]], "__delitem__() (pyedaa.projectmodel.vhdllibrary method)": [[18, "pyEDAA.ProjectModel.VHDLLibrary.__delitem__"]], "__dir__() (pyedaa.projectmodel.filetype method)": [[18, "pyEDAA.ProjectModel.FileType.__dir__"]], "__getattribute__() (pyedaa.projectmodel.filetype method)": [[18, "pyEDAA.ProjectModel.FileType.__getattribute__"]], "__getitem__() (pyedaa.projectmodel.design method)": [[18, "pyEDAA.ProjectModel.Design.__getitem__"]], "__getitem__() (pyedaa.projectmodel.fileset method)": [[18, "pyEDAA.ProjectModel.FileSet.__getitem__"]], "__getitem__() (pyedaa.projectmodel.project method)": [[18, "pyEDAA.ProjectModel.Project.__getitem__"]], "__getitem__() (pyedaa.projectmodel.vhdllibrary method)": [[18, "pyEDAA.ProjectModel.VHDLLibrary.__getitem__"]], "__init__() (pyedaa.projectmodel.design method)": [[18, "pyEDAA.ProjectModel.Design.__init__"]], "__init__() (pyedaa.projectmodel.fileset method)": [[18, "pyEDAA.ProjectModel.FileSet.__init__"]], "__init__() (pyedaa.projectmodel.filetype method)": [[18, "pyEDAA.ProjectModel.FileType.__init__"]], "__init__() (pyedaa.projectmodel.project method)": [[18, "pyEDAA.ProjectModel.Project.__init__"]], "__init__() (pyedaa.projectmodel.vhdllibrary method)": [[18, "pyEDAA.ProjectModel.VHDLLibrary.__init__"]], "__instancecheck__() (pyedaa.projectmodel.filetype method)": [[18, "pyEDAA.ProjectModel.FileType.__instancecheck__"]], "__len__() (pyedaa.projectmodel.design method)": [[18, "pyEDAA.ProjectModel.Design.__len__"]], "__len__() (pyedaa.projectmodel.fileset method)": [[18, "pyEDAA.ProjectModel.FileSet.__len__"]], "__len__() (pyedaa.projectmodel.project method)": [[18, "pyEDAA.ProjectModel.Project.__len__"]], "__len__() (pyedaa.projectmodel.vhdllibrary method)": [[18, "pyEDAA.ProjectModel.VHDLLibrary.__len__"]], "__new__() (pyedaa.projectmodel.filetype static method)": [[18, "pyEDAA.ProjectModel.FileType.__new__"]], "__or__() (pyedaa.projectmodel.filetype method)": [[18, "pyEDAA.ProjectModel.FileType.__or__"]], "__prepare__() (pyedaa.projectmodel.filetype class method)": [[18, "pyEDAA.ProjectModel.FileType.__prepare__"]], "__repr__() (pyedaa.projectmodel.filetype method)": [[18, "pyEDAA.ProjectModel.FileType.__repr__"]], "__ror__() (pyedaa.projectmodel.filetype method)": [[18, "pyEDAA.ProjectModel.FileType.__ror__"]], "__setattr__() (pyedaa.projectmodel.filetype method)": [[18, "pyEDAA.ProjectModel.FileType.__setattr__"]], "__setitem__() (pyedaa.projectmodel.design method)": [[18, "pyEDAA.ProjectModel.Design.__setitem__"]], "__setitem__() (pyedaa.projectmodel.fileset method)": [[18, "pyEDAA.ProjectModel.FileSet.__setitem__"]], "__setitem__() (pyedaa.projectmodel.project method)": [[18, "pyEDAA.ProjectModel.Project.__setitem__"]], "__setitem__() (pyedaa.projectmodel.vhdllibrary method)": [[18, "pyEDAA.ProjectModel.VHDLLibrary.__setitem__"]], "__sizeof__() (pyedaa.projectmodel.filetype method)": [[18, "pyEDAA.ProjectModel.FileType.__sizeof__"]], "__str__() (pyedaa.projectmodel.design method)": [[18, "pyEDAA.ProjectModel.Design.__str__"]], "__str__() (pyedaa.projectmodel.fileset method)": [[18, "pyEDAA.ProjectModel.FileSet.__str__"]], "__str__() (pyedaa.projectmodel.project method)": [[18, "pyEDAA.ProjectModel.Project.__str__"]], "__str__() (pyedaa.projectmodel.vhdllibrary method)": [[18, "pyEDAA.ProjectModel.VHDLLibrary.__str__"]], "__subclasscheck__() (pyedaa.projectmodel.filetype method)": [[18, "pyEDAA.ProjectModel.FileType.__subclasscheck__"]], "__subclasses__() (pyedaa.projectmodel.filetype method)": [[18, "pyEDAA.ProjectModel.FileType.__subclasses__"]], "__text_signature__ (pyedaa.projectmodel.filetype attribute)": [[18, "pyEDAA.ProjectModel.FileType.__text_signature__"]], "_checkforabstractmethods() (pyedaa.projectmodel.filetype class method)": [[18, "pyEDAA.ProjectModel.FileType._checkForAbstractMethods"]], "_iteratebaseclasspaths() (pyedaa.projectmodel.filetype class method)": [[18, "pyEDAA.ProjectModel.FileType._iterateBaseClassPaths"]], "_wrapnewmethodifabstract() (pyedaa.projectmodel.filetype class method)": [[18, "pyEDAA.ProjectModel.FileType._wrapNewMethodIfAbstract"]], "_wrapnewmethodifsingleton() (pyedaa.projectmodel.filetype class method)": [[18, "pyEDAA.ProjectModel.FileType._wrapNewMethodIfSingleton"]], "module": [[18, "module-pyEDAA.ProjectModel"], [19, "module-pyEDAA.ProjectModel.Altera"], [20, "module-pyEDAA.ProjectModel.Altera.Quartus"], [21, "module-pyEDAA.ProjectModel.Attributes"], [22, "module-pyEDAA.ProjectModel.GHDL"], [23, "module-pyEDAA.ProjectModel.Intel"], [24, "module-pyEDAA.ProjectModel.Intel.QuartusPrime"], [25, "module-pyEDAA.ProjectModel.MentorGraphics"], [26, "module-pyEDAA.ProjectModel.MentorGraphics.ModelSim"], [27, "module-pyEDAA.ProjectModel.MentorGraphics.QuestaSim"], [28, "module-pyEDAA.ProjectModel.OSVVM"], [29, "module-pyEDAA.ProjectModel.VHDL"], [30, "module-pyEDAA.ProjectModel.Verilog"], [31, "module-pyEDAA.ProjectModel.Xilinx"], [32, "module-pyEDAA.ProjectModel.Xilinx.ISE"], [33, "module-pyEDAA.ProjectModel.Xilinx.Vivado"]], "mro() (pyedaa.projectmodel.filetype method)": [[18, "pyEDAA.ProjectModel.FileType.mro"]], "pyedaa.projectmodel": [[18, "module-pyEDAA.ProjectModel"]], "pyedaa.projectmodel.altera": [[19, "module-pyEDAA.ProjectModel.Altera"]], "pyedaa.projectmodel.altera.quartus": [[20, "module-pyEDAA.ProjectModel.Altera.Quartus"]], "keyvalueattribute (class in pyedaa.projectmodel.attributes)": [[21, "pyEDAA.ProjectModel.Attributes.KeyValueAttribute"]], "__init__() (pyedaa.projectmodel.attributes.keyvalueattribute method)": [[21, "pyEDAA.ProjectModel.Attributes.KeyValueAttribute.__init__"]], "pyedaa.projectmodel.attributes": [[21, "module-pyEDAA.ProjectModel.Attributes"]], "pyedaa.projectmodel.ghdl": [[22, "module-pyEDAA.ProjectModel.GHDL"]], "pyedaa.projectmodel.intel": [[23, "module-pyEDAA.ProjectModel.Intel"]], "pyedaa.projectmodel.intel.quartusprime": [[24, "module-pyEDAA.ProjectModel.Intel.QuartusPrime"]], "pyedaa.projectmodel.mentorgraphics": [[25, "module-pyEDAA.ProjectModel.MentorGraphics"]], "pyedaa.projectmodel.mentorgraphics.modelsim": [[26, "module-pyEDAA.ProjectModel.MentorGraphics.ModelSim"]], "pyedaa.projectmodel.mentorgraphics.questasim": [[27, "module-pyEDAA.ProjectModel.MentorGraphics.QuestaSim"]], "pyedaa.projectmodel.osvvm": [[28, "module-pyEDAA.ProjectModel.OSVVM"]], "pyedaa.projectmodel.vhdl": [[29, "module-pyEDAA.ProjectModel.VHDL"]], "pyedaa.projectmodel.verilog": [[30, "module-pyEDAA.ProjectModel.Verilog"]], "pyedaa.projectmodel.xilinx": [[31, "module-pyEDAA.ProjectModel.Xilinx"]], "pyedaa.projectmodel.xilinx.ise": [[32, "module-pyEDAA.ProjectModel.Xilinx.ISE"]], "usedinattribute (class in pyedaa.projectmodel.xilinx.vivado)": [[33, "pyEDAA.ProjectModel.Xilinx.Vivado.UsedInAttribute"]], "pyedaa.projectmodel.xilinx.vivado": [[33, "module-pyEDAA.ProjectModel.Xilinx.Vivado"]]}})
\ No newline at end of file
diff --git a/typing/html/ProjectModel/Altera/Quartus.py.html b/typing/html/ProjectModel/Altera/Quartus.py.html
new file mode 100644
index 00000000..f1b492ae
--- /dev/null
+++ b/typing/html/ProjectModel/Altera/Quartus.py.html
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 + |
+# ==================================================================================================================== # +# _____ ____ _ _ ____ _ _ __ __ _ _ # +# _ __ _ _| ____| _ \ / \ / \ | _ \ _ __ ___ (_) ___ ___| |_| \/ | ___ __| | ___| | # +# | '_ \| | | | _| | | | |/ _ \ / _ \ | |_) | '__/ _ \| |/ _ \/ __| __| |\/| |/ _ \ / _` |/ _ \ | # +# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| __/| | | (_) | | __/ (__| |_| | | | (_) | (_| | __/ | # +# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_| |_| \___// |\___|\___|\__|_| |_|\___/ \__,_|\___|_| # +# |_| |___/ |__/ # +# ==================================================================================================================== # +# Authors: # +# Patrick Lehmann # +# # +# License: # +# ==================================================================================================================== # +# Copyright 2017-2023 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 # +# ==================================================================================================================== # +# +"""Specific file types and attributes for Altera Quartus.""" +from pyTooling.Decorators import export + +from pyEDAA.ProjectModel import ConstraintFile, ProjectFile, SDCContent, TCLContent + + +@export +class QuartusProjectFile(ProjectFile, TCLContent): + """A Quartus project file (``*.qpf``).""" + + +@export +class SDCConstraintFile(ConstraintFile, SDCContent): + """A Quartus constraint file (Synopsys Design Constraints; ``*.sdc``).""" + |
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 + |
+# ==================================================================================================================== # +# _____ ____ _ _ ____ _ _ __ __ _ _ # +# _ __ _ _| ____| _ \ / \ / \ | _ \ _ __ ___ (_) ___ ___| |_| \/ | ___ __| | ___| | # +# | '_ \| | | | _| | | | |/ _ \ / _ \ | |_) | '__/ _ \| |/ _ \/ __| __| |\/| |/ _ \ / _` |/ _ \ | # +# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| __/| | | (_) | | __/ (__| |_| | | | (_) | (_| | __/ | # +# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_| |_| \___// |\___|\___|\__|_| |_|\___/ \__,_|\___|_| # +# |_| |___/ |__/ # +# ==================================================================================================================== # +# Authors: # +# Patrick Lehmann # +# # +# License: # +# ==================================================================================================================== # +# Copyright 2017-2023 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 # +# ==================================================================================================================== # +# +"""A vendor specific package for Altera (now Intel FPGA).""" + |
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 + |
+# ==================================================================================================================== # +# _____ ____ _ _ ____ _ _ __ __ _ _ # +# _ __ _ _| ____| _ \ / \ / \ | _ \ _ __ ___ (_) ___ ___| |_| \/ | ___ __| | ___| | # +# | '_ \| | | | _| | | | |/ _ \ / _ \ | |_) | '__/ _ \| |/ _ \/ __| __| |\/| |/ _ \ / _` |/ _ \ | # +# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| __/| | | (_) | | __/ (__| |_| | | | (_) | (_| | __/ | # +# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_| |_| \___// |\___|\___|\__|_| |_|\___/ \__,_|\___|_| # +# |_| |___/ |__/ # +# ==================================================================================================================== # +# Authors: # +# Patrick Lehmann # +# # +# License: # +# ==================================================================================================================== # +# Copyright 2017-2023 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 # +# ==================================================================================================================== # +# +"""A set of common attributes to store meta information on ProjectModel entities (project, design, fileset, file, ...).""" +from typing import Dict +from pyTooling.Decorators import export + +from pyEDAA.ProjectModel import Attribute + + +@export +class KeyValueAttribute(Attribute): + KEY = "ID" + + _keyValuePairs: Dict[str, str] + + def __init__(self): + super().__init__() + + self._keyValuePairs = {} + + def __getitem__(self, item: str) -> str: + return self._keyValuePairs[item] + + def __setitem__(self, key: str, value: str) -> None: + self._keyValuePairs[key] = value + |
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 + |
+# ==================================================================================================================== # +# _____ ____ _ _ ____ _ _ __ __ _ _ # +# _ __ _ _| ____| _ \ / \ / \ | _ \ _ __ ___ (_) ___ ___| |_| \/ | ___ __| | ___| | # +# | '_ \| | | | _| | | | |/ _ \ / _ \ | |_) | '__/ _ \| |/ _ \/ __| __| |\/| |/ _ \ / _` |/ _ \ | # +# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| __/| | | (_) | | __/ (__| |_| | | | (_) | (_| | __/ | # +# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_| |_| \___// |\___|\___|\__|_| |_|\___/ \__,_|\___|_| # +# |_| |___/ |__/ # +# ==================================================================================================================== # +# Authors: # +# Patrick Lehmann # +# # +# License: # +# ==================================================================================================================== # +# Copyright 2017-2023 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 # +# ==================================================================================================================== # +# +"""Specific file types and attributes for `GHDL <https://github.com/ghdl>`__.""" +from pyTooling.Decorators import export + +from pyEDAA.ProjectModel import WaveformExchangeFile + + +@export +class GHDLWaveformFile(WaveformExchangeFile): + """GHDL's waveform file (``*.ghw``) supporting VHDL and Verilog simulation results.""" + |
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 + |
+# ==================================================================================================================== # +# _____ ____ _ _ ____ _ _ __ __ _ _ # +# _ __ _ _| ____| _ \ / \ / \ | _ \ _ __ ___ (_) ___ ___| |_| \/ | ___ __| | ___| | # +# | '_ \| | | | _| | | | |/ _ \ / _ \ | |_) | '__/ _ \| |/ _ \/ __| __| |\/| |/ _ \ / _` |/ _ \ | # +# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| __/| | | (_) | | __/ (__| |_| | | | (_) | (_| | __/ | # +# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_| |_| \___// |\___|\___|\__|_| |_|\___/ \__,_|\___|_| # +# |_| |___/ |__/ # +# ==================================================================================================================== # +# Authors: # +# Patrick Lehmann # +# # +# License: # +# ==================================================================================================================== # +# Copyright 2017-2023 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 # +# ==================================================================================================================== # +# +"""Specific file types and attributes for Intel FPGA Quartus Prime.""" +from pyTooling.Decorators import export + +from pyEDAA.ProjectModel import ConstraintFile, ProjectFile, SDCContent, TCLContent + + +@export +class QuartusProjectFile(ProjectFile, TCLContent): + """A Quartus project file (``*.qpf``).""" + + +@export +class SDCConstraintFile(ConstraintFile, SDCContent): + """A Quartus constraint file (Synopsys Design Constraints; ``*.sdc``).""" + |
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 + |
+# ==================================================================================================================== # +# _____ ____ _ _ ____ _ _ __ __ _ _ # +# _ __ _ _| ____| _ \ / \ / \ | _ \ _ __ ___ (_) ___ ___| |_| \/ | ___ __| | ___| | # +# | '_ \| | | | _| | | | |/ _ \ / _ \ | |_) | '__/ _ \| |/ _ \/ __| __| |\/| |/ _ \ / _` |/ _ \ | # +# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| __/| | | (_) | | __/ (__| |_| | | | (_) | (_| | __/ | # +# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_| |_| \___// |\___|\___|\__|_| |_|\___/ \__,_|\___|_| # +# |_| |___/ |__/ # +# ==================================================================================================================== # +# Authors: # +# Patrick Lehmann # +# # +# License: # +# ==================================================================================================================== # +# Copyright 2017-2023 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 # +# ==================================================================================================================== # +# +"""A vendor specific package for Intel FPGA (formerly Altera).""" + |
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 + |
+# ==================================================================================================================== # +# _____ ____ _ _ ____ _ _ __ __ _ _ # +# _ __ _ _| ____| _ \ / \ / \ | _ \ _ __ ___ (_) ___ ___| |_| \/ | ___ __| | ___| | # +# | '_ \| | | | _| | | | |/ _ \ / _ \ | |_) | '__/ _ \| |/ _ \/ __| __| |\/| |/ _ \ / _` |/ _ \ | # +# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| __/| | | (_) | | __/ (__| |_| | | | (_) | (_| | __/ | # +# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_| |_| \___// |\___|\___|\__|_| |_|\___/ \__,_|\___|_| # +# |_| |___/ |__/ # +# ==================================================================================================================== # +# Authors: # +# Patrick Lehmann # +# # +# License: # +# ==================================================================================================================== # +# Copyright 2017-2023 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 # +# ==================================================================================================================== # +# +"""Specific file types and attributes for Mentor Graphics ModelSim.""" +from pyTooling.Decorators import export + +from pyEDAA.ProjectModel import ProjectFile, SettingFile, INIContent, WaveformConfigFile, TCLContent + + +@export +class ModelSimProjectFile(ProjectFile): + pass + + +@export +class ModelSimINIFile(SettingFile, INIContent): + pass + + +@export +class WaveDoFile(WaveformConfigFile, TCLContent): + pass + |
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 + |
+# ==================================================================================================================== # +# _____ ____ _ _ ____ _ _ __ __ _ _ # +# _ __ _ _| ____| _ \ / \ / \ | _ \ _ __ ___ (_) ___ ___| |_| \/ | ___ __| | ___| | # +# | '_ \| | | | _| | | | |/ _ \ / _ \ | |_) | '__/ _ \| |/ _ \/ __| __| |\/| |/ _ \ / _` |/ _ \ | # +# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| __/| | | (_) | | __/ (__| |_| | | | (_) | (_| | __/ | # +# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_| |_| \___// |\___|\___|\__|_| |_|\___/ \__,_|\___|_| # +# |_| |___/ |__/ # +# ==================================================================================================================== # +# Authors: # +# Patrick Lehmann # +# # +# License: # +# ==================================================================================================================== # +# Copyright 2017-2023 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 # +# ==================================================================================================================== # +# +"""Specific file types and attributes for Mentor Graphics QuestaSim.""" +from pyTooling.Decorators import export + +from pyEDAA.ProjectModel import ProjectFile, SettingFile, INIContent, WaveformConfigFile, TCLContent + + +@export +class ModelSimProjectFile(ProjectFile): + pass + + +@export +class ModelSimINIFile(SettingFile, INIContent): + pass + + +@export +class WaveDoFile(WaveformConfigFile, TCLContent): + pass + |
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 + |
+# ==================================================================================================================== # +# _____ ____ _ _ ____ _ _ __ __ _ _ # +# _ __ _ _| ____| _ \ / \ / \ | _ \ _ __ ___ (_) ___ ___| |_| \/ | ___ __| | ___| | # +# | '_ \| | | | _| | | | |/ _ \ / _ \ | |_) | '__/ _ \| |/ _ \/ __| __| |\/| |/ _ \ / _` |/ _ \ | # +# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| __/| | | (_) | | __/ (__| |_| | | | (_) | (_| | __/ | # +# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_| |_| \___// |\___|\___|\__|_| |_|\___/ \__,_|\___|_| # +# |_| |___/ |__/ # +# ==================================================================================================================== # +# Authors: # +# Patrick Lehmann # +# # +# License: # +# ==================================================================================================================== # +# Copyright 2017-2023 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 # +# ==================================================================================================================== # +# +"""A vendor specific package for Mentor Graphics (now Siemens EDA).""" + |
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 + |
+# ==================================================================================================================== # +# _____ ____ _ _ ____ _ _ __ __ _ _ # +# _ __ _ _| ____| _ \ / \ / \ | _ \ _ __ ___ (_) ___ ___| |_| \/ | ___ __| | ___| | # +# | '_ \| | | | _| | | | |/ _ \ / _ \ | |_) | '__/ _ \| |/ _ \/ __| __| |\/| |/ _ \ / _` |/ _ \ | # +# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| __/| | | (_) | | __/ (__| |_| | | | (_) | (_| | __/ | # +# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_| |_| \___// |\___|\___|\__|_| |_|\___/ \__,_|\___|_| # +# |_| |___/ |__/ # +# ==================================================================================================================== # +# Authors: # +# Patrick Lehmann # +# # +# License: # +# ==================================================================================================================== # +# Copyright 2017-2023 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 # +# ==================================================================================================================== # +# +"""Specific file types and attributes for `OSVVM <https://github.com/OSVVM>`__.""" +from pathlib import Path + +from pyTooling.Decorators import export +from typing import Optional as Nullable, List + +from pyEDAA.ProjectModel import ProjectFile, TCLContent, Project, Design, FileSet, VHDLLibrary, VHDLSourceFile + + +@export +class OSVVMProjectFile(ProjectFile, TCLContent): + """An OSVVM project file (``*.pro``).""" + + _osvvmProject: Nullable[Project] + + def __init__( + self, + path: Path, + project: Project = None, + design: Design = None, + fileSet: FileSet = None + ): + super().__init__(path, project, design, fileSet) + + self._osvvmProject = None + + @property + def ProjectModel(self) -> Project: + return self._osvvmProject + + class Instruction: + _line: int + + def __init__(self, line: int): + self._line = line + + class Empty(Instruction): + def __init__(self, line: int): + super().__init__(line) + + class Comment(Instruction): + _commentText: str + + def __init__(self, line: int, commentText: str): + super().__init__(line) + self._commentText = commentText.rstrip() + + @property + def CommentText(self) -> str: + return self._commentText + + class Analyze(Instruction): + _vhdlSourceFile: VHDLSourceFile + + def __init__(self, line: int, parameterText: str): + super().__init__(line) + self._vhdlSourceFile = VHDLSourceFile(Path(parameterText.strip())) + + @property + def VHDLSourceFile(self) -> VHDLSourceFile: + return self._vhdlSourceFile + + class Library(Instruction): + _vhdlLibrary: VHDLLibrary + + def __init__(self, line: int, parameterText: str): + super().__init__(line) + self._vhdlLibrary = VHDLLibrary(parameterText.strip()) + + @property + def VHDLLibrary(self) -> VHDLLibrary: + return self._vhdlLibrary + + class Include(Instruction): + _osvvmProjectFile: 'OSVVMProjectFile' + _fileSet: FileSet + + def __init__(self, line: int, workingDirectory: Path, parameterText: str): + super().__init__(line) + + includeFile = Path(parameterText.strip()) + includePath = (workingDirectory / includeFile).resolve() + + self._fileSet = FileSet(includeFile.name, directory=includeFile.parent) + self._osvvmProjectFile = OSVVMProjectFile(includePath) + + @property + def OSVVMProjectFile(self) -> 'OSVVMProjectFile': + return self._osvvmProjectFile + + def Parse(self, fileSet: FileSet): + self._fileSet.Parent = fileSet + + for instruction in self._osvvmProjectFile._Parse(): + if isinstance(instruction, OSVVMProjectFile.Include): + instruction.Parse(self._fileSet) + elif isinstance(instruction, OSVVMProjectFile.Analyze): + self._fileSet.AddFile(instruction.VHDLSourceFile) + elif isinstance(instruction, OSVVMProjectFile.Library): + self._fileSet.Design.AddVHDLLibrary(instruction.VHDLLibrary) +# elif isinstance(instruction, OSVVMProjectFile.Build): + + elif not isinstance(instruction, (OSVVMProjectFile.Empty, OSVVMProjectFile.Comment)): + raise Exception(f"Unknown instruction '{instruction.__class__.__name__}' in OSVVM project file '{self._osvvmProjectFile.ResolvedPath}'") + + def Parse(self): + projectName = self._path.name + self._osvvmProject = Project(projectName, rootDirectory=self._path.parent) + + fileSet = self._osvvmProject.DefaultDesign.DefaultFileSet + + for instruction in self._Parse(): + if isinstance(instruction, OSVVMProjectFile.Include): + instruction.Parse(fileSet) + elif isinstance(instruction, OSVVMProjectFile.Analyze): + fileSet.AddFile(instruction.VHDLSourceFile) + elif not isinstance(instruction, (OSVVMProjectFile.Empty, OSVVMProjectFile.Comment)): + raise Exception(f"Unknown instruction '{instruction.__class__.__name__}' in OSVVM project file '{self.ResolvedPath}'") + + def _Parse(self): + path = self.ResolvedPath + if not path.exists(): + raise Exception(f"OSVVM project file '{path}' not found.") from FileNotFoundError(f"File '{path}' not found.") + + instructions: List = [] + print() + with path.open("r") as file: + i = 1 + for line in file: + line = line.lstrip() + + if line.startswith("#"): + comment = OSVVMProjectFile.Comment(i, line[1:]) + instructions.append(comment) + + elif line.startswith("analyze"): + vhdlFile = OSVVMProjectFile.Analyze(i, line[8:]) + instructions.append(vhdlFile) + + elif line.startswith("library"): + vhdlLibrary = OSVVMProjectFile.Library(i, line[8:]) + instructions.append(vhdlLibrary) + + elif line.startswith("include"): + include = OSVVMProjectFile.Include(i, path.parent, line[8:]) + instructions.append(include) + + elif line.startswith("build"): + parameter = line[6:] + print(f"BUILD: {parameter}") + elif line.startswith("if"): + print(f"IF (line={i}): {line[3:].rstrip()}") + elif line.startswith("}"): + print(f"}} (line={i}): {line[2:].rstrip()}") + elif len(line) == 0: + instructions.append(OSVVMProjectFile.Empty(i)) + else: + print(f"UNKNOWN (line={i}): '{line.rstrip()}'") + + i += 1 + + return instructions + |
+
+ | + |
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 + |
+# ==================================================================================================================== # +# _____ ____ _ _ ____ _ _ __ __ _ _ # +# _ __ _ _| ____| _ \ / \ / \ | _ \ _ __ ___ (_) ___ ___| |_| \/ | ___ __| | ___| | # +# | '_ \| | | | _| | | | |/ _ \ / _ \ | |_) | '__/ _ \| |/ _ \/ __| __| |\/| |/ _ \ / _` |/ _ \ | # +# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| __/| | | (_) | | __/ (__| |_| | | | (_) | (_| | __/ | # +# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_| |_| \___// |\___|\___|\__|_| |_|\___/ \__,_|\___|_| # +# |_| |___/ |__/ # +# ==================================================================================================================== # +# Authors: # +# Patrick Lehmann # +# # +# License: # +# ==================================================================================================================== # +# Copyright 2017-2023 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 # +# ==================================================================================================================== # +# +"""Specific file types and attributes for Verilog.""" +from pyTooling.Decorators import export + +from pyEDAA.ProjectModel import WaveformExchangeFile + + +@export +class ValueChangeDumpFile(WaveformExchangeFile): + """Verilog's waveform file (``*.vcd``) for exchanging value changes as defined by IEEE Std. 1364.""" + |
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 + |
+# ==================================================================================================================== # +# _____ ____ _ _ ____ _ _ __ __ _ _ # +# _ __ _ _| ____| _ \ / \ / \ | _ \ _ __ ___ (_) ___ ___| |_| \/ | ___ __| | ___| | # +# | '_ \| | | | _| | | | |/ _ \ / _ \ | |_) | '__/ _ \| |/ _ \/ __| __| |\/| |/ _ \ / _` |/ _ \ | # +# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| __/| | | (_) | | __/ (__| |_| | | | (_) | (_| | __/ | # +# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_| |_| \___// |\___|\___|\__|_| |_|\___/ \__,_|\___|_| # +# |_| |___/ |__/ # +# ==================================================================================================================== # +# Authors: # +# Patrick Lehmann # +# # +# License: # +# ==================================================================================================================== # +# Copyright 2017-2023 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 # +# ==================================================================================================================== # +# +"""Specific file types and attributes for Xilinx ISE.""" +from pyTooling.Decorators import export + +from pyEDAA.ProjectModel import ConstraintFile, ProjectFile, HumanReadableContent + + +@export +class ISEProjectFile(ProjectFile): + pass + + +@export +class UCFConstraintFile(ConstraintFile, HumanReadableContent): + pass + |
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 + |
+# ==================================================================================================================== # +# _____ ____ _ _ ____ _ _ __ __ _ _ # +# _ __ _ _| ____| _ \ / \ / \ | _ \ _ __ ___ (_) ___ ___| |_| \/ | ___ __| | ___| | # +# | '_ \| | | | _| | | | |/ _ \ / _ \ | |_) | '__/ _ \| |/ _ \/ __| __| |\/| |/ _ \ / _` |/ _ \ | # +# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| __/| | | (_) | | __/ (__| |_| | | | (_) | (_| | __/ | # +# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_| |_| \___// |\___|\___|\__|_| |_|\___/ \__,_|\___|_| # +# |_| |___/ |__/ # +# ==================================================================================================================== # +# Authors: # +# Patrick Lehmann # +# # +# License: # +# ==================================================================================================================== # +# Copyright 2017-2023 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 # +# ==================================================================================================================== # +# +"""Specific file types and attributes for Xilinx Vivado.""" +from pathlib import Path +from typing import Iterable + +from xml.dom import minidom, Node + +from pyTooling.MetaClasses import ExtendedType +from pyVHDLModel import VHDLVersion +from pyTooling.Decorators import export + +from pyEDAA.ProjectModel import ProjectFile, XMLFile, XMLContent, SDCContent, Project, FileSet, Attribute, Design +from pyEDAA.ProjectModel import File as Model_File +from pyEDAA.ProjectModel import ConstraintFile as Model_ConstraintFile +from pyEDAA.ProjectModel import VerilogSourceFile as Model_VerilogSourceFile +from pyEDAA.ProjectModel import VHDLSourceFile as Model_VHDLSourceFile + + +@export +class UsedInAttribute(Attribute): + KEY = "UsedIn" + VALUE_TYPE = Iterable[str] + + +@export +class File(Model_File): + pass + + +class VivadoFileMixIn(metaclass=ExtendedType, mixin=True): + def _registerAttributes(self): + self._attributes[UsedInAttribute] = [] + + +@export +class ConstraintFile(Model_ConstraintFile, VivadoFileMixIn): + def _registerAttributes(self): + super()._registerAttributes() + VivadoFileMixIn._registerAttributes(self) + + +@export +class VerilogSourceFile(Model_VerilogSourceFile): + def _registerAttributes(self): + super()._registerAttributes() + VivadoFileMixIn._registerAttributes(self) + + +@export +class VHDLSourceFile(Model_VHDLSourceFile): + def _registerAttributes(self): + super()._registerAttributes() + VivadoFileMixIn._registerAttributes(self) + + +@export +class VivadoProjectFile(ProjectFile, XMLContent): + """A Vivado project file (``*.xpr``).""" + + _xprProject: Project + + def __init__( + self, + path: Path, + project: Project = None, + design: Design = None, + fileSet: FileSet = None + ): + super().__init__(path, project, design, fileSet) + + self._xprProject = None + + @property + def ProjectModel(self) -> Project: + return self._xprProject + + def Parse(self): + if not self._path.exists(): + raise Exception(f"Vivado project file '{self._path!s}' not found.") from FileNotFoundError(f"File '{self._path!s}' not found.") + + try: + root = minidom.parse(str(self._path)).documentElement + except Exception as ex: + raise Exception(f"Couldn't open '{self._path!s}'.") from ex + + self._xprProject = Project(self._path.stem, rootDirectory=self._path.parent) + self._ParseRootElement(root) + + def _ParseRootElement(self, root): + for rootNode in root.childNodes: + if rootNode.nodeName == "FileSets": + self._ParseFileSets(rootNode) + break + + def _ParseFileSets(self, filesetsNode): + for fileSetsNode in filesetsNode.childNodes: + if fileSetsNode.nodeType == Node.ELEMENT_NODE and fileSetsNode.tagName == "FileSet": + self._ParseFileSet(fileSetsNode) + + def _ParseFileSet(self, filesetNode): + filesetName = filesetNode.getAttribute("Name") + fileset = FileSet(filesetName, design=self._xprProject.DefaultDesign) + + for fileNode in filesetNode.childNodes: + if fileNode.nodeType == Node.ELEMENT_NODE: + if fileNode.tagName == "File": + self._ParseFile(fileNode, fileset) + elif fileNode.nodeType == Node.ELEMENT_NODE and fileNode.tagName == "Config": + self._ParseFileSetConfig(fileNode, fileset) + + def _ParseFile(self, fileNode, fileset): + croppedPath = fileNode.getAttribute("Path").replace("$PPRDIR/", "") + filePath = Path(croppedPath) + 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) + fileset.AddFile(vhdlFile) + usedInAttr = vhdlFile[UsedInAttribute] + + for childNode in fileNode.childNodes: + if childNode.nodeType == Node.ELEMENT_NODE and childNode.tagName == "FileInfo": + if childNode.getAttribute("SFType") == "VHDL2008": + vhdlFile.VHDLVersion = VHDLVersion.VHDL2008 + else: + vhdlFile.VHDLVersion = VHDLVersion.VHDL93 + + for fileAttribute in childNode.childNodes: + if fileAttribute.nodeType == Node.ELEMENT_NODE and fileAttribute.tagName == "Attr": + if fileAttribute.getAttribute("Name") == "Library": + libraryName = fileAttribute.getAttribute("Val") + vhdlFile.VHDLLibrary = fileset.GetOrCreateVHDLLibrary(libraryName) + elif fileAttribute.getAttribute("Val") == "UsedIn": + usedInAttr.append(fileAttribute.getAttribute("Val")) + + def _ParseDefaultFile(self, _, path, fileset): + File(path, fileSet=fileset) + + def _ParseXDCFile(self, _, path, fileset): + XDCConstraintFile(path, fileSet=fileset) + + def _ParseVerilogFile(self, _, path, fileset): + VerilogSourceFile(path, fileSet=fileset) + + def _ParseXCIFile(self, _, path, fileset): + IPCoreInstantiationFile(path, fileSet=fileset) + + def _ParseFileSetConfig(self, fileNode, fileset): + for option in fileNode.childNodes: + if option.nodeType == Node.ELEMENT_NODE and option.tagName == "Option": + if option.getAttribute("Name") == "TopModule": + fileset.TopLevel = option.getAttribute("Val") + + +@export +class XDCConstraintFile(ConstraintFile, SDCContent): + """A Vivado constraint file (Xilinx Design Constraints; ``*.xdc``).""" + + +@export +class IPCoreDescriptionFile(XMLFile): + pass + + +@export +class IPCoreInstantiationFile(XMLFile): + """A Vivado IP core instantiation file (Xilinx IPCore Instance; ``*.xci``).""" + |
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 + |
+# ==================================================================================================================== # +# _____ ____ _ _ ____ _ _ __ __ _ _ # +# _ __ _ _| ____| _ \ / \ / \ | _ \ _ __ ___ (_) ___ ___| |_| \/ | ___ __| | ___| | # +# | '_ \| | | | _| | | | |/ _ \ / _ \ | |_) | '__/ _ \| |/ _ \/ __| __| |\/| |/ _ \ / _` |/ _ \ | # +# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| __/| | | (_) | | __/ (__| |_| | | | (_) | (_| | __/ | # +# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_| |_| \___// |\___|\___|\__|_| |_|\___/ \__,_|\___|_| # +# |_| |___/ |__/ # +# ==================================================================================================================== # +# Authors: # +# Patrick Lehmann # +# # +# License: # +# ==================================================================================================================== # +# Copyright 2017-2023 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 # +# ==================================================================================================================== # +# +"""A vendor specific package for Xilinx.""" + |
+
1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +55 +56 +57 +58 +59 +60 +61 +62 +63 +64 +65 +66 +67 +68 +69 +70 +71 +72 +73 +74 +75 +76 +77 +78 +79 +80 +81 +82 +83 +84 +85 +86 +87 +88 +89 +90 +91 +92 +93 +94 +95 +96 +97 +98 +99 +100 +101 +102 +103 +104 +105 +106 +107 +108 +109 +110 +111 +112 +113 +114 +115 +116 +117 +118 +119 +120 +121 +122 +123 +124 +125 +126 +127 +128 +129 +130 +131 +132 +133 +134 +135 +136 +137 +138 +139 +140 +141 +142 +143 +144 +145 +146 +147 +148 +149 +150 +151 +152 +153 +154 +155 +156 +157 +158 +159 +160 +161 +162 +163 +164 +165 +166 +167 +168 +169 +170 +171 +172 +173 +174 +175 +176 +177 +178 +179 +180 +181 +182 +183 +184 +185 +186 +187 +188 +189 +190 +191 +192 +193 +194 +195 +196 +197 +198 +199 +200 +201 +202 +203 +204 +205 +206 +207 +208 +209 +210 +211 +212 +213 +214 +215 +216 +217 +218 +219 +220 +221 +222 +223 +224 +225 +226 +227 +228 +229 +230 +231 +232 +233 +234 +235 +236 +237 +238 +239 +240 +241 +242 +243 +244 +245 +246 +247 +248 +249 +250 +251 +252 +253 +254 +255 +256 +257 +258 +259 +260 +261 +262 +263 +264 +265 +266 +267 +268 +269 +270 +271 +272 +273 +274 +275 +276 +277 +278 +279 +280 +281 +282 +283 +284 +285 +286 +287 +288 +289 +290 +291 +292 +293 +294 +295 +296 +297 +298 +299 +300 +301 +302 +303 +304 +305 +306 +307 +308 +309 +310 +311 +312 +313 +314 +315 +316 +317 +318 +319 +320 +321 +322 +323 +324 +325 +326 +327 +328 +329 +330 +331 +332 +333 +334 +335 +336 +337 +338 +339 +340 +341 +342 +343 +344 +345 +346 +347 +348 +349 +350 +351 +352 +353 +354 +355 +356 +357 +358 +359 +360 +361 +362 +363 +364 +365 +366 +367 +368 +369 +370 +371 +372 +373 +374 +375 +376 +377 +378 +379 +380 +381 +382 +383 +384 +385 +386 +387 +388 +389 +390 +391 +392 +393 +394 +395 +396 +397 +398 +399 +400 +401 +402 +403 +404 +405 +406 +407 +408 +409 +410 +411 +412 +413 +414 +415 +416 +417 +418 +419 +420 +421 +422 +423 +424 +425 +426 +427 +428 +429 +430 +431 +432 +433 +434 +435 +436 +437 +438 +439 +440 +441 +442 +443 +444 +445 +446 +447 +448 +449 +450 +451 +452 +453 +454 +455 +456 +457 +458 +459 +460 +461 +462 +463 +464 +465 +466 +467 +468 +469 +470 +471 +472 +473 +474 +475 +476 +477 +478 +479 +480 +481 +482 +483 +484 +485 +486 +487 +488 +489 +490 +491 +492 +493 +494 +495 +496 +497 +498 +499 +500 +501 +502 +503 +504 +505 +506 +507 +508 +509 +510 +511 +512 +513 +514 +515 +516 +517 +518 +519 +520 +521 +522 +523 +524 +525 +526 +527 +528 +529 +530 +531 +532 +533 +534 +535 +536 +537 +538 +539 +540 +541 +542 +543 +544 +545 +546 +547 +548 +549 +550 +551 +552 +553 +554 +555 +556 +557 +558 +559 +560 +561 +562 +563 +564 +565 +566 +567 +568 +569 +570 +571 +572 +573 +574 +575 +576 +577 +578 +579 +580 +581 +582 +583 +584 +585 +586 +587 +588 +589 +590 +591 +592 +593 +594 +595 +596 +597 +598 +599 +600 +601 +602 +603 +604 +605 +606 +607 +608 +609 +610 +611 +612 +613 +614 +615 +616 +617 +618 +619 +620 +621 +622 +623 +624 +625 +626 +627 +628 +629 +630 +631 +632 +633 +634 +635 +636 +637 +638 +639 +640 +641 +642 +643 +644 +645 +646 +647 +648 +649 +650 +651 +652 +653 +654 +655 +656 +657 +658 +659 +660 +661 +662 +663 +664 +665 +666 +667 +668 +669 +670 +671 +672 +673 +674 +675 +676 +677 +678 +679 +680 +681 +682 +683 +684 +685 +686 +687 +688 +689 +690 +691 +692 +693 +694 +695 +696 +697 +698 +699 +700 +701 +702 +703 +704 +705 +706 +707 +708 +709 +710 +711 +712 +713 +714 +715 +716 +717 +718 +719 +720 +721 +722 +723 +724 +725 +726 +727 +728 +729 +730 +731 +732 +733 +734 +735 +736 +737 +738 +739 +740 +741 +742 +743 +744 +745 +746 +747 +748 +749 +750 +751 +752 +753 +754 +755 +756 +757 +758 +759 +760 +761 +762 +763 +764 +765 +766 +767 +768 +769 +770 +771 +772 +773 +774 +775 +776 +777 +778 +779 +780 +781 +782 +783 +784 +785 +786 +787 +788 +789 +790 +791 +792 +793 +794 +795 +796 +797 +798 +799 +800 +801 +802 +803 +804 +805 +806 +807 +808 +809 +810 +811 +812 +813 +814 +815 +816 +817 +818 +819 +820 +821 +822 +823 +824 +825 +826 +827 +828 +829 +830 +831 +832 +833 +834 +835 +836 +837 +838 +839 +840 +841 +842 +843 +844 +845 +846 +847 +848 +849 +850 +851 +852 +853 +854 +855 +856 +857 +858 +859 +860 +861 +862 +863 +864 +865 +866 +867 +868 +869 +870 +871 +872 +873 +874 +875 +876 +877 +878 +879 +880 +881 +882 +883 +884 +885 +886 +887 +888 +889 +890 +891 +892 +893 +894 +895 +896 +897 +898 +899 +900 +901 +902 +903 +904 +905 +906 +907 +908 +909 +910 +911 +912 +913 +914 +915 +916 +917 +918 +919 +920 +921 +922 +923 +924 +925 +926 +927 +928 +929 +930 +931 +932 +933 +934 +935 +936 +937 +938 +939 +940 +941 +942 +943 +944 +945 +946 +947 +948 +949 +950 +951 +952 +953 +954 +955 +956 +957 +958 +959 +960 +961 +962 +963 +964 +965 +966 +967 +968 +969 +970 +971 +972 +973 +974 +975 +976 +977 +978 +979 +980 +981 +982 +983 +984 +985 +986 +987 +988 +989 +990 +991 +992 +993 +994 +995 +996 +997 +998 +999 +1000 +1001 +1002 +1003 +1004 +1005 +1006 +1007 +1008 +1009 +1010 +1011 +1012 +1013 +1014 +1015 +1016 +1017 +1018 +1019 +1020 +1021 +1022 +1023 +1024 +1025 +1026 +1027 +1028 +1029 +1030 +1031 +1032 +1033 +1034 +1035 +1036 +1037 +1038 +1039 +1040 +1041 +1042 +1043 +1044 +1045 +1046 +1047 +1048 +1049 +1050 +1051 +1052 +1053 +1054 +1055 +1056 +1057 +1058 +1059 +1060 +1061 +1062 +1063 +1064 +1065 +1066 +1067 +1068 +1069 +1070 +1071 +1072 +1073 +1074 +1075 +1076 +1077 +1078 +1079 +1080 +1081 +1082 +1083 +1084 +1085 +1086 +1087 +1088 +1089 +1090 +1091 +1092 +1093 +1094 +1095 +1096 +1097 +1098 +1099 +1100 +1101 +1102 +1103 +1104 +1105 +1106 +1107 +1108 +1109 +1110 +1111 +1112 +1113 +1114 +1115 +1116 +1117 +1118 +1119 +1120 +1121 +1122 +1123 +1124 +1125 +1126 +1127 +1128 +1129 +1130 +1131 +1132 +1133 +1134 +1135 +1136 +1137 +1138 +1139 +1140 +1141 +1142 +1143 +1144 +1145 +1146 +1147 +1148 +1149 +1150 +1151 +1152 +1153 +1154 +1155 +1156 +1157 +1158 +1159 +1160 +1161 +1162 +1163 +1164 +1165 +1166 +1167 +1168 +1169 +1170 +1171 +1172 +1173 +1174 +1175 +1176 +1177 +1178 +1179 +1180 +1181 +1182 +1183 +1184 +1185 +1186 +1187 +1188 +1189 +1190 +1191 +1192 +1193 +1194 +1195 +1196 +1197 +1198 +1199 +1200 +1201 +1202 +1203 +1204 +1205 +1206 +1207 +1208 +1209 +1210 +1211 +1212 +1213 +1214 +1215 +1216 +1217 +1218 +1219 +1220 +1221 +1222 +1223 +1224 +1225 +1226 +1227 +1228 +1229 +1230 +1231 +1232 +1233 +1234 +1235 +1236 +1237 +1238 +1239 +1240 +1241 +1242 +1243 +1244 +1245 +1246 +1247 +1248 +1249 +1250 +1251 +1252 +1253 +1254 +1255 +1256 +1257 +1258 +1259 +1260 +1261 +1262 +1263 +1264 +1265 +1266 +1267 +1268 +1269 +1270 +1271 +1272 +1273 +1274 +1275 +1276 +1277 +1278 +1279 +1280 +1281 +1282 +1283 +1284 +1285 +1286 +1287 +1288 +1289 +1290 +1291 +1292 +1293 +1294 +1295 +1296 +1297 +1298 +1299 +1300 +1301 +1302 +1303 +1304 +1305 +1306 +1307 +1308 +1309 +1310 +1311 +1312 +1313 +1314 +1315 +1316 +1317 +1318 +1319 +1320 +1321 +1322 +1323 +1324 +1325 +1326 +1327 +1328 +1329 +1330 +1331 +1332 +1333 +1334 +1335 +1336 +1337 +1338 +1339 +1340 +1341 +1342 +1343 +1344 +1345 +1346 +1347 +1348 +1349 +1350 +1351 +1352 +1353 +1354 +1355 +1356 +1357 +1358 +1359 +1360 +1361 +1362 +1363 +1364 +1365 +1366 +1367 +1368 +1369 +1370 +1371 +1372 +1373 +1374 +1375 +1376 +1377 +1378 +1379 +1380 +1381 +1382 +1383 +1384 +1385 +1386 +1387 +1388 +1389 +1390 +1391 +1392 +1393 +1394 +1395 +1396 +1397 +1398 +1399 +1400 +1401 +1402 +1403 +1404 +1405 +1406 +1407 +1408 +1409 +1410 +1411 +1412 +1413 +1414 +1415 +1416 +1417 +1418 +1419 +1420 +1421 +1422 +1423 +1424 +1425 +1426 +1427 +1428 +1429 +1430 +1431 +1432 +1433 +1434 +1435 +1436 +1437 +1438 +1439 +1440 +1441 +1442 +1443 +1444 +1445 +1446 +1447 +1448 +1449 +1450 +1451 +1452 +1453 +1454 +1455 +1456 +1457 +1458 +1459 +1460 +1461 +1462 +1463 +1464 +1465 +1466 +1467 +1468 +1469 +1470 +1471 +1472 +1473 +1474 +1475 +1476 +1477 +1478 +1479 +1480 +1481 +1482 +1483 +1484 +1485 +1486 +1487 +1488 +1489 +1490 +1491 +1492 +1493 +1494 +1495 +1496 +1497 +1498 +1499 +1500 +1501 +1502 +1503 +1504 +1505 +1506 +1507 +1508 +1509 +1510 +1511 +1512 +1513 +1514 +1515 +1516 +1517 +1518 +1519 +1520 +1521 +1522 +1523 +1524 +1525 +1526 +1527 +1528 +1529 +1530 +1531 +1532 +1533 +1534 +1535 +1536 +1537 +1538 +1539 +1540 +1541 +1542 +1543 +1544 +1545 +1546 +1547 +1548 +1549 +1550 +1551 +1552 +1553 +1554 +1555 +1556 +1557 +1558 +1559 +1560 +1561 +1562 +1563 +1564 +1565 +1566 +1567 +1568 +1569 +1570 +1571 +1572 +1573 +1574 +1575 +1576 +1577 +1578 +1579 +1580 +1581 +1582 +1583 +1584 +1585 +1586 +1587 +1588 +1589 +1590 +1591 +1592 +1593 +1594 +1595 +1596 +1597 +1598 +1599 +1600 +1601 +1602 +1603 +1604 +1605 +1606 +1607 +1608 +1609 +1610 +1611 +1612 +1613 +1614 +1615 +1616 +1617 +1618 +1619 +1620 +1621 +1622 +1623 +1624 +1625 +1626 +1627 +1628 +1629 +1630 +1631 +1632 +1633 +1634 +1635 +1636 +1637 +1638 +1639 +1640 +1641 +1642 +1643 +1644 +1645 +1646 +1647 +1648 +1649 +1650 +1651 +1652 +1653 +1654 +1655 +1656 +1657 +1658 +1659 +1660 +1661 +1662 +1663 +1664 +1665 +1666 +1667 +1668 +1669 +1670 +1671 +1672 +1673 +1674 +1675 +1676 +1677 +1678 +1679 +1680 +1681 +1682 +1683 +1684 +1685 +1686 +1687 +1688 +1689 +1690 +1691 +1692 +1693 +1694 +1695 +1696 +1697 +1698 +1699 +1700 +1701 +1702 +1703 +1704 +1705 +1706 +1707 +1708 +1709 +1710 +1711 +1712 +1713 +1714 +1715 +1716 +1717 +1718 +1719 +1720 +1721 +1722 +1723 +1724 +1725 +1726 +1727 +1728 +1729 +1730 +1731 +1732 +1733 +1734 +1735 +1736 +1737 +1738 +1739 +1740 +1741 +1742 +1743 +1744 +1745 +1746 +1747 +1748 +1749 +1750 +1751 +1752 +1753 +1754 +1755 +1756 +1757 +1758 +1759 +1760 +1761 +1762 +1763 +1764 +1765 +1766 +1767 +1768 +1769 +1770 +1771 +1772 +1773 +1774 +1775 +1776 +1777 +1778 +1779 +1780 +1781 +1782 +1783 +1784 +1785 +1786 +1787 +1788 +1789 +1790 +1791 +1792 +1793 +1794 +1795 +1796 +1797 +1798 +1799 +1800 +1801 +1802 +1803 +1804 +1805 +1806 +1807 +1808 +1809 +1810 +1811 +1812 +1813 +1814 +1815 +1816 +1817 +1818 +1819 +1820 +1821 +1822 +1823 +1824 +1825 +1826 +1827 +1828 +1829 +1830 +1831 +1832 +1833 +1834 +1835 +1836 +1837 +1838 +1839 +1840 +1841 +1842 +1843 +1844 +1845 +1846 +1847 +1848 +1849 +1850 +1851 +1852 +1853 + |
+# ==================================================================================================================== # +# _____ ____ _ _ ____ _ _ __ __ _ _ # +# _ __ _ _| ____| _ \ / \ / \ | _ \ _ __ ___ (_) ___ ___| |_| \/ | ___ __| | ___| | # +# | '_ \| | | | _| | | | |/ _ \ / _ \ | |_) | '__/ _ \| |/ _ \/ __| __| |\/| |/ _ \ / _` |/ _ \ | # +# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| __/| | | (_) | | __/ (__| |_| | | | (_) | (_| | __/ | # +# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_| |_| \___// |\___|\___|\__|_| |_|\___/ \__,_|\___|_| # +# |_| |___/ |__/ # +# ==================================================================================================================== # +# Authors: # +# Patrick Lehmann # +# # +# License: # +# ==================================================================================================================== # +# Copyright 2017-2023 Patrick Lehmann - Boetzingen, Germany # +# Copyright 2014-2016 Technische Universität Dresden - Germany, Chair of VLSI-Design, Diagnostics and Architecture # +# # +# 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 # +# ==================================================================================================================== # +# +"""An abstract model of EDA tool projects.""" +__author__ = "Patrick Lehmann" +__email__ = "Paebbels@gmail.com" +__copyright__ = "2014-2023, Patrick Lehmann, Unai Martinez-Corral" +__license__ = "Apache License, Version 2.0" +__version__ = "0.5.0" +__keywords__ = ["eda project", "model", "abstract", "xilinx", "vivado", "osvvm", "file set", "file group", "test bench", "test harness"] + +from os.path import relpath as path_relpath +from pathlib import Path as pathlib_Path +from typing import Dict, Union, Optional as Nullable, List, Iterable, Generator, Tuple, Any as typing_Any, Type, Set, Any + +from pyTooling.Decorators import export +from pyTooling.MetaClasses import ExtendedType +from pyTooling.Graph import Graph, Vertex +from pySVModel import SystemVerilogVersion +from pyVHDLModel import VHDLVersion +from pySystemRDLModel import SystemRDLVersion + + +@export +class Attribute(metaclass=ExtendedType): + KEY: str + VALUE_TYPE: typing_Any + + @staticmethod + def resolve(obj: typing_Any, key: Type['Attribute']): + if isinstance(obj, File): + return obj._fileSet[key] + elif isinstance(obj, FileSet): + return obj._design[key] + elif isinstance(obj, Design): + return obj._project[key] + else: + raise Exception("Resolution error") + + +@export +class FileType(ExtendedType): + """ + A :term:`meta-class` to construct *FileType* classes. + + Modifications done by this meta-class: + * Register all classes of type :class:`FileType` or derived variants in a class field :attr:`FileType.FileTypes` in this meta-class. + """ + + FileTypes: Dict[str, 'FileType'] = {} #: Dictionary of all classes of type :class:`FileType` or derived variants + Any: 'FileType' + + def __init__(cls, name: str, bases: Tuple[type, ...], dictionary: Dict[str, typing_Any], **kwargs): + super().__init__(name, bases, dictionary, **kwargs) + cls.Any = cls + + def __new__(cls, className, baseClasses, classMembers: Dict, *args, **kwargs): + fileType = super().__new__(cls, className, baseClasses, classMembers, *args, **kwargs) + cls.FileTypes[className] = fileType + return fileType + + def __getattr__(cls, item) -> 'FileType': + if item[:2] != "__" and item[-2:] != "__": + return cls.FileTypes[item] + else: + return super().__getattribute__(item) + + def __contains__(cls, item) -> bool: + return issubclass(item, cls) + + +@export +class File(metaclass=FileType, slots=True): + """ + A :term:`File` represents a file in a design. This :term:`base-class` is used + for all derived file classes. + + A file can be created standalone and later associated to a fileset, design and + project. Or a fileset, design and/or project can be associated immediately + while creating a file. + + :arg path: Relative or absolute path to the file. + :arg project: Project the file is associated with. + :arg design: Design the file is associated with. + :arg fileSet: Fileset the file is associated with. + """ + + _path: pathlib_Path + _fileType: 'FileType' + _project: Nullable['Project'] + _design: Nullable['Design'] + _fileSet: Nullable['FileSet'] + _attributes: Dict[Type[Attribute], typing_Any] + + def __init__( + self, + path: pathlib_Path, + project: 'Project' = None, + design: 'Design' = None, + fileSet: 'FileSet' = None + ): + self._fileType = getattr(FileTypes, self.__class__.__name__) + self._path = path + if project is not None: + self._project = project + self._design = design + if fileSet is not None: + self.FileSet = fileSet + elif design is not None: + self._project = design._project + self._design = design + self.FileSet = design.DefaultFileSet if fileSet is None else fileSet + elif fileSet is not None: + design = fileSet._design + if design is not None: + self._project = design._project + else: + self._project = None + self._design = design + self.FileSet = fileSet + else: + self._project = None + self._design = None + self._fileSet = None + + self._attributes = {} + self._registerAttributes() + + def _registerAttributes(self): + pass + + @property + def FileType(self) -> 'FileType': + """Read-only property to return the file type of this file.""" + return self._fileType + + @property + def Path(self) -> pathlib_Path: + """Read-only property returning the path of this file.""" + return self._path + + # TODO: setter? + + @property + def ResolvedPath(self) -> pathlib_Path: + """Read-only property returning the resolved path of this file.""" + if self._path.is_absolute(): + return self._path.resolve() + elif self._fileSet is not None: + path = (self._fileSet.ResolvedPath / self._path).resolve() + + if path.is_absolute(): + return path + else: + # WORKAROUND: https://stackoverflow.com/questions/67452690/pathlib-path-relative-to-vs-os-path-relpath + return pathlib_Path(path_relpath(path, pathlib_Path.cwd())) + else: + # TODO: message and exception type + raise Exception("") + + @property + def Project(self) -> Nullable['Project']: + """Property setting or returning the project this file is used in.""" + return self._project + + @Project.setter + 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']: + """Property setting or returning the design this file is used in.""" + return self._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: + raise Exception("The design's project is not identical to the already assigned project.") + + @property + def FileSet(self) -> Nullable['FileSet']: + """Property setting or returning the fileset this file is used in.""" + return self._fileSet + + @FileSet.setter + def FileSet(self, value: 'FileSet') -> None: + self._fileSet = value + value._files.append(self) + + def Validate(self): + """Validate this file.""" + if self._path is None: + raise Exception("Validation: File has no path.") + try: + path = self.ResolvedPath + except Exception as ex: + raise Exception(f"Validation: File '{self._path}' could not compute resolved path.") from ex + if not path.exists(): + raise Exception(f"Validation: File '{self._path}' (={path}) does not exist.") + if not path.is_file(): + raise Exception(f"Validation: File '{self._path}' (={path}) is not a file.") + + if self._fileSet is None: + raise Exception(f"Validation: File '{self._path}' has no fileset.") + if self._design is None: + raise Exception(f"Validation: File '{self._path}' has no design.") + if self._project is None: + raise Exception(f"Validation: File '{self._path}' has no project.") + + def __len__(self) -> int: + """ + Returns number of attributes set on this file. + + :returns: The number if attributes set on this file. + """ + return len(self._attributes) + + def __getitem__(self, key: Type[Attribute]) -> Any: + """Index access for returning attributes on this file. + + :param key: The attribute type. + :returns: The attribute's value. + :raises TypeError: When parameter 'key' is not a subclass of Attribute. + """ + if not issubclass(key, Attribute): + raise TypeError("Parameter 'key' is not an 'Attribute'.") + + try: + return self._attributes[key] + except KeyError: + return key.resolve(self, key) + + def __setitem__(self, key: Type[Attribute], value: typing_Any) -> None: + """ + Index access for adding or setting attributes on this file. + + :param key: The attribute type. + :param value: The attributes value. + :raises TypeError: When parameter 'key' is not a subclass of Attribute. + """ + if not issubclass(key, Attribute): + raise TypeError("Parameter 'key' is not an 'Attribute'.") + + self._attributes[key] = value + + def __delitem__(self, key: Type[Attribute]) -> None: + """ + Index access for deleting attributes on this file. + + :param key: The attribute type. + """ + if not issubclass(key, Attribute): + raise TypeError("Parameter 'key' is not an 'Attribute'.") + + del self._attributes[key] + + def __str__(self) -> str: + return f"{self._path}" + + +FileTypes = File + + +@export +class HumanReadableContent(metaclass=ExtendedType, mixin=True): + """A file type representing human-readable contents.""" + + +@export +class XMLContent(HumanReadableContent, mixin=True): + """A file type representing XML contents.""" + + +@export +class YAMLContent(HumanReadableContent, mixin=True): + """A file type representing YAML contents.""" + + +@export +class JSONContent(HumanReadableContent, mixin=True): + """A file type representing JSON contents.""" + + +@export +class INIContent(HumanReadableContent, mixin=True): + """A file type representing INI contents.""" + + +@export +class TOMLContent(HumanReadableContent, mixin=True): + """A file type representing TOML contents.""" + + +@export +class TCLContent(HumanReadableContent, mixin=True): + """A file type representing content in TCL code.""" + + +@export +class SDCContent(TCLContent, mixin=True): + """A file type representing contents as Synopsys Design Constraints (SDC).""" + + +@export +class PythonContent(HumanReadableContent, mixin=True): + """A file type representing contents as Python source code.""" + + +@export +class TextFile(File, HumanReadableContent): + """A text file (``*.txt``).""" + + +@export +class LogFile(File, HumanReadableContent): + """A log file (``*.log``).""" + + +@export +class XMLFile(File, XMLContent): + """An XML file (``*.xml``).""" + + +@export +class SourceFile(File): + """Base-class of all source files.""" + + +@export +class HDLSourceFile(SourceFile): + """Base-class of all HDL source files.""" + + +@export +class RDLSourceFile(SourceFile): + """Base-class of all RDL source files.""" + + +@export +class NetlistFile(SourceFile): + """Base-class of all netlist source files.""" + + +@export +class EDIFNetlistFile(NetlistFile): + """Netlist file in EDIF (Electronic Design Interchange Format).""" + + +@export +class TCLSourceFile(SourceFile, TCLContent): + """A TCL source file.""" + + +@export +class VHDLSourceFile(HDLSourceFile, HumanReadableContent): + """ + A VHDL source file (of any language version). + + :arg path: Relative or absolute path to the file. + :arg vhdlLibrary: VHDLLibrary this VHDL source file is associated wih. + :arg vhdlVersion: VHDLVersion this VHDL source file is associated wih. + :arg project: Project the file is associated with. + :arg design: Design the file is associated with. + :arg fileSet: Fileset the file is associated with. + """ + + _vhdlLibrary: Nullable['VHDLLibrary'] + _vhdlVersion: VHDLVersion + + def __init__(self, path: pathlib_Path, vhdlLibrary: Union[str, 'VHDLLibrary'] = None, vhdlVersion: VHDLVersion = None, project: 'Project' = None, design: 'Design' = None, fileSet: 'FileSet' = None): + super().__init__(path, project, design, fileSet) + + if isinstance(vhdlLibrary, str): + if design is not None: + try: + vhdlLibrary = design.VHDLLibraries[vhdlLibrary] + except KeyError as ex: + raise Exception(f"VHDL library '{vhdlLibrary}' not found in design '{design.Name}'.") from ex + elif project is not None: + try: + vhdlLibrary = project.DefaultDesign.VHDLLibraries[vhdlLibrary] + except KeyError as ex: + raise Exception(f"VHDL library '{vhdlLibrary}' not found in default design '{project.DefaultDesign.Name}'.") from ex + else: + raise Exception(f"Can't lookup VHDL library because neither 'project' nor 'design' is given as a parameter.") + elif isinstance(vhdlLibrary, VHDLLibrary): + self._vhdlLibrary = vhdlLibrary + vhdlLibrary.AddFile(self) + elif vhdlLibrary is None: + self._vhdlLibrary = None + else: + raise TypeError(f"Parameter 'vhdlLibrary' is neither a 'str' nor 'VHDLibrary'.") + + self._vhdlVersion = vhdlVersion + + def Validate(self) -> None: + """Validate this VHDL source file.""" + super().Validate() + + try: + _ = self.VHDLLibrary + except Exception as ex: + raise Exception(f"Validation: VHDLSourceFile '{self._path}' (={self.ResolvedPath}) has no VHDLLibrary assigned.") from ex + try: + _ = self.VHDLVersion + except Exception as ex: + raise Exception(f"Validation: VHDLSourceFile '{self._path}' (={self.ResolvedPath}) has no VHDLVersion assigned.") from ex + + @property + def VHDLLibrary(self) -> 'VHDLLibrary': + """Property setting or returning the VHDL library this VHDL source file is used in.""" + if self._vhdlLibrary is not None: + return self._vhdlLibrary + elif self._fileSet is not None: + return self._fileSet.VHDLLibrary + else: + raise Exception("VHDLLibrary was neither set locally nor globally.") + + @VHDLLibrary.setter + def VHDLLibrary(self, value: 'VHDLLibrary') -> None: + self._vhdlLibrary = value + value._files.append(self) + + @property + def VHDLVersion(self) -> VHDLVersion: + """Property setting or returning the VHDL version this VHDL source file is used in.""" + if self._vhdlVersion is not None: + return self._vhdlVersion + elif self._fileSet is not None: + return self._fileSet.VHDLVersion + else: + raise Exception("VHDLVersion was neither set locally nor globally.") + + @VHDLVersion.setter + def VHDLVersion(self, value: VHDLVersion) -> None: + self._vhdlVersion = value + + def __repr__(self) -> str: + return f"<VHDL file: '{self.ResolvedPath}'; lib: '{self.VHDLLibrary}'; version: {self.VHDLVersion}>" + + +class VerilogMixIn(metaclass=ExtendedType, mixin=True): + @property + def VerilogVersion(self) -> SystemVerilogVersion: + """Property setting or returning the Verilog version this Verilog source file is used in.""" + if self._version is not None: + return self._version + elif self._fileSet is not None: + return self._fileSet.VerilogVersion + else: + raise Exception("VerilogVersion was neither set locally nor globally.") + + @VerilogVersion.setter + def VerilogVersion(self, value: SystemVerilogVersion) -> None: + self._version = value + + +class SystemVerilogMixIn(metaclass=ExtendedType, mixin=True): + @property + def SVVersion(self) -> SystemVerilogVersion: + """Property setting or returning the SystemVerilog version this SystemVerilog source file is used in.""" + if self._version is not None: + return self._version + elif self._fileSet is not None: + return self._fileSet.SVVersion + else: + raise Exception("SVVersion was neither set locally nor globally.") + + @SVVersion.setter + def SVVersion(self, value: SystemVerilogVersion) -> None: + self._version = value + + +@export +class VerilogBaseFile(HDLSourceFile, HumanReadableContent): + _version: SystemVerilogVersion + + def __init__(self, path: pathlib_Path, version: SystemVerilogVersion = None, project: 'Project' = None, design: 'Design' = None, fileSet: 'FileSet' = None): + super().__init__(path, project, design, fileSet) + + self._version = version + + +@export +class VerilogSourceFile(VerilogBaseFile, VerilogMixIn): + """A Verilog source file (of any language version).""" + + +@export +class VerilogHeaderFile(VerilogBaseFile, VerilogMixIn): + """A Verilog header file (of any language version).""" + + +@export +class SystemVerilogBaseFile(VerilogBaseFile): + ... + + +@export +class SystemVerilogSourceFile(SystemVerilogBaseFile, SystemVerilogMixIn): + """A SystemVerilog source file (of any language version).""" + + +@export +class SystemVerilogHeaderFile(SystemVerilogBaseFile, SystemVerilogMixIn): + """A SystemVerilog header file (of any language version).""" + + +@export +class SystemRDLSourceFile(RDLSourceFile, HumanReadableContent): + """A SystemRDL source file (of any language version).""" + + _srdlVersion: SystemRDLVersion + + def __init__(self, path: pathlib_Path, srdlVersion: SystemRDLVersion = None, project: 'Project' = None, design: 'Design' = None, fileSet: 'FileSet' = None): + super().__init__(path, project, design, fileSet) + + self._srdlVersion = srdlVersion + + @property + def SystemRDLVersion(self) -> SystemRDLVersion: + """Property setting or returning the SystemRDL version this SystemRDL source file is used in.""" + if self._srdlVersion is not None: + return self._srdlVersion + elif self._fileSet is not None: + return self._fileSet.SRDLVersion + else: + raise Exception("SRDLVersion was neither set locally nor globally.") + + @SystemRDLVersion.setter + def SystemRDLVersion(self, value: SystemRDLVersion) -> None: + self._srdlVersion = value + + +@export +class PythonSourceFile(SourceFile, PythonContent): + """A Python source file.""" + + +# TODO: move to a Cocotb module +@export +class CocotbPythonFile(PythonSourceFile): + """A Python source file used by Cocotb.""" + + +@export +class ConstraintFile(File, HumanReadableContent): + """Base-class of all constraint files.""" + + +@export +class ProjectFile(File): + """Base-class of all tool-specific project files.""" + + +@export +class CSourceFile(SourceFile): + """Base-class of all ANSI-C source files.""" + + +@export +class CppSourceFile(SourceFile): + """Base-class of all ANSI-C++ source files.""" + + +@export +class SettingFile(File): + """Base-class of all tool-specific setting files.""" + + +@export +class SimulationAnalysisFile(File): + """Base-class of all tool-specific analysis files.""" + + +@export +class SimulationElaborationFile(File): + """Base-class of all tool-specific elaboration files.""" + + +@export +class SimulationStartFile(File): + """Base-class of all tool-specific simulation start-up files.""" + + +@export +class SimulationRunFile(File): + """Base-class of all tool-specific simulation run (execution) files.""" + + +@export +class WaveformConfigFile(File): + """Base-class of all tool-specific waveform configuration files.""" + + +@export +class WaveformDatabaseFile(File): + """Base-class of all tool-specific waveform database files.""" + + +@export +class WaveformExchangeFile(File): + """Base-class of all tool-independent waveform exchange files.""" + + +@export +class FileSet(metaclass=ExtendedType, slots=True): + """ + A :term:`FileSet` represents a group of files. Filesets can have sub-filesets. + + The order of insertion is preserved. A fileset can be created standalone and + later associated to another fileset, design and/or project. Or a fileset, + design and/or project can be associated immediately while creating the + fileset. + + :arg name: Name of this fileset. + :arg topLevel: Name of the fileset's toplevel. + :arg directory: Path of this fileset (absolute or relative to a parent fileset or design). + :arg project: Project the file is associated with. + :arg design: Design the file is associated with. + :arg parent: Parent fileset if this fileset is nested. + :arg vhdlLibrary: Default VHDL library for files in this fileset, if not specified for the file itself. + :arg vhdlVersion: Default VHDL version for files in this fileset, if not specified for the file itself. + :arg verilogVersion: Default Verilog version for files in this fileset, if not specified for the file itself. + :arg svVersion: Default SystemVerilog version for files in this fileset, if not specified for the file itself. + :arg srdlVersion: Default SystemRDL version for files in this fileset, if not specified for the file itself. + """ + + _name: str + _topLevel: Nullable[str] + _project: Nullable['Project'] + _design: Nullable['Design'] + _directory: pathlib_Path + _parent: Nullable['FileSet'] + _fileSets: Dict[str, 'FileSet'] + _files: List[File] + _set: Set + _attributes: Dict[Type[Attribute], typing_Any] + _vhdlLibraries: Dict[str, 'VHDLLibrary'] + _vhdlLibrary: 'VHDLLibrary' + _vhdlVersion: VHDLVersion + _verilogVersion: SystemVerilogVersion + _svVersion: SystemVerilogVersion + _srdlVersion: SystemRDLVersion + + def __init__( + self, + name: str, + topLevel: str = None, + directory: pathlib_Path = pathlib_Path("."), + project: 'Project' = None, + design: 'Design' = None, + parent: Nullable['FileSet'] = None, + vhdlLibrary: Union[str, 'VHDLLibrary'] = None, + vhdlVersion: VHDLVersion = None, + verilogVersion: SystemVerilogVersion = None, + svVersion: SystemVerilogVersion = None, + srdlVersion: SystemRDLVersion = None + ): + self._name = name + self._topLevel = topLevel + if project is not None: + self._project = project + self._design = design if design is not None else project.DefaultDesign + + elif design is not None: + self._project = design._project + self._design = design + else: + self._project = None + self._design = None + self._directory = directory + self._parent = parent + self._fileSets = {} + self._files = [] + self._set = set() + + if design is not None: + design._fileSets[name] = self + + self._attributes = {} + self._vhdlLibraries = {} + + # TODO: handle if vhdlLibrary is a string + self._vhdlLibrary = vhdlLibrary + self._vhdlVersion = vhdlVersion + self._verilogVersion = verilogVersion + self._svVersion = svVersion + self._srdlVersion = srdlVersion + + @property + def Name(self) -> str: + """Property setting or returning the fileset's name.""" + return self._name + + @Name.setter + def Name(self, value: str) -> None: + self._name = value + + @property + def TopLevel(self) -> str: + """Property setting or returning the fileset's toplevel.""" + return self._topLevel + + @TopLevel.setter + def TopLevel(self, value: str) -> None: + self._topLevel = value + + @property + def Project(self) -> Nullable['Project']: + """Property setting or returning the project this fileset is used in.""" + return self._project + + @Project.setter + def Project(self, value: 'Project') -> None: + self._project = value + + @property + def Design(self) -> Nullable['Design']: + """Property setting or returning the design this fileset is used in.""" + if self._design is not None: + return self._design + elif self._parent is not None: + return self._parent.Design + else: + return None + # TODO: raise exception instead + # QUESTION: how to handle if design and parent is set? + + @Design.setter + def Design(self, value: 'Design') -> None: + self._design = value + if self._project is None: + self._project = value._project + elif self._project is not value._project: + raise Exception("The design's project is not identical to the already assigned project.") + + @property + def Directory(self) -> pathlib_Path: + """Property setting or returning the directory this fileset is located in.""" + return self._directory + + @Directory.setter + def Directory(self, value: pathlib_Path) -> None: + self._directory = value + + @property + def ResolvedPath(self) -> pathlib_Path: + """Read-only property returning the resolved path of this fileset.""" + if self._directory.is_absolute(): + return self._directory.resolve() + else: + if self._parent is not None: + directory = self._parent.ResolvedPath + elif self._design is not None: + directory = self._design.ResolvedPath + elif self._project is not None: + directory = self._project.ResolvedPath + else: + # TODO: message and exception type + raise Exception("") + + directory = (directory / self._directory).resolve() + if directory.is_absolute(): + return directory + else: + # WORKAROUND: https://stackoverflow.com/questions/67452690/pathlib-path-relative-to-vs-os-path-relpath + return pathlib_Path(path_relpath(directory, pathlib_Path.cwd())) + + @property + def Parent(self) -> Nullable['FileSet']: + """Property setting or returning the parent fileset this fileset is used in.""" + return self._parent + + @Parent.setter + def Parent(self, value: 'FileSet') -> None: + self._parent = value + value._fileSets[self._name] = self + # TODO: check it it already exists + # QUESTION: make an Add fileset method? + + @property + def FileSets(self) -> Dict[str, 'FileSet']: + """Read-only property returning the dictionary of sub-filesets.""" + return self._fileSets + + def Files(self, fileType: FileType = FileTypes.Any, fileSet: Union[bool, str, 'FileSet'] = None) -> Generator[File, None, None]: + """ + Method returning the files of this fileset. + + :arg fileType: A filter for file types. Default: ``Any``. + :arg fileSet: Specifies how to handle sub-filesets. + """ + if fileSet is False: + for file in self._files: + if file.FileType in fileType: + yield file + elif fileSet is None: + for fileSet in self._fileSets.values(): + for file in fileSet.Files(fileType): + yield file + for file in self._files: + if file.FileType in fileType: + yield file + else: + if isinstance(fileSet, str): + fileSetName = fileSet + try: + fileSet = self._fileSets[fileSetName] + except KeyError as ex: + raise Exception(f"Fileset {fileSetName} not bound to fileset {self.Name}.") from ex + elif not isinstance(fileSet, FileSet): + raise TypeError("Parameter 'fileSet' is not of type 'str' or 'FileSet' nor value 'None'.") + + for file in fileSet.Files(fileType): + yield file + + def AddFileSet(self, fileSet: "FileSet") -> None: + """ + Method to add a single sub-fileset to this fileset. + + :arg fileSet: A fileset to add to this fileset as sub-fileset. + """ + if not isinstance(fileSet, FileSet): + raise ValueError("Parameter 'fileSet' is not of type ProjectModel.FileSet.") + elif fileSet in self._fileSets: + raise Exception("Sub-fileset already contains this fileset.") + elif fileSet.Name in self._fileSets.keys(): + raise Exception(f"Fileset already contains a sub-fileset named '{fileSet.Name}'.") + + self._fileSets[fileSet.Name] = fileSet + fileSet._parent = self + + def AddFileSets(self, fileSets: Iterable["FileSet"]) -> None: + """ + Method to add a multiple sub-filesets to this fileset. + + :arg fileSets: An iterable of filesets to add each to the fileset. + """ + for fileSet in fileSets: + self.AddFileSet(fileSet) + + @property + def FileSetCount(self) -> int: + """Returns number of file sets excl. sub-filesets.""" + return len(self._fileSets) + + @property + def TotalFileSetCount(self) -> int: + """Returns number of file sets incl. sub-filesets.""" + fileSetCount = len(self._fileSets) + for fileSet in self._fileSets.values(): + fileSetCount += fileSet.TotalFileSetCount + + return fileSetCount + + def AddFile(self, file: File) -> None: + """ + Method to add a single file to this fileset. + + :arg file: A file to add to this fileset. + """ + if not isinstance(file, File): + raise TypeError("Parameter 'file' is not of type ProjectModel.File.") + elif file._fileSet is not None: + ex = ValueError(f"File '{file.Path!s}' is already part of fileset '{file.FileSet.Name}'.") + ex.add_note(f"A file can't be assigned to another fileset.") + raise ex + elif file in self._set: + ex = ValueError(f"File '{file.Path!s}' is already part of this fileset.") + ex.add_note(f"A file can't be added twice to a fileset.") + raise ex + + self._files.append(file) + self._set.add(file) + file._fileSet = self + + def AddFiles(self, files: Iterable[File]) -> None: + """ + Method to add a multiple files to this fileset. + + :arg files: An iterable of files to add each to the fileset. + """ + for file in files: + self.AddFile(file) + + @property + def FileCount(self) -> int: + """Returns number of files excl. sub-filesets.""" + return len(self._files) + + @property + def TotalFileCount(self) -> int: + """Returns number of files incl. the files in sub-filesets.""" + fileCount = len(self._files) + for fileSet in self._fileSets.values(): + fileCount += fileSet.FileCount + + return fileCount + + def Validate(self) -> None: + """Validate this fileset.""" + if self._name is None or self._name == "": + raise Exception("Validation: FileSet has no name.") + + if self._directory is None: + raise Exception(f"Validation: FileSet '{self._name}' has no directory.") + try: + path = self.ResolvedPath + except Exception as ex: + raise Exception(f"Validation: FileSet '{self._name}' could not compute resolved path.") from ex + if not path.exists(): + raise Exception(f"Validation: FileSet '{self._name}'s directory '{path}' does not exist.") + if not path.is_dir(): + raise Exception(f"Validation: FileSet '{self._name}'s directory '{path}' is not a directory.") + + if self._design is None: + raise Exception(f"Validation: FileSet '{self._directory}' has no design.") + if self._project is None: + raise Exception(f"Validation: FileSet '{self._directory}' has no project.") + + for fileSet in self._fileSets.values(): + fileSet.Validate() + for file in self._files: + file.Validate() + + def GetOrCreateVHDLLibrary(self, name) -> 'VHDLLibrary': + if name in self._vhdlLibraries: + return self._vhdlLibraries[name] + elif name in self._design._vhdlLibraries: + library = self._design._vhdlLibraries[name] + self._vhdlLibraries[name] = library + return library + else: + library = VHDLLibrary(name, design=self._design, vhdlVersion=self._vhdlVersion) + self._vhdlLibraries[name] = library + return library + + @property + def VHDLLibrary(self) -> 'VHDLLibrary': + """Property setting or returning the VHDL library of this fileset.""" + if self._vhdlLibrary is not None: + return self._vhdlLibrary + elif self._parent is not None: + return self._parent.VHDLLibrary + elif self._design is not None: + return self._design.VHDLLibrary + else: + raise Exception("VHDLLibrary was neither set locally nor globally.") + + @VHDLLibrary.setter + def VHDLLibrary(self, value: 'VHDLLibrary') -> None: + self._vhdlLibrary = value + + @property + def VHDLVersion(self) -> VHDLVersion: + """Property setting or returning the VHDL version of this fileset.""" + if self._vhdlVersion is not None: + return self._vhdlVersion + elif self._parent is not None: + return self._parent.VHDLVersion + elif self._design is not None: + return self._design.VHDLVersion + else: + raise Exception("VHDLVersion was neither set locally nor globally.") + + @VHDLVersion.setter + def VHDLVersion(self, value: VHDLVersion) -> None: + self._vhdlVersion = value + + @property + def VerilogVersion(self) -> SystemVerilogVersion: + """Property setting or returning the Verilog version of this fileset.""" + if self._verilogVersion is not None: + return self._verilogVersion + elif self._parent is not None: + return self._parent.VerilogVersion + elif self._design is not None: + return self._design.VerilogVersion + else: + raise Exception("VerilogVersion was neither set locally nor globally.") + + @VerilogVersion.setter + def VerilogVersion(self, value: SystemVerilogVersion) -> None: + self._verilogVersion = value + + @property + def SVVersion(self) -> SystemVerilogVersion: + """Property setting or returning the SystemVerilog version of this fileset.""" + if self._svVersion is not None: + return self._svVersion + elif self._parent is not None: + return self._parent.SVVersion + elif self._design is not None: + return self._design.SVVersion + else: + raise Exception("SVVersion was neither set locally nor globally.") + + @SVVersion.setter + def SVVersion(self, value: SystemVerilogVersion) -> None: + self._svVersion = value + + @property + def SRDLVersion(self) -> SystemRDLVersion: + if self._srdlVersion is not None: + return self._srdlVersion + elif self._parent is not None: + return self._parent.SRDLVersion + elif self._design is not None: + return self._design.SRDLVersion + else: + raise Exception("SRDLVersion was neither set locally nor globally.") + + @SRDLVersion.setter + def SRDLVersion(self, value: SystemRDLVersion) -> None: + self._srdlVersion = value + + def __len__(self) -> int: + """ + Returns number of attributes set on this fileset. + + :returns: The number if attributes set on this fileset. + """ + return len(self._attributes) + + def __getitem__(self, key: Type[Attribute]) -> Any: + """Index access for returning attributes on this fileset. + + :param key: The attribute type. + :returns: The attribute's value. + :raises TypeError: When parameter 'key' is not a subclass of Attribute. + """ + if not issubclass(key, Attribute): + raise TypeError("Parameter 'key' is not an 'Attribute'.") + + try: + return self._attributes[key] + except KeyError: + return key.resolve(self, key) + + def __setitem__(self, key: Type[Attribute], value: typing_Any) -> None: + """ + Index access for adding or setting attributes on this fileset. + + :param key: The attribute type. + :param value: The attributes value. + :raises TypeError: When parameter 'key' is not a subclass of Attribute. + """ + if not issubclass(key, Attribute): + raise TypeError("Parameter 'key' is not an 'Attribute'.") + + self._attributes[key] = value + + def __delitem__(self, key: Type[Attribute]) -> None: + """ + Index access for deleting attributes on this fileset. + + :param key: The attribute type. + """ + if not issubclass(key, Attribute): + raise TypeError("Parameter 'key' is not an 'Attribute'.") + + del self._attributes[key] + + def __str__(self) -> str: + """Returns the fileset's name.""" + return self._name + + +@export +class VHDLLibrary(metaclass=ExtendedType, slots=True): + """ + A :term:`VHDLLibrary` represents a group of VHDL source files compiled into the same VHDL library. + + :arg name: The VHDL libraries' name. + :arg project: Project the VHDL library is associated with. + :arg design: Design the VHDL library is associated with. + :arg vhdlVersion: Default VHDL version for files in this VHDL library, if not specified for the file itself. + """ + + _name: str + _project: Nullable['Project'] + _design: Nullable['Design'] + _files: List[File] + _vhdlVersion: VHDLVersion + + _dependencyNode: Vertex + + def __init__( + self, + name: str, + project: 'Project' = None, + design: 'Design' = None, + vhdlVersion: VHDLVersion = None + ): + self._name = name + if project is not None: + self._project = project + self._design = project._defaultDesign if design is None else design + self._dependencyNode = Vertex(value=self, graph=self._design._vhdlLibraryDependencyGraph) + + if name in self._design._vhdlLibraries: + raise Exception(f"Library '{name}' already in design '{self._design.Name}'.") + else: + self._design._vhdlLibraries[name] = self + + elif design is not None: + self._project = design._project + self._design = design + self._dependencyNode = Vertex(value=self, graph=design._vhdlLibraryDependencyGraph) + + if name in design._vhdlLibraries: + raise Exception(f"Library '{name}' already in design '{design.Name}'.") + else: + design._vhdlLibraries[name] = self + + else: + self._project = None + self._design = None + self._dependencyNode = None + + self._files = [] + self._vhdlVersion = vhdlVersion + + @property + def Name(self) -> str: + return self._name + + @property + def Project(self) -> Nullable['Project']: + """Property setting or returning the project this VHDL library is used in.""" + return self._project + + @Project.setter + def Project(self, value: 'Project') -> None: + if not isinstance(value, Project): + raise TypeError("Parameter 'value' is not of type 'Project'.") + + if value is None: + # TODO: unlink VHDLLibrary from project + self._project = None + else: + self._project = value + if self._design is None: + self._design = value._defaultDesign + + @property + def Design(self) -> Nullable['Design']: + """Property setting or returning the design this VHDL library is used in.""" + return self._design + + @Design.setter + def Design(self, value: 'Design') -> None: + if not isinstance(value, Design): + raise TypeError("Parameter 'value' is not of type 'Design'.") + + if value is None: + # TODO: unlink VHDLLibrary from design + self._design = None + else: + if self._design is None: + self._design = value + self._dependencyNode = Vertex(value=self, graph=self._design._vhdlLibraryDependencyGraph) + elif self._design is not value: + # TODO: move VHDLLibrary to other design + # TODO: create new vertex in dependency graph and remove vertex from old graph + self._design = value + else: + pass + + if self._project is None: + self._project = value._project + elif self._project is not value._project: + raise Exception("The design's project is not identical to the already assigned project.") + + @property + def Files(self) -> Generator[File, None, None]: + """Read-only property to return all files in this VHDL library.""" + for file in self._files: + yield file + + @property + def VHDLVersion(self) -> VHDLVersion: + """Property setting or returning the VHDL version of this VHDL library.""" + if self._vhdlVersion is not None: + return self._vhdlVersion + elif self._design is not None: + return self._design.VHDLVersion + else: + raise Exception("VHDLVersion is not set on VHDLLibrary nor parent object.") + + @VHDLVersion.setter + def VHDLVersion(self, value: VHDLVersion) -> None: + self._vhdlVersion = value + + def AddDependency(self, library: 'VHDLLibrary') -> None: + library.parent = self + + def AddFile(self, vhdlFile: VHDLSourceFile) -> None: + if not isinstance(vhdlFile, VHDLSourceFile): + raise TypeError(f"Parameter 'vhdlFile' is not a 'VHDLSourceFile'.") + + self._files.append(vhdlFile) + + def AddFiles(self, vhdlFiles: Iterable[VHDLSourceFile]) -> None: + for vhdlFile in vhdlFiles: + if not isinstance(vhdlFile, VHDLSourceFile): + raise TypeError(f"Item '{vhdlFile}' in parameter 'vhdlFiles' is not a 'VHDLSourceFile'.") + + self._files.append(vhdlFile) + + @property + def FileCount(self) -> int: + """Returns number of files.""" + return len(self._files) + + def __len__(self) -> int: + """ + Returns number of attributes set on this VHDL library. + + :returns: The number if attributes set on this VHDL library. + """ + return len(self._attributes) + + def __getitem__(self, key: Type[Attribute]) -> Any: + """Index access for returning attributes on this VHDL library. + + :param key: The attribute type. + :returns: The attribute's value. + :raises TypeError: When parameter 'key' is not a subclass of Attribute. + """ + if not issubclass(key, Attribute): + raise TypeError("Parameter 'key' is not an 'Attribute'.") + + try: + return self._attributes[key] + except KeyError: + return key.resolve(self, key) + + def __setitem__(self, key: Type[Attribute], value: typing_Any) -> None: + """ + Index access for adding or setting attributes on this VHDL library. + + :param key: The attribute type. + :param value: The attributes value. + :raises TypeError: When parameter 'key' is not a subclass of Attribute. + """ + if not issubclass(key, Attribute): + raise TypeError("Parameter 'key' is not an 'Attribute'.") + + self._attributes[key] = value + + def __delitem__(self, key: Type[Attribute]) -> None: + """ + Index access for deleting attributes on this VHDL library. + + :param key: The attribute type. + """ + if not issubclass(key, Attribute): + raise TypeError("Parameter 'key' is not an 'Attribute'.") + + del self._attributes[key] + + def __str__(self) -> str: + """Returns the VHDL library's name.""" + return self._name + + +@export +class Design(metaclass=ExtendedType, slots=True): + """ + A :term:`Design` represents a group of filesets and the source files therein. + + Each design contains at least one fileset - the :term:`default fileset`. For + designs with VHDL source files, a independent `VHDLLibraries` overlay structure + exists. + + :arg name: The design's name. + :arg topLevel: Name of the design's toplevel. + :arg directory: Path of this design (absolute or relative to the project). + :arg project: Project the design is associated with. + :arg vhdlVersion: Default VHDL version for files in this design, if not specified for the file itself. + :arg verilogVersion: Default Verilog version for files in this design, if not specified for the file itself. + :arg svVersion: Default SystemVerilog version for files in this design, if not specified for the file itself. + :arg srdlVersion: Default SystemRDL version for files in this fileset, if not specified for the file itself. + """ + + _name: str + _topLevel: Nullable[str] + _project: Nullable['Project'] + _directory: pathlib_Path + _fileSets: Dict[str, FileSet] + _defaultFileSet: Nullable[FileSet] + _attributes: Dict[Type[Attribute], typing_Any] + + _vhdlLibraries: Dict[str, VHDLLibrary] + _vhdlVersion: VHDLVersion + _verilogVersion: SystemVerilogVersion + _svVersion: SystemVerilogVersion + _srdlVersion: SystemRDLVersion + _externalVHDLLibraries: List + + _vhdlLibraryDependencyGraph: Graph + _fileDependencyGraph: Graph + + def __init__( + self, + name: str, + topLevel: str = None, + directory: pathlib_Path = pathlib_Path("."), + project: 'Project' = None, + vhdlVersion: VHDLVersion = None, + verilogVersion: SystemVerilogVersion = None, + svVersion: SystemVerilogVersion = None, + srdlVersion: SystemRDLVersion = None + ): + self._name = name + self._topLevel = topLevel + 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) + self._attributes = {} + self._vhdlLibraries = {} + self._vhdlVersion = vhdlVersion + self._verilogVersion = verilogVersion + self._svVersion = svVersion + self._srdlVersion = srdlVersion + self._externalVHDLLibraries = [] + + self._vhdlLibraryDependencyGraph = Graph() + self._fileDependencyGraph = Graph() + + @property + def Name(self) -> str: + """Property setting or returning the design's name.""" + return self._name + + @Name.setter + def Name(self, value: str) -> None: + self._name = value + + @property + def TopLevel(self) -> str: + """Property setting or returning the fileset's toplevel.""" + return self._topLevel + + @TopLevel.setter + def TopLevel(self, value: str) -> None: + self._topLevel = value + + @property + def Project(self) -> Nullable['Project']: + """Property setting or returning the project this design is used in.""" + return self._project + + @Project.setter + def Project(self, value: 'Project') -> None: + self._project = value + + @property + def Directory(self) -> pathlib_Path: + """Property setting or returning the directory this design is located in.""" + return self._directory + + @Directory.setter + def Directory(self, value: pathlib_Path) -> None: + self._directory = value + + @property + def ResolvedPath(self) -> pathlib_Path: + """Read-only property returning the resolved path of this fileset.""" + if self._directory.is_absolute(): + return self._directory.resolve() + elif self._project is not None: + path = (self._project.ResolvedPath / self._directory).resolve() + + if path.is_absolute(): + return path + else: + # WORKAROUND: https://stackoverflow.com/questions/67452690/pathlib-path-relative-to-vs-os-path-relpath + return pathlib_Path(path_relpath(path, pathlib_Path.cwd())) + else: + # TODO: message and exception type + raise Exception("") + + @property + def DefaultFileSet(self) -> FileSet: + """Property setting or returning the default fileset of this design.""" + return self._defaultFileSet + + @DefaultFileSet.setter + def DefaultFileSet(self, value: Union[str, FileSet]) -> None: + if isinstance(value, str): + if value not in self._fileSets.keys(): + raise Exception(f"Fileset '{value}' is not in this design.") + + self._defaultFileSet = self._fileSets[value] + elif isinstance(value, FileSet): + if value not in self.FileSets: + raise Exception(f"Fileset '{value}' is not associated to this design.") + + self._defaultFileSet = value + else: + raise ValueError("Unsupported parameter type for 'value'.") + + # TODO: return generator with another method + @property + def FileSets(self) -> Dict[str, FileSet]: + """Read-only property returning the dictionary of filesets.""" + return self._fileSets + + def Files(self, fileType: FileType = FileTypes.Any, fileSet: Union[str, FileSet] = None) -> Generator[File, None, None]: + """ + Method returning the files of this design. + + :arg fileType: A filter for file types. Default: ``Any``. + :arg fileSet: Specifies if all files from all filesets (``fileSet=None``) are files from a single fileset are returned. + """ + if fileSet is None: + for fileSet in self._fileSets.values(): + for file in fileSet.Files(fileType): + yield file + else: + if isinstance(fileSet, str): + try: + fileSet = self._fileSets[fileSet] + except KeyError as ex: + raise Exception(f"Fileset {fileSet.Name} not bound to design {self.Name}.") from ex + elif not isinstance(fileSet, FileSet): + raise TypeError("Parameter 'fileSet' is not of type 'str' or 'FileSet' nor value 'None'.") + + for file in fileSet.Files(fileType): + yield file + + def Validate(self) -> None: + """Validate this design.""" + if self._name is None or self._name == "": + raise Exception("Validation: Design has no name.") + + if self._directory is None: + raise Exception(f"Validation: Design '{self._name}' has no directory.") + try: + path = self.ResolvedPath + except Exception as ex: + raise Exception(f"Validation: Design '{self._name}' could not compute resolved path.") from ex + if not path.exists(): + raise Exception(f"Validation: Design '{self._name}'s directory '{path}' does not exist.") + if not path.is_dir(): + raise Exception(f"Validation: Design '{self._name}'s directory '{path}' is not a directory.") + + if len(self._fileSets) == 0: + raise Exception(f"Validation: Design '{self._name}' has no fileset.") + try: + if self._defaultFileSet is not self._fileSets[self._defaultFileSet.Name]: + raise Exception(f"Validation: Design '{self._name}'s default fileset is the same as listed in filesets.") + except KeyError as ex: + raise Exception(f"Validation: Design '{self._name}'s default fileset is not in list of filesets.") from ex + if self._project is None: + raise Exception(f"Validation: Design '{self._path}' has no project.") + + for fileSet in self._fileSets.values(): + fileSet.Validate() + + @property + def VHDLLibraries(self) -> Dict[str, VHDLLibrary]: + return self._vhdlLibraries + + @property + def VHDLVersion(self) -> VHDLVersion: + if self._vhdlVersion is not None: + return self._vhdlVersion + elif self._project is not None: + return self._project.VHDLVersion + else: + raise Exception("VHDLVersion was neither set locally nor globally.") + + @VHDLVersion.setter + def VHDLVersion(self, value: VHDLVersion) -> None: + self._vhdlVersion = value + + @property + def VerilogVersion(self) -> SystemVerilogVersion: + if self._verilogVersion is not None: + return self._verilogVersion + elif self._project is not None: + return self._project.VerilogVersion + else: + raise Exception("VerilogVersion was neither set locally nor globally.") + + @VerilogVersion.setter + def VerilogVersion(self, value: SystemVerilogVersion) -> None: + self._verilogVersion = value + + @property + def SVVersion(self) -> SystemVerilogVersion: + if self._svVersion is not None: + return self._svVersion + elif self._project is not None: + return self._project.SVVersion + else: + raise Exception("SVVersion was neither set locally nor globally.") + + @SVVersion.setter + def SVVersion(self, value: SystemVerilogVersion) -> None: + self._svVersion = value + + @property + def SRDLVersion(self) -> SystemRDLVersion: + if self._srdlVersion is not None: + return self._srdlVersion + elif self._project is not None: + return self._project.SRDLVersion + else: + raise Exception("SRDLVersion was neither set locally nor globally.") + + @SRDLVersion.setter + def SRDLVersion(self, value: SystemRDLVersion) -> None: + self._srdlVersion = value + + @property + def ExternalVHDLLibraries(self) -> List: + return self._externalVHDLLibraries + + def AddFileSet(self, fileSet: FileSet) -> None: + if not isinstance(fileSet, FileSet): + raise ValueError("Parameter 'fileSet' is not of type ProjectModel.FileSet.") + elif fileSet in self._fileSets: + raise Exception("Design already contains this fileset.") + elif fileSet.Name in self._fileSets.keys(): + raise Exception(f"Design already contains a fileset named '{fileSet.Name}'.") + + self._fileSets[fileSet.Name] = fileSet + fileSet.Design = self + fileSet._parent = self + + def AddFileSets(self, fileSets: Iterable[FileSet]) -> None: + for fileSet in fileSets: + self.AddFileSet(fileSet) + + @property + def FileSetCount(self) -> int: + """Returns number of file sets excl. sub-filesets.""" + return len(self._fileSets) + + @property + def TotalFileSetCount(self) -> int: + """Returns number of file sets incl. sub-filesets.""" + fileSetCount = len(self._fileSets) + for fileSet in self._fileSets.values(): + fileSetCount += fileSet.TotalFileSetCount + + return fileSetCount + + def AddFile(self, file: File) -> None: + if file.FileSet is None: + self._defaultFileSet.AddFile(file) + else: + raise ValueError(f"File '{file.Path!s}' is already part of fileset '{file.FileSet.Name}' and can't be assigned via Design to a default fileset.") + + def AddFiles(self, files: Iterable[File]) -> None: + for file in files: + self.AddFile(file) + + def AddVHDLLibrary(self, vhdlLibrary: VHDLLibrary) -> None: + if vhdlLibrary.Name in self._vhdlLibraries: + if self._vhdlLibraries[vhdlLibrary.Name] is vhdlLibrary: + raise Exception(f"The VHDLLibrary '{vhdlLibrary.Name}' was already added to the design.") + else: + raise Exception(f"A VHDLLibrary with same name ('{vhdlLibrary.Name}') already exists for this design.") + + + def __len__(self) -> int: + """ + Returns number of attributes set on this design. + + :returns: The number if attributes set on this design. + """ + return len(self._attributes) + + def __getitem__(self, key: Type[Attribute]) -> Any: + """Index access for returning attributes on this design. + + :param key: The attribute type. + :returns: The attribute's value. + :raises TypeError: When parameter 'key' is not a subclass of Attribute. + """ + if not issubclass(key, Attribute): + raise TypeError("Parameter 'key' is not an 'Attribute'.") + + try: + return self._attributes[key] + except KeyError: + return key.resolve(self, key) + + def __setitem__(self, key: Type[Attribute], value: typing_Any) -> None: + """ + Index access for adding or setting attributes on this design. + + :param key: The attribute type. + :param value: The attributes value. + :raises TypeError: When parameter 'key' is not a subclass of Attribute. + """ + if not issubclass(key, Attribute): + raise TypeError("Parameter 'key' is not an 'Attribute'.") + + self._attributes[key] = value + + def __delitem__(self, key: Type[Attribute]) -> None: + """ + Index access for deleting attributes on this design. + + :param key: The attribute type. + """ + if not issubclass(key, Attribute): + raise TypeError("Parameter 'key' is not an 'Attribute'.") + + del self._attributes[key] + + def __str__(self) -> str: + return self._name + + +@export +class Project(metaclass=ExtendedType, slots=True): + """ + A :term:`Project` represents a group of designs and the source files therein. + + :arg name: The project's name. + :arg rootDirectory: Base-path to the project. + :arg vhdlVersion: Default VHDL version for files in this project, if not specified for the file itself. + :arg verilogVersion: Default Verilog version for files in this project, if not specified for the file itself. + :arg svVersion: Default SystemVerilog version for files in this project, if not specified for the file itself. + """ + + _name: str + _rootDirectory: pathlib_Path + _designs: Dict[str, Design] + _defaultDesign: Design + _attributes: Dict[Type[Attribute], typing_Any] + + _vhdlVersion: VHDLVersion + _verilogVersion: SystemVerilogVersion + _svVersion: SystemVerilogVersion + _srdlVersion: SystemRDLVersion + + def __init__( + self, + name: str, + rootDirectory: pathlib_Path = pathlib_Path("."), + vhdlVersion: VHDLVersion = None, + verilogVersion: SystemVerilogVersion = None, + svVersion: SystemVerilogVersion = None + ): + self._name = name + self._rootDirectory = rootDirectory + self._designs = {} + self._defaultDesign = Design("default", project=self) + self._attributes = {} + self._vhdlVersion = vhdlVersion + self._verilogVersion = verilogVersion + self._svVersion = svVersion + + @property + def Name(self) -> str: + """Property setting or returning the project's name.""" + return self._name + + @property + def RootDirectory(self) -> pathlib_Path: + """Property setting or returning the root directory this project is located in.""" + return self._rootDirectory + + @RootDirectory.setter + def RootDirectory(self, value: pathlib_Path) -> None: + self._rootDirectory = value + + @property + def ResolvedPath(self) -> pathlib_Path: + """Read-only property returning the resolved path of this fileset.""" + path = self._rootDirectory.resolve() + if self._rootDirectory.is_absolute(): + return path + else: + # WORKAROUND: https://stackoverflow.com/questions/67452690/pathlib-path-relative-to-vs-os-path-relpath + return pathlib_Path(path_relpath(path, pathlib_Path.cwd())) + + # TODO: return generator with another method + @property + def Designs(self) -> Dict[str, Design]: + return self._designs + + @property + def DefaultDesign(self) -> Design: + return self._defaultDesign + + def Validate(self) -> None: + """Validate this project.""" + if self._name is None or self._name == "": + raise Exception("Validation: Project has no name.") + + if self._rootDirectory is None: + raise Exception(f"Validation: Project '{self._name}' has no root directory.") + try: + path = self.ResolvedPath + except Exception as ex: + raise Exception(f"Validation: Project '{self._name}' could not compute resolved path.") from ex + if not path.exists(): + raise Exception(f"Validation: Project '{self._name}'s directory '{path}' does not exist.") + if not path.is_dir(): + raise Exception(f"Validation: Project '{self._name}'s directory '{path}' is not a directory.") + + if len(self._designs) == 0: + raise Exception(f"Validation: Project '{self._name}' has no design.") + try: + if self._defaultDesign is not self._designs[self._defaultDesign.Name]: + raise Exception(f"Validation: Project '{self._name}'s default design is the same as listed in designs.") + except KeyError as ex: + raise Exception(f"Validation: Project '{self._name}'s default design is not in list of designs.") from ex + + for design in self._designs.values(): + design.Validate() + + @property + def DesignCount(self) -> int: + """Returns number of designs.""" + return len(self._designs) + + @property + def VHDLVersion(self) -> VHDLVersion: + # TODO: check for None and return exception + return self._vhdlVersion + + @VHDLVersion.setter + def VHDLVersion(self, value: VHDLVersion) -> None: + self._vhdlVersion = value + + @property + def VerilogVersion(self) -> SystemVerilogVersion: + # TODO: check for None and return exception + return self._verilogVersion + + @VerilogVersion.setter + def VerilogVersion(self, value: SystemVerilogVersion) -> None: + self._verilogVersion = value + + @property + def SVVersion(self) -> SystemVerilogVersion: + # TODO: check for None and return exception + return self._svVersion + + @SVVersion.setter + def SVVersion(self, value: SystemVerilogVersion) -> None: + self._svVersion = value + + @property + def SRDLVersion(self) -> SystemRDLVersion: + # TODO: check for None and return exception + return self._srdlVersion + + @SRDLVersion.setter + def SRDLVersion(self, value: SystemRDLVersion) -> None: + self._srdlVersion = value + + def __len__(self) -> int: + """ + Returns number of attributes set on this project. + + :returns: The number if attributes set on this project. + """ + return len(self._attributes) + + def __getitem__(self, key: Type[Attribute]) -> Any: + """Index access for returning attributes on this project. + + :param key: The attribute type. + :returns: The attribute's value. + :raises TypeError: When parameter 'key' is not a subclass of Attribute. + """ + if not issubclass(key, Attribute): + raise TypeError("Parameter 'key' is not an 'Attribute'.") + + try: + return self._attributes[key] + except KeyError: + return key.resolve(self, key) + + def __setitem__(self, key: Type[Attribute], value: typing_Any) -> None: + """ + Index access for adding or setting attributes on this project. + + :param key: The attribute type. + :param value: The attributes value. + :raises TypeError: When parameter 'key' is not a subclass of Attribute. + """ + if not issubclass(key, Attribute): + raise TypeError("Parameter 'key' is not an 'Attribute'.") + + self._attributes[key] = value + + def __delitem__(self, key: Type[Attribute]) -> None: + """ + Index access for deleting attributes on this project. + + :param key: The attribute type. + """ + if not issubclass(key, Attribute): + raise TypeError("Parameter 'key' is not an 'Attribute'.") + + del self._attributes[key] + + def __str__(self) -> str: + return self._name + |
+
File | +Imprecision | +Lines | +
---|---|---|
Total | +14.11% imprecise | +2735 LOC | +
ProjectModel | +11.49% imprecise | +1853 LOC | +
ProjectModel.Altera | +0.00% imprecise | +31 LOC | +
ProjectModel.Altera.Quartus | +2.27% imprecise | +44 LOC | +
ProjectModel.Attributes | +7.55% imprecise | +53 LOC | +
ProjectModel.GHDL | +2.56% imprecise | +39 LOC | +
ProjectModel.Intel | +0.00% imprecise | +31 LOC | +
ProjectModel.Intel.QuartusPrime | +2.27% imprecise | +44 LOC | +
ProjectModel.MentorGraphics | +0.00% imprecise | +31 LOC | +
ProjectModel.MentorGraphics.ModelSim | +2.04% imprecise | +49 LOC | +
ProjectModel.MentorGraphics.QuestaSim | +2.04% imprecise | +49 LOC | +
ProjectModel.OSVVM | +38.02% imprecise | +192 LOC | +
ProjectModel.VHDL | +0.00% imprecise | +0 LOC | +
ProjectModel.Verilog | +2.56% imprecise | +39 LOC | +
ProjectModel.Xilinx | +0.00% imprecise | +31 LOC | +
ProjectModel.Xilinx.ISE | +2.27% imprecise | +44 LOC | +
ProjectModel.Xilinx.Vivado | +43.41% imprecise | +205 LOC | +