Interrupts

The main point of interrupts is that they provide a mechanism for off-loading the task of polling devices to determine their status from software to hardware. Most IO devices take some time to perform their operations; the CPU is required to start them up, and then to service them when they have completed their tasks. In order to do this, it's necessary to be aware of when they finish.

The simplest way to do this, from both the programmer's and the hardware's points of view, is to use software polling: the device has status bits, which the CPU can query. This has two major drawbacks: first, the time spent polling is time the software could be doing something else. Second, unless the polling is continuous (making the CPU useless for anything except the current IO operation), there is likely to be a delay between the time when the device is actually finished with its operation and when the CPU finds out about it. This results in reduced utilization of the device, and, if response is time-critical, possible missed deadlines.

Interrupts move the polling process into hardware. The basic concept is that when a device has finished an operation, it signals the CPU. The CPU is checking for interrupts before every instruction fetch. If an interrupt is being signalled, and the CPU decides to acknowledge it, the CPU saves a little bit of its current state (frequently just the program counter and processor status word), changes to Kernel mode, and jumps to a software routine to service the interrupt. The interrupt service routine has the responsibility of ensuring that if it is going to modify any part of the process state, it has to save it somewhere first so the process that was interrupted can resume. This includes both obvious parts of the process state (like the program counter) and less obvious parts (like the condition codes, if they weren't saved as part of the PSW). When the interrupt service routine finishes, it restores the state of the process so the interrupted process can continue.

From our perspective, the important part of the interrupt is the part that's handled by hardware. Once we hand it off to the interrupt service routine, our work is finished.

There are many variations on this basic model; we'll discuss some of them below.

Interrupt Schemes

At least three separate issues: how device requests interrupts on bus, how interrupts are presented to CPU, and how CPU responds to interrupts.

Most systems use a prioritized interrupt scheme: several wires on bus are ``interrupt lines.'' Devices are typically either open-collector (which means that the device can pull the bus wire down to ground, but can't try to pull it up to power supply voltage) or tri-state (which means the device can pull the wire down, pull it up, or let it float). Interrupt lines have pull-ups holding them high, so if no device is trying to pull them to ground they are at the power supply voltage. The resistor has to be sized so that when the device pulls the output down to ground voltage, there isn't too much current flowing through the resistor and the device; the larger the resistor the less current flows, but the slower the line can ``float'' back up to a high state.

The advantage of tri-state outputs is that they can pull their output voltage up to power supply voltage faster than a pullup resistor can - that's because they can pass more current doing it. The advantage of open-collector outputs is that they are safer; if you have two tri-state devices driving a bus line you can have one trying to drive the line high and the other trying to drive it low, which can destroy one or both devices (well, in practice the devices will have current limiters to prevent this, but the result is that the wire is at some intermediate voltage, which may be recognized as either a 1 or a 0 by the CPU. So even if it doesn't damage the hardware, the result is unlikely to be what was intended).

When a device requests an interrupt, it pulls the line to ground, signalling CPU that an interrupt is requested. CPU responds to interrupt with an acknowledgement line, and device releases interrupt request.

Open Collector Interrupt Request Lines

Typically several priorities are available, so more important, time-critical devices (eg disk) take priority over low-priority, less time-critical devices (eg keyboard). Lower-priority interrupts have to be disabled while servicing higher-priority devices to avoid priority inversion (a phenomenon in which lower-priority devices end up getting serviced first).

Notice that this scheme supports multiple devices sharing an interrupt line: any device can pull the line down, and figuring out which of the possible devices is actually responsible has to be figured out later; some schemes handle this in hardware, and some in software.

PDP-11 Interrupts

This machine had four interrupt request lines, and four interrupt grant lines (confusingly called bus request and bus grant, though they had nothing to do with bus mastering. Also confusingly, they were numbered 4-7). The processor maintained an ``interrupt priority level'' as part of the PSW. The protocol was complex, to say the least; however, it gives a good example of how the CPU and a device can communicate the necessary information for an interrupt.

When a device requested an interrupt, it would assert its bus request line (multiple devices could share a single line). If the processor was running at a lower priority level than the level of the requested interrupt, it would respond by asserting the corresponding grant line (if multiple request lines were asserted, it would grant the highest-priority interrupt) -- notice that processor priority levels 0-3 all had all interrupts enabled, and also that PPL 7 was an absolute interrupt disable: if a device driver had a bug that would set the PPL to 7 and leave it, there was no way to get the machine's attention except the RESET button.

The devices daisy-chain the interrupt grant, so the physically closest device has the highest priority within a level.

Daisy Chained Devices

When an interrupting device receives the grant signal, it responds by placing an eight bit, longword-aligned, address on the bus. This is the address of the device's interrupt vector (since it's longword-aligned, the device actually only puts six bits on the bus. This allows 64 different interrupt vectors).

The CPU stacks the current PC and PSW, and loads a new PC and PSW from the specified vector.

