Skip to content
DenseChip
Learn
PracticeCode labInterview

DenseChip

Navigate

Menu

LearnPracticeCode labInterview

Tools

All toolsSV editorCode repoResume
DenseChip

Practice, courses, and chip-design tools in one focused workspace.

LearnPracticeCode labInterviewToolsLearning paths

© 2026 DenseChip

AboutContactPrivacyTerms
Skip to lesson

Course contents

  • How to Use This Course
  • Reading Paths
  • Concept Map
  • How to Read the Diagrams
  • Part 0: What Is a Protocol?10
  • Part 1: Timing and Clocking11
  • Part 2: Encoding and Framing12
  • Part 3: Handshakes13
  • Part 4: Flow Control17
  • Part 5: Transactions19
  • Part 6: Concurrency and Performance17
  • Part 7: Ordering13
  • Part 8: Sharing and Arbitration12
    • Shared Media and Topologies
    • Arbitration Policies
    • Fairness and Starvation
    • Priority Inversion
    • Arbitration Granularity
    • Distributed Arbitration
    • Quality of Service
    • Virtual Channels
    • Routing
    • Multicast and Broadcast
    • Protocols Compared: Sharing and Arbitration
    • Drills: Sharing and Arbitration
  • Part 9: Deadlock and Liveness13
  • Part 10: Reliability and Recovery20
  • Part 11: Bring-Up and Link Management10
  • Part 12: Power8
  • Part 13: Shared State and Coherence9
  • Part 14: Security and Isolation7
  • Part 15: Specifying and Verifying11
  • Part 16: Protocols Dissected17
  • Part 17: Capstones5
  • Part 18: Interview Preparation6
Loading lesson

‹Part 8: Sharing and Arbitration
  1. Topics
  2. First Principles of Hardware Protocols
  3. Part 8: Sharing and Arbitration
  4. Distributed Arbitration

Part 8 · Sharing and Arbitration · Working (W)

Distributed Arbitration

Arbitration with no central arbiter: competitors settle who wins on the wire itself. Wired-AND bit-by-bit arbitration in I2C and CAN, where the winner's message survives intact, and collision detection where nobody wins.

