Skip to content

UCIe · Module 16

UCIe and CHI

Where an existing CHI coherent fabric stops and the UCIe die boundary begins — the responsibility ledger, why CHI was a Streaming Protocol in UCIe 1.0 and what UCIe 1.1 changed, the bridge that must not become a second home node, semantic identity surviving a transport identity that is recycled beneath it, per-class queues and progress traffic that must never be starved, metadata that must not drift from its payload, what survives a UCIe recovery mid-transaction, and why a lane-width change must be invisible to coherence.

Chapter 16.3 taught coherence crossing a chiplet boundary in the abstract — semantic operations, messages, transport attempts, and the gate between them. This chapter puts a real coherent fabric on one side of that boundary and asks a narrower question with a much sharper answer.

1. The One-Sentence Model

CHI owns coherence semantics. UCIe owns die-to-die transport. The integration problem is preserving CHI's meaning while changing the physical boundary underneath it — and every bug in this chapter is a design that let the transport boundary reach up and change the meaning.

2. What This Chapter Owns — and What It Deliberately Does Not

This is not a CHI tutorial. This repository already has a full CHI curriculum, and this chapter links into it rather than restating it.

QuestionWhere it is answered
What is CHI, and why was it created?CHI 19.1 — What Is CHI?
What are the node roles?CHI 4.2 — RN · 4.3 — HN · 4.4 — SN
What are the four channels?CHI 6.1 — The Four CHI Channels
What are CHI's cache states?CHI 10.1 — The CHI Cache States
How does CHI order transactions?CHI 12.2 — Transaction Ordering
How does a coherent op cross any chiplet boundary?16.3 — Chiplet-Level Coherency
How does CXL ride UCIe, in mechanism detail?11.4 · 11.5

What is new here, and could not have been taught earlier:

The relationship is different from CXL's. Official UCIe material maps PCIe and CXL natively; CHI appears in that material as a Streaming Protocol, and in UCIe 1.0 only in Raw Mode (§3, §6). That single difference reorganises the whole responsibility ledger, and Module 11 never had to confront it because Module 11 never discussed CHI.

The bridge is a real block with real state. 16.3 kept the boundary abstract. Here it is a design: a mapping table, per-class queues, an arbiter, a recovery epoch, and a set of things it must be forbidden from knowing (§9).

And the failure modes are named-protocol failures — a transport identity recycled under a live CHI transaction, a UCIe recovery flushing a bridge table, a lane-width change altering coherence behaviour.

3. Sourcing

4. The Layer Picture

A stack of five responsibility layers. At the top, CHI coherence agents and the home node own ownership semantics, snoop meaning, transaction identity, ordering obligations and completion. Below that, a CHI to UCIe bridge owns only classification, identity mapping, queueing, arbitration and lifetime, and is explicitly forbidden from interpreting coherence. Below that, the UCIe transport path, which in UCIe 1.0 for streaming protocols was Raw Mode and from UCIe 1.1 may instead use the die to die Adapter over FDI and reuse its CRC and retry. Below that, the UCIe physical layer owning lanes, training, repair and rate. At the bottom, the package channel carrying the bumps and traces between dies.CHI over UCIe — who owns which jobCHI coherence fabricOwnership, snoop meaning, identity, ordering, completion — see the CHI trackOwnership, snoop meaning, identity, ordering, completion — see the CHI trackCHI-to-UCIe bridgeClassification, identity mapping, queues, arbitration, lifetime. Interprets nothing.Classification, identity mapping, queues, arbitration, lifetime. Interprets nothing.UCIe transport pathRaw Mode in UCIe 1.0; from 1.1, the D2D Adapter over FDI with CRC and retry (§6)Raw Mode in UCIe 1.0; from 1.1, the D2D Adapter over FDI with CRC and retry (§6)UCIe Physical LayerLanes, training, repair, rate. Changes capacity, never meaning (§28)Lanes, training, repair, rate. Changes capacity, never meaning (§28)Package channelBumps and traces between two diesBumps and traces between two dies
Responsibility, top to bottom. The CHI fabric owns coherence meaning; the bridge owns only translation and lifetime; UCIe owns transport. Layer boundaries are drawn at responsibility, not at any specified interface.

Read the second layer as the whole chapter. It is the only one this chapter designs, it is the smallest, and it is where every bug lives — because it is the one place where a semantic lifetime and a transport lifetime are both visible at once.

5. The Responsibility Ledger

The table to keep. Each row is qualified against what §3 actually verified.

ResponsibilityCHI / coherent fabricUCIeQualification
Cache-line ownership semanticsownsnonearchitecture-level; nothing in UCIe material claims coherence semantics
Snoop meaning and obligationownstransportswhat a snoop obliges is CHI's; this chapter asserts no snoop rule
Semantic transaction identityownsmapped, not replaced (§12)the bridge's mapping is illustrative
Semantic ordering dependenciesownsmust be preserved by the mapping (§29)no CHI ordering rule is stated here
Completion semanticsownsmust not be substituted by transport completionthe retirement point is CHI's, and §34's final property stays abstract
Packet integrity (CRC)the Adapter's, where in the pathUCIe 1.0 quote: optionally guaranteed
Retransmission on failurethe Adapter's, where in the pathRaw Mode: not reused from the Adapter (inferred — §3)
Link state, parameter negotiationUCIeAdapter role, per UCIe 1.0 material
Lane training, repair, rateUCIeModules 7 and 8
Physical capacity of the boundaryUCIeand it changes; see §28

Two rows are the ones engineers actually get wrong.

Row 5 — completion. A transport layer signals delivered. CHI defines complete. They are different events with different lifetimes, and merging them is §13's and §26's family of bugs.

Row 7 — retransmission. It reads "the Adapter's" and it is conditional on a design decision made in §6. A team that assumes UCIe is retrying its CHI traffic, in a configuration where the Adapter is not in the path, has an unprotected coherent link and does not know it.

6. The Mode Question

This decision comes before any of the mechanisms below, because it decides which of them the design must build itself.

Raw ModeThrough the D2D Adapter (FDI)
UCIe 1.0 support for CHI / SMP coherencythe only option (§3)not available
UCIe 1.1 onwardstill availableavailable (§3)
Adapter CRC reusedno (inferred — §3)yes, where applicable
Adapter retry reusedno (inferred — §3)yes, where applicable
Who owns duplicate suppressionthe CHI-side integrationUCIe's mechanism, used by the integration

Three consequences, and the third is the reason the section is first.

Roughly half this chapter is conditional. §23's retry invariant, §24's lost acknowledgement and §26's replay hazard all presume a transport that retransmits. In Raw Mode they describe whatever the CHI-side integration provides instead — identical structure, different provider.

And roughly half is unconditional. Identity mapping, per-class queueing, progress starvation, metadata alignment, recovery lifetime and ordering are consequences of putting a die boundary in the middle of a coherent fabric, and they apply in both modes.

The third consequence is that "which mode" is a verification axis, not a footnote. A design that supports both and tests one has verified half its configurations (§35).

7. What UCIe Does Not Change

State it flatly, because most integration bugs are a violation of one of these lines.

Placing a UCIe link inside a CHI fabric does not:

  • change what a coherence transaction means;
  • change which node is the serialisation point for an address;
  • change what a snoop obliges its target to do;
  • change CHI's transaction identity, or make a transport identity a substitute for it;
  • change when a CHI transaction is complete;
  • change any CHI ordering dependency;
  • make a coherence obligation disappear because a link went down.

It does change how long things take, how much can be in flight, how failures manifest, and how many places a transaction is simultaneously represented. Latency, capacity and failure modes — never meaning.

