自作CPUでMinCamlを動かしてみる
from マルチサイクル RISC-V CPU を作成したい
事前準備
odeeen リポジトリの firmware/bin へ、ビルドした min-caml のコンパイラを、firmware/test ディレクトリへ MinCaml のテストコードを配置しておく。
MinCamlのコードのビルド手順
bin/min-caml コマンドで MinCaml のソースコードをコンパイルすると、
code:sh
cd firmware/
bin/min-caml test/fib
test/fib.s ファイルが生成される。
code:test/fib.s
.text
.globl min_caml_start
.align 2
fib.10:
li t0, 1
bgt a0, t0, ble_else.24
ret
ble_else.24:
addi a1, a0, -1
sw a0, 0(s10)
mv t0, ra
mv a0, a1
sw t0, 4(s10)
addi s10, s10, 8
call fib.10
addi s10, s10, -8
lw t0, 4(s10)
mv ra, t0
lw a1, 0(s10)
addi a1, a1, -2
sw a0, 4(s10)
mv t0, ra
mv a0, a1
sw t0, 12(s10)
addi s10, s10, 16
call fib.10
addi s10, s10, -16
lw t0, 12(s10)
mv ra, t0
lw a1, 4(s10)
add a0, a1, a0
ret
min_caml_start: # main entry point
mv s10, a0
mv s11, a1
addi s10, s10, 16
sw ra, -8(s10)
sw s0, -4(s10)
addi s0, s10, -16
# main program starts
li a0, 30
mv t0, ra
sw t0, 4(s10)
addi s10, s10, 8
call fib.10
addi s10, s10, -8
lw t0, 4(s10)
mv ra, t0
mv t0, ra
sw t0, 4(s10)
addi s10, s10, 8
call min_caml_print_int
addi s10, s10, -8
lw t0, 4(s10)
mv ra, t0
# main program ends
lw ra, -8(s10)
lw s0, -4(s10)
addi s10, s10, -16
ret
スタックポインタとヒープポインタと一時レジスタ
手元の MinCaml では、s10 s11 t0 レジスタは以下の用途で使用している。
s10 (x26)
スタックポインタ
s11 (x27)
ヒープポインタ
t0 (x5)
Temp レジスタ
stub.S
code:stub.S
//-------------------------------------------------------------------------
// min_caml_start を呼び出すためのスタブ
//-------------------------------------------------------------------------
.text
.globl _start
_start:
// スタックポインタの開始アドレス (0x4F000000 ~ 0x4FFFFFFF)
li a0, 0x4F000000
// ヒープポインタの開始アドレス (0x4E000000 ~ 0x4EFFFFFF)
li a1, 0x4E000000
call min_caml_start
loop:
j loop
libmincaml.S
code:libmincaml.S
.text
.globl min_caml_print_int
min_caml_print_int:
// ひとまず LED に出力
lui s0, 0xf0001
sw a0, 0(s0)
ret
バイナリをビルドする。0番地から実行が始まるため、_start が置いてある stub.S を一番前に置く必要がある。
code:sh
$ cd firmware
$ riscv64-unknown-elf-gcc -nostdlib -march=rv32i -mabi=ilp32 -Wl,-Ttext=0x00000000 stub.S test/fib.s libmincaml.S -o firmware.elf
$ riscv64-unknown-elf-objcopy -O verilog --verilog-data-width 4 firmware.elf firmware.hex
Makefileを用意
make コマンドからビルドできるようにした。
code:diff
# MinCaml のプログラムをビルド
FIRMWARE_TARGET = test/fib
firmware/firmware.hex: firmware/$(FIRMWARE_TARGET).ml firmware/libmincaml.S firmware/stub.S
firmware/bin/min-caml firmware/${FIRMWARE_TARGET}
riscv64-unknown-elf-gcc -nostdlib -march=rv32i -mabi=ilp32 -Wl,-Ttext=0x00000000 firmware/stub.S firmware/${FIRMWARE_TARGET}.s firmware/libmincaml.S -o firmware/firmware.elf
riscv64-unknown-elf-objcopy -O verilog --verilog-data-width 4 firmware/firmware.elf firmware/firmware.hex
ビルドして実行
make prog でビルドとアップロードを行う。
code:sh
$ make prog
fujprog -j SRAM ulx3s.bit
ULX2S / ULX3S JTAG programmer v4.8 (git cc3ea93 built Nov 5 2024 02:49:16)
Copyright (C) Marko Zec, EMARD, gojimmypi, kost and contributors
no root permissions, not handling kexts
Using USB cable: ULX3S FPGA 85K v3.0.8
Programming: 100%
Completed in 7.91 seconds.
$
アップロードに成功したら、screen コマンドでシリアルコンソールに接続。
code:sh
$ screen /dev/cu.usbserial-D00084 115200
謎のゴミデータが表示されるので、Ctrl-a :clear でクリアする(どうやったら出なくなるんや...)
https://gyazo.com/15b0ea933318b961e3b2f1bedba7c8b6
B0ボタンを押してCPUをリセットし、MinCamlアプリを最初から実行。フィボナッチの結果がシリアルコンソールに出力されればOK
https://gyazo.com/ed6d7b4422209a1cf6fd83205eac47de
実装が必要な MinCaml のライブラリ関数
(int のみのやつ)
min_caml_print_int
a0: int value
min_caml_print_byte
a0: int value
min_caml_read_int
return: int
min_caml_print_newline
create_array (min_caml_create_array)
a0: number of elements
a1: initial value
(float が必要なやつ)
min_caml_print_float
fa0: float value
min_caml_read_float
return: float
min_caml_atan
fa0: float value
return : float
min_caml_cos
fa0: float value
return : float
min_caml_floor
fa0: float value
return : float
min_caml_sin
fa0: float value
return : float
min_caml_abs_float
fa0: float value
return : float
min_caml_sqrt
fa0: float value
return : float
min_caml_float_of_int
a0: int value
return : float
min_caml_int_of_float
fa0: float value
return: int
min_caml_truncate
fa0: float value
return: int
create_float_array (min_caml_create_float_array)
a0: number of elements
fa0: initial value