Disclaimer: I make no warranties as to the accuracy of the information below. I am simply citing from Beneath Apple DOS, copyright (c) 1981 by Quality Software (RIP). --------------------------------- DATA STRUCTURE ON THE DISK MEDIUM --------------------------------- Under DOS 3.3 and ProDOS formatted systems (I'm not sure about HFS) the structure of disk data is the same. The following is the general format of disk data: GAP1 ADDRESS0 GAP2 DATA0 GAP3 ADDRESS1 GAP2 DATA1 GAP3 ... The fields are as follows: GAP1 contains HEX $FF self sync bytes (discussed below.) Typically, there are anywhere between 40 and 95. ADDRESS0 contains address prologue, volume, track number, sector number, checksum, and epilogue fields. The address prologue has the HEX values of D5 AA 96. The epilogue field has the HEX values of DE AA EB. All of the other fields are two bytes wide and subject to 4 and 4 encoding (the simplest kind.) GAP2 also contains HEX $FF self sync bytes. There are 5 to 10 bytes in this field. DATA0 contains data prologue, data, checksum, and epilogue fields. The data prologue has the HEX values of D5 AA AD. The epilogue has the HEX values of DE AA EB. The data field is subject to 6 and 2 encoding and the checksum is a literal value. See NOTE below about the length of this field. GAP3 contains HEX $FF self sync bytes. There are 14 to 24 bytes in this field. NOTE: There are 342 data bytes in a 6 and 2 encoded format; in DOS 3.2.1 and previous, the data field contained 410 bytes because it used a 5 and 3 encoded format. NOTE: Also note that ProDOS (and Apple Pascal, too, I believe) use two sectors consecutive sectors to form one disk block. If memory serves, HFS partitions use a disk block of size 524 (instead of 256 * 2 = 512) bytes--can anyone confirm this? --------------------------------------------- SELF SYNC BYTES: GETTING THE HARDWARE IN SYNC --------------------------------------------- When you begin a read (or write) operation, it is impossible to tell if the disk head is at the beginning, middle, or end of a byte. This problem requires that some sort of mechanism be in place to let the software know that it is "in sync" with the hardware. Self sync bytes are special kind of byte to help the software remain in sync with the where it is on the disk. It is the method for the operating system to know that it is not reading data from the middle of a byte of the above mentioned fields; such a situation would result in rather bizaare data and would probably be devasting to your system. The HEX $FF self sync byte differs from a regular HEX $FF byte in that it is 10 bits long. The operating systems assume that it has read a complete byte only when the most significant bit of a byte is set. On the other side of the coin, the operating system must ensure that it writes bytes to disk with the most significant bit set--an encoding (and sometimes translation) scheme must be applied. Suppose that you have the following bit streams on a disk: 0110101110101100111101101110101 As disk head moves across the stream during a read operation, bits are shifted into the data latch. Starting from the left-most position, bits would be read and the data latch would evolve as follows: 0000 0000 (initial state) 0000 0000 (shift the zero bit in) 0000 0001 0000 0011 (...) 1101 0111 (final identified byte) NOTE: The byte is NOT 0110 1011 as you might have expected because the high bit would still be clear; therefore, another bit must be read (and the data latch shift left) until the high bit becomes set. This is where the need for HEX $FF self sync bytes comes in. The bit stream of several consecutive self sync bytes follows: 1111111100111111110011111111001111111100111111110011111111001111111100 ^ Suppose that the read position started where the carret sign is. The data latch would progress to fill with the following byte. 1110 0111 1111111100111111110011111111001111111100111111110011111111001111111100 ^ The read position is again where the carret is. The data latch again: 1111 1001 Once again: 1111111100111111110011111111001111111100111111110011111111001111111100 ^ 1111 1110 And again: 1111111100111111110011111111001111111100111111110011111111001111111100 ^ 1111 1111 (remeber that a byte isn't a byte without bit 7 set) This is the turning point; from this moment on, all bytes read into the data latch will be HEX $FF. The software is now synchronized with the starting points of bytes on the disk medium. ---------------------------------------------- MAKE BYTES CONFORM TO DISK MEDIUM REQUIREMENTS ---------------------------------------------- Realistically, it is rather unlikely that all bytes to be read from (or written to) the disk medium are going to have their high bit set. Thus, encoding and decoding data (and sometimes translation) is a necessary requirement for the operating system. There are three types of encoding used by all of Apple's operating systems. They are 4 and 4, 5 and 3, and 6 and 2. All encoding requires the expansion of one byte to at least one byte and two bits. ---------------- 4 AND 4 ENCODING ---------------- 4 and 4 encoded bytes require two bytes (by splitting actual bits evenly between two bytes) and have the following format: 1 b7 1 b5 1 b3 1 b1 1 b6 1 b4 1 b2 1 b0 In order to get a usable data byte, it is necessary to shift the first byte left one bit cell, set the least significant bit in that byte, and logically AND the two bytes. Thus: b7 1 b5 1 b3 1 b1 1 (shift and logically OR 00000001) 1 b6 1 b4 1 b2 1 b0 ------------------------------ b7 b6 b5 b4 b3 b2 b1 b0 (logical AND of previous) 4 and 4 encoding is used only on the ADDRESSx section of disk data in the volume, track, sector, and checksum fields. The rationale behind it is that it is the speediest way to decode data so you can find out where you are on the disk quickly; other forms of encoding and decoding require translation first and last, respectively. Encoding bytes with the 4 and 4 method is accomplished by the following pseudo-code: load original data byte shift byte right one position logically OR with a bit mask of 10101010 save as first output byte load original data byte logically OR with a bit mask of 10101010 save as second output byte NOTE: The checksum field is the 4 and 4 encoded byte of the EXCLUSIVE OR of the byte representations of the previous fields (volume, track, and sector.) ---------------- 5 AND 3 ENCODING ---------------- 5 and 3 encoding has not been used since DOS 3.2.1. DOS 3.3 began the use of the 6 and 2 method; it is more memory efficient and makes the 5 and 3 method obsolete. It is probably not necessary for you to deal with the 5 and 3 scheme unless you want to write a file system translator for 13 sector/track DOS disks, so an explanation of 5 and 3 encoding has been omitted. ---------------- 6 AND 2 ENCODING ---------------- 6 and 2 encoding might seem rather complicated, but after digging, it is not as complex at it might seem to be. Suppose that you have read in (and translated) the 343 bytes (data field + checksum) of a sector into a buffer with the beginning of the buffer being represented by byte position HEX $000 and the end being represented by byte position HEX $156. The buffer would have the following appearance: $000: 0 0 a7 a6 a5 a4 a3 a2 $001: 0 0 b7 b6 b5 b4 b3 b2 $002: 0 0 c7 c6 c5 c4 c3 c2 $003: 0 0 | | | | | | $004: 0 0 | | | | | | $005: 0 0 v v v v v v $100: 0 0 < < $150: 0 0 ^ ^ ^ ^ ^ ^ $151: 0 0 | | | | | | $152: 0 0 | | | | | | $153: 0 0 | | | | | | $154: 0 0 | | | | c0 c1 $155: 0 0 | | | | b0 b1 $156: 0 0 | | | | a0 a1 The v's and ^'s means that the same pattern continues until $0FF and $100, respectively. The <'s mean that the pattern continues but is wrapped around to the next two bit cells at the bottom of the buffer. NOTE: The above figure only represents the data AFTER a proper read (or before a proper write) from (or to) the disk medium. See the next section for more details. -------------------------------------------------- ACTUAL READING FROM AND WRITING TO THE DISK MEDIUM -------------------------------------------------- In order to validate the integrity of the data in the data field of a disk sector, a checksum method is used. The method of acquiring a checksum requires a rather bizaare reading and writing algorithm-- probably the most difficult portion to grasp of all the information presented here. The checksum is acquire by logically EXCLUSIVELY ORing bytes in the encoded buffer. After the EXCLUSIVE OR, translation of bytes must take place before writing can begin; this is discussed later. The EXCLUSIVE ORing algorithm is rather strange in that the indexing used seems to jump around the buffer. Here is a chart of what happens during a writing session: buffer index disk data 0 \ > EOR ---> write translation ---> byte 000 $155 / $155 \ > EOR ---> write translation ---> byte 001 $154 / $154 \ > EOR ---> write translation ---> byte 002 $153 / (...) $101 \ > EOR ---> write translation ---> byte 085 $100 / $100 \ > EOR ---> write translation ---> byte 086 $000 / $000 \ > EOR ---> write translation ---> byte 087 $001 / $001 \ > EOR ---> write translation ---> byte 088 $002 / (...) $0FD \ > EOR ---> write translation ---> byte 340 $0FE / $0FE \ > EOR ---> write translation ---> byte 341 $0FF / $0FF CHKSUM ---> write translation ---> byte 342 Conversely, this is what happens during a read session: disk data buffer index byte 000 ---> read translation ---> EOR 0 ---> $155 byte 001 ---> read translation ---> EOR $155 ---> $154 byte 002 ---> read translation ---> EOR $154 ---> $153 (...) byte 085 ---> read translation ---> EOR $101 ---> $100 byte 086 ---> read translation ---> EOR $100 ---> $000 byte 087 ---> read translation ---> EOR $000 ---> $001 byte 088 ---> read translation ---> EOR $001 ---> $002 (...) byte 340 ---> read translation ---> EOR $0FD ---> $0FE byte 341 ---> read translation ---> EOR $0FE ---> $0FF byte 342 ---> read translation ---> EOR $0FF ---> 0 if data valid ----------------- TRANSLATING BYTES ----------------- Because of the 6 and 2 encoding scheme, the high bit of every byte is guarenteed to be clear. But, as the values of the each byte are limited between HEX $00 and HEX $3F, it is possible to translate each byte to another byte with its high bit set. Here is the 6 and 2 write translation table: 00 = 96 10 = B4 20 = D6 30 = ED 01 = 97 11 = B5 21 = D7 31 = EE 02 = 9A 12 = B6 22 = D9 32 = EF 03 = 9B 13 = B7 23 = DA 33 = F2 04 = 9D 14 = B9 24 = DB 34 = F3 05 = 9E 15 = BA 25 = DC 35 = F2 06 = 9F 16 = BB 26 = DD 36 = F5 07 = A6 17 = BC 27 = DE 37 = F6 08 = A7 18 = BD 28 = DF 38 = F7 09 = AB 19 = BE 29 = E5 39 = F9 0A = AC 1A = BF 2A = E6 3A = FA 0B = AD 1B = CB 2B = E7 3B = FB 0C = AE 1C = CD 2C = E9 3C = FC 0D = AF 1D = CE 2D = EA 3D = FD 0E = B2 1E = CF 2E = EB 3E = FE 0F = B3 1F = D3 2F = EC 3F = FF Reserved bytes are AA and D5. For the convenience of locating prologue fields as quickly as possible. The reverse of this table will give you a read tranlation table. ----------------------------- QUESTIONS I CAN'T ANSWER HERE ----------------------------- It is not explicitly stated in the Beneath Apple DOS manual as to how the boot sector is encoded. For the same drives to boot both 13 sectors/track DOS 3.2.1 disks and 16 sectors/track DOS 3.3 disks, it seems rather unclear as to what encoding scheme would be present in the firmware to overcome. Can the Apple IIc and Apple IIGS internal firmwares even handle booting DOS 3.2.1 disks directly? ------------------------------------------------------------------------ The information presented above is only of concern when working directly with Apple storage disk media. Smartport and SCSI drives don't require (allow?) you to access the hardware directly, so it does not apply. I hope that this information is as complete as you need it to be. Working directly with drive hardware is another task altogether, and I am not nearly confident enough with that information at this time to explain it. Perhaps in the future. ;-) -- Sean Dockery dockery@griffin.cuc.ab.ca sbdocker@acs.ucalgary.ca