Skip to content
VLSI Mentor

Ethernet · Module 1

The Shared-Medium Problem

Why several independent transmitters on one medium is a distributed timing problem, not a formatting problem. Propagation delay makes every station's view of the medium stale, so two locally correct decisions can still collide — and that is the constraint the Ethernet MAC was built around.

Most Ethernet material opens with a frame: preamble, then destination address, then source address. That ordering teaches a byte layout and skips the reason the layout exists.

Ethernet was not invented to format bytes. It was invented to answer a harder question, and the frame is a consequence of the answer rather than the starting point.

When several independent transmitters are attached to one physical medium and none of them can see what the others are doing right now, how does any one of them decide that it may transmit?

That question has a hardware answer, and the answer is what a MAC is. This chapter develops the problem precisely enough that the next chapter's algorithm reads as the only reasonable response to it rather than as an arbitrary historical artefact.

1. What Changes When the Medium Is Shared

Two topologies, and one difference that produces every problem below.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
Dedicated (point-to-point):
 
    A ─────────────────────── B
 
Shared:
 
    A ─┬─────┬─────┬─────┬───
       │     │     │     │
       B     C     D     E

On the dedicated link, A's transmit engine owns its transmit path outright. Nothing else can drive it. A's only scheduling question is do I have data, and the answer is entirely local — it depends on state A holds in its own registers, clocked by A's own clock. There is no external condition to evaluate, so there is nothing to be wrong about.

On the shared medium, A's transmit engine owns nothing. The path it would drive is the same path B, C, D and E would drive, and it is a single electrical resource: one signal at a time, or nothing coherent at all. A's scheduling question becomes do I have data, and may I send it, and the second half of that question is not answerable from local state.

That second half is the entire subject. Everything else in this chapter is a consequence of it:

  • The condition A must evaluate lives outside A.
  • Evaluating it requires observing the medium.
  • Observation is not instantaneous.
  • Therefore A can only ever evaluate a past condition and act in the present.

A dedicated link has none of these steps, which is why the comparison is worth making explicitly. The same contrast drove the parallel-bus-to-serial-link transition on the host side — PCIe's shared-bus chapter reaches the same conclusion from a different direction, and point-to-point links is what it concluded.

2. Contention Is Not Collision

These two words are used interchangeably in casual writing, and the conflation destroys the ability to reason about the system. They describe different things at different layers.

Contention is a demand condition. Two or more stations want the medium during an overlapping interval. Contention is present whenever the offered load comes from more than one source, and it is present even on a segment where nothing ever goes wrong. Contention is not a fault. It is the normal state of a shared resource with more than one user.

Collision is a physical outcome. Two or more stations actually drove the medium during an overlapping interval, and the resulting signal is not a valid transmission from any of them. Collision is one possible consequence of contention that the access protocol failed to resolve in advance.

The relationship is one-directional and worth stating precisely:

  • Contention without collision is the success case. The stations wanted the medium at overlapping times, and the access mechanism serialised them. This is what a working shared segment does all day.
  • Collision without contention is impossible. If only one station wanted the medium, only one drove it.
  • Contention with collision is the case the protocol did not resolve in time — and Section 4 shows why "in time" is a hard constraint rather than a matter of effort.

3. The Fact That Breaks Every Simple Answer

A signal takes time to travel down a medium. This is not a subtlety; it is the whole difficulty, and every naive access scheme fails on it.

Concretely: when station A begins driving the medium, the resulting signal exists at A immediately and at a station 200 m away only after the time it takes to cover 200 m. Until that moment, the distant station's receiver observes exactly what it observed before — an idle medium — because nothing has physically arrived.

That distant station is not malfunctioning. Its carrier detector is working correctly and reporting the truth about the medium at its own location. The problem is that the truth is location-dependent, and there is no location from which the medium's global state can be observed.

Three consequences follow, and all three are load-bearing for the rest of the track.

Every observation is stale. A station's view of the medium is always delayed by the propagation time from wherever the relevant event occurred. There is no way to reduce this to zero and no way to detect that it has happened. "The medium is idle" always means "the medium was idle at my location, and I have no information about what has been launched elsewhere and has not yet arrived".

Two correct decisions can conflict. If A and B each observe an idle medium and each begins transmitting, both acted correctly on the information available to them. There is no bug to find in either station. This is the single most important idea in the chapter, because it means the access protocol cannot be built on prevention alone.

The problem is distributed, not local. No station holds enough state to make a globally correct decision, and no station can be given that state, because acquiring it would itself take a propagation delay. This is why the shared medium is fundamentally an arbitration problem over a network with delay — and why, as Section 5 shows, the schemes that do eliminate collisions do so by changing the system model rather than by reasoning harder.

4. A Worked Timing Example

Numbers make the constraint concrete. The following are illustrative and chosen for arithmetic clarity — the normative values that Ethernet actually fixes are Chapter 1.2's subject and are deliberately not used here.

QuantityIllustrative valueNote
Distance A to B200 mone segment
Signal velocityapproximately 2 × 10⁸ m/sroughly two-thirds of the speed of light, a common approximation for a copper channel
One-way propagation, A to B1.0 µs200 m divided by 2 × 10⁸ m/s
Signalling rate10 Mb/sso one bit time is 100 ns
One-way propagation, in bit times10 bit times1.0 µs divided by 100 ns

Now run a specific case. A has a frame queued and starts first; B's frame becomes ready shortly afterwards.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
t = 0.0 µs   A senses the medium: idle. A begins transmitting.
             A's signal starts travelling toward B.
 
t = 0.6 µs   B senses the medium: IDLE — correctly, because A's signal
             has covered only 120 m and has not reached B.
             B begins transmitting.
 
