Floppy Disk Controller: Difference between revisions

Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content deleted Content added
More polling mode info, slight reformat, some fixes
Line 33: Line 33:


=== How Many Drives? ===
=== How Many Drives? ===

It is probably wisest to always get the drive count and types from [[CMOS]], register 0x10.
It is probably wisest to always get the drive count and types from [[CMOS]], register 0x10.


Line 86: Line 85:
if there were any errors. See below for more detail.
if there were any errors. See below for more detail.


==== Bochs can't handle Polling PIO ====
==== Bochs Can't Handle Polling PIO ====
If you try to turn off the IRQs in Bochs (to use pure polling PIO mode), Bochs will panic. It may also not be able to handle
If you try to turn off the IRQs in Bochs (to use pure polling PIO mode), Bochs will panic. It may also not be able to handle
non-DMA data transfers properly, even if IRQs are turned on. It is currently mainly designed to model the floppy using DMA.
non-DMA data transfers properly, even if IRQs are turned on. It is currently mainly designed to model the floppy using DMA.
Line 98: Line 97:
in all 3 modes.
in all 3 modes.


=== Most commands run "silently" ===
=== 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
There are only a few commands/conditions that produce interrupts: a reset (in polling mode only), Seek, Recalibrate, or one of the
read/write/verify/format commands. Several commands do not produce any result bytes, either. If you want to verify that a silent
read/write/verify/format commands. Several commands do not produce any result bytes, either. If you want to verify that a silent
Line 149: Line 148:
access STATUS_REGISTER_B on FDC 1, you would use FDC1_BASE_ADDRESS + STATUS_REGISTER_B = 0x370 + 1 = 0x371.
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 ===
As said above, the most common controller chip has 3 modes, and many bitflags in the registers are different (or opposite!) depending on
As said above, the most common controller chip has 3 modes, and many bitflags in the registers are different (or opposite!) depending on
the mode. However, all of the important registers and bitflags remain the same between modes.
the mode. However, all of the important registers and bitflags remain the same between modes.
They are the following:
They are the following:


=== FIFO and Tape Drive Registers ===
FIFO: The FIFO register may not have a 16byte buffer in all modes, but this is a minor difference that does not really affect its operation.
FIFO: The FIFO register may not have a 16byte buffer in all modes, but this is a minor difference that does not really affect its operation.


TDR: The Tape Drive Register is identical in all modes, but it is useless (you will never find functional equipment that requires it).
TDR: The Tape Drive Register is identical in all modes, but it is useless (you will never find functional equipment that requires it).


==== DOR bitflag definitions ====
=== DOR bitflag definitions ===


