CS452 - Real-Time Programming - Spring 2012

Lecture 12 - Hardware Interrupts

Public Service Annoucements

  1. Wednesday's class
  2. Assignment 3

Hardware Interrupts

What is a Hardware Interrupt?

Context Switches for Interrupts

Difference from Software Interrupts

It is impossible to predict where they occur

Assymmetry between User Task and Kernel

Scratch Registers must be saved

Helpful Features of the ICU

  1. Several places where you can read state
  2. Several places where you can block interrupt flow
  3. Trigger hardware interrupt from software

The Hardware in the Trains Lab

32-bit Timer

Interrupt Control Unit (ICU)

The actual device is the ARM PL190

Hardware Definitions

Registers for Basic Operation
Register Name Offset R/W Description
VICxIRQStatus 0x00 RO One bit for each interrupt source

1 if interrupt is asserted and enabled

VICxFIQStatus 0x04 RO As above for FIQ
VICxRawIntr 0x08 RO As above but not masked
VICxIntSelect 0x0c R/W 0: IRQ, 1: FIQ
VICxIntEnable 0x10 R/W 0: Masked, 1: Enabled
VICxIntEnClear 0x14 WO Clears bits in VICxIntEnable
VICxSoftInt 0x18 R/W Asserts interrupt from software
VICxSoftIntClear 0x1c WO Clears interrupt from software
VICxProtection 0x20 R/W Bit 0 enables protection from user mode access
VICxVectAddr 0x30 R/W Enables priority hardware

See documentation.

Helpful Features of the ICU

  1. Several places where you can read state
  2. Several places where you can block interrupt flow
  3. Trigger hardware interrupt from softwareonce
    1. What makes interrupts hard is that you are doing two semi-hard things at once
      • Making the hardware produce the interrupt
      • Responding to the interrupt
    2. Software interrupt generation allows you to separate them in developing/debugging


Non-vectored Operation

Initialization

  1. Enable interrupt in device
  2. Enable interrupt in ICU
  3. Enable interrupt in CPU, usually by MOVS

Interrupt occurs

  1. AND of IRQ and NOT( IRQ disabled ) is checked before each instruction fetch.
  2. If set IRQ exception is taken in place of next instruction fetch.
  3. Context switch into kernel


    Context switch novelties

    Difference from Software Interrupts


  4. Locate source of interrupt
  5. Collect volatile data
  6. Turn off interrupt in device
  7. Turn off interrupt in device

You are now ready to process the interrupt in the kernel


Vectored Operation

General Idea

The standard way of programming the ICU requires the kernel to query the ICU. Sometimes (!), this is unacceptably inefficient. Then, you have another alternative, vectored interrupts.

Relevant registers:

  1. there are 16 pairs that you write
    Register Name Offset R/W Description Comments
    VICxVectAddry 0x100+4y R/W Vector address for interrupt y Entry point of ISR for interrupt y
    VICxVectCntly 0x200+4y R/W Control register for interrupt y Bit[0-4]: interrupt source for interrupt y
    Bit[5]: enable vectored interrupt y

  2. There is one pair used by the program
    Register Name Offset R/W Description
    VICxVectAddr 0x030 R/W Read: address of vector for highest priority interrupt

    Write: service complete, enable priority hardware

    VICxDefVectAddr 0x034 R/W Default vector address

Procedure

Initialization

  1. Write kernel entry point into VICxDefVectAddr
  2. If desired write special entry point into VICxVectAddry
  3. When ready to accept interrupts write source and enable into VICxVectCntly

When an interrupt occurs

  1. Read VICxVectAddr to find address
  2. Move result to PC
        ldr   pc, #<VicVectAddr>

    (Note that this is similar to the instruction in 0x014. Could we do it all in one?)

  3. Before interrupts are re-enabled write VICxVectAddr to start priority hardware

Answer to question.

Look carefully at what's in 0x18


Clock Server, Task Structure

A New Kernel Primitive: int AwaitEvent( int EventType )

How is AwaitEvent Used?

  1. There should (almost) always be a task blocked on AwaitEvent for every interrupt type. Why?
  2. A server cannot call AwaitEvent. Why?
  3. We call the task that calls AwaitEvent a Notifier. Why?
  4. Code for a typical Notifier
    main( ) {
        Tid server;
        int evtType, data;
        Receive( &server, &evtType, ... );
        // Other initialization
        Reply( server, ... );
        FOREVER {
            data = AwaitEvent( evtType );
            Send( server, &data, ... );
        }
    }
  5. Code for a typical server
    main( ) {
        notifier = Create( HIGHEST, ... );
        // other initialization
        Send( notifier, &evtType, ... );
        FOREVER {
            Receive( &requester, &request, ... );
            switch ( request.type ) {
            case NOTIFIER:
                Reply( notifier );
                data = request.data;
                break;
            case CLIENT:
                ...
            }
        }
    }

More About AwaitEvent

Argument

  1. Somewhere there is a list of event types
  2. This is not very portable

Processing in the kernel

HALT versus an Idle Task

What do you do when there are no tasks to run?


Clock Server

Primitives

int Time( )
int Delay( int ticks )
int DelayUntil( int ticks )

Implementation

main( ) {
    notifier = Create( HIGHEST, ... );
    time = 0
    Send( notifier, &evtType, ... );
    FOREVER {
        Receive( &requester, &request, ... );
        switch ( request.type ) {
        case NOTIFIER:
            Reply( notifier, ... )
            time++;
            break;
        case TIME_REQUEST:
            Reply( requester, time,... )
            break;
        case DELAY_REQUEST: 
            Add requester to list of suspended tasks
            break;
        }
        Check list of suspended tasks and reply
    }
}

Comments:

  1. You need a common request type, or possibly a union.
  2. You should notice a typical server pattern.

It's normal to sort the list of suspended tasks. Why?


Return to: