Memory, Addressing, and I/O Concepts
How the CPU finds and accesses data — the memory map, addressing modes, and the I/O subsystem
Open interactive version (quiz + challenge)Real-world analogy
What is it?
Memory in the 8086 system is a 1 MB address space (00000h-FFFFFh) accessed through segmentation, where physical address = segment * 16 + offset. The CPU supports multiple addressing modes — immediate, register, direct, register indirect, based, indexed, and combinations — to flexibly specify where data lives. I/O is accessed either through a separate 64 KB port space (using IN/OUT instructions) or through memory-mapped addresses. Address decoding hardware ensures the right chip responds to each address.
Real-world relevance
When your computer boots, the CPU fetches its first instruction from ROM at address FFFF0h — that's a direct result of the memory map design. When you type on a keyboard, the CPU reads I/O port 60h using IN AL, 60h. When a program accesses video memory, it writes to addresses starting at B8000h (memory-mapped I/O). Understanding the memory map and addressing modes is essential for writing device drivers, BIOS code, bootloaders, and any software that interacts directly with hardware.
Key points
- The 8086 Memory Space — 1 MB — The 8086 has a 20-bit address bus giving access to 2^20 = 1,048,576 bytes (1 MB) of memory, addressed from 00000h to FFFFFh. This memory is shared between RAM, ROM, and memory-mapped devices. The programmer sees a flat 1 MB space, but it is physically divided into segments for access using 16-bit registers.
- Segmented Memory Architecture — Since the 8086 has only 16-bit registers but needs 20-bit addresses, it uses segmentation. A physical address is calculated as: Segment * 16 + Offset (or equivalently, Segment << 4 + Offset). This means multiple segment:offset pairs can point to the same physical address — for example, 1000:0050 and 0FFF:0060 both equal 10050h.
- RAM vs ROM — RAM (Random Access Memory) is volatile read-write memory — it loses content when power is off. ROM (Read-Only Memory) is non-volatile and retains its content permanently. The 8086 system puts the BIOS in ROM at the top of the memory map (near FFFFFh) and user programs/data in RAM at the bottom. The reset vector must be in ROM because RAM is empty at power-on.
- Addressing Modes — How the CPU Specifies Operands — The 8086 supports multiple addressing modes that determine how the operand's location is calculated. These range from simple (the data is in the instruction itself) to complex (the address is computed from multiple registers plus a displacement). Mastering addressing modes is key to writing efficient assembly code.
- Direct Addressing — In direct addressing, the memory address is specified as a constant in the instruction. The CPU computes the physical address as DS*16 + displacement. This is simple and clear but inflexible — you can only access one fixed location. Useful for accessing known variables at fixed addresses.
- Register Indirect and Based Addressing — Register indirect addressing uses a register (BX, SI, DI, or BP) to hold the address. Based addressing adds a constant displacement to the register. This enables dynamic memory access — like array traversal and structure field access — because the register can be changed at runtime.
- Based + Indexed Addressing — The most powerful mode combines a base register (BX or BP), an index register (SI or DI), and an optional displacement. This is ideal for accessing elements of 2D arrays or fields within arrays of structures. The effective address = base + index + displacement.
- Memory-Mapped I/O vs Port-Mapped I/O — The 8086 supports two methods for accessing peripherals. Memory-mapped I/O treats device registers as memory addresses — you use MOV to read/write them. Port-mapped I/O uses a separate 64 KB I/O address space (0000h-FFFFh) accessed with special IN and OUT instructions. The M/IO pin distinguishes the two.
- The I/O Address Space — The 8086 has a separate 16-bit I/O address space with 65,536 ports (0000h-FFFFh). Ports 00h-FFh can be accessed with direct addressing (IN AL, port). Ports 0000h-FFFFh require indirect addressing through DX (IN AL, DX). Common ports include 60h (keyboard), 3F8h (COM1 serial), and 20h (PIC interrupt controller).
- Address Decoding — Address decoding is the hardware logic that determines which memory or I/O chip responds to a given address. Upper address bits are fed into a decoder (like the 74138) that generates chip-select signals. When the CPU puts an address on the bus, only the selected chip activates. Without proper decoding, multiple chips would conflict on the data bus.
Code example
; Demonstrating memory addressing modes and I/O on 8086
; --- Setup ---
MOV AX, 1000h
MOV DS, AX ; DS = 1000h (data segment)
MOV AX, 2000h
MOV SS, AX ; SS = 2000h (stack segment)
MOV SP, 0FFEh ; SP = top of stack area
; --- Immediate Addressing ---
MOV AX, 1234h ; AX = 1234h (value in instruction)
MOV CX, 0005h ; CX = 5 (loop counter)
; --- Direct Addressing ---
MOV [0100h], AX ; store 1234h at DS:0100h
; physical = 10000h + 0100h = 10100h
; --- Register Indirect ---
MOV BX, 0100h
MOV DX, [BX] ; DX = value at DS:BX = DS:0100h
; DX now = 1234h
; --- Based Addressing (array access) ---
MOV BX, 0200h ; BX = base of array
MOV AX, [BX+0] ; element 0
MOV AX, [BX+2] ; element 1
MOV AX, [BX+4] ; element 2
; --- Based + Indexed (2D array) ---
MOV BX, 0300h ; base of 2D table
MOV SI, 0010h ; row offset
MOV AX, [BX+SI+4] ; table[row][col]
; EA = 0300h + 0010h + 4 = 0314h
; --- Stack Addressing (BP-based) ---
PUSH 0042h ; push value onto stack
MOV BP, SP
MOV AX, [BP+0] ; read top of stack via BP
; uses SS segment: SS:BP
; --- I/O Port Access ---
IN AL, 60h ; port-mapped I/O: read keyboard port
; M/IO = 0, address bus = 0060h
MOV DX, 03F8h
IN AL, DX ; read COM1 serial port data
; indirect port addressing via DX
; --- Memory-Mapped I/O (video memory) ---
MOV AX, 0B800h
MOV ES, AX ; ES points to video memory
MOV DI, 0000h
MOV WORD [ES:DI], 0741h ; write 'A' (41h) in white (07h)
; to top-left of text screen
HLTLine-by-line walkthrough
- 1. We start by setting up segment registers. DS=1000h means our data area starts at physical address 10000h. SS=2000h with SP=0FFEh means our stack grows downward from physical address 20FFEh.
- 2. MOV AX, 1234h demonstrates immediate addressing — the value 1234h is encoded right in the instruction bytes. No memory access needed beyond the instruction fetch.
- 3. MOV [0100h], AX uses direct addressing. The assembler encodes 0100h as a displacement in the instruction. Physical address = DS*16 + 0100h = 10100h. The data bus carries 1234h from AX to memory.
- 4. MOV BX, 0100h / MOV DX, [BX] shows register indirect addressing. BX holds the offset, and the CPU computes DS*16 + BX to find the physical address. The value at that address (1234h, which we stored earlier) loads into DX.
- 5. The based addressing section (MOV AX, [BX+0], [BX+2], [BX+4]) treats BX as the base of an array. Adding 0, 2, 4 accesses consecutive 16-bit elements — this is how you walk through arrays in assembly.
- 6. MOV AX, [BX+SI+4] is the most powerful mode: based + indexed + displacement. BX is the table base, SI is the row offset, and 4 is the column offset. The CPU adds all three to compute the effective address.
- 7. Stack access via BP (MOV AX, [BP+0]) automatically uses the SS segment instead of DS. This is how functions access their parameters and local variables on the stack.
- 8. IN AL, 60h shows port-mapped I/O. The address bus carries 0060h, M/IO is set to 0 (selecting I/O space), and the keyboard controller responds with the scan code on the data bus.
- 9. The video memory write (MOV WORD [ES:DI], 0741h) is memory-mapped I/O. ES points to segment B800h (video RAM), and writing 0741h places the character 'A' (41h) with white attribute (07h) at the top-left screen position.
Spot the bug
; Program to copy 10 bytes from source to destination
; Source: DS:1000h
; Destination: DS:2000h
MOV AX, 3000h
MOV DS, AX ; DS = 3000h
MOV SI, 1000h ; source offset
MOV DI, 2000h ; destination offset
MOV CX, 10 ; 10 bytes to copy
COPY_LOOP:
MOV AL, [SI] ; read byte from DS:SI
MOV [DI], AL ; write byte to DS:DI
INC SI
INC DI
DEC CX
JNZ COPY_LOOP
; BUG: What if source is at DS:1000h and
; destination needs to be in a DIFFERENT segment?Need a hint?
Show answer
Explain like I'm 5
Fun fact
Hands-on challenge
More resources
- 8086 Addressing Modes (GeeksforGeeks)
- Memory Organization in 8086 (YouTube)
- 8086 I/O Interfacing (TutorialsPoint)
- x86 Memory Segmentation (Wikipedia)