⚠ LLM-Generated Documentation: This documentation was created using a Large Language Model (LLM) and may contain errors, omissions, or inaccuracies. Always verify critical details against the source code and test suite before relying on this content for design or implementation decisions.

LiteUSB — Architecture & Module Reference

A complete USB 2.0 device stack for FPGAs, ported from LUNA (Amaranth HDL) to Migen / LiteX. Supports High Speed (480 Mbps) and Full Speed (12 Mbps) operation with Control, Bulk, Interrupt, and Isochronous endpoints. Tested and verified on Terasic DECA (MAX10 + TUSB1210 ULPI PHY).

Table of Contents

1. Architecture Overview

LiteUSB is organized as a layered protocol stack. Data flows upward from the physical USB bus (ULPI/UTMI PHY signals) through packet detection, endpoint routing, transfer management, and finally to application-level streams.

┌─────────────────────────────────────────────────────────┐
│                   Application Logic                     │
│   (CDC-ACM serial, bulk loopback, vendor requests)      │
├─────────────────────────────────────────────────────────┤
│                    Stream Interfaces                    │
│         USBInStreamInterface / USBOutStreamInterface    │
├───────────────┬──────────────────┬──────────────────────┤
│   Endpoints   │  Control  (EP0)  │  Transfer Managers   │
│               │  Bulk / Interrupt│  (Double‑buffered IN)│
│               │  Isochronous     │                      │
├───────────────┴──────────────────┴──────────────────────┤
│               USBEndpointMultiplexer                    │
│   (Priority-encoder OR-tree: routes tokens to endpoints)│
├─────────────────────────────────────────────────────────┤
│                 USB2Device / USBDevice                  │
│    Token detection, handshake generation, CRC, timing   │
├─────────────────────────────────────────────────────────┤
│                  USBResetSequencer                      │
│     Bus reset, HS chirp handshake, suspend/resume       │
├─────────────────────────────────────────────────────────┤
│                    PHY Interface                        │
│    ULPI (8‑bit, 60 MHz)  │  UTMI (simulation)           │
├─────────────────────────────────────────────────────────┤
│              Physical USB Bus (D+/D−)                   │
└─────────────────────────────────────────────────────────┘
USB 2.0 Spec §4.2: "USB defines several layers of the protocol: the physical layer (signaling), the link layer (packet framing, error detection), the protocol layer (endpoint communication), and the application layer (device-specific functions)." — USB in a Nutshell

1.1 Clock Domains

DomainFrequencyPurpose
sysPlatform-dependentMigen default; application logic
sync120 MHz (typical)General synchronous logic
usb60 MHzAll USB protocol logic (ULPI driven)
fastOptionalHigh-speed application processing
Important: Almost all gateware modules are renamed into the usb clock domain via ClockDomainsRenamer("usb"). The PHY clock loop requires with_reset=False on the USB clock domain — otherwise the PLL-lock-gated reset deadlocks: the PHY needs the clock to start, but the clock won't start until it sees the PHY's output, which won't start without the clock.

2. PHY Layer

LiteUSB supports three PHY interfaces for connecting to the physical USB bus:

2.1 UTMI Interface

liteusb.gateware.interface.utmi.UTMIInterface

The UTMI (USB 2.0 Transceiver Macrocell Interface) is a parallel 8-bit interface standardized in the USB 2.0 specification. It is primarily used in simulation and as an internal abstraction layer.

SignalWidthDirectionDescription
rx_data8PHY → DeviceReceive data bus
rx_active1PHY → DeviceReceive in progress
rx_valid1PHY → DeviceReceive data valid
tx_data8Device → PHYTransmit data bus
tx_valid1Device → PHYTransmit data valid
tx_ready1PHY → DevicePHY ready to accept transmit
line_state2PHY → DeviceD+/D- state (00=SE0, 01=J, 10=K)
op_mode2Device → PHYOperating mode
xcvr_select2Device → PHYTransceiver speed
term_select1Device → PHYTermination selection

2.2 ULPI Interface

liteusb.gateware.interface.ulpi.ULPIInterface

