Backup 1

Committer:
borlanic
Date:
Tue Apr 24 11:45:18 2018 +0000
Revision:
0:02dd72d1d465
BaBoRo_test2 - backup 1

Who changed what in which revision?

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