t = 1.0 µs   A's leading edge arrives at B. B's receiver now sees energy
             that B did not originate. B's collision detector asserts.
 
t = 1.6 µs   B's leading edge arrives at A (B started at 0.6, plus 1.0 µs
             of propagation). A's collision detector asserts.

Four facts fall out of that trace, and each one becomes a hardware requirement later.

Neither station made a mistake. At t = 0.6 µs the medium genuinely was idle at B's location. A carrier detector that reported "busy" there would have been reporting something false.

The two stations learn at different times. B knows at 1.0 µs, 0.4 µs after it started. A knows at 1.6 µs, a full 1.6 µs after it started. There is no instant at which both stations know. Any recovery mechanism must therefore work correctly when the participants have inconsistent knowledge — which is why the recovery is not simply "the loser stops".

The wasted interval is bounded by the geometry, not by the data. A occupied the medium for 1.6 µs before discovering the attempt was already ruined. That number came from cable length and signal velocity. It has nothing to do with frame contents, frame length, or how the stations are implemented.

The worst case is a full round trip. Push B's start as late as it can be while still causing a collision: if B starts at t = 0.999 µs — one instant before A's signal arrives — then B's signal reaches A at t = 1.999 µs, just under two one-way propagation times after A began.

That last line is the constraint the whole of Chapter 1.2 is built on:

Station A senses the medium and finds it idle, then begins transmitting. Before A's signal arrives, station B senses the medium, also finds it idle, and begins transmitting. A's signal then reaches B and B detects a collision. Separately and later, B's signal reaches A and A detects a collision.Two idle observations, one collisionStation AShared mediumStation Bsense: idle —correct at Abegin transmittingsense: idle — alsocorrect at Bbegin transmittingA's signal arrives:collision at BB's signal arrives:collision at A
Figure 1 — the collision as a sequence of decisions rather than voltages.

Read the last two messages as separate events rather than as one. They arrive at different times, so there is no instant at which both stations hold the same view of what happened — a property Section 13's scoreboard has to be built around.

5. Why the Obvious Fixes Do Not Work

Working through the tempting answers is more useful than being handed the eventual one, because each failure isolates a different property of the problem.

"Transmit whenever data is ready."

Fails immediately and for the obvious reason: nothing prevents two stations from having data ready at the same time. Worth stating anyway, because it identifies the minimum requirement — the transmit decision must depend on something other than local queue state.

"Sense the medium first, and only transmit if it is idle."

A real improvement, and it is genuinely half of the answer. It eliminates every collision in which one station starts well after another's signal has already arrived — which, on a lightly loaded segment, is the large majority of contention cases.

It cannot eliminate all of them. Section 4 is the counterexample: two stations that both sense idle within one propagation window of each other will both start, and both were right to. Carrier sense narrows the window in which a collision is possible to one round-trip propagation time. It cannot close it. A mechanism that reduces a failure's probability without bounding its possibility still needs a recovery path, and that is exactly why detection has to exist alongside sensing.

"Give every station a fixed time slot."

This does work — it makes collisions structurally impossible, because no two stations are ever permitted to transmit in the same interval. It is a real technique, used in real systems.

What it costs is the part worth understanding. A fixed schedule requires every station to agree on the slot boundaries, which means it requires synchronised time, which on a medium with propagation delay is itself a hard problem — the one that Module 16 spends five chapters on. It also allocates the medium to stations whether or not they have anything to send, so an idle station's slot is dead channel time, and a busy station cannot use it. On bursty traffic, where most stations are silent most of the time, that is a large fraction of the capacity.

Note the trade this represents: a fixed schedule converts a statistical problem (collisions under load) into a deterministic one (bounded, guaranteed access) and pays for it in utilisation. That is precisely the trade Time-Sensitive Networking makes deliberately, decades later, for traffic that needs a latency bound more than it needs throughput — Module 17.

"Use a central arbiter that grants permission."

Also works, and also changes the system rather than solving it.

A station must now request the medium and await a grant, so every transmission costs at least a round trip to the arbiter before any data moves — the propagation delay has not gone away, it has been moved into the critical path of every frame. The arbiter is a single point of failure and a capacity ceiling. And there must be some way to carry requests and grants, which is either a second medium or the shared medium itself, in which case the requests contend.

What this reveals: the arbitration is not optional; only its location is a choice. Placing it in a central point makes it explicit and costly. Distributing it across the stations makes it cheap and probabilistic. Ethernet chose the distributed form, which is the reason collisions exist at all — and, as Chapter 1.6 argues, a large part of the reason Ethernet was cheap enough to win.

Where this leaves the design. Sensing is necessary and insufficient. Scheduling and central arbitration both work by removing the distributed model rather than by operating within it. So a distributed shared medium needs the remaining option: sense before starting, detect while transmitting, and recover afterwards. Each of those three is a distinct piece of hardware, and Section 10 builds a controller with all three.

6. What a Collision Physically Is

Precision matters here, because a vague picture of a collision produces a vague picture of the detector.

A shared medium carries one signal. When two stations drive it simultaneously, the medium carries the superposition of what they drove — a waveform that is neither station's transmission. It is not interleaved data and not corrupted data in the sense of a few flipped bits. It is a different signal, and no receiver can extract either original from it.

Three consequences:

Both transmissions are lost, not one. There is no winner. A scheme where the "stronger" or "earlier" station succeeds would require the medium to arbitrate, and a passive medium does not arbitrate.

Receivers see something invalid, not something absent. A station listening to a collision receives energy — it just does not decode to a valid frame. This is why a MAC needs an explicit notion of an invalid reception rather than treating an unsuccessful frame as silence. Chapter 7.3 develops the full validity taxonomy.

