INTRODUCTION
In this chapter, the coverage of basic I/O and programmable peripheral interfaces is expanded by examining a technique called interrupt-processed I/O. An interrupt is a hardware-initiated procedure that interrupts whatever program is currently executing. This chapter provides examples and a detailed explanation of the interrupt structure of the entire Intel family of microprocessors.
CHAPTER OBJECTIVES
Upon completion of this chapter, you will be able to:
1. Explain the interrupt structure of the Intel family of microprocessors.
2. Explain the operation of software interrupt instructions INT, INTO, INT 3, and BOUND.
3. Explain how the interrupt enable flag bit (IF) modifies the interrupt structure.
4. Describe the function of the trap interrupt flag bit (TF) and the operation of trap-generated tracing.
5. Develop interrupt-service procedures that control lower-speed, external peripheral devices.
6. Expand the interrupt structure of the microprocessor by using the 82S9A programmable interrupt controller and other techniques.
7. Explain the purpose and operation of a real-time clock.
BASIC INTERRUPT PROCESSING
In this section, we discuss the function of an interrupt in a microprocessor-based system, and the structure and features of interrupts available to the Intel family of microprocessors.
The Purpose of Interrupts
Interrupts are particularly useful when interfacing I/O devices that provide or require data at relatively low data transfer rates. In Chapter 11, for instance, we showed a keyboard example using strobed input operation of the 82C55. In that example, software polled the 82C55 and its IBF bit to decide whether data were available from the keyboard. If the person using the keyboard typed
one character per second, the software for the 82C55 waited an entire second between each key- stroke for the person to type another key. This process was such a tremendous waste of time that designers developed another process, interrupt processing, to handle this situation.
Unlike the polling technique, interrupt processing allows the microprocessor to execute other software while the keyboard operator is thinking about what key to type next. As soon as a key is pressed, the keyboard encoder debounces the switch and puts out one pulse that interrupts the microprocessor. The microprocessor executes other software until the key is actually pressed, when it reads a key and returns to the program that was interrupted. As a result, the micro- processor can print reports or complete any other task while the operator is typing a document and thinking about what to type next.
Figure 12–1 shows a time line that indicates a typist typing data on a keyboard, a printer removing data from the memory, and a program executing. The program is the main program that is interrupted for each keystroke and each character that is to print on the printer. Note that the keyboard interrupt service procedure, called by the keyboard interrupt, and the printer interrupt service procedure each take little time to execute.
Interrupts
The interrupts of the entire Intel family of microprocessors include two hardware pins that request interrupts (INTR and NMI), and one hardware pin (INTA) that acknowledges the interrupt requested through INTR. In addition to the pins, the microprocessor also has software interrupts INT, INTO, INT 3, and BOUND. Two flag bits, IF (interrupt flag) and TF (trap flag), are also used with the interrupt structure and a special return instruction, IRET (or IRETD in the 80386, 80486, or Pentium–Pentium 4).
Interrupt Vectors. The interrupt vectors and vector table are crucial to an understanding of hardware and software interrupts. The interrupt vector table is located in the first 1024 bytes of memory at addresses 000000H–0003FFH. It contains 256 different four-byte interrupt vectors. An interrupt vector contains the address (segment and offset) of the interrupt service procedure.
Figure 12–2 illustrates the interrupt vector table for the microprocessor. The first five interrupt vectors are identical in all Intel microprocessor family members, from the 8086 to the Pentium. Other interrupt vectors exist for the 80286 that are upward-compatible to the 80386, 80486, and Pentium–Core2, but not downward-compatible to the 8086 or 8088. Intel reserves the first 32 interrupt vectors for their use in various microprocessor family members. The last 224 vectors are available as user interrupt vectors. Each vector is four bytes long in the real mode and contains the starting address of the interrupt service procedure. The first two bytes of the vector contain the offset address and the last two bytes contain the segment address.
The following list describes the function of each dedicated interrupt in the microprocessor:
TYPE 0 The divide error whenever the result from a division overflows or an attempt is made to divide by zero.
TYPE 1 Single-step or trap occurs after the execution of each instruction if the trap (TF) flag bit is set. Upon accepting this interrupt, the TF bit is cleared so that the
interrupt service procedure executes at full speed. (More detail is provided about this interrupt later in this section of the chapter.)
TYPE 2 The non-maskable interrupt occurs when a logic 1 is placed on the NMI input pin to the microprocessor. This input is non-maskable, which means that it cannot be disabled.
TYPE 3 A special one-byte instruction (INT 3) that uses this vector to access its interrupt- service procedure. The INT 3 instruction is often used to store a breakpoint in a program for debugging.
TYPE 4 Overflow is a special vector used with the INTO instruction. The INTO instruction interrupts the program if an overflow condition exists, as reflected by the overflow flag (OF).
TYPE 5 The BOUND instruction compares a register with boundaries stored in the memory. If the contents of the register are greater than or equal to the first word in memory and less than or equal to the second word, no interrupt occurs because the contents of the register are within bounds. If the contents of the register are out of bounds, a type 5 interrupt ensues.
TYPE 6 An invalid opcode interrupt occurs whenever an undefined opcode is encountered in a program.
TYPE 7 The coprocessor not available interrupt occurs when a coprocessor is not found in the system, as dictated by the machine status word (MSW or CR0) coprocessor control bits. If an ESC or WAIT instruction executes and the coprocessor is not found, a type 7 exception or interrupt occurs.
TYPE 8 A double fault interrupt is activated whenever two separate interrupts occur during the same instruction.
TYPE 9 The coprocessor segment overrun occurs if the ESC instruction (coprocessor opcode) memory operand extends beyond offset address FFFFH in real mode.
TYPE 10 An invalid task state segment interrupt occurs in the protected mode if the TSS is invalid because the segment limit field is not 002BH or higher. In most cases, this is caused because the TSS is not initialized.
TYPE 11 The segment not present interrupt occurs when the protected mode P bit (P = 0) in a descriptor indicates that the segment is not present or not valid.
TYPE 12 A stack segment overrun occurs if the stack segment is not present (P = 0) in the protected mode or if the limit of the stack segment is exceeded.
TYPE 13 The general protection fault occurs for most protection violations in the 80286–Core2 protected mode system. (These errors occur in Windows as general protection faults.) A list of these protection violations follows:
(a) Descriptor table limit exceeded
(b) Privilege rules violated
(c) Invalid descriptor segment type loaded
(d) Write to code segment that is protected
(e) Read from execute-only code segment
(f) Write to read-only data segment
(g) Segment limit exceeded
(h) CPL = IOPL when executing CTS, HLT, LGDT, LIDT, LLDT, LMSW, or LTR
(i) CPL > IOPL when executing CLI, IN, INS, LOCK, OUT, OUTS, and STI
TYPE 14 Page fault interrupts occur for any page fault memory or code access in the 80386, 80486, and Pentium–Core2 microprocessors.
TYPE 16 Coprocessor error takes effect whenever a coprocessor error (ERROR = 0) occurs for the ESCape or WAIT instructions for the 80386, 80486, and Pentium–Core2 microprocessors only.
TYPE 17 Alignment checks indicate that word and doubleword data are addressed at an odd memory location (or an incorrect location, in the case of a doubleword). This interrupt is active in the 80486 and Pentium–Core2 microprocessors.
TYPE 18 A machine check activates a system memory management mode interrupt in the Pentium–Core2 microprocessors.
Interrupt Instructions: BOUND, INTO, INT, INT 3, and IRET
Of the five software interrupt instructions available to the microprocessor, INT and INT 3 are very similar, BOUND and INTO are conditional, and IRET is a special interrupt return instruction.
The BOUND instruction, which has two operands, compares a register with two words of memory data. For example, if the instruction BOUND AX,DATA is executed, AX is compared with the contents of DATA and DATA+1 and also with DATA+2 and DATA+3. If AX is less than the contents of DATA and DATA+1, a type 5 interrupt occurs. If AX is greater than DATA+2 and DATA+3, a type 5 interrupt occurs. If AX is within the bounds of these two memory words, no interrupt occurs.
The INTO instruction checks or tests the overflow flag (O). If O = 1, the INTO instruction calls the procedure whose address is stored in interrupt vector type number 4. If O = 0, then the INTO instruction performs no operation and the next sequential instruction in the program executes.
The INT n instruction calls the interrupt service procedure that begins at the address represented in vector number n. For example, an INT 80H or INT 128 calls the interrupt service procedure whose address is stored in vector type number 80H (000200H–00203H). To determine the vector address, just multiply the vector type number (n) by 4, which gives the beginning address of the four-byte long interrupt vector. For example, INT 5 = 4 × 5 or 20 (14H). The vector for INT 5 begins at address 0014H and continues to 0017H. Each INT instruction is stored in two bytes of memory: The first byte contains the opcode, and the second byte contains the interrupt type number. The only exception to this is the INT 3 instruction, a one-byte instruction. The INT 3 instruction is often used as a breakpoint-interrupt because it is easy to insert a one-byte instruction into a program. Breakpoints are often used to debug faulty software.
The IRET instruction is a special return instruction used to return for both software and hardware interrupts. The IRET instruction is much like a far RET, because it retrieves the return address from the stack. It is unlike the near return because it also retrieves a copy of the flag register from the stack. An IRET instruction removes six bytes from the stack: two for the IP, two for the CS, and two for the flags.
In the 80386–Core2, there is also an IRETD instruction because these microprocessors can push the EFLAG register (32 bits) on the stack, as well as the 32-bit EIP in the protected mode and 16-bit code segment register. If operated in the real mode, we use the IRET instruction with the 80386–Core2 microprocessors. If the Pentium 4 operates in 64-bit mode, an IRETQ instruction is used to return from an interrupt. The IRETQ instruction pops the EFLAG register into RFLAGS and also the 64-bit return address is placed into the RIP register.
The Operation of a Real Mode Interrupt
When the microprocessor completes executing the current instruction, it determines whether an interrupt is active by checking (1) instruction executions, (2) single-step, (3) NMI, (4) coprocessor segment overrun, (5) INTR, and (6) INT instructions in the order presented. If one or more of these interrupt conditions are present, the following sequence of events occurs:
1. The contents of the flag register are pushed onto the stack.
2. Both the interrupt (IF) and trap (TF) flags are cleared. This disables the INTR pin and the trap or single-step feature.
3. The contents of the code segment register (CS) are pushed onto the stack.
4. The contents of the instruction pointer (IP) are pushed onto the stack.
5. The interrupt vector contents are fetched, and then placed into both IP and CS so that the next instruction executes at the interrupt service procedure addressed by the vector.
Whenever an interrupt is accepted, the microprocessor stacks the contents of the flag register, CS and IP; clears both IF and TF; and jumps to the procedure addressed by the interrupt vector. After the flags are pushed onto the stack, IF and TF are cleared. These flags are returned to the state prior to the interrupt when the IRET instruction is encountered at the end of the interrupt service procedure. Therefore, if interrupts were enabled prior to the interrupt service procedure, they are automatically re-enabled by the IRET instruction at the end of the procedure.
The return address (in CS and IP) is pushed onto the stack during the interrupt. Sometimes the return address points to the next instruction in the program; sometimes it points to the instruction or point in the program where the interrupt occurred. Interrupt type numbers 0, 5, 6, 7, 8, 10, 11, 12, and 13 push a return address that points to the offending instruction, instead of to the next instruction in the program. This allows the interrupt service procedure to possibly retry the instruction in certain error cases.
Some of the protected mode interrupts (types 8, 10, 11, 12, and 13) place an error code on the stack following the return address. The error code identifies the selector that caused the interrupt. In cases where no selector is involved, the error code is a 0.
Operation of a Protected Mode Interrupt
In the protected mode, interrupts have exactly the same assignments as in the real mode, but the interrupt vector table is different. In place of interrupt vectors, protected mode uses a set of 256 interrupt descriptors that are stored in an interrupt descriptor table (IDT). The interrupt descriptor table is 256 × 8 (2K) bytes long, with each descriptor containing eight bytes. The interrupt descriptor table is located at any memory location in the system by the interrupt descriptor table address register (IDTR).
Each entry in the IDT contains the address of the interrupt service procedure in the form of a segment selector and a 32-bit offset address. It also contains the P bit (present) and DPL bits to describe the privilege level of the interrupt. Figure 12–3 shows the contents of the interrupt descriptor.
Real mode interrupt vectors can be converted into protected mode interrupts by copying the interrupt procedure addresses from the interrupt vector table and converting them to 32-bit offset addresses that are stored in the interrupt descriptors. A single selector and segment descriptor can be placed in the global descriptor table that identifies the first 1M byte of memory as the interrupt segment.
Other than the IDT and interrupt descriptors, the protected mode interrupt functions like the real mode interrupt. We return from both interrupts by using the IRET or IRETD instruction. The only difference is that in protected mode the microprocessor accesses the IDT instead of the
interrupt vector table. In the 64-bit mode of the Pentium 4 and Core2, an IRETQ must be used to return from an interrupt. This is one reason why there are different drivers and operating systems for the 64-bit mode.
Interrupt Flag Bits
The interrupt flag (IF) and the trap flag (TF) are both cleared after the contents of the flag register are stacked during an interrupt. Figure 12–4 illustrates the contents of the flag register and the location of IF and TF. When the IF bit is set, it allows the INTR pin to cause an interrupt; when the IF bit is cleared, it prevents the INTR pin from causing an interrupt. When TF = 1, it causes a trap interrupt (type number 1) to occur after each instruction executes. This is why we often call trap a single-step. When TF = 0, normal program execution occurs. This flag bit allows debugging, as explained in Chapters 17 through 19, which detail the 80386–Core2.
The interrupt flag is set and cleared by the STI and CLI instructions, respectively. There are no special instructions that set or clear the trap flag. Example 12–1 shows an interrupt service procedure that turns tracing on by setting the trap flag bit on the stack from inside the procedure. Example 12–2 shows an interrupt service procedure that turns tracing off by clearing the trap flag on the stack from within the procedure.
In both examples, the flag register is retrieved from the stack by using the BP register, which, by default, addresses the stack segment. After the flags are retrieved, the TF bit is either set (TRON) or clears (TROFF) before returning from the interrupt service procedure. The IRET instruction restores the flag register with the new state of the trap flag.
Trace Procedure. Assuming that TRON is accessed by an INT 40H instruction and TROFF is accessed by an INT 41H instruction, Example 12–3 traces through a program immediately fol- lowing the INT 40H instruction. The interrupt service procedure illustrated in Example 12–3 responds to interrupt type number 1 or a trap interrupt. Each time that a trap occurs—after each instruction executes following INT 40H—the TRACE procedure stores the contents of all the 32-bit microprocessor registers in an array called REGS. This provides a register trace of all the instructions between the INT 40H (TRON) and INT 41H (TROFF) if the contents of the registers stored in the array are saved.
Storing an Interrupt Vector in the Vector Table
In order to install an interrupt vector—sometimes called a hook—the assembler must address absolute memory. Example 12–4 shows how a new vector is added to the interrupt vector table by using the assembler and a DOS function call. Here, the vector for INT 40H, for interrupt procedure NEW40, is installed in memory at real mode vector location 100H–103H. The first thing accomplished by the procedure is that the old interrupt vector contents are saved in case we need to uninstall the vector. This step can be skipped if there is no need to uninstall the interrupt.
The function AX = 3100H for INT 21H, the DOS access function, installs the NEW40 procedure in memory until the computer is shut off. The number in DX is the length of the software in paragraphs (16-byte chunks). Refer to Appendix A for more detail about this DOS function.
Notice that the INT40 function has an IRET instruction before ENDP. This is required because the assembler has no way of determining if the FAR procedure is an interrupt procedure. Normal FAR procedures do not need a return instruction, but an interrupt procedure does need an IRET. Interrupts must always be defined as FAR.