Select Git revision
PosixTime.h
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
hdl_config.py 21.04 KiB
###############################################################################
#
# Copyright (C) 2014
# ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################
"""HDL configuration for building simulation and synthesis targets.
There should be one hdltool.cfg file somewhere in the toolRootDir and at
least one hdllib.cfg file somewhere in the libRootDir. Every HDL library
that is in the libRootDir can be found if it has a hdllib.cfg file.
Together the hdltool.cfg and hdllib.cfg files contain all the keys and
values that are sufficient to be able to build the targets for the HDL
library. The possible targets are:
- compile to created the library binaries for simulation
- synthesize to created an image that can be loaded ion the FPGA
- verify VHDL test benches in simulation
- verify Python test cases via the MM control interface in simulation
- validate Python test cases on hardware via the MM control interface
The contents of the cfg files consist of a series of key - value pairs
that are read into a dictionary as defined in common_dict_file.py. Whether
the key is a valid key depends on the application that interprets the
dictionary.
The methods can have the library dictionary or the library name as
argument. The default arguments are the self.libs.dicts and the
corresponding self.lib_names. The argument can be a list or a single value.
Similar the return can be a list or a single value, because a list of one
element is unlistified.
"""
import common as cm
import common_dict_file
import sys
import os
import os.path
import shutil
class HdlConfig:
def __init__(self, toolRootDir, libFileName='hdllib.cfg', toolFileName='hdltool.cfg', technologyNames=[]):
"""Get tool dictionary info from toolRootDir and all HDL library dictionary info for it
- self.tool.dicts = single dictionary that contains the tool info
- self.libs.dicts = list of dictionaries that contains the info of the HDL libraries.
The technologyNames parameter allow control over which HDL libraries are kept. If technologyNames is:
[] : Keep all HDL libraries that were found.
['ip_stratixiv', 'ip_arria10'] : The HDL libraries with a hdl_lib_technology that is not '' or does not match one of the technologies
in technologyNames are removed from the list of HDL library dictionaries.
"""
self.toolRootDir = toolRootDir
# HDL tool config file
self.tool = common_dict_file.CommonDictFile(toolRootDir, toolFileName) # tool dict file
if self.tool.nof_dicts==0: sys.exit('Error : No HDL tool config file found')
if self.tool.nof_dicts >1: sys.exit('Error : Multiple HDL tool config files found')
# HDL library config files
self.libRootDir = os.path.expandvars(self.tool.get_key_values('lib_root_dir'))
self.libs = common_dict_file.CommonDictFile(self.libRootDir, libFileName) # library dict files
if self.libs.nof_dicts==0: sys.exit('Error : No HDL library config file found')
# Keep the generic HDL libraries and remove those that do not match the specified IP technologies
self.technologyNames = cm.listify(technologyNames)
self.removed_dicts = []
if len(self.technologyNames)>0:
for d in self.libs.dicts:
if not(d['hdl_lib_technology']=='' or d['hdl_lib_technology'] in self.technologyNames):
self.removed_dicts.append(d)
for d in self.removed_dicts:
self.libs.remove_dict_from_list(d)
# Keep list of HDL library names
self.lib_names = self.libs.get_key_values('hdl_lib_name')
# Check that there are no duplicate library names (eg. due to copying a hdlib.cfg without modifying the hdl_lib_name value)
duplicate_lib_names = cm.list_duplicates(self.lib_names)
if len(duplicate_lib_names)>0: sys.exit('Error : Duplicate HDL library config file found %s' % duplicate_lib_names)
def get_used_libs(self, build_type, lib_dict, arg_exclude_libs=[]):
"""Get the list of used HDL libraries from the lib_dict and remove the excluded libs.
- 'hdl_lib_uses_synth' and 'hdl_lib_uses_sim' define the used libraries that are directly used in this library
- 'hdl_lib_excludes' defines the libraries that must be excluded
"""
# use list() to take local copy, to avoid next that default empty list argument arg_exclude_libs=[] gets disturbed
exclude_libs = list(arg_exclude_libs)
if 'hdl_lib_uses_synth' in lib_dict:
use_libs = lib_dict['hdl_lib_uses_synth'].split()
if build_type=='sim':
if 'hdl_lib_uses_sim' in lib_dict:
use_libs += lib_dict['hdl_lib_uses_sim'].split()
if 'hdl_lib_excludes' in lib_dict:
exclude_libs += lib_dict['hdl_lib_excludes'].split()
for exclude_lib in exclude_libs:
if exclude_lib in use_libs:
use_libs.remove(exclude_lib)
return use_libs, exclude_libs
def derive_all_use_libs(self, build_type, lib_name, arg_exclude_libs=[]):
"""Derive a list of all HDL libraries that the specified HDL lib_name library depends on.
The build_type can be:
'sim' uses both the 'hdl_lib_uses_synth' and the 'hdl_lib_uses_sim' key in the lib_dict,
'synth' uses only the 'hdl_lib_uses_synth' key in the lib_dict
Note:
. Only the generic HDL libraries and the technology specific libraries that match self.technologyNames are used.
. The hdl_lib_uses_<build type> key only needs to contain all libraries that are declared at the VHDL LIBRARY
clauses of the source files in this library. This derive_all_use_libs() will recursively find all deeper
level libraries as well.
. Pass on exclude_libs through the recursion hierarchy to ensure that the excluded library and all libraries
that are used by it and not by any other library are excluded as well.
"""
# use list() to take local copy, to avoid next that default empty list argument arg_exclude_libs=[] gets disturbed
exclude_libs = list(arg_exclude_libs)
if lib_name in self.lib_names:
all_use_libs = [lib_name]
lib_dict = self.libs.dicts[self.lib_names.index(lib_name)]
# use recursion to include all used libs
use_libs, exclude_libs = self.get_used_libs(build_type, lib_dict, exclude_libs)
try:
use_libs
for use_lib in use_libs:
if use_lib in self.lib_names:
all_use_libs.append(use_lib)
all_use_libs += self.derive_all_use_libs(build_type, use_lib, exclude_libs)
except NameError:
pass
# remove all duplicates from the list
return cm.unique(all_use_libs)
else:
sys.exit('Error : Unknown HDL library name')
def derive_lib_order(self, build_type, lib_names=None):
"""Derive the dependency order for all HDL libraries in the fully specified list of lib_names.
Note:
. Only the generic HDL libraries and the technology specific libraries that match self.technologyNames are used.
. The lib_names list must include all used libs, so if necessary first call derive_all_use_libs().
"""
if lib_names==None: lib_names=self.lib_names
lib_dicts = self.libs.get_dicts('hdl_lib_name', lib_names)
# use list() to take local copy to avoid modifying list order of self.lib_names which matches self.libs.dicts list order
lib_order = list(lib_names)
for lib_dict in cm.listify(lib_dicts):
lib_name = lib_dict['hdl_lib_name']
use_libs, exclude_libs = self.get_used_libs(build_type, lib_dict, [])
try:
for use_lib in use_libs:
if use_lib in lib_names:
if lib_order.index(use_lib) > lib_order.index(lib_name):
lib_order.remove(use_lib)
lib_order.insert(lib_order.index(lib_name), use_lib) # move used lib to just before this lib
except NameError:
pass
# use recursion to keep on reordering the lib_order until it is stable
if lib_names != lib_order:
lib_order = self.derive_lib_order(build_type, lib_order)
return lib_order
def get_tool_build_dir(self, build_type):
"""Get the central tool build directory.
The build_type can be:
'sim' uses the 'build_dir_sim' key in the self.tool dictionary
'synth' uses the 'build_dir_synth' key in the self.tool dictionary
The build dir key value must be an absolute directory path. The tool build dir consists of
- the absolute path to the central main build directory
- the tool_name_key value as subdirectory
"""
build_dir_key = 'build_dir_' + build_type
tool_name_key = 'tool_name_' + build_type
if self.tool.get_key_values(build_dir_key)==None:
sys.exit('Error : Unknown build type for build_dir_key')
build_maindir = os.path.expandvars(self.tool.get_key_values(build_dir_key))
if not os.path.isabs(build_maindir):
sys.exit('Error : The build_dir_key value must be an absolute path')
if self.tool.get_key_values(tool_name_key)==None:
sys.exit('Error : Unknown build type for tool_name_key')
build_tooldir = self.tool.get_key_values(tool_name_key)
return build_maindir, build_tooldir
def get_lib_build_dirs(self, build_type, lib_dicts=None):
"""Get the subdirectories within the central tool build directory for all HDL libraries in the specified list of lib_dicts.
The build_type can be:
'sim' uses the 'build_dir_sim' key in the self.tool dictionary
'synth' uses the 'build_dir_synth' key in the self.tool dictionary
The build dir key value must be an absolute directory path. The lib build dir consists of
- the absolute path to the central main build directory
- the tool_name_key value as subdirectory
- the library name as library subdirectory
"""
if lib_dicts==None: lib_dicts=self.libs.dicts
build_maindir, build_tooldir = self.get_tool_build_dir(build_type)
build_dirs = []
for lib_dict in cm.listify(lib_dicts):
lib_name = lib_dict['hdl_lib_name']
build_dirs.append(os.path.join(build_maindir, build_tooldir, lib_name)) # central build main directory with subdirectory per library
return cm.unlistify(build_dirs)
def create_lib_order_files(self, build_type, lib_names=None):
"""Create the compile order file '<lib_name>_lib_order.txt' for all HDL libraries in the specified list of lib_names.
The file is stored in the sim build directory of the HDL library.
The file is read by commands.do in Modelsim to avoid having to derive the library compile order in TCL.
"""
if lib_names==None: lib_names=self.lib_names
lib_dicts = self.libs.get_dicts('hdl_lib_name', lib_names)
for lib_dict in cm.listify(lib_dicts):
lib_name = lib_dict['hdl_lib_name']
use_libs = self.derive_all_use_libs(build_type, lib_name)
lib_order = self.derive_lib_order(build_type, use_libs)
file_name = lib_name + '_lib_order.txt'
file_path = self.get_lib_build_dirs('sim', lib_dicts=lib_dict)
cm.mkdir(file_path)
filePathName = os.path.join(file_path, file_name)
with open(filePathName, 'w') as fp:
for lib in lib_order:
fp.write('%s ' % lib)
def read_hdl_libraries_technology_file(self, technologyName, filePath=None):
"""Read the list of technology HDL libraries from a file.
Arguments:
- technologyName : refers to the hdl_libraries_<technologyName>.txt file
- filePath : path to hdl_libraries_<technologyName>.txt, when None then the file is
read in the default toolRootDir
"""
fileName = 'hdl_libraries_' + technologyName + '.txt' # use fixed file name format
if filePath==None:
toolSubDir = self.tool.get_key_values('tool_name_synth')
fileNamePath=os.path.join(self.toolRootDir, toolSubDir, fileName) # default file path
else:
fileNamePath=os.path.join(filePath, fileName) # specified file path
tech_dict = self.tool.read_dict_file(fileNamePath)
return tech_dict
def copy_files(self, build_type, lib_names=None):
"""Copy all source directories and source files listed at the <tool_name>_copy_files key. The build_type selects the <tool_name>_copy_files key using the
tool_name_<build_type> key value from the hdltool.cfg.
The <tool_name>_copy_files key expects a source and a destination pair per listed directory or file:
- The sources need to be specified with absolute path or relative to the HDL library source directory where the hdllib.cfg is stored
- The destinations need to be specified with absolute path or relative to HDL library build directory where the project file (e.g. mpf, qpf) gets stored
Arguments:
- lib_names : one or more HDL libraries
"""
if lib_names==None: lib_names=self.lib_names
lib_dicts = self.libs.get_dicts(key='hdl_lib_name', values=lib_names)
tool_name_key = 'tool_name_' + build_type
tool_name_value = self.tool.get_key_values(tool_name_key)
tool_name_copy_key = tool_name_value + '_copy_files'
for lib_dict in cm.listify(lib_dicts):
if tool_name_copy_key in lib_dict:
lib_path = self.libs.get_filePath(lib_dict)
build_path = self.get_lib_build_dirs(build_type, lib_dicts=lib_dict)
cm.mkdir(build_path)
key_values = lib_dict[tool_name_copy_key].split()
sources = key_values[0::2]
destinations = key_values[1::2]
file_io = zip(sources, destinations)
for fpn_io in file_io:
sourcePathName = cm.expand_file_path_name(fpn_io[0], lib_path)
buildPath = cm.expand_file_path_name(fpn_io[1], build_path)
if os.path.isfile(sourcePathName):
shutil.copy(sourcePathName, buildPath) # copy file
else:
if os.path.exists(buildPath):
shutil.rmtree(buildPath)
shutil.copytree(sourcePathName, buildPath) # copy directory tree
if __name__ == '__main__':
# Mode
# 0 = Read dictionary info from all HDL tool and library configuration files and derive the compile order
# 1 = Change a key value in all hdllib.cfg dict files
# 2 = Insert a new key = value pair in all hdllib.cfg dict files at the specified line number
# 3 = Insert a new key = value pair in all hdllib.cfg dict files just before an already existing key
# 4 = Rename a key in all hdllib.cfg dict files
# 5 = Remove a new key = value pair from all hdllib.cfg dict files
mode = 0
if mode==0:
# Read the dictionary info from all HDL tool and library configuration files in the current directory and the sub directories
technologyNames = []
technologyNames = ['ip_stratixiv']
hdl = HdlConfig(toolRootDir=os.path.expandvars('$RADIOHDL/tools'), libFileName='hdllib.cfg', toolFileName='hdltool.cfg', technologyNames=technologyNames)
print '#'
print '# HdlConfig:'
print '#'
for i, p in enumerate(hdl.libs.filePathNames):
print i, p
d = hdl.libs.dicts[i]
for k,v in d.iteritems():
print k, '=', v
print ''
print ''
print 'tool = ', hdl.tool.filePathNames[0]
print ''
print 'lib paths'
for p in hdl.libs.filePaths:
print ' ', p
print ''
print 'lib paths names'
for p in hdl.libs.filePathNames:
print ' ', p
print ''
print 'lib_names = ', hdl.lib_names
print 'derive_lib_order for sim : ', hdl.derive_lib_order('sim')
print 'derive_lib_order for synth : ', hdl.derive_lib_order('synth')
print ''
print 'get_lib_build_dirs for simulation:'
for sim_dir in hdl.get_lib_build_dirs('sim'):
print ' ', sim_dir
print ''
if hdl.libRootDir=='RADIOHDL':
#use_libs = hdl.derive_all_use_libs('sim', 'unb1_minimal')
#use_libs = hdl.derive_all_use_libs('sim', 'dp')
#use_libs = hdl.derive_all_use_libs('sim', 'tech_xaui')
use_libs = hdl.derive_all_use_libs('sim', 'unb1_test_10GbE')
use_libs = hdl.derive_all_use_libs('sim', 'tech_ddr')
print 'derive_all_use_libs = ', use_libs
lib_order = hdl.derive_lib_order('sim', use_libs)
print 'derive_lib_order = ', lib_order
if hdl.libRootDir=='UNB':
use_libs = hdl.derive_all_use_libs('sim', 'unb_minimal')
use_libs = hdl.derive_all_use_libs('sim', 'dp')
print 'derive_all_use_libs = ', use_libs
lib_order = hdl.derive_lib_order('sim', use_libs)
print 'derive_lib_order = ', lib_order
if mode==1:
key = 'build_dir_synth'
new_value = '$HDL_BUILD_DIR'
# Read the dictionary info from all HDL tool and library configuration files in the current directory and the sub directories
hdl = HdlConfig(toolRootDir=os.path.expandvars('$RADIOHDL/tools'), libFileName='hdllib.cfg', toolFileName='hdltool.cfg', technologyNames=[])
for p in hdl.libs.filePathNames:
hdl.libs.change_key_value_in_dict_file(p, key, new_value)
if mode==2:
insert_key = 'hdl_lib_technology'
insert_value = ''
insertLineNr = 4
# Read the dictionary info from all HDL tool and library configuration files in the current directory and the sub directories
hdl = HdlConfig(toolRootDir=os.path.expandvars('$RADIOHDL/tools'), libFileName='hdllib.cfg', toolFileName='hdltool.cfg', technologyNames=[])
for p in hdl.libs.filePathNames:
hdl.libs.insert_key_in_dict_file_at_line_number(p, insert_key, insert_value, insertLineNr)
if mode==3:
insert_key = 'hdl_lib_uses_sim'
insert_value = '\n'
insert_beforeKey = 'hdl_lib_technology'
# Read the dictionary info from all HDL tool and library configuration files in the current directory and the sub directories
hdl = HdlConfig(toolRootDir=os.path.expandvars('$RADIOHDL/tools'), libFileName='hdllib.cfg', toolFileName='hdltool.cfg', technologyNames=[])
for p in hdl.libs.filePathNames:
hdl.libs.insert_key_in_dict_file_before_another_key(p, insert_key, insert_value, insert_beforeKey)
if mode==4:
old_key = 'hdl_lib_uses'
new_key = 'hdl_lib_uses_synth'
# Read the dictionary info from all HDL tool and library configuration files in the current directory and the sub directories
hdl = HdlConfig(toolRootDir=os.path.expandvars('$RADIOHDL/tools'), libFileName='hdllib.cfg', toolFileName='hdltool.cfg', technologyNames=[])
for p in hdl.libs.filePathNames:
hdl.libs.rename_key_in_dict_file(p, old_key, new_key)
if mode==5:
remove_key = 'build_dir_synth'
# Read the dictionary info from all HDL tool and library configuration files in the current directory and the sub directories
hdl = HdlConfig(toolRootDir=os.path.expandvars('$RADIOHDL/tools'), libFileName='hdllib.cfg', toolFileName='hdltool.cfg', technologyNames=[])
for p in hdl.libs.filePathNames:
hdl.libs.remove_key_from_dict_file(p, remove_key)