On modern processors the x87 FPU is integrated in the CPU chip, but it used to be a separate chip before the 80486. So is there any way to detect its presence, and maybe even its generation (8087, 80187 etc)?
The documented way to detect an x87 FPU is to attempt to initialise it, and then read its control word (
FPU_STATUS must be set to some non-zero value first):
FNSTSW WORD PTR [FPU_STATUS]
This uses the non-waiting variants, otherwise the CPU will wait for a non-existent FPU to respond. If the status word is not 0 after this, no FPU is installed — the FPU socket is supposed to be wired in such a way that at least one of the lower eight bits of the status word floats high when no FPU is installed. (The iAPX 286 Programmer’s Reference Manual has details, in chapter 3 of the Numeric Supplement.)
To check that the FPU is actually communicating, detection routines typically then try to write the control word.
If an FPU is detected, determining its generation involves two main scenarios. In some cases the FPU generation has to match the installed CPU type, so detection boils down to identifying the CPU: if it’s an 8086 or 8088, the FPU is an 8087; if it’s a 186 or 188, the FPU is a 187; if it’s a 486, the FPU is built-in or the system is running on a 487SX. In other cases FPU features need to be used; the 286 and 386 can be paired with either a 287 or a 387 (in the guise of a 287XL on 286s and some 386s), and distinguishing these can be done by comparing positive and negative infinities — the 287 says they’re equal, the 287XL and 387 (and 187) say they’re different. (Thanks to mnem for the reminder!)
It is also possible to detect different FPUs by checking for other variations in behaviours. TMI0SDGL includes sample code which shows how to do this. This would also be required to detect more capable clones of the Intel FPUs — some IIT FPUs added registers and instructions, and some Cyrix FPUs had more precise transcendental implementations.
Note that FPU emulators on 286 and later CPUs, such as EM87 or Q387, can fool the detection procedure shown above; but in such cases the EM bit of the machine status word is set, so it is still possible to distinguish between an emulator and an FPU (without resorting to timing measurements).
COPRO16A.TXT, “Everything you always wanted to know about math coprocessors”, goes into much more detail about all this. His
COMPTEST program includes detection source code for CPUs and FPUs (in
CCNEW.ASM, with detailed explanations in
COMPTEST.DOC), capable, like TMI0SDGL, of distinguishing between specific FPU models (Intel, Cyrix, IIT, C&T FPUs, and emulators).
All this ignores the Weitek 3167 and 4167 coprocessors, which are very different both in terms of their interface with the CPU and in terms of their instruction sets.