ULPI (UTMI+ Low Pin Interface) reduces the UTMI pin count from ~30 to 12 by serializing control and status onto the 8-bit data bus. This is the interface used for external PHY chips like the TUSB1210.

SignalWidthDescription
data8 (bidirectional)Multiplexed data/command/status
clk160 MHz clock from PHY
dir1PHY → FPGA: bus direction (1=PHY drives)
nxt1PHY → FPGA: data accepted / next byte
stp1FPGA → PHY: stop / end of packet
rst1FPGA → PHY: reset

2.3 ULPI ↔ UTMI Translation

liteusb.gateware.interface.ulpi.UTMITranslator

The UTMITranslator is the bridge that converts between the ULPI 12-pin bus and the internal UTMI record used by all downstream gateware. It contains four sub-modules:

Sub-moduleFunction
ULPIRegisterWindowULPI register read/write protocol (REG_WRITE=0x80, REG_READ=0xC0)
ULPIRxEventDecoderDecodes RxCmd bytes into line_state, vbus_valid, rx_active, rx_error
ULPIControlTranslatorConverts UTMI control signals into sequenced ULPI register writes
ULPITransmitTranslatorTranslates UTMI tx_valid/tx_data into ULPI TRANSMIT_COMMAND + data + STP

3. Packet Layer

liteusb.gateware.usb.usb2.packet

The packet layer handles USB packet framing as defined in USB 2.0 §8. It contains 10 classes that collectively detect, deserialize, generate, and serialize all USB packet types.

USB 2.0 Spec §8.1: "A packet is a collection of fields organized into a defined group. Each packet begins with a synchronization (SYNC) field, followed by a Packet Identifier (PID), and optionally, an address, endpoint, frame number, data, and CRC field." — USB in a Nutshell §3

3.1 USBTokenDetector

Detects IN, OUT, SETUP, and SOF tokens on the UTMI receive data stream. The FSM transitions through IDLE → READ_PID → READ_TOKEN_0 → READ_TOKEN_1 → TOKEN_COMPLETE → IDLE. It also performs address matching — tokens addressed to other devices are silently ignored.

USBTokenDetector FSM

Source: USBTokenDetector in packet.py:259

3.2 USBHandshakeDetector

Detects handshake PID bytes (ACK, NAK, STALL, NYET) on the UTMI bus. FSM: IDLE → READ_PID → AWAIT_COMPLETION → IDLE. Since handshake packets contain only a PID byte, detection is a single-cycle observation.

USBHandshakeDetector FSM

Source: USBHandshakeDetector in packet.py:453

3.3 USBDataPacketCRC

Implements the CRC-16 polynomial used in USB data packets. Polynomial: x^16 + x^15 + x^2 + 1 (0x8005, reflected form 0xA001). Operates continuously on the data stream and provides separate CRCs for each endpoint through the DataCRCInterface.

3.4 USBDataPacketReceiver

Receives DATA0/DATA1/DATA2/MDATA packets from the UTMI rx bus, verifies the CRC-16, and produces a USBOutStreamInterface. The receiver strips the PID and CRC bytes — only the payload reaches the stream.

USBDataPacketReceiver FSM

Source: USBDataPacketReceiver in packet.py:673

3.5 USBDataPacketDeserializer

High-level wrapper around USBDataPacketReceiver that captures data packets into a byte array (packet[]). Also validates CRC — invalid packets set new_packet=0. Used by the SETUP decoder to capture 8-byte setup packets.

3.6 USBDataPacketGenerator

Generates complete USB data packets from a USBInStreamInterface. Produces: PID byte (DATA0/DATA1/DATA2/MDATA) → payload bytes → CRC-16 (2 bytes, LSB first). The FSM advances on tx.ready handshake.

USBDataPacketGenerator FSM

Source: USBDataPacketGenerator in packet.py:1055

3.7 USBHandshakeGenerator

Generates handshake packets (ACK, NAK, STALL) on the UTMI output. FSM: IDLE → TRANSMIT. Strobe issue_ack (or equivalent) to send a single PID byte with proper tx_valid/tx_ready handshake.

USBHandshakeGenerator FSM

Source: USBHandshakeGenerator in packet.py:1219

