RIFT64 // REMOTE_GATEWAY

PROTOCOL

Feature-Complete Byte-Stream Reference (V1 Beta)

🖥️ V1 Protocol Beta
🏎️ SwiftLink 38400+ Baud
💾 Legacy C64/C128 & Replicas

The RIFT64 Wire Protocol

The RIFT64 protocol is an optimized, unframed, byte-stream protocol designed specifically for low-bandwidth, high-speed serial links (such as SwiftLink cartridges operating at 38.4kbps). By utilizing a compact character-prefix format followed by hexadecimal arguments, RIFT64 achieves extreme parsing efficiency directly on the C64's 8-bit 6502 microprocessor.

Status: V1 Feature Complete (Active Beta). Future development goals include: Mouse input routing, direct SID register streams, dynamic connection/crash recovery, and client-side custom ML execution.

! Write Text

No Reply
ASCII Code: 33 ($21)
Payload Format: <text> + CR or LF
Destination Registers: $0400 Screen / $D800 Color RAM

Streams ASCII text directly at the current cursor offset using the active default foreground color. The stream terminates as soon as a Carriage Return (`$0D`) or Line Feed (`$0A`) is parsed. Letters are dynamically converted from ASCII to native C64 screen codes on-the-fly.

// Example: Write "RIFT64 ACTIVE" and wrap cursor
!RIFT64 ACTIVE<CR>

@ Batch Sprite Position

No Reply
ASCII Code: 64 ($40)
Payload Format: MM + (XHXLYY × N)
Destination Registers: $D000-$D010 (VIC-II Sprite Coords)

A high-speed shortcut command that updates the position of one or more sprites without altering pointers, colors, or other configurations. `MM` is an 8-bit mask whose set bits select which of the 8 sprites are being updated; the client then reads one 6-hex-digit `XHXLYY` block per set bit, in ascending sprite-ID order. `XH` carries the X-MSB bit (used when X > 255), `XL` is the low byte of X, and `YY` is the Y coordinate.

// Example: Move Sprite 0 to (X=300, Y=150) and Sprite 2 to (X=80, Y=200)
// Mask = %00000101 = $05; entries follow in ID order (0, then 2)
@05 012C96 0050C8

~ Framed Command

A (ACK) N (NAK)
ASCII Code: 126 ($7E)
Payload Format: CLL + <data> + SS
Destination Registers: Staging Buffer (Validated)

Invokes a framed, checksum-verified packet. `C` is a one-byte framed command ID (e.g. `L` for length text, `C` for clear). `LL` is the payload length. `SS` is an additive checksum calculated over the entire packet: `SS = (C + LL + sum(data)) & $FF`.

// Example: Send a framed text packet with checksum verification
~L13FRAMED TEXT PAYLOAD5F

? Capabilities Query

String Reply
ASCII Code: 63 ($3F)
Payload Format: None
Destination Registers: ACIA Out Stream

Instructs the Commodore 64 client to write its features/capabilities string back upstream. Useful on connection handshakes to detect compatibility and the set of supported command opcodes. The C64 client immediately streams back a CR-terminated response listing the supported command letters, terminated by an `ACK` token: RIFT64 CKPLQXZ~FIDY@UGHNA ACK<CR>.

// Example: Send query to the C64
?

A Audio Module Control

A (ACK) N (NAK)
ASCII Code: 65 ($41)
Payload Format: S + <hex args>
Destination Registers: SID Music Module ($D400-$D41C)

Drives the resident SID music-module player. The first byte `S` is an ASCII subcommand digit selecting the operation; remaining hex bytes are subcommand-specific arguments. Most subcommands return `A` (ACK) on success or `N` (NAK) on failure; A7 returns a single state byte instead.

Subcommands:
  • A0 — Stop playback.
  • A1 TT — Start playback of subtune TT (1..127).
  • A2 — Pause playback.
  • A3 — Resume playback.
  • A4 TT — Set playback tempo TT.
  • A5 LLHH — Bind the music module installed at address $HHLL.
  • A6 0V — Set master volume V (low nibble, 0..F).
  • A7 — Query state; the client streams back a single status byte (no ACK).
// Example: Bind a music module previously uploaded to $C000, then start subtune 1
A500C0
A101

