Written and Maintained by Gregory Nacu

C64 OS: USER'S GUIDE

Last modified: Jun 27, 2019

Files and File References

C64 OS uses the C64 KERNAL ROM's implementation for IEC serial bus access, and File I/O. C64 OS does not provide a fast loader. C64 OS is compatible with JiffyDOS, and purchasing a copy (from Retro Innovations) is highly recommended.

File Module KERNAL Calls

finit

RegPtr → Pointer to a File Reference
A ← Error Code
C ← Set on Error

Initializes the device specified by the file reference. Set's the device's default partition and default path to match the file reference. Called automatically by fopen.

ferror

currentdv → a device number
A ← Value of L_CODE

Reads and clears the current device's status.
Populates: L_CODE, L_DEV, L_STAT, L_MSG, L_TRK and L_SEC.


fopen

RegPtr → Pointer to an unopen File Reference
A → File Access Flags

Opens the file, on the device, specified by the File Reference.
Marks the file reference as open by setting its logical file number.
Calls ferror to retrieve device status.

fread

RegPtr → Pointer to an Open File Reference
A1 → .W Pointer to Buffer
A2 → .W 16-bit Length to Read

Reads from the current offset into the file, length number of bytes, into buffer.
If the end of file is reached before reading the requested length, no error results, it just stops reading.
The file must be open for read or a file not open error will be generated.

fwrite

RegPtr → Pointer to an Open File Reference
A1 → .W Pointer to Buffer
A2 → .W 16-bit Length to Write

Writes length number of bytes from the buffer to the file.
If the specified length is longer than the buffer, random data following the buffer will be written out to disk.
The file must be open for write or a file not open error will be generated.

fclose

RegPtr → Pointer to an Open File Reference

Closes the file, on the device and in the KERNAL open files table, specified by the File Reference.
If the file is already closed, no error will be produced.


frefcvt

C → Set for Serialize
RegPtr → Pointer to a File Reference Structure
RegPtr ← Pointer to a File Reference String

C → Clear for Unserialize
RegPtr → Pointer to a File Reference String
RegPtr ← Pointer to a File Reference Structure

Converts a file reference between a 1-Memory Page structure and a packed string representation. The string representation is used for storage to disk. The in–memory structure is used for opening and working with the file, as it maintains runtime flags and pointers that have no representation in the string format.


clipin

RegPtr → Pointer to memory buffer
A → Length to read

Opens the clipboard for read. Reads data from the clipboard, up to the length specified, into the specified buffer. Closes the clipboard.
If A is passed as 0, the full clipboard will be read into the buffer.

Usage Notes: Use the clipboard workspace values to check the data type and subtype for type compatibility before allowing the user to paste. Before reading in the entire clipboard, use C_DSIZE to check that the clip will not overflow the buffer.
See: Clipboard Workspace Values, below.

clipout

RegPtr → Pointer to memory buffer
A → Length to write

Writes data to the clipboard, up to the length specified, from the specified buffer.
If A is passed as 0, writing will continue until the first NULL byte is reached. Closes the clipboard.

The size of the clipboard is recorded automatically.
The datatype of the clipboard is set by default to text/plain.


copen

A → fopen flags. Only FF_R and FF_W are supported.

Opens the clipboard. If the clipboard is open for write, clears the previous contents from the clipboard.

cread

RegPtr → Pointer to memory buffer
A → Length to read

The clipboard must be open for read before calling cread.
Reads data from the clipboard, up to the length specified, into the specified buffer.
If A is passed as 0, the full clipboard will be read into the buffer.
Advances the clipboard read cursor.

Usage Notes: Use the clipboard workspace values to check the data type and subtype for type compatibility before allowing the user to paste. Before reading in the entire clipboard, use C_DSIZE to check that the clip will not overflow the buffer.
See: Clipboard Workspace Values, below.

cwrite

RegPtr → Pointer to memory buffer
A → Length to write

The clipboard must be open for write before calling cwrite.
Writes data to the clipboard, up to the length specified, from the specified buffer.
If A is passed as 0, writing will continue until the first NULL byte is reached.
Appends the data to the currently open clipboard.
The size of the clipboard is recorded automatically as data is written out to it, even if data is written out using multiple calls to cwrite.

cclose

X → Clipboard data type
Y → Clipboard data subtype

Closes the clipboard. Assigns the clipboard's data type and subtype.


File Constants

File Flags. These flags can be OR'd together when passed to fopen with a File Reference.

Constant Description
FF_R Read. Used to open a file for read only.
FF_S Status. Used when opening a file to have the file's size read into the File Reference.
FF_W Write. Used to open a file for write. Cannot be combined with FF_R. If the file already exists, an error will be generated.
FF_A Append. Used in conjunction with FF_W. File is opened for write. If the file already exists, it is opened and the file cursor is positioned to the end of the file.
FF_O Overwrite. Can be used in conjunction with FF_W. Cannot be used with FF_A. Opens a file for write. If the file already exists, the old file is scratched first.

Clipboard Workspace Values

The following values are generally READ only.

