Upload
duongbao
View
231
Download
5
Embed Size (px)
Citation preview
情報システム学実験2ボードコンピュータ
2014年度
第4週
MipsIt
• Lund University, Royal Institute of Technology (Sweden)で開発されたMIPSの教育用システム
• Windows上で動作する開発環境(MipsIt Studio)とシミュレータを利用する
• スイッチ、LEDの入出力がプログラミング可能
• コンソール入出力用基本関数が利用できる
MipsItシミュレータ
操作手順
• MipsIt Studioでソースファイルを作る
• MipsIt Studioでコンパイルする
• シミュレータを起動する
• 実行ファイルをシミュレータにアップロードする
• シミュレータで実行する
操作方法
• MipsIt Studioの起動
– E¥MipsIt¥bin¥MipsIt.exeをクリックする
(エラーメッセージが出ても無視してOKを押す)
– File Menuでopen projectを選択
– E¥MipsIt¥example¥example4-1¥example4-1.mipを選択
– example4-1.sをクリックする
• コンパイル:Build menuでCompileを選択
• シミュレータの起動– E¥MipsIt¥bin¥Mips.exeをクリックする
• シミュレータへのアップロード:Build menuでuploadを選択
ディレクトリ構成以下のようにフォルダを作ること
課題ごとにprojectを作ること
MipsIt
example(例題)
kadai(課題)
example4-1example4-2
kadai4-3
kadai4-4
bin MipsIt.exe (開発環境)
Mips.exe (シミュレータ)
課題4-1:例4-1の総和を求めるプログラムをMipsItシミュレータで1命令ずつ実行し、動作を確認せよ。次にラベルがloopの命令にブレークポイントを設定して連続実行し、loopごとのレジスタの値の変化を観察せよ。
例4-1(総和を求める).set noreorder # 命令の順序を変えない.data # データ領域の開始
A: .word 1 # 変数Aの宣言 ( word, 値は 1).word 2.word 4.word 3.word 0.text # 命令領域の開始.globl start # 開始命令startのglobal宣言.ent start # 関数startの開始
start: add $8, $0, $0 # $8 <= 0la $9, A # $9 <= Aのアドレス (ポインタの初期化)
loop: lw $10, 0($9) # $10 <= A[i]nop # beq $10,$0, halt # if ($10 == 0) goto haltnop # add $8, $8,$10 # $8 <= $8 + $10addi $9, $9, 4 # $9 <= $9 + 4 (ポインタのインクリメント)j loop # nop #
halt: j haltnop # .end start # 関数startの終了
la命令(load address):擬似命令
la $9, A Aのアドレスを$9に格納する
• Aのアドレスの割当てはプログラマには見えないが、アセンブラには分かる
• アセンブラでは、以下のように置き換える
lui $9, Aの上位16bitaddiu $9, Aの下位16bit
課題4-2:例4-2の総和を求めるプログラムをMipsItシミュレータで実行せよ。また、アセンブラによりどこにNOPが挿入され、どのようにコードが生成されているかを調べよ。
例4-2.set noreorder がない→アセンブラが最適化を行う。(NOPは不要)#include <iregdef.h>→ レジスタの名称を使用できる
RAMウィンドウの中の命令を読み、例4-2の記述と比較するNOPの挿入、命令順序の変更に着目する
例4-2(総和を求める)#include <iregdef.h> # レジスタの名称を使用する
.data # データ領域の開始A: .word 1
.word 2
.word 4
.word 3
.word 0.text # 命令領域の開始.globl start # 開始命令startのglobal宣言.ent start # 関数startの宣言
start: add t0, zero, zero # t0 <= 0la t1, A # t1 <= Aのアドレス(ポインタ初期化)
loop: lw t2, 0(t1) # t2 <= A[i]beq t2, zero, halt # if (t2 == 0) goto haltadd t0, t0, t2 # t0 <= t0 + t2addi t1, t1, 4 # t1 <= t1 + 4 (ポインタのインクリメント)j loop # jump to loop
halt: j halt .end start # 関数startの終了
課題4-3:例4-2を参考にして、最大値を求めるプログラムを作成し、MipsItで実行せよ。また、アセンブラによりどのように最適化されるかを調べよ。
関数の呼び出し
main:
addi a0, zero, 1jal procadd s0, v0, zero
proc:
jr ra
引数:a0
結果:v0
関数呼び出しに用いるレジスタ• a0~a3:引数を渡す• v0~v1:結果の値を返す• ra: 戻りアドレスを格納する
関数の呼び出し :jal命令(リターンアドレスをraレジスタに格納)関数のリターン :jr ra (raに格納されているアドレスに分岐)
start:
addi a0, zero, 1addi a1, zero, 2jal max
max: slt s1, a0, a1bne s1, zero, L1add v0, a0, zeroj L2
L1: add v0, a1, zeroL2: jr ra
引数:a0,a1
戻り値:v0
これでは、maxの中でs1が破壊されるstartの中でs1を利用していると、関数呼び出しによりs1が破壊される.
そのため、呼び出された関数ではスタックを用いて値の退避と復元を行う
例4-3:2つの引数の大きい方を返す関数(1)
a0:a1
v0<=a0 v0<=a1
<
>= L1
例4-3:2つの引数の大きい方を返す関数(2)
max: addi sp, sp, -4sw s1, 0(sp) # s1の退避slt s1, a0, a1 # if (a0 < a1) s1 <= 1bne s1, zero, L1 # if (s1 != 0) goto L1add v0, a0, zero # v0 <= a0 (a0が大きいとき)j L2
L1: add v0, a1, zero # v0 <= a1 (a1が大きいとき)L2: lw s1, 0(sp) # s1の復元
addi sp, sp, 4jr ra # return.
退避
復帰
本体
スタック
SP
ここより下にはデータが格納されている
s1
MIPSでは、手続き呼び出しにおいてs0~s7レジスタの退避・復元は行うが、t0~t9レジスタの退避・復元は行わないことが規定されている。
課題4-4例4-3のmax関数を用いて課題4-3の最大値を求めるプログラムを書き換えよ。
課題4-3のプログラムで大小比較をしている部分をmaxに書換える引数の渡し方、戻り値の利用に注意
コンソール入出力関数関数 引数 戻り値
printf a0:format文字列a1~a3:引数formatは%d,%s,%fのみ
なし
putchar a0:文字 なし
getchar なし v0:文字
puts a0:文字列アドレス なし
gets a0:文字列アドレス v0:文字列アドレス
atoi a0:文字列アドレス v0:数値
例4-4:文字数をカウントするプログラム(1)
#include <iregdef.h>.data
Text1: .asciiz “input characters¥n”Text2: .asciiz “number of character is %d¥n”A: .space 80
.text
.globl startent start
start:
.end start
文字列の宣言
領域の宣言
プログラムの中身
例4-4:文字数をカウントするプログラム(2)
.ent startstart: add t1,zero,zero # カウンタの初期化
la a0, Text1jal printf # print Text1la a0, Ajal gets # 領域Aへの文字入力
LOOP: lb t2, 0(v0)beq t2,zero,NEXT # 入力文字列の最終チェックadd t1,t1,1 # カウンタのインクリメントadd v0,v0,1 # ポインタのインクリメントj LOOP
NEXT: la a0, Text2add a1, t1, zerojal printf # print Text2j start.end start
getsの使用例
printfの使用例
乗除算
mul rd, rs, rt # rd <= rs * rtdiv rd, rs, rt # rd <= rs / rt
アセンブラは機械語命令(MULT、DIV)と演算結果のレジスタへの転送命令を生成する。(ただし、符号なし整数32ビット)
剰余を求めるときは、mfhi命令を用いればよい。div t3, t1, t2mfhi t4
擬似命令
課題4-5
X<=M[i]
i<=0, S<=0
S<= S*10 +Xー’0’
X:’9’+1
X:’0’
開始
終了
i++
<0
>=0>=0
<0
コンソールから入力されたASCIIコードをintegerに変換するatoi関数を作成せよ。
int atoi(char s[]){int i, n;
n = 0;for (i=0; s[i] >= ‘0’ && s[i] <= ‘9’; ++i)
n = 10 * n + (s[i] – ‘0’);return n;}
進捗確認
① 課題4-1/4-2の動作(TA確認)
② 課題4-3の動作(TA確認)
③ 課題4-4の動作(TA確認)
④ 課題4-5の動作(TA確認)