CS-220, Sec. 90, Week 10-C
R. Eckert

INTERRUPTS

An interrupt is a signal that can cause the processor to suspend execution
of the current program and transfer control to another program called an
"interrupt service routine" (ISR), also known as an "interrupt handler."

Types of interrupts--

Hardware: the source of the interrupt is some device connected to the
computer. These can be further subdivided into "maskable" and
"non-maskable" interrupts. Maskable interrupts can be disabled, which means
that they will not be responded to. Non-maskable interrupts cannot be
disabled and are always responded to by the processor. These could be used
to alert the processor of catastrophic events such as a power failure.

Internally generated: These signals are generated internally by the
processor in response to certain conditions. They are also called "traps."
For example, 80x86 processors generate an internal interrupt whenever 
there is divide overflow (the result of a division is too large to fit 
in the quotient register).

Software: Some processors have instructions in their instruction
sets that will generate an interrupt whenever they are executed. For
example, the 80x86 INT instruction does this.

Intel 80x86 interrupts--

Interrupts on the 80x86 family of processors are "vectored." In this
system, the start address of the interrupt service routine is obtained
from a table of "interrupt vectors." This table is memory resident and
begins at absolute address 0. Each entry in the table is four bytes long.
The low order two bytes specify the offset part of the start address of
the ISR, and the high order two bytes the base address (divided by 16) of
the segment containing the ISR. An "interrupt type number" is provided by
the interrupting device (in the case of hardware interrupts) or as the
operand of the INT instruction (in the case of software interrupts). The
type number is a single byte, which means that there can be up to 256
possible values. The address of the vector that points to the ISR that
corresponds to a given type number is computed by the processor by
multiplying the type number by 4.

The 80x86 has two hardware interrupt input signals, called INTR and NMI.
The former is maskable, while the latter is non-maskable. In the case of
devices connected to INTR, it is the responsibility of the interface
circuitry to provide the type number on the data bus after the interrupt
is generated. In the case of NMI, a type number of 2 is always generated.

80x86 maskable interrupts are enabled by the instruction STI and they are
disabled by the instruction CLI. These instructions set or clear,
respectively, the processor's interrupt-enabled status flag.

The following is the sequence of events that automatically occurs anytime
a device activates the INTR signal on an 80x86 processor:

1. A device activates INTR
2. The processor completes execution of the current instruction
3. If the interrupt-enabled flag is set (inerrupts enabled):
    A. The processor's flags register is pushed onto the stack
       (This means that the current status or context is saved)
    B. An interrupt type number is read from the data bus
       (the device must supply this)
    C. Interrupts are disabled
    D. Address of the interrupt vector is computed (4 * type number)
    E. CS and IP are pushed onto the stack
       (This means that the address of the next instruction is saved)
    F. CS and IP are loaded with the interrupt vector from the table
       (address from step D)

As a consequence of this sequence of events, the next instruction will be
fetched from the address obtained from the table of interrupt vectors.
This effectively transfers control to the first instruction of the
appropriate ISR. (Note for this to work properly, the table of interrupt
vectors must be set up before interrupts will be handled. Also, the actual 
code for the ISR must also be be preloaded at the correct address--the 
address specified by the interrupt vector.)

Also, note that the address of the instruction after the one that was
executing when the interrupt came along has been safely saved on the
stack.

What must an ISR do?

1. It must save any registers it will alter (crucial!)
2. If it is to be interruptable, it must enable interrupts (STI)
3. It should "do it's thing"--for HW interrupts, this will usually
   be to perform (control) the I/O from or to the device that generated
   the interrupt
4. It must restore any registers it saved in step 1
6. It must execute an IRET instruction

The IRET instruction performs three pops of the stack--the first into IP,
the second into CS, and the third into the flags register. This guarantees
that the next instruction to be fetched will be the one following the
instruction that was executing when the interrupt was generated. It also
guarantees that all the status flags will be restored to the values they
had when the original program was executing.

Interrupts on PC and PC-compatible computers--

Many I/O devices contected to a PC are interrupt driven. Some of the
devices and the type numbers (also called IRQs) that are generated for
them by the interrupt circuitry inside the PC are:

Device              type #  Some Details

Timer/Oscillator 0    8     Generated every 54.9 msec, used by OS to 
                            update the time of day.
Keyboard              9     Generated with any key press or key release.
                            A keyboard "scan code" will be in Port 60h.
