Floppy Disk Controller: Difference between revisions

m
Bot: Replace deprecated source tag with syntaxhighlight
[unchecked revision][unchecked revision]
m (fixed a formatting issue)
m (Bot: Replace deprecated source tag with syntaxhighlight)
 
(24 intermediate revisions by 15 users not shown)
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 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
Line 29:
subsystem is the primary remaining one that accesses the obsolete and terrible ISA DMA system for its data transfers.
 
=== How Many Controllers? One! Usually. ===
Each ribbon cable for floppy drives can support 2 drives. One floppy controller chip can control 2 floppy cables, for a total
of 4 drives. It is theoretically possible for a system to have more than one controller chip, but you will not find anymany existing systems with
more than one. If a system were to havehas more than one floppy controller, the second controller wouldwill be found at a base IO port address of 0x370.
 
Some systems also have a third floppy controller, but these are exceedingly rare. Most of these will have originally been disk
duplication systems. The third floppy controller can be found at a base IO port address of 0x360.
 
=== How Many Drives? ===
Line 53 ⟶ 56:
numbers are typically 0 to 79 inclusive, heads are 0 or 1, and sector numbers are 1 to 18 inclusive. Asking for sector number 0
is always highly illegal and this is a major source of errors in prototype driver code.
 
It is, however, much more logical to address things in LBA (Logical Block Addressing), as the first sector is at 0 (like an array).
Conversion between the two is rather simple. The equations are as follows:
 
''CYL = LBA / (HPC * SPT)''
 
''HEAD = (LBA % (HPC * SPT)) / SPT''
 
''SECT = (LBA % (HPC * SPT)) % SPT + 1''
 
''LBA = ( ( CYL * HPC + HEAD ) * SPT ) + SECT - 1''
 
This can be described in C with the following code:
 
<syntaxhighlight lang="c">
void lba_2_chs(uint32_t lba, uint16_t* cyl, uint16_t* head, uint16_t* sector)
{
*cyl = lba / (2 * FLOPPY_144_SECTORS_PER_TRACK);
*head = ((lba % (2 * FLOPPY_144_SECTORS_PER_TRACK)) / FLOPPY_144_SECTORS_PER_TRACK);
*sector = ((lba % (2 * FLOPPY_144_SECTORS_PER_TRACK)) % FLOPPY_144_SECTORS_PER_TRACK + 1);
}
</syntaxhighlight>
 
You would then send this data to the floppy controller.
 
=== DMA Data Transfers ===
Line 78 ⟶ 105:
 
If you are using PIO mode in a singletasking environment then the IRQ6s just waste CPU cycles, and you should be using polling instead.
You can usually shut the IRQs off by setting bit 3 (value = 8) of the Digital OuptputOutput Register (see below). If you want, you can even
toggle that bit on and off for specific commands, so that you receive some types of interrupts but not others.
 
Line 128 ⟶ 155:
The basic set of floppy registers can be found in the following enumeration:
 
<sourcesyntaxhighlight lang="c">
enum FloppyRegisters
{
Line 141 ⟶ 168:
CONFIGURATION_CONTROL_REGISTER = 0x3F7 // write-only
};
</syntaxhighlight>
</source>
 
All commands, parameter information, result codes, and disk data transfers go through the FIFO port.
Line 158 ⟶ 185:
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.
 
=== Tape Drive Register ===
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 a R/W register which is identical in all modes. According to the documentation for the Intel 82077AA, the two least significant bits form a number between 1 and 3 (0 is an invalid value, drive 0 may not be selected) that assigns tape support to one particular drive out of four total drives. It is probably irrelevant for modern uses, is not supported by any emulator and is probably not worth implementing support for unless you have all the real hardware to test this functionality on.
 
=== DOR bitflag definitions ===
Line 486 ⟶ 515:
with a * and a comment.
 
<sourcesyntaxhighlight lang="c">
enum FloppyCommands
{
Line 500 ⟶ 529:
READ_DELETED_DATA = 12,
FORMAT_TRACK = 13, // *
DUMPREG = 14,
SEEK = 15, // * seek both heads to cylinder X
VERSION = 16, // * used during initialization, once
Line 510 ⟶ 540:
SCAN_HIGH_OR_EQUAL = 29
};
</syntaxhighlight>
</source>
 
==== "Deleted sectors" ====
Deleted sectors is a legacy feature, dating back to the 1970s, when IBM data entry terminals stored a single database record in each (128 byte) floppy sector, and a record could be marked as deleted by writing a different address mark before the sector. This feature was almost never used with IBM PC and compatibles – exceptions were occasional abuse by copy protection schemes, and (possibly) hiding bad sectors. Few (if any) emulators emulate this functionality, and many late model FDCs didn't implement it.
 
The "WRITE_DELETED_DATA" command can be used to create a deleted sector, and the "READ_DELETED_DATA" command can be used to read one back.
 
==== Option bits ====
Line 520 ⟶ 555:
===== Bit MF =====
Value = 0x40. "MFM" magnetic encoding mode. Always set it for read/write/format/verify operations.
 
A zero value represents the old "single density" FM format, which (on IBM PCs) was only used by 8-inch floppies (which were extremely rare). Few people ever used FM format, except for data interchange with non-PC systems (such as CP/M or minicomputers). Later model FDCs (e.g. Intel 82078) dropped support for it.
 
===== Bit SK =====
Value = 0x20. Skip mode. IgnoreThis thisskips bit"deleted andsectors" leave(see itexplanation cleared,in unlesssection you have a really good reason not toabove).
 
Ignore this bit and leave it cleared, unless you have a really good reason not to.
 
==== Status Registers ====
Line 569 ⟶ 609:
* Configure command = 0x13
* First parameter byte = 0
* Second parameter byte = (implied seek enableENable << 6) | (fifo '''DIS'''able << 5) | (drive polling mode enable'''DIS'''able << 4) | thresh_val (= threshold - 1)
* Third parameter byte = precomp_val = 0
* No result bytes.
Line 620 ⟶ 660:
 
Keeping statistics in that way only works when the drive in question is used often. Now that internal floppy drives are nearly obsolete,
it is worthless. So the current recommendataionrecommendation is just to use very safe values, and forget about performance.
 
If you look up spec sheets for individual floppy drives, they usually show a worst-case "track to track seek time" = SRT, but not the other two.
Line 720 ⟶ 760:
* Second parameter byte = cylinder number
* Third parameter byte = head number (yes, this is a repeat of the above value)
* ThirdFourth parameter byte = starting sector number
* FourthFifth parameter byte = 2 (all floppy drives use 512bytes per sector)
* FifthSixth parameter byte = EOT (end of track, the last sector countnumber on tothe transfertrack)
* SixthSeventh parameter byte = 0x1b (GAP1 default size)
* SeventhEighth parameter byte = 0xff (all floppy drives use 512bytes per sector)
 
* First result byte = [[#st0|st0]] status register
Line 737 ⟶ 777:
value of 0. This is also likely to get your driver out of sync with the FDC for input/output.
 
Note2: You'll see that there's no sector count parameter. Instead, the FDC figures out when to stop by the DMA signaling to the FDC
Note2: Floppy media and electronics are well known for being unreliable. Any read or write command that fails should be retried
that it's done, or in PIO mode, by the FDC experiencing a FIFO overrun or underrun.
 
Note2Note3: Floppy media and electronics are well known for being unreliable. Any read or write command that fails should be retried
at least twice, unless it was a write and failed on "write protect".
 
Line 760 ⟶ 803:
== Code Examples ==
 
=== A common coding error example ===
The following code intentionally contains a common bug that causes an infinite loop (waiting for IRQ6) on most emulators.
 
<sourcesyntaxhighlight lang="c">
volatile byte ReceivedIRQ = false;
 
Line 787 ⟶ 830:
WaitForIRQ();
}
</syntaxhighlight>
</source>
 
Sure this code ''looks'' OK, but some emulators or floppy drives might manage to be faster than your code. What if you've just returned from
Line 793 ⟶ 836:
set it to false again and then infinitely loop, waiting for an IRQ that has already been received. It's usually better to do something like:
 
<sourcesyntaxhighlight lang="c">
volatile byte ReceivedIRQ = false;
 
Line 828 ⟶ 871:
outb(Controller.FIFO, headload_ndma);
}
</syntaxhighlight>
</source>
 
== Related Links ==
Line 839 ⟶ 882:
* http://bos.asmhackers.net/docs/floppy/docs/floppy_tutorial.txt
* [http://www.intel.com/design/archives/periphrl/docs/29046803.htm Intel 82078 CHMOS SINGLE-CHIP FLOPPY DISK CONTROLLER datasheet (useless)]
* http://www.brokenthorn.com/Resources/OSDev20.html
 
=== Forum Posts ===
Line 849 ⟶ 893:
 
=== Implementations ===
* [httphttps://kodersgithub.com/cFDOS/fid051291340B94EC7F5D1A38EF6843466C0B07627Bkernel/blob/master/drivers/floppy.aspx?s=fdcasm freedosFreeDOS] (C, GPL)
* [http://bos.asmhackers.net/docs/floppy/snippet_9/fdc.c GazOS] (C, GPL)
* [http://bos.asmhackers.net/docs/floppy/snippet_5/FLOPPY.ASM RDOS] (ASMAssembly, GPL)
* [httphttps://wwwgithub.gelato.unsw.edu.aucom/lxrtorvalds/sourcelinux/blob/master/drivers/block/floppy.c Linux] (C, GPL)
 
[[de:Floppy Disk Controller]]
[[Category:Storage]]
[[Category:Common Devices]]