← RTL Design Interviews

Interview Question · Debug

The Link Where Each Side Waits for the Other

L2 Mid-LevelL3 Seniorcombinational loopshandshakesvalid ready

The Question

The interviewer asks

A source and a sink pass all their unit tests. Joined, the link never moves a beat. Here is the log. What is wrong?

log
edge: valid=x ready=x
edge: valid=x ready=x
edge: valid=x ready=x
0 beats in 9 cycles
Reveal the Model Answer

The source drives valid = have_data && ready, and the sink drives ready = valid && !full. Each waits for the other through logic, so the two ANDs form a combinational loop. Both 0 and both 1 are stable, and nothing picks one, so simulation shows X. The rule is that valid must not depend on ready. The sink may wait for valid.

The Loop and the Two Ways OutArrows are combinational paths inside one clock cycle. A flop ends a path; the next cycle starts from it.
The loop and the two ways outArrows are combinational paths inside one clock cycle. A flop ends a path; the next cycle starts from it. flop src state flop: IDLE or SEND logic valid gate send && ready logic ready gate empty && valid flop snk state flop: EMPTY or FULL logic sink takes beat at the edge sendemptyvalidreadybeat
  1. The loop

    valid depends on ready and ready depends on valid in the same cycle. No flop sits on the circle, so its value has no clock to settle on.

  2. Source from state

    Write valid = send. The arrow from ready to the valid gate is gone; the circle is open. The source waits for ready at the edge, as the handshake rule asks.

  3. Sink from state

    Write ready = empty. The sink promises room before it sees a beat. This is the shipped lab: both outputs come from flops.

Read the diagram as text
  • src state: flop: IDLE or SEND
  • valid gate: send && ready
  • ready gate: empty && valid
  • snk state: flop: EMPTY or FULL
  • sink takes beat: at the edge
  • src state → valid gate: send
  • snk state → ready gate: empty
  • valid gate → ready gate: valid
  • ready gate → valid gate: ready
  • valid gate → sink takes beat: beat

Opening either arrow breaks the loop. The house style opens both.

Both Sides Waiting for the OtherThe looped version on the lab bench. The source is in SEND from edge 2 and the sink is EMPTY, yet valid and ready stay 0.
0123456clksrcSENDsnkEMPTYvalidready
  1. Cycle 0

    Edge 2: the source enters SEND. valid = send && ready, and ready is 0, so valid stays 0.

  2. Cycle 1

    ready = empty && valid, and valid is 0, so ready stays 0. Each value holds the other at 0.

  3. Cycle 6

    After seven cycles nothing has moved. The run ends with "0 beats in 9 cycles".

Measured with Icarus, cycles e2 to e8. Verilator printed the same 0 beats.

Self-Check

Tick each key point you covered in your answer.

What Interviewers Listen For (Mid-Level)

A good mid-level answer reads the X on both wires as a loop, not a reset bug. It traces valid to ready and back, then quotes the dependency rule.

Cross-Questions

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

