Skip to content
VLSI Mentor

USB · Module 12

Handshake Stage

The stage whose transmitter changes with the token's direction — why the host answers an IN, why isochronous has no handshake stage, and the mutation that says every right thing while driving the wrong wire.

Chapter 12.2 moved data. Nobody has yet said whether it arrived.

That is this stage, and Chapter 11.3 already built the four packets it uses. What that chapter could not say is who transmits one — because the answer is not a property of the device or the host. It is a property of the token.

1. The Receiver Answers

One rule generates everything in this chapter:

Whoever received the data sends the handshake.

And the direction of the transaction decides who that is:

TransactionData flowsHandshake comes from
OUThost → devicethe device
SETUPhost → devicethe device
INdevice → hostthe host

Which produces a fact that surprises people who have only read Chapter 11.3:

On an IN transaction, the ACK comes from the host.

A device transmits data and then listens for an acknowledgement. It is the same relationship as an OUT, with the roles exchanged — and the entire reason Chapter 11.2's toggle exists on both sides rather than just the device's.

2. Isochronous Has No Handshake Stage

Not an omitted handshake. The stage does not exist.

Chapter 10.5 established that isochronous has no retry mechanism. A handshake's only purpose is to tell the sender whether to retry, so with retry impossible there is nothing a handshake could usefully say:

  • ACK would tell the sender its data arrived — which it can do nothing with.
  • NAK would ask for a retry that cannot happen.
  • STALL would report a permanent condition on a stream whose next packet is due in one interval regardless.

So an isochronous transaction is two stages: token, then data. The bus moves straight on.

And the saving is measurable. Chapter 10.5 §2 measured it from the other direction — the kernel's bus-time formulas differ by a fixed 283 ns per high-speed transaction between handshaked and isochronous traffic, with the comment “ISO is a bit less, no ACK.” This chapter is the structural reason that constant exists.

The design consequence is that the stage count is not fixed, which matters more than it sounds: a state machine that always expects three stages will wait for a handshake that is never coming on every isochronous transaction. §6's H1 is that defect.

3. The Bus Turns Around — Twice, and in Opposite Orders

A handshake stage means the bus changes owner, and the order differs between IN and OUT.

TokenDataHandshakeTurnarounds
OUThost driveshost drivesdevice drivesone, after the data
INhost drivesdevice driveshost drivestwo — before and after the data
ISO OUThost driveshost drives—none
ISO INhost drivesdevice drives—one, before the data

An IN transaction turns the bus around twice, and the device is responsible for both halves: it must start driving after the token and stop driving after its data, promptly enough that the host can drive the handshake slot.

A sequence diagram of four transactions showing bus ownership. In an OUT transaction the host drives the token and then the data, the bus turns around once, and the device drives the handshake. In an IN transaction the host drives the token, the bus turns around, the device drives the data, the bus turns around a second time, and the host drives the handshake — so the device must stop driving promptly enough for the host to use its slot. In an isochronous OUT transaction the host drives the token and the data and there is no handshake stage, so the bus never turns around. In an isochronous IN transaction the host drives the token, the bus turns around once, the device drives the data, and the transaction simply ends with no handshake.Who drives, and when it changesHostBus ownershipDeviceOUT token · hostdrivesDATA · host drives▸ turnaround ◂ACK · device drivesIN token · hostdrives▸ turnaround 1 ◂DATA · device drives▸ turnaround 2 —device MUST release◂ACK · host drivesISO OUT token, thenDATA · host drivesno handshake stage —no turnaround at all
Figure 1 — four transactions and their bus ownership. The OUT turns around once; the IN turns around twice, with the device responsible for releasing the bus before the host's handshake slot; the isochronous OUT never turns around at all. The shaded band under each row is who is driving.

4. Silence Still Costs a Stage

Chapter 11.3 §3 established that a corrupted payload is answered with nothing. It is worth being precise about what that means at the stage level, because it is easy to conclude the stage is skipped.

It is not. The handshake stage still happens; the receiver still owns the slot; the bus still turns around. The receiver simply declines to transmit in a slot that belongs to it.

