=====================================================================
                     ARMプロセッサ依存部
                                  Last Modified: 2012 May 01 17:02:23
=====================================================================

○概要

ARM にはアーキテクチャーバージョンが幾つか存在する．本カーネルでは，
ARMv4 以上のアーキテクチャーをサポートすることとする．基本的には， 
ARMv4 を前提として記述している．しかしながら，上位のアーキテクチャでは
記述方法を変更することによって性能向上を図れる箇所が存在する．そのよう
な箇所については，条件コンパイルによって対応することにする．


○開発環境

コンパイラは，CodeSourceryでリリースされているGNU C/C++のバイナリを使
用することとする．


○CPU例外の取り扱い

●例外とPCの関連

例外                              モード      アドレス   戻り先PC
リセット             Reset          svc      0x00000000     
未定義命令           Undefined      und      0x00000004    pc(コプロはpc-4)
SWI                  Software Int   swi      0x00000008    pc(次の命令)
プリフェッチアボート Prefetch Abort abt      0x0000000C    pc-4(再実行)
データアボード       Data Abort     abt      0x00000010    pc-4(再実行pc-8)
IRQ                  IRQ            irq      0x00000018    pc-4(次の命令)
FIQ                  FIQ            fiq      0x0000001C    pc-4(次の命令)

ARMは，例外毎に戻り番地が異なり，例外の要因になった命令を再実行するか
どうかによっても戻り番地が異なる．そのため，カーネルの例外ハンドラでは，
戻り先のPCは操作せず．戻り先のPCを設定させる機能を提供する．ユーザは
CPU例外ハンドラでこれらの機能を用いて戻り先のアドレスを設定する．

      uint32_t x_get_exc_raddr(void *p_excinf);

      void x_set_exc_raddr(void *p_excinf, uint32_t pc);

●CPU例外ハンドラ番号

例外毎に次のようにCPU例外ハンドラ番号を割り付ける．なお，0番,5番にはユ
ーザーはCPU例外ハンドラを登録できない．

 リセット             0
 未定義命令           1
 SWI                  2
 プリフェッチアボート 3
 データアボード       4
 IRQ                  5
 FIQ                  6

●ベクターテーブル

ARMのベクタ（vector_table）は，ARMのベクタアドレス0x00000000から配置す
る．vector_ref_tblは，例外発生時のジャンプ先のテーブルで，vector_tble
の命令から参照される．

    .section .vector,"a"
    .global vector_table
vector_table:
    ldr pc, reset_vector       /* リセット             */
    ldr pc, undef_vector       /* 未定義命令           */
    ldr pc, swi_vector         /* ソフトウェア割込み   */
    ldr pc, prefech_vector     /* プリフェッチアボード */
    ldr pc, data_abort_vector  /* データアボード       */
    ldr pc, reset_vector
    ldr pc, irq_vector         /* IRQ                  */
    ldr pc, fiq_vector         /* FIQ                  */

    .align  2
    .global vector_ref_tbl
vector_ref_tbl:
reset_vector:
    .long   start
undef_vector:
    .long   undef_handler
swi_vector:
    .long   swi_handler
prefech_vector:
    .long   prefetch_handler
data_abort_vector:
    .long   data_abort_handler
irq_vector:
    .long   IRQ_Handler
fiq_vector:
    .long   fiq_handler


また，vector_ref_tblをRAM上に配置した場合には，カーネル管理外の例外と
して，vector_ref_tblに直接ユーザーのハンドラを登録する関数を用意する．
なお，vector_ref_tblをフラッシュメモリに配置した場合は，このシステムコ
ールは正常に動作しないので，注意が必要である．

      void x_install_exc(EXCNO excno, FP exchdr)

ディフォルトのvector_ref_tblの登録内容は上に示した通りである．startと
IRQ_Handler以外は，core_support.Sに定義されており，それぞれ，スーパーバ
イザーモードに移行して，スタック上にコンテキストを積んだ後，元のモード
に戻り，r0に例外発生時のpc, r1に例外発生時のcsr, r2に例外番号を入れて，
ターゲット依存部で定義する target_exc_handler へジャンプする．


●ベクタの保護

前述の通りARMのベクタ（vector_table）は，0x00000000 に配置する必要があ
る．通常はこのアドレスにはROMやフラッシュメモリ等の不揮発性のメモリが
割り当てられるが，ターゲットによっては，RAMをリマップすることが可能で
ある．RAMを0x00000000 を配置して，ベクタ（vector_table）を配置すると，
ユーザープログラムでベクタを書き換えることが可能となるので注意が必要で
ある．特にユーザープログラムによる，NULLポインタによるアクセスにより書
き換えられる可能性が高い．安全性を高めるためには，ターゲット依存で次の
対策を行うことを推奨する．

  ・リマップを行わず，不揮発性メモリにベクタを置く．
  ・MMUによりベクタの領域を書き込み禁止とする．
  ・High Vector機能を使用し，ベクタを0x00000000以外に配置する．


