A DMA engine copies data: it reads from one buffer and writes to another, as fast as it can. On a bus with one shared data path, every cycle carries either read data or write data, never both, so the copy runs at half the bus's rate. A protocol with separate channels for read data and write data runs the same copy at full rate in both directions at once.
Why split a transaction into several independent channels, and what still ties them together?
The obvious split protocol has two paths: requests go one way, responses come back the other. That works, but it bundles things that move at different times and in different amounts. A write's address is one beat; its data may be sixteen. A read's address goes out while another read's data comes back. Bundled into one path, the small items wait behind the large ones, and reads and writes take turns on a single data path.
Give each kind of information its own channel, each a one-way valid/ready interface with its own handshake (Part 3). The generic set for a memory protocol is five channels:
Channel | Direction | Carries | Beats per transaction |
|---|---|---|---|
Write address | Requester → target | Address, length, size, ID, attributes | One |
Write data | Requester → target | Data and byte strobes, last-beat marker | One per beat |
Write response | Target → requester | ID, status | One per burst |
Read address | Requester → target | Address, length, size, ID, attributes | One |
Read data | Target → requester | ID, data, status, last-beat marker | One per beat |
Reads and writes move at the same time: the copy engine above uses read data and write data together.
Addresses run ahead of data. A requester can issue the next address while the previous burst's data is still moving, keeping the target's pipeline full.
Each channel is a plain valid/ready interface, so register slices and skid buffers (lessons 3.8 and 3.9) can be inserted on any channel independently to close timing.
Small items never wait behind large ones: a one-beat response does not queue behind a sixteen-beat data burst.
Independent does not mean unrelated. Some orders are forced, because a channel's information only makes sense after another's:
Dependency | Why |
|---|---|
A write response comes after the last beat of its write data | The target cannot report the outcome of data it has not received |
Read data comes after its read address | The target cannot return data for an address it has not seen |
Write data may arrive before its write address | Allowed in some protocols (AXI allows it); the target must then buffer the data until the address arrives |
There is no order between reads and writes | A read and a write to the same address on different channels can arrive in either order; whoever needs an order must wait for the write response before issuing the read (Part 7) |
The last row is the price of independence: the protocol no longer orders reads against writes for you.
Protocol | Channels |
|---|---|
AXI | Exactly the five above: AW, W, B, AR, R, each with VALID/READY. One write response per burst; read data carries a status on every beat. |
APB | One combined channel: address, data and response all belong to a single transfer. |
PCI Express | One link per direction carrying packets of every kind; independence comes from separate packet types and credit pools per type (lesson 4.6). |
A target (illustrative) accepted write data only after it had seen the write address, while its requester sent write data first and only then the address, because both orders were legal. The requester waited for the data to be accepted before sending the address; the target waited for the address before accepting the data. Neither moved. Each side was individually correct; together they deadlocked. Independent channels need explicit rules about which side may wait for which, and the AXI specification spells these out for exactly this reason.
Shared: 4 bytes per cycle (reads and writes take turns). Separate: 8 bytes per cycle, reading and writing at the same time.
The response reports the outcome of the whole write; the target cannot know it until it has received all the data.
Independent channels give each kind of information its own valid/ready handshake.
They let reads and writes move together, let addresses run ahead, and let each channel be pipelined alone.
Some dependencies remain, and there is no order between reads and writes unless the requester waits for it.