Rust driver for the USBSID-Pico — a Raspberry Pi Pico (RP2040 / RP2350) based board for interfacing one or more MOS SID chips (6581/8580) and hardware SID emulators over USB.
This is a Rust implementation of the original C++ driver by LouDnl. The original driver uses libusb; this crate defaults to serial port communication instead, which avoids platform-specific USB driver setup.
- Rust 1.70+ (2021 edition)
- A connected USBSID-Pico device
- On Linux:
libudev-devfor serial port enumerationsudo apt install libudev-dev # Debian/Ubuntu sudo dnf install systemd-devel # Fedora
cargo build --releaseThe default serial feature uses the OS-provided COM / tty port — no
additional drivers or libraries are needed on any platform.
If you want the libusb backend instead (matching the original C++ driver),
enable the usb feature. This requires libusb 1.0 headers and on Windows
a WinUSB driver via Zadig:
cargo build --features usbWhen both features are enabled, the driver tries USB first and falls back to serial.
use usbsid_pico::UsbSid;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut sid = UsbSid::new();
sid.init(/* threaded */ true, /* with_cycles */ true)?;
// Write to SID register via the ring buffer
sid.write_ring_cycled(0x01, 0x01, 0xFFFF)?;
// Read a register
let val = sid.single_read(0x1B)?;
println!("OSC3 random: 0x{:02X}", val);
Ok(())
}cargo run --example basic
cargo run --example simple_tone
cargo run --example sid_player -- path/to/tune.sid
cargo run --example sid_player -- path/to/tune.sid --stereo
cargo run --example sid_player -- path/to/tune.sid --sid4 $DE00The sid_player example includes a 6502 CPU emulator and supports
PSID/RSID v1–v4 files with automatic multi-SID detection from the header.
| Feature | Default | Description |
|---|---|---|
serial |
Yes | Serial port backend via serialport. No driver setup needed. |
usb |
No | libusb backend via rusb. Matches original C++ driver. Needs libusb headers and on Windows a WinUSB driver. |
debug_memory |
No | SID memory tracking. |
| Module | Description |
|---|---|
device |
Core UsbSid struct — connection setup, I/O, threading, timing |
transport |
Transport trait with serial and libusb backends |
constants |
Protocol opcodes, USB IDs, clock/timing tables, SID address helpers |
ringbuffer |
Lock-free SPSC ring buffer for the background writer thread |
error |
UsbSidError enum and Result alias |
ffi |
extern "C" functions for C/C++ consumers |
| Mode | Function | Description |
|---|---|---|
| Synchronous | single_write / single_read |
Blocking transfers |
| Async direct | write / write_cycled |
Non-threaded writes |
| Async threaded | write_ring / write_ring_cycled |
Background thread drains ring buffer |
Each SID occupies 32 registers (0x20 bytes):
| SID | Registers |
|---|---|
| SID1 | $00–$1F |
| SID2 | $20–$3F |
| SID3 | $40–$5F |
| SID4 | $60–$7F |
The crate exposes a C-compatible interface. Build as a shared library:
cargo build --release
# → target/release/libusbsid_pico.{so,dylib,dll}Generate the C header with cbindgen:
cargo install cbindgen
cbindgen --config cbindgen.toml --crate usbsid-pico --output usbsid_pico.hLinux — You may need a udev rule for non-root access:
echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="cafe", ATTR{idProduct}=="4011", MODE="0666"' | \
sudo tee /etc/udev/rules.d/99-usbsid.rules
sudo udevadm control --reload-rulesmacOS — With the default serial backend no special setup is needed.
Windows — The default serial backend uses the COM port that Windows
assigns automatically. If using the usb feature you need to install a
WinUSB driver with Zadig.
Licensed under either of
at your option.
USBSID-Pico hardware and firmware by LouDnl.