Lesson 42 of 48 advanced

8259 Programmable Interrupt Controller

Managing Hardware Interrupts with Priority

Open interactive version (quiz + challenge)

Real-world analogy

The 8259 PIC is like a hospital triage nurse. Eight patients (devices) arrive at the emergency room (interrupt lines IR0-IR7) simultaneously. The nurse (priority resolver) decides who sees the doctor (CPU) first based on urgency. The nurse also makes sure the doctor finishes with one patient before starting the next, unless someone more urgent arrives. ICW/OCW are the hospital policies that define how triage works.

What is it?

The 8259 PIC (Programmable Interrupt Controller) manages up to 8 hardware interrupt sources for the 8086 CPU. It contains priority resolution logic, masking capability, and vector generation. Initialized with ICW1-4 (setting trigger mode, vector base, cascade config, and 8086 mode), it is controlled during operation with OCW1-3 (masking, EOI, register reads). Multiple 8259s can be cascaded for up to 64 interrupts.

Real-world relevance

The IBM PC used two 8259A PICs in cascade (master at 20h-21h, slave at A0h-A1h) providing 15 interrupt channels. IRQ0 was the timer, IRQ1 the keyboard, IRQ6 the floppy drive. This architecture persisted until modern PCs replaced the 8259 with the APIC (Advanced PIC) for multi-core support — but even today, the APIC still emulates the 8259 for legacy compatibility during boot.

Key points

Code example

; =============================================
; 8259 PIC — Full Initialization and Usage
; =============================================
;
; Single 8259 at ports 20h (A0=0) and 21h (A0=1)
; Vectors: IR0=INT 08h, IR1=INT 09h, ..., IR7=INT 0Fh
;
; === INITIALIZATION ===
;
; ICW1: edge-triggered, cascade, ICW4 needed
  MOV AL, 11h           ; 0001 0001
  OUT 20h, AL
;
; ICW2: base vector = 08h
  MOV AL, 08h           ; IR0 → INT 08h
  OUT 21h, AL
;
; ICW3: master — slave on IR2
  MOV AL, 04h           ; bit 2 = 1 (slave on IR2)
  OUT 21h, AL
;
; ICW4: 8086 mode, normal EOI
  MOV AL, 01h           ; 0000 0001
  OUT 21h, AL
;
; === OPERATION ===
;
; Unmask Timer (IR0) and Keyboard (IR1):
  MOV AL, 0FCh          ; 1111 1100
  OUT 21h, AL           ; OCW1: IR0,IR1 enabled
;
; ISR for Timer (INT 08h):
TIMER_ISR:
  PUSH AX
  PUSH DS
  ; ... increment tick counter ...
  MOV AX, 0040h
  MOV DS, AX
  INC WORD PTR [006Ch]  ; BIOS tick counter
  MOV AL, 20h           ; non-specific EOI
  OUT 20h, AL
  POP DS
  POP AX
  IRET                  ; return from interrupt
;
; ISR for Keyboard (INT 09h):
KBD_ISR:
  PUSH AX
  IN AL, 60h            ; read scan code from keyboard
  ; ... process key ...
  MOV AL, 20h           ; EOI
  OUT 20h, AL
  POP AX
  IRET

