CP/M Disk Formats

I’ve updated the CP/M File System tool to support some additional disk formats. The tool allows you to copy files to and from the disk images that you use in CP/M emulators (see Edit CP/M Disk Image for details).

The disk types supported are now:

  • 8 = 8″ standard format CP/M disk.
  • 5 = 5″ not as standard; but common.
  • C5Q = CDOS format 5 inch DSDD disks.

Here’s some of the details of the disk image formats …

8 Inch

The 8 inch format was a standard that was used for passing programs and files around. Just about everybody supported this format. It’s only drawback was the limited storage. You could get about 241K on one, plus the operating system. Technically, it was 77 tracks, 26 sectors per track, 128 byte sectors. Disks were single-sided, single-density (SSSD).

CP/M used the first two tracks (track 0 and track 1). The directory was stored in the “first” 8 sectors of Track 2, and data followed that.

I used quotes around “first” because the standard was to skew sectors from track 2 onward by a factor of 6. On the disk they were written as sector 1, 2, …, 26; but CP/M accessed them in a different order. The idea behind it was simple and quite sensible: if it takes a little while to process a sector (do something with it), and the disk is spinning while you do that, then by the time you are ready for the next sector, you will have missed it! You have to wait for the disk to complete almost another full turn before sector 2 is underneath the read head again.

Here are a few lines from the CP/M BIOS assembly code:

;       sector translate vector
trans:  db      1,7,13,19       ;sectors 1,2,3,4
        db      25,5,11,17      ;sectors 5,6,7,8
        db      23,3,9,15       ;sectors 9,10,11,12
        db      21,2,8,14       ;sectors 13,14,15,16
        db      20,26,6,12      ;sectors 17,18,19,20
        db      18,24,4,10      ;sectors 21,22,23,24
        db      16,22           ;sectors 25,26


(From the Digital Research supplied CBIOS.ASM)

That means it reads and writes physical sectors in the order 1, 7, 13, 19, …, 16, 22.

All of the sectors on the track are accessed. They’re just not accessed in the order you’d first think of. That’s the skew factor. The computer has plenty of time to do things with sector 1 before it asks for the next sector, sector 7. If a drive was spinning the disk at about 300-360 RPM (from memory), and if there were 26 sectors per track, it would have 5 sectors between the end of sector 1 and the start of sector 7, or 5/26ths of a full rotation the disk. That is 5/26ths of 1/360 of a minute or 0.192 of 167 mS, about 32 mS. On a 2 MHz computer from that era, each clock cycle takes 0.5 uS so you could do 6,400 instructions (assuming 10 clock cycles per instruction) before you’re too late.

Disk images are direct copies of just that. They are the data on the disk, as it is on the disk. If you look through a disk image you’ll see files split up in the order stated in the CP/M BIOS.

With 128 bytes per sector, each sector occupies 80H of a binary dump of an image file. Every 100H is two sectors.

Here’s what the start of a bootable CP/M disk looks like:

Turbo Dump  Version 5.0.16.12 Copyright (c) 1988, 2000 Inprise Corporation
                     Display of File CPMA.CPM

000000: C3 19 00 42 4F 4F 54 3A  20 65 72 72 6F 72 20 62 ...BOOT: error b 
000010: 6F 6F 74 69 6E 67 0D 0A  00 01 02 00 16 32 21 00 ooting.......2!. 
000020: E4 AF D3 0A 78 D3 0B 79  D3 0C 7D D3 0F 7C D3 10 ....x..y..}..|.. 
000030: AF D3 0D DB 0D B7 CA 33  00 DB 0E B7 CA 4F 00 21 .......3.....O.! 
000040: 03 00 7E B7 CA 4D 00 D3  01 23 C3 42 00 F3 76 15 ..~..M...#.B..v. 
000050: CA 00 FA 31 80 00 39 0C  79 FE 1B DA 24 00 0E 01 ...1..9.y...$... 
000060: 04 C3 24 00 00 00 00 00  00 00 00 00 00 00 00 00 ..$............. 
000070: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 ................ 
000080: C3 5C E7 C3 58 E7 7F 00  20 20 20 20 20 20 20 20 .\..X...         
000090: 20 20 20 20 20 20 20 20  43 4F 50 59 52 49 47 48         COPYRIGH 
0000A0: 54 20 28 43 29 20 31 39  37 39 2C 20 44 49 47 49 T (C) 1979, DIGI 
0000B0: 54 41 4C 20 52 45 53 45  41 52 43 48 20 20 00 00 TAL RESEARCH  .. 
0000C0: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 ................ 
0000D0: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 ................ 
0000E0: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 ................ 
0000F0: 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 ................ 

