Floppy Disk Controller: Difference between revisions

Jump to navigation Jump to search
Auto motor off info, fixed a couple more errors
[unchecked revision][unchecked revision]
(Added some notes, fixed one error)
(Auto motor off info, fixed a couple more errors)
Line 1:
== Overview and Documentation ==
The Floppy Disk Controller (FDC) is a (legacy) device that controls '''internal''' 3.5/5.25 inch floppy disk drive devices on desktop x86 systems.
There are a range of chips that have been produced for this function which include: 8272A, 82078, 82077SL & 82077AA. The 82077AA is the most
advanced, and has been produced since 1991. For more recent systems, a model of that chip has been embedded in the motherboard chipset.
Line 6:
 
=== Accessing Floppies in Real Mode ===
For bootloaders or OSes that run with the CPU remaining in [[Real Mode]], use [[BIOS (PC)#BIOS functions|BIOS Function]] INT13h AH=2 (read) or AH=3 (write) to access
INT13h AH=2 (read) or AH=3 (write) to access floppy drives. You need to know the "drive number" (typically 0 or 1), and put that value in DL.
More detailed info can be found in the [[ATA in x86 RealMode (BIOS)]] article, because accessing a floppy is identical to accessing a hard disk
(using CHS) in Real Mode. The rest of this article deals with creating Protected Mode drivers for the floppy subsystem.
Line 50:
 
=== DMA Data Transfers ===
The floppy typically uses ISA DMA (which is NOT'''not''' the same thing as PCI BusMastering DMA) to do data transfers. The floppy
is hardwired to DMA channel 2. The only other way of doing data transfers is called "PIO Mode" (see below).
 
Line 86:
 
=== There are 3 "Modes" ===
There were several generations of floppy controller chips on several generations of 80286 (and prior) computers, before
the 82077AA chip existed. The 82077AA was built to emulate all of them, by setting various pins on the chip to 5 volts.
The three modes are: PC-AT mode, PS/2 mode, and Model 30 mode.
The only mode you will ever see on any hardware that still runs is PS/2Model 30 mode. InSadly, themost documentation,emulator youprograms run in PS/2 mode!
can ignoreIn the Modeldocumentation, 30you andcan ignore PC-AT modesmode. Or you can try to handle all three, by only using registers and commands that are identical
in all 3 modes.
 
=== Most commands run "silently" ===
There are only a few commands/conditions that produce interrupts: a reset (in polling mode only), Seek, Recalibrate, or one of the many
read/write/verify/format commands. Several commands do not produce any result bytes, either. If you want to verify that a silent
command actually worked, just about the only thing you can do is use the Dumpreg command to check the current state of the
Line 101:
=== Timing Issues ===
On real hardware, there are definite timing issues. Seek delays and motor delays are just what any programmer would expect. It
would be nice if the drive would send an IRQ when the motor was up to speed, but it does not. TheTwo thingthings that you may not
expect isare that quite new hardware may still need artificial delays between outputting "command/parameter" bytes., Thereand is a bit in thethat MSRyou
probably also need artificial delays between inputting "result" bytes. There is a bit in the MSR
to test, to know when the next byte can be sent/retrieved. It is not a good idea to simply hardcode specific delays between output/input bytes.
If you really feel you must do that, though, then a 400ns delay (consisting of reading the MSR port 4 times and discarding the
results) is probably adequate. Looping 20 times, and testing the value of the RMQ bit in the MSR each time, should always be a sufficient "timeout".
 
a sufficient "timeout".
Using IO Port reads to generate delays leads to poor performance in a multitasking environment, and you may want to put the
driver to sleep for the shortest possible period (microsleep), instead.
 
== Registers ==
Line 138 ⟶ 140:
Note: IO port 0x3F6 is the ATA (hard disk) Alternate Status register, and is not used by any floppy controller.
 
Note2: some people prefer to give the registers values based on their offset from the base address, and then add the FDC's base address (0x3F0 or 0x370).
FDC's base address (0x3F0 or 0x370). So STATUS_REGISTER_A would have value 0, STATUS_REGISTER_B value 1, etc., and to access STATUS_REGISTER_B on FDC 1,
access STATUS_REGISTER_B on FDC 1, you would use FDC1_BASE_ADDRESS + STATUS_REGISTER_B = 0x370 + 1 = 0x371.
 
=== Bitflags and Registers that you can rely on ===
Line 199 ⟶ 201:
in place, just in case the IRQs happen anyway. The bit '''must''' be set for DMA to function.
 
Note2: Ifif you want to execute a command that accesses a disk (see the command list below), then that respective disk must have its
motor spinning (and up to speed), '''and''' its "select" bits must be set in the DOR, '''first'''. -- but if you wait more than a
couple of seconds after turning a motor on, it will turn itself off automatically and your command will fail.
 
Note3: toggling DOR reset state requires a 4 microsecond delay. It may be smarter to use DSR reset mode, because
Line 266 ⟶ 269:
Alternately, you can always set both of them, for maximum compatibility with ancient chipsets.
 
The bottom 2 bits specify the data transfer rate to/from the drive. You want both bits set to zero for a 1.44MB or 1.2M2MB floppy drive.
So generally, you want to set CCR to zero just once, after bootup (because the BIOS may not have done it, unless it booted a floppy disk).
 
Line 281 ⟶ 284:
</pre>
 
Note: There is also a 300Kbps (value = 1), and a 250Kbps setting (value = 2) but they are only used for utterly obsolete drives/media.
 
=== Important Bitflags that depend on the Mode ===
 
==== DIR register, Disk Change bit ====
Note: many sources say that you must turn on the drive motor bit before you access the DIR register for a selected drive.
This claim needs further testing.
 
This bit (bit 7, value = 0x80) could be very useful, if it actually works for you. It is supposed to tell you if the floppy door was
opened. Sadly, almost all the emulator programs set and clear this bit completely inappropriately. Do not trust your handling of this
bit until you have tested the functionality on real hardware.
 
Note: many sources say that you must turn on the drive motor bit before you access the DIR register for a selected drive.
This claim needs further testing.
 
Basically, you want to keep a flag for whether there is media in each drive. if Disk Change is "true" and there was media,
the OS should get a signal that the previous media was ejected, and the driver should automatically try to recalibrate the drive
for the new media. The recalibration serves two purposes. The heads may have moved when the new media was inserted, and the
recalibrate will correct for this. Also, the recalibrate will clear the Disk Change flag to "false" if there is '''new''' media
in the drive. You can find out initially whether there is media in the drives by issuing Recalibrate or Seek commands to all the drives
(see the [[#Reinitialization|reinitialization]] procedure below).
 
Line 303 ⟶ 306:
on the drive. If Disk Change remains "true", then the drive is still empty. If it goes "false", it means that a new
floppy has been inserted, and the OS should get a "media inserted" signal. On some/most hardware, it is possible to
simply toggle the drive motor bit on, off, and then on again, to achieve the same result as doing a Seek (Linux calls this a "twaddle").
 
But there is a problem. As the section title says, the problem is that the '''value''' of the Disk Change bitflag depends
Line 317 ⟶ 320:
 
If you ignore PC-AT mode, then you can tell whether Disk Change is true or false by looking at the other bits in upper DIR.
Bits 4, 5, and 6 of DIR tell you what value of Disk Change is "truefalse". Usually "true" = 1 on real hardware.
 
The workaround (to do ONCE): Read DIR. Assume that the current value of Disk Change means "true". Send a Recalibrate command.
Line 371 ⟶ 374:
# Turn on the drive's motor and select the drive, using an "outb" command to the DOR IO port.
# Wait for awhile for the motor to get up to speed, using some waiting scheme.
# Issue your command byte plus some parameter bytes (the "command phase") to the FIFO IO port.
# Exchange data with the drive / "seek" the drive heads (the "execution phase"), on the FIFO IO port.
# Get an IRQ6 at the end of the execution phase, but '''only if the command HAS an execution phase'''.
# Read any "result bytes" produced by the command (the "result phase"), on the FIFO IO port.
# The commands "Recalibrate", "Seek", and "Seek Relative" do not have a result phase, and require an additional "Sense Interrupt" command to be sent.
 
Line 380 ⟶ 383:
 
=== Motor Delays ===
Note: the Linux floppy driver sourcecode has a comment that claims that turning on the motorMOTC foror driveMOTD 2bits orin drivethe 3DOR
on a floppy bus can completely lock up some systems. This claim seems unlikely?
 
Note2: modern floppy drives ignoreonly spin the motordisk bitsfor one or two seconds, and onlythen spinautomatically theturn disk whenthe theymotors thinkback theyoff needby tothemselves.
You need to access the drive within that window, or you will get an error. The motor might not even visibly turn on until you send
a command.
 
When you turn a floppy drive motor on, it takes quite a few milliseconds to "spinup" -- to reach the (stabilized) speed
Line 389 ⟶ 394:
If you start reading/writing immediately after the motor is turned on, "the PLL will fail to lock on to the data signal" and you will get an error.
 
After you are done reading (or writing), you should typically wait an additional 2half secondssecond to turnforce the motor off. (It may also be smart
to seek the heads back to cylinder 0 just before turning the motor off.) You could leave the motor on longer,
but it might give the user the idea that the floppy is still transferring data and that it's taking an awfully long time. --
and, as said above, the floppy drive may well turn its own motor off anyway.
 
The suggested delays when turning the motor on are:
Line 398 ⟶ 404:
* 500 milliseconds (for a 5.25" floppy).
 
These values should be more than enough for any floppy drive to spin up correctly. 100ms50ms should be sufficient, in fact.
 
Another functional method is not delaying or waiting at all, but just enter a loop and keep retrying any command until it works.
Line 417 ⟶ 423:
a 1680Kb floppy disk. These disks may be unreliable on very old computers (where accuracy and speed variation may be worse),
but were considered reliable enough for Microsoft to distribute a version of Windows on 1680Kb floppies (Windows 95 on a set of 12 floppies).
It is also possible to format 3 extra cylinders on each disk, for a total of 83.
 
=== Hardware Control of Bad Cylinders ===
The FDC subsystem has a built-in method for handling unreliable media. However, it is probably not a good idea to use it.
It involves finding a bad sector on the media, and then marking the entire track or cylinder as being bad, during the formatting process.
 
If you try to do this, then you cannot simply seek to a cylinder. All of the cylinders get "remapped" with new "TrackID"s. Whenever
you seek to a cylinder, then you need to use the ReadID command to verify that the cylinder you seeked to contains the data that you
actually want. So this eliminates any possibility of using implied seeks, and adds an extra step to most read/write operations.
 
=== Procedures ===
Line 452 ⟶ 467:
# Do a Drive Select procedure for the next drive to be accessed.
 
Note: A reset clears all the Specify information, so the next Select procedure must send a new Specify command (use some sort of flag to tell the driver to do this).
driver to do this).
 
Note2: Emulators will often set the Disk Change flag to "true" after a reset, '''but this does not happen on real hardware''' -- it is
a shared bug in all the emulators that do it.
 
==== Drive Selection ====
Line 552 ⟶ 571:
 
==== Status Registers ====
 
There are 3 registers that hold information about the last error encountered. The st0 register information
is passed back with the result bytes of most commands, and can be retrieved at any time with a Sense
Line 561 ⟶ 579:
The top bit (value = 0x80) being set indicates two types of errors that you should never see.
Bit 6 (value = 0x40) is set for any "normal" error condition, unless the error locks up the controller completely.
Bit 4 (value = 0x10) is set if Recalibrate, failsSeek, or an implied seek succeeds. The other bits are not useful.
===== st1 =====
The st1 register provides more detail about errors during read/write operations.
Line 683 ⟶ 701:
* First result byte = [[#st0|st0]]
* Second result byte = controller's idea of the current cylinder
 
Note: if you try to read the result bytes without waiting for RQM to set, then you are likely to always get an incorrect result value
of 0. This is also likely to get your driver out of sync with the FDC for input/output.
 
==== Recalibrate ====
Note: There is an error in the FDC datasheet regarding this command. Some statements say the command will try a maximum of 80 head
assembly steps. In other places it says 79 steps. The value 79 is correct.
 
The motor needs to be on, and the drive needs to be selected. For this particular command, you do not have to wait for the command to
complete before selecting a different drive, and sending another Recalibrate command to it. (but the Step Rates have to match, for this
to work).
 
TheIt commandis willpossible only tryfor a maximumnormal of1.44M 80floppy headto assemblybe stepsformatted with 83 cylinders. So, theoretically, it may take severaltwo Recalibrates(or tomore) move the head backRecalibrates
to move the head back to cylinder 0. So itIt is a good idea to test forbit an5 error(value = 0x20) in [[#st0|st0]] after the Sense Interrupt, and retry the command.
retry the Recalibrate command if that bit is clear.
 
* Recalibrate command = 0x7
Line 703 ⟶ 729:
The motor needs to be on, and the drive needs to be selected.
For this particular command, you do not have to wait for the command to complete before selecting a different drive, and sending another
Seek command to it. Maximum cylinder number is 255; if the disk has more, you must use the Relative Seek command, instead. There is
really no reason to ever use head 1 when seeking.
 
* Seek command = 0xf
Line 747 ⟶ 774:
* Seventh result byte = 2
 
Note: if you try to read the result bytes without waiting for RQM to set, then you are likely to always get an incorrect result
value of 0. This is also likely to get your driver out of sync with the FDC for input/output.
 
Note2: Floppy media and electronics are well known for being unreliable. Any read or write command that fails should be retried
at least twice.
 
=== Perpendicular Mode and 2.88M floppies ===
Anonymous user
Cookies help us deliver our services. By using our services, you agree to our use of cookies.

Navigation menu