MIPSの命令形式
MIPSの命令の形式は全部で3種類
R形式
| 名前 | op | rs | rt | rd | shamt | funct |
|---|---|---|---|---|---|---|
| 種類 | オペコード | 第一ソースオペランドレジスタ指定 | 第二ソースオペランドレジスタ指定 | デスティネーションオペランドレジスタ指定 | シフト命令で指定するシフト量を即値で与える | opと組み合わせて命令を選択(addとsubとか) |
| 与える情報 | 命令の形式 | レジスタ番号0~32 | レジスタ番号 | レジスタ番号 | シフト命令のためにレジスタを使用しない | 命令の形式 |
| ビット長さ | 6 | 5 | 5 | 5 | 5 | 6 |
I形式(Immidiate)
| 名前 | op | rs | rt | 即値 |
|---|---|---|---|---|
| 種類 | オペコード | ソースオペランドレジスタ指定 | ディスティネーションオペランドレジスタ指定 | 定数や変位 |
| 与える情報 | 命令の形式 | レジスタ番号 | レジスタ番号 | 即値 |
| ビット長さ | 6 | 5 | 5 | 16 |
J形式(Jump)
| 名前 | op | アドレス |
|---|---|---|
| 種類 | オペコード | ジャンプ先 |
| 与える情報 | 命令の形式 | アドレス |
| ビット長さ | 6 | 26 |
→これでは32ビットのアドレスを指定できないのでは?
MIPSのアドレス指定
- 即値アドレス指定
addi $t0, $t1, 3- I形式、3番を見に行く
- レジスタ直接指定
add $t0, $t1, $t2- R形式
- ベースレジスタ修飾
lw $t0, -4($t1)- I形式
- PC相対アドレス指定
beq $t0, $t1, loop- I形式、プログラムカウンタをアドレス指定に利用
- 疑似直接アドレス指定
-
jal printf -
J形式
- J形式はアドレスとして26ビットしか使えないがアラインメント制約によって下位2ビットを省略できる。それでもまだ足りないのでプログラムカウンタの上位4ビットをつなげて32ビットとする
- 上位4ビットの範囲が変わらない位置に命令を配置することによって制約を受けないアドレス指定方式の比較図
mindmap root((MIPS アドレス指定)) 即値アドレス指定 命令内に直接値 addi $t0, $t1, 3 レジスタ直接指定 レジスタ番号で指定 add $t0, $t1, $t2 ベースレジスタ修飾 ベース + オフセット lw $t0, -4($t1) PC相対アドレス指定 PC + オフセット beq $t0, $t1, loop 疑似直接アドレス指定 PC上位4bit + 26bit jal printfflowchart TD A[命令実行] --> B{アドレス指定方式} B -->|即値| C[命令内の即値を使用] B -->|レジスタ直接| D[レジスタの内容をそのまま] B -->|ベースレジスタ修飾| E[レジスタ値 + 即値オフセット] B -->|PC相対| F[PC + 即値オフセット] B -->|疑似直接| G[PC上位4bit + Jアドレス26bit] C --> H[有効アドレス決定] D --> H E --> H F --> H G --> H H --> I[メモリアクセス or 演算]
-
MIPSのアセンブリ言語
数値の算術演算
| 種類 | 名前 | 構文 | 意味 | 備考 |
|---|---|---|---|---|
| 算術 | add | add $rd, $rs, $rt | $rd ← $rs + $rt | R形式 |
| add unsigned | addu $rd, $rs, $rt | $rd ← $rs + $rt (符号なし) | R形式 | |
| add immediate | addi $rt, $rs, imm | $rt ← $rs + imm | I形式 | |
| subtract | sub $rd, $rs, $rt | $rd ← $rs - $rt | R形式 | |
| or immediate | ori $rt, $rs, imm | $rt ← $rs | imm | I形式 | |
| データ転送 | load word | lw $rt, offset($rs) | $rt ← Mem[$rs + offset] | I形式 |
| load word | lw $rt, label | ラベルからアドレスを読み込み | 疑似命令 | |
| load byte | lb $rt, offset($rs) | $rt ← Mem[$rs + offset] (符号拡張) | I形式 | |
| load byte | lb $rt, label | ラベルからアドレスを読み込み | 疑似命令 | |
| store word | sw $rt, offset($rs) | Mem[$rs + offset] ← $rt | I形式 | |
| store byte | sb $rt, offset($rs) | Mem[$rs + offset] ← $rt (下位8bit) | I形式 | |
| load immediate | li $rt, imm | $rt ← imm | 疑似命令 (lui+ori) | |
| load upper imm. | lui $rt, imm | $rt ← imm << 16 | I形式 | |
| move | move $rd, $rs | $rd ← $rs | 疑似命令 (add rs,$zero) | |
| load address | la $rd, label | $rd ← labelのアドレス | 疑似命令 | |
| 比較 | set on less than | slt $rd, $rs, $rt | $rd ← ($rs < $rt ? 1 : 0) | R形式 |
| set on less than imm. | slti $rt, $rs, imm | $rt ← ($rs < imm ? 1 : 0) | I形式 | |
| 条件分岐 | branch on equal | beq $rs, $rt, label | if ($rs == $rt) then PC ← PC + offset | I形式 |
| branch on not eq. | bne $rs, $rt, label | if ($rs != $rt) then PC ← PC + offset | I形式 | |
| 無条件ジャンプ | jump | j label | PC ← (PC上位4bit << 28) | (label << 2) | J形式 |
| jump register | jr $rs | PC ← $rs | R形式 | |
| jump and link | jal label | $ra ← PC+4; PC ← ... | J形式 | |
| その他 | system call | syscall | OS呼び出し | R形式 (funct=12) |
SPIMで扱えるsyscall
| サービス | システムコールコード | 引数 | 結果 |
|---|---|---|---|
| print_int | 1 | $a0 = 出力する整数 | |
| print_float | 2 | $f12 = 出力するfloat | |
| print_double | 3 | $f12 = 出力するdouble | |
| print_string | 4 | $a0 = 出力する文字列のアドレス | |
| read_int | 5 | $v0 に整数が返る | |
| read_float | 6 | $f0 にfloatが返る | |
| read_double | 7 | $f0 にdoubleが返る | |
| read_string | 8 | $a0 = バッファのアドレス$a1 = バッファの長さ | 文字列がバッファに格納 |
乗算命令は計算結果が64ビットまで行く可能性がある
→専用のHiレジスタとLoレジスタを利用
mult $rs, $rt
→R形式、符号付き乗算。$rs×$rtの上位32ビットをHi,下位32ビットをLoへ
mfhi $rd
→R形式で$rd←Hi、似たように使えるmfloがある
パイプラインの都合で掛け算がめんどくさい
mul $rd, $rs, $rt/即値
→R形式疑似命令、$rd←$rs×$rdの下位32ビットを格納
div $rs, $rt
→R形式符号付き除算、商をLo、剰余をHiに格納
div $rd, $rs, $rt/即値
→商を$rdに格納、オーバーフローとゼロ除算を考慮
(g+h)*(i-j)
add $t4, $t0, $t1
sub $t5, $t2, $t3
mul $t5, $t4, $t5ここではghijを0123に格納、結果を6にした
tレジスタは汎用的に使える(sレジスタを使うときにはcallee-saveに留意)
条件分岐
if(x==y){
hoge;
}else{
huga;
}
hunya;bne $t8,$t9, ELse
hoge
j Exit
Else:
huga
Exit:
hunyaラベルの名前が命令と同じものだったり同じ名前が複数個あったりしたらアウト
if(x<18){
hoge;
}else{
huga;
}
hunya;slti $t0, $t8, 18 // $t0←($t8<18)?1:0 (SetonLessThanImm)
beq $t0, $zero, Else
hoge
j Exit
Else:
huga
Exit:
hunya