This card was originally developped by Texas Instruments to control upto three single-density, double-sided drives. One of the drives was meant to be installed inside the PE-box, the other two being external, with their own power supply. Several other controller cards were developped later on, to allow for use of double-density disks or even quad-density. This page will concentrate on the original TI card, but I will also discuss the FD179x controller used in double-density cards.
The TI controller card consists in: the FD1771 FDC, a 8Kb ROM containing the DSRs and subprograms, and logic circuits to access each of these. The ROM maps at >4000-5FEF, and the FDC registers at >5FF0-5FFF. There is also quite a bit of electronics to deal with the drive interface.
Here is an annotated picture of the card.
Theory of operation
Disk physical organisation
Magnetic media and write precomp
Data encoding
Tracks and sectors
CRC
Sector interleaving
Disk logical organisation
Volume information block
File descriptor records
The FDC
FD1771 Pinout
FD179x Pinout
Internal structure
Commands
_Status register
_Stepping commands
__Head-step time
_Read sector
__Sector size codes
_Write sector
_Read ID
_Read track
_Write track
_Force interrupt
Timing diagrams
Electrical characteristics
The TI controller card
CRU and registers map
Sample programs
Low-level routines
Track-by-track access
Sector access
Checking drive speed
Goofy formats
The card ROM
File buffers in VDP memory
Power-up routine
Device Service Routines
Subprograms
Disk drives
Models
Connection cable
Terminal resistor pack
Shunt pack
Power supply
Floppy disks are made of a thin layer of ferromagnetic medium coating a plastic film. Contrarily to paramagnetic or diamagnetic media, a ferromagnetic element (or alloy, e.g. iron, cobalt, nickel, Fe65Co35, MnBi, etc) has the property to amplify and possibly to "remember" an externally applied magnetic field. This is due to the number of electrons in the outside layer of ferromagnetic atoms: each atom behaves like a tiny magnet. Since magnets attract/repell each other, an atom can recruit its neighbours and force them to point in the same direction than itself. These atoms can in turn recruit their neighbours, and the process goes on... until it clashes with another cluster of atoms, oriented differently and too large to be recruited. A ferromagnetic medium is thus made of millions of tiny domains, into which the atoms are oriented in the same direction. Each domain acts as a little magnet, but since they are randomly oriented the gobal result is magnetically "neutral".
However, if an external magnetic field is applied to a ferromagnetic medium, it can force some of the domains to align themselves in the direction of the field. The easier domains to recruit will of course be those whose orientation is already close to that of the field. But if the field is strong enough, and if it lasts long enough, it will eventually recruit all domains. When the field is interrupted the domains remain frozen as they were, which means that the medium is not globally neutral any more: it now behaves like a magnet. The intensity of the remaining field with respect to the field that created it is known as remanence, and depends on the element/alloy used.
There are two ways to reverse this magnetization: the first one is to apply an external magnetic field with the opposite orientation. The intensity needed to cancel a magnetization is known as coercivity. Again it depends on the type of atom involved: as you may suspect, elements that have a high remanence also have a high coercivity, they are known as magnetically hard elements. The other way to cancel a magnetisation is to warm up the medium above its "Curie point": the temperature at which the molecular motion becomes strong enough so that atoms can overcome their dependance to their neighbours and freely change their orientation (this property is used in magneto-optic disks).
With floppy disks, a magnetic head generates a magnetic field strong enough to magnetize a small area in the ferromagnetic layer of the disk. Originally some drives used to orient these "magnets" vertically (i.e whithin the thickness of the layer itself), but nowaday all drives arrange the magnetic domains horizontally, along the tracks. When the disk moves, these magnetized area generate a current in the reading head and can therefore be detected. Note however that only changes in magnetic fields generate current, thus if a disk does not spin it can still be written (at the bit currently under the head), but nothing can be read back.
Not all floppy disks are born equal however: high-density disk (HD) are made of a medium with higher remanence and coercivity than single- or double-density disks. This allows to pack bits closer to each other, but requires a writing head capable of generating stonger magnetic fields. HD drives can do that, and they can also reduce their write current to handle SD or DD diks. However, SD or DD drives cannot handle HD disks: their read/write head just can't generate enough magnetic field to overcome the coercivity of the medium.
A big problem with magnets is that they attract and repell each other. This is also true for the small magnetic areas used to encode bits! With certain bit patterns the attraction/repulsions of several successive bits combine is such a way that it can result in "bit shifting", i.e. a bit moves slightly ahead, or behind the positions it should occupy on a track. This is especially marked towards the center of the disk, since the inner tracks are shorter but must hold the same amount of information than the outer tracks: the distance between bits is thus smaller and the attraction they apply to each other is stronger.
To overcome that phenomenon, that could give rise to reading
problems,
some disk controllers use a special trick known as "write
precompensation":
depending on the bit pattern, critical bits can be written slighlty
earlier
or slightly later than they should. When shifting occurs, these bits
end
up precisely where they are supposed to be. Nifty, isn't it?
Data can be stored on magnetic media using various encoding schemes. The original one was FM (frequency modulation), wich was later modified into MFM (modified frequency modulation). Nowadays, more sophisticated methods are used (such as RLL: run length limited), but the TI controller cards don't know about them.
FM
In FM, clock bits are recorded at regular intervals. In between two
clock pulses, there can be a data pulse or not. If there is a pulse, it
encodes a "1" bit, else it encodes a "0". This is how
a byte (>A3: 10100011) is encoded using FM:
_ _ _ _ _ _ _ _ _ _ _ _
__|c|_| |_|c|_____|c|_| |_|c|_____|c|_____|c|_____|c|_| |_|c|_| |_ c: clock pulses
| 1 | 0 | 1 | 0 | 0 | 0 | 1 | 1 |
MFM
Things are a tad more complicated with MFM: the data bits are
encoded
as above, with a pulse for "1" and no pulse for "0".
But clock bits are only issued in between two "0" data bits.
Here is how the same byte is encoded with MFM:
_ _ _ _ _ _
______| |_____________| |_________|c|_____|c|_________| |_____| |_ c: clock pulses
| 1 | 0 | 1 | 0 | 0 | 0 | 1 | 1 |
As you can see, this method leaves more room between pulses, which means that we can compress the above by a factor of two and still have the same minimum interval between pulses than with FM:
_ _ _ _ _ _
______| |_____| |___|c|_|c|___| |_| |_
| 1 | 0 | 1 | 0 | 0 | 0 | 1 | 1 |
Marks
The controller is also able to record some bytes in a special way.
These bytes will be used as synchronisation marks, to define the
beginning
or the end of a data area for instance.
The way it is done in FM is by omitting two or three clock pulses in the middle of the byte. We saw above that there are normally 8 clock bits per byte. If we represent each clock bit with a "1", the normal clock pattern is thus 11111111, or >FF. This clock pattern is interlaced with the data bits for synchronisation purposes. The FD179x can encode marks with a >C7 (11000111) or a >D7 (11010111) clock pattern. To prevent the controller from completely loosing sync, the bytes encoded with such a clock pattern should contain a lot of 1s: the FD179x uses >F8-FB or >FE with a >C7 clock pattern, and >FC with a >D7 clock pattern.
In the TI-99/4A disk format described below, a >FE mark signals the ID block in a sector, whereas a >FB mark signals the data block. A >F8 indicates a deleted data mark. Finally, the IBM format uses >FC at the beginning of the track, to mark the location of the index hole on the track. The unique >D7 clock pattern of the >FC mark tells the CRC logic not to reset the CRC count, as it normally does with sector marks. Track marks are not part of the TI-99/4A format.
Data mark:
_ _ _ _ _ _ _ _ _ _ _ _
__|c|_| |_|c|_| |_____| |_____| |_____| |_|c|_____|c|_| |_|c|_| |_
| 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 Data: >FB
1 1 0 0 0 1 1 1 Clock: >C7
ID mark:
_ _ _ _ _ _ _ _ _ _ _ _
__|c|_| |_|c|_| |_____| |_____| |_____| |_|c|_| |_|c|_| |_|c|_____
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 Data: >FE
1 1 0 0 0 1 1 1 Clock: >C7
Track mark:
_ _ _ _ _ _ _ _ _ _ _ _
__|c|_| |_|c|_| |_____| |_____| |_|c|_| |_|c|_| |_|c|_____|c|_____
| 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | Data: >FC
1 1 0 0 1 1 1 1 1 Clock: >D7
In MFM, marks are generated by omiting a clock transition between bits
4 and 5, or between bits 3 and 4 of the data byte. Obviously, these
data
bits must be 0s, otherwise no clock bit would be expected there. The
two
MFM marks are >A1 (missing a clock bit between bits 4 and 5) for
sector
marks, and >C2 (missing a clock bit between bits 3 and 4) for track
marks. An MFM mark is repeted 3 times and followed by a normally
encoded
byte, with the value of the corresponding FM mark (>FB, >FE,
>FC,
etc). Byte >FC comes after three >C2 track marks, all other bytes
after three >A1 sector marks.
Sector marks
| MFM mark >A1 (3 times) | Type of mark (normal MFM) |
_ _ _ _ _ _ _ _ _ _ _ _
______| |_____| |_______|c|_|c|___| |_| |_| |_| |_| |_| |_____| |_| |_
| 1 | 0 | 1 | 0 | 0 | 0 | 0 | 1 : 1 | 1 | 1 | 1 | 1 | 0 | 1 | 1 | Data >A1 : >FB
^ missing clock bit
Track mark
| MFM mark >C2 (3 times) | Type of mark (normal MFM) |
_ _ _ _ _ _ _ _ _ _ _ _
______| |_| |___|c|_|c|_______| |_____| |_| |_| |_| |_| __| |___|c|_
| 1 | 1 | 0 | 0 | 0 | 0 | 1 | 0 : 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | Data >C2 : >FC
^ missing clock bit
A disk is divided into a number of concentric circles called tracks. Each track is in turn divided into several data segments called sectors. Finally, most floppy disks can be written on both sides.
The number of sides per disk and the number of tracks per side depend on the hardware: you need two reading heads to access both sides of a disk. And the number and positions of the tracks depends on the mechanics that move the reading head in the drive. Typically, TI-drives have 35 or 40 tracks per side. IBM drives can have upto 76 tracks.
On the other hand, the number and the size of the sectors do not depend on the hardware. It is said that floppies are "soft sectored" (hard-sectored disks have an index hole for each sector, soft-sectored disks have only one hole). In the TI single-density format, there are 9 sectors per track, each 256 bytes in length. Double-density format has 18 sectors per track. But this is no obligation: you could elect to have only one big sector per track : this will result in faster data transfer, but may cause a tremendous waste of space if your file is just 1 byte larger than a sector.
Each sector is composed of two parts: a sector ID block and a data block. The sector ID block contains the track number, the side, the sector number and a code for the sector size. When you access a sector, the FDC checks each ID block until it finds one that with the right sector, track and side numbers. If it does not find one after 5 disk revolutions, it returns a "record not found" error. Not surprisingly, the data block contains data, to be transfered to or from the CPU. Each block ends with a CRC byte (cyclic redundancy check) which is a way for the FDC to ensure that the information on the disk has not been corrupted. Special marks (recorded in a special way) are used to define the begining of each block after a stretch of zeros intended to allow for synchronisation.
A track begins shortly after the index hole has been detected by the controller: there are a few >FF filler bytes before the first sector. Similarly, any unused space after the last sector is filled by >FF bytes. There are also filler bytes between the ID and data blocks.
In summary, here is how a single-density track looks like in the TI format. The part in bold type is rewritten during sector write operations. The number of bytes preceded by a ~ may vary when a sector is rewritten, due to slight variations in the speed of the drive motor (especially, if the sector was written with another drive than the one used to initialize the disk).
Name | Bytes | Value | Description | |
---|---|---|---|---|
Index gap | 12 | >FF | Index mark filler | |
x9 | ID sync | 6 | >00 | Synchronizes the controller for ID mark |
ID mark | 1 | >FE | Recorded in a special way (clock >C7) | |
Track | 1 | >00-FF | Track number (normally 0-39) | |
Side | 1 | >00-01 | >00=side A, >01=side B | |
Sector | 1 | >00-FF | Sector number (normally 0-8) | |
Length | 1 | >01-04 | Sector size (normally >01: 256 bytes) | |
CRC | 2 | crc | Cyclic redundance check | |
Separator | ~11 | >FF | Prevents "Write sector" from erasing the ID block | |
Data sync | 6 | >00 | Synchronizes the controller for data mark | |
Data mark | 1 | >FB | Recorded in a special way (clock >C7) | |
Data | 256 | data | This is the data contained in the sector | |
CRC | 2 | crc | Cyclic redundancy check | |
Separator | ~36 | >FF | Prevents "Write sector" from erasing next ID block | |
End filler | ~240 | >FF | Varies with motor speed (+/- 32 bytes) |
Total data bytes: 9 x 256 = 2304 bytes
Total sector bytes: 9 x 325 = 2925 bytes
Total per track: about 3177 bytes
And here is a double-density track.
Name | Bytes | Value | Description | |
---|---|---|---|---|
Index gap | 32 | >4E | Index mark filler | |
x18 | ID sync | 12 | >00 | Synchronizes the controller for ID mark |
MFM mark | 3 | >A1 | Recorded in a special way (missing clock 4-5) | |
ID mark | 1 | >FE | Recorded in normal MFM | |
Track | 1 | >00-FF | Track number (normally 0-39) | |
Side | 1 | >00-01 | >00=side A, >01=side B | |
Sector | 1 | >00-FF | Sector number (normally 0-17) | |
Length | 1 | >01 | Sector size (normally >01: 256 bytes) | |
CRC | 2 | crc | Cyclic redundance check | |
Separator | ~22 | >4E | Prevents "Write sector" from erasing the ID block | |
Data sync | 12 | >00 | Synchronizes the controller for data mark | |
MFM mark | 3 | >A1 | Recorded in a special way (missing clock 4-5) | |
Data mark | 1 | >FB | Recorded in normal MFM | |
Data | 256 | data | This is the data contained in the sector | |
CRC | 2 | crc | Cyclic redundancy check | |
Separator | ~28 | >4E | Prevents "Write sector" from erasing next ID block | |
End filler | ~190 | >FF | Varies with motor speed: (+/- 32 bytes) |
Total data bytes: 18 x 256 = 4608 bytes
Total sector bytes: 18 x 346 = 6228 bytes
Total per track: about 6450 bytes
Cyclic redundancy check (CRC) is a very powerfull method to detect a data alteration the disk, or a transmission error. Unfortunately, it's not as simple to explain as a checksum, but I'll do my best.
We saw above that the data block of a sector is normally 2048-bit long. Traditionnally, we think of these bits as 256 bytes of 8 bits, but nothing prevents us to consider them as 128 words of 16 bits or even as a single 2048-bit number. The lattest provides us with a nice way to verify data integrity: let's just divide this huge number by an arbitrary value and store the result (the quotient or the remainder) toghether with the data. The problem with the quotient is that it may well be a very large number in itself and may require many bits of storage space. The remainder, on the other hand, is by definition smaller than the divisor by at least 1 bit. Therefore, if we were to use a 17-bit divisor, we would be sure to get a 16-bit remainder that can conveniently be stored as two extra bytes, toghether with the sector data. It's not completely impossible that an alteration of the data will result in a number that provides the same remainder, but it's very unlikely: for a 16-bit remainder (17-bit divisor) the odds are 1/216, i.e. one chance in 65536.
The only problem with this technique is that long divisions are difficult to perform for electronic circuits. For neuronal circuits also: just try to divide 12,146,753,456 by 1,247. You have five seconds. Answer......now!
One way to make it easier is to split the operation into a series of partial divisions, and to combine them with shifts and substratctions. This is the traditional way we learn at school:
153 / 12 = Divide 153 by 12
153 First shift 12 all the way to the left
12 Now, how many times 12 in 15? Answer=1
153 / 12 = 1 Write down partial result
12 Get the remainder (i.e. substract 12 from 15)
33 Bring down the next digit
153 / 12 = 1
12
33 Shift the divisor (12) by 1 position to the right
12 Now, how many times 12 in 33? Answer=2 (remainder=9)
153 /12 = 12 Write down the result: this is the quotient
12
33
12
9 Calculate the remainder (substract 2*12 from 33)
We could to the same with binary numbers. It would even be easier since there are only two posible answers to the question "how many times X in Y?", these are 0 and 1. Thus we can replace partial divisions with comparisons: "is X greater than Y?", which is much easier to perform for electronic circuits. What's less easy to obtain is the remainder since substactions (and additions for that matter) require moderately complicated circuits, due to the need to borrow (or carry) bits from the next position on the left. Things would be easier if we could replace substractions with a bitwise operation such as AND, OR or XOR.
But wait, nothing prevents us from doing it! The result may not be very meaningfull, but as long as it retains the same properties than a division that's all we need. CRC codes are generated with such "pseudo-divisions", that use an XOR operation instead of a substraction. Just to refresh you memory: a XOR operation on two bits results in 1 when one or the other bit is 1 (but not both). The truth table is:
0 xor 0 = 0
0 xor 1 = 1
1 xor 0 = 1
1 xor 1 = 0
Now let's "divide" 111001 by 1101 (both being binary values: 57 and 11 in decimal) using our XOR-division scheme:
111001 % 1101 = Pseudo-divide (%) 111001 by 1101
1101 Is 1110 greater than 1011? Answer=1 (yes)
111001 % 1011 = 1 Write down the partial result (i.e. 1)
1101 Calculate the "remainder"...
0011 ...but use XOR instead of substract
111001 % 1011 = 1
1101
00110 Bring down the next digit
1011 Shift the divisor. Is 0110 greater than 1011? No.
111001 % 1011 = 10 Write down the partial result (i.e. 0)
1101
001101 Bring down the next digit
1011 Shift the divisor. Is 1101 greater than 1011? Yes.
111001 % 1011 = 101 Write down the result. This is the pseudo-quotient.
1101
001101
1011 Perform another XOR (ignore leftmost digits)
0110 And this is the final pseudo-remainder.
As you see, this kind of operation is fairly easy to perform for a human brain, and even more so for an electronic circuit. The final "remainder" is our CRC value. Just like the remainder of a division, it is not unique to a given dividend, but the probability that an altered dividend gives the same CRC than the original one is very low. More precisely it is 1/2n , where n is the number of bits in the CRC value.
This means that our 16-bit CRC scheme will pick up 65535 errors out of 65536, or 99.9985 %. Not bad, eh? But we can make it even better if we consider the way errors appear on a disk. They can be due to spontaneous demagnetisation, in which cas only one or two bits at a time will be affected, unless you let a disk sit for 10 years. Or a precise spot on the disk may be damaged and the faulty bits will be grouped toghether (at the place you put your greasy fingers on the magnetic medium). So is often the case with serial transmissions: a burst of statics scrambles a whole bunch of bits. It turns out that some CRC "divisors" (the official name is "generator") are better than other at detecting such burst errors. For instance, the widely-used CCITT generator 1,0001,0000,0010,0001 results in the following impressive performances:
Type of error | Detection rate |
---|---|
Single bit errors | 100% |
Two bits errors | 100% |
Any even number of faulty bits | 100% |
Burst errors of 16 bits or less | 100% |
Burst errors of 17 bits | 99.9969% |
All other burst errors | 99.9984% |
This happens to be the CRC generator used by the FD197x controller.
By the way, did you notice that it's not very convenient to "spell out" a generator, even if we use comma to group the bits 4 by 4? Therefore, the traditional way of writing down a CRC generator is to give its polynomial, i.e. which of the bits are set to 1. In the case of the CCITT generator, the polynomial is x16+x12+x5+1, i.e. bits 16, 12, 5 and 0 (x0 =1) are set to 1. For obvious reasons the leftmost bit is always 1 in CRC generators (otherwise we would have 15-bit CRC values and lower error detection rates). For reasons that are much less obvious to me, the rightmost bit should also be 1.
One last detail. You may think that when reading data from the disk, the controller calculates the CRC and compares it with the CRC value written on disk. You're close, but no cigar. You see, this would require a special comparison circuit. On the other hand, one can check if two numbers are identical by XORing them: A xor B is always 0 if, and only if, A=B. It is thus possible to use the existing XOR logic in the CRC circuitery to perform the check. This is done as follow:
When writing a sector, the FDC considers it as a 2064-bit number, made of 256 8-bit bytes plus a trailing >0000 16-bit word. Upon writing, it replaces the final >0000 with the CRC value. When reading, it just calculate the CRC of the 2064 bits: the result should be 0 since the CRC value will be XORed with itself.
This may remind you of the method used to check parity in serial transmission chips. No wonder: the parity bit is nothing else than a 1-bit CRC. Odd parity uses a 10 generator, and even parity a 11 generator (i.e. the polynomial is x+1). Of course, the error detection rate is fairly low since 1/21 is only 50%...
A word about numbering. On each side tracks are numbered from 0 to 39 starting from the outside of the disk. On each track, sectors are numberd from 0 to 8 (or to 17 for DD disks). When you try to a sector, the software determines on which track it is, and what sector number is will have on this track. Note that sector numbers grow inwards on side A, but outwards on side B (even though track numbers grow inwards on both sides).
However, this numbering scheme is only a software convention, you are allowed to use another numbering scheme provided your software knows how to deal with it. For instance, some protection programs assign random numbers to their sectors (41, 12, 88, 26, etc). The loading software knows which sector to call on which track, but plain-vanilla disk management softwares are completely lost and cannot copy such a disk (see goofy formats, below).
Even though sectors are numbered from 0 to 8, they need not to be arranged in this order on the track. In fact, it is generally better that they are not! This is because it will take some time for the software to deal with a sector before trying to access the next one. In the mean time, the disk will have spun and may have skipped several sectors. To optimize access speed, it is thus advisable to figure out an interleaving (a.k.a. interlacing) scheme designed in such a way that reading head arrives on the next sector just when the software is ready to access it.
For instance, assume that the disk spins by three sectors before the software is ready to proceed. The ideal sequence of sectors would be something like this: 0 x x x 1 x x x 2 x x x 3 x x x 4 x x x 5 x x x 6 x x x 7 x x x 8. Since tracks are circular, this sequence results in the following interleave: 0 7 5 3 1 8 6 4 2. You can verify that consecutive sectors are always 4 sectors apart on the disk (this happens to be the best interlace pattern for the TI disk controller card).
The first two sectors on the disk are reserved for important information about the disk and its content. One uses the first sectors because they are on the outside of the disk, where tracks are physically longer than in the center. Since floppies rotate at a constant speed (unlike CDs), there will be more space to write the same amount of information on track 0 than on track 39. As a result, the probability of data corruption is less on the outer tracks.
Sector 0
This sector is called the VIB (volume information block) and
contains
various information about the disk: name, size, protection, and most
importantly
a sector bitmap.
This bitmap is used by the software to determine whether a sector is free or used. Each sector is represented by one bit (starting with the least significant bit of each byte): when the bit is 0, the sector is free and can be used to create a new file or appended to an existing file. When the bit is 1, the sector is either used or damaged. There are 200 bytes available in the bitmap, which is enough to map 1600 sectors. That's more than enough, since even DS/DD disks have only 1440 sectors.
Exemple:
Byte Sectors
>38: 7 6 5 4 3 2 1 0
>39: 15 14 13 12 11 10 9 8
Content of sector 0:
Bytes | Contents | Typical values |
---|---|---|
>00-09 | Disk name | "DISKNAME01" |
>0A-0B | # of sectors | SS/SD: >168 DS/SD: >2D0 SS/DD: >2D0 DS/DD: >5A9 |
>0C | Sectors/track | SD: >09 DD: >12 |
>0D-0F | DSR mark | "DSK" |
>10 | Protection | Unprot: " " Protected: "P" |
>11 | Tracks/side | >23 / >28 |
>12 | Sides | >01 / >02 |
>13 | Density | SS: >01 DS: >02 |
>14-37 | (reserved) | >00 |
>38-EB | Bitmap | SS/SD: >38-64 DS/SD and SS/DD: >38-91 DS/DD: >38-EB |
>EC-FF | (reserved) | Must be >FF |
Some reserved bytes are sometimes used by disk managers to store extra information about the disk: for instance, DISKU by the late John Birdwell stores an 8-char date string into bytes >20 to >27.
Sector 1
This sector contains a list of pointers (i.e. sector numbers) to
file
descriptor records, sorted in alphabetical order. Each pointer is 2
bytes
long (since there are more that 256 sectors on a disk) and the list
ends
with >0000, which allows us to list 127 files per disk.
Interesting things happen when you play around with that sector:
Each file consists of at least one sector, even when empty. This sector is known as the File Descriptor Record (FDR) and contains various informations about the file: its name, its type, its size, etc. It also contains a list of the sectors where the file data is to be found. The list does not enumerate each sector as this would drastically limitate the maximum file size. Rather it lists clusters, i.e. chunks of consecutive sectors belonging to the file.
Ideally, a file should consist in only one big cluster. However, as other files are written on the disk, it may be that the next sector is not available when it is time to increase the file size. It is thus necessary to start a new cluster, in a free area of the disk: the file is now fractured. Disks that contain a lot of files that have often been modified may end-up in a awfully fractured way, which results in decreasing the access speed (as the reading head must move from one cluster to the next) and may impose a limit on the file size (as only 76 clusters can be defined in the FDR). Therefore, most disk managers will rearrange the files in single clusters when copying a disk.
The FDR dedicates three bytes per cluster, that are used to define the sector number where the cluster begins and the total file size (in sectors, minus one) reached with this cluster. As both numbers may be bigger than 256, each is encoded using one byte and a half (3 nibbles), as follow: UM SN OF Where N U M are the three nibbles forming the sector number (in this order) and O F S are the three nibbles forming the total file offset (counting from zero).
Exemple:
A file consists in 7 sectors: sectors >02E and >02EF and
sectors
>192-196 (5 more sectors).
This makes two clusters: the first starts at sector >02E and ends
with
an offset of >001, the second starts at sector >192 and ends with
a total of >006 sectors.
The cluster list would thus look like this: >2E >10 >00 >92
>61 >00.
Note: the DISKU disk manager uses the end of the FDR to store a user defined comment about the content of the file, in bytes 220 to 254. I suppose John Birdwell assumed no file will be so hopelessly fractured as to require more that 64 clusters...
Bytes | Contents | Comments |
---|---|---|
>00-09 | File name | "MYFILE01" |
>0A-0B | (reserved) | >00 |
>0C | File type | >80: variable >08: write protected >02: internal >01: program |
>0D | Records/sector | >00 for program files |
>0E-0F | # of sectors in file | Not counting FDR |
>10 | Last byte in last sector | >00 for fixed files |
>11 | Record length | >00 for program files |
>12-13 | Fixed: number of records Var: number of sectors Program: >00 |
! Bytes are swapped ! |
>14-1B | (reserved) | >00 |
>1C-FF | Cluster list | >UM >SN >OF == >NUM >OFS |
The Floppy Disk Controller (FDC) is the microprocessor that carries out all disk operations: it starts and stops the motor, moves the reading head to the required track, searches for the specified sector, and reads or writes it one bit at a time. It transfers these bits to/from the CPU one byte at a time.
The FD1771 encodes data in FM (frequency modulation) and can therefore only handle single-density disks.
+----+--+----+
Vbb |1 o 40| Vdd
WE* |2 39| INTRQ
CS* |3 F 38| DRQ
RE* |4 D 37| DINT*
A0 |5 1 36| WPRT*
A1 |6 7 35| IP*
DAL0 |7 1 34| TR00*
DAL1 |8 1 33| WF*
DAL2 |9 32| READY
DAL3 |10 31| WD
DAL4 |11 30| WG
DAL5 |12 29| TG43
DAL6 |13 28| HLD
DAL7 |14 27| FDDATA
PH1*/STEP |15 26| FDCLK
PH2*/DIRC |16 25| XTDS*
PH3 |17 24| CLK
3PM* |18 23| HLT
MR* |19 22| TEST*
Vss |20 21| Vcc
+------------+
Power supply
Vdd: +12 Volts
Vcc: +5 Volts
Vbb: -5 Volts
Vss: Ground
Computer interface
MR*: Master Reset. When hold low for at least 50 usec, this
input pin resets the FDC and resets the "Not-ready" status bit.
When MR* becomes high again, the FDC executes a Restore (>03)
command
and loads >01 into the Sector register.
CS*: Chip Select. Enables FDC access when low.
A0,A1: Address lines. Select the register to be accessed.
0=Command
(write) or Status (read), 1= Track, 2=Sector, 3=Data.
DAL0-DAL7: Data Access Lines. Inverted bidirectional data bus,
enabled
by WE* and RE*.
WE*: Write Enable. Used by the CPU to tell the FDC that data has
been sent on the data bus. Active low.
RE*: Read Enable. Used by the CPU to read cause the FDC to place
data on the data bus. Active low.
CLOCK: This input pin must receive a 2 MHz +/- 1% square wave
signal,
with a 50% duty cycle.
DRQ: Data Request. This open collector output is used by the FDC
during read operations to indicate that a byte of data is ready in the
Data register (high signal). During write operations, a high level
signals
that the Data register is now empty and ready to receive another byte.
Should be pulled up to +5V with a 10K resistor.
INTRQ: Interrupt request. This open collector output (to be
pulled
up with a 10K to +5V) becomes low each time the FDC has completed a
command.
Reset when the command register is loaded with a new command.
Disk drive interface
The FD1771 can be handle two types of drive interface: it can
either
command 3 stepper motors by sending successive three phase pulses on
pins
PH1, PH2 and PH3, or it can send stepping pulses on the PH1/STEP pin
and
a direction control on the PH2/DIRC pin. Pin 3PM is used to determine
the
type of interface used.
PH1*/STEP: If 3PM is high. the FDC sends a 4 microseconds
high
pulse on this output pin, causing the drive to move the reading head by
one track. If 3PM is low, the FDC sends one active low signal out of
three
on this pin.
PH2*/DIRC: When 3PM is high, this pin determines the direction
in
which the head will move. Low=outwards, high=inwards. If 3PM is low,
the
FDC send one active low signal out of three on this pin.
PH3: When 3PM is low, the FDC sends one active low signal out of
three on this pin. Not used if 3PM is high. Note that PH3 needs an
external
inverter.
3PM: This pin should be hardwired low to use a 3-step drive
interface:
pulses will be sent as PH1-PH2-PH3-PH1 to step in and as
PH1-PH3-PH2-PH1
to step out. Alternatively, 3PM can be wired high for a more
sophisticated
interface: a single stepping pulse will be sent on STEP. whith DIRC
indicating
the direction.
TG43: Track greater than 43. This output pin tells the drive
that
the head is positioned beyond track 43 (some drives use it to
compensate
for the higher density of data bits on these tracks). Valid only during
read and write commands.
HLT: Head Loading Time. When high, the magnetic head is assumed
to be engaged. This input is typically driven by a one-shot timer
triggered
by HLD but could also be connected to +5V if the internal delay is
sufficient
(command bit "E": the HLT line will only be sampled 10 ms after
HLD went high).
HLD: Head load. Tells the drive to load the read/write head on
the
magnetic medium. Typically used to trigger a one-shot that fires back
to
HLT.
The FD1771 can either receive a mixed signal from the drive, i.e clock and data bits together, or receive the clock bits on pin FDCLK and the data bits on pin FDDATA. Pin XTDS is hardwired to determine the mode to be used.
FDCLK: When XTDS* is low, this pin receives the clock bits
from
the drive, processed by an external separator. If XTDS* is low, this
pin
should be tied to a logic high.
FDDATA: Data input from the drive. When XTDS* is low, this pin
receives
externally separated data bits from the drive. If XTDS* is high, this
pin
receives raw data from the drive and an internal separator is used.
XTDS*: This pin should be hardwired low if an external data
separator
is used. It should be tied high or left open to make use of the
internal
data separator.
WG: Write Gate. Becomes active before write operations.
WD: Write Data. This output pin sends 500 ns pulses to the drive
for each flux transition. This signal always incorporates data and
clock
bits (including marks), no matter the status of XTDS*.
READY: Input pin used by the drive to tell the FDC that it is
ready
for the next operation.
WF*: Write fault. The drive can bring this pin low to indicate
wrinting
faults. If WG was high, the current write command is terminated and the
"write fault" status bit is set. This line should remain inactive
(high) when WG is low.
TR00*: Track 0. The drive uses this pin to inform the FDC that
the
head is on track 0 (to the outside of the disk). Active low..
IP*: Index pulse. Used by the drive to signal index holes.
Low=hole.
WPRT*. Write protected. Used by the drive to signal a write
protection.
A low level aborts any write command and sets the "write protected"
status bit.
DINT*: Disk Init. Used to prevent disk formating: the FD1771
samples
this input when a Write Track command is received. If the pin is low,
the
operation is terminated and the "write protected" status bit
is set.
TEST*: Ouput pin for test purposes. Should be left open or
pulled
up to +5V.
The Floppy Disk Controller (FDC) is the new version of the FD1771. The main improvement is that it can handle double-density disks, by performing MFM encoding.
There are six, slightly different FD179x models. The FD1791, FD1792 and FD1795 have an inverted data bus. The FD1791, FD1793, FD1795 and FD1797 can deal with double-density. The FD1795 and FD1797 have a side selection output.
+----+--+----+
nc |1 o 40| Vdd
WE* |2 39| INTRQ
CS* |3 F 38| DRQ
RE* |4 D 37| DDEN*
A0 |5 1 36| WPRT*
A1 |6 7 35| IP*
DAL0 |7 9 34| TR00
DAL1 |8 x 33| WF*/VFOE*
DAL2 |9 - 32| READY
DAL3 |10 0 31| WD
DAL4 |11 2 30| WG
DAL5 |12 29| TG43
DAL6 |13 28| HLD
DAL7 |14 27| RAWREAD*
STEP |15 26| RCLK
DIRC |16 25| RG/SSO
EARLY |17 24| CLK
LATE |18 23| HLT
MR* |19 22| TEST*
Vss |20 21| Vcc
+------------+
Power supply
Vdd: +12 Volts
Vcc: +5 Volts
Vss: Ground
Computer interface
MR*: Master Reset. When hold low for at least 50 usec, this
input pin resets the FDC and resets the "Not-ready" status bit.
When MR* becomes high again, the FDC executes a Restore (>03)
command
and loads >01 into the Sector register.
CS*: Chip Select. Enables FDC access when low.
A0,A1: Address lines. Select the register to be accessed.
0=Command
(write) or Status (read), 1= Track, 2=Sector, 3=Data.
DAL0-DAL7: Data Access Lines. Bidirectional data bus. Inverted
on
the FD1791, FD1792 and FD1795.
WE*: Write Enable. Used by the CPU to tell the FDC that data has
been sent on the data bus (pins DAL0-DAL7).
RE*: Read Enable. Used by the CPU to read cause the FDC to place
data on the data bus.
CLOCK: This input pin must receive a 1 MHz (2 MHz for 8"
floppies) square wave signal, with a 50% duty cycle.
DRQ: Data Request. This open collector output is used by the FDC
during read operations to indicate that a byte of data is ready in the
Data register (high signal). During write operations, a high level
signals
that the Data register is now empty and ready to receive another byte.
Should be pulled up to +5V with a 10K resistor.
INTRQ: Interrupt request. This open collector output (to be
pulled
up with a 10K to +5V) becomes low each time the FDC has completed a
command.
Disk drive interface
STEP: The FDC sends a pulse on this output pin, causing the
drive to move the reading head by one track.
DIRC: Direction. This output pin determines in which direction
the
head will move. Low=outwards, high=inwards.
TG43: Track greater than 43. This output pin tells the drive
that
the head is positioned beyond track 43. Valid only during read and
write
commands.
HLT: Head Loading Time. When high, the magnetic head is assumed
to be engaged. This input is typically driven by a one-shot timer
triggered
by HLD but could also be connected to +5V if an internal delay is used
(command bit "E")..
HLD: Head load. Tells the drive to load the read/write head on
the
magnetic medium. Typically used to trigger a one-shot.
SSO: Side Select Ouput. Tells the drive which side of the disk
to
access (for FD1795/97 only).
RG: Read Gate. Used for synchronisation of external data
separators
(for FD1791-94 only). Goes high after two >00 bytes in SD (4 bytes
of
>00 or >FF in DD).
DDEN*. Double Density Enable. This input pin puts the FDC in
double-density
mode when low, in single-density mode when high. Must be left open on
the
FD1792/1794 (that cannot handle double density).
EARLY: When active (high) indicates that the write data pulse
should
be shifted early for write precompensation.
LATE: When active (high) indicates that the write data pulse
should
be shifted early for write precompensation.
RCLK: Read Clock. The drive sends a nominal square wave
signal
derived from the data stream on this pin. The polarity of the signal
(+/-)
does not matter, only phasing (i.e. transitions) does.
RAWREAD*: Data input from the drive. Active low, i.e. each
recorded
flux transition should send a negative pulse.
WG: Write Gate. Becomes active before write operations.
WD: Write Data. This output pin sends a 500 ns (FM) or 200 ns
(MFM)
pulse to the drive for each flux transition. This signal incorporates
data
and clock bits (including marks).
READY: Input pin used by the drive to tell the FDC that it is
ready
for the next operation.
WF*/VFOE*: Compined input/output pin. During write operations
(when
WG is high) this pin is used as input for a Write Fault signal: when
active
(low) it interrupts the current write command. During read operations
(when
WG is low) this pin becomes a VFO enable output signal.On the FD1791/93
it goes low once the head has settled (HLT is high) and remains low
until
the end of the data field. Additionally, on the FD1795/97 it
temporarily
goes high between the end of the ID CRC and 4 bytes (8 in MFM) before
the
data mark. This pin has an internal 100K pull-up resistor.
TR00: Track 0. The drive uses this pin to inform the FDC that
the
head is on track 0 (to the outside of the disk).
IP*: Index pulse. Used by the drive to signal index holes.
Low=hole.
WPRT*. Write protected. Used by the drive to signal a write
protection.
A low level aborts any write command.
TEST*: Ouput pin for test purposes. Should be left open or
pulled
up to +5V. Used with voice-coil actuated steppers (i.e. linear stepper
motors. But appart for some antiques, all drives use rotating stepper
motors
to move the read/write head).
The FDC contains five 1-byte registers: a write-only Command register, a read-only Status register, a Data register, a Track register and a Sector register. These registers are mapped at addresses >5FF0-5FFE in the TI controller card.
The write-only Command register accepts 11 different commands from the CPU. They are described below.
The meaning of the various bits in the read-only Status register depends on the current command. Several bits reflect the state of output pins ("Busy" for INTREQ, "DRQ pin" for DRQ, etc), which gives the designer the option to physically tie those pin to the CPU, or to read them via the Status register. See "Commands" for more details.
The Data register is used as a holding register during read or write operations. It communicates with an internal shift register that allows to serialize data to send it to the drive (on the WD pin). Conversely, during read operations, the shift registers accepts data from the drive (on the RAWREAD* or FDDATA pin), assembles it into a byte and transfers this byte to the data register.
The Track register contains the number of the track the magnetic read/write head is on. Valid values are 0 to 255, although I don't think any TI-99/4A-compatible drive ever went beyond 76 tracks. The FDC automatically updates the Track register when stepping the magnetic head. The content of this register is compared to the track number recorded on the disk during read, write and verify operations. The track register can also be modified directly by the CPU.
The Sector register holds the number of the desired sector, as loaded by the CPU. The content of this register is compared to the sector number recorded on the disk during read, write and verify operations.
In addition to these five register (and the shift register), the FDC
also contains several functional units that are not directly accessible
by the CPU:
An ALU (Arithmetic and Logic Unit) used to perform comparisons
and
register modifications.
An address mark detector, that checks the clock pulses and
detects
the ID and data marks.
A CRC logic (Cyclic Redundancy Check), used to write and verify
a CRC code on disk. The polynomial is x16+x12+x5+1,
which is the standard CCITT CRC generator (see above).
And last but not least, a timing and control circuit, triggered
by an external clock signal, that controls all drive operations.
The FDC accepts 11 different commands. Their syntax is summarized in the table below. Be aware that there are subtle differences between the FD1771 and the newer FD179x. Furthermore, there are differences between the various subtypes of FD179x.
Most commands will abort if the drive is not ready: the FDC checks for that by sampling the READY pin at the beginning of the command. The meaning of the various bits in the Status register depends on the command being executed, but one constant is the Busy bit (weight >01). No new command should be sent to the Command register as long as this bit is set (apart for the "Force interrupt" command). Once the command has been completed, the Busy bit is cleared and an interrupt is issued on the INTREQ pin.
Command | >80 | >40 | >20 | >10 | >08 | >04 | >02 | >01 |
---|---|---|---|---|---|---|---|---|
Restore | 0 | 0 | 0 | 0 | h | V | r1 | r0 |
Seek | 0 | 0 | 0 | 1 | h | V | r1 | r0 |
Step | 0 | 0 | 1 | T | h | V | r1 | r0 |
Step-in | 0 | 1 | 0 | T | h | V | r1 | r0 |
Step-out | 0 | 1 | 1 | T | h | V | r1 | r0 |
Read sector | 1 | 0 | 0 | m | S | E | C/0 | 0 |
Write sector | 1 | 0 | 1 | m | S | E | C/a1 | a0 |
Read ID | 1 | 1 | 0 | 0 | 0 | E' | 0 | 0 |
Read track | 1 | 1 | 1 | 0 | 0 | E' | 0 | s* |
Write track | 1 | 1 | 1 | 1 | 0 | E' | 0 | 0 |
Force interrupt | 1 | 1 | 0 | 1 | I3 | I2 | I1 | I0 |
r0,r1: stepping motor rate (see below)
V: verify track number flag. 1=verify, 0=don't.
h: head load flag. 0=unload head at beginning, 1=load head at
beginning.
T: track update flag. 1=update track register, 0=don't.
a0: data mark flag. For FD179x: 0=data mark (>FB),
1=deleted
data mark (>F8). For FD1771: combined with C to select one in 4
possible
data marks: 00 = >FB, 01 = FA, 10 = >F9, 11 = >F8.
E: delay flag: 0=no delay, 1=15 msec delay before sampling the
HLT
pin (10 msec for FD1771).
E': same as E, but always 1 with FD1771.
C/a1: For FD1795/97: compare side number flag. 0=disable,
1=enable:
set value of SSO pin (for all read/write commands). For the FD1771:
always
0 for read command, combines with a0 for write commands.
S: For FD 1791/2/3: expected side, to be compared to side number
on disk if C=1. For FD1771 and FD1795/97: changes the meaning of the sector
size code.
m: multiple record flag. 0=read/write one sector. 1=keep
reading/writing
sectors on that track until Force interrupt is issued.
s*: For FD1771 only. Synchronize to address marks if 0, ignore
address
marks if 1. Always enabled with the FD179x.
I3: issue an interrupt now. This bit can only be reset with
another
"Force interrupt" command.
I2: issue an interrupt at the next index pulse.
I1: issue an interrupt at the next ready to not-ready transition
of the READY pin.
I0: issue an interrupt at the next not-ready to ready transition
of the READY pin.
(If I0-I3 are 0: don't issue any interrupt, but still abort the current
command).
The meaning of the status bits for the different commands is summarized below:
Command | >80 | >40 | >20 | >10 | >08 | >04 | >02 | >01 |
---|---|---|---|---|---|---|---|---|
All steppings + Force interrupt |
Not ready | Write protect | Head loaded | Seek error | (CRC error) | Track 0 | Index pulse | Busy |
Read ID | Not ready | 0 | 0 | Rec not found | CRC error | Lost data | DRQ pin | Busy |
Read sector | Not ready | 0 (Mark type) | Mark type | Rec not found | CRC error | Lost data | DRQ pin | Busy |
Read track | Not ready | 0 | 0 | 0 | 0 | Lost data | DRQ pin | Busy |
Write sector | Not ready | Write protect | Write fault | Rec not found | CRC error | Lost data | DRQ pin | Busy |
Write track | Not ready | Write protect | Write fault | 0 | 0 | Lost data | DRQ pin | Busy |
Not-ready: inverted copy of the READY input pin ("ORed"
with MasterReset pin). A 1 indicates the drive in not ready.
Write protect: inverted copy of the WPRT* input pin. A 1
indicates
the disk is write protected.
Head loaded: logical "and" of HLD and HLT pins. A 1 indicates
the head is loaded and engaged.
Seek error: if 1, the desired track did not match. Reset when
updated.
CRC error: if 1 the CRC found on disk did not match the
calculated
one. For stepping commands: CRC found in an ID field..
Track 0: inverted copy of the TR00* input pin. A 1 indicates the
magnetic head is on track 0.
Index pulse: inverted copy of the IP* pin. A 1 indicates an
index
hole.
Busy: a 1 indicates a command in progress.
Mark type: For FD179x a 0 indicates a normal data mark (>FB),
a 1 indicates a deleted data mark (>F8). For FD1771, two bits are
used:
00 = >FB, 01 = >FA, 10 = >F9, 11 = >F8.
Write fault: a 1 indicates a write fault detected by the drive.
Reset when updated.
Rec not found: a 1 indicates the desired track+sector+side ID
combination
was not found in any ID block.
Lost data: a 1 indicates that the CPU did not read/write the
data
register in time for the next byte to be processed.
DRQ pin: copy of the DRQ pin. For read operations, a 1 indicates
that the Data register is full and must be read. For write operations,
a 1 indicates that the Data register is empty and must be filled. Reset
when updated.
This command causes the FDC to issue a pulse on the STEP pin, which results in moving the magnetic head by one track in the currently selected direction. If the h flag is set, the head will be loaded onto the magnetic medium at the beginning of the command. After a delay specified by the r0+r1 bits, the track number is verified from the first encountered ID field, provided the V flag was set (no verification is done with the FD1795/97). Finally, if the T flag is set, the Track register will be incremented/decremented by one.
Head step times (the usual value for the TI controller card is in bold)
Clock | 2 MHz | 2 MHz | 1 MHz | 1 MHz | 2 MHz | 1 MHz | 2MHz | 1 MHz | 2MHz | 1MHz | |
---|---|---|---|---|---|---|---|---|---|---|---|
DDEN* | low | high | low | high | any | any | FD1771 | FD1771 | FD1771 | FD1771 | |
TEST* r1 r0 |
high |
high |
high |
high |
low |
low |
high |
high |
low |
low |
|
0 | 0 | 3 ms | 3 ms | 6 ms | 6 ms | 184 us | 368 us | 6 ms | 12 ms | ~400 us | ~600 us |
0 | 1 | 6 ms | 6 ms | 12 ms | 12 ms | 190 us | 380 us | 6 ms | 12 ms | ~400 us | ~600 us |
1 | 0 | 10 ms | 10 ms | 20 ms | 20 ms | 198 us | 396 us | 10 ms | 20 ms | ~400 us | ~600 us |
1 | 1 | 15 ms | 15 ms | 30 ms | 30 ms | 208 us | 416 us | 20 ms | 40 ms | ~400 us | ~600 us |
NB The CorComp card provides a way to determine the proper head-step time by reading CRU bits 18 and 22. You can determine which card is in use by trying to bank-switch the card ROM with CRU bit 11: if the ROM changes, it's probably a CorComp card. Don't forget that it does not invert the data bus!
* This routine tests for the presence of the CorComp card |
This commands sets the current direction as "inward" (pin DIRC is high), then executes a Step command.
This commands sets the current direction as "outward" (pin DIRC is low), then executes a Step command.
The CPU uses this command to move the magnetic head on a specific track. The desired track number should be loaded in the Data register and it is assumed that the Track register contains an up-to-date track number. The latter can be a problem when using multiple drives: the current track number for a drive must be saved by the software before to operate another drive. Upon reception of the command, the FDC compares these two registers to determine the adequate direction and sets the DIRC pin accordingly. It then executes the required number of Step commands to make the Track register match the Data register.
This command seeks track 0. It sets the Track register as 255 and the Data register as 0. Then is executes a Seek command, which will result in moving the magnetic head outwards. The Restore command constantly monitors the TR00* pin: when the head reaches track 0 this pin goes low and the command is aborted. The Track register is set as 0, and the track number is verified (by reading an ID block) if the V flag was set. If TR00* does not become active after 255 steps, a Seek error is issued (provided the V flag was set) and the command terminates. This command is automatically executed after a master reset.
This commands reads one or more sectors from disk (only the data part of the sector is transfered). The desired sector number should be placed in the Sector register.
For obvious reasons, the FDC always activated the HLD pin to load the magnetic head at the beginning of a read or write command. This operation takes some time and there are two ways to wait for its completion. Before to perform any read/write operation, the FDC waits for the HLT pin to becomes high, a feature meant for use with an external "one-shot" timer. If the "E" bit is set, the FDC first wait 15 msec (10 msec with the FD1771) before to check the HLT pin, a feature meant for use with a HLT pin permanently tied to +5V.
If the content of the Track register is greater than 43, the TG43 pin is set as high, otherwise it is set as low.
The Read sector command then checks every ID block on the current track until it encouters one that matches the required parameters. It first verifies that the track number matches the content of the Track register, then that the sector number matches the content of the Sector register, then that the side number matches the "S" bit in the Command register. If there is a mismatch the next ID block is checked. If no matching ID block (or no ID block at all) is found whithin 5 disk revolutions, as detected by the index hole pulses on the IP* pin, the command ends with the "rec not found" bit set in the Status register. If a matching ID block is found, the FDC loads the sector size and check the CRC. If the CRC does not match, the search continues.
When a matching ID field is found, the FDC expects a data mark within the next 30 bytes (43 for double-density disks). If none occured, the search procedure resumes. Once the data mark has been found, the CRC counter is reset and bytes read from disk are transfered to the Data register, via the shift register. Once a byte is ready, the DRQ pin is activated and the CPU must read the Data register before the next byte arrives (which resets the DRQ pin). If this did not happen, the " lost data" bit is set in the status register, but reading continues normally.
Once the appropriate number of bytes have been read, the CRC field is read and compared with the calculated CRC value. If they don't match, the command aborts and sets the "CRC error" bit in the Status register. Otherwise the commands terminates normally and the type of address mark is saved in the "mark type" bit of the status register.
If the m bit is set in the Command register, the FDC increments the Sector register and proceeds with reading the next sector. This goes on until either a sector cannot be found on the track, or the Force interrupt command is received.
The L flag exists only on the FD1795/97. It is assumed to be 1 on the other models. For the FD1771, the L flag selects either the IBM set of sizes (128, 256, 512 or 1024 bytes ) or a non-IBM set in which the sector length field is multiplied by 16 to yield the sector length (0 stands for 256, ie. 4096 bytes). The default value for the TI-99/4A controller card is 256 bytes.
L flag in command |
Sector length in ID field | ||||||
---|---|---|---|---|---|---|---|
0 | 1 | 2 | 3 | ...n | >FF | ||
0: FD179x | 256 | 512 | 1024 | 128 | - | - | |
0: FD1771 | 4096 | 16 | 32 | 48 | n*16 | 4080 | |
1: both | 128 | 256 | 512 | 1024 | - | - |
This command is used to write data into the data block of a sector on disk. The desired sector number should be placed in the Sector register. The Write sector command looks for a matching ID field just as the Read sector command does, excepts that it also checks the WRPRT* pin. If this pin is active (low) the command aborts with the "write protected" bit set in the status register.
Once a proper ID block has been found, the FDC sets the DRQ pin to request data from the CPU, counts 11 bytes after the ID block CRC (22 bytes with DD disks) and enables the WG pin. This only occurs if data has been placed in the data register, else the command terminates and sets the "lost data" bit in the status register (a way to prevent accidental write commands). The FDC then writes six >00 bytes (12 with DD disks) and a data mark. The type of data mark is determined by the "a" bit in the Command register: 0 = standard mark (>FB), 1 = deleted mark (>F8). The older model FD1771 can use 4 different data marks: >F8 through FB.
The FDC then writes data to the disk, taking bytes from the Data register and processing them through the shift register to the WD pin, after due mixing with clock pulses. Each time a byte is transfered to the shift register, the DRQ pin is activated to tell the CPU that it can place the next byte into the Data register. This operation will reset DRQ. If it does not happen in time, a >00 byte is written on disk and the "lost data" bit is set in the Status register, but the command is not terminated. The number of bytes to be written is determined by the sector lenght byte read from the ID block.
Once a sector has been written, the contents of the CRC counter is written as two bytes, followed by a >FF byte (two in DD). The WG pin is then deactivated. Note that it is not advisable to let the FDC fill the end of a sector with zeros by just stopping to send data, as writting errors won't be detected. Instead, write the number of required >00 bytes, just like any other byte value.
The Write command will go on with the next sector if the "m" bit was set in the Command register, the Sector register being automatically incremented. This goes on until a matching ID field cannot be found, or a Force interrupt command is issued.
This command is used to read the next ID block encountered on the track. The HLD, HLT and TG43 pins are dealt with as described in the Read Sector command. The ID block is passed to the CPU via the Data register as a string of six bytes: track number, side number, sector number, sector lenght code, and CRC (2 bytes). The track number is then copied into the Sector register, the CRC is checked and the "CRC error" bit of the Status register set accordingly.
If no ID field is found during 5 disk revolutions, the "record not found" bit is set in the Status register and the command aborts.
This command reads a whole track from disk, as raw data. It is meant for diagnostic purposes, therefore most checking mechanisms are disabled: no CRC checking is performed, ID fields are not checked for track and side number and the RG pin is not activated.
The FDC deals with the HLD, HLT and TG43 pins as described above, then check the IP* pin and waits for an index hole. The contents of the track is then passed to the Data register, via the shift register. The DRQ pin is activated once a byte is ready and must be cleared by reading the Data register before the next byte comes in. If it is not the case, the "lost data" bit is set in the Status register and reading continues.
The address mark detector is working during the whole commands. ID and data marks are thus recognized and used to synchronise the flow of bits (i.e. to detect bytes boundaries). If a mark does not occur where expected, the "lost data" bit is set. As a result, the sector ID blocks and Data blocks will always be correct, but the number of filler bytes in the gaps may vary. With the FD1771, it is possible to inactivate the address mark detector during Read Track commands (bit s*).
This command is used to write a track on disk, for formatting purposes. Some byte values (>F5-FE) are reserved to instruct the FDC to write marks or CRC values on the disk. In FM, filler bytes should be >FF, but the FD1795/97 will also accept >00. In MFM, filler bytes should be >4E. It is acceptable to use more filler bytes than specified by the format, although the IBM format does not allow that before the ID block. The number of >00 used for sync must be exact in the ID block, but may be increased in the data block.
The FDC deals with the HLD, HLT and TG43 pins as described above. It checks the WPRT* pin and aborts with the "write protected" bit set in the Status register is the pin is active. The FD1771 additionally checks the DINT* pin and issues the same error if this pin is low. Otherwise, The FDC ctivates the DRQ pin and awaits the first data byte in the Data register, for as long as it would take to write three bytes. If no data arrives, the command aborts with the "lost data" bit set.
The FDC then waits for an index hole, by checking the IP* pin. Once the hole is detected, the FDC starts writting data on disk: the first byte is transfered from the Data register to the shift register and the DRQ pin is activated. If the CPU fails to provide the next byte in time, a >00 byte is written on disk and the "lost data" bit is set in the Status register. The command terminates when the index hole is detected again.
Before to write a byte of data, the FDC checks its value. If it is in the range >F5-FE, it causes the FRC to write marks or CRC on disk: see the table below. As a consequence, those bytes cannot be part of the data written on disk. This is no problem upon formatting, since all sector data blocks contain a default value (>E5 with the TI disk manager), but it is a major pain in the butt when it comes to copy a disk track-by-track!
Byte | Meaning in FM | Meaning in MFM |
---|---|---|
>00- >F4 |
Written normally | Written normally |
>F5 | Not allowed | Write >A1, missing clock between bits 4-5 Reset CRC |
>F6 | Not allowed | Write >C2, missing clock between bits 3-4 |
>F7 | Generate 2 CRC bytes | Generate 2 CRC bytes |
>F8- >FB |
Written as a mark with clock pattern >C7. Reset CRC |
Written normally |
>FC | Written as a track mark (clock >D7) | Written normally |
>FD | Written normally. Reset CRC. | Written normally |
>FE | Written as a mark with clock pattern >C7. Reset CRC |
Written normally |
>FF | Written normally | Written normally |
This command is generally used to stop a multiple Sector read or Sector write. It can also be used to place the Status register in a defined state: if a command is interrupted, the Status register reflects the current status of this command (with the "busy" bit cleared), otherwise the meaning of the status byte is that of the Force interrupt command. Finally, this command can be used to physically generate interrupts.
Interrupts are issued by setting one (or more) of the I0-I3 bits to 1. When one of the conditions for the interrupt is met, the INTREQ line goes active (high). I3 issues an interrupt immediately. I2 issues an interrupt when an index hole is detected. I1 and I0 issue interrupts when the READY pin changes state: I1 when it becomes not-ready, I0 when it becomes ready. I0 to I2 are reset automatically, but I3 must be reset by loading another Force interrupt command, with I3=0.
The CPU should wait 8 usec (16 usec for DD) after the command is loaded, before loading another command (else it would cancel the Force interrupt). These times doubble with a 1 MHz clock.
When diagrams are valid for both the FD1771 and the FD179x, values specific for the FD179x are indicated in green. All times are for a 2 MHz clock, you should double them for a 1MHz clock.
_______________
__| |400-500|__________________________________ DRQ
___________________________________________
| a | 500-3000 ns |_________ INTRQ
_______________________________
_____| | >10 |_______________ A0, A1, CS*
__________ >400 ns _____________________
|>100| >500 ns | RE*
>50 _______|____| 50-150
| <450 ns | valid data | DAL0-DAL7
<350 ns
a) Tservice: 27.5 us in FM, 13.5 us in MFM
_______________
__| |400-500|__________________________________ DRQ
___________________________________________
| 500-3000 ns |_________ INTRQ
| FM <23.5 us MFM <11.5 us |
_____| | >10 |_______________ A0, A1, CS*
__________ _____________________
|>50 | >350 ns | >70 WE*
>250 | >150
| valid data | DAL0-DAL7
data bit=0 =1 |__>2500 ns |__
____ ! |a | | |________| |____ FDDATA
|>500 |
____|a | | |________| | ! FDCLOCK
| >2500 ns | missing clock
a) 150-350 ns.
FDDATA and FDCLOCK may be reversed. The FD1771 decides which is which.
__ __ |__>2500 ns |__
| | |a | | |________| |____ FDDATA
clock clock data clock
a) 150-350 ns.
__| |<100|___ WG
|1200|__ 2000 ns |__ |__ >4000 ns |__ __
| | |a | | |___________________| |________| |________ WD
clock data clock data clock last data
a) 500-660 ns.
FD179x drive interface: Input data
| 1500-2000 ns | ___
|a | |__| RAWREAD*
|>40 ns|>40 ns|
__________| b | c | RCLK (polarity may be inverted)
| 1500-2000 ns |
a) 100-300 ns. Can be any length if entirely whithin window.
If pulse occur in both windows, must be <300 ns in MFM, <600 ns in FM
b) and c) 4 us in FM. 2 us in MFM (for 8" disks: 2 us in FM, 1 us in MFM)
Single density (DDEN* high)
|250 ns (200-20000)|250 ns (230-20000)| CLK
a
///////////>50|>30 \\\\\\\\\\\ WD
Double density (DDEN* low)
| | 125 ns | 125 ns | CLK
a
///////////>50|>30\\\\\\\\\\\ WD
a) Pulse width 500-600 ns in FM, 200-350 ns in MFM.
Pulse edges must be in shaded area.
step in ...
| | step out DIRC
12 us a a
|24 us | | | | ... |12 us | | | | STEP
| b | | b |
a) 4 us if FM 2 us in MFM
b) Step time: depends on r1,r0 bits in command
MR* or IP* or WF*
| |
For the FD1771
Vdd to Vss.....................+20V to -0.3V
Any input to Vss.............+20V to -0.3V
Icc.................................30 mA nominal
Idd................................10 mA nominal
Ibb................................0.4 uA nominal
Operating temp..............0 to 70 `C
Storage temp................-55 to +125 `C
For the FD179x
Vdd to Vss.....................+15V to -0.3V
Any input to Vss.............+15V to -0.3V
Icc.................................60 mA (35 mA nominal)
Idd................................15 mA (10 mA nominal)
Cin................................15 pF max
Cout..............................15 pF max
Operating temp..............0 to 70 `C
Storage temp................-55 to +125 `C
FD1771: Vdd = +12V, Vss = 0V, Vcc = +5V, Vbb=-5V, TA = 0-70 `C
FD179x: Vdd = +6V, Vss = 0V, Vcc = +5V, TA = 0-70 `C
Parameter | Test conditions | Min | Max | Unit |
---|---|---|---|---|
Input leakage | Vin=Vdd. Pins without pull-ups (not for pins 22,23,33,36,37) |
. | 10 | uA |
Output leakage | Vout=Vdd | . | 10 | uA |
Input high voltage | . | 2.6 | . | V |
Input low voltage | . | . | 0.8 | V |
Output high voltage | I = -100 uA | 2.8 | . | V |
Output low voltage | I = 1.6 mA (1.0 for 1792/94) | . | 0.45 | V |
Power dissipation | . | . | 0.6 | W |