6.2.3 Coordinating Memory Access

The math coprocessor works simultaneously with the main processor. However, since the coprocessor cannot handle device input or output, data originates in the main processor.

Summary: The processor and coprocessor exchange data through memory.

The main processor and the coprocessor have their own registers, which are completely separate and inaccessible to each other. They usually exchange data through memory, since memory is available to both.

When using the coprocessor, follow these three steps:

1.Load data from memory to coprocessor registers.

2.Process the data.

3.Store the data from coprocessor registers back to memory.

Step 2, processing the data, can occur while the main processor is handling other tasks. Steps 1 and 3 must be coordinated with the main processor so that the processor and coprocessor do not try to access the same memory at the same time; otherwise, problems of coordinating memory access can occur. Since the processor and coprocessor work independently, they may not finish working on memory in the order in which you give instructions. Two potential timing conflicts can occur; they are handled in different ways.

One timing conflict results if a coprocessor instruction follows a processor instruction. The processor may have to wait until the coprocessor finishes if the next processor instruction requires the result of the coprocessor's calculation. You do not have to write your code to avoid this conflict, however. The assembler coordinates this timing automatically for the 8088 and 8086 processors, and the processor coordinates it automatically on the 80186–80486 processors. This is the first case shown in the example later in this section.

Another conflict results if a processor instruction that accesses memory follows a coprocessor instruction that accesses the same memory. The processor can try to load a variable that is still being used by the coprocessor. You need careful synchronization to control the timing, and this synchronization is not automatic on the 8087 coprocessor. For code to run correctly on the 8087, you must include the WAIT or FWAIT instruction (they are mnemonics for the same instruction) to ensure that the coprocessor finishes before the processor begins, as shown in the second example. In this situation, the processor does not generate the FWAIT instruction automatically.

; Processor instruction first - No wait needed

mov WORD PTR mem32[0], ax ; Load memory

mov WORD PTR mem32[2], dx

fild mem32 ; Load to register

; Coprocessor instruction first - Wait needed (for 8087)

fist mem32 ; Store to memory

fwait ; Wait until coprocessor

; is done

mov ax, WORD PTR mem32[0] ; Move to register

mov dx, WORD PTR mem32[2]

When generating code for the 8087 coprocessor, the assembler automatically inserts a WAIT instruction before the coprocessor instruction. However, if you use the .286 or .386 directive, the compiler assumes that the coprocessor instructions are for the 80287 or 80387 and does not insert the WAIT instruction.

If your code does not need to run on an 8086 or 8088 processor, you can make your programs shorter and more efficient by using the .286 or .386 directive.