Skip to content

UCIe · Module 16

UCIe and CXL

Which responsibilities belong to CXL and which to UCIe — why native mapping and streaming are different relationships, the three subprotocols' three different boundary contracts, why a UCIe send is not a CXL completion, the destination decided once and never recomputed, CXL.mem traffic that starves CXL.cache into deadlock, what a UCIe recovery may and may not touch, why a degraded link is slower and not different, and a layer-attribution method for deciding which protocol to blame.

Chapter 16.4 put an existing coherent fabric at a UCIe boundary and found that UCIe carries it as a Streaming Protocol. CXL's relationship is different — official UCIe material maps it natively — and that difference reorganises the whole responsibility ledger.

1. The One-Sentence Model

CXL defines what a transaction means. UCIe determines how that traffic crosses the die boundary. Native mapping changes who provides the transport machinery — it does not move a single semantic responsibility across the line.

2. What This Chapter Owns — and What Module 11 Already Owns

Module 11 is five chapters deep on CXL over UCIe. This chapter does not rewrite any of them.

QuestionWhere it is answeredNot repeated here
Why CXL exists; device types; the coherence contract11.1 — Why CXL Matters
HDM/PDM, memory windows, interleaving, routing11.2 — Memory Expansion Over CXL
Line metadata, transient states, probes, same-line conflict11.3 — Cache Coherency Over CXL
Flit format, ARB/MUX, stacked retry, the delivery fence11.4 — CXL Transport on UCIe
The three state planes, cross-plane validity, four tracking entries11.5 — CXL-over-UCIe Integration

What is new here, and could not have been written before 16.4:

The comparison. CXL is natively mapped; CHI in UCIe 1.0 was a Streaming Protocol in Raw Mode (§3, §4). Module 11 never had a second relationship to compare against, so it could not draw this distinction — and the distinction is what determines who provides the transport machinery for a coherent protocol over UCIe.

The subprotocol asymmetry. Module 11 treats CXL.io, CXL.cache and CXL.mem as three classes in a multiplexer. This chapter treats them as three different boundary contracts with different obligations, different failure modes and different starvation consequences (§7).

Degradation invariance. Modules 14 and 15 taught link degradation; Module 11 predates it in the curriculum. Composing the two — what a lane-width change may and may not do to a CXL semantic — is new (§28, §29).

And an attribution method. §30 is a procedure for deciding which of the two protocols to blame, which is the practical payoff of a responsibility ledger and is the thing engineers actually need at 2 a.m.

3. Sourcing

4. Native Mapping and Streaming Are Different Relationships

The axis 16.4 made visible.

CXL over UCIeCHI over UCIe
How UCIe material describes it"maps ... natively" (§3)a Streaming Protocol (§3)
UCIe 1.0natively mappedRaw Mode only
UCIe 1.1 changemay use the D2D Adapter over FDI
Where the protocol's own link layer sitsCXL has one, with its own CRC and retry (11.4 §12)the fabric brings whatever it has
The design question that followswhich retry is in force11.4 §13's stacked-retry problemwhether any UCIe retry is in force at all (16.4 §6)

Two readings, and they are opposite problems.

CXL's risk is redundancy. CXL has its own link-layer retry; UCIe's Adapter optionally has one. The failure mode is two reliability mechanisms stacked on one path, each retrying the other's retries — which is 11.4 §13, and it produces latency amplification and confusing failure attribution rather than data loss.

CHI's risk is absence. In Raw Mode there is no Adapter CRC or retry to reuse (inferred — 16.4 §3), so if the fabric does not bring its own, the link is unprotected.

Native mapping is a statement about ecosystem and machinery, not about semantics. It does not move ownership, coherence state, ordering or completion into UCIe. Every semantic responsibility stays exactly where it was — which is §6, and is the sentence this whole chapter defends.

5. The Layer Picture

A stack of five responsibility layers. At the top, the CXL semantic protocols: CXL dot io for discovery and control, CXL dot cache for ownership, and CXL dot mem for memory operations, each owning its own meaning, ordering obligations and completion. Below that, the CXL link layers with their own flit framing, per message class credits and link layer retry, taught in chapter eleven point four. Below that, the native mapping boundary, which owns classification, identity association, destination capture and lifetime, and interprets nothing. Below that, the UCIe die to die Adapter with link state management, parameter negotiation, multi protocol arbitration and optional CRC and retry. At the bottom, the UCIe physical layer owning lanes, training, repair and rate, which changes capacity and never meaning.CXL over UCIe — the responsibility ledger, drawnCXL semantic protocolsCXL.io, CXL.cache, CXL.mem — meaning, ordering, completion. Three contracts (§7)CXL.io, CXL.cache, CXL.mem — meaning, ordering, completion. Three contracts (§7)CXL link layersFlit framing, per-class credits, link-layer retry — detailed in 11.4Flit framing, per-class credits, link-layer retry — detailed in 11.4Native-mapping boundaryClassification, identity, destination capture, lifetime. Interprets nothing.Classification, identity, destination capture, lifetime. Interprets nothing.UCIe D2D AdapterLink state, negotiation, multi-protocol arbitration, optional CRC and retry (§3)Link state, negotiation, multi-protocol arbitration, optional CRC and retry (§3)UCIe Physical LayerLanes, training, repair, rate. Changes capacity — never meaning (§29)Lanes, training, repair, rate. Changes capacity — never meaning (§29)
Responsibility, top to bottom. CXL's three subprotocols own meaning; the native-mapping boundary owns classification and lifetime; the Adapter and physical layer own transport. Boundaries are drawn at responsibility, not at any specified interface.

The middle layer is the chapter. Above it, meaning. Below it, transport. It is the only place where a semantic lifetime and a transport lifetime are both visible, which is why it is where the mistakes are.

6. The Responsibility Ledger

ResponsibilityCXLUCIeQualification
Memory semantic operationownstransports"memory use cases are handled through CXL.Mem" (§3)
Cache ownership semanticsownstransportscaching addressed through the caching protocol (§3)
Discovery and control semanticsownstransportsaddressed with PCIe/CXL.io (§3)
Address decode and destinationownsmust not change it in flight (§13)mechanism in 11.2
Semantic completionownsmust not be substituted by transport completion (§11)the retirement point is CXL's
Ordering obligationsownsmust be preserved by the mappingno CXL ordering rule stated here
Flit framing and per-class creditsCXL's own link layerAdapter framing where applicable11.4
Link-layer retryCXL has oneAdapter optionally has onewhich is in force is the open question (11.4 §2)
Link state, parameter negotiationUCIeAdapter role (§3)
Lane training, repair, rate, widthUCIeModules 7, 8, 14

Three rows carry the chapter.

Row 5 — completion. UCIe signals transmitted and later delivered. CXL defines complete. §11 is the bug where the first is mistaken for the third, and it is the single most common CXL-integration defect.

Row 4 — destination. The address decode is CXL's, performed once. Anything that recomputes it later — after a retry, after a recovery, after a configuration change — has taken a CXL responsibility and executed it at the wrong time (§14).

