Skip to content
VLSI Mentor

USB · Module 5

High Speed (HS)

Not Full Speed with a faster clock — a second electrical world on the same conductors, entered by a transition. What operating in it commits an implementation to, why active mode must be centralised state, and the difference between supported, requested and active.

Chapters 5.1 and 5.2 described two variations on one design. Both use the same conductors the same way, are announced by the same mechanism, and differ in commitments that a single implementation absorbs as qualified decisions.

High Speed breaks that, and this chapter is about what breaking it costs.

It also builds the distinction this module exists to establish — between the mode a system supports, the mode it requested, and the mode that is actually active. Those are three different things, drivers and testbenches conflate them constantly, and a controller that conflates them is wrong in a way that is very hard to see.

1. A Second Electrical World

Chapter 3.8 §3 established the physical facts; here is what they mean as an envelope.

High Speed runs at a nominal 480 Mbit/s on the same D+/D- conductors — and almost nothing else about its electrical arrangement is shared with the modes before it.

The line is terminated. Each conductor is terminated to ground at nominally 45 Ω, presenting the cable's 90 Ω differential impedance. The earlier modes terminate nothing.

The swing is much smaller. Chapter 3.8 §3 explained why this is affordable only because the line is terminated and controlled — a small signal is workable once the things that would corrupt it are dealt with.

The pull-up is removed. This is the sharpest break. Chapters 5.1 and 5.2 are announced by a pull-up's position; High Speed operates without one, because against a 45 Ω termination it is electrically negligible and is an unwanted offset on a line that must present a matched impedance.

So the mode that announces itself by biasing and the mode that terminates the line cannot coexist on the same conductors at the same instant. They are alternatives, and moving between them is a transition rather than a setting change — which is precisely why Chapter 3.7's handshake exists at all.

2. Supported, Requested, Active

Now the distinction, because everything in §3 onward depends on it.

Supported is a static property of a component: the set of modes this PHY, this controller, this device is built to operate in. It is fixed at design time and is a property of one participant.

Requested is what software or a test asked for. It is an intention, and it may be unsatisfiable.

Active is what the connection is actually running, right now. It is an observed operating state, and per Chapter 4.7 §3 it is bounded by the intersection of every participant's capability, not by any one of them.

These are routinely conflated, and each conflation has a characteristic failure.

ConflationWhere it happensWhat goes wrong
supported = activedatasheets, procurementa capable part on an inadequate path underperforms and looks broken
requested = activedrivers, testbenchesthe system believes it is in a mode it is not, and every mode-dependent decision downstream is wrong
active inferred from software reportdebugginga driver's interpretation of controller status is treated as evidence about the physical layer

The second row is the dangerous one for engineers. A testbench that configures High Speed and then checks high-speed behaviour has assumed what it should have verified — and if establishment silently fell back, the test is now checking the wrong expectations against the wrong mode and may well pass.

The rule this module asks you to keep: requested is an input, active is an output, and only the output may be used to qualify behaviour.

3. Establishment, Seen From the Controller

Chapter 3.7 builds the handshake. From the controller's side it looks like this — and this view is what the RTL in §5 is written against.

The controller's view of speed-mode establishment. Software expresses a requested capability to the controller, which is an intention rather than a result. The PHY conducts the physical establishment sequence with the attached device, described in Chapter 3.7, and reports the resulting mode and a validity indication back to the controller. The controller latches that reported mode as the active mode, and all mode-dependent logic downstream is qualified by the active mode rather than by the request. The request and the active mode are separate signals that may disagree.Software requestan intention — may be unsatisfiableControllerlatches the reported outcomePHYconducts the sequence — Chapter 3.7Reported mode + validan OUTCOME, not a settingActive modewhat all mode-dependent logic usesrequested12
Figure 1 — from the controller's perspective the mode is an outcome reported to it, not a setting it applies. Everything mode-dependent must wait for the report.

Controller-side mode establishment — abstraction level: controller interface, not physical signalling