Line-by-line walkthrough

  1. 1. Title comment for 8259 PIC setup
  2. 2. Separator line
  3. 3. Blank line
  4. 4. PIC is at I/O ports 20h (commands) and 21h (data/mask)
  5. 5. Vector mapping: IR0 maps to INT 08h, IR1 to INT 09h, and so on
  6. 6. Blank line
  7. 7. === INITIALIZATION SECTION ===
  8. 8. Blank line
  9. 9. ICW1: edge-triggered interrupts, cascade mode, ICW4 will follow
  10. 10. 11h = 00010001 in binary: bit4=1 starts init, bit0=1 means ICW4 needed
  11. 11. Write ICW1 to port 20h (A0=0 is required for ICW1)
  12. 12. Blank line
  13. 13. ICW2: set the base vector number — IR0 will map to INT 08h
  14. 14. Only the upper 5 bits matter (08h = 00001 000), IR number fills lower 3
  15. 15. Write ICW2 to port 21h (A0=1 for ICW2-4)
  16. 16. Blank line
  17. 17. ICW3: on the master, bit 2 set means a slave 8259 is connected to IR2
  18. 18. 04h = 00000100 — only IR2 has a cascade slave
  19. 19. Write ICW3 to port 21h
  20. 20. Blank line
  21. 21. ICW4: set 8086 mode (vs 8080) and normal EOI (not auto-EOI)
  22. 22. 01h = 00000001 — bit 0 = 1 means 8086/8088 mode
  23. 23. Write ICW4 to port 21h — initialization complete
  24. 24. Blank line
  25. 25. === OPERATION SECTION ===
  26. 26. Blank line
  27. 27. OCW1 sets the interrupt mask register
  28. 28. 0FCh = 11111100 — bits 0 and 1 are 0 (unmasked), enabling IR0 and IR1
  29. 29. Write mask to port 21h — only timer and keyboard can now interrupt
  30. 30. Blank line
  31. 31. Timer ISR label — CPU jumps here on INT 08h (timer tick)
  32. 32. Save AX and DS on stack (preserve caller's state)
  33. 33. Comment: perform the timer handler actions
  34. 34. Point DS to BIOS data segment at 0040h
  35. 35. Set DS to 0040h
  36. 36. Increment the 16-bit BIOS tick counter at 0040:006Ch
  37. 37. Load non-specific EOI command (20h) into AL
  38. 38. Send EOI to 8259 at port 20h — clears the ISR bit for this interrupt
  39. 39. Restore DS and AX from stack
  40. 40. Blank line
  41. 41. IRET returns from interrupt — restores IP, CS, and FLAGS
  42. 42. Blank line
  43. 43. Keyboard ISR label — CPU jumps here on INT 09h
  44. 44. Save AX
  45. 45. Read keyboard scan code from port 60h (keyboard controller)
  46. 46. Comment: process the key (buffer it, translate to ASCII, etc.)
  47. 47. Send EOI to 8259
  48. 48. Blank line
  49. 49. Restore AX and return from interrupt

Spot the bug

; Initialize 8259 at port 20h/21h:
;
  MOV AL, 11h
  OUT 20h, AL          ; ICW1
;
  MOV AL, 20h
  OUT 21h, AL          ; ICW2: base vector 20h
;
  MOV AL, 01h
  OUT 21h, AL          ; ICW4: 8086 mode
;
; Unmask IR0:
  MOV AL, 0FEh
  OUT 21h, AL          ; OCW1
;
; Timer ISR:
TIMER:
  ; handle timer...
  IRET
Need a hint?
ICW1 specified cascade mode (bit SNGL=0), but how many ICW words were actually written? Count them.
Show answer
ICW1 sets SNGL=0 (cascade mode), which requires ICW3 to define the cascade configuration. But ICW3 was skipped — the code jumps from ICW2 directly to ICW4. The 8259 expects ICW3 after ICW2 in cascade mode, so what the code writes as ICW4 (01h) is actually interpreted as ICW3, and the 8259 never receives ICW4. Fix: either add ICW3 (e.g., MOV AL,00h / OUT 21h,AL) before ICW4, or change ICW1 to 17h (set SNGL=1) if cascade is not needed. Also, the ISR is missing the EOI command before IRET.

Explain like I'm 5

Imagine you are a teacher and 8 students all raise their hands at once. You cannot talk to all of them at the same time! The 8259 is like a class monitor who watches all 8 hands, decides which student has the most urgent question (priority), taps you on the shoulder (INTR), and tells you which student number to call on (vector). After you answer that student, the monitor says 'done!' (EOI) and checks if anyone else still has their hand up.

Fun fact

The 8259 was designed by Intel in 1976 and became one of the longest-lived chip designs in computing history. When the IBM PC/AT added a second 8259 in 1984 for more interrupts, the cascade on IR2 created the famous IRQ numbering gap: IRQ0-1 worked normally, IRQ2 was replaced by IRQ9 from the slave, and the system had 15 usable IRQs instead of 16. This quirk persisted for over 30 years in PC architecture.

Hands-on challenge

Initialize a cascaded 8259 system (master at 20h, slave at A0h) with IR0=timer (vector 20h on master), IR1=keyboard (vector 21h on master), and slave on IR2 with IR8=real-time clock (vector 70h). Write the complete ICW1-4 sequence for BOTH master and slave, then write ISR stubs for the timer and RTC including proper cascaded EOI.

More resources

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