When a hardware device sends a signal to the ARM processor indicating that it needs attention, this is called an interrupt. The process of sending an interrupt is known as an interrupt request. Devices handled by interrupts include the keyboard, printer, mouse, serial port, disc drives and expansion cards, as well as built-in timers.
When an interrupt is received, RISC OS temporarily halts the active task, and enters an interrupt routine. The routine deals with the interrupting device very quickly so it can continue with the previous task as quickly as possible. Often, interrupts are handled so quickly that users never realise their task was temporarily halted.
Interrupts are an efficient method of dealing with hardware devices, as the devices inform the system that it needs attention, rather than the system regularly checking all the devices. Because external hardware, such as expansion cards, can generate new interrupts, it is possible to install new routines to deal with them.
Each device that can generate interrupts has a device number. There are corresponding device vectors, similar to Software Vectors and Hardware Vectors. Installed on each vector is a default device driver that receives only interrupts from that device.
There are two different types of interrupt requests: IRQs (interrupt requests) and FIQs (fast interrupt requests). As the name suggests, FIQs are generated by devices that require their request be serviced more quickly than the normal IRQ request. The ARM processor has a separate mode, its own hardware vector and range of device numbers for dealing with FIQs.
Different RISC OS computers use different interrupt generating hardware. The very early Archimedes range used a variety of different peripheral control chips, whereas later versions used the 82C710 or 82C711 chip. Because different controllers have been used, device numbers differ between models of RISC OS computers. A list of current RISC OS system device numbers is here.
It is possible to claim device vectors and call a routine of your choosing, instead of the default one. With the exception of the Expansion Card interrupts (8 and 13), all device vectors call the most recent routine that claimed the vector. Previous routines that claimed the vector remain on the vector chain, unless they are released. If the most recent routine is released, then the previous owner of the vector is re-installed as the routine that is called.
To claim and release vectors, two SWI calls are used:
When a routine claims a vector, RISC OS first checks the vector chain to see if there are any earlier instances of the same routine claiming this vector. If found, it removes them from the chain before claiming the vector.
When releasing a device vector, RISC OS checks the vector chain for any earlier claimants of the vector. If none are found, it will automatically disable interrupts from the corresponding device. No attempt to manually disable interrupts should be made.
As mentioned earlier, the routine dealing with the interrupting device must do so quickly. If a routine cannot deal with a device quickly, it should re-enable interrupts (as they are disabled automatically when entering a routine). Any routine that re-enables interrupts must be able to cope with further interrupts if they occur, and hence the routine being entered for the second time. This is called re-entrancy.
Routines that handle interrupts must only call the error-returning SWI calls (that is, SWI calls that have their X-bit set). If an error is returned to the routine, appropriate action must be taken within the routine. It may be useful to store an error indicator within the routine, so that the next call to an appropriate SWI (one in the module that provides the routine) will generate an error.
Some SWIs are defined as being re-entrant: that is, they can safely be called even though they are currently in the process of being used already. Some SWIs are deemed to be not re-entrant (i.e. they cannot handle more than one simultaneous call).
As a result of this, non re-entrant SWIs should not be called from within an interrupt handling routine. An example of why this is the case is shown below:
Once the routine has serviced the interrupt, it must also clear the interrupt so that it does continue to generate the same interrupt. The interrupt is cleared by accessing the hardware that is generating the interrupt.
Devices that issue FIQs require them to be handled more quickly, and unlike IRQs no SWI can be called within the handler routine. The default owner of the FIQ vector is the Econet module (which is a proprietary network), and only one owner of the FIQ is supported, so any task that wishes to claim the FIQ vector must follow the process below:
When an interrupt routine is called, interrupts are by default disabled until the routine completes. However, there may be other times when it is desirable to manually disable interrupts (i.e. IRQs). Because interrupts are an important to the integrity of a system it is important to minimise the amount of time interrupts are disabled.
Perhaps the easiest method of enabling and disabling interrupts from user mode is to use the OS_IntOn and OS_IntOff SWIs.
Unlike the method of disabling IRQs, you must be in a privileged mode to disable FIQs or specific devices. To disable specific devices, all interrupts must first have been disabled, before clearing the relevant bits of the interrupt mask registers.