Skip to content
VLSI Mentor

Ethernet · Module 3

Copper Ethernet

From 1000BASE-T onward every twisted pair carries both directions at once, so each receiver hears its own transmitter louder than the far end. Cancelling a known local signal is why BASE-T PHYs are adaptive signal-processing engines, and why pair count and signalling changed at every generation.

Chapter 2.6 established what a PHY owes the MAC and named the three sublayers that divide the work. It said almost nothing about the medium itself, because the medium is where the abstraction stops being portable: a copper channel and a fibre channel impose completely different problems on the silicon that drives them.

This chapter takes copper. The instinct most engineers arrive with is that twisted-pair Ethernet is the simple case — four wire pairs, some drivers, some receivers, and a serialiser. That instinct survives 10BASE-T and dies at gigabit.

Here is why. On a 1000BASE-T link, all four pairs transmit and receive at the same time, on the same pair. Every receiver's input is therefore dominated by its own transmitter's output, leaking back through the very same connector. The far-end signal — the one it actually wants — arrives attenuated by up to a hundred metres of cable, buried under a local signal that is orders of magnitude stronger.

How does a receiver read a signal it can barely hear, underneath one it is generating itself?

1. Scope — What This Chapter Owns

This chapter owns: twisted pair as an engineering channel, why generations differ in pair count and directionality, the hybrid and why echo cancellation is unavoidable above 100 Mb/s, the digital interface a copper PHY presents, per-pair state and its aggregation into a link, and the boundary between what RTL can model and what it cannot.

This chapter does not own: differential signalling itself, common-mode rejection, reflections, jitter and eye behaviour — Chapter 3.3 owns those, and this chapter uses them by name while pointing forward. Nor does it own the line codes: 4B/5B and its successors belong to Chapter 3.5, and PAM signalling to Chapter 3.6.

The division is deliberate. This chapter is about the copper channel and the PHY architecture it forces. The physics of a differential pair and the details of the codes carried over it are each large enough to own a chapter, and splitting a topic across two chapters that each half-explain it serves nobody.

2. What a Twisted Pair Is, and Why It Is Twisted

A twisted pair is two conductors carrying equal and opposite signals, physically twisted around each other at a controlled rate along the cable.

The signal is the difference between them. A receiver measures one conductor against the other, not against ground. Chapter 3.3 develops what that buys in detail; the part needed here is the immediate consequence: interference that lands on both conductors equally cancels in the difference, because it adds the same amount to both sides of a subtraction.

The twisting is what makes "equally" true. Along a twisted pair the two conductors continuously swap physical positions, so any external field that would otherwise couple more strongly into the nearer conductor couples into each of them for the same fraction of the cable length. Without the twist, one conductor is systematically nearer the interferer and the disturbance appears in the difference — as signal.

Twisting also limits how much each pair disturbs its neighbours. A cable carries four pairs in one jacket, each twisted at a different pitch. If two pairs shared a pitch they would stay in a fixed relative orientation for the whole run and couple consistently; different pitches keep the coupling from accumulating coherently.

TermWhat it namesWhy the PHY cares
Insertion losshow much signal amplitude the channel removessets how small the received signal is, and it worsens with frequency
Return losshow much energy reflects back from discontinuitiesreflections arrive delayed and add to later symbols
NEXT (near-end crosstalk)coupling from a local transmitter into a local receiver on another pairstrongest interferer after the pair's own echo
FEXT (far-end crosstalk)coupling from a far-end transmitter into a different pair at this endattenuated by the cable, so weaker than NEXT
Echoa pair's own transmitter leaking into its own receiveronly exists when a pair is bidirectional

Every row is a distortion the PHY must handle in silicon, and the last row exists only for the generations that made pairs bidirectional. That single row is why 1000BASE-T needed an architecture 100BASE-TX did not.

3. Four Generations, Four Architectures

The most damaging simplification available here is to describe "copper Ethernet" as one thing. It is not, and the differences are architectural rather than parametric.

10BASE-T100BASE-TX1000BASE-T10GBASE-T
Pairs used2244
Direction per pairone way eachone way eachboth, simultaneouslyboth, simultaneously
Echo cancellationnot needednot neededrequiredrequired
Line signallingManchester4B/5B, then NRZI, then MLT-3PAM-5PAM-16, arranged as DSQ128, with precoding
Symbol rate per pair125 MBd125 MBd800 MBd
Forward error correctionnonenonetrellis codingLDPC block code
IEEE clauseClause 14Clauses 24 and 25Clause 40 (802.3ab)Clause 55 (802.3an)

Read the table across the "direction per pair" row. That is the architectural break. Everything below it in the 1000BASE-T and 10GBASE-T columns — echo cancellation, higher-order signalling, forward error correction — follows from the decision to run both directions on every pair.

Why that decision was made: at 100 Mb/s, two pairs at 125 MBd each carrying one direction is comfortable. Scaling that approach to 1 Gb/s would have required either ten times the symbol rate on two pairs, or four pairs at a much higher rate. Both push the signal into frequencies where the installed cable's insertion loss makes the received amplitude untenable. Using all four pairs in both directions keeps the symbol rate at 125 MBd — unchanged from 100BASE-TX — and buys the factor of ten from four pairs, two directions, and more bits per symbol instead. The rate stayed still and the complexity moved into signal processing, which is exactly the trade that made gigabit work on cable already in the walls.

4. The Hybrid, and Why Echo Cancellation Is Not Optional

When one pair carries both directions at once, a transmitter and a receiver share one physical connection. The circuit that joins them is a hybrid — the same idea as the telephone hybrid that let one pair carry both halves of a conversation.

A hybrid is imperfect by construction. Some fraction of the transmitted signal appears at the local receiver's input, and that fraction is not small relative to what matters.

A transmit path drives the hybrid, which connects to the twisted pair. The hybrid also feeds the receive path, so the local transmit signal leaks into the local receiver as echo. A copy of the transmitted signal is fed to an echo canceller, whose estimate is subtracted from the receiver input before detection.Transmit pathencoder and line driverHybridjoins both directions toone pairTwisted pairattenuates, reflects,couplesFar-end PHYtransmitting toward usSubtractorremoves the estimateReceive pathequalise, then detectEcho cancelleradaptive model of our ownleakour signalwanted plus echowantedcopy of what we sentestimate12
Figure 1 — the receiver's largest interferer is its own transmitter, arriving through the hybrid.

