WRITING AN INTERRUPT SERVICE ROUTINE - GENERAL INFORMATION ABOUT INTERRUPTS
AND THE FILE HLINT.SEQ.
TIM HENDTLASS, PHYSICS DEPARTMENT, SWINBURNE INSTITUTE OF TECHNOLOGY, P.O.BOX
218, HAWTHORNE 3122 AUSTRALIA. JULY 1990.
HLINT provides a mechanism by which interrupt service routines can be written
directly in high level Forth instead of having to be written in assembler.
The FORTH is automatically compiled into ISR form by the ISR: compiler,
following the syntax:-
ISR: high-level-Forth ISR;
ISR: and ISR; automatically install extra code to save the necessary
information, load a new copy of F-PC and then at the end of the ISR to
re-enable interrupts, reset the interrupt controller of the PC and restore
the saved information so that the interrupted task continues as if nothing has
happened. However just writing an ISR to service a source of interrupts is
not enough, the start address of the ISR must also be put in a place where the
processor can find it when an interrupt occurs.
To handle a source of interrupts, one would have to first write the interrupt
service routine and then install it by putting the address of this ISR in the
correct place in the interrupt vector table in the memory region from 0:0 to
0:3FFH. Before you write the address of your new ISR, however, you should note
the current service installed for that interrupt (apparently `unused'
interrupts may have a trap service installed). The address currently there
should be saved so that the original service can be restored later. Of course,
if you are sure you will never want to restore the original service, you can
write over it. To assist when using interrupts with F-PC, a number of
convenience words are provided based on the file INTERRUP.SEQ contributed to
the F-PC package by C.H.Ting. ?INTERRUPT returns the address of the current
interrupt service routine, this can be replaced later with RE-INSTALL-
INTERRUPT. INSTALL-INTERRUPT is used to write the address of a Forth ISR into
a specified position in the vector table and REMOVE-INTERRUPT installs the
address of a `do-nothing' routine. You must never get into the situation
where an interrupt vector `points to' (is the address of) an ISR that no
longer exists. Disaster is assured if you do and this interrupt occurs.
It is sometimes convenient to turn interrupts off and on directly with high
level Forth words. Two trivial Forth words are provided to do just that,
INT-ON and INT-OFF.
AN EXAMPLE OF A HIGH LEVEL ISR.
The example below produces an interrupt driven counter which is incremented at
a regular rate and can be used as the basis for a host of timing purposes.
: DINC ( adr -- ) \ increment a double variable
dup [email protected] 0.1 d+ rot 2!
: INIT-TICKS ( -- ) \ initialize the counter to zero
0 0 ticks 2!
: TICKS? ( -- ) \ read and display the counter
ticks [email protected] ud.
External hardware interrupts the processor in the IBM-PC family at a regular
rate. As well as producing interrupts used by the BIOS in the PC, this
hardware signal triggers interrupt 1Chex which normally is serviced by the
`do nothing' ISR. We may re-vector this interrupt to our own ISR that
increments a 32 bit counter. The interrupt occurs at 18.2 Hz and so our
counter will be incremented approximately once every 55 milliseconds.
We need to install this ISR before it can be used.
' ticking 1C install-interrupt
A couple of other minor words are needed, one to initialize (zero) the value
in the counter and the other to read and display the current value in the
counter. These are also also shown above. INIT-TICKS will zero the counter
and TICKS? will print the current value in the counter. Despite 1C interrupts
occurring at no doubt inconvenient times as Forth continues to be used, all
continues as it should as TICKING meets the requirements of a good ISR - it is
short, fast and it leaves no trace of itself behind on any stack when it has
finished running. As in this example we knew the original interrupt vector we
overwrote was to the `do nothing' routine we did not need to save it, and,
when we are done with TICKING, can safely replace it by typing:
hex 1c remove-interrupt
Remember that interrupt 1C `fires' 18 times or so every second. So it must
always be vectored to a physically existing ISR. Don't leave F-PC and load
another program without performing at least remove-interrupt, or else the
system will crash as the memory image of the ISR code of ticking get
HARDWARE INTERRUPTS ON THE PC/XT/AT FAMILY.
The words given so far control how the processor itself handles interrupts.
Many computers use extra hardware external to the processor that provides
extra control over interrupts, in particular to exercise various forms of
priority control which allow high priority interrupts to take precedence over
lower priority ones. The IBM PC/XT/AT family is no exception and has an 8259A
interrupt priority controller which provides various features at the cost of
having to be programmed. A full discussion of this chip is outside the scope
of this document file but the following should provide enough information to
allow use to be made of the interrupt lines on the I/O bus of the IBM PC
family of computers. For information about features not discussed here, such
as changing the priorities of the various interrupt request signals, the user
is referred to the 8259A data sheet. The I/O bus of the IBM PC and XT
provides six lines, called IRQ2 through IRQ7, each of which signals that an
interrupt service is required when taken high. There are also two other lines
which are on the motherboard but are not bought out onto the I/O bus. The
electrical signals on these lines have to pass through the interrupt
controller chip to get to the processor. The controller decides which, if any
, request should be passed onto the processor. It decides this based on the
priority of the interrupt (whether this is of high enough priority to be
allowed to interrupt what the processor is currently doing) and whether it has
been explicitly been disallowed from passed on this type of interrupt. Each
of the signals from the eight lines may be disabled by writing a 1 to the
appropriate bit in a register inside the 8259A. Bit 3 of this register
controls line IRQ3 etc. The IBM AT has more IRQ lines on the secondary I/O
channel connector and uses the normal IRQ2 to indicate activity on the
secondary onnector IRQ lines.
The eight interrupt request lines on the I/O bus, their normal use, and the
interrupt number they are mapped to are listed below. Each of the lines may
be used by an end user's hardware, although difficulties will be experienced
if the normal `owner' of the lines uses it at the same time. If you do
install your own interrupt service routine for any of these interrupts, make
sure you restore the one normally there when you are done.
This is used for system timing applications and is mapped to interrupt 8.
Interrupt 8 on completion passes control to interrupt 1C hex which is the user
timer interrupt and whose vector normally points to a simple IRET. This line
does not appear on the I/O channel.
This is used for the keyboard and mapped to interrupt vector 9. This line
does not appear on the I/O channel.
This is reserved in the PC and XT. It is used in the AT family and vectored
to interrupt number 0Ahex.
This is normally used by the secondary asynchronous communications device
(COMS2) and is mapped to interrupt number 0Bhex.
This is normally used by the primary asynchronous communications device
(COMS1) and is mapped to interrupt number 0Chex.
This is normally used by the fixed (hard) disk and is mapped to interrupt
This is normally used by the diskette (floppy disk) and is mapped to
interrupt number 0Ehex.
This is normally used by the parallel printer (PRN) and is mapped to
interrupt number 0Fhex.
An interrupt can be signaled by bringing the relevant IRQ line from the low to
the high state. It must be kept in the high state until the interrupt
service routine for this interrupt has been begun. As initialized by the
BIOS, the interrupt controller will not pass a second interrupt signal onto
the processor until it has been given a signal to do so. This signal is given
by the processor writing 20 hex to output port 20 hex. This can be done as
soon as it would be convenient to receive another interrupt. Do not confuse
this signal which re-enables the external interrupt priority controller chip
with the interrupt enable flag inside the processor. The external interrupt
priority controller can stop any specific hardware interrupt signal(s) from
passing onto the processor. The processor interrupt enable flag will stop or
allow all maskable interrupts, hardware or software triggered. The IRQ0
signal is handled by interrupt 8 before being passed onto us at interrupt 1C
hex and the interrupt 8 code resets the interrupt priority controller. This
is why the user timer interrupt was used in the example of a high level
interrupt handler above, it saved having to introduce the extra complication
of resetting this chip at that time. However for virtually all other hardware
interrupts we need to be prepared to handle the chore of resetting this chip.
The mechanism by which the relevant IRQ line was held high until the ISR was
started (usually a flip-flop) must be reset by the ISR routine itself as the
interrupt acknowledge signal from the processor is not bought out onto the I/O
bus. Thus the ISR will need to have two extra items in it over and above what
it needs to suit the processor and the main ISR task to be done - it needs to
reset the interrupt priority controller and it needs to reset the IRQ
The 8259A fairly complex, although it only occupies two output ports it is
programmed by sending information by way of strings of bytes written in
carefully controlled sequences to these two ports. To rewrite the contents of
the interrupt mask register (the register which determine which interrupts
are categorically not to be allowed through), one writes a byte to output port
21 hex, a 1 in bit 0 will allow interrupts from IRQ0 to be processed, a 0 will
prevent them from being processed. The same holds for the other seven bits
and the corresponding IRQ lines. To find the current mask installed, read
input port 21 hex. See an 8259A data sheet or "Interfacing to the IBM
Personal Computer" by Lewis C. Eggebrecht, published by Howard W. Sams & Co.
for the sequences needed to alter other features of the interrupt controller.