Skip to content

UCIe · Module 14

Link Robustness

How a link keeps working while part of its physical path degrades — mask-and-retrain as the verified repair action, spare lanes on advanced packages against width degradation on standard ones, per-lane health monitoring with hysteresis, quiescing live traffic before a map change, atomic lane-map commit, why a transport object must never span two configurations, preserving replay state across a repair, and the performance consequences of reduced width and rate.

Chapter 14.2 rebuilt a link whose assumptions had become unsafe. Chapter 14.3 re-drove the transport work that was not safely accepted. Both assumed the physical path was still worth using.

This chapter handles the case where it is not — and where the answer is neither "keep going" nor "give up."

1. The One-Sentence Model

Robustness is graceful reduction of capability while preserving correctness. A link that has lost a lane may legitimately become slower. It may never become wrong.

The ordering in that sentence is the whole discipline. Correctness first, capability second — and the mechanisms below exist because the natural way to reduce capability quickly is to change the physical configuration while traffic is running, which is precisely what makes it wrong.

2. What This Chapter Owns

Lane mechanics already have chapters. This one is the runtime integration, and the boundary matters because the temptation is to re-derive rather than build on them.

ChapterWhat it ownsWhat it does not
Lane Concepts §13–§14lane identity, the mapping table, striping and reconstruction, degradation as defined behaviour, spare lanes and repairchanging any of it while traffic flows
Link Widths §9requested width is not active width; width as configuration; width and bufferingcommitting a width change on a live link
8.3 — Link Trainingtraining convergence, candidate-versus-active, atomic commit with nothing in flightcommit with transport state outstanding
14.2 — Error Recoverythe recovery controller, quiesce, capture, requested/active configurationwhich configuration to move to, and why
14.3 — Retry Mechanismsreplay entries and their retirementsurviving a physical reconfiguration
14.4 — this chapterdetecting degradation at runtime, deciding what to reduce, and changing physical configuration without corrupting anything in flight

Specifically new here: per-lane health monitoring with thresholds and hysteresis, and why reacting to one error is wrong; quiescing live traffic before a map change and what "drained" has to mean; the atomic lane-map commit and the one-lane-at-a-time bug that is this chapter's signature failure; the property that a transport object must not span two configurations; preserving replay state across a repair, which is where 14.3 and 14.4 meet; the partial-transfer problem; width and rate reduction as an operating-point change with consequences for every resource in Module 13; and the degradation feedback loop in which reduced capability increases utilisation and can trigger further degradation.

3. Sourcing — and This Chapter Has a Verified Spine

4. Two Mechanisms, Chosen by Package

The verified distinction, developed — because its consequences reach every other section.

Advanced package (UCIe-A)Standard package (UCIe-S)
Data lanes per cluster6416
Failure mechanismspare laneswidth degradation
What a repair doesremaps the function of a failed lane onto a spareremoves capacity
Bandwidth after repairunchanged — the spare replaces the failurereduced
Coversdata, and clock, valid, sidebanddata lanes
Spare exhaustionfurther failures fall back to broader actionnot applicable — every failure costs width

Four consequences, and the third is the one that changes system design.

Repair on an advanced package is bandwidth-neutral; degradation on a standard package is not. A design that assumes a repaired link runs at full width is right on one packaging option and wrong on the other. The performance model must be package-aware, and §17's operating-point analysis applies to one column and not the other.

Spare coverage extends beyond data. The verified text includes "clock, valid, sideband" among what spares handle. A failure of the valid lane or the forwarded clock is not a fractional bandwidth loss — it is a total loss of the cluster's ability to frame or sample. That a spare can cover them is architecturally significant: on an advanced package these are repairable failures rather than fatal ones.

The advanced package's larger cluster makes a single lane a smaller fraction. Losing one of 16 is 6.25% of the data lanes; one of 64 is 1.56%. So the standard package both loses more per failure and has no spare — its degradation steps are coarser and its failures more consequential, which is the argument for the more careful hysteresis of §9 on exactly the platform where the reaction costs most.

And the mechanism is fixed before the first error. A design does not decide at runtime whether to repair or degrade. It knows from its packaging option, so the policy ladder of §14 is parameterised by that, and the two variants have genuinely different shapes.

5. Degradation Sources

Officially described detection paths:

  • Periodic parity flit injection and checking during mission mode, with results in the per-lane error log register and an interrupt (§3). This is a continuous, per-lane, in-mission health measurement — not an error report about traffic, but a deliberate test woven into normal operation.
  • Eye margin measurement during training, captured in standard-format registers, with software able to trigger a periodic retrain to refresh it (§3).

Representative implementation triggers — plausible and not asserted as UCIe requirements:

SourceWhat it indicatesIs it lane-attributable?
Rising CRC failure ratecorruption somewhere in the pathno — a CRC is over the whole unit (14.1 §5)
Per-lane parity/test errorsa specific laneyes — this is the verified path
Persistent retry rate (14.3 §37)the channel is not deliveringno
Training failure or degraded margin on retrainthis lane cannot meet its eyeyes
Deskew drift beyond tolerancetiming relationship changingyes

The second column is the section's point. A CRC failure tells you something is wrong and cannot tell you where — the check spans the whole unit. Attributing a fault to a lane requires a per-lane detector, which is exactly what the verified parity-injection-plus-per-lane-log mechanism provides. 14.1 §47's misconception — "CRC alone identifies which lane is bad" — is the error this table exists to prevent, and it is why a robustness design cannot be built on integrity counters alone.

6. Per-Lane Health State

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ILLUSTRATIVE per-lane health record. The STRUCTURE is architecture; the
// THRESHOLDS are design choices — UCIe publishes none (Section 3).
//
// Fed by the verified per-lane detection path: periodic parity flit injection
// and checking, reported per lane.
typedef struct packed {
  logic [ERR_W-1:0] error_count;     // errors attributed to THIS lane
  logic [AGE_W-1:0] unhealthy_age;   // how long it has been above threshold
  logic [RPR_W-1:0] repair_count;    // times this lane has been repaired
  logic             suspect;         // above the warning threshold
  logic             degraded;        // above the action threshold
} lane_health_t;
 
lane_health_t lane_health_q [NUM_LANES];
 
// Per-lane update. Note error_count SATURATES — it is a diagnostic
// (14.1 Section 33), and a wrapped count reads as a healthy lane.
always_ff @(posedge clk or negedge rst_n) begin
  if (!rst_n) begin
    for (int l = 0; l < NUM_LANES; l++) lane_health_q[l] <= '0;
  end else begin
    for (int l = 0; l < NUM_LANES; l++) begin
      if (lane_error[l] && !(&lane_health_q[l].error_count))
        lane_health_q[l].error_count <= lane_health_q[l].error_count + 1'b1;
 
      // Age accumulates only while the lane is above threshold, and clears
      // when it recovers — the same episode discipline as 13.4 Section 13.
      if (lane_health_q[l].suspect) begin
        if (!(&lane_health_q[l].unhealthy_age))
          lane_health_q[l].unhealthy_age <= lane_health_q[l].unhealthy_age + 1'b1;
      end else begin
        lane_health_q[l].unhealthy_age <= '0;
      end
    end
  end
end

Architecture. One record per lane, because the action is per lane. A single aggregate error count cannot answer the only question that matters at repair time — which lane — and the verified mechanism reports per lane precisely because that is the actionable granularity.

State. error_count and repair_count are sticky for the debug epoch; unhealthy_age is per unhealthy episode; suspect and degraded are derived per cycle. Four fields, three lifetimes, and the episode-scoped one is the one that gets reset wrongly (see Failure).

Cycle behaviour. Both counters saturate. 14.1 §33's rule applies: saturate diagnostics, never saturate accounting. A wrapped per-lane error count reads as a healthy lane at exactly the moment the lane is worst — the single most misleading value a health monitor can present.

Contract. degraded drives the policy FSM (§13); error_count and repair_count are read by software, which the verified path says assesses whether repair is needed. So this structure is not purely internal — it is the hardware half of a hardware-software decision, and its fields must remain meaningful to a reader who arrives long after the events.

Failure. Clearing unhealthy_age on a momentary dip below threshold. A lane oscillating around the threshold then reports thousands of one-cycle unhealthy episodes instead of one long one, so the persistence test of §10 never fires and a genuinely degrading lane is never actioned — 13.4 §6's failure mode, in the lane domain.

DV. Inject errors on one lane and confirm only that lane's record moves. Drive a lane above threshold with a one-cycle dip mid-episode and confirm the age continues. Saturate both counters and confirm they clip rather than wrap.

7. Per-Lane Diagnostics Worth Building

Beyond the policy inputs, five values that make a post-silicon session tractable:

ValueLifetimeWhy it is worth a register
First failing lanedebug epoch, latch-oncein a multi-lane failure, which went first identifies the mechanism (14.2 §13)
Per-lane error countdebug epoch, saturatingseparates one bad lane from a common-mode problem (§25)
Per-lane repair countlife of the parta lane repaired repeatedly is a marginal lane, not a transient
Retrain countlife of the partdistinguishes "recovered once" from "recovering constantly"
Current active masklink epochthe configuration everything else must be interpreted against

The first row is the highest-value single register in the chapter. When several lanes report errors, the distribution is ambiguous — a genuinely marginal lane that destabilised its neighbours looks much like a common-mode event. The lane that failed first, latched once and never overwritten, discriminates them, and it is the same first-cause argument 14.1 §34 and 14.2 §13 both make.

And the third row is what separates a repair from a fix. A lane repaired once is a repaired lane. A lane repaired five times is a lane whose repair keeps being undone, which on an advanced package means spares are being consumed and on a standard package means width is being lost repeatedly — and neither is visible from a per-episode view.

8. Thresholds and Hysteresis

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ILLUSTRATIVE lane health thresholds. All values are DESIGN CHOICES;
// UCIe publishes no lane-degradation threshold (Section 3).
localparam int LANE_WARN_ERRORS   = 4;      // ILLUSTRATIVE — enter suspect
localparam int LANE_CLEAR_ERRORS  = 1;      // ILLUSTRATIVE — leave suspect
localparam int LANE_ACT_ERRORS    = 16;     // ILLUSTRATIVE — enter degraded
localparam int LANE_ACT_AGE       = 4096;   // ILLUSTRATIVE — persistence test
 