Row 8 — retry. It is genuinely ambiguous, it is stated as ambiguous, and an implementer must resolve it from the revision they build rather than assume it. A wrong answer designs in either an unprotected link or two stacked mechanisms.

7. Three Subprotocols, Three Different Boundary Contracts

The section that most distinguishes this chapter from Module 11. Module 11 treats the three as classes in a multiplexer. At the responsibility boundary they are not interchangeable, and the differences drive different bugs.

CXL.ioCXL.cacheCXL.mem
What it carriesdiscovery, configuration, controlownership and permission changesmemory reads and writes
Semantic obligation createda control operation must completean ownership transition must resolvea memory access must return or land
Cost of delaying itusually bounded — control is burstycan deadlock the system (§23)throughput loss
Cost of duplicating itdepends on the operation's idempotencea second ownership action — corruptiona second write — corruption
Destination stability matters?at bring-upper linecritically — §14
Typical bandwidth sharesmallsmalldominant
Boundary riskmistaken for readiness (§19)starved by CXL.mem (§23)starves the others (§23)

Read the last three rows together, because they compose into one system failure.

CXL.mem is dominant in bandwidth and CXL.cache is critical to progress. A shared resource will be filled by the former and needed by the latter. §23 is that collision, and it deadlocks.

And the duplication row is why the three cannot share one duplicate-suppression policy either. Some control operations are naturally idempotent; an ownership transition is not, and neither is a write. A boundary that suppresses duplicates for one class and not another has to justify the asymmetry class by class.

8. What Native Mapping Does and Does Not Buy

Native mapping doesNative mapping does not
let CXL reuse an existing ecosystem across a die boundarymove any semantic responsibility into UCIe
make the Adapter's arbitration available across protocol classesmake the Adapter aware of what a class means
put UCIe's link-state and negotiation machinery underneath CXLgive UCIe an opinion about coherence, ordering or completion
make the reliability question answerable per revision (§6)answer it for you

The tempting inference — "it's native, so UCIe handles it" — is exactly backwards. Native mapping means UCIe carries CXL well. It has never meant UCIe carries CXL's obligations.

9. Four Lifetimes, and the Use This Chapter Makes of Them

11.5 §12 established that one transaction is simultaneously represented in four structures — the semantic entry, the mapping queue entry, the replay entry and the PHY transmit state — and that their occupancies do not have to relate. That is not restated here.

What this chapter adds is the attribution use. Each lifetime, when violated, produces a characteristic failure, and the mapping from failure to lifetime is the debugging method in §30:

Lifetime released too earlyCharacteristic symptom
semantic entrya returning response matches nothing — a hang, far from the cause
mapping entryan accepted object vanishes without ever being transmitted
replay entrya recoverable transport error becomes unrecoverable
PHY statetruncated or interleaved transmission

And released too late:

Lifetime held too longCharacteristic symptom
semantic entryoutstanding-count exhaustion; the fabric throttles for no visible reason
mapping entrytable full; backpressure that looks like link congestion but is not
replay entryreplay-space exhaustion (14.3 §28)

Two symptom families, four structures, and each cell is distinguishable from the others — which is what makes the taxonomy in §31 actionable rather than decorative.

10. The Integration Mapping Entry

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ILLUSTRATIVE integration state. NOT a CXL structure and NOT a UCIe structure,
// and no field corresponds to any specified field of either (Section 3).
typedef struct packed {
  logic                  valid;
  logic [SEM_ID_W-1:0]   cxl_semantic_id;   // CXL's identity for the operation
  logic [CLASS_W-1:0]    cxl_class;         // io / cache / mem — Section 7
  logic [TR_ID_W-1:0]    ucie_transport_id; // UCIe's identity — recycled by UCIe
  logic [DEST_W-1:0]     destination;       // captured ONCE, at acceptance
  logic [EPOCH_W-1:0]    config_epoch;      // which configuration decided that
} cxl_ucie_map_t;
 
cxl_ucie_map_t map_q [MAP_DEPTH];

Architecture. A binding between two namespaces, plus the two facts the boundary must remember about when the decision was made: the destination and the configuration epoch that produced it.

