Each check belongs to one place in the fabric. Draw the top level first, then sign it off box by box.
The numbers are the rows of the table below, in order. Read the picture top to bottom, as a request travels.
Check 1, decode: the map in the decoder matches the software headers.
Check 2, bridge: every bridge names its clock and reset on both sides.
Checks 3 and 4, read path: lane order and endianness survive the mux, and responses stay ordered with their owners under backpressure.
Check 5, arbiter: the debug master and the production masters are each served within a bound.
Each item below pairs the check with the evidence that proves it. An unchecked box with no evidence attached is not signed off.
Item | Evidence that proves it |
|---|---|
Memory map matches software headers | Independent header expectations versus the production integration map; the standalone example below checks decoder defaults only. |
Clock and reset domain per bridge documented | Bridge list naming each clock and reset plus lint with no new clock-domain waivers. |
Width and endianness aligned at every interface | Fixed-pattern test through the mux, such as 0x44332211, checking lane order on both sides. |
Backpressure paths verified under load | Ordered payload/status/sideband/owner scoreboard at actual acceptance/completion edges; stalled-offer stability; stop/drain to empty under a justified progress bound. Counts are necessary but not sufficient. |
Debug paths do not starve production traffic | Arbitration test with the debug master requesting alongside production masters, each served within bound. |
Run the map check whenever a header changes. Maps drift one register at a time, and the check is cheap.
Close with load and starvation runs. Backpressure under load and debug-path fairness are system properties, so they are proven at the top, not inside one slave.
Competing causes include stale headers or binary, production decoder overrides, target-select wiring, bridge address translation and a wrong device image. Read a distinct peripheral identity register through the deployed software-visible path, compare its actual bus address and selected target, then compare binary/header/map revisions. The standalone decoder test cannot identify one cause by itself.
Debug traffic is rare and easy to ignore in arbitration. Without a bound, a debug session can stall production traffic or be locked out by it.
A discriminating identity test reads UART_ID at UART_BASE+ID_OFFSET and SPI_ID at SPI_BASE+ID_OFFSET using the deployed driver/binary, expecting different documented constants. Trace the issued address, bridge translation, decoded select, physical target instance and returned ID. If decode is right but ID is wrong, investigate target wiring; if the issued address is wrong, inspect software/map versions. Keep expected identities independent of the DUT wiring under test.
The example checks the decoder's independently declared production defaults against software-header constants. In a real SoC, instantiate the integration top with its production overrides and import the generated header map independently.
// tb_map_check: compare production decoder defaults with illustrative header expectations.
// The decoder under check (same definition as the decode lesson).
module bus_decode #(
parameter [31:0] BASE0 = 32'h0000_1000,
parameter [31:0] LIMIT0 = 32'h0000_1FFF,
parameter [31:0] BASE1 = 32'h0000_2000,
parameter [31:0] LIMIT1 = 32'h0000_2FFF
)(
input logic [31:0] addr,
output logic sel0, sel1,
output logic default_err
);
assign sel0 = (addr >= BASE0) && (addr <= LIMIT0);
assign sel1 = (addr >= BASE1) && (addr <= LIMIT1);
assign default_err = !(sel0 || sel1);
endmodule
The listing checks the decoder's independently declared production defaults against software-header constants. It does not configure the DUT from the expected values, and it does not read an external header or prove a top-level configuration; in a real SoC, instantiate the integration top with its production overrides and import the generated header map independently.