So here I am, writing a bit of test code to figure out the behavior of x87 FPUs with regard to saving and loading the FPU state (FSTENV/FLDENV and FSAVE/FRSTOR instructions in different modes and formats).
The original real-mode only 8087 state format included the instruction and operand pointers as 20-bit linear addresses (because $REASONS) and also stored 11 bits of the floating-point (FP) opcode; the remaining five were always the ESC instruction.
The 287 also needed to be able to save the state in protected mode, with full segment and offset addresses. For whatever reason, Intel decided to keep the size of the saved FP environment (7 words); because the saved code and data pointer addresses used 32 bits each instead of 20, there was no longer room for the floating-point opcode. That wasn’t a huge deal because the opcode could be fished out of memory.
When the 387 came out, it naturally needed to support 32-bit state, with 16-bit segments and 32-bit offsets. Instead of 7 words, the 32-bit state was extended to 7 dwords, with extra padding in reserved fields.
I was pretty sure the floating-point opcode is there somewhere in the 32-bit protected-mode state, but needed a reminder as to where exactly. I happened to have Agarwal’s 80×86 Architecture & Programming, Volume II (1991) open on a nearby page, so I looked there first. On page 240, there’s a diagram of the 32-bit protected-mode FPU state format. But no FP opcode. Odd.
The next closest book was Hummel’s PC Magazine Programmer’s Technical Reference: The Processor and Coprocessor (1992). On page 696, documenting the FSTENV/FNSTENV instruction, there’s the saved state diagram. But again, no floating-point opcode! Is my memory that bad? (Rhetorical question, don’t answer!)
Desperate, I checked the latest Intel SDM and ascertained that no, my memory is not that bad. The 32-bit protected-mode floating-point environment does store the floating-point opcode. But then how is it that two randomly chosen but usually accurate references don’t list it?
Maybe it was missing in the 486 datasheets? No… it’s always been there. Could it have been missing in the 387 datasheets? I had the Intel 231920-003 datasheet from October 1987 (80387 80-BIT CHMOS III Numeric Processor Extension) on hand, but no luck, so to speak… the floating-point opcode was right there (at offset 12h).
But if it’s always been there in Intel documents, why was it missing in two different third party references? If it were just one, I’d chalk it up to a simple error, but two? That can’t be a coincidence. So I dug deeper.
Eventually I located an earlier Intel 231920-002 datasheet from January 1987. And guess what… the FP opcode was not there!
The change is even clearly documented right there in the revision history section of the newer 231920-003 datasheet:
- Figure 2.3 was updated with the addition of a new opcode field to the 32-bit protected mode format. The opcode field facilitates easier error recovery for numeric operation in protected mode.
It’s now clear that the FP opcode field was not part of the 32-bit protected-mode FPU state in the original 80387 specification. But it was (very reasonably) added at some point in 1987, almost certainly before any 80387s started shipping.
Somehow or other, the outdated Intel documentation became the basis of third-party documents. And so, in 1992, Hummel’s book still does not list the FP opcode field, five years after it had been added to the 387.