The stream bridge and the DMA share an AXI-Stream link that works the first time, while the software handshake between the same two blocks fails twice: once because the two LEN registers are separate and drift apart, once because a driver writes KEY while the DMA is busy and the write is silently ignored. The wires kept their promise; the unwritten contract did not. Every interface carries six facets, and the four teams usually write down, protocol and address, are not the ones that fail. All six are named below, each with its NanoSoC example.
Facet | Promises | NanoSoC example |
|---|---|---|
Protocol | Signals, handshake, burst rules, error responses | AXI4 fabric: INCR bursts to 16 beats, no WRAP, one outstanding ID per master; APB3 with no PSTRB and no PPROT |
Timing | Clocks per transfer, wait behaviour, timeouts | DMA register access takes 3 system clocks; the bridge adds accept and respond; the slow-segment bridge answers in 208.33 ns |
Clock and reset | Domains, synchronisation, release order | 192, 96 and 24 MHz; async assert with sync release per domain; slaves and fabric first, CPU last |
Power | Domains, isolation, sequencing | PD_SW versus PD_AON; 114 clamp cells; isolate before reset before power off |
Address | Map, attributes, security, errors | DMA canonical window 0x4000_0000 to 0x4000_00FF; SRAM1 secure-only with SLVERR; DECERR versus SLVERR |
Software | Reset values, access types, side effects | CTRL bit 0 reads 0; STATUS bits are write-1-to-clear; LEN and KEY ignored while BUSY |
Two facets need a worked demonstration because they are where NanoSoC actually bit. The address facet carries alias A1: the slot is 4 KB but the DMA consumes 8 address bits, so the 256-byte window repeats sixteen times and only the first image is canonical. The checker below classifies any slot address as canonical, alias image, unmapped, or outside, and proves the project's rule executable: headers may contain canonical addresses only. The clock-and-reset facet carries the release contract: every domain gets asynchronous assertion with synchronous release through a two-flop synchroniser, in its own domain, and the module below is that contract in gates.
// NanoSoC teaching values: per-domain reset synchroniser.
// Contract: assertion is asynchronous, release is synchronous to clk,
// and every domain gets its own instance (rst_per_n, rst_sys_n, rst_cpu_n).
module nano_rst_sync (
input logic clk,
input logic rst_n_in, // async assert, from the reset controller
output logic rst_n_out // released synchronously in clk
);
logic [1:0] sync;
always_ff @(posedge clk or negedge rst_n_in) begin
if (!rst_n_in) sync <= 2'b00;
else sync <= {sync[0], 1'b1};
end
assign rst_n_out = sync[1];
endmoduleThe script below enforces the address facet for the DMA slot: the five offsets 0x00, 0x04, 0x08, 0x0C, 0x10 are registers; every other offset in each 256-byte image answers PSLVERR, images repeat every 256 bytes, and only image zero is canonical. It proves the rule against the exact addresses the lessons quote, including the 0x4000_0204 read that works but is illegal by project rule.
SLOT_BASE, SLOT_SIZE = 0x4000_0000, 0x1000 # NanoSoC DMA slot
DMA_REGS = (0x00, 0x04, 0x08, 0x0C, 0x10) # DMA specification offsets
def classify(addr):
if not (SLOT_BASE <= addr < SLOT_BASE + SLOT_SIZE):
return "outside-slot"
off = addr - SLOT_BASE
image, reg = off >> 8, off & 0xFF
if reg not in DMA_REGS:
return "unmapped-PSLVERR"
return "canonical" if image == 0 else "alias-image-%d" % image
assert classify(0x4000_0004) == "canonical"
assert classify(0x4000_0100) == "alias-image-1"
assert classify(0x4000_0204) == "alias-image-2" # works, but illegal
assert classify(0x4000_0014) == "unmapped-PSLVERR"
assert classify(0x4000_1000) == "outside-slot" # the SBR slot
headers = [0x4000_0000, 0x4000_0004, 0x4000_0008, 0x4000_000C, 0x4000_0010]
assert all(classify(a) == "canonical" for a in headers)
print("PASS: canonical, alias, PSLVERR and outside-slot all classified")Every top-level interface names all six facets in its contract page; a facet marked not-applicable says why.
The reset contract points at one synchroniser instance per domain, not a shared one.
The address contract marks canonical ranges, and the header check enforces them.
When an interface fails, walk the facets in order: force the protocol with a directed transfer, measure the timing against the specified clocks, confirm the domains and release order, check the power state and isolation, decode the address by hand, and only then read the driver. Protocol signal detail belongs to the Protocol First Principles course, which covers the AXI, AHB, APB and AXI-Stream contracts from first principles; this course never re-teaches it.
The software facet of the stream contract: the two LENs are separate registers that must hold one value. The driver rule writes one variable to both, owned by software, stated on the contract page.