Three consequences, and the third is a design obligation:

  • The sender still waits. It does not know the data was corrupted, so it waits the full timeout — Chapter 12.5.
  • The bus is still busy for the duration, which is why the timeout is short.
  • The device must still release the bus on an IN even though the handshake it is waiting for never comes. Silence does not suspend the ownership rules, and a design that only releases when it sees a handshake will hold the bus through every corrupted transaction.

§5's RTL makes this visible by separating who owns the slot from who transmits in it — two outputs rather than one, because they differ on exactly this case.

5. The Handshake Stage Controller, as RTL

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// usb_handshake_stage
//
// Classification: SIMPLIFIED SYNTHESIZABLE TEACHING RTL. It answers three
// questions about the third stage: does it exist, who transmits in it, and
// who is driving the wire.
//
// WHAT IT MODELS. Sections 1 to 4 -- the receiver answers, isochronous has
// no such stage, the turnaround, and the separation of slot OWNERSHIP from
// slot USE.
//
// WHAT IT DOES NOT MODEL. WHICH handshake to send -- ACK, NAK, STALL, NYET
// or silence is Chapter 11.3's block, and this one deliberately does not
// duplicate it; the packet's bits or framing (Module 14); the timeout that
// bounds the wait (Chapter 12.5); and the stage sequencing that invokes
// this one (Chapter 12.4).
//
// ── WHY `device_sends_hs` AND `device_drives_next` ARE SEPARATE ─────────
// They differ on exactly one case and it is section 4's: a corrupted
// payload means the device OWNS the handshake slot and TRANSMITS NOTHING in
// it. Folding them into one signal forces a choice between two wrong
// answers -- either the device transmits into a slot it should leave empty,
// or it stops owning a slot it must still release the bus for. Section 6's
// H5 measures what happens when ownership follows the wrong rule.
// ─────────────────────────────────────────────────────────────────────────
module usb_handshake_stage #(
  // Chapter 10.1's bmAttributes[1:0] encoding, verified against ch9.h.
  parameter int unsigned XT_CONTROL = 0,
  parameter int unsigned XT_ISOC    = 1,
  parameter int unsigned XT_BULK    = 2,
  parameter int unsigned XT_INTR    = 3
)(
  input  logic       clk,
  input  logic       rst_n,
  input  logic       bus_reset,

  // Chapter 12.1's captured context. Note that the transfer TYPE is part of
  // it: this stage's very existence depends on it, so it cannot be looked up
  // later from the endpoint any more than the direction could.
  input  logic       txn_open,
  input  logic       ctx_is_in,
  input  logic [1:0] ctx_xfer_type,

  input  logic       data_stage_done,
  input  logic       data_ok,          // Chapter 11.6's verdict

  output logic       hs_stage_exists,
  output logic       device_sends_hs,
  output logic       host_sends_hs,
  output logic       bus_turnaround,
  output logic       device_drives_next
);

  logic is_iso;
  assign is_iso = (ctx_xfer_type == XT_ISOC[1:0]);

  // SECTION 2. The stage does not exist for isochronous -- it is not skipped
  // or omitted, there is no third stage. A sequencer that assumes three
  // stages waits forever here, which is section 6's H1.
  assign hs_stage_exists = txn_open && data_stage_done && !is_iso;

  // SECTION 1. Whoever received the data answers.
  assign device_sends_hs = hs_stage_exists && !ctx_is_in;
  assign host_sends_hs   = hs_stage_exists &&  ctx_is_in;

  // SECTION 4. A completed data stage always costs a turnaround, INCLUDING
  // when the handshake will be silence: the receiver must stop driving
  // before the sender can begin timing out.
  assign bus_turnaround = txn_open && data_stage_done;

  // SECTION 4's obligation. We drive the handshake slot only when it is ours
  // AND we have something to put in it. On an IN we must NOT drive -- we
  // have just finished transmitting and the slot belongs to the host.
  assign device_drives_next = device_sends_hs && data_ok;

endmodule

