13. Interrupts and Traps

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

Contents

13.1. The Trap Vector
13.2. The Trap Registers
13.3. A Prototype Handler


13.1. The Trap Vector

The following assembly language definitions are used here in the discussion of the trap vector:

RESTRAP = #00
BUSTRAP = #10
INSTRAP = #20
PRIVTRAP= #30
MMUTRAP = #40
COPTRAP = #50
; --      #60
; --      #70
IRQ0    = #80
IRQ1    = #90
IRQ2    = #A0
IRQ3    = #B0
IRQ4    = #C0
IRQ5    = #D0
IRQ6    = #E0
IRQ7    = #F0

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

Traps occur because something prevents an instruction from being completed. As a result, the instruction is aborted before it can have any side effects, and control is transferred to a trap handler. Programming errors commonly cause a variety of traps, but some have other uses. The following conditions lead to traps:

Restart -- location 0016 (RESTRAP)
A restart traps indicates power on or an external reset.

Bus -- location 1016 (BUSTRAP)
A bus trap occurs when the CPU attempts to fetch from nonexistant memory or store in nonexistant or read-only memory.

Instruction -- location 2016 (INSTRAP)
An instruction trap occurs when the CPU attempts to execute an undefined instruction. An instruction-trap handler may implement in software (virtualize) instructions that are not implemented in hardware, for example, implementing long Hawk instructions on a Sparrowhawk (see Chapter 16).

Privilege -- location 3016 (PRIVTRAP)
A privileged instruction was encountered when the CPU was running in an unprivileged state. That is, CPUGET or CPUSET (see Section 11.5) was encountered when PSW.level = 11112 (see Section 1.3.4.1).

The memory management unit and coprocessors are not strictly part of the CPU, but they will force traps when instructions that use them cannot be completed:

MMU -- location 4016 (MMUTRAP)
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 (see Section 11.4). As with bus traps, programming errors are a common cause of MMU traps. An MMU-trap handler may be used to virtualize the address space.

Coprocessor -- location 5016 (COPTRAP)
disabled or nonexistant coprocessor referenced by COGET or COSET (see Section 11.4). Unless a trap handler is written to virtualize a non-existant coprocessor, this trap is almost always the result of a programming error.

Two additional locations 6016 and 7016 are included in the trap vector and reserved for future traps.

Interrupts occur because something outside the processor needs service. If an interrupt is requested while an instruction is being executed, that instruction is allowed to execute to completion before control is transferred to an interrupt handler. Examples events that may cause interrupts are timer expiration and key presses.

The final 8 locations in the interrupt-and-trap vector from are conventionally reserved for device interrupts. IRQ0 or 8016 is the highest priority interrupt, a non-maskable interrupt that cannot be disabled by software. Devices asserting IRQ0 must retract their interrupt request immediately when the CPU acts on it or the CPU will hang.

IRQ1 or 9016 through IRQ7 or F016 are controlled by the PSW level field:

There are two distinct ways that multiple devices may be assigned interrupt levels. One uses each level bit as an interrupt-enable bit for one device. In this case, only IRQ1, IRQ3 and IRQ7 should be used for high, medium and low priority devices, and PSW.level = 00002 should never be set to values other than x0002, x0012, x0112 and x1112.

The other approach requires an 8-way priority interrupt encoder, allowing seven distinct interrupt levels in numerical order. This is upward compatible from the simpler model.

13.2. The Trap Registers

Each of these registers can be manipulated with CPUGET and CPUSET (see Section 11.5).

When an interrupt or trap occurs, the CPU first stores the program counter in the trap program counter and the level field of the processor-status word is copied into the prior field, before setting the level field to zero (see Section 1.3.4.1). More formally:

PSW.prior = PSW.level
PSW.level = 00002
TPC = PC PC = trap-vector location

This makes the trap handler uninterruptable and privileged, and it turns off the memory management unit.

In addition, 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 (see Section 1.3.4.3). The trap save register TSV is available for use by trap service routines.

13.3. A Prototype Handler

A typical trap or interrupt handler begins by saving the entire CPU state in memory, then doing something about the trap, and then restoring the (possibly altered) CPU state. Trap handlers that alter the CPU state are common. For example, an unimplemented-instruction-trap handler that implements a virtual machine instruction will change the CPU state the way that machine instruction should.

To speed trap or interrupt service, parts of the state that are not needed by the handler need not be saved. This example saves all of the general purpose registers, but some handlers may only need a few registers. Many handlers make no use of coprocessors, so no coprocessor state is saved by the hanlder given in this example.

The data structure in which the system state is saved can be thought of as a record with one field for each saved register, or it can be thought of as the activation record of the trap handler. The following assembly language definitions describe the record structure for the prototype handler given here:

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

svPC    =  0 <<2  ; save area for PC
svR1    =  1 <<2  ; save area for registers
svR2    =  2 <<2
svR3    =  3 <<2

...   save areas for R4-RC

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

The following prototype handler code assumes that a separate save area with the above structure is statically allocated, in RAM, for each trap or interrupt or trap handler.

Given the above save area structure, the following code for one trap vector entry will begin the process of saving the CPU state and then transfer control to the remainder of the handler which begins by saving the remainder of the CPU state.

; code to handle illegal memory references
.       =       BUSTRAP
        CPUSET  R2,TSV          ; 2  partially save R2
        LOAD    R2,BUSSVP       ; 6  get the save area pointer
        LOADS   PC,PC           ; 8  join common code for all traps
        W       BUSHANDLE       ; 12 code pointer
BUSSVP: W       BUSSVAREA       ; 16 save area pointer

The comments above include accounting for memory used because the trap and interrupt vector entries must occupy no more than 16 bytes each, and the two one word pointers must be word aligned. This code sets up r[2] as a pointer to the save area after using the trap-save register to temporarily cache the old value of r[2]. At the point that control enters the code to save registers, key parts of the CPU state are in TPC and TSV; these must be recovered and saved before the straightforward code to save the other parts of the CPU state.

Note that the BUSHANDLE code given below is just a wrapper around the code that does the actual work. For a bus trap, the actual work could be as simple as outputting an error message and then hanging the CPU awaiting a hardware reset. For an instruction-trap handler, the actual work might involve inspecting the PC in order to inspect the instruction that caused the trap, and then, if the opcode is one that the handler virtualizes, emulating that instruction before returning from trap. For an interrupt handler, the actual work would typicaly involve initiating the next input or output data transfer.

BUSHANDLE:      ; enter with: R2 pointing to save area and stack
                ;             TPC holds user's PC
                ;             TSV holds user's R2
        STORE   R1,R2,svR1      ; save R1
        STORE   R3,R2,svR3      ; save R3
        CPUGET  R1,TSV
        CPUGET  R3,TPC
        STORE   R1,R2,svR2      ; R2 now fully saved
        STORE   R3,R2,svPC      ; PC now fully saved
        CPUGET  R1,TMA
        CPUGET  R3,PSW
        STORE   R1,R2,svMA      ; TMA saved
        STORE   R3,R2,svPSW     ; PSW saved
        STORE   R4,R2,svR4      ; R4 saved
          .
          .   straightforward code to save R5-R14
          .
        STORE   R15,R2,svRF     ; R15 saved
          .
          .   body of trap handler
          .
        LOAD    R15,R2,svRF     ; R15 restored
          .
          .   code to restore R14-5
          .
        LOAD    R4,R2,svR4      ; R4 restored
        LOAD    R3,R2,svPSW
        LOAD    R1,R2,svPC
        CPUSET  R3,PSW          ; PSW restored (interrupts disabled)
        CPUSET  R1,TPC
        LOAD    R3,R2,svR3	; R3 restored
        LOAD    R1,R2,svR1	; R1 restored
        LOAD    R2,R2,svR2	; R2 restored
        RTT                     ; PC restored (return to user!)

The above code is written using R1 and R3 as alternate temporaries in order to improve pipeilined execution.

The code given above all runs with the memory management unit turned off and interrupts disabled. The code for the body of the handler may safely enable interrupts by changing the level field of the processor status word, but note that interrupt handlers should never enable their own or lower priority interrupts.

It is possible to construct variants on the above code that use a common block of code to save and restore registers, avoiding code duplication. It is also possible to have a single register save area shared by multiple traps and interrupts so long as the handlers that share a save area do not themselves cause traps or allow interrupts that require use of the same save area.

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.