The DOS Floppy Controller State Machine: Command, Execution, Result
Operate a 765-compatible floppy controller with phase-aware FIFO handling, DMA discipline, result-byte checks, and bounded recovery.
A floppy disk controller (FDC) is not a synchronous sector API. A 765-compatible controller accepts a command and parameter bytes, enters an execution phase that transfers data to or from the medium, and later exposes a result phase with status and address information. A DOS driver that treats the controller as “write a command, then read a sector” will eventually mis-handle a timeout, a DMA boundary, a disk change, or a command that returns more result bytes than expected.
The Intel 82077 documentation describes the command, execution, and result phases directly. The exact controller and board wiring still matter: ISA DMA channel, IRQ, motor-control bits, data rate, and enhanced-controller features differ by machine. Use this article as a protocol model, not as permission for an application to bypass an existing diskette driver.
Phase one: command bytes and parameters
The controller’s main status register (MSR) reports whether the FIFO can accept or return data and in which direction. Before writing a command byte or parameter, the driver checks that the controller is ready for host-to-controller data. Before reading a result byte, it checks that the FIFO is ready in the reverse direction. The RQM and DIO bits are phase indicators; a fixed delay after every byte is not a replacement for reading the controller’s current state.
The command byte includes operation flags, and subsequent parameter bytes encode drive/head selection, cylinder, head, sector, size code, end-of-track, gap, and data length according to that command. A read command and a write command have different data directions. A format command has its own parameter structure and is destructive. Build a complete parameter list from the controller manual, validate the drive and geometry, and do not send extra bytes once the controller has transitioned out of command phase.
An MSR polling loop must be bounded. If the controller never reports ready, preserve the last MSR value, operation, drive, and elapsed time; then enter the documented reset/recalibration path. A loop that spins forever can hide a disconnected controller, wrong I/O base, failed reset, or a driver that never drained a prior result phase.
Phase two: execution and data movement
In DMA mode, the controller raises its data-request signal and the DMA controller moves bytes between the FDC FIFO and host memory. The CPU still owns setup and completion: it configures the DMA channel, address, direction, count, and page register, then starts the FDC command and waits for the operation’s interrupt or bounded status transition. The DMA transfer count and FDC byte count must agree. For ISA DMA, the buffer must satisfy the channel’s address-width and boundary requirements; use a verified bounce buffer when ordinary DOS memory cannot meet them.
In non-DMA mode, the CPU services FIFO requests through the data register. The timing budget is much tighter because each byte needs host intervention. The FDC’s non-DMA execution phase may return to command/result handling differently from DMA mode, so do not reuse a DMA completion routine without checking the controller’s non-DMA status. A driver should use one transfer model per command and record which mode it chose.
The physical medium adds additional completion delays: motor spin-up, head settle, seek, track change, and data separation. A command accepted by the FDC is not proof that the requested sector was read or written. The driver may need motor control, recalibration, seek, and correct data-rate selection before issuing the transfer. Each step needs a separate status check and bounded timeout.
DMA and non-DMA operation also differ in how transfer termination is observed. In DMA mode, the controller can continue draining or filling its internal FIFO after the host DMA controller moves the nominal count; the driver must follow the controller’s timing and interrupt behavior and not assume the DMA terminal-count event supplies all FDC result bytes. In non-DMA mode, the MSR’s non-DMA indication changes the expected service pattern. These details are why a driver must use the exact controller variant’s programming sequence rather than copying one 765 routine into every clone.
The drive-output register is not merely a motor switch. It can select drive lines, control reset, and enable the controller/IRQ path. Changing it without preserving other bits can reset the controller or disable another drive. Some later controllers also expose a data-rate select register; the expected value depends on the drive and media. Record board-level choices in driver configuration rather than scattering port constants through a read routine.
Phase three: drain and interpret the result
For a completed data command, the interrupt signals the beginning of the result phase on controllers following this interface. The driver must read the defined result bytes before issuing another command. A common data result returns status bytes ST0, ST1, and ST2, followed by cylinder, head, sector, and size information. The exact count is command-specific. Reading too few bytes leaves the controller in result phase; issuing a new command too early can cause an overrun or an invalid sequence.
Preserve the result bytes before resetting. ST0 carries unit, head, interrupt-code, and seek-end/error information; ST1 and ST2 expose conditions such as missing address marks, write protection, CRC/data errors, no data, or track/overrun conditions. Interpret the bits together with the command and returned address. A success-looking interrupt without the expected result phase is not enough to declare success.
Do not equate a completed command with valid data. For reads, check the controller result and validate the caller’s buffer before exposing its contents. For writes, a timeout or error after data transfer can leave a sector partially or fully modified. Do not automatically retry destructive format/write requests without determining whether the first operation reached media and whether retry is safe.
DMA, IRQ, and ownership boundaries
A production driver coordinates the FDC with the DMA controller and interrupt controller, which are separate devices. The FDC’s interrupt route is board-specific; the DMA channel has direction, address, count, and boundary constraints. A correct controller phase machine can still corrupt memory if the DMA page or count is wrong. Use explicit ownership of IRQ and DMA resources and restore any shared configuration when unloading a driver.
On a system already running DOS, a BIOS diskette call or DOS block-device call should ordinarily be used instead of direct FDC access. The floppy driver owns motor state, media-change reporting, diskette parameter tables, DMA, IRQ, retries, and cache coherence. Another resident component can be interrupted by your command even when the ports seem idle. Direct commands are appropriate only when the application is the driver or the machine is otherwise under exclusive control.
Recovery and measurable checks
Separate reset, recalibrate, seek, and data-command failures in logs. Capture the MSR at timeout, result bytes, selected drive/head, command flags, DMA address/count, interrupt number, motor state, and the detected disk geometry. A reset should be bounded and followed by a known initialization sequence; it is not a universal way to make an invalid command valid.
Test no drive, no media, wrong data rate, write-protected media, end-of-track, CRC error, DMA-boundary rejection, and a deliberately incomplete command/result sequence in an emulator or sacrificial test disk. Confirm that every command drains its documented result bytes, every wait terminates, DMA never crosses an invalid boundary, and the recovery path does not silently convert an error into a successful read.
The FDC protocol becomes understandable when each command is treated as a transition across three explicit phases. MSR state governs byte direction, execution may involve DMA or tight PIO service, and the result phase must be drained and interpreted. Keep diskette controller ownership with the driver, honor DMA constraints, and report the specific phase that failed.
Also test that an error in one phase does not leave the next request consuming leftover FIFO bytes. Inject a timeout while sending parameters, during execution, and while reading results. After recovery, issue a benign status or recalibrate operation and confirm the controller returns to a known state. A harness should track expected command, parameter, transfer, and result byte counts and flag any phase that reads or writes more or less than expected.
Related:
- ISA DMA on DOS PCs: Page Boundaries, Address Units, and Safe Buffers
- How to Test a FreeDOS Monthly Test Release Without Risking Your Main Installation
Sources: