Minor 387 Documentation Mystery

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).

231920-003 datasheet, Oct 1987

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!

231920-002 datasheet, Jan 1987

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.

This entry was posted in Documentation, Intel, x87. Bookmark the permalink.

6 Responses to Minor 387 Documentation Mystery

  1. Richard Wells says:

    The critical question was whether the field was there before being documented. Intel was always willing to conceal behavior that no programmer needed to be concerned about but sometimes Intel documented a change while not mentioning its lack in earlier iterations of ostensibly the same chip.

  2. Michal Necasek says:

    Good question. I have not been able to pin down exactly when the 387 started shipping; it was probably sometime in the second half of 1987. It is likely that the old (Jan ’87) datasheet does not apply to production units, so finding 387s to test could be really difficult.

    But it has also occurred to me that the 387 may have always behaved the same, and the documentation was simply updated to match existing chip behavior. The datasheet revision text isn’t explicit about whether it’s a documentation change or a hardware change. Later on, Intel was usually clear about what’s a documentation change and what’s a hardware change.

  3. SweetLow says:

    Do I remember it right – on modern processors it is the opcode of the last FPU command with exception but can be switched to the old behavior (the last non control FPU command).

  4. Michal Necasek says:

    My notes say that P4s (at least some) could control the opcode tracking (always vs exceptions only) in IA32_MISC_ENABLE MSR. Newer Intels just do it on exceptions only, there’s no switch anymore. I guess they found that in practice, only exception handlers look at the FP opcode.

    Which sounds reasonable to me — while it is trivial to write code that checks the FP opcode after each FP instruction, I don’t think anything besides an exception handler needs to look at it.

  5. SweetLow says:

    >My notes say that P4s
    Thank, so I remember everything almost right, except that the processors are not quite modern (or not modern at all from other point of view).

  6. SweetLow says:

    >My notes say that P4s
    Thank, so I remember everything almost right, except that the processors are not quite modern (or not modern at all from other point of view).

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.