Floppy Disk Controller: Difference between revisions

Jump to navigation Jump to search
[unchecked revision][unchecked revision]
Content deleted Content added
added source tags
Creature (talk | contribs)
Cleaned up the article and added some additional information.
Line 1: Line 1:
The Floppy Disk Controller (FDC) is a (legacy) device that controls hardware for access to 3.5/5.25 inch floppy disks. There are a range of chips that have been produced for this function and include: 8272A, 82078, 82077SL & 82077AA.
The Floppy Disk Controller (FDC) is a (legacy) device that controls hardware for access to 3.5/5.25 inch floppy disks. There are a range of chips that have been produced for this function and include: 8272A, 82078, 82077SL & 82077AA.


==A quick look at floppy hardware==
== Quick Look at the Hardware ==
The floppy controller is programmed through 8 registers, which can be accessed from ports 0x3F0 through 0x3F7. As usual on the PC architecture, some of those registers have different meanings depending on whether you read from or write to them. For extra information, please refer to the datasheet (see the link below). Note that snippets and datasheets name those registers based on their trigrams (e.g. SRA, MSR, DIR, CCR, etc.).

The most common floppy registers can be found in the following enumeration:


Floppy controller is programmed through 8 registers accessed from 0x3F0 through 0x3F7 I/O ports. As usual on PC architecture, some of those registers have different meaning depending on whether you read or write them. For extra info, refer to the datasheet (see link below). Note that snippets and datasheets name those registers from their trigrams (e.g. SRA, MSR, DIR, CCR, etc)
<source lang="c">
<source lang="c">
enum FloppyRegisters {
enum FloppyRegisters
{
STATUS_REGISTER_A = 0x3F0, // read-only
STATUS_REGISTER_B = 0x3F1, // read-only
STATUS_REGISTER_A = 0x3F0, // read-only
STATUS_REGISTER_B = 0x3F1, // read-only
DIGITAL_OUTPUT_REGISTER = 0x3F2,
TAPE_DRIVE_REGISTER = 0x3F3,
DIGITAL_OUTPUT_REGISTER = 0x3F2,
TAPE_DRIVE_REGISTER = 0x3F3,
MAIN_STATUS_REGISTER = 0x3F4, // read-only
DATA_RATE_SELECT_REGISTER= 0x3F4, // write-only
MAIN_STATUS_REGISTER = 0x3F4, // read-only
DATA_RATE_SELECT_REGISTER = 0x3F4, // write-only
DATA_FIFO = 0x3F5,
DATA_FIFO = 0x3F5,
DIGITAL_INPUT_REGISTER = 0x3F7, // read-only
CONFIGURATION_CONTROL_REGISTER = 0x3F7, //write only
DIGITAL_INPUT_REGISTER = 0x3F7, // read-only
CONFIGURATION_CONTROL_REGISTER = 0x3F7 // write-only
};
};
</source>
</source>

Note that this only applies to FDC (Floppy Disk Controller) 0. FDC 1 can usually be found at address 0x370, some people prefer to give the registers values based on their offset from the base address, and then add the FDC's base address based on what FDC you want to use. So STATUS_REGISTER_A would have value 0, STATUS_REGISTER_B value 1, and so on. Then when you want to access STATUS_REGISTER_B on FDC 1, you would use FDC1_BASE_ADDRESS + STATUS_REGISTER_B = 0x370 + 1 = 0x371.


Note that all command parameter information and disk data transfers go through the FIFO. The other registers barely tell you if the disk/controller is busy or not (MSR), control the transfer rate (DIR, CCR, DRS) and select disks (DOR).
Note that all command parameter information and disk data transfers go through the FIFO. The other registers barely tell you if the disk/controller is busy or not (MSR), control the transfer rate (DIR, CCR, DRS) and select disks (DOR).


Beyond that basic configuration, you talk to the floppy controller by the way of _commands_ sent through the data fifo. Each command is a sequence of bytes that start with a command code and optional parameters. Note that most of these commands have 'option' bits (such as MFM, MT) which are not covered here.
Beyond that basic configuration, you talk to the floppy controller by sending commands through the data FIFO. Each command is a sequence of bytes that starts with a command code and optionally has some parameters. Note that most of these commands have 'option' bits, such as MFM and MT, which are not covered here.