That’s the boot sector (at 000000-00007F) and the first sector of CP/M (at 000080-0000FF).

The boot sector starts with a JMP to 0019 (this one runs from address 0 of memory) “C3 19 00”.

CP/M starts with a JMP to E75C (“C3 5C E7”). It is a 64K build of CP/M so it expects to be loaded at E400.

Subsequent sectors are sequential parts of CP/M because sectors from the system area of the disk are loaded sequentially. Note that the boot sector is just one sector and it has to get all of CP/M into memory. There’s 128 bytes to do that in and that’s not a lot of space for anything fancy like sector skewing.

Two tracks of 26 sectors per track is 52 sectors of system area. That covers 000000-0019FF.

The data area of the disk starts at 001A00 and here’s where you can see sector skewing:

001A00: 00 44 55 4D 50 20 20 20  20 43 4F 4D 00 00 00 03 .DUMP    COM.... 
001A10: 02 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 ................ 
001A20: 00 53 44 49 52 20 20 20  20 43 4F 4D 00 00 00 77 .SDIR    COM...w 
001A30: 08 17 1A 1B 1C A8 C7 C8  C9 CA CB CE E2 E3 EB 00 ................ 
001A40: 00 53 55 42 4D 49 54 20  20 43 4F 4D 00 00 00 0A .SUBMIT  COM.... 
001A50: 0B 0C 00 00 00 00 00 00  00 00 00 00 00 00 00 00 ................ 
001A60: 00 45 44 20 20 20 20 20  20 43 4F 4D 00 00 00 34 .ED      COM...4 
001A70: 10 11 12 13 14 15 16 00  00 00 00 00 00 00 00 00 ................ 

