66, fetchFromGitHub
77, writeText
88} :
9+ # Construct a minimal STM32CubeN6-based platform environment for building
10+ # nucleo-n657x0-q benchmarks. The package copies only the required Cube headers
11+ # and sources, then patches selected files where needed to get the intended
12+ # RAM-loaded benchmark behavior.
913stdenvNoCC . mkDerivation {
1014 pname = "mlkem-native-nucleo-n657x0-q" ;
1115 version = "main" ;
1216
13- # Fetch STM32CubeN6 (Template + CMSIS headers)
14- # TODO(GAP): Pin rev + hash for reproducibility.
1517 src = fetchFromGitHub {
1618 owner = "STMicroelectronics" ;
1719 repo = "STM32CubeN6" ;
@@ -22,222 +24,168 @@ stdenvNoCC.mkDerivation {
2224
2325 dontBuild = true ;
2426
25- propagatedBuildInputs = [ ] ;
26-
2727 installPhase = ''
2828 set -eu
2929
3030 outp="$out/platform/nucleo-n657x0-q/src/platform"
31- mkdir -p "$outp"
32-
33- tpl="Projects/NUCLEO-N657X0-Q/Templates/Template"
34-
35- if [ ! -d "$tpl" ]; then
36- echo "ERROR: expected Cube template at $tpl"
37- exit 1
38- fi
39-
40- # Copy CMSIS headers needed by system/startup from the Cube tree
41- mkdir -p "$outp/Drivers/CMSIS/Core"
42- mkdir -p "$outp/Drivers/CMSIS/Device"
43-
44- cp -r "Drivers/CMSIS/Core/Include" "$outp/Drivers/CMSIS/Core/"
45- # Ensure m-profile subdir (pmu_armv8.h) is present, as some builds include it directly
46- if [ -d "Drivers/CMSIS/Core/Include/m-profile" ]; then
47- mkdir -p "$outp/Drivers/CMSIS/Core/Include"
48- cp -r "Drivers/CMSIS/Core/Include/m-profile" "$outp/Drivers/CMSIS/Core/Include/" || true
49- fi
50- cp -r "Drivers/CMSIS/Device/ST" "$outp/Drivers/CMSIS/Device/"
51-
52- # Copy startup + system files
53- # Prefer board-specific FSBL-LRUN files explicitly when available.
5431 fsbl_tpl="Projects/NUCLEO-N657X0-Q/Templates/Template_FSBL_LRUN"
55- mkdir -p "$outp/gcc"
56- if [ -d "$fsbl_tpl" ]; then
57- # Explicitly select:
58- # - Startup: STM32CubeIDE/Boot/Startup/startup_stm32n657xx_fsbl.s
59- # - System: FSBL/Src/system_stm32n6xx_fsbl.c
60- # - IT/MSP: FSBL/Src/stm32n6xx_it.c, stm32n6xx_hal_msp.c
61- start_src="$fsbl_tpl/STM32CubeIDE/Boot/Startup/startup_stm32n657xx_fsbl.s"
62- sys_src="$fsbl_tpl/FSBL/Src/system_stm32n6xx_fsbl.c"
63- it_src="$fsbl_tpl/FSBL/Src/stm32n6xx_it.c"
64- msp_src="$fsbl_tpl/FSBL/Src/stm32n6xx_hal_msp.c"
65- if [ -f "$start_src" ]; then
66- # Normalize to canonical name searched by platform.mk
67- cp -v "$start_src" "$outp/gcc/startup_stm32n657xx.S"
68- # Replace the Cube FSBL startup's fixed SRAM initial SP with the
69- # linker-provided stack top so RAM-only tests can use the DTCM stack
70- # selected by their linker script.
71- sed -i.bak -E 's@[.]word[[:space:]]+0x34110000@.word _estack@' "$outp/gcc/startup_stm32n657xx.S"
72- # Disable interrupts immediately on entry to Reset_Handler. The RAM
73- # test image starts after debugger-controlled load/jump, so this keeps
74- # stale board/debug state from delivering an interrupt before C startup
75- # has initialized the test image.
76- sed -i.bak -E '/^Reset_Handler:/a\ cpsid i' "$outp/gcc/startup_stm32n657xx.S"
77- fi
78- if [ -f "$sys_src" ]; then
79- cp -v "$sys_src" "$outp/system_stm32n6xx.c"
80- fi
81- if [ -f "$it_src" ]; then
82- cp -v "$it_src" "$outp/"
83- fi
84- if [ -f "$msp_src" ]; then
85- cp -v "$msp_src" "$outp/"
86- fi
87- else
88- # Generic fallback to CMSIS templates if FSBL files are not located
89- cp -r Drivers/CMSIS/Device/ST/STM32N6xx/Source/Templates/* "$outp" || true
90- cp -r Drivers/CMSIS/Device/ST/STM32N6xx/Source/Templates/gcc/* "$outp/gcc/" || true
91- fi
32+ hal="Drivers/STM32N6xx_HAL_Driver"
33+ cmsis_core="Drivers/CMSIS/Core/Include"
34+ cmsis_device="Drivers/CMSIS/Device/ST/STM32N6xx/Include"
35+
36+ install_file() {
37+ src_file="$1"
38+ dst_file="$outp/$2"
39+ mkdir -p "$(dirname "$dst_file")"
40+ cp "$src_file" "$dst_file"
41+ }
42+
43+ # CMSIS headers reached by stm32n657xx.h/core_cm55.h under the GCC build.
44+ for header in \
45+ cmsis_compiler.h \
46+ cmsis_gcc.h \
47+ cmsis_version.h \
48+ core_cm55.h \
49+ m-profile/armv7m_cachel1.h \
50+ m-profile/armv8m_mpu.h \
51+ m-profile/armv8m_pmu.h \
52+ m-profile/cmsis_gcc_m.h
53+ do
54+ install_file "$cmsis_core/$header" "Drivers/CMSIS/Core/Include/$header"
55+ done
56+
57+ for header in \
58+ stm32n6xx.h \
59+ stm32n657xx.h \
60+ system_stm32n6xx.h
61+ do
62+ install_file "$cmsis_device/$header" "Drivers/CMSIS/Device/ST/STM32N6xx/Include/$header"
63+ done
64+
65+ # FSBL files used by platform.mk.
66+ install_file \
67+ "$fsbl_tpl/STM32CubeIDE/Boot/Startup/startup_stm32n657xx_fsbl.s" \
68+ "gcc/startup_stm32n657xx.S"
69+
70+ # Use the linker-provided stack top instead of Cube's fixed SRAM stack.
71+ sed -i.bak -E 's@[.]word[[:space:]]+0x34110000@.word _estack@' \
72+ "$outp/gcc/startup_stm32n657xx.S"
73+
74+ # Mask interrupts as soon as Reset_Handler starts to avoid stale debug/board
75+ # state firing before this RAM-loaded test image initializes C runtime state.
76+ sed -i.bak -E '/^Reset_Handler:/a\ cpsid i' \
77+ "$outp/gcc/startup_stm32n657xx.S"
78+ rm -f "$outp/gcc/startup_stm32n657xx.S.bak"
79+
80+ install_file "$fsbl_tpl/FSBL/Src/system_stm32n6xx_fsbl.c" "system_stm32n6xx.c"
81+ install_file "$fsbl_tpl/FSBL/Src/stm32n6xx_it.c" "stm32n6xx_it.c"
82+ install_file "$fsbl_tpl/FSBL/Inc/stm32n6xx_it.h" "Inc/stm32n6xx_it.h"
83+ install_file "$fsbl_tpl/FSBL/Inc/main.h" "Inc/main.h"
84+ install_file "$fsbl_tpl/FSBL/Inc/stm32n6xx_hal_conf.h" "Inc/stm32n6xx_hal_conf.h"
9285
93- # Copy HAL driver includes and sources so FSBL files build if they reference HAL symbols
94- mkdir -p "$outp/Drivers/STM32N6xx_HAL_Driver"
95- if [ -d Drivers/STM32N6xx_HAL_Driver/Inc ]; then
96- cp -r Drivers/STM32N6xx_HAL_Driver/Inc "$outp/Drivers/STM32N6xx_HAL_Driver/" || true
97- fi
98- if [ -d Drivers/STM32N6xx_HAL_Driver/Src ]; then
99- cp -r Drivers/STM32N6xx_HAL_Driver/Src "$outp/Drivers/STM32N6xx_HAL_Driver/" || true
100- fi
101- # Guarantee HAL Driver Src exists under output (fallback search if not found in expected path)
102- if [ ! -d "$outp/Drivers/STM32N6xx_HAL_Driver/Src" ]; then
103- alt_hal_dir=$(find Drivers -type d -name 'STM32N6xx_HAL_Driver' -print -quit || true)
104- if [ -n "$alt_hal_dir" ] && [ -d "$alt_hal_dir/Src" ]; then
105- echo "Copying HAL Driver Src from $alt_hal_dir"
106- mkdir -p "$outp/Drivers/STM32N6xx_HAL_Driver"
107- cp -r "$alt_hal_dir/Src" "$outp/Drivers/STM32N6xx_HAL_Driver/" || true
108- fi
109- fi
110-
111-
112- # Copy HAL configuration header, preferring FSBL-LRUN Inc; then disable BSEC and XSPI modules
113- fsbl_inc_conf="$fsbl_tpl/FSBL/Inc/stm32n6xx_hal_conf.h"
114- if [ -f "$fsbl_inc_conf" ]; then
115- mkdir -p "$outp/Inc"
116- cp -v "$fsbl_inc_conf" "$outp/Inc/stm32n6xx_hal_conf.h"
117- # Also provide FSBL interrupt header in include path if present
118- fsbl_it_hdr="$fsbl_tpl/FSBL/Inc/stm32n6xx_it.h"
119- if [ -f "$fsbl_it_hdr" ]; then
120- cp -v "$fsbl_it_hdr" "$outp/Inc/stm32n6xx_it.h"
121- fi
122- # Also provide FSBL main.h in include path if present
123- fsbl_main_hdr="$fsbl_tpl/FSBL/Inc/main.h"
124- if [ -f "$fsbl_main_hdr" ]; then
125- cp -v "$fsbl_main_hdr" "$outp/Inc/main.h"
126- fi
127- else
128- # Fallback: Copy the first hal_conf found under Projects
129- hal_conf=$(find Projects -type f -name 'stm32n6xx_hal_conf.h' | head -n1 || true)
130- if [ -n "$hal_conf" ]; then
131- incdir=$(dirname "$hal_conf")
132- cp -r "$incdir" "$outp/Inc"
133- # Attempt to locate an stm32n6xx_it.h nearby if FSBL header not used
134- it_hdr=$(find "$(dirname "$incdir")" -name 'stm32n6xx_it.h' -type f | head -n1 || true)
135- if [ -n "$it_hdr" ] && [ ! -f "$outp/Inc/stm32n6xx_it.h" ]; then
136- cp -v "$it_hdr" "$outp/Inc/stm32n6xx_it.h"
137- fi
138- # Attempt to locate a main.h nearby if FSBL header not used
139- main_hdr=$(find "$(dirname "$incdir")" -name 'main.h' -type f | head -n1 || true)
140- if [ -n "$main_hdr" ] && [ ! -f "$outp/Inc/main.h" ]; then
141- cp -v "$main_hdr" "$outp/Inc/main.h"
142- fi
143- fi
144- fi
145-
146- # Ensure BSEC and XSPI are disabled for our test build
14786 conf="$outp/Inc/stm32n6xx_hal_conf.h"
148- if [ -f "$conf" ]; then
149- # Comment out any explicit enable lines
150- sed -i.bak -E 's@^\s*#\s*define\s+HAL_BSEC_MODULE_ENABLED@/* #define HAL_BSEC_MODULE_ENABLED */@' "$conf" || true
151- sed -i.bak -E 's@^\s*#\s*define\s+HAL_XSPI_MODULE_ENABLED@/* #define HAL_XSPI_MODULE_ENABLED */@' "$conf" || true
152- # Also handle commented-but-enabled variants
153- sed -i.bak -E 's@^\s*//\s*#\s*define\s+HAL_BSEC_MODULE_ENABLED@/* #define HAL_BSEC_MODULE_ENABLED */@' "$conf" || true
154- sed -i.bak -E 's@^\s*//\s*#\s*define\s+HAL_XSPI_MODULE_ENABLED@/* #define HAL_XSPI_MODULE_ENABLED */@' "$conf" || true
155- sed -i.bak -E 's@^\s*/\*\s*#\s*define\s+HAL_BSEC_MODULE_ENABLED\s*\*/@/* #define HAL_BSEC_MODULE_ENABLED */@' "$conf" || true
156- sed -i.bak -E 's@^\s*/\*\s*#\s*define\s+HAL_XSPI_MODULE_ENABLED\s*\*/@/* #define HAL_XSPI_MODULE_ENABLED */@' "$conf" || true
157- # Belt-and-suspenders: append explicit undefs to override any includes afterward
158- printf "\n#undef HAL_BSEC_MODULE_ENABLED\n#undef HAL_XSPI_MODULE_ENABLED\n" >> "$conf"
159- fi
16087
161- # Extract SystemClock_Config and related user clock snippets from FSBL template into a standalone clock_config.c
88+ # Disable BSEC because the platform test build does not link the BSEC HAL.
89+ sed -i.bak -E 's@^[[:space:]]*#[[:space:]]*define[[:space:]]+HAL_BSEC_MODULE_ENABLED@/* #define HAL_BSEC_MODULE_ENABLED */@' "$conf"
90+
91+ # Disable XSPI because only the extracted clock setup is used, not Cube's
92+ # external memory setup or XSPI HAL driver.
93+ sed -i.bak -E 's@^[[:space:]]*#[[:space:]]*define[[:space:]]+HAL_XSPI_MODULE_ENABLED@/* #define HAL_XSPI_MODULE_ENABLED */@' "$conf"
94+ rm -f "$conf.bak"
95+
96+ # HAL files named directly by platform.mk, plus headers enabled by the
97+ # pruned FSBL HAL config and their direct dependencies.
98+ for header in \
99+ Legacy/stm32_hal_legacy.h \
100+ stm32n6xx_hal.h \
101+ stm32n6xx_hal_cortex.h \
102+ stm32n6xx_hal_def.h \
103+ stm32n6xx_hal_dma.h \
104+ stm32n6xx_hal_dma_ex.h \
105+ stm32n6xx_hal_exti.h \
106+ stm32n6xx_hal_gpio.h \
107+ stm32n6xx_hal_gpio_ex.h \
108+ stm32n6xx_hal_pwr.h \
109+ stm32n6xx_hal_pwr_ex.h \
110+ stm32n6xx_hal_rcc.h \
111+ stm32n6xx_hal_rcc_ex.h \
112+ stm32n6xx_ll_bus.h \
113+ stm32n6xx_ll_rcc.h
114+ do
115+ install_file "$hal/Inc/$header" "Drivers/STM32N6xx_HAL_Driver/Inc/$header"
116+ done
117+
118+ for source in \
119+ stm32n6xx_hal.c \
120+ stm32n6xx_hal_cortex.c \
121+ stm32n6xx_hal_pwr.c \
122+ stm32n6xx_hal_pwr_ex.c \
123+ stm32n6xx_hal_rcc.c \
124+ stm32n6xx_hal_rcc_ex.c
125+ do
126+ install_file "$hal/Src/$source" "Drivers/STM32N6xx_HAL_Driver/Src/$source"
127+ done
128+
162129 fsbl_main_c="$fsbl_tpl/FSBL/Src/main.c"
163130 clock_out="$outp/clock_config.c"
164- if [ -f "$fsbl_main_c" ]; then
165- echo "Generating clock_config.c from $fsbl_main_c"
166- tmpclk="$TMPDIR/clock_config.$$.$RANDOM.c"
167- : > "$tmpclk"
168- # 1) Header block
169- awk '
170- /\/\* USER CODE BEGIN Header \*\// { print; inhdr=1; next }
171- inhdr { print }
172- /\/\* USER CODE END Header \*\// { print; inhdr=0 }
173- ' "$fsbl_main_c" >> "$tmpclk"
174- # 2) Includes lines
175- printf "\n/* Includes ------------------------------------------------------------------*/\n" >> "$tmpclk"
176- printf "#include \"main.h\"\n\n" >> "$tmpclk"
177- # 3) USER CLK 1 block
178- awk '
179- /\/\* USER CODE BEGIN CLK 1 \*\// { print; inclk=1; next }
180- inclk { print }
181- /\/\* USER CODE END CLK 1 \*\// { print; inclk=0 }
182- ' "$fsbl_main_c" >> "$tmpclk"
183- printf "\n" >> "$tmpclk"
184- # 4) SystemClock_Config (try to include preceding comment header if present)
185- awk '
186- BEGIN { copy=0; lvl=0; sig=0 }
187- # Signature with brace on same line
188- /^[ \t]*void[ \t]+SystemClock_Config[ \t]*\([ \t]*void[ \t]*\)[ \t]*\{/ {
189- print; copy=1; lvl=1; next
190- }
191- # Signature line without brace; start copying and wait for opening brace
192- /^[ \t]*void[ \t]+SystemClock_Config[ \t]*\([ \t]*void[ \t]*\)[ \t]*$/ {
193- print; copy=1; sig=1; next
194- }
195- copy {
196- if (sig) {
197- # Print until we see the first brace; then start level tracking
198- if ($0 ~ /\{/) {
199- nopen=gsub(/{/,"{"); nclose=gsub(/}/,"}"); lvl += nopen - nclose; print; sig=0;
200- if (lvl<=0) exit; next
201- }
202- print; next
203- }
204- nopen=gsub(/{/,"{"); nclose=gsub(/}/,"}"); lvl += nopen - nclose; print;
205- if (lvl<=0) exit
206- }
207- ' "$fsbl_main_c" >> "$tmpclk"
208- # Sanity check: ensure we captured the function signature
209- if ! grep -q "SystemClock_Config" "$tmpclk"; then
210- echo "ERROR: Failed to extract SystemClock_Config from $fsbl_main_c" >&2
211- exit 1
212- fi
213- mv "$tmpclk" "$clock_out"
214- # Ensure main.h exists and declares needed prototypes
215- mkdir -p "$outp/Inc"
216- fsbl_main_h="$fsbl_tpl/FSBL/Inc/main.h"
217- dest_main_h="$outp/Inc/main.h"
218- if [ ! -f "$dest_main_h" ] && [ -f "$fsbl_main_h" ]; then
219- cp -v "$fsbl_main_h" "$dest_main_h"
220- fi
221- if [ -f "$dest_main_h" ]; then
222- if ! grep -q "void[[:space:]]\+SystemClock_Config[[:space:]]*([[:space:]]*void[[:space:]]*)" "$dest_main_h"; then
223- printf "\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n" >> "$dest_main_h"
224- printf "void SystemClock_Config(void);\n" >> "$dest_main_h"
225- printf "#ifdef __cplusplus\n}\n#endif\n" >> "$dest_main_h"
226- fi
227- if ! grep -q "void[[:space:]]\+Error_Handler[[:space:]]*([[:space:]]*void[[:space:]]*)" "$dest_main_h"; then
228- printf "void Error_Handler(void);\n" >> "$dest_main_h"
229- fi
230- fi
231- else
232- echo "WARNING: FSBL main.c not found at $fsbl_main_c; skipping clock_config generation" >&2
131+ tmpclk="$TMPDIR/clock_config.$$.$RANDOM.c"
132+ : > "$tmpclk"
133+
134+ # Preserve the Cube file header in the generated standalone clock source.
135+ awk '
136+ /\/\* USER CODE BEGIN Header \*\// { print; inhdr=1; next }
137+ inhdr { print }
138+ /\/\* USER CODE END Header \*\// { inhdr=0 }
139+ ' "$fsbl_main_c" >> "$tmpclk"
140+ printf "\n#include \"main.h\"\n\n" >> "$tmpclk"
141+
142+ # Keep Cube's clock-tree explanatory comment next to SystemClock_Config.
143+ awk '
144+ /\/\* USER CODE BEGIN CLK 1 \*\// { print; inclk=1; next }
145+ inclk { print }
146+ /\/\* USER CODE END CLK 1 \*\// { inclk=0 }
147+ ' "$fsbl_main_c" >> "$tmpclk"
148+ printf "\n" >> "$tmpclk"
149+
150+ # Extract exactly the SystemClock_Config function body from the FSBL main.c
151+ # into the generated clock_config.c, tracking braces so that file does not
152+ # pull in unused FSBL code.
153+ awk '
154+ BEGIN { copy=0; lvl=0; sig=0 }
155+ /^[ \t]*void[ \t]+SystemClock_Config[ \t]*\([ \t]*void[ \t]*\)[ \t]*\{/ {
156+ print; copy=1; lvl=1; next
157+ }
158+ /^[ \t]*void[ \t]+SystemClock_Config[ \t]*\([ \t]*void[ \t]*\)[ \t]*$/ {
159+ print; copy=1; sig=1; next
160+ }
161+ copy {
162+ if (sig && $0 !~ /\{/) { print; next }
163+ nopen=gsub(/{/,"{")
164+ nclose=gsub(/}/,"}")
165+ lvl += nopen - nclose
166+ print
167+ sig=0
168+ if (lvl<=0) exit
169+ }
170+ ' "$fsbl_main_c" >> "$tmpclk"
171+ grep -q "SystemClock_Config" "$tmpclk"
172+ mv "$tmpclk" "$clock_out"
173+
174+ # The standalone clock_config.c calls SystemClock_Config, so make sure the
175+ # copied FSBL main.h exposes the declaration expected by local platform code.
176+ if ! grep -q "void[[:space:]]\+SystemClock_Config[[:space:]]*([[:space:]]*void[[:space:]]*)" "$outp/Inc/main.h"; then
177+ printf "\nvoid SystemClock_Config(void);\n" >> "$outp/Inc/main.h"
233178 fi
234179
235- # The repository linker scripts define RAM-only config/test layouts explicitly.
180+ # SystemClock_Config calls Error_Handler on HAL failures; the implementation
181+ # is provided by the platform test sources, but main.h must declare it.
182+ if ! grep -q "void[[:space:]]\+Error_Handler[[:space:]]*([[:space:]]*void[[:space:]]*)" "$outp/Inc/main.h"; then
183+ printf "void Error_Handler(void);\n" >> "$outp/Inc/main.h"
184+ fi
236185 '' ;
237186
238187 setupHook = writeText "setup-hook.sh" ''
239188 export NUCLEO_N657X0_Q_PATH="$1/platform/nucleo-n657x0-q/src/platform/"
240- # Platform sources only; the devshell provides the OpenOCD runtime backend.
241189 '' ;
242190
243191 meta = {
0 commit comments