第9章  割り込み管理機能


本章では,RI78V4が提供している割り込み管理機能について解説しています。

9.1 概  要

RI78V4における割り込み管理機能では,マスカブル割り込みが発生した際に起動する割り込みハンドラに関連した機能を提供しています。

なお,RI78V4では,RI78V4が管理する割り込み処理を“割り込みハンドラ”と呼び,RI78V4の管理外で動作する割り込み処理とは区別しています。

以下に,割り込みハンドラとRI78V4の管理外で動作する割り込み処理の差異を示します。

表9−1  割り込みハンドラと割り込み処理の差異

割り込みハンドラ

RI78V4管理外の割り込み処理

サービス・コールの発行



不可

割り込みの種別

マスカブル割り込み

マスカブル割り込み

ソフトウエア割り込み

リセット割り込み

割り込みの優先順位

レベル2,3

レベル0,1(※)

システム・コンフィギュレーション・ファイルでの定義

DEF_INHで定義する

DEF_INHで定義しない



※ 多重割り込みを禁止するアプリケーションの場合は,レベル2,3に割り付けることも可能です。

備考1 割り込み優先度は,対象CPUの優先順位指定フラグ・レジスタで設定します。
なお,割り込み優先度は,その値が小さいほど,高い優先度であることを意味します。


備考2 RI78V4では,割り込みを発生させるハードウエア(割り込みコントローラなど)の初期化処理を行いません。したがって,該当初期化処理については,ブート処理,または初期化ルーチンにおいて,ユーザが記述する必要があります。

9.2 割り込みエントリ処理

割り込みエントリ処理は,割り込みが発生した際にCPUが強制的に制御を移すベクタ・テーブル・アドレスに該当処理(割り込みハンドラブート処理など)への分岐命令を割り付けるためにユーザ・オウン・コーディング部として切り出されたエントリ処理専用ルーチンです。



なお,割り込みハンドラをC言語で記述(システム・コンフィギュレーション・ファイルの割り込みハンドラ定義(DEF_INH)にてTA_HLNG属性を指定)する場合,Cコンパイラが“割り込み要求名に対応した割り込みエントリ処理”を自動的に出力するため,ユーザが割り込みエントリ処理を記述する必要はありません。



割り込みハンドラをアセンブリ言語で記述(システム・コンフィギュレーション・ファイルの割り込みハンドラ定義(DEF_INH)にてTA_ASM属性を指定)する場合,割り込みエントリ処理はユーザが記述する必要があります。なお,ブート処理への分岐に関してはアセンブリ言語で記述する必要があります。

9.2.1 割り込みエントリ処理の基本型

割り込みエントリ処理の記述方法は,該当処理(割り込みハンドラブート処理など)がnear領域に割り付けられているのか,またはfar領域に割り付けられているのかにより異なります。

以下に,割り込みエントリ処理の記述例を示します。

【 near領域に該当処理(割り込みハンドラブート処理など)を割り付ける場合 】

    .PUBLIC   _func_inthdr
 _func_inthdr   .VECTOR  0x002C    ;割り込みハンドラに制御を移す
 
      .SECTION  .text, TEXT        ;ベクタ・テーブル・アドレスの設定
 _func_inthdr:
 
         ............              ;割り込みハンドラの本体処理
 
 

【 far領域に該当処理(割り込みハンドラブート処理など)を割り付ける場合 】

      .EXTERN _intent_RESET        ;シンボルの外部参照宣言
      .EXTERN _intent_INTTM00      ;シンボルの外部参照宣言
 
      .SECTION   .vecttable, TEXT  ;ベクタ・テーブルのセクション設定
 _intent_RESET   .VECTOR  0x0000   ;ベクタ・テーブル・アドレスの設定
 _intent_INTTM00 .VECTOR  0x002C   ;ベクタ・テーブル・アドレスの設定
 
      .SECTION  .textf, TEXTF      ;ベクタ・テーブルの設定
 _intent_RESET:
         BR      !!_boot           ;ブート処理に制御を移す
 _intent_INTTM00:
         BR      !!_func_inthdr    ;割り込みハンドラに制御を移す
 

9.2.2 割り込みエントリ処理内での処理

割り込みエントリ処理は,割り込みが発生した際にRI78V4を介在させることなく呼び出されるエントリ処理専用ルーチンです。このため,割り込みエントリ処理を記述する際には,以下に示す注意点があります。

- 記述方法
割り込みエントリ処理は,アセンブリ言語で記述します。
なお,割り込みエントリ処理を記述する場合は,アセンブラの関数呼び出し規約に従った形式で作成してください。



- スタックの切り替え
割り込みエントリ処理を実行するうえで切り替えを必要とするスタックは存在しません。したがって,割り込みエントリ処理内でスタックの切り替えに関する記述を行う必要はありません。


- サービス・コールの発行
RI78V4では,割り込みエントリ処理内でサービス・コールを発行することを禁止しています。


以下に,割り込みエントリ処理として実行すべき処理の一覧を示します。

- ベクタ・テーブル・アドレスの設定

- 該当処理(割り込みハンドラブート処理など)に制御を移す

9.3 割り込みハンドラ

割り込みハンドラは,割り込みが発生した際に起動される割り込み処理専用ルーチンであり,割り込みエントリ処理から呼び出されます。

なお,RI78V4では,割り込みハンドラを“非タスク(タスクとは独立したもの)”として位置づけています。このため,割り込みが発生した際には,システム内で最高優先度を持つタスクが処理を実行中であっても,その処理は中断され,割り込みハンドラに制御が移ります。

以下に,割り込みの発生から割り込みハンドラに制御が移るまでに実行される処理の流れを示します。

図9−1  処理の流れ(割り込みハンドラ)



9.3.1 割り込みハンドラの登録

割り込みハンドラの登録は,割り込みが発生した際にCPUが強制的に制御を移すベクタ・テーブル・アドレスに割り込みエントリ処理(割り込みハンドラへの分岐命令)を記述することにより実現されます。

ただし,割り込みエントリ処理の記述方法は,割り込みハンドラがnear領域に割り付けられているのか,またはfar領域に割り付けられているのかにより異なります。



なお,割り込みハンドラをC言語で記述(システム・コンフィギュレーション・ファイルの割り込みハンドラ定義(DEF_INH)にてTA_HLNG属性を指定)する場合,Cコンパイラが“割り込み要求名に対応した割り込みエントリ処理”を自動的に出力するため,ユーザが該当割り込みエントリ処理を記述する必要はありません。



割り込みハンドラをアセンブリ言語で記述(システム・コンフィギュレーション・ファイルの割り込みハンドラ定義(DEF_INH)にてTA_ASM属性を指定)する場合,割り込みエントリ処理はユーザが記述する必要があります。

9.3.2 割り込みハンドラの基本型

割り込みハンドラをC言語で記述する場合,引き数を持たないvoid型の関数(関数名:任意)として記述します。

また,割り込みハンドラをnear領域に配置するか,far領域に配置するかにより,記述内容が若干異なります。

割り込みハンドラをC言語で記述する場合の基本型を示します。

【 C言語記述の割り込みハンドラをnear領域に配置する場合 】

 #include        <kernel.h>              /*標準ヘッダ・ファイルの定義*/
 #include        <kernel_id.h>           /*システム情報ヘッダ・ファイルの定義*/
 
 void
 __near func_inthdr ( void )
 {
         ............                    /*割り込みハンドラの本体処理*/
         ............
 
         return;                         /*割り込みハンドラの終了*/
 }
 

備考1 システム・コンフィギュレーション・ファイルの割り込みハンドラの定義(DEF_INH)においてTA_HLNG属性,およびTA_NEAR属性を指定します。