8. Three Objects at a Named Boundary

16.3's hierarchy, now anchored to a real fabric:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
1 CHI semantic transaction        — one coherent operation, owned by CHI

N CHI protocol transfers          — the messages that operation comprises

N transport objects               — one per transfer at the bridge

≥ N physical attempts             — one or more per object, if the path retries

The invariant that holds across all four levels, and the one every property in §34 is a specialisation of:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
semantic allocations per operation   == 1
transfers per operation              >= 1
attempts per transfer                >= 1
semantic deliveries per transfer     <= 1

A count at one level proves nothing about another. Eight transfers delivered is not one operation completed; twelve attempts is not twelve transfers. §32's three scoreboard layers exist because of that sentence.

9. The Bridge Must Not Become a Second Home Node

The single most important architectural constraint in the chapter, and the one that keeps the bridge small.

A bridge that starts interpreting coherence acquires, in order: a copy of line state, an opinion about ordering, a reason to hold transactions, and eventually a race with the real home node.

The bridge may knowThe bridge must not know
that a transfer belongs to semantic operation Xwhat X means for line ownership
which traffic class a transfer belongs towhether that class implies a coherence state change
where the transfer must be routedwhether the destination will grant or refuse
whether the transfer has been delivered oncewhether the operation has completed
that a recovery occurredwhether the recovery changes any coherence outcome

The bridge tracks lifetimes and identities. It never tracks meaning. Every field it holds must be justifiable as "needed to deliver this exactly once, to the right place, in a way the CHI layer can still recognise" — and if a field cannot be justified that way, it belongs above the bridge.

This is 11.4 §9's rule — the Adapter must not understand coherence — applied one layer up, and the reason it must be restated is that a bridge is far more tempted than an Adapter. It already knows the semantic identity, so knowing a little more feels free.

10. Boundary State — Only What the Boundary Needs

A CHI to UCIe bridge drawn as five internal structures. Incoming CHI transfers enter a classifier, which sorts them into per class queues so that one class cannot block another. An arbiter with a reserved progress slot selects among the queues. Selected transfers are recorded in a mapping table that binds the CHI semantic identity to a UCIe transport identity, a destination and a class, and are then handed to the UCIe transport path. A recovery epoch register qualifies both the mapping table and the delivery gate on the receive side, so that a transfer generated before a link recovery cannot be mistaken for current traffic. The point of the drawing is that the bridge holds only identity, class, destination, lifetime and epoch, and no coherence state at all.CHI transfersfrom the fabricClassifierclass, destinationPer-class queuesno cross-classblockingArbiterreserved progress slotMapping tablesemantic id totransport idRecovery epochqualifies every entryUCIe transportRaw or Adapter path12
The bridge's own state. A mapping table binds each accepted CHI transfer to a transport object; per-class queues keep traffic classes from blocking one another; an arbiter with a reserved progress slot selects among them; and a recovery epoch qualifies everything so that pre-recovery traffic cannot be mistaken for current traffic.

Five structures, and each earns its place by answering a question no other structure can:

StructureThe question only it answers
Mapping tablewhich CHI operation does this returning transport object belong to?
Per-class queuesis this class blocked, or merely behind another class?
Arbiterwhich class transmits this cycle, and is any class starving?
Recovery epochis this arriving object from the current link epoch, or a dead one?
Destination recordwhere was this transfer decided to go — before anything changed?

Nothing in that list is coherence state, which is §9 made concrete.

11. The Boundary Envelope

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ILLUSTRATIVE integration-side envelope.
// NOT an Arm CHI packet, NOT a UCIe wire format, and not claimed to correspond
// to any field of either (Section 3). Symbolic widths throughout.
typedef struct packed {
  logic [SEM_ID_W-1:0]  semantic_id;    // which CHI operation this belongs to
  logic [CLASS_W-1:0]   channel_class;  // which traffic class — Section 15
  logic [DEST_W-1:0]    destination;    // decided ONCE, at acceptance
  logic                 has_data;
  logic [PAYLOAD_W-1:0] payload;        // opaque to the bridge, by Section 9
} chi_ucie_envelope_t;

Architecture. One packed object carrying identity, class, destination, a data-presence flag, and an opaque payload. The opacity is the design: the bridge routes and delivers the payload without parsing it, which is the only structural guarantee that §9's rule cannot quietly erode.

State. One register stage per pipeline stage the envelope passes through. Packed, not a bundle of parallel signals — §21 is what happens when the fields travel separately.

Cycle behaviour. Formed at acceptance and held stable until it is transferred (§22). destination is captured at acceptance and never recomputed, which is the property §26's recovery case and 16.5's remap case both depend on.

Contract. The remote side must be able to recover semantic_id and channel_class from what it receives, or it cannot associate the transfer with anything. How that is achieved on the wire is a mapping question this chapter does not answer, because no source I could reach describes one.

Failure. Omitting destination and recomputing it downstream — the bug in §26's family. Or omitting channel_class and inferring it from the payload, which puts the bridge in the business of parsing (§9).

DV. Assert stability under stall (§22). Assert that the class recovered at the remote end equals the class assigned at acceptance (§21's detector).

12. Semantic Identity Must Survive the Mapping

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ILLUSTRATIVE mapping table. TWO NAMESPACES, deliberately kept apart.
typedef struct packed {
  logic                   valid;
  logic [SEM_ID_W-1:0]    semantic_id;    // CHI's — the fabric allocates and frees it
  logic [TRANSPORT_W-1:0] transport_id;   // UCIe's — the transport recycles it
  logic [DEST_W-1:0]      destination;
  logic [CLASS_W-1:0]     channel_class;
  logic [EPOCH_W-1:0]     epoch;          // which link epoch created this binding
} chi_map_entry_t;
 
chi_map_entry_t map_q [MAP_DEPTH];

Architecture. A binding, not a container. The table exists because two layers name the same thing differently and each recycles its names on its own schedule — and if a design can carry the semantic identity inside the transfer and recover it on arrival, this table shrinks or disappears, which is the better design where it is available.

State. MAP_DEPTH entries. Sizing is the maximum number of transfers the bridge may have accepted but not resolved, which is a bridge parameter, not a CHI one — and the bridge must backpressure rather than overflow (§34).

Cycle behaviour. An entry is written when the arbiter selects a transfer, and freed when the transfer is resolved. Written and freed on different events, which is why the two must never share a signal.

Contract, and it is the section's point. The transport identity is allocated and recycled by the transport layer, on a schedule that has nothing to do with CHI. 14.3 §24 established that a retransmission reuses the same transport identity, and 12.4 established that identities are recycled after retirement. So a transport identity identifies "this object" only within its own epoch, and a design that stores CHI state under a transport index inherits a recycling policy CHI never agreed to.

Failure. §13.

DV. Assert that semantic_id is stable for a given operation across every attempt of every one of its transfers — the property that separates the levels of §8.

13. Wrong RTL — Transport Identity Replaces Semantic Identity

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// WRONG — the bridge keys its state on the TRANSPORT identity.
always_ff @(posedge clk)
  if (transfer_accepted) begin
    bridge_q[transport_id].valid       <= 1'b1;      // ← transport-indexed
    bridge_q[transport_id].destination <= dest;
    bridge_q[transport_id].chi_context <= chi_ctx;
  end
 
// ... and later, when something comes back:
always_ff @(posedge clk)
  if (transport_response_arrived)
    chi_return(bridge_q[resp_transport_id].chi_context);   // ← may be a stale row

Why it looks reasonable. The transport identity is right there on the interface, it is dense, and it indexes a small array beautifully.

Why it is wrong, in three independent ways.

Recycling. The transport layer frees a transport identity when its obligation ends — typically at acknowledgement (14.3 §14). The CHI operation is usually still live at that moment. The next transfer allocated may legitimately receive the same transport identity, overwriting the row that a still-outstanding CHI transaction depends on.

Cardinality. One CHI operation spans several transfers, hence several transport objects (§8). A transport-indexed table cannot express "these four rows are one operation" — so the bridge cannot answer the only question it exists to answer.

Retry. A retransmission reuses the same transport identity. If the bridge treats an arriving object as a fresh allocation, a replay allocates a second binding for a transfer that already has one — 16.3 §10's duplicate, at a named boundary.

What the reader sees in the lab. Responses come back and are handed to the CHI fabric — for the wrong transaction. Transport statistics are perfect: every object was sent, acknowledged and retired. The transport scoreboard passes and the fabric misbehaves, which is the signature in §36.

14. SVA — One Semantic Owner Per Live Transport Object

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// MANDATORY. A live mapping entry binds exactly one semantic operation, and the
// binding does not change under it.
property p_one_semantic_owner_per_object;
  @(posedge clk) disable iff (!rst_n)
    (map_q[IDX].valid && $past(map_q[IDX].valid))
      |-> $stable(map_q[IDX].semantic_id);
endproperty
a_one_semantic_owner_per_object: assert property (p_one_semantic_owner_per_object);
 
// A transport retry must not create a new binding.
property p_retry_creates_no_binding;
  @(posedge clk) disable iff (!rst_n)
    (transport_object_arrived && duplicate_attempt) |=> $stable(map_alloc_count);
endproperty
a_retry_creates_no_binding: assert property (p_retry_creates_no_binding);
 
// A returning object must resolve to a LIVE entry of the CURRENT epoch.
property p_response_resolves_to_live_entry;
  @(posedge clk) disable iff (!rst_n)
    transport_response_delivered
      |-> (map_q[resp_idx].valid && (map_q[resp_idx].epoch == current_epoch));
endproperty
a_response_resolves_to_live_entry: assert property (p_response_resolves_to_live_entry);
 
// The table must backpressure rather than overwrite.
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);

