Skip to content

Commit 3bda0ef

Browse files
author
Cruz Monrreal
authored
Merge pull request ARMmbed#10021 from bridadan/uvision_postbuild_regions
Enable post build bootloader merging in uvision
2 parents b1e48db + fb6fcc5 commit 3bda0ef

File tree

12 files changed

+192
-23
lines changed

12 files changed

+192
-23
lines changed

tools/export/__init__.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ def get_exporter_toolchain(ide):
136136

137137

138138
def generate_project_files(resources, export_path, target, name, toolchain, ide,
139-
macros=None):
139+
zip, macros=None):
140140
"""Generate the project files for a project
141141
142142
Positional arguments:
@@ -147,13 +147,14 @@ def generate_project_files(resources, export_path, target, name, toolchain, ide,
147147
toolchain - a toolchain class that corresponds to the toolchain used by the
148148
IDE or makefile
149149
ide - IDE name to export to
150+
zip - True if the exported project will be zipped
150151
151152
Optional arguments:
152153
macros - additional macros that should be defined within the exported
153154
project
154155
"""
155156
exporter_cls, _ = get_exporter_toolchain(ide)
156-
exporter = exporter_cls(target, export_path, name, toolchain,
157+
exporter = exporter_cls(target, export_path, name, toolchain, zip,
157158
extra_symbols=macros, resources=resources)
158159
exporter.generate()
159160
files = exporter.generated_files
@@ -278,9 +279,9 @@ def export_project(src_paths, export_path, target, ide, libraries_paths=None,
278279
if toolchain.config.name:
279280
name = toolchain.config.name
280281

281-
files, exporter = generate_project_files(resources, export_path,
282-
target, name, toolchain, ide,
283-
macros=macros)
282+
files, exporter = generate_project_files(
283+
resources, export_path, target, name, toolchain, ide, zip_proj, macros=macros
284+
)
284285
if zip_proj:
285286
resources.add_features(ALLOWED_FEATURES)
286287
if isinstance(zip_proj, basestring):

tools/export/exporters.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,15 @@ class Exporter(object):
7373
CLEAN_FILES = ("GettingStarted.html",)
7474

7575

76-
def __init__(self, target, export_dir, project_name, toolchain,
76+
def __init__(self, target, export_dir, project_name, toolchain, zip,
7777
extra_symbols=None, resources=None):
7878
"""Initialize an instance of class exporter
7979
Positional arguments:
8080
target - the target mcu/board for this project
8181
export_dir - the directory of the exported project files
8282
project_name - the name of the project
8383
toolchain - an instance of class toolchain
84+
zip - True if the exported project will be zipped
8485
8586
Keyword arguments:
8687
extra_symbols - a list of extra macros for the toolchain
@@ -94,6 +95,7 @@ def __init__(self, target, export_dir, project_name, toolchain,
9495
self.jinja_environment = Environment(loader=jinja_loader)
9596
resources.win_to_unix()
9697
self.resources = resources
98+
self.zip = zip
9799
self.generated_files = []
98100
getting_started_name = "GettingStarted.html"
99101
dot_mbed_name = ".mbed"

tools/export/uvision/__init__.py

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
from builtins import str
33

44
import os
5-
from os.path import normpath, exists, dirname
5+
from os.path import normpath, exists, dirname, join, abspath, relpath
66
import ntpath
77
import copy
88
from collections import namedtuple
99
import shutil
1010
from subprocess import Popen, PIPE
1111
import re
12+
import json
1213

1314
from tools.resources import FileType
1415
from tools.targets import TARGET_MAP, CORE_ARCH
@@ -243,7 +244,31 @@ def generate(self):
243244
'include_paths': ';'.join(self.filter_dot(d) for d in
244245
self.resources.inc_dirs),
245246
'device': DeviceUvision(self.target),
247+
'postbuild_step_active': 0,
246248
}
249+
250+
if self.toolchain.config.has_regions and not self.zip:
251+
# Serialize region information
252+
export_info = {}
253+
restrict_size = getattr(self.toolchain.config.target, "restrict_size")
254+
if restrict_size:
255+
export_info["target"] = {
256+
"restrict_size": restrict_size
257+
}
258+
259+
binary_path = "BUILD/{}.hex".format(self.project_name)
260+
region_list = list(self.toolchain.config.regions)
261+
export_info["region_list"] = [
262+
r._replace(filename=binary_path) if r.active else r for r in region_list
263+
]
264+
# Enable the post build step
265+
postbuild_script_path = join(relpath(dirname(__file__)), "postbuild.py")
266+
ctx['postbuild_step'] = (
267+
'python {} "$K\\" "#L"'.format(postbuild_script_path)
268+
)
269+
ctx['postbuild_step_active'] = 1
270+
ctx['export_info'] = json.dumps(export_info, indent=4)
271+
247272
sct_file_ref = self.resources.get_file_refs(FileType.LD_SCRIPT)[0]
248273
sct_file_ref = self.toolchain.correct_scatter_shebang(
249274
sct_file_ref, dirname(sct_file_ref.name)
@@ -271,10 +296,29 @@ def generate(self):
271296
'uvision/uvision_debug.tmpl', ctx, self.project_name + ".uvoptx"
272297
)
273298

299+
if ctx['postbuild_step_active']:
300+
self.gen_file(
301+
'uvision/debug_init.ini', ctx, 'debug_init.ini'
302+
)
303+
self.gen_file(
304+
'uvision/flash_init.ini', ctx, 'flash_init.ini'
305+
)
306+
self.gen_file(
307+
'uvision/export_info.tmpl', ctx, 'export_info.json'
308+
)
309+
274310
@staticmethod
275311
def clean(project_name):
276312
os.remove(project_name + ".uvprojx")
277313
os.remove(project_name + ".uvoptx")
314+
315+
if exists("export_info.json"):
316+
os.remove("export_info.json")
317+
if exists("debug_init.ini"):
318+
os.remove("debug_init.ini")
319+
if exists("flash_init.ini"):
320+
os.remove("flash_init.ini")
321+
278322
# legacy .build directory cleaned if exists
279323
if exists('.build'):
280324
shutil.rmtree('.build')

tools/export/uvision/debug_init.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Add the debug symbols
2+
Load "[email protected]" NOCODE

tools/export/uvision/export_info.tmpl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{{export_info}}

tools/export/uvision/flash_init.ini

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Flash device
2+
Load "$L@L_combined.hex" INCREMENTAL

tools/export/uvision/postbuild.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
#! /usr/bin/env python2
2+
"""
3+
mbed SDK
4+
Copyright (c) 2019 ARM Limited
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
18+
LIBRARIES BUILD
19+
"""
20+
from __future__ import print_function, division, absolute_import
21+
22+
import sys
23+
from os.path import join, abspath, dirname, normpath
24+
import json
25+
from shutil import copyfile
26+
from argparse import ArgumentParser
27+
from copy import copy
28+
29+
# Be sure that the tools directory is in the search path
30+
ROOT = abspath(join(dirname(__file__), "../../../"))
31+
sys.path.insert(0, ROOT)
32+
33+
from tools.regions import merge_region_list, UPDATE_WHITELIST
34+
from tools.notifier.term import TerminalNotifier
35+
from tools.config import Region
36+
from tools.utils import split_path, run_cmd_ext, generate_update_filename
37+
38+
39+
if __name__ == "__main__":
40+
parser = ArgumentParser()
41+
42+
parser.add_argument(
43+
"toolchain_path",
44+
help="Path to the Keil folder"
45+
)
46+
47+
parser.add_argument(
48+
"linker_output",
49+
help="Path to the built axf file"
50+
)
51+
52+
options = parser.parse_args()
53+
axf_file = normpath(options.linker_output)
54+
output_directory, output_name, output_ext = split_path(axf_file)
55+
hex_file = join(output_directory, output_name + ".hex")
56+
combined_hex_file = join(output_directory, output_name + "_combined.hex")
57+
58+
command = [
59+
join(normpath(options.toolchain_path), "ARM/ARMCC/bin/fromelf.exe"),
60+
"--i32", "--output", hex_file, axf_file
61+
]
62+
stdout, stderr, retcode = run_cmd_ext(command)
63+
64+
if retcode:
65+
err_msg = (
66+
"Failed to convert axf to hex.\r\n"
67+
"Command: {}\r\n"
68+
"retcode: {}\r\n"
69+
"stdout: {}\r\n"
70+
"stderr: {}"
71+
).format(command, retcode, stdout, stderr)
72+
raise Exception(err_msg)
73+
74+
with open(join("export_info.json"), "r") as export_info_file:
75+
export_info_data = json.load(export_info_file)
76+
77+
region_list = [Region(*r) for r in export_info_data.get("region_list", [])]
78+
79+
for index, region in enumerate(copy(region_list)):
80+
if region.name == "application":
81+
region_data = region._asdict()
82+
region_data["filename"] = hex_file
83+
region_list[index] = Region(**region_data)
84+
break
85+
else:
86+
raise Exception("No application region found")
87+
88+
notify = TerminalNotifier()
89+
restrict_size = export_info_data.get("target", {}).get("restrict_size")
90+
merge_region_list(
91+
region_list, combined_hex_file, notify, restrict_size=restrict_size
92+
)
93+
94+
update_regions = [
95+
r for r in region_list if r.name in UPDATE_WHITELIST
96+
]
97+
98+
if update_regions:
99+
update_res = normpath(
100+
join(
101+
output_directory,
102+
generate_update_filename(output_name, None)
103+
)
104+
)
105+
merge_region_list(
106+
update_regions, update_res, notify, restrict_size=restrict_size
107+
)
108+
109+
sys.exit(0)

tools/export/uvision/uvision.tmpl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,9 @@
8282
<nStopB2X>0</nStopB2X>
8383
</BeforeMake>
8484
<AfterMake>
85-
<RunUserProg1>0</RunUserProg1>
85+
<RunUserProg1>{{postbuild_step_active}}</RunUserProg1>
8686
<RunUserProg2>0</RunUserProg2>
87-
<UserProg1Name></UserProg1Name>
87+
<UserProg1Name>{{postbuild_step if postbuild_step_active else ''}}</UserProg1Name>
8888
<UserProg2Name></UserProg2Name>
8989
<UserProg1Dos16Mode>0</UserProg1Dos16Mode>
9090
<UserProg2Dos16Mode>0</UserProg2Dos16Mode>
@@ -182,7 +182,7 @@
182182
<bUseTDR>1</bUseTDR>
183183
<Flash2>BIN\UL2CM3.DLL</Flash2>
184184
<Flash3></Flash3>
185-
<Flash4></Flash4>
185+
<Flash4>{{'./flash_init.ini' if postbuild_step_active else ''}}</Flash4>
186186
<pFcarmOut></pFcarmOut>
187187
<pFcarmGrp></pFcarmGrp>
188188
<pFcArmRoot></pFcArmRoot>

tools/export/uvision/uvision_debug.tmpl

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,20 @@
66
<ToolsetNumber>0x4</ToolsetNumber>
77
<ToolsetName>ARM-ADS</ToolsetName>
88
<TargetOption>
9+
{% if postbuild_step_active %}
10+
<OPTTT>
11+
<RunAbUc>1</RunAbUc>
12+
</OPTTT>
13+
{% endif %}
914
<DebugOpt>
1015
<uSim>0</uSim>
1116
<uTrg>1</uTrg>
1217
<nTsel>11</nTsel>
1318
<pMon>{{device.debug_interface.bin_loc}}</pMon>
19+
{% if postbuild_step_active %}
20+
<tIfile>./debug_init.ini</tIfile>
21+
<tLdApp>0</tLdApp>
22+
{% endif %}
1423
</DebugOpt>
1524
<TargetDriverDllRegistry>
1625
<SetRegEntry>
@@ -21,4 +30,4 @@
2130
</TargetDriverDllRegistry>
2231
</TargetOption>
2332
</Target>
24-
</ProjectOpt>
33+
</ProjectOpt>

tools/regions.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,15 +106,16 @@ def merge_region_list(
106106
region_list,
107107
destination,
108108
notify,
109-
config,
110-
padding=b'\xFF'
109+
padding=b'\xFF',
110+
restrict_size=None
111111
):
112112
"""Merge the region_list into a single image
113113
114114
Positional Arguments:
115115
region_list - list of regions, which should contain filenames
116116
destination - file name to write all regions to
117117
padding - bytes to fill gaps with
118+
restrict_size - check to ensure a region fits within the given size
118119
"""
119120
merged = IntelHex()
120121
_, format = splitext(destination)
@@ -145,7 +146,7 @@ def merge_region_list(
145146
# Normally, we assume that part.maxddr() can be beyond
146147
# end of rom. If the size is restricted with config, don't
147148
# allow this.
148-
if config.target.restrict_size is not None:
149+
if restrict_size is not None:
149150
part_size = (part.maxaddr() - part.minaddr()) + 1
150151
if part_size > region.size:
151152
raise ToolException(

0 commit comments

Comments
 (0)