www.riscos.com Technical Support:
Acorn Assembler


Exception handling

This chapter describes the processor configuration and modes used by RISC OS when running on 32 bit architecture ARMs (i.e. ARM6 series and later), and the ways in which this affects exception handling. If you are writing any exception handler that you wish to run on such a processor, you must read both this chapter and the The ARM CPU, especially the Exceptions.

RISC OS processor configuration and modes

Early in its startup code, RISC OS writes to the ARM's control register to change it into the 32 bit program and data space configuration, where it remains. You must not alter the processor's configuration yourself when writing code for RISC OS.

Although RISC OS runs under a 32 bit configuration, it remains in 26 bit modes for normal operation, providing a high degree of backward compatibility with code written to run on earlier 26 bit processors.

However, because the processor is in a 32 bit configuration, all exceptions (including Undefined Instruction and Software Interrupt) force the processor to a privileged 32 bit mode appropriate to the exception. There are therefore some differences in exception handling between 26 and 32 bit architecture ARM chips, although RISC OS provides a considerable degree of backward compatibility by faking 26 bit behaviour on 32 bit architecture chips in most circumstances. For full details, see the next section.

The pre-veneers

To ensure easy backward compatibility, 32 bit aware versions of RISC OS 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 earlier chips' behaviour. 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).

Entering 32 bit modes

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.

Claiming the hardware vectors

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 (page 5-46 of the RISC OS 3 Programmer's Reference Manual), 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:

  • On versions up to RISC OS 3.1, you must write directly to the vector, doing any appropriate housekeeping yourself
  • On later versions you must call OS_ClaimProcessorVector.

Your handler must also cope with running in both 26 bit and 32 bit modes.

Writing to the FIQ vector

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.)

This edition Copyright © 3QD Developments Ltd 2015
Last Edit: Tue,03 Nov 2015