5

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.

3 Answers 3

6

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.

6
  • 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, 2020 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, 2020 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, 2020 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, 2020 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, 2020 at 9:04
4

+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

1
  • 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, 2020 at 9:24
3

I know this is an old thread, but I've recently come across the same problem.

In the end, I realized that there are three possible disk formats I need to be aware of, so I write my disk initialisation logic as per below;

  1. Amstrad T0S0 DIB is in place - Follow it. ( Test for E5's and Filenames first )
  2. Amstrad T0S0 is all E5 bytes ( 229 dec ). Assume default Amstrad config.
  3. Amstrad T0S0 contains directory - Look for an ASCII Valid directory character in second byte of S0. Assume default Amstrad config with 0 reserved tracks.

My CP/M DSK reader works OK now under Windows 10 and I can move files between images, and work with CP/M files.

I can work with very large disks also, but haven't worked out if the +3 can accept an extent > 16Kb yet. But all my file operations seem to work.

However I too found the concept of looking for a valid filename as unsatisfactory in this process, even though it's trivial. Just curious if anyone found a more predictable way. ( I'm probably going to have to reverse engineer the ROM at this rate to find my answer otherwise. )

Thanks David

2
  • Welcome to Retrocomputing Stack Exchange. Please read the tour. We're not like most forums; answers are expected to be self-contained answers (see How to Answer) and follow-up questions should be posted as separate questions (see How to Answer). It would be good if you could elaborate on your answer, and split off the new question as a separate post.
    – wizzwizz4
    Jan 28, 2022 at 21:04
  • I recommend registering an account, but if you can't get back into your unregistered one, it's fine if you submit a suggested edit to this answer. We'll know to approve it. (Once you have a registered account, or technically even if you don't have one, you can request the accounts to be merged using the contact form, also available at the bottom of every page.)
    – wizzwizz4
    Jan 28, 2022 at 21:05

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .