Floppy Disk Controller: Difference between revisions

Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content deleted Content added
added 2 commands to the command listing
Fixed errors re: IRQs
Line 74: Line 74:
in/out of the FIFO buffer -- or wait for an IRQ6 to do the same thing. When the transfer is complete, read the "result" bytes to see
in/out of the FIFO buffer -- or wait for an IRQ6 to do the same thing. When the transfer is complete, read the "result" bytes to see
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 ====
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 only designed to model the floppy using DMA.


=== There are 3 "Modes" ===
=== There are 3 "Modes" ===
Line 82: Line 86:
can just ignore the other 2 modes. Or you can try to handle all three, by only using registers and commands that are identical
can just ignore the other 2 modes. Or you can try to handle all three, by only using registers and commands that are identical
in all 3 modes. The mode does not affect the driver code much, except for detecting "Disk Change".
in all 3 modes. The mode does not affect the driver code much, except for detecting "Disk Change".

=== Most commands run "silently" ===
There are only a few commands/conditions that produce interrupts: a reset, Seek, Recalibrate, or one of the (several kinds of)
read/write/verify/format commands. Many of the commands do not produce any result bytes, either. If you want to verify that your
command actually worked, just about the only thing you can do is use the Dumpreg command to check the current state of the
controller.


== Registers ==
== Registers ==
Line 225: Line 235:
|}
|}


The two important bits are RQM and DIO. NDMA is also useful in polling PIO mode, and BUSY, too.
The two important bits are RQM and DIO. NDMA and BUSY are also useful in polling PIO mode.
Most important is RQM, which is set when it is OK (or necessary!) to read/write data from/to the FIFO port.
Most important is RQM, which is set when it is OK (or necessary!) to read/write data from/to the FIFO port.
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").
Line 234: Line 244:
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
one or the other of DSR and CCR can be ignored in any modern system.
one or the other of DSR and CCR can be ignored in any modern system.
Alternately, you can always set both of them (and then do two Sense Interrupt commands), for maximum compatibility with ancient chipsets.
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 floppy drive.
The bottom 2 bits specify the data transfer rate to/from the drive. You want both bits set to zero for a 1.44MB floppy drive.
So generally, you want to set CCR to zero just once, after bootup (because the BIOS may not have done it). This produces an IRQ6 which
So generally, you want to set CCR to zero just once, after bootup (because the BIOS may not have done it).
must be waited for (or RQM polled in PIO mode, if IRQ6 is disabled). Then a Sense Interrupt command is mandatory.


Note: a reset procedure does not affect this register. However, if you have drives of different types on the bus which
Note: a reset procedure does not affect this register. However, if you have drives of different types on the bus which
Line 334: Line 343:
# Issue your command byte plus some parameter bytes (the "command phase").
# Issue your command byte plus some parameter bytes (the "command phase").
# Exchange data with the drive / "seek" the drive heads (the "execution phase").
# Exchange data with the drive / "seek" the drive heads (the "execution phase").
# Get an IRQ6 at the end of the execution phase.
# 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").
# Read any "result bytes" produced by the command (the "result phase").
# The commands "Recalibrate", "Seek", and "Seek Relative" require an additional "Sense Interrupt" command to be sent.
# The commands "Recalibrate", "Seek", and "Seek Relative" require an additional "Sense Interrupt" command to be sent.
Line 404: Line 413:
# Wait for the resulting IRQ6.
# Wait for the resulting IRQ6.
# Send a Sense Interrupt command (required).
# Send a Sense Interrupt command (required).
# If your OS/driver never sent a Lock command, then you have to send 3 more Sense Interrupt commands and you need to send a new Configure command.
# If your OS/driver never turned off polling mode (see the Configure command), then you have to send 3 more Sense Interrupt commands and you need to send a new Configure command.
# 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 416: Line 425:


# Send the correct Datarate setting to CCR. Usually this is a 0 (1.44MB floppy drive).
# Send the correct Datarate setting to CCR. Usually this is a 0 (1.44MB floppy drive).
# Wait for the IRQ6.
# Send a Sense Interrupt command (required).
# If the newly selected drive is a different type than the previously selected drive (or changing from PIO to DMA mode), send a new Specify command.
# If the newly selected drive is a different type than the previously selected drive (or changing from PIO to DMA mode), send a new Specify command.
# Set the "drive select" bits (and the other bitflags) in DOR properly, including possibly turning on the Motor bit for the drive (if it will be accessed soon).
# Set the "drive select" bits (and the other bitflags) in DOR properly, including possibly turning on the Motor bit for the drive (if it will be accessed soon).
Line 444: Line 451:
# 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, then send the next parameter byte for the command to the FIFO port.
# Execution Phase begins when all parameter bytes have been sent.
# 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.
# If using DMA, or the command does not perform read/write operations, skip to the Result Phase.
# (In PIO Mode) read MSR, verify NDMA = 1 ((Value & 0x20) == 0x20)
# begin a loop:
# begin a loop:
# Either poll MSR until RQM = 1, or wait for an IRQ6, using some waiting method.
# Either poll MSR until RQM = 1, or wait for an IRQ6, using some waiting method.
# In an inner loop: transfer a byte in or out of the FIFO port via a system buffer, then read MSR. Repeat while RQM = 1 and NDMA = 1 ((Value & 0xa0) == 0xa0).
# In an inner loop: transfer a byte in or out of the FIFO port via a system buffer, then read MSR. Repeat while RQM = 1 and NDMA = 1 ((Value & 0xa0) == 0xa0).
# if NDMA = 1, loop back to the beginning of the outer loop, unless your data buffer ran out (detect underflow/overflow).
# if NDMA = 1, loop back to the beginning of the outer loop, unless your data buffer ran out (detect underflow/overflow).
# Result Phase begins. If the command does not have a Result phase, it silently exits to waiting for the next command.
# Result Phase begins.
# if using DMA, wait for a terminal IRQ6
# If using DMA on a read/write command, wait for a terminal IRQ6.
## Loop on reading MSR until RQM = 1, verify that DIO = 1.
# ''If the command has a result phase:''
## loop on reading MSR until RQM = 1, verify that DIO = 1
## In a loop: read the next result byte from the FIFO, loop on reading MSR until RQM = 1, verify CMD BSY = 1 and DIO = 1 ((Value & 0x50) == 0x50).
## In a loop: read the next result byte from the FIFO, loop on reading MSR until RQM = 1, verify CMD BSY = 1 and DIO = 1 ((Value & 0x50) == 0x50).
# After reading all the expected result bytes: check them for error conditions, verify that RQM = 1, CMD BSY = 0, and DIO = 0. '''If not''' retry the
# After reading all the expected result bytes: check them for error conditions, verify that RQM = 1, CMD BSY = 0, and DIO = 0. '''If not''' retry the
Line 559: Line 564:
* Third parameter byte = precomp_val = 0
* Third parameter byte = precomp_val = 0
* No result bytes.
* No result bytes.
* No interrupt.


==== Version ====
==== Version ====
Line 565: Line 571:
* Version command = 0x10
* Version command = 0x10
* No parameter bytes.
* No parameter bytes.
* No interrupt.
* First result byte = 0x90
* First result byte = 0x90


Line 576: Line 583:
* '''or''' Unlock command = 0x14
* '''or''' Unlock command = 0x14
* No parameter bytes.
* No parameter bytes.
* No interrupt.
* First result byte = lock bit << 4
* First result byte = lock bit << 4


Line 591: Line 599:
* Second parameter byte = HLT_value << 1 | NDMA
* Second parameter byte = HLT_value << 1 | NDMA
* No result bytes.
* No result bytes.
* No interrupt.


===== SRT, HLT and HUT =====
===== SRT, HLT and HUT =====
Line 626: Line 635:
bitflag in the controller. It is required in four circumstances that produce interrupts.
bitflag in the controller. It is required in four circumstances that produce interrupts.


# After setting the datarate in CCR/DSR.
# After doing a Controller Reset procedure (you may need to send 4 of them, then).
# After doing a Controller Reset procedure (you may need to send 4 of them, then).
# 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 it 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 polling instead.


* Sense Interrupt command = 0x8
* Sense Interrupt command = 0x8
* No parameter bytes
* No parameter bytes.
* No interrupt.
* First result byte = [[#st0|st0]]
* First result byte = [[#st0|st0]]
* Second result byte = controller's idea of the current cylinder
* Second result byte = controller's idea of the current cylinder
Line 644: Line 653:


The command will only try a maximum of 80 head assembly steps. So, theoretically, it may take several Recalibrates to move the head back
The command will only try a maximum of 80 head assembly steps. So, theoretically, it may take several Recalibrates to move the head back
to cylinder 0. So it is a good idea to test for an error in [#st0] after the Sense Interrupt, and retry the command.
to cylinder 0. So it is a good idea to test for an error in [[#st0|st0]] after the Sense Interrupt, and retry the command.


* Recalibrate command = 0x7
* Recalibrate command = 0x7
* First parameter byte = drive number = 0 to 3.
* First parameter byte = drive number = 0 to 3.
* No result bytes.
* No result bytes.
* The interrupt may take up to 3 seconds to arrive, so use a long timeout.


It is possible to poll the "disk active" bits in the MSR to find out when the head movement is finished.
It is possible to poll the "disk active" bits in the MSR to find out when the head movement is finished.
HIHI!! mention that Sense Int is only needed if INTs are turned on!
A Sense Interrupt command is required after this command completes, to clear it from being BUSY. (Multiple Sense Interrupts,
A Sense Interrupt command is required after this command completes, to clear it from being BUSY. (Multiple Sense Interrupts,
if you ran multiple simultaneous Recalibrates.)
if you ran multiple simultaneous Recalibrates.)
Line 664: Line 673:
* Second parameter byte = requested cylinder number
* Second parameter byte = requested cylinder number
* No result bytes.
* No result bytes.
* The interrupt may take up to 3 seconds to arrive, so use a long timeout.


It is possible to poll the "disk active" bits in the MSR to find out when the head movement is finished.
It is possible to poll the "disk active" bits in the MSR to find out when the head movement is finished.
Line 713: Line 723:
* First parameter byte = (Drive 3 enable << 5) | (Drive 2 enable << 4) | (Drive 1 enable << 3) | (Drive 0 enable << 2)
* First parameter byte = (Drive 3 enable << 5) | (Drive 2 enable << 4) | (Drive 1 enable << 3) | (Drive 0 enable << 2)
* No result bytes.
* No result bytes.
* No interrupt.


You also need to set CCR/DSR for the 1M datarate (value = 3) to access a 2.88M drive.
You also need to set CCR/DSR for the 1M datarate (value = 3) to access a 2.88M drive.