This lesson has one job: stop two errors from meeting in one word. Scrubbing reads every protected word on a schedule, correcting single-bit decay before a second upset in the same word turns it uncorrectable. Initialisation writes every protected word once before the first real read, because a read of an uninitialised word fails its own check and looks exactly like a double-bit fault. One is a background rate, the other is a boot rule, and both are integrator-owned.
The scrub engine reuses the idle port cycles of each bank: it walks the address range bottom to top, reads each word through the ECC corrector, and writes back only words that needed correction. The interval is the whole design: sweep the full 16,384 words of a bank often enough that two upsets rarely land in one word between sweeps. Initialisation is simpler and stricter: the boot ROM clears 4 KB of SRAM0 (the top 4 KB, where its own stack lives) with posted writes on a cold boot before any protected read there. That is 1/16 of SRAM0 and none of SRAM1: every other protected word must be written by software before it is read, and a full 16,384-word bank takes about 170.7 microseconds at one write per system clock. For the circuit-level view of partial writes and initialisation see Partial Writes and Scrubbing and Initialization, Injection, and Signoff.
The worked example prices the sweep with NanoSoC teaching values. If the scrubber steals one bank cycle in every 64 when the bank is idle, a full 16,384-word sweep takes about one million system clocks, or roughly 10.9 ms; that is the script's middle row, and the table around it shows how the steal rate trades against sweep time.
words = 16384
f_sys = 96e6
for steal in (16, 64, 256):
clocks = words * steal
ms = clocks / f_sys * 1000
print(f"1 steal in {steal}: sweep {clocks} clocks = {ms:.2f} ms")
assert clocks == words * steal
assert abs(16384 * 64 / f_sys * 1000 - 10.922667) < 0.001
print("PASS: 1-in-64 scrub sweeps a bank in about 10.92 ms")The scrub interval is derived from the upset rate and the word count, not copied, and the steal rate is budgeted against live traffic.
Boot code initialises every protected word it reads, including the stack area below the first push.
Fault injection covers the uninitialised read: it must report uncorrectable, never return garbage as good data.
Run the scrubber against a bank preloaded with single-bit faults at known addresses and confirm each is corrected without a write-back storm on clean words. Then boot with the initialisation loop shortened in a scratch build and confirm the first protected read traps: if it returns data, the check path is bypassed, not merely uninitialised.
No, provided the correction counter moved: silent correction with counted statistics is the design. It becomes a bug only if the counter is unwired, because then the dying bank hides behind perfect data.