Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
153 commits
Select commit Hold shift + click to select a range
148015a
silicon: NUCLEO-G474RE anchor protocol scaffolding (board-prep)
avrabe May 3, 2026
92765ff
fix(silicon): repair capture.sh --help and manifest csv_sha256 escaping
avrabe May 9, 2026
cbda915
silicon: add tick-source axis (systick / lptim) for 4-run anchor matrix
avrabe May 9, 2026
aa94832
silicon: smart-data emission — DWT counters + STM32G4 MCU health
avrabe May 9, 2026
d6fb524
ci: trigger workflows after PR base retarget
avrabe May 9, 2026
3aa74c1
silicon: enable CONFIG_ADC on nucleo_g474re bench overlay
avrabe May 9, 2026
0651509
fix(silicon): LPTIM kernel-tick needs CONFIG_PM=y, not CORTEX_M_SYSTI…
avrabe May 9, 2026
af7778f
fix(bench): repair reader_loop hang and per-step drain when ISR drops…
avrabe May 10, 2026
9da0cbb
silicon: capture.sh — default --runner openocd, explicit post-flash r…
avrabe May 10, 2026
63de330
silicon(runs): first NUCLEO-G474RE anchor — baseline + gale × systick
avrabe May 10, 2026
4547580
silicon: bump LPUART1 baud 115200→921600 to drop the drop-bias
avrabe May 10, 2026
a9075a3
Revert "silicon: bump LPUART1 baud 115200→921600 to drop the drop-bias"
avrabe May 10, 2026
8a4d817
fix(bench): bigger ring (256→2048) so silicon-anchor captures don't drop
avrabe May 10, 2026
418c6b8
silicon(runs): publication-grade NUCLEO-G474RE anchor — drops=0
avrabe May 10, 2026
fd15738
silicon(runs): synth-Gale on G474RE — Renode's −34.5% delta is a TB a…
avrabe May 10, 2026
b48a81a
silicon: document LLVM-LTO build crash on G474RE (ADC IRQ 18 spurious)
avrabe May 10, 2026
f6f6128
silicon(runs): LTO + ADC=n controls — LTO recovers FFI seam, beats ba…
avrabe May 10, 2026
3730bdc
silicon(runs): LTO+ADC=y on G474RE — fixed via dropping ISR_TABLES_LO…
avrabe May 10, 2026
35f90fb
silicon: wasm-cross-LTO spike — pipeline works, codegen gap to LTO do…
avrabe May 10, 2026
f6db15e
silicon: wasm-cross-LTO spike — full integration attempt + 3rd synth bug
avrabe May 10, 2026
a4beaeb
silicon: link wasm-cross-LTO notes to upstream issues filed in synth …
avrabe May 10, 2026
e537f8b
silicon: wasm-cross-LTO multi-target testbed + ARM/RISC-V silicon res…
avrabe Jun 3, 2026
6f4d0e5
Merge remote-tracking branch 'origin/main' into feat/silicon-smart-data
avrabe Jun 3, 2026
7df8f0f
silicon(riscv): full RISC-V wasm-cross-LTO table — all 4 fns correct …
avrabe Jun 3, 2026
33b56bb
fix(engine_control): gate 2048-sample ring on STM32G4 (fixes QEMU smo…
avrabe Jun 3, 2026
0ba530f
testbed(riscv): add RV32 functional regression lane (catches synth #232)
avrabe Jun 3, 2026
99cbda8
runs(riscv): v0.11.27 four-leaf re-measure (Opt3 #1 + #232 div fix va…
avrabe Jun 3, 2026
530443d
notes: v0.11.27 composed-path codegen breakdown (Opt3 increment #2 ta…
avrabe Jun 3, 2026
f0bfea7
testbed(riscv): expand RV32 funccheck to 10 edge vectors (const-CSE net)
avrabe Jun 3, 2026
fe4fc52
testbed(arm): add ARM functional lane (arm_funccheck.py) + document s…
avrabe Jun 3, 2026
3442160
docs(testbed): document arm_funccheck.py + synth ARM r0..r7 arg ABI i…
avrabe Jun 3, 2026
465e974
testbed: Phase-5 flight_control wasm-cross-LTO readiness (real contro…
avrabe Jun 3, 2026
ee6aa53
testbed: Phase-5 flight_control bench verified functional + dissolved…
avrabe Jun 3, 2026
e5a2fe5
bench(flight_control): add opt-in GALE_FC_WASM_LTO variant (Phase 5)
avrabe Jun 3, 2026
935f9ed
notes: flight_control wasm-LTO variant validated running on real G474…
avrabe Jun 3, 2026
645bd67
wasm-lto(mutex): add dissolvable k_mutex_unlock shim + gale_w_current…
avrabe Jun 4, 2026
f7e1ce9
notes(mutex): wasm-cross-LTO seam dissolution PROVEN for the mutex pr…
avrabe Jun 4, 2026
a8cfa46
wasm-lto(mutex): integration scaffolding (guard + GALE_WASM_LTO_MUTEX…
avrabe Jun 4, 2026
67c5a0e
notes(mutex): integration wired, link blocked on synth#235 (ET_REL he…
avrabe Jun 4, 2026
5254aaf
notes(mutex): UNBLOCKED by synth v0.11.28 - links + runs on G474RE
avrabe Jun 4, 2026
f3bcdec
notes(mutex): v0.11.28 links it but drop-in faults on silicon — filed…
avrabe Jun 4, 2026
6b57f69
repro(synth#237): faulting dissolved mutex .o + loom.wasm (no .data s…
avrabe Jun 4, 2026
03316e9
testbed(mutex): stage one-command wasm-cross-LTO re-measurement for s…
avrabe Jun 4, 2026
e6754c2
testbed: consolidated wasm-cross-LTO RESULTS-SUMMARY (single referenc…
avrabe Jun 4, 2026
73a5548
repro(synth#237): v0.11.29 --native-pointer-abi mutex .o still faults…
avrabe Jun 4, 2026
595314d
testbed(mutex): harden remeasure script (set -e tolerant capture loop)
avrabe Jun 4, 2026
f027273
repro(synth#237): v0.11.29+BSS-fix(34dfd97) mutex STILL no .bss/MOVW-…
avrabe Jun 4, 2026
c2d35a6
notes(wasm-lto): mutex root cause = linmem stack; answered #237 desig…
avrabe Jun 4, 2026
9895cb0
notes(wasm-lto): ABI design call — self-contained __synth_wasm_data-r…
avrabe Jun 4, 2026
afff83f
notes(wasm-lto): oracle-validate self-contained pass; sizing caveat (…
avrabe Jun 4, 2026
3643985
notes(wasm-lto): v0.11.29 = data-statics only; mutex byte-identical, …
avrabe Jun 4, 2026
072a5e4
test(wasm-lto): PR#240 on G474RE — object-correct but callees fault (…
avrabe Jun 4, 2026
f8e8cba
bench(wasm-lto): controller_step ARM silicon 169/61=2.77x; synth r0-r…
avrabe Jun 4, 2026
2687a90
notes(wasm-lto): v0.11.30 merged (leaf only); HW shows gmutex oracle …
avrabe Jun 4, 2026
c53d89f
opt(wasm-lto): refresh #209 const-CSE/spill data (61% redundant), lin…
avrabe Jun 4, 2026
8c004a2
notes(wasm-lto): PR#243 liveness merged (byte-identical, no regressio…
avrabe Jun 4, 2026
a377699
bench(wasm-lto): flat_flight ARM microbench + CORRECT baseline 262/2.…
avrabe Jun 4, 2026
33d6d49
notes(wasm-lto): nudge GI-NPA-003 (mutex callee, stalled); #247 test-…
avrabe Jun 4, 2026
133cb3a
opt(wasm-lto): full 262->103 gap decomposition — clamp-lowering + mla…
avrabe Jun 4, 2026
fe10e68
test(wasm-lto): first codegen-application delta on silicon — PR#250 A…
avrabe Jun 4, 2026
993f812
notes(wasm-lto): immediate-fold family complete (net -1cyc); #252 no-…
avrabe Jun 4, 2026
839e2d5
notes(wasm-lto): encoder merge batch no-op on gale; filed #255 (CMP/A…
avrabe Jun 4, 2026
21b8d9d
notes(wasm-lto): #255 fixed by #256 (~1h); exact const-CSE target (cl…
avrabe Jun 4, 2026
dc9f455
bench(wasm-lto): flight_control macro bench (Phase 5) validated on si…
avrabe Jun 4, 2026
eab21d7
notes(wasm-lto): quiet period; filed #257 (mul+add->mla fusion, lever…
avrabe Jun 4, 2026
249e662
notes(wasm-lto): filed #258 (clamp-lowering, lever #3) — full 262->10…
avrabe Jun 5, 2026
ae05e42
notes(wasm-lto): filed #259 (load/store imm12 bounds-check); independ…
avrabe Jun 5, 2026
2c973f5
notes(wasm-lto): #259 fixed by #261 (byte-identical, no regression); …
avrabe Jun 5, 2026
70b3206
bench(wasm-lto): lever #3 (clamp cmp/cmn fold #258/#262) landed — fla…
avrabe Jun 5, 2026
1087af3
notes(wasm-lto): v0.11.31 — mla wired but fires 0x on real flat_fligh…
avrabe Jun 5, 2026
f7ef87b
bench(wasm-lto): mla fires (PR#274) but silicon regresses 255->257 (+…
avrabe Jun 5, 2026
223e9b0
bench(wasm-lto): v0.11.32 mla MIXED on silicon — filter_axis 37->36 w…
avrabe Jun 5, 2026
f8dd53b
bench(wasm-lto): mla regression RESOLVED — maintainer un-wired (PR#27…
avrabe Jun 5, 2026
80a0aba
bench(wasm-lto): control_step ARM microbench (the directive's named e…
avrabe Jun 5, 2026
010f545
bench(wasm-lto): v0.11.34 full-suite mla data — control_step also a w…
avrabe Jun 5, 2026
5fbfc9e
notes(wasm-lto): MILESTONE — maintainer routes const-CSE+mla through …
avrabe Jun 5, 2026
cb1c032
bench(wasm-lto): PR#283 in-place select — BIGGEST lever, flat_flight …
avrabe Jun 6, 2026
2a06414
summary(wasm-lto): #283 in-place select merged — new baselines flat_f…
avrabe Jun 6, 2026
5a45b5f
summary(wasm-lto): controller_step 169->150 (was stale; #250/#258/#28…
avrabe Jun 6, 2026
53ee095
silicon: v0.11.35 validation (cycle-neutral, -6% code) + #288 realloc…
avrabe Jun 10, 2026
5d2d515
notes: v0.11.36 incoming (flag ON + dead-save elim) — pre-tag cycle p…
avrabe Jun 10, 2026
3028cea
silicon: PR #309 pre-merge validation — filter -8 cyc uniform (29/21/…
avrabe Jun 10, 2026
c3b6c59
silicon: sem 907 provenance broken — shim passed NULL wait_q + skewed…
avrabe Jun 10, 2026
ff8b14c
silicon: sem hang isolated -> synth#311 (i64 unpack clobbers live u64…
avrabe Jun 10, 2026
8daf29e
testbed: i64-unpack differential lane (synth#311 guard) — wasmtime-vs…
avrabe Jun 10, 2026
3aa56c3
notes: #311 bisected to v0.11.18/#214 (R12 reservation removed the sc…
avrabe Jun 10, 2026
87dd190
notes: synth#312 filed — RV32 i64 local.tee rejection; packed-u64 dec…
avrabe Jun 10, 2026
94f504a
silicon(rv32): v0.11.35 re-baseline — flat_flight 181->172, filter/co…
avrabe Jun 10, 2026
f86d48e
notes: PR #310 pre-merge test — call-form fixed; inlined shape = i64.…
avrabe Jun 10, 2026
19b2b0a
silicon(rv32): controller_step 100 on v0.11.35 — table complete (only…
avrabe Jun 10, 2026
82ad785
notes: #311 defect #3 (callee i64 return lo-half only) + loom#198 (v1…
avrabe Jun 10, 2026
dda493c
notes: v0.11.36/37 verified (u64 GREEN, gates PASS, filter 29/21/22 s…
avrabe Jun 11, 2026
820d4f5
silicon: SOUND sem re-baseline 860 cyc (v0.11.37 faithful shim, n=148…
avrabe Jun 11, 2026
7520ad3
testbed: u64 lane grows the RV32 leg — wasm/ARM/RV32 three-way differ…
avrabe Jun 11, 2026
8fd0226
notes: mutex lane blocked by v0.11.36+ register exhaustion (pair-tagg…
avrabe Jun 11, 2026
8630e01
silicon(mutex): v0.11.40 unblocks the lane (#326 verified); fix TWO s…
avrabe Jun 11, 2026
6df356c
notes: retract #326 encoding false-alarm (flat-link harness artifact,…
avrabe Jun 13, 2026
d2a041e
notes: mutex owner=0x1 = real on-silicon failure in unlock-body tail …
avrabe Jun 13, 2026
21bb9d1
notes: gdb confirms mutex unlock body executes correctly (sp balanced…
avrabe Jun 13, 2026
7122dd1
notes: mutex residual sharpened — DWARF confirms offsets, lock_count@…
avrabe Jun 13, 2026
dab0b15
notes: mutex lane blocker characterized (single-unlock OK, 200x measu…
avrabe Jun 13, 2026
4b3a6aa
notes: mutex measure-loop = DEADLOCK (idle thread, lock_count=1/owner…
avrabe Jun 13, 2026
53e44a8
notes: mutex deadlock ATTRIBUTED to synth spill-slot collision (synth…
avrabe Jun 13, 2026
8b57173
notes: optimize thread — quantified compare->select flag round-trip (…
avrabe Jun 13, 2026
f76de53
notes: optimize thread — headline sem overhead breakdown (flag-fold r…
avrabe Jun 13, 2026
2bfd34a
notes: synth#331 answered by maintainer -> delivered committed failin…
avrabe Jun 13, 2026
8588a6a
measure: control_step re-measured on G474RE at v0.11.40 = 151/67 (2.2…
avrabe Jun 13, 2026
68126ac
measure+triage: flat_flight re-measured at v0.11.40 = 241/103 (2.34x,…
avrabe Jun 13, 2026
dfc6cef
🎯 mutex MEASURED: k_mutex_unlock wasm-cross-LTO = 501/124 (4.04x) on …
avrabe Jun 13, 2026
a6b50bc
notes: v0.11.41 installed + body-of-work regression-clean (testbed gr…
avrabe Jun 13, 2026
ec93aef
testbed: add kernel-primitives codegen lane (k_sem_give + k_mutex_unl…
avrabe Jun 13, 2026
b2604b7
notes: testbed primitives lane + #331 guard added
avrabe Jun 13, 2026
66ad30d
measure: flight_control Phase-5 macro bench re-confirmed on v0.11.41 …
avrabe Jun 13, 2026
2142bac
notes: Phase-5 macro bench re-confirmed v0.11.41 (algo 157, ~11% in-c…
avrabe Jun 13, 2026
5b7c579
notes: shippable mutex wasm module -> gale PR #60 (shim+tramp+dist bu…
avrabe Jun 13, 2026
b7c3289
notes: mutex module #60 completed (consume wiring) + 2 bugs caught by…
avrabe Jun 13, 2026
572bae6
notes: PR #60 mutex module faults in full mutex_api (MOVW_ABS __synth…
avrabe Jun 13, 2026
0f2bc91
notes: PR#60 fault narrowed — objcopy + synth-reloc ruled out; link-c…
avrabe Jun 13, 2026
953d0d3
notes: PR#60 root cause = decide struct-return forces wasm sret/linme…
avrabe Jun 13, 2026
b77b39d
notes: PR#60 u64-repack TESTED on scratch — removes __synth_globals r…
avrabe Jun 13, 2026
23726b9
notes: filed synth#345 (dissolved-object 64KB-linmem + abs-MOVW = PR#…
avrabe Jun 13, 2026
b65b140
measure: controller_step v0.11.41 = 150/61 (2.46x, 6 flag-folds/3 spi…
avrabe Jun 13, 2026
6db7b4f
notes: v0.11.42 installed + regression-clean (testbed green; sem/cont…
avrabe Jun 13, 2026
7a4a5f7
notes: FFI decide ABI survey (5 u64 / 51 struct) -> #345 blast radius…
avrabe Jun 13, 2026
0ad45e2
notes: maintainer registered #345 blast radius (building .bss-first);…
avrabe Jun 14, 2026
2ad16fd
notes: ruled out --native-pointer-abi-drop workaround on hardware — w…
avrabe Jun 14, 2026
eb5baad
stage: verify_mutex_module_silicon.sh — #345 kill-criterion harness (…
avrabe Jun 14, 2026
be9da04
notes: dry-ran #345 harness on v0.11.42 — mechanics validated (instan…
avrabe Jun 14, 2026
d471ba2
notes: sem_take verified sem-shaped (gate-2 pass, .data=0/0 relocs; k…
avrabe Jun 14, 2026
8812af5
notes: sem_take gate-2 re-verified with faithful 2-arg decide (correc…
avrabe Jun 14, 2026
2c4cdf5
notes: sem_take module precisely scoped (5 files incl new shared gale…
avrabe Jun 14, 2026
7eb3b00
notes: loom#142 FIXED (#216, diagnosis confirmed — v1.1.13 ships bina…
avrabe Jun 14, 2026
2dbbc5f
notes: synth 0.11.42 tested (control_step 354B IDENTICAL, no reflash)…
avrabe Jun 14, 2026
69bbe80
testbed: pipe_write is 2nd clean u64 drop-in — gate-2 VERIFIED sem-sh…
avrabe Jun 14, 2026
2e9f09d
testbed: pipe_read gate-2 also sem-shaped -> pipe verified clean BOTH…
avrabe Jun 14, 2026
6a06a3b
testbed: sem_take gate-2 clean -> sem primitive COMPLETE (give+take) …
avrabe Jun 14, 2026
f5a874e
notes: #345 VERIFIED FIXED on G474RE (v0.11.43, reloc MOVW_ABS 22->0)…
avrabe Jun 14, 2026
66464f0
notes: gale#62 FIXED + verified on G474RE — wasm-LTO mutex module pas…
avrabe Jun 14, 2026
ad75923
results: mutex_unlock re-measured on v0.11.43 = 472 cyc (was 501, -5.…
avrabe Jun 14, 2026
b8ad825
notes: sem .o byte-diff on v0.11.43 = IDENTICAL (540B, 20/230/6/284) …
avrabe Jun 14, 2026
6af495e
testbed: k_fatal gate-2 clean -> u64-clean partition 5/5 complete (se…
avrabe Jun 14, 2026
1b64837
notes: full v0.11.43 byte-diff sweep — algos all IDENTICAL (control_s…
avrabe Jun 14, 2026
07d492c
testbed: stack_push hits synth#350 (ARM 'ADD immediate too large') ->…
avrabe Jun 14, 2026
fece55f
notes: synth#350 blast radius = stack+msgq only (bounded-buffer decid…
avrabe Jun 14, 2026
75c7a3e
testbed: stage synth#350 kill-criterion re-survey (resurvey_struct_re…
avrabe Jun 14, 2026
fd80c59
notes: synth#350 fix landing (PR#351 merged + #352 R12 follow-up; rel…
avrabe Jun 14, 2026
d4f0873
notes: synth#350 VERIFIED FIXED v0.11.44 (stack/msgq compile, re-surv…
avrabe Jun 14, 2026
04455ed
notes: synth#354 blast radius = stack+msgq (2-page linmem w/ high-off…
avrabe Jun 14, 2026
6b1db02
testbed: extend struct-return re-survey with #354 .data-bound gate (m…
avrabe Jun 14, 2026
9069f8f
testbed: flight_control bench now runs dissolved algo+sem on G474RE (…
avrabe Jun 14, 2026
e4606da
testbed: flight_control runs algo+sem+MUTEX ALL dissolved on G474RE, …
avrabe Jun 14, 2026
5ef9e81
notes: synth#354 VERIFIED FIXED v0.11.45 (msgq .data 65556->20, stack…
avrabe Jun 14, 2026
8701da8
opt: file loom#219 (seam-SROA: dissolve the u64 ABI pack/unpack post-…
avrabe Jun 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions benches/engine_control/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,21 @@ target_sources(app PRIVATE
src/main.c
src/control.c
src/tables.c
src/smart_dwt.c
)
target_include_directories(app PRIVATE src)

# MCU self-monitoring backend: vendor-specific where we have one AND
# the ADC is enabled. The G4 backend uses Zephyr's ADC API; on builds
# that explicitly disable ADC (e.g. the LTO experiments where the
# ADC IRQ-table interaction crashes the chip), fall back to the stub
# so the CSV row format stays uniform regardless of the variant.
if(CONFIG_SOC_SERIES_STM32G4X AND CONFIG_ADC)
target_sources(app PRIVATE src/smart_mcu_g4.c)
else()
target_sources(app PRIVATE src/smart_mcu_stub.c)
endif()

# -DENGINE_BENCH_TOTAL_SAMPLES=N on the west build line becomes
# -DTOTAL_SAMPLES=N to the compiler. Default is 150 (QEMU smoke-test
# friendly); Renode long runs pass 10000+.
Expand Down
13 changes: 13 additions & 0 deletions benches/engine_control/boards/nucleo_g474re.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# NUCLEO-G474RE bench Kconfig overlay — enables ADC for smart-data MCU
# health snapshots (smart_mcu_g4.c).
#
# The DT overlay in `boards/nucleo_g474re.overlay` puts ADC1 + the
# two internal channels (TS=ch16, VREFINT=ch18) in place; without
# CONFIG_ADC, the driver source isn't compiled in and the
# DEVICE_DT_GET(DT_NODELABEL(adc1)) call in smart_mcu_g4.c fails to
# link with `undefined reference to __device_dts_ord_*`.
#
# CONFIG_ADC_STM32 auto-selects when CONFIG_ADC=y and the DT compatible
# match fires.

CONFIG_ADC=y
43 changes: 43 additions & 0 deletions benches/engine_control/boards/nucleo_g474re.overlay
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright (c) 2026 PulseEngine
*
* NUCLEO-G474RE bench overlay — enable ADC1 internal channels
* for smart-data MCU health snapshots.
*
* Zephyr's stock nucleo_g474re DTS leaves ADC1 disabled; the
* silicon-anchor protocol needs it to read the on-die temperature
* sensor (TS, channel 16) and internal reference (VREFINT,
* channel 18) so the H-row in the captured CSV records actual
* thermal and supply state alongside the algorithm timings.
*
* Channel numbers per STM32G474RE reference manual RM0440 §21.4.31
* (ADC channels) — TS = IN16, VREFINT = IN18.
*/

&adc1 {
status = "okay";
st,adc-clock-source = "SYNC";
st,adc-prescaler = <4>;
pinctrl-0 = <>;
pinctrl-names = "default";

#address-cells = <1>;
#size-cells = <0>;

channel@10 {
reg = <16>;
zephyr,gain = "ADC_GAIN_1";
zephyr,reference = "ADC_REF_INTERNAL";
zephyr,acquisition-time = <ADC_ACQ_TIME_MAX>;
zephyr,resolution = <12>;
};

channel@12 {
reg = <18>;
zephyr,gain = "ADC_GAIN_1";
zephyr,reference = "ADC_REF_INTERNAL";
zephyr,acquisition-time = <ADC_ACQ_TIME_MAX>;
zephyr,resolution = <12>;
};
};
6 changes: 6 additions & 0 deletions benches/engine_control/prj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ CONFIG_ISR_STACK_SIZE=2048
# Enable the primitives the benchmark exercises in the ISR / thread path.
CONFIG_EVENTS=y
CONFIG_RING_BUFFER=y
# 2048-sample ring (32 KB) is needed to absorb high-RPM ISR bursts on
# real silicon at 115200-baud UART throughput without dropping samples.
# RING_BUFFER_LARGE lifts Zephyr's static-assertion size cap so
# RING_BUF_DECLARE accepts the larger backing array. Inert for the
# QEMU/Renode CI lanes (their drops were 0 already at the smaller ring).
CONFIG_RING_BUFFER_LARGE=y

# Pump tick rate up so k_timer can approximate 10 μs periods
# (default is 10 ms / 100 Hz, way too coarse for 60 kHz targets).
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# LLVM-LTO + Gale build crashes on NUCLEO-G474RE silicon

**Status:** known-broken on real silicon as of gale@`418c6b8c`. Renode CI passes the same build.
**Discovered:** 2026-05-10, during Phase B of the silicon-anchor protocol.
**Action:** silicon-anchor protocol intentionally **does not** capture an LTO variant for this board until this is fixed.

## What runs

- The build itself succeeds (FLASH 26,592 B, 1 surviving `gale_` symbol vs 3 in the rustc-direct gale build — LTO is doing meaningful inlining).
- `west flash --runner openocd` writes the ELF cleanly.
- The chip starts executing; a few bytes of the bench's `print_csv_header` reach the VCP (`# DWT rows: ...`, partial `# health rows:...`), then the chip resets / re-boots / faults.

## Crash signature

Halting the chip via `openocd ... halt` once it's in the fault state:

```
PC: 0x08004d9a → arch_system_halt at zephyr/kernel/fatal.c:30
xPSR: 0x21000022 → IPSR ISR_NUMBER = 0x22 = 34 = External IRQ 18
CFSR: 0x00000000 (no Cortex-M fault flags — not a hardfault)
HFSR: 0x00000000
SHCSR: 0x00070000 (USGFAULTENA + BUSFAULTENA + MEMFAULTENA — all enabled, none active)
ICSR: 0x0400f822 (VECTACTIVE = 34 = ExtIRQ 18; pending: USG, MEM, BUS, SVCALL faults)
VTOR: 0x08000000 (vector table at start of flash, normal)
```

**External IRQ 18 on STM32G474 = ADC1_2 (ADC1 / ADC2 global interrupt)**, per RM0440 §11.3 (Interrupt and exception vectors).

The chip is permanently sitting in `arch_system_halt`, which is reached via Zephyr's `z_irq_spurious` → fatal handler chain when an IRQ fires without a registered handler.

## Hypothesis

Smart-data emission's `smart_mcu_g4.c` uses Zephyr's ADC API (`DEVICE_DT_GET(DT_NODELABEL(adc1))` + `adc_channel_setup` + `adc_read`). Under the LLVM cross-language LTO link step, one of the following is happening:

1. **Init-order race:** the ADC driver's `Z_DEVICE_DT_INST` static initializer registers the ADC IRQ handler in the IRQ table, but the LLVM linker is reordering the initializer such that an ADC interrupt fires (perhaps from an ADC self-calibration sequence in `smart_mcu_init`) before the handler entry is in place.
2. **IRQ table eviction:** LTO's aggressive inlining is folding the ADC IRQ handler symbol into the calling code, but the IRQ-table-vs-handler symbol matching logic in `gen_isr_tables.py` doesn't see the inlined version, leaving the table slot pointing at `z_irq_spurious`.
3. **Calibration state corruption:** STM32G4 ADC requires explicit calibration (`LL_ADC_StartCalibration`) before first conversion. If LTO reorders init-fn pointers vs the device-driver auto-init, calibration may be skipped and the first ADC operation triggers an internal error → ADC IRQ 18.

Renode's `stm32f4_disco` simulation lane passes because Renode does not model the ADC peripheral with the same interrupt fidelity — the published Renode "LLVM+LTO+Gale = same as rustc-direct" claim is consequently silicon-untested.

## Reproduction

Toolchain matched at LLVM 21.1.8 (rustc 1.94.1 + brew `llvm@21` + brew `lld@21`):

```sh
SDK_DIR=/Volumes/Home/zephyr-sdk/zephyr-sdk-1.0.1
ARM_BIN="${SDK_DIR}/gnu/arm-zephyr-eabi"
GCC_LIB_DIR=$(dirname $("${ARM_BIN}/bin/arm-zephyr-eabi-gcc" -print-libgcc-file-name -mcpu=cortex-m4 -mthumb -mfloat-abi=soft))
PICOLIBC_DIR="${ARM_BIN}/arm-zephyr-eabi/lib/thumb/v7e-m/nofp"
LLD_LIBS="-L${GCC_LIB_DIR} -L${PICOLIBC_DIR}"

export PATH=/opt/homebrew/opt/llvm@21/bin:/opt/homebrew/opt/lld@21/bin:${ARM_BIN}/bin:$PATH
export ZEPHYR_BASE=/Volumes/Home/git/pulseengine/zephyr
export ZEPHYR_SDK_INSTALL_DIR=${SDK_DIR}
GALE_ROOT=/Volumes/Home/git/pulseengine/gale-smart-data

west build -b nucleo_g474re -d /tmp/silicon-lto -s "$GALE_ROOT/benches/engine_control" -- \
-DZEPHYR_TOOLCHAIN_VARIANT=llvm \
-DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY \
-DZEPHYR_EXTRA_MODULES="$GALE_ROOT" \
-DOVERLAY_CONFIG="$GALE_ROOT/benches/engine_control/prj-gale.conf;$GALE_ROOT/zephyr/gale_lto_overlay.conf" \
-DCMAKE_EXE_LINKER_FLAGS="${LLD_LIBS}" \
-DENGINE_BENCH_SWEEP=long
```

## Discriminating tests for next session

1. Build LTO **without smart-data** (drop the `boards/nucleo_g474re.conf` `CONFIG_ADC=y` and conditionally compile-out `smart_mcu_g4.c`). If it boots, ADC interaction is confirmed.
2. Build LTO **without `CONFIG_ISR_TABLES_LOCAL_DECLARATION`** (remove from `gale_lto_overlay.conf`). Tests whether the local ISR-table machinery is the trigger.
3. Build with the `arm-zephyr-eabi-gcc` toolchain + `CONFIG_LTO=y` (GCC-side LTO, no clang). If GCC-LTO works and clang-LTO doesn't, narrows the bug to the LLVM linker plugin / lld.
4. Capture the chip's pre-fault `printk` output via openocd `tracesetup` + ITM trace, to see the last function called before the IRQ 18 fires.

## Why this matters for the publication

The "Three Quiet Barriers" blog post claims LLVM-LTO+Gale produces handoff timing equivalent to rustc-direct+Gale (both at 347 cyc on Renode `stm32f4_disco`). On real `nucleo_g474re` silicon, the LTO build does not run at all. Until this crash is root-caused, **no headline "LLVM cross-language LTO works on this MCU family" claim can be sustained for the G4** — only for the F4 (which the published Renode CI uses).
Loading