This lesson has one job: price the plumbing and order the boot. The UART, SPI and GPIO do not hang off the fast fabric: they sit on a 24 MHz APB segment behind a clock-domain crossing, and two peripheral siblings, the DMA and the stream bridge, sit on a 96 MHz APB segment in front of it. Every register touch in this section pays the bridge toll, every peripheral shares one reset, and the bring-up order is forced by dependencies: clocks before release, controller before DMA self-test, UART before the banner, SPI before the image. Write the order down once and every later section reuses it.
The AXI-to-APB bridge plus the slot decoder translate each fabric access into APB: one bridge-accept cycle, three APB clocks on the fast segment for the DMA and bridge registers, then bridge-respond and fabric return. Behind the APB clock bridge the five slow peripherals each take two 24 MHz clocks per APB access plus the request and response synchronisation, which total 208.33 ns for the whole slow-segment access path, APB beats included. The blocking, one-access-at-a-time totals are 125 ns for a DMA or bridge register read from the CPU and 281.25 ns for a UART, SPI, GPIO, controller or reset-controller register read. Nothing here is pipelined or posted from software's view: each access completes before the next starts, which is why the boot table can simply add them.
Resets are shared per segment, not per block: rst_per_n releases the UART, SPI, GPIO, controller, reset controller and the slow side of the crossing together, 2 clk_per cycles after the oscillator is ready. The DMA and bridge release with rst_sys_n much later, after the PLL locks and the gates open. Bring-up order follows the hardware: release, read the reset-cause register first so the cause is never lost, enable the UART and print the banner as the first signs of life, run the DMA self-test while the fabric is idle, then load the image over SPI and check it. A secure note belongs here: the reset controller is secure-only, so non-secure software cannot issue the software reset or gate clocks; the boot ROM runs secure and owns those registers throughout.
The script below adds the peripheral-side accesses from the boot flow: three UART configuration writes, the 16-character banner, the DMA self-test register traffic, and the SPI image load, confirming the NanoSoC boot total of 12.581 ms and showing where each microsecond goes.
T_CPU = 1 / 192e6
per_access = 281.25e-9 # one clk_per peripheral register access
dma_access = 125e-9 # one DMA/SBR register access from the CPU
uart_cfg = 3 * per_access
assert abs(uart_cfg - 843.75e-9) < 1e-12
banner = 16 * 10 / (24e6 / (16 * 13))
assert abs(banner - 1386.667e-6) < 1e-9
T_SYS = 1 / 96e6
dma_selftest = 5 * dma_access + 7 * dma_access + 72 * T_SYS + 135.4e-9 + 6000e-9
print(f"UART config: {uart_cfg * 1e9:.2f} ns")
print(f"banner: {banner * 1e6:.1f} us")
print(f"DMA self-test: {dma_selftest * 1e6:.3f} us")
assert abs(dma_selftest - 8.385e-6) < 0.05e-6
spi_load = (8192 + 4) * 8 / 6e6
total = 53.948e-6 + 125e-9 + 10.667e-6 + 281.25e-9 + uart_cfg + banner
total += dma_selftest + spi_load + 192e-6
print(f"reset + clear + cause + UART + banner + DMA + SPI + checksum:")
print(f" total {total * 1e3:.3f} ms")
assert abs(total - 12.581e-3) < 0.002e-3
share = spi_load / total
print(f"SPI share: {share * 100:.1f}%")
assert share > 0.86
print("PASS: boot totals 12.581 ms; SPI load is 86.9%")Every peripheral access in every boot-time claim uses 281.25 ns for slow registers and 125 ns for fast ones, never a guessed round number.
The bring-up order is written as a numbered list with the dependency for each step: cause before config, UART before banner, self-test before image.
The reset-cause register is read before any write to any peripheral, and the secure-only registers have an owner that runs secure.
Time the banner on the bench: 1,386.7 us at the reset divider is the cheapest oscilloscope check that the crystal, the divider and the peripheral clock are all correct. If one peripheral answers and the others do not, the APB slot decoder is the suspect, not the blocks: confirm the slot number in address bits 15 down to 12. If no slow peripheral answers but DMA registers do, the APB clock bridge is held in reset or its clocks are gated; if nothing answers, check rst_sys_n, rst_per_n and the PLL lock first, then the bridge; the reset-cause register is itself an APB register behind that bridge, so it cannot answer either. Once any register answers, RST_CAUSE tells you which reset fired.
Correct behaviour: the reset controller slot is secure-only, so the interconnect returns SLVERR to the non-secure access. Clock policy belongs to secure firmware; the application asks through a call, never through the register.