Skip to content

File drop: mount and autostart .d64 images, mount the other image types - #21

Merged
crustovsky merged 7 commits into
mainfrom
disk-images
Sep 2, 2026
Merged

crustovsky merged 7 commits into
mainfrom
disk-images

Conversation

@crustovsky

Copy link
Copy Markdown
Owner

Dropping a .d64 now mounts it on drive A and autostarts it; the other image types the mount API accepts are mounted without touching the machine.

How

  • .d64: one RUN_IMG (0xFF0B) frame on the DMA socket (port 64, 24-bit length). The firmware saves it as /temp/tcpimage.d64, mounts it, resets, and types LOAD"*",8,1 and RUN itself. Cartridge parking and the readiness gate apply as for run_prg.
  • .g64 / .d71 / .g71 / .d81: POST /v1/drives/a:mount?type=<t> with the image as the body. No autostart exists in firmware for these, so the machine is left running and the log says to type LOAD"*",8,1.

Also

  • The port-64 code is now a small shared DMA-socket helper. It authenticates when a network password is set (AUTHENTICATE 0xFF1F), which the keyboard channel never did before.
  • C64U_DMA_PORT redirects port 64 for tests; fakeultimate.py gained a DMA socket listener that logs frames.
  • Integration tests: .d64 frame with parking and gate order, password handshake before the image frame, REST mount for .d81 with no parking.
  • Help overlay row render-checked; --help, README, and CLAUDE.md updated.

Verified on hardware (firmware 1.1.0): c64uv --run wolf64.d64 mounted the image and screen RAM showed the firmware's LOAD"*",8,1 / RUN sequence.

No version bump yet; to be released after hands-on testing.

🤖 Generated with Claude Code

https://claude.ai/code/session_01GCACXGV72EjRZUUKapybmQ

crustovsky and others added 7 commits September 2, 2026 22:14
A dropped .d64 goes out as one RUN_IMG frame on the firmware's DMA socket
(port 64, 24-bit length): the firmware saves it as /temp/tcpimage.d64,
mounts it on drive A, resets the machine and types LOAD"*",8,1 and RUN
itself. Verified on firmware 1.1.0 by reading screen RAM back. Cartridge
parking and the readiness gate apply as for a program run. .g64/.d71/.g71/
.d81 have no firmware autostart, so they are mounted over
POST /v1/drives/a:mount and the machine is left alone.

The port-64 code moves into a small DMA-socket helper shared with the
keyboard channel. It now authenticates when a network password is set
(AUTHENTICATE 0xFF1F, one-byte reply), which the keyboard path never did;
C64U_DMA_PORT redirects the port for tests. fakeultimate.py grows a DMA
socket listener that logs every frame, and the integration suite checks
the .d64 frame with cartridge parking and gate, the password handshake
order, and the REST mount for a .d81.

Help overlay (render-checked), --help, README and CLAUDE.md document the
new drop types and the firmware facts.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GCACXGV72EjRZUUKapybmQ
…owly

The connect timeout (1-3 s) doubles as the socket's send timeout, and the
Ultimate's TCP stack takes in a 175 KB image slowly enough that a single
send() can hit it: "DMA socket send failed: Resource temporarily
unavailable" on a real .d64 drop. send_all now treats a would-block as
"wait for room" (compat_wait_writable) and only gives up after 30 s
without progress. compat gains compat_neterr_transient and
compat_wait_writable, with unit coverage. Three images re-run on
firmware 1.1.0, all mounted and started.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GCACXGV72EjRZUUKapybmQ
The Ultimate's DMA task serves one client at a time: it accepts a
connection and reads from it until it closes before accepting the next.
The windowed viewer keeps its keyboard channel connected, so a dropped
.d64's RUN_IMG connection queued behind it and stalled until the keyboard
socket happened to drop (30 s stall, then "Resource temporarily
unavailable"). Headless --run never showed it because nothing else holds
the port. Reproduced by holding an idle port-64 connection during a
--run: the transfer waited, and finished 0.1 s after the idle client
closed.

run_file_async now closes the keyboard socket before the run thread
starts and keyb_try_connect stays off port 64 while g_run_busy; the
channel reconnects on the next keypress afterwards. The transfer
publishes its progress (g_run_pct) and the event loop shows it in the
window title ("sending game.d64 42%"), restoring the normal title when
done.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GCACXGV72EjRZUUKapybmQ
… port 64

Reconnecting only on the next keypress could lose that keystroke. The
drop marks the channel for reclaim and the event loop reconnects it the
moment the run thread clears g_run_busy. Only then: a blind retry every
loop would block the render loop for the connect timeout whenever the
Ultimate is unreachable.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GCACXGV72EjRZUUKapybmQ
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GCACXGV72EjRZUUKapybmQ
@crustovsky
crustovsky merged commit d6c11a0 into main Sep 2, 2026
1 check passed
@crustovsky
crustovsky deleted the disk-images branch September 2, 2026 20:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant