I'm trying to parse Spectrum +3 disk images. I only ever had a tape-based Speccy back in the day.

The +3 had a built-in floppy drive but was late to the party and not that successful. It had the same drive as the Amstrad CPC/PCW and the same layout as the latter, based on CP/M.

On the images I have that have directories they seem to be located on either the first or second sector. But I can't find anything in the on-disk structures, or in the docs I've found on the internet to indicate where the directory will be.

Some disks even don't have a directory but I know some of the disk images are of protected games so they could have purposely confusing disk layouts that load correctly but confused crackers and pirates back in the day.

Perhaps it's simply that the directory is in the first sector if there's no bootblock and in the second if there is a bootblock? I haven't been able to find confirmation of this theory though. Also, I'm having trouble detecting presence of bootblocks and just posted a separate question on that topic.

If it makes a difference, I'm using DSK and EDSK format disk images files.


It's probably best to take a look at the +3DOS DD_LOGIN function, since that's the ultimate source for how a +3 identifies a disc. What this does is:

  1. Call DD_SEL_FORMAT with A=0 to select the standard +3 format (180k, single sided, with one system track).
  2. Call DD_READ_ID with D=0 to read the identity of a sector (any sector) on track 0 of the disc.
  3. Look at the top two bits of the value returned. If they are 0,1 (ie, the sector ID is 40h-7Fh) then the disc is in CPC system format. Call DD_SEL_FORMAT with A=1 to select this format, and return.
  4. If the top two bits of the sector ID are 1,1 (ie, the sector ID is 0C0h-0FFh) then the disc is in CPC data format. Call DD_SEL_FORMAT with A=2 to select this format, and return.
  5. If neither of the above two cases were true, load the boot sector (cylinder 0, head 0, sector 1). [In fact, this uses a specialised read function that only reads the first ten bytes of the sector].
  6. If the first ten bytes of the sector are all the same, assume that they are 00h,00h,28h,09h,02h,01h,03h,02h,2Ah,52h (this defines a standard +3-format floppy).
  7. Call DD_L_XDPB to calculate the drive and filesystem parameters from the 10-byte specification.

The meanings of the 10-byte specification can be found in the documentation of the DD_L_DPB function in, for example, the Spectrum +3 CP/M manual.

  • Ah so even the checksum is checked outside this? It must be used only for deciding if sector zero has executable boot code, and not to distinguish whether the header. The 10 bytes are part of the 16-byte header/struct that's been confusing me. The next five are officially unused, and the last is that pesky checksum. May 1 '20 at 0:31
  • John, there seems to be one more trick needed to find the start of the directory. The above method finds the correct blocks, but often the space where the first entry would be holds instead the disk specification, so the directory starts 32 bytes later. How is this taken into account? in DD_L_XDPB or perhaps in DOS_CATALOG? May 10 '20 at 23:51
  • The disk specification will only coincide with the first directory entry when there are no system tracks. There's no special code in +3DOS to handle this scenario, since the only 'standard' Amstrad format with no system tracks is the CPC Data format, which has its own method of detection. If you do encounter a disk like this, the directory isn't moved by 32 bytes - you just have to ignore the first entry if it looks like a disk spec (first byte 0 or 3, second byte 0-3 or 80h-83h is a good guess).
    – john_e
    May 11 '20 at 7:42
  • Yes two of the DSK files I've downloaded, Tetris (Mirrorsoft) and ZxZvm Infocom Sampler 1, use CPC data format and have this prolem. The Speccy emulators don't list the disk spec entry when I do cat but all other files are listed. I haven't been parsing the directory entries yet though other than extracting the filenames, and I haven't tried tracing through the ROM disassembly to see what it does. Working on those is tonight's mission... May 11 '20 at 7:58
  • 1
    A CPC data format disk wouldn't show the entry, because the first byte of the disk spec would be 2 - so it would only show if you asked to list files for user 2 (CAT "2A:")
    – john_e
    May 11 '20 at 9:04

+3 disks are actually CP/M disks. Disk organization details are stored in the XDPB table, which is generated by the firmware from the data found at the beginning of the disk. This can be read on part 27 of the +3 manual:

The PCW range disk format (used by the +3) is, in fact, a family of formats the precise member of which is defined in the 'disk specification' which is recorded on bytes 0...15 of sector 1, track 0 side 0. The format used on the +3 is the same as disk type 0 below. The sector holding this specification is also that used for a bootstrap program.

This paragraph also mentions the bootstrap program. On part 26, this can be read:

bootstart: ; ;The bootstrap sector contains the 16 bytes disk
specification at the start. ;The following values are for a AMSTRAD
PCW range CF2/Spectrum +3 format disk. ;

               db   0                   ;+3 format
               db   0                   ;single sided
               db   40                  ;40 tracks per side
               db   9                   ;9 sectors per track

               db   2                   ;log2(512)-7 = sector size
               db   1                   ;1 reserved track
               db   3                   ;blocks
               db   2                   ;2 directory blocks

               db   02Ah                ;gap length (r/w)
               db   052h                ;page length (format)
               ds   5,0                 ;5 reserved bytes

cksum:         db   0         ;checksum must = 3 mod 256 for the sector

A non bootable disk will have 0 reserved tracks and hence, the directory area is what will come first.

By default, a standard data disk (non system, non bootable) have 64 directory entries, and these begin at track 0, sector 1 (sector numbers begin at 1), so the directory area lies in the first 2KB of the disk.

A directory entry is 32 bytes within the directory area, but unlike FAT, there can be multiple directory entries per file. Each entry is called a "extent".

A extent is made from several records. A record is 128 bytes long. A extent may use all its records or only a fraction of them.

If a extent uses all its records, this may mean that you need to search if there is another extent for this file. A record is used completely and there is no length field in the directory entry, so you must assume that all filled records belong to the file, or in other words, that a file length is always a multiple of 128.

A file is read by scanning the directory area for extents that belong to the same filename. Each extent has an extent counter so you can read them in asceding order.

Details can be read from the +3 manual (part 27): http://www.worldofspectrum.org/ZXSpectrum128+3Manual/chapter8pt27.html and here: https://www.seasip.info/Cpm/format22.html .

About 10 years ago I wrote a piece of software that can handle CP/M disks (IDEDOS partitions, which are actually (very) big CP/M disks). It's called "3e", and you can check the source: http://www.zxprojects.com/images/stories/3e_card_manager/3e.zip

  • The problem seems to be that only bootable (and system?) disks have the "disk specification" that would spell all this out. Other disks use these same 16 bytes for half of the first 32-byte directory entry. Is the trick to determine which of the two occupies this 16-byte area? If it makes a difference I'm working with "extended" DSK disk image files aka EDSK files. Apr 30 '20 at 9:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.