=====================================================================
                         ARM-Mプロセッサ依存部設計メモ
                                  Last Modified:2016 Jan 10 20:10:29
=====================================================================

○このドキュメントの位置づけ

このドキュメントは，TOPPERS/ASPカーネルをARMvX-Mプロセッサに移植するため
の設計メモである．


○ARMVx-Mの仕様まとめ(FPU以外)

ARMvX-Mの仕様のうち，カーネルの設計に関係する事項について，まずARMv7-M
についてまとめる．ARMv6-Mは最後にARMv7-Mとの差分として説明する．

●参考資料

[参考文献1]ARMv7-M Architecture Reference Manual E.b
DDI0403E_B_armv7m_arm.pdf 

[参考文献2]ARM Cortex™-M Programming Guide to Memory Barrier Instructions
Application Note 321

●レジスタ

汎用レジスタはR0～R15の16種類あり，R13のみが2バンク構成（PSP,MSP）とな
っている．R15はPC, R14はリンクレジスタ（LR）となっている．R0～R3,R12は
スクラッチレジスタである．

●コーリングコンベンション

R0～R4が引数，それ以上はスタック．戻り値は，R0～R1に格納される．(ARMに
より規定されているため，コンパイラに依存せずこのルールとなる．)

●CONTROLレジスタ

PSP,MSPの切り替え，PrivilageとUserモードのレジスタ．変更後は，インスト
ラクションバッファフラッシュ命令を実行する必要がある（isb）．CONTROLレ
ジスタの詳細は，ARMv7-M Architecture Application Level Reference 
Manual の B1-9 を参照のこと．

●割込みベクタ

ベクタテーブル型で，ベクタテーブルのアドレスは，リセット時は0x00で，
Vector Table Offset Register（メモリマップドレジスタ） を操作すること
で，任意のアドレスに配置可能である．

●優先度

値が小さい方が高優先度となり，0が最高優先度となる．一方，後述するプロ
セッサの割込み優先度を設定するBASEPRIレジスタは'0'をセットすると，全て
の割込みを許可するため，最高優先度は，有効なビットのLSBを'1'とした値で
ある（3bitの場合は0x20）．また，割込みの優先度に'0'を設定すると，
BASEPRIレジスタでマスクできない割込みとなる．

優先度は最大8bitであり，SoC毎に実装されているビット幅が異なる．実装さ
れるビットが8bit以下の場合は，LSBから無効になる．例えば，実装されてい
るビット幅が7bitの場合は，ビット0が無効となる．

優先度のビットフィールドのLSBから数ビットをサブ優先度と呼ぶフィールド
に設定することが可能である．残りの上位ビットをプリエンプション優先度と
呼ぶ．プリエンプション優先度が同じで，サブ優先度が異なる優先度のグルー
プは，お互いをプリエンプトすることができない．

Reset,NMI,Hard Fault 以外の例外は割込みと同様に優先度が設定可能であり，
割込みマスク機能により，発生を禁止することが可能である．


●CPUモード

プロセッサは，ThreadモードもしくはHandlerモードのいずれかのモードとな
る．

●リセット時の状態

リセット時はThreadモード，MSPが有効となっている．

●Handlerモード

例外/割込みを受け付けると遷移するモード．受け付けた例外/割込みの例外番
号が，IPSRにセットされる．例外番号は，TRMで定められている番号である．

        例外              例外番号
  Reset                      1
  Non-makable Interrupt      2
  Hard Fault                 3
  Memory Management          4
  Bus Fault                  5
  Usage Fault                6
  SVCall                    11
  Debug Monitor             12
  PendSV                    14
  SysTick                   15
  IRQ0                      16
  IRQ1                      17
  ..

例外/割込みを受け付けると，受け付けた例外/割込みの優先度以下の例外/割
込みを禁止する．この優先度マスクを"NVIC優先度マスク"と呼ぶ．この優先度
は，ソフトウェアから変更することができず，例外/割込みのリターンにより
割込み前の値に自動的に戻る．

●スタックポインタ（PSPとMSP）

スタックポインタは，PSPとMSPがあり，排他的に使用可能である．Handlerモ
ードではMSPのみ使用可能であり，ThreadモードではCONTROLレジスタで選択可
能である．CONTROLレジスタの1ビット目をセットするとPSPが有効に，クリア
すると，MSPが有効になる．

●ThreadモードとHandlerモードの遷移

ThreadモードからHandlerモードへの遷移は，例外/割込みを受け付けることで
発生する．一方，HandlerモードからThreadモードへの遷移は，PCに
EXC_RETURN(0xfffffffx)の値を設定することにより行う（例外リターン処理と
呼ぶ）．EXC_RETURNの下位4bitにより，遷移先のモードや使用するスタックポ
インタを変更可能である．例外リターンにより，PRIMASKやBASEPRIの値は変化
しない．一方，FAULTMASKの値は'0'にクリアさせる．

●EXC_RETURN

