PIC32memo
CQ
『はじめて読む MIPS(リローデッド)』 by 中森章 - CQ出版社
- www.cqpub.co.jp/interface/TechI/Vol39/app/mips_asm.pdf
アーキテクチャー
- MIPS M4KとMIPS16eをサポート。
- MX1xx/2xxには、microMIPSのサポートは無い。
- MX1xx/2xxには、(割り込み応答高速化の)シャドウレジスタのサポートはない。(GP*1 )のコピーのみ存在)
- 32bitレジスタはr0〜r31の32本
- r0は常に零。書き込んでも値は零のまま。
- r31(ra)はリターンアドレス(サブルーチン呼び出しの戻り番地を記憶)
- そのほかには乗算結果を置くHI,LOレジスタとPCがある。
- mips16eモードではレジスタは8本しか使えない(s0,s1,v0,v1,a0,a1,a2,a3)。
- mips16eモードではレジスタt8(分岐条件),sp(スタック),ra(戻り番地)が暗黙的に使用される。
MICROCHIP PIC32ファミリ リファレンスマニュアル
MIPS カルトFAQ
r31はスタックポインタと違うの?
- mips16e命令では、r29(sp)をリターンスタックに使用します。
- MIPS32命令では、何と、スタックポインタという機能を持った特殊レジスタはありません。
- ですが、コンパイラはr29(sp)をスタックポインタのように使用して、レジスタ退避などを行います。*2
- 質問のr31(ra)はリターンアドレス(サブルーチン呼び出しの戻り番地を記憶)というレジスタで、
jal <番地> (サブルーチンコール命令のようなもの)
- を実行したときにjalの次の番地のPC値がraにコピーされます。
- なので、サブルーチンがネストする場合は必ず、サブルーチン側でraを保存し、復帰しなければいけません。(スタックにpush,popします)
- Leaf関数(内部でサブルーチンを呼んでない関数)に限り、raの保存、復帰が不要になるため、高速になります。
- 速度ネックになるのは、一番外側の、たくさん呼ばれる関数ですから、それがLeafになる確率は高いです。
カーネルテンポラリ:k0(r26),k1(r27)レジスタの役割は?
- 割り込みおよび例外処理時に(のみ)使用されるレジスタです。
- 割り込み処理時以外では使ってはいけません。(割り込むたびに破壊され、いつ壊れるかわからないからです)
- コンパイラは通常$k0,$k1を使用しないことが保証されています。
- 割り込み発生時、$k0,$k1レジスタは破壊されますが、多重破壊を防ぐため、$k0,$k1操作はdi状態で実行されます。
GPって、何?
- 28番レジスタに付けられた名前です。
r28=gp (グローバルポインタ)
- 共通データへの高速アクセスに使用、とありますが、何のことだか分かりませんが、
- その名の通り、グローバル変数群(64kB以内の一箇所に置く)を常に指しておくポインタです。
- これを設定したり使用するためには、mips-gccのコンパイルオプション-G もしくは --gpsizeを指定してコンパイルする必要があります。
- グローバル変数が一箇所に置かれ、そのど真ん中あたり(というか先頭+32kB位置)にgpが設定されます。
- グローバル変数はすべて
offset(gp)
- でアクセスされるので、MIPS固有の2命令による絶対番地ロードが1命令で済むようになってめでたしめでたし(本当?)
- グローバル変数が全部で64kBを越えるような場合はリンカエラーが出ます。
- その場合は、グローバル変数として扱う変数のサイズを-Gオプションで小さく(たとえば4byte以下)します。
- それでも64kBを越えるような(グローバル変数の多い)プログラムは書くべきではありませんが、越える場合は-Gオプションの使用を諦めてください。
- 実際のところ、コードサイズは少しだけ減りますが、まあ誤差の範囲です。
- 割り込んだときに、gp参照コードはバグるので注意が必要です。(割り込み時にCPUの機能としてgpが別物にすりかわったりしますし、マルチタスク環境では各elf毎にgpの値は異なります)割り込みハンドラーは-Gオプション無しでビルドするほうがより安全です。
*1 このページの下に記述
*2 push,pop命令のようなものはありません。通常のポインタ操作で行います。オートインクリメント、デクリメントもありません。