Skip to content
VLSI Mentor

Ethernet · Module 1

From Coax to Twisted Pair to Switched Links

Coax, repeater, hub, bridge, switch — four steps, and only the last touched contention. A repeater reproduces a signal and cannot buffer, so it spends collision-domain budget and partitions nothing; a bridge holds the whole frame, and that buffer is what makes every other capability possible.

Chapter 1.1 established the shared-medium problem and Chapter 1.2 solved it — with a slot time, a minimum frame, a jam and a backoff policy, all of it derived from how long a signal takes to cross a cable and come back.

Then the industry spent twenty years dismantling the assumption that made all of it necessary.

The steps look like a gradual improvement in cabling and speed. They are not. Two of them changed nothing about contention while making the timing budget worse, one of them changed everything, and telling the two apart is the point of this chapter.

A signal on one shared coax, and a frame between two ports of a modern switch, are separated by four physical steps. What did each one actually change in the hardware?

1. The Four Steps

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
1.  SHARED COAX          one cable, all stations tapped onto it
        │                one collision domain, no active devices

2.  REPEATER             two segments, signal regenerated between them
        │                STILL one collision domain — and now a bigger one

3.  HUB                  N ports, signal regenerated onto all others
        │                STILL one collision domain, N stations in it

4.  BRIDGE / SWITCH      frames received, decided about, forwarded
                         ONE COLLISION DOMAIN PER PORT
A four-step flow: shared coax with one collision domain; a repeater joining two segments, still one collision domain but larger; a hub with N ports, still one collision domain with N stations; and a bridge or switch, which gives each port its own collision domain.Coax to switch, by what each step changed1Shared coaxone domain, no active device2Repeaterreach bought with timing budget3HubN stations, still one domain4Bridge / switchone domain per port
Figure 1 — four steps, and only the last one is a different kind of device.

Steps 2 and 3 are the same device with a different port count. Step 4 is a different kind of device altogether.

The interesting question is why steps 2 and 3 existed at all, given they did nothing for contention. The answer is that they solved a different problem, and solving it was genuinely necessary — which is Section 2.

2. Coax, and the Problem the Repeater Solved

The original medium was a single coaxial cable with stations tapped onto it. Physically it is the honest form of everything Chapter 1.1 described: one conductor, several transmitters, no arbiter.

It has two limits, and only one of them is about contention.

The contention limit is the one the first two chapters own: more stations means more collisions, and a longer cable means a longer round trip inside a fixed budget.

The physical limit is separate and comes first. A signal attenuates and distorts as it travels. Past some distance the receiver cannot recover it reliably — not because of collisions but because the waveform has degraded. There is also a limit on how many taps a segment can carry, because each one loads the cable.

A repeater solves the second problem and nothing else. It receives a degraded signal on one segment, regenerates it — restores amplitude, retimes the edges — and drives it onto the other. Two segments become one electrically continuous medium with the reach of two.

3. RTL 1 — An N-Port Repeater

The clearest way to see that a repeater cannot help contention is to write one. It is a strikingly small module, and its smallness is the finding.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// SYNTHESIZABLE. Logical model of an N-port repeater: whatever arrives on
// one port is driven onto every other, and a collision anywhere is a
// collision everywhere.
//
// NOT a real repeater: no regeneration, no retiming, no jabber protection,
// no auto-partition. Those are analog and management functions.
module repeater_hub #(
  parameter int unsigned PORTS = 4
) (
  input  logic clk,
  input  logic rst_n,
 
  // Per-port receive: a port is carrying a signal, and the bit it carries.
  input  logic [PORTS-1:0] rx_active,
  input  logic [PORTS-1:0] rx_bit,
 
  // Per-port transmit, driven onto the medium at that port.
  output logic [PORTS-1:0] tx_active,
  output logic [PORTS-1:0] tx_bit,
 
  // Per-port carrier sense and collision indications, as each attached
  // station's MAC observes them.
  output logic [PORTS-1:0] carrier_sense,
  output logic [PORTS-1:0] collision_detect,
 
  output logic             domain_collision  // any collision, anywhere
);
 
  // THE ENTIRE DEVICE, in one line: more than one port carrying a signal is
  // a collision. There is no arbitration here, no queue, and no port that
  // wins — because a repeater has nothing to arbitrate WITH. Every station
  // in this domain will see this and back off, which is exactly what
  // Chapter 1.2's backoff engine is for.
  assign domain_collision = ($countones(rx_active) > 1);
 
  always_comb begin
    for (int unsigned p = 0; p < PORTS; p++) begin
      // Repeat everything from every OTHER port onto this one. The exclusion
      // of the port's own receive is the only selectivity in the device, and
      // it is not filtering — it is just not echoing a station to itself.
      automatic logic others_active = 1'b0;
      automatic logic others_bit    = 1'b0;
      for (int unsigned q = 0; q < PORTS; q++) begin
        if (q != p) begin
          others_active |= rx_active[q];
          // Superposition, not selection. With two sources active the result
          // is neither station's data — which is the physical truth of a
          // collision and the reason no receiver can recover either frame.
          others_bit    |= (rx_active[q] & rx_bit[q]);
        end
      end
      tx_active[p] = others_active;
      tx_bit[p]    = others_bit;
 
      // Carrier sense at a port is "something is on the medium here",
      // INCLUDING this station's own transmission — the property Chapter 1.1
      // showed makes a `!carrier_sense` guard on tx_enable a fatal mistake.
      carrier_sense[p]    = rx_active[p] || others_active;
      collision_detect[p] = domain_collision;
    end
  end
 
  // A repeater has no datapath state at all. This register exists ONLY for
  // observability — a device that propagates collisions but cannot report
  // how many it has seen is undiagnosable in the field.
  logic [15:0] collision_cnt_q;
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n)                                    collision_cnt_q <= '0;
    else if (domain_collision && &collision_cnt_q != 1'b1) collision_cnt_q <= collision_cnt_q + 1'b1;
  end
 
endmodule

Classification: synthesizable.

What it teaches: the finding is in what the module does not contain. No memory on the datapath. No address comparison. No queue. No per-port decision. Add ports and you add stations to one contention region — you do not add capacity, because there is nothing in the device that could allocate any.

collision_detect[p] = domain_collision for every port is the line that settles the chapter's central question. Every attached station is told about every collision anywhere in the domain, because a repeater reproduces signal conditions and a collision is a signal condition. Every station's Chapter 1.2 backoff engine will engage, including stations on segments where nothing happened.

The |= superposition is deliberate and is not a shortcut. A multiplexer that selected one active port would model a device that arbitrates, and no such device exists here. Two simultaneous sources produce a signal that is neither of theirs, which is precisely why both frames are lost and why Chapter 1.1 insisted a collision has no winner.

Deliberately simplified: no regeneration, retiming or amplitude restoration, which is what a real repeater is actually for; no jabber protection; no auto-partition of a permanently faulty port; no per-port delay, which Section 4 adds as a parameter rather than as logic.

Production implication: a real repeater restores signal amplitude and edge timing, partitions a port that transmits continuously so one faulty station cannot destroy the domain, counts collisions and partition events per port, and specifies its own propagation delay — because that delay is an input to every collision-domain budget the network designer computes.

4. RTL 2 — What Each Hop Costs the Budget

Chapter 1.2 §13 established the collision-domain budget: round-trip propagation plus jam must fit inside slot time. It does not need re-deriving. What this chapter adds is that each repeater hop spends from it, and that the spending is silent.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ELABORATION-TIME CHECK. Accumulates a topology's round-trip delay hop by
// hop and fails the build when the collision domain no longer fits inside
// slot time.
//
// Extends Chapter 1.2's budget check with the per-hop term a repeater adds.
// Delay figures are the INTEGRATOR'S; the standard's per-media path-delay
// tables are the real source for them.
module repeater_chain_budget #(
  parameter int unsigned SLOT_TIME_BITS    = 512,      // NORMATIVE (10/100 Mb/s)
  parameter int unsigned JAM_BITS          = 32,       // NORMATIVE
  parameter int unsigned BIT_TIME_PS       = 100_000,  // 100 ns at 10 Mb/s
  parameter int unsigned SEGMENTS          = 3,
  parameter int unsigned SEGMENT_M         = 180,
  parameter int unsigned VELOCITY_M_PER_US = 200,      // ~2e8 m/s
  parameter int unsigned REPEATER_DELAY_NS = 400,
  parameter int unsigned DETECT_LATENCY_NS = 600
) ();
 
  // A chain of S segments has S-1 repeaters between them.
  localparam int unsigned REPEATERS = (SEGMENTS > 0) ? SEGMENTS - 1 : 0;
 
  localparam int unsigned CABLE_ONE_WAY_PS =
    (SEGMENTS * SEGMENT_M * 1_000_000) / VELOCITY_M_PER_US;
 
  localparam int unsigned CABLE_RT_PS  = 2 * CABLE_ONE_WAY_PS;
  localparam int unsigned REPEAT_RT_PS = 2 * REPEATERS * REPEATER_DELAY_NS * 1000;
  localparam int unsigned DETECT_PS    = DETECT_LATENCY_NS * 1000;
  localparam int unsigned JAM_PS       = JAM_BITS * BIT_TIME_PS;
 
  localparam int unsigned REQUIRED_PS = CABLE_RT_PS + REPEAT_RT_PS + DETECT_PS + JAM_PS;
  localparam int unsigned BUDGET_PS   = SLOT_TIME_BITS * BIT_TIME_PS;
  localparam int unsigned USED_PCT    = (REQUIRED_PS * 100) / BUDGET_PS;
 
  // The number the chapter is about: what ONE more repeater hop costs. It is
  // charged twice — the signal crosses the device in each direction.
  localparam int unsigned PER_HOP_PS  = 2 * REPEATER_DELAY_NS * 1000;
  localparam int unsigned HOP_PCT     = (PER_HOP_PS * 100) / BUDGET_PS;
 
  if (REQUIRED_PS > BUDGET_PS) begin : g_over
    $error("repeater chain over budget: %0d segments and %0d repeaters need %0d ps against a %0d ps slot time (%0d%%). Each further hop costs another %0d%%.",
           SEGMENTS, REPEATERS, REQUIRED_PS, BUDGET_PS, USED_PCT, HOP_PCT);
  end
 
  // The warning matters more than the error. A chain at 85% passes, ships,
  // and fails the day someone adds one more repeater — as intermittent late
  // collisions, which Chapter 1.2 section 18 shows is a signature that points
  // at everything except cable length.
  if (REQUIRED_PS <= BUDGET_PS && USED_PCT > 80) begin : g_tight
    $warning("repeater chain uses %0d%% of slot time; one more hop adds %0d%% and would exceed it.",
             USED_PCT, HOP_PCT);
  end
 
