Skip to content

UCIe · Module 4

The UCIe Mental Model

The three-layer UCIe stack — Protocol Layer, Die-to-Die Adapter, and Physical Layer — what each owns, how information travels between two dies, and why layer boundaries are ownership boundaries rather than mandatory pipeline stages.

This is the first chapter about UCIe itself, and its job is narrow and important: give you one picture you can redraw from memory, correctly, before any mechanism is introduced. Every later module — link training, flit formats, retry, power management, verification — attaches to this picture. Learn it precisely now and those chapters read as detail filling in a structure you already hold. Learn it vaguely and each one arrives as unconnected vocabulary.

We will build the picture, then immediately make it concrete in hardware — because a layer boundary that exists only in a diagram teaches nothing, while a layer boundary expressed as an interface with state, backpressure, and invariants teaches how the architecture actually behaves.

1. The Picture

UCIe defines a stack of three layers, and a link between two dies is that stack, mirrored:

Protocol LayerDie-to-Die AdapterPhysical Layerpackage channelPhysical LayerDie-to-Die AdapterProtocol Layer

Information originates in one die's Protocol Layer, descends through the Adapter and the Physical Layer, crosses the package, and ascends the mirror-image stack on the other die. Nothing skips a layer.

The two boundaries between those layers are named in the specification, and knowing the names now saves confusion later:

  • FDI — the Flit-Aware Die-to-Die Interface, between the Protocol Layer and the D2D Adapter.
  • RDI — the Raw Die-to-Die Interface, between the D2D Adapter and the Physical Layer.

Those are architectural interfaces defined by the specification, not signal names invented here. Their detailed contents belong to later chapters; what matters now is that the boundaries are specified rather than left to each implementer — which is precisely the property Chapter 3.2 showed was necessary for independently designed logic to interoperate, applied within an endpoint so that a protocol implementation, an adapter implementation, and a PHY implementation can come from different sources.

Die A's Protocol Layer connects through the FDI boundary to its Die-to-Die Adapter, which connects through the RDI boundary to its Physical Layer. The Physical Layer drives the package channel to Die B's Physical Layer, which passes upward through Die B's adapter to Die B's Protocol Layer.Protocol Layerdie A - owns meaningD2D Adapterdie A - owns transportPhysical Layerdie A - owns bitsPackage channelthe physical linkPhysical Layerdie B - owns bitsD2D Adapterdie B - owns transportProtocol Layerdie B - owns meaningFDIRDIRDIFDI12
Figure 1 — the UCIe stack, mirrored across a die-to-die link. Information descends one die's Protocol Layer, D2D Adapter, and Physical Layer, crosses the package channel, and ascends the mirror-image stack on the partner die. The two inter-layer boundaries are specified interfaces — FDI between Protocol and Adapter, RDI between Adapter and Physical Layer — which is what allows the three layers to be implemented independently.

2. Why Three Layers, Specifically

The split is not arbitrary and it is not imitation of network models. It exists because three genuinely different kinds of problem need to be solved and to change independently.

The Protocol Layer's problem is meaning. What is a request? What is a response? What ordering may a consumer rely on? These are questions about the semantics of the traffic, and the answers differ per protocol. UCIe carries established protocols — PCIe and CXL — as well as a streaming/raw option for traffic that does not fit either. Those have different transaction models, and a die-to-die link that hard-coded one of them would be useful for a narrower set of systems.

The Adapter's problem is reliable transport. Given a payload with meaning attached, get it to the other die intact, in order where required, without overrunning the receiver, coordinating link state and power with the partner, and recovering when something goes wrong. Notice that none of this depends on what the payload means, and none of it depends on how many lanes the PHY has.

The Physical Layer's problem is the channel. Drive bits across real conductors in a real package: signalling, clocking, training the link into a working state, dealing with the physical reality Chapter 2.6 described. Notice that none of this depends on what is being carried.

The test of a good layer boundary is whether the layers can vary independently, and here they can. A new protocol can be carried over an unchanged Adapter and PHY. A PHY can be re-implemented for a different packaging technology without the Protocol Layer knowing. That independence is the entire return on the added interface complexity.

3. What Each Layer Owns

Protocol Layer — owns semantics. It works in terms of the transactions or messages of whatever protocol it implements. It does not see lanes, does not see electrical behaviour, and does not participate in training the physical link. Its view of the link below is essentially: is it usable, and will you accept this payload right now?