例外/割込み受付け時にlrに設定される値．ビット31～4ビットは全て'1'で，
下位4bitは，受付け時のCPUモードやスタックを反映した値となっている．

 0b0001 : Handlerモード
 0b1001 : Threadモード with MSP
 0b1101 : Threadモード with PSP

●ThreadモードとHandlerモードの判定

現状のモードを判定するには，IPSRを見て，'0'ならThreadモード，それ以外
なら，Handlerモードとなる．

●BASEPRIレジスタ

設定した優先度以下の優先度の割込みの受付を禁止する．この優先度マスクを
"BASEPRI優先度マスク"と呼ぶ．'0'を設定すると，全ての割込みを許可する．
例外/割込みの受付とリターンにより変化しない．例外/割込みに対する割込み
優先度マスクは，NVIC優先度マスクとBASEPRIの設定値の高い方（値が小さい
方）となる．

●FAULTMASK

FAULTMASKは'1'をセットすることにより，NMI以外の全ての割込みを禁止する．
FAULTMASKは，例外のリターン処理により'0'にクリアさせる．

●PRIMASKとWFI

PRIMASKを'1'に設定すると，NMI と Hardware Fault 以外の例外/割込みを禁
止する．PRIMASKは割込みの許可と割込み待ちをアトミックに行うために用い
る．具体的には，PRIMASKがセットされている状態でwfiを実行すると，割り込
み待ちとなり，割込み受付けるとハンドラを実行せずに，wfiからリターンし
てくる．

●例外/割込みの受付

・例外/割込みを受付けると，受付け時にアクティブなスタック上に以下のコ
  ンテキストを保存する(例外フレームと呼ぶ)．

   -----------
  |    R0     |  <- new SP
   -----------
  |    R1     |
   -----------
  |    R2     |
   -----------
  |    R3     |
   -----------
  |    R12    |
   -----------
  |    LR     |
   -----------
  |    PC     |
   -----------
  |   xPSR    |
   -----------
  |           | <- old SP

・プロセッサをHandlerモードとする．MSPが有効となる．
・受付けた例外/割込みの例外番号をIPSRに設定する．
・NVIC割込み優先度マスクを受付けた例外/割込みの優先度に設定する．
・lrにEXC_RETURNの値が設定される．
・ベクタテーブルを読み込みハンドラを実行する．
・スタックフレームは，Configureation and Control Register(CCR)の
  STKALIGNが'1'の場合は，8byte境界にアラインされる．

●例外/割込みからのリターン

pcにEXC_RETURNの値を設定することにより，例外/割込みからリターンする．
pcへの設定に使用可能な命令には制限があり，以下命令が使用可能である．

  ・POP/LDM, LDR, BX

●未解決課題

・ベクターテーブルに登録する関数のアドレスのLSBは'1'にするべきか?
・NVICは例外・割込みのネスト回数を内部的に管理しているらしい．
  (!リファレンスを明らかに)．
    ソフトウェアでは，ネストの帳尻を合わせれば，リターンスタックを偽造し
    ても問題ないか．

●stmfdの制限

stmfdはレジスタリストが1個の場合の動作は不定となっている．そのため，レ
ジスタリストが1個の記述をアセンブラにした場合は，アセンブラがstr.w に
変換するが，アセンブラによってはワーニングを出すため，レジスタリストが
1個の場合は，str.wを使用する．

なお，ldmfdにはこの制限がない．

●メモリ同期

Cortex-M0/M0+/M3/M4では，SCSのアクセスの前後にはDSB相当が実行される．
ただし，Cortex-M3/M4ではSLEEPONEXITを無効にして例外からリータンする際には，DSBが必要．
[参考文献2] 4.4 SCS peripheral accesses Implementaion requirements

NVICによる割込み許可の直後にペンディングしている割り込みを即座に受けつ
けたい場合は，ISBを実行すればよい．
[参考文献2] 4.5 Enabling Interrupts using NVIC

NVICによる割込み禁止命令の後の命令実行中に割込みを受けつけないようにす
るには，DSB,ISBを実行する必要がある．ただし．前述の通り，
Cortex-M0/M0+/M3/M4 では，ISBのみを記述すればよい．
[参考文献2] 4.5 Enabling Interrupts using NVIC

CPSによる割込み許可の直後にペンディングしている割り込みを即座に受けつ
けたい場合は，ISBを実行すればよい．
[参考文献2] 4.7 Enabling interrupts using CPS instructions and MSR instructions

CPSによる割込み禁止の直後はメモリバリアは必要無い．
[参考文献2] 4.8 Disabling interrupts using CPS and MSR instructions

NVICによる優先度変更を反映した後に命令を実行する場合は，DSB,ISBを実行
する必要がある．ただし．前述の通り，Cortex-M3/M4 では，ISBのみを記述す
ればよい（M0/M0+はサポートしていない）．
[参考文献2] 4.10 Changing priority level of an interrupt



