6.7.2. C 言語を使用した単純な割り込みハンドラの記述

__irq 関数宣言キーワードを使用して、単純な割り込みハンドラを C 言語で記述できます。__irq キーワードは、単純な 1 レベルの割り込みハンドラと、サブルーチンを呼び出す割り込みハンドラの両方に使用できます。ただし、__irq キーワードを使用しても SPSR の保存と復元は行われないため、これをリエントラントな 割り込みハンドラに使用することはできません。ここでのリエントラントとは、ハンドラが割り込みを再イネーブルし、それ自身に割り込ませることが可能なことを意味します。詳細については、リエントラント割り込みハンドラを参照して下さい。

__irq キーワードの使用により、以下のようになります。

関数がサブルーチンを呼び出す場合、__irq を使用することにより、破壊される可能性のあるレジスタが保存されるだけでなく、その割り込みモードのリンクレジスタも保存されます。詳細については、「割り込みハンドラからのサブルーチンの呼び出し」を参照して下さい。

Note

Thumb C コードをコンパイルする場合は、この方法で C 言語の割り込みハンドラを作成することはできません。Thumb のコード(--thumb オプションまたは #pragma thumb)をコンパイルするときは、__irq として指定されている関数が ARM モードにコンパイルされます。

しかし、インターワークがイネーブルされている場合には、__irq 関数によって呼び出されるサブルーチンを Thumb モードでコンパイルできます。インターワークの詳細については、「Chapter 4 ARM と Thumb のインターワーク」を参照して下さい。

割り込みハンドラからのサブルーチンの呼び出し

トップレベルの割り込みハンドラからサブルーチンを呼び出す場合に __irq キーワードを使用すると、スタックから lr_IRQ の値が復元されます。そのため、SUBS 命令は、割り込み処理後にこの値を使用して正しいアドレスに復帰できます。

Example 6.14 はこれを実装するコードを示しています。トップレベル割り込みハンドラは、メモリマップされた割り込みコントローラのベースアドレスの値を 0x80000000 から読み出します。このアドレスの値が 1 のとき、トップレベルのハンドラは C で記述されたハンドラに分岐します。

Example 6.14. 

__irq void IRQHandler (void)
{
    volatile unsigned int *base = (unsigned int *) 0x80000000;

    if (*base == 1)          // which interrupt was it?
    {
        C_int_handler();     // process the interrupt
    }
    *(base+1) = 0;           // clear the interrupt
}

armcc でコンパイルすると、Example 6.14 からは以下のコードが生成されます。

IRQHandler PROC
        STMFD    sp!,{r0-r4,r12,lr}
        MOV      r4,#0x80000000
        LDR      r0,[r4,#0]
        SUB      sp,sp,#4
        CMP      r0,#1
        BLEQ     C_int_handler
        MOV      r0,#0
        STR      r0,[r4,#4]
        ADD      sp,sp,#4
        LDMFD    sp!,{r0-r4,r12,lr}
        SUBS     pc,lr,#4
        ENDP

これを、__irq キーワードが使用されていない場合の以下の結果と比較して下さい。

IRQHandler PROC
        STMFD    sp!,{r4,lr}
        MOV      r4,#0x80000000
        LDR      r0,[r4,#0]
        CMP      r0,#1
        BLEQ     C_int_handler
        MOV      r0,#0
        STR      r0,[r4,#4]
        LDMFD    sp!,{r4,pc}
        ENDP
Copyright © 2002-2006 ARM Limited. All rights reserved.ARM DUI 0203GJ
Non-Confidential