例外と割り込み

例外

例外と割り込みの違い

例外とは、プログラムがある処理を実行している途中で、突如として別の仕事(タスク)を要求される処理のことを言います。例外の中で、用途が決まっていない汎用的な例外のことを割り込みと呼んでいます。ARMプロセッサ(Cortex-Mシリーズを除く)では、IRQ/FIQを割り込みとして利用することができます。

Cortex-Aシリーズで発生する例外について、発生要因や制御方法を含めて説明します。

リセット例外

すべてのプロセッサにはリセット入力があり、リセット後に直ちにリセット例外を実行します。リセットは最も優先度が高い例外で禁止できません。

未定義命令例外

次の場合に未定義命令例外が発生します。

  • ●コアが本当に定義されていない命令でオペコードの実行を試みた場合
  • ●適切なコプロセッサがシステムに存在しない場合
  • ●適切なコプロセッサが存在するが、イネーブルされていない場合
  • ●NEON/VFP(Vector Floating Point)のアクセス権が適切に設定されてない場合
  • ●NEON/VFPが停止状態でNEON/VFP命令を実行した場合
  • ●非特権モードで、特権命令の実行をした場合

SVC(スーパーバイザコール)例外

ユーザーモードから特権モード状態で実行する命令を呼び出す場合、SVC命令を使用してSVC例外を発生します。SVC例外を使用する場合、SVC命令とSVC番号を使用しますが、命令フォーマットによってSVC番号の設定範囲が異なります。

【Thumb命令では、8ビットSVC番号を含んでいます】

図1

【ARM命令では、24ビットSVC番号を含んでいます】

図2

SVC番号を示すレジスタはありません。SVC例外ハンドラで、SVC命令のアドレスを求め、命令フォーマットに従いSVC番号を求めなければなりません。

プリフェッチアボート例外

「命令フェッチの失敗」が発生した場合、プリフェッチアボート例外が発生します。IFSR(命令フォールトステータスレジスタ)で発生要因、IFAR(命令フォールトアドレスレジスタ)で発生したアドレスを確認することができます。

【IFSR】

IFSRには、最後の命令フォールトに関するステータス情報が保持されます。32ビットのレジスタとして定義され、特権モードのみでのアクセスが可能です。セキュリティ拡張機能が実装されている場合は、バンクレジスタとなります。

【レジスタフォーマット】

図3
ビット 名称 内容
12 Ext 外部アボートタイプ
外部データアボートの実装定義の分類を提供するために使用可能です。
外部アボート以外のアボートでは、このビットは常に0を返します。
10,3:0 FS フォルトスタータスビット
ARMアーキテクチャリファレンスマニュアル ARMv7-AおよびARMv7-Rエディション VMSA(仮想メモリシステムアーキテクチャ)VMSAv7 IFSRのエンコード」を参照ください。

【レジスタへのアクセス命令】

								MRC p15,0,<Rt>,c5,c0,1 ; IFSRの読み込み。
								MCR p15,0,<Rt>,c5,c0,1 ; IFSRへの書き込み。
								

データアボート例外

「データアクセスの失敗」が発生およびデータボート例外が発生した場合、DFSR(データフォールトステータスレジスタ)で発生要因がわかります。

【DFSR】

DFSRには、最後のデータフォールトに関するステータス情報が保持されます。32ビットレジスタとして定義され、特権モードのみでのアクセスが可能です。セキュリティ拡張機能が実装されている場合は、バンクレジスタとなります。

【レジスタフォーマット】

図4
ビット 名称 内容
12 Ext 外部アボートタイプ
外部データアボートの実装定義の分類を提供するために使用可能です。外部アボート以外のアボートでは、このビットは常に0を返します。
11 WnR アボート発生時のアクセス
0:読み込みアクセスで引き起こされたアボートです。
1:書き込みアクセスで引き起こされたアボートです。
10,3:0 FS フォルトスタータスビット
ARMアーキテクチャリファレンスマニュアル ARMv7-AおよびARMv7-Rエディション VMSA(仮想メモリシステムアーキテクチャ)VMSAv7 DFSRのエンコード」を参照ください。
7:4 ドメイン フォールトアドレスのドメイン

【レジスタへのアクセス命令】

								MRC p15,0,<Rt>,c5,c0,0 ;  DFSRの読み込み。
								MCR p15,0,<Rt>,c5,c0,0 ;  DFSRへの書き込み。
								

割り込み

IRQ割り込み

cpsr(カレントプログラムステータスレジスタ)のIビットが0およびIRQ端子が有効になった場合、IRQ割り込み例外が発生します。IRQ割り込みの禁止・許可はソフトウェアで設定可能です。

コンパイラ組み込み関数を使用してのIRQ割り込み制御方法

ARMコンパイラでは、組み込み関数でIRQ割り込みの許可・禁止を設定できます。

関数名 動作概要
int __disable_irq(void) IRQ割り込みを禁止にし、設定前のIRQ割り込み設定値を返します。
void __disable_irq(void) IRQ割り込みを禁止します。
void __enable_irq(void) IRQ割り込みを許可します。

全アーキテクチャで動作可能なIRQ割り込み制御プログラム例