Architecture. Four properties: a binding is stable, a retry creates none, a response resolves to a live current-epoch entry, and allocation never silently overwrites.

Why the fourth is not paranoia. §13's failure is exactly a silent overwrite, and it is silent by construction — the overwriting write is a perfectly ordinary allocation. The assertion is the only thing that makes it loud.

DV. The second property needs a retry to occur while a CHI transaction is live, which does not happen spontaneously and is a coverage cross in §35.

15. Traffic Classes at the Boundary

CHI separates traffic into channels. This chapter does not assert what those channels are permitted or required to do — CHI 6.1 is where that is taught. What matters at the boundary is architectural and protocol-neutral:

Different semantic classes have different ordering requirements, different response expectations, and different importance to forward progress. A boundary that flattens them into one stream has destroyed information the fabric above it depends on.

Class propertyConsequence at the boundary
some classes carry obligations being createdthey may be delayed without deadlocking anything
some classes carry obligations being resolveddelaying them can deadlock the fabric (§18)
some classes must not be reordered relative to each otherthe mapping must preserve that (§29)
some classes carry bulk datathey will fill any shared resource, given the chance

The last two rows in combination are the whole of §16 through §19, and the general principle is 11.3 §28's: a message that resolves an obligation must not queue behind one that creates obligations.

16. Queueing Architecture — Three Choices

One shared queuePer-class queuesHybrid: shared + reservation
Area / statesmallestNUM_CLASSES × depthshared pool + a small reserved slice
Utilisationhighestlowest — a full class cannot borrowhigh
Head-of-line blockingyes, across classesnobounded
Deadlock risk from class couplingreal (§18)removed by constructionremoved by reservation
Complexitytrivialmoderatemoderate

The recommendation, stated as one rather than dressed as a law. For a coherent fabric crossing a die boundary, the hybrid is usually right: a shared pool for utilisation, with a small reserved capacity for whichever classes resolve obligations. The reservation does not need to be large — it needs to be non-zero and guaranteed, because what breaks the deadlock cycle is a bound, not fairness.

17. Arbiter RTL — Rotating, With a Reserved Progress Slot

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ILLUSTRATIVE class arbiter. Rotating priority with a reserved slot for
// progress-critical traffic. Not a CHI-mandated policy (Section 16).
logic [NUM_CLASSES-1:0]      req;
logic [NUM_CLASSES-1:0]      grant;
logic [CLASS_W-1:0]          last_grant_q;
logic [NUM_CLASSES-1:0]      is_progress_class;   // static configuration
logic [AGE_W-1:0]            progress_wait_q;     // how long progress has waited
 
// Rotating mask: everything strictly "after" the last grant, wrapping.
logic [NUM_CLASSES-1:0] rotated_req;
always_comb
  for (int c = 0; c < NUM_CLASSES; c++)
    rotated_req[c] = req[(c + last_grant_q + 1) % NUM_CLASSES];
 
// The reservation overrides rotation once progress has waited too long.
logic progress_starved;
assign progress_starved = (progress_wait_q >= PROGRESS_BOUND);
 
always_comb begin
  grant = '0;
  if (progress_starved && |(req & is_progress_class))
    grant = lowest_set(req & is_progress_class);      // bounded override
  else
    grant = unrotate(lowest_set(rotated_req), last_grant_q);
end
 
// State advances ONLY on an actual transfer — never on a grant that did not fire.
always_ff @(posedge clk or negedge rst_n)
  if (!rst_n) begin
    last_grant_q    <= '0;
    progress_wait_q <= '0;
  end else begin
    if (tx_fire)
      last_grant_q <= onehot_to_index(grant);
 
    if (|(req & is_progress_class) && !(tx_fire && |(grant & is_progress_class)))
      progress_wait_q <= (progress_wait_q == AGE_MAX) ? AGE_MAX : progress_wait_q + 1'b1;
    else if (tx_fire && |(grant & is_progress_class))
      progress_wait_q <= '0;
  end

Architecture. Rotating priority for fairness, with a bounded override so that progress-critical traffic can never wait longer than PROGRESS_BOUND. The override is what turns a fairness policy into a liveness guarantee, and the two are not the same thing (§19).

State. last_grant_q (the rotation pointer) and progress_wait_q (a saturating age). Saturating, not wrapping — an age counter that wraps reports young at the moment the problem is worst, which is 13.4 §13's rule.

Cycle behaviour. grant is combinational from req. last_grant_q advances only on tx_fire — never on a grant that the downstream did not accept. That is the single most-repeated arbiter bug in this curriculum (13.4 §18), and its symptom here is a class being skipped in rotation without ever having transmitted.

Contract. The queues rely on eventual selection; the fabric above relies on progress traffic being bounded. Both are properties of this block, and neither is visible from its interface — which is why §19 asserts them.

Failure. Advancing last_grant_q on grant instead of tx_fire. Or setting is_progress_class to zero "for now", which silently deletes the liveness guarantee while leaving the code that looks like it.

DV. Drive sustained requests on every class and check the maximum observed inter-grant gap per class. Then drive sustained bulk load with progress requests trickling in, and check progress_wait_q never reaches AGE_MAX.

18. Wrong RTL — Strict Priority for Bulk Data

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// WRONG at system scope. A coherence obligation can be starved indefinitely.
assign tx_select = data_pending ? TX_DATA : TX_COHERENCE_CONTROL;

