www.riscos.com Technical Support:
This chapter describes the ways in which the 32 bit processor configuration used by RISC OS 3.5 and later affects exception handling. If you are writing any exception handler, you must read both this chapter and Hardware vectors.
Exceptions arise whenever there is a need for the normal flow of program execution to be broken, so that (for instance) the processor can be diverted to handle an interrupt from a peripheral. The processor state just prior to handling the exception must be preserved so that the original program can be resumed when the exception routine has completed. Many exceptions may arise at the same time.
ARM handles exceptions by making use of the banked registers to save state. The old PC and PSR are copied, under RISC OS 3.1 or earlier (ie on a 26 bit addressing ARM) to the appropriate R14, or under RISC OS 3.5 or later (ie on a 32 bit configured ARM) to the appropriate R14 and SPSR. The PC and processor mode bits are forced to a value which depends on the exception. Interrupt disable flags are set where required to prevent otherwise unmanageable nestings of exceptions. In the case of a re-entrant interrupt handler, R14 should be saved onto a stack in main memory before re-enabling the interrupt. When multiple exceptions arise simultaneously a fixed priority determines the order in which they are handled.
The FIQ (Fast Interrupt reQuest) exception is externally generated by taking the FIQ pin LOW. This input can accept asynchronous transitions, and is delayed by one clock cycle for synchronisation before it can affect the processor execution flow. It is designed to support a data transfer or channel process, and has sufficient private registers to remove the need for register saving in such applications, so that the overhead of context switching is minimised.
The FIQ exception may be disabled by setting the F flag in the PSR (but note that this is not possible from User mode). If the F flag is clear ARM checks for a LOW level on the output of the FIQ synchroniser at the end of each instruction.
When ARM is successfully FIQed it will:
To return normally from FIQ use:
This will resume execution of the interrupted code sequence, and restore the original mode and interrupt enable state.
The IRQ (Interrupt ReQuest) exception is a normal interrupt caused by a LOW level on the IRQ pin. This input can accept asynchronous transitions, and is delayed by one clock cycle for synchronisation before it can affect processor execution. It has a lower priority than FIQ, and is masked out when a FIQ sequence is entered. Its effect may be masked out at any time by setting the I bit in the PC (but note that this is not possible from user mode). If the I flag is clear ARM checks for a LOW level on the output of the IRQ synchroniser at the end of each instruction.
When ARM is successfully IRQed it will:
To return normally from IRQ use:
This will restore the original processor state and thereby re-enable IRQ.
Under RISC OS 3.5 or later, address exceptions are never generated, and you may therefore ignore this section.
Under RISC OS 3.1 or earlier, an address exception arises whenever a data transfer is attempted with a calculated address above &3FFFFFF. The ARM address bus is 26 bits wide, but an address calculation has a 32 bit result. If this result has a logic '1' in any of the top 6 bits it is assumed that the address overflow is an error, and the address exception trap is taken.
Note that a branch cannot cause an address exception, and a block data transfer instruction which starts in the legal area but increments into the illegal area will not trap (it wraps round to address 0 instead). The check is performed only on the address of the first word to be transferred.
When an address exception is seen ARM will:
Normally an address exception is caused by erroneous code, and it is inappropriate to resume execution. If a return is required from this trap, use SUBS PC,R14_svc,#4. This will return to the instruction after the one causing the trap.
The Abort signal comes from an external Memory Management system, and indicates that the current memory access cannot be completed. ARM checks for an Abort at the end of the first phase of each bus cycle. When successfully Aborted ARM will respond in one of three ways.
If abort is signalled during an instruction prefetch (a Prefetch abort), the prefetched instruction is marked as invalid; when it comes to execution, it is reinterpreted as below. (If the instruction is not executed, for example as a result of a branch being taken while it is in the pipeline, the abort will have no effect.)
Then ARM will:
To continue after a Prefetch abort use SUBS PC,R14,#4 (where R14 is R14_svc or R14_abt depending on the version of RISC OS). The ARM will then re-execute the aborting instruction, so you should ensure that you have removed the cause of the original abort.
If the abort command occurs during a data access (a Data Abort), the action depends on the instruction type.
Then ARM will:
To continue after a data abort, remove the cause of the abort, then reverse any auto-indexing that the original instruction may have done, then return to the original instruction with SUBS PC,R14,#8 (where R14 is R14_svc or R14_abt depending on the processor configuration).
The ARM ignores aborts signalled during internal cycles.
The abort mechanism allows a 'demand paged virtual memory system' to be implemented when a suitable memory management unit (such as MEMC) is available. The processor is allowed to generate arbitrary addresses, and when the data at an address is unavailable the memory manager signals an abort. The processor traps into system software which must work out the cause of the abort, make the requested data available, and retry the aborted instruction. The application program needs no knowledge of the amount of memory available to it, nor is its state in any way affected by the abort.
The software interrupt instruction is used for getting into supervisor mode, usually to request a particular supervisor function. ARM will:
To return from a SWI, use MOVS PC,R14_svc. This returns to the instruction following the SWI.
When ARM executes a coprocessor instruction or an undefined instruction, it offers it to any coprocessors which may be present. If a coprocessor can perform this instruction but is busy at that moment, ARM will wait until the coprocessor is ready. If no coprocessor can handle the instruction ARM will take the undefined instruction trap.
When the undefined instruction trap is taken ARM will:
The undefined instruction trap may be used for software emulation of a coprocessor in a system which does not have the coprocessor hardware; or for general purpose instruction set extension by software emulation (the floating point instruction set is implemented in software this way).
To return from this trap (after performing a suitable emulation of the required function), use MOVS PC,R14 (where R14 is R14_svc or R14_und depending on the processor configuration). This will return to the instruction following the undefined instruction.
ARM can be reset by pulling its RESET pin HIGH. If this happens, ARM will stop the currently executing instruction and start executing no-ops. When RESET goes LOW again, it will:
The first eight words of store normally contain branch instructions pointing to the relevant routines. The FIQ routine may reside at &000001C onwards, and thereby avoid the need for (and execution time of) a branch instruction.
When multiple exceptions arise at the same time, a fixed priority system determines the order in which they will be handled:
Note that not all exceptions can occur at once. Address exception and data abort are mutually exclusive, since if an address is illegal the ARM will ignore the ABORT input. Undefined instruction and software interrupt are also mutually exclusive since they each correspond to particular (non-overlapping) decodings of the current instruction.
If an address exception or data abort occurs at the same time as a FIQ, and FIQs are enabled (ie the F flag in the PSR is clear), ARM will enter the address exception or data abort handler and then immediately proceed to the FIQ vector. A normal return from FIQ will cause the address exception or data abort handler to resume execution. Placing address exception and data abort at a higher priority than FIQ is necessary to ensure that the transfer error does not escape detection, but the time for this exception entry should be added to worst case FIQ latency calculations.
To ensure easy backward compatibility, versions of RISC OS from 3.5 onwards install a pre-veneer on all hardware vectors apart from FIQ (see the chapter entitled Writing to the FIQ vector) and address exception (which is never generated by a 32 bit configured ARM). Each pre-veneer first sets up R14 to contain a combined PC and PSR that will return the processor to the 26 bit mode it was in when the exception arose. It then places the processor in the privileged 26 bit mode used by the earlier 26 bit chips for that exception. It thus effectively fakes the behaviour of earlier versions of RISC OS that run on those chips.
The pre-veneer is called before any exception handlers that are installed with software interfaces such as OS_ChangeEnvironment, so you can usually use such exception handlers unchanged on all versions of RISC OS (hardware dependencies excepted).
One consequence of this is that you may not enter a 32 bit mode with IRQs enabled. Were you to do so, and an IRQ were to occur, the IRQ pre-veneer would be entered; then the IRQ handler would return you to a 26 bit mode, rather than the 32 bit mode you were in at the time of the IRQ.
Note that you shouldn't use 32 bit modes except for writing exception handlers; see the chapter entitled Running 32 bit code.
Under earlier versions of RISC OS, you could also claim the hardware vectors directly, by overwriting the existing instruction on the vector, and replacing it afterwards. It was your responsibility to do any housekeeping, in particular checking for subsequent claimants before restoring the original instruction.
Under 32 bit aware versions of RISC OS, if you attempt to write to any hardware vector other than FIQ a data abort is generated. You must instead call the new SWI OS_ClaimProcessorVector, passing it the address of your exception handler. The handler is installed on the vector, and is called directly, before the pre-veneers. Such handlers are therefore entered in a 32 bit mode.
For handlers installed directly on the vector to work across all versions of RISC OS, you must therefore change the method of claiming and releasing the vector depending on the version of RISC OS:
Your handler must also cope with running in both 26 bit and 32 bit modes.
On a 32 bit architecture ARM, the FIQ vector is entered in FIQ mode (i.e. the 32 bit form of the mode). There are no pre-veneers to simulate 26 bit behaviour. To install a FIQ handler, you must write directly to the FIQ vector, just as always.
The sample code below is the recommended way to write to the FIQ vector on both 26 and 32 bit configured processors - you can use the same code on all versions of RISC OS. Obviously the handler you install must cope with running in both 26 bit and 32 bit FIQ modes. In practice this is unlikely to be a problem, and most existing handlers will run unchanged once installed.
In the code, comments that are prefixed by '32:' apply to a 32 bit configured processor, and comments that are prefixed by '26:' apply to a 26 bit configured processor.
; We assume that at this point, you are already in a privileged 26 bit mode. ; 26: Does not alter processor mode. Reads as follows: ; NOP ; 26: Encodes a NOP (TST Ra,R0) ; Push Ra ; 26: Pushes entry Ra onto stack ; ORR Ra, Ra, #2_11000000 ; 26: Corrupts Ra ; NOP ; 26: Encodes a NOP (TEQ R9,Ra) ; ORR Ra, Ra, #2_10000 ; 26: Corrupts Ra ; NOP ; 26: Encodes a NOP (TEQ R9,Rb) ; 32: Switch to _32 mode with IRQs and FIQs off. ; 32: Must switch interrupts off before switching mode as there can be ; 32: an interrupt after the MSR instruction but before the next one. MRS Ra, CPSR_all ; 32: Read privileged 26 bit mode, Push Ra ; 32: and push it onto the stack ORR Ra, Ra, #2_11000000 ; 32: Set IRQ and FIQ disable bits MSR CPSR_all, Ra ; 32: Disable IRQs and FIQs ORR Ra, Ra, #2_10000 ; 32: Set M4 bit (for 32 bit mode) MSR CPSR_all, Ra ; 32: Change to 32 bit mode ; Now do a NOP, to let things settle down: NOP ; e.g. MOV R0,R0 ; Now in a suitable mode to write FIQ handler code to FIQ vector ; (&1C-&FC incl.), whatever the processor configuration. ; Code written should be able to run in both fiq_32 and fiq_26 modes, ; and should end with a SUBS PC,R14,#4 to return normally. ; For example we might write the handler code like this: ; Assume Rb already points to location from which to copy the handler. MOV LR, #FIQVector ; Get address of FIQ vector 40 LDR Ra, [Rb], #4 ; Get opcode. TEQS Ra, #0 ; All done? STRNE Ra, [LR], #4 ; No, so copy to FIQ area... BNE %BT40 ; ...and repeat for next opcode. ; The above may not be optimal, and is for illustration only. ; Having written FIQ vector, now need to restore the original ; privileged 26 bit mode. ; 26: Does not alter processor mode. Reads as follows: ; PULL Ra ; 26: Pull entry Ra from stack ; NOP ; 26: Encodes a NOP (TST Ra,R0) PULL Ra ; 32: Pull saved CPSR, and MSR CPSR_all, Ra ; 32: Restore privileged 26 bit mode ; Now back where we started, except Ra and Rb should be treated as corrupted. ; (We must assume neither is preserved, because we don't know the processor ; configuration.)
Provides a means for a module to attach itself to one of the processor's vectors
R0 = vector and flags:
|0 - 7||vector number:|
|0||'Branch through 0' vector|
|5||Address exception (only on ARM 2 and 3)|
|(all other values reserved for future use)|
|8||0 RELEASE_ 1 claim|
|9 - 31||reserved, must be 0|
R1 = replacement address of exception handler
R2 = address which should currently be on vector (only needed for release)
R1 = address which has been replaced (only returned on claim)
Interrupt status is undefined
Fast interrupts are enabled
Processor is in SVC mode
This SWI provides a means for a module to attach itself to one of the processor's vectors. This is a direct attachment; you get no environment except what the processor provides.
As such, claiming and releasing the vectors is somewhat primitive - the claims and releases must occur in the right order (the release order being the reverse of claim order). On release if the value in R2 doesn't match what is currently on the vector then an error will be returned. This ensures correct chaining of claims and releases.