A bus connects several masters to several slaves through shared address, data and control wires. Integration is the work that makes the sharing correct: decoding each address to one slave, multiplexing the replies, answering illegal accesses with errors, arbitrating between masters and proving all of it.
Decode works from an address map: each slave owns one range, and every address outside them goes to the default slave.
Read the ladder from the bottom up. The shaded regions are the only addresses a real slave answers.
Adjacent regions: the UART limit 0x0000_1FFF is one below the SPI base 0x0000_2000, so the boundary needs its own test.
Gaps: both dashed regions go to the default slave, which returns an error response, never floated data or a false OKAY.
6 lessons, about 30 min
The data is garbage, but OKAY tells software it is valid. The default slave must answer unmapped addresses with an error response, and read data must never float.
The whole topic on one page, taken from each lesson's Remember box. Read it before an interview, or print it.
Address Decode
Keep the base and limit pairs in one place so the map can be checked against the software headers.
Exactly one select is high for a mapped address. An overlap is a map bug.
An AND-OR read mux returns zero when nothing is selected. That is not a valid completion, so a default slave must return an error.
Rule of thumb: test the limit, the base and one address past the limit, not just the middle of each range.
Mux Trees and Read Paths
AND each slave word with its select replicated across the width, then OR the terms. The one-hot select belongs in an assertion.
Capture the {data, status, owner} tuple only when the response slot is free, and hold it while the receiver stalls.
Byte lanes must keep their order, and both sides must agree on endianness. Do not infer a lane swap from CPU endianness alone.
Error Paths and Timeouts
DECERR means no slave matched the address. SLVERR means a slave detected the error.
The timeout counter runs while req && !ack, fires at LIMIT, and drops when ack arrives or req falls.
A monitor is a detector, not a transaction engine: it sends no error and does not quarantine late replies.
Rule of thumb: an error response is data too, so the default slave must produce it.
Arbitration
Fixed priority is a priority encoder and cheap, but it can starve a master, so document that.
Round-robin searches after the last owner. With persistent requests, each master is served within N accepted ownership intervals.
A grant stays until accept_i is high, then clears for one arbitration cycle before the next owner is chosen.
Integration Checklist
Each item pairs a check with the evidence that proves it: which test, which bound, which log.
Re-run the map check whenever a header changes, because maps drift one register at a time.
Load, starvation and debug-path fairness are system properties, so prove them at the top, with complete ordered tuples rather than counts.
An End-to-End Bus Example
The grant names the owner until the reply. End the ownership interval on the response, never on the request handshake.
Register the slave select at issue and steer the reply by it. Unmapped addresses get DECERR from a default slave that always answers.
A timeout ends a hung access with SLVERR and must also stop the slave from replying late. Every bus bench needs watchdogs.
Rule of thumb: route each reply by who owns the transaction, never by who is asking now.
Practice question: AXI4-Lite slave with invalid address protection
Practice question: Waveform debug: write transaction timeout
Practice question: Memory arbiter for two masters
Code lab: Round-robin arbiter
Interview: run a mock interview on this topic