CPS命令による割込み許可

●ARMv6-M

カーネルの設計に対して，ARMv6-MのARMv7-Mに対する差分は次の通りである．

・BASEPRIレジスタ
  ARMv6-MではBASEPRIレジスタを持たない．

・FAULTMASK
  ARMv6-MではFAULTMASKレジスタを持たない．
  
・命令
  一部命令が使用出来ない．
  同じ命令でも指定可能なレジスタに制限がある
  
・外部割込み数
  最大32個
  

○FPU関連の仕様

●参考資料

ARMv7-M Architecture Reference Manual E.b
DDI0403E_B_armv7m_arm.pdf 

ARM CortexR-M4 Processor Technical Reference Manual Revision: r0p1 
arm_cortexm4_processor_trm_100166_0001_00_en.pdf

Cortex-M4(F) Lazy Stacking and Context Switching Application Note 298
DAI0298A_cortex_m4f_lazy_stacking_and_context_switching.pdf

●概要

Cortex-M4はARMv7E-Mをベースとしている．FPUサポートした実装とサポートし
ていない実装がある．FPUをサポートした実装をCortex-M4Fと呼ぶ．
在する．

FPUはARMv7E-M Floatng Point Extension(FPv4-SP)をサポートしている．

FPv4-SPは次の仕様となっている．

レジスタ : 単精度レジスタ S0～S32 / 倍精度レジスタ D0～D15 
           D0は(S0とS1)と等価．
命令     : 単精度命令をサポート

●制御レジスタ

FPSCR : Floating-point Status and Control Register
・FPUのステータスとコントロールフィールドを持つ

CPACR : Coprocessor Access Control Register
・FPUを有効にする場合にセットする必要がある

FPCCR : Floating-point Context Control Register
・FPU関連のコンテキストの保存方法を選択可能

FPCAR : Floating Point Context Address Register
・例外フレームのFPUレジスタの保存アドレス(S0のアドレス)を保持． 

FPDSCR : Floating-point Default Status Control Register
・FPSCRのディフォルト値を保存
・FPUを初めて使用した場合に[26:22]がFPSCRにコピーされる．

CONTROLの拡張
・.FPCA(Bit[2])
  ・FPUを使用すると'1'にセットされる．

EXC_RETURNの拡張

EXC_RETURN[4]
 '0' : FPUの領域あり(保存されているかは別の制御)
       S0～S15とFPSCRのための領域．
 '1' : FPUの領域なし

●ABI

S0～S15,FPSCR  : caller saved registers
S16～S17       : callee saved registers

●例外・割込み発生時の振る舞い

詳細は ARMv7-M Architecture Reference Manual E.bの B1.5.6 Exception 
entry behavior と B1.5.8 Exception return behavior を参照のこと．
 
コンテキストの保存パターン
    FPCCR
 LSPEN  ASPEN      名称(本ドキュメントオリジナル)
   0      0      :  NoAutomatic
   0      1      :  DisableLazystacking
   1      1      :  Lazystacking
 
NoAutomatic 
・自動保存なし

DisableLazystacking
・自動保存あり．Lazystackingしない．
・FPUを使用すると CONTROL.FPCA に'1'がセットされる．
・CONTROL.FPCA == 1の場合に例外/割込みが発生するとFPUコンテキストをス
  タックに保存する．

Lazystacking
・自動保存あり．Lazystacking を行う．
・FPUを使用すると CONTROL.FPCA に'1'がセットされる．
・CONTROL.FPCA == '1'の場合に例外/割込みが発生するとFPUコンテキストの保
  存用の領域のみ確保され，FPCCR.LSPACT に'1'に設定される．
・FPCCR.LSPACT == '1' の場合にFPU命令を使用するとFPUのコンテキストが保
  存領域に保存される．

FPUに関する例外/割込みの入り口処理

・DisableLazystacking or Lazystacking の場合
 ・CONTROL.FPCA == 1の場合
   ・例外フレームにFPUレジスタ保存用の領域を確保
   ・DisableLazystacking の場合
     ・FPUレジスタ保存用の領域にFPUレジスタ(S0～S15,FPSCR)を保存
   ・Lazystacking
     ・FPCAR に例外フレームのFPUレジスタの保存アドレス(S0のアドレス)を保持．
     ・FPCCR.LSPACT を1に．
・CONTROL.FPCAを0にクリア

FPUに関する例外/割込みの出口処理

・EXC_RETURNの4ビット目が'0'の場合(戻り先でFPUを使用していた)
 ・FPCCR.LSPACT == '1'の場合(割込みハンドラでFPUを使用しなかった)
   ・FPCCR.LSPACTを'0'に
 ・FPCCR.LSPACT == '0'の場合(割込みハンドラでFPUを使用した)    
   ・S0～S32とFPSCRを例外フレームから戻す    
・EXC_RETURNの4ビット目の否定をCONTROL.FPCAに設定
 ・実質，戻り先のCONTROL.FPCAを復帰

ISRでのFPUの振る舞い

FPCCR.LSPACT==1時(Lazystackingの時にのみ発生)にFPU命令を使用した場合
・FPCARのアドレスにFPUレジスタ(S0～S15,FPSCR)を保存
・FPCCR.LSPACT を0にする．

○OSの実装

1.ターゲット名

 1-1 cm3(Cortex-M3)
 1-2 armv7m(ARMv7-M)
 1-3 arm_m

cm3では，ARMv6-Mをサポートする場合に問題となる．armv7mでは，armv8mがリ
リースされた場合に問題となる．ARM依存部はJSPでは，armv4となっていたが，
armv5やarmv7も動作するためASPでは単にarmとした．そのため，arm_mが無難
と考えられる．


2.ThreadモードとHandlerモードの使い分け

 2-1
  タスクコンテキストはThreadモード，非タスクコンテキストはHandlerモー
  ドで動作させる．

 2-2
  タスクコンテキストと非タスクコンテキスト共にHandlerモードで動作させ
  る．

プロセッサの設計方針を考慮すると2-1が有力．2-1での問題点としては，割込
みハンドラからタスクへのリターン時にモードの変更が以下の様に多発するこ
とが挙げられる．

1.割込みハンドラ               : Handlerモード
2.タスク例外ハンドラの呼び出し : Threadモード
3.タスクへのリターン処理       : Handlerモード
4.タスクの再開                 : Threadモード

3でHandlerモードに移行する必要があるのは，例外フレームを用いて復帰する
には，Handlerモードで例外リターン処理を行う必要があるためである．ARMで
は，複数レジスタのロードとCPSRの復帰を同時に行えるが，M3は行えないため，
この方法で割込み先のタスクにリターンする必要がある．

2-2の場合の割込みハンドラからタスクへのリターン時にモードの変更を以下
に示す．また，2-2では割込み優先度の最低値をタスクの実行時の優先度とし
てリザーブする必要がある．

1.割込みハンドラ               : Handlerモード
2.NVIC優先度マスク'0'を0へ     : Threadモード
3.最低優先度のHandlerモードへ  : Handlerモード
4.タスク例外ハンドラの呼び出し : Handlerモード
5.タスクへのリターンの前処理   : Threadモード
3.タスクへのリターン           : Handlerモード
4.タスクの再開                 : Handlerモード

割込みハンドラからタスクのリターンに関しては，2-2であっても，2を実行す
る場合に，NVIC優先度マスクを'0'にするため，例外リターン処理を行う必要
がある．また，NVIC自体が，割込みのネスト回数を管理しているため，3から4
への遷移のために，いったん例外/割込みを受付けた状態にする必要があるた
め，結果的に2-1以上の遷移が必要となる．

2-2の場合は，MSPしか使えないため，割込みの入り口でネスト回数を判断して，
スタックを入れ替える必要がある．

HRP等でメモリ保護を用いる場合は2-1となる．

以上の理由により，2-1を採用する．ただし2-1は，カーネル起動時とIDLEルー
プの扱いを検討する必要がある．これらについては別途議論する．


3.ディスパッチャの実行モード

 3-1
  Threadモードで実行する

 3-2
  Handlerモードで実行する

ディスパッチャをThreadモードで実行すると，割込みによりプリエンプトされ
たタスクに戻る場合は次のようなパスになる．

 1. ディスパッチャ呼び出し : Threadモード 
 2. ディスパッチャ実行     : Threadモード
 3. タスク例外実行         : Threadモード
 4．タスクへのリターン処理 : Handlerモード
 5. タスクの再開           : Threadモード

割込みハンドラから自らディスパッチしたタスクへリターンする場合は次のパ
スになる．

 1.割込みハンドラ               : Handlerモード
 2.ディスパッチャ実行           : Threadモード
 3.タスク例外ハンドラの呼び出し : Threadモード
 4.タスクへのリターン           : Handlerモード
 5.タスクの再開                 : Threadモード

一方，ディスパッチャをHandlerモードで実行すると，割込みによりプリエン
プトされたタスクに戻る場合は次のようなパスになる．

 1. ディスパッチャ呼び出し : Threadモード 
 2. ディスパッチャ実行     : Handlerモード
 3. タスク例外実行         : Threadモード
 4．タスクへのリターン     : Handlerモード
 5. タスクの再開           : Threadモード

割込みハンドラの出口から自らディスパッチしたタスクへリターンする場合は
次のパスになる．

 1.割込みハンドラ               : Handlerモード
 2.ディスパッチャ実行           : Handlerモード
 3.タスク例外ハンドラの呼び出し : Threadモード
 4.タスクへのリターン           : Handlerモード
 5.タスクの再開                 : Threadモード

タスク例外ハンドラがないOSの場合は，Handlerモードで実行した方がモード
の遷移の回数が減るが，タスク例外ハンドラがあると，Threadモードの方が遷
移回数が減るため，Threadモードとする．

メモリ保護を考慮すると，ディスパッチャはHandlerモードで動作させた方が
効率がよいと考えられる（SVCでハンドラを呼び出すとHandlerモードとなるた
め）．


4.スタックの使い分け

 4-1
  タスクコンテキストをPSP, 非タスクコンテキストをMSP
 4-2
  タスクコンテキスト，非タスクコンテキスト共にMSP

4-2の場合，割込みの入り口でネスト回数を判断して，スタックを入れ替える
必要がある．2でタスクコンテキストはThreadモード，非タスクコンテキスト
はHandlerモードで動作させるとしたため，4-1を採用すると，割込みの入り口
で自動的にスタックが切り替わる．ThreadモードでのPSPのアクセスも，
mrs/msr命令で行えるため，4-1を採用する．


5.コンテキストの判定

 5-1
  IPSRが'0'(Threadモード)ならタスクタスクコンテキスト，'1'(Handlerモー
  ド)なら非タスクコンテキストとする．

 5-2
  割込みのネスト回数を保持する変数を用意．1以上で非タスクコンテキスト．

 5-3
  アクティブなスタックにより判断（MSPなら非タスクコンテキスト，PSPなら
  タスクコンテキストとする）

5-1は，ソフトウェア側でコンテキスト管理のための処理を行う必要がないと
いうメリットがある．しかしながら，カーネルの起動時Threadモードであるた
め，Handlerモードへ移行する必要がある．ASPカーネルでは，IDLEループ実行
は非タスクコンテキストとして動作させる必要があるため，IDLEループは
Handlerモードで動作させる必要がある．IDLEループはディスパッチャから呼
び出される．3で定めたように，ディスパッチャをThreadモードで動作させる
ため，IDLEループを呼び出す際には，Handlerモードへ遷移する必要がある．
Handlerモードへの遷移は，SVC/PendSVCを用いると実現可能であるが，6の割
込みにプリエンプトされたタスクへのリターン時のHandlerモードへの移行で
もSVC/PendSVCの使用が必要となるため，SVCハンドラでは，どの目的で呼び出
されたか判定する必要が出てくるため，オーバヘッドが増大する．

5-2では，カーネル起動時やIDLEループ時に変数を'1'に設定すればよいことに
なる．この場合，カーネル起動時やIDLEループ時にThreadモードで実行しても
動作に問題がないよう，特に割込みの出入り口の設計を注意する必要がある．

カーネル起動時に関しては，全割込みを禁止しており，割込みが入らないので
特に問題はない．IDLEループ時は，ThreadモードでMSPとPSPの選択が可能であ
ることを利用して，非タスクコンテキストのスタックであるMSPに変更する．
例外/割込みの入り口では，多重割込みであるかをEXC_RETURNのモード判定の
ビットではなく，スタックの判定ビットで行えば問題ない．例外/割込みから
のリターンに関しては，多重割込みの判定は，入り口と同様にEXC_RETURNのス
タック判定ビットで行えばよい．例外リターン処理時にpcに代入する
EXC_RETURNの値を一律0xfffffffd (Threadモード with MSP)とするのではなく，
例外/割込み受付け時にLRに設定されるEXC_RETURNを用いることにより，IDLE
ループに割り込んだ場合でも問題なくリターンする．

カーネル起動時は，MSPがアクティブであり，割込みハンドラ実行時はHandler
モードであることからMSPがアクティブでり，IDLEループ時にMSPをアクティブ
に設定すると，非タスクコンテキストは全て，MSPをアクティブにして動作す
ることになる．また，割込み時は割込み前にアクティブなスタックの情報が，
EXC_RETURNに設定される．そのため，コンテキストの判定は，割込みネスト回
数を保持する変数がなくとも，アクティブなスタックを見ればよいことになる．
また，exc_sense_context()に関しては，例外フレーム中にEXC_RETURNを追加
し，その内容により判断すればよい．以上の理由により，5-3を採用する．


6.割込みにプリエンプトされたタスクへのリターン時のHandlerモードへの移
  行方法

 6-1
  SVCを用いる
 6-2
  PendSVCを用いる

PendSVCとSVCの違いは，PendSVCが要求がキューイングされ，SVCは要求がキュ
ーイングされないことである．割込みにプリエンプトされたタスクへのリター
ン時のHandlerモードへの移行は，キューイングされずに即座に処理される必
要があるため，どちらで実現しても問題ない．どちらをカーネルのリソースし
て使用するかの選択だけである．

どちらを使うとしても，優先度の設定が問題となる．ディスパッチャから割込
みにプリエンプトされたタスクへのリターンまでの処理は，少なくともCPUロ
ック状態で実行されなければならない．SVCやPendSVCはどちらも割込み優先度
を持つため，NVIC優先度マスクよりBASEPRI優先度マスクの方が高い場合，処
理されない．