What it models. Whether a third stage exists, which end transmits in it, and whether this device drives the wire.

Engineering reason. Because the transmitter changes with the token's direction, and a device that gets it wrong contends the bus rather than merely answering wrongly.

Inputs. The captured context including the transfer type, and the data stage's completion and integrity.

State retained. None. Every output is a function of the context and this stage's outcome.

Outputs. Stage existence, the two transmitter indications, the turnaround, and the drive enable.

Hardware implied. A handful of gates and one 2-bit comparator.

Reset behaviour. Nothing to reset.

Assumptions. That ctx_xfer_type was captured with the rest of the context (Chapter 12.1) rather than looked up later; that data_stage_done marks the end of the data stage and not the end of a packet within it; and that data_ok refers to this stage's data.

Omissions. Which handshake to send, the packet, the timeout and the sequencing — in the header.

What DV should verify. That an isochronous transaction never produces a handshake stage; that exactly one end is the transmitter when a stage exists; that the host is that end on an IN; that the device never drives during an IN handshake slot; that it does drive on an OUT with good data; and that a completed data stage always signals a turnaround, silence included.

Who answers, and who drives

8 cycles
A waveform of the handshake stage controller over eight situations. In the first, an OUT transaction's data stage is still in progress, so no handshake stage exists and the device does not drive. In the second the OUT data stage is done, so the device is the answerer and drives the slot. In the third an IN transaction's data stage is in progress. In the fourth the IN data stage is done, so the host is the answerer and the device does not drive, having just released the bus. In the fifth an OUT data stage completed with a failed check, so the device still owns the handshake slot but does not drive it, transmitting silence. In the sixth and seventh, isochronous OUT and IN transactions complete their data stages and no handshake stage exists at all, so nobody answers and the device does not drive. In the eighth a SETUP transaction's data stage completes and the device answers and drives, because a SETUP is host-to-device like an OUT.IN: the HOST sends the ACKIN: the HOST sends the ACKowns the slot, drives nothingowns the slot, drivesnothingisochronous — no third stageisochronous — no thirdstageSETUP is host-to-device, like OUTSETUP is host-to-device,like OUTsituationOUT dataOUT doneIN dataIN doneOUT badISO OUTISO INSETUPdirectionOUTOUTININOUTOUTINOUTdata_okanswerernonedevicenoneHOSTdeviceno stageno stagedeviceturnarounddev_drivest0t1t2t3t4t5t6t7
Figure 2 — eight stage outcomes, every column taken from a simulation of the block above. Column 4 is §4's case: the device owns the handshake slot and does not drive it, because the data was corrupt. Columns 5 and 6 are isochronous, where the stage does not exist at all and the bus simply moves on.

6. Mutation Test

Five mutations over 64 stimuli — all 32 input combinations, twice: once with good data and once with a failed check. Exhaustive is affordable because the block is combinational with five inputs.

The unmutated block answered 6 device, 6 host, 4 silence, produced no handshake stage on any of the 4 isochronous cases, and reported 0 errors of every kind.

who wrongiso given a stageturnaround misseddrives during an INfails to drive on OUT
golden00000
H1 isochronous gets a stage44000
H2 device always answers120030
H3 transmitter inverted240033
H4 no turnaround signalled001600
H5 device keeps the bus on an IN00060

H1 — give isochronous a handshake stage

Measured: all 4 isochronous transactions given a stage that does not exist.

§2's rule removed. The consequence is a wait, not a wrong packet: the sequencer expects a third stage on a transaction that has two, and Chapter 12.5's timeout is what eventually releases it.

And the cost is per-transaction on the type that can least afford it. Chapter 10.5: an isochronous endpoint's slot is a frame, and a device that spends every slot waiting out a timeout has less time for the next one — so a latency defect becomes a throughput defect on a stream with a deadline.

H2 — the device always answers

Measured: 12 wrong transmitters, and 3 cases where the device drove the bus during an IN handshake slot.

The device answers its own IN transactions. It has just transmitted data and now transmits again into a slot the host owns — §3's contention, arriving as the direct consequence of the simplest possible misreading of §1.

