8272A  -  NEC uPD765  -  Floppy Disk Controller

================================================================
3F0h	FDC Diskette Status Register A
	(read-only; PS/2 only)
================================================================
7 6 5 4 3 2 1 0
| | | | | | | `---- direction
| | | | | | `------ write protect
| | | | | `-------- index
| | | | `---------- head 1 select
| | | `------------ track 0
| | `-------------- step
| `---------------- second drive installed
`------------------ interrupt pending

================================================================
3F1h	FDC Diskette Status Register B
	(read-only; PS/2 only)
================================================================
7 6 5 4 3 2 1 0
| | | | | | | `---- motor enable 0
| | | | | | `------ motor enable 1
| | | | | `-------- write enable
| | | | `---------- read data (toggles w/positive transition in -RD DATA)
| | | `------------ write data (toggles w/positive transition in WR DATA)
| | `-------------- drive select
`-+---------------- reserved

================================================================
3F2h	FDC Digital Output Register at 3F2h
	(write only)
================================================================
7 6 5 4 3 2 1 0
| | | | | | `-+---- floppy drive select (0=A, 1=B, 2=floppy C, ...)
| | | | | `-------- 1 = FDC enable, 0 = hold FDC at reset
| | | | `---------- 1 = DMA & I/O interface enabled  (reserved PS/2)
| | | `------------ 1 = turn floppy drive A motor on
| | `-------------- 1 = turn floppy drive B motor on
| `---------------- 1 = turn floppy drive C motor on; (reserved PS/2)
`------------------ 1 = turn floppy drive D motor on; (reserved PS/2)

- used to control drive motors, drive selection, and feature enable
- PS/2 only uses bit 0 for floppy drive select; bit 1 is reserved
- PS/2 only uses bits 5 & 4 for  motor enable; bits 7&6 are reserved
- all DOR bits are cleared during controller reset

================================================================
3F4h	FDC Main Status Register
	(read only)
================================================================
7 6 5 4 3 2 1 0
| | | | | | | `---- floppy drive 0 in seek mode/busy
| | | | | | `------ floppy drive 1 in seek mode/busy
| | | | | `-------- floppy drive 2 in seek mode/busy (reserved PS/2)
| | | | `---------- floppy drive 3 in seek mode/busy (reserved PS/2)
| | | `------------ FDC read or write command in progress
| | `-------------- FDC is in non-DMA mode
| `---------------- I/O direction;  1 = FDC to CPU; 0 = CPU to FDC
`------------------ data reg ready for I/O to/from CPU (request for master)

================================================================
3F5h	FDC Command Status Register 0
================================================================
7 6 5 4 3 2 1 0
| | | | | | `-+---- unit selected at interrupt (0=A, 1=B, 2=...)
| | | | | `-------- head number at interrupt (head 0 or 1)
| | | | `---------- not ready on read/write or SS access to head 1
| | | `------------ equipment check (see note)
| | `-------------- set to 1 when FDD completes a seek command
`-+---------------- last command status (see below)

Bits 76		Last Command Status
00		command terminated successfully
01		command execution started but terminated abnormally
10		invalid command issued
11		command terminated abnormally due to a change in state of
		the Ready Signal from the FDC  (reserved on PS/2)

- equipment check can occur if FDD signals a fault or track zero is
  not found after 77 steps on a recalibrate command
- PS/2 only uses bits 1-0 for drive (values are 01b and 10b)

================================================================
3F5h	FDC Command Status Register 1
================================================================
7 6 5 4 3 2 1 0
| | | | | | | `---- FDC cannot find ID address mark (see reg 2)
| | | | | | `------ write protect detected during write
| | | | | `-------- FDC cannot find sector ID
| | | | `---------- unused (always zero)
| | | `------------ over-run;  FDC not serviced in reasonable time
| | `-------------- data error (CRC) in ID field or data field
| `---------------- unused (always zero)
`------------------ end of cylinder; sector# greater than sectors/track

- bit 0 of Status Register 1 and bit 4 of Status Register 2 are
  related and mimic each other

================================================================
3F5h	FDC Command Status Register 2
================================================================
7 6 5 4 3 2 1 0
| | | | | | | `---- missing address mark in data field
| | | | | | `------ bad cylinder, ID not found and Cyl Id=FFh
| | | | | `-------- scan command failed, sector not found in cylinder
| | | | `---------- scan command equal condition satisfied
| | | `------------ wrong cylinder detected
| | `-------------- CRC error detected in sector data
| `---------------- sector with deleted data address mark detected
`------------------ unused (always zero)

- bit 0 of Status Register 1 and bit 4 of Status Register 2 are
  related and mimic each other

================================================================
3F5h	FDC Command Status Register 3 at 3F5h
================================================================
7 6 5 4 3 2 1 0
| | | | | | `-+---- FDD unit selected status (0=A, 1=B, 2=...)
| | | | | `-------- FDD side head select status (0=head 0, 1=head 1)
| | | | `---------- FDD two sided status signal
| | | `------------ FDD track zero status signal
| | `-------------- FDD ready status signal
| `---------------- FDD write protect status signal
`------------------ FDD fault status signal

================================================================
3F7h	FDC Digital Input Register
	(PS/2 only; read only)
================================================================
7 6 5 4 3 2 1 0
| | | | | | | `--- high density select
| `-+-+-+-+-+----- reserved
`----------------- diskette change

- Digital Input Register is used to sense the state of the
  (-diskette change) and the (-high density select) signals

================================================================
3F7h	FDC Configuration Control Register
	(PS/2 only; write only)
================================================================
7 6 5 4 3 2 1 0
| | | | | | `-+-- DRC1, DRC0  (see below)
`-+-+-+-+-+------ reserved

DRC1 DRC0
  0   0    500000 bit per second mode
  0   1    reserved
  1   0    250000 bit per second mode
  1   1    reserved

- Configuration Control Register is used to set the transfer rate

================================================================
FDC Programming Considerations
================================================================
Three phases of command execution:

1.  Command phase; commands are sent from the CPU to the FDC via
    port 3F5h;	bit 6 of the Status Register at 3F4h must be zero
2.  Execution phase; FDC executes instruction & generates INT 6
3.  Result phase; status and other information is available to CPU;
    INT 6 sets bit 7 of BIOS Data Area location 40:3E which can
    be polled for completion status

Example of a read operation:

1. turn disk motor on and set delay time for drive spin up
2. perform seek operation;  wait for disk interrupt
3. prepare DMA chip to move data to memory
4. send read command and wait for transfer complete interrupt
5. read status information
6. turn disk motor off


Floppy Diskette Controller Operations (15 commands)

Read Data       	D7  D6  D5  D4  D3  D2  D1  D0
-------------------	------------------------------
command byte 0: 	MT  MF  SK   0   0   1   1   0
command byte 1: 	 ?   ?   ?   ?   ?  HD  US1 US0
command byte 2: 	cylinder number
command byte 3: 	head number
command byte 4: 	sector number
command byte 5: 	BPS
command byte 6: 	end of track (last sector in track)
command byte 7: 	gap 3 length
command byte 8: 	data length (if cmd byte 5==0)

result byte 0:		status register 0
result byte 1:		status register 1
result byte 2:		status register 2
result byte 3:		cylinder number
result byte 4:		head number
result byte 5:		sector number
result byte 6:		BPS

Read Deleted Data  	D7  D6  D5  D4  D3  D2  D1  D0
-------------------	------------------------------
command byte 0:    	MT  MF  SK   0   1   1   0   0
command byte 1:    	 ?   ?   ?   ?   ?  HD  US1 US0
command byte 2:    	cylinder number
command byte 3:    	head number
command byte 4:    	sector number
command byte 5:    	BPS
command byte 6:    	end of track (last sector in track)
command byte 7:    	gap 3 length
command byte 8:    	data length (if cmd byte 5==0)

result byte 0:	   	status register 0
result byte 1:	   	status register 1
result byte 2:	   	status register 2
result byte 3:	   	cylinder number
result byte 4:	   	head number
result byte 5:	   	sector number
result byte 6:	   	BPS

Write Data         	D7  D6  D5  D4  D3  D2  D1  D0
-------------------	------------------------------
command byte 0:    	MT  MF   0   0   0   1   0   1
command byte 1:    	 ?   ?   ?   ?   ?  HD  US1 US0
command byte 2:    	cylinder number
command byte 3:    	head number
command byte 4:    	sector number
command byte 5:    	BPS
command byte 6:    	end of track (last sector in track)
command byte 7:    	gap 3 length
command byte 8:    	data length (if cmd byte 5==0)