備考2 #pragma rtos_interrupt指令は,kernel_id.h内に定義されています(CF78V4が自動的に出力します)。そのため,kernel_id.hは必ずインクルードしてください。

【 C言語記述の割り込みハンドラをfar領域に配置する場合 】

 #include        <kernel.h>              /*標準ヘッダ・ファイルの定義*/
 #include        <kernel_id.h>           /*システム情報ヘッダ・ファイルの定義*/
 
 void
 __far func_inthdr ( void )
 {
         ............                    /*割り込みハンドラの本体処理*/
         ............
 
         return;                         /*割り込みハンドラの終了*/
 }
 

備考1 システム・コンフィギュレーション・ファイルの割り込みハンドラの定義(DEF_INH)においてTA_HLNG属性,およびTA_FAR属性を指定します。

備考2 #pragma rtos_interrupt指令は,kernel_id.h内に定義されています(CF78V4が自動的に出力します)。そのため,kernel_id.hは必ずインクルードしてください。

割り込みハンドラをアセンブリ言語で記述する場合,引き数を持たないvoid型の関数(関数名:任意)として記述します。なお,割り込みハンドラをnear領域に配置する場合とfar領域に配置する場合で,記述内容が若干異なります。

- 割り込みハンドラをnear領域に配置する場合
割り込みハンドラの開始部分でAXレジスタの退避,およびAXレジスタに割り込み要因のベクタ・テーブル・アドレスを設定したのち,システム・スタックへの切り替え処理(関数名:_kernel_int_entry)の呼び出しを,終了部分で終了処理(関数名:_kernel_int_exit)の呼び出しを行います。なお,割り込みハンドラの配置セクションとして,near配置属性のセクションを指定します。


【 アセンブリ言語記述の割り込みハンドラをnear領域に配置する場合 】

 $INCLUDE        (kernel.inc)     ;標準ヘッダ・ファイルの定義
 $INCLUDE        (kernel_id.inc)  ;システム情報ヘッダ・ファイルの定義
    .PUBLIC   _func_inthdr
 
 _func_inthdr   .VECTOR  0x002C   ;割り込みハンドラに制御を移す
 
      .SECTION  .text, TEXT
 _func_inthdr:                    ;割り込みハンドラ
 
      PUSH   AX                   ;AXレジスタの退避
      MOV    AX, #0x002C          ;割り込み要因のベクタ・テーブル・アドレスをAXレジスタに設定
 
    CALL   !!__kernel_int_entry ;システム・スタックの切り替え,レジスタの退避
 
         ............             ;割り込みハンドラの本体処理
 
      BR     !!__kernel_int_exit  ;割り込みハンドラの終了,レジスタの復帰
 
 

備考 システム・コンフィギュレーション・ファイルの割り込みハンドラの定義(DEF_INH)においてTA_ASM属性,およびTA_NEAR属性を指定します。

- 割り込みハンドラをfar領域に配置する場合
割り込みハンドラの開始部分でシステム・スタックへの切り替え処理(関数名:_kernel_int_entry)の呼び出しを,終了部分で終了処理(関数名:_kernel_int_exit)の呼び出しを行います。なお,割り込みハンドラの配置セクションとして,far配置属性のセクションを指定します。


【 アセンブリ言語記述の割り込みハンドラをfar領域に配置する場合 】

 $INCLUDE        (kernel.inc)     ;標準ヘッダ・ファイルの定義
 $INCLUDE        (kernel_id.inc)  ;システム情報ヘッダ・ファイルの定義
    .PUBLIC   _func_inthdr
 
 _func_inthdr   .VECTOR  0x002C
 
      .SECTION  .textf, TEXTF    ;割り込みハンドラ
 _func_inthdr:
    CALL   !!__kernel_int_entry ;システム・スタックの切り替え,レジスタの退避
 
         ............             ;割り込みハンドラの本体処理
 
      BR     !!__kernel_int_exit  ;割り込みハンドラの終了,レジスタの復帰
 
 

