13. Hawk Interrupts and Traps

Part of the Hawk Manual
by Douglas W. Jones
THE UNIVERSITY OF IOWA Department of Computer Science


13.1. The Trap Vector
13.2. The Trap Registers
13.3. A Trap Service Example

13.1. The Trap Vector

BUSTRAP         = #10
INSTRTRAP       = #20
PRIVTRAP        = #30
MMUTRAP         = #40
COPROCTRAP      = #50

The lowest memory addresses in a Hawk machine are known as the trap and interrupt vector area. When the CPU detects an abnormal condition, either internally or signalled by external hardware, control is transferred to a location in the trap vector. The special conditions detected internally are:

Restart -- location #00
A restart traps indicates power on or an external reset.

Bus -- location #10
A bus trap occurs when the CPU attempts to fetch from nonexistant memory or store in nonexistant or read-only memory. The cause is usually a programming error such as following an invalid pointer or corrupting a return address.

Instruction -- location #20
An instruction trap occurs when the CPU attempts to execute an undefined instruction. The cause is usually an attempt to execute data or a corrupt return address.

Privilege -- location #30
A privileged instruction (CPUGET or CPUSET) was attempted in user state (PSW.level = 11112).

Strictly speaking, the memory management unit and coprocessors are not part of the CPU, although they are closer to it than most other devices. The MMU and coprocessors report the following conditions:

MMU -- location #40
The memory management unit was unable to translate the virtual address provided by the CPU or it detected an attempt to violate the access rights for the indicated address. As with bus traps, programming errors are a common cause of MMU traps.

Coprocessor -- location #50
An attempt was made to access a disabled or nonexistant coprocessor using COGET or COSET.
Additional locations up through #F0 are included in the trap vector and reserved for other traps and device interrupts. Trap service routines and interrupt service routines are the same from the point of view of entry and exit, but traps and interrupts are handled differently by the CPU. Specifically, when a trap condition is reported to or by the CPU, the instruction currently being executed is aborted and the values in registers are preserved as they were immediately before the instruction that caused the trap. In contrast, when an interrupt is requested, the current instruction is allowed to complete before the CPU responds.

13.2. The Trap Registers

TPC — the trap program counter
TMA — the trap memory address
TSV — the trap save register

These registers are documented more fully in the section on processor control registers Each of these registers can be manipulated with the CPUGET and CPUSET instructions.

When an interrupt or trap occurs, the CPU stores the program counter in the trap program counter register TPC. If the trap occurred because of a memory addressing fault, the memory address and a notice of the cause is stored in the trap memory address register TMA. The trap save register TSV is available for use by trap service software. When a trap occurs, the level field of the processor status word PSW is copied into the prior field, before setting the level field to zero. This makes the trap service routine uninterruptable and privileged, and it turns off the memory management unit.

13.3. A Trap Service Example

The following model trap service routine saves the entire system state. We assume that the trap vector itself may be in ROM, with statically allocated RAM addresses for the register save areas associated with each entry in the trap vector, and no recursive trap service routines.

; code to handle illegal memory references
.       =       BUSTRAP
        CPUSET  R2,TSV          ; partially save R2
        LIL     R2,BUSSAVEAREA  ; get the save area pointer
        STORE   R1,R2,svR1      ; save R1
        LIL     R0,SAVEREGS	; join common code for all traps

The above bit of code occupies exactly 14 bytes and allows each trap to be handled using its own register save area. The common code shared by all trap service routines saves the registers as follows:

SAVEREGS:       ; enter with: R2 pointing to save area and stack
                ;             TPC holding user's PC
                ;             TSV holding user's R2
                ;             R1 saved in save area
        STORE   R3,R2,svR3
        CPUGET  R1,TSV
        CPUGET  R3,TPC
        STORE   R1,R2,svR2      ; R2 now properly saved
        STORE   R3,R2,svPC      ; PC now properly saved
        CPUGET  R1,TMA
        CPUGET  R3,PSW
        STORE   R1,R2,svMA
        STORE   R3,R2,svPSW

        ; ... straightforward code to save R4-15

        LOAD    R3,R2,myPSW
        LOAD    R1,R2,myCODE
        CPUSET  R3,PSW          ; this may enable interrupts
        ADDI    R2,R2,svSIZE
        JSRS    R1,R3           ; go serve the trap
        ADDI    R2,R2,-svSIZE

        ; ... code to restore R4-15

        LOAD    R3,R2,svPSW
        LOAD    R1,R2,svPC
        CPUSET  R3,PSW          ; disables interrupts
        CPUSET  R1,TPC
        LOAD    R3,R2,svR3
        LOAD    R1,R2,svR1
        LOAD    R2,R2,svR2
        RTT                     ; return to user!

The above code is written using R1 and R3 as alternate temporaries in order to improve pipeilined execution. On a superscalar machines, using more registers would allow even more parallelism.

The save area specific to each trap service routine, and pointed to by R2 in the above code is assumed to be a record with field offsets declared something like the following:

; trap save area record structure
; (all fields are 1 word, so displacements are shown in words)

myCODE  =  0 <<2  ; pointer to trap-specific routine entry
myPSW   =  1 <<2  ; initial PSW to use for trap service
svPC    =  2 <<2  ; save area for PC
svR1    =  3 <<2  ; save area for registers
svR2    =  4 <<2
svR3    =  5 <<2

...   save areas for R4-12

svRD    = 15 <<2
svRE    = 16 <<2
svRF    = 17 <<2
svPSW   = 18 <<2  ; save area for PSW
svMA    = 19 <<2  ; save area for trap MA
svSIZE  = 20 <<2  ; size of register-save area

Note that the SAVEREGS code assumes that this save area is at the base of a region of memory that will serve as the stack for the trap service routine, and it assumes that the routine called as myCODE uses R2 as a stack pointer for any local variables or temporaries it may require.

The trap and interrupt entry sequence runs with the level field of the PSW set to zero, preventing interrupts. Once the state of the interrupted code is saved, the PSW may be set with a level field that enables some interrupts during the service of this trap or interrupt. The myPSW field of the trap service record allows for this.

If a trap service routines uses only a few registers before returning, an abbreviated version of SAVEREGS can be used that only saves those registers. If a trap service routine uses any coprocessors, it will need to use an extended version of SAVEREGS that saves the required coprocessor registers.

This approach to trap service is at the extreme RISC end of the spectrum! Many machines include complex trap entry hardware that automatically saves and restores blocks of registers.