An interviewer sketches a DMA engine next to a CPU and a memory, and asks: "Is the DMA a master or a slave?" The candidate answers "master, because it moves the data." The interviewer nods and asks how the CPU tells the DMA what to move. The candidate realises the CPU writes the DMA's registers, which makes the DMA a slave on that interface.
If one block can be both, what does a role actually describe?
The obvious answer is that a role describes a block: the CPU is a master, a memory is a slave, a DMA is a master. That works until a block has more than one interface, which is almost always. The DMA has a register port the CPU writes, a data port it uses to read and write memory, and an interrupt line it uses to tell the CPU it finished. Calling it "a master" hides two of its three relationships, and the hidden ones are exactly where integration bugs live: who may wait on whom, and who must always answer.
A role describes one side of one interface. The same block holds a different role on each of its interfaces. Three pairs of words cover almost every protocol, and they answer different questions:
Pair | Question it answers | Typical words in specs |
|---|---|---|
Initiator / target | Who starts a transaction? | Master and slave in older specs; newer specs often use other names |
Requester / completer | Who asks, and who must produce an answer? | PCI Express uses these words |
Producer / consumer | Which way does the data flow? | Streams and FIFOs; independent of who starts |
The third pair is the one people forget. On a read, the initiator is the consumer: it starts the transaction, but the data flows towards it. On a write, the initiator is the producer. So "who starts" and "which way the data goes" are two separate facts about an interface, and a good description states both.
Roles also decide who owns what state. The initiator tracks what it has asked for and not yet received. The target owns the resource (registers, memory) and must answer every request it accepts. Who must always answer, and who may wait, becomes central in Part 9: most deadlocks come from a block that, in one role, waits on itself in another role.
A sensor block streams samples into a FIFO. A DMA engine moves samples from the FIFO to memory, and the CPU configures both and reads the results. Listing each interface separately gives an unambiguous picture:
Interface | Initiator | Target | Data flows from → to |
|---|---|---|---|
Sensor → FIFO stream | Sensor (pushes) | FIFO | Sensor → FIFO |
DMA reads FIFO | DMA | FIFO | FIFO → DMA (initiator consumes) |
DMA writes memory | DMA | Memory | DMA → memory (initiator produces) |
CPU configures DMA | CPU | DMA | CPU → DMA |
CPU reads memory | CPU | Memory | Memory → CPU (initiator consumes) |
DMA interrupt | DMA | CPU | DMA → CPU (one bit of news) |
Six interfaces, and the DMA appears in four of them with three different roles. When you design or verify such a system, this table, not a box diagram with "master" and "slave" labels, is what tells you where each side may wait and who must always answer.
Arrangement | What it costs | When it wins |
|---|---|---|
Separate ports per role (a target port for configuration, an initiator port for data) | More wires and two interfaces to verify | Almost always: each port has one clear role and the deadlock analysis stays simple |
One shared port carrying both roles | Fewer wires; the block must keep the two roles from blocking each other | Pin-limited links, such as a single PCIe link carrying requests in both directions |
Pure target (memory, register block) | Cannot start anything, so cannot notify | Passive resources |
Pure initiator (a CPU's data port) | Cannot be configured through that port | Blocks that are only clients of the fabric |
Protocol | How it assigns roles |
|---|---|
AXI | Each interface has one master side and one slave side; a block with both roles, such as a DMA engine, has separate master and slave interfaces. |
PCI Express | Uses requester and completer per transaction. A link carries traffic in both directions, so the same device is a requester for its own reads and a completer for reads aimed at it. |
I2C | A shared bus where any device that can act as a master may start a transfer; a device can be master for one transfer and slave for the next, and masters arbitrate bit by bit on SDA. |
A bridge connects two buses (illustrative). On its target side it accepts requests from bus A; on its initiator side it forwards them to bus B. The designers sized it so that while one forwarded request is waiting on bus B, it refuses new requests from bus A. Meanwhile, a block on bus B tries to reach a target on bus A through the same bridge in the other direction, and waits. Each side is waiting for the other: the bridge's initiator role is blocked by the very traffic its target role is refusing.
The bug is invisible on a box diagram that labels the bridge "master" or "slave". It becomes obvious the moment you list both of its roles on both of its interfaces and ask, for each, what it waits for. Part 9 turns this into a method: draw who waits for whom, and look for a cycle.
The requester (for example the CPU) is the initiator and the consumer; the memory is the target and the producer. Who starts and which way the data flows are separate facts.
Each port then has a single role, so it is clear who must answer and who may wait on each, and configuration traffic can never be stuck behind data traffic. A shared port works but needs extra rules to keep the two roles from blocking each other.
Often yes (bridges do it), but it creates a dependency: the target's answer now depends on another interface. If that other interface can, in turn, wait on this target, the dependency forms a cycle and can deadlock. The dependency must be documented and checked.
A role describes one side of one interface; the same block holds different roles on different interfaces.
Initiator/target says who starts, requester/completer says who must answer, producer/consumer says which way the data flows; on a read the initiator is the consumer.
Listing every interface with its roles shows who may wait on whom, which is where deadlocks are found.