This is the mutation an engineer writes by not asking the question. The device sends handshakes is true two-thirds of the time and is not the rule.

H3 — invert the transmitter

Measured: 24 wrong — the worst of the five — plus 3 contentions and 3 failures to answer an OUT.

Both directions wrong at once. The device stays silent on OUTs, so the host times out and retransmits every OUT packet forever, and it drives on INs, so those contend.

Loud, total, and found by the first transaction of any test — included as the contrast case for H5.

H4 — never signal a turnaround

Measured: 16 missed turnarounds, and every other output correct.

The protocol decisions are all right and the bus-ownership transition is never announced. Whatever consumes this signal — the physical-layer driver enable — never changes direction, so the device either holds the bus permanently or never takes it, depending on which way its default sits.

H5 — keep driving the bus during an IN

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
assign device_drives_next = device_sends_hs || ctx_is_in;   // MUTANT H5

Measured: 6 contentions — and every other check clean. Zero. The transmitter is named correctly, the stage exists exactly when it should, the turnaround is signalled, isochronous is handled right.

§3's callout, realised. The device says all the right things and does not let go of the wire.

7. The Assertions

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// Classification: TEACHING ASSERTIONS about the handshake stage.
// S-properties concern the stage's EXISTENCE; W who transmits;
// B the BUS -- and B2 is the only property in Module 12 that is about
// electricity rather than about protocol.
// ─────────────────────────────────────────────────────────────────────────

// S1 -- ISOCHRONOUS HAS NO HANDSHAKE STAGE. Section 2, and section 6's H1.
property p_no_iso_handshake;
  @(posedge clk) disable iff (!rst_n)
    (ctx_xfer_type == XT_ISOC[1:0]) |-> !hs_stage_exists;
endproperty
assert property (p_no_iso_handshake);

// S2 -- AND EVERY OTHER TYPE HAS ONE. Without this, S1 is satisfied by a
// design with no handshake stage at all.
property p_nonzero_types_have_one;
  @(posedge clk) disable iff (!rst_n)
    (txn_open && data_stage_done && (ctx_xfer_type != XT_ISOC[1:0]))
      |-> hs_stage_exists;
endproperty
assert property (p_nonzero_types_have_one);

// W1 -- EXACTLY ONE END TRANSMITS. Catches both "neither" and "both",
// and "both" is the one that would put two handshakes on the wire.
property p_exactly_one_transmitter;
  @(posedge clk) disable iff (!rst_n)
    hs_stage_exists |-> (device_sends_hs ^ host_sends_hs);
endproperty
assert property (p_exactly_one_transmitter);

// W2 -- AND IT IS THE RECEIVER. Section 1, stated as an equivalence against
// the DIRECTION rather than against the design's own term -- Chapter 11.3
// section 8's rule, applied.
property p_receiver_answers;
  @(posedge clk) disable iff (!rst_n)
    hs_stage_exists |-> (device_sends_hs == !ctx_is_in);
endproperty
assert property (p_receiver_answers);

// B1 -- A COMPLETED DATA STAGE ALWAYS COSTS A TURNAROUND, silence included.
// Section 4: the receiver must stop driving before the sender can time out,
// so the turnaround does not depend on anything being transmitted.
property p_turnaround_always;
  @(posedge clk) disable iff (!rst_n)
    (txn_open && data_stage_done) |-> bus_turnaround;
endproperty
assert property (p_turnaround_always);

// B2 -- THE DEVICE NEVER DRIVES A SLOT IT DOES NOT OWN. The only property
// here about ELECTRICAL behaviour, and the only one that catches section
// 6's H5 -- whose every protocol output is correct.
//
// Note what it is NOT stated in terms of: not packets, not handshake types,
// not decisions. A bus-contention obligation has to be written in the
// language of who is driving, because that is the language it is violated
// in -- and it is a language no protocol trace speaks.
property p_no_contention_on_in;
  @(posedge clk) disable iff (!rst_n)
    (hs_stage_exists && ctx_is_in) |-> !device_drives_next;
