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
    • Valid-Only Streams
    • Wait States and Stretching
    • The Valid/Ready Handshake
    • The Valid/Ready Rules
    • Request/Acknowledge: Two-Phase and Four-Phase
    • Push and Pull
    • Global Stall or Elastic Pipeline
    • Register Slices
    • Skid Buffers
    • Bubbles and Half Throughput
    • Latency-Insensitive Design
    • Protocols Compared: Handshakes
    • Drills: Handshakes
  • Part 4: Flow Control17
  • Part 5: Transactions19
  • Part 6: Concurrency and Performance17
  • Part 7: Ordering13
  • Part 8: Sharing and Arbitration12
  • 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 3: Handshakes
  1. Topics
  2. First Principles of Hardware Protocols
  3. Part 3: Handshakes
  4. The Valid/Ready Rules

Part 3 · Handshakes · Working (W)

The Valid/Ready Rules

Why valid must never wait for ready, why ready may wait for valid, why valid and data must hold until accepted, and the deadlock and glitches you get when a side breaks a rule.

On this page

    Note

    Level: Working (W) · Answers: Is the receiver ready?

    Before this: The Valid/Ready Handshake

    Two blocks from two teams are connected with valid/ready. Each was verified against its own testbench, and each testbench's partner behaved politely. Connected to each other, nothing ever moves: both sit at zero forever. Each team insists its block is correct, and in isolation each one is.

    Which rules must each side of a valid/ready interface follow so that any compliant producer works with any compliant consumer?

    The obvious answer, and why it breaks

    Lesson 3.3 gave the core rule: a word moves on an edge where valid and ready are both high. It is tempting to think that is all. But the rule says nothing about when each side may raise its signal. A cautious producer might reason: "I'll raise valid only once the consumer is ready, so I never offer a word that can't be taken." A cautious consumer might reason: "I'll raise ready only once a word is offered." Each policy sounds sensible. Together they wait for each other forever.

    The idea: three rules, and an asymmetry

    Every robust valid/ready protocol adopts the same three rules. AXI states them for all of its channels:

    1. The producer must not wait for ready before raising valid. When it has a word, it raises valid, whatever ready is doing.

    2. Once valid is high, the producer holds valid and the data unchanged until the word moves (an edge with valid and ready both high).

    3. The consumer may wait for valid before raising ready, or raise ready first. Ready may depend on valid.

    The asymmetry is the point. If both sides were allowed to wait for the other, two compliant blocks could deadlock. By forbidding exactly one side, the producer, from waiting, the protocol guarantees that someone always goes first: valid rises on its own, and the consumer, whatever its policy, eventually sees it.

    Rule 1 also has a timing form: there must be no combinational path from ready to valid. Rule 3 permits a path from valid to ready. If both existed, valid and ready would form a combinational loop, which can oscillate or settle unpredictably, and which every synthesis and timing tool rejects.

    The deadlock rule 1 prevents: two reasonable policies that each wait for the other side to go first.

    Build it: a compliant pair and a broken pair

    The testbench runs two pairs side by side. Pair A follows the rules: its producer raises valid when it has data, and its consumer, legally, waits for valid. Pair B has the same consumer, but its producer breaks rule 1 by waiting for ready. Both sides of pair B register their decisions, so there is no combinational loop, only the protocol mistake.

    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    // Two producer/consumer pairs side by side.
    //   Pair A follows the rules: the producer raises valid when it has data, without
    //   looking at ready; the consumer may wait for valid before raising ready.
    //   Pair B breaks rule 1: its producer waits for ready before raising valid, and its
    //   consumer (legally) waits for valid before raising ready. Each waits for the other.
    // The checker shows pair A delivering all its words and pair B delivering none.
    module tb;
      logic clk = 0;
      always #5 clk = ~clk;
      logic rst_n = 0;
      initial begin
        $dumpfile("wave.vcd"); $dumpvars(0, tb);
        #12 rst_n = 1;
      end
    
      // ---- Pair A: correct ----
      logic       vld_a = 0;
      logic [7:0] data_a = 0;
      logic [3:0] sent_a = 0;
      wire        rdy_a = vld_a;               // consumer waits for valid (allowed)
      wire        xfer_a = vld_a && rdy_a;
      always @(posedge clk) if (rst_n) begin
        if (!vld_a || xfer_a) begin            // free to offer the next word
          vld_a <= (sent_a < 4);
          if (sent_a < 4) begin data_a <= 8'(sent_a); sent_a <= sent_a + 1; end
        end
      end
    
      // ---- Pair B: producer breaks rule 1 ----
      // Both sides register their decision (no combinational loop): each raises its
      // signal one cycle after it sees the other's. Neither ever goes first.
      logic       have_b = 0;                  // producer has data from cycle 1 on
      logic       vld_b = 0, rdy_b = 0;
      wire        xfer_b = vld_b && rdy_b;
      always @(posedge clk) if (rst_n) begin
        have_b <= 1;
        vld_b  <= have_b && rdy_b;             // WRONG: valid waits for ready
        rdy_b  <= vld_b;                       // consumer waits for valid (allowed)
      end
    
      int moved_a = 0, moved_b = 0;
      always @(posedge clk) if (rst_n) begin
        moved_a += xfer_a;
        moved_b += xfer_b;
      end
      initial begin
        #300;
        if (moved_a == 4 && moved_b == 0)
          $display("PASS: the correct pair moved 4 words; the pair where valid waits for ready moved 0 (deadlock)");
        else $display("FAIL: pair A moved %0d, pair B moved %0d", moved_a, moved_b);
        $finish;
      end
    endmodule

    Watch it run

    How to read it, slot by slot:

    • Pair A, slots 1 to 4: vld_a rises as soon as the producer has a word. rdy_a follows it in the same cycle (the consumer waits for valid, which rule 3 allows), so xfer_a is high and words 0 to 3 move on four consecutive edges.

    • Pair B, slot 1 onwards: have_b shows the producer has data. But its valid waits for ready, and its consumer's ready waits for valid. vld_b, rdy_b and xfer_b stay at 0 for the rest of the run, and would forever.

    Both consumers are identical and both are compliant. The only difference is one producer that waited for ready. That is why rule 1 is written for the producer: it is the one rule that, if everyone follows it, makes deadlock between compliant blocks impossible.

    The rules as assertions

    Rules 1 to 3 translate directly into checks. Rule 2 is easy to check on a waveform; rule 1, being about what valid waits for, is checked by design review, by a formal tool, or by a testbench that holds ready low indefinitely and checks that valid still rises:

    design.sv
    1
    2
    3
    4
    5
    6
    7
    8
    // snippet: the valid/ready rules as SystemVerilog assertions
    // Rule 2: once valid, hold valid and data until the transfer.
    assert property (@(posedge clk) disable iff (!rst_n)
      valid && !ready |=> valid && $stable(data));
    // Rule 1 (testbench form): with ready held low for 20 cycles, a producer that has
    // data must still raise valid.
    assert property (@(posedge clk) disable iff (!rst_n)
      has_data && !ready [*20] |-> valid);

    The first assertion is the most valuable single check on any valid/ready interface: it catches producers that drop or change a stalled word, the bug behind most lost or duplicated data.

    The design space

    What a side may do

    Producer

    Consumer

    Raise its signal without seeing the other's

    Must (rule 1)

    May (ready before valid)

    Wait for the other's signal first

    Must not

    May (ready after valid)

    Combinational path from the other's signal to its own

    Must not (no ready → valid)

    May (valid → ready)

    Change its signal after raising it, before a transfer

    Must not (rule 2)

    Usually allowed while valid is low; check the specific protocol

    How real protocols chose

    Protocol

    Its rules

    AXI (all five channels)

    A source must not wait for READY before asserting VALID; once VALID is asserted it stays asserted until the transfer, with the payload stable while VALID is high and READY is low; a destination may wait for VALID before asserting READY, or assert READY first. The reason given is exactly the deadlock above.

    AXI-Stream

    The same rules for TVALID and TREADY.

    What breaks

    The opening hang (illustrative): the producing team had tested against a consumer model that held ready high all the time, so their producer's "wait for ready" policy never mattered. The consuming team had tested against a producer model that raised valid whenever it had data. Connected together, the two real blocks deadlocked on the first word. Each block was correct against its own test partner; the producer broke rule 1, which neither testbench checked.

    • Lesson for verification: every valid/ready testbench should include a partner that does the least the rules allow: a consumer that waits for valid before raising ready, and a producer that raises valid only when it has data. A block that works only with a generous partner is not compliant.

    Why this matters

    Senior lens. When reviewing a valid/ready block, trace where ready and valid come from. A producer whose valid has any logical dependence on ready, even through a register or a state machine, breaks rule 1 and will deadlock against some compliant consumer. A consumer whose ready comes combinationally from valid is legal but creates a long backward timing path through chains of such blocks; that is what register slices and skid buffers fix (lessons 3.8 and 3.9).

    Interview

    Asked: "May ready depend on valid? May valid depend on ready?"

    Weak answer: Both can depend on each other as long as it works.

    Strong answer: Ready may depend on valid; valid must not depend on ready. If both sides waited for the other, two compliant blocks could deadlock, so the protocol forbids exactly one side, the producer, from waiting. It also rules out a combinational loop: valid to ready is allowed, ready to valid isn't. And once valid is high, the producer holds valid and data until the transfer.

    Follow-ups: (1) Write an assertion that catches a producer changing a stalled word. (2) How would you test that a producer obeys rule 1?

    Check yourself A producer raises valid only on cycles when ready was high in the previous cycle. Does it break rule 1?

    Yes. Its valid depends on ready, through a register. Paired with a consumer that waits for valid before raising ready, neither will ever go first.

    Check yourself Why is a combinational path from valid to ready allowed but not the reverse?

    Allowing both would create a combinational loop between the two signals. Forbidding ready → valid is enough to prevent the loop, and it is the same restriction that prevents the deadlock.

    Check yourself A consumer raises ready, then lowers it again before any valid arrives. Is the protocol still safe?

    For deadlock, yes: the producer never waits for ready, so it will still raise valid when it has data. Whether a particular protocol allows ready to be withdrawn before valid is a detail to check in its specification.

    Key takeaways

    • The producer must not wait for ready before raising valid; the consumer may wait for valid.

    • Once valid is high, valid and data hold until the transfer; checking this one rule catches most lost and duplicated words.

    • No combinational path from ready to valid: valid → ready is allowed, the reverse would create a loop and a deadlock.

    Keep going

    Next: Lesson 3.5, Request/Acknowledge: Two-Phase and Four-Phase. The older handshake that still crosses every clock domain: request and acknowledge, in four phases or two.

    Related topics

    • Part 3 overview: Handshakes

    • RTL course: Valid/Ready Handshake

    Previous

    41 / 234

    Next: Request/Acknowledge: Two-Phase and Four-Phase

    Up next

    Up nextRequest/Acknowledge: Two-Phase and Four-Phase

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • Valid-Only Streams
    • Wait States and Stretching
    • Push and Pull
    clkvld_ardy_adata_a0123xfer_ahave_bvld_brdy_bxfer_b
    Simulation output: pair A (top) moves four words; pair B (bottom) has data from slot 1 but never raises valid or ready. One slot is one cycle.