The dashed path is the whole idea. The echo canceller has an enormous advantage: it knows exactly what was transmitted. It is not trying to remove unknown noise; it is trying to remove a known signal that has been distorted by an unknown but stable path — the hybrid's imbalance plus the near-end reflections of the cable.

So the canceller builds an adaptive model of that path, applies it to a copy of the transmit data, and subtracts the prediction from the receiver's input. Whatever survives the subtraction is the far-end signal.

Three consequences follow directly, and every one of them shows up at the digital interface you will integrate against:

  1. A link needs training. The filter coefficients are not known in advance; they depend on this cable, these connectors, this installation. They must be learned before data can flow, which is why a copper link takes time to come up.
  2. Convergence can be lost without anything being unplugged. Temperature drift, a marginal connector, a cable moved by a technician — the path changes, the model no longer matches, and the residual echo swamps the far-end signal. The link fails while the cable is still perfectly connected.
  3. Each pair converges separately. Four pairs, four echo cancellers, four independent convergence states — and the link is only usable when all four have succeeded. Section 8's aggregation makes that explicit, and Section 16 shows why exposing it per pair is the difference between a five-minute diagnosis and a day of guessing.

5. Magnetics, Isolation, and the DC Constraint

Between the PHY silicon and the connector sits a transformer — usually with common-mode chokes, packaged together and universally called "the magnetics".

What it is for, in order of how often it matters:

  1. Galvanic isolation. Two pieces of equipment on a link may sit on grounds at different potentials, sometimes very different. The transformer passes signal without a DC path, so no ground current flows through the cable and neither endpoint's ground is imposed on the other. This is a safety and equipment-survival requirement long before it is a signal one.
  2. Common-mode rejection at the boundary. The transformer passes the differential signal and largely rejects what is common to both conductors, adding to the pair's own rejection.
  3. A DC block, which constrains the line code. A transformer cannot pass a constant. A line code with a sustained DC component simply does not arrive.

Point three is the one that reaches back into digital design. It is the same constraint Chapter 2.6 named when it introduced running disparity, arriving here from the physical side: the medium is AC-coupled, so a code that can transmit a long run of one level is unusable regardless of how efficient it looks on paper.

This is a real design boundary, not a footnote. The DC constraint is why every Ethernet line code — Manchester, MLT-3, PAM-5's mapping, the scrambling in 10GBASE-T — has balance as an explicit property rather than an accident. Chapter 3.5 owns how each code achieves it.

6. RTL 1 — The Pair Abstraction

Here is where a digital designer actually meets a copper PHY. The analog work of Sections 4 and 5 does not appear at this interface; what appears is per-pair state, and data that is only trustworthy once that state says so.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// SYNTHESIZABLE. The digital face of a multi-pair copper PHY.
//
// The one rule this module exists to enforce: on a BASE-T link the pairs are
// not independent channels. The data is STRIPED across them, so a single
// pair losing convergence invalidates every symbol -- not one quarter of
// them. A design that treats pairs as independent lanes will pass data
// through a degraded link and corrupt it silently.
package basex_pkg;
  typedef enum logic [2:0] {
    PAIR_RESET    = 3'd0,
    PAIR_SILENT   = 3'd1,  // no energy detected on the pair
    PAIR_DETECTED = 3'd2,  // energy present, nothing converged
    PAIR_TRAINING = 3'd3,  // adaptive filters converging
    PAIR_READY    = 3'd4,  // converged, symbols trustworthy
    PAIR_DEGRADED = 3'd5   // was ready, error rate now unacceptable
  } pair_state_e;
endpackage
 
module pair_datapath
  import basex_pkg::*;
#(
  parameter int unsigned PAIRS       = 4,
  // Bits carried per pair per symbol period. 1000BASE-T carries two bits per
  // pair per symbol; the parameter exists so the same structure serves other
  // generations without a rewrite.
  parameter int unsigned BITS_PER_PAIR = 2
) (
  input  logic clk,
  input  logic rst_n,
 
  // Per-pair status, from the analog front end. NOT modelled here.
  input  pair_state_e            pair_state   [PAIRS],
  input  logic [PAIRS-1:0]       pair_symbol_valid,
  input  logic [BITS_PER_PAIR-1:0] pair_symbol [PAIRS],
 
  // The reassembled parallel word handed upward to the PCS.
  output logic                             word_valid,
  output logic [PAIRS*BITS_PER_PAIR-1:0]   word,
 
  // Why the datapath is not producing words. Two distinct reasons, kept
  // apart because they send an engineer to two different places.
  output logic all_pairs_ready,
  output logic any_pair_degraded
);
 
  logic [PAIRS-1:0] ready_mask;
  logic [PAIRS-1:0] degraded_mask;
 
  always_comb begin
    for (int unsigned p = 0; p < PAIRS; p++) begin
      ready_mask[p]    = (pair_state[p] == PAIR_READY);
      degraded_mask[p] = (pair_state[p] == PAIR_DEGRADED);
    end
    all_pairs_ready   = &ready_mask;
    any_pair_degraded = |degraded_mask;
  end
 
  // Striping. Pair p contributes a fixed slice of every word, and the slice
  // assignment is FIXED -- a receiver that guessed the pair order wrong
  // produces a word whose bits are all present and all in the wrong place.
  // That failure mode looks like data corruption, not like a link fault,
  // which is exactly why pair identity must be established during training
  // and never inferred later.
  logic [PAIRS*BITS_PER_PAIR-1:0] word_c;
  always_comb begin
    word_c = '0;
    for (int unsigned p = 0; p < PAIRS; p++) begin
      word_c[p*BITS_PER_PAIR +: BITS_PER_PAIR] = pair_symbol[p];
    end
  end
 
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      word_valid <= 1'b0;
      word       <= '0;
    end else begin
      // The AND of every pair's valid, gated by the whole link being ready.
      // Both terms are necessary: a pair can present a valid symbol while
      // still converging, and that symbol is not trustworthy.
      word_valid <= all_pairs_ready && (&pair_symbol_valid);
      word       <= word_c;
    end
  end
 
