Floppy Disks

The Commodore 64 Floppy Disk

A while ago I became interested in looking into how some of the old Commodore 64 games used to work. This led me down a rabbit hole of looking into the old hardware and how disks encoded their information.

A lot of the old games used copy protection, which was implemented by writing things to the floppy disks in non standard ways, so that standard copy utilities would not be able to copy them successfully. When the game was loading, it would check if the disk contained the particular error and if it did not, then the software would know that this was a copy of the game rather than an original, so it would stop loading the game.

As I was eager to understand the games fully as they were written, this meant I started by looking at the disks themselves. In particular, how did they work and how was information stored on them.

The 5.25" Floppy Disk

A floppy disk consists of a thin flexible magnetic disk enclosed in a square 5.25" plastic case. The magnetic disk is a thin plastic base material coated in iron oxide. The oxide is ferromagnetic meaning that it can be permanently magnetised by exposing it to a magnetic field. This disk is sandwiched between two layers of fabric which were designed to reduce friction, static electricity and keep the disk clean.

The disk has a 1.6" (40 mm) hole in the center for the drive spindle to attach to and spin the magnetic disk. There is also a slot cut into the lower side of the disk to allow the magnetic heads of the drive to come in contact with the spinning disk. Many 5.25" disks also have a small 0.25" index hole cut into them so that a sensor can detect if the disk was rotating, however this is not used by 1541 Disk Drive that the Commodore 64 uses to read and write to the disks.

Disk Layout

Data is written to the disk in circular tracks that are spaced at a density of 48 Tracks Per Inch (TPI). The tracks do not physically exist on the disk before it is formatted as the disk itself is just a uniform ferromagnetic media. To read or write a track, the head of the disk drive is moved to specific offset and the disk is spun at 300 RPM, or 5 revolutions per second, under it. The circle formed at this head position is a track.

The Commodore 64 (and 1541 Disk Drive) used 35 tracks on the disk, although 40 were usable in practice. The outermost track is called track 1 and it is the longest, with a linear length of 420 mm. As you move towards the center of the disk, the tracks get smaller and smaller with track 40 measuring only 200 mm.

The disk rotates at a constant speed (300 RPM) however as the surface speed of the ferromagnetic media will be faster at the edge of the disk than at the center. This means that if the data is written to the disk at the same speed on the outer tracks as in the inner tracks, then the size of each bit will be larger the further out on the disk you go. This would waste space on the disk, and so to combat this, the disk is broken up into density zones.

Density Zones

The disk has four separate density or zones as follows where the speed at which the magnetic head reads bits is altered. On the outer tracks, a single bit lasts for 3.25 uS whereas in the inner tracks, the head writes slower at 4 uS per bit. The standard disk format for the Commodore 64 uses the following zone format:

ZoneTracksSpeedSectorsRaw Data
31 - 173.25 uS / bit217.7 kB
218-243.5 uS / bit197.1 kB
125 - 303.75 uS / bit186.7 kB
031 - 354 uS / bit176.3 kB

Total capacity of the disk is approximately 252kB gross however data written to the disk uses GCR encoding (see below) which has a 20% overhead. The standard format used by the Commodore 64 contains a total of 683 sectors of 256 bytes each and Track 18 is reserved for the disk managment structures of the filesystem. So as a result there are only 664 usable sectors (blocks) remain for use which provides 165 kB of space.

Encoding Data

The raw data is written to the disk by magnetising the iron oxide on the surface of the disk. A logical '1' is stored as a high frequency alternation of the magnetic field where as a logical '0' is represented by a constant magnetisation. The sensor in the disk head can detect these oscillating magnetic fields, however it if the field is steady for too long it will have trouble making a reading. Because of this limitation, the drive cannot reliably read more than two consecutive '0' bits. So to prevent this from happening, before data is written it is encoded using Group Coded Recording (GCR).

DataGCR codeDataGCR code
000001010100001001
000101011100111001
001010010101011010
001110011101111011
010001110110001101
010101111110111101
011010110111011110
011110111111110101

The GCR uses the above table to map 4 bits onto 5 bits ensuring that there are never more than two consecutive zeros or 8 consecutive ones. This ensures that the read head on the disk is able to reliabaly read the media.

Track and Sector format

Each track contains a sequence series of sectors and each sector is preceeded by a sector header. All of the data is encoded using the GCR however if the disk started reading at a random position, it would not be possible to work out the correct byte alignment of the data being read. In order to allow for correct byte alignment, each header and sector is preceded with a sync signal to allow the drive to correctly detect the start of a GCR frame. The sinc signal is a section of 10 or more consecutive '1' bits and on the Commodore 64, 40 were used in practice. The sync signal is followed by a magic byte ('08' for headers and '07' for sectors) to indicate the data type that follows.

A header is 8 bytes in size (10 bytes after GCR encoding) contains data in the following format:

Magic:    08     Sector header magic
Track:    01     Current track number
Sector:   00     Current sector number
ID:       4D 53  Unique disk ID.
Checksum: 1F     Track, Sector and ID
Padding:  0F 0F  for GCR alignment.

The disk ID is randomly set when the disk is formatted and the same value it written to every sector header. It is used by the disk drive to detect when a new disk has been is inserted.

The checksum is simply an XOR of all of the data values with the header (excluding the magic and padding). Following the header is a gap of 9 bytes then another Sync marker followed by the sector data. The sector contains:

Magic:    07 Sector data magic
Data:     48 45 CF 20 ... 
Checksum: CC - XOR of the data bytes
Padding:  00 00 - for GCR alignment

After the sector there is another gap of 7 bytes then the next Sector header starts. The gaps allow time for the disk drive to decode the header and also provides a safety margin so that when sectors are rewritten they do not overwrite any of the adjacent sectors.

All of the sector headers are written to the disk when it is formatted, but they stay static after formatting. When data is written to a disk, only the sector data sections are overwritten.