D2D Adapter — owns the link abstraction. It is the bridge between protocol semantics and physical transport. Its documented responsibilities include coordinating the higher-level link state machine and bring-up, negotiating parameters with the remote partner, and — when configured for it — providing reliability through CRC and link-level retry. Where multiple protocols share one link it also arbitrates and multiplexes between them.

One nuance worth carrying from the start, because it shows the boundaries are configurable rather than fixed: reliability is not unconditionally the Adapter's job. In the operating mode where the Adapter handles flit framing, it inserts and checks CRC. In a raw mode, the payload is populated entirely by the Protocol Layer, and error protection — CRC, retry, and any forward error correction — becomes the Protocol Layer's responsibility instead. The layers are fixed; the assignment of some responsibilities depends on the configured mode. That is a more sophisticated model than "each layer always does exactly these things", and it is the accurate one.

Physical Layer — owns the channel. Lanes and modules, electrical signalling, clocking, the training that brings the link to a usable state, and the sideband path used to coordinate that. A point that matters enormously for RTL engineers and is covered properly in the next chapter: the Physical Layer is not merely analog circuitry — it contains substantial digital logic and state.

4. Layer Boundaries as RTL Interfaces

A layer boundary drawn in a diagram is a claim; a layer boundary in RTL is a set of ports with an owner on each side. Here is the shape of an endpoint, reduced to what the boundaries look like structurally.

Illustrative UCIe endpoint architecture — not normative UCIe port naming. FDI and RDI are real specification-defined interfaces with richer contents than shown; this abstracts them to payload-plus-backpressure to make ownership visible.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
module illustrative_ucie_endpoint #(
  parameter int unsigned DATA_W = 256
) (
  input  logic                clk,
  input  logic                rst_n,
 
  // Upper edge: the protocol implementation this endpoint serves.
  input  logic [DATA_W-1:0]   proto_tx_data,
  input  logic                proto_tx_valid,
  output logic                proto_tx_ready,
 
  output logic [DATA_W-1:0]   proto_rx_data,
  output logic                proto_rx_valid,
  input  logic                proto_rx_ready
);
 
  // ---- Protocol <-> Adapter boundary (conceptually FDI) -----------------
  logic [DATA_W-1:0] adp_tx_data;
  logic              adp_tx_valid;
  logic              adp_tx_ready;
 
  // ---- Adapter <-> PHY boundary (conceptually RDI) ----------------------
  logic [DATA_W-1:0] phy_tx_data;
  logic              phy_tx_valid;
  logic              phy_tx_ready;
 
  // ---- Status abstracted upward by the lower layers ---------------------
  logic              link_operational;   // from adapter/PHY, consumed above
 
  // u_protocol, u_adapter, u_phy instantiated here.
 
endmodule

Architecture. Two internal boundaries, each with its own payload and its own backpressure, plus one status signal travelling upward. That asymmetry is the design: payload flows down, backpressure flows up, and status is abstracted upward in a form the layer above can act on.

State. The wires themselves hold nothing. Each layer holds its own state — the point of the next section is that a boundary without storage somewhere is a boundary that loses data.

Contract. Each boundary carries the invariant of Chapter 3.2: a presented payload is held stable until accepted.

Ownership, read from the code. Ask of every signal which layer may act on this:

  • Only the Protocol Layer may change what a payload means. The Adapter and PHY may reframe, protect, serialise, and retransmit it — they may not reinterpret it.
  • Every layer may stall. proto_tx_ready, adp_tx_ready, and phy_tx_ready each let a layer refuse work, and refusal propagates upward.
  • Only the lower layers know link state. link_operational is the abstracted form the Protocol Layer consumes.
  • Only the PHY knows about lanes. No lane-level signal appears in the list above, and the next chapter shows what goes wrong when one does.

5. What Happens When a Lower Layer Stalls

The most instructive failure at a layer boundary, and one that looks harmless in code review.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// INCORRECT: the protocol edge always claims to accept, regardless of
// whether anything below can actually carry the payload.
assign proto_tx_ready = 1'b1;

Trace it. Suppose the Adapter is not ready — the link has not finished coming up, or the PHY is applying backpressure:

  • Cycle N. Protocol asserts proto_tx_valid with a payload. It observes proto_tx_ready high, so by the ready/valid contract the transfer has occurred. Protocol retires the transaction, frees its buffer, and moves on.
  • Cycle N. Downstream, adp_tx_ready is low. Nothing captured the payload.
  • Cycle N+1. Protocol presents the next payload. The previous one exists nowhere — not in Protocol, which retired it, and not in the Adapter, which never accepted it.

The transaction is silently lost. No protocol rule was violated on any wire, nothing asserted an error, and the symptom appears much later as a missing completion or a timeout — far from the cause. This is the layer-boundary form of the payload-overwrite bug from Chapter 3.2, and it is the same class of failure: an endpoint claiming an obligation it cannot honour.

The fix has two parts, and both matter.

Part one — tell the truth about readiness.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// The protocol edge accepts only when the endpoint can actually take it.
assign proto_tx_ready = adapter_has_space && link_operational;

Part two — give the boundary somewhere to put the payload. Readiness is only honest if something stores what was accepted. A single-entry buffer at the boundary is the minimum:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// One-entry boundary buffer: makes "accepted" mean "retained".
logic [DATA_W-1:0] buf_data_q;
logic              buf_valid_q;
 
always_ff @(posedge clk) begin
  if (!rst_n) begin
    buf_valid_q <= 1'b0;
    buf_data_q  <= '0;
  end else begin
    // Accept from above when we have space and the link is usable.
    if (proto_tx_valid && proto_tx_ready) begin
      buf_valid_q <= 1'b1;
      buf_data_q  <= proto_tx_data;
    // Release downstream only when the next layer takes it.
    end else if (buf_valid_q && adp_tx_ready) begin
      buf_valid_q <= 1'b0;
    end
  end
end
 
assign adapter_has_space = !buf_valid_q || adp_tx_ready;
assign adp_tx_valid      = buf_valid_q;
assign adp_tx_data       = buf_data_q;

State. buf_valid_q is occupancy; buf_data_q is the retained payload. That is the whole state, and it is what makes acceptance meaningful.

Cycle behaviour. On any edge where the upper layer's transfer fires, occupancy is set and the payload captured. On any edge where the lower layer accepts, occupancy clears. adapter_has_space is high when empty, or when the entry will drain this cycle — which is what allows back-to-back transfers rather than one every other cycle.

Contract. Once accepted, the payload is retained until the next layer takes it, and buf_data_q cannot change underneath it.

Failure/DV. Remove the buffer and restore ready = 1'b1 and you get the silent loss traced above. The assertions in §6 catch both the loss and the corruption forms.

6. Two Invariants Worth Asserting

Illustrative layer-boundary properties — conceptual invariants, not UCIe normative requirements.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// 1. A payload presented at a layer boundary must not change while the
//    layer below is stalling. This is what lets the lower layer take
//    several cycles to decide, or register the payload later.
property p_hold_adapter_payload_when_stalled;
  @(posedge clk) disable iff (!rst_n)
    (adp_tx_valid && !adp_tx_ready) |=> (adp_tx_valid && $stable(adp_tx_data));
endproperty
assert property (p_hold_adapter_payload_when_stalled)
  else $error("payload changed at the FDI-side boundary while stalled");
 
// 2. No protocol traffic may be accepted while the link is not usable.
//    Catches exactly the "ready is always 1" bug: without this, payloads
//    are retired into a link that cannot carry them.
property p_no_protocol_accept_when_link_down;
  @(posedge clk) disable iff (!rst_n)
    !link_operational |-> !(proto_tx_valid && proto_tx_ready);
endproperty
assert property (p_no_protocol_accept_when_link_down)
  else $error("protocol transfer accepted while link not operational");

The first catches corruption: a sender that advances its payload while stalled, so the receiver eventually captures the wrong beat. The second catches loss: acceptance of traffic that nothing downstream can carry. Between them they cover the two ways a layer boundary betrays the layer above it, and both are cheap to bind into any boundary you build.

7. A Cycle-Level Walkthrough

Follow one payload down the stack. This is a conceptual ownership sequence, not a claim about UCIe latency — real implementations pipeline differently, and §8 explains why that is not a contradiction.

  • Cycle 0. Protocol presents a payload with proto_tx_valid high. The link is operational and the boundary buffer is empty, so proto_tx_ready is high. The transfer fires.
  • Cycle 1. The payload is in the boundary buffer; adp_tx_valid is high toward the Adapter. Suppose the Adapter is busy — adp_tx_ready low. The buffer holds. adapter_has_space is now low, so the Protocol Layer is correctly told to wait, and it holds its next payload rather than losing it.
  • Cycle 2. The Adapter accepts. Occupancy clears, adapter_has_space rises, and Protocol may present again. The Adapter now does its work — framing the payload for transport and, in the appropriate mode, attaching error-detection information.
  • Cycle 3. The Adapter presents a transport unit to the PHY across the RDI boundary. If the physical link is applying backpressure the Adapter holds it, exactly as the boundary above held its payload.
  • Later. The PHY transmits across the package. The remote PHY receives, hands upward to the remote Adapter, which checks and reconstructs, and hands upward to the remote Protocol Layer — which finally sees a payload with the same meaning the originating Protocol Layer gave it.

The pattern to extract is that each boundary behaves identically: present, hold while stalled, release on acceptance. That regularity is what makes the stack tractable to design and to verify.

8. Layering Is Ownership, Not Pipeline Depth

The misconception most likely to mislead an RTL engineer, and worth killing immediately.

Three layers does not mean three cycles. Layers are a partition of responsibility, not a mandated sequence of pipeline stages. A boundary can be purely combinational in an implementation where timing allows, or several cycles deep where the design needs pipelining, buffering, clock-domain crossing, or width conversion. Two conforming implementations can have different latencies through the same layers.

What the layering does fix is which logic is allowed to do what — and therefore what each boundary must guarantee. That is why the walkthrough above is labelled an ownership sequence: the order in which layers touch a payload is architectural, while the number of cycles each takes is an implementation decision. Chapter 3.3's principle applies inside the endpoint exactly as it did between vendors: the contract is specified, the implementation is free.

9. Why the Split Helps Verification

Layering decomposes a hard verification problem into tractable ones, and this structure recurs through the later modules:

  • Protocol-side. Given a protocol implementation, does the traffic it presents at its lower boundary match what that protocol should produce? An abstract model stands in for everything below.
  • Adapter. Given well-formed traffic arriving from above and a model of the layer below, does transport preserve payload and ordering under stalls, and behave correctly when errors are injected?
  • PHY. Does the physical layer train, carry transport units, and report status correctly?
  • End-to-end. With two endpoints connected, does information presented at one Protocol Layer emerge intact and correctly at the other?

The decomposition is worth it because each environment can use models rather than full implementations of everything else, and because a failure localises: if the Adapter environment passes and end-to-end fails, the defect is at a boundary or in a layer the Adapter environment modelled rather than exercised. The next chapter turns this into a concrete debug checklist.

10. Common Misconceptions

11. Understanding Check

12. Summary and What Comes Next

UCIe is a stack of three layers, mirrored across a link: Protocol Layer → D2D Adapter → Physical Layer → package channel → Physical Layer → D2D Adapter → Protocol Layer. The two inter-layer boundaries are specified interfaces — FDI between Protocol and Adapter, RDI between Adapter and Physical Layer — which is what allows the layers to be implemented independently, applying Chapter 3.2's lesson inside the endpoint.

Three layers exist because three different problems need independent owners. Protocol owns meaning and works in the transactions of the protocol it implements. The Adapter owns the link abstraction — bring-up and link-state coordination, parameter negotiation with the partner, arbitration between protocols sharing the link, and, in the appropriate mode, CRC and retry; note that in a raw mode that error protection moves up to the Protocol Layer, so responsibility assignment is mode-dependent while the layers are fixed. The PHY owns the channel — lanes, signalling, clocking, and training.

In hardware those boundaries are payload plus backpressure, with status abstracted upward. The characteristic failure is a boundary that claims readiness it cannot honour: tie ready high and the layer above retires a transaction that nothing captured, producing silent loss with a distant symptom. The fix is honest readiness plus storage — acceptance must mean retention. Two invariants cover the boundary: payload held stable while stalled (catches corruption), and no acceptance while the link is unusable (catches loss).

Finally, and most easily misread: layering is ownership, not pipeline depth. Three layers does not mean three cycles, and two conforming implementations may differ in latency through the same structure.

The picture is now in place. Next it becomes an architecture — which functions live where, what state each layer holds, how backpressure and status cross the boundaries, and what goes wrong when responsibility lands in the wrong layer:

  • 4.2 — UCIe Layered Architecture — sharpening the boundaries: layer ownership, state placement, the combinational-path trap, and the invariants that hold each boundary together.

Browse the full path on the UCIe tutorials index.