endmodule

Classification: synthesizable.

What it teaches: that pairs on a BASE-T link are not independent lanes. Data is striped, so the link is ready when every pair is ready and produces nothing when any pair is not. The all_pairs_ready gate is the entire difference between a design that stops cleanly on a degraded pair and one that emits corrupted words while every pair-level indicator still looks plausible.

Deliberately simplified: no deskew between pairs. Real four-pair copper PHYs must compensate for propagation-delay differences between pairs in the same jacket — pair-to-pair skew is a specified cable property — and a production datapath contains per-pair alignment buffers. That mechanism is the same one Chapter 2.6 described for elastic buffering, and Chapter 3.8 owns lane deskew properly.

Production implication: the fixed slice assignment is a trap worth naming. If pair identity is wrong — swapped pairs in a patch cable, a crossed connector — every bit still arrives and every one lands in the wrong position. The symptom is data corruption with a perfectly healthy link, which sends people to the MAC and the software. Real BASE-T PHYs resolve pair identity and polarity during training precisely to eliminate this, and the RTL below the PHY must never try to infer it.

Later ownership: deskew and alignment belong to Chapter 3.8.

7. RTL 2 — Per-Pair Training

Section 4 established that filters must converge before data can flow. That convergence is a state machine, and its shape is dictated by the physics rather than chosen for tidiness.

A per-pair training state machine. From SILENT, detecting energy moves to DETECTED. From DETECTED, training begins and moves to TRAINING. TRAINING reaches READY when the filters converge, or falls back to SILENT if energy is lost. READY moves to DEGRADED when the error rate rises, and DEGRADED returns to TRAINING to re-converge or to SILENT if energy is lost.SILENTDETECTTRAINREADYDEGRADEDenergy detectedenergy detectedbegin convergingbegin convergingconvergedconvergederrors exceed thresholderrors exceed thresholderrorsexceed…re-convergere-convergeenergy lostenergy lost
Figure 2 — energy, then convergence, then trust — and degradation is a return, not a fault.

The topology is not decorative. DEGRADED returns to TRAIN, not to SILENT, because a link whose filters have drifted still has energy on the pair and still knows roughly what the channel looks like — re-converging from a warm start is far faster than starting over. And TRAIN falls back to SILENT on energy loss rather than to DETECT, because losing energy means the far end stopped or the cable opened, and there is nothing to converge against.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// SYNTHESIZABLE. Per-pair training supervision.
//
// This module does NOT converge anything. It sequences convergence, times
// it out, and remembers what happened -- which is the part a digital
// designer owns and the part integration bugs live in.
module pair_training_fsm
  import basex_pkg::*;
