• Please review our updated Terms and Rules here

8087/8 Behavior on Decode Failure

cr1901

Veteran Member
Joined
Dec 28, 2011
Messages
817
Location
NJ
According to the Wikipedia page for the 8087, the coprocessor may potentially crash an XT-class machine if it's given an undefined opcode.

According to an earlier thread here, the 8087 in practice executes a NOP if it finds the 0xD8 escape code sequence. Because assemblers in practice will add FWAIT after floating point instructions, I assume that the reason a crash might occur is one of two reasons:

  1. Bus contention due to the FPU executing garbage as the 8088 continues processing.
  2. The FPU never signaling that it's "done" via NMI (which makes making sure NMI is enabled vital!).

Can anyone confirm whether either of the two above reasons are correct? What makes it so the same thing doesn't happen if a 287 or 387 gets a bad instruction? How does the processor know to ignore it and continue without contention (due to a bad opcode making the 2/387 execute garbage) occurring?
 
Your conclusions are not correct :)

1. 8087 synchronizes its bus accesses with 8086/88 using a bus arbitration protocol (RQ/GT signals).
2. The "done" condition is signaled by de-asserting BUSY/TEST pin. That is the pin that WAIT instruction monitors (FWAIT and WAIT is the same instruction).

Now regarding your references:
Wikipedia - the key words are "may potentially". I don't see any examples. But it shouldn't be difficult to test given an 8088 computer with 8087 coprocessor.
Older thread - it discusses why it is possible to implement x87 software emulation on 286/386 but not on 8086/88. And the reason is that 286/386 processors implement an EM (emulation) bit in MSW/CR0, and if this bit is set when decoding ESC instruction the processor will execute INT 7 instead of trying to communicate to the NPU. The x87 emulation software processes this interrupt and emulates the x86 functionality. Now I don't think that feeding the NPU an invalid opcode will result in CPU's "Invalid Opcode" exception, instead the NPU will generate an "Invalid Operation" error.

BTW ESC instruction on 8086/88 is not exactly NOP. 8086/8088 will actually decode it and if the mode in the second byte of the instruction is a memory mode, it will calculate the effective address and put it on the address bus. The 8087 will read this address from the address bus, and use it for FLD*/FST* instructions.
 
Last edited:
Can anyone confirm whether either of the two above reasons are correct? What makes it so the same thing doesn't happen if a 287 or 387 gets a bad instruction? How does the processor know to ignore it and continue without contention (due to a bad opcode making the 2/387 execute garbage) occurring?

This seems somewhat related to the problem I had with OpenWatcom earlier: http://www.vintage-computer.com/vcf...-9-built-binaries-lock-up-on-8088-without-FPU
I found out that fwait will indeed lock up an XT-class machine forever if there is no FPU to signal that it is done.
So, at least reason 2 seems valid: If there are any circumstances where the FPU does not signal 'done', even though it is present, the fwait instruction will likely wait forever, and lock the machine.
Whether there actually is such a circumstance, I do not know.

Why does it not happen with 287 or higher? Well, for the simple reason that fwait doesn't lock the CPU indefinitely. The interface between CPU and FPU is different, and the FWAIT-instruction is not used for sync, it is done in the ESC byte itself, which is processed by the CPU.
See more background info here: http://www.openwatcom.org/index.php/Math_Coprocessor_Interface_Evolution
 
I found out that fwait will indeed lock up an XT-class machine forever if there is no FPU to signal that it is done.

That's correct. So the program needs to make sure that 8087 coprocessor is present before trying to execute WAIT/FWAIT instructions. You could either use INT 11h / Equipment check, or run a short program (that does not use WAIT instructions) to check that 8087 is present. E.g. do FNINIT, wait a bit, do FNSTCW and check if the returned control word equals to 3FFh.
 
run a short program (that does not use WAIT instructions) to check that 8087 is present. E.g. do FNINIT, wait a bit, do FNSTCW and check if the returned control word equals to 3FFh.

I grabbed the code from an old Intel manual, which does FNINIT/FNSTSW, which apparently does not need a delay, other than the mov they put in between there, so no bytes wasted, just clever organizing of code.
Detection routine can be found here: https://sourceforge.net/p/cpuinfo/code/ci/default/tree/CPUInfo.c (see GetFPU()).
There's some more code to determine which class of FPU it is.
In most cases, the FPU matches the CPU family. The 386 is an exception to the rule though, since you can actually put a 287 into a 386 machine.
So there is code to check whether you have a 287 or 387, if a 386 CPU is detected.
 
You can also put a 387 in an 286 machine by using the 287XL.

Even up till quite recently, the IA-86 manuals from Intel has mentioned how bad of an idea it was to connect the FPU interrupt signal through the NMI, and how all CPUs since the 486DX are stuck with a masked NMI due to the need for PC-compability.
 
Last edited:
I grabbed the code from an old Intel manual, which does FNINIT/FNSTSW, which apparently does not need a delay, other than the mov they put in between there, so no bytes wasted, just clever organizing of code.
Good to know, I can save a few bytes in my BIOS :)
In most cases, the FPU matches the CPU family.
Except when it doesn't :) 80286XL and 80C187 are based on 80387 design.
 
I grabbed the code from an old Intel manual, which does FNINIT/FNSTSW, which apparently does not need a delay, other than the mov they put in between there, so no bytes wasted, just clever organizing of code.[/qutoe]

Yup, that's the way I did it back in the 80s when I was doing the math pack for a spreadsheet. This had to work over a wide range of semi-compatibles, so you couldn't depend on the Equipment Check service. (Anyone remember SuperCalc? )
 
Back
Top