7 cycles
A controller-side view of speed-mode establishment. Software asserts a requested capability early and it remains asserted throughout. The PHY conducts its establishment sequence, during which its reported mode is not yet valid. When the sequence completes the PHY asserts mode-valid and reports the established mode. Only then does the controller latch the active mode and enable mode-dependent logic. The figure shows the controller interface rather than any physical signalling, and depicts no real durations.establishment running — reported mode NOT yet meaningfulestablishment running —reported mode NOT yetmeaningfulPHY asserts valid and reports the outcomePHY asserts valid andreports the outcomecontroller latches active mode; only now enablecontroller latches activemode; only now enablerequestedHSHSHSHSHSHSHSphy_busyphy_mode????HSHSHSphy_mode_validactive_modenonenonenonenonenoneHSHShs_logic_ent0t1t2t3t4t5t6
Figure 2 — mode-dependent logic must stay disabled until the PHY reports a valid outcome. Enabling on the request is the bug section 7 traces.

4. Centralise the Mode

Figure 2 implies an RTL architecture, and it is worth stating as a principle before the code.

If behaviour depends on the operating mode, the mode should be held in one place and consumed through a defined interface. The alternative — mode tests scattered through unrelated logic — produces three specific problems:

Inconsistent views. Two blocks testing the mode independently can disagree during a transition, because they sample at different moments.

No single point of validity. The mode is not yet known condition of Figure 2 has to be honoured everywhere, and a scattered design will honour it in most places.

Magic constants. Mode-dependent parameters — timing, sizes, limits — end up written as literals at each use, which is how a parameter gets updated in three of the four places that need it.

The architecture that avoids all three is a single block that owns the active mode, derives the mode-dependent configuration from it, and exposes both to everything else — with a validity signal that gates the lot.

5. Mode State and Configuration, as RTL

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// usb_mode_config
//
// Classification: SIMPLIFIED SYNTHESIZABLE TEACHING RTL. It implements the
// ARCHITECTURE of section 4 -- centralised active mode plus mode-derived
// configuration -- and no USB mechanism whatsoever.
//
// WHAT IT MODELS. The controller-side half of Figure 1: latching an
// established mode reported by the PHY, refusing to present a mode that was
// never established, and deriving mode-dependent configuration from the
// ACTIVE mode rather than from the request.
//
// WHAT IT DOES NOT MODEL. The establishment sequence itself (Chapter 3.7),
// any physical signalling, packets, transfers, or real USB timing values.
// The configuration fields below are ABSTRACT teaching parameters chosen to
// show the lookup pattern -- they are NOT USB timing numbers and must not
// be read as any specification's values.
// ─────────────────────────────────────────────────────────────────────────
package usb_mode_pkg;
  typedef enum logic [1:0] {
    MODE_NONE = 2'b00,   // nothing established -- the reset and failure state
    MODE_LS   = 2'b01,
    MODE_FS   = 2'b10,
    MODE_HS   = 2'b11
  } usb_mode_e;
endpackage

module usb_mode_config
  import usb_mode_pkg::*;
