This lesson has one job: account for every microsecond between power-on and the first application instruction. The boot model lists sixteen steps, one access in flight at a time, totalling 12,580.917 microseconds, and its last line already gives away the ending: the SPI image load is 86.9 percent, the UART banner 11.0 percent, and everything else 2.1 percent. Anyone asked to boot faster who starts anywhere but the loader is optimising the 2 percent.
Hardware owns the first 53.948 microseconds: the oscillator is ready at 42.667, the PLL locks in 10.833 more, and four small steps of 0.083, 0.083, 0.1875 and 0.094 microseconds (0.448 in all) release the peripheral reset, open the clock gates and release the system and CPU resets. The CPU then fetches its first line from ROM (125 ns) and the ROM reads RST_CAUSE (281.25 ns), which is the first thing it does: step 9 ends at 54.354 microseconds. On a cold boot only, software then sets the stack pointer and clears 4 KB of SRAM0 with 1024 posted writes at one per system clock, initialises the UART with three register writes, prints sixteen banner characters at 115,384.6 baud, self-tests the DMA, loads 8,196 bytes over a 6 Mb/s SPI link, checksums 2,048 words with single reads, and jumps. A wake cause skips the clear (and, as the next lesson shows, everything up to the jump). The waveform below shows the opening: reset release, the first ROM fetch, and the jump to SRAM0, with the middle of the boot cut out.
How to read it: the time axis is not to scale. Each slot is one tick of a 10 ns teaching clock, and the 12.5 ms between the line fill and the jump (steps 9 to 15: the cause read, the clear, the UART, the DMA self-test, the SPI load and the checksum) is omitted: in real time the first fetch ends at 54.073 microseconds and the jump happens at 12,580.917. The rst_cpu_n lane stands for the last reset release, rst_cpu_n at step 7, and it rises once and stays high. While it is low both select lanes are low. After release the rom_sel lane is high for four slots, standing for the 4-word line fill from address zero (in real time 24 CPU clocks, 125 ns), then falls as the sram_sel lane takes over for three slots for the jump to SRAM0. The boot_done lane rises in the slot where sram_sel falls and stays high. The lanes show one release, one fetch burst from ROM, one handoff to SRAM, and completion, in that order, with the time between them removed.
The script recomputes the three steps people misquote: the hardware total, the banner time from sixteen characters at ten bits each over the real baud rate, and the SPI load of image plus four command bytes. Every constant is a NanoSoC reference value.
t_per = 1 / 24e6
t_sys = 1 / 96e6
t_cpu = 1 / 192e6
hw = (1024 + 2 + 260 + 2) * t_per + 18 * t_sys + (8 * t_sys + 2 * t_cpu)
assert abs(hw * 1e6 - 53.948) < 0.002, hw
fetch = 24 * t_cpu
cause = 281.25e-9
clear = 1024 * t_sys
uart = 3 * 281.25e-9
baud = 24e6 / (16 * 13)
banner = 16 * 10 / baud
assert abs(baud - 115384.6) < 0.1, baud
assert abs(banner * 1e6 - 1386.667) < 0.001, banner
dma = 625e-9 + 875e-9 + 72 * t_sys + 135.4e-9 + 6000e-9
spi = (8192 + 4) * 8 / 6e6
assert abs(spi * 1e6 - 10928.0) < 0.01, spi
checksum = 2048 * 18 * t_cpu
steps = [hw, fetch, cause, clear, uart, banner, dma, spi, checksum]
total = sum(steps)
assert abs(total * 1e6 - 12580.917) < 0.01, total
print(f"hardware {hw * 1e6:.3f} us, banner {banner * 1e6:.3f} us, SPI {spi * 1e6:.1f} us")
print(f"shares: SPI {spi / total * 100:.1f}%, banner {banner / total * 100:.1f}%, hardware {hw / total * 100:.2f}%")
assert abs(spi / total * 100 - 86.9) < 0.05
assert abs(banner / total * 100 - 11.0) < 0.05
assert abs(hw / total * 100 - 0.43) < 0.005
before_clear = hw + fetch + cause
assert abs(before_clear * 1e6 - 54.354) < 0.002, before_clear
print(f"PASS: steps sum to {total * 1e6:.3f} us; RST_CAUSE read ends at {before_clear * 1e6:.3f} us")The boot-time ledger lists every step with its duration and running total, with no silent rounding: 53.948, 1,386.667, 10,928 and 12,580.917 microseconds.
Any faster-boot proposal names which dominant step it shrinks and prices the change in the loader, not in the reset logic.
The self-test step is in the plan by name with its 8.385 microsecond budget, not folded into a margin.
Boot in simulation with one access in flight and compare each step's cycle count against the ledger: oscillator 1024 peripheral clocks, lock 260, release 18 plus 8 plus 2, line fill 24 CPU clocks, then the cause read before anything else. A step that runs long points at an extra wait state; a step that runs short points at a skipped initialisation. Measure the banner on the wire too: sixteen characters at the real baud must span 1,386.667 microseconds.
No: hardware reset is 0.43 percent of the total. Halving it saves 27 microseconds of 12.581 milliseconds. The SPI load is the only step worth touching: doubling its clock to 12 Mb/s would cut the wire time from 10.928 to 5.464 milliseconds, but only with a loader that keeps up. A CPU-driven loader needs a DATA write, a STATUS poll and a DATA read per byte, three 281.25 ns accesses or 0.844 microseconds, against 0.667 microseconds on the wire at 12 Mb/s, so the gain needs a DMA-driven or FIFO-buffered loader.