# Ch2:Instructions: Language of the Computer :::warning 本筆記只有抄到 2-12,因為後面的出題機率過低就不寫了 之後應該會補上 ::: 本章主要在讓讀者理解電腦真正能「聽懂」的是什麼語言——也就是機器指令(machine instructions),本章將從高階語言一路深入到底層的指令集結構。 ## 2-1 Instruction - **Instruction set(指令集)**: - 不同電腦有不同的指令集(但大部分相同) - 早期電腦使用**較簡單的指令集** ### MIPS 指令集 :::warning 本書所有指令都參考 MIPS ::: - 是 **RISC** 結構的代表 - 被廣泛運用在**嵌入式系統** - 是許多現代指令集的經典 ## 2-2 Operations of the Computer Hardware ![IMG_7127_11zon](https://hackmd.io/_uploads/SyYt5lmA1e.jpg) ![IMG_7128_11zon](https://hackmd.io/_uploads/BkKY5gQ01x.jpg) ## 2-3 Operands of the Computer Hardware ### Regigster Operands - 用於**算數操作** - MIPS 共有 32 * 32-bit 的 register file - 用於**高頻率存取**資料 - 編號從 0 ~ 31 - 32-bit 的資料稱為一個 **word** - Assembler name - **Temporary Value**:`$t0` 到 `$t9` - **Static variables**:`$s0` 到 `$s7` - `$zero`:MIPS register 中的預留常數,不可被 overwrite ### Memory Operands - **Main memory** 用來儲存**複合資料** - Array, Structure, Dynamic Data - 每一個 memory address 對應到一個 bytes - **MIPS** 是 **Big Endian** 的 - **Big Endian**:MSB first - **Little Endian**:LSB first ![image](https://hackmd.io/_uploads/r1rLBZ7CJx.png) - 範例: - h in `$s2`, A in `$s3` - C code ```c= A[12] = h + A[8]; ``` - MIPS ```mips= lw $t0, 32($s3) add $t0, $s2, $t0 sw $t0, 48($s3) ``` ### Immediate Operands :::warning 注意:Immediate Operands 不可以進行減法 ::: - 在指令中的**常數資料** - 不可被用於減法,可以透過**加負數**來進行減法 ```mips= addi $s2, $s1, -1 ``` ## 2-4 Unsigned and Signed ### Unsigned - 無號數 -> 可以直接轉換 - e.g. $0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 0000\ 1011_2 = 11_{10}$ - 範圍:$0$ ~ $2^n-1$ ### 2's-Complement - 有號數 - 轉換方式: - 範例:-14(8-bit) - **先把無號數轉成 2 進位**:$14 = 0000\ 1110_2$ - **0 -> 1, 1 -> 0**: $0000\ 1110_2 = 1111\ 0001_2$ - **加一**: $1111\ 0010_2$ - 範圍:$-2^{n-1}$ ~ $2^{n-1}-1$ - **Sign Extension**: - 當我們要用更大容量的資料型態儲存我們的數字時,就必須做 sign extension - **正數補 0,負數補 1** ![image](https://hackmd.io/_uploads/H1qkM-E01e.png) ### Sign-magnitude - 有號數,把 sign 和 magnitude 分開表示 - 轉換方式: - 範例:-14(8-bit) - **Sign** = 1(Negative) - **Magnitude** = $14 = 000\ 1110_2$ - **Sign + Magnitude**:$-14 = 1000\ 1110_2$ - 範圍:$-2^{n-1}+1$ ~ $2^{n-1}-1$ ## 2-5 Representing Instructions in the Computer - 所有 MIPS 指令大小都是 32-bits ### R-format ![image](https://hackmd.io/_uploads/SJ96H-4Akl.png) - `op`: operation code **(opcode)** - ==**R-format 一律放 0**== - `rs`: first source register number - `rt`: second source register number - `rd`: **destination** source register number - `shamt`: shift amount - `funct`: function code (extend opcode) - ==R-format 放 opcode== - 範例: ![image](https://hackmd.io/_uploads/r1luIW4RJx.png) ### I-format ![image](https://hackmd.io/_uploads/SkhFLb4A1g.png) - `rt`: **destination or source** register number ### J-format ![image](https://hackmd.io/_uploads/Bko46rVC1l.png) ## 2-6 Logical Operation ![image](https://hackmd.io/_uploads/Hkirsb40ye.png) - **sll**:左移 - **srl**:右移 ## 2-7 Conditional Operations ### 條件判斷 - 條件判斷:當條件符合時跳到指定的 instruction - 若不符合:繼續往下執行 - **beq**:if ```mips= beq rs, rt, L1 ``` - if **(rs == rt)** branch to instruction labeled L1 - **bne**:if not ```mips= bne rs, rt, L1 ``` - if **(rs != rt)** branch to instruction labeled L1 - **slt**: - MIPS: ```mips= slt rd, rs, rt ``` - C code: ```c= if (rs < rt) rd = 1; else rd = 0; ``` - **sle**: - MIPS: ```mips= slti rt, rs, constant ``` - C code: ```c= if (rs < constant) rt = 1; else rt = 0; ``` - **j**:jump - 直接跳到指定的 instruction ### Loop statement - **C code**: ```c= while (save[i] == k) i += 1; ``` - **MIPS**: - i in `$s3`, k in `$s5`, address of save in `$s6` ```mips= Loop: sll $t1, $s3, 2 add $t1, $t1, $s6 lw $t0, 0($t1) bne $t0, $s5, Exit addi $s3, $s3, 1 j Loop Exit:... ``` ### Basic block - **定義**:Basic block 是一連串代碼,包含以下兩個特性: - **沒有內部分支(embedded branches)**,除了結尾(例如跳躍或條件分支)。 - 沒有分支目標(branch targets),除了在區塊開頭。 - Compiler 會辨別程式裡的 Basic block 進行優化 ![image](https://hackmd.io/_uploads/SyH_ZMVCJe.png) ### Unsigned and Sign Comparison - **Signed**:slt, slti - **Unsigned**:sltu,sltui ![image](https://hackmd.io/_uploads/HJhJSzE0yx.png) ## 2-8 Supporting Procedures in Computer Hardware ### Register 使用 - `$a0` ~ `$a3`: 參數暫存器(arguments) - 對應 register 4 ~ 7。 - 用來傳遞函式的參數。 - `$v0`, `$v1`: 回傳值暫存器(result values) - 對應 register 2 和 3。 - 用來存放函式的回傳值。 - `$t0` ~ `$t9`: 暫時暫存器(temporary values) - 用來儲存**臨時計算**結果。 - 可以被呼叫者**覆寫**(callee 可以自由使用,不用保留)。 - `$s0` ~ `$s7`: 保存暫存器(saved variables) - 用來儲存**需要保留的資料**。 - **必須由被呼叫者保存與恢復**(callee 必須在進入與離開時處理)。 - `$gp`: global pointer - Register 28。 - 指向靜態資料的全域指標。 - `$sp`: stack pointer - Register 29。 - 指向目前 stack 的頂端,管理函式呼叫時的堆疊空間。 - `$fp`: frame pointer - Register 30。 - 協助存取目前函式的參數與區域變數。 - `$ra`: return address - Register 31。 - 儲存函式呼叫的返回位址(通常由 `jal` 指令自動寫入)。 ### Procedure call - **jal**:jump and link - 語法: ```mips= jal ProcedureLabel ``` - 功能: - 把下一條指令的 address 存到 `$ra` 裡,儲存跳回來的地方 - 跳到 `ProcedureLabel` 所代表的副程式位置執行。 - 執行完副程式後會自己跳回來 - **jr**:Jump register - 語法: ```mips= jr $ra ``` - 功能: - 把 `$ra` 的內容複製到 PC(program counter) - 放在**副程式**裡面,這樣就會跳回主程式 - 比較: | 指令 | 全名 | 功能描述 | 是否儲存 return address | 用途範例 | |---------|------|----|-------|-----------| | `j` | jump | 無條件跳轉到指定的標籤(Address) | 否 | 跳過一段程式碼 | | `jal` | jump and link | 跳轉到副程式並儲存返回 Address 至 `$ra` | 是 | 呼叫副程式(function call) | | `jr` | jump register | 跳轉到暫存器指定的 Address(通常是 `$ra`) | 否 | 副程式返回、switch-case | ### Local Data on the Stack :::warning 注意,Stack 是倒過來長的 ::: - Local data 會被 callee 分配的 - **Procedure frame**: - 用來存放副程式執行所需的資料 - MIPS 會使用 `$fp`, `$sp`,來標記 procedure frame 的位置 - 程式可以存取 procedure frame 內部的資料 ![image](https://hackmd.io/_uploads/rywst7EAyl.png) - **以下資料需要用 stack 存**: - `$s0` ~ `$s7` - `$ra` - 第五個以上的 argument(`$a0` ~ `$a3` 不夠存) ### Leaf procedure - **定義**:不呼叫任何其他函式的函式 - Example: - C code: ```c= int leaf_example (int g, h, i, j){ int f; f = (g + h) - (i + j); return f; } ``` - MIPS code: - Arguments g, …, j in `$a0`, …, `$a3` - f in `$s0` (hence, need to save `$s0` on stack) - result in `$v0` ```mips= leaf_example: # Save $s0 on stack addi $sp, $sp, -4 sw $s0, 0($sp) # Body add $t0, $a0, $a1 add $t1, $a2, $a3 sub $s0, $t0, $t1 # Result add $v0, $s0, $zero # Restore $s0 lw $s0, 0($sp) addi $sp, $sp, 4 # return jr $ra ``` - `sw`:把 register 的資料 store 到 memory 中 - `lw`:把 memory 的資料 load 到 register 中 ### Non Leaf Procedure - **定義**:有呼叫其他函式的函式 - Example: - C code: ```c= int fact (int n){ if (n < 1) return 1; else return n * fact(n - 1); } ``` - MIPS: - Argument n in `$a0` - Result in `$v0` ```mips= fact: addi $sp, $sp, -8 sw $ra, 4($sp) sw $a0, 0($sp) # test for n < 1 slti $t0, $a0, 1 beq $t0, $zero, L1 addi $v0, $zero, 1 addi $sp, $sp, 8 jr $ra L1: # recursive call jar fact lw $a0, 0($sp) lw $ra, 4($sp) addi $sp, $sp, 8 mul $v0, $a0, $v0 jr $ra ``` - 呼叫在其他函式後,register 中的 `$a0`, `$ra` 會被改變,需要用 **lw** 來還原 ### Memory layout - **Text**:code - **Static data**:Global variables - **Dynamic data**:儲存於 heap,屬於動態分配的記憶體 - e.g. `malloc` - **Stack**:自動存取 ![image](https://hackmd.io/_uploads/rkSGT7ERyx.png) ## 2-9 Communicating with People - **ASCII**:128 characters - **Unicode**:256 characters ![image](https://hackmd.io/_uploads/BymBbS4Ckx.png) ## 2-10 MIPS Addressing for 32-bit Immediates and Addresses ### Byte/Halfword Operations - 主要處理較小單位的應用 - byte = 8 bit - halfword = 16 bit - **lb**:讀取 **8 bits** 擴充**有號數**到 32 bits ```mips lb rt, offset(rs) ``` - **lh**:讀取 **16 bits** 擴充**有號數**到 32 bits ```mips lh rt, offset(rs) ``` - **lbu**:讀取 **8 bits** 擴充**無號數**到 32 bits ```mips lbu rt, offset(rs) ``` - **lhu**:讀取 **16 bits** 擴充**無號數**到 32 bits ```mips lhu rt, offset(rs) ``` - **sb**:只儲存**最低 byte** ```mips sb rt, offset(rs) ``` - **sb**:只儲存**最低 byte** ```mips sb rt, offset(rs) ``` - **sh**:只儲存**最低 halfword** ```mips sh rt, offset(rs) ``` ### 32-bit Constant - 大部分的常數都只有 16 bit - 我們可以透過下方方式來組合出一個 32 bit 常數 ```mips= lui $s0 upper_16_bits ori $s0 $s0 lower_16_bits ``` - **lui**:把 16 bit 存到高 16 位 - **ori**:利用 **or** 運算儲存低 16 位 ![image](https://hackmd.io/_uploads/rkCcjHV0Jx.png) ### Branch Addressing :::warning **Branch Addressing** 用於目標 address 在 PC 附近的情況(移動範圍:16 bit) ::: - 大部分的目標都在鄰近的 branch 上 - 可以用前進、後退的方式查找 ![image](https://hackmd.io/_uploads/H1xthBE0yl.png) - **PC-relative addressing**: - 目標 address = PC(現在的 address) + offset $\times$ 4 ### Jump Addressing :::warning **Jump Addressing** 用於目標 address 離 PC 很遠的情況(移動範圍:26 bit) ::: - Jump(j, jal)指令可以允許程式移動到 **Text segment** 中的任何地方 - **J format**: ![image](https://hackmd.io/_uploads/Bko46rVC1l.png) - 目標 address = PC31...28 : (address $\times$ 4) ### Branch Far Away 我們可以使用 **j** 指令來取代 branch 太遠的情形 - **改善前**: ```mips= beq $s0, $s1, L1 # 16 bits ``` - L1 太遠,我們抓不到 - **改善後**: ```mips= bne $s0, $s1, L2 # 16 bits j L1 # 26 bits L2: ... ``` - 使用 **j** 來存取 L1 ### MIPS 存址的五大模式 ![image](https://hackmd.io/_uploads/B1U_X8V01l.png) ## 2-12 Translating and Starting a Program ![image](https://hackmd.io/_uploads/r1ewWU4Ckx.png)