Lesson 30 of 48 intermediate

Your First 8086 Program

Write, understand, and run complete assembly programs — from Hello World to arithmetic

Open interactive version (quiz + challenge)

Real-world analogy

Your first 8086 program is like your first recipe in the kitchen. You follow exact steps: gather ingredients (.DATA), prepare your workspace (initialize DS), follow the recipe (instructions), and serve the dish (display output). At first, even a simple recipe feels complex, but once you understand the pattern, you can cook anything.

What is it?

Your first 8086 programs combine everything learned so far: data definitions, register operations, arithmetic, and DOS interrupts for I/O. The core pattern is: initialize segments, read input, process data, display output, and exit cleanly. Even a 'Hello World' program teaches segment setup, string termination, and interrupt calling — foundational skills for all assembly programming.

Real-world relevance

Every developer's journey in any language starts with simple I/O programs. In assembly, these teach you the actual machine operations behind high-level abstractions. When you debug a crashed program and see register dumps, or write an embedded bootloader that must print diagnostics without an OS, these fundamentals are what you rely on.

Key points

Code example

; Program: Calculator — add, subtract, multiply two single-digit numbers
.MODEL SMALL
.STACK 100h
.DATA
  msg1  DB 'Enter first digit (0-9): $'
  msg2  DB 0Dh, 0Ah, 'Enter second digit (0-9): $'
  msg3  DB 0Dh, 0Ah, 'Sum: $'
  msg4  DB 0Dh, 0Ah, 'Difference: $'
  msg5  DB 0Dh, 0Ah, 'Product: $'
  num1  DB ?
  num2  DB ?

.CODE
MAIN PROC
  MOV AX, @DATA
  MOV DS, AX

  ; --- Read first number ---
  MOV AH, 09h
  LEA DX, msg1
  INT 21h
  MOV AH, 01h
  INT 21h            ; AL = ASCII digit
  SUB AL, 30h        ; convert to number
  MOV [num1], AL

  ; --- Read second number ---
  MOV AH, 09h
  LEA DX, msg2
  INT 21h
  MOV AH, 01h
  INT 21h
  SUB AL, 30h
  MOV [num2], AL

  ; --- Addition ---
  MOV AH, 09h
  LEA DX, msg3
  INT 21h
  MOV AL, [num1]
  ADD AL, [num2]     ; AL = sum (may be > 9)
  CALL print_al      ; display result

  ; --- Subtraction ---
  MOV AH, 09h
  LEA DX, msg4
  INT 21h
  MOV AL, [num1]
  SUB AL, [num2]     ; AL = difference
  CALL print_al

  ; --- Multiplication ---
  MOV AH, 09h
  LEA DX, msg5
  INT 21h
  MOV AL, [num1]
  MOV BL, [num2]
  MUL BL             ; AX = product
  CALL print_al

  ; --- Exit ---
  MOV AH, 4Ch
  INT 21h
MAIN ENDP

; Procedure: print number in AL (0-99)
print_al PROC NEAR
  CMP AL, 10
  JB  single_digit

  ; Two digits: divide by 10
  XOR AH, AH        ; clear AH
  MOV BL, 10
  DIV BL             ; AL = tens, AH = ones
  PUSH AX            ; save ones in AH

  ADD AL, 30h        ; tens digit to ASCII
  MOV DL, AL
  MOV AH, 02h
  INT 21h

  POP AX
  MOV AL, AH         ; ones digit

single_digit:
  ADD AL, 30h
  MOV DL, AL
  MOV AH, 02h
  INT 21h
  RET
print_al ENDP
END MAIN

Line-by-line walkthrough

  1. 1. MOV AX, @DATA / MOV DS, AX — initialize DS so we can access all variables defined in .DATA
  2. 2. MOV AH, 09h / LEA DX, msg1 / INT 21h — print the prompt 'Enter first digit (0-9): ' using DOS string output
  3. 3. MOV AH, 01h / INT 21h — wait for the user to type a character. The ASCII code goes into AL
  4. 4. SUB AL, 30h — convert ASCII to numeric value. If user typed '5' (ASCII 35h), AL becomes 5
  5. 5. MOV [num1], AL — save the numeric value into our data variable for later use
  6. 6. ADD AL, [num2] — add the two numbers. Result may exceed 9 (e.g., 7+8=15), so we need the two-digit display procedure
  7. 7. CALL print_al — call our procedure that handles both single and double digit display
  8. 8. In print_al: CMP AL, 10 / JB single_digit — if result is less than 10, just add 30h and print one character
  9. 9. For two digits: DIV BL divides AX by 10. AL gets the tens digit, AH gets the ones digit. Print each after converting to ASCII
  10. 10. MUL BL — unsigned multiply. AL * BL, result in AX. For single digits, the product fits in AL (max 9*9=81)

Spot the bug

MOV AH, 01h
INT 21h
MOV BL, AL      ; BL = first digit ASCII
MOV AH, 01h
INT 21h
ADD AL, BL      ; 'add' the two digits
MOV DL, AL
MOV AH, 02h
INT 21h
Need a hint?
What happens when you add two ASCII values? What is '3' + '5' in ASCII?
Show answer
The code adds ASCII values instead of numeric values. '3' (33h) + '5' (35h) = 68h = 'h'. The fix: subtract 30h from each digit before adding. After ADD, add 30h back to convert the sum to ASCII: SUB BL, 30h before saving, SUB AL, 30h before ADD, then ADD AL, 30h before display (for single-digit sums).

Explain like I'm 5

Imagine you are a waiter in a restaurant (the CPU). A customer (the user) tells you their order (keyboard input). You write it on a slip (register). You take it to the kitchen (ALU), where the chef adds ingredients together (ADD). Then you bring the dish back and show it to the customer (display output). The restaurant's opening and closing procedures (MOV DS, AX and INT 21h/4Ch) are the setup and cleanup you must always do.

Fun fact

The very first IBM PC in 1981 came with a BASIC interpreter in ROM, but power users would write assembly programs using DEBUG.COM — a tiny debugger built into DOS. You could type 'a 100' to start assembling at offset 100h, enter instructions line by line, and run them immediately. Many legendary DOS programs were first prototyped this way.

Hands-on challenge

Write a complete 8086 program that: (1) asks the user for two single-digit numbers, (2) displays their sum, difference, product, and quotient, (3) handles the case where the subtraction result is negative by printing a minus sign, and (4) handles division by zero by printing an error message.

More resources

Open interactive version (quiz + challenge) ← Back to course: Microprocessor A–Z