The channel time is spent regardless. The interval consumed by a collision produced nothing and is not recoverable. At light load this is negligible. Section 8 explains why at high load it is not.

The detection mechanism itself is physical and medium-specific: it may compare transmitted against received signal, or monitor the medium's electrical state for a level that only concurrent drive can produce. The important architectural fact for a digital designer is what that machinery presents to the MAC — a signal asserting that this station's current transmission has been compromised. That is the interface Section 10 designs against, and the analog realisation behind it belongs to Module 3.

7. The Collision Domain

The set of stations that can collide with one another is the collision domain. It is a property of the physical topology, not of configuration, and naming it precisely matters because the next several modules manipulate it.

A single shared segment is one collision domain. Every attached station's transmission reaches every other, so every station contends with every other.

A repeater or hub extends the same collision domain. A repeater regenerates and forwards the signal on all other ports. It restores signal quality and physical reach, and it does nothing whatsoever about contention — a station on one hub port and a station on another are still in one contention region, because a transmission from either still reaches the other. Adding a hub adds stations to the domain and adds propagation delay to it. Both of those make the problem worse, and a hub was never intended to make it better.

A switch partitions collision domains. A switch receives a frame, makes a forwarding decision, and transmits it onward on the port it selected. Each port is a separate contention region: a station on port 1 and a station on port 2 do not share a medium and cannot collide. This is not an incremental improvement to contention management — it is the removal of contention between those stations, and it is the single most consequential change in Ethernet's history. Module 12 is the mechanism.

A full-duplex point-to-point link has no collision domain at all. Two stations, separate paths per direction, no shared resource to arbitrate for. Section 15 returns to this.

8. What Happens as the Domain Grows

The qualitative behaviour matters; specific throughput figures depend on frame-size distribution, traffic pattern, station count and topology, and are not asserted here.

More stations means more overlapping demand. With one active station there is no contention. Each additional independent source adds opportunities for two decisions to fall inside the same round-trip window. The number of pairs that can conflict grows faster than the number of stations.

Under heavy load the medium spends a growing fraction of its time on collisions. Each collision consumes channel time and delivers nothing, and the stations involved must retry — which places their retransmissions back into the same contended medium. Load produces collisions and collisions produce more load, which is the classic shape of a system that degrades rather than saturates gracefully.

Latency becomes not just larger but less predictable. A station's delay depends on how many other stations happened to want the medium, which is a random variable. Under contention, the variance grows faster than the mean — and for a designer, a transmit path whose worst case cannot be bounded is a different kind of problem from one that is merely slow. This is why a shared-medium segment cannot carry traffic with a hard latency requirement, and it is the direct motivation for the deterministic mechanisms in Module 17.

Fairness is statistical, not structural. Nothing in a distributed access scheme guarantees any station a turn. In practice access is roughly fair over long intervals, but a station can lose repeatedly, and any recovery policy that treats a repeatedly unlucky station identically to a lucky one will make that worse. This is a real design pressure on the retry policy — and the reason the policy in Chapter 1.2 adapts to how many attempts have already failed rather than retrying at a fixed rate.

A larger span makes every one of the above worse simultaneously, because it widens the window in which two decisions can conflict and lengthens the time before either station finds out.

9. From Medium Problem to RTL Problem

The chain from a physical property to a digital design is short, and following it explicitly is what makes the next section read as engineering rather than as history.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
MEDIUM PROBLEM
  One physical resource, several independent drivers,
  and a propagation delay that makes every observation stale.


MAC ACCESS-CONTROL PROBLEM
  Decide when this station may drive the medium; discover
  when that decision turned out to be wrong; recover.


RTL STATE-MACHINE PROBLEM
  Hold the decision as state. Gate the drive enable on it.
  Accept two asynchronous medium observations as inputs.
  Produce a bounded, deterministic response to each.


VERIFICATION PROBLEM
  The failing cases are timing coincidences, not data cases.
  They must be constructed deliberately, because a directed
  test that sends frames one at a time never produces one.

The middle two steps are where a digital designer's work actually is, and the top-to-bottom reading gives the interface: the medium's uncertainty reaches the MAC as exactly two signals — one saying the medium appears busy, one saying this transmission has been compromised. Everything in Section 3 arrives at the digital design through those two wires, and the controller's whole job is to hold enough state to respond to them correctly.

10. RTL — A Shared-Medium Transmit Controller

A block diagram of a shared-medium transmit controller, reading left to right. Three inputs enter the controller from the left: transmit request from the client, carrier sense from the PHY, and collision detect from the PHY. Three outputs leave to the right: transmit enable, jam enable, and a retry request to the external backoff policy.tx_reqclient: a frame is queuedcarrier_sensePHY: medium busy here, onepropagation delay agocollision_detectPHY: this transmission iscompromisedshared_medium_tx_ctrlholds the access decision asstatetx_enabledrive the medium this cyclejam_enablemake the collisionunambiguousretry_reqone pulse to the backoffpolicy — Chapter 1.212
Figure 2 — the controller's interface: three inputs in, three drive decisions out.

