A big speedup can be get by using a program called read1581, which uses the Amiga's built-in 3½-inch drive to read 1581 disks. However, this doesn't help when you need to transfer data from the host system (in my case Amiga) to the C64 environment. The documentation in the read1581 (or copy1581) package mentioned that the author may later make a version which writes to 1581 disks. Unfortunately he hasn't made this kind of version, so I was encouraged to write my own.
Actually the whole thing started when I purchased a used 5¼-inch drive for my Amiga. I found a program named 1541 from aminet, which promised to read 1541-created disks with a 5¼-inch drive. However, I didn't quite get it to work, and finally read the documentation, which revealed that the disk spin rate would need to be decreased. I couldn't do this with my drive, because it does not have the appropriate trimmer capacitor (or resistor).
Adjustment was needed because the 1541 GCR disk format has four so-called speed zones, where the bit lengths are different. The length varies from 3µs to 4µs. However, this didn't stop me, because the source code was included. I used the Amiga disk hardware in 2µs mode to read from the drive at double speed and then tried to interpret the data. This was a moderate success, the program could successfully read the speed zones 0, 1 and 3 (sometimes retries were required), but still has troubles reading zone 2. The reason is a bit complicated, but basically it's because there are several possible interpretations for exactly the same input bit patterns and they are all right in different occasions. This was a fact I had to finally admit to myself. It just could not be done properly.
Anyway, fiddling with the 1541's GCR format led me to try to cure my many-year gripes about the read1851, which could only read 1581 disks. The Amiga disk hardware can read multiple disk formats because all it does is read the raw bitstream from the disk, the decoding is done in software. Whole tracks are read and written instead of single sectors. GCR or MFM, it doesn't matter, the encoding is pure software. And now I had an example source code I could experiment with.
If you copy c1581-handler to L:, change the mount file accordingly. If you have a 1581 disk in the drive, this will log in the disk and it will appear on the workbench. If you didn't have a disk in the drive, you can now insert one.
This "mount c0" must be done in the directory containing the handler (if you didn't move it to L:) so that it can be located by DOS.
The c1581 handler handles the MFM decoding and encoding itself, thus mfm.device is not used. Mountfiles C0 (unit 0), C1 (unit 1) and C2 (unit 2) are provided. These are for WB2.1+, but it should be easy to add "C0:" and "#" when adding to mountlist.
Currently you can't control the usage of disk buffers. "Addbuffers" shows the amount of memory allocated in 512-byte increments. The handler caches whole tracks, so you should expect values 1,20,40,etc. Aging is performed on the tracks, so if a track is not referenced in a while, it is flushed, I'm just not sure if the aging is fast (or slow) enough. Written data is flushed in each Close() and after 1.5-2s non-activity time.
LHA and some other compression programs have problems packing directly from the handler, because the actual file size and the size in the file info block do not match (a performance issue). Copy the files first, pack them later. The real drag about this is that LhA seems to succeed creating the packet, but actually generates a broken archive. Very nice, right?
Previously you could only format disks that were NOT 1581 disks. Now you can format any disk you want, provided you use "format quick". This is because otherwise the format command tries to use the trackdisk.device to do a low-level format first, which will fail.
Because you are beta-testing this handler (and even if you weren't), please comment on
Just fearlessly mail albert@cs.tut.fi, and reveal your thoughts. Please, let me know!
Error handling is improved. Disk removal while writing now causes a "Must replace disk" requestor.
Doslist is now properly locked for volumenode insertions and deletions. I hope this fixes the lockup problems on some OS3.1 machines. Also, Inhibit() now handles "more Uninhibits than Inhibits" scenarios better, i.e. you can mount the handler from devs:dosdrivers now. (Remember to correct the handler location in the mount file.)
I also added a separate program 1581 to read and write disk images,
as adding disk image support to the handler seemed more problematic
than it was worth.
1581 0 file - reads from drive 0 to file
1581 1 file write - writes to drive 1 from file
Performs verify on write and handles disk removal while writing or reading.
Real file sizes are reported when directly examining a file. i.e. "dir c0:" shows rouded-up sizes for files, while "dir c0:file" shows the actual size of "file". Unfortunately, this doesn't cure the problem with LhA and other compression programs, unless you list the files separately (lha a pack c0:file1 c1:file2) instead of using wildcard patterns.
Now returns secondary error 0 in ParentDir() call for disk root directories. Now you can change current directory to the handler in AmigaDOS shell also (i.e. you can "cd" to the handler.) and not only get strange error messages.
You can now format 1581 disks also.
'Direct-access', i.e. disk image copying "with copy c0:«zzz» c1:«zzz»" («zzz» to be decided) ("cat c0: >file" already works)
Maybe a separate disk editor/repair program?.
Relative file read/write (actually, read works just as PRG/SEQ/USR).
In addition to valid GCR data we need some kind of a marker, sync, to tell us where the sector headers and sector data blocks start. In GCR a long run of 1-bits is used. At least 16 consequtive 1-bits are used as a sync mark.
Nybble GCR 0 0 0000 01010 a 10 1 1 0001 01011 b 11 2 2 0010 10010 12 18 3 3 0011 10011 13 19 4 4 0100 01110 e 14 5 5 0101 01111 f 15 6 6 0110 10110 16 22 7 7 0111 10111 17 23 8 8 1000 01001 9 9 9 9 1001 11001 19 25 a 10 1010 11010 1a 26 b 11 1011 11011 1b 27 c 12 1100 01101 d 13 d 13 1101 11101 1d 29 e 14 1110 11110 1e 30 f 15 1111 10101 15 21
1541 sectors: SYNC 0x08 csum sector track id1 id2 GAP SYNC 0x07 (256 x data) csum GAPEach sector has two parts: header and data. If there is a 0x08 after a sync mark, it is a sector header, if there is 0x07, it's the sector data itself. Both parts have a checksum, which is calculated from the contents by xor:ing them together. For example if (csum^sector^track^id1^id2) is not zero, there is an error in the data. Because the bit length changes depending on the speed zone, there are more sectors on some tracks than there are on others.
0 0 0 0 0 1 0 1 0 0 1 1 1 0 1 1 1 0 1 1 1 x01010x x010010 x00100x x001010 0100010 010100x 0101010
sync: 0100 0100 1000 1001 ($4489) 1 0 1 0 0^0 0 1 | `-- 'invalid' MFM, should be 1
1581 track: 10 sectors: 10x (3x $4489 + header + 3x $4489 + sector ) + pad 10x (3x 16 b + 656 b + 3x 16 b + 8992 b ) + 2785 b = 97440 + 2785 10x (SYNC + 7+34B + SYNC + 515+47B) + pad header: ident 0xfe track side (1=down, 0=up) sector sector size (2=512 bytes) crc1 crc2 sector: ident 0xfb 512 bytes of data crc1 crc2Even though the c1581 file system handles the disk as 3200 256-byte sectors, the actual physical format is 80 tracks, 2 sides, 10 512-byte sectors each. Three sync marks ($4489) are used before header and sector data. An identification byte tells whether it is a sector header or sector data.
CRC is calculated from the whole contents, including the ident byte, and the result should be zero. The same CRC polynomial as in Y-modem, Z-modem etc. is used. The curiosity is that the initial value (shift register state) of 0xe59a must be used.