This post ended up being much longer than originally intended because halfway into writing it, I found that 286 and later CPUs don’t behave the way I had assumed they would…
While investigating a bug related to a program using floating-point math on a 386SX system with no FPU, I started pondering how exactly FPU detection works on 286 and newer CPUs. Although math co-processors became standard some 30 years ago, on old PCs they were an uncommon and expensive add-on, and a 66 MHz 486SX2 would still have a usable yet FPU-less processor in the mid-1990s.
The CPU/FPU interface and FPU detection on the 8086/8088 was discussed before. To recap, the 8086/8087 interface is a little odd because it is in fact a generic co-processor interface. The 8086 was launched in 1978; probably sometime in 1979, the Intel 8089 I/O Coprocessor arrived; the 8087 only appeared in 1980.
The ESC instruction (opcode range D8h-DFh) was used for communication with a co-processor on the 8086. While the CPU didn’t exactly execute the instruction, it had to know how to decode it. The ESC instruction used a standard ModR/M byte to indicate an optional memory operand, which the CPU needed to be able to write to or read from the co-processor.
If there is no co-processor attached to an 8086, the ESC instructions simply do nothing because the co-processor isn’t there to read or write any data. However, the WAIT instruction designed for synchronization will (in a typical 8088/8086 PC design) hang indefinitely because the missing co-processor acts as if it were permanently busy. For that reason, FPU detection must use the non-waiting FNINIT/FNSTSW sequence (or an equivalent) to avoid hangs on 8086-class machines.
Additional information about what things look like from the 8087’s perspective has been recently published.
Continue reading




