Vivado.py
Summary
- Lines:
114 of 128 covered (89.1%)
- Branches:
38 of 46 taken (82.6%), 4 lines partially
- Coverage:
87.4%
- Directory:
- Missed lines:
85-86, 119, 123-124, 158-163, 183, 186, 192, 195
Source
pyEDAA/ProjectModel/Xilinx/Vivado.pycoveredpartialuncoveredexcludednot executable
1# ==================================================================================================================== #
2# _____ ____ _ _ ____ _ _ __ __ _ _ #
3# _ __ _ _| ____| _ \ / \ / \ | _ \ _ __ ___ (_) ___ ___| |_| \/ | ___ __| | ___| | #
4# | '_ \| | | | _| | | | |/ _ \ / _ \ | |_) | '__/ _ \| |/ _ \/ __| __| |\/| |/ _ \ / _` |/ _ \ | #
5# | |_) | |_| | |___| |_| / ___ \ / ___ \ _| __/| | | (_) | | __/ (__| |_| | | | (_) | (_| | __/ | #
6# | .__/ \__, |_____|____/_/ \_\/_/ \_(_)_| |_| \___// |\___|\___|\__|_| |_|\___/ \__,_|\___|_| #
7# |_| |___/ |__/ #
8# ==================================================================================================================== #
9# Authors: #
10# Patrick Lehmann #
11# #
12# License: #
13# ==================================================================================================================== #
14# Copyright 2021-2026 Electronic Design Automation Abstraction (EDA²) #
15# Copyright 2017-2020 Patrick Lehmann - Boetzingen, Germany #
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"""Specific file types and attributes for Xilinx Vivado."""
33from pathlib import Path
34from typing import Iterable, Optional as Nullable
35from xml.dom import minidom, Node
36
37from pyTooling.Decorators import export
38from pyTooling.MetaClasses import ExtendedType
39from pyVHDLModel import VHDLVersion
40
41from pyEDAA.ProjectModel import ProjectFile, XMLFile, XMLContent, SDCContent, Project, FileSet, Attribute, Design, \
42 File as Model_File, ConstraintFile as Model_ConstraintFile, \
43 VerilogSourceFile as Model_VerilogSourceFile, VHDLSourceFile as Model_VHDLSourceFile
44
45
46@export
47class UsedInAttribute(Attribute):
48 KEY = "UsedIn"
49 VALUE_TYPE = Iterable[str]
50
51
52@export
53class ScopeToRefAttribute(Attribute):
54 KEY = "ScopeToRef"
55 VALUE_TYPE = Nullable[str]
56
57
58@export
59class ScopeToCellAttribute(Attribute):
60 KEY = "ScopeToCell"
61 VALUE_TYPE = Nullable[str]
62
63
64@export
65class File(Model_File):
66 pass
67
68
69@export
70class VivadoFileMixIn(metaclass=ExtendedType, mixin=True):
71 def _registerAttributes(self) -> None:
72 self._attributes[UsedInAttribute] = []
73
74
75@export
76class ConstraintFile(Model_ConstraintFile, VivadoFileMixIn):
77 def _registerAttributes(self) -> None:
78 super()._registerAttributes()
79 VivadoFileMixIn._registerAttributes(self)
80
81
82@export
83class VerilogSourceFile(Model_VerilogSourceFile):
84 def _registerAttributes(self) -> None:
85 super()._registerAttributes()
86 VivadoFileMixIn._registerAttributes(self)
87
88
89@export
90class VHDLSourceFile(Model_VHDLSourceFile):
91 def _registerAttributes(self) -> None:
92 super()._registerAttributes()
93 VivadoFileMixIn._registerAttributes(self)
94
95
96@export
97class VivadoProjectFile(ProjectFile, XMLContent):
98 """A Vivado project file (``*.xpr``)."""
99
100 _xprProject: Project
101
102 def __init__(
103 self,
104 path: Path,
105 project: Nullable[Project] = None,
106 design: Nullable[Design] = None,
107 fileSet: Nullable[FileSet] = None
108 ) -> None:
109 super().__init__(path, project, design, fileSet)
110
111 self._xprProject = None
112
113 @property
114 def ProjectModel(self) -> Project:
115 return self._xprProject
116
117 def Parse(self) -> None:
118 if not self._path.exists():
119 raise Exception(f"Vivado project file '{self._path!s}' not found.") from FileNotFoundError(f"File '{self._path!s}' not found.")
120
121 try:
122 root = minidom.parse(str(self._path)).documentElement
123 except Exception as ex:
124 raise Exception(f"Couldn't open '{self._path!s}'.") from ex
125
126 self._xprProject = Project(self._path.stem, rootDirectory=self._path.parent)
127 self._ParseRootElement(root)
128
129 def _ParseRootElement(self, root) -> None:
130 for rootNode in root.childNodes:
131 if rootNode.nodeName == "FileSets":
132 self._ParseFileSets(rootNode)
133 break
134
135 def _ParseFileSets(self, filesetsNode) -> None:
136 for fileSetsNode in filesetsNode.childNodes:
137 if fileSetsNode.nodeType == Node.ELEMENT_NODE and fileSetsNode.tagName == "FileSet":
138 self._ParseFileSet(fileSetsNode)
139
140 def _ParseFileSet(self, filesetNode) -> None:
141 filesetName = filesetNode.getAttribute("Name")
142 fileset = FileSet(filesetName, design=self._xprProject.DefaultDesign)
143
144 for fileNode in filesetNode.childNodes:
145 if fileNode.nodeType == Node.ELEMENT_NODE:
146 if fileNode.tagName == "File":
147 self._ParseFile(fileNode, fileset)
148 elif fileNode.nodeType == Node.ELEMENT_NODE and fileNode.tagName == "Config":
149 self._ParseFileSetConfig(fileNode, fileset)
150
151 def _ParseFile(self, fileNode, fileset) -> None:
152 croppedPath = fileNode.getAttribute("Path").replace("$PPRDIR/", "")
153 filePath = Path(croppedPath)
154 if filePath.suffix in (".vhd", ".vhdl"):
155 self._ParseVHDLFile(fileNode, filePath, fileset)
156 elif filePath.suffix == ".xdc":
157 self._ParseXDCFile(fileNode, filePath, fileset)
158 elif filePath.suffix == ".v":
159 self._ParseVerilogFile(fileNode, filePath, fileset)
160 elif filePath.suffix == ".xci":
161 self._ParseXCIFile(fileNode, filePath, fileset)
162 else:
163 self._ParseDefaultFile(fileNode, filePath, fileset)
164
165 def _ParseVHDLFile(self, fileNode, path, fileset) -> None:
166 vhdlFile = VHDLSourceFile(path)
167 fileset.AddFile(vhdlFile)
168 usedInAttr = vhdlFile[UsedInAttribute]
169
170 for childNode in fileNode.childNodes:
171 if childNode.nodeType == Node.ELEMENT_NODE and childNode.tagName == "FileInfo":
172 if childNode.getAttribute("SFType") == "VHDL2008":
173 vhdlFile.VHDLVersion = VHDLVersion.VHDL2008
174 else:
175 vhdlFile.VHDLVersion = VHDLVersion.VHDL93
176
177 for fileAttribute in childNode.childNodes:
178 if fileAttribute.nodeType == Node.ELEMENT_NODE and fileAttribute.tagName == "Attr":
179 if fileAttribute.getAttribute("Name") == "Library":
180 libraryName = fileAttribute.getAttribute("Val")
181 vhdlFile.VHDLLibrary = fileset.GetOrCreateVHDLLibrary(libraryName)
182 elif fileAttribute.getAttribute("Val") == "UsedIn":
183 usedInAttr.append(fileAttribute.getAttribute("Val"))
184
185 def _ParseDefaultFile(self, _, path, fileset) -> None:
186 File(path, fileSet=fileset)
187
188 def _ParseXDCFile(self, _, path, fileset) -> None:
189 XDCConstraintFile(path, fileSet=fileset)
190
191 def _ParseVerilogFile(self, _, path, fileset) -> None:
192 VerilogSourceFile(path, fileSet=fileset)
193
194 def _ParseXCIFile(self, _, path, fileset) -> None:
195 IPCoreInstantiationFile(path, fileSet=fileset)
196
197 def _ParseFileSetConfig(self, fileNode, fileset) -> None:
198 for option in fileNode.childNodes:
199 if option.nodeType == Node.ELEMENT_NODE and option.tagName == "Option":
200 if option.getAttribute("Name") == "TopModule":
201 fileset.TopLevel = option.getAttribute("Val")
202
203
204@export
205class XDCConstraintFile(ConstraintFile, SDCContent):
206 """A Vivado constraint file (Xilinx Design Constraints; ``*.xdc``)."""
207
208 def _registerAttributes(self) -> None:
209 super()._registerAttributes()
210 self._attributes[ScopeToRefAttribute] = None
211 self._attributes[ScopeToCellAttribute] = None
212
213
214@export
215class IPCoreDescriptionFile(XMLFile):
216 pass
217
218
219@export
220class IPCoreInstantiationFile(XMLFile):
221 """A Vivado IP core instantiation file (Xilinx IPCore Instance; ``*.xci``)."""