Ruud's Commodore Site Home  Email

The filesystem for 1541IDE and C64IDE





What is it

I have several projects using an harddisk: To be able to make use of an harddisk, you need a filesystem and the appropriate software to handle it. Commodore's original FS is only able to handle up to 16 MB. This is not enough for nowadays harddisks then can go up to 500 GB !!! SO I developed a FS that can handle disks up to 2 TB.

This is the first real proposal for a filesystem and some proposals for handling it. The goal is to stay independent of the way how the HD is connected to the system and the what kind of system it is.
Personal comment: I favour the system using a 1541-board. So it is possible that the idea is 'coloured' by this favouritism.


The bootsector

The Bootsector is the first sector of a drive: track 0, head 0, sector 1
* identifier like "CBM-HD00"                                     8 bytes 
* version like "00.00.01"                                        8 bytes
                 |  |  |---> enhancement
                 |  |------> sub version
                 |---------> main version 
Explanation: 
* 'Main version' speaks for itself. 
* Sub version: adding extra functionality's like extra commands.
* enhancement: used for fixes/patches 
* HD-parameters                                                  4 bytes
* number of tracks, lowbyte and highbyte   2 bytes
* number of heads                          1 byte 
* number of sectors                        1 byte 
    
A PC can determine the size of a drive (command $EC) so it should be possible
for us to do as well. 
Remark: The above 2/1/1 byte construction I will call TTHS-format 
* pointer to the Boot-PRG, all 0 when none. See: Boot-PRG        4 bytes TTHS
* base drive number in case dipswitches are used                 1 byte 
  with no valid identifier, base number is 8 

Why using TTHS?

For one simple reason: speed. If I used linear positioning then I first had to do some arithmetic to find out about the TTHS value because I need that one anyway. Loading a file now means that after reading the first sector, I immediately have the coordinates of the next logical sector at hand.

Although I use TTHS to locate sectors, I cannot do completely without linear positioning. The linear positioning starts at track 0, head 0, sector 1. Then it starts counting the rest of the sectors of that track. Then it moves to the next head. Why? No mechanical move of the head needed, saves time. Having gone through all heads, the counting goes on with track 1, head 0 sector 1. Now imagine the first sector of the image is situated at, for example, sector 3052. All I need the know now is that the 342 sectors I need to hold a D64-image are located from sector 3052 to 3349. Where that is on the harddisk, I don't care; my TTHS2LIN routine takes care of that conversion.


The Partition table

The partition table can be found on the second sector of a drive: track 0, head 0, sector 2. The idea is to let the harddisk emulate/serve as more then one drive.
Each entry is 32 bytes:
* Devicenumber                                                   1 byte
number is to be added to 'base number + dipswitches' 
$FF means not in use
* Drivenumber                                                     1 byte
* 0..$FE number to be used 
* $FF any Drivenumber is valid
* First sector                                                   4 bytes TTHS
* Last sector                                                    4 bytes TTHS
* Disk label                                                    16 Chars
* Use image                                                      1 byte
0 : normal drive, first sector is directory
1 : use image starting at "First sector", 
Disk label provides type of image: 'D64', 'D82' etc.
* Page where reserved memory starts                              1 byte
* Future use                                                     4 bytes
Reserving only one sector means that one is only able to create up to 8 partitions. Remember: we need to reserve memory for each partion and 32 KB is used up very quickly. Having some memory left to run some user provided utilities comes in handy as well.


The BAM table

The BAM-table starts at track 0, head 0, sector 3. The 1541 reserves 4 bytes for every track: one byte is used for the number of free sectors, the other three for marking the used sectors. The main problem is that the number of sectors/track can vary from HD to HD ranging from 17 to 63.

My idea is to reserve 8 bytes for every track; one bit for every sector and no "free sectors" (that can be calculated). In this way we will loose space but it simplifies calculations. How many packs of 8 bytes we need at the end depends on the size of the HD.


The Boot-program

The old 1540 and early 1541 had a way to load and execute a program by manipulating the DAT- and CLOCK-line of the IEC-bus. You can see this as executing the &-command immediately after a Reset. The 4 bytes in the very first sector can point to such an &-file. If not used they are $00.

I'm thinking of using this feature to enable one to make patches to the original Kernal by loading software in the extra RAM and changing the RAM-vectors. To avoid the problem that the drive keeps loading a faulty patch after every reset, the TTHS in the bootsector is cleared after loading the software.


The Directory

The root directory starts at the first sector of any partition. Except this particular sector, I've no plans of dedicating other sectors to directories or files.

