As a BBC Micro enthusiast, I've got loads of DFS and ADFS floppy disks.
I'm fortunate in that I still have a BBC Master 128 in service, but some
of the data on the disks is useful to have on my day-to-day platform -
which is Linux. So I set about trying to read the disks...
My testing has mainly been with 3.5" floppies, although I've had
success with these methods on an old machine with a 5.25" drive.
I had a read about kernel modules, looked at the source code for the floppy driver, and decided I needed more time... Two of the challenges are:
I then came across libdsk, a library for accessing discs and disc image files. This seems to be just the ticket, built it and read an ADFS disk to an image file in about 5 minutes!
acorn160 | 40 track single-sided (S) |
acorn320 | 80 track single-sided (M) |
acorn640 | 80 track double-sided (L) |
acorn800 | 80 track double sided, 5 sectors of 1024 bytes. This covers the 'D' and 'E' ADFS formats which appeared with the Archimedes. The same format was also available for DOS Plus (but not ADFS) on the Master 512 |
acorn1600 | This is, I believe, the 'F' AFDS format disk - High Density on the Archimedes. |
Initially I was sceptical: back in the early 1990s I'd looked at the circuit diagram of an 80286 PC clone and seen that the 'density select' pin of the FDC chip was hard-wired to ground - disabling single-density. It was only after someone had told me that 'OmniFlop' on some other sort of OS for PCs (i.e. not Linux, FreeBSD, OpenBSD, NetBSD, Solaris x86, ...) could read DFS disks that I looked into it again. My 'dmesg' tells me "FDC 0 is a post-1991 82077", so I found the data sheet on the 82077 and it supports single density - that's a start (unless you have a 82077AA, which doesn't do single density). And dsktrans mentions two 'bbc' formats (in addition to the 'acorn' ones - interesting difference in labelling).
Pop an 80 track DFS disk in the floppy drive, do
dsktrans /dev/fd0 dfs.raw -otype raw -format bbc200 and blow me,
there's 'dfs.raw' as an image of the DFS disk!
It looks like are 2 DFS formats supported by dsktrans:
bbc100 | 40 track |
bbc200 | 80 track |
If you're using a version of libdsk which is version 1.1.3 or later (at the time of writing, 1.0.0 is the stable version) then there is a -retry <count> option which I've been told helps with some floppy disks.
Well, it can be done. We need to use setfdprm to set the parameters of
the floppy driver to match the floppy disk. Now there are (at least) 2
different setfdprm programs around: my Fedora Core machines used to
provide one in /usr/bin from the 'util-linux' package; and there's a
different one provided by the fdutils
software which Debian provide as the 'fdutils' package. I guess they both
can do the same thing (as they are merely doing an ioctl() call to the floppy
driver), but the setfdprm from fdutils is easier to understand (once you've
found the documention for it!) because it has easy-to-remember parameters.
So I'm going to assume that you have the fdutils software available.
'setfdprm' (to set the floppy drive parameters) has a matching 'getfdprm' command to read the floppy drive parameters. It's worth running 'getfdprm' after a 'setfdprm' (at least while you're getting used to things) to verify that the floppy drive parameters have been set as you expected. I've had the odd occasion when 'setfdprm' failed to set the parameters correctly.
Pop a disk in the floppy drive. Now, for an ADFS 'L' format disk, issue
the command:
setfdprm /dev/fd0 dd sect=16 head=2 cyl=80 ssize=256 zerobased
The floppy drive should blip its motor, and the disk is mounted. Now
you can use 'dd' to copy the disk to a file (OK, we did that with the
libdsk software, but now we are using native Unix commands). You can use
the blocksize option to dd to speed up the transfer, and the count option
to limit the copy to a number of blocks (e.g. bs=256 count=1
will just get the first sector).
Now there's one slight problem, which only applies to 'L' format disks.
They are 80 tracks, double sided, and the Acorn sector order is to read all
the tracks on the first side, followed by all the tracks on the second side.
However, the Linux floppy driver reads track N on the first side, then
track N on the second side, then track N+1 on the first side, ... So the
disk image has the two sides interleaved, which is a bit of a drag.
ADFS 'M' format.
This is a single-sided format, using only the first side. So
setfdprm /dev/fd0 dd sect=16 cyl=80 head=1 ssize=256 zerobased
does the right thing, and no worrying about interleaving.
In fact, if you have a 'L' format floppy which doesn't use space above
track 79, you could pretend that it's a 'M' format floppy and avoid the
interleaving problem.
ADFS 'S' format.
This is also a single-sided format, for 40 track drives. We need to
double-step the Linux drive - so I believe what's needed is:
setfdprm /dev/fd0 dd sect=16 cyl=80 head=1 ssize=256 zerobased stretch
but I haven't tested this.
ADFS 'D' format.
I believe this should need:
setfdprm /dev/fd0 dd sect=5 head=2 cyl=80 ssize=1024 zerobased
but I have no way of checking this.
ADFS 'F' format.
Murray Colpman kindly informed me that the command needed for this is:
setfdprm /dev/fd0 hd sect=10 head=2 cyl=80 ssize=1024 zerobased
This will enable 'F' format floppy disks to be mounted using the kernel ADFS driver.
Pop a disk in the floppy drive. For the first side (Acorn drive 0), issue
the command:
setfdprm /dev/fd0 sd sect=10 head=1 cyl=80 ssize=256 zerobased
The floppy drive should blip its motor again, and you can now use dd as before.
For the second side ('drive 1'), issue the command:
setfdprm /dev/fd0 sd sect=10 head=1 cyl=80 ssize=256 zerobased swapsides
DFS floppies are always single-sided, so we don't have any interleaving problem.
Note you may need to use the dtr=2 parameter (to set the data
transfer rate). My first attempts to read DFS floppies always failed, and
I found that after setting 'dtr=2' my attempts always worked.
However my most recent testing with 5.25" floppies in old hardware running
Debian have shown that 'dtr=2' prevents reading the DFS floppies, and that
not using the parameter is the right thing to do.
I've found that reading DFS disks is slow. Painfully slow in fact. But it works!
I've written an old-map ADFS module using Fuse, written in Perl which gives you read-only access to the ADFS filesystem on an image file or floppy drive as if it were a native filing system. It only supports old-map ADFS (i.e. the ADFS on 6502-based machines, and the 'D' format introduced with the Archimedes).
There's also David Boddie's
ADFS module written in Python using FUSE, although it tries to decode the
load/execution addresses as timestamps (which is OK for 'D', 'E', and 'F'
formats but not for 'S', 'M', and 'L' formats).
Having written the ADFS FUSE module, it seemed only logical to do the same
for DFS. So I wrote DFS module using Fuse,
written in Perl, which gives you read-only access to the DFS
filesystem on an image file or floppy drive as if it were a native filing
system. Copes with Acorn, Watford, and Solidisk DFS, including
double-density, and also copes with the dual-catalog '*SWAP' feature
from Disk Doctor.
See if the floppy driver can be patched to have an option (perhaps via the
'stretch' parameter ?) for "do 'tracks then heads' rather than 'heads than
tracks'".
And there's my 20 MByte Hard Disk on the BBC Master 128. The Adaptec ACB4000
board presents a SCSI interface, so if I plugged it into the 50 pin bus on my
SCSI controller on a Linux box.... 256 byte sectors again though...
What's next ?
There's a file named /etc/fdprm provided by the 'util-linux' package,
which defines known floppy formats. It would be great to get the BBC format
disks added to this file, so one could use a construct like
"setfdprm /dev/fd0 ADFS_L".
Andrew Benham (G8FSL), Salisbury, Wilts SP1, United Kingdom