I wrote about the Disk II self-sync pattern: > The controller doesn't care if there are a few extra zero bits between > the end of one nibble and the beginning of the next one. This is used > for the self-sync method. > > In 13-sector format, the self-sync pattern consists of a series of > self-sync nibbles that each have eight 1 bits followed by a single 0 bit > (total of nine bits each). If the controller starts attempting to read > at an arbitrary point in the sequence, the first byte it reads will > probably contain at least one 0 bit, rather than being the desired all > 1s pattern (hex FF). Because the zero bits can NEVER be interpreted as > the high bit of a nibble, as it reads each succeeding byte from the > controller, it will "catch up" to the point where it reads synchronized > FF bytes. > > In 16-sector format, the self-sync uses eight 1 bits followed by two 0 > bits (total of ten bits each). This allows the controller and software > to get in sync faster. Here is an example of the 9-bit self sync pattern, showing what happens if the controller starts reading at three of the nine possible positions: disk: 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 0 case 1: 1 1 1 1 1 1 1 1 \ / FF - in sync at outset case 2: 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 \ / \ / FE FF - in sync after first nibble case 3: 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 0 1 1 1 1 1 1 1 1 \ / \ / \ / FD FE FF -- in sync after second nibble For the remaining cases, it just takes more repetitions of the self-sync pattern. I'll only show them in hexadecimal: case 4: FB FD FE FF case 5: F7 FB FD FE FF case 6: 7F F7 FB FD FE FF case 7: DF 7F F7 FB FD FE FF case 8: BF DF 7F F7 FB FD FE FF case 9: (leading 0 bit discarded) FF The final case occurs if the the start of the read is at the 0 bit. Because the controller detects that it has read a full nibble by the most significant bit of the shift register being 1, a leading 0 will simply get shifted out and ignored. Thus synchronization is effectively already achieved as in case 1, but with about ~4 us delay. The result is that after reading at least seven nibbles of a self-sync area, synchronization is guaranteed. The 10-bit nibbles work similarly, but can guarantee sync after reading at least four nibbles. case 1: FF - in sync at outset case 2: FE FF case 3: FC FF case 4: F9 FE FF case 5: F3 FC FF case 6: E7 F9 FE FF case 7: CF F3 FC FF case 8: 9F E7 F9 FE FF case 9: (leading 00 bits discarded) FF - in sync case 10: (leading 0 bits discarded) FF Of course, the disk controller may start reading at any point, not just in a self-sync area. But it is only interested in finding an address mark (D5 AA 96). The self-sync area immediately precedes the address mark. The software just reads and discards nibbles until it sees the correct sequence of address mark nibbles; if it starts at some random point out of sync (which is likely), the self-sync area will force it into correct sync by the start of the address mark. Of course, if it starts reading in the middle of the address mark, or near the end of the self-sync area, it will fail to read that address mark correctly. But it will continue trying, and in the absence of disk errors will be able to read all of the subsequent address marks. As each address field is read, the track and sector number in the address field are compared with those in the I/O request. If they do not match, the software will go back to searching for the next address mark. If it was searching for the sector for which the address mark was initially read incorrectly, it will find it when it comes around again after slightly less than one full revolution. The software will time out if the desired address field is not found within some period of time. Reading a data mark works similarly. The data mark pattern for 16-sector ormat is D5 AA AD. There is a self-sync pattern before the data mark. The software (RWTS or equivalent) doesn't attempt to find the data mark until immediately after it has decoded the desired address mark, so it doesn't try for nearly as long. It would not be acceptable for it to read the data field of the wrong sector. Eric Smith wrote: >Reading a data mark works similarly. The data mark pattern for 16-sector >ormat is D5 AA AD. There is a self-sync pattern before the data mark. >The software (RWTS or equivalent) doesn't attempt to find the data mark >until immediately after it has decoded the desired address mark, so it >doesn't try for nearly as long. It would not be acceptable for it to >read the data field of the wrong sector. It is worth pointing out that no self-sync bytes would be needed before data marks if data fields were never re-written, since the state machine would stay in sync between the address and data fields. When a write to disk is done, the software reads, searching for the correct address mark and address, as when reading, but then it switches on the write head and (re-)writes the data self-sync nibbles, the data mark, the data, and the data epilog nibbles. (Actually, because of a bug, it only writes the first two epilog nibbles correctly, so the third epilog nibble is ignored on read.) Because switching on the write head cannot be guaranteed to be "coherent" with the previously written nibbles, new "lead-in" self- sync nibbles must be written to ensure that, when reading, the state machine will be correctly synchronized. More than the minimum required number of self-sync nibbles are written to create a "gap" to accomodate the write head switching and disk speed variations. -michael Check out parallel computing for 8-bit Apples on my Home page: http://members.aol.com/MJMahon/ In article , Eric Smith wrote: > The final case occurs if the the start of the read is at the 0 bit. Because > the controller detects that it has read a full nibble by the most significant > bit of the shift register being 1 No, the controller doesn't detect anything by the MSB being 1. The controller merely transfers whatever bits it reads off the disk into its 8-bit shift register. Then it's the responsibility of the software (i.e. RWTS) to read a valid nibble by reading the shift register at the appropriate time. It's a tight loop in the RWTS which decides when a valid nibble is in the shift register (= when the high bit is a 1): nibloop: LDA (addr_of_shift_reg),X BPL nibloop where X contains the disk controller slot number multiplied by 16. Note that there's no timeout or any other exit out of this loop if the high bit never should become 1 for some reason (e.g. hardware failure). There's no time for such "fancy" stuff if one wants to make sure to not miss any new bit which arrives in the shift register every 4'th clock cycle. After a new valid nibble has been read, one has some 30 clock cycles to do some other stuff, which in the RWTS of DOS, ProDOS, CP/M (yep, the RWTS of the various CP/M implementations of Apple II are all written in 6502 assembly) and most other OS'es is just storing the nibble in a buffer. The RWTS of Apple Pascal though mamanges to actually de-nibblize the data as well, so when the sector has been read, it's been de-nibblized as well, and the next sector can be read+denibblized "on the fly", enabling Apple Pascal to read one track in just one disk revolution. In the other Apple II OS'es de-nibblizing is done separately after the sector read -- and this causes the RWTS to miss the next sector on the disk, forcing a read of one entire track to take at least two disk revoutions. The fast RWTS read code of Apple Pascal has to pay a price though: that code is very large, compared to the much more compact RWTS'es of the other Apple II OS'es. The Apple Pascal RWTS uses a well-known loop optimization trick: if the loop is to always be executed a fixed number of times, it executes faster if it is replaced with linear code. This is called "loop unrolling". -- ---------------------------------------------------------------- Paul Schlyter, Grev Turegatan 40, SE-114 38 Stockholm, SWEDEN e-mail: pausch at stockholm dot bostream dot se WWW: http://www.stjarnhimlen.se/ http://home.tiscali.se/pausch/ Paul Schlyter wrote: >In article , >Eric Smith wrote: > >> The final case occurs if the the start of the read is at the 0 bit. Because >> the controller detects that it has read a full nibble by the most significant >> bit of the shift register being 1 > >No, the controller doesn't detect anything by the MSB being 1. The >controller merely transfers whatever bits it reads off the disk into >its 8-bit shift register. Then it's the responsibility of the software >(i.e. RWTS) to read a valid nibble by reading the shift register at the >appropriate time. > >It's a tight loop in the RWTS which decides when a valid nibble is in >the shift register (= when the high bit is a 1): > >nibloop: LDA (addr_of_shift_reg),X BPL nibloop > >where X contains the disk controller slot number multiplied by 16. Actually, the controller state machine _does_ detect the MSB going to 1, and enters a special sequence which keeps the data in the shift register valid (and unshifted) for at least two bit periods (16-17 sequencer clocks). This special detection ensures that the polling loop in RWTS will find the valid byte, since each iteration of this loop requires 7 processor cycles, or 14 sequencer clocks, or almost two disk bit periods. If the controller continued to shift disk bits into the shift register, the data would remain valid for an average of only 8 sequencer clocks, or 4 processor clocks, and the polling loop would not be able to read it reliably. >Note that there's no timeout or any other exit out of this loop if >the high bit never should become 1 for some reason (e.g. hardware >failure). There's no time for such "fancy" stuff if one wants to >make sure to not miss any new bit which arrives in the shift register >every 4'th clock cycle. And there is no need for a timeout, since the disk read amplifier will always generate occasional 1 pulses. The effect is that RWTS cannot get stuck in this loop, but will get an I/O error instead. >After a new valid nibble has been read, one has some 30 clock cycles >to do some other stuff, which in the RWTS of DOS, ProDOS, CP/M (yep, >the RWTS of the various CP/M implementations of Apple II are all >written in 6502 assembly) and most other OS'es is just storing the >nibble in a buffer. The RWTS of Apple Pascal though mamanges to >actually de-nibblize the data as well, so when the sector has been >read, it's been de-nibblized as well, and the next sector can be >read+denibblized "on the fly", enabling Apple Pascal to read one >track in just one disk revolution. In the other Apple II OS'es >de-nibblizing is done separately after the sector read -- and this >causes the RWTS to miss the next sector on the disk, forcing a read >of one entire track to take at least two disk revoutions. > >The fast RWTS read code of Apple Pascal has to pay a price though: >that code is very large, compared to the much more compact RWTS'es of >the other Apple II OS'es. The Apple Pascal RWTS uses a well-known >loop optimization trick: if the loop is to always be executed a fixed >number of times, it executes faster if it is replaced with linear >code. This is called "loop unrolling". It would have been nice to offer a choice in ProDOS about whether to use the standard RWTS or the faster one, by sacrificing some space for the code and the track buffer. -michael Check out parallel computing for 8-bit Apples on my Home page: http://members.aol.com/MJMahon/ pausch@saaf.se (Paul Schlyter) wrote in message news:... > No, the controller doesn't detect anything by the MSB being 1. The > controller merely transfers whatever bits it reads off the disk into > its 8-bit shift register. Then it's the responsibility of the software > (i.e. RWTS) to read a valid nibble by reading the shift register at the > appropriate time. Actually, the sequencer code *does* keep track of whether the high bit of the data shift register is one; this is probably the trickiest part of understanding the Woz state machine. In write mode, it has to keep track, because that determines whether the "high numbered" states with the write pulse = 1 or the "low numbered" state with the write pulse = 0 get executed. _Beneath Apple DOS/ProDOS_ totally skimp on their description of write mode, but if you look at the schematic, you see the connection. In read mode, the state machine logic holds off on shifting in the bits of the next byte when the data register is high-bit 1, by taking separate branches for "10" and "11" Just for my own records, Here is a link to a Google cache of a P6 rom description.