B Draw Border

No Reply
ASCII Code: 66 ($42)
Payload Format: WWHH + 9-byte layout config
Destination Registers: $0400 Screen / $D800 Color RAM

Automatically draws a rectangular border outline on the C64 screen starting from the current cursor coordinates. `WW` is the width, and `HH` is the height. The 9-byte configuration payload contains the raw C64 character codes representing corners and vertical/horizontal bars.

// Example: Draw a 10x10 border outline using custom corners and line characters
B0A0A[9 bytes of layout config]

C Clear Screen

No Reply
ASCII Code: 67 ($43)
Payload Format: None
Destination Registers: $0400-$07E7 (Screen RAM)

Clears the 40x25 character matrix back to spaces (`$20`), resets the cursor position to column 0, row 0, and hides the hardware cursor. To avoid a jarring visual flash, the border and background colors are preserved during this clear step.

// Example: Clears screen instantly
C

D Draw Metatile

A (ACK)
ASCII Code: 68 ($44)
Payload Format: 20 hex bytes (window + colour config)
Destination: Caller-supplied screen + colour RAM pointers

Renders a rectangular window of a tile-id map into screen RAM in a single round-trip. Supports three tile modes (1 = raw 1×1 char, 2 = 2×2 metatiles, 3 = 3×3 metatiles), arbitrary target stride, sub-tile scroll offsets (offX/offY) for smooth scrolling, an edge fill character, and a configurable colour-RAM pass (cMode: 00=NONE, 01=FILL, 02=MAP, 03=PERCELL). PERCELL is mode-2 only and uses a 1 KB page-aligned bank of 4 parallel slot pages, indexed by tile id, giving a distinct colour to each child cell of every metatile (mode 3 transparently falls back to MAP). The renderer ACKs with A after the entire window is drawn. See the metatile guide for the full payload layout and SDK helper.

// Payload (each field is one hex pair):
// mode mapLo mapHi mapW mapH metaHi tgtLo tgtHi stride winW winH x y offX offY fill cMode cTgtLo cTgtHi cSrcLo cSrcHi cFill
D[20 hex bytes]

E Erase Run

No Reply
ASCII Code: 69 ($45)
Payload Format: LL (1-Byte Hex)
Destination Registers: $0400-$07E7 (Screen RAM)

Writes exactly `LL` spaces (`$20`) starting from the current cursor offset. When complete, the cursor position automatically restores to its starting offset. Ideal for erasing lines, status displays, or rendering clear space runs.

// Example: Erase 40 ($28) cells (a full row) from current cursor
E28

F Charset Bank Swap

A (ACK)
ASCII Code: 70 ($46)
Payload Format: Hex Nibble + Hex Byte
Destination Registers: $D018 / $DD00

Alters the active VIC-II bank and character memory offset mapping. Allows developers to toggle live between uppercase, lowercase, and custom uploaded fonts/tile matrices. The client responds with `A` (ACK) after register swapping.

// Example: Switch charset bank register offsets
F[Hex Nibble + Hex Byte]

G Scroll Region

No Reply
ASCII Code: 71 ($47)
Payload Format: XXYYWWHHD
Destination Registers: $0400 (Screen) & $D800 (Color RAM)

Executes hardware subregion shifting of width `WW` and height `HH` from coordinate `XXYY`. Direction `D` controls the shift: `0` Up, `1` Down, `2` Left, `3` Right. Shshifted lines automatically preserve color RAM values. Newly exposed row/column slots are cleared to spaces using the default background/foreground colors.

// Example: Scroll a 40x10 region from column 0, row 5 upwards
G0005280A0

H Cursor Visibility

No Reply
ASCII Code: 72 ($48)
Payload Format: 0 (Hide) or 1 (Show)
Destination Registers: Cursor Status Variable

Controls whether the C64 client actively renders and flashes the text cursor. Hiding the cursor (`H0`) is highly recommended during game loops or graphic rendering to prevent visual glitches. Show the cursor (`H1`) when waiting for text inputs.

// Example: Hide the cursor
H0

I Display Mode

A (ACK)
ASCII Code: 73 ($49)
Payload Format: Mode byte + Bank registers
Destination Registers: $D011 (BMM/ECM) & $D016 (MCM)