#(
  // Timeout in clock cycles before a stuck convergence is abandoned and
  // retried. A real value is generation-specific and comes from the PHY
  // vendor, not from this module.
  parameter int unsigned TRAIN_TIMEOUT = 1_000_000,
  parameter int unsigned TIMER_W       = $clog2(TRAIN_TIMEOUT + 1)
) (
  input  logic clk,
  input  logic rst_n,
 
  // From the analog front end.
  input  logic energy_detect,   // signal present on this pair
  input  logic converged,       // adaptive filters have settled
  input  logic error_excessive, // running error rate above threshold
 
  output pair_state_e state,
  output logic        train_enable,   // tells the AFE to run adaptation
  output logic        train_timeout,  // pulse: convergence gave up
 
  // Restart accounting. A pair that keeps retraining is the signature of a
  // marginal channel, and it is invisible unless counted -- because each
  // individual retrain succeeds and the link looks healthy between them.
  output logic        retrain_event   // pulse on every entry to TRAIN
);
 
  pair_state_e      state_q, state_d;
  logic [TIMER_W-1:0] timer_q, timer_d;
  logic               timeout_c;
 
  assign timeout_c = (timer_q >= TIMER_W'(TRAIN_TIMEOUT));
 
  always_comb begin
    state_d = state_q;
    timer_d = timer_q;
 
    unique case (state_q)
      PAIR_RESET: begin
        state_d = PAIR_SILENT;
        timer_d = '0;
      end
 
      PAIR_SILENT: begin
        timer_d = '0;
        if (energy_detect) state_d = PAIR_DETECTED;
      end
 
      PAIR_DETECTED: begin
        timer_d = '0;
        if      (!energy_detect) state_d = PAIR_SILENT;
        else                     state_d = PAIR_TRAINING;
      end
 
      PAIR_TRAINING: begin
        timer_d = timer_q + 1'b1;
        // Energy loss beats convergence: there is nothing to converge to.
        if      (!energy_detect) state_d = PAIR_SILENT;
        else if (converged)      state_d = PAIR_READY;
        else if (timeout_c)      state_d = PAIR_DETECTED; // retry, warm
      end
 
      PAIR_READY: begin
        timer_d = '0;
        if      (!energy_detect)  state_d = PAIR_SILENT;
        else if (error_excessive) state_d = PAIR_DEGRADED;
      end
 
      PAIR_DEGRADED: begin
        timer_d = '0;
        // Warm restart: the channel estimate is stale, not absent.
        if      (!energy_detect) state_d = PAIR_SILENT;
        else                     state_d = PAIR_TRAINING;
      end
 
      default: state_d = PAIR_RESET;
    endcase
  end
 
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      state_q <= PAIR_RESET;
      timer_q <= '0;
    end else begin
      state_q <= state_d;
      timer_q <= timer_d;
    end
  end
 
  assign state         = state_q;
  assign train_enable  = (state_q == PAIR_TRAINING);
  assign train_timeout = (state_q == PAIR_TRAINING) && timeout_c;
  assign retrain_event = (state_q != PAIR_TRAINING) && (state_d == PAIR_TRAINING);
 
endmodule

Classification: synthesizable.

What it teaches: that link training is a supervised, bounded activity rather than an open-ended wait. The timeout exists because a convergence that cannot succeed — a badly terminated cable, a far end that is transmitting something unexpected — will otherwise hold the pair in TRAINING forever, and a link that never comes up and never reports why is the worst possible failure mode.

Deliberately simplified: converged is a single input. Real convergence is a set of independent adaptations — echo canceller, near-end crosstalk cancellers, feed-forward and decision-feedback equalisers, timing recovery — each with its own criterion, and a production PHY exposes several of them. The sequencing this module performs is unchanged; only the width of the input grows.

Production implication: retrain_event is the field that finds marginal cable. A pair that retrains every few minutes comes up successfully every time, so every point-in-time check reports a healthy link. Only the count over time reveals it — and the traffic loss during each retrain is real and shows up to users as intermittent stalls with no error logged anywhere. Count retrains, or you will never find this class of fault.

Later ownership: auto-negotiation — how the two ends agree on a speed and a master/slave relationship before any of this begins — belongs to Chapter 3.8.

Four pairs, four state machines, one link. The aggregation looks like an AND gate and is not.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// SYNTHESIZABLE. Combines per-pair state into a link status.
//
// Two things make this more than an AND gate:
//   1. Hysteresis. Pairs converge at different times, so a raw AND toggles
//      repeatedly during link-up and every layer above sees a flapping link.
//   2. Cause. When the link drops, WHICH pair dropped it is the only piece
//      of information that shortens the diagnosis, and an AND destroys it.
module link_aggregator
  import basex_pkg::*;
#(
  parameter int unsigned PAIRS      = 4,
  // Cycles all pairs must be simultaneously ready before the link is
  // declared up. Prevents announcing a link that is still settling.
  parameter int unsigned UP_HOLD    = 1024,
  parameter int unsigned HOLD_W     = $clog2(UP_HOLD + 1)
) (
  input  logic clk,
  input  logic rst_n,
 
  input  pair_state_e     pair_state [PAIRS],
  input  logic [PAIRS-1:0] pair_retrain_event,
 
  output logic             link_up,
 
  // Per-pair visibility, preserved rather than reduced. This is the whole
  // reason the module exists in this form.
  output logic [PAIRS-1:0] pair_ready_mask,
  output logic [PAIRS-1:0] pair_degraded_mask,
  output logic [PAIRS-1:0] pair_silent_mask,
 
  // Which pairs were NOT ready at the moment the link last went down, held
  // until the link comes back up. By the time an operator looks, the pair
  // has usually recovered -- so the state at the moment of failure is the
  // only evidence that still exists.
  output logic [PAIRS-1:0] down_cause_mask,
  output logic             down_cause_valid
);
 
  logic [PAIRS-1:0]  ready_c, degraded_c, silent_c;
  logic              all_ready_c;
  logic [HOLD_W-1:0] hold_q;
  logic              link_up_q;
 
  always_comb begin
    for (int unsigned p = 0; p < PAIRS; p++) begin
      ready_c[p]    = (pair_state[p] == PAIR_READY);
      degraded_c[p] = (pair_state[p] == PAIR_DEGRADED);
      silent_c[p]   = (pair_state[p] == PAIR_SILENT);
    end
    all_ready_c = &ready_c;
  end
 
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      hold_q           <= '0;
      link_up_q        <= 1'b0;
      down_cause_mask  <= '0;
      down_cause_valid <= 1'b0;
    end else begin
      if (!all_ready_c) begin
        hold_q <= '0;
        // Capture the failing pairs on the DOWN edge only. Overwriting on
        // every cycle of an outage would record the last state before
        // recovery rather than the state that caused the failure.
        if (link_up_q) begin
          down_cause_mask  <= ~ready_c;
          down_cause_valid <= 1'b1;
        end
        link_up_q <= 1'b0;
      end else begin
        if (hold_q < HOLD_W'(UP_HOLD)) hold_q <= hold_q + 1'b1;
        else                           link_up_q <= 1'b1;
      end
    end
  end
 
  assign link_up            = link_up_q;
  assign pair_ready_mask    = ready_c;
  assign pair_degraded_mask = degraded_c;
  assign pair_silent_mask   = silent_c;
 
endmodule
Four per-pair state machines feed an aggregator. The aggregator produces link_up for the layers above it, and separately preserves the per-pair ready mask and the captured down-cause mask, which are what an engineer reads during an outage.Four pair FSMsone state each, independentAggregatorhysteresis, then a verdictlink_upall the layers above consumethisPer-pair masksready, degraded, down causeThe engineerreads these during an outagefour statesone bitwhich pair12
Figure 3 — one output for the layers above, and a different one for the engineer.

Classification: synthesizable.

What it teaches: that a status aggregation must preserve its inputs. link_up is what the layers above consume; pair_ready_mask and down_cause_mask are what an engineer consumes, and a design that produces only the first has made itself undiagnosable to save four flip-flops.

Deliberately simplified: no down-hold. Production designs usually hysteresis both edges so a momentary glitch does not drop a link; only the up edge is held here, to keep the module readable.

Production implication: down_cause_mask captures on the down edge specifically. This is the detail that gets implemented wrong most often — updating the register throughout the outage records the state just before recovery, which is typically all pairs recovering and tells you nothing. Capture the transition, not the condition.

9. RTL 4 — Per-Pair Telemetry

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// SYNTHESIZABLE INSTRUMENTATION.
//
// Per-pair, because the point is DISCRIMINATION. An aggregate error count
// says the link is unhealthy. A per-pair count says pair 3 is unhealthy and
// the other three are fine -- which is a physical claim about one wire pair
// in one cable, and it is actionable in a way the aggregate never is.
module pair_telemetry #(
  parameter int unsigned PAIRS = 4,
  parameter int unsigned CNT_W = 24
) (
  input  logic clk,
  input  logic rst_n,
  input  logic clear,
 
  input  logic [PAIRS-1:0] retrain_event,
  input  logic [PAIRS-1:0] train_timeout,
  input  logic [PAIRS-1:0] entered_degraded,
  input  logic [PAIRS-1:0] symbol_error,     // detector reported a bad symbol
  input  logic             link_went_down,
 
  output logic [CNT_W-1:0] c_retrain  [PAIRS],
  output logic [CNT_W-1:0] c_timeout  [PAIRS],
  output logic [CNT_W-1:0] c_degraded [PAIRS],
  output logic [CNT_W-1:0] c_symerr   [PAIRS],
  output logic [CNT_W-1:0] c_link_down,
 
  // Sticky: has this pair EVER been ready since reset? Distinguishes "this
  // pair has degraded" from "this pair has never worked at all", which are
  // a marginal channel and a broken one -- different faults entirely.
  output logic [PAIRS-1:0] ever_ready
);
 
  function automatic logic [CNT_W-1:0] bump(input logic [CNT_W-1:0] v,
                                            input logic             en);
    bump = (en && !(&v)) ? (v + 1'b1) : v;   // saturating, never wrapping
  endfunction
 
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n || clear) begin
      for (int unsigned p = 0; p < PAIRS; p++) begin
        c_retrain[p]  <= '0;
        c_timeout[p]  <= '0;
        c_degraded[p] <= '0;
        c_symerr[p]   <= '0;
      end
      c_link_down <= '0;
      // ever_ready survives `clear`: it is a property of the installation,
      // not of the measurement window an operator happened to choose.
      if (!rst_n) ever_ready <= '0;
    end else begin
      for (int unsigned p = 0; p < PAIRS; p++) begin
        c_retrain[p]  <= bump(c_retrain[p],  retrain_event[p]);
        c_timeout[p]  <= bump(c_timeout[p],  train_timeout[p]);
        c_degraded[p] <= bump(c_degraded[p], entered_degraded[p]);
        c_symerr[p]   <= bump(c_symerr[p],   symbol_error[p]);
        if (entered_degraded[p]) ever_ready[p] <= 1'b1; // it was ready before
      end
      c_link_down <= bump(c_link_down, link_went_down);
    end
  end
 
