The Programmable Interrupt Controllers (PICs)

Bibliographical note: Most of the information in this document comes from two sources. The first is the "PC Programmer's Handbook, 2nd edition" by Julio Sanchez and Maria P. Canton, published by McGraw-Hill; the second is the online reference HelpPC by Dave Jurgens, which should be available from the internet.

Please see the disclaimer on the main page.

Modern PC systems are equipped with two 8259A Programmable Interrupt Controllers (or PICs). These interrupt controllers are responsible for recieving interrupt signals from system devices (such as disk drive controllers, sound cards etc) and relaying those signals to the CPU, generating what is known as a hardware interrupt.

On receiving an interrupt request from a device, a PIC signals the CPU which, if it is accepting interrupts, acknowledges the request, causing the PIC to send the interrupt identification number (which is the line number on which the request came, plus a programmable base value) on the data bus. The CPU then looks up the appropriate entry in the interrupt vector table and calls the appropriate software entry point (interrupt handler). This is similar to what happens when an INT instruction is executed by the CPU, however, in this case the interrupt identification number is an argument to that instruction.

It is the responsibility of the interrupt handler to then send an EOI (end-of-interrupt) signal to the appropriate PIC(s) - otherwise further interrupt requests (of a lower priority) will not be processed.

Each PIC has 8 interrupt request lines (IRQs). The IRQs on the first controller are numbered 0 to 7, and those on the second are 8 to 15. The second PIC controller is actually cascaded through IRQ line 2 of the first controller, and the first controller is configured accordingly. IRQ2 is generally "disabled" to prevent an IRQ2 being visible to the CPU; instead, the 2nd PIC sends the appropriate interrupt identification number on the data bus. Thus, IRQ lines 8 to 15 generate a single interrupt despite the cascade. However, it should be noted that interrupt handlers for interrupts generated through the 2nd PIC need to send an EOI to both PICs.

Capabilities of the 8259A include the ability to programatically mask individual IRQs, to prioritize IRQs, and to use a variable 'base' for interrupt numbers as sent to the CPU. Thus IRQ0 can be tied to CPU interrupt number 8 (the default), or 16, or 24... etc.


Port assignments

1st PIC2nd PIC
First access port0x200xA0
Second access port0x210xA1

Note that there should be a short delay between port accesses in order to give the PIC chip 'recovery time' (at least, this is the case for the original AT computers). The exact amount of time is probably around 5 10-millionths of a second (50 microseconds). For newer hardware, this may not be necessary.

Note also that the 8259A chip was not designed specifically for the PC family of computers. Therefore, there are certain configurable options which have little meaning due to the particulars of the implementation of the PC.


Overview of Operation

This requires a small introduction due to terminology. First off, most of the settings of a PIC are given in the initialization command, which is made up of up to four initialization commandss (ICWs) which are called ICW1, ICW2, ICW3, and ICW4 (see: initialization commands). These commands are always sent in sequence, except that ICW3 and ICW4 are optional and should only be present if their presence is indicated by options in ICW1 and 2. Each ICW consists of one byte, where certain bits are fixed and certain bits are parametric values which determine how the PIC will behave. The exact details of bit meanings in the four control words, which port they are sent to and when they are required are given below.

There are other control words which can be sent to the PIC, however. These are called operation commands (OCWs), and there are three of them. They are used for setting the interrupt mask register (which controls whether individual interrupts are enabled or disabled), acknowledging the end of an interrupt processing in order to allow a lower priority interrupt to be sent to the CPU [This is, incidentally, how the interrupt prioritizing works. When the PIC believes that an interrupt of a certain priority is being serviced, it will not send lower priority interrupts to the CPU until it receives an EOI], and reading the interrupt request register and the in-service register.

There are three externally visible registers in the PIC: The first is the IMR (interrupt mask register), which is 8 bits wide. It can be read from the second access port, and is written using OCW1 (ie, by writing directly to that same port! Nothing more). Each bit is linked to the corresponding IRQ line of the PIC. A 1 in the bit corresponding to a particular IRQ will disable that interrupt request line and a 0 will enable it. Note that, if interrupts are disabled in the PIC, or in the CPU, or are blocked due to higher priority interrupts being processed, the interrupts are not thrown away; they will be processed as soon as they are no longer blocked.

The second and third registers are the ISR (in-service register), which keeps track of which interrupts are currently being serviced (1 bit for each IRQ line; a 1 indicates that the IRQ is being serviced), and the IRR (interrupt request register) which keeps track of which IRQ lines have received a request, but the request has not yet been echoed to the CPU. Note that when an IRQ is passed to the CPU, the corresponding bit in the IRR is cleared and the corresponding bit in the ISR is set. These registers are read-only from the viewpoint of the CPU and are read using OCW3.


The initialization commands

There are four initialization commands (ICW1-4), always generated in sequence. The first goes to access port 1 and the rest to port 2. Note that the PIC distinguishes between ICWs and OCWs both by the setting of various bits in the commands, and by which port the command is sent to.

ICW1bit 7 - 5must be 000
bit 41 (identifies initialization command)
bit 31 = level triggered interrupts (as in PS/2 systems) 0 = edge triggered interrupts (as in other PC systems)
bit 21 = 4 byte interrupt vectors, 0 = 8 byte interrupt vectors (as in PC systems)
bit 11 = Only one 8259A in system 0 = more than one 8259A in system (as in PC systems)
bit 01 = ICW4 will be sent (as needed in PC systems) 0 = ICW4 will not be sent
ICW2bit 7 - 3Most significant 5 bits of interrupt type (interrupt identification number as given to CPU, for any generated interrupts). Setting this to x causes the PIC to generate interrupts x through x + 7 to the CPU. Usual values are 8h for master PIC and 70h for slave, but any value may be used.
bit 2 - 0000
Note ICW3 is required only if bit 1 of ICW1 was 0 (two PICs present)
ICW3For master PICEach bit is 1 if a slave is attached to the corresponding IRQ line (bit 0 for IRQ0, etc). For PC systems, the slave is attached to IRQ2.
For slaveBits 7-3 are 0, and bits 2 to 1 give (as a binary number) the IRQ line of the master to which the slave is attached. This is 2 in PC systems (010b).
Note ICW4 is required only if bit 0 in ICW1 was 1 (as in PC systems)
ICW4bits 7 - 5000
bit 41 = 'Fully nested mode', 0 = 'Not fully nested mode' (usual in PC systems)
bit 31 = 'buffered mode', 0 = 'nonbuffered mode' (usual in PC systems)
bit 21 = master function, 0 = slave function. Not significant in non-buffered mode.
bit 11 = 'automatic EOI', 0 = normal EOI (usual in PC systems)
bit 01 = 8086 mode (as in PC systems), 0 = 8085 mode


OCW1

OCW1 is used to change the value of the IMR (interrupt mask register). To perform an OCW1, simply write the new value of the IMR to access port 2.


OCW2

The OCW2 command is how an EOI (end-of-interrupt) is issued to the PIC by the CPU. This must be done explicitly by code in the interrupt handler; it is not automatic. Before the handler returns, it should therefore send an OCW2 to just PIC#1 (for IRQs 0 - 7) or to both PIC#2 and PIC#1 (for IRQs 8 - 15). In this latter case, because of the cascade arrangement, an interrupt has effectively been generated by both PICs.

OCW2 is given by writing the value 20h to access port 1.

The HelpPC reference further documents the command, giving the following bitmask. The meanings of most of this are unknown to me.

bits 7 - 5EOI type:
001: non-specific EOI command
010: NOP [no operation]
011: specific EOI command
100: rotate in automatic EOI mode
101: rotate on non-specific EOI command
110: set priority command (uses bits 0-2)
111: rotate on specific EOI command
bits 4 - 3must be 00
bits 2 - 0interrupt request level to act upon.


OCW3

An OCW3 is used to read the ISR and IRR. The command is issued (to access port 1), indicating which register value is required, and the read is then performed from access port 1.

The command bitmask is as thus:

bit 7 - 40000
bit 31
bit 2'Polling control bit': '1 = Read highest level requesting service' (usually 0 for PC systems; exact use unknown by me)
bit 1 - 011 = Read ISR (in-service register), 10 = Read IRR (interrupt request register)

The HelpPC reference gives a more detailed bitmask, which I have duplicated below. The meaning of most of this is unknown to me.

bit 7must be 0
bit 61 = act on value of bit 5, 0 = no action if bit 5 set
bit 51 = set special mask, 0 = reset special mask
bit 4 - 3must be 01
bit 21 = poll command issued, 0 = no poll command issued
bit 11 = act one value of bit 0, 0 = no action if bit 0 set
bit 01 = read IRR on next read, 0 = read ISR on next read