Switches the active VIC-II graphics mode. Allows the host to switch the screen from standard text mode into multicolor bitmap, standard bitmap, or extended color modes. Returns `A` (ACK) on successful transition.

// Example: Set screen to Multicolor Bitmap Mode
I[Mode parameters]

J Telemetry Control

No Reply
ASCII Code: 74 ($4A)
Payload Format: S [+ DD MM]
Destination Registers: Upstream Telemetry State

Controls the upstream telemetry generator. The first byte `S` is an ASCII subcommand digit. J1 additionally takes a 1-byte hex divider DD (frames between sends) and a 1-byte hex channel mask MM selecting which hardware sources to sample.

Subcommands & Channel Mask:
  • J0 — Disable telemetry.
  • J1 DD MM — Enable periodic streaming. DD = frame divider; MM = channel mask (bit 0 Joy port 2, bit 1 Joy port 1, bit 2 Sprite-Sprite collision $D01E, bit 3 Sprite-Background collision $D01F).
  • J2 — Send a single one-shot telemetry packet immediately.
// Example: Enable telemetry every 3 frames, sampling both joysticks + sprite collisions
J1030F

K Set Colors

No Reply
ASCII Code: 75 ($4B)
Payload Format: BF (1-Byte Hex)
Destination Registers: $D020 (Border), $D021 (Bg), Fg Variable

Sets the background and border color registers to the hex color value `B`, and sets the default text foreground write color to `F`. Both `B` and `F` must be lowercase or uppercase hex digits (0-F).

// Example: Set background/border to Black ($00), and foreground to White ($01)
K01

L Length-Prefixed Text

A (ACK) N (NAK)
ASCII Code: 76 ($4C)
Payload Format: LL + <bytes>
Destination Registers: $0400 Screen / $D800 Color RAM

Writes exactly `LL` bytes of text. Safe for streaming raw strings containing control characters, escape sequences, or binary formatting bytes that would prematurely terminate a standard `!` command. The client returns `A` (ACK) once the exact byte length is consumed.

Length Constraints & Special Cases:
  • LL = 01 to FF → Represents 1 to 255 bytes of text payload.
  • LL = 00 → Special case representing exactly 256 bytes of payload.
// Example: Write exactly 12 ($0C) bytes of raw text
L0CHELLO WORLD

M Store Memory

No Reply
ASCII Code: 77 ($4D)
Payload Format: AAAALL + <data>
Destination Registers: $AAAA-$FFFF (C64 System RAM)

Writes binary bytes directly to C64 RAM starting at destination address `AAAA` for length `LL` (where `00` represents 256 bytes). This is highly powerful, allowing you to stream custom sprite bitmaps, font banks, or raw 6502 Machine Language code directly to the C64.

Length Details & Safety Constraints:
  • Length Range: LL = 01 to FF writes 1 to 255 bytes of binary data.
  • Special Case (256 Bytes): Setting LL = 00 is a special case representing exactly 256 bytes of payload.
  • System Safety: Writing to zero page ($0000-$00FF), stack pointer ($0100-$01FF), or RIFT64's dynamic ACIA serial receive buffer (allocated at the end of the client code, usually around $2B00-$2BFF) will cause immediate connection drops or system crashes.
// Example: Upload 64 ($40) bytes of sprite data to $3E00
M3E0040[64 bytes of raw sprite binary]

N Raster Split

A (ACK)
ASCII Code: 78 ($4E)
Payload Format: Raster parameters & split point
Destination Registers: $D011 / $D012 (Interrupt Line)

Configures a horizontal raster split line. Highly advanced, this enables split-screen graphics—for example, rendering a full-color bitmap image at the top of the screen while preserving a standard character text terminal at the bottom! Returns `A` (ACK) on completion.

// Example: Configure a raster split at horizontal line 150
N[Split parameters]

O Custom Restore

No Reply
ASCII Code: 79 ($4F)
Payload Format: None
Destination Registers: Client Interrupt Restores

Signals a custom, client-side visual restoration routine. Used to return from heavy custom graphics or raster split interfaces back to standard boot screen matrices.

// Example: Invoke client custom restore
O

P Set Cursor Position

No Reply
ASCII Code: 80 ($50)
Payload Format: XXYY (2-Byte Hex)
Destination Registers: Cursor Offset Pointer

Positions the hardware cursor on the screen. `XX` represents the column offset (clamped to 0-39) and `YY` represents the row offset (clamped to 0-24). Decoding is performed on the C64 dynamically to calculate the absolute RAM writing index.

// Example: Move the cursor to Column 10 ($0A), Row 5 ($05)
P0A05

Q Color RAM Block

A (ACK)
ASCII Code: 81 ($51)
Payload Format: XXYYWWHH + <colors>
Destination Registers: $D800-$DBE7 (Color RAM Only)

Directly updates the color RAM matrix for a rectangular region of width `WW` and height `HH` from coordinate `XXYY` without changing any text character codes on the screen. Each color is a single low-nibble byte. Returns `A` (ACK) on completion.

Payload Details:
  • Payload Size: Exactly WW × HH bytes must follow.
  • Color RAM In C64: Modifies standard color attributes at $D800 + YY * 40 + XX.
// Example: Paint a 10x2 block at (2, 5) with custom colors
Q02050A02[20 color bytes]

R Restore Screen Buffer

No Reply
ASCII Code: 82 ($52)
Payload Format: 0 (Slot 0) or 1 (Slot 1)
Destination Registers: $0400 (Screen) & $D800 (Color RAM)

Restores the complete 1000-character screen and color RAM grids back from one of the off-screen backup slots (0 or 1) on the C64. This is extremely fast (virtually instantaneous), allowing you to draw temporary popups, overlay menus, or dialogs, and then dismiss them instantly without stream overhead!

// Example: Restore the screen from Slot 0
R0

S Save Screen Buffer

No Reply
ASCII Code: 83 ($53)
Payload Format: 0 (Slot 0) or 1 (Slot 1)
Destination Registers: Off-screen Backup Buffers

Saves the entire current screen RAM (`$0400-$07E7`) and color RAM (`$D800-$DBE7`) matrices into a local backup buffer slot (0 or 1) residing in upper C64 RAM. Essential for preserving the screen state before loading overlays or menus.

// Example: Save screen to Slot 0
S0

T Write Colored Text

No Reply
ASCII Code: 84 ($54)
Payload Format: F + <text> + CR or LF
Destination Registers: $0400 Screen / $D800 Color RAM

Sets the active default foreground text color to `F` (low nibble), then writes the text exactly like the `!` write text command. Terminated by a Carriage Return or Line Feed.

// Example: Write "ONLINE" in Cyan ($03) text
T3ONLINE<CR>

U Sprite Multicolor

No Reply
ASCII Code: 85 ($55)
Payload Format: Sprite multicolor parameters
Destination Registers: $D01C / $D025 / $D026

Configures the VIC-II's sprite multicolor state. Allows you to toggle individual sprites between standard (high resolution, 1 color) and multicolor (lower resolution, 4 colors) modes, and configure the two shared multicolor registers (`$D025` and `$D026`).

// Example: Configure sprite multicolor registers
U[Multicolor registers]

V Write Colored Window

No Reply
ASCII Code: 86 ($56)
Payload Format: FWWHH + <data>
Destination Registers: $0400 Screen / $D800 Color RAM

Sets the active default foreground text color to `F` (low nibble), then writes a window block exactly like the standard `W` draw window command.

// Example: Draw a 10x2 window in Orange ($08) foreground
V80A02[20 bytes of raw data]

W Draw Window

No Reply
ASCII Code: 87 ($57)
Payload Format: WWHH + <data>
Destination Registers: $0400-$07E7 (Screen RAM)

Writes a rectangular grid of raw characters of width `WW` and height `HH`. The current cursor position forms the top-left boundary of the window. After each row of size `WW` is written, the cursor position dynamically resets to the starting column and advances down by one row, allowing rapid batch painting.

Payload Calculations & Screen Bounds:
  • Payload Length: Exactly WW × HH bytes of screen data must be sent.
  • Screen Bounds Clamping: Width WW is clamped to 1-40. Height HH is clamped to 1-25.
