Interrupts — NMI/IRQ/BRK vs. IM 0/1/2
8-Bit CPUs — 6502/6510 & Z80
Chapter 9 · Interrupts — NMI/IRQ/BRK vs. IM 0/1/2
assembly1-8 named interrupts only in passing — hardware signaling the CPU instead of the CPU repeatedly polling — and deliberately left the mechanism for later, more advanced material. This chapter is that material, on two real chips, and it's also where cpu8bit1-6's own shadow register preview finally gets to pay off for real.
The 6502's Interrupt Model — NMI, IRQ, BRK
The 6502 keeps interrupts as simple as everything else about it:
- IRQ (Interrupt Request) — triggered by external hardware wanting attention. Maskable: the I flag in the status register (
cpu8bit1-3's own P register) can disable it entirely. - NMI (Non-Maskable Interrupt) — reserved for events too critical to ever ignore. Cannot be disabled by any flag, and has its own dedicated vector.
- BRK — not a hardware event at all, but a real opcode a program can execute deliberately, triggering interrupt-like behavior in software. Historically used for debugging breakpoints and software-triggered system calls.
Whichever one fires, the sequence is identical: the CPU automatically pushes PC and the status register onto the stack — cpu8bit1-3's own page-1 stack, doing real work here — then jumps to a fixed handler address read from a small vector table near the very top of memory ($FFFA–$FFFF holds the NMI/RESET/IRQ vectors). The handler ends with RTI (Return from Interrupt), which pulls the status register and PC back off the stack, resuming exactly where the program left off. This is exactly why cpu8bit1-3's own status register includes the B flag — its entire purpose is letting the handler tell a genuine hardware IRQ apart from a deliberate software BRK once execution lands at that shared vector.
Only three vectors exist in total (NMI, RESET, and a shared IRQ/BRK vector) — one fixed handler address per category, no further sorting done by the hardware itself.
The Z80's Interrupt Model — NMI and Three Interrupt Modes
The Z80 also has an NMI, working much like the 6502's own (a fixed vector, unmaskable, automatic PC push). Its maskable interrupt is where the real richness shows up: the programmer selects one of three interrupt modes via a dedicated instruction (IM 0, IM 1, IM 2):
- IM 0 — the interrupting device itself supplies an instruction for the CPU to execute directly, usually a short call. This is inherited straight from 8080 compatibility (
cpu8bit1-5's own founding constraint) — flexible, but the most primitive and least commonly used of the three. - IM 1 — always jumps to one single fixed address ($0038), no matter which device interrupted. As simple as the 6502's own shared IRQ vector.
- IM 2 — the genuinely powerful mode. The CPU builds a 16-bit pointer by combining the high byte from a dedicated register (I, the interrupt vector register) with a low byte the interrupting device itself supplies, then looks up a full 16-bit handler address at that computed location in a table the programmer sets up in advance. Because the device-supplied byte is even, up to 128 distinct table entries are addressable — meaning every peripheral can get its own dedicated handler, instead of one shared entry point that then has to work out which device actually interrupted.
cpu8bit1-7's own cycle-cost warn-box, showing up here as setup complexity rather than raw runtime cost.
Where the Shadow Register Set Finally Pays Off
cpu8bit1-6 previewed EXX/EX AF,AF′ and named their real, historical purpose: fast interrupt entry. Now it's possible to see exactly why. A Z80 interrupt handler can execute a single EXX the moment it starts, instantly gaining a completely fresh, empty set of BC/DE/HL to work with — no need to push the main program's register values onto the stack to protect them first. A single EXX back at the end restores everything, and the handler returns.
A 6502 interrupt handler has no such option — anything it needs a register for, it must PHA/PLA (and similarly for X and Y, transferred through A first, since only A has native push/pull) around its own use of that register, each one a real, separate instruction costing real cycles on both entry and exit. The shadow set turns an entire category of that overhead into a single instruction.
Minimalism vs. Richness, a Third Time
| 6502 | Z80 | |
|---|---|---|
| Interrupt sources | NMI, IRQ, BRK (software) — 3 fixed vectors | NMI, plus a maskable INT with 3 selectable modes |
| Masking | The I flag in P disables IRQ | EI/DI instructions enable/disable the maskable interrupt |
| Handler dispatch | One shared vector per category — software must sort out the source | IM 2 gives up to 128 distinct, hardware-selected handlers |
| Register protection on entry | Manual PHA/PLA (and friends) around whatever's needed | A single EXX / EX AF,AF′ swaps in an entire fresh register set |
This is the same contrast cpu8bit1-2 and cpu8bit1-5 established for the chips overall, and cpu8bit1-8 made concrete for loops — now showing up a third time, in a third domain entirely.
assembly1-8 left this topic. Both chips in this course now show two genuinely different, real implementations of that idea — one minimal and uniform, one rich and selectively dispatched — closing a loop this whole course arc has been building toward since its very first LC-3 chapter.
Hands-On Exercises
Explain the real difference between the 6502's IRQ and NMI in terms of maskability, and explain why BRK is categorized alongside them despite not being triggered by external hardware at all.
📄 View solutionUsing this chapter's own explanation of IM 2, describe how the final 16-bit vector address is assembled from the I register and the device-supplied byte, and explain why this allows up to 128 distinct interrupt handlers rather than just one shared entry point.
📄 View solutionUsing cpu8bit1-6's own shadow-register material and this chapter's own coverage, explain concretely why a Z80 interrupt handler using EXX enters and exits faster than an equivalent 6502 handler that must manually PHA/PLA the registers it needs.
📄 View solutionChapter 9 Quick Reference
- 6502: IRQ (maskable, hardware), NMI (unmaskable, hardware), BRK (software) — 3 fixed vectors, shared IRQ/BRK entry point
- Z80: NMI (unmaskable), plus a maskable INT with 3 selectable modes (IM 0/1/2)
- IM 1 is as simple as the 6502's shared vector; IM 2 combines the I register + a device-supplied byte into a full vectored table, up to 128 distinct handlers
- Both chips push PC (and status, on the 6502) to the stack automatically and return via RTI — the same mechanism, different vector richness
- EXX / EX AF,AF′ finally pay off cpu8bit1-6's own preview — one instruction replaces the 6502's manual PHA/PLA register-saving on every interrupt entry/exit
- IM 2's power requires real setup discipline (I register, device wiring, table construction) — richness costing complexity, not just cycles or transistors
- This is the third domain (after registers and addressing) where the same minimalism-vs-richness contrast shows up concretely