8259 Programmable Interrupt Controller
Managing Hardware Interrupts with Priority
Open interactive version (quiz + challenge)Real-world analogy
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
- Why We Need an Interrupt Controller — The 8086 CPU has only one hardware interrupt pin (INTR). But a real system has many devices (keyboard, timer, disk, serial port) that all need to interrupt the CPU. The 8259 PIC (Programmable Interrupt Controller) accepts up to 8 interrupt requests, resolves priority, and signals the CPU one at a time via INTR. It is the traffic cop between devices and the CPU.
- 8259 Architecture — Key Components — The 8259 contains: IRR (Interrupt Request Register) — latches incoming requests on IR0-IR7. ISR (In-Service Register) — tracks which interrupt is currently being serviced. IMR (Interrupt Mask Register) — masks (disables) individual interrupts. Priority Resolver — compares IRR and ISR to determine the highest-priority pending interrupt. It also generates the interrupt vector number sent to the CPU during the acknowledge cycle.
- Initialization Command Words (ICW1-ICW4) — Before the 8259 can operate, it must be initialized with ICW1 through ICW4, written in strict sequence. ICW1 (port base, A0=0): starts initialization, edge/level trigger, single/cascade. ICW2 (port base+1): sets the base interrupt vector number (upper 5 bits, T7-T3). ICW3: defines cascade connections (master/slave relationship). ICW4: sets 8086 mode, auto-EOI, buffered mode.
- Operation Command Words (OCW1-OCW3) — After initialization, OCWs control the 8259 during normal operation. OCW1 (port base+1): writes the IMR to mask/unmask individual interrupts. OCW2 (port base, A0=0): sends EOI commands and controls priority rotation. OCW3 (port base, A0=0): selects which register to read (IRR or ISR) and controls special mask mode.
- Interrupt Acknowledge Sequence — When the 8259 asserts INTR: (1) CPU finishes current instruction. (2) CPU sends first INTA pulse — 8259 sets the ISR bit for the highest-priority request and clears the IRR bit. (3) CPU sends second INTA pulse — 8259 places the 8-bit interrupt vector number on the data bus. (4) CPU reads the vector, looks up the ISR address in the IVT, and jumps to the handler. (5) Handler ends with EOI command to 8259, then IRET.
- Cascading — Expanding to 64 Interrupts — A single 8259 handles 8 interrupts. For more, cascade a master 8259 with up to 8 slave 8259s, giving up to 64 interrupt sources. The slave's INT output connects to one of the master's IR inputs. ICW3 tells the master which IR lines have slaves, and tells each slave its cascade ID. The IBM PC/AT uses one master and one slave for 15 usable interrupts.
- End of Interrupt (EOI) — Why It Matters — After the CPU finishes an ISR, it must send an EOI command to the 8259 to clear the ISR bit. Without EOI, the 8259 thinks the interrupt is still being serviced and blocks all equal-or-lower-priority interrupts. Non-specific EOI (20h) clears the highest ISR bit. Specific EOI (60h+level) clears a specific bit. Auto-EOI mode (set in ICW4) clears the bit automatically during INTA — but this can cause issues with nested interrupts.
- Complete 8259 Setup Example — A typical single-8259 setup for an 8086 system: initialize with ICW1-4 to set edge-triggered, vector base 20h (IR0 maps to INT 20h), single mode, 8086 mode. Then use OCW1 to unmask the desired interrupts. Write ISR handlers at the vector table addresses. Each ISR ends with EOI and IRET.
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
IRETLine-by-line walkthrough
- 1. Title comment for 8259 PIC setup
- 2. Separator line
- 3. Blank line
- 4. PIC is at I/O ports 20h (commands) and 21h (data/mask)
- 5. Vector mapping: IR0 maps to INT 08h, IR1 to INT 09h, and so on
- 6. Blank line
- 7. === INITIALIZATION SECTION ===
- 8. Blank line
- 9. ICW1: edge-triggered interrupts, cascade mode, ICW4 will follow
- 10. 11h = 00010001 in binary: bit4=1 starts init, bit0=1 means ICW4 needed
- 11. Write ICW1 to port 20h (A0=0 is required for ICW1)
- 12. Blank line
- 13. ICW2: set the base vector number — IR0 will map to INT 08h
- 14. Only the upper 5 bits matter (08h = 00001 000), IR number fills lower 3
- 15. Write ICW2 to port 21h (A0=1 for ICW2-4)
- 16. Blank line
- 17. ICW3: on the master, bit 2 set means a slave 8259 is connected to IR2
- 18. 04h = 00000100 — only IR2 has a cascade slave
- 19. Write ICW3 to port 21h
- 20. Blank line
- 21. ICW4: set 8086 mode (vs 8080) and normal EOI (not auto-EOI)
- 22. 01h = 00000001 — bit 0 = 1 means 8086/8088 mode
- 23. Write ICW4 to port 21h — initialization complete
- 24. Blank line
- 25. === OPERATION SECTION ===
- 26. Blank line
- 27. OCW1 sets the interrupt mask register
- 28. 0FCh = 11111100 — bits 0 and 1 are 0 (unmasked), enabling IR0 and IR1
- 29. Write mask to port 21h — only timer and keyboard can now interrupt
- 30. Blank line
- 31. Timer ISR label — CPU jumps here on INT 08h (timer tick)
- 32. Save AX and DS on stack (preserve caller's state)
- 33. Comment: perform the timer handler actions
- 34. Point DS to BIOS data segment at 0040h
- 35. Set DS to 0040h
- 36. Increment the 16-bit BIOS tick counter at 0040:006Ch
- 37. Load non-specific EOI command (20h) into AL
- 38. Send EOI to 8259 at port 20h — clears the ISR bit for this interrupt
- 39. Restore DS and AX from stack
- 40. Blank line
- 41. IRET returns from interrupt — restores IP, CS, and FLAGS
- 42. Blank line
- 43. Keyboard ISR label — CPU jumps here on INT 09h
- 44. Save AX
- 45. Read keyboard scan code from port 60h (keyboard controller)
- 46. Comment: process the key (buffer it, translate to ASCII, etc.)
- 47. Send EOI to 8259
- 48. Blank line
- 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...
IRETNeed a hint?
Show answer
Explain like I'm 5
Fun fact
Hands-on challenge
More resources
- 8259 PIC Explained (Neso Academy)
- 8259 Programmable Interrupt Controller (GeeksforGeeks)
- Intel 8259A Datasheet (Intel)
- How IRQs Work in PCs (Education 4u)