Ethernet · Module 22
Single-Pair Automotive Ethernet
3B2T gets 1.5 bits from three levels where MLT-3 gets one, so 100 Mb/s fits on one pair at 66.67 MBd — and the price is an echo canceller sized by the cable's round trip.
A car needed a hundred megabits on two wires instead of four, unshielded, from −40 °C to +125 °C, for fifteen years. Every difference in this chapter follows from that sentence.
| 100BASE-TX | 100BASE-T1 | |
|---|---|---|
| conductors | 4 — one pair per direction | 2 — both directions on one |
| symbol rate | 125 MBd | 66.67 MBd |
| modulation | MLT-3, three levels | PAM3, three levels |
| bits per symbol | 1 | 1.5 |
| fundamental | 31.25 MHz | 33.33 MHz |
| link segment | 100 m | 15 m |
| shield | needed to meet automotive emissions | not needed |
| auto-negotiation | Chapter 9.2 §4's FLP burst | none — master and slave are configured |
Read rows two to five together, because that is where the chapter's central result is. 100BASE-T1 halves the copper and raises the fundamental by only 6.7%. It does not do that with a wider channel or a bigger constellation — both are three-level — it does it by getting one and a half bits out of a symbol where MLT-3 gets one.
And the price is in row one. Both directions on one pair means every receiver hears its own transmitter, at a level far above the partner's, and must subtract it. Chapter 9.3 §2 called that trade explicitly — more levels or more cancellation — and gigabit over four pairs chose cancellation. Automotive chose cancellation for the same reason and with half the copper, which makes the echo canceller the single largest block in the PHY.
| Derived in this chapter | |
|---|---|
| 3B2T uses 8 of the 9 ternary pairs | 88.9% of the alphabet, 94.6% of its information capacity |
| echo delay spread over a 15 m segment | 10.1 symbols round trip at 66.67 MBd |
| the same at 1000BASE-T1's 750 MBd | 113.6 symbols |
| a 192-tap gigabit canceller | 3 456 flops — 24.4% of Chapter 19.7 §19's MAC datapath |
| conductor mass saved over 100 m of link | 0.37 kg — and it is not the point |
Row five is the honest one and Section 14 is about why the weight argument is the weakest of the three constraints. The constraint that actually forced a new physical layer is emissions, and it is not a matter of degree: an unshielded 100BASE-TX link does not meet automotive limits at all, so there was no version of the existing PHY that could be made to work by trying harder.
1. Scope — A Different Physical Layer, and the Three Constraints That Forced It
Scope: why single-pair Ethernet exists, where 100BASE-T1's and 1000BASE-T1's numbers come from, what the shared pair costs in silicon, and what a car deleted from the link layer.
Not in scope: the frame, the MAC, addressing, the check sequence, or anything above the reconciliation sublayer. None of it changes. Chapter 4.1 §3 drew the MAC/PHY split precisely so that a new physical layer would not disturb the MAC, and automotive Ethernet is the cleanest demonstration in the track that the split held: a completely different channel, modulation, negotiation model and qualification regime, and the MAC above it is the same MAC Module 19 built.
Three constraints, and they are not equally binding.
| Constraint | Binding? | Why |
|---|---|---|
| emissions and immunity | absolutely | unshielded 100BASE-TX cannot meet automotive limits — not a matter of margin |
| connector and harness | strongly | pin count, not conductor mass |
| temperature and life | shapes the design | −40 to +125 °C, fifteen years, no service visit |
Row one is the one that forced a new PHY and rows two and three are the ones that shaped it. That ordering matters because the popular account reverses it — weight is the argument everybody repeats and Section 14 shows it is worth 0.37 kilograms per hundred metres of link.
And one thing a car deleted outright.
100BASE-T1 has no auto-negotiation. Master and slave are configured, not discovered, and a mis-set pair does not link at all.
Chapter 21.5 spent a chapter on the duplex mismatch — a fault that links, passes traffic, and degrades under load in a way that takes a two-ended counter comparison to attribute. Automotive removed the mechanism that produces it. The replacement fault is louder and simpler: no link. Section 10 argues that is a straight improvement, and prices what was given up to get it.
2. The Three Constraints, Priced
Take them in the order of how much they constrain, which is not the order they are usually given.
Constraint one — emissions, and it is a hard wall.
| Spectrum | |
|---|---|
| 100BASE-TX, MLT-3 at 125 MBd | fundamental 31.25 MHz, real energy to 125 MHz |
| 100BASE-T1, PAM3 at 66.67 MBd | Nyquist 33.33 MHz, and the transmit filter stops there |
| the FM broadcast band | 88–108 MHz |
| which of the two overlaps it | only the first |
MLT-3 needs four symbols to complete one cycle, so 125 MBd gives a 31.25 MHz fundamental — lower than PAM3's 33.33 MHz Nyquist, which is the fact that surprises people. The difference is not the fundamental. It is the occupied bandwidth above it: MLT-3's symbol stream carries real energy across the whole band up to the symbol rate, and a car's antenna is bonded to the same chassis as the harness.
So the choice was: shield every link, or move the spectrum. Shielding costs mass, connector complexity, and a termination scheme that has to survive fifteen years of vibration; moving the spectrum costs an echo canceller. Automotive took the silicon.
Constraint two — the connector, and the arithmetic is in pins rather than grams.
| Domain controller | 100BASE-TX pins | 100BASE-T1 pins |
|---|---|---|
| 4 links | 16 | 8 |
| 8 links | 32 | 16 |
| 12 links | 48 | 24 |
| 24 links | 96 | 48 |
A 24-port automotive switch saves 48 connector pins, and in a sealed, vibration-qualified, fifteen-year connector a pin is an expensive object. Add the shield termination 100BASE-TX would have needed and the difference widens further — a shielded connector needs a 360-degree bond, which is a mechanical requirement rather than an electrical one.
Constraint three — temperature and life, which changes almost nothing in the digital design and a great deal in the analog.
| Data centre | Automotive | |
|---|---|---|
| ambient | 0 to +70 °C | −40 to +125 °C — a 165 °C span |
| service life | three-year refresh | fifteen years |
| repair | swap the module | a workshop visit, at cost |
| clock accuracy required | ±100 ppm | ±100 ppm — unchanged |
Row four is the interesting one because it does not move. Chapter 4.4 §2 fixed the clock budget at ±100 ppm per end, 200 ppm between ends, and that figure is in IEEE 802.3 rather than in a channel specification — so an automotive PHY has exactly the same elastic-buffer sizing problem as a data-centre one, and Chapter 4.4 §3's result that a maximum frame accumulates about 0.3 of an octet at 200 ppm holds unchanged in a car.
What does move is how hard ±100 ppm is to hold. An oscillator that must stay inside ±100 ppm across 165 °C and fifteen years of ageing has a far smaller budget for each contribution than one that lives in a rack at a controlled temperature. That is a component-selection problem rather than an RTL problem, and it is the reason automotive PHY datasheets specify a crystal far more tightly than the MAC beside them needs.
3. RTL 1 — The Single-Pair PHY Package
// ---------------------------------------------------------------------
// t1phy_pkg -- the constants of a single-pair automotive link, derived
// rather than quoted.
//
// Everything here follows from three numbers: the data rate, the bits
// a ternary symbol pair can carry, and the length of the cable. The
// rest of the chapter is those three numbers having consequences.
// ---------------------------------------------------------------------
package t1phy_pkg;
// ---- 100BASE-T1 -----------------------------------------------------
// 3 binary bits map to 2 ternary symbols: 2^3 = 8 <= 3^2 = 9.
localparam int BITS_PER_GROUP = 3;
localparam int SYMS_PER_GROUP = 2;
// 1.5 bits per symbol, so 100 Mb/s needs 66.67 MBd.
localparam int RATE_MBPS_100 = 100;
localparam int BAUD_KBD_100 = 66_667; // thousands of symbols/s
localparam int NYQUIST_KHZ_100 = 33_333;
// ---- 1000BASE-T1 ----------------------------------------------------
// The same 1.5 bits per symbol at 750 MBd gives 1125 Mb/s raw, and
// the coding must give back 1000/1125 = 88.9%.
localparam int RATE_MBPS_1000 = 1000;
localparam int BAUD_KBD_1000 = 750_000;
localparam int RAW_MBPS_1000 = 1125;
localparam int NYQUIST_KHZ_1000 = 375_000;
// ---- the cable ------------------------------------------------------
// A link segment is short by design, and the echo's delay spread is
// a cable length rather than a design choice. 15 m at 0.66c is
// 75.8 ns one way.
localparam int SEGMENT_M = 15;
localparam int ONE_WAY_NS_X10 = 758; // tenths of a nanosecond
// ---- what a ternary symbol is ---------------------------------------
typedef enum logic [1:0] {
PAM3_NEG = 2'b00,
PAM3_ZER = 2'b01,
PAM3_POS = 2'b10,
PAM3_RSV = 2'b11 // the fourth code is not a level
} pam3_e;
// 3B2T: index by the 3 data bits, get two ternary symbols. Nine
// pairs exist and eight are used -- the ninth is available for
// control, which Section 5 is about.
localparam logic [3:0] MAP_3B2T [8] = '{
{PAM3_NEG, PAM3_NEG}, // 000
{PAM3_NEG, PAM3_ZER}, // 001
{PAM3_NEG, PAM3_POS}, // 010
{PAM3_ZER, PAM3_NEG}, // 011
{PAM3_ZER, PAM3_ZER}, // 100
{PAM3_ZER, PAM3_POS}, // 101
{PAM3_POS, PAM3_NEG}, // 110
{PAM3_POS, PAM3_ZER} // 111
};
// The unused pair, reserved for signalling rather than data.
localparam logic [3:0] PAIR_UNUSED = {PAM3_POS, PAM3_POS};
// ---- the role, which is configured and not negotiated ---------------
typedef enum logic {
ROLE_SLAVE = 1'b0,
ROLE_MASTER = 1'b1
} t1_role_e;
// Echo canceller sizing: the tap count must span the round trip.
function automatic int echo_taps(int baud_kbd, int one_way_ns_x10);
// symbols in one way = baud [kSym/s] * ns/10 * 1e-... written out
// as an integer identity: taps = 2 * baud_kbd * ns_x10 / 10_000_000
return (2 * baud_kbd * one_way_ns_x10) / 10_000_000;
endfunction
endpackageClassification: a constants package in which every constant is a consequence of three inputs.
What it teaches: that BITS_PER_GROUP and SYMS_PER_GROUP are the whole rate story. Three bits into two ternary symbols is 1.5 bits per symbol, so 100 Mb/s needs 66.67 MBd and nothing else needs choosing. Chapter 9.2 §2's MLT-3 gets one bit per symbol at 125 MBd for the same 100 Mb/s — so single-pair Ethernet's entire spectral advantage comes from a code, not from a channel.
And it teaches that PAIR_UNUSED exists. Nine ternary pairs, eight needed: one code is left over, and a code that never appears in data is a code that can carry something other than data. Chapter 3.5 §6's argument about 4B/5B's spare codewords is exactly this, one alphabet down — and Section 5 is what it is spent on.
Deliberately simplified: MAP_3B2T is an arbitrary assignment of eight of the nine pairs; a real mapping is chosen for DC balance and transition density, which Chapter 3.5 §3 established as the two things a line code must buy. pam3_e uses two bits for three levels, so a quarter of the encoding is PAM3_RSV and must never be driven. echo_taps assumes the echo's energy is confined to the round-trip window, which ignores multiple reflections between connectors — and an automotive link segment is allowed four inline connectors, each of which is a reflector.
Production implication: the four-connector allowance is what makes the echo canceller's sizing a real engineering question rather than the one-line calculation above. Each connector reflects, and a reflection between two connectors near the far end arrives at the near end after a round trip of its own — so the impulse response has energy well beyond the cable's single round trip. Size the tap bank against the worst-case topology the specification allows, not against the cable length, and provide a way to measure the residual, because a canceller that is a few taps short converges to a stable, wrong answer rather than failing.
// ---------------------------------------------------------------------
// pam3_slicer -- three levels, two thresholds, and one output nobody
// expects to need: the residual.
//
// The residual is the difference between the sample and the level the
// slicer chose. It is the adaptation error for everything downstream,
// and Section 20's rejected property is about what it does NOT tell
// you.
// ---------------------------------------------------------------------
module pam3_slicer
import t1phy_pkg::*;
#(
parameter int W = 12, // sample width, signed
parameter int THRESH = 340 // half-way between levels
)(
input logic clk,
input logic rst_n,
input logic s_valid,
input logic signed [W-1:0] sample,
output pam3_e level,
output logic signed [W-1:0] residual,
output logic near_threshold,
output logic [31:0] c_symbols,
output logic [31:0] c_near_threshold
);
pam3_e lvl_c;
logic signed [W-1:0] res_c;
always_comb begin
if (sample > THRESH) lvl_c = PAM3_POS;
else if (sample < -THRESH) lvl_c = PAM3_NEG;
else lvl_c = PAM3_ZER;
case (lvl_c)
PAM3_POS: res_c = sample - (2*THRESH);
PAM3_NEG: res_c = sample + (2*THRESH);
default: res_c = sample;
endcase
end
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
level <= PAM3_ZER; residual <= '0; near_threshold <= 1'b0;
c_symbols <= '0; c_near_threshold <= '0;
end else if (s_valid) begin
level <= lvl_c;
residual <= res_c;
// A sample within a tenth of a threshold is a symbol that nearly
// sliced the other way. Chapter 3.7 Section 15's slope, one
// layer down: the count rises long before an error occurs.
near_threshold <= ((res_c > (THRESH/10)) || (res_c < -(THRESH/10)));
c_symbols <= c_symbols + 32'd1;
if ((res_c > (THRESH/10)) || (res_c < -(THRESH/10)))
c_near_threshold <= c_near_threshold + 32'd1;
end
end
endmoduleClassification: a three-level decision device whose second output is the one worth wiring.
What it teaches: that c_near_threshold is the single-pair equivalent of Chapter 3.7 §10's pre-correction count, and for exactly the same reason. A link whose residuals are creeping toward the threshold is still delivering perfect symbols, so every counter above it reads zero; the margin is visible only here. Chapter 21.9 §17 made the general version of this point — a capture sees the PHY's output and never its margin — and this counter is the margin, at the cheapest possible place to take it.
And it teaches that residual is the input every adaptive block downstream needs. The echo canceller of Section 7, the equaliser, and the timing recovery loop all adapt on the slicer error, so a slicer that discards it forces each of them to recompute it.
Deliberately simplified: THRESH is a constant where a real slicer's levels are adapted, because the channel's gain is unknown and varies with temperature over the 165 °C range of Section 2. The residual is computed against nominal levels rather than adapted ones, so a gain error appears as a residual on every symbol rather than as a gain error. And PAM3_RSV is unreachable here, which is correct for a slicer and means the pam3_e encoding wastes a quarter of its space.
Production implication: adapting the levels rather than fixing them is not optional in a car, and the reason is the temperature span rather than the cable. A 165 °C ambient range moves the line driver's output amplitude, the cable's attenuation and the receiver's front-end gain, and their product is what the slicer sees. A fixed threshold that is correct at 25 °C is wrong at both ends of the range, and the failure mode is a slowly rising near-threshold count followed by symbol errors on a cold morning — which is Chapter 21.4 §12's intermittent class, with a cause that is fully explicable and completely invisible to every counter above the PHY.
4. One Pair, Both Directions: The Arithmetic
Derive the rate from the code rather than quoting the standard, because the derivation is short and it explains the whole physical layer.
Step 1 — how much a ternary symbol can carry.
log₂(3) = 1.585 bits per symbol
Step 2 — how much 3B2T actually takes. Three bits need 8 distinct patterns; two ternary symbols offer 9.
3 bits ÷ 2 symbols = 1.5 bits per symbol
Step 3 — the efficiency of that choice.
| Value | |
|---|---|
| states used | 8 of 9 — 88.9% |
| information efficiency | 1.5 ÷ 1.585 = 94.6% |
| spare capacity | 0.085 bits per symbol |
Step 4 — and the symbol rate falls out.
100 Mb/s ÷ 1.5 bits/symbol = 66.67 MBd
Nyquist = 66.67 ÷ 2 = 33.33 MHz
Now put that beside Chapter 9.2's MLT-3, which carries the same 100 Mb/s.
| 100BASE-TX | 100BASE-T1 | |
|---|---|---|
| line code | 4B/5B then MLT-3 | scrambling then 3B2T |
| symbol rate | 125 MBd | 66.67 MBd |
| bits per symbol | 1 | 1.5 |
| levels | 3 | 3 |
| fundamental / Nyquist | 31.25 MHz | 33.33 MHz |
| occupied bandwidth | to 125 MHz | to 33.33 MHz |
| pairs | 2 | 1 |
Row three against row four is the result. Both codes use three levels; one gets a bit per symbol from them and the other gets one and a half. MLT-3 spends its third level on transition density — it cycles through the levels so a long run of ones still produces transitions, which Chapter 3.5 §4 identified as a line code's second job. 3B2T gets the transitions from the scrambler instead and spends all three levels on data.
The single-pair PHY's rate advantage is a code that does not pay for its own clock recovery. The scrambler pays, and the scrambler is free.
Step 5 — and then both directions go on the one pair, which is the price.
| Consequence | |
|---|---|
| the receiver hears its own transmitter | at a level far above the partner's |
| the hybrid gives partial separation | 20 to 30 dB, not enough |
| the rest is digital cancellation | Section 7 |
| the canceller's input is known exactly | it is our own transmitted symbol stream |
Row four is the one piece of good news in the arrangement and it is decisive. An echo canceller is an adaptive filter, and its reference input is not a noisy estimate — it is the exact ternary sequence the transmitter just sent, two bits per symbol, available without error. Chapter 9.3 §6's adaptive loop had the same advantage on four pairs; here it is the only thing that makes one pair possible at all.
5. RTL 2 — The 3B2T Mapper and Its Ninth Code
// ---------------------------------------------------------------------
// ternary_mapper_3b2t -- three bits in, two ternary symbols out, and
// one code left over.
//
// Chapter 3.5 Section 6 made the same observation one alphabet up: 4B/5B
// needs 16 of 32 codewords and spends the other 16 on control. Here
// the surplus is one pair out of nine, which is 11.1% of the alphabet
// and 5.4% of its information capacity.
// ---------------------------------------------------------------------
module ternary_mapper_3b2t
import t1phy_pkg::*;
(
input logic clk,
input logic rst_n,
input logic d_valid,
input logic [2:0] d_bits, // scrambled data
input logic send_control, // use the ninth code instead
output logic s_valid,
output pam3_e sym_a,
output pam3_e sym_b,
output logic control_sent,
output logic [31:0] c_groups,
output logic [31:0] c_control,
output logic signed [31:0] running_disparity
);
logic [3:0] pair_c;
always_comb begin
pair_c = send_control ? PAIR_UNUSED : MAP_3B2T[d_bits];
end
function automatic int signed lvl_weight(pam3_e s);
case (s)
PAM3_POS: return 1;
PAM3_NEG: return -1;
default: return 0;
endcase
endfunction
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
s_valid <= 1'b0; control_sent <= 1'b0;
c_groups <= '0; c_control <= '0; running_disparity <= '0;
sym_a <= PAM3_ZER; sym_b <= PAM3_ZER;
end else begin
s_valid <= d_valid;
control_sent <= d_valid && send_control;
if (d_valid) begin
sym_a <= pam3_e'(pair_c[3:2]);
sym_b <= pam3_e'(pair_c[1:0]);
c_groups <= c_groups + 32'd1;
if (send_control) c_control <= c_control + 32'd1;
// Chapter 3.5 Section 3's first job of a line code. The mapping
// here does NOT balance -- the scrambler does -- so this
// counter is a monitor rather than a control.
running_disparity <= running_disparity
+ lvl_weight(pam3_e'(pair_c[3:2]))
+ lvl_weight(pam3_e'(pair_c[1:0]));
end
end
end
endmoduleClassification: a lookup table, a spare code, and a disparity accumulator that observes rather than corrects.
What it teaches: that running_disparity is a monitor here where in 8B/10B it was a control. Chapter 3.5 §3 established DC balance as one of a line code's two jobs; 8B/10B bought it by choosing between two codewords per byte, at 25% overhead. 3B2T buys nothing — it is a fixed table — so the balance has to come from the scrambler, and the accumulator exists to prove the scrambler is doing it.
And it teaches what PAIR_UNUSED is for. One code in nine that never carries data is a symbol the receiver can detect unambiguously in the data stream, without an escape mechanism and without a framing layer. Chapter 3.5 §6's 4B/5B had sixteen such codes and spent them on idle, start and error; here there is exactly one, and it is worth far more than its information content because it is the only in-band signalling the physical layer has.
Deliberately simplified: the mapping table is arbitrary, where a real one is selected to minimise low-frequency content and to keep the two symbols of a pair from being identical too often. running_disparity is a 32-bit signed accumulator with no bound check, which over fifteen years at 33.3 million groups per second is exactly Chapter 19.5 §19's rejected class 85 — a bound whose time-to-violation exceeds any simulation. And send_control is an input, so the decision about when to spend the ninth code lives somewhere else.
Production implication: the disparity monitor is worth keeping in silicon even though it controls nothing, and the reason is that it is the only cheap test of the scrambler. A scrambler stuck in a degenerate state — seeded wrong, or with a stuck bit in its shift register — produces a data stream that still decodes, still passes the check sequence, and has a growing DC component, which is the one thing the transformer-coupled front end cannot pass. The symptom is a link that comes up and then loses lock, the disparity accumulator names the cause in one read, and without it the fault presents as a channel problem.
6. What the Spare Code Buys, and Why the Scrambler Is Load-Bearing
Two consequences of Section 4's arithmetic, and both are larger than they look.
First, the spare code. Nine ternary pairs exist; eight carry data.
| Value | |
|---|---|
| codes in the alphabet | 9 |
| used for data | 8 |
| spare | 1 — 11.1% of the alphabet |
| in information terms | log₂(9) − log₂(8) = 0.170 bits per pair — 0.085 per symbol, 5.4% |
That one code is the physical layer's entire in-band vocabulary. Chapter 3.5 §6's 4B/5B had a comfortable surplus — sixteen spare codewords out of thirty-two — and spent them on idle, start-of-stream, end-of-stream and error. Single-pair Ethernet has one, so every one of those functions has to be built from sequences of the spare code rather than from distinct codes, which is a slower and more fragile signalling channel and is the direct consequence of choosing a denser data code.
A code that wastes 11% of its alphabet is a code with one spare symbol. The 4B/5B that wasted 50% of its alphabet could afford four distinct control codes. Density is paid for in vocabulary.
Second, the scrambler, which is now doing two jobs that used to be separate.
| Job | In 100BASE-TX | In 100BASE-T1 |
|---|---|---|
| transition density for clock recovery | MLT-3's level cycling plus 4B/5B's run limit | the scrambler alone |
| DC balance | 4B/5B's codeword selection | the scrambler alone |
| spectral flattening (emissions) | partly the code | the scrambler alone |
All three columns collapse into one mechanism, and that mechanism is a shift register with a feedback polynomial and no knowledge of what it is protecting. Chapter 3.5 §9 made the general form of the argument — a statistical guarantee replacing a structural one — and this is the most concentrated example in the track, because a single scrambler now underwrites clock recovery, DC balance and electromagnetic emissions.
Which makes the scrambler's failure modes worth enumerating, because they are not the ones people expect.
| Failure | Symptom | Who notices |
|---|---|---|
| seeded identically at both ends by accident | transmit and echo correlate; the canceller misbehaves | the echo canceller's residual |
| stuck in an all-zero state | no transitions; clock recovery loses lock | the PHY, immediately |
| a short cycle in the polynomial | a periodic spectrum — a tone | the emissions test, in a chamber |
| correct but with a long run by chance | a brief DC excursion | nothing — and it is fine |
Row three is the one that is found in a test chamber and not in a lab. A scrambler with an unintended short cycle produces a repeating pattern, a repeating pattern has line spectra rather than a flat noise floor, and a line spectrum at a few tens of megahertz is exactly what an automotive emissions limit is written to catch. The design passes every functional test, links reliably, carries traffic correctly, and fails qualification — which is the most expensive place in this chapter's world to find a defect.
Row one is the subtlest and it belongs to this chapter specifically. On a two-pair link the transmit and receive scramblers are independent and nothing correlates them. On one pair the transmitted signal is present at the receiver, so if the two ends happen to run correlated sequences, the echo and the far-end signal become statistically similar — and an adaptive canceller whose reference correlates with the signal it is trying to preserve cancels some of the signal. Section 20's rejected property is the formal version of that sentence.
7. RTL 3 — The Echo Canceller's Tap Bank
// ---------------------------------------------------------------------
// echo_canceller_bank -- subtract our own transmission from what the
// receiver hears.
//
// The reference input is EXACT: it is the ternary symbol stream this
// PHY just transmitted, two bits per symbol, with no noise. That is
// what makes one-pair operation possible at all, and Chapter 9.3
// Section 6's adaptive loop had the same advantage on four pairs.
//
// What the block cannot do is tell a poorly converged canceller from
// a noisy partner. Section 20 is about that.
// ---------------------------------------------------------------------
module echo_canceller_bank
import t1phy_pkg::*;
#(
parameter int TAPS = 32, // 100BASE-T1; 1000BASE-T1 needs ~192
parameter int COEFF_W = 16,
parameter int SAMP_W = 12,
parameter int MU_SHIFT= 12 // adaptation step, as a right shift
)(
input logic clk,
input logic rst_n,
input logic adapt_en,
input logic tx_sym_valid,
input pam3_e tx_sym, // OUR symbol, exact
input logic rx_valid,
input logic signed [SAMP_W-1:0] rx_sample, // partner + echo + noise
input logic signed [SAMP_W-1:0] slicer_error, // from pam3_slicer
output logic signed [SAMP_W-1:0] rx_clean,
output logic converged,
output logic [31:0] c_updates,
output logic signed [31:0] residual_energy,
output logic coeff_saturated,
output logic tail_energy_high // taps are short
);
logic signed [COEFF_W-1:0] coeff [TAPS];
logic signed [1:0] hist [TAPS]; // -1, 0, +1
localparam logic signed [COEFF_W-1:0] COEFF_MAX = (1 <<< (COEFF_W-1)) - 1;
localparam logic signed [COEFF_W-1:0] COEFF_MIN = -(1 <<< (COEFF_W-1));
function automatic logic signed [1:0] w(pam3_e s);
case (s)
PAM3_POS: return 2'sd1;
PAM3_NEG: return -2'sd1;
default: return 2'sd0;
endcase
endfunction
// The estimate: sum of coefficient times our own past symbol. Because
// the symbol is -1, 0 or +1, every multiply is an add, a subtract or
// nothing -- which is why a tap costs a register and not a
// multiplier.
logic signed [SAMP_W+COEFF_W-1:0] est;
always_comb begin
est = '0;
for (int i = 0; i < TAPS; i++) begin
if (hist[i] == 2'sd1) est = est + coeff[i];
else if (hist[i] == -2'sd1) est = est - coeff[i];
end
end
assign rx_clean = rx_sample - est[SAMP_W-1:0];
// The last eighth of the tap bank should hold near-zero energy. If it
// does not, the impulse response is longer than the bank and the
// canceller has converged to a stable WRONG answer.
logic signed [31:0] tail_acc;
always_comb begin
tail_acc = '0;
for (int i = TAPS - (TAPS/8); i < TAPS; i++)
tail_acc = tail_acc + ((coeff[i] < 0) ? -coeff[i] : coeff[i]);
end
assign tail_energy_high = (tail_acc > (COEFF_MAX >>> 4));
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
c_updates <= '0; residual_energy <= '0; converged <= 1'b0;
coeff_saturated <= 1'b0;
for (int i = 0; i < TAPS; i++) begin
coeff[i] <= '0; hist[i] <= 2'sd0;
end
end else begin
if (tx_sym_valid) begin
for (int i = TAPS-1; i > 0; i--) hist[i] <= hist[i-1];
hist[0] <= w(tx_sym);
end
if (rx_valid && adapt_en) begin
c_updates <= c_updates + 32'd1;
coeff_saturated <= 1'b0;
for (int i = 0; i < TAPS; i++) begin
automatic logic signed [COEFF_W-1:0] upd;
// sign-sign LMS: the gradient is error times reference, and
// the reference is -1, 0 or +1.
if (hist[i] == 2'sd0) upd = coeff[i];
else if ((hist[i] == 2'sd1) == (slicer_error >= 0))
upd = coeff[i] + (1 <<< 0);
else upd = coeff[i] - (1 <<< 0);
if (upd > COEFF_MAX) begin
coeff[i] <= COEFF_MAX; coeff_saturated <= 1'b1;
end else if (upd < COEFF_MIN) begin
coeff[i] <= COEFF_MIN; coeff_saturated <= 1'b1;
end else begin
coeff[i] <= upd;
end
end
residual_energy <= (slicer_error < 0) ? -32'(slicer_error)
: 32'(slicer_error);
converged <= (residual_energy < 32'(COEFF_MAX >>> MU_SHIFT));
end
end
end
endmoduleClassification: a sign-sign LMS adaptive filter whose reference is exact and whose failure mode is silent convergence.
What it teaches: that a ternary reference makes every multiply an add. The history register holds our own transmitted symbols, which are −1, 0 or +1, so the filter's inner product is a sum of conditionally negated coefficients — no multiplier anywhere. That is why a tap costs about eighteen flip-flops and not a DSP slice, and it is the reason this filter is affordable at 192 taps in a part that also has to be cheap enough to put twenty of on a vehicle.
And it teaches that tail_energy_high is the output that catches the design error. A canceller whose bank is shorter than the channel's impulse response does not diverge and does not oscillate — it converges, stably, to the best filter of that length, and leaves the rest of the echo in the signal as what looks exactly like additive noise. The only evidence is that the last taps are not near zero, because the filter has pushed energy to the end of the bank trying to reach what lies beyond it.
Deliberately simplified: the update is ± 1 per tap per sample rather than a scaled gradient, so MU_SHIFT names a step size the code does not actually use. The whole bank updates every sample, which at 192 taps and 750 MBd is not implementable and would be done in stages. converged compares a single-sample residual against a threshold where a real detector needs an averaged energy over thousands of samples. And hist shifts on tx_sym_valid while the update runs on rx_valid, with no alignment between them — the real relative delay is the hybrid's, and it must be calibrated.
Production implication: the short-bank failure is the one to design the telemetry for, because it is indistinguishable from a bad cable in every measurement above the PHY. The residual looks like noise, the noise raises the symbol error rate, the FEC or the check sequence catches it, and the counters report a channel problem — so the vehicle is diagnosed by replacing a harness, which is expensive, takes a workshop visit, and does not fix it. tail_energy_high costs a handful of adders and one comparison and is the difference between that and a one-register answer. Expose it through MDIO — Chapter 4.5 §5's Clause 45 address space has room — and read it in the field.
8. The Echo's Delay Spread Is a Cable Length
The tap count is not a design parameter. It is the cable, converted into symbols.
The derivation is three lines.
propagation velocity ≈ 0.66 c = 1.98 × 10⁸ m/s
15 m one way = 75.8 ns
taps needed = 2 × 75.8 ns × symbol rate
| Link | Segment | One way | Round trip, in symbols |
|---|---|---|---|
| 100BASE-T1 at 66.67 MBd | 15 m | 75.8 ns | 10.1 |
| 1000BASE-T1 at 750 MBd | 15 m | 75.8 ns | 113.6 |
| 1000BASE-T at 125 MBd, for comparison | 100 m | 505 ns | 126.3 |
Row two against row three is the chapter's most compact result. A fifteen-metre gigabit automotive link and a hundred-metre gigabit office link need almost the same echo canceller — 114 symbols against 126 — because the automotive link trades a factor of 6.7 in length for a factor of 6 in symbol rate. The two nearly cancel.
Shortening the cable did not make the canceller smaller. It made the symbol rate affordable, and the canceller stayed the same size.
And the single reflection above is a floor rather than an answer.
| Reflector | Contributes |
|---|---|
| the near-end hybrid's imperfect balance | energy at tap 0 — the largest term |
| the far-end termination | energy at the round trip — 10.1 or 113.6 taps out |
| each inline connector | its own round trip, and a re-reflection with the others |
| a harness splice | the same, at an undocumented position |
An automotive link segment permits up to four inline connectors, which is the specification acknowledging that a car's harness is assembled in sections. Four reflectors give six pairwise round trips in addition to the four direct ones, and the last of them arrives after the longest inter-connector distance's round trip. So the bank must be sized against the topology, with margin, which is why a real 100BASE-T1 canceller is 32 or 64 taps rather than the 11 the cable alone demands.
The cost, in the unit this track prices everything in.
| Canceller | Taps | Flops | Against Chapter 19.7 §19's 14 166 |
|---|---|---|---|
| 100BASE-T1, 32 taps | 32 | 576 | 4.1% |
| 100BASE-T1, 64 taps | 64 | 1 152 | 8.1% |
| 1000BASE-T1, 192 taps | 192 | 3 456 | 24.4% |
A gigabit single-pair echo canceller is a quarter of a MAC receive datapath, and it sits in the PHY, on a different budget, in a part whose whole reason for existing is to be cheap. That is the real price of putting both directions on one pair, and it is paid once per port, twenty or more times per vehicle.
One number for scale. Chapter 19.4 §19's correction barrels were 5 397 XOR terms; the gigabit canceller is 3 456 flops plus 192 conditional adds. They are the same order of magnitude, and both are dominated by a structure that exists because a physical layer made a choice — FEC's, and the single pair's.
9. RTL 4 — Master and Slave, Decided by Configuration
// ---------------------------------------------------------------------
// master_slave_role -- on a single-pair link the two ends cannot both
// own the clock, and nothing on the wire decides which one does.
//
// Chapter 9.3 Section 4 met this on four pairs and resolved it inside
// auto-negotiation's exchange. 100BASE-T1 has no auto-negotiation, so
// the role is a strap, a register, or a line in a build file -- and a
// wrong one produces no link rather than a degraded one.
// ---------------------------------------------------------------------
module master_slave_role
import t1phy_pkg::*;
(
input logic clk,
input logic rst_n,
input t1_role_e cfg_role, // from a strap or a register
input logic cfg_valid,
input logic partner_energy, // the far end is transmitting
input logic local_lock, // our receiver has symbol lock
input logic partner_lock_seen, // the far end reports lock, in-band
output t1_role_e role,
output logic drives_clock,
output logic recovers_clock,
output logic link_up,
output logic role_conflict_suspected,
output logic [31:0] c_bringup_attempts,
output logic [31:0] c_no_lock_with_energy
);
assign role = cfg_role;
assign drives_clock = (cfg_role == ROLE_MASTER);
assign recovers_clock = (cfg_role == ROLE_SLAVE);
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
link_up <= 1'b0; role_conflict_suspected <= 1'b0;
c_bringup_attempts <= '0; c_no_lock_with_energy <= '0;
end else begin
if (cfg_valid && !link_up)
c_bringup_attempts <= c_bringup_attempts + 32'd1;
link_up <= cfg_valid && local_lock && partner_lock_seen;
// The ONLY evidence a role is mis-set: the partner is clearly
// transmitting and we never achieve lock. Two masters both drive
// a clock and neither recovers one; two slaves drive nothing.
// Note the asymmetry -- the two-slave case has NO energy at all,
// so this detector cannot see it.
if (partner_energy && !local_lock)
c_no_lock_with_energy <= c_no_lock_with_energy + 32'd1;
role_conflict_suspected <= (c_no_lock_with_energy > 32'd1000);
end
end
endmoduleClassification: a role register, a link-up gate, and one heuristic that can only see half the fault it is looking for.
What it teaches: that the two role errors are not symmetric and only one of them leaves evidence. Two masters both drive the clock, so both ends see energy and neither achieves lock — c_no_lock_with_energy climbs and names the fault. Two slaves both recover, so neither transmits, and both ends see an idle line — which is identical to a broken cable, an unpowered partner, and a partner that has not booted. Chapter 21.4's dark class, arrived at by configuration rather than by hardware.
And it teaches what was traded away. Chapter 9.2 §4's FLP burst discovers the partner's capabilities, including which end will be master on a link that supports both; 100BASE-T1 removes the discovery and keeps the requirement. The requirement did not go away — a single-pair link still needs exactly one clock owner — it moved from the wire into the build.
Deliberately simplified: role is combinational from cfg_role with no way to change it after link-up, which is correct; a real PHY allows a register write and then needs a defined restart. partner_lock_seen is an input that has to come from the in-band signalling Section 6's spare code provides, and the block does not say how. The 1 000-sample threshold for role_conflict_suspected is arbitrary. And there is no timeout: a link that never comes up increments c_bringup_attempts forever rather than escalating.
Production implication: the two-slave case being invisible is the fault to build the system around, because it will happen — an ECU replaced under warranty with a part whose strap resistor is fitted for the other side of the link produces exactly it. The countermeasure is not in the PHY; it is that every node's configured role is readable over the vehicle's diagnostic bus, so a workshop can compare the two ends without an oscilloscope. A PHY register that reports the role costs one bit and converts a dark fault into a two-minute check — and a design that does not expose it converts the same fault into a harness replacement.
10. What Automotive Deleted: Auto-Negotiation, and What Replaced It
100BASE-T1 has no auto-negotiation. That deletion removes a whole chapter of Module 21 and adds a smaller one.
What Chapter 9.2 §4's mechanism did, and whether a car needed it.
| Auto-negotiation resolved | Does a car need it? |
|---|---|
| speed — 10, 100 or 1000 | no — the link's rate is a design decision made years earlier |
| duplex — half or full | no — half duplex does not exist here |
| which end is master | yes, and it is configured instead |
| flow-control capability | rarely — the topology is known |
| backward compatibility with a non-negotiating partner | no — every partner is specified |
Four of five rows are "no", and the reason is the same in each case: a vehicle's network is engineered, not discovered. Every node, every rate and every topology is fixed at design time and does not change in the field. Auto-negotiation solves the problem of an unknown partner, and a car does not have one.
And the fault classes move accordingly.
| Fault | Enterprise Ethernet | Automotive single-pair |
|---|---|---|
| duplex mismatch | Chapter 21.5's whole chapter | cannot occur — no half duplex |
| speed mismatch | no link, or a slow link | cannot occur — rate is fixed |
| negotiation that fails to complete | Chapter 21.4 §8's class | cannot occur |
| role mis-set, two masters | — | no link, with energy — detectable |
| role mis-set, two slaves | — | no link, no energy — dark |
| polarity or pair swap | auto-MDI-X corrects it | the PHY must tolerate polarity inversion |
Rows one to three vanish and rows four to six appear, and the trade is strongly favourable. Chapter 21.5 §1 priced a duplex mismatch as a fault that links, passes traffic, and loses 37.69% of maximum-size frames at 50% offered load while losing exactly zero minimum-size ones — a fault that ping cannot find and that takes a two-ended counter comparison to attribute.
The automotive replacement is a link that does not come up.
A fault that produces no link is diagnosable in minutes. A fault that produces a working link with a size-dependent loss rate cost Module 21 an entire chapter.
That said, one of the two new faults is genuinely worse than it looks, and it is row five. Two slaves is silent at both ends, which means it presents identically to Chapter 21.4's dark class — a link that is down for one of fourteen reasons, none of which produces a frame. Section 9's remedy is the only one available: make the configured role readable, so the comparison that resolves it needs a diagnostic session rather than an instrument.
And one thing that did not move at all.
| Value | |
|---|---|
| clock accuracy, per end | ±100 ppm — Chapter 4.4 §2 |
| worst-case difference | 200 ppm |
| accumulation over a 1 518-octet frame | about 0.3 of an octet |
| who discharges it | the interframe gap, as always |
The elastic buffer's sizing argument is rate-independent and channel-independent, so Chapter 4.4 §10's two-part depth calculation transfers into an automotive PHY unchanged. It is worth saying explicitly because almost nothing else in this chapter does — and it is the clearest evidence for Chapter 4.1 §3's split having been drawn in the right place.
11. RTL 5 — Link Bring-Up Without Negotiation
// ---------------------------------------------------------------------
// t1_link_bringup -- a state machine with no exchange of capabilities,
// because there is nothing to exchange.
//
// Chapter 9.2 Section 5's FLP burst carried a capability page and
// resolved a negotiation. This machine carries nothing: the master
// transmits, the slave locks to it, and the only signalling is the
// ninth ternary code of Section 6.
// ---------------------------------------------------------------------
module t1_link_bringup
import t1phy_pkg::*;
#(
parameter int LOCK_SYMBOLS = 100_000, // ~1.5 ms at 66.67 MBd
parameter int TRAIN_SYMBOLS = 2_000_000, // canceller convergence
parameter int RETRY_LIMIT = 8
)(
input logic clk,
input logic rst_n,
input t1_role_e role,
input logic symbol_lock,
input logic canceller_converged,
input logic control_code_seen, // the spare pair, in-band
input logic partner_energy,
output logic tx_enable,
output logic adapt_enable,
output logic send_control,
output logic link_up,
output logic training_timeout,
output logic gave_up,
output logic [2:0] state_q,
output logic [31:0] c_retries,
output logic [31:0] c_time_to_link_symbols
);
typedef enum logic [2:0] {
S_RESET = 3'd0,
S_SILENT = 3'd1, // slave: listen; master: skipped
S_SEND = 3'd2, // master: transmit, unconditionally
S_LOCK = 3'd3, // acquire symbol timing
S_TRAIN = 3'd4, // converge the echo canceller
S_UP = 3'd5,
S_FAILED = 3'd6
} st_e;
st_e st;
logic [31:0] ctr;
assign state_q = st;
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
st <= S_RESET; ctr <= '0; c_retries <= '0;
c_time_to_link_symbols <= '0; gave_up <= 1'b0;
training_timeout <= 1'b0;
end else begin
training_timeout <= 1'b0;
if (st != S_UP && st != S_FAILED)
c_time_to_link_symbols <= c_time_to_link_symbols + 32'd1;
case (st)
S_RESET: begin
ctr <= '0;
// The master's asymmetry is the whole protocol: it transmits
// whether or not anyone is there.
st <= (role == ROLE_MASTER) ? S_SEND : S_SILENT;
end
S_SILENT: begin
// A slave with no partner energy waits forever. This is the
// two-slave case of Section 9, and it is indistinguishable
// from an unplugged cable.
if (partner_energy) st <= S_LOCK;
end
S_SEND: begin
st <= S_LOCK;
end
S_LOCK: begin
ctr <= ctr + 32'd1;
if (symbol_lock) begin
ctr <= '0; st <= S_TRAIN;
end else if (ctr > LOCK_SYMBOLS) begin
ctr <= '0;
if (c_retries >= RETRY_LIMIT) begin
st <= S_FAILED;
end else begin
c_retries <= c_retries + 32'd1;
st <= S_RESET;
end
end
end
S_TRAIN: begin
ctr <= ctr + 32'd1;
if (canceller_converged && control_code_seen) begin
st <= S_UP;
end else if (ctr > TRAIN_SYMBOLS) begin
training_timeout <= 1'b1;
ctr <= '0;
if (c_retries >= RETRY_LIMIT) st <= S_FAILED;
else begin c_retries <= c_retries + 32'd1; st <= S_RESET; end
end
end
S_UP: begin
if (!symbol_lock) begin
ctr <= '0; st <= S_RESET;
end
end
S_FAILED: begin
gave_up <= 1'b1;
end
default: st <= S_RESET;
endcase
end
end
assign tx_enable = (st == S_SEND) || (st == S_LOCK)
|| (st == S_TRAIN) || (st == S_UP)
|| ((role == ROLE_MASTER) && (st != S_RESET));
assign adapt_enable = (st == S_TRAIN) || (st == S_UP);
assign send_control = (st == S_TRAIN);
endmoduleClassification: a seven-state bring-up with an asymmetry between the ends and no capability exchange at all.
What it teaches: that the master's S_SEND transitions unconditionally and that is the protocol. There is no handshake, no partner detection, and no page exchange: the master transmits into a possibly empty cable and the slave locks to whatever it hears. Chapter 9.2 §5's FLP burst was designed to be backward compatible with a partner that does not negotiate, and that compatibility requirement shaped its entire structure. A car has no legacy partner, so the mechanism is a state machine with two roles and one direction of initiative.
And it teaches that c_time_to_link_symbols is a field-diagnostic worth more than it costs. A link that comes up in 2.1 million symbols is healthy; one that comes up in 16 million has retried and is marginal; both report link_up and nothing above the PHY can tell them apart. Chapter 21.4 §14's intermittent class is exactly this — a link that works now and will not next winter — and a bring-up time counter is the cheapest predictor of it available.
Deliberately simplified: LOCK_SYMBOLS and TRAIN_SYMBOLS are single constants where a real machine adapts the training length to how far the canceller has to move. S_UP leaves only on loss of symbol lock, so a canceller that diverges after link-up is not detected. tx_enable's expression overlaps the state decode with a role term, which is redundant and is written that way to make the master's unconditional transmission explicit. And gave_up is terminal with no recovery path, where a vehicle needs a periodic retry — a link that failed at −40 °C on a cold start must come up when the cabin warms.
Production implication: the missing warm-retry is a real automotive bug pattern and it is worth stating concretely. A PHY that gives up permanently after eight attempts, in a node that powers on at −40 °C, will have exhausted its retries before the cable's characteristics settle — and the vehicle then runs the whole drive cycle with a dead link that would have come up ninety seconds later. Make S_FAILED re-enter S_RESET on a slow timer, and count the escapes, because the count is the difference between a marginal design and a warranty claim.
12. 1000BASE-T1, and the Same Arithmetic at Ten Times the Rate
Gigabit single-pair is the same three-line derivation with one number changed, and one mechanism added.
The derivation, unchanged in form.
750 MBd × 1.5 bits/symbol = 1 125 Mb/s raw
1 000 ÷ 1 125 = 88.9% — the coding must give back 11.1%
| Value | |
|---|---|
| symbol rate | 750 MBd |
| bits per symbol | 1.5 — the same 3B2T |
| raw rate | 1 125 Mb/s |
| required coding efficiency | 88.9% |
| Nyquist | 375 MHz |
And the standard's two codes multiply to almost exactly that.
| Code | Rate |
|---|---|
| an RS-FEC of 450 symbols carrying 406 | 0.9022 |
| an 80-bit block in 81 | 0.9877 |
| product | 0.8911 |
| against the required | 0.8889 |
| resulting payload rate | 1 002.5 Mb/s |
The residual 0.25% is the PHY's own idle and alignment accounting — the same kind of slack Chapter 3.5 §13 found in 64B/66B. The point of running the arithmetic rather than quoting it is that the coding budget was not free to choose: 11.1% was the number available, and the design had to fit FEC and block synchronisation inside it.
What is genuinely new at gigabit is that FEC became mandatory.
| 100BASE-T1 | 1000BASE-T1 | |
|---|---|---|
| forward error correction | none | required |
| why | 33.3 MHz on 15 m of cable has margin | 375 MHz does not |
| latency added | none | a codeword's worth |
| Chapter 3.7's argument | not yet binding | binding |
That is Chapter 9.6's transition happening again, two orders of magnitude lower in rate and for the same reason. Chapter 3.7 §2 established that FEC becomes mandatory when the raw error rate the channel delivers exceeds what the application can tolerate; a car's channel is short but it is also unshielded, in a 100 V/m field, at 375 MHz — and the margin that 100BASE-T1 had at 33 MHz is gone.
And it brings Chapter 21.9 §17's warning with it. A 1000BASE-T1 link correcting steadily delivers perfect frames; the margin is visible only in the decoder's pre-correction counts, and every counter above the PHY reads clean. In a vehicle that is worse than in a data centre, because there is no operator watching a dashboard — the only time anyone looks is after a fault, and by then the link has crossed the cliff.
The cost comparison, in this track's unit.
| Mechanism | Flops | Against 14 166 |
|---|---|---|
| 100BASE-T1 canceller, 32 taps | 576 | 4.1% |
| 1000BASE-T1 canceller, 192 taps | 3 456 | 24.4% |
| 1000BASE-T1 RS-FEC decoder, order of | comparable to Chapter 19.4 §19's 5 397 XOR terms | — |
Gigabit single-pair costs roughly six times the digital front end of the hundred-megabit version and adds a decoder, for ten times the rate — which is a good trade and is why the rate transition happened at all.
13. RTL 6 — The Emission Budget Monitor
// ---------------------------------------------------------------------
// emission_budget_monitor -- the digital half of an analog
// requirement.
//
// A PHY cannot measure its own radiated emissions. What it CAN do is
// detect the digital conditions that produce a line spectrum, which is
// what an emissions limit is written to catch: a stuck scrambler, a
// periodic transmit pattern, and a transmit amplitude above nominal.
//
// This is a proxy, and Section 20's rejected property is about the
// difference between a proxy and the thing.
// ---------------------------------------------------------------------
module emission_budget_monitor
import t1phy_pkg::*;
#(
parameter int PERIOD_WINDOW = 4096, // symbols
parameter int AMP_NOMINAL = 680,
parameter int AMP_MARGIN_PCT= 10
)(
input logic clk,
input logic rst_n,
input logic tx_valid,
input pam3_e tx_sym,
input logic signed [15:0] tx_amplitude,
input logic signed [31:0] running_disparity,
input logic scrambler_all_zero,
output logic periodic_suspected,
output logic amplitude_out_of_band,
output logic disparity_drifting,
output logic scrambler_degenerate,
output logic emissions_risk,
output logic [31:0] c_periodic_flags,
output logic [15:0] repeat_period_symbols
);
// A very cheap periodicity test: compare the symbol stream against
// itself delayed by a set of candidate periods. A scrambler doing
// its job makes every comparison fail about two thirds of the time.
localparam int CANDIDATES = 4;
localparam int PERIODS [CANDIDATES] = '{7, 31, 127, 511};
logic [1:0] delay_line [512];
logic [15:0] match_cnt [CANDIDATES];
logic [15:0] window_cnt;
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
window_cnt <= '0; periodic_suspected <= 1'b0;
c_periodic_flags <= '0; repeat_period_symbols <= '0;
for (int i = 0; i < CANDIDATES; i++) match_cnt[i] <= '0;
for (int i = 0; i < 512; i++) delay_line[i] <= 2'b01;
end else if (tx_valid) begin
for (int i = 511; i > 0; i--) delay_line[i] <= delay_line[i-1];
delay_line[0] <= tx_sym[1:0];
for (int i = 0; i < CANDIDATES; i++)
if (delay_line[PERIODS[i]-1] == tx_sym[1:0])
match_cnt[i] <= match_cnt[i] + 16'd1;
window_cnt <= window_cnt + 16'd1;
if (window_cnt == PERIOD_WINDOW-1) begin
periodic_suspected <= 1'b0;
for (int i = 0; i < CANDIDATES; i++) begin
// Chance agreement for a ternary symbol is one in three.
// Two thirds agreement is a repeating pattern.
if (match_cnt[i] > ((2*PERIOD_WINDOW)/3)) begin
periodic_suspected <= 1'b1;
repeat_period_symbols <= 16'(PERIODS[i]);
c_periodic_flags <= c_periodic_flags + 32'd1;
end
match_cnt[i] <= '0;
end
window_cnt <= '0;
end
end
end
always_comb begin
amplitude_out_of_band =
(tx_amplitude > ((AMP_NOMINAL * (100 + AMP_MARGIN_PCT)) / 100)) ||
(tx_amplitude < ((AMP_NOMINAL * (100 - AMP_MARGIN_PCT)) / 100));
disparity_drifting = (running_disparity > 32'sd100000) ||
(running_disparity < -32'sd100000);
scrambler_degenerate = scrambler_all_zero;
emissions_risk = periodic_suspected | amplitude_out_of_band
| disparity_drifting | scrambler_degenerate;
end
endmoduleClassification: a proxy detector — four digital conditions that correlate with an analog failure the block cannot measure.
What it teaches: that the useful emissions checks are all about structure in the transmitted stream, not about power. A scrambled ternary stream has a flat spectrum; a stream with a repeating period has line spectra, and a line at a few tens of megahertz is what an automotive limit is written to catch. The block does not measure a field strength — it measures whether the transmitter has become predictable, which is the digital precondition for the analog failure.
And it teaches the chance-agreement arithmetic that makes the test cheap. Two ternary symbols separated by any period agree one time in three if the stream is random; a period that produces two-thirds agreement over four thousand symbols is not chance. The whole test is a delay line, four comparators and four counters.
Deliberately simplified: the candidate periods are four fixed values chosen to be the lengths of short LFSR cycles, so a repeat at any other period is missed entirely — a real monitor needs an autocorrelation over a range. The 512-entry delay line of 2-bit symbols is 1 024 flops, which is a lot for a monitor and would in practice be a small RAM. AMP_NOMINAL is a constant where the real nominal moves with temperature over Section 2's 165 °C span. And disparity_drifting uses a fixed threshold on an unbounded accumulator, which is again Chapter 19.5 §19's class 85.
Production implication: this monitor exists because of where the failure is found. An emissions defect is found in a test chamber, at a cost of a chamber booking and a build, and the design that failed is functionally perfect — it links, it carries traffic, and every counter reads zero. A monitor that names a periodic transmit pattern at design time, in simulation, from the same stimulus the functional tests already run, converts a chamber failure into a simulation failure, and the price difference between those two is the largest in this chapter.
14. Unshielded Is the Requirement, Not the Saving
The popular account of single-pair Ethernet is that it saves weight. The arithmetic says the weight saving is real and small, and that it was never the binding constraint.
The conductor mass, derived.
24 AWG conductor: diameter 0.511 mm, area 0.205 mm²
copper density 8.96 g/cm³ → 1.84 g per metre per conductor
| 100BASE-TX | 100BASE-T1 | Saving | |
|---|---|---|---|
| conductors | 4 | 2 | 2 |
| copper, g/m | 7.35 | 3.68 | 3.68 |
| over 50 m of link | 0.37 kg | 0.18 kg | 0.18 kg |
| over 100 m | 0.74 kg | 0.37 kg | 0.37 kg |
| over 200 m | 1.47 kg | 0.74 kg | 0.74 kg |
Under a kilogram, on a vehicle that weighs between one and three tonnes. It is not nothing — mass compounds through the suspension and the body structure — but it is not a reason to define a new physical layer either.
The constraint that was binding is in the next table, and it is not a matter of degree.
| Requirement | 100BASE-TX, unshielded | 100BASE-T1, unshielded |
|---|---|---|
| occupied bandwidth | to 125 MHz | to 33.3 MHz |
| overlaps the FM broadcast band (88–108 MHz) | yes | no |
| meets automotive radiated-emission limits | no | yes |
| survives a 100 V/m immunity field | marginal at best | by design |
Row three is a "no", not a "worse". There is no configuration of 100BASE-TX that meets automotive emissions limits without a shield — so the choice was never between two unshielded options. It was between shielded 100BASE-TX and unshielded 100BASE-T1, and once the comparison is framed that way the savings change character.
| Shielded 2-pair | Unshielded 1-pair | |
|---|---|---|
| conductors | 4 | 2 |
| shield | a foil or braid over the whole cable | none |
| connector | shielded, with a 360° bond | a 2-way sealed connector |
| termination | the shield must be bonded at defined points | nothing to bond |
| assembly | a controlled process, inspectable | a crimp |
| failure mode over 15 years | a degraded bond is an intermittent emissions fault | — |
Row six is the cost that does not appear in any bill of materials. A shield whose bond degrades — from vibration, corrosion, or a repair done without the right tooling — stops working as a shield and starts working as an antenna, and the symptom is an intermittent radio interference complaint that no network counter can see. Removing the shield removes that failure mode entirely, and over a fifteen-year life in an environment that vibrates, that is worth more than the copper.
Single-pair Ethernet did not save two wires. It removed a shield, and with it a fifteen-year mechanical failure mode that no diagnostic in this track could ever have found.
And the pin arithmetic of Section 2 lands in the same place.
| 24-port domain controller | |
|---|---|
| shielded 2-pair: signal pins | 96 |
| plus shield terminations | 24 |
| unshielded 1-pair: signal pins | 48 |
| shield terminations | 0 |
| difference | 72 connector features |
Seventy-two fewer things to seal, inspect and qualify, on a part that must survive fifteen years of a 165 °C thermal cycle. That is the saving, and it is a manufacturing saving rather than a mass one.
15. RTL 7 — T1 PHY Telemetry
// ---------------------------------------------------------------------
// t1phy_telemetry -- what a single-pair PHY knows about itself, in one
// snapshot, exposed where a workshop can read it.
//
// Chapter 4.5 Section 5's Clause 45 address space is the delivery
// mechanism. The argument for putting these fields there is the whole
// of Section 17: in a vehicle, nobody is watching, and the only time
// anyone looks is after a complaint.
// ---------------------------------------------------------------------
module t1phy_telemetry
import t1phy_pkg::*;
(
input logic clk,
input logic rst_n,
input logic snapshot,
input t1_role_e i_role,
input logic [2:0] i_bringup_state,
input logic [31:0] i_time_to_link_symbols,
input logic [31:0] i_retries,
input logic [31:0] i_symbols,
input logic [31:0] i_near_threshold,
input logic signed [31:0] i_residual_energy,
input logic [31:0] i_no_lock_with_energy,
input logic signed [31:0] i_running_disparity,
input logic [31:0] i_periodic_flags,
input logic i_tail_energy_high,
input logic i_coeff_saturated,
input logic i_converged,
input logic i_emissions_risk,
output logic o_role,
output logic [2:0] o_bringup_state,
output logic [31:0] o_time_to_link_symbols,
output logic [31:0] o_retries,
output logic [15:0] o_near_threshold_ppm,
output logic signed [31:0] o_residual_energy,
output logic [31:0] o_no_lock_with_energy,
output logic signed [31:0] o_running_disparity,
output logic [31:0] o_periodic_flags,
output logic [4:0] o_flags,
output logic o_margin_is_shrinking
);
localparam int F_TAIL = 0; // canceller bank too short
localparam int F_SAT = 1; // a coefficient hit its rail
localparam int F_NOCONV = 2;
localparam int F_EMI = 3;
localparam int F_ROLE = 4; // energy present, never locked
logic [15:0] prev_ppm;
always_ff @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
o_role <= 1'b0; o_bringup_state <= '0;
o_time_to_link_symbols <= '0; o_retries <= '0;
o_near_threshold_ppm <= '0; o_residual_energy <= '0;
o_no_lock_with_energy <= '0; o_running_disparity <= '0;
o_periodic_flags <= '0; o_flags <= '0; prev_ppm <= '0;
o_margin_is_shrinking <= 1'b0;
end else if (snapshot) begin
o_role <= (i_role == ROLE_MASTER);
o_bringup_state <= i_bringup_state;
o_time_to_link_symbols <= i_time_to_link_symbols;
o_retries <= i_retries;
o_residual_energy <= i_residual_energy;
o_no_lock_with_energy <= i_no_lock_with_energy;
o_running_disparity <= i_running_disparity;
o_periodic_flags <= i_periodic_flags;
// The margin figure, normalised so two snapshots are comparable.
// Chapter 3.7 Section 15's slope, made a register.
if (i_symbols != 0)
o_near_threshold_ppm <= 16'((i_near_threshold * 1_000_000)
/ i_symbols);
prev_ppm <= o_near_threshold_ppm;
o_margin_is_shrinking <= (o_near_threshold_ppm > prev_ppm);
o_flags[F_TAIL] <= i_tail_energy_high;
o_flags[F_SAT] <= i_coeff_saturated;
o_flags[F_NOCONV] <= !i_converged;
o_flags[F_EMI] <= i_emissions_risk;
o_flags[F_ROLE] <= (i_no_lock_with_energy > 32'd1000);
end
end
endmoduleClassification: a snapshot bank, with one derived field and one trend.
What it teaches: that o_near_threshold_ppm is the field worth the whole block. Chapter 3.7 §15's read the slope, not the cliff is a procedure, and a procedure needs two readings that are comparable — which a raw count is not, because the two snapshots cover different numbers of symbols. Normalising to parts per million makes the comparison valid, and o_margin_is_shrinking does it in hardware so the reader does not have to.
And it teaches why o_role is one bit and is the most useful bit in the register. Section 9's two-slave fault is dark at both ends; a workshop that can read both ends' configured role resolves it without an instrument. One bit, and it turns a harness replacement into a check.
Deliberately simplified: prev_ppm holds one previous snapshot, so the trend is a two-point difference and is noisy; a real design keeps a short history. There is no read-clear, so the counters are cumulative since reset and a long-lived vehicle's values saturate. o_flags[F_ROLE] re-derives a threshold the role block already computed, which is duplication. And nothing here is per-temperature, where the most useful automotive form of every one of these fields would be binned by the die temperature at which it was recorded.
Production implication: the missing temperature binning is the field enhancement with the best return, and the reason is Section 18. A vehicle's failures cluster at the ends of the temperature range — a cold start at −30 °C, an engine bay at +110 °C — and a counter that aggregates over a drive cycle averages those away. Four bins, split at 0 °C, 40 °C and 85 °C, cost four times the counter area and turn this link is marginal into this link is marginal when cold, which names the mechanism — connector contact resistance, crystal pull, driver amplitude — rather than just the symptom.
16. RTL 8 — The T1 Conformance Monitor
// ---------------------------------------------------------------------
// t1phy_conformance_monitor -- properties over the single-pair PHY's
// own behaviour.
//
// The one property that must NOT appear here is the tempting one:
// that a clean received signal means the partner transmitted cleanly.
// On a shared pair the received signal has two authors and Section 20
// is about naming only one of them.
// ---------------------------------------------------------------------
module t1phy_conformance_monitor
import t1phy_pkg::*;
(
input logic clk,
input logic rst_n,
input t1_role_e role,
input logic drives_clock,
input logic recovers_clock,
input logic [2:0] bringup_state,
input logic link_up,
input logic tx_enable,
input logic adapt_enable,
input logic send_control,
input logic symbol_lock,
input logic canceller_converged,
input logic coeff_saturated,
input logic tail_energy_high,
input logic control_sent,
input pam3_e sym_a,
input pam3_e sym_b,
input logic s_valid,
input logic emissions_risk
);
// 1. Exactly one end owns the clock, and this end's two role
// outputs are complementary.
p_t1_one_clock_owner: assert property (@(posedge clk) disable iff (!rst_n)
drives_clock != recovers_clock);
// 2. The reserved ternary code never carries data.
p_t1_reserved_not_data: assert property (@(posedge clk) disable iff (!rst_n)
(s_valid && !control_sent) |->
!((sym_a == PAM3_POS) && (sym_b == PAM3_POS)));
// 3. No symbol is ever the unused fourth encoding.
p_t1_no_fourth_level: assert property (@(posedge clk) disable iff (!rst_n)
s_valid |-> ((sym_a != PAM3_RSV) && (sym_b != PAM3_RSV)));
// 4. Link-up requires symbol lock.
p_t1_link_needs_lock: assert property (@(posedge clk) disable iff (!rst_n)
link_up |-> symbol_lock);
// 5. Link-up requires a converged canceller.
p_t1_link_needs_converged: assert property (@(posedge clk) disable iff (!rst_n)
link_up |-> canceller_converged);
// 6. Adaptation only runs when we are training or up.
p_t1_adapt_scope: assert property (@(posedge clk) disable iff (!rst_n)
adapt_enable |-> (bringup_state == 3'd4) || (bringup_state == 3'd5));
// 7. A master transmits from reset onwards; it never waits.
p_t1_master_transmits: assert property (@(posedge clk) disable iff (!rst_n)
((role == ROLE_MASTER) && (bringup_state != 3'd0)) |-> tx_enable);
// 8. A slave never transmits before it has locked.
p_t1_slave_silent_first: assert property (@(posedge clk) disable iff (!rst_n)
((role == ROLE_SLAVE) && (bringup_state == 3'd1)) |-> !tx_enable);
// 9. Control codes are sent only during training.
p_t1_control_scope: assert property (@(posedge clk) disable iff (!rst_n)
send_control |-> (bringup_state == 3'd4));
// 10. A saturated coefficient is reported, never silently clipped.
p_t1_sat_reported: assert property (@(posedge clk) disable iff (!rst_n)
coeff_saturated |-> ##[0:2] $rose(coeff_saturated) || coeff_saturated);
// 11. A short tap bank is reported even while the link is up --
// especially while the link is up, since that is when it lies.
p_t1_tail_visible: assert property (@(posedge clk) disable iff (!rst_n)
(link_up && tail_energy_high) |-> tail_energy_high);
// 12. Losing lock drops the link.
p_t1_lock_loss_drops: assert property (@(posedge clk) disable iff (!rst_n)
(link_up && !symbol_lock) |=> !link_up);
endmoduleClassification: twelve properties about a PHY, and every one of them is about this end.
What it teaches: that property 2 is the only in-band protocol guarantee the physical layer has, and it is worth an assertion precisely because there is exactly one reserved code. Chapter 3.5 §6's 4B/5B could afford a whole control alphabet; one spare pair means one property, and violating it destroys the only unambiguous signalling on the wire.
And it teaches that properties 7 and 8 encode the asymmetry that replaced auto-negotiation. A master transmits unconditionally; a slave is silent until it has locked. Those two lines are the entire bring-up protocol, and stating them as properties is the closest this physical layer comes to having a specification of an exchange.
Deliberately simplified: property 10's ##[0:2] window is a placeholder for a real reporting latency. Property 11 is a tautology as written — it says a flag implies itself — and is kept because it names the requirement that the flag must not be suppressed while link_up, which a real implementation would express against a telemetry register rather than against the flag. Property 6 compares against a literal state encoding rather than the enumeration, which breaks silently if the states are renumbered. And there is no property about the far end at all, which is the section's point and Section 20's subject.
Production implication: properties 4 and 5 together are the ones to insist on in a PHY you are integrating, and they are commonly weaker in practice than they look. A PHY that asserts link-up on symbol lock alone, before the echo canceller has converged, passes traffic immediately — and the first few hundred microseconds of that traffic have an error rate the link will never show again. The MAC above sees a burst of check-sequence failures at every link-up, Chapter 21.3's counter climbs, and the cause is a link-up signal that was true too early. Require canceller_converged in the gate, and measure how long it takes, because Section 11's c_time_to_link_symbols is what tells you whether the requirement is expensive.
17. What the Car Changes Above the PHY — and What It Does Not
A useful way to end the physical-layer argument is to say exactly how far up it reaches. The answer is: not far at all, and that is the point.
| Layer | Changed by automotive? |
|---|---|
| the channel — cable, connectors, shield | completely |
| modulation and line code | completely |
| echo cancellation and equalisation | completely |
| bring-up and role selection | completely — auto-negotiation deleted |
| the xMII / reconciliation sublayer | not at all |
| the frame | not at all |
| addressing | not at all |
| the check sequence | not at all |
| the elastic buffer's sizing | not at all — Chapter 4.4 §2's ±100 ppm is unchanged |
| Chapter 19.7's counters | not at all |
| queueing and scheduling | ****Chapter 22.2's subject, and it is Module 17's mechanisms |
The line between rows four and five is Chapter 4.1 §3's MAC/PHY split, and this chapter is the strongest evidence in the track that it was drawn correctly. Everything below it changed and nothing above it did. A MAC designed in Module 19 for a data-centre port attaches to a 100BASE-T1 PHY through the same reconciliation sublayer, with the same signals, and does not need to know that both directions are sharing a wire on the other side.
Three consequences of that, in increasing order of practical value.
First, the verification transfers. Chapter 20.6's agent, Chapter 20.3's scoreboard and Chapter 20.5's error injection all sit above the xMII and are unchanged. The new verification is entirely below it, and it is analog-adjacent: convergence, residual energy, tap distribution, temperature.
Second, the diagnosis does not transfer, and Module 21's chapters split cleanly.
| Module 21 chapter | Applies in a car? |
|---|---|
| Chapter 21.1 — the receive path's twelve sites | yes, unchanged |
| Chapter 21.2 — the error classes | yes, unchanged |
| Chapter 21.3 — the check sequence's one bit | yes, unchanged |
| Chapter 21.4 — fourteen link sites | partly — the MDIO evidence differs |
| Chapter 21.5 — the duplex mismatch | no — the mechanism does not exist |
| Chapter 21.6 — silent drops | yes, unchanged |
| Chapter 21.7 — descriptor faults | yes, unchanged |
| Chapter 21.8 — the ceilings | yes, with different numbers |
| Chapter 21.9 — the capture | yes, and harder |
Row nine deserves a sentence. Chapter 21.9 priced a capture at 84 milliseconds per gigabyte at 100 Gb/s; at 100 Mb/s the same gigabyte covers 84 seconds, which is a thousand times better and makes the instrument genuinely practical. But there is nowhere to stand. A vehicle harness has no span port, the connector is sealed, and inserting a tap means breaking into a harness — so the capture's reach improves by three orders of magnitude and its accessibility collapses.
Third, and most usefully: the field diagnostics have to be in the PHY, because nothing else is there. A data centre has an operator, a monitoring system, a maintenance window and a spare port. A vehicle has a workshop visit, once, after a complaint. Every counter this chapter has added — near-threshold rate, time-to-link, retries, tail energy, role — exists because the only diagnostic session that will ever happen is a single read of a register set, months after the symptom.
18. Fifteen Years and 125 °C
The qualification regime is not a footnote. It changes which failure modes matter and therefore which counters are worth flops.
| Data-centre port | Automotive port | |
|---|---|---|
| ambient range | 0 to +70 °C | −40 to +125 °C |
| span | 70 °C | 165 °C |
| service life | 3 years, then refreshed | 15 years |
| power cycles | few | tens of thousands |
| vibration | none | continuous |
| who notices a fault | a monitoring system, within minutes | a driver, eventually |
| cost of a repair | swap a module | a workshop visit |
Row two changes the analog design and almost nothing digital. The slicer thresholds of Section 3, the driver amplitude of Section 13 and the crystal's frequency all move across 165 °C, and each must be either adapted or budgeted. The one digital consequence is that every adaptive loop in the PHY must track, rather than converging once at link-up — which is why Section 11's adapt_enable stays true in S_UP and not only during training.
Row four is the one that is usually underestimated. Tens of thousands of power cycles over fifteen years means the link comes up tens of thousands of times, and a bring-up that succeeds 99.99% of the time fails several times over the vehicle's life. A bring-up failure that is not retried is a dead link for a drive cycle, which is Section 11's missing warm-retry stated as a reliability number rather than as a code review comment.
Rows six and seven together are why the telemetry exists.
In a data centre, an instrument watches. In a vehicle, a register remembers. Everything this chapter counts is counted because nobody will be looking when it happens.
And the accumulation problem has a specific automotive shape. Chapter 19.7 §8 sized RMON counters to saturate correctly; a vehicle's counters run for fifteen years without a read. A 32-bit symbol counter at 66.67 MBd wraps in 64 seconds. So every counter here must either be wide, saturating, or read and cleared by the diagnostic session — and the third is the only affordable option, which means the vehicle's diagnostic software is part of the counter's specification. That is an unusual coupling and it is worth being explicit about, because a counter designed without it silently reports a wrapped value that looks like a small number.
| Counter | Wraps at 66.67 MBd |
|---|---|
| 32-bit symbol count | 64 s |
| 32-bit near-threshold count at 10⁻⁶ | 740 days |
| 32-bit time-to-link, counted in symbols | 64 s — and it only ever counts during bring-up |
| 32-bit retry count | never, in practice |
Row one is the trap and row three is the reason it is survivable. A free-running symbol counter is useless after a minute; a counter that runs only during bring-up and stops at link-up is a duration, and durations in this system are milliseconds. Design the counter to measure an interval, not to accumulate, wherever the quantity is an interval.
19. The Cost, Accounted
Priced the way every chapter in Modules 19 to 21 prices its mechanism: in flip-flops, against Chapter 19.7 §19's 14 166-flop MAC receive datapath.
| Block | Flops | Share of 14 166 |
|---|---|---|
pam3_slicer | 90 | 0.6% |
ternary_mapper_3b2t | 104 | 0.7% |
echo_canceller_bank, 32 taps | 576 | 4.1% |
master_slave_role | 67 | 0.5% |
t1_link_bringup | 99 | 0.7% |
emission_budget_monitor | 1 153 | 8.1% |
t1phy_telemetry | 234 | 1.7% |
t1phy_conformance_monitor | 0 — assertions | — |
| total, 100BASE-T1 | 2 323 | 16.4% |
| with a 192-tap gigabit canceller instead | 5 203 | 36.7% |
Two rows in that table are surprising and both are worth a sentence.
The emissions monitor at 1 153 flops is the second largest block, and 1 024 of those are its 512-entry delay line of 2-bit symbols. In silicon that is a small RAM and not a register file, which drops the flop count to about eighty and moves the cost to an area the flop accounting does not capture — the first place in this track where the unit stops being the right one. It is worth saying plainly: a delay line is memory, and pricing memory in flip-flops overstates it by an order of magnitude, exactly as Chapter 21.9 §19 found with its capture buffer.
And the 100BASE-T1 total at 2 323 flops is 16.4% of the MAC it attaches to. A whole single-pair digital front end — slicer, mapper, canceller, role, bring-up, emissions monitor and telemetry — costs about a sixth of Chapter 19.7 §19's receive datapath, for a hundred megabits, on one pair, unshielded, across 165 °C. For comparison, Chapter 21.9 §19's capture control blocks came to 8 025 flops, 56.6% — the instrument that watches a link is three and a half times the front end that drives one.
The gigabit row is the one that decides a product.
| 100BASE-T1 | 1000BASE-T1 | Ratio | |
|---|---|---|---|
| rate | 100 Mb/s | 1 000 Mb/s | 10× |
| symbol rate | 66.67 MBd | 750 MBd | 11.25× |
| canceller taps | 32 | 192 | 6× |
| digital front end, flops | 2 323 | 5 203 | 2.24× |
| FEC | none | required | — |
Ten times the rate for 2.25 times the digital front end, plus a decoder. That is a good trade by any measure, and the reason the front end scales so much better than the rate is Section 8's result: the echo canceller's tap count is set by the cable's round trip, and the cable did not get longer.
20. Properties Worth Asserting, and One Worth Refusing
Six groups. Every property's subject is this end of the link, and Section 20's refused class explains why that restriction is not a limitation of the properties but a fact about the medium.
Group A — the code.
// A1. Every emitted symbol is one of the three levels.
p_t1_levels: assert property (@(posedge clk) disable iff (!rst_n)
s_valid |-> (sym_a inside {PAM3_NEG, PAM3_ZER, PAM3_POS}) &&
(sym_b inside {PAM3_NEG, PAM3_ZER, PAM3_POS}));
// A2. The reserved pair is never used for data.
p_t1_reserved: assert property (@(posedge clk) disable iff (!rst_n)
(s_valid && !control_sent) |->
!((sym_a == PAM3_POS) && (sym_b == PAM3_POS)));
// A3. The mapping is injective: two different inputs never give the
// same pair. Checked as a static elaboration property.
p_t1_map_injective: assert property (@(posedge clk) disable iff (!rst_n)
s_valid |-> (MAP_3B2T[d_bits] == {sym_a, sym_b}) || control_sent);
// A4. One group in, one pair out -- no rate change.
p_t1_rate: assert property (@(posedge clk) disable iff (!rst_n)
d_valid |=> s_valid);
// A5. Disparity moves by at most two per group.
p_t1_disparity_step: assert property (@(posedge clk) disable iff (!rst_n)
s_valid |=> ((running_disparity - $past(running_disparity)) <= 2) &&
((running_disparity - $past(running_disparity)) >= -2));Group B — the role and the clock.
// B1. Exactly one of drive and recover is true.
p_t1_one_owner: assert property (@(posedge clk) disable iff (!rst_n)
drives_clock != recovers_clock);
// B2. The role never changes while the link is up.
p_t1_role_stable: assert property (@(posedge clk) disable iff (!rst_n)
link_up |=> (role == $past(role)));
// B3. A master transmits once out of reset.
p_t1_master_tx: assert property (@(posedge clk) disable iff (!rst_n)
((role == ROLE_MASTER) && (bringup_state != S_RESET)) |-> tx_enable);
// B4. A slave is silent while listening.
p_t1_slave_silent: assert property (@(posedge clk) disable iff (!rst_n)
((role == ROLE_SLAVE) && (bringup_state == S_SILENT)) |-> !tx_enable);
// B5. Energy with no lock, sustained, sets the role-conflict flag.
p_t1_role_flag: assert property (@(posedge clk) disable iff (!rst_n)
(c_no_lock_with_energy > 1000) |-> role_conflict_suspected);Group C — bring-up.
// C1. Link-up implies lock.
p_t1_up_lock: assert property (@(posedge clk) disable iff (!rst_n)
link_up |-> symbol_lock);
// C2. Link-up implies a converged canceller. The property Section 16
// argues you should insist on from a vendor.
p_t1_up_converged: assert property (@(posedge clk) disable iff (!rst_n)
link_up |-> canceller_converged);
// C3. Adaptation runs only in training or up.
p_t1_adapt: assert property (@(posedge clk) disable iff (!rst_n)
adapt_enable |-> (bringup_state inside {S_TRAIN, S_UP}));
// C4. Control codes only in training.
p_t1_ctrl: assert property (@(posedge clk) disable iff (!rst_n)
send_control |-> (bringup_state == S_TRAIN));
// C5. Losing lock drops the link on the next cycle.
p_t1_lock_drop: assert property (@(posedge clk) disable iff (!rst_n)
(link_up && !symbol_lock) |=> !link_up);
// C6. Retries are bounded.
p_t1_retry_bound: assert property (@(posedge clk) disable iff (!rst_n)
c_retries <= RETRY_LIMIT);
// C7. The time-to-link counter stops at link-up.
p_t1_ttl_stops: assert property (@(posedge clk) disable iff (!rst_n)
link_up |=> (c_time_to_link_symbols == $past(c_time_to_link_symbols)));Group D — the echo canceller.
// D1. Coefficients never wrap; saturation is reported.
p_ec_no_wrap: assert property (@(posedge clk) disable iff (!rst_n)
(coeff_saturated) |-> ((coeff[sat_idx] == COEFF_MAX) ||
(coeff[sat_idx] == COEFF_MIN)));
// D2. The history register holds only valid ternary weights.
p_ec_hist_ternary: assert property (@(posedge clk) disable iff (!rst_n)
hist[0] inside {-2'sd1, 2'sd0, 2'sd1});
// D3. With adaptation off, coefficients are frozen.
p_ec_frozen: assert property (@(posedge clk) disable iff (!rst_n)
!adapt_en |=> (coeff[0] == $past(coeff[0])));
// D4. A short bank is flagged, and the flag does not clear while the
// condition holds.
p_ec_tail: assert property (@(posedge clk) disable iff (!rst_n)
(tail_acc > (COEFF_MAX >>> 4)) |-> tail_energy_high);
// D5. The cleaned sample is the raw sample minus the estimate.
p_ec_subtract: assert property (@(posedge clk) disable iff (!rst_n)
rx_valid |-> (rx_clean == (rx_sample - est[SAMP_W-1:0])));
// D6. Convergence is not claimed while a coefficient is saturated.
p_ec_sat_not_converged: assert property (@(posedge clk) disable iff (!rst_n)
coeff_saturated |-> !converged);Group E — the slicer and the margin.
// E1. The chosen level is consistent with the sample and thresholds.
p_sl_consistent: assert property (@(posedge clk) disable iff (!rst_n)
s_valid |-> ((level == PAM3_POS) == ($past(sample) > THRESH)));
// E2. The residual is bounded by one threshold.
p_sl_resid_bound: assert property (@(posedge clk) disable iff (!rst_n)
s_valid |-> ((residual <= THRESH) && (residual >= -THRESH)));
// E3. Near-threshold implies a residual above a tenth.
p_sl_near: assert property (@(posedge clk) disable iff (!rst_n)
near_threshold |-> ((residual > (THRESH/10)) ||
(residual < -(THRESH/10))));
// E4. The symbol counter is monotone.
p_sl_mono: assert property (@(posedge clk) disable iff (!rst_n)
c_symbols >= $past(c_symbols));
// E5. The near-threshold count never exceeds the symbol count.
p_sl_subset: assert property (@(posedge clk) disable iff (!rst_n)
c_near_threshold <= c_symbols);Group F — emissions and telemetry.
// F1. Any of the four conditions raises the risk flag.
p_emi_or: assert property (@(posedge clk) disable iff (!rst_n)
emissions_risk == (periodic_suspected | amplitude_out_of_band |
disparity_drifting | scrambler_degenerate));
// F2. A reported period is one of the candidates.
p_emi_period_valid: assert property (@(posedge clk) disable iff (!rst_n)
periodic_suspected |-> (repeat_period_symbols inside {7,31,127,511}));
// F3. An all-zero scrambler is always degenerate.
p_emi_zero: assert property (@(posedge clk) disable iff (!rst_n)
scrambler_all_zero |-> scrambler_degenerate);
// F4. The normalised margin is a ratio of two snapshot fields.
p_tel_ppm: assert property (@(posedge clk) disable iff (!rst_n)
(snapshot && (i_symbols != 0)) |=>
(o_near_threshold_ppm == 16'((($past(i_near_threshold)) * 1000000)
/ $past(i_symbols))));
// F5. The telemetry role bit matches the PHY's role.
p_tel_role: assert property (@(posedge clk) disable iff (!rst_n)
snapshot |=> (o_role == ($past(i_role) == ROLE_MASTER)));
// F6. The margin trend is set only when the ratio rose.
p_tel_trend: assert property (@(posedge clk) disable iff (!rst_n)
o_margin_is_shrinking |-> (o_near_threshold_ppm > prev_ppm));Thirty-four properties, and the twelve of Section 16 bring the chapter to forty-six. Every one names this end. None names the partner, and the reason is not modesty.
21. Verification Scenarios
Fifty-eight scenarios. The hard ones are all temperature, convergence, or the two ends disagreeing about who owns the clock.
Group 1 — the code and the mapper (10).
| # | Scenario | Expect |
|---|---|---|
| 1 | all eight 3-bit inputs, in order | eight distinct ternary pairs; none is the reserved one |
| 2 | send_control asserted | the reserved pair only; control_sent high |
| 3 | a long run of the same input | disparity drifts — the scrambler is what prevents it |
| 4 | scrambler disabled, all-zero data | disparity_drifting asserts within the window |
| 5 | random scrambled data over 10⁶ groups | disparity bounded; no periodicity flag |
| 6 | d_valid low for 1 000 cycles | no symbols, no disparity movement |
| 7 | PAM3_RSV forced onto sym_a | p_t1_no_fourth_level fires |
| 8 | the reserved pair emitted with send_control low | p_t1_reserved fires |
| 9 | two inputs mapped to the same pair | p_t1_map_injective fires |
| 10 | disparity moved by 3 in one group | p_t1_disparity_step fires |
Group 2 — the slicer and the margin (9).
| # | Scenario | Expect |
|---|---|---|
| 11 | clean samples at exactly ±2·THRESH and 0 | correct levels; residual zero |
| 12 | samples offset by a constant gain error | residual on every symbol — the fixed-threshold flaw |
| 13 | noise at a tenth of a threshold | near_threshold on about half the symbols |
| 14 | noise ramped from 0 to a threshold | c_near_threshold rises before any symbol error |
| 15 | a sample exactly at THRESH | sliced to PAM3_ZER — the boundary convention |
| 16 | 1e6 clean symbols | o_near_threshold_ppm near zero |
| 17 | two snapshots, margin worsening | o_margin_is_shrinking high |
| 18 | two snapshots over different symbol counts | the ppm normalisation makes them comparable |
| 19 | c_near_threshold forced above c_symbols | p_sl_subset fires |
Group 3 — the echo canceller (12).
| # | Scenario | Expect |
|---|---|---|
| 20 | echo only, no partner, 32-tap channel | converges; rx_clean goes to zero |
| 21 | echo plus partner, echo 20 dB larger | converges; partner recoverable |
| 22 | a channel 64 taps long into a 32-tap bank | converges, stably, wrong; tail_energy_high |
| 23 | the same, checked from above the PHY | looks like additive noise — the point of the test |
| 24 | an echo path with a huge tap-0 term | coeff_saturated; converged stays low — D6 |
| 25 | adapt_en deasserted mid-convergence | coefficients frozen — D3 |
| 26 | four inline connectors, six pairwise round trips | energy beyond the single round trip; sizing matters |
| 27 | transmit and receive scramblers correlated | the canceller eats signal; error falls — class 103 |
| 28 | the same, with tail_energy_high watched | the coefficients show it; the error does not |
| 29 | tx_enable low, partner transmitting | the only clean measurement of the partner — property 3 |
| 30 | a step change in echo path at +125 °C | re-converges if adapt_en stays high in S_UP |
| 31 | rx_clean forced not equal to sample minus estimate | p_ec_subtract fires |
Group 4 — role and bring-up (13).
| # | Scenario | Expect |
|---|---|---|
| 32 | master and slave, correctly configured | link in about 2.1 M symbols — 31.5 ms |
| 33 | two masters | no link; c_no_lock_with_energy climbs; flag sets |
| 34 | two slaves | no link; no energy; NOTHING detects it |
| 35 | slave powered first, master 500 ms later | slave waits in S_SILENT, then links |
| 36 | master powered first, no slave | master transmits into an empty cable forever |
| 37 | lock achieved, canceller never converges | training_timeout, retry, eventually S_FAILED |
| 38 | eight retries exhausted | gave_up; no recovery — the missing warm retry |
| 39 | link up, then symbol lock lost | drops to S_RESET — C5 |
| 40 | cold start at −40 °C, link at attempt 6 | c_retries = 5; c_time_to_link_symbols large |
| 41 | the same link at +25 °C | first attempt; the contrast IS the diagnostic |
| 42 | role changed while link up | p_t1_role_stable fires |
| 43 | a master that does not transmit out of reset | p_t1_master_tx fires |
| 44 | a slave transmitting in S_SILENT | p_t1_slave_silent fires |
Group 5 — emissions (8).
| # | Scenario | Expect |
|---|---|---|
| 45 | scrambled random data | no candidate period exceeds two-thirds agreement |
| 46 | a period-31 repeating pattern | periodic_suspected; repeat_period_symbols = 31 |
| 47 | a period-63 pattern | missed — not a candidate; the known hole |
| 48 | scrambler stuck all-zero | scrambler_degenerate and no transitions |
| 49 | transmit amplitude +15% | amplitude_out_of_band |
| 50 | amplitude drifting with temperature within ±10% | no flag — the band is deliberately wide |
| 51 | disparity beyond ±100 000 | disparity_drifting |
| 52 | a reported period not in the candidate set | p_emi_period_valid fires |
Group 6 — the system, over temperature and life (6).
| # | Scenario | Expect |
|---|---|---|
| 53 | a −40 to +125 °C sweep with fixed slicer thresholds | near-threshold rate rises at both ends of the sweep |
| 54 | the same with adapted thresholds | flat — which is why they are adapted |
| 55 | 10 000 power cycles at a 99.99% bring-up rate | about one failure; the retry path must exist |
| 56 | a 32-bit symbol counter run for 64 s | wraps — Section 18's trap |
| 57 | a diagnostic read that clears the counters | intervals remain interpretable |
| 58 | fifteen years with no diagnostic read | every cumulative counter is meaningless |
Scenario 34 is the one no test can catch and scenario 23 is the one every system-level test gets wrong.
The directed test random stimulus will not produce
This test needs the echo canceller to be working correctly and the link to be failing, at the same time, for a reason that is in neither.
The arrangement:
| Step | Action |
|---|---|
| 1 | a correct master/slave pair on a 15 m segment with four inline connectors |
| 2 | the canceller bank is 32 taps; the topology's impulse response runs to 58 |
| 3 | the link comes up normally, converges, and reports converged high |
| 4 | tail_energy_high is asserted and is not wired to anything above the PHY |
| 5 | the residual left by the missing 26 taps raises the symbol error rate to 10⁻⁷ |
| 6 | the MAC above counts check-sequence errors at Chapter 21.3's rate and reports a channel fault |
Random stimulus will not produce this because it needs a channel whose impulse response is specifically longer than the bank and specifically short enough that the filter still converges. A randomised channel length produces either a comfortable fit — nothing to see — or a gross mismatch that fails to converge and trips training_timeout. The interesting window is narrow: long enough to leave residual, short enough that the loop stays stable, and it has to be paired with a topology the specification permits, which a random channel generator does not know about.
The oracle is in four parts and part four is a negative result.
| Part | Signal | Required value | Why alone it is not enough |
|---|---|---|---|
| 1 — the canceller believes it is fine | converged | 1 | it is telling the truth about its own criterion |
| 2 — the coefficients say otherwise | tail_energy_high | 1 | means nothing unless someone reads it |
| 3 — the symptom is above the PHY | check-sequence error rate | ≈ 10⁻⁷ | identical to a bad cable |
| 4 — no measurement above the PHY separates them | every MAC counter | identical in both cases | this is the finding |
Part 4 is the assertion worth writing and it is about the absence of a distinction. Run the test twice — once with a short bank on a good cable, once with an adequate bank on a genuinely degraded cable — and require that every counter in Chapter 19.7's 27 reads the same in both runs. The test passes when they do, because that is the true statement about the system, and it fails if a MAC-level counter accidentally distinguishes them, which would mean the model is wrong.
Then run it a third time with tail_energy_high wired into the telemetry of Section 15. The two cases separate instantly, and the whole cost is one bit in an MDIO register. That contrast is the test's purpose: it does not find a bug, it demonstrates the value of a field that a design review would otherwise cut.
22. Debugging a Single-Pair Link
A procedure, ordered by what costs nothing first — which in a vehicle means register reads before anything physical.
| Step | Do | Because |
|---|---|---|
| 1 | read both ends' configured role | Section 9 — two slaves is dark and this is the only evidence |
| 2 | read c_time_to_link_symbols and c_retries | a link that took six attempts is marginal and reports "up" |
| 3 | read o_near_threshold_ppm and compare with the last visit | Chapter 3.7 §15's slope, before the cliff |
| 4 | read tail_energy_high and coeff_saturated | separates a short canceller from a bad cable |
| 5 | read the emissions flags | a periodic pattern is a design fault, not a harness fault |
| 6 | only now consider the harness | it is the expensive hypothesis |
| 7 | if the partner is suspect, use transmit-disable | the only condition where the signal has one author |
| 8 | check the MAC counters last | Chapter 19.7's 27 cannot see below the xMII |
Step 8 being last inverts Module 21's advice and the inversion is deliberate. Chapter 21.1 §12 put counters first because in a data centre they are free and continuous. In a vehicle the PHY registers are equally free and are far closer to the fault, because almost every automotive link failure is physical — and the MAC counters, by construction, report only what reached the xMII.
Three signatures worth memorising.
| Signature | Cause |
|---|---|
| no link, both ends see energy | two masters |
| no link, neither end sees energy | two slaves, a broken cable, or an unpowered partner — indistinguishable |
link up, rising near-threshold ppm, tail_energy_high clear | the channel is genuinely degrading |
link up, flat near-threshold ppm, tail_energy_high set | the canceller is short — a design fault in the field |
| link up only when warm | a connector, a crystal, or an unadapted threshold |
Rows three and four are the pair that matters because they present identically above the PHY and have completely different remedies: one is a harness, one is a firmware or silicon change. Getting them the wrong way round costs a harness replacement that does not fix anything, which is the most expensive single error available in this domain.
And one signature that is not a fault at all.
| Observation | Reading |
|---|---|
| a burst of check-sequence errors at every link-up, then nothing | link_up asserted before the canceller converged |
Section 16's properties 4 and 5 exist to prevent it, and a PHY that violates them produces an error count that climbs at every ignition cycle. Over fifteen years and tens of thousands of cycles that is a large number of counted errors that never corresponded to a lost frame — and it will be read, once, by a workshop, as evidence of a failing link.
23. Misconceptions
Six, in wrong-model / what-it-costs / corrected-model form.
Misconception 1 — "single-pair Ethernet exists to save weight."
Wrong model: two wires instead of four halves the harness, and that is the point.
What it costs: the actual constraint, and therefore the design conversation. Section 14's arithmetic: 24 AWG copper is 1.84 g per metre per conductor, so removing two conductors saves 3.68 g/m — 0.37 kg over a hundred metres of link, on a vehicle weighing one to three tonnes. A team that believes weight is the driver optimises the wrong variable and will propose shielded two-pair solutions whenever weight is not critical.
Corrected model: the binding constraint is emissions, and it is categorical rather than marginal. 100BASE-TX unshielded does not meet automotive radiated-emission limits, because its symbol stream occupies bandwidth to 125 MHz and overlaps the FM broadcast band. The real comparison was shielded two-pair against unshielded single-pair, and what was saved was a shield, its 360-degree bond, and a fifteen-year mechanical failure mode — not two wires.
Misconception 2 — "one pair is half the bandwidth, so it must be slower."
Wrong model: fewer conductors, less capacity.
What it costs: an understanding of where the rate comes from. Section 4: MLT-3 gets one bit per symbol from three levels; 3B2T gets one and a half from the same three levels. So 100BASE-T1 carries the same 100 Mb/s at 66.67 MBd against 125, on one pair rather than two, with a fundamental only 6.7% higher.
Corrected model: the rate came from a denser code, and the cost was paid in two other currencies. Control vocabulary — nine ternary pairs, eight used, one spare where 4B/5B had sixteen — and echo cancellation, because both directions now share the wire. Neither cost is bandwidth.
Misconception 3 — "a shorter cable means a smaller echo canceller."
Wrong model: 15 metres instead of 100 should need a seventh of the taps.
What it costs: a wrong area estimate for the gigabit part, by a factor of six. Section 8's arithmetic: the tap count is the round-trip delay times the symbol rate, and a 15 m link at 750 MBd needs 113.6 symbols against a 100 m link at 125 MBd needing 126.3. The length fell by 6.7× and the symbol rate rose by 6×, and they nearly cancel.
Corrected model: shortening the cable did not shrink the canceller — it made the higher symbol rate possible, which is a different and larger benefit. A 192-tap gigabit canceller is 3 456 flops, 24.4% of Chapter 19.7 §19's whole MAC receive datapath, and it is the largest digital block in the PHY.
Misconception 4 — "no auto-negotiation means fewer things to go wrong."
Wrong model: deleting a protocol deletes its faults.
What it costs: half the truth. Chapter 21.5's duplex mismatch genuinely cannot occur — there is no half duplex — and that is a real gain, because it removed a fault that links, passes traffic, and loses 37.69% of maximum-size frames at 50% load while losing zero minimum-size ones. But two new faults appeared.
Corrected model: the requirement did not vanish, it moved. A single-pair link still needs exactly one clock owner, and with no negotiation that is a configuration. Two masters is loud and detectable. Two slaves is completely silent at both ends — indistinguishable from a cut cable, an unpowered ECU, or a node that has not booted. The net trade is favourable, and it is a trade rather than a deletion.
Misconception 5 — "if the received signal is clean, the partner is fine."
Wrong model: the receiver measures the far end.
What it costs: every diagnosis on a shared pair, and it is Section 20's rejected class. The received sample is far_end + our_own_echo + noise, and the echo is the larger term after only 20 to 30 dB of hybrid separation. What the slicer error measures is far_end_error + canceller_residual, and the property names one of the two.
Corrected model: on one pair there is no signal anywhere that belongs to the partner alone while this end is transmitting. The measurement that does exist is transmit-disable: turn our transmitter off and the received signal has one author. It is a register bit, it breaks the link while set, and it is the only honest way to blame the far end.
Misconception 6 — "the counters will tell us."
Wrong model: Chapter 19.7's 27 RMON counters diagnose an automotive link the way they diagnose a data-centre port.
What it costs: the whole fault space below the xMII. Every counter in that block sits above the reconciliation sublayer, so a short echo-canceller bank, a rising near-threshold rate, a marginal bring-up that needed six retries, and a scrambler producing a line spectrum are all invisible to all 27. They report the consequence — check-sequence errors — which is Chapter 21.3's one bit, shared by every physical cause.
Corrected model: in a vehicle the useful counters are in the PHY, exposed through Chapter 4.5 §5's Clause 45 space, and read once, by a workshop, months after the symptom. That is why Section 15 exists and why the fields it normalises — parts per million rather than raw counts — matter: two readings months apart are only comparable if they were normalised when they were taken.
24. Interview Questions
Six, with what a strong answer contains.
1. Where does 100BASE-T1's rate come from, given it uses one pair and three levels like 100BASE-TX uses two pairs and three levels?
From the code. MLT-3 spends its third level on transition density and gets one bit per symbol; 3B2T maps three bits to two ternary symbols — 8 of the 9 available pairs — for 1.5 bits per symbol, and gets its transitions from the scrambler instead. So 100 Mb/s needs 66.67 MBd rather than 125. A strong answer names the price: one spare code instead of sixteen, and a scrambler that now single-handedly underwrites clock recovery, DC balance and emissions.
2. Why is the echo canceller for a 15 m gigabit automotive link about the same size as for a 100 m gigabit office link?
Because the tap count is a round-trip time times a symbol rate. Fifteen metres at 0.66c is 75.8 ns one way, so at 750 MBd the round trip is 113.6 symbols; a hundred metres at 125 MBd is 126.3. The length fell by 6.7 and the rate rose by 6. A strong answer adds that the specification permits four inline connectors, each a reflector, so the real bank is sized against the topology rather than against the cable.
3. What did automotive delete from the link layer, and what replaced it?
Auto-negotiation. Four of the five things it resolved — speed, duplex, flow control, legacy compatibility — are fixed at vehicle design time, and the fifth, which end owns the clock, became a configured role. A strong answer names the asymmetry in the new fault space: two masters produces energy with no lock and is detectable; two slaves produces silence at both ends and is indistinguishable from a cut cable — and that the remedy is to make the configured role readable over the diagnostic bus.
4. A link is up, the check-sequence error rate is 10⁻⁷, and the harness tests good. What do you look at?
The echo canceller's coefficients. A bank shorter than the channel's impulse response converges stably to the wrong filter and leaves the remainder in the signal as what looks exactly like additive noise. The evidence is that the last taps are not near zero, which is one comparison in hardware and invisible to every counter above the PHY. A strong answer notes that this presents identically to a degraded cable, so the two are separated only by a PHY register — and that replacing the harness is the expensive wrong answer.
5. Why can you not write an assertion that says the partner is transmitting correctly?
Because on a single pair the received signal has two authors. rx_sample = far_end + our_own_echo + noise, and after a hybrid's 20 to 30 dB the echo is still the larger term. The slicer error measures far_end_error + canceller_residual, so a property naming only the far end is wrong in three ways — and the worst is that an over-converged canceller makes it pass while eating the partner's signal. A strong answer names the fix: transmit-disable, the one condition where the received signal has a single author.
6. Name something a car did not change about Ethernet, and say why that matters.
The clock budget, the frame, the addressing, the check sequence and the elastic buffer's sizing. Chapter 4.4 §2's ±100 ppm per end, 200 ppm between ends is in IEEE 802.3 rather than in a channel specification, so a maximum frame still accumulates about 0.3 of an octet and the interframe gap still discharges it. Everything below the reconciliation sublayer changed completely and nothing above it changed at all. A strong answer draws the conclusion: that is Chapter 4.1 §3's MAC/PHY split proving itself, and it is why a MAC from Module 19 attaches to this PHY unmodified.
25. Questions and Answers
26. What's Next
The physical layer is done. Everything above it in a vehicle is Module 17's mechanisms applied to a topology with deadlines.
| This chapter established | |
|---|---|
| the rate comes from a code | 3B2T's 1.5 bits per symbol against MLT-3's 1 |
| the price is an echo canceller | 576 flops at 100 Mb/s, 3 456 at 1 Gb/s |
| its size is a cable round trip | 10.1 symbols, or 113.6 at gigabit |
| the binding constraint was emissions | not weight — that is 0.37 kg per 100 m |
| auto-negotiation was deleted | and one of its two replacement faults is dark |
| nothing above the xMII changed | including Chapter 4.4 §2's ±100 ppm |
Chapter 22.2 takes the next layer up. A vehicle backbone carries control traffic with hard deadlines alongside sensor streams with large, bursty volumes, on the same links this chapter just built. Chapter 17.1 established why standard switched Ethernet cannot bound latency; Chapter 17.2 built the gate schedule that can; Chapter 17.3 built preemption. None of that is re-taught. What the next chapter does is apply it to a real topology and price it: how many gates, how much guard band, what the schedule costs in flops, and what happens to the whole construction when the synchronised clock that Chapter 16.2 provides is lost.
Continue learning
Related tutorials
- Related topic
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.
- Related topic
The PHY Layer
Coding, serialisation, clock recovery and line drive all exist because a real channel attenuates, disperses and carries no clock. The PCS, PMA and PMD split follows the same logic — each owns one consequence of physics, and each changes on its own schedule.
- Related topic
Fibre Ethernet
Separate strands per direction delete the echo problem that shapes copper PHYs, and introduce two others: a conversion boundary inside a pluggable module you do not own, and a link that can break in one direction while the far end still reports perfect health.
- Related topic
Differential Signalling and the Analog Channel
A PHY does not read bits off a wire — it infers symbols from a waveform the channel has attenuated, reflected and smeared into its neighbours. Differential signalling, impedance, jitter and the eye are one subject: what margin is left after the channel takes its share.
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.