Advantages: very flexible. Lots of devices possible (I wonder how many PDP-11s ever ran out of interrupt vectors?). Notice that things like whether to disable all interrupts, or just all interrupts of lower priority than the one that triggered the request, are decided under software control (the intent was that the new PSW that was loaded would have the same PPL as the interrupt that just occurred; but, there's nothing to stop putting a 7 in and disabling all interrupts).

Disadvantages: slow. requires very smart device (especially by 1972 standards!). In retrospect, it's surprising that DEC implemented such a complex (and consequently expensive) scheme in low-cost computers.

IBM PC Interrupts (ISA bus)

The main point of this scheme will be that it moves much of the hardware level interrupt handling out from the CPU and the device, and gives it to a third party (the interrupt controller chip).

The Intel CPU family doesn't have any sort of priority levels like the PDP-11. It only has a single interrupt enable/disable bit; priorities are implemented by a separate interrupt controller chip.

Interrupts on the PC are presented to the CPU by an Intel 8259 programmable interrupt controller chip. This chip has eight interrupt request lines coming in; each one has a corresponding mask bit. When an unmasked interrupt is requested by a device, a signal is sent to the CPU. When the CPU acknowledges it, the 8259 responds with the ID of the interrupt (0-7) prepended with five bits programmed into the 8259 at initialization time; this is multiplied by four and used as an interrupt vector.

The controller chip has several programmable modes of operation, including:

Getting the device to stop requesting an interrupt is up to the software device driver.

The 8259 is also capable of expansion by using a ``cascade mode.'' In this mode, we can have a two-level tree of 8259's, with up to eight leaves called ``slaves.'' connecting to a single ``master'' (I don't think you can get any deeper than this, but I'd have to look it up to be sure. Two levels will let you have 64 interrupts anyway, which ought to be ample... just like 640K of memory!). In this mode, a device requesting an interrupt makes the request to the slave controller. The slave signals an interrupt to the master controller through one of the master's interrupt input lines; the master responds as if the slave were a device. When the master responds to the slave, the slave dumps its interrupt number to the bus.

The original PC only had a single 8259, which turned out to not be enough interrupts. When the bus was extended for the PC/AT, a second 8259 was added, in cascade mode. IRQ2 was picked as the line on which the slave would make requests of the master (presumably, IBM felt that there were fewer devices already making use of this interrupt than others); since it had to be backward compatible, the IRQ2 interrupts had to come in on some other interrupt line. They picked IRQ9, which is the reason for all the confusion ever since regarding trying to configure IRQ2 and IRQ9.

Unfortunately, IBM defined the bus so that the device signals the interrupt controller that an interrupt is needed by pulling the line up, instead of down. This means that the ISA bus can't share interrupts. They must have seen a way to save a dollar there someplace, but I haven't found it.

In modern chipsets, the 8259s are long gone. But in the interest of backward compatibility, their functionality is faithfully duplicated. Right down the IRQ2/9 confusion.

Motorola 68000

A good example of a typical modern scheme is used by the Motorola 68000. This scheme has a strong resemblance to the PDP-11 scheme, but with simplified hardware requirements. Actually, that's a pretty good summary of the relationship of a 68000 to a PDP-11 in most ways!

Something nice we'll see with the Motorola scheme is that if you have a relatively sophisticated device it can take advantage of that, but if the device is simpler we can fall-back to defaults inside the CPU.

Like the PDP-11, the 68000 has a processor priority level in the processor status word. Unlike the PDP-11, it has a 3-bit IPL input to the processor. When this input is a 0, no input is being requested. Levels 1-7 are all different interrupt levels. The interrupt is accepted if either IPL > PPL, or IPL == 7. The intent is that an external interrupt controller chip generates the IPL input; this can be as simple as an eight bit priority encoder.

Again, like the PDP-11, the processor stacks the PC and SR (status register); if the device has responded to the acknowledge with a vector it uses that, otherwise it pulls a new pc out of address 0x60 + ipl*4. The PPL is set to the same level as the requesting interrupt, and the machine is put in System mode.

I've long said that the only good thing about the ISA bus is that it isn't as bad as the original Macintosh. Let's see what the original Mac did to the 68000's interrupt scheme... Remember, it was a closed architecture -- no expansion bus, no memory expansion. When somebody found a way to put a hard disk on it (I don't know how they did that), doing so would void the warrantee.

So this machine had exactly three devices that could generate interrupts: the timer system, and the two serial ports (that's right, not the keyboard, not the floppy disk, not the video display).

But the serial ports didn't generate interrupts when characters came in (they could have, but they weren't configured that way). They generated interrupts when one of the RS-232 status lines changed state (the Mac didn't use RS-232, it used a related standard called RS-422 that doesn't use all the control and status lines that RS-232 does. 422 is actually a more appropriate standard for communicating between computers, rather than communicating between a computer and a modem). So they wired up the mouse X and Y inputs to these status lines, one on each serial port. So the machine got serial port interrupts when you moved the mouse.

The way you used the floppy was you'd start a request (like go to the next track), and then set a timer for when you expected the operation to be complete. When the timer went off, you'd start polling.

Last thing: these three devices were wired directly to the 68000 IPL lines. So any device could have an interrupt come in on any of four levels. This actually wasn't as big a disaster as it sounded, since you would set the interrupt vectors appropriately for the highest priority device at any interrupt level.... cheap, but, well, cheap.

MIPS Interrupts

MIPS uses a very simple scheme for interrupts. It appears that a decision has been made that the actual interrupt vectoring is such a small part of servicing an interrupt that you might as well simplify the hardware and move it to software.

It uses two registers in a coprocessor (the Cause register and the Exception PC) to remember the cause of the exception and the address of the instruction that had the exception.

It then disables interrupts, switches to kernel mode, and jumps to address 0x80000080.

Software at that location is responsible for using the exception type to jump to the actual handler, using a jump table.

Interrupts on PCI Bus

See PCI description page


Last modified: Fri Apr 11 09:24:34 MDT 2003