第9章 割り込み管理機能
備考2 RI78V4では,割り込みを発生させるハードウエア(割り込みコントローラなど)の初期化処理を行いません。したがって,該当初期化処理については,ブート処理,または初期化ルーチンにおいて,ユーザが記述する必要があります。
割り込みエントリ処理は,割り込みが発生した際にCPUが強制的に制御を移すベクタ・テーブル・アドレスに該当処理(割り込みハンドラ,ブート処理など)への分岐命令を割り付けるためにユーザ・オウン・コーディング部として切り出されたエントリ処理専用ルーチンです。
なお,割り込みハンドラをC言語で記述(システム・コンフィギュレーション・ファイルの割り込みハンドラ定義(DEF_INH)にてTA_HLNG属性を指定)する場合,Cコンパイラが“割り込み要求名に対応した割り込みエントリ処理”を自動的に出力するため,ユーザが割り込みエントリ処理を記述する必要はありません。
割り込みハンドラをアセンブリ言語で記述(システム・コンフィギュレーション・ファイルの割り込みハンドラ定義(DEF_INH)にてTA_ASM属性を指定)する場合,割り込みエントリ処理はユーザが記述する必要があります。なお,ブート処理への分岐に関してはアセンブリ言語で記述する必要があります。
.PUBLIC _func_inthdr _func_inthdr .VECTOR 0x002C ;割り込みハンドラに制御を移す .SECTION .text, TEXT ;ベクタ・テーブル・アドレスの設定 _func_inthdr: ............ ;割り込みハンドラの本体処理 |
なお,RI78V4では,割り込みハンドラを“非タスク(タスクとは独立したもの)”として位置づけています。このため,割り込みが発生した際には,システム内で最高優先度を持つタスクが処理を実行中であっても,その処理は中断され,割り込みハンドラに制御が移ります。
なお,割り込みハンドラをC言語で記述(システム・コンフィギュレーション・ファイルの割り込みハンドラ定義(DEF_INH)にてTA_HLNG属性を指定)する場合,Cコンパイラが“割り込み要求名に対応した割り込みエントリ処理”を自動的に出力するため,ユーザが該当割り込みエントリ処理を記述する必要はありません。
割り込みハンドラをアセンブリ言語で記述(システム・コンフィギュレーション・ファイルの割り込みハンドラ定義(DEF_INH)にてTA_ASM属性を指定)する場合,割り込みエントリ処理はユーザが記述する必要があります。
#include <kernel.h> /*標準ヘッダ・ファイルの定義*/ #include <kernel_id.h> /*システム情報ヘッダ・ファイルの定義*/ void __near func_inthdr ( void ) { ............ /*割り込みハンドラの本体処理*/ ............ return; /*割り込みハンドラの終了*/ } |
備考2 #pragma rtos_interrupt指令は,kernel_id.h内に定義されています(CF78V4が自動的に出力します)。そのため,kernel_id.hは必ずインクルードしてください。
#include <kernel.h> /*標準ヘッダ・ファイルの定義*/ #include <kernel_id.h> /*システム情報ヘッダ・ファイルの定義*/ void __far func_inthdr ( void ) { ............ /*割り込みハンドラの本体処理*/ ............ return; /*割り込みハンドラの終了*/ } |
備考2 #pragma rtos_interrupt指令は,kernel_id.h内に定義されています(CF78V4が自動的に出力します)。そのため,kernel_id.hは必ずインクルードしてください。
割り込みハンドラをアセンブリ言語で記述する場合,引き数を持たないvoid型の関数(関数名:任意)として記述します。なお,割り込みハンドラをnear領域に配置する場合とfar領域に配置する場合で,記述内容が若干異なります。
- 割り込みハンドラをnear領域に配置する場合
割り込みハンドラの開始部分でAXレジスタの退避,およびAXレジスタに割り込み要因のベクタ・テーブル・アドレスを設定したのち,システム・スタックへの切り替え処理(関数名:_kernel_int_entry)の呼び出しを,終了部分で終了処理(関数名:_kernel_int_exit)の呼び出しを行います。なお,割り込みハンドラの配置セクションとして,near配置属性のセクションを指定します。
割り込みハンドラの開始部分でAXレジスタの退避,およびAXレジスタに割り込み要因のベクタ・テーブル・アドレスを設定したのち,システム・スタックへの切り替え処理(関数名:_kernel_int_entry)の呼び出しを,終了部分で終了処理(関数名:_kernel_int_exit)の呼び出しを行います。なお,割り込みハンドラの配置セクションとして,near配置属性のセクションを指定します。
- 割り込みハンドラをfar領域に配置する場合
割り込みハンドラの開始部分でシステム・スタックへの切り替え処理(関数名:_kernel_int_entry)の呼び出しを,終了部分で終了処理(関数名:_kernel_int_exit)の呼び出しを行います。なお,割り込みハンドラの配置セクションとして,far配置属性のセクションを指定します。
割り込みハンドラの開始部分でシステム・スタックへの切り替え処理(関数名:_kernel_int_entry)の呼び出しを,終了部分で終了処理(関数名:_kernel_int_exit)の呼び出しを行います。なお,割り込みハンドラの配置セクションとして,far配置属性のセクションを指定します。
備考2 割り込みハンドラをfar領域に配置した場合,far分岐情報が必要となります。つまり,ベクタ・テーブル・アドレスからfar分岐情報へ分岐し,そこから割り込みハンドラへ分岐します。このfar分岐情報はCF78V4がシステム情報テーブル・ファイルに自動的に出力します。
備考3 割り込みハンドラの開始部分でAXレジスタの退避,および,AXレジスタに割り込み要因のベクタ・テーブル・アドレスを設定する処理は,CF78V4がシステム情報テーブル・ファイルに自動的に出力します(上記のfar分岐情報に含まれます)。
- スタックの切り替え
C言語で記述した割り込みハンドラについては,Cコンパイラが“システム・スタックへの切り替え処理(関数名:_kernel_int_entry)の呼び出し”を自動的に出力するため,ユーザが該当切り替え処理を記述する必要がありません。
なお,アセンブリ言語で記述された割り込みハンドラについては,割り込みハンドラの開始部分でAXレジスタの退避,および,AXレジスタに割り込み要因のベクタ・テーブル・アドレスの設定を行ったのち,“システム・スタックへの切り替え処理(関数名:_kernel_int_entry)の呼び出し”を,終了部分で“終了処理(関数名:_kernel_int_exit)の呼び出し”を明示的に行う必要があります。
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といったレジスタの退避/復帰が該当関数内で実行されます。
C言語で記述した割り込みハンドラについては,Cコンパイラが“_kernel_int_entryの呼び出し”および“_kernel_int_exitの呼び出し”を自動的に出力するため,ユーザが該当退避/復帰処理を記述する必要がありません。
なお,アセンブリ言語で記述された割り込みハンドラについては,“レジスタの退避処理(関数名:_kernel_int_entry)の呼び出し”を,終了部分で“レジスタの復帰処理(関数名:_kernel_int_exit)の呼び出し”を明示的に行うことにより,汎用レジスタ(AX,BC,DE,HL),および,ES,CSといったレジスタの退避/復帰が該当関数内で実行されます。
- 割り込み状態
RI78V4では,割り込みハンドラに制御を移す際に以下の状態となります。
したがって,割り込みハンドラに制御が移った後,該当レベルよりも高い優先順位の割り込みが発生した場合,多重割り込みが受け付けられます。
RI78V4では,割り込みハンドラに制御を移す際に以下の状態となります。
したがって,割り込みハンドラに制御が移った後,該当レベルよりも高い優先順位の割り込みが発生した場合,多重割り込みが受け付けられます。
- サービス・コールの発行
RI78V4では,割り込みハンドラを“非タスク”として位置づけています。
このため,割り込みハンドラ内で発行可能なサービス・コールは,“非タスクから発行可能なサービス・コール”に限られます。
RI78V4では,割り込みハンドラを“非タスク”として位置づけています。
このため,割り込みハンドラ内で発行可能なサービス・コールは,“非タスクから発行可能なサービス・コール”に限られます。
備考2 RI78V4では,割り込みハンドラ内の処理を高速に終了させる目的から,割り込みハンドラ内の処理が完了するまでの間に“ディスパッチ処理(タスクのスケジューリング処理)を伴うサービス・コール(ichg_pri,isig_semなど)”が発行された場合には,キュー操作,カウンタ操作などといった処理を行うだけであり,実際のディスパッチ処理は,割り込みハンドラからの復帰命令(return命令の発行など)が発行されるまで遅延され,一括して行うようにしています。
マイクロコントローラで管理する割り込みレベルは“レベル0~レベル3”の4レベルです。そのうち,RI78V4では,割り込みからサービス・コールを発行できる割り込みレベルを“レベル2とレベル3”に固定し,“RI78V4管理下の割り込みレベル”としています。
- レベル2とレベル3の割り込みはRI78V4管理下の割り込みレベルです。
レベル2とレベル3からは,サービス・コールを発行することができます。RI78V4管理下の割り込みである“割り込みハンドラ”(タイマ割り込みも割り込みハンドラに含みます)は,レベル2とレベル3に設定する必要があります。
レベル2とレベル3からは,サービス・コールを発行することができます。RI78V4管理下の割り込みである“割り込みハンドラ”(タイマ割り込みも割り込みハンドラに含みます)は,レベル2とレベル3に設定する必要があります。
- レベル0とレベル1の割り込みはRI78V4管理外の割り込みレベルです。
レベル0とレベル1からは,サービス・コールを発行することができません。レベル0とレベル1からサービス・コールを発行した場合は動作を保証することができません。RI78V4管理外の割り込みである“割り込み処理”は,レベル0とレベル1に設定する必要があります。ただし,後述の多重割り込みを禁止するユーザ・アプリケーションの場合のみ,例外的にレベル2とレベル3に設定することが可能です。
レベル0とレベル1からは,サービス・コールを発行することができません。レベル0とレベル1からサービス・コールを発行した場合は動作を保証することができません。RI78V4管理外の割り込みである“割り込み処理”は,レベル0とレベル1に設定する必要があります。ただし,後述の多重割り込みを禁止するユーザ・アプリケーションの場合のみ,例外的にレベル2とレベル3に設定することが可能です。
RI78V4では,割り込みの許可・禁止はPSWレジスタの“ISP1”,“ISP0”ビットを使用して行われます。RI78V4内で割り込みを禁止する場合は“ISP1=0”,“ISP0=1”が設定されます。また,RI78V4内で割り込みを許可する場合は“ISP1=1”,“ISP0=1”が設定されます。
RI78V4内ではPSWレジスタの“IE”ビットの値はサービス・コールやRI78V4用関数の発行元の値が引き継がれ,EI命令,DI命令による“IE”の操作は行われません。ただし,例外的にRI78V4内でEI命令,DI命令が使用される箇所があります。
ユーザ・アプリケーション上での割り込み操作には,__EI関数(またはEI命令),__DI関数(またはDI命令)を使用します。タスクなどのユーザ処理上では,DI関数を使用するとすべてのマスカブル割り込みの受け付けが禁止され,EI関数を使用すると“ISP1”,“ISP0”の状態に従ったマスカブル割り込みの受け付けが許可される動作となります。
割り込みハンドラに制御が移る際は,マスカブル割り込みの受け付けが許可された状態“IE = 1”となります。このため,割り込みハンドラ上では基本的に多重割り込みが受け付けられます。タイマ割り込みやそこから呼び出される周期ハンドラも同様に,多重割り込みが受け付けられます。
割り込み処理に制御が移る際は,マスカブル割り込みの受け付けが禁止された状態“IE = 0”となります(RI78V4が介在しないため,マイクロコントローラの動作に従った動作となります)。このため,割り込み処理上では基本的に多重割り込みが受け付けられません。多重割り込みの受け付けを許可したい場合は,割り込み処理上で__EI関数を呼び出す必要があります。なお,割り込み処理上から割り込みハンドラを多重に受け付けることは禁止しており,割り込みハンドラを多重に受け付けた場合の動作は保証外となります。