The structure of an directory-sector should look like this:
* pointer to next sector                                         4 bytes TTHS
* pointer to previous sector                                     4 bytes TTHS
* 7 entries of 72 bytes each                                   504 bytes
An entry should look like this:
    
* filetype                                                        1 byte
* 00 = DELeted
* 01 = SEQuential
* 02 = PRoGram
* 03 = USeR
* 04 = RELative
* 05 = DIRectory (1581 compatibility, not used)
* 06 = DIRectory
* 07 = SYStem
* 08 = UEX, User EXtension
* 09 = EXE
* 0A..0F = future use
  
The four bits of the highnibble are used as the 1541 uses them:
value:       1                0    
* bit 7: file is closed / not closed
* bit 6: file is locked / not locked 
* bit 5: used by 1541 for ???
* bit 4: used by 1541 for ??? 
Filetype 7, SYStem, is meant to enable the host (= C64/128, 1541-board) to create a swapfile or whatever you want.
File type 8 enables a user to supply a file with its own extension. When listing such a file, the 1541 will send these three chars to the host instead of a predefined one. This feature also enables us to store well known Commodore images on the disk and to mark them as so. This on its turn can be used to let the HD emulate a specific Commodore drive. These three chars themselves can be found a little bit further in the list.
Filetype 9, EXEcutable: The first two bytes of a PRG describe the loading address. But the 65816 can handle 16 MB ie. needs 3 bytes and the new 65GZ032 even needs four bytes. The idea is to use this filetype for these type of PRG's. The first four bytes describe the 32 bits loading address. If the EXE is meant to run on a 65816 equipped machine, the first byte is $00.
  
* filetype, extra info                                            1 byte
* bit 0: hidden / not hidden 
The file is shown or not when listing a directory. This bit is equivalent
to the "hidden" attribute used with MS-DOS. 
* bit 1: no thumbnail / thumbnail 
Can be used for graphical images to inform that there is a thumbnail of
this file available.
* bit 2: no icon / icon 
can be used to tell the GUI of the OS that there is an icon available to
represent the file on the screen and/or directory. 
* bit 3..7: future use
* name, 1541-format                                              32 bytes
* pointer to first sector                                         4 bytes TTHS
* pointer to last sector                                          4 bytes TTHS 
* pointer to icon                                                 4 bytes TTHS
* number of sectors per file                                      4 bytes
* number of bytes in last sector                                  2 bytes
* type dependant information                                      4 bytes TTHS
* entry side-sector-block relative file
* pointer to thumbnail graphic file
* record length relative file                                     1 byte 
* date/time-stamp, YYYYMMDDHHMISS                                 7 bytes 
* user supplied extension                                         3 bytes
* filename number                                                 1 byte
* future use                                                      4 bytes 

The linksystem

I have chosen for using for the link-system as used by Commodore and not for the FAT-system as used by PC's. The idea is simple: the first four bytes of a sector are reserved for pointing to the next sector in the link. An extra addition to the original system is that next four bytes point to the previous sector. This doesn't only come in handy when searching backwards, but also gives one an extra mean of restoring links after a crash.
The remaining 504 bytes are data.

The reasons for choosing the link-system above the FAT-system: A pessimist could say that link-system needs more disk space. It does indeed: the room taken for the BAM tables to be precise. But if we would ommit the pointers to the previous sector, the link-system would be the big winner!


About the images

The idea behind supporting images is to remain as compatible as possible to the original Commodore drives. At least we should support D64 and D71 images but IMHO it should also be possible to support D81 (1581), D80 (8050), D82 (8250), D40 (3040) and D16/CMD in the future. The D16-image is "my own" invention and can be seen as a 1541-alike floppy with 255 tracks with each 256 sectors. As the original BAM is not big enough, it has one of his own. To remain a little bit compatible with the 1541, track 18/sector 1 is reserved for the directory but from then on the system is free to use any free sector. Of course D16 supports subdirectories but not like the 1581 does. A subdirectory is an ordinary file but its contents happen to have the same structure as a directory.
Somebody told me that this is exactly as how CMD does it on their harddisks. Once I know more about how a CMD-partition looks like, I could use that instead of my own D16-image.

How do we store images? Storing the contents of the file as regular data means splitting the original sectors inside the image as we can only store 504 bytes and two D64-sectors are make bytes. My idea is to store an image as one unfragmented file with _NO_ link-bytes. The directory tells us where to find the first sector. A "simple" calculation should tell us where to find any desired track/sector within the image.
I can imagine that creating a 16 MB sized D16/CMD image on an harddisk already in use for some time, can cause problems. This simply means we have to provide tools to defragment a harddisk.


Handling the filesystem

