Everything
4.2.6.5 割り込み/例外処理ハンドラ

CC-RHでは,C言語で“割り込み”や“例外”が発生したときに呼ばれる“割り込みハンドラ”,“例外ハンドラ”を記述することができます。ここでは,その記述方法などについて説明します。

(1)

割り込み/例外の発生

RH850ファミリでは,割り込みや例外が発生すると,その割り込みや例外に対応したハンドラ・アドレスにジャンプします。

なお,ハンドラ・アドレスの並びや,搭載している割り込みは,RH850の品種ごとに異なります。詳細は,使用する各デバイスのユーザーズマニュアルを参照してください。

具体的な記述方法は「(3) 割り込み/例外ハンドラの記述方法」で説明します。

(2)

割り込み/例外発生時に行う必要のある処理

関数実行時に割り込み/例外が入ると,即座に割り込み/例外処理を行う必要があります。そして割り込み/例外処理が終わると,割り込みが入った時点の関数に戻る必要があります。

したがって,割り込み/例外発生時には,そのときのレジスタ情報を保存し,割り込み/例外処理が終わった後は,そのレジスタ情報を復帰する必要があります。

(3)

割り込み/例外ハンドラの記述方法

割り込み/例外ハンドラの記述上の形態は,通常のC言語関数と変わりませんが,C言語で記述した関数を,CC-RHに対して“割り込み/例外ハンドラ”として認識させる必要があります。CC-RHでは,割り込み/例外ハンドラの指定を“#pragma interrupt指令”で行います。

#pragma interrupt ( 関数指定 [, 関数指定]... ) 
  関数指定 : 関数名 [(割り込み仕様 [, 割り込み仕様]...)]

外側のかっこは省略可能です。

 

関数名は,C言語記述の関数名を記述してください。たとえば,"void func1 ( ) { }"という関数であれば"func1"と指定します。

割り込み関数は,関数の出口コードが通常関数と異なるため,通常関数のように呼び出さないでください。

(a)

割り込み仕様

割り込み仕様には,以下のものを指定できます。

enable=

多重割込の可否を指定します。true/false/manualが記載できます。

-

true

ei/diを出力します。

eipc/eipswの退避/復帰コードを出力します。

-

false(デフォルト)

ei/diを出力しません。

eipc/eipswの退避/復帰コードを出力しません。

-

manual

ei/diを出力しません。

eipc/eipswの退避/復帰コードを出力します。

priority=

channel=

priority,またはchannel のどちらか一方のみ記述可能です(両方書いた場合は,コンパイル・エラーとなります)。

-

priority=

例外発生要因を指定します。以下の字句から1個のみを書くことができます。

SYSERR/FETRAP/TRAP0/TRAP1/RIE/FPP注1/FPI注1/FPINT注2/FPE注3/ FXE注3/UCPOP/MIP/MDP/PIE/MAE/FENMI/FEINT/EIINT_PRIORITYX(X は0から15)

-

channel=

割込発生チャネルを指定します。割り込みの「拡張仕様」を使う場合に選択してください。

EI ハンドラと判断してコードを生成します。

priority,またはchannel を記載しなかった場合は,EIINTと判断します。

fpu=

fpuのコンテキストfpepc/fpsrを退避/復帰するか指定します。true/false/autoが記載できます。

-

true

fpepc/fpsrを退避/復帰します。

-

false

fpepc/fpsrを退避/復帰しません。

-

auto(デフォルト)

-Xfloat=fpuオプションが指定されている場合は,trueを指定したとみなします。

-Xfloat=softの場合は,falseを指定したとみなします。

fxu=注3

fxuのコンテキストfxsr/fxxpを退避/復帰するか指定します。true/false/autoを指定できます。

-

true

fxsr/fxxpを退避/復帰します。

-

false

fxsr/fxxpを退避/復帰しません。

-

auto(デフォルト)

-Xfxu=onオプションが指定されている場合は,fxsr/fxxpを退避/復帰します。

-Xfxu=offの場合は,fxsr/fxxpを退避/復帰しません。