cpsrのリード・モディファイ・ライト動作を行いますので、アトミック(*1)な操作ではありません。

								I_Bit   EQU   0x80	; IRQビットを定義。

								; IRQ割り込みを許可。
								; 関数型式:void enable_irq(void)
								enable_irq
								    MSR r0,CPSR		; cpsrをr0レジスタに読み込み。
								    BIC r0,#I_Bit	; Iビットを0に設定。
								    MRS CPSR_c,r0	; cpsrにr0レジスタを書き込み。
								    BX  lr			; 関数をリターン。

								; IRQ割り込みを禁止。
								; 関数型式:void disable_irq(void)
								disable_irq
								    MSR r0,CPSR		; cpsrをr0レジスタに読み込み。
								    ORR r0,#I_Bit	; Iビットを1に設定。
								    MRS CPSR_c,r0	; cpsrにr0レジスタを書き込み。
								    BX  lr			; 関数をリターン。
								
  • (*1)アトミックとは、複数の操作を組み合わせた場合、システムの他の部分から見て、一つの操作になることです。

ARMv6以降で動作可能なIRQ割り込み制御プログラム例

Cortex-Aシリーズでは、ARM v6以降で使用できる、IRQ割り込み許可・禁止命令を使用可能です。

								; IRQ割り込みを許可。
								; 関数型式:void enable_irq(void)
								enable_irq
								    CPSIE I			; IRQ割り込みを許可。
								    BX    lr		; 関数をリターン。
								; IRQ割り込みを禁止。
								; 関数型式:void disable_irq(void)
								disable_irq
								    CPSID I			; IRQ割り込みを禁止。
								    BX    lr		; 関数をリターン。
								

FIQ割り込み

cpsrのFビットが0およびFIQ端子が有効になった場合、FIQ割り込み例外が発生します。FIQ割り込みの禁止・許可はソフトウェアで設定可能です。

コンパイラ組み込み関数を使用してのFIQ割り込み制御方法

ARMコンパイラでは、組み込み関数でFIQ割り込みの許可・禁止を設定できます。

関数名 動作概要
int __disable_fiq(void) FIQ割り込みを禁止にし、設定前のFIQ割り込み設定値を返します。
void __disable_fiq(void) FIQ割り込みを禁止します。
void __enable_fiq(void) FIQ割り込みを許可します。

全アーキテクチャで動作可能なFIQ割り込み制御プログラム例

cpsrのリード・モディファイ・ライト動作を行いますので、アトミックな操作ではありません。

								F_Bit   EQU   0x40	; FIQビットを定義。

								; FIQ割り込みを許可。
								; 関数型式:void enable_fiq(void)
								enable_fiq
								    MSR r0,CPSR		; cpsrをr0レジスタに読み込み。
								    BIC r0,#F_bit	; Fビットを0に設定。
								    MRS CPSR_c,r0	; cpsrにr0レジスタを書き込み。
								    BX  lr			; 関数をリターン。

								; FIQ割り込みを禁止。
								; 関数型式:void disable_fiq(void)
								disable_fiq
								    MSR r0,CPSR		; cpsrをr0レジスタに読み込み。
								    ORR r0,#F_bit	; Fビットを1に設定。
								    MRS CPSR_c,r0	; cpsrにr0レジスタを書き込み。
								    BX  lr			; 関数をリターン。
								

ARMv6以降で動作可能なFIQ割り込み制御プログラム例

Cortex-Aシリーズでは、ARM v6以降で使用できる、FIQ割り込み許可・禁止命令を使用可能です。

								; IRQ割り込みを許可。
								; 関数型式:void enable_fiq(void)
								enable_fiq
								    CPSIE F			; FIQ割り込みを許可。
								    BX    lr		; 関数をリターン。
								; IRQ割り込みを禁止。
								; 関数型式:void disable_fiq(void)
								disable_fiq
								    CPSID F			; FIQ割り込みを禁止。
								    BX    lr		; 関数をリターン。
								

IRQ割り込み処理ハンドラの記述例

Cortex-Aシリーズで割り込みハンドラを記述する場合、アセンブリ言語で記述することが一般的です。以下の手順で、割り込みハンドラを作成します。

  • ①r0からr3,r12,r14(lr)の各レジスタをスタックに退避。
  • ②irq_handler()関数を呼び出して、割り込み処理を実行。
  • ③スタックから、r0からr3,r12,r14(lr)の各レジスタを復帰。
  • ④r14(lr)を補正し復帰。

IRQ割り込みハンドラ例

								IRQ_Handler
								    PUSH {r0-r3,r12,lr}	; スタックにレジスタを退避。
								    BL    irq_handler	; 割り込みハンドラを呼び出し。
								    POP  {r0-r3,r12,lr}	; スタックからレジスタを復帰。
								    SUBS pc,lr,#4		; リターンアドレスを補正し、例外処理から復帰。
								

なぜ、r0からr3,r12,r14(lr)の各レジスタをスタックに退避するのでしょうか?「AAPCS(ARMアーキテクチャのプロシージャコール標準)」にヒントがあります。

  • ●r4からr11の各レジスタを使用する場合、スタックに退避するので、割り込みハンドラで退避しません。
  • ●r0からr3、r12の各レジスタを使用する場合、スタックに退避しないので、割り込みハンドラでスタックに退避します。
  • ●r14(lr)レジスタは、irq_handler()関数の呼び出しで使用しますので、スタックに退避します。