Clone of official tools

Committer:
Anders Blomdell
Date:
Thu Feb 04 17:17:13 2021 +0100
Revision:
47:21ae3e5a7128
Parent:
43:2a7da56ebd24
Add a few normpath calls

Who changed what in which revision?

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