result byte 0:	   	status register 0
result byte 1:	   	status register 1
result byte 2:	   	status register 2
result byte 3:	   	cylinder number
result byte 4:	   	head number
result byte 5:	   	sector number
result byte 6:	   	BPS

Write Deleted Data 	D7  D6  D5  D4  D3  D2  D1  D0
-------------------	------------------------------
command byte 0:    	MT  MF   0   0   1   0   0   1
command byte 1:    	 ?   ?   ?   ?   ?  HD  US1 US0
command byte 2:    	cylinder number
command byte 3:    	head number
command byte 4:    	sector number
command byte 5:    	BPS
command byte 6:    	end of track (last sector in track)
command byte 7:    	gap 3 length
command byte 8:    	data length (if cmd byte 5==0)

result byte 0:	   	status register 0
result byte 1:	   	status register 1
result byte 2:	   	status register 2
result byte 3:	   	cylinder number
result byte 4:	   	head number
result byte 5:	   	sector number
result byte 6:	   	BPS

Read a Track       	D7  D6  D5  D4  D3  D2  D1  D0
-------------------	------------------------------
(Diagnostic)
command byte 0:    	 0  MF  SK   0   0   0   1   0
command byte 1:    	 ?   ?   ?   ?   ?  HD  US1 US0
command byte 2:    	cylinder number
command byte 3:    	head number
command byte 4:    	sector number
command byte 5:    	BPS
command byte 6:    	end of track (last sector in track)
command byte 7:    	gap 3 length
command byte 8:    	data length (if cmd byte 5==0)

result byte 0:	   	status register 0
result byte 1:	   	status register 1
result byte 2:	   	status register 2
result byte 3:	   	cylinder number
result byte 4:	   	head number
result byte 5:	   	sector number
result byte 6:	   	BPS

Read ID            	D7  D6  D5  D4  D3  D2  D1  D0
-------------------	------------------------------
command byte 0:    	 0  MF   0   0   1   0   1   0
command byte 1:    	 ?   ?   ?   ?   ?  HD  US1 US0

result byte 0:	   	status register 0
result byte 1:	   	status register 1
result byte 2:	   	status register 2
result byte 3:	   	cylinder number
result byte 4:	   	head number
result byte 5:	   	sector number
result byte 6:	   	BPS

Format a Track     	D7  D6  D5  D4  D3  D2  D1  D0
-------------------	------------------------------
(Write Sector IDs)
command byte 0:    	 0  MF   0   0   1   1   0   1
command byte 1:    	 ?   ?   ?   ?   ?  HD  US1 US0
command byte 2:    	BPS
command byte 3:    	sectors per track
command byte 4:    	gap 3 length
command byte 5:    	filler pattern to write in each byte

result byte 0:	   	status register 0
result byte 1:	   	status register 1
result byte 2:	   	status register 2
result byte 3:	   	cylinder number
result byte 4:	   	head number
result byte 5:	   	sector number
result byte 6:	   	BPS

Scan Equal         	D7  D6  D5  D4  D3  D2  D1  D0
-------------------	------------------------------
command byte 0:    	MT  MF  SK   1   0   0   0   1
command byte 1:    	 ?   ?   ?   ?   ?  HD  US1 US0
command byte 2:    	cylinder number
command byte 3:    	head number
command byte 4:    	sector number
command byte 5:    	BPS
command byte 6:    	end of track (last sector in track)
command byte 7:    	gap 3 length
command byte 8:    	scan test (1=scan contiguous, 2=scan alternate)

result byte 0:	   	status register 0
result byte 1:	   	status register 1
result byte 2:	   	status register 2
result byte 3:	   	cylinder number
result byte 4:	   	head number
result byte 5:	   	sector number
result byte 6:	   	BPS

Scan Low or Equal  	D7  D6  D5  D4  D3  D2  D1  D0
-------------------	------------------------------
command byte 0:    	MT  MF  SK   1   1   0   0   1
command byte 1:    	 ?   ?   ?   ?   ?  HD  US1 US0
command byte 2:    	cylinder number
command byte 3:    	head number
command byte 4:    	sector number
command byte 5:    	BPS
command byte 6:    	end of track (last sector in track)
command byte 7:    	gap 3 length
command byte 8:    	scan test (1=scan contiguous, 2=scan alternate)