The failure sequence, and every step is individually correct:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
1. A streaming workload keeps `data_pending` continuously asserted.
2. Progress-critical coherence traffic is never selected.
3. The home node waits for a response that is queued behind bulk data.
4. Transactions the fabric is holding for that line never resolve.
5. The bulk workload itself eventually needs a line whose ownership is
   stuck at step 4.
6. → deadlock, in a system that was "optimised" for data throughput.

Three properties that make this hard to find.

It is safety-correct. No coherence rule is violated at any point. Nothing is corrupted, nothing is delivered twice, no assertion about ownership fires. The system is simply stopped, and safety verification has nothing to say about it.

It is delayed and load-dependent. For a long time the system runs beautifully with excellent throughput. The failure arrives only when the data path itself needs a coherence transition — which may be far into a run, and never in a short directed test.

And the diagnosis points the wrong way. The link is busy, no errors are logged, and 15.5 §19's classifier reports high useful-cycle counts right up to the hang. Everything says "healthy" except that nothing is finishing.

Unlike 13.4 §16's strict-priority arbiter, this one does not self-resolve. There, a full buffer eventually throttled admissions and let the starved class through. Here the starved message is the thing that would unblock the data path, so the data path keeps generating work until it blocks on what it starved.

19. SVA — Progress-Critical Traffic Is Served, Under Stated Assumptions

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// LIVENESS, bounded, with assumptions stated explicitly. An unqualified
// eventuality here would be unprovable and useless (15.2 Section 36).
//
//   A1: the downstream transport eventually accepts, when not in recovery
//   A2: a requesting class keeps requesting until granted
//   A3: recovery terminates — it does not persist forever (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)
  (req[CLS] && !grant[CLS]) |=> req[CLS]);
 
property p_progress_class_served;
  @(posedge clk) disable iff (!rst_n)
    (req[CLS] && is_progress_class[CLS])
      |-> ##[1:PROGRESS_SERVICE_BOUND] (grant[CLS] && tx_fire);
endproperty
a_progress_class_served: assert property (p_progress_class_served);
 
// And every class is served eventually — fairness, distinct from the above.
property p_every_class_served;
  @(posedge clk) disable iff (!rst_n)
    req[CLS] |-> ##[1:FAIRNESS_BOUND] (grant[CLS] && tx_fire);
endproperty
a_every_class_served: assert property (p_every_class_served);

Architecture. Two liveness properties with different bounds. PROGRESS_SERVICE_BOUND should be small and is guaranteed by the reservation; FAIRNESS_BOUND is larger and comes from rotation.

Contract, and the reason they are separate. Fairness says everyone eventually goes. Progress-liveness says the specific traffic that unblocks the system goes soon. A design can be perfectly fair and still deadlock, because "eventually" measured in rotation cycles is unbounded when a class can always re-request.

Failure. Writing one property with a single generous bound and calling it both. When it fails, it does not tell you which guarantee broke.

DV. Prove both with the assumptions enabled. Then deliberately disable A3 and confirm the proof fails — which validates that the assumption is describing a real dependency rather than papering over one.

20. Metadata and Payload Must Stay Aligned

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ILLUSTRATIVE. Metadata and payload travel as ONE object through every stage.
// Section 21 is what happens when they do not.
chi_ucie_envelope_t stage_q [PIPE_DEPTH];
 
always_ff @(posedge clk)
  if (stage_advance)
    for (int s = PIPE_DEPTH-1; s > 0; s--)
      stage_q[s] <= stage_q[s-1];

Architecture. A packed envelope shifted as a unit. The whole point is that there is no way to advance the class without advancing the payload, because they are the same register.

State. PIPE_DEPTH copies of the envelope — more area than moving a narrow tag beside a wide bus, and that cost buys a structural guarantee.

Cycle behaviour. All fields advance on the same enable. No field has its own valid, its own enable, or its own bypass.

Contract. The receiver associates a payload with a class. If the association can be wrong, every downstream decision is made about the wrong thing — and the payload itself will be perfectly intact, which is what makes it so hard to see.

Failure. §21.

DV. At the remote end, compare the recovered class against a testbench-tracked expectation keyed by a reference ID. Do not compare it against the class the receiver itself derived, which would compare the design to itself.

21. Wrong RTL — Class Delayed Differently From Payload

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// WRONG — the class tag takes a shorter path than the payload.
always_ff @(posedge clk) begin
  payload_q  <= payload_in;                  // 1 cycle
  class_q    <= class_in;                    // 1 cycle
  class_q2   <= class_q;                     // ...but only the payload is
  payload_q2 <= payload_q;                   //    further delayed downstream
  payload_q3 <= payload_q2;                  // ← 3 stages
end
assign out_class   = class_q2;               // ← 2 stages. Off by one, forever.
assign out_payload = payload_q3;

One transfer's payload is emitted with the previous transfer's class.

Cyclepayload emittedclass emittedcorrect?
nP0C0✓ by luck — first transfer
n+1P1C0
n+2P2C1

Three properties that make this a flagship bug.

Transport integrity passes completely. Every bit crossed correctly; CRC is clean; nothing was retried. The payload is exactly what was sent. It is being interpreted as the wrong kind of thing.

The remote side reconstructs a valid object. It is not malformed, so nothing rejects it. It is a well-formed transfer of the wrong class, which is a protocol corruption that only a semantic model can detect.

And it is systematic, not intermittent. Every transfer after the first is wrong by exactly one. Which paradoxically makes it easier to find once suspected and nearly impossible to find by staring at waveforms, because each individual cycle looks reasonable.

22. SVA — the Envelope Is Stable Under Stall

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// MANDATORY. An offered envelope does not change while it is waiting.
property p_envelope_stable_under_stall;
  @(posedge clk) disable iff (!rst_n)
    (tx_valid && !tx_ready) |=> (tx_valid && $stable(tx_envelope));
endproperty
a_envelope_stable_under_stall: assert property (p_envelope_stable_under_stall);
 
// Class and payload advance together — never one without the other.
property p_class_payload_move_together;
  @(posedge clk) disable iff (!rst_n)
    $changed(out_payload) |-> $changed(out_class) || (out_class == $past(out_class) && payload_repeat);
endproperty
 
// The class recovered remotely equals the class assigned at acceptance.
// tb_class_of() is TESTBENCH knowledge — the design must not synthesise it.
property p_class_survives_the_boundary(int unsigned rid);
  @(posedge clk) disable iff (!rst_n)
    (remote_deliver && (tb_ref_id == rid)) |-> (remote_class == tb_class_of(rid));
endproperty
a_class_survives_the_boundary: assert property (p_class_survives_the_boundary(REF_UT));

Architecture. Stability under stall, joint movement, and an end-to-end class check.

Why the third must use a testbench reference ID. The wire carries a class field; the knowledge that "this payload was assigned class C at acceptance" belongs to whatever generated the traffic. Synthesising that knowledge into the design to assert against would build a second copy of the same logic, with the same bug.

DV. §21's off-by-one is caught by the third property on the second transfer of any stream — so it needs at least two back-to-back transfers of differing classes, which is a trivial test that a single-transaction smoke test does not contain.

23. Retry Interaction — the Invariant, Not the Mechanism

Where 14.3 meets this chapter. The exact retry mechanism depends on §6's mode and on the UCIe revision, and this chapter does not state it. What it states is the invariant that must hold whoever provides it:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
semantic allocations per CHI operation   == 1
transfers per operation                  >= 1
physical attempts per transfer           >= 1
SEMANTIC DELIVERIES per transfer         <= 1

Two kinds of duplicate, and they must be distinguished at the boundary:

Physical duplicateSemantic duplicate
What it isthe same transfer transmitted againa second, genuinely new CHI transfer
Causelost acknowledgement, integrity failure, replaythe fabric issued another one
Correct handlingsuppress the semantic effectprocess it
Told apart bytransport identity and historysemantic identity

The gate is the same construction as 16.3 §11: the CHI fabric is reached by semantic delivery, never by physical arrival. In Raw Mode there is no Adapter history to lean on (§6), so the integration must supply the equivalent — the gate's shape does not change, its implementation does.

24. Lost Acknowledgement, Named

Only applicable where the path retries (§6). The canonical case:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
1. The bridge transmits a CHI transfer; the transport retains it for replay.
2. The remote side receives it, and the remote bridge delivers it semantically
   to its CHI fabric — ONCE. The fabric acts.
3. The transport-level acknowledgement is lost on the return path.
4. The local transport replays the object. It arrives at the remote side again.
5. The remote bridge MUST NOT deliver it to the CHI fabric a second time.

Step 5 is the whole difficulty, and it has the same two halves as 14.3 §22:

Suppress the effect. The fabric has already acted; acting again is a second semantic action that the invariant in §23 forbids.

Do not suppress the reply. If the remote side recognises the duplicate and stays silent, the local transport never gets its acknowledgement and replays forever — a livelock built from two individually correct behaviours. The acknowledgement must be re-sent.

And the local CHI fabric must not be told anything at all. From above the bridge, the retry is invisible: one transfer, one delivery, one completion. That invisibility is the bridge's entire job in this scenario, and a bridge that surfaces retries upward has made the fabric depend on transport behaviour.

25. Recovery While a CHI Transaction Is Live

The hardest case in the chapter. A UCIe recovery is a transport event (14.2 §4). It has no coherence meaning.

StateOwnerSurvives a UCIe recovery?
CHI semantic transactionthe fabricyes — the operation is not finished
CHI line/ownership statethe fabricyes — per address, not per link
Any dirty-data obligationthe fabricyes — losing it is data loss
Bridge mapping entrythe bridgeyes — re-qualified by epoch, not deleted (§26)
Recorded destinationthe bridgeyes — and it must not be recomputed
Queued, unsent transfersthe bridgeyes — held, not dropped
Transport replay entriesthe transportresolved by the reliability layer (14.3 §37)
Credits, link state, lane mapUCIerebuilt (14.2 §6)
In-flight physical attemptsUCIeretransmitted or abandoned
Link epochthe bridge and transportincremented — this is the one thing that changes

A recovery re-establishes a link. It does not release a CHI transaction, does not un-invalidate anything, and does not change what any node owes. Everything above the transport rows survives untouched; only the transport rows are rebuilt; and the epoch increment is what lets the two be told apart afterwards.

Why the epoch is not optional. A response generated before the recovery may arrive after it. Without an epoch check it is indistinguishable from a current response, and it will resolve a mapping entry that has since been re-driven. §14's third property is that check.

26. Wrong RTL — Recovery Flushes the Bridge Table

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// WRONG — the bridge treats a transport event as a reason to forget semantics.
always_ff @(posedge clk)
  if (ucie_recovery_entered)
    for (int i = 0; i < MAP_DEPTH; i++)
      map_q[i].valid <= 1'b0;          // ← every live CHI binding, gone

Why it looks reasonable. Recovery means the link state is untrustworthy, and clearing state that describes an untrustworthy link feels like the safe, conservative action.

What actually happens.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
1. A CHI transaction is outstanding; its mapping entry binds it to a transport object.
2. UCIe enters recovery. This code clears the entry.
3. UCIe recovers. The transport replays or re-sends.
4. The response returns, correctly, at the transport level.
5. The bridge looks up its mapping: NOTHING.
6. → the response is orphaned. The CHI fabric waits forever for a completion
     that arrived and was discarded at the bridge.

Three properties.

The transport is blameless. Recovery worked, replay worked, the response crossed intact. The transport scoreboard shows a clean recovery and a delivered response.

The symptom is a hang, far from the cause. The fabric times out on a transaction whose response the bridge threw away several thousand cycles earlier. First-cause diagnostics (14.5) are what connect the two, and without them the investigation starts at the timeout.

And it is the same lifetime error, for the fifth time in this curriculum. 14.3 §15 freed a replay entry on tx_fire; 15.2 §15 retired a latency entry on response arrival; 11.5 §14 retired semantic state at a transport event; 16.3 §13 cleared a pending bit on probe transmission. Every time, a semantic obligation was released by a transport signal — and every time, the transport signal was the local, convenient one.

The correct action is to re-qualify, not to clear:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ILLUSTRATIVE. Recovery advances the epoch; live bindings are retained and
// re-bound to the new epoch. Nothing semantic is discarded.
always_ff @(posedge clk or negedge rst_n)
  if (!rst_n)
    current_epoch_q <= '0;
  else if (ucie_recovery_completed)
    current_epoch_q <= current_epoch_q + 1'b1;
 
always_ff @(posedge clk)
  if (ucie_recovery_completed)
    for (int i = 0; i < MAP_DEPTH; i++)
      if (map_q[i].valid)
        map_q[i].epoch <= current_epoch_q + 1'b1;   // re-bound, still valid

27. SVA — Semantic State Survives a Transport Recovery

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// MANDATORY. The property that makes Section 26 impossible.
property p_map_survives_recovery;
  @(posedge clk) disable iff (!rst_n)
    ucie_recovery_entered |=> ($stable(map_q[IDX].valid)
                            && $stable(map_q[IDX].semantic_id)
                            && $stable(map_q[IDX].destination));
endproperty
a_map_survives_recovery: assert property (p_map_survives_recovery);
 
// Queued but unsent transfers are held, never dropped.
property p_queued_transfers_survive_recovery;
  @(posedge clk) disable iff (!rst_n)
    ucie_recovery_entered |=> $stable(queue_occupancy);
endproperty
a_queued_transfers_survive_recovery: assert property (p_queued_transfers_survive_recovery);
 
// The destination is decided once and never recomputed.
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);
 
// A pre-recovery object cannot resolve a re-bound entry.
property p_stale_epoch_rejected;
  @(posedge clk) disable iff (!rst_n)
    (transport_response_arrived && (resp_epoch != current_epoch_q))
      |=> $stable(map_q[resp_idx]);
endproperty
a_stale_epoch_rejected: assert property (p_stale_epoch_rejected);

Architecture. Four properties covering both failure directions.

Why both directions are needed. The first three protect against a recovery destroying semantic state — the hang in §26. The fourth protects against a recovery admitting state that should have died with the previous epoch — which produces a wrong resolution rather than a hang, and is the harder of the two to debug because the system keeps running.

DV. All four require a recovery injected while a CHI transaction is live with a transfer outstanding, which never occurs spontaneously (§35).

28. Lane and Rate Changes Must Be Invisible to CHI

A link may recover in a degraded configuration — fewer usable lanes, a lower rate (14.4).

What changesWhat must not change
bandwidth across the boundarywhat any CHI transaction means
latency of every transferany transaction's identity
queue occupancy and backpressureany recorded destination
credit and replay dynamicsany coherence state or obligation
how long a transaction takeswhether it completes correctly

Transport capacity is a performance property. Coherence is a correctness property. A design in which a width change alters a coherence outcome has coupled the two, and the coupling is a bug regardless of which value it produces.

Two places the coupling sneaks in.

Timeouts derived from a fixed cycle count. A transaction that completed comfortably at full width may exceed a fixed timeout at half width. The timeout then reports a fault that is really a capacity change, and whatever recovery it triggers is unnecessary and disruptive. Bounds that must survive degradation have to be derived from the active configuration, not hard-coded.

