MIPS命令シミュレータ mipsy


概要

演習で使用することを目的として作られた、 MIPS命令セットを解釈・実行するソフトウェアシミュレータである。
各命令を6クロックサイクルの非パイプライン方式で処理するように作られている。

シミュレータはC++言語により記述されており、構造が単純であるため全体の 構造を短期間に理解可能である。 そのため、シミュレータの改造や機能拡張が容易である。

C言語あるいはMIPSアセンブリ言語で記述したプログラムソースファイルを クロスコンパイラおよびクロスアセンブラで実行可能バイナリコードを生成し、 生成したバイナリコードを16進表現でダンプしたテキストファイル(正式には 「モトローラSレコード形式」)をシミュレータの入力として読み込み、実行する。

(現在のところ)ライブラリが要求するシステムコールを実装していないため、 printf()などの標準Cライブラリは使用できないが、 入出力の代替手段として簡単なサービスコール機能を備えており、これにより 整数型データや文字列データなどの入出力やプログラムの終了などを行うことが できる。

ソースファイル

mipsyは以下のファイルから構成される。

上記ソースファイルをまとめたZIPファイルを ここに置いておくので 一括してファイルを取得した場合に利用するとよい。

命令セット

MIPS-I命令セットのサブセットとなる命令に対応している。 演習での使用を目的として、必要最小限の数の命令に対応するため、 整数系の命令(の一部)のみが実装されている。 (浮動小数演算命令については実装されていない)
具体的には以下に示す命令を実装している。
各命令の動作内容については ここ(Wikipedia) を参照。
(参考資料「はじめて読むMIPS」にも説明が載っている)

サービスコール

break命令を使ったサービスコールを行うことで、 データの入出力やプログラムの終了などの機能を実現することができる。
レジスタ2番に機能コードをセットし、レジスタ4番〜7番 (ただし、必要な個数のレジスタのみ使用)に引数をセットして break命令を実行する。 サービスコールの返値はレジスタ2番にセットされる。

現在、以下の機能を使うことができる。

具体的な動作はmipsyソースコードの mipsクラスの メンバ関数do_break()内を調べるとよい。

以下はサービスコールの使い方を示した例である。

li      $4,123        /* 表示する値をレジスタ4番にセット */
li      $2,0x21       /* 整数型データ出力の機能コード(== 0x21)を
                         レジスタ2番にセット */
break                 /* break命令を実行
                         レジスタ4番にセットした値が画面に表示される */


la      $4,SBUF_LABEL /* 文字列入力用のバッファの先頭アドレスを
                         レジスタ4番にセット */
li      $2,0x13       /* 文字列データ入力の機能コード(== 0x13)を
                         レジスタ2番にセット */
break                 /* break命令を実行
                         レジスタ4番で指定したアドレスに文字列データが
                         読み込まれる */

インラインアセンブラを使うことで、 C言語からもサービスコールを使うことができる。

int v = 123;
char strbuf[2048];

... (中略) ...

/* 整数型データ出力 */
asm ("move $4,%0" : : "r" (v));
asm ("li	$2,0x21");
asm ("break");

/* 文字列データ入力 */
asm ("move $4,%0" : : "r" (strbuf));
asm ("li	$2,0x13");
asm ("break");

C言語でインラインアセンブラ記述が続くとソースコードが読みにくくなる& 間違ったコードが入りやすくなるため、C言語のマクロとして定義しておくと 便利である。
ここにマクロ定義したヘッダファイル mipsy.hが置いてあるので自由に使ってよい。
このヘッダファイルを使ってサービスコールを使った例を以下に示す。

#include "mipsy.h"

int main()
{
    int v;
    char c;
    char tmpbuf[512];

    PRINT_INT(123456789);
    PRINT_CHAR('X');
    PRINT_STRING("FIZZ BUZZ");

    READ_INT(v);
    READ_CHAR(c);
    READ_STRING(tmpbuf);

    PRINT_INT(v);
    PRINT_CHAR(c);
    PRINT_STRING(tmpbuf);

    EXIT(0);

    /* control does not reach here */
    return 0;
}

C言語を使ったmipsy用プログラムの記述

システムコールが実装されていないため、現時点では printf()などの標準Cライブラリ関数を使うことは出来ない。 そのため、これらの関数を使わずに記述する必要がある。
また、通常のCプログラムではmain関数の最後で特にプログラムの終了 を指示しなくても問題はなかったが、mipsy用のプログラムでは プログラム終了を明示的に記述する必要がある。
以下はプログラム記述例(階乗の計算)である。
※以下の例ではmipsy.hを 使用してプログラムの記述を省力化している。 もし自分で作るプログラムでmipsy.hを 使用する場合は、プログラムのソースファイルと同じフォルダに mipsy.hを忘れずに置くこと。

#include "mipsy.h"

int fact(int n)
{
    if (n <= 1)
        return 1;
    else
        return n * fact(n - 1);
}

int main()
{
    int v = fact(10);

    PRINT_INT(v);
    EXIT(0);            /* program end here */

    /* control never reaches here */
    return 0;
}
Cソースファイル/ 逆アセンブルリスト/ ダンプテキストファイル

mipsyでのプログラムの実行方法

MIPSアーキテクチャ用クロスコンパイラ/アセンブラ環境で作成した ダンプテキストファイル(.srecファイル)をシミュレータに入力して実行する。 ダンプテキストファイル(.srecファイル)のファイル名をコマンドライン引数で 指定する。

実行方法は コマンドラインから実行する場合と Visual Studioから実行する場合の 二つの方法がある。

コマンドラインから実行する場合

まず、ダンプテキストファイル(.srecファイル)を実行可能ファイル(.exeファイル) mipsy.exeと同じフォルダにコピーする。
※場所はプロジェクトのフォルダの一つ上の階層のフォルダにある debugフォルダの下。
ファイルの用意が出来たら、以下のように入力してシミュレータを実行する。
mipsy program_file_name.srec

Visual Studio 2010から実行する場合

まず、ダンプテキストファイル(.srecファイル)をプロジェクトのフォルダ (シミュレータのソースファイル等が置かれている)にコピーする。
次に、以下の操作を行い、シミュレータ実行時のコマンドライン引数を設定する。
  1. 「プロジェクト」メニューから「プロパティ」を選択
  2. ウィンドウ左側の「デバッグ」項目を選択
  3. 右側に現れる「コマンド引数」項目に (mipsy用プログラムの)ダンプテキストファイル(.srec)のファイル名を設定
設定ができたら、「デバッグ」メニューからシミュレータを実行する。


文責:大津