●例外フレーム（CPU例外ハンドラへの引数）

ASPカーネルの仕様では，CPU例外ハンドラの引数には，CPU例外に関する情報
を記憶している領域（例外フレーム）の先頭番地が渡される．そのため，CPU
例外発生時のコンテキストを保存したスタックへのポインタを渡す．

例外フレームは，ARMアーキテクチャ毎に異なり，ARMv4/ARMv5では次のように
なる．このうち，R0,R1,R2,R3,ipに関しては，ARMプロセッサ依存部で設定さ
れる．その他の値は，ターゲット毎の target_exc_handler で作成する．例外
前の割込み優先度マスクは，PRI(int_t)型の外部表現である．

           例外フレーム(ARMv4-5)            offset
      ------------------------------
     |  例外前のネストカウント      |  0  <-- p_excinf
      ------------------------------
     |  例外前の割込み優先度マスク  |  1
      ------------------------------
     |        例外前のCPSR          |  2
      ------------------------------
     |            R0                |  3
      ------------------------------
     |            R1                |  4
      ------------------------------
     |            R2                |  5
      ------------------------------
     |            R3                |  6
      ------------------------------
     |            IP                |  7
      ------------------------------
     |          LR_svc              |  8
      ------------------------------
     |     例外前のPC(戻り先)       |  9
      ------------------------------

ARMv6/ARMv7では次のようになる．このうち，R0,R1,R2,R3,IP,LR_svc,例外前
のPC,例外前のCPSRに関しては，ARMプロセッサ依存部で設定される．その他の
値は，ターゲット毎の target_exc_handler で作成する．例外前の割込み優先
度マスクは，PRI(int_t)型の外部表現である．

           例外フレーム(ARMv6-7)            offset
      ------------------------------
     |  例外前のネストカウント      |  0  <-- p_excinf
      ------------------------------
     |  例外前の割込み優先度マスク  |  1
      ------------------------------
     |            R0                |  2
      ------------------------------
     |            R1                |  3
      ------------------------------
     |            R2                |  4
      ------------------------------
     |            R3                |  5
      ------------------------------
     |            IP                |  6
      ------------------------------
     |          LR_svc              |  7
      ------------------------------
     |     例外前のPC(戻り先)       |  8
      ------------------------------
     |        例外前のCPSR          |  9
      ------------------------------

○割り込みの取り扱い

●カーネル管理内/外の割込み

IRQをカーネル管理内，FIQをカーネル管理外の割込みとする．

●CPUロックフラグ

CPUロックフラグとして，ステータスレジスタのIRQビットを用いる．すなわち
，CPUロック状態では，IRQビットをセットし，カーネル管理内の割込みを禁止
し，CPUロック解除状態では，IRQビットをクリアする．

●割込みロックフラグ

割込みロックフラグとしては，CPSRのFIQビットとIRQビットを用いる．割り込
みロック状態では，IRQビットとFIQビットをセットする．


=====================================================================
                  カーネル開発者向けの情報
=====================================================================
○アーキテクチャ指定

アーキテクチャを次のマクロで指定する．

  __TARGET_ARCH_ARM

それぞれのアーキテクチャと設定する値は次の通りである．

  ARMv4 : 4
  ARMv5 : 5
  ARMv6 : 6
  ARMv7 : 7
  
○コンテキストの判定

カーネルは，割り込み/例外の入り口で，カーネル内のカウント用の変数（
excpt_nest_count）をカウントアップし，出口でカウントダウンする．そのた
め，excpt_nest_count が0の場合はタスクコンテキスト，1以上の場合は非タ
スクコンテキストと判断する．


○例外エントリ処理

各例外のエントリ処理は要因毎にカーネルで個別に持つ．JSPではルーチンを
共有していたが，ルーチンを共有化すると，例外発生後，一時的にレジスタを
退避させるために一時領域を用いる必要があるため，個別に持つように変更し
た．

各例外のエントリ処理では以下の処理を行う．

 ・タスク動作時のモードに移行（スタックを切り替える）
 ・r0-r3,ip,lr,pcを保存（PCはダミー）
 ・元のモードに戻る
 ・r0にlr，r1にspsrを，r2にCPU例外番号を入れる
 ・target_exc_handlerへジャンプ

