MIPSシミュレータSPIM

アセンブリ言語の演習にはMIPSのシミュレータであるSPIMを使用します。通常アセンブリ言語で書いたコードの実行にはアセンブラによる機械語への変換が必要ですが、SPIMは対話的な環境ですので、アセンブラは用いません。

SPIMを使用するには、ターミナル上で spim コマンドを実行します。下記の例ではspimを起動し、アセンブリコードtotal-10.sを読み込んで(load)、実行(run)しています。「(spim) 」はspimのプロンプトです。runの直後の55はプログラムが出力した結果で、改行されずに次のプロンプトが続いています。

【実行例】 $ spim Loaded: /usr/lib/spim/exceptions.s (spim) load "total-10.s" (spim) run 55(spim) exit $  

SPIMでよく使うコマンド

コマンド 機能
load "ファイル名" プログラムの読み込み
run プログラムの実行
exit, quit spimの終了
改行 直前のコマンドの繰り返し
reinitialize メモリーとレジスターの初期化(プログラムを再読み込みする際に必要)
? コマンド一覧の表示

SPIMの代表的なシステムコール

システムコールとはOSが提供する機能を呼び出すメカニズムで、用意されるシステムコールは OS 毎に異なります。

SPIMは汎用的なシミュレータで、特定のOSを想定しているわけではないため、SPIM独自のシステムコールが用意されています。以下にSPIMが提供しているシステムコールの内、代表的なものを載せます。

システムコールを利用する時は、$v0に利用したいシステムコールコードをセットし、必要であれば$a0などの引数も設定してsyscallを実行します。

SPIMではシステムコールを利用しても レジスタの値が破壊されないため、$s0~$s7以外のレジスタの値がシステムコール呼び出し後も継続して利用できてしまいます。また、SPIM起動直後はレジスタやメモリーの内容も全てゼロになっているため、初期化しなくても計算に利用できてしまいます。しかし、これは一般的なアセンブリ言語によるプログラムの振る舞いではないことに注意して下さい。

サービス システムコール
コード
($v0 で指定する)
引数 結果
print_int 1 $a0 = integer
print_float 2 $f12 = float
print_double 3 $f12 = double
print_string 4 $a0 = string
read_int 5 $v0 ← integer
read_float 6 $f0 ← float
read_double 7 $f0 ← double
read_string 8 $a0 = buffer
$a1 = length
引数 $a0 で指定したアドレスに格納される
# 整数 123 を表示する li $v0, 1 li $a0, 123 syscall

擬似命令の使用

シミューレータSPIMは多くの疑似命令を用意しており、MIPSの命令にはない記述をかなり自由に書けてしまいます。たとえば分岐命令には即値との比較はありませんが、下記のような記述が許されています。

move $t0, $zero LABEL: ... ... addi $t0, $t0, 1 bne $t0, 10, LABEL

これは実際には以下のように展開されます。

move $t0, $zero LABEL: ... ... addi $t0, $t0, 1 li $at, 10 bne $t0, $at, LABEL

これは10回の繰り返しを実現したプログラムの例ですが、この例では繰り返し内で毎回定数10をレジスタ$atに格納することになり、 これと同様の処理を繰り返しの外に出せば無駄を省けることが分かります。さらに繰り返しの制御を0から始めて上限値の10で停める場合はレジスタをこのために1つ使用するため、10 から0へと変化させる場合よりも余分にレジスタを使うことが分かります。

CPUの振舞いを正しく理解するためにも、むやみにSPIMの疑似命令を使用せず、この教材に載せた命令(推薦図書「コンピュータの仕組み」と同等)の範疇でプログラムを書くようにしましょう。

HOMEに戻る