8086 Assembly Language Programming

Master 8086 assembly language programming with comprehensive examples, programming techniques, and real-world applications.

Assembly Language Programming Fundamentals

Assembly language programming represents the closest level of programming to machine code while maintaining human readability. In 8086 assembly programming, each mnemonic instruction corresponds directly to a specific machine language instruction, providing programmers with direct control over processor operations and memory management.

What is Assembly Language?

Assembly language serves as an intermediary between high-level programming languages and machine code:

  • Low-Level Control: Direct access to processor registers and memory
  • Hardware Specific: Designed for specific processor architecture (8086 family)
  • Symbolic Representation: Uses mnemonics instead of binary codes
  • One-to-One Mapping: Each assembly instruction maps to one machine instruction
  • Maximum Efficiency: Enables optimal performance and minimal resource usage

Programming Language Hierarchy

Loading diagram...

Why Learn 8086 Assembly Programming?

Learning 8086 assembly programming provides several educational and practical benefits:

  • Computer Architecture Understanding: Deep insight into processor operation
  • Performance Optimization: Ability to write highly efficient code
  • System Programming: Essential for device drivers and embedded systems
  • Debugging Skills: Better understanding of program execution
  • Legacy System Maintenance: Many existing systems use 8086-compatible code
  • Reverse Engineering: Understanding how compiled programs work

8086 Assembly Program Structure - Foundation

A complete 8086 assembly program follows a specific structure that defines memory organization and program flow:


; Complete 8086 Assembly Program Structure
.MODEL SMALL            ; Memory model specification
.STACK 100H             ; Stack segment allocation (256 bytes)

.DATA                   ; Data segment begins
    ; Variable declarations go here
    message DB 'Hello, World!$'
    number  DW 1234H
    result  DW ?

.CODE                   ; Code segment begins
START:                  ; Program entry point
    ; Initialize data segment register
    MOV AX, @DATA       ; Load data segment address
    MOV DS, AX          ; Set DS to point to data segment
    
    ; Main program logic
    MOV AX, number      ; Load number into AX
    ADD AX, 100H        ; Add 100H to AX
    MOV result, AX      ; Store result
    
    ; Program termination
    MOV AH, 4CH         ; DOS terminate program function
    INT 21H             ; Call DOS interrupt
END START               ; End of program, specify entry point
        

Memory Models - Program Organization Strategy

Memory Models - Program Organization Strategy

Memory models define how the program's code, data, and stack segments are organized and accessed. The choice of memory model affects program size limitations and addressing methods:

ModelCode SegmentData + StackFile TypeUse Case
TINY≤ 64KB≤ 64KB.COMSmall utilities, TSR programs
SMALL≤ 64KB≤ 64KB.EXEMost common, typical applications
MEDIUM≤ 1MB≤ 64KB.EXELarge programs with small data
COMPACT≤ 64KB≤ 1MB.EXEPrograms with large data sets
LARGEMultiple 64KB segmentsMultiple 64KB segments.EXELarge apps (manual far ptr mgmt)
HUGE*Like LARGELike LARGE.EXEArrays >64KB (compiler fixes far idx)

Memory Model Notes:

  • SMALL Model: Recommended for learning and most programs
  • TINY Model: For programs that need to run as .COM files
  • MEDIUM Model: When code exceeds 64KB but data is small
  • COMPACT Model: When data exceeds 64KB but code is small
  • *Huge: Term common in high-level compilers; in raw MASM you manage far pointers manually.

Data Declaration and Types

Data declaration defines variables and constants in the data segment with specific data types and initial values.

Data Types


.DATA
; Byte data (8-bit)
char1    DB 'A'          ; Single character
char2    DB 65           ; ASCII value of 'A'
string1  DB 'Hello$'     ; String with $ terminator
buffer   DB 100 DUP(?)   ; 100 uninitialized bytes
pattern  DB 0, 1, 2, 3, 4; Array of bytes

; Word data (16-bit)
num1     DW 1234H        ; Hexadecimal word
num2     DW 5678         ; Decimal word
array16  DW 10 DUP(0)    ; 10 words initialized to 0
pointer  DW OFFSET string1; Offset address

; Double word (32-bit)
long1    DD 12345678H    ; 32-bit value
real1    DD 3.14159      ; Floating point (if supported)

; Constants
MAX_SIZE EQU 100         ; Symbolic constant
PI       EQU 3.14159     ; Floating point constant

Advanced Data Declarations


; Structure definition (simplified)
STUDENT STRUC
    name    DB 20 DUP(?)  ; Student name (20 chars)
    age     DW ?          ; Age (word)
    grade   DB ?          ; Grade (byte)