001A80: 20 69 66 20 28 69 20 26  20 28 31 3C 3C 35 29 29  if (i & (1<<5)) 
001A90: 20 70 2B 2B 3B 0D 0A 20  20 20 20 20 20 20 20 69  p++;..        i 
001AA0: 66 20 28 69 20 26 20 28  31 3C 3C 36 29 29 20 70 f (i & (1<<6)) p 
001AB0: 2B 2B 3B 0D 0A 20 20 20  20 20 20 20 20 69 66 20 ++;..        if  
001AC0: 28 69 20 26 20 28 31 3C  3C 37 29 29 20 70 2B 2B (i & (1<<7)) p++ 
001AD0: 3B 0D 0A 20 20 20 20 20  20 20 20 66 20 3D 20 69 ;..        f = i 
001AE0: 3F 28 69 26 53 46 29 3A  5A 46 3B 0D 0A 20 20 20 ?(i&SF):ZF;..    
001AF0: 20 20 20 20 20 66 20 7C  3D 20 28 69 20 26 20 28      f |= (i & ( 

001B00: 66 6C 6F 77 0D 0A 23 64  65 66 69 6E 65 20 58 46 flow..#define XF 
001B10: 20 30 78 30 38 20 20 20  20 20 20 20 20 20 20 20  0x08            
001B20: 20 20 2F 2F 20 75 6E 64  6F 63 75 6D 65 6E 74 65   // undocumente 
001B30: 64 20 62 69 74 20 33 0D  0A 23 64 65 66 69 6E 65 d bit 3..#define 
001B40: 20 48 46 20 30 78 31 30  20 20 20 20 20 20 20 20  HF 0x10         
001B50: 20 20 20 20 20 2F 2F 20  68 61 6C 66 2D 63 61 72      // half-car 
001B60: 72 79 0D 0A 23 64 65 66  69 6E 65 20 59 46 20 30 ry..#define YF 0 
001B70: 78 32 30 20 20 20 20 20  20 20 20 20 20 20 20 20 x20              

001B80: 20 44 69 73 6B 20 41 73  73 69 67 6E 6D 65 6E 74  Disk Assignment 
001B90: 00 57 72 6F 6E 67 20 43  50 2F 4D 20 56 65 72 73 .Wrong CP/M Vers 
001BA0: 69 6F 6E 20 28 52 65 71  75 69 72 65 73 20 32 2E ion (Requires 2. 
001BB0: 30 29 00 21 00 00 39 22  6B 15 21 8D 15 F9 CD ED 0).!..9"k.!..... 
001BC0: 04 FE 20 D2 4F 04 01 11  04 CD D2 04 C3 8B 04 21 .. .O..........! 
001BD0: 96 15 36 01 3A 5C 00 D6  00 D6 01 9F F5 3A 5D 00 ..6.:\.......:]. 
001BE0: D6 20 D6 01 9F C1 48 A1  1F D2 72 04 CD 33 0D C3 . ....H...r..3.. 
001BF0: 8B 04 3A 5C 00 FE 00 CA  80 04 CD 02 14 C3 8B 04 ..:\............ 

I've split the listing after each 80H (sector) so you can more easily see what's not sequential.

We start with the directory, as claimed, but then there's anything but directory. There's two sectors with text (related but the fragments don't flow) and then a sector of the middle of a program. The "next" directory sector is physical sector 7 (per the CBIOS above). That is at 001A00 + (sector 7 - sector 1 = 6)*80H = 001D00. Sure enough, that looks like more of the directory:

001D00: 00 53 54 41 54 20 20 20  20 43 4F 4D 00 00 00 28 .STAT    COM...( 
001D10: 09 18 DC DD DE 00 00 00  00 00 00 00 00 00 00 00 ................ 
001D20: 00 42 59 45 20 20 20 20  20 43 4F 4D 00 00 00 02 .BYE     COM.... 
001D30: 19 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 ................ 
001D40: 00 52 4D 41 43 20 20 20  20 43 4F 4D 00 00 00 6A .RMAC    COM...j 
001D50: 76 77 78 79 7A 7B 7C 7D  7E 7F 80 81 82 83 00 00 vwxyz{|}~....... 
001D60: 00 43 52 45 46 38 30 20  20 43 4F 4D 00 00 00 20 .CREF80  COM...  
001D70: 1D 1E 1F 20 00 00 00 00  00 00 00 00 00 00 00 00 ... ............ 

The "first" eight sectors of the data area are 1,7,13,19, 25,5,11,17.

Those are addresses: 001A00, 001D00, 002000, 002300, 002600, 001C00, 001F00, 002200 in a disk image.

The easiest way to view the right parts of the disk is to use the cpmfs.exe program and its "dir2" command. That will show you the File Control Blocks that aren't marked as deleted files.

5 Inch CP/M Disks

The 5 inch format wasn't quite as standard. If it was SSSD then it still had 128 byte sectors.

Due to the technology of the time, you could only fit 18 sectors on a track (they're smaller disks), so that was reasonably consistent across manufacturers too.

CP/M wouldn't fit in 2 tracks x 18 sectors x 128 bytes. That's only 36 sectors when we had 52 for CP/M on an 8" disk. A third track is needed in the system area of a 5 (and 1/4) inch disk so the standard was 3 tracks on 5" SSSD disks.

Drives seemed to come in 40 track versions, 35 track versions or 38 track versions.

Given that 3 tracks are used for the system area, even a 40 track drive only gave 37 x 18 x 128 bytes (=83.25 KB) of storage. If the directory used up 1K (or 2K in some variations), you were down to about 81 KB of storage per drive.

There was a lot of incentive to move to double sided drives and to introduce double density recording modes. Some people even punched an extra hole in the disk and simply turned them over for another 81 KB. With the trend towards change, a lot of variations occurred. There were questions like, "Do you read all of the sectors on one side before using the other head; or do you alternate sides" and "Does the extra side appear as 80 tracks or 36 sectors" or, "Is there a whole new command to the drive to set track, sector AND side?"

One easy option was to change the sector size. It was still 5". It was still single-sided. It didn't require any holes and manually turning the disk over at the end. It didn't require better technology to write more dense information. It just got rid of some of the overhead between the sectors.

You could go from 18 x 128 byte sectors to 10 x 512 byte sectors. A simple software change would give a 20% increase in storage.

All of these needs and ideas for improvement took the world forward but it made interoperability difficult. The standard 5" format was:

40 tracks, 18 sectors per track, 128 byte sectors, 3 system tracks for CP/M, 8 sectors (1 block) of directory entries, a skew factor of 5.

The skew table seems to have been: 1, 6, 11, 16, 3, 8, 13, 18, 5, 10, 15, 2, 7, 12, 17, 4, 9, 14.

CDOS 5 Inch DSDD Disks

CDOS was the Cromemco Disk Operating System. It was a CP/M look alike (and behave alike). The CDOS 2 Manual (023-0036) from 1980 puts it this way:

"The Cromemco Disk Operating System (CDOS) * is an original product designed and written in Z80 machine code by Cromemco, Inc. for its own line of microcomputers. However, due to the large number of programs currently available to run under the CP/M** operating system, CDOS was designed to be upwards CP/M-compatible. Cromemco is licensed by Digital Research, the originator of CP/M, for use of the CP/M data structures and user interface. This means that most programs written for CP/M (versions up to and including 1.3) will run without modification under CDOS. This also means that programs written for CDOS will not generally run under CP/M."

I quite liked CDOS. It seemed, to me, to be a more polished version of CP/M. No offense intended to anyone. The two catered for different markets with similar, but different requirements.

Given the CP/M compatability, CDOS would read and write CP/M disks. You could use standard 8" CP/M disks in a CDOS system. You could also use 5" SSSD CP/M floppies with a CDOS system.

Cromemco were very much an innovator and they moved to DSDD disks. However, they wanted to support their existing customers so they wanted disks that would still boot with existing hardware. The Cromemco systems had drive controller cards that connected to the floppy drives. The controller had a Read-Only Memory (ROM) that would boot a SSSD 8" disk or a SSSD 5" disk. It expected 26 sectors or 18 sectors, with each being 128 bytes. The new disks had a different number of sectors and a different sector size. The Resident Disk Operating System (RDOS) within the ROM was going to load the boot sector and more of it was going to keep coming after 128 bytes!

As a result, the CDOS disks of the time had an unusual format. All of the disks had a SSSD track 0.

This means a CDOS 5" DSDD disk has:

Track Sectors Size
0 18 128 bytes
1-39 10 512 bytes

That's a pretty strange combination for disk image programs to deal with. The usual approach of, "how many sectors per track" and "how many system tracks" doesn't work with imagers that record
what they get. In a disk image file you have 58 x 128 byte CP/M records (18 x 128 bytes + 10 x 4 x 128 bytes) of system area; yet, there are 2 reserved tracks and the stated "sectors per track" is 10. It is never going to add up if you use the usual parameters.

I rewrote my cpmfs.exe program to work in 128 byte records and to allow the system area to be specified as a number of records rather than a number of tracks. You can see the source code in cpmfs-0.02.c. It does successfully read and write files to/from a Windows environment from/to a CDOS disk image.

The skew factor is 4 which is a smaller number that makes sense given that there are only 10 sectors on a disk track and the Cromemco computers typically had 4 MHz CPUs at this stage instead of 2 MHz ones.

The skew table in cpmfs.c looks strange because 4 CP/M records are read sequentially (4 x 128 byte records = 1 x 512 byte sector) before any skew happens. In the program it looks like:

    int trans[] = { 
         0, 1, 2, 3, 16,17,18,19, 32,33,34,35,  8, 9,10,11,
        24,25,26,27,  4, 5, 6, 7, 20,21,22,23, 36,37,38,39,
        12,13,14,15, 28,29,30,31 };


That is sectors: 1, 5, 9, 3, 7, 2, 6, 10, 4, 8. Note: for the program's convenience, sectors are numbered from 0 (in the extract above) but on disk, all sectors are numbered from 1 (eg 1-26, 1-18, 1-10).

Different Skew Factors

The definitive reference on disk skew factors seems to be a macro in the 8080 Assembly language tools.

The Digital Research BIOS.ASM for CP/M 2.2 for the MDS-800 has:

maclib  diskdef	;load the disk definition library
        disks	4	;four disks
        diskdef	0,1,26,6,1024,243,64,64,offset
        diskdef	1,0
        diskdef	2,0
        diskdef	3,0

The diskdef macro is in CP/M file DISKDEF.LIB in the DRI CPM_2-2/UTILSRC collection. It basically:
- checks for the greatest common denominator (GCD) of sectors and skew
- notes that the sequence will repeat after sectors divided by that
- starts with a base of 0
- adds 1 to the base after every sectors/GCD items

So, for 26 and 6:
- the GCD is 2 (26/2=13, 6/2=3)
- the sequence repeats after every 13 sectors
- so we would have:

  1,  7, 13, 19, 25, (+6=31, -26=)
  5, 11, 17, 23, (+6=29, -26=)
  3,  9, 15, 21, (+6=27, -26=)
  1, ...


- it is repeating after 13 sectors so we add 1 to get:

  2,  8, 14, 20, 26, (+6=32, -26=)
  6, 12, 18, 24, (+6=30, -26=)
  4, 10, 16, 22, (+6=28, -26=)
  2, ...

If we hadn't now done all 26 sectors, we would have added 1 and continued.

This is how you can work out any combination of sectors and skew.

See also:
The old programs for new computers collection.
what-is-on-sector-1-cylinder-0-side-0

It's only fair to share...Share on FacebookTweet about this on TwitterShare on Google+Share on LinkedInShare on StumbleUponDigg thisPin on PinterestEmail this to someone

Leave a Reply

Your email address will not be published. Required fields are marked *