Skip to content

PCIe · Module 5

PCIe Gen5 — Margin Becomes the System Problem

Gen5 doubles again to 32 GT/s with the same encoding, halving the unit interval to 31.25 ps. Why equalisation and channel quality become central, why raw error counts must be normalised before comparison, and how to separate margin-limited from workload-limited behaviour.

Chapter 5.4 established the pattern: same encoding, doubled rate, capacity doubles cleanly, and the difficulty is entirely in preserving margin. Gen5 repeats that pattern once more, and the repetition is the point — because the difficulty does not scale linearly.

What changes when PCIe reaches 32 GT/s, where preserving enough margin becomes a major system-level engineering challenge?

1. The Arithmetic

The derivation is by now routine, which is itself informative — the protocol arithmetic has stopped being where the difficulty lives.

Step 1. 32 × 10⁹ transfers/second, per lane, per direction.

Step 2. Still 128b/130b, still ≈98.4615%. 32 GT/s × (128/130) = 31.507692307... Gb/s≈ 31.5077 Gb/s

Step 3. ÷ 8 = 3.938461538... GB/s

Step 4. ≈ 3938.462 MB/s, decimal units.

Gen3Gen4Gen5
Signalling rate8 GT/s16 GT/s32 GT/s
Encoding128b/130b128b/130b128b/130b
Efficiency≈98.4615%≈98.4615%≈98.4615%
Encoding-adjusted bit rate≈7.8769 Gb/s≈15.7538 Gb/s≈31.5077 Gb/s
Encoding-adjusted byte rate≈984.6 MB/s≈1969.2 MB/s≈3938.5 MB/s

All per lane, per direction, theoretical, before higher-layer overhead. Each step is exactly 2.000× the previous, because the efficiency ratio is 1.000.

2. The Unit Interval, Three Generations Deep

This is the chapter's central quantitative picture, and it is where the escalation becomes visible.

Unit interval comparison across three generations: Gen3 at 8 giga-transfers per second has a 125 picosecond unit interval where a hypothetical 10 picosecond uncertainty is 8 percent; Gen4 at 16 giga-transfers per second has 62.5 picoseconds where the same uncertainty is 16 percent; Gen5 at 32 giga-transfers per second has 31.25 picoseconds where it is 32 percent.Gen38 GT/s → UI 125 pshypothetical 10 ps = 8% of the intervalGen416 GT/s → UI 62.5 psthe same 10 ps = 16% of the intervalGen532 GT/s → UI 31.25 psthe same 10 ps = 32% of the interval
Figure 1 — the unit interval halving across three generations, with a hypothetical fixed 10 ps timing uncertainty shown as a fraction of each. The impairment never changes; the budget it competes for halves each time, so its relative cost doubles. The 10 ps figure is chosen to make the arithmetic legible — it is not a PCIe budget, not a measured value, and the unit interval is not the sampling margin available to a receiver.

The arithmetic: UI = 1/rate, giving 125 ps, 62.5 ps, and 31.25 ps. A fixed 10 ps uncertainty is 8%, 16%, and 32% of those respectively.

Nothing about the impairment changed across those three rows. The same board, the same connector, the same jitter — and its relative cost quadrupled from Gen3 to Gen5.

3. Why the Difficulty Escalates Faster Than the Rate

If margin were the only issue, Gen5 would be twice as hard as Gen4. Several effects compound, which is why it is harder than that.

Channel loss grows with frequency content. Attenuation in interconnect generally increases with frequency, and faster signalling puts more energy higher. The relationship is not linear in rate, so doubling the rate typically costs more than double in loss at the frequencies that matter.

Inter-symbol interference worsens. With less time between transitions, residual energy from previous transfers is proportionally larger relative to the current one. Shorter intervals give the channel less opportunity to settle.

Reflections land in later transfers. Energy reflected from a discontinuity returns after a delay set by physical distance. As the interval shortens, that fixed delay spans more transfers, so reflected energy from a fixed physical structure interferes with transfers further along the stream.

Crosstalk contributes more. Coupling between neighbouring conductors generally increases with edge rates and frequency content, while the budget available to absorb it shrinks.

Jitter occupies more of the interval. The §2 argument.

Package, connector, and board become significant contributors. At lower rates these were often approximately transparent. At Gen5 rates, transitions between package, board, and connector represent structures the signal must traverse, each contributing loss and discontinuity.

4. Equalisation, Stated Carefully

Equalisation is in this chapter's canonical purpose, so it deserves precision rather than a slogan.

What it does: compensates for frequency-dependent channel behaviour, shaping the transmitted or received signal to counteract impairment so the receiver can recover the intended information more reliably.

What it does not do:

Equalisation does not restore the original signal, and it does not remove channel loss.

It compensates within implementation and channel limits. Those limits are real: a compensator has finite range and finite resolution, and a channel sufficiently degraded cannot be compensated into a working one. Equalisation improves recoverability; it does not make an inadequate channel adequate.

5. Telemetry for Margin-Limited Behaviour

If the channel cannot be simulated in RTL (Chapter 5.4), the hardware must be able to report on it. Gen5 raises the stakes enough that this stops being optional instrumentation and becomes a design requirement.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Illustrative synthesizable RTL — PHY-health telemetry.
// NOT a PCIe controller, NOT PCIe-defined registers. Records abstract
// transport-health events over an epoch alongside the traffic volume observed,
// so counts can be normalised rather than compared raw.
module phy_health_telemetry #(
  parameter int unsigned CNT_W = 32,
  parameter int unsigned VOL_W = 48
) (
  input  logic             clk,
  input  logic             rst_n,
 
  // Abstract health events from whatever produces them.
  input  logic             error_event,
  input  logic             retrain_event,
  input  logic             recovery_event,
  input  logic             link_down_event,
 
  // Traffic volume observed this cycle — the denominator for normalisation.
  input  logic             xfer_event,       // one transfer observed
  input  logic [3:0]       active_gen,       // operating rate identifier
 
  input  logic             epoch_start,
  input  logic             epoch_stop,
 
  output logic [CNT_W-1:0] snap_errors,
  output logic [CNT_W-1:0] snap_retrains,
  output logic [CNT_W-1:0] snap_recoveries,
  output logic [CNT_W-1:0] snap_link_downs,
  output logic [VOL_W-1:0] snap_transfers,   // denominator, same epoch
  output logic [3:0]       snap_gen,
  output logic             snap_saturated,
  output logic             snap_valid,
  output logic             degraded_sticky
);
 
  logic [CNT_W-1:0] c_err, c_ret, c_rec, c_dn;
  logic [VOL_W-1:0] c_xfer;
  logic [3:0]       gen_q;
  logic             running_q, sat_q;
 
  // Saturating increments. A wrapped count reads as a small plausible number
  // for a link that is failing badly, which is worse than an obvious ceiling.
  function automatic logic [CNT_W-1:0] sat_c(input logic [CNT_W-1:0] v);
    return (&v) ? v : (v + 1'b1);
  endfunction
  function automatic logic [VOL_W-1:0] sat_v(input logic [VOL_W-1:0] v);
    return (&v) ? v : (v + 1'b1);
  endfunction
 
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      running_q <= 1'b0; snap_valid <= 1'b0; sat_q <= 1'b0;
      c_err <= '0; c_ret <= '0; c_rec <= '0; c_dn <= '0; c_xfer <= '0;
      gen_q <= '0; degraded_sticky <= 1'b0;
    end else if (epoch_start) begin
      running_q <= 1'b1; snap_valid <= 1'b0; sat_q <= 1'b0;
      c_err <= '0; c_ret <= '0; c_rec <= '0; c_dn <= '0; c_xfer <= '0;
      // Latch the rate: counts from two different rates must never be mixed
      // in one epoch, or the normalised metric is meaningless.
      gen_q <= active_gen;
    end else if (running_q && epoch_stop) begin
      running_q       <= 1'b0;
      snap_errors     <= c_err;
      snap_retrains   <= c_ret;
      snap_recoveries <= c_rec;
      snap_link_downs <= c_dn;
      snap_transfers  <= c_xfer;
      snap_gen        <= gen_q;
      snap_saturated  <= sat_q;
      snap_valid      <= 1'b1;
    end else if (running_q) begin
      if (xfer_event)      c_xfer <= sat_v(c_xfer);
      if (error_event)     begin c_err <= sat_c(c_err); if (&c_err) sat_q <= 1'b1; end
      if (retrain_event)   begin c_ret <= sat_c(c_ret); if (&c_ret) sat_q <= 1'b1; end
      if (recovery_event)  begin c_rec <= sat_c(c_rec); if (&c_rec) sat_q <= 1'b1; end
      if (link_down_event) begin c_dn  <= sat_c(c_dn);  if (&c_dn)  sat_q <= 1'b1; end
    end
 
    // Sticky: records that this link has misbehaved at some point. A per-epoch
    // counter loses that, and "clean last window" is not "always clean".
    if (rst_n && error_event) degraded_sticky <= 1'b1;
  end
endmodule

Classification: synthesizable.

What it teaches: that health telemetry must capture the denominator alongside the numerator. Counting errors without counting the traffic they occurred during produces a number that cannot be compared with anything.

Deliberately simplified: abstract events rather than a specific error taxonomy; a single epoch; no per-lane breakdown; no software access mechanism.

What to notice: snap_transfers is captured in the same atomic snapshot as the error counts. Reading numerator and denominator from different instants produces a ratio describing no actual epoch — a subtle measurement bug that yields plausible numbers.

Production implication: a real design would tie these to normative error detection, report per lane, and expose the counters through a defined interface.

6. Why Raw Error Counts Mislead

The engineering point that makes the telemetry worth having.

Suppose two measurements:

  • Gen4 epoch: 12 errors observed.
  • Gen5 epoch: 12 errors observed.

Equally healthy? Unknowable from those numbers alone. If the Gen5 epoch carried twice the traffic — which at double the rate over the same wall-clock duration it plausibly did — then 12 errors represent half the error rate. Conversely, if the Gen5 epoch was half as long, the same count represents a considerably worse link.

Raw counts are only comparable when the observation conditions are identical. They usually are not.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// Verification-only. NOT synthesizable, NOT PCIe protocol state.
// Normalises health counts against observed traffic volume so measurements
// taken under different conditions become comparable.
//
// Errors per million transfers, computed in integer arithmetic:
//   ppm = (errors * 1_000_000) / transfers
// Multiplication precedes division so small error counts do not floor to zero.
function automatic longint unsigned errors_per_million_transfers(
  input longint unsigned errors,
  input longint unsigned transfers
);
  if (transfers == 0) return 0;               // undefined; report 0 and flag
  return (errors * 1_000_000) / transfers;
endfunction
 
// A comparison is only meaningful if the epochs are of comparable volume.
// Below roughly this many transfers, a normalised figure is dominated by
// counting noise and should not be reported as a quality measure.
localparam longint unsigned MIN_MEANINGFUL_TRANSFERS = 1_000_000;
 
function automatic bit normalisation_is_meaningful(input longint unsigned transfers);
  return (transfers >= MIN_MEANINGFUL_TRANSFERS);
endfunction

Classification: verification-only.

What it teaches: normalising a count against the volume it was observed over, and — equally important — refusing to report a figure when the sample is too small to mean anything.

7. Assertions

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// SVA over the illustrative telemetry. Implementation invariants for THIS
// design — not PCIe protocol requirements.
 
// STABILITY — P1: the operating rate is fixed for an epoch. Mixing rates in
// one epoch makes every normalised figure meaningless.
property p_gen_stable_in_epoch;
  @(posedge clk) disable iff (!rst_n)
  running_q |=> $stable(gen_q);
endproperty
a_gen_stable : assert property (p_gen_stable_in_epoch);
 
// SAFETY — P2: counters saturate rather than wrap.
property p_err_saturates;
  @(posedge clk) disable iff (!rst_n)
  (c_err == '1) |=> (c_err == '1);
endproperty
a_err_saturates : assert property (p_err_saturates);
 
// CONSERVATION — P3: error count is monotonic within an epoch. It records
// occurrences; it can never decrease before the epoch ends.
property p_err_monotonic_in_epoch;
  @(posedge clk) disable iff (!rst_n)
  (running_q && !epoch_start) |=> (c_err >= $past(c_err));
endproperty
a_err_monotonic : assert property (p_err_monotonic_in_epoch);
 
// SAFETY — P4: sticky degradation survives epoch boundaries; only reset clears.
property p_sticky_survives;
  @(posedge clk) disable iff (!rst_n)
  (degraded_sticky && epoch_start) |=> degraded_sticky;
endproperty
a_sticky_survives : assert property (p_sticky_survives);
 
// STABILITY — P5: the snapshot is atomic and coherent. Numerator and
// denominator must come from the same epoch or the ratio describes nothing.
property p_snapshot_atomic;
  @(posedge clk) disable iff (!rst_n)
  (snap_valid && !epoch_start) |=> ($stable(snap_errors) && $stable(snap_transfers)
                                    && $stable(snap_gen));
endproperty
a_snapshot_atomic : assert property (p_snapshot_atomic);

P1 catches the bug that invalidates cross-generation comparison at its root.

P3 catches a counter being cleared or corrupted mid-epoch, which would understate errors without any other symptom.

P5 is the one specific to normalisation: if snap_errors and snap_transfers can come from different instants, the computed ratio describes no epoch that ever occurred. The number will look entirely reasonable.

8. Verification

Monitors observe: health events, transfer volume, the latched rate, epoch boundaries, and the snapshot.

The scoreboard independently computes: expected capacity from first principles, expected normalised error figures from injected error rates, and whether a given epoch meets the minimum-volume threshold for a meaningful comparison. As established in Chapter 5.1, it must not reuse the design's arithmetic.

Scenarios:

  • Gen4 clean, Gen5 degraded. Inject an abstract error rate at Gen5 only. Verify the telemetry attributes counts to the correct rate and that the normalised figure reflects the injection.
  • Same raw count, different traffic volume. Two epochs, identical error counts, different transfer volumes. Demonstrates that raw comparison is wrong and normalised comparison is right — the scenario that justifies the denominator.
  • Bursty degradation. All errors concentrated in a short interval rather than distributed. Verify the aggregate figure is computed correctly and observe that it conceals the burstiness — which is the limitation §6 warns about, made concrete.
  • Below-threshold epoch. Very few transfers. Verify the design or environment declines to report a meaningful quality figure rather than producing a noisy one.
  • Counter saturation. Drive error counts to maximum; verify saturation and the saturation flag.
  • Rate change attempted mid-epoch. Should be prevented; P1 catches it.

Coverage: each event type; each rate latched; saturation reached; epochs above and below the volume threshold; bursty and uniform error distributions.

9. Debugging: Expected 2×, Got Much Less

The reference debug flow for this module. Each step either explains the result or eliminates a class of cause.

1. Confirm the units and the expectation. Is the comparison like-for-like — payload against payload, per lane against per lane, same direction, consistent decimal units? A large share of reports resolve here, and it costs nothing to check.

2. Confirm the operating rate. Is the Link actually running at Gen5? Verify rather than assume. A Link operating at a lower rate cannot deliver the expected capacity, and this is cheap to eliminate.

3. Inspect utilisation. From the cycle classification of Chapter 5.1: high idle means the source never presented the demand, so the Link was not the constraint; high stall means something downstream was.

4. Inspect topology. If the device sits behind a Switch, its own Link is one hop (Chapter 4.2). Check whether a shared upstream segment is binding, and whether other devices behind it are similarly constrained.

5. Inspect PHY telemetry. Errors, retrains, recoveries — normalised against traffic volume and attributed to the correct rate. Elevated figures suggest margin problems; clean figures largely exonerate the physical layer.

6. Compare the same workload at Gen4. The single most informative experiment. It separates rate-dependent behaviour from everything else.

7. Determine what the symptom follows. Does it follow the rate — appearing at Gen5, absent at Gen4? The topology — following a slot or path rather than a device? Or the workload — following the traffic pattern regardless of rate and position?

10. The Generation Ladder

Module 5 so far, in one view. Every figure is theoretical encoding-adjusted capacity, per lane, per direction, before packet, protocol, and workload overhead. None is application throughput.

GenerationSignalling rateEncodingEfficiencyEncoding-adjusted capacityNominal UI
Gen12.5 GT/s8b/10b80%250 MB/s400 ps
Gen25 GT/s8b/10b80%500 MB/s200 ps
Gen38 GT/s128b/130b≈98.4615%≈984.6 MB/s125 ps
Gen416 GT/s128b/130b≈98.4615%≈1969.2 MB/s62.5 ps
Gen532 GT/s128b/130b≈98.4615%≈3938.5 MB/s31.25 ps

Two patterns worth reading off it.

The encoding changed once. Gen1→Gen2 and Gen3→Gen4→Gen5 are pure rate doublings with capacity ratios of exactly 2.000×. Only Gen2→Gen3 moved both variables, which is why its ratio is ≈1.969× rather than the 1.6× its rates alone suggest.

The unit interval has fallen by 12.8× from Gen1 to Gen5 while physical impairments have not shrunk correspondingly. That divergence — capacity rising, interval falling, impairments roughly fixed — is the entire engineering story of the ladder.

11. Common Misconceptions

12. Understanding Check

13. Summary

Gen5 doubles the signalling rate to 32 GT/s, retaining 128b/130b at ≈98.4615%, so capacity doubles cleanly again:

32 GT/s × 128/130 ≈ 31.5077 Gb/s÷ 8 ≈ 3.9385 GB/s≈ 3938.5 MB/s

per lane, per direction, theoretical — exactly 2.000× Gen4.

The unit interval falls to 31.25 ps, a quarter of Gen3's. A hypothetical fixed 10 ps uncertainty goes from 8% of the interval at Gen3 to 32% at Gen5 — the impairment unchanged, the budget quartered. The UI is a nominal interval, not a sampling margin.

Difficulty escalates faster than the rate, because channel loss grows more than linearly with frequency content, inter-symbol interference worsens, reflections span more transfers, and package and connector transitions become significant contributors. Equalisation compensates within implementation and channel limits — it does not restore the original signal, and it did not appear at Gen5; its burden simply became decisive.

For measurement, health telemetry must capture the denominator with the numerator and latch the operating rate, so counts are normalisable and attributable. Normalisation enables comparison but does not establish significance — sample size and burstiness both matter, and real margin claims require characterisation outside RTL simulation.

For debugging, the reference flow is: units → operating rate → utilisation → topology → telemetry → same workload at the lower rate → what the symptom follows. That last comparison is the strongest single discriminator, because workload- and path-limited behaviour look alike at both rates and margin-limited behaviour does not.

Hold the model: capacity doubled again; the margin available to achieve it did not, and the effects working against it grew faster than the rate.

14. What Comes Next

Gen1 through Gen5 share a pattern: the encoding changed once, and every other transition was a rate doubling with the protocol model largely preserved. Chapter 5.6 — PCIe Gen6 breaks that pattern.

Gen6 changes more than the signalling rate. It alters how information is represented on the wire and how it is organised for transport, which makes it a genuine architectural transition rather than another doubling — and means the derivation used throughout this module must be revisited rather than re-parameterised. That is its own chapter, and this one deliberately previews no further.

Module 6 then takes up Link width, which every chapter in this module deliberately held at one lane. Its Chapter 6.7 owns throughput calculation combining rate, width, and encoding — where these per-lane figures become system-level numbers.

Revisit PCIe Gen4 for the margin argument this chapter escalates, or Physical Layer for the architectural framing. Browse the full path on the PCIe tutorials index.