endproperty
assert property (p_no_contention_on_in);

// B3 -- AND IT DOES DRIVE WHEN THE SLOT IS ITS OWN AND IT HAS SOMETHING TO
// SAY. The other half: without it, a device that never drives satisfies B2.
property p_drives_own_slot;
  @(posedge clk) disable iff (!rst_n)
    (device_sends_hs && data_ok) |-> device_drives_next;
endproperty
assert property (p_drives_own_slot);

// B4 -- BUT NOT WHEN IT HAS NOTHING TO SAY. Section 4: owning the slot and
// transmitting in it are different, and this is the case that separates them.
property p_silence_does_not_drive;
  @(posedge clk) disable iff (!rst_n)
    (device_sends_hs && !data_ok) |-> !device_drives_next;
endproperty
assert property (p_silence_does_not_drive);

B2 is the property this chapter exists for, and its language is the lesson. Every other assertion in Module 12 constrains a decision — which packet, which end, which stage. B2 constrains a wire.

An obligation is only checkable in the language it can be violated in. H5 violates nothing about packets, so no property about packets can catch it.

B2, B3 and B4 have to be written as a trio, and the reason is §4: ownership and transmission differ on exactly one case. B2 alone is satisfied by a device that never drives; B3 alone by one that always does; B4 is the case that exists only because silence is a response, and without it a design that transmits into a slot it should leave empty passes both others.

8. Verification

This chapter's commit point is the right end answered, and only one end was driving.

Stimulus. All 32 combinations of the five inputs, exhaustively — twice, once with data_ok high and once low, because §4's separation of ownership from transmission is visible only in the second pass.

Observation. All five outputs, plus a histogram of answerers — device, host, silence, no-stage. The histogram is what makes §6's table readable: H2 shows as host = 0, which is a stronger signal than a count that merely shifted.

Reference model. Three sentences from §§1–2 evaluated directly: the stage exists unless isochronous; the device answers unless IN; the device drives only its own slot and only with something to say. Its independence comes from being that short — each expectation is a specification sentence rather than a re-derivation.

Coverage — crosses:

  • transfer type (control / isochronous / bulk / interrupt) × direction × data_stage_done
  • data_ok × device_sends_hs — the cell where ownership and transmission differ
  • txn_open low with every other combination — nothing may happen outside a transaction
  • direction × device_drives_next — all four, with two of them forbidden

Negative cases with defined outcomes: no handshake stage on isochronous; never two transmitters and never none when a stage exists; the device never drives during an IN; it never fails to drive its own slot with good data; and it never drives its own slot with bad data.

9. Debugging: the IN Transfer That Corrupts the Next Transaction

A device's IN endpoint returns correct data, verified byte for byte. But the transaction after every IN is unreliable — sometimes the next token is missed, sometimes another device on the bus reports errors. The device's own OUT endpoints are flawless.

What does the next transaction tell you? That the fault is at a boundary, not inside a transaction. Whatever is wrong happens at the end of the IN and lands on whatever comes next.

What happens at the end of an IN that does not happen at the end of an OUT? §3: the device stops driving. On an OUT it never started; on an IN it must release the bus so the host can send the handshake.

So what would too-late release produce? Contention during the host's handshake slot — and because the contention is electrical, the corruption extends past the slot until the device actually lets go. Whatever the host sends next is damaged.

Why do other devices report errors? Because the bus is shared. A device contending it corrupts traffic that has nothing to do with it — which is why the symptom is reported by innocent parties, the same pattern as Chapter 12.1 §11's promiscuous receiver.

What would a protocol analyser show? Correct IN data, then a damaged or missing handshake, then a damaged next packet. It will not show the cause, because two drivers fighting decodes to nothing — §6's callout. The trace shows an absence and an unexplained error.

What is the decisive observation? Not the decode. The differential pair, with an oscilloscope, during the window after the device's last data bit. Contention has a characteristic signature — intermediate voltages that are neither of the two valid states — and it is unmistakable once looked at.

