|
| 1 | +音界咒的編譯目標是精五門(RISC-V)真言,精五門真言本就十分精簡,在零.一版,更是僅需要 |
| 2 | + |
| 3 | +- 整數加減乘除 |
| 4 | +- 指定暫存器的值 |
| 5 | + |
| 6 | +等寥寥幾個指令而已。 |
| 7 | + |
| 8 | +但在介紹這些指令之前,先來寫個最簡單的範例,並讓它動起來。 |
| 9 | + |
| 10 | +## 實驗環境架設 |
| 11 | + |
| 12 | +絕大部分的人手邊都沒有精五架構的板子,需要先安裝交叉編譯器跟精五模擬器(本作選擇使用 qemu)。 |
| 13 | + |
| 14 | +## 返回 100 |
| 15 | + |
| 16 | +以下是貧道所能構造的最簡易的範例,它一啟動就以 100 當結束碼關閉程序: |
| 17 | + |
| 18 | +```assembly |
| 19 | +.section .text |
| 20 | +.global _start |
| 21 | +
|
| 22 | +_start: |
| 23 | + li a7, 93 # RISCV Linux 中 exit 系統呼叫編號是 93 |
| 24 | + li a0, 100 # a0 是函數呼叫時,第一個參數位置 |
| 25 | + ecall # 執行系統呼叫 exit(100) |
| 26 | +``` |
| 27 | +將之命名為 `100.S` 。 |
| 28 | + |
| 29 | +### 編譯、執行 |
| 30 | +``` |
| 31 | +riscv64-unknown-elf-gcc -nostdlib 100.S # 編譯後應得 a.out 檔案 |
| 32 | +qemu-riscv64 a.out # qemu-riscv64 並非單單模擬裸機,還實作了部分系統呼叫 |
| 33 | +echo $? # 可以看到上一個程序的結束碼是 100 |
| 34 | +``` |
| 35 | + |
| 36 | +## 整數加減乘除 |
| 37 | + |
| 38 | +```assembly |
| 39 | +add 目標, 源1, 源2 |
| 40 | +sub 目標, 源1, 源2 |
| 41 | +mul 目標, 源1, 源2 |
| 42 | +div 目標, 源1, 源2 |
| 43 | +``` |
| 44 | + |
| 45 | +以上就是加減乘除四個指令了,此處的目標、源1、源2,都是暫存器的名字。精五(RISC-V)有 32 個整數通用暫存器,在零.一版的編譯目標中,僅使用臨時暫存器 t0 ~ t6 就可以了。 |
| 46 | + |
| 47 | +除了讓暫存器跟暫存器加減乘除,精五也支援讓暫存器與(12位)立即數做加運算。 |
| 48 | + |
| 49 | +```assembly |
| 50 | +addi 目標, 源, 立即數 |
| 51 | +``` |
| 52 | + |
| 53 | +由於立即數可以寫負數,就不支援減立即數的操作了,畢竟加上一個負數就等同於減。 |
| 54 | + |
| 55 | +## 指定暫存器的值 |
| 56 | + |
| 57 | +``` |
| 58 | +li 目標, 立即數 # 將目標暫存器的值設為立即數 |
| 59 | +mv 目標, 源 # 將目標暫存器的值設為源暫存器的值 |
| 60 | +``` |
| 61 | + |
| 62 | +`li` 跟 `mv` 都是偽指令,也就是說,在組譯階段,指令會被變成一到多個真實指令。 |
| 63 | + |
| 64 | +例如當立即數可用 12 位元表示時,`li 目標, 立即數` 會被譯為 `addi 目標, x0, 立即數`。其中 `x0` 是一個特殊的唯獨暫存器,其值永遠為 0。 |
| 65 | + |
| 66 | +而 `mv 目標, 源` 會被譯為 `addi 目標, 源, 0`。 |
| 67 | + |
| 68 | +## 音界咒編譯實例 |
| 69 | + |
| 70 | +```音界 |
| 71 | +元.甲=(1+3)*4 |
| 72 | +甲+1 |
| 73 | +``` |
| 74 | +編譯出的精五真言,其結束碼為音界咒中最後一行的值,在上述範例中,即是「甲+1」的值。 |
| 75 | + |
| 76 | + |
| 77 | +```assembly |
| 78 | +.section .text |
| 79 | +.global _start |
| 80 | +
|
| 81 | +_start: |
| 82 | + li t0, 1 # t0 = 1 |
| 83 | + li t1, 3 # t1 = 3 |
| 84 | + add t0, t0, t1 # t0 = t0 + t1 |
| 85 | +
|
| 86 | + li t1, 4 # t1 = 4 |
| 87 | + mul t0, t0, t1 # t0 = t0 * t1 |
| 88 | + addi t0, t0, 1 # t0 = t0 + 1 |
| 89 | +
|
| 90 | + li a7, 93 # RISCV Linux 中 exit 系統呼叫編號是 93 |
| 91 | + mv a0, t0 # a0 = t0 |
| 92 | + ecall # 執行系統呼叫 exit(t0) |
| 93 | +``` |
| 94 | + |
| 95 | +試著編譯執行看看,並驗證結束碼是否是 17。 |
0 commit comments