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. Valid-Only Streams

Part 3 · Handshakes · Foundation (F)

Valid-Only Streams

The simplest stream has a valid signal and no way to push back. When that is enough, and what happens the first cycle the receiver cannot keep up.

On this page

    Note

    Level: Foundation (F) · Answers: Is the receiver ready?

    Before this: Part 3 overview, A Protocol Is a Contract

    A sensor block streams one sample per cycle into a filter. The interface is just valid and data. It works perfectly until the filter gains a feature that occasionally needs two cycles for one sample. In those cycles a sample arrives anyway and is lost, and the filter's output develops small, rare glitches that look like noise in the sensor.

    When is a stream with no way to say "wait" good enough, and what does it cost when it is not?

    The obvious answer, and why it breaks

    The obvious design for a stream is the cheapest one: the producer drives valid high whenever its data is real, and the consumer captures every valid word. No other signal, no other logic. It is correct exactly as long as the consumer can accept a word in every cycle the producer might send one. The moment the consumer cannot, for one cycle, there is nowhere for the word to go and no way to tell the producer. That is called overrun: data arrives faster than the receiver can take it, and the excess is lost.

    The idea: valid-only is a promise about the receiver

    A valid-only interface is not missing a feature; it moves a promise from the protocol into the design. Instead of the receiver saying "wait" when it needs to, the receiver promises never to need to: it will accept a word in every cycle, at the producer's peak rate, forever. If that promise holds, valid-only is the best interface possible: no extra wires, no handshake timing paths, no stalls.

    The canonical figure with the return path removed. Everything rests on the consumer keeping up.

    The promise usually comes from one of three places:

    • The consumer is fixed-rate and at least as fast as the producer: a pipeline that always takes one word per cycle.

    • A buffer absorbs bursts: a FIFO sized for the longest burst at the peak rate, drained faster than the average arrival rate.

    • The data may be dropped: some streams (sensor samples, video in some cases) prefer losing a sample to stalling the source.

    Build it: watch an overrun

    The testbench streams ten words, one per cycle, to a consumer that is busy in three cycles. The consumer has no way to push back, so the words that arrive in those cycles are lost. The checker counts them.

    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
    // A valid-only stream: the producer sends a word whenever it has one, and the
    // consumer has no way to say "not now". The consumer takes one word per cycle except
    // while it is busy (for example writing to a slow memory). Any word that arrives while
    // it is busy is lost. The checker counts lost words and confirms the count matches the
    // busy cycles that overlapped the stream.
    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
    
      int cyc = 0;
      always @(posedge clk) if (rst_n) cyc <= cyc + 1;
    
      // Producer: words 0..9, one per cycle, starting in cycle 1. No way to be told to wait.
      logic       vld;
      logic [7:0] data;
      assign vld  = (cyc >= 1 && cyc <= 10);
      assign data = vld ? 8'(cyc - 1) : 8'h00;
    
      // Consumer: busy in cycles 4, 5 and 8 (it cannot accept anything then).
      wire busy = (cyc == 4 || cyc == 5 || cyc == 8);
      wire lost = vld && busy;               // the word on the wire this cycle is dropped
    
      logic [7:0] got [0:9]; int n = 0, nlost = 0;
      always @(posedge clk) if (rst_n && vld) begin
        if (busy) nlost++;
        else begin got[n] = data; n++; end
      end
    
      initial begin
        #160;
        if (n == 7 && nlost == 3 && got[3] == 8'd5)
          $display("PASS: 3 of 10 words lost while the consumer was busy; valid alone cannot push back");
        else $display("FAIL: received %0d, lost %0d", n, nlost);
        $finish;
      end
    endmodule

    Watch it run

    How to read it, slot by slot:

    • Slots 1 to 10: vld is high and data carries words 0 to 9, one per cycle. The producer never waits, because nothing tells it to.

    • Slots 4 and 5: the consumer is busy. Words 3 and 4 are on the wire, and lost is high: they vanish.

    • Slot 8: busy again; word 7 is lost.

    • Result: the consumer receives 0, 1, 2, 5, 6, 8, 9. Nothing in the interface reports the gaps.

    Worked numbers: how big a buffer replaces back-pressure?

    If you keep a valid-only interface but put a FIFO in front of the consumer, the FIFO must hold every word that arrives while the consumer is behind. With illustrative numbers: a producer bursts at one word per cycle for up to 64 cycles, and the consumer drains at 3 words every 4 cycles.

    Diagram
    During a 64-cycle burst:
      words arriving  = 64
      words drained   = 64 x 3/4 = 48
      FIFO must hold  = 64 - 48 = 16 words (more if bursts can come back to back)
    
    And on average the consumer must keep up: average arrival rate < 0.75 words per cycle,
    otherwise no finite FIFO is enough.

    That is the general trade: without back-pressure, the receiver's buffering must cover the worst-case burst, and its long-run rate must beat the producer's. With back-pressure (the rest of this part), the producer simply waits, and a small buffer suffices.

    The design space

    Option

    What it costs

    When it wins

    Valid only

    Nothing extra, but the consumer must keep up every cycle

    Fixed-rate pipelines; data that may be dropped

    Valid only + FIFO sized for the worst burst

    Buffer area; a guaranteed average rate

    Bursty sources that cannot be stalled (for example a sensor or a link)

    Valid + ready (lesson 3.3)

    One more wire and a timing path backwards

    Almost all on-chip streams where the producer can wait

    Credits (Part 4)

    A counter and a return path

    Long paths where a per-cycle ready would arrive late

    How real protocols chose

    Protocol

    Its choice

    AXI-Stream

    Defines TREADY for back-pressure: a transfer happens only when TVALID and TREADY are both high. A stream that never needs back-pressure can hold TREADY high, which turns it into a valid-only stream.

    UART

    No back-pressure in the basic protocol: the receiver must take every character, and buffering (or optional flow-control wires) is the receiver's problem.

    Both show the same principle from opposite ends: AXI-Stream builds back-pressure in and lets a design opt out; UART leaves it out and lets a design add it.

    What breaks

    The opening story, as debug steps (illustrative):

    • Symptom: rare, small glitches in the filter's output that look like sensor noise.

    • Evidence: a counter of words received over a fixed time is slightly lower than the number sent, and the shortfall matches the number of two-cycle samples.

    • Root cause: a valid-only interface whose consumer broke its promise to accept every cycle.

    • Fix: either restore the promise (keep the filter at one sample per cycle), add a FIFO sized for the worst case, or add a ready signal so the sensor path can wait. The cheapest permanent fix is an assertion on the consumer: "never busy while valid is high", so the broken promise is caught the day it is introduced.

    Why this matters

    Senior lens. Valid-only interfaces fail silently, so treat every one as a documented promise: state the producer's peak rate and longest burst, the consumer's guaranteed rate, and the buffering between them, and add an overflow assertion or counter. When reviewing a design change on either side, check whether it breaks that promise. Most overrun bugs are introduced long after the interface was designed, by a feature that made the consumer occasionally slower.

    Interview

    Asked: "When is it acceptable to have no ready signal on a stream?"

    Weak answer: When the data is not important.

    Strong answer: When the consumer can guarantee to accept a word every cycle at the producer's peak rate, for example a fixed-rate pipeline, or when a FIFO sized for the worst-case burst sits in front of a consumer whose average rate exceeds the producer's, or when losing data is acceptable. Otherwise words are lost silently, so I'd document the rate promise and add an overflow assertion.

    Follow-ups: (1) How do you size the FIFO if you keep valid-only? (2) How would you detect overrun in silicon?

    Check yourself A producer sends 4-word bursts at one word per cycle with at least 12 idle cycles between bursts. The consumer takes one word every 2 cycles. Is valid-only safe with a buffer, and how deep?

    During a 4-cycle burst the consumer drains 2 words, so 2 must be buffered (plus margin). Between bursts it has 12 cycles to drain them, far more than needed, so the average rate is fine. A buffer of a few words makes it safe.

    Check yourself Why is overrun dangerous even when it is rare?

    Nothing in a valid-only interface reports it: data simply goes missing, and the symptom appears far downstream as corrupted results.

    Check yourself How does holding TREADY high relate to this lesson?

    It turns an AXI-Stream interface into a valid-only stream: the consumer promises to accept every transfer, and back-pressure is never used.

    Key takeaways

    • A valid-only stream moves a promise into the design: the consumer must accept a word in every cycle the producer may send one.

    • When that promise breaks, words are lost silently (overrun).

    • Without back-pressure, buffering must cover the worst-case burst and the consumer must beat the producer's average rate.

    Keep going

    Next: Lesson 3.2, Wait States and Stretching. The simplest way for a receiver to push back: stretch the current transfer until it is ready.

    Related topics

    • Part 3 overview: Handshakes

    • RTL course: Synchronous FIFO

    Previous

    38 / 234

    Next: Wait States and Stretching

    Up next

    Up nextWait States and Stretching

    Sign in to save progress

    Practice this lessonReport an error

    See also

    • The Valid/Ready Handshake
    • The Valid/Ready Rules
    • Request/Acknowledge: Two-Phase and Four-Phase
    clkvlddata01234567890busylost
    Simulation output: ten words stream past a consumer that is busy in three cycles. Every word that arrives during a busy cycle is lost. One slot is one cycle.