CPUロック状態をBASEPRIの設定で実現した場合，その設定値をSVCやPendSVCに
設定した値より低くする必要がある．言い換えると，SVCやPendSVCの優先度を
CPUロック時の優先度マスクの値より高い値（他の割込みより高い優先度）と
する必要がある．

CPUロック状態をFAULTMASKやPRIMASKで実現した場合は，これらが設定される
と，SVCやPendSVCが受付けられないため，いったんBASEPRIにより割込みをマ
スクするように設定する必要がある．この場合も，SVCやPendSVCは他の割込み
より高い優先度を設定する必要がある．

以上により，Handlerモードへの移行のためには，CPUロック状態をBASEPRIで
実現し，SVCやPendSVCに設定する優先度をカーネル管理内の最高優先度より一
つ高い優先度に設定する必要がある．

ARMv7-MではSVCにより実現する．SVNの方がPendSVCより実行オーバヘッドが小
さいため，SVCを使用する

ARMv6-MではPendSVCにより実現する．ARMv6-MはCPUロック状態をPRIMASKで実
現しているPRIMASKをセットした状態でSVCを実行するとフォールトとなるため，
PendSVCを発行して，PRIMASKをクリアすることで実現する．PendSVCの割込み
優先度は最高としているため，この間で割込みが入ることはない．


7. 例外/割込み出入り口での多重割込みの判断

7-1
 EXC_RETURNのモード判定ビット
7-2
 EXC_RETURNのスタック判定ビット
7-3
 割込みネスト回数の管理変数

例外/割込み受付け時は，受付けた例外/割込み以下の割込みは禁止するが，全
割込み禁止状態にはならない．そのため，割込みネスト回数の管理変数をイン
クリメントする前に割込みが入る可能性があるため，7-3は使用することがで
きない．

5で議論した通り，IDLEループをThreadモードで実行するため，7-1ではなく，
7-2で判断する必要がある．


8. IDLEループ

8-1
 Threadモードで実行
8-2
 Handlerモードで実行

5で議論した通り，Threadモードで実行できた方がオーバヘッドが小さい．ま
た，Threadモードで実行しても，割り込みの出入り口で正しく非タスクコンテ
キストと判定できれば，Threadモードで問題ない．


9．カーネル管理外の割込みのサポート

9-1
 カーネル管理外の割込みをサポートしない
9-2
 カーネル管理外の割込みをサポートする

ARMv7-Mでは，CPUロックをBASEPRIで実現していること，ベクタテーブルをサ
ポートしており，割込みハンドラもC言語で記述可能であるため，サポートが
容易であるため，サポートする．

ARMv6-Mでは，CPUロックをPRIMASKで実現しているため，サーポートしない．


10. CPUロック

10-1
 BASEPRIを使用(ARMv7-M) 
 個別の割込み禁止許可でエミュレーション(ARMv6-M)
10-2 
 FAULTMASK/PRIMASKを使用

カーネルの管理外の割込みをサポートするなら，BASEPRIを使用する必要があ
る．

ARMv7-MではCPUロックにBASEPRIを使用する．

ARMv6-MではCPUロックにPRIMASKを使用する．個別の割込み禁止許可でエミュ
レーションする方法は，SysTicのみ別のレジスタで設定する必要があり，実行
オーバヘッドが大きいという問題がある．

11. 割込みロックとCPU例外の関係

11-1
 BASEPRIを使用(ARMv7-M) 
11-2 
 FAULTMASK/PRIMASKを使用 

FAULTMASK/PRIMASKを使用すると，NMI と Hardware Fault 以外のCPU例外も禁
止されてしまう．

BASEPRIを用いると，割込みロック中にもCPU例外を受付けたい場合は，
BASEPRIを用いて，最高優先度をCPU例外のためにリザーブする必要がある．

割込みロック時も，CPU例外を受付けるようにしたければBASEPRIを使用する必
要がある．

μIRON4.0仕様の3.5.3では，CPU例外の優先度は次のように定められている．

"CPU例外ハンドラの優先順位は，CPU例外が発生した処理の優先度と，ディス
パッチャの優先順位のいずれかよりも高い．"

CPU例外が発生した処理の優先度よりも高いとあるので，CPUロックや割込みロ
ック状態のタスクで発生した場合でも，優先して実行されるべきだとも考えら
れる．

一方，TOPPERS標準割込み処理モデルの仕様書では，CPU例外は，プロセッサ毎
に異なるため，CPU例外の処理モデルの標準化検討の対象外としている．その
ため，ARM-Mでの扱いを決めて，マニュアルに明記すればよいと考えられる．

ARMv7-Mでは割込みロックはBASEPRIを使用する．

ARMv6-Mでは割込みロックはPRIMASKを使用する．


12. 外部優先度と内部優先度の変換

外部優先度とはAPIで指定する割込み優先度(PRI型)のことであり，値が小さい
ほど優先度が高い．割込みハンドラには，-1から連続した負の値を設定可能で
ある．内部優先度は，BASEPRIやNVICの優先度レジスタに設定する値である．

