Skip to content

Commit e870a90

Browse files
committed
Added toolchain hooks and support for LPC4088_EA binary generation
A new hooks mechanism (hooks.py) allows various targets to customize part(s) of the build process. This was implemented to allow generation of custom binary images for the EA LPC4088 target, but it should be generic enough to allow other such customizations in the future. For now, only the 'binary' step is hooked in toolchains/arm.py.
1 parent 2cdd41d commit e870a90

File tree

6 files changed

+148
-3
lines changed

6 files changed

+148
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
; *************************************************************
2+
; *** Scatter-Loading Description File generated by uVision ***
3+
; *************************************************************
4+
5+
LR_IROM1 0x00000000 0x00080000 { ; load region size_region
6+
ER_IROM1 0x00000000 0x00080000 { ; load address = execution address
7+
*.o (RESET, +First)
8+
*(InRoot$$Sections)
9+
.ANY (+RO)
10+
}
11+
RW_IRAM1 0x100000E8 0x0000FF18 { ; RW data
12+
.ANY (+RW +ZI)
13+
}
14+
RW_IRAM2 0x20000000 0x00008000 {
15+
.ANY (AHBSRAM1)
16+
}
17+
}
18+
19+
LR_IROM2 0x28000000 0x01000000 {
20+
ER_IROM2 0x28000000 0x01000000 { ; load address = execution address
21+
.ANY (+RO)
22+
}
23+
}
24+

workspace_tools/hooks.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Configurable hooks in the build system. Can be used by various platforms
2+
# to customize the build process.
3+
4+
################################################################################
5+
# Hooks for the various parts of the build process
6+
7+
# Internal mapping of hooks per tool
8+
_hooks = {}
9+
10+
# Internal mapping of running hooks
11+
_running_hooks = {}
12+
13+
# Available hook types
14+
_hook_types = ["binary"]
15+
16+
# Available hook steps
17+
_hook_steps = ["pre", "replace", "post"]
18+
19+
# Hook the given function. Use this function as a decorator
20+
def hook_tool(function):
21+
tool = function.__name__
22+
tool_flag = "_" + tool + "_done"
23+
def wrapper(t_self, *args, **kwargs):
24+
# if a hook for this tool is already running, it's most likely
25+
# coming from a derived class, so don't hook the super class version
26+
if _running_hooks.get(tool, False):
27+
return function(t_self, *args, **kwargs)
28+
_running_hooks[tool] = True
29+
# If this tool isn't hooked, return original function
30+
if not _hooks.has_key(tool):
31+
res = function(t_self, *args, **kwargs)
32+
_running_hooks[tool] = False
33+
return res
34+
tooldesc = _hooks[tool]
35+
setattr(t_self, tool_flag, False)
36+
# If there is a replace hook, execute the replacement instead
37+
if tooldesc.has_key("replace"):
38+
res = tooldesc["replace"](t_self, *args, **kwargs)
39+
# If the replacement has set the "done" flag, exit now
40+
# Otherwise continue as usual
41+
if getattr(t_self, tool_flag, False):
42+
_running_hooks[tool] = False
43+
return res
44+
# Execute pre-function before main function if specified
45+
if tooldesc.has_key("pre"):
46+
tooldesc["pre"](t_self, *args, **kwargs)
47+
# Execute the main function now
48+
res = function(t_self, *args, **kwargs)
49+
# Execute post-function after main function if specified
50+
if tooldesc.has_key("post"):
51+
post_res = tooldesc["post"](t_self, *args, **kwargs)
52+
_running_hooks[tool] = False
53+
return post_res or res
54+
else:
55+
_running_hooks[tool] = False
56+
return res
57+
return wrapper
58+
59+
class Hook:
60+
def __init__(self, target, toolchain):
61+
_hooks.clear()
62+
self.toolchain = toolchain
63+
target.init_hooks(self, toolchain.__class__.__name__)
64+
65+
def hook_add(self, hook_type, hook_step, function):
66+
if not hook_type in _hook_types or not hook_step in _hook_steps:
67+
return False
68+
if not hook_type in _hooks:
69+
_hooks[hook_type] = {}
70+
_hooks[hook_type][hook_step] = function
71+
return True
72+
73+
def hook_add_binary(self, hook_step, function):
74+
return self.hook_add("binary", hook_step, function)
75+
76+
################################################################################
77+

workspace_tools/targets.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
"Cortex-M4" : "M4"
2424
}
2525

26+
import os
27+
import shutil
2628