STUDENT ENDS

; Structure variables
student1 STUDENT <'John Doe', 20, 'A'>
student2 STUDENT <>       ; Uninitialized

; Far pointer
farptr   DD 12345678H    ; Segment:Offset pointer

Basic Programming Examples

Example 1: Simple Addition Program


.MODEL SMALL
.STACK 100H
.DATA
    num1 DW 25
    num2 DW 35
    result DW ?

.CODE
START:
    MOV AX, @DATA
    MOV DS, AX
    
    MOV AX, num1    ; Load first number
    ADD AX, num2    ; Add second number
    MOV result, AX  ; Store result
    
    MOV AH, 4CH     ; Exit program
    INT 21H
END START

Example 2: Display Character


.MODEL SMALL
.STACK 100H

.CODE
START:
    MOV AH, 02H     ; DOS display character function
    MOV DL, 'A'     ; Character to display
    INT 21H         ; Call DOS interrupt
    
    MOV AH, 4CH     ; Exit program
    INT 21H
END START

Example 3: Display String


.MODEL SMALL
.STACK 100H
.DATA
    message DB 'Hello, World!$'

.CODE
START:
    MOV AX, @DATA
    MOV DS, AX
    
    MOV AH, 09H         ; DOS display string function
    MOV DX, OFFSET message
    INT 21H             ; Call DOS interrupt
    
    MOV AH, 4CH         ; Exit program
    INT 21H
END START

Input/Output Operations

I/O operations in 8086 assembly use DOS interrupts for character and string input/output.

Loading diagram...

Character Input/Output


; Character input
MOV AH, 01H         ; DOS character input function
INT 21H             ; Call DOS interrupt
; Character returned in AL

; Character output
MOV AH, 02H         ; DOS character output function
MOV DL, 'A'         ; Character to display
INT 21H             ; Call DOS interrupt

; Character input without echo
MOV AH, 08H         ; DOS character input (no echo)
INT 21H             ; Character in AL

String Input/Output


.DATA
    input_buffer DB 50, ?, 50 DUP(?)  ; Max length, actual length, buffer
    output_msg   DB 'Enter text: $'
    result_msg   DB 'You entered: $'

.CODE
    ; Display prompt
    MOV AH, 09H
    MOV DX, OFFSET output_msg
    INT 21H
    
    ; Input string
    MOV AH, 0AH
    MOV DX, OFFSET input_buffer
    INT 21H
    
    ; Display result message
    MOV AH, 09H
    MOV DX, OFFSET result_msg
    INT 21H

Complete I/O Example


.MODEL SMALL
.STACK 100H
.DATA
    prompt DB 'Enter a character: $'
    result DB 'You entered: $'
    newline DB 0DH, 0AH, '$'

.CODE
START:
    MOV AX, @DATA
    MOV DS, AX
    
    ; Display prompt
    MOV AH, 09H
    MOV DX, OFFSET prompt
    INT 21H
    
    ; Input character
    MOV AH, 01H
    INT 21H
    MOV BL, AL      ; Save input character
    
    ; New line
    MOV AH, 09H
    MOV DX, OFFSET newline
    INT 21H
    
    ; Display result message
    MOV AH, 09H
    MOV DX, OFFSET result
    INT 21H
    
    ; Display the character
    MOV AH, 02H
    MOV DL, BL
    INT 21H
    
    MOV AH, 4CH
    INT 21H
END START

Control Structures

Assembly language uses labels and conditional jumps to implement control structures like loops and conditions.

If-Then-Else Structure


; Check if AL is positive, negative, or zero
CMP AL, 0           ; Compare AL with 0
JZ  ZERO_CASE       ; Jump if zero
JS  NEGATIVE_CASE   ; Jump if negative (sign flag set)

; Positive case
MOV DL, 'P'         ; Positive indicator
JMP DISPLAY

NEGATIVE_CASE:
    MOV DL, 'N'     ; Negative indicator
    JMP DISPLAY

ZERO_CASE:
    MOV DL, 'Z'     ; Zero indicator

DISPLAY:
    MOV AH, 02H     ; Display character
    INT 21H

For Loop Structure


; Display numbers 1 to 10
MOV CX, 10          ; Loop counter
MOV AL, 1           ; Starting number

FOR_LOOP:
    ADD AL, 30H     ; Convert to ASCII
    MOV AH, 02H     ; Display character function
    MOV DL, AL      ; Character to display
    INT 21H
    
    SUB AL, 30H     ; Convert back to number
    INC AL          ; Next number
    LOOP FOR_LOOP   ; Decrement CX and loop if CX ≠ 0

While Loop Structure


; Input characters until 'q' is entered
WHILE_LOOP:
    MOV AH, 01H     ; Input character
    INT 21H
    
    CMP AL, 'q'     ; Check for quit character
    JE END_WHILE    ; Exit loop if 'q'
    
    ; Process character (example: convert to uppercase)
    CMP AL, 'a'
    JL DISPLAY
    CMP AL, 'z'
    JG DISPLAY
    SUB AL, 20H     ; Convert to uppercase
    
DISPLAY:
    MOV AH, 02H     ; Display character
    MOV DL, AL
    INT 21H
    
    JMP WHILE_LOOP  ; Continue loop

END_WHILE:

Procedures and Functions

Procedures provide code modularity and reusability in assembly programming.

Loading diagram...

Simple Procedure Example


.MODEL SMALL
.STACK 100H

.CODE
START:
    CALL DISPLAY_HELLO  ; Call procedure
    CALL DISPLAY_HELLO  ; Call again
    
    MOV AH, 4CH         ; Exit program
    INT 21H

; Procedure definition
DISPLAY_HELLO PROC
    MOV AH, 02H         ; Display character function
    MOV DL, 'H'
    INT 21H
    MOV DL, 'i'
    INT 21H
    MOV DL, '!'
    INT 21H
    RET                 ; Return to caller
DISPLAY_HELLO ENDP

END START

Procedure with Parameters


; Procedure to display a character multiple times
; Input: AL = character, CX = count
REPEAT_CHAR PROC
    PUSH AX             ; Save registers
    PUSH DX
    
REPEAT_LOOP:
    MOV AH, 02H         ; Display character function
    MOV DL, AL          ; Character to display
    INT 21H
    LOOP REPEAT_LOOP    ; Repeat CX times
    
    POP DX              ; Restore registers
    POP AX
    RET
REPEAT_CHAR ENDP

; Usage example
MOV AL, '*'             ; Character to repeat
MOV CX, 5               ; Number of times
CALL REPEAT_CHAR        ; Call procedure

Procedure with Stack Parameters


; Add two numbers using stack parameters
; Parameters pushed in order: second number, first number
ADD_NUMBERS PROC
    PUSH BP             ; Save base pointer
    MOV BP, SP          ; Set up stack frame
    
    MOV AX, [BP+4]      ; Get first parameter
    ADD AX, [BP+6]      ; Add second parameter
    ; Result in AX
    
    POP BP              ; Restore base pointer
    RET 4               ; Return and clean 4 bytes from stack
ADD_NUMBERS ENDP

; Usage example
PUSH 25                 ; Second number
PUSH 15                 ; First number
CALL ADD_NUMBERS        ; Result in AX = 40

Array and String Processing

Arrays and strings are fundamental data structures that require special handling in assembly language.

Array Initialization and Access


.DATA
    numbers DW 10, 20, 30, 40, 50      ; Array of words
    count   EQU ($-numbers)/2           ; Number of elements

.CODE
    ; Initialize array pointer
    MOV SI, OFFSET numbers              ; Point to array start
    MOV CX, count                       ; Number of elements
    
    ; Process each element
PROCESS_ARRAY:
    MOV AX, [SI]                        ; Load current element
    ADD AX, 100                         ; Process element (add 100)
    MOV [SI], AX                        ; Store back to array
    ADD SI, 2                           ; Move to next word
    LOOP PROCESS_ARRAY

Finding Maximum in Array


FIND_MAX PROC
    ; Input: SI = array address, CX = count
    ; Output: AX = maximum value
    
    MOV AX, [SI]        ; Initialize max with first element
    ADD SI, 2           ; Move to second element
    DEC CX              ; Decrease count
    
COMPARE_LOOP:
    CMP AX, [SI]        ; Compare current max with array element
    JGE NEXT            ; Jump if current max &gt;= array element
    MOV AX, [SI]        ; Update max
    
NEXT:
    ADD SI, 2           ; Move to next element
    LOOP COMPARE_LOOP
    
    RET
FIND_MAX ENDP

String Length Calculation


STRING_LENGTH PROC
    ; Input: SI = string address
    ; Output: AX = string length
    
    PUSH SI             ; Save original pointer
    MOV AX, 0           ; Initialize length counter
    
COUNT_LOOP:
    CMP BYTE PTR [SI], '$'  ; Check for string terminator
    JE DONE                 ; Exit if terminator found
    INC AX                  ; Increment length
    INC SI                  ; Move to next character
    JMP COUNT_LOOP
    
DONE:
    POP SI              ; Restore original pointer
    RET
STRING_LENGTH ENDP

String Copy Procedure


STRING_COPY PROC
    ; Input: SI = source, DI = destination
    ; Copies string until '$' terminator
    
COPY_LOOP:
    MOV AL, [SI]        ; Load source character
    MOV [DI], AL        ; Store to destination
    CMP AL, '$'         ; Check for terminator
    JE COPY_DONE        ; Exit if terminator
    INC SI              ; Move source pointer
    INC DI              ; Move destination pointer
    JMP COPY_LOOP
    
COPY_DONE:
    RET
STRING_COPY ENDP

Mathematical Operations

Complex mathematical operations often require special techniques in assembly language.

Multi-precision Arithmetic


; 32-bit addition: (DX:AX) + (CX:BX) -&gt; (DX:AX)
ADD32 PROC
    ADD AX, BX          ; add low word
    ADC DX, CX          ; add high word with carry
    RET
ADD32 ENDP

; 32-bit subtraction: (DX:AX) - (CX:BX) -&gt; (DX:AX)
SUB32 PROC
    SUB AX, BX          ; subtract low word
    SBB DX, CX          ; subtract high word with borrow
    RET
SUB32 ENDP

Square Root Calculation (Integer)


; Integer square root using iterative approximation
; Input: AX = N (0..FFFF)
; Output: AX = floor(sqrt(N))
ISQRT PROC
    MOV DX, AX          ; DX = N (preserve)
    CMP AX, 1
    JBE ISQRT_DONE      ; sqrt(0)=0, sqrt(1)=1
    MOV BX, AX
    SHR BX, 1           ; initial guess = N/2
ISQ_LOOP:
    MOV AX, DX          ; AX = N
    XOR CX, CX
    DIV BX              ; AX = N/guess , remainder in DX
    ADD AX, BX          ; AX = guess + N/guess
    SHR AX, 1           ; average
    CMP AX, BX
    JE ISQRT_DONE       ; converged
    MOV BX, AX          ; new guess
    JMP ISQ_LOOP
ISQRT_DONE:
    MOV AX, BX          ; result in AX
    RET
ISQRT ENDP

Binary to Decimal Conversion


BIN_TO_DEC PROC
    ; Convert 16-bit binary in AX to decimal string
    ; Output string stored at DI
    PUSH DI             ; Save destination pointer
    MOV BX, 10          ; Divisor for decimal conversion
    MOV CX, 0           ; Digit counter

CONVERT_LOOP:
    MOV DX, 0           ; Clear upper part
    DIV BX              ; Divide by 10
    PUSH DX             ; Save remainder (digit)
    INC CX              ; Count digits
    CMP AX, 0           ; Check if quotient is zero
    JNE CONVERT_LOOP    ; Continue if not zero

STORE_DIGITS:           ; Pop digits and store as characters
    POP DX              ; Get digit
    ADD DL, '0'         ; Convert to ASCII
    MOV [DI], DL        ; Store
    INC DI
    LOOP STORE_DIGITS
    MOV BYTE PTR [DI], '$'
    POP DI              ; Restore dest
    RET
BIN_TO_DEC ENDP

Example 2: Prime Number Checker (Revised)


.MODEL SMALL
.STACK 100H
.DATA
    prompt      DB 'Enter a number (1-99): $'
    prime_msg   DB ' is Prime$'
    notprime_msg DB ' is NOT Prime$'
    newline     DB 0DH, 0AH, '$'
    num_storage DB ?

.CODE
START:
    MOV AX, @DATA
    MOV DS, AX

    MOV AH, 09H
    MOV DX, OFFSET prompt
    INT 21H

    ; Read first digit
    MOV AH, 01H
    INT 21H
    SUB AL, '0'
    MOV BL, AL          ; tens

    ; Read second digit (optional ENTER check omitted for brevity)
    MOV AH, 01H
    INT 21H
    SUB AL, '0'
    MOV BH, AL          ; ones

    MOV AL, BL
    MOV AH, 0
    MOV CL, 10
    MUL CL              ; AX = tens*10
    ADD AL, BH          ; add ones
    MOV num_storage, AL ; save number
    MOV BL, AL          ; BL = number to test

    CALL CHECK_PRIME    ; returns AH=1 if prime

    ; New line
    MOV AH, 09H
    MOV DX, OFFSET newline
    INT 21H

    ; Display number (simple: only two digits, no leading zero handling)
    MOV AL, num_storage
    MOV AH, 0
    MOV CL, 10
    DIV CL              ; AL= quotient (tens), AH = remainder (ones)
    ADD AL, '0'
    MOV DL, AL
    MOV AH, 02H
    INT 21H
    ADD AH, '0'
    MOV DL, AH
    MOV AH, 02H
    INT 21H

    ; Space
    MOV DL, ' '
    MOV AH, 02H
    INT 21H

    CMP byte ptr [num_storage], 2
    JB NOT_PRIME_MSG    ; 0 or 1 are not prime
    CMP AH, 1           ; AH from CHECK_PRIME
    JNE NOT_PRIME_MSG

PRIME_MSG:
    MOV AH, 09H
    MOV DX, OFFSET prime_msg
    INT 21H
    JMP EXIT

NOT_PRIME_MSG:
    MOV AH, 09H
    MOV DX, OFFSET notprime_msg
    INT 21H

EXIT:
    MOV AH, 4CH
    INT 21H

; BL = number (2..99)  -&gt; AH=1 prime, AH=0 not prime
CHECK_PRIME PROC
    CMP BL, 2
    JE PRM
    MOV CL, 2
CHK_LOOP:
    MOV AL, BL
    MOV AH, 0
    DIV CL             ; AL= quotient, AH= remainder
    CMP AH, 0
    JE NOTP
    INC CL
    MOV AL, CL
    MOV AH, 0
    MUL CL             ; quick check CL*CL <= BL
    CMP AX, BL
    JB CHK_LOOP
PRM: MOV AH, 1
    RET
NOTP: MOV AH, 0
    RET
CHECK_PRIME ENDP
END START

Debugging and Testing

Effective debugging techniques are essential for assembly language programming.

Loading diagram...

Debugging Techniques

  • Use DEBUG.EXE: Step through instructions one by one
  • Insert Debug Output: Display register values at key points
  • Check Flags: Monitor flag changes after operations
  • Verify Stack: Ensure proper PUSH/POP balance
  • Test Edge Cases: Zero values, maximum values, negative numbers

Debug Output Example


; Debug procedure to display AX in hexadecimal
DISPLAY_AX_HEX PROC
    PUSH AX
    PUSH BX
    PUSH CX
    PUSH DX
    
    MOV CX, 4       ; 4 hex digits
    
DISPLAY_LOOP:
    MOV BX, AX
    SHR BX, 12      ; Get upper 4 bits
    AND BX, 0FH     ; Mask lower bits
    
    CMP BL, 9
    JLE DIGIT
    ADD BL, 7       ; Convert A-F
    
DIGIT:
    ADD BL, '0'     ; Convert to ASCII
    MOV AH, 02H
    MOV DL, BL
    INT 21H
    
    SHL AX, 4       ; Shift for next digit
    LOOP DISPLAY_LOOP
    
    POP DX
    POP CX
    POP BX
    POP AX
    RET
DISPLAY_AX_HEX ENDP

Testing Framework


; Simple testing procedure
TEST_ADDITION PROC
    ; Test case 1: 5 + 3 = 8
    MOV AL, 5
    MOV BL, 3
    ADD AL, BL
    CMP AL, 8
    JE TEST1_PASS
    ; Handle test failure
    
TEST1_PASS:
    ; Test case 2: 255 + 1 = 0 (overflow)
    MOV AL, 255
    MOV BL, 1
    ADD AL, BL
    CMP AL, 0
    JE TEST2_PASS
    ; Handle test failure
    
TEST2_PASS:
    ; All tests passed
    RET
TEST_ADDITION ENDP

Programming Best Practices

Following best practices leads to maintainable and efficient assembly code.

Loading diagram...

Code Organization Guidelines

  • Use meaningful labels: CALC_TOTAL instead of LABEL1
  • Comment extensively: Explain purpose, not just operation
  • Group related code: Keep procedures together
  • Consistent indentation: Use tabs or spaces consistently
  • Separate data and code: Clear segment organization

Performance Optimization

  • Register usage: Keep frequently used data in registers
  • Instruction selection: Use faster equivalents (XOR AX,AX vs MOV AX,0)
  • Loop optimization: Minimize operations inside loops
  • Address calculation: Use LEA for complex address arithmetic

Error Handling


; Example with error checking
SAFE_DIVIDE PROC
    ; Input: AX = dividend, BX = divisor
    ; Output: AX = quotient, DX = remainder, CF = error flag
    
    CMP BX, 0           ; Check for division by zero
    JE DIV_ERROR
    
    MOV DX, 0           ; Clear remainder
    DIV BX              ; Perform division
    CLC                 ; Clear carry flag (no error)
    RET
    
DIV_ERROR:
    STC                 ; Set carry flag (error)
    RET
SAFE_DIVIDE ENDP

Suggetested Articles