Skip to main content

GDB Stub

Spectranext cartridges support the GDB Remote Serial Protocol (RSP), enabling external tools to automate file operations, device control, and debugging tasks. This protocol allows you to build custom tools that interact with the cartridge's onboard XFS filesystem without requiring a web browser or manual file transfers.

Overview​

The GDB RSP implementation in Spectranext provides:

  • File operations via vFile protocol extension
  • Device-specific operations via vSpectranext protocol extension
  • Standard GDB debugging capabilities (register access, memory read/write, breakpoints)
  • Connection via USB CDC or TCP socket (port 1337, for emulators)

Protocol Basics​

Packet Format​

GDB RSP uses a simple packet-based protocol:

$<data>#<checksum>

Where:

  • $ - Packet start delimiter
  • <data> - Packet payload (can contain any bytes, including null bytes)
  • # - Checksum delimiter
  • <checksum> - Two hex digits representing the 8-bit checksum of all bytes in <data>

Checksum Calculation​

The checksum is the sum of all bytes in the data payload, modulo 256:

checksum = sum(ord(byte) for byte in data) & 0xFF

Acknowledgments​

  • ACK (+): Sent when a packet is received correctly
  • NAK (-): Sent when a packet checksum is invalid or packet is malformed

Interrupt Character​

The interrupt character (\x03, Ctrl+C) can be sent at any time to halt execution. It is only processed when the deframer is in idle state (not receiving a packet).

Connection Methods​

USB CDC (Serial)​

The device appears as a USB CDC serial port (e.g., /dev/ttyACM0 on Linux, COM28 on Windows).

TCP Socket (Emulators)​

Connect via TCP socket:

  • Host: localhost (or remote host if GDB server is running remotely)
  • Port: 1337 (default)

The TCP connection is useful when using the Fuse emulator's GDB server.

Protocol Detection​

To detect if a device supports Spectranext extensions, send a qSupported query:

$qSupported#<checksum>

The response will include vSpectranext+ if supported:

$PacketSize=4000;qXfer:features:read+;qXfer:auxv:read+;vSpectranext+#<checksum>

Live Spectrum screen​

Send vSpectranext:screen:binary to request a complete snapshot with one command. Over USB, the device sends one response:

F<frame-id-8>,<write-count-8>,<size-4>,<fnv1a-32-8>,<border-2>:<RSP-escaped screen bytes>

Over Wi-Fi, it sends these responses in order, without waiting for another request:

S<frame-id-8>,<write-count-8>,<size-4>,<chunk-size-4>,<chunk-count-2>,<border-2>
B<frame-id-8>,<part-2>,<offset-4>:<RSP-escaped screen bytes>
... (one B response per part)
E<frame-id-8>,<fnv1a-32-8>

Numeric fields are hexadecimal. Parts are numbered from zero. border is the most recently observed colour from writes to port $xxFE, in the range 0–7. It is sampled when the screen snapshot is made, so rapid border colour changes within a video frame are not represented. Older firmware omits this field.

Raw screen bytes $, #, *, and } are escaped as } followed by the byte XOR 0x20. The RSP packet checksum covers the escaped payload. The final checksum is FNV-1a (32 bit, initial value 2166136261) over the 6,912 raw screen bytes. Accept a frame only when its ID, offsets, lengths, part count, and final checksum all match. Each B response fits the transport's advertised PacketSize using five portions of up to 1,400 bytes over Wi-Fi. The complete escaped USB frame fits in its 16,384-byte RSP packet limit.

vSpectranext:screen:stream uses the same header and end response, with D responses containing ASCII hexadecimal screen bytes. It remains available for clients that cannot read binary RSP payloads.

The older two-command read interface remains available:

The vSpectranext:screen:begin request copies the current 6,912-byte screen shadow to a readable snapshot. The response is S followed by an eight-digit hexadecimal count of captured screen writes.

Read the snapshot with vSpectranext:screen:read:<offset>,<length>. Offset and length are hexadecimal; each response contains exactly twice length ASCII hexadecimal digits. A read may contain at most 4,096 bytes, and the client must also respect PacketSize from qSupported. Read offsets 0 through 6,143 for the Spectrum bitmap and 6,144 through 6,911 for the colour attributes. Call screen:begin again for the next frame. Invalid ranges return E22.

The shadow currently observes writes to the normal $4000–$5AFF display memory. It starts empty at controller boot and fills as the Spectrum writes the screen; the alternate 128K display bank is not captured yet.

vFile Protocol​