State. MAP_DEPTH entries — the maximum number of accepted-but-unresolved objects. The boundary must backpressure at full, never overwrite (§16's fourth property), because an overwrite silently discards a CXL obligation.

Cycle behaviour. Allocated at acceptance, freed when the operation's transport representation resolves. Not freed when the transport retires — those are different events and §11 is the bug that merges them.

Contract. ucie_transport_id belongs to UCIe and is recycled on UCIe's schedule; cxl_semantic_id belongs to CXL. They must never be treated as one identity, for the reasons 16.4 §12 sets out in detail.

Why config_epoch is not optional. It records which address-decode configuration produced this destination. Without it, a request outstanding across a configuration change is indistinguishable from one issued after it — which is §14, and which has no local symptom at all.

Failure. Omitting destination and recomputing it downstream (§14). Omitting config_epoch and assuming configuration is static (§14 again, one layer deeper).

DV. Assert destination immutability (§16) and that a stale-epoch response cannot resolve a re-driven entry.

11. Wrong RTL — a UCIe Send Treated as a CXL Completion

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// WRONG — the CXL semantic obligation is retired when UCIe accepts the object.
always_ff @(posedge clk)
  if (ucie_tx_fire)
    cxl_txn_valid_q[id] <= 1'b0;      // ← transport launch, not semantic completion

Transport launch is not delivery. Delivery is not action. Action is not completion. This code collapses four distinct events into the earliest and most local one.

What happens, step by step:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
1. The CXL semantic entry is freed the cycle UCIe accepts the object.
2. The object crosses. The remote side acts. A response is generated.
3. The response returns — correctly, intact, at the right time.
4. The boundary looks for the semantic entry: gone.
5. → the response is orphaned, and whatever CXL was waiting on never completes.

Three properties.

Every layer below is blameless. UCIe transmitted, retried where needed, retired its object and delivered a response. The transport scoreboard is clean end to end.

And every layer above is blameless. CXL issued a legal operation and is waiting for a legal completion.

The bug is entirely in the one line that chose the wrong event. ucie_tx_fire is available in this module this cycle; the CXL completion is a round trip and several layers away. That asymmetry is why this bug is written, and it is the sixth time this curriculum has seen a semantic obligation released by a transport signal14.3 §15, 15.2 §15, 11.5 §14, 16.3 §13, 16.4 §26, and now this.

The correct form separates the two explicitly:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ILLUSTRATIVE. Two events, two effects, and they are never the same signal.
always_ff @(posedge clk) begin
  if (ucie_tx_fire)
    map_q[id].transport_launched <= 1'b1;      // transport progress only
 
  if (cxl_semantic_completion_observed[id])    // the CXL-defined event
    cxl_txn_valid_q[id] <= 1'b0;               // and ONLY this frees it
end

12. SVA — Semantic State Survives Transport Ownership

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// MANDATORY. The property that makes Section 11 impossible.
property p_semantic_not_retired_on_transport_event;
  @(posedge clk) disable iff (!rst_n)
    (ucie_tx_fire && !cxl_semantic_completion_observed[ID])
      |=> $stable(cxl_txn_valid_q[ID]);
endproperty
a_semantic_not_retired_on_transport_event:
  assert property (p_semantic_not_retired_on_transport_event);
 
// Nor on transport RETIREMENT, which is a different and later transport event.
property p_semantic_not_retired_on_transport_retire;
  @(posedge clk) disable iff (!rst_n)
    (ucie_object_retired && !cxl_semantic_completion_observed[ID])
      |=> $stable(cxl_txn_valid_q[ID]);
endproperty
a_semantic_not_retired_on_transport_retire:
  assert property (p_semantic_not_retired_on_transport_retire);
 
// A returning response must find a live semantic entry.
property p_response_finds_live_semantic;
  @(posedge clk) disable iff (!rst_n)
    cxl_response_delivered |-> cxl_txn_valid_q[resp_id];
endproperty
a_response_finds_live_semantic: assert property (p_response_finds_live_semantic);

Architecture. Three properties covering the two transport events that tempt an early retire, plus the consequence check.

Why the second property is not redundant with the first. A design that correctly avoids retiring on tx_fire very often retires on ucie_object_retired instead — which is a later, more plausible-looking transport event and is still the wrong one. The semantic obligation outlives both.

Why the third catches what the first two might miss. They are written per-ID and depend on choosing the right ID under test. The third is universal and fires the moment any response arrives for a dead entry — which is the observable form of the bug.

DV. Force an early retire in an error-injection build and confirm all three fire; then confirm they are silent in the clean build across the full regression.

13. CXL.mem at the Boundary

Not a retelling of 11.2. HDM windows, interleaving, the readiness vector and the memory request object are taught there. What the responsibility boundary adds is four obligations:

Address decode happens above the boundary, once. The boundary receives a destination; it does not compute one. A boundary that decodes is doing CXL's job at the wrong layer and at the wrong time (§14).

The destination must not change while the operation is in flight. Whatever the transport does — retry, recovery, re-arbitration — the recorded destination is the one the operation was accepted with (§16).

A transport recovery must not invalidate an accepted memory obligation. The device still owes a response, or the write still has to land. 11.2 §18 established that outstanding state survives UCIe recovery; the responsibility statement is that survival is CXL's requirement, not the transport's courtesy.

And a response must map back to its semantic request, exactly once. 11.2 §19 has the mechanism. The boundary obligation is that the identity used for that mapping is CXL's, never UCIe's (§10).

14. Wrong Integration — the Destination Recomputed After a Recovery

The strongest cross-module bug in the chapter, because it composes a Module 11 mechanism with a Module 14 event.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// WRONG — the destination is derived at TRANSMIT time from live configuration.
assign tx_destination = decode_hdm(map_q[id].address, hdm_config_q);
//                                                     ^^^^^^^^^^^^
//                             live configuration, read at an arbitrary later cycle

The sequence:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
1. A CXL.mem write to address A is accepted. Configuration epoch 7 decodes
   A to device X. The operation is now an obligation against device X.
2. UCIe enters recovery. The object has not yet been transmitted, or is replayed.
3. During or after recovery, host software reconfigures the memory map.
   Configuration epoch 8 decodes A to device Y.
4. The object is transmitted. `decode_hdm` is evaluated NOW — epoch 8.
5. → the write lands in device Y.

Four properties, and they make this the worst kind of bug.

There is no local symptom whatsoever. UCIe transported perfectly. The write was well-formed, accepted and acknowledged. Device Y stored exactly the bytes it was sent. Every layer reports success.

It is silent data corruption at two addresses. Device X's copy of A is stale; device Y has data that does not belong to it at that offset. Neither device can detect this, because neither has any way to know what the other holds.

The window is narrow and load-dependent, which means it will not appear in directed tests and may appear in the field.

And the detector cannot be local. It requires a model that predicts the destination independently, from the configuration in force at acceptance11.5 §20's point, and §32's Layer 1.

The correct form captures the decision, not the inputs to it:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ILLUSTRATIVE. The destination is a DECISION, made once and recorded, along
// with the configuration epoch that produced it.
always_ff @(posedge clk)
  if (cxl_accept_fire) begin
    map_q[alloc_id].destination  <= decode_hdm(accept_address, hdm_config_q);
    map_q[alloc_id].config_epoch <= hdm_config_epoch_q;
  end
 
// And transmission uses the recorded decision — never a fresh decode.
assign tx_destination = map_q[id].destination;

15. Wrong Integration — a Replay Producing a Second Semantic Action

The CXL.cache version, and it is 11.3 §25's hazard stated as a responsibility.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// WRONG — the semantic layer is driven by physical arrival.
always_ff @(posedge clk)
  if (ucie_object_arrived)
    start_ownership_transition(arrived_line, arrived_requester);

A retransmitted object arrives again, and this allocates a second ownership transition for one line. Both may probe; a single response may satisfy both; both may commit.

DuplicatedConsequence
an ownership requesttwo transitions for one line; both may grant (11.3 §16)
a probethe target may respond twice
a responsepending state cleared twice — a premature commit (16.2 §21)

All three are coherence corruptions with a transport cause, and the transport did nothing wrong. The fix is the same construction as 11.4 §16's semantic delivery fence and 16.3 §11's gate: the semantic layer is reached by delivery, never by arrival. The invariant it enforces:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
semantic allocations per CXL operation  == 1
transport attempts per object           >= 1
SEMANTIC DELIVERIES per object          <= 1

16. SVA — Destination and Semantic Identity Are Immutable

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// MANDATORY. The destination is decided once (Section 14).
property p_destination_immutable;
  @(posedge clk) disable iff (!rst_n)
    map_q[IDX].valid |-> $stable(map_q[IDX].destination);
endproperty
a_destination_immutable: assert property (p_destination_immutable);
 
// It survives a transport retry unchanged.
property p_destination_stable_across_retry;
  @(posedge clk) disable iff (!rst_n)
    (transport_retry_fire && map_q[IDX].valid) |=> $stable(map_q[IDX].destination);
endproperty
a_destination_stable_across_retry: assert property (p_destination_stable_across_retry);
 
// And across a recovery — the case Section 14 exploits.
property p_destination_stable_across_recovery;
  @(posedge clk) disable iff (!rst_n)
    (ucie_recovery_event && map_q[IDX].valid)
      |=> ($stable(map_q[IDX].destination) && $stable(map_q[IDX].config_epoch));
endproperty
a_destination_stable_across_recovery:
  assert property (p_destination_stable_across_recovery);
 
// Allocation backpressures; it never silently overwrites a live obligation.
property p_no_silent_overwrite;
  @(posedge clk) disable iff (!rst_n)
    map_alloc_fire |-> !map_q[alloc_idx].valid;
endproperty
a_no_silent_overwrite: assert property (p_no_silent_overwrite);
 
// A transport replay allocates no new semantic operation (Section 15).
property p_replay_allocates_nothing;
  @(posedge clk) disable iff (!rst_n)
    (ucie_object_arrived && duplicate_attempt) |=> $stable(semantic_alloc_count);
endproperty
a_replay_allocates_nothing: assert property (p_replay_allocates_nothing);

Architecture. Immutability under three different events, plus overflow safety, plus the replay invariant.

Why three separate immutability properties rather than one. The first is the general invariant; the second and third name the two events that plausibly disturb it. When the general one fails, the specific ones tell you which event did it — which is the difference between a bug report and a debugging session.

Failure the fourth property catches. A full mapping table that overwrites rather than backpressures discards a live CXL obligation with no error anywhere — and the overwriting write is an entirely ordinary allocation, so nothing else will notice.

DV. The third property needs a recovery while an accepted operation is unresolved, and §35's third trace is that scenario.

17. CXL.cache at the Boundary

Not a retelling of 11.3. Line metadata, stable and transient states, probes, same-line conflict and the two completion points are taught there. The responsibility statements are:

Coherence state lives above the transport, always. No transport event — send, retire, retry, recovery — may create, destroy or alter a coherence state. The transport's entire relationship to coherence is delivery.

A UCIe retry cannot allocate another ownership transition (§15).

Pending semantic responses stay live across a UCIe recovery. The agents that owe them still owe them; a link event does not discharge an obligation (11.3 §26).

And a dirty-data obligation survives everything the transport does. Whoever holds the newest copy still holds it after a recovery, a retrain, a width change or a rate change. Losing that obligation is data loss, and it is the one failure in this chapter with no recovery path at all.

18. CXL.io at the Boundary

Concise, because 11.5 §7 owns the readiness vector. The responsibility statement is one sentence and it is worth its own section:

A UCIe link being up proves that bits can cross. It proves nothing about whether the CXL device has been discovered, configured, mapped, or made ready to serve.

Three distinct facts, routinely conflated:

FactEstablished byProves
the link is operationalUCIe training and link statebits cross reliably
the device is discovered and configuredCXL.io control operationsthe device exists and has been set up
a region is usableaddress decode plus device readinesstraffic to that range will be served

Each is necessary and none implies another. §19 is the bug of assuming the first implies the third.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// WRONG — transport liveness treated as semantic readiness.
assign cxl_ready = ucie_link_active;

Everything that can be true while ucie_link_active is asserted:

ConditionConsequence of admitting traffic
discovery has not completedrequests to a device the host has not identified
the memory map is not programmedrequests to an address with no defined target
the device's memory is not initialisedreads return whatever the device happens to hold
the coherence agent is not readyownership requests against uninitialised metadata (11.1 §13)
a region is being reconfigured§14's window, deliberately entered

The correct form is a conjunction whose terms are separately owned:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ILLUSTRATIVE. Each term is established by a different layer, and every one
// of them is necessary. Not all subprotocols need be enabled in every design —
// the conjunction is over what THIS design actually uses.
assign cxl_admit_allowed =
      ucie_transport_ready_q            // UCIe: link operational
   && cxl_config_valid_q                // CXL.io: device discovered and configured
   && region_mapped_q                   // address decode: this range has a target
   && class_target_ready_q;             // the target is ready for THIS class

Architecture. A named conjunction rather than an alias. Each term names the layer that owns it, so a failure to admit is immediately attributable.

Cycle behaviour, and this is the subtle part. The conjunction is evaluated at acceptance, and the result is bound to the accepted operation — it is not re-evaluated continuously underneath work already accepted. 11.5 §9 makes that argument in full; the responsibility version is that withdrawing readiness must not retroactively cancel an obligation the system already took on.

Failure. Any single-term shortcut. Also making class_target_ready_q a single bit shared by all three subprotocols, which asserts that they become ready together — and they do not (§7).

20. Class Resource Sharing — Three Structures

One shared poolPer-class poolsShared + reservation
Utilisationhighestlowesthigh
Head-of-line blocking across classesyesnobounded
CXL.mem can starve CXL.cacheyes — §23nono
State costsmallestNUM_CLASSES × depthpool + a small slice
Suitssingle-class trafficstrict isolation requirementsmost real designs

21. Progress Reservation

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ILLUSTRATIVE admission and arbitration state. A bounded reservation, not a
// full QoS scheme — what breaks Section 23's cycle is a bound, not fairness.
logic                    cache_progress_pending;   // a response that RESOLVES an obligation
logic                    mem_bulk_pending;
logic [AGE_W-1:0]        progress_wait_q;          // saturating
logic                    progress_resource_available;
 
assign progress_resource_available =
       (free_slots > RESERVED_FOR_PROGRESS) || cache_progress_pending;
 
always_comb begin
  tx_select = TX_IDLE;
  if (cache_progress_pending && (progress_wait_q >= PROGRESS_BOUND))
    tx_select = TX_CACHE_PROGRESS;                 // bounded override
  else if (mem_bulk_pending && progress_resource_available)
    tx_select = TX_MEM_BULK;
  else if (cache_progress_pending)
    tx_select = TX_CACHE_PROGRESS;
end
 
always_ff @(posedge clk or negedge rst_n)
  if (!rst_n)
    progress_wait_q <= '0;
  else if (cache_progress_pending && !(tx_fire && (tx_select == TX_CACHE_PROGRESS)))
    progress_wait_q <= (progress_wait_q == AGE_MAX) ? AGE_MAX : progress_wait_q + 1'b1;
  else if (tx_fire && (tx_select == TX_CACHE_PROGRESS))
    progress_wait_q <= '0;

Architecture. Two mechanisms working together: a reservation that stops bulk traffic from consuming the last slots, and a bounded override that guarantees progress traffic is served within PROGRESS_BOUND even if the reservation is somehow exhausted. Belt and braces, deliberately — the reservation is the common case and the override is the guarantee.

State. One saturating age counter and one comparison against free_slots. Saturating, because an age counter that wraps reports young exactly when the problem is worst (13.4 §13).

Cycle behaviour. tx_select is combinational. progress_wait_q advances only when progress traffic is pending and did not actually transfer — not merely when it was not selected, because a selected transfer that the downstream refused has not made progress either.

Contract. The coherence layer above depends on responses being delivered within a bound in order to guarantee its own liveness (11.3 §29). That dependency is invisible at this block's interface, which is precisely why §22 asserts it.

Failure. Setting RESERVED_FOR_PROGRESS to zero, which deletes the guarantee while leaving all the code that looks like it. Or classifying every CXL.cache message as progress-critical, which reserves so much that the reservation stops functioning as one.

DV. Saturate with CXL.mem traffic, trickle CXL.cache responses, and check progress_wait_q never reaches AGE_MAX. Then set RESERVED_FOR_PROGRESS to zero and confirm the design deadlocks in the predicted way — which validates that the mechanism is doing what the argument says.

22. SVA — Progress-Sensitive Traffic Is Served, Under Assumptions

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// LIVENESS, bounded, with assumptions stated. An unqualified eventuality would
// be unprovable and useless (15.2 Section 36).
//
//   A1: the transport eventually accepts when not in recovery
//   A2: pending progress traffic remains pending until served
//   A3: recovery terminates (14.2 Section 30)
assume property (@(posedge clk) disable iff (!rst_n)
  (tx_valid && !recovery_active) |-> ##[1:TX_ACCEPT_BOUND] tx_ready);
assume property (@(posedge clk) disable iff (!rst_n)
  (cache_progress_pending && !tx_fire) |=> cache_progress_pending);
 
property p_progress_served_within_bound;
  @(posedge clk) disable iff (!rst_n)
    cache_progress_pending
      |-> ##[1:PROGRESS_SERVICE_BOUND] (tx_fire && (tx_select == TX_CACHE_PROGRESS));
endproperty
a_progress_served_within_bound: assert property (p_progress_served_within_bound);
 
// Bulk traffic is not starved either — fairness, a DIFFERENT claim.
property p_bulk_not_starved;
  @(posedge clk) disable iff (!rst_n)
    mem_bulk_pending |-> ##[1:BULK_FAIRNESS_BOUND] (tx_fire && (tx_select == TX_MEM_BULK));
endproperty
a_bulk_not_starved: assert property (p_bulk_not_starved);

Architecture. Two bounded liveness properties with different bounds, plus three explicit assumptions.

Why the second matters as much as the first. A reservation that is too aggressive inverts the problem: bulk memory traffic starves instead, and the system is now slow rather than stopped. That is a better failure and it is still a failure, and only a property with its own bound will catch it.

Why A3 must be an assumption. Without it, the progress property fails on a design that is correct and merely stuck in a long recovery. Stating it converts "this hangs" into "this hangs because recovery did not terminate" — a diagnosis rather than a symptom.

DV. Prove both. Then disable A3 and confirm the first fails, verifying that the assumption is load-bearing rather than decorative.

23. Wrong Resource Sharing — CXL.mem Starves CXL.cache Into Deadlock

The system insight of the chapter, and it needs no unfairness, no bug in any single block, and no protocol violation.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
1. A large CXL.mem streaming workload fills the shared transport staging.
2. A CXL.cache response — one that RESOLVES an ownership obligation — queues
   behind that bulk traffic and is not scheduled.
3. The coherence agent waiting on that response cannot complete its transition.
4. The line stays in a transient state; further operations on it are serialised
   behind the transition (11.3 §15).
5. The CXL.mem workload eventually issues an access to that line — or to a line
   whose transition is queued behind the same resource.
6. → deadlock, in a system that was tuned for memory throughput.

Four properties that make it genuinely hard.

Every participant is correct. CXL.mem is issuing legal requests. The scheduler is applying a defensible policy. The coherence agent is waiting for a response it is entitled to. No assertion about safety fires, because nothing incorrect happens — nothing happens at all.

It is delayed and load-dependent. Low and moderate load never reaches it. It appears at exactly the traffic levels a performance campaign is designed to produce, which is when the least verification attention is on functional correctness.

The class asymmetry is what creates it (§7). CXL.mem is the bandwidth-dominant class; CXL.cache carries the progress-critical messages. A shared resource will be filled by the first and needed by the second, and that is a structural property of the workload rather than a bug.

And the diagnosis is actively misleading. The link is busy, no errors are logged, and 15.5 §19's classifier reports high useful cycles right up to the stall. Everything reads healthy except that nothing completes.

The remedy is §21's, and the requirement is a bound, not fairness — because what has to be broken is a dependency cycle, and a cycle is broken by any guaranteed service, however small.

24. Recovery — Who Owns What

StateOwnerWhat a UCIe recovery does to it
CXL semantic request outstandingCXLpreserved — the obligation is unchanged
CXL cache line state, stable or transientCXLuntouched — indexed by address, not by link
Dirty-data obligationCXLuntouched — losing it is data loss (§17)
Recorded destination and config epochintegrationpreserved and not recomputed (§14, §16)
Mapping entryintegrationretained, re-qualified by epoch
Queued, unsent objectsintegrationheld, never dropped
Address-decode configurationCXL / host softwareunaffected by the link event — but it may change for other reasons (§14)
Replay entriesUCIe reliabilityresolved by the reliability layer (14.3 §37)
Credits, link state, lane mapUCIerebuilt (14.2 §6)
In-flight physical attemptsUCIeretransmitted or abandoned

Read the top six rows. None of them is a link property, so none of them has any business changing when the link is re-established. A recovery re-establishes a link — nothing more (14.2 §4).

And read row 7 carefully, because it is the one that catches people. The link event does not change the memory map. But a recovery is often accompanied by software activity, and if that activity remaps a range while an operation is outstanding against it, §14's window is open — which is why the epoch record exists.

25. Lost Response Ambiguity

A timeout says no response arrived. It does not say the remote did nothing.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
1. A CXL.mem write is transmitted and delivered.
2. The remote device performs the write. The data has landed.
3. The response is lost — or its transport acknowledgement is.
4. The local side times out.
5. It CANNOT conclude that the write did not happen.

Three consequences, and the middle one is where designs go wrong.

Re-issuing is safe only if the operation is idempotent. A plain write to a fixed address usually is. An ownership transition is not, and neither is a read-modify-write (11.3 §27, 14.2 §22).

Rolling back is not available. The remote state has already moved and cannot be un-moved by a local decision. A design that "cleans up" by assuming the operation did not occur has made its model diverge from reality — and the divergence is silent.

And the semantic entry must stay live. It correctly records an unresolved obligation. The resolution is to determine what happened, not to assume — which is exactly what an exactly-once transport mechanism exists to make determinable (14.3 §20).

26. Degradation — Capacity Changes, Semantics Do Not

A link may recover narrower or slower (14.4).

ChangesDoes not change
bandwidth across the boundarywhat any CXL operation means
latency of every transferany semantic identity
queue occupancy, backpressure, credit dynamicsany address's meaning or destination
replay-window pressure (14.3 §28)any coherence state or obligation
how long an operation takeswhether it completes correctly

A degraded link is slower. It is not different. A design in which a width change alters a CXL outcome has coupled a performance property to a correctness property, and the coupling is the bug — whichever outcome it happens to produce.

Note the third row on the right, because it is this chapter's specific hazard. 11.2 established that a memory address's destination is architectural state. A width change must not touch it — and §27 is the mechanism by which it accidentally does.

27. Wrong RTL — a Bound Derived From a Fixed Cycle Count

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// WRONG — the timeout assumes full-width, full-rate transport, forever.
localparam int TIMEOUT_CYCLES = 4096;    // measured on an x16 link at full rate
 
always_ff @(posedge clk)
  if (op_outstanding[id] && (age_q[id] >= TIMEOUT_CYCLES))
    declare_operation_failed(id);        // ← fires on a healthy, degraded link

What happens after a recovery to half width:

LinkTypical completionTIMEOUT_CYCLESVerdict
x16, full rate~2,100 cycles4096fine
x8, full rate~3,900 cycles4096marginal
x4, reduced rate~7,600 cycles4096spurious failure on every operation

Three consequences.

A capacity change is reported as a fault. The transport is working; the operation would have completed. The timeout manufactures a failure that did not exist.

And the response to that fault is usually worse than the fault. Declaring an operation failed may trigger a recovery, a retry storm, or an escalation (14.5) — on a link that had just successfully recovered, potentially producing a recovery loop.

The fix is that bounds which must survive degradation are derived from the active configuration, not from a constant measured once:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ILLUSTRATIVE. The bound scales with the ACTIVE configuration, and the
// configuration is the committed one (14.4's requested-vs-active distinction).
logic [TO_W-1:0] timeout_cycles_q;
always_ff @(posedge clk)
  if (config_commit_fire)
    timeout_cycles_q <= scale_timeout(BASE_TIMEOUT, active_width_q, active_rate_q);

And the same reasoning applies to every depth, credit and window sized against a peak the link may no longer be delivering. If the response to a full structure is anything other than backpressure, degradation becomes loss (§16).

28. The Attribution Method

The practical payoff of a responsibility ledger. Given a failure, decide which of the two protocols to investigate — in a fixed order, because the cheap questions eliminate the most cases.

StepQuestionIf yesIf no
1Did every object cross intact and exactly once?continueUCIe transport — integrity, retry, recovery
2Did each semantic operation get exactly one delivery?continuethe boundary — the delivery gate (§15)
3Did each response resolve to a live semantic entry?continuethe boundary — lifetime (§11)
4Was every destination the one captured at acceptance?continuethe boundary — destination handling (§14)
5Did any progress class exceed its service bound?continue
6If none of the above, the failure is semanticCXL — coherence, ordering, memory semantics

Three notes on using it.

Steps 1 to 4 are answerable from the boundary's own instrumentation, cheaply and without a semantic model. Most integration failures are eliminated in those four steps, and reaching step 6 with all four clean is genuine evidence that the problem is above the boundary.

Step 5 is deliberately not a pass/fail gate. A starved progress class is a contributing condition, not usually the whole story — but knowing it occurred reframes everything below it.

And a "yes" at every step is not proof of a CXL bug. It is proof that this boundary is not the cause, which is a smaller and much more defensible claim — and it is the one that ends the "is it your layer or mine" conversation with evidence instead of assertion.

29. Three Scoreboard Layers

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Verification-only. THREE models, three identities, three failure classes.
class cxl_ucie_scoreboard;
 
  // ---- Layer 1: CXL SEMANTIC model. What was promised, and to whom.
  typedef struct {
    int  cxl_class;              // io / cache / mem
    bit  live;
    int  predicted_destination;  // computed INDEPENDENTLY, from the config in
                                 // force at ACCEPTANCE — this is what catches §14
    int  accept_config_epoch;
    int  semantic_deliveries;    // MUST be <= 1
    int  allocations;            // MUST be 1
    bit  completed;
  } semantic_op_t;
 
  // ---- Layer 2: INTEGRATION model. Which mapping represents it, for how long.
  typedef struct {
    int  semantic_id;
    int  transport_id;
    int  recorded_destination;
    int  recorded_config_epoch;
    bit  bound;
    bit  survived_recovery;
  } integration_t;
 
  // ---- Layer 3: UCIe TRANSPORT model. What physically happened.
  typedef struct {
    int  attempts;
    bit  retired;
    bit  crossed_recovery;
  } transport_obj_t;
 
  semantic_op_t   semantic    [int];
  integration_t   integration [int];
  transport_obj_t transport   [int];
 
  // ---- The check that catches Section 14, and nothing else can.
  function void check_destination(int sid, int idx);
    if (integration[idx].recorded_destination != semantic[sid].predicted_destination)
      $error("DESTINATION DIVERGED op %0d: recorded %0d, predicted %0d "
           , "(accept epoch %0d, recorded epoch %0d) — Section 14",
             sid, integration[idx].recorded_destination,
             semantic[sid].predicted_destination,
             semantic[sid].accept_config_epoch,
             integration[idx].recorded_config_epoch);
  endfunction
 
  // ---- The check that catches Section 11.
  function void check_lifetime(int sid);
    if (!semantic[sid].live && !semantic[sid].completed)
      $error("SEMANTIC OP %0d retired without completion — Section 11", sid);
  endfunction
 
  // ---- Cross-layer conservation (Section 15).
  function void check_conservation(int sid);
    if (semantic[sid].allocations != 1)
      $error("OP %0d allocated %0d times (must be 1)", sid, semantic[sid].allocations);
    if (semantic[sid].semantic_deliveries > 1)
      $error("OP %0d delivered %0d times (must be <= 1)",
             sid, semantic[sid].semantic_deliveries);
  endfunction
 
  // ---- Recovery survival (Section 24).
  function void check_recovery_survival(int idx);
    if (integration[idx].survived_recovery && !integration[idx].bound)
      $error("BINDING %0d lost across recovery — Section 24", idx);
  endfunction
 
endclass

Architecture. Three models keyed by semantic identity, mapping index and transport object.

The field that matters most is predicted_destination. It must be computed by the model, from the configuration in force at acceptance — never read back from the design. A model that reads the design's recorded destination and compares it to the design's transmitted destination is comparing the design to itself, and §14 passes.

And accept_config_epoch alongside it is what makes a divergence explicable rather than merely detected: the error message names which configuration each side used.

30. Why This Differs From Module 11's Integration Scoreboard

11.5 §20's three-model scoreboard is organised by state plane — memory mapping, coherence, transport — because that chapter is about three planes being simultaneously valid.

This one is organised by responsibility owner — CXL, the boundary, UCIe — because this chapter is about attribution.

11.5's modelThis chapter's model
Keyed byplaneowner
Question it answersis each plane internally consistent?whose responsibility failed?
Distinguishesmemory vs coherence vs transport stateCXL vs boundary vs UCIe
Feedscross-plane validity checks§28's attribution procedure

They are complements, not alternatives. A serious environment builds both, and the reason is visible in one example: a wrong destination is a memory-plane failure in 11.5's model and a boundary failure in this one — and both statements are true, because the memory plane's state was corrupted by the boundary using it at the wrong time. The first tells you what is broken; the second tells you who broke it.

31. Flagship Trace 1 — a CXL.mem Request Across UCIe

Illustrative. One memory read, accepted at configuration epoch 7.

CycCXL semantic opRecorded dest / epochMapping entryUCIe objectLinkNote
0operational
1accepteddev X / epoch 7operationaldestination decided ONCE
2liveX / 7boundoperational
3liveX / 7boundformed, retainedoperational
4liveX / 7boundattempt 1transmittinguses the recorded dest
6liveX / 7boundin flightoperational
7liveX / 7boundarrivedoperationalintegrity checked
8liveX / 7bounddeliveredoperationalsemantic delivery ×1
9liveX / 7boundacknowledgedoperational
10liveX / 7boundretiredoperationalsemantic op still live
14liveX / 7boundoperationaldevice X reads
18liveX / 7boundoperationalresponse in flight
20liveX / 7boundoperationalresponse arrives
21liveX / 7boundoperationalmatched to semantic id
22liveX / 7releasedoperationalmapping freed
23liveoperationaldata returned to CXL
24completedoperationalsemantic completion

Four readings.

Cycle 1 records the destination and the epoch, and neither is touched again. Everything downstream uses the record, never a fresh decode. §14's bug is re-deriving it at cycle 4.

Cycle 10: the UCIe object retires while the semantic operation is live — fourteen cycles before completion. §11's bug is freeing the semantic entry here.

Cycle 22 releases the mapping when the response resolves, not when the transport retired. Two structures, two lifetimes.

And cycle 24 is the completion — not cycle 4, not cycle 10, not cycle 20. Four candidate events, one correct answer, and the correct one is the last and least local.

32. Flagship Trace 2 — a CXL.cache Ownership Transition With a Replay

CycSemantic transitionPending responsesUCIe attemptsSemantic deliveriesCorrect?
1allocated (once)00
3live{B}attempt 10
6live{B}arrived, integrity FAIL0✓ gate blocks
10live{B}attempt 2, same object0✓ replay
13live{B}arrived, OK1✓ first delivery
14live{B}1B invalidates
16live{B}1B's response sent
18live{B}1response lost
24live{B}attempt 3 — lost-ACK replay1
26live{B}arrived, OK1duplicate suppressed
27live{B}1ACK re-sent anyway
30live{}1B's re-sent response lands
31committed1one transition

Four readings.

Three physical attempts, one semantic delivery, one ownership transition. §15's invariant holding under replay.

Cycle 1 allocates once and nothing re-allocates. §16's fifth property is exactly this.

Cycle 26 and 27 are the two halves that pull opposite ways. The effect is suppressed — B does not invalidate twice and no second transition appears. The reply is not — because a silent duplicate leaves the pending set non-empty forever (14.3 §22).

And the CXL layer above saw one clean transition. Slower than it would have been. Not different.

33. Flagship Trace 3 — Degradation With CXL Traffic Outstanding

CycSemantic ops outstandingRecorded destsLinkActive configWhat must be true
06X, X, Y, X, Y, Yoperationalx16, full ratesteady
56unchangederror detectedx16
66unchangedrecovery enteredx16no semantic op is cancelled
76unchangedquiescingx16queued objects held
126unchangedretraining
186unchangedrecoveredx4, reduced ratedestinations untouched
196unchangedoperationalx4timeouts rescaled (§27)
206unchangedoperationalx4transmission resumes
404unchangedoperationalx4draining — slower
900operationalx4all six completed correctly

Five readings, and this is the chapter's clearest statement of its thesis.

Cycle 6: six operations outstanding, six preserved. Not one is cancelled, failed or re-issued. The link event has no semantic content.

Cycle 18: the link returns at a quarter of the width and a lower rate. Roughly an order of magnitude less capacity. Every recorded destination is byte-identical to cycle 0.

Cycle 19 is the step most designs omit. Bounds derived from the previous configuration are now wrong, and if they are not rescaled the very next cycle produces §27's spurious failures — on a link that just recovered successfully, potentially looping.

Cycles 20 to 90: the drain is slow. Ten times the cycles for the same six operations. That is the correct outcome, and a performance report should say so rather than a fault report.

And every operation completed correctly. Capacity changed; correctness did not. If any of the six had completed differently, the design would have coupled the two.

34. Error Injection

#InjectionTargets
1retry on an outbound CXL.mem object§15 — duplicate delivery
2retry on a CXL.cache response§32's cycle 24 — the duplicate that must still be answered
3lost response after the remote acted§25 — timeout ambiguity
4recovery with operations outstanding§24, §33
5memory remap while an operation is outstanding§14 — the silent-corruption case
6recovery returning a narrower link§26, §27, §33
7mapping table full§16's fourth property
8sustained CXL.mem load with CXL.cache responses trickling§22, §23
9ucie_link_active before CXL.io configuration completes§19
10a region withdrawn after acceptance but before transmission§19's binding-at-acceptance rule
11transport identity reused while the semantic op is live§10's contract
12dirty owner probed, then the link degrades§17 — obligation survival
13all three classes offered simultaneously at full rate§7, §20

Two notes.

Row 5 is the highest-value injection in the chapter and the one most environments cannot produce, because it needs configuration change coordinated with in-flight traffic. It is the only test of §14, and §14 is silent data corruption.

Row 2 is not the same test as row 1. A retried request and a retried response break different things (§34's first two rows are two different failures) — and an environment that injects only on the request path tests half the boundary.

35. Coverage

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
covergroup cg_cxl_ucie_boundary @(posedge clk);
  option.per_instance = 1;
 
  // --- The class dimension (Section 7).
  cp_class : coverpoint active_cxl_class {
    bins cxl_io    = {0};
    bins cxl_cache = {1};
    bins cxl_mem   = {2};
  }
  cp_class_mix : coverpoint num_classes_active {
    bins one = {1}; bins two = {2}; bins all_three = {3};   // Section 20
  }
 
  // --- Lifetime (Sections 11, 12).
  cp_retire_event : coverpoint semantic_retire_trigger {
    bins on_completion = {0};                 // the only correct one
    bins on_tx_fire    = {1};                 // must never occur
    bins on_retire     = {2};                 // must never occur
  }
 
  // --- Destination stability (Sections 14, 16).
  cp_config_change : coverpoint config_change_relative_to_op {
    bins none          = {0};
    bins before_accept = {1};
    bins after_accept_before_tx = {2};        // THE case — Section 14
    bins after_tx      = {3};
  }
  cp_dest_epoch_mismatch : coverpoint dest_epoch_mismatch_observed;
 
  // --- Transport interaction (Section 15).
  cp_retry_point : coverpoint retry_occurred_on {
    bins none = {0}; bins request = {1}; bins response = {2};
  }
  cp_duplicate_gated : coverpoint duplicate_suppressed_at_gate;
 
  // --- Recovery and degradation (Sections 24, 26, 27).
  cp_recovery_point : coverpoint recovery_during {
    bins none = {0};
    bins ops_outstanding = {1};
    bins objects_queued  = {2};
  }
  cp_width_after_rec : coverpoint width_after_recovery {
    bins same = {0}; bins narrower = {1};     // Section 33
  }
  cp_timeout_rescaled : coverpoint timeout_rescaled_after_config_commit;
 
  // --- Readiness (Sections 18, 19).
  cp_readiness : coverpoint admit_gate_terms_false {
    bins none         = {0};
    bins transport    = {1};
    bins cxl_config   = {2};
    bins region_map   = {3};
    bins target_ready = {4};                  // each term must gate ALONE
  }
 
  // --- Liveness (Sections 21-23).
  cp_progress_wait : coverpoint progress_wait_q {
    bins none = {0};
    bins some = {[1:PROGRESS_BOUND-1]};
    bins at_bound = {PROGRESS_BOUND};         // the override firing
  }
 
  // --- Crosses that carry the information.
  x_config_recovery : cross cp_config_change, cp_recovery_point;   // Section 14
  x_class_progress  : cross cp_class, cp_progress_wait;            // Section 23
  x_recovery_width  : cross cp_recovery_point, cp_width_after_rec; // Section 33
  x_retry_class     : cross cp_retry_point, cp_class;
endcovergroup

Six bins whose value is in whether they are reachable at all:

cp_retire_event.on_tx_fire and .on_retire must stay at zero. They are the only bins in this curriculum whose coverage goal is never to be hit — they exist as detectors, and hitting either is §11.

cp_config_change.after_accept_before_tx. §14's exact window. It requires configuration change coordinated with in-flight traffic and is the bin most environments lack.

cp_readiness — every term, alone. Each admission term must be shown to gate by itself; a design where one term is redundant has a readiness check that is smaller than it looks (§19).

cp_width_after_rec.narrower. §26 and §33. A recovery that returns the same width tests nothing about degradation.

cp_timeout_rescaled. §27's fix, exercised. A design that never rescales will pass every test that never degrades.

And cp_class_mix.all_three. All three subprotocols active simultaneously — §7's asymmetry and §23's starvation both need it, and neither appears with one class active.

36. Debug Taxonomy

SignatureMost likely causeFirst instrument
UCIe packets correct, stale or wrong dataCXL semantics or §14 — not transportLayer-1 predicted destination vs recorded
A CXL operation disappears after a recovery§24 — the boundary released semantic state on a transport eventwhat was cleared at the recovery cycle
A response arrives and matches nothing§11 — semantic entry retired earlywhich event freed it: tx_fire, retire, or completion?
Duplicate ownership action after a retry§15 — semantic layer driven by arrival, not deliveryis there a delivery gate, and is it combinational?
Link active, CXL request rejected§19 — higher-layer readiness or configuration incompletewhich admit-gate term is false
Heavy CXL.mem load hangs CXL.cache traffic§23 — no progress reservationprogress_wait_q under load; is anything reserved?
Operations fail immediately after a successful recovery§27 — a bound not rescaled to the active configurationwhich timeouts derive from active width and rate
A degraded link changes an address's destination§14 + §26 — decode coupled to live configurationis the destination recorded at acceptance?
Writes land, reads return stale, no errors anywhere§14 — two devices each holding part of one addresspredicted vs recorded destination, per operation
Transfers vanish under load with no error§16's fourth property — mapping table overwrittenoccupancy vs MAP_DEPTH; is there an overflow assertion?
Retries never stop on one object§32's cycle 27 — the duplicate suppressed the reply toois the acknowledgement re-sent on a recognised duplicate?

Row 9 deserves emphasis. Writes land, reads return stale, and nothing anywhere reports an error is the signature of §14, and it is the hardest failure in this chapter. Every layer is functioning; the operations simply went to two different places.

37. Debug Checklist

  1. Which CXL subprotocol — io, cache or mem? (§7)
  2. Which semantic operation, and what identity does it carry?
  3. What destination was recorded, and at which configuration epoch? (§10)
  4. Does that match what an independent model predicts from the accept-time configuration? (§29)
  5. Which mapping entry represents it, and to which UCIe transport identity?
  6. How many transport attempts occurred?
  7. How many semantic deliveries occurred? Must be ≤ 1. (§15)
  8. Did a retry occur — on the request, on the response, or both? (§34)
  9. Did a UCIe recovery occur while the operation was outstanding? (§24)
  10. Did the link return at a different width or rate? (§26)
  11. Were bounds rescaled to the active configuration afterwards? (§27)
  12. Did the memory map change at any point during the operation's life? (§14)
  13. Is the semantic entry still live — and if not, which event freed it? (§11)
  14. Did the response resolve to a live semantic entry? (§12)
  15. Which admit-gate terms were true at acceptance? (§19)
  16. Was CXL.cache progress traffic starved by CXL.mem? (§23)
  17. Is a dirty-data obligation involved, and where is it? (§17)
  18. Run §28's attribution steps in order — which step first answered "no"?
  19. Which scoreboard layer diverged first? (§29, §30)

38. Common Misconceptions

"UCIe owns CXL coherence." It does not. Official UCIe material says UCIe maps CXL natively and that caching requirements are addressed through the caching protocol. Native mapping is a statement about ecosystem and machinery. Not one semantic responsibility crosses the line (§3, §4, §8).

"CXL and UCIe transaction lifetimes are the same." One CXL operation is simultaneously represented in several structures with different lifetimes, and the transport's representation typically retires while the semantic obligation is still outstanding (11.5 §12, §9).

"A UCIe link being active means CXL is ready." The link being up proves bits can cross. It proves nothing about discovery, configuration, address mapping, or a target being ready to serve — and each of those is necessary and none implies another (§18, §19).

"A UCIe retry should regenerate the CXL operation." A retry re-transmits the same object. Regenerating the operation produces a second semantic action — a second ownership transition, or a second write — from a mechanism that was working correctly (§15).

"CXL.mem and CXL.cache can always share one queue safely." CXL.mem is bandwidth-dominant and CXL.cache carries progress-critical responses. A shared resource will be filled by the first and needed by the second, and the resulting deadlock is safety-correct, load-dependent, and arrives at exactly the traffic levels a performance campaign produces (§7, §23).

"UCIe recovery invalidates CXL semantic state." It does not. A recovery re-establishes a link. Outstanding requests, line states, dirty-data obligations, recorded destinations and queued objects all survive — and the recorded destination in particular must not be recomputed afterwards (§14, §24).

"A clean UCIe transport scoreboard proves CXL correctness." Every object can cross once with clean integrity, every replay entry can retire, and a write can still land in the wrong device. Transport correctness is a strictly weaker claim (§14, §29).

"Link degradation only changes physical bits, so there is no visible impact." Degradation changes latency, bandwidth, queue pressure and replay dynamics — which is very visible in performance. What it must not change is any semantic outcome, and a design with fixed-cycle timeouts converts a capacity change into a manufactured fault (§26, §27).

"Module 11 and this chapter are the same topic." Module 11 teaches the mechanisms — flit framing, HDM windows, coherence states, the three state planes. This chapter teaches the responsibility ledger and an attribution method, and it is only possible after 16.4 because the CXL/CHI contrast is what makes native mapping meaningful as a category (§2, §4, §30).

39. Understanding Check

40. Module 16 Complete — and What Comes Next

Module 16 in five chapters:

16.1Shared memorywhat it takes for several dies to agree that address X names one location
16.2Cache coherencythe state that makes N-agent coherence correct — ownership, sharers, transients
16.3Coherency across UCIesemantic operations against messages against attempts, generically
16.4The CHI boundarya Streaming Protocol; reliability ownership depends on mode and revision
16.5The CXL boundarynatively mapped; the responsibility ledger and how to attribute a failure

And one sentence held across all five: transport carries meaning without owning it. Every failure in the module is a design that let a transport event decide something semantic — a pending bit cleared on transmit, a binding freed on retirement, a semantic entry retired on a send, a destination recomputed after a recovery, a bound derived from a width that no longer exists.

Two protocols, two relationships, one ledger. CXL is natively mapped and CHI was a Streaming Protocol in Raw Mode; the machinery differs and not one semantic responsibility moves in either case.

Three subprotocols, three contracts. CXL.io is mistaken for readiness, CXL.cache is starved, CXL.mem starves — and each has its own duplication cost.

And an attribution method that answers "whose layer" with evidence: exactly-once crossing, exactly-one delivery, a live entry for every response, a destination unchanged since acceptance, and a progress class within its bound.

Module 16 has treated memory as something coherence operates on. Module 17 turns to the memory itself — the memory chiplet as a manufactured, standalone die with its own timing, its own maintenance obligations, and its own reasons for existing, reached across exactly the boundary this module has spent five chapters characterising.

Browse the full path on the UCIe tutorials index.