Every arrow carries one direction, and the figure is the dataflow view rather than the port list: the backoff policy's retry_grant and retry_abandon return into the controller and are shown in the module header below. What the picture is for is the shape — two of the three inputs come from the medium and are the only things the station can learn about it, and all three outputs are decisions about driving it.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// SYNTHESIZABLE. Teaching model of the transmit-side medium-access decision
// for a half-duplex shared segment.
//
// NOT an 802.3 MAC. No framing, CRC, interframe gap, address filtering, or
// backoff algorithm. JAM_CYCLES is illustrative and is NOT a standard value.
module shared_medium_tx_ctrl #(
  // How long to keep driving after a collision so that every other station
  // in the domain observes it. Illustrative; the normative length and the
  // reason a jam is needed at all are Chapter 1.2's subject.
  parameter int unsigned JAM_CYCLES = 8
) (
  input  logic clk,
  input  logic rst_n,
 
  // ── Client side ─────────────────────────────────────────────────────────
  input  logic tx_req,          // a frame is queued and may be sent
  input  logic tx_frame_done,   // serialiser has emitted the final bit
  output logic tx_enable,       // drive the medium this cycle
 
  // ── Medium observation, from the PHY ────────────────────────────────────
  // ASSUMED already synchronised to clk by the integrator. Real carrier and
  // collision indications are asynchronous to the MAC clock; treating them
  // as clean synchronous inputs is this model's largest simplification and
  // is called out again in Section 13.
  input  logic carrier_sense,
  input  logic collision_detect,
 
  // ── Retry policy interface ──────────────────────────────────────────────
  // The POLICY is deliberately external. This block decides that a retry is
  // required; Chapter 1.2 decides when it happens and when to give up.
  output logic jam_enable,
  output logic retry_req,       // one-cycle pulse: this attempt failed
  input  logic retry_grant,     // policy: attempt again now
  input  logic retry_abandon,   // policy: stop, discard the frame
 
  // ── Status pulses ───────────────────────────────────────────────────────
  output logic tx_abort,        // this attempt was destroyed
  output logic tx_error         // attempts exhausted; frame discarded
);
 
  typedef enum logic [2:0] {
    S_IDLE     = 3'd0,  // nothing to send
    S_DEFER    = 3'd1,  // want to send; medium observed busy
    S_TRANSMIT = 3'd2,  // driving the medium
    S_JAM      = 3'd3,  // collision seen; making it unambiguous to everyone
    S_RETRY    = 3'd4   // waiting for the external policy to say when
  } tx_state_e;
 
  tx_state_e state_q, state_d;
 
  localparam int unsigned JAM_W = (JAM_CYCLES <= 1) ? 1 : $clog2(JAM_CYCLES);
  logic [JAM_W-1:0] jam_cnt_q;
  logic             jam_last;
 
  assign jam_last = (jam_cnt_q == JAM_W'(JAM_CYCLES - 1));
 
  // ── Next state ──────────────────────────────────────────────────────────
  always_comb begin
    state_d = state_q;
    case (state_q)
      // The medium is sampled ONCE here, and the sample is already stale.
      // This single line is the whole chapter: a correct station reads an
      // idle medium and starts, and may still be about to collide.
      S_IDLE:
        if (tx_req)
          state_d = carrier_sense ? S_DEFER : S_TRANSMIT;
 
      S_DEFER:
        if (!tx_req)             state_d = S_IDLE;      // client withdrew
        else if (!carrier_sense) state_d = S_TRANSMIT;
 
      S_TRANSMIT:
        if (collision_detect)    state_d = S_JAM;
        else if (tx_frame_done)  state_d = S_IDLE;
 
      S_JAM:
        if (jam_last)            state_d = S_RETRY;
 
      // A grant returns to S_DEFER, NEVER straight to S_TRANSMIT. The medium
      // must be observed again: whoever won the previous contention is very
      // likely still transmitting, and resuming blind re-collides with them
      // deterministically. See assertion P5.
      S_RETRY:
        if (retry_abandon)       state_d = S_IDLE;
        else if (retry_grant)    state_d = S_DEFER;
 
      // Unreachable encodings 5..7 recover to a safe state rather than
      // holding an undefined one — this block drives an external medium.
      default:                   state_d = S_IDLE;
    endcase
  end
 
  // ── State and jam counter ───────────────────────────────────────────────
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      state_q   <= S_IDLE;
      jam_cnt_q <= '0;
    end else begin
      state_q <= state_d;
      // Armed on ENTRY to S_JAM and then run from the state alone. It never
      // re-reads collision_detect, so a collision indication that drops early
      // cannot shorten the jam — which is the point of jamming at all.
      if (state_d == S_JAM && state_q != S_JAM) jam_cnt_q <= '0;
      else if (state_q == S_JAM)                jam_cnt_q <= jam_cnt_q + 1'b1;
    end
  end
 
  // ── Outputs ─────────────────────────────────────────────────────────────
  // Control outputs are Moore — decoded from the registered state alone, so
  // they cannot glitch in response to a medium input.
  assign tx_enable  = (state_q == S_TRANSMIT);
  assign jam_enable = (state_q == S_JAM);
  assign retry_req  = (state_q == S_JAM) && jam_last;
 
  // Status pulses are Mealy: they mark the cycle in which an OBSERVATION was
  // made, which is what a counter or a trace wants to record. They drive
  // nothing outside this station.
  assign tx_abort   = (state_q == S_TRANSMIT) && collision_detect;
  assign tx_error   = (state_q == S_RETRY)    && retry_abandon;
 
endmodule

Classification: synthesizable.

What it teaches: that the shared medium's uncertainty enters a digital design as exactly two inputs, and that responding to them correctly requires five states — one for having nothing to do, one for wanting the medium and not having it, one for holding it, one for discovering the hold was invalid, and one for waiting on a policy that lives elsewhere. Collapsing any of them produces a specific bug, which is what the assertions in Section 12 are aimed at.

A five-state machine laid out as a cycle. IDLE is the start state. From IDLE, a transmit request with the medium busy goes up to DEFER; a transmit request with the medium clear goes right to TRANSMIT. DEFER goes to TRANSMIT when carrier clears. TRANSMIT returns to IDLE when the frame completes, or continues right to JAM on collision detect. JAM goes up-left to RETRY when the jam count completes. RETRY returns left to DEFER on a retry grant, and down-left to IDLE on retry abandon.DEFERRETRYIDLETRANSMITJAMtx_req · carrier busytx_req · carrier busycarrier clearcarrier cleartx_req · carrier cleartx_req · carrier cleartx_req ·carrier…tx_frame_donetx_frame_donecollision_detectcollision_detectjam completejam completeretry_grantretry_grantretry_abandonretry_abandon
Figure 3 — the access decision as five states, read as a cycle: want, wait, drive, abort, retry.

Two transitions in the RTL are omitted from the figure for legibility: S_DEFER back to S_IDLE when the client withdraws its request, and the retry_abandon path is drawn while its tx_error pulse is not. The property the picture is meant to make obvious is the one assertion P5 encodes: every arrow into TRANSMIT originates at a state that has just observed carrier sense — including the return path from a failed attempt, which is why retry_grant points at DEFER and not at TRANSMIT.

The design decision worth arguing about

tx_enable is decoded from state alone. A tempting alternative is to guard it:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// WRONG. Do not write this.
assign tx_enable = (state_q == S_TRANSMIT) && !carrier_sense;

That line looks like a safety improvement — never drive a busy medium — and it breaks the design completely.

A transmitting station's own signal is present on the medium, so its own carrier sense is asserted throughout its own transmission. The guard therefore deasserts tx_enable one propagation-detection delay after transmission begins, on every single frame, including every successful one. The station transmits a fragment and stops.

This is not a hypothetical. It is a recurring integration bug, and it produces a signature worth memorising: every frame becomes a runt, and no collision is ever reported. Section 14 returns to it.

The correct statement of the rule is narrower than it first appears, and getting the wording exactly right is what prevents the bug:

Carrier sense gates the start of a transmission. It does not gate its continuation.

Once transmission has started, the only input permitted to stop it is collision_detect. That asymmetry is not a simplification of this model — it is a real property of the mechanism, and Section 12's first two assertions exist to encode it.

Deliberately simplified: the medium inputs are treated as synchronous; there is no interframe gap (Chapter 5.9); there is no attempt counter, because counting attempts is the policy's job; jam length is a fixed parameter rather than a defined sequence; and the client interface has no flow control beyond tx_req and tx_frame_done.

Production implication: a real MAC needs synchronisers with a documented latency budget on both medium inputs, interframe-gap enforcement between consecutive frames, the frame buffered and held intact until success, per-attempt statistics separated from per-frame statistics, and a defined interaction with the transmit FIFO so that a discarded frame does not leave the datapath misaligned.

11. Waveform — Two Locally Correct Decisions

The trace below is the Section 4 scenario in the controller's own terms, with both stations' controllers shown together. Propagation delay is modelled as two cycles in each direction, chosen so the effect is visible in a short trace; it is not a real ratio.

Two stations, one medium, two correct decisions

10 cycles
Ten cycles. Station A asserts transmit enable at cycle 2 and its own carrier sense rises with it. Station B's carrier sense stays low through cycle 3 because A's signal has not yet propagated, so B asserts transmit enable at cycle 4. A's signal reaches B at cycle 4, B's collision detect asserts at cycle 5, and B's transmit enable falls at cycle 6 as B begins jamming. B's signal reaches A at cycle 6, A's collision detect asserts at cycle 6, and A's transmit enable falls at cycle 7 as A begins jamming.A starts — medium idleA starts — medium idleB senses idle, correctlyB senses idle, correctlyB starts; A arrives at BB starts; A arrives at BB detects collisionB detects collisionA detects collisionA detects collisionclka_carriera_tx_ena_cola_jamb_tx_reqb_carrierb_tx_enb_colb_jamt0t1t2t3t4t5t6t7t8t9
Figure 4 — the same collision in digital signals, with propagation modelled as two cycles.

Three things in that trace are worth reading deliberately.

Cycle 3 is the whole lesson. b_carrier is low and b_tx_req is high, so B's state machine moves to S_TRANSMIT. Nothing about that is wrong. The information B needed did not exist at B yet.

a_carrier rises at cycle 2, with a_tx_en. A's own transmission is on the medium, so A's carrier detector reports busy. This is the concrete form of the argument in Section 10: a !carrier_sense term on tx_enable would have ended A's transmission at cycle 3.

The two stations learn at very different points in their own transmissions. B started at cycle 4 and knew at cycle 5 — one cycle in. A started at cycle 2 and did not know until cycle 6 — four cycles in, having driven the medium the whole time for nothing. That asymmetry is the digital form of Section 4's timing table, and it means there is no cycle at which both stations hold the same view: at cycle 6, B is already jamming while A is only now discovering there is a problem. Any reasoning that assumes the stations agree is wrong by construction, and Section 13's scoreboard has to be built accordingly.

12. Assertions

These are invariants of this model. None of them is a normative IEEE 802.3 requirement, and two of them encode timing contracts that this design defines for itself.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// SVA over shared_medium_tx_ctrl. Implementation invariants for THIS design.
 
// SAFETY — P1: no transmission STARTS while the medium is observed busy.
// Deliberately phrased as "does not start" rather than "is not driving": a
// station that is already transmitting sees its own carrier. See the note
// on the rejected property below.
property p_no_start_when_busy;
  @(posedge clk) disable iff (!rst_n)
  (!tx_enable && carrier_sense) |=> !tx_enable;
endproperty
a_no_start_when_busy : assert property (p_no_start_when_busy);
 
// SAFETY — P2: a detected collision stops transmission within this model's
// declared response time of one cycle. The NUMBER is this design's contract,
// not a standard requirement; what is architectural is that the bound exists
// and is stated, so a violation is a test failure rather than a discussion.
property p_collision_stops_tx;
  @(posedge clk) disable iff (!rst_n)
  (tx_enable && collision_detect) |=> !tx_enable;
endproperty
a_collision_stops_tx : assert property (p_collision_stops_tx);
 
// SAFETY — P3: the two medium-driving outputs are mutually exclusive. A
// design that can assert both has two drive paths onto one resource, which
// is the failure this whole block exists to prevent.
property p_drive_exclusive;
  @(posedge clk) disable iff (!rst_n)
  !(tx_enable && jam_enable);
endproperty
a_drive_exclusive : assert property (p_drive_exclusive);
 
// CAUSATION — P4: jamming only ever begins because a transmission was
// aborted. Catches a jam entered from a decode error or a spurious input,
// which would put this station onto an idle medium for no reason.
property p_jam_needs_abort;
  @(posedge clk) disable iff (!rst_n)
  (!jam_enable ##1 jam_enable) |-> $past(tx_abort);
endproperty
a_jam_needs_abort : assert property (p_jam_needs_abort);
 
// CAUSATION — P5: a granted retry passes through deferral. This is the one
// property that encodes Section 3's conclusion rather than a handshake rule:
// a station resuming after a collision has NO current knowledge of the
// medium, and must acquire some before driving. A design that goes straight
// from S_RETRY to S_TRANSMIT passes every other property here and collides
// with the winner of the previous contention on essentially every retry.
property p_grant_defers_before_tx;
  @(posedge clk) disable iff (!rst_n)
  (state_q == S_RETRY && retry_grant) |=> (state_q == S_DEFER);
endproperty
a_grant_defers : assert property (p_grant_defers_before_tx);
 
// CAUSATION — P6: a retry is requested only at the end of a jam, exactly
// once. Catches a level rather than a pulse, which would make an external
// policy count one failure many times and back off far too aggressively.
property p_retry_req_is_single_pulse;
  @(posedge clk) disable iff (!rst_n)
  retry_req |=> !retry_req;
endproperty
a_retry_single_pulse : assert property (p_retry_req_is_single_pulse);
 
// SAFETY — P7: reset never leaves this station driving a shared medium.
// No disable iff, deliberately: the reset window is exactly what is checked.
property p_reset_releases_medium;
  @(posedge clk)
  !rst_n |=> (!tx_enable && !jam_enable);
endproperty
a_reset_releases : assert property (p_reset_releases_medium);
 
// LIVENESS — P8: a deferring station eventually transmits. ASSUMPTION, and
// it must be written down: this holds only if the medium eventually goes
// idle and the policy eventually grants. Neither is guaranteed by this
// block, and without both the property is false for a CORRECT design.
assume property (@(posedge clk) s_eventually (!carrier_sense));
property p_defer_eventually_transmits;
  @(posedge clk) disable iff (!rst_n)
  (state_q == S_DEFER) |-> s_eventually (tx_enable);
endproperty
a_defer_progresses : assert property (p_defer_eventually_transmits);

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_never_drive_busy_medium;
//   @(posedge clk) disable iff (!rst_n)
//   carrier_sense |-> !tx_enable;
// endproperty

It reads like the definition of carrier-sense multiple access, and it fires on every successful frame this design ever sends, because a transmitting station's own signal asserts its own carrier sense.

The failure mode this produces in a real project is worth naming: the assertion fires constantly, someone concludes the assertion is noisy rather than wrong, and it gets waived. A waived assertion in that family is worse than no assertion, because the real property — P1, which constrains only the start — now looks like it is already covered. Getting P1's phrasing right is the substantive work; writing it is not.

13. Verification

Monitors observe: the client handshake (tx_req, tx_frame_done), both medium inputs, all three drive-related outputs, the retry handshake, and the state register.

The scoreboard independently predicts the expected state sequence and the expected output for each. Its model must be written from the specification of the state machine, not from the RTL's own state_d expression — a checker that reuses the design's next-state logic agrees with the design about every bug in it.

Scenarios

  1. Request on an idle medium. tx_req with carrier_sense low. Expect a direct move to S_TRANSMIT and tx_enable in the following cycle. The baseline case, and the one that must never regress.
  2. Request on a busy medium. tx_req with carrier_sense high. Expect S_DEFER and no drive. Hold busy for a long interval; verify the request is not lost and no drive leaks.
  3. Carrier clears while deferring. Release carrier_sense. Expect transmission to begin. Repeat with carrier_sense clearing for exactly one cycle and then reasserting, which is the case a naively coded deferral loses.
  4. Collision in the first cycle of transmission. The tightest case: collision_detect in the same cycle tx_enable first asserts. Verify the jam still runs to full length and the retry request is still produced — this exercises the path where the collision arrives before any state has settled.
  5. Collision after many cycles. Same expectations, deep into the frame. Verify the jam counter is armed on entry to S_JAM rather than carrying a stale value from a previous collision — a counter cleared in the wrong place passes case 4 and fails here.
  6. Repeated collisions. Grant a retry, collide again, several times. Verify each attempt produces exactly one retry_req pulse and that nothing accumulates across attempts. This is the scenario that catches the level-versus-pulse bug P6 targets.
  7. Retry grant while the medium is busy. Grant a retry with carrier_sense high. Expect S_DEFER, not S_TRANSMIT. This is the single most valuable directed test in the list, because the bug it catches is invisible on a quiet bench: with only one station, the medium is always idle at retry time and the deferral is never exercised.
  8. Retry abandoned. Expect tx_error, a return to S_IDLE, and no drive.
  9. Client withdraws while deferring. Deassert tx_req in S_DEFER. Expect a clean return to S_IDLE.
  10. Reset in every state. Particularly in S_TRANSMIT and S_JAM, where the block is driving the medium. Verify drive is released, no stale request appears afterwards, and the jam counter does not resume mid-count.
  11. Medium inputs toggling at state boundaries. Assert and deassert carrier_sense and collision_detect in the cycle of each transition. In this synchronous model that is a legitimate stimulus and the design must be deterministic under it.

A directed stimulus for the case randomisation will not find

Scenario 7 is the one worth writing by hand, because it needs four ordered events and randomisation essentially never produces the sequence.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// NON-SYNTHESIZABLE — directed stimulus. Drives the full path
// idle → request → transmit → collision → jam → retry grant → DEFER,
// with the medium deliberately busy at the moment of the grant.
task automatic collide_then_grant_into_busy_medium();
  // 1. Idle medium, frame queued. Expect a direct start.
  carrier_sense    <= 1'b0;
  collision_detect <= 1'b0;
  tx_req           <= 1'b1;
  @(posedge clk);
  assert (dut.state_q == S_TRANSMIT)
    else $error("did not start on an idle medium");
 
  // 2. Collide a few cycles in. Expect abort, then a jam of full length.
  repeat (3) @(posedge clk);
  collision_detect <= 1'b1;
  @(posedge clk);
  collision_detect <= 1'b0;          // the indication drops early ON PURPOSE
  assert (!tx_enable)
    else $error("still driving one cycle after collision_detect");
  repeat (JAM_CYCLES - 1) @(posedge clk);
  assert (retry_req)                 // exactly one pulse, at the jam's end
    else $error("no retry request at end of jam");
 
  // 3. THE CASE. Make the medium busy, then grant. A design that resumes
  //    transmission here passes every other test in the suite and collides
  //    with the previous winner on essentially every retry.
  carrier_sense <= 1'b1;
  retry_grant   <= 1'b1;
  @(posedge clk);
  retry_grant   <= 1'b0;
  @(posedge clk);
  assert (dut.state_q == S_DEFER && !tx_enable)
    else $error("resumed transmission without re-observing the medium");
endtask

What each check is for. The first proves the baseline still works. Dropping collision_detect after one cycle in step 2 is deliberate: it proves the jam runs from the state and not from the input, which is the difference between a jam every station observes and one that ends the moment the analog indication flickers. The third assertion is the whole point of the task, and it is the executable form of property P5.

Coverage

Cross the state register against each medium input. Cover collisions at the first, an intermediate, and the final cycle of transmission. Cover deferral durations of one cycle, of many cycles, and of a duration that spans a retry grant. Cover consecutive retry attempts to a depth greater than one, and reset asserted in each state.

14. Debugging — Separating Four Failure Classes

A station "cannot transmit reliably" is not a diagnosis. Four distinct faults produce overlapping symptoms, and separating them early is most of the work.

Contention behaviour — the medium is working as designed. Transmission succeeds but with variable delay, and both collision counts and successful-frame counts rise together with offered load. Nothing is broken; the segment is loaded. Distinguishing evidence: the behaviour tracks load, and it improves immediately when other stations go quiet.

PHY or link failure. No successful transmission at all, and — the informative part — no collisions either. A station that cannot reach the medium also cannot collide with anyone on it. Distinguishing evidence: zero collisions together with zero successes is much stronger evidence of a link fault than of a contention problem, because contention produces collisions by definition. Check carrier_sense behaviour first: a detector stuck high produces a station that defers forever and never transmits, while a detector stuck low produces a station that transmits into everything and collides constantly.

MAC transmit-state bug. Failures that do not track load and do not correlate with any other station's activity. The controller here has three characteristic ones, each with its own signature:

SymptomLikely causeFirst thing to inspect
Every frame is short; collisions never reportedtx_enable gated by carrier_sense — the Section 10 bugThe tx_enable assignment, before anything else
Collision reported, but drive continuesThe S_TRANSMIT to S_JAM transition, or a tx_enable decode that includes S_JAMState register against tx_enable on the failing cycle
Collides on nearly every retry, on an otherwise quiet segmentS_RETRY transitioning to S_TRANSMIT instead of S_DEFERThe S_RETRY next-state arm; assertion P5

Buffer or retry-policy bug. The controller reaches S_RETRY correctly and the frame is still lost, or is sent twice, or is sent with its contents altered. This is not an access-control fault at all — it is a fault in how the frame is held across attempts. Distinguishing evidence: the medium signals and the state sequence are all correct, and the defect is visible only in what arrives.

15. What Full Duplex Removed

Every mechanism in this chapter exists because one medium is shared by several transmitters. Remove the sharing and the mechanisms have nothing to do.

A full-duplex point-to-point link has exactly two stations, and each direction has its own path driven by exactly one of them. There is no resource to arbitrate for, because nothing else can drive the path this station drives. The consequence for the MAC is unusually clean:

MechanismPurpose on a shared mediumOn a full-duplex link
Carrier sense before transmitAvoid starting into an in-progress transmissionNo longer applicable — nothing else can be transmitting on this path
Collision detectionDiscover that a committed decision was wrongNo collisions to detect
JamMake the collision unambiguous to every stationNothing to make unambiguous
Retry and backoffRe-attempt after a failed contentionNo contention, so no contention-driven retry
Minimum frame size from the round tripKeep transmitting long enough to detect a collisionThe timing reason disappears; the field-format requirement remains

Most of shared_medium_tx_ctrl becomes dead logic: S_DEFER, S_JAM and S_RETRY are unreachable, and the controller collapses to idle and transmitting.

Two things do not disappear, and confusing them with the ones that do is a common error.

The minimum frame size stays, even though its original justification is gone. It became a fixed property of the frame format, and every receiver still validates against it. A field whose reason has expired and whose requirement has not is a recurring pattern in long-lived protocols, and it is why Chapter 5.6 has to explain both the historical derivation and the present-day rule.

The need to stop a sender stays, and takes a different form. On a shared medium, a receiver that could not keep up was protected incidentally: the medium was busy, so nobody could send. On a dedicated full-duplex link the sender can transmit continuously and nothing physically restrains it. That gap is exactly what flow control fills, and it is why Module 14 exists — a mechanism created because full duplex removed a constraint that had been doing useful work by accident.

Chapter 1.5 develops both consequences.

16. Common Misconceptions

"Carrier sense guarantees there will be no collision."

The wrong model: the medium has a state, and a station can read it before deciding, so a station that checks first cannot conflict with one that also checked first.

What it costs: an engineer holding this model treats every collision as a defect and goes looking for the bug that caused it. On a healthy loaded segment there is no such bug, and the search consumes days. The same model produces the rejected assertion in Section 12 and the tx_enable gating bug in Section 10 — both are attempts to enforce a guarantee that carrier sense cannot provide.

The corrected model: carrier sense reports the medium at this station's location, one propagation delay in the past. It removes every collision in which one station started well after another's signal arrived, which is most of them. It cannot remove collisions between stations that decide within one propagation window of each other, because the information needed to prevent those has not physically arrived yet.

"A collision means some station transmitted while it knew the medium was busy."

The wrong model: collisions are caused by a misbehaving station — one that skipped the check, or ignored the answer.

What it costs: it turns a normal system event into a hunt for a culprit, and it makes the collision counter unreadable. A rising collision count is interpreted as evidence of a defective station rather than as a measurement of load, and the actual problem — a domain that is too large or too busy — is not investigated.

The corrected model: two stations can each observe an idle medium, each correctly, and each start. Section 4 constructs exactly this with no misbehaviour anywhere. Collisions are the designed-for outcome of distributed access under contention, not evidence of a fault.

"Ethernet always has collisions."

The wrong model: CSMA/CD is what Ethernet is, so any Ethernet link is a contention domain.

What it costs: it produces confident, wrong reasoning about modern systems — attributing latency variation on a switched link to contention, expecting collision counters to be non-zero on healthy full-duplex ports, and looking for shared-medium explanations for problems that are queueing, flow-control or configuration problems. On a full-duplex link, a non-zero collision count is a symptom of misconfiguration — very often the duplex mismatch in Chapter 11.4 — and reading it as normal operation hides a real fault.

The corrected model: a full-duplex switched link has one station per end and separate paths per direction. No shared medium, no collision domain, and no collisions in correct operation. The shared-medium model explains the MAC's history and vocabulary; it does not describe a modern port.

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

The wrong model: both connect stations together, and a switch is a faster hub.

What it costs: it makes the fix for a saturated hub look like "buy a faster hub", and it makes collision-domain size look like a tuning parameter rather than a topology fact. It also obscures the reason a switch changes latency predictability and not merely throughput.

The corrected model: a hub is a repeater. It regenerates the signal onto every other port, so all attached stations remain in one collision domain — and adding ports adds both stations and propagation delay to it. A switch receives a frame, decides where it goes, and transmits it onward, so each port is a separate collision domain. That is a change in the number of contention regions, not a change in speed, and it is why the switch retired the shared-medium problem rather than optimising it. Module 12 is the mechanism.

17. Interview Reasoning

Because carrier sense reports the medium at the sensing station's own location, and a signal launched elsewhere takes time to arrive. Within one propagation delay of a station starting, every station that has not yet received its signal observes an idle medium — correctly — and may start.

What a strong answer includes beyond the mechanism:

  • Both stations are behaving correctly. The collision is not a defect in either.
  • The window is bounded by the propagation delay between them, so it is a property of the physical geometry, not of the implementations.
  • The worst case is a full round trip: the far station may start one instant before the near station's signal arrives, so its own signal takes another one-way delay to travel back.
  • Which is why detection has to exist alongside sensing — and why a transmission must be long enough to still be in progress when a collision arrives, the constraint that fixes Ethernet's minimum frame size.

An answer that stops at "propagation delay" states the fact. An answer that reaches the round-trip bound and connects it to the minimum frame size demonstrates that the model is actually being used.

18. Understanding Check

19. What's Next

This chapter deliberately stopped short of an algorithm. What it established is the shape of the constraint any algorithm has to satisfy:

  • Sensing the medium is necessary, and it leaves a window one round trip wide.
  • Detection during transmission is therefore mandatory, not an optimisation.
  • A transmission has to still be in progress when a collision comes back, or the collision is undetectable — which puts a lower bound on how long a station must transmit.
  • After a collision, every station involved has to retry, and if they all retry identically they collide again — so the retry cannot be uniform.

Which leaves one question, and it is now a narrow one:

If listening before transmitting cannot eliminate collisions, what does a station do about the ones that remain — and how long must a frame be for that to work at all?

Chapter 1.2 — CSMA/CD, Collision Domains and Slot Time answers it. It supplies the algorithm, the normative round-trip bound this chapter deliberately left as illustrative arithmetic, and the derivation of Ethernet's minimum frame size from that bound. The parameters left open in shared_medium_tx_ctrl — how long to jam, when to retry, when to give up — are its subject.

The rest of Module 1 then follows the consequences outward: Chapter 1.3 on packet switching as the alternative to allocating the medium in advance, Chapter 1.4 on the coax-to-switch evolution that dismantled the shared medium, and Chapter 1.5 on full duplex, which removed most of this chapter's machinery and created the need for flow control in its place. 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.