---
# System prepended metadata

title: 'Chap. 02 - Instructuion Set '
tags: [課堂筆記, 計算機組織]

---

# Chap. 02 - Instructuion Set Architecture
> 課程內容 : 清華大學開放式課程 黃婷婷教授
> 參考書目 : Computer Organization and Design: The Hardware/Software Interface (5th), David A. Patterson, John L. Hennessy
> 
> 其他科目內容請參見 [[Here]](https://hackmd.io/@ChenZE/By4SOO6Jyl)

## Content
* [Sec. 2.1 Instruction set architecture](#Sec-21-Instruction-set-architecture)
    * [1. Recall in C language](#1-Recall-in-C-language)
    * [2. Components of an ISA](#1-Components-of-an-ISA)
* [Sec. 2.2 Operands](#Sec-22-Operands)
    * [1. Register operands and their organization](#1-Register-operands-and-their-organization)
        * [1.1 Register](#11-Register)
        * [1.2 Register architecture](#12-Register-architecture)
    * [2. Memory operands and data transfer](#2-Memory-operands-and-data-transfer)
        * [2.1 Data transfer: Memory to Register](#21-Data-transfer-Memory-to-Register)
        * [2.2 Data transfer instruction](#22-Data-transfer-instruction)
        * [2.3 Compilation with memory](#23-Compilation-with-memory)
        * [2.4 Data transfer: Register to memory](#24-Data-transfer-Register-to-memory)
        * [2.5 Compilation with memory](#25-Compilation-with-memory)
        * [2.6 Register V.S. Memory](#26-Register-VS-Memory)
    * [3. Immediate operands](#3-Immediate-operands)
        * [3.1 The constant zero](#31-The-constant-zero)
* [Sec. 2.3 Sign and unsigned number (略)](#Sec-23-Sign-and-unsigned-number-略)
* [Sec. 2.4 Representing instructions](#Sec-24-Representing-instructions)
    * [1. R-format instruction](#1-R-format-instruction)
    * [2. I-format instruction](#2-I-format-instruction)
        * [2.1 Example (1)](#21-Example-1)
        * [2.2 Example (2)](#22-Example-2)
* [Sec. 2.5 Operation](#Sec-25-Operation)
    * [1. Logical](#1-Logical)
        * [1.1 Shift operations](#11-Shift-operations)
        * [1.2 AND operation](#12-AND-operation)
        * [1.3 OR operation](#13-OR-operation)
        * [1.4 NOT operations](#14-NOT-operations)
    * [2. Decision making and branches](#2-Decision-making-and-branches)
        * [2.1 $\mathtt{beq}$: branch equal](#21-mathttbeq-branch-equal)
        * [2.2 J-format instruction](#22-J-format-instruction)
        * [2.3 Inequality](#23-Inequality)
        * [2.4 Signed v.s. Unsigned](#24-Signed-vs-Unsigned)
* [Sec. 2.6 Supporting procedures in hardware](#Sec-26-Supporting-procedures-in-hardware)
    * [1. Procedure calling](#1-Procedure-calling)
    * [2. Instruction for procedure call](#2-Instruction-for-procedure-call)
    * [3. Code for callee](#3-Code-for-callee)
    * [4. Non-leaf procedures](#4-Non-leaf-procedures)
    * [5. Memory layout](#5-Memory-layout)
* [Sec. 2.7 Communicating with people](#Sec-27-Communicating-with-people)
    * [1. Challenge](#1-Challenge)
    * [2. Improvenment](#2-Improvenment)
        * [2.1 Example](#21-Example)
* [Sec. 2.8 Addressing for 32-bit immediate and addresses](#Sec-28-Addressing-for-32-bit-immediate-and-addresses)
    * [1. 32-bit constants](#1-32-bit-constants)
    * [2. Branch addressing](#2-Branch-addressing)
        * [2.1 Syntax](#21-Syntax)
        * [2.2 Improvement](#22-Improvement)
    * [3. Jump addressing](#3-Jump-addressing)
        * [3.1 Syntax](#31-Syntax)
        * [3.2 Improvement](#32-Improvement)
    * [4. MIPS instruction summary](#4-MIPS-instruction-summary)
* [Sec. 2.9 補充: Translating and starting program](#Sec-29-補充-Translating-and-starting-program)
* [Sec. 2.10 Sort example](#Sec-210-Sort-example)
    * [1. C sort example (暫略)](#1-C-sort-example-暫略)
    * [2. Optimization](#2-Optimization)
* [Sec. 2.11 Arrays v.s. pointers](#Sec-211-Arrays-vs-pointers)
    * [1. Difference](#1-Difference)
    * [2. Example: clearing and array](#2-Example-clearing-and-array)
* [Sec. 2.12 ARM and X86 instruction sets](#Sec-212-ARM-and-X86-instruction-sets)
    * [1. Instruction](#1-Instruction)
    * [2. ARM v.s. MIPS](#2-ARM-vs-MIPS)
    * [3. Fallacies (常見錯誤迷思)](#3-Fallacies-常見錯誤迷思)
    * [4. Pitfalls (易錯觀念)](#4-Pitfalls-易錯觀念)
    * [5. Concluding remarks](#5-Concluding-remarks)

## Sec. 2.1 Instruction set architecture
### 1. Recall in C language
> Computer architecture = Instruction set architecture + Machine organization

回顧 C 語言(或其他語言)中，程式碼通常可分成以下的幾個區塊
* 運算子 operator : `+`、`-`、`*`、`/`、`%`
* 運算元 operand
    * 變數 variable : `lower`, `upper`, ...
    * 常數 constant : `0`, `1`, ...
* 敘述 assignment statement : `a = b + 1`

當使用 Assembler 組譯成組合語言時，以 `a = b + 5` 為例

![S__2170886](https://hackmd.io/_uploads/rJ5zNl0mC.jpg)

同樣會有些運算子、運算元等基本要素構成

### 2. Components of an ISA
ISA 的組成包含以下幾點
* Organization of programmable storage，用以表示資料該怎麼放，怎麼組織
    * register 暫存器
    * memory 記憶體
    * mode of addressing and accessing data item and instruction
* Data type and data structure，資料型態與結構
* Instruction format，指令的格式，例如長度為 32 bits 或 64 bits，或是每個區塊代表的意義
* Instruction set(或稱 operaion code, op code)，表示可以執行哪些指令

以 MIPS 架構為例，指令長度為 32-bits，且總共有三種不同的格式，如下圖

![S__2170887](https://hackmd.io/_uploads/rJUV8xR7C.jpg)

## Sec. 2.2 Operands
### 1. Register operands and their organization
以下為最基本的 MIPS arithmetic/logic instruction(算數與邏輯指令)，總共包含四個區塊(field)

$$
\begin{align*}
&1 & &2 & &3 & &4\\
a&dd & $&s0 & $&s1 & $&s2
\end{align*}
$$

* 各部名稱
    * Field 1 : operation by name, or called OP code (運算子的名稱)
    * Field 2 : operand getting result, or called destination (儲存結果)
    * Field 3 : 1st operand for operation, or called "source 1" (來源 1)
    * Field 4 : 2nd operand for operation, or called "source 1" (來源 2)
* 意義 : 把 $s1$ 的內容 $+$ $s2$ 的內容後放到 $s0$ 中
* 以上四個區塊的順序不可改變，且語法結構是固定的
    * 目的 : Keep hardward simply via regularity
* 每一個指令的長度皆為 32-bits

> **Design principle 1** - Simplicity favors regularity
> * Regularity makes implementation simpler
> * Simplicity enables highers performance at lower cost
> * 越簡單，速度越快

舉例 : How to do the following C statement ?
```c
f = (g + h) - (i - j);
```
經過編譯器編譯成 MIPS code 後
$$
\begin{align*}
&add & &t0, & &g, &h & &// \text{temp} \;\; t0 = g + h\\
&add & &t1, & &i, &j & &// \text{temp} \;\; t1 = i + j\\
&sub & &f, & &t0, &t1 & &//f = t0 - t1\\
\end{align*}
$$

#### 1.1 Register
與一般的高階語言不同，組合語言不會使用變數(variables)，組合語言的運算子稱為 Register (暫存器)。是靠近計算單元的一個特殊位置，數量有限，目的是用來儲存暫存的資料。直接焊接在 Hardware 之上，運算通常會在 Register 之中完成。因為是直接以 Hardware 實作，所以優點是速度比記憶體快，且易於實作與編譯

以 MIPS 架構為例，總共有 32 個暫存器，因此需要 5 bits 來描述暫存器的位置 $(\because 2^5=32)$ 且每個暫存器的大小為 32 bits (32 bits wide)，表示可以處理 32 bits 的資料量。每 32 bits 的大小稱為 a word in MIPS 

> Why is 32？
> **Design Principle 2** - Smaller is faster 

這 32 個暫存器可以用數字(from $0 to $31)或名稱來稱呼，習慣上 ＄16 到 $23 被稱為 $s0 到 $s7，作用相當於高階語言中的變數。 $8 到 $15 被稱為 $t0 到 $t7，作用相當於中間值(temporary)，每個暫存器都有他各自的意義與用途(如下圖)

![S__2179092](https://hackmd.io/_uploads/ryfvwpLNA.jpg)

以上述的 C 語言加法為例，若 f 到 j 依序使用 $s0 到 $s4 且中間值使用 $t0 與 $t1，則編譯成組合語言後為

$$
\begin{align*}
&add & &$t0, & &$s1, & &$s2 &//\text{temp}\;t0 = g + h\\
&add & &$t1, & &$s3, & &$s4 &//\text{temp}\;\;t1 = i + j\\
&sub & &$s0, & &$t0, & &$t1 &// f = (g+h) - (h+j)\\
\end{align*}
$$

#### 1.2 Register architecture
暫存器的架構共有 4 種
1. Accumulator(累加器)
只有一個 Register，做法是將資料從 Memory 載入並加到  Accumulator 之中。例如 : 
    *  1 address : $\text{add} \; A$ 表示 $acc \leftarrow acc + Mem[A]$
    * 1 + x address : $\text{add} \; A$ 表示 $acc \leftarrow acc + Mem[A+x]$
2. Stack
以 Stack 的方式實作，例如 : 
    * 0 address : $\text{add}$ 表示 $tos \leftarrow tos + next$
3. General Purpose Register
    * 2 address : $\text{add} \; A, B$ 表示 $EA(A) \leftarrow EA(A) + EA(B)$
    * 3 address : $\text{add} \; A, B, C$ 表示 $EA(A) \leftarrow EA(A) + EA(B) + EA(C)$
4. Load/Store(a special case of GPR)
    * 3 address : 
    $\text{add}$ $ra, $rb, $rc 表示 $ra $\leftarrow$ $rb + $rc
    $\text{load}$ $ra, $rb 表示 $ra $\leftarrow$ Mem[$rb] 

前兩種方式是早期做法，因為硬體資源貴，所以只有一個暫存器。後兩種方式差別在於第 3 種的資料可放在 Memory 或 Register 但第 4 種資料一定放在 Register 中

### 2. Memory operands and data transfer
> Variables in C is mapping to register, then however **what about large data structure like arrays ?**

#### 2.1 Data transfer: Memory to Register
在 MIPS 中，算術運算的指令是在 Register 中完成的，不是直接在 Memory 中。相關的指令包括 $lw, $sw 等，稱為 Data transfer instruction，目的是將資料從 Memory 移動到 Register 中，因此需要一個能夠處理記憶體的運算元

因為 Memory address 的大小也是 32-bits 所以無法使用指令來表示記憶體位址(太長)，因此可將 Address 視為一個一維陣列，以一個 pointer 來表示記憶體位址，再使用一個 offset (偏移量，以 byte 為單位)來表示相對距離，就可指出資料的記憶體位址。

![S__2179096](https://hackmd.io/_uploads/HksHZmwER.jpg)

舉例 : 8($t0) 表示記憶體位址 = $t0 所存的位址 + 8 bytes

:::info
因為 MIPS 架構中 Instruction 的長度是 32-bits，而記憶體位址的表示長度也是 32-bits，所以如果使用指令來表示記憶體位址，那其他的 OP code, Register 就會無法表示
:::

#### 2.2 Data transfer instruction
$$
\begin{align*}
&1 & &2 & &3 & &4\\
&lw & $&t0, & &12 & ($&s0)
\end{align*}
$$

* 各部名稱
    * Filed 1 : OP code
    * Field 2 : register that will receive **value** (存值，不是位址)
    * Field 3 : offset in bytes
    * Field 4 : register containing pointer to memory, called base register typically

舉例 : 

$$
lw \;\;\; $t0, 12($s0)
$$

where $s0 = 1000
* Take the pointer in $s0 then add 12 bytes to it
    * $s0 + 12 = 1012
* Load word(lw) from the memory pointed into register $t0
    * 將記憶體位址 1012 所存的內容存到暫存器 $t0

![S__2211842](https://hackmd.io/_uploads/r15jbelSR.jpg)

#### 2.3 Compilation with memory
舉例 : 

假設 $s1 表示變數 g , $s2 表示變數 h , $s3 表示 base，編譯程式碼 `g = h + A[8];` 有兩個動作

* 載入 `A[8]` 的值
    * 有 8 個元素，每個元素大小為 4 byte : $8 \times 4 = 32$ (offsets)
* 相加

因此，程式碼 `g = h + A[8];` 編譯完後的結果為
```mips
lw $t0 32($s3)   # load value to t0
add $s1 $s2 $t0  # add s2 and t0 then store into s1
```

#### 2.4 Data transfer: Register to memory

$$
\text{sw}\ \ \ $t0,\ 12($s0)
$$

與 lw 相同，sw 表示 store word，暫存器 \$t0 表示要存到記憶體的值，常數表示 offest，$s0 表示 base register

![S__2211843](https://hackmd.io/_uploads/H1ATilgrA.jpg)

#### 2.5 Compilation with memory
假設 \$s2 表示變數 h，\$s3 表示 base，編譯程式碼 `A[12] = h + A[8];` 有三個動作
* 載入 `A[8]` 的值
* 相加
* 儲存 `A[12]` 的值

```mips
lw  $t0, 32  $s3   # load A[8] to t0 where offset = 8*4 = 32
add $t0, $s2 $t0   # add to and s2 in t0
sw  $t0, 48  $s3   # store t0 into A[12]
```
#### 2.6 Register V.S. Memory
* 如果編譯過程中，變數的數量多於暫存器的數量？
    * Compiler 會將使用頻率高的變數放在 register
    * 使用頻率低的變數放在 Memory : spilling
* 為何不把所有的變數都放在記憶體中？
    * 因為記憶體的存取比較耗時

### 3. Immediate operands
對於常用的常數，或是會頻繁使用的常數，如果存在記憶體中等需要時再從記憶體載入，時間會太慢，因此會將一些常用到的常數直接寫到指令中，例如 : 

$$
\text{addi}\ \ \ $29,\ \ \ $29,\ \ \ 4
$$

OP code 後面的 i 表示其中一個 operand 存放在 instruction 之中，因此常數 4 是在指令中，不是存於 register

> **Design Principle 3** - Make the common case fast

因此，類此這樣的程式碼 : `f = g + 10;` (in C)經過編譯後會是

$$
\text{addi}\ \ \ $s0,\ \ \ $s1,\ \ \ 10
$$

另外，由於已經將常用寫到指令之中，所以就不會再有減法的 opcode 了，直接用負數表示減法即可

#### 3.1 The constant zero
由於常數 0 出現頻率極高，依此常數 0 直接寫入到硬體之中，單獨使用一個 register ($zero or $0)來表示 0，且 register $zero 有以下特色 : 
* 無法被覆寫(overwritten)
* 定義於硬體之中
* 通常用於資料的搬移

舉例 : 
(1) 下列指令中，第一個指令不會發生任何事情，因為 $0 不會被覆寫，加完後依舊是 0
(2) 將 $s1 的資料搬到 $t2 中
```mips
addi $0, $0, 5 # nothing happen since $0 can not be overwritten
add $t2 $s1 $0 # data movement
```
## Sec. 2.3 Sign and unsigned number (略)
## Sec. 2.4 Representing instructions
一個指令中有 32-bits :arrow_right: 分割一個 instruction word 變成多個 "fields"，每個 fields 會有各自所代表的意義

一般來說，在指令中會定義許多 "fields"。但在 MIPS 的架構中因為要簡單化，所以只定義了 3 種基本的指令型式
* **R-format** : for register
* **I-format** : for immediate, $\mathtt{lw}$ and $\mathtt{sw}$
* **J-format** : for jump

### 1.  R-format instruction
R-format 指令的定義如下 : 主要用於 $+$、$-$、$\times$、$/$ 之類的運算

| $\mathtt{OP code}$ | $\mathtt{rs}$ | $\mathtt{rt}$ | $\mathtt{rd}$ | $\mathtt{shamt}$ | $\mathtt{funct}$ |
| :-:                | :-:           | :-:           | :-:           | :-:              | :-:              |
| 6-bits             | 5-bits        | 5-bits        | 5-bits        | 5-bits           | 6-bits           |

* $\mathtt{Opcode}$ : 具體描述這個使令是哪一種指令，**但是 R-format 的 opcode 都是由 0 組成**，會進一步用 funct 做區分
* $\mathtt{funct}$  : 與 $\mathtt{opcode}$ 一起組成，表示指令用途
* $\mathtt{rs}$ : Source register
* $\mathtt{rt}$ : Target register
* $\mathtt{rd}$ : Destination registet，接收計算結果的暫存器
* $\mathtt{shamt}$ : 移動量(?)

:::info
Instruction 的 binary code 所表示的順序與 compile 後的順序不太一樣(見下面例子)
:::

$$
\text{add} \ \ \ $\text{t0}, \ \ $\text{s1}, \ \ $\text{s2}
$$
| $\mathtt{OP code}$ | $\mathtt{rs}$ | $\mathtt{rt}$ | $\mathtt{rd}$ | $\mathtt{shamt}$ | $\mathtt{funct}$ |
| :-:                | :-:           | :-:           | :-:           | :-:              | :-:              |
| 6-bits             | 5-bits        | 5-bits        | 5-bits        | 5-bits           | 6-bits           |
| Special            | $s1           | $s2           | $t0           | 0                | add              |
| 0                  | 17            | 18            | 8             | 0                | 32               |
| 000000             | 10001         | 10010         | 00100         | 00000            | 100000           |

指令型式 : $00000 | 10001 | 10010 | 00100 | 00000 | 100000_2 = 02323020_{16}$

### 2. I-format instruction
I-format 指令的定義如下 : 主要用於載入(load word)、儲存(store word)、常數運算(addi)之類的運算。與 R-format 相比，兩者有類似的結構，差別在於 I-format 是將 R-format 中後面的 $\mathtt{rd}$, $\mathtt{shamt}$ 和 $\mathtt{funct}$ 合併改成是 $\mathtt{immediate}$ (見 Design Principle 4)

:::danger
這邊有一段是解釋為什麼 R-format 後面會有一段 func 需要 field，而不是直接用 OPcode 表示即可，但聽不太懂(?)
:::

| $\mathtt{OP code}$ | $\mathtt{rs}$ | $\mathtt{rt}$ | $\mathtt{immediate}$ |
| :-:                | :-:           | :-:           | :-:                  |
| 6-bits             | 5-bits        | 5-bits        | 16-bits              |

* $\mathtt{Opcode}$ : 具體描述是哪一種 I-format 指令
* $\mathtt{rs}$ : Source register，I-format 中唯一的 operand
* $\mathtt{rt}$ : Target register，接收計算結果
* $\mathtt{immediate}$ : 一個常數
    * 以 16-bits 表示一個常數，但因為 register 中的資料是以 32-bits 為單位來儲存，所以這個 16-bits 的常數會根據最前面的 sign symbol (0 for positive and 1 for negative) 來擴增 bits (padding 0 or 1)，也就是做 sing-extended

> **Design Principle 4 -** Good design demands good compromises
> * Different formats complicate decoding, but allow 32-bits instruction uniformly
> * Keep formats as similar as possible

#### 2.1 Example (1)
$$
\begin{align}
&\text{addi} & &\text{dst}, & &\text{src}, & &\text{cons}\\
&\text{addi} & &$21       , & &\$22,       & &$-50
\end{align}
$$

| $\mathtt{OP code}$ | $\mathtt{rs}$ | $\mathtt{rt}$ | $\mathtt{immediate}$ |
| :-:                | :-:           | :-:           | :-:                  |
| 6-bits             | 5-bits        | 5-bits        | 16-bits              |
| 8                  | $22           | $21           | -50                  |
| 001000             | 10110         | 10101         | 1111111111001110     |

表示 : \$21 = \$22 + (-50)

#### 2.2 Example (2)
$$
\begin{align}
&\text{lw}   & &\text{dst}, & &\text{cons}, & &\text{src}\\
&\text{lw} & &$\text{t0}, & &1200,        & &$\text{t1}
\end{align}
$$

| $\mathtt{OP code}$ | $\mathtt{rs}$ | $\mathtt{rt}$ | $\mathtt{immediate}$ |
| :-:                | :-:           | :-:           | :-:                  |
| 6-bits             | 5-bits        | 5-bits        | 16-bits              |
| 35                 | $9            | $8            | 1200                 |
| 100011             | 01001         | 01000         | 0000010010110000     |

Address = 8 + 1200 = 1208 + X04B8
$t0 = X04B8

## Sec. 2.5 Operation
到目前為止，不論是 register 的個數，還是 instruction 的長度，或是 memory address 都是以 32-bit 為單位，所有指令都是以 32-bit 作為一個整體的 block 進行操作和運算，不過其實也可以將這 32-bits 的 block 視為 32 個單一的 bit 為單位進行運算。
> New perspective : View contents of rerister as **32 bits** rather than as **a 32-bit number**
> 
### 1. Logical

Instruction for bitwise manipulation
| Operation   | In C | In Java | In MIPS                        |
| :-:         | :-:  | :-:     | :-:                            |
| shift left  | <<   | <<      | $\mathtt{sll}$                 |
| shift right | <<   | <<      | $\mathtt{srl}$                 |
| bitwise AND | <<   | <<      | $\mathtt{and},\ \mathtt{andi}$ |
| bitwise OR  | <<   | <<      | $\mathtt{or},\ \mathtt{ori}$   |
| bitwise NOT | <<   | <<      | $\mathtt{nor}$                 |

:::info
bitwise NOT 中，因為 MIPS 的 R-foramt instruction 具有兩個輸入值(source register)，但 NOT 運算只要一個輸入就好，因此在 MIPS 的架構中是使用 $\mathtt{nor}$ 的運算(i.e., $\mathtt{nor}=\mathtt{not}+\mathtt{or}$)來保證具有兩個 source register
:::

#### 1.1 Shift operations
指令定義如下 : 

| $\mathtt{OP code}$ | $\mathtt{rs}$ | $\mathtt{rt}$ | $\mathtt{rd}$ | $\mathtt{shamt}$ | $\mathtt{funct}$ |
| :-:                | :-:           | :-:           | :-:           | :-:              | :-:    |
| 6-bits             | 5-bits        | 5-bits        | 5-bits        | 5-bits           | 6-bits |

* $\mathtt{shamt}$ : how many positions to shift
    * shift left logical
        * shift left and fill with 0 bits (左移，且空的位置補 0)
        * $\mathtt{sll}$ by $i$ bits multiplies by $2^i$ (左移的效果等價於 $\times 2$)
    * shift right logical
        * shift right and fill with 0 bits (右移，且空的位置補 0)
        * $\mathtt{srl}$ by $i$ bits divides by $2^i$ (右移的效果等價於 $\div 2$)

#####  Syntax
$$
\begin{align}
&1          & &2           & &3           & &4\\
s&ll & $&\text{t2}, & $&\text{s0}, & &4
\end{align}
$$

* Field 1 : OP code
* Field 2 : register that will receive value
* Field 3 : first operand(register)
* Field 4 : shift amount(constant)

MIPS 中有三種不同的 shift instructions
* $\mathtt{sll}$ (shift left logical) : 往左移動，且空的位置補 0
* $\mathtt{srl}$ (shift right logical) : 往右移動，且空的位置補 0
* $\mathtt{sra}$ (shift right arithmetic) : 往右移動，且空的位置補 sign symbol

##### Example
* shift right by 8-bits ($\mathtt{srl}$)
    * 原始 : **0001 0010 0011 0100 0101 0110** 0111 1000
    * 輸出 : ==0000 0000== **0001 0010 0011 0100 0101 0110** (padding 0)
* shift right arithmetic by 8-bits ($\mathtt{sra}$)
    * 原始 : **1001 0010 0011 0100 0101 0110** 0111 1000
    * 輸出 : ==1111 1111== **==1==001 0010 0011 0100 0101 0110** (padding sign symbol **1**)

在二元運算中，$\times 4$ 等價於左移 2 位元(Ex: $11_2 \times 100_2 = 1100_2$)，同理，$\times 2^n$ 等價於右移 n 位元。由此可以想見 bitwise shift 的運算算度會比一般乘法速度快上取多，所以在 C 語言中如果是進行 $\times 2^n$ 的運算，通常會編譯成 shift instruction。例如 : 
* C language : `a *= 8;`
* Compile to MIPS instruction : `sll $s0, $s0, 3`

#### 1.2 AND operation
AND 運算主要用來 **masked** 某些位元，目的在於保留某些 bits (與 1 作 AND)且其餘設為 0 (與 0 作 AND)

$$
\text{add}\ \ \ $t0,\ \ $t1,\ \ $t2
$$

$$
\begin{align}
$t2 : 0000\ 0000\ 0000\ 0000\ 00\textbf{00}\ \textbf{11}01\ 1100\ 0000\\
$t1 : 0000\ 0000\ 0000\ 0000\ 00\textbf{11}\ \textbf{11}00\ 0000\ 0000\\
$t0 : 0000\ 0000\ 0000\ 0000\ 00\textbf{00}\ \textbf{11}00\ 0000\ 0000\\
\end{align}
$$

#### 1.3 OR operation
OR 運算主要用來 **include** 某些位元，目的在於將某些 bits 設為 1 (與 1 作 OR)且其餘不變(與 0 作 OR)

$$
\text{or}\ \ \ $t0,\ \ $t1,\ \ $t2
$$

$$
\begin{align}
$t2 : 0000\ 0000\ 0000\ 0000\ 00\textbf{00}\ \textbf{11}01\ 1100\ 0000\\
$t1 : 0000\ 0000\ 0000\ 0000\ 00\textbf{11}\ \textbf{11}00\ 0000\ 0000\\
$t0 : 0000\ 0000\ 0000\ 0000\ 00\textbf{11}\ \textbf{11}00\ 0000\ 0000\\
\end{align}
$$

#### 1.4 NOT operations
NOT 運算主要用來 **invert** 某些位元，目的在於將 0 設為 1 且 1 設為 0 

$$
\text{nor}\ \ \ $t0,\ \ $t1,\ \ $\text{zero}
$$

$$
\begin{align}
$t1 : 0000\ 0000\ 0000\ 0000\ 00\textbf{11}\ \textbf{11}00\ 0000\ 0000\\
$t0 : 1111\ 1111\ 1111\ 1111\ 11\textbf{00}\ \textbf{00}11\ 1111\ 1111\\
\end{align}
$$

雖然只要做 NOT 運算即可，但因為 load-store 的指令需要有 2 個輸入，所以改為 NOT + OR 的運算，也就是先與 \$zero 作 OR 再將結果作 NOT 運算 ($\mathtt{NOT}$ a ==  $\mathtt{NOT}$ (a $\mathtt{OR}$ \$zero) == a $\mathtt{NOR}$ \$zero)

### 2. Decision making and branches
程式語言厲害的地方在於可以進行選擇性結構來做程式區段的跳躍，接下來的指令同樣會進行判斷與區段的跳躍。

#### 2.1 $\mathtt{beq}$: branch equal
語法結構如下 : 

$$
\begin{align}
 &1   &     &2     &      &3     & &4  \\
b&eq  & regi&ster1 &  regi&ster2 & &L1 \\
\end{align}
$$

* Field 1 : OP code
    * $\mathtt{beq}$ means branch if (register are) equal
    * In other word :arrow_right: `if (register1 == register2) goto L1`
    * 類似的 OP code 還有 $\mathtt{bne}$ (branch if not equal)
* Field 2 : First register
* Field 3 : Second register
* Field 4 : Label

以上這些指令($\mathtt{beq}$ 與 $\mathtt{bne}$) 被稱為 conditional branches，表示條件判斷正確的話執行(跳到)後面的敘述

:::info
仔細觀察這個 instruction 的結構會發現，他的結構與 I-format 的結構很像，都是一個 OPcode 和兩個輸入值，因次這類型的 conditional branches 其實是一種 I-format 的 instruction
:::

#### 2.2 J-format instruction
J-format 是一種 unconditional branch，不用任何的條件判斷就可以直接跳至指定的區段中，定義如下


$$
\begin{align}
&1 &   &2   \\
&j & la&bel \\
\end{align}
$$

Field 1 : OPcode
Field 2 : Label, destination

只要看到這個指令，直接跳到 label 的地方繼續執行，不用作任何判斷。此外這個指令也可以使用 $\mathtt{beq}$ 表示 : `beq $0, $0, label`

##### Example (1)
```flow
cond=>condition: i == j?
ed=>end: Exit
add=>operation: f = g + h
sub=>operation: f = g - h

cond(yes)->add->ed
cond(no)->sub->ed
```

C code
```c
if (i == j)
    f = g + h;
else
    f = g - h;
```
使用 $s0 到 $s4 表示變數 f 到 j，則編譯後的 MIPS 為 : 
```assembly=
       bne    $s3, $s4, Else   # branch (i != j)
       add    $s0, $s1, $s2    # f = g + h (True)
       j      Exit             # go to Exit
Else:  sub    $s0, $s1, $s2    # f = g - h (False)
Exit:
```
* 第 1 行表示 : 若 $s3 != $s4 (條件判斷正確)則跳到 Else 的地方繼續執行
* 第 2 行表示 : 若 $s3 == $s4 (條件判斷錯誤)則繼續往後執行
* 第 3 行表示 : 執行完加法後直接跳到 Exit 的地方結束
* 第 4 行表示 : 執行條件中的減法運算
* 第 5 行表示 : 結束

:::warning
第 4 行的 jump 指令一定要加，否則程式執行完 add 指令後會接續執行 sub 指令
:::

##### Example (2)
C code
```c
while (save[i] == k)
    i += 1;
```

假設變數 i 存放於 $s3，變數 k 存放於 $s5，且 memory address base 存放於 $s6

Compile to MIPS code
```assembly=
Loop:    sll  $t1, $s3, 2    # t1 = i * 4(bytes)
         add  $t1, $t1, $s6  # t1 = addr of save[i]
         lw   $t0, 0($t1)    # t0 = save[i]
         bne  $t0, $s5, Exit # if save[i] != k goto Exit
         addi $s3, $s3, 1    # i = i + 1
         j    Loop           # go to Loop
Exit: 
```
1. 必須先存取 Array 中的變數，且因為 Array 中的變數大小是以 4 bytes 為單位，因此使用 `ssl $t1, $s3, 2` 將 \$s3 的值右移兩個 bits $(\times 4)$ 得到 offset (存放在 \$t1)
2. 將 \$t1 中的 offset 加上 memory address base (\$s6) 得到當前 `save[i]` 的位址
3. 使用 `lw $t0, 0($t1)` 來存取 \$t1 中位址的數值。至此完成 `save[i]` 的讀取
4. 判斷 \$t0 (i.e., `save[i]`) 與 \$s5 (i.e., `k`) 的數值是否相同
    * 相同(`False`)則接續進行 5.
    * 不相同(`True`)則跳至 7.
5. 執行 `i += 1`
6. 變數 `i` 加完後直接跳值 `Loop` 標籤的位置繼續進行迴圈
7. 程式結束


#### 2.3 Inequality
到目前為止已經介紹了 equality 的狀況(`==` 或 `!=`)，但 programming language 中尚有包含不等式。在 MIPS 中會使用 `slt` 或 `slti` (set on less than)來表示不等式

$$
\begin{align}
     &1  & &2   & &3   & &4\\
    s&lt & &rd, & &rs, & &rt\\
\end{align}
$$

`slt rd, rs, rt` 表示 `if (rs < rt) rd = 1; else rd = 0;`

$$
\begin{align}
     &1   & &2   & &3   & &4\\
    s&lti & &rt, & &rs, & cons&tant\\
\end{align}
$$

`slti rt, rs, constant` 表示 `if (rs < constant) rt = 1; else rt = 0;`

從語法架構上可發現他與 R-format 類似，此外因為 MIPS 講求越簡單越好，因此在設計上只有 $<$ 的語法，其他的 $\le$, $>$, $\ge$ 等都可以用小於搭配其他等式結構來創建

##### Example
C code
```c
if (g < h)
    goto Less;
```
假設變數 `g: $s0`  且 `h: $s1`

```assembly=
         slt $t0, $s0, $s1   # if g < h then $t0 = 1, otherwise $t0 = 0
         bne $t0,   0, Less  # $t0 != 0 (i.e., g < h, True), goto Less
Less:
```

#### 2.4 Signed v.s. Unsigned
在做比較時，會牽扯到正負數的 symbol 問題，若是 signed number 則會使用 `slt`, `slti` 來比較；若是 unsigned number 則會使用 `sltu`, `sltiu` 比較。例如 : 
`$s0 = 1111 1111 1111 1111 1111 1111 1111 1111` 與
`$s1 = 0000 0000 0000 0000 0000 0000 0000 0001`
在 sign 與 unsigned 是兩種不同的意義，在 sign number 中 \$s0 表示 -1 而 \$s1 表示 1；在 unsigned number 中 \$s0 表示 +4,294,967,295 而 \$s1 表示 +1

## Sec. 2.6 Supporting procedures in hardware
類似 programming language 中的函數呼叫，講的是程式進行時主控權的轉換，牽涉到程式主控權轉換時需要進行的動作，例如變數的儲存、下一個指令的位址(i.e., program counter)等

### 1. Procedure calling
procedure calling 過程中的需求
* Caller (叫人的)
    * 將參數放到 register 之中 (place parameters in registers)
    * 轉移程式的控制權 (transfer control to procedure)
* Callee (被叫的)
    * 取得 procedure 的儲存空間 (acquire storage for procedure)
    * 執行 procedure 的運算 (perform procedure's operation)
    * 將結果放在 register 之中 (place result in register for caller)
    * 返回控制權 (return to place of call)

以下列這段 C code 為例
```c=
sum = leaf_example(a, b, c, d);

int leaf_example(int g, h, i ,j){
    ing f;
    
    f = (g + h) - (i + j);
    return f;
}
```
* Return address : `$ra`
    * 當程式轉移控制權時，需要紀錄轉移前進行到哪個指令，才能在之後回到該指令的下一步繼續進行
* Procedure address : `Label`
    * 要跳到哪一個 procedure
* Arguments : `$a0`, `$a1`, `$a2`, `$a3`
    * 用來儲存 arguments 的特殊 register
* Return value : `$v0`, `$v1`
    * 用來儲存返回值的特殊 register
* Local variables : `$s0`, `$s1`, ..., `$s7`
    * 用來儲存 procedure 中局部變數的特殊 register

關於 register 的使用習慣如下圖所示

![register-convention-mips](https://hackmd.io/_uploads/HyvMO9MdC.jpg)

`$8` 到 `$15` 主要是給 caller 使用，`$16` 到 `$23` 主要是給 callee 使用，`$4` 到 `$7` 是紀錄 arguments 的，`$31` 是給 return address 的 register

### 2. Instruction for procedure call
當程式需要執行 child procedure 時需要做兩的動作: (1) 紀錄當前執行到哪個 instruction 並在返還時回到 next instruction ，也就是 program conunter 的概念 (2) 紀錄完後跳到要執行的 child procedure。由此可衍生出 jump and link ($\mathtt{jal}$) 這個指令 : 

$$
\begin{align}
     &1  &            &2\\
    j&al & procudure&\_label
\end{align}
$$

* address of following instruction put in `$ra`
* jumps to target address (i.e., procedure_label)

執行完 child procedure 後，要回到 parent procedure，此時需要加 `$ra` 中所儲存的 return address 傳給 program counter，由此可衍生出 jump reguster ($\mathtt{jr}$) 這個指令 : 

$$
\begin{align}
     &1  & &2\\
     &jr & &\$ra
\end{align}
$$

以前段 C code 中的第一行 `sum = leaf_example(a, b, c, d);` 為例。假設變數 `a` 到 `d` 為 `$s0` 到 `$s3` 且 變數 `sum` 對應到 `$s4` ，則 compile to MIPS code 如下

```assembly=
add $a0, $0, $s0  # 將 $s0 的內容搬移到 $a0
add $a1, $0, $s1  # 將 $s1 的內容搬移到 $a1
add $a2, $0, $s2  # 將 $s2 的內容搬移到 $a2
add $a3, $0, $s3  # 將 $s3 的內容搬移到 $a3
jal leaf_example  # jump to leaf_example
add $s4, $0, $v0  # 將 $v0 的結果搬移到 $s4
```
### 3. Code for callee
前一小節主要聚焦在 caller 的指令，也就是以 parent procedure 為主角描述控制權轉移，這小節以 callee 為主。同樣以以下的 C code 為例
```c=
int lead_example(int g, h, i, j){
    int f;
    f = (g + h) - (i + j);
    return f;
}
```
* arguments `g` to `j` are saved in `$a0` to `$a3`
* local variable `f` is saved in `$s0`
* results of `g + h` and `i + j` are saved in `$t0` and `$t1`, respectively
* final result is saved in `$v0`

因為 `s0`, `$t0`, `$t1` 已經在 caller (或其他地方)  使用過了，所以 callee 使用前需要先將這些 register 中原有的值儲存起來，避免被刪除 :arrow_right: 以 stack 的方式存在 memory 中 (如下圖)。注意在 memory 中 stack 的堆疊是往下長的，所以 memory address 是負號，此外會使用另一個 register ($\mathtt{sp}$) 來儲存 stack pointer (stack 的最底層)

![S__2236443_0](https://hackmd.io/_uploads/r1Ea7ifd0.jpg)

上述的 C code 經過 compile 後的 MIPS code 如下
```assembly=
# 在 memory 中以 stack 形式儲存 register 的值
addi $sp, $sp, -12  # save base address to stack pointer
sw   $s0, 0($sp)    # $s0 = $sp + 0, stack in memory
sw   $t0, 4($sp)    # $t0 = $sp + 4, stack in memory
sw   $t1, 8($sp)    # $t1 = $sp + 8, stack in memory

# 執行 child procedure
add  $t0, $a0, $a1  # g + h
add  $t1, $a2, $a3  # i + j
sub  $s0, $t0, $t1  # f = (g + h) - (i + j)
add  $v0, $s0, $0   # move $s0 to $v0

# 從 memory 中載入原先 register 的值
lw   $s0, 0($sp)    # $s0 = $sp + 0, load value from memory
lw   $t0, 4($sp)    # $t0 = $sp + 4, load value from memory
lw   $t1, 8($sp)    # $t1 = $sp + 8, load value from memory
addi $sp, $sp, -12

# 返回控制權
jr   $ra
```

但上述方式會有一些缺點 : memory access 的過程中非常耗時。因此改善方式會將某些不重要的值不再放入 memory stack 之中，避免過多資料搬移而浪費時間。所以 register 在命名上才會有 `$t0` (temporary) 與 `$s0` 的差別。以上述的 MIPS code 為例， `$t0` 與 `$t1` 就不會再存入 memory stack 之中，詳見下方 MIPS code (與上述比較)
```assembly=
# 在 memory 中以 stack 形式儲存 register 的值
addi $sp, $sp, 4  # save base address to stack pointer
sw   $s0, 0($sp)    # $s0 = $sp + 0, stack in memory

# 執行 child procedure
add  $t0, $a0, $a1  # g + h
add  $t1, $a2, $a3  # i + j
sub  $s0, $t0, $t1  # f = (g + h) - (i + j)
add  $v0, $s0, $0   # move $s0 to $v0

# 從 memory 中載入原先 register 的值
lw   $s0, 0($sp)    # $s0 = $sp + 0, load value from memory
addi $sp, $sp, 4

# 返回控制權
jr   $ra
```

### 4. Non-leaf procedures
會呼叫其他 procedure 的 procedure 稱為 Ｎon-lead procedure，簡單來說就類似於巢狀結構或迴圈的概念，一層一層傳遞下去，同時每一層的 caller 都會被存在 stack 之中，也就是說每一層的 caller 的 return address 都要儲存

以此段 C code 為例
```c
int fact(int n){
    if (n < 1)
        return 1;
    else
        return n * fact(n-1);
}
```
假設 argument `n` 會被存在 `$a0` 且 result 存在 `$v0`
Compile 為 MIPS code 後如下
```assembly=
fact:
    # (Block: 1) 創建記憶體空間來儲存當前的 "回傳位址" 與 "參數"
    addi $sp, $sp, -8   # create storage of stack for 2 items
    sw   $ra, 0(sp)     # add($ra) = $sp + 0, save return address
    sw   $a0, 4(sp)     # add($a0) = $sp + 4, save argument

    # (Block: 2) 判斷 if (n < 1)
    slti $t0, $a0, 1    # set $t0 = 1 if n($a0) < 1, oeherwise $to = 0
    beq  $t0, $zero, L1 # $t0 == 0, goto L1

    # (Block: 3) True
    addi $v0, $zero, 1  # 回傳結果 1
    addi $sp, $sp, 8    # 釋放當前的記憶體空間
    $jr  $ra            # 跳到 $ra(前一層的回傳位址), 也就是 "前一層的下個指令"

L1: 
    # (Block: 4) False
    addi $a0, $a0, -1   # n = n - 1
    jal  fact           # recursive call
    
    # (Block: 5) 
    lw   $a0, 0($sp)    # 從記憶體載入當前參數
    lw   $ra, 4($sp)    # 從記憶體載入 "前一層的回傳位址"
    addi $sp, $sp, 8    # 釋放空間
    mul  $v0, $a0, $v0  # 後一層結果($v0)與當前參數($a0)相乘
    jr   $ra            # 跳到 $ra(前一層的回傳位址), 也就是 "前一層的下個指令"
    
```
細節流程可參考下圖，以 `fact(n=3)` 為例
![EE4CEBDA-63DB-4C6C-BEC9-D8607166723F](https://hackmd.io/_uploads/BJc6kgHuA.jpg)

![1F3DD9B1-0B72-4A11-BA91-8171CEE05662](https://hackmd.io/_uploads/Hyz0ygruR.jpg)

### 5. Memory layout
Procedure 執行的過程中，callee 會分配一些記憶體空間來儲存局部變數，而類似這樣由 callee 所產生的 procedure frame 稱為 activation record (下圖黃色區塊)

![S__2236451](https://hackmd.io/_uploads/HkmaXzSOA.jpg)

以整個記憶體空間的配置來看(如下圖)，大致可分為以下區域 : 
* Text : 主要存放程式碼 (program code)
* Static data : 不會被改變的全域變數，例如
    * static variables in C
    * constant array, strings
* Dynamic data : heap
    * malloc in C
    * new in Java
* Stack : 自動的儲存空間

![S__2236448](https://hackmd.io/_uploads/HkESVzSdC.jpg)

由上圖可知，前述在分配記憶體空間時是往下長，但並不是所有資料儲存時都是往下儲存的 stack 型式，也有往上的 dynamic data

## Sec. 2.7 Communicating with people
### 1. Challenge
字元(character) 與字串 (string) 等資料與整數型資料不同，無法直接由 binary code 組成，因此這類資料在搬運時不能直接做載入與儲存

### 2. Improvenment
分為兩種運算 bytes 與 halfword，可進行以下動作
* 資料的儲存(sign) : load bytes/halfword
    * `lb  rt, offset(rs)`
    * `lh  rt, offset(rs)`
    * sign extend to 32 bits in `rt`
* 資料儲存(unsign)
    * `lbu  rt, offset(rs)`
    * `lhu  rt, offset(rs)`
    * zero extend to 32 bits in `rt`
* 資料載入 : store bytes/halfword
    * `sb  rt, offset(rs)`
    * `sh  rt, offset(rs)`
    * sign extend to 32 bits in `rt`

如下圖所示，其中 F7 是 16 進位表示法，共 8-bits 也就是 1 byte

![S__2236450](https://hackmd.io/_uploads/r1dBkmrOC.jpg)

#### 2.1 Example
以下列 C code 為例，進行字元陣列的複製，此處需要注意兩件事
1. C code 中 Array 的引用方式是 call by address，所以直接傳入 address 就好，傳入的 address 會作為 memory address base 放到 register 之中
2. 無法直接從 array y 的 address 搬移資料到 array x 的 address 之中，須先放到 register 做間接的複製
```c
void strcpy (char x[], char y[]){
    int i = 0;
    while ((x[i] = y[i]) != '\0')
        i += 1;
}
```

假設 array x 與 array y 的 address base  分別存在 $a0, $a1 且變數 i 存在 $s0，則 Compile to MIPS code
```assembly=
# 創建空間儲存變數 i
       addi $sp, $sp, -4
       sw   $s0, 0($sp)
       
# initialize i
       add  $s0, $zero, $zero # i = 0
       
# load y[i]
L1:    add  $t1, $s0, $a1  # addr(y[i]): $t1 = $a1 + $s0
       lbu  $t2, 0($t1)    # $t2 = y[i]

# x[i] = y[i]
       add  $t3, $s0, $a0  # addr(x[i]): $t3 = $a0 + $s0
       sb   $t3, 0($t3)    # x[i] = y[i]
       
# x[i] != '\0'
       beq  $t2, $zero, L2 # if y[i] == 0, goto L2
       addi $s0, $s0, 1    # i = i + 1
       j    L1             # loop

# 刪除儲存空間
L2:    lw  $s0, 0($sp)     # restore saved $s0
       addo $sp, $sp, 4
       jr $ra
```

## Sec. 2.8 Addressing for 32-bit immediate and addresses

### 1. 32-bit constants
這個小節要解決的問題是，當要處理的數字或地址過大，無法用 16-bits 表示時有什麼解決辦法

使用 load upper immediate 指令 (`lui rt, constant`)，他是一種 I-format 型式的指令，主要做以下兩個動作 : 
* 複製 16-bits 的常數到 $rt 的左邊 16-bits
* 將 $rt 右邊 16-bits 設為 0

例如原始資料是
$$
\text{ori} : 0000 | 0000 | 0011 | 1101 | 0000 | 1001 | 0000 | 0000
$$

前 16-bits 表示整數 $61$，後 16-bits 表示整數 $2304$
經過 `lui $s0 61` 後可得

$$
\$\text{s0} : \textbf{0000} | \textbf{0000} | \textbf{0011} | \textbf{1101} | 0000 | 0000 | 0000 | 0000
$$

再使用 `ori $s0, $s0, 2304` 跟原始資料做 `or` 運算可得

$$
\begin{align}
&\$\text{s0} : &0000 | 0000 | 0011 | 1101 | 0000 | 0000 | 0000 | 0000 \\
&\text{ori} : &0000 | 0000 | 0011 | 1101 | 0000 | 1001 | 0000 | 0000\\
&\$\text{s0} : &0000 | 0000 | 0011 | 1101 | 0000 | 1001 | 0000 | 0000\\
\end{align}
$$

如此可將原始資料複製到 `$s0`

### 2. Branch addressing
前面在使用 branch 的相關指令時 (Ex: `beq`)，immediate 都是用 Label 表示跳轉位置，但實際上 Label 也是一個 memory address，此節要說的就是如何表示這個 branch 的 immediate

#### 2.1 Syntax
語法上使用 I-format 的型式 (可參考 4.2 I-format instruction)

| $\mathtt{opcode}$ | $\mathtt{rs}$ | $\mathtt{rt}$ | $\mathtt{immediate}$ |
| :-:               | :-:           | :-:           | :-:                  |
| 6-bits            | 5-bits        | 5-bits        | 16-bits              |

此處的 $\mathtt{OP code}$ 指定為 $\mathtt{beq}$ 或 $\mathtt{bne}$ 的兩種。而 $\mathtt{immediate}$ 的用意類似於 $\mathtt{lw}$ 中的 offset，只不過是以 PC-relative addressing 作為當前位址並向上加/下減位移量，也就是說 PC-relative addressing 其實類似 $\mathtt{lw}$ 中的 base memory address。

此外，因為 $\mathtt{immediate}$ 只有 16-bits 所以無法表示整個記憶體空間

#### 2.2 Improvement
將 $\mathtt{immediate}$ 指定為 word address。

前面的 I-format 指令中(Ex: $\mathtt{lw}$) 的 $\mathtt{immediate}$ 都是使用以 bytes 為主的 bytes address，但 $\mathtt{beq}$ 與 $\mathtt{bne}$ 都是以指令的跳轉為主，所以是使用以 instruction 的數量為單位的 word address。此外，因為每個 word (or instruction) 的大小為 4-bytes，所以如果要轉成該指令所在的記憶體位址，需要在 $\mathtt{immediate}$ 後面補 00，相當於 $\times 4$ bytes。如此一來就可以以 PC 為中心，跳轉 $\pm 2^{15}$ 的 word (或 $\pm 2^{17}$ bytes)

因為 PC 預設會指向當前執行的下一個指令，所以實際上應該是從 PC+4 開始算起 : 
* If branch not taken : PC = Pc + 4
* If branch taken : PC = (pc + 4) + (immediate \* 4)

:::info
PC (program counter) 的單位是 byte address
:::

##### Example
MIPS code : 
```assembly=
Loop:    beq  $9, $0, End  # PC (目前執行指令)
         add  $8, $8, $10  # PC + 4 (當前 PC 指向)
         addi $9, $9, -1
         j    Loop
End:
```
已知 $\mathtt{beq}$ 的 OPcode = 4，$\mathtt{rs}$ = \$9，$\mathtt{rt}$ = \$0，因為進行到 $\mathtt{beq}$ 指令時，當前的 PC + 4 指向 $\mathtt{add}$ 指令，再經過 3 個指令後可到 End 標籤，因此 `beq  $9, $0, End` 指令中的 immediate (或 End 標籤) 應該 = 3 = 0000000000000011

### 3. Jump addressing
理論上來說，$\mathtt{j}$ 指令 (i.e., jump) 可以跳到記憶體空間的任何地方，但實際上因為 OPcode 佔了 6-bits 的關係，而一個 word (或 instruction) 又只有 32-bits，所以只剩下 $32-6-28$ bits 能夠表示記憶體位址。又因為記憶體位址的長度也是 32-bits 所以在計算上也都是以 32-bits 為主，因此這 28-bits 必須補足剩下的 6-bits

#### 3.1 Syntax
| $\mathtt{opcode}$ | $\mathtt{target\ address}$ |
| :-:               | :-:                        |
| 6-bits            | 26-bits                    |

:::warning
Question - 如何補足剩下的 6-bits ?
:::

#### 3.2 Improvement
1. 因為同樣是指令的跳轉，所以此處的 $\mathtt{target\ address}$ 同樣是以 word address 為主，又因為每個 word (或 instruction) 的大小為 4-bytes，因此直接在 $\mathtt{target\ address}$ 後面補上 00 表示 $\times 4$ bytes，如此就變成 26 + 2 = 28-bits
2. 至於剩下的 4-bits 可以直接複製 PC 的前面 4 個 bits 補在 $\mathtt{target\ address}$ 的前面。
    * 原因在於，1 個 bit 可以將記憶體空間切成 2 塊，2 個 bits 可以切成 4 塊
    * 而每個 program 中的指令通常都是在同一區塊中，因此 PC 的前 4-bits 通常是相同的
    * 但前提是 program 必須要在相同的 block 中 (見下圖)
3. 如此可得到 28 + 4 = 32-bits

![S__2244611](https://hackmd.io/_uploads/B1X2-CIuR.jpg)

結果表示如下 : 
* New PC = PC[28:31] \|| $\mathtt{target\ address}$ \|| 00
* New PC = 4-bits \|| 26-bits \|| 2-bits

總結來說
* 短距離的指令跳轉 : 使用 relative PC address (Ex: $\mathtt{beq}$)
* 中距離的指令跳轉 : 使用有限制範圍的 absolute address (Ex: $\mathtt{jal}$)
* 長距離的指令跳轉 : 直接使用 $ra (return address)，因為 register 可以儲存 32-bits 的資料

##### Example
![S__2244613](https://hackmd.io/_uploads/ByV8QCU_R.jpg)

> Quesiton : 
> 1. 黃色螢光筆處的 Exit 標籤所對應的 $\mathtt{immediate}$ 為何是 2
> 2. 紅色螢光筆處的 Loop 標籤所對應的 $\mathtt{immediate}$ 為何是 20000

以上圖來說，當執行到 $\mathtt{bne}$ 時，PC + 4 指向 $\mathtt{addi}$ 指令，再過 2 個 instruction 就可以到 Exit，所以 Exit 標籤所代表的 immediate = 2

接著，因為 Loop 標籤所對應到的 address 為 $80000_{10}$ ，所以 Loop 標籤所對應到的 $\mathtt{immediate}$ 應該是 $80000 / 4$ bytes $= 20000$

::: info
如果 $\mathtt{beq}$ 或 $\mathtt{bne}$ 指令所要跳轉的位址真的太遠，可以先做一個假的 instruction 到 $\mathtt{jump}$，再利用 $\mathtt{jump}$ 跳遠一點
:::

### 4. MIPS instruction summary
* R-format
    1. Register addressing (Ex : $\mathtt{add}$)
* I-format
    2. Base addressing (Ex : $\mathtt{lw}$)
    3. immediate addressing (Ex : $\mathtt{addi}$)
    4. PC-relative addressing (Ex : $\mathtt{beq}$)
* J-format
    5. pseudodirect addressing (Ex : $\mathtt{jal}$)

![4506614C-7ED9-44EA-934A-3F0E8DA1C2E7](https://hackmd.io/_uploads/ryO0nRLd0.jpg)

![6F3374C3-554C-4BBC-A49D-B461A85D0AAC](https://hackmd.io/_uploads/B1k16AIdA.jpg)

## Sec. 2.9 補充: Translating and starting program
Assembler pseudo instruction 的概念類似 programming language 中的 pseudo code。並不是真正的 instruction。當使用 pseudo instruction 的時候，只要創建一個 instruction 就必須有 Hardware 與之對應。例如以下的 pseudo instruction

```assembler=
move  $t0, $t1
blt   $t0, $t1, L
```
實際上並沒有 `move` 與 `blt` 這兩個 instruction，而真正所對應到的 assemblt code 如下
```assembly=
add   $t0, $zero, $t1
slt   $at, $t0, $t1
bne   $at, $zero, L
```
`move` 對應到 `add` 而 `blt` 對應到 `slt` 和 `bne`。此外會發現它寫成真正的 assembly code 時，實際上會需要 3 個 register。多餘的 register 由 `$at` (或 `$1`) 提供，他是一個專門提供給 assembler 使用的 register，可參考上面的 convention register 圖片

## Sec. 2.10 Sort example
### 1. C sort example (暫略)
### 2. Optimization
一個 complier 的最佳化與評估方式大致上可以分以下幾點
* Instruction count and CPI are not good performance indicators in isolation
* Compiler optimizations are sensitive to the algorithm
* Nothing cna fix a dumb algorithm (先寫出好的演算法再做最佳化)

## Sec. 2.11 Arrays v.s. pointers
### 1. Difference
Array 與 pointer 在 assembly code 的實作上可以使用 index 或 pointer 兩種方式，兩者差異如下

* Array index
    * index 必須乘上元素大小 (Ex: int 大小為 4 bytes)
    * 上述大小需再加上 array base memory address
* Pointer
    * 直接對應到 array 的記憶體位置
    * 避免複雜的 index
### 2. Example: clearing and array
以下圖為例，左邊是以 array 的 index 做，右邊是直接以 array 的 address 做，兩者功能相同但做法不同。比較後可發現，右邊的 address 版本並沒有用到 invreament by i 且有沒有不斷地 $\times 4$

![S__2244614](https://hackmd.io/_uploads/rkhX6DwOC.jpg)

因此，一個好的 compiler 必須做到: (1) strength reduced，也就是將 $\times 4$ 改為 shift。(2) induciton variable elimination，也就是將 increament by i 移到迴圈外

## Sec. 2.12 ARM and X86 instruction sets
### 1. Instruction
目前主流的三種 instruction set 分別是用於手機與嵌入式系統的 ARM、用於個人 PC 的 X86 與 MIPS。

雖然 Intel 的 X86 最早發展，但因為用途分佈最多，以及程式相容性的問題，所以目前還是存在。不過因為內容隨時代不斷擴展，所以比較複雜，

![S__2244617](https://hackmd.io/_uploads/SJUSAPD_C.jpg)

### 2. ARM v.s. MIPS
兩者功能與結構類似，且都是屬於 RISC isa (X86 屬於 SISC)，但 ARM 用途最廣。兩主比較如下 : 

![S__2244616](https://hackmd.io/_uploads/BJ_81dPOA.jpg)

其中最大的差異在 compare 與 branch 這兩個方式。在 ARM 的 instruction 中，最前方有 4-bits 的 conditional code 來決定該 instruction 是否要執行，但在 MIPS 中做 condition 時需要使用兩個指令才能做條件判斷: (1) $\mathtt{slt}$: 比對結果 (2) $\mathtt{beq}$/$\mathtt{bne}$: 測試結果 + 跳轉

### 3. Fallacies (常見錯誤迷思)
* Powerful instruction $\rightarrow$ higher performance (X)
    * 越複雜 instruction 越難實作
    * 指令通常越好越好
* Use assembly code for high performance (X)
    * assembly language 非常繁瑣且行數更多
    * 越多的行數會導致高更多錯誤率以及更低的生產力

### 4. Pitfalls (易錯觀念)
instruction (或 word) 雖然是連續的，但不代表他在記憶體空間上的位址也是連續的，因為一個 word 的大小是 4 bytes，所以在跳轉指令或是使用記憶體位址表示時，必須 +4 bytes 而不是 +1 byte

### 5. Concluding remarks
總結 ISA 的設計原則
> Design principles - 
> 1. Simplicity favors regularity (Ex: 結構固定，OPcode 都是 6-bits)
> 2. Smaller is faster (Ex: 資料大小是 32-bits 不是 64-bits)
> 3. Make the common case fast (Ex: constant 常用，所以直接設一個 immediate format)
> 4. Good design demands good compromises (Ex: 不同需求有不同設計)
> 