// Entering and leaving use DIFFERENT thresholds — 13.4 Section 10's argument,
// and the cost of getting it wrong here is a configuration change rather than
// a policy flip.
always_comb begin
  for (int l = 0; l < NUM_LANES; l++) begin
    lane_suspect[l]  = (lane_health_q[l].error_count >= ERR_W'(LANE_WARN_ERRORS));
    lane_clear[l]    = (lane_health_q[l].error_count <= ERR_W'(LANE_CLEAR_ERRORS));
 
    // Action requires BOTH magnitude AND persistence. Either alone is wrong.
    lane_degraded[l] = (lane_health_q[l].error_count  >= ERR_W'(LANE_ACT_ERRORS))
                    && (lane_health_q[l].unhealthy_age >= AGE_W'(LANE_ACT_AGE));
  end
end
 
initial begin
  assert (LANE_CLEAR_ERRORS < LANE_WARN_ERRORS)
    else $fatal(1, "lane hysteresis inverted");
  assert (LANE_WARN_ERRORS  < LANE_ACT_ERRORS)
    else $fatal(1, "warn and action thresholds overlap");
end

Architecture. Two-level classification — suspect and degraded — with hysteresis on the first and a conjunction of magnitude and persistence on the second.

Why the action condition needs both terms. Magnitude alone reacts to a burst: 14.1 §37 established that one physical disturbance corrupts many consecutive units, so an error count can jump by dozens from a single event that has already passed. Persistence alone reacts to a lane that is slightly noisy forever but perfectly usable. Requiring both means the lane must be both bad and stay bad, which is the actual definition of degraded.

State. Combinational from §6's record.

Contract. lane_degraded is the input to the policy FSM (§13), and — following the verified path — is also what feeds the per-lane error log that software reads to assess whether repair is needed (§3). The threshold is therefore a hardware-software interface decision, not a purely internal one.

Failure. §9, and separately, inverted thresholds after reparameterisation — which the elaboration assertions catch at build time rather than in the field.

DV. Sweep an injected error rate across the thresholds in both directions and confirm the suspect flag shows hysteresis. Drive a burst — many errors in a few cycles, then nothing — and confirm the lane does not become degraded, because persistence was never satisfied. That negative test is the one that proves the conjunction is doing its job.

9. Wrong Design — Acting on a Single Error

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// WRONG — one error disables a lane.
always_ff @(posedge clk)
  if (lane_error[l]) active_lane_mask_q[l] <= 1'b0;

Three things wrong, in increasing order of consequence.

It reacts to an event the link is designed to absorb. UCIe 3.0's target BER is 10⁻¹² at 64 GT/s (§3), which is one bit error per lane roughly every 15.6 seconds (13.5 §29). Those errors are expected, and CRC and replay exist to handle them. Disabling a lane on the first one means every lane is disabled within a couple of minutes of normal operation.

On a standard package it collapses bandwidth in steps that cannot be recovered. With 16 data lanes, four such events cost 25% of the link — and width degradation does not come back on its own. The link is permanently narrower because of four expected events.

And it modifies the active mask directly, with traffic running. This is §16's corruption, and it is by far the worst of the three: the lane is removed from the transmitter's striping while the receiver still expects it, so every subsequent beat is misassembled. The design has converted a recoverable single-bit error into deterministic, sustained corruption.

A single error is evidence of nothing except that the detector works. Degradation is a rate and a duration, and the response is a reconfiguration — the most expensive action the link has.

10. Persistence — Transient Against Degrading

ObservationInterpretationCorrect response
A few errors, then clean for a long timea transient — a disturbance that has passednone. CRC and replay already handled it
A burst, then cleanone physical event, many symptoms (14.1 §37)none, and do not count it as many faults
Errors continuing at a low rate on one lanea marginal lanemonitor; consider a retrain to refresh margin
Errors continuing at a rising rate on one lanea degrading lanemask and retrain (§12)
Errors on all lanes simultaneouslycommon-mode — clock, supply, rate, or temperaturenot a lane problem. Masking will not help (§25)

The last row is why per-lane data must be examined as a distribution, not as a maximum. A design that acts on "the worst lane" will mask a lane during a supply droop that affected everything, losing capacity for a fault that was never local — and then find the errors continue, because the cause was never addressed.

And the fourth row is the only one that justifies the expense. Everything above it is handled by mechanisms that already exist. Reconfiguration is reserved for the case where the physical path has genuinely and persistently changed.

11. Active Lane Map Is Not Requested Lane Map

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ILLUSTRATIVE two-copy lane map. Same discipline as Chapter 14.2 Section 24
// for configuration and Link Widths Section 9 for width — here applied to the
// per-lane mapping on a link with transport state in flight.
logic [NUM_LANES-1:0] active_lane_mask_q;      // what the datapath USES
logic [NUM_LANES-1:0] requested_lane_mask_q;   // what we intend to use next
 
// Staging is free — no datapath consumer reads the requested copy.
always_ff @(posedge clk)
  if (lane_stage_en) requested_lane_mask_q <= proposed_lane_mask;
 
// Committing is not. One event, one edge, every consumer together.
always_ff @(posedge clk or negedge rst_n)
  if (!rst_n)           active_lane_mask_q <= LANE_MASK_RESET;
  else if (map_commit)  active_lane_mask_q <= requested_lane_mask_q;

Architecture. Two registers, asymmetric exposure. The requested copy can be written, rewritten and abandoned during retraining with no observable effect on traffic; the active copy is read by the striping logic, the reconstruction logic, the framing logic and the valid/track handling, and changing it changes all of them on the next cycle.

State. requested_lane_mask_q has repair-episode lifetime and may be discarded if validation fails. active_lane_mask_q has link-epoch lifetime and is what 14.2 §23's epoch counts.

Cycle behaviour. Note active_lane_mask_q is not reset by a failed repair — the previous working map is a better fallback than a default, exactly as 14.2 §24 argued for configuration generally.

Contract. No datapath block may read the requested copy. Not enforceable by the type system; enforceable by module boundaries, and worth enforcing that way because §16 is the consequence.

Failure. §16, and its severity is the reason for two registers rather than one written carefully.

DV. Drive the requested mask with a different value throughout a live transfer and assert that no transported byte changes. That single test proves no consumer is reading the staged copy, which no amount of code review reliably establishes.

12. Mask and Retrain — the Verified Repair

The officially described action, in order, with what each step actually requires.

UCIe 1.1: "the existing UCIe 1.0 mechanism (e.g., mask faulty lane and retrain) can be used for repair."

StepWhat it doesWhat it requires first
1. Assesssoftware reads the per-lane error log and decides repair is neededthe per-lane data must exist and be meaningful (§6, §7)
2. Quiescestop admission, drain in-flight transport§15 — and "drained" must mean no partial unit exists (§21)
3. Maskstage a lane map excluding the faulty laneinto requested_lane_mask_q, not the active copy (§11)
4. Retrainre-establish timing, deskew and identity for the new map8.3 owns this
5. Validateconfirm the new map works end to endbefore commit, never after
6. Commitatomically switch every consumer to the new map§17
7. Resumerelease traffic14.2 §28's four-term gate

Two observations about the verified two-word description.

"Mask and retrain" — the second word carries the weight. Masking a lane changes the striping, the lane-to-signal assignment, and the deskew relationships. A masked link is not the old link minus one lane; it is a different physical configuration, and it needs training to establish that configuration exactly as an initial bring-up does. A design that masks without retraining has changed the mapping and kept the old timing.

And where the spare comes in on an advanced package. With spares available (§4), the "mask" step remaps the failed lane's function onto a spare rather than removing it — so steps 3 through 6 are structurally identical and step 6 commits a map with the same width. The mechanism is the same; the capability outcome is not.

13. The Robustness Controller

An illustrative eight-state lane-robustness controller. HEALTHY is the start state. Rising per-lane errors move it to SUSPECT. From SUSPECT, errors clearing return to HEALTHY with no action taken, while persistent errors above the action threshold move to QUIESCE. QUIESCE stops admission and drains in-flight transport, then moves to RETRAIN, which attempts to restore margin at the current lane map. If retraining succeeds, it moves to VALIDATE; if the lane is still failing, it moves to REPAIR, which stages a new lane map masking the faulty lane or assigning a spare, then moves to VALIDATE. VALIDATE proves the staged configuration and commits it, returning to HEALTHY at full capability or to REDUCED if width or rate was lowered. REDUCED is a normal operating state that is itself monitored and returns to SUSPECT if errors rise again. REPAIR moves to FAIL when no viable configuration remains.HEALTHYSUSPECTQUIESCERETRAINREPAIRVALIDATEREDUCEDFAILerrors riseerrors riseclearsclearspersistspersistsdraineddrainedmargin okmargin okstill failingstill failingmap stagedmap stagedno config leftno configleftfull widthfull widthreducedreducederrors riseerrors rise
Figure 1 — an illustrative lane-degradation controller. A suspect lane that clears returns to healthy with no action; one that persists drives a quiesce, a retrain, and — if retraining does not restore it — a repair that masks the lane or assigns a spare. The new configuration is validated before it is committed, and the link resumes either at full capability or in a reduced mode that is itself monitored.

Three structural readings.

SUSPECT can return to HEALTHY with no action. That path is the most-travelled one in a healthy link and it is the point of §8's hysteresis: most suspicion resolves itself, and a controller without that path reconfigures on every transient.

RETRAIN is attempted before REPAIR. A lane whose margin has drifted may be restored by retraining at the same map — UCIe 3.0's LTSM enhancements "perform I/O corrections as well as EQ preset selections to establish the desired eye margins" (§3). Only a lane that fails after a retrain has demonstrably degraded, and masking before retraining spends capacity on a lane that might have been recoverable.

REDUCED is a normal operating state, not a fault state. It is monitored exactly as HEALTHY is and can degrade further. A controller that treats reduced operation as terminal cannot respond to a second failure, which on a link that has already lost one lane is not a remote possibility.

14. The Escalation Ladder, Parameterised by Package

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ILLUSTRATIVE escalation. The LADDER differs by packaging option because
// the MECHANISM does (Section 3, verified): advanced packages have spare
// lanes; standard packages degrade width.
typedef enum logic [2:0] {
  RB_RETRAIN_SAME = 3'd0,   // refresh margin at the current map
  RB_REPAIR_SPARE = 3'd1,   // ADVANCED PACKAGE ONLY: assign a spare
  RB_REDUCE_WIDTH = 3'd2,   // STANDARD PACKAGE: degrade width
  RB_REDUCE_RATE  = 3'd3,   // lower the data rate to regain margin
  RB_FAIL         = 3'd4    // no viable configuration remains
} rb_action_e;
 
function automatic rb_action_e next_action(rb_action_e cur, logic advanced_pkg,
                                           logic spares_available);
  unique case (cur)
    RB_RETRAIN_SAME: return (advanced_pkg && spares_available) ? RB_REPAIR_SPARE
                                                              : RB_REDUCE_WIDTH;
    RB_REPAIR_SPARE: return spares_available ? RB_REPAIR_SPARE   // another spare
                                             : RB_REDUCE_WIDTH;  // spares exhausted
    RB_REDUCE_WIDTH: return RB_REDUCE_RATE;
    RB_REDUCE_RATE : return RB_FAIL;
    default        : return RB_FAIL;
  endcase
endfunction

Architecture. A ladder whose shape is set at elaboration by the packaging option, following the verified mechanism split (§4). One ladder with a branch, rather than two ladders, because the tail — reduce width, reduce rate, fail — is common once spares are gone.

State. The current rung has degradation-episode lifetime; spares_available is life of the part, because a consumed spare does not come back.

Cycle behaviour. Pure function, evaluated when an attempt fails. Note RB_REPAIR_SPARE can repeat — a second lane failure on an advanced package with spares remaining is another spare assignment, not an escalation to width reduction.

Contract. The action selects what REPAIR stages into requested_lane_mask_q and what width or rate VALIDATE proves. Every rung ends in the same commit path (§17), which is what keeps the atomicity argument uniform across four quite different actions.

Failure. Escalating past RB_REPAIR_SPARE while spares remain — spending width on a link that had a spare available. And the reverse: attempting a spare assignment on a standard package, where the mechanism does not exist.

Not asserted as normative. The verified material describes the mechanisms and the software-assessed decision; it does not define an autonomous escalation policy (§3). This ladder is a policy an implementation may adopt.

DV. Elaborate both packaging options and confirm the ladder shape differs. Exhaust spares on the advanced variant and confirm the fallback to width reduction.

15. Quiescing Live Traffic

Before anything physical changes, traffic must stop — and "stop" has a stricter meaning here than in 14.2 §10.

RequirementWhy it is stricter here
Stop new admissionsame as 14.2
No partial transport unit may exista unit half-transmitted under the old map cannot finish under the new one (§21)
Preserve replay entriessame as 14.2 — and §19 is why it matters more here
Preserve transaction statesame as 14.2

The second row is the addition, and it is what makes no_transfer_in_flight a term in the commit condition (§17). A recovery that does not change the lane map can tolerate a unit that was mid-flight and is simply retransmitted. A lane-map change cannot, because the two halves would be striped differently.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ILLUSTRATIVE quiesce-complete condition for a configuration change.
// Note the third term — it is what Section 21 exists for.
assign quiesce_complete = !new_admission_pending      // nothing new accepted
                       && tx_unit_boundary           // no PARTIAL unit on the wire
                       && rx_unit_boundary           // nor inbound
                       && !retrain_in_progress;

Architecture. A four-term condition, and tx_unit_boundary is the one that distinguishes this from a generic drain. It is not "the queue is empty" — it is "no unit is partially transmitted", which is a framing question rather than an occupancy one.

Contract. The transmit path must expose a genuine unit-boundary indication. A design whose framing logic cannot say "I am between units" cannot safely change its lane map at all, and discovering that late is expensive.

Failure. Using queue-empty as the drain condition. A unit can be mid-transmission with the queue already empty — the last unit is exactly the one most likely to be in flight when a drain completes.

DV. Trigger a repair at every beat offset within a unit, including the last beat, and confirm the quiesce waits for the boundary in each case.

16. Wrong RTL — Updating the Mask One Lane at a Time

This chapter's signature failure.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// WRONG — lanes are disabled individually as they are found faulty, while
// traffic is running.
always_ff @(posedge clk)
  for (int l = 0; l < NUM_LANES; l++)
    if (lane_degraded[l]) active_lane_mask_q[l] <= 1'b0;

Two separate corruptions, and the second is the subtler one.

Transmitter against receiver. The transmitter's striping now uses 15 lanes; the receiver's reconstruction still uses 16. Every subsequent beat is assembled from the wrong lanes. Lane Concepts §10 established that striping and reconstruction are inverse operations parameterised by the map — change one side's parameter and they stop being inverses.

Consumer against consumer, on the same die. If the striping logic, the framing logic and the valid/track handling each read active_lane_mask_q through different pipeline depths — or one takes a registered copy "for timing" — they disagree for one or more cycles even on the transmitting side. A unit is then framed for 16 lanes, striped across 15, and marked valid for 16. That corruption is entirely local and would occur even in a loopback test.

What the symptom looks like, and why it misleads. The receiver computes a CRC over misassembled bytes and it fails. The reported error is a CRC failure, which reads as a physical problem — so the investigation goes to eye margin and temperature, on a link whose physical layer is fine. 14.1 §45 names this signature: errors beginning exactly at a configuration change are a commit problem, not a channel problem.

And it is self-amplifying. The corruption produces CRC failures on every lane's data, which the per-lane attribution logic may credit to further lanes, which disables more lanes, which corrupts further. A single-lane fault becomes a total link failure in a few microseconds, and the error log at the end shows every lane failing — which reads convincingly as a common-mode event (§25).

17. Atomic Map Commit

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ILLUSTRATIVE atomic lane-map commit. ONE event; every consumer on the same
// edge; and never while a unit is in flight.
assign map_commit = (rb_state_q == RB_VALIDATE)
                 && map_validated          // the new map was proven
                 && peer_map_agreed        // both sides will switch
                 && no_unit_in_flight      // Section 15 / Section 21
                 && !map_commit_done_q;    // exactly once per episode
 
// EVERY consumer reads the SAME register directly. No local copies.
wire [NUM_LANES-1:0] stripe_mask = active_lane_mask_q;
wire [NUM_LANES-1:0] recon_mask  = active_lane_mask_q;
wire [NUM_LANES-1:0] frame_mask  = active_lane_mask_q;
wire [WIDTH_W-1:0]   active_w    = count_ones(active_lane_mask_q);

Architecture. Structural atomicity — one register, read directly by every consumer. The three wire declarations are deliberately trivial: they exist to make the point that each consumer's view is the same register, not a copy of it.

State. map_commit_done_q is per degradation episode and prevents a double commit, which would advance 14.2 §23's epoch twice for one change.

Cycle behaviour. One clock edge. active_w is derived combinationally from the mask rather than being a separate register — a separately-registered width is a second source of truth that can disagree with the mask for a cycle, which is §16's local corruption in a different guise.

Contract, term by term. map_validated — the new map was proven, and 8.3 §12's validation-before-commit discipline applies. peer_map_agreed — a unilateral change is §16 regardless of validation. no_unit_in_flight — §21. !map_commit_done_q — exactly once.

Failure. Any consumer holding a registered copy. This is worth a specific review question rather than a general one: "does any block latch the lane mask?" — because the answer is often yes, added for timing closure, with no awareness that it breaks atomicity.

DV. Sample every mask-derived signal on the commit cycle and confirm they all change together. A registered copy shows as a one-cycle skew immediately, and no functional test will reveal it.

18. SVA — the Map Is Stable During Live Transport

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// MANDATORY. The property that makes Section 16 impossible.
property p_map_stable_without_commit;
  @(posedge clk) disable iff (!rst_n)
    !map_commit |=> $stable(active_lane_mask_q);
endproperty
a_map_stable_without_commit: assert property (p_map_stable_without_commit);
 
// Stronger: the map may not change while a transport unit is in progress,
// even on a legal commit.
property p_no_map_change_mid_unit;
  @(posedge clk) disable iff (!rst_n)
    unit_in_progress |-> $stable(active_lane_mask_q);
endproperty
a_no_map_change_mid_unit: assert property (p_no_map_change_mid_unit);
 
// The commit is legal only after validation and agreement.
property p_map_commit_qualified;
  @(posedge clk) disable iff (!rst_n)
    map_commit |-> (map_validated && peer_map_agreed && no_unit_in_flight);
endproperty
a_map_commit_qualified: assert property (p_map_commit_qualified);
 
// And the derived width always matches the mask — no second source of truth.
property p_width_matches_mask;
  @(posedge clk) disable iff (!rst_n)
    (active_w == WIDTH_W'($countones(active_lane_mask_q)));
endproperty
a_width_matches_mask: assert property (p_width_matches_mask);

Architecture. Four properties: the map changes only on a commit, never mid-unit, only when qualified, and the derived width never diverges from it.

Why the fourth is worth having despite looking tautological. It is tautological only if active_w is combinational from the mask. The moment someone registers it for timing, the property fires — which is precisely the change that silently breaks §17's atomicity, and the property converts a subtle timing-driven refactor into an immediate assertion failure.

Why $countones rather than a reference model. It computes the answer from the design's own state with no second copy to maintain, which is the same reasoning 13.2 §19 used for occupancy against $countones of the valid bits.

DV. These need a repair that actually changes the map. A regression whose repairs recommit identical masks satisfies all four while exercising none of them — cover the changed-map case explicitly (§27).

19. Replay State Must Survive a Repair

Where 14.3 and this chapter meet, and where the most damaging shortcut lives.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// WRONG — the replay buffer is cleared because the physical configuration
// changed.
if (map_commit) begin
  replay_valid_q <= '0;                 // every unretired object: gone
  rp_count_q     <= '0;
end

Why this is written. The reasoning is superficially sound: the objects in the replay buffer were transmitted under the old lane map, so they are stale. The premise is right and the conclusion is exactly backwards.

They were transmitted under the old map — which is why they may not have arrived. These are the objects whose delivery is unconfirmed, and the lane degradation is a very good reason to think some of them failed. They are the work most in need of retransmission, and clearing them guarantees its loss.

And retransmission under the new map is not only safe but the point. 14.3 §6 established that a replay entry retains the transport object, not a lane-specific encoding. Re-striping the same object across a different lane map produces a correct transmission — the map is a parameter of the transmission, not part of the object.

The consequence chain, when it is cleared:

  1. Unretired objects are destroyed.
  2. The remote side never receives them and never acknowledges them.
  3. The transactions that generated them wait forever.
  4. 12.4's timeout fires, at the Protocol Layer.
  5. The reported fault is a transaction timeout on a link that just successfully repaired itself — and the repair is reported as a success.

The correct behaviour, stated positively:

A lane repair changes how bytes are placed on wires. It does not change which objects are owed. Replay entries, their identities and their attempt counts must all survive the commit unchanged, and be re-driven under the new configuration before general traffic resumes.

One thing that must be re-examined, though, and it is a genuine subtlety: an object that was partially transmitted when degradation was recognised is in a different situation from one that was never sent or fully sent. §21 is that case.

20. SVA — Replay State Survives the Commit

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// The retention claim across a physical reconfiguration.
property p_replay_survives_map_commit;
  @(posedge clk) disable iff (!rst_n)
    map_commit |=> (rp_count_q == $past(rp_count_q));
endproperty
a_replay_survives_map_commit: assert property (p_replay_survives_map_commit);
 
// Per entry, including its identity and attempt count — a repair must not
// silently renumber anything.
generate for (genvar i = 0; i < REPLAY_DEPTH; i++) begin : g_replay_survive
  a_entry_survives: assert property (@(posedge clk) disable iff (!rst_n)
    (map_commit && $past(replay_mem[i].valid))
      |=> (replay_mem[i].valid
           && (replay_mem[i].seq == $past(replay_mem[i].seq))
           && (replay_mem[i].attempt_count == $past(replay_mem[i].attempt_count))));
end endgenerate
 
// And transaction state survives too — 14.2 Section 12's claim, at the
// configuration boundary specifically.
property p_outstanding_survives_map_commit;
  @(posedge clk) disable iff (!rst_n)
    map_commit |=> (outstanding_q == $past(outstanding_q));
endproperty
a_outstanding_survives_map_commit: assert property (p_outstanding_survives_map_commit);

Architecture. Three properties: occupancy survives, every entry survives with its identity and attempt count intact, and transaction state survives.

Why the identity clause matters as much as the validity clause. An entry that survives with a renumbered sequence is worse than one that was cleared: it will be retransmitted under a new identity, which the receiver cannot recognise as a repeat, so a lost acknowledgement now produces a double semantic delivery (14.3 §20). Surviving is not enough; surviving unchanged is the requirement.

Why attempt_count is included. Preserving it keeps 14.3 §36's escalation meaningful across a repair. Resetting it means an object that had already failed seven times starts again at zero, so a permanently undeliverable object can retry indefinitely, alternating with repairs, and neither mechanism ever escalates.

DV. Trigger a repair with the replay buffer non-empty at several occupancy levels, including full. A repair on an empty buffer satisfies all three properties vacuously, and an idle-link repair is the easy case that random stimulus produces most often.

21. The Partially Transmitted Unit

The case that no_unit_in_flight exists to prevent, and it is worth understanding rather than merely gating.

A transport unit spans several beats. Suppose degradation is recognised after beat 2 of 4.

OptionWhat it meansProblem
Complete it under the old mapfinish beats 3–4 on the degraded lane setthe lane is failing — these beats are the ones most likely to be corrupt
Continue it under the new mapbeats 1–2 striped one way, 3–4 anotherthe receiver cannot reconstruct it. Its reconstruction is parameterised by one map
Abandon and re-framediscard the partial unit; retransmit wholerequires the receiver to discard the partial unit too, and agree on where the boundary is

The middle option is the one that must never happen, and it is what an un-gated commit produces. The receiver reassembles a unit using a single map — that is what reconstruction is (Lane Concepts §10) — so a unit whose beats were striped under two different maps cannot be reassembled correctly by any receiver, however careful. The bytes are permanently scrambled.

And this is why the quiesce condition of §15 is a framing condition rather than an occupancy one. "The queue is empty" does not imply "no unit is partially on the wire" — in fact the last unit is the most likely to be mid-transmission exactly when the queue drains.

22. Configuration Version, and the Property It Enables

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ILLUSTRATIVE local configuration version. LOCAL CONTROL AND VERIFICATION
// STATE — no on-wire version field is claimed (Section 3).
logic [CFG_VER_W-1:0] active_cfg_version_q;
 
always_ff @(posedge clk or negedge rst_n)
  if (!rst_n)          active_cfg_version_q <= '0;
  else if (map_commit) active_cfg_version_q <= active_cfg_version_q + CFG_VER_W'(1);
 
// Each transport unit records the version it BEGAN under, so the property
// below can compare it against the version at completion.
logic [CFG_VER_W-1:0] unit_start_version_q;
 
always_ff @(posedge clk)
  if (unit_start) unit_start_version_q <= active_cfg_version_q;

Architecture. A counter incremented at the commit, plus a per-unit capture of the version in force when the unit began. Neither is on the wire and neither affects the datapath — they exist so that the property below is expressible.

State. active_cfg_version_q has link-epoch lifetime; unit_start_version_q has per-unit lifetime.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// EXCELLENT property: a transport object must not span two configurations.
property p_unit_within_one_config;
  @(posedge clk) disable iff (!rst_n)
    unit_complete |-> (active_cfg_version_q == unit_start_version_q);
endproperty
a_unit_within_one_config: assert property (p_unit_within_one_config);

Contract. This is §21's constraint made checkable, and it is stronger than gating the commit on no_unit_in_flightthe gate is a design intention; the property is a proof. A gate that is subtly wrong about what "in flight" means still permits the violation; the property catches it regardless of how the gate was computed.

Failure it catches. Any commit that lands mid-unit, from any cause — a mis-derived boundary signal, a race between the boundary detector and the commit, or a deliberate "we drained, it's fine" shortcut.

DV. Deliberately force a commit mid-unit in a directed test and confirm the property fires. A property that has never been demonstrated to fire on the condition it targets has not been validated as a property, and this one is easy to get wrong in a way that makes it vacuous — for example if unit_complete is itself suppressed during a reconfiguration.

23. Width Reduction — an Operating-Point Change

Reduced width changes throughput. It must not change semantics.

ChangesDoes not change
beats per transport unitthe object's meaning or identity
raw bandwidthtransaction ordering rules
striping patternthe reliability contract
the rate × latency products of Module 13which objects are owed

Three consequences that reach Module 13, and none of them resizes a buffer.

Every rate × latency product changes because rate changed. 13.5 §14's table — credits, outstanding slots, replay entries, pipeline registers — is all rate × latency. At half width the required amount of each is roughly halved, so a design provisioned for full width now has surplus.

But the latency terms may change in the opposite direction, and this is the subtle part. A transport unit now takes more beats, so its transmission time rises. Acknowledgement round trip measured in cycles can therefore increase even as the required window in objects decreases, and the two effects partly cancel. Which dominates is a measurement, not a derivation.

And the buffers do not physically resize. A 32-entry replay buffer is 32 entries at any width. What changes is whether 32 is generous or marginal, and the honest way to find out is 13.5 §16's low-water mark instrument, re-read after the reduction rather than assumed.

Reduced width is a new operating point, not a degraded mode with the same characteristics. Every sizing conclusion drawn at full width should be re-checked, and the instrument for that already exists.

24. Rate Reduction — the Margin Trade

Lowering the data rate is the other capability reduction, and it trades differently from width.

Width reductionRate reduction
Bandwidthfalls proportionallyfalls proportionally
Signal marginunchanged — the surviving lanes run as beforeimproves — this is the point
Latency per unitrises (more beats)rises (each beat is slower)
Fixesa specific failing lanea common-mode margin problem
Cycle-count relationshipschange with beats per unitchange with the cycle time itself

The fourth row is the diagnostic one. Width reduction is the right response to a lane-attributable fault; rate reduction is the right response to a margin problem affecting everything, which is §25's common-mode case. Applying the wrong one wastes capability and does not fix the fault.

And the verified numbers make the margin trade concrete. UCIe 3.0 targets a BER of 10⁻¹⁵ at 48 GT/s and 10⁻¹² at 64 GT/s (§3) — three orders of magnitude better error rate at the lower rate. So a link failing at 64 GT/s and stepping down to 48 GT/s is not making a marginal improvement; it is moving to an operating point specified for a thousand-fold lower error rate. That is why rate reduction sits below width reduction on the ladder despite costing bandwidth: it addresses a far wider class of causes.

The cross-layer effect worth naming. Latencies measured in cycles change when the cycle time changes. A credit round trip that was 40 cycles at 64 GT/s is a different number of cycles at 48 GT/s depending on where the clocking boundaries sit, so the pools sized in 13.5 §17's conjunction must be re-evaluated after a rate change — and a design that was exactly sized at the higher rate may be under- or over-provisioned at the lower one.

25. Fault Localisation

ObservationInterpretationCorrect action
One lane's errors rise, others flatlane-local physical issuemask and retrain that lane (§12)
All lanes degrade togethercommon-mode — clock, supply, rate, temperaturenot a lane problem. Rate reduction or a broader recovery
Errors begin exactly at a map commitconfiguration mismatch — §16, or a consumer with a registered copycheck the commit, not the channel
Errors only after a retraintraining converged to a bad point, or the map committed differs from the map trainedcompare the trained map against the committed one
One lane fails repeatedly after each repairthe repair is not addressing the cause — check repair_count (§7)escalate; the lane may not be the fault
Errors correlate with temperature or activitygenuine physical marginrate reduction; margin measurement

Two rows deserve development.

The all-lanes row is the one masking makes worse. A supply droop or a thermal excursion raises the error rate on every lane. A controller acting on "the worst lane" masks one, loses capacity, and the errors continue — because the cause was never local. The distribution across lanes is the discriminator, which is why §6 keeps a per-lane record rather than a maximum.

And the repeated-repair row identifies a genuine trap. A lane repaired repeatedly may not be the faulty element at all: a marginal neighbour can be the aggressor, or the fault may be in the shared clock or valid path — which the verified text notes spares can cover on an advanced package (§4). repair_count per lane, sticky for the life of the part, is what makes this visible, and it is invisible from any per-episode view.

26. The Robustness Scoreboard

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Verification-only reference model. Not synthesisable.
class robustness_scoreboard;
 
  typedef struct {
    int  semantic_deliveries;   // must remain <= 1 across ALL repairs
    int  cfg_version_at_start;
    int  cfg_version_at_end;
    bit  retired;
  } obj_t;
 
  obj_t objects[int];
  bit [NUM_LANES-1:0] model_active_mask;
  int  model_cfg_version;
  int  commits, repairs, lane_events;
  int  loss_count, span_count, dup_count;
 
  // ---- Check 1: no semantic loss across a repair. The core claim.
  function void check_no_loss_across_repair();
    foreach (objects[id])
      if (!objects[id].retired && !dut_has_replay_or_txn_state(id)) begin
        loss_count++;
        $error("LOSS ACROSS REPAIR: object %0d unretired with no DUT state", id);
      end
  endfunction
 
  // ---- Check 2: no object spans two configurations. Section 22's property,
  //      independently modelled so a shared bug cannot hide it.
  function void on_unit_complete(int id);
    objects[id].cfg_version_at_end = model_cfg_version;
    if (objects[id].cfg_version_at_end != objects[id].cfg_version_at_start) begin
      span_count++;
      $error("CONFIG SPAN: object %0d began at version %0d, completed at %0d",
             id, objects[id].cfg_version_at_start, objects[id].cfg_version_at_end);
    end
  endfunction
 
  // ---- Check 3: exactly-once survives repairs. A repair must not cause a
  //      re-delivery, and must not prevent the delivery that is owed.
  function void on_semantic_deliver(int id);
    objects[id].semantic_deliveries++;
    if (objects[id].semantic_deliveries > 1) begin
      dup_count++;
      $error("DUPLICATE ACROSS REPAIR: object %0d delivered %0d times",
             id, objects[id].semantic_deliveries);
    end
  endfunction
 
  // ---- Check 4: the mask changes only at commits, one version per commit.
  function void on_map_commit(bit [NUM_LANES-1:0] new_mask);
    model_active_mask = new_mask;
    model_cfg_version++;
    commits++;
    if (model_cfg_version != dut_cfg_version())
      $error("VERSION DIVERGENCE: model %0d, dut %0d",
             model_cfg_version, dut_cfg_version());
    if (dut_active_mask() != model_active_mask)
      $error("MASK DIVERGENCE after commit");
  endfunction
 
  // ---- Check 5: lane-health events are attributed to the right lane.
  function void on_lane_error(int lane);
    lane_events++;
    if (!dut_lane_error_logged(lane))
      $error("ATTRIBUTION MISS: error injected on lane %0d not logged there", lane);
  endfunction
 
endclass

Architecture. Five checks in three groups: semantic safety across a physical change (1 and 3), configuration integrity (2 and 4), and attribution correctness (5).

Check 2 is modelled independently of the DUT's version counter, deliberately. Reading the DUT's counter would agree with the DUT about a mid-unit commit; an independent model is the only thing that catches a version counter that is itself mis-incremented. Same reasoning as 14.2 §31's epoch check.

Check 3 is the connection to 14.3, and it is easy to omit. A repair that causes an already-delivered object to be re-driven under a new identity produces a second semantic delivery — 14.3 §20's exactly-once broken by a physical-layer event. The scoreboard must span the repair to see it, which means it cannot be reset when the configuration changes.

Check 5 is the one most designs never write. Injecting an error on lane 7 and confirming it is logged against lane 7 verifies the attribution path end to end — and attribution is the entire basis for the repair decision. A design that logs errors against the wrong lane will mask the wrong lane, and every downstream mechanism will work perfectly on the wrong target.

27. Coverage

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
covergroup cg_robustness @(posedge clk);
  option.per_instance = 1;
 
  // --- Controller states and ARCS.
  cp_state : coverpoint rb_state_q;
  cp_arc   : coverpoint {rb_prev_q, rb_state_q} {
    bins h_s   = {{RB_HEALTHY,  RB_SUSPECT}};
    bins s_h   = {{RB_SUSPECT,  RB_HEALTHY}};    // cleared with NO action
    bins s_q   = {{RB_SUSPECT,  RB_QUIESCE}};
    bins q_r   = {{RB_QUIESCE,  RB_RETRAIN}};
    bins r_v   = {{RB_RETRAIN,  RB_VALIDATE}};   // retrain alone restored it
    bins r_rep = {{RB_RETRAIN,  RB_REPAIR}};
    bins rep_v = {{RB_REPAIR,   RB_VALIDATE}};
    bins v_h   = {{RB_VALIDATE, RB_HEALTHY}};    // full width restored
    bins v_red = {{RB_VALIDATE, RB_REDUCED}};
    bins red_s = {{RB_REDUCED,  RB_SUSPECT}};    // SECOND degradation
    bins rep_f = {{RB_REPAIR,   RB_FAIL}};
  }
 
  // --- Which lane, and how many. Every lane must be exercised — including
  //     lane 0 and the top lane, where off-by-one masking bugs live.
  cp_failing_lane : coverpoint first_failing_lane {
    bins lane0    = {0};
    bins middle[] = {[1:NUM_LANES-2]};
    bins top      = {NUM_LANES-1};
  }
  cp_failed_count : coverpoint num_masked_lanes {
    bins none = {0}; bins one = {1}; bins two = {2}; bins many = {[3:$]};
  }
 
  // --- Error shape (Section 10). The burst bin must NOT cause action.
  cp_error_shape : coverpoint lane_error_shape {
    bins single    = {SHAPE_SINGLE};
    bins burst     = {SHAPE_BURST};        // must NOT trigger degradation
    bins persistent= {SHAPE_PERSISTENT};   // MUST trigger degradation
    bins common    = {SHAPE_ALL_LANES};    // Section 25 — not a lane problem
  }
 
  // --- WHAT WAS IN FLIGHT at the repair. A repair on an idle link proves
  //     very little (Sections 19, 20).
  cp_inflight : coverpoint inflight_at_repair {
    bins idle          = {IF_NONE};
    bins replay_only   = {IF_REPLAY};
    bins txn_only      = {IF_TXN};
    bins both          = {IF_BOTH};
    bins partial_unit  = {IF_PARTIAL};     // Section 21 — the hard case
  }
 
  // --- Did the map actually change? Section 18's assertions need this.
  cp_map_changed : coverpoint map_changed_at_commit;
  cp_action      : coverpoint rb_action_q;   // retrain / spare / width / rate
 
  // --- Package variant — the ladder differs (Section 4).
  cp_package : coverpoint advanced_package;
  cp_spares  : coverpoint spares_remaining {
    bins some = {[1:$]}; bins exhausted = {0};
  }
 
  // --- Crosses that carry the information.
  x_inflight_action : cross cp_inflight, cp_action;     // repair with work live
  x_shape_action    : cross cp_error_shape, cp_action;  // burst must map to none
  x_pkg_action      : cross cp_package, cp_action;      // spare only on advanced
  x_lane_count      : cross cp_failing_lane, cp_failed_count;
endcovergroup

Six bins whose value is being non-zero:

cp_inflight — everything except idle, and especially partial_unit. §19's and §20's survival properties, and §21's constraint, are all vacuous on an idle-link repair. partial_unit is the hard case and needs the repair triggered at a specific beat offset.

cp_arc.red_s. A second degradation while already reduced — the arc that proves REDUCED is a monitored operating state rather than a terminal one.

cp_arc.r_v. Retraining alone restoring the lane, without a repair. This is the outcome that saves capability, and a controller that always escalates to masking never reaches it.

cp_map_changed. Without it, §18's four assertions have only seen commits that changed nothing.

x_pkg_action with the spare action on the advanced package and width reduction on the standard one. The verified mechanism split (§4), which a single-variant regression never exercises.

And one whose value should be zero: x_shape_action with burst crossed with any action other than none. A burst must not trigger degradation (§8, §10), and a non-zero count there means the persistence conjunction is not working.

28. Flagship Trace — Lane 3 Degrades

Illustrative. 16 data lanes, mask 0xFFFF. Objects P and Q are replay-owned; transaction T has a response outstanding. Lane 3's error rate rises from cycle 2.

CycLane 3 healthFSMActive maskReplayTxn TWidth/rateTraffic
0cleanHEALTHY0xFFFFP, Qpending16 @ 64flowing
1cleanHEALTHY0xFFFFP, Qpending16 @ 64flowing
2err=1HEALTHY0xFFFFP, Qpending16 @ 64flowing — one error is nothing (§9)
3err=3HEALTHY0xFFFFP, Qpending16 @ 64flowing
4err=5SUSPECT0xFFFFP, Qpending16 @ 64flowing — suspect takes no action
5err=9SUSPECT0xFFFFP, Q, Rpending16 @ 64flowing; R allocated
6err=17, age highQUIESCE0xFFFFP, Q, Rretained16 @ 64admission stops
7err=17QUIESCE0xFFFFP, Q, Rretained16 @ 64in-flight unit completes to its boundary
8err=17QUIESCE0xFFFFP, Q, Rretained16 @ 64tx_unit_boundary — drained
9err=17RETRAIN0xFFFFP, Q, Rretained16 @ 64link down; replay untouched
10err=17RETRAIN0xFFFFP, Q, Rretained16 @ 64retraining at the current map
11still failingREPAIR0xFFFFP, Q, Rretained16 @ 64requested = 0xFFF7 staged; active unchanged
12maskedREPAIR0xFFFFP, Q, Rretained16 @ 64retrain for the new map
13maskedVALIDATE0xFFFFP, Q, Rretained16 @ 64new map proven; active STILL old
14maskedVALIDATE0xFFFFP, Q, Rretained16 @ 64peer agreement obtained
15maskedREDUCED0xFFF7P, Q, Rretained15 @ 64map_commit: version 0→1, every consumer together
16maskedREDUCED0xFFF7P replayedretained15 @ 64replay re-driven under the new map
17maskedREDUCED0xFFF7Q replayedretained15 @ 64
18maskedREDUCED0xFFF7R replayedretained15 @ 64
19maskedREDUCED0xFFF7emptyretained15 @ 64obligations resolved
20maskedREDUCED0xFFF7resp arrives15 @ 64traffic resumes; T completes normally

Eight readings, and the most important are the columns that do not move.

Cycles 2–3: errors accumulate with no action. One error, then three. §9's bug is the version of this table where the mask changes at cycle 2 — and every subsequent beat is corrupt.

Cycle 4: SUSPECT, and traffic keeps flowing. Suspicion is a monitoring state, not an action state. Most suspicion resolves itself (§13), and reconfiguring here would spend a full quiesce-retrain-commit cycle on a lane that might be fine.

Cycle 6: action requires magnitude and persistence. err=17 exceeds the action threshold and the unhealthy age is satisfied. A burst reaching 17 in two cycles would not have triggered this (§8).

Cycles 7–8: the drain waits for a unit boundary, not for an empty queue. One extra cycle at 7 lets the in-flight unit finish. §21 is why that cycle is not optional.

Cycles 6–19: the Replay column never loses an entry, and T is never cleared. Fourteen cycles including a link-down retrain and a lane-map change. §19's bug is the version where the Replay column empties at cycle 15 — and P, Q and R are lost with the repair reported as a success.

Cycles 11–14: requested is 0xFFF7 while active remains 0xFFFF. Four cycles in which the design knows the new map and has not applied it. §16's bug is the version where the Active mask column changes at cycle 11.

Cycle 15 is one atomic event. Mask, width and version change together on one edge. Not the mask at 15 and the width at 16.

Cycles 16–18: replay is re-driven under the new map before general traffic resumes. P, Q and R are re-striped across 15 lanes — the same objects, the same identities, a different placement on wires (§19). And at cycle 20, T's response arrives and matches: from the Protocol Layer's view, a lane failure was a latency event and a bandwidth change.

29. Failure Trace — the Map Changed Mid-Unit

The same scenario with §16's per-lane update, on a unit spanning beats 0–3.

CycBeatTX mask usedRX mask usedResult
600xFFFF0xFFFFcorrect
710xFFFF0xFFFFcorrect
820xFFF70xFFFFstriped across 15, reconstructed as 16
930xFFF70xFFFFcorrupt

Two independent corruptions from one change.

Transmitter against receiver. The receiver reconstructs beats 2 and 3 using a map the transmitter has stopped using. Every byte from beat 2 onward is placed wrongly.

And the unit spans two configurations, which is §21's impossible case — beats 0–1 under one map, beats 2–3 under another. No receiver can reassemble this correctly, because reconstruction takes one map parameter. Even a receiver that somehow learned of the change at the right instant could not, because the unit's own bytes require two different inverse mappings.

What is reported. A CRC failure. The investigation goes to the physical layer, where nothing is wrong, on a link that just "successfully" repaired itself.

And it amplifies. The corrupted bytes are attributed by the per-lane logic to further lanes, which cross their thresholds, which masks more lanes, which corrupts further. Within microseconds every lane is logged as failing — and the final error report reads exactly like a common-mode event (§25), sending the investigation to clock and supply.

The fix is two properties, and they are cheap. p_map_stable_without_commit makes the direct write impossible; p_unit_within_one_config catches any commit that lands mid-unit regardless of how the boundary was computed, which is the stronger of the two because it does not trust the gate.

30. Performance After Degradation

A successful repair is not a full success, and treating it as one hides the cost.

What to measure after a repairWhy
Useful throughput, not link statethe link is up; the question is what it delivers (13.5 §30)
Active width and ratethe operating point changed (§23, §24)
Retry rateif it is still elevated, the repair did not address the cause
Stall attributionthe binding resource may have moved (13.5 §35)
Congestion statereduced capacity against unchanged offered load (13.4)

The last row is the one that produces a second incident. The workload does not know the link narrowed. Offered load is unchanged and capacity fell, so utilisation rises toward saturation, queues fill, and the congestion policy engages on a link that is working exactly as designed after a repair.

And useful / transmitted remains the discriminator (13.5 §30). A repaired link with an elevated retry rate is busy and delivering less; a repaired link that is simply narrower is busy and delivering proportionally less with the ratio unchanged. Those two look identical in a utilisation figure and completely different in that ratio.

31. The Degradation Feedback Loop

The systems-level insight, and it composes every module.

  1. Physical errors rise on one lane.
  2. Retries rise (14.3), consuming replay residency and bandwidth.
  3. Congestion rises (13.4 §26) — the retry tax is an amplifier.
  4. Robustness policy acts: quiesce, retrain, repair, commit.
  5. Capability is reduced — narrower, or slower.
  6. Utilisation rises against unchanged offered load.
  7. Queues fill; congestion engages (13.4).
  8. And if the underlying physical cause persists, the loop re-enters at step 1 on the remaining lanes.

Three properties of this loop.

Every step is a correct local response. Retry retries. Congestion policy throttles. Robustness repairs. Nothing in the chain is a bug, and each mechanism can be verified correct in isolation while the composition degrades.

It can converge or diverge, and which depends on the physical cause. If the fault was genuinely local to one lane, step 5 removes it and the loop terminates with a narrower, stable link. If the cause is common-mode (§25), masking lanes does not address it, so the loop re-enters and the link walks down its escalation ladder to failure — losing capability at each step for a fault that was never lane-local.

And the flap detector is the instrument that distinguishes them (14.2 §19). A link that repairs once and stabilises has converged. A link that repairs repeatedly is diverging, and the correct response is to stop masking lanes and look for the common cause — which is a decision the verified architecture routes through software (§3), and this is a good illustration of why.

32. Debug Taxonomy

SignatureMost likely causeFirst instrument
One lane's errors rise before a retry stormgenuine lane degradationper-lane error log; the first-failing-lane register
Errors begin exactly after a map commit§16 or §29 — configuration mismatch or a mid-unit commitis the map written anywhere except map_commit? does any consumer latch it?
All lanes fail togethercommon-mode — clock, supply, rate, temperature (§25)the distribution across lanes, not the maximum
Repair succeeds, an object is missing§19 — replay cleared at the commitreplay occupancy immediately before and after the commit
A transaction times out after a successful repair§19, or the outstanding table cleared (14.2 §11)tracking population across the commit
Link works, throughput exactly halvessuccessful degraded operation — this is the mechanism workingactive width against the previous width
Throughput falls more than the width didthe operating point changed and a pool is now binding (13.5 §35)stall attribution, re-measured after the repair
Repeated repair/recovery loopmarginal channel, or a common-mode cause being treated as lane-local (§31)repair count per lane; flap rate
One lane repaired repeatedlythe repair is not addressing the cause — aggressor neighbour, or shared clock/valid pathper-lane repair_count, sticky
Errors attributed to a lane that tests cleanattribution path bugscoreboard check 5 — inject on a known lane, confirm where it is logged
A burst of errors triggers a repair§8 — the persistence term is missing from the action conditionis lane_degraded a conjunction of magnitude and age?
Congestion appears after a successful repair§30 — unchanged offered load against reduced capacityoffered load against active width

33. Debug Checklist

  1. Which lane degraded first? Latch-once, never overwritten (§7) — in a multi-lane failure this is the discriminator.
  2. Which detector identified it? The verified per-lane path, or an inference from CRC? Only the first is lane-attributable (§5).
  3. Was the error transient, a burst, persistent, or common-mode? §10 — three of the four require no lane action.
  4. What was the active lane map before the event? Everything else is interpreted against it.
  5. Was traffic quiesced, and did the drain wait for a unit boundary? Not queue-empty (§15).
  6. Which objects were replay-owned at the repair? They must survive with identity and attempt count intact (§20).
  7. Was any unit partially transmitted? §21 — this is the case that cannot simply continue.
  8. What map or rate was requested, and was it staged rather than applied? §11.
  9. When was it validated, and did the peer agree? Both, before the commit.
  10. When was it committed — one cycle, one event? §17.
  11. Did every consumer switch on that edge? Any registered copy is a one-cycle disagreement, which is local corruption (§16).
  12. Did replay state survive the commit unchanged? Not merely survive — unchanged, including sequence identity (§20).
  13. Did transaction state survive? 14.2 §12's census across the configuration boundary.
  14. What changed in throughput, and does it match the width change? More than proportional means a pool is now binding (§30).
  15. Is the degradation stable or flapping? Repair count per lane and flap rate — a diverging loop means the cause is not lane-local (§31).

34. Common Misconceptions

"Lane repair means just disabling a bad lane." The verified action is "mask faulty lane and retrain". Masking changes the striping, the lane-to-signal assignment and the deskew relationships — a masked link is a different physical configuration, and it needs training to establish it. Masking without retraining changes the mapping and keeps the old timing (§12).

"Lane mapping can change while traffic runs." The transmitter's striping and the receiver's reconstruction are inverse operations parameterised by the map. Change one side and they stop being inverses; change it mid-unit and no receiver can reassemble the unit, because reconstruction takes one map parameter (§16, §21).

"Recovery may clear replay state." The entries were transmitted under the failing configuration, which is exactly why some may not have arrived — they are the work most in need of retransmission. A replay entry stores the transport object, not a lane-specific encoding, so re-striping it under the new map is correct (§19).

"A successful degraded link is equivalent to full-rate operation." It delivers less, its rate × latency products have all changed, and the workload's offered load has not — so utilisation rises and congestion can appear on a link that is working as designed (§23, §30).

"One lane error always requires a full link reset." At the specified BER a lane sees an error roughly every 15.6 seconds at 64 GT/s. Those are expected and are handled by CRC and replay. Reconfiguration is reserved for a fault that is both large and persistent (§9, §10).

"Width reduction only affects throughput." It changes beats per unit, the striping pattern, and every rate × latency product in Module 13 — while buffers do not physically resize, so whether the existing depth is generous or marginal changes (§23).

"Rate reduction cannot affect buffer or credit behaviour." Latencies measured in cycles change when the cycle time changes, so the pools sized in the concurrency conjunction must be re-evaluated. And the verified BER targets differ by three orders of magnitude between 64 and 48 GT/s, which is why rate reduction addresses a much wider class of causes than width reduction (§24).

"CRC alone identifies which lane is bad." A CRC is computed over a whole transport unit and cannot attribute a fault to a lane. Attribution requires a per-lane detector — which is exactly what the verified periodic parity injection with per-lane error logging provides (§5).

"If retraining succeeds, the configuration commit is trivial." The commit is where the two sides switch together, atomically, with no unit in flight. Every corruption in this chapter happens at or around the commit, not during the training (§16, §17, §29).

"Repeated recovery is only a physical-layer concern." A diverging repair loop usually means a common-mode cause is being treated as lane-local, so each iteration spends capability on a fault that was never in a lane. Repair count per lane and flap rate are what distinguish convergence from divergence (§25, §31).

"Spare lanes and width degradation are two policy choices." They are two mechanisms tied to the packaging option — advanced packages have spare lanes covering data, clock, valid and sideband; standard packages degrade width. A design knows which it has before it sees a single error (§4).

35. Understanding Check

36. Summary and What Comes Next

Robustness is graceful reduction of capability while preserving correctness — in that order. A link that loses a lane may become slower; it may never become wrong.

UCIe defines two mechanisms and the packaging option chooses between them. Advanced packages have spare lanes covering data, clock, valid and sideband; standard packages degrade width. Repair is bandwidth-neutral on one and not on the other, so the performance model must be package-aware — and the design knows which it has before it sees an error.

The verified repair action is "mask faulty lane and retrain", and the second word carries the weight: a masked link is a different physical configuration, not the old one minus a lane, and it needs training to establish it.

Attribution requires a per-lane detector. A CRC spans a whole unit and cannot say which lane. The verified path is periodic parity flit injection during mission mode, logged per lane, with software assessing whether repair is needed — so the health record is the hardware half of a hardware-software decision.

Act on magnitude and persistence. A single error is expected at the specified BER; a burst is one event with many symptoms; only a lane that is both bad and stays bad justifies the most expensive action the link has.

Requested map is not active map, and the commit is atomic — one register, one edge, every consumer reading it directly, gated on validation, peer agreement, no unit in flight, and exactly once. Updating lanes individually while traffic runs is this chapter's signature corruption, and it is self-amplifying: the resulting errors are attributed to further lanes, which mask further, until the log reads like a common-mode event.

A transport object must never span two configurations, because reconstruction takes one map parameter. Gating the commit is the intention; the configuration-version property is the proof, and it holds regardless of how the boundary was computed.

Replay and transaction state survive a repair unchanged — including sequence identity and attempt count. The entries were sent under the failing configuration, which is exactly why they may not have arrived, and re-striping the same object under a new map is correct because the map is a parameter of the transmission and not part of the object.

And reduced capability is a new operating point, not the old one with a smaller number. Every rate × latency product changes, buffers do not resize, offered load does not fall, and utilisation rises — so congestion can appear on a link that is working exactly as designed. Whether the degradation loop converges depends on whether the fault was ever lane-local, and repair count with flap rate is what tells you.

The link can now detect that trust has been lost, restore it, replay the work that was damaged, and survive physical degradation. The final reliability question is system-facing: how are persistent faults reported, isolated, escalated, and made visible to software without destroying the diagnostic context that makes them explicable?

Browse the full path on the UCIe tutorials index.