← RTL Design Interviews

Interview Question · Code Writing

Registering Ready with a Skid Buffer

L2 Mid-Levelpipeliningvalid readybackpressure

The Question

The interviewer asks

Your valid/ready pipeline fails timing on the ready path, which runs combinationally through ten stages. Write a stage whose in_ready comes straight from a flop and never loses a beat.

Reveal the Model Answer

Use a skid buffer: an output register plus one spare entry. in_ready is simply "the spare entry is empty", which is a flop. When the sink stalls, the beat already in flight lands in the spare entry. When the sink is ready again, the spare drains first. Two entries are needed, because ready reaches the source one cycle late.

A Stage with a Skid RegisterArrows carry beats, except in_ready and out_ready, which carry the ready flags. in_ready is !skid_valid, a flop output.
A stage with a skid registerArrows carry beats, except `in_ready` and `out_ready`, which carry the ready flags. `in_ready` is `!skid_valid`, a flop output. source producer offers a beat until itis taken flop skid register skid_valid, skid_data flop main register out_valid, out_data sink consumer drops out_ready tostall beat, normal flowbeat during a stalldrainbeat outout_readyin_ready = !skid_valid
  1. Normal flow

    With the skid empty, a beat goes straight into the main register while the previous beat leaves.

    Follow the calls, values and waits
    1. data beat 3: producer → main register
  2. The stall

    The consumer drops out_ready, so beat 3 stays in the main register. in_ready is still 1, and beat 4 arrives.

    Follow the calls, values and waits
    1. call out_ready 0: consumer → main register
    2. data beat 4: producer → skid register
  3. Ready falls

    The skid is full, so in_ready is 0 from the next edge. The producer holds beat 5.

    Follow the calls, values and waits
    1. call in_ready 0: skid register → producer
  4. Drain

    The consumer takes beat 3. At the same edge beat 4 moves from the skid into the main register, so order is kept, and in_ready returns.

    Follow the calls, values and waits
    1. data beat 3: main register → consumer
    2. data beat 4: skid register → main register
Read the diagram as text
  • producer: offers a beat until it is taken
  • skid register: skid_valid, skid_data
  • main register: out_valid, out_data
  • consumer: drops out_ready to stall
  • producer → main register: beat, normal flow
  • producer → skid register: beat during a stall
  • skid register → main register: drain
  • main register → consumer: beat out
  • consumer → main register: out_ready
  • skid register → producer: in_ready = !skid_valid

The stage holds up to two beats, and no combinational path runs through it from out_ready to in_ready.

The Same Stall with a Skid RegisterSame producer, same consumer. Beat 4 lands in the skid at edge 5 and goes to the main register at edge 6, as beat 3 leaves.
in_datain_readyout_dataout_readyProducerbeats 1 to 6Stagemain and skidmainskidConsumerstops at edge 5

A lit wire carries a 1. A pill is a transfer in that cycle; slots are the entries held.

012345678910clkin_validin_data01234567in_readyskid_validskid_datax4out_validout_datax123456out_ready
  1. Cycle 5

    The consumer stops. Beat 3 stays in the main register and beat 4 comes in anyway: it goes to the skid.

  2. Cycle 6

    The skid holds beat 4, so in_ready is 0 and beat 5 waits. Beat 3 leaves; beat 4 moves up behind it.

  3. Cycle 7

    The skid is empty again and in_ready is back. Beat 5 enters as beat 4 leaves.

  4. Cycle 9

    Six in, six out, in order. The stall cost the producer one edge.

Measured on the lab bench with the skid added (skid_valid and skid_data read from inside the stage).

The skid buffer under a repeating stall pattern, with the source always offering data.

RUNIcarus Verilog · in your browser
Edit the code, then run it
Expected: beats sent=40 received=38 out of order or missing=0

Self-Check

Tick each key point you covered in your answer.

What Interviewers Listen For (Junior)

A good junior answer explains why a registered ready arrives one cycle late. It says one beat may already be on its way when the sink stalls.

Cross-Questions

Where the interviewer goes next. Open a node to practise that follow-up.