The clipboard size and datatype are managed automatically by the clipboard KERNAL routines. They may be modified manually, if the program changing them is a clipboard manager. The C64 OS clipboard utility is an example of such a program.

Value Description
C_DTYPE The clipboard's primary datatype
C_DSTYPE The clipboard's data subtype
C_DSIZE The 16–bit clipboard size

File System

C64 OS cannot be booted from a 1541, 1571 or 1581 because the C64 OS system folder depends on a file system that supports subdirectories. All of the most common devices that support subdirectories are being tested to be supported by C64 OS. These devices include, CMD HD, CMD RL, CMD FD, IDE64, and all varieties of device based on the SD2IEC firmware. C64 OS can use a device without subdirectory support, for data storage, but the system folder out of which C64 OS boots must reside on a device that supports subdirectories. (1581 sub-partitions are not supported, as they require a non–standard syntax to navigate.)

Every system file and every installed Utility and Application must be installed in the same partition of the same device. That device cannot be removed from the system while C64 OS is running. For a CMD HD that means the CMD HD cannot be turned off while C64 OS is running. Nor may its device swap buttons be pressed. A CMD RamLink or FD device swap buttons also may not be used. If C64 OS is installed on a CMD FD disk, that disk may not be removed.1 If C64 OS is installed on an SD2IEC device, the SD Card may not be removed while C64 OS is running.

There was a time when storage was in short supply, and C64s were frequently saddled with only a single floppy disk drive. It was necessary to allow the user to remove the disk, to put in a different disk to access more storage space. Operating systems like GEOS (and even Amiga OS) check the ID of a disk and will request the original disk be swapped back in when it needs to access system files. Today, a single SD card, that costs just a few dollars, can have many gigabytes of data. (More than enough space for the complete system and more Applications and Utiliites than will likely ever exist.) A 1541 cost around $1000 in today's money, for one 10th the cost today, you can buy two SD2IEC devices. Use one for the permanent internal storage, and a second one for hotswapping the SD media. Everything is made simpler if the OS is allowed to assume that its boot volume is permanent.

File References

For a detailed explanation of File References, what they are for, how they work and why they are necessary, see the weblog post KERNAL, File Refs and Services.

A C64 OS file reference is 1 page of structured memory, and must be paged aligned. Creating a new file reference is as easy as allocating one page of memory with PGALLOC. A file reference absolutely locates a file, and also contains meta data about the size of the file, its opened or closed status, and logical file number if open.

The first 5 properties have a small fixed length. Device number, partition number, logical file number, file size in blocks and filename. The filename is null terminated, and may be from 1 to 16 characters long. The remaining space in the page is alloted for an absolute path from the root of that device's partition. The path has the most variability in length, and can be from 1 to 233 characters long.

It is possible to create a file reference manually. However it is more common that a file reference will be generated for you. For example, the Files utility, in open mode, allows the user to navigate the devices and their file systems to find a file to open. Upon selecting a file, the Files utility creates a new file reference to the file, and then sends a message to the app to open a file, and passes it a pointer to the file reference.

The application only needs to store the pointer in workspace memory, at the address defined by the constant OPNFILEREF. The C64 OS status bar, in file mode, renders a serialized version of the open file reference.

A pointer to a file reference is passed to F_OPEN, F_READ, F_WRITE and F_CLOSE. When saving a file, then, the application can open the current file by passing the pointer stored at OPNFILEREF to F_OPEN with write and overwrite flags. Then write out the data and close, and never have known where exactly the data came from nor where it was saved to.

If the application wants to save its data to a new file, the application can spawn the Files utility in save mode. The utility lets the user navigate around the devices and file systems, as well as to supply a filename. The utility creates a new file reference that may or may not have a corresponding file. The application can then F_OPEN that file reference, which may create the file anew.

Additionally, when an application is opened, the system creates a file reference that points to the root of the application's bundle, and puts a pointer to that file reference in work space memory, which is referenced by the constant APPFILEREF. By means of this standardized file reference an application always has generic access to its own bundle. It can use this at runtime to locate additional resources. Similarly, each utility is programmed either to save its state and configuration data globally or locally. If globally, it access its config file in the settings folder of the current system folder. But, if it access its config file locally, then it too uses the APPFILEREF to find the root of the currently running application's bundle. In this way, utilities can have different state and configuration per application.

There may be situations where the application needs to access a resource relative to the system folder. There is a C64 OS KERNAL routine in the Services module to create and return a new system file reference. An application can call this, then append to its path, and set its filename, before passing it to F_OPEN, etc.

Lastly, the KERNAL routine, frefcvt, is used to convert a file reference memory structure into a compacted, serialized format. This string can be written to disk. Frefcvt can also be used in reverse, to create a new file reference memory structure from the serialized string format. This has many uses. An application that currently has a file open, can serialize the OPNFILEREF and then write that to a file in its own bundle. The next time the application is opened, it can check for the presence of this file in its bundle. If it finds it, it can unserialize its contents and restore the OPNFILEREF, and thus reopen the last open file automatically. This can be a very good user experience.

The C64 OS status bar, when in file mode, renders the file reference pointed to by OPNFILEREF. This allows the user to see what file the application is currently working on. In order to render the file reference to the status bar, it uses frefcvt.

