###### tags: `組合語言`
# 組合語言共筆 9 : Load / Store Instructions
## (1) - Load / Store 介紹
Load / Store 是操作 Memory 和 Register,來進行資料的存取與載入
- Load : 從 Memory 載入資料到 Register
- Store : 將資料從 Register 儲存到 Memory

:::info
- **指令種類**
- **Single Register Load/Store Instruction** :
=> 單個 Register 的操作,只能操作最多 32 bit 的資料 ( 16, 8 bit )
=> 指令 : <font color=blue>LDR / STR</font>
- **Multiple Register Load/Store Instruction** :
=> 使用多個 Register 操作,可以進行一個區塊的操作
=> 指令 : <font color=blue>LDMFB / STMFB</font>
- **Single Register Swap Instuction** :
=> 使用一道指令就可將一個 Register 的資料和 Memory 中的"交換"
:::
<br>
## (2) - Single Register Load/Store
### - Load/Store 的指令按照以下規律來作設計
:::info
`<Opcode>{<cond><size>} Rd, <address>`
- <Opcode> : 主指令名稱,代表該指令主要的意義
- <cond> : 此指令加上 Condition ( 前一小節的 Condition Execution )
- <size> : Load / Store 資料的大小,8, 16, 32 bit
- Rd : Register
- < address > : 記憶體位置(地址)
ex : `LDREQB` => `<LDR> <EQ> <B>`
:::
### - 各種 Load/Store 指令
```
LDR / STR : 對一個 word ( 32 bit ) 作操作
LDRB / STRB : 對一個 Byte ( 8 bit ) 作操作,未達到 32 bit 的 bit 會補 0
LDRH / STRH : 對 half Word ( 16 bit ) 作操作,未達到 32 bit 的 bit 會補 0
LDRSB / LDRSB
LDRSH / LDRSH : 主要是加上 S,表示 sign extended to 32 bit,
當[符號位元]=1 補 1,[符號位元]=0 補 0
( 符號位元為最左邊的數字 )
Ex. 1000 ( 16 bit ) 符號位元 = 1 => 11111000 ( 32 bit )
LDREQB : 加上 Condition <EQ>
```
### - 用法舉例
:::warning
- r1 : 指 R1 暫存器
- [r1] : 指 R1 暫存器存的資料
```
#### Load 用法 ####
ldr r5, [r2] @ 意義是 r2 中存了某個 Memory address(位址)
@ 將此 Memory address 中的資料取出
@ 載入存到 r5 中
ldrb r1, [r9, #4] @ 將 r9 中存的 address + 4
@ 並取出 ( r9 + 4 ) 的 Memory 資料
@ ex : 原 address=0x0A00 => 加 4 後 => 0x0A04
@ 載入存到 r1
ldrb r1, [r9, #4]! @ 同理以上
@ 但最後還會將 ( r9 + 4 ) 的新 address 存到 r9 中
@ 覆蓋原 r9 存的 address 資料
```
```
#### Store 用法 ####
與 Load 用法類似
str r5, [r2] @ 將暫存在 r5 的資料取出
@ 並將資料存到 r2 中存的 Memory address 指向的 Memory 位置
str r5, [r2, #4] @ 同理以上
@ 只是儲存的 Memory 位置會是原來 r2 中存的 address 加 4
str r5, [r2, #4]! @ 同理以上
@ 並將 ( r2 + 4 ) 的新 address 存入 r2
```
:::
<br>
## (3) - Load/Store [定址指令]用法整理
這裡是指對使用方式的整理,不會特別寫出 Load/Store 的指令
只列出指令後面的 < address > 的不同操作方式
### 1. 普通情況
:::info
```
[Rn] // 普通呼叫 Rn == [Rn, #0]
[Rn, #<offset_12>] // 呼叫 Rn 並將其儲存的 address 資訊加減 offset
[Rn, Rm] // 將 Rm 中存的資訊當作是 offset 與 Rn address 加減
[Rn, Rm, <shift> #<shift_imm>] // 可以對 Rm 存的 offset 做 Scale
// - <shift> : 這裡的 shift 可以對 offset 進行 Scale 取代乘法運算,會標示移動方向
// - <shift_imm> : Scale 移動的量
//
// ex : LSL#1 // 向左移一位
// 0101 << 1 = 1010 // 向左移一位,數值會從 5 -> 10
// 0100 >> 1 = 0010 // 向右移一位,數值從 4 -> 2
//
```
:::
<br>
### 2. 加入驚嘆號
:::info
加入驚嘆號主要是指會將加上 offset 後的 memory address 存回 Rn
其餘功能則是都相同
```
[Rn, #<offset_12>]!
[Rn, Rm]!
[Rn, Rm, <shift> #<shift_imm>]!
```
:::
### 3. 順序改變
:::info
這邊主要會將操作的順序做一點改變,指令上會是將 offset 獨立出來寫
順序會變成 :
1. 使用原本就存在 Rn 中的 address 做操作(load/store)
2. 之後將 address 加上 offset 儲存到 Rn
```
[Rn], #<offset_12>
[Rn], Rm
[Rn], Rm, <shift> #<shift_imm>
```
:::
<br>
## (4) - Pointers
### - Pointer 定義
Pointer 的概念類似 C++ 的指標 ( 都稱 pointer )
可以像是變數的方式來儲存某個記憶體位址,方便取用該位置資料
設定 Pointer 的方式其實就是之前在 [Assembly Syntax 組語句法分類](/0GTXTUZMT-OiYX6YIq4wrg) 中說的 Label
```assembly=
/*設定 Pointer [msg] 儲存 "Hello world" 的記憶體位置*/
msg: .asciz "Hello world"
...
```
<br>
### - 使用 Pointer
使用 `=Pointer` 就可以存取到該 pointer 中存的記憶體位置的資料
```assembly=
/*將 Pointer 存放的位址中的資訊 ("Hello world") Load 到 r4 中*/
ldr r4, =msg
```
<br>
## (5) - Loading Constants 常數
### - 立即值 Immediate Constants
立即值是可以立即取用的 Constant ex : `#4`, 雖然 Register 儲存空間有 32 bit
但立即值的 data 只有 12 bit,其他空間會儲存其他資訊 ( 以後會講 )
<font color=blue>前面說的位址的 offset 就是立即值,所以才會稱 #<offset_12> </font>
:::info
12 bit 的空間又存了兩種資訊
- 8 bit : 儲存 constant,如是 unsign 範圍為 [0~255],如是 sign 範圍為 [-127~127]
- 4 bit : 剩下 4 bit 儲存了 "旋轉量" 以後還會再提到
:::
<br>
### - MOV 簡介 & Immediate Constants 存取
`mov` 類似 `ldr` 但他只允許在 Register 間做資料的移動,或是讀取 Immediate Constants
```assembly=
mov r1, r2 @將 r2 中資料轉移到 r1
mov r0, #0x40 @將立即值 #0x40 存入 r0
```
<br>
### - Pseudo-Instruction 與 Immediate Constants 存取
可以利用 "**Pseudo-Instruction**" 將 Immediate Constants 存取成類似變數形式
並且會在外生成一個 Constant (literal) pool 來存放 constant
:::warning
`LDR Rd, =const`
ex :
```assembly=
MOV r0,=&FF ; MOV r0,#0xFF
LDR r0,=&55555555 ; MOV r0,[PC,#Imm10]
```
:::
<br>
## (6) - Multiple Registers Load / Store
### - **介紹語法**
Multiple Register 是使用多個 Register 來 Load / Store 資料
其中又分為兩種操作方式
- **Block Copy** : 利用某 Register 存的記憶體位址,來 load/store 連續的記憶體資料
- **Stack Type** : 利用堆疊暫存器 (SP/r13) 來存取當前堆疊頂端位置,並取出堆疊中的資料
:::info
**語法**
```assembly=
LDM/STM{<variant>} Rd{!}, {Rx-Ry}
/*{Rx-Ry}=={Rx,Rx+1...,Ry}*/
```
:::
:::warning
**不同操作方式 Instruction**
- **Stack Type**

- **Block Copy**
<font color=blue>**Increment 意義** : 為原來位址再加上 4 byte 也就是移動到下一層 memory
ex : 0x0004 => increment => 0x0008 </font>

:::
<br>
### - **Stack Type**
Stack Type 的操作方式會根據 SP 所指向的 Stack Top 位置開始做 Load/Store
並且會更新 SP 的位置 ( Top 位置 )
:::info
這邊範例皆使用 fd (Full Descending) 做舉例
ex :
```assembly=
stmfd sp!, {r4,r5,r6}
@ 將 r4,r5,r6 中儲存的資訊,
@ 存入記憶體中的 Stack,
@ 也就是 SP 指向的位置。 */
ldmfb sp!, {r4-r6}
@ 從 SP 指向的位置取出資料
@ 並存放在 r4,r5,r6 中。
```
:::
### - **Block Copy**
Block Copy 是從 <Rd> 指向的記憶體位址,開始取出一連串資料
指令中的差別主要是 Increment、Decrement 的順序
```
- ia : 在 load/store 完後,再進行 Increment,
意思是,在資料 load/store 完後 <Rd> 會指向最後一個操作資料的位址,
ia 會將位址在加上 4 byte (Increment),也就是會指向再下一個記憶體區塊
- ib : 在進行 load/store 之前,就做 Increment,
也就是取出的第一個資料,會是原 <Rd> 指向的下一個位址的資料
- da : 與 ia 的情況類似,但這邊會往下儲存(記憶體 address 減少),
並在 load/store 完資料後再減 4 byte (Decrement)
- db : 與 ib 類似,會在 load/store 完資料前先減 4 byte (Decrement)
```
:::info
這邊只用 ia, ib 做舉例
<ia> ex :
```assembly=
ldmia r0!, {r1-r3}
@ 將 r0 指向的位置連續 load 到 r1,r2,r3
@ 最後進行 Increment ( 0x018 + 4byte = 0x01c ) 存入 r0
```

<br>
<ib> ex :
```assembly=
ldmib r0!, {r1-r3}
@ 先進行 Increment 並將位址存入 r0
@ 之後把新的 r0 指向的位置連續 load 到 r1,r2,r3
```

:::
<br>
## (7) - Atomic Load/Store (SWP)
這邊簡單介紹一個可以同時做 Load/Store 的指令 Swap (SWP)
顧名思義就是交換,會 Load 資料進來 Rd,並同時將 Rm 的資料存到記憶體 [Rn]
```
SWP{<cond>} Rd, Rm, [Rn]
- 將 [Rn] 存的記憶體位置資料 load 到 Rd,並將 Rm 資料存到 Rn 記憶體位置
ex :
swpeqb r1, r4, [r3] @ b:byte
```
---
## Reference
- [JoeTheProfessor | 03: ARM Cortex-M Load/Store Instructions](https://www.youtube.com/watch?v=07ATOG5wXPE)
- [MEMORY INSTRUCTIONS: LOAD AND STORE (!!推推!!)](https://azeria-labs.com/memory-instructions-load-and-store-part-4/)
- [ARM Instruction Set - Multiple Register Load Store Instruction(!!推推!!)](https://www.youtube.com/watch?v=Rpuxgv4coeQ)