β¨ Current status β Full HDL Implementation with USB Host Mode!
The project now provides two implementations:
- New HDL Implementation (
HDL/) - A complete Verilog implementation with:
- β USB passthrough and monitoring
- β UART-controlled HID injection
- β NEW: USB Host Mode - Complete device enumeration and HID keyboard support
- Legacy Python/Luna (
legacy/) - Original amaranth/LUNA implementationThe HDL implementation can now act as both a passive USB sniffer and an active USB keyboard host!
HurricaneFPGA explores lowβlevel USB manipulation on the Cynthion FPGA. It ships:
- Hurricane HDL β Complete Verilog implementation for advanced USB manipulation
- Legacy Amaranth/LUNA gateware β FS passthrough + UART HID injection
- Rust CLI β networkβtoβUART bridge for easy scripting
- Features
- Requirements
- Installation
3.1Β EnvironmentΒ setupΒ |Β 3.2Β BuildΒ gatewareΒ |Β 3.3Β FlashΒ gatewareΒ |Β 3.4Β BuildΒ RustΒ CLI - HardwareΒ setup
- Usage
5.1Β RunΒ gatewayΒ |Β 5.2Β SendΒ commands - Architecture
- Development
- Troubleshooting
- License
- Acknowledgements
- USB passthrough β Fullβ/LowβSpeed packets flow between TARGET (J2) β CONTROL (J3).
- HID injection β FPGA can splice oneβbyteβperβaxis mouse reports (
buttons, dx, dy). - UART control β Send exactly three bytes over PMOD A @ 115200 baud to inject.
- Rust gateway β Accepts UDP strings (
buttons,dx,dy) β forwards raw UART bytes. - Command acknowledgment β FPGA sends ACK/NAK responses with error codes.
- Complete device enumeration β Automatically enumerate USB devices with speed detection (LS/FS/HS)
- HID keyboard support β Poll USB keyboards and extract key reports
- HID mouse support β Poll USB mice and extract movement/button data
- Automatic operation β Self-configuring after enumeration completes
- Status monitoring β LED indicators and comprehensive status reporting
- Python control interface β Easy-to-use script for host mode control
- Real-time events β Monitor key presses and mouse movements with decoded reports
See HDL/USB_HOST_QUICKSTART.md for a quick start guide!
| Category | Items |
|---|---|
| Hardware | Cynthion board (r0.5+) |
| FPGA toolchain | OSS CAD Suite (Yosys + nextpnrβecp5 + Trellis) |
| Python | Python 3 Β· amaranth Β· luna Β· pyserial |
| Rust | Stable toolchain (rustup, cargo) |
| Debug Interface | Built-in UART0βUSB (no external adapter needed!) |
You only need Docker (with BuildKit support) for the initial build. We provide an optimized Makefile with layer caching for fast rebuilds:
# Quick start - build everything with caching
make build
# Fast rebuild using existing cache (much faster for incremental changes)
make build-fast
# Or manually with Docker
docker build -t amaranth-cynthion .Performance Tips:
- First build will take ~10-15 minutes as it downloads and compiles all dependencies
- Subsequent builds with
make build-fasttypically complete in 1-2 minutes - BuildKit cache mounts speed up Cargo and pip operations significantly
- The
.dockerignorefile ensures only necessary files are included in build context - In CI environments (GitHub Actions), inline cache is automatically used for compatibility
See make help for all available commands.
Python should be able to run this with python legacy/src/flash_fpga.py
The HDL implementation provides dedicated flashing tools:
cd HDL/tools
./flash_cynthion.sh # Flash the precompiled bitstreamFor advanced builds and debugging:
# Compile a custom bitstream
./compile_bitstream.sh
# Validate HDL before building
./validate_hdl.sh
# Debug connected Cynthion
python cynthion_debugger.pySee HDL/architecture.md and HDL/transparent_proxy_implementation.md for detailed documentation on the HDL implementation.
The Rust CLI is now built automatically within Docker:
# Build everything (Docker image + extract binaries)
make build
# Or manually
docker build -t amaranth-cynthion .
./deploy.sh
# Run the CLI
make run-rust
# Or directly:
./build/binaries/hurricanefpga --helpThe binary will be available at build/binaries/hurricanefpga.
Note: Docker now builds both the PC CLI tool and the SAMD51 embedded firmware using ARM cross-compilation. Both binaries are extracted to the
build/directory. Seedocs/RUST_PROJECTS.mdfor details on the two Rust projects.
The build system uses Docker BuildKit with aggressive caching for optimal rebuild times:
# Normal build (updates cache)
make build # Full build with cache update (~2 min after first build)
# Fast incremental builds
make build-fast # Use cache but skip cache export (~1 min)
make rebuild-fast # Clean artifacts, keep cache, rebuild
# Complete rebuilds
make rebuild # Clean everything including cache (~10-15 min)
make clean-cache # Remove only the Docker build cacheCache Storage:
- Local development:
/tmp/docker-cache-amaranth-cynthion/(local filesystem cache) - GitHub Actions: Inline cache in Docker image layers (compatible with docker driver)
- Cargo registry cache: Mounted during build (ephemeral)
- Pip cache: Mounted during build (ephemeral)
When to use each:
make build-fast: Day-to-day development (fastest)make build: After major dependency changesmake rebuild: When troubleshooting build issues
CI/CD Notes: The build system automatically detects CI environments and uses inline caching instead of local filesystem cache for compatibility with GitHub Actions' docker driver.
| Connection | Details |
|---|---|
| Host PC USB | β TARGET (J2) |
| USB device (keyboard, mouse, etc.) | β CONTROL (J3) or TARGET B |
| Debug/Control | β CONTROL port (USB, built-in UART0βUSB CDC-ACM) |
Debug Interface: Connect Cynthion's CONTROL port to your PC. It appears as
/dev/ttyACM0(Linux) or a COM port (Windows) for real-time status and HID report monitoring. No external UART adapter needed!See
HDL/UART0_USB_INTEGRATION.mdfor complete details.
The FPGA now outputs real-time status via UART0βUSB:
# Linux/macOS
picocom -b 115200 /dev/ttyACM0
# Or simply:
cat /dev/ttyACM0
# Windows (PowerShell)
# Check Device Manager for COM port, then:
mode COM3 BAUD=115200 PARITY=n DATA=8
type COM3Example Output:
[STATUS] Proxy: ON, Host: ON, Enum: DONE
[HID-KBD] Mod: 0x00, Keys: [0x04, 0x00, 0x00]
[HID-MOUSE] Btn: 0x01, dX: 0x05, dY: 0xFD
[STATUS] Proxy: ON, Host: ON, Enum: DONE
See HDL/UART0_USB_INTEGRATION.md for detailed message formats.
# list serial ports
target/release/packetry_injector --list
# start UDPβUART bridge
target/release/packetry_injector \
--udp 127.0.0.1:9001 \
--control-serial /dev/ttyUSB0 # or COM3 on WindowsThe FPGA now provides acknowledgments for each command sent:
- ACK (0x06) - Command was successfully received and processed
- NAK (0x15) + Error Code - Command failed with specific error code:
0x01- Value out of range0x02- Syntax error0x03- System busy0x04- Buffer overflow
The Rust CLI automatically handles these acknowledgments.
The HDL implementation now supports USB host functionality for enumerating and communicating with USB keyboards.
# Install Python dependencies
pip install pyusb
# Navigate to tools directory
cd HDL/tools
# Enable USB host mode
./usb_host_control.py --enable
# Connect USB keyboard to PHY2 port (J2 on Cynthion)
# OR connect USB mouse to PHY2 port
# Start enumeration
./usb_host_control.py --enumerate
# Monitor keyboard events in real-time
./usb_host_control.py --monitor # Auto-detects keyboard or mouseKeyboard:
Detected keyboard, starting keyboard monitor...
Monitoring keyboard events... (Ctrl+C to stop)
[10:45:23] H
[10:45:24] E
[10:45:25] L
[10:45:26] L
[10:45:27] O
[10:45:28] LEFT_SHIFT + W
[10:45:29] O
[10:45:30] R
[10:45:31] L
[10:45:32] D
Mouse:
Detected mouse, starting mouse monitor...
Monitoring mouse events... (Ctrl+C to stop)
[10:50:15] Move(+10, + 5)
[10:50:16] LEFT
[10:50:17] Move( +3, + 2) LEFT
[10:50:18] Wheel( +1)
| LED | Meaning | State |
|---|---|---|
| LED7 | Host Mode Enabled | ON when host mode active |
| LED6 | Enumeration Complete | ON after successful enumeration |
| LED5 | Device Polling | ON when actively polling keyboard/mouse |
| LED4 | New Report | BLINKS when keys pressed or mouse moved |
For complete USB host mode documentation, see:
HDL/USB_HOST_QUICKSTART.md- Quick start and troubleshootingHDL/USB_HOST_INTEGRATION.md- Complete architecture and integration detailsHDL/USB_HOST_COMPLETE.md- Full feature summary
ββββββββββββββββββββ Serial ββββββββββββββ
β Rust Gateway CLI β ββββββββΊ β UARTΒ Dongleβ
β packetry_injectorβ β (FT232) β
ββββββββββββββββββββ βββββββ¬βββββββ
β
βΌ
ββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββ> β CynthionΒ FPGA (ECP5) β
|DEVICE| β β’ ULPI AUX β HostΒ PC β
β β’ ULPI HOST β TargetΒ Device β
β β’ UARTΒ Rx/Tx β PMODΒ A β
β β’ Amaranth/LUNA passthrough/injector β
ββββββββββββββββββββββββββββββββββββββββββ
|
|
βΌ
HOST PC
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Cynthion FPGA (ECP5) β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β USB Host Mode β β
β β ββββββββββββββββ βββββββββββββββββ ββββββββββββββββ β β
β β β Reset Ctrl β β Enumerator β βTransaction β β β
β β β β β β βEngine β β β
β β ββββββββ¬ββββββββ βββββββββ¬ββββββββ ββββββββ¬ββββββββ β β
β β β β β β β
β β ββββββββββββ¬ββββββββ΄βββββββββββββββββββ β β
β β βΌ β β
β β βββββββββββββββββββββββββββ β β
β β β USB Host Arbiter β Priority-based TX β β
β β β (PHY2 TX Multiplexer) β signal multiplexing β β
β β βββββββββββ¬ββββββββββββββββ β β
β β β β β
β β βββββββββββΌββββββββββββββββ β β
β β β Token Request Arbiter β Request arbitration β β
β β β (Token Generator Mux) β for shared resources β β
β β βββββββββββ¬ββββββββββββββββ β β
β β βΌ β β
β β ββββββββββββββββββββ β β
β β β Token Generator β β β
β β ββββββββββββββββββββ β β
β β ββββββββββββββββ ββββββββββββββββ β β
β β β HID Keyboard β β HID Mouse β β β
β β β Engine β β Engine β β β
β β ββββββββββββββββ ββββββββββββββββ β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β USB Proxy/Monitor β β
β β ββββββββββββββ ββββββββββββββ ββββββββββββββββ β β
β β βUSB Monitor β βPacket Proxyβ βBuffer Managerβ β β
β β β (PHY0/1) β β β β (32KB) β β β
β β ββββββββββββββ ββββββββββββββ ββββββββββββββββ β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β UART Interface β β
β β UART0 (Built-in USB CDC-ACM) β Status & Debug Output β β
β β PMOD A β Command Input (Legacy) β β
β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β β
βΌ βΌ βΌ
PHY0 (J1) PHY1 (J3) PHY2 (J2)
Device Side Control/Monitor Host Side
The HDL implementation uses a dual-arbiter architecture to manage multiple USB host controllers:
Purpose: Multiplexes UTMI TX signals from multiple host controllers to PHY2
Priority Order (Highest to Lowest):
- Reset Controller - Handles bus reset and speed detection
- Enumerator - Manages device enumeration sequence
- Transaction Engine - Executes USB transactions (SETUP/IN/OUT)
- Protocol Handler - Handles protocol-level responses
- Token Generator - Sends USB token packets
- SOF Generator - Generates Start-of-Frame packets
Key Features:
- Combinatorial priority-based selection
- Active signal gating for priority control
- Separate TX data/valid wires per module
- Single unified output to PHY
Purpose: Arbitrates token generator requests from multiple controllers
Priority Order (Highest to Lowest):
- Enumerator - Enumeration must complete without interruption
- Transaction Engine - Normal data transfers
- Keyboard Engine - Periodic polling (lowest priority)
Key Features:
- Request-level arbitration (not data path)
- Shared resource management for token generator
- Prevents conflicting token requests
- Maintains proper USB timing
-
USB Host Operation:
- Controller generates TX data on dedicated wires
- Controller asserts active signal
- USB Host Arbiter selects highest priority active controller
- Selected TX data forwarded to PHY2
-
Token Generation:
- Controller asserts token request signals
- Token Request Arbiter selects highest priority request
- Token Generator processes unified request
- Token completion signaled to all controllers
-
Data Reception:
- PHY2 RX data broadcast to all controllers
- Each controller processes relevant packets
- Protocol handler manages handshakes
USB Host Components:
usb_reset_controller.v- Bus reset, speed detection, connection monitoringusb_enumerator.v- Complete enumeration sequence (GetDescriptor, SetAddress, SetConfig)usb_transaction_engine.v- SETUP/IN/OUT transaction managementusb_token_generator.v- USB token packet generation (IN/OUT/SETUP/SOF)usb_sof_generator.v- Start-of-Frame timing and frame number trackingusb_protocol_handler.v- USB protocol state tracking and validationusb_host_arbiter.v- NEW: PHY TX signal multiplexerusb_token_arbiter.v- NEW: Token request arbitration
HID Engines:
usb_hid_keyboard_engine.v- Keyboard interrupt endpoint pollingusb_hid_mouse_engine.v- Mouse interrupt endpoint polling
Proxy/Monitor:
usb_monitor.v- Packet capture and analysispacket_proxy.v- Packet forwarding and modificationbuffer_manager.v- 32KB ring buffer with dual-port BRAM
Supporting:
uart_interface.v- UART0 CDC-ACM interface for debug outputdebug_interface.v- Status register accesstimestamp_generator.v- Microsecond-precision timestamping
The HDL uses Yosys for synthesis with three optimization levels:
make synth-fast # ~30s - Quick iteration
make synth # ~1-2min - Balanced (recommended)
make synth-max # ~3-5min - Maximum optimizationSee HDL/architecture.md for detailed module documentation.
cd HDL
# Validate Verilog syntax
make validate
# Synthesize (fast iteration)
make synth-fast
# Full build with place & route
make all
# Flash to device
cd tools && ./flash_cynthion.sh# Rust CLI (Host PC)
cargo build --release
# SAMD51 Firmware (Cross-compile for ARM)
cd firmware/samd51_hid_injector
cargo build --releaseComprehensive test coverage across all layers:
# Run all tests
make test-local
# or
./run_tests.sh
# Run individual test suites
make test-rust # Firmware unit tests (66 tests)
make test-python # Python unit tests (59 tests)
# Test results
# β
Rust firmware: 66/66 passed
# β
Python tools: 59/59 passed
# β
Total: 125 testsTest Coverage:
- Firmware: HID reports, recoil patterns, protocol parsing, state management
- Python Tools: Command generation, validation, descriptor parsing
- HDL: USB token generation, transaction engine, HID injector
See TESTING.md for complete testing documentation and TEST_COVERAGE_SUMMARY.md for detailed coverage metrics.
USB device on J3 not detected by host
- Reβflash correct bitstream & reset.
- Check cabling: HostΒ βΒ J2, DeviceΒ βΒ J3.
- Only FS/LS devices work.
- Ensure VBUS on J3 (jumper) or selfβpowered device.
# Cynthion DFU
SUBSYSTEM=="usb", ATTRS{idVendor}=="1d50", ATTRS{idProduct}=="615b", MODE="0666"
# CP210x example
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", MODE="0666", GROUP="dialout"
# FT232 example
SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", MODE="0666", GROUP="dialout"
sudo udevadm control --reload-rules && sudo udevadm triggerDistributed under the terms of the MITΒ License β see LICENSE.
- Cynthion by GreatΒ ScottΒ Gadgets.
- Built with AmaranthΒ HDL, LUNA USB framework, and a stack of fantastic Rust crates.