callt=

calltのコンテキストctpc/ctpswを退避/復帰するか指定します。true/falseが記載できます。

-

true(デフォルト)

ctpc/ctpswを退避/復帰します。

-

false

ctpc/ctpswを退避/復帰しません。

resbank注3

関数の出口コードにresbank命令を出力します。また,コンテキスト退避命令列の一部を出力しません。

 

以下の場合は警告を出力します。

-

割り込み仕様fpu=falseを同時に指定した場合

-

-Xreg_mode=22または-Xreg_mode=commonを同時に指定した場合

-

-Xreserve_r2を同時に指定した場合

-

-Xep=fixを同時に指定した場合

 

以下の場合はエラーになります。

-

割り込み仕様priority=に,EIINT以外を同時に指定した場合

param=

例外要因レジスタの値を仮引数で受け取る方法を指定します。

param=( )の中に,仮引数の個数だけ例外要因レジスタ名を指定します。

例外要因レジスタ名は1~4個まで指定可能であり,カンマ(,)で区切って指定します。

指定可能な例外要因レジスタ名は以下の通りです。

eiic,feic,fpsr,fxsr注3,fxxc注3,fxxp注3

 

以下の場合はエラーになります。

-

指定した例外要因レジスタ名と,仮引数の個数が合わない場合

-

同じ例外要因レジスタ名を複数回指定した場合

注 1.

-Xcpu=g3mhが指定されている場合はエラーになります。

注 2.

-Xcpu=g3mhが指定されていない場合はエラーになります。

注 3.

-Xcpu=g4mhが指定されていない場合はエラーになります。

 

割り込み仕様のパラメータは省略できません。

たとえば,“enable=”だけを書くとコンパイル・エラーとなります。割り込み仕様のデフォルトとは,個々の割り込み仕様を書かない場合の動作を意味します。

(b)

割り込み関数定義

割り込み関数の戻り型は,常にvoid型としてください。

割り込み関数の仮引数は,割り込み仕様param=を指定した場合は4個まで,指定しない場合は1個まで記述できます。

仮引数の型は,常にunsigned long型としてください。

param=を指定しない場合は,EIレベル例外であればEIICレジスタの値が,それ以外であればFEICレジスタの値が仮引数に格納されます。

param=を指定した場合は,指定した内容に従って,各例外要因レジスタの値が,対応する仮引数に格納されます。

 

#pragma interrupt handler1 (priority=EIINT)
void handler1(unsigned long a) {  /* a = EIIC; */
    :
}
 
#pragma interrupt handler2
void handler2(unsigned long a) {  /* a = FEIC */
    :
}
 
#pragma interrupt handler3 (param=(eiic,feic,fpsr))
void handler3(unsigned long a, unsigned long b, unsigned long c) {
    /* a = EIIC, b = FEIC, c = FPSR */
    :
}

 

(c)

EIレベル例外の出力コード内容

EIレベル例外の割り込み関数に対して,コンパイラが入口/出口に挿入する命令列を以下に示します。主に,EIINTやFPI等がこれに該当します。
ただし,これらをすべての割り込み関数に挿入するわけではなく,ユーザの#pragma記述やコンパイル・オプション等に応じて必要な処理が出力されます。

<1>

[割り込み関数の入口コード]

(1)コンテキストの退避に使用するスタック領域を確保

(2)割り込み関数中で使用する関数呼び出し前後で内容が保証されないレジスタを退避

(3)EIPC,EIPSWを退避

(4)仮引数を記述した関数の場合,EIICをR6に設定

(5)多重割り込みを許可

(6)CTPC,CTPSWを退避

(7)FPEPC,FPSRを退避

<2>

[割り込み関数の出口コード]

(8)インプレサイス割り込み待ちを設定

(9)FPEPC,FPSRを復帰

(10)CTPC,CTPSWを復帰

(11)多重割り込みを禁止

(12)EIPC,EIPSWを復帰

(13)割り込み関数中で使用した関数呼び出し前後で内容が保証されないレジスタを復帰