<source lang="c">
<source lang="c">
enum FloppyCommands {
enum FloppyCommands
{
READ_TRACK = 2,
SPECIFY = 3,
READ_TRACK = 2,
SPECIFY = 3,
SENSE_DRIVE_STATUS = 4,
WRITE_DATA = 5,
SENSE_DRIVE_STATUS = 4,
READ_DATA = 6,
WRITE_DATA = 5,
READ_DATA = 6,
RECALIBRATE = 7,
RECALIBRATE = 7,
SENSE_INTERRUPT = 8,
SENSE_INTERRUPT = 8,
WRITE_DELETED_DATA = 9,
READ_ID = 10,
WRITE_DELETED_DATA = 9,
READ_ID = 10,
READ_DELETED_DATA = 12,
READ_DELETED_DATA = 12,
FORMAT_TRACK = 13,
FORMAT_TRACK = 13,
SEEK = 15,
SEEK = 15,
VERSION = 16,
VERSION = 16,
SCAN_EQUAL = 17,
SCAN_EQUAL = 17,
PERPENDICULAR_MODE = 18,
PERPENDICULAR_MODE = 18,
CONFIGURE = 19,
CONFIGURE = 19,
VERIFY = 22,
VERIFY = 22,
SCAN_LOW_OR_EQUAL = 25,
SCAN_LOW_OR_EQUAL = 25,
SCAN_HIGH_OR_EQUAL = 29,
SCAN_HIGH_OR_EQUAL = 29
};
};
</source>
</source>

There are several things you need to take into account when programming a floppy controller:
== Programming Notes ==
*motor spinning: You need to turn the motor on and wait for a suitable amount of time after that so that the motor has reached the speed needed for data transfer. You're also welcome to stop the motor after you're done reading (but preferably not too early). The recommended "motor on" delays are 300 mS for a 3.5 inch floppy and 500 mS for a 5.25 inch floppy (these values should be conservative). If you start a read immediately after turning the floppy motor on, the internal electronics will fail to "lock on" to the signal being read and you'll get an error. It is possible to use this to minimize (or avoid) the "motor on" delay by repeatedly retrying the read until it works successfully. Typically a delay of 2 seconds is used for the "motor off" delay - longer delays increase the chance that the "motor on" delay can be avoided for additional data transfers (but leaving the motor on for longer can give users the perception that data is still being transfered, and that it's taking too long!).
There are several things you need to take into account when programming the floppy controller(s). These things include motor spinning, data transfers and head positions.
*data transfers: Those occur using the ISA DMA controller. The "data fifo" register is mainly there to exchange commands and status information with the controller (e.g. what track/sector you want, etc.)

*head positions: Before you can read/write to a track, you need to issue a "seek/recalibrate" command to reach that track.
=== Motor Spinning ===
What you need to do is turn the motor on and then wait for a while so the motor gets the time it needs to reach the speed needed for data transfer. After you're done reading (or writing), you can stop the floppy motor if you want (but be careful not to stop it too early). The recommended delays when turning the motor on are:

* 300 milliseconds (for a 3.5" floppy).
* 500 milliseconds (for a 5.25" floppy).

Note that these are 'approximate' values and serve as an example, but they should be more than enough for a floppy drive to spin up correctly. When you start reading immediately after the motor is turned on, the internal electronics will fail to 'lock on' to the signal you sent and you'll get error.

Another way of performing an operation is not delaying or waiting at all, but just enter a loop and keep trying to perform the operation until it works.

When you want to turn the motor off, you should typically wait an additional 2 seconds. You could leave the motor on too, but it might give the user the idea that the floppy is still transfering data and that it's taking an awfully long time.

=== Data Transfers ===
These occur when you're using the ISA DMA controller. The data FIFO register is mainly used to exchange commands and status information with the controller (e.g. what track/sector to use).

=== Head Positions ===
Before you can read or write to a track, you need to issue a Seek/Recalibrate command to reach that track.


==How do I read/write to the floppy in [[Protected Mode|protected mode]]?==
==How do I read/write to the floppy in [[Protected Mode|protected mode]]?==