3.8 USBInterpacketTimer

Speed-aware interpacket gap timer. Monitors interpacket delays mandated by the USB spec:

USB 2.0 Spec §7.1.18: "The hub or host controller must wait at least the interpacket delay before transmitting. The interpacket delay is measured from the last bit of the EOP to the first bit of the next SYNC field."

4. Device Layer

4.1 USBResetSequencer

liteusb.gateware.usb.usb2.reset

A 14-state FSM that manages the complete USB bus state lifecycle: bus reset detection, high-speed chirp handshake, suspend/resume, and forced disconnect.

USBResetSequencer FSM

Source: USBResetSequencer in reset.py:53

USB 2.0 Spec §7.1.7.5 — Reset: "A USB device shall recognize a reset when both D+ and D- are driven to SE0 for at least 2.5 μs. ... After a reset, the device shall be capable of responding to the high-speed chirp handshake."

4.2 USBDevice / USB2Device

liteusb.gateware.usb.usb2.device.USBDevice (also re-exported from liteusb.gateware.usb.device)

The top-level USB device module. Instantiates all packet-layer submodules and the reset sequencer, then connects them to the internal endpoint collection. Maintains device state registers:

RegisterWidthDescription
address7USB device address (assigned via SET_ADDRESS)
configuration8Current configuration number
frame_number11Most recent SOF frame number
connect1Assert to connect pull-up (D+ for FS, terminate for HS)
USB 2.0 Spec §9.1: "All USB devices support a common set of operations through the Default Control Pipe (endpoint zero). Endpoint zero is always enabled once a device has been powered, has been reset, and has received a SET_ADDRESS command."

5. Endpoint Layer

5.1 EndpointInterface

liteusb.gateware.usb.usb2.endpoint.EndpointInterface

A per-endpoint record that bundles all signals needed for endpoint operation: tokenizer (address + direction matching), RX/TX streams, handshake I/O, speed configuration, address/config change notifications, data CRC interface, and interpacket timer connection.

5.2 USBEndpointMultiplexer

liteusb.gateware.usb.usb2.endpoint.USBEndpointMultiplexer

A priority-encoder OR-tree multiplexer that routes shared packet-layer resources (CRC, timer, tokenizer, handshakes, RX) to the appropriate endpoint. Each endpoint's interface.claim signal forms a priority chain — the first matching endpoint wins. This ensures that EP0 always has the highest priority.

5.3 USBControlEndpoint (EP0)

liteusb.gateware.usb.usb2.control.USBControlEndpoint

The mandatory control endpoint (endpoint 0) handles USB enumeration. Contains a 5-state FSM for SETUP / DATA / STATUS phases, plus a USBSetupDecoder and USBRequestHandlerMultiplexer.

USBControlEndpoint FSM

Source: USBControlEndpoint in control.py:24

USB 2.0 Spec §5.5: "Control transfers have two or three stages: Setup, Data (optional), and Status. The Setup stage always uses a DATA0 PID. The direction of the Data stage is indicated in the Setup packet. The Status stage is always in the opposite direction."

6. Transfer Layer

6.1 USBInTransferManager

liteusb.gateware.usb.usb2.transfer.USBInTransferManager

Double-buffered IN transfer sequencer. Converts an arbitrary-length application stream into packet-sized chunks on the USB bus.

USBInTransferManager FSM

Source: USBInTransferManager in transfer.py:22

Key features:

USB 2.0 Spec §5.3.2 — Data Toggle: "The data toggle synchronizes between the host and the device. The data toggle is toggled only when the receiver is able to accept data and the receiver returns an ACK handshake."
USB 2.0 Spec §5.5.3 — ZLP: "When all of the data structure is returned to the host, the function shall indicate that the Data stage is completed by returning a packet shorter than the maximum packet size. ... If the data being returned is an exact multiple of the pipe's maximum packet size, the function must return a zero-length packet."

7. Descriptor Layer

7.1 USBDescriptorStreamGenerator

liteusb.gateware.usb.usb2.descriptor.USBDescriptorStreamGenerator

