1 |
4 |
danv |
###############################################################################
|
2 |
|
|
#
|
3 |
|
|
# Copyright (C) 2014
|
4 |
|
|
# ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
|
5 |
|
|
# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
|
6 |
|
|
#
|
7 |
|
|
# This program is free software: you can redistribute it and/or modify
|
8 |
|
|
# it under the terms of the GNU General Public License as published by
|
9 |
|
|
# the Free Software Foundation, either version 3 of the License, or
|
10 |
|
|
# (at your option) any later version.
|
11 |
|
|
#
|
12 |
|
|
# This program is distributed in the hope that it will be useful,
|
13 |
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 |
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15 |
|
|
# GNU General Public License for more details.
|
16 |
|
|
#
|
17 |
|
|
# You should have received a copy of the GNU General Public License
|
18 |
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19 |
|
|
#
|
20 |
|
|
###############################################################################
|
21 |
|
|
|
22 |
|
|
"""HDL configuration for building simulation and synthesis targets.
|
23 |
|
|
|
24 |
|
|
There should be one hdl_buildset_<buildset>.cfg file per buildset somewhere in the
|
25 |
|
|
toolRootDir and at least one hdllib.cfg file somewhere in the libRootDir.
|
26 |
|
|
Every HDL library that is in the libRootDir can be found if it has a hdllib.cfg file.
|
27 |
|
|
Together the hdl_buildset_<buildset>.cfg and hdllib.cfg files contain all the keys and
|
28 |
|
|
values that are sufficient to be able to build the targets for the HDL
|
29 |
|
|
library. The possible targets are:
|
30 |
|
|
|
31 |
|
|
- compile to created the library binaries for simulation
|
32 |
|
|
- synthesize to created an image that can be loaded ion the FPGA
|
33 |
|
|
- verify VHDL test benches in simulation
|
34 |
|
|
- verify Python test cases via the MM control interface in simulation
|
35 |
|
|
- validate Python test cases on hardware via the MM control interface
|
36 |
|
|
|
37 |
|
|
The contents of the cfg files consist of a series of key - value pairs
|
38 |
|
|
that are read into a dictionary as defined in hdl_configfile.py. Whether
|
39 |
|
|
the key is a valid key depends on the application that interprets the
|
40 |
|
|
dictionary.
|
41 |
|
|
|
42 |
|
|
The methods can have the library dictionary or the library name as
|
43 |
|
|
argument. The default arguments are the self.libs.dicts and the
|
44 |
|
|
corresponding self.lib_names. The argument can be a list or a single value.
|
45 |
|
|
Similar the return can be a list or a single value, because a list of one
|
46 |
|
|
element is unlistified.
|
47 |
|
|
|
48 |
|
|
"""
|
49 |
|
|
|
50 |
|
|
import sys
|
51 |
|
|
import fnmatch
|
52 |
|
|
from os import listdir, walk, getenv
|
53 |
|
|
from os.path import expandvars, isabs, join, isfile
|
54 |
|
|
import shutil
|
55 |
|
|
from distutils.dir_util import copy_tree
|
56 |
|
|
from argparse import ArgumentParser
|
57 |
|
|
import collections
|
58 |
|
|
import common_radiohdl as cm
|
59 |
|
|
from configfile import ConfigFile
|
60 |
|
|
from hdl_configfile import HdlBuildset
|
61 |
|
|
from hdl_configtree import HdlLibTree
|
62 |
|
|
|
63 |
|
|
__all__ = ['HdlLibrariesWizard']
|
64 |
|
|
|
65 |
|
|
|
66 |
|
|
class HdlLibrariesWizard:
|
67 |
|
|
|
68 |
|
|
def __init__(self, toolRootDir, toolFileName, libFileName='hdllib.cfg', libFileSections=None):
|
69 |
|
|
"""Get tool dictionary info from toolRootDir and all HDL library dictionary info for it
|
70 |
|
|
|
71 |
|
|
- self.tool.dicts = single dictionary that contains the tool info (only one tool dict in dicts list)
|
72 |
|
|
- self.libs.dicts = list of dictionaries that contains the info of the HDL libraries.
|
73 |
|
|
|
74 |
|
|
The libRootDir parameter is defined in the hdl_buildset_<buildset>.cfg file and is the root directory from where the hdllib.cfg
|
75 |
|
|
files are searched for.
|
76 |
|
|
|
77 |
|
|
- self.lib_names = the library names of self.libs.dicts
|
78 |
|
|
|
79 |
|
|
In parallel to the self.libs.dicts list of dictionaries a list of self.lib_names is created to be able to identify
|
80 |
|
|
a HDL library dict also by its library name. Iherefore it is important that the indexing of parallel lists remains
|
81 |
|
|
intact at all times.
|
82 |
|
|
|
83 |
|
|
- self.technologyNames = the technologyNames parameter is defined in the hdl_buildset_<buildset>.cfg file. All generic HDL
|
84 |
|
|
libraries and these technology specific libraries are kept. If self.technologyNames is:
|
85 |
|
|
[] : Keep all HDL libraries that were found.
|
86 |
|
|
['ip_stratixiv', 'ip_arria10'] : The HDL libraries with a hdl_lib_technology that is not '' or does not match one of the technologies
|
87 |
|
|
in technologyNames are removed from the list of HDL library dictionaries.
|
88 |
|
|
|
89 |
|
|
- self.removed_libs = contains the HDL library dicts that have been removed from self.libs.dicts, because they are for
|
90 |
|
|
a technology that is not within technologyNames.
|
91 |
|
|
|
92 |
|
|
Keep lists of all unavailable library names that were found at the hdl_lib_uses_synth, hdl_lib_uses_ip, hdl_lib_uses_sim and
|
93 |
|
|
hdl_lib_include_ip keys in the self.libs.dicts:
|
94 |
|
|
|
95 |
|
|
- self.unavailable_use_libs = self.unavailable_use_synth_libs + self.unavailable_use_ip_libs + self.unavailable_use_sim_libs
|
96 |
|
|
- self.unavailable_include_ip_libs
|
97 |
|
|
|
98 |
|
|
Unavailable used libraries can be missing for a valid reason when they are not required (e.g. IP for another technology). Being able to
|
99 |
|
|
ignore missing libraries does require that the entities from these libraries are instantiated as components in the VHDL. The difference
|
100 |
|
|
between a removed library and an unavailable library is that for a removed library the HDL config information is still known, whereas
|
101 |
|
|
for an unavailable library it is not. Therefore the library clause names for referred but unavailable HDL libraries are disclosed at the
|
102 |
|
|
'hdl_lib_disclose_library_clause_names' keys of the libraries that use them and kept in a dictionary:
|
103 |
|
|
|
104 |
|
|
- self.disclosed_library_clause_names
|
105 |
|
|
|
106 |
|
|
"""
|
107 |
|
|
print("HdlLibrariesWizard(toolRootDir=%s, toolFileName=%s, libFileName=%s, libFileSections=%s)"
|
108 |
|
|
% (toolRootDir, toolFileName, libFileName, libFileSections))
|
109 |
|
|
self.toolRootDir = toolRootDir # TODO almost obsolete
|
110 |
|
|
|
111 |
|
|
# read the buildset file. This file contains major information about paths, technologies, and so on
|
112 |
|
|
full_buildsetfile_name = "%s/%s" % (toolRootDir, toolFileName)
|
113 |
|
|
buildset_info = HdlBuildset(full_buildsetfile_name)
|
114 |
|
|
buildset_info.resolve_key_references()
|
115 |
|
|
self.buildset = buildset_info.content
|
116 |
|
|
|
117 |
|
|
# HDL library config files
|
118 |
|
|
self.libRootDirs = [expandvars(rootdir) for rootdir in self.buildset['lib_root_dirs'].replace("\t", " ").split(" ")
|
119 |
|
|
if rootdir != '']
|
120 |
|
|
self.libs = HdlLibTree(rootdirs=self.libRootDirs,
|
121 |
|
|
filename=libFileName,
|
122 |
|
|
sections=libFileSections) # library dict files
|
123 |
|
|
if len(self.libs.configfiles) == 0:
|
124 |
|
|
sys.exit('Error : No HDL library config files found')
|
125 |
|
|
print("Found %d hdllib files:" % len(self.libs.configfiles))
|
126 |
|
|
|
127 |
|
|
# Substitute key words occurring in hdllib.cfg files with their value.
|
128 |
|
|
self.substitute_key_words()
|
129 |
|
|
|
130 |
|
|
self.familyNames = self.buildset['family_names'].split()
|
131 |
|
|
print("### self.familyNames = ", self.familyNames)
|
132 |
|
|
|
133 |
|
|
# Keep the generic HDL libraries and remove those that do not match the specified IP technologies
|
134 |
|
|
self.technologyNames = self.buildset['technology_names'].split()
|
135 |
|
|
print("### self.technologyNames = ", self.technologyNames)
|
136 |
|
|
self.removed_libs = {}
|
137 |
|
|
|
138 |
|
|
buildset_files = []
|
139 |
|
|
for root, dirs, files in walk(join(getenv("RADIOHDL_GEAR"), 'config')):
|
140 |
|
|
for name in files:
|
141 |
|
|
if fnmatch.fnmatch(name, 'hdl_buildset_*.cfg'):
|
142 |
|
|
buildset_files.append(join(root, name))
|
143 |
|
|
all_buildset_names = [bs[bs.rfind('_')+1:bs.rfind('.')] for bs in buildset_files]
|
144 |
|
|
# print(all_buildset_names)
|
145 |
|
|
|
146 |
|
|
for cfglib_name in list(self.libs.configfiles.keys()):
|
147 |
|
|
techname = self.libs.configfiles[cfglib_name]['hdl_lib_technology']
|
148 |
|
|
if (techname != '' and techname not in self.technologyNames):
|
149 |
|
|
# keep the removed libs we need the content of those libs later.
|
150 |
|
|
self.removed_libs[cfglib_name] = self.libs.configfiles[cfglib_name]
|
151 |
|
|
else:
|
152 |
|
|
# accept only projects for active buildset_name
|
153 |
|
|
# this method asume the hdl_lib_name is starting with the buildset_name and ending with
|
154 |
|
|
# the project name seperated by a '_'
|
155 |
|
|
# for example unb2b_<project_name>
|
156 |
|
|
for buildset_name in sorted(all_buildset_names)[::-1]:
|
157 |
|
|
if buildset_name == self.buildset['buildset_name']:
|
158 |
|
|
continue
|
159 |
|
|
if buildset_name+'_' in self.libs.configfiles[cfglib_name]['hdl_lib_name']:
|
160 |
|
|
# keep the removed libs we need the content of those libs later.
|
161 |
|
|
self.removed_libs[cfglib_name] = self.libs.configfiles[cfglib_name]
|
162 |
|
|
|
163 |
|
|
self.libs.remove_files_from_tree(list(self.removed_libs.keys()))
|
164 |
|
|
print(len(self.removed_libs), "REMOVED LIBS:", sorted(self.removed_libs))
|
165 |
|
|
|
166 |
|
|
# Keep list of used HDL library names
|
167 |
|
|
self.lib_names = list(self.libs.configfiles.keys())
|
168 |
|
|
print(len(self.lib_names), "KEPT LIBS:", sorted(self.lib_names))
|
169 |
|
|
|
170 |
|
|
# No need to check for duplicates since HdlLibTree did that already.
|
171 |
|
|
|
172 |
|
|
# create dictionary of library names with library clause names that are disclosed at the 'hdl_lib_disclose_library_clause_names' keys.
|
173 |
|
|
self.disclosed_library_clause_names = {}
|
174 |
|
|
for lib in list(self.libs.configfiles.values()):
|
175 |
|
|
if lib.get_value('hdl_lib_disclose_library_clause_names'):
|
176 |
|
|
key_values = lib.get_value('hdl_lib_disclose_library_clause_names').split()
|
177 |
|
|
lib_name = key_values[0::2]
|
178 |
|
|
lib_clause_name = key_values[1::2]
|
179 |
|
|
lib_pairs = list(zip(lib_name, lib_clause_name))
|
180 |
|
|
# No need to check for duplicate lib_names, because a dictionary cannot have duplicate keys
|
181 |
|
|
for lp in lib_pairs:
|
182 |
|
|
self.disclosed_library_clause_names[lp[0]] = lp[1]
|
183 |
|
|
# Check whether the used libraries from the self.libs.dicts keys indeed exist, otherwise remove them from the dictionary key
|
184 |
|
|
# string and add the used library name to the list of unavailable used library names and check that the library use clause
|
185 |
|
|
# name was disclosed at the 'hdl_lib_disclose_library_clause_names' key. In this way other methods do not have to check a
|
186 |
|
|
# used library does indeed exist.
|
187 |
|
|
self.unavailable_use_synth_libs = []
|
188 |
|
|
self.unavailable_use_ip_libs = []
|
189 |
|
|
self.unavailable_use_sim_libs = []
|
190 |
|
|
self.unavailable_include_ip_libs = []
|
191 |
|
|
for lib in list(self.libs.configfiles.values()):
|
192 |
|
|
use_synth_libs = []
|
193 |
|
|
use_ip_libs = []
|
194 |
|
|
use_sim_libs = []
|
195 |
|
|
include_ip_libs = []
|
196 |
|
|
if lib.get_value('hdl_lib_uses_synth'):
|
197 |
|
|
use_synth_libs = lib.get_value('hdl_lib_uses_synth').split()
|
198 |
|
|
if lib.get_value('hdl_lib_uses_ip'):
|
199 |
|
|
use_ip_libs += lib.get_value('hdl_lib_uses_ip').split()
|
200 |
|
|
if lib.get_value('hdl_lib_uses_sim'):
|
201 |
|
|
use_sim_libs += lib.get_value('hdl_lib_uses_sim').split()
|
202 |
|
|
if lib.get_value('hdl_lib_include_ip'):
|
203 |
|
|
include_ip_libs = lib.get_value('hdl_lib_include_ip').split()
|
204 |
|
|
for use_name in use_synth_libs:
|
205 |
|
|
if (use_name not in self.lib_names) and (use_name not in self.removed_libs):
|
206 |
|
|
lib['hdl_lib_uses_synth'] = cm.remove_from_list_string(lib['hdl_lib_uses_synth'], use_name)
|
207 |
|
|
self.unavailable_use_synth_libs.append(use_name)
|
208 |
|
|
if use_name not in list(self.disclosed_library_clause_names.keys()):
|
209 |
|
|
sys.exit("Error : Unavailable library %s at 'hdl_lib_uses_synth' key is not disclosed at 'hdl_lib_disclose_library_clause_names' key in library %s" % (use_name, lib_name))
|
210 |
|
|
for use_name in use_ip_libs:
|
211 |
|
|
if (use_name not in self.lib_names) and (use_name not in self.removed_libs):
|
212 |
|
|
lib['hdl_lib_uses_ip'] = cm.remove_from_list_string(lib['hdl_lib_uses_ip'], use_name)
|
213 |
|
|
self.unavailable_use_ip_libs.append(use_name)
|
214 |
|
|
if use_name not in list(self.disclosed_library_clause_names.keys()):
|
215 |
|
|
sys.exit("Error : Unavailable library %s at 'hdl_lib_uses_ip' key is not disclosed at 'hdl_lib_disclose_library_clause_names' key in library %s" % (use_name, lib_name))
|
216 |
|
|
for use_name in use_sim_libs:
|
217 |
|
|
if (use_name not in self.lib_names) and (use_name not in self.removed_libs):
|
218 |
|
|
lib['hdl_lib_uses_sim'] = cm.remove_from_list_string(lib['hdl_lib_uses_sim'], use_name)
|
219 |
|
|
self.unavailable_use_sim_libs.append(use_name)
|
220 |
|
|
if use_name not in list(self.disclosed_library_clause_names.keys()):
|
221 |
|
|
sys.exit("Error : Unavailable library %s at 'hdl_lib_uses_sim' key is not disclosed at 'hdl_lib_disclose_library_clause_names' key in library %s" % (use_name, lib_name))
|
222 |
|
|
for use_name in include_ip_libs:
|
223 |
|
|
if (use_name not in self.lib_names) and (use_name not in self.removed_libs):
|
224 |
|
|
lib['hdl_lib_include_ip'] = cm.remove_from_list_string(lib['hdl_lib_include_ip'], use_name)
|
225 |
|
|
self.unavailable_include_ip_libs.append(use_name)
|
226 |
|
|
if use_name not in list(self.disclosed_library_clause_names.keys()):
|
227 |
|
|
sys.exit("Error : Unavailable library %s at 'hdl_lib_include_ip' key in library %s is not disclosed at any 'hdl_lib_disclose_library_clause_names' key" % (use_name, lib_name))
|
228 |
|
|
# remove all duplicates from the list
|
229 |
|
|
self.unavailable_use_synth_libs = cm.unique(self.unavailable_use_synth_libs)
|
230 |
|
|
self.unavailable_use_ip_libs = cm.unique(self.unavailable_use_ip_libs)
|
231 |
|
|
self.unavailable_use_sim_libs = cm.unique(self.unavailable_use_sim_libs)
|
232 |
|
|
self.unavailable_include_ip_libs = cm.unique(self.unavailable_include_ip_libs) # list of include_ip_use_libs
|
233 |
|
|
self.unavailable_use_libs = self.unavailable_use_synth_libs + self.unavailable_use_ip_libs + self.unavailable_use_sim_libs
|
234 |
|
|
self.unavailable_use_libs = cm.unique(self.unavailable_use_libs) # aggregate list of use_*_libs
|
235 |
|
|
|
236 |
|
|
# The Key value pairs defined in hdltool<buildset>.cfg can be used in hdllib.cfg files. See hdllib.cfg of technology library
|
237 |
|
|
def substitute_key_words(self):
|
238 |
|
|
for lib in list(self.libs.configfiles.values()):
|
239 |
|
|
for lib_key, lib_value in list(lib.content.items()):
|
240 |
|
|
for tool_key, tool_value in list(self.buildset.items()):
|
241 |
|
|
tool_key_string = '<%s>' % tool_key
|
242 |
|
|
if tool_key_string in lib_value:
|
243 |
|
|
lib[lib_key] = lib_value.replace(tool_key_string, tool_value)
|
244 |
|
|
|
245 |
|
|
def check_library_names(self, check_lib_names, lib_names=None):
|
246 |
|
|
"""Check that HDL library names exists within the list of library names, if not then exit with Error message.
|
247 |
|
|
The list of library names can be specified via the argument lib_names, or it defaults to the list of
|
248 |
|
|
self.lib_names of HDL libraries that were found in the toolRootDir for the libFileName of this object.
|
249 |
|
|
"""
|
250 |
|
|
if lib_names is None:
|
251 |
|
|
lib_names = self.lib_names
|
252 |
|
|
for check_lib_name in cm.listify(check_lib_names):
|
253 |
|
|
if check_lib_name not in cm.listify(lib_names):
|
254 |
|
|
sys.exit('Error : Unknown HDL library name %s found with %s' % (check_lib_name, cm.method_name()))
|
255 |
|
|
|
256 |
|
|
def get_used_libs(self, build_type, lib_dict, arg_include_ip_libs=[]):
|
257 |
|
|
"""Get the list of used HDL libraries from the lib_dict that this library directly depends on, so only at this HDL library hierachy level.
|
258 |
|
|
|
259 |
|
|
Which libraries are actually used depends on the build_type. The build_type can be:
|
260 |
|
|
'' uses all libraries from 'hdl_lib_uses_synth', 'hdl_lib_uses_ip' and 'hdl_lib_uses_sim' in the lib_dict
|
261 |
|
|
'sim' uses all libraries from 'hdl_lib_uses_synth', 'hdl_lib_uses_ip' and 'hdl_lib_uses_sim' in the lib_dict
|
262 |
|
|
'synth' uses all libraries from 'hdl_lib_uses_synth' in the lib_dict and from 'hdl_lib_uses_ip' it only uses the IP
|
263 |
|
|
libraries that are mentioned in the local 'hdl_lib_include_ip' key or in the global arg_include_ip_libs
|
264 |
|
|
|
265 |
|
|
The 'hdl_lib_uses_*' keys all appear locally in the same hdllib.cfg file. The 'hdl_lib_include_ip' key appears at this level or at
|
266 |
|
|
a higher level (design) library hdllib.cfg file to select which of all available 'hdl_lib_uses_ip' IP libraries will actually be
|
267 |
|
|
used in the design. The 'hdl_lib_include_ip' cannot appear in a lower level hdllib.cfg, because a lower level HDL library cannot
|
268 |
|
|
depend on a higher level HDL library. Therefore the IP libraries that need to be included from 'hdl_lib_uses_ip' will be known in
|
269 |
|
|
include_ip_libs.
|
270 |
|
|
"""
|
271 |
|
|
# Get local library dependencies
|
272 |
|
|
use_synth_libs = []
|
273 |
|
|
use_ip_libs = []
|
274 |
|
|
use_sim_libs = []
|
275 |
|
|
include_ip_libs = []
|
276 |
|
|
if 'hdl_lib_uses_synth' in lib_dict.content:
|
277 |
|
|
use_synth_libs = lib_dict['hdl_lib_uses_synth'].split()
|
278 |
|
|
if 'hdl_lib_uses_ip' in lib_dict.content:
|
279 |
|
|
use_ip_libs += lib_dict['hdl_lib_uses_ip'].split()
|
280 |
|
|
if 'hdl_lib_uses_sim' in lib_dict.content:
|
281 |
|
|
use_sim_libs += lib_dict['hdl_lib_uses_sim'].split()
|
282 |
|
|
if 'hdl_lib_include_ip' in lib_dict.content:
|
283 |
|
|
include_ip_libs = lib_dict['hdl_lib_include_ip'].split()
|
284 |
|
|
|
285 |
|
|
# Append include_ip_libs from this level to the global list of arg_include_ip_libs
|
286 |
|
|
include_ip_libs = list(arg_include_ip_libs) + include_ip_libs
|
287 |
|
|
|
288 |
|
|
# Get the actually use_libs for lib_dict
|
289 |
|
|
use_libs = use_synth_libs + use_ip_libs + use_sim_libs # default include all IP, so ignore include_ip_libs
|
290 |
|
|
if build_type == 'sim':
|
291 |
|
|
use_libs = use_synth_libs + use_ip_libs + use_sim_libs # for simulation included all IP, so ignore include_ip_libs
|
292 |
|
|
if build_type == 'synth':
|
293 |
|
|
use_libs = use_synth_libs
|
294 |
|
|
# For synthesis only keep the local use_ip_libs if it is mentioned in the global include_ip_libs. Vice versa also only
|
295 |
|
|
# include the global include_ip_libs if they appear in a local use_ip_libs, to avoid that an IP library that is mentioned
|
296 |
|
|
# in the global include_ip_libs gets included while it is not instantiated anywhere in the design.
|
297 |
|
|
for ip_lib in use_ip_libs:
|
298 |
|
|
if ip_lib in include_ip_libs:
|
299 |
|
|
use_libs += [ip_lib]
|
300 |
|
|
|
301 |
|
|
# Remove any duplicate library names from the lists
|
302 |
|
|
use_libs = cm.unique(use_libs)
|
303 |
|
|
include_ip_libs = cm.unique(include_ip_libs)
|
304 |
|
|
|
305 |
|
|
# Remove libraries that are in the removed technologies (use list() to take copy)
|
306 |
|
|
for use_name in list(use_libs):
|
307 |
|
|
if use_name in self.removed_libs:
|
308 |
|
|
use_libs.remove(use_name)
|
309 |
|
|
for use_name in list(include_ip_libs):
|
310 |
|
|
if use_name in self.removed_libs:
|
311 |
|
|
include_ip_libs.remove(use_name)
|
312 |
|
|
|
313 |
|
|
return use_libs, include_ip_libs
|
314 |
|
|
|
315 |
|
|
def derive_all_use_libs(self, build_type, lib_name, arg_include_ip_libs=[]):
|
316 |
|
|
"""Recursively derive a complete list of all HDL libraries that the specified HDL lib_name library depends on, so from this
|
317 |
|
|
HDL library down the entire hierachy.
|
318 |
|
|
|
319 |
|
|
The hdl_lib_uses_* key only needs to contain all libraries that are declared at the VHDL LIBRARY clauses of the
|
320 |
|
|
source files in this VHDL library. This derive_all_use_libs() will recursively find all deeper level VHDL libraries as well.
|
321 |
|
|
|
322 |
|
|
The arg_include_ip_libs selects the IP library to keep from 'hdl_lib_uses_ip'. The include_ip_libs is passed on
|
323 |
|
|
through the recursion hierarchy via arg_include_ip_libs to ensure that the from the top level library down all
|
324 |
|
|
multiple choice IP libraries in 'hdl_lib_uses_ip' that need to be included are indeed included. The multiple choice IP
|
325 |
|
|
libraries in 'hdl_lib_uses_ip' that are not in include_ip_libs are excluded.
|
326 |
|
|
|
327 |
|
|
Note:
|
328 |
|
|
. Only the generic HDL libraries and the technology specific libraries that match self.technologyNames are used,
|
329 |
|
|
because the other technology libraries have been removed from self.libs.dicts already at __init__() and from the
|
330 |
|
|
library dependency lists in get_used_libs()
|
331 |
|
|
. If Python breaks because recursion limit is reached, then two hdllib.cfg probably mutually use eachother which is
|
332 |
|
|
not allowed.
|
333 |
|
|
"""
|
334 |
|
|
# use list() to take local copy, to avoid next that default empty list argument arg_include_ip_libs=[] gets disturbed
|
335 |
|
|
include_ip_libs = list(arg_include_ip_libs)
|
336 |
|
|
if lib_name in self.lib_names:
|
337 |
|
|
all_use_libs = [lib_name]
|
338 |
|
|
lib_dict = self.libs.configfiles[lib_name]
|
339 |
|
|
use_libs, include_ip_libs = self.get_used_libs(build_type, lib_dict, include_ip_libs)
|
340 |
|
|
|
341 |
|
|
for use_lib in use_libs:
|
342 |
|
|
if use_lib not in all_use_libs:
|
343 |
|
|
all_use_libs.append(use_lib)
|
344 |
|
|
# use recursion to include all used libs
|
345 |
|
|
all_use_libs += self.derive_all_use_libs(build_type, use_lib, include_ip_libs)
|
346 |
|
|
# remove all duplicates from the list
|
347 |
|
|
return cm.unique(all_use_libs)
|
348 |
|
|
else:
|
349 |
|
|
sys.exit('Error : Unknown HDL library name %s in %s()' % (lib_name, cm.method_name()))
|
350 |
|
|
|
351 |
|
|
def derive_lib_order(self, build_type, lib_name, lib_names=None):
|
352 |
|
|
"""Derive the dependency order for all HDL libraries in lib_names that HDL library lib_name depends on.
|
353 |
|
|
"""
|
354 |
|
|
if lib_names is None:
|
355 |
|
|
# At first entry derive the list of all HDL libraries that lib_name depends on
|
356 |
|
|
lib_names = self.derive_all_use_libs(build_type, lib_name)
|
357 |
|
|
|
358 |
|
|
# Derive the order of all HDL libraries that lib_name depends on, start with the order of lib_names
|
359 |
|
|
lib_dicts = self.libs.get_configfiles('hdl_lib_name', values=lib_names)
|
360 |
|
|
# use list() to take local copy to avoid modifying list order of self.lib_names which matches self.libs.dicts list order
|
361 |
|
|
lib_order = list(lib_names)
|
362 |
|
|
for lib_dict in lib_dicts:
|
363 |
|
|
lib_name = lib_dict['hdl_lib_name']
|
364 |
|
|
use_libs, _ = self.get_used_libs('', lib_dict, [])
|
365 |
|
|
for use_lib in use_libs:
|
366 |
|
|
if use_lib in lib_names:
|
367 |
|
|
if lib_order.index(use_lib) > lib_order.index(lib_name):
|
368 |
|
|
lib_order.remove(use_lib)
|
369 |
|
|
lib_order.insert(lib_order.index(lib_name), use_lib) # move used lib to just before this lib
|
370 |
|
|
# use recursion to keep on reordering the lib_order until it is stable
|
371 |
|
|
if lib_names != lib_order:
|
372 |
|
|
lib_order = self.derive_lib_order(build_type, lib_name, lib_order)
|
373 |
|
|
return lib_order
|
374 |
|
|
|
375 |
|
|
def get_lib_dicts_from_lib_names(self, lib_names=None):
|
376 |
|
|
"""Get list the HDL libraries lib_dicts from list of HDL libraries lib_names and preseve the library order.
|
377 |
|
|
"""
|
378 |
|
|
if lib_names is None:
|
379 |
|
|
lib_names = self.lib_names
|
380 |
|
|
|
381 |
|
|
# Cannot use:
|
382 |
|
|
# lib_dicts = self.libs.get_configfiles('hdl_lib_name', values=lib_names)
|
383 |
|
|
# because then the order of self.libs.dicts is used
|
384 |
|
|
lib_dicts = []
|
385 |
|
|
for lib_name in cm.listify(lib_names):
|
386 |
|
|
lib_dicts.append(self.libs.configfiles[lib_name])
|
387 |
|
|
return lib_dicts
|
388 |
|
|
|
389 |
|
|
def get_lib_names_from_lib_dicts(self, lib_dicts=None):
|
390 |
|
|
"""Get list the HDL libraries lib_names from list of HDL libraries lib_dicts and preseve the library order.
|
391 |
|
|
"""
|
392 |
|
|
lib_names = self.libs.get_key_values('hdl_lib_name', lib_dicts)
|
393 |
|
|
return lib_names
|
394 |
|
|
|
395 |
|
|
def get_tool_build_dir(self, build_type):
|
396 |
|
|
"""Get the central tool build directory.
|
397 |
|
|
|
398 |
|
|
The build_type can be:
|
399 |
|
|
'sim' uses the 'sim_tool_name' key in the self.buildset
|
400 |
|
|
'synth' uses the 'synth_tool_name' key in the self.buildset
|
401 |
|
|
When another name is used that name is used directly as toolname in the construction of the path.
|
402 |
|
|
|
403 |
|
|
The function returns a tuple with the following four components:
|
404 |
|
|
- the absolute path to the central main build directory
|
405 |
|
|
- the buildset_name key value as subdirectory
|
406 |
|
|
- the toolname as subdirectory (derived from *_tool_name or the given value of 'build_type')
|
407 |
|
|
- project_deeper_subdir. See explanation below.
|
408 |
|
|
|
409 |
|
|
The project file will be located in the build dir or at some levels deeper in the build dir.
|
410 |
|
|
These optional extra subdirectory levels allow for relative file reference from project file
|
411 |
|
|
location. This is useful to be able to keep memory initialisation files in the library build
|
412 |
|
|
directory that are referred to using some fixed ../../ path in the HDL code.
|
413 |
|
|
- project_deeper_subdir = '' when project_dir_depth_<build_type> = 0 or not in buildset
|
414 |
|
|
- project_deeper_subdir = 'p/' when project_dir_depth_<build_type> = 1
|
415 |
|
|
- project_deeper_subdir = 'p/p/' when project_dir_depth_<build_type> = 2,
|
416 |
|
|
- project_deeper_subdir = 'p/p/p/' when project_dir_depth_<build_type> = 3, etc
|
417 |
|
|
"""
|
418 |
|
|
# Determine build_maindir
|
419 |
|
|
build_maindir = expandvars('${RADIOHDL_BUILD_DIR}')
|
420 |
|
|
if not isabs(build_maindir):
|
421 |
|
|
sys.exit('Error : The build_dir value must be an absolute path')
|
422 |
|
|
|
423 |
|
|
# Determine build_buildset_dir
|
424 |
|
|
build_buildset_dir = self.buildset['buildset_name']
|
425 |
|
|
|
426 |
|
|
# Determine build_tooldir
|
427 |
|
|
tool_name_key = build_type + '_tool_name'
|
428 |
|
|
if tool_name_key in self.buildset:
|
429 |
|
|
build_tooldir = self.buildset[tool_name_key]
|
430 |
|
|
else:
|
431 |
|
|
build_tooldir = build_type
|
432 |
|
|
|
433 |
|
|
# Determine project_deeper_subdir
|
434 |
|
|
project_dir_depth_key = 'project_dir_depth_' + build_type
|
435 |
|
|
if project_dir_depth_key not in self.buildset:
|
436 |
|
|
project_deeper_subdir = ''
|
437 |
|
|
else:
|
438 |
|
|
project_deeper_subdir = 'p/' * int(self.buildset[project_dir_depth_key])
|
439 |
|
|
|
440 |
|
|
return build_maindir, build_buildset_dir, build_tooldir, project_deeper_subdir
|
441 |
|
|
|
442 |
|
|
def get_lib_build_dirs(self, build_type, lib_dicts=None):
|
443 |
|
|
"""Get the subdirectories within the central tool build directory for all HDL libraries in the specified list of lib_dicts.
|
444 |
|
|
|
445 |
|
|
The build_type can be:
|
446 |
|
|
'sim' uses the 'sim_tool_name' key in the self.buildset
|
447 |
|
|
'synth' uses the 'synth_tool_name' key in the self.buildset
|
448 |
|
|
|
449 |
|
|
The build dir key value must be an absolute directory path. The lib build dir consists of
|
450 |
|
|
- the absolute path to the central main build directory
|
451 |
|
|
- the buildset_name key value as subdirectory
|
452 |
|
|
- the tool_name_key value as subdirectory
|
453 |
|
|
- the library name as library subdirectory
|
454 |
|
|
- zero or more extra subdirectory levels to allow for relative file reference from project file location
|
455 |
|
|
"""
|
456 |
|
|
if lib_dicts is None:
|
457 |
|
|
lib_dicts = list(self.libs.configfiles.values())
|
458 |
|
|
build_maindir, build_buildset_dir, build_tooldir, project_deeper_subdir = self.get_tool_build_dir(build_type)
|
459 |
|
|
build_dirs = []
|
460 |
|
|
for lib_dict in cm.listify(lib_dicts):
|
461 |
|
|
lib_name = lib_dict['hdl_lib_name']
|
462 |
|
|
build_dirs.append(join(build_maindir, build_buildset_dir, build_tooldir, lib_name, project_deeper_subdir)) # central build main directory with subdirectory per library
|
463 |
|
|
return cm.unlistify(build_dirs)
|
464 |
|
|
|
465 |
|
|
def create_lib_order_files(self, build_type, lib_names=None):
|
466 |
|
|
"""Create the compile order file '<lib_name>_lib_order.txt' for all HDL libraries in the specified list of lib_names.
|
467 |
|
|
|
468 |
|
|
The file is stored in the sim build directory of the HDL library.
|
469 |
|
|
The file is read by commands.do in Modelsim to avoid having to derive the library compile order in TCL.
|
470 |
|
|
"""
|
471 |
|
|
if lib_names is None:
|
472 |
|
|
lib_names = self.lib_names
|
473 |
|
|
|
474 |
|
|
lib_dicts = self.libs.get_configfiles(key='hdl_lib_name', values=lib_names)
|
475 |
|
|
for lib_dict in lib_dicts:
|
476 |
|
|
lib_name = lib_dict['hdl_lib_name']
|
477 |
|
|
lib_order = self.derive_lib_order(build_type, lib_name)
|
478 |
|
|
file_name = lib_name + '_lib_order.txt'
|
479 |
|
|
file_path = self.get_lib_build_dirs('sim', lib_dicts=lib_dict)
|
480 |
|
|
cm.mkdir(file_path)
|
481 |
|
|
filePathName = join(file_path, file_name)
|
482 |
|
|
with open(filePathName, 'w') as fp:
|
483 |
|
|
for lib in lib_order:
|
484 |
|
|
fp.write('%s ' % lib)
|
485 |
|
|
print("Created {} lib-order files".format(len(lib_dicts)))
|
486 |
|
|
|
487 |
|
|
# Methods to create sub directories at various levels in the build directory as defined in HDL tool config file
|
488 |
|
|
def create_sub_directory_in_build_main_dir(self, build_type, subdir_name):
|
489 |
|
|
"""Create <subdir_name>/ in the central <build_main>/ directory
|
490 |
|
|
"""
|
491 |
|
|
build_maindir, build_buildset_dir, build_tooldir, project_deeper_subdir = self.get_tool_build_dir(build_type)
|
492 |
|
|
subdir_path = join(build_maindir, subdir_name)
|
493 |
|
|
cm.mkdir(subdir_path)
|
494 |
|
|
|
495 |
|
|
def create_sub_directory_in_build_buildset_dir(self, build_type, subdir_name):
|
496 |
|
|
"""Create <subdir_name>/ in the central <build_main>/<build_buildset_dir>/ directory.
|
497 |
|
|
"""
|
498 |
|
|
build_maindir, build_buildset_dir, build_tooldir, project_deeper_subdir = self.get_tool_build_dir(build_type)
|
499 |
|
|
subdir_path = join(build_maindir, build_buildset_dir, subdir_name)
|
500 |
|
|
cm.mkdir(subdir_path)
|
501 |
|
|
|
502 |
|
|
def create_sub_directory_in_build_tool_dir(self, build_type, subdir_name):
|
503 |
|
|
"""Create <subdir_name>/ in the central <build_main>/<build_buildset_dir>/<build_tooldir>/ directory.
|
504 |
|
|
"""
|
505 |
|
|
build_maindir, build_buildset_dir, build_tooldir, project_deeper_subdir = self.get_tool_build_dir(build_type)
|
506 |
|
|
subdir_path = join(build_maindir, build_buildset_dir, build_tooldir, subdir_name)
|
507 |
|
|
cm.mkdir(subdir_path)
|
508 |
|
|
|
509 |
|
|
def create_sub_directory_in_build_lib_dir(self, build_type, subdir_name, lib_names=None):
|
510 |
|
|
"""Create <subdir_name>/ in project local build directory <lib_name>/ for all HDL libraries in the specified list of lib_names.
|
511 |
|
|
"""
|
512 |
|
|
if lib_names is None:
|
513 |
|
|
lib_names = self.lib_names
|
514 |
|
|
lib_dicts = self.libs.get_configfiles('hdl_lib_name', values=lib_names)
|
515 |
|
|
for lib_dict in lib_dicts:
|
516 |
|
|
lib_path = self.get_lib_build_dirs('sim', lib_dicts=lib_dict)
|
517 |
|
|
subdir_path = join(lib_path, subdir_name)
|
518 |
|
|
cm.mkdir(subdir_path)
|
519 |
|
|
print("Created {} subdirectories".format(len(lib_dicts)))
|
520 |
|
|
|
521 |
|
|
def copy_files(self, build_type, lib_names=None):
|
522 |
|
|
"""
|
523 |
|
|
Copy all source directories and source files listed at the <tool_name>_copy_files key.
|
524 |
|
|
The build_type selects the <tool_name>_copy_files key using the <build_type>_tool_name key value
|
525 |
|
|
from the hdl_buildset_<buildset>.cfg.
|
526 |
|
|
The <tool_name>_copy_files key expects a source and a destination pair per listed directory or file:
|
527 |
|
|
- The sources need to be specified with absolute path or relative to the HDL library source directory
|
528 |
|
|
where the hdllib.cfg is stored
|
529 |
|
|
- The destinations need to be specified with absolute path or relative to HDL library build directory
|
530 |
|
|
where the project file (e.g. mpf, qpf) gets stored
|
531 |
|
|
|
532 |
|
|
Arguments:
|
533 |
|
|
- lib_names : zero or more HDL libraries
|
534 |
|
|
"""
|
535 |
|
|
if lib_names is None:
|
536 |
|
|
lib_names = self.lib_names
|
537 |
|
|
|
538 |
|
|
lib_dicts = self.libs.get_configfiles(key='hdl_lib_name', values=lib_names)
|
539 |
|
|
tool_name_key = build_type + '_tool_name'
|
540 |
|
|
tool_name_value = self.buildset[tool_name_key]
|
541 |
|
|
tool_name_copy_key = tool_name_value + '_copy_files'
|
542 |
|
|
lib_count = 0
|
543 |
|
|
dir_count = 0
|
544 |
|
|
file_count = 0
|
545 |
|
|
for lib_dict in lib_dicts:
|
546 |
|
|
if tool_name_copy_key in lib_dict.content:
|
547 |
|
|
lib_count += 1
|
548 |
|
|
lib_path = lib_dict.location
|
549 |
|
|
build_dir_path = self.get_lib_build_dirs(build_type, lib_dicts=lib_dict)
|
550 |
|
|
cm.mkdir(build_dir_path)
|
551 |
|
|
key_values = lib_dict[tool_name_copy_key].split()
|
552 |
|
|
sources = key_values[0::2]
|
553 |
|
|
destinations = key_values[1::2]
|
554 |
|
|
file_io = list(zip(sources, destinations))
|
555 |
|
|
for fpn_io in file_io:
|
556 |
7 |
danv |
try:
|
557 |
|
|
sourcePathName = cm.expand_file_path_name(fpn_io[0], lib_path)
|
558 |
|
|
destinationPath = cm.expand_file_path_name(fpn_io[1], build_dir_path)
|
559 |
|
|
# print("Copy '{}'' to '{}'".format(sourcePathName, destinationPath))
|
560 |
|
|
if isfile(sourcePathName):
|
561 |
|
|
shutil.copy(sourcePathName, destinationPath) # copy file
|
562 |
|
|
file_count += 1
|
563 |
|
|
else:
|
564 |
|
|
copy_tree(sourcePathName, destinationPath) # copy directory tree (will create new destinationPath directory)
|
565 |
|
|
dir_count += 1
|
566 |
|
|
except:
|
567 |
|
|
print("Could not copy source {} to desination {}".format(sourcePathName,destinationPath))
|
568 |
4 |
danv |
print("Copied {} files and {} directories for {} libraries".format(file_count, dir_count, lib_count))
|
569 |
|
|
|
570 |
|
|
|
571 |
|
|
if __name__ == '__main__':
|
572 |
|
|
# Parse command line arguments
|
573 |
|
|
buildsetSelect = sorted([cfgfile[13:-4] for cfgfile in listdir(expandvars('$RADIOHDL_CONFIG'))
|
574 |
|
|
if cfgfile.startswith("hdl_buildset_") and cfgfile.endswith(".cfg")])
|
575 |
|
|
argparser = ArgumentParser(description='Hdl_config shows several selections of all of your hdllib.cfg files.')
|
576 |
|
|
argparser.add_argument('buildset', help='choose buildset %s' % (buildsetSelect))
|
577 |
|
|
argparser.add_argument('--toplib', default=None, required=False, help='top library to show more information about.')
|
578 |
|
|
args = argparser.parse_args()
|
579 |
|
|
|
580 |
|
|
# check arguments
|
581 |
|
|
if args.buildset not in buildsetSelect:
|
582 |
|
|
print('buildset %s is not supported' % args.buildset)
|
583 |
|
|
print("Supported buildset are:", buildsetSelect)
|
584 |
|
|
sys.exit(1)
|
585 |
|
|
args.buildsetFile = 'hdl_buildset_' + args.buildset + '.cfg'
|
586 |
|
|
|
587 |
|
|
# Read the dictionary info from all HDL tool and library configuration files in the current directory and the sub directories
|
588 |
|
|
hdl = HdlLibrariesWizard(toolRootDir=expandvars('${RADIOHDL_CONFIG}'),
|
589 |
|
|
toolFileName=args.buildsetFile,
|
590 |
|
|
libFileName='hdllib.cfg')
|
591 |
|
|
|
592 |
|
|
print('#')
|
593 |
|
|
print('# HdlLibrariesWizard:')
|
594 |
|
|
print('#')
|
595 |
|
|
for libname in list(hdl.libs.configfiles.keys()):
|
596 |
|
|
print("\n", libname)
|
597 |
|
|
libinfo = hdl.libs.configfiles[libname]
|
598 |
|
|
for k, v in libinfo.content.items():
|
599 |
|
|
print(k, '=', v)
|
600 |
|
|
print('')
|
601 |
|
|
|
602 |
|
|
print('')
|
603 |
|
|
print('Library paths :')
|
604 |
|
|
for libname in list(hdl.libs.configfiles.keys()):
|
605 |
|
|
print(' ', hdl.libs.configfiles[libname].location)
|
606 |
|
|
|
607 |
|
|
print('')
|
608 |
|
|
print('Library file names :"')
|
609 |
|
|
for libname in list(hdl.libs.configfiles.keys()):
|
610 |
|
|
print(' ', libname)
|
611 |
|
|
|
612 |
|
|
print('')
|
613 |
|
|
print('Library section headers :')
|
614 |
|
|
for libname, libinfo in hdl.libs.configfiles.items():
|
615 |
|
|
print(' %-52s : %s' % (libname, libinfo['section_headers']))
|
616 |
|
|
|
617 |
|
|
print('')
|
618 |
|
|
print('Build directories for simulation:')
|
619 |
|
|
for build_dir in hdl.get_lib_build_dirs('sim'):
|
620 |
|
|
print(' ', build_dir)
|
621 |
|
|
|
622 |
|
|
print('')
|
623 |
|
|
print('Build directories for synthesis:')
|
624 |
|
|
for build_dir in hdl.get_lib_build_dirs('synth'):
|
625 |
|
|
print(' ', build_dir)
|
626 |
|
|
|
627 |
|
|
print('')
|
628 |
|
|
print('Removed library names = \n', list(hdl.removed_libs.keys()))
|
629 |
|
|
|
630 |
|
|
print('')
|
631 |
|
|
print("Unavailable library names in any 'hdl_lib_uses_synth' key = \n", hdl.unavailable_use_synth_libs)
|
632 |
|
|
print("Unavailable library names in any 'hdl_lib_uses_ip' key = \n", hdl.unavailable_use_ip_libs)
|
633 |
|
|
print("Unavailable library names in any 'hdl_lib_uses_sim' key = \n", hdl.unavailable_use_sim_libs)
|
634 |
|
|
print("Unavailable library names in any 'hdl_lib_uses_*' key = \n", hdl.unavailable_use_libs)
|
635 |
|
|
print('')
|
636 |
|
|
print("Unavailable library names in any 'hdl_lib_include_ip' key = \n", hdl.unavailable_include_ip_libs)
|
637 |
|
|
|
638 |
|
|
print('')
|
639 |
|
|
print("Used library clause names that are explicitly disclosed at the 'hdl_lib_disclose_library_clause_names' keys:")
|
640 |
|
|
for key in list(hdl.disclosed_library_clause_names.keys()):
|
641 |
|
|
print(' %-52s : %s' % (key, hdl.disclosed_library_clause_names[key]))
|
642 |
|
|
|
643 |
|
|
if args.toplib:
|
644 |
|
|
for build_type in ['sim', 'synth']:
|
645 |
|
|
print('')
|
646 |
|
|
print('derive_all_use_libs for %s of %s = \n'
|
647 |
|
|
% (build_type, args.toplib), hdl.derive_all_use_libs(build_type, args.toplib))
|
648 |
|
|
print('')
|
649 |
|
|
print('derive_lib_order for %s of %s = \n'
|
650 |
|
|
% (build_type, args.toplib), hdl.derive_lib_order(build_type, args.toplib))
|
651 |
|
|
|
652 |
|
|
|