備考1 システム・コンフィギュレーション・ファイルの割り込みハンドラの定義(DEF_INH)においてTA_ASM属性,およびTA_FAR属性を指定します。

備考2 割り込みハンドラをfar領域に配置した場合,far分岐情報が必要となります。つまり,ベクタ・テーブル・アドレスからfar分岐情報へ分岐し,そこから割り込みハンドラへ分岐します。このfar分岐情報はCF78V4がシステム情報テーブル・ファイルに自動的に出力します。

備考3 割り込みハンドラの開始部分でAXレジスタの退避,および,AXレジスタに割り込み要因のベクタ・テーブル・アドレスを設定する処理は,CF78V4がシステム情報テーブル・ファイルに自動的に出力します(上記のfar分岐情報に含まれます)。

9.3.3 割り込みハンドラ内での処理

RI78V4では,割り込みハンドラを“非タスク”として位置づけています。

また,RI78V4では,割り込みハンドラに制御を移す際に“独自の前処理”を,割り込みハンドラから制御を戻す際にも“独自の後処理”を実行しています。

このため,割り込みハンドラを記述する際には,以下に示す注意点があります。

- 記述方法
割り込みハンドラは,「9.3.2 割り込みハンドラの基本型」で示された関数形式でC言語,またはアセンブリ言語を用いて記述します。


- スタックの切り替え
C言語で記述した割り込みハンドラについては,Cコンパイラが“システム・スタックへの切り替え処理(関数名:_kernel_int_entry)の呼び出し”を自動的に出力するため,ユーザが該当切り替え処理を記述する必要がありません。
なお,アセンブリ言語で記述された割り込みハンドラについては,割り込みハンドラの開始部分でAXレジスタの退避,および,AXレジスタに割り込み要因のベクタ・テーブル・アドレスの設定を行ったのち,“システム・スタックへの切り替え処理(関数名:_kernel_int_entry)の呼び出し”を,終了部分で“終了処理(関数名:_kernel_int_exit)の呼び出し”を明示的に行う必要があります。



- レジスタの退避/復帰
C言語で記述した割り込みハンドラについては,Cコンパイラが“_kernel_int_entryの呼び出し”および“_kernel_int_exitの呼び出し”を自動的に出力するため,ユーザが該当退避/復帰処理を記述する必要がありません。
なお,アセンブリ言語で記述された割り込みハンドラについては,“レジスタの退避処理(関数名:_kernel_int_entry)の呼び出し”を,終了部分で“レジスタの復帰処理(関数名:_kernel_int_exit)の呼び出し”を明示的に行うことにより,汎用レジスタ(AX,BC,DE,HL),および,ES,CSといったレジスタの退避/復帰が該当関数内で実行されます。



備考 PSW,および,PCについては,CPUによって自動的に退避/復帰されます。

- 割り込み状態
RI78V4では,割り込みハンドラに制御を移す際に以下の状態となります。
したがって,割り込みハンドラに制御が移った後,該当レベルよりも高い優先順位の割り込みが発生した場合,多重割り込みが受け付けられます。



- マスカブル割り込みの受け付けが許可された状態

IE = 0

- 以下の優先順位の割り込みが禁止された状態

レベル2の割り込みハンドラ処理中の場合: ISP1 = 0,ISP0 = 1

レベル3の割り込みハンドラ処理中の場合: ISP1 = 1,ISP0 = 0

備考 レベル0,1は割り込みハンドラとして定義することができません。

備考 割り込みハンドラ内でマスカブル割り込みの受け付けを禁止(IE = 0)した場合も,割り込みハンドラからの復帰後は,マスカブル割り込みの受け付けが許可状態(IE = 1)となります。

- サービス・コールの発行
RI78V4では,割り込みハンドラを“非タスク”として位置づけています。
このため,割り込みハンドラ内で発行可能なサービス・コールは,“非タスクから発行可能なサービス・コール”に限られます。



備考1 サービス・コールの発行有効範囲についての詳細は,表12−8表12−17を参照してください。