endmodule

Classification: synthesizable instrumentation.

What it teaches: that the useful axis of a counter is the one that lets you discriminate. Four separate counts across pairs answer "is it the cable or the chip?"; one summed count answers nothing. The ever_ready mask adds a second discrimination — a pair that has never converged is a different fault from one that converged and drifted.

Deliberately simplified: no rate windows and no time-stamping. Production PHYs typically expose both, and both matter for correlating an outage with an event elsewhere in the system.

Production implication: ever_ready deliberately survives clear. An operator clearing counters to get a clean measurement window would otherwise destroy the one fact that distinguishes "this cable has a broken pair" from "this cable is marginal", and they would have no way to know they had done it.

10. What RTL Cannot Model — and the Verification Model That Admits It

This is the most important paragraph in the chapter for a verification engineer.

None of the modules above simulates a copper channel. Not one line of RTL in this chapter models attenuation, insertion loss, echo, crosstalk, reflection, or the operation of an adaptive filter. Those are analog, continuous-time phenomena; RTL is a discrete-time model of logic values, and the mismatch is categorical rather than a matter of insufficient effort.

The questionWhat can answer it
does the training FSM sequence correctly?RTL simulation — fully
does the link stay down when a pair degrades?RTL simulation — fully
are the counters exhaustive and correct?RTL simulation — fully
does the datapath stripe pairs correctly?RTL simulation — fully
does the echo canceller converge on this channel?analog or mixed-signal simulation, then measurement
what is the bit error rate at 100 metres of this cable?laboratory measurement, on real cable
does this design meet the clause's return-loss mask?laboratory measurement, against the standard

A verification plan that does not draw this line explicitly will either over-claim — "the PHY is verified" when only its digital supervision is — or waste months building a behavioural channel model that cannot answer the questions it was built for.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// NON-SYNTHESIZABLE. VERIFICATION ONLY.
//
// ============================================================================
// THIS DOES NOT MODEL AN ANALOG COPPER CHANNEL.
//
// It corrupts symbols on a schedule so that the DIGITAL supervision logic --
// the training FSM, the aggregator, the counters -- can be driven into states
// that clean stimulus never reaches. Insertion loss, echo, crosstalk and
// equaliser convergence are absent, and no conclusion about real link
// performance may be drawn from any result produced here.
// ============================================================================
module channel_impairment_model #(
  parameter int unsigned PAIRS         = 4,
  parameter int unsigned BITS_PER_PAIR = 2
) (
  input  logic clk,
  input  logic rst_n,
 
  input  logic [BITS_PER_PAIR-1:0] clean_symbol [PAIRS],
  input  logic [PAIRS-1:0]         clean_valid,
 
  // Directed controls. Deliberately explicit rather than random: the point
  // is to reach a named state, not to sample a distribution.
  input  logic [PAIRS-1:0] force_symbol_error,
  input  logic [PAIRS-1:0] force_silence,      // drop energy on a pair
  input  int unsigned      burst_length,       // consecutive corrupt symbols
 
  output logic [BITS_PER_PAIR-1:0] dirty_symbol [PAIRS],
  output logic [PAIRS-1:0]         dirty_valid,
  output logic [PAIRS-1:0]         energy_detect
);
 
  int unsigned burst_remaining [PAIRS];
 
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      for (int unsigned p = 0; p < PAIRS; p++) burst_remaining[p] <= 0;
    end else begin
      for (int unsigned p = 0; p < PAIRS; p++) begin
        if (force_symbol_error[p])          burst_remaining[p] <= burst_length;
        else if (burst_remaining[p] != 0)   burst_remaining[p] <= burst_remaining[p] - 1;
      end
    end
  end
 
  always_comb begin
    for (int unsigned p = 0; p < PAIRS; p++) begin
      energy_detect[p] = !force_silence[p];
      dirty_valid[p]   = clean_valid[p] && !force_silence[p];
      // Inversion stands in for "the detector sliced the wrong level". It is
      // a placeholder for a decision error, NOT a model of why one occurs.
      dirty_symbol[p]  = (burst_remaining[p] != 0) ? ~clean_symbol[p]
                                                   :  clean_symbol[p];
    end
  end
 
endmodule

Classification: non-synthesizable, verification only.

What it teaches: how to build a stimulus model whose limitations are stated in the model itself. The header comment is not decoration — it is the artefact that stops a future engineer from citing a simulation result as evidence about a physical link.

