An access-control rule is only as good as the block that checks it, and on NanoSoC the check has to live in two different places for a structural reason: the DMA cannot check anything. Its APB port has no protection input, so a rule like RSTPWR is secure-only cannot be enforced by the block itself. Somebody upstream must refuse on its behalf, and forgetting that is how secure peripherals end up reachable by anyone who can reach the bus.
The first filter sits in the interconnect beside the decode: it sees every AXI address with its AxPROT bit 1, compares against the security column, and steers violations to the fault responder for SLVERR. It has exactly one secure-only target, SRAM1; the ROM, SRAM0 and the whole APB window are open at this level, and the per-slot rule behind the bridge belongs to the second filter. The second filter sits in the APB slot decoder and checks per slot, because slots differ: six are open and one, the reset controller, is secure-only, and the bridge window as a whole cannot express that. The slot decoder therefore receives the caller's security state alongside the address and refuses secure-only slots itself, raising PSLVERR that the bridge converts to SLVERR. Masters carry state into both checks: the CPU from its software's world, and the stream bridge from a register bit, which is where the planted bug lives.
# not-run: NanoSoC access-control decisions, NanoSoC teaching values
Caller state comes from AxPROT[1]: 0 = secure, 1 = non-secure.
Interconnect: SRAM1 + non-secure -> sel_fault -> SLVERR, no data.
Slot decoder: slot 6 (RSTPWR) + non-secure -> PSLVERR -> bridge SLVERR.
SBR master state: CTRL[2] NS, reset value 1 = non-secure; reset CTRL = 0x4.
DMA copy SRAM1 -> SRAM0 with NS = 1: first read beat SLVERR, SBR STATUS.ERR = 1,
DMA COUNT stays 0 and BUSY stays 1 (no data ever streams).That last block is the seventh planted bug in this design, and its shape is worth learning. The SBR resets with NS equal to one so that an unconfigured bridge starts in the less privileged state; secure software is expected to clear the bit deliberately before copying out of SRAM1. When nobody does, the first read beat of the copy returns SLVERR, the bridge records ERR in its STATUS, and the DMA waits forever for data that will never arrive, BUSY high and COUNT stuck at zero. The CPU reading the same SRAM1 works perfectly, which is the clue that separates a filter bug from a memory bug: same destination, different master, different state. The fix is one deliberate write from secure software, plus one line in the map for each master: the security attribute it issues and what that attribute resets to.
Now the uncomfortable part, because the reset default is not a security control and must not be taught as one. The NS bit lives in the SBR's CTRL register, and the SBR slot is open to non-secure software. Any non-secure program can therefore write NS to zero itself and make the bridge issue secure reads of SRAM1, defeating the filter completely. What the bit actually protects against is accident: an unconfigured or crashed bridge streaming secure memory somewhere unintended. What it does not protect against is a deliberate non-secure caller. A real control would put the bit beyond non-secure reach: move CTRL, or the whole SBR slot, behind the per-slot secure check, or drive the bridge's issued security state from a secure-only register. On NanoSoC as specified, treat the writable NS bit as a known weakness of the teaching design, and make a test of it, as the next lesson does: non-secure software sets NS to zero and the SRAM1 copy succeeds, proving that the SRAM1 filter alone is not a boundary while this register is reachable.
Every secure-only region is guarded at a named level: interconnect for AXI slaves, slot decoder for APB slots, with the DMA's missing protection port called out as the reason.
Every master's issued security state and its reset value appear in the map documentation, next to the slave table it is checked against.
Reset defaults are stated with what they do and do not guarantee: the bridge wakes non-secure, which is a safe starting point but not a control, because the register holding that bit is itself writable by non-secure software (see below).
Reproduce bug 7 in simulation before fixing it: program a copy from SRAM1 with NS left at its reset value and confirm ERR rises with COUNT at zero. Then clear NS from secure software and confirm the same copy completes. The pair of runs pins both the filter and the intended software contract. If the first run succeeds, the interconnect is not checking the bridge's state at all, which is a worse bug than the one planted.
The master's security state: the CPU issues secure accesses while the bridge issues non-secure ones because CTRL NS reset to 1. Secure software clears CTRL bit 2 (writing CTRL with NS = 0), after which the bridge's reads pass the filter.