Skip to content
VLSI Mentor

Ethernet · Module 11

Ability Advertisement and Priority Resolution

The protocol exchanges abilities and never conclusions. Each end resolves against its own copy of a priority table that is never transmitted, and acknowledge confirms receipt of an advertisement and nothing more.

Chapter 11.1 delivered sixteen bits, together with a per-bit confidence saying which of them are believable.

This chapter asks what those bits mean, and its answer contains one structural surprise.

The protocol exchanges abilities and never conclusions.

Each end advertises what it can do. Each end then resolves, independently, using its own copy of a priority table. And nothing anywhere in the protocol confirms that the two resolutions agree.

There is an acknowledge bit, and it does not close the gap. ACK means I received your advertisement — it is set after three identical copies have arrived and is then sent six to eight times — and it says nothing about what was concluded from that advertisement.

Which is exactly the gap Chapter 9.2's duplex mismatch lives in. Two ends that advertise correctly, acknowledge correctly, resolve correctly against different tables, and disagree — with every counter clean at both ends.

1. Scope — What This Chapter Owns

This chapter owns the link code word and what is done with it: the fields, the technology ability bits, the priority table, the acknowledge mechanism, next pages, and the resolution itself.

It does not re-derive what other chapters own. Chapter 11.1 owns the FLP burst, its timing and the confidence that qualifies the decoded word — this chapter starts from a fully-bracketed 16-bit word. Chapter 9.2 §4 gave a four-technology arbiter and §7 the duplex-mismatch consequence; this chapter gives the full field layout, the complete table, and the acknowledge behaviour that chapter took for granted.

Chapter 11.3 owns the complete bring-up sequence from power-on to a MAC that may legally transmit. Chapter 11.4 owns the failure modes.

The claim this chapter defends: when a specification is compiled into a table inside each implementation, a property that re-derives the same table cannot verify it — the check and the checked share an author and therefore a failure mode, and the only useful properties are structural invariants that hold for any correct table.

2. Sixteen Bits, Field by Field

The base link code word is sixteen bits. The lowest five bits are the selector field, which says which standard the remaining bits should be interpreted against, and in practice always carries the value for the eight oh two dot three standard. The next eight bits are the technology ability field, one bit per capability, covering ten and one hundred megabit modes in half and full duplex plus flow control. Bit thirteen is remote fault. Bit fourteen is acknowledge. Bit fifteen is next page. So half the word is capability, five bits are a selector that has essentially one value, and only three bits carry protocol at all.Bits 4:0 — Selectorwhich standardBits 12:5 — Ability8 bits, one per capabilityBit 13 — RFremote faultBit 14 — ACKreceipt, not agreementBit 15 — NPnext page followsNo conclusion fieldnowhere in the word12
Figure 1 — half the word is abilities, a third is a selector nobody uses, and three bits carry the entire protocol.
BitsFieldWidthPurpose
4:0Selector5which standard the rest is read against — 00001 = IEEE 802.3
12:5Technology Ability8one bit per capability, A0 to A7
13RF1remote fault
14ACK1acknowledge — receipt of an advertisement
15NP1a next page follows
16

Half the word is capability. Five bits are a selector with essentially one value. Three bits carry the entire protocol.

And there is no field for the result. Nowhere in these sixteen bits is there a place to say I have concluded we should run at 100BASE-TX full duplex. The word carries what a device can do and never what it decided.

3. The Eight Ability Bits

Eight bits, A0 through A7, and not all of them are technologies.

BitWord bitMeaning
A0510BASE-T
A1610BASE-T full duplex
A27100BASE-TX
A38100BASE-TX full duplex
A49100BASE-T4
A510PAUSE — flow control
A611ASM_DIR — asymmetric pause
A712reserved

Three observations, and each one shapes an RTL decision later in this chapter.

Half duplex and full duplex are separate bits, not a mode flag. 10BASE-T and 10BASE-T full duplex are two independent advertisements — a device may claim either, both, or neither — which is why the resolution operates over nine technologies rather than over a speed and a duplex.

PAUSE and ASM_DIR are not technologies at all. They describe flow control, which is orthogonal to speed and duplex and is not part of the priority resolution. A resolver that includes them in the technology comparison will resolve to "PAUSE", which is not a way to run a link.

And gigabit is not here. 1000BASE-T's abilities do not fit in eight bits alongside everything else, so they are carried in a next page — which is Section 11's subject and the reason the next-page mechanism exists at all.

4. RTL 1 — Building an Advertisement

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// SYNTHESIZABLE.
//
// Builds the base link code word this device advertises.
//
// THE FIELDS (clause 28):
//   4:0   selector, 00001 = IEEE 802.3
//   12:5  technology ability A0..A7
//   13    RF   remote fault
//   14    ACK  acknowledge -- set by Section 9, NOT here
//   15    NP   next page follows
//
// THE RULE THIS MODULE ENFORCES: an advertised ability must be one the
// device can actually deliver. A device that advertises 1000BASE-T and
// cannot do it will win the resolution at both ends and then fail to
// establish -- and the failure appears as a link that will not come up
// between two devices that each believe they agreed.
package autoneg_res_pkg;
 
  localparam logic [4:0] SELECTOR_802_3 = 5'b00001;
 
  // Technology ability bit positions WITHIN the word.
  localparam int unsigned A_10T        = 5;
  localparam int unsigned A_10T_FD     = 6;
  localparam int unsigned A_100TX      = 7;
  localparam int unsigned A_100TX_FD   = 8;
  localparam int unsigned A_100T4      = 9;
  localparam int unsigned A_PAUSE      = 10;
  localparam int unsigned A_ASM_DIR    = 11;
  localparam int unsigned A_RESERVED   = 12;
 
  localparam int unsigned B_RF  = 13;
  localparam int unsigned B_ACK = 14;
  localparam int unsigned B_NP  = 15;
 
  // The technologies the resolution ranks. PAUSE and ASM_DIR are NOT
  // here: they are flow control, orthogonal to speed and duplex, and a
  // resolver that ranks them can resolve to "PAUSE", which is not a way
  // to run a link.
  typedef enum logic [3:0] {
    TECH_NONE,
    TECH_10T_HD,
    TECH_10T_FD,
    TECH_100TX_HD,
    TECH_100T4,
    TECH_100TX_FD,
    TECH_1000T_HD,     // advertised by next page
    TECH_1000T_FD      // advertised by next page
  } tech_e;
 
  // THE PRIORITY TABLE, as a RANK rather than as an ordered list.
  // Higher rank wins. Expressing it as a function of the technology
  // makes it checkable: Section 13 asserts that the ranks form a
  // STRICT TOTAL ORDER, which catches a duplicated or missing entry
  // without re-deriving what the order should be.
  function automatic logic [3:0] tech_rank (input tech_e t);
    unique case (t)
      TECH_1000T_FD: tech_rank = 4'd9;
      TECH_1000T_HD: tech_rank = 4'd8;
      TECH_100TX_FD: tech_rank = 4'd7;
      TECH_100T4:    tech_rank = 4'd6;
      TECH_100TX_HD: tech_rank = 4'd5;
      TECH_10T_FD:   tech_rank = 4'd4;
      TECH_10T_HD:   tech_rank = 4'd3;
      default:       tech_rank = 4'd0;
    endcase
  endfunction
 
  // Clause 28's acknowledge rule.
  localparam int unsigned ACK_RX_REQUIRED = 3;   // identical copies received
  localparam int unsigned ACK_TX_MIN      = 6;   // copies sent with ACK
  localparam int unsigned ACK_TX_MAX      = 8;
 
endpackage
 
module link_code_word_builder
  import autoneg_res_pkg::*;