Deliberately simplified: everything physical. There is no channel here at all.

Production implication: models like this get reused far beyond their intended scope, and the reuse is usually well-intentioned. The defence is to make the boundary impossible to miss, in the file, where someone reading the code will encounter it.

11. Reach as a Budget, Not a Number

"100 metres" is the number everyone knows, and treating it as a property of copper is the mistake.

Reach is the distance at which the received signal is still recoverable, and it is the outcome of an inequality: the signal must exceed everything competing with it by enough margin for the detector to decide reliably.

What consumes the budgetGrows with
insertion losslength, and frequency
reflections from discontinuitiesnumber and quality of connectors and patch points
crosstalk from neighbouring pairscable construction, and frequency
residual echo after cancellationhow well the canceller converged
noise from outside the cablethe environment, and the pair's rejection of it

Two consequences follow. First, reach depends on the generation, because a higher symbol rate pushes energy into frequencies where insertion loss and crosstalk are both worse. This is exactly why 10GBASE-T requires better cable to reach the same distance as 1000BASE-T: "Category 6A is required to reach the full distance and category 5e or 6 may reach up to 55 metres depending on the quality of installation."

Second, reach depends on the installation, not only on the cable specification. Connectors, patch panels, bend radius and termination quality all consume budget. A run that passes at one rate and fails at the next has not changed; the budget required of it has.

For the digital designer, this is why link status is a measured property rather than a configured one, and why Section 7's training exists at all. The PHY discovers what this particular channel can support. Nothing upstream can predict it.

12. Equalisation, Named and Deferred

The echo canceller of Section 4 removes a known local signal. Equalisation addresses a different problem: the channel's frequency response is not flat, so a transmitted symbol arrives smeared across the symbol periods that follow it.

That smearing is inter-symbol interference, and the receiver compensates by applying an approximate inverse of the channel — a filter that is again adaptive, again converged during training, and again part of what converged in Section 7 collapses into one bit.

This chapter stops here deliberately. Inter-symbol interference, channel memory, eye closure and the equalisation strategies that address them are the subject of Chapter 3.3, which develops them properly and for both copper and optical channels rather than half-explaining them twice.

What matters for copper specifically, and what belongs here: equalisation and echo cancellation are separate mechanisms solving separate problems, they converge together during the same training phase, and a failure of either produces the same digital symptom — a pair that will not leave TRAINING. Section 16 shows why that shared symptom makes per-pair counters so valuable.

13. Assertions

Every property below is a property of these teaching models, not an IEEE 802.3 requirement. IEEE 802.3 specifies electrical characteristics, coding and the auto-negotiation protocol; how a particular design supervises training and reports status is an implementation choice.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─── Safety: no data escapes an unready link ───────────────────────────────
// The single most important property in the chapter. Because data is striped
// across pairs, a word produced while any pair is unconverged is not
// degraded -- it is wrong. Catches: an optimisation that gates on
// pair_symbol_valid alone and forgets the readiness term.
property p_no_word_unless_all_ready;
  @(posedge clk) disable iff (!rst_n)
  word_valid |-> $past(all_pairs_ready);
endproperty
 
// ─── Safety: the striping map is fixed ─────────────────────────────────────
// Catches: a parameterisation change that reorders the slice assignment, so
// every bit arrives in the wrong position. Presents as data corruption on a
// healthy link, which is the hardest failure in the chapter to diagnose.
property p_stripe_map_is_fixed;
  @(posedge clk) disable iff (!rst_n)
  word_valid |-> (word[BITS_PER_PAIR-1:0] == $past(pair_symbol[0]));
endproperty
 
// ─── Causation: training runs only in TRAINING ─────────────────────────────
// Catches: adaptation left enabled in READY, which lets the filters drift on
// live data and produces a link that degrades slowly under traffic.
property p_train_enable_matches_state;
  @(posedge clk) disable iff (!rst_n)
  train_enable == (state == PAIR_TRAINING);
endproperty
 
// ─── Liveness with an explicit assumption ──────────────────────────────────
// ASSUMPTION: energy is present and convergence eventually reports success.
// Under that assumption a pair must reach READY. Without the assumption the
// property is unprovable, and stating it is the point.
property p_training_terminates;
  @(posedge clk) disable iff (!rst_n)
  (state == PAIR_TRAINING) |-> ##[1:$] (state != PAIR_TRAINING);
endproperty
 
// ─── Bounded response: training cannot hang ────────────────────────────────
// The bounded companion to the property above, and the one that is actually
// provable. Catches: a timeout that never fires because the timer is reset
// in the wrong branch.
property p_training_bounded;
  @(posedge clk) disable iff (!rst_n)
  $rose(train_enable) |-> ##[1:TRAIN_TIMEOUT+2] (state != PAIR_TRAINING);
endproperty
 
// ─── Ordering: degradation is a warm restart, never a cold one ─────────────
// Catches: a simplification that routes DEGRADED back to SILENT, throwing
// away the channel estimate and turning a fast re-converge into a full
// link-down that upper layers see as an outage.
property p_degraded_warm_restarts;
  @(posedge clk) disable iff (!rst_n)
  ((state == PAIR_DEGRADED) && energy_detect) |=> (state == PAIR_TRAINING);
endproperty
 
// ─── Safety: energy loss dominates every other transition ──────────────────
// Catches: a priority inversion where `converged` is evaluated before
// `energy_detect`, declaring a pair ready after the cable was unplugged.
property p_energy_loss_wins;
  @(posedge clk) disable iff (!rst_n)
  (!energy_detect && (state != PAIR_RESET)) |=> (state == PAIR_SILENT);
endproperty
 
// ─── Stability: link_up does not chatter during convergence ────────────────
// Catches: a missing up-hold, so every pair converging at a slightly
// different time produces a burst of link transitions that every layer
// above must absorb.
property p_link_up_requires_hold;
  @(posedge clk) disable iff (!rst_n)
  $rose(link_up) |-> $past(&pair_ready_mask, UP_HOLD);
endproperty
 
