� Complete Guide to 8086 Assembly Language
Programming
From Zero to Exam-Ready
Table of Contents
1. Chapter 1: The Foundation — Understanding the 8086 Processor
2. Chapter 2: Registers — The Heart of 8086
3. Chapter 3: Memory Segmentation & Addressing
4. Chapter 4: Your First Assembly Program
5. Chapter 5: Data Movement — MOV and Friends
6. Chapter 6: Arithmetic Operations
7. Chapter 7: Logical & Bitwise Operations
8. Chapter 8: Flags Register Deep Dive
9. Chapter 9: Branching & Conditional Jumps
10. Chapter 10: Loops
11. Chapter 11: The Stack & Procedures
12. Chapter 12: String Operations
13. Chapter 13: Addressing Modes — Complete Guide
14. Chapter 14: Interrupts & DOS Services (INT 21h)
15. Chapter 15: Shift & Rotate Operations
16. Chapter 16: Complete Programs & Exam Practice
17. Quick Reference Card
Chapter 1: The Foundation — Understanding
the 8086 Processor
What is Assembly Language?
Assembly language is the lowest-level human-readable programming lan-
guage. It maps almost 1:1 to the machine code that the processor actually
executes.
High Level: result = a + b (C, Python, Java)
Assembly: ADD AX, BX (Human-readable processor instructions)
Machine Code: 01 D8 (Binary/Hex the CPU actually runs)
1
Why 8086?
The Intel 8086 is a 16-bit processor. This means: - It processes 16 bits (2
bytes) of data at a time - Its general-purpose registers are 16 bits wide - It
can address up to 1 MB of memory (20-bit address bus) - It has a 16-bit
data bus
Key Specs of the 8086 at a Glance
Feature Value
Data Bus Width 16 bits
Address Bus Width 20 bits
Max Memory 1 MB (2²�)
Number of Registers 14
Instruction Queue 6 bytes
Clock Speed 5-10 MHz
Chapter 2: Registers — The Heart of 8086
Registers are tiny, ultra-fast storage locations inside the CPU. The 8086
has 14 registers, divided into 4 categories.
2.1 General Purpose Registers (4 registers, each 16-bit)
Each can be split into two 8-bit halves:
AX (Accumulator) = AH (high 8 bits) + AL (low 8 bits)
BX (Base) = BH (high 8 bits) + BL (low 8 bits)
CX (Counter) = CH (high 8 bits) + CL (low 8 bits)
DX (Data) = DH (high 8 bits) + DL (low 8 bits)
Visual Breakdown of AX:
AX (16 bits)
�����������������������
� AH (8) � AL (8) �
� Bit15-8 � Bit7-0 �
�����������������������
What Each Register is Primarily Used For:
2
Register Name Primary Use
AX Accumulator Arithmetic, I/O operations, MUL/DIV default
BX Base Base address for memory access, lookup tables
CX Counter Loop counter (LOOP, REP), shift/rotate counts
DX Data I/O port addressing, extends AX in MUL/DIV
(32-bit)
Important: You CAN use any general-purpose register for general
arithmetic, but certain instructions require specific registers (e.g.,
MUL always uses AX).
2.2 Segment Registers (4 registers, each 16-bit)
These define the start of memory segments (we’ll cover segmentation in
Chapter 3):
Register Name Points To
CS Code Segment Where your instructions live
DS Data Segment Where your variables live
SS Stack Segment Where the stack lives
ES Extra Segment Extra data segment (strings)
Rule: You cannot MOV an immediate value directly into a segment
register.
MOV DS, 1234h ; � ILLEGAL
MOV AX, 1234h ; � First load into a GP register
MOV DS, AX ; � Then move to segment register
2.3 Pointer and Index Registers (5 registers, each 16-bit)
Register Name Purpose
SP Stack Pointer Points to the top of the stack
BP Base Pointer Used to access parameters on the stack
SI Source Index Source pointer for string operations
DI Destination Index Destination pointer for string operations
IP Instruction Pointer Points to the NEXT instruction to execute
IP is read-only — you cannot directly modify it with MOV. It
changes via JMP, CALL, RET, and interrupts.
3
2.4 Flags Register (1 register, 16-bit)
The FLAGS register contains individual bits that are set/cleared by operations:
Bit: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
- - - - OF DF IF TF SF ZF - AF - PF - CF
The 6 STATUS flags (set automatically by arithmetic/logical operations):
Flag Name Set When (= 1)
CF Carry Unsigned overflow (carry out of MSB)
ZF Zero Result is zero
SF Sign Result is negative (MSB = 1)
OF Overflow Signed overflow occurred
PF Parity Low byte has even number of 1-bits
AF Aux Carry Carry from bit 3 to bit 4 (used in BCD)
The 3 CONTROL flags (set by the programmer):
Flag Name Purpose
DF Direction String operations direction (0=forward, 1=backward)
IF Interrupt Enable/disable hardware interrupts
TF Trap Single-step debugging mode
Chapter 3: Memory Segmentation & Addressing
3.1 The Problem
The 8086 registers are 16-bit, so they can only hold values up to FFFFh (65,535).
But the address bus is 20-bit, meaning it can access up to FFFFFh (1,048,575
= 1 MB).
How do you create a 20-bit address from 16-bit registers?
3.2 The Segment:Offset Solution
The 8086 uses two 16-bit values to compute a 20-bit Physical Address:
Physical Address = (Segment × 16) + Offset
= (Segment × 10h) + Offset
= Segment shifted left 4 bits + Offset
4
Example:
Segment = 1234h
Offset = 0005h
Physical Address = 1234h × 10h + 0005h
= 12340h + 0005h
= 12345h ← This is the 20-bit physical address
Visual:
Segment: 1 2 3 4 0 (shifted left by one hex digit = 4 bits)
+ Offset: 0 0 0 5
= Physical: 1 2 3 4 5
3.3 Default Segment Associations
Operation Default Segment:Offset
Fetching instructions CS:IP
Stack operations (PUSH/POP) SS:SP
General data access DS:BX, DS:SI, DS:DI
String destination ES:DI
BP-based access SS:BP
3.4 Real Mode Memory Map (1 MB)
FFFFFh �������������������������
� BIOS ROM � Top of memory
F0000h ������������������������
� Reserved �
A0000h ������������������������
� Video Memory �
������������������������
� �
� User Programs �
� (Free RAM) �
� �
00500h ������������������������
� BIOS Data Area �
00400h ������������������������
� Interrupt Vector �
� Table (IVT) �
00000h ������������������������
5
Chapter 4: Your First Assembly Program
4.1 Program Structure (Template)
Every 8086 assembly program (for DOS, using MASM/TASM) follows this struc-
ture:
; ============================================
; Program: Description of what this program does
; ============================================
.MODEL SMALL ; Memory model: 1 code segment, 1 data segment
.STACK 100h ; Reserve 256 bytes for the stack
.DATA ; Data segment — declare your variables here
; variables go here
.CODE ; Code segment — your instructions go here
MAIN PROC
; Initialize Data Segment
MOV AX, @DATA ; Load address of data segment into AX
MOV DS, AX ; Set DS to point to our data segment
; =============================
; Your program logic goes here
; =============================
; Terminate program (return to DOS)
MOV AH, 4Ch ; DOS function: terminate program
INT 21h ; Call DOS interrupt
MAIN ENDP ; End of MAIN procedure
END MAIN ; Entry point of the program
4.2 Understanding Each Line
Line What It Does
.MODEL SMALL One code segment + one data segment (good for small
programs)
.STACK 100h Reserves 256 bytes for the stack
.DATA Start of data segment (variables declared here)
.CODE Start of code segment (instructions go here)
MOV AX, @DATA @DATA is the address of the data segment
MOV DS, AX Now DS points to our variables
MOV AH, 4Ch DOS function 4Ch = terminate program
6
Line What It Does
INT 21h Calls DOS to execute function in AH
MAIN ENDP Marks end of MAIN procedure
END MAIN Tells assembler where the program starts
4.3 Declaring Variables in .DATA
DB — Define Byte (1 byte = 8 bits)
.DATA
myChar DB 'A' ; Single character (ASCII 65)
myNum DB 25 ; Decimal number (stored as 19h)
myHex DB 0FFh ; Hex number (prefix 0 if starts with letter)
myMsg DB 'Hello$' ; String ($ terminates for DOS print)
myArray DB 10, 20, 30 ; Array of bytes
buffer DB 50 DUP(0) ; 50 bytes, all initialized to 0
unInit DB ? ; 1 byte, uninitialized
DW — Define Word (2 bytes = 16 bits)
myWord DW 1234h ; 16-bit value
wordArr DW 100, 200, 300; Array of words
bigBuf DW 20 DUP(?) ; 20 words, uninitialized
Important: DUP Directive
DB 10 DUP(0) ; Creates 10 bytes, each = 0
DB 5 DUP('A') ; Creates: 'A', 'A', 'A', 'A', 'A'
DW 10 DUP(?) ; Creates 10 words, uninitialized
4.4 Program — Hello World!
; ============================================
; Program: Print "Hello, World!" to the screen
; ============================================
.MODEL SMALL
.STACK 100h
.DATA
msg DB 'Hello, World!$' ; $ marks end of string for INT 21h/09h
.CODE
MAIN PROC
MOV AX, @DATA
MOV DS, AX
7
; Print string
LEA DX, msg ; Load Effective Address of msg into DX
MOV AH, 09h ; DOS function 09h = print string
INT 21h ; Call DOS
; Exit
MOV AH, 4Ch
INT 21h
MAIN ENDP
END MAIN
Output:
Hello, World!
Chapter 5: Data Movement — MOV and Friends
5.1 MOV — The Most Used Instruction
Syntax: MOV destination, source
Think of it as: destination ← source (source is copied, NOT moved)
� Valid MOV Combinations:
MOV AX, BX ; Register ← Register
MOV AX, 1234h ; Register ← Immediate (constant)
MOV AX, [myVar] ; Register ← Memory
MOV [myVar], AX ; Memory ← Register
MOV [myVar], 5 ; Memory ← Immediate
� INVALID MOV Operations:
MOV [var1], [var2] ; � Memory ← Memory (NEVER ALLOWED)
MOV CS, AX ; � Cannot MOV into CS
MOV DS, 1234h ; � Cannot MOV immediate into segment register
MOV AH, BX ; � Size mismatch (8-bit ← 16-bit)
Fix for Memory-to-Memory:
; To copy one memory variable to another:
MOV AX, [var1] ; Load var1 into AX
MOV [var2], AX ; Store AX into var2
8
5.2 XCHG — Exchange Values
XCHG AX, BX ; Swap AX and BX (no temp needed!)
XCHG AL, BL ; Swap AL and BL
XCHG AX, [myVar] ; Swap AX with memory variable
5.3 LEA — Load Effective Address
Loads the address of a variable, NOT its value:
LEA BX, myVar ; BX = address of myVar
; Equivalent to:
MOV BX, OFFSET myVar ; Same result
5.4 PUSH and POP
PUSH AX ; Push AX onto stack (SP decreases by 2)
POP BX ; Pop top of stack into BX (SP increases by 2)
Stack is LIFO (Last In, First Out) and grows downward in memory:
; Example:
PUSH AX ; Stack: [AX value]
PUSH BX ; Stack: [AX value] [BX value] ← SP points here
POP CX ; CX = BX value, Stack: [AX value]
POP DX ; DX = AX value, Stack: (empty)
5.5 CBW and CWD — Sign Extension
; CBW: Convert Byte to Word (extends AL into AX)
MOV AL, -5 ; AL = FBh (signed -5)
CBW ; AX = FFFBh (sign-extended to 16 bits)
; CWD: Convert Word to Double-word (extends AX into DX:AX)
MOV AX, -100 ; AX = FF9Ch
CWD ; DX:AX = FFFF:FF9Ch (32-bit signed)
Chapter 6: Arithmetic Operations
6.1 ADD and SUB
ADD AX, BX ; AX = AX + BX
ADD AX, 5 ; AX = AX + 5
ADD AL, [myVar] ; AL = AL + value at myVar
9
SUB AX, BX ; AX = AX - BX
SUB AX, 10 ; AX = AX - 10
Example: Add Two Numbers
.MODEL SMALL
.STACK 100h
.DATA
num1 DB 25
num2 DB 30
result DB ?
.CODE
MAIN PROC
MOV AX, @DATA
MOV DS, AX
MOV AL, num1 ; AL = 25
ADD AL, num2 ; AL = 25 + 30 = 55
MOV result, AL ; Store result
MOV AH, 4Ch
INT 21h
MAIN ENDP
END MAIN
6.2 ADC and SBB — With Carry/Borrow
Used for multi-precision arithmetic (numbers larger than 16 bits):
; Adding two 32-bit numbers: DX:AX + CX:BX
ADD AX, BX ; Add low 16 bits (may set CF)
ADC DX, CX ; Add high 16 bits + Carry Flag
; Subtracting: DX:AX - CX:BX
SUB AX, BX ; Subtract low 16 bits (may set CF for borrow)
SBB DX, CX ; Subtract high 16 bits - Borrow (CF)
6.3 INC and DEC
INC AX ; AX = AX + 1
INC [myVar] ; myVar = myVar + 1
DEC CX ; CX = CX - 1
Note: INC and DEC do NOT affect the Carry Flag (CF). All other
arithmetic flags are affected.
10
6.4 MUL — Unsigned Multiplication
MUL always uses AX (or AL) as one operand implicitly.
; 8-bit multiplication: AX = AL × operand
MOV AL, 10
MOV BL, 25
MUL BL ; AX = AL × BL = 10 × 25 = 250
; 16-bit multiplication: DX:AX = AX × operand
MOV AX, 1000
MOV BX, 500
MUL BX ; DX:AX = AX × BX = 1000 × 500 = 500000
; Result is 32-bit, stored across DX (high) and AX (low)
MUL Summary Table:
Operand Size Operation Result Stored In
8-bit AL × operand AX
16-bit AX × operand DX:AX
6.5 IMUL — Signed Multiplication
Same as MUL but treats operands as signed numbers:
MOV AL, -5 ; AL = FBh (signed -5)
MOV BL, 3
IMUL BL ; AX = -5 × 3 = -15 (FFF1h)
6.6 DIV — Unsigned Division
DIV also uses AX (or DX:AX) implicitly.
; 8-bit division: AL = AX ÷ operand, AH = remainder
MOV AX, 25
MOV BL, 7
DIV BL ; AL = 25 ÷ 7 = 3 (quotient)
; AH = 25 mod 7 = 4 (remainder)
; 16-bit division: AX = DX:AX ÷ operand, DX = remainder
MOV DX, 0 ; Clear DX (important for 16-bit DIV!)
MOV AX, 1000
MOV BX, 7
DIV BX ; AX = 1000 ÷ 7 = 142 (quotient)
; DX = 1000 mod 7 = 6 (remainder)
11
DIV Summary Table:
Operand Size Dividend Quotient Remainder
8-bit AX AL AH
16-bit DX:AX AX DX
� Common Error: Forgetting to clear DX before 16-bit DIV →
garbage result!
6.7 IDIV — Signed Division
Same as DIV but for signed numbers. Use CWD before IDIV to sign-extend
AX into DX:AX:
MOV AX, -100
CWD ; Sign-extend AX into DX:AX
MOV BX, 7
IDIV BX ; AX = -100 ÷ 7 = -14, DX = -100 mod 7 = -2
6.8 NEG — Negate (Two’s Complement)
MOV AX, 5
NEG AX ; AX = -5 (FFFBh) — flips the sign
6.9 Complete Arithmetic Example — Simple Calculator
; ============================================
; Program: Calculate (A + B) × C - D
; Where A=10, B=20, C=3, D=5
; Expected result: (10 + 20) × 3 - 5 = 85
; ============================================
.MODEL SMALL
.STACK 100h
.DATA
A DW 10
B DW 20
C DW 3
D DW 5
result DW ?
.CODE
MAIN PROC
MOV AX, @DATA
MOV DS, AX
12
MOV AX, A ; AX = 10
ADD AX, B ; AX = 10 + 20 = 30
MUL C ; DX:AX = 30 × 3 = 90 (DX=0, AX=90)
SUB AX, D ; AX = 90 - 5 = 85
MOV result, AX ; Store result = 85
MOV AH, 4Ch
INT 21h
MAIN ENDP
END MAIN
Chapter 7: Logical & Bitwise Operations
7.1 AND — Bitwise AND
Both bits must be 1 to produce 1:
MOV AL, 0Fh ; AL = 00001111b
AND AL, 3Ch ; AND 00111100b
; = 00001100b = 0Ch
Common Use: Masking (extracting) specific bits, clearing bits.
AND AL, 0Fh ; Keep only the lower 4 bits (lower nibble)
AND AL, 0F0h ; Keep only the upper 4 bits (upper nibble)
7.2 OR ��� Bitwise OR
Either bit being 1 produces 1:
MOV AL, 0Fh ; AL = 00001111b
OR AL, 30h ; OR 00110000b
; = 00111111b = 3Fh
Common Use: Setting specific bits.
OR AL, 01h ; Set bit 0 (make number odd)
OR AL, 20h ; Convert uppercase to lowercase ('A' OR 20h = 'a')
7.3 XOR — Bitwise Exclusive OR
Bits must differ to produce 1:
MOV AL, 0FFh ; AL = 11111111b
XOR AL, 0Fh ; XOR 00001111b
; = 11110000b = F0h
Common Uses:
13
XOR AX, AX ; AX = 0 (fastest way to zero a register!)
XOR AL, 20h ; Toggle case: 'A' � 'a'
7.4 NOT — Bitwise Complement
Flips every bit:
MOV AL, 0Fh ; AL = 00001111b
NOT AL ; AL = 11110000b = F0h
Note: NOT does not affect any flags. AND, OR, XOR do affect
flags (CF=0, OF=0, ZF/SF/PF updated).
7.5 TEST — Non-Destructive AND
Works like AND but doesn’t store the result — only sets flags:
TEST AL, 01h ; Is bit 0 set? (is AL odd?)
JNZ its_odd ; Jump if ZF=0 (bit was set)
TEST AL, 80h ; Is bit 7 set? (is AL negative in signed?)
JNZ its_negative
7.6 CMP — Compare (Non-Destructive SUB)
Works like SUB but doesn’t store the result — only sets flags:
CMP AX, BX ; Compute AX - BX, set flags, discard result
JE equal ; Jump if AX == BX (ZF=1)
JG ax_greater ; Jump if AX > BX (signed)
JA ax_above ; Jump if AX > BX (unsigned)
Chapter 8: Flags Register Deep Dive
Understanding which flags are set and when is critical for exam questions.
8.1 Example — Trace Through Flags
MOV AL, 0FFh ; AL = 255 (unsigned) or -1 (signed)
ADD AL, 01h ; AL = 00h (wraps around)
After this ADD:
Flag Value Why
CF 1 Carry out of bit 7 (255+1 overflows 8 bits)
ZF 1 Result is zero
14
Flag Value Why
SF 0 Bit 7 of result is 0
OF 0 No signed overflow (-1 + 1 = 0, valid)
PF 1 Zero 1-bits in low byte = even count
AF 1 Carry from bit 3 to bit 4
8.2 Another Example
MOV AL, 7Fh ; AL = 127 (max positive signed byte)
ADD AL, 01h ; AL = 80h = 128 unsigned, -128 signed
Flag Value Why
CF 0 No carry out of bit 7 (127+1=128 fits in 8 bits unsigned)
ZF 0 Result � 0
SF 1 Bit 7 = 1
OF 1 Signed overflow! (127+1 = -128 is wrong for signed)
PF 0 Only one 1-bit in low byte (odd count)
Chapter 9: Branching & Conditional Jumps
9.1 Unconditional Jump
JMP label ; Always jump to label
Example:
MOV AX, 5
JMP skip_this
MOV AX, 99 ; This line is NEVER executed
skip_this:
; AX is still 5
9.2 Conditional Jumps (Used After CMP or Arithmetic)
For UNSIGNED comparisons (after CMP A, B):
Instruction Meaning Condition
JE / JZ Jump if Equal / Zero ZF = 1
JNE / JNZ Jump if Not Equal ZF = 0
JA / JNBE Jump if Above CF=0 AND ZF=0
JAE / JNB Jump if Above or Equal CF = 0
15
Instruction Meaning Condition
JB / JNAE Jump if Below CF = 1
JBE / JNA Jump if Below or Equal CF=1 OR ZF=1
For SIGNED comparisons (after CMP A, B):
Instruction Meaning Condition
JE / JZ Jump if Equal ZF = 1
JNE / JNZ Jump if Not Equal ZF = 0
JG / JNLE Jump if Greater ZF=0 AND SF=OF
JGE / JNL Jump if Greater or Equal SF = OF
JL / JNGE Jump if Less SF � OF
JLE / JNG Jump if Less or Equal ZF=1 OR SF�OF
Individual flag checks:
Instruction Meaning Condition
JC Jump if Carry CF = 1
JNC Jump if No Carry CF = 0
JO Jump if Overflow OF = 1
JNO Jump if No Overflow OF = 0
JS Jump if Sign (negative) SF = 1
JNS Jump if No Sign (positive) SF = 0
JP / JPE Jump if Parity Even PF = 1
JNP / JPO Jump if Parity Odd PF = 0
Memory Trick: - Above / Below = Unsigned - Greater / Less =
Signed
9.3 If-Else Structure in Assembly
C Equivalent:
if (ax == bx)
cx = 1;
else
cx = 0;
Assembly:
CMP AX, BX
JE is_equal ; If AX == BX, jump to is_equal
MOV CX, 0 ; ELSE: CX = 0
16
JMP done
is_equal:
MOV CX, 1 ; THEN: CX = 1
done:
9.4 Finding Maximum of Two Numbers
; ============================================
; Program: Find the larger of two numbers
; ============================================
.MODEL SMALL
.STACK 100h
.DATA
num1 DW 45
num2 DW 72
max DW ?
.CODE
MAIN PROC
MOV AX, @DATA
MOV DS, AX
MOV AX, num1 ; AX = 45
CMP AX, num2 ; Compare 45 with 72
JGE ax_is_max ; If AX >= num2 (signed), AX is max
MOV AX, num2 ; Otherwise, load num2 as max
ax_is_max:
MOV max, AX ; Store the maximum
MOV AH, 4Ch
INT 21h
MAIN ENDP
END MAIN
Chapter 10: Loops
10.1 LOOP Instruction
LOOP automatically uses CX as a counter: 1. Decrements CX by 1 2. If CX � 0,
jumps to the label 3. If CX = 0, falls through
MOV CX, 5 ; Loop 5 times
repeat:
; body of loop (executes 5 times)
17
LOOP repeat ; CX-- ; if CX � 0, goto repeat
Example: Sum Numbers 1 to 10
.MODEL SMALL
.STACK 100h
.DATA
sum DW ?
.CODE
MAIN PROC
MOV AX, @DATA
MOV DS, AX
MOV AX, 0 ; AX = running sum
MOV CX, 10 ; Loop counter = 10
add_loop:
ADD AX, CX ; Add CX (10, 9, 8, ..., 1) to sum
LOOP add_loop ; CX--, jump if CX � 0
MOV sum, AX ; Store result (sum = 55)
MOV AH, 4Ch
INT 21h
MAIN ENDP
END MAIN
Trace:
Iteration CX (before ADD) AX (after ADD)
1 10 10
2 9 19
3 8 27
4 7 34
5 6 40
6 5 45
7 4 49
8 3 52
9 2 54
10 1 55
10.2 Manual Loops with CMP and JMP
When you need more control (or need CX for something else):
18
; Print 'A' through 'E'
MOV DL, 'A' ; Starting character
print_loop:
MOV AH, 02h ; DOS: print character in DL
INT 21h
INC DL ; Next character
CMP DL, 'F' ; Past 'E'?
JB print_loop ; If DL < 'F', keep going
10.3 Nested Loops
Since LOOP uses CX, you must save CX for outer loops:
MOV CX, 3 ; Outer loop: 3 times
outer:
PUSH CX ; Save outer counter!
MOV CX, 5 ; Inner loop: 5 times
inner:
; inner body
LOOP inner ; Inner CX--, loop
POP CX ; Restore outer counter
LOOP outer ; Outer CX--, loop
10.4 While Loop Pattern
C:
while (ax > 0) {
ax = ax - 3;
}
Assembly:
while_start:
CMP AX, 0
JLE while_end ; If AX <= 0, exit loop
SUB AX, 3
JMP while_start
while_end:
10.5 Do-While Loop Pattern
C:
do {
ax = ax - 3;
} while (ax > 0);
19
Assembly:
do_loop:
SUB AX, 3
CMP AX, 0
JG do_loop ; If AX > 0, repeat
Chapter 11: The Stack & Procedures
11.1 How the Stack Works
The stack grows downward in memory (from high addresses to low):
Memory Address
SS:0100h ������������
� (empty) �
SS:00FEh ������������
� (empty) �
SS:00FCh ������������ ← SP (Stack Pointer) after 2 PUSHes
� Value2 �
SS:00FEh ������������
� Value1 �
SS:0100h ������������ ← SP starts here (bottom of stack)
; PUSH decreases SP by 2, then stores value
PUSH AX ; SP = SP - 2; [SS:SP] = AX
; POP reads value, then increases SP by 2
POP BX ; BX = [SS:SP]; SP = SP + 2
11.2 Procedures (Subroutines/Functions)
Defining and Calling:
.CODE
MAIN PROC
MOV AX, @DATA
MOV DS, AX
CALL myProcedure ; Call the procedure
; Execution continues here after RET
MOV AH, 4Ch
INT 21h
MAIN ENDP
20
; ---- Procedure Definition ----
myProcedure PROC
; Do something here
MOV AX, 5
ADD AX, 3
RET ; Return to caller
myProcedure ENDP
END MAIN
How CALL and RET Work:
CALL myProc:
1. PUSH IP (return address onto stack)
2. IP = address of myProc
RET:
1. POP IP (jump back to instruction after CALL)
11.3 Passing Parameters via Registers
; ============================================
; Program: Procedure to add two numbers
; Parameters passed in AX and BX
; Result returned in AX
; ============================================
.MODEL SMALL
.STACK 100h
.DATA
result DW ?
.CODE
MAIN PROC
MOV AX, @DATA
MOV DS, AX
MOV AX, 15 ; First parameter
MOV BX, 25 ; Second parameter
CALL AddNums ; Call procedure
MOV result, AX ; AX = 40 (returned by procedure)
MOV AH, 4Ch
INT 21h
MAIN ENDP
AddNums PROC
21
ADD AX, BX ; AX = AX + BX
RET
AddNums ENDP
END MAIN
11.4 Passing Parameters via the Stack
This is the more “formal” way, commonly asked in exams:
; ============================================
; Procedure to add two numbers using stack
; ============================================
.MODEL SMALL
.STACK 100h
.DATA
result DW ?
.CODE
MAIN PROC
MOV AX, @DATA
MOV DS, AX
; Push parameters (right to left by convention)
PUSH 25 ; Second parameter
PUSH 15 ; First parameter
CALL AddNums ; Pushes return address, then jumps
ADD SP, 4 ; Clean up stack (2 parameters × 2 bytes)
MOV result, AX
MOV AH, 4Ch
INT 21h
MAIN ENDP
AddNums PROC
PUSH BP ; Save old BP
MOV BP, SP ; BP = current stack pointer
; Stack layout at this point:
; [BP+0] = Old BP
; [BP+2] = Return Address
; [BP+4] = First parameter (15)
; [BP+6] = Second parameter (25)
MOV AX, [BP+4] ; AX = first parameter (15)
ADD AX, [BP+6] ; AX = 15 + 25 = 40
22
POP BP ; Restore old BP
RET
AddNums ENDP
END MAIN
Stack Frame Diagram:
High Memory
������������������
� 25 � [BP+6] Second parameter
������������������
� 15 � [BP+4] First parameter
������������������
� Return Address � [BP+2] Pushed by CALL
������������������
� Old BP � [BP+0] Pushed by PUSH BP ← BP points here
������������������ ← SP points here
Low Memory
11.5 Preserving Registers
Convention: If your procedure modifies registers, save and restore them:
MyProc PROC
PUSH AX ; Save registers you will modify
PUSH BX
PUSH CX
; ... procedure body ...
POP CX ; Restore in REVERSE order!
POP BX
POP AX
RET
MyProc ENDP
Chapter 12: String Operations
String operations work on arrays of bytes or words. They use SI (source) and
DI (destination) and auto-increment/decrement based on the Direction Flag
(DF).
23
12.1 Setup Requirements
; Source: DS:SI
; Destination: ES:DI
; Direction: DF=0 (CLD → forward), DF=1 (STD → backward)
; Count: CX (for REP prefix)
CLD ; Clear Direction Flag → process forward (SI++, DI++)
STD ; Set Direction Flag → process backward (SI--, DI--)
12.2 String Instructions
Instruction Operation Size
MOVSB Move byte: [ES:DI] ← [DS:SI], advance SI & DI Byte
MOVSW Move word: [ES:DI] ← [DS:SI], advance SI & DI Word
LODSB Load byte: AL ← [DS:SI], advance SI Byte
LODSW Load word: AX ← [DS:SI], advance SI Word
STOSB Store byte: [ES:DI] ← AL, advance DI Byte
STOSW Store word: [ES:DI] ← AX, advance DI Word
CMPSB Compare byte: [DS:SI] vs [ES:DI], set flags Byte
SCASB Scan byte: AL vs [ES:DI], set flags Byte
12.3 REP Prefix
Repeats the string instruction CX times:
Prefix Meaning
REP Repeat CX times
REPE/REPZ Repeat while equal (ZF=1), max CX
REPNE/REPNZ Repeat while not equal (ZF=0)
Example: Copy a String
.MODEL SMALL
.STACK 100h
.DATA
source DB 'Hello, World!', 0
dest DB 14 DUP(0)
.CODE
MAIN PROC
MOV AX, @DATA
MOV DS, AX
MOV ES, AX ; ES = DS (same segment)
24
CLD ; Forward direction
LEA SI, source ; SI → source string
LEA DI, dest ; DI → destination
MOV CX, 14 ; 14 bytes to copy (13 chars + null)
REP MOVSB ; Copy CX bytes from DS:SI to ES:DI
MOV AH, 4Ch
INT 21h
MAIN ENDP
END MAIN
Example: Fill Array with a Value
CLD
LEA DI, buffer ; DI → destination buffer
MOV AL, 0 ; Value to fill
MOV CX, 100 ; Fill 100 bytes
REP STOSB ; [ES:DI] ← AL, CX times
Chapter 13: Addressing Modes — Complete
Guide
Addressing modes define HOW the operand of an instruction is specified.
13.1 All Addressing Modes
1. Immediate Addressing
The operand is a constant value in the instruction itself:
MOV AX, 1234h ; 1234h is the immediate operand
ADD BL, 05h
MOV CL, 'A'
2. Register Addressing
The operand is a register:
MOV AX, BX ; Both operands are registers
ADD AL, BL
INC CX
3. Direct Addressing
The operand is at a fixed memory address:
25
MOV AX, [1234h] ; Load from memory address DS:1234h
MOV AX, myVar ; Load from the address of myVar
MOV [myVar], BX ; Store BX at the address of myVar
4. Register Indirect Addressing
The address is in a register (BX, SI, DI, or BP):
MOV BX, OFFSET myVar ; BX = address of myVar
MOV AX, [BX] ; AX = value at address in BX
MOV [SI], CX ; Store CX at address in SI
5. Based Addressing (Register + Displacement)
Base register (BX or BP) + constant offset:
MOV AX, [BX+4] ; AX = value at DS:(BX+4)
MOV AX, [BP+6] ; AX = value at SS:(BP+6) ← Note: BP uses SS!
6. Indexed Addressing (Index Register + Displacement)
Index register (SI or DI) + constant offset:
MOV AX, [SI+2] ; AX = value at DS:(SI+2)
MOV AX, [DI+4] ; AX = value at DS:(DI+4)
7. Based Indexed Addressing (Base + Index)
Combines a base register with an index register:
MOV AX, [BX+SI] ; AX = value at DS:(BX+SI)
MOV AX, [BX+DI] ; AX = value at DS:(BX+DI)
MOV AX, [BP+SI] ; AX = value at SS:(BP+SI)
8. Based Indexed with Displacement
Base + Index + Constant:
MOV AX, [BX+SI+2] ; AX = value at DS:(BX+SI+2)
MOV AX, [BP+DI+4] ; AX = value at SS:(BP+DI+4)
13.2 Valid Base and Index Combinations
Only these register combinations are valid for memory addressing:
Base Register Index Register Default Segment
BX SI DS
BX DI DS
BP SI SS
26
Base Register Index Register Default Segment
BP DI SS
BX (none) DS
BP (none) SS
(none) SI DS
(none) DI DS
� You CANNOT use AX, CX, DX, SP as base/index registers for
addressing!
MOV AX, [CX] ; � INVALID
MOV AX, [AX+BX] ; � INVALID
MOV AX, [SP+2] ; � INVALID
13.3 Addressing Mode Quick Reference Diagram
Addressing Mode Example Effective Address
�������������������������������������������������������������������������
Immediate MOV AX, 5 (value is 5)
Register MOV AX, BX (value is in BX)
Direct MOV AX, [1234h] DS:1234h
Register Indirect MOV AX, [BX] DS:BX
Based MOV AX, [BX+4] DS:(BX+4)
Indexed MOV AX, [SI+4] DS:(SI+4)
Based Indexed MOV AX, [BX+SI] DS:(BX+SI)
Based Indexed + Displacement MOV AX, [BX+SI+4] DS:(BX+SI+4)
Chapter 14: Interrupts & DOS Services (INT
21h)
14.1 What is an Interrupt?
An interrupt is a signal that pauses the CPU’s current work to execute a
special routine called an Interrupt Service Routine (ISR). INT is a software
interrupt.
INT 21h ; Call DOS interrupt (function number in AH)
INT 10h ; Call BIOS video interrupt
27
14.2 Essential INT 21h Functions
Display a Single Character (AH = 02h)
MOV AH, 02h
MOV DL, 'A' ; Character to display
INT 21h ; Output: A
Display a String (AH = 09h)
.DATA
msg DB 'Hello, World!$' ; Must end with '$'
.CODE
LEA DX, msg ; DX → address of string
MOV AH, 09h
INT 21h ; Output: Hello, World!
Read a Single Character with Echo (AH = 01h)
MOV AH, 01h
INT 21h ; Wait for key press
; AL = ASCII code of key pressed (character is also echoed to screen)
Read a Single Character without Echo (AH = 08h)
MOV AH, 08h
INT 21h ; Wait for key press (no echo)
; AL = ASCII code of key pressed
Read a String (Buffered Input) (AH = 0Ah)
.DATA
buffer DB 50 ; Max characters to read (including Enter)
DB ? ; Actual characters read (filled by DOS)
DB 50 DUP('$') ; Buffer space
.CODE
LEA DX, buffer
MOV AH, 0Ah
INT 21h ; Reads a line of input
; buffer+1 = number of characters typed
; buffer+2 onward = the actual characters
Terminate Program (AH = 4Ch)
MOV AH, 4Ch
MOV AL, 00h ; Return code (0 = success)
28
INT 21h
14.3 Printing a New Line
; Newline = Carriage Return (0Dh) + Line Feed (0Ah)
MOV AH, 02h
MOV DL, 0Dh ; Carriage Return
INT 21h
MOV DL, 0Ah ; Line Feed
INT 21h
Or define it in data:
.DATA
newline DB 0Dh, 0Ah, '$'
.CODE
LEA DX, newline
MOV AH, 09h
INT 21h
14.4 ASCII Table Reference (Most Common)
Char ASCII (Hex) ASCII (Dec)
‘0’ 30h 48
‘9’ 39h 57
‘A’ 41h 65
‘Z’ 5Ah 90
‘a’ 61h 97
‘z’ 7Ah 122
Space 20h 32
Enter 0Dh 13
Newline 0Ah 10
Key relationships:
'A' to 'a' difference = 20h (32 decimal)
'0' to integer: subtract 30h (48 decimal)
integer to '0': add 30h
29
Chapter 15: Shift & Rotate Operations
15.1 Shift Operations
SHL / SAL — Shift Left (Logical / Arithmetic — same operation)
Before: 1 0 1 1 0 1 1 0
SHL 1: 0 1 1 0 1 1 0 0 ← 0 fills from right, MSB goes to CF
SHL AX, 1 ; Shift AX left by 1 (multiply by 2)
MOV CL, 3
SHL AX, CL ; Shift AX left by 3 (multiply by 8)
SHL by 1 = × 2, SHL by N = × 2�
SHR — Shift Right (Logical — unsigned)
Before: 1 0 1 1 0 1 1 0
SHR 1: 0 1 0 1 1 0 1 1 ← 0 fills from left, LSB goes to CF
SHR AX, 1 ; Unsigned divide by 2
MOV CL, 2
SHR AX, CL ; Unsigned divide by 4
SAR — Shift Right (Arithmetic — signed, preserves sign bit)
Before: 1 0 1 1 0 1 1 0 (negative number, MSB=1)
SAR 1: 1 1 0 1 1 0 1 1 ← Sign bit (1) fills from left
SAR AX, 1 ; Signed divide by 2 (preserves sign)
15.2 Rotate Operations
ROL — Rotate Left
Before: 1 0 1 1 0 1 1 0
ROL 1: 0 1 1 0 1 1 0 1 ← MSB wraps around to LSB and CF
CF = 1
ROL AX, 1 ; Rotate left by 1
ROR — Rotate Right
Before: 1 0 1 1 0 1 1 0
ROR 1: 0 1 0 1 1 0 1 1 ← LSB wraps around to MSB and CF
CF = 0
RCL — Rotate Left through Carry
Includes CF as part of the rotation:
30
CF=0, AL = 1 0 1 1 0 1 1 0
RCL 1:
CF=1, AL = 0 1 1 0 1 1 0 0 ← MSB→CF, old CF→LSB
RCR — Rotate Right through Carry
CF=0, AL = 1 0 1 1 0 1 1 0
RCR 1:
CF=0, AL = 0 1 0 1 1 0 1 1 ← LSB→CF, old CF→MSB
15.3 Shift/Rotate Summary Table
Instruction Direction Fill Bit Use Case
SHL/SAL Left 0 Multiply by 2�
SHR Right 0 Unsigned divide by 2�
SAR Right Sign bit Signed divide by 2�
ROL Left Wraps MSB Bit manipulation
ROR Right Wraps LSB Bit manipulation
RCL Left CF→LSB Multi-word shifts
RCR Right CF→MSB Multi-word shifts
8086 Rule: You can only shift/rotate by 1 or by CL. You cannot
use an immediate value greater than 1.
SHL AX, 1 ; � OK
MOV CL, 4
SHL AX, CL ; � OK
SHL AX, 4 ; � ILLEGAL on 8086 (works on 80186+)
Chapter 16: Complete Programs & Exam Prac-
tice
Program 1: Read a Character and Display It
; Read a character and display it back with a message
.MODEL SMALL
.STACK 100h
.DATA
prompt DB 'Enter a character: $'
msg1 DB 0Dh, 0Ah, 'You entered: $'
.CODE
MAIN PROC
31
MOV AX, @DATA
MOV DS, AX
; Print prompt
LEA DX, prompt
MOV AH, 09h
INT 21h
; Read character
MOV AH, 01h
INT 21h ; AL = character entered
MOV BL, AL ; Save character in BL
; Print message
LEA DX, msg1
MOV AH, 09h
INT 21h
; Display the character
MOV DL, BL
MOV AH, 02h
INT 21h
; Exit
MOV AH, 4Ch
INT 21h
MAIN ENDP
END MAIN
Program 2: Check if a Character is Uppercase or Lowercase
.MODEL SMALL
.STACK 100h
.DATA
prompt DB 'Enter a letter: $'
upper DB 0Dh, 0Ah, 'It is UPPERCASE$'
lower DB 0Dh, 0Ah, 'It is lowercase$'
invalid DB 0Dh, 0Ah, 'Not a letter!$'
.CODE
MAIN PROC
MOV AX, @DATA
MOV DS, AX
LEA DX, prompt
MOV AH, 09h
32
INT 21h
MOV AH, 01h
INT 21h ; AL = input character
; Check if uppercase (A-Z: 41h to 5Ah)
CMP AL, 'A'
JB not_letter
CMP AL, 'Z'
JBE is_upper
; Check if lowercase (a-z: 61h to 7Ah)
CMP AL, 'a'
JB not_letter
CMP AL, 'z'
JBE is_lower
JMP not_letter
is_upper:
LEA DX, upper
JMP print_result
is_lower:
LEA DX, lower
JMP print_result
not_letter:
LEA DX, invalid
print_result:
MOV AH, 09h
INT 21h
MOV AH, 4Ch
INT 21h
MAIN ENDP
END MAIN
Program 3: Convert Lowercase to Uppercase
“‘asm .MODEL SMALL .STACK 100h .DATA prompt DB ‘Enter a lowercase
letter: $’ result DB 0Dh, 0Ah, ‘Uppercase: $’
.CODE MAIN PROC MOV AX, @DATA MOV DS, AX
LEA D
33