Lesson 38 of 48 intermediate

I/O-Mapped vs Memory-Mapped I/O

Two Ways to Talk to Peripherals

Open interactive version (quiz + challenge)

Real-world analogy

Imagine your house has two types of doors. Memory-mapped I/O is like having peripheral devices (TV, fridge, washing machine) inside rooms along the same hallway as your bedrooms — same address system, same keys. I/O-mapped (isolated) I/O is like having a separate service entrance with its own numbering — the postman uses one door, the delivery guy uses another, and they never confuse each other.

What is it?

I/O-mapped (isolated) I/O uses separate IN/OUT instructions and a dedicated 64KB address space to access peripherals, signaled by M/IO=0. Memory-mapped I/O places device registers in the normal memory address space and uses standard MOV/ADD/CMP instructions, signaled by M/IO=1. The 8086 supports both methods, and most real systems use a combination of both.

Real-world relevance

Your PC still uses both methods today. When your OS reads the keyboard controller, it uses IN/OUT instructions (I/O-mapped). When your GPU driver writes pixels, it writes to memory-mapped video RAM. The PCI Express bus on modern computers is entirely memory-mapped — every PCIe device gets a range of physical addresses.

Key points

Code example

; =============================================
; I/O-Mapped vs Memory-Mapped I/O Comparison
; =============================================
;
; === I/O-Mapped (Isolated) I/O ===
; Access a device at I/O port 60h:
;
  IN AL, 60h           ; read byte from port 60h
                        ; M/IO = 0 (I/O cycle)
                        ; address bus = 0060h
  OR AL, 80h           ; process in register
  OUT 60h, AL          ; write back to port 60h
;
; === Memory-Mapped I/O ===
; Access a device at memory address B8000h:
;
  MOV AX, 0B800h
  MOV ES, AX           ; point ES to device
  MOV AL, ES:[0]       ; read from device
                        ; M/IO = 1 (memory cycle)
                        ; address bus = B8000h
  OR ES:[0], 80h       ; modify device register DIRECTLY
                        ; (can't do this with I/O-mapped!)
;
; Key difference: I/O-mapped uses IN/OUT only
; Memory-mapped can use ANY memory instruction

Line-by-line walkthrough

  1. 1. Title comment for the I/O comparison
  2. 2. Separator line
  3. 3. Blank line
  4. 4. Section header: I/O-Mapped (Isolated) I/O
  5. 5. Comment: accessing a device at I/O port 60h
  6. 6. Blank line
  7. 7. IN AL, 60h — special instruction reads one byte from port 60h into AL
  8. 8. Comment: M/IO pin goes LOW (0) telling hardware this is an I/O cycle
  9. 9. Comment: only the lower 16 address bits carry the port address
  10. 10. OR AL, 80h — manipulate the data in a register (set bit 7)
  11. 11. OUT 60h, AL — write the modified byte back to port 60h
  12. 12. Blank line
  13. 13. Section header: Memory-Mapped I/O
  14. 14. Comment: accessing a device at memory address B8000h
  15. 15. Blank line
  16. 16. Load segment value 0B800h into AX
  17. 17. Move AX into ES segment register (ES now points to B8000h)
  18. 18. Read a byte from ES:[0] which is physical address B8000h — the device register
  19. 19. Comment: M/IO pin goes HIGH (1) because this is a normal memory cycle
  20. 20. Comment: the full 20-bit address appears on the bus
  21. 21. OR ES:[0], 80h — directly modify the device register in place using OR instruction
  22. 22. Comment: this direct-modify trick is impossible with I/O-mapped I/O
  23. 23. Blank line
  24. 24. Summary: I/O-mapped is limited to IN/OUT instructions
  25. 25. Memory-mapped can leverage the entire instruction set on device registers

Spot the bug

; Read from I/O port 300h
;
  IN AL, 300h         ; read byte from port 300h
;
; Write to memory-mapped device at C0000h
;
  MOV AX, 0C000h
  MOV DS, AX
  OUT [0], AL          ; write to device
Need a hint?
Check the rules for IN instruction addressing and what instruction is used for memory-mapped I/O.
Show answer
Two bugs: (1) IN AL, 300h is invalid — direct port addressing only supports 8-bit addresses (0-FFh). For port 300h, use: MOV DX, 300h then IN AL, DX. (2) OUT [0], AL is wrong — OUT is for I/O ports only. For memory-mapped I/O, use MOV [0], AL (or MOV DS:[0], AL).

Explain like I'm 5

Imagine you live in a building with 100 apartments (that is your memory). I/O-mapped I/O is like having a separate little mailroom in the lobby with 10 mailboxes for sending packages to shops outside — you use a special 'send package' form (IN/OUT). Memory-mapped I/O is like giving one of the 100 apartments to a shop — now the shop has a door just like any apartment, and you visit it the same way you visit a neighbor (MOV). But now you only have 99 apartments left for people!

Fun fact

The Motorola 68000 processor (used in original Macintosh and Sega Genesis) had NO separate I/O space at all — everything was memory-mapped. Intel's x86 kept the separate I/O space for backward compatibility with the 8080, and it persists in x86-64 processors to this day, over 45 years later.

Hands-on challenge

Design address decoding for a system with: (1) 8KB RAM at 00000h-01FFFh (memory-mapped), (2) 8KB ROM at FE000h-FFFFFh (memory-mapped), and (3) an 8255 PPI at I/O ports 80h-83h (I/O-mapped). Show how M/IO is used in each chip select equation. Write sample code to read from all three.

More resources

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