4649を出力するだけのRP2350コードを出力
#MinCaml #RP2350
from Raspberry Pi Pico2でCPU実験のレイトレを動かしたい
最初は 4649 を出力するだけのMinCamlコードをコンパイルできるようにする。
テストコードと中間コード
以下のテストコードを用意する。
code:sample/4649.ml
let x = 4649 in print_int x
中間コード
code:sh
$ rlwrap ./min-caml.top
# let src = "let x = 4649 in print_int x" in Virtual.f (Closure.f (Alpha.f (KNormal.f (Typing.f (MyParser.exp MyLexer.token (Lexing.from_string src))))));;
free variable print_int assumed as external
- : Asm.prog =
Asm.Prog ([], [],
Asm.Let (("x.1", Type.Int), Asm.Li 4649,
Asm.Ans (Asm.CallDir (Id.L "min_caml_print_int", "x.1", []))))
#
レジスタの設定
アセンブリソースを出力する前に、まずはレジスタの設定を確認。
RP2350の汎用レジスタ
R0〜R12
R12:スクラッチレジスタ(一時用途)
R13:スタックポインタ(SP / MinCamlのスタックポインタとは別に管理する必要あり)
R14:リンクレジスタ(LR / 関数戻りアドレスを保持)
R15:プログラムカウンタ(PC)
浮動小数点レジスタ
単精度レジスタ:S0〜S15
倍精度レジススタ:D0〜D15(RP2350は単精度なので、こちらはなさそう)
MinCamlのヒープとスタック
R10:MinCamlのスタックポインタ(sp)として利用
R11:MinCamlのヒープポインタ(hp)として利用
4649が動くように修正してみる
以下のコマンドでビルド
code:sh
$ touch sample/4649.ml && make clean min-caml sample/4649.res
4649が動くよう、以下のように修正。
code:diff
diff --git a/Makefile b/Makefile
index 5625ab9..727e705 100644
--- a/Makefile
+++ b/Makefile
@@ -71,7 +71,9 @@ test/%.ans: test/%.ml
test/%.cmp: test/%.res test/%.ans
diff $^ > $@
-sample/%.elf: sample/%.S startup.c stub.c libmincaml.S
+sample/%.s: sample/%.ml
+ ./$(RESULT) sample/$*
+sample/%.elf: sample/%.s startup.c stub.c libmincaml.S
$(TGT_CC) $(TGT_CFLAGS) $(TGT_LDFLAGS) -o $@ $^
sample/%.res: sample/%.elf
qemu-system-arm \
diff --git a/RP2350/asm.ml b/RP2350/asm.ml
index 491c82c..b7672ad 100644
--- a/RP2350/asm.ml
+++ b/RP2350/asm.ml
@@ -43,20 +43,18 @@ type prog = Prog of (Id.l * float) list * fundef list * t
let fletd(x, e1, e2) = Let((x, Type.Float), e1, e2)
let seq(e1, e2) = Let((Id.gentmp Type.Unit, Type.Unit), e1, e2)
-let regs = (* Array.init 27 (fun i -> Printf.sprintf "_R_%d" i) *)
- [| "%r2"; "%r5"; "%r6"; "%r7"; "%r8"; "%r9"; "%r10";
- "%r11"; "%r12"; "%r13"; "%r14"; "%r15"; "%r16"; "%r17"; "%r18";
- "%r19"; "%r20"; "%r21"; "%r22"; "%r23"; "%r24"; "%r25"; "%r26";
- "%r27"; "%r28"; "%r29"; "%r30" |]
+(* 汎用レジスタのうちのR0からR9を使用(R10はMinCamlスタック、R11はMinCamlヒープに用いる) *)
+let regs =
+ "%r0"; "%r1"; "%r3"; "%r4"; "%r5"; "%r6"; "%r7"; "%r8"; "%r9" |
let fregs = Array.init 32 (fun i -> Printf.sprintf "%%f%d" i)
let allregs = Array.to_list regs
let allfregs = Array.to_list fregs
let reg_cl = regs.(Array.length regs - 1) (* closure address (caml2html: sparcasm_regcl) *)
let reg_sw = regs.(Array.length regs - 2) (* temporary for swap *)
let reg_fsw = fregs.(Array.length fregs - 1) (* temporary for swap *)
-let reg_sp = "%r3" (* stack pointer *)
-let reg_hp = "%r4" (* heap pointer (caml2html: sparcasm_reghp) *)
-let reg_tmp = "%r31" (* XX ad hoc *)
+let reg_sp = "%r10" (* stack pointer *)
+let reg_hp = "%r11" (* heap pointer (caml2html: sparcasm_reghp) *)
+let reg_tmp = "%r12" (* XX ad hoc *)
let is_reg x = (x.0 = '%')
(* super-tenuki *)
diff --git a/RP2350/emit.ml b/RP2350/emit.ml
index 323144d..de38b75 100644
--- a/RP2350/emit.ml
+++ b/RP2350/emit.ml
@@ -59,7 +59,7 @@ let rec g oc = function (* 命令列のアセンブリ生成 (caml2html: emit_g)
and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprime) *)
(* 末尾でなかったら計算結果をdestにセット (caml2html: emit_nontail) *)
| NonTail(_), Nop -> ()
- | NonTail(x), Li(i) when -32768 <= i && i < 32768 -> Printf.fprintf oc "\tli\t%s, %d\n" (reg x) i
+ | NonTail(x), Li(i) when -32768 <= i && i < 32768 -> Printf.fprintf oc "\tldr %s, =%d\n" (reg x) i
| NonTail(x), Li(i) ->
let n = i lsr 16 in
let m = i lxor (n lsl 16) in
@@ -200,19 +200,19 @@ and g' oc = function (* 各命令のアセンブリ生成 (caml2html: emit_gprim
Printf.fprintf oc "\tfmr\t%s, %s\n" (reg a) (reg fregs.(0));
Printf.fprintf oc "\tmtlr\t%s\n" (reg reg_tmp)
| (NonTail(a), CallDir(Id.L(x), ys, zs)) ->
- Printf.fprintf oc "\tmflr\t%s\n" (reg reg_tmp);
+ Printf.fprintf oc "\tmov %s, lr\n" (reg reg_tmp);
g'_args oc [] ys zs;
let ss = stacksize () in
- Printf.fprintf oc "\tstw\t%s, %d(%s)\n" (reg reg_tmp) (ss - 4) (reg reg_sp);
- Printf.fprintf oc "\taddi\t%s, %s, %d\n" (reg reg_sp) (reg reg_sp) ss;
+ Printf.fprintf oc "\tstr %s, %s, #%d\n" (reg reg_tmp) (reg reg_sp) (ss - 4);
+ Printf.fprintf oc "\tadd %s, %s, #%d\n" (reg reg_sp) (reg reg_sp) ss;
Printf.fprintf oc "\tbl\t%s\n" x;
- Printf.fprintf oc "\tsubi\t%s, %s, %d\n" (reg reg_sp) (reg reg_sp) ss;
- Printf.fprintf oc "\tlwz\t%s, %d(%s)\n" (reg reg_tmp) (ss - 4) (reg reg_sp);
+ Printf.fprintf oc "\tsub %s, %s, #%d\n" (reg reg_sp) (reg reg_sp) ss;
+ Printf.fprintf oc "\tldr %s, %s, #%d\n" (reg reg_tmp) (reg reg_sp) (ss - 4);
if List.mem a allregs && a <> regs.(0) then
Printf.fprintf oc "\tmr\t%s, %s\n" (reg a) (reg regs.(0))
else if List.mem a allfregs && a <> fregs.(0) then
Printf.fprintf oc "\tfmr\t%s, %s\n" (reg a) (reg fregs.(0));
- Printf.fprintf oc "\tmtlr\t%s\n" (reg reg_tmp)
+ Printf.fprintf oc "\tmov lr, %s\n" (reg reg_tmp)
and g'_tail_if oc e1 e2 b bn =
let b_else = Id.genid (b ^ "_else") in
Printf.fprintf oc "\t%s\tcr7, %s\n" bn b_else;
@@ -271,22 +271,39 @@ let f oc (Prog(data, fundefs, e)) =
Printf.fprintf oc "\t.long\t%ld\n" (getlo d))
data);
Printf.fprintf oc "\t.text\n";
- Printf.fprintf oc "\t.globl _min_caml_start\n";
- Printf.fprintf oc "\t.align 2\n";
+ Printf.fprintf oc "\t.syntax unified\n";
+ Printf.fprintf oc "\t.thumb\n";
+ Printf.fprintf oc "\t.globl min_caml_start\n";
List.iter (fun fundef -> h oc fundef) fundefs;
- Printf.fprintf oc "_min_caml_start: # main entry point\n";
+ Printf.fprintf oc "min_caml_start: # main entry point\n";
+
+ (* callee-saved レジスタと LR を通常スタックへ退避 *)
+ Printf.fprintf oc "\tstmdb sp!, {r4-r11, lr}\n";
+
+ (* r10 = sp, r11 = hp *)
+ Printf.fprintf oc "\tmov %s, r0\n" (reg reg_sp);
+ Printf.fprintf oc "\tmov %s, r1\n" (reg reg_hp);
+ (*
Printf.fprintf oc "\tmflr\tr0\n";
Printf.fprintf oc "\tstmw\tr30, -8(r1)\n";
Printf.fprintf oc "\tstw\tr0, 8(r1)\n";
Printf.fprintf oc "\tstwu\tr1, -96(r1)\n";
+ *)
+
Printf.fprintf oc "#\tmain program starts\n";
stackset := S.empty;
stackmap := [];
g oc (NonTail("_R_0"), e);
Printf.fprintf oc "#\tmain program ends\n";
- (* Printf.fprintf oc "\tmr\tr3, %s\n" regs.(0); *)
+
+ (* callee-saved レジスタと LR を通常スタックから復帰 *)
+ Printf.fprintf oc "\tldmia sp!, {r4-r11, lr}\n";
+
+ Printf.fprintf oc "\tbx lr\n";
+ (*
Printf.fprintf oc "\tlwz\tr1, 0(r1)\n";
Printf.fprintf oc "\tlwz\tr0, 8(r1)\n";
Printf.fprintf oc "\tmtlr\tr0\n";
Printf.fprintf oc "\tlmw\tr30, -8(r1)\n";
Printf.fprintf oc "\tblr\n"
+ *)
diff --git a/linker.ld b/linker.ld
new file mode 100644
index 0000000..819a0fb
--- /dev/null
+++ b/linker.ld
@@ -0,0 +1,46 @@
+ENTRY(Reset_Handler)
+
+MEMORY
+{
+ FLASH (rx) : ORIGIN = 0x10000000, LENGTH = 512K
+ RAM (rwx) : ORIGIN = 0x80000000, LENGTH = 8M
+}
+
+_estack = ORIGIN(RAM) + LENGTH(RAM);
+
+SECTIONS
+{
+ .isr_vector :
+ {
+ KEEP(*(.isr_vector))
+ } > FLASH
+
+ .text :
+ {
+ *(.text*)
+ *(.rodata*)
+ . = ALIGN(4);
+ _etext = .;
+ } > FLASH
+
+ .data : AT(_etext)
+ {
+ . = ALIGN(4);
+ _sdata = .;
+ *(.data*)
+ . = ALIGN(4);
+ _edata = .;
+ } > RAM
+
+ _sidata = LOADADDR(.data);
+
+ .bss :
+ {
+ . = ALIGN(4);
+ _sbss = .;
+ *(.bss*)
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } > RAM
+}
diff --git a/sample/4649.ml b/sample/4649.ml
new file mode 100644
index 0000000..16e88b0
--- /dev/null
+++ b/sample/4649.ml
@@ -0,0 +1 @@
+let x = 4649 in print_int x
出力されたアセンブリ
code:asm
.text
.syntax unified
.thumb
.globl min_caml_start
min_caml_start: # main entry point
stmdb sp!, {r4-r11, lr}
mov r10, r0
mov r11, r1
# main program starts
ldr r0, =4649
mov r12, lr
str r12, r10, #4
add r10, r10, #8
bl min_caml_print_int
sub r10, r10, #8
ldr r12, r10, #4
mov lr, r12
# main program ends
ldmia sp!, {r4-r11, lr}
bx lr
動かしてみる。4649が表示されればOK。
code:sh
$ touch sample/4649.ml && make clean min-caml sample/4649.res
generating assembly...
arm-none-eabi-gcc -mcpu=cortex-m33 -mthumb -mfpu=fpv5-sp-d16 -mfloat-abi=hard -ffreestanding -nostdlib -Wall -Wextra -O2 -T linker.ld -nostdlib -Wl,-Map=main.map -o sample/4649.elf sample/4649.s startup.c stub.c libmincaml.S
qemu-system-arm \
-machine mps2-an505 \
-cpu cortex-m33 \
-m 16M \
-nographic \
-monitor none \
-kernel sample/4649.elf
Hello from QEMU mps2-an505 Cortex-M33!
4649
実機(Adafruit Metro RP2350)でも動いたよ。
https://gyazo.com/47faa235f807f6c65357d0f8a24f032c