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,71 +145,101 @@ 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
182185 try :
186+ # Validate argument dependencies
187+ if args .out_periphconf_hex :
188+ if args .periphconf_address is None :
189+ raise ScriptError ("--periphconf-address is required when --out-periphconf-hex is used" )
190+ if args .periphconf_size is None :
191+ raise ScriptError ("--periphconf-size is required when --out-periphconf-hex is used" )
192+
183193 init_values = DISABLED_VALUE .to_bytes (4 , "little" ) * (c .sizeof (Uicr ) // 4 )
184194 uicr = Uicr .from_buffer_copy (init_values )
185195
186196 uicr .VERSION .MAJOR = UICR_FORMAT_VERSION_MAJOR
187197 uicr .VERSION .MINOR = UICR_FORMAT_VERSION_MINOR
188198
189- kconfig_str = args .in_config .read ()
190- kconfig = parse_kconfig (kconfig_str )
191-
192- edt = pickle .load (args .in_edt_pickle )
199+ # Process periphconf data first and configure UICR completely before creating hex objects
200+ periphconf_hex = IntelHex ()
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 .out_periphconf_hex :
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 periphconf hex object
209+ periphconf_hex .frombytes (periphconf_final , offset = args .periphconf_address )
209210
210- if kconfig . get ( "CONFIG_NRF_HALTIUM_UICR_PERIPHCONF" ) == "y" :
211+ # Configure UICR with periphconf settings
211212 uicr .PERIPHCONF .ENABLE = ENABLED_VALUE
212- uicr .PERIPHCONF .ADDRESS = periphconf_address
213- uicr .PERIPHCONF .MAXCOUNT = math .floor (periphconf_size / 8 )
213+ uicr .PERIPHCONF .ADDRESS = args .periphconf_address
214+
215+ # MAXCOUNT is given in number of 8-byte peripheral
216+ # configuration entries and periphconf_size is given in
217+ # bytes. When setting MAXCOUNT based on the
218+ # periphconf_size we must first assert that
219+ # periphconf_size has not been misconfigured.
220+ if args .periphconf_size % 8 != 0 :
221+ raise ScriptError (
222+ f"args.periphconf_size was { args .periphconf_size } , but must be divisible by 8"
223+ )
214224
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
225+ uicr .PERIPHCONF .MAXCOUNT = args .periphconf_size // 8
222226
227+ # Create UICR hex object with final UICR data
223228 uicr_hex = IntelHex ()
224- uicr_hex .frombytes (bytes (uicr ), offset = uicr_node . regs [ 0 ]. addr )
229+ uicr_hex .frombytes (bytes (uicr ), offset = args . uicr_address )
225230
226- uicr_hex .write_hex_file (args .out_uicr_hex )
231+ # Create merged hex by combining UICR and periphconf hex objects
232+ merged_hex = IntelHex ()
233+ merged_hex .fromdict (uicr_hex .todict ())
227234
228- if args .out_periphconf_hex is not None :
229- periphconf_hex = IntelHex ()
230- periphconf_hex .frombytes (periphconf_final , offset = periphconf_address )
235+ if args .out_periphconf_hex :
231236 periphconf_hex .write_hex_file (args .out_periphconf_hex )
232237
238+ merged_hex .fromdict (periphconf_hex .todict ())
239+
240+ merged_hex .write_hex_file (args .out_merged_hex )
241+ uicr_hex .write_hex_file (args .out_uicr_hex )
242+
233243 except ScriptError as e :
234244 print (f"Error: { e !s} " )
235245 sys .exit (1 )
@@ -270,16 +280,5 @@ def extract_and_combine_periphconfs(elf_files: list[argparse.FileType]) -> bytes
270280 return bytes (final_periphconf )
271281
272282
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-
284283if __name__ == "__main__" :
285284 main ()
0 commit comments