The interconnect cannot know which of the sixteen APB slots an address targets, and the DMA cannot know it lives at 0x4000_0000. Each level decodes only the bits it owns, and every classic decode bug is a level reaching for bits that belong to another. The DMA alias is exactly that: the slot owns twelve offset bits but the slave consumes eight, and the four dropped bits repeat the window sixteen times. Understanding which level owns which bits turns the alias from a mystery into arithmetic.
An APB address arrives at the bridge as a full 32-bit value and is consumed in three slices. The interconnect has already used bits 31 down to 16 to route the whole 64 KB window to the bridge. The slot decoder then uses bits 15 down to 12 as the slot number: 0 for the DMA through 6 for the reset controller, 7 to 15 to its own default slave. The selected slave receives bits 11 down to 0 as its 12-bit APB address. The DMA consumes only bits 7 down to 0 into its 8-bit paddr port, which is where the sixteen images come from: images differ only in bits 11 down to 8, which nothing downstream looks at.
Level | Bits owned | Decision | NanoSoC example |
|---|---|---|---|
Interconnect (nano_xbar) | addr[31:16], ROM addr[31:14] | Which window: ROM, SRAM0, SRAM1, APB, default | 0x4000_1xxx routes to the APB bridge |
Slot decoder (nano_apb_dec) | addr[15:12] | Which slot: 0 to 6 mapped, 7 to 15 default | 0x4000_1xxx is slot 1, the SBR |
Slave wrapper | addr[11:0] as apb_paddr | Which register, which image | SBR decodes 0x00 to 0x10; DMA sees only [7:0] |
Block core (DMA) | paddr[7:0] | Which register or PSLVERR | Offsets 0x00, 0x04, 0x08, 0x0C, 0x10 mapped; every other offset (incl. 0x01 to 0x03) PSLVERR |
Slot size versus real footprint is the second half of the lesson. Every slot reserves 4 KB but no block comes close to filling it: the DMA implements five registers, the SBR five, the UART four, and the rest are similar. The unused offsets are not free space; unmapped offsets inside a slot answer PSLVERR, exactly like every unimplemented DMA offset, so a stray offset gives a clean error instead of a silent mirror. The slot is large because 4 KB slots keep the slot number on a nibble boundary, which keeps the second-level decode to one four-bit compare, the same economy the first level gets from power-of-two windows.
Each level's documentation names exactly the bits it consumes, and no bit is consumed twice or never.
The dropped DMA bits 11 down to 8 are called out in the wrapper, with the lint rule that no slave input depends on them.
Every unmapped offset inside every slot has a specified error response, matching the DMA's PSLVERR behaviour.
Walk one address per slot plus the slot boundaries: 0x4000_0FFF must still be DMA while 0x4000_1000 is SBR, and 0x4000_6FFF must still be the reset controller while 0x4000_7000 takes the default slave. Then read one DMA register through two images, 0x4000_0004 and 0x4000_0104, to confirm the alias, and read 0x4000_0014 to confirm PSLVERR inside an image. If a slot boundary is off by one nibble, the symptom is unmistakable: a whole 4 KB block of registers answers one slot early or late.
Bits 15 down to 12 equal 1 pick the slot; the register sits at window base plus slot offset plus register offset: 0x4000_0000 plus 0x1000 plus 0x0C, which is 0x4000_100C.