Skip to content
VLSI Mentor

USB · Module 13

Status Stage

A zero-length packet running the opposite way to the data stage — the only place a device can report that a request it already accepted has failed.

Two stages down. The third carries no data at all — a zero-length packet, always — and it is the strangest of the three for two reasons.

It runs in the opposite direction to the data stage. And it is the only place a device can say that a request it already accepted has failed.

1. Why a Transfer Needs a Third Stage

Chapter 13.1 §3 established that a device may not refuse a SETUP. It must acknowledge every one, whatever state it is in.

Which creates a gap. The device has accepted the request — that is what the ACK meant — and it has not yet done it. And for many requests it cannot do it immediately:

  • SET_ADDRESS must not take effect until the transfer completes, or the host's next token would be addressed differently from the one in flight;
  • SET_CONFIGURATION allocates endpoints and buffers;
  • a vendor request may write flash, move a motor, or wait on something.

The setup stage's ACK means I have received this request. It does not and cannot mean I have carried it out.

So the protocol needs a second acknowledgement, after the work — and that is the status stage.

2. The Direction Reverses

The rule, and it is short:

The status stage runs opposite to the data stage.

Data stageStatus stageWho sends the ZLP
IN (device → host)OUTthe host
OUT (host → device)INthe device
noneINthe device

Why reverse? Because the status stage is an acknowledgement, and Chapter 12.3 §1's rule applies one level up: whoever received the data reports on it. After an IN data stage the host is the one with something to say, so the host transmits.

And the third row is the interesting one, because there is no data stage to reverse.

A sequence diagram of three control transfers. In the first, a GET_DESCRIPTOR, the setup stage is followed by an IN data stage in which the device sends the descriptor; the status stage therefore runs OUT and the host transmits a zero-length packet to acknowledge that the request succeeded. In the second, a SET_ADDRESS with a zero length, there is no data stage at all; the status stage is IN by rule and the device transmits the zero-length packet once it has accepted the new address. In the third, a SET_DESCRIPTOR with an OUT data stage, the host sends the data and the status stage runs IN; the device, having found it cannot carry out the request, answers the status stage with a STALL rather than a zero-length packet, which is the only point in the transfer at which it can report that failure.Three shapes, three status directionsHostControl endpointSETUP ·GET_DESCRIPTOR ·wLength 18DATA — thedescriptor (IN)STATUS: zero-lengthpacket (OUT)SETUP · SET_ADDRESS· wLength 0no data stage —nothing to reverseSTATUS: zero-lengthpacket (IN, by rule)SETUP ·SET_DESCRIPTOR ·wLength 8DATA — eight bytes(OUT)…cannot carry thisoutSTATUS: STALL — theonly place to say so
Figure 1 — three control transfers and their status stages. The direction reverses in the first two; the third has no data stage to reverse, so the rule fixes it as IN. Note that the party transmitting the status ZLP is always the one that received the data — or, when there was none, the device that did the work.

3. Three Answers, Not One

The status stage is a transaction like any other, so Chapter 11.3's answers apply — and here each of them means something specific about the request:

AnswerMeans
ZLP (or ACK of one)the request succeeded
NAKnot yet — the device is still working on it
STALLthe request failed, or is not supported

The NAK is what makes a slow request possible. A device that needs a millisecond to write flash NAKs the status stage until it is done — and the host retries. Nothing about the transfer is lost; it simply takes longer.

And the STALL is what makes the status stage load-bearing. Without it, a device that accepted a SETUP it cannot honour would have to either lie or go silent.

The status stage is the only place in a control transfer where a device can report a failure of meaning rather than a failure of transmission.

Everything before it reports transmission. A STALL in the data stage says I cannot supply these bytes; a STALL in the status stage says I understood you and could not do it — and only the second distinguishes an unsupported request from a broken link.

4. What the Device May Not Do

Two constraints that follow from §1's gap and are easy to violate.

The request must not take effect before the status stage completes. SET_ADDRESS is the canonical case and Chapter 8.4 established why: the device must answer the status stage at its old address, because the host's transaction is already in flight. Changing address early means the status stage is addressed to a device that no longer exists.