(
  input  logic       clk,
  input  logic       rst_n,

  // ── From the PHY: the OUTCOME of establishment ─────────────────────────
  input  usb_mode_e  phy_mode,
  // LEVEL, not a pulse: asserted for as long as a mode is established, as
  // drawn in Figure 2. This contract is load-bearing -- wiring a one-cycle
  // pulse here invalidates the mode on the very next cycle, because "the
  // PHY no longer asserts that a mode is established" is exactly what the
  // logic below is written to honour.
  input  logic       phy_mode_valid,
  // Link lost. Assumed MUTUALLY EXCLUSIVE with phy_mode_valid: a PHY does
  // not report an established mode on a detached link. Simulation of this
  // block with both asserted shows why the contract matters -- the detach
  // clears the mode and the still-asserted valid immediately re-establishes
  // it, which is the logic faithfully honouring contradictory inputs.
  input  logic       phy_detached,

  // ── What this controller is BUILT to support ───────────────────────────
  // A capability mask, not a request. A mode outside it must never become
  // active however enthusiastically the PHY reports it.
  input  logic [3:0] supported_mask,   // indexed by usb_mode_e

  // ── To the rest of the controller ──────────────────────────────────────
  output usb_mode_e  active_mode,
  output logic       active_valid,     // gate EVERYTHING mode-dependent
  output logic       mode_changed,     // 1-cycle pulse

  // Mode-derived configuration. Abstract teaching parameters -- see header.
  output logic [15:0] cfg_max_payload,
  output logic        cfg_allows_bulk_iso
);

  usb_mode_e active_q;
  logic      valid_q;

  // A reported mode is accepted only if this controller supports it. The
  // check is here, once, rather than at every consumer -- which is the
  // whole argument of section 4.
  logic report_acceptable;
  assign report_acceptable = phy_mode_valid
                          && (phy_mode != MODE_NONE)
                          && supported_mask[phy_mode];

  assign mode_changed = valid_q && (active_q != phy_mode) && report_acceptable;

  always_ff @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      active_q <= MODE_NONE;
      valid_q  <= 1'b0;
    end else if (phy_detached) begin
      // Detach invalidates. Leaving a stale active mode asserted after the
      // link is gone lets downstream logic keep operating on an assumption
      // that is no longer true -- see section 7.
      active_q <= MODE_NONE;
      valid_q  <= 1'b0;
    end else if (report_acceptable) begin
      active_q <= phy_mode;
      valid_q  <= 1'b1;
    end else if (!phy_mode_valid) begin
      // Establishment in progress or failed: no mode is active. We do NOT
      // fall back to a previous value, because "what it was last time" is
      // not evidence about what is established now.
      valid_q <= 1'b0;
    end
  end

  assign active_mode  = active_q;
  assign active_valid = valid_q;

  // ── Mode-derived configuration ─────────────────────────────────────────
  // One lookup, from the ACTIVE mode. Consumers take these outputs and hold
  // no mode knowledge of their own, so a parameter changes in one place.
  always_comb begin
    unique case (active_q)
      MODE_LS: begin cfg_max_payload = 16'd8;    cfg_allows_bulk_iso = 1'b0; end
      MODE_FS: begin cfg_max_payload = 16'd64;   cfg_allows_bulk_iso = 1'b1; end
      MODE_HS: begin cfg_max_payload = 16'd512;  cfg_allows_bulk_iso = 1'b1; end
      default: begin cfg_max_payload = 16'd0;    cfg_allows_bulk_iso = 1'b0; end
    endcase
  end

endmodule

Models. Centralised active-mode state, acceptance filtered by local capability, and mode-derived configuration.

Hardware implied. A mode register, a validity flag, a small acceptance decode, and a configuration lookup.

Assumptions. That phy_mode_valid is a level asserted for as long as a mode is established, not a pulse announcing that it became established — the distinction is load-bearing, and simulation of this block makes it obvious: a pulsed valid invalidates the mode one cycle later, which is the logic correctly honouring an input that was not what the designer meant. That phy_mode and phy_mode_valid are already synchronised into this domain — a mode value crossing from PHY timing is a multi-bit encoded crossing and is not safe to synchronise bit by bit, exactly as Chapter 3.1 §7 warned. That the supported mask is static. And that the PHY reports an outcome rather than being commanded.

Does not model. The establishment sequence, any physical behaviour, packets, transfers, or real USB timing. The configuration values are abstract teaching parameters, chosen only to show the lookup pattern.

Input contract worth stating. phy_detached and phy_mode_valid are assumed mutually exclusive. Driving both asserted is a contradiction — the PHY claiming simultaneously that the link is gone and that a mode is established — and the block resolves it by clearing on detach and then immediately re-latching from the still-valid report. That is not a defect in the logic; it is what honouring contradictory inputs looks like, and it is a good argument for asserting input contracts as well as output properties.