The vFile protocol extension provides file operations on the cartridge's local XFS filesystem. All paths and data are encoded as ASCII-hex (two hex characters per byte). Writes go to the RAM layer; use vFile:commit to copy a file or directory into the overlayed flash layer.

Packet Format​

$vFile:<subcommand>:<args>#<checksum>

Commands​

vFile:open​

Open a file for reading or writing.

Request:

$vFile:open:<fd>,<flags>,<mode>,<path>#<checksum>
  • <fd>: File descriptor (hex, ignored, use 1)
  • <flags>: Open flags (hex):
    • 0x0000 = O_RDONLY (read-only)
    • 0x0001 = O_WRONLY (write-only)
    • 0x0002 = O_RDWR (read-write)
    • 0x0008 = O_APPEND (append mode)
    • 0x0100 = O_CREAT (create if not exists)
    • 0x0200 = O_CREAT | O_TRUNC (create and truncate)
  • <mode>: File mode (hex, ignored)
  • <path>: File path (ASCII-hex encoded)

Response:

  • Success: F<fd> where <fd> is the file descriptor (hex, typically 1)
  • Error: F-1,<errno> where <errno> is the error number (hex)

Example:

Request:  $vFile:open:1,2,0,2f746573742e747874#<checksum>
(opens "/test.txt" for read-write)

Response: F1

vFile:close​

Close an open file.

Request:

$vFile:close:<fd>#<checksum>
  • <fd>: File descriptor (hex)

Response:

  • Success: F0
  • Error: F-1,<errno>

Example:

Request:  $vFile:close:1#<checksum>

Response: F0

vFile:pread​

Read data from an open file (sequential read from current position).

Request:

$vFile:pread:<fd>,<count>#<checksum>
  • <fd>: File descriptor (hex)
  • <count>: Number of bytes to read (hex)

Response:

  • Success: <hex-data> (hex-encoded binary data, no prefix)
  • Error: F-1,<errno>

Example:

Request:  $vFile:pread:1,100#<checksum>
(read 256 bytes)

Response: 48656c6c6f20576f726c64...
(hex-encoded "Hello World...")

vFile:pwrite​

Write data to an open file (sequential write at current position).

Request:

$vFile:pwrite:<fd>,<hex-data>#<checksum>
  • <fd>: File descriptor (hex)
  • <hex-data>: Binary data encoded as ASCII-hex (two hex chars per byte)

Response:

  • Success: F<bytes-written> where <bytes-written> is the number of bytes written (hex)
  • Error: F-1,<errno>

Example:

Request:  $vFile:pwrite:1,48656c6c6f#<checksum>
(write "Hello" = 0x48 0x65 0x6c 0x6c 0x6f)

Response: F5
(5 bytes written)

vFile:size​

Get the size of a file.

Request:

$vFile:size:<path>#<checksum>
  • <path>: File path (ASCII-hex encoded)

Response:

  • Success: F<size> where <size> is the file size in bytes (hex)
  • Error: F-1,<errno>

Example:

Request:  $vFile:size:2f746573742e747874#<checksum>
(get size of "/test.txt")

Response: F1000
(file is 4096 bytes)

vFile:exists​

Check if a file exists.

Request:

$vFile:exists:<path>#<checksum>
  • <path>: File path (ASCII-hex encoded)

Response:

  • Exists: F,1
  • Not exists: F,0
  • Error: F-1,<errno>

Example:

Request:  $vFile:exists:2f746573742e747874#<checksum>

Response: F,1

vFile:unlink​

Delete a file.

Request:

$vFile:unlink:<path>#<checksum>
  • <path>: File path (ASCII-hex encoded)

Response:

  • Success: F0
  • Error: F-1,<errno>

Example:

Request:  $vFile:unlink:2f746573742e747874#<checksum>

Response: F0

vFile:commit​

Commit a file or directory from RAM to flash.

Request:

$vFile:commit:<path>#<checksum>
  • <path>: File or directory path (ASCII-hex encoded)

Response:

  • Success: F0
  • Error: F-1,<errno>

Example:

Request:  $vFile:commit:2f746573742e747874#<checksum>
(commit "/test.txt" to flash)

Response: F0

vSpectranext Protocol​

The vSpectranext protocol extension provides Spectranext-specific operations for device control and directory operations.

Packet Format​

$vSpectranext:<subcommand>:<args>#<checksum>

Commands​

vSpectranext:reboot​

Trigger a ZX Spectrum reboot.

Request:

$vSpectranext:reboot#<checksum>

