Broadcomのmips SOCで動かしているmrubyはメモリ8M固定でStack Pointer(SP)を8Mの位置に設定して動作していました。これは8Mしかメモリがない機種があったためにそうしました。16Mのメモリをつんでいる機種では8Mが使えない状態でした。
しかしせっかくなので、メモリ量を考慮してSPを設定できるようにしたいと考えました。
物理メモリ量はブートローダーのCFEのAPIを使うと取得できます。しかしCFEのAPIはcなので、SPを最初に設定しているスタートアップのアセンブラコードでは利用できません。
スタートアップのアセンブラコードでは一旦8MでSPを設定して、呼び出されたcコードで、APIを利用してメモリ量を取得して、8Mより大きい場合はSPを移動するようにしてみました。この処理はcでは書けないのでアセンブラで書きました。
mipsのアセンブラはいろいろな大学で課題になっていてgoogleで検索するといろいろ出てきますが、最初にあった岡山大学の以下のページを参考にしました。
cコードに入っているのでStackはすで使用さているので、使用されているStackをコピーしてSPを移動する処理をします。
relocsp:
move $8, $sp
li $9, 0x80800000
move $10, $sp
add $10, $10, $4
2: lw $11, 0($8)
sw $11, 0($10)
add $8, 4
add $10, 4
blt $8,$9,2b
add $sp, $sp, $4
move $2, $sp
j $ra
cコードからは以下のように呼び出します。返り値で変更されたSPが渡されます。
cfe_getfwinfo(&fwinfo);
tomem = fwinfo.fwi_totalmem;
sp = relocsp(tomem - 0x800000);
アセンブラはもう少し簡潔に書けそうな気もするのですが、私はこれしか書けません。
アセンブラ -> c -> mrubyのように処理が流れてmrubyのコードが終了すると c -> アセンブラになり、現在のアセンブラコードは無限ループに入ります。この処理が正常に動いているのでStackは正常と考えられます。