WhyWhat IfProve ItCompareScale It

  1. The Link Where Each Side Waits for the Other
  2. WhyWhy the Rule Constrains Valid and Not ReadyL1 JuniorL2 Mid-Level

    Why does the handshake rule say valid must not wait for ready, but ready may wait for valid?

    Reveal the Model Answer

    One side must be allowed to go first without waiting, or a deadlock is possible. The rule picks the sender. A sender that has data raises valid on its own. Then any receiver works, whether it waits for valid or raises ready early.

    Self-Check

    Tick each key point you covered in your answer.

    Spec Misquote

    "Neither signal may depend on the other."

    That is stricter than the rule. A receiver may legally wait for valid, and many simple sinks do.

    Source Arm AMBA AXI Protocol Specification IHI 0022H.c §A3.3.1 Dependencies between channel handshake signals (as read for lesson R3.3)

  3. What IfA Sink That Raises Ready EarlyL1 Junior

    What if the sink raises ready before there is any valid?

    Reveal the Model Answer

    That is allowed and often faster, because a beat moves in the first cycle valid rises. The sink must then be able to take a beat in any cycle where ready is high. Nothing transfers until both are high at the same edge.

    Self-Check

    Tick each key point you covered in your answer.

    Spec Misquote

    "Ready high with no valid is a protocol error."

    A transfer needs both high at one edge. Ready alone is just an offer to accept.

    Source Arm AMBA AXI Protocol Specification IHI 0022H.c §A3.1.1 and §A3.2.1 (as read for lesson R3.3)

  4. CompareA Registered Ready vs a Combinational ReadyL2 Mid-LevelL3 Senior

    Compare a ready that comes from a flop with one computed from logic.

    Reveal the Model Answer

    A combinational ready can depend on what happens downstream in the same cycle. In a chain of stages it becomes one long path that grows with every stage. A registered ready cuts that path and every loop through it. But it arrives a cycle late, so the stage needs a spare entry, a skid buffer, to keep full rate.

    Four Beats with Valid and Ready from StateThe source holds valid from edge 2. The sink is ready every other cycle.
    validdatareadySourceSEND: four beatsSinkone-beat buffer

    A lit wire carries a 1. A pill is a transfer in that cycle.

    012345678clkvalidreadydata12341
    1. Cycle 0

      Cycle e2: both are 1. Beat 1 moves at edge 3.

    2. Cycle 1

      Cycle e3: the sink is FULL, so ready is 0. The source holds valid and data 2.

    3. Cycle 2

      Cycle e4: the consumer emptied the buffer at edge 4. Beat 2 moves at edge 5.

    4. Cycle 6

      Beat 4 moves at edge 9 and the source returns to IDLE.

    Measured on the lab bench: "4 beats, e3 to e9".

    Self-Check

    Tick each key point you covered in your answer.

    Missed Corner

    "Registering ready only costs one flop."

    Without a spare entry, the stage must stop a cycle early and loses rate, or it drops a beat. The skid entry costs area.

    Source Lesson R4.4, measured: the registered-ready stage without a skid buffer lost beat 3 on the lab bench

  5. Scale ItStopping Handshake Loops at IntegrationL3 SeniorL4 Staff

    Scale it: dozens of blocks from several teams meet on valid/ready ports. How do you stop this class of bug?

    Reveal the Model Answer

    Write it down as an interface rule. No port has a combinational path from an input to an output, and valid never waits for ready. Check it on the joined design at every integration drop. Use lint and the synthesis check. Bind assertions on every port, such as valid staying high until the transfer.

    Self-Check

    Tick each key point you covered in your answer.

    Wrong Altitude

    "Each team runs lint, so integration is covered."

    Loops through two blocks appear only in the joined netlist. The check must run where the blocks meet.

    Source Lesson R3.3, measured with Verilator 5.052 --lint-only -Wall: UNOPTFLAT "Circular combinational logic" on the looped link

    Half-Truth

    Relies on the full-chip regression to show deadlocks.

    A deadlock shows only if a test reaches both waiting states together. The structural check finds the loop without any test.

  6. Prove ItSolve R3.3.1: The Link That Moved NothingSimulator-graded

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

    Open Problem R3.3.1

What People Get Wrong

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

Misconception

"A polite source waits for ready before it raises valid."

If the sink also waits for valid, neither ever goes first. The twin moves 0 beats in 9 cycles.

Run It

The source gates valid with ready; the sink gates ready with valid.

RUNIcarus Verilog · in your browser
Edit the code, then run it
Expected: edge: valid=x ready=x 0 beats in 9 cycles FAIL: valid waits for ready and ready waits for valid, so no beat ever moves
See the Fix
module src (input logic clk, rst_n, ready, output logic valid, output logic [7:0] data);
  logic [2:0] sent;
  assign valid = (sent < 4);             // offer whenever there is data
  assign data  = 8'd1 + sent;
  always_ff @(posedge clk or negedge rst_n)
    if (!rst_n) sent <= 0; else if (valid && ready) sent <= sent + 3'd1;
endmodule

module snk (input logic clk, rst_n, valid, input logic [7:0] data, output logic ready, output int beats);
  logic full;
  assign ready = valid && !full;          // the sink waits for valid: this is allowed
  always_ff @(posedge clk or negedge rst_n)
    if (!rst_n) begin full <= 0; beats <= 0; end
    else if (valid && ready) beats <= beats + 1;
endmodule

module tb;
  logic clk = 0, rst_n = 0, valid, ready;
  logic [7:0] data;
  int beats;
  src s (.*);
  snk k (.*);
  always #5 clk = ~clk;
  initial begin
    #12 rst_n = 1;
    repeat (3) @(posedge clk) $display("edge: valid=%b ready=%b", valid, ready);
    repeat (6) @(posedge clk);
    $display("%0d beats in 9 cycles", beats);
    if (beats == 4) $display("PASS: valid no longer waits for ready, and all 4 beats move");
    $finish;
  end
endmodule

Prints: 4 beats in 9 cycles PASS: valid no longer waits for ready, and all 4 beats move

Missed Corner

"The X is a reset problem; reset the wires to 0."

Both are outputs of logic, not flops. The X comes from the loop having two stable values, and 0 would only hide the deadlock.

Source Measured: the twin on design.loop.valid-ready-deadlock, Icarus Verilog 12

Delivery

Blames the sink and rewrites it to raise ready first.

That happens to work here, but the sink was legal. The source broke the rule, and the next legal sink will deadlock it again.

Learn It, Then Prove It