WhyWhat IfProve ItCompare

  1. Registering Ready with a Skid Buffer
  2. WhyWhy a Skid Buffer Needs Two EntriesL2 Mid-Level

    Why does a skid buffer need exactly two entries, not one?

    Reveal the Model Answer

    When the sink drops ready, the stage only tells the source at the next edge. In that cycle the source may already send one more beat. The output register holds the stalled beat and the spare holds the one in flight. With one entry, the stage must stall every other cycle to stay safe.

    A Registered Ready and No Room for the Extra BeatThe producer offers beats 1 to 6. The consumer drops out_ready for edge 5 only. Each column shows the values just before an edge, which decide what moves at it.
    012345678910clkin_validin_data01234567in_readyout_validout_datax123456out_ready
    1. Cycle 4

      Steady flow: beat 3 enters while beat 2 leaves. One beat per edge.

    2. Cycle 5

      The consumer stops, so beat 3 must stay. But in_ready is still 1, copied from the edge before, and beat 4 comes in.

    3. Cycle 6

      Beat 4 sits where beat 3 was. Beat 3 is gone. Only now does in_ready show the stall.

    4. Cycle 9

      Beats 1, 2, 4, 5 and 6 came out: six in, five out.

    Measured on the lab bench. The consumer stopped for one edge; the stage heard about it one edge later.

    Self-Check

    Tick each key point you covered in your answer.

    Misconception

    "Two entries are just extra margin."

    They are the minimum for a one-cycle-late ready at full throughput. Fewer loses data or halves the rate.

    Source Lesson R4.4 review claims (the skid buffer and its bench)

  3. What IfReady That Arrives Two Cycles LateL2 Mid-LevelL3 Senior

    What if ready reaches the source two cycles late, for example across a long wire with two register stages?

    Reveal the Model Answer

    Then up to two beats can be in flight when the sink stalls. The buffer needs room for all of them. In general, the spare space must cover the round-trip delay of the ready signal. This is the same arithmetic as a credit scheme or a FIFO almost-full threshold.

    Self-Check

    Tick each key point you covered in your answer.

    Half-Truth

    "Add one skid buffer per register stage on the wire."

    That works but spreads the storage out. One buffer at the end, sized for the round trip, uses the same storage and is simpler to verify.

    Source Lesson P1.6 review claims (flow control: FIFO depth and credits)

  4. CompareSkid Buffer Versus a Small FIFOL2 Mid-Level

    Compare a skid buffer with a two-entry FIFO in the same place.

    Reveal the Model Answer

    Both store two beats and both can drive ready from a flop. A skid buffer keeps the output register at the output, so out_data comes straight from a flop and needs no read mux. A FIFO has pointers and a read mux, which costs more logic. It scales to any depth with the same code.

    Self-Check

    Tick each key point you covered in your answer.

    Missed Corner

    "A two-entry FIFO with ready = !full is the same as a skid buffer."

    It is close, but full must come from a flop and the FIFO must accept a write when a read frees space. Many FIFOs refuse that write.

    Source Lesson R5.2 review claims (a write is accepted only on the flags before the edge)

  5. Prove ItSolve R4.4.1: A Skid BufferSimulator-graded

    Show it, don't just say it: this Silicon Lab problem is graded by the simulator.

    Open Problem R4.4.1

What People Get Wrong

Common wrong answers and why they fail. Run It shows the wrong belief failing on a real simulator.

Misconception

"Just register ready; the stage stays the same."

The source sees ready one cycle late and sends a beat the stage cannot hold. The output register gets overwritten, as the twin shows.

Run It

The same bench on a stage that only registers ready.

RUNIcarus Verilog · in your browser
Edit the code, then run it
Expected: beats sent=39 received=23 out of order or missing=14 FAIL: registering ready alone dropped beats while the sink stalled
See the Fix
// A skid buffer: a pipeline stage whose ready output comes straight from a flop.
module skid #(parameter int W = 8) (
  input  logic         clk, rst_n,
  input  logic         in_valid,
  input  logic [W-1:0] in_data,
  output logic         in_ready,
  output logic         out_valid,
  output logic [W-1:0] out_data,
  input  logic         out_ready
);
  logic         skid_valid;
  logic [W-1:0] skid_data;
  assign in_ready = !skid_valid;                     // a flop output: no path from out_ready
  always_ff @(posedge clk or negedge rst_n)
    if (!rst_n) begin
      out_valid  <= 0;
      skid_valid <= 0;
    end else if (out_ready || !out_valid) begin      // the output register can load
      if (skid_valid) begin                          // drain the spare entry first
        out_data   <= skid_data;
        out_valid  <= 1;
        skid_valid <= 0;
      end else begin
        out_valid <= in_valid;
        if (in_valid) out_data <= in_data;
      end
    end else if (in_valid && in_ready) begin         // output stalled: catch the beat in flight
      skid_data  <= in_data;
      skid_valid <= 1;
    end
endmodule
module tb;
  logic clk = 0, rst_n = 0;
  always #5 clk = ~clk;
  logic       in_valid = 0, in_ready, out_valid, out_ready = 0;
  logic [7:0] in_data = 0, out_data, next_out = 0;
  int sent = 0, got = 0, wrong = 0;
  logic [15:0] stall = 16'b1011_0011_1001_1101;      // the sink's ready pattern, repeating
  skid #(.W(8)) dut (.*);
  initial begin
    #12 rst_n = 1;
    for (int i = 0; i < 64; i++) begin
      @(posedge clk);
      if (in_valid && in_ready) begin in_data <= in_data + 1; sent++; end
      if (out_valid && out_ready) begin
        got++;
        if (out_data !== next_out) wrong++;
        next_out <= out_data + 1;
      end
      in_valid  <= 1;                                // the source always has data
      out_ready <= stall[i % 16];
    end
    $display("beats sent=%0d received=%0d out of order or missing=%0d", sent, got, wrong);
    if (wrong == 0) $display("PASS: the skid buffer kept every beat in order");
    $finish;
  end
endmodule

Prints: beats sent=40 received=38 out of order or missing=0 PASS: the skid buffer kept every beat in order

Spec Misquote

"Make the source wait for ready before raising valid."

A valid/ready source must not wait for ready. If both sides wait for each other, nothing ever moves.

Source Arm IHI 0051B AXI4-Stream §2.2.1 (handshake: TVALID must not wait for TREADY), as cited in lesson R4.4

Missed Corner

Writes a one-entry buffer and calls it a skid buffer.

One entry cannot both hold the stalled output and catch the beat in flight. It either loses data or must drop throughput to half.

Source Lesson R4.4 review claims (the two-entry skid buffer, measured on its bench)

Learn It, Then Prove It