DV checks. That a mode outside supported_mask never becomes active; that active_valid is low whenever the PHY's report is not valid; that detach clears both; that configuration always corresponds to the registered active mode; and that no previous mode is resurrected after a failed establishment.

6. The Assertions

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// ─────────────────────────────────────────────────────────────────────────
// Assertions for usb_mode_config.
//
// Classification: ARCHITECTURAL TEACHING ASSERTIONS about mode state. They
// verify this abstraction's contract and make no USB compliance claim.
// ─────────────────────────────────────────────────────────────────────────

// M1 -- THE CENTRAL ONE. A mode this controller does not support must never
// become active, whatever the PHY reports. Catches a PHY/controller
// capability disagreement being resolved in favour of the wrong side.
property p_active_is_supported;
  @(posedge clk) disable iff (!rst_n)
    active_valid |-> supported_mask[active_mode];
endproperty
assert property (p_active_is_supported);

// M2 -- validity gates meaning. An established mode is never presented as
// valid while the PHY says its report is not. Catches the section 7 bug,
// where mode-dependent logic runs on a mode that was never established.
property p_valid_requires_phy_valid;
  @(posedge clk) disable iff (!rst_n)
    active_valid |-> $past(phy_mode_valid);
endproperty
assert property (p_valid_requires_phy_valid);

// M3 -- MODE_NONE is never an active mode. It is the absence of one, and
// treating it as a value lets a consumer's default branch execute as though
// a mode were established.
property p_none_is_never_active;
  @(posedge clk) disable iff (!rst_n)
    active_valid |-> (active_mode != MODE_NONE);
endproperty
assert property (p_none_is_never_active);

// M4 -- detach invalidates immediately. Stale mode outliving the link is
// how downstream logic keeps operating on an assumption that has expired.
property p_detach_invalidates;
  @(posedge clk) disable iff (!rst_n)
    phy_detached |=> !active_valid;
endproperty
assert property (p_detach_invalidates);

// M5 -- configuration always corresponds to the ACTIVE mode, never to a
// request and never to a previous mode. This is the property that makes
// the centralisation of section 4 worth doing.
property p_config_matches_active;
  @(posedge clk) disable iff (!rst_n)
    (active_valid && active_mode == MODE_LS) |-> !cfg_allows_bulk_iso;
endproperty
assert property (p_config_matches_active);

M2 is the one that protects the ordering of Figure 2, and M5 is the one that makes §4's architecture pay: it ties a mode's restriction — Low Speed forbidding bulk and isochronous, from Chapter 5.1 §3 — directly to the active mode, so a consumer cannot be given permission the mode does not grant.

7. The Bug: Enabling on the Request

A controller enables its high-speed datapath when software requests High Speed, rather than when the PHY reports it established. Against a high-speed-capable device everything works. Against a full-speed device, or when establishment fails, the controller operates high-speed logic on a link that is running something else.

Why does it pass testing? Because in the common case the request and the outcome agree. A test that configures High Speed and attaches a high-speed device exercises only the path where the bug is invisible.

What does it look like in the field? Malformed traffic, or no traffic, whenever the device is not high-speed capable — with the controller's own status cheerfully reporting High Speed because that is what was asked for. The reported mode and the actual mode disagree, and the report is the one most engineers consult first.

Why is it hard to diagnose? Because the evidence that would settle it lives at a different level than the symptom. The controller says High Speed; the physical layer is doing something else; and per Chapter 3.8 §4 no single instrument sees both.

Which assertion catches it? M2 — validity requires the PHY's report to have been valid. A controller enabling on the request has active_valid asserted while the PHY never said so.

And the general rule. Requested is an input; active is an output; only the output may qualify behaviour. That is §2's rule, and this is what it costs to break it.

8. Verification

Stimulus must include establishment failing. A device that does not support High Speed, and an establishment attempt that does not complete, are the cases that separate a correct controller from one that trusts the request.

