The first question silicon must answer is whether the map is the map: every region where the table says, every hole answering as documented, every register at its reset value. A sweep answers all of it with the simplest possible stimulus, one directed access per claim, and it catches the integration-class bugs that block testing is structurally blind to. It earns its place as the section's gate, and it belongs in the test environment: the boot ROM touches only mapped addresses, and production software never probes.
A sweep is only as good as its predictor. The model below encodes the NanoSoC windows, the slot decoder, the DMA's mapped offsets inside every alias image and the two security rules, then predicts the response class for sixteen probes: data, DECERR or SLVERR. Each probe is chosen to falsify one claim: a window edge, a hole of each kind, an alias image, an unmapped register offset in the DMA, SBR and UART slots, the secure-only memory and slot from both states. The predictor keeps a list of mapped offsets per slot, because every slot answers PSLVERR for offsets it does not implement, and the last lines show what happens without that list. If the chip matches the model on all sixteen, the map, the decode and both responders agree in fact, not just in documents.
# Mapped register offsets per APB slot (design specification): the rest answer PSLVERR.
OFFSETS = {
0: {0x00, 0x04, 0x08, 0x0C, 0x10}, # DMA, only paddr[7:0] decoded
1: {0x00, 0x04, 0x08, 0x0C, 0x10}, # SBR
2: {0x00, 0x04, 0x08, 0x0C}, 3: {0x00, 0x04, 0x08, 0x0C}, # UART, SPI
4: {0x00, 0x04, 0x08, 0x0C}, 5: {0x00, 0x04, 0x08, 0x0C}, # GPIO, INTC
6: {0x00, 0x04, 0x08, 0x0C, 0x10, 0x14, 0x18, 0x1C}, # RSTPWR, secure-only
}
def predict(addr, ns, offsets=OFFSETS):
# First level: window select. Returns DATA, DECERR or SLVERR.
if addr < 0x4000:
return "DATA" # BOOTROM
if 0x2000_0000 <= addr < 0x2001_0000:
return "DATA" # SRAM0
if 0x2001_0000 <= addr < 0x2002_0000:
return "SLVERR" if ns else "DATA" # SRAM1 secure-only (fault responder)
if 0x4000_0000 <= addr < 0x4001_0000:
slot = (addr >> 12) & 0xF
if slot not in offsets:
return "SLVERR" # H3 slots 7..15, APB default
if slot == 6 and ns:
return "SLVERR" # RSTPWR secure-only: refused before the offset matters
off = addr & 0xFF if slot == 0 else addr & 0xFFF # the DMA decodes 8 bits
return "DATA" if off in offsets[slot] else "SLVERR"
return "DECERR" # H1, H2, H4 interconnect default
PROBES = [
(0x0000_0000, 0, "DATA"), (0x0000_3FFC, 0, "DATA"), (0x0000_4000, 0, "DECERR"),
(0x2000_0000, 1, "DATA"), (0x2001_0000, 0, "DATA"), (0x2001_0000, 1, "SLVERR"),
(0x4000_0004, 0, "DATA"), (0x4000_0014, 0, "SLVERR"), (0x4000_0104, 0, "DATA"),
(0x4000_1014, 0, "SLVERR"), (0x4000_2010, 0, "SLVERR"),
(0x4000_6000, 0, "DATA"), (0x4000_6000, 1, "SLVERR"), (0x4000_7000, 0, "SLVERR"),
(0x2002_0000, 0, "DECERR"), (0xFFFF_FFFC, 0, "DECERR"),
]
for addr, ns, want in PROBES:
assert predict(addr, ns) == want, hex(addr)
kinds = {w for _a, _n, w in PROBES}
assert kinds == {"DATA", "DECERR", "SLVERR"}
# The predictor can fail: a sloppy slot decoder that accepts every offset in slots 1 to 5
# answers DATA for the two unmapped-offset probes, and the sweep notices.
sloppy = {s: (set(range(0, 0x1000, 4)) if 1 <= s <= 5 else o) for s, o in OFFSETS.items()}
wrong = [hex(a) for a, n, w in PROBES if predict(a, n, sloppy) != w]
assert wrong == ["0x40001014", "0x40002010"]
print("PASS: 16 probes predicted; every response class exercised; sloppy predictor caught")The register half of the sweep reads every register at reset and compares it against the specification table: DMA all zeros, SBR addresses at the two SRAM bases with CTRL at 0x4, the UART divider at 13, the reset controller's clock enables at 0x3 and PLL control enabled. A single wrong reset value localises to one block and one table row. Access-type checks follow the same pattern per register: write a read-only register and confirm no change, clear status with ones and with zeros, write a keyed register without its key. Together the three sweeps cover the entire software-visible surface of the chip with directed accesses that run in seconds and mean something individually when they fail.
Predictions come from the map model generated from the table, so a table change regenerates the expected answers.
Every probe failure names the level at fault: window, slot, offset, security or responder.
Reset readback runs before any write in the test, so values are silicon truth, not test residue.
Run the sweeps in simulation at integration, then unchanged on the bench. The hang class has its own probe: with the DMA clock-enable bit cleared in the reset controller, an access to the DMA slot never completes, so run it with a timeout and treat the timeout as the expected result (the 256-cycle bridge watchdog of NanoSoC turns it into SLVERR). A probe answering DECERR where data is predicted means the window moved or the master cannot reach it; SLVERR where data is predicted points at the security state or the offset; data where an error is predicted is the dangerous one and means a check is missing, so stop and find which level failed to refuse. Each outcome is a named debug branch, not a mystery.
The model is right: 0x104 is 0x100 plus 0x04: image index 1 of 16, register offset 0x04, which is STATUS, so the DMA answers normally. The legal software range is only the first image, but the hardware cannot distinguish images, which is exactly why the probe belongs in the sweep.