(14)コンテキストの退避に使用したスタック領域を解放

(15)eiret

 

次に,具体的な出力コード例を示します。コード例中の番号(1)~(15)は,上記の各処理に記載された番号と対応しています。

なお,必ず出力コード例のとおりの命令が出力されるわけではありません。使用する命令や汎用レジスタ等は,コード例とは異なる場合があります。

例 1.

EIレベル例外の出力例1

#pragma interrupt func1(enable=true, callt=true, fpu=true)
void func1(unsigned long eiic)
{
        ユーザ記述の処理;
}

 

例 2.

EIレベル例外の出力例2
仮引数なし,割り込みの多重化は手動(enable=manual)の場合

#pragma interrupt func1(enable=true, callt=true, fpu=true)
void func1(unsigned long eiic)
 {
        ユーザ記述の処理;
}

 

(d)

FEレベル例外の出力コード内容

FEレベル例外の割り込み関数に対して,コンパイラが入口/出口に挿入する命令列を以下に示します。主に,FEINTやPIE等がこれに該当します。
ただし,これらをすべての割り込み関数に挿入するわけではなく,ユーザの#pragma記述やコンパイル・オプション等に応じて必要な処理が出力されます。

<1>

[割り込み関数の入口コード]

(1)コンテキストの退避に使用するスタック領域を確保

(2)割り込み関数中で使用する関数呼び出し前後で内容が保証されないレジスタすべてを退避

(3)仮引数を記述した関数の場合,FEICをR6に設定

(4)CTPC,CTPSWを退避

(5)FPEPC,FPSRを退避

<2>

[割り込み関数の出口コード]

(6)FPEPC,FPSRを復帰

(7)CTPC,CTPSWを復帰

(8)割り込み関数中で使用する関数呼び出し前後で内容が保証されないレジスタすべてを復帰

(9)コンテキストの退避に使用したスタック領域を解放

(10)feret

 

次に,具体的な出力コード例を示します。コード例中の番号(1)~(10)は,上記の各処理に記載された番号と対応しています。

なお,必ず出力コード例のとおりの命令が出力されるわけではありません。使用する命令や汎用レジスタ等は,コード例とは異なる場合があります。

FEレベル例外の出力例

#pragma interrupt func1(priority=feint, callt=true, fpu=true)
void func1(unsigned long feic)
{
        ユーザ記述の処理;
}

 

(e)

FEレベル例外(復帰/回復不可)の出力コード内容

FEレベル例外(復帰/回復不可)の割り込み関数に対して,コンパイラが入口/出口に挿入する命令列を以下に示します。主に,FENMIやSYSERR等がこれに該当します。

<1>

[割り込み関数の入口コード]

(1)仮引数を記述した関数の場合,FEICをR6に設定

仮引数を記述しない場合は,何も出力されません。

<2>

[割り込み関数の出口コード]

なし

備考

コンテキストの退避/復帰は一切出力されません。
関数呼び出し前後で内容が保証されるレジスタの退避/復帰も出力されません。
関数内で abort() を呼び出してプログラムを終了させるなど,ユーザ・プログラムで適切に処置してください。

 

次に,具体的な出力コード例を示します。コード例中の番号(1)は,上記の各処理に記載された番号と対応しています。

FEレベル例外(復帰/回復不可)の出力例

#pragma interrupt func1(priority=fenmi)
void func1(unsigned long feic)
{
        ユーザ記述の処理;
}

 

(f)

resbank指定をしたEIレベル例外の出力コード内容

resbank指定をしたEIレベル例外の割り込み関数に対して,コンパイラが入口/出口に挿入する命令列を以下に示します。

通常のEIレベル例外の割り込み関数で出力する命令列とは,次の点が異なります。

-

レジスタ・バンク機能が自動的に退避するコンテキストに対する,退避用の命令列がない。

-

同コンテキストに対する,復帰用の命令列のかわりに,resbank命令を出力する。

 

なお,レジスタ・バンク機能が自動的に退避するコンテキストの情報は,-Xresbank_modeオプション指定から判断します。