#(
  parameter int unsigned CNT_W = 16
) (
  input  logic clk,
  input  logic rst_n,
 
  // What this device CAN do -- from straps, fuses or PHY capability
  // registers. Not from software configuration.
  input  logic cap_10t_hd,
  input  logic cap_10t_fd,
  input  logic cap_100tx_hd,
  input  logic cap_100tx_fd,
  input  logic cap_100t4,
  input  logic cap_pause,
  input  logic cap_asm_dir,
  input  logic cap_1000t,            // requires a next page
 
  // What software has been allowed to DISABLE. Software may advertise
  // less than the hardware can do; it may never advertise more.
  input  logic [7:0] admin_mask,
 
  input  logic remote_fault,
  input  logic ack_from_tracker,     // Section 9 owns this bit
 
  output logic [15:0] link_code_word,
  output logic        next_page_required,
 
  // Software asked to advertise something the hardware cannot do.
  // REFUSED and reported -- an advertised ability that cannot be
  // delivered wins the resolution at BOTH ends and then fails.
  output logic             over_advertisement_refused,
  output logic [7:0]       refused_bits,
  output logic [CNT_W-1:0] c_refusals,
  output logic             ever_over_advertised
);
 
  logic [7:0] capability_c;
  logic [7:0] requested_c;
  logic [7:0] advertised_c;
 
  always_comb begin
    // The hardware's true capability, one bit per ability position.
    capability_c = {1'b0,              // A7 reserved, never advertised
                    cap_asm_dir,
                    cap_pause,
                    cap_100t4,
                    cap_100tx_fd,
                    cap_100tx_hd,
                    cap_10t_fd,
                    cap_10t_hd};
 
    // What software asked for.
    requested_c = admin_mask;
 
    // THE INTERSECTION. Software can subtract and never add.
    advertised_c = capability_c & requested_c;
  end
 
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      link_code_word <= 16'd0;
      next_page_required <= 1'b0;
      over_advertisement_refused <= 1'b0;
      refused_bits <= 8'd0; c_refusals <= '0;
      ever_over_advertised <= 1'b0;
    end else begin
      over_advertisement_refused <= 1'b0;
 
      link_code_word <= {
        1'b0,                         // NP, set below
        ack_from_tracker,             // ACK -- owned by Section 9
        remote_fault,                 // RF
        advertised_c,                 // A7..A0
        SELECTOR_802_3                // selector
      };
 
      // Gigabit needs a next page; the base page cannot express it.
      next_page_required     <= cap_1000t && admin_mask[0];
      link_code_word[B_NP]   <= cap_1000t && admin_mask[0];
 
      // REFUSAL. Software asking for an ability the hardware lacks is
      // not an error to be obeyed -- an advertised ability that cannot
      // be delivered wins at both ends and then does not work, and the
      // symptom is a link that will not come up between two devices
      // that each believe they agreed.
      if ((requested_c & ~capability_c) != 8'd0) begin
        over_advertisement_refused <= 1'b1;
        refused_bits               <= requested_c & ~capability_c;
        ever_over_advertised       <= 1'b1;
        if (!(&c_refusals)) c_refusals <= c_refusals + 1'b1;
      end
    end
  end
 
endmodule

Classification: synthesizable.

What it teaches: that software may subtract abilities and must never add them, which is the capability & admin_mask intersection. An advertised ability the hardware cannot deliver is not a harmless optimism — it will be selected by the priority resolver at both ends, because both ends see it advertised and both rank it highest — and then the link will not establish. The symptom is two devices that negotiated successfully and cannot pass traffic.

Deliberately simplified: capabilities arrive as individual inputs. In a real PHY they come from a capability register whose contents are set at manufacture, and the point of reading them rather than trusting configuration is exactly the same.

Production implication: over_advertisement_refused fires on a configuration error that is otherwise completely silent until it matters. A device configured to advertise 1000BASE-T on hardware that cannot do it will look correct in every register, negotiate to gigabit against a capable partner, and fail to bring the link up — appearing as a cabling or PHY fault. refused_bits names the ability, which turns a bring-up mystery into a configuration line.

5. RTL 2 — Parsing, and Validating the Fields

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// SYNTHESIZABLE.
//
// Parses a received link code word and validates its fields BEFORE
// anything acts on them.
//
// WHY VALIDATION MATTERS HERE MORE THAN USUAL. Chapter 11.1 §5 showed
// that a pulse accepted beyond data_detect_max shifts every subsequent
// bit, producing a well-formed 16-bit word that is a ROTATION of the
// transmitted one. A rotated word decodes to a plausible and entirely
// wrong set of abilities, with no error indication anywhere.
//
// THREE CHECKS CATCH IT, none of which was designed for it:
//   1. the SELECTOR must be 00001. A rotated word almost never has it.
//   2. the RESERVED bit A7 must be zero.
//   3. an advertisement of NOTHING -- zero technology bits -- is legal
//      to receive and means the partner can do nothing, which is
//      almost always a decode failure rather than a real claim.
module link_code_word_parser
  import autoneg_res_pkg::*;
#(
  parameter int unsigned CNT_W = 16
) (
  input  logic clk,
  input  logic rst_n,
  input  logic clear,
 
  input  logic [15:0] word_in,
  input  logic        word_valid,
  input  logic        word_fully_bracketed,   // from Chapter 11.1
 
  output logic [4:0]  selector,
  output logic [7:0]  abilities,
  output logic        remote_fault,
  output logic        ack,
  output logic        next_page,
  output logic        parse_valid,
 
  // Validation results, each named because each is a different fault.
  output logic bad_selector,
  output logic reserved_bit_set,
  output logic empty_advertisement,
  output logic not_bracketed,
 
  output logic [CNT_W-1:0] c_words,
  output logic [CNT_W-1:0] c_bad_selector,
  output logic [CNT_W-1:0] c_reserved_set,
  output logic [CNT_W-1:0] c_empty_ads,
  output logic [CNT_W-1:0] c_rejected,
  output logic             ever_bad_selector
);
 
  wire [4:0] sel_c  = word_in[4:0];
  wire [7:0] abil_c = word_in[12:5];
 
  wire bad_sel_c   = (sel_c != SELECTOR_802_3);
  wire reserved_c  = word_in[A_RESERVED];
  // Technology bits only -- PAUSE and ASM_DIR are not technologies, so
  // a word advertising only flow control advertises no way to run.
  wire empty_c     = (abil_c[4:0] == 5'd0);
 
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      selector <= 5'd0; abilities <= 8'd0; remote_fault <= 1'b0;
      ack <= 1'b0; next_page <= 1'b0; parse_valid <= 1'b0;
      bad_selector <= 1'b0; reserved_bit_set <= 1'b0;
      empty_advertisement <= 1'b0; not_bracketed <= 1'b0;
      c_words <= '0; c_bad_selector <= '0; c_reserved_set <= '0;
      c_empty_ads <= '0; c_rejected <= '0; ever_bad_selector <= 1'b0;
    end else if (clear) begin
      c_words <= '0; c_bad_selector <= '0; c_reserved_set <= '0;
      c_empty_ads <= '0; c_rejected <= '0;
      // ever_bad_selector survives: a partner that has ever sent a word
      // with the wrong selector is a partner worth suspecting.
    end else begin
      parse_valid         <= 1'b0;
      bad_selector        <= 1'b0;
      reserved_bit_set    <= 1'b0;
      empty_advertisement <= 1'b0;
      not_bracketed       <= 1'b0;
 
      if (word_valid) begin
        if (!(&c_words)) c_words <= c_words + 1'b1;
 
        selector     <= sel_c;
        abilities    <= abil_c;
        remote_fault <= word_in[B_RF];
        ack          <= word_in[B_ACK];
        next_page    <= word_in[B_NP];
 
        // A word whose bits could not all be vouched for is not parsed.
        // Chapter 11.1's bit_confidence is what makes this checkable,
        // and a design that discards it cannot make this decision.
        if (!word_fully_bracketed) begin
          not_bracketed <= 1'b1;
          if (!(&c_rejected)) c_rejected <= c_rejected + 1'b1;
 
        end else if (bad_sel_c) begin
          // THE SELECTOR CHECK. Designed so one FLP mechanism could
          // serve several standards; useful because a bit-shifted
          // decode almost never lands 00001 in the low five bits.
          bad_selector      <= 1'b1;
          ever_bad_selector <= 1'b1;
          if (!(&c_bad_selector)) c_bad_selector <= c_bad_selector + 1'b1;
          if (!(&c_rejected))     c_rejected     <= c_rejected + 1'b1;
 
        end else if (reserved_c) begin
          // A reserved bit set is not a technology this design does not
          // know. It is a word that should not exist, and treating it
          // as an unknown ability would advertise agreement with it.
          reserved_bit_set <= 1'b1;
          if (!(&c_reserved_set)) c_reserved_set <= c_reserved_set + 1'b1;
          if (!(&c_rejected))     c_rejected     <= c_rejected + 1'b1;
 
        end else if (empty_c) begin
          // A partner claiming no technologies at all. LEGAL to
          // receive, and almost always a decode failure rather than a
          // real advertisement -- so it is reported and not resolved.
          empty_advertisement <= 1'b1;
          if (!(&c_empty_ads)) c_empty_ads <= c_empty_ads + 1'b1;
          if (!(&c_rejected))  c_rejected  <= c_rejected + 1'b1;
 
        end else begin
          parse_valid <= 1'b1;
        end
      end
    end
  end
 
endmodule

Classification: synthesizable.

What it teaches: that the selector field catches a corruption it was never designed to catch. It exists so one FLP mechanism could serve several standards — a use case that essentially never shipped. But a word rotated by Chapter 11.1 §5's late-pulse failure almost never has 00001 in its low five bits, so the check rejects the class of decode error that produces a plausible-looking word full of wrong abilities.

Deliberately simplified: three validations. A production parser also range-checks the next-page message code and handles selector values for the other standards that were allocated.

Production implication: empty_advertisement is reported rather than resolved, and the reasoning is worth stating. A partner advertising zero technologies is legal — it means I cannot do anythingand it is almost always a decode failure. Resolving it yields TECH_NONE and a link that does not come up; reporting it says whether the partner claimed nothing or whether this receiver failed to hear the claim, which are different work orders entirely.

6. The Priority Table

Each end advertises a set of abilities in its link code word, and each end receives the other's. Both then compute the intersection of the two sets and select the highest ranked member using a priority table. That table is not transmitted anywhere: each device holds its own copy, compiled from the standard by whoever implemented its firmware. So two devices with different tables will both complete the exchange successfully, both set acknowledge, and select different technologies, with no mechanism anywhere to detect the disagreement.Both advertisesets of abilitiesIntersectthe common setApply the tablehighest rank winsEach resolves aloneno exchange of resultsThe table is NOTsenteach holds its own copyDifferent tables →disagreeand nothing detects it12
Figure 2 — the table is the only part of the mechanism that is not on the wire, and both ends must hold identical copies.

Nine technologies, ranked. Highest common wins.

RankTechnologyWhere advertised
91000BASE-T full duplexnext page
81000BASE-T half duplexnext page
7100BASE-TX full duplexbase page, A3
6100BASE-T4base page, A4
5100BASE-TX half duplexbase page, A2
410BASE-T full duplexbase page, A1
310BASE-T half duplexbase page, A0

Two orderings in that table are worth pausing on.

Full duplex always outranks half duplex at the same speed, because a full-duplex link is strictly better — twice the capacity and no collisions — and there is no case in which a device that can do both prefers half.

And 100BASE-T4 outranks 100BASE-TX half duplex. T4 uses four pairs of Category 3 cable (Chapter 9.2 §13) and is half duplex only; TX half duplex uses two pairs of Category 5. They are the same speed and the same duplex, so the ordering is a judgement about which is preferable when both are available — and it is exactly the kind of judgement two implementers could compile differently.

Which brings us to the fact this whole chapter turns on: the table is not transmitted.

Each device holds its own copy, compiled from the standard by whoever wrote its firmware. Two devices with different tables complete the exchange successfully, both set ACK, and select different technologies — and there is no mechanism anywhere in autonegotiation to notice.

7. RTL 3 — Resolving, With the Table Made Checkable

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// SYNTHESIZABLE.
//
// Computes the resolution: intersect the two advertisements and select
// the highest-ranked common technology.
//
// THE DESIGN DECISION THAT MATTERS is that the table is expressed as a
// RANK FUNCTION rather than as an ordered if-else chain.
//
//   an if-else chain      -- correct or not, and the only way to check
//        it is to write the same chain again in a property, which
//        checks that two copies of one author's reading agree.
//   a rank function       -- has STRUCTURAL properties that hold for
//        ANY correct table: the ranks are distinct, they are a strict
//        total order, and the resolution is the argmax over the common
//        set. Those are checkable without re-deriving the order.
//
// Section 13's rejected property is the if-else chain written twice.
module priority_resolver
  import autoneg_res_pkg::*;
#(
  parameter int unsigned CNT_W = 16
) (
  input  logic clk,
  input  logic rst_n,
 
  input  logic [7:0] local_abilities,
  input  logic [7:0] partner_abilities,
  input  logic       local_1000t_hd,
  input  logic       local_1000t_fd,
  input  logic       partner_1000t_hd,
  input  logic       partner_1000t_fd,
  input  logic       resolve,
 
  output tech_e      resolution,
  output logic       resolution_valid,
  output logic [3:0] resolution_rank,
 
  // The common set, exported. A human debugging a wrong resolution
  // needs to see what BOTH ends claimed, and this is the intersection
  // the decision was actually made over.
  output logic [8:0] common_set,
  output logic [3:0] common_count,
 
  // No common technology at all. A distinct outcome from resolving to
  // the lowest one, and the two must never be confused.
  output logic       no_common_technology,
 
  // Flow control is resolved SEPARATELY, because PAUSE and ASM_DIR are
  // not technologies and ranking them yields "PAUSE", which is not a
  // way to run a link.
  output logic       pause_resolved,
  output logic       asm_dir_resolved,
 
  output logic [CNT_W-1:0] c_resolutions,
  output logic [CNT_W-1:0] c_no_common
);
 
  // The common set, one bit per technology, in rank order for clarity.
  //   [0] 10T HD  [1] 10T FD  [2] 100TX HD  [3] 100T4
  //   [4] 100TX FD [5] 1000T HD [6] 1000T FD
  logic [6:0] common_c;
  tech_e      best_c;
  logic [3:0] best_rank_c;
  logic [3:0] count_c;
 
  always_comb begin
    common_c[0] = local_abilities[A_10T      - 5] & partner_abilities[A_10T      - 5];
    common_c[1] = local_abilities[A_10T_FD   - 5] & partner_abilities[A_10T_FD   - 5];
    common_c[2] = local_abilities[A_100TX    - 5] & partner_abilities[A_100TX    - 5];
    common_c[3] = local_abilities[A_100T4    - 5] & partner_abilities[A_100T4    - 5];
    common_c[4] = local_abilities[A_100TX_FD - 5] & partner_abilities[A_100TX_FD - 5];
    common_c[5] = local_1000t_hd & partner_1000t_hd;
    common_c[6] = local_1000t_fd & partner_1000t_fd;
 
    count_c = 4'd0;
    for (int i = 0; i < 7; i = i + 1)
      if (common_c[i]) count_c = count_c + 4'd1;
 
    // ARGMAX OVER THE RANK FUNCTION. Not an ordered if-else chain --
    // a search for the highest rank among the common members. Which
    // means the ORDER lives in one place (tech_rank) and the SELECTION
    // logic is order-independent and separately checkable.
    best_c      = TECH_NONE;
    best_rank_c = 4'd0;
    if (common_c[0] && (tech_rank(TECH_10T_HD)   > best_rank_c)) begin
      best_c = TECH_10T_HD;   best_rank_c = tech_rank(TECH_10T_HD);   end
    if (common_c[1] && (tech_rank(TECH_10T_FD)   > best_rank_c)) begin
      best_c = TECH_10T_FD;   best_rank_c = tech_rank(TECH_10T_FD);   end
    if (common_c[2] && (tech_rank(TECH_100TX_HD) > best_rank_c)) begin
      best_c = TECH_100TX_HD; best_rank_c = tech_rank(TECH_100TX_HD); end
    if (common_c[3] && (tech_rank(TECH_100T4)    > best_rank_c)) begin
      best_c = TECH_100T4;    best_rank_c = tech_rank(TECH_100T4);    end
    if (common_c[4] && (tech_rank(TECH_100TX_FD) > best_rank_c)) begin
      best_c = TECH_100TX_FD; best_rank_c = tech_rank(TECH_100TX_FD); end
    if (common_c[5] && (tech_rank(TECH_1000T_HD) > best_rank_c)) begin
      best_c = TECH_1000T_HD; best_rank_c = tech_rank(TECH_1000T_HD); end
    if (common_c[6] && (tech_rank(TECH_1000T_FD) > best_rank_c)) begin
      best_c = TECH_1000T_FD; best_rank_c = tech_rank(TECH_1000T_FD); end
  end
 
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      resolution <= TECH_NONE; resolution_valid <= 1'b0;
      resolution_rank <= 4'd0; common_set <= 9'd0; common_count <= 4'd0;
      no_common_technology <= 1'b0;
      pause_resolved <= 1'b0; asm_dir_resolved <= 1'b0;
      c_resolutions <= '0; c_no_common <= '0;
    end else begin
      resolution_valid <= 1'b0;
 
      if (resolve) begin
        resolution       <= best_c;
        resolution_rank  <= best_rank_c;
        common_set       <= {2'd0, common_c};
        common_count     <= count_c;
        resolution_valid <= 1'b1;
        if (!(&c_resolutions)) c_resolutions <= c_resolutions + 1'b1;
 
        // NO COMMON TECHNOLOGY is a distinct outcome from resolving to
        // the lowest one. A link with nothing in common must not come
        // up; a link resolving to 10BASE-T half duplex must.
        no_common_technology <= (count_c == 4'd0);
        if (count_c == 4'd0) begin
          if (!(&c_no_common)) c_no_common <= c_no_common + 1'b1;
        end
 
        // FLOW CONTROL, resolved separately and never ranked. PAUSE is
        // not a way to run a link, and a resolver that ranks it can
        // select it.
        pause_resolved   <= local_abilities[A_PAUSE   - 5] &
                            partner_abilities[A_PAUSE - 5];
        asm_dir_resolved <= local_abilities[A_ASM_DIR   - 5] &
                            partner_abilities[A_ASM_DIR - 5];
      end
    end
  end
 
endmodule

Classification: synthesizable.

What it teaches: that expressing the table as a rank function rather than as an ordered if-else chain is what makes it checkable. An if-else chain encodes the order in its structure, so the only way to verify it is to write the same chain again in a property — which checks that two copies of one author's reading agree. A rank function separates the order (one small function) from the selection (an argmax that is order-independent), and the order then has structural properties that hold for any correct table: the ranks are distinct, they form a strict total order, and the result is the maximum over the common set.

Deliberately simplified: seven technologies with gigabit's two arriving as separate inputs from the next-page engine. Production resolvers handle more, including 100BASE-T2 and the various backplane technologies, with the same structure.

Production implication: common_set and common_count are exported because a wrong resolution is debugged by looking at the inputs, not the output. A link that came up at 10BASE-T when both ends support gigabit has a common set with one member — and seeing which member, and therefore which advertisements were missing, is the difference between suspecting the resolver and finding the lost pulse Chapter 11.1 §6 describes.

8. RTL 4 — Acknowledge: Three In, Six to Eight Out

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// SYNTHESIZABLE.
//
// Implements clause 28's acknowledge, whose rules are asymmetric and
// whose meaning is narrower than its name suggests.
//
// THE RULES:
//   RECEIVE side -- set ACK only after THREE identical copies of the
//        partner's link code word have arrived. Not three words: three
//        IDENTICAL ones. A partner mid-negotiation emits words that
//        change, and acting on the first is acting on a transient.
//   TRANSMIT side -- once ACK is set, send between SIX and EIGHT
//        copies with it set before considering the exchange complete.
//        The range is a range: fewer than six risks the partner
//        missing them all, more than eight wastes time.
//
// WHAT ACK MEANS: "I received your advertisement."
// WHAT IT DOES NOT MEAN: "I agree", "I applied it", "we resolved the
//        same way", or "we are configured identically".
//
// The gap between those two lists is where Chapter 9.2's duplex
// mismatch lives, and no bit in this protocol closes it.
module acknowledge_tracker
  import autoneg_res_pkg::*;
#(
  parameter int unsigned CNT_W = 16
) (
  input  logic clk,
  input  logic rst_n,
  input  logic restart,
 
  input  logic        word_received,
  input  logic [15:0] received_word,
  input  logic        partner_ack,
 
  output logic        send_ack,
  output logic        exchange_complete,
  output logic [3:0]  identical_count,
  output logic [3:0]  ack_sent_count,
 
  // The exchange completed, and this is EXACTLY what it establishes:
  // both ends received an advertisement. Nothing about conclusions.
  output logic        advertisement_confirmed,
  // The partner's word changed AFTER we set ACK. Legal -- it may be
  // renegotiating -- and worth counting, because a partner whose word
  // keeps changing is not converging.
  output logic        word_changed_after_ack,
 
  output logic [CNT_W-1:0] c_exchanges,
  output logic [CNT_W-1:0] c_restarts,
  output logic [CNT_W-1:0] c_changes_after_ack,
  output logic [3:0]       worst_identical_wait
);
 
  logic [15:0] last_word_q;
  logic [3:0]  same_q;
  logic [3:0]  sent_q;
  logic        acked_q;
 
  // Compare everything EXCEPT the acknowledge bit. The partner sets it
  // when it has heard us, so including it would restart our own count
  // every time the partner's state advances.
  wire [15:0] mask = 16'hFFFF & ~(16'd1 << B_ACK);
 
  assign identical_count = same_q;
  assign ack_sent_count  = sent_q;
 
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n || restart) begin
      last_word_q <= 16'd0; same_q <= 4'd0; sent_q <= 4'd0;
      acked_q <= 1'b0; send_ack <= 1'b0;
      exchange_complete <= 1'b0; advertisement_confirmed <= 1'b0;
      word_changed_after_ack <= 1'b0;
      worst_identical_wait <= 4'd0;
      if (!rst_n) begin
        c_exchanges <= '0; c_restarts <= '0; c_changes_after_ack <= '0;
      end else begin
        if (!(&c_restarts)) c_restarts <= c_restarts + 1'b1;
      end
    end else begin
      exchange_complete      <= 1'b0;
      word_changed_after_ack <= 1'b0;
 
      if (word_received) begin
        if ((received_word & mask) == (last_word_q & mask)) begin
          if (same_q != 4'd15) same_q <= same_q + 4'd1;
 
          // THREE IDENTICAL COPIES. Not three words -- three the same.
          // A partner mid-negotiation emits words that change, and a
          // receiver acting on the first reconfigures on a transient.
          if ((same_q + 4'd1) >= 4'(ACK_RX_REQUIRED) && !acked_q) begin
            acked_q  <= 1'b1;
            send_ack <= 1'b1;
            sent_q   <= 4'd0;
            if ((same_q + 4'd1) > worst_identical_wait)
              worst_identical_wait <= same_q + 4'd1;
          end
 
        end else begin
          if (acked_q) begin
            // The partner's advertisement changed after we acked it.
            // Legal -- it may be renegotiating -- and counted, because
            // a word that keeps changing is a partner not converging.
            word_changed_after_ack <= 1'b1;
            if (!(&c_changes_after_ack))
              c_changes_after_ack <= c_changes_after_ack + 1'b1;
          end
          same_q      <= 4'd1;
          last_word_q <= received_word;
          acked_q     <= 1'b0;
          send_ack    <= 1'b0;
          sent_q      <= 4'd0;
        end
      end
 
      if (acked_q && word_received) begin
        if (sent_q != 4'(ACK_TX_MAX)) sent_q <= sent_q + 4'd1;
 
        // SIX TO EIGHT copies sent with ACK set, AND the partner must
        // have acked us too. Both conditions: our advertisement was
        // heard, and theirs was.
        if ((sent_q + 4'd1 >= 4'(ACK_TX_MIN)) && partner_ack) begin
          exchange_complete       <= 1'b1;
          // AND THIS IS ALL IT ESTABLISHES. Both advertisements were
          // received. Not that both ends resolved the same way.
          advertisement_confirmed <= 1'b1;
          if (!(&c_exchanges)) c_exchanges <= c_exchanges + 1'b1;
        end
      end
    end
  end
 
endmodule

Classification: synthesizable.

What it teaches: that the comparison masks off the acknowledge bit, and forgetting that is a subtle and complete failure. The partner sets its ACK when it has heard us — an event driven by our own transmission — so a receiver comparing the whole word restarts its identical-copy count every time the partner's state advances. The count never reaches three, ACK is never set, and neither end ever completes, on a link where both are behaving correctly.

Deliberately simplified: the send count advances per received word rather than per transmitted burst. The real state machine counts transmitted link code words, and the six-to-eight range exists so that a few lost bursts do not prevent completion.

Production implication: advertisement_confirmed is named for exactly what it establishes and no more. Both ends received an advertisement. It does not say the two ends resolved the same way, and a system that treats exchange_complete as "we are configured identically" has assumed the one thing this protocol never provides — which is Section 13's subject.

9. What Acknowledge Establishes

Each end transmits its advertisement repeatedly. Each end waits for three identical copies from the other before setting the acknowledge bit, then sends between six and eight copies with acknowledge set. When both ends have seen the other's acknowledge, the exchange is complete. What that establishes is that both advertisements were received. Each end then applies its own copy of the priority table to the intersection of the two advertisements and selects a technology, entirely independently, and no further message is exchanged. So the resolution is never confirmed, never compared and never acknowledged, and two ends holding different tables complete the exchange successfully and disagree.Advertise,repeatedlyevery 8–16 msThree identicalthen set ACKSix to eight sentwith ACK setExchange completeboth were heardEach resolves aloneown table, no messageNever confirmedthe mismatch lives here12
Figure 3 — the acknowledge closes the loop on the advertisement and leaves the resolution entirely unconfirmed.

Be precise about what a completed exchange proves, because the gap is the whole chapter.

StatementEstablished by the exchange?
my advertisement reached the partneryes — the partner's ACK
the partner's advertisement reached meyes — my three identical copies
both advertisements were received intactpartly — three identical copies is strong evidence
the partner applied my abilities to a tableno
the partner's table is the same as mineno
we selected the same technologyno
we are configured identicallyno

Rows four to seven are all unconfirmed, and rows six and seven are the ones that matter.

The arithmetic of the exchange, computed:

StepAt 8 ms spacingAt 16 ms spacing
three identical copies received24 ms48 ms
six copies sent with ACK48 ms96 ms
eight copies sent with ACK64 ms128 ms
worst-case total88 ms176 ms

So a negotiation takes tens to low hundreds of milliseconds — which matches Chapter 11.1 §13's budget and is the number to compare a slow link against.

And the three-copy rule is not debouncing. A partner mid-negotiation emits words that change: it may be adding next pages, setting its own ACK, or restarting. Three identical copies means the partner has settled, which is a statement about the far end's state machine rather than about noise.

10. RTL 5 — Next Pages: Extending Sixteen Bits

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// SYNTHESIZABLE.
//
// The next-page mechanism, which is how a 16-bit word came to carry
// gigabit abilities that did not exist when it was defined.
//
// THE PROBLEM: the base page has 8 technology bits and they were all
// allocated. 1000BASE-T needs two more, plus a master/slave preference
// (Chapter 9.3 §4), plus a seed for the tie-break.
//
// THE MECHANISM: bit 15 (NP) says "another page follows". Pages are
// exchanged in the same FLP bursts, each acknowledged the same way, and
// the sequence continues until both ends clear NP.
//
// THE RULE THAT MAKES IT WORK: a device that does not understand next
// pages sets NP=0 and the exchange ends after the base page -- so an
// old device negotiates successfully against a new one and simply does
// not learn about the abilities it could not have used anyway.
//
// AND THE ASYMMETRY: if ONE end has more pages to send, the other must
// keep sending NULL pages to keep the exchange alive. A device that
// stops because it has nothing more to say stalls a partner that does.
module next_page_engine
  import autoneg_res_pkg::*;
#(
  parameter int unsigned MAX_PAGES = 8,
  parameter int unsigned CNT_W = 16
) (
  input  logic clk,
  input  logic rst_n,
  input  logic restart,
 
  input  logic        base_page_done,
  input  logic        partner_np,          // partner has more to send
  input  logic        page_acked,          // this page's exchange done
  input  logic [15:0] partner_page,
 
  // Pages this device wants to send, presented one at a time.
  input  logic        have_page,
  input  logic [15:0] page_to_send,
 
  output logic [15:0] page_out,
  output logic        page_out_valid,
  output logic        np_bit,
  output logic        sending_null_page,
 
  // Extracted gigabit abilities, which is what next pages are mostly
  // used for in practice.
  output logic        partner_1000t_hd,
  output logic        partner_1000t_fd,
  output logic        partner_prefers_master,
 
  output logic        exchange_done,
  output logic [3:0]  pages_exchanged,
  // The page count hit its bound. A partner that keeps setting NP
  // forever is either broken or speaking an extension this design
  // does not know, and either way the exchange must terminate.
  output logic        page_limit_reached,
 
  output logic [CNT_W-1:0] c_pages,
  output logic [CNT_W-1:0] c_null_pages,
  output logic [CNT_W-1:0] c_limit_hits,
  output logic             ever_limit_reached
);
 
  // A null message page: valid, acknowledgeable, and carrying nothing.
  // It exists so a device with nothing left to say can keep a partner's
  // page sequence alive.
  localparam logic [15:0] NULL_MESSAGE_PAGE = 16'h2001;
 
  logic [3:0] count_q;
  logic       active_q;
 
  assign pages_exchanged = count_q;
 
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n || restart) begin
      count_q <= 4'd0; active_q <= 1'b0;
      page_out <= 16'd0; page_out_valid <= 1'b0; np_bit <= 1'b0;
      sending_null_page <= 1'b0;
      partner_1000t_hd <= 1'b0; partner_1000t_fd <= 1'b0;
      partner_prefers_master <= 1'b0;
      exchange_done <= 1'b0; page_limit_reached <= 1'b0;
      if (!rst_n) begin
        c_pages <= '0; c_null_pages <= '0; c_limit_hits <= '0;
        ever_limit_reached <= 1'b0;
      end
    end else begin
      page_out_valid     <= 1'b0;
      page_limit_reached <= 1'b0;
 
      if (base_page_done && !active_q) begin
        active_q      <= 1'b1;
        exchange_done <= 1'b0;
      end
 
      if (active_q) begin
        if (count_q == 4'(MAX_PAGES)) begin
          // BOUNDED. A partner that keeps setting NP forever is broken
          // or speaking an extension we do not know, and either way
          // the exchange must terminate rather than continue.
          page_limit_reached <= 1'b1;
          ever_limit_reached <= 1'b1;
          exchange_done      <= 1'b1;
          active_q           <= 1'b0;
          if (!(&c_limit_hits)) c_limit_hits <= c_limit_hits + 1'b1;
 
        end else if (page_acked) begin
          count_q <= count_q + 4'd1;
          if (!(&c_pages)) c_pages <= c_pages + 1'b1;
 
          // Extract what the partner's page carried. In practice next
          // pages are mostly gigabit abilities plus Chapter 9.3's
          // master/slave preference.
          if (partner_page[0]) begin
            partner_1000t_hd       <= partner_page[9];
            partner_1000t_fd       <= partner_page[10];
            partner_prefers_master <= partner_page[12];
          end
 
          if (have_page) begin
            page_out          <= page_to_send;
            np_bit            <= 1'b1;
            sending_null_page <= 1'b0;
            page_out_valid    <= 1'b1;
 
          end else if (partner_np) begin
            // THE ASYMMETRY. We have nothing more to say and the
            // partner does -- so we must keep the sequence alive with
            // a null page. A device that simply stops here stalls a
            // partner that still has pages to send.
            page_out          <= NULL_MESSAGE_PAGE;
            np_bit            <= 1'b1;
            sending_null_page <= 1'b1;
            page_out_valid    <= 1'b1;
            if (!(&c_null_pages)) c_null_pages <= c_null_pages + 1'b1;
 
          end else begin
            // Neither end has more. The sequence ends here.
            np_bit        <= 1'b0;
            active_q      <= 1'b0;
            exchange_done <= 1'b1;
          end
        end
      end
    end
  end
 
endmodule

Classification: synthesizable.

What it teaches: that a device with nothing left to say must keep sending null pages while its partner still has pages to send, and this asymmetry is the mechanism's least obvious rule. Next pages are exchanged in lockstep — each page acknowledged before the next — so a device that simply stops because its own list is empty stalls a partner whose list is not. The null message page exists for exactly this: a page that is valid, acknowledgeable, and carries nothing.

Deliberately simplified: page contents are extracted with fixed bit positions. Real next pages have message and unformatted variants with a message-code field selecting the interpretation, and gigabit's abilities occupy defined positions in a specific message page.

Production implication: page_limit_reached bounds a sequence that a conforming partner will terminate and a broken one will not. A device that sets NP forever — because of a firmware bug, or because it speaks an extension with more pages than this design knows — would otherwise hold the exchange open indefinitely, and the link would never come up with no timer anywhere expiring.

11. RTL 6 — Checking the Table Without Re-Deriving It

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// SYNTHESIZABLE.
//
// Checks the priority table's STRUCTURE rather than its contents.
//
// THE PROBLEM Section 13's rejected property runs into: to verify that
// the resolver picks the right technology, a property must know which
// technology is right -- which means implementing the table again, in
// the property, from the same reading of the standard by the same
// author. A misreading is then duplicated into both, and the assertion
// is green.
//
// WHAT THIS MODULE DOES INSTEAD: it checks properties that hold for
// ANY correct table and fail for specific CLASSES of table error,
// without knowing what the correct order is.
//
//   1. the ranks are DISTINCT -- no two technologies share one, which
//      catches a copy-paste duplicate.
//   2. the ranks are DENSE over their range -- no gaps, which catches
//      an omitted entry.
//   3. every technology has a NON-ZERO rank -- which catches an
//      unhandled enum case falling into the default.
//   4. the ordering is CONSISTENT with two invariants the standard
//      states in prose and which no plausible misreading violates:
//        full duplex outranks half duplex at the same speed, and
//        a higher speed outranks a lower one at the same duplex.
//
// The fourth is the interesting one. It does not encode the table; it
// encodes two RULES the table must satisfy -- and it catches a swapped
// pair without anybody re-deriving the order.
module resolution_consistency_checker
  import autoneg_res_pkg::*;
#(
  parameter int unsigned N_TECH = 7,
  parameter int unsigned CNT_W  = 16
) (
  input  logic clk,
  input  logic rst_n,
 
  input  logic check_request,
 
  output logic table_valid,
  output logic ranks_distinct,
  output logic ranks_dense,
  output logic all_ranks_nonzero,
  output logic duplex_ordering_ok,
  output logic speed_ordering_ok,
 
  output logic [3:0] first_bad_rank,
  output logic [CNT_W-1:0] c_checks,
  output logic [CNT_W-1:0] c_failures,
  output logic             ever_table_invalid
);
 
  tech_e ranked [N_TECH];
  logic  distinct_c, dense_c, nonzero_c, duplex_c, speed_c;
  logic [3:0] bad_c;
  logic [15:0] seen_c;
 
  always_comb begin
    ranked[0] = TECH_10T_HD;
    ranked[1] = TECH_10T_FD;
    ranked[2] = TECH_100TX_HD;
    ranked[3] = TECH_100T4;
    ranked[4] = TECH_100TX_FD;
    ranked[5] = TECH_1000T_HD;
    ranked[6] = TECH_1000T_FD;
 
    // 1 and 3: distinct, and none falling through to the default.
    distinct_c = 1'b1;
    nonzero_c  = 1'b1;
    seen_c     = 16'd0;
    bad_c      = 4'd0;
    for (int i = 0; i < N_TECH; i = i + 1) begin
      if (tech_rank(ranked[i]) == 4'd0) begin
        nonzero_c = 1'b0;
        bad_c     = 4'(i);
      end
      if (seen_c[tech_rank(ranked[i])]) begin
        distinct_c = 1'b0;
        bad_c      = tech_rank(ranked[i]);
      end
      seen_c[tech_rank(ranked[i])] = 1'b1;
    end
 
    // 2: dense -- the N ranks occupy N consecutive values, so an
    // omitted entry leaves a gap and is caught.
    dense_c = 1'b1;
    for (int r = 3; r < 3 + N_TECH; r = r + 1)
      if (!seen_c[r]) dense_c = 1'b0;
 
    // 4a: full duplex outranks half duplex at the SAME speed. A rule
    // from the standard's prose that no plausible misreading violates,
    // and it catches a swapped pair without encoding the order.
    duplex_c = (tech_rank(TECH_10T_FD)   > tech_rank(TECH_10T_HD)) &&
               (tech_rank(TECH_100TX_FD) > tech_rank(TECH_100TX_HD)) &&
               (tech_rank(TECH_1000T_FD) > tech_rank(TECH_1000T_HD));
 
    // 4b: a higher speed outranks a lower one at the SAME duplex.
    speed_c = (tech_rank(TECH_100TX_HD) > tech_rank(TECH_10T_HD)) &&
              (tech_rank(TECH_1000T_HD) > tech_rank(TECH_100TX_HD)) &&
              (tech_rank(TECH_100TX_FD) > tech_rank(TECH_10T_FD)) &&
              (tech_rank(TECH_1000T_FD) > tech_rank(TECH_100TX_FD));
  end
 
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      table_valid <= 1'b0; ranks_distinct <= 1'b0; ranks_dense <= 1'b0;
      all_ranks_nonzero <= 1'b0; duplex_ordering_ok <= 1'b0;
      speed_ordering_ok <= 1'b0; first_bad_rank <= 4'd0;
      c_checks <= '0; c_failures <= '0; ever_table_invalid <= 1'b0;
    end else if (check_request) begin
      ranks_distinct     <= distinct_c;
      ranks_dense        <= dense_c;
      all_ranks_nonzero  <= nonzero_c;
      duplex_ordering_ok <= duplex_c;
      speed_ordering_ok  <= speed_c;
      first_bad_rank     <= bad_c;
 
      table_valid <= distinct_c && dense_c && nonzero_c &&
                     duplex_c && speed_c;
 
      if (!(&c_checks)) c_checks <= c_checks + 1'b1;
      if (!(distinct_c && dense_c && nonzero_c && duplex_c && speed_c)) begin
        ever_table_invalid <= 1'b1;
        if (!(&c_failures)) c_failures <= c_failures + 1'b1;
      end
    end
  end
 
endmodule

Classification: synthesizable; in practice this runs once at reset or is elaborated away entirely, and its value is that it fails elaboration or bring-up rather than shipping.

What it teaches: that a table can be checked structurally without anybody re-deriving its contents. The five checks catch classes of error: a duplicated rank (copy-paste), a gap (an omitted entry), a zero rank (an enum case falling into the default), a swapped duplex pair, and a swapped speed pair. None of them requires knowing what the correct order is — they encode two rules from the standard's prose plus three structural invariants.

Deliberately simplified: seven technologies and a fixed rank base of 3. A production version is usually a set of elaboration-time assertions or a generated table with the checks in the generator, so the cost at runtime is zero.

Production implication: this is the only check in the entire mechanism that can catch a wrong priority table, because Section 6 established that the table is never transmitted. Two devices with different tables negotiate successfully and disagree, and no runtime observation at either end distinguishes that from a correct negotiation. A structural check at build time is the last point at which the error is catchable at all.

12. RTL 7 — Reporting What Was Agreed and What Was Not

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// SYNTHESIZABLE.
//
// Publishes what the negotiation established, what it assumed, and how
// much margin it had -- the same provenance-and-margin discipline
// Chapter 11.1 §12 applies to discovery.
//
// THE CENTRAL OUTPUT: resolution_is_unconfirmed. It is TRUE on every
// successful negotiation, always, because the protocol never confirms
// a resolution. Publishing a constant true might look pointless; it is
// not. It is the design stating, in a register a human can read, that
// the thing everybody assumes was checked was not.
module resolution_telemetry
  import autoneg_res_pkg::*;
#(
  parameter int unsigned CNT_W = 16
) (
  input  logic clk,
  input  logic rst_n,
  input  logic clear,
 
  input  logic        resolution_valid,
  input  tech_e       resolution,
  input  logic [8:0]  common_set,
  input  logic [3:0]  common_count,
  input  logic        no_common_technology,
  input  logic        advertisement_confirmed,
  input  logic        table_valid,
  input  logic        parse_valid,
  input  logic        bad_selector,
  input  logic        empty_advertisement,
  input  logic [3:0]  pages_exchanged,
  input  logic [15:0] exchange_ms,
  input  logic        over_advertisement_refused,
 
  // What was established.
  output tech_e resolved_technology,
  output logic  advertisements_were_confirmed,
  // ALWAYS TRUE. The protocol has no mechanism to confirm a
  // resolution, and saying so in a register is the honest output.
  output logic  resolution_is_unconfirmed,
 
  // How much room there was.
  output logic [3:0]  common_count_last,
  output logic        resolved_at_lowest_common,
  output logic [15:0] worst_exchange_ms,
  output logic [3:0]  worst_pages,
 
  output logic [CNT_W-1:0] c_resolutions,
  output logic [CNT_W-1:0] c_no_common,
  output logic [CNT_W-1:0] c_rejected_words,
 
  // Sticky facts a counter clear destroys.
  output logic ever_no_common,
  output logic ever_bad_table,
  output logic ever_over_advertised,
  output logic ever_single_option
);
 
  // The protocol has no confirmation mechanism, so this is a constant.
  assign resolution_is_unconfirmed = 1'b1;
 
  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      resolved_technology <= TECH_NONE;
      advertisements_were_confirmed <= 1'b0;
      common_count_last <= 4'd0; resolved_at_lowest_common <= 1'b0;
      worst_exchange_ms <= 16'd0; worst_pages <= 4'd0;
      c_resolutions <= '0; c_no_common <= '0; c_rejected_words <= '0;
      ever_no_common <= 1'b0; ever_bad_table <= 1'b0;
      ever_over_advertised <= 1'b0; ever_single_option <= 1'b0;
    end else begin
      if (clear) begin
        c_resolutions <= '0; c_no_common <= '0; c_rejected_words <= '0;
        worst_exchange_ms <= 16'd0; worst_pages <= 4'd0;
        // The four ever_* flags survive.
      end
 
      if (!table_valid) ever_bad_table <= 1'b1;
      if (over_advertisement_refused) ever_over_advertised <= 1'b1;
      if (bad_selector || empty_advertisement || !parse_valid) begin
        if (!(&c_rejected_words)) c_rejected_words <= c_rejected_words + 1'b1;
      end
 
      if (resolution_valid) begin
        resolved_technology           <= resolution;
        advertisements_were_confirmed <= advertisement_confirmed;
        common_count_last             <= common_count;
 
        // A resolution with exactly ONE common technology has no
        // fallback: any further loss of an advertised ability takes the
        // link down rather than a step down. Not an error, and the only
        // warning available before it happens.
        if (common_count == 4'd1) ever_single_option <= 1'b1;
        resolved_at_lowest_common <= (common_count == 4'd1);
 
        if (exchange_ms > worst_exchange_ms) worst_exchange_ms <= exchange_ms;
        if (pages_exchanged > worst_pages)   worst_pages <= pages_exchanged;
 
        if (!(&c_resolutions)) c_resolutions <= c_resolutions + 1'b1;
        if (no_common_technology) begin
          ever_no_common <= 1'b1;
          if (!(&c_no_common)) c_no_common <= c_no_common + 1'b1;
        end
      end
    end
  end
 
endmodule

Classification: synthesizable.

What it teaches: that publishing a constant true is sometimes the most useful thing a design can do. resolution_is_unconfirmed is asserted on every successful negotiation, forever, because the protocol has no mechanism to confirm a resolution — and stating that in a register is what stops a system integrator from assuming it was checked. The alternative is a design that reports negotiation_complete and lets everybody above it infer more than happened.

Deliberately simplified: the margin outputs are a small selection. A production block also reports the resolved flow-control state, the remote-fault history and the number of restarts.

Production implication: ever_single_option is the chapter's margin signal, and it is the analogue of Chapter 10.4's narrow eye. A link that resolved with a common set of one has no fallback: the next lost pulse, the next ageing cable, the next configuration change takes the link down rather than a step down. A link with a common set of five degrades gracefully three more times before that happens. Both report the same resolved technology, and only the count distinguishes them.

13. Properties Worth Asserting, and One Worth Refusing

Every earlier chapter's rejected property was wrong about the world — a clock that stops, a stream that changes, an absence with several causes. This one is wrong about the checker itself.

The advertisement

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// P1. The selector is always the 802.3 value.
property p_selector_is_802_3;
  @(posedge clk) disable iff (!rst_n)
  link_code_word[4:0] == SELECTOR_802_3;
endproperty
a_selector_802_3: assert property (p_selector_is_802_3);
 
// P2. The reserved bit is never advertised.
property p_reserved_never_set;
  @(posedge clk) disable iff (!rst_n)
  !link_code_word[A_RESERVED];
endproperty
a_reserved_never_set: assert property (p_reserved_never_set);
 
// P3. THE SUBSET PROPERTY. Software may subtract abilities and never
// add them -- an advertised ability the hardware cannot deliver wins
// the resolution at BOTH ends and then fails to establish.
property p_advertisement_subset_of_capability;
  @(posedge clk) disable iff (!rst_n)
  (link_code_word[12:5] & ~capability_c) == 8'd0;
endproperty
a_advertisement_subset: assert property (p_advertisement_subset_of_capability);
 
// P4. And an attempt to over-advertise is REPORTED, not silently
// clipped -- the configuration is wrong and somebody needs to know.
property p_over_advertisement_reported;
  @(posedge clk) disable iff (!rst_n)
  ((requested_c & ~capability_c) != 8'd0) |=> over_advertisement_refused;
endproperty
a_over_advertisement_reported: assert property (p_over_advertisement_reported);
 
// P5. Gigabit sets the next-page bit, because the base page cannot
// carry it.
property p_gigabit_requires_next_page;
  @(posedge clk) disable iff (!rst_n)
  next_page_required |-> link_code_word[B_NP];
endproperty
a_gigabit_needs_np: assert property (p_gigabit_requires_next_page);

Parsing and validation

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// P6. A word whose bits could not all be vouched for is never parsed.
// Chapter 11.1's confidence is what makes this decidable.
property p_unbracketed_never_parsed;
  @(posedge clk) disable iff (!rst_n)
  (word_valid && !word_fully_bracketed) |=> !parse_valid;
endproperty
a_unbracketed_not_parsed: assert property (p_unbracketed_never_parsed);
 
// P7. A bad selector rejects the word. Designed for multi-standard
// use; useful because a bit-rotated word almost never has 00001.
property p_bad_selector_rejects;
  @(posedge clk) disable iff (!rst_n)
  (word_valid && word_fully_bracketed && (word_in[4:0] != SELECTOR_802_3))
    |=> (bad_selector && !parse_valid);
endproperty
a_bad_selector_rejects: assert property (p_bad_selector_rejects);
 
// P8. A reserved bit set rejects the word rather than being treated as
// an unknown ability.
property p_reserved_set_rejects;
  @(posedge clk) disable iff (!rst_n)
  (word_valid && word_fully_bracketed && word_in[A_RESERVED])
    |=> (reserved_bit_set && !parse_valid);
endproperty
a_reserved_rejects: assert property (p_reserved_set_rejects);
 
// P9. An empty advertisement is REPORTED rather than resolved to
// nothing -- "the partner claimed nothing" and "we failed to hear the
// claim" are different work orders.
property p_empty_advertisement_reported;
  @(posedge clk) disable iff (!rst_n)
  (word_valid && word_fully_bracketed && (word_in[9:5] == 5'd0))
    |=> empty_advertisement;
endproperty
a_empty_reported: assert property (p_empty_advertisement_reported);

The resolution — structural properties only

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// P10. THE MEMBERSHIP PROPERTY. The resolution is a member of the
// common set. True for ANY correct table, and it catches a resolver
// that selects something neither end advertised.
property p_resolution_is_common;
  @(posedge clk) disable iff (!rst_n)
  (resolution_valid && (resolution != TECH_NONE))
    |-> common_set[resolution_index(resolution)];
endproperty
a_resolution_is_common: assert property (p_resolution_is_common);
 
// P11. THE MAXIMALITY PROPERTY. No common member outranks the
// resolution. Also true for any correct table -- it says the resolver
// implements an argmax, without saying what the ranks should be.
property p_resolution_is_maximal;
  @(posedge clk) disable iff (!rst_n)
  resolution_valid |-> (resolution_rank == max_rank_over(common_set));
endproperty
a_resolution_is_maximal: assert property (p_resolution_is_maximal);
 
// P12. THE MONOTONICITY PROPERTY. Adding an ability to either
// advertisement never LOWERS the resolution. A table with a swapped
// pair violates this for the specific inputs that expose the swap.
property p_resolution_monotone;
  @(posedge clk) disable iff (!rst_n)
  (resolution_valid && $past(resolution_valid) &&
   ((local_abilities & $past(local_abilities)) == $past(local_abilities)) &&
   (partner_abilities == $past(partner_abilities)))
    |-> (resolution_rank >= $past(resolution_rank));
endproperty
a_resolution_monotone: assert property (p_resolution_monotone);
 
// P13. THE DETERMINISM PROPERTY. The same inputs always yield the same
// resolution -- which is what makes two ends with the SAME table agree.
property p_resolution_deterministic;
  @(posedge clk) disable iff (!rst_n)
  (resolution_valid && $past(resolution_valid) &&
   (local_abilities   == $past(local_abilities)) &&
   (partner_abilities == $past(partner_abilities)))
    |-> (resolution == $past(resolution));
endproperty
a_resolution_deterministic: assert property (p_resolution_deterministic);
 
// P14. An empty common set yields TECH_NONE and a distinct flag -- not
// the lowest technology.
property p_no_common_is_distinct;
  @(posedge clk) disable iff (!rst_n)
  (resolution_valid && (common_count == 4'd0))
    |-> (no_common_technology && (resolution == TECH_NONE));
endproperty
a_no_common_distinct: assert property (p_no_common_is_distinct);
 
// P15. Flow control is never a resolution. PAUSE is not a way to run
// a link, and a resolver that ranks it can select it.
property p_flow_control_not_a_technology;
  @(posedge clk) disable iff (!rst_n)
  resolution_valid |-> (resolution inside {TECH_NONE, TECH_10T_HD,
    TECH_10T_FD, TECH_100TX_HD, TECH_100T4, TECH_100TX_FD,
    TECH_1000T_HD, TECH_1000T_FD});
endproperty
a_flow_control_not_tech: assert property (p_flow_control_not_a_technology);

The table's structure

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// P16. Ranks are distinct -- catches a copy-paste duplicate.
property p_ranks_distinct;
  @(posedge clk) disable iff (!rst_n)
  check_request |=> ranks_distinct;
endproperty
a_ranks_distinct: assert property (p_ranks_distinct);
 
// P17. Ranks are dense -- catches an omitted entry.
property p_ranks_dense;
  @(posedge clk) disable iff (!rst_n)
  check_request |=> ranks_dense;
endproperty
a_ranks_dense: assert property (p_ranks_dense);
 
// P18. No technology falls into the default case.
property p_no_zero_ranks;
  @(posedge clk) disable iff (!rst_n)
  check_request |=> all_ranks_nonzero;
endproperty
a_no_zero_ranks: assert property (p_no_zero_ranks);
 
// P19. Full duplex outranks half duplex at the same speed. A rule from
// the standard's prose, not a re-derivation of the table.
property p_full_outranks_half;
  @(posedge clk) disable iff (!rst_n)
  check_request |=> duplex_ordering_ok;
endproperty
a_full_outranks_half: assert property (p_full_outranks_half);
 
// P20. And a higher speed outranks a lower one at the same duplex.
property p_faster_outranks_slower;
  @(posedge clk) disable iff (!rst_n)
  check_request |=> speed_ordering_ok;
endproperty
a_faster_outranks_slower: assert property (p_faster_outranks_slower);

Acknowledge and next pages

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// P21. ACK is set only after three IDENTICAL copies -- and the
// comparison masks the ACK bit, or the count never reaches three.
property p_ack_needs_three_identical;
  @(posedge clk) disable iff (!rst_n)
  $rose(send_ack) |-> ($past(same_q) >= 4'(ACK_RX_REQUIRED) - 4'd1);
endproperty
a_ack_needs_three: assert property (p_ack_needs_three_identical);
 
// P22. The exchange completes only after at least ACK_TX_MIN copies
// have been sent AND the partner has acked.
property p_exchange_needs_six_and_partner_ack;
  @(posedge clk) disable iff (!rst_n)
  exchange_complete |-> (($past(sent_q) + 4'd1 >= 4'(ACK_TX_MIN)) &&
                         $past(partner_ack));
endproperty
a_exchange_needs_six: assert property (p_exchange_needs_six_and_partner_ack);
 
// P23. A device with nothing left to send keeps the sequence alive
// with a null page while the partner still has pages.
property p_null_page_when_partner_has_more;
  @(posedge clk) disable iff (!rst_n)
  (page_acked && !have_page && partner_np) |=> sending_null_page;
endproperty
a_null_page_kept_alive: assert property (p_null_page_when_partner_has_more);
 
// P24. The page sequence terminates. A partner setting NP forever must
// not hold the exchange open indefinitely.
property p_page_sequence_bounded;
  @(posedge clk) disable iff (!rst_n)
  $rose(active_q) |-> ##[1:$] (exchange_done || page_limit_reached);
endproperty
a_page_sequence_bounded: assert property (p_page_sequence_bounded);

14. Verification Scenarios

  1. Full capability, no admin restriction — all supported abilities advertised, selector 00001, reserved bit clear.
  2. Software disabling 100BASE-TX full duplex — the bit clears; everything else is unchanged.
  3. Software requesting 1000BASE-T on hardware without itover_advertisement_refused, refused_bits naming it, and the bit is not advertised.
  4. A capability register of all zeros — an empty advertisement is built; legal to send, and the far end will report it.
  5. Gigabit capable and enablednext_page_required and bit 15 set.
  6. ACK driven by the tracker — the builder never sets it itself; ownership is exactly one module's.

Parsing

  1. A well-formed word — parsed, all fields extracted, parse_valid.
  2. Selector 00010bad_selector, parse_valid low, ever_bad_selector sticky.
  3. A word rotated by one bit (Chapter 11.1 §5's late-pulse failure) — the selector almost never survives; rejected. The check catching what it was not designed for.
  4. Reserved bit A7 setreserved_bit_set, rejected.
  5. All five technology bits zero, PAUSE setempty_advertisement; the partner advertised flow control and no way to run.
  6. A word with word_fully_bracketed lownot_bracketed, never parsed, whatever its contents.
  7. Selector correct but abilities implausible (all ones) — parsed; the design has no basis to reject it, and the resolution will select the highest.

Resolution

  1. Both ends advertising everything — resolution is 1000BASE-T full duplex, common_count = 7.
  2. Both advertising only 10BASE-T half duplex — resolution TECH_10T_HD, common_count = 1, resolved_at_lowest_common.
  3. No overlap at allno_common_technology, resolution TECH_NONE, distinct from resolving to the lowest.
  4. 100BASE-T4 and 100BASE-TX half duplex both common, nothing higher — resolution is T4, which is the table's one genuinely debatable ordering.
  5. 100BASE-TX full duplex and 100BASE-T4 both common — resolution is TX full duplex; full duplex outranks a half-duplex technology at the same speed.
  6. PAUSE and ASM_DIR common, no technology commonno_common_technology; flow control is never a resolution. P15.
  7. Adding an ability to the local advertisement — the resolution never falls. P12, monotonicity.
  8. The same inputs presented twice — the same resolution. P13, determinism.
  9. A resolver mutated to select a non-common technology — P10 fires.
  10. A resolver mutated to select a non-maximal common member — P11 fires.

The table

  1. The correct table — all five structural checks pass, table_valid.
  2. Two technologies given the same rankranks_distinct low, first_bad_rank naming it.
  3. One technology omitted from the rank function — falls to the default, rank 0: all_ranks_nonzero low.
  4. A gap in the ranksranks_dense low.
  5. 10BASE-T full duplex ranked below half duplexduplex_ordering_ok low. A swapped pair, caught without re-deriving the table.
  6. 100BASE-TX half duplex ranked above 1000BASE-T half duplexspeed_ordering_ok low.
  7. T4 and TX half duplex swappedall five structural checks pass, because neither prose rule constrains that pair. The honest limit of the method, and the case scenario 33 is about.

Acknowledge and next pages

  1. Three identical wordssend_ack rises exactly then, not before.
  2. Two identical words then a different one — the count restarts; ACK not set.
  3. The partner's word changing only in bit 14 — the count continues; the mask works. Without it, neither end ever completes.
  4. A comparison that does not mask ACK (deliberate mutation) — send_ack never rises at either end; the link never comes up, symmetrically.
  5. Six copies sent with ACK and the partner ackedexchange_complete.
  6. Five copies sent — not complete; ACK_TX_MIN is a floor.
  7. The partner's word changing after ACKword_changed_after_ack, counted, and the exchange restarts.
  8. A next page exchanged after the base pagepages_exchanged increments, gigabit abilities extracted.
  9. This end out of pages, partner still sendingnull pages emitted; the sequence continues. P23.
  10. A partner setting NP foreverpage_limit_reached at MAX_PAGES; the exchange terminates.

15. Debugging: The Table Is the Last Thing Anybody Suspects

ObservationLikely causeThe distinguishing check
link comes up one step below what both ends supporta lost pulse (Chapter 11.1 §6)common_count; the missing member names the lost bit
the two ends report different technologiesdifferent priority tablescompare both ends' resolved technology; nothing else can
link negotiates to gigabit and will not establishan over-advertisement — a claimed ability the hardware lacksever_over_advertised, refused_bits
neither end ever completes the exchangethe ACK bit not masked in the identical-copy compareidentical_count stuck below three at both ends
the exchange restarts continuouslythe partner's word keeps changingc_changes_after_ack; the partner is not converging
gigabit never negotiated between capable devicesthe next-page sequence stalledpages_exchanged, sending_null_page
the exchange never terminatesa partner setting NP foreverpage_limit_reached
resolution TECH_NONE with both ends capablewords rejected before resolutionc_rejected_words, bad_selector, not_bracketed
link comes up correctly but has no fallbackcommon_count == 1ever_single_option; not an error, and the only warning
abilities decode to nonsensea bit-rotated wordbad_selector — the selector catches it

Four habits.

First, on any "wrong speed" complaint, read common_count before anything else. A resolution at 10BASE-T with a common set of one means everything else was lost or not advertised; the same resolution with a common set of five means the partner genuinely cannot do more. Same resolved technology, opposite diagnoses.

Second, when the two ends report different technologies, stop looking at the link. The cable is fine, the pulses are fine, the exchange completed and both acknowledged. The only unshared constant in the mechanism is the priority table, and comparing the two ends' resolved technology is the only observation that distinguishes a table disagreement from anything else.

Third, treat "neither end completes" as an ACK-masking bug. It fails symmetrically, at both ends, on a perfect link — which makes it look like a physical problem. identical_count stuck at one or two at both ends is the signature, and it is one line of RTL.

Fourth, treat ever_single_option on a working link as an open item. A resolution with one common technology has no fallback: the next lost pulse takes the link down rather than a step down. A resolution with five degrades gracefully three more times first.

16. Common Misconceptions

"Autonegotiation agrees on a configuration."

The wrong model: two peers negotiate and converge on a shared answer.

What it costs: you cannot explain a duplex mismatch, a table disagreement, or why ACK does not prevent either.

The corrected model: it exchanges abilities and never conclusions. Each end advertises what it can do; each end then applies its own copy of a priority table to the intersection, independently; and no further message is exchanged. The resolution is never transmitted, never compared and never acknowledged — so two ends with different tables complete the exchange successfully and disagree, with every counter clean.

"The acknowledge bit confirms the agreement."

The wrong model: ACK closes the loop on the outcome.

What it costs: a system that treats exchange_complete as "we are configured identically" — which is exactly the assumption Chapter 9.2's mismatch violates.

The corrected model: ACK means I received your advertisement. It is set after three identical copies have arrived and then sent six to eight times. It does not mean I agree, I applied it, we resolved the same way, or we are configured identically. The exchange confirms that two advertisements were received and nothing beyond that.

"Half duplex and full duplex are a mode, so a mismatch shouldn't be possible."

The wrong model: an advertisement says a speed and a duplex.

What it costs: you cannot see why a lost bit downgrades a link cleanly.

The corrected model: they are separate ability bits. 10BASE-T and 10BASE-T full duplex are two independent claims, so an advertisement is a set and the resolution is a highest common member. A lost pulse removes one member and the link comes up at the next one down — cleanly, with both ends agreeing, and no error anywhere. It is also what makes the mechanism extensible: gigabit added two members and two table rows rather than redefining a field.

"The priority table is in the standard, so everybody has the same one."

The wrong model: a published constant is a shared constant.

What it costs: the one failure in this chapter that no runtime observation can find.

The corrected model: the table is not transmitted. It is compiled into each implementation from a prose reading of the standard, and nothing at runtime can compare two implementations' copies. A table over nine technologies has 9! = 362 880 orderings and one is right; most wrong ones differ by a single swap, which produces a disagreement only in the narrow case where both ends advertise both swapped technologies and nothing higher. Deterministic, reproducible with those two products, and impossible to reproduce with any others.

"A property that computes the expected resolution verifies the resolver."

The wrong model: comparing against a reference model is the strongest available check.

What it costs: the illusion of verification over the one error that matters.

The corrected model: the reference is a second implementation of the same table, written by the same author from the same reading. It catches implementation slips and cannot catch a misreading, because the misreading is duplicated into both. The useful properties are ones that hold for any correct table — membership, maximality, monotonicity, determinism — plus structural checks on the table itself derived from the standard's prose rather than from its ordered list.

17. Interview Reasoning

"What does autonegotiation actually agree on?"

Nothing. It exchanges abilities and never conclusions. Each end advertises what it can do in a 16-bit link code word — five bits of selector, eight of technology ability, then remote fault, acknowledge and next page — and each end then applies its own copy of a priority table to the intersection, independently. The resolution is never transmitted, never compared and never acknowledged. The strong answer names what ACK does mean: receipt of an advertisement, set after three identical copies are received and sent six to eight times — not agreement, not application, not a shared conclusion. The finishing point: the priority table is the only constant in the mechanism that is not on the wire, so two implementations with different tables negotiate successfully and disagree, and no runtime observation at either end can tell that from a correct negotiation.

"Why is a duplex mismatch possible at all, given that both ends negotiated?"

Because half and full duplex are separate ability bits, and because the resolution is computed twice, independently. An advertisement is a set{100BASE-TX, 100BASE-TX full duplex} — and each end selects the highest common member using its own table. Two things can go wrong and neither is detectable. A lost pulse (Chapter 11.1) turns a one into a zero, removing a member, so the link comes up one step down cleanly with both ends agreeing — the abilities were simply wrong. Or the two tables differ, and each end resolves correctly against its own. In both cases the exchange completes, both set ACK, and every counter is clean. The strong answer adds the third case: a partner that does not negotiate at all gets parallel-detected, and duplex is then assumed rather than agreed — which is 9.2's original mismatch.

"What does the acknowledge mechanism actually require, and what is the classic bug?"

Three identical copies received before ACK is set; six to eight copies sent with it set before completing. At an 8 to 16 ms burst spacing that is a 24 to 48 ms wait plus a 48 to 128 ms send, so 88 to 176 ms worst case — which is the number to compare a slow link against. The classic bug is failing to mask the ACK bit in the identical-copy comparison. The partner sets its ACK when it has heard us, so the partner's word changes as a direct consequence of our own transmission — and a receiver comparing all sixteen bits restarts its count at exactly that moment. The count never reaches three, our ACK is never set, the partner never completes either, and the failure is perfectly symmetric on a perfect link — which makes it look like a physical problem rather than one line of RTL.

"Would you verify the resolver by comparing it against a model that computes the expected resolution?"

No, and the objection is unusual: the property is not wrong about the world, it is wrong about itself. expected_resolution() is a second implementation of the same priority table, written by the same engineer from the same reading of the same standard — so a misreading is duplicated into both, and the property compares two copies of one belief and finds them consistent. It catches every implementation slip and cannot catch the one error that matters, which is the table being wrong — and Section 6 established that the table is the only unshared constant, so a build-time check is the last point at which the error is catchable. Assert what holds for any correct table instead: the resolution is a member of the common set, is the maximum over it, is monotone and deterministic; and the table's ranks are distinct, dense, non-zero, and consistent with two rules from the standard's prose — full duplex outranks half at the same speed, and higher speed outranks lower at the same duplex. A check derived from a different form of the specification is the only kind that does not share the design's failure mode.

18. Understanding Check

Sixteen bits, half of them abilities, and no field for the answer.

BitsFieldWidthPurpose
4:0Selector5which standard — 00001 = IEEE 802.3
12:5Technology Ability8A0A7, one bit per capability
13RF1remote fault
14ACK1receipt of an advertisement
15NP1a next page follows

The eight ability bits are 10BASE-T, 10BASE-T full duplex, 100BASE-TX, 100BASE-TX full duplex, 100BASE-T4, PAUSE, ASM_DIR and one reserved — so two of the eight are flow control, not technologies, and gigabit is not present at all because it does not fit and is carried in a next page.

What is missing is a field for the resolved technology. Nowhere in these sixteen bits is there a place to say I have concluded we should run at 100BASE-TX full duplex.

The word carries what a device can do and never what it decided — which is the chapter's whole subject.

19. What's Next

The claim this chapter defended: when a specification is compiled into a table inside each implementation, a property that re-derives the same table cannot verify it.

Autonegotiation's base page is sixteen bits: five of selector, eight of technology ability, and three of protocol — remote fault, acknowledge, next page. Half the word is capability and none of it is a conclusion.

Each end advertises what it can do. Each end applies its own copy of a priority table to the intersection. And nothing is exchanged afterwards. The acknowledge closes the loop on the advertisement — three identical copies received, six to eight sent, 88 to 176 ms worst case — and leaves the resolution entirely unconfirmed. Which is precisely the gap Chapter 9.2's duplex mismatch occupies, and the same gap a priority-table disagreement occupies: two devices that complete the exchange, both set ACK, and select different technologies, with every counter clean at both ends.

The table is the mechanism's only unshared constant, which makes it the only thing a build-time check can still catch — and the reason the rejected property here is the one everybody writes. A model that computes the expected resolution is a second copy of the same reading, and it catches every implementation slip and no misreading at all.

What replaces it is structural. The resolution is a member of the common set, is its maximum, is monotone and deterministic. The ranks are distinct, dense and non-zero. And the ordering satisfies two rules from the standard's prose — full duplex outranks half at the same speed, higher speed outranks lower at the same duplex — which constrain the table without encoding it, and catch the likeliest misreadings at build time rather than never.

Chapter 11.3 — Full Link Bring-Up Sequence puts the whole path together.

Chapter 11.1 established what can be observed before anything is agreed; this chapter established what is exchanged and what is not. 11.3 traces a complete bring-up from power-on to a MAC that may legally transmit — the PHY's reset and its capability registers, discovery, the ability exchange, the resolution, the technology-dependent establishment that follows it (Chapter 9.3's master/slave arbitration and canceller training among them), the interface bring-up from Module 10, and finally the moment a MAC's transmit enable may be asserted. Every stage has a precondition, a timer and a named failure, and the chapter's argument is that the ordering is not a convenience: each stage measures something the next one depends on, and starting one early produces a link that comes up and does not work.

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.