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.
| 1st PIC | 2nd PIC | |
| First access port | 0x20 | 0xA0 |
| Second access port | 0x21 | 0xA1 |
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.
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.
| ICW1 | bit 7 - 5 | must be 000 | |||||||||||||
| bit 4 | 1 (identifies initialization command) | ||||||||||||||
| bit 3 | 1 = level triggered interrupts (as in PS/2 systems) 0 = edge triggered interrupts (as in other PC systems) | ||||||||||||||
| bit 2 | 1 = 4 byte interrupt vectors, 0 = 8 byte interrupt vectors (as in PC systems) | ||||||||||||||
| bit 1 | 1 = Only one 8259A in system 0 = more than one 8259A in system (as in PC systems) | ||||||||||||||
| bit 0 | 1 = ICW4 will be sent (as needed in PC systems) 0 = ICW4 will not be sent | ||||||||||||||
| ICW2 | bit 7 - 3 | Most 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 - 0 | 000 | ||||||||||||||
| Note ICW3 is required only if bit 1 of ICW1 was 0 (two PICs present) | |||||||||||||||
| ICW3 | For master PIC | Each 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 slave | Bits 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)
| ICW4 | bits 7 - 5 | 000
| bit 4 | 1 = 'Fully nested mode',
0 = 'Not fully nested mode' (usual in PC systems)
| bit 3 | 1 = 'buffered mode',
0 = 'nonbuffered mode' (usual in PC systems)
| bit 2 | 1 = master function,
0 = slave function. Not significant in non-buffered mode.
| bit 1 | 1 = 'automatic EOI',
0 = normal EOI (usual in PC systems)
| bit 0 | 1 = 8086 mode (as in PC systems),
0 = 8085 mode
| | ||
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 - 5 | EOI 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 - 3 | must be 00 |
| bits 2 - 0 | interrupt request level to act upon. |
The command bitmask is as thus:
| bit 7 - 4 | 0000 |
| bit 3 | 1 |
| bit 2 | 'Polling control bit': '1 = Read highest level requesting service' (usually 0 for PC systems; exact use unknown by me) |
| bit 1 - 0 | 11 = 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 7 | must be 0 |
| bit 6 | 1 = act on value of bit 5, 0 = no action if bit 5 set |
| bit 5 | 1 = set special mask, 0 = reset special mask |
| bit 4 - 3 | must be 01 |
| bit 2 | 1 = poll command issued, 0 = no poll command issued |
| bit 1 | 1 = act one value of bit 0, 0 = no action if bit 0 set |
| bit 0 | 1 = read IRR on next read, 0 = read ISR on next read |