endmodule

Classification: elaboration-time check; no synthesizable logic.

What it teaches: that "adding a repeater" is a timing decision, not a cabling one. Extending reach and shrinking the collision-domain margin are the same action, and there is no run-time indication that the margin has been spent — the network works until the day two stations at the extremes collide in the window the last hop created.

Why the per-hop figure is reported alongside the total. A total says whether the current topology fits. The per-hop figure says whether the next change will, which is the question actually being asked when someone is standing in a wiring closet with another repeater. Reporting only the total makes the check a gate; reporting both makes it advice.

The relationship worth carrying: every hop is charged twice, because the signal crosses the device in each direction of the round trip. A device advertising a 400 ns delay costs 800 ns of budget.

Deliberately simplified: uniform segment lengths and identical repeaters; one worst-case path rather than every station pair; no per-media differentiation; no receive-side asymmetry between different station types.

Production implication: a real check evaluates every station pair against per-media path-delay values from the standard, uses the actual delay of each specific device rather than a uniform figure, and is generated from the same topology description that produces the cabling records — so the model and the installation cannot drift apart.

5. Twisted Pair, and the Change That Mattered Later

The move from coax to twisted pair is usually described as a cabling change. Structurally it is a topology change with one consequence that does not pay off for another decade.

Coax is a bus. One conductor, stations tapped along it, a genuinely shared medium in the electrical sense.

Twisted pair is a star. Each station has its own cable to a central device. Electrically there is no longer one shared conductor at all — the sharing is now performed by the device in the middle.

That distinction is what makes step 4 possible. On a bus there is no place to put a decision; the medium is the medium. Once every station has a private cable to a central point, the central point can be anything — and for a decade it was a hub, which chose to behave exactly like the bus it replaced.

And twisted pair separates the directions. A BASE-T link uses different pairs for transmitting and receiving. On coax, transmit and receive were the same conductor and simultaneous bidirectional operation was physically impossible. On twisted pair it is physically possible from the beginning — and unusable, because as long as the central device is a repeater, a station transmitting while receiving is a collision by definition.

6. The Bridge — Where a Decision First Appears

A bridge does something no repeater can: it receives a whole frame before deciding anything about it.

That single change produces every capability the rest of this track depends on.

Because it buffers the frameIt can
the frame is complete before any decisionvalidate the check value and discard a damaged frame instead of spreading it
it has the destination addressforward to one port instead of all of them
it has the source addresslearn where that station is — Chapter 12.2
each port transmits independentlyrun its own access method per port, so a collision on one port is not a collision on another
it is not reproducing a signalconnect segments of different speeds, since it re-transmits rather than repeats

The last two are the ones that end this chapter's story. Per-port independence is the partition of the collision domain, and re-transmission rather than repetition is what makes a 10 Mb/s segment and a 100 Mb/s segment connectable at all.

And it costs something specific: latency. A repeater's delay is a regeneration time measured in bit times. A bridge must receive the whole frame before it forwards, so its delay includes the frame's own serialization time — Chapter 8.1's term, and for a maximum-size frame it is far larger than any repeater delay. That cost is exactly what cut-through switching later attacks, and Chapter 12.6 owns the trade.

7. Why a Bridge Can Join Two Different Speeds

Section 6's table listed speed conversion almost in passing. It deserves its own treatment, because it is the clearest demonstration that repeating and re-transmitting are different operations rather than the same one done better.

A repeater cannot change rate, and the reason is definitional. It reproduces a signal. A signal arriving at one rate and leaving at another is not the same signal — the bit times differ, so the waveform differs, so it has not been repeated. There is also nowhere to put the difference: if the output rate is slower than the input, bits arrive faster than they can leave and something must hold them, and a repeater has nothing that holds anything.

A bridge changes rate for free, and "for free" is precise. It already holds the whole frame. Once the frame is in a buffer, the rate at which it was received and the rate at which it is sent are independent facts — the buffer decouples them, which is what a buffer does. The bridge is not converting a signal; it is re-transmitting the frame's contents onto a different medium under that medium's own rules.

Three consequences a hardware engineer meets.

The buffer must absorb the rate difference for a whole frame. Receiving a maximum-size frame at 100 Mb/s and transmitting it at 10 Mb/s means the output is ten times slower for the frame's whole duration. Store-and-forward already requires holding the frame, so the depth is already there — but the occupancy now persists ten times longer, and a port doing this continuously needs proportionally more buffering than one bridging equal rates.

Sustained rate mismatch is an overrun, not a conversion. A bridge can convert rate; it cannot create capacity. A 100 Mb/s port sending continuously to a 10 Mb/s port will fill any finite buffer and then discard. This is the origin of one of the most common real-world switch complaints, and the honest answer is that the topology asked for more than the link can carry.

And this is where flow control becomes necessary rather than merely useful. The buffer's job is to absorb a transient difference. A persistent one needs the sender slowed down, and nothing in the mechanisms built so far can do that — a shared medium throttled a sender incidentally, by being busy, and a private full-duplex link does not. Module 14 exists to fill that gap, and Chapter 1.5 shows exactly when it opened.