実装される割込み優先度のビット幅を TBITW_IPRI とすると，設定可能な外部
優先度は次のようになる．

  TIPM_ENAALL（＝0）～ -(1 << TBITW_IPRI)


13. カーネル管理内の最高優先度(CPUロック状態での優先度マスク)

6.で述べたように，割込みの出口でSVCハンドラを呼び出す必要があるため，
SVCハンドラはCPUロック状態のBASEPRIに設定する優先度マスクより高い優先度
を設定する必要がある．

実装される割込み優先度のビット幅を TBITW_IPRI，優先度中のサブ優先度の
ビット幅をTBIT_IPRIとすると，CPUロック状態（カーネル管理内割込みに設定
可能な最高優先度）として指定可能な優先度マスクの設定範囲は以下の値の範
囲となる．

    -(2^(TBIW_IPRI) - 1) + (2^TBITW_SUBIPRI) ～ -1


14. 割込み優先度マスク

ARMv7-MではBASEPRIにより実現する．

ARMv6-Mでは個別の割込み禁止許可機能を用いてエミュレーションする．


15. FPUのサポート

15-1
 FPUを使用するタスク/ISRをユーザが指定する． 指定していないタスク/ISR
 ではFPUを使用すると例外となる．
15-2
 FPUを使用するタスク/ISRをユーザは指定しない．全てのタスク/ISRでFPUを
 使用可能である．
 
15-1は一般にコンテキストの保存復帰のオーバヘッドを低減する目的で採用さ
れる．15-1を採用すると，タスクとISRの属性の拡張が必要となる．

ARMv7-Mでは，FPUを使用した場合のみ例外・割込みの入り口でFPUコンテキス
トを保存する機能があるため，15-2を選択しても，FPUを使わない限りはペナ
ルティはないと考え，15-2を採用する．

FPUに関するサポートのバリエーションは次の組み合わせが可能である．

                       FPCCR                          コンテキスト  
                    LSPEN  ASPEN コンパイルオプション  保存復帰     FPU
NO_FPU                -      -        指定なし           なし       無効   
FPU_NO_PRESERV        0      0    -mfpu=fpv4-sp-d16      なし       有効
FPU_NO_LAZYSTACKING   0      1    -mfpu=fpv4-sp-d16      あり       有効
FPU_LAZYSTACKING      1      1    -mfpu=fpv4-sp-d16      あり       有効

NO_FPU
FPUを使用しない．Cortex-M0/Cortex-M0+/Cortex-M3/Cortex-M4 の場合に指定．
ディスパッチャ等ではFPUコンテキストの保存復帰を行わない．

FPU_NO_PRESERV
FPUを使用する．Cortex-M4F の場合に指定可能．
ディスパッチャ等ではFPUコンテキストの保存復帰を行わない．
FPUを使用可能なタスクは1個もしくは，システム中の最高優先度のISR群で使
用可能．

FPU_NO_LAZYSTACKING
FPUを使用する．Cortex-M4F の場合に指定可能．
ディスパッチャ等ではFPUコンテキストの保存復帰を行う．Lazy stacking は
使用しない．
全てのタスク/ISRでFPUを使用可能．

FPU_LAZYSTACKING
FPUを使用する．Cortex-M4F の場合に指定可能．
ディスパッチャ等ではFPUコンテキストの保存復帰を行う．Lazy stacking を
使用する．
全てのタスク/ISRでFPUを使用可能．


FPU_NO_LAZYSTACKING時のレジスタの保存・復帰コード

FPU_NO_LAZYSTACKING の場合は一般レジスタと同じタイミングで，ディスパッ
チ元のタスクがFPUを使用していたかを判断してレジスタを保存・復帰すれば
よい．該当する箇所は次の通りである．

ディスパッチ(dispatch)
・CONTROL.FPCAをチェックして'1'ならs16-s31を保存する
・復帰用にCONTROL.FPCAをタスクスタックに保存

ディスパッチからの復帰(dispatch)
・CONTROL.FPCAをタスクスタックから復帰する
・復帰したCONTROL.FPCAをチェックして'1'ならs16-s31をタスクスタックから
  復帰する．

遅延ディスパッチ(ret_int_4)
・タスクが割り込まれた際のEXC_RETURNをタスクスタックに保存しておく
・EXC_RETURNをタスクスタックから復帰
・復帰したEXC_RETURN[4] == 0(FPU使用)ならs16-s31をタスクスタックに保存
  する．
・復帰用にEXC_RETURNの値をタスクスタックに保存  

遅延ディスパッチからの復帰(ret_int_r)
・タスクが割り込まれた際のEXC_RETURNの値をタスクスタックから復帰
・復帰したEXC_RETURN[4] == 0(FPU使用)ならs16-s31をタスクスタックから復帰
・先のSVCハンドラ呼び出し時にFPUレジスタを積まないようにCONTROL.FPCAをクリア．