Resource sizing that assumed a rate. A mapping table or queue sized for full-rate drain may back up at reduced rate, and if the bridge's response to a full table is anything other than backpressure, degradation turns into loss (§14's fourth property).

29. The Ordering Boundary

If the coherent fabric imposes a semantic dependency between two operations, the mapping and the transport must not produce an order that violates it.

Three practical implications, kept protocol-neutral.

The dependency is usually narrow and the transport's freedom is usually wide. Two operations on the same line are related; two operations on unrelated lines generally are not. So a transport may reorder freely across the unrelated majority, and must respect order within the narrow minority — which is why line-granular serialisation (16.2 §16) is the right granularity rather than a global order.

A response and the transfer it answers are ordered by causality, not by the transport. A design in which a response can overtake its own request's delivery has a structural error, and it becomes reachable the moment the two travel different queues.

And ordering must be enforced where the semantics live. Forbidding all reordering in the transport is correct and expensive — it serialises the unrelated majority to protect the minority. Enforcing the dependency above the bridge costs nothing for unrelated traffic.

30. Wrong Architecture — Transport QoS Inverts a Dependency

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// WRONG in principle: a class-based fast path that can carry a DEPENDENT
// transfer past the transfer it depends on.
assign use_low_latency_path = (channel_class == CLS_FAST);

The scenario, kept generic because the dependency is:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
1. Transfer A is issued. It is classified onto the normal path.
2. Transfer B is issued later and DEPENDS on A having been observed first.
3. B is classified onto the low-latency path.
4. B is delivered semantically before A.
5. If the fabric requires A-before-B, the mapping has violated it —
   while the transport performed exactly as designed.

Two readings.

A QoS decision became a correctness decision. Latency classes are a performance mechanism. The moment two paths with different latencies can carry semantically dependent traffic, path selection is part of the protocol — and it must then be justified against the protocol's rules rather than against a latency target.

And the correct fix is not "one path". It is that dependent transfers must share an ordering domain, however that domain is realised — same queue, an explicit dependency interlock, or a rule that the dependent transfer is not offered until its predecessor is delivered. Collapsing to a single path is the crude version of that, and it pays for the whole workload to protect a fraction of it.

31. Three Scoreboard Layers

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Verification-only. THREE models, three identities. Section 32 shows why no
// one of them can detect the others' failures.
class chi_ucie_scoreboard;
 
  // ---- Layer 1: CHI SEMANTIC reference model.
  //      What the fabric was asked to do, and what it owes.
  typedef struct {
    bit  live;
    int  destination;
    int  semantic_deliveries;      // per transfer: MUST be <= 1
    int  allocations;              // per operation: MUST be 1
    int  expected_completions;
    bit  completed;
  } semantic_txn_t;
 
  // ---- Layer 2: BRIDGE MAPPING model.
  //      Which semantic identity owns which transport object, and for how long.
  typedef struct {
    int  semantic_id;
    int  transport_id;
    int  channel_class;
    int  destination;
    int  epoch;
    bit  bound;
  } mapping_t;
 
  // ---- Layer 3: UCIe TRANSPORT model.
  //      What physically crossed, how often, and whether it retired.
  typedef struct {
    int  attempts;
    bit  retired;
    bit  crossed_recovery;
  } transport_obj_t;
 
  semantic_txn_t  semantic  [int];    // keyed by CHI semantic id
  mapping_t       mapping   [int];    // keyed by mapping index
  transport_obj_t transport [int];    // keyed by transport object
 
  // ---- Cross-layer conservation (Section 8).
  function void check_conservation(int sid);
    if (semantic[sid].allocations != 1)
      $error("OPERATION %0d allocated %0d times (must be 1)", sid, semantic[sid].allocations);
    if (semantic[sid].semantic_deliveries > 1)
      $error("OPERATION %0d delivered semantically %0d times (must be <= 1)",
             sid, semantic[sid].semantic_deliveries);
  endfunction
 
  // ---- Layer 2 check: a binding never changes owner while live.
  function void check_binding(int idx, int observed_sid);
    if (mapping[idx].bound && (mapping[idx].semantic_id != observed_sid))
      $error("BINDING %0d changed owner: was %0d now %0d — Section 13",
             idx, mapping[idx].semantic_id, observed_sid);
  endfunction
 
  // ---- Cross-layer: recovery must not have cost us a binding.
  function void check_recovery_survival(int idx);
    if (transport[idx].crossed_recovery && !mapping[idx].bound)
      $error("BINDING %0d lost across recovery — Section 26", idx);
  endfunction
 
  // ---- The observation Section 32 is built on.
  function void note_clean_transport_with_semantic_failure();
    $display("NOTE: transport layer clean while CHI semantics failed — "
           , "expected, and the reason three layers exist");
  endfunction
 
endclass

Architecture. Three associative models keyed by three different identities — semantic id, mapping index, transport object. That is §8's hierarchy expressed as verification structure.

What each layer is for. Layer 1 knows there is an obligation. Layer 2 knows which transport object currently represents it. Layer 3 knows what physically happened. No layer can be derived from another, which is exactly §32.

Note what is deliberately abstract. expected_completions and completed are populated from whatever the CHI completion rule turns out to be. This chapter does not fill them in, because doing so would assert a CHI semantic it has not verified (§3).

32. Why One Layer Cannot Substitute for Another

FailureLayer 3 (transport)Layer 2 (mapping)Layer 1 (CHI semantic)
a replay entry leakscatchesblindblind
transport identity recycled under a live binding (§13)blind — recycling was correctcatchescatches, later and confusingly
a retry causes a second semantic delivery (§23)blindcatchescatches, later
the class drifts from its payload (§21)blind — bits were perfectcatches — if it models classcatches
a recovery orphans a binding (§26)blind — recovery succeededcatchescatches as a hang, far away
a dependency inverted by QoS (§30)blindblind — both were mapped correctlycatches
the fabric completes the wrong transactionblindblindcatches

Read the top-left column. A transport model reports success for every failure below the first row. That is 16.2 §31's result at a named boundary: transport correctness is a strictly weaker claim than protocol correctness, and no quantity of the first implies the second.

And read the bottom-right column against the middle one. Layer 1 eventually catches most things — as a hang or a wrong result, thousands of cycles after the cause. Layer 2 exists so the binding failure is reported when the binding fails.

A verification plan with a packet-level scoreboard alone is verifying one third of this boundary and reporting on all of it.

33. Flagship Trace 1 — A Clean CHI Transaction Across UCIe

Illustrative. One CHI semantic transaction, one transfer out, one response back, through the Adapter path.

CycCHI semantic txnBridge map entryTransport objectPHY / linkRemote bridgeCompletion
0operational
1allocatedoperational
2liveoperational— accepted at the boundary
3livebound (epoch 4)formedoperationaldestination captured
4liveboundretained for replayoperational
5liveboundattempt 1transmitting
6liveboundin flighttransmitting
7liveboundin flightoperationalarrivedintegrity checked
8liveboundin flightoperationalgate: valid, not a duplicate
9liveboundin flightoperationalsemantic delivery ×1remote fabric acts
10liveboundacknowledgedoperational
11liveboundretiredoperationalreplay entry released
12liveboundoperationalresponse formed
13liveboundoperationalresponse in flight
14liveboundoperationalresponse arrives locally
15liveboundoperationalresolves to entry, epoch 4 ✓
16livereleasedoperationalhanded to the CHI fabric
17liveoperationalfabric processes
18liveoperational
19liveoperationalCHI completion point
20retiredoperationalsemantic obligation discharged

Five readings, and the lifetimes are the point.