Observation must read the active mode, from the controller's own reporting of the established outcome — never from what the test configured. An environment that records its own configuration as ground truth cannot detect a fallback.

Checking is mode-qualified. Expectations are selected by the observed mode, which means the reference model must itself be mode-aware and must follow the DUT's active mode rather than the test's intent.

Negative cases with defined correct outcomes: a PHY reporting a mode the controller does not support, which must be refused (M1); a report while validity is low, which must be ignored (M2); detach during operation, which must invalidate (M4); and establishment failing after a previous success, which must not resurrect the previous mode.

Representative coverage — crosses, not margins:

  • requested mode × established mode, including every disagreeing pair
  • active mode × mode-dependent configuration consistency
  • establishment success × failure × failure-after-previous-success
  • detach during each active mode

The requested × established cross is the important one, and it is empty in most environments because most environments only ever request what they know will be granted.

9. Common Misconceptions

10. Reason It Through

A device is expected to operate at High Speed. Software reports High Speed. Traffic is malformed. A protocol analyser shows signalling consistent with Full Speed.

What has the contradiction localised? The disagreement is between the software report and the physical observation, so the fault lies in the path between them — not at either end. Both observations are probably accurate about their own level.

What are the candidate explanations? Either establishment genuinely reached High Speed and the physical layer is misbehaving, or establishment did not reach High Speed and the controller believes otherwise. The analyser showing coherent full-speed signalling favours the second strongly: a broken high-speed link looks like errors, not like a different mode working correctly.

Which specific defect? The controller latching the request rather than the outcome — §7's bug exactly. Its signature is precisely this: software confidently reporting the requested mode while the link runs what was actually established.

What single observation confirms it? The PHY's own reported mode and validity, read at the controller boundary. If the PHY says Full Speed and the controller says High Speed, the controller is not consuming the PHY's report.

What if the PHY also says High Speed? Then the diagnosis inverts: establishment did succeed and the problem is physical — and Chapter 3.8's reasoning applies, with the expectation of a statistical rather than deterministic signature.

The general lesson. Two observations at different levels that disagree localise the fault to the transformation between them — and the level whose report is easiest to obtain is usually the one most likely to be repeating an assumption rather than reporting a measurement.

11. Understanding Check

12. Summary

High Speed runs at nominally 480 Mbit/s on the same conductors as the earlier modes and shares almost nothing else electrically: the line is terminated, the swing is much smaller, and the pull-up is removed. The announcing mode and the terminating mode cannot coexist, so moving between them is a transition, which is why Chapter 3.7's handshake exists.

The module's governing distinction is established here. Supported is a static property of one component; requested is an intention that may be unsatisfiable; active is an observed operating state bounded by every participant. Requested is an input, active is an output, and only the output may qualify behaviour.

That implies an architecture: centralise the active mode, gate everything with a validity signal, and derive mode-dependent configuration from the active mode in one place — avoiding inconsistent views during transitions, partial honouring of the not-yet-known condition, and scattered magic constants.

The teaching RTL adds the details that decide whether such a block works: accept only modes this controller supports, treat no mode as a distinct state rather than a value, invalidate on detach, and never resurrect a previous mode after a failed establishment.

The bug it prevents is enabling on the request, which passes testing because request and outcome usually agree, and in the field produces a controller confidently reporting a mode the link is not running — with the evidence to settle it living at a level the reporting engineer is not looking at.

13. What Comes Next

Three modes so far, all on the same two conductors. Low and Full Speed differ by qualified decisions; High Speed differs by being a second electrical world entered by a transition. In every case, one mode is active on the pair at a time.

Chapter 5.4 takes SuperSpeed, where that last assumption fails. SuperSpeed does not operate on those conductors at all — it runs on the additional pairs Chapter 4.3 described, which means it is not an alternative to the modes in this chapter but a parallel one. That forces a genuinely different question: when a mode lives on its own physical path, what does active mode even mean, and can two be active at once?

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.