{| {{wikitable}}
{| {{wikitable}}
Line 212: Line 211:
the hardware "untoggles" reset mode automatically after the proper delay.
the hardware "untoggles" reset mode automatically after the proper delay.


==== MSR bitflag definitions ====
=== MSR bitflag definitions ===


{| {{wikitable}}
{| {{wikitable}}
Line 267: Line 266:
DIO and BUSY should be checked to verify proper command termination (the end of "result phase" and beginning of "command phase").
DIO and BUSY should be checked to verify proper command termination (the end of "result phase" and beginning of "command phase").


==== CCR and DSR ====
=== CCR and DSR ===
The bottom 2 bits of DSR match CCR, and setting one of them sets the other. The upper 6 bits on both DSR and CCR default to 0, and
The bottom 2 bits of DSR match CCR, and setting one of them sets the other. The upper 6 bits on both DSR and CCR default to 0, and
can always be set to zero safely. So, even though they have different bit definitions, you always set them with identical values, and
can always be set to zero safely. So, even though they have different bit definitions, you always set them with identical values, and
Line 292: Line 291:
Note: There is also a 300Kbps (value = 1), and a 250Kbps setting (value = 2) but they are only for utterly obsolete drives/media.
Note: There is also a 300Kbps (value = 1), and a 250Kbps setting (value = 2) but they are only for utterly obsolete drives/media.


==== DIR register, Disk Change bit ====
=== DIR register, Disk Change bit ===
This bit (bit 7, value = 0x80) is fairly useful. It gets set if the floppy door was opened/closed. Sadly, almost all the emulator
This bit (bit 7, value = 0x80) is fairly useful. It gets set if the floppy door was opened/closed. Sadly, almost all the emulator
programs set and clear this bit completely inappropriately (especially after a reset).
programs set and clear this bit completely inappropriately (especially after a reset).
Line 302: Line 301:


Note2: You must turn on the drive motor bit before you access the DIR register for a selected drive (you do not have to wait
Note2: You must turn on the drive motor bit before you access the DIR register for a selected drive (you do not have to wait
for the motor to spin up, though). It may also be necessary to read the register twice (and discard the first value), when
for the motor to spin up, though). It may also be necessary to read the register five times (discard the first 4 values) when
changing the selected drive -- because "selecting" sometimes takes a little time.
'''changing''' the selected drive -- because "selecting" sometimes takes a little time.


Basically, you want to keep a flag for whether there is media in each drive. If Disk Change is set and there was media,
Basically, you want to keep a flag for whether there is media in each drive. If Disk Change is set and there was media,
the OS should get a signal that the previous media was ejected.
the OS should get a signal that the previous media was ejected.


Once the Disk Change bit gets set (and you have "processed that message"), you need to try to clear the bit. The main way to
Once the Disk Change bit signals "true" (and you have processed that "event"), you need to try to clear the bit. The main way to
clear the bit is with a '''successful''' Seek to a '''new''' cylinder on the media. (Recalibrate or Reset do not work. And if the
clear the bit is with a '''successful''' Seek/Recalibrate to a '''new''' cylinder on the media. (A reset does not work. If the
controller thinks the heads are already on the correct cylinder, it will eat the Seek command without clearing the Disk
controller thinks the heads are already on the correct cylinder, it will eat a Seek command without clearing the Disk
Change bit.) If the seek fails, you can be fairly certain that there is no media in the drive anymore. It is important to note that
Change bit. If the heads are already on cylinder 0, a Recalibrate is also a no-op.) If the seek '''fails''', you can be fairly
certain that there is no media in the drive anymore. It is important to note that
this means you should check the value of Disk Change just prior to every Seek command that you do, because otherwise you
this means you should check the value of Disk Change just prior to every Seek command that you do, because otherwise you
will lose any Disk Change information. This is also true for implied seeks, and relative seeks.
will lose any Disk Change information. This is also true for implied seeks, and relative seeks.
Line 321: Line 321:


== Programming Details ==
== Programming Details ==
Overall, the controller needs to be initialized and reset (see below for the steps involved). Then a particular drive can be
Overall, the controller needs to be initialized and reset once (see below for the steps involved). Then drives can be
accessed. To do that, you:
accessed. To access drives:
# Turn on the drive's motor and select the drive, using an "outb" command to the DOR IO port.
# 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 (but don't wait too long).
# 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.
# 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.
# Exchange data with the drive / "seek" the drive heads (the "execution phase"), on the FIFO IO port.
Line 346: Line 346:
The reason to leave the motor on is that your driver may not know if there is a queue of sector reads or writes
The reason to leave the motor on is that your driver may not know if there is a queue of sector reads or writes
that are going to be executed next. If there are going to be more drive accesses immediately, they won't need to wait
that are going to be executed next. If there are going to be more drive accesses immediately, they won't need to wait
for the motor to spin up, if the motor is still on.
for the motor to spin up.


The suggested delays when turning the motor on are:
The suggested delays when turning the motor on are:
Line 386: Line 386:
==== Reinitialization ====
==== Reinitialization ====


The BIOS probably leaves the controller in its default state. Polling on, FIFO off, threshold = 1, implied seek off, lock off. This
The BIOS probably leaves the controller in its default state. "Drive polling mode" on, FIFO off, threshold = 1, implied seek off,
is a lousy state for the controller to be in, and your OS will need to fix it. The BIOS probably also does not have any better
lock off. This is a lousy state for the controller to be in, and your OS will need to fix it. The BIOS probably also does not have
guess as to the proper values for the "Specify" command than your OS does (the values are specific to the particular drive). There
any better guess as to the proper values for the "Specify" command than your OS does (the values are specific to the particular
is certainly no reason why you should trust the BIOS to have done any of it '''correctly.'''
drive). There is certainly no reason why you should trust the BIOS to have done any of it '''correctly.'''


So, when your OS is initializing:
So, when your OS is initializing:
# Send 4 Sense Interrupt commands to the controller. This may clear a problem with default "polling mode".
# Send a Version command to the controller.
# Send a Version command to the controller.
# Verify that the result byte is 0x90 -- if it is not, it might be a good idea to abort and not support the floppy subsystem. Almost all of the code based on this article will work, even on the oldest chipsets -- but there are a few commands that will not.
# Verify that the result byte is 0x90 -- if it is not, it might be a good idea to abort and not support the floppy subsystem. Almost all of the code based on this article will work, even on the oldest chipsets -- but there are a few commands that will not.
# If you don't want to bother having to send another Configure command after every Reset procedure, then:
# If you don't want to bother having to send another Configure command after every Reset procedure, then:
## Send a better Configure command to the controller. A suggestion would be: polling off, FIFO on, threshold = 8, implied seek on, precompensation 0.
## Send a better Configure command to the controller. A suggestion would be: drive polling mode off, FIFO on, threshold = 8, implied seek on, precompensation 0.
## send a Lock command.
## send a Lock command.
# Do a Controller Reset procedure.
# Do a Controller Reset procedure.
# Send a Recalibrate command to each of the drives. (You can do them all at the same time, or you can use this as an opportunity to handle the "Disk Change" bit, and/or you can use this as a chance to detect which drives actually have media in them.)
# Send a Recalibrate command to each of the drives.


==== Controller Reset ====
==== Controller Reset ====
Line 410: Line 409:
## Bit 2 (value = 4) in the DOR: Save the current/"original" value of the DOR, write a 0 to the DOR, wait 4 microseconds, then write the original value (bit 2 is always set) back to the DOR.
## Bit 2 (value = 4) in the DOR: Save the current/"original" value of the DOR, write a 0 to the DOR, wait 4 microseconds, then write the original value (bit 2 is always set) back to the DOR.
## '''or''' Bit 7 (value = 0x80) in the DSR: Precalculate a good value for the DSR (generally 0), and OR it with 0x80. Write that value to the DSR.
## '''or''' Bit 7 (value = 0x80) in the DSR: Precalculate a good value for the DSR (generally 0), and OR it with 0x80. Write that value to the DSR.
# Wait for the resulting IRQ6. HIHI!! only in polling mode?
# Wait for the resulting IRQ6 (unless you have IRQs turned off in the DOR)
# Send a Sense Interrupt command (required).
# If (and only if) [[#Configure|drive polling mode]] is turned on, send 4 Sense Interrupt commands (required).
# If your OS/driver never turned off polling mode (see the Configure command), then you have to send 3 more Sense Interrupt commands. (Alternately, you can tell if you need the extra 3 by examining the top 2 bits of the st0 byte returned by the first Sense Interrupt. If both bits are set, you need to send 3 more.)
# If your OS/driver never sent a Lock command, then you probably need to send a new Configure command (the fifo settings were lost in the reset).
# If your OS/driver never sent a Lock command, then you need to send a new Configure command (the fifo information was lost in the reset).
# Do a Drive Select procedure for the next drive to be accessed.
# Do a Drive Select procedure for the next drive to be accessed.


Line 421: Line 419:
Note2: Emulators will often set the Disk Change flag to "true" after a reset, '''but this does not happen on real hardware''' -- it is
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.
a shared bug in all the emulators that do it.

Note3: A reset does not change the [[#Configure|drive polling mode or implied seek]] settings.


==== Drive Selection ====
==== Drive Selection ====
Line 437: Line 437:
command fails -- this may be the reason why.
command fails -- this may be the reason why.


# Turn the drive motor bit on.
# Read DIR. If the "Disk Change" bitflag is set to "true", then the floppy drive door was opened, so the OS needs to test if a new disk is in the drive.
# Read DIR. If the "Disk Change" bitflag is set to "true", then the floppy drive door was opened, so the OS needs to test if a new disk is in the drive.


Line 452: Line 453:
# Verify that RQM = 1 and DIO = 0 ((Value & 0xc0) == 0x80) -- if not, reset the controller and start all over.
# Verify that RQM = 1 and DIO = 0 ((Value & 0xc0) == 0x80) -- if not, reset the controller and start all over.
# Send your chosen command byte to the FIFO port (port 0x3F5).
# Send your chosen command byte to the FIFO port (port 0x3F5).
# In a loop: loop on reading MSR until RQM = 1, then send the next parameter byte for the command to the FIFO port.
# In a loop: loop on reading MSR until RQM = 1. Verify DIO = 0, then send the next parameter byte for the command to the FIFO port.
# Either Execution or Result Phase begins when all parameter bytes have been sent, depending on whether you are in PIO mode, and the command has an Execution phase. If using DMA, or the command does not perform read/write/head movement operations, skip to the Result Phase.
# Either Execution or Result Phase begins when all parameter bytes have been sent, depending on whether you are in PIO mode, and the command has an Execution phase. If using DMA, or the command does not perform read/write/head movement operations, skip to the Result Phase.
# (In PIO Mode Execution phase) read MSR, verify NDMA = 1 ((Value & 0x20) == 0x20) -- if it's not set, the command has no Execution phase, so skip to Result phase.
# (In PIO Mode Execution phase) read MSR, verify NDMA = 1 ((Value & 0x20) == 0x20) -- if it's not set, the command has no Execution phase, so skip to Result phase.
Line 543: Line 544:
==== Configure ====
==== Configure ====
This command initializes controller-specific values: the data buffer "threshold" value, implied seek enable, FIFO disable, polling enable.
This command initializes controller-specific values: the data buffer "threshold" value, implied seek enable, FIFO disable, polling enable.
(And "Write Precompensation".) A good setting is: implied seek on, FIFO on, polling off, threshold = 8, precompensation 0.
(And "Write Precompensation".) A good setting is: implied seek on, FIFO on, drive polling mode off, threshold = 8, precompensation 0.


If you enable implied seeks, then you don't have to send Seek commands (or Sense Interrupt commands for the Seek commands).
If you enable implied seeks, then you don't have to send Seek commands (or Sense Interrupt commands for the Seek commands).
Line 551: Line 552:
transfer!).
transfer!).


Polling is just an annoyance that is there for backwards software compatibility. It makes you need extra Sense Interrupts
Drive polling mode is just an annoyance that is there for backwards software compatibility. It makes you need Sense Interrupts
after every reset. Always turn it off, if you send a Configure command.
after every reset. Always turn it off, if you send a Configure command.


Line 562: Line 563:
* Configure command = 0x13
* Configure command = 0x13
* First parameter byte = 0
* First parameter byte = 0
* Second parameter byte = (implied seek enable << 6) | (fifo '''DIS'''able << 5) | (polling enable << 4) | thresh_val (= threshold - 1)
* Second parameter byte = (implied seek enable << 6) | (fifo '''DIS'''able << 5) | (drive polling mode enable << 4) | thresh_val (= threshold - 1)
* Third parameter byte = precomp_val = 0
* Third parameter byte = precomp_val = 0
* No result bytes.
* No result bytes.
Line 636: Line 637:
bitflag in the controller. It is required in three circumstances that produce interrupts.
bitflag in the controller. It is required in three circumstances that produce interrupts.


# After doing a Controller Reset procedure (you may need to send 4 of them, then).
# After doing a Controller Reset procedure with [[#Configure|drive polling mode]] turned on.
# After the completion of a Seek command (or Relative Seek).
# After the completion of a Seek command (or Relative Seek).
# After the completion of a Recalibrate command.
# After the completion of a Recalibrate command.


These are the only times when you should send a Sense Interrupt. You should still send them even if you have IRQs turned off in
These are the only times when you should send a Sense Interrupt. You should still send them even if you have IRQs turned off in
the DOR and you are using polling instead.
the DOR and you are using PIO polling instead. If you send Sense Interrupt commands at other times: the command will complete, return
a 0x80, and then lock up the controller until you do a Reset.


* Sense Interrupt command = 0x8
* Sense Interrupt command = 0x8
Line 651: Line 653:
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
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. The correct value of st0 after a reset should
of 0. This is also likely to get your driver out of sync with the FDC for input/output. The correct value of st0 after a reset should
be 0xC0 | drive number. After a Recalibrate/Seek it should be 0x20 | drive number.
be 0xC0 | drive number (drive number = 0 to 3). After a Recalibrate/Seek it should be 0x20 | drive number.


==== Recalibrate ====
==== Recalibrate ====