Skip to content

Commit

Permalink
介紹堆疊機
Browse files Browse the repository at this point in the history
  • Loading branch information
MROS committed Oct 3, 2024
1 parent d741589 commit a272c8f
Showing 1 changed file with 107 additions and 2 deletions.
109 changes: 107 additions & 2 deletions book/零.一版/精五真言生成.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

### 精五真言的數據段

很容易就能用精五真言設定全域變數,一下是範例`數據段.S`
很容易就能用精五真言設定全域變數,以下是範例`數據段.S`

```assembly
.section .data
Expand All @@ -32,7 +32,7 @@ qemu-riscv64 a.out # qemu-riscv64 並非單單模擬裸
echo $? # 可以看到上一個程序的結束碼是 50
```

`數據段.S` 首先在數據段 `.section .data` ,中用 `.word` 開闢 32 位元的空間,前方的``是一個標籤,在後續程式段的真言中會被代換為該空間的位址。
`數據段.S` 首先在數據段 `.section .data` `.word` 開闢 32 位元的空間,前方的``是一個標籤,在後續程式段的真言中會被代換為該空間的位址。

再來看 `_start` 的第一行 `lw t0, 甲`,lw 是 load word 的縮寫,效果是從位址甲開始讀取 32 位元放進 t0 暫存器。 `lw` 執行完後, `t0` 就是 `50` 了,最後 `mv a0, t0` 把程序結束碼設為 50。

Expand Down Expand Up @@ -65,3 +65,108 @@ sw rd, 標籤[31:12](rd) # 把被汙染的值寫到記憶體
所以 `sw rd, 標籤, rt` 的第三個參數 rt 省不了。

## 運算

在語法樹中,`算式`是一棵二元樹,要從樹形轉換為循序、線性的真言並不是一目瞭然的事情。若先將算術二元樹轉換為後序表達式,計算的順序會比較明瞭一些。道友們在煉氣(學習編程基礎、資料結構)時,想必對後序表達式不陌生,後序拜訪二元樹就能得到。

```虛擬碼
後序拜訪(樹) {
後序拜訪(樹.左子樹)
後序拜訪(樹.右子樹)
打印(樹.值)
}
```

舉個例子:

```
+
/ \
* 5
/ \
3 -
/ \
4 2
```
後序拜訪後,會打印出:

```
3 4 2 - * 5 +
```

這時計算的順序就很清楚了,由左而右是 - * + ,得到順序後,把每個數字放進一個暫存器,可以生成真言

```
li t0, 3
li t1, 4
li t2, 2
sub t1, t1, t2
mul t0, t1, t1
li t1, 5
add t0, t1, t1
```

然而算術樹可能會很高很畸形,導致暫存器的數量不夠用,這時就得把數字放進記憶體暫時儲存了。

道友們煉氣時應該都有印象,藉助資料結構「棧(堆疊)」可以很輕鬆的計算後序表達式,若需要複習,可以看看下方的逐步操作回憶一下:

```
[3] # 遇數字 3,壓入棧
[3, 4] # 遇數字 4,壓入棧
[3, 4, 2] # 遇數字 2,壓入棧
[3, 2] # 遇運算 -,計算 4 - 2 = 2,將結果壓入棧
[6] # 遇運算 *,計算 3 * 2 = 6,將結果壓入棧
[6, 5] # 遇數字 5,壓入棧
[11] # 遇運算 +,計算 6 + 5 = 11,將結果壓入棧
```

把所有運算都存到棧裡是很慢的,畢竟一次記憶體存取可能比是存取暫存器要慢上幾十乃至上百倍,即使快取命中也要好幾個 cycle 才拿得回來,但堆疊機實現起來容易。就先暫且把暫存器分配問題丟到一邊,來看看在精五真言中如何模擬堆疊機。

## 精五真言棧操作

精五(RISC-V)架構的棧一般來說是從高位址往低位址成長的。棧頂位址由暫存器 sp 記錄,`addi sp, sp, -8` 可擴大棧,相反地,`addi sp, sp, 8`會縮小棧。

以下精五真言將數字 3 壓入棧
```assembly
addi sp, sp, -8 # 擴大棧 64 位元(8 位元組 = 64 位元)
li t0, 3 # t0 = 3
sd t0, 0(sp) # sd 將 64 位元 t0 存到棧頂
```

最後來看上述算術樹轉成堆疊機操作的完整精五真言:

```assembly
# 3 入棧
addi sp, sp, -8
li t0, 3
sd t0, 0(sp)
# 4 入棧
addi sp, sp, -8
li t0, 4
sd t0, 0(sp)
# 2 入棧
addi sp, sp, -8
li t0, 2
sd t0, 0(sp)
# 減
ld t1, 0(sp) # t1 = 棧頂
addi sp, sp, 8 # 棧頂縮小 64 位元
ld t0, 0(sp) # t0 = 棧頂
sub t0, t0, t1 # t0 = t0 - t1
sd t0, 0(sp) # sd 將 64 位元 t0 存到棧頂
# 乘
ld t1, 0(sp)
addi sp, sp, 8
ld t0, 0(sp)
mul t0, t0, t1
sd t0, 0(sp)
# 5 入棧
addi sp, sp, -8
li t0, 5
sd t0, 0(sp)
# 加
ld t1, 0(sp)
addi sp, sp, 8
ld t0, 0(sp)
add t0, t0, t1
sd t0, 0(sp)
```

0 comments on commit a272c8f

Please sign in to comment.