On this page

    Note

    Level: Working (W) · Answers: Who gets the wire?

    Before this: Arbitration Policies

    Two microcontrollers on the same I2C bus decide, at the same instant, to talk to a sensor. There is no arbiter chip, no request lines, no grant lines: just two shared wires and a pull-up resistor on each. Both start sending. One of them finishes its message as though nothing happened. The other notices, a few bits in, that it has lost, and goes quiet without corrupting a single bit.

    How can competitors arbitrate with no arbiter, and how does the loser know it lost?

    The obvious answer, and why it breaks

    The obvious answer is a central arbiter: every master asks it for permission. That needs request and grant wires for every master, and a single place every master can reach, which a two-wire bus between independent chips does not have. The other obvious answer, "just send and hope", fails when two senders drive opposite values: the wire's value is undefined, and on most buses both messages are destroyed.

    The idea: let the wire decide

    Make the wire itself combine competitors' bits in a defined way. With open-drain drivers and a pull-up, any device driving 0 pulls the wire low; the wire is 1 only if everyone releases it. The wire computes the AND of all senders' bits. Now arbitration is a rule each sender follows on its own:

    • Send your message bit by bit, and read the wire back on every bit.

    • If you sent 1 (released) but read 0, someone else sent 0: you have lost. Stop driving and listen.

    • If you sent what you read, keep going. The sender whose message has a 0 where the others have a 1 wins, and its message on the wire is exactly what it sent.

    Nobody needs to know who else is competing, and the winner's message is never corrupted. Priority is built into the message: lower values (more leading 0s) win.

    Build it: two I2C masters collide

    Master A sends address 1010010; master B sends 1011010. They agree for three bits and differ at the fourth, where A sends 0 and B sends 1. One bit per clock here; real I2C also synchronises the two masters' clocks on the wired-AND clock line.

    tb.sv
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    // Two I2C masters start at the same moment and send different addresses, MSB first,
    // on a wired-AND SDA line: the line is low if either master drives low. A master
    // that sends a 1 (releases the line) but reads a 0 has lost: it stops driving and
    // listens. Master A sends 1010010 (0x52), master B sends 1011010 (0x5A); they first
    // differ at the fourth bit, where A sends 0 and B sends 1. One bit per clock here.
    module tb;
      logic clk = 0;
      always #5 clk = ~clk;
      initial begin $dumpfile("wave.vcd"); $dumpvars(0, tb); end
    
      localparam logic [6:0] ADDR_A = 7'h52, ADDR_B = 7'h5A;
      int bit_n = -1;                               // -1: idle; then bit 0 = MSB
      logic lost_a = 0, lost_b = 0;
      wire  active = (bit_n >= 0) && (bit_n < 7);
      wire  sda_a = (!active || lost_a) ? 1'b1 : ADDR_A[6 - bit_n];   // 1 = release (pulled up)
      wire  sda_b = (!active || lost_b) ? 1'b1 : ADDR_B[6 - bit_n];
      wire  sda   = sda_a & sda_b;                  // wired-AND
      always @(posedge clk) begin
        if (active) begin
          if (!lost_a && sda_a && !sda) lost_a <= 1;
          if (!lost_b && sda_b && !sda) lost_b <= 1;
        end
        if (bit_n < 7) bit_n <= bit_n + 1;
      end
    
      // The address seen on the bus must be the winner's, unharmed
      logic [6:0] seen = 0;
      always @(posedge clk) if (active) seen <= {seen[5:0], sda};
      initial begin
        #100;
        if (lost_b && !lost_a && seen == ADDR_A) $display("PASS: B lost at the fourth bit; the bus carried A's address 0x%0h intact", seen);
        else $display("FAIL: lost_a %0b lost_b %0b seen %0h", lost_a, lost_b, seen);
        $finish;
      end
    endmodule

    The whole arbitration is one comparison per master: driving 1 while the wire reads 0 means lost.

    Watch it run

    How to read it, slot by slot:

    • Slots 0 to 2: both masters send 1, 0, 1 (sda_a, sda_b); the line (sda) carries the same.

    • Slot 3: A sends 0, B sends 1 (releases). The line reads 0. B sent 1 but sees 0: it has lost. lost_b rises on the next edge.

    • Slots 4 to 6: B keeps its line released (1) and only listens; the line follows A: 0, 1, 0. The bus carried 1010010, A's address, as if B had never spoken.

    Arbitration, or collision detection

    Scheme

    When two send at once

    Result

    Wired-AND bitwise arbitration (I2C, CAN)

    The dominant value (0) overrides the recessive one

    One winner, message intact; the loser retries later

    Collision detection (classic shared Ethernet)

    Both signals are corrupted; senders detect the collision

    Nobody wins; both back off for a random time and retry

    Central arbiter (on-chip buses)

    Cannot happen: only the granted master drives

    Needs request and grant wires to every master

    Bitwise arbitration wastes no time, since the winner's message continues, but it requires a wire that combines values deterministically and every sender reading back each bit. That limits bit rate and bus length: the bit must settle along the whole wire before anyone reads it.

    How real protocols chose

    Protocol

    Distributed arbitration

    I2C

    Open-drain SDA and SCL. Arbitration runs bit by bit on SDA while SCL is high; a master that drives 1 but reads 0 loses and stops driving. The wired-AND SCL synchronises the masters' clocks.

    CAN

    Dominant and recessive bits; arbitration on the identifier field, bit by bit. The lowest identifier wins without being corrupted, so identifiers double as message priorities.

    Classic shared Ethernet

    Carrier sense and collision detection on a shared medium, with random back-off. Modern switched, full-duplex Ethernet has no shared medium and needs none of it.

    What breaks

    A board (illustrative) put a master that did not support multi-master arbitration on an I2C bus with another master. It never read SDA back while sending, so when it lost arbitration it kept driving its address bits over the winner's. Both transactions failed intermittently. Every master on a shared I2C bus must implement arbitration, or the bus must have only one master.

    Why this matters

    Senior lens. Distributed arbitration moves the arbiter into the electrical behaviour of the wire and into every sender's logic. Check that the wire is wired-AND (open-drain everywhere, correct pull-ups), that every sender reads back every bit including during addresses and data, and that the bit time leaves room for the signal to settle along the whole bus. One non-compliant sender breaks it for everyone.

    Interview

    Asked: "How do two I2C masters resolve a collision?"

    Weak answer: The bus controller decides.

    Strong answer: There's no arbiter. SDA is open-drain, so the line is the AND of what both masters drive. Each master reads SDA back on every bit while SCL is high; if it released the line (sent 1) but reads 0, the other sent 0, so it has lost, stops driving, and listens. The winner never notices: the line carried exactly its bits. Arbitration can run through the address and into the data, and the wired-AND SCL keeps the two masters' clocks in step.

    Follow-ups: (1) How does CAN use the same idea for priority? (2) Why does this limit bus speed?

    Check yourself Two CAN nodes start sending identifiers 0x120 and 0x121 at once. Which wins, and where?

    0x120: they differ only in the last bit, where 0x120 sends dominant 0 and 0x121 sends recessive 1, so 0x121 loses at that bit.

    Check yourself Why does the winner's message survive intact in bitwise arbitration but not in collision detection?

    The wired-AND line takes the dominant value, which is the winner's bit; with ordinary drivers, conflicting values corrupt the line for both.

    Key takeaways

    • Distributed arbitration lets the wire decide: a wired-AND line carries 0 if anyone sends 0.

    • Each sender reads back every bit; sending 1 but reading 0 means it lost and must stop.

    • The winner's message is intact and priority lives in the message; collision detection instead discards both and backs off.

    Keep going

    Next: Lesson 8.7, Quality of Service. Traffic classes, priorities and bandwidth regulation: guaranteeing a display next to a GPU.

    Related topics

    • Part 8 overview: Sharing and Arbitration

    Previous

    122 / 234

    Next: Quality of Service

    Up next

    Up nextQuality of Service

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Shared Media and Topologies
    • Arbitration Policies
    • Fairness and Starvation
    clksda_asda_bsdalost_b
    Simulation output: two masters send different addresses on a wired-AND line. B loses at the fourth bit; the line carries A's address unharmed.