Cycle 1 to 20: one semantic transaction spans nineteen cycles and outlives every transport object inside it.

Cycle 11: the replay entry retires while the transaction continues. Transport's obligation is discharged nine cycles before CHI's. §13's and §26's bugs are both "retire the semantic row at cycle 11 too".

Cycle 8 to 9 is the semantic delivery gate, one cycle after physical arrival. That gap is where integrity, duplication and epoch are checked — and only then does the remote fabric see anything.

Cycle 16: the mapping entry is released when the response resolves, not when the transport object retired at cycle 11. Two structures, two lifetimes, correctly decoupled.

And cycle 19 is the CHI completion point, which this chapter deliberately leaves abstract (§3, §31). Whatever CHI defines it to be, it is not cycle 5 and not cycle 11.

34. Flagship Trace 2 — the Same Transaction, With a Retry

Only the transport rows change. Applicable where the path retries (§6).

CycCHI semantic txnMap entryTransportRemote semantic deliveriesCorrect?
5liveboundattempt 10
7liveboundarrived, integrity FAIL0✓ gate blocks
8livebounddiscarded0
12liveboundattempt 2 — same transport id0✓ retry
14liveboundarrived, integrity OK0
15liveboundgate: not a duplicate1✓ first delivery
22liveboundattempt 3 — lost ACK replay1
24liveboundarrived, integrity OK1
25liveboundgate: DUPLICATE1✓ effect suppressed
26livebound1ACK re-sent anyway (§24)
30livereleasedretired1
34retired1✓ one completion

Four readings.

Three physical attempts, one semantic delivery. §23's invariant, holding.