And the device must not refuse the status stage forever. NAK is not yet, and a device that NAKs indefinitely has produced Chapter 11.3 §2's worst failure — a transfer that never completes and never fails, on a bus that looks healthy.

Both are the same underlying constraint stated twice: the status stage is the transfer's commit point, and a device must arrange for that commit to be reachable and atomic with respect to the host's view.

5. The Status Stage, as RTL

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// usb_ctrl_status_stage
//
// Classification: SIMPLIFIED SYNTHESIZABLE TEACHING RTL. It models section
// 2's direction rule and section 3's three answers.
//
// WHAT IT MODELS. When the status stage is due, which way it runs, which
// end transmits the zero-length packet, and what the device answers -- which
// is the transfer's commit point.
//
// WHAT IT DOES NOT MODEL. The transactions that carry the stage (Module
// 12); the data stage (Chapter 13.2); the SETUP (Chapter 13.1); the WORK the
// request asks for, which arrives here only as request_ok / request_pending;
// and the deferred application of that work (section 4), which belongs to
// whatever executes the request.
//
// ── WHY THE SHAPE IS CAPTURED AT SETUP ──────────────────────────────────
// `has_data_q` and `data_in_q` are latched when the SETUP lands, not read
// live. By the time the status stage runs, the SETUP is several transactions
// in the past -- Chapter 12.1's capture rule, one level up. A design reading
// wLength live here would work only as long as nothing else drove it.
// ─────────────────────────────────────────────────────────────────────────
module usb_ctrl_status_stage (
  input  logic        clk,
  input  logic        rst_n,
  input  logic        bus_reset,

  // From Chapter 13.1's decode, at the moment the SETUP completed.
  input  logic        setup_new,
  input  logic [15:0] wLength,
  input  logic        dir_is_in,        // the DATA stage's direction

  input  logic        data_stage_done,

  // Section 3: what the REQUEST did, supplied by whatever executes it.
  input  logic        request_ok,
  input  logic        request_pending,

  input  logic        status_pkt,       // the status transaction happened

  output logic        status_due,
  output logic        status_is_in,     // section 2
  output logic        device_sends_zlp,
  output logic        host_sends_zlp,
  output logic        send_stall,       // section 3: the request FAILED
  output logic        send_nak,         // section 3: not yet
  output logic        transfer_done
);

  logic has_data;
  assign has_data = (wLength != 16'd0);

  logic armed_q, has_data_q, data_in_q;
  assign status_due = armed_q;

  // ── SECTION 2'S RULE ────────────────────────────────────────────────────
  // Opposite to the data stage -- and IN when there is no data stage to be
  // opposite to. The second half is a RULE, not a derivation, which is why
  // it is written as a literal rather than computed from dir_is_in.
  assign status_is_in = has_data_q ? !data_in_q : 1'b1;

  // Whoever did NOT send the data sends the status packet.
  assign device_sends_zlp = armed_q &&  status_is_in && request_ok && !request_pending;
  assign host_sends_zlp   = armed_q && !status_is_in;

  // ── SECTION 3 ───────────────────────────────────────────────────────────
  // The only point at which a device can report that a request it already
  // accepted cannot be carried out. Removing it (section 6's T3) leaves a
  // device that has no way to say no after saying yes.
  assign send_stall = armed_q && !request_ok && !request_pending;

  // "Not yet" -- the mechanism that makes a slow request possible without
  // making it a failure. Section 4: it must not be forever.
  assign send_nak = armed_q && request_pending;

  assign transfer_done = armed_q && status_pkt;

  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      armed_q <= 1'b0; has_data_q <= 1'b0; data_in_q <= 1'b0;
    end else if (bus_reset) begin
      armed_q <= 1'b0; has_data_q <= 1'b0; data_in_q <= 1'b0;
    end else if (setup_new) begin
      has_data_q <= has_data;
      data_in_q  <= dir_is_in;
      // A zero-length request goes straight to the status stage: there is
      // no data stage to wait for.
      armed_q    <= !has_data;
    end else if (data_stage_done) begin
      armed_q <= 1'b1;
    end else if (armed_q && status_pkt) begin
      armed_q <= 1'b0;
    end
  end

endmodule

What it models. When the status stage is due, its direction, its transmitter, and the device's answer.

Engineering reason. Because the setup stage's ACK cannot carry a claim about the request, so the transfer needs a commit point — and that point has a direction rule with a special case.

Inputs. The SETUP's length and direction, the data stage's completion, the request's outcome, and the status transaction.

State retained. Three bits — armed, had-data, data-direction.

Outputs. Due, direction, the two transmitters, two negative answers, and completion.

Hardware implied. Three flip-flops and a handful of gates.

Reset behaviour. Disarmed; a control transfer does not survive a bus reset.

Assumptions. That request_ok and request_pending are stable for the duration of the status stage — a request that changes its mind mid-stage is not modelled; that status_pkt marks a completed status transaction; and that whatever executes the request defers its effect until transfer_done, which this block cannot enforce.

Omissions. The transactions, the other two stages, the request's execution and its deferral — in the header.

What DV should verify. That the status direction is opposite the data stage; that a zero-length request's status stage is IN; that exactly one end transmits; that a failed request stalls the status stage; that a pending one NAKs and does not stall; that a completion outside an armed stage does nothing; and that the stage always arms and always clears.

The direction reverses, and the answer is about the request

10 cycles
A waveform of the status stage controller over ten events spanning three control transfers. The first transfer is a GET_DESCRIPTOR with a declared length of eighteen and an IN data stage. Its setup and data-done events leave the status stage not yet due; once the data stage completes, the status stage becomes due, runs OUT because the data stage ran IN, and the host transmits the zero-length packet. The second transfer is a SET_ADDRESS with a declared length of zero, so there is no data stage; the status stage becomes due immediately, runs IN by rule, and the device transmits the zero-length packet. The third transfer is a SET_DESCRIPTOR with a declared length of eight and an OUT data stage; once that completes, the status stage runs IN, and because the request could not be carried out the device answers with a STALL rather than a zero-length packet.IN data → OUT status, host sends itIN data → OUT status, hostsends itno data → IN status, by ruleno data → IN status, byrulerequest failed — the only place to say sorequest failed — the onlyplace to say sophaseGET_DESCdata doneSTATUSZLPSET_ADDRSTATUSZLPSET_DESCdata doneSTATUSwLength18181818000888data dirININININnonenonenoneOUTOUTOUTstatus_duestatus dir——OUTOUT—ININ——INanswer——hosthost—devicedevice——STALLt0t1t2t3t4t5t6t7t8t9
Figure 2 — three control transfers, every column taken from a simulation of the block above. The first has an IN data stage and an OUT status stage transmitted by the host; the second has no data stage and an IN status stage transmitted by the device; the third has an OUT data stage, an IN status stage, and a request that failed — so the device answers STALL instead of a zero-length packet.

6. Mutation Test

Five mutations over 408 control transfers, covering all four shapes — IN data, OUT data, no data with each direction bit — plus failed requests, pending requests of 1 to 4 cycles, and 400 randomised transfers.

The unmutated block: 217 IN status stages, 191 OUT, 25 stalls, 629 NAK cycles, and 0 errors of every kind.

direction wrongof which no-datawrong transmitterfailure unreportedpending unreporteddone unarmed
golden000000
T1 direction not reversed3990226000
T2 no-data status is OUT994000
T3 never stalls0002500
T4 never NAKs00006290
T5 completion not gated on armed00000408

T1 — do not reverse the direction

Measured: 399 wrong out of 408 — every transfer that has a data stage — and 226 cases where the wrong end transmitted.

§2's rule removed. The device tries to transmit the status ZLP after an IN data stage, where the host owns the slot — which is Chapter 12.3 §3's bus contention arriving one level up.

Caught by the first transfer of any test, and included as the contrast for T2.

T2 — make the no-data status stage OUT

Measured: 9 wrong out of 408 — and all 9 are zero-length transfers.

§2's callout. Nine is 2.2% of the bench and 100% of the requests enumeration depends on: SET_ADDRESS and SET_CONFIGURATION are both zero-length, and a device that expects the host to send their status ZLP waits for a packet the host will never send.

The device then NAKs or times out on SET_ADDRESS — so it never acquires an address, which presents as a device that is detected and never enumerates.

T1 is nine times more wrong and a hundred times easier to find.

T3 — never stall the status stage

Measured: 25 failures unreported, and nothing else changed.

§3's load-bearing answer removed. A device that cannot carry out a request now reports success, and the host proceeds on the assumption that it worked.

And the damage is entirely downstream. The transfer completes, the host's state diverges from the device's, and the failure surfaces as something unrelated — a configuration the device does not have, a feature the host believes is enabled. There is no error anywhere near the cause.

T4 — never NAK a pending request

Measured: 629 NAK cycles unreported.

Without not yet, a device that needs time has only two answers: succeed before it has or fail. §4: a slow request becomes either a lie or an error, and a device that writes flash on SET_FEATURE has no way to be honest about taking a millisecond.

T5 — report completion without an armed stage

Measured: 408 spurious completions — one per transfer.

A status packet arriving outside a status stage completes… something. The transfer that was not running. Chapter 12.1 §3's stray-packet problem, one level up: a packet that belongs to no open context must do nothing, and gating on armed_q is the whole of that.

7. The Assertions

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// Classification: TEACHING ASSERTIONS about the status stage.
// D-properties are the DIRECTION rule; A the three ANSWERS;
// C the commit point.
// ─────────────────────────────────────────────────────────────────────────

// D1 -- THE STATUS STAGE REVERSES THE DATA STAGE. Section 2, and section
// 6's T1. Stated against the CAPTURED data direction, because that is what
// the rule is about -- not against whatever dir_is_in currently reads.
property p_status_reverses_data;
  @(posedge clk) disable iff (!rst_n)
    (status_due && had_data) |-> (status_is_in == !captured_data_in);
endproperty
assert property (p_status_reverses_data);   // via bind

// D2 -- AND WITH NO DATA STAGE IT IS IN. Section 2's rule with nothing to
// reverse, and section 6's T2. Separate from D1 because it is a DIFFERENT
// rule rather than a case of the same one -- and a failing assertion should
// say which rule broke.
property p_no_data_status_is_in;
  @(posedge clk) disable iff (!rst_n)
    (status_due && !had_data) |-> status_is_in;
endproperty
assert property (p_no_data_status_is_in);   // via bind

// D3 -- EXACTLY ONE END TRANSMITS, and it is the one the direction names.
property p_one_transmitter;
  @(posedge clk) disable iff (!rst_n)
    (status_due && !send_stall && !send_nak)
      |-> (device_sends_zlp ^ host_sends_zlp);
endproperty
assert property (p_one_transmitter);

// A1 -- A FAILED REQUEST STALLS THE STATUS STAGE. Section 3, and section
// 6's T3. The ONLY place a request-level failure can be reported.
property p_failure_stalls;
  @(posedge clk) disable iff (!rst_n)
    (status_due && !request_ok && !request_pending) |-> send_stall;
endproperty
assert property (p_failure_stalls);

// A2 -- A PENDING REQUEST NAKS, AND DOES NOT STALL. Section 6's T4, and the
// second conjunct is the important one: "not yet" reported as "never" is
// Chapter 11.3 section 2's inversion, and it aborts a transfer that would
// have succeeded.
property p_pending_naks;
  @(posedge clk) disable iff (!rst_n)
    (status_due && request_pending) |-> (send_nak && !send_stall);
endproperty
assert property (p_pending_naks);

// A3 -- AND A SUCCESSFUL ONE DOES NEITHER. Without this, a device that
// stalls everything satisfies A1.
property p_success_is_clean;
  @(posedge clk) disable iff (!rst_n)
    (status_due && request_ok && !request_pending)
      |-> (!send_stall && !send_nak);
endproperty
assert property (p_success_is_clean);

// C1 -- COMPLETION REQUIRES AN ARMED STAGE. Section 6's T5.
property p_done_needs_armed;
  @(posedge clk) disable iff (!rst_n)
    transfer_done |-> status_due;
endproperty
assert property (p_done_needs_armed);

// C2 -- AND EVERY TRANSFER REACHES A STATUS STAGE. A progress property:
// a control transfer that never arms one has no commit point at all. The
// bound is Chapter 12.5's timeout, so this is stated as "within the window"
// rather than as an unbounded eventually -- Chapter 10.3 section 7's rule.
property p_status_eventually_due;
  @(posedge clk) disable iff (!rst_n)
    setup_new |-> ##[1:STATUS_WINDOW] (status_due || bus_reset);
endproperty
assert property (p_status_eventually_due);

D1 and D2 are deliberately separate, and a minimality-minded reviewer would merge them into one conditional expression. They are two different rules: one derives a direction and the other asserts one, and §6 measures them at 399 and 9 violations respectively. A merged property would fire on both and name neither.

A2's second conjunct carries the weight. send_nak alone would be satisfied by a design that also stalls — and not yet reported alongside never is Chapter 11.3 §2's inversion, which makes a host abandon a transfer that was about to succeed.

8. Verification

This chapter's commit point — literally — is the transfer committed exactly once, in the right direction, with an honest answer about the request.

Stimulus. All four transfer shapes; a failed request with and without a data stage; a pending request held for 1 to 5 cycles; a status packet arriving outside any status stage, after every transfer; a bus reset mid-transfer; and 400 randomised transfers over length, direction, outcome and pending duration.

Observation. The direction and both transmitters at the moment the stage becomes due; the three answers against the request's outcome; and a check after every transfer that a stray status packet completes nothing.

Reference model. Two rules evaluated directly — opposite to the data stage, IN when there is none — plus the three answers as a priority. Its independence comes from being a transcription of §§2–3 rather than a second implementation.

Coverage — crosses:

  • data direction (IN / OUT / none) × request outcome (ok / failed / pending)
  • wLength = 0 with the direction bit set and clear — the case T2 lives in
  • pending duration 0 to 5 cycles
  • bus reset before the data stage, after it, and during the status stage
  • a status packet with no stage armed — after every transfer

Negative cases with defined outcomes: the status direction is never the same as the data direction; a zero-length transfer's status stage is never OUT; both transmitters are never active together; a pending request never stalls; a successful one never does either; and a stray status packet never completes a transfer.

9. Debugging: the Device That Is Detected and Never Enumerates

A newly-built device is detected by the host — the port reports a connection and a speed — and enumeration never completes. The host retries and gives up. An analyser shows the host sending SET_ADDRESS and the device acknowledging the SETUP, and then nothing.

What does the SETUP is acknowledged establish? That the control endpoint receives, that the device decodes eight bytes, and that it can transmit a handshake. Quite a lot works.

What comes after a SET_ADDRESS SETUP? §2's third row: wLength is zero, so there is no data stage, and the status stage is IN — the device transmits the zero-length packet.

So what does and then nothing mean? That the device did not transmit it. And there are exactly two reasons: it does not believe the status stage is its to transmit, or it believes the request is still pending.

How do you tell them apart? By whether the host's status token is answered at all. A device with the direction backwards is waiting for the host to send a ZLP that the host is waiting to receive — deadlock, and the host's IN token goes unanswered entirely. A device that thinks the request is pending NAKs — a visible answer, repeatedly.

Silence versus NAK, and the trace shows which. §6's T2 produces the first; a stuck request_pending produces the second.

What if the device transmits the ZLP and enumeration still fails? Then the status stage worked and the fault is §4's other constraint: the device applied the new address too early, so the host's next token — addressed to the new address — reaches a device that has already moved, or the status stage itself was answered from the wrong address.

And why does this present as detected but never enumerated? Because SET_ADDRESS is the third control transfer of every enumeration and nothing after it can happen. A device that fails here fails identically regardless of everything downstream — which is why the symptom is so uninformative and the trace so decisive.

The signature to keep: a device that acknowledges a SETUP and then goes silent on a zero-length request has its status-stage direction backwards — and the discriminator is silence against NAK.

10. Common Misconceptions

11. Reason It Through

A device implements a vendor request that erases a flash sector, which takes 40 ms. The firmware performs the erase inside its SETUP handler, then returns. The device works on a bench host and fails intermittently on a customer's embedded host, which reports a timeout on that request.

Where does the 40 ms go? Inside the SETUP handler — before the device acknowledges anything after the SETUP itself.

What is the host doing during it? The request is zero-length, so after the SETUP the host immediately issues the IN status token — §2's third row. The device is busy erasing and does not answer.

Is that a violation? Not by itself. Chapter 12.5's turnaround timeout is tens of nanoseconds; the host times out, retries the status token, and keeps retrying. A device that eventually answers has taken a long time and broken nothing.

So why does one host fail? Because hosts differ in how long they retry before abandoning the transfer — which is Chapter 12.5 §5's software timeout, not its hardware one. The bench host retried for longer than 40 ms; the embedded one did not.

What is the correct implementation? §3: NAK the status stage while the erase proceeds. A NAK is an answer — the host sees a live device saying not yet, and its retry logic is designed for exactly that. Silence and NAK are treated very differently by a host, and the device chose the one that looks like a fault.

Does that fix the 40 ms? No, and it does not need to. It changes an unanswered transaction into an answered one, which is the difference between a host that waits and a host that gives up.

Is there a deeper problem? Yes: the handler blocks. A device that spends 40 ms inside a SETUP handler cannot answer anything — not this transfer's status stage, not another endpoint's traffic, not a bus reset. The NAK path requires the work to be asynchronous, which is the real change, and the NAK is what makes it expressible.

And the transferable point: a protocol's not yet answer exists so that slow work does not have to look like a fault — and a device that does long work synchronously has no way to use it. The mechanism and the architecture are coupled: you cannot adopt the NAK path without also making the work interruptible.

12. Understanding Check

13. Summary

The status stage exists because a device may not refuse a SETUP. Its acknowledgement of the setup stage means I received these eight bytes and cannot mean I did it — so the transfer needs a second acknowledgement, after the work. A control transfer has three handshakes and only the third is about the request.

It runs opposite to the data stage, because whoever received the data reports on it — so an IN data stage has an OUT status stage transmitted by the host. And with no data stage there is nothing to reverse, so the direction is fixed by rule as IN.

Three answers, not one: a zero-length packet means success, a NAK means not yet, and a STALL means the request failed. The status stage is the only place a device can report a failure of meaning rather than a failure of transmission.

§6 measured five mutations over 408 transfers:

  • Not reversing the direction is wrong on 399 of 408 and contends the bus — found by the first transfer of any test.
  • Making the no-data case OUT is wrong on 9 — which are SET_ADDRESS and SET_CONFIGURATION, so the device is detected and never enumerates. Nine times less wrong and a hundred times harder to find.
  • Never stalling reports success for requests that failed, with the damage surfacing far from the cause.
  • Never NAKing removes not yet, which reads as a simplification and is a constraint on every future request.
  • Ungating completion completes a transfer that was not running — and was caught only because the bench sends a stray status packet after every transfer and checks that nothing happens.

Which is §8's practice, and it generalises:

The negative space of a control signal is the cycles in which it must be low, and a bench that only observes during activity has no opinion about them at all.

And §11's worked example is the module's clearest coupling of mechanism to architecture: a device that does 40 ms of work inside its SETUP handler cannot use the NAK path, because the NAK path requires the work to be asynchronous. You cannot adopt not yet without making the work interruptible.

14. What Comes Next

Three stages, and not one of them has said what any request means.

Chapter 13.4 is the eleven standard requests — GET_STATUS through SYNCH_FRAME — and its subject is not a table of codes. It is which requests are legal in which device state, because Module 8's state machine and this module's request set are the same mechanism seen from two sides: a device in Default answers a different set than one that is Configured, and answering the wrong set is how a device becomes unreachable.

The codes themselves have a detail worth noticing in advance: they are not contiguous. 0x02 and 0x04 are gaps.

Browse the full path on the USB tutorials index.

Continue learning

Standards & specifications

Governing standard
USB-IF (Universal Serial Bus Specification)(opens USB Implementers Forum (USB-IF) in a new tab)

Defines the USB bus — its electrical signalling, connectors, packet and transaction model, device framework and the descriptors a device must expose — together with the device-class specifications layered on it. It does not define host-controller register interfaces (xHCI and EHCI are separate documents) nor any operating system's driver architecture.

This page also covers RTL structure, verification approach and debugging technique. Those are engineering practice built on the standard, not requirements the standard itself imposes.

Where this fits

Part of the USB curriculum.