This is an HTML-ized version of the opcode map for the 8086 processor. It is based on the opcode map from Appendix A of Volume 2 of the Intel Architecture Software Developer's Manual. A plain-text version - easily parsable by software - is also available.
This map was constructed by taking a map for a more recent x86 processor and removing information irrelevant to the (much earlier) 8086 processor. I wanted as simple a map as possible, and, to that end, this map contains some lacunae:
In addition to the information that was removed, this map contains two known errors. These were added intentionally so that the results of disassembly based upon this map would mirror the output of DOS DEBUG:
To use the map, find the cell in the row labelled with the opcode's most significant 4 bits, and the column labelled with the opcode's least significant 4 bits. (The map is split in half; columns 0-7 appear in the first part, while columns 8-F appear in the second.) For instance, opcode 23 appears in the 3rd row, 4th column of the first part of the map (AND Gv, Ev). Opcode 4E appears in the 5th row, 7th column of the second part of the map (DEC SI).
Arguments are either a pair of letters - the first in upper case, the second in lower case - or a special symbol. An upper case/lower case pair can be interpreted by looking up the upper case letter in the "Argument Addressing Codes" table, and the lower case letter in the "Argument Operand Codes" table. Other special symbols can be looked up in the "Special Argument Codes" table.
Continuing the earlier example, opcode 23 resolves to an AND Gv, Ev instruction. Both arguments are upper case/lower case pairs. G represents a general-purpose register selected by the reg bits of a ModR/M byte following the opcode byte. E represents a memory location or general-purpose register selected by the mod and r/m bits of a ModR/M byte following the opcode byte. Both operands are of type "v", so both are WORDs. Opcode 23, therefore, takes the logical AND of a WORD from a 16-bit register or memory location with the WORD from a 16-bit register, and stores the result to the latter register. The particular register(s) and/or memory location involved can be determined by examining the ModR/M byte following the opcode, and consulting page 2-5 of the Instruction Set Reference.
Opcode 4E, on the other hand, resolves to a DEC SI instruction. The SI argument is not an upper case/lower case pair, so we check the special code table. SI turns out to represent (as one might expect) the 16-bit SI register, so opcode 4E simply decrements this register by 1. (Yes, with nearly 30 years hindsight, there probably shouldn't be an entire opcode devoted to this operation.)
The one remaining complexity involves "group" opcodes, such as 80. These opcodes perform different operations depending upon the value of the reg bits in the ModR/M byte following the opcode byte. For example, opcode 80 followed by a ModR/M byte with a reg of 4 is an AND Eb, Ib instruction, while that same opcode followed by a ModR/M byte with a reg of 7 is a CMP Eb, Ib instruction.
To disassemble "group" opcodes, consult the "Opcode Extensions" table for any entry in the opcode map with a mneumonic of the form GRP#. Find the entry in the row labelled with the mneumonic and the column labeled with the value of the reg field of the ModR/M byte following the opcode byte. Note that arguments may be specified in both the opcode map and the opcode extensions table (e.g. for opcode F6, reg 0); if this occurs, the entries in the extensions table take precedence. Normally, however, the arguments from the opcode map are used.
As far as I know, this opcode map is, modulo the lacunae and errata mentioned above, correct. I've used it to implement a full 8086 integer disassembler, the results of which agree with DOS DEBUG. However, if you see something that doesn't look right, please contact me. If you're interested in reading more about the disassembler, the following posts might be worth a look:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
0 |
ADD |
ADD |
ADD |
ADD |
ADD |
ADD |
PUSH |
POP |
1 |
ADC |
ADC |
ADC |
ADC |
ADC |
ADC |
PUSH |
POP |
2 |
AND |
AND |
AND |
AND |
AND |
AND |
ES:
|
DAA
|
3 |
XOR |
XOR |
XOR |
XOR |
XOR |
XOR |
SS:
|
AAA
|
4 |
INC |
INC |
INC |
INC |
INC |
INC |
INC |
INC |
5 |
PUSH |
PUSH |
PUSH |
PUSH |
PUSH |
PUSH |
PUSH |
PUSH |
6 |
|
|
|
|
|
|
|
|
7 |
JO |
JNO |
JB |
JNB |
JZ |
JNZ |
JBE |
JA |
8 |
TEST |
TEST |
XCHG |
XCHG |
||||
9 |
NOP
|
XCHG |
XCHG |
XCHG |
XCHG |
XCHG |
XCHG |
XCHG |
A |
MOV |
MOV |
MOV |
MOV |
MOVSB
|
MOVSW
|
CMPSB
|
CMPSW
|
B |
MOV |
MOV |
MOV |
MOV |
MOV |
MOV |
MOV |
MOV |
C |
|
|
RET |
RET
|
LES |
LDS |
MOV |
MOV |
D |
AAM |
AAD |
|
XLAT
|
||||
E |
LOOPNZ |
LOOPZ |
LOOP |
JCXZ |
IN |
IN |
OUT |
OUT |
F |
LOCK
|
|
REPNZ
|
REPZ
|
HLT
|
CMC
|
8 | 9 | A | B | C | D | E | F | |
0 |
OR |
OR |
OR |
OR |
OR |
OR |
PUSH |
|
1 |
SBB |
SBB |
SBB |
SBB |
SBB |
SBB |
PUSH |
POP |
2 |
SUB |
SUB |
SUB |
SUB |
SUB |
SUB |
CS:
|
DAS
|
3 |
CMP |
CMP |
CMP |
CMP |
CMP |
CMP |
DS:
|
AAS
|
4 |
DEC |
DEC |
DEC |
DEC |
DEC |
DEC |
DEC |
DEC |
5 |
POP |
POP |
POP |
POP |
POP |
POP |
POP |
POP |
6 |
|
|
|
|
|
|
|
|
7 |
JS |
JNS |
JPE |
JPO |
JL |
JGE |
JLE |
JG |
8 |
MOV |
MOV |
MOV |
MOV |
MOV |
LEA |
MOV |
POP |
9 |
CBW
|
CWD
|
CALL |
WAIT
|
PUSHF
|
POPF
|
SAHF
|
LAHF
|
A |
TEST |
TEST |
STOSB
|
STOSW
|
LODSB
|
LODSW
|
SCASB
|
SCASW
|
B |
MOV |
MOV |
MOV |
MOV |
MOV |
MOV |
MOV |
MOV |
C |
|
|
RETF |
RETF
|
INT |
INT |
INTO
|
IRET
|
D |
|
|
|
|
|
|
|
|
E |
CALL |
JMP |
JMP |
JMP |
IN |
IN |
OUT |
OUT |
F |
CLC
|
STC
|
CLI
|
STI
|
CLD
|
STD
|
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
ADD
|
OR
|
ADC
|
SBB
|
AND
|
SUB
|
XOR
|
CMP
|
|
ROL
|
ROR
|
RCL
|
RCR
|
SHL
|
SHR
|
|
SAR
|
|
TEST |
|
NOT
|
NEG
|
MUL
|
IMUL
|
DIV
|
IDIV
|
|
TEST |
|
NOT
|
NEG
|
MUL
|
IMUL
|
DIV
|
IDIV
|
|
INC
|
DEC
|
|
|
|
|
|
|
|
INC
|
DEC
|
CALL
|
CALL |
JMP
|
JMP |
PUSH
|
|
Direct address. The instruction has no ModR/M byte; the address of the operand is encoded in the instruction. Applicable, e.g., to far JMP (opcode EA). |
|
A ModR/M byte follows the opcode and specifies the operand. The operand is either a general-purpose register or a memory address. If it is a memory address, the address is computed from a segment register and any of the following values: a base register, an index register, a displacement. |
|
The reg field of the ModR/M byte selects a general register. |
|
Immediate data. The operand value is encoded in subsequent bytes of the instruction. |
|
The instruction contains a relative offset to be added to the address of the subsequent instruction. Applicable, e.g., to short JMP (opcode EB), or LOOP. |
|
The ModR/M byte may refer only to memory. Applicable, e.g., to LES and LDS. |
|
The instruction has no ModR/M byte; the offset of the operand is encoded as a WORD in the instruction. Applicable, e.g., to certain MOVs (opcodes A0 through A3). |
|
The reg field of the ModR/M byte selects a segment register. |
Byte argument. Unusual in that arguments of this type are suppressed in ASM output when they have the default value of 10 (0xA). Applicable, e.g., to AAM and AAD. |
|
Byte argument. |
|
32-bit segment:offset pointer. |
|
Word argument. |
|
Word argument. (The 'v' code has a more complex meaning in later x86 opcode maps, from which this was derived, but here it's just a synonym for the 'w' code.) |
8-bit register: The low byte of AX |
|
8-bit register: The low byte of CX |
|
8-bit register: The low byte of DX |
|
8-bit register: The low byte of BX |
|
8-bit register: The high byte of AX |
|
8-bit register: The high byte of CX |
|
8-bit register: The high byte of DX |
|
8-bit register: The high byte of BX |
|
16-bit register: The 'accumulator' register |
|
16-bit register: The 'counter' register |
|
16-bit register: The 'data' register |
|
16-bit register: The 'base' register |
|
16-bit register: The 'stack pointer' register |
|
16-bit register: The 'base pointer' register |
|
16-bit register: The 'source index' register |
|
16-bit register: The 'destination index' register |
|
16-bit register: The 'extra' segment register |
|
16-bit register: The 'code' segment register |
|
16-bit register: The 'stack' segment register |
|
16-bit register: The 'data' segment register |
|
A constant argument of 1, implicit in the opcode, and not represented elsewhere in the instruction. This argument *is* displayed in assembly code. |
|
A constant argument of 3, implicit in the opcode, and not represented elsewhere in the instruction. This argument *is* displayed in assembly code. |
|
The ModR/M byte refers to a memory location, however the contents of that memory location are irrelevant; the address itself is the operand of the instruction. Applicable, e.g., to LEA. |