The FAT filesystem in 16-bit CP/M-86
Concurrent CP/M 3.1 and later, and single-user CP/M-86 with BDOS 3.3 and later (including DOS Plus), allow CP/M programs to access DOS-formatted discs via conventional BDOS calls, emulating (as far as possible) the behaviour of a normal CP/M filesystem. The behaviour is probably a good starting point for anyone writing a CP/M emulator which uses a hierarchical or non-CP/M filesystem.
Test for DOS media
The test used by the DOS Plus utilities is to perform a Search First (BDOS function 11h) with the first 12 bytes of the FCB containing '?' marks. On a DOS disc, this will return a "disc label" directory entry, and byte 0Fh of this entry will be 80h. On a CP/M disc, it may or may not return the label, but if it does byte 0Fh of the label entry will be zero.
FCB functions in general
If bit 7 of the "drive" byte in the FCB is set, then the call is assumed to apply to directories rather than files. The following calls appear to support directories:
- Open. Changes to the specified subdirectory (can be ".."). The Extent byte should be 0 to set the current directory, or 1-3 to set a "floating" drive (N: O: or P:) to the specified directory.
- Close. Changes to the root directory.
- Search first. Will return directories and files.
- Search next.
- Delete. Will remove a subdirectory if it is empty.
- Create. Creates a new subdirectory.
FCB functions behave normally, but the allocation area (16 bytes at FCB+10h) contains the following data:
fl fl of 00 cc cc ci ci dd dd cl cl le le le le ................ Where: fl = flags: d7 always set d6 set if file is a directory d5 set if file is hidden d4-d0 are high bits of file number of = file number, low 8 bits. Number is 0 for 1st dir entry, 1 for 2nd, etc. cc = current cluster, 0 if none ci = index of current cluster (0, 1, 2, ...) in file chain. Only meaningful if cc is nonzero. dd = DOS date cl = DOS cluster le = DOS length
Functions 11h and 12h
Functions 11h and 12h will return a fake directory record with:
- Entry 0 holding the file data:
uu F1 F2 F3 F4 F5 F6 F7 F8 T1 T2 T3 ex s1 s2 rc .FILENAMETYP.... fl fl of 00 00 00 tt tt dd dd cl cl le le le le ................ Where: uu = current CP/M user number, or 20h for volume label. ex = simulated extent number, 0-31. s1 = Last record byte count. s2 = simulated extent number, high bits. rc = simulated record count. fl = flags: d7 always set (thus "block" number is either >80h (8bit blocks) or >8000h (16bit blocks) d6 set if file is a directory (only shows up with user "?" in search FCB, or if bit 7 is set in FCB "drive" byte) d5 set if file is hidden d4-d0 are high bits of file number of = file number, low 8 bits. Number is 0 for 1st dir entry, 1 for 2nd, etc. tt = DOS time dd = DOS date cl = DOS cluster le = DOS length
- Entries 1 & 2 blank
- Entry 3 holding SFCB
The emulation goes to some pains to ensure that if a '?' is in byte 0Ch of the search FCB, a suitable list of "extents" is returned.
The XIOS returns an Extended DPB (call it an EDPB) for DOS media:
DW extflag ;On a DOS disc, this will be -1 for FAT12 ;and -2 for FAT16 (CCP/M-86 3.1 only supports FAT12). ;On a CP/M-86 disc, a normal DPB is returned, and ;this will be its SPT (Sectors per track) entry. DW nfats ;Number of FATs (normally 2) DW nfatrecs ;The number of physical sectors per FAT. DW nclstrs ;The number of clusters on the disc. DW clsize ;The number of bytes per cluster. DW fatadd ;The number of the sector holding the start of ;the first FAT. ; ; followed by a CP/M DPB: ; DW spt ;Physical sectors per track DB bsh ;Block shift. 3 => 1k, 4 => 2k, 5 => 4k, ... DB blm ;Block mask. 7 => 1k, 0Fh => 2k, 1Fh => 4k,... DB exm ;Extent mask. Must be 0 for DOS media. DW dsm ;Number of clusters - 1 DW drm ;Root directory entries - 1 DB al0 ;Not used for DOS media DB al1 ;Not used for DOS media DW cks ;Checksum vector size: 0 or 8000h for a fixed disc, ;else number of (root directory entries)/4,rounded up DW off ;Number of reserved tracks DB psh ;Physical sector shift 0 => 128-byte sectors, ;1 => 256-byte sectors, 2 => 512-byte sectors,... DB prm ;Physical record mask 0 => 128-byte sectors, ;1 => 256-byte sectors, 3 => 512-byte sectors,...
The BDOS returns the normal DPB rather than the EDPB to function 1Fh, so this function can't be used to detect DOS-formatted discs.
John Elliott 16 July 2005