assemblyx86x86-16machine-codeinstruction-encoding

What are 8086 ESC instruction opcodes


Mostly of a historical interest and if I were to implement 8086 compatibility for assembler, what operands are considered valid for ESC instruction?

ESC opcode, source

From 8086 Programmer's manual I know, that opcode is an immediate in range 0 to 63 and source is a register or memory. But what registers can be encoded? Both reg8 and reg16 or only reg16? If source is memory, does operand size (mem8 or mem16) matter?

Basically, both of the above don't really matter from instruction encoding perspective (as, for example, both esc 0x01, ch and esc 0x01, bp would produce the same result), but maybe assemblers had forced restrictions

And, the last, but not the least, where can I find description for ESC opcodes?


Solution

  • The 8086 has an opcode space collectively designated ESC (escape to coprocessor). It occupies the range d8 to df. Each instruction in this instruction space is followed by a modr/m byte and depending on the mod-field, zero to two displacement bytes. When the 8086 encounters an ESC instruction with two register operands (i.e. mod = 11), it performs a nop. When the processor encounters an ESC instruction with a memory operand, a read cycle is performed from the address indicated by the memory operand and the result is discarded.

    Using two special signal lines, a coprocessor can distinguish data fetches from instruction fetches, allowing it to decode the instruction stream in parallel with the 8086.

    This mechanism is used by the 8087 to hook into the instruction stream: The three available bits in the opcode byte together with the three bits of the reg field in the modr/m byte form a six bit opcode. The r/m field of the modr/m byte is used to designate either a location on the FPU register stack (if mod = 11, indicating two register operands) or a memory operand. Some opcodes encode a variety of instructions depending on the content of r/m field. In all these cases, one instruction is encoded for memory operands while eight other instructions are encoded for each possible register operand.

    The 8087 registers when the 8086 performs the dummy fetch immediately after fetching the instruction and remembers the address. In case of an instruction that loads from memory, it loads the additional words of the memory operand and performs its function. In case of a store, it ignores the result of the fetch and stores its values to the address indicated by the 8086.

    The 8087 performs operation asynchronously to the 8086. However, no implicit synchronization exists. If an attempt is made to issue an ESC instruction while the coprocessor is busy, the instruction is silently ignored. To solve this problem, the 8087 asserts its BUSY pin (connected to the 8086's TEST pin) while performing operation. The programmer can issue a wait instruction (9b, wait for coprocessor ready) to wait until the 8087 has concluded operation and consequently released the WAIT line. This is typically done before every single 8087 instruction and many assemblers of the day would automatically insert WAIT prefixes. For high performance code, it was also common to instead manually calculate how long the 8087 was going to take for a certain instruction and to omit the wait when the previous floating point instruction was guaranteed to have finished.