result byte 0:	   	status register 0
result byte 1:	   	status register 1
result byte 2:	   	status register 2
result byte 3:	   	cylinder number
result byte 4:	   	head number
result byte 5:	   	sector number
result byte 6:	   	BPS

Scan High or Equal 	D7  D6  D5  D4  D3  D2  D1  D0
-------------------	------------------------------
command byte 0:    	MT  MF  SK   1   1   1   0   1
command byte 1:    	 ?   ?   ?   ?   ?  HD  US1 US0
command byte 2:    	cylinder number
command byte 3:    	head number
command byte 4:    	sector number
command byte 5:    	BPS
command byte 6:    	end of track (last sector in track)
command byte 7:    	gap 3 length
command byte 8:    	scan test (1=scan contiguous, 2=scan alternate)

result byte 0:	   	status register 0
result byte 1:	   	status register 1
result byte 2:	   	status register 2
result byte 3:	   	cylinder number
result byte 4:	   	head number
result byte 5:	   	sector number
result byte 6:	   	BPS

Recalibrate        	D7  D6  D5  D4  D3  D2  D1  D0
-------------------	------------------------------
command byte 0:     	 0   0   0   0   0   1   1   1
command byte 1:     	 ?   ?   ?   ?   ?   0  US1 US0

returns nothing

Sense Interrupt    	D7  D6  D5  D4  D3  D2  D1  D0
-------------------	------------------------------
command byte 0:    	 0   0   0   0   1   0   0   0

result byte 0:	   	status register 0
result byte 1:	   	present cylinder number

Specify Step		D7  D6  D5  D4  D3  D2  D1  D0
-------------------	------------------------------
command byte 0:    	 0   0   0   0   0   0   1   1
command byte 1:    	step rate time | head unload time
command byte 2:    	------head load time------   ND

returns nothing

Sense Drive Status	D7  D6  D5  D4  D3  D2  D1  D0
-------------------	------------------------------
command byte 0:    	 0   0   0   0   0   1   0   0
command byte 1:    	 ?   ?   ?   ?   ?  HD  US1 US0

result byte 0:	   	status register 3

Seek               	D7  D6  D5  D4  D3  D2  D1  D0
-------------------	------------------------------
command byte 0:    	 0   0   0   0   1   1   1   1
command byte 1:    	 ?   ?   ?   ?   ?  HD  US1 US0
command byte 2:    	new cylinder number

returns nothing

uPD765 Version          D7  D6  D5  D4  D3  D2  D1  D0
-------------------	------------------------------
command byte 0:    	 ?   ?   ?   1   0   0   0   0

result byte 0:	   	status register 0
                        90h = uPD765B
			80h = uPD765A or uPD765A-2

Invalid Command
-------------------	------------------------------
result byte 0:	   	status register 0 (value of 80h)


Key to Abbreviations
HD = Head Number Selected	SK = SKip Deleted-data address mark
MT = Multi-Track		US0 = drive select bit 0
MF = MFM mode			US1 = drive select bit 1
ND = Non-DMA mode
BPS = Bytes Per Sector:
	0=?				1=?
	2=512 bytes/sector		3=?

Head Load Time = 2 to 254ms in 2ms increments
Head Unload Time = 16 to 240ms in 16ms increments
Step Rate Time = 1 to 16ms in 1ms increments

- PS/2 systems use the 8272A diskette controller which is software
  and port compatible with the NEC uPD765
- accessed through ports 3F0h-3F7h;
  NEC uPD765 is accessed through ports 3F2h, 3F4h and 3F5h;
  the 8272A uses ports 3F0h, 3F1h, 3F2h, 3F4h, 3F5h and 3F7h
- data, command and status registers are all accessed through
  port 3F5h a register stack with one address presented to the bus
- bit 7 of BIOS Data Area byte 0040h:003Eh can be polled to determine
  if a BIOS disk operation has completed;  this bit is set by the
  interrupt handler when the operation has completed;  it should
  be reset before continuing on with the next FDC operation
