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

AboutRoadmapCareersInternshipsFAQContactPrivacyTerms
Skip to lesson

Course contents

  • How to Use This Puzzle Bank
  • SystemVerilog Language Puzzles25
  • Difficulty Guide
  • Full Topic Map
  • Interview-Day Tips
  • Study Route: One Week Before the Interview
  • Study Route: Two Weeks
  • Study Route: Four Weeks (Full Course)4
  • OOP & Testbench Puzzles25
  • Concurrency & Timing Puzzles25
  • Randomization & Constraint Puzzles25
  • SVA Assertion Puzzles25
  • Functional Coverage Puzzles25
  • Logic & Aptitude Puzzles25
  • Scenario & Debug Puzzles25
  • UVM Testbench Puzzles25
  • Clock, Reset & CDC Puzzles25
  • Bus and Interface Protocol Puzzles25
    • Valid/Ready Handshake Puzzles
      • Counting Transfers in a Valid/Ready Trace
      • Which Cycle Drops VALID Illegally?
      • Payload Changes While Stalled
      • Both Sides Wait: The Handshake Deadlock
      • Registered READY Overflows a FIFO
      • Register Slice: 50% Throughput Without Data Errors
    • APB Protocol Puzzles
    • AXI Protocol Puzzles
    • FIFO, Arbitration and Credit Puzzles
    • Bus and Interface Protocol Puzzles: Tricky Q&A
  • Interview Prep: Puzzle Rounds7
  • DV Puzzle Cheatsheet
Loading lesson

←Valid/Ready Handshake Puzzles
  1. Topics
  2. DV Interview Puzzles
  3. Bus and Interface Protocol Puzzles
  4. Valid/Ready Handshake Puzzles
  5. Register Slice: 50% Throughput Without Data Errors
