Lesson 11 of 48 intermediate

8086 Register Set

The 8086's fourteen registers — your processor's fast scratchpad for data, addresses, and status

Open interactive version (quiz + challenge)

Real-world analogy

Think of registers as the pockets in a chef's apron. The chef (EU) keeps the most-used ingredients in these pockets for instant access, instead of walking to the pantry (memory) every time. AX through DX are like four big pockets for ingredients (data). SP and BP are like the left hand managing a stack of plates. SI and DI are fingers pointing at recipe cards (arrays). CS, DS, SS, ES are labels on different pantry shelves (memory segments). The Flags register is a checklist clipped to the apron — did the last recipe overflow? Was the result zero?

What is it?

The 8086 has fourteen 16-bit registers organized into four groups. Four general-purpose registers (AX, BX, CX, DX) handle data and arithmetic, with each splittable into two 8-bit halves. Two pointer registers (SP, BP) manage the stack. Two index registers (SI, DI) support array and string operations. Four segment registers (CS, DS, SS, ES) define 64 KB windows into the 1 MB address space. The Flags register holds status and control bits. The Instruction Pointer (IP) tracks the next instruction to execute. Together, these 14 registers form the complete programmer-visible state of the 8086.

Real-world relevance

Every x86-64 register you use today is a direct extension of the original 8086 registers. EAX (32-bit) and RAX (64-bit) are extensions of AX. When you debug C code and see variables stored in EAX, ESP, or EDI, you are looking at the grandchildren of the 8086 registers. Compilers still respect the implicit roles: ECX for loop counters, EAX for return values, ESP for the stack pointer — conventions that trace directly back to the 8086.

Key points

Code example

; Demonstrate all four register groups
.MODEL SMALL
.STACK 100h
.DATA
  nums  DW 10, 20, 30, 40, 50
  count DW 5
  sum   DW 0

.CODE
MAIN PROC
  MOV AX, @DATA     ; setup segment register (DS)
  MOV DS, AX

  ; General-purpose registers
  XOR AX, AX        ; AX = accumulator = 0
  MOV CX, [count]   ; CX = counter = 5
  LEA BX, nums      ; BX = base address of array

  ; Index register
  XOR SI, SI         ; SI = index = 0

  ; Loop using CX counter and SI index
add_loop:
  ADD AX, [BX+SI]   ; AX += nums[SI] (base+index)
  ADD SI, 2          ; next word (2 bytes)
  LOOP add_loop      ; CX-- and loop if CX != 0

  MOV [sum], AX      ; store result to memory

  ; Pointer registers demonstrated
  PUSH AX            ; SP decremented, AX on stack
  MOV BP, SP         ; BP = stack frame pointer
  MOV DX, [BP]       ; DX = value at top of stack
  POP AX             ; restore AX, SP incremented

  MOV AH, 4Ch
  INT 21h
MAIN ENDP
END MAIN

Line-by-line walkthrough

  1. 1. MOV AX, @DATA / MOV DS, AX — loads the data segment address into DS via AX. This is a segment register setup using a general-purpose register as intermediary
  2. 2. XOR AX, AX — zeroes AX by XOR-ing it with itself. Faster and shorter than MOV AX, 0. AX will be our sum accumulator
  3. 3. MOV CX, [count] — loads 5 into CX from memory. CX will serve its role as the loop counter for the LOOP instruction
  4. 4. LEA BX, nums — loads the offset address of the nums array into BX. BX serves its role as the base register for array addressing
  5. 5. XOR SI, SI — zeroes SI. It will be our index offset into the array, incrementing by 2 each iteration (word-sized elements)
  6. 6. ADD AX, [BX+SI] — base+index addressing. The physical address is DS*16 + BX + SI. Adds the word at that address to AX
  7. 7. ADD SI, 2 — advances SI by 2 bytes (one word) to point to the next array element
  8. 8. LOOP add_loop — decrements CX, jumps back if CX != 0. After 5 iterations, AX = 10+20+30+40+50 = 150
  9. 9. PUSH AX / MOV BP, SP / MOV DX, [BP] / POP AX — demonstrates pointer registers: PUSH modifies SP, BP accesses the stack frame, POP restores SP

Spot the bug

MOV CX, 5
MOV SI, 0
MOV AX, 0
add_loop:
  ADD AX, [SI]     ; read array element
  ADD SI, 2
  LOOP add_loop
Need a hint?
SI is being used as the only address. What segment and base address is being used? Where is the array actually located?
Show answer
The code uses [SI] without a base register, so it reads from DS:SI starting at offset 0 — which is NOT where the array is stored. It should be ADD AX, [BX+SI] where BX holds the array's offset, or use a direct reference like ADD AX, nums[SI]. Without the base address, the code reads arbitrary data from the beginning of the data segment.

Explain like I'm 5

Your brain has quick-access thoughts — like remembering your phone number or your name. You do not have to look them up; they are just there. Registers are like that for the CPU — tiny super-fast storage slots right inside the processor. AX is the main 'thinking' register (it does most math), CX counts things (like fingers), BX points to stuff (like your index finger pointing at a list), and SP keeps track of a pile of papers (the stack). The CPU can use registers instantly but has to go on a field trip to use memory.

Fun fact

The 8086's register names are not arbitrary letters. AX stands for Accumulator, BX for Base, CX for Counter, DX for Data, SP for Stack Pointer, BP for Base Pointer, SI for Source Index, DI for Destination Index. Intel engineers named them by function because they wanted assembly programmers to immediately know each register's primary purpose. These names survived for 45+ years.

Hands-on challenge

Write an 8086 assembly program that uses all four general-purpose registers (AX, BX, CX, DX) simultaneously. The program should: load an array base address into BX, use CX as a loop counter of 5, accumulate a sum in AX, and store the final result using DX as an intermediate. Also demonstrate accessing AH and AL separately to split a 16-bit result into high and low bytes.

More resources

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