What if the scope is clean? Then the release is fine and the fault is timing rather than contention: the device releases correctly but too late, leaving too little of the turnaround window — Chapter 12.5. Same symptom, adjacent cause, and the scope distinguishes them because one shows a fight and the other shows a late edge.

The signature to keep: a fault that lands on the transaction after an IN, and on other devices, is a bus-release fault — and it is diagnosed with a scope, not a decoder.

10. Common Misconceptions

11. Reason It Through

A device controller is being ported from full speed to high speed. On the faster link, IN transfers to one particular endpoint fail intermittently — more often when the payload is large. Small IN payloads and all OUT transfers are unaffected.

What is different about a large IN payload? It occupies the bus for longer — but length alone should not matter, because the protocol is the same at any length.

What does change with length? When the transmission ends. A longer payload means the device's last data bit is later, and therefore its bus release is later — relative to the start of the transaction, though not relative to its own last bit.

Does that matter? Only if something is measuring from the wrong reference. A release timed from the token rather than from the last data bit would be correct for a fixed payload length and progressively wrong as the payload grows.

Why would high speed expose it? Because the turnaround window scales with the bit rate. Chapter 12.5: a window measured in bit times is forty times shorter in absolute terms at high speed than at full speed, so a fixed-delay implementation that had margin before has none now.

Which of the two is more likely? The second, and for a reason worth generalising: the port changed the bit rate and not the code. A defect that appears only after a speed change is usually a fixed delay that was always wrong and always had margin.

How would you distinguish them? Vary the payload length at full speed. If the failure appears there too at some length, it is the reference point; if full speed is clean at every length, it is the fixed delay. One experiment, and it does not need a scope.

And the transferable point: a quantity expressed in bit times is not a quantity expressed in nanoseconds, and every design that hard-codes the second has an undocumented dependency on the first. Chapter 12.2 §11 found the same error in a different field — wMaxPacketSize treated as a constant — and the shape is identical: a value that varies with the link treated as a property of the design.

12. Understanding Check

13. Summary

Whoever received the data sends the handshake — so on an OUT or SETUP the device answers, and on an IN the host does. A handshake carries the one fact that could not travel with the data, because it is about the data's arrival.

Isochronous has no handshake stage at all. Not a skipped one: with retry impossible, nothing a handshake could say is actionable — and Chapter 10.5's measured 283 ns per high-speed transaction is this structural fact showing up in the kernel's bandwidth arithmetic.

An OUT turns the bus around once; an IN turns it around twice, and the device owns both halves of the second case.

And silence still costs a stage. A corrupted payload means the receiver owns the handshake slot and transmits nothing in it — which is why ownership and transmission are separate signals in §5, differing on exactly that case.

§6 measured five mutations over all 32 input combinations, twice. Four are protocol errors of varying loudness. The fifth is not a protocol error at all:

H5 produced zero wrong protocol outputs and contended the bus six times. The right end was named, the stage existed when it should, the turnaround was signalled — and the device did not let go of the wire.

Protocol correctness and electrical correctness are different properties, and only one of them is in a trace: two drivers fighting decode to nothing, so an analyser records an absence and an unexplained error in the next transaction, reported by other devices.

§8 therefore adds a distinct shape to the catalogue, and it is not Chapter 12.2's. There the bench could not generate the input; here it generated it six times and had nothing to observe it with.

When a defect can only be seen in the physical layer, a protocol-level bench will report success no matter how exhaustive it is.

The remedy is one signal and one property — a modelled drive enable, and an assertion that at most one end asserts it — and nothing in the packet-level specification suggests either is needed.

14. What Comes Next

Three stages, each described in isolation. Chapter 12.4 puts them in order — and the order is where the interesting failures live, because a state machine that walks token → data → handshake has to answer questions none of the three chapters could: what happens when a stage arrives that does not belong to the current one, how a transaction ends when the next stage simply never comes, and what a device believes about a transaction the host has already abandoned.

That last one is the module's hardest problem: the two ends maintain separate beliefs about the same transaction, and nothing on the wire reconciles them.

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.