Repository navigation
Conversation
…VDrive will share The GEOS installer and the TR block device each carry their own image geometry, BAM and directory code, and VDrive brings a third, more complete engine (40-track D64s, error bytes, BAM and directory growth for all three kinds, tested against c1541). Bring VDrive's engine in under Source/Teensy/DiskImage so the other two can move onto it. Nothing uses it yet. The copy differs from teensyrom-vdrive's d64/ only in what the firmware needs: SPDX lines, the placement macros moving into d64.h, and its three constant tables marked D64_FLASH so they land in PROGMEM rather than DTCM. DiskImage.h includes the code once for the single translation unit the firmware and the host harnesses build. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X5t9wWXadFkQgKaCnjreF7
…a 1541 does The allocator searched outward from the file's last sector and reported the disk full when it reached the end of the allocation order, so a file appended to after a scratch freed earlier tracks failed with blocks free. A hint on the directory track, D71 track 53 or D64 tracks 36-40 failed on its first new block. The search now restarts once from the start of the order before it reports FULL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… write does When the last data sector or the directory entry could not be written, d64_close_write returned the error and left the entry unclosed with its blocks allocated. A new file or a copy left a splat file and leaked blocks, contrary to d64_copy's "nothing is left behind"; an append left the original file unclosed, so the next validate deleted all of it. The close now aborts the write as d64_write does on an error, which puts an appended file back. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… does d64_create with replace scratched the old file before writing the new one, so a replace that ran out of room lost the old file. The old entry is now kept in the write handle and scratched once the new file has closed; a write that fails leaves it as it was. Both files need room at once, so a replace can now fail on a nearly full disk where scratching first would have fit, which is also what a 1541 does. A locked file is refused before anything is written. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ritten d64_create now checks the lock itself instead of relying on the scratch it no longer does first; without the check the new file is written and the close fails with both files left on the disk. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… image It returned 0 both when the buffer was too small and when the header, directory or BAM could not be read, so a caller could only report an unreadable image as a buffer problem. It now returns the length, the new D64_E_BUF for a small buffer, or the read's own error (D64_E_IO, D64_E_LOOP for a looping directory chain). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
It skips d64_format's clearing pass, so on a used image the old data stays in every sector it does not write. The comment said what it writes but not that the caller must guarantee the rest is already zero. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… engine TRBlockImage did its own track/sector arithmetic on top of GEOS's format table, which knows only the three plain sizes. A D64 with the error bytes copiers append, or a 40-track D64, therefore mounted as no image. The backend now opens the image with d64_open_exact and reads and writes through d64_block_read/d64_block_write, so those images mount and the geometry is the one VDrive uses. The error table is left unread: the driver has no status for a bad sector, so it gets the sector's bytes. Files of any other size still mount as no image; the harness now reads one byte past the largest image so an oversized file cannot pass as one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X5t9wWXadFkQgKaCnjreF7
… image engine GeosDiskPatch.h carried a second implementation of what the shared engine does: BAM places, allocation, directory chains and growth, file chains. It now asks the engine for all of it and keeps only what is GEOS's own: the info block, the GEOS bytes of the directory entry, and moving the TR driver ahead of the other input drivers. GeosBoot.h reads the boot file, refreshes an old TR mouse driver and sets up CONFIGURE through the engine too. The header goes from 596 lines to 362. The driver now lands where 1541 DOS would put it (nearest the directory, interleave 10) rather than first-free from track 1: one allocator in the firmware, and GEOS does not care where its files are. trmouse.py models the same allocator so the byte-for-byte test still holds, and docs/Architecture/Disk-Images.md records the choice. The room checks happen before the first write, now from the engine: d64_blocks_allocatable counts exactly what the allocator can hand out, so a BAM count below its bitmap is no longer refused and can no longer run the write out of room partway. Images with error bytes and 40-track D64s are accepted. The engine gains d64_dir_check, d64_dir_room, d64_blocks_allocatable and d64_alloc_next, which VDrive can use as well, and no longer grows a D81 directory into BAM sector 40/1 or 40/2 when a damaged BAM shows one free. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X5t9wWXadFkQgKaCnjreF7
… shared engine D64.ino carried its own sector geometry and file-chain reader. Loading a program from an image now goes through the shared engine via DiskImage/MenuDisk.h, which also holds the menu's size tolerance: short D64s down to 171520 bytes (Realm.d64) still open, and a sector past the file's end fails to read rather than the image being refused. Valid files load the same bytes as before. A chain that loops or links off the image now fails with "File could not be read" instead of reading until RAM runs out or seeking to a wrong offset, and the size limit is the buffer's exact size rather than 254 bytes short of it. The directory listing is unchanged here; it moves in the next commit, which changes what the menu shows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X5t9wWXadFkQgKaCnjreF7
…d engine The last disk image code of its own in the firmware was the menu's directory walk. It now goes through the shared engine's iterator, via MenuDiskList in DiskImage/MenuDisk.h, which is host-tested. This changes what the menu shows, to match a drive's directory listing: - a deleted file (type byte 0, name still in the slot) is no longer listed; - an empty slot no longer ends its directory sector, so entries after a gap are listed. The listing still starts at the first directory sector (18/1, or 40/3 on a D81) rather than the header's link, as the menu always has. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X5t9wWXadFkQgKaCnjreF7
wesbiggs
force-pushed
the
shared-disk-menu
branch
from
November 6, 2026 22:47
154ee10 to
e17649f
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is part 4 of a series of PRs to streamline and consolidate disk image (.d64/.d71/.d81) access, which will then be used to power the VDrive Special IO. It moves the TR menu's own D64/D71/D81 code, loading a file and listing a directory, onto the shared engine from #88. After it, the firmware has no disk image code of its own left, and the series stops here until the VDrive work proper.
Depends on #88, #89 and #90. Only the last two commits (
b1010ded,154ee102) are new here, so please review those. Once the others merge, I'll rebase this branch ontomainand it will shrink to those two commits.Rationale
D64.inocarried its own sector geometry, file-chain reader and directory walk: a fourth copy of what the engine does, and the least defended one. A file chain that loops or links off the image read until RAM ran out or seeked to a wrong offset, and the listing stopped a directory sector at its first empty slot.State of affairs after this PR
b1010ded) goes through the engine viaDiskImage/MenuDisk.h, which also holds the menu's size tolerance: short D64s down to 171520 bytes (Realm.d64is one) still open, and a sector past the file's end fails to read rather than the image being refused. Valid files load the same bytes as before. A chain that loops or links off the image now fails with "File could not be read", and the size limit is the buffer's exact size rather than 254 bytes short of it.154ee102) goes through the engine's directory iterator, viaMenuDiskList. This changes what the menu shows, to match a drive's own listing:LoadDxxDirectoryandLoadDxxFilekeep their signatures, so every way into them (the menu, andDriveDirLoad.ino's callers) takes the new path.Memory
D64.inoandMenuDisk.hareFLASHMEM, and the engine's areVD_COLD, which isFLASHMEMon the firmware. None of it is on the PHI2 path.MenuDisk.h's size and track tables arePROGMEM, and the menu's two load-failure messages usePSTR().npm run build:tr,npm run build:tr-plus), at firmware: the GEOS installer and boot-file reader use the shared disk image engine #90's tip (81b2e06c) and at this branch's tip: no change. TR and TR+ main, MinimalBoot and the TR+ extension image report the same RAM1free for local variablesandpaddingand RAM2variablesbefore and after (TR main 122748 / 6008 / 17600, TR+ main 79836 / 25864 / 17600).Docs
docs/Architecture/Disk-Images.md:MenuDisk.h, and the TR menu as the engine's third caller, with what its listing shows.Testing
Source/Teensy/tests/menu-disk.test.jslists directories and loads files the way the TR menu does, from each kind, short and odd-sized images, deleted entries, gaps, and chains that loop or link off the image.npm testpasses at this branch's tip.Compatibility
The menu's listing of a disk image changes as described above: deleted files no longer show, and files after an empty directory slot now do. No change to the remote protocol (
docs/ControlComms.md), the cartridge register map, the EEPROM settings or any timing.License
My own work, MIT licensed like the rest of the repository.
🤖 Generated with Claude Code