20260525_2


MIPSの命令形式

MIPSの命令の形式は全部で3種類

R形式

名前oprsrtrdshamtfunct
種類オペコード第一ソースオペランドレジスタ指定第二ソースオペランドレジスタ指定デスティネーションオペランドレジスタ指定シフト命令で指定するシフト量を即値で与えるopと組み合わせて命令を選択(addとsubとか)
与える情報命令の形式レジスタ番号0~32レジスタ番号レジスタ番号シフト命令のためにレジスタを使用しない命令の形式
ビット長さ655556

I形式(Immidiate)

名前oprsrt即値
種類オペコードソースオペランドレジスタ指定ディスティネーションオペランドレジスタ指定定数や変位
与える情報命令の形式レジスタ番号レジスタ番号即値
ビット長さ65516

J形式(Jump)

名前opアドレス
種類オペコードジャンプ先
与える情報命令の形式アドレス
ビット長さ626

→これでは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 printf
      
      flowchart 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のアセンブリ言語

数値の算術演算

種類名前構文意味備考
算術addadd $rd, $rs, $rt$rd ← $rs + $rtR形式
add unsignedaddu $rd, $rs, $rt$rd ← $rs + $rt (符号なし)R形式
add immediateaddi $rt, $rs, imm$rt ← $rs + immI形式
subtractsub $rd, $rs, $rt$rd ← $rs - $rtR形式
or immediateori $rt, $rs, imm$rt ← $rs | immI形式
データ転送load wordlw $rt, offset($rs)$rt ← Mem[$rs + offset]I形式
load wordlw $rt, labelラベルからアドレスを読み込み疑似命令
load bytelb $rt, offset($rs)$rt ← Mem[$rs + offset] (符号拡張)I形式
load bytelb $rt, labelラベルからアドレスを読み込み疑似命令
store wordsw $rt, offset($rs)Mem[$rs + offset] ← $rtI形式
store bytesb $rt, offset($rs)Mem[$rs + offset] ← $rt (下位8bit)I形式
load immediateli $rt, imm$rt ← imm疑似命令 (lui+ori)
load upper imm.lui $rt, imm$rt ← imm << 16I形式
movemove $rd, $rs$rd ← $rs疑似命令 (add rs,$zero)
load addressla $rd, label$rd ← labelのアドレス疑似命令
比較set on less thanslt $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 equalbeq $rs, $rt, labelif ($rs == $rt) then PC ← PC + offsetI形式
branch on not eq.bne $rs, $rt, labelif ($rs != $rt) then PC ← PC + offsetI形式
無条件ジャンプjumpj labelPC ← (PC上位4bit << 28) | (label << 2)J形式
jump registerjr $rsPC ← $rsR形式
jump and linkjal label$ra ← PC+4; PC ← ...J形式
その他system callsyscallOS呼び出しR形式 (funct=12)

SPIMで扱えるsyscall

サービスシステムコールコード引数結果
print_int1$a0 = 出力する整数
print_float2$f12 = 出力するfloat
print_double3$f12 = 出力するdouble
print_string4$a0 = 出力する文字列のアドレス
read_int5$v0 に整数が返る
read_float6$f0 にfloatが返る
read_double7$f0 にdoubleが返る
read_string8$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