Files
2024-02-19 00:25:23 -05:00

1940 lines
90 KiB
HTML

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0069)http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html -->
<HTML><HEAD><TITLE>Programming the NEC µPD765 and Intel 82072/7 Floppy Disk Controller</TITLE>
<META content="text/html; charset=iso-8859-1" http-equiv=Content-Type><!------------------------------------------------------------------------>
<META content="MSHTML 5.00.3502.5390" name=GENERATOR></HEAD>
<BODY aLink=olive bgColor=#ffffcc link=red onload=tcI1() onresize=tcI2()
onscroll=tcI2() vLink=purple onMove="tcI2()">
<DIV id=tcI19
style="LEFT: 0px; POSITION: absolute; TOP: 0px; VISIBILITY: hidden; Z-INDEX: 2147483632">
<TABLE bgColor=#eeeeee border=0 cellPadding=0 cellSpacing=0 height=62>
<TBODY>
<TR>
<TD vAlign=top><A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/"
onclick="tcI26(); return false;" title="Click here to expand banner"><IMG
border=0 height=12 src="floppy.files/left.gif" width=12></A></TD></TR>
<TR>
<TD vAlign=bottom><A href="http://www.easyspace.com/" target=_blank><IMG
border=0 src="floppy.files/littlelogo.gif"></A></TD></TR></TBODY></TABLE></DIV>
<DIV id=tcI18
style="LEFT: 0px; POSITION: absolute; TOP: 0px; VISIBILITY: hidden; Z-INDEX: 2147483647">
<TABLE border=0 cellPadding=0 cellSpacing=0 height=62>
<TBODY>
<TR>
<TD rowSpan=2 vAlign=top><A
href="http://www.easyspace.com/redirect.cgi?type=BNR-EASYSPACE-468-LOOP-4.gif&amp;url=http://www.easyspace.com/domains/"
target=_new><IMG alt="Easyspace for your domain registration" border=0
height=60 src="floppy.files/EASYSPACE-468-LOOP-4.gif" width=468></A></TD>
<TD bgColor=#eeeeee vAlign=top><A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/"
onclick="tcI25(); return false;" title="Click here to shrink banner"><IMG
border=0 height=12 src="floppy.files/right.gif" width=12></A></TD></TR>
<TR>
<TD bgColor=#eeeeee vAlign=bottom><A href="http://www.easyspace.com/"
target=_blank><IMG border=0
src="floppy.files/littlelogo.gif"></A></TD></TR></TBODY></TABLE></DIV><BASEFONT
face=Arial>
<TABLE border=0 cellPadding=0 cellSpacing=0 width="100%">
<TBODY>
<TR>
<TD>
<H1 align=center>Programming Floppy Disk Controllers </H1><BR>
<P align=center title="">[ <A
href="http://debs.future.easyspace.com/index.html">Home </A>] [ <A
href="http://debs.future.easyspace.com/Programming/index.html"
title="Programming Home">Programming </A>] </P></TD></TR></TBODY></TABLE>
<HR color=gray SIZE=3>
<BR><BR><!---------------------------------------------------------------------------------------->
<TABLE border=0 cellPadding=10 cellSpacing=0 width="100%">
<TBODY>
<TR>
<TD vAlign=top width=10>[ <A
href="http://debs.future.easyspace.com/Index.html">Home </A>] <BR>[ <A
href="http://debs.future.easyspace.com/Programming/Index.html"
title="Programming Home">Programming </A>] </TD>
<TD>
<P>The purpose of this document is to provide information related to
programming the NEC µPD765 and the Intel 82072/7 Floppy Disk Controllers
(FDCs), by use of the registers. The document is split into several
sections: </P><BR>
<OL>
<LI><A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#Overview">Overview
</A>
<LI><A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#Configuration">Configuration
of an FDC on a PC </A>
<LI><A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#FDC Registers">FDC
Registers </A>
<LI><A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#Commands">Command
Set </A></LI></OL><BR></TD></TR></TBODY></TABLE>
<HR color=gray SIZE=3>
<!---------------------------------------------------------------------------------------->
<H2 align=center><A name=Overview>Overview </A></H2>
<P>The PC usually uses the NEC µPD765 floppy disk controller. The AT can also
incorporate an Intel 82072A controller, while the PS/2 uses an Intel 82077A. The
µPD765 and the ROM code in the controller form a microcontroller, and this
handles the majority of the work of the controller. All PC compatibles have FDCs
which are compatible with the controllers described in this document. </P>
<P>This document describes the registers used to interface with the controller,
and the commands which it recognises. </P>
<P>There are a lot of delays involved in communicating with the controller.
These delays are for a variety of reasons, including the time needed to spin up
the drive motor, and the time taken to move the head to a new position and wait
for it to settle in place. </P>
<P>When the drive motor is started up or the a seek is requested, there will be
a delay until the drive is ready for the next command. An interrupt is issued by
the hardware when it is ready for the next command, and this will tell you that
the drive is ready for your command. </P>
<P>In a single tasked environment (such as DOS), the only option is to have your
driver constantly wait for an interrupt, and then respond to it. However, in a
multi-tasked or multi-threaded environment, it is perfectly acceptable to write
a driver which allows other tasks to be executed while waiting for the
interrupt. </P>
<P>When performing a read or write operation, data may be transferred a byte at
a time by reading from or writing to the appropriate port, or a sector/track at
a time through the use of DMA channel 2. Programming the DMA controller is
beyond the scope of this document, but will be described in a future document to
be added to this site. </P>
<P>The registers, what they do and what commands can be used are all detailed in
the following sections. If there are any errors, I will gratefully accept any
feedback you might like to send to me via <A
href="mailto:debs@savah.freeserve.co.uk">e-mail </A>. </P>
<HR color=gray SIZE=3>
<BR><BR><!---------------------------------------------------------------------------------------->
<H2 align=center><A name=Configuration>Configuration of an FDC on a PC </A></H2>
<P>The Floppy Controller on a PC uses a standard configuration. On the XT there
are 3 ports available for control and data access registers. On the AT, there
are 4, and on the PS/2 there are 6. </P>
<P>The base port address used for the controller is dependant on whether the
controller is configured as the primary or secondary controller. This base
address controls the port addresses used for each of the registers on the
controller. It can additionally be noted that all floppy controllers on a PC use
DMA channel 2 for data transfer during a read or write, and they all issue a
hardware interrupt via IRQ6 to be serviced by INT 0eh by default. </P><BR>
<TABLE align=center border=1 cellPadding=0 cellSpacing=0>
<TBODY>
<TR>
<TD width=300>&nbsp; </TD>
<TD width=75><STRONG>Primary <BR>Address </STRONG></TD>
<TD width=75><STRONG>Secondary <BR>Address </STRONG></TD>
<TD width=75><STRONG>Write (W) <BR>Read (R) </STRONG></TD></TR>
<TR>
<TD>&nbsp; </TD>
<TD>&nbsp; </TD>
<TD>&nbsp; </TD>
<TD>&nbsp; </TD></TR>
<TR>
<TD>base address </TD>
<TD>3f0h </TD>
<TD>370h </TD>
<TD>&nbsp; </TD></TR>
<TR>
<TD>status register A (PS/2) </TD>
<TD>3f0h </TD>
<TD>370h </TD>
<TD>R </TD></TR>
<TR>
<TD>status register B (PS/2) </TD>
<TD>3f1h </TD>
<TD>371h </TD>
<TD>R </TD></TR>
<TR>
<TD>digital output register DOR </TD>
<TD>3f2h </TD>
<TD>372h </TD>
<TD>W </TD></TR>
<TR>
<TD>main status register </TD>
<TD>3f4h </TD>
<TD>374h </TD>
<TD>R </TD></TR>
<TR>
<TD>data rate select register (DSR)(PS/2) </TD>
<TD>3f4h </TD>
<TD>374h </TD>
<TD>W </TD></TR>
<TR>
<TD>data register </TD>
<TD>3f5h </TD>
<TD>375h </TD>
<TD>R/W </TD></TR>
<TR>
<TD>digital input register DIR (AT) </TD>
<TD>3f7h </TD>
<TD>377h </TD>
<TD>R </TD></TR>
<TR>
<TD>configuration control register (AT) </TD>
<TD>3f7h </TD>
<TD>377h </TD>
<TD>W </TD></TR>
<TR>
<TD>DMA channel </TD>
<TD>2 </TD>
<TD>2 </TD>
<TD>&nbsp; </TD></TR>
<TR>
<TD>IRQ </TD>
<TD>6 </TD>
<TD>6 </TD>
<TD>&nbsp; </TD></TR>
<TR>
<TD>INTR </TD>
<TD>0eh </TD>
<TD>0eh </TD>
<TD>&nbsp; </TD></TR></TBODY></TABLE><BR><BR><BR>
<P>Note that the controller can be configured differently from the defaults for
handling interrupts. </P>
<HR color=gray SIZE=3>
<BR><BR><!---------------------------------------------------------------------------------------->
<H2 align=center><A name="FDC Registers">FDC Registers </A></H2>
<P>This section gives more detailed information on the use of the registers
listed in the above table. Additionally, the first registers to be described are
those common to each system described, and these will be followed by
descriptions of AT specific registers and PS/2 specific registers. </P>
<P>Common Registers: </P>
<OL>
<LI><A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#DOR">Digital
Output Register DOR </A>
<LI><A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#MSR">Main
Status Register </A>
<LI><A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#Data">Data
Register </A></LI></OL>AT Specific Registers:
<OL>
<LI><A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#DIR">Digital
Input Register DIR </A>
<LI><A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#CCR">Configuration
Control Register </A></LI></OL>PS/2 Specific Registers:
<OL>
<LI><A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#Status">Status
Register A </A>
<LI><A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#Status">Status
Register B </A>
<LI><A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#DRSR">Data
Rate Select Register </A></LI></OL>
<HR>
<H3><A name=DOR>Digital Output Register DOR </A></H3>
<P align=center><IMG alt="image of Digital Output Register" height=136
src="floppy.files/DOR.gif" title="Digital Output Register" width=260> </P>
<TABLE cellPadding=2 width=550>
<TBODY>
<TR>
<TD><STRONG><FONT size=-1>MOTD, MOTC, MOTB, MOTA:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>Motor control for floppy drive D, C, B, A
</STRONG></FONT></TD></TR>
<TR>
<TD></TD>
<TD>
<TABLE width="100%">
<TBODY>
<TR>
<TD width="50%"><FONT size=-1>1 = Start motor</FONT> </TD>
<TD><FONT size=-1>0 = Stop motor</FONT> </TD></TR></TBODY></TABLE></TD></TR>
<TR>
<TD><STRONG><FONT size=-1>DMA:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>DMA and IRQ channel</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD>
<TABLE width="100%">
<TBODY>
<TR>
<TD width="50%"><FONT size=-1>1 = Enabled</FONT> </TD>
<TD><FONT size=-1>0 = Disabled</FONT> </TD></TR></TBODY></TABLE></TD></TR>
<TR>
<TD><STRONG><FONT size=-1><A style="TEXT-DECORATION: overline">REST:
</A></FONT></STRONG></TD>
<TD><STRONG><FONT size=-1>Controller reset</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD>
<TABLE width="100%">
<TBODY>
<TR>
<TD width="50%"><FONT size=-1>1 = Controller enabled</FONT> </TD>
<TD><FONT size=-1>0 = Execute controller reset</FONT>
</TD></TR></TBODY></TABLE></TD></TR>
<TR>
<TD><STRONG><FONT size=-1>DR1,DR0:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Drive select</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD>
<TABLE width="100%">
<TBODY>
<TR>
<TD width="25%"><FONT size=-1>00 = drive 0 (A)</FONT> </TD>
<TD width="25%"><FONT size=-1>01 = drive 1 (B)</FONT> </TD>
<TD width="25%"><FONT size=-1>10 = drive 2 (C)</FONT> </TD>
<TD><FONT size=-1>11 = drive 3 (D)</FONT>
</TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR><BR>
<P>This register is write only, and controls the drive motors, as well as
selecting a drive and the DMA/IRQ mode, and resetting the controller. </P>
<P>If the REST bit is set, the controller is enabled, in order to accept and
execute commands. If it is equal to 0, the controller ignores all commands and
carries out an internal reset of all internal registers (except the DOR). </P>
<P>Note that a drive cannot be selected unless its motor is on, although setting
the bits at the same time is acceptable. </P>
<P>Note also that drives 2 and 3 (floppy drives C and D) are not supported in
all systems. </P>
<P><STRONG>Example: </STRONG><BR>To start the motor on drive A and select it,
ready for another operation, you would use the following: <BR><BR></P>
<DL>
<DD>MOTA = 1 (start motor for drive A)
<DD>DMA = 1 (assuming you want to use DMA and interrupts)
<DD>REST = 1 (Controller enabled, otherwise no other commands will be
executed)
<DD>DR1,DR0 = 00 (Select drive A)
<DD>All other bits are set to 0 <BR><BR>Thus 16 + 8 + 4 + 0 = 28, or 01Ch, is
sent to port 3f2h (Drive A is usually on the primary controller). </DD></DL>
<P>In assembly language, this would be written as: </P><PRE><STRONG><FONT size=+2>
mov al,01ch
mov dx,03f2h
out dx,al</FONT></STRONG>
</PRE><BR>
<P><STRONG>Example: </STRONG><BR>To reset the controller, send 0 to port 3f2h.
This turns off all motors, selects no drives (because drive A's motor is not
active, it cannot be selected), disables the DMA and IRQ line, and resets the
controller. </P>
<P>The code for this is as follows: <BR><BR></P><PRE><STRONG><FONT size=+2>
mov al,0
mov dx,03f2h
out dx,al</FONT></STRONG>
</PRE><BR>
<HR>
<!---------------------------------------------------------------------------------------->
<H3><A name=MSR>Main Status Register </A></H3>
<P align=center><IMG alt="image of Main Status Register" height=136
src="floppy.files/MSR.gif" title="Main Status Register" width=260> </P>
<TABLE cellPadding=2 width=550>
<TBODY>
<TR>
<TD><STRONG><FONT size=-1>MRQ:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>main request</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD>
<TABLE width="100%">
<TBODY>
<TR>
<TD width="50%"><FONT size=-1>1 = data register ready</FONT> </TD>
<TD><FONT size=-1>0 = data register not ready</FONT>
</TD></TR></TBODY></TABLE></TD></TR>
<TR>
<TD><STRONG><FONT size=-1>DIO:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>data input/output </STRONG></FONT></TD></TR>
<TR>
<TD></TD>
<TD>
<TABLE cellPadding=2 width="100%">
<TBODY>
<TR>
<TD width="50%"><FONT size=-1>1 = controller ? CPU</FONT> </TD>
<TD><FONT size=-1>0 = CPU ? controller</FONT>
</TD></TR></TBODY></TABLE></TD></TR>
<TR>
<TD><STRONG><FONT size=-1>NDMA:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>non-DMA mode </STRONG></FONT></TD></TR>
<TR>
<TD></TD>
<TD>
<TABLE cellPadding=2 width="100%">
<TBODY>
<TR>
<TD width="50%"><FONT size=-1>1 = controller not in DMA mode</FONT>
</TD>
<TD><FONT size=-1>0 = controller in DMA mode</FONT>
</TD></TR></TBODY></TABLE></TD></TR>
<TR>
<TD><STRONG><FONT size=-1>BUSY:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>instruction (device busy) </STRONG></FONT></TD></TR>
<TR>
<TD></TD>
<TD>
<TABLE cellPadding=2 width="100%">
<TBODY>
<TR>
<TD width="50%"><FONT size=-1>1 = active</FONT> </TD>
<TD><FONT size=-1>0 = not active</FONT> </TD></TR></TBODY></TABLE></TD></TR>
<TR>
<TD><STRONG><FONT size=-1>ACTD, ACTC, ACTB, ACTA:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>drive D, C, B, A in positioning mode
</STRONG></FONT></TD></TR>
<TR>
<TD></TD>
<TD>
<TABLE cellPadding=2 width="100%">
<TBODY>
<TR>
<TD width="50%"><FONT size=-1>1 = active</FONT> </TD>
<TD><FONT size=-1>0 = not active</FONT>
</TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR><BR>
<P>The MSR is read-only, and contains the controller's status information. This
register can be read whatever else the controller is doing. </P>
<P>It should be noted that this register is different from status registers
ST0-ST3, which contain data concerning the last command executed. These
registers are accessed via the data registers. </P>
<P>Bit 7 (MRQ) indicates whether the controller is ready to receive or send data
or commands via the data register. </P>
<P>DIO is used to provide an indication of whether the controller is expecting
to receive data from the CPU, or if it wants to output data to the CPU. </P>
<P>If the controller is set up to use DMA channel 2 to transfer data to or from
main memory, the NDMA bit is not set. If this bit is set, data transfer is
carried out exclusively by means of read or write commands to the data register.
In this case, the controller issues a hardware interrupt every time that it
either expects to receive or wants to supply a data byte. </P>
<P>Bit 4 indicates whether the controller is busy or not. If the bit is set, the
controller is currently executing a command. </P>
<P>Bits 0-3 indicate which (if any) drive is currently in the process of
positioning it's read/write heads, or being recalibrated. </P>
<P>Note that the delay waiting for the controller to be ready for a read or
write can be as much as 175µs on an Intel controller, and longer on older
controllers. </P>
<P><STRONG>Example: </STRONG><BR>To test whether the controller is ready to
receive commands and data, it is necessary to test MRQ and DIO. This involves
reading the port, masking the bits, and doing a comparison on the result (to
test the values of the bits). </P>
<P>In assembly language, this is can be written as: <BR><BR></P><PRE><STRONG><FONT size=+2>
mrqloop:
mov dx,03f4h
in al,dx
and al,0c0h
cmp al,080h
jne mrqloop</FONT></STRONG>
</PRE><BR>
<P>This code will keep looping until the controller says that it is ready to
receive data. Note that if the controller is expecting to output data to the
CPU, this code will not spot that. You would need to add another couple of lines
of code if you need to check for both possibilities (In general, you would know
from previous commands whether the controller should be expecting or offering
data, and so only need to check for one condition). </P>
<HR>
<!---------------------------------------------------------------------------------------->
<H3><A name=Data>Data Register </A></H3>
<P>The data register is an 8 bit register, like each of the other registers,
which provides indirect access to a stack of registers. A command can be one to
nine bytes in length, and the first byte tells the controller how many more
bytes to expect. The controller sends the command bytes to the correct registers
in it's stack, saving the programmer from the need to use a separate index
register, as is the case in some other devices (e.g. some VGA registers). </P>
<P>Some controllers, such as the i82077A, have a buffer, with a programmable
threshold, allowing the data to be transferred several bytes at a time. This
helps to speed up the transfer of data and commands, as well as reducing the
response time seen on the µPD765. </P>
<P>Following some of the commands, the values in the status registers are
returned. The layout of the status registers follows, with the <A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#Commands">commands
</A>being listed at the end of this document. </P>
<HR SIZE=1>
<!---------------------------------------------------------------------------------------->
<H4><A name=Status0>Status Register </A>ST0 </H4>
<P align=center><IMG alt="image of Status Register 0" height=136
src="floppy.files/ST0.gif" title="Status Register 0" width=260> </P>
<TABLE cellPadding=2>
<TBODY>
<TR>
<TD><STRONG><FONT size=-1>IC <SUB>1 </SUB>,IC <SUB>0
</SUB>:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>interrupt code</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD>
<TABLE cellPadding=2 width="100%">
<TBODY>
<TR>
<TD vAlign=top><FONT size=-1>00&nbsp;=&nbsp;</FONT> </TD>
<TD><FONT size=-1>normal termination; <BR>command terminated without
any errors</FONT> </TD></TR>
<TR>
<TD vAlign=top><FONT size=-1>01&nbsp;=&nbsp;</FONT> </TD>
<TD><FONT size=-1>abnormal termination; <BR>the controller started
execution of the command, but couldn't terminate it correctly</FONT>
</TD></TR>
<TR>
<TD vAlign=top><FONT size=-1>10&nbsp;=&nbsp;</FONT> </TD>
<TD><FONT size=-1>invalid command; <BR>the controller could not
start command execution</FONT> </TD></TR>
<TR>
<TD vAlign=top><FONT size=-1>11&nbsp;=&nbsp;</FONT> </TD>
<TD><FONT size=-1>abnormal termination by polling; <BR>drive became
not ready</FONT> </TD></TR></TBODY></TABLE></TD></TR>
<TR>
<TD><STRONG><FONT size=-1>SE:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>seek end </STRONG></FONT></TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>The controller has completed a seek or a calibration
command, <BR>or has correctly executed a read or write command which has
an implicit seek</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>UC:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>unit check </STRONG></FONT></TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>Set if the drive faults or if a recalibrate cannot find
track 0 after 79 pulses.</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>NR:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>drive not ready </STRONG></FONT></TD></TR>
<TR>
<TD><STRONG><FONT size=-1>HD:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>head currently active </STRONG></FONT></TD></TR>
<TR>
<TD></TD>
<TD>
<TABLE cellPadding=2>
<TBODY>
<TR>
<TD><FONT size=-1>1&nbsp;=&nbsp;</FONT> </TD>
<TD><FONT size=-1>head 1</FONT> </TD></TR>
<TR>
<TD><FONT size=-1>0&nbsp;=&nbsp;</FONT> </TD>
<TD><FONT size=-1>head 0</FONT> </TD></TR></TBODY></TABLE></TD></TR>
<TR>
<TD><STRONG><FONT size=-1>US <SUB>1 </SUB>, US <SUB>0 </SUB></FONT>:
</STRONG></TD>
<TD><FONT size=-1><STRONG>currently selected drive (unit select)
</STRONG></FONT></TD></TR>
<TR>
<TD></TD>
<TD>
<TABLE cellPadding=2>
<TBODY>
<TR>
<TD><FONT size=-1>00&nbsp;=&nbsp;</FONT> </TD>
<TD><FONT size=-1>drive 0 (A:)</FONT> </TD></TR>
<TR>
<TD><FONT size=-1>01&nbsp;=&nbsp;</FONT> </TD>
<TD><FONT size=-1>drive 1 (B:)</FONT> </TD></TR>
<TR>
<TD><FONT size=-1>10&nbsp;=&nbsp;</FONT> </TD>
<TD><FONT size=-1>drive 2 (C:)</FONT> </TD></TR>
<TR>
<TD><FONT size=-1>11&nbsp;=&nbsp;</FONT> </TD>
<TD><FONT size=-1>drive 3 (D:)</FONT>
</TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR>
<HR SIZE=1>
<!---------------------------------------------------------------------------------------->
<H4>Status Register ST1 </H4>
<P align=center><IMG alt="image of Status Register 1" height=136
src="floppy.files/ST1.gif" title="Status Register 1" width=260> </P>
<TABLE cellPadding=2>
<TBODY>
<TR>
<TD><STRONG><FONT size=-1>EN:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>End of Cylinder </STRONG></FONT></TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>Set when the sector count exceeds the number of sectors
on a track. <BR>i.e. the controller attempts to access a sector after the
last sector of a cylinder.</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>xx:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>bit unused </STRONG></FONT></TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>value always equal to 0</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>DE:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>data error </STRONG></FONT></TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>Set if the controller detected an error in the ID
address field or the data field of a sector</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>TO:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>time-out </STRONG></FONT></TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>Set for a data overrun; <BR>No signal received from the
DMA controller or CPU within the required time period.</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>NDAT:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>no data </STRONG></FONT></TD></TR>
<TR>
<TD></TD>
<TD>
<TABLE cellPadding=2>
<TBODY>
<TR>
<TD align=right vAlign=top><STRONG><FONT
size=-1>Set&nbsp;if:&nbsp;</FONT></STRONG> </TD>
<TD><FONT size=-1>The addressed sector in a <I>read sector </I>or
<I>read deleted sector </I>cannot be found <BR>by the
controller.</FONT> </TD></TR>
<TR>
<TD align=right vAlign=top><FONT size=-1><STRONG>OR:
</STRONG>&nbsp;</FONT> </TD>
<TD><FONT size=-1>The controller cannot read the ID address mark in
response to a <I>read ID </I>command <BR>without error.</FONT>
</TD></TR>
<TR>
<TD align=right vAlign=top><STRONG><FONT
size=-1>OR:&nbsp;</FONT></STRONG> </TD>
<TD><FONT size=-1>The controller cannot correctly determine the
sequence of sectors in a <I>read track </I><BR>command</FONT>
</TD></TR></TBODY></TABLE></TD></TR>
<TR>
<TD><STRONG><FONT size=-1>NW:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>not writable </STRONG></FONT></TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>Set if the disk in the selected drive is write protected
while the controller attempts to <BR>execute a write command.</FONT>
</TD></TR>
<TR>
<TD><STRONG><FONT size=-1>NID:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>no address mark </STRONG></FONT></TD></TR>
<TR>
<TD></TD>
<TD>
<TABLE cellPadding=2>
<TBODY>
<TR>
<TD align=right vAlign=top><STRONG><FONT
size=-1>Set&nbsp;if:&nbsp;</FONT></STRONG> </TD>
<TD><FONT size=-1>The ID address mark was not found after one
complete disk revolution</FONT> </TD></TR>
<TR>
<TD align=right vAlign=top><STRONG><FONT
size=-1>OR:&nbsp;</FONT></STRONG> </TD>
<TD><FONT size=-1>The controller could not find: <BR></FONT>
<DL>
<DD><FONT size=-1>a data address mark DAM</FONT>
<DD><FONT size=-1>a deleted data address mark DAM <BR>on the
specified track.</FONT>
</DD></DL></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR>
<HR SIZE=1>
<!---------------------------------------------------------------------------------------->
<H4>Status Register ST2 </H4>
<P align=center><IMG alt="image of Status Register 2" height=136
src="floppy.files/ST2.gif" title="Status Register 2" width=260> </P>
<TABLE cellPadding=2>
<TBODY>
<TR>
<TD><STRONG><FONT size=-1>xx:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>bit unused </STRONG></FONT></TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>value always equal to 0</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>DADM:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>deleted address mark </STRONG></FONT></TD></TR>
<TR>
<TD></TD>
<TD>
<TABLE cellPadding=2>
<TBODY>
<TR>
<TD align=right vAlign=top><STRONG><FONT size=-1>Set
if:&nbsp;</FONT></STRONG> </TD>
<TD><FONT size=-1>A deleted data address mark DAM is detected when a
<I>read sector </I>command is <BR>being executed.</FONT> </TD></TR>
<TR>
<TD align=right vAlign=top><STRONG><FONT
size=-1>OR:&nbsp;</FONT></STRONG> </TD>
<TD><FONT size=-1>A valid data address mark DAM is detected when a
<I>read deleted sector </I>command <BR>is being executed.</FONT>
</TD></TR></TBODY></TABLE></TD></TR>
<TR>
<TD><STRONG><FONT size=-1>CRCE:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>CRC error in data field </STRONG></FONT></TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>Set if a CRC error was detected in the data field of the
sector.</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>WCYL:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>wrong cylinder </STRONG></FONT></TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>Set if the track address in the controller and the track
address in the ID address mark are <BR>different.</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>SEQ:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>seek equal </STRONG></FONT></TD></TR>
<TR>
<TD></TD>
<TD>
<TABLE cellPadding=2>
<TBODY>
<TR>
<TD align=right vAlign=top><STRONG><FONT
size=-1>Set&nbsp;if:</FONT></STRONG> </TD>
<TD><FONT size=-1>controller is a µPD765 and the condition <I>seek
equal </I>is fulfilled</FONT> </TD></TR>
<TR>
<TD align=right vAlign=top><STRONG><FONT
size=-1>else:</FONT></STRONG> </TD>
<TD><FONT size=-1>SGL is not used, this field is always equal to
0</FONT> </TD></TR></TBODY></TABLE></TD></TR>
<TR>
<TD><STRONG><FONT size=-1>SERR:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>seek error </STRONG></FONT></TD></TR>
<TR>
<TD></TD>
<TD>
<TABLE cellPadding=2>
<TBODY>
<TR>
<TD align=right vAlign=top><STRONG><FONT
size=-1>Set&nbsp;if:</FONT></STRONG> </TD>
<TD><FONT size=-1>controller is a µPD765 and the controller did not
find the corresponding sector when <BR>seeking on the
cylinder.</FONT> </TD></TR>
<TR>
<TD align=right vAlign=top><STRONG><FONT
size=-1>else:</FONT></STRONG> </TD>
<TD><FONT size=-1>SERR is not used, this field is always equal to
0</FONT> </TD></TR></TBODY></TABLE></TD></TR>
<TR>
<TD><STRONG><FONT size=-1>BCYL:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>bad cylinder </STRONG></FONT></TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>This field indicates that the track address in the ID
address mark differs from the track <BR>address in the controller. <BR>The
value equals <STRONG>ffh </STRONG>, indicating a bad track with a physical
error, according to the IBM soft <BR>sector format.</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>NDAM:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>not data address mark DAM </STRONG></FONT></TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>Set if the controller cannot find a valid or deleted
data address mark DAM.</FONT> </TD></TR></TBODY></TABLE><BR><BR>
<HR SIZE=1>
<!---------------------------------------------------------------------------------------->
<H4>Status Register ST3 </H4>
<P align=center><IMG alt="image of Status Register 3" height=136
src="floppy.files/ST3.gif" title="Status Register 3" width=260> </P>
<TABLE cellPadding=2>
<TBODY>
<TR>
<TD><STRONG><FONT size=-1>ESIG:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>error</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD>
<TABLE cellPadding=2>
<TBODY>
<TR>
<TD align=right vAlign=top><STRONG><FONT
size=-1>Set&nbsp;if:</FONT></STRONG> </TD>
<TD><FONT size=-1>controller is a µPD765 and the drives error signal
is active <BR>i.e. an error has occurred</FONT> </TD></TR>
<TR>
<TD align=right vAlign=top><STRONG><FONT
size=-1>else:</FONT></STRONG> </TD>
<TD><FONT size=-1>ESIG is not used and is always equal to 0</FONT>
</TD></TR></TBODY></TABLE></TD></TR>
<TR>
<TD><STRONG><FONT size=-1>WPDR:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>write protection</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>Set if the disk is write protected (indicates the
write-protection line is active).</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>RDY:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>ready</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD>
<TABLE cellPadding=2>
<TBODY>
<TR>
<TD align=right vAlign=top><STRONG><FONT
size=-1>Set&nbsp;if:</FONT></STRONG> </TD>
<TD><FONT size=-1>controller is a µPD765 and the drive is ready
(indicates the ready signal of the <BR>drive is active).</FONT>
</TD></TR>
<TR>
<TD align=right vAlign=top><STRONG><FONT
size=-1>else:</FONT></STRONG> </TD>
<TD><FONT size=-1>RDY is not used and this field is always
set</FONT> </TD></TR></TBODY></TABLE></TD></TR>
<TR>
<TD><STRONG><FONT size=-1>TRK0:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>track 0</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>The head is above track 0 (the TRK0 signal of the drive
is active).</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>DSDR:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>double sided drive</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>The drive is double sided (indicates the DSDR signal is
active).</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>HDDR:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>head</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>This bit indicates the status of the HDSEL signal of the
drive: <BR>1 = head 1 active, <BR>0 = head 0 active</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>DS1,&nbsp;DS0:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>drive select</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>Both bits indicate the select signals DS1 and DS0 of the
drive: <BR>00 = drive 0 (A:) <BR>01 = drive 1 (B:) <BR>10 = drive 2 (C:)
<BR>11 = drive 3 (D:) <BR></FONT></TD></TR></TBODY></TABLE><BR><BR>
<HR>
<!---------------------------------------------------------------------------------------->
<H3><A name=DIR>Digital Input Register </A></H3>
<P align=center>DIR (AT) <BR><IMG alt="image of Digital Input Register (AT)"
height=136 src="floppy.files/DIR_(AT).gif" title="Digital Input Register (AT)"
width=260> <BR></P>
<TABLE cellPadding=2>
<TBODY>
<TR>
<TD align=middle>DIR (PS/2 except Model 30) <BR><IMG
alt="image of Digital Input Register (PS/2 except Model 30)" height=136
src="floppy.files/DIR_(PS2_except_model_30).gif"
title="Digital Input Register (PS/2 except Model 30)" width=260> </TD>
<TD align=middle>DIR (PS/2 Model 30) <BR><IMG
alt="image of Digital Input Register (PS/2 Model 30)" height=136
src="floppy.files/DIR_(PS2_model_30).gif"
title="Digital Input Register (PS/2 Model 30)" width=260>
</TD></TR></TBODY></TABLE><BR>
<TABLE cellPadding=2>
<TBODY>
<TR>
<TD><STRONG><FONT size=-1>CHAN:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Disk Change</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD>
<TABLE cellPadding=2 width="100%">
<TBODY>
<TR>
<TD><FONT size=-1>1 = disk changed since last command</FONT> </TD>
<TD><FONT size=-1>0 = disk not changed</FONT>
</TD></TR></TBODY></TABLE></TD></TR>
<TR>
<TD><STRONG><FONT size=-1>RAT1,&nbsp;RAT2:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Data Rate</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>00 = 500 kbits/s <BR>01 = 300 kbits/s <BR>10 = 250
kbits/s <BR>11 = 1Mbits/s</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1><A style="TEXT-DECORATION: overline">HiDe
</A></FONT></STRONG></TD>
<TD><STRONG><FONT size=-1>High-density Rate</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>1 = data rate 250kbits/s or 300 kbits/s <BR>0 = data
rate 1Mbits/s or 500 kbits/s</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>DMA:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Value of DMA bit in DOR</FONT></STRONG> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>NOPR:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Value of NOPR bit in Control Configuration
Register</FONT></STRONG> </TD></TR></TBODY></TABLE><BR><BR>
<P>This register is available only in the AT and the PS/2, and is read only. The
above diagrams show that there are 3 different configurations for this register,
differing in the AT, PS/2 and PS/2 Model 30. These registers all allow you to
detect a disk change by reading bit 7, with additional information available for
the PS/2 and Model 30 variants. </P>
<P>For each of the registers, when bit 7 is set, it indicates that the disk has
been changed since the last command was executed. This can be used by a driver
to speed up access to data, by buffering of data. When buffering data, if the
disk has not been changed, required sectors can already be in memory when
requested (for example, a whole track can be read at a time and stored in a
buffer, including the possibility of storing multiple tracks when sectors are
read from different cylinders). If this happens, the data only needs reading
from disk when a new cylinder is being read from, or when the disk has been
changed. </P>
<P>In the PS/2 and Model 30, the registers also contain information about the
current data transfer rate. For Model 30, this information is read from bits 1
and 0, while in the other PS/2 models, the data is read from bits 2 and 1. This
data can be used when the rate is set through the Control Configuration Register
to check that the rate has been correctly set, or to check what rate the
controller is set to at any time. </P>
<P>In PS/2 models other than Model 30, bit 1 can be read to help determine
whether the controller is set to a high or low data transfer rate for a high
density disk. </P>
<P>In Model 30, bit 3 corresponds to bit 3 of the DOR. bit 2 corresponds to bit
2 of the CCR (only used in this model). In both these cases, the value is
read-only in the DIR, and can be written to in the corresponding register. </P>
<HR>
<!---------------------------------------------------------------------------------------->
<H3><A name=CCR>Control Configuration Register </A></H3><BR align="center">
<TABLE cellPadding=2>
<TBODY>
<TR>
<TD align=middle>CCR (AT and PS/2) <BR><IMG
alt="image of Control Configuration Register (AT and PS/2)" height=136
src="floppy.files/CCR_(AT_PS2).gif"
title="Control Configuration Register (AT and PS/2)" width=260> </TD>
<TD align=middle>CCR (PS/2 Model 30) <BR><IMG
alt="image of Control Configuration Register (PS/2 Model 30)" height=136
src="floppy.files/CCR_(PS2_Model_30).gif"
title="Control Configuration Register (PS/2 Model 30)" width=260>
</TD></TR></TBODY></TABLE><BR>
<TABLE cellPadding=2>
<TBODY>
<TR>
<TD><STRONG><FONT size=-1>RAT1,&nbsp;RAT0:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Data Transfer Rate</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>00 = 500kbits/s <BR>01 = 300kbits/s <BR>10 = 250kbits/s
<BR>11 - 1Mbits/s</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>NOPR:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>(No) Precompensate</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0 = Precompensation Enabled (standard) <BR>1 = No
Precompensation</FONT> </TD></TR></TBODY></TABLE><BR><BR>
<P align=center><STRONG>Data Transfer Rates </STRONG><BR><BR></P>
<TABLE cellPadding=2>
<TBODY>
<TR>
<TD><STRONG><FONT size=-1>Rate</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Disk <BR>Capacity</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Size</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Drive <BR>Capacity</FONT></STRONG> </TD></TR>
<TR>
<TD><FONT size=-1>250 kbits/s</FONT> </TD>
<TD><FONT size=-1>360&nbsp;kbyte</FONT> </TD>
<TD><FONT size=-1>5?</FONT> </TD>
<TD><FONT size=-1>360&nbsp;kbyte</FONT> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>720&nbsp;kbyte</FONT> </TD>
<TD><FONT size=-1>3?</FONT> </TD>
<TD><FONT size=-1>1.44&nbsp;Mbytes</FONT> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>720&nbsp;kbyte</FONT> </TD>
<TD><FONT size=-1>3?</FONT> </TD>
<TD><FONT size=-1>720&nbsp;kbyte</FONT> </TD></TR>
<TR>
<TD><FONT size=-1>300 kbits/s</FONT> </TD>
<TD><FONT size=-1>720&nbsp;kbyte</FONT> </TD>
<TD><FONT size=-1>3?</FONT> </TD>
<TD><FONT size=-1>720&nbsp;kbyte</FONT> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>360&nbsp;kbyte</FONT> </TD>
<TD><FONT size=-1>5?</FONT> </TD>
<TD><FONT size=-1>1.2&nbsp;&nbsp;Mbyte</FONT> </TD></TR>
<TR>
<TD><FONT size=-1>500 kbits/s</FONT> </TD>
<TD><FONT size=-1>1.2&nbsp;&nbsp;Mbyte</FONT> </TD>
<TD><FONT size=-1>5?</FONT> </TD>
<TD><FONT size=-1>1.2&nbsp;&nbsp;Mbyte</FONT> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>1.44&nbsp;Mbytes</FONT> </TD>
<TD><FONT size=-1>3?</FONT> </TD>
<TD><FONT size=-1>1.44&nbsp;Mbytes</FONT> </TD></TR></TBODY></TABLE><BR><BR>
<P>In the AT and all PS/2 models, the data transfer rate can be set through bits
1 and 0 of the CCR. Valid transfer rates are shown in the table immediately
above, and the table below the diagram shows what values need to be sent to
these two fields to set the appropriate rate. </P>
<P>In the Model 30 it is also possible to program the precompensation through
bit 2 of this register. The default is for precompensate to be enabled, with
this field set to 0. Setting the field to 1 turns precompensation off. </P>
<HR>
<!---------------------------------------------------------------------------------------->
<H3><A name=Status>Status Registers A and B </A></H3><BR align="center">
<TABLE cellPadding=2>
<TBODY>
<TR>
<TD align=middle>Status Register A (PS/2) <BR><IMG
alt="image of Status Register A (PS/2)" height=136
src="floppy.files/StatusA1.gif" title="Status Register A (PS/2)"
width=260> </TD>
<TD align=middle>Status Register A (Model 30) <BR><IMG
alt="image of Status Register A (Model 30)" height=136
src="floppy.files/StatusA2.gif" title="Status Register A (Model 30)"
width=260> </TD></TR>
<TR>
<TD align=middle vAlign=top>
<TABLE cellPadding=2>
<TBODY>
<TR>
<TD><STRONG><FONT size=-1>INTP:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Interrupt Pending</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0 = interrupt signal inactive <BR>1 =
active</FONT> </TD></TR>
<TR>
<TD vAlign=top><STRONG><FONT size=-1><A
style="TEXT-DECORATION: overline">DRV2 </A>:</FONT></STRONG> </TD>
<TD><FONT size=-1>0 = 2 drives connected <BR>1 = one drive
only</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>STEP:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Stepper Pulse</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0 = no pulse <BR>1 = pulse is submitted</FONT>
</TD></TR>
<TR>
<TD><STRONG><FONT size=-1><A style="TEXT-DECORATION: overline">TRK0
</A>:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Track 0</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0 = head not above track 0 <BR>1 = head above
track 0</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>HDSL:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Head Select</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0 = head 0 <BR>1 = head 1</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1><A style="TEXT-DECORATION: overline">INDX
</A>:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Index Mark</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0 = detected <BR>1 = not detected</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1><A style="TEXT-DECORATION: overline">WP
</A>:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Write Protection</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0 = disk write protected <BR>1 = not write
protected</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>DIR:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Direction of Head</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0 = outwards (to smaller cylinder numbers) <BR>1 =
inwards (to higher cylinder numbers)</FONT> </TD></TR></TBODY></TABLE></TD>
<TD align=middle vAlign=top>
<TABLE cellPadding=2>
<TBODY>
<TR>
<TD><STRONG><FONT size=-1>INTP:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Interrupt Pending</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0 = interrupt signal inactive <BR>1 =
active</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>DRQ:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>DMA Request</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0 = not active <BR>1 = active</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>STEP:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Step Pulse</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0 = pulse is submitted <BR>1 = no pulse</FONT>
</TD></TR>
<TR>
<TD><STRONG><FONT size=-1>TRK0:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Track 0</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0 = head above track 0 <BR>1 = head not above
track 0</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1><A style="TEXT-DECORATION: overline">HDSL
</A>:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Head Select</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0 = head 1 <BR>1 = head 0</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>INDX:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Index Mark</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0 = not detected <BR>1 = detected</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>WP:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Write Protection</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0 = disk not write protected <BR>1 = disk write
protected</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1><A style="TEXT-DECORATION: overline">DIR
</A>:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Head Direction</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0 = inwards (to higher cylinder numbers) <BR>1 =
outwards (to lower cylinder numbers)</FONT>
</TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR><BR><BR title=""
align="center">
<TABLE cellPadding=2>
<TBODY>
<TR>
<TD align=middle>Status Register B (PS/2) <BR><IMG
alt="image of Status Register B (PS/2)" height=136
src="floppy.files/StatusB1.gif" title="Status Register B (PS/2)"
width=260> </TD>
<TD align=middle>Status Register B (Model 30) <BR><IMG
alt="image of Status Register B (Model 30)" height=136
src="floppy.files/StatusB2.gif" title="Status Register B (Model 30)"
width=260> </TD></TR>
<TR>
<TD align=middle vAlign=top>
<TABLE cellPadding=2>
<TBODY>
<TR>
<TD><STRONG><FONT size=-1>DS0:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Drive Select</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0 = drive other than 0 <BR>1 = drive 0</FONT>
</TD></TR>
<TR>
<TD><STRONG><FONT size=-1>WDAT:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Write Data</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0 = no data can be written to drive <BR>1 = data
can be transferred to drive</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>RDAT:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Read Data</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0 = no data can be read from drive <BR>1 = data
can be transferred from drive</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>WE:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Write Enabled</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0 = head is set to read data <BR>1 = head is
activated for data writes</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>MOT1,&nbsp;MOT0:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Motor of drive 1, 0</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0 = motor is switched off <BR>1 = motor is
switched on</FONT> </TD></TR></TBODY></TABLE></TD>
<TD align=middle vAlign=top>
<TABLE>
<TBODY>
<TR>
<TD><STRONG><FONT size=-1><A style="TEXT-DECORATION: overline">DRV2
</A>:</FONT></STRONG> </TD>
<TD><FONT size=-1>0 = two drives connected <BR>1 = only one drive
connected</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1><A style="TEXT-DECORATION: overline">DS1
</A>:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Drive Select 1</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0 = drive 1 selected <BR>1 = drive not
selected</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1><A style="TEXT-DECORATION: overline">DS0
</A>:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Drive Select 0</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0 = drive 0 selected <BR>1 = drive not
selected</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>WDAT:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Write Data</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0 = no data can be written <BR>1 = data can be
transferred to the drive</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>RDAT:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Read Data</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0&nbsp;= data cannot be read from drive <BR>1 =
data can be read from drive</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>WE:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Write Enabled</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0 = head enabled to read data <BR>1 = head enabled
to write data</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1><A style="TEXT-DECORATION: overline">DS3
</A>:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Drive Select 3</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0 = drive 3 selected <BR>1 = drive not
selected</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1><A style="TEXT-DECORATION: overline">DS2
</A>:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Drive Select 2</FONT></STRONG> </TD></TR>
<TR>
<TD></TD>
<TD><FONT size=-1>0 = drive 2 selected <BR>1 = drive not
selected</FONT> </TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR><BR>
<P>These registers are read only, and only available on the PS/2. </P>
<P>By the use of the two status registers A and B on a PS/2, it is possible to
read the status of the control lines between the floppy controller and drive.
Register bits <A style="TEXT-DECORATION: overline">DRV2 </A>, <A
style="TEXT-DECORATION: overline">TRK0 </A>, <A
style="TEXT-DECORATION: overline">INDX </A>, <A
style="TEXT-DECORATION: overline">WP </A>and RDAT indicate the status of the
corresponding data lines. Note that the bit values vary between Status Registers
A and B on Model 30 and other PS/2 models. Some of the values are also
detectable through other registers and the Status Registers readable through the
data register on the AT. </P>
<HR>
<!---------------------------------------------------------------------------------------->
<H3><A name=DRSR>Data Rate Select Register </A></H3><BR>
<P>If you know of any source of information on this register (available only on
the PS/2), please <A href="mailto:debs@savah.freeserve.co.uk">e-mail </A>me with
details. As soon as I am able to find the information, it will be added to this
page. </P>
<HR color=gray SIZE=3>
<!---------------------------------------------------------------------------------------->
<H2 align=center><A name=Commands>Command Set </A></H2>
<P>There are a total of 13 commands available on the µPD765 and compatible FDCs.
A further 4 commands are available on the 8207x controllers. </P>
<P>The <I>sector identification </I>consists of the cylinder, head, sector
number and sector size. This tells the controller the position and number of
sectors to perform this command on. </P>
<P>All commands and status bytes are transferred via the data register, at port
37fh or 377h. Before the command can be written or the status byte read, it is
necessary to read the MRQ bit in the main status register. This determines
whether the data register is ready to supply or receive a byte. It is also
necessary to fix the drive format prior to any read, write or format operation.
</P>
<P>For most data transfers, DMA is used. Although the programming of the DMA is
beyond the scope of this document, I have provided some <A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#DMA_Prog">example
code </A>showing how to set up the DMA for writing a single sector from a floppy
disk drive to main memory. All data transfers concern all sectors from the start
sector to the end of the track. The operation can be stopped earlier by either
setting the command byte <I>track length/max. sector number </I>to a value which
indicates the last sector to be operated on, or setting the count value of the
DMA controller so that it issues a TC (Terminal Count) signal after the required
number of sectors are transfered (the latter method is demonstrated in the <A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#DMA_Prog">example
DMA code </A>below). </P>
<P>If you want a command to be executed on both heads, you need to set the
Multiple Track Bit. This tells the controller to operate on the programmed head
first, then to carry out the same command from the start of the other head. </P>
<P>Once the command has been completed, the status registers ST0-3 return
information which can help you either confirm correct execution of the command,
or determine the cause of an error. </P>
<P>The commands fall into 3 categories. Data transfer commands and control
commands are available on all controllers. The extended commands are only
available on the AT or PS/2. </P>
<HR>
<!---------------------------------------------------------------------------------------->
<H3>List of Valid Commands </H3><!---------------------------------------------------------------------------------------->
<H4><A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#datacom">Data
Transfer Commands </A></H4><PRE>Command Name | Function
-----------------------------------------
read complete track | x2h
write sector | x5h
read sector | x6h
write deleted sector | x9h
read deleted sector | xch
format track | xdh
</PRE><!---------------------------------------------------------------------------------------->
<H4><A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#ctrlcom">Control
Commands </A></H4><PRE>Command Name | Function
-----------------------------------------
fix drive data | x3h
check drive status | x4h
calibrate drive | x7h
check interrupt status | x8h
read sector ID | xah
seek/park head | xfh
invalid command | all invalid opcodes
</PRE><!---------------------------------------------------------------------------------------->
<H4><A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#extcom">Extended
Commands </A></H4><PRE>Command Name | Function
-----------------------------------------------
register summary | 0fh
determine controller version | x10h
verify | x16h
seek relative | 1xfh
</PRE>
<P>In each of the above, 'x' refers to bits 7-5 of byte 0 of the command. Note
that in the <I>seek relative </I>command, x refers to just bits 6 and 5, as bit
7 is always set to 1. The remainder of the function number refers to bits 4-0.
Bit 4 is only used on the AT and PS/2, in 2 of the extended commands. </P>
<P>The function number given is the first byte of the command it applies to. The
commands vary in size from 1 to 9 bytes, and the controller knows from the
function number how many more bytes to expect. For example, if the first byte
received by the data register is <B>66h </B>, in which the upper 5 bits are 06h,
the controller knows that you are sending a <I>read sector </I>command, and it
expects 8 more bytes from the CPU. Additionally, you do nto need to worry about
which of the internal registers each byte of any command has to be directed to,
as the controller does that for you. </P>
<P>Fields common to many of the commands include the following: </P>
<TABLE cellPadding=2>
<TBODY>
<TR>
<TD vAlign=top><STRONG><FONT size=-1>M:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>Multi-track operation </STRONG><BR>1 = carry out
operation on both tracks of programmed cylinder. <BR>0 = carry out
operation on single track.</FONT> </TD></TR>
<TR>
<TD vAlign=top><STRONG><FONT size=-1>F:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>FM/MFM mode </STRONG><BR>1 = operate in MFM
(double density) mode (default) <BR>0 = operate in FM (single density)
mode</FONT> </TD></TR>
<TR>
<TD vAlign=top><STRONG><FONT size=-1>S:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>Skip mode </STRONG><BR>1 = skip deleted data
address marks, 0 = do not skip</FONT> </TD></TR>
<TR>
<TD vAlign=top><STRONG><FONT size=-1>HD:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>head number </STRONG><BR>(always equal to head
address in byte 3 of all commands using a sector ID)</FONT> </TD></TR>
<TR>
<TD vAlign=top><STRONG><FONT size=-1>DR1,DR0:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>Drive: </STRONG><BR>00 = drive 0 (A); 01 = drive
1 (B); 10 = drive 2 (C); 11 = drive 3 (D)</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>Cylinder, Head, Sector Number:</FONT></STRONG>
</TD>
<TD><STRONG><FONT size=-1>Address of first sector to read.</FONT></STRONG>
</TD></TR>
<TR>
<TD vAlign=top><STRONG><FONT size=-1>Sector size code:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>Sector size </STRONG>= 128 * 2^x where x is the
value in this field. <BR>eg If this field is 2 (the default), sector size
= 128 * 2^2 = 512 bytes</FONT> </TD></TR>
<TR>
<TD vAlign=top><STRONG><FONT size=-1>Track length/Max sector
number:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>Number of sectors per track or max. sector
number </STRONG>to operate command on.</FONT> </TD></TR>
<TR>
<TD vAlign=top><STRONG><FONT size=-1>Length of GAP 3:</FONT></STRONG> </TD>
<TD><FONT size=-1>Standard value = 42, minimal value = 32 (5?)
<BR>standard value = 27 (3?)</FONT> </TD></TR>
<TR>
<TD vAlign=top><STRONG><FONT size=-1>Data length:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>length of data to read </STRONG><BR>in bytes
(only valid if sector size = 0, else equal 0ffh)</FONT>
</TD></TR></TBODY></TABLE>
<HR>
<!---------------------------------------------------------------------------------------->
<H3><A name=datacom>Data Transfer Commands </A></H3>
<P>These are the commands used to transfer data between a disk and main memory,
or to format a track. </P>
<P>Each of these commands returns its' <A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#Results1">results
</A>in the same format, which is only described for the <I>read track
</I>command. </P>
<HR SIZE=1>
<!---------------------------------------------------------------------------------------->
<H4>Read Track (x2h) </H4>
<P align=center><IMG alt="Image of Read Track Command" height=240
src="floppy.files/rdtrk.gif" title="Read Track Command" width=300> </P>
<P>When a <I>read track </I>command is issued, the data of a single complete
track is read. The sector specification in the command phase is ignored for this
command, and the reading starts with the first sector after the index address
mark <STRONG>IDAM </STRONG>, reading sector by sector (paying no attention to
the logical sector number given in the ID address mark), until the end of the
track is reached. </P>
<P>The track is treated as a contigusous data block, and the read buffer in main
memory should be large enough to store this amount of data. Also, multi-track
operations are not allowed with this command. If you want to read the same track
on both heads, you have to send the command twice, unlike other read commands
which allow for multi-track operations with a single command. </P>
<H4><A name=Results1>Results Phase </A></H4>
<P align=center><IMG alt="image of Data Transfer Command Results Phase"
height=175 src="floppy.files/Result1.gif"
title="Data Transfer Command Results Phase" width=290> </P>
<TABLE>
<TBODY>
<TR>
<TD><STRONG><FONT size=-1>ST0,&nbsp;ST1,&nbsp;ST2:</FONT></STRONG> </TD>
<TD><FONT size=-1><A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#Status0">Status
Registers </A>0 to 2</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>Cylinder,&nbsp;head, sector number,&nbsp;sector
size:</FONT></STRONG> </TD>
<TD><FONT size=-1>Sector ID. (see table below)</FONT>
</TD></TR></TBODY></TABLE><BR><STRONG>Sector ID in the Result Phase
</STRONG><BR>
<TABLE cellPadding=2>
<TBODY>
<TR vAlign=top>
<TD><STRONG><FONT size=-1>M&nbsp;&nbsp;</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>HD <SUB>prog </SUB>&nbsp;&nbsp;</FONT></STRONG>
</TD>
<TD><STRONG><FONT size=-1>Last sector affected&nbsp;&nbsp; <BR>by
command</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Cylinder&nbsp;&nbsp;</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Head&nbsp;&nbsp;</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Sector&nbsp;&nbsp;</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>Sector Size</FONT></STRONG> </TD></TR>
<TR>
<TD><FONT size=-1>0</FONT> </TD>
<TD><FONT size=-1>0</FONT> </TD>
<TD><FONT size=-1>before end of track</FONT> </TD>
<TD><FONT size=-1>cyl <SUB>prog </SUB></FONT></TD>
<TD><FONT size=-1>HD <SUB>prog </SUB></FONT></TD>
<TD><FONT size=-1>sec <SUB>prog </SUB></FONT></TD>
<TD><FONT size=-1>siz <SUB>prog </SUB></FONT></TD></TR>
<TR>
<TD><FONT size=-1>0</FONT> </TD>
<TD><FONT size=-1>0</FONT> </TD>
<TD><FONT size=-1>end of track</FONT> </TD>
<TD><FONT size=-1>cyl <SUB>prog+1 </SUB></FONT></TD>
<TD><FONT size=-1>HD <SUB>prog </SUB></FONT></TD>
<TD><FONT size=-1>1</FONT> </TD>
<TD><FONT size=-1>siz <SUB>prog </SUB></FONT></TD></TR>
<TR>
<TD><FONT size=-1>0</FONT> </TD>
<TD><FONT size=-1>1</FONT> </TD>
<TD><FONT size=-1>before end of track</FONT> </TD>
<TD><FONT size=-1>cyl <SUB>prog </SUB></FONT></TD>
<TD><FONT size=-1>HD <SUB>prog </SUB></FONT></TD>
<TD><FONT size=-1>sec <SUB>prog </SUB></FONT></TD>
<TD><FONT size=-1>siz <SUB>prog </SUB></FONT></TD></TR>
<TR>
<TD><FONT size=-1>0</FONT> </TD>
<TD><FONT size=-1>1</FONT> </TD>
<TD><FONT size=-1>end of track</FONT> </TD>
<TD><FONT size=-1>cyl <SUB>prog+1 </SUB></FONT></TD>
<TD><FONT size=-1>HD <SUB>prog </SUB></FONT></TD>
<TD><FONT size=-1>1</FONT> </TD>
<TD><FONT size=-1>siz <SUB>prog </SUB></FONT></TD></TR>
<TR>
<TD><FONT size=-1>1</FONT> </TD>
<TD><FONT size=-1>0</FONT> </TD>
<TD><FONT size=-1>before end of track</FONT> </TD>
<TD><FONT size=-1>cyl <SUB>prog </SUB></FONT></TD>
<TD><FONT size=-1>HD <SUB>prog </SUB></FONT></TD>
<TD><FONT size=-1>sec <SUB>prog </SUB></FONT></TD>
<TD><FONT size=-1>siz <SUB>prog </SUB></FONT></TD></TR>
<TR>
<TD><FONT size=-1>1</FONT> </TD>
<TD><FONT size=-1>0</FONT> </TD>
<TD><FONT size=-1>end of track</FONT> </TD>
<TD><FONT size=-1>cyl <SUB>prog </SUB></FONT></TD>
<TD><FONT size=-1>HD <SUB>prog </SUB></FONT></TD>
<TD><FONT size=-1>1</FONT> </TD>
<TD><FONT size=-1>siz <SUB>prog </SUB></FONT></TD></TR>
<TR>
<TD><FONT size=-1>1</FONT> </TD>
<TD><FONT size=-1>1</FONT> </TD>
<TD><FONT size=-1>before end of track</FONT> </TD>
<TD><FONT size=-1>cyl <SUB>prog </SUB></FONT></TD>
<TD><FONT size=-1>(inverse of) HD <SUB>prog </SUB></FONT></TD>
<TD><FONT size=-1>sec <SUB>prog </SUB></FONT></TD>
<TD><FONT size=-1>siz <SUB>prog </SUB></FONT></TD></TR>
<TR>
<TD><FONT size=-1>1</FONT> </TD>
<TD><FONT size=-1>1</FONT> </TD>
<TD><FONT size=-1>end of track</FONT> </TD>
<TD><FONT size=-1>cyl <SUB>prog+1 </SUB></FONT></TD>
<TD><FONT size=-1>(inverse of) HD <SUB>prog </SUB></FONT></TD>
<TD><FONT size=-1>1</FONT> </TD>
<TD><FONT size=-1>siz <SUB>prog </SUB></FONT></TD></TR></TBODY></TABLE><BR>
<TABLE>
<TBODY>
<TR>
<TD><FONT size=-1>HD <SUB>prog </SUB>:</FONT> </TD>
<TD><FONT size=-1>programmed head&nbsp;&nbsp;</FONT> </TD>
<TD><FONT size=-1>sec <SUB>prog </SUB>:</FONT> </TD>
<TD><FONT size=-1>programmed sector</FONT> </TD></TR>
<TR>
<TD><FONT size=-1>cyl <SUB>prog </SUB>:</FONT> </TD>
<TD><FONT size=-1>programmed cylinder&nbsp;&nbsp;</FONT> </TD>
<TD><FONT size=-1>siz <SUB>prog </SUB>:</FONT> </TD>
<TD><FONT size=-1>programmed sector size</FONT>
</TD></TR></TBODY></TABLE><BR><BR>
<P>The Sector ID consists of Cylinder, Head, Sector and Sector Size. Given the
values programmed for M (multi-track) and HD (head number), the values for the
sector ID in the results phase indicate whether the last sector affected was the
last sector of the command or not. </P>
<HR SIZE=1>
<!---------------------------------------------------------------------------------------->
<H4>Write Sector (x5h) </H4>
<P align=center><IMG alt="Image of Write Sector Command" height=240
src="floppy.files/wrsec.gif" title="Write Sector Command" width=300> </P>
<P>The <I>write sector </I>command transfers one or more sectors from main
memory to the controller, from where it is transferred to the disk. As the
controller writes each sector, it also writes a valid <I>data address mark
</I>to the disk. This command can operate on both heads, starting from the first
sector of the second head after reaching the end of the first head. </P>
<P>The <A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#Results1">results
phase </A>is the same as for the read track command. </P>
<HR SIZE=1>
<!---------------------------------------------------------------------------------------->
<H4>Read Sector (x6h) </H4>
<P align=center><IMG alt="Image of Read Sector Command" height=240
src="floppy.files/rdsec.gif" title="Read Sector Command" width=300> </P>
<P>The <I>read sector </I>command reads one or more sectors with a valid data
address mark from the disk, and transfers the data into main memory. This
command can operate on both heads. </P>
<P>The <A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#Results1">results
phase </A>is the same as for the read track command. </P>
<HR SIZE=1>
<!---------------------------------------------------------------------------------------->
<H4>Write Deleted Sector (x9h) </H4>
<P align=center><IMG alt="Image of Write Deleted Sector Command" height=240
src="floppy.files/wrdelsec.gif" title="Write Deleted Sector Command" width=300>
</P>
<P>The <I>write deleted sector </I>command is the same as the <I>write sector
</I>command, except that for each sector written a <I>deleted data address mark
</I>is written instead of the normal data address mark. </P>
<P>The <A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#Results1">results
phase </A>is the same as for the read track command. </P>
<HR SIZE=1>
<!---------------------------------------------------------------------------------------->
<H4>Read Deleted Sector (xch) </H4>
<P align=center><IMG alt="Image of Read Deleted Sector Command" height=240
src="floppy.files/rddelsec.gif" title="Read Deleted Sector Command" width=300>
</P>
<P>The <I>read deleted sector </I>command is the same as the <I>read sector
</I>command, except that only sectors with a deleted data address mark can be
read. All sectors with valid data address marks will be ignored. </P>
<P>The <A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#Results1">results
phase </A>is the same as for the read track command. </P>
<HR SIZE=1>
<!---------------------------------------------------------------------------------------->
<H4>Format Track (xdh) </H4>
<P align=center><IMG alt="Image of Format Track Command" height=180
src="floppy.files/fmttrk.gif" title="Format Track Command" width=300> </P>
<P>This command formats a single track. A 4 byte format buffer must be provided
for each sector of the track. The buffer holds the sector ID of the
corresponding sector. The format buffer should be large enough to hold the data
required for all sectors of the track. The <A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#fmtbuf">buffer
format </A>is shown below. </P>
<P>For ease of use, the DMA controller should be programmed to enable the
controller to read the format buffer via DMA channel 2. Alternatively, the
format data can be transferred by the use of interrupt-driven data exchange. The
controller issues a hardware interrupt before fromatting each sector. The
handler can then transfer the 4 byte format information for the next sector to
be formatted. </P>
<P>The formatting begins once the drive has provided a signal on the IDX line,
indicating the beginning of the track. Sectors are formatted continuously until
the drive passes the same signal again, this time indicating the end of the
track (note that the start and end of the track are at the same point, marked by
an index hole on the disk). </P>
<P>For the format command, the length of the GAP field is larger than when
reading or writing data. Unless i find any further information on the GAP
length, I can only include the default GAP length in this document. </P>
<P>The <A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#Results1">results
phase </A>is the same as for the read track command. </P>
<H4><A name=fmtbuf>Format buffer for one sector </A></H4>
<P align=center><IMG alt="Image of Format Buffer" height=120
src="floppy.files/fmtbuf.gif" title="Format Buffer" width=170> </P>
<P>In the above table, <I>Sector Size </I>uses the same codes as for each of the
commands described above. </P>
<HR>
<!---------------------------------------------------------------------------------------->
<H3><A name=ctrlcom>Control Commands </A></H3>
<P>This set of commands includes various miscellaneous commands relating to the
status of a disk or drive, including seeking to a new cylinder and responding to
invalid commands. </P>
<HR SIZE=1>
<!---------------------------------------------------------------------------------------->
<H4>Fix Drive Data (x3h) </H4>
<P align=center><IMG alt="image of Fix Drive Data Command" height=120
src="floppy.files/FixData.gif" title="Fix Drive Data Command" width=300> </P>
<TABLE>
<TBODY>
<TR>
<TD vAlign=top><STRONG><FONT size=-1>NDM:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>Non-DMA Mode </STRONG><BR>0 = Data Transfer via
DMA <BR>1 = Data Transfer not via DMA</FONT>
</TD></TR></TBODY></TABLE><BR><BR><BR align="center">
<TABLE>
<TBODY>
<TR>
<TD align=middle>Step Rate [ms] <BR><IMG alt="image of Step Rate"
height=190 src="floppy.files/StepRate.gif" title="Step Rate" width=220>
</TD>
<TD align=middle>Head Unload Time [ms] <BR><IMG
alt="image of Head Unload Time" height=190 src="floppy.files/HdUnload.gif"
title="Head Unload Time" width=220> </TD>
<TD align=middle>Head Load Time [ms]<IMG alt="image of Head Load Time"
height=190 src="floppy.files/HeadLoad.gif" title="Head Load Time"
width=220> </TD></TR></TBODY></TABLE><BR><BR>
<P>This command is used to pass mechanical control data to the controller for
the connected drives. It should be noted, as shown in the bottom 3 diagrams,
that the values are also dependent on the data transfer rate, which in the AT
and PS/2 is set in the <A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#CCR">control
configuration register </A>. </P>
<P>This command doesn't have a result phase. </P>
<HR SIZE=1>
<!---------------------------------------------------------------------------------------->
<H4>Check Drive Status (x4h) </H4>
<P align=center><IMG alt="image of Check Drive Status Command" height=100
src="floppy.files/ChkDrvStatus.gif" title="Check Drive Status Command"
width=300> </P>
<P>This command provides status information relating to the state of the
connected drives. </P>
<H4>Result Phase </H4>
<P align=center><IMG alt="image of Check Drive Status Command Result Phase"
height=50 src="floppy.files/Result2.gif"
title="Check Drive Status Command Result Phase" width=290> </P>
<P>Status Register 3 contains drive information. </P>
<HR SIZE=1>
<!---------------------------------------------------------------------------------------->
<H4>Calibrate Drive (x7h) </H4>
<P align=center><IMG alt="image of Calibrate Drive Command" height=100
src="floppy.files/Calibrate.gif" title="Calibrate Drive Command" width=300> </P>
<P>This command is used to position the read/write head to cylinder 0. If a seek
error occurs in the course of a sector access, the head can be moved to an
absolute cylinder to recalibrate the drive. </P>
<P>This command doesn't return a result phase, but after cmopletion an interrupt
is issued. To check the status information of this command, you should issue a
<I>check interrupt status </I>cmomand to determine the commands status
information. </P>
<P>When the controller sees this command, it sets the DIR signal to 0, and
passes the drive up to 79 step pulses. After each of these pulses, the
controller checks the TRK0 signal. If it is active (htat is, the head is on
track 0), the controller sets the SE bit in Status Register 0, and aborts the
command. If TRK0 is not active after 79 step pulses, the controller sets bits SE
and EC in Status Register 0, and terminates the command. </P>
<P>To calibrate the drive, you may have to issue several calibration commands,
especially if the drive being calibrated has more than 80 tracks. After
completion of the command, you should always check whether the head is correctly
positioned over track 0, using the <I>check interrupt status </I>command. A
calibration is always necessary after a power up, to initialise the head
position correctly. </P>
<HR SIZE=1>
<!---------------------------------------------------------------------------------------->
<H4><A name=chkint>Check Interrupt Status </A>(x8h) </H4>
<P align=center><IMG alt="image of Check Interrupt Status Command" height=80
src="floppy.files/ChkInts.gif" title="Check Interrupt Status Command" width=300>
</P>
<P>This command is used to check status infromation about the state of the
controller in the result phase when the controller has returned an interrupt.
</P>
<P>The interrupt signal is reset by this command, which also determines the
source of the interrupt via status register ST0. If the command is issued with
no interrupts pending, a value of 80h is returned in ST0, corresponding to the
message <I>invalid command </I>. </P>
<P>Interrupts are issued in the following cases: </P><PRE>At the beginning of the result phase of the commands:
read sector
read deleted sector
write sector
write deleted sector
read track
format track
read sector ID
verify
After completion of the following commands without a result phase:
calibrate drive
seek
seek relative
For data exchange between main memory and controller when interrupt-driven data exchange
is active and the controller is not using DMA.
</PRE>
<H4>Result Phase </H4>
<P align=center><IMG alt="Image of Check Interrupt Status Command Return Phase"
height=70 src="floppy.files/Result3.gif"
title="Check Interrupt Status Command Return Phase" width=290> </P>
<HR SIZE=1>
<!---------------------------------------------------------------------------------------->
<H4>Read Sector ID (xah) </H4>
<P align=center><IMG alt="#image of Read Sector ID Command" height=100
src="floppy.files/RdSecID.gif" title="Read Sector ID Command" width=300> </P>
<P>This command is used to read the Sector ID of the first ID address mark the
controller is able to detect. Using this command, it is possible to determine
the current position of the read/write head. If no ID address mark can be read
in one complete disk revolution, the controller issues an error message,
detected from the values returned in ST0-2. </P>
<H4>Result Phase </H4>
<P align=center><IMG alt="image of Read Sector ID Command Result Phase"
height=175 src="floppy.files/Result1.gif"
title="Read Sector ID Command Result Phase" width=290> </P>
<P>The values in the sector ID are calculated in the same way as for the <A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#Results1">result
phase </A>of the read track command. </P>
<HR SIZE=1>
<!---------------------------------------------------------------------------------------->
<H4>Seek/Park Head (xfh) </H4>
<P align=center><IMG alt="image of Park Head Command" height=120
src="floppy.files/ParkHead.gif" title="Park Head Command" width=300> </P>
<P>The Seek Head command, sometimes called the Park Head command, moves the
read/write head to the specified cylinder. When the controller receives this
command, it compares the programmed cylinder number and the current cylinder
number. The direction signal (DIR) is set, and step pulses are issued until the
two cylinder numbers match. </P>
<P>This command has no result phase. To verify successful completion of the
command, it is necessary to check the head position immediately after completion
of the command, using the <A
href="http://debs.future.easyspace.com/Programming/Hardware/FDC/floppy.html#chkint">check
interrupt status </A>command. </P>
<HR SIZE=1>
<!---------------------------------------------------------------------------------------->
<H4>invalid command (all invalid opcodes) </H4>
<P align=center><IMG alt="image of Invalid Opcode Command" height=80
src="floppy.files/Invalid.gif" title="Invalid Opcode Command" width=300> </P>
<P>Whenever an invalid opcode is detected, the controller switches to a standby
state, and bit 7 of ST0 is set. The same happens if <I>check interrupt status
</I>is issued with no interrupts pending. </P>
<H4>Result Phase </H4>
<P align=center><IMG alt="image of Invalid Opcode Command Result Phase"
height=50 src="floppy.files/Result4.gif"
title="Invalid Opcode Command Result Phase" width=290> </P>
<HR>
<!---------------------------------------------------------------------------------------->
<H3><A name=extcom>Extended Commands </A></H3>
<P>These commands are not available on all controllers, being introduced in the
AT and PS/2. If the controller does not support any of these commands, it will
treat them as invalid commands. </P>
<HR SIZE=1>
<!---------------------------------------------------------------------------------------->
<H4>Register Summary (0fh) </H4>
<P align=center><IMG alt="image of Register Summary" height=80
src="floppy.files/RegDump.gif" title="Register Summary" width=300> </P>
<P>This command returns the values read from the internal controller registers.
</P>
<H4>Result Phase </H4>
<P align=center><IMG alt="image of Register Summary Command Result Phase"
height=175 src="floppy.files/Result5.gif"
title="Register Summary Command Result Phase" width=290> </P>
<TABLE>
<TBODY>
<TR>
<TD vAlign=top><STRONG><FONT
size=-1>Current&nbsp;Cylinder&nbsp;DR0,&nbsp;DR1,&nbsp;DR2&nbsp;DR3:</FONT></STRONG>
</TD>
<TD><FONT size=-1>Cylinder on drive 0, 1, 2, 3 where read/write head is
currently positioned.</FONT> </TD></TR>
<TR>
<TD vAlign=top><STRONG><FONT size=-1>step&nbsp;time,
head&nbsp;unload&nbsp;time, head&nbsp;load&nbsp;time:</FONT></STRONG> </TD>
<TD><FONT size=-1>mechanical characteristics set by the <I>fix drive data
</I>command</FONT> </TD></TR>
<TR>
<TD vAlign=top><STRONG><FONT size=-1>NDM:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>non-DMA mode </STRONG><BR>1 = DMA disabled <BR>0
= DMA enabled</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>number of sectors/track length</FONT></STRONG>
</TD>
<TD><FONT size=-1><STRONG>number of sectors per track
</STRONG></FONT></TD></TR></TBODY></TABLE><BR><BR>
<HR SIZE=1>
<!---------------------------------------------------------------------------------------->
<H4>Determine Controller Version (10h) </H4>
<P align=center><IMG alt="image of Get Controller Version Command" height=80
src="floppy.files/CtrVer.gif" title="Get Controller Version Command" width=300>
</P>
<P>This command determines whether there is a controller present which supports
the extended commands. If the controller does not support the extended commands,
this command is treated as an invalid opcode, and an error message is returned.
</P>
<H4>Result Phase </H4>
<P align=center><IMG
alt="image of Determine Controller Version Command Result Phase" height=50
src="floppy.files/Result6.gif"
title="Determine Controller Version Command Result Phase" width=290> </P>
<P>This result is only returned if an extended controller is installed. </P>
<HR SIZE=1>
<!---------------------------------------------------------------------------------------->
<H4>Verify (x16h) </H4>
<P align=center><IMG alt="image of Verify Command" height=240
src="floppy.files/Verify.gif" title="Verify Command" width=300> </P>
<TABLE cellPadding=2>
<TBODY>
<TR>
<TD vAlign=top><STRONG><FONT size=-1>EC:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>enable count value </STRONG><BR>1 = command byte
8 specifies the number of sectors to verify <BR>0 = command byte 8
specifies the data length, if sector size = 0</FONT> </TD></TR>
<TR>
<TD vAlign=top><STRONG><FONT
size=-1>data&nbsp;length/verify&nbsp;sectors:&nbsp;&nbsp;</FONT></STRONG>
</TD>
<TD><FONT size=-1><STRONG>If EC = 0 and sector size = 0:
</STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;length of data to verify, in bytes.
<BR><STRONG>Else: </STRONG><BR>&nbsp;&nbsp;&nbsp;&nbsp;number of sectors
to verify.</FONT> </TD></TR></TBODY></TABLE><BR><BR>
<P>This command is similar to the read command, except that it doesn't transfer
data to main memory. One or more sectros with valid DAMs are read from the disk,
and their CRC is calculated. This value is compared to the read CRC, inorder to
check the internal consistency of the data. As no data is transferred, the
command cannot be aborted by a TC signal from the DMA controller. However, if
youset the EC bit to 1, the controller issues an implicit TC signal when the
count value in <I>data length/verify sectors </I>is decremented to 0. In that
case, <I>data length/verify sectors </I>indicates the number of sectors to be
verified. A value of 0 in this byte tells the controller to check 256 sectors.
When EC is set to 0, <I>data length/verify data </I>should be set to ffh. </P>
<H4>Result Phase </H4>
<P align=center><IMG alt="image of Verify Command Result Phase" height=175
src="floppy.files/Result1.gif" title="Verify Command Result Phase" width=290>
</P>
<HR SIZE=1>
<!---------------------------------------------------------------------------------------->
<H4>Seek Relative (1xfh) </H4>
<P align=center><IMG alt="image of Seek Relative Command" height=120
src="floppy.files/SeekRel.gif" title="Seek Relative Command" width=300> </P>
<TABLE cellPadding=2>
<TBODY>
<TR>
<TD vAlign=top><STRONG><FONT size=-1>DIR:</FONT></STRONG> </TD>
<TD><FONT size=-1><STRONG>Step Direction </STRONG><BR>1 = inward (to
larger cylinder numbers) <BR>0 = outward (to smaller cylinder
numbers)</FONT> </TD></TR>
<TR>
<TD><STRONG><FONT size=-1>cylinder step:</FONT></STRONG> </TD>
<TD><STRONG><FONT size=-1>number of cylinders to step</FONT></STRONG>
</TD></TR></TBODY></TABLE><BR><BR>
<P>This command is sued to move the read/write head relative to the current
cylinder. There is no result phase for this command, but its' result can be
checked through the use of either the <I>read sector ID </I>or the <I>register
dump </I>command. </P>
<HR color=gray SIZE=3>
<!---------------------------------------------------------------------------------------->
<H2 align=center>Sample code </H2>
<HR SIZE=1>
<!---------------------------------------------------------------------------------------->
<H4><A name=DMA_Prog>Initialise DMA for writing a single sector from FDC to main
memory </A></H4><!---------------------------------------------------------------------------------------->
<P>Please note that this code was added in a hurry and has not yet been tested.
I wanted to publish this page with DMA initialisation code before going on
holiday. The code will be tested and, if necessary, adjusted, late in June
(1999), when I get back from my vacation. </P><PRE><STRONG>
;*******************************************************************************
; This code expects to receive the data buffer address in ES:BX
;
; ES: Buffer segment
; BX: Buffer offset
;
; The address is a 20 bit segmented address, calculated from Segment*16 + Offset
;
; Bits 19-16 of the address form the entry for the DMA page entry
; Bits 15-8 of the address form the high-order byte for the DMA address register
; Bits 7-0 of the address form the low-order byte for the DMA address register
;
; For more information on this, it will be necessary to read other literature
; specifically targetting the DMA controller.
;*******************************************************************************
disable_dma1: ; disable DMA 1
mov al, 14h ; output 14h to the command register to disable and
out 08h, al ; initialise the DMA controller
mode: ; set up DMA transfer mode for channel 2
mov al, 56h ; set up for a single write transfer to main memory
out 0bh, al ; using DMA channel 2
; for a read, output 5ah
get_address: ; get the buffer address, and split into component parts
; as required by the DMA controller.
mov ax, es ; load buffer segment into AX
mov cl, 04h ;
shl ax, cl ; shift value in ax left 4 times
add ax, bx ; add offest + buffer. AX now contains high and low
; for the DMA address register.
jc carry ; if carry is set, jump to carry
no_carry:
mov bx, es ; load segment of buffer into BX
mov cl, 04h ;
shr bh, cl ; shift right BH 4 times. BH now contains the value
; for the DMA page segment
jmp buffer_address; output the buffer address
carry:
mov bx, es ; load segment of buffer into BX
mov cl, 04h ;
shr bh, cl ; shift right BH 4 times. BH now contains the high
; bits of the segment
adc bh, 00h
buffer_address: ; output the address to the DMA controller
out 0ch, al ; reset flip-flop. I am not sure what this does,
; but my reference shows this as necessary.
out 04h, al ; output low order address byte to address register
mov al, ah ;
out 04h, al ; output high-order address byte to address register
mov al, bh ;
out 81h, al ; load page register with page value
count: ; set up count register
out 0ch, al ; reset flip-flop
mov al, 0ffh ;
out 05h, al ;
mov al, 01h ;
out 05h, al ; load 511 into count register (to read one sector)
; it should be noted that for multiple transfers, the
; second value output to port 05h is equivalent to
; (2*number of sectors)-1
release_channel:
mov al, 02h
out 0ah, al ; release channel 2
enable_dma1: ; enable DMA 1
mov al, 10h
out 08h, al ; this is the value for enabling the DMA for the mode required
</STRONG>
</PRE>
<HR>
<!---------------------------------------------------------------------------------------->
<P>Once I have written my own floppy disk drivers for the operating system I am
working on, I'll add a link to that. Until then, I'm happy to continue replying
to any questions I receive by email. Please note that I am a programmer, not a
hardware expert, and as such may not be able to answer questions that relate to
how to produce hardware using a FDC. </P>
<P>If you have any comments on the content of this page, including errors and
typos, please contact me:</P>
<P align=center>
<SCRIPT language=javascript><!--
var contact = "<img src=../../../mail-me.jpg>"
var localhost = "Webmistress"
var emailHost = "dwiles"
var domain = "demon.co.uk"
var subject = "FDC"
document.write("<a href=" + "mail" + "to:" + localhost + "@" + emailHost + "." + domain +
"?" + "Subject" + "=" + subject + ">" + contact + "</a>" + ".")
//-->
</SCRIPT>
</P></BASEFONT></BODY></HTML>