The map entry is bound throughout. It was not re-allocated on attempt 2 or attempt 3 (§14's second property), and it was not released when the transport retired.

Cycle 25 and 26 are the two halves of §24. The effect is suppressed; the acknowledgement is not. A design that suppresses both livelocks at cycle 26.

And the CHI fabric saw none of this. From above the bridge the trace is identical to §33's — one transfer, one delivery, one completion, arriving later. That invisibility is the correctness criterion.

35. Flagship Trace 3 — Recovery While the Transaction Is Live

The hardest case, and the one §27's properties exist for.

CycCHI semantic txnMap entryEpochTransportLinkWhat must be true
5livebound4attempt 1 in flightoperational
8livebound4in flighterror detected
9livebound4replay heldrecovery enterednothing semantic changes
10livebound4retrainingqueued transfers held
11livebound4retrainingdestination unchanged
14livebound4recovered, x8 → x4capacity changed only (§28)
15livere-bound5operationalepoch advanced, entry retained
16livebound5attempt 2operationalsame destination
19livebound5arrivedoperationalsemantic delivery ×1
23livebound5operationalresponse returns, epoch 5
24livebound5stale response, epoch 4operationalrejected (§27)
25livereleased5operationalresolved by the epoch-5 response
29retired5operationalone completion, degraded link

Five readings, and this is the strongest section in the chapter.

Cycle 9 to 11: the semantic rows do not move. The transaction is live, the binding is bound, the destination is recorded, and the queued transfers are held. §26's bug is clearing the map row at cycle 9.

Cycle 14: the link comes back narrower. Fewer lanes, less bandwidth, more latency. Not one semantic row changes, which is §28.

Cycle 15: the entry is re-bound to epoch 5 — retained, not recreated. The distinction matters: recreating would lose the original acceptance context, including the destination.

Cycle 24 is the case most designs never test. A response generated before the recovery arrives after it, carrying epoch 4. Without the epoch check it would resolve the entry — and the epoch-5 response arriving at cycle 23 would then find nothing. The failure would look like a lost response on a link that had just recovered successfully.

And cycle 29: one completion, on a degraded link. The transaction is correct; it merely took longer. Which is the whole thesis of §28 in one row.

36. Error Injection

#InjectionTargets
1transport retry on an outbound transfer§13, §23 — duplicate binding, duplicate delivery
2transport retry on a returning response§14's third property
3lost acknowledgement with the fabric live§24 — both halves
4recovery with a transfer in flight§25, §27
5recovery with transfers queued but unsent§27's second property
6stale-epoch object after a recovery§27's fourth property
7recovery that returns a narrower link§28 — degradation invariance
8mapping table full§14's fourth property — backpressure, not overwrite
9sustained bulk load with progress traffic trickling§18, §19
10class tag delayed one cycle from payload§21, §22
11two dependent transfers on different-latency paths§30
12transport identity reused immediately after retirement§12's contract
13response naming a semantic id that has retired§14's third property
14back-to-back transfers of differing classes§22's third property — catches the off-by-one

Two notes.

Rows 1 and 2 are the same physical event in two directions, and they break different things. Injecting retry only on the outbound path tests half the boundary.

Row 14 is trivial to build and catches a flagship bug. §21's off-by-one is invisible with a single transfer or with a uniform-class stream. Two back-to-back transfers of different classes is the whole test, and a great many environments do not contain it.

37. Coverage

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
covergroup cg_chi_ucie_boundary @(posedge clk);
  option.per_instance = 1;
 
  // --- The architectural fork (Section 6).
  cp_mode : coverpoint transport_mode {
    bins raw     = {0};            // no Adapter CRC/retry to reuse
    bins adapter = {1};
  }
 
  // --- Class dimension (Sections 15-19).
  cp_class : coverpoint active_class {
    bins each[] = {[0:NUM_CLASSES-1]};
  }
  cp_class_concurrency : coverpoint num_classes_requesting {
    bins one = {1}; bins some = {[2:3]}; bins all = {[4:$]};
  }
  cp_progress_starved : coverpoint progress_wait_q {
    bins none  = {0};
    bins some  = {[1:PROGRESS_BOUND-1]};
    bins at_bound = {PROGRESS_BOUND};      // the reservation firing
  }
 
  // --- Transport interaction (Sections 23, 24).
  cp_retry_point : coverpoint retry_occurred_on {
    bins none     = {0};
    bins outbound = {1};
    bins response = {2};                   // two DIFFERENT failures
  }
  cp_duplicate_gated : coverpoint duplicate_suppressed_at_gate;
  cp_ack_resent      : coverpoint ack_resent_after_duplicate;   // Section 24
 
  // --- Recovery (Sections 25-28).
  cp_recovery_point : coverpoint recovery_during {
    bins none              = {0};
    bins transfer_inflight = {1};
    bins transfers_queued  = {2};
    bins response_inflight = {3};          // the stale-epoch case
  }
  cp_stale_epoch     : coverpoint stale_epoch_object_arrived;
  cp_width_after_rec : coverpoint width_after_recovery {
    bins same     = {0};
    bins narrower = {1};                   // Section 28
  }
 
  // --- Structural (Sections 12, 14).
  cp_map_occupancy : coverpoint map_occupancy {
    bins empty = {0};
    bins mid   = {[1:MAP_DEPTH-2]};
    bins full  = {MAP_DEPTH};              // backpressure, not overwrite
  }
  cp_transport_id_reuse : coverpoint transport_id_reused_while_semantic_live;
 
  // --- Crosses that carry the information.
  x_mode_retry     : cross cp_mode, cp_retry_point;            // Section 6
  x_recovery_width : cross cp_recovery_point, cp_width_after_rec;
  x_class_progress : cross cp_class, cp_progress_starved;
  x_retry_class    : cross cp_retry_point, cp_class;
endcovergroup

Six bins whose value is being non-zero:

cp_mode — both bins. §6's fork. Testing one mode verifies half the configurations, and the Raw Mode half is the one with no Adapter reliability underneath it.

cp_retry_point — outbound and response. Two different corruptions (§36).

cp_recovery_point.transfers_queued. Recovery with transfers accepted but not yet transmitted — §27's second property, and a state most environments never construct.

cp_stale_epoch. §35's cycle 24. It cannot occur without deliberate injection.

cp_width_after_rec.narrower. §28. A recovery that returns the same width tests nothing about degradation invariance.

And cp_transport_id_reuse. A transport identity recycled while the CHI transaction that used it is still live — the precondition for §13's bug, and a design can pass an entire regression without ever reaching it.

38. Debug Taxonomy

SignatureMost likely causeFirst instrument
UCIe clean, CHI completion wrong or missing§13 — mapping keyed on transport identityis the bridge table indexed by semantic or transport id?
A retry produces a duplicate coherence action§23 — the semantic delivery gate is missing or bypassedis the fabric driven by delivery or by arrival?
Retries never stop on one transfer§24 — the duplicate suppressed the reply as well as the effectis the acknowledgement re-sent on a recognised duplicate?
Hang only under heavy bulk load§18 — progress class starvedprogress_wait_q under load; is any class reserved?
Recovery produces an orphaned response§26 — the bridge flushed live bindingswhat cleared at the recovery cycle?
Response lost right after a successful recovery§27 — a stale-epoch object resolved the entry firstepoch of the resolving object vs current
Payload correct, behaviour wrong for its type§21 — class drifted from payloadremote class vs testbench-assigned class
Behaviour changes after a link degrades§28 — a bound or a resource assumed full capacitywhich timeouts and depths are derived from the active config?
Transfers silently disappear under load§14's fourth property — mapping table overwritten instead of backpressuredoccupancy vs MAP_DEPTH, and is there an overflow assertion?
Dependent operations observed out of order§30 — dependent traffic on different-latency pathsdo dependent transfers share an ordering domain?
Works through the Adapter, fails in Raw Mode§6 — the integration assumed reliability it does not havewhich mode; where does duplicate suppression live?

The last row deserves its own note. A bridge developed and tested only on the Adapter path inherits CRC and retry. In Raw Mode it has neither, and every mechanism that quietly assumed them loses its foundation without a single line of code changing.

39. Debug Checklist

  1. What CHI semantic operation is live? Which line, which requester?
  2. Which node is the serialisation point for that address? (CHI 4.3)
  3. What semantic identity does the operation carry?
  4. Which UCIe revision, and which transport mode — Raw or Adapter? (§6)
  5. Is duplicate suppression provided by UCIe or by the integration? (§23)
  6. Which mapping entry binds this operation, and to what transport identity?
  7. How many transfers does the operation comprise? (§8)
  8. How many physical attempts did each transfer take?
  9. How many semantic deliveries did each transfer produce? Must be ≤ 1.
  10. Did a retry occur — outbound, on the response, or both? (§36)
  11. Did a link recovery occur while the operation was live? (§25)
  12. Did every semantic row survive it? (§27)
  13. Was any pre-recovery object accepted after the recovery? (§27)
  14. Did the link return at a different width or rate? (§28)
  15. Which traffic class, and was any progress class starved? (§19)
  16. Did metadata and payload stay aligned end to end? (§22)
  17. Was any semantic ordering dependency inverted by path or QoS choice? (§30)
  18. Was the destination recomputed anywhere after acceptance? (§27)
  19. Which event retired the CHI semantic state — and was it the CHI completion point? (§33)
  20. Do all three scoreboard layers agree, and which one diverged first? (§32)

40. Common Misconceptions

"UCIe replaces CHI." It does not. Official UCIe material names CHI among the Streaming Protocols UCIe carries; it says nothing about UCIe providing coherence semantics. UCIe changes the physical boundary; CHI keeps the meaning (§3, §5).

"CHI coherence state belongs in the UCIe Adapter." It belongs in the fabric. A bridge that starts holding coherence state acquires an opinion about ordering and eventually races the real home node (§9). The Adapter must understand even less than the bridge does (11.4 §9).

"One CHI operation equals one physical packet." One operation becomes several transfers, each becoming a transport object, each of which may take several attempts. A count at one level says nothing about another (§8).

"Transport ID and CHI semantic ID are the same thing." Different namespaces, allocated and recycled by different layers on different schedules. Indexing bridge state by a transport identity inherits a recycling policy CHI never agreed to — and the transport frees its identity while the CHI transaction is usually still live (§12, §13).

"A UCIe retry should allocate CHI state again." A retry is the same transfer delivered twice. Allocating again produces a second semantic action from a mechanism that was working correctly (§13, §23).

"Raw Mode and the Adapter path have the same reliability ownership." They do not. UCIe 1.1 added Adapter reuse for Streaming Protocols; before that, CHI over UCIe was Raw Mode only. Which mode is in force decides who owns CRC, retry and duplicate suppression (§3, §6).

"UCIe recovery may clear CHI outstanding state." It may not. A recovery re-establishes a link; it does not release a transaction, un-invalidate a line, or change what a node owes. Clearing the bridge table on recovery orphans every response that then returns correctly (§25, §26).

"A clean UCIe CRC proves CHI semantic correctness." Every object can cross once with clean integrity, every replay entry can retire, and the fabric can still complete the wrong transaction. Transport correctness is a strictly weaker claim (§32).

"All CHI traffic can safely share one strict-priority queue." A strict-priority arbiter favouring bulk data starves exactly the messages that would unblock the data path, and the resulting deadlock is safety-correct, load-dependent, and arrives long after the system looked healthy (§18).

"UCIe lane changes can alter CHI ordering or outcomes." They must not. A width or rate change alters capacity and latency. A design in which it alters a coherence outcome has coupled a performance property to a correctness property (§28).

41. Understanding Check

42. Summary and What Comes Next

CHI owns coherence semantics; UCIe owns die-to-die transport. Between them sits a bridge that must translate identity and manage lifetime, and must interpret nothing.

The mode question comes first. Official material establishes that UCIe 1.0 supported streaming protocols including CHI only in Raw Mode, and that UCIe 1.1 added the ability to use the D2D Adapter over FDI and reuse its CRC and retry. Which of those a design chose decides who owns integrity, retransmission and duplicate suppression — and roughly half this chapter's mechanisms are conditional on the answer.

One operation, several transfers, more attempts. Many attempts, at most one semantic delivery is the invariant the delivery gate implements and the scoreboards check.

Two namespaces, never one. The transport recycles its identities on its own schedule, typically freeing them while the CHI transaction is still live — so a bridge keyed on transport identity hands responses to the wrong transaction while every transport statistic reads perfect.

Classes are not one stream. A boundary that flattens them destroys information the fabric depends on, and a strict-priority arbiter favouring bulk data produces a safety-correct, load-dependent deadlock that arrives long after the system looked healthy.

Metadata travels with its payload or it drifts from it — systematically, by exactly one, with clean CRC the whole way.

A recovery rebuilds a link and changes nothing semantic. The transaction, the binding, the destination and the queued transfers all survive; the epoch advances; and a pre-recovery object must be rejected rather than allowed to resolve an entry that has since been re-driven.

And a narrower link is slower, not different. Capacity is a performance property; coherence is a correctness property; the moment a width change alters a coherence outcome, the two have been coupled.

CHI shows how an existing coherent fabric can be brought to a UCIe die boundary — as a Streaming Protocol, with reliability ownership that depends on the mode. CXL presents a different relationship entirely: UCIe maps it natively. The next chapter is about what that difference does to the responsibility ledger, and about the integration mistakes that come from confusing which of the two protocols owns what — without re-teaching the CXL mechanisms Module 11 already covers in depth.

Browse the full path on the UCIe tutorials index.