Skip to content

音界咒的編譯目標是精五門(RISC-V)真言,精五門真言本就十分精簡,在零.一版,更是僅需要

  • 整數加減乘除
  • 指定暫存器的值

等寥寥幾個指令而已。

但在介紹這些指令之前,先來寫個最簡單的範例,並讓它動起來。

實驗環境架設

絕大部分的人手邊都沒有精五架構的板子,在其他架構的機器上,需要先安裝一些工具才能模擬精五架構:

  • 交叉編譯器工具鏈
  • 精五模擬器(本作選擇使用 qemu)

以下是 ubuntu 的安裝指令。

sudo apt install gcc-riscv64-unknown-elf # 安裝編譯目標為 riscv64 的工具鏈
sudo apt install qemu-user               # 安裝可執行 linux 執行檔的 qemu

返回 100

以下是貧道所能構造的最簡易的範例,它一啟動就以 100 當結束碼關閉程序:

assembly
.section .text
.global _start

_start:
    li a7, 93         # RISCV Linux 中 exit 系統呼叫編號是 93
    li a0, 100        # a0 是函數呼叫時,第一個參數位置
    ecall             # 執行系統呼叫 exit(100)

將之命名為 100.S

編譯、執行

riscv64-unknown-elf-gcc -nostdlib 100.S    # 編譯後應得 a.out 檔案
qemu-riscv64 a.out                         # qemu-riscv64 並非單單模擬裸機,還實作了部分系統呼叫
echo $?                                    # 可以看到上一個程序的結束碼是 100

整數加減乘除

assembly
add 目標, 源1, 源2
sub 目標, 源1, 源2
mul 目標, 源1, 源2
div 目標, 源1, 源2

以上就是加減乘除四個指令了,此處的目標、源1、源2,都是暫存器的名字。精五(RISC-V)有 32 個整數通用暫存器,在零.一版的編譯目標中,僅使用臨時暫存器 t0 ~ t6 就可以了。

除了讓暫存器跟暫存器加減乘除,精五也支援讓暫存器與(12位)立即數做加運算。

assembly
addi 目標, 源, 立即數

由於立即數可以寫負數,就不支援減立即數的操作了,畢竟加上一個負數就等同於減。

指定暫存器的值

li 目標, 立即數          # 將目標暫存器的值設為立即數
mv 目標, 源             # 將目標暫存器的值設為源暫存器的值

limv 都是偽指令,也就是說,在組譯階段,指令會被變成一到多個真實指令。

例如當立即數可用 12 位元表示時,li 目標, 立即數 會被譯為 addi 目標, x0, 立即數。其中 x0 是一個特殊的唯獨暫存器,其值永遠為 0。

mv 目標, 源 會被譯為 addi 目標, 源, 0

音界咒編譯實例

音界
元.甲=(1+3)*4
甲+1

編譯出的精五真言,其結束碼定義為:若最後一行是算式,則為算式求值結果,在上述範例中,即是「甲+1」的值。若最後一行是變數宣告,結束碼定義為該變數的值。

assembly
.section .text
.global _start

_start:
    li t0, 1          # t0 = 1
    li t1, 3          # t1 = 3
    add t0, t0, t1    # t0 = t0 + t1

    li t1, 4          # t1 = 4
    mul t0, t0, t1   # t0 = t0 * t1
    addi t0, t0, 1    # t0 = t0 + 1

    li a7, 93         # RISCV Linux 中 exit 系統呼叫編號是 93
    mv a0, t0         # a0 = t0
    ecall             # 執行系統呼叫 exit(t0)

試著編譯執行看看,並驗證結束碼是否是 17。