A memory controller accepts a write's address only once the write's data has arrived, so that it can schedule the whole write at once. A DMA engine sends a write's data only once its address has been accepted, so that it never has data in flight for an address the target might reject. Both are sensible. Connected together, the address waits for data and the data waits for the address, for ever.
When a protocol has several channels, which may wait for which?
The obvious approach is to let each side decide its own waits, since only it knows what it needs. But each side's choice is only safe if the other side's choice cannot close a loop with it. Without a shared rule, two independently designed, individually correct blocks can deadlock the first time they meet. So protocols that have independent channels also specify a dependency rule: which waits are allowed, for each side, on each pair of channels.
For every pair of channels, ask: may this side hold back channel X until it has seen activity on channel Y? Draw an arrow X → Y for every allowed wait, on both sides. The rules are chosen so that the combined graph can never contain a cycle, whatever each compliant side does.
The pattern is the same as the valid/ready rule of lesson 3.4, extended across channels: the side that offers (valid) must not wait for the side that accepts (ready). The accepting side may wait for whatever it likes from the offering side. Then every arrow points from accepter to offerer, and no cycle can form.
Side | May wait for | Must not wait for |
|---|---|---|
Requester, before offering address or data | Nothing on these channels | The target accepting the address or the data |
Target, before accepting address or data | The address, the data, or both | — |
Target, before sending the write response | The address and the last data beat (it cannot answer otherwise) | The requester being ready for the response |
Requester, before accepting the response | Anything (it may be busy) | —, but it must accept eventually (lesson 9.5) |
Protocol | Dependency rules |
|---|---|
AXI | A manager must not wait for AWREADY or WREADY before asserting AWVALID or WVALID. A subordinate may wait for AWVALID, WVALID or both before asserting AWREADY or WREADY. It must wait for the address and the last data handshakes before asserting BVALID, and must not wait for BREADY before asserting BVALID. |
PCI Express | Rules on which traffic type may block which (lesson 7.6): posted writes and completions must never be blocked by non-posted requests. |
The opening pair (illustrative) is the hang you will debug in lesson 9.10. The memory controller's wait (address waits for data) was allowed. The DMA engine's wait (data waits for the address to be accepted) broke the rule. A protocol checker on the DMA engine's port would have flagged it in the first simulation; without one, it showed up only when the two blocks were integrated.
A requester that waits for BVALID before asserting BREADY (allowed) waits for the target while the target waits for it: a deadlock.
The offering side must not wait for the accepting side's readiness; the accepting side may wait for what the offerer provides. All arrows then point one way, and no cycle can form.
Independent channels need a dependency rule saying which side may wait for which channel.
The offering side never waits on the accepting side; the accepting side may wait for anything offered.
Check every block against the rule in isolation; violations appear as deadlocks at integration.