Serves USB descriptors (device, configuration, string, etc.) from a ROM (Migen Memory primitive) initialized at build time. Outputs a USBInStreamInterface with first/last packet framing.

USBDescriptorStreamGenerator FSM

Source: USBDescriptorStreamGenerator in descriptor.py:19

Parameters: start_position (byte offset), max_length (truncation). Supports sub-descriptor selection via offset signal.

8. Request Layer

8.1 SetupPacket

liteusb.gateware.usb.request.interface.SetupPacket

A Record capturing the parsed 8-byte SETUP packet from a control transfer:

FieldWidthOffsetDescription
recipient5bmRequestType[0:4]Device, Interface, Endpoint, or Other
type2bmRequestType[5:6]Standard, Class, or Vendor
is_in_request1bmRequestType[7]Direction: 0=Host→Device, 1=Device→Host
request8bRequestSpecific request code
value16wValueParameter
index16wIndexParameter
length16wLengthData stage length
USB 2.0 Spec §9.3: "All USB devices respond to requests from the host on the device's Default Control Pipe. These requests are made using control transfers. The request and the request's parameters are sent to the device in the Setup packet."

8.2 USBSetupDecoder

liteusb.gateware.usb.usb2.request.USBSetupDecoder

Detects the SETUP PID, uses the USBDataPacketDeserializer to capture the 8-byte setup packet, and translates it into a SetupPacket record. Handles interpacket delay (2.5 μs at FS) for ACK timing.

8.3 StandardRequestHandler

liteusb.gateware.usb.request.standard.StandardRequestHandler

Implements all standard USB device requests required for enumeration:

9. Stream Utilities

9.1 USBInStreamInterface / USBOutStreamInterface

liteusb.gateware.usb.stream

Thin Record wrappers that bridge between the UTMI bus signals and application-level stream logic.

RecordSignalsConnects to
USBInStreamInterfacevalid, payload, readyUTMI tx_valid, tx_data, tx_ready
USBOutStreamInterfacevalid, next, payloadUTMI rx_active, rx_valid, rx_data

9.2 USBOutStreamBoundaryDetector

Because UTMI does not signal packet boundaries, this module injects a 2-byte pipeline delay to detect first and last byte positions within a received data stream.

USBOutStreamBoundaryDetector FSM

Source: USBOutStreamBoundaryDetector in stream.py:102

10. Test Suite

LiteUSB's test suite comprises 48 tests across 12 test modules, all passing. Tests use migen.sim.run_simulation with the UTMI interface as a test harness — the host controller is modeled as a Python generator that drives utmi.rx_active, rx_valid, and rx_data signals and observes tx_valid, tx_data, and tx_ready.

10.1 Packet Tests

18 tests in 6 classes covering token detection, handshake detection, data receive/deserialize, data generate, handshake generate, and interpacket timing.

Token Detection Tests

Handshake Detection Tests

Data Packet Receiver Tests

Data Packet Deserializer Tests

Data Packet Generator Tests

Handshake Generator Tests

Interpacket Timer Tests

10.2 Endpoint Tests

2 tests covering isochronous stream endpoints.

10.3 Descriptor Tests

7 tests covering all descriptor types, offsets, truncation, ZLP, and error cases.

Descriptor Retrieval Tests (5 tests)

Error Case Tests (2 tests)

10.4 Transfer Tests

4 tests covering IN transfer manager.

10.5 Request Tests

3 tests covering SETUP decoder.

10.6 Reset Tests

1 test covering the 14-state reset sequencer.

10.7 ULPI Tests

8 tests in 4 classes covering ULPIRegisterWindow, ULPIRxEventDecoder, ULPIControlTranslator, and ULPITransmitTranslator.

ULPIRegisterWindow Tests (4 tests)

ULPIRxEventDecoder Test (1 test)

ULPIControlTranslator Test (1 test)

ULPITransmitTranslator Tests (2 tests)

10.8 Stream Tests

1 test covering the boundary detector.

10.9 Device-Level Tests

3 tests from test_usb2_device.py (now collected and run by pytest).

10.10 Integration Tests with USBStreamOutEndpoint

2 tests from the ULPI test module.

11. References