Serial Port          12
Diskette Drive       14
Parallel Printer     15

Software Interrupts and Operating System Services on a PC--

As mentioned above, the INT instruction generates a software interrupt.
The same basic sequence of events as given above occurs, with the
exception of Step B. The interrupt type number, instead of coming from a
device, is obtained from the operand in the instruction. For example, in
the following instruction:

                       INT 35

the type number is 35.

In many ways the INT instruction is like a call to a far procedure. The
main difference is that in the case of a CALL, the address of the
procedure is given in the instruction, whereas, in the case of the INT,
the address must come from the table of interrupt vectors. Therefore it is
very easy to implement "relocatable" procedures as interrupt service
routines. The only thing that is necessary to relocate the routine is to
change 4 bytes in the table of interrupt vectors.

This means that the INT instruction can be used as an alternative to
calling a procedure--a fact that is used extensively by the operating
system on a PC to provide operating system services, such as the control
of many different I/O devices.

So we can talk about several levels of control of devices. At the lowest
level, we can access the various ports or memory addresses associated with
the device directly. (For example, the program you wrote to output to the
parallel printer.) At a slightly higher level, the Basic Input/Output
System (BIOS) part of the Operating System provides a series of low-level
routines burned into Read-Only Memory (ROM) that provide control services
for many devices. These services can be invoked using the appropriate INT
instruction. Finally, the Disk Operating System (DOS) part of the
Operating System provides higher-level routines loaded into Read/Write
Memory (RAM) when the computer is started. These services can be invoked
by using the DOS interrupt (INT 21h). We've already seen the examples of
single character input from the keyboard and single character output to
the screen.

The following table gives some of the BIOS-level interrupts and the types
of I/O control services provided. (We'll look at some of these in more
detail later.)

  int 10h      Video control services (text/graphics output)
  int 14h      Serial communication services
  int 16h      Keyboard control services (input from keyboard)
  int 17h      Printer services
  int 25h,26h  Disk I/O services (reading/writing disk sectors)

It should be emphasized that these are NOT hardware interrupts generated
by the devices--instead the interrupt service routines associated with
these software interrupts provide code that controls the I/O from these
devices.

Some of the DOS interrupt services provided by int 21h are given below.
In many cases parameters are passed from our program to the DOS routine
(and vice-versa) in general-purpose registers.

AH=1   Single-character keyboard input with echo--char returned in AL
AH=2   Single-character screen output--char must be in DL
AH=5   Single character printer output--char must be in DL
AH=7   Single-char keyboard input, no echo--char returned in AL
AH=9   String output--DS:DX points to string; must terminate with '$'
AH=0Ah Buffered keybd input--DS:DX points to buffer
AH=2Ah Get date--AL=day, CX=year, DH=month, DL=day
AH=2Bh Set date--same registers used
AH=2Ch Get time--CH=hour, CL=minute, DH=second, DL=1/100 second
AH=4Ch Terminate a process, remove pgm from memory--AL=return code (0)
AH=31h Terminate & stay resident--AL=0, DX=# of paragraphs to stay resident
AH=25h Set interrupt vector--AL=type #, DS:DX=must contain vector to ISR*
AH=35h Get interrupt vector--AL=type #, ES:BX will contain vector to ISR*
AH=3C-42h Disk read/write operations

* vector to ISR = segment base : offset of ISR


There are many, many more DOS services available through INT 21h.

It should be pointed out that when a PC is first booted up, the table of
interrupt vectors is loaded with the addresses of all these hardware,
BIOS, and DOS system interrupt service routines. If we want to intercept
any of these interrupts (for example, write our own keyboard handler), we 
need to load the code for our handler into memory, make it resident (DOS 
service 31h can do this for us), and update the appropriate entry in the 
table of interrupt vectors with the vector (base/offset) to the start of
your code (DOS service 25h can do this for us). Furthermore, if we want
to restore the original handler provided by the operating system, we would
need to get the original vector prior to the update (DOS service 35h can
do this for us).


Some 80x86 Traps--

Divide overflow--the processor generates a type-0 interrupt whenever this
occurs. The default ISR outputs an appropriate mesage to the screen.

Single step--If the processor's trap flag is set, the processor will
generate a type-1 interrupt after every instruction is executed.

INTO--This instruction will cause a type-4 interrupt if the overflow
flag is set.