Response:

  • Success: OK (sent before reboot)

Example:

Request:  $vSpectranext:reboot#<checksum>

Response: OK
(device reboots immediately after)

vSpectranext:autoboot​

Configure autoboot from xfs://ram/ and reboot the device.

Request:

$vSpectranext:autoboot#<checksum>

Response:

  • Success: OK (sent before reboot)
  • Error: E<errno>

Example:

Request:  $vSpectranext:autoboot#<checksum>

Response: OK
(device configures autoboot and reboots)

vSpectranext:opendir​

Open a directory for reading.

Request:

$vSpectranext:opendir:<path>#<checksum>
  • <path>: Directory path (ASCII-hex encoded)

Response:

  • Success: OK
  • Error: E<errno>

Example:

Request:  $vSpectranext:opendir:2f#<checksum>
(open root directory "/")

Response: OK

vSpectranext:readdir​

Read the next directory entry.

Request:

$vSpectranext:readdir#<checksum>

Response:

  • Success: FOK,<name>,<type>,<size>,<storage> where:
    • <name>: File/directory name (ASCII-hex encoded)
    • <type>: F for file, D for directory
    • <size>: File size in bytes (hex, ignored for directories)
    • <storage>: Storage layer flag (0 = RAM, 1 = flash/committed)
  • End of directory: `` (empty string)
  • Error: E<errno>

Example:

Request:  $vSpectranext:readdir#<checksum>

Response: FOK,746573742e747874,46,1000,1
(file "test.txt", type file, size 4096 bytes, committed to flash)

Request: $vSpectranext:readdir#<checksum>

Response:
(end of directory)

vSpectranext:closedir​

Close an open directory.

Request:

$vSpectranext:closedir#<checksum>

Response:

  • Success: OK
  • Error: E<errno>

Example:

Request:  $vSpectranext:closedir#<checksum>

Response: OK

vSpectranext:mv​

Move/rename a file or directory.

Request:

$vSpectranext:mv:<old-path>,<new-path>#<checksum>
  • <old-path>: Current path (ASCII-hex encoded)
  • <new-path>: New path (ASCII-hex encoded)

Response:

  • Success: OK
  • Error: E<errno>

Example:

Request:  $vSpectranext:mv:2f6f6c64,2f6e6577#<checksum>
(rename "/old" to "/new")

Response: OK

vSpectranext:mkdir​

Create a directory.

Request:

$vSpectranext:mkdir:<path>#<checksum>
  • <path>: Directory path (ASCII-hex encoded)

Response:

  • Success: OK
  • Error: E<errno>

Example:

Request:  $vSpectranext:mkdir:2f6d79646972#<checksum>
(create "/mydir")

Response: OK

vSpectranext:rmdir​

Remove an empty directory.

Request:

$vSpectranext:rmdir:<path>#<checksum>
  • <path>: Directory path (ASCII-hex encoded)

Response:

  • Success: OK
  • Error: E<errno>

Example:

Request:  $vSpectranext:rmdir:2f6d79646972#<checksum>

Response: OK

Error Codes​

Error responses use standard errno values:

  • 0 = Success (no error)
  • 2 = ENOENT (No such file or directory)
  • 5 = EIO (Input/output error)
  • 9 = EBADF (Bad file descriptor)
  • 12 = ENOMEM (Out of memory)
  • 17 = EEXIST (File exists)
  • 20 = ENOTDIR (Not a directory)
  • 21 = EISDIR (Is a directory)
  • 22 = EINVAL (Invalid argument)
  • 27 = EFBIG (File too large)
  • 28 = ENOSPC (No space left on device)
  • 39 = ENOTEMPTY (Directory not empty)

Implementation Notes​

Sequential I/O​

vFile:pread and vFile:pwrite perform sequential I/O from the current file position. The position advances automatically after each read or write operation.

Path Encoding​

All paths must be encoded as ASCII-hex (two hex characters per byte). For example:

  • / → 2f
  • /test.txt → 2f746573742e747874
  • /my dir/file.bin → 2f6d79206469722f66696c652e62696e

Binary Data Encoding​

Binary data in vFile:pwrite requests must be hex-encoded. Binary data in vFile:pread responses is returned as hex-encoded.

Packet Size Limits​

The maximum packet size is as advertised in qSupported. For large file transfers, split data into multiple vFile:pwrite operations.

Reference Implementation​

The spx command-line tool (sdk/bin/spx.py) provides a complete reference implementation of the GDB RSP protocol for Spectranext. You can use it as a reference for building your own tools.

See Also​