# システム状態 (overview)

このカテゴリに入っている関数は、主にCPSR ( Current Program Status Register ) やコプロセッサ15 (CP15) 内の状態を扱うものになります。

## CPSR について

CPSR はステータスレジスタで、内部には、論理演算のステータス、FIQ 割り込みと IRQ 割り込みのディセーブルフラグ、プロセッサモードの情報が含まれます。

N, Z, C, V フラグは論理演算の結果設定される条件ビットです。N は演算結果が負の場合、Z は演算結果が 0 の場合、C は演算でキャリーが発生した場合、V は演算でオーバーフローが発生した場合にセットされます。

Q フラグは QADD, QSUB, QDADD, QDSUB といったサチュレート(飽和)算術命令でオーバーフローの発生を調べるために用いられます。

I フラグ がセットされていると、IRQ 割り込みがディセーブルとなります。

F フラグ がセットされていると、FIQ 割り込みがディセーブルとなります。

T フラグは現在のプロセッサ状態(ARM か Thumb) を表し、セットされていると Thumb です。

mode ビットはプロセッサモードで、以下の7つのうちのどれかになります。TWL の通常実行時は システムモードです。割り込みが入ると IRQ モードになります。

mode bits | モード
--- | ---
0b10000 | ユーザモード
0b10001 | FIQ モード
0b10010 | IRQ モード
0b10011 | スーパバイザモード
0b10111 | アボートモード
0b11011 | 未定義モード
0b11111 | システムモード

## 割り込み状態 (IRQ)

`OS_EnableInterrupts()` は I ビットをクリアします。すなわち、IRQ 割り込みをイネーブルにします。

`OS_DisableInterrupts()` は I ビットをセットします。すなわち、IRQ 割り込みをディセーブルにします。

`OS_RestoreInterrupts()` は I ビットを指定の状態にします。すなわち IRQ割り込みを指定の状態に設定します。

これらの関数は、変更する以前の状態を返します。`OS_EnableInterrupts()` や `OS_DisableInterrupts()` で状態を変更して何らかの処理を行なった後は `OS_RestoreInterrupts()` で元の状態に戻すことに用いられます。通常は次の例のように割り込み状態の変化とその復帰とをペアで使用します。

> `(例)
> OSIntrMode enabled = OS_EnableInterrups();
> :
> (void)OS_RestoreInterrupts( enabled );`

## 割り込み状態 (IRQ と FIQ)

> (注)
> FIQ 割り込みはデバッグツールで使用しているためアプリケーションが使用することは出来ません。また通常使う必要はありません。ここで説明する FIQ を扱う関数はシステムツールやミドルウェアなど一部のソフトで使用するために用意されています。

IRQ 割り込みに関する関数と同様に、IRQ 割り込みと FIQ 割り込みの両方を同時に設定する関数も用意されています。

`OS_EnableInterrupts_IrqAndFiq()` は I ビットと F ビットをクリアします。すなわち、IRQ 割り込みと FIQ 割り込みをイネーブルにします。

`OS_DisableInterrupts_IrqAndFiq()` は I ビットと F ビットをセットします。すなわち、IRQ 割り込みと FIQ 割り込みをイネーブルにします。

`OS_RestoreInterrups()_IrqAndFiq()` は I ビットと F ビットを指定の状態にします。すなわち IRQ 割り込みと FIQ 割り込みを指定の状態に設定します。

これら IRQ 割り込みと FIQ 割り込みに関する関数群も、状態復帰のために `OS_RestoreInterrupts_IrqAndFiq()` が用いられ、Enable - Restore または Disable - Restore のペアで通常は使用します。

> `(例)
> OSIntrMode enabled = OS_EnableInterrups_IrqAndFiq();
> :
> (void)OS_RestoreInterrupts_IrqAndFiq( enabled );`

## 状態取得(IRQ, プロセッサモード)

現在の IRQ 割り込みの設定を取得するには `OS_GetCpsrIrq()` を用います。

現在のプロセッサモードを取得するには、`OS_GetProcMode()` を用います。なお、通常は システムモードで動作しています。

## CPU HALT

CPU で何もすることが無いときに、CPU をHALTさせて消費電力を節約をすることが出来ます。HALT 状態であっても割り込みを受け付け、復帰します。ARM9 、ARM7 ともに `OS_Halt()` でHALT状態になります。

なお、特にアプリケーション側で意識する必要はありませんが、ARM9 では CP15 の機能でHALT状態となり、ARM7 ではシステムコールを使用しています。

## プログラムの停止

現在のプログラム実行を停止する関数として、`OS_Terminate()` が用意されています。この関数の内部では、IRQ 割り込みをディセーブルにして、`OS_Halt()` を呼ぶループとなっています。ループに入ってからは他のスレッドに移行することもありませんし、割り込みハンドラが呼ばれることもありません。NITRO モードでは、この関数は ARM9 プロセッサをループに閉じ込めますが ARM7 は動作し続けます。TWL モードでは、ARM9 プロセッサと ARM7 プロセッサの両方がループに入ります。

`OS_Exit()` や `OS_FExit()` もプログラムの実行を停止する関数です。内部では指定のステータスを表示して `OS_Teminate()` を呼んでいます。こちらは文字列を表示することで `loadrun` や `loadrun.TWL` を停止させることが出来ます。

類似の関数に `OS_Panic()` や `OS_FPanic()` があります。これらの関数は、停止したプログラム位置をソースファイル名と行数で示します。また指定の文字列も併せて表示します。この関数はデバッグ用途で指定され、FINALROM 時には `OS_Terminate()` と同じになります。

> (例)
> `OS_Terminate();
> OS_Exit( 100 );
> OS_Panic( "now stop (x=%d)", myX );`

## ウェイト

`OS_SpinWait()`, `OS_SpinWaitCpuCycles()` , `OS_SpinWaitSysCycles()` は CPU によるループで指定の時間だけウェイトします。しかし、CPU でループしているだけですので、割り込みが発生したりすることで指定の時間よりも長い間、関数から戻ってこない場合があります。指定の時間は「最低限のウェイト時間」と解釈して下さい。

`OS_SpinWait()`は NITRO との互換性を考慮して、ARM9 は約 67MHz, ARM7 は約 33MHz を基準とします。ARM9 の倍速モードに影響されません。

`OS_SpinWaitCpuCycles()`は はCPUサイクルを基準とします。ARM9 が倍速で動作していれば約 134MHz となります。

`OS_SpinWaitSysCycles()` はベースサイクル(約 33MHz) を基準とします。

## 参照

`OS関数一覧(システム状態)`

## 履歴

2009/04/13 プログラムの停止について、プロセッサの動きを修正
2008/05/23 `OS_Panic()` について追記
2007/09/27 `OS_SpinWaitCpuCycles()` , `OS_SpinWaitSysCycles()` を追記
2004/12/14 用語や語尾など修正
2004/11/09 初版