88import argparse
99import ctypes as c
1010import math
11- import pickle
12- import re
1311import sys
14- from collections import defaultdict
1512from itertools import groupby
1613
1714from elftools .elf .elffile import ELFFile
2522# Must match the name used in the linker script.
2623PERIPHCONF_SECTION = "uicr_periphconf_entry"
2724
28- # Expected nodelabel of the UICR devicetree node, used to extract its location from the devicetree.
29- UICR_NODELABEL = "uicr"
30- # Nodelabel of the PERIPHCONF devicetree node, used to extract its location from the devicetree.
31- PERIPHCONF_NODELABEL = "periphconf_partition"
32-
3325# Common values for representing enabled/disabled in the UICR format.
3426ENABLED_VALUE = 0xFFFF_FFFF
3527DISABLED_VALUE = 0xBD23_28A8
@@ -141,18 +133,6 @@ def main() -> None:
141133 "peripherals, and to protect the device in various ways."
142134 ),
143135 )
144- parser .add_argument (
145- "--in-config" ,
146- required = True ,
147- type = argparse .FileType ("r" ),
148- help = "Path to the .config file from the application build" ,
149- )
150- parser .add_argument (
151- "--in-edt-pickle" ,
152- required = True ,
153- type = argparse .FileType ("rb" ),
154- help = "Path to the edt.pickle file from the application build" ,
155- )
156136 parser .add_argument (
157137 "--in-periphconf-elf" ,
158138 dest = "in_periphconf_elfs" ,
@@ -165,17 +145,40 @@ def main() -> None:
165145 "by ascending address and cleared of duplicate entries."
166146 ),
167147 )
148+ parser .add_argument (
149+ "--out-merged-hex" ,
150+ required = True ,
151+ type = argparse .FileType ("w" , encoding = "utf-8" ),
152+ help = "Path to write the merged UICR+PERIPHCONF HEX file to" ,
153+ )
168154 parser .add_argument (
169155 "--out-uicr-hex" ,
170156 required = True ,
171157 type = argparse .FileType ("w" , encoding = "utf-8" ),
172- help = "Path to write the generated UICR HEX file to" ,
158+ help = "Path to write the UICR-only HEX file to" ,
173159 )
174160 parser .add_argument (
175161 "--out-periphconf-hex" ,
176- default = None ,
177162 type = argparse .FileType ("w" , encoding = "utf-8" ),
178- help = "Path to write the generated PERIPHCONF HEX file to" ,
163+ help = "Path to write the PERIPHCONF-only HEX file to" ,
164+ )
165+ parser .add_argument (
166+ "--periphconf-address" ,
167+ default = None ,
168+ type = lambda s : int (s , 0 ),
169+ help = "Absolute flash address of the PERIPHCONF partition (decimal or 0x-prefixed hex)" ,
170+ )
171+ parser .add_argument (
172+ "--periphconf-size" ,
173+ default = None ,
174+ type = lambda s : int (s , 0 ),
175+ help = "Size in bytes of the PERIPHCONF partition (decimal or 0x-prefixed hex)" ,
176+ )
177+ parser .add_argument (
178+ "--uicr-address" ,
179+ required = True ,
180+ type = lambda s : int (s , 0 ),
181+ help = "Absolute flash address of the UICR region (decimal or 0x-prefixed hex)" ,
179182 )
180183 args = parser .parse_args ()
181184
@@ -186,48 +189,43 @@ def main() -> None:
186189 uicr .VERSION .MAJOR = UICR_FORMAT_VERSION_MAJOR
187190 uicr .VERSION .MINOR = UICR_FORMAT_VERSION_MINOR
188191
189- kconfig_str = args .in_config .read ()
190- kconfig = parse_kconfig (kconfig_str )
192+ # Create separate hex objects
193+ merged_hex = IntelHex ()
194+ uicr_hex = IntelHex ()
195+ periphconf_hex = IntelHex ()
191196
192- edt = pickle .load (args .in_edt_pickle )
197+ # Always add UICR data
198+ uicr_data = bytes (uicr )
199+ uicr_hex .frombytes (uicr_data , offset = args .uicr_address )
200+ merged_hex .frombytes (uicr_data , offset = args .uicr_address )
193201
194- try :
195- periphconf_partition = edt .label2node [PERIPHCONF_NODELABEL ]
196- except LookupError as e :
197- raise ScriptError (
198- "Failed to find a PERIPHCONF partition in the devicetree. "
199- f"Expected a DT node with label '{ PERIPHCONF_NODELABEL } '."
200- ) from e
202+ if args .in_periphconf_elfs : # Check if periphconf data is provided
203+ periphconf_combined = extract_and_combine_periphconfs (args .in_periphconf_elfs )
201204
202- flash_base_address = periphconf_partition .flash_controller .regs [0 ].addr
203- periphconf_address = flash_base_address + periphconf_partition .regs [0 ].addr
204- periphconf_size = periphconf_partition .regs [0 ].size
205+ padding_len = args .periphconf_size - len (periphconf_combined )
206+ periphconf_final = periphconf_combined + bytes ([0xFF for _ in range (padding_len )])
205207
206- periphconf_combined = extract_and_combine_periphconfs ( args . in_periphconf_elfs )
207- padding_len = periphconf_size - len ( periphconf_combined )
208- periphconf_final = periphconf_combined + bytes ([ 0xFF for _ in range ( padding_len )] )
208+ # Add periphconf data to separate and merged hex files
209+ periphconf_hex . frombytes ( periphconf_final , offset = args . periphconf_address )
210+ merged_hex . frombytes ( periphconf_final , offset = args . periphconf_address )
209211
210- if kconfig .get ("CONFIG_NRF_HALTIUM_UICR_PERIPHCONF" ) == "y" :
211212 uicr .PERIPHCONF .ENABLE = ENABLED_VALUE
212- uicr .PERIPHCONF .ADDRESS = periphconf_address
213- uicr .PERIPHCONF .MAXCOUNT = math .floor (periphconf_size / 8 )
214-
215- try :
216- uicr_node = edt .label2node [UICR_NODELABEL ]
217- except LookupError as e :
218- raise ScriptError (
219- "Failed to find UICR node in the devicetree. "
220- f"Expected a DT node with label '{ UICR_NODELABEL } '."
221- ) from e
222-
223- uicr_hex = IntelHex ()
224- uicr_hex .frombytes (bytes (uicr ), offset = uicr_node .regs [0 ].addr )
225-
213+ uicr .PERIPHCONF .ADDRESS = args .periphconf_address
214+ uicr .PERIPHCONF .MAXCOUNT = math .floor (args .periphconf_size / 8 )
215+
216+ # Update UICR hex with the modified UICR data
217+ uicr_data = bytes (uicr )
218+ uicr_hex = IntelHex () # Reset and rebuild with updated UICR
219+ uicr_hex .frombytes (uicr_data , offset = args .uicr_address )
220+ merged_hex = IntelHex () # Reset and rebuild merged
221+ merged_hex .frombytes (uicr_data , offset = args .uicr_address )
222+ merged_hex .frombytes (periphconf_final , offset = args .periphconf_address )
223+
224+ # Write the three hex files
225+ merged_hex .write_hex_file (args .out_merged_hex )
226226 uicr_hex .write_hex_file (args .out_uicr_hex )
227227
228- if args .out_periphconf_hex is not None :
229- periphconf_hex = IntelHex ()
230- periphconf_hex .frombytes (periphconf_final , offset = periphconf_address )
228+ if args .out_periphconf_hex and args .in_periphconf_elfs :
231229 periphconf_hex .write_hex_file (args .out_periphconf_hex )
232230
233231 except ScriptError as e :
@@ -270,16 +268,5 @@ def extract_and_combine_periphconfs(elf_files: list[argparse.FileType]) -> bytes
270268 return bytes (final_periphconf )
271269
272270
273- def parse_kconfig (content : str ) -> dict [str , str | None ]:
274- result = defaultdict (None )
275- match_iter = re .finditer (
276- r"^(?P<config>(SB_)?CONFIG_[^=\s]+)=(?P<value>[^\s#])+$" , content , re .MULTILINE
277- )
278- for match in match_iter :
279- result [match ["config" ]] = match ["value" ]
280-
281- return result
282-
283-
284271if __name__ == "__main__" :
285272 main ()
0 commit comments