77
88### 精五真言的數據段
99
10- 很容易就能用精五真言設定全域變數,一下是範例 ` 數據段.S ` :
10+ 很容易就能用精五真言設定全域變數,以下是範例 ` 數據段.S ` :
1111
1212``` assembly
1313.section .data
@@ -32,7 +32,7 @@ qemu-riscv64 a.out # qemu-riscv64 並非單單模擬裸
3232echo $? # 可以看到上一個程序的結束碼是 50
3333```
3434
35- ` 數據段.S ` 首先在數據段 ` .section .data ` ,中用 ` .word ` 開闢 32 位元的空間,前方的` 甲 ` 是一個標籤,在後續程式段的真言中會被代換為該空間的位址。
35+ ` 數據段.S ` 首先在數據段 ` .section .data ` 用 ` .word ` 開闢 32 位元的空間,前方的` 甲 ` 是一個標籤,在後續程式段的真言中會被代換為該空間的位址。
3636
3737再來看 ` _start ` 的第一行 ` lw t0, 甲 ` ,lw 是 load word 的縮寫,效果是從位址甲開始讀取 32 位元放進 t0 暫存器。 ` lw ` 執行完後, ` t0 ` 就是 ` 50 ` 了,最後 ` mv a0, t0 ` 把程序結束碼設為 50。
3838
@@ -65,3 +65,108 @@ sw rd, 標籤[31:12](rd) # 把被汙染的值寫到記憶體
6565所以 ` sw rd, 標籤, rt ` 的第三個參數 rt 省不了。
6666
6767## 運算
68+
69+ 在語法樹中,` 算式 ` 是一棵二元樹,要從樹形轉換為循序、線性的真言並不是一目瞭然的事情。若先將算術二元樹轉換為後序表達式,計算的順序會比較明瞭一些。道友們在煉氣(學習編程基礎、資料結構)時,想必對後序表達式不陌生,後序拜訪二元樹就能得到。
70+
71+ ``` 虛擬碼
72+ 後序拜訪(樹) {
73+ 後序拜訪(樹.左子樹)
74+ 後序拜訪(樹.右子樹)
75+ 打印(樹.值)
76+ }
77+ ```
78+
79+ 舉個例子:
80+
81+ ```
82+ +
83+ / \
84+ * 5
85+ / \
86+ 3 -
87+ / \
88+ 4 2
89+ ```
90+ 後序拜訪後,會打印出:
91+
92+ ```
93+ 3 4 2 - * 5 +
94+ ```
95+
96+ 這時計算的順序就很清楚了,由左而右是 - * + ,得到順序後,把每個數字放進一個暫存器,可以生成真言
97+
98+ ```
99+ li t0, 3
100+ li t1, 4
101+ li t2, 2
102+ sub t1, t1, t2
103+ mul t0, t1, t1
104+ li t1, 5
105+ add t0, t1, t1
106+ ```
107+
108+ 然而算術樹可能會很高很畸形,導致暫存器的數量不夠用,這時就得把數字放進記憶體暫時儲存了。
109+
110+ 道友們煉氣時應該都有印象,藉助資料結構「棧(堆疊)」可以很輕鬆的計算後序表達式,若需要複習,可以看看下方的逐步操作回憶一下:
111+
112+ ```
113+ [3] # 遇數字 3,壓入棧
114+ [3, 4] # 遇數字 4,壓入棧
115+ [3, 4, 2] # 遇數字 2,壓入棧
116+ [3, 2] # 遇運算 -,計算 4 - 2 = 2,將結果壓入棧
117+ [6] # 遇運算 *,計算 3 * 2 = 6,將結果壓入棧
118+ [6, 5] # 遇數字 5,壓入棧
119+ [11] # 遇運算 +,計算 6 + 5 = 11,將結果壓入棧
120+ ```
121+
122+ 把所有運算都存到棧裡是很慢的,畢竟一次記憶體存取可能比是存取暫存器要慢上幾十乃至上百倍,即使快取命中也要好幾個 cycle 才拿得回來,但堆疊機實現起來容易。就先暫且把暫存器分配問題丟到一邊,來看看在精五真言中如何模擬堆疊機。
123+
124+ ## 精五真言棧操作
125+
126+ 精五(RISC-V)架構的棧一般來說是從高位址往低位址成長的。棧頂位址由暫存器 sp 記錄,` addi sp, sp, -8 ` 可擴大棧,相反地,` addi sp, sp, 8 ` 會縮小棧。
127+
128+ 以下精五真言將數字 3 壓入棧
129+ ``` assembly
130+ addi sp, sp, -8 # 擴大棧 64 位元(8 位元組 = 64 位元)
131+ li t0, 3 # t0 = 3
132+ sd t0, 0(sp) # sd 將 64 位元 t0 存到棧頂
133+ ```
134+
135+ 最後來看上述算術樹轉成堆疊機操作的完整精五真言:
136+
137+ ``` assembly
138+ # 3 入棧
139+ addi sp, sp, -8
140+ li t0, 3
141+ sd t0, 0(sp)
142+ # 4 入棧
143+ addi sp, sp, -8
144+ li t0, 4
145+ sd t0, 0(sp)
146+ # 2 入棧
147+ addi sp, sp, -8
148+ li t0, 2
149+ sd t0, 0(sp)
150+ # 減
151+ ld t1, 0(sp) # t1 = 棧頂
152+ addi sp, sp, 8 # 棧頂縮小 64 位元
153+ ld t0, 0(sp) # t0 = 棧頂
154+ sub t0, t0, t1 # t0 = t0 - t1
155+ sd t0, 0(sp) # sd 將 64 位元 t0 存到棧頂
156+ # 乘
157+ ld t1, 0(sp)
158+ addi sp, sp, 8
159+ ld t0, 0(sp)
160+ mul t0, t0, t1
161+ sd t0, 0(sp)
162+ # 5 入棧
163+ addi sp, sp, -8
164+ li t0, 5
165+ sd t0, 0(sp)
166+ # 加
167+ ld t1, 0(sp)
168+ addi sp, sp, 8
169+ ld t0, 0(sp)
170+ add t0, t0, t1
171+ sd t0, 0(sp)
172+ ```
0 commit comments