また,これらをすべての割り込み関数に挿入するわけではなく,ユーザの#pragma記述やコンパイル・オプション等に応じて必要な処理が出力されます。

resbank未指定時

resbank指定時(-Xresbank_mode=0)

_handler:
movea 0xFFFFFFA8, r3, r3
st.w r1, 0x14[r3]     ; save r1
st.w r2, 0x18[r3]     ; save r2
st.w r5, 0x1C[r3]     ; save r5
st23.dw r6, 0x20[r3]  ; save r6,r7
st23.dw r8, 0x28[r3]  ; save r8,r9
st23.dw r10, 0x30[r3] ; save r10,r11
st23.dw r12, 0x38[r3] ; save r12,r13
st23.dw r14, 0x40[r3] ; save r14,r15
st23.dw r16, 0x48[r3] ; save r16,r17
st23.dw r18, 0x50[r3] ; save r18,r19
stsr 0x10, r8, 0x00
stsr 0x11, r9, 0x00
st23.dw r8, 0x00[r3]  ; save CTPC,CTPSW
stsr 0x06, r8, 0x00
st.w r8, 0x08[r3]     ; save FPSR
stsr 0x06, r8, 0x0A
stsr 0x0D, r9, 0x0A
st23.dw r8, 0x0C[r3]  ; save FXSR,FXXP
prepare 0x01, 0x00    ; save r31
jarl _sub, r31
dispose 0x00, 0x01    ; restore r31
ld23.dw 0x0C[r3], r8
ldsr r9, 0x0D, 0x0A   ; restore FXXP
ldsr r8, 0x06, 0x0A   ; restore FXSR
ld.w 0x08[r3], r8
ldsr r8, 6            ; restore FPSR
ld23.dw 0x00[r3], r8
ldsr r9, 0x11, 0x00   ; restore CTPSW
ldsr r8, 0x10, 0x00   ; restore CTPC
ld23.dw 0x50[r3], r18 ; restore r18,r19
ld23.dw 0x48[r3], r16 ; restore r16,r17
ld23.dw 0x40[r3], r14 ; restore r14,r15
ld23.dw 0x38[r3], r12 ; restore r12,r13
ld23.dw 0x30[r3], r10 ; restore r10,r11
ld23.dw 0x28[r3], r8  ; restore r8,r9
ld23.dw 0x20[r3], r6  ; restore r6,r7
ld.w 0x1C[r3], r5     ; restore r5
ld.w 0x18[r3], r2     ; restore r2
ld.w 0x14[r3], r1     ; restore r1
movea 0x58, r3, r3
eiret
_handler:
movea 0xFFFFFFF0, r3, r3
 
 
 
 
 
 
 
 
 
 
stsr 0x10, r8, 0x00
stsr 0x11, r9, 0x00
st23.dw r8, 0x00[r3]  ; save CTPC,CTPSW
 
 
stsr 0x06, r8, 0x0A
stsr 0x0D, r9, 0x0A
st23.dw r8, 0x08[r3]  ; save FXSR,FXXP
prepare 0x01, 0x00    ; save r31
jarl _sub, r31
dispose 0x00, 0x01    ; restore r31
ld23.dw 0x08[r3], r8
ldsr r9, 0x0D, 0x0A   ; restore FXXP
ldsr r8, 0x06, 0x0A   ; restore FXSR
 
 
ld23.dw 0x00[r3], r8
ldsr r9, 0x11, 0x00   ; restore CTPSW
ldsr r8, 0x10, 0x00   ; restore CTPC
resbank  ; restore r1-r19,r30,EIIC,FPSR
 
 
 
 
 
 
 
 
 
 
eiret

 

[備考]

割り込み仕様resbankを使用しても,RBCR0へ値を設定するコードは生成されません。ユーザ・プログラムで直接設定してください。

 

(4)

割り込み/例外ハンドラの記述時の注意事項

-

#pragma interruptは,次の#pragma指令とは同時に指定できません。

#pragma inline_asm,#pragma inline,#pragma noinline,#pragma interrupt,

#pragma block_interrupt