On this page

    VLSI DV Interview PuzzlesAll levels

    Register Slice: 50% Throughput Without Data Errors

    Three one-stage pipeline implementations see the same input: the source always has a beat (and holds it until accepted) and the sink READY follows 11110011111111 over 14 cycles. A = ready from the stage's own register only (in_ready = !full); B = in_ready = !full || out_ready; C = skid buffer with registered ready. How many beats does each deliver and how many arrive wrong or out of order? Which would you choose for timing closure at full speed?

    Puzzle

    Difficulty: Hard · Puzzle 6 of 6 · Topic: Valid/Ready Handshake Puzzles

    Three one-stage pipeline implementations see the same input: the source always has a beat (and holds it until accepted) and the sink READY follows 11110011111111 over 14 cycles. A = ready from the stage's own register only (in_ready = !full); B = in_ready = !full || out_ready; C = skid buffer with registered ready. How many beats does each deliver and how many arrive wrong or out of order? Which would you choose for timing closure at full speed?

    Code

    slice_reg.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
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    `timescale 1ns/1ns
    // A: ready comes only from the stage's own register (no combinational path from out_ready)
    module slice_reg(input bit clk, input bit in_valid, output bit in_ready, input bit [7:0] in_data,
                     output bit out_valid, input bit out_ready, output bit [7:0] out_data);
      bit v_q = 0; bit [7:0] d_q = 0;
      assign in_ready = !v_q;
      assign out_valid = v_q; assign out_data = d_q;
      always @(posedge clk) begin
        if (in_valid && in_ready) begin v_q <= 1; d_q <= in_data; end
        else if (out_ready) v_q <= 0;
      end
    endmodule
    
    // B: ready also looks at out_ready (combinational ready path)
    module slice_comb(input bit clk, input bit in_valid, output bit in_ready, input bit [7:0] in_data,
                      output bit out_valid, input bit out_ready, output bit [7:0] out_data);
      bit v_q = 0; bit [7:0] d_q = 0;
      assign in_ready = !v_q || out_ready;
      assign out_valid = v_q; assign out_data = d_q;
      always @(posedge clk) begin
        if (in_valid && in_ready) begin v_q <= 1; d_q <= in_data; end
        else if (out_ready) v_q <= 0;
      end
    endmodule
    
    // C: skid buffer: registered ready, full throughput
    module slice_skid(input bit clk, input bit in_valid, output bit in_ready, input bit [7:0] in_data,
                      output bit out_valid, input bit out_ready, output bit [7:0] out_data);
      bit v_main = 0, v_skid = 0; bit [7:0] d_main = 0, d_skid = 0;
      assign in_ready = !v_skid;
      assign out_valid = v_main; assign out_data = d_main;
      always @(posedge clk) begin
        if (out_ready || !v_main) begin
          if (v_skid) begin d_main <= d_skid; v_main <= 1; v_skid <= 0; end
          else        begin d_main <= in_data; v_main <= in_valid; end
        end else if (in_valid && in_ready) begin
          d_skid <= in_data; v_skid <= 1;
        end
      end
    endmodule
    
    module env #(parameter int KIND = 0) (input bit clk, input bit out_ready);
      bit [7:0] next = 0, expect_d = 0;
      int out_cnt = 0, bad = 0;
      wire in_valid = 1;                        // source always has a beat and holds it until accepted
      wire in_ready, out_valid; wire [7:0] out_data;
      if (KIND == 0) slice_reg  u(clk, in_valid, in_ready, next, out_valid, out_ready, out_data);
      if (KIND == 1) slice_comb u(clk, in_valid, in_ready, next, out_valid, out_ready, out_data);
      if (KIND == 2) slice_skid u(clk, in_valid, in_ready, next, out_valid, out_ready, out_data);
      always @(posedge clk) begin
        if (in_valid && in_ready) next <= next + 1;
        if (out_valid && out_ready) begin
          out_cnt++;
          if (out_data !== expect_d) bad++;
          expect_d <= expect_d + 1;
        end
      end
    endmodule
    
    module tb;
      bit clk = 0;
      always #5 clk = ~clk;
      localparam int N = 14;
      //                       cycle: 01234567890123
      localparam bit [0:N-1] SINK = 14'b11110011111111;
      int cyc = 0;
      always @(posedge clk) cyc <= cyc + 1;
      wire out_ready = SINK[cyc];
      env #(0) a(clk, out_ready);
      env #(1) b(clk, out_ready);
      env #(2) c(clk, out_ready);
      initial begin
        #(10*N);
        $display("A registered-ready only : out=%0d wrong=%0d", a.out_cnt, a.bad);
        $display("B combinational ready   : out=%0d wrong=%0d", b.out_cnt, b.bad);
        $display("C skid buffer           : out=%0d wrong=%0d", c.out_cnt, c.bad);
        $finish;
      end
    endmodule

    Hint

    In A, a full stage cannot accept in the same cycle it drains. Count how many cycles per beat.

    Step-by-step solution

    Diagram
    1) Sink ready pattern: cycles 0-3 high, 4-5 low, 6-13 high.
    2) A: the stage is full after accepting, so in_ready=0 while it drains, then it accepts again: one beat per two cycles while the sink is ready -> 6 beats in 14 cycles.
    3) B: in_ready follows out_ready, so a full stage drains and refills every cycle -> 11 beats (cycles 1-3 and 6-13). It has a combinational ready path from sink to source.
    4) C: the skid register absorbs the one beat that arrives in the cycle ready was still high while the main register was blocked, so ready can be a flop output and throughput is full -> 11 beats.
    5) No design loses or reorders data (wrong=0 everywhere). A is not broken, only slow.

    Answer

    Answer: A delivers 6, B delivers 11, C delivers 11; wrong=0 in all three. Choose C: full throughput without a combinational ready chain through the pipeline.

    How this was checked

    Checked by running the code in Verilator 5; the printed output supports the answer above. Same traffic for all three stages: the registered-only slice delivers 6 beats, the combinational-ready and skid versions deliver 11, none corrupts data.

    Why candidates get it wrong

    A passes every data-integrity check: scoreboards report zero errors. The bug is bandwidth (50%), which only a throughput or latency check catches. And B 'fixes' it with a combinational ready path that ripples through a chain of stages and kills the timing.

    Interviewer follow-up

    What does the skid buffer cost and why does it hold exactly one extra beat? Model answer: One extra data register plus a mux per stage. Because ready is registered, the stage learns that it is blocked one cycle late, so exactly one more beat can already be in flight; the skid register stores that one beat, and ready is deasserted so no second extra beat can arrive.

    Related topics

    • Back to Valid/Ready Handshake Puzzles

    • Bus and Interface Protocol Puzzles section

    Previous

    266 / 293

    Next: APB Protocol Puzzles

    Up next

    Up nextAPB Protocol Puzzles

    Sign in to save progress

    Practice this lessonPrevious lessonReport an error

    See also

    • Counting Transfers in a Valid/Ready Trace
    • Which Cycle Drops VALID Illegally?
    • Payload Changes While Stalled