target_exc_handler はターゲット毎に用意する．ターゲット毎に用意するの
は，前述の例外フレームに例外前の割込み優先度マスクが含まれており，この
割込み優先度マスクの扱いがターゲット毎に異なるためである．

target_exc_handler では，前述の例外フレームのフォーマットに従って例外
フレームを作成して，その先頭番地を引数にして，対応するCPU例外ハンドラ
を呼び出す．

FIQのエントリ処理（fiq_handler）については，ターゲット依存部側で用意す
る場合には，それぞれ，以下のマクロを定義すれば，ARM依存部側のエントリ
処理が無効となる．

     TARGET_FIQ_HANDLER


○アイドル処理

実行するべきタスクがない場合は，ディスパッチャーで割込みを許可して，割
込みを待つ（dispatcher_2）．ARM依存部のコードでは，次のようになってい
る．

       割込みを許可
       nop
       割り込み禁止

ターゲット依存で，上記の処理の代わりに，省電力モード等に移行する処理を
記述したい場合には，ターゲット依存部で，TOPPERS_CUSTOM_IDLEを定義し，
代わりに実行した処理を toppers_asm_custom_idle というアセンブラマクロ
として記述する．

なお，toppers_asm_custom_idle の記述にあたっては，次のレジスタは
oppers_asm_custom_idleの前後で使用するため，oppers_asm_custom_idle 内
で使用する場合は，前後で保存復帰すること．これらのレジスタは Calee 
saved レジスタであるため， oppers_asm_custom_idle として関数呼び出しを
した場合は，呼び出した関数で自動的に保存復帰されるため，アセンブラレベ
ルでの保存復帰は必要ない．

レジスタ : 内容
r4      : '0'
r5      : '1'
r6      : reqflgのアドレス
r7      : excpt_nest_countのアドレス
sp      : 非タスクコンテキスト用のスタックの先頭アドレス．

アセンブラマクロはC言語記述中に展開するとエラーとなる．core_support.S で
は，TOPPERS_ASM_MACRO というマクロを定義しているため，ターゲット依存部
で toppers_asm_custom_idle アセンブラマクロを定義する際には，
TOPPERS_ASM_MACRO を条件コンパイルの条件として用いること．


○CPSRに常にセットする値

CPSRの変更時，常にセットするパターンを CPSR_ALWAYS_SET として，ターゲ
ット依存部で定義可能である．


○Makefileでの定義事項


○Thumb Mode 用のコンパイル

カーネルを Thumb Mode 用にコンパイルする場合は，マクロ 
__thumb__ を定義すること．


○ARMCC共有コードの記述方法

ARMCCと共有するコードは，次のルールに従ってコードを記述する必要がある．

1.メモリバリア命令(Asm("":::"memory"))のマクロ化

ターゲット依存部 ポーティングガイドの(1-6-2)(c)には，次のように記述さ
れている．

-----
(c) クリティカルセクションの出入処理の本質的な部分が，マクロやインライ
	ン関数呼出しで実現している場合には，クリティカルセクションに入る処
	理の最後と出る処理の先頭に，Asm("":::"memory")という記述を入れる．
-----

メモリバリア命令(Asm("":::"memory"))は，ARMCCと互換性がないため，この
記述をする箇所は，次のマクロで記述すると，コンパイル時に適切なメモリバ
リア命令に置き換えられる．

  ARM_MEMORY_CHANGED


○GICドライバ

ARM依存部では，ARM Generic Interrupt Controller Ver.1用のドライバを用
意している(gic.h/gic.c)．このドライバを使用するためには，以下のパラメ
ータを定義する必要がある．

 GICC_BASE  : CPU Interface のベースアドレス
 GICD_BASE   : Distributor のベースアドレス
 GIC_PRI_LEVEL   : 優先度レベル
 GIC_SUPPORT_SECURE : セキュアレジスタをサポートする場合に定義

また，以下のファイルをコンパイル対象とすること．

 gic.c
 gic_support.S


2.インクルード方法

ターゲット依存部 ポーティングガイドの1.5には，次のように記述されている．

-----
その他のヘッダファイルは，「#include "..."」によりインクルードする．ヘッ
ダファイルが，カレントディレクトリやインクルードするファイルと同じディ
レクトリ以外のディレクトリに置かれている場合には，次のようにパス指定を
行う．
-----

GCC依存部とARMCC依存部でヘッダファイルを共有できない場合には，それぞれ
で同じ名前のファイルを持つ．そして，コンパイルオプションでインクルード
すべきファイルを先に指定している．そのため，ARMCCと共有するファイルで
これらのファイルをインクルードする場合には，「#include "..."」ではなく，
「#include <...>」で記述し，相対パスではなくファイル名のみを記載するこ
と．

