UCIe · Module 5
Layer Responsibilities
A decision framework for assigning UCIe functions to layers — the uncertainty-and-lifetime test, a full responsibility matrix, three worked wrong-ownership cases, and a design-review checklist that outlives UCIe.
Chapters 5.1 to 5.3 examined each layer in isolation. This chapter is not a recap of them, and if it were it would be worthless — you can already recite what each layer does. The useful question is harder and comes up constantly in real design work:
A new function appears in the design. Which layer should own it?
Specifications enumerate the functions that already exist. They do not tell you where to put the one your architecture just invented — a new status register, a new metadata field, a new recovery behaviour, a new configuration parameter. This chapter builds the test for that, and the test generalises well beyond UCIe.
1. The Ownership Test
Two questions decide it, and they are almost always sufficient:
- What uncertainty does this function resolve?
- What state lifetime must it maintain?
The layer that owns both answers owns the function.
A function belongs to the layer that owns the uncertainty it resolves and the state lifetime it must maintain.
Mapped onto the stack:
| Layer | Uncertainty it owns | State lifetime it maintains |
|---|---|---|
| Protocol | What does this traffic mean? | The semantic transaction — issue to completion |
| Adapter | Can this be transported reliably, and does the link permit progress? | The transport and the link session |
| PHY | Can the physical channel move bits at all? | The physical link — training to retrain |
The two questions usually agree, and when they disagree you have found something interesting: either the function should be split, or it is genuinely mode-dependent (§6).
2. The Responsibility Matrix
The complete picture. The interesting rows are the ones people get wrong, and each of those carries its reasoning.
| Function | Protocol | Adapter | PHY | Why |
|---|---|---|---|---|
| Transaction meaning | ✓ | Only Protocol can interpret it | ||
| Transaction tags | ✓ | Identity; released on semantic completion (§4) | ||
| Ordering guarantees | ✓ | Defined by the protocol; nothing below knows what may pass what | ||
| Transport framing | ✓ | Defines delivery units, not meaning (§3) | ||
| Integrity (CRC) | mode | ✓ mode | Mode-dependent (§5) | |
| Retry / replay | mode | ✓ mode | Needs detection and retained state (§5) | |
| Flow / resource accounting | ✓ | Tracks capacity on the remote die | ||
| Protocol arbitration | ✓ | Chooses between streams sharing one link | ||
| Parameter negotiation | ✓ | Exchanges with the remote partner | ||
| Higher-level link state | ✓ | Owns bring-up coordination | ||
| Lane mapping | ✓ | Physical arrangement | ||
| Lane health | ✓ | Discovered physically | ||
| Training | ✓ | Establishes the physical link | ||
| Sideband control path | ✓ | Physical control channel | ||
| Clocking and signalling | ✓ | Electrical | ||
| Status abstraction upward | ✓ | ✓ | Each layer compresses its own state for the layer above (§7) |
Three rows deserve unpacking, and they are §3, §5, and §6.
3. Framing: Meaning Versus Delivery
"Framing" is ambiguous, and the ambiguity causes real design arguments. Split it:
- Protocol structure describes meaning — what a request looks like, which fields carry an address, how a completion is recognised. That belongs to the layer implementing the protocol.
- Transport framing describes delivery — where a transport unit begins and ends so the receiver can find its boundaries and check it.
Protocol structure describes meaning; transport framing describes delivery.
The test discriminates cleanly. Transport framing resolves transport uncertainty — where does this unit end, is it intact — and its state lives for the transfer. Protocol structure resolves semantic uncertainty and its state lives for the transaction. Different uncertainty, different lifetime, different owner.
The mode nuance from 5.1 applies here too: in a raw format the Protocol Layer populates the payload entirely, so the division shifts. The principle does not shift — it is still meaning versus delivery — only which layer is doing which.
4. State Lifetime as the Decisive Test
When the uncertainty question is ambiguous, lifetime usually settles it. Follow one transaction and watch three pieces of state with three different lifespans:
| State | Created | Destroyed | Lifetime |
|---|---|---|---|
| Protocol tag | Request issued | Completion matched | The full semantic round trip |
| Adapter replay entry | Transport unit launched | Delivery confirmed | One delivery, plus confirmation latency |
| PHY training state | Bring-up or recovery | Retrain or link loss | The physical link session |
These are nested but not aligned: a single tag may outlive many replay entries, and a replay entry may outlive nothing at all if delivery is immediate. A PHY training state may span thousands of transactions or be destroyed mid-transaction by a fault.
State with different lifetimes cannot share an owner, because the owner would have to implement all three destruction rules and would need information from all three layers to know when each applies. That is the mechanical reason the layers exist — not tidiness, but the impossibility of one module correctly managing three unrelated lifetimes.
5. Why Reliability Is Not Automatically the PHY's Job
A natural instinct says errors are physical, so error protection belongs at the physical layer. Apply the test and see why that fails.
Reliability requires two capabilities: detecting that something went wrong, and recovering from it. The PHY can plausibly do the first — it is closest to the channel. It cannot do the second, because recovery requires a retained copy of what was sent, and retention must last until delivery is confirmed by the far side. That is transport-session state, not physical-link state.
Reliability belongs where the architecture has both enough information to detect failure and enough retained state to recover from it.
That is why CRC-in-the-PHY is insufficient rather than merely unconventional: a layer that detects corruption but holds nothing to resend can only report, not repair. And it is why the Adapter — which already retains transport units for flow control and already coordinates with the remote partner — is the natural owner when reliability is enabled.
The mode dependency then reads sensibly rather than as an exception: in a raw format the Protocol Layer retains its own state and handles its own protection, which satisfies the same rule with a different layer.
6. Bring-Up Has Three Separate Owners
Collapsing bring-up into one link_up bit is among the most common architectural errors, and 5.5 will show what it costs at integration. Three distinct questions, three owners:
- PHY: can the physical link function? Training complete, sufficient usable lanes, signalling established.
- Adapter: have both ends agreed a usable operating point, and is transport ready? Parameters negotiated, resources initialised, link state machine in its ready state.
- Protocol: may semantic traffic now progress? Its own resources available — tags free, ordering permits, queues have space.
Each is a genuine precondition for the next, and each can be false while the others are true. A PHY that is trained but not negotiated is not usable. An Adapter that is ready but whose Protocol Layer has no free tags cannot issue. One bit cannot represent three conditions, and squashing them together means the debug question "why is nothing moving?" has no localising answer.
7. Three Wrong-Ownership Cases
Each is a real pattern, and each looks locally reasonable.
Case 1 — Protocol owns lane health
// BAD ownership — illustrative architecture RTL, not UCIe normative naming.
assign may_issue = have_request && lane_good[0] && lane_good[1];Why it is wrong. Protocol now depends on a specific lane count and numbering. Lane repair that transparently remaps lanes becomes visible upward and breaks it. The Protocol Layer can no longer be verified against an abstract model of the layer below, because that model would have to expose lane detail. And the layer is now bound to one PHY family rather than to a specification-defined boundary.
Test. Lane health resolves physical uncertainty with a physical-link lifetime — both PHY. Protocol should consume the abstraction:
assign may_issue = have_request && link_operational && protocol_resources_ready;Case 2 — PHY owns transaction ordering
// BAD ownership — the PHY cannot legitimately know this input exists.
if (packet_is_ordered)
hold_lane_transfer <= 1'b1;Why it is wrong. This is semantic leakage downward, and the giveaway is the input itself: packet_is_ordered is a protocol classification. For the PHY to have it, something must have carried semantic meaning down two layers — meaning the Adapter also had to pass through information it does not interpret. The uncertainty being resolved is semantic and the lifetime is the transaction's; both say Protocol.
Case 3 — Adapter owns the tag lifecycle
The subtlest, because the Adapter genuinely handles tags — they pass through it on every transfer.
But handling is not owning. The Adapter cannot know when the semantic transaction completes, when a tag may be safely reused, or whether a returning completion matches the outstanding entry — all of which require interpreting the transaction. It carries tag bits as opaque payload.
This is the clearest illustration that contact is not ownership. The test: tag lifetime is issue-to-completion (Protocol); the uncertainty is which request a completion belongs to (semantic). Both say Protocol, despite the Adapter touching the bits more often than the Protocol Layer does.
8. Ownership Shows Up in Module Ports
The cleanest structural check available: look at what crosses each module boundary.
// Illustrative endpoint hierarchy — not UCIe normative port naming.
module endpoint;
protocol_layer u_protocol (...);
d2d_adapter u_adapter (...);
physical_layer u_phy (...);
endmoduleWhat must not appear on u_protocol's ports: lane_good, lane_map, training_state, module_enable — any physical detail.
What must not appear on u_phy's ports: transaction_tag, ordered_request_class, completion_expected — any semantic classification.
This makes ownership reviewable without reading a line of logic: a port list is an ownership claim. If a physical signal appears on the protocol module, the violation is visible in the hierarchy before anyone examines behaviour — which is why port-list review is worth doing deliberately rather than incidentally.
9. What May Legitimately Cross
Abstraction does not mean hiding everything, and over-hiding is its own failure — a system nobody can debug.
Each layer should compress its internal state into defined facts the layer above can act on:
- PHY upward: operational or not; degraded capability where the architecture defines it; error indication.
- Adapter upward: link operational; negotiated capability; transport and error status.
The distinction that matters: an abstraction is a defined interface contract; raw internal state is an implementation detail. phy_degraded is a contract — it means something the Adapter can act on and it survives a PHY reimplementation. lane_good[7] is implementation.
For debug, the answer is not to widen the functional interface but to expose internal state through a separate observability path — status registers, debug buses, trace — that no functional logic depends on. That keeps the functional contract narrow while keeping the design diagnosable.
10. Assertions Can Catch the Symptoms
Assertions cannot prove an architecture is correctly layered — that is a structural review question (§8). They can catch behavioural manifestations:
// Illustrative ownership-boundary properties — conceptual, not UCIe normative.
// Protocol must not accept traffic while the abstracted link is down.
property p_no_protocol_accept_when_link_down;
@(posedge clk) disable iff (!rst_n)
!link_operational |-> !(fdi_valid && fdi_ready);
endproperty
assert property (p_no_protocol_accept_when_link_down);
// Adapter must not transmit while the PHY is not operational.
property p_no_adapter_tx_when_phy_down;
@(posedge clk) disable iff (!rst_n)
!phy_link_up |-> !(rdi_valid && rdi_ready);
endproperty
assert property (p_no_adapter_tx_when_phy_down);Both are safety properties, and note what they check: that each layer respects the abstraction its neighbour provides. They would not catch Case 1 or Case 3 above, because those are structural violations that behave correctly in the configuration they were written for. Ownership defects are found by review; ownership-respecting behaviour is found by assertion. Use both and do not confuse them.
11. A Design-Review Checklist
For any new signal, state element, or function — in UCIe or anywhere layered:
- What uncertainty does it resolve?
- Which layer has the information to interpret it? If a layer must be told what it means, it does not own it.
- How long must the state live, and what event destroys it? Can the candidate owner observe that event?
- Which neighbour needs only an abstraction of it? Define that abstraction explicitly.
- Would exposing it across a boundary make one layer change when the other's implementation changes? If yes, it is leaking.
- Can each layer still be verified with its neighbour replaced by a model? If not, the boundary has been broken.
Question 6 is the sharpest practical test, because it is checkable rather than a matter of taste: if a layer's testbench needs a real neighbour rather than a model, something crossed the boundary that should not have.
12. Common Misconceptions
13. Understanding Check
14. Summary and What Comes Next
Ownership is decided by two questions: what uncertainty does this resolve, and what state lifetime must it maintain? Protocol owns semantic uncertainty over a transaction lifetime; Adapter owns transport and link uncertainty over a session lifetime; PHY owns physical uncertainty over a link lifetime. The two questions almost always agree, and where they do not you have found either a function that should be split or one that is genuinely mode-dependent.
Three rows in the matrix carry most of the difficulty. Framing divides into protocol structure (meaning) and transport framing (delivery). Reliability needs detection and retained state for recovery, which is why the PHY cannot own it alone. And bring-up has three owners, not one bit — physical function, negotiated transport, and protocol resources are independent conditions.
The wrong-ownership cases share a shape: Protocol reading lane health binds it to a PHY implementation; the PHY reading a semantic class proves meaning leaked down through the layer between; and the Adapter appearing to own tags is really contact mistaken for ownership. State with different lifetimes cannot share an owner, because no single module can observe all three destruction events.
For review, a port list is an ownership claim, and the sharpest practical test is whether each layer can be verified with its neighbour replaced by a model. Assertions catch layers failing to respect an abstraction; they do not catch a leak that happens to behave.
Ownership says where state belongs. It says nothing about what happens when those layers exchange signals on the same clock edge — under stalls, status changes, resets, and asynchronous updates. That composition is where locally correct layers produce a broken system:
- 5.5 — Layer Interactions — combinational ready-loops, elastic buffering, status racing data, reset sequencing across three state machines, CDC at layer boundaries, backpressure latency, and deadlock.
Browse the full path on the UCIe tutorials index.