---
# System prepended metadata

title: ISA進階操作(Cont.)

---

# ISA進階操作(Cont.)
## MIPS Decision Instructions
* `beq`（Branch if Equal）：當兩個 register 的值相等時，執行分支。語法如下：
    * `beq register1, register2, L1` 相當於c語言 `if (register1==register2) goto L1`
* `bne`（Branch if Not Equal）：當兩個 register 的值不相等時，執行分支。語法如下：
    * `bne register1, register2, L1` 相當於c語言 `if (register1!=register2) goto L1`
    
這些稱為 conditional branches(有條件分支)
* `j label`
    * 這條指令的意義是直接跳轉到給定的 `label`，可以視為無條件的 goto 操作
    * 這條指令採用J-format指令，詳情可見上一篇筆記

這稱為 unconditional branches(無條件分支)

以下`if-else`程式碼舉例：
```
# C code
if (i == j) f = g + h;
else f = g - h;

# 對應的 MIPS assembly code
bne $s2, $s3, Else  # 如果 i != j，跳轉到 Else
add $s0, $s1, $s4   # f=g+h
j Exit              # 跳轉到 Exit
Else: 
sub $s0, $s1, $s4   # f=g-h
Exit:
```
以及`while` 舉例
```
# C code:
while (save[i] == k) i += 1;
# i in $s3, k in $s5, address of save in $s6

# 對應的 MIPS code:
# Compiled MIPS 代碼:
Loop: 
    sll $t1, $s3, 2     # 將$s3 的值左移兩位，相當於乘以 4（2^2）。結果存儲在 $t1 中。
    add $t1, $t1, $s6   # $t1 = save[5] 的地址，將 (3 + 2)的 offset 加上 $s6中save[0] 的位址得到 save[5]的位址，並存儲在$t1
    lw $t0, 0($t1)      # $t0 = save[i]，載入 save[i] 的值
    bne $t0, $s5, Exit  # 如果 save[i] 不等於 k，跳轉到 Exit 標籤
    addi $s3, $s3, 1    # i = i + 1，增加索引
    j Loop              # 跳轉回 Loop 標籤，重新執行迴圈

Exit:
```
進行小於（<）的比較可以使用 `slt` （Set on Less Than）指令。
* `slt rd, rs, rt`
    * 如果 rs 小於 rt，則將目的 register rd 設置為 1，否則設置為 0。
* `slti rt, rs, constant`
    * 如果 rs 小於Immediate constant，則將目的 register rt 設置為 1，否則設置為 0。
以下舉例
```
# c語言
if (g < h) goto Less;
# g: $s0, h: $s1

slt $t0, $s0, $s1    # $t0 = 1 if g < h
bne $t0, $zero, Less # 如果 $t0 不等於 0（即 g < h 成立），則跳轉到 Less

```
### 但需要注意在assembly language中，要區分 signed 以及 unsigned

例子：
$s0 = 1111 1111 1111 1111 1111 1111 1111 1111
$s1 = 0000 0000 0000 0000 0000 0000 0000 0001

```
# signed 比較，檢查 $s0 是否小於 $s1
slt $t0, $s0, $s1
# 結果：-1 < +1，因此 $t0 被設置為 1

# unsigned 比較，檢查 $s0 是否小於 $s1
sltu $t0, $s0, $s1
# 結果：+4,294,967,295（unsigned最大值） > +1，因此 $t0 被設置為 0
```
在signed 以及 unsigned 的情境下，相同的二進位表示可以有不同的解釋。

## Procedure Calling
相當於程式語言中的函式調用
以下是涉及到呼叫方（Caller）和被呼叫方（Callee）之間的一系列步驟：

**Caller（呼叫方）:**
1. Caller將需要傳遞給被Caller的參數放入指定的 register 中。通常，前幾個參數會被放入特定的 register （例如 $a0, $a1 等）。

2. Caller使用 jal（Jump and Link）指令將控制權轉移到被Caller的起始地址。在轉移之前，jal 指令會將返回地址存儲在 register  $ra 中

**被呼叫方（Callee）:**

3. Callee 為程序的local variable和其他存儲需求分配空間。這通常通過修改 stack pointer `$sp` 來實現。

4. Callee 執行程序的操作，包括對參數的處理、local variable的使用等。

5. 如果程序有返回值，Callee 將結果放入呼叫方指定的 register 中。通常，這是通過將結果存儲在 $v0（返回值 register ）中來完成的。

6. Callee 使用 jr $ra 指令將控制權返回到呼叫方。這個指令從 $ra register 中載入返回地址，並跳轉到該地址。

舉例來說：
```
c code
int leaf_example (int g, h, i, j)
{ int f;
 f = (g + h) - (i + j);
 return f;
}

leaf_example:
    addi $sp, $sp, -12   # 1. 調整stack pointer，為局local variable的使用等分配12個 bits 的空間
    sw $s0, 0($sp)       # 2. 將 $s0 register 的值存入 stack 
    sw $t1, 4($sp)       # 3. 將 $t1 register 的值存入 stack 
    sw $t2, 8($sp)       # 4. 將 $t2 register 的值存入 stack 

    add $t1, $a0, $a1    # 5. 計算 $t1 = g + h
    add $t2, $a2, $a3    # 6. 計算 $t2 = i + j
    sub $s0, $t1, $t2    # 7. 計算 $s0 = $t1 - $t2

    move $v0, $s0        # 8. 將結果 $s0 存入Result register $v0

    lw $s0, 0($sp)       # 9. 從 stack 中還原 $s0 的值
    lw $t1, 4($sp)       # 10. 從 stack 中還原 $t1 的值
    lw $t2, 8($sp)       # 11. 從 stack 中還原 $t2 的值
    addi $sp, $sp, 12    # 12. 調整 stack pointer，釋放局部變數佔用的空間
    jr $ra               # 13. Result，跳轉到返回地址

Program Counter (PC) 的作用：
    # 在步驟 1-12 中，PC 在這段代碼中沒有被直接修改，因此保持不變。
    # 在步驟 13 中，`jr $ra` 指令將 PC 設置為返回地址，即返回到调用 leaf_example 過程的指令。
```