3.アセンブラディレクティブ

GCCとARMCCのアセンブラディレクティブは互換性がない．そのため，ARMCCと
共有するファイルは次に示すマクロディレクティブで記述すること．

マクロディレクティブ     GCCディレクティブ
 ASECTION(name)          .section name,"a"
 ATEXT                   .text
 AGLOBAL(name)           .global name
 AALIGN(x)               .align x
 ALONG                   .long
 ALABEL(label)           label:
 AOR                       |

=====================================================================
                             変更履歴
=====================================================================
2012/05/01
・MPCore依存部のコードのうち，ARMv6/ARMv7依存の部分をARM依存部に移動．
・GIC依存部をMPCore依存部からARM依存部へ移動．
・GICのレジスタ名をGIC v2 準拠に変更(v1は名前が分かりにくいため採用し
  ない)．

2012/04/29
・インデントをスペースからタブに変更．
・その他HRP2とコードを極力合わせるように変更．

2012/04/16
・core_kernel.h/core_config.h
 ・ARMv4/ARMv5とARMv6/ARMv7の例外フレームの違いに以下の関数が追従してい
   なかったため修正．
  ・exc_sense_context()/exc_get_ipm()/exc_get_sr()
  ・x_get_exc_raddr()/x_set_exc_raddr()

2012/02/2
・core_config.h/core_config.c
  ・共通部で initialize_exception() は通常の関数としてプロトタイプ宣言
    されているため，インライン関数ではなく，通常の関数として宣言するよ
    う変更．
・core_support.S
  ・toppers_asm_custom_idleの前後で使用するレジスタを変更．この変更に
    より，toppers_asm_custom_idle で関数呼び出しをする場合は，アセンブ
    ラレベルでのレジスタの保存が必要なくなった．
      
2012/01/13
・割込み・例外の出入口処理をFMP 1.2 と互換に変更．

2011/11/22
・ARMCC対応に伴う変更
  ・core_asm.inc(追加)
    ・GCCのアセンブラのディレクティブの定義を記述したファイルを追加．
  ・core_config.h(変更)
    ・core_insn.h のインクルード方法を""から<>に変更して，コンパイラの
      引数で指定された順でインクルードファイルをサーチするよう変更．
   ・メモリバリア命令(Asm("":::"memory"))をマクロ化してcore_insn.h に
     定義を使用するよう変更．     
  ・core_insn.h(変更)
   ・メモリバリア命令(Asm("":::"memory"))のマクロ定義を追加
  ・core_support.S(変更)
   ・ARMCCとファイルを共有するため，ディレクティブをマクロに書き換え．      
  ・start.S(変更)
   ・ARMCCとファイルを共有するため，ディレクティブをマクロに書き換え．  
・CPSRの操作にcxsfを付加
  ・core_sil.h内のインラインアセンブラ内を変更．
  
2011/05/09
・ASP 1.7.0 への追従．
  ・オフセットファイルの生成方法をコンフィギュレータを用いる方法に変更．
  
2011/03/10
・ASP 1.7.0 への追従．

2010/10/04
・Thumb Mode 用のsrの設定・参照関数の追加．

2010/10/01
・アセンブラファイル中の分岐命令のAAPCS推奨への変更忘れを修正．

2010/08/01
・ASP 1.6.0 へ追従．

2010/07/26
・VECTOR_KERNELの廃止．

2010/07/26
・アセンブラファイル中の分岐命令を AAPCS推奨に変更．

2010/07/25
・ASP 1.5.0 へ追従．

2009/07/14
・例外フレーム入れる例外前の割込み優先度マスクの値をターゲット依存の
  値から外部表現に変更．
  
2008/08/27
・core_support.S
  ・call_exit_kernel で割込みを許可していた問題を修正
・共通部 Release 1.3.2への追従．
  ・特に変更内容なし

2008/05/13
・共通部 Release 1.3.1への追従．

2008/04/15
・start.S 
  ・dataセクションの初期化を省略する TOPPERS_OMIT_DATA_INIT を追加
2008/04/12
・非依存部 1.3.0 追従

2008/03/20
・非依存部 1.2 追従

2007/12/25
・core_support.S
  ・OMIT_DEFAULT_IDLE を TOPPERS_CUSTOM_IDLE に変更
  ・idle処理のマクロ名を toppers_asm_custom_idle に変更

・start.S
  ・bssの初期化を省略する TOPPERS_OMIT_BSS_INIT を追加

以上．