FPU_LAZYSTACKING時のレジスタの保存・復帰コード

FPU_NO_LAZYSTACKING時のコードをそのまま使用するとFPU_LAZYSTACKINGの場
合は，割込み・例外発生後に次のタイミングで例外フレームにFPUのコンテキ
ストがハードウェアによって自動的に保存される．

例外・割込みハンドラ実行中
FPUを使用したタスク/ISR実行中に例外・割込みが発生し，例外・割込みハン
ドラでFPU命令を実行した場合．FPCCR.LSPACT==1 となっているため．

遅延ディスパッチ時(ret_int_4)
例外・割込みハンドラでFPUを使用しなかった場合は，ret_int_4実行時にはコ
ンテキストは保存されていない．さらに各レジスタの値は次のようになってい
る．
・FPCCR.LSPACT == '1'
・FPCAR = 例外フレームのFPUレジスタの保存アドレス(S0のアドレス)
ret_int_4では，s16-s31 をタスクスタックに保存する．ここでFPUを使用する
ため，s0-s15,FPSRは例外フレームに保存される．

以下の箇所はFPU_LAZYSTACKINGの場合にのみ必要である．

割込み出口でのタスク例外呼び出し時
FPUを使用したタスク実行中に例外/割込みが発生し，例外/割込みの出口から
タスク例外処理を呼び出した場合には，FPCCR.LSPACT == '1' とFPUコンテキ
ストが保存されていない状態でタスク例外が呼び出される可能性がある．タス
ク例外でext_tsk()を呼び出した場合や他のタスクにディスパッチされ，
ter_tsk()で終了させられた場合には，FPCCR.LSPACT を '0'にクリアする必要
がある．ext_tsk()のケースはターゲット依存部exit_and_dispatch()が呼び出
されるため，ここでクリアすれば良いが，ter_tsk()ではターゲット依存部を
呼び出さないため，クリアすることが出来ない．そのため，割込み出口でのタ
スク例外呼び出すタイミングで，FPUコンテキストをスタックに格納するため，
副作用のないFPU命令を発行する．

CONTROL.FPCAのセット・クリアのタイミング

クリアする箇所が複数箇所になると把握が困難であるため，ディスパッチャの先頭で
は一律CONTROL.FPCAを'0'にクリアする．

dispatchを呼び出したタスクへのリターンする際には，戻り先のタスクがFPU
を使用しいた場合は，s16～s31の復帰を行うため，この処理により
CONTROL.FPCAが'1'にセットされる．

また，EXC_RETURNによるリータン時はEXC_RETURNの値によってリーターン時に
ハードウェア的に自動的にCONTROL.FPCAが元の状態に復帰されるのでソフトウ
ェアによる処理は必要ない．

タスク例外の扱い

タスク例外でFPUを使用して，通常の処理でFPUを使用しない場合は，タスク例
外の呼び出しの前後で CONTROL.FPCA を保存復帰する方法もあるが，レアケー
スであると考えられるためサポートしない．

ABI

GCCでは3種類選択可能．

hard    : 浮動小数点命令を使用してABIはFPUレジスタを使用．
soft    : 浮動小数点命令を使用しない．
softfp  : 浮動小数点命令を使用するがABIはsoftと同じ．

既存のライブラリとリンクする場合はsoftfpが有効だが，ユーザーカスタマイ
ズとしてディフォルトは，hardとする．

マクロ

FPUコンテキスト復帰保存を有効化するマクロ．

TOPPERS_FPU_CONTEXT

FPUの使用を有効化するマクロ．

TOPPERS_FPU_ENABLE

FPUのアーキテクチャを指定するマクロ．ARMCCと合わせて次のマクロを使用する．
__TARGET_FPU_FPV4_SP

FPU_NO_PRESERV/FPU_NO_LAZYSTACKING/FPU_LAZYSTACKINGの場合は次のマクロを定義する．

TOPPERS_FPU_NO_PRESERV

TOPPERS_FPU_NO_LAZYSTACKING

TOPPERS_FPU_LAZYSTACKING

17. メモリ同期

アーキテクチャ的には，NVICにより割込み禁止・許可・優先度変更した後に次
の命令の前に影響を反映するには，DSB,ISBを実行する必要がある．割込み許
可操作を即座に反映する必要はないが，割込み禁止・優先度変更は反映する必
要がある．一方，Cortex-M0/M0+/M3/M4ではDSBは実行する必要はない．将来的
な実装ではDSBが必要なことも考えられるため，該当処理の後には，SCS_SYNC
というマクロを呼び出すことにする．

16. 未解決課題
・割込みロックとCPU例外の関係
  BASEPRIを使ったとしても，あるCPU例外処理中に他の例外が発生すると，そ
  の例外は受け付けられないため，ITRON仕様は満たせない．
  ->あきらめてマニュアル記載に逃げるか.
  メモリプロテクションの例外もマスク可能であるため要件等．

以上．