// ─── Causation: the down cause is captured on the edge ─────────────────────
// Catches: a cause register updated throughout the outage, which records
// recovery rather than failure -- the single most common instrumentation
// bug in this chapter.
property p_down_cause_captured_on_edge;
  @(posedge clk) disable iff (!rst_n)
  $fell(link_up) |=> $stable(down_cause_mask);
endproperty
 
// ─── Conservation: telemetry never loses an event ──────────────────────────
// Catches: a counter that misses coincident events across pairs, which
// makes a per-pair comparison meaningless.
property p_retrain_counted;
  @(posedge clk) disable iff (!rst_n)
  (retrain_event[0] && !(&c_retrain[0])) |=> (c_retrain[0] == $past(c_retrain[0]) + 1);
endproperty
 
// ─── Safety: counters saturate rather than wrap ────────────────────────────
// Catches: a wrapping counter, which can be read twice and appear to
// DECREASE -- after which an operator stops believing any counter.
property p_counters_saturate;
  @(posedge clk) disable iff (!rst_n)
  (&c_symerr[0]) |=> (&c_symerr[0]);
endproperty

14. Verification

Scenarios

  1. Clean bring-up, all four pairs converging together. The nominal case. Verify each pair walks SILENT to DETECT to TRAIN to READY, and that link_up asserts exactly UP_HOLD cycles after the last one arrives.
  2. Staggered convergence. Pairs reach READY hundreds of cycles apart. Verify link_up asserts once, after the last, with no intermediate pulses. This is the scenario the up-hold exists for.
  3. One pair never converges. Verify link_up stays low indefinitely, train_timeout fires on that pair, and the retry returns it to DETECT rather than SILENT.
  4. Energy lost during training. Verify the pair goes to SILENT, not to READY, even if converged asserts in the same cycle. This is the priority inversion p_energy_loss_wins guards.
  5. Energy lost while ready. Verify an immediate drop to SILENT, link_up deasserting, and down_cause_mask naming that pair alone.
  6. A single pair degrades under traffic. Verify the link drops, down_cause_mask names exactly that pair, and the pair re-enters TRAINING — a warm restart, not a cold one.
  7. All four pairs degrade simultaneously. Verify down_cause_mask names all four and that the aggregator does not favour a lowest-index pair.
  8. Degrade, recover, degrade again. Verify down_cause_mask updates on each down edge and c_degraded advances per pair.
  9. Word production against readiness. Drive pair_symbol_valid high on all pairs while one pair is still TRAINING. Verify no word is produced. A design that gates only on pair_symbol_valid passes every other scenario and fails this one.
  10. Striping correctness. Drive a distinct pattern per pair and verify each lands in its own slice. Then repeat with PAIRS changed, since a parameterisation change is what breaks it.
  11. Reset during training. Verify all state machines return to RESET, no partial word escapes, and link_up is low.
  12. Counter saturation. Drive one per-pair counter to maximum and verify it holds. Verify p_counters_close style reasoning is not applied to a saturated counter.
  13. Clear during operation. Verify clear zeroes the counters and — the part that matters — that ever_ready survives it.
  14. A pair that has never been ready. Verify ever_ready stays low for it while other pairs set theirs. This is the discrimination between a broken pair and a marginal one.
  15. Burst corruption via the impairment model. Drive force_symbol_error with a burst length and verify c_symerr advances on that pair only, with the other three untouched.
  16. Timeout boundary. Hold converged low for exactly TRAIN_TIMEOUT cycles, then assert it one cycle late. Verify the timeout won and the pair retried, rather than a race that lets both happen.

What the checker must own

  • A state-machine reference model replicating Section 7's six transitions. Small, and it catches every priority regression — particularly the energy-loss precedence, which is easy to break in a refactor.
  • A striping scoreboard that reconstructs pair symbols from the output word. It must be parameterised on PAIRS, because that is where the fixed-map assumption breaks.
  • Coverage crosses of pair state against link_up. In particular, the bin (any pair not READY, link_up high) must be unreachable; if it is ever hit, the containment property has failed and the coverage model has caught what the assertion should have.

15. Debugging — Descending Per Pair

The symptom: a link that comes up, works, and intermittently stalls, with no errors logged anywhere.

Step 1 — read c_retrain per pair, twice, with a known interval between. This single measurement partitions the entire problem:

ReadingWhat it meansWho owns it
all four pairs at zerothe PHY is not retraining; the problem is above itMAC, driver, or software
one pair rising, three flatone physical pair is marginalcabling — connector, termination, that run
all four rising togetherthe PHY's own environmentsupply, reference clock, temperature
one pair with ever_ready lowthat pair has never workeda break, not a marginal channel

The fourth row is why ever_ready exists. A pair that has never converged and a pair that converges and drifts produce the same link_up behaviour and demand completely different investigations — replace a cable against chase an environmental margin.

Step 2 — if a single pair is implicated, read c_timeout for it. Retrains that succeed mean the channel is marginal but usable, and the fault is degrading over time. Retrains that time out mean convergence cannot be achieved at all, which points at a break, a severe impedance fault, or a far end transmitting something unexpected.

Step 3 — if all four pairs are implicated, check whether they degrade simultaneously. Four independent marginal pairs in one cable is improbable; four pairs degrading on the same cycle is a common cause, and the common causes are shared: supply, reference clock, temperature, or a far end that reset.

Step 4 — read down_cause_mask after an event. By the time anyone looks, every pair has usually recovered and current state says nothing. The captured mask is the state at the instant of failure, and it is the only evidence remaining.

Step 5 — only now go to the analog domain. Everything above is answerable from digital registers in seconds. Cable certification, time-domain reflectometry and eye measurement are the right next tools, but they are slow and they require physical access, and Steps 1 through 4 tell you which pair to measure and which end to stand at.

The method stated once: per-pair counters convert "the network is flaky" into "pair 3 on this run retrains every 90 seconds and has always eventually succeeded". The first statement has no owner. The second has exactly one, and names the measurement that confirms it.

16. Common Misconceptions

"Copper Ethernet is just digital bits on four wires."

The wrong model: the PHY serialises data, a driver puts it on the cable, a receiver reads it back.

