commanderx16 / x16-rom

Other
153 stars 44 forks source link

GEOS: FAT support #317

Open mist64 opened 2 years ago

mist64 commented 2 years ago

The main piece of work that is still necessary for GEOS is a proper filesystem interface.

Current Status

Since it is derived from the C64 version, X16 GEOS currently assumes the SD card is a 1541 disk. Nice for a proof of concept, because you can pass -sdcard APPS64.D64 to the emulator command line and it'll boot into "Desk Top". But users aren't going to waste their 32 GB SD card by using them as a single 170 KB disk.

The Problem

The Commodore version of GEOS, which the X16's version is based on, depends a lot on the "BAM" filesystem (1541, 1571, 1581, CMD FD, CMD HD). This happens on the following layers:

  1. The plug-in disk driver (1541, 1571, ...) abstracts block reading/writing, block allocation and the directory structure.
  2. The generic filesystem handler deals directly with BAM-features like block chaining, the VLIR format and the directory entry format.
  3. This is exposed through a 3-layer API: a) low-level API: interfaces the block reading and writing functions of (1) b) mid-level API: interfaces with block allocation, directory structure of (1), adds logic on top c) high-level API: abstract enumerating, reading, writing files
  4. Some applications decode parts of the filesystem manually and rely on the VLIR on-disk format. (Because GEOS can only handle one VLIR file at a time, geoWrite reads overlays from its own executables manually, for example.)

While it would be okay to rewrite (1) and (2) and patch applications (4), the fact that some the API (3b) is BAM-based (similar to CP/M FCBs) makes this tricky.

Approaches

BAM Disk Images

A simple solution would be to use disk images on top of FAT. But this carries a lot of legacy baggage and makes it very hard to exchange files with modern systems. Also, the maximum size of BAM-like filesystems is 16 MB (255 tracks of 256 sectors of 256 bytes).

(The X16 isn't about recreating the past and being compatible, but about making new retro development easy, so we shouldn't be too worried about compatibility. In other words: X16 GEOS is not there to run the full C64 GEOS catalog – it's there to be able to write new GEOS applications on nicer hardware.)

Apple-like Port

There was an Apple II version of GEOS that worked on top of the ProDOS filesystem, with 512 byte blocks, different block linking, different allocation tables, a different directory entry format – and subdirectory support! This was so different that applications weren't binary compatible between Commodore and Apple, but they could be 99% the same code, plus some #ifdefs.

We could port GEOS to FAT like it has been ported to ProDOS: Keep the high-level API the same, keep the rest of the API the same in spirit, but change all necessary details, and add functions. This will make some applications incompatible, but is a very clean solution.

In-between

There is a way to retain some more compatibility without going into great lengths. Examples:

The GEOS Disk API

VLIR Level

API Description
OpenRecordFile Open an existing VLIR file for access given its filename.
CloseRecordFile Update the VLIR file's IndexTable and the disk BAM. indicate no open VLIR file.
UpdateRecordFile Update the VLIR file's IndexTable, disk BAM, and Time/date stamp.
PreviousRecord
NextRecord
PointRecord
Adjust current record pointer to the previous, next, or to a specific record in the vlir file.
DeleteRecord Deletes current record and leaves curRecord pointing to the following record.
WriteRecord Writes contents of memory area out to Current Record.
ReadRecord Reads Current Record into memory.

These are sufficiently high-level that they should work with any underlying filesystem. These are the core APIs used by document-based applications.

High-Level Disk Routines

API Description Comment
GetPtrCurDkNm  Returns a pointer to a buffer containing the name of the disk easy
SetGEOSDisk  Converts a normal C64 DOS disk to a GEOS disk trivial
CheckDkGEOS Checks to see if the current disk is a GEOS disk trivial
FindFTypes Generates a list of all files on the disk of a specific type easy
GetFile Launch app/desk accessory or open file in app no change
FindFile Searches the disk for the file, returns its Directory Entry "Directory Entry" virtualization
DeleteFile Deletes a file from the disk easy
SaveFile Saves a GEOS file to disk "T/S" virtualization
RenameFile Gives a file a new name easy
CalcBlocksFree See how many free block there are left on disk 65535 blocks (16 MB) limit

Intermediate Routines

API Description Comment
FindFile Returns a file's Directory Entry. "Directory Entry" virtualization
GetBlock Reads a block from disk. not useful
PutBlock Write a block to disk, and verifies it. not useful
GetFHdrInfo Given a Directory Entry, fetches the file's File Header block. "Directory Entry" virtualization
ReadFile Reads a track/sector linked chain of blocks from disk. "T/S" virtualization
WriteFile Writes memory data out to a linked chain of blocks on disk. "T/S" virtualization (b)
ReadByte Simulates reading a byte at a time from a chain of blocks. "T/S" virtualization
GetDirHead Read the Directory Header and BAM from disk. "Dir Head" virtualization
PutDirHead Writes the Directory Header and BAM back to disk. "Dir Head" virtualization
NewDisk Initialize the drive. trivial
LdApplic Loads and runs a GEOS application. unchanged?
LdDeskAcc Loads and runs a GEOS desk accessory. unchanged?
LdFile Loads a GEOS file. unchanged?
GetFreeDirBlk Get a free Dir. Entry. Allocate a new Dir. Block if necessary. "T/S" virtualization? (b)
BlkAlloc
NxtBlkAlloc
Allocate a chain of blocks on the disk. "T/S" virtualization? (a) (b)
SetNextFree Allocates a free block on disk. "T/S" virtualization?
FreeBlock Frees up one block on disk. "T/S" virtualization? (b)
SetGDirEntry
BldGDirEntry
Create a Directory Entry from a Header Block. "T/S" virtualization? (a) (b)
FollowChain Create the tr/sec list in fileTrScTab for a chain of blocks. "Directory Entry" virtualization (a) (b)
FastDelFile Frees blocks indicated by the tr/sec list in fileTrScTab. not useful (a) (b)
FindBAMBit Returns information about a block. "T/S" virtualization? (b)
FreeFile Free all blocks in a file. Leave the Directory Entry intact. not useful (a) (b)
ChangeDiskDevice Changes the device number (8 or 9) the drive responds to. not useful (b)

(a)These APIs are not called by Desk Top (a very low-level app!) (b)These APIs are not called by geoWrite. These should give an indication that some APIs are not common in applications.

The Most Primitive Level

API Description Comment
ReadBlock not useful
WriteBlock not useful
VerWriteBlock not useful