Floppy Disk Controller: Difference between revisions

Added USB comment, comments about emulation errors
[unchecked revision][unchecked revision]
(Fixed errors re: IRQs)
(Added USB comment, comments about emulation errors)
Line 8:
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.
 
=== Accessing USB Floppy Drives ===
All [[USB]] devices, including USB floppy drives, are accessed indirectly (using SCSI-style commands encoded in USB datapackets) over the USB bus.
USB floppy drives do not use any of the IO ports or FDC commands described in this article.
 
=== The Floppy Subsystem is Ugly ===
Line 77 ⟶ 81:
==== 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 onlymainly designed to model the floppy using DMA.
 
=== There are 3 "Modes" ===
There were several generations of floppy controller chips on several generations of 80286 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 mode you will typically see on emulators is Model 30 Mode.
The only mode you will ever see on any hardware that still runs is ModelPS/2 30 Modemode. SoIt inis theunfortunate documentation,that youemulators get this wrong,
but the only real effect from it is in the logic for testing "Disk Change" (see below). In the documentation, you
can just ignore the other 2PC-AT 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.
 
=== 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 youra silent
command actually worked, just about the only thing you can do is use the Dumpreg command to check the current state of the
controller.
 
=== 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 doesn't. The thing that you '''don't'''
expect is that you need a microsecond delay between each command/parameter byte that you output to the FDC, even on machines as recent as Pentium
166 systems. This can be done by, for example, reading port 0x3F6 (the ATA alternate status port) 10 times. Or, you can just decide
that the floppy is a low priority device, and swap out the driver between each output byte. Wasting an entire microsecond of CPU
time just to make FDC commands run as quickly as possible seems unreasonable.
 
== Registers ==
Line 132 ⟶ 145:
 
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.
But be sure to place a fairly big delay (1 microsecond) betweeen each "outb" to the FIFO.
 
TDR: The Tape Drive Register is identical in all modes, but it is useless (you will never find functional equipment that requires it).
 
Line 137 ⟶ 152:
 
{| {{wikitable}}
|-
! Mnemonic
! bit number
! value
! meaning/usage
|-
| MOTD
| 7
| 0x80
| Set to turn drive 3's motor ON
|-
| MOTC
| 6
| 0x40
| Set to turn drive 2's motor ON
|-
| MOTB
| 5
| 0x20
| Set to turn drive 1's motor ON
|-
| MOTA
| 4
| 0x10
| Set to turn drive 0's motor ON
|-
| IRQ
| 3
| 8
| Set to enable IRQs and DMA
|-
| RESET
| 2
| 4
| Clear = enter reset mode, Set = normal operation
|-
| DSEL1 and 0
| 0, 1
Line 184 ⟶ 199:
Note2: If 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'''.
 
Note3: toggling DOR reset state requires a 4 microsecond delay. It may be smarter to use DSR reset mode, because
the hardware "untoggles" reset mode automatically after the proper delay.
 
==== MSR bitflag definitions ====
 
{| {{wikitable}}
|-
! Mnemonic
! bit number
! value
! meaning/usage
|-
| RQM
| 7
| 0x80
| Set if it's OK (or mandatory) to exchange bytes with the FIFO IO port
|-
| DIO
| 6
| 0x40
| Set if FIFO IO port expects an IN opcode
|-
| NDMA
| 5
| 0x20
| Set in Execution phase of PIO mode read/write commands only.
|-
| CB
| 4
| 0x10
| Command Busy: set when command byte received, cleared at end of Result phase
|-
| ACTD
| 3
| 8
| Drive 3 is seeking
|-
| ACTC
| 2
| 4
| Drive 2 is seeking
|-
| ACTB
| 1
| 2
| Drive 1 is seeking
|-
| ACTA
| 0
Line 268 ⟶ 286:
 
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
opened/closed.
bit until you have tested the functionality on real hardware.
 
SoBasically, you want to keep a flag for whether there is media in the drive. if Disk Change is "true" and there was media,
the OS should get a signal that the previous media was ejected.
 
Line 300 ⟶ 319:
Logic diagram:
{| {{wikitable}}
|-
! State of media
! actual DskChg flag
! guess
! Recalibrate result
! new actual DskChg flag
! guess good?
|-
| None in drive
| true
Line 314 ⟶ 333:
| true
| yes
|-
| Just inserted
| true
Line 321 ⟶ 340:
| false
| yes
|-
| accessed many times
| false
Line 409 ⟶ 428:
 
# Either use:
## 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.
# Wait for the resulting IRQ6.
# Send a Sense Interrupt command (required).
# 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.
(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 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.
 
Line 431 ⟶ 453:
 
The user can swap media out of a floppy drive at any moment. If your driver sends a command to the drive, and the
command fails -- this may be the reason why.
 
# You need to either know or assume the "true" value for the Disk Change bitflag in DIR.
Line 481 ⟶ 503:
enum FloppyCommands
{
READ_TRACK = 2, // generates IRQ6
SPECIFY = 3, // * set drive parameters
SENSE_DRIVE_STATUS = 4,
Line 489 ⟶ 511:
SENSE_INTERRUPT = 8, // * ack IRQ6, get status of last command
WRITE_DELETED_DATA = 9,
READ_ID = 10, // generates IRQ6
READ_DELETED_DATA = 12,
FORMAT_TRACK = 13, // *
Line 633 ⟶ 655:
==== Sense Interrupt ====
This command's main function is to return any error code from a Seek or Recalibrate command to your driver. It also clears an internal
bitflag in the controller. It is required in fourthree circumstances that produce interrupts.
 
# After doing a Controller Reset procedure (you may need to send 4 of them, then).
Anonymous user