What it costs: you budget a copper PHY like a serial one and miss its area, power and latency. You cannot explain why a link takes time to come up, so you treat training time as a defect. You assume a link that came up will stay up, and you have no design response when it does not.

The corrected model: from 1000BASE-T onward the receiver's dominant interferer is its own transmitter, and reading the far end means cancelling a known local signal with an adaptive filter that must converge first. The PHY is a signal-processing engine; the serialiser is a small part of it.

"All copper Ethernet works the same way, just faster."

The wrong model: one architecture scaled by clock rate.

What it costs: you assume 100BASE-TX's two-pairs-one-direction-each applies at gigabit, so you cannot explain why all four pairs must be intact for a gigabit link — and you misdiagnose a broken pair as a cable that "should still work at a lower speed", which is sometimes true and sometimes not, for reasons the wrong model cannot predict.

The corrected model: Section 3's table. 10BASE-T and 100BASE-TX use two pairs, one direction each. 1000BASE-T and 10GBASE-T use all four, both directions on each, which is why they need echo cancellation and why every pair matters.

"The magnetics are just isolation."

The wrong model: a transformer for safety, otherwise transparent.

What it costs: you treat DC balance as an optional property of a line code and cannot explain why every Ethernet code has it as an explicit design goal. You design or select a coding scheme with a sustained DC component and find the signal does not arrive at all.

The corrected model: the transformer cannot pass a constant. That is a hard constraint on the line code, and it is the physical origin of the running-disparity requirement Chapter 2.6 introduced from the digital side.

"100 metres is a property of copper cable."

The wrong model: copper reaches 100 metres, full stop.

What it costs: you cannot explain why a run that carried gigabit fails at 10 gigabit, so you suspect the equipment. You size an installation on cable category alone and ignore connectors and patch points, which consume real budget.

The corrected model: reach is a budget balancing signal against loss, reflections, crosstalk and noise — and the budget tightens with symbol rate. 10GBASE-T needs Category 6A for the full distance and may reach roughly 55 metres on Cat5e or Cat6, "depending on the quality of installation".

"A link that is up is a link that is healthy."

The wrong model: link_up is the health indicator.

What it costs: you miss the entire class of faults in Section 15 — the marginal pair that retrains every few minutes, comes back every time, and reports up at every instant anyone checks. Users see intermittent stalls; monitoring sees a perfect link.

The corrected model: link_up is instantaneous state. Health is a rate, and it is only visible in counters accumulated over time — per pair, because the aggregate cannot say which one.

17. Interview Reasoning

"Why is a 10GBASE-T PHY so much larger and hotter than a 10GBASE-R one at the same rate?"

The answer that ends the topic names the work: continuous adaptive cancellation of echo and crosstalk on four bidirectional pairs, plus equalisation, plus an LDPC decoder. A serial PHY does none of it. The measurable consequence — roughly 2 to 4 microseconds of latency against 1 microsecond or less — makes the argument concrete rather than hand-waved.

"A gigabit link works and a 10 gigabit link on the same cable does not. What is your first question?"

Not "is the cable bad". The right first move is to establish that reach is a budget that tightens with symbol rate, and then to ask which pair fails — because a single failing pair points at the run, and all four point at the environment or the equipment. Naming a first measurement is what distinguishes a strong answer.

"Why can a copper link fail without anyone touching the cable?"

Because the PHY holds an adaptive model of a channel that changes with temperature and mechanical settling. When the model no longer matches, residual echo swamps the far-end signal. The follow-up worth anticipating is why the correct response is re-convergence rather than a fault — which is Section 13's rejected property, and getting that right signals real familiarity.

18. Understanding Check

Because on a 1000BASE-T link every pair carries both directions simultaneously, so each receiver's input is dominated by its own transmitter leaking through the hybrid that joins them.

The far-end signal has crossed up to a hundred metres of cable and is heavily attenuated. The local echo has crossed a few millimetres of silicon and package. The wanted signal is far smaller than the interference, and no amount of serialiser architecture changes that.

How the PHY solves it: the echo canceller knows exactly what was transmitted. It builds an adaptive model of the leakage path, predicts the echo from a copy of the transmit data, and subtracts the prediction. What survives is the far end.

What that forces into the design: the filter must converge before data flows, which is why a copper link takes time to come up. It converges per pair, so readiness is per-pair state. And it can lose convergence when the channel drifts, which is why a link can fail with nothing unplugged.

The follow-up to be ready for: does 100BASE-TX need this? No — it uses two pairs, one direction each, so no receiver ever hears its own transmitter. Echo cancellation is a consequence of the bidirectional decision, not of copper.

19. What's Next

Copper's defining problem is that a gigabit receiver hears its own transmitter louder than it hears the far end. Everything architectural follows: the hybrid, the echo canceller, per-pair convergence, training time, and a link that can fail without being touched.

The generations differ architecturally rather than by degree — two pairs one way each at 10 and 100 Mb/s, all four pairs both ways from gigabit onward — and flattening them into one story loses the only fact that explains why a broken pair behaves differently at each rate.

Chapter 3.2 — Fibre Ethernet takes the other medium, and the contrast is instructive: an optical link has no echo problem at all, because transmit and receive use separate fibres. What it has instead is a completely different boundary — an electrical-to-optical conversion, a module that may be pluggable, and failure modes that have no copper equivalent.

Beyond that, Chapter 3.3 develops what a real channel does to a signal, Chapter 3.4 gives the sublayer split in depth, and Chapter 3.5 owns the line codes this chapter named and deferred.

The full path is on the Ethernet curriculum index.

Continue learning

Standards & specifications

Governing standard
IEEE Std 802.3 (Ethernet)(opens IEEE in a new tab)

Defines the Ethernet MAC, the media-independent interfaces and the physical-layer sublayers, including framing, access control, auto-negotiation and per-rate PHY specifications. VLAN tagging, priority and time-sensitive shaping are defined by IEEE 802.1, not by 802.3.

This page also covers RTL structure, verification approach and debugging technique. Those are engineering practice built on the standard, not requirements the standard itself imposes.

Where this fits

Part of the Ethernet curriculum.