備考2 RI78V4では,割り込みハンドラ内の処理を高速に終了させる目的から,割り込みハンドラ内の処理が完了するまでの間に“ディスパッチ処理(タスクのスケジューリング処理)を伴うサービス・コール(ichg_priisig_semなど)”が発行された場合には,キュー操作,カウンタ操作などといった処理を行うだけであり,実際のディスパッチ処理は,割り込みハンドラからの復帰命令(return命令の発行など)が発行されるまで遅延され,一括して行うようにしています。

9.4 割り込み許可・禁止の制御

9.4.1 RI78V4管理下の割り込みレベル

マイクロコントローラで管理する割り込みレベルは“レベル0〜レベル3”の4レベルです。そのうち,RI78V4では,割り込みからサービス・コールを発行できる割り込みレベルを“レベル2とレベル3”に固定し,“RI78V4管理下の割り込みレベル”としています。

- レベル2とレベル3の割り込みはRI78V4管理下の割り込みレベルです。
レベル2とレベル3からは,サービス・コールを発行することができます。RI78V4管理下の割り込みである“割り込みハンドラ”(タイマ割り込みも割り込みハンドラに含みます)は,レベル2とレベル3に設定する必要があります。


- レベル0とレベル1の割り込みはRI78V4管理外の割り込みレベルです。
レベル0とレベル1からは,サービス・コールを発行することができません。レベル0とレベル1からサービス・コールを発行した場合は動作を保証することができません。RI78V4管理外の割り込みである“割り込み処理”は,レベル0とレベル1に設定する必要があります。ただし,後述の多重割り込みを禁止するユーザ・アプリケーションの場合のみ,例外的にレベル2とレベル3に設定することが可能です。


9.4.2 RI78V4内での割り込み許可・禁止の制御

RI78V4では,割り込みの許可・禁止はPSWレジスタの“ISP1”,“ISP0”ビットを使用して行われます。RI78V4内で割り込みを禁止する場合は“ISP1=0”,“ISP0=1”が設定されます。また,RI78V4内で割り込みを許可する場合は“ISP1=1”,“ISP0=1”が設定されます。

図9−2  PSWレジスタのISP1,ISP0ビット



RI78V4内ではPSWレジスタの“IE”ビットの値はサービス・コールやRI78V4用関数の発行元の値が引き継がれ,EI命令,DI命令による“IE”の操作は行われません。ただし,例外的にRI78V4内でEI命令,DI命令が使用される箇所があります。

- 割り込み禁止指定のタスク起動直前にはDI命令が使用され“IE=0”となります。

- 割り込み許可指定のタスク起動直前にはEI命令が使用され“IE=1”となります。

- アイドル・ルーチンの開始直前にはEI命令が使用され“IE=1”となります。

- 割り込みハンドラの開始処理である__kernel_int_entry関数内の最初は“IE=1”となります。

9.4.3 ユーザ処理上での割り込み許可・禁止の制御

ユーザ・アプリケーション上での割り込み操作には,__EI関数(またはEI命令),__DI関数(またはDI命令)を使用します。タスクなどのユーザ処理上では,DI関数を使用するとすべてのマスカブル割り込みの受け付けが禁止され,EI関数を使用すると“ISP1”,“ISP0”の状態に従ったマスカブル割り込みの受け付けが許可される動作となります。

ユーザ処理開始時の割り込み許可・禁止状態はRI78V4によって設定されます。以下に,その状態の一覧を示します。

表9−2  処理開始時の割り込み許可・禁止状態

開始する処理

IE

ISP1

ISP0

開始時の割り込み許可・禁止状態

初期化ルーチン

0

1

1

割り込み禁止(処理上で許可をした場合は動作保証外)

アイドル・ルーチン

1

1

1

割り込み許可,全割り込みレベル受け付け

タスク

割り込み許可指定時

1

1

1

割り込み許可,全割り込みレベル受け付け

