レイトレを動かしてみる
レイトレを組み込んでみたものの、黒い画像しか表示されない...
どこが原因かを探るにあたり、既存のレイトレではどのようなデータが流れているかを確認しておきたい。
OCamlのレイトレで、小さい画像を生成して流れるデータを確認してみる。
OCamlでレイトレ
以下のコマンドで min-rt.ml をOCamlで実行できる
code:sh
$ cd min-rt
$ make ball.ocamlopt.ppm
以下のコマンドでPPMファイルをターミナルに表示できる。
code:sh
ocamlopt -unsafe -inline 100 -c -pp ./preprocess.sh min-rt.ml && ocamlopt -unsafe -inline 100 -o min-rt miniMLRuntime.cmx globals.cmx min-rt.cmx && ./min-rt < ball.sld
画像サイズを小さく(3x3)
code:diff
diff --git a/min-rt/min-rt.ml b/min-rt/min-rt.ml
index d19ded6..2b5f421 100644
--- a/min-rt/min-rt.ml
+++ b/min-rt/min-rt.ml
@@ -1268,4 +1268,4 @@ in
)
in
-rt 768 768 false
+rt 3 3 false
処理の流れ
rt
sizeを初期化
read_parameter
read_environ
screenを初期化
cos_vを初期化
sin_vを初期化
lightを初期化
beamを初期化
vp(視点位置ベクトル・ローカル座標)を初期化
view(視点位置ベクトル・ワールド座標)を初期化
read_all_object
read_object 0
read_nth_object n
abc = Array.make 3 0.0
xyz = Array.make 3 0.0
refparam = Array.make 2 0.0
color = Array.make 3 0.0
rotation = Array.make 3 0.0
objectsを初期化
cs_tempをrotationで初期化
(デバッグ出力)
Format.eprintf "OBJ #%d: %d (%f %f %f) (%f %f %f) [%f %f %f]@."
n form abc.(0) abc.(1) abc.(2) xyz.(0) xyz.(0) xyz.(0)
rotation.(0) rotation.(1) rotation.(2);
read_object (n + 1)
read_and_network 0
read_net_item 0
-1でなければ and_netを初期化
read_and_network (n + 1)
or_net.(0) <- read_or_network 0
scan_start
write_ppm_header
sizex = float_of_int size.(0)
scan_d(0) <- 128.0 /. sizex
scan_offset.(0) <- sizex /. 2.0
scan_line 0
scan_point 0
raytracing 0 1.0
crashed_p = tracer viewpoint vscan → 大丈夫そう
write_rgb
scan_point (scanx + 1)
scan_line (scany + 1)
bright
bright に 0.774 を入れると何かが出力された。bright は何をやってる?
code:ocaml
if crashed_p then
(* オブジェクトにぶつかった場合 *)
(
(* 1. 物体に当たる光 *)
let cobj = objects.(crashed_object.(0)) in
get_nvector cobj crashed_point;
let bright =
if (shadow_check_one_or_matrix 0 or_net.(0) crashed_point)
then
0.0 (* 影なので光は当たらない *)
else (
let br = -.(in_prod nvector light) in
let br1 = if 0.0 > br then 0.2 else br +. 0.2 in
br1 *. energy *. o_diffuse cobj
)
in
shadow_check_one_or_matrix 0 or_net.(0) crashed_point で true = 1 が返るのが原因。
code:ocaml
(* 1. 物体に当たる光 *)
let cobj = objects.(crashed_object.(0)) in
get_nvector cobj crashed_point;
let bright =
let b = shadow_check_one_or_matrix 0 or_net.(0) crashed_point in
let _ = print_byte 64 in
let _ = print_byte 32 in
let _ = if b then print_int 1 else print_int 0 in
let _ = print_newline () in
if (shadow_check_one_or_matrix 0 or_net.(0) crashed_point)
then
0.0 (* 影なので光は当たらない *)
else (
let br = -.(in_prod nvector light) in
let br1 = if 0.0 > br then 0.2 else br +. 0.2 in
br1 *. energy *. o_diffuse cobj
)
in
crashed_point の値は同じ
code:text
P3
3 3
255
0 0 0 @ -28936
28936
-28721
197 0 0 @ 28936
28936
-28721
197 0 0 0 0 0 @ -28936
-28936
-28721
197 0 0 @ 28936
-28936
-28721
197 0 0 0 0 0 0 0 0 0 0 0
crashed_object.(0) の値も同じ
code:text
P3
3 3
255
0 0 0 @ 0
197 0 0 @ 0
197 0 0 0 0 0 @ 0
197 0 0 @ 0
197 0 0 0 0 0 0 0 0 0 0 0
or_net.(0) も同じみたい
code:ocaml
if crashed_p then
(* オブジェクトにぶつかった場合 *)
(
(* 1. 物体に当たる光 *)
let cobj = objects.(crashed_object.(0)) in
get_nvector cobj crashed_point;
let bright =
let _ = print_byte 64 in
let _ = print_byte 32 in
let _ = print_int or_net.(0).(0).(0) in
let _ = print_newline () in
let _ = print_int or_net.(0).(0).(1) in
let _ = print_newline () in
let _ = print_int or_net.(0).(0).(2) in
let _ = print_newline () in
let _ = print_int or_net.(0).(1).(0) in
let _ = print_newline () in
if (shadow_check_one_or_matrix 0 or_net.(0) crashed_point)
then
0.0 (* 影なので光は当たらない *)
else (
let br = -.(in_prod nvector light) in
let br1 = if 0.0 > br then 0.2 else br +. 0.2 in
br1 *. energy *. o_diffuse cobj
)
in
(OCaml版)
code:text
P3
3 3
255
0 0 0 @ 99
0
-1
-1
197 0 0 @ 99
0
-1
-1
197 0 0 0 0 0 @ 99
0
-1
-1
197 0 0 @ 99
0
-1
-1
(MinCaml版)
code:text
P3
3 3
255
0 0 0 @ 99
0
-1
-1
0 0 0 @ 99
0
-1
-1
0 0 0 0 0 0 @ 99
0
-1
-1
0 0 0 @ 99
0
-1
-1
以下が true になるのが原因かも
code:ocaml
let t0 = solver obj light p in
let t0p = solver_dist.(0) in
if (if t0 <> 0 then t0p < -0.2 else false)
code:ocaml
(**** AND ネットワーク iand の影内かどうかの判定 ****)
(*MINCAML*)let rec shadow_check_and_group iand_ofs and_group p =
(*NOMINCAML let rec shadow_check_and_group iand_ofs and_group p =*)
if and_group.(iand_ofs) = -1 then
false
else
let obj = and_group.(iand_ofs) in
(*
if crashed_object.(0) = obj
then shadow_check_and_group (iand_ofs + 1) and_group p
else
*)
let t0 = solver obj light p in
let t0p = solver_dist.(0) in
if (if t0 <> 0 then t0p < -0.2 else false)
then
let _ = print_byte 64; print_byte 64; print_byte 64 in
(* Q: 交点の候補。実際にすべてのオブジェクトに *)
(* 入っているかどうかを調べる。*)
let t = t0p +. 0.01 in
chkinside_p.(0) <- light.(0) *. t +. p.(0);
chkinside_p.(1) <- light.(1) *. t +. p.(1);
chkinside_p.(2) <- light.(2) *. t +. p.(2);
if (check_all_inside 0 and_group)
then true
else shadow_check_and_group (iand_ofs + 1) and_group p
(* 次のオブジェクトから候補点を探す *)
else
(* 交点がない場合: 極性が正(内側が真)の場合、 *)
(* AND ネットの共通部分はその内部に含まれるため、*)
(* 交点はないことは自明。探索を打ち切る。 *)
if o_isinvert (objects.(obj))
then shadow_check_and_group (iand_ofs + 1) and_group p
else false
in
-0.007 < -0.2 が true になってしまうのが原因っぽい→FLE.Sがバグってた
code:ocaml
let t0 = solver obj light p in
let t0p = solver_dist.(0) in
let _ = print_byte 64; print_byte 64; print_byte 64 in
let _ = print_int (int_of_float (t0p *. 1000.0)) in
let _ = print_byte (if t0 <> 0 then 84 else 70) in (* T or F *)
let _ = print_byte (if t0p < -0.2 then 84 else 70) in (* T or F *)
if (if t0 <> 0 then t0p < -0.2 else false)
(OCaml版)
OCaml版では、-0.007 < -0.2 は false
code:text
P3
3 3
255
0 0 0 @@@-7TF197 0 0 @@@-7TF197 0 0 0 0 0 @@@-7TF197 0 0 @@@-7TF197 0 0 0 0 0 0 0 0 0 0 0
(MinCaml版)
OCaml版では、-0.007 < -0.2 が true
code:text
P3
3 3
255
0 0 0 @@@-7TT0 0 0 @@@-7TT0 0 0 0 0 0 @@@-7TT0 0 0 @@@-7TT0 0 0 0 0 0 0 0 0 0 0 0
code:text
00003428 <beq_cont.6198>:
3428: 00008293 mv t0,ra
342c: 00058513 mv a0,a1
3430: 025d2223 sw t0,36(s10)
3434: 028d0d13 addi s10,s10,40
3438: 1fd020ef jal 5e34 <min_caml_print_byte>
343c: fd8d0d13 addi s10,s10,-40
3440: 024d2283 lw t0,36(s10)
3444: 00028093 mv ra,t0
3448: 000062b7 lui t0,0x6
344c: 1442a507 flw fa0,324(t0) # 6144 <l.5065>
3450: 018d2587 flw fa1,24(s10)
3454: a0b502d3 fle.s t0,fa0,fa1
3458: 00100313 li t1,1
345c: 00629663 bne t0,t1,3468 <beq_else.6199>
3460: 04600513 li a0,70
3464: 0080006f j 346c <beq_cont.6200>
code:text
00006144 <l.5065>:
6144: cccd .insn 2, 0xcccd
6146: be4c .insn 2, 0xbe4c
FLE.Sがバグってる
直した。
code:diff
commit a0067ca9099d01059e8373a0795aec3e0e825ed8
Author: takashi hatakeyama <takashi.hatakeyama@gmail.com>
Date: Thu Jan 16 13:14:44 2025 +0900
Fix FLE.S bug
diff --git a/firmware/test/float_if.ml b/firmware/test/float_if.ml
index 7a38b67..0e348b6 100644
--- a/firmware/test/float_if.ml
+++ b/firmware/test/float_if.ml
@@ -27,10 +27,16 @@ let rec test4 x y =
let rec test5 x y =
if x = y then 1 else 0
in
-
+let rec test6 _ =
+ let c = -0.007 in
+ let d = -0.2 in
+ (* 負の値どうしの FLE.S がバグってた *)
+ if c < d then 1 else 0
+in
test1 a a;
test2 a b;
test3 a b;
test4 b a;
print_int (test5 a a);
+print_int (test6 ()); (* => 0 が返って欲しい *)
print_newline ()
diff --git a/rtl/fpu_controller.sv b/rtl/fpu_controller.sv
index 6111da0..1eed005 100644
--- a/rtl/fpu_controller.sv
+++ b/rtl/fpu_controller.sv
@@ -309,7 +309,7 @@ module fpu_controller(
(fp_sign1 === 1 && fp_sign2 === 0) ? 32'h00000001 :
(fp_sign1 === 0 && fp_sign2 === 1) ? 32'h00000000 :
(fp_sign1 === 0 && fp_sign2 === 0 && fp_exp1 < fp_exp2) ? 32'h00000001 :
- (fp_sign1 === 1 && fp_sign2 === 1 && fp_exp1 > fp_exp2) ? 32'h00000000 :
+ (fp_sign1 === 1 && fp_sign2 === 1 && fp_exp1 > fp_exp2) ? 32'h00000001 :
(fp_sign1 === 0 && fp_sign2 === 0 && fp_exp1 === fp_exp2 && fp_frac1 < fp_frac2) ? 32'h00000001
: 32'h00000000;
assign fle_in1_ack = 1'b1;
ball.sldが動いた
https://gyazo.com/129d2a98bee9491f3e4b65cc99cfeab3
tron.sldが動いた
https://gyazo.com/dfa19bcf6e63f60b62223a5ad744a16b
shuttle.sldが動かない
途中で出力が途絶えてしまう。3x3のうちの2行目に問題がありそう。
code:text
P3
3 3
255
0 0 0 194 194 194 255 255 0
utexture cobj crashed_point; (* テクスチャを計算 *) で落ちてるみたい。
テクスチャ周りのロジックを一部コメントアウトしたらそれっぽい画像が出力されるようになった。
https://gyazo.com/5b879fedba3086f94be983cc86c98be9
code:text
let foo = p.(1) *. 0.25 in
(* let bar = sin foo in *)
sin 10.469 で落ちてるような?
(OK)
U1:10469:-864
code:text
A:3 B:0 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:F Z:32 1 1 B:1 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:T E:553 U:0 F: G: Z:34 119 119 B:2 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:T E:692 U:0 F: G: Z:166 191 46 B:3 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:T E:641 U:0 F: G: Z:232 253 119 B:4 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:T E:226 U:0 F: G: Z:60 47 0 B:5 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:F Z:31 0 0 B:6 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:F Z:31 0 0 B:7 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:F Z:31 0 0 B:8 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:F Z:31 0 0 B:9 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:F Z:31 0 0 B:10 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:F Z:31 0 0 B:11 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:F Z:31 0 0 B:12 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:F Z:31 0 0 B:13 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:F Z:31 0 0 B:14 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:F Z:31 0 0 B:15 C:0:1000 D:T E:796 U:2 U1:10469:-864 E1:747 F: G: Z:151 51 203 B:16 C:0:1000 D:T E:952 U:2 U1:10772:-975 E1:951 F: G: Z:255 57 255 B:17 C:0:1000 D:T E:810 U:2 U1:10761:-972 E1:946 F: G: Z:196 12 207 B:18 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:F Z:31 0 0 B:19 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:F Z:31 0 0
(NG)
code:text
A:3 B:0 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:F Z:32 1 1 B:1 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:T E:553 U:0 F: G: Z:34 119 119 B:2 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:T E:692 U:0 F: G: Z:166 191 46 B:3 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:T E:641 U:0 F: G: Z:232 253 119 B:4 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:T E:226 U:0 F: G: Z:60 47 0 B:5 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:F Z:31 0 0 B:6 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:F Z:31 0 0 B:7 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:F Z:31 0 0 B:8 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:F Z:31 0 0 B:9 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:F Z:31 0 0 B:10 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:F Z:31 0 0 B:11 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:F Z:31 0 0 B:12 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:F Z:31 0 0 B:13 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:F Z:31 0 0 B:14 C:0:1000 D:T E:122 U:0 F: G: C:1:800 D:F Z:31 0 0 B:15 C:0:1000 D:T E:796 U:2 U1:10469:
code:ruby
irb(main):042:0> my_sin(0.0)
=> 0.0
irb(main):043:0> my_sin(1.0)
=> 0.8414710097001764
irb(main):044:0> my_sin(2.0)
=> 0.909347442680776
irb(main):045:0> my_sin(3.0)
=> 0.1453124999999999
irb(main):046:0> my_sin(4.0)
=> -0.7570155063211148
irb(main):047:0> my_sin(5.0)
=> -0.9589246596582796
irb(main):048:0> my_sin(6.0)
=> -0.2794154981989492
irb(main):049:0> my_sin(7.0)
=> 0.6569865993598377
irb(main):050:0> my_sin(8.0)
=> 0.9893676359401486
irb(main):051:0> my_sin(9.0)
=> 0.413541440727335
irb(main):052:0> my_sin(10.0)
=> -0.5447853145181427
adjust で無限ループしてるみたい。FLE.S がまたバグってる?
code:text
000060b4 <min_caml_start>:
60b4: 00050d13 mv s10,a0
60b8: 00058d93 mv s11,a1
60bc: 010d0d13 addi s10,s10,16
60c0: fe1d2c23 sw ra,-8(s10)
60c4: fe8d2e23 sw s0,-4(s10)
60c8: ff0d0413 addi s0,s10,-16
60cc: 000082b7 lui t0,0x8
60d0: e0c2a507 flw fa0,-500(t0) # 7e0c <l.5024>
60d4: 000082b7 lui t0,0x8
60d8: d742a587 flw fa1,-652(t0) # 7d74 <l.5529>
60dc: a0b502d3 fle.s t0,fa0,fa1
60e0: 00100313 li t1,1
60e4: 00629463 bne t0,t1,60ec <beq_else.6612>
60e8: 0400006f j 6128 <beq_cont.6613>
000060ec <beq_else.6612>:
60ec: 3a300513 li a0,931
60f0: 00008293 mv t0,ra
60f4: 005d2223 sw t0,4(s10)
60f8: 008d0d13 addi s10,s10,8
60fc: 084000ef jal 6180 <min_caml_print_int>
6100: ff8d0d13 addi s10,s10,-8
6104: 004d2283 lw t0,4(s10)
6108: 00028093 mv ra,t0
610c: 00008293 mv t0,ra
6110: 005d2223 sw t0,4(s10)
6114: 008d0d13 addi s10,s10,8
6118: 350000ef jal 6468 <min_caml_print_newline>
611c: ff8d0d13 addi s10,s10,-8
6120: 004d2283 lw t0,4(s10)
6124: 00028093 mv ra,t0
00006128 <beq_cont.6613>:
6128: ff8d2083 lw ra,-8(s10)
612c: ffcd2403 lw s0,-4(s10)
6130: ff0d0d13 addi s10,s10,-16
6134: 00008067 ret
FLE.Sを再度修正した... orz
code:diff
diff --git a/Makefile b/Makefile
index 67ca19a..15af15a 100644
--- a/Makefile
+++ b/Makefile
@@ -58,9 +58,9 @@ run: firmware
firmware/firmware.hex:
-# FIRMWARE_TARGET = libmincaml_test.S
+# FIRMWARE_TARGET = fle_test.S
# firmware/firmware.hex: firmware/$(FIRMWARE_TARGET)
-# riscv64-unknown-elf-gcc -march=rv32i -mabi=ilp32 -nostdlib -Wl,-Ttext=0x00000000 $< -o firmware/firmware.elf
+# riscv64-unknown-elf-gcc -march=rv32if -mabi=ilp32f -nostdlib -Wl,-Ttext=0x00000000 $< -o firmware/firmware.elf
# riscv64-unknown-elf-objcopy -O verilog --verilog-data-width 4 firmware/firmware.elf firmware/firmware.hex
# MinCaml のプログラムをビルド
@@ -78,7 +78,7 @@ firmware/firmware.hex: Makefile firmware/min-rt/min-rt.ml firmware/sld_data.s fi
cat firmware/pre_firmware.hex | grep -v "@" > firmware/firmware.hex
# riscv64-unknown-elf-objcopy -O verilog --verilog-data-width 4 firmware/firmware.elf firmware/firmware.hex
-SLD_FILE = firmware/min-rt/ball.sld
+SLD_FILE = firmware/min-rt/contest.sld
firmware/sld_data.s: $(SLD_FILE) Makefile
ruby firmware/bin/sld2asm.rb $(SLD_FILE) > firmware/sld_data.s
diff --git a/firmware/min-rt/min-rt.ml b/firmware/min-rt/min-rt.ml
index 0aff98f..04844af 100644
--- a/firmware/min-rt/min-rt.ml
+++ b/firmware/min-rt/min-rt.ml
@@ -33,9 +33,9 @@ let rec sin x =
else
x
in
- let x1 = adjust x in
- let x2 = x1 *. x1 in
- let x3 = x1 *. x2 in
+ let x = adjust x in
+ let x2 = x *. x in
+ let x3 = x *. x2 in
let x5 = x3 *. x2 in
let x7 = x5 *. x2 in
let x9 = x7 *. x2 in
@@ -1539,21 +1539,6 @@ in
)
in
-(* rt 40 40 false; *)
-rt 40 40 false;
+(* rt 128 128 false; *)
+rt 256 256 false;
print_newline ()
-
-(* print_int (int_of_float ((sin 0.0) *. 1000.0));
-print_newline ();
-print_int (int_of_float ((sin 1.0) *. 1000.0));
-print_newline ();
-print_int (int_of_float ((sin 2.0) *. 1000.0));
-print_newline ();
-print_int (int_of_float ((sin 3.0) *. 1000.0));
-print_newline ();
-print_int (int_of_float ((sin 4.0) *. 1000.0));
-print_newline ();
-print_int (int_of_float ((sin 5.0) *. 1000.0));
-print_newline ();
-print_int (int_of_float ((sin 10.0) *. 1000.0));
-print_newline () *)
無事に表示されるようになったレイトレ殿
https://gyazo.com/0d9c5448e09d85a03ad2ef2832e0a336