MIPSアセンブリ言語入門1

#概要

MIPSについてまとめてみた
MIPSのプログラムの実行はシミュレータのSPIMを使用している

#Hello World

##Hello Worldの表示

最初にHello Worldを表示するプログラムを作ってみる。

```MIPS:hello.asm
#Hello Worldを表示するプログラム

#データ
        .data
msg:    .asciiz "Hello World\n"

#テキスト

        .text
        .globl main
main:
  li    $v0, 4
        la        $a0, msg
        syscall
        jr        $ra

# end
```

```:実行結果
Hello World
```

##hello.asmの説明

`#`の後はコメントアウト
プログラムはデータ領域とテキスト領域で構成される。

###データ領域

データ領域とは変数値や計算の途中で一時的に使われる領域のこと。

```:hello.asmのデータ領域
        .data
msg:    .asciiz "Hello World\n"
```

1行目の`.data`はデータ領域の開始の宣言を表す。
2行目の`msg:    .asciiz "Hello World\n"`はラベル`msg`の宣言をしている。

ラベルを宣言することによって、このアドレスを`msg`という記号で参照することができる。

###テキスト領域

テキスト領域とはプログラムを配置する領域である。

```:hello.asmのテキスト領域
        .text
        .globl main
main:
  li    $v0, 4
        la        $a0, msg
        syscall
        jr        $ra

# end
```

1行目の`.text`でテキスト領域の開始の宣言をする。
2行目の`.globl main`で下で定義されている`main`というラベルがグローバル(このプログラムの外部から見える)であることを宣言する。
3行目でラベル`main`を宣言。
4行目`li    $v0, 4`は$v0レジスタに値4をロードする。
5行目`la        $a0, msg`$a0はレジスタに付加パラメータ(この場合は表示する文字列を格納した領域のアドレス)をロードする。
6行目`syscall`はシステムコールを実行する。実行するシステムコールの種類は$v0で指す
7行目`jr        $ra`は呼び出しもとに戻る(return)。アドレスは$raに格納されている。

#レジスタ

MIPSのレジスタは32個ある。

### $s0〜$7 (16〜23)

プログラムの変数の値を保持

### $t0〜$t7 (8〜15）

計算途中の一時的な値を保持

### $zero (0)
常に0という値を持つ特別なレジスタ

#アセンブリ命令

##算術演算

###add

```
add $s1, $s2, $s3
```


```math
$s1 = $s2 + $s3
```

###sub

```
sub $s1, $s2, $s3    
```


```math
$s1 = $s2 - $s3
```

###addi

```
addi $s1, $s2, num
```


```math
$s1 = $s2 + num
```

##データ転送

load命令とstore命令がある。

* load命令 : 主記憶かrレジスタに値を転送する
* store命令 : レジスタから主記憶に値を転送する

###lw

```
lw $s1, num($s2)
```


```math
$s1 = メモリ[$s2 + num]
```

###sw

```
sw $s1, num($s2)
```


```math
$s1 = メモリ[$s2 + num]
```

##論理演算

###and

```
and $s1, $s2, $s3
```

```math
$s1 = $s2 \quad \& \quad $s3
```
###or

```
nor $s1, $s2, $s3
```

```math
$s1 = $s2 \quad || \quad $s3
```


###nor

```
nor $s1, $s2, $s3
```

```math
$s1 = ! ($s2 \quad || \quad $s3)
```

###sll

```
sll $s1, $s2, 10
```

```math
$s1 = $s2 \quad << \quad 10
```

###sli

```
sli $s1, $s2, 10
```

```math
$s1 = $s2 \quad >> \quad 10
```

##無条件ジャンプ

###j

```
j 2500     意味　: go to 2500
```

#MIPSのフィールド


| op | rs | rt | rd | shamt | funct |
|:-:|:-:|:-:|:-:|:-:|:-:|
| 6bit  | 5bit  | 5bit  | 5bit  | 5bit  | 6bit  |

* OP : 命令の基本操作。オペコード
* rs : 第１のソース・オペランドのレジスタ
* rt : 第2のソース・オペランドのレジスタ
* rd : ディスティネーション・オペランドのレジスタ。結果を収める先
* shamt : シフト量
* funct : 機能コード。命令操作フィールドのバリエーションを表す。

#実際のプログラム例

##assing.asm

```c:assign.c
int src = 1234;
int dst;

int main()
{
	dst = src;

	return 0;
}
```

これをMIPSのコードにコンパイルすると

```assign.asm
# データ領域の宣言
        .data

# int src = 1234
        .globl    src
src:    .word     1234

# int dst
        .globl    dst
dst:    .word     0

#データ領域の宣言の終了
        .text

# int main ()
        .globl    main
main:

# dst = src;
        la    $t0, src     # srcのアドレス値をt0にロードする
        lw    $s0, 0($t0)  # t0の内容をs0にロードする
        la    $t1, dst     # dstのアドレス値をt1にロードする
        sw    $s0, 0($t1)  # s0の内容をt1にストアする

#return 0
        li    $v0, 0    # $v0に値9をロードする
        jr    $ra       # 呼び出しもとに戻る
```

##addition.asm

```c:addition.c
int x1 = 1234;
int x2 = 5678;
int y;

int main()
{
	y = x1 + x2;

	return 0;
}
```

これをMIPSのコードにコンパイルすると

```asm:addition.asm
# データ領域開始の宣言
        .data

# int x1 = 1234
        .globl    x1
x1:     .word     1234

# int x2 = 5678
        .globl    x2
x2:     .word     5678

# int y
        .globl    y
y:      .word     0

#テキスト領域の開始
        .text

# int main
        .globl    main
main:

# y = x1 + x2
    la    $t0, x1    
    lw    $s0, 0($t0)
    la    $t0, x2
    lw    $s1, 0($t0)
    add   $s0, $s0, $s1
    la    $t0, y
    sw    $s0, 0($t0)

# return 0
    li    $v0, 0
    jr    $ra
```

##addition2.asm

`addition2.c`は`addition.c`とほぼ変わらないが、初期値宣言をしていない。

```c:addition2.c
int p;
int q;
int r;

int main()
{
    p = 1;
    q = 2;
    r = p + q;

    return 0;
}
```

これをコンパイルすると

```:addition2.asm
# データ領域の開始の宣言
        .data

# int p
        .globl    p
p:      .word     0

# int q
        .globl    q
q:      .word     0

# int r
        .globl    r
r:      .word     0

# テキスト領域の開始の宣言
        .text

# int main
        .globl    main
main:

# p = 1
    la    $t0, p
    li    $s0, 1
    sw    $s0, 0($t0)

# q = 2
    la    $t0, q
    li    $s0, 2
    sw    $s0, 0($t0)

# r = p + q
    la    $t0, p
    lw    $s0, 0($t0)
    la    $t0, q
    lw    $s1, 0($t0)
    add   $s0, $s0, $s1
    la    $t0, r
    sw    $s0, 0($t0)

# return 0
    li    $v0, 0
    jr    $ra

```

`addition2.asm`と`addition.asm`を比較してみると初期値宣言をしている`addition.asm`の方が効率が良いことが分かる。

#関連記事

https://qiita.com/twrcd1227/items/405cf58e8c9fcd3447ac