2729
class Target:
2830
def __init__(self):
@@ -46,6 +48,8 @@ def program_cycle_s(self):
4648
def get_labels(self):
4749
return [self.name, CORE_LABELS[self.core]] + self.extra_labels
4850

51+
def init_hooks(self, hook, toolchain_name):
52+
pass
4953

5054
class LPC2368(Target):
5155
def __init__(self):
@@ -140,6 +144,42 @@ def __init__(self):
140144

141145
self.supported_toolchains = ["ARM", "GCC_CR"]
142146

147+
# Use this target to generate the custom binary image for LPC4088 EA boards
148+
class LPC4088_EA(LPC4088):
149+
def __init__(self):
150+
LPC4088.__init__(self)
151+
152+
def init_hooks(self, hook, toolchain_name):
153+
if toolchain_name in ['ARM_STD', 'ARM_MICRO']:
154+
hook.hook_add_binary("post", self.binary_hook)
155+
156+
@staticmethod
157+
def binary_hook(t_self, elf, binf):
158+
if not os.path.isdir(binf):
159+
# Regular binary file, nothing to do
160+
return
161+
outbin = open(binf + ".temp", "wb")
162+
partf = open(os.path.join(binf, "ER_IROM1"), "rb")
163+
# Pad the fist part (internal flash) with 0xFF to 512k
164+
data = partf.read()
165+
outbin.write(data)
166+
outbin.write('\xFF' * (512*1024 - len(data)))
167+
partf.close()
168+
# Read and append the second part (external flash) in chunks of fixed size
169+
chunksize = 128 * 1024
170+
partf = open(os.path.join(binf, "ER_IROM2"), "rb")
171+
while True:
172+
data = partf.read(chunksize)
173+
outbin.write(data)
174+
if len(data) < chunksize:
175+
break
176+
partf.close()
177+
outbin.close()
178+
# Remove the directory with the binary parts and rename the temporary
179+
# file to 'binf'
180+
shutil.rmtree(binf, True)
181+
os.rename(binf + '.temp', binf)
182+
t_self.debug("Generated custom binary file (internal flash + SPIFI)")
143183

144184
class LPC4330_M4(Target):
145185
def __init__(self):
@@ -254,7 +294,8 @@ def __init__(self):
254294
LPC1347(),
255295
LPC1114(),
256296
LPC11C24(),
257-
LPC11U35_401()
297+
LPC11U35_401(),
298+
LPC4088_EA()
258299
]
259300

260301
# Map each target name to its unique instance

workspace_tools/toolchains/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from workspace_tools.patch import patch
2626
from workspace_tools.settings import BUILD_OPTIONS
2727

28+
import workspace_tools.hooks as hooks
2829

2930
def print_notify(event):
3031
# Default command line notification
@@ -144,6 +145,7 @@ class mbedToolchain:
144145
def __init__(self, target, options=None, notify=None):
145146
self.target = target
146147
self.name = self.__class__.__name__
148+
self.hook = hooks.Hook(target, self)
147149

148150
self.legacy_ignore_dirs = LEGACY_IGNORE_DIRS - set([target.name, LEGACY_TOOLCHAIN_NAMES[self.name]])
149151

workspace_tools/toolchains/arm.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
from workspace_tools.toolchains import mbedToolchain
2121
from workspace_tools.settings import ARM_BIN, ARM_INC, ARM_LIB, MY_ARM_CLIB, ARM_CPPLIB
22-
22+
from workspace_tools.hooks import hook_tool
2323

2424
class ARM(mbedToolchain):
2525
LINKER_EXT = '.sct'
@@ -97,12 +97,13 @@ def archive(self, objects, lib_path):
9797
self.default_cmd([self.ar, '-r', lib_path] + objects)
9898

9999
def link(self, output, objects, libraries, lib_dirs, mem_map):
100-
args = ["-o", output, "--userlibpath", ",".join(lib_dirs), "--info=totals", "--list=.link_totals.txt"]
100+
args = ["-o", output, "--userlibpath", ",".join(lib_dirs), "--info=totals", "--list=.link_totals.txt", "--any_placement=first_fit"]
101101
if mem_map:
102102
args.extend(["--scatter", mem_map])
103103

104104
self.default_cmd(self.ld + args + objects + libraries + self.sys_libs)
105105

106+
@hook_tool
106107
def binary(self, elf, bin):
107108
self.default_cmd([self.elf2bin, '--bin', '-o', bin, elf])
108109

0 commit comments

Comments
 (0)