feat(core): opt-in H5 FLASH fidelity gates — program write-buffer/errors + read-while-write (silicon-validated)#335
Merged
Merged
Conversation
…ERR) Add an opt-in fidelity gate to the STM32H5 FLASH model. When enabled via the flash peripheral config (error_flags: true), a program (a write into the flash region) is validated against RM0481 §7 silicon programming rules before it commits: a non-16-byte (quad-word) aligned target sets PGSERR + INCERR, and a target not in the erased (0xFF) state sets PGSERR. On a violation the NSSR sticky flags are set and the write is rejected (does not store), matching real silicon. NSSR error bits are W1C. Default off: with the gate off the flash-region write path is byte-identical to before (every program commits, no flag), so existing tests and configs are unchanged. The gate is a no-op on non-H5 layouts. WRPERR is scoped out: the model does not yet track per-region write protection, so raising it would be inaccurate. The check is keyed to the flash register peripheral so it can set NSSR. The bus caches the gated flash index in rebuild_peripheral_ranges and consults it on flash-region byte writes (the single write_u8 funnel that u16/u32 region writes decompose into).
The opt-in H5 program-fidelity gate was built from datasheet guesses that silicon testing on a NUCLEO-H563ZI disproved. Replace the per-byte alignment reject with the verified write-buffer state machine: - Track a single pending 16-byte quad-word buffer (aligned base + which bytes written + buffered values), gated on NSCR.PG. - Partial quad-word sets WBNE (live status), commits nothing, no error. - A full aligned quad-word commits as the bitwise AND of new & existing (flash flips only 1->0), sets EOP, clears WBNE. Program-over-not-erased is allowed (the AND models it) — not PGSERR. - A misaligned/inconsistent run (first byte off the 16-aligned base, or a jump to another quad-word before the current one completes) raises INCERR alone and commits nothing. - Flags clear via NSCCR (0x30) W1C; writing NSSR no longer clears. - The bus owns the flash backing memory, so h5_program_byte returns an H5ProgAction the bus acts on; the AND-commit happens on the bus side. Gate-off path stays byte-identical (the bus never calls the state machine when flash_error_flags_idx is None). Unit + bus-level tests rewritten to mirror the silicon trace.
On real STM32H563 silicon (RM0481 §7) a flash bank cannot be fetched
from or read while that same bank is being erased or programmed; code
executing from that bank stalls and cannot make progress, so production
flash routines run from SRAM. The forgiving sim let an OTA bootloader
erase the boot-state sector of the bank it executes from, which works in
sim but stalls/faults on the real part.
Add an opt-in per-peripheral gate (config { read_while_write: true },
default off, H5-only) that mirrors the existing error_flags opt-in. When
on, applying an EraseSector whose target physical bank is the one the CPU
is currently executing from raises SimulationError::Other with a reason
string telling the firmware to run the routine from SRAM, instead of
silently succeeding. The bank comparison is SWAP_BANK-aware: both the
BKSEL logical erase bank and PC's bank are translated to a physical bank
through the active swap state (toggled when SwapAndReset is applied). PC
outside the flash region (the SRAM-resident routine) never faults, and a
cross-bank erase proceeds unchanged. Gate off and every non-H5 chip stay
byte-identical.
…+ drift_ack Ran the FLASH program/erase behavioural live-diff on the NUCLEO-H563ZI over SWD: write buffer (WBNE) commits a 16-byte quad-word with EOP only on completion, misaligned quad-word raises INCERR alone and commits nothing, program-over-not-erased ANDs the bits with no PGSERR, and flags clear via NSCCR not NSSR. The opt-in H5 program error-flag and read-while-write fidelity gates were corrected to match this capture. Bump last_capture and drift_ack to 2026-06-22 and regenerate VALIDATION_STATUS.md.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds two opt-in STM32H5 FLASH fidelity gates that make the simulator refuse the kinds of operations real H563 silicon rejects, so firmware bugs that the forgiving model used to pass become visible. Both default OFF (per-peripheral
config:keys), so every existing example and chip is byte-identical; a chip/example opts in explicitly.Both gates were validated against a real NUCLEO-H563ZI over SWD, and the silicon corrected the datasheet-from-memory model on several points (recorded below).
1. Program write-buffer + error fidelity (
config: { error_flags: true })Models the H5 quad-word programming path as it actually behaves on silicon, rather than writing every store straight through:
Silicon corrections captured during validation: the first cut raised PGSERR on misaligned (silicon raises INCERR alone), rejected program-over-not-erased with PGSERR (silicon allows it and ANDs), and made NSSR write-to-clear (silicon clears via NSCCR). All three were wrong and are now fixed to match the chip.
2. Read-while-write fault (
config: { read_while_write: true })On real H5 you cannot fetch/read from a flash bank while that same bank is being erased or programmed. When enabled, a sector erase whose target physical bank equals the bank the CPU is executing from faults (SWAP_BANK-aware), instead of silently succeeding. Cross-bank operations (execute from the active bank, erase/program the inactive one) proceed unchanged. This forces firmware that erases a sector of its own bank to run the flash routine from SRAM, as silicon requires.
Scope notes
Companion to the udslib
examples/h563_uds_bootloader/work (w1ne/udslib#64); these gates underpin upcoming firmware-correctness hardening.Gates:
cargo test -p labwired-core --lib1427 passed;cargo fmt --checkandcargo clippy -D warningsclean.