// Example: Render a 4x2 ($0402) block of filled blocks (8 bytes)
W0402[8 bytes of raw data]

X Checked Window

A (ACK) N (NAK)
ASCII Code: 88 ($58)
Payload Format: WWHH + <data> + SS
Destination Registers: MemoryStoreBuffer → Screen RAM

Buffered window block render verified by an 8-bit additive checksum `SS`. The C64 client reads the incoming character stream first into an internal, 256-byte staging buffer named `MemoryStoreBuffer` (located in the client's memory copying module, memory_store.asm). It then validates the checksum. If the checksum matches, the block is dynamically copied row-by-row to the screen matrix; if it fails, the C64 drops the data and returns `N` (NAK).

Buffer Size & Staging Constraints:
  • Payload Length: Exactly WW × HH bytes of screen data must follow.
  • Hardware Clamping: Width WW is clamped to 1-40. Height HH is clamped to 1-25.
  • Critical Buffer Limit: Because the X command stages data inside the 256-byte MemoryStoreBuffer, the product WW × HH must not exceed 256 bytes, or memory overflow/corruption will occur on your Commodore!
// Example: Write a verified 4x2 window with checksum (8 bytes + 1 checksum byte)
X0402[8 bytes of raw data]5A

Y Set Sprite

No Reply
ASCII Code: 89 ($59)
Payload Format: IIXHXLYYCCPPBBEE
Destination Registers: VIC-II Sprite Offset Registers

Configures one of the 8 built-in C64 hardware sprites. `II` selects the sprite ID (0-7). `XH` handles the Sprite X-MSB bit (controls if X is > 255). `XL` is the X position (0-255). `YY` is the Y position. `CC` controls the sprite color. `PP` is the sprite memory block pointer (relative to VIC Bank). `BB` controls the active 16KB VIC bank. `EE` toggles the sprite's enable status (`00` is off, `01` is on).

// Example: Enable Sprite 0 at X=150, Y=120, Color Green ($05), Pointer $3E
Y00009678053E0301

Z Checked Memory Store

A (ACK) N (NAK)
ASCII Code: 90 ($5A)
Payload Format: AAAALL + <data> + SS
Destination Registers: C64 System RAM (Validated)

Identical to the `M` memory copy command, but validated via an 8-bit additive checksum `SS`. If the checksum fails, the write is aborted, and `N` is returned, preventing code or memory corruption in noisy serial environments.

Length Details & Checksum Calculations:
  • Length Range: LL = 01 to FF writes 1 to 255 bytes. LL = 00 writes exactly 256 bytes.
  • Checksum Math: The 1-byte hex checksum SS must equal the 8-bit sum of all raw data bytes: SS = sum(data) & $FF.
  • Memory Protection: Aborts writes if a transmission error occurs, shielding sensitive assembly pointers from corruption.
// Example: Upload checked binary blocks to RAM (64 bytes + 1 checksum byte)
Z3E0040[64 bytes of raw sprite binary]AF

Upstream Telemetry Packets (J Command)

The RIFT64 terminal client on the Commodore 64 doesn't just receive rendering data; it also acts as an active telemetry source, pushing real-time hardware status (joystick ports and VIC-II collision latches) back upstream to your backend server.

Whenever telemetry is enabled (J1) or one-shot (J2), the C64 client emits a fixed-length 8-byte packet over the same SwiftLink stream. Channels masked off by the MM argument are reported as zero. Keyboard input continues to use the existing inline upstream byte path and is not framed by this packet.

Offset Byte Field Description
0$7ESYNCFixed sync marker.
1$55TYPEPacket type id ('U' = upstream telemetry v1).
2seqSequenceRolling 0..255 counter for loss detection.
3joy1Joystick (Port 2)CIA1 $DC00, low 5 bits inverted to active-high (0 if channel disabled).
4joy2Joystick (Port 1)CIA1 $DC01, low 5 bits inverted to active-high (0 if channel disabled).
5spr_sprSprite-Sprite CollisionsLatched VIC-II $D01E (0 if channel disabled).
6spr_bgSprite-Background CollisionsLatched VIC-II $D01F (0 if channel disabled).
7cksumChecksum(seq + joy1 + joy2 + spr_spr + spr_bg) & $FF.