The 8086's instruction set is the seed crystal of the entire x86 instruction set. Master it and you can read most modern x86 assembly with a chapter of additions in your head.
2.1 The assembly toolchain
source.asm ─[ MASM / NASM / TASM ]─→ source.obj
│
[ LINK ]
▼
program.exe ──→ DOS / DOSBox / BIOSThe flow: write a .asm source file, assemble (nasm -f obj source.asm or masm /c source.asm) into an .obj, link (link source.obj) into an .exe, run on DOS or in a DOSBox emulator. Real PCs cannot natively run 8086 binaries today (they boot in long mode), but DOSBox is a clean emulator and is excellent for learning.
2.2 Instruction set categories
Data transfer. Move bytes and words between registers, memory, and I/O.
MOV dst, src— copy. The most-used instruction by far.PUSH src,POP dst— to and from the stack.XCHG a, b— swap.IN AL, port,OUT port, AL— read/write I/O port.LEA reg, mem— load effective address (the computed address itself, not the value at the address). Useful for pointer arithmetic.
Arithmetic.
ADD dst, src,ADC dst, src(add-with-carry, used to chain multi-precision adds).SUB,SBB.INC,DEC— by 1, no flags-write of CF.MUL src— unsigned multiply: AX = AL × src (8-bit), or DX:AX = AX × src (16-bit). Result is wider than operands.IMUL src— signed multiply.DIV src— unsigned divide: AX/src → quotient AL, remainder AH (8-bit); or DX:AX/src → quotient AX, remainder DX (16-bit).IDIV src— signed divide. Beware: dividing by zero, or producing a quotient too large to fit, fires interrupt 0.NEG dst— two's-complement negate.CMP a, b— compute a−b, set flags, discard result. Used before conditional jumps.
Logical.
AND,OR,XOR,NOT.TEST a, b— like AND but discard result; used to test bits.SHL/SHR— shift left/right (logical).SAL/SAR— shift arithmetic (preserves sign on right shift).ROL/ROR/RCL/RCR— rotate (with or without carry).
String. The 8086 has dedicated string-operation instructions that work on byte/word arrays at DS:SI (source) and ES:DI (destination), automatically incrementing or decrementing the indices based on the DF flag.
MOVS— copyDS:[SI]toES:[DI], advance both.CMPS— compare two strings.SCAS— scan for a byte/word matching AL/AX.LODS— load fromDS:[SI]into AL/AX.STOS— store AL/AX toES:[DI].REP/REPE/REPNE— repeat prefix; runs the string instruction CX times (or until ZF condition).
So REP MOVSB with CX=100 copies 100 bytes — memcpy in two assembly instructions.
Branch / control flow.
JMP target— unconditional. Can be near (within segment) or far (to another segment).- Conditional:
JE/JZ(equal/zero),JNE/JNZ,JG/JNLE(signed greater),JL/JNGE,JA/JNBE(unsigned above),JB/JC,JS/JNS(sign),JO/JNO(overflow),JP/JNP(parity). About 30 mnemonics, all really six bits of flag-test. LOOP target— decrement CX, jump if non-zero.LOOPE/LOOPNE— extra ZF condition.CALL target— push return address, jump.RET— pop return, jump.INT n— software interrupt.IRET— return from interrupt.
Processor control.
STC/CLC— set/clear CF.STI/CLI— set/clear IF (enable/disable interrupts).STD/CLD— set/clear DF.NOP— do nothing for one instruction (actuallyXCHG AX, AX).HLT— halt until next interrupt.
2.3 Addressing modes
The 8086 has eight addressing modes. The compiler/assembler chooses based on how you write the operand.
| Mode | Example | Effective address |
|---|---|---|
| Immediate | MOV AX, 1234h | (operand is the value 1234h) |
| Register | MOV AX, BX | (operand is in BX) |
| Direct | MOV AX, [1000h] | DS:1000h |
| Register indirect | MOV AX, [BX] | DS:BX |
| Based | MOV AX, [BX+10h] | DS:(BX+10h) |
| Indexed | MOV AX, [SI] | DS:SI |
| Based indexed | MOV AX, [BX+SI] | DS:(BX+SI) |
| Based indexed + disp | MOV AX, [BX+SI+10h] | DS:(BX+SI+10h) |
A few notes. The base register can be BX or BP (where BP defaults to SS instead of DS — useful for stack frames). The index register can be SI or DI. The displacement is an 8-bit or 16-bit signed value baked into the instruction. You can override the default segment with a prefix: MOV AX, ES:[BX] reads from ES instead of DS.
2.4 Assembler directives
These are not instructions. They tell the assembler how to lay out memory.
| Directive | Effect |
|---|---|
DB 0xFF, 0x12 | Define byte(s). |
DW 0x1234 | Define word (16-bit). |
DD 0x12345678 | Define double word. |
100 DUP(0) | Duplicate: 100 copies of zero. |
VAL EQU 50 | Equate: symbolic constant. |
ORG 100h | Set origin (current address). |
SEGMENT name / ENDS | Begin/end segment. |
PROC name / ENDP | Begin/end procedure. |
END start | End of source, with start label. |
2.5 Sample programs
Add two 16-bit numbers and store the result.
.MODEL SMALL
.STACK 100h
.DATA
NUM1 DW 1234h
NUM2 DW 5678h
SUM DW 0
.CODE
START: MOV AX, @DATA ; load DS with start of data segment
MOV DS, AX
MOV AX, NUM1 ; AX = 1234
ADD AX, NUM2 ; AX = 1234 + 5678 = 68AC
MOV SUM, AX ; store
MOV AX, 4C00h ; DOS exit with code 0
INT 21h
END STARTLoop counting (sum 1..10).
MOV CX, 10 ; counter
MOV AX, 0 ; running sum
MOV BX, 1 ; current value
NEXT: ADD AX, BX
INC BX
LOOP NEXT ; CX-- ; if CX != 0, jump back
; AX = 55Multiply two 16-bit numbers (32-bit result in DX:AX).
MOV AX, 1000h
MOV BX, 2000h
MUL BX ; DX:AX = AX * BX = 0200_0000hDivide.
MOV AX, 0FFFFh
MOV DX, 0 ; DX:AX = dividend (zero-extended)
MOV CX, 10
DIV CX ; AX = quotient (6553), DX = remainder (5)String copy (memcpy of N bytes).
MOV CX, N ; count
LEA SI, SOURCE ; DS:SI = source
LEA DI, DEST ; ES:DI = dest
CLD ; clear DF → SI/DI increment
REP MOVSB ; copy CX bytesBCD addition (Binary-Coded Decimal — each nibble holds one decimal digit).
MOV AL, 25h ; BCD 25
ADD AL, 18h ; binary add: AL = 3D
DAA ; Decimal Adjust Accumulator: AL = 43h, the BCD answer 43ASCII to binary (single digit).
SUB AL, '0' ; '7' (37h) becomes 72.6 Tools
MASM (Microsoft Macro Assembler), NASM (Netwide), TASM (Borland) are the canonical assemblers. DOSBox is a free DOS emulator that runs on every modern OS — assemble with NASM, run in DOSBox, debug with the legendary DEBUG.EXE that ships with DOS. For Windows you can also try emu8086, a teaching IDE that highlights flag changes step-by-step.