For the images the same commands as known by the original system must be implemented if possible, or adapted to the HD. Example: Commands regarding the MFM-mode of the 1571 are in fact impossible on the 1541-board or direct system and must be "translated" or neglected.
Remark: I have no idea yet how to handle CP/M-floppies. But I fear that it will cost a lot of ROM due to the number of formats. Don't forget, the ROM of a 1571 is 32 KB !!!

long name:              ab.:    function:
  
&:filename                      load file at address in drive-RAM and execute
BLOCK-ALLOCATE          B-A     FS-2001: Syntax error
                                image: Block Allocate
BLOCK-EXECUTE           B-E     FS-2001: Syntax error
                                image: Block Execute
BLOCK-FREE              B-F     FS-2001: Syntax error
                                image: Block Free
BLOCK-READ              B-R     FS-2001: Syntax error
                                image: Block Read
BLOCK-WRITE             B-W     FS-2001: Syntax error
                                image: Block Write
BUFFER-POINTER          B-P     Buffer Pointer
COPYx:new=y:old         C       copy files (between internal drive "x" and "y") INITIALIZE              I       FS-2001: nothing
                                image:   read BAM
INITIALIZE:filename     I       FS-2001: use image to emulate floppy
                                image:   read BAM
M-E                             Memory Execute
M-R                             Memory Read
M-W                             Memory Write
NEW:name,id                     creates new empty image (default D64)
NEW:name                        empties image with that name
Pxxxx                           point to record
RENAME:new=old          R       rename file or directory
SCRATCH:name                    deletes a file from the HD/image
U0                              Restores jump-table ???
U1                              Block Read
U2                              Block Write
U3                              Jump to buffer 2
U4                              Jump to buffer 2 + offset 3
U5                              Jump to buffer 2 + offset 6
U6                              Jump to buffer 2 + offset 9
U7                              Jump to buffer 2 + offset $0C 
U8                              Jump to buffer 2 + offset $0F 
U9                              Jump to $FFFA   (warm start) 
U:                              RESET drive/image
UA                              Block Read
UB                              Block Write
UC                              Jump to buffer 2
UD                              Jump to buffer 2 + offset 3
UE                              Jump to buffer 2 + offset 6
UF                              Jump to buffer 2 + offset 9
UG                              Jump to buffer 2 + offset $0C 
UH                              Jump to buffer 2 + offset $0F 
UI                              Jump to $FFFA   (warm start) 
UJ                              RESET drive/image
VALIDATE                V       Validates the drive
  

New commands (proposals)
CHANGEDIR:directory     CD      change directory
DEFRAG                  DF      defragments the drive.
DELETE:name             DEL     same as SCRATCH
DELTREE:directory       DT      like the MS-DOS command 'deltree': deletes
                                complete directory incl. subdirectories
FORMAT                  FO      format harddisk
FORMAT:         FO      format partition
FTD:YYYY-MM-DD HH:MM:SS         Date/time-format
HIDE:name               HI      makes a file invisible for listings 
LOCK                    LO      locks a file
MAKEDIR                 MD      make subdirectory
REMOVEDIR               RD      remove empty (!) directory
SECTOR-ALLOCATE         S-A     image: Syntax error
                                FS-2001: Block Allocate
SECTOR-EXECUTE          S-E     image: Syntax error
                                FS-2001: Block Execute
SECTOR-FREE             S-F     image: Syntax error
                                FS-2001: Block Free
SECTOR-READ             S-R     image: Syntax error
                                FS-2001: Block Read
SECTOR-WRITE            S-W     image: Syntax error
                                FS-2001: Block Write
START                   SA      start harddisk
STOP                    SO      stop harddisk
TIMEDATE                TD      supplies date and time to host through
                                errormessage: "0, 2005-02-27 15:23:13, 0, 0"



UNHIDE:name             UH      makes file visible again
UNLOCK:name             UL      unlocks a file
XCOPY:new=old           XC      like MS-DOS command 'xcopy': copies complete
                                directories and subdirectories
The old floppy drives had TWO drives and they could be addressed separately by their drivenumber. You could even copy files from one drive to the other without the need of using the host computer as buffer: "COPY1:new_file=0:old_file". I'll see if it is possible to use this feature as well between partitions declared as separate drives.


How to handle more device/drive-numbers?

The HD-system can only handle one command a time. If it receives a command, it first has to check for which device/drive-number the command is meant. If it is a number supported by the drive, the system must prepare itself by first saving the momentary contents of the memory and registers of the processor. Then it must fill the registers and the original 2K-memory with the contents they had after executing the last command for this device. At the end of the action it must look as if nothing had happened at all between the new and previous command for the device now in charge of the system.





Having questions or comment? You want more Info?
You can email me here.