Prioritised Interrupts for 6502, 65C02 and 65C816 By Paul Fellingham (smiler@g7fjc.fsnet.co.uk)

In larger systems, where there are several devices that could potentially interrupt, polling each device to see if it was the cause of the interrupt can take considerable time.

Most newer processors have 'Vectored Interrupt' capabilities. The processor generates an Interrupt Acknowledge signal and the interrupting device sends back a byte identifying itself. The processor uses this byte to get the interrupt service routine address from a table of addresses.

With just two 74HC logic devices, it is possible to implement something similar on the 6502, 65C02 or 65C816. The circuit is shown below.

Note - the IRQ line numbers don't match the 74HC148 input numbers. This is because the 74HC148 has active low outputs. With the circuit as shown, the value read by the processor is the number of the IRQ line multiplied by 2.

When any of the 8 interrupt lines is pulled low, the 74HC148 priority encoder pulls its GS pin low. This is connected to the CPU's IRQ line and causes an interrupt.

The interrupt inputs are prioritised, with IRQ0 having the highest priority and IRQ7 having the lowest priority.

It might seem that the latch is unnecessary and a 3-state buffer could be used instead. However, interrupts are not synchronous to the CPU clock. If the interrupt lines changed just as phase-2 went low when the CPU was reading the IRQ port, the CPU could read garbled data and jump to the wrong address. By latching the IRQ value when phase-2 goes high, we guarantee the data will be valid when the CPU reads it.

After pushing registers onto the stack, the processor reads the input port. This gives the number of the highest priority IRQ line that is currently active. The CPU can then use this number to identify the interrupting device. Suitable code for the 65C02 and 65C816 (with 8-bit index) is as follows

IRQ       PHX
          LDX  IRQPORT
          JMP  (IRQTABLE,X)

IQRTABLE  Address of service routine for IRQ0
          Address of service routine for IRQ1
          Address of service routine for IRQ2
          ...

This pushes X onto the stack, then loads the value from the IRQ port into X. This is then used, with indexed indirect addressing, to jump to the start of the appropriate interrupt service routine via a jump table.

With the NMOS 6502, which does not have the preindexed indirect JMP instruction, the following code is required.

IRQ     PHA
        TXA
        PHA
        LDX    IRQPORT
        LDA    IRQTABLE,X
        STA    TEMP
        INX
        LDA    IRQTABLE,X
        STA    TEMP+1
        JMP    (TEMP)

IQRTABLE  Address of service routine for IRQ0
          Address of service routine for IRQ1
          Address of service routine for IRQ2
          ...

This copies the interrupt handler address from the table to a temporary location, then jumps indirectly via this location.

Note that the IRQ port inputs the active IRQ on D1..D3 rather than D0..D2. This automatically multiples the IRQ value by 2 to match the spacing of the jump table.

After an interrupt service routine has finished and executes RTI, if a lower priority interrupt is still active, the processor will be interrupted again. This time, reading the IRQ port will see the lower priority interrupt and the processor will
service the second device.

Note - In order for lower priority interrupts to be seen when two devices interrupt simultaneously, this circuit requires a level sensitive interrupt input on the processor. As a result, it can be used with IRQ on the 65C02 and 65C816 but not with NMI, which is edge-sensitive.

Prioritised interrupts with minimum interrupt level mask


The above circuit, a modification of the original, allows the masking out of interrupts below a particular priority level. A second latch is used to store the interrupt priority level. The current active level is compared with the priority level using a magnitude comparator. This generates an CPU interrupt only when the active interrupt level is lower than that set in the priority latch. (Remember, lower level numbers have higher priority)

A value of 8 written to the priority latch will enable all interrupts.
A value of 5 written to the priority latch will enable IQR0 - IRQ4. IRQ5 - IRQ7 will be disabled.
A value of 3 written to the priority latch will enable IQR0 - IRQ2. IRQ3 - IRQ7 will be disabled.
A value of 0 written to the priority latch will disable all interrupts.

Using this circuit, a long interrupt handler could re-enable higher priority interrupts while lower proirity interrupts would have to wait until the handler has finished.

The code given above for interrupt handler selection is equally suitable for use with this circuit.