Maxim nexpaq / nexpaq_dev
Committer:
nexpaq
Date:
Fri Nov 04 20:27:58 2016 +0000
Revision:
0:6c56fb4bc5f0
Moving to library for sharing updates

Who changed what in which revision?

UserRevisionLine numberNew contents of line
nexpaq 0:6c56fb4bc5f0 1 """
nexpaq 0:6c56fb4bc5f0 2 mbed SDK
nexpaq 0:6c56fb4bc5f0 3 Copyright (c) 2011-2016 ARM Limited
nexpaq 0:6c56fb4bc5f0 4
nexpaq 0:6c56fb4bc5f0 5 Licensed under the Apache License, Version 2.0 (the "License");
nexpaq 0:6c56fb4bc5f0 6 you may not use this file except in compliance with the License.
nexpaq 0:6c56fb4bc5f0 7 You may obtain a copy of the License at
nexpaq 0:6c56fb4bc5f0 8
nexpaq 0:6c56fb4bc5f0 9 http://www.apache.org/licenses/LICENSE-2.0
nexpaq 0:6c56fb4bc5f0 10
nexpaq 0:6c56fb4bc5f0 11 Unless required by applicable law or agreed to in writing, software
nexpaq 0:6c56fb4bc5f0 12 distributed under the License is distributed on an "AS IS" BASIS,
nexpaq 0:6c56fb4bc5f0 13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
nexpaq 0:6c56fb4bc5f0 14 See the License for the specific language governing permissions and
nexpaq 0:6c56fb4bc5f0 15 limitations under the License.
nexpaq 0:6c56fb4bc5f0 16 """
nexpaq 0:6c56fb4bc5f0 17
nexpaq 0:6c56fb4bc5f0 18 import os
nexpaq 0:6c56fb4bc5f0 19 import binascii
nexpaq 0:6c56fb4bc5f0 20 import struct
nexpaq 0:6c56fb4bc5f0 21 import shutil
nexpaq 0:6c56fb4bc5f0 22 import inspect
nexpaq 0:6c56fb4bc5f0 23 import sys
nexpaq 0:6c56fb4bc5f0 24 from tools.patch import patch
nexpaq 0:6c56fb4bc5f0 25 from tools.paths import TOOLS_BOOTLOADERS
nexpaq 0:6c56fb4bc5f0 26 from tools.utils import json_file_to_dict
nexpaq 0:6c56fb4bc5f0 27
nexpaq 0:6c56fb4bc5f0 28 CORE_LABELS = {
nexpaq 0:6c56fb4bc5f0 29 "ARM7TDMI-S": ["ARM7", "LIKE_CORTEX_ARM7"],
nexpaq 0:6c56fb4bc5f0 30 "Cortex-M0" : ["M0", "CORTEX_M", "LIKE_CORTEX_M0"],
nexpaq 0:6c56fb4bc5f0 31 "Cortex-M0+": ["M0P", "CORTEX_M", "LIKE_CORTEX_M0"],
nexpaq 0:6c56fb4bc5f0 32 "Cortex-M1" : ["M1", "CORTEX_M", "LIKE_CORTEX_M1"],
nexpaq 0:6c56fb4bc5f0 33 "Cortex-M3" : ["M3", "CORTEX_M", "LIKE_CORTEX_M3"],
nexpaq 0:6c56fb4bc5f0 34 "Cortex-M4" : ["M4", "CORTEX_M", "RTOS_M4_M7", "LIKE_CORTEX_M4"],
nexpaq 0:6c56fb4bc5f0 35 "Cortex-M4F" : ["M4", "CORTEX_M", "RTOS_M4_M7", "LIKE_CORTEX_M4"],
nexpaq 0:6c56fb4bc5f0 36 "Cortex-M7" : ["M7", "CORTEX_M", "RTOS_M4_M7", "LIKE_CORTEX_M7"],
nexpaq 0:6c56fb4bc5f0 37 "Cortex-M7F" : ["M7", "CORTEX_M", "RTOS_M4_M7", "LIKE_CORTEX_M7"],
nexpaq 0:6c56fb4bc5f0 38 "Cortex-M7FD" : ["M7", "CORTEX_M", "RTOS_M4_M7", "LIKE_CORTEX_M7"],
nexpaq 0:6c56fb4bc5f0 39 "Cortex-A9" : ["A9", "CORTEX_A", "LIKE_CORTEX_A9"]
nexpaq 0:6c56fb4bc5f0 40 }
nexpaq 0:6c56fb4bc5f0 41
nexpaq 0:6c56fb4bc5f0 42 ################################################################################
nexpaq 0:6c56fb4bc5f0 43 # Generic Target class that reads and interprets the data in targets.json
nexpaq 0:6c56fb4bc5f0 44
nexpaq 0:6c56fb4bc5f0 45 class HookError(Exception):
nexpaq 0:6c56fb4bc5f0 46 """ A simple class that represents all the exceptions associated with
nexpaq 0:6c56fb4bc5f0 47 hooking
nexpaq 0:6c56fb4bc5f0 48 """
nexpaq 0:6c56fb4bc5f0 49 pass
nexpaq 0:6c56fb4bc5f0 50
nexpaq 0:6c56fb4bc5f0 51 CACHES = {}
nexpaq 0:6c56fb4bc5f0 52 def cached(func):
nexpaq 0:6c56fb4bc5f0 53 """A simple decorator used for automatically caching data returned by a
nexpaq 0:6c56fb4bc5f0 54 function
nexpaq 0:6c56fb4bc5f0 55 """
nexpaq 0:6c56fb4bc5f0 56 def wrapper(*args, **kwargs):
nexpaq 0:6c56fb4bc5f0 57 """The wrapped function itself"""
nexpaq 0:6c56fb4bc5f0 58 if not CACHES.has_key((func.__name__, args)):
nexpaq 0:6c56fb4bc5f0 59 CACHES[(func.__name__, args)] = func(*args, **kwargs)
nexpaq 0:6c56fb4bc5f0 60 return CACHES[(func.__name__, args)]
nexpaq 0:6c56fb4bc5f0 61 return wrapper
nexpaq 0:6c56fb4bc5f0 62
nexpaq 0:6c56fb4bc5f0 63 class Target(object):
nexpaq 0:6c56fb4bc5f0 64 """An object to represent a Target (MCU/Board)"""
nexpaq 0:6c56fb4bc5f0 65 # Cumulative attributes can have values appended to them, so they
nexpaq 0:6c56fb4bc5f0 66 # need to be computed differently than regular attributes
nexpaq 0:6c56fb4bc5f0 67 cumulative_attributes = ['extra_labels', 'macros', 'device_has', 'features']
nexpaq 0:6c56fb4bc5f0 68
nexpaq 0:6c56fb4bc5f0 69 # List of targets that were added dynamically using "add_py_targets" (see
nexpaq 0:6c56fb4bc5f0 70 # below)
nexpaq 0:6c56fb4bc5f0 71 __py_targets = set()
nexpaq 0:6c56fb4bc5f0 72
nexpaq 0:6c56fb4bc5f0 73 # Default location of the 'targets.json' file
nexpaq 0:6c56fb4bc5f0 74 __targets_json_location_default = os.path.join(
nexpaq 0:6c56fb4bc5f0 75 os.path.dirname(os.path.abspath(__file__)), '..', 'hal', 'targets.json')
nexpaq 0:6c56fb4bc5f0 76
nexpaq 0:6c56fb4bc5f0 77 # Current/new location of the 'targets.json' file
nexpaq 0:6c56fb4bc5f0 78 __targets_json_location = None
nexpaq 0:6c56fb4bc5f0 79
nexpaq 0:6c56fb4bc5f0 80 @staticmethod
nexpaq 0:6c56fb4bc5f0 81 @cached
nexpaq 0:6c56fb4bc5f0 82 def get_json_target_data():
nexpaq 0:6c56fb4bc5f0 83 """Load the description of JSON target data"""
nexpaq 0:6c56fb4bc5f0 84 return json_file_to_dict(Target.__targets_json_location or
nexpaq 0:6c56fb4bc5f0 85 Target.__targets_json_location_default)
nexpaq 0:6c56fb4bc5f0 86
nexpaq 0:6c56fb4bc5f0 87 @staticmethod
nexpaq 0:6c56fb4bc5f0 88 def set_targets_json_location(location=None):
nexpaq 0:6c56fb4bc5f0 89 """Set the location of the targets.json file"""
nexpaq 0:6c56fb4bc5f0 90 Target.__targets_json_location = (location or
nexpaq 0:6c56fb4bc5f0 91 Target.__targets_json_location_default)
nexpaq 0:6c56fb4bc5f0 92 # Invalidate caches, since the location of the JSON file changed
nexpaq 0:6c56fb4bc5f0 93 CACHES.clear()
nexpaq 0:6c56fb4bc5f0 94
nexpaq 0:6c56fb4bc5f0 95 @staticmethod
nexpaq 0:6c56fb4bc5f0 96 @cached
nexpaq 0:6c56fb4bc5f0 97 def get_module_data():
nexpaq 0:6c56fb4bc5f0 98 """Get the members of this module using Python's "inspect" module"""
nexpaq 0:6c56fb4bc5f0 99 return dict([(m[0], m[1]) for m in
nexpaq 0:6c56fb4bc5f0 100 inspect.getmembers(sys.modules[__name__])])
nexpaq 0:6c56fb4bc5f0 101
nexpaq 0:6c56fb4bc5f0 102 def __get_resolution_order(self, target_name, order, level=0):
nexpaq 0:6c56fb4bc5f0 103 """ Return the order in which target descriptions are searched for
nexpaq 0:6c56fb4bc5f0 104 attributes. This mimics the Python 2.2 method resolution order, which
nexpaq 0:6c56fb4bc5f0 105 is what the old targets.py module used. For more details, check
nexpaq 0:6c56fb4bc5f0 106 http://makina-corpus.com/blog/metier/2014/python-tutorial-understanding-python-mro-class-search-path
nexpaq 0:6c56fb4bc5f0 107 The resolution order contains (name, level) tuples, where "name" is the
nexpaq 0:6c56fb4bc5f0 108 name of the class and "level" is the level in the inheritance hierarchy
nexpaq 0:6c56fb4bc5f0 109 (the target itself is at level 0, its first parent at level 1, its
nexpaq 0:6c56fb4bc5f0 110 parent's parent at level 2 and so on)
nexpaq 0:6c56fb4bc5f0 111 """
nexpaq 0:6c56fb4bc5f0 112 # the resolution order can't contain duplicate target names
nexpaq 0:6c56fb4bc5f0 113 if target_name not in [l[0] for l in order]:
nexpaq 0:6c56fb4bc5f0 114 order.append((target_name, level))
nexpaq 0:6c56fb4bc5f0 115 parents = self.get_json_target_data()[target_name].get("inherits", [])
nexpaq 0:6c56fb4bc5f0 116 for par in parents:
nexpaq 0:6c56fb4bc5f0 117 order = self.__get_resolution_order(par, order, level + 1)
nexpaq 0:6c56fb4bc5f0 118 return order
nexpaq 0:6c56fb4bc5f0 119
nexpaq 0:6c56fb4bc5f0 120 @staticmethod
nexpaq 0:6c56fb4bc5f0 121 def __add_paths_to_progen(data):
nexpaq 0:6c56fb4bc5f0 122 """Modify the exporter specification ("progen") by changing all
nexpaq 0:6c56fb4bc5f0 123 "template" keys to full paths
nexpaq 0:6c56fb4bc5f0 124 """
nexpaq 0:6c56fb4bc5f0 125 out = {}
nexpaq 0:6c56fb4bc5f0 126 for key, val in data.items():
nexpaq 0:6c56fb4bc5f0 127 if isinstance(val, dict):
nexpaq 0:6c56fb4bc5f0 128 out[key] = Target.__add_paths_to_progen(val)
nexpaq 0:6c56fb4bc5f0 129 elif key == "template":
nexpaq 0:6c56fb4bc5f0 130 out[key] = [os.path.join(os.path.dirname(__file__), 'export', v)
nexpaq 0:6c56fb4bc5f0 131 for v in val]
nexpaq 0:6c56fb4bc5f0 132 else:
nexpaq 0:6c56fb4bc5f0 133 out[key] = val
nexpaq 0:6c56fb4bc5f0 134 return out
nexpaq 0:6c56fb4bc5f0 135
nexpaq 0:6c56fb4bc5f0 136 def __getattr_cumulative(self, attrname):
nexpaq 0:6c56fb4bc5f0 137 """Look for the attribute in the class and its parents, as defined by
nexpaq 0:6c56fb4bc5f0 138 the resolution order
nexpaq 0:6c56fb4bc5f0 139 """
nexpaq 0:6c56fb4bc5f0 140 tdata = self.get_json_target_data()
nexpaq 0:6c56fb4bc5f0 141 # For a cumulative attribute, figure out when it was defined the
nexpaq 0:6c56fb4bc5f0 142 # last time (in attribute resolution order) then follow the "_add"
nexpaq 0:6c56fb4bc5f0 143 # and "_remove" data fields
nexpaq 0:6c56fb4bc5f0 144 for idx, target in enumerate(self.resolution_order):
nexpaq 0:6c56fb4bc5f0 145 # the attribute was defined at this level in the resolution
nexpaq 0:6c56fb4bc5f0 146 # order
nexpaq 0:6c56fb4bc5f0 147 if attrname in tdata[target[0]]:
nexpaq 0:6c56fb4bc5f0 148 def_idx = idx
nexpaq 0:6c56fb4bc5f0 149 break
nexpaq 0:6c56fb4bc5f0 150 else:
nexpaq 0:6c56fb4bc5f0 151 raise AttributeError("Attribute '%s' not found in target '%s'"
nexpaq 0:6c56fb4bc5f0 152 % (attrname, self.name))
nexpaq 0:6c56fb4bc5f0 153 # Get the starting value of the attribute
nexpaq 0:6c56fb4bc5f0 154 starting_value = (tdata[self.resolution_order[def_idx][0]][attrname]
nexpaq 0:6c56fb4bc5f0 155 or [])[:]
nexpaq 0:6c56fb4bc5f0 156 # Traverse the resolution list in high inheritance to low
nexpaq 0:6c56fb4bc5f0 157 # inheritance level, left to right order to figure out all the
nexpaq 0:6c56fb4bc5f0 158 # other classes that change the definition by adding or removing
nexpaq 0:6c56fb4bc5f0 159 # elements
nexpaq 0:6c56fb4bc5f0 160 for idx in xrange(self.resolution_order[def_idx][1] - 1, -1, -1):
nexpaq 0:6c56fb4bc5f0 161 same_level_targets = [tar[0] for tar in self.resolution_order
nexpaq 0:6c56fb4bc5f0 162 if tar[1] == idx]
nexpaq 0:6c56fb4bc5f0 163 for tar in same_level_targets:
nexpaq 0:6c56fb4bc5f0 164 data = tdata[tar]
nexpaq 0:6c56fb4bc5f0 165 # Do we have anything to add ?
nexpaq 0:6c56fb4bc5f0 166 if data.has_key(attrname + "_add"):
nexpaq 0:6c56fb4bc5f0 167 starting_value.extend(data[attrname + "_add"])
nexpaq 0:6c56fb4bc5f0 168 # Do we have anything to remove ?
nexpaq 0:6c56fb4bc5f0 169 if data.has_key(attrname + "_remove"):
nexpaq 0:6c56fb4bc5f0 170 # Macros can be defined either without a value (MACRO)
nexpaq 0:6c56fb4bc5f0 171 # or with a value (MACRO=10). When removing, we specify
nexpaq 0:6c56fb4bc5f0 172 # only the name of the macro, without the value. So we
nexpaq 0:6c56fb4bc5f0 173 # need to create a mapping between the macro name and
nexpaq 0:6c56fb4bc5f0 174 # its value. This will work for extra_labels and other
nexpaq 0:6c56fb4bc5f0 175 # type of arrays as well, since they fall into the
nexpaq 0:6c56fb4bc5f0 176 # "macros without a value" category (simple definitions
nexpaq 0:6c56fb4bc5f0 177 # without a value).
nexpaq 0:6c56fb4bc5f0 178 name_def_map = {}
nexpaq 0:6c56fb4bc5f0 179 for crtv in starting_value:
nexpaq 0:6c56fb4bc5f0 180 if crtv.find('=') != -1:
nexpaq 0:6c56fb4bc5f0 181 temp = crtv.split('=')
nexpaq 0:6c56fb4bc5f0 182 if len(temp) != 2:
nexpaq 0:6c56fb4bc5f0 183 raise ValueError(
nexpaq 0:6c56fb4bc5f0 184 "Invalid macro definition '%s'" % crtv)
nexpaq 0:6c56fb4bc5f0 185 name_def_map[temp[0]] = crtv
nexpaq 0:6c56fb4bc5f0 186 else:
nexpaq 0:6c56fb4bc5f0 187 name_def_map[crtv] = crtv
nexpaq 0:6c56fb4bc5f0 188 for element in data[attrname + "_remove"]:
nexpaq 0:6c56fb4bc5f0 189 if element not in name_def_map:
nexpaq 0:6c56fb4bc5f0 190 raise ValueError(
nexpaq 0:6c56fb4bc5f0 191 ("Unable to remove '%s' in '%s.%s' since "
nexpaq 0:6c56fb4bc5f0 192 % (element, self.name, attrname)) +
nexpaq 0:6c56fb4bc5f0 193 "it doesn't exist")
nexpaq 0:6c56fb4bc5f0 194 starting_value.remove(name_def_map[element])
nexpaq 0:6c56fb4bc5f0 195 return starting_value
nexpaq 0:6c56fb4bc5f0 196
nexpaq 0:6c56fb4bc5f0 197 def __getattr_helper(self, attrname):
nexpaq 0:6c56fb4bc5f0 198 """Compute the value of a given target attribute"""
nexpaq 0:6c56fb4bc5f0 199 if attrname in self.cumulative_attributes:
nexpaq 0:6c56fb4bc5f0 200 return self.__getattr_cumulative(attrname)
nexpaq 0:6c56fb4bc5f0 201 else:
nexpaq 0:6c56fb4bc5f0 202 tdata = self.get_json_target_data()
nexpaq 0:6c56fb4bc5f0 203 starting_value = None
nexpaq 0:6c56fb4bc5f0 204 for target in self.resolution_order:
nexpaq 0:6c56fb4bc5f0 205 data = tdata[target[0]]
nexpaq 0:6c56fb4bc5f0 206 if data.has_key(attrname):
nexpaq 0:6c56fb4bc5f0 207 starting_value = data[attrname]
nexpaq 0:6c56fb4bc5f0 208 break
nexpaq 0:6c56fb4bc5f0 209 else: # Attribute not found
nexpaq 0:6c56fb4bc5f0 210 raise AttributeError(
nexpaq 0:6c56fb4bc5f0 211 "Attribute '%s' not found in target '%s'"
nexpaq 0:6c56fb4bc5f0 212 % (attrname, self.name))
nexpaq 0:6c56fb4bc5f0 213 # 'progen' needs the full path to the template (the path in JSON is
nexpaq 0:6c56fb4bc5f0 214 # relative to tools/export)
nexpaq 0:6c56fb4bc5f0 215 if attrname == "progen":
nexpaq 0:6c56fb4bc5f0 216 return self.__add_paths_to_progen(starting_value)
nexpaq 0:6c56fb4bc5f0 217 else:
nexpaq 0:6c56fb4bc5f0 218 return starting_value
nexpaq 0:6c56fb4bc5f0 219
nexpaq 0:6c56fb4bc5f0 220 def __getattr__(self, attrname):
nexpaq 0:6c56fb4bc5f0 221 """ Return the value of an attribute. This function only computes the
nexpaq 0:6c56fb4bc5f0 222 attribute's value once, then adds it to the instance attributes (in
nexpaq 0:6c56fb4bc5f0 223 __dict__), so the next time it is returned directly
nexpaq 0:6c56fb4bc5f0 224 """
nexpaq 0:6c56fb4bc5f0 225 result = self.__getattr_helper(attrname)
nexpaq 0:6c56fb4bc5f0 226 self.__dict__[attrname] = result
nexpaq 0:6c56fb4bc5f0 227 return result
nexpaq 0:6c56fb4bc5f0 228
nexpaq 0:6c56fb4bc5f0 229 @staticmethod
nexpaq 0:6c56fb4bc5f0 230 def add_py_targets(new_targets):
nexpaq 0:6c56fb4bc5f0 231 """Add one or more new target(s) represented as a Python dictionary
nexpaq 0:6c56fb4bc5f0 232 in 'new_targets'. It is an error to add a target with a name that
nexpaq 0:6c56fb4bc5f0 233 already exists.
nexpaq 0:6c56fb4bc5f0 234 """
nexpaq 0:6c56fb4bc5f0 235 crt_data = Target.get_json_target_data()
nexpaq 0:6c56fb4bc5f0 236 for target_key, target_value in new_targets.items():
nexpaq 0:6c56fb4bc5f0 237 if crt_data.has_key(target_key):
nexpaq 0:6c56fb4bc5f0 238 raise Exception(
nexpaq 0:6c56fb4bc5f0 239 "Attempt to add target '%s' that already exists"
nexpaq 0:6c56fb4bc5f0 240 % target_key)
nexpaq 0:6c56fb4bc5f0 241 # Add target data to the internal target dictionary
nexpaq 0:6c56fb4bc5f0 242 crt_data[target_key] = target_value
nexpaq 0:6c56fb4bc5f0 243 # Create the new target and add it to the relevant data structures
nexpaq 0:6c56fb4bc5f0 244 new_target = Target(target_key)
nexpaq 0:6c56fb4bc5f0 245 TARGETS.append(new_target)
nexpaq 0:6c56fb4bc5f0 246 TARGET_MAP[target_key] = new_target
nexpaq 0:6c56fb4bc5f0 247 TARGET_NAMES.append(target_key)
nexpaq 0:6c56fb4bc5f0 248
nexpaq 0:6c56fb4bc5f0 249 @staticmethod
nexpaq 0:6c56fb4bc5f0 250 @cached
nexpaq 0:6c56fb4bc5f0 251 def get_target(target_name):
nexpaq 0:6c56fb4bc5f0 252 """ Return the target instance starting from the target name """
nexpaq 0:6c56fb4bc5f0 253 return Target(target_name)
nexpaq 0:6c56fb4bc5f0 254
nexpaq 0:6c56fb4bc5f0 255 def __init__(self, target_name):
nexpaq 0:6c56fb4bc5f0 256 self.name = target_name
nexpaq 0:6c56fb4bc5f0 257
nexpaq 0:6c56fb4bc5f0 258 # Compute resolution order once (it will be used later in __getattr__)
nexpaq 0:6c56fb4bc5f0 259 self.resolution_order = self.__get_resolution_order(self.name, [])
nexpaq 0:6c56fb4bc5f0 260 # Create also a list with only the names of the targets in the
nexpaq 0:6c56fb4bc5f0 261 # resolution order
nexpaq 0:6c56fb4bc5f0 262 self.resolution_order_names = [target[0] for target
nexpaq 0:6c56fb4bc5f0 263 in self.resolution_order]
nexpaq 0:6c56fb4bc5f0 264
nexpaq 0:6c56fb4bc5f0 265 @property
nexpaq 0:6c56fb4bc5f0 266 def program_cycle_s(self):
nexpaq 0:6c56fb4bc5f0 267 """Special override for program_cycle_s as it's default value depends
nexpaq 0:6c56fb4bc5f0 268 upon is_disk_virtual
nexpaq 0:6c56fb4bc5f0 269 """
nexpaq 0:6c56fb4bc5f0 270 try:
nexpaq 0:6c56fb4bc5f0 271 return self.__getattr__("program_cycle_s")
nexpaq 0:6c56fb4bc5f0 272 except AttributeError:
nexpaq 0:6c56fb4bc5f0 273 return 4 if self.is_disk_virtual else 1.5
nexpaq 0:6c56fb4bc5f0 274
nexpaq 0:6c56fb4bc5f0 275 def get_labels(self):
nexpaq 0:6c56fb4bc5f0 276 """Get all possible labels for this target"""
nexpaq 0:6c56fb4bc5f0 277 labels = [self.name] + CORE_LABELS[self.core] + self.extra_labels
nexpaq 0:6c56fb4bc5f0 278 # Automatically define UVISOR_UNSUPPORTED if the target doesn't
nexpaq 0:6c56fb4bc5f0 279 # specifically define UVISOR_SUPPORTED
nexpaq 0:6c56fb4bc5f0 280 if "UVISOR_SUPPORTED" not in labels:
nexpaq 0:6c56fb4bc5f0 281 labels.append("UVISOR_UNSUPPORTED")
nexpaq 0:6c56fb4bc5f0 282 return labels
nexpaq 0:6c56fb4bc5f0 283
nexpaq 0:6c56fb4bc5f0 284 def init_hooks(self, hook, toolchain_name):
nexpaq 0:6c56fb4bc5f0 285 """Initialize the post-build hooks for a toolchain. For now, this
nexpaq 0:6c56fb4bc5f0 286 function only allows "post binary" hooks (hooks that are executed
nexpaq 0:6c56fb4bc5f0 287 after the binary image is extracted from the executable file)
nexpaq 0:6c56fb4bc5f0 288 """
nexpaq 0:6c56fb4bc5f0 289
nexpaq 0:6c56fb4bc5f0 290 # If there's no hook, simply return
nexpaq 0:6c56fb4bc5f0 291 try:
nexpaq 0:6c56fb4bc5f0 292 hook_data = self.post_binary_hook
nexpaq 0:6c56fb4bc5f0 293 except AttributeError:
nexpaq 0:6c56fb4bc5f0 294 return
nexpaq 0:6c56fb4bc5f0 295 # A hook was found. The hook's name is in the format
nexpaq 0:6c56fb4bc5f0 296 # "classname.functionname"
nexpaq 0:6c56fb4bc5f0 297 temp = hook_data["function"].split(".")
nexpaq 0:6c56fb4bc5f0 298 if len(temp) != 2:
nexpaq 0:6c56fb4bc5f0 299 raise HookError(
nexpaq 0:6c56fb4bc5f0 300 ("Invalid format for hook '%s' in target '%s'"
nexpaq 0:6c56fb4bc5f0 301 % (hook_data["function"], self.name)) +
nexpaq 0:6c56fb4bc5f0 302 " (must be 'class_name.function_name')")
nexpaq 0:6c56fb4bc5f0 303 class_name, function_name = temp[0], temp[1]
nexpaq 0:6c56fb4bc5f0 304 # "class_name" must refer to a class in this file, so check if the
nexpaq 0:6c56fb4bc5f0 305 # class exists
nexpaq 0:6c56fb4bc5f0 306 mdata = self.get_module_data()
nexpaq 0:6c56fb4bc5f0 307 if not mdata.has_key(class_name) or \
nexpaq 0:6c56fb4bc5f0 308 not inspect.isclass(mdata[class_name]):
nexpaq 0:6c56fb4bc5f0 309 raise HookError(
nexpaq 0:6c56fb4bc5f0 310 ("Class '%s' required by '%s' in target '%s'"
nexpaq 0:6c56fb4bc5f0 311 % (class_name, hook_data["function"], self.name)) +
nexpaq 0:6c56fb4bc5f0 312 " not found in targets.py")
nexpaq 0:6c56fb4bc5f0 313 # "function_name" must refer to a static function inside class
nexpaq 0:6c56fb4bc5f0 314 # "class_name"
nexpaq 0:6c56fb4bc5f0 315 cls = mdata[class_name]
nexpaq 0:6c56fb4bc5f0 316 if (not hasattr(cls, function_name)) or \
nexpaq 0:6c56fb4bc5f0 317 (not inspect.isfunction(getattr(cls, function_name))):
nexpaq 0:6c56fb4bc5f0 318 raise HookError(
nexpaq 0:6c56fb4bc5f0 319 ("Static function '%s' " % function_name) +
nexpaq 0:6c56fb4bc5f0 320 ("required by '%s' " % hook_data["function"]) +
nexpaq 0:6c56fb4bc5f0 321 ("in target '%s' " % self.name) +
nexpaq 0:6c56fb4bc5f0 322 ("not found in class '%s'" % class_name))
nexpaq 0:6c56fb4bc5f0 323 # Check if the hook specification also has target restrictions
nexpaq 0:6c56fb4bc5f0 324 toolchain_restrictions = hook_data.get("toolchains", [])
nexpaq 0:6c56fb4bc5f0 325 if toolchain_restrictions and \
nexpaq 0:6c56fb4bc5f0 326 (toolchain_name not in toolchain_restrictions):
nexpaq 0:6c56fb4bc5f0 327 return
nexpaq 0:6c56fb4bc5f0 328 # Finally, hook the requested function
nexpaq 0:6c56fb4bc5f0 329 hook.hook_add_binary("post", getattr(cls, function_name))
nexpaq 0:6c56fb4bc5f0 330
nexpaq 0:6c56fb4bc5f0 331 ################################################################################
nexpaq 0:6c56fb4bc5f0 332 # Target specific code goes in this section
nexpaq 0:6c56fb4bc5f0 333 # This code can be invoked from the target description using the
nexpaq 0:6c56fb4bc5f0 334 # "post_binary_hook" key
nexpaq 0:6c56fb4bc5f0 335
nexpaq 0:6c56fb4bc5f0 336 class LPCTargetCode(object):
nexpaq 0:6c56fb4bc5f0 337 """General LPC Target patching code"""
nexpaq 0:6c56fb4bc5f0 338 @staticmethod
nexpaq 0:6c56fb4bc5f0 339 def lpc_patch(t_self, resources, elf, binf):
nexpaq 0:6c56fb4bc5f0 340 """Patch an elf file"""
nexpaq 0:6c56fb4bc5f0 341 t_self.debug("LPC Patch: %s" % os.path.split(binf)[1])
nexpaq 0:6c56fb4bc5f0 342 patch(binf)
nexpaq 0:6c56fb4bc5f0 343
nexpaq 0:6c56fb4bc5f0 344 class LPC4088Code(object):
nexpaq 0:6c56fb4bc5f0 345 """Code specific to the LPC4088"""
nexpaq 0:6c56fb4bc5f0 346 @staticmethod
nexpaq 0:6c56fb4bc5f0 347 def binary_hook(t_self, resources, elf, binf):
nexpaq 0:6c56fb4bc5f0 348 """Hook to be run after an elf file is built"""
nexpaq 0:6c56fb4bc5f0 349 if not os.path.isdir(binf):
nexpaq 0:6c56fb4bc5f0 350 # Regular binary file, nothing to do
nexpaq 0:6c56fb4bc5f0 351 LPCTargetCode.lpc_patch(t_self, resources, elf, binf)
nexpaq 0:6c56fb4bc5f0 352 return
nexpaq 0:6c56fb4bc5f0 353 outbin = open(binf + ".temp", "wb")
nexpaq 0:6c56fb4bc5f0 354 partf = open(os.path.join(binf, "ER_IROM1"), "rb")
nexpaq 0:6c56fb4bc5f0 355 # Pad the fist part (internal flash) with 0xFF to 512k
nexpaq 0:6c56fb4bc5f0 356 data = partf.read()
nexpaq 0:6c56fb4bc5f0 357 outbin.write(data)
nexpaq 0:6c56fb4bc5f0 358 outbin.write('\xFF' * (512*1024 - len(data)))
nexpaq 0:6c56fb4bc5f0 359 partf.close()
nexpaq 0:6c56fb4bc5f0 360 # Read and append the second part (external flash) in chunks of fixed
nexpaq 0:6c56fb4bc5f0 361 # size
nexpaq 0:6c56fb4bc5f0 362 chunksize = 128 * 1024
nexpaq 0:6c56fb4bc5f0 363 partf = open(os.path.join(binf, "ER_IROM2"), "rb")
nexpaq 0:6c56fb4bc5f0 364 while True:
nexpaq 0:6c56fb4bc5f0 365 data = partf.read(chunksize)
nexpaq 0:6c56fb4bc5f0 366 outbin.write(data)
nexpaq 0:6c56fb4bc5f0 367 if len(data) < chunksize:
nexpaq 0:6c56fb4bc5f0 368 break
nexpaq 0:6c56fb4bc5f0 369 partf.close()
nexpaq 0:6c56fb4bc5f0 370 outbin.close()
nexpaq 0:6c56fb4bc5f0 371 # Remove the directory with the binary parts and rename the temporary
nexpaq 0:6c56fb4bc5f0 372 # file to 'binf'
nexpaq 0:6c56fb4bc5f0 373 shutil.rmtree(binf, True)
nexpaq 0:6c56fb4bc5f0 374 os.rename(binf + '.temp', binf)
nexpaq 0:6c56fb4bc5f0 375 t_self.debug("Generated custom binary file (internal flash + SPIFI)")
nexpaq 0:6c56fb4bc5f0 376 LPCTargetCode.lpc_patch(t_self, resources, elf, binf)
nexpaq 0:6c56fb4bc5f0 377
nexpaq 0:6c56fb4bc5f0 378 class TEENSY3_1Code(object):
nexpaq 0:6c56fb4bc5f0 379 """Hooks for the TEENSY3.1"""
nexpaq 0:6c56fb4bc5f0 380 @staticmethod
nexpaq 0:6c56fb4bc5f0 381 def binary_hook(t_self, resources, elf, binf):
nexpaq 0:6c56fb4bc5f0 382 """Hook that is run after elf is generated"""
nexpaq 0:6c56fb4bc5f0 383 from intelhex import IntelHex
nexpaq 0:6c56fb4bc5f0 384 binh = IntelHex()
nexpaq 0:6c56fb4bc5f0 385 binh.loadbin(binf, offset=0)
nexpaq 0:6c56fb4bc5f0 386
nexpaq 0:6c56fb4bc5f0 387 with open(binf.replace(".bin", ".hex"), "w") as file_desc:
nexpaq 0:6c56fb4bc5f0 388 binh.tofile(file_desc, format='hex')
nexpaq 0:6c56fb4bc5f0 389
nexpaq 0:6c56fb4bc5f0 390 class MTSCode(object):
nexpaq 0:6c56fb4bc5f0 391 """Generic MTS code"""
nexpaq 0:6c56fb4bc5f0 392 @staticmethod
nexpaq 0:6c56fb4bc5f0 393 def _combine_bins_helper(target_name, binf):
nexpaq 0:6c56fb4bc5f0 394 """combine bins with the bootloader for a particular target"""
nexpaq 0:6c56fb4bc5f0 395 loader = os.path.join(TOOLS_BOOTLOADERS, target_name, "bootloader.bin")
nexpaq 0:6c56fb4bc5f0 396 target = binf + ".tmp"
nexpaq 0:6c56fb4bc5f0 397 if not os.path.exists(loader):
nexpaq 0:6c56fb4bc5f0 398 print "Can't find bootloader binary: " + loader
nexpaq 0:6c56fb4bc5f0 399 return
nexpaq 0:6c56fb4bc5f0 400 outbin = open(target, 'w+b')
nexpaq 0:6c56fb4bc5f0 401 part = open(loader, 'rb')
nexpaq 0:6c56fb4bc5f0 402 data = part.read()
nexpaq 0:6c56fb4bc5f0 403 outbin.write(data)
nexpaq 0:6c56fb4bc5f0 404 outbin.write('\xFF' * (64*1024 - len(data)))
nexpaq 0:6c56fb4bc5f0 405 part.close()
nexpaq 0:6c56fb4bc5f0 406 part = open(binf, 'rb')
nexpaq 0:6c56fb4bc5f0 407 data = part.read()
nexpaq 0:6c56fb4bc5f0 408 outbin.write(data)
nexpaq 0:6c56fb4bc5f0 409 part.close()
nexpaq 0:6c56fb4bc5f0 410 outbin.seek(0, 0)
nexpaq 0:6c56fb4bc5f0 411 data = outbin.read()
nexpaq 0:6c56fb4bc5f0 412 outbin.seek(0, 1)
nexpaq 0:6c56fb4bc5f0 413 crc = struct.pack('<I', binascii.crc32(data) & 0xFFFFFFFF)
nexpaq 0:6c56fb4bc5f0 414 outbin.write(crc)
nexpaq 0:6c56fb4bc5f0 415 outbin.close()
nexpaq 0:6c56fb4bc5f0 416 os.remove(binf)
nexpaq 0:6c56fb4bc5f0 417 os.rename(target, binf)
nexpaq 0:6c56fb4bc5f0 418
nexpaq 0:6c56fb4bc5f0 419 @staticmethod
nexpaq 0:6c56fb4bc5f0 420 def combine_bins_mts_dot(t_self, resources, elf, binf):
nexpaq 0:6c56fb4bc5f0 421 """A hook for the MTS MDOT"""
nexpaq 0:6c56fb4bc5f0 422 MTSCode._combine_bins_helper("MTS_MDOT_F411RE", binf)
nexpaq 0:6c56fb4bc5f0 423
nexpaq 0:6c56fb4bc5f0 424 @staticmethod
nexpaq 0:6c56fb4bc5f0 425 def combine_bins_mts_dragonfly(t_self, resources, elf, binf):
nexpaq 0:6c56fb4bc5f0 426 """A hoof for the MTS Dragonfly"""
nexpaq 0:6c56fb4bc5f0 427 MTSCode._combine_bins_helper("MTS_DRAGONFLY_F411RE", binf)
nexpaq 0:6c56fb4bc5f0 428
nexpaq 0:6c56fb4bc5f0 429 class MCU_NRF51Code(object):
nexpaq 0:6c56fb4bc5f0 430 """NRF51 Hooks"""
nexpaq 0:6c56fb4bc5f0 431 @staticmethod
nexpaq 0:6c56fb4bc5f0 432 def binary_hook(t_self, resources, _, binf):
nexpaq 0:6c56fb4bc5f0 433 """Hook that merges the soft device with the bin file"""
nexpaq 0:6c56fb4bc5f0 434 # Scan to find the actual paths of soft device
nexpaq 0:6c56fb4bc5f0 435 sdf = None
nexpaq 0:6c56fb4bc5f0 436 for softdevice_and_offset_entry\
nexpaq 0:6c56fb4bc5f0 437 in t_self.target.EXPECTED_SOFTDEVICES_WITH_OFFSETS:
nexpaq 0:6c56fb4bc5f0 438 for hexf in resources.hex_files:
nexpaq 0:6c56fb4bc5f0 439 if hexf.find(softdevice_and_offset_entry['name']) != -1:
nexpaq 0:6c56fb4bc5f0 440 t_self.debug("SoftDevice file found %s."
nexpaq 0:6c56fb4bc5f0 441 % softdevice_and_offset_entry['name'])
nexpaq 0:6c56fb4bc5f0 442 sdf = hexf
nexpaq 0:6c56fb4bc5f0 443
nexpaq 0:6c56fb4bc5f0 444 if sdf is not None:
nexpaq 0:6c56fb4bc5f0 445 break
nexpaq 0:6c56fb4bc5f0 446 if sdf is not None:
nexpaq 0:6c56fb4bc5f0 447 break
nexpaq 0:6c56fb4bc5f0 448
nexpaq 0:6c56fb4bc5f0 449 if sdf is None:
nexpaq 0:6c56fb4bc5f0 450 t_self.debug("Hex file not found. Aborting.")
nexpaq 0:6c56fb4bc5f0 451 return
nexpaq 0:6c56fb4bc5f0 452
nexpaq 0:6c56fb4bc5f0 453 # Look for bootloader file that matches this soft device or bootloader
nexpaq 0:6c56fb4bc5f0 454 # override image
nexpaq 0:6c56fb4bc5f0 455 blf = None
nexpaq 0:6c56fb4bc5f0 456 if t_self.target.MERGE_BOOTLOADER is True:
nexpaq 0:6c56fb4bc5f0 457 for hexf in resources.hex_files:
nexpaq 0:6c56fb4bc5f0 458 if hexf.find(t_self.target.OVERRIDE_BOOTLOADER_FILENAME) != -1:
nexpaq 0:6c56fb4bc5f0 459 t_self.debug("Bootloader file found %s."
nexpaq 0:6c56fb4bc5f0 460 % t_self.target.OVERRIDE_BOOTLOADER_FILENAME)
nexpaq 0:6c56fb4bc5f0 461 blf = hexf
nexpaq 0:6c56fb4bc5f0 462 break
nexpaq 0:6c56fb4bc5f0 463 elif hexf.find(softdevice_and_offset_entry['boot']) != -1:
nexpaq 0:6c56fb4bc5f0 464 t_self.debug("Bootloader file found %s."
nexpaq 0:6c56fb4bc5f0 465 % softdevice_and_offset_entry['boot'])
nexpaq 0:6c56fb4bc5f0 466 blf = hexf
nexpaq 0:6c56fb4bc5f0 467 break
nexpaq 0:6c56fb4bc5f0 468
nexpaq 0:6c56fb4bc5f0 469 # Merge user code with softdevice
nexpaq 0:6c56fb4bc5f0 470 from intelhex import IntelHex
nexpaq 0:6c56fb4bc5f0 471 binh = IntelHex()
nexpaq 0:6c56fb4bc5f0 472 binh.loadbin(binf, offset=softdevice_and_offset_entry['offset'])
nexpaq 0:6c56fb4bc5f0 473
nexpaq 0:6c56fb4bc5f0 474 if t_self.target.MERGE_SOFT_DEVICE is True:
nexpaq 0:6c56fb4bc5f0 475 t_self.debug("Merge SoftDevice file %s"
nexpaq 0:6c56fb4bc5f0 476 % softdevice_and_offset_entry['name'])
nexpaq 0:6c56fb4bc5f0 477 sdh = IntelHex(sdf)
nexpaq 0:6c56fb4bc5f0 478 binh.merge(sdh)
nexpaq 0:6c56fb4bc5f0 479
nexpaq 0:6c56fb4bc5f0 480 if t_self.target.MERGE_BOOTLOADER is True and blf is not None:
nexpaq 0:6c56fb4bc5f0 481 t_self.debug("Merge BootLoader file %s" % blf)
nexpaq 0:6c56fb4bc5f0 482 blh = IntelHex(blf)
nexpaq 0:6c56fb4bc5f0 483 binh.merge(blh)
nexpaq 0:6c56fb4bc5f0 484
nexpaq 0:6c56fb4bc5f0 485 with open(binf.replace(".bin", ".hex"), "w") as fileout:
nexpaq 0:6c56fb4bc5f0 486 binh.tofile(fileout, format='hex')
nexpaq 0:6c56fb4bc5f0 487
nexpaq 0:6c56fb4bc5f0 488 class NCS36510TargetCode:
nexpaq 0:6c56fb4bc5f0 489 @staticmethod
nexpaq 0:6c56fb4bc5f0 490 def ncs36510_addfib(t_self, resources, elf, binf):
nexpaq 0:6c56fb4bc5f0 491 from tools.add_fib import add_fib_at_start
nexpaq 0:6c56fb4bc5f0 492 print("binf ", binf)
nexpaq 0:6c56fb4bc5f0 493 add_fib_at_start(binf[:-4])
nexpaq 0:6c56fb4bc5f0 494 ################################################################################
nexpaq 0:6c56fb4bc5f0 495
nexpaq 0:6c56fb4bc5f0 496 # Instantiate all public targets
nexpaq 0:6c56fb4bc5f0 497 TARGETS = [Target.get_target(name) for name, value
nexpaq 0:6c56fb4bc5f0 498 in Target.get_json_target_data().items()
nexpaq 0:6c56fb4bc5f0 499 if value.get("public", True)]
nexpaq 0:6c56fb4bc5f0 500
nexpaq 0:6c56fb4bc5f0 501 # Map each target name to its unique instance
nexpaq 0:6c56fb4bc5f0 502 TARGET_MAP = dict([(t.name, t) for t in TARGETS])
nexpaq 0:6c56fb4bc5f0 503
nexpaq 0:6c56fb4bc5f0 504 TARGET_NAMES = TARGET_MAP.keys()
nexpaq 0:6c56fb4bc5f0 505
nexpaq 0:6c56fb4bc5f0 506 # Some targets with different name have the same exporters
nexpaq 0:6c56fb4bc5f0 507 EXPORT_MAP = {}
nexpaq 0:6c56fb4bc5f0 508
nexpaq 0:6c56fb4bc5f0 509 # Detection APIs
nexpaq 0:6c56fb4bc5f0 510 def get_target_detect_codes():
nexpaq 0:6c56fb4bc5f0 511 """ Returns dictionary mapping detect_code -> platform_name
nexpaq 0:6c56fb4bc5f0 512 """
nexpaq 0:6c56fb4bc5f0 513 result = {}
nexpaq 0:6c56fb4bc5f0 514 for target in TARGETS:
nexpaq 0:6c56fb4bc5f0 515 for detect_code in target.detect_code:
nexpaq 0:6c56fb4bc5f0 516 result[detect_code] = target.name
nexpaq 0:6c56fb4bc5f0 517 return result
nexpaq 0:6c56fb4bc5f0 518
nexpaq 0:6c56fb4bc5f0 519 def set_targets_json_location(location=None):
nexpaq 0:6c56fb4bc5f0 520 """Sets the location of the JSON file that contains the targets"""
nexpaq 0:6c56fb4bc5f0 521 # First instruct Target about the new location
nexpaq 0:6c56fb4bc5f0 522 Target.set_targets_json_location(location)
nexpaq 0:6c56fb4bc5f0 523 # Then re-initialize TARGETS, TARGET_MAP and TARGET_NAMES. The
nexpaq 0:6c56fb4bc5f0 524 # re-initialization does not create new variables, it keeps the old ones
nexpaq 0:6c56fb4bc5f0 525 # instead. This ensures compatibility with code that does
nexpaq 0:6c56fb4bc5f0 526 # "from tools.targets import TARGET_NAMES"
nexpaq 0:6c56fb4bc5f0 527 TARGETS[:] = [Target.get_target(target) for target, obj
nexpaq 0:6c56fb4bc5f0 528 in Target.get_json_target_data().items()
nexpaq 0:6c56fb4bc5f0 529 if obj.get("public", True)]
nexpaq 0:6c56fb4bc5f0 530 TARGET_MAP.clear()
nexpaq 0:6c56fb4bc5f0 531 TARGET_MAP.update(dict([(target.name, target) for target in TARGETS]))
nexpaq 0:6c56fb4bc5f0 532 TARGET_NAMES[:] = TARGET_MAP.keys()