8. RTL 3 — A Bridge Port with Store-and-Forward

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// SYNTHESIZABLE. One bridge port: receive a whole frame, validate it, decide
// about it, then transmit. The buffer is the device.
//
// NOT a switch: no learning, no forwarding table, no VLANs, no real FCS.
// Module 12 owns those. This is the store-and-forward structure alone.
module bridge_port #(
  parameter int unsigned WIDTH     = 8,
  parameter int unsigned MAX_BEATS = 64,
  localparam int unsigned CNT_W    = $clog2(MAX_BEATS + 1)
) (
  input  logic clk,
  input  logic rst_n,
 
  // Receive side, from this port's own medium.
  input  logic             rx_valid,
  input  logic [WIDTH-1:0] rx_data,
  input  logic             rx_last,
  input  logic             rx_error,      // stands in for an FCS failure
 
  // Forwarding decision, supplied by the (out-of-scope) lookup.
  input  logic             fwd_permit,
 
  // Transmit side, onto a DIFFERENT port's medium.
  output logic             tx_valid,
  output logic [WIDTH-1:0] tx_data,
  output logic             tx_last,
  input  logic             tx_ready,
 
  output logic             rx_dropped_err,   // discarded: damaged
  output logic             rx_dropped_full,  // discarded: no room
  output logic             rx_filtered       // discarded: not forwarded
);
 
  typedef enum logic [1:0] {
    B_RECEIVE = 2'd0,   // filling the buffer
    B_DECIDE  = 2'd1,   // frame complete; one cycle to choose
    B_SEND    = 2'd2    // draining the buffer to the far port
  } b_state_e;
 
  b_state_e         state_q, state_d;
  logic [WIDTH-1:0] buf_q [MAX_BEATS];
  logic [CNT_W-1:0] len_q, rd_q;
  logic             err_q, full_q;
 
  // THE STRUCTURAL DIFFERENCE FROM SECTION 3, in one signal: this port
  // accepts receive beats while it is receiving, and NOT while it is
  // sending. A repeater has no equivalent — it cannot decline a bit,
  // because it is reproducing a signal rather than accepting data.
  wire rx_accept = (state_q == B_RECEIVE) && rx_valid;
 
  always_comb begin
    state_d = state_q;
    case (state_q)
      B_RECEIVE: if (rx_accept && rx_last) state_d = B_DECIDE;
      // A frame that is damaged, over-length, or not permitted never enters
      // B_SEND at all. Discarding here rather than mid-transmission is the
      // whole reason the frame was buffered first.
      B_DECIDE:  state_d = (err_q || full_q || !fwd_permit) ? B_RECEIVE : B_SEND;
      B_SEND:    if (tx_valid && tx_ready && (rd_q == len_q - 1'b1)) state_d = B_RECEIVE;
      default:   state_d = B_RECEIVE;
    endcase
  end
 
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      state_q <= B_RECEIVE; len_q <= '0; rd_q <= '0;
      err_q <= 1'b0; full_q <= 1'b0;
    end else begin
      state_q <= state_d;
 
      if (state_q == B_RECEIVE) begin
        if (rx_accept) begin
          // Over-length is latched rather than truncating the frame: a
          // partial frame forwarded is worse than a frame discarded, because
          // the far end cannot tell it was truncated.
          if (len_q == CNT_W'(MAX_BEATS)) full_q <= 1'b1;
          else begin
            buf_q[len_q] <= rx_data;
            len_q        <= len_q + 1'b1;
          end
          if (rx_error) err_q <= 1'b1;
        end
        if (state_d == B_DECIDE) rd_q <= '0;
      end else if (state_q == B_SEND && tx_valid && tx_ready) begin
        rd_q <= rd_q + 1'b1;
      end
 
      // Clear on return to receive, whichever path got us there.
      if (state_d == B_RECEIVE && state_q != B_RECEIVE) begin
        len_q <= '0; err_q <= 1'b0; full_q <= 1'b0;
      end
    end
  end
 
  assign tx_valid = (state_q == B_SEND);
  assign tx_data  = buf_q[rd_q];
  assign tx_last  = tx_valid && (rd_q == len_q - 1'b1);
 
  // Three DISTINCT discard reasons, counted separately. A single "dropped"
  // signal would merge a damaged frame, an over-long frame and a correctly
  // filtered one — three completely different conclusions from one number.
  assign rx_dropped_err  = (state_q == B_DECIDE) && err_q;
  assign rx_dropped_full = (state_q == B_DECIDE) && !err_q && full_q;
  assign rx_filtered     = (state_q == B_DECIDE) && !err_q && !full_q && !fwd_permit;
 
endmodule
A three-state machine. RECEIVE is the start state and fills the buffer. When the frame is complete it moves to DECIDE. From DECIDE, a clean and permitted frame moves to SEND; a damaged, over-long or filtered frame returns to RECEIVE. SEND returns to RECEIVE after the last beat.RECEIVEDECIDESENDframe completeframecompleteclean · permittedclean · permitteddamaged · over-long · filtereddamaged · over-long · filtereddamaged ·over-long ·…last beatlast beat
Figure 2 — the bridge port: three states, and a decision that needs the whole frame.

Classification: synthesizable.

What it teaches: that the buffer is not an optimisation, it is the enabling structure. Every capability in Section 6's table requires the whole frame to be present, and the whole frame can only be present if something held it. A repeater's inability to filter, validate or forward selectively is a consequence of having nowhere to put the frame while it thinks.

Why the three discard outputs are separate. A damaged frame means the link or a station has a problem. An over-long frame means a configuration mismatch, usually MTU. A filtered frame means the bridge is working exactly as intended. Merging them into one counter produces a number from which no conclusion can be drawn — the failure mode Chapter 1.2 §18 describes for collision counters, in a different device.

The err_q latch rather than an immediate abort is a deliberate choice worth arguing about. Aborting reception the moment an error appears would free the buffer sooner. It would also mean the port stops counting the frame's length, so an over-length and damaged frame reports only the damage — and the two have different causes. Receiving to the end and deciding once is slower and diagnostically complete.

Deliberately simplified: one frame in flight; no forwarding table, so fwd_permit arrives from outside; a beat-granular buffer with no byte enables; rx_error stands in for a check-value result that Module 6 actually computes; no cut-through path.

Production implication: a real port has multiple frames in flight with a proper queue, computes and checks the FCS itself, holds per-port and per-priority occupancy for flow control, implements a cut-through mode with a defined fallback to store-and-forward, and counts each discard reason in a saturating counter with defined clear-on-read.

9. RTL 4 — The Two Ports, Side by Side

The difference between the two devices is easiest to see when the two port models are written against the same interface. The port lists are the argument.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// A REPEATER PORT. Combinational. No state, no storage, no decision.
module hub_port_face (
  input  logic       rx_active,
  input  logic       rx_bit,
  input  logic       others_active,   // any other port carrying a signal
  input  logic       others_bit,
  input  logic       domain_collision,
 
  output logic       tx_active,
  output logic       tx_bit,
  output logic       carrier_sense,
  output logic       collision_detect
);
  assign tx_active        = others_active;
  assign tx_bit           = others_bit;
  assign carrier_sense    = rx_active || others_active;
  // The defining line. A collision anywhere in the domain is reported HERE,
  // to a station that may be nowhere near it.
  assign collision_detect = domain_collision;
endmodule
 
 
// A BRIDGE PORT. Sequential. Storage, a decision, and per-port carrier.
module switch_port_face (
  input  logic       clk,
  input  logic       rst_n,
 
  input  logic       rx_valid,
  input  logic       rx_last,
  output logic       rx_ready,        // it can DECLINE. A repeater cannot.
 
  output logic       fwd_request,     // a decision it is now able to make
  input  logic       fwd_grant,
 
  output logic       tx_valid,
  input  logic       tx_ready,
 
  input  logic       local_collision, // THIS port's medium only
  output logic       carrier_sense,
  output logic       collision_detect
);
  logic busy_q, have_frame_q;
 
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      busy_q <= 1'b0; have_frame_q <= 1'b0;
    end else begin
      if (rx_valid && rx_ready && rx_last) have_frame_q <= 1'b1;
      else if (fwd_grant)                  have_frame_q <= 1'b0;
      busy_q <= tx_valid && !tx_ready;
    end
  end
 
  assign rx_ready         = !have_frame_q;
  assign fwd_request      = have_frame_q;
  assign tx_valid         = fwd_grant;
  assign carrier_sense    = rx_valid || busy_q;
  // The defining line, and the whole chapter. Only THIS port's medium can
  // produce a collision on this port. Whatever happens on any other port is
  // now invisible here, because the two are no longer one medium.
  assign collision_detect = local_collision;
endmodule

Classification: both synthesizable.

What it teaches: the entire chapter, in two port lists.

hub_port_face has no clock. That is not a simplification — a device with no state cannot have a clock on its datapath, and a device that must reproduce a signal cannot have state. From it follow: no rx_ready (it cannot decline a bit), no forwarding request (it has nothing to decide with), and collision_detect sourced from a domain-wide signal.

switch_port_face has a clock, storage, an rx_ready it can withhold, a forwarding request, and — the line that matters — collision_detect sourced from local_collision. One signal name is the difference between one collision domain and N of them.

Deliberately simplified: both are faces rather than complete ports; the bridge port holds one frame as a flag rather than a real buffer; arbitration between ports is out of scope.

Production implication: a real repeater port adds regeneration, jabber protection and auto-partition; a real bridge port adds a full queue, the FCS check, the address lookup interface and per-priority backpressure. Neither addition changes the structural difference above, which is why that difference is what these faces isolate.

10. The Partition, Stated Precisely

Replacing a repeater with a bridge changes the number of collision domains, and it is worth stating exactly what does and does not follow.

What is partitioned. Contention. Two stations on different ports never drive a common medium, so they cannot collide. Each port's collision domain contains that port and whatever is attached to it — one station, in the normal case.

What is not removed. Contention for the output port is still real: two ports can both want to send to a third at once. It has moved from the medium into the device, where it is resolved by queueing rather than by collision. Contention did not disappear, it changed venue — and that is the reason a switch needs buffers at all, which is the reason Module 14's flow control exists.

What follows for Chapter 1.2's budget. With one station per port, the round trip is one short cable. The budget is no longer close to binding, which is why the relationship between segment length and minimum frame size stops being an operational constraint — even though the minimum frame size stays, for the reasons Chapter 5.6 gives.

What follows for the MAC. With one station at each end of a private medium, the conditions for full duplex are satisfied, and the whole apparatus of Chapter 1.2 becomes unreachable logic. Chapter 1.5 develops exactly what that retires and what it creates in its place.

11. Waveform — The Same Collision, Two Devices

The most direct way to see the partition is one event, observed at a port that is not involved.

A collision on ports 0 and 1, as port 2 sees it

10 cycles
Ten clock cycles. Ports 0 and 1 both become active at cycle 2, producing a collision. Port 2 is idle for the whole trace. In the hub model, port 2 sees carrier sense and collision detect assert at cycle 2 even though it is not involved. In the switch model, port 2 sees neither.collision on ports 0 and 1collision on ports 0 and 1hub tells port 2 as wellhub tells port 2 as wellport 2 free againport 2 free againclkp0_activep1_activep2_activehub_p2_crshub_p2_colsw_p2_crssw_p2_colp2_wantsp2_deferst0t1t2t3t4t5t6t7t8t9
Figure 3 — port 2 is idle throughout; only the hub tells it there was a collision.

p2_active is low for the entire trace. The station on port 2 never transmits, and it is not part of the collision in any physical sense.

hub_p2_col asserts anyway. With a repeater in the middle, the collision is a signal condition on one medium that all three ports share, so port 2's MAC sees it and — as p2_defers shows — stops trying to transmit for the duration. Its Chapter 1.2 machinery engages over an event four cycles long that had nothing to do with it.

sw_p2_col never asserts. Port 2's medium is its own. The collision on ports 0 and 1 is invisible here, and the station on port 2 transmits whenever it likes. That is the partition, and it is one signal wide.

What is easy to miss: the switch has not made collisions rarer for ports 0 and 1. If two stations still share port 0's medium, they still collide exactly as before. What changed is that the domain got smaller — and in the normal modern case, with one station per port, it got small enough to contain no contention at all.

12. Assertions

Invariants of these models. None is an IEEE requirement.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// SVA over repeater_hub, bridge_port, and the two port faces.
 
// SAFETY — P1: a repeater reports every domain collision on every port. This
// is the property that makes it a repeater; a design that reported per-port
// would silently create the partition it is not supposed to have, and
// stations on quiet segments would transmit into a busy medium.
property p_repeater_reports_everywhere;
  @(posedge clk) disable iff (!rst_n)
  domain_collision |-> (&collision_detect);
endproperty
a_repeater_global : assert property (p_repeater_reports_everywhere);
 
// SAFETY — P2: a repeater's schedule is data-independent — it has no
// schedule at all. Catches an "optimisation" that arbitrates between ports,
// which would make it a bridge with no buffer: it would have to drop the
// loser's bits with nowhere to put them.
property p_repeater_never_arbitrates;
  @(posedge clk) disable iff (!rst_n)
  ($countones(rx_active) > 1) |-> domain_collision;
endproperty
a_repeater_no_arbitration : assert property (p_repeater_never_arbitrates);
 
// SAFETY — P3: a bridge port never forwards a frame it marked damaged.
// The single most important property here: forwarding a bad frame spreads
// corruption that the buffer existed to contain.
property p_no_forward_damaged;
  @(posedge clk) disable iff (!rst_n)
  (state_q == B_DECIDE && err_q) |=> (state_q == B_RECEIVE);
endproperty
a_no_forward_damaged : assert property (p_no_forward_damaged);
 
// SAFETY — P4: a bridge port never transmits a partial frame. An over-length
// frame is discarded whole; a truncated forward is undetectable at the far
// end, which is strictly worse than a discard.
property p_no_partial_forward;
  @(posedge clk) disable iff (!rst_n)
  (state_q == B_SEND) |-> (len_q != '0 && !full_q);
endproperty
a_no_partial_forward : assert property (p_no_partial_forward);
 
// CONSERVATION — P5: exactly one discard reason per discarded frame. Merged
// reasons produce a counter from which no conclusion can be drawn.
property p_one_discard_reason;
  @(posedge clk) disable iff (!rst_n)
  $onehot0({rx_dropped_err, rx_dropped_full, rx_filtered});
endproperty
a_one_discard_reason : assert property (p_one_discard_reason);
 
// CAUSATION — P6: a bridge port declines receive while it is sending. This
// is the capability a repeater structurally lacks, and asserting it catches
// a bypass that would overwrite the buffer mid-transmission.
property p_bridge_declines_while_busy;
  @(posedge clk) disable iff (!rst_n)
  (state_q == B_SEND) |-> !rx_accept;
endproperty
a_bridge_declines : assert property (p_bridge_declines_while_busy);
 
// SAFETY — P7: a switch port's collision indication depends only on its own
// medium. The partition, as a property. A failure means a domain-wide signal
// leaked into a per-port face and the partition is not real.
property p_switch_port_is_local;
  @(posedge clk) disable iff (!rst_n)
  collision_detect == local_collision;
endproperty
a_switch_local : assert property (p_switch_port_is_local);
 
// SAFETY — P8: the buffer is cleared before the next frame. Catches a stale
// length or a stale error flag carried into a frame that is actually fine —
// which presents as random discards of good frames.
property p_buffer_cleared;
  @(posedge clk) disable iff (!rst_n)
  ($rose(state_q == B_RECEIVE)) |-> (len_q == '0 && !err_q && !full_q);
endproperty
a_buffer_cleared : assert property (p_buffer_cleared);
 
// LIVENESS — P9: a buffered frame is eventually forwarded or discarded.
// ASSUMPTION, stated: the far port eventually accepts. Without it this is
// false for a correct design.
assume property (@(posedge clk) s_eventually (tx_ready));
property p_frame_resolves;
  @(posedge clk) disable iff (!rst_n)
  (state_q == B_DECIDE) |-> s_eventually (state_q == B_RECEIVE);
endproperty
a_frame_resolves : assert property (p_frame_resolves);

The property that must not be written

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// FALSE for a correct design. Included as a warning, not as a check.
// property p_a_collision_affects_only_its_own_ports;
//   @(posedge clk) disable iff (!rst_n)
//   !rx_active[2] |-> !collision_detect[2];
// endproperty

It reads like the definition of a well-behaved network device, and against repeater_hub it is exactly backwards.

A repeater must tell every port about every collision. If it did not, a station on a quiet segment would observe an idle medium, transmit into a domain where a collision is already in progress, and make it worse. The global report is the correct behaviour, and P1 asserts it deliberately.

The property is true of switch_port_face and false of hub_port_face, which is the entire chapter. Writing it once, against both, is how an engineer discovers that they had been thinking of the two devices as differing in degree rather than in kind — and waiving it because "it fires on the hub" throws away P1, which is the property that catches a repeater that has silently stopped propagating collisions.

13. Verification

Monitors observe: every port's receive and transmit activity in the repeater; the domain collision signal against each port's collision indication; the bridge port's state, buffer length, error and full flags, and each of its three discard outputs; and both port faces' collision sources.

The scoreboard independently predicts which ports should see carrier and collision for a given set of active ports, and which frames should emerge from a bridge port given the frames offered and the permit decisions. It must compute the expected port set itself rather than reading domain_collision — a checker that reads the design's own aggregate agrees with the design about every aggregation bug in it.

Scenarios

  1. Single active port, repeater. One port receives, all others transmit the same bits. Verify no collision and correct fan-out.
  2. Two active ports, repeater. Verify domain_collision and that every port reports it, including inactive ones (P1). The chapter's central measurement.
  3. All ports active, repeater. Verify the collision indication does not depend on how many are active beyond two.
  4. Port count sweep. Elaborate at 2, 4, 8 and 16 ports and verify the fan-out and collision logic hold. Adding ports adds contenders, never capacity — the sweep makes that a tested claim.
  5. A station's own carrier. One port active, others idle. Verify that port's carrier_sense is high from its own transmission — the Chapter 1.1 property that makes a !carrier_sense guard on transmit enable fatal.
  6. Budget check, in and out of range. Elaborate repeater_chain_budget with a topology that fits and one that does not; verify the $error fires only for the second, and the $warning fires in the 80-to-100% band.
  7. Budget boundary. Elaborate at exactly 100% and at 99%. The off-by-one in a comparison that ships is the one nobody tested.
  8. Bridge, clean frame, permitted. Verify it is forwarded whole and in order.
  9. Bridge, damaged frame. Verify rx_dropped_err, no transmission at all (P3), and clean recovery.
  10. Bridge, over-length frame. Verify rx_dropped_full, no partial transmission (P4), and that the length counter did not wrap.
  11. Bridge, damaged AND over-length. Verify exactly one discard reason is reported (P5) and that the priority is deterministic.
  12. Bridge, frame not permitted. Verify rx_filtered and that it is distinguishable from both error cases.
  13. Bridge, receive offered while sending. Verify rx_ready is withheld (P6) and no buffer corruption.
  14. Bridge, back-to-back frames with no gap. Verify the buffer clears in time (P8) and the second frame is not contaminated by the first.
  15. Reset in each state of the bridge port. Verify no stale length, no stale error flag, and no partial frame emitted afterwards.

Coverage

Cross the active-port count against every port index in the repeater, so P1 is exercised for each inactive port individually rather than in aggregate. Cover bridge frames at 1 beat, MAX_BEATS-1, MAX_BEATS and MAX_BEATS+1. Cover the cross of err_q, full_q and fwd_permit — all eight combinations, because P5's one-hot property is only meaningful if the multi-cause cases occur. Cover reset in each bridge state.

A directed stimulus for the partition

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// NON-SYNTHESIZABLE — directed stimulus. Drives one collision on ports 0
// and 1 and checks what an UNINVOLVED port is told, in both devices.
task automatic collision_visibility_at_uninvolved_port();
  // Port 2 is silent for the whole task. It is the observer.
  rx_active <= 4'b0000;
  @(posedge clk);
 
  // A collision between ports 0 and 1.
  rx_active <= 4'b0011;
  @(posedge clk);
  @(posedge clk);
 
  // The repeater MUST report it at port 2. This is not a defect; a repeater
  // that stayed quiet here would let port 2's station transmit into an
  // in-progress collision.
  assert (hub.collision_detect[2])
    else $error("repeater failed to propagate a collision to an uninvolved port");
  assert (hub.carrier_sense[2])
    else $error("repeater failed to propagate carrier to an uninvolved port");
 
  // The switch port MUST NOT. Port 2's medium is its own.
  assert (!sw_p2.collision_detect)
    else $error("switch leaked another port's collision — the partition is not real");
 
  // And the consequence, which is the point: the port-2 station is blocked
  // behind the repeater and free behind the switch.
  assert (hub_p2_station.deferring && !sw_p2_station.deferring)
    else $error("partition did not change what the uninvolved station may do");
 
  rx_active <= 4'b0000;
endtask

The final assertion is the whole chapter in one line. The two devices are given identical stimulus and an uninvolved station reaches opposite conclusions about whether it may transmit. Everything else in this file explains why.

14. Debugging — Which Device Are You Actually Behind

Topology faults have signatures that point at the device class, and the first question is usually not the one people ask.

SymptomLikely device relationshipFirst check
Collisions on a port with one station attachedYou are behind a repeater, or duplex is mismatchedDuplex configuration first; then whether the device is genuinely a switch
One station's traffic slows when an unrelated station is busyShared collision domainAre they on the same port, or is the device a hub?
Intermittent late collisions, worsening after a topology changeThe budget is overspent — Section 4Count repeater hops and total span against slot time
Frames arriving damaged at the far endA repeater is propagating a fault a bridge would have containedWhether the path has a device that validates the check value
Adding ports made everything slowerPorts were added to one domain, not as new domainsWhether the device buffers, which decides which it did

The last row is the most common misdiagnosis in this chapter's territory. Adding stations to a hub adds contenders and propagation delay to one domain, so aggregate performance falls. Adding ports to a switch adds independent domains, so it does not. Both are described as "adding ports", and the outcomes are opposite.

And the third row connects directly to Chapter 1.2. Late collisions are never normal, and one of their three causes is a collision domain that is physically too large. A topology change that added a repeater hop is exactly how a domain crosses the line, and the fault appears afterwards with no obvious link to the change — because Section 4's budget has no run-time indicator.

15. Common Misconceptions

"A hub and a switch differ mainly in speed."

The wrong model: both connect stations; a switch is a faster hub; the difference is performance.

What it costs: the fix for a saturated hub looks like "buy a faster hub", and collision-domain size looks like a tuning parameter rather than a topology fact. It also hides why a switch changes latency predictability and not just throughput.

The corrected model: they differ in kind. A repeater reproduces a signal and cannot buffer, so all its ports are one collision domain. A bridge receives whole frames and must buffer, so each port is its own. Section 9's two port lists are the difference — one has a clock and an rx_ready, the other structurally cannot.

"A repeater improves the network because it extends its reach."

The wrong model: more reach is more capability, so a repeater is an improvement.

What it costs: every hop is added without accounting for its cost, and the collision-domain budget is spent silently until the network starts producing late collisions with no apparent cause — after a change that looked purely additive.

The corrected model: a repeater buys physical reach and pays in timing budget, charged twice because the signal crosses it in each direction. It does nothing whatsoever for contention, and it makes contention worse by putting more stations and more delay into one domain. Section 4 makes both halves of that trade a number.

"Twisted pair replaced coax because it is faster."

The wrong model: a cabling upgrade for bandwidth.

What it costs: the topology consequence is missed, so the reason switching became possible looks unrelated to cabling — and the origin of full duplex looks like a MAC feature rather than a physical-layer capability that had been waiting.

The corrected model: the important change was bus to star. Once every station has a private cable to a central point, the central point can make decisions — which a shared conductor offered nowhere to do. Separate transmit and receive pairs also made full duplex physically possible years before a repeater in the middle stopped forbidding it. Chapter 1.5 collects that debt.

"A switch eliminates contention."

The wrong model: switching removes collisions, therefore switching removes contention.

What it costs: a design that assumes a switched fabric cannot congest, and is then surprised by drops, latency variation and the need for flow control — all of which exist because contention is still present.

The corrected model: a switch relocates contention. Two ports can still want the same output port at the same instant. The conflict has moved from the medium, where it was resolved destructively by collision, into the device, where it is resolved constructively by queueing. That is a large improvement and not an elimination — and it is exactly why a switch needs buffers, why those buffers can fill, and why Module 14 exists.

16. Interview Reasoning

A hub is a repeater and a switch is a bridge, and the difference is structural rather than a matter of performance.

The chain a strong answer walks:

  • A repeater reproduces a signal. To do that it must forward bits as they arrive, so it cannot buffer, which means it has no frame, no address, and nothing to decide with.
  • Therefore it forwards everything everywhere, it must propagate collisions — a station on a quiet segment would otherwise transmit into an in-progress collision — and all its ports are one collision domain.
  • A bridge receives a whole frame before deciding. That requires a buffer, and the buffer is what makes everything else possible: validating the check value, forwarding to one port, learning source addresses, and running an independent access method per port.
  • So each bridge port is its own collision domain. Two stations on different ports never share a medium and cannot collide.

What separates a good answer from a complete one: naming the buffer as the enabling structure rather than listing features, and adding that a switch relocates contention rather than eliminating it — two ports can still want the same output port, and that conflict is now resolved by queueing, which is why switches need buffers and flow control.

The follow-up to be ready for: what does a repeater cost? Propagation delay, charged twice because the signal crosses it in each direction, spent out of the fixed slot-time budget. Adding hops shrinks the collision-domain margin with no run-time indication, and the eventual symptom is intermittent late collisions after a change that looked purely additive.

17. Understanding Check

18. What's Next

Four steps, and the shape of the story is that only one of them touched the problem the first two chapters solved. Coax was the honest shared medium. Repeaters and hubs extended it, spent its timing budget, and left contention exactly where it was. Bridges introduced a buffer, and with it the ability to decide — which partitioned the collision domain, one port at a time.

The final state is a link with one station at each end, a private medium, separate pairs for each direction, and no possibility of contention between independent MACs. Every condition Chapter 1.2's machinery was built for is now false.

Chapter 1.5 — Full Duplex and What It Removed from the MAC collects that. It shows precisely which of Chapter 1.2's six blocks become unreachable logic, what survives and why, and the new problem the change created — because full duplex removed a constraint that had been doing useful work by accident, and something had to replace it.

The full path is on the Ethernet curriculum index.

Continue learning

Standards & specifications

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

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

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

Where this fits

Part of the Ethernet curriculum.