An application could also allow the user to type in C64 OS file reference, in the compact serialized format. Then the application could convert what the user typed into a real file reference and attempt to open it. Thus giving the user a way to specify a file with the keyboard rather than the mouse.

Summary of File Reference structure components.

File Ref Part Size Description
FREFDEV 1 byte The standard Commodore device number, from 8 to 30.
FREFPART 1 byte The partition number on devices which support multiple partitions. On 1541, 1571, and 1581 drives partition number is always 0.
FREFLFN 1 byte The KERNAL ROM's logical file number. This is assigned automatically by fopen. Doubles as a flag to indicate file open status. It is 0 when the file is closed.
FREFBLKS 2 bytes Size of the file in 254-byte blocks. Automatically populated by finit, when a file is opened by fopen using the FF_S (Status) flag.
FREFNAME 17 bytes A filename, up to 16 characters long, plus NULL terminator
FREFPATH 234 bytes An absolute path, CMD Format (SD2IEC compatible.)

Drive Detection

C64 OS uses a detected drives table, stored in workspace memory, to determine what storage devices are available. The Files utility, for picking files to open, and for finding a place to name and save a file, uses the detected drives table to present and allow the user to navigate the available drives. The C64 OS File Manager homebase application uses the table in the same way.

The table is constructed at boot time. The booter loads a special drive detection program, which polls the device numbers from 8 to 29 to look for a device. When it finds a device, the program uses common techniques to identify the device type. C64 OS has a system of device type IDs which are inserted into the detected drives table offset to the corresponding device number. C64 OS device type IDs can be used to determine if the device supports subdirectories.

After turning a device off, or after turning on a new device, the detected drives table will be out of date. You must run the Drives utility, and use it to re–run drive detection. This allows the set of available drives to be changed without rebooting C64 OS. The system's boot device cannot be disabled in this manner. C64 OS has support for 5 drives active simultaneously.

Supported devices and their C64 OS detection codes

Code Code (Binary) Device Type Constant
Do not support subdirectories
0 %0000 0000 Device Not Present DEVNOT
1 %0000 0001 Foreign/Unknown Device DEVFOR
41 %0010 1001 Commodore 1541 DEV1541
71 %0100 0111 Commodore 1571 DEV1571
81 %0101 0001 Commodore 1581 DEV1581
Support subdirectories (Bit7 is set)
130 %1000 0010 CMD FD DEVCMDFD
131 %1000 0011 CMD HD DEVCMDHD
132 %1000 0100 CMD RamLink DEVCMDRL
133 %1000 0101 RamDrive / RamDOS DEVCMDRD
134 %1000 0110 SD2IEC DEVSDIEC
135 %1000 0111 IDE64 DEVIDE64

The drive detection map is in workspace memory, defined by the constant DRIVEMAP, and runs from DRIVEMAP+8 to DRIVEMAP+29.

If a 1541 is configured as device 9, then you'll find 41 (DEV1541) at DRIVEMAP+9. If an SD2IEC is configured as device 12, you'll find 134 (DEVSDIEC) at DRIVEMAP+12. And so on.

WARNING: DRIVEMAP+0 to DRIVEMAP+7 are not part of the map and those addresses are allocated for other purposes.

Drive and File Status

After any disk command is issued, the status of the drive should be read. All detected drives have their command channel (channel 15) opened, left open, and statically assigned a logical file number based on the device number. The KERNAL routine ferror reads the status from the last accessed device (currentdv). The drive's status is cleared automatically, and the drive's error LED stops blinking. The status is converted and stored in workspace memory, at addresses defined by the following constants:

Value Description Format
L_STAT Device Status Code PETSCII
L_MSG Device Status Message PETSCII
L_TRK Track, or secondary status code. PETSCII
L_SEC Sector PETSCII
These correspond with the 4 standard status fields:
62, FILE NOT FOUND,00,00
L_CODE Device Status Code 8-Bit Int
L_DEV Device of Last Status 8-Bit Int

L_STAT is automatically converted to an INT and stored at L_CODE. This makes it easy to test. L_DEV is the device number whence the current status was read. This will not necessarily remain the last accessed device. The C64 OS status bar, when in device status mode, renders:

LDEV:L_STAT, L_MSG, L_TRK, L_SEC

Example, if the status is OK, on the device 9.

9:00, OK,00,00

The status bar is notified to rerender whenever these fields change.

After any manually issued command, you should manually call ferror. Ferror is called automatically after each use of F_OPEN, F_READ and F_WRITE. Ferror also returns L_CODE in the accumulator, so it is extra easy to test.


Next Section: Screen Compositor

  1. Because a CMD FD supports native partitions with subdirectories, a CMD FD behaves much like a CMD HD, but one with very tiny swappable media. For this reason, C64 OS can be booted from a CMD FD, but it is not designed to be run "from floppy." Unlike GEOS or Amiga OS which will ask you to put in the disk that's needed, C64 OS assumes that its boot volume is permanent. []

Table of Contents



This is document is continually updated.

Refer to the last modified date at the top of this document for the most recent changes.