割り込み禁止指定時

0

1

1

割り込み禁止(許可された場合は全割り込みレベル受け付け)

周期

ハンドラ

レベル2割り込み発生時

1

0

1

割り込み許可,割り込みレベル0,1受け付け

レベル3割り込み発生時

1

1

0

割り込み許可,割り込みレベル0,1,2受け付け

割り込み

ハンドラ

レベル2割り込み発生時

1

0

1

割り込み許可,割り込みレベル0,1受け付け

レベル3割り込み発生時

1

1

0

割り込み許可,割り込みレベル0,1,2受け付け

割り込み

処理

レベル0割り込み発生時

0

0

0

割り込み禁止(許可された場合は割り込みレベル0受け付け)

レベル1割り込み発生時

0

0

0

割り込み禁止(許可された場合は割り込みレベル0受け付け)

レベル2割り込み発生時

0

0

1

割り込み禁止(許可された場合は割り込みレベル0,1受け付け)

レベル3割り込み発生時

0

1

0

割り込み禁止(許可された場合は割り込みレベル0,1,2受け付け)



なお,タスクはそれぞれ固有に“IE”の状態を保持します。中断されたタスクが再開される際には,中断前の“IE”の状態に戻ります。

9.5 多重割り込み

RI78V4では,割り込みハンドラ内で再び割り込みが発生することを“多重割り込み”と呼んでいます。

以下に,多重割り込みが発生した際の処理の流れを示します。

図9−3  多重割り込み



割り込みハンドラに制御が移る際は,マスカブル割り込みの受け付けが許可された状態“IE = 1”となります。このため,割り込みハンドラ上では基本的に多重割り込みが受け付けられます。タイマ割り込みやそこから呼び出される周期ハンドラも同様に,多重割り込みが受け付けられます。

割り込み処理に制御が移る際は,マスカブル割り込みの受け付けが禁止された状態“IE = 0”となります(RI78V4が介在しないため,マイクロコントローラの動作に従った動作となります)。このため,割り込み処理上では基本的に多重割り込みが受け付けられません。多重割り込みの受け付けを許可したい場合は,割り込み処理上で__EI関数を呼び出す必要があります。なお,割り込み処理上から割り込みハンドラを多重に受け付けることは禁止しており,割り込みハンドラを多重に受け付けた場合の動作は保証外となります。

多重割り込みを許可するユーザ・アプリケーションの場合は,以下のように割り込みハンドラ/割り込み処理の割り込みレベルを設定する必要があります。

表9−3  設定可能な割り込みレベル(多重割り込みを許可するユーザ・アプリケーションの場合)

割り込みハンドラ

割り込み処理

割り込みレベル0

不可



割り込みレベル1

不可



割り込みレベル2



不可

割り込みレベル3



不可



多重割り込みを禁止するユーザ・アプリケーションの場合は,以下のいずれかのパターンに割り込みハンドラ/割り込み処理の割り込みレベルを設定する必要があります。

パターン1: 全割り込みハンドラと全割り込み処理を割り込みレベル2に設定する。

パターン2: 全割り込みハンドラと全割り込み処理を割り込みレベル3に設定する。

パターン3: 全割り込みハンドラを割り込みレベル2に設定し,全割り込み処理を割り込みレベル2,3のいずれかに設定する。割り込みレベル3の割り込み処理中は割り込み禁止(IE = 0)。

表9−4  設定可能な割り込みレベル(多重割り込みを禁止するユーザ・アプリケーションの場合)

パターン1

パターン2

パターン3

割り込みハンドラ

割り込み処理

割り込みハンドラ

割り込み処理

割り込みハンドラ

割り込み処理

割り込みレベル0

不可

不可

不可

不可

不可

不可

割り込みレベル1

不可

不可

不可

不可

不可

不可

割り込みレベル2





不可

不可





割り込みレベル3

不可

不可





不可

可(※)



※この割り込み処理中は割り込み禁止(IE = 0)