The 8087 has many instructions - too many, it seems, to be encoded as part of the 8086 instruction set. How did the Intel 8086 interface with an Intel 8087 FPU that a user added?

Consider the following x86 assembly code sample:

// c = a + b;
fld    DWORD PTR [rbp-0xc]  // a;
fadd   DWORD PTR [rbp-0x8]  // b;
fstp   DWORD PTR [rbp-0x4]  // c;

The instructions fld, fadd, and ftsp I assume are not hardwired into the 8086 circuit. So are they pseudo-instructions that the assembler subsequently converts to command/data instructions for the 8086 to pass onto the 8087 appropriately?

For example fld might be encoded as command 0 and for data the value of rbp-0xc is encoded which the 8087 would know is an address in memory holding the value it needs? And then a sequence of OUT instructions are used by the 8086 to send the command and data to the 8087?


The opcodes in your list are all only 16 bits (plus the extra bytes for address calculation) and you'll notice that they all begin (in hex) with Dx where x >= 8. This is because, to the 8086, any instruction whose first byte has the bit pattern 11011xxx was deemed to be an 8087 coprocessor instruction.

When the 8086 encountered a floating point opcode, it would do all the stuff to calculate the effective address and fetch the byte at that address and then it would just carry on.

Meanwhile the 8087 reads all the same instructions as the 8086 and when it encountered an instruction destined for it (i.e. that started with 11011xx), it would simply read the data bus at the right time to get the first byte i.e. when the 8086 was fetching the data. For multi-byte reads it would also read the address bus and then take control of the memory bus after the 8086 read cycle and read the remaining bytes pointed to by the address using direct memory access (DMA). For writes, it would ignore the data bus, read the address and then use DMA to write the data.

The only direct connections between the 8086 and 8087 were a few control lines, some to synchronise the prefetch queues of the 8086 and the 8087 - so the 8087 would know exactly when the 8086 was executing floating point instructions - and one so that the 8086 could tell when the 8087 had finished the last instruction and was ready for the next. There was a special instruction in the 8086 called wait that would simply cause the 8086 to wait until the 8087 signalled it was not busy on this line.

  • 2
    Maybe worth mentioning that some mnemonics for instructions that read x87 state bake in a wait. e.g. fstsw [bp-4] (store the status word, e.g. after an FP compare; then you'd load it into AX and use lahf to set up for a jp (unordered) or ja/jb or whatever). The manual felixcloutier.com/x86/fstsw:fnstsw lists the machine code as 9B DD /7 m2byte, where the 9B is a fwait instruction and the DD /7 is the actual fnstsw. (Yes there are fn... mnemonics for the no-wait version. On modern x86 with integrated x87 you don't need the fwait.) – Peter Cordes Feb 13 '19 at 7:13
  • 2
    @Peter re the last point, IIRC FWAIT isn’t necessary since the 286 (which checks its TEST line before executing an NPX instruction). Most assemblers will omit FWAITs if .287 or later is specified. – Stephen Kitt Feb 13 '19 at 8:45
  • 6
    11011 is the ESC (escape) instruction prefix, of which coprocessor instructions are a subset. The second byte of the instruction starts with 11 if it’s a non-memory instruction, and the usual mode field if it isn’t — that’s how the 8086 knows how to handle the instruction without knowing what it does, or who handles it. – Stephen Kitt Feb 13 '19 at 8:50
  • 2
    @glglgl there were, see this question. – Stephen Kitt Feb 13 '19 at 10:02
  • 2
    @hjf That is true for 486SX and 487. The latter is a fully-functional 